Mercurial > libervia-backend
comparison src/tools/xml_tools.py @ 224:9c6ee3f9ab29
files reorganisation
author | Goffi <goffi@goffi.org> |
---|---|
date | Tue, 04 Jan 2011 19:30:27 +0100 |
parents | src/sat/tools/xml_tools.py@86d249b6d9b7 |
children | b1794cbb88e5 |
comparison
equal
deleted
inserted
replaced
223:86d249b6d9b7 | 224:9c6ee3f9ab29 |
---|---|
1 #!/usr/bin/python | |
2 # -*- coding: utf-8 -*- | |
3 | |
4 """ | |
5 SAT: a jabber client | |
6 Copyright (C) 2009, 2010 Jérôme Poisson (goffi@goffi.org) | |
7 | |
8 This program is free software: you can redistribute it and/or modify | |
9 it under the terms of the GNU General Public License as published by | |
10 the Free Software Foundation, either version 3 of the License, or | |
11 (at your option) any later version. | |
12 | |
13 This program is distributed in the hope that it will be useful, | |
14 but WITHOUT ANY WARRANTY; without even the implied warranty of | |
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
16 GNU General Public License for more details. | |
17 | |
18 You should have received a copy of the GNU General Public License | |
19 along with this program. If not, see <http://www.gnu.org/licenses/>. | |
20 """ | |
21 | |
22 from logging import debug, info, error | |
23 from xml.dom import minidom | |
24 from wokkel import data_form | |
25 import pdb | |
26 | |
27 """This library help manage XML used in SàT (parameters, registration, etc) """ | |
28 | |
29 | |
30 def dataForm2xml(form): | |
31 """Take a data form (xep-0004, Wokkel's implementation) and convert it to a SàT xml""" | |
32 | |
33 form_ui = XMLUI("form", "vertical") | |
34 | |
35 if form.instructions: | |
36 form_ui.addText('\n'.join(form.instructions), 'instructions') | |
37 | |
38 labels = filter(lambda field:field.label,form.fieldList) | |
39 if labels: | |
40 #if there is no label, we don't need to use pairs | |
41 form_ui.changeLayout("pairs") | |
42 | |
43 for field in form.fieldList: | |
44 if field.fieldType == 'fixed': | |
45 __field_type = 'text' | |
46 elif field.fieldType == 'text-single': | |
47 __field_type = "string" | |
48 elif field.fieldType == 'text-private': | |
49 __field_type = "password" | |
50 elif field.fieldType == 'list-single': | |
51 __field_type = "list" | |
52 else: | |
53 error (u"FIXME FIXME FIXME: Type [%s] is not managed yet by SàT" % field.fieldType) | |
54 __field_type = "string" | |
55 | |
56 if labels: | |
57 if field.label: | |
58 form_ui.addLabel(field.label) | |
59 else: | |
60 form_ui.addEmpty() | |
61 | |
62 elem = form_ui.addElement(__field_type, field.var, field.value, [option.value for option in field.options]) | |
63 return form_ui.toXml() | |
64 | |
65 def tupleList2dataForm(values): | |
66 """convert a list of tuples (name,value) to a wokkel submit data form""" | |
67 form = data_form.Form('submit') | |
68 for value in values: | |
69 field = data_form.Field(var=value[0], value=value[1]) | |
70 form.addField(field) | |
71 | |
72 return form | |
73 | |
74 def paramsXml2xmlUI(xml): | |
75 """Convert the xml for parameter to a SàT XML User Interface""" | |
76 params_doc = minidom.parseString(xml.encode('utf-8')) | |
77 top = params_doc.documentElement | |
78 if top.nodeName != 'params': | |
79 error(_('INTERNAL ERROR: parameters xml not valid')) | |
80 assert(False) | |
81 param_ui = XMLUI("param", "tabs") | |
82 for category in top.getElementsByTagName("category"): | |
83 name = category.getAttribute('name') | |
84 label = category.getAttribute('label') | |
85 if not name: | |
86 error(_('INTERNAL ERROR: params categories must have a name')) | |
87 assert(False) | |
88 param_ui.addCategory(name, 'pairs', label=label) | |
89 for param in category.getElementsByTagName("param"): | |
90 name = param.getAttribute('name') | |
91 label = param.getAttribute('label') | |
92 if not name: | |
93 error(_('INTERNAL ERROR: params must have a name')) | |
94 assert(False) | |
95 type = param.getAttribute('type') | |
96 value = param.getAttribute('value') or None | |
97 callback_id = param.getAttribute('callback_id') or None | |
98 if type == "button": | |
99 param_ui.addEmpty() | |
100 else: | |
101 param_ui.addLabel(label or name) | |
102 param_ui.addElement(name=name, type=type, value=value, callback_id=callback_id) | |
103 | |
104 return param_ui.toXml() | |
105 | |
106 | |
107 | |
108 | |
109 class XMLUI: | |
110 """This class is used to create a user interface (form/window/parameters/etc) using SàT XML""" | |
111 | |
112 def __init__(self, panel_type, layout="vertical", title=None): | |
113 """Init SàT XML Panel | |
114 @param panel_type: one of | |
115 - window (new window) | |
116 - form (formulaire, depend of the frontend, usually a panel with cancel/submit buttons) | |
117 - param (parameters, presentatio depend of the frontend) | |
118 @param layout: disposition of elements, one of: | |
119 - vertical: elements are disposed up to bottom | |
120 - horizontal: elements are disposed left to right | |
121 - pairs: elements come on two aligned columns | |
122 (usually one for a label, the next for the element) | |
123 - tabs: elemens are in categories with tabs (notebook) | |
124 @param title: title or default if None | |
125 """ | |
126 if not panel_type in ['window', 'form', 'param']: | |
127 error(_("Unknown panel type [%s]") % panel_type) | |
128 assert(False) | |
129 self.type = panel_type | |
130 impl = minidom.getDOMImplementation() | |
131 | |
132 self.doc = impl.createDocument(None, "sat_xmlui", None) | |
133 top_element = self.doc.documentElement | |
134 top_element.setAttribute("type", panel_type) | |
135 if title: | |
136 top_element.setAttribute("title", title) | |
137 self.parentTabsLayout = None #used only we have 'tabs' layout | |
138 self.currentCategory = None #used only we have 'tabs' layout | |
139 self.changeLayout(layout) | |
140 | |
141 def __del__(self): | |
142 self.doc.unlink() | |
143 | |
144 def __createLayout(self, layout, parent=None): | |
145 """Create a layout element | |
146 @param type: layout type (cf init doc) | |
147 @parent: parent element or None | |
148 """ | |
149 if not layout in ['vertical', 'horizontal', 'pairs', 'tabs']: | |
150 error (_("Unknown layout type [%s]") % layout) | |
151 assert (False) | |
152 layout_elt = self.doc.createElement('layout') | |
153 layout_elt.setAttribute('type',layout) | |
154 if parent != None: | |
155 parent.appendChild(layout_elt) | |
156 return layout_elt | |
157 | |
158 def __createElem(self, type, name=None, parent = None): | |
159 """Create an element | |
160 @param type: one of | |
161 - empty: empty element (usefull to skip something in a layout, e.g. skip first element in a PAIRS layout) | |
162 - text: text to be displayed in an multi-line area, e.g. instructions | |
163 @param name: name of the element or None | |
164 @param parent: parent element or None | |
165 """ | |
166 elem = self.doc.createElement('elem') | |
167 if name: | |
168 elem.setAttribute('name', name) | |
169 elem.setAttribute('type', type) | |
170 if parent != None: | |
171 parent.appendChild(elem) | |
172 return elem | |
173 | |
174 def changeLayout(self, layout): | |
175 """Change the current layout""" | |
176 self.currentLayout = self.__createLayout(layout, self.currentCategory if self.currentCategory else self.doc.documentElement) | |
177 if layout == "tabs": | |
178 self.parentTabsLayout = self.currentLayout | |
179 | |
180 | |
181 def addEmpty(self, name=None): | |
182 """Add a multi-lines text""" | |
183 elem = self.__createElem('empty', name, self.currentLayout) | |
184 | |
185 def addText(self, text, name=None): | |
186 """Add a multi-lines text""" | |
187 elem = self.__createElem('text', name, self.currentLayout) | |
188 text = self.doc.createTextNode(text) | |
189 elem.appendChild(text) | |
190 | |
191 def addLabel(self, text, name=None): | |
192 """Add a single line text, mainly useful as label before element""" | |
193 elem = self.__createElem('label', name, self.currentLayout) | |
194 elem.setAttribute('value', text) | |
195 | |
196 def addString(self, name=None, value=None): | |
197 """Add a string box""" | |
198 elem = self.__createElem('string', name, self.currentLayout) | |
199 if value: | |
200 elem.setAttribute('value', value) | |
201 | |
202 def addPassword(self, name=None, value=None): | |
203 """Add a password box""" | |
204 elem = self.__createElem('password', name, self.currentLayout) | |
205 if value: | |
206 elem.setAttribute('value', value) | |
207 | |
208 def addTextBox(self, name=None, value=None): | |
209 """Add a string box""" | |
210 elem = self.__createElem('textbox', name, self.currentLayout) | |
211 if value: | |
212 elem.setAttribute('value', value) | |
213 | |
214 def addBool(self, name=None, value="true"): | |
215 """Add a string box""" | |
216 assert value in ["true","false"] | |
217 elem = self.__createElem('bool', name, self.currentLayout) | |
218 elem.setAttribute('value', value) | |
219 | |
220 def addList(self, options, name=None, value=None, style=set()): | |
221 """Add a list of choices""" | |
222 styles = set(style) | |
223 assert (options) | |
224 assert (styles.issubset(['multi'])) | |
225 elem = self.__createElem('list', name, self.currentLayout) | |
226 self.addOptions(options, elem) | |
227 if value: | |
228 elem.setAttribute('value', value) | |
229 for style in styles: | |
230 elem.setAttribute(style, 'yes') | |
231 | |
232 def addButton(self, callback_id, name, value, fields_back=[]): | |
233 """Add a button | |
234 @param callback: callback which will be called if button is pressed | |
235 @param name: name | |
236 @param value: label of the button | |
237 @fields_back: list of names of field to give back when pushing the button""" | |
238 elem = self.__createElem('button', name, self.currentLayout) | |
239 elem.setAttribute('callback_id', callback_id) | |
240 elem.setAttribute('value', value) | |
241 for field in fields_back: | |
242 fback_el = self.doc.createElement('field_back') | |
243 fback_el.setAttribute('name', field) | |
244 elem.appendChild(fback_el) | |
245 | |
246 | |
247 | |
248 def addElement(self, type, name = None, value = None, options = None, callback_id = None): | |
249 """Convenience method to add element, the params correspond to the ones in addSomething methods""" | |
250 if type == 'empty': | |
251 self.addEmpty(name) | |
252 elif type == 'text': | |
253 assert(value!=None) | |
254 self.addText(value, name) | |
255 elif type == 'label': | |
256 assert(value) | |
257 self.addLabel(value) | |
258 elif type == 'string': | |
259 self.addString(name, value) | |
260 elif type == 'password': | |
261 self.addPassword(name, value) | |
262 elif type == 'textbox': | |
263 self.addTextBox(name, value) | |
264 elif type == 'bool': | |
265 if not value: | |
266 value = "true" | |
267 self.addBool(name, value) | |
268 elif type == 'list': | |
269 self.addList(options, name, value) | |
270 elif type == 'button': | |
271 assert(callback_id and value) | |
272 self.addButton(callback_id, name, value) | |
273 | |
274 def addOptions(self, options, parent): | |
275 """Add options to a multi-values element (e.g. list) | |
276 @param parent: multi-values element""" | |
277 for option in options: | |
278 opt = self.doc.createElement('option') | |
279 opt.setAttribute('value', option) | |
280 parent.appendChild(opt) | |
281 | |
282 def addCategory(self, name, layout, label=None): | |
283 """Add a category to current layout (must be a tabs layout)""" | |
284 assert(layout != 'tabs') | |
285 if not self.parentTabsLayout: | |
286 error(_("Trying to add a category without parent tabs layout")) | |
287 assert(False) | |
288 if self.parentTabsLayout.getAttribute('type') != 'tabs': | |
289 error(_("parent layout of a category is not tabs")) | |
290 assert(False) | |
291 | |
292 if not label: | |
293 label = name | |
294 self.currentCategory = cat = self.doc.createElement('category') | |
295 cat.setAttribute('name', name) | |
296 cat.setAttribute('label', label) | |
297 self.changeLayout(layout) | |
298 self.parentTabsLayout.appendChild(cat) | |
299 | |
300 def toXml(self): | |
301 """return the XML representation of the panel""" | |
302 return self.doc.toxml() |