Mercurial > libervia-backend
view src/tools/xml_tools.py @ 297:c5554e2939dd
plugin XEP 0277: author for in request + author, updated management for out request
- a workaround is now used to parse "nick" tag (Jappix behaviour)
- author and updated can now be used in data when sendind microblog. Is no author is given, user jid is used, if no updated is given, current timestamp is used
author | Goffi <goffi@goffi.org> |
---|---|
date | Fri, 18 Feb 2011 22:32:02 +0100 |
parents | 0e54b1b0a8c8 |
children | e04ccf122bb6 |
line wrap: on
line source
#!/usr/bin/python # -*- coding: utf-8 -*- """ SAT: a jabber client Copyright (C) 2009, 2010, 2011 Jérôme Poisson (goffi@goffi.org) This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses/>. """ from logging import debug, info, error from xml.dom import minidom from wokkel import data_form import pdb from twisted.words.xish import domish """This library help manage XML used in SàT (parameters, registration, etc) """ def dataForm2xml(form): """Take a data form (xep-0004, Wokkel's implementation) and convert it to a SàT xml""" form_ui = XMLUI("form", "vertical") if form.instructions: form_ui.addText('\n'.join(form.instructions), 'instructions') labels = filter(lambda field:field.label,form.fieldList) if labels: #if there is no label, we don't need to use pairs form_ui.changeLayout("pairs") for field in form.fieldList: if field.fieldType == 'fixed': __field_type = 'text' elif field.fieldType == 'text-single': __field_type = "string" elif field.fieldType == 'text-private': __field_type = "password" elif field.fieldType == 'list-single': __field_type = "list" else: error (u"FIXME FIXME FIXME: Type [%s] is not managed yet by SàT" % field.fieldType) __field_type = "string" if labels: if field.label: form_ui.addLabel(field.label) else: form_ui.addEmpty() elem = form_ui.addElement(__field_type, field.var, field.value, [option.value for option in field.options]) return form_ui.toXml() def tupleList2dataForm(values): """convert a list of tuples (name,value) to a wokkel submit data form""" form = data_form.Form('submit') for value in values: field = data_form.Field(var=value[0], value=value[1]) form.addField(field) return form def paramsXml2xmlUI(xml): """Convert the xml for parameter to a SàT XML User Interface""" params_doc = minidom.parseString(xml.encode('utf-8')) top = params_doc.documentElement if top.nodeName != 'params': error(_('INTERNAL ERROR: parameters xml not valid')) assert(False) param_ui = XMLUI("param", "tabs") for category in top.getElementsByTagName("category"): name = category.getAttribute('name') label = category.getAttribute('label') if not name: error(_('INTERNAL ERROR: params categories must have a name')) assert(False) param_ui.addCategory(name, 'pairs', label=label) for param in category.getElementsByTagName("param"): name = param.getAttribute('name') label = param.getAttribute('label') if not name: error(_('INTERNAL ERROR: params must have a name')) assert(False) type = param.getAttribute('type') value = param.getAttribute('value') or None callback_id = param.getAttribute('callback_id') or None if type == "button": param_ui.addEmpty() else: param_ui.addLabel(label or name) param_ui.addElement(name=name, type=type, value=value, callback_id=callback_id) return param_ui.toXml() class XMLUI: """This class is used to create a user interface (form/window/parameters/etc) using SàT XML""" def __init__(self, panel_type, layout="vertical", title=None): """Init SàT XML Panel @param panel_type: one of - window (new window) - form (formulaire, depend of the frontend, usually a panel with cancel/submit buttons) - param (parameters, presentatio depend of the frontend) @param layout: disposition of elements, one of: - vertical: elements are disposed up to bottom - horizontal: elements are disposed left to right - pairs: elements come on two aligned columns (usually one for a label, the next for the element) - tabs: elemens are in categories with tabs (notebook) @param title: title or default if None """ if not panel_type in ['window', 'form', 'param']: error(_("Unknown panel type [%s]") % panel_type) assert(False) self.type = panel_type impl = minidom.getDOMImplementation() self.doc = impl.createDocument(None, "sat_xmlui", None) top_element = self.doc.documentElement top_element.setAttribute("type", panel_type) if title: top_element.setAttribute("title", title) self.parentTabsLayout = None #used only we have 'tabs' layout self.currentCategory = None #used only we have 'tabs' layout self.changeLayout(layout) def __del__(self): self.doc.unlink() def __createLayout(self, layout, parent=None): """Create a layout element @param type: layout type (cf init doc) @parent: parent element or None """ if not layout in ['vertical', 'horizontal', 'pairs', 'tabs']: error (_("Unknown layout type [%s]") % layout) assert (False) layout_elt = self.doc.createElement('layout') layout_elt.setAttribute('type',layout) if parent != None: parent.appendChild(layout_elt) return layout_elt def __createElem(self, type, name=None, parent = None): """Create an element @param type: one of - empty: empty element (usefull to skip something in a layout, e.g. skip first element in a PAIRS layout) - text: text to be displayed in an multi-line area, e.g. instructions @param name: name of the element or None @param parent: parent element or None """ elem = self.doc.createElement('elem') if name: elem.setAttribute('name', name) elem.setAttribute('type', type) if parent != None: parent.appendChild(elem) return elem def changeLayout(self, layout): """Change the current layout""" self.currentLayout = self.__createLayout(layout, self.currentCategory if self.currentCategory else self.doc.documentElement) if layout == "tabs": self.parentTabsLayout = self.currentLayout def addEmpty(self, name=None): """Add a multi-lines text""" elem = self.__createElem('empty', name, self.currentLayout) def addText(self, text, name=None): """Add a multi-lines text""" elem = self.__createElem('text', name, self.currentLayout) text = self.doc.createTextNode(text) elem.appendChild(text) def addLabel(self, text, name=None): """Add a single line text, mainly useful as label before element""" elem = self.__createElem('label', name, self.currentLayout) elem.setAttribute('value', text) def addString(self, name=None, value=None): """Add a string box""" elem = self.__createElem('string', name, self.currentLayout) if value: elem.setAttribute('value', value) def addPassword(self, name=None, value=None): """Add a password box""" elem = self.__createElem('password', name, self.currentLayout) if value: elem.setAttribute('value', value) def addTextBox(self, name=None, value=None): """Add a string box""" elem = self.__createElem('textbox', name, self.currentLayout) if value: elem.setAttribute('value', value) def addBool(self, name=None, value="true"): """Add a string box""" assert value in ["true","false"] elem = self.__createElem('bool', name, self.currentLayout) elem.setAttribute('value', value) def addList(self, options, name=None, value=None, style=set()): """Add a list of choices""" styles = set(style) assert (options) assert (styles.issubset(['multi'])) elem = self.__createElem('list', name, self.currentLayout) self.addOptions(options, elem) if value: elem.setAttribute('value', value) for style in styles: elem.setAttribute(style, 'yes') def addButton(self, callback_id, name, value, fields_back=[]): """Add a button @param callback: callback which will be called if button is pressed @param name: name @param value: label of the button @fields_back: list of names of field to give back when pushing the button""" elem = self.__createElem('button', name, self.currentLayout) elem.setAttribute('callback_id', callback_id) elem.setAttribute('value', value) for field in fields_back: fback_el = self.doc.createElement('field_back') fback_el.setAttribute('name', field) elem.appendChild(fback_el) def addElement(self, type, name = None, value = None, options = None, callback_id = None): """Convenience method to add element, the params correspond to the ones in addSomething methods""" if type == 'empty': self.addEmpty(name) elif type == 'text': assert(value!=None) self.addText(value, name) elif type == 'label': assert(value) self.addLabel(value) elif type == 'string': self.addString(name, value) elif type == 'password': self.addPassword(name, value) elif type == 'textbox': self.addTextBox(name, value) elif type == 'bool': if not value: value = "true" self.addBool(name, value) elif type == 'list': self.addList(options, name, value) elif type == 'button': assert(callback_id and value) self.addButton(callback_id, name, value) def addOptions(self, options, parent): """Add options to a multi-values element (e.g. list) @param parent: multi-values element""" for option in options: opt = self.doc.createElement('option') opt.setAttribute('value', option) parent.appendChild(opt) def addCategory(self, name, layout, label=None): """Add a category to current layout (must be a tabs layout)""" assert(layout != 'tabs') if not self.parentTabsLayout: error(_("Trying to add a category without parent tabs layout")) assert(False) if self.parentTabsLayout.getAttribute('type') != 'tabs': error(_("parent layout of a category is not tabs")) assert(False) if not label: label = name self.currentCategory = cat = self.doc.createElement('category') cat.setAttribute('name', name) cat.setAttribute('label', label) self.changeLayout(layout) self.parentTabsLayout.appendChild(cat) def toXml(self): """return the XML representation of the panel""" return self.doc.toxml() class ElementParser(object): """callable class to parse XML string into Element Found at http://stackoverflow.com/questions/2093400/how-to-create-twisted-words-xish-domish-element-entirely-from-raw-xml/2095942#2095942 (c) Karl Anderson""" def __call__(self, s): self.result = None def onStart(el): self.result = el def onEnd(): pass def onElement(el): self.result.addChild(el) parser = domish.elementStream() parser.DocumentStartEvent = onStart parser.ElementEvent = onElement parser.DocumentEndEvent = onEnd tmp = domish.Element(("", "s")) tmp.addRawXml(s.replace('\n','').replace('\t','')) parser.parse(tmp.toXml()) return self.result.firstChildElement()