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

Commits:

5 changed files:

Changes:

  • gajim/gtk/chat_action_processor.py
    ... ... @@ -38,11 +38,7 @@
    38 38
     
    
    39 39
     
    
    40 40
     class ChatActionProcessor(Gtk.Popover):
    
    41
    -    def __init__(self,
    
    42
    -                 account: str,
    
    43
    -                 contact: types.ChatContactT,
    
    44
    -                 message_input: MessageInputTextView
    
    45
    -                 ) -> None:
    
    41
    +    def __init__(self, message_input: MessageInputTextView) -> None:
    
    46 42
             Gtk.Popover.__init__(self)
    
    47 43
             self._menu = Gio.Menu()
    
    48 44
             self.bind_model(self._menu)
    
    ... ... @@ -53,23 +49,28 @@ def __init__(self,
    53 49
             self.connect('closed', self._on_popover_closed)
    
    54 50
             self.connect('destroy', self._on_destroy)
    
    55 51
     
    
    52
    +        self._account: Optional[str] = None
    
    53
    +        self._contact: Optional[types.ChatContactT] = None
    
    54
    +
    
    56 55
             self._message_input = message_input
    
    57 56
             self._message_input.connect('key-press-event', self._on_key_press)
    
    58 57
     
    
    59 58
             self._buf = message_input.get_buffer()
    
    60 59
             self._buf.connect('changed', self._on_changed)
    
    61 60
     
    
    62
    -        self._nick_completion: Optional[GroupChatNickCompletion] = None
    
    63
    -        if contact.is_groupchat:
    
    64
    -            assert isinstance(contact, GroupchatContact)
    
    65
    -            self._nick_completion = GroupChatNickCompletion(
    
    66
    -                account, contact, message_input)
    
    61
    +        self._nick_completion = GroupChatNickCompletion()
    
    67 62
     
    
    68 63
             self._start_mark: Optional[Gtk.TextMark] = None
    
    69 64
             self._current_iter: Optional[Gtk.TextIter] = None
    
    70 65
     
    
    71 66
             self._active = False
    
    72 67
     
    
    68
    +    def switch_contact(self, contact: types.ChatContactT) -> None:
    
    69
    +        self._account = contact.account
    
    70
    +        self._contact = contact
    
    71
    +        if isinstance(contact, GroupchatContact):
    
    72
    +            self._nick_completion.switch_contact(contact)
    
    73
    +
    
    73 74
         def _on_destroy(self, _popover: Gtk.Popover) -> None:
    
    74 75
             app.check_finalize(self)
    
    75 76
     
    
    ... ... @@ -77,7 +78,7 @@ def _on_key_press(self,
    77 78
                           textview: MessageInputTextView,
    
    78 79
                           event: Gdk.EventKey
    
    79 80
                           ) -> bool:
    
    80
    -        if self._nick_completion is not None:
    
    81
    +        if isinstance(self._contact, GroupchatContact):
    
    81 82
                 res = self._nick_completion.process_key_press(textview, event)
    
    82 83
                 if res:
    
    83 84
                     return True
    
    ... ... @@ -122,8 +123,9 @@ def _replace_text(self, selected_action: str) -> None:
    122 123
     
    
    123 124
         def _get_commands(self) -> list[str]:
    
    124 125
             commands: list[str] = []
    
    125
    -        control = app.window.get_control(
    
    126
    -            self._message_input.account, self._message_input.contact.jid)
    
    126
    +        assert self._account
    
    127
    +        assert self._contact
    
    128
    +        control = app.window.get_control(self._account, self._contact.jid)
    
    127 129
             assert control is not None
    
    128 130
             for command in control.list_commands():
    
    129 131
                 for name in command.names:
    
    ... ... @@ -325,6 +327,9 @@ def _item_has_focus(item: Gtk.ModelButton) -> bool:
    325 327
             flags = item.get_state_flags()
    
    326 328
             return 'GTK_STATE_FLAG_FOCUSED' in str(flags)
    
    327 329
     
    
    328
    -    def process_outgoing_message(self, contact: str, highlight: bool) -> None:
    
    329
    -        if self._nick_completion is not None:
    
    330
    -            self._nick_completion.record_message(contact, highlight)
    330
    +    def process_outgoing_message(self,
    
    331
    +                                 contact_name: str,
    
    332
    +                                 highlight: bool
    
    333
    +                                 ) -> None:
    
    334
    +        if isinstance(self._contact, GroupchatContact):
    
    335
    +            self._nick_completion.process_message(contact_name, highlight)

  • gajim/gtk/groupchat_nick_completion.py
    ... ... @@ -14,6 +14,7 @@
    14 14
     
    
    15 15
     from __future__ import annotations
    
    16 16
     
    
    17
    +from typing import Optional
    
    17 18
     from typing import TYPE_CHECKING
    
    18 19
     
    
    19 20
     import logging
    
    ... ... @@ -33,22 +34,38 @@
    33 34
     
    
    34 35
     
    
    35 36
     class GroupChatNickCompletion:
    
    36
    -    def __init__(self,
    
    37
    -                 account: str,
    
    38
    -                 contact: types.GroupchatContactT,
    
    39
    -                 message_input: MessageInputTextView
    
    40
    -                 ) -> None:
    
    41
    -        self._account = account
    
    42
    -
    
    43
    -        self._contact = contact
    
    44
    -        self._contact.connect(
    
    45
    -            'user-nickname-changed', self._on_user_nickname_changed)
    
    37
    +    def __init__(self) -> None:
    
    38
    +        self._account: Optional[str] = None
    
    39
    +        self._contact: Optional[types.GroupchatContactT] = None
    
    46 40
     
    
    47 41
             self._sender_list: list[str] = []
    
    48
    -        self._attention_list: list[str] = []
    
    42
    +        self._highlight_list: list[str] = []
    
    49 43
             self._nick_hits: list[str] = []
    
    50 44
             self._last_key_tab = False
    
    51 45
     
    
    46
    +        self._nick_data: dict[str, tuple[list[str], list[str]]] = {}
    
    47
    +
    
    48
    +    def switch_contact(self, contact: types.GroupchatContactT) -> None:
    
    49
    +        self._nick_hits.clear()
    
    50
    +        self._last_key_tab = False
    
    51
    +
    
    52
    +        if self._contact is not None:
    
    53
    +            self._contact.disconnect_all_from_obj(self)
    
    54
    +            self._nick_data[str(self._contact.jid)] = (
    
    55
    +                self._sender_list, self._highlight_list)
    
    56
    +
    
    57
    +        nick_data = self._nick_data.get(str(contact.jid))
    
    58
    +        if nick_data is None:
    
    59
    +            self._sender_list.clear()
    
    60
    +            self._highlight_list.clear()
    
    61
    +        else:
    
    62
    +            self._sender_list, self._highlight_list = nick_data
    
    63
    +
    
    64
    +        self._account = contact.account
    
    65
    +        self._contact = contact
    
    66
    +        self._contact.connect(
    
    67
    +            'user-nickname-changed', self._on_user_nickname_changed)
    
    68
    +
    
    52 69
         def _on_user_nickname_changed(self,
    
    53 70
                                       _contact: types.GroupchatContact,
    
    54 71
                                       _signal_name: str,
    
    ... ... @@ -63,12 +80,13 @@ def _on_user_nickname_changed(self,
    63 80
             new_name = properties.muc_user.nick
    
    64 81
             assert new_name is not None
    
    65 82
             log.debug('Contact %s renamed to %s', old_name, new_name)
    
    66
    -        for lst in (self._attention_list, self._sender_list):
    
    83
    +        for lst in (self._highlight_list, self._sender_list):
    
    67 84
                 for idx, contact in enumerate(lst):
    
    68 85
                     if contact == old_name:
    
    69 86
                         lst[idx] = new_name
    
    70 87
     
    
    71
    -    def record_message(self, contact_name: str, highlight: bool) -> None:
    
    88
    +    def process_message(self, contact_name: str, highlight: bool) -> None:
    
    89
    +        assert self._contact
    
    72 90
             if contact_name == self._contact.nickname:
    
    73 91
                 return
    
    74 92
     
    
    ... ... @@ -78,12 +96,12 @@ def record_message(self, contact_name: str, highlight: bool) -> None:
    78 96
     
    
    79 97
             if highlight:
    
    80 98
                 try:
    
    81
    -                self._attention_list.remove(contact_name)
    
    99
    +                self._highlight_list.remove(contact_name)
    
    82 100
                 except ValueError:
    
    83 101
                     pass
    
    84
    -            if len(self._attention_list) > 6:
    
    85
    -                self._attention_list.pop(0)  # remove older
    
    86
    -            self._attention_list.append(contact_name)
    
    102
    +            if len(self._highlight_list) > 6:
    
    103
    +                self._highlight_list.pop(0)  # remove older
    
    104
    +            self._highlight_list.append(contact_name)
    
    87 105
     
    
    88 106
             # TODO implement it in a more efficient way
    
    89 107
             # Currently it's O(n*m + n*s), where n is the number of participants and
    
    ... ... @@ -111,12 +129,13 @@ def _generate_suggestions(self,
    111 129
             `beginning` is the text already typed by the user
    
    112 130
             """
    
    113 131
             def _nick_matching(nick: str) -> bool:
    
    132
    +            assert self._contact
    
    114 133
                 return (nick != self._contact.nickname and
    
    115 134
                         nick.lower().startswith(beginning.lower()))
    
    116 135
     
    
    117 136
             if beginning == '':
    
    118 137
                 # empty message, so just suggest recent mentions
    
    119
    -            potential_matches = self._attention_list
    
    138
    +            potential_matches = self._highlight_list
    
    120 139
             else:
    
    121 140
                 # nick partially typed, try completing it
    
    122 141
                 potential_matches = self._sender_list
    
    ... ... @@ -179,6 +198,7 @@ def process_key_press(self,
    179 198
                 self._nick_hits.append(self._nick_hits[0])
    
    180 199
                 begin = self._nick_hits.pop(0)
    
    181 200
             else:
    
    201
    +            assert self._contact
    
    182 202
                 list_nick = self._contact.get_user_nicknames()
    
    183 203
                 list_nick = list(filter(self._jid_not_blocked, list_nick))
    
    184 204
     
    
    ... ... @@ -215,6 +235,7 @@ def process_key_press(self,
    215 235
                 else:
    
    216 236
                     start_iter.backward_chars(len(begin))
    
    217 237
     
    
    238
    +            assert self._account
    
    218 239
                 client = app.get_client(self._account)
    
    219 240
                 client.get_module('Chatstate').block_chatstates(
    
    220 241
                     self._contact, True)
    
    ... ... @@ -255,6 +276,8 @@ def process_key_press(self,
    255 276
             return True
    
    256 277
     
    
    257 278
         def _jid_not_blocked(self, resource: str) -> bool:
    
    279
    +        assert self._account
    
    280
    +        assert self._contact
    
    258 281
             resource_contact = self._contact.get_resource(resource)
    
    259 282
             return not jid_is_blocked(
    
    260 283
                 self._account, str(resource_contact.jid))

  • gajim/gtk/message_actions_box.py
    ... ... @@ -173,6 +173,7 @@ def switch_contact(self, contact: ChatContactT) -> None:
    173 173
             self._set_spell_checker_language(contact)
    
    174 174
             self._set_chatstate()
    
    175 175
     
    
    176
    +        self.msg_textview.switch_contact(contact)
    
    176 177
             self._security_label_selector.switch_contact(contact)
    
    177 178
     
    
    178 179
         def _set_chatstate(self) -> None:
    

  • gajim/gtk/message_input.py
    ... ... @@ -57,9 +57,6 @@ class MessageInputTextView(Gtk.TextView):
    57 57
         """
    
    58 58
         def __init__(self) -> None:
    
    59 59
             Gtk.TextView.__init__(self)
    
    60
    -   #     self.account = account
    
    61
    -    #    self.contact = contact
    
    62
    -
    
    63 60
             self.set_border_width(3)
    
    64 61
             self.set_accepts_tab(True)
    
    65 62
             self.set_editable(True)
    
    ... ... @@ -76,8 +73,7 @@ def __init__(self) -> None:
    76 73
             self._undo_list: list[str] = []
    
    77 74
             self.undo_pressed: bool = False
    
    78 75
     
    
    79
    - #       self._chat_action_processor = ChatActionProcessor(
    
    80
    - #           account, contact, self)
    
    76
    +        self._chat_action_processor = ChatActionProcessor(self)
    
    81 77
     
    
    82 78
             self.get_buffer().create_tag('strong', weight=Pango.Weight.BOLD)
    
    83 79
             self.get_buffer().create_tag('emphasis', style=Pango.Style.ITALIC)
    
    ... ... @@ -91,6 +87,9 @@ def __init__(self) -> None:
    91 87
             self.connect('destroy', self._on_destroy)
    
    92 88
             self.connect('populate-popup', self._on_populate_popup)
    
    93 89
     
    
    90
    +    def switch_contact(self, contact: ChatContactT) -> None:
    
    91
    +        self._chat_action_processor.switch_contact(contact)
    
    92
    +
    
    94 93
         def _on_destroy(self, _widget: Gtk.Widget) -> None:
    
    95 94
             # We restore the TextView’s drag destination to avoid a GTK warning
    
    96 95
             # when closing the control. BaseControl.shutdown() calls destroy()
    
    ... ... @@ -323,9 +322,8 @@ def process_outgoing_message(self,
    323 322
                                      contact_name: str,
    
    324 323
                                      highlight: bool
    
    325 324
                                      ) -> None:
    
    326
    -        # self._chat_action_processor.process_outgoing_message(
    
    327
    -        #     contact_name, highlight)
    
    328
    -        pass
    
    325
    +        self._chat_action_processor.process_outgoing_message(
    
    326
    +            contact_name, highlight)
    
    329 327
     
    
    330 328
         def _on_populate_popup(self,
    
    331 329
                                _textview: MessageInputTextView,
    

  • test/no_gui/test_nick_completion.py
    ... ... @@ -10,13 +10,12 @@
    10 10
     class Test(unittest.TestCase):
    
    11 11
     
    
    12 12
         def test_generate_suggestions(self):
    
    13
    -        contact = MagicMock()
    
    14 13
             message_input = MagicMock()
    
    15
    -        gen = GroupChatNickCompletion('testacc', contact, message_input)
    
    14
    +        gen = GroupChatNickCompletion(message_input)
    
    16 15
     
    
    17 16
             l = ['aaaa', 'fooo', 'xxxxz', 'xaaaz']
    
    18 17
             for n in l:
    
    19
    -            gen.record_message(n, False)
    
    18
    +            gen.process_message(n, False)
    
    20 19
             l2 = ['xxx'] + l
    
    21 20
             r = gen._generate_suggestions(nicks=l2, beginning='x')
    
    22 21
             self.assertEqual(r, ['xaaaz', 'xxxxz', 'xxx'])
    
    ... ... @@ -28,7 +27,7 @@ def test_generate_suggestions(self):
    28 27
             self.assertEqual(r, [])
    
    29 28
     
    
    30 29
             for n in ['xaaaz', 'xxxxz']:
    
    31
    -            gen.record_message(n, True)
    
    30
    +            gen.process_message(n, True)
    
    32 31
     
    
    33 32
             r = gen._generate_suggestions(
    
    34 33
                 nicks=l2,