changeset 803:f100fd8d279f

core, frontends: implementation of AdvancedListContainer first draft + misc: /!\ Urwid SàText must be updated as the new TableContainer is used /!\ - fixed button value in paramsXML2XMLUI - new Urwid SàText TabContainer is used in Primitivus for PairsContainer and AdvancedListContainer - fixed in core's XMLUI AdvanceListContainer
author Goffi <goffi@goffi.org>
date Tue, 04 Feb 2014 18:19:29 +0100
parents 9007bb133009
children 5174657b3378
files frontends/src/primitivus/constants.py frontends/src/primitivus/xmlui.py frontends/src/tools/xmlui.py frontends/src/wix/xmlui.py src/tools/xml_tools.py
diffstat 5 files changed, 77 insertions(+), 37 deletions(-) [+]
line wrap: on
line diff
--- a/frontends/src/primitivus/constants.py	Tue Feb 04 18:19:00 2014 +0100
+++ b/frontends/src/primitivus/constants.py	Tue Feb 04 18:19:29 2014 +0100
@@ -69,6 +69,8 @@
                ('show_xa_focus', 'dark red, bold', 'default'),
                ('status', 'yellow', 'default'),
                ('status_focus', 'yellow, bold', 'default'),
+               ('param_selected','default, bold', 'dark red'),
+               ('table_selected','default, bold', 'default'),
                ]
     PRESENCE = {"unavailable": (u'⨯', "show_disconnected"),
                 "": (u'✔', "show_normal"),
--- a/frontends/src/primitivus/xmlui.py	Tue Feb 04 18:19:00 2014 +0100
+++ b/frontends/src/primitivus/xmlui.py	Tue Feb 04 18:19:29 2014 +0100
@@ -103,25 +103,31 @@
         return [option.value for option in self.getSelectedValues()]
 
 
-class PrimitivusPairsContainer(xmlui.PairsContainer, urwid.WidgetWrap):
+class PrimitivusAdvancedListContainer(xmlui.AdvancedListContainer, sat_widgets.TableContainer):
 
-    def __init__(self, parent, weight_0='1', weight_1='1'):
-        self.idx = 0
-        self.weight_0 = weight_0
-        self.weight_1 = weight_1
-        columns = urwid.Columns([urwid.Text(''), urwid.Text('')])
-        #XXX: empty Text hack needed because Pile doesn't support empty list
-        urwid.WidgetWrap.__init__(self,columns)
+    def __init__(self, parent, columns):
+        options = {'ADAPT':(), 'HIGHLIGHT':()}
+        sat_widgets.TableContainer.__init__(self, columns=columns, options=options)
 
     def _xmluiAppend(self, widget):
-        pile = self._w.widget_list[self.idx]
-        if isinstance(pile, urwid.Text):
-            self._w.widget_list[self.idx] = urwid.Pile([widget])
-            if self.idx == 1:
-                self._w.set_focus(1)
-        else:
-            pile.contents.append((widget,('weight',getattr(self,'weight_'+str(self.idx)))))
-        self.idx = (self.idx + 1) % 2
+        self.addWidget(widget)
+
+    def _xmluiAddRow(self):
+        pass
+
+class PrimitivusPairsContainer(xmlui.PairsContainer, sat_widgets.TableContainer):
+
+    def __init__(self, parent):
+        options = {'ADAPT':(0,), 'HIGHLIGHT':(0,)}
+        if self._xmlui_main.type == 'param':
+            options['FOCUS_ATTR'] = 'param_selected'
+        sat_widgets.TableContainer.__init__(self, columns=2, options=options)
+
+    def _xmluiAppend(self, widget):
+        if isinstance(widget, PrimitivusEmptyWidget):
+            # we don't want highlight on empty widgets
+            widget = urwid.AttrMap(widget, 'default')
+        self.addWidget(widget)
 
 
 class PrimitivusTabsContainer(xmlui.TabsContainer, sat_widgets.TabsContainer):
@@ -153,13 +159,15 @@
 
     def __getattr__(self, attr):
         if attr.startswith("create"):
-            return globals()["Primitivus" + attr[6:]] # XXX: we prefix with "Primitivus" to work around an Urwid bug, WidgetMeta in Urwid don't manage multiple inheritance with same names
-
+            cls = globals()["Primitivus" + attr[6:]] # XXX: we prefix with "Primitivus" to work around an Urwid bug, WidgetMeta in Urwid don't manage multiple inheritance with same names
+            cls._xmlui_main = self._xmlui_main
+            return cls
 
 class XMLUI(xmlui.XMLUI, urwid.WidgetWrap):
     widget_factory = WidgetFactory()
 
     def __init__(self, host, xml_data, title = None, flags = None):
+        self.widget_factory._xmlui_main = self
         self._dest = "window"
         xmlui.XMLUI.__init__(self, host, xml_data, title, flags)
         urwid.WidgetWrap.__init__(self, self.main_cont)
--- a/frontends/src/tools/xmlui.py	Tue Feb 04 18:19:00 2014 +0100
+++ b/frontends/src/tools/xmlui.py	Tue Feb 04 18:19:29 2014 +0100
@@ -120,6 +120,10 @@
     pass
 
 
+class AdvancedListContainer(Container):
+    """ Widgets are disposed in rows with advaned features """
+    pass
+
 class XMLUI(object):
     """ Base class to construct SàT XML User Interface
     New frontends can inherite this class to easily implement XMLUI
@@ -178,7 +182,7 @@
         """
         for node in current_node.childNodes:
             if wanted and not node.nodeName in wanted:
-                raise InvalidXMLUI
+                raise InvalidXMLUI('Unexpected node: [%s]' % node.nodeName)
 
             if node.nodeName == "container":
                 type_ = node.getAttribute('type')
@@ -195,6 +199,13 @@
                 elif type_ == "pairs":
                     cont = self.widget_factory.createPairsContainer(parent)
                     self._parseChilds(cont, node, ('widget', 'container'))
+                elif type_ == "advanced_list":
+                    try:
+                        columns = int(node.getAttribute('columns'))
+                    except (TypeError, ValueError):
+                        raise DataError("Invalid columns")
+                    cont = self.widget_factory.createAdvancedListContainer(parent, columns)
+                    self._parseChilds(cont, node, ('row',))
                 else:
                     warning(_("Unknown container [%s], using default one") % type_)
                     cont = self.widget_factory.createVerticalContainer(parent)
@@ -207,7 +218,7 @@
                     else:
                         raise Exception(_("Internal Error, container has not _xmluiAppend method"))
 
-            elif node.nodeName == "tab":
+            elif node.nodeName == 'tab':
                 name = node.getAttribute('name')
                 label = node.getAttribute('label')
                 if not name or not isinstance(data, TabsContainer):
@@ -218,6 +229,10 @@
                 new_tab = tab_cont._xmluiAddTab(label or name)
                 self._parseChilds(new_tab, node, ('widget', 'container'))
 
+            elif node.nodeName == 'row':
+                parent._xmluiAddRow()
+                self._parseChilds(parent, node, ('widget', 'container'))
+
             elif node.nodeName == "widget":
                 id_ = node.getAttribute("id")
                 name = node.getAttribute("name")
--- a/frontends/src/wix/xmlui.py	Tue Feb 04 18:19:00 2014 +0100
+++ b/frontends/src/wix/xmlui.py	Tue Feb 04 18:19:29 2014 +0100
@@ -138,9 +138,20 @@
         self.sizer.Add(widget, self._xmlui_proportion, flag=wx.EXPAND)
 
 
+class AdvancedListContainer(WixContainer, xmlui.AdvancedListContainer, wx.Panel):
+
+    def __init__(self, parent, columns):
+        wx.Panel.__init__(self, parent)
+        self.sizer = wx.FlexGridSizer(cols=columns)
+        self.SetSizer(self.sizer)
+
+    def _xmluiAddRow(self):
+        pass
+
+
 class PairsContainer(WixContainer, xmlui.PairsContainer, wx.Panel):
 
-    def __init__(self, parent, weight_0='1', weight_1='1'):
+    def __init__(self, parent):
         wx.Panel.__init__(self, parent)
         self.sizer = wx.FlexGridSizer(cols=2)
         self.sizer.AddGrowableCol(1) #The growable column need most of time to be the right one in pairs
--- a/src/tools/xml_tools.py	Tue Feb 04 18:19:00 2014 +0100
+++ b/src/tools/xml_tools.py	Tue Feb 04 18:19:29 2014 +0100
@@ -92,10 +92,10 @@
 
     return form_ui
 
-def dataFormResult2AdvancedList(form_ui, form_xml):
+def dataFormResult2AdvancedList(xmlui, form_xml):
     """Take a raw data form (not parsed by XEP-0004) and convert it to an advanced list
     raw data form is used because Wokkel doesn't manage result items parsing yet
-    @param form_ui: the XMLUI where the AdvancedList will be added
+    @param xmlui: the XMLUI where the AdvancedList will be added
     @param form_xml: domish.Element of the data form
     @return: AdvancedList element
     """
@@ -116,8 +116,8 @@
     if not headers:
         raise exceptions.DataError("No reported fields (see XEP-0004 §3.4)")
 
-    adv_list = AdvancedListContainer(form_ui, headers=headers, columns=len(headers), parent=form_ui.current_container)
-    form_ui.changeContainer(adv_list)
+    adv_list = AdvancedListContainer(xmlui, headers=headers, columns=len(headers), parent=xmlui.current_container)
+    xmlui.changeContainer(adv_list)
 
     item_elts = form_xml.elements('jabber:x:data', 'item')
 
@@ -129,9 +129,9 @@
             field = data_form.Field.fromElement(elt)
 
             widget_type, widget_args, widget_kwargs = _dataFormField2XMLUIData(field)
-            form_ui.addWidget(widget_type, *widget_args, **widget_kwargs)
+            xmlui.addWidget(widget_type, *widget_args, **widget_kwargs)
 
-    return form_ui
+    return xmlui
 
 def dataFormResult2XMLUI(form_xml, session_id=None):
     """Take a raw data form (not parsed by XEP-0004) and convert it to a SàT XMLUI
@@ -140,9 +140,9 @@
     @return: XMLUI interface
     """
 
-    form_ui = XMLUI("window", "vertical", session_id=session_id)
-    dataFormResult2AdvancedList(form_ui, form_xml)
-    return form_ui
+    xmlui = XMLUI("window", "vertical", session_id=session_id)
+    dataFormResult2AdvancedList(xmlui, form_xml)
+    return xmlui
 
 def XMLUIResult2DataFormResult(xmlui_data):
     """ Extract form data from a XMLUI return
@@ -202,6 +202,7 @@
 
             if type_ == "button":
                 param_ui.addEmpty()
+                value = param_label
             else:
                 param_ui.addLabel(param_label or param_name)
 
@@ -249,8 +250,7 @@
         self.xmlui = xmlui
         if parent is not None:
             parent.append(self)
-        else:
-            self.parent = parent
+        self.parent = parent
 
     def append(self, child):
         self.elem.appendChild(child.elem)
@@ -409,7 +409,7 @@
         if columns is None:
             columns = len(items[0])
         self._columns = columns
-        self._current_column = 0
+        self._item_idx = 0
         self.current_row = None
         if headers:
             if len(headers) != self._columns:
@@ -417,6 +417,7 @@
             self.addHeaders(headers)
         if items:
             self.addItems(items)
+        self.elem.setAttribute('columns', str(self._columns))
 
     def addHeaders(self, headers):
         for header in headers:
@@ -427,12 +428,15 @@
 
     def addItems(self, items):
         for item in items:
-            self.addItem(item)
+            self.append(item)
 
-    def addItem(self, item):
-        if self._current_column % self._columns == 0:
+    def append(self, child):
+        if isinstance(child, RowElement):
+            return super(AdvancedListContainer, self).append(child)
+        if self._item_idx % self._columns == 0:
             self.current_row = RowElement(self)
-        self.current_row.append(item)
+        self.current_row.append(child)
+        self._item_idx += 1
 
     def end(self):
         """ Called when we have finished list