comparison sat_frontends/quick_frontend/quick_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
81 # selected entities, full jid 81 # selected entities, full jid
82 self._selected = set() 82 self._selected = set()
83 83
84 # options 84 # options
85 self.show_disconnected = False 85 self.show_disconnected = False
86 self.show_empty_groups = True 86 self._show_empty_groups = True
87 self.show_resources = False 87 self.show_resources = False
88 self.show_status = False 88 self.show_status = False
89 # do we show entities with notifications? 89 # do we show entities with notifications?
90 # if True, entities will be show even if they normally would not 90 # if True, entities will be show even if they normally would not
91 # (e.g. not in contact list) if they have notifications attached 91 # (e.g. not in contact list) if they have notifications attached
92 self.show_entities_with_notifs = True 92 self.show_entities_with_notifs = True
93 93
94 self.host.bridge.asyncGetParamA( 94 self.host.bridge.param_get_a_async(
95 C.SHOW_EMPTY_GROUPS, 95 C.SHOW_EMPTY_GROUPS,
96 "General", 96 "General",
97 profile_key=profile, 97 profile_key=profile,
98 callback=self._showEmptyGroups, 98 callback=self._show_empty_groups_cb,
99 ) 99 )
100 100
101 self.host.bridge.asyncGetParamA( 101 self.host.bridge.param_get_a_async(
102 C.SHOW_OFFLINE_CONTACTS, 102 C.SHOW_OFFLINE_CONTACTS,
103 "General", 103 "General",
104 profile_key=profile, 104 profile_key=profile,
105 callback=self._showOfflineContacts, 105 callback=self._show_offline_contacts,
106 ) 106 )
107 107
108 self.host.addListener("presence", self.onPresenceUpdate, [self.profile]) 108 self.host.addListener("presence", self.on_presence_update, [self.profile])
109 self.host.addListener("nicknames", self.onNicknamesUpdate, [self.profile]) 109 self.host.addListener("nicknames", self.on_nicknames_update, [self.profile])
110 self.host.addListener("notification", self.onNotification, [self.profile]) 110 self.host.addListener("notification", self.on_notification, [self.profile])
111 # onNotification only updates the entity, so we can re-use it 111 # on_notification only updates the entity, so we can re-use it
112 self.host.addListener("notificationsClear", self.onNotification, [self.profile]) 112 self.host.addListener("notificationsClear", self.on_notification, [self.profile])
113 113
114 @property 114 @property
115 def whoami(self): 115 def whoami(self):
116 return self.host.profiles[self.profile].whoami 116 return self.host.profiles[self.profile].whoami
117 117
118 def _showEmptyGroups(self, show_str): 118 def _show_empty_groups_cb(self, show_str):
119 # Called only by __init__ 119 # Called only by __init__
120 # self.update is not wanted here, as it is done by 120 # self.update is not wanted here, as it is done by
121 # handler when all profiles are ready 121 # handler when all profiles are ready
122 self.showEmptyGroups(C.bool(show_str)) 122 self.show_empty_groups(C.bool(show_str))
123 123
124 def _showOfflineContacts(self, show_str): 124 def _show_offline_contacts(self, show_str):
125 # same comments as for _showEmptyGroups 125 # same comments as for _show_empty_groups
126 self.showOfflineContacts(C.bool(show_str)) 126 self.show_offline_contacts(C.bool(show_str))
127 127
128 def __contains__(self, entity): 128 def __contains__(self, entity):
129 """Check if entity is in contact list 129 """Check if entity is in contact list
130 130
131 An entity can be in contact list even if not in roster 131 An entity can be in contact list even if not in roster
132 use isInRoster to check if entity is in roster. 132 use is_in_roster to check if entity is in roster.
133 @param entity (jid.JID): jid of the entity (resource is not ignored, 133 @param entity (jid.JID): jid of the entity (resource is not ignored,
134 use bare jid if needed) 134 use bare jid if needed)
135 """ 135 """
136 if entity.resource: 136 if entity.resource:
137 try: 137 try:
207 key: bare jid, value: data 207 key: bare jid, value: data
208 """ 208 """
209 return { 209 return {
210 jid_: cache 210 jid_: cache
211 for jid_, cache in self._cache.items() 211 for jid_, cache in self._cache.items()
212 if self.entityVisible(jid_) 212 if self.entity_visible(jid_)
213 } 213 }
214 214
215 def getItem(self, entity): 215 def get_item(self, entity):
216 """Return item representation of requested entity 216 """Return item representation of requested entity
217 217
218 @param entity(jid.JID): bare jid of entity 218 @param entity(jid.JID): bare jid of entity
219 @raise (KeyError): entity is unknown 219 @raise (KeyError): entity is unknown
220 """ 220 """
221 return self._cache[entity] 221 return self._cache[entity]
222 222
223 def _gotContacts(self, contacts): 223 def _got_contacts(self, contacts):
224 """Add contacts and notice parent that contacts are filled 224 """Add contacts and notice parent that contacts are filled
225 225
226 Called during initial contact list filling 226 Called during initial contact list filling
227 @param contacts(tuple): all contacts 227 @param contacts(tuple): all contacts
228 """ 228 """
233 # will cause troubles 233 # will cause troubles
234 log.warning( 234 log.warning(
235 "Roster entities with resources are not managed, ignoring {entity}" 235 "Roster entities with resources are not managed, ignoring {entity}"
236 .format(entity=entity)) 236 .format(entity=entity))
237 continue 237 continue
238 self.host.newContactHandler(*contact, profile=self.profile) 238 self.host.contact_new_handler(*contact, profile=self.profile)
239 handler._contactsFilled(self.profile) 239 handler._contacts_filled(self.profile)
240 240
241 def _fill(self): 241 def _fill(self):
242 """Get all contacts from backend 242 """Get all contacts from backend
243 243
244 Contacts will be cleared before refilling them 244 Contacts will be cleared before refilling them
245 """ 245 """
246 self.clearContacts(keep_cache=True) 246 self.clear_contacts(keep_cache=True)
247 self.host.bridge.getContacts(self.profile, callback=self._gotContacts) 247 self.host.bridge.contacts_get(self.profile, callback=self._got_contacts)
248 248
249 def fill(self): 249 def fill(self):
250 handler.fill(self.profile) 250 handler.fill(self.profile)
251 251
252 def getCache( 252 def getCache(
283 # we won't get the avatar set in the resource 283 # we won't get the avatar set in the resource
284 try: 284 try:
285 cache = self._cache[entity.bare] 285 cache = self._cache[entity.bare]
286 except KeyError: 286 except KeyError:
287 if create_if_not_found: 287 if create_if_not_found:
288 self.setContact(entity) 288 self.set_contact(entity)
289 cache = self._cache[entity.bare] 289 cache = self._cache[entity.bare]
290 else: 290 else:
291 raise exceptions.NotFound 291 raise exceptions.NotFound
292 292
293 if name is None: 293 if name is None:
317 elif entity.resource: 317 elif entity.resource:
318 try: 318 try:
319 return cache[C.CONTACT_RESOURCES][entity.resource][name] 319 return cache[C.CONTACT_RESOURCES][entity.resource][name]
320 except KeyError as e: 320 except KeyError as e:
321 if bare_default is None: 321 if bare_default is None:
322 bare_default = not self.isRoom(entity.bare) 322 bare_default = not self.is_room(entity.bare)
323 if not bare_default: 323 if not bare_default:
324 if default is Exception: 324 if default is Exception:
325 raise e 325 raise e
326 else: 326 else:
327 return default 327 return default
332 if default is Exception: 332 if default is Exception:
333 raise e 333 raise e
334 else: 334 else:
335 return default 335 return default
336 336
337 def setCache(self, entity, name, value): 337 def set_cache(self, entity, name, value):
338 """Set or update value for one data in cache 338 """Set or update value for one data in cache
339 339
340 @param entity(JID): entity to update 340 @param entity(JID): entity to update
341 @param name(str): value to set or update 341 @param name(str): value to set or update
342 """ 342 """
343 self.setContact(entity, attributes={name: value}) 343 self.set_contact(entity, attributes={name: value})
344 344
345 def getFullJid(self, entity): 345 def get_full_jid(self, entity):
346 """Get full jid from a bare jid 346 """Get full jid from a bare jid
347 347
348 @param entity(jid.JID): must be a bare jid 348 @param entity(jid.JID): must be a bare jid
349 @return (jid.JID): bare jid + main resource 349 @return (jid.JID): bare jid + main resource
350 @raise ValueError: the entity is not bare 350 @raise ValueError: the entity is not bare
351 """ 351 """
352 if entity.resource: 352 if entity.resource:
353 raise ValueError("getFullJid must be used with a bare jid") 353 raise ValueError("get_full_jid must be used with a bare jid")
354 main_resource = self.getCache(entity, C.CONTACT_MAIN_RESOURCE) 354 main_resource = self.getCache(entity, C.CONTACT_MAIN_RESOURCE)
355 return jid.JID("{}/{}".format(entity, main_resource)) 355 return jid.JID("{}/{}".format(entity, main_resource))
356 356
357 def setGroupData(self, group, name, value): 357 def set_group_data(self, group, name, value):
358 """Register a data for a group 358 """Register a data for a group
359 359
360 @param group: a valid (existing) group name 360 @param group: a valid (existing) group name
361 @param name: name of the data (can't be "jids") 361 @param name: name of the data (can't be "jids")
362 @param value: value to set 362 @param value: value to set
363 """ 363 """
364 assert name != "jids" 364 assert name != "jids"
365 self._groups[group][name] = value 365 self._groups[group][name] = value
366 366
367 def getGroupData(self, group, name=None): 367 def get_group_data(self, group, name=None):
368 """Return value associated to group data 368 """Return value associated to group data
369 369
370 @param group: a valid (existing) group name 370 @param group: a valid (existing) group name
371 @param name: name of the data or None to get the whole dict 371 @param name: name of the data or None to get the whole dict
372 @return: registered value 372 @return: registered value
373 """ 373 """
374 if name is None: 374 if name is None:
375 return self._groups[group] 375 return self._groups[group]
376 return self._groups[group][name] 376 return self._groups[group][name]
377 377
378 def isInRoster(self, entity): 378 def is_in_roster(self, entity):
379 """Tell if an entity is in roster 379 """Tell if an entity is in roster
380 380
381 @param entity(jid.JID): jid of the entity 381 @param entity(jid.JID): jid of the entity
382 the bare jid will be used 382 the bare jid will be used
383 """ 383 """
384 return entity.bare in self._roster 384 return entity.bare in self._roster
385 385
386 def isRoom(self, entity): 386 def is_room(self, entity):
387 """Helper method to know if entity is a MUC room 387 """Helper method to know if entity is a MUC room
388 388
389 @param entity(jid.JID): jid of the entity 389 @param entity(jid.JID): jid of the entity
390 hint: use bare jid here, as room can't be full jid with MUC 390 hint: use bare jid here, as room can't be full jid with MUC
391 @return (bool): True if entity is a room 391 @return (bool): True if entity is a room
392 """ 392 """
393 assert entity.resource is None # FIXME: this may change when MIX will be handled 393 assert entity.resource is None # FIXME: this may change when MIX will be handled
394 return self.isSpecial(entity, C.CONTACT_SPECIAL_GROUP) 394 return self.is_special(entity, C.CONTACT_SPECIAL_GROUP)
395 395
396 def isSpecial(self, entity, special_type): 396 def is_special(self, entity, special_type):
397 """Tell if an entity is of a specialy _type 397 """Tell if an entity is of a specialy _type
398 398
399 @param entity(jid.JID): jid of the special entity 399 @param entity(jid.JID): jid of the special entity
400 if the jid is full, will be added to special extras 400 if the jid is full, will be added to special extras
401 @param special_type: one of special type (e.g. C.CONTACT_SPECIAL_GROUP) 401 @param special_type: one of special type (e.g. C.CONTACT_SPECIAL_GROUP)
402 @return (bool): True if entity is from this special type 402 @return (bool): True if entity is from this special type
403 """ 403 """
404 return self.getCache(entity, C.CONTACT_SPECIAL, default=None) == special_type 404 return self.getCache(entity, C.CONTACT_SPECIAL, default=None) == special_type
405 405
406 def setSpecial(self, entity, special_type): 406 def set_special(self, entity, special_type):
407 """Set special flag on an entity 407 """Set special flag on an entity
408 408
409 @param entity(jid.JID): jid of the special entity 409 @param entity(jid.JID): jid of the special entity
410 if the jid is full, will be added to special extras 410 if the jid is full, will be added to special extras
411 @param special_type: one of special type (e.g. C.CONTACT_SPECIAL_GROUP) 411 @param special_type: one of special type (e.g. C.CONTACT_SPECIAL_GROUP)
412 or None to remove special flag 412 or None to remove special flag
413 """ 413 """
414 assert special_type in C.CONTACT_SPECIAL_ALLOWED + (None,) 414 assert special_type in C.CONTACT_SPECIAL_ALLOWED + (None,)
415 self.setCache(entity, C.CONTACT_SPECIAL, special_type) 415 self.set_cache(entity, C.CONTACT_SPECIAL, special_type)
416 416
417 def getSpecials(self, special_type=None, bare=False): 417 def get_specials(self, special_type=None, bare=False):
418 """Return all the bare JIDs of the special roster entities of with given type. 418 """Return all the bare JIDs of the special roster entities of with given type.
419 419
420 @param special_type(unicode, None): if not None, filter by special type 420 @param special_type(unicode, None): if not None, filter by special type
421 (e.g. C.CONTACT_SPECIAL_GROUP) 421 (e.g. C.CONTACT_SPECIAL_GROUP)
422 @param bare(bool): return only bare jids if True 422 @param bare(bool): return only bare jids if True
432 continue 432 continue
433 yield entity 433 yield entity
434 434
435 def disconnect(self): 435 def disconnect(self):
436 # for now we just clear contacts on disconnect 436 # for now we just clear contacts on disconnect
437 self.clearContacts() 437 self.clear_contacts()
438 438
439 def clearContacts(self, keep_cache=False): 439 def clear_contacts(self, keep_cache=False):
440 """Clear all the contact list 440 """Clear all the contact list
441 441
442 @param keep_cache: if True, don't reset the cache 442 @param keep_cache: if True, don't reset the cache
443 """ 443 """
444 self.select(None) 444 self.select(None)
447 self._groups.clear() 447 self._groups.clear()
448 self._specials.clear() 448 self._specials.clear()
449 self._roster.clear() 449 self._roster.clear()
450 self.update() 450 self.update()
451 451
452 def setContact(self, entity, groups=None, attributes=None, in_roster=False): 452 def set_contact(self, entity, groups=None, attributes=None, in_roster=False):
453 """Add a contact to the list if it doesn't exist, else update it. 453 """Add a contact to the list if it doesn't exist, else update it.
454 454
455 This method can be called with groups=None for the purpose of updating 455 This method can be called with groups=None for the purpose of updating
456 the contact's attributes (e.g. nicknames). In that case, the groups 456 the contact's attributes (e.g. nicknames). In that case, the groups
457 attribute must not be set to the default group but ignored. If not, 457 attribute must not be set to the default group but ignored. If not,
471 471
472 entity_bare = entity.bare 472 entity_bare = entity.bare
473 # we check if the entity is visible before changing anything 473 # we check if the entity is visible before changing anything
474 # this way we know if we need to do an UPDATE_ADD, UPDATE_MODIFY 474 # this way we know if we need to do an UPDATE_ADD, UPDATE_MODIFY
475 # or an UPDATE_DELETE 475 # or an UPDATE_DELETE
476 was_visible = self.entityVisible(entity_bare) 476 was_visible = self.entity_visible(entity_bare)
477 477
478 if in_roster: 478 if in_roster:
479 self._roster.add(entity_bare) 479 self._roster.add(entity_bare)
480 480
481 cache = self._cache.setdefault( 481 cache = self._cache.setdefault(
524 cache[C.CONTACT_RESOURCES].setdefault(entity.resource, {}) 524 cache[C.CONTACT_RESOURCES].setdefault(entity.resource, {})
525 if entity.resource 525 if entity.resource
526 else cache 526 else cache
527 ) 527 )
528 for attribute, value in attributes.items(): 528 for attribute, value in attributes.items():
529 if attribute == "nicknames" and self.isSpecial( 529 if attribute == "nicknames" and self.is_special(
530 entity, C.CONTACT_SPECIAL_GROUP 530 entity, C.CONTACT_SPECIAL_GROUP
531 ): 531 ):
532 # we don't want to keep nicknames for MUC rooms 532 # we don't want to keep nicknames for MUC rooms
533 # FIXME: this is here as plugin XEP-0054 can link resource's nick 533 # FIXME: this is here as plugin XEP-0054 can link resource's nick
534 # with bare jid which in the case of MUC 534 # with bare jid which in the case of MUC
538 # may not be needed anymore… 538 # may not be needed anymore…
539 continue 539 continue
540 cache_attr[attribute] = value 540 cache_attr[attribute] = value
541 541
542 # we can update the display if needed 542 # we can update the display if needed
543 if self.entityVisible(entity_bare): 543 if self.entity_visible(entity_bare):
544 # if the contact was not visible, we need to add a widget 544 # if the contact was not visible, we need to add a widget
545 # else we just update id 545 # else we just update id
546 update_type = C.UPDATE_MODIFY if was_visible else C.UPDATE_ADD 546 update_type = C.UPDATE_MODIFY if was_visible else C.UPDATE_ADD
547 self.update([entity], update_type, self.profile) 547 self.update([entity], update_type, self.profile)
548 elif was_visible: 548 elif was_visible:
549 # the entity was visible and is not anymore, we remove it 549 # the entity was visible and is not anymore, we remove it
550 self.update([entity], C.UPDATE_DELETE, self.profile) 550 self.update([entity], C.UPDATE_DELETE, self.profile)
551 551
552 def entityVisible(self, entity, check_resource=False): 552 def entity_visible(self, entity, check_resource=False):
553 """Tell if the contact should be showed or hidden. 553 """Tell if the contact should be showed or hidden.
554 554
555 @param entity (jid.JID): jid of the contact 555 @param entity (jid.JID): jid of the contact
556 @param check_resource (bool): True if resource must be significant 556 @param check_resource (bool): True if resource must be significant
557 @return (bool): True if that contact should be showed in the list 557 @return (bool): True if that contact should be showed in the list
569 (show is not None and show != C.PRESENCE_UNAVAILABLE) 569 (show is not None and show != C.PRESENCE_UNAVAILABLE)
570 or self.show_disconnected 570 or self.show_disconnected
571 or entity in selected 571 or entity in selected
572 or ( 572 or (
573 self.show_entities_with_notifs 573 self.show_entities_with_notifs
574 and next(self.host.getNotifs(entity.bare, profile=self.profile), None) 574 and next(self.host.get_notifs(entity.bare, profile=self.profile), None)
575 ) 575 )
576 or entity.resource is None and self.isRoom(entity.bare) 576 or entity.resource is None and self.is_room(entity.bare)
577 ) 577 )
578 578
579 def anyEntityVisible(self, entities, check_resources=False): 579 def any_entity_visible(self, entities, check_resources=False):
580 """Tell if in a list of entities, at least one should be shown 580 """Tell if in a list of entities, at least one should be shown
581 581
582 @param entities (list[jid.JID]): list of jids 582 @param entities (list[jid.JID]): list of jids
583 @param check_resources (bool): True if resources must be significant 583 @param check_resources (bool): True if resources must be significant
584 @return (bool): True if a least one entity need to be shown 584 @return (bool): True if a least one entity need to be shown
585 """ 585 """
586 # FIXME: looks inefficient, really needed? 586 # FIXME: looks inefficient, really needed?
587 for entity in entities: 587 for entity in entities:
588 if self.entityVisible(entity, check_resources): 588 if self.entity_visible(entity, check_resources):
589 return True 589 return True
590 return False 590 return False
591 591
592 def isEntityInGroup(self, entity, group): 592 def is_entity_in_group(self, entity, group):
593 """Tell if an entity is in a roster group 593 """Tell if an entity is in a roster group
594 594
595 @param entity(jid.JID): jid of the entity 595 @param entity(jid.JID): jid of the entity
596 @param group(unicode): group to check 596 @param group(unicode): group to check
597 @return (bool): True if the entity is in the group 597 @return (bool): True if the entity is in the group
598 """ 598 """
599 return entity in self.getGroupData(group, "jids") 599 return entity in self.get_group_data(group, "jids")
600 600
601 def removeContact(self, entity): 601 def remove_contact(self, entity):
602 """remove a contact from the list 602 """remove a contact from the list
603 603
604 @param entity(jid.JID): jid of the entity to remove (bare jid is used) 604 @param entity(jid.JID): jid of the entity to remove (bare jid is used)
605 """ 605 """
606 entity_bare = entity.bare 606 entity_bare = entity.bare
607 was_visible = self.entityVisible(entity_bare) 607 was_visible = self.entity_visible(entity_bare)
608 try: 608 try:
609 groups = self._cache[entity_bare].get(C.CONTACT_GROUPS, set()) 609 groups = self._cache[entity_bare].get(C.CONTACT_GROUPS, set())
610 except KeyError: 610 except KeyError:
611 log.error(_("Trying to delete an unknow entity [{}]").format(entity)) 611 log.error(_("Trying to delete an unknow entity [{}]").format(entity))
612 try: 612 try:
627 to_remove.add(set_entity) 627 to_remove.add(set_entity)
628 iterable.difference_update(to_remove) 628 iterable.difference_update(to_remove)
629 if was_visible: 629 if was_visible:
630 self.update([entity], C.UPDATE_DELETE, self.profile) 630 self.update([entity], C.UPDATE_DELETE, self.profile)
631 631
632 def onPresenceUpdate(self, entity, show, priority, statuses, profile): 632 def on_presence_update(self, entity, show, priority, statuses, profile):
633 """Update entity's presence status 633 """Update entity's presence status
634 634
635 @param entity(jid.JID): entity updated 635 @param entity(jid.JID): entity updated
636 @param show: availability 636 @param show: availability
637 @parap priority: resource's priority 637 @parap priority: resource's priority
638 @param statuses: dict of statuses 638 @param statuses: dict of statuses
639 @param profile: %(doc_profile)s 639 @param profile: %(doc_profile)s
640 """ 640 """
641 # FIXME: cache modification should be done with setContact 641 # FIXME: cache modification should be done with set_contact
642 # the resources/presence handling logic should be moved there 642 # the resources/presence handling logic should be moved there
643 was_visible = self.entityVisible(entity.bare) 643 was_visible = self.entity_visible(entity.bare)
644 cache = self.getCache(entity, create_if_not_found=True) 644 cache = self.getCache(entity, create_if_not_found=True)
645 if show == C.PRESENCE_UNAVAILABLE: 645 if show == C.PRESENCE_UNAVAILABLE:
646 if not entity.resource: 646 if not entity.resource:
647 cache[C.CONTACT_RESOURCES].clear() 647 cache[C.CONTACT_RESOURCES].clear()
648 cache[C.CONTACT_MAIN_RESOURCE] = None 648 cache[C.CONTACT_MAIN_RESOURCE] = None
678 key=lambda res: resources_data[res].get( 678 key=lambda res: resources_data[res].get(
679 C.PRESENCE_PRIORITY, -2 ** 32 679 C.PRESENCE_PRIORITY, -2 ** 32
680 ), 680 ),
681 ) 681 )
682 cache[C.CONTACT_MAIN_RESOURCE] = priority_resource 682 cache[C.CONTACT_MAIN_RESOURCE] = priority_resource
683 if self.entityVisible(entity.bare): 683 if self.entity_visible(entity.bare):
684 update_type = C.UPDATE_MODIFY if was_visible else C.UPDATE_ADD 684 update_type = C.UPDATE_MODIFY if was_visible else C.UPDATE_ADD
685 self.update([entity], update_type, self.profile) 685 self.update([entity], update_type, self.profile)
686 elif was_visible: 686 elif was_visible:
687 self.update([entity], C.UPDATE_DELETE, self.profile) 687 self.update([entity], C.UPDATE_DELETE, self.profile)
688 688
689 def onNicknamesUpdate(self, entity, nicknames, profile): 689 def on_nicknames_update(self, entity, nicknames, profile):
690 """Update entity's nicknames 690 """Update entity's nicknames
691 691
692 @param entity(jid.JID): entity updated 692 @param entity(jid.JID): entity updated
693 @param nicknames(list[unicode]): nicknames of the entity 693 @param nicknames(list[unicode]): nicknames of the entity
694 @param profile: %(doc_profile)s 694 @param profile: %(doc_profile)s
695 """ 695 """
696 assert profile == self.profile 696 assert profile == self.profile
697 self.setCache(entity, "nicknames", nicknames) 697 self.set_cache(entity, "nicknames", nicknames)
698 698
699 def onNotification(self, entity, notif, profile): 699 def on_notification(self, entity, notif, profile):
700 """Update entity with notification 700 """Update entity with notification
701 701
702 @param entity(jid.JID): entity updated 702 @param entity(jid.JID): entity updated
703 @param notif(dict): notification data 703 @param notif(dict): notification data
704 @param profile: %(doc_profile)s 704 @param profile: %(doc_profile)s
705 """ 705 """
706 assert profile == self.profile 706 assert profile == self.profile
707 if entity is not None and self.entityVisible(entity): 707 if entity is not None and self.entity_visible(entity):
708 self.update([entity], C.UPDATE_MODIFY, profile) 708 self.update([entity], C.UPDATE_MODIFY, profile)
709 709
710 def unselect(self, entity): 710 def unselect(self, entity):
711 """Unselect an entity 711 """Unselect an entity
712 712
745 else: 745 else:
746 cache[C.CONTACT_SELECTED].add(entity.resource) 746 cache[C.CONTACT_SELECTED].add(entity.resource)
747 self._selected.add(entity) 747 self._selected.add(entity)
748 self.update([entity], C.UPDATE_SELECTION, profile=self.profile) 748 self.update([entity], C.UPDATE_SELECTION, profile=self.profile)
749 749
750 def showOfflineContacts(self, show): 750 def show_offline_contacts(self, show):
751 """Tell if offline contacts should be shown 751 """Tell if offline contacts should be shown
752 752
753 @param show(bool): True if offline contacts should be shown 753 @param show(bool): True if offline contacts should be shown
754 """ 754 """
755 assert isinstance(show, bool) 755 assert isinstance(show, bool)
756 if self.show_disconnected == show: 756 if self.show_disconnected == show:
757 return 757 return
758 self.show_disconnected = show 758 self.show_disconnected = show
759 self.update(type_=C.UPDATE_STRUCTURE, profile=self.profile) 759 self.update(type_=C.UPDATE_STRUCTURE, profile=self.profile)
760 760
761 def showEmptyGroups(self, show): 761 def show_empty_groups(self, show):
762 assert isinstance(show, bool) 762 assert isinstance(show, bool)
763 if self.show_empty_groups == show: 763 if self._show_empty_groups == show:
764 return 764 return
765 self.show_empty_groups = show 765 self._show_empty_groups = show
766 self.update(type_=C.UPDATE_STRUCTURE, profile=self.profile) 766 self.update(type_=C.UPDATE_STRUCTURE, profile=self.profile)
767 767
768 def showResources(self, show): 768 def show_resources(self, show):
769 assert isinstance(show, bool) 769 assert isinstance(show, bool)
770 if self.show_resources == show: 770 if self.show_resources == show:
771 return 771 return
772 self.show_resources = show 772 self.show_resources = show
773 self.update(type_=C.UPDATE_STRUCTURE, profile=self.profile) 773 self.update(type_=C.UPDATE_STRUCTURE, profile=self.profile)
774 774
775 def plug(self): 775 def plug(self):
776 handler.addProfile(self.profile) 776 handler.add_profile(self.profile)
777 777
778 def unplug(self): 778 def unplug(self):
779 handler.removeProfile(self.profile) 779 handler.remove_profile(self.profile)
780 780
781 def update(self, entities=None, type_=None, profile=None): 781 def update(self, entities=None, type_=None, profile=None):
782 handler.update(entities, type_, profile) 782 handler.update(entities, type_, profile)
783 783
784 784
928 928
929 This method should only be used in QuickContactList 929 This method should only be used in QuickContactList
930 """ 930 """
931 self._widgets.remove(widget) 931 self._widgets.remove(widget)
932 932
933 def addProfiles(self, profiles): 933 def add_profiles(self, profiles):
934 """Add a contact list for plugged profiles 934 """Add a contact list for plugged profiles
935 935
936 @param profile(iterable[unicode]): plugged profiles 936 @param profile(iterable[unicode]): plugged profiles
937 """ 937 """
938 for profile in profiles: 938 for profile in profiles:
939 if profile not in self._clist: 939 if profile not in self._clist:
940 self._clist[profile] = ProfileContactList(profile) 940 self._clist[profile] = ProfileContactList(profile)
941 return [self._clist[profile] for profile in profiles] 941 return [self._clist[profile] for profile in profiles]
942 942
943 def addProfile(self, profile): 943 def add_profile(self, profile):
944 return self.addProfiles([profile])[0] 944 return self.add_profiles([profile])[0]
945 945
946 def removeProfiles(self, profiles): 946 def remove_profiles(self, profiles):
947 """Remove given unplugged profiles from contact list 947 """Remove given unplugged profiles from contact list
948 948
949 @param profile(iterable[unicode]): unplugged profiles 949 @param profile(iterable[unicode]): unplugged profiles
950 """ 950 """
951 for profile in profiles: 951 for profile in profiles:
952 del self._clist[profile] 952 del self._clist[profile]
953 953
954 def removeProfile(self, profile): 954 def remove_profile(self, profile):
955 self.removeProfiles([profile]) 955 self.remove_profiles([profile])
956 956
957 def getSpecialExtras(self, special_type=None): 957 def get_special_extras(self, special_type=None):
958 """Return special extras with given type 958 """Return special extras with given type
959 959
960 If special_type is None, return all special extras. 960 If special_type is None, return all special extras.
961 961
962 @param special_type(unicode, None): one of special type 962 @param special_type(unicode, None): one of special type
964 None to return all special extras. 964 None to return all special extras.
965 @return (set[jid.JID]) 965 @return (set[jid.JID])
966 """ 966 """
967 entities = set() 967 entities = set()
968 for contact_list in self._clist.values(): 968 for contact_list in self._clist.values():
969 entities.update(contact_list.getSpecialExtras(special_type)) 969 entities.update(contact_list.get_special_extras(special_type))
970 return entities 970 return entities
971 971
972 def _contactsFilled(self, profile): 972 def _contacts_filled(self, profile):
973 self._to_fill.remove(profile) 973 self._to_fill.remove(profile)
974 if not self._to_fill: 974 if not self._to_fill:
975 del self._to_fill 975 del self._to_fill
976 # we need a full update when all contacts are filled 976 # we need a full update when all contacts are filled
977 self.update() 977 self.update()
978 self.host.callListeners("contactsFilled", profile=profile) 978 self.host.call_listeners("contactsFilled", profile=profile)
979 979
980 def fill(self, profile=None): 980 def fill(self, profile=None):
981 """Get all contacts from backend, and fill the widget 981 """Get all contacts from backend, and fill the widget
982 982
983 Contacts will be cleared before refilling them 983 Contacts will be cleared before refilling them
1007 ) 1007 )
1008 ) 1008 )
1009 for profile in remaining: 1009 for profile in remaining:
1010 self._clist[profile]._fill() 1010 self._clist[profile]._fill()
1011 1011
1012 def clearContacts(self, keep_cache=False): 1012 def clear_contacts(self, keep_cache=False):
1013 """Clear all the contact list 1013 """Clear all the contact list
1014 1014
1015 @param keep_cache: if True, don't reset the cache 1015 @param keep_cache: if True, don't reset the cache
1016 """ 1016 """
1017 for contact_list in self._clist.values(): 1017 for contact_list in self._clist.values():
1018 contact_list.clearContacts(keep_cache) 1018 contact_list.clear_contacts(keep_cache)
1019 # we need a full update 1019 # we need a full update
1020 self.update() 1020 self.update()
1021 1021
1022 def select(self, entity): 1022 def select(self, entity):
1023 for contact_list in self._clist.values(): 1023 for contact_list in self._clist.values():
1025 1025
1026 def unselect(self, entity): 1026 def unselect(self, entity):
1027 for contact_list in self._clist.values(): 1027 for contact_list in self._clist.values():
1028 contact_list.select(entity) 1028 contact_list.select(entity)
1029 1029
1030 def lockUpdate(self, locked=True, do_update=True): 1030 def lock_update(self, locked=True, do_update=True):
1031 """Forbid contact list updates 1031 """Forbid contact list updates
1032 1032
1033 Used mainly while profiles are plugged, as many updates can occurs, causing 1033 Used mainly while profiles are plugged, as many updates can occurs, causing
1034 an impact on performances 1034 an impact on performances
1035 @param locked(bool): updates are forbidden if True 1035 @param locked(bool): updates are forbidden if True
1065 1065
1066 # options 1066 # options
1067 # for next values, None means use indivual value per profile 1067 # for next values, None means use indivual value per profile
1068 # True or False mean override these values for all profiles 1068 # True or False mean override these values for all profiles
1069 self.show_disconnected = None # TODO 1069 self.show_disconnected = None # TODO
1070 self.show_empty_groups = None # TODO 1070 self._show_empty_groups = None # TODO
1071 self.show_resources = None # TODO 1071 self.show_resources = None # TODO
1072 self.show_status = None # TODO 1072 self.show_status = None # TODO
1073 1073
1074 def postInit(self): 1074 def post_init(self):
1075 """Method to be called by frontend after widget is initialised""" 1075 """Method to be called by frontend after widget is initialised"""
1076 handler.register(self) 1076 handler.register(self)
1077 1077
1078 @property 1078 @property
1079 def all_iter(self): 1079 def all_iter(self):
1106 @param profile(unicode, None): profile concerned with the update 1106 @param profile(unicode, None): profile concerned with the update
1107 None if all profiles need to be updated 1107 None if all profiles need to be updated
1108 """ 1108 """
1109 raise NotImplementedError 1109 raise NotImplementedError
1110 1110
1111 def onDelete(self): 1111 def on_delete(self):
1112 QuickWidget.onDelete(self) 1112 QuickWidget.on_delete(self)
1113 handler.unregister(self) 1113 handler.unregister(self)