Mercurial > libervia-backend
comparison src/tools/xml_tools.py @ 1476:48706f4ff19c
core (xmlui): added JidsListWidget to manage editable list of jids:
- can be used to manage XEP-0004's jid-multi
- can be used in the future for search result to display found entities (need a read-only style)
- generaly usefull to manage list of entites
- implemented in params too
author | Goffi <goffi@goffi.org> |
---|---|
date | Thu, 20 Aug 2015 18:33:52 +0200 |
parents | 7ac073d2e7e0 |
children | a77217511afd |
comparison
equal
deleted
inserted
replaced
1475:7ac073d2e7e0 | 1476:48706f4ff19c |
---|---|
23 log = getLogger(__name__) | 23 log = getLogger(__name__) |
24 | 24 |
25 from xml.dom import minidom, NotFoundErr | 25 from xml.dom import minidom, NotFoundErr |
26 from wokkel import data_form | 26 from wokkel import data_form |
27 from twisted.words.xish import domish | 27 from twisted.words.xish import domish |
28 from twisted.words.protocols.jabber import jid | |
28 from sat.core import exceptions | 29 from sat.core import exceptions |
29 | 30 |
30 | 31 |
31 """This library help manage XML used in SàT (parameters, registration, etc)""" | 32 """This library help manage XML used in SàT (parameters, registration, etc)""" |
32 | 33 |
252 """Convert the XML for parameter to a SàT XML User Interface. | 253 """Convert the XML for parameter to a SàT XML User Interface. |
253 | 254 |
254 @param xml (unicode) | 255 @param xml (unicode) |
255 @return: XMLUI | 256 @return: XMLUI |
256 """ | 257 """ |
258 # TODO: refactor params and use Twisted directly to parse XML | |
257 params_doc = minidom.parseString(xml.encode('utf-8')) | 259 params_doc = minidom.parseString(xml.encode('utf-8')) |
258 top = params_doc.documentElement | 260 top = params_doc.documentElement |
259 if top.nodeName != 'params': | 261 if top.nodeName != 'params': |
260 raise exceptions.DataError(_('INTERNAL ERROR: parameters xml not valid')) | 262 raise exceptions.DataError(_('INTERNAL ERROR: parameters xml not valid')) |
261 | 263 |
279 | 281 |
280 value = param.getAttribute('value') or None | 282 value = param.getAttribute('value') or None |
281 callback_id = param.getAttribute('callback_id') or None | 283 callback_id = param.getAttribute('callback_id') or None |
282 | 284 |
283 if type_ == 'list': | 285 if type_ == 'list': |
284 options, selected = _getParamListOptions(param) | 286 options, selected = _paramsGetListOptions(param) |
285 widget_kwargs['options'] = options | 287 widget_kwargs['options'] = options |
286 widget_kwargs['selected'] = selected | 288 widget_kwargs['selected'] = selected |
289 elif type_ == 'jids_list': | |
290 widget_kwargs['jids'] = _paramsGetListJids(param) | |
287 | 291 |
288 if type_ in ("button", "text"): | 292 if type_ in ("button", "text"): |
289 param_ui.addEmpty() | 293 param_ui.addEmpty() |
290 value = param_label | 294 value = param_label |
291 else: | 295 else: |
306 param_ui.addWidget(type_, **widget_kwargs) | 310 param_ui.addWidget(type_, **widget_kwargs) |
307 | 311 |
308 return param_ui.toXml() | 312 return param_ui.toXml() |
309 | 313 |
310 | 314 |
311 def _getParamListOptions(param): | 315 def _paramsGetListOptions(param): |
312 """Retrieve the options for list element. | 316 """Retrieve the options for list element. |
313 | 317 |
314 The <option/> tags must be direct children of <param/>. | 318 The <option/> tags must be direct children of <param/>. |
315 @param param (domish.Element): element | 319 @param param (domish.Element): element |
316 @return: a tuple (options, selected_value) | 320 @return: a tuple (options, selected_value) |
322 return [] | 326 return [] |
323 options = [elem.getAttribute("value") for elem in elems] | 327 options = [elem.getAttribute("value") for elem in elems] |
324 selected = [elem.getAttribute("value") for elem in elems if elem.getAttribute("selected") == 'true'] | 328 selected = [elem.getAttribute("value") for elem in elems if elem.getAttribute("selected") == 'true'] |
325 return (options, selected) | 329 return (options, selected) |
326 | 330 |
327 | 331 def _paramsGetListJids(param): |
328 ## XMLUI Elements | 332 """Retrive jids from a jids_list element. |
333 | |
334 the <jid/> tags must be direct children of <param/> | |
335 @param param (domish.Element): element | |
336 @return: a list of jids | |
337 """ | |
338 elems = param.getElementsByTagName("jid") | |
339 jids = [elem.firstChild.data for elem in elems | |
340 if elem.firstChild is not None | |
341 and elem.firstChild.nodeType == elem.TEXT_NODE] | |
342 return jids | |
343 | |
344 | |
345 ### XMLUI Elements ### | |
329 | 346 |
330 | 347 |
331 class Element(object): | 348 class Element(object): |
332 """ Base XMLUI element """ | 349 """ Base XMLUI element """ |
333 type = None | 350 type = None |
425 self.elem.setAttribute('label', label) | 442 self.elem.setAttribute('label', label) |
426 if selected: | 443 if selected: |
427 self.elem.setAttribute('selected', 'true') | 444 self.elem.setAttribute('selected', 'true') |
428 | 445 |
429 | 446 |
447 class JidElement(Element): | |
448 """" Used by JidsListWidget to specify jids""" | |
449 type = 'jid' | |
450 | |
451 def __init__(self, parent, jid_): | |
452 """ | |
453 @param jid_(jid.JID, unicode): jid to append | |
454 """ | |
455 assert isinstance(parent, JidsListWidget) | |
456 super(JidElement, self).__init__(parent.xmlui, parent) | |
457 if isinstance(jid_, jid.JID): | |
458 value = jid.full | |
459 elif isinstance(jid_, basestring): | |
460 value = unicode(jid_) | |
461 else: | |
462 raise NotImplementedError | |
463 jid_txt = self.xmlui.doc.createTextNode(value) | |
464 self.elem.appendChild(jid_txt) | |
465 | |
466 | |
430 class RowElement(Element): | 467 class RowElement(Element): |
431 """" Used by AdvancedListContainer """ | 468 """" Used by AdvancedListContainer """ |
432 type = 'row' | 469 type = 'row' |
433 | 470 |
434 def __init__(self, parent): | 471 def __init__(self, parent): |
458 self.elem.setAttribute('name', name) | 495 self.elem.setAttribute('name', name) |
459 if label: | 496 if label: |
460 self.elem.setAttribute('label', label) | 497 self.elem.setAttribute('label', label) |
461 if description: | 498 if description: |
462 self.elem.setAttribute('description', description) | 499 self.elem.setAttribute('description', description) |
500 | |
501 | |
502 ## Containers ## | |
463 | 503 |
464 | 504 |
465 class Container(Element): | 505 class Container(Element): |
466 """ And Element which contains other ones and has a layout """ | 506 """ And Element which contains other ones and has a layout """ |
467 type = None | 507 type = None |
601 raise exceptions.DataError(_("Incorrect number of items in list")) | 641 raise exceptions.DataError(_("Incorrect number of items in list")) |
602 parent_container = self.getParentContainer() | 642 parent_container = self.getParentContainer() |
603 self.xmlui.changeContainer(parent_container) | 643 self.xmlui.changeContainer(parent_container) |
604 | 644 |
605 | 645 |
646 ## Widgets ## | |
647 | |
648 | |
606 class Widget(Element): | 649 class Widget(Element): |
607 type = None | 650 type = None |
608 | 651 |
609 def __init__(self, xmlui, name=None, parent=None): | 652 def __init__(self, xmlui, name=None, parent=None): |
610 """Create an element | 653 """Create an element |
796 | 839 |
797 | 840 |
798 class ListWidget(InputWidget): | 841 class ListWidget(InputWidget): |
799 type = 'list' | 842 type = 'list' |
800 | 843 |
801 def __init__(self, xmlui, options, selected=None, style=None, name=None, parent=None): | 844 def __init__(self, xmlui, options, selected=None, styles=None, name=None, parent=None): |
802 """ | 845 """ |
803 | 846 |
804 @param xmlui | 847 @param xmlui |
805 @param options (list[option]): each option can be given as: | 848 @param options (list[option]): each option can be given as: |
806 - a single string if the label and the value are the same | 849 - a single string if the label and the value are the same |
807 - a tuple with a couple of string (value,label) if the label and the value differ | 850 - a tuple with a couple of string (value,label) if the label and the value differ |
808 @param selected (list[string]): list of the selected values | 851 @param selected (list[string]): list of the selected values |
809 @param style (string) | 852 @param styles (iterable[string]): flags to set the behaviour of the list |
810 @param name (string) | 853 @param name (string) |
811 @param parent | 854 @param parent |
812 """ | 855 """ |
813 if style is None: | 856 styles = set() if styles is None else set(styles) |
814 style = set() | 857 if styles is None: |
815 styles = set(style) | 858 styles = set() |
859 else: | |
860 styles = set(styles) | |
816 if not options: | 861 if not options: |
817 log.warning(_('empty "options" list')) | 862 log.warning(_('empty "options" list')) |
818 if not styles.issubset(['multi']): | 863 if not styles.issubset(['multi']): |
819 raise exceptions.DataError(_("invalid styles")) | 864 raise exceptions.DataError(_("invalid styles")) |
820 super(ListWidget, self).__init__(xmlui, name, parent) | 865 super(ListWidget, self).__init__(xmlui, name, parent) |
831 selected = [] | 876 selected = [] |
832 for option in options: | 877 for option in options: |
833 assert isinstance(option, basestring) or isinstance(option, tuple) | 878 assert isinstance(option, basestring) or isinstance(option, tuple) |
834 value = option if isinstance(option, basestring) else option[0] | 879 value = option if isinstance(option, basestring) else option[0] |
835 OptionElement(self, option, value in selected) | 880 OptionElement(self, option, value in selected) |
881 | |
882 class JidsListWidget(InputWidget): | |
883 """A list of text or jids where elements can be added/removed or modified""" | |
884 type = 'jids_list' | |
885 | |
886 def __init__(self, xmlui, jids, styles=None, name=None, parent=None): | |
887 """ | |
888 | |
889 @param xmlui | |
890 @param jids (list[jid.JID]): base jids | |
891 @param styles (iterable[string]): flags to set the behaviour of the list | |
892 @param name (string) | |
893 @param parent | |
894 """ | |
895 super(JidsListWidget, self).__init__(xmlui, name, parent) | |
896 styles = set() if styles is None else set(styles) | |
897 if not styles.issubset([]): # TODO | |
898 raise exceptions.DataError(_("invalid styles")) | |
899 for style in styles: | |
900 self.elem.setAttribute(style, 'yes') | |
901 if not jids: | |
902 log.debug('empty jids list') | |
903 else: | |
904 self.addJids(jids) | |
905 | |
906 def addJids(self, jids): | |
907 for jid_ in jids: | |
908 JidElement(self, jid_) | |
836 | 909 |
837 | 910 |
838 ## Dialog Elements ## | 911 ## Dialog Elements ## |
839 | 912 |
840 | 913 |