changeset 968:75f3b3b430ff

tools, frontends, memory: param definition and XMLUI handle multi-selection for list widgets: - we need to update urwid_satext to revision 79 - no more "value" attribute value in the "list" element, use HTML-style "select" attribute in the "option" elements instead - /!\ param saving do not handle multiple values yet!
author souliane <souliane@mailoo.org>
date Tue, 01 Apr 2014 21:21:13 +0200
parents 242bd4fc654c
children 5c7707c958d8
files frontends/src/primitivus/xmlui.py frontends/src/tools/xmlui.py frontends/src/wix/xmlui.py src/memory/params.py src/plugins/deprecated_misc_cs.py src/plugins/plugin_misc_text_syntaxes.py src/plugins/plugin_xep_0249.py src/tools/xml_tools.py
diffstat 8 files changed, 82 insertions(+), 39 deletions(-) [+]
line wrap: on
line diff
--- a/frontends/src/primitivus/xmlui.py	Tue Apr 01 16:27:59 2014 +0200
+++ b/frontends/src/primitivus/xmlui.py	Tue Apr 01 21:21:13 2014 +0200
@@ -102,13 +102,13 @@
         sat_widgets.AdvancedEdit.__init__(self, edit_text=value, multiline=True)
 
     def _xmluiGetValue(self):
-        return self.getValue()
+        return self.get_edit_text()
 
 
 class PrimitivusBoolWidget(xmlui.BoolWidget, urwid.CheckBox, PrimitivusEvents):
 
     def __init__(self, parent, state):
-        urwid.CheckBox.__init__(self, '', state = state)
+        urwid.CheckBox.__init__(self, '', state=state)
 
     def _xmluiGetValue(self):
         return "true" if self.get_state() else "false"
@@ -122,12 +122,16 @@
 
 class PrimitivusListWidget(xmlui.ListWidget, sat_widgets.List, PrimitivusEvents):
 
-    def __init__(self, parent, options, flags):
+    def __init__(self, parent, options, selected, flags):
         sat_widgets.List.__init__(self, options=options, style=flags)
+        self._xmluiSelectValues(selected)
 
     def _xmluiSelectValue(self, value):
         return self.selectValue(value)
 
+    def _xmluiSelectValues(self, values):
+        return self.selectValues(values)
+
     def _xmluiGetSelectedValues(self):
         return [option.value for option in self.getSelectedValues()]
 
--- a/frontends/src/tools/xmlui.py	Tue Apr 01 16:27:59 2014 +0200
+++ b/frontends/src/tools/xmlui.py	Tue Apr 01 21:21:13 2014 +0200
@@ -301,16 +301,16 @@
                 elif type_=="bool":
                     ctrl = self.widget_factory.createBoolWidget(parent, value=='true')
                     self.ctrl_list[name] = ({'type':type_, 'control':ctrl})
-                elif type_=="list":
-                    style=[] if node.getAttribute("multi")=='yes' else ['single']
+                elif type_ == "list":
+                    style = [] if node.getAttribute("multi") == 'yes' else ['single']
                     _options = [(option.getAttribute("value"), option.getAttribute("label")) for option in node.getElementsByTagName("option")]
-                    ctrl = self.widget_factory.createListWidget(parent, _options, style)
-                    ctrl._xmluiSelectValue(node.getAttribute("value"))
-                    self.ctrl_list[name] = ({'type':type_, 'control':ctrl})
+                    _selected = [option.getAttribute("value") for option in node.getElementsByTagName("option") if option.getAttribute('selected') == 'true']
+                    ctrl = self.widget_factory.createListWidget(parent, _options, _selected, style)
+                    self.ctrl_list[name] = ({'type': type_, 'control': ctrl})
                 elif type_=="button":
                     callback_id = node.getAttribute("callback")
                     ctrl = self.widget_factory.createButtonWidget(parent, value, self.onButtonPress)
-                    ctrl._xmlui_param_id = (callback_id,[field.getAttribute('name') for field in node.getElementsByTagName("field_back")])
+                    ctrl._xmlui_param_id = (callback_id, [field.getAttribute('name') for field in node.getElementsByTagName("field_back")])
                 else:
                     print(_("FIXME FIXME FIXME: widget type [%s] is not implemented") % type_)
                     raise NotImplementedError(_("FIXME FIXME FIXME: type [%s] is not implemented") % type_)
@@ -408,7 +408,7 @@
             escaped = self.escape(field)
             ctrl = self.ctrl_list[field]
             if isinstance(ctrl['control'], ListWidget):
-                data[escaped] = u'\t'.join(ctrl['control']._xmluiGetSelected())
+                data[escaped] = u'\t'.join(ctrl['control']._xmluiGetSelectedValues())
             else:
                 data[escaped] = ctrl['control']._xmluiGetValue()
         self._xmluiLaunchAction(callback_id, data)
--- a/frontends/src/wix/xmlui.py	Tue Apr 01 16:27:59 2014 +0200
+++ b/frontends/src/wix/xmlui.py	Tue Apr 01 21:21:13 2014 +0200
@@ -122,14 +122,16 @@
         self._xmlui_click_callback(event.GetEventObject())
         event.Skip()
 
