Philipp Hörist pushed to branch master at gajim / gajim

Commits:

16 changed files:

Changes:

  • gajim/accounts_window.py
    ... ... @@ -258,10 +258,8 @@ class AccountsWindow(Gtk.ApplicationWindow):
    258 258
                     'accounts', account, 'name')
    
    259 259
             app.block_signed_in_notifications[account] = True
    
    260 260
             app.sleeper_state[account] = 'off'
    
    261
    -        app.encrypted_chats[account] = []
    
    262 261
             app.last_message_time[account] = {}
    
    263 262
             app.status_before_autoaway[account] = ''
    
    264
    -        app.transport_avatar[account] = {}
    
    265 263
             app.gajim_optional_features[account] = []
    
    266 264
             app.caps_hash[account] = ''
    
    267 265
             helpers.update_optional_features(account)
    
    ... ... @@ -292,10 +290,8 @@ class AccountsWindow(Gtk.ApplicationWindow):
    292 290
             del app.to_be_removed[account]
    
    293 291
             del app.newly_added[account]
    
    294 292
             del app.sleeper_state[account]
    
    295
    -        del app.encrypted_chats[account]
    
    296 293
             del app.last_message_time[account]
    
    297 294
             del app.status_before_autoaway[account]
    
    298
    -        del app.transport_avatar[account]
    
    299 295
             del app.gajim_optional_features[account]
    
    300 296
             del app.caps_hash[account]
    
    301 297
             if len(app.connections) >= 2:
    

  • gajim/common/app.py
    ... ... @@ -24,6 +24,9 @@
    24 24
     # You should have received a copy of the GNU General Public License
    
    25 25
     # along with Gajim. If not, see <http://www.gnu.org/licenses/>.
    
    26 26
     
    
    27
    +from typing import Dict  # pylint: disable=unused-import
    
    28
    +from typing import List  # pylint: disable=unused-import
    
    29
    +
    
    27 30
     import os
    
    28 31
     import sys
    
    29 32
     import logging
    
    ... ... @@ -68,53 +71,66 @@ css_config = None
    68 71
     
    
    69 72
     os_info = None # used to cache os information
    
    70 73
     
    
    71
    -transport_type = {} # list the type of transport
    
    74
    +transport_type = {}  # type: Dict[str, str]
    
    72 75
     
    
    73
    -last_message_time = {} # list of time of the latest incoming message
    
    74
    -                       # {acct1: {jid1: time1, jid2: time2}, }
    
    75
    -encrypted_chats = {}   # list of encrypted chats {acct1: [jid1, jid2], ..}
    
    76
    +# dict of time of the latest incoming message per jid
    
    77
    +# {acct1: {jid1: time1, jid2: time2}, }
    
    78
    +last_message_time = {}  # type: Dict[str, Dict[str, float]]
    
    76 79
     
    
    77 80
     contacts = LegacyContactsAPI()
    
    78
    -gc_connected = {}    # tell if we are connected to the room or not
    
    79
    -                     # {acct: {room_jid: True}}
    
    80
    -gc_passwords = {}    # list of the pass required to enter a room
    
    81
    -                     # {room_jid: password}
    
    82
    -automatic_rooms = {} # list of rooms that must be automaticaly configured
    
    83
    -                     # and for which we have a list of invities
    
    84
    -                     #{account: {room_jid: {'invities': []}}}
    
    85
    -
    
    86
    -groups = {} # list of groups
    
    87
    -newly_added = {} # list of contacts that has just signed in
    
    88
    -to_be_removed = {} # list of contacts that has just signed out
    
    81
    +
    
    82
    +# tell if we are connected to the room or not
    
    83
    +# {acct: {room_jid: True}}
    
    84
    +gc_connected = {}  # type: Dict[str, Dict[str, bool]]
    
    85
    +
    
    86
    +# dict of the pass required to enter a room
    
    87
    +# {room_jid: password}
    
    88
    +gc_passwords = {}  # type: Dict[str, str]
    
    89
    +
    
    90
    +# dict of rooms that must be automaticaly configured
    
    91
    +# and for which we have a list of invities
    
    92
    +# {account: {room_jid: {'invities': []}}}
    
    93
    +automatic_rooms = {}  # type: Dict[str, Dict[str, Dict[str, List[str]]]]
    
    94
    +
    
    95
    + # dict of groups, holds if they are expanded or not
    
    96
    +groups = {}  # type: Dict[str, Dict[str, Dict[str, bool]]]
    
    97
    +
    
    98
    +# list of contacts that has just signed in
    
    99
    +newly_added = {}  # type: Dict[str, List[str]]
    
    100
    +
    
    101
    +# list of contacts that has just signed out
    
    102
    +to_be_removed = {}  # type: Dict[str, List[str]]
    
    89 103
     
    
    90 104
     events = Events()
    
    91 105
     
    
    92 106
     notification = None
    
    93 107
     
    
    94
    -nicks = {} # list of our nick names in each account
    
    108
    +# list of our nick names in each account
    
    109
    +nicks = {}  # type: Dict[str, str]
    
    110
    +
    
    95 111
     # should we block 'contact signed in' notifications for this account?
    
    96 112
     # this is only for the first 30 seconds after we change our show
    
    97 113
     # to something else than offline
    
    98 114
     # can also contain account/transport_jid to block notifications for contacts
    
    99 115
     # from this transport
    
    100 116
     block_signed_in_notifications = {}
    
    101
    -con_types = {} # type of each connection (ssl, tls, tcp, ...)
    
    102 117
     
    
    103
    -sleeper_state = {} # whether we pass auto away / xa or not
    
    118
    + # type of each connection (ssl, tls, tcp, ...)
    
    119
    +con_types = {}  # type: Dict[str, Optional[str]]
    
    120
    +
    
    121
    +# whether we pass auto away / xa or not
    
    104 122
     #'off': don't use sleeper for this account
    
    105 123
     #'online': online and use sleeper
    
    106 124
     #'autoaway': autoaway and use sleeper
    
    107 125
     #'autoxa': autoxa and use sleeper
    
    108
    -status_before_autoaway = {}
    
    126
    +sleeper_state = {}  # type: Dict[str, str]
    
    109 127
     
    
    110
    -# jid of transport contacts for which we need to ask avatar when transport will
    
    111
    -# be online
    
    112
    -transport_avatar = {} # {transport_jid: [jid_list]}
    
    128
    +status_before_autoaway = {}  # type: Dict[str, str]
    
    113 129
     
    
    114 130
     # Is Gnome configured to activate on single click ?
    
    115 131
     single_click = False
    
    116 132
     SHOW_LIST = ['offline', 'connecting', 'online', 'chat', 'away', 'xa', 'dnd',
    
    117
    -        'invisible', 'error']
    
    133
    +             'invisible', 'error']
    
    118 134
     
    
    119 135
     # zeroconf account name
    
    120 136
     ZEROCONF_ACC_NAME = 'Local'
    

  • gajim/common/types.py
    ... ... @@ -32,6 +32,7 @@ if TYPE_CHECKING:
    32 32
         from gajim.common.zeroconf.connection_zeroconf import ConnectionZeroconf
    
    33 33
         from gajim.common.contacts import Contact
    
    34 34
         from gajim.common.contacts import GC_Contact
    
    35
    +    from gajim.common.nec import NetworkEvent
    
    35 36
     
    
    36 37
     ConnectionT = Union['Connection', 'ConnectionZeroconf']
    
    37 38
     ContactT = Union['Contact', 'GC_Contact']
    
    ... ... @@ -44,3 +45,9 @@ PEPHandlersDict = Dict[str, List[PEPNotifyCallback]]
    44 45
     
    
    45 46
     # Configpaths
    
    46 47
     PathTuple = Tuple[Optional[PathLocation], str, Optional[PathType]]
    
    48
    +
    
    49
    +# Plugins
    
    50
    +PluginExtensionPoints = Dict[str, Tuple[Optional[Callable[..., None]],
    
    51
    +                                        Optional[Callable[..., None]]]]
    
    52
    +EventHandlersDict = Dict[str, Tuple[int, Callable[['NetworkEvent'], Optional[bool]]]]
    
    53
    +PluginEvents = List['NetworkEvent']

  • gajim/config.py
    ... ... @@ -674,10 +674,8 @@ class RemoveAccountWindow:
    674 674
                 del app.to_be_removed[self.account]
    
    675 675
                 del app.newly_added[self.account]
    
    676 676
                 del app.sleeper_state[self.account]
    
    677
    -            del app.encrypted_chats[self.account]
    
    678 677
                 del app.last_message_time[self.account]
    
    679 678
                 del app.status_before_autoaway[self.account]
    
    680
    -            del app.transport_avatar[self.account]
    
    681 679
                 del app.gajim_optional_features[self.account]
    
    682 680
                 del app.caps_hash[self.account]
    
    683 681
             if len(app.connections) >= 2: # Do not merge accounts if only one exists
    

  • gajim/gtk/account_wizard.py
    ... ... @@ -582,10 +582,8 @@ class AccountCreationWizard:
    582 582
             app.nicks[self.account] = config['name']
    
    583 583
             app.block_signed_in_notifications[self.account] = True
    
    584 584
             app.sleeper_state[self.account] = 'off'
    
    585
    -        app.encrypted_chats[self.account] = []
    
    586 585
             app.last_message_time[self.account] = {}
    
    587 586
             app.status_before_autoaway[self.account] = ''
    
    588
    -        app.transport_avatar[self.account] = {}
    
    589 587
             app.gajim_optional_features[self.account] = []
    
    590 588
             app.caps_hash[self.account] = ''
    
    591 589
             helpers.update_optional_features(self.account)
    

  • gajim/gtk/const.py
    1
    +# This file is part of Gajim.
    
    2
    +#
    
    3
    +# Gajim is free software; you can redistribute it and/or modify
    
    4
    +# it under the terms of the GNU General Public License as published
    
    5
    +# by the Free Software Foundation; version 3 only.
    
    6
    +#
    
    7
    +# Gajim is distributed in the hope that it will be useful,
    
    8
    +# but WITHOUT ANY WARRANTY; without even the implied warranty of
    
    9
    +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    
    10
    +# GNU General Public License for more details.
    
    11
    +#
    
    12
    +# You should have received a copy of the GNU General Public License
    
    13
    +# along with Gajim. If not, see <http://www.gnu.org/licenses/>.
    
    14
    +
    
    15
    +# Constants for the gtk module
    
    16
    +
    
    17
    +from collections import namedtuple
    
    18
    +
    
    19
    +Filter = namedtuple('Filter', 'name pattern default')

  • gajim/gtk/emoji_data.py
    1
    +# This file is part of Gajim.
    
    2
    +#
    
    3
    +# Gajim is free software; you can redistribute it and/or modify
    
    4
    +# it under the terms of the GNU General Public License as published
    
    5
    +# by the Free Software Foundation; version 3 only.
    
    6
    +#
    
    7
    +# Gajim is distributed in the hope that it will be useful,
    
    8
    +# but WITHOUT ANY WARRANTY; without even the implied warranty of
    
    9
    +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    
    10
    +# GNU General Public License for more details.
    
    11
    +#
    
    12
    +# You should have received a copy of the GNU General Public License
    
    13
    +# along with Gajim. If not, see <http://www.gnu.org/licenses/>.
    
    14
    +
    
    1 15
     import re
    
    2 16
     import weakref
    
    3 17
     from enum import IntEnum
    

  • gajim/gtk/emoji_data.pyi
    1
    -# Needs to be here because mypy get stuck on emoji_data.py
    1
    +# This file is part of Gajim.
    
    2
    +#
    
    3
    +# Gajim is free software; you can redistribute it and/or modify
    
    4
    +# it under the terms of the GNU General Public License as published
    
    5
    +# by the Free Software Foundation; version 3 only.
    
    6
    +#
    
    7
    +# Gajim is distributed in the hope that it will be useful,
    
    8
    +# but WITHOUT ANY WARRANTY; without even the implied warranty of
    
    9
    +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    
    10
    +# GNU General Public License for more details.
    
    11
    +#
    
    12
    +# You should have received a copy of the GNU General Public License
    
    13
    +# along with Gajim. If not, see <http://www.gnu.org/licenses/>.
    
    14
    +
    
    15
    +from enum import IntEnum
    
    16
    +from collections import OrderedDict
    
    17
    +
    
    18
    +from gi.repository import GdkPixbuf
    
    19
    +
    
    20
    +class Emoji(IntEnum):
    
    21
    +    ...
    
    22
    +
    
    23
    +def is_emoji(codepoints: str) -> bool: ...
    
    24
    +def get_emoji_pixbuf(codepoints: str) -> GdkPixbuf.Pixbuf: ...
    
    25
    +
    
    26
    +class EmojiData(OrderedDict):
    
    27
    +    ...
    
    28
    +
    
    29
    +class EmojiPixbufs(dict):
    
    30
    +    ...
    
    31
    +
    
    32
    +class EmojiAsciiData(dict):
    
    33
    +    ...
    
    34
    +
    
    35
    +emoji_pixbufs = EmojiPixbufs()
    
    36
    +
    
    37
    +emoji_ascii_data = EmojiAsciiData()
    
    38
    +
    
    39
    +emoji_data = EmojiData()

  • gajim/gtk/filechoosers.py
    ... ... @@ -18,7 +18,6 @@
    18 18
     import os
    
    19 19
     import sys
    
    20 20
     from pathlib import Path
    
    21
    -from collections import namedtuple
    
    22 21
     
    
    23 22
     from gi.repository import Gtk
    
    24 23
     from gi.repository import GdkPixbuf
    
    ... ... @@ -26,11 +25,11 @@ from gi.repository import GObject
    26 25
     
    
    27 26
     from gajim.common import app
    
    28 27
     from gajim.common.i18n import _
    
    28
    +from gajim.gtk.const import Filter
    
    29
    +from gajim.gtk.types import FilterList  # pylint: disable=unused-import
    
    29 30
     
    
    30
    -Filter = namedtuple('Filter', 'name pattern default')
    
    31 31
     
    
    32
    -
    
    33
    -def _require_native():
    
    32
    +def _require_native() -> bool:
    
    34 33
         if app.is_flatpak():
    
    35 34
             return True
    
    36 35
         if sys.platform in ('win32', 'darwin'):
    
    ... ... @@ -85,7 +84,7 @@ class BaseFileChooser:
    85 84
     class BaseFileOpenDialog:
    
    86 85
     
    
    87 86
         _title = _('Choose File to Send…')
    
    88
    -    _filters = [Filter(_('All files'), '*', True)]
    
    87
    +    _filters = [Filter(_('All files'), '*', True)]  # type: FilterList
    
    89 88
     
    
    90 89
     
    
    91 90
     class BaseAvatarChooserDialog:
    
    ... ... @@ -96,7 +95,7 @@ class BaseAvatarChooserDialog:
    96 95
         if _require_native():
    
    97 96
             _filters = [Filter(_('PNG files'), '*.png', True),
    
    98 97
                         Filter(_('JPEG files'), '*.jp*g', False),
    
    99
    -                    Filter(_('SVG files'), '*.svg', False)]
    
    98
    +                    Filter(_('SVG files'), '*.svg', False)]  # type: FilterList
    
    100 99
         else:
    
    101 100
             _filters = [Filter(_('Images'), ['image/png',
    
    102 101
                                              'image/jpeg',
    
    ... ... @@ -106,7 +105,7 @@ class BaseAvatarChooserDialog:
    106 105
     class NativeFileChooserDialog(Gtk.FileChooserNative, BaseFileChooser):
    
    107 106
     
    
    108 107
         _title = ''
    
    109
    -    _filters = []
    
    108
    +    _filters = []  # type: FilterList
    
    110 109
         _action = Gtk.FileChooserAction.OPEN
    
    111 110
     
    
    112 111
         def __init__(self, accept_cb, cancel_cb=None, transient_for=None,
    
    ... ... @@ -161,7 +160,7 @@ class NativeAvatarChooserDialog(BaseAvatarChooserDialog, NativeFileChooserDialog
    161 160
     class GtkFileChooserDialog(Gtk.FileChooserDialog, BaseFileChooser):
    
    162 161
     
    
    163 162
         _title = ''
    
    164
    -    _filters = []
    
    163
    +    _filters = []  # type: FilterList
    
    165 164
         _action = Gtk.FileChooserAction.OPEN
    
    166 165
         _preivew_size = (200, 200)
    
    167 166
     
    

  • gajim/gtk/types.py
    1
    +# This file is part of Gajim.
    
    2
    +#
    
    3
    +# Gajim is free software; you can redistribute it and/or modify
    
    4
    +# it under the terms of the GNU General Public License as published
    
    5
    +# by the Free Software Foundation; version 3 only.
    
    6
    +#
    
    7
    +# Gajim is distributed in the hope that it will be useful,
    
    8
    +# but WITHOUT ANY WARRANTY; without even the implied warranty of
    
    9
    +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    
    10
    +# GNU General Public License for more details.
    
    11
    +#
    
    12
    +# You should have received a copy of the GNU General Public License
    
    13
    +# along with Gajim.  If not, see <http://www.gnu.org/licenses/>.
    
    14
    +
    
    15
    +# Types for typechecking
    
    16
    +
    
    17
    +from typing import ClassVar
    
    18
    +from typing import List
    
    19
    +
    
    20
    +from gajim.gtk.const import Filter
    
    21
    +
    
    22
    +FilterList = ClassVar[List[Filter]]

  • gajim/gtkexcepthook.py
    ... ... @@ -17,6 +17,8 @@
    17 17
     # You should have received a copy of the GNU General Public License
    
    18 18
     # along with Gajim. If not, see <http://www.gnu.org/licenses/>.
    
    19 19
     
    
    20
    +from typing import cast
    
    21
    +
    
    20 22
     import sys
    
    21 23
     import os
    
    22 24
     import traceback
    
    ... ... @@ -40,7 +42,8 @@ if __name__ == '__main__':
    40 42
         glade_file = os.path.join('data', 'gui', 'exception_dialog.ui')
    
    41 43
     else:
    
    42 44
         from gajim.common import configpaths
    
    43
    -    glade_file = os.path.join(configpaths.get('GUI'), 'exception_dialog.ui')
    
    45
    +    gui_path = cast(str, configpaths.get('GUI'))
    
    46
    +    glade_file = os.path.join(gui_path, 'exception_dialog.ui')
    
    44 47
     
    
    45 48
     
    
    46 49
     _exception_in_progress = threading.Lock()
    

  • gajim/gui_interface.py
    ... ... @@ -2714,10 +2714,8 @@ class Interface:
    2714 2714
                 app.nicks[a] = app.config.get_per('accounts', a, 'name')
    
    2715 2715
                 app.block_signed_in_notifications[a] = True
    
    2716 2716
                 app.sleeper_state[a] = 0
    
    2717
    -            app.encrypted_chats[a] = []
    
    2718 2717
                 app.last_message_time[a] = {}
    
    2719 2718
                 app.status_before_autoaway[a] = ''
    
    2720
    -            app.transport_avatar[a] = {}
    
    2721 2719
                 app.gajim_optional_features[a] = []
    
    2722 2720
                 app.caps_hash[a] = ''
    
    2723 2721
     
    

  • gajim/htmltextview.py
    ... ... @@ -44,10 +44,6 @@ from gi.repository import Gtk
    44 44
     from gi.repository import Gdk
    
    45 45
     from gi.repository import GdkPixbuf
    
    46 46
     
    
    47
    -if __name__ == '__main__':
    
    48
    -    from gajim.common import configpaths
    
    49
    -    configpaths.init()
    
    50
    -
    
    51 47
     from gajim.common import app
    
    52 48
     from gajim.common import helpers
    
    53 49
     from gajim.common.i18n import _
    
    ... ... @@ -1086,185 +1082,3 @@ class HtmlTextView(Gtk.TextView):
    1086 1082
             self.add_child_at_anchor(emoji, anchor)
    
    1087 1083
             buffer_.delete_mark(start_mark)
    
    1088 1084
             buffer_.delete_mark(end_mark)
    1089
    -
    
    1090
    -change_cursor = None
    
    1091
    -
    
    1092
    -if __name__ == '__main__':
    
    1093
    -    from gajim.conversation_textview import ConversationTextview
    
    1094
    -    from gajim.gui_interface import Interface
    
    1095
    -
    
    1096
    -    Interface()
    
    1097
    -
    
    1098
    -    # create fake app.plugin_manager.gui_extension_point method for tests
    
    1099
    -    def extension_point(*args):
    
    1100
    -        pass
    
    1101
    -    def gui_extension_point(*args):
    
    1102
    -        pass
    
    1103
    -    app.plugin_manager = Interface()
    
    1104
    -    app.plugin_manager.extension_point = extension_point
    
    1105
    -    app.plugin_manager.gui_extension_point = gui_extension_point
    
    1106
    -
    
    1107
    -    htmlview = ConversationTextview(None)
    
    1108
    -
    
    1109
    -    def on_textview_motion_notify_event(widget, event):
    
    1110
    -        """
    
    1111
    -        Change the cursor to a hand when we are over a mail or an url
    
    1112
    -        """
    
    1113
    -        global change_cursor
    
    1114
    -        w = htmlview.tv.get_window(Gtk.TextWindowType.TEXT)
    
    1115
    -        device = w.get_display().get_device_manager().get_client_pointer()
    
    1116
    -        pointer = w.get_device_position(device)
    
    1117
    -        x = pointer[1]
    
    1118
    -        y = pointer[2]
    
    1119
    -        tags = htmlview.tv.get_iter_at_location(x, y)[1].get_tags()
    
    1120
    -        if change_cursor:
    
    1121
    -            w.set_cursor(get_cursor('XTERM'))
    
    1122
    -            change_cursor = None
    
    1123
    -        for tag in tags:
    
    1124
    -            try:
    
    1125
    -                if tag.is_anchor:
    
    1126
    -                    w.set_cursor(get_cursor('HAND2'))
    
    1127
    -                    change_cursor = tag
    
    1128
    -            except Exception:
    
    1129
    -                pass
    
    1130
    -
    
    1131
    -    htmlview.tv.connect('motion_notify_event', on_textview_motion_notify_event)
    
    1132
    -
    
    1133
    -    def handler(texttag, widget, event, iter_, kind):
    
    1134
    -        if event.type == Gdk.EventType.BUTTON_PRESS:
    
    1135
    -            pass
    
    1136
    -
    
    1137
    -    htmlview.tv.hyperlink_handler = htmlview.hyperlink_handler
    
    1138
    -
    
    1139
    -    htmlview.print_real_text(None, xhtml='<div>'
    
    1140
    -    '<span style="color: red; text-decoration:underline">Hello</span><br/>\n'
    
    1141
    -      '  <img src="http://images.slashdot.org/topics/topicsoftware.gif"/><br/>\n'
    
    1142
    -    '<span style="font-size: 500%; font-family: serif">World</span>\n'
    
    1143
    -      '</div>\n')
    
    1144
    -    htmlview.print_real_text(None, xhtml='<hr />')
    
    1145
    -    htmlview.print_real_text(None, xhtml='''
    
    1146
    -    <body xmlns='http://www.w3.org/1999/xhtml'>
    
    1147
    -     <p xmlns='http://www.w3.org/1999/xhtml'>a:b
    
    1148
    -       <a href='http://google.com/' xmlns='http://www.w3.org/1999/xhtml'>Google
    
    1149
    -       </a>
    
    1150
    -     </p><br/>
    
    1151
    -    </body>''')
    
    1152
    -    htmlview.print_real_text(None, xhtml='''
    
    1153
    -     <body xmlns='http://www.w3.org/1999/xhtml'>
    
    1154
    -      <p style='font-size:large'>
    
    1155
    -            <span style='font-style: italic'>O
    
    1156
    -            <span style='font-size:larger'>M</span>G</span>,
    
    1157
    -            I&apos;m <span style='color:green'>green</span>
    
    1158
    -            with <span style='font-weight: bold'>envy</span>!
    
    1159
    -      </p>
    
    1160
    -     </body>
    
    1161
    -            ''')
    
    1162
    -    htmlview.print_real_text(None, xhtml='<hr />')
    
    1163
    -    htmlview.print_real_text(None, xhtml='''
    
    1164
    -    <body xmlns='http://www.w3.org/1999/xhtml'>
    
    1165
    -            http://test.com/  testing links autolinkifying
    
    1166
    -    </body>
    
    1167
    -            ''')
    
    1168
    -    htmlview.print_real_text(None, xhtml='<hr />')
    
    1169
    -    htmlview.print_real_text(None, xhtml='''
    
    1170
    -    <body xmlns='http://www.w3.org/1999/xhtml'>
    
    1171
    -      <p>As Emerson said in his essay <span style='
    
    1172
    -        font-style: italic; background-color:cyan'>Self-Reliance</span>:</p>
    
    1173
    -      <p style='margin-left: 5px; margin-right: 2%'>
    
    1174
    -            &quot;A foolish consistency is the hobgoblin of little minds.&quot;
    
    1175
    -      </p>
    
    1176
    -    </body>
    
    1177
    -            ''')
    
    1178
    -    htmlview.print_real_text(None, xhtml='<hr />')
    
    1179
    -    htmlview.print_real_text(None, xhtml='''
    
    1180
    -    <body xmlns='http://www.w3.org/1999/xhtml'>
    
    1181
    -      <p style='text-align:center'>
    
    1182
    -        Hey, are you licensed to <a href='http://www.jabber.org/'>Jabber</a>?
    
    1183
    -      </p>
    
    1184
    -      <p style='text-align:right'>
    
    1185
    -        <img src='http://www.xmpp.org/images/psa-license.jpg'
    
    1186
    -        alt='A License to Jabber' width='50%' height='50%'/>
    
    1187
    -      </p>
    
    1188
    -    </body>
    
    1189
    -            ''')
    
    1190
    -    htmlview.print_real_text(None, xhtml='<hr />')
    
    1191
    -    htmlview.print_real_text(None, xhtml='''
    
    1192
    -    <body xmlns='http://www.w3.org/1999/xhtml'>
    
    1193
    -      <ul style='background-color:rgb(120,140,100)'>
    
    1194
    -       <li> One </li>
    
    1195
    -       <li> Two </li>
    
    1196
    -       <li> Three </li>
    
    1197
    -      </ul><hr /><pre style="background-color:rgb(120,120,120)">def fac(n):
    
    1198
    -def faciter(n,acc):
    
    1199
    -    if n==0: return acc
    
    1200
    -    return faciter(n-1, acc*n)
    
    1201
    -if n&lt;0: raise ValueError('Must be non-negative')
    
    1202
    -return faciter(n,1)</pre>
    
    1203
    -    </body>
    
    1204
    -            ''')
    
    1205
    -    htmlview.print_real_text(None, xhtml='<hr />')
    
    1206
    -    htmlview.print_real_text(None, xhtml='''
    
    1207
    -    <body xmlns='http://www.w3.org/1999/xhtml'>
    
    1208
    -     <ol style='background-color:rgb(120,140,100)'>
    
    1209
    -       <li> One </li>
    
    1210
    -       <li> Two is nested: <ul style='background-color:rgb(200,200,100)'>
    
    1211
    -                     <li> One </li>
    
    1212
    -                     <li style='font-size:50%'> Two </li>
    
    1213
    -                     <li style='font-size:200%'> Three </li>
    
    1214
    -                     <li style='font-size:9999pt'> Four </li>
    
    1215
    -                    </ul></li>
    
    1216
    -       <li> Three </li></ol>
    
    1217
    -    </body>
    
    1218
    -            ''')
    
    1219
    -    htmlview.print_real_text(None, xhtml='<hr />')
    
    1220
    -    htmlview.print_real_text(None, xhtml='''
    
    1221
    -    <body xmlns='http://www.w3.org/1999/xhtml'>
    
    1222
    -    <p>
    
    1223
    -      <strong>
    
    1224
    -        <a href='xmpp:example@example.org'>xmpp link</a>
    
    1225
    -      </strong>: </p>
    
    1226
    -    <div xmlns='http://www.w3.org/1999/xhtml'>
    
    1227
    -      <cite style='margin: 7px;' title='xmpp:examples@example.org'>
    
    1228
    -        <p>
    
    1229
    -          <strong>examples@example.org wrote:</strong>
    
    1230
    -        </p>
    
    1231
    -        <p>this cite - bla bla bla, smile- :-)  …</p>
    
    1232
    -      </cite>
    
    1233
    -      <div>
    
    1234
    -        <p>some text</p>
    
    1235
    -      </div>
    
    1236
    -    </div>
    
    1237
    -    <p/>
    
    1238
    -    <p>#232/1</p>
    
    1239
    -    </body>
    
    1240
    -    ''')
    
    1241
    -    htmlview.print_real_text(None, xhtml='<hr />')
    
    1242
    -    htmlview.print_real_text(None, xhtml='''
    
    1243
    -    <body xmlns='http://www.w3.org/1999/xhtml'>
    
    1244
    -    <br/>
    
    1245
    -<img src='data:image/png;base64,R0lGODdhMAAwAPAAAAAAAP///ywAAAAAMAAw\
    
    1246
    -AAAC8IyPqcvt3wCcDkiLc7C0qwyGHhSWpjQu5yqmCYsapyuvUUlvONmOZtfzgFz\
    
    1247
    -ByTB10QgxOR0TqBQejhRNzOfkVJ+5YiUqrXF5Y5lKh/DeuNcP5yLWGsEbtLiOSp\
    
    1248
    -a/TPg7JpJHxyendzWTBfX0cxOnKPjgBzi4diinWGdkF8kjdfnycQZXZeYGejmJl\
    
    1249
    -ZeGl9i2icVqaNVailT6F5iJ90m6mvuTS4OK05M0vDk0Q4XUtwvKOzrcd3iq9uis\
    
    1250
    -F81M1OIcR7lEewwcLp7tuNNkM3uNna3F2JQFo97Vriy/Xl4/f1cf5VWzXyym7PH\
    
    1251
    -hhx4dbgYKAAA7' alt='Larry'/>
    
    1252
    -    </body>
    
    1253
    -    ''')
    
    1254
    -    htmlview.tv.show()
    
    1255
    -    sw = Gtk.ScrolledWindow()
    
    1256
    -    sw.set_property('hscrollbar-policy', Gtk.PolicyType.AUTOMATIC)
    
    1257
    -    sw.set_property('vscrollbar-policy', Gtk.PolicyType.AUTOMATIC)
    
    1258
    -    sw.set_property('border-width', 0)
    
    1259
    -    sw.add(htmlview.tv)
    
    1260
    -    sw.show()
    
    1261
    -    frame = Gtk.Frame()
    
    1262
    -    frame.set_shadow_type(Gtk.ShadowType.IN)
    
    1263
    -    frame.show()
    
    1264
    -    frame.add(sw)
    
    1265
    -    win = Gtk.Window()
    
    1266
    -    win.add(frame)
    
    1267
    -    win.set_default_size(400, 300)
    
    1268
    -    win.show_all()
    
    1269
    -    win.connect('destroy', lambda win: Gtk.main_quit())
    
    1270
    -    Gtk.main()

  • gajim/plugins/gajimplugin.py
    ... ... @@ -21,15 +21,25 @@ Base class for implementing plugin.
    21 21
     :license: GPL
    
    22 22
     '''
    
    23 23
     
    
    24
    +from typing import List  # pylint: disable=W0611
    
    25
    +from typing import Tuple  # pylint: disable=W0611
    
    26
    +from typing import Dict  # pylint: disable=W0611
    
    27
    +from typing import Any  # pylint: disable=W0611
    
    28
    +
    
    24 29
     import os
    
    25 30
     import locale
    
    31
    +import logging
    
    32
    +import pickle
    
    26 33
     
    
    27 34
     from gajim.common import configpaths
    
    35
    +from gajim.common.types import PluginExtensionPoints  # pylint: disable=W0611
    
    36
    +from gajim.common.types import EventHandlersDict  # pylint: disable=W0611
    
    37
    +from gajim.common.types import PluginEvents  # pylint: disable=W0611
    
    28 38
     
    
    29 39
     from gajim.plugins.helpers import log_calls, log
    
    30 40
     from gajim.plugins.gui import GajimPluginConfigDialog
    
    31 41
     
    
    32
    -import logging
    
    42
    +
    
    33 43
     log = logging.getLogger('gajim.p.plugin')
    
    34 44
     
    
    35 45
     
    
    ... ... @@ -86,7 +96,7 @@ class GajimPlugin:
    86 96
     
    
    87 97
         :todo: should be allow rich text here (like HTML or reStructuredText)?
    
    88 98
         '''
    
    89
    -    authors = []
    
    99
    +    authors = []  # type: List[str]
    
    90 100
         '''
    
    91 101
         Plugin authors.
    
    92 102
     
    
    ... ... @@ -104,7 +114,7 @@ class GajimPlugin:
    104 114
         :todo: should we check whether provided string is valid URI? (Maybe
    
    105 115
         using 'property')
    
    106 116
         '''
    
    107
    -    gui_extension_points = {}
    
    117
    +    gui_extension_points = {}  # type: PluginExtensionPoints
    
    108 118
         '''
    
    109 119
         Extension points that plugin wants to connect with and handlers to be used.
    
    110 120
     
    
    ... ... @@ -118,7 +128,7 @@ class GajimPlugin:
    118 128
         or when extpoint is destroyed and plugin is activate (eg. chat window
    
    119 129
         closed).
    
    120 130
         '''
    
    121
    -    config_default_values = {}
    
    131
    +    config_default_values = {}  # type: Dict[str, Tuple[Any, str]]
    
    122 132
         '''
    
    123 133
         Default values for keys that should be stored in plug-in config.
    
    124 134
     
    
    ... ... @@ -132,7 +142,7 @@ class GajimPlugin:
    132 142
     
    
    133 143
         :type: {} of 2-element tuples
    
    134 144
         '''
    
    135
    -    events_handlers = {}
    
    145
    +    events_handlers = {}  # type: EventHandlersDict
    
    136 146
         '''
    
    137 147
         Dictionary with events handlers.
    
    138 148
     
    
    ... ... @@ -143,7 +153,7 @@ class GajimPlugin:
    143 153
     
    
    144 154
         :type: {} with 2-element tuples
    
    145 155
         '''
    
    146
    -    events = []
    
    156
    +    events = []  # type: PluginEvents
    
    147 157
         '''
    
    148 158
         New network event classes to be registered in Network Events Controller.
    
    149 159
     
    
    ... ... @@ -152,7 +162,7 @@ class GajimPlugin:
    152 162
         '''
    
    153 163
     
    
    154 164
         @log_calls('GajimPlugin')
    
    155
    -    def __init__(self):
    
    165
    +    def __init__(self) -> None:
    
    156 166
             self.config = GajimPluginConfig(self)
    
    157 167
             '''
    
    158 168
             Plug-in configuration dictionary.
    
    ... ... @@ -168,11 +178,11 @@ class GajimPlugin:
    168 178
             self.init()
    
    169 179
     
    
    170 180
         @log_calls('GajimPlugin')
    
    171
    -    def save_config(self):
    
    181
    +    def save_config(self) -> None:
    
    172 182
             self.config.save()
    
    173 183
     
    
    174 184
         @log_calls('GajimPlugin')
    
    175
    -    def load_config(self):
    
    185
    +    def load_config(self) -> None:
    
    176 186
             self.config.load()
    
    177 187
     
    
    178 188
         def __eq__(self, plugin):
    
    ... ... @@ -203,7 +213,6 @@ class GajimPlugin:
    203 213
         def deactivate(self):
    
    204 214
             pass
    
    205 215
     
    
    206
    -import pickle
    
    207 216
     
    
    208 217
     class GajimPluginConfig():
    
    209 218
         @log_calls('GajimPluginConfig')
    

  • test/gtk/htmltextview.py
    1
    +import sys
    
    2
    +import os
    
    3
    +from unittest.mock import MagicMock
    
    4
    +
    
    5
    +sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), '..', '..')))
    
    6
    +
    
    7
    +from gi.repository import Gtk, Gdk
    
    8
    +
    
    9
    +from gajim.common import app
    
    10
    +from gajim.common import configpaths
    
    11
    +configpaths.init()
    
    12
    +from gajim.common import caps_cache
    
    13
    +
    
    14
    +from gajim.gtk.util import get_cursor
    
    15
    +from gajim.conversation_textview import ConversationTextview
    
    16
    +from gajim.gui_interface import Interface
    
    17
    +
    
    18
    +
    
    19
    +caps_cache.capscache = MagicMock()
    
    20
    +app.plugin_manager = MagicMock()
    
    21
    +app.logger = MagicMock()
    
    22
    +app.interface = Interface()
    
    23
    +
    
    24
    +change_cursor = None
    
    25
    +htmlview = ConversationTextview(None)
    
    26
    +
    
    27
    +def on_textview_motion_notify_event(widget, event):
    
    28
    +    """
    
    29
    +    Change the cursor to a hand when we are over a mail or an url
    
    30
    +    """
    
    31
    +    global change_cursor
    
    32
    +    w = htmlview.tv.get_window(Gtk.TextWindowType.TEXT)
    
    33
    +    device = w.get_display().get_device_manager().get_client_pointer()
    
    34
    +    pointer = w.get_device_position(device)
    
    35
    +    x = pointer[1]
    
    36
    +    y = pointer[2]
    
    37
    +    tags = htmlview.tv.get_iter_at_location(x, y)[1].get_tags()
    
    38
    +    if change_cursor:
    
    39
    +        w.set_cursor(get_cursor('XTERM'))
    
    40
    +        change_cursor = None
    
    41
    +    for tag in tags:
    
    42
    +        try:
    
    43
    +            if tag.is_anchor:
    
    44
    +                w.set_cursor(get_cursor('HAND2'))
    
    45
    +                change_cursor = tag
    
    46
    +        except Exception:
    
    47
    +            pass
    
    48
    +
    
    49
    +htmlview.tv.connect('motion_notify_event', on_textview_motion_notify_event)
    
    50
    +
    
    51
    +def handler(texttag, widget, event, iter_, kind):
    
    52
    +    if event.type == Gdk.EventType.BUTTON_PRESS:
    
    53
    +        pass
    
    54
    +
    
    55
    +htmlview.tv.hyperlink_handler = htmlview.hyperlink_handler
    
    56
    +
    
    57
    +htmlview.print_real_text(None, xhtml='<div>'
    
    58
    +'<span style="color: red; text-decoration:underline">Hello</span><br/>\n'
    
    59
    +  '  <img src="http://images.slashdot.org/topics/topicsoftware.gif"/><br/>\n'
    
    60
    +'<span style="font-size: 500%; font-family: serif">World</span>\n'
    
    61
    +  '</div>\n')
    
    62
    +htmlview.print_real_text(None, xhtml='<hr />')
    
    63
    +htmlview.print_real_text(None, xhtml='''
    
    64
    +<body xmlns='http://www.w3.org/1999/xhtml'>
    
    65
    + <p xmlns='http://www.w3.org/1999/xhtml'>a:b
    
    66
    +   <a href='http://google.com/' xmlns='http://www.w3.org/1999/xhtml'>Google
    
    67
    +   </a>
    
    68
    + </p><br/>
    
    69
    +</body>''')
    
    70
    +htmlview.print_real_text(None, xhtml='''
    
    71
    + <body xmlns='http://www.w3.org/1999/xhtml'>
    
    72
    +  <p style='font-size:large'>
    
    73
    +        <span style='font-style: italic'>O
    
    74
    +        <span style='font-size:larger'>M</span>G</span>,
    
    75
    +        I&apos;m <span style='color:green'>green</span>
    
    76
    +        with <span style='font-weight: bold'>envy</span>!
    
    77
    +  </p>
    
    78
    + </body>
    
    79
    +        ''')
    
    80
    +htmlview.print_real_text(None, xhtml='<hr />')
    
    81
    +htmlview.print_real_text(None, xhtml='''
    
    82
    +<body xmlns='http://www.w3.org/1999/xhtml'>
    
    83
    +        http://test.com/  testing links autolinkifying
    
    84
    +</body>
    
    85
    +        ''')
    
    86
    +htmlview.print_real_text(None, xhtml='<hr />')
    
    87
    +htmlview.print_real_text(None, xhtml='''
    
    88
    +<body xmlns='http://www.w3.org/1999/xhtml'>
    
    89
    +  <p>As Emerson said in his essay <span style='
    
    90
    +    font-style: italic; background-color:cyan'>Self-Reliance</span>:</p>
    
    91
    +  <p style='margin-left: 5px; margin-right: 2%'>
    
    92
    +        &quot;A foolish consistency is the hobgoblin of little minds.&quot;
    
    93
    +  </p>
    
    94
    +</body>
    
    95
    +        ''')
    
    96
    +htmlview.print_real_text(None, xhtml='<hr />')
    
    97
    +htmlview.print_real_text(None, xhtml='''
    
    98
    +<body xmlns='http://www.w3.org/1999/xhtml'>
    
    99
    +  <p style='text-align:center'>
    
    100
    +    Hey, are you licensed to <a href='http://www.jabber.org/'>Jabber</a>?
    
    101
    +  </p>
    
    102
    +  <p style='text-align:right'>
    
    103
    +    <img src='http://www.xmpp.org/images/psa-license.jpg'
    
    104
    +    alt='A License to Jabber' width='50%' height='50%'/>
    
    105
    +  </p>
    
    106
    +</body>
    
    107
    +        ''')
    
    108
    +htmlview.print_real_text(None, xhtml='<hr />')
    
    109
    +htmlview.print_real_text(None, xhtml='''
    
    110
    +<body xmlns='http://www.w3.org/1999/xhtml'>
    
    111
    +  <ul style='background-color:rgb(120,140,100)'>
    
    112
    +   <li> One </li>
    
    113
    +   <li> Two </li>
    
    114
    +   <li> Three </li>
    
    115
    +  </ul><hr /><pre style="background-color:rgb(120,120,120)">def fac(n):
    
    116
    +def faciter(n,acc):
    
    117
    +if n==0: return acc
    
    118
    +return faciter(n-1, acc*n)
    
    119
    +if n&lt;0: raise ValueError('Must be non-negative')
    
    120
    +return faciter(n,1)</pre>
    
    121
    +</body>
    
    122
    +        ''')
    
    123
    +htmlview.print_real_text(None, xhtml='<hr />')
    
    124
    +htmlview.print_real_text(None, xhtml='''
    
    125
    +<body xmlns='http://www.w3.org/1999/xhtml'>
    
    126
    + <ol style='background-color:rgb(120,140,100)'>
    
    127
    +   <li> One </li>
    
    128
    +   <li> Two is nested: <ul style='background-color:rgb(200,200,100)'>
    
    129
    +                 <li> One </li>
    
    130
    +                 <li style='font-size:50%'> Two </li>
    
    131
    +                 <li style='font-size:200%'> Three </li>
    
    132
    +                 <li style='font-size:9999pt'> Four </li>
    
    133
    +                </ul></li>
    
    134
    +   <li> Three </li></ol>
    
    135
    +</body>
    
    136
    +        ''')
    
    137
    +htmlview.print_real_text(None, xhtml='<hr />')
    
    138
    +htmlview.print_real_text(None, xhtml='''
    
    139
    +<body xmlns='http://www.w3.org/1999/xhtml'>
    
    140
    +<p>
    
    141
    +  <strong>
    
    142
    +    <a href='xmpp:example@example.org'>xmpp link</a>
    
    143
    +  </strong>: </p>
    
    144
    +<div xmlns='http://www.w3.org/1999/xhtml'>
    
    145
    +  <cite style='margin: 7px;' title='xmpp:examples@example.org'>
    
    146
    +    <p>
    
    147
    +      <strong>examples@example.org wrote:</strong>
    
    148
    +    </p>
    
    149
    +    <p>this cite - bla bla bla, smile- :-)  …</p>
    
    150
    +  </cite>
    
    151
    +  <div>
    
    152
    +    <p>some text</p>
    
    153
    +  </div>
    
    154
    +</div>
    
    155
    +<p/>
    
    156
    +<p>#232/1</p>
    
    157
    +</body>
    
    158
    +''')
    
    159
    +htmlview.print_real_text(None, xhtml='<hr />')
    
    160
    +htmlview.print_real_text(None, xhtml='''
    
    161
    +<body xmlns='http://www.w3.org/1999/xhtml'>
    
    162
    +<br/>
    
    163
    +<img src='data:image/png;base64,R0lGODdhMAAwAPAAAAAAAP///ywAAAAAMAAw\
    
    164
    +AAAC8IyPqcvt3wCcDkiLc7C0qwyGHhSWpjQu5yqmCYsapyuvUUlvONmOZtfzgFz\
    
    165
    +ByTB10QgxOR0TqBQejhRNzOfkVJ+5YiUqrXF5Y5lKh/DeuNcP5yLWGsEbtLiOSp\
    
    166
    +a/TPg7JpJHxyendzWTBfX0cxOnKPjgBzi4diinWGdkF8kjdfnycQZXZeYGejmJl\
    
    167
    +ZeGl9i2icVqaNVailT6F5iJ90m6mvuTS4OK05M0vDk0Q4XUtwvKOzrcd3iq9uis\
    
    168
    +F81M1OIcR7lEewwcLp7tuNNkM3uNna3F2JQFo97Vriy/Xl4/f1cf5VWzXyym7PH\
    
    169
    +hhx4dbgYKAAA7' alt='Larry'/>
    
    170
    +</body>
    
    171
    +''')
    
    172
    +htmlview.tv.show()
    
    173
    +sw = Gtk.ScrolledWindow()
    
    174
    +sw.set_property('hscrollbar-policy', Gtk.PolicyType.AUTOMATIC)
    
    175
    +sw.set_property('vscrollbar-policy', Gtk.PolicyType.AUTOMATIC)
    
    176
    +sw.set_property('border-width', 0)
    
    177
    +sw.add(htmlview.tv)
    
    178
    +sw.show()
    
    179
    +frame = Gtk.Frame()
    
    180
    +frame.set_shadow_type(Gtk.ShadowType.IN)
    
    181
    +frame.show()
    
    182
    +frame.add(sw)
    
    183
    +win = Gtk.Window()
    
    184
    +win.add(frame)
    
    185
    +win.set_default_size(400, 300)
    
    186
    +win.show_all()
    
    187
    +win.connect('destroy', lambda win: Gtk.main_quit())
    
    188
    +Gtk.main()

  • test/lib/gajim_mocks.py
    ... ... @@ -35,10 +35,8 @@ class MockConnection(Mock, ConnectionHandlers):
    35 35
             app.nicks[account] = app.config.get_per('accounts', account, 'name')
    
    36 36
             app.block_signed_in_notifications[account] = True
    
    37 37
             app.sleeper_state[account] = 0
    
    38
    -        app.encrypted_chats[account] = []
    
    39 38
             app.last_message_time[account] = {}
    
    40 39
             app.status_before_autoaway[account] = ''
    
    41
    -        app.transport_avatar[account] = {}
    
    42 40
             app.gajim_optional_features[account] = []
    
    43 41
             app.caps_hash[account] = ''
    
    44 42