Daniel Brötzmann pushed to branch master at gajim / gajim
Commits: b212d481 by wurstsalat at 2021-12-24T00:39:40+01:00 Helpers: Typing
- - - - - eb7237d6 by wurstsalat at 2021-12-24T01:50:27+01:00 GroupchatRoster: Typing
- - - - - b4147774 by wurstsalat at 2021-12-24T01:56:17+01:00 CallRow: Remove superfluous sound.stop()
- - - - -
4 changed files:
- gajim/common/helpers.py - gajim/gtk/conversation/rows/call.py - gajim/gtk/groupchat_roster.py - gajim/gtk/types.py
Changes:
===================================== gajim/common/helpers.py ===================================== @@ -373,7 +373,10 @@ def get_uf_chatstate(chatstate: str) -> str: return _('has closed the chat window or tab') return ''
-def exec_command(command, use_shell=False, posix=True): +def exec_command(command: str, + use_shell: bool = False, + posix: bool = True + ) -> None: """ execute a command. if use_shell is True, we run the command as is it was typed in a console. So it may be dangerous if you are not sure about what @@ -455,7 +458,7 @@ def _cut_if_long(string_): return reduced_text
-def get_contact_dict_for_account(account): +def get_contact_dict_for_account(account: str) -> Dict[str, types.BareContact]: """ Creates a dict of jid -> contact with all contacts of account Can be used for completion lists @@ -533,7 +536,7 @@ def strip_soundfile_path(file_, dirs=None, abs_=True): return name return file_
-def play_sound_file(path_to_soundfile: str, loop: bool = False): +def play_sound_file(path_to_soundfile: str, loop: bool = False) -> None: path_to_soundfile = check_soundfile_path(path_to_soundfile) if path_to_soundfile is None: return @@ -647,7 +650,7 @@ def get_os_info() -> str: return info
-def message_needs_highlight(text, nickname, own_jid): +def message_needs_highlight(text: str, nickname: str, own_jid: str) -> bool: """ Check text to see whether any of the words in (muc_highlight_words and nick) appear @@ -697,7 +700,7 @@ def allow_sound_notification(account: str, sound_event: str) -> bool: return False
-def get_optional_features(account): +def get_optional_features(account: str) -> List[Namespace]: features = []
if app.settings.get_account_setting(account, 'request_user_data'): @@ -720,7 +723,7 @@ def get_optional_features(account): app.plugin_manager.extension_point('update_caps', account, features) return features
-def jid_is_blocked(account, jid): +def jid_is_blocked(account: str, jid: str) -> bool: con = app.connections[account] return jid in con.get_module('Blocking').blocked
@@ -773,7 +776,7 @@ def version_condition(current_version, required_version): return False return True
-def get_available_emoticon_themes(): +def get_available_emoticon_themes() -> List[str]: files = [] for folder in configpaths.get('EMOTICONS').iterdir(): if not folder.is_dir(): @@ -811,7 +814,7 @@ def load_json(path: Path, return json_dict.get(key, default)
-def ignore_contact(account, jid): +def ignore_contact(account: str, jid: JID) -> bool: client = app.get_client(account) contact = client.get_module('Contacts').get_contact(jid)
@@ -1097,7 +1100,7 @@ def geo_provider_from_location(lat: str, lon: str) -> str: return f'https://www.openstreetmap.org/?mlat=%7Blat%7D&mlon=%7Blon%7D&zoom=16'
-def get_resource(account): +def get_resource(account: str) -> Optional[str]: resource = app.settings.get_account_setting(account, 'resource') if not resource: return None @@ -1129,7 +1132,7 @@ def get_default_muc_config() -> Dict[str, Union[bool, str]]: }
-def validate_jid(jid, type_=None): +def validate_jid(jid: Union[str, JID], type_: Optional[str] = None) -> JID: try: jid = JID.from_string(str(jid)) except InvalidJid as error:
===================================== gajim/gtk/conversation/rows/call.py ===================================== @@ -24,7 +24,6 @@ from gajim.common.const import KindConstant from gajim.common.i18n import _ from gajim.common.jingle_session import JingleSession -from gajim.common import sound
from .widgets import SimpleLabel from .base import BaseRow @@ -96,7 +95,6 @@ def _on_accept(self, button): self.get_parent().accept_call(self._session)
def _on_decline(self, _button): - sound.stop() # dialing/ringing if self._event is not None: session = self._client.get_module('Jingle').get_jingle_session( self._event.fjid, self._event.sid)
===================================== gajim/gtk/groupchat_roster.py ===================================== @@ -12,18 +12,26 @@ # You should have received a copy of the GNU General Public License # along with Gajim. If not, see http://www.gnu.org/licenses/.
+from __future__ import annotations +from typing import Any +from typing import cast from typing import Optional +from typing import Tuple
import locale from enum import IntEnum
+from gi.repository import Gdk from gi.repository import Gtk from gi.repository import GLib from gi.repository import GObject from nbxmpp.const import Affiliation +from nbxmpp.const import Role +from nbxmpp.structs import MessageProperties
from gajim.common import app from gajim.common import ged +from gajim.common import types from gajim.common.helpers import get_uf_role from gajim.common.helpers import get_uf_affiliation from gajim.common.helpers import jid_is_blocked @@ -33,6 +41,7 @@ from gajim.gui_menu_builder import get_groupchat_roster_menu from .tooltips import GCTooltip from .builder import get_builder +from .types import GroupchatControlType from .util import EventHelper
@@ -62,7 +71,11 @@ class GroupchatRoster(Gtk.ScrolledWindow, EventHelper): (str, )) # arguments }
- def __init__(self, account, room_jid, control): + def __init__(self, + account: str, + room_jid: str, + control: GroupchatControlType + ) -> None: Gtk.ScrolledWindow.__init__(self) EventHelper.__init__(self) self.set_policy(Gtk.PolicyType.NEVER, Gtk.PolicyType.AUTOMATIC) @@ -74,14 +87,18 @@ def __init__(self, account, room_jid, control): self._show_roles = True self._tooltip = GCTooltip() self._group_chat_contact = control.contact - self._group_chat_contact.connect('user-avatar-update', - self._on_user_avatar_update) + self._group_chat_contact.connect( + 'user-avatar-update', self._on_user_avatar_update) self._group_chat_contact.connect('user-joined', self._on_user_joined) self._group_chat_contact.connect('user-left', self._on_user_left) - self._group_chat_contact.connect('user-affiliation-changed', self._update_contact) - self._group_chat_contact.connect('user-role-changed', self._update_contact) - self._group_chat_contact.connect('user-status-show-changed', self._on_user_status_show_changed) - self._group_chat_contact.connect('user-nickname-changed', self._on_user_nickname_changed) + self._group_chat_contact.connect( + 'user-affiliation-changed', self._update_contact) + self._group_chat_contact.connect( + 'user-role-changed', self._update_contact) + self._group_chat_contact.connect( + 'user-status-show-changed', self._on_user_status_show_changed) + self._group_chat_contact.connect( + 'user-nickname-changed', self._on_user_nickname_changed) # self._group_chat_contact.connect('muc-user-presence-update', # self._on_muc_user_presence_update)
@@ -90,14 +107,14 @@ def __init__(self, account, room_jid, control): self.add(self._ui.roster_treeview)
# Holds the Gtk.TreeRowReference for each contact - self._contact_refs = {} + self._contact_refs: dict[str, Gtk.TreeRowReference] = {} # Holds the Gtk.TreeRowReference for each group - self._group_refs = {} + self._group_refs: dict[str, Gtk.TreeRowReference] = {}
- self._store = self._ui.participant_store + self._store = cast(Gtk.TreeStore, self._ui.participant_store) self._store.set_sort_func(Column.TEXT, self._tree_compare_iters)
- self._roster = self._ui.roster_treeview + self._roster = cast(Gtk.TreeView, self._ui.roster_treeview) self._roster.set_search_equal_func(self._search_func) self._roster.set_has_tooltip(True) self._roster.connect('query-tooltip', self._query_tooltip) @@ -115,16 +132,22 @@ def __init__(self, account, room_jid, control): ])
@staticmethod - def _on_focus_out(treeview, _param): + def _on_focus_out(treeview: Gtk.TreeView, _param: Gdk.EventFocus) -> None: treeview.get_selection().unselect_all()
- def set_model(self): + def set_model(self) -> None: self._roster.set_model(self._store)
- def set_show_roles(self, enabled): + def set_show_roles(self, enabled: bool) -> None: self._show_roles = enabled
- def _query_tooltip(self, widget, x_pos, y_pos, _keyboard_mode, tooltip): + def _query_tooltip(self, + widget: Gtk.Widget, + x_pos: int, + y_pos: int, + _keyboard_mode: bool, + tooltip: Gtk.Tooltip + ) -> bool: try: row = self._roster.get_path_at_pos(x_pos, y_pos)[0] except TypeError: @@ -154,7 +177,11 @@ def _query_tooltip(self, widget, x_pos, y_pos, _keyboard_mode, tooltip): return value
@staticmethod - def _search_func(model, _column, search_text, iter_): + def _search_func(model: Gtk.TreeModel, + _column: int, + search_text: str, + iter_: Gtk.TreeIter + ) -> bool: return search_text.lower() not in model[iter_][1].lower()
def _get_group_iter(self, group_name: str) -> Optional[Gtk.TreeIter]: @@ -179,10 +206,15 @@ def _get_contact_iter(self, nick: str) -> Optional[Gtk.TreeIter]: return None return self._store.get_iter(path)
- def _on_user_joined(self, _contact, _signal_name, user_contact, *args): + def _on_user_joined(self, + _contact: types.GroupchatContact, + _signal_name: str, + user_contact: types.GroupchatParticipant, + *args: Any + ) -> None: self._add_contact(user_contact)
- def _add_contact(self, contact): + def _add_contact(self, contact: types.GroupchatParticipant) -> None: group_name, group_text = self._get_group_from_contact(contact) nick = contact.name
@@ -212,24 +244,44 @@ def _add_contact(self, contact): self._roster.get_model() is not None): self._roster.expand_row(role_path, False)
- def _on_user_left(self, _contact, _signal_name, user_contact, *args): + def _on_user_left(self, + _contact: types.GroupchatContact, + _signal_name: str, + user_contact: types.GroupchatParticipant, + *args: Any + ) -> None: self._remove_contact(user_contact) self.draw_groups()
- def _update_contact(self, _contact, _signal_name, user_contact, *args): + def _update_contact(self, + _contact: types.GroupchatContact, + _signal_name: str, + user_contact: types.GroupchatParticipant, + *args: Any + ) -> None: self._remove_contact(user_contact) self._add_contact(user_contact)
- def _on_user_nickname_changed(self, contact, _signal_name, user_contact, properties): + def _on_user_nickname_changed(self, + contact: types.GroupchatContact, + _signal_name: str, + user_contact: types.GroupchatParticipant, + properties: MessageProperties + ) -> None: self._remove_contact(user_contact)
user_contact = contact.get_resource(properties.muc_user.nick) self._add_contact(user_contact)
- def _on_user_status_show_changed(self, _contact, _signal_name, user_contact, *args): + def _on_user_status_show_changed(self, + _contact: types.GroupchatContact, + _signal_name: str, + user_contact: types.GroupchatParticipant, + *args: Any + ) -> None: self.draw_contact(user_contact.name)
- def _remove_contact(self, contact): + def _remove_contact(self, contact: types.GroupchatParticipant) -> None: nick = contact.name iter_ = self._get_contact_iter(nick) if not iter_: @@ -247,33 +299,43 @@ def _remove_contact(self, contact): self._store.remove(group_iter)
@staticmethod - def _get_group_from_contact(contact): + def _get_group_from_contact(contact: types.GroupchatParticipant + ) -> Tuple[str, str]: if contact.affiliation in (Affiliation.OWNER, Affiliation.ADMIN): return contact.affiliation.value, get_uf_affiliation( contact.affiliation, plural=True) return contact.role.value, get_uf_role(contact.role, plural=True)
@staticmethod - def _text_cell_data_func(_column, renderer, model, iter_, _user_data): + def _text_cell_data_func(_column: Gtk.TreeViewColumn, + renderer: Gtk.CellRenderer, + model: Gtk.TreeModel, + iter_: Gtk.TreeIter, + _user_data: Optional[object] + ) -> None: has_parent = bool(model.iter_parent(iter_)) style = 'contact' if has_parent else 'group'
- bgcolor = app.css_config.get_value('.gajim-%s-row' % style, + bgcolor = app.css_config.get_value(f'.gajim-{style}-row', StyleAttr.BACKGROUND) renderer.set_property('cell-background', bgcolor)
- color = app.css_config.get_value('.gajim-%s-row' % style, + color = app.css_config.get_value(f'.gajim-{style}-row', StyleAttr.COLOR) renderer.set_property('foreground', color)
- desc = app.css_config.get_font('.gajim-%s-row' % style) + desc = app.css_config.get_font(f'.gajim-{style}-row') renderer.set_property('font-desc', desc)
if not has_parent: renderer.set_property('weight', 600) renderer.set_property('ypad', 6)
- def _on_roster_row_activated(self, _treeview, path, _column): + def _on_roster_row_activated(self, + _treeview: Gtk.TreeView, + path: Gtk.TreePath, + _column: Gtk.TreeViewColumn + ) -> None: iter_ = self._store.get_iter(path) if self._store.iter_parent(iter_) is None: # This is a group row @@ -283,7 +345,10 @@ def _on_roster_row_activated(self, _treeview, path, _column): return self.emit('row-activated', nick)
- def _on_roster_button_press_event(self, treeview, event): + def _on_roster_button_press_event(self, + treeview: Gtk.TreeView, + event: Gdk.EventButton + ) -> None: if event.button not in (2, 3): return
@@ -307,7 +372,7 @@ def _on_roster_button_press_event(self, treeview, event): if event.button == 2: # middle click self.emit('row-activated', nick)
- def _show_contact_menu(self, nick): + def _show_contact_menu(self, nick: str) -> None: self_contact = self._group_chat_contact.get_self() contact = self._group_chat_contact.get_resource(nick) menu = get_groupchat_roster_menu(self._account, @@ -324,11 +389,15 @@ def destroy(menu, _pspec): menu.connect('notify::visible', destroy) menu.popup_at_pointer()
- def _tree_compare_iters(self, model, iter1, iter2, _user_data): + def _tree_compare_iters(self, + model: Gtk.TreeModel, + iter1: Gtk.TreeIter, + iter2: Gtk.TreeIter, + _user_data: Optional[object] + ) -> int: """ Compare two iterators to sort them """ - is_contact = model.iter_parent(iter1) if is_contact: # Sort contacts with pending events to top @@ -356,28 +425,28 @@ def _tree_compare_iters(self, model, iter1, iter2, _user_data): group2_index = AffiliationRoleSortOrder[group2] return -1 if group1_index < group2_index else 1
- def enable_sort(self, enable): + def enable_sort(self, enable: bool) -> None: column = Gtk.TREE_SORTABLE_UNSORTED_SORT_COLUMN_ID if enable: column = Column.TEXT
self._store.set_sort_column_id(column, Gtk.SortType.ASCENDING)
- def invalidate_sort(self): + def invalidate_sort(self) -> None: self.enable_sort(False) self.enable_sort(True)
- def initial_draw(self): + def initial_draw(self) -> None: self.enable_sort(True) self.set_model() self._roster.expand_all()
- def redraw(self): + def redraw(self) -> None: self._roster.set_model(None) self._roster.set_model(self._store) self._roster.expand_all()
- def draw_contact(self, nick): + def draw_contact(self, nick: str) -> None: iter_ = self._get_contact_iter(nick) if not iter_: return @@ -391,9 +460,9 @@ def draw_contact(self, nick): name = GLib.markup_escape_text(contact.name)
# Strike name if blocked - fjid = self.room_jid + '/' + nick + fjid = f'{self.room_jid}/{nick}' if jid_is_blocked(self._account, fjid): - name = '<span strikethrough="true">%s</span>' % name + name = f'<span strikethrough="true">{name}</span>'
# add status msg, if not empty, under contact name status = contact.status @@ -404,16 +473,16 @@ def draw_contact(self, nick): # Display only first line status = status.split('\n', 1)[0] # escape markup entities and make them small italic and fg color - name += ('\n<span size="small" style="italic" alpha="70%">' - '{}</span>'.format(GLib.markup_escape_text(status))) + name += (f'\n<span size="small" style="italic" alpha="70%">' + f'{GLib.markup_escape_text(status)}</span>')
self._store[iter_][Column.TEXT] = name
- def draw_contacts(self): + def draw_contacts(self) -> None: for nick in self._contact_refs: self.draw_contact(nick)
- def draw_group(self, group): + def draw_group(self, group: str) -> None: group_iter = self._get_group_iter(group) if not group_iter: return @@ -426,15 +495,15 @@ def draw_group(self, group): total_users = self._get_total_user_count() group_users = self._store.iter_n_children(group_iter)
- group_text += ' (%s/%s)' % (group_users, total_users) + group_text += f' ({group_users}/{total_users})'
self._store[group_iter][Column.TEXT] = group_text
- def draw_groups(self): + def draw_groups(self) -> None: for group in self._group_refs: self.draw_group(group)
- def draw_avatar(self, contact): + def draw_avatar(self, contact: types.GroupchatParticipant) -> None: iter_ = self._get_contact_iter(contact.name) if iter_ is None: return @@ -446,13 +515,13 @@ def draw_avatar(self, contact): def _on_user_avatar_update(self, _contact, _signal_name, user_contact): self.draw_avatar(user_contact)
- def _get_total_user_count(self): + def _get_total_user_count(self) -> int: count = 0 for group_row in self._store: count += self._store.iter_n_children(group_row.iter) return count
- def get_role(self, nick): + def get_role(self, nick: str) -> Role: contact = self._group_chat_contact.get_resource(nick) return contact.role
@@ -462,12 +531,12 @@ def _on_theme_update(self, _event): def process_avatar_update(self, event): self.draw_avatar(event.contact)
- def clear(self): + def clear(self) -> None: self._contact_refs = {} self._group_refs = {} self._store.clear()
- def _on_destroy(self, _roster): + def _on_destroy(self, _roster: Any) -> None: self._group_chat_contact.disconnect(self)
self._contact_refs = {}
===================================== gajim/gtk/types.py ===================================== @@ -55,3 +55,5 @@ 'PrivateChatControl', 'GroupchatControl' ] + +GroupchatControlType = Union['GroupchatControl']
View it on GitLab: https://dev.gajim.org/gajim/gajim/-/compare/4fdf993e6732382dbe837583136646e3...