comparison sat_frontends/primitivus/contact_list.py @ 4037:524856bd7b19

massive refactoring to switch from camelCase to snake_case: historically, Libervia (SàT before) was using camelCase as allowed by PEP8 when using a pre-PEP8 code, to use the same coding style as in Twisted. However, snake_case is more readable and it's better to follow PEP8 best practices, so it has been decided to move on full snake_case. Because Libervia has a huge codebase, this ended with a ugly mix of camelCase and snake_case. To fix that, this patch does a big refactoring by renaming every function and method (including bridge) that are not coming from Twisted or Wokkel, to use fully snake_case. This is a massive change, and may result in some bugs.
author Goffi <goffi@goffi.org>
date Sat, 08 Apr 2023 13:54:42 +0200
parents be6d91572633
children 4b842c1fb686
comparison
equal deleted inserted replaced
4036:c4464d7ae97b 4037:524856bd7b19
44 QuickContactList.__init__(self, host, profiles) 44 QuickContactList.__init__(self, host, profiles)
45 self.contact_list = self.host.contact_lists[self.profile] 45 self.contact_list = self.host.contact_lists[self.profile]
46 46
47 # we now build the widget 47 # we now build the widget
48 self.status_bar = StatusBar(host) 48 self.status_bar = StatusBar(host)
49 self.frame = sat_widgets.FocusFrame(self._buildList(), None, self.status_bar) 49 self.frame = sat_widgets.FocusFrame(self._build_list(), None, self.status_bar)
50 PrimitivusWidget.__init__(self, self.frame, _("Contacts")) 50 PrimitivusWidget.__init__(self, self.frame, _("Contacts"))
51 if on_click: 51 if on_click:
52 urwid.connect_signal(self, "click", on_click, user_data) 52 urwid.connect_signal(self, "click", on_click, user_data)
53 if on_change: 53 if on_change:
54 urwid.connect_signal(self, "change", on_change, user_data) 54 urwid.connect_signal(self, "change", on_change, user_data)
55 self.host.addListener("notification", self.onNotification, [self.profile]) 55 self.host.addListener("notification", self.on_notification, [self.profile])
56 self.host.addListener("notificationsClear", self.onNotification, [self.profile]) 56 self.host.addListener("notificationsClear", self.on_notification, [self.profile])
57 self.postInit() 57 self.post_init()
58 58
59 def update(self, entities=None, type_=None, profile=None): 59 def update(self, entities=None, type_=None, profile=None):
60 """Update display, keep focus""" 60 """Update display, keep focus"""
61 # FIXME: full update is done each time, must handle entities, type_ and profile 61 # FIXME: full update is done each time, must handle entities, type_ and profile
62 widget, position = self.frame.body.get_focus() 62 widget, position = self.frame.body.get_focus()
63 self.frame.body = self._buildList() 63 self.frame.body = self._build_list()
64 if position: 64 if position:
65 try: 65 try:
66 self.frame.body.focus_position = position 66 self.frame.body.focus_position = position
67 except IndexError: 67 except IndexError:
68 pass 68 pass
83 self.contact_list.show_status = not self.contact_list.show_status 83 self.contact_list.show_status = not self.contact_list.show_status
84 self.update() 84 self.update()
85 elif ( 85 elif (
86 key == a_key["DISCONNECTED_HIDE"] 86 key == a_key["DISCONNECTED_HIDE"]
87 ): # user wants to (un)hide disconnected contacts 87 ): # user wants to (un)hide disconnected contacts
88 self.host.bridge.setParam( 88 self.host.bridge.param_set(
89 C.SHOW_OFFLINE_CONTACTS, 89 C.SHOW_OFFLINE_CONTACTS,
90 C.boolConst(not self.contact_list.show_disconnected), 90 C.bool_const(not self.contact_list.show_disconnected),
91 "General", 91 "General",
92 profile_key=self.profile, 92 profile_key=self.profile,
93 ) 93 )
94 elif key == a_key["RESOURCES_HIDE"]: # user wants to (un)hide contacts resources 94 elif key == a_key["RESOURCES_HIDE"]: # user wants to (un)hide contacts resources
95 self.contact_list.showResources(not self.contact_list.show_resources) 95 self.contact_list.show_resources(not self.contact_list.show_resources)
96 self.update() 96 self.update()
97 return super(ContactList, self).keypress(size, key) 97 return super(ContactList, self).keypress(size, key)
98 98
99 # QuickWidget methods 99 # QuickWidget methods
100 100
101 @staticmethod 101 @staticmethod
102 def getWidgetHash(target, profiles): 102 def get_widget_hash(target, profiles):
103 profiles = sorted(profiles) 103 profiles = sorted(profiles)
104 return tuple(profiles) 104 return tuple(profiles)
105 105
106 # modify the contact list 106 # modify the contact list
107 107
108 def setFocus(self, text, select=False): 108 def set_focus(self, text, select=False):
109 """give focus to the first element that matches the given text. You can also 109 """give focus to the first element that matches the given text. You can also
110 pass in text a sat_frontends.tools.jid.JID (it's a subclass of unicode). 110 pass in text a sat_frontends.tools.jid.JID (it's a subclass of unicode).
111 111
112 @param text: contact group name, contact or muc userhost, muc private dialog jid 112 @param text: contact group name, contact or muc userhost, muc private dialog jid
113 @param select: if True, the element is also clicked 113 @param select: if True, the element is also clicked
115 idx = 0 115 idx = 0
116 for widget in self.frame.body.body: 116 for widget in self.frame.body.body:
117 try: 117 try:
118 if isinstance(widget, sat_widgets.ClickableText): 118 if isinstance(widget, sat_widgets.ClickableText):
119 # contact group 119 # contact group
120 value = widget.getValue() 120 value = widget.get_value()
121 elif isinstance(widget, sat_widgets.SelectableText): 121 elif isinstance(widget, sat_widgets.SelectableText):
122 # contact or muc 122 # contact or muc
123 value = widget.data 123 value = widget.data
124 else: 124 else:
125 # Divider instance 125 # Divider instance
126 continue 126 continue
127 # there's sometimes a leading space 127 # there's sometimes a leading space
128 if text.strip() == value.strip(): 128 if text.strip() == value.strip():
129 self.frame.body.focus_position = idx 129 self.frame.body.focus_position = idx
130 if select: 130 if select:
131 self._contactClicked(False, widget, True) 131 self._contact_clicked(False, widget, True)
132 return 132 return
133 except AttributeError: 133 except AttributeError:
134 pass 134 pass
135 idx += 1 135 idx += 1
136 136
137 log.debug("Not element found for {} in setFocus".format(text)) 137 log.debug("Not element found for {} in set_focus".format(text))
138 138
139 # events 139 # events
140 140
141 def _groupClicked(self, group_wid): 141 def _group_clicked(self, group_wid):
142 group = group_wid.getValue() 142 group = group_wid.get_value()
143 data = self.contact_list.getGroupData(group) 143 data = self.contact_list.get_group_data(group)
144 data[C.GROUP_DATA_FOLDED] = not data.setdefault(C.GROUP_DATA_FOLDED, False) 144 data[C.GROUP_DATA_FOLDED] = not data.setdefault(C.GROUP_DATA_FOLDED, False)
145 self.setFocus(group) 145 self.set_focus(group)
146 self.update() 146 self.update()
147 147
148 def _contactClicked(self, use_bare_jid, contact_wid, selected): 148 def _contact_clicked(self, use_bare_jid, contact_wid, selected):
149 """Method called when a contact is clicked 149 """Method called when a contact is clicked
150 150
151 @param use_bare_jid: True if use_bare_jid is set in self._buildEntityWidget. 151 @param use_bare_jid: True if use_bare_jid is set in self._build_entity_widget.
152 @param contact_wid: widget of the contact, must have the entity set in data attribute 152 @param contact_wid: widget of the contact, must have the entity set in data attribute
153 @param selected: boolean returned by the widget, telling if it is selected 153 @param selected: boolean returned by the widget, telling if it is selected
154 """ 154 """
155 entity = contact_wid.data 155 entity = contact_wid.data
156 self.host.modeHint(C.MODE_INSERTION) 156 self.host.mode_hint(C.MODE_INSERTION)
157 self._emit("click", entity) 157 self._emit("click", entity)
158 158
159 def onNotification(self, entity, notif, profile): 159 def on_notification(self, entity, notif, profile):
160 notifs = list(self.host.getNotifs(C.ENTITY_ALL, profile=self.profile)) 160 notifs = list(self.host.get_notifs(C.ENTITY_ALL, profile=self.profile))
161 if notifs: 161 if notifs:
162 self.title_dynamic = "({})".format(len(notifs)) 162 self.title_dynamic = "({})".format(len(notifs))
163 else: 163 else:
164 self.title_dynamic = None 164 self.title_dynamic = None
165 self.host.redraw() # FIXME: should not be necessary 165 self.host.redraw() # FIXME: should not be necessary
166 166
167 # Methods to build the widget 167 # Methods to build the widget
168 168
169 def _buildEntityWidget( 169 def _build_entity_widget(
170 self, 170 self,
171 entity, 171 entity,
172 keys=None, 172 keys=None,
173 use_bare_jid=False, 173 use_bare_jid=False,
174 with_notifs=True, 174 with_notifs=True,
220 markup.insert(0, "{} ".format(show_icon)) 220 markup.insert(0, "{} ".format(show_icon))
221 else: 221 else:
222 entity_attr = "default" 222 entity_attr = "default"
223 223
224 notifs = list( 224 notifs = list(
225 self.host.getNotifs(entity, exact_jid=special, profile=self.profile) 225 self.host.get_notifs(entity, exact_jid=special, profile=self.profile)
226 ) 226 )
227 mentions = list( 227 mentions = list(
228 self.host.getNotifs(entity.bare, C.NOTIFY_MENTION, profile=self.profile) 228 self.host.get_notifs(entity.bare, C.NOTIFY_MENTION, profile=self.profile)
229 ) 229 )
230 if notifs or mentions: 230 if notifs or mentions:
231 attr = 'cl_mention' if mentions else 'cl_notifs' 231 attr = 'cl_mention' if mentions else 'cl_notifs'
232 header = [(attr, "({})".format(len(notifs) + len(mentions))), " "] 232 header = [(attr, "({})".format(len(notifs) + len(mentions))), " "]
233 else: 233 else:
243 markup, selected=entity in selected, header=header 243 markup, selected=entity in selected, header=header
244 ) 244 )
245 widget.data = entity 245 widget.data = entity
246 widget.comp = entity_txt.lower() # value to use for sorting 246 widget.comp = entity_txt.lower() # value to use for sorting
247 urwid.connect_signal( 247 urwid.connect_signal(
248 widget, "change", self._contactClicked, user_args=[use_bare_jid] 248 widget, "change", self._contact_clicked, user_args=[use_bare_jid]
249 ) 249 )
250 return widget 250 return widget
251 251
252 def _buildEntities(self, content, entities): 252 def _build_entities(self, content, entities):
253 """Add entity representation in widget list 253 """Add entity representation in widget list
254 254
255 @param content: widget list, e.g. SimpleListWalker 255 @param content: widget list, e.g. SimpleListWalker
256 @param entities (iterable): iterable of JID to display 256 @param entities (iterable): iterable of JID to display
257 """ 257 """
260 widgets = [] # list of built widgets 260 widgets = [] # list of built widgets
261 261
262 for entity in entities: 262 for entity in entities:
263 if ( 263 if (
264 entity in self.contact_list._specials 264 entity in self.contact_list._specials
265 or not self.contact_list.entityVisible(entity) 265 or not self.contact_list.entity_visible(entity)
266 ): 266 ):
267 continue 267 continue
268 markup_extra = [] 268 markup_extra = []
269 if self.contact_list.show_resources: 269 if self.contact_list.show_resources:
270 for resource in self.contact_list.getCache(entity, C.CONTACT_RESOURCES): 270 for resource in self.contact_list.getCache(entity, C.CONTACT_RESOURCES):
286 else: 286 else:
287 if self.contact_list.show_status: 287 if self.contact_list.show_status:
288 status = self.contact_list.getCache(entity, "status", default=None) 288 status = self.contact_list.getCache(entity, "status", default=None)
289 status_disp = ("status", "\n " + status) if status else "" 289 status_disp = ("status", "\n " + status) if status else ""
290 markup_extra.append(status_disp) 290 markup_extra.append(status_disp)
291 widget = self._buildEntityWidget( 291 widget = self._build_entity_widget(
292 entity, 292 entity,
293 ("cache_nick", "cache_name", "node"), 293 ("cache_nick", "cache_name", "node"),
294 use_bare_jid=True, 294 use_bare_jid=True,
295 markup_append=markup_extra, 295 markup_append=markup_extra,
296 ) 296 )
299 widgets.sort(key=lambda widget: widget.comp) 299 widgets.sort(key=lambda widget: widget.comp)
300 300
301 for widget in widgets: 301 for widget in widgets:
302 content.append(widget) 302 content.append(widget)
303 303
304 def _buildSpecials(self, content): 304 def _build_specials(self, content):
305 """Build the special entities""" 305 """Build the special entities"""
306 specials = sorted(self.contact_list.getSpecials()) 306 specials = sorted(self.contact_list.get_specials())
307 current = None 307 current = None
308 for entity in specials: 308 for entity in specials:
309 if current is not None and current.bare == entity.bare: 309 if current is not None and current.bare == entity.bare:
310 # nested entity (e.g. MUC private conversations) 310 # nested entity (e.g. MUC private conversations)
311 widget = self._buildEntityWidget( 311 widget = self._build_entity_widget(
312 entity, ("resource",), markup_prepend=" ", special=True 312 entity, ("resource",), markup_prepend=" ", special=True
313 ) 313 )
314 else: 314 else:
315 # the special widgets 315 # the special widgets
316 if entity.resource: 316 if entity.resource:
317 widget = self._buildEntityWidget(entity, ("resource",), special=True) 317 widget = self._build_entity_widget(entity, ("resource",), special=True)
318 else: 318 else:
319 widget = self._buildEntityWidget( 319 widget = self._build_entity_widget(
320 entity, 320 entity,
321 ("cache_nick", "cache_name", "node"), 321 ("cache_nick", "cache_name", "node"),
322 with_show_attr=False, 322 with_show_attr=False,
323 special=True, 323 special=True,
324 ) 324 )
325 content.append(widget) 325 content.append(widget)
326 326
327 def _buildList(self): 327 def _build_list(self):
328 """Build the main contact list widget""" 328 """Build the main contact list widget"""
329 content = urwid.SimpleListWalker([]) 329 content = urwid.SimpleListWalker([])
330 330
331 self._buildSpecials(content) 331 self._build_specials(content)
332 if self.contact_list._specials: 332 if self.contact_list._specials:
333 content.append(urwid.Divider("=")) 333 content.append(urwid.Divider("="))
334 334
335 groups = list(self.contact_list._groups) 335 groups = list(self.contact_list._groups)
336 groups.sort(key=lambda x: x.lower() if x else '') 336 groups.sort(key=lambda x: x.lower() if x else '')
337 for group in groups: 337 for group in groups:
338 data = self.contact_list.getGroupData(group) 338 data = self.contact_list.get_group_data(group)
339 folded = data.get(C.GROUP_DATA_FOLDED, False) 339 folded = data.get(C.GROUP_DATA_FOLDED, False)
340 jids = list(data["jids"]) 340 jids = list(data["jids"])
341 if group is not None and ( 341 if group is not None and (
342 self.contact_list.anyEntityVisible(jids) 342 self.contact_list.any_entity_visible(jids)
343 or self.contact_list.show_empty_groups 343 or self.contact_list.show_empty_groups
344 ): 344 ):
345 header = "[-]" if not folded else "[+]" 345 header = "[-]" if not folded else "[+]"
346 widget = sat_widgets.ClickableText(group, header=header + " ") 346 widget = sat_widgets.ClickableText(group, header=header + " ")
347 content.append(widget) 347 content.append(widget)
348 urwid.connect_signal(widget, "click", self._groupClicked) 348 urwid.connect_signal(widget, "click", self._group_clicked)
349 if not folded: 349 if not folded:
350 self._buildEntities(content, jids) 350 self._build_entities(content, jids)
351 not_in_roster = ( 351 not_in_roster = (
352 set(self.contact_list._cache) 352 set(self.contact_list._cache)
353 .difference(self.contact_list._roster) 353 .difference(self.contact_list._roster)
354 .difference(self.contact_list._specials) 354 .difference(self.contact_list._specials)
355 .difference((self.contact_list.whoami.bare,)) 355 .difference((self.contact_list.whoami.bare,))
356 ) 356 )
357 if not_in_roster: 357 if not_in_roster:
358 content.append(urwid.Divider("-")) 358 content.append(urwid.Divider("-"))
359 self._buildEntities(content, not_in_roster) 359 self._build_entities(content, not_in_roster)
360 360
361 return urwid.ListBox(content) 361 return urwid.ListBox(content)
362 362
363 363
364 quick_widgets.register(QuickContactList, ContactList) 364 quick_widgets.register(QuickContactList, ContactList)