Daniel Brötzmann pushed to branch newcontrol at gajim / gajim
Commits:
-
1627d7ae
by wurstsalat at 2022-07-11T13:32:03+02:00
-
3d849e73
by wurstsalat at 2022-07-11T13:32:39+02:00
-
58aa8db0
by wurstsalat at 2022-07-11T13:36:53+02:00
9 changed files:
- gajim/common/modules/contacts.py
- gajim/data/gui/groupchat_control.ui
- gajim/gtk/chat_banner.py
- gajim/gtk/chat_stack.py
- gajim/gtk/const.py
- gajim/gtk/controls/base.py
- gajim/gtk/controls/groupchat.py
- gajim/gtk/menus.py
- gajim/gtk/message_actions_box.py
Changes:
| ... | ... | @@ -551,6 +551,13 @@ def __init__(self, logger: LogAdapter, jid: JID, account: str) -> None: |
| 551 | 551 | def is_groupchat(self) -> bool:
|
| 552 | 552 | return True
|
| 553 | 553 | |
| 554 | + @property
|
|
| 555 | + def is_irc(self) -> bool:
|
|
| 556 | + disco_info = self.get_disco()
|
|
| 557 | + if disco_info is None:
|
|
| 558 | + return False
|
|
| 559 | + return disco_info.is_irc
|
|
| 560 | + |
|
| 554 | 561 | def add_resource(self, resource: str) -> GroupchatParticipant:
|
| 555 | 562 | jid = self._jid.new_with(resource=resource)
|
| 556 | 563 | assert isinstance(self._log, LogAdapter)
|
| ... | ... | @@ -921,164 +921,7 @@ |
| 921 | 921 | </packing>
|
| 922 | 922 | </child>
|
| 923 | 923 | <child>
|
| 924 | - <object class="GtkBox">
|
|
| 925 | - <property name="visible">True</property>
|
|
| 926 | - <property name="can-focus">False</property>
|
|
| 927 | - <property name="orientation">vertical</property>
|
|
| 928 | - <child>
|
|
| 929 | - <!-- n-columns=1 n-rows=6 -->
|
|
| 930 | - <object class="GtkGrid">
|
|
| 931 | - <property name="visible">True</property>
|
|
| 932 | - <property name="can-focus">False</property>
|
|
| 933 | - <property name="halign">center</property>
|
|
| 934 | - <property name="valign">center</property>
|
|
| 935 | - <property name="hexpand">True</property>
|
|
| 936 | - <property name="vexpand">True</property>
|
|
| 937 | - <property name="row-spacing">6</property>
|
|
| 938 | - <child>
|
|
| 939 | - <object class="GtkLabel">
|
|
| 940 | - <property name="visible">True</property>
|
|
| 941 | - <property name="can-focus">False</property>
|
|
| 942 | - <property name="margin-bottom">6</property>
|
|
| 943 | - <property name="label" translatable="yes">Destroy This Chat</property>
|
|
| 944 | - <property name="ellipsize">end</property>
|
|
| 945 | - <property name="single-line-mode">True</property>
|
|
| 946 | - <property name="max-width-chars">22</property>
|
|
| 947 | - <property name="xalign">0</property>
|
|
| 948 | - <style>
|
|
| 949 | - <class name="bold16"/>
|
|
| 950 | - </style>
|
|
| 951 | - </object>
|
|
| 952 | - <packing>
|
|
| 953 | - <property name="left-attach">0</property>
|
|
| 954 | - <property name="top-attach">0</property>
|
|
| 955 | - </packing>
|
|
| 956 | - </child>
|
|
| 957 | - <child>
|
|
| 958 | - <object class="GtkBox">
|
|
| 959 | - <property name="visible">True</property>
|
|
| 960 | - <property name="can-focus">False</property>
|
|
| 961 | - <property name="homogeneous">True</property>
|
|
| 962 | - <child>
|
|
| 963 | - <object class="GtkButton">
|
|
| 964 | - <property name="label" translatable="yes">_Cancel</property>
|
|
| 965 | - <property name="visible">True</property>
|
|
| 966 | - <property name="can-focus">True</property>
|
|
| 967 | - <property name="receives-default">True</property>
|
|
| 968 | - <property name="halign">start</property>
|
|
| 969 | - <property name="valign">start</property>
|
|
| 970 | - <property name="use-underline">True</property>
|
|
| 971 | - <signal name="clicked" handler="_on_page_cancel_clicked" swapped="no"/>
|
|
| 972 | - </object>
|
|
| 973 | - <packing>
|
|
| 974 | - <property name="expand">False</property>
|
|
| 975 | - <property name="fill">True</property>
|
|
| 976 | - <property name="position">0</property>
|
|
| 977 | - </packing>
|
|
| 978 | - </child>
|
|
| 979 | - <child>
|
|
| 980 | - <object class="GtkButton" id="destroy_button">
|
|
| 981 | - <property name="label" translatable="yes">_Destroy</property>
|
|
| 982 | - <property name="visible">True</property>
|
|
| 983 | - <property name="can-focus">True</property>
|
|
| 984 | - <property name="can-default">True</property>
|
|
| 985 | - <property name="receives-default">True</property>
|
|
| 986 | - <property name="halign">end</property>
|
|
| 987 | - <property name="valign">start</property>
|
|
| 988 | - <property name="use-underline">True</property>
|
|
| 989 | - <signal name="clicked" handler="_on_destroy_confirm" swapped="no"/>
|
|
| 990 | - <style>
|
|
| 991 | - <class name="destructive-action"/>
|
|
| 992 | - </style>
|
|
| 993 | - </object>
|
|
| 994 | - <packing>
|
|
| 995 | - <property name="expand">False</property>
|
|
| 996 | - <property name="fill">True</property>
|
|
| 997 | - <property name="position">1</property>
|
|
| 998 | - </packing>
|
|
| 999 | - </child>
|
|
| 1000 | - </object>
|
|
| 1001 | - <packing>
|
|
| 1002 | - <property name="left-attach">0</property>
|
|
| 1003 | - <property name="top-attach">5</property>
|
|
| 1004 | - </packing>
|
|
| 1005 | - </child>
|
|
| 1006 | - <child>
|
|
| 1007 | - <object class="GtkEntry" id="destroy_alternate_entry">
|
|
| 1008 | - <property name="width-request">200</property>
|
|
| 1009 | - <property name="visible">True</property>
|
|
| 1010 | - <property name="can-focus">True</property>
|
|
| 1011 | - <property name="margin-bottom">6</property>
|
|
| 1012 | - <property name="activates-default">True</property>
|
|
| 1013 | - <property name="caps-lock-warning">False</property>
|
|
| 1014 | - <property name="secondary-icon-tooltip-text" translatable="yes">Insert Emoji</property>
|
|
| 1015 | - <property name="placeholder-text" translatable="yes">Alternate venue (optional)...</property>
|
|
| 1016 | - <signal name="notify::text" handler="_on_destroy_alternate_changed" swapped="no"/>
|
|
| 1017 | - </object>
|
|
| 1018 | - <packing>
|
|
| 1019 | - <property name="left-attach">0</property>
|
|
| 1020 | - <property name="top-attach">4</property>
|
|
| 1021 | - </packing>
|
|
| 1022 | - </child>
|
|
| 1023 | - <child>
|
|
| 1024 | - <object class="GtkEntry" id="destroy_reason_entry">
|
|
| 1025 | - <property name="width-request">200</property>
|
|
| 1026 | - <property name="visible">True</property>
|
|
| 1027 | - <property name="can-focus">True</property>
|
|
| 1028 | - <property name="margin-bottom">6</property>
|
|
| 1029 | - <property name="activates-default">True</property>
|
|
| 1030 | - <property name="caps-lock-warning">False</property>
|
|
| 1031 | - <property name="secondary-icon-tooltip-text" translatable="yes">Insert Emoji</property>
|
|
| 1032 | - <property name="placeholder-text" translatable="yes">Reason (optional)...</property>
|
|
| 1033 | - <property name="show-emoji-icon">True</property>
|
|
| 1034 | - </object>
|
|
| 1035 | - <packing>
|
|
| 1036 | - <property name="left-attach">0</property>
|
|
| 1037 | - <property name="top-attach">2</property>
|
|
| 1038 | - </packing>
|
|
| 1039 | - </child>
|
|
| 1040 | - <child>
|
|
| 1041 | - <object class="GtkLabel">
|
|
| 1042 | - <property name="visible">True</property>
|
|
| 1043 | - <property name="can-focus">False</property>
|
|
| 1044 | - <property name="halign">start</property>
|
|
| 1045 | - <property name="label" translatable="yes">Reason for destruction</property>
|
|
| 1046 | - <style>
|
|
| 1047 | - <class name="dim-label"/>
|
|
| 1048 | - </style>
|
|
| 1049 | - </object>
|
|
| 1050 | - <packing>
|
|
| 1051 | - <property name="left-attach">0</property>
|
|
| 1052 | - <property name="top-attach">1</property>
|
|
| 1053 | - </packing>
|
|
| 1054 | - </child>
|
|
| 1055 | - <child>
|
|
| 1056 | - <object class="GtkLabel">
|
|
| 1057 | - <property name="visible">True</property>
|
|
| 1058 | - <property name="can-focus">False</property>
|
|
| 1059 | - <property name="halign">start</property>
|
|
| 1060 | - <property name="label" translatable="yes">Where participants should go</property>
|
|
| 1061 | - <style>
|
|
| 1062 | - <class name="dim-label"/>
|
|
| 1063 | - </style>
|
|
| 1064 | - </object>
|
|
| 1065 | - <packing>
|
|
| 1066 | - <property name="left-attach">0</property>
|
|
| 1067 | - <property name="top-attach">3</property>
|
|
| 1068 | - </packing>
|
|
| 1069 | - </child>
|
|
| 1070 | - </object>
|
|
| 1071 | - <packing>
|
|
| 1072 | - <property name="expand">False</property>
|
|
| 1073 | - <property name="fill">True</property>
|
|
| 1074 | - <property name="position">0</property>
|
|
| 1075 | - </packing>
|
|
| 1076 | - </child>
|
|
| 1077 | - </object>
|
|
| 1078 | - <packing>
|
|
| 1079 | - <property name="name">destroy</property>
|
|
| 1080 | - <property name="position">8</property>
|
|
| 1081 | - </packing>
|
|
| 924 | + <placeholder/>
|
|
| 1082 | 925 | </child>
|
| 1083 | 926 | <child>
|
| 1084 | 927 | <object class="GtkBox">
|
| ... | ... | @@ -17,7 +17,6 @@ |
| 17 | 17 | from typing import Any
|
| 18 | 18 | from typing import Optional
|
| 19 | 19 | |
| 20 | -from gi.repository import Gio
|
|
| 21 | 20 | from gi.repository import Gtk
|
| 22 | 21 | |
| 23 | 22 | import cairo
|
| ... | ... | @@ -73,9 +72,6 @@ def __init__(self) -> None: |
| 73 | 72 | 'hide_groupchat_occupants_list',
|
| 74 | 73 | self._set_toggle_roster_button_icon)
|
| 75 | 74 | |
| 76 | - action = Gio.SimpleAction.new('request-voice', None)
|
|
| 77 | - app.window.add_action(action)
|
|
| 78 | - |
|
| 79 | 75 | self.show_all()
|
| 80 | 76 | |
| 81 | 77 | def switch_contact(self,
|
| ... | ... | @@ -290,7 +286,7 @@ def _update_account_badge(self) -> None: |
| 290 | 286 | |
| 291 | 287 | def _on_request_voice_clicked(self, _button: Gtk.Button) -> None:
|
| 292 | 288 | self._ui.visitor_popover.popdown()
|
| 293 | - app.window.activate_action('request-voice', None)
|
|
| 289 | + app.window.activate_action('muc-request-voice', None)
|
|
| 294 | 290 | |
| 295 | 291 | def _on_toggle_roster_clicked(self, _button: Gtk.Button) -> None:
|
| 296 | 292 | state = app.settings.get('hide_groupchat_occupants_list')
|
| ... | ... | @@ -28,6 +28,7 @@ |
| 28 | 28 | from nbxmpp.structs import PresenceProperties
|
| 29 | 29 | |
| 30 | 30 | from gajim.common import app, helpers
|
| 31 | +from gajim.common.events import MucDiscoUpdate
|
|
| 31 | 32 | from gajim.common.i18n import _
|
| 32 | 33 | from gajim.common.const import CallType
|
| 33 | 34 | from gajim.common.modules.contacts import BareContact
|
| ... | ... | @@ -38,6 +39,7 @@ |
| 38 | 39 | |
| 39 | 40 | from .chat_banner import ChatBanner
|
| 40 | 41 | from .control_stack import ControlStack
|
| 42 | +from .controls.groupchat import GroupchatControl
|
|
| 41 | 43 | from .message_actions_box import MessageActionsBox
|
| 42 | 44 | from .util import EventHelper, open_window
|
| 43 | 45 | |
| ... | ... | @@ -92,8 +94,10 @@ def show_chat(self, account: str, jid: JID) -> None: |
| 92 | 94 | self._update_base_actions(self._current_contact)
|
| 93 | 95 | if isinstance(self._current_contact, GroupchatContact):
|
| 94 | 96 | self._current_contact.multi_connect({
|
| 97 | + 'user-joined': self._on_user_joined,
|
|
| 95 | 98 | 'user-role-changed': self._on_user_role_changed,
|
| 96 | - 'state-changed': self._on_muc_state_changed
|
|
| 99 | + 'user-affiliation-changed': self._on_user_affiliation_changed,
|
|
| 100 | + 'state-changed': self._on_muc_state_changed,
|
|
| 97 | 101 | })
|
| 98 | 102 | self._update_group_chat_actions(self._current_contact)
|
| 99 | 103 | elif isinstance(self._current_contact, GroupchatParticipant):
|
| ... | ... | @@ -109,6 +113,14 @@ def _on_muc_state_changed(self, |
| 109 | 113 | ) -> None:
|
| 110 | 114 | self._update_group_chat_actions(contact)
|
| 111 | 115 | |
| 116 | + def _on_user_joined(self,
|
|
| 117 | + contact: GroupchatContact,
|
|
| 118 | + _signal_name: str,
|
|
| 119 | + _user_contact: GroupchatParticipant,
|
|
| 120 | + _properties: PresenceProperties
|
|
| 121 | + ) -> None:
|
|
| 122 | + self._update_group_chat_actions(contact)
|
|
| 123 | + |
|
| 112 | 124 | def _on_user_role_changed(self,
|
| 113 | 125 | contact: GroupchatContact,
|
| 114 | 126 | _signal_name: str,
|
| ... | ... | @@ -117,6 +129,24 @@ def _on_user_role_changed(self, |
| 117 | 129 | ) -> None:
|
| 118 | 130 | self._update_group_chat_actions(contact)
|
| 119 | 131 | |
| 132 | + def _on_user_affiliation_changed(self,
|
|
| 133 | + contact: GroupchatContact,
|
|
| 134 | + _signal_name: str,
|
|
| 135 | + _user_contact: GroupchatParticipant,
|
|
| 136 | + _properties: PresenceProperties
|
|
| 137 | + ) -> None:
|
|
| 138 | + self._update_group_chat_actions(contact)
|
|
| 139 | + |
|
| 140 | + def _on_muc_disco_update(self, event: MucDiscoUpdate) -> None:
|
|
| 141 | + if self._current_contact is None:
|
|
| 142 | + return
|
|
| 143 | + |
|
| 144 | + if event.jid != self._current_contact.jid:
|
|
| 145 | + return
|
|
| 146 | + |
|
| 147 | + if isinstance(self._current_contact, GroupchatContact):
|
|
| 148 | + self._update_group_chat_actions(self._current_contact)
|
|
| 149 | + |
|
| 120 | 150 | def _connect_actions(self) -> None:
|
| 121 | 151 | actions = [
|
| 122 | 152 | 'add-to-roster',
|
| ... | ... | @@ -129,7 +159,15 @@ def _connect_actions(self) -> None: |
| 129 | 159 | 'start-video-call',
|
| 130 | 160 | 'start-voice-call',
|
| 131 | 161 | 'send-message',
|
| 132 | - 'request-voice',
|
|
| 162 | + 'muc-change-nickname',
|
|
| 163 | + 'muc-invite',
|
|
| 164 | + 'muc-contact-info',
|
|
| 165 | + 'muc-execute-command',
|
|
| 166 | + 'muc-ban',
|
|
| 167 | + 'muc-kick',
|
|
| 168 | + 'muc-change-role',
|
|
| 169 | + 'muc-change-affiliation',
|
|
| 170 | + 'muc-request-voice',
|
|
| 133 | 171 | ]
|
| 134 | 172 | |
| 135 | 173 | stateful_actions = [
|
| ... | ... | @@ -203,9 +241,18 @@ def _update_group_chat_actions(self, contact: GroupchatContact) -> None: |
| 203 | 241 | assert self_contact
|
| 204 | 242 | is_visitor = self_contact.role.is_visitor
|
| 205 | 243 | |
| 206 | - app.window.get_action('request-voice').set_enabled(is_visitor)
|
|
| 244 | + app.window.get_action('muc-change-nickname').set_enabled(
|
|
| 245 | + joined and not contact.is_irc)
|
|
| 246 | + |
|
| 247 | + app.window.get_action('muc-contact-info').set_enabled(joined)
|
|
| 248 | + app.window.get_action('muc-execute-command').set_enabled(joined)
|
|
| 249 | + app.window.get_action('muc-ban').set_enabled(joined)
|
|
| 250 | + app.window.get_action('muc-kick').set_enabled(joined)
|
|
| 251 | + app.window.get_action('muc-change-role').set_enabled(joined)
|
|
| 252 | + app.window.get_action('muc-change-affiliation').set_enabled(joined)
|
|
| 253 | + app.window.get_action('muc-invite').set_enabled(joined)
|
|
| 207 | 254 | |
| 208 | - app.window.get_action('show-contact-info').set_enabled(joined)
|
|
| 255 | + app.window.get_action('muc-request-voice').set_enabled(is_visitor)
|
|
| 209 | 256 | |
| 210 | 257 | app.window.get_action('quote').set_enabled(joined)
|
| 211 | 258 | app.window.get_action('mention').set_enabled(joined)
|
| ... | ... | @@ -224,6 +271,7 @@ def _on_action(self, |
| 224 | 271 | account = contact.account
|
| 225 | 272 | client = app.get_client(account)
|
| 226 | 273 | jid = contact.jid
|
| 274 | + current_control = self._control_stack.get_current_control()
|
|
| 227 | 275 | |
| 228 | 276 | if action_name == 'send-message':
|
| 229 | 277 | self._on_send_message()
|
| ... | ... | @@ -236,9 +284,8 @@ def _on_action(self, |
| 236 | 284 | |
| 237 | 285 | elif action_name.startswith('send-file'):
|
| 238 | 286 | name = action.get_name()
|
| 239 | - control = self._control_stack.get_current_control()
|
|
| 240 | 287 | if 'httpupload' in name:
|
| 241 | - app.interface.send_httpupload(control)
|
|
| 288 | + app.interface.send_httpupload(current_control)
|
|
| 242 | 289 | return
|
| 243 | 290 | |
| 244 | 291 | if 'jingle' in name:
|
| ... | ... | @@ -251,7 +298,7 @@ def _on_action(self, |
| 251 | 298 | return
|
| 252 | 299 | |
| 253 | 300 | if method == 'httpupload':
|
| 254 | - app.interface.send_httpupload(control)
|
|
| 301 | + app.interface.send_httpupload(current_control)
|
|
| 255 | 302 | else:
|
| 256 | 303 | app.interface.instances[
|
| 257 | 304 | 'file_transfers'].show_file_send_request(account, contact)
|
| ... | ... | @@ -266,7 +313,7 @@ def _on_action(self, |
| 266 | 313 | open_window('AddContact', account=account, jid=jid)
|
| 267 | 314 | |
| 268 | 315 | elif action_name == 'clear-chat':
|
| 269 | - self._control_stack.get_current_control().reset_view()
|
|
| 316 | + current_control.reset_view()
|
|
| 270 | 317 | |
| 271 | 318 | elif action_name == 'show-contact-info':
|
| 272 | 319 | if isinstance(contact, GroupchatContact):
|
| ... | ... | @@ -274,7 +321,58 @@ def _on_action(self, |
| 274 | 321 | else:
|
| 275 | 322 | app.window.contact_info(account, str(jid))
|
| 276 | 323 | |
| 277 | - elif action_name == 'request-voice':
|
|
| 324 | + elif action_name == 'muc-contact-info':
|
|
| 325 | + assert param is not None
|
|
| 326 | + nick = param.get_string()
|
|
| 327 | + assert isinstance(contact, GroupchatContact)
|
|
| 328 | + resource_contact = contact.get_resource(nick)
|
|
| 329 | + open_window(
|
|
| 330 | + 'ContactInfo', account=account, contact=resource_contact)
|
|
| 331 | + |
|
| 332 | + elif action_name == 'muc-invite':
|
|
| 333 | + assert isinstance(current_control, GroupchatControl)
|
|
| 334 | + current_control.show_inviter()
|
|
| 335 | + |
|
| 336 | + elif action_name == 'muc-change-nickname':
|
|
| 337 | + assert isinstance(current_control, GroupchatControl)
|
|
| 338 | + current_control.show_change_nick()
|
|
| 339 | + |
|
| 340 | + elif action_name == 'muc-execute-command':
|
|
| 341 | + assert isinstance(current_control, GroupchatControl)
|
|
| 342 | + nick = None
|
|
| 343 | + if param is not None:
|
|
| 344 | + nick = param.get_string()
|
|
| 345 | + if nick:
|
|
| 346 | + assert isinstance(contact, GroupchatContact)
|
|
| 347 | + resource_contact = contact.get_resource(nick)
|
|
| 348 | + jid = resource_contact.jid
|
|
| 349 | + open_window('AdHocCommands', account=account, jid=jid)
|
|
| 350 | + |
|
| 351 | + elif action_name == 'muc-kick':
|
|
| 352 | + assert isinstance(current_control, GroupchatControl)
|
|
| 353 | + assert param is not None
|
|
| 354 | + kick_nick = param.get_string()
|
|
| 355 | + current_control.show_kick(kick_nick)
|
|
| 356 | + |
|
| 357 | + elif action_name == 'muc-ban':
|
|
| 358 | + assert isinstance(current_control, GroupchatControl)
|
|
| 359 | + assert param is not None
|
|
| 360 | + ban_jid = param.get_string()
|
|
| 361 | + current_control.show_ban(ban_jid)
|
|
| 362 | + |
|
| 363 | + elif action_name == 'muc-change-role':
|
|
| 364 | + assert param is not None
|
|
| 365 | + nick, role = param.get_strv()
|
|
| 366 | + client.get_module('MUC').set_role(contact.jid, nick, role)
|
|
| 367 | + |
|
| 368 | + elif action_name == 'muc-change-affiliation':
|
|
| 369 | + assert param is not None
|
|
| 370 | + jid, affiliation = param.get_strv()
|
|
| 371 | + client.get_module('MUC').set_affiliation(
|
|
| 372 | + contact.jid,
|
|
| 373 | + {jid: {'affiliation': affiliation}})
|
|
| 374 | + |
|
| 375 | + elif action_name == 'muc-request-voice':
|
|
| 278 | 376 | client.get_module('MUC').request_voice(contact.jid)
|
| 279 | 377 | |
| 280 | 378 | def _on_stateful_action(self,
|
| ... | ... | @@ -374,6 +472,8 @@ def clear(self) -> None: |
| 374 | 472 | self._control_stack.clear()
|
| 375 | 473 | |
| 376 | 474 | def process_event(self, event: Any) -> None:
|
| 475 | + if isinstance(event, MucDiscoUpdate):
|
|
| 476 | + self._on_muc_disco_update(event)
|
|
| 377 | 477 | self._control_stack.process_event(event)
|
| 378 | 478 | |
| 379 | 479 |
| ... | ... | @@ -206,6 +206,15 @@ def __str__(self): |
| 206 | 206 | ('clear-chat', None, False),
|
| 207 | 207 | ('show-contact-info', None, False),
|
| 208 | 208 | ('send-message', None, False),
|
| 209 | + ('muc-change-nickname', None, False),
|
|
| 210 | + ('muc-invite', None, False),
|
|
| 211 | + ('muc-contact-info', 's', False),
|
|
| 212 | + ('muc-execute-command', 's', False),
|
|
| 213 | + ('muc-ban', 's', False),
|
|
| 214 | + ('muc-kick', 's', False),
|
|
| 215 | + ('muc-change-role', 'as', False),
|
|
| 216 | + ('muc-change-affiliation', 'as', False),
|
|
| 217 | + ('muc-request-voice', None, False),
|
|
| 209 | 218 | ]
|
| 210 | 219 | |
| 211 | 220 |
| ... | ... | @@ -133,8 +133,7 @@ def __init__(self, widget_name: str, account: str, jid: JID) -> None: |
| 133 | 133 | self._units = GLib.FormatSizeFlags.DEFAULT
|
| 134 | 134 | |
| 135 | 135 | self.xml = get_builder(f'{widget_name}.ui')
|
| 136 | - # TODO
|
|
| 137 | - # self.xml.connect_signals(self)
|
|
| 136 | + self.xml.connect_signals(self)
|
|
| 138 | 137 | self.widget: Gtk.Box = self.xml.get_object(f'{widget_name}_hbox')
|
| 139 | 138 | |
| 140 | 139 | # Drag and drop
|
| ... | ... | @@ -128,27 +128,16 @@ def __init__(self, account: str, jid: JID) -> None: |
| 128 | 128 | 'hide_groupchat_occupants_list', self._show_roster)
|
| 129 | 129 | self.roster.connect('row-activated', self._on_roster_row_activated)
|
| 130 | 130 | |
| 131 | - self.add_actions()
|
|
| 132 | - GLib.idle_add(self.update_actions)
|
|
| 133 | - |
|
| 134 | 131 | # Holds CaptchaRequest widget
|
| 135 | 132 | self._captcha_request: Optional[DataFormWidget] = None
|
| 136 | 133 | |
| 137 | 134 | self._subject_text = ''
|
| 138 | 135 | |
| 139 | 136 | # Groupchat invite
|
| 140 | - # self.xml.quick_invite_button.set_action_name(
|
|
| 141 | - # f'win.invite-{self.control_id}')
|
|
| 142 | - |
|
| 143 | 137 | self._invite_box = GroupChatInviter(self.room_jid)
|
| 144 | 138 | self.xml.invite_grid.attach(self._invite_box, 0, 0, 1, 1)
|
| 145 | 139 | self._invite_box.connect('listbox-changed', self._on_invite_ready)
|
| 146 | 140 | |
| 147 | - app.settings.connect_signal('gc_print_join_left_default',
|
|
| 148 | - self.update_actions)
|
|
| 149 | - app.settings.connect_signal('gc_print_status_default',
|
|
| 150 | - self.update_actions)
|
|
| 151 | - |
|
| 152 | 141 | self._set_control_inactive()
|
| 153 | 142 | |
| 154 | 143 | # Stack
|
| ... | ... | @@ -212,60 +201,6 @@ def _on_client_state_changed(self, |
| 212 | 201 | def disco_info(self):
|
| 213 | 202 | return app.storage.cache.get_last_disco_info(self.contact.jid)
|
| 214 | 203 | |
| 215 | - def add_actions(self) -> None:
|
|
| 216 | - actions = [
|
|
| 217 | - ('change-nickname-', None, self._on_change_nick),
|
|
| 218 | - ('destroy-', None, self._on_destroy_room),
|
|
| 219 | - ('invite-', None, self._on_invite),
|
|
| 220 | - ('contact-information-', 's', self._on_contact_information),
|
|
| 221 | - ('execute-command-', 's', self._on_execute_command),
|
|
| 222 | - ('ban-', 's', self._on_ban),
|
|
| 223 | - ('kick-', 's', self._on_kick),
|
|
| 224 | - ('change-role-', 'as', self._on_change_role),
|
|
| 225 | - ('change-affiliation-', 'as', self._on_change_affiliation),
|
|
| 226 | - ]
|
|
| 227 | - |
|
| 228 | - for action in actions:
|
|
| 229 | - action_name, variant, func = action
|
|
| 230 | - if variant is not None:
|
|
| 231 | - variant = GLib.VariantType.new(variant)
|
|
| 232 | - act = Gio.SimpleAction.new(action_name + self.control_id, variant)
|
|
| 233 | - act.connect("activate", func)
|
|
| 234 | - app.window.add_action(act)
|
|
| 235 | - |
|
| 236 | - def update_actions(self, *args: Any) -> None:
|
|
| 237 | - joined = self.contact.is_joined
|
|
| 238 | - |
|
| 239 | - self._get_action('change-nickname-').set_enabled(
|
|
| 240 | - joined and not self.is_irc())
|
|
| 241 | - |
|
| 242 | - self._get_action('execute-command-').set_enabled(joined)
|
|
| 243 | - |
|
| 244 | - self._get_action('contact-information-').set_enabled(joined)
|
|
| 245 | - |
|
| 246 | - self._get_action('ban-').set_enabled(joined)
|
|
| 247 | - |
|
| 248 | - self._get_action('kick-').set_enabled(joined)
|
|
| 249 | - |
|
| 250 | - self._get_action('invite-').set_enabled(joined)
|
|
| 251 | - |
|
| 252 | - def remove_actions(self) -> None:
|
|
| 253 | - actions = [
|
|
| 254 | - 'change-nickname-',
|
|
| 255 | - 'destroy-',
|
|
| 256 | - 'configure-',
|
|
| 257 | - 'invite-',
|
|
| 258 | - 'contact-information-',
|
|
| 259 | - 'execute-command-',
|
|
| 260 | - 'ban-',
|
|
| 261 | - 'kick-',
|
|
| 262 | - 'change-role-',
|
|
| 263 | - 'change-affiliation-',
|
|
| 264 | - ]
|
|
| 265 | - |
|
| 266 | - for action in actions:
|
|
| 267 | - app.window.remove_action(f'{action}{self.control_id}')
|
|
| 268 | - |
|
| 269 | 204 | def is_irc(self) -> bool:
|
| 270 | 205 | if self.disco_info is None:
|
| 271 | 206 | return False
|
| ... | ... | @@ -277,20 +212,15 @@ def _show_page(self, name: str) -> None: |
| 277 | 212 | transition = Gtk.StackTransitionType.SLIDE_UP
|
| 278 | 213 | active_control = app.window.get_active_control()
|
| 279 | 214 | if active_control == self:
|
| 280 | - self.msg_textview.grab_focus()
|
|
| 215 | + pass
|
|
| 216 | + #self.msg_textview.grab_focus()
|
|
| 281 | 217 | self.xml.stack.set_visible_child_full(name, transition)
|
| 282 | 218 | |
| 283 | 219 | def _get_current_page(self) -> str:
|
| 284 | 220 | return self.xml.stack.get_visible_child_name()
|
| 285 | 221 | |
| 286 | - def _on_muc_disco_update(self, _event: events.MucDiscoUpdate) -> None:
|
|
| 287 | - self.update_actions()
|
|
| 288 | - |
|
| 289 | 222 | # Actions
|
| 290 | - def _on_invite(self,
|
|
| 291 | - _action: Gio.SimpleAction,
|
|
| 292 | - _param: Optional[GLib.Variant]
|
|
| 293 | - ) -> None:
|
|
| 223 | + def show_inviter(self) -> None:
|
|
| 294 | 224 | self._invite_box.load_contacts()
|
| 295 | 225 | self._show_page('invite')
|
| 296 | 226 | |
| ... | ... | @@ -314,98 +244,24 @@ def invite(self, invited_jid: JID) -> None: |
| 314 | 244 | self.add_info_message(
|
| 315 | 245 | _('%s has been invited to this group chat') % invited_contact.name)
|
| 316 | 246 | |
| 317 | - def _on_destroy_room(self, _button: Gtk.Button) -> None:
|
|
| 318 | - self.xml.destroy_reason_entry.grab_focus()
|
|
| 319 | - self.xml.destroy_button.grab_default()
|
|
| 320 | - self._show_page('destroy')
|
|
| 321 | - |
|
| 322 | - def _on_destroy_alternate_changed(self,
|
|
| 323 | - entry: Gtk.Entry,
|
|
| 324 | - _param: Any
|
|
| 325 | - ) -> None:
|
|
| 326 | - jid = entry.get_text()
|
|
| 327 | - if jid:
|
|
| 328 | - try:
|
|
| 329 | - jid = helpers.validate_jid(jid)
|
|
| 330 | - except Exception:
|
|
| 331 | - icon = 'dialog-warning-symbolic'
|
|
| 332 | - text = _('Invalid XMPP Address')
|
|
| 333 | - self.xml.destroy_alternate_entry.set_icon_from_icon_name(
|
|
| 334 | - Gtk.EntryIconPosition.SECONDARY, icon)
|
|
| 335 | - self.xml.destroy_alternate_entry.set_icon_tooltip_text(
|
|
| 336 | - Gtk.EntryIconPosition.SECONDARY, text)
|
|
| 337 | - self.xml.destroy_button.set_sensitive(False)
|
|
| 338 | - return
|
|
| 339 | - self.xml.destroy_alternate_entry.set_icon_from_icon_name(
|
|
| 340 | - Gtk.EntryIconPosition.SECONDARY, None)
|
|
| 341 | - self.xml.destroy_button.set_sensitive(True)
|
|
| 342 | - |
|
| 343 | - def _on_destroy_confirm(self, _button: Gtk.Button) -> None:
|
|
| 344 | - reason = self.xml.destroy_reason_entry.get_text()
|
|
| 345 | - jid = self.xml.destroy_alternate_entry.get_text()
|
|
| 346 | - self._client.get_module('MUC').destroy(self.room_jid, reason, jid)
|
|
| 347 | - self._show_page('groupchat')
|
|
| 348 | - |
|
| 349 | - def _on_execute_command(self,
|
|
| 350 | - _action: Gio.SimpleAction,
|
|
| 351 | - param: GLib.Variant
|
|
| 352 | - ) -> None:
|
|
| 353 | - jid = self.room_jid
|
|
| 354 | - nick = param.get_string()
|
|
| 355 | - if nick:
|
|
| 356 | - jid += '/' + nick
|
|
| 357 | - open_window('AdHocCommands', account=self.account, jid=jid)
|
|
| 358 | - |
|
| 359 | - def _on_contact_information(self,
|
|
| 360 | - _action: Gio.SimpleAction,
|
|
| 361 | - param: GLib.Variant
|
|
| 362 | - ) -> None:
|
|
| 363 | - nick = param.get_string()
|
|
| 364 | - contact = self.contact.get_resource(nick)
|
|
| 365 | - open_window('ContactInfo', account=self.account, contact=contact)
|
|
| 366 | - |
|
| 367 | - def _on_kick(self,
|
|
| 368 | - _action: Gio.SimpleAction,
|
|
| 369 | - param: GLib.Variant
|
|
| 370 | - ) -> None:
|
|
| 371 | - nick = param.get_string()
|
|
| 372 | - self._kick_nick = nick
|
|
| 373 | - text = _('Kick %s') % nick
|
|
| 247 | + def show_kick(self, kick_nick: str) -> None:
|
|
| 248 | + self._kick_nick = kick_nick
|
|
| 249 | + text = _('Kick %s') % kick_nick
|
|
| 374 | 250 | self.xml.kick_label.set_text(text)
|
| 375 | 251 | self.xml.kick_label.set_tooltip_text(text)
|
| 376 | 252 | self.xml.kick_reason_entry.grab_focus()
|
| 377 | 253 | self.xml.kick_participant_button.grab_default()
|
| 378 | 254 | self._show_page('kick')
|
| 379 | 255 | |
| 380 | - def _on_ban(self,
|
|
| 381 | - _action: Gio.SimpleAction,
|
|
| 382 | - param: GLib.Variant
|
|
| 383 | - ) -> None:
|
|
| 384 | - jid = param.get_string()
|
|
| 385 | - self._ban_jid = jid
|
|
| 386 | - text = _('Ban %s') % jid
|
|
| 256 | + def show_ban(self, ban_jid: str) -> None:
|
|
| 257 | + self._ban_jid = ban_jid
|
|
| 258 | + text = _('Ban %s') % ban_jid
|
|
| 387 | 259 | self.xml.ban_label.set_text(text)
|
| 388 | 260 | self.xml.ban_label.set_tooltip_text(text)
|
| 389 | 261 | self.xml.ban_reason_entry.grab_focus()
|
| 390 | 262 | self.xml.ban_participant_button.grab_default()
|
| 391 | 263 | self._show_page('ban')
|
| 392 | 264 | |
| 393 | - def _on_change_role(self,
|
|
| 394 | - _action: Gio.SimpleAction,
|
|
| 395 | - param: GLib.Variant
|
|
| 396 | - ) -> None:
|
|
| 397 | - nick, role = param.get_strv()
|
|
| 398 | - self._client.get_module('MUC').set_role(self.room_jid, nick, role)
|
|
| 399 | - |
|
| 400 | - def _on_change_affiliation(self,
|
|
| 401 | - _action: Gio.SimpleAction,
|
|
| 402 | - param: GLib.Variant
|
|
| 403 | - ) -> None:
|
|
| 404 | - jid, affiliation = param.get_strv()
|
|
| 405 | - self._client.get_module('MUC').set_affiliation(
|
|
| 406 | - self.room_jid,
|
|
| 407 | - {jid: {'affiliation': affiliation}})
|
|
| 408 | - |
|
| 409 | 265 | def _show_roster(self, show_roster: bool, *args: Any) -> None:
|
| 410 | 266 | transition = Gtk.RevealerTransitionType.SLIDE_RIGHT
|
| 411 | 267 | if show_roster:
|
| ... | ... | @@ -613,16 +469,12 @@ def _set_control_active(self) -> None: |
| 613 | 469 | self.roster.initial_draw()
|
| 614 | 470 | self.conversation_view.update_avatars()
|
| 615 | 471 | |
| 616 | - self.update_actions()
|
|
| 617 | - |
|
| 618 | 472 | def _set_control_inactive(self) -> None:
|
| 619 | 473 | self.roster.enable_sort(False)
|
| 620 | 474 | self.roster.clear()
|
| 621 | 475 | |
| 622 | 476 | self._client.get_module('Chatstate').remove_delay_timeout(self.contact)
|
| 623 | 477 | |
| 624 | - self.update_actions()
|
|
| 625 | - |
|
| 626 | 478 | def rejoin(self) -> None:
|
| 627 | 479 | self._client.get_module('MUC').join(self.room_jid)
|
| 628 | 480 | |
| ... | ... | @@ -657,9 +509,6 @@ def _on_user_joined(self, |
| 657 | 509 | _('The server has assigned or modified your nickname in this '
|
| 658 | 510 | 'group chat'))
|
| 659 | 511 | |
| 660 | - # Update Actions
|
|
| 661 | - self.update_actions()
|
|
| 662 | - |
|
| 663 | 512 | def _on_room_config_finished(self,
|
| 664 | 513 | _contact: GroupchatContact,
|
| 665 | 514 | _signal_name: str
|
| ... | ... | @@ -735,7 +584,6 @@ def _on_user_affiliation_changed(self, |
| 735 | 584 | reason=reason)
|
| 736 | 585 | |
| 737 | 586 | self.add_info_message(message)
|
| 738 | - self.update_actions()
|
|
| 739 | 587 | |
| 740 | 588 | def _on_user_role_changed(self,
|
| 741 | 589 | _contact: GroupchatContact,
|
| ... | ... | @@ -765,7 +613,6 @@ def _on_user_role_changed(self, |
| 765 | 613 | reason=reason)
|
| 766 | 614 | |
| 767 | 615 | self.add_info_message(message)
|
| 768 | - self.update_actions()
|
|
| 769 | 616 | |
| 770 | 617 | def _on_room_kicked(self,
|
| 771 | 618 | _contact: GroupchatContact,
|
| ... | ... | @@ -968,8 +815,6 @@ def shutdown(self, reason: Optional[str] = None) -> None: |
| 968 | 815 | self.roster.destroy()
|
| 969 | 816 | self.roster = None
|
| 970 | 817 | |
| 971 | - self.remove_actions()
|
|
| 972 | - |
|
| 973 | 818 | super(GroupchatControl, self).shutdown()
|
| 974 | 819 | app.check_finalize(self)
|
| 975 | 820 | |
| ... | ... | @@ -1006,6 +851,7 @@ def delegate_action(self, action: str) -> int: |
| 1006 | 851 | return res
|
| 1007 | 852 | |
| 1008 | 853 | if action == 'change-nickname':
|
| 854 | + # TODO
|
|
| 1009 | 855 | control_action = f'{action}-{self.control_id}'
|
| 1010 | 856 | app.window.lookup_action(control_action).activate()
|
| 1011 | 857 | return Gdk.EVENT_STOP
|
| ... | ... | @@ -1046,8 +892,6 @@ def focus(self) -> None: |
| 1046 | 892 | self._captcha_request.focus_first_entry()
|
| 1047 | 893 | elif page_name == 'invite':
|
| 1048 | 894 | self._invite_box.focus_search_entry()
|
| 1049 | - elif page_name == 'destroy':
|
|
| 1050 | - self.xml.destroy_reason_entry.grab_focus_without_selecting()
|
|
| 1051 | 895 | |
| 1052 | 896 | def _on_kick_participant_clicked(self, _button: Gtk.Button) -> None:
|
| 1053 | 897 | reason = self.xml.kick_reason_entry.get_text()
|
| ... | ... | @@ -1077,10 +921,7 @@ def _on_page_change(self, stack: Gtk.Stack, _param: Any) -> None: |
| 1077 | 921 | elif page_name == 'error':
|
| 1078 | 922 | self.xml.close_button.grab_default()
|
| 1079 | 923 | |
| 1080 | - def _on_change_nick(self,
|
|
| 1081 | - _action: Gio.SimpleAction,
|
|
| 1082 | - _param: Optional[GLib.Variant]
|
|
| 1083 | - ) -> None:
|
|
| 924 | + def show_change_nick(self) -> None:
|
|
| 1084 | 925 | if self._get_current_page() != 'groupchat':
|
| 1085 | 926 | return
|
| 1086 | 927 | self.xml.nickname_entry.set_text(self.contact.nickname)
|
| ... | ... | @@ -117,9 +117,9 @@ def get_send_file_submenu() -> GajimMenu: |
| 117 | 117 | def get_groupchat_menu(contact: GroupchatContact) -> GajimMenu:
|
| 118 | 118 | menuitems: MenuItemListT = [
|
| 119 | 119 | (_('Details'), 'win.show-contact-info', None),
|
| 120 | - (_('Change Nickname…'), 'win.change-nickname', None),
|
|
| 121 | - (_('Request Voice'), 'win.request-voice', None),
|
|
| 122 | - (_('Execute Command…'), 'win.execute-command', '""'),
|
|
| 120 | + (_('Change Nickname…'), 'win.muc-change-nickname', None),
|
|
| 121 | + (_('Request Voice'), 'win.muc-request-voice', None),
|
|
| 122 | + (_('Execute Command…'), 'win.muc-execute-command', '""'),
|
|
| 123 | 123 | (_('Search…'), 'win.search-history', None)
|
| 124 | 124 | ]
|
| 125 | 125 | |
| ... | ... | @@ -452,13 +452,12 @@ def get_workspace_params(current_workspace_id: str, |
| 452 | 452 | yield name, params
|
| 453 | 453 | |
| 454 | 454 | |
| 455 | -def get_groupchat_admin_menu(control_id: str,
|
|
| 456 | - self_contact: types.GroupchatParticipant,
|
|
| 455 | +def get_groupchat_admin_menu(self_contact: types.GroupchatParticipant,
|
|
| 457 | 456 | contact: types.GroupchatParticipant) -> GajimMenu:
|
| 458 | 457 | |
| 459 | 458 | menu = GajimMenu()
|
| 460 | 459 | |
| 461 | - action = f'win.change-affiliation-{control_id}'
|
|
| 460 | + action = 'win.muc-change-affiliation'
|
|
| 462 | 461 | |
| 463 | 462 | if is_affiliation_change_allowed(self_contact, contact, 'owner'):
|
| 464 | 463 | value = f'["{contact.real_jid}", "owner"]'
|
| ... | ... | @@ -478,7 +477,7 @@ def get_groupchat_admin_menu(control_id: str, |
| 478 | 477 | |
| 479 | 478 | if is_affiliation_change_allowed(self_contact, contact, 'outcast'):
|
| 480 | 479 | value = f'"{contact.real_jid}"'
|
| 481 | - menu.add_item(_('Ban…'), f'win.ban-{control_id}', value)
|
|
| 480 | + menu.add_item(_('Ban…'), 'win.muc-ban', value)
|
|
| 482 | 481 | |
| 483 | 482 | if not menu.get_n_items():
|
| 484 | 483 | menu.add_item(_('Not Available'), 'dummy', None)
|
| ... | ... | @@ -486,8 +485,7 @@ def get_groupchat_admin_menu(control_id: str, |
| 486 | 485 | return menu
|
| 487 | 486 | |
| 488 | 487 | |
| 489 | -def get_groupchat_mod_menu(control_id: str,
|
|
| 490 | - self_contact: types.GroupchatParticipant,
|
|
| 488 | +def get_groupchat_mod_menu(self_contact: types.GroupchatParticipant,
|
|
| 491 | 489 | contact: types.GroupchatParticipant
|
| 492 | 490 | ) -> GajimMenu:
|
| 493 | 491 | |
| ... | ... | @@ -495,9 +493,9 @@ def get_groupchat_mod_menu(control_id: str, |
| 495 | 493 | |
| 496 | 494 | if is_role_change_allowed(self_contact, contact):
|
| 497 | 495 | value = f'"{contact.name}"'
|
| 498 | - menu.add_item(_('Kick…'), f'win.kick-{control_id}', value)
|
|
| 496 | + menu.add_item(_('Kick…'), 'win.muc-kick', value)
|
|
| 499 | 497 | |
| 500 | - action = f'win.change-role-{control_id}'
|
|
| 498 | + action = 'win.muc-change-role'
|
|
| 501 | 499 | |
| 502 | 500 | if is_role_change_allowed(self_contact, contact):
|
| 503 | 501 | if contact.role.is_visitor:
|
| ... | ... | @@ -514,7 +512,6 @@ def get_groupchat_mod_menu(control_id: str, |
| 514 | 512 | |
| 515 | 513 | |
| 516 | 514 | def get_groupchat_roster_menu(account: str,
|
| 517 | - control_id: str,
|
|
| 518 | 515 | self_contact: types.GroupchatParticipant,
|
| 519 | 516 | contact: types.GroupchatParticipant
|
| 520 | 517 | ) -> GajimMenu:
|
| ... | ... | @@ -522,8 +519,8 @@ def get_groupchat_roster_menu(account: str, |
| 522 | 519 | value = f'"{contact.name}"'
|
| 523 | 520 | |
| 524 | 521 | general_items: MenuItemListT = [
|
| 525 | - (_('Details'), f'win.contact-information-{control_id}', value),
|
|
| 526 | - (_('Execute Command…'), f'win.execute-command-{control_id}', value),
|
|
| 522 | + (_('Details'), 'win.muc-contact-info', value),
|
|
| 523 | + (_('Execute Command…'), 'win.muc-execute-command', value),
|
|
| 527 | 524 | ]
|
| 528 | 525 | |
| 529 | 526 | real_contact = contact.get_real_contact()
|
| ... | ... | @@ -532,8 +529,8 @@ def get_groupchat_roster_menu(account: str, |
| 532 | 529 | action = f'app.{account}-add-contact'
|
| 533 | 530 | general_items.insert(1, (_('Add to Contact List…'), action, value))
|
| 534 | 531 | |
| 535 | - mod_menu = get_groupchat_mod_menu(control_id, self_contact, contact)
|
|
| 536 | - admin_menu = get_groupchat_admin_menu(control_id, self_contact, contact)
|
|
| 532 | + mod_menu = get_groupchat_mod_menu(self_contact, contact)
|
|
| 533 | + admin_menu = get_groupchat_admin_menu(self_contact, contact)
|
|
| 537 | 534 | |
| 538 | 535 | menu = GajimMenu.from_list(general_items)
|
| 539 | 536 | menu.append_section(_('Moderation'), mod_menu)
|
| ... | ... | @@ -101,6 +101,8 @@ def __init__(self) -> None: |
| 101 | 101 | self._ui.formattings_button.set_menu_model(get_format_menu())
|
| 102 | 102 | self._ui.encryption_menu_button.set_menu_model(get_encryption_menu())
|
| 103 | 103 | |
| 104 | + self._ui.quick_invite_button.set_action_name('win.muc-invite')
|
|
| 105 | + |
|
| 104 | 106 | self._init_emoticon_popover()
|
| 105 | 107 | # TODO init spellchecker uses a contact on callback, contact might
|
| 106 | 108 | # be None
|