# HG changeset patch # User Goffi # Date 1509120418 -7200 # Node ID 3ff9d7a7fe7113d2d8db8c91acec6dd023b71d33 # Parent 7fff98d64ab5f1008ba85608cdc6c36b731e356c 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. diff -r 7fff98d64ab5 -r 3ff9d7a7fe71 src/plugins/plugin_exp_pubsub_schema.py --- a/src/plugins/plugin_exp_pubsub_schema.py Fri Oct 27 18:03:35 2017 +0200 +++ b/src/plugins/plugin_exp_pubsub_schema.py Fri Oct 27 18:06:58 2017 +0200 @@ -199,24 +199,27 @@ def _getDataFormItems(self, form_ns='', service='', node='', schema='', max_items=10, item_ids=None, sub_id=None, extra_dict=None, profile_key=C.PROF_KEY_NONE): client = self.host.getClient(profile_key) service = jid.JID(service) if service else None + if not node: + raise exceptions.DataError(_(u'empty node is not allowed')) if schema: schema = generic.parseXml(schema.encode('utf-8')) else: schema = None max_items = None if max_items == C.NO_LIMIT else max_items extra = self._p.parseExtra(extra_dict) - d = self.getDataFormItems(client, form_ns or None, service, node or None, schema, max_items or None, item_ids, sub_id or None, extra.rsm_request, extra.extra) + d = self.getDataFormItems(client, form_ns or None, service, node, schema, max_items or None, item_ids, sub_id or None, extra.rsm_request, extra.extra) d.addCallback(self._p.serItemsData) return d @defer.inlineCallbacks - def getDataFormItems(self, client, form_ns, service, nodeIdentifier, schema=None, max_items=None, item_ids=None, sub_id=None, rsm_request=None, extra=None): + def getDataFormItems(self, client, form_ns, service, nodeIdentifier, schema=None, max_items=None, item_ids=None, sub_id=None, rsm_request=None, extra=None, filters=None): """Get items known as being data forms, and convert them to XMLUI @param form_ns (unicode, None): namespace of the form None to accept everything, even if form has no namespace @param schema(domish.Element, data_form.Form, None): schema of the node if known if None, it will be retrieved from node + @param filters(dict, None): same as for xml_tools.dataFormResult2XMLUI other parameters as the same as for [getItems] @return (list[unicode]): XMLUI of the forms if an item is invalid (not corresponding to form_ns or not a data_form) @@ -235,7 +238,8 @@ xmlui = xml_tools.dataFormResult2XMLUI( form, schema_form, - prepend = (('label', 'id'),('text', item_elt['id'], u'id')) + prepend = (('label', 'id'),('text', item_elt['id'], u'id')), + filters = filters, ) items_xmlui.append(xmlui) break diff -r 7fff98d64ab5 -r 3ff9d7a7fe71 src/tools/xml_tools.py --- 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 """