diff --git a/.gitignore b/.gitignore index 495657a..5e4d717 100644 --- a/.gitignore +++ b/.gitignore @@ -3,9 +3,15 @@ *.pyc *.pyo +*.zip +*.bak +*.lis +*.dst +*.so + toxygen/toxcore tests/tests -tests/libs +toxygen/libs tests/.cache tests/__pycache__ tests/avatars diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml new file mode 100644 index 0000000..524302e --- /dev/null +++ b/.pre-commit-config.yaml @@ -0,0 +1,23 @@ +# -*- mode: yaml; indent-tabs-mode: nil; tab-width: 2; coding: utf-8-unix -*- +--- + +default_language_version: + python: python3.11 +default_stages: [pre-commit] +fail_fast: true +repos: +- repo: local + hooks: + - id: pylint + name: pylint + entry: env PYTHONPATH=/mnt/o/var/local/src/toxygen.git/toxygen toxcore_pylint.bash + language: system + types: [python] + args: + [ + "--source-roots=/mnt/o/var/local/src/toxygen.git/toxygen", + "-rn", # Only display messages + "-sn", # Don't display the score + "--rcfile=/usr/local/etc/testforge/pylint.rc", # Link to your config file + "-E" + ] diff --git a/.pylintrc b/.pylintrc new file mode 100644 index 0000000..e79a8ae --- /dev/null +++ b/.pylintrc @@ -0,0 +1,4 @@ +[pre-commit-hook] +command=env PYTHONPATH=/mnt/o/var/local/src/toxygen.git/toxygen /usr/local/bin/toxcore_pylint.bash +params= -E --exit-zero +limit=8 diff --git a/.rsync.sh b/.rsync.sh index af7bde5..f29cc52 100644 --- a/.rsync.sh +++ b/.rsync.sh @@ -1,7 +1,7 @@ #!/bin/sh -find * -name \*.py | xargs grep -l '[ ]*$' | xargs sed -i -e 's/[ ]*$//' -rsync "$@" -vax --include \*.py \ +#find * -name \*.py | xargs grep -l '[ ]*$' | xargs sed -i -e 's/[ ]*$//' +rsync "$@" -vaxL --include \*.py \ --exclude Toxygen.egg-info --exclude build \ --exclude \*.pyc --exclude .pyl\* --exclude \*~ \ --exclude __pycache__ --exclude \*.egg-info --exclude \*.new \ diff --git a/pyproject.tom b/pyproject.tom deleted file mode 100644 index 3a178d7..0000000 --- a/pyproject.tom +++ /dev/null @@ -1,51 +0,0 @@ -[project] -name = "stem_examples" -description = "examples of using stem" -authors = [{ name = "emdee", email = "emdee@spm.plastiras.org" } ] -requires-python = ">=3.6" -dependencies = [ - 'stem', -] -keywords = ["stem", "python3", "tor"] -classifiers = [ - "License :: OSI Approved", - "Operating System :: POSIX :: BSD :: FreeBSD", - "Operating System :: POSIX :: Linux", - "Programming Language :: Python :: 3 :: Only", - "Programming Language :: Python :: 3.6", - "Programming Language :: Python :: 3.7", - "Programming Language :: Python :: 3.8", - "Programming Language :: Python :: 3.9", - "Programming Language :: Python :: 3.10", - "Programming Language :: Python :: 3.11", - "Programming Language :: Python :: Implementation :: CPython", - ] -# -dynamic = ["version", "readme", ] # cannot be dynamic ['license'] - -[project.scripts] -toxygen = "toxygen.toxygen.main:main" - -#[project.license] -#file = "LICENSE.md" - -[project.urls] -repository = "https://git.plastiras.org/emdee/toxygen" - -[build-system] -requires = ["setuptools >= 61.0"] -build-backend = "setuptools.build_meta" - -[tool.setuptools.dynamic] -version = {attr = "stem_examples.__version__"} -readme = {file = ["README.md", "ToDo.txt"]} - -[tool.setuptools] -packages = ["toxygen"] - -[tool.setuptools.packages.find] -where = "toxygen" - -[tool.setuptools.packages.package-data] -"*" = ["*.ui"] - diff --git a/setup.py b/setup.py deleted file mode 100644 index a3f543d..0000000 --- a/setup.py +++ /dev/null @@ -1,53 +0,0 @@ -import sys -import os -from setuptools import setup -from setuptools.command.install import install - -version = '1.0.0' - -MODULES = open('requirements.txt', 'rt').readlines() - -def get_packages(): - directory = os.path.join(os.path.dirname(__file__), 'tox_wrapper') - for root, dirs, files in os.walk(directory): - packages = map(lambda d: 'toxygen.' + d, dirs) - packages = ['toxygen'] + list(packages) - return packages - -class InstallScript(install): - """This class configures Toxygen after installation""" - - def run(self): - install.run(self) - -setup(name='Toxygen', - version=version, - description='Toxygen - Tox client', - long_description='Toxygen is powerful Tox client written in Python3', - url='https://git.plastiras.org/emdee/toxygen/', - keywords='toxygen Tox messenger', - author='Ingvar', - maintainer='', - license='GPL3', - packages=get_packages(), - install_requires=MODULES, - include_package_data=True, - classifiers=[ - 'Programming Language :: Python :: 3 :: Only', - "Programming Language :: Python :: 3.6", - "Programming Language :: Python :: 3.7", - "Programming Language :: Python :: 3.8", - "Programming Language :: Python :: 3.9", - "Programming Language :: Python :: 3.10", - "Programming Language :: Python :: 3.11", - 'Programming Language :: Python :: 3.11', - ], - entry_points={ - 'console_scripts': ['toxygen=toxygen.main:main'] - }, - package_data={"": ["*.ui"],}, - cmdclass={ - 'install': InstallScript, - }, - zip_safe=False - ) diff --git a/tests/travis.py b/tests/travis.py index 30d5edd..af8f83f 100644 --- a/tests/travis.py +++ b/tests/travis.py @@ -1,4 +1,4 @@ class TestToxygen: def test_main(self): - import toxygen.main # check for syntax errors + import toxygen.__main__ # check for syntax errors diff --git a/toxygen/app.py b/toxygen/app.py index a6cb8a1..17921bc 100644 --- a/toxygen/app.py +++ b/toxygen/app.py @@ -208,7 +208,7 @@ class App: """ Main function of app. loads login screen if needed and starts main screen """ - self._app = QtWidgets.QApplication([]) + self._app = QApplication([]) self._load_icon() # is this still needed? diff --git a/toxygen/av/call.py b/toxygen/av/call.py index 6098670..73caa25 100644 --- a/toxygen/av/call.py +++ b/toxygen/av/call.py @@ -1,4 +1,4 @@ - +# -*- mode: python; indent-tabs-mode: nil; py-indent-offset: 4; coding: utf-8 -*- class Call: diff --git a/toxygen/av/calls.py b/toxygen/av/calls.py index a1d0922..9b40fc1 100644 --- a/toxygen/av/calls.py +++ b/toxygen/av/calls.py @@ -13,6 +13,7 @@ with ts.ignoreStderr(): from av import screen_sharing from av.call import Call import common.tox_save +from middleware.threads import BaseQThread from utils import ui as util_ui from middleware.threads import invoke_in_main_thread @@ -36,7 +37,7 @@ class AudioThread(BaseQThread): LOG_DEBUG(f"AudioThread join {self}") # dunno - def run(self): + def run(self) -> None: LOG_DEBUG('AudioThread run: ') # maybe not needed while not self._stop_thread: @@ -53,7 +54,7 @@ class VideoThread(BaseQThread): LOG_DEBUG(f"VideoThread join {self}") # dunno - def run(self): + def run(self) -> None: LOG_DEBUG('VideoThread run: ') # maybe not needed while not self._stop_thread: @@ -109,13 +110,13 @@ class AV(common.tox_save.ToxAvSave): global oPYA oPYA = self._audio = pyaudio.PyAudio() - def stop(self): + def stop(self) -> None: LOG_DEBUG(f"AV.CA stop {self._video_thread}") self._running = False self.stop_audio_thread() self.stop_video_thread() - def __contains__(self, friend_number): + def __contains__(self, friend_number:int) -> bool: return friend_number in self._calls # Calls @@ -141,9 +142,9 @@ class AV(common.tox_save.ToxAvSave): def accept_call(self, friend_number, audio_enabled, video_enabled): # obsolete - return self.call_accept_call(friend_number, audio_enabled, video_enabled) + self.call_accept_call(friend_number, audio_enabled, video_enabled) - def call_accept_call(self, friend_number, audio_enabled, video_enabled): + def call_accept_call(self, friend_number, audio_enabled, video_enabled) -> None: # called from CM.accept_call in a try: LOG.debug(f"call_accept_call from F={friend_number} R={self._running}" + f" A={audio_enabled} V={video_enabled}") @@ -171,7 +172,7 @@ class AV(common.tox_save.ToxAvSave): # may raise self.start_audio_thread() - def finish_call(self, friend_number, by_friend=False): + def finish_call(self, friend_number, by_friend=False) -> None: LOG.debug(f"finish_call {friend_number}") if friend_number in self._calls: del self._calls[friend_number] @@ -191,13 +192,13 @@ class AV(common.tox_save.ToxAvSave): self._toxav.call_control(friend_number, TOXAV_CALL_CONTROL['CANCEL']) LOG.debug(f"finish_call after call_control {friend_number}") - def finish_not_started_call(self, friend_number): + def finish_not_started_call(self, friend_number:int) -> None: if friend_number in self: call = self._calls[friend_number] if not call.is_active: self.finish_call(friend_number) - def toxav_call_state_cb(self, friend_number, state): + def toxav_call_state_cb(self, friend_number, state) -> None: """ New call state """ @@ -214,12 +215,12 @@ class AV(common.tox_save.ToxAvSave): if state | TOXAV_FRIEND_CALL_STATE['ACCEPTING_V'] and call.out_video: self.start_video_thread() - def is_video_call(self, number): + def is_video_call(self, number) -> bool: return number in self and self._calls[number].in_video # Threads - def start_audio_thread(self, bSTREAM_CALLBACK=False): + def start_audio_thread(self, bSTREAM_CALLBACK=False) -> None: """ Start audio sending from a callback @@ -309,7 +310,7 @@ class AV(common.tox_save.ToxAvSave): else: LOG_DEBUG(f"start_audio_thread {self._audio_stream}") - def stop_audio_thread(self): + def stop_audio_thread(self) -> None: LOG_DEBUG(f"stop_audio_thread {self._audio_stream}") if self._audio_thread is None: @@ -326,7 +327,7 @@ class AV(common.tox_save.ToxAvSave): self._out_stream.close() self._out_stream = None - def start_video_thread(self): + def start_video_thread(self) -> None: if self._video_thread is not None: return s = self._settings @@ -334,7 +335,7 @@ class AV(common.tox_save.ToxAvSave): LOG.warn("AV.__init__ 'video' not in s" ) LOG.debug(f"start_video_thread {s}" ) raise RuntimeError("start_video_thread not 'video' in s)" ) - elif 'device' not in s['video']: + if 'device' not in s['video']: LOG.error("start_video_thread not 'device' in s['video']" ) LOG.debug(f"start_video_thread {s['video']}" ) raise RuntimeError("start_video_thread not 'device' ins s['video']" ) @@ -342,7 +343,7 @@ class AV(common.tox_save.ToxAvSave): self._video_height = s['video']['height'] # dunno - if True or s['video']['device'] == -1: + if s['video']['device'] == -1: self._video = screen_sharing.DesktopGrabber(s['video']['x'], s['video']['y'], s['video']['width'], @@ -509,24 +510,24 @@ class AV(common.tox_save.ToxAvSave): if frame is None: LOG_WARN(f"send_video video_send_frame _video.read result={result} frame={frame}") continue + + LOG_TRACE(f"send_video video_send_frame _video.read result={result}") + height, width, channels = frame.shape + friends = [] + for friend_num in self._calls: + if self._calls[friend_num].out_video: + friends.append(friend_num) + if len(friends) == 0: + LOG_WARN(f"send_video video_send_frame no friends") else: - LOG_TRACE(f"send_video video_send_frame _video.read result={result}") - height, width, channels = frame.shape - friends = [] - for friend_num in self._calls: - if self._calls[friend_num].out_video: - friends.append(friend_num) - if len(friends) == 0: - LOG_WARN(f"send_video video_send_frame no friends") - else: - LOG_TRACE(f"send_video video_send_frame {friends}") - friend_num = friends[0] - try: - y, u, v = self.convert_bgr_to_yuv(frame) - self._toxav.video_send_frame(friend_num, width, height, y, u, v) - except Exception as e: - LOG_WARN(f"send_video video_send_frame ERROR {e}") - pass + LOG_TRACE(f"send_video video_send_frame {friends}") + friend_num = friends[0] + try: + y, u, v = self.convert_bgr_to_yuv(frame) + self._toxav.video_send_frame(friend_num, width, height, y, u, v) + except Exception as e: + LOG_WARN(f"send_video video_send_frame ERROR {e}") + pass except Exception as e: LOG_ERROR(f"send_video video_send_frame {e}") diff --git a/toxygen/av/calls_manager.py b/toxygen/av/calls_manager.py index ac645c8..d0d6683 100644 --- a/toxygen/av/calls_manager.py +++ b/toxygen/av/calls_manager.py @@ -31,7 +31,7 @@ class CallsManager: self._call_finished_event = event.Event() # friend_number, is_declined self._app = app - def set_toxav(self, toxav): + def set_toxav(self, toxav) -> None: self._callav.set_toxav(toxav) # Events @@ -48,7 +48,7 @@ class CallsManager: # AV support - def call_click(self, audio=True, video=False): + def call_click(self, audio=True, video=False) -> None: """User clicked audio button in main window""" num = self._contacts_manager.get_active_number() if not self._contacts_manager.is_active_a_friend(): @@ -62,7 +62,7 @@ class CallsManager: elif num in self._callav: # finish or cancel call if you call with active friend self.stop_call(num, False) - def incoming_call(self, audio, video, friend_number): + def incoming_call(self, audio, video, friend_number) -> None: """ Incoming call from friend. """ @@ -80,7 +80,7 @@ class CallsManager: self._call_widgets[friend_number].set_pixmap(friend.get_pixmap()) self._call_widgets[friend_number].show() - def accept_call(self, friend_number, audio, video): + def accept_call(self, friend_number, audio, video) -> None: """ Accept incoming call with audio or video Called from a thread @@ -127,7 +127,7 @@ class CallsManager: self.close_call(friend_number) LOG.debug(f" closed self._call_widgets[{friend_number}]") - def close_call(self, friend_number): + def close_call(self, friend_number:int) -> None: # refactored out from above because the accept window not getting # taken down in some accept audio calls LOG.debug(f"close_call {friend_number}") @@ -145,7 +145,7 @@ class CallsManager: QtCore.QCoreApplication.processEvents() - def stop_call(self, friend_number, by_friend): + def stop_call(self, friend_number, by_friend) -> None: """ Stop call with friend """ @@ -174,7 +174,7 @@ class CallsManager: LOG.debug(f"CM.stop_call _call_finished_event") self._call_finished_event(friend_number, is_declined) - def friend_exit(self, friend_number): + def friend_exit(self, friend_number:int) -> None: if friend_number in self._callav: self._callav.finish_call(friend_number, True) diff --git a/toxygen/av/screen_sharing.py b/toxygen/av/screen_sharing.py index e82b991..e0f783b 100644 --- a/toxygen/av/screen_sharing.py +++ b/toxygen/av/screen_sharing.py @@ -1,5 +1,6 @@ -from qtpy import QtWidgets +# -*- mode: python; indent-tabs-mode: nil; py-indent-offset: 4; coding: utf-8 -*- +from qtpy import QtWidgets class DesktopGrabber: @@ -12,7 +13,7 @@ class DesktopGrabber: self._height -= height % 4 self._screen = QtWidgets.QApplication.primaryScreen() - def read(self): + def read(self) -> tuple: pixmap = self._screen.grabWindow(0, self._x, self._y, self._width, self._height) image = pixmap.toImage() s = image.bits().asstring(self._width * self._height * 4) diff --git a/toxygen/bootstrap/bootstrap.py b/toxygen/bootstrap/bootstrap.py index 542900a..6d64783 100644 --- a/toxygen/bootstrap/bootstrap.py +++ b/toxygen/bootstrap/bootstrap.py @@ -19,7 +19,7 @@ import toxygen_wrapper.tests.support_testing as ts global LOG LOG = logging.getLogger('app.'+'bootstrap') -def download_nodes_list(settings, oArgs): +def download_nodes_list(settings, oArgs) -> str: if not settings['download_nodes_list']: return '' if not ts.bAreWeConnected(): @@ -40,7 +40,7 @@ def download_nodes_list(settings, oArgs): _save_nodes(result, settings._app) return result -def _save_nodes(nodes, app): +def _save_nodes(nodes, app) -> None: if not nodes: return with open(_get_nodes_path(app._args), 'wb') as fl: diff --git a/toxygen/common/event.py b/toxygen/common/event.py index 687a34d..f51a51f 100644 --- a/toxygen/common/event.py +++ b/toxygen/common/event.py @@ -1,4 +1,4 @@ - +# -*- mode: python; indent-tabs-mode: nil; py-indent-offset: 4; coding: utf-8 -*- class Event: diff --git a/toxygen/common/provider.py b/toxygen/common/provider.py index d16edb4..687fd9a 100644 --- a/toxygen/common/provider.py +++ b/toxygen/common/provider.py @@ -1,4 +1,4 @@ - +# -*- mode: python; indent-tabs-mode: nil; py-indent-offset: 4; coding: utf-8 -*- class Provider: diff --git a/toxygen/common/tox_save.py b/toxygen/common/tox_save.py index 09c159b..45563b2 100644 --- a/toxygen/common/tox_save.py +++ b/toxygen/common/tox_save.py @@ -1,4 +1,4 @@ - +# -*- mode: python; indent-tabs-mode: nil; py-indent-offset: 4; coding: utf-8 -*- class ToxSave: diff --git a/toxygen/contacts/common.py b/toxygen/contacts/common.py index a8f2587..bd46c32 100644 --- a/toxygen/contacts/common.py +++ b/toxygen/contacts/common.py @@ -1,6 +1,8 @@ -from pydenticon import Generator +# -*- mode: python; indent-tabs-mode: nil; py-indent-offset: 4; coding: utf-8 -*- + import hashlib +from pydenticon import Generator # Typing notifications @@ -17,7 +19,7 @@ class BaseTypingNotificationHandler: class FriendTypingNotificationHandler(BaseTypingNotificationHandler): - def __init__(self, friend_number): + def __init__(self, friend_number:int): super().__init__() self._friend_number = friend_number diff --git a/toxygen/contacts/contact_provider.py b/toxygen/contacts/contact_provider.py index 1d7faf0..0c5a61d 100644 --- a/toxygen/contacts/contact_provider.py +++ b/toxygen/contacts/contact_provider.py @@ -21,7 +21,7 @@ class ContactProvider(tox_save.ToxSave): # Friends - def get_friend_by_number(self, friend_number): + def get_friend_by_number(self, friend_number:int): try: public_key = self._tox.friend_get_public_key(friend_number) except Exception as e: @@ -124,7 +124,7 @@ class ContactProvider(tox_save.ToxSave): # Group peers def get_all_group_peers(self): - return list() + return [] def get_group_peer_by_id(self, group, peer_id): peer = group.get_peer_by_id(peer_id) diff --git a/toxygen/contacts/contacts_manager.py b/toxygen/contacts/contacts_manager.py index 8a429e0..6f0dae8 100644 --- a/toxygen/contacts/contacts_manager.py +++ b/toxygen/contacts/contacts_manager.py @@ -1,6 +1,6 @@ # -*- mode: python; indent-tabs-mode: nil; py-indent-offset: 4; coding: utf-8 -*- -import traceback +import logging from contacts.friend import Friend from contacts.group_chat import GroupChat @@ -13,13 +13,11 @@ import toxygen_wrapper.toxcore_enums_and_consts as enums # LOG=util.log global LOG -import logging LOG = logging.getLogger('app.'+__name__) - UINT32_MAX = 2 ** 32 -1 -def set_contact_kind(contact): +def set_contact_kind(contact) -> None: bInvite = len(contact.name) == enums.TOX_PUBLIC_KEY_SIZE * 2 and \ contact.status_message == '' bBot = not bInvite and contact.name.lower().endswith(' bot') @@ -59,7 +57,7 @@ class ContactsManager(ToxSave): self._history = history self._load_contacts() - def _log(self, s): + def _log(self, s) -> None: try: self._ms._log(s) except: pass @@ -72,23 +70,23 @@ class ContactsManager(ToxSave): def get_curr_contact(self): return self._contacts[self._active_contact] if self._active_contact + 1 else None - def save_profile(self): + def save_profile(self) -> None: data = self._tox.get_savedata() self._profile_manager.save_profile(data) - def is_friend_active(self, friend_number): + def is_friend_active(self, friend_number:int) -> bool: if not self.is_active_a_friend(): return False return self.get_curr_contact().number == friend_number - def is_group_active(self, group_number): + def is_group_active(self, group_number) -> bool: if self.is_active_a_friend(): return False return self.get_curr_contact().number == group_number - def is_contact_active(self, contact): + def is_contact_active(self, contact) -> bool: if self._active_contact == -1: # LOG.debug("No self._active_contact") return False @@ -107,7 +105,7 @@ class ContactsManager(ToxSave): # Reconnection support - def reset_contacts_statuses(self): + def reset_contacts_statuses(self) -> None: for contact in self._contacts: contact.status = None @@ -441,7 +439,7 @@ class ContactsManager(ToxSave): def add_group_peer(self, group, peer): contact = self._contact_provider.get_group_peer_by_id(group, peer.id) if self.check_if_contact_exists(contact.tox_id): - return + return contact contact._kind = 'grouppeer' self._contacts.append(contact) contact.reset_avatar(self._settings['identicons']) @@ -651,7 +649,7 @@ class ContactsManager(ToxSave): try: index = list(map(lambda x: x[0], self._settings['friends_aliases'])).index(contact.tox_id) del self._settings['friends_aliases'][index] - except: + except Exception as e: pass if contact.tox_id in self._settings['notes']: del self._settings['notes'][contact.tox_id] diff --git a/toxygen/contacts/friend.py b/toxygen/contacts/friend.py index 084672a..24b04ad 100644 --- a/toxygen/contacts/friend.py +++ b/toxygen/contacts/friend.py @@ -1,3 +1,5 @@ +# -*- mode: python; indent-tabs-mode: nil; py-indent-offset: 4; coding: utf-8 -*- + import os from contacts import contact, common diff --git a/toxygen/contacts/friend_factory.py b/toxygen/contacts/friend_factory.py index c3c3646..31d5eec 100644 --- a/toxygen/contacts/friend_factory.py +++ b/toxygen/contacts/friend_factory.py @@ -1,7 +1,8 @@ +# -*- mode: python; indent-tabs-mode: nil; py-indent-offset: 4; coding: utf-8 -*- + from contacts.friend import Friend from common.tox_save import ToxSave - class FriendFactory(ToxSave): def __init__(self, profile_manager, settings, tox, db, items_factory): @@ -15,7 +16,7 @@ class FriendFactory(ToxSave): friend_number = self._tox.friend_by_public_key(public_key) return self.create_friend_by_number(friend_number) - def create_friend_by_number(self, friend_number): + def create_friend_by_number(self, friend_number:int): aliases = self._settings['friends_aliases'] sToxPk = self._tox.friend_get_public_key(friend_number) assert sToxPk, sToxPk diff --git a/toxygen/contacts/group_peer_contact.py b/toxygen/contacts/group_peer_contact.py index 3d232eb..3e6131c 100644 --- a/toxygen/contacts/group_peer_contact.py +++ b/toxygen/contacts/group_peer_contact.py @@ -1,7 +1,8 @@ +# -*- mode: python; indent-tabs-mode: nil; py-indent-offset: 4; coding: utf-8 -*- + import contacts.contact from contacts.contact_menu import GroupPeerMenuGenerator - class GroupPeerContact(contacts.contact.Contact): def __init__(self, profile_manager, message_getter, peer_number, name, widget, tox_id, group_pk, status_message=None): diff --git a/toxygen/contacts/group_peer_factory.py b/toxygen/contacts/group_peer_factory.py index 772cf4f..1804b50 100644 --- a/toxygen/contacts/group_peer_factory.py +++ b/toxygen/contacts/group_peer_factory.py @@ -1,7 +1,7 @@ +# -*- mode: python; indent-tabs-mode: nil; py-indent-offset: 4; coding: utf-8 -*- from common.tox_save import ToxSave from contacts.group_peer_contact import GroupPeerContact - class GroupPeerFactory(ToxSave): def __init__(self, tox, profile_manager, db, items_factory): diff --git a/toxygen/file_transfers/file_transfers.py b/toxygen/file_transfers/file_transfers.py index a4a1e09..5fa87f9 100644 --- a/toxygen/file_transfers/file_transfers.py +++ b/toxygen/file_transfers/file_transfers.py @@ -1,3 +1,5 @@ +# -*- mode: python; indent-tabs-mode: nil; py-indent-offset: 4; coding: utf-8 -*- + import os from os import chdir, remove, rename from os.path import basename, getsize, exists, dirname @@ -80,9 +82,7 @@ class FileTransfer: def get_file_id(self): return self._file_id - # WTF - def get_file_id(self): - return self._tox.file_get_file_id(self._friend_number, self._file_number) +#? return self._tox.file_get_file_id(self._friend_number, self._file_number) file_id = property(get_file_id) @@ -331,7 +331,7 @@ class ReceiveAvatar(ReceiveTransfer): ihash = self.get_file_id() with open(path, 'rb') as fl: data = fl.read() - existing_ihash = Tox.hash(data) + existing_hash = Tox.hash(data) if ihash == existing_hash: self.send_control(TOX_FILE_CONTROL['CANCEL']) self._file.close() diff --git a/toxygen/file_transfers/file_transfers_handler.py b/toxygen/file_transfers/file_transfers_handler.py index 69d042c..a9085c2 100644 --- a/toxygen/file_transfers/file_transfers_handler.py +++ b/toxygen/file_transfers/file_transfers_handler.py @@ -1,5 +1,6 @@ # -*- mode: python; indent-tabs-mode: nil; py-indent-offset: 4; coding: utf-8 -*- -from copy import deepcopy + +import logging from messenger.messages import * from file_transfers.file_transfers import SendAvatar, is_inline @@ -11,7 +12,6 @@ from middleware.callbacks import LOG_ERROR, LOG_WARN, LOG_INFO, LOG_DEBUG, LOG_T # LOG=util.log global LOG -import logging LOG = logging.getLogger('app.'+__name__) log = lambda x: LOG.info(x) @@ -32,13 +32,13 @@ class FileTransfersHandler(ToxSave): profile.avatar_changed_event.add_callback(self._send_avatar_to_contacts) self. lBlockAvatars = [] - def stop(self): + def stop(self) -> None: self._settings['paused_file_transfers'] = self._paused_file_transfers if self._settings['resend_files'] else {} self._settings.save() # File transfers support - def incoming_file_transfer(self, friend_number, file_number, size, file_name): + def incoming_file_transfer(self, friend_number, file_number, size, file_name) -> None: # main thread """ New transfer @@ -86,7 +86,7 @@ class FileTransfersHandler(ToxSave): self._file_transfers_message_service.add_incoming_transfer_message( friend, accepted, size, file_name, file_number) - def cancel_transfer(self, friend_number, file_number, already_cancelled=False): + def cancel_transfer(self, friend_number, file_number, already_cancelled=False) -> None: """ Stop transfer :param friend_number: number of friend @@ -106,19 +106,19 @@ class FileTransfersHandler(ToxSave): elif not already_cancelled: self._tox.file_control(friend_number, file_number, TOX_FILE_CONTROL['CANCEL']) - def cancel_not_started_transfer(self, friend_number, message_id): + def cancel_not_started_transfer(self, friend_number, message_id) -> None: friend = self._get_friend_by_number(friend_number) if friend is None: return None friend.delete_one_unsent_file(message_id) - def pause_transfer(self, friend_number, file_number, by_friend=False): + def pause_transfer(self, friend_number, file_number, by_friend=False) -> None: """ Pause transfer with specified data """ tr = self._file_transfers[(friend_number, file_number)] tr.pause(by_friend) - def resume_transfer(self, friend_number, file_number, by_friend=False): + def resume_transfer(self, friend_number, file_number, by_friend=False) -> None: """ Resume transfer with specified data """ @@ -128,7 +128,7 @@ class FileTransfersHandler(ToxSave): else: tr.send_control(TOX_FILE_CONTROL['RESUME']) - def accept_transfer(self, path, friend_number, file_number, size, inline=False, from_position=0): + def accept_transfer(self, path, friend_number, file_number, size, inline=False, from_position=0) -> None: """ :param path: path for saving :param friend_number: friend number @@ -155,7 +155,7 @@ class FileTransfersHandler(ToxSave): if inline: self._insert_inline_before[(friend_number, file_number)] = message.message_id - def send_screenshot(self, data, friend_number): + def send_screenshot(self, data, friend_number) -> None: """ Send screenshot :param data: raw data - png format @@ -163,12 +163,12 @@ class FileTransfersHandler(ToxSave): """ self.send_inline(data, 'toxygen_inline.png', friend_number) - def send_sticker(self, path, friend_number): + def send_sticker(self, path, friend_number) -> None: with open(path, 'rb') as fl: data = fl.read() self.send_inline(data, 'sticker.png', friend_number) - def send_inline(self, data, file_name, friend_number, is_resend=False): + def send_inline(self, data, file_name, friend_number, is_resend=False) -> None: friend = self._get_friend_by_number(friend_number) if friend is None: LOG_WARN("fsend_inline Error friend is None file_name: {file_name}") @@ -182,7 +182,7 @@ class FileTransfersHandler(ToxSave): st = SendFromBuffer(self._tox, friend.number, data, file_name) self._send_file_add_set_handlers(st, friend, file_name, True) - def send_file(self, path, friend_number, is_resend=False, file_id=None): + def send_file(self, path, friend_number, is_resend=False, file_id=None) -> None: """ Send file to current active friend :param path: file path @@ -202,19 +202,19 @@ class FileTransfersHandler(ToxSave): file_name = os.path.basename(path) self._send_file_add_set_handlers(st, friend, file_name) - def incoming_chunk(self, friend_number, file_number, position, data): + def incoming_chunk(self, friend_number, file_number, position, data) -> None: """ Incoming chunk """ self._file_transfers[(friend_number, file_number)].write_chunk(position, data) - def outgoing_chunk(self, friend_number, file_number, position, size): + def outgoing_chunk(self, friend_number, file_number, position, size) -> None: """ Outgoing chunk """ self._file_transfers[(friend_number, file_number)].send_chunk(position, size) - def transfer_finished(self, friend_number, file_number): + def transfer_finished(self, friend_number, file_number) -> None: transfer = self._file_transfers[(friend_number, file_number)] friend = self._get_friend_by_number(friend_number) if friend is None: return None @@ -231,7 +231,7 @@ class FileTransfersHandler(ToxSave): self._file_transfers_message_service.add_inline_message(transfer, index) del self._file_transfers[(friend_number, file_number)] - def send_files(self, friend_number): + def send_files(self, friend_number:int) -> None: try: friend = self._get_friend_by_number(friend_number) if friend is None: return @@ -255,7 +255,7 @@ class FileTransfersHandler(ToxSave): except Exception as ex: LOG_ERROR('send_files EXCEPTION in file sending: ' + str(ex)) - def friend_exit(self, friend_number): + def friend_exit(self, friend_number:int) -> None: # RuntimeError: dictionary changed size during iteration lMayChangeDynamically = self._file_transfers.copy() for friend_num, file_num in lMayChangeDynamically: @@ -284,7 +284,7 @@ class FileTransfersHandler(ToxSave): # Avatars support - def send_avatar(self, friend_number, avatar_path=None): + def send_avatar(self, friend_number, avatar_path=None) -> None: """ :param friend_number: number of friend who should get new avatar :param avatar_path: path to avatar or None if reset @@ -309,7 +309,7 @@ class FileTransfersHandler(ToxSave): LOG_WARN(f"send_avatar EXCEPTION {e}") self.lBlockAvatars.append( (avatar_path, friend_number,) ) - def incoming_avatar(self, friend_number, file_number, size): + def incoming_avatar(self, friend_number, file_number, size) -> None: """ Friend changed avatar :param friend_number: friend number @@ -325,7 +325,7 @@ class FileTransfersHandler(ToxSave): elif not size: friend.reset_avatar(self._settings['identicons']) - def _send_avatar_to_contacts(self, _): + def _send_avatar_to_contacts(self, _) -> None: # from a callback friends = self._get_all_friends() for friend in filter(self._is_friend_online, friends): @@ -333,13 +333,13 @@ class FileTransfersHandler(ToxSave): # Private methods - def _is_friend_online(self, friend_number): + def _is_friend_online(self, friend_number:int) -> bool: friend = self._get_friend_by_number(friend_number) if friend is None: return None return friend.status is not None - def _get_friend_by_number(self, friend_number): + def _get_friend_by_number(self, friend_number:int): return self._contact_provider.get_friend_by_number(friend_number) def _get_all_friends(self): diff --git a/toxygen/file_transfers/file_transfers_messages_service.py b/toxygen/file_transfers/file_transfers_messages_service.py index ce7aa7b..1b292ee 100644 --- a/toxygen/file_transfers/file_transfers_messages_service.py +++ b/toxygen/file_transfers/file_transfers_messages_service.py @@ -1,9 +1,12 @@ +# -*- mode: python; indent-tabs-mode: nil; py-indent-offset: 4; coding: utf-8 -*- + +import logging + from messenger.messenger import * import utils.util as util from file_transfers.file_transfers import * global LOG -import logging LOG = logging.getLogger('app.'+__name__) from av.calls import LOG_ERROR, LOG_WARN, LOG_INFO, LOG_DEBUG, LOG_TRACE @@ -47,7 +50,7 @@ class FileTransfersMessagesService: return tm - def add_inline_message(self, transfer, index): + def add_inline_message(self, transfer, index) -> None: """callback""" if not self._is_friend_active(transfer.friend_number): return @@ -57,7 +60,8 @@ class FileTransfersMessagesService: return count = self._messages.count() if count + index + 1 >= 0: - self._create_inline_item(transfer.data, count + index + 1) + # assumes .data + self._create_inline_item(transfer, count + index + 1) def add_unsent_file_message(self, friend, file_path, data): assert friend @@ -74,7 +78,7 @@ class FileTransfersMessagesService: # Private methods - def _is_friend_active(self, friend_number): + def _is_friend_active(self, friend_number:int) -> bool: if not self._contacts_manager.is_active_a_friend(): return False diff --git a/toxygen/groups/group_ban.py b/toxygen/groups/group_ban.py index 89ecc7e..2b17a25 100644 --- a/toxygen/groups/group_ban.py +++ b/toxygen/groups/group_ban.py @@ -1,4 +1,4 @@ - +# -*- mode: python; indent-tabs-mode: nil; py-indent-offset: 4; coding: utf-8 -*- class GroupBan: diff --git a/toxygen/groups/group_invite.py b/toxygen/groups/group_invite.py index a2eed47..2332933 100644 --- a/toxygen/groups/group_invite.py +++ b/toxygen/groups/group_invite.py @@ -1,4 +1,4 @@ - +# -*- mode: python; indent-tabs-mode: nil; py-indent-offset: 4; coding: utf-8 -*- class GroupInvite: diff --git a/toxygen/groups/group_peer.py b/toxygen/groups/group_peer.py index 9e644ee..a96c751 100644 --- a/toxygen/groups/group_peer.py +++ b/toxygen/groups/group_peer.py @@ -1,4 +1,4 @@ - +# -*- mode: python; indent-tabs-mode: nil; py-indent-offset: 4; coding: utf-8 -*- class GroupChatPeer: """ diff --git a/toxygen/groups/groups_service.py b/toxygen/groups/groups_service.py index ec40104..0e52d2a 100644 --- a/toxygen/groups/groups_service.py +++ b/toxygen/groups/groups_service.py @@ -1,4 +1,5 @@ # -*- mode: python; indent-tabs-mode: nil; py-indent-offset: 4; coding: utf-8 -*- +import logging import common.tox_save as tox_save import utils.ui as util_ui @@ -9,7 +10,6 @@ from toxygen_wrapper.toxcore_enums_and_consts import * from toxygen_wrapper.tox import UINT32_MAX global LOG -import logging LOG = logging.getLogger('app.'+'gs') class GroupsService(tox_save.ToxSave): @@ -26,14 +26,14 @@ class GroupsService(tox_save.ToxSave): # maybe just use self self._tox = tox - def set_tox(self, tox): + def set_tox(self, tox) -> None: super().set_tox(tox) for group in self._get_all_groups(): group.set_tox(tox) # Groups creation - def create_new_gc(self, name, privacy_state, nick, status): + def create_new_gc(self, name, privacy_state, nick, status) -> None: try: group_number = self._tox.group_new(privacy_state, name, nick, status) except Exception as e: @@ -47,7 +47,7 @@ class GroupsService(tox_save.ToxSave): group.status = constants.TOX_USER_STATUS['NONE'] self._contacts_manager.update_filtration() - def join_gc_by_id(self, chat_id, password, nick, status): + def join_gc_by_id(self, chat_id, password, nick, status) -> None: try: group_number = self._tox.group_join(chat_id, password, nick, status) assert type(group_number) == int, group_number @@ -74,18 +74,18 @@ class GroupsService(tox_save.ToxSave): # Groups reconnect and leaving - def leave_group(self, group_number): + def leave_group(self, group_number) -> None: if type(group_number) == int: self._tox.group_leave(group_number) self._contacts_manager.delete_group(group_number) - def disconnect_from_group(self, group_number): + def disconnect_from_group(self, group_number) -> None: self._tox.group_disconnect(group_number) group = self._get_group_by_number(group_number) group.status = None self._clear_peers_list(group) - def reconnect_to_group(self, group_number): + def reconnect_to_group(self, group_number) -> None: self._tox.group_reconnect(group_number) group = self._get_group_by_number(group_number) group.status = constants.TOX_USER_STATUS['NONE'] @@ -93,7 +93,7 @@ class GroupsService(tox_save.ToxSave): # Group invites - def invite_friend(self, friend_number, group_number): + def invite_friend(self, friend_number, group_number) -> None: if self._tox.friend_get_connection_status(friend_number) == TOX_CONNECTION['NONE']: title = f"Error in group_invite_friend {friend_number}" e = f"Friend not connected friend_number={friend_number}" @@ -106,7 +106,7 @@ class GroupsService(tox_save.ToxSave): title = f"Error in group_invite_friend {group_number} {friend_number}" util_ui.message_box(title +'\n' +str(e), title) - def process_group_invite(self, friend_number, group_name, invite_data): + def process_group_invite(self, friend_number, group_name, invite_data) -> None: friend = self._get_friend_by_number(friend_number) # binary {invite_data} LOG.debug(f"process_group_invite {friend_number} {group_name}") @@ -114,7 +114,7 @@ class GroupsService(tox_save.ToxSave): self._group_invites.append(invite) self._update_invites_button_state() - def accept_group_invite(self, invite, name, status, password): + def accept_group_invite(self, invite, name, status, password) -> None: pk = invite.friend_public_key friend = self._get_friend_by_public_key(pk) LOG.debug(f"accept_group_invite {name}") @@ -122,7 +122,7 @@ class GroupsService(tox_save.ToxSave): self._delete_group_invite(invite) self._update_invites_button_state() - def decline_group_invite(self, invite): + def decline_group_invite(self, invite) -> None: self._delete_group_invite(invite) self._main_screen.update_gc_invites_button_state() @@ -142,7 +142,7 @@ class GroupsService(tox_save.ToxSave): group.name = self._tox.group_get_name(group.number) group.status_message = self._tox.group_get_topic(group.number) - def set_group_topic(self, group): + def set_group_topic(self, group) -> None: if not group.is_self_moderator_or_founder(): return text = util_ui.tr('New topic for group "{}":'.format(group.name)) @@ -153,29 +153,29 @@ class GroupsService(tox_save.ToxSave): self._tox.group_set_topic(group.number, topic) group.status_message = topic - def show_group_management_screen(self, group): + def show_group_management_screen(self, group) -> None: widgets_factory = self._get_widgets_factory() self._screen = widgets_factory.create_group_management_screen(group) self._screen.show() - def show_group_settings_screen(self, group): + def show_group_settings_screen(self, group) -> None: widgets_factory = self._get_widgets_factory() self._screen = widgets_factory.create_group_settings_screen(group) self._screen.show() - def set_group_password(self, group, password): + def set_group_password(self, group, password) -> None: if group.password == password: return self._tox.group_founder_set_password(group.number, password) group.password = password - def set_group_peers_limit(self, group, peers_limit): + def set_group_peers_limit(self, group, peers_limit) -> None: if group.peers_limit == peers_limit: return self._tox.group_founder_set_peer_limit(group.number, peers_limit) group.peers_limit = peers_limit - def set_group_privacy_state(self, group, privacy_state): + def set_group_privacy_state(self, group, privacy_state) -> None: is_private = privacy_state == constants.TOX_GROUP_PRIVACY_STATE['PRIVATE'] if group.is_private == is_private: return @@ -184,13 +184,13 @@ class GroupsService(tox_save.ToxSave): # Peers list - def generate_peers_list(self): + def generate_peers_list(self) -> None: if not self._contacts_manager.is_active_a_group(): return group = self._contacts_manager.get_curr_contact() PeersListGenerator().generate(group.peers, self, self._peers_list_widget, group.tox_id) - def peer_selected(self, chat_id, peer_id): + def peer_selected(self, chat_id, peer_id) -> None: widgets_factory = self._get_widgets_factory() group = self._get_group_by_public_key(chat_id) self_peer = group.get_self_peer() @@ -202,16 +202,16 @@ class GroupsService(tox_save.ToxSave): # Peers actions - def set_new_peer_role(self, group, peer, role): + def set_new_peer_role(self, group, peer, role) -> None: self._tox.group_mod_set_role(group.number, peer.id, role) peer.role = role self.generate_peers_list() - def toggle_ignore_peer(self, group, peer, ignore): + def toggle_ignore_peer(self, group, peer, ignore) -> None: self._tox.group_toggle_ignore(group.number, peer.id, ignore) peer.is_muted = ignore - def set_self_info(self, group, name, status): + def set_self_info(self, group, name, status) -> None: self._tox.group_self_set_name(group.number, name) self._tox.group_self_set_status(group.number, status) self_peer = group.get_self_peer() @@ -221,24 +221,24 @@ class GroupsService(tox_save.ToxSave): # Bans support - def show_bans_list(self, group): + def show_bans_list(self, group) -> None: return widgets_factory = self._get_widgets_factory() self._screen = widgets_factory.create_groups_bans_screen(group) self._screen.show() - def ban_peer(self, group, peer_id, ban_type): + def ban_peer(self, group, peer_id, ban_type) -> None: self._tox.group_mod_ban_peer(group.number, peer_id, ban_type) - def kick_peer(self, group, peer_id): + def kick_peer(self, group, peer_id) -> None: self._tox.group_mod_remove_peer(group.number, peer_id) - def cancel_ban(self, group_number, ban_id): + def cancel_ban(self, group_number, ban_id) -> None: self._tox.group_mod_remove_ban(group_number, ban_id) # Private methods - def _add_new_group_by_number(self, group_number): + def _add_new_group_by_number(self, group_number) -> None: LOG.debug(f"_add_new_group_by_number group_number={group_number}") self._contacts_manager.add_group(group_number) @@ -251,22 +251,22 @@ class GroupsService(tox_save.ToxSave): def _get_all_groups(self): return self._contacts_provider.get_all_groups() - def _get_friend_by_number(self, friend_number): + def _get_friend_by_number(self, friend_number:int): return self._contacts_provider.get_friend_by_number(friend_number) def _get_friend_by_public_key(self, public_key): return self._contacts_provider.get_friend_by_public_key(public_key) - def _clear_peers_list(self, group): + def _clear_peers_list(self, group) -> None: group.remove_all_peers_except_self() self.generate_peers_list() - def _delete_group_invite(self, invite): + def _delete_group_invite(self, invite) -> None: if invite in self._group_invites: self._group_invites.remove(invite) # status should be dropped - def _join_gc_via_invite(self, invite_data, friend_number, nick, status='', password=''): + def _join_gc_via_invite(self, invite_data, friend_number, nick, status='', password='') -> None: LOG.debug(f"_join_gc_via_invite friend_number={friend_number} nick={nick} datalen={len(invite_data)}") if nick is None: nick = '' @@ -284,8 +284,8 @@ class GroupsService(tox_save.ToxSave): LOG.error(f"_join_gc_via_invite group_number={group_number} {e}") return - def _update_invites_button_state(self): + def _update_invites_button_state(self) -> None: self._main_screen.update_gc_invites_button_state() - def _get_widgets_factory(self): + def _get_widgets_factory(self) -> None: return self._widgets_factory_provider.get_item() diff --git a/toxygen/groups/peers_list.py b/toxygen/groups/peers_list.py index c5aac34..97641d9 100644 --- a/toxygen/groups/peers_list.py +++ b/toxygen/groups/peers_list.py @@ -1,8 +1,9 @@ +# -*- mode: python; indent-tabs-mode: nil; py-indent-offset: 4; coding: utf-8 -*- + from ui.group_peers_list import PeerItem, PeerTypeItem from toxygen_wrapper.toxcore_enums_and_consts import * from ui.widgets import * - # Builder diff --git a/toxygen/history/history_logs_generators.py b/toxygen/history/history_logs_generators.py index 3e9e74d..91c0a28 100644 --- a/toxygen/history/history_logs_generators.py +++ b/toxygen/history/history_logs_generators.py @@ -1,3 +1,5 @@ +# -*- mode: python; indent-tabs-mode: nil; py-indent-offset: 4; coding: utf-8 -*- + import utils.util as util from messenger.messages import * diff --git a/toxygen/messenger/messages.py b/toxygen/messenger/messages.py index 47c6545..d44a7a9 100644 --- a/toxygen/messenger/messages.py +++ b/toxygen/messenger/messages.py @@ -1,3 +1,5 @@ +# -*- mode: python; indent-tabs-mode: nil; py-indent-offset: 4; coding: utf-8 -*- + import os.path from history.database import MESSAGE_AUTHOR @@ -67,7 +69,7 @@ class Message: def get_widget(self, *args): # FixMe - self._widget = self._create_widget(*args) + self._widget = self._create_widget(*args) # pylint: disable=assignment-from-none return self._widget @@ -86,7 +88,7 @@ class Message: return None @staticmethod - def _get_id(): + def _get_id() -> int: Message.MESSAGE_ID += 1 return int(Message.MESSAGE_ID) @@ -102,7 +104,7 @@ class TextMessage(Message): self._message = message self._id = message_id - def get_text(self): + def get_text(self) -> str: return self._message text = property(get_text) @@ -136,8 +138,8 @@ class OutgoingTextMessage(TextMessage): class GroupChatMessage(TextMessage): - def __init__(self, id, message, owner, iTime, message_type, name): - super().__init__(id, message, owner, iTime, message_type) + def __init__(self, cid, message, owner, iTime, message_type, name): + super().__init__(cid, message, owner, iTime, message_type) self._user_name = name @@ -153,13 +155,13 @@ class TransferMessage(Message): self._file_name = file_name self._friend_number, self._file_number = friend_number, file_number - def is_active(self, file_number): + def is_active(self, file_number) -> bool: if self._file_number != file_number: return False return self._state not in (FILE_TRANSFER_STATE['FINISHED'], FILE_TRANSFER_STATE['CANCELLED']) - def get_friend_number(self): + def get_friend_number(self) -> int: return self._friend_number friend_number = property(get_friend_number) diff --git a/toxygen/messenger/messenger.py b/toxygen/messenger/messenger.py index 099ef35..c38bc31 100644 --- a/toxygen/messenger/messenger.py +++ b/toxygen/messenger/messenger.py @@ -1,4 +1,5 @@ # -*- mode: python; indent-tabs-mode: nil; py-indent-offset: 4; coding: utf-8 -*- +import logging import common.tox_save as tox_save import utils.ui as util_ui @@ -7,7 +8,6 @@ from toxygen_wrapper.tests.support_testing import assert_main_thread from toxygen_wrapper.toxcore_enums_and_consts import TOX_MAX_MESSAGE_LENGTH global LOG -import logging LOG = logging.getLogger('app.'+__name__) log = lambda x: LOG.info(x) @@ -31,7 +31,7 @@ class Messenger(tox_save.ToxSave): def __repr__(self): return "" - def get_last_message(self): + def get_last_message(self) -> str: contact = self._contacts_manager.get_curr_contact() if contact is None: return str() @@ -40,7 +40,7 @@ class Messenger(tox_save.ToxSave): # Messaging - friends - def new_message(self, friend_number, message_type, message): + def new_message(self, friend_number, message_type, message) -> None: """ Current user gets new message :param friend_number: friend_num of friend who sent message @@ -52,7 +52,7 @@ class Messenger(tox_save.ToxSave): text_message = TextMessage(message, MessageAuthor(friend.name, MESSAGE_AUTHOR['FRIEND']), t, message_type) self._add_message(text_message, friend) - def send_message(self): + def send_message(self) -> None: text = self._screen.messageEdit.toPlainText() plugin_command_prefix = '/plugin ' @@ -88,7 +88,7 @@ class Messenger(tox_save.ToxSave): assert_main_thread() util_ui.message_box(text, title) - def send_message_to_friend(self, text, message_type, friend_number=None): + def send_message_to_friend(self, text, message_type, friend_number=None) -> None: """ Send message :param text: message text @@ -124,7 +124,7 @@ class Messenger(tox_save.ToxSave): self._screen.messageEdit.clear() self._screen.messages.scrollToBottom() - def send_messages(self, friend_number): + def send_messages(self, friend_number:int) -> None: """ Send 'offline' messages to friend """ @@ -140,7 +140,7 @@ class Messenger(tox_save.ToxSave): # Messaging - groups - def send_message_to_group(self, text, message_type, group_number=None): + def send_message_to_group(self, text, message_type, group_number=None) -> None: if group_number is None: group_number = self._contacts_manager.get_active_number() @@ -161,7 +161,7 @@ class Messenger(tox_save.ToxSave): self._screen.messageEdit.clear() self._screen.messages.scrollToBottom() - def new_group_message(self, group_number, message_type, message, peer_id): + def new_group_message(self, group_number, message_type, message, peer_id) -> None: """ Current user gets new message :param message_type: message type - plain text or action message (/me) @@ -181,7 +181,7 @@ class Messenger(tox_save.ToxSave): # Messaging - group peers - def send_message_to_group_peer(self, text, message_type, group_number=None, peer_id=None): + def send_message_to_group_peer(self, text, message_type, group_number=None, peer_id=None) -> None: if group_number is None or peer_id is None: group_peer_contact = self._contacts_manager.get_curr_contact() peer_id = group_peer_contact.number @@ -225,7 +225,7 @@ class Messenger(tox_save.ToxSave): self._screen.messageEdit.clear() self._screen.messages.scrollToBottom() - def new_group_private_message(self, group_number, message_type, message, peer_id): + def new_group_private_message(self, group_number, message_type, message, peer_id) -> None: """ Current user gets new message :param message: text of message @@ -246,13 +246,13 @@ class Messenger(tox_save.ToxSave): # Message receipts - def receipt(self, friend_number, message_id): + def receipt(self, friend_number, message_id) -> None: friend = self._get_friend_by_number(friend_number) friend.mark_as_sent(message_id) # Typing notifications - def send_typing(self, typing): + def send_typing(self, typing) -> None: """ Send typing notification to a friend """ @@ -261,7 +261,7 @@ class Messenger(tox_save.ToxSave): contact = self._contacts_manager.get_curr_contact() contact.typing_notification_handler.send(self._tox, typing) - def friend_typing(self, friend_number, typing): + def friend_typing(self, friend_number, typing) -> None: """ Display incoming typing notification """ @@ -270,7 +270,7 @@ class Messenger(tox_save.ToxSave): # Contact info updated - def new_friend_name(self, friend, old_name, new_name): + def new_friend_name(self, friend, old_name, new_name) -> None: if old_name == new_name or friend.has_alias(): return message = util_ui.tr('User {} is now known as {}') @@ -282,7 +282,7 @@ class Messenger(tox_save.ToxSave): # Private methods @staticmethod - def _split_message(message): + def _split_message(message) -> list: messages = [] while len(message) > TOX_MAX_MESSAGE_LENGTH: size = TOX_MAX_MESSAGE_LENGTH * 4 // 5 @@ -303,7 +303,7 @@ class Messenger(tox_save.ToxSave): return messages - def _get_friend_by_number(self, friend_number): + def _get_friend_by_number(self, friend_number:int): return self._contacts_provider.get_friend_by_number(friend_number) def _get_group_by_number(self, group_number): @@ -312,7 +312,7 @@ class Messenger(tox_save.ToxSave): def _get_group_by_public_key(self, public_key): return self._contacts_provider.get_group_by_public_key( public_key) - def _on_profile_name_changed(self, new_name): + def _on_profile_name_changed(self, new_name) -> None: if self._profile_name == new_name: return message = util_ui.tr('User {} is now known as {}') @@ -321,18 +321,18 @@ class Messenger(tox_save.ToxSave): self._add_info_message(friend.number, message) self._profile_name = new_name - def _on_call_started(self, friend_number, audio, video, is_outgoing): + def _on_call_started(self, friend_number, audio, video, is_outgoing) -> None: if is_outgoing: text = util_ui.tr("Outgoing video call") if video else util_ui.tr("Outgoing audio call") else: text = util_ui.tr("Incoming video call") if video else util_ui.tr("Incoming audio call") self._add_info_message(friend_number, text) - def _on_call_finished(self, friend_number, is_declined): + def _on_call_finished(self, friend_number, is_declined) -> None: text = util_ui.tr("Call declined") if is_declined else util_ui.tr("Call finished") self._add_info_message(friend_number, text) - def _add_info_message(self, friend_number, text): + def _add_info_message(self, friend_number, text) -> None: friend = self._get_friend_by_number(friend_number) assert friend message = InfoMessage(text, util.get_unix_time()) @@ -340,12 +340,12 @@ class Messenger(tox_save.ToxSave): if self._contacts_manager.is_friend_active(friend_number): self._create_info_message_item(message) - def _create_info_message_item(self, message): + def _create_info_message_item(self, message) -> None: assert_main_thread() self._items_factory.create_message_item(message) self._screen.messages.scrollToBottom() - def _add_message(self, text_message, contact): + def _add_message(self, text_message, contact) -> None: assert_main_thread() if not contact: LOG.warn("_add_message null contact") @@ -362,6 +362,6 @@ class Messenger(tox_save.ToxSave): if not contact.visibility: self._contacts_manager.update_filtration() - def _create_message_item(self, text_message): + def _create_message_item(self, text_message) -> None: # pixmap = self._contacts_manager.get_curr_contact().get_pixmap() self._items_factory.create_message_item(text_message) diff --git a/toxygen/middleware/callbacks.py b/toxygen/middleware/callbacks.py index 0c1e0a2..e0842f7 100644 --- a/toxygen/middleware/callbacks.py +++ b/toxygen/middleware/callbacks.py @@ -18,13 +18,13 @@ iMAX_INT32 = 4294967295 def LOG_ERROR(l): print(f"EROR. {l}") def LOG_WARN(l): print(f"WARN. {l}") def LOG_INFO(l): - bIsVerbose = not hasattr(__builtins__, 'app') or app.oArgs.loglevel <= 20-1 + bIsVerbose = not hasattr(__builtins__, 'app') or app.oArgs.loglevel <= 20-1 # pylint dusable=undefined-variable if bIsVerbose: print(f"INFO. {l}") def LOG_DEBUG(l): - bIsVerbose = not hasattr(__builtins__, 'app') or app.oArgs.loglevel <= 10-1 + bIsVerbose = not hasattr(__builtins__, 'app') or app.oArgs.loglevel <= 10-1 # pylint dusable=undefined-variable if bIsVerbose: print(f"DBUG. {l}") def LOG_TRACE(l): - bIsVerbose = not hasattr(__builtins__, 'app') or app.oArgs.loglevel < 10-1 + bIsVerbose = not hasattr(__builtins__, 'app') or app.oArgs.loglevel < 10-1 # pylint dusable=undefined-variable pass # print(f"TRACE. {l}") global aTIMES @@ -425,9 +425,9 @@ def video_receive_frame(toxav, friend_number, width, height, y, u, v, ystride, u frame[height * 5 // 4:, :width // 2] = v[:height // 2:2, :width // 2] frame[height * 5 // 4:, width // 2:] = v[1:height // 2:2, :width // 2] - frame = cv2.cvtColor(frame, cv2.COLOR_YUV2BGR_I420) + frame = cv2.cvtColor(frame, cv2.COLOR_YUV2BGR_I420) # pylint: disable=no-member # imshow - invoke_in_main_thread(cv2.imshow, str(friend_number), frame) + invoke_in_main_thread(cv2.imshow, str(friend_number), frame) # pylint: disable=no-member except Exception as ex: LOG_ERROR(f"video_receive_frame {ex} #{friend_number}") pass diff --git a/toxygen/network/tox_dns.py b/toxygen/network/tox_dns.py index 94ffd96..58c9da1 100644 --- a/toxygen/network/tox_dns.py +++ b/toxygen/network/tox_dns.py @@ -1,15 +1,19 @@ # -*- mode: python; indent-tabs-mode: nil; py-indent-offset: 4; coding: utf-8 -*- import json import urllib.request -import utils.util as util -from qtpy import QtNetwork, QtCore +import logging + try: import requests except ImportError: requests = None +from qtpy import QtNetwork, QtCore + +import utils.util as util global LOG -import logging + +iTIMEOUT=60 LOG = logging.getLogger('app.'+__name__) class ToxDns: @@ -55,7 +59,7 @@ class ToxDns: try: headers = dict() headers['Content-Type'] = 'application/json' - req = requests.get(url, headers=headers) + req = requests.get(url, headers=headers, timeout=iTIMEOUT) if req.status_code < 300: result = req.content return result diff --git a/toxygen/notifications/sound.py b/toxygen/notifications/sound.py index fce8e44..9df46b2 100644 --- a/toxygen/notifications/sound.py +++ b/toxygen/notifications/sound.py @@ -1,7 +1,10 @@ +# -*- mode: python; indent-tabs-mode: nil; py-indent-offset: 4; coding: utf-8 -*- + import os.path -import utils.util import wave +import utils.util + import toxygen_wrapper.tests.support_testing as ts with ts.ignoreStderr(): import pyaudio diff --git a/toxygen/notifications/tray.py b/toxygen/notifications/tray.py index 55dcf29..0a6bca3 100644 --- a/toxygen/notifications/tray.py +++ b/toxygen/notifications/tray.py @@ -1,5 +1,6 @@ -from qtpy import QtCore, QtWidgets +# -*- mode: python; indent-tabs-mode: nil; py-indent-offset: 4; coding: utf-8 -*- +from qtpy import QtCore, QtWidgets def tray_notification(title, text, tray, window): """ diff --git a/toxygen/plugin_support/plugin_support.py b/toxygen/plugin_support/plugin_support.py index d61c2cb..f180e4d 100644 --- a/toxygen/plugin_support/plugin_support.py +++ b/toxygen/plugin_support/plugin_support.py @@ -1,14 +1,15 @@ # -*- mode: python; indent-tabs-mode: nil; py-indent-offset: 4; coding: utf-8 -*- -import utils.util as util import os import importlib import inspect -import plugins.plugin_super_class as pl import sys +import logging + +import utils.util as util +import plugins.plugin_super_class as pl # LOG=util.log global LOG -import logging LOG = logging.getLogger('plugin_support') def trace(msg, *args, **kwargs): LOG._log(0, msg, []) LOG.trace = trace @@ -42,14 +43,14 @@ class PluginLoader: self._app = app self._plugins = {} # dict. key - plugin unique short name, value - Plugin instance - def set_tox(self, tox): + def set_tox(self, tox) -> None: """ New tox instance """ for plugin in self._plugins.values(): plugin.instance.set_tox(tox) - def load(self): + def load(self) -> None: """ Load all plugins in plugins folder """ @@ -100,7 +101,7 @@ class PluginLoader: LOG.info('Added plugin: ' +short_name +' from file: ' +fl) break - def callback_lossless(self, friend_number, data): + def callback_lossless(self, friend_number, data) -> None: """ New incoming custom lossless packet (callback) """ @@ -118,7 +119,7 @@ class PluginLoader: if name in self._plugins and self._plugins[name].is_active: self._plugins[name].instance.lossy_packet(''.join(chr(x) for x in data[l + 1:]), friend_number) - def friend_online(self, friend_number): + def friend_online(self, friend_number:int) -> None: """ Friend with specified number is online """ @@ -126,7 +127,7 @@ class PluginLoader: if plugin.is_active: plugin.instance.friend_connected(friend_number) - def get_plugins_list(self): + def get_plugins_list(self) -> list: """ Returns list of all plugins """ @@ -154,7 +155,7 @@ class PluginLoader: return None - def toggle_plugin(self, key): + def toggle_plugin(self, key) -> None: """ Enable/disable plugin :param key: plugin short name @@ -171,7 +172,7 @@ class PluginLoader: self._settings['plugins'].remove(key) self._settings.save() - def command(self, text): + def command(self, text) -> None: """ New command for plugin """ @@ -210,7 +211,7 @@ class PluginLoader: pass return result - def stop(self): + def stop(self) -> None: """ App is closing, stop all plugins """ @@ -219,7 +220,7 @@ class PluginLoader: self._plugins[key].instance.close() del self._plugins[key] - def reload(self): + def reload(self) -> None: path = util.get_plugins_directory() if not os.path.exists(path): self._app._log('WARN: Plugin directory not found: ' + path) diff --git a/toxygen/plugins/ae.py b/toxygen/plugins/ae.py index f0146cb..b30ea66 100644 --- a/toxygen/plugins/ae.py +++ b/toxygen/plugins/ae.py @@ -1,9 +1,11 @@ # -*- mode: python; indent-tabs-mode: nil; py-indent-offset: 4; coding: utf-8 -*- -import plugin_super_class import json -from user_data import settings import os +from qtpy import QtWidgets + from bootstrap.bootstrap import get_user_config_path +from user_data import settings +import plugin_super_class class AvatarEncryption(plugin_super_class.PluginSuperClass): @@ -17,7 +19,7 @@ class AvatarEncryption(plugin_super_class.PluginSuperClass): self._contacts = self._profile._contacts_provider.get_all_friends() def get_description(self): - return QApplication.translate("AvatarEncryption", 'Encrypt all avatars using profile password.') + return QtWidgets.QApplication.translate("AvatarEncryption", 'Encrypt all avatars using profile password.') def close(self): if not self._encrypt_save.has_password(): diff --git a/toxygen/plugins/awayl.py b/toxygen/plugins/awayl.py index 5df6109..9b63720 100644 --- a/toxygen/plugins/awayl.py +++ b/toxygen/plugins/awayl.py @@ -1,9 +1,12 @@ import plugin_super_class import threading -import time -from qtpy import QtCore, QtWidgets -from subprocess import check_output +# -*- mode: python; indent-tabs-mode: nil; py-indent-offset: 4; coding: utf-8 -*- + import json +from subprocess import check_output +import time + +from qtpy import QtCore, QtWidgets class InvokeEvent(QtCore.QEvent): diff --git a/toxygen/plugins/bday.py b/toxygen/plugins/bday.py index 6a6d327..8563638 100644 --- a/toxygen/plugins/bday.py +++ b/toxygen/plugins/bday.py @@ -1,8 +1,11 @@ -import plugin_super_class -from qtpy import QtWidgets, QtCore +# -*- mode: python; indent-tabs-mode: nil; py-indent-offset: 4; coding: utf-8 -*- + import json import importlib +from qtpy import QtWidgets, QtCore + +import plugin_super_class class BirthDay(plugin_super_class.PluginSuperClass): @@ -16,7 +19,7 @@ class BirthDay(plugin_super_class.PluginSuperClass): self._profile=self._app._ms._profile self._window = None - def start(self): + def start(self) -> None: now = self._datetime.datetime.now() today = {} x = self._profile.tox_id[:64] @@ -34,9 +37,9 @@ class BirthDay(plugin_super_class.PluginSuperClass): msgbox.exec_() def get_description(self): - return QApplication.translate("BirthDay", "Send and get notifications on your friends' birthdays.") + return QtWidgets.QApplication.translate("BirthDay", "Send and get notifications on your friends' birthdays.") - def get_window(self): + def get_window(self) -> None: inst = self x = self._profile.tox_id[:64] @@ -73,7 +76,7 @@ class BirthDay(plugin_super_class.PluginSuperClass): self._window = Window() return self._window - def lossless_packet(self, data, friend_number): + def lossless_packet(self, data, friend_number) -> None: if len(data): friend = self._profile.get_friend_by_number(friend_number) self._data[friend.tox_id] = data @@ -81,13 +84,13 @@ class BirthDay(plugin_super_class.PluginSuperClass): elif self._data['send_date'] and self._profile.tox_id[:64] in self._data: self.send_lossless(self._data[self._profile.tox_id[:64]], friend_number) - def friend_connected(self, friend_number): + def friend_connected(self, friend_number:int) -> None: timer = QtCore.QTimer() timer.timeout.connect(lambda: self.timer(friend_number)) timer.start(10000) self._timers.append(timer) - def timer(self, friend_number): + def timer(self, friend_number:int) -> None: timer = self._timers.pop() timer.stop() if self._profile.get_friend_by_number(friend_number).tox_id not in self._data: diff --git a/toxygen/plugins/bot.py b/toxygen/plugins/bot.py index bbd60d1..71db5a0 100644 --- a/toxygen/plugins/bot.py +++ b/toxygen/plugins/bot.py @@ -1,7 +1,9 @@ -import plugin_super_class -from qtpy import QtCore import time +from qtpy import QtCore, QtWidgets + +import plugin_super_class + class InvokeEvent(QtCore.QEvent): EVENT_TYPE = QtCore.QEvent.Type(QtCore.QEvent.registerEventType()) @@ -40,7 +42,7 @@ class Bot(plugin_super_class.PluginSuperClass): self._window = None def get_description(self): - return QApplication.translate("Bot", 'Plugin to answer bot to your friends.') + return QtWidgets.QApplication.translate("Bot", 'Plugin to answer bot to your friends.') def start(self): self._timer.start(10000) diff --git a/toxygen/plugins/chess.py b/toxygen/plugins/chess.py index 89c7785..f5c6feb 100644 --- a/toxygen/plugins/chess.py +++ b/toxygen/plugins/chess.py @@ -1,15 +1,16 @@ -# -*- coding: utf-8 -*- +# -*- mode: python; indent-tabs-mode: nil; py-indent-offset: 4; coding: utf-8 -*- import collections import re import math -import plugin_super_class +from qtpy import QtWidgets from qtpy.QtCore import * from qtpy.QtWidgets import * from qtpy.QtGui import * from qtpy.QtSvg import * +import plugin_super_class START_FEN = "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1" @@ -1621,7 +1622,7 @@ class Chess(plugin_super_class.PluginSuperClass): self._window = None def get_description(self): - return QApplication.translate("Chess", 'Plugin which allows you to play chess with your friends.') + return QtWidgets.QApplication.translate("Chess", 'Plugin which allows you to play chess with your friends.') def get_window(self): inst = self @@ -1690,6 +1691,6 @@ class Chess(plugin_super_class.PluginSuperClass): QTimer.singleShot(1000, self.resend_move) def get_menu(self, menu, num): - act = QAction(QApplication.translate("Chess", "Start chess game"), menu) + act = QAction(QtWidgets.QApplication.translate("Chess", "Start chess game"), menu) act.triggered.connect(lambda: self.start_game(num)) return [act] diff --git a/toxygen/plugins/garland.py b/toxygen/plugins/garland.py index 2ad5747..d6e1a0d 100644 --- a/toxygen/plugins/garland.py +++ b/toxygen/plugins/garland.py @@ -1,8 +1,11 @@ -import plugin_super_class +# -*- mode: python; indent-tabs-mode: nil; py-indent-offset: 4; coding: utf-8 -*- + import threading import time -from qtpy import QtCore +from qtpy import QtCore, QtWidgets + +from plugins.plugin_super_class import PluginSuperClass class InvokeEvent(QtCore.QEvent): EVENT_TYPE = QtCore.QEvent.Type(QtCore.QEvent.registerEventType()) @@ -27,7 +30,7 @@ def invoke_in_main_thread(fn, *args, **kwargs): QtCore.QCoreApplication.postEvent(_invoker, InvokeEvent(fn, *args, **kwargs)) -class Garland(plugin_super_class.PluginSuperClass): +class Garland(PluginSuperClass): def __init__(self, *args): super(Garland, self).__init__('Garland', 'grlnd', *args) @@ -39,7 +42,7 @@ class Garland(plugin_super_class.PluginSuperClass): self._window = None def get_description(self): - return QApplication.translate("Garland", "Changes your status like it's garland.") + return QtWidgets.QApplication.translate("Garland", "Changes your status like it's garland.") def close(self): self.stop() diff --git a/toxygen/plugins/mrq.py b/toxygen/plugins/mrq.py index 9136c6d..db718fe 100644 --- a/toxygen/plugins/mrq.py +++ b/toxygen/plugins/mrq.py @@ -1,9 +1,10 @@ # -*- mode: python; indent-tabs-mode: nil; py-indent-offset: 4; coding: utf-8 -*- -import plugin_super_class import threading import time -from qtpy import QtCore +from qtpy import QtCore, QtWidgets + +import plugin_super_class class InvokeEvent(QtCore.QEvent): EVENT_TYPE = QtCore.QEvent.Type(QtCore.QEvent.registerEventType()) @@ -40,7 +41,7 @@ class MarqueeStatus(plugin_super_class.PluginSuperClass): self._window = None def get_description(self): - return QApplication.translate("MarqueeStatus", 'Create ticker from your status message.') + return QtWidgets.QApplication.translate("MarqueeStatus", 'Create ticker from your status message.') def close(self): self.stop() diff --git a/toxygen/plugins/plugin_super_class.py b/toxygen/plugins/plugin_super_class.py index 0351253..4c6287d 100644 --- a/toxygen/plugins/plugin_super_class.py +++ b/toxygen/plugins/plugin_super_class.py @@ -1,17 +1,17 @@ # -*- mode: python; indent-tabs-mode: nil; py-indent-offset: 4; coding: utf-8 -*- import os + from qtpy import QtCore, QtWidgets + import utils.ui as util_ui import common.tox_save as tox_save - MAX_SHORT_NAME_LENGTH = 5 LOSSY_FIRST_BYTE = 200 LOSSLESS_FIRST_BYTE = 160 - def path_to_data(name): """ :param name: plugin unique name @@ -180,7 +180,7 @@ class PluginSuperClass(tox_save.ToxSave): """ pass - def friend_connected(self, friend_number): + def friend_connected(self, friend_number:int): """ Friend with specified number is online now """ diff --git a/toxygen/plugins/srch.py b/toxygen/plugins/srch.py index a7678e3..5dcf8d3 100644 --- a/toxygen/plugins/srch.py +++ b/toxygen/plugins/srch.py @@ -1,6 +1,8 @@ -import plugin_super_class +# -*- mode: python; indent-tabs-mode: nil; py-indent-offset: 4; coding: utf-8 -*- + from qtpy import QtGui, QtCore, QtWidgets +import plugin_super_class class SearchPlugin(plugin_super_class.PluginSuperClass): @@ -8,7 +10,7 @@ class SearchPlugin(plugin_super_class.PluginSuperClass): super(SearchPlugin, self).__init__('SearchPlugin', 'srch', *args) def get_description(self): - return QApplication.translate("SearchPlugin", 'Plugin search with search engines.') + return QtWidgets.QApplication.translate("SearchPlugin", 'Plugin search with search engines.') def get_message_menu(self, menu, text): google = QtWidgets.QAction( diff --git a/toxygen/plugins/toxid.py b/toxygen/plugins/toxid.py index 1646e57..e604092 100644 --- a/toxygen/plugins/toxid.py +++ b/toxygen/plugins/toxid.py @@ -1,9 +1,12 @@ -import plugin_super_class -from qtpy import QtCore, QtWidgets +# -*- mode: python; indent-tabs-mode: nil; py-indent-offset: 4; coding: utf-8 -*- + import json +from qtpy import QtCore, QtWidgets -class CopyableToxId(plugin_super_class.PluginSuperClass): +from plugins.plugin_super_class import PluginSuperClass + +class CopyableToxId(PluginSuperClass): def __init__(self, *args): super(CopyableToxId, self).__init__('CopyableToxId', 'toxid', *args) @@ -47,7 +50,7 @@ class CopyableToxId(plugin_super_class.PluginSuperClass): self._window = Window() return self._window - def lossless_packet(self, data, friend_number): + def lossless_packet(self, data, friend_number) -> None: if len(data): self._data['id'] = list(filter(lambda x: not x.startswith(data[:64]), self._data['id'])) self._data['id'].append(data) @@ -60,7 +63,7 @@ class CopyableToxId(plugin_super_class.PluginSuperClass): elif self._data['send_id']: self.send_lossless(self._tox.self_get_address(), friend_number) - def error(self): + def error(self) -> None: msgbox = QtWidgets.QMessageBox() title = QtWidgets.QApplication.translate("TOXID", "Error") msgbox.setWindowTitle(title.format(self._name)) @@ -68,7 +71,7 @@ class CopyableToxId(plugin_super_class.PluginSuperClass): msgbox.setText(text) msgbox.exec_() - def timer(self): + def timer(self) -> None: self._copy = False if self._curr + 1: public_key = self._tox.friend_get_public_key(self._curr) @@ -83,10 +86,10 @@ class CopyableToxId(plugin_super_class.PluginSuperClass): self.error() self._timer.stop() - def friend_connected(self, friend_number): + def friend_connected(self, friend_number:int): self.send_lossless('', friend_number) - def command(self, text): + def command(self, text) -> None: if text == 'copy': num = self._profile.get_active_number() if num == -1: @@ -129,8 +132,9 @@ help: show this help""") else: self.error() - def get_menu(self, menu, num): + def get_menu(self, menu, num) -> list: act = QtWidgets.QAction(QtWidgets.QApplication.translate("TOXID", "Copy TOX ID"), menu) friend = self._profile.get_friend(num) - act.connect(act, QtCore.SIGNAL("triggered()"), lambda: self.command('copy ' + str(friend.number))) + act.connect(act, QtCore.Signal("triggered()"), + lambda: self.command('copy ' + str(friend.number))) return [act] diff --git a/toxygen/smileys/smileys.py b/toxygen/smileys/smileys.py index 6bc50d2..604e681 100644 --- a/toxygen/smileys/smileys.py +++ b/toxygen/smileys/smileys.py @@ -1,12 +1,16 @@ -from utils import util +# -*- mode: python; indent-tabs-mode: nil; py-indent-offset: 4; coding: utf-8 -*- + import json +import logging import os from collections import OrderedDict + from qtpy import QtCore +from utils import util + # LOG=util.log global LOG -import logging LOG = logging.getLogger('app.'+__name__) log = lambda x: LOG.info(x) diff --git a/toxygen/stickers/stickers.py b/toxygen/stickers/stickers.py index 14142c7..56a0a29 100644 --- a/toxygen/stickers/stickers.py +++ b/toxygen/stickers/stickers.py @@ -1,7 +1,8 @@ +# -*- mode: python; indent-tabs-mode: nil; py-indent-offset: 4; coding: utf-8 -*- + import os import utils.util as util - def load_stickers(): """ :return list of stickers diff --git a/toxygen/styles/style.py b/toxygen/styles/style.py index 7a60366..dca54d8 100644 --- a/toxygen/styles/style.py +++ b/toxygen/styles/style.py @@ -1,4 +1,4 @@ -# -*- coding: utf-8 -*- +# -*- mode: python; indent-tabs-mode: nil; py-indent-offset: 4; coding: utf-8 -*- from qtpy import QtCore diff --git a/toxygen/tests/socks.py b/toxygen/tests/socks.py index 748fa8e..f9f730e 100644 --- a/toxygen/tests/socks.py +++ b/toxygen/tests/socks.py @@ -1,3 +1,5 @@ +# -*- mode: python; indent-tabs-mode: nil; py-indent-offset: 4; coding: utf-8 -*- + """SocksiPy - Python SOCKS module. Version 1.00 diff --git a/toxygen/tests/test_gdb.py b/toxygen/tests/test_gdb.py index 61ecea3..584987a 100644 --- a/toxygen/tests/test_gdb.py +++ b/toxygen/tests/test_gdb.py @@ -1,3 +1,5 @@ +# -*- mode: python; indent-tabs-mode: nil; py-indent-offset: 4; coding: utf-8 -*- + # Verify that gdb can pretty-print the various PyObject* types # # The code for testing gdb was adapted from similar work in Unladen Swallow's diff --git a/toxygen/third_party/qweechat/__init__.py b/toxygen/third_party/qweechat/__init__.py deleted file mode 100644 index f510618..0000000 --- a/toxygen/third_party/qweechat/__init__.py +++ /dev/null @@ -1,19 +0,0 @@ -# -*- coding: utf-8 -*- -# -# Copyright (C) 2011-2022 Sébastien Helleu -# -# This file is part of QWeeChat, a Qt remote GUI for WeeChat. -# -# QWeeChat is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 3 of the License, or -# (at your option) any later version. -# -# QWeeChat is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with QWeeChat. If not, see . -# diff --git a/toxygen/third_party/qweechat/about.py b/toxygen/third_party/qweechat/about.py deleted file mode 100644 index 8ec87ab..0000000 --- a/toxygen/third_party/qweechat/about.py +++ /dev/null @@ -1,61 +0,0 @@ -# -*- coding: utf-8 -*- -# -# about.py - about dialog box -# -# Copyright (C) 2011-2022 Sébastien Helleu -# -# This file is part of QWeeChat, a Qt remote GUI for WeeChat. -# -# QWeeChat is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 3 of the License, or -# (at your option) any later version. -# -# QWeeChat is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with QWeeChat. If not, see . -# - -"""About dialog box.""" - -from qtpy import QtCore, QtWidgets as QtGui - -from qweechat.version import qweechat_version - - -class AboutDialog(QtGui.QDialog): - """About dialog.""" - - def __init__(self, app_name, author, weechat_site, *args): - QtGui.QDialog.__init__(*(self,) + args) - self.setModal(True) - self.setWindowTitle('About') - - close_button = QtGui.QPushButton('Close') - close_button.pressed.connect(self.close) - - hbox = QtGui.QHBoxLayout() - hbox.addStretch(1) - hbox.addWidget(close_button) - hbox.addStretch(1) - - vbox = QtGui.QVBoxLayout() - messages = [ - f'{app_name} {qweechat_version()}', - f'© 2011-2022 {author}', - '', - f'{weechat_site}', - '', - ] - for msg in messages: - label = QtGui.QLabel(msg) - label.setAlignment(QtCore.Qt.AlignHCenter) - vbox.addWidget(label) - vbox.addLayout(hbox) - - self.setLayout(vbox) - self.show() diff --git a/toxygen/third_party/qweechat/buffer.py b/toxygen/third_party/qweechat/buffer.py deleted file mode 100644 index 9cca40e..0000000 --- a/toxygen/third_party/qweechat/buffer.py +++ /dev/null @@ -1,249 +0,0 @@ -# -*- coding: utf-8 -*- -# -# buffer.py - management of WeeChat buffers/nicklist -# -# Copyright (C) 2011-2022 Sébastien Helleu -# -# This file is part of QWeeChat, a Qt remote GUI for WeeChat. -# -# QWeeChat is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 3 of the License, or -# (at your option) any later version. -# -# QWeeChat is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with QWeeChat. If not, see . -# - -"""Management of WeeChat buffers/nicklist.""" - -from pkg_resources import resource_filename - -from qtpy import QtCore, QtGui, QtWidgets -from qtpy.QtCore import Signal - -from qweechat.chat import ChatTextEdit -from qweechat.input import InputLineEdit -from qweechat.weechat import color - - -class GenericListWidget(QtWidgets.QListWidget): - """Generic QListWidget with dynamic size.""" - - def __init__(self, *args): - super().__init__(*args) - self.setMaximumWidth(100) - self.setTextElideMode(QtCore.Qt.ElideNone) - self.setHorizontalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff) - self.setFocusPolicy(QtCore.Qt.NoFocus) - pal = self.palette() - pal.setColor(QtGui.QPalette.Highlight, QtGui.QColor('#ddddff')) - pal.setColor(QtGui.QPalette.HighlightedText, QtGui.QColor('black')) - self.setPalette(pal) - - def auto_resize(self): - size = self.sizeHintForColumn(0) - if size > 0: - size += 4 - self.setMaximumWidth(size) - - def clear(self, *args): - """Re-implement clear to set dynamic size after clear.""" - QtWidgets.QListWidget.clear(*(self,) + args) - self.auto_resize() - - def addItem(self, *args): - """Re-implement addItem to set dynamic size after add.""" - QtWidgets.QListWidget.addItem(*(self,) + args) - self.auto_resize() - - def insertItem(self, *args): - """Re-implement insertItem to set dynamic size after insert.""" - QtWidgets.QListWidget.insertItem(*(self,) + args) - self.auto_resize() - - -class BufferListWidget(GenericListWidget): - """Widget with list of buffers.""" - - def switch_prev_buffer(self): - if self.currentRow() > 0: - self.setCurrentRow(self.currentRow() - 1) - else: - self.setCurrentRow(self.count() - 1) - - def switch_next_buffer(self): - if self.currentRow() < self.count() - 1: - self.setCurrentRow(self.currentRow() + 1) - else: - self.setCurrentRow(0) - - -class BufferWidget(QtWidgets.QWidget): - """ - Widget with (from top to bottom): - title, chat + nicklist (optional) + prompt/input. - """ - - def __init__(self, display_nicklist=False): - super().__init__() - - # title - self.title = QtWidgets.QLineEdit() - self.title.setFocusPolicy(QtCore.Qt.NoFocus) - - # splitter with chat + nicklist - self.chat_nicklist = QtWidgets.QSplitter() - self.chat_nicklist.setSizePolicy(QtWidgets.QSizePolicy.Expanding, - QtWidgets.QSizePolicy.Expanding) - self.chat = ChatTextEdit(debug=False) - self.chat_nicklist.addWidget(self.chat) - self.nicklist = GenericListWidget() - if not display_nicklist: - self.nicklist.setVisible(False) - self.chat_nicklist.addWidget(self.nicklist) - - # prompt + input - self.hbox_edit = QtWidgets.QHBoxLayout() - self.hbox_edit.setContentsMargins(0, 0, 0, 0) - self.hbox_edit.setSpacing(0) - self.input = InputLineEdit(self.chat) - self.hbox_edit.addWidget(self.input) - prompt_input = QtWidgets.QWidget() - prompt_input.setLayout(self.hbox_edit) - - # vbox with title + chat/nicklist + prompt/input - vbox = QtWidgets.QVBoxLayout() - vbox.setContentsMargins(0, 0, 0, 0) - vbox.setSpacing(0) - vbox.addWidget(self.title) - vbox.addWidget(self.chat_nicklist) - vbox.addWidget(prompt_input) - - self.setLayout(vbox) - - def set_title(self, title): - """Set buffer title.""" - self.title.clear() - if title is not None: - self.title.setText(title) - - def set_prompt(self, prompt): - """Set prompt.""" - if self.hbox_edit.count() > 1: - self.hbox_edit.takeAt(0) - if prompt is not None: - label = QtWidgets.QLabel(prompt) - label.setContentsMargins(0, 0, 5, 0) - self.hbox_edit.insertWidget(0, label) - - -class Buffer(QtCore.QObject): - """A WeeChat buffer.""" - - bufferInput = Signal(str, str) - - def __init__(self, data=None): - QtCore.QObject.__init__(self) - self.data = data or {} - self.nicklist = {} - self.widget = BufferWidget(display_nicklist=self.data.get('nicklist', - 0)) - self.update_title() - self.update_prompt() - self.widget.input.textSent.connect(self.input_text_sent) - - def pointer(self): - """Return pointer on buffer.""" - return self.data.get('__path', [''])[0] - - def update_title(self): - """Update title.""" - try: - self.widget.set_title( - color.remove(self.data['title'])) - except Exception: # noqa: E722 - # TODO: Debug print the exception to be fixed. - # traceback.print_exc() - self.widget.set_title(None) - - def update_prompt(self): - """Update prompt.""" - try: - self.widget.set_prompt(self.data['local_variables']['nick']) - except Exception: # noqa: E722 - self.widget.set_prompt(None) - - def input_text_sent(self, text): - """Called when text has to be sent to buffer.""" - if self.data: - self.bufferInput.emit(self.data['full_name'], text) - - def nicklist_add_item(self, parent, group, prefix, name, visible): - """Add a group/nick in nicklist.""" - if group: - self.nicklist[name] = { - 'visible': visible, - 'nicks': [] - } - else: - self.nicklist[parent]['nicks'].append({ - 'prefix': prefix, - 'name': name, - 'visible': visible, - }) - - def nicklist_remove_item(self, parent, group, name): - """Remove a group/nick from nicklist.""" - if group: - if name in self.nicklist: - del self.nicklist[name] - else: - if parent in self.nicklist: - self.nicklist[parent]['nicks'] = [ - nick for nick in self.nicklist[parent]['nicks'] - if nick['name'] != name - ] - - def nicklist_update_item(self, parent, group, prefix, name, visible): - """Update a group/nick in nicklist.""" - if group: - if name in self.nicklist: - self.nicklist[name]['visible'] = visible - else: - if parent in self.nicklist: - for nick in self.nicklist[parent]['nicks']: - if nick['name'] == name: - nick['prefix'] = prefix - nick['visible'] = visible - break - - def nicklist_refresh(self): - """Refresh nicklist.""" - self.widget.nicklist.clear() - for group in sorted(self.nicklist): - for nick in sorted(self.nicklist[group]['nicks'], - key=lambda n: n['name']): - prefix_color = { - '': '', - ' ': '', - '+': 'yellow', - } - col = prefix_color.get(nick['prefix'], 'green') - if col: - icon = QtGui.QIcon( - resource_filename(__name__, - 'data/icons/bullet_%s_8x8.png' % - col)) - else: - pixmap = QtGui.QPixmap(8, 8) - pixmap.fill() - icon = QtGui.QIcon(pixmap) - item = QtWidgets.QListWidgetItem(icon, nick['name']) - self.widget.nicklist.addItem(item) - self.widget.nicklist.setVisible(True) diff --git a/toxygen/third_party/qweechat/chat.py b/toxygen/third_party/qweechat/chat.py deleted file mode 100644 index 43c4568..0000000 --- a/toxygen/third_party/qweechat/chat.py +++ /dev/null @@ -1,142 +0,0 @@ -# -*- coding: utf-8 -*- -# -# chat.py - chat area -# -# Copyright (C) 2011-2022 Sébastien Helleu -# -# This file is part of QWeeChat, a Qt remote GUI for WeeChat. -# -# QWeeChat is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 3 of the License, or -# (at your option) any later version. -# -# QWeeChat is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with QWeeChat. If not, see . -# - -"""Chat area.""" - -import datetime - -from qtpy import QtCore, QtWidgets, QtGui - -from qweechat import config -from qweechat.weechat import color - - -class ChatTextEdit(QtWidgets.QTextEdit): - """Chat area.""" - - def __init__(self, debug, *args): - QtWidgets.QTextEdit.__init__(*(self,) + args) - self.debug = debug - self.readOnly = True - self.setFocusPolicy(QtCore.Qt.NoFocus) - self.setFontFamily('monospace') - self._textcolor = self.textColor() - self._bgcolor = QtGui.QColor('#FFFFFF') - self._setcolorcode = { - 'F': (self.setTextColor, self._textcolor), - 'B': (self.setTextBackgroundColor, self._bgcolor) - } - self._setfont = { - '*': self.setFontWeight, - '_': self.setFontUnderline, - '/': self.setFontItalic - } - self._fontvalues = { - False: { - '*': QtGui.QFont.Normal, - '_': False, - '/': False - }, - True: { - '*': QtGui.QFont.Bold, - '_': True, - '/': True - } - } - self._color = color.Color(config.color_options(), self.debug) - - def display(self, time, prefix, text, forcecolor=None): - if time == 0: - now = datetime.datetime.now() - else: - now = datetime.datetime.fromtimestamp(float(time)) - self.setTextColor(QtGui.QColor('#999999')) - self.insertPlainText(now.strftime('%H:%M ')) - prefix = self._color.convert(prefix) - text = self._color.convert(text) - if forcecolor: - if prefix: - prefix = '\x01(F%s)%s' % (forcecolor, prefix) - text = '\x01(F%s)%s' % (forcecolor, text) - if prefix: - self._display_with_colors(prefix + ' ') - if text: - self._display_with_colors(text) - if text[-1:] != '\n': - self.insertPlainText('\n') - else: - self.insertPlainText('\n') - self.scroll_bottom() - - def _display_with_colors(self, string): - self.setTextColor(self._textcolor) - self.setTextBackgroundColor(self._bgcolor) - self._reset_attributes() - items = string.split('\x01') - for i, item in enumerate(items): - if i > 0 and item.startswith('('): - pos = item.find(')') - if pos >= 2: - action = item[1] - code = item[2:pos] - if action == '+': - # set attribute - self._set_attribute(code[0], True) - elif action == '-': - # remove attribute - self._set_attribute(code[0], False) - else: - # reset attributes and color - if code == 'r': - self._reset_attributes() - self._setcolorcode[action][0]( - self._setcolorcode[action][1]) - else: - # set attributes + color - while code.startswith(('*', '!', '/', '_', '|', - 'r')): - if code[0] == 'r': - self._reset_attributes() - elif code[0] in self._setfont: - self._set_attribute( - code[0], - not self._font[code[0]]) - code = code[1:] - if code: - self._setcolorcode[action][0]( - QtGui.QColor(code)) - item = item[pos+1:] - if len(item) > 0: - self.insertPlainText(item) - - def _reset_attributes(self): - self._font = {} - for attr in self._setfont: - self._set_attribute(attr, False) - - def _set_attribute(self, attr, value): - self._font[attr] = value - self._setfont[attr](self._fontvalues[self._font[attr]][attr]) - - def scroll_bottom(self): - scroll = self.verticalScrollBar() - scroll.setValue(scroll.maximum()) diff --git a/toxygen/third_party/qweechat/config.py b/toxygen/third_party/qweechat/config.py deleted file mode 100644 index ffdf793..0000000 --- a/toxygen/third_party/qweechat/config.py +++ /dev/null @@ -1,136 +0,0 @@ -# -*- coding: utf-8 -*- -# -# config.py - configuration for QWeeChat -# -# Copyright (C) 2011-2022 Sébastien Helleu -# -# This file is part of QWeeChat, a Qt remote GUI for WeeChat. -# -# QWeeChat is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 3 of the License, or -# (at your option) any later version. -# -# QWeeChat is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with QWeeChat. If not, see . -# - -"""Configuration for QWeeChat.""" - -import configparser -import os - -from pathlib import Path - -CONFIG_DIR = '%s/.config/qweechat' % os.getenv('HOME') -CONFIG_FILENAME = '%s/qweechat.conf' % CONFIG_DIR - -CONFIG_DEFAULT_RELAY_LINES = 50 - -CONFIG_DEFAULT_SECTIONS = ('relay', 'look', 'color') -CONFIG_DEFAULT_OPTIONS = (('relay.hostname', '127.0.0.1'), - ('relay.port', '9000'), - ('relay.ssl', 'off'), - ('relay.password', ''), - ('relay.autoconnect', 'off'), - ('relay.lines', str(CONFIG_DEFAULT_RELAY_LINES)), - ('look.debug', 'off'), - ('look.statusbar', 'on')) - -# Default colors for WeeChat color options (option name, #rgb value) -CONFIG_DEFAULT_COLOR_OPTIONS = ( - ('separator', '#000066'), # 0 - ('chat', '#000000'), # 1 - ('chat_time', '#999999'), # 2 - ('chat_time_delimiters', '#000000'), # 3 - ('chat_prefix_error', '#FF6633'), # 4 - ('chat_prefix_network', '#990099'), # 5 - ('chat_prefix_action', '#000000'), # 6 - ('chat_prefix_join', '#00CC00'), # 7 - ('chat_prefix_quit', '#CC0000'), # 8 - ('chat_prefix_more', '#CC00FF'), # 9 - ('chat_prefix_suffix', '#330099'), # 10 - ('chat_buffer', '#000000'), # 11 - ('chat_server', '#000000'), # 12 - ('chat_channel', '#000000'), # 13 - ('chat_nick', '#000000'), # 14 - ('chat_nick_self', '*#000000'), # 15 - ('chat_nick_other', '#000000'), # 16 - ('', '#000000'), # 17 (nick1 -- obsolete) - ('', '#000000'), # 18 (nick2 -- obsolete) - ('', '#000000'), # 19 (nick3 -- obsolete) - ('', '#000000'), # 20 (nick4 -- obsolete) - ('', '#000000'), # 21 (nick5 -- obsolete) - ('', '#000000'), # 22 (nick6 -- obsolete) - ('', '#000000'), # 23 (nick7 -- obsolete) - ('', '#000000'), # 24 (nick8 -- obsolete) - ('', '#000000'), # 25 (nick9 -- obsolete) - ('', '#000000'), # 26 (nick10 -- obsolete) - ('chat_host', '#666666'), # 27 - ('chat_delimiters', '#9999FF'), # 28 - ('chat_highlight', '#3399CC'), # 29 - ('chat_read_marker', '#000000'), # 30 - ('chat_text_found', '#000000'), # 31 - ('chat_value', '#000000'), # 32 - ('chat_prefix_buffer', '#000000'), # 33 - ('chat_tags', '#000000'), # 34 - ('chat_inactive_window', '#000000'), # 35 - ('chat_inactive_buffer', '#000000'), # 36 - ('chat_prefix_buffer_inactive_buffer', '#000000'), # 37 - ('chat_nick_offline', '#000000'), # 38 - ('chat_nick_offline_highlight', '#000000'), # 39 - ('chat_nick_prefix', '#000000'), # 40 - ('chat_nick_suffix', '#000000'), # 41 - ('emphasis', '#000000'), # 42 - ('chat_day_change', '#000000'), # 43 -) -config_color_options = [] - - -def read(): - """Read config file.""" - global config_color_options - config = configparser.RawConfigParser() - if os.path.isfile(CONFIG_FILENAME): - config.read(CONFIG_FILENAME) - - # add missing sections/options - for section in CONFIG_DEFAULT_SECTIONS: - if not config.has_section(section): - config.add_section(section) - for option in reversed(CONFIG_DEFAULT_OPTIONS): - section, name = option[0].split('.', 1) - if not config.has_option(section, name): - config.set(section, name, option[1]) - section = 'color' - for option in reversed(CONFIG_DEFAULT_COLOR_OPTIONS): - if option[0] and not config.has_option(section, option[0]): - config.set(section, option[0], option[1]) - - # build list of color options - config_color_options = [] - for option in CONFIG_DEFAULT_COLOR_OPTIONS: - if option[0]: - config_color_options.append(config.get('color', option[0])) - else: - config_color_options.append('#000000') - - return config - - -def write(config): - """Write config file.""" - Path(CONFIG_DIR).mkdir(mode=0o0700, parents=True, exist_ok=True) - with open(CONFIG_FILENAME, 'w') as cfg: - config.write(cfg) - - -def color_options(): - """Return color options.""" - global config_color_options - return config_color_options diff --git a/toxygen/third_party/qweechat/connection.py b/toxygen/third_party/qweechat/connection.py deleted file mode 100644 index 7f1884d..0000000 --- a/toxygen/third_party/qweechat/connection.py +++ /dev/null @@ -1,134 +0,0 @@ -# -*- coding: utf-8 -*- -# -# connection.py - connection window -# -# Copyright (C) 2011-2022 Sébastien Helleu -# -# This file is part of QWeeChat, a Qt remote GUI for WeeChat. -# -# QWeeChat is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 3 of the License, or -# (at your option) any later version. -# -# QWeeChat is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with QWeeChat. If not, see . -# - -"""Connection window.""" - -from qtpy import QtGui, QtWidgets - - -class ConnectionDialog(QtWidgets.QDialog): - """Connection window.""" - - def __init__(self, values, *args): - super().__init__(*args) - self.values = values - self.setModal(True) - self.setWindowTitle('Connect to WeeChat') - - grid = QtWidgets.QGridLayout() - grid.setSpacing(10) - - self.fields = {} - focus = None - - # hostname - grid.addWidget(QtWidgets.QLabel('Hostname'), 0, 0) - line_edit = QtWidgets.QLineEdit() - line_edit.setFixedWidth(200) - value = self.values.get('hostname', '') - if value in ['None', None]: - value = '0' - elif type(value) == int: - value = str(value) - line_edit.insert(value) - grid.addWidget(line_edit, 0, 1) - self.fields['hostname'] = line_edit - if not focus and not value: - focus = 'hostname' - - # port / SSL - grid.addWidget(QtWidgets.QLabel('Port'), 1, 0) - line_edit = QtWidgets.QLineEdit() - line_edit.setFixedWidth(200) - value = self.values.get('port', '') - if value in ['None', None]: - value = '0' - elif type(value) == int: - value = str(value) - line_edit.insert(value) - grid.addWidget(line_edit, 1, 1) - self.fields['port'] = line_edit - if not focus and not value: - focus = 'port' - - ssl = QtWidgets.QCheckBox('SSL') - ssl.setChecked(self.values['ssl'] == 'on') - grid.addWidget(ssl, 1, 2) - self.fields['ssl'] = ssl - - # password - grid.addWidget(QtWidgets.QLabel('Password'), 2, 0) - line_edit = QtWidgets.QLineEdit() - line_edit.setFixedWidth(200) - line_edit.setEchoMode(QtWidgets.QLineEdit.Password) - value = self.values.get('password', '') - if value in ['None', None]: - value = '0' - elif type(value) == int: - value = str(value) - line_edit.insert(value) - grid.addWidget(line_edit, 2, 1) - self.fields['password'] = line_edit - if not focus and not value: - focus = 'password' - - # TOTP (Time-Based One-Time Password) - label = QtWidgets.QLabel('TOTP') - label.setToolTip('Time-Based One-Time Password (6 digits)') - grid.addWidget(label, 3, 0) - line_edit = QtWidgets.QLineEdit() - line_edit.setPlaceholderText('6 digits') - validator = QtGui.QIntValidator(0, 999999, self) - line_edit.setValidator(validator) - line_edit.setFixedWidth(80) - value = self.values.get('totp', '') - line_edit.insert(value) - grid.addWidget(line_edit, 3, 1) - self.fields['totp'] = line_edit - if not focus and not value: - focus = 'totp' - - # lines - grid.addWidget(QtWidgets.QLabel('Lines'), 4, 0) - line_edit = QtWidgets.QLineEdit() - line_edit.setFixedWidth(200) - validator = QtGui.QIntValidator(0, 2147483647, self) - line_edit.setValidator(validator) - line_edit.setFixedWidth(80) - value = self.values.get('lines', '') - line_edit.insert(value) - grid.addWidget(line_edit, 4, 1) - self.fields['lines'] = line_edit - if not focus and not value: - focus = 'lines' - - self.dialog_buttons = QtWidgets.QDialogButtonBox() - self.dialog_buttons.setStandardButtons( - QtWidgets.QDialogButtonBox.Ok | QtWidgets.QDialogButtonBox.Cancel) - self.dialog_buttons.rejected.connect(self.close) - - grid.addWidget(self.dialog_buttons, 5, 0, 1, 2) - self.setLayout(grid) - self.show() - - if focus: - self.fields[focus].setFocus() diff --git a/toxygen/third_party/qweechat/debug.py b/toxygen/third_party/qweechat/debug.py deleted file mode 100644 index 48be08e..0000000 --- a/toxygen/third_party/qweechat/debug.py +++ /dev/null @@ -1,51 +0,0 @@ -# -*- coding: utf-8 -*- -# -# debug.py - debug window -# -# Copyright (C) 2011-2022 Sébastien Helleu -# -# This file is part of QWeeChat, a Qt remote GUI for WeeChat. -# -# QWeeChat is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 3 of the License, or -# (at your option) any later version. -# -# QWeeChat is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with QWeeChat. If not, see . -# - -"""Debug window.""" - -from qtpy import QtWidgets - -from qweechat.chat import ChatTextEdit -from qweechat.input import InputLineEdit - - -class DebugDialog(QtWidgets.QDialog): - """Debug dialog.""" - - def __init__(self, *args): - QtWidgets.QDialog.__init__(*(self,) + args) - self.resize(1024, 768) - self.setWindowTitle('Debug console') - - self.chat = ChatTextEdit(debug=True) - self.input = InputLineEdit(self.chat) - - vbox = QtWidgets.QVBoxLayout() - vbox.addWidget(self.chat) - vbox.addWidget(self.input) - - self.setLayout(vbox) - self.show() - - def display_lines(self, lines): - for line in lines: - self.chat.display(*line[0], **line[1]) diff --git a/toxygen/third_party/qweechat/input.py b/toxygen/third_party/qweechat/input.py deleted file mode 100644 index 98b05bd..0000000 --- a/toxygen/third_party/qweechat/input.py +++ /dev/null @@ -1,95 +0,0 @@ -# -*- coding: utf-8 -*- -# -# input.py - input line for chat and debug window -# -# Copyright (C) 2011-2022 Sébastien Helleu -# -# This file is part of QWeeChat, a Qt remote GUI for WeeChat. -# -# QWeeChat is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 3 of the License, or -# (at your option) any later version. -# -# QWeeChat is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with QWeeChat. If not, see . -# - -"""Input line for chat and debug window.""" - -from qtpy import QtCore, QtWidgets -from qtpy.QtCore import Signal - -class InputLineEdit(QtWidgets.QLineEdit): - """Input line.""" - - bufferSwitchPrev = Signal() - bufferSwitchNext = Signal() - textSent = Signal(str) - - def __init__(self, scroll_widget): - super().__init__() - self.scroll_widget = scroll_widget - self._history = [] - self._history_index = -1 - self.returnPressed.connect(self._input_return_pressed) - - def keyPressEvent(self, event): - key = event.key() - modifiers = event.modifiers() - scroll = self.scroll_widget.verticalScrollBar() - if modifiers == QtCore.Qt.ControlModifier: - if key == QtCore.Qt.Key_PageUp: - self.bufferSwitchPrev.emit() - elif key == QtCore.Qt.Key_PageDown: - self.bufferSwitchNext.emit() - else: - QtWidgets.QLineEdit.keyPressEvent(self, event) - elif modifiers == QtCore.Qt.AltModifier: - if key in (QtCore.Qt.Key_Left, QtCore.Qt.Key_Up): - self.bufferSwitchPrev.emit() - elif key in (QtCore.Qt.Key_Right, QtCore.Qt.Key_Down): - self.bufferSwitchNext.emit() - elif key == QtCore.Qt.Key_PageUp: - scroll.setValue(scroll.value() - (scroll.pageStep() / 10)) - elif key == QtCore.Qt.Key_PageDown: - scroll.setValue(scroll.value() + (scroll.pageStep() / 10)) - elif key == QtCore.Qt.Key_Home: - scroll.setValue(scroll.minimum()) - elif key == QtCore.Qt.Key_End: - scroll.setValue(scroll.maximum()) - else: - QtWidgets.QLineEdit.keyPressEvent(self, event) - elif key == QtCore.Qt.Key_PageUp: - scroll.setValue(scroll.value() - scroll.pageStep()) - elif key == QtCore.Qt.Key_PageDown: - scroll.setValue(scroll.value() + scroll.pageStep()) - elif key == QtCore.Qt.Key_Up: - self._history_navigate(-1) - elif key == QtCore.Qt.Key_Down: - self._history_navigate(1) - else: - QtWidgets.QLineEdit.keyPressEvent(self, event) - - def _input_return_pressed(self): - self._history.append(self.text()) - self._history_index = len(self._history) - self.textSent.emit(self.text()) - self.clear() - - def _history_navigate(self, direction): - if self._history: - self._history_index += direction - if self._history_index < 0: - self._history_index = 0 - return - if self._history_index > len(self._history) - 1: - self._history_index = len(self._history) - self.clear() - return - self.setText(self._history[self._history_index]) diff --git a/toxygen/third_party/qweechat/network.py b/toxygen/third_party/qweechat/network.py deleted file mode 100644 index 0127a98..0000000 --- a/toxygen/third_party/qweechat/network.py +++ /dev/null @@ -1,371 +0,0 @@ -# -*- coding: utf-8 -*- -# -# network.py - I/O with WeeChat/relay -# -# Copyright (C) 2011-2022 Sébastien Helleu -# -# This file is part of QWeeChat, a Qt remote GUI for WeeChat. -# -# QWeeChat is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 3 of the License, or -# (at your option) any later version. -# -# QWeeChat is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with QWeeChat. If not, see . -# - -"""I/O with WeeChat/relay.""" - -import hashlib -import secrets -import struct - -from qtpy import QtCore, QtNetwork -# from PyQt5.QtCore import pyqtSignal as Signal -from qtpy.QtCore import Signal - -from qweechat import config -from qweechat.debug import DebugDialog - - -# list of supported hash algorithms on our side -# (the hash algorithm will be negotiated with the remote WeeChat) -_HASH_ALGOS_LIST = [ - 'plain', - 'sha256', - 'sha512', - 'pbkdf2+sha256', - 'pbkdf2+sha512', -] -_HASH_ALGOS = ':'.join(_HASH_ALGOS_LIST) - -# handshake with remote WeeChat (before init) -_PROTO_HANDSHAKE = f'(handshake) handshake password_hash_algo={_HASH_ALGOS}\n' - -# initialize with the password (plain text) -_PROTO_INIT_PWD = 'init password=%(password)s%(totp)s\n' # nosec - -# initialize with the hashed password -_PROTO_INIT_HASH = ('init password_hash=' - '%(algo)s:%(salt)s%(iter)s:%(hash)s%(totp)s\n') - -_PROTO_SYNC_CMDS = [ - # get buffers - '(listbuffers) hdata buffer:gui_buffers(*) number,full_name,short_name,' - 'type,nicklist,title,local_variables', - # get lines - '(listlines) hdata buffer:gui_buffers(*)/own_lines/last_line(-%(lines)d)/' - 'data date,displayed,prefix,message', - # get nicklist for all buffers - '(nicklist) nicklist', - # enable synchronization - 'sync', -] - -STATUS_DISCONNECTED = 'disconnected' -STATUS_CONNECTING = 'connecting' -STATUS_AUTHENTICATING = 'authenticating' -STATUS_CONNECTED = 'connected' - -NETWORK_STATUS = { - STATUS_DISCONNECTED: { - 'label': 'Disconnected', - 'color': '#aa0000', - 'icon': 'dialog-close.png', - }, - STATUS_CONNECTING: { - 'label': 'Connecting…', - 'color': '#dd5f00', - 'icon': 'dialog-warning.png', - }, - STATUS_AUTHENTICATING: { - 'label': 'Authenticating…', - 'color': '#007fff', - 'icon': 'dialog-password.png', - }, - STATUS_CONNECTED: { - 'label': 'Connected', - 'color': 'green', - 'icon': 'dialog-ok-apply.png', - }, -} - - -class Network(QtCore.QObject): - """I/O with WeeChat/relay.""" - - statusChanged = Signal(str, str) - messageFromWeechat = Signal(QtCore.QByteArray) - - def __init__(self, *args): - super().__init__(*args) - self._init_connection() - self.debug_lines = [] - self.debug_dialog = None - self._lines = config.CONFIG_DEFAULT_RELAY_LINES - self._buffer = QtCore.QByteArray() - self._socket = QtNetwork.QSslSocket() - self._socket.connected.connect(self._socket_connected) - self._socket.readyRead.connect(self._socket_read) - self._socket.disconnected.connect(self._socket_disconnected) - - def _init_connection(self): - self.status = STATUS_DISCONNECTED - self._hostname = None - self._port = None - self._ssl = None - self._password = None - self._totp = None - self._handshake_received = False - self._handshake_timer = None - self._handshake_timer = False - self._pwd_hash_algo = None - self._pwd_hash_iter = 0 - self._server_nonce = None - - def set_status(self, status): - """Set current status.""" - self.status = status - self.statusChanged.emit(status, None) - - def pbkdf2(self, hash_name, salt): - """Return hashed password with PBKDF2-HMAC.""" - return hashlib.pbkdf2_hmac( - hash_name, - password=self._password.encode('utf-8'), - salt=salt, - iterations=self._pwd_hash_iter, - ).hex() - - def _build_init_command(self): - """Build the init command to send to WeeChat.""" - totp = f',totp={self._totp}' if self._totp else '' - if self._pwd_hash_algo == 'plain': - cmd = _PROTO_INIT_PWD % { - 'password': self._password, - 'totp': totp, - } - else: - client_nonce = secrets.token_bytes(16) - salt = self._server_nonce + client_nonce - pwd_hash = None - iterations = '' - if self._pwd_hash_algo == 'pbkdf2+sha512': - pwd_hash = self.pbkdf2('sha512', salt) - iterations = f':{self._pwd_hash_iter}' - elif self._pwd_hash_algo == 'pbkdf2+sha256': - pwd_hash = self.pbkdf2('sha256', salt) - iterations = f':{self._pwd_hash_iter}' - elif self._pwd_hash_algo == 'sha512': - pwd = salt + self._password.encode('utf-8') - pwd_hash = hashlib.sha512(pwd).hexdigest() - elif self._pwd_hash_algo == 'sha256': - pwd = salt + self._password.encode('utf-8') - pwd_hash = hashlib.sha256(pwd).hexdigest() - if not pwd_hash: - return None - cmd = _PROTO_INIT_HASH % { - 'algo': self._pwd_hash_algo, - 'salt': bytearray(salt).hex(), - 'iter': iterations, - 'hash': pwd_hash, - 'totp': totp, - } - return cmd - - def _build_sync_command(self): - """Build the sync commands to send to WeeChat.""" - cmd = '\n'.join(_PROTO_SYNC_CMDS) + '\n' - return cmd % {'lines': self._lines} - - def handshake_timer_expired(self): - if self.status == STATUS_AUTHENTICATING: - self._pwd_hash_algo = 'plain' - self.send_to_weechat(self._build_init_command()) - self.sync_weechat() - self.set_status(STATUS_CONNECTED) - - def _socket_connected(self): - """Slot: socket connected.""" - self.set_status(STATUS_AUTHENTICATING) - self.send_to_weechat(_PROTO_HANDSHAKE) - self._handshake_timer = QtCore.QTimer() - self._handshake_timer.setSingleShot(True) - self._handshake_timer.setInterval(2000) - self._handshake_timer.timeout.connect(self.handshake_timer_expired) - self._handshake_timer.start() - - def _socket_read(self): - """Slot: data available on socket.""" - data = self._socket.readAll() - self._buffer.append(data) - while len(self._buffer) >= 4: - remainder = None - length = struct.unpack('>i', self._buffer[0:4].data())[0] - if len(self._buffer) < length: - # partial message, just wait for end of message - break - # more than one message? - if length < len(self._buffer): - # save beginning of another message - remainder = self._buffer[length:] - self._buffer = self._buffer[0:length] - self.messageFromWeechat.emit(self._buffer) - if not self.is_connected(): - return - self._buffer.clear() - if remainder: - self._buffer.append(remainder) - - def _socket_disconnected(self): - """Slot: socket disconnected.""" - if self._handshake_timer: - self._handshake_timer.stop() - self._init_connection() - self.set_status(STATUS_DISCONNECTED) - - def is_connected(self): - """Return True if the socket is connected, False otherwise.""" - return is_state(self, at='ConnectedState') - - def is_state(self, at='ConnectedState'): - """Return True if the socket is connected, False otherwise.""" - if hasattr(QtNetwork.QAbstractSocket, 'ConnectedState'): - if self._socket.state() == getattr(QtNetwork.QAbstractSocket, at): - return True - return False - if hasattr(QtNetwork.QAbstractSocket, 'SocketState'): - if self._socket.state() == getattr(QtNetwork.QAbstractSocket.SocketState, at): - return True - return False - return False - - def is_ssl(self): - """Return True if SSL is used, False otherwise.""" - return self._ssl - - def connect_weechat(self, hostname, port, ssl, password, totp, lines): - """Connect to WeeChat.""" - self._hostname = hostname - try: - self._port = int(port) - except ValueError: - self._port = 0 - self._ssl = ssl - self._password = password - self._totp = totp - try: - self._lines = int(lines) - except ValueError: - self._lines = config.CONFIG_DEFAULT_RELAY_LINES - # AttributeError: type object 'QAbstractSocket' has no attribute 'ConnectedState' - if self.is_connected(): - return - if not self.is_state('UnconnectedState'): - self._socket.abort() - if self._ssl: - self._socket.ignoreSslErrors() - self._socket.connectToHostEncrypted(self._hostname, self._port) - else: - self._socket.connectToHost(self._hostname, self._port) - self.set_status(STATUS_CONNECTING) - - def disconnect_weechat(self): - """Disconnect from WeeChat.""" - if self.is_state('UnconnectedState'): - self.set_status(STATUS_DISCONNECTED) - return - if self.is_state('ConnectedState'): - self.send_to_weechat('quit\n') - self._socket.waitForBytesWritten(1000) - else: - self.set_status(STATUS_DISCONNECTED) - self._socket.abort() - - def send_to_weechat(self, message): - """Send a message to WeeChat.""" - self.debug_print(0, '<==', message, forcecolor='#AA0000') - self._socket.write(message.encode('utf-8')) - - def init_with_handshake(self, response): - """Initialize with WeeChat using the handshake response.""" - self._pwd_hash_algo = response['password_hash_algo'] - self._pwd_hash_iter = int(response['password_hash_iterations']) - self._server_nonce = bytearray.fromhex(response['nonce']) - if self._pwd_hash_algo: - cmd = self._build_init_command() - if cmd: - self.send_to_weechat(cmd) - self.sync_weechat() - self.set_status(STATUS_CONNECTED) - return - # failed to initialize: disconnect - self.disconnect_weechat() - - def desync_weechat(self): - """Desynchronize from WeeChat.""" - self.send_to_weechat('desync\n') - - def sync_weechat(self): - """Synchronize with WeeChat.""" - self.send_to_weechat(self._build_sync_command()) - - def status_label(self, status): - """Return the label for a given status.""" - return NETWORK_STATUS.get(status, {}).get('label', '') - - def status_color(self, status): - """Return the color for a given status.""" - return NETWORK_STATUS.get(status, {}).get('color', 'black') - - def status_icon(self, status): - """Return the name of icon for a given status.""" - return NETWORK_STATUS.get(status, {}).get('icon', '') - - def get_options(self): - """Get connection options.""" - return { - 'hostname': self._hostname, - 'port': self._port, - 'ssl': 'on' if self._ssl else 'off', - 'password': self._password, - 'lines': str(self._lines), - } - - def debug_print(self, *args, **kwargs): - """Display a debug message.""" - self.debug_lines.append((args, kwargs)) - if self.debug_dialog: - self.debug_dialog.chat.display(*args, **kwargs) - - def _debug_dialog_closed(self, result): - """Called when debug dialog is closed.""" - self.debug_dialog = None - - def debug_input_text_sent(self, text): - """Send debug buffer input to WeeChat.""" - if self.network.is_connected(): - text = str(text) - pos = text.find(')') - if text.startswith('(') and pos >= 0: - text = '(debug_%s)%s' % (text[1:pos], text[pos+1:]) - else: - text = '(debug) %s' % text - self.network.debug_print(0, '<==', text, forcecolor='#AA0000') - self.network.send_to_weechat(text + '\n') - - def open_debug_dialog(self): - """Open a dialog with debug messages.""" - if not self.debug_dialog: - self.debug_dialog = DebugDialog() - self.debug_dialog.input.textSent.connect( - self.debug_input_text_sent) - self.debug_dialog.finished.connect(self._debug_dialog_closed) - self.debug_dialog.display_lines(self.debug_lines) - self.debug_dialog.chat.scroll_bottom() diff --git a/toxygen/third_party/qweechat/preferences.py b/toxygen/third_party/qweechat/preferences.py deleted file mode 100644 index 64a3d79..0000000 --- a/toxygen/third_party/qweechat/preferences.py +++ /dev/null @@ -1,557 +0,0 @@ -# -*- coding: utf-8 -*- -# -# preferences.py - preferences dialog box -# -# Copyright (C) 2016 Ricky Brent -# -# This file is part of QWeeChat, a Qt remote GUI for WeeChat. -# -# QWeeChat is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 3 of the License, or -# (at your option) any later version. -# -# QWeeChat is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with QWeeChat. If not, see . -# - -import config -import utils -from inputlinespell import InputLineSpell - -from qtpy import QtCore, QtGui - -class PreferencesDialog(QtGui.QDialog): - """Preferences dialog.""" - - custom_sections = { - "look": "Look", - "input": "Input Box", - "nicks": "Nick List", - "buffers": "Buffer List", - "buffer_flags": False, - "notifications": "Notifications", - "color": "Colors", - "relay": "Relay/Connection" - } - - def __init__(self, name, parent, *args): - QtGui.QDialog.__init__(*(self,) + args) - self.setModal(True) - self.setWindowTitle(name) - self.parent = parent - self.config = parent.config - self.stacked_panes = QtGui.QStackedWidget() - self.list_panes = PreferencesTreeWidget("Settings") - - splitter = QtGui.QSplitter() - splitter.addWidget(self.list_panes) - splitter.addWidget(self.stacked_panes) - - # Follow same order as defaults: - section_panes = {} - for section in config.CONFIG_DEFAULT_SECTIONS: - item = QtGui.QTreeWidgetItem(section) - name = section - item.setText(0, section.title()) - if section in self.custom_sections: - if not self.custom_sections[section]: - continue - item.setText(0, self.custom_sections[section]) - section_panes[section] = PreferencesPaneWidget(section, name) - self.list_panes.addTopLevelItem(item) - self.stacked_panes.addWidget(section_panes[section]) - - for setting, default in config.CONFIG_DEFAULT_OPTIONS: - section_key = setting.split(".") - section = section_key[0] - key = ".".join(section_key[1:]) - section_panes[section].addItem( - key, self.config.get(section, key), default) - for key, value in self.config.items("color"): - section_panes["color"].addItem(key, value, False) - notification_field_count = len(section_panes["notifications"].fields) - notification = PreferencesNotificationBlock( - section_panes["notifications"]) - section_panes["notifications"].grid.addLayout( - notification, notification_field_count, 0, 1, -1) - - self.list_panes.currentItemChanged.connect(self._pane_switch) - self.list_panes.setCurrentItem(self.list_panes.topLevelItem(0)) - - hbox = QtGui.QHBoxLayout() - self.dialog_buttons = QtGui.QDialogButtonBox() - self.dialog_buttons.setStandardButtons( - QtGui.QDialogButtonBox.Save | QtGui.QDialogButtonBox.Cancel) - self.dialog_buttons.rejected.connect(self.close) - self.dialog_buttons.accepted.connect(self._save_and_close) - - hbox.addStretch(1) - hbox.addWidget(self.dialog_buttons) - hbox.addStretch(1) - - vbox = QtGui.QVBoxLayout() - vbox.addWidget(splitter) - vbox.addLayout(hbox) - - self.setLayout(vbox) - self.show() - - def _pane_switch(self, item): - """Switch the visible preference pane.""" - index = self.list_panes.indexOfTopLevelItem(item) - if index >= 0: - self.stacked_panes.setCurrentIndex(index) - - def _save_and_close(self): - for widget in (self.stacked_panes.widget(i) - for i in range(self.stacked_panes.count())): - for key, field in widget.fields.items(): - if isinstance(field, QtGui.QComboBox): - text = field.itemText(field.currentIndex()) - data = field.itemData(field.currentIndex()) - text = data if data else text - elif isinstance(field, QtGui.QCheckBox): - text = "on" if field.isChecked() else "off" - else: - text = field.text() - self.config.set(widget.section_name, key, str(text)) - config.write(self.config) - self.parent.apply_preferences() - self.close() - - -class PreferencesNotificationBlock(QtGui.QVBoxLayout): - """Display notification settings with drill down to configure.""" - def __init__(self, pane, *args): - QtGui.QVBoxLayout.__init__(*(self,) + args) - self.section = "notifications" - self.config = QtGui.QApplication.instance().config - self.pane = pane - self.stack = QtGui.QStackedWidget() - - self.table = QtGui.QTableWidget() - fg_color = self.table.palette().text().color().name() - self.action_labels = { - "sound": "Play a sound", - "message": "Show a message in a popup", - "file": "Log to a file", - "taskbar": "Mark taskbar entry", - "tray": "Mark systray/indicator", - "command": "Run a command"} - self.action_icons = { - "sound": utils.qicon_from_theme("media-playback-start"), - "message": utils.qicon_from_theme("dialog-information"), - "file": utils.qicon_from_theme("document-export"), - "taskbar": utils.qicon_from_theme("weechat"), - "tray": utils.qicon_tint("ic_hot", fg_color), - "command": utils.qicon_from_theme("system-run")} - self.icon_widget_qss = "padding:0;min-height:10px;min-width:16px;" - self.table.resizeColumnsToContents() - self.table.setColumnCount(2) - self.table.resizeRowsToContents() - self.table.setSelectionBehavior(QtGui.QAbstractItemView.SelectRows) - self.table.setSelectionMode(QtGui.QAbstractItemView.SingleSelection) - self.table.setHorizontalHeaderLabels(["State", "Type"]) - self.table.horizontalHeader().setStretchLastSection(True) - self.table.horizontalHeader().setHighlightSections(False) - self.table.verticalHeader().setVisible(False) - self.table.setShowGrid(False) - self.table.itemSelectionChanged.connect(self._table_row_changed) - - self.buftypes = {} - for key, value in config.CONFIG_DEFAULT_NOTIFICATION_OPTIONS: - buftype, optkey = key.split(".") - if buftype not in self.buftypes: - self.buftypes[buftype] = {} - self.buftypes[buftype][optkey] = self.config.get(self.section, key) - for buftype, optkey in self.buftypes.items(): - self._insert_type(buftype) - self.update_icons() - self.resize_table() - self.addWidget(self.table) - self.addWidget(self.stack) - self.table.selectRow(0) - - def _insert_type(self, buftype): - row = self.table.rowCount() - self.table.insertRow(row) - buftype_item = QtGui.QTableWidgetItem(buftype) - buftype_item.setTextAlignment(QtCore.Qt.AlignCenter) - self.table.setItem(row, 0, QtGui.QTableWidgetItem()) - self.table.setItem(row, 1, buftype_item) - subgrid = QtGui.QGridLayout() - subgrid.setColumnStretch(2, 1) - subgrid.setSpacing(10) - - for key, qicon in self.action_icons.items(): - value = self.buftypes[buftype][key] - line = subgrid.rowCount() - label = IconTextLabel(self.action_labels[key], qicon, 16) - - checkbox = QtGui.QCheckBox() - span = 1 - edit = None - if key in ("message", "taskbar", "tray"): - checkbox.setChecked(value == "on") - span = 2 - elif key == "sound": - edit = PreferencesFileEdit( - checkbox=checkbox, caption='Select a sound file', - filter='Audio Files (*.wav *.mp3 *.ogg)') - elif key == "file": - edit = PreferencesFileEdit(checkbox=checkbox, mode="save") - else: - edit = PreferencesFileEdit(checkbox=checkbox) - if edit: - edit.insert(value) - subgrid.addWidget(edit, line, 2) - else: - edit = checkbox - subgrid.addWidget(label, line, 1, 1, span) - subgrid.addWidget(checkbox, line, 0) - self.pane.fields[buftype + "." + key] = edit - subpane = QtGui.QWidget() - subpane.setLayout(subgrid) - subpane.setMaximumHeight(subgrid.totalMinimumSize().height()) - self.stack.addWidget(subpane) - - def resize_table(self): - """Fit the table height to contents.""" - height = self.table.horizontalHeader().height() - height = height * (self.table.rowCount() + 1) - height += self.table.contentsMargins().top() - height += self.table.contentsMargins().bottom() - self.table.setMaximumHeight(height) - self.table.setMinimumHeight(height) - self.table.setVerticalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff) - - def update_icons(self): - """Draw the correct icons in the left col.""" - for i in range(self.table.rowCount()): - hbox = QtGui.QHBoxLayout() - iconset = QtGui.QWidget() - buftype = self.table.item(i, 1).text() - for key, qicon in self.action_icons.items(): - field = self.pane.fields[buftype + "." + key] - if isinstance(field, QtGui.QCheckBox): - val = "on" if field.isChecked() else "off" - else: - val = field.text() - iconbtn = QtGui.QPushButton() - iconbtn.setContentsMargins(0, 0, 0, 0) - iconbtn.setFlat(True) - iconbtn.setFocusPolicy(QtCore.Qt.NoFocus) - if val and val != "off": - iconbtn.setIcon(qicon) - iconbtn.setStyleSheet(self.icon_widget_qss) - iconbtn.setToolTip(key) - iconbtn.clicked.connect(lambda i=i: self.table.selectRow(i)) - hbox.addWidget(iconbtn) - iconset.setLayout(hbox) - self.table.setCellWidget(i, 0, iconset) - - def _table_row_changed(self): - row = self.table.selectionModel().selectedRows()[0].row() - self.stack.setCurrentIndex(row) - - -class PreferencesTreeWidget(QtGui.QTreeWidget): - """Widget with tree list of preferences.""" - def __init__(self, header_label, *args): - QtGui.QTreeWidget.__init__(*(self,) + args) - self.setHeaderLabel(header_label) - self.setRootIsDecorated(False) - self.setMaximumWidth(180) - self.setTextElideMode(QtCore.Qt.ElideNone) - self.setHorizontalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff) - self.setFocusPolicy(QtCore.Qt.NoFocus) - - -class PreferencesSliderEdit(QtGui.QSlider): - """Percentage slider.""" - def __init__(self, *args): - QtGui.QSlider.__init__(*(self,) + args) - self.setMinimum(0) - self.setMaximum(100) - self.setTickPosition(QtGui.QSlider.TicksBelow) - self.setTickInterval(5) - - def insert(self, percent): - self.setValue(int(percent[:-1])) - - def text(self): - return str(self.value()) + "%" - - -class PreferencesColorEdit(QtGui.QPushButton): - """Simple color square that changes based on the color selected.""" - def __init__(self, *args): - QtGui.QPushButton.__init__(*(self,) + args) - self.color = "#000000" - self.clicked.connect(self._color_picker) - # Some of the configured colors use a astrisk prefix. - # Toggle this on right click. - self.star = False - self.setContextMenuPolicy(QtCore.Qt.CustomContextMenu) - self.customContextMenuRequested.connect(self._color_star) - - def insert(self, color): - """Insert the desired color for the widget.""" - if color[:1] == "*": - self.star = True - color = color[1:] - self.setText("*" if self.star else "") - self.color = color - self.setStyleSheet("background-color: " + color) - - def text(self): - """Returns the hex value of the color.""" - return ("*" if self.star else "") + self.color - - def _color_picker(self): - color = QtGui.QColorDialog.getColor(self.color) - self.insert(color.name()) - - def _color_star(self): - self.star = not self.star - self.insert(self.text()) - - -class PreferencesFontEdit(QtGui.QWidget): - """Font entry and selection.""" - def __init__(self, *args): - QtGui.QWidget.__init__(*(self,) + args) - layout = QtGui.QHBoxLayout() - self.checkbox = QtGui.QCheckBox() - self.edit = QtGui.QLineEdit() - self.font = "" - self.qfont = None - self.button = QtGui.QPushButton("C&hoose") - self.button.clicked.connect(self._font_picker) - self.checkbox.toggled.connect( - lambda: self._checkbox_toggled(self.checkbox)) - layout.addWidget(self.checkbox) - layout.addWidget(self.edit) - layout.addWidget(self.button) - layout.setContentsMargins(0, 0, 0, 0) - self.setLayout(layout) - - def insert(self, font_str): - """Insert the font described by the string.""" - self.font = font_str - self.edit.insert(font_str) - if font_str: - self.qfont = utils.Font.str_to_qfont(font_str) - self.edit.setFont(self.qfont) - self.checkbox.setChecked(True) - self._checkbox_toggled(self.checkbox) - else: - self.checkbox.setChecked(False) - self.qfont = None - self._checkbox_toggled(self.checkbox) - - def text(self): - """Returns the human readable font string.""" - return self.font - - def _font_picker(self): - font, ok = QtGui.QFontDialog.getFont(self.qfont) - if ok: - self.insert(utils.Font.qfont_to_str(font)) - - def _checkbox_toggled(self, button): - if button.isChecked() is False and not self.font == "": - self.insert("") - self.edit.setEnabled(button.isChecked()) - self.button.setEnabled(button.isChecked()) - - -class PreferencesFileEdit(QtGui.QWidget): - """File entry and selection.""" - def __init__(self, checkbox=None, caption="Select a file", filter=None, - mode="open", *args): - QtGui.QWidget.__init__(*(self,) + args) - layout = QtGui.QHBoxLayout() - self.caption = caption - self.filter = filter - self.edit = QtGui.QLineEdit() - self.file_str = "" - self.mode = mode - self.button = QtGui.QPushButton("B&rowse") - self.button.clicked.connect(self._file_picker) - if checkbox: - self.checkbox = checkbox - else: - self.checkbox = QtGui.QCheckBox() - layout.addWidget(self.checkbox) - self.checkbox.toggled.connect( - lambda: self._checkbox_toggled(self.checkbox)) - layout.addWidget(self.edit) - layout.addWidget(self.button) - layout.setContentsMargins(0, 0, 0, 0) - self.setLayout(layout) - - def insert(self, file_str): - """Insert the file.""" - self.file_str = file_str - self.edit.insert(file_str) - if file_str: - self.checkbox.setChecked(True) - self._checkbox_toggled(self.checkbox) - else: - self.checkbox.setChecked(False) - self._checkbox_toggled(self.checkbox) - - def text(self): - """Returns the human readable font string.""" - return self.file_str - - def _file_picker(self): - path = "" - if self.mode == "save": - fn = QtGui.QFileDialog.getSaveFileName - else: - fn = QtGui.QFileDialog.getOpenFileName - filename, fil = fn(self, self.caption, path, self.filter, self.filter) - if filename: - self.insert(filename) - - def _checkbox_toggled(self, button): - if button.isChecked() is False and not self.file_str == "": - self.insert("") - self.edit.setEnabled(button.isChecked()) - self.button.setEnabled(button.isChecked()) - - -class PreferencesPaneWidget(QtGui.QWidget): - """ - Widget with (from top to bottom): - title, chat + nicklist (optional) + prompt/input. - """ - - disabled_fields = ["show_hostnames", "hide_nick_changes", - "hide_join_and_part"] - - def __init__(self, section, section_name): - QtGui.QWidget.__init__(self) - self.grid = QtGui.QGridLayout() - self.grid.setAlignment(QtCore.Qt.AlignTop) - self.section = section - self.section_name = section_name - self.fields = {} - self.setLayout(self.grid) - self.grid.setColumnStretch(2, 1) - self.grid.setSpacing(10) - self.int_validator = QtGui.QIntValidator(0, 2147483647, self) - toolbar_icons = [ - ('ToolButtonFollowStyle', 'Default'), - ('ToolButtonIconOnly', 'Icon Only'), - ('ToolButtonTextOnly', 'Text Only'), - ('ToolButtonTextBesideIcon', 'Text Alongside Icons'), - ('ToolButtonTextUnderIcon', 'Text Under Icons')] - tray_options = [ - ('always', 'Always'), - ('unread', 'On Unread Messages'), - ('never', 'Never'), - ] - list_positions = [ - ('left', 'Left'), - ('right', 'Right'), - ] - sort_options = ['A-Z Ranked', 'A-Z', 'Z-A Ranked', 'Z-A'] - spellcheck_langs = [(x, x) for x in - InputLineSpell.list_languages()] - spellcheck_langs.insert(0, ('', '')) - focus_opts = ["requested", "always", "never"] - self.comboboxes = {"style": QtGui.QStyleFactory.keys(), - "position": list_positions, - "toolbar_icons": toolbar_icons, - "focus_new_tabs": focus_opts, - "tray_icon": tray_options, - "sort": sort_options, - "spellcheck_dictionary": spellcheck_langs} - - def addItem(self, key, value, default): - """Add a key-value pair.""" - line = len(self.fields) - name = key.split(".")[-1:][0].capitalize().replace("_", " ") - label = QtGui.QLabel(name) - start = 0 - - if self.section == "color": - start = 2 * (line % 2) - line = line // 2 - edit = PreferencesColorEdit() - edit.setFixedWidth(edit.sizeHint().height()) - edit.insert(value) - label.setAlignment(QtCore.Qt.AlignRight | QtCore.Qt.AlignVCenter) - elif key == "custom_stylesheet": - edit = PreferencesFileEdit(caption='Select QStyleSheet File', - filter='*.qss') - edit.insert(value) - elif name.lower()[-5:] == "sound": - edit = PreferencesFileEdit( - caption='Select a sound file', - filter='Audio Files (*.wav *.mp3 *.ogg)') - edit.insert(value) - elif name.lower()[-4:] == "font": - edit = PreferencesFontEdit() - edit.setFixedWidth(200) - edit.insert(value) - elif key in self.comboboxes.keys(): - edit = QtGui.QComboBox() - if len(self.comboboxes[key][0]) == 2: - for keyvalue in self.comboboxes[key]: - edit.addItem(keyvalue[1], keyvalue[0]) - # if self.section == "nicks" and key == "position": - # edit.addItem("below", "Below Buffer List") - # edit.addItem("above", "Above Buffer List") - edit.setCurrentIndex(edit.findData(value)) - else: - edit.addItems(self.comboboxes[key]) - edit.setCurrentIndex(edit.findText(value)) - edit.setFixedWidth(200) - elif default in ["on", "off"]: - edit = QtGui.QCheckBox() - edit.setChecked(value == "on") - elif default[-1:] == "%": - edit = PreferencesSliderEdit(QtCore.Qt.Horizontal) - edit.setFixedWidth(200) - edit.insert(value) - else: - edit = QtGui.QLineEdit() - edit.setFixedWidth(200) - edit.insert(value) - if default.isdigit() or key == "port": - edit.setValidator(self.int_validator) - if key == 'password': - edit.setEchoMode(QtGui.QLineEdit.Password) - if key in self.disabled_fields: - edit.setDisabled(True) - self.grid.addWidget(label, line, start + 0) - self.grid.addWidget(edit, line, start + 1) - - self.fields[key] = edit - - -class IconTextLabel(QtGui.QWidget): - """An icon next to text.""" - def __init__(self, text=None, icon=None, extent=None): - QtGui.QWidget.__init__(self) - text_label = QtGui.QLabel(text) - if not extent: - extent = text_label.height() - icon_label = QtGui.QLabel() - pixmap = icon.pixmap(extent, QtGui.QIcon.Normal, QtGui.QIcon.On) - icon_label.setPixmap(pixmap) - label_layout = QtGui.QHBoxLayout() - label_layout.addWidget(icon_label) - label_layout.addWidget(text_label) - label_layout.setAlignment(QtCore.Qt.AlignLeft | QtCore.Qt.AlignVCenter) - self.setLayout(label_layout) diff --git a/toxygen/third_party/qweechat/qweechat.py b/toxygen/third_party/qweechat/qweechat.py deleted file mode 100644 index ed6187a..0000000 --- a/toxygen/third_party/qweechat/qweechat.py +++ /dev/null @@ -1,554 +0,0 @@ -# -*- coding: utf-8 -*- -# -# qweechat.py - WeeChat remote GUI using Qt toolkit -# -# Copyright (C) 2011-2022 Sébastien Helleu -# -# This file is part of QWeeChat, a Qt remote GUI for WeeChat. -# -# QWeeChat is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 3 of the License, or -# (at your option) any later version. -# -# QWeeChat is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with QWeeChat. If not, see . -# - -""" -QWeeChat is a WeeChat remote GUI using Qt toolkit. - -It requires requires WeeChat 0.3.7 or newer, running on local or remote host. -""" - -# -# History: -# -# 2011-05-27, Sébastien Helleu : -# start dev -# - -import sys -import traceback -from pkg_resources import resource_filename - -from qtpy import QtCore, QtGui, QtWidgets - -from qweechat import config -from qweechat.about import AboutDialog -from qweechat.buffer import BufferListWidget, Buffer -from qweechat.connection import ConnectionDialog -from qweechat.network import Network, STATUS_DISCONNECTED -from qweechat.preferences import PreferencesDialog -from qweechat.weechat import protocol - - -APP_NAME = 'QWeeChat' -AUTHOR = 'Sébastien Helleu' -WEECHAT_SITE = 'https://weechat.org/' - -# not QFrame -class MainWindow(QtWidgets.QMainWindow): - """Main window.""" - - def __init__(self, *args): - super().__init__(*args) - - self.config = config.read() - - self.resize(1000, 600) - self.setWindowTitle(APP_NAME) - - self.about_dialog = None - self.connection_dialog = None - self.preferences_dialog = None - - # network - self.network = Network() - self.network.statusChanged.connect(self._network_status_changed) - self.network.messageFromWeechat.connect(self._network_weechat_msg) - - # list of buffers - self.list_buffers = BufferListWidget() - self.list_buffers.currentRowChanged.connect(self._buffer_switch) - - # default buffer - self.buffers = [Buffer()] - self.stacked_buffers = QtWidgets.QStackedWidget() - self.stacked_buffers.addWidget(self.buffers[0].widget) - - # splitter with buffers + chat/input - splitter = QtWidgets.QSplitter() - splitter.addWidget(self.list_buffers) - splitter.addWidget(self.stacked_buffers) - - self.list_buffers.setSizePolicy(QtWidgets.QSizePolicy.Preferred, - QtWidgets.QSizePolicy.Preferred) - self.stacked_buffers.setSizePolicy(QtWidgets.QSizePolicy.Expanding, - QtWidgets.QSizePolicy.Expanding) - # MainWindow - self.setCentralWidget(splitter) - - if self.config.getboolean('look', 'statusbar'): - self.statusBar().visible = True - self.statusBar().visible = True - - # actions for menu and toolbar - actions_def = { - 'connect': [ - 'network-connect.png', - 'Connect to WeeChat', - 'Ctrl+O', - self.open_connection_dialog, - ], - 'disconnect': [ - 'network-disconnect.png', - 'Disconnect from WeeChat', - 'Ctrl+D', - self.network.disconnect_weechat, - ], - 'debug': [ - 'edit-find.png', - 'Open debug console window', - 'Ctrl+B', - self.network.open_debug_dialog, - ], - 'preferences': [ - 'preferences-other.png', - 'Change preferences', - 'Ctrl+P', - self.open_preferences_dialog, - ], - 'about': [ - 'help-about.png', - 'About QWeeChat', - 'Ctrl+H', - self.open_about_dialog, - ], - 'save connection': [ - 'document-save.png', - 'Save connection configuration', - 'Ctrl+S', - self.save_connection, - ], - 'quit': [ - 'application-exit.png', - 'Quit application', - 'Ctrl+Q', - self.close, - ], - } - self.actions = {} - for name, action in list(actions_def.items()): - self.actions[name] = QtWidgets.QAction( - QtGui.QIcon( - resource_filename(__name__, 'data/icons/%s' % action[0])), - name.capitalize(), self) - self.actions[name].setToolTip(f'{action[1]} ({action[2]})') - self.actions[name].setShortcut(action[2]) - self.actions[name].triggered.connect(action[3]) - - # menu - self.menu = self.menuBar() - menu_file = self.menu.addMenu('&File') - menu_file.addActions([self.actions['connect'], - self.actions['disconnect'], - self.actions['preferences'], - self.actions['save connection'], - self.actions['quit']]) - menu_window = self.menu.addMenu('&Window') - menu_window.addAction(self.actions['debug']) - menu_help = self.menu.addMenu('&Help') - menu_help.addAction(self.actions['about']) - self.network_status = QtWidgets.QLabel() - self.network_status.setFixedHeight(20) - self.network_status.setFixedWidth(200) - self.network_status.setContentsMargins(0, 0, 10, 0) - self.network_status.setAlignment(QtCore.Qt.AlignRight) - if hasattr(self, 'menuBar'): - if hasattr(self.menu, 'setCornerWidget'): - self.menu.setCornerWidget(self.network_status, - QtCore.Qt.TopRightCorner) - self.network_status_set(STATUS_DISCONNECTED) - - # toolbar - if hasattr(self, 'addToolBar'): - toolbar = self.addToolBar('toolBar') - toolbar.setToolButtonStyle(QtCore.Qt.ToolButtonTextUnderIcon) - toolbar.addActions([self.actions['connect'], - self.actions['disconnect'], - self.actions['debug'], - self.actions['preferences'], - self.actions['about'], - self.actions['quit']]) - - self.buffers[0].widget.input.setFocus() - - # open debug dialog - if self.config.getboolean('look', 'debug'): - self.network.open_debug_dialog() - - # auto-connect to relay - if self.config.getboolean('relay', 'autoconnect'): - self.network.connect_weechat( - hostname=self.config.get('relay', 'hostname', fallback='127.0.0.1'), - port=self.config.get('relay', 'port', fallback='9000'), - ssl=self.config.getboolean('relay', 'ssl', fallback=''), - password=self.config.get('relay', 'password', fallback=''), - totp=None, - lines=self.config.get('relay', 'lines', fallback=''), - ) - - self.show() - - def _buffer_switch(self, index): - """Switch to a buffer.""" - if index >= 0: - self.stacked_buffers.setCurrentIndex(index) - self.stacked_buffers.widget(index).input.setFocus() - - def buffer_input(self, full_name, text): - """Send buffer input to WeeChat.""" - if self.network.is_connected(): - message = 'input %s %s\n' % (full_name, text) - self.network.send_to_weechat(message) - self.network.debug_print(0, '<==', message, forcecolor='#AA0000') - - def open_preferences_dialog(self): - """Open a dialog with preferences.""" - # TODO: implement the preferences dialog box - self.preferences_dialog = PreferencesDialog(self) - - def save_connection(self): - """Save connection configuration.""" - if self.network: - options = self.network.get_options() - for option in options: - self.config.set('relay', option, options[option]) - - def open_about_dialog(self): - """Open a dialog with info about QWeeChat.""" - self.about_dialog = AboutDialog(APP_NAME, AUTHOR, WEECHAT_SITE, self) - - def open_connection_dialog(self): - """Open a dialog with connection settings.""" - values = {} - for option in ('hostname', 'port', 'ssl', 'password', 'lines'): - values[option] = self.config.get('relay', option, fallback='') - self.connection_dialog = ConnectionDialog(values, self) - self.connection_dialog.dialog_buttons.accepted.connect( - self.connect_weechat) - - def connect_weechat(self): - """Connect to WeeChat.""" - self.network.connect_weechat( - hostname=self.connection_dialog.fields['hostname'].text(), - port=self.connection_dialog.fields['port'].text(), - ssl=self.connection_dialog.fields['ssl'].isChecked(), - password=self.connection_dialog.fields['password'].text(), - totp=self.connection_dialog.fields['totp'].text(), - lines=int(self.connection_dialog.fields['lines'].text()), - ) - self.connection_dialog.close() - - def _network_status_changed(self, status, extra): - """Called when the network status has changed.""" - if self.config.getboolean('look', 'statusbar'): - self.statusBar().showMessage(status) - self.network.debug_print(0, '', status, forcecolor='#0000AA') - self.network_status_set(status) - - def network_status_set(self, status): - """Set the network status.""" - pal = self.network_status.palette() - try: - pal.setColor(self.network_status.foregroundRole(), - self.network.status_color(status)) - except: - # dunno - pass - ssl = ' (SSL)' if status != STATUS_DISCONNECTED \ - and self.network.is_ssl() else '' - self.network_status.setPalette(pal) - icon = self.network.status_icon(status) - if icon: - self.network_status.setText( - ' %s' % - (resource_filename(__name__, 'data/icons/%s' % icon), - self.network.status_label(status) + ssl)) - else: - self.network_status.setText(status.capitalize()) - if status == STATUS_DISCONNECTED: - self.actions['connect'].setEnabled(True) - self.actions['disconnect'].setEnabled(False) - else: - self.actions['connect'].setEnabled(False) - self.actions['disconnect'].setEnabled(True) - - def _network_weechat_msg(self, message): - """Called when a message is received from WeeChat.""" - self.network.debug_print( - 0, '==>', - 'message (%d bytes):\n%s' - % (len(message), - protocol.hex_and_ascii(message.data(), 20)), - forcecolor='#008800', - ) - try: - proto = protocol.Protocol() - message = proto.decode(message.data()) - if message.uncompressed: - self.network.debug_print( - 0, '==>', - 'message uncompressed (%d bytes):\n%s' - % (message.size_uncompressed, - protocol.hex_and_ascii(message.uncompressed, 20)), - forcecolor='#008800') - self.network.debug_print(0, '', 'Message: %s' % message) - self.parse_message(message) - except Exception: # noqa: E722 - print('Error while decoding message from WeeChat:\n%s' - % traceback.format_exc()) - self.network.disconnect_weechat() - - def _parse_handshake(self, message): - """Parse a WeeChat message with handshake response.""" - for obj in message.objects: - if obj.objtype != 'htb': - continue - self.network.init_with_handshake(obj.value) - break - - def _parse_listbuffers(self, message): - """Parse a WeeChat message with list of buffers.""" - for obj in message.objects: - if obj.objtype != 'hda' or obj.value['path'][-1] != 'buffer': - continue - self.list_buffers.clear() - while self.stacked_buffers.count() > 0: - buf = self.stacked_buffers.widget(0) - self.stacked_buffers.removeWidget(buf) - self.buffers = [] - for item in obj.value['items']: - buf = self.create_buffer(item) - self.insert_buffer(len(self.buffers), buf) - self.list_buffers.setCurrentRow(0) - self.buffers[0].widget.input.setFocus() - - def _parse_line(self, message): - """Parse a WeeChat message with a buffer line.""" - for obj in message.objects: - lines = [] - if obj.objtype != 'hda' or obj.value['path'][-1] != 'line_data': - continue - for item in obj.value['items']: - if message.msgid == 'listlines': - ptrbuf = item['__path'][0] - else: - ptrbuf = item['buffer'] - index = [i for i, b in enumerate(self.buffers) - if b.pointer() == ptrbuf] - if index: - lines.append( - (index[0], - (item['date'], item['prefix'], - item['message'])) - ) - if message.msgid == 'listlines': - lines.reverse() - for line in lines: - self.buffers[line[0]].widget.chat.display(*line[1]) - - def _parse_nicklist(self, message): - """Parse a WeeChat message with a buffer nicklist.""" - buffer_refresh = {} - for obj in message.objects: - if obj.objtype != 'hda' or \ - obj.value['path'][-1] != 'nicklist_item': - continue - group = '__root' - for item in obj.value['items']: - index = [i for i, b in enumerate(self.buffers) - if b.pointer() == item['__path'][0]] - if index: - if not index[0] in buffer_refresh: - self.buffers[index[0]].nicklist = {} - buffer_refresh[index[0]] = True - if item['group']: - group = item['name'] - self.buffers[index[0]].nicklist_add_item( - group, item['group'], item['prefix'], item['name'], - item['visible']) - for index in buffer_refresh: - self.buffers[index].nicklist_refresh() - - def _parse_nicklist_diff(self, message): - """Parse a WeeChat message with a buffer nicklist diff.""" - buffer_refresh = {} - for obj in message.objects: - if obj.objtype != 'hda' or \ - obj.value['path'][-1] != 'nicklist_item': - continue - group = '__root' - for item in obj.value['items']: - index = [i for i, b in enumerate(self.buffers) - if b.pointer() == item['__path'][0]] - if not index: - continue - buffer_refresh[index[0]] = True - if item['_diff'] == ord('^'): - group = item['name'] - elif item['_diff'] == ord('+'): - self.buffers[index[0]].nicklist_add_item( - group, item['group'], item['prefix'], item['name'], - item['visible']) - elif item['_diff'] == ord('-'): - self.buffers[index[0]].nicklist_remove_item( - group, item['group'], item['name']) - elif item['_diff'] == ord('*'): - self.buffers[index[0]].nicklist_update_item( - group, item['group'], item['prefix'], item['name'], - item['visible']) - for index in buffer_refresh: - self.buffers[index].nicklist_refresh() - - def _parse_buffer_opened(self, message): - """Parse a WeeChat message with a new buffer (opened).""" - for obj in message.objects: - if obj.objtype != 'hda' or obj.value['path'][-1] != 'buffer': - continue - for item in obj.value['items']: - buf = self.create_buffer(item) - index = self.find_buffer_index_for_insert(item['next_buffer']) - self.insert_buffer(index, buf) - - def _parse_buffer(self, message): - """Parse a WeeChat message with a buffer event - (anything except a new buffer). - """ - for obj in message.objects: - if obj.objtype != 'hda' or obj.value['path'][-1] != 'buffer': - continue - for item in obj.value['items']: - index = [i for i, b in enumerate(self.buffers) - if b.pointer() == item['__path'][0]] - if not index: - continue - index = index[0] - if message.msgid == '_buffer_type_changed': - self.buffers[index].data['type'] = item['type'] - elif message.msgid in ('_buffer_moved', '_buffer_merged', - '_buffer_unmerged'): - buf = self.buffers[index] - buf.data['number'] = item['number'] - self.remove_buffer(index) - index2 = self.find_buffer_index_for_insert( - item['next_buffer']) - self.insert_buffer(index2, buf) - elif message.msgid == '_buffer_renamed': - self.buffers[index].data['full_name'] = item['full_name'] - self.buffers[index].data['short_name'] = item['short_name'] - elif message.msgid == '_buffer_title_changed': - self.buffers[index].data['title'] = item['title'] - self.buffers[index].update_title() - elif message.msgid == '_buffer_cleared': - self.buffers[index].widget.chat.clear() - elif message.msgid.startswith('_buffer_localvar_'): - self.buffers[index].data['local_variables'] = \ - item['local_variables'] - self.buffers[index].update_prompt() - elif message.msgid == '_buffer_closing': - self.remove_buffer(index) - - def parse_message(self, message): - """Parse a WeeChat message.""" - if message.msgid.startswith('debug'): - self.network.debug_print(0, '', '(debug message, ignored)') - elif message.msgid == 'handshake': - self._parse_handshake(message) - elif message.msgid == 'listbuffers': - self._parse_listbuffers(message) - elif message.msgid in ('listlines', '_buffer_line_added'): - self._parse_line(message) - elif message.msgid in ('_nicklist', 'nicklist'): - self._parse_nicklist(message) - elif message.msgid == '_nicklist_diff': - self._parse_nicklist_diff(message) - elif message.msgid == '_buffer_opened': - self._parse_buffer_opened(message) - elif message.msgid.startswith('_buffer_'): - self._parse_buffer(message) - elif message.msgid == '_upgrade': - self.network.desync_weechat() - elif message.msgid == '_upgrade_ended': - self.network.sync_weechat() - else: - print(f"Unknown message with id {message.msgid}") - - def create_buffer(self, item): - """Create a new buffer.""" - buf = Buffer(item) - buf.bufferInput.connect(self.buffer_input) - buf.widget.input.bufferSwitchPrev.connect( - self.list_buffers.switch_prev_buffer) - buf.widget.input.bufferSwitchNext.connect( - self.list_buffers.switch_next_buffer) - return buf - - def insert_buffer(self, index, buf): - """Insert a buffer in list.""" - self.buffers.insert(index, buf) - self.list_buffers.insertItem(index, '%s' - % (buf.data['local_variables']['name'])) - self.stacked_buffers.insertWidget(index, buf.widget) - - def remove_buffer(self, index): - """Remove a buffer.""" - if self.list_buffers.currentRow == index and index > 0: - self.list_buffers.setCurrentRow(index - 1) - self.list_buffers.takeItem(index) - self.stacked_buffers.removeWidget(self.stacked_buffers.widget(index)) - self.buffers.pop(index) - - def find_buffer_index_for_insert(self, next_buffer): - """Find position to insert a buffer in list.""" - index = -1 - if next_buffer == '0x0': - index = len(self.buffers) - else: - index = [i for i, b in enumerate(self.buffers) - if b.pointer() == next_buffer] - if index: - index = index[0] - if index < 0: - print('Warning: unable to find position for buffer, using end of ' - 'list by default') - index = len(self.buffers) - return index - - def closeEvent(self, event): - """Called when QWeeChat window is closed.""" - self.network.disconnect_weechat() - if self.network.debug_dialog: - self.network.debug_dialog.close() - config.write(self.config) - QtWidgets.QFrame.closeEvent(self, event) - - -def main(): - app = QtWidgets.QApplication(sys.argv) - app.setStyle(QtWidgets.QStyleFactory.create('Cleanlooks')) - app.setWindowIcon(QtGui.QIcon( - resource_filename(__name__, 'data/icons/weechat.png'))) - main_win = MainWindow() - main_win.show() - sys.exit(app.exec_()) - - -if __name__ == '__main__': - main() diff --git a/toxygen/third_party/qweechat/version.py b/toxygen/third_party/qweechat/version.py deleted file mode 100644 index 25bbf46..0000000 --- a/toxygen/third_party/qweechat/version.py +++ /dev/null @@ -1,30 +0,0 @@ -# -*- coding: utf-8 -*- -# -# version.py - version of QWeeChat -# -# Copyright (C) 2011-2022 Sébastien Helleu -# -# This file is part of QWeeChat, a Qt remote GUI for WeeChat. -# -# QWeeChat is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 3 of the License, or -# (at your option) any later version. -# -# QWeeChat is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with QWeeChat. If not, see . -# - -"""Version of QWeeChat.""" - -VERSION = '0.0.1-dev' - - -def qweechat_version(): - """Return QWeeChat version.""" - return VERSION diff --git a/toxygen/ui/av_widgets.py b/toxygen/ui/av_widgets.py index aafff73..e750231 100644 --- a/toxygen/ui/av_widgets.py +++ b/toxygen/ui/av_widgets.py @@ -1,7 +1,9 @@ +# -*- mode: python; indent-tabs-mode: nil; py-indent-offset: 4; coding: utf-8 -*- +import logging import threading +import wave from qtpy import QtCore, QtGui, QtWidgets -import wave from ui import widgets import utils.util as util @@ -10,7 +12,6 @@ with ts.ignoreStderr(): import pyaudio global LOG -import logging LOG = logging.getLogger('app.'+__name__) class IncomingCallWidget(widgets.CenteredWidget): @@ -66,7 +67,7 @@ class IncomingCallWidget(widgets.CenteredWidget): output_device_index = self._settings._oArgs.audio['output'] - if False and self._settings['calls_sound']: + if self._settings['calls_sound']: class SoundPlay(QtCore.QThread): def __init__(self): diff --git a/toxygen/ui/contact_items.py b/toxygen/ui/contact_items.py index 8938c3b..bdff447 100644 --- a/toxygen/ui/contact_items.py +++ b/toxygen/ui/contact_items.py @@ -1,5 +1,7 @@ -from toxygen_wrapper.toxcore_enums_and_consts import * +# -*- mode: python; indent-tabs-mode: nil; py-indent-offset: 4; coding: utf-8 -*- from qtpy import QtCore, QtGui, QtWidgets +from toxygen_wrapper.toxcore_enums_and_consts import * + from utils.util import * from ui.widgets import DataLabel diff --git a/toxygen/ui/create_profile_screen.py b/toxygen/ui/create_profile_screen.py index 041d5be..f507a1d 100644 --- a/toxygen/ui/create_profile_screen.py +++ b/toxygen/ui/create_profile_screen.py @@ -1,9 +1,11 @@ -from ui.widgets import * +# -*- mode: python; indent-tabs-mode: nil; py-indent-offset: 4; coding: utf-8 -*- + from qtpy import uic + +from ui.widgets import * import utils.util as util import utils.ui as util_ui - class CreateProfileScreenResult: def __init__(self, save_into_default_folder, password): diff --git a/toxygen/ui/group_bans_widgets.py b/toxygen/ui/group_bans_widgets.py index f5e31cf..60f1e9e 100644 --- a/toxygen/ui/group_bans_widgets.py +++ b/toxygen/ui/group_bans_widgets.py @@ -1,9 +1,11 @@ -from ui.widgets import CenteredWidget +# -*- mode: python; indent-tabs-mode: nil; py-indent-offset: 4; coding: utf-8 -*- + from qtpy import uic, QtWidgets, QtCore + +from ui.widgets import CenteredWidget import utils.util as util import utils.ui as util_ui - class GroupBanItem(QtWidgets.QWidget): def __init__(self, ban, cancel_ban, can_cancel_ban, parent=None): @@ -22,15 +24,20 @@ class GroupBanItem(QtWidgets.QWidget): ban_time = self._ban.ban_time self.banTimeLabel.setText(util.unix_time_to_long_str(ban_time)) - self.cancelPushButton.clicked.connect(self._cancel_ban) - self.cancelPushButton.setEnabled(self._can_cancel_ban) + self.cancelPushButton.clicked.connect(self.cancel_ban) + self.cancelPushButton.setEnabled(self.can_cancel_ban) def _retranslate_ui(self): self.cancelPushButton.setText(util_ui.tr('Cancel ban')) - def _cancel_ban(self): - self._cancel_ban(self._ban.ban_id) + def cancel_ban(self): # pylint: disable=method-hidden + # FixMe broken + # self._cancel_ban(self._ban.ban_id) + pass + def can_cancel_ban(self): # pylint: disable=method-hidden + # FixMe missing + pass class GroupBansScreen(CenteredWidget): diff --git a/toxygen/ui/group_invites_widgets.py b/toxygen/ui/group_invites_widgets.py index 46e7920..6b9fa9e 100644 --- a/toxygen/ui/group_invites_widgets.py +++ b/toxygen/ui/group_invites_widgets.py @@ -1,9 +1,12 @@ +# -*- mode: python; indent-tabs-mode: nil; py-indent-offset: 4; coding: utf-8 -*- + +import logging from qtpy import uic, QtWidgets + import utils.util as util from ui.widgets import * global LOG -import logging LOG = logging.getLogger('app') class GroupInviteItem(QtWidgets.QWidget): diff --git a/toxygen/ui/group_peers_list.py b/toxygen/ui/group_peers_list.py index f72bc62..ec8f95d 100644 --- a/toxygen/ui/group_peers_list.py +++ b/toxygen/ui/group_peers_list.py @@ -1,7 +1,8 @@ +# -*- mode: python; indent-tabs-mode: nil; py-indent-offset: 4; coding: utf-8 -*- + from ui.widgets import * from toxygen_wrapper.toxcore_enums_and_consts import * - class PeerItem(QtWidgets.QWidget): def __init__(self, peer, handler, width, parent=None): diff --git a/toxygen/ui/groups_widgets.py b/toxygen/ui/groups_widgets.py index 3fb01ab..ceda0ef 100644 --- a/toxygen/ui/groups_widgets.py +++ b/toxygen/ui/groups_widgets.py @@ -1,9 +1,11 @@ +# -*- mode: python; indent-tabs-mode: nil; py-indent-offset: 4; coding: utf-8 -*- + from qtpy import uic + import utils.util as util from ui.widgets import * from toxygen_wrapper.toxcore_enums_and_consts import * - class BaseGroupScreen(CenteredWidget): def __init__(self, groups_service, profile): diff --git a/toxygen/ui/items_factories.py b/toxygen/ui/items_factories.py index f6f38eb..530839c 100644 --- a/toxygen/ui/items_factories.py +++ b/toxygen/ui/items_factories.py @@ -1,7 +1,8 @@ +# -*- mode: python; indent-tabs-mode: nil; py-indent-offset: 4; coding: utf-8 -*- + from ui.contact_items import * from ui.messages_widgets import * - class ContactItemsFactory: def __init__(self, settings, main_screen): @@ -59,11 +60,14 @@ class MessagesItemsFactory: elem = QtWidgets.QListWidgetItem() # AttributeError: 'bytes' object has no attribute 'data' if type(message) == bytes: + # was used data = message elif hasattr(message, 'data'): + # used data = message.data else: - return + # unreached + return None item = InlineImageItem(data, self._messages.width(), elem, self._messages) elem.setSizeHint(QtCore.QSize(self._messages.width(), item.height())) if append: diff --git a/toxygen/ui/login_screen.py b/toxygen/ui/login_screen.py index 788aea4..93362fd 100644 --- a/toxygen/ui/login_screen.py +++ b/toxygen/ui/login_screen.py @@ -1,9 +1,12 @@ -from ui.widgets import * -from qtpy import uic -import utils.util as util -import utils.ui as util_ui +# -*- mode: python; indent-tabs-mode: nil; py-indent-offset: 4; coding: utf-8 -*- + import os.path +from qtpy import uic + +from ui.widgets import * +import utils.util as util +import utils.ui as util_ui class LoginScreenResult: diff --git a/toxygen/ui/main_screen.py b/toxygen/ui/main_screen.py index 27bbbeb..f65a0af 100644 --- a/toxygen/ui/main_screen.py +++ b/toxygen/ui/main_screen.py @@ -709,6 +709,9 @@ class MainWindow(QtWidgets.QMainWindow): except ImportError as e: LOG.error(f"ImportError Loading import qweechat {e} {sys.path}") LOG.debug(traceback.print_exc()) + text = f"ImportError Loading import qweechat {e} {sys.path}" + title = util_ui.tr('Error importing qweechat') + util_ui.message_box(text, title) return try: @@ -755,7 +758,8 @@ class MainWindow(QtWidgets.QMainWindow): # LOG.debug(e) font_width = size geometry = self._we.geometry() - geometry.setWidth(int(font_width*80+20)) + # make this configable? + geometry.setWidth(int(font_width*70)) geometry.setHeight(int(font_width*(2+24)*11/8)) self._we.setGeometry(geometry) #? QtCore.QSize() diff --git a/toxygen/ui/main_screen_widgets.py b/toxygen/ui/main_screen_widgets.py index ec1ff7a..064cb09 100644 --- a/toxygen/ui/main_screen_widgets.py +++ b/toxygen/ui/main_screen_widgets.py @@ -62,7 +62,7 @@ class MessageArea(QtWidgets.QPlainTextEdit): text = self.toPlainText() text_cursor = self.textCursor() pos = text_cursor.position() - current_word = re.split("\s+", text[:pos])[-1] + current_word = re.split(r"\s+", text[:pos])[-1] start_index = text.rindex(current_word, 0, pos) peer_name = self._contacts_manager.get_gc_peer_name(current_word) self.setPlainText(text[:start_index] + peer_name + text[pos:]) diff --git a/toxygen/ui/menu.py b/toxygen/ui/menu.py index a51a0f9..9f0fc05 100644 --- a/toxygen/ui/menu.py +++ b/toxygen/ui/menu.py @@ -21,10 +21,10 @@ oPYA = pyaudio.PyAudio() class AddContact(CenteredWidget): """Add contact form""" - def __init__(self, settings, contacts_manager, tox_id=''): + def __init__(self, dsettings, contacts_manager, tox_id=''): super().__init__() self._app = QtWidgets.QApplication.instance() - self._settings = settings + self._settings = dsettings self._contacts_manager = contacts_manager uic.loadUi(get_views_path('add_contact_screen'), self) self._update_ui(tox_id) @@ -75,10 +75,10 @@ class AddContact(CenteredWidget): class AddBootstrap(CenteredWidget): """Add bootstrap form""" - def __init__(self, settings, bootstraps_manager, tox_id=''): + def __init__(self, dsettings, bootstraps_manager, tox_id=''): super().__init__() self._app = QtWidgets.QApplication.instance() - self._settings = settings + self._settings = dsettings self._bootstraps_manager = bootstraps_manager uic.loadUi(get_views_path('add_bootstrap_screen'), self) self._update_ui(tox_id) @@ -122,10 +122,10 @@ class AddBootstrap(CenteredWidget): class NetworkSettings(CenteredWidget): """Network settings form: UDP, Ipv6 and proxy""" - def __init__(self, settings, reset): + def __init__(self, dsettings, reset): super().__init__() self._app = QtWidgets.QApplication.instance() - self._settings = settings + self._settings = dsettings self._reset = reset uic.loadUi(get_views_path('network_settings_screen'), self) self._update_ui() @@ -202,14 +202,14 @@ class NetworkSettings(CenteredWidget): class PrivacySettings(CenteredWidget): """Privacy settings form: history, typing notifications""" - def __init__(self, contacts_manager, settings): + def __init__(self, contacts_manager, dsettings): """ :type contacts_manager: ContactsManager """ super().__init__() self._app = QtWidgets.QApplication.instance() self._contacts_manager = contacts_manager - self._settings = settings + self._settings = dsettings self.initUI() self.center() @@ -324,10 +324,10 @@ class PrivacySettings(CenteredWidget): class NotificationsSettings(CenteredWidget): """Notifications settings form""" - def __init__(self, setttings): + def __init__(self, dsettings): super().__init__() self._app = QtWidgets.QApplication.instance() - self._settings = setttings + self._settings = dsettings # pylint: disable=undefined-variable uic.loadUi(get_views_path('notifications_settings_screen'), self) self._update_ui() self.center() @@ -357,10 +357,10 @@ class NotificationsSettings(CenteredWidget): class InterfaceSettings(CenteredWidget): """Interface settings form""" - def __init__(self, settings, smiley_loader): + def __init__(self, dsettings, smiley_loader): super().__init__() self._app = QtWidgets.QApplication.instance() - self._settings = settings + self._settings = dsettings self._smiley_loader = smiley_loader uic.loadUi(get_views_path('interface_settings_screen'), self) @@ -493,10 +493,10 @@ class AudioSettings(CenteredWidget): Audio calls settings form """ - def __init__(self, settings): + def __init__(self, dsettings): super().__init__() self._app = QtWidgets.QApplication.instance() - self._settings = settings + self._settings = dsettings self._in_indexes = self._out_indexes = None uic.loadUi(get_views_path('audio_settings_screen'), self) self._update_ui() @@ -554,10 +554,10 @@ class VideoSettings(CenteredWidget): Video calls settings form """ - def __init__(self, settings): + def __init__(self, dsettings): super().__init__() self._app = QtWidgets.QApplication.instance() - self._settings = settings + self._settings = dsettings uic.loadUi(get_views_path('video_settings_screen'), self) self._devices = self._frame_max_sizes = None self._update_ui() @@ -608,13 +608,13 @@ class VideoSettings(CenteredWidget): with ts.ignoreStdout(): # was range(10) for i in map(int, ts.get_video_indexes()): - v = cv2.VideoCapture(i) + v = cv2.VideoCapture(i) # pylint: disable=no-member if v.isOpened(): - v.set(cv2.CAP_PROP_FRAME_WIDTH, 10000) - v.set(cv2.CAP_PROP_FRAME_HEIGHT, 10000) + v.set(cv2.CAP_PROP_FRAME_WIDTH, 10000) # pylint: disable=no-member + v.set(cv2.CAP_PROP_FRAME_HEIGHT, 10000) # pylint: disable=no-member - width = int(v.get(cv2.CAP_PROP_FRAME_WIDTH)) - height = int(v.get(cv2.CAP_PROP_FRAME_HEIGHT)) + width = int(v.get(cv2.CAP_PROP_FRAME_WIDTH)) # pylint: disable=no-member + height = int(v.get(cv2.CAP_PROP_FRAME_HEIGHT)) # pylint: disable=no-member del v self._devices.append(i) self._frame_max_sizes.append((width, height)) @@ -758,10 +758,10 @@ class UpdateSettings(CenteredWidget): Updates settings form """ - def __init__(self, settings, version): + def __init__(self, dsettings, version): super().__init__() self._app = QtWidgets.QApplication.instance() - self._settings = settings + self._settings = dsettings self._version = version uic.loadUi(get_views_path('update_settings_screen'), self) self._update_ui() diff --git a/toxygen/ui/messages_widgets.py b/toxygen/ui/messages_widgets.py index 0c71511..2c0ddfb 100644 --- a/toxygen/ui/messages_widgets.py +++ b/toxygen/ui/messages_widgets.py @@ -1,13 +1,17 @@ +# -*- mode: python; indent-tabs-mode: nil; py-indent-offset: 4; coding: utf-8 -*- + +import html as h +import re + +from qtpy import QtCore, QtGui, QtWidgets + from toxygen_wrapper.toxcore_enums_and_consts import * import ui.widgets as widgets import utils.util as util import ui.menu as menu -import html as h -import re from ui.widgets import * from messenger.messages import MESSAGE_AUTHOR from file_transfers.file_transfers import * -from qtpy import QtCore, QtGui, QtWidgets class MessageBrowser(QtWidgets.QTextBrowser): diff --git a/toxygen/ui/password_screen.py b/toxygen/ui/password_screen.py index f4bd856..57f7b95 100644 --- a/toxygen/ui/password_screen.py +++ b/toxygen/ui/password_screen.py @@ -1,9 +1,12 @@ -from ui.widgets import CenteredWidget, LineEdit, DialogWithResult +# -*- mode: python; indent-tabs-mode: nil; py-indent-offset: 4; coding: utf-8 -*- + +import logging from qtpy import QtCore, QtWidgets + +from ui.widgets import CenteredWidget, LineEdit, DialogWithResult import utils.ui as util_ui global LOG -import logging LOG = logging.getLogger('app.'+__name__) class PasswordArea(LineEdit): diff --git a/toxygen/ui/peer_screen.py b/toxygen/ui/peer_screen.py index b5d0a9e..6bca903 100644 --- a/toxygen/ui/peer_screen.py +++ b/toxygen/ui/peer_screen.py @@ -1,5 +1,8 @@ -from ui.widgets import CenteredWidget +# -*- mode: python; indent-tabs-mode: nil; py-indent-offset: 4; coding: utf-8 -*- + from qtpy import uic + +from ui.widgets import CenteredWidget import utils.util as util import utils.ui as util_ui from ui.contact_items import * diff --git a/toxygen/ui/profile_settings_screen.py b/toxygen/ui/profile_settings_screen.py index 342f7c3..5b4658f 100644 --- a/toxygen/ui/profile_settings_screen.py +++ b/toxygen/ui/profile_settings_screen.py @@ -1,9 +1,11 @@ +# -*- mode: python; indent-tabs-mode: nil; py-indent-offset: 4; coding: utf-8 -*- + +from qtpy import QtGui, QtCore, uic + from ui.widgets import CenteredWidget import utils.ui as util_ui from utils.util import join_path, get_images_directory, get_views_path from user_data.settings import Settings -from qtpy import QtGui, QtCore, uic - class ProfileSettings(CenteredWidget): """Form with profile settings such as name, status, TOX ID""" diff --git a/toxygen/ui/self_peer_screen.py b/toxygen/ui/self_peer_screen.py index 69f148c..7f30653 100644 --- a/toxygen/ui/self_peer_screen.py +++ b/toxygen/ui/self_peer_screen.py @@ -1,5 +1,8 @@ -from ui.widgets import CenteredWidget, LineEdit +# -*- mode: python; indent-tabs-mode: nil; py-indent-offset: 4; coding: utf-8 -*- + from qtpy import uic + +from ui.widgets import CenteredWidget, LineEdit import utils.util as util import utils.ui as util_ui from ui.contact_items import * diff --git a/toxygen/ui/tray.py b/toxygen/ui/tray.py index fb02ba5..c838a0d 100644 --- a/toxygen/ui/tray.py +++ b/toxygen/ui/tray.py @@ -1,3 +1,5 @@ +# -*- mode: python; indent-tabs-mode: nil; py-indent-offset: 4; coding: utf-8 -*- + from qtpy import QtWidgets, QtGui, QtCore # from PyQt5.QtCore import pyqtSignal as Signal from qtpy.QtCore import Signal @@ -7,7 +9,6 @@ from utils.util import * from ui.password_screen import UnlockAppScreen import os.path - class SystemTrayIcon(QtWidgets.QSystemTrayIcon): # FixMe: AttributeError: module 'qtpy.QtCore' has no attribute 'pyqtSignal' leftClicked = Signal() diff --git a/toxygen/user_data/backup_service.py b/toxygen/user_data/backup_service.py index bb0cef9..9f3a051 100644 --- a/toxygen/user_data/backup_service.py +++ b/toxygen/user_data/backup_service.py @@ -1,6 +1,8 @@ -import os.path -from utils.util import get_profile_name_from_path, join_path +# -*- mode: python; indent-tabs-mode: nil; py-indent-offset: 4; coding: utf-8 -*- +import os.path + +from utils.util import get_profile_name_from_path, join_path class BackupService: diff --git a/toxygen/user_data/toxes.py b/toxygen/user_data/toxes.py index 982f287..84b8636 100644 --- a/toxygen/user_data/toxes.py +++ b/toxygen/user_data/toxes.py @@ -1,3 +1,4 @@ +# -*- mode: python; indent-tabs-mode: nil; py-indent-offset: 4; coding: utf-8 -*- class ToxES: diff --git a/toxygen/utils/ui.py b/toxygen/utils/ui.py index add4c09..f7d20e8 100644 --- a/toxygen/utils/ui.py +++ b/toxygen/utils/ui.py @@ -1,6 +1,8 @@ -from qtpy import QtWidgets -import utils.util as util +# -*- mode: python; indent-tabs-mode: nil; py-indent-offset: 4; coding: utf-8 -*- +from qtpy import QtWidgets + +import utils.util as util def tr(s): return QtWidgets.QApplication.translate('Toxygen', s) @@ -36,9 +38,9 @@ def file_dialog(caption, file_filter=None): options=QtWidgets.QFileDialog.DontUseNativeDialog) -def save_file_dialog(caption, filter=None): +def save_file_dialog(caption, file_filter=None): return QtWidgets.QFileDialog.getSaveFileName(None, caption, util.curr_directory(), - filter=filter, + filter=file_filter, options=QtWidgets.QFileDialog.ShowDirsOnly | QtWidgets.QFileDialog.DontUseNativeDialog) diff --git a/toxygen/utils/util.py b/toxygen/utils/util.py index 6bb0150..70cc7ff 100644 --- a/toxygen/utils/util.py +++ b/toxygen/utils/util.py @@ -33,7 +33,7 @@ def log(data=None): except Exception as ex: oFD = None print(f"ERROR: opening toxygen.log: {ex}") - return + return '' if data is None: return oFD try: oFD.write(str(data) +'\n')