diff src/tools/xml_tools.py @ 2398:3ff9d7a7fe71

core (XMLUI): filters can now be used when converting data form to XMLUI: they can be used to modify created widgets, this is specially useful to customise well known field.
author Goffi <goffi@goffi.org>
date Fri, 27 Oct 2017 18:06:58 +0200
parents 7fff98d64ab5
children f4b6176eb65f
line wrap: on
line diff
--- a/src/tools/xml_tools.py	Fri Oct 27 18:03:35 2017 +0200
+++ b/src/tools/xml_tools.py	Fri Oct 27 18:06:58 2017 +0200
@@ -102,7 +102,7 @@
     return widget_type, widget_args, widget_kwargs
 
 
-def dataForm2Widgets(form_ui, form, read_only=False, prepend=None):
+def dataForm2Widgets(form_ui, form, read_only=False, prepend=None, filters=None):
     """Complete an existing XMLUI with widget converted from XEP-0004 data forms.
 
     @param form_ui (XMLUI): XMLUI instance
@@ -111,6 +111,11 @@
     @param prepend(iterable, None): widgets to prepend to main LabelContainer
         if not None, must be an iterable of *args for addWidget. Those widgets will
         be added first to the container.
+    @param filters(dict, None): if not None, a dictionary of callable:
+        key is the name of the widget to filter
+        the value is a callable, it will get widget's type, args and kwargs
+            and must return the same variable, which it can modify
+        This is especially useful to modify well known fields
     @return: the completed XMLUI instance
     """
     if form.instructions:
@@ -124,6 +129,12 @@
 
     for field in form.fieldList:
         widget_type, widget_args, widget_kwargs = _dataFormField2XMLUIData(field, read_only)
+        try:
+            widget_filter = filters[widget_kwargs['name']]
+        except KeyError:
+            pass
+        else:
+            widget_type, widget_args, widget_kwargs = widget_filter(widget_type, widget_args, widget_kwargs)
         label = field.label or field.var
         if label:
             form_ui.addLabel(label)
@@ -235,7 +246,7 @@
         dataForm2Widgets(xml_ui, parsed_form, read_only=True)
     return xml_ui
 
-def dataFormResult2XMLUI(result_form, base_form, session_id=None, prepend=None):
+def dataFormResult2XMLUI(result_form, base_form, session_id=None, prepend=None, filters=None):
     """Convert data form result to SàT XMLUI.
 
     @param result_form (data_form.Form): result form to convert
@@ -243,6 +254,7 @@
         this one is necessary to reconstruct options when needed (e.g. list elements)
     @param session_id (unicode): session id to return with the data
     @param prepend: same as for [dataForm2Widgets]
+    @param filters: same as for [dataForm2Widgets]
     @return: XMLUI instance
     """
     form = deepcopy(result_form)
@@ -253,7 +265,7 @@
             continue
         field.options = base_field.options[:]
     xml_ui = XMLUI("window", "vertical", session_id=session_id)
-    dataForm2Widgets(xml_ui, form, read_only=True, prepend=prepend)
+    dataForm2Widgets(xml_ui, form, read_only=True, prepend=prepend, filters=filters)
     return xml_ui
 
 
@@ -760,6 +772,9 @@
         super(Widget, self).__init__(xmlui, parent)
         if name:
             self.elem.setAttribute('name', name)
+            if name in xmlui.named_widgets:
+                raise exceptions.ConflictError(_(u'A widget with the name "{name}" already exists.').format(name=name))
+            xmlui.named_widgets[name] = self
         self.elem.setAttribute('type', self.type)
 
     def setInternalCallback(self, callback, fields, data_elts=None):
@@ -1128,6 +1143,7 @@
         @param title: title or default if None
         @param submit_id: callback id to call for panel_type we can submit (form, param, dialog)
         @param session_id: use to keep a session attached to the dialog, must be returned by frontends
+        @attribute named_widgets(dict): map from name to widget
         """
         self._introspect() # FIXME: why doing that on each XMLUI ? should be done once
         if panel_type not in [C.XMLUI_WINDOW, C.XMLUI_FORM, C.XMLUI_PARAM, C.XMLUI_POPUP, C.XMLUI_DIALOG]:
@@ -1155,6 +1171,7 @@
             return
         self.main_container = self._createContainer(container, TopElement(self))
         self.current_container = self.main_container
+        self.named_widgets = {}
 
     def _introspect(self):
         """ Introspect module to find Widgets and Containers """