Daniel Brötzmann pushed to branch newcontrol at gajim / gajim

Commits:

9 changed files:

Changes:

  • gajim/common/modules/contacts.py
    ... ... @@ -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)
    

  • gajim/data/gui/groupchat_control.ui
    ... ... @@ -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">
    

  • gajim/gtk/chat_banner.py
    ... ... @@ -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')
    

  • gajim/gtk/chat_stack.py
    ... ... @@ -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
     
    

  • gajim/gtk/const.py
    ... ... @@ -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
     
    

  • gajim/gtk/controls/base.py
    ... ... @@ -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
    

  • gajim/gtk/controls/groupchat.py
    ... ... @@ -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)
    

  • gajim/gtk/menus.py
    ... ... @@ -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)
    

  • gajim/gtk/message_actions_box.py
    ... ... @@ -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