comparison 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
comparison
equal deleted inserted replaced
2397:7fff98d64ab5 2398:3ff9d7a7fe71
100 widget_kwargs["name"] = field.var 100 widget_kwargs["name"] = field.var
101 101
102 return widget_type, widget_args, widget_kwargs 102 return widget_type, widget_args, widget_kwargs
103 103
104 104
105 def dataForm2Widgets(form_ui, form, read_only=False, prepend=None): 105 def dataForm2Widgets(form_ui, form, read_only=False, prepend=None, filters=None):
106 """Complete an existing XMLUI with widget converted from XEP-0004 data forms. 106 """Complete an existing XMLUI with widget converted from XEP-0004 data forms.
107 107
108 @param form_ui (XMLUI): XMLUI instance 108 @param form_ui (XMLUI): XMLUI instance
109 @param form (data_form.Form): Wokkel's implementation of data form 109 @param form (data_form.Form): Wokkel's implementation of data form
110 @param read_only (bool): if True and it makes sense, create a read only input widget 110 @param read_only (bool): if True and it makes sense, create a read only input widget
111 @param prepend(iterable, None): widgets to prepend to main LabelContainer 111 @param prepend(iterable, None): widgets to prepend to main LabelContainer
112 if not None, must be an iterable of *args for addWidget. Those widgets will 112 if not None, must be an iterable of *args for addWidget. Those widgets will
113 be added first to the container. 113 be added first to the container.
114 @param filters(dict, None): if not None, a dictionary of callable:
115 key is the name of the widget to filter
116 the value is a callable, it will get widget's type, args and kwargs
117 and must return the same variable, which it can modify
118 This is especially useful to modify well known fields
114 @return: the completed XMLUI instance 119 @return: the completed XMLUI instance
115 """ 120 """
116 if form.instructions: 121 if form.instructions:
117 form_ui.addText('\n'.join(form.instructions), 'instructions') 122 form_ui.addText('\n'.join(form.instructions), 'instructions')
118 123
122 for widget_args in prepend: 127 for widget_args in prepend:
123 form_ui.addWidget(*widget_args) 128 form_ui.addWidget(*widget_args)
124 129
125 for field in form.fieldList: 130 for field in form.fieldList:
126 widget_type, widget_args, widget_kwargs = _dataFormField2XMLUIData(field, read_only) 131 widget_type, widget_args, widget_kwargs = _dataFormField2XMLUIData(field, read_only)
132 try:
133 widget_filter = filters[widget_kwargs['name']]
134 except KeyError:
135 pass
136 else:
137 widget_type, widget_args, widget_kwargs = widget_filter(widget_type, widget_args, widget_kwargs)
127 label = field.label or field.var 138 label = field.label or field.var
128 if label: 139 if label:
129 form_ui.addLabel(label) 140 form_ui.addLabel(label)
130 else: 141 else:
131 form_ui.addEmpty() 142 form_ui.addEmpty()
233 except exceptions.DataError: 244 except exceptions.DataError:
234 parsed_form = data_form.Form.fromElement(form_elt) 245 parsed_form = data_form.Form.fromElement(form_elt)
235 dataForm2Widgets(xml_ui, parsed_form, read_only=True) 246 dataForm2Widgets(xml_ui, parsed_form, read_only=True)
236 return xml_ui 247 return xml_ui
237 248
238 def dataFormResult2XMLUI(result_form, base_form, session_id=None, prepend=None): 249 def dataFormResult2XMLUI(result_form, base_form, session_id=None, prepend=None, filters=None):
239 """Convert data form result to SàT XMLUI. 250 """Convert data form result to SàT XMLUI.
240 251
241 @param result_form (data_form.Form): result form to convert 252 @param result_form (data_form.Form): result form to convert
242 @param base_form (data_form.Form): initial form (i.e. of form type "form") 253 @param base_form (data_form.Form): initial form (i.e. of form type "form")
243 this one is necessary to reconstruct options when needed (e.g. list elements) 254 this one is necessary to reconstruct options when needed (e.g. list elements)
244 @param session_id (unicode): session id to return with the data 255 @param session_id (unicode): session id to return with the data
245 @param prepend: same as for [dataForm2Widgets] 256 @param prepend: same as for [dataForm2Widgets]
257 @param filters: same as for [dataForm2Widgets]
246 @return: XMLUI instance 258 @return: XMLUI instance
247 """ 259 """
248 form = deepcopy(result_form) 260 form = deepcopy(result_form)
249 for name, field in form.fields.iteritems(): 261 for name, field in form.fields.iteritems():
250 try: 262 try:
251 base_field = base_form.fields[name] 263 base_field = base_form.fields[name]
252 except KeyError: 264 except KeyError:
253 continue 265 continue
254 field.options = base_field.options[:] 266 field.options = base_field.options[:]
255 xml_ui = XMLUI("window", "vertical", session_id=session_id) 267 xml_ui = XMLUI("window", "vertical", session_id=session_id)
256 dataForm2Widgets(xml_ui, form, read_only=True, prepend=prepend) 268 dataForm2Widgets(xml_ui, form, read_only=True, prepend=prepend, filters=filters)
257 return xml_ui 269 return xml_ui
258 270
259 271
260 def _cleanValue(value): 272 def _cleanValue(value):
261 """Workaround method to avoid DBus types with D-Bus bridge. 273 """Workaround method to avoid DBus types with D-Bus bridge.
758 """ 770 """
759 self.elem = xmlui.doc.createElement('widget') 771 self.elem = xmlui.doc.createElement('widget')
760 super(Widget, self).__init__(xmlui, parent) 772 super(Widget, self).__init__(xmlui, parent)
761 if name: 773 if name:
762 self.elem.setAttribute('name', name) 774 self.elem.setAttribute('name', name)
775 if name in xmlui.named_widgets:
776 raise exceptions.ConflictError(_(u'A widget with the name "{name}" already exists.').format(name=name))
777 xmlui.named_widgets[name] = self
763 self.elem.setAttribute('type', self.type) 778 self.elem.setAttribute('type', self.type)
764 779
765 def setInternalCallback(self, callback, fields, data_elts=None): 780 def setInternalCallback(self, callback, fields, data_elts=None):
766 """Set an internal UI callback when the widget value is changed. 781 """Set an internal UI callback when the widget value is changed.
767 782
1126 - C.XMLUI_DATA_FILETYPE_DEFAULT: same as C.XMLUI_DATA_FILETYPE_FILE 1141 - C.XMLUI_DATA_FILETYPE_DEFAULT: same as C.XMLUI_DATA_FILETYPE_FILE
1127 1142
1128 @param title: title or default if None 1143 @param title: title or default if None
1129 @param submit_id: callback id to call for panel_type we can submit (form, param, dialog) 1144 @param submit_id: callback id to call for panel_type we can submit (form, param, dialog)
1130 @param session_id: use to keep a session attached to the dialog, must be returned by frontends 1145 @param session_id: use to keep a session attached to the dialog, must be returned by frontends
1146 @attribute named_widgets(dict): map from name to widget
1131 """ 1147 """
1132 self._introspect() # FIXME: why doing that on each XMLUI ? should be done once 1148 self._introspect() # FIXME: why doing that on each XMLUI ? should be done once
1133 if panel_type not in [C.XMLUI_WINDOW, C.XMLUI_FORM, C.XMLUI_PARAM, C.XMLUI_POPUP, C.XMLUI_DIALOG]: 1149 if panel_type not in [C.XMLUI_WINDOW, C.XMLUI_FORM, C.XMLUI_PARAM, C.XMLUI_POPUP, C.XMLUI_DIALOG]:
1134 raise exceptions.DataError(_("Unknown panel type [%s]") % panel_type) 1150 raise exceptions.DataError(_("Unknown panel type [%s]") % panel_type)
1135 if panel_type == C.XMLUI_FORM and submit_id is None: 1151 if panel_type == C.XMLUI_FORM and submit_id is None:
1153 dialog_opt = {} 1169 dialog_opt = {}
1154 self._createDialog(dialog_opt) 1170 self._createDialog(dialog_opt)
1155 return 1171 return
1156 self.main_container = self._createContainer(container, TopElement(self)) 1172 self.main_container = self._createContainer(container, TopElement(self))
1157 self.current_container = self.main_container 1173 self.current_container = self.main_container
1174 self.named_widgets = {}
1158 1175
1159 def _introspect(self): 1176 def _introspect(self):
1160 """ Introspect module to find Widgets and Containers """ 1177 """ Introspect module to find Widgets and Containers """
1161 self._containers = {} 1178 self._containers = {}
1162 self._widgets = {} 1179 self._widgets = {}