+
 class ListWidget(EventWidget, WixWidget, xmlui.ListWidget, wx.ListBox):
     _xmlui_change_event = wx.EVT_LISTBOX
 
-    def __init__(self, parent, options, flags):
+    def __init__(self, parent, options, selected, flags):
         styles = wx.LB_MULTIPLE if not 'single' in flags else wx.LB_SINGLE
         wx.ListBox.__init__(self, parent, -1, choices=[option[1] for option in options], style=styles)
         self._xmlui_attr_map = {label: value for value, label in options}
         self._xmlui_proportion = 1
+        self._xmluiSelectValues(selected)
 
     def _xmluiSelectValue(self, value):
         try:
@@ -140,6 +142,10 @@
         for idx in xrange(self.GetCount()):
             self.SetSelection(idx, self.GetString(idx) == label)
 
+    def _xmluiSelectValues(self, values):
+        for value in values:
+            self._xmluiSelectValue(value)
+
     def _xmluiGetSelectedValues(self):
         ret = []
         labels = [self.GetString(idx) for idx in self.GetSelections()]
--- a/src/memory/params.py	Tue Apr 01 16:27:59 2014 +0200
+++ b/src/memory/params.py	Tue Apr 01 21:21:13 2014 +0200
@@ -21,7 +21,7 @@
 
 from sat.core import exceptions
 from sat.core.constants import Const as C
-from xml.dom import minidom
+from xml.dom import minidom, NotFoundErr
 from logging import debug, info, warning, error
 from twisted.internet import defer
 from twisted.python.failure import Failure
@@ -494,7 +494,17 @@
                                                         cache=profile_cache, profile=profile)
                         if profile_value is not None:
                             # there is a value for this profile, we must change the default
-                            dest_params[name].setAttribute('value', profile_value)
+                            if dest_params[name].getAttribute('type') == 'list':
+                                for option in dest_params[name].getElementsByTagName("option"):
+                                    if option.getAttribute('value') == profile_value:
+                                        option.setAttribute('selected', 'true')
+                                    else:
+                                        try:
+                                            option.removeAttribute('selected')
+                                        except NotFoundErr:
+                                            pass
+                            else:
+                                dest_params[name].setAttribute('value', profile_value)
                     if new_node:
                         prof_xml.documentElement.appendChild(dest_cat)
 
--- a/src/plugins/deprecated_misc_cs.py	Tue Apr 01 16:27:59 2014 +0200
+++ b/src/plugins/deprecated_misc_cs.py	Tue Apr 01 21:21:13 2014 +0200
@@ -163,7 +163,7 @@
         interface.addText(_("G'day %(name)s, you have %(nb_message)i unread message%(plural_mess)s and %(unread_CR_mess)s unread couch request message%(plural_CR)s\nIf you want to send a message, select the recipient(s) in the list below") % {'name': user_name, 'nb_message': unread_mess, 'plural_mess': 's' if unread_mess > 1 else '', 'unread_CR_mess': unread_CR_mess, 'plural_CR': 's' if unread_CR_mess > 1 else ''})
         if unread_mess:
             interface.addButton('plugin_CS_showUnreadMessages', 'showUnreadMessages', _('Show unread message%(plural)s in external web browser') % {'plural': 's' if unread_mess > 1 else ''})
-        interface.addList(friends_list, 'friends', style=['multi'])
+        interface.addList(friends_list, 'friends', None, style=['multi'])
         interface.changeLayout('pairs')
         interface.addLabel(_("Subject"))
         interface.addString('subject')
--- a/src/plugins/plugin_misc_text_syntaxes.py	Tue Apr 01 16:27:59 2014 +0200
+++ b/src/plugins/plugin_misc_text_syntaxes.py	Tue Apr 01 21:21:13 2014 +0200
@@ -77,8 +77,7 @@
     <params>
     <individual>
     <category name="%(category_name)s" label="%(category_label)s">
-        <param name="%(name)s" label="%(label)s"
-           value="%(default)s" type="list" security="0">
+        <param name="%(name)s" label="%(label)s" type="list" security="0">
             %(options)s
         </param>
     </category>
@@ -91,7 +90,6 @@
         'category_label': _(CATEGORY),
         'name': NAME,
         'label': _(NAME),
-        'default': _SYNTAX_XHTML,
         'syntaxes': {},
         }
 
@@ -128,7 +126,8 @@
         options = []
 
         for syntax in syntaxes:
-            options.append(u'<option value="%s" />' % syntax)
+            selected = 'selected="true"' if syntax == _SYNTAX_XHTML else ''
+            options.append(u'<option value="%s" %s/>' % (syntax, selected))
 
         TextSyntaxes.params_data["options"] = u'\n'.join(options)
         self.host.memory.updateParams(TextSyntaxes.params % TextSyntaxes.params_data)
