Philipp Hörist pushed to branch master at gajim / gajim
Commits:
5a906c14 by Philipp Hörist at 2018-09-21T13:46:52Z
Move HtmlTextView test into test folder
- - - - -
3f2f51c1 by Philipp Hörist at 2018-09-21T13:46:52Z
Add license header to emoji_data.py
- - - - -
4d4d0023 by Philipp Hörist at 2018-09-21T13:46:52Z
Extend stubs for emoji_data
- - - - -
f7a2ac9d by Philipp Hörist at 2018-09-21T13:46:52Z
Add annotations
- Add a gtk/types modules
- Add a gtk/const module to prevent circular imports
- - - - -
74b66837 by Philipp Hörist at 2018-09-21T13:46:52Z
Add annotations
- Remove some unused vars from app
- - - - -
16 changed files:
- gajim/accounts_window.py
- gajim/common/app.py
- gajim/common/types.py
- gajim/config.py
- gajim/gtk/account_wizard.py
- + gajim/gtk/const.py
- gajim/gtk/emoji_data.py
- gajim/gtk/emoji_data.pyi
- gajim/gtk/filechoosers.py
- + gajim/gtk/types.py
- gajim/gtkexcepthook.py
- gajim/gui_interface.py
- gajim/htmltextview.py
- gajim/plugins/gajimplugin.py
- + test/gtk/htmltextview.py
- test/lib/gajim_mocks.py
Changes:
=====================================
gajim/accounts_window.py
=====================================
@@ -258,10 +258,8 @@ class AccountsWindow(Gtk.ApplicationWindow):
'accounts', account, 'name')
app.block_signed_in_notifications[account] = True
app.sleeper_state[account] = 'off'
- app.encrypted_chats[account] = []
app.last_message_time[account] = {}
app.status_before_autoaway[account] = ''
- app.transport_avatar[account] = {}
app.gajim_optional_features[account] = []
app.caps_hash[account] = ''
helpers.update_optional_features(account)
@@ -292,10 +290,8 @@ class AccountsWindow(Gtk.ApplicationWindow):
del app.to_be_removed[account]
del app.newly_added[account]
del app.sleeper_state[account]
- del app.encrypted_chats[account]
del app.last_message_time[account]
del app.status_before_autoaway[account]
- del app.transport_avatar[account]
del app.gajim_optional_features[account]
del app.caps_hash[account]
if len(app.connections) >= 2:
=====================================
gajim/common/app.py
=====================================
@@ -24,6 +24,9 @@
# You should have received a copy of the GNU General Public License
# along with Gajim. If not, see <http://www.gnu.org/licenses/>.
+from typing import Dict # pylint: disable=unused-import
+from typing import List # pylint: disable=unused-import
+
import os
import sys
import logging
@@ -68,53 +71,66 @@ css_config = None
os_info = None # used to cache os information
-transport_type = {} # list the type of transport
+transport_type = {} # type: Dict[str, str]
-last_message_time = {} # list of time of the latest incoming message
- # {acct1: {jid1: time1, jid2: time2}, }
-encrypted_chats = {} # list of encrypted chats {acct1: [jid1, jid2], ..}
+# dict of time of the latest incoming message per jid
+# {acct1: {jid1: time1, jid2: time2}, }
+last_message_time = {} # type: Dict[str, Dict[str, float]]
contacts = LegacyContactsAPI()
-gc_connected = {} # tell if we are connected to the room or not
- # {acct: {room_jid: True}}
-gc_passwords = {} # list of the pass required to enter a room
- # {room_jid: password}
-automatic_rooms = {} # list of rooms that must be automaticaly configured
- # and for which we have a list of invities
- #{account: {room_jid: {'invities': []}}}
-
-groups = {} # list of groups
-newly_added = {} # list of contacts that has just signed in
-to_be_removed = {} # list of contacts that has just signed out
+
+# tell if we are connected to the room or not
+# {acct: {room_jid: True}}
+gc_connected = {} # type: Dict[str, Dict[str, bool]]
+
+# dict of the pass required to enter a room
+# {room_jid: password}
+gc_passwords = {} # type: Dict[str, str]
+
+# dict of rooms that must be automaticaly configured
+# and for which we have a list of invities
+# {account: {room_jid: {'invities': []}}}
+automatic_rooms = {} # type: Dict[str, Dict[str, Dict[str, List[str]]]]
+
+ # dict of groups, holds if they are expanded or not
+groups = {} # type: Dict[str, Dict[str, Dict[str, bool]]]
+
+# list of contacts that has just signed in
+newly_added = {} # type: Dict[str, List[str]]
+
+# list of contacts that has just signed out
+to_be_removed = {} # type: Dict[str, List[str]]
events = Events()
notification = None
-nicks = {} # list of our nick names in each account
+# list of our nick names in each account
+nicks = {} # type: Dict[str, str]
+
# should we block 'contact signed in' notifications for this account?
# this is only for the first 30 seconds after we change our show
# to something else than offline
# can also contain account/transport_jid to block notifications for contacts
# from this transport
block_signed_in_notifications = {}
-con_types = {} # type of each connection (ssl, tls, tcp, ...)
-sleeper_state = {} # whether we pass auto away / xa or not
+ # type of each connection (ssl, tls, tcp, ...)
+con_types = {} # type: Dict[str, Optional[str]]
+
+# whether we pass auto away / xa or not
#'off': don't use sleeper for this account
#'online': online and use sleeper
#'autoaway': autoaway and use sleeper
#'autoxa': autoxa and use sleeper
-status_before_autoaway = {}
+sleeper_state = {} # type: Dict[str, str]
-# jid of transport contacts for which we need to ask avatar when transport will
-# be online
-transport_avatar = {} # {transport_jid: [jid_list]}
+status_before_autoaway = {} # type: Dict[str, str]
# Is Gnome configured to activate on single click ?
single_click = False
SHOW_LIST = ['offline', 'connecting', 'online', 'chat', 'away', 'xa', 'dnd',
- 'invisible', 'error']
+ 'invisible', 'error']
# zeroconf account name
ZEROCONF_ACC_NAME = 'Local'
=====================================
gajim/common/types.py
=====================================
@@ -32,6 +32,7 @@ if TYPE_CHECKING:
from gajim.common.zeroconf.connection_zeroconf import ConnectionZeroconf
from gajim.common.contacts import Contact
from gajim.common.contacts import GC_Contact
+ from gajim.common.nec import NetworkEvent
ConnectionT = Union['Connection', 'ConnectionZeroconf']
ContactT = Union['Contact', 'GC_Contact']
@@ -44,3 +45,9 @@ PEPHandlersDict = Dict[str, List[PEPNotifyCallback]]
# Configpaths
PathTuple = Tuple[Optional[PathLocation], str, Optional[PathType]]
+
+# Plugins
+PluginExtensionPoints = Dict[str, Tuple[Optional[Callable[..., None]],
+ Optional[Callable[..., None]]]]
+EventHandlersDict = Dict[str, Tuple[int, Callable[['NetworkEvent'], Optional[bool]]]]
+PluginEvents = List['NetworkEvent']
=====================================
gajim/config.py
=====================================
@@ -674,10 +674,8 @@ class RemoveAccountWindow:
del app.to_be_removed[self.account]
del app.newly_added[self.account]
del app.sleeper_state[self.account]
- del app.encrypted_chats[self.account]
del app.last_message_time[self.account]
del app.status_before_autoaway[self.account]
- del app.transport_avatar[self.account]
del app.gajim_optional_features[self.account]
del app.caps_hash[self.account]
if len(app.connections) >= 2: # Do not merge accounts if only one exists
=====================================
gajim/gtk/account_wizard.py
=====================================
@@ -582,10 +582,8 @@ class AccountCreationWizard:
app.nicks[self.account] = config['name']
app.block_signed_in_notifications[self.account] = True
app.sleeper_state[self.account] = 'off'
- app.encrypted_chats[self.account] = []
app.last_message_time[self.account] = {}
app.status_before_autoaway[self.account] = ''
- app.transport_avatar[self.account] = {}
app.gajim_optional_features[self.account] = []
app.caps_hash[self.account] = ''
helpers.update_optional_features(self.account)
=====================================
gajim/gtk/const.py
=====================================
@@ -0,0 +1,19 @@
+# This file is part of Gajim.
+#
+# Gajim 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; version 3 only.
+#
+# Gajim 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 Gajim. If not, see <http://www.gnu.org/licenses/>.
+
+# Constants for the gtk module
+
+from collections import namedtuple
+
+Filter = namedtuple('Filter', 'name pattern default')
=====================================
gajim/gtk/emoji_data.py
=====================================
@@ -1,3 +1,17 @@
+# This file is part of Gajim.
+#
+# Gajim 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; version 3 only.
+#
+# Gajim 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 Gajim. If not, see <http://www.gnu.org/licenses/>.
+
import re
import weakref
from enum import IntEnum
=====================================
gajim/gtk/emoji_data.pyi
=====================================
@@ -1 +1,39 @@
-# Needs to be here because mypy get stuck on emoji_data.py
+# This file is part of Gajim.
+#
+# Gajim 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; version 3 only.
+#
+# Gajim 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 Gajim. If not, see <http://www.gnu.org/licenses/>.
+
+from enum import IntEnum
+from collections import OrderedDict
+
+from gi.repository import GdkPixbuf
+
+class Emoji(IntEnum):
+ ...
+
+def is_emoji(codepoints: str) -> bool: ...
+def get_emoji_pixbuf(codepoints: str) -> GdkPixbuf.Pixbuf: ...
+
+class EmojiData(OrderedDict):
+ ...
+
+class EmojiPixbufs(dict):
+ ...
+
+class EmojiAsciiData(dict):
+ ...
+
+emoji_pixbufs = EmojiPixbufs()
+
+emoji_ascii_data = EmojiAsciiData()
+
+emoji_data = EmojiData()
=====================================
gajim/gtk/filechoosers.py
=====================================
@@ -18,7 +18,6 @@
import os
import sys
from pathlib import Path
-from collections import namedtuple
from gi.repository import Gtk
from gi.repository import GdkPixbuf
@@ -26,11 +25,11 @@ from gi.repository import GObject
from gajim.common import app
from gajim.common.i18n import _
+from gajim.gtk.const import Filter
+from gajim.gtk.types import FilterList # pylint: disable=unused-import
-Filter = namedtuple('Filter', 'name pattern default')
-
-def _require_native():
+def _require_native() -> bool:
if app.is_flatpak():
return True
if sys.platform in ('win32', 'darwin'):
@@ -85,7 +84,7 @@ class BaseFileChooser:
class BaseFileOpenDialog:
_title = _('Choose File to Send…')
- _filters = [Filter(_('All files'), '*', True)]
+ _filters = [Filter(_('All files'), '*', True)] # type: FilterList
class BaseAvatarChooserDialog:
@@ -96,7 +95,7 @@ class BaseAvatarChooserDialog:
if _require_native():
_filters = [Filter(_('PNG files'), '*.png', True),
Filter(_('JPEG files'), '*.jp*g', False),
- Filter(_('SVG files'), '*.svg', False)]
+ Filter(_('SVG files'), '*.svg', False)] # type: FilterList
else:
_filters = [Filter(_('Images'), ['image/png',
'image/jpeg',
@@ -106,7 +105,7 @@ class BaseAvatarChooserDialog:
class NativeFileChooserDialog(Gtk.FileChooserNative, BaseFileChooser):
_title = ''
- _filters = []
+ _filters = [] # type: FilterList
_action = Gtk.FileChooserAction.OPEN
def __init__(self, accept_cb, cancel_cb=None, transient_for=None,
@@ -161,7 +160,7 @@ class NativeAvatarChooserDialog(BaseAvatarChooserDialog, NativeFileChooserDialog
class GtkFileChooserDialog(Gtk.FileChooserDialog, BaseFileChooser):
_title = ''
- _filters = []
+ _filters = [] # type: FilterList
_action = Gtk.FileChooserAction.OPEN
_preivew_size = (200, 200)
=====================================
gajim/gtk/types.py
=====================================
@@ -0,0 +1,22 @@
+# This file is part of Gajim.
+#
+# Gajim 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; version 3 only.
+#
+# Gajim 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 Gajim. If not, see <http://www.gnu.org/licenses/>.
+
+# Types for typechecking
+
+from typing import ClassVar
+from typing import List
+
+from gajim.gtk.const import Filter
+
+FilterList = ClassVar[List[Filter]]
=====================================
gajim/gtkexcepthook.py
=====================================
@@ -17,6 +17,8 @@
# You should have received a copy of the GNU General Public License
# along with Gajim. If not, see <http://www.gnu.org/licenses/>.
+from typing import cast
+
import sys
import os
import traceback
@@ -40,7 +42,8 @@ if __name__ == '__main__':
glade_file = os.path.join('data', 'gui', 'exception_dialog.ui')
else:
from gajim.common import configpaths
- glade_file = os.path.join(configpaths.get('GUI'), 'exception_dialog.ui')
+ gui_path = cast(str, configpaths.get('GUI'))
+ glade_file = os.path.join(gui_path, 'exception_dialog.ui')
_exception_in_progress = threading.Lock()
=====================================
gajim/gui_interface.py
=====================================
@@ -2714,10 +2714,8 @@ class Interface:
app.nicks[a] = app.config.get_per('accounts', a, 'name')
app.block_signed_in_notifications[a] = True
app.sleeper_state[a] = 0
- app.encrypted_chats[a] = []
app.last_message_time[a] = {}
app.status_before_autoaway[a] = ''
- app.transport_avatar[a] = {}
app.gajim_optional_features[a] = []
app.caps_hash[a] = ''
=====================================
gajim/htmltextview.py
=====================================
@@ -44,10 +44,6 @@ from gi.repository import Gtk
from gi.repository import Gdk
from gi.repository import GdkPixbuf
-if __name__ == '__main__':
- from gajim.common import configpaths
- configpaths.init()
-
from gajim.common import app
from gajim.common import helpers
from gajim.common.i18n import _
@@ -1086,185 +1082,3 @@ class HtmlTextView(Gtk.TextView):
self.add_child_at_anchor(emoji, anchor)
buffer_.delete_mark(start_mark)
buffer_.delete_mark(end_mark)
-
-change_cursor = None
-
-if __name__ == '__main__':
- from gajim.conversation_textview import ConversationTextview
- from gajim.gui_interface import Interface
-
- Interface()
-
- # create fake app.plugin_manager.gui_extension_point method for tests
- def extension_point(*args):
- pass
- def gui_extension_point(*args):
- pass
- app.plugin_manager = Interface()
- app.plugin_manager.extension_point = extension_point
- app.plugin_manager.gui_extension_point = gui_extension_point
-
- htmlview = ConversationTextview(None)
-
- def on_textview_motion_notify_event(widget, event):
- """
- Change the cursor to a hand when we are over a mail or an url
- """
- global change_cursor
- w = htmlview.tv.get_window(Gtk.TextWindowType.TEXT)
- device = w.get_display().get_device_manager().get_client_pointer()
- pointer = w.get_device_position(device)
- x = pointer[1]
- y = pointer[2]
- tags = htmlview.tv.get_iter_at_location(x, y)[1].get_tags()
- if change_cursor:
- w.set_cursor(get_cursor('XTERM'))
- change_cursor = None
- for tag in tags:
- try:
- if tag.is_anchor:
- w.set_cursor(get_cursor('HAND2'))
- change_cursor = tag
- except Exception:
- pass
-
- htmlview.tv.connect('motion_notify_event', on_textview_motion_notify_event)
-
- def handler(texttag, widget, event, iter_, kind):
- if event.type == Gdk.EventType.BUTTON_PRESS:
- pass
-
- htmlview.tv.hyperlink_handler = htmlview.hyperlink_handler
-
- htmlview.print_real_text(None, xhtml='<div>'
- '<span style="color: red; text-decoration:underline">Hello</span><br/>\n'
- ' <img src="http://images.slashdot.org/topics/topicsoftware.gif"/><br/>\n'
- '<span style="font-size: 500%; font-family: serif">World</span>\n'
- '</div>\n')
- htmlview.print_real_text(None, xhtml='<hr />')
- htmlview.print_real_text(None, xhtml='''
- <body xmlns='http://www.w3.org/1999/xhtml'>
- <p xmlns='http://www.w3.org/1999/xhtml'>a:b
- <a href='http://google.com/' xmlns='http://www.w3.org/1999/xhtml'>Google
- </a>
- </p><br/>
- </body>''')
- htmlview.print_real_text(None, xhtml='''
- <body xmlns='http://www.w3.org/1999/xhtml'>
- <p style='font-size:large'>
- <span style='font-style: italic'>O
- <span style='font-size:larger'>M</span>G</span>,
- I'm <span style='color:green'>green</span>
- with <span style='font-weight: bold'>envy</span>!
- </p>
- </body>
- ''')
- htmlview.print_real_text(None, xhtml='<hr />')
- htmlview.print_real_text(None, xhtml='''
- <body xmlns='http://www.w3.org/1999/xhtml'>
- http://test.com/ testing links autolinkifying
- </body>
- ''')
- htmlview.print_real_text(None, xhtml='<hr />')
- htmlview.print_real_text(None, xhtml='''
- <body xmlns='http://www.w3.org/1999/xhtml'>
- <p>As Emerson said in his essay <span style='
- font-style: italic; background-color:cyan'>Self-Reliance</span>:</p>
- <p style='margin-left: 5px; margin-right: 2%'>
- "A foolish consistency is the hobgoblin of little minds."
- </p>
- </body>
- ''')
- htmlview.print_real_text(None, xhtml='<hr />')
- htmlview.print_real_text(None, xhtml='''
- <body xmlns='http://www.w3.org/1999/xhtml'>
- <p style='text-align:center'>
- Hey, are you licensed to <a href='http://www.jabber.org/'>Jabber</a>?
- </p>
- <p style='text-align:right'>
- <img src='http://www.xmpp.org/images/psa-license.jpg'
- alt='A License to Jabber' width='50%' height='50%'/>
- </p>
- </body>
- ''')
- htmlview.print_real_text(None, xhtml='<hr />')
- htmlview.print_real_text(None, xhtml='''
- <body xmlns='http://www.w3.org/1999/xhtml'>
- <ul style='background-color:rgb(120,140,100)'>
- <li> One </li>
- <li> Two </li>
- <li> Three </li>
- </ul><hr /><pre style="background-color:rgb(120,120,120)">def fac(n):
-def faciter(n,acc):
- if n==0: return acc
- return faciter(n-1, acc*n)
-if n<0: raise ValueError('Must be non-negative')
-return faciter(n,1)</pre>
- </body>
- ''')
- htmlview.print_real_text(None, xhtml='<hr />')
- htmlview.print_real_text(None, xhtml='''
- <body xmlns='http://www.w3.org/1999/xhtml'>
- <ol style='background-color:rgb(120,140,100)'>
- <li> One </li>
- <li> Two is nested: <ul style='background-color:rgb(200,200,100)'>
- <li> One </li>
- <li style='font-size:50%'> Two </li>
- <li style='font-size:200%'> Three </li>
- <li style='font-size:9999pt'> Four </li>
- </ul></li>
- <li> Three </li></ol>
- </body>
- ''')
- htmlview.print_real_text(None, xhtml='<hr />')
- htmlview.print_real_text(None, xhtml='''
- <body xmlns='http://www.w3.org/1999/xhtml'>
- <p>
- <strong>
- <a href='xmpp:example@example.org'>xmpp link</a>
- </strong>: </p>
- <div xmlns='http://www.w3.org/1999/xhtml'>
- <cite style='margin: 7px;' title='xmpp:examples@example.org'>
- <p>
- <strong>examples(a)example.org wrote:</strong>
- </p>
- <p>this cite - bla bla bla, smile- :-) …</p>
- </cite>
- <div>
- <p>some text</p>
- </div>
- </div>
- <p/>
- <p>#232/1</p>
- </body>
- ''')
- htmlview.print_real_text(None, xhtml='<hr />')
- htmlview.print_real_text(None, xhtml='''
- <body xmlns='http://www.w3.org/1999/xhtml'>
- <br/>
-<img src='data:image/png;base64,R0lGODdhMAAwAPAAAAAAAP///ywAAAAAMAAw\
-AAAC8IyPqcvt3wCcDkiLc7C0qwyGHhSWpjQu5yqmCYsapyuvUUlvONmOZtfzgFz\
-ByTB10QgxOR0TqBQejhRNzOfkVJ+5YiUqrXF5Y5lKh/DeuNcP5yLWGsEbtLiOSp\
-a/TPg7JpJHxyendzWTBfX0cxOnKPjgBzi4diinWGdkF8kjdfnycQZXZeYGejmJl\
-ZeGl9i2icVqaNVailT6F5iJ90m6mvuTS4OK05M0vDk0Q4XUtwvKOzrcd3iq9uis\
-F81M1OIcR7lEewwcLp7tuNNkM3uNna3F2JQFo97Vriy/Xl4/f1cf5VWzXyym7PH\
-hhx4dbgYKAAA7' alt='Larry'/>
- </body>
- ''')
- htmlview.tv.show()
- sw = Gtk.ScrolledWindow()
- sw.set_property('hscrollbar-policy', Gtk.PolicyType.AUTOMATIC)
- sw.set_property('vscrollbar-policy', Gtk.PolicyType.AUTOMATIC)
- sw.set_property('border-width', 0)
- sw.add(htmlview.tv)
- sw.show()
- frame = Gtk.Frame()
- frame.set_shadow_type(Gtk.ShadowType.IN)
- frame.show()
- frame.add(sw)
- win = Gtk.Window()
- win.add(frame)
- win.set_default_size(400, 300)
- win.show_all()
- win.connect('destroy', lambda win: Gtk.main_quit())
- Gtk.main()
=====================================
gajim/plugins/gajimplugin.py
=====================================
@@ -21,15 +21,25 @@ Base class for implementing plugin.
:license: GPL
'''
+from typing import List # pylint: disable=W0611
+from typing import Tuple # pylint: disable=W0611
+from typing import Dict # pylint: disable=W0611
+from typing import Any # pylint: disable=W0611
+
import os
import locale
+import logging
+import pickle
from gajim.common import configpaths
+from gajim.common.types import PluginExtensionPoints # pylint: disable=W0611
+from gajim.common.types import EventHandlersDict # pylint: disable=W0611
+from gajim.common.types import PluginEvents # pylint: disable=W0611
from gajim.plugins.helpers import log_calls, log
from gajim.plugins.gui import GajimPluginConfigDialog
-import logging
+
log = logging.getLogger('gajim.p.plugin')
@@ -86,7 +96,7 @@ class GajimPlugin:
:todo: should be allow rich text here (like HTML or reStructuredText)?
'''
- authors = []
+ authors = [] # type: List[str]
'''
Plugin authors.
@@ -104,7 +114,7 @@ class GajimPlugin:
:todo: should we check whether provided string is valid URI? (Maybe
using 'property')
'''
- gui_extension_points = {}
+ gui_extension_points = {} # type: PluginExtensionPoints
'''
Extension points that plugin wants to connect with and handlers to be used.
@@ -118,7 +128,7 @@ class GajimPlugin:
or when extpoint is destroyed and plugin is activate (eg. chat window
closed).
'''
- config_default_values = {}
+ config_default_values = {} # type: Dict[str, Tuple[Any, str]]
'''
Default values for keys that should be stored in plug-in config.
@@ -132,7 +142,7 @@ class GajimPlugin:
:type: {} of 2-element tuples
'''
- events_handlers = {}
+ events_handlers = {} # type: EventHandlersDict
'''
Dictionary with events handlers.
@@ -143,7 +153,7 @@ class GajimPlugin:
:type: {} with 2-element tuples
'''
- events = []
+ events = [] # type: PluginEvents
'''
New network event classes to be registered in Network Events Controller.
@@ -152,7 +162,7 @@ class GajimPlugin:
'''
@log_calls('GajimPlugin')
- def __init__(self):
+ def __init__(self) -> None:
self.config = GajimPluginConfig(self)
'''
Plug-in configuration dictionary.
@@ -168,11 +178,11 @@ class GajimPlugin:
self.init()
@log_calls('GajimPlugin')
- def save_config(self):
+ def save_config(self) -> None:
self.config.save()
@log_calls('GajimPlugin')
- def load_config(self):
+ def load_config(self) -> None:
self.config.load()
def __eq__(self, plugin):
@@ -203,7 +213,6 @@ class GajimPlugin:
def deactivate(self):
pass
-import pickle
class GajimPluginConfig():
@log_calls('GajimPluginConfig')
=====================================
test/gtk/htmltextview.py
=====================================
@@ -0,0 +1,188 @@
+import sys
+import os
+from unittest.mock import MagicMock
+
+sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), '..', '..')))
+
+from gi.repository import Gtk, Gdk
+
+from gajim.common import app
+from gajim.common import configpaths
+configpaths.init()
+from gajim.common import caps_cache
+
+from gajim.gtk.util import get_cursor
+from gajim.conversation_textview import ConversationTextview
+from gajim.gui_interface import Interface
+
+
+caps_cache.capscache = MagicMock()
+app.plugin_manager = MagicMock()
+app.logger = MagicMock()
+app.interface = Interface()
+
+change_cursor = None
+htmlview = ConversationTextview(None)
+
+def on_textview_motion_notify_event(widget, event):
+ """
+ Change the cursor to a hand when we are over a mail or an url
+ """
+ global change_cursor
+ w = htmlview.tv.get_window(Gtk.TextWindowType.TEXT)
+ device = w.get_display().get_device_manager().get_client_pointer()
+ pointer = w.get_device_position(device)
+ x = pointer[1]
+ y = pointer[2]
+ tags = htmlview.tv.get_iter_at_location(x, y)[1].get_tags()
+ if change_cursor:
+ w.set_cursor(get_cursor('XTERM'))
+ change_cursor = None
+ for tag in tags:
+ try:
+ if tag.is_anchor:
+ w.set_cursor(get_cursor('HAND2'))
+ change_cursor = tag
+ except Exception:
+ pass
+
+htmlview.tv.connect('motion_notify_event', on_textview_motion_notify_event)
+
+def handler(texttag, widget, event, iter_, kind):
+ if event.type == Gdk.EventType.BUTTON_PRESS:
+ pass
+
+htmlview.tv.hyperlink_handler = htmlview.hyperlink_handler
+
+htmlview.print_real_text(None, xhtml='<div>'
+'<span style="color: red; text-decoration:underline">Hello</span><br/>\n'
+ ' <img src="http://images.slashdot.org/topics/topicsoftware.gif"/><br/>\n'
+'<span style="font-size: 500%; font-family: serif">World</span>\n'
+ '</div>\n')
+htmlview.print_real_text(None, xhtml='<hr />')
+htmlview.print_real_text(None, xhtml='''
+<body xmlns='http://www.w3.org/1999/xhtml'>
+ <p xmlns='http://www.w3.org/1999/xhtml'>a:b
+ <a href='http://google.com/' xmlns='http://www.w3.org/1999/xhtml'>Google
+ </a>
+ </p><br/>
+</body>''')
+htmlview.print_real_text(None, xhtml='''
+ <body xmlns='http://www.w3.org/1999/xhtml'>
+ <p style='font-size:large'>
+ <span style='font-style: italic'>O
+ <span style='font-size:larger'>M</span>G</span>,
+ I'm <span style='color:green'>green</span>
+ with <span style='font-weight: bold'>envy</span>!
+ </p>
+ </body>
+ ''')
+htmlview.print_real_text(None, xhtml='<hr />')
+htmlview.print_real_text(None, xhtml='''
+<body xmlns='http://www.w3.org/1999/xhtml'>
+ http://test.com/ testing links autolinkifying
+</body>
+ ''')
+htmlview.print_real_text(None, xhtml='<hr />')
+htmlview.print_real_text(None, xhtml='''
+<body xmlns='http://www.w3.org/1999/xhtml'>
+ <p>As Emerson said in his essay <span style='
+ font-style: italic; background-color:cyan'>Self-Reliance</span>:</p>
+ <p style='margin-left: 5px; margin-right: 2%'>
+ "A foolish consistency is the hobgoblin of little minds."
+ </p>
+</body>
+ ''')
+htmlview.print_real_text(None, xhtml='<hr />')
+htmlview.print_real_text(None, xhtml='''
+<body xmlns='http://www.w3.org/1999/xhtml'>
+ <p style='text-align:center'>
+ Hey, are you licensed to <a href='http://www.jabber.org/'>Jabber</a>?
+ </p>
+ <p style='text-align:right'>
+ <img src='http://www.xmpp.org/images/psa-license.jpg'
+ alt='A License to Jabber' width='50%' height='50%'/>
+ </p>
+</body>
+ ''')
+htmlview.print_real_text(None, xhtml='<hr />')
+htmlview.print_real_text(None, xhtml='''
+<body xmlns='http://www.w3.org/1999/xhtml'>
+ <ul style='background-color:rgb(120,140,100)'>
+ <li> One </li>
+ <li> Two </li>
+ <li> Three </li>
+ </ul><hr /><pre style="background-color:rgb(120,120,120)">def fac(n):
+def faciter(n,acc):
+if n==0: return acc
+return faciter(n-1, acc*n)
+if n<0: raise ValueError('Must be non-negative')
+return faciter(n,1)</pre>
+</body>
+ ''')
+htmlview.print_real_text(None, xhtml='<hr />')
+htmlview.print_real_text(None, xhtml='''
+<body xmlns='http://www.w3.org/1999/xhtml'>
+ <ol style='background-color:rgb(120,140,100)'>
+ <li> One </li>
+ <li> Two is nested: <ul style='background-color:rgb(200,200,100)'>
+ <li> One </li>
+ <li style='font-size:50%'> Two </li>
+ <li style='font-size:200%'> Three </li>
+ <li style='font-size:9999pt'> Four </li>
+ </ul></li>
+ <li> Three </li></ol>
+</body>
+ ''')
+htmlview.print_real_text(None, xhtml='<hr />')
+htmlview.print_real_text(None, xhtml='''
+<body xmlns='http://www.w3.org/1999/xhtml'>
+<p>
+ <strong>
+ <a href='xmpp:example@example.org'>xmpp link</a>
+ </strong>: </p>
+<div xmlns='http://www.w3.org/1999/xhtml'>
+ <cite style='margin: 7px;' title='xmpp:examples@example.org'>
+ <p>
+ <strong>examples(a)example.org wrote:</strong>
+ </p>
+ <p>this cite - bla bla bla, smile- :-) …</p>
+ </cite>
+ <div>
+ <p>some text</p>
+ </div>
+</div>
+<p/>
+<p>#232/1</p>
+</body>
+''')
+htmlview.print_real_text(None, xhtml='<hr />')
+htmlview.print_real_text(None, xhtml='''
+<body xmlns='http://www.w3.org/1999/xhtml'>
+<br/>
+<img src='data:image/png;base64,R0lGODdhMAAwAPAAAAAAAP///ywAAAAAMAAw\
+AAAC8IyPqcvt3wCcDkiLc7C0qwyGHhSWpjQu5yqmCYsapyuvUUlvONmOZtfzgFz\
+ByTB10QgxOR0TqBQejhRNzOfkVJ+5YiUqrXF5Y5lKh/DeuNcP5yLWGsEbtLiOSp\
+a/TPg7JpJHxyendzWTBfX0cxOnKPjgBzi4diinWGdkF8kjdfnycQZXZeYGejmJl\
+ZeGl9i2icVqaNVailT6F5iJ90m6mvuTS4OK05M0vDk0Q4XUtwvKOzrcd3iq9uis\
+F81M1OIcR7lEewwcLp7tuNNkM3uNna3F2JQFo97Vriy/Xl4/f1cf5VWzXyym7PH\
+hhx4dbgYKAAA7' alt='Larry'/>
+</body>
+''')
+htmlview.tv.show()
+sw = Gtk.ScrolledWindow()
+sw.set_property('hscrollbar-policy', Gtk.PolicyType.AUTOMATIC)
+sw.set_property('vscrollbar-policy', Gtk.PolicyType.AUTOMATIC)
+sw.set_property('border-width', 0)
+sw.add(htmlview.tv)
+sw.show()
+frame = Gtk.Frame()
+frame.set_shadow_type(Gtk.ShadowType.IN)
+frame.show()
+frame.add(sw)
+win = Gtk.Window()
+win.add(frame)
+win.set_default_size(400, 300)
+win.show_all()
+win.connect('destroy', lambda win: Gtk.main_quit())
+Gtk.main()
=====================================
test/lib/gajim_mocks.py
=====================================
@@ -35,10 +35,8 @@ class MockConnection(Mock, ConnectionHandlers):
app.nicks[account] = app.config.get_per('accounts', account, 'name')
app.block_signed_in_notifications[account] = True
app.sleeper_state[account] = 0
- app.encrypted_chats[account] = []
app.last_message_time[account] = {}
app.status_before_autoaway[account] = ''
- app.transport_avatar[account] = {}
app.gajim_optional_features[account] = []
app.caps_hash[account] = ''
View it on GitLab: https://dev.gajim.org/gajim/gajim/compare/efca9cd9c7296b4be1b2496c1390836f6…
--
View it on GitLab: https://dev.gajim.org/gajim/gajim/compare/efca9cd9c7296b4be1b2496c1390836f6…
You're receiving this email because of your account on dev.gajim.org.
Philipp Hörist pushed to branch master at gajim / gajim
Commits:
6c80473e by Philipp Hörist at 2018-09-18T15:39:35Z
pylint W0143 is not available on pylint < 2.0
- - - - -
2 changed files:
- gajim/common/connection.py
- gajim/gui_menu_builder.py
Changes:
=====================================
gajim/common/connection.py
=====================================
--- a/gajim/common/connection.py
+++ b/gajim/common/connection.py
@@ -1031,7 +1031,7 @@ class Connection(CommonConnection, ConnectionHandlers):
nbxmpp.dispatcher_nb.DEFAULT_TIMEOUT_SECONDS = \
self.try_connecting_for_foo_secs
# FIXME: this is a hack; need a better way
- if self.on_connect_success == self._on_new_account: # pylint: disable=W0143
+ if self.on_connect_success == self._on_new_account:
con.RegisterDisconnectHandler(self._on_new_account)
if self.client_cert and app.config.get_per('accounts', self.name,
=====================================
gajim/gui_menu_builder.py
=====================================
--- a/gajim/gui_menu_builder.py
+++ b/gajim/gui_menu_builder.py
@@ -41,7 +41,6 @@ def build_resources_submenu(contacts, account, action, room_jid=None,
item = Gtk.MenuItem.new_with_label(
'%s (%s)' % (c.resource, str(c.priority)))
sub_menu.append(item)
- # pylint: disable=W0143
if action == roster.on_invite_to_room:
item.connect('activate', action, [(c, account)], room_jid,
room_account, c.resource)
View it on GitLab: https://dev.gajim.org/gajim/gajim/commit/6c80473ebe645e38c38b10a3d67d008f27…
--
View it on GitLab: https://dev.gajim.org/gajim/gajim/commit/6c80473ebe645e38c38b10a3d67d008f27…
You're receiving this email because of your account on dev.gajim.org.