comparison sat_frontends/quick_frontend/quick_contact_list.py @ 2624:56f94936df1e

code style reformatting using black
author Goffi <goffi@goffi.org>
date Wed, 27 Jun 2018 20:14:46 +0200
parents 81b70eeb710f
children ce1e15d59496
comparison
equal deleted inserted replaced
2623:49533de4540b 2624:56f94936df1e
20 """Contact List handling multi profiles at once, 20 """Contact List handling multi profiles at once,
21 should replace quick_contact_list module in the future""" 21 should replace quick_contact_list module in the future"""
22 22
23 from sat.core.i18n import _ 23 from sat.core.i18n import _
24 from sat.core.log import getLogger 24 from sat.core.log import getLogger
25
25 log = getLogger(__name__) 26 log = getLogger(__name__)
26 from sat.core import exceptions 27 from sat.core import exceptions
27 from sat_frontends.quick_frontend.quick_widgets import QuickWidget 28 from sat_frontends.quick_frontend.quick_widgets import QuickWidget
28 from sat_frontends.quick_frontend.constants import Const as C 29 from sat_frontends.quick_frontend.constants import Const as C
29 from sat_frontends.tools import jid 30 from sat_frontends.tools import jid
30 from collections import OrderedDict 31 from collections import OrderedDict
31 32
32 33
33 try: 34 try:
34 # FIXME: to be removed when an acceptable solution is here 35 # FIXME: to be removed when an acceptable solution is here
35 unicode('') # XXX: unicode doesn't exist in pyjamas 36 unicode("") # XXX: unicode doesn't exist in pyjamas
36 except (TypeError, AttributeError): # Error raised is not the same depending on 37 except (TypeError, AttributeError): # Error raised is not the same depending on
37 # pyjsbuild options 38 # pyjsbuild options
38 # XXX: pyjamas' max doesn't support key argument, so we implement it ourself 39 # XXX: pyjamas' max doesn't support key argument, so we implement it ourself
39 pyjamas_max = max 40 pyjamas_max = max
40 41
41 def max(iterable, key): 42 def max(iterable, key):
42 iter_cpy = list(iterable) 43 iter_cpy = list(iterable)
93 # do we show entities with notifications? 94 # do we show entities with notifications?
94 # if True, entities will be show even if they normally would not 95 # if True, entities will be show even if they normally would not
95 # (e.g. not in contact list) if they have notifications attached 96 # (e.g. not in contact list) if they have notifications attached
96 self.show_entities_with_notifs = True 97 self.show_entities_with_notifs = True
97 98
98 self.host.bridge.asyncGetParamA(C.SHOW_EMPTY_GROUPS, 99 self.host.bridge.asyncGetParamA(
99 "General", 100 C.SHOW_EMPTY_GROUPS,
100 profile_key=profile, 101 "General",
101 callback=self._showEmptyGroups) 102 profile_key=profile,
102 103 callback=self._showEmptyGroups,
103 self.host.bridge.asyncGetParamA(C.SHOW_OFFLINE_CONTACTS, 104 )
104 "General", 105
105 profile_key=profile, 106 self.host.bridge.asyncGetParamA(
106 callback=self._showOfflineContacts) 107 C.SHOW_OFFLINE_CONTACTS,
108 "General",
109 profile_key=profile,
110 callback=self._showOfflineContacts,
111 )
107 112
108 # FIXME: workaround for a pyjamas issue: calling hash on a class method always 113 # FIXME: workaround for a pyjamas issue: calling hash on a class method always
109 # return a different value if that method is defined directly within the 114 # return a different value if that method is defined directly within the
110 # class (with the "def" keyword) 115 # class (with the "def" keyword)
111 self.presenceListener = self.onPresenceUpdate 116 self.presenceListener = self.onPresenceUpdate
112 self.host.addListener('presence', self.presenceListener, [self.profile]) 117 self.host.addListener("presence", self.presenceListener, [self.profile])
113 self.nickListener = self.onNickUpdate 118 self.nickListener = self.onNickUpdate
114 self.host.addListener('nick', self.nickListener, [self.profile]) 119 self.host.addListener("nick", self.nickListener, [self.profile])
115 self.notifListener = self.onNotification 120 self.notifListener = self.onNotification
116 self.host.addListener('notification', self.notifListener, [self.profile]) 121 self.host.addListener("notification", self.notifListener, [self.profile])
117 # notifListener only update the entity, so we can re-use it 122 # notifListener only update the entity, so we can re-use it
118 self.host.addListener('notificationsClear', self.notifListener, [self.profile]) 123 self.host.addListener("notificationsClear", self.notifListener, [self.profile])
119 124
120 def _showEmptyGroups(self, show_str): 125 def _showEmptyGroups(self, show_str):
121 # Called only by __init__ 126 # Called only by __init__
122 # self.update is not wanted here, as it is done by 127 # self.update is not wanted here, as it is done by
123 # handler when all profiles are ready 128 # handler when all profiles are ready
153 def roster_connected(self): 158 def roster_connected(self):
154 """Return all the bare JIDs of the roster entities that are connected. 159 """Return all the bare JIDs of the roster entities that are connected.
155 160
156 @return (set[jid.JID]) 161 @return (set[jid.JID])
157 """ 162 """
158 return set([entity for entity in self._roster 163 return set(
159 if self.getCache(entity, C.PRESENCE_SHOW) is not None]) 164 [
165 entity
166 for entity in self._roster
167 if self.getCache(entity, C.PRESENCE_SHOW) is not None
168 ]
169 )
160 170
161 @property 171 @property
162 def roster_entities_by_group(self): 172 def roster_entities_by_group(self):
163 """Return a dictionary binding the roster groups to their entities bare JIDs. 173 """Return a dictionary binding the roster groups to their entities bare JIDs.
164 174
165 This also includes the empty group (None key). 175 This also includes the empty group (None key).
166 @return (dict[unicode,set(jid.JID)]) 176 @return (dict[unicode,set(jid.JID)])
167 """ 177 """
168 return {group: self._groups[group]['jids'] for group in self._groups} 178 return {group: self._groups[group]["jids"] for group in self._groups}
169 179
170 @property 180 @property
171 def roster_groups_by_entities(self): 181 def roster_groups_by_entities(self):
172 """Return a dictionary binding the entities bare JIDs to their roster groups 182 """Return a dictionary binding the entities bare JIDs to their roster groups
173 183
174 @return (dict[jid.JID, set(unicode)]) 184 @return (dict[jid.JID, set(unicode)])
175 """ 185 """
176 result = {} 186 result = {}
177 for group, data in self._groups.iteritems(): 187 for group, data in self._groups.iteritems():
178 for entity in data['jids']: 188 for entity in data["jids"]:
179 result.setdefault(entity, set()).add(group) 189 result.setdefault(entity, set()).add(group)
180 return result 190 return result
181 191
182 @property 192 @property
183 def selected(self): 193 def selected(self):
193 203
194 entities are not sorted 204 entities are not sorted
195 """ 205 """
196 return self._cache.iteritems() 206 return self._cache.iteritems()
197 207
198
199 @property 208 @property
200 def items(self): 209 def items(self):
201 """Return item representation for all visible entities in cache 210 """Return item representation for all visible entities in cache
202 211
203 entities are not sorted 212 entities are not sorted
204 key: bare jid, value: data 213 key: bare jid, value: data
205 """ 214 """
206 return {jid_:cache for jid_, cache in self._cache.iteritems() 215 return {
207 if self.entityVisible(jid_)} 216 jid_: cache
208 217 for jid_, cache in self._cache.iteritems()
218 if self.entityVisible(jid_)
219 }
209 220
210 def getItem(self, entity): 221 def getItem(self, entity):
211 """Return item representation of requested entity 222 """Return item representation of requested entity
212 223
213 @param entity(jid.JID): bare jid of entity 224 @param entity(jid.JID): bare jid of entity
273 284
274 if name is None: 285 if name is None:
275 # full cache is requested 286 # full cache is requested
276 return cache 287 return cache
277 288
278 if name in ('status', C.PRESENCE_STATUSES, C.PRESENCE_PRIORITY, C.PRESENCE_SHOW): 289 if name in ("status", C.PRESENCE_STATUSES, C.PRESENCE_PRIORITY, C.PRESENCE_SHOW):
279 # these data are related to the resource 290 # these data are related to the resource
280 if not entity.resource: 291 if not entity.resource:
281 main_resource = cache[C.CONTACT_MAIN_RESOURCE] 292 main_resource = cache[C.CONTACT_MAIN_RESOURCE]
282 if main_resource is None: 293 if main_resource is None:
283 # we ignore presence info if we don't have any resource in cache 294 # we ignore presence info if we don't have any resource in cache
285 return 296 return
286 cache = cache[C.CONTACT_RESOURCES].setdefault(main_resource, {}) 297 cache = cache[C.CONTACT_RESOURCES].setdefault(main_resource, {})
287 else: 298 else:
288 cache = cache[C.CONTACT_RESOURCES].setdefault(entity.resource, {}) 299 cache = cache[C.CONTACT_RESOURCES].setdefault(entity.resource, {})
289 300
290 if name == 'status': # XXX: we get the first status for 'status' key 301 if name == "status": # XXX: we get the first status for 'status' key
291 # TODO: manage main language for statuses 302 # TODO: manage main language for statuses
292 return cache[C.PRESENCE_STATUSES].get(C.PRESENCE_STATUSES_DEFAULT, '') 303 return cache[C.PRESENCE_STATUSES].get(C.PRESENCE_STATUSES_DEFAULT, "")
293 304
294 elif entity.resource: 305 elif entity.resource:
295 try: 306 try:
296 return cache[C.CONTACT_RESOURCES][entity.resource][name] 307 return cache[C.CONTACT_RESOURCES][entity.resource][name]
297 except KeyError: 308 except KeyError:
330 341
331 @param group: a valid (existing) group name 342 @param group: a valid (existing) group name
332 @param name: name of the data (can't be "jids") 343 @param name: name of the data (can't be "jids")
333 @param value: value to set 344 @param value: value to set
334 """ 345 """
335 assert name is not 'jids' 346 assert name is not "jids"
336 self._groups[group][name] = value 347 self._groups[group][name] = value
337 348
338 def getGroupData(self, group, name=None): 349 def getGroupData(self, group, name=None):
339 """Return value associated to group data 350 """Return value associated to group data
340 351
386 @return (iter[jid.JID]): found special entities 397 @return (iter[jid.JID]): found special entities
387 """ 398 """
388 for entity in self._specials: 399 for entity in self._specials:
389 if bare and entity.resource: 400 if bare and entity.resource:
390 continue 401 continue
391 if (special_type is not None 402 if (
392 and self.getCache(entity, C.CONTACT_SPECIAL) != special_type): 403 special_type is not None
404 and self.getCache(entity, C.CONTACT_SPECIAL) != special_type
405 ):
393 continue 406 continue
394 yield entity 407 yield entity
395 408
396 def disconnect(self): 409 def disconnect(self):
397 # for now we just clear contacts on disconnect 410 # for now we just clear contacts on disconnect
438 was_visible = self.entityVisible(entity_bare) 451 was_visible = self.entityVisible(entity_bare)
439 452
440 if in_roster: 453 if in_roster:
441 self._roster.add(entity_bare) 454 self._roster.add(entity_bare)
442 455
443 cache = self._cache.setdefault(entity_bare, {C.CONTACT_RESOURCES: {}, 456 cache = self._cache.setdefault(
444 C.CONTACT_MAIN_RESOURCE: None, 457 entity_bare,
445 C.CONTACT_SELECTED: set()}) 458 {
459 C.CONTACT_RESOURCES: {},
460 C.CONTACT_MAIN_RESOURCE: None,
461 C.CONTACT_SELECTED: set(),
462 },
463 )
446 464
447 # we don't want forbidden data in attributes 465 # we don't want forbidden data in attributes
448 assert not C.CONTACT_DATA_FORBIDDEN.intersection(attributes) 466 assert not C.CONTACT_DATA_FORBIDDEN.intersection(attributes)
449 467
450 # we set groups and fill self._groups accordingly 468 # we set groups and fill self._groups accordingly
452 if not groups: 470 if not groups:
453 groups = [None] # [None] is the default group 471 groups = [None] # [None] is the default group
454 if C.CONTACT_GROUPS in cache: 472 if C.CONTACT_GROUPS in cache:
455 # XXX: don't use set(cache[C.CONTACT_GROUPS]).difference(groups) because 473 # XXX: don't use set(cache[C.CONTACT_GROUPS]).difference(groups) because
456 # it won't work in Pyjamas if None is in cache[C.CONTACT_GROUPS] 474 # it won't work in Pyjamas if None is in cache[C.CONTACT_GROUPS]
457 for group in [group for group in cache[C.CONTACT_GROUPS] 475 for group in [
458 if group not in groups]: 476 group for group in cache[C.CONTACT_GROUPS] if group not in groups
459 self._groups[group]['jids'].remove(entity_bare) 477 ]:
478 self._groups[group]["jids"].remove(entity_bare)
460 cache[C.CONTACT_GROUPS] = groups 479 cache[C.CONTACT_GROUPS] = groups
461 for group in groups: 480 for group in groups:
462 self._groups.setdefault(group, {}).setdefault('jids', set()).add( 481 self._groups.setdefault(group, {}).setdefault("jids", set()).add(
463 entity_bare) 482 entity_bare
483 )
464 484
465 # special entities management 485 # special entities management
466 if C.CONTACT_SPECIAL in attributes: 486 if C.CONTACT_SPECIAL in attributes:
467 if attributes[C.CONTACT_SPECIAL] is None: 487 if attributes[C.CONTACT_SPECIAL] is None:
468 del attributes[C.CONTACT_SPECIAL] 488 del attributes[C.CONTACT_SPECIAL]
471 self._specials.add(entity) 491 self._specials.add(entity)
472 cache[C.CONTACT_MAIN_RESOURCE] = None 492 cache[C.CONTACT_MAIN_RESOURCE] = None
473 493
474 # now the attributes we keep in cache 494 # now the attributes we keep in cache
475 # XXX: if entity is a full jid, we store the value for the resource only 495 # XXX: if entity is a full jid, we store the value for the resource only
476 cache_attr = (cache[C.CONTACT_RESOURCES].setdefault(entity.resource, {}) 496 cache_attr = (
477 if entity.resource else cache) 497 cache[C.CONTACT_RESOURCES].setdefault(entity.resource, {})
498 if entity.resource
499 else cache
500 )
478 for attribute, value in attributes.iteritems(): 501 for attribute, value in attributes.iteritems():
479 if value is None: 502 if value is None:
480 # XXX: pyjamas hack: we need to use pop instead of del 503 # XXX: pyjamas hack: we need to use pop instead of del
481 try: 504 try:
482 cache_attr[attribute].pop(value) 505 cache_attr[attribute].pop(value)
483 except KeyError: 506 except KeyError:
484 pass 507 pass
485 else: 508 else:
486 if attribute == 'nick' and self.isSpecial(entity, C.CONTACT_SPECIAL_GROUP): 509 if attribute == "nick" and self.isSpecial(
510 entity, C.CONTACT_SPECIAL_GROUP
511 ):
487 # we don't want to keep nick for MUC rooms 512 # we don't want to keep nick for MUC rooms
488 # FIXME: this is here as plugin XEP-0054 can link resource's nick 513 # FIXME: this is here as plugin XEP-0054 can link resource's nick
489 # with bare jid which in the case of MUC 514 # with bare jid which in the case of MUC
490 # set the nick for the whole MUC 515 # set the nick for the whole MUC
491 # resulting in bad name displayed in some frontends 516 # resulting in bad name displayed in some frontends
516 541
517 if check_resource: 542 if check_resource:
518 selected = self._selected 543 selected = self._selected
519 else: 544 else:
520 selected = {selected.bare for selected in self._selected} 545 selected = {selected.bare for selected in self._selected}
521 return ((show is not None and show != C.PRESENCE_UNAVAILABLE) 546 return (
522 or self.show_disconnected 547 (show is not None and show != C.PRESENCE_UNAVAILABLE)
523 or entity in selected 548 or self.show_disconnected
524 or (self.show_entities_with_notifs 549 or entity in selected
525 and next(self.host.getNotifs(entity.bare, profile=self.profile), None)) 550 or (
526 ) 551 self.show_entities_with_notifs
552 and next(self.host.getNotifs(entity.bare, profile=self.profile), None)
553 )
554 )
527 555
528 def anyEntityVisible(self, entities, check_resources=False): 556 def anyEntityVisible(self, entities, check_resources=False):
529 """Tell if in a list of entities, at least one should be shown 557 """Tell if in a list of entities, at least one should be shown
530 558
531 @param entities (list[jid.JID]): list of jids 559 @param entities (list[jid.JID]): list of jids
562 self._roster.remove(entity_bare) 590 self._roster.remove(entity_bare)
563 except KeyError: 591 except KeyError:
564 pass 592 pass
565 del self._cache[entity_bare] 593 del self._cache[entity_bare]
566 for group in groups: 594 for group in groups:
567 self._groups[group]['jids'].remove(entity_bare) 595 self._groups[group]["jids"].remove(entity_bare)
568 if not self._groups[group]['jids']: 596 if not self._groups[group]["jids"]:
569 # FIXME: we use pop because of pyjamas: 597 # FIXME: we use pop because of pyjamas:
570 # http://wiki.goffi.org/wiki/Issues_with_Pyjamas/en 598 # http://wiki.goffi.org/wiki/Issues_with_Pyjamas/en
571 self._groups.pop(group) 599 self._groups.pop(group)
572 for iterable in (self._selected, self._specials): 600 for iterable in (self._selected, self._specials):
573 to_remove = set() 601 to_remove = set()
597 cache[C.CONTACT_MAIN_RESOURCE] = None 625 cache[C.CONTACT_MAIN_RESOURCE] = None
598 else: 626 else:
599 try: 627 try:
600 del cache[C.CONTACT_RESOURCES][entity.resource] 628 del cache[C.CONTACT_RESOURCES][entity.resource]
601 except KeyError: 629 except KeyError:
602 log.error(u"Presence unavailable received " 630 log.error(
603 u"for an unknown resource [{}]".format(entity)) 631 u"Presence unavailable received "
632 u"for an unknown resource [{}]".format(entity)
633 )
604 if not cache[C.CONTACT_RESOURCES]: 634 if not cache[C.CONTACT_RESOURCES]:
605 cache[C.CONTACT_MAIN_RESOURCE] = None 635 cache[C.CONTACT_MAIN_RESOURCE] = None
606 else: 636 else:
607 if not entity.resource: 637 if not entity.resource:
608 log.warning(_(u"received presence from entity " 638 log.warning(
609 u"without resource: {}".format(entity))) 639 _(
640 u"received presence from entity "
641 u"without resource: {}".format(entity)
642 )
643 )
610 resources_data = cache[C.CONTACT_RESOURCES] 644 resources_data = cache[C.CONTACT_RESOURCES]
611 resource_data = resources_data.setdefault(entity.resource, {}) 645 resource_data = resources_data.setdefault(entity.resource, {})
612 resource_data[C.PRESENCE_SHOW] = show 646 resource_data[C.PRESENCE_SHOW] = show
613 resource_data[C.PRESENCE_PRIORITY] = int(priority) 647 resource_data[C.PRESENCE_PRIORITY] = int(priority)
614 resource_data[C.PRESENCE_STATUSES] = statuses 648 resource_data[C.PRESENCE_STATUSES] = statuses
615 649
616 if entity.bare not in self._specials: 650 if entity.bare not in self._specials:
617 # we may have resources with no priority 651 # we may have resources with no priority
618 # (when a cached value is added for a not connected resource) 652 # (when a cached value is added for a not connected resource)
619 priority_resource = max(resources_data, 653 priority_resource = max(
620 key=lambda res: resources_data[res].get( 654 resources_data,
621 C.PRESENCE_PRIORITY, -2**32)) 655 key=lambda res: resources_data[res].get(
656 C.PRESENCE_PRIORITY, -2 ** 32
657 ),
658 )
622 cache[C.CONTACT_MAIN_RESOURCE] = priority_resource 659 cache[C.CONTACT_MAIN_RESOURCE] = priority_resource
623 if self.entityVisible(entity.bare): 660 if self.entityVisible(entity.bare):
624 update_type = C.UPDATE_MODIFY if was_visible else C.UPDATE_ADD 661 update_type = C.UPDATE_MODIFY if was_visible else C.UPDATE_ADD
625 self.update([entity], update_type, self.profile) 662 self.update([entity], update_type, self.profile)
626 elif was_visible: 663 elif was_visible:
632 @param entity(jid.JID): entity updated 669 @param entity(jid.JID): entity updated
633 @param new_nick(unicode): new nick of the entity 670 @param new_nick(unicode): new nick of the entity
634 @param profile: %(doc_profile)s 671 @param profile: %(doc_profile)s
635 """ 672 """
636 assert profile == self.profile 673 assert profile == self.profile
637 self.setCache(entity, 'nick', new_nick) 674 self.setCache(entity, "nick", new_nick)
638 675
639 def onNotification(self, entity, notif, profile): 676 def onNotification(self, entity, notif, profile):
640 """Update entity with notification 677 """Update entity with notification
641 678
642 @param entity(jid.JID): entity updated 679 @param entity(jid.JID): entity updated
721 def update(self, entities=None, type_=None, profile=None): 758 def update(self, entities=None, type_=None, profile=None):
722 handler.update(entities, type_, profile) 759 handler.update(entities, type_, profile)
723 760
724 761
725 class QuickContactListHandler(object): 762 class QuickContactListHandler(object):
726
727 def __init__(self, host): 763 def __init__(self, host):
728 super(QuickContactListHandler, self).__init__() 764 super(QuickContactListHandler, self).__init__()
729 self.host = host 765 self.host = host
730 global handler 766 global handler
731 if handler is not None: 767 if handler is not None:
732 raise exceptions.InternalError(u"QuickContactListHandler must be " 768 raise exceptions.InternalError(
733 u"instanciated only once") 769 u"QuickContactListHandler must be " u"instanciated only once"
770 )
734 handler = self 771 handler = self
735 self._clist = {} # key: profile, value: ProfileContactList 772 self._clist = {} # key: profile, value: ProfileContactList
736 self._widgets = set() 773 self._widgets = set()
737 self._update_locked = False # se to True to ignore updates 774 self._update_locked = False # se to True to ignore updates
738 775
739 def __getitem__(self, profile): 776 def __getitem__(self, profile):
740 """Return ProfileContactList instance for the requested profile""" 777 """Return ProfileContactList instance for the requested profile"""
741 return self._clist[profile] 778 return self._clist[profile]
742 779
843 key: bare jid, value: data 880 key: bare jid, value: data
844 """ 881 """
845 return self.items_sort(self.items) 882 return self.items_sort(self.items)
846 883
847 def items_sort(self, items): 884 def items_sort(self, items):
848 """sort items 885 """sort items
849 886
850 @param items(dict): items to sort (will be emptied !) 887 @param items(dict): items to sort (will be emptied !)
851 @return (OrderedDict): sorted items 888 @return (OrderedDict): sorted items
852 """ 889 """
853 ordered_items = OrderedDict() 890 ordered_items = OrderedDict()
854 bare_jids = sorted(items.keys()) 891 bare_jids = sorted(items.keys())
855 for jid_ in bare_jids: 892 for jid_ in bare_jids:
856 ordered_items[jid_] = items.pop(jid_) 893 ordered_items[jid_] = items.pop(jid_)
857 return ordered_items 894 return ordered_items
858 895
859 def register(self, widget): 896 def register(self, widget):
860 """Register a QuickContactList widget 897 """Register a QuickContactList widget
861 898
862 This method should only be used in QuickContactList 899 This method should only be used in QuickContactList
938 else: 975 else:
939 to_fill.update(self._clist.items()) 976 to_fill.update(self._clist.items())
940 977
941 remaining = to_fill.difference(filled) 978 remaining = to_fill.difference(filled)
942 if remaining != to_fill: 979 if remaining != to_fill:
943 log.debug(u"Not re-filling already filled contact list(s) for {}".format( 980 log.debug(
944 u', '.join(to_fill.intersection(filled)))) 981 u"Not re-filling already filled contact list(s) for {}".format(
982 u", ".join(to_fill.intersection(filled))
983 )
984 )
945 for profile in remaining: 985 for profile in remaining:
946 self._clist[profile]._fill() 986 self._clist[profile]._fill()
947 987
948 def clearContacts(self, keep_cache=False): 988 def clearContacts(self, keep_cache=False):
949 """Clear all the contact list 989 """Clear all the contact list
971 @param locked(bool): updates are forbidden if True 1011 @param locked(bool): updates are forbidden if True
972 @param do_update(bool): if True, a full update is done after unlocking 1012 @param do_update(bool): if True, a full update is done after unlocking
973 if set to False, widget state can be inconsistent, be sure to know 1013 if set to False, widget state can be inconsistent, be sure to know
974 what youa re doing! 1014 what youa re doing!
975 """ 1015 """
976 log.debug(u"Contact lists updates are now {}".format( 1016 log.debug(
977 u"LOCKED" if locked else u"UNLOCKED")) 1017 u"Contact lists updates are now {}".format(
1018 u"LOCKED" if locked else u"UNLOCKED"
1019 )
1020 )
978 self._update_locked = locked 1021 self._update_locked = locked
979 if not locked and do_update: 1022 if not locked and do_update:
980 self.update() 1023 self.update()
981 1024
982 def update(self, entities=None, type_=None, profile=None): 1025 def update(self, entities=None, type_=None, profile=None):
985 widget.update(entities, type_, profile) 1028 widget.update(entities, type_, profile)
986 1029
987 1030
988 class QuickContactList(QuickWidget): 1031 class QuickContactList(QuickWidget):
989 """This class manage the visual representation of contacts""" 1032 """This class manage the visual representation of contacts"""
990 SINGLE=False 1033
991 PROFILES_MULTIPLE=True 1034 SINGLE = False
1035 PROFILES_MULTIPLE = True
992 # Can be linked to no profile (e.g. at the early frontend start) 1036 # Can be linked to no profile (e.g. at the early frontend start)
993 PROFILES_ALLOW_NONE=True 1037 PROFILES_ALLOW_NONE = True
994 1038
995 def __init__(self, host, profiles): 1039 def __init__(self, host, profiles):
996 super(QuickContactList, self).__init__(host, None, profiles) 1040 super(QuickContactList, self).__init__(host, None, profiles)
997 1041
998 # options 1042 # options
999 # for next values, None means use indivual value per profile 1043 # for next values, None means use indivual value per profile
1000 # True or False mean override these values for all profiles 1044 # True or False mean override these values for all profiles
1001 self.show_disconnected = None # TODO 1045 self.show_disconnected = None # TODO
1002 self.show_empty_groups = None # TODO 1046 self.show_empty_groups = None # TODO
1003 self.show_resources = None # TODO 1047 self.show_resources = None # TODO
1004 self.show_status = None # TODO 1048 self.show_status = None # TODO
1005 1049
1006 def postInit(self): 1050 def postInit(self):
1007 """Method to be called by frontend after widget is initialised""" 1051 """Method to be called by frontend after widget is initialised"""
1008 handler.register(self) 1052 handler.register(self)
1009 1053