changeset 2015:20fb71b656e3

quick_frontend, primitivus (contact_list): improved and simplified handling of "special" entities: - special_extras has been removed - specials handle all entities (bare + full) in a single set
author Goffi <goffi@goffi.org>
date Sun, 24 Jul 2016 17:47:09 +0200 (2016-07-24)
parents 0694a2611bad
children f09562b0704d
files frontends/src/primitivus/chat.py frontends/src/primitivus/contact_list.py frontends/src/quick_frontend/quick_chat.py frontends/src/quick_frontend/quick_contact_list.py
diffstat 4 files changed, 31 insertions(+), 61 deletions(-) [+]
line wrap: on
line diff
--- a/frontends/src/primitivus/chat.py	Tue Jul 19 21:25:22 2016 +0200
+++ b/frontends/src/primitivus/chat.py	Sun Jul 24 17:47:09 2016 +0200
@@ -553,7 +553,7 @@
         super(Chat, self)._onHistoryPrinted()
 
     def onPrivateCreated(self, widget):
-        self.host.contact_lists[widget.profile].specialResourceVisible(widget.target)
+        self.host.contact_lists[widget.profile].setSpecial(widget.target, C.CONTACT_SPECIAL_GROUP)
 
     def onSelected(self):
         self.focus_marker_set = False
--- a/frontends/src/primitivus/contact_list.py	Tue Jul 19 21:25:22 2016 +0200
+++ b/frontends/src/primitivus/contact_list.py	Sun Jul 24 17:47:09 2016 +0200
@@ -122,17 +122,6 @@
 
         log.debug(u"Not element found for {} in setFocus".format(text))
 
-    def specialResourceVisible(self, entity):
-        """Assure a resource of a special entity is visible and clickable
-
-        Mainly used to display private conversation in MUC rooms
-        @param entity: full jid of the resource to show
-        """
-        assert isinstance(entity, jid.JID)
-        if entity not in self._special_extras:
-            self._special_extras.add(entity)
-            self.update()
-
     # events
 
     def _groupClicked(self, group_wid):
@@ -163,7 +152,7 @@
 
     # Methods to build the widget
 
-    def _buildEntityWidget(self, entity, keys=None, use_bare_jid=False, with_notifs=True, with_show_attr=True, markup_prepend=None, markup_append = None):
+    def _buildEntityWidget(self, entity, keys=None, use_bare_jid=False, with_notifs=True, with_show_attr=True, markup_prepend=None, markup_append=None, special=False):
         """Build one contact markup data
 
         @param entity (jid.JID): entity to build
@@ -177,6 +166,7 @@
         @param with_show_attr (bool): if True, show color corresponding to presence status
         @param markup_prepend (list): markup to prepend to the generated one before building the widget
         @param markup_append (list): markup to append to the generated one before building the widget
+        @param special (bool): True if entity is a special one
         @return (list): markup data are expected by Urwid text widgets
         """
         markup = []
@@ -269,25 +259,18 @@
 
     def _buildSpecials(self, content):
         """Build the special entities"""
-        specials = list(self.contact_list._specials)
-        specials.sort()
-        extra_shown = set()
+        specials = sorted(self.contact_list.getSpecials())
+        current = None
         for entity in specials:
-            # the special widgets
-            widget = self._buildEntityWidget(entity, ('cache_nick', 'cache_name', 'node'), with_show_attr=False)
-            content.append(widget)
-
-            # resources which must be displayed (e.g. MUC private conversations)
-            extras = [extra for extra in self.contact_list._special_extras if extra.bare == entity.bare]
-            extras.sort()
-            for extra in extras:
-                widget = self._buildEntityWidget(extra, ('resource',), markup_prepend = '  ')
-                content.append(widget)
-                extra_shown.add(extra)
-
-        # entities which must be visible but not resource of current special entities
-        for extra in self.contact_list._special_extras.difference(extra_shown):
-            widget = self._buildEntityWidget(extra, ('resource',))
+            if current is not None and current.bare == entity.bare:
+                # nested entity (e.g. MUC private conversations)
+                widget = self._buildEntityWidget(entity, ('resource',), markup_prepend='  ', special=True)
+            else:
+                # the special widgets
+                if entity.resource:
+                    widget = self._buildEntityWidget(entity, ('resource',), special=True)
+                else:
+                    widget = self._buildEntityWidget(entity, ('cache_nick', 'cache_name', 'node'), with_show_attr=False, special=True)
             content.append(widget)
 
     def _buildList(self):
--- a/frontends/src/quick_frontend/quick_chat.py	Tue Jul 19 21:25:22 2016 +0200
+++ b/frontends/src/quick_frontend/quick_chat.py	Sun Jul 24 17:47:09 2016 +0200
@@ -106,7 +106,7 @@
             except KeyError:
                 log.error(u"extra data is missing user nick for uid {}".format(self.uid))
                 return ""
-        if self.parent.type == C.CHAT_GROUP or entity in contact_list.getSpecialExtras(C.CONTACT_SPECIAL_GROUP):
+        if self.parent.type == C.CHAT_GROUP or entity in contact_list.getSpecials(C.CONTACT_SPECIAL_GROUP):
             return entity.resource or ""
         if entity.bare in contact_list:
             return contact_list.getCache(entity, 'nick') or contact_list.getCache(entity, 'name') or entity.node or entity
--- a/frontends/src/quick_frontend/quick_contact_list.py	Tue Jul 19 21:25:22 2016 +0200
+++ b/frontends/src/quick_frontend/quick_contact_list.py	Sun Jul 24 17:47:09 2016 +0200
@@ -56,10 +56,9 @@
         # for different profiles (e.g. directed presence)
         self._cache = {}
 
-        # special entities (groupchat, gateways, etc), bare jids
+        # special entities (groupchat, gateways, etc)
+        # may be bare or full jid
         self._specials = set()
-        # extras are specials with full jids (e.g.: private MUC conversation)
-        self._special_extras = set()
 
         # group data contain jids in groups and misc frontend data
         # None key is used for jids with not group
@@ -178,20 +177,6 @@
         """
         return self._cache[entity]
 
-    def getSpecialExtras(self, special_type=None):
-        """Return special extras with given type
-
-        If special_type is None, return all special extras.
-
-        @param special_type(unicode, None): one of special type (e.g. C.CONTACT_SPECIAL_GROUP)
-            None to return all special extras.
-        @return (set[jid.JID])
-        """
-        if special_type is None:
-            return self._special_extras
-        specials = self.getSpecials(special_type)
-        return {extra for extra in self._special_extras if extra.bare in specials}
-
     def _gotContacts(self, contacts):
         """Called during filling, add contacts and notice parent that contacts are filled"""
         for contact in contacts:
@@ -289,22 +274,25 @@
         """Set special flag on an entity
 
         @param entity(jid.JID): jid of the special entity
+            if the jid is full, will be added to special extras
         @param special_type: one of special type (e.g. C.CONTACT_SPECIAL_GROUP) or None to remove special flag
         """
         assert special_type in C.CONTACT_SPECIAL_ALLOWED + (None,)
         self.setCache(entity, C.CONTACT_SPECIAL, special_type)
 
-    def getSpecials(self, special_type=None):
+    def getSpecials(self, special_type=None, bare=False):
         """Return all the bare JIDs of the special roster entities of with given type.
 
-        If special_type is None, return all specials.
-        @param special_type: one of special type (e.g. C.CONTACT_SPECIAL_GROUP) or None to return all specials.
-        @return: set(jid.JID)
+        @param special_type(unicode, None): if not None, filter by special type (e.g. C.CONTACT_SPECIAL_GROUP)
+        @param bare(bool): return only bare jids if True
+        @return (iter[jid.JID]): found special entities
         """
-        if special_type is None:
-            return self._specials
-        return set([entity for entity in self._specials if self.getCache(entity, C.CONTACT_SPECIAL) == special_type])
-
+        for entity in self._specials:
+            if bare and entity.resource:
+                continue
+            if special_type is not None and self.getCache(entity, C.CONTACT_SPECIAL) != special_type:
+                continue
+            yield entity
 
     def disconnect(self):
         # for now we just clear contacts on disconnect
@@ -320,7 +308,6 @@
             self._cache.clear()
         self._groups.clear()
         self._specials.clear()
-        self._special_extras.clear()
         self._roster.clear()
         self.update()
 
@@ -369,9 +356,9 @@
         if C.CONTACT_SPECIAL in attributes:
             if attributes[C.CONTACT_SPECIAL] is None:
                 del attributes[C.CONTACT_SPECIAL]
-                self._specials.remove(entity_bare)
+                self._specials.remove(entity)
             else:
-                self._specials.add(entity_bare)
+                self._specials.add(entity)
                 cache[C.CONTACT_MAIN_RESOURCE] = None
 
         # now the attributes we keep in cache
@@ -441,7 +428,7 @@
             self._groups[group]['jids'].remove(entity_bare)
             if not self._groups[group]['jids']:
                 self._groups.pop(group) # FIXME: we use pop because of pyjamas: http://wiki.goffi.org/wiki/Issues_with_Pyjamas/en
-        for iterable in (self._selected, self._specials, self._special_extras):
+        for iterable in (self._selected, self._specials):
             to_remove = set()
             for set_entity in iterable:
                 if set_entity.bare == entity.bare: