Philipp Hörist pushed to branch unify-control at gajim / gajim
Commits:
-
7d4e2c9c
by lovetox at 2022-08-08T23:20:36+02:00
-
92188873
by lovetox at 2022-08-08T23:27:10+02:00
-
41d327d2
by lovetox at 2022-08-08T23:28:33+02:00
-
e12bd5d4
by lovetox at 2022-08-08T23:29:00+02:00
-
19e86bdf
by lovetox at 2022-08-08T23:29:31+02:00
4 changed files:
- gajim/common/helpers.py
- gajim/common/modules/contacts.py
- gajim/gtk/control.py
- gajim/gtk/groupchat_roster.py
Changes:
| ... | ... | @@ -1229,19 +1229,46 @@ def __init__(self, log_: Union[logging.Logger, LogAdapter, None] = None): |
| 1229 | 1229 | self._log = log_
|
| 1230 | 1230 | self._callbacks: types.ObservableCbDict = defaultdict(list)
|
| 1231 | 1231 | |
| 1232 | - def disconnect_signals(self) -> None:
|
|
| 1233 | - self._callbacks = defaultdict(list)
|
|
| 1232 | + def __disconnect(self,
|
|
| 1233 | + obj: Any,
|
|
| 1234 | + signals: Optional[set[str]] = None
|
|
| 1235 | + ) -> None:
|
|
| 1236 | + |
|
| 1237 | + def _remove(handlers: list[weakref.WeakMethod[types.AnyCallableT]]
|
|
| 1238 | + ) -> None:
|
|
| 1234 | 1239 | |
| 1235 | - def disconnect_all_from_obj(self, obj: Any) -> None:
|
|
| 1236 | - for handlers in self._callbacks.values():
|
|
| 1237 | 1240 | for handler in list(handlers):
|
| 1238 | 1241 | func = handler()
|
| 1239 | 1242 | if func is None or func.__self__ is obj:
|
| 1240 | 1243 | handlers.remove(handler)
|
| 1241 | 1244 | |
| 1245 | + if signals is None:
|
|
| 1246 | + for handlers in self._callbacks.values():
|
|
| 1247 | + _remove(handlers)
|
|
| 1248 | + |
|
| 1249 | + else:
|
|
| 1250 | + for signal in signals:
|
|
| 1251 | + _remove(self._callbacks.get(signal, []))
|
|
| 1252 | + |
|
| 1253 | + def disconnect_signals(self) -> None:
|
|
| 1254 | + self._callbacks = defaultdict(list)
|
|
| 1255 | + |
|
| 1256 | + def multi_disconnect(self,
|
|
| 1257 | + obj: Any,
|
|
| 1258 | + signals: Optional[set[str]]
|
|
| 1259 | + ) -> None:
|
|
| 1260 | + |
|
| 1261 | + self.__disconnect(obj, signals)
|
|
| 1262 | + |
|
| 1263 | + def disconnect_all_from_obj(self, obj: Any) -> None:
|
|
| 1264 | + self.__disconnect(obj)
|
|
| 1265 | + |
|
| 1242 | 1266 | def disconnect(self, obj: Any) -> None:
|
| 1243 | 1267 | self.disconnect_all_from_obj(obj)
|
| 1244 | 1268 | |
| 1269 | + def disconnect_signal(self, obj: Any, signal: str) -> None:
|
|
| 1270 | + self.__disconnect(obj, {signal})
|
|
| 1271 | + |
|
| 1245 | 1272 | def connect_signal(self,
|
| 1246 | 1273 | signal_name: str,
|
| 1247 | 1274 | func: types.AnyCallableT) -> None:
|
| ... | ... | @@ -669,6 +669,11 @@ def get_resource(self, resource: str) -> GroupchatParticipant: |
| 669 | 669 | contact = self.add_resource(resource)
|
| 670 | 670 | return contact
|
| 671 | 671 | |
| 672 | + def get_participants(self) -> Iterator[GroupchatParticipant]:
|
|
| 673 | + for contact in self._resources.values():
|
|
| 674 | + if contact.is_available:
|
|
| 675 | + yield contact
|
|
| 676 | + |
|
| 672 | 677 | @property
|
| 673 | 678 | def name(self) -> str:
|
| 674 | 679 | client = app.get_client(self._account)
|
| ... | ... | @@ -119,8 +119,6 @@ def __init__(self) -> None: |
| 119 | 119 | |
| 120 | 120 | self._subject_text_cache: dict[JID, str] = {}
|
| 121 | 121 | |
| 122 | - # self._set_control_inactive()
|
|
| 123 | - |
|
| 124 | 122 | self.widget = cast(Gtk.Box, self._ui.get_object('control_box'))
|
| 125 | 123 | self.widget.show_all()
|
| 126 | 124 | |
| ... | ... | @@ -133,6 +131,8 @@ def has_active_chat(self) -> bool: |
| 133 | 131 | return self.contact is not None
|
| 134 | 132 | |
| 135 | 133 | def clear(self) -> None:
|
| 134 | + log.info('Clear')
|
|
| 135 | + |
|
| 136 | 136 | if self.contact is not None:
|
| 137 | 137 | self.contact.disconnect_all_from_obj(self)
|
| 138 | 138 | |
| ... | ... | @@ -149,6 +149,7 @@ def switch_contact(self, contact: Union[BareContact, |
| 149 | 149 | GroupchatContact,
|
| 150 | 150 | GroupchatParticipant]) -> None:
|
| 151 | 151 | |
| 152 | + log.info('Switch to %s (%s)', contact.jid, contact.account)
|
|
| 152 | 153 | if self.contact is not None:
|
| 153 | 154 | self.contact.disconnect_all_from_obj(self)
|
| 154 | 155 | |
| ... | ... | @@ -179,7 +180,6 @@ def switch_contact(self, contact: Union[BareContact, |
| 179 | 180 | |
| 180 | 181 | elif isinstance(self.contact, GroupchatContact):
|
| 181 | 182 | self.contact.multi_connect({
|
| 182 | - 'state-changed': self._on_muc_state_changed,
|
|
| 183 | 183 | 'user-joined': self._on_user_joined,
|
| 184 | 184 | 'user-left': self._on_user_left,
|
| 185 | 185 | 'user-affiliation-changed': self._on_user_affiliation_changed,
|
| ... | ... | @@ -791,17 +791,6 @@ def _on_user_status_show_changed(self, |
| 791 | 791 | status=status)
|
| 792 | 792 | self.add_info_message(message)
|
| 793 | 793 | |
| 794 | - def _on_muc_state_changed(self,
|
|
| 795 | - _contact: GroupchatContact,
|
|
| 796 | - _signal_name: str
|
|
| 797 | - ) -> None:
|
|
| 798 | - |
|
| 799 | - if self.contact.is_joined:
|
|
| 800 | - self._set_control_active()
|
|
| 801 | - |
|
| 802 | - elif self.contact.is_not_joined:
|
|
| 803 | - self._set_control_inactive()
|
|
| 804 | - |
|
| 805 | 794 | def _on_muc_disco_update(self, event: events.MucDiscoUpdate) -> None:
|
| 806 | 795 | pass
|
| 807 | 796 | |
| ... | ... | @@ -969,18 +958,6 @@ def _on_room_config_changed(self, |
| 969 | 958 | for change in changes:
|
| 970 | 959 | self.add_info_message(change)
|
| 971 | 960 | |
| 972 | - def _set_control_active(self) -> None:
|
|
| 973 | - assert self.roster is not None
|
|
| 974 | - self.roster.initial_draw()
|
|
| 975 | - self.conversation_view.update_avatars()
|
|
| 976 | - |
|
| 977 | - def _set_control_inactive(self) -> None:
|
|
| 978 | - assert self.roster is not None
|
|
| 979 | - self.roster.enable_sort(False)
|
|
| 980 | - self.roster.reset()
|
|
| 981 | - |
|
| 982 | - self._client.get_module('Chatstate').remove_delay_timeout(self.contact)
|
|
| 983 | - |
|
| 984 | 961 | def rejoin(self) -> None:
|
| 985 | 962 | self._client.get_module('MUC').join(self.contact.jid)
|
| 986 | 963 |
| ... | ... | @@ -18,6 +18,7 @@ |
| 18 | 18 | from typing import Optional
|
| 19 | 19 | |
| 20 | 20 | import locale
|
| 21 | +import logging
|
|
| 21 | 22 | from enum import IntEnum
|
| 22 | 23 | |
| 23 | 24 | from gi.repository import Gdk
|
| ... | ... | @@ -44,6 +45,9 @@ |
| 44 | 45 | from .util import EventHelper
|
| 45 | 46 | |
| 46 | 47 | |
| 48 | +log = logging.getLogger('gajim.gui.groupchat_roster')
|
|
| 49 | + |
|
| 50 | + |
|
| 47 | 51 | AffiliationRoleSortOrder = {
|
| 48 | 52 | 'owner': 0,
|
| 49 | 53 | 'admin': 1,
|
| ... | ... | @@ -61,6 +65,17 @@ class Column(IntEnum): |
| 61 | 65 | NICK_OR_GROUP = 4
|
| 62 | 66 | |
| 63 | 67 | |
| 68 | +CONTACT_SIGNALS = {
|
|
| 69 | + 'user-affiliation-changed',
|
|
| 70 | + 'user-avatar-update',
|
|
| 71 | + 'user-joined',
|
|
| 72 | + 'user-left',
|
|
| 73 | + 'user-nickname-changed',
|
|
| 74 | + 'user-role-changed',
|
|
| 75 | + 'user-status-show-changed',
|
|
| 76 | +}
|
|
| 77 | + |
|
| 78 | + |
|
| 64 | 79 | class GroupchatRoster(Gtk.ScrolledWindow, EventHelper):
|
| 65 | 80 | |
| 66 | 81 | __gsignals__ = {
|
| ... | ... | @@ -107,36 +122,33 @@ def __init__(self) -> None: |
| 107 | 122 | ])
|
| 108 | 123 | |
| 109 | 124 | def clear(self) -> None:
|
| 110 | - if self._contact is not None:
|
|
| 111 | - self._contact.disconnect_all_from_obj(self)
|
|
| 112 | - |
|
| 125 | + log.info('Clear')
|
|
| 126 | + if self._contact is None:
|
|
| 127 | + return
|
|
| 128 | + self._unload_roster()
|
|
| 129 | + self._contact.disconnect_signal(self, 'state-changed')
|
|
| 113 | 130 | self._contact = None
|
| 114 | - self.reset()
|
|
| 115 | 131 | |
| 116 | 132 | def switch_contact(self, contact: types.ChatContactT) -> None:
|
| 117 | - self.clear()
|
|
| 133 | + if self._contact is not None:
|
|
| 134 | + self.clear()
|
|
| 118 | 135 | |
| 119 | 136 | if not isinstance(contact, GroupchatContact):
|
| 120 | 137 | return
|
| 121 | 138 | |
| 122 | - contact.connect('user-avatar-update', self._on_user_avatar_update)
|
|
| 123 | - contact.connect('user-joined', self._on_user_joined)
|
|
| 124 | - contact.connect('user-left', self._on_user_left)
|
|
| 125 | - contact.connect('user-affiliation-changed', self._update_contact)
|
|
| 126 | - contact.connect('user-role-changed', self._update_contact)
|
|
| 127 | - contact.connect('user-nickname-changed', self._on_user_nickname_changed)
|
|
| 128 | - contact.connect('user-status-show-changed',
|
|
| 129 | - self._on_user_status_show_changed)
|
|
| 139 | + log.info('Switch to %s (%s)', contact.jid, contact.account)
|
|
| 140 | + |
|
| 141 | + contact.connect('state-changed', self._on_muc_state_changed)
|
|
| 130 | 142 | |
| 131 | 143 | self._contact = contact
|
| 132 | 144 | |
| 145 | + if self._contact.is_joined:
|
|
| 146 | + self._load_roster()
|
|
| 147 | + |
|
| 133 | 148 | @staticmethod
|
| 134 | 149 | def _on_focus_out(treeview: Gtk.TreeView, _param: Gdk.EventFocus) -> None:
|
| 135 | 150 | treeview.get_selection().unselect_all()
|
| 136 | 151 | |
| 137 | - def _set_model(self) -> None:
|
|
| 138 | - self._roster.set_model(self._store)
|
|
| 139 | - |
|
| 140 | 152 | def _query_tooltip(self,
|
| 141 | 153 | widget: Gtk.Widget,
|
| 142 | 154 | x_pos: int,
|
| ... | ... | @@ -393,6 +405,17 @@ def destroy(popover: Gtk.Popover) -> None: |
| 393 | 405 | popover.connect('closed', destroy)
|
| 394 | 406 | popover.popup()
|
| 395 | 407 | |
| 408 | + def _on_muc_state_changed(self,
|
|
| 409 | + contact: GroupchatContact,
|
|
| 410 | + _signal_name: str
|
|
| 411 | + ) -> None:
|
|
| 412 | + |
|
| 413 | + if contact.is_joined:
|
|
| 414 | + self._load_roster()
|
|
| 415 | + |
|
| 416 | + elif contact.is_not_joined:
|
|
| 417 | + self._unload_roster()
|
|
| 418 | + |
|
| 396 | 419 | def _tree_compare_iters(self,
|
| 397 | 420 | model: Gtk.TreeModel,
|
| 398 | 421 | iter1: Gtk.TreeIter,
|
| ... | ... | @@ -436,15 +459,40 @@ def enable_sort(self, enable: bool) -> None: |
| 436 | 459 | |
| 437 | 460 | self._store.set_sort_column_id(column, Gtk.SortType.ASCENDING)
|
| 438 | 461 | |
| 439 | - def invalidate_sort(self) -> None:
|
|
| 440 | - self.enable_sort(False)
|
|
| 441 | - self.enable_sort(True)
|
|
| 462 | + def _load_roster(self) -> None:
|
|
| 463 | + log.info('Load Roster')
|
|
| 464 | + self._contact.multi_connect({
|
|
| 465 | + 'user-affiliation-changed': self._update_contact,
|
|
| 466 | + 'user-avatar-update': self._on_user_avatar_update,
|
|
| 467 | + 'user-joined': self._on_user_joined,
|
|
| 468 | + 'user-left': self._on_user_left,
|
|
| 469 | + 'user-nickname-changed': self._on_user_nickname_changed,
|
|
| 470 | + 'user-role-changed': self._update_contact,
|
|
| 471 | + 'user-status-show-changed': self._on_user_status_show_changed,
|
|
| 472 | + })
|
|
| 473 | + |
|
| 474 | + for participant in self._contact.get_participants():
|
|
| 475 | + self._add_contact(participant)
|
|
| 442 | 476 | |
| 443 | - def initial_draw(self) -> None:
|
|
| 444 | 477 | self.enable_sort(True)
|
| 445 | - self._set_model()
|
|
| 478 | + self._roster.set_model(self._store)
|
|
| 446 | 479 | self._roster.expand_all()
|
| 447 | 480 | |
| 481 | + def _unload_roster(self) -> None:
|
|
| 482 | + log.info('Unload Roster')
|
|
| 483 | + self._contact.multi_disconnect(self, CONTACT_SIGNALS)
|
|
| 484 | + |
|
| 485 | + self._roster.set_model(None)
|
|
| 486 | + self._store.clear()
|
|
| 487 | + self.enable_sort(False)
|
|
| 488 | + |
|
| 489 | + self._contact_refs = {}
|
|
| 490 | + self._group_refs = {}
|
|
| 491 | + |
|
| 492 | + def invalidate_sort(self) -> None:
|
|
| 493 | + self.enable_sort(False)
|
|
| 494 | + self.enable_sort(True)
|
|
| 495 | + |
|
| 448 | 496 | def _redraw(self) -> None:
|
| 449 | 497 | self._roster.set_model(None)
|
| 450 | 498 | self._roster.set_model(self._store)
|
| ... | ... | @@ -530,8 +578,3 @@ def _get_total_user_count(self) -> int: |
| 530 | 578 | |
| 531 | 579 | def _on_theme_update(self, _event: ApplicationEvent) -> None:
|
| 532 | 580 | self._redraw() |
| 533 | - |
|
| 534 | - def reset(self) -> None:
|
|
| 535 | - self._contact_refs = {}
|
|
| 536 | - self._group_refs = {}
|
|
| 537 | - self._store.clear() |