changeset 1476:48706f4ff19c

core (xmlui): added JidsListWidget to manage editable list of jids: - can be used to manage XEP-0004's jid-multi - can be used in the future for search result to display found entities (need a read-only style) - generaly usefull to manage list of entites - implemented in params too
author Goffi <goffi@goffi.org>
date Thu, 20 Aug 2015 18:33:52 +0200 (2015-08-20)
parents 7ac073d2e7e0
children ac522c4dab0e
files src/tools/xml_tools.py
diffstat 1 files changed, 81 insertions(+), 8 deletions(-) [+]
line wrap: on
line diff
--- a/src/tools/xml_tools.py	Tue Aug 18 10:52:18 2015 +0200
+++ b/src/tools/xml_tools.py	Thu Aug 20 18:33:52 2015 +0200
@@ -25,6 +25,7 @@
 from xml.dom import minidom, NotFoundErr
 from wokkel import data_form
 from twisted.words.xish import domish
+from twisted.words.protocols.jabber import jid
 from sat.core import exceptions
 
 
@@ -254,6 +255,7 @@
     @param xml (unicode)
     @return: XMLUI
     """
+    # TODO: refactor params and use Twisted directly to parse XML
     params_doc = minidom.parseString(xml.encode('utf-8'))
     top = params_doc.documentElement
     if top.nodeName != 'params':
@@ -281,9 +283,11 @@
             callback_id = param.getAttribute('callback_id') or None
 
             if type_ == 'list':
-                options, selected = _getParamListOptions(param)
+                options, selected = _paramsGetListOptions(param)
                 widget_kwargs['options'] = options
                 widget_kwargs['selected'] = selected
+            elif type_ == 'jids_list':
+                widget_kwargs['jids'] = _paramsGetListJids(param)
 
             if type_ in ("button", "text"):
                 param_ui.addEmpty()
@@ -308,7 +312,7 @@
     return param_ui.toXml()
 
 
-def _getParamListOptions(param):
+def _paramsGetListOptions(param):
     """Retrieve the options for list element.
 
     The <option/> tags must be direct children of <param/>.
@@ -324,8 +328,21 @@
     selected = [elem.getAttribute("value") for elem in elems if elem.getAttribute("selected") == 'true']
     return (options, selected)
 
+def _paramsGetListJids(param):
+    """Retrive jids from a jids_list element.
 
-## XMLUI Elements
+    the <jid/> tags must be direct children of <param/>
+    @param param (domish.Element): element
+    @return: a list of jids
+    """
+    elems = param.getElementsByTagName("jid")
+    jids = [elem.firstChild.data for elem in elems
+            if elem.firstChild is not None
+            and elem.firstChild.nodeType == elem.TEXT_NODE]
+    return jids
+
+
+### XMLUI Elements ###
 
 
 class Element(object):
@@ -427,6 +444,26 @@
             self.elem.setAttribute('selected', 'true')
 
 
+class JidElement(Element):
+    """" Used by JidsListWidget to specify jids"""
+    type = 'jid'
+
+    def __init__(self, parent, jid_):
+        """
+        @param jid_(jid.JID, unicode): jid to append
+        """
+        assert isinstance(parent, JidsListWidget)
+        super(JidElement, self).__init__(parent.xmlui, parent)
+        if isinstance(jid_, jid.JID):
+            value = jid.full
+        elif isinstance(jid_, basestring):
+            value = unicode(jid_)
+        else:
+            raise NotImplementedError
+        jid_txt = self.xmlui.doc.createTextNode(value)
+        self.elem.appendChild(jid_txt)
+
+
 class RowElement(Element):
     """" Used by AdvancedListContainer """
     type = 'row'
@@ -462,6 +499,9 @@
             self.elem.setAttribute('description', description)
 
 
+## Containers ##
+
+
 class Container(Element):
     """ And Element which contains other ones and has a layout """
     type = None
@@ -603,6 +643,9 @@
         self.xmlui.changeContainer(parent_container)
 
 
+## Widgets ##
+
+
 class Widget(Element):
     type = None
 
@@ -798,7 +841,7 @@
 class ListWidget(InputWidget):
     type = 'list'
 
-    def __init__(self, xmlui, options, selected=None, style=None, name=None, parent=None):
+    def __init__(self, xmlui, options, selected=None, styles=None, name=None, parent=None):
         """
 
         @param xmlui
@@ -806,13 +849,15 @@
             - a single string if the label and the value are the same
             - a tuple with a couple of string (value,label) if the label and the value differ
         @param selected (list[string]): list of the selected values
-        @param style (string)
+        @param styles (iterable[string]): flags to set the behaviour of the list
         @param name (string)
         @param parent
         """
-        if style is None:
-            style = set()
-        styles = set(style)
+        styles = set() if styles is None else set(styles)
+        if styles is None:
+            styles = set()
+        else:
+            styles = set(styles)
         if not options:
             log.warning(_('empty "options" list'))
         if not styles.issubset(['multi']):
@@ -834,6 +879,34 @@
             value = option if isinstance(option, basestring) else option[0]
             OptionElement(self, option, value in selected)
 
+class JidsListWidget(InputWidget):
+    """A list of text or jids where elements can be added/removed or modified"""
+    type = 'jids_list'
+
+    def __init__(self, xmlui, jids, styles=None, name=None, parent=None):
+        """
+
+        @param xmlui
+        @param jids (list[jid.JID]): base jids
+        @param styles (iterable[string]): flags to set the behaviour of the list
+        @param name (string)
+        @param parent
+        """
+        super(JidsListWidget, self).__init__(xmlui, name, parent)
+        styles = set() if styles is None else set(styles)
+        if not styles.issubset([]): # TODO
+            raise exceptions.DataError(_("invalid styles"))
+        for style in styles:
+            self.elem.setAttribute(style, 'yes')
+        if not jids:
+            log.debug('empty jids list')
+        else:
+            self.addJids(jids)
+
+    def addJids(self, jids):
+        for jid_ in jids:
+            JidElement(self, jid_)
+
 
 ## Dialog Elements ##