--- a/src/plugins/plugin_xep_0249.py	Tue Apr 01 16:27:59 2014 +0200
+++ b/src/plugins/plugin_xep_0249.py	Tue Apr 01 21:21:13 2014 +0200
@@ -59,7 +59,7 @@
     <params>
     <individual>
     <category name="%(category_name)s" label="%(category_label)s">
-        <param name="%(param_name)s" label="%(param_label)s" value="%(param_default)s" type="list" security="0">
+        <param name="%(param_name)s" label="%(param_label)s" type="list" security="0">
             %(param_options)s
         </param>
      </category>
@@ -70,8 +70,9 @@
         'category_label': _("Misc"),
         'param_name': AUTOJOIN_NAME,
         'param_label': _("Auto-join MUC on invitation"),
-        'param_default': AUTOJOIN_VALUES[0],
-        'param_options': ['<option value="%s"/>' % value for value in AUTOJOIN_VALUES]
+        'param_options': '\n'.join(['<option value="%s" %s/>' % \
+                                   (value, 'selected="true"' if value == AUTOJOIN_VALUES[0] else '') \
+                                   for value in AUTOJOIN_VALUES])
     }
 
     def __init__(self, host):
--- a/src/tools/xml_tools.py	Tue Apr 01 16:27:59 2014 +0200
+++ b/src/tools/xml_tools.py	Tue Apr 01 21:21:13 2014 +0200
@@ -207,8 +207,9 @@
             callback_id = param.getAttribute('callback_id') or None
 
             if type_ == 'list':
-                options = _getParamListOptions(param)
+                options, selected = _getParamListOptions(param)
                 widget_kwargs['options'] = options
+                widget_kwargs['selected'] = selected
 
             if type_ in ("button", "text"):
                 param_ui.addEmpty()
@@ -230,16 +231,16 @@
 
 
 def _getParamListOptions(param):
-    """Retrieve the options for list element. Allow listing the <option/>
-    tags directly in <param/> or in an intermediate <options/> tag."""
-    elems = param.getElementsByTagName("options")
-    if len(elems) == 0:
-        elems = param.getElementsByTagName("option")
-    else:
-        elems = elems.item(0).getElementsByTagName("option")
+    """Retrieve the options for list element. The <option/> tags
+    must be direct children of <param/>."""
+    if len(param.getElementsByTagName("options")) > 0:
+        raise exceptions.DataError(_("The 'options' tag is not allowed in parameter of type 'list'!"))
+    elems = param.getElementsByTagName("option")
     if len(elems) == 0:
         return []
-    return [elem.getAttribute("value") for elem in elems]
+    options = [elem.getAttribute("value") for elem in elems]
+    selected = [elem.getAttribute("value") for elem in elems if elem.getAttribute("selected") == 'true']
+    return  (options, selected)
 
 
 ## XMLUI Elements
@@ -302,7 +303,13 @@
     """" Used by ListWidget to specify options """
     type = 'option'
 
-    def __init__(self, parent, option):
+    def __init__(self, parent, option, selected=False):
+        """
+
+        @param parent
+        @param option (string, tuple)
+        @param selected (boolean)
+        """
         assert(isinstance(parent, ListWidget))
         super(OptionElement, self).__init__(parent.xmlui, parent)
         if isinstance(option, basestring):
@@ -311,6 +318,8 @@
             value, label = option
         self.elem.setAttribute('value', value)
         self.elem.setAttribute('label', label)
+        if selected:
+            self.elem.setAttribute('selected', 'true')
 
 
 class RowElement(Element):
@@ -609,13 +618,24 @@
         if value:
             self.elem.setAttribute('value', value)
         for field in fields_back:
-            fback_el = FieldBackElement(self, field)
+            FieldBackElement(self, field)
 
 
 class ListWidget(InputWidget):
     type = 'list'
 
-    def __init__(self, xmlui, options, value=None, style=None, name=None, parent=None):
+    def __init__(self, xmlui, options, selected=None, style=None, name=None, parent=None):
+        """
+
+        @param xmlui
+        @param options (list[string, tuple]): each option can be given as:
+                                              - a string if the label and the value are the same
+                                              - a couple if the label and the value differ
+        @param selected (list[string]): list of the selected values
+        @param style (string)
+        @param name (string)
+        @param parent
+        """
         if style is None:
             style = set()
         styles = set(style)
@@ -624,16 +644,19 @@
         if not styles.issubset(['multi']):
             raise exceptions.DataError(_("invalid styles"))
         super(ListWidget, self).__init__(xmlui, name, parent)
-        self.addOptions(options)
-        if value:
-            self.elem.setAttribute('value', value)
+        self.addOptions(options, selected)
         for style in styles:
             self.elem.setAttribute(style, 'yes')
 
-    def addOptions(self, options):
-        """i Add options to a multi-values element (e.g. list) """
+    def addOptions(self, options, selected=None):
+        """Add options to a multi-values element (e.g. list) """
+        if selected:
+            if isinstance(selected, basestring):
+                selected = [selected]
+        else:
+            selected = []
         for option in options:
-            OptionElement(self, option)
+            OptionElement(self, option, option in selected)
 
 
 ## XMLUI main class