Mercurial > libervia-backend
comparison sat_frontends/tools/xmlui.py @ 2624:56f94936df1e
code style reformatting using black
author | Goffi <goffi@goffi.org> |
---|---|
date | Wed, 27 Jun 2018 20:14:46 +0200 |
parents | 9446f1ea9eac |
children | c274201cea94 |
comparison
equal
deleted
inserted
replaced
2623:49533de4540b | 2624:56f94936df1e |
---|---|
17 # You should have received a copy of the GNU Affero General Public License | 17 # You should have received a copy of the GNU Affero General Public License |
18 # along with this program. If not, see <http://www.gnu.org/licenses/>. | 18 # along with this program. If not, see <http://www.gnu.org/licenses/>. |
19 | 19 |
20 from sat.core.i18n import _ | 20 from sat.core.i18n import _ |
21 from sat.core.log import getLogger | 21 from sat.core.log import getLogger |
22 | |
22 log = getLogger(__name__) | 23 log = getLogger(__name__) |
23 from sat_frontends.quick_frontend.constants import Const as C | 24 from sat_frontends.quick_frontend.constants import Const as C |
24 from sat.core import exceptions | 25 from sat.core import exceptions |
25 | 26 |
26 | 27 |
27 class_map = {} | 28 class_map = {} |
28 CLASS_PANEL = 'panel' | 29 CLASS_PANEL = "panel" |
29 CLASS_DIALOG = 'dialog' | 30 CLASS_DIALOG = "dialog" |
30 CURRENT_LABEL = 'current_label' | 31 CURRENT_LABEL = "current_label" |
32 | |
31 | 33 |
32 class InvalidXMLUI(Exception): | 34 class InvalidXMLUI(Exception): |
33 pass | 35 pass |
34 | 36 |
35 | 37 |
51 return u"".join(data) | 53 return u"".join(data) |
52 | 54 |
53 | 55 |
54 class Widget(object): | 56 class Widget(object): |
55 """base Widget""" | 57 """base Widget""" |
58 | |
56 pass | 59 pass |
57 | 60 |
58 | 61 |
59 class EmptyWidget(Widget): | 62 class EmptyWidget(Widget): |
60 """Just a placeholder widget""" | 63 """Just a placeholder widget""" |
64 | |
61 pass | 65 pass |
62 | 66 |
63 | 67 |
64 class TextWidget(Widget): | 68 class TextWidget(Widget): |
65 """Non interactive text""" | 69 """Non interactive text""" |
70 | |
66 pass | 71 pass |
67 | 72 |
68 | 73 |
69 class LabelWidget(Widget): | 74 class LabelWidget(Widget): |
70 """Non interactive text""" | 75 """Non interactive text""" |
76 | |
71 pass | 77 pass |
72 | 78 |
73 | 79 |
74 class JidWidget(Widget): | 80 class JidWidget(Widget): |
75 """Jabber ID""" | 81 """Jabber ID""" |
82 | |
76 pass | 83 pass |
77 | 84 |
78 | 85 |
79 class DividerWidget(Widget): | 86 class DividerWidget(Widget): |
80 """Separator""" | 87 """Separator""" |
88 | |
81 pass | 89 pass |
82 | 90 |
83 | 91 |
84 class StringWidget(Widget): | 92 class StringWidget(Widget): |
85 """Input widget wich require a string | 93 """Input widget wich require a string |
86 | 94 |
87 often called Edit in toolkits | 95 often called Edit in toolkits |
88 """ | 96 """ |
97 | |
89 pass | 98 pass |
90 | 99 |
91 | 100 |
92 class JidInputWidget(Widget): | 101 class JidInputWidget(Widget): |
93 """Input widget wich require a string | 102 """Input widget wich require a string |
94 | 103 |
95 often called Edit in toolkits | 104 often called Edit in toolkits |
96 """ | 105 """ |
106 | |
97 pass | 107 pass |
98 | 108 |
99 | 109 |
100 class PasswordWidget(Widget): | 110 class PasswordWidget(Widget): |
101 """Input widget with require a masked string""" | 111 """Input widget with require a masked string""" |
112 | |
102 pass | 113 pass |
103 | 114 |
104 | 115 |
105 class TextBoxWidget(Widget): | 116 class TextBoxWidget(Widget): |
106 """Input widget with require a long, possibly multilines string | 117 """Input widget with require a long, possibly multilines string |
107 often called TextArea in toolkits | 118 often called TextArea in toolkits |
108 """ | 119 """ |
120 | |
109 pass | 121 pass |
110 | 122 |
111 | 123 |
112 class BoolWidget(Widget): | 124 class BoolWidget(Widget): |
113 """Input widget with require a boolean value | 125 """Input widget with require a boolean value |
114 often called CheckBox in toolkits | 126 often called CheckBox in toolkits |
115 """ | 127 """ |
128 | |
116 pass | 129 pass |
117 | 130 |
118 | 131 |
119 class IntWidget(Widget): | 132 class IntWidget(Widget): |
120 """Input widget with require an integer""" | 133 """Input widget with require an integer""" |
134 | |
121 pass | 135 pass |
122 | 136 |
123 | 137 |
124 class ButtonWidget(Widget): | 138 class ButtonWidget(Widget): |
125 """A clickable widget""" | 139 """A clickable widget""" |
140 | |
126 pass | 141 pass |
127 | 142 |
128 | 143 |
129 class ListWidget(Widget): | 144 class ListWidget(Widget): |
130 """A widget able to show/choose one or several strings in a list""" | 145 """A widget able to show/choose one or several strings in a list""" |
146 | |
131 pass | 147 pass |
132 | 148 |
133 | 149 |
134 class JidsListWidget(Widget): | 150 class JidsListWidget(Widget): |
135 """A widget able to show/choose one or several strings in a list""" | 151 """A widget able to show/choose one or several strings in a list""" |
152 | |
136 pass | 153 pass |
137 | 154 |
138 | 155 |
139 class Container(Widget): | 156 class Container(Widget): |
140 """Widget which can contain other ones with a specific layout""" | 157 """Widget which can contain other ones with a specific layout""" |
150 instance.__class__ = type(cls.__name__, cls.__bases__, dict(cls.__dict__)) | 167 instance.__class__ = type(cls.__name__, cls.__bases__, dict(cls.__dict__)) |
151 | 168 |
152 | 169 |
153 class PairsContainer(Container): | 170 class PairsContainer(Container): |
154 """Widgets are disposed in rows of two (usually label/input)""" | 171 """Widgets are disposed in rows of two (usually label/input)""" |
172 | |
155 pass | 173 pass |
156 | 174 |
157 | 175 |
158 class LabelContainer(Container): | 176 class LabelContainer(Container): |
159 """Widgets are associated with label or empty widget""" | 177 """Widgets are associated with label or empty widget""" |
178 | |
160 pass | 179 pass |
161 | 180 |
162 | 181 |
163 class TabsContainer(Container): | 182 class TabsContainer(Container): |
164 """A container which several other containers in tabs | 183 """A container which several other containers in tabs |
165 | 184 |
166 Often called Notebook in toolkits | 185 Often called Notebook in toolkits |
167 """ | 186 """ |
168 pass | 187 |
188 pass | |
189 | |
169 | 190 |
170 class VerticalContainer(Container): | 191 class VerticalContainer(Container): |
171 """Widgets are disposed vertically""" | 192 """Widgets are disposed vertically""" |
193 | |
172 pass | 194 pass |
173 | 195 |
174 | 196 |
175 class AdvancedListContainer(Container): | 197 class AdvancedListContainer(Container): |
176 """Widgets are disposed in rows with advaned features""" | 198 """Widgets are disposed in rows with advaned features""" |
199 | |
177 pass | 200 pass |
178 | 201 |
179 | 202 |
180 class Dialog(object): | 203 class Dialog(object): |
181 """base dialog""" | 204 """base dialog""" |
204 pass | 227 pass |
205 | 228 |
206 | 229 |
207 class MessageDialog(Dialog): | 230 class MessageDialog(Dialog): |
208 """Dialog with a OK/Cancel type configuration""" | 231 """Dialog with a OK/Cancel type configuration""" |
232 | |
209 pass | 233 pass |
210 | 234 |
211 | 235 |
212 class NoteDialog(Dialog): | 236 class NoteDialog(Dialog): |
213 """Short message which doesn't need user confirmation to disappear""" | 237 """Short message which doesn't need user confirmation to disappear""" |
238 | |
214 pass | 239 pass |
215 | 240 |
216 | 241 |
217 class ConfirmDialog(Dialog): | 242 class ConfirmDialog(Dialog): |
218 """Dialog with a OK/Cancel type configuration""" | 243 """Dialog with a OK/Cancel type configuration""" |
224 data[C.XMLUI_DATA_ANSWER] = C.BOOL_FALSE | 249 data[C.XMLUI_DATA_ANSWER] = C.BOOL_FALSE |
225 | 250 |
226 | 251 |
227 class FileDialog(Dialog): | 252 class FileDialog(Dialog): |
228 """Dialog with a OK/Cancel type configuration""" | 253 """Dialog with a OK/Cancel type configuration""" |
254 | |
229 pass | 255 pass |
230 | 256 |
231 | 257 |
232 class XMLUIBase(object): | 258 class XMLUIBase(object): |
233 """Base class to construct SàT XML User Interface | 259 """Base class to construct SàT XML User Interface |
234 | 260 |
235 This class must not be instancied directly | 261 This class must not be instancied directly |
236 """ | 262 """ |
237 | 263 |
238 def __init__(self, host, parsed_dom, title=None, flags=None, callback=None, profile=C.PROF_KEY_NONE): | 264 def __init__( |
265 self, | |
266 host, | |
267 parsed_dom, | |
268 title=None, | |
269 flags=None, | |
270 callback=None, | |
271 profile=C.PROF_KEY_NONE, | |
272 ): | |
239 """Initialise the XMLUI instance | 273 """Initialise the XMLUI instance |
240 | 274 |
241 @param host: %(doc_host)s | 275 @param host: %(doc_host)s |
242 @param parsed_dom: main parsed dom | 276 @param parsed_dom: main parsed dom |
243 @param title: force the title, or use XMLUI one if None | 277 @param title: force the title, or use XMLUI one if None |
248 - if None is used, default behaviour will be used (closing the dialog and calling host.actionManager) | 282 - if None is used, default behaviour will be used (closing the dialog and calling host.actionManager) |
249 - if a callback is provided, it will be used instead, so you'll have to manage | 283 - if a callback is provided, it will be used instead, so you'll have to manage |
250 dialog closing or new xmlui to display, or other action (you can call host.actionManager) | 284 dialog closing or new xmlui to display, or other action (you can call host.actionManager) |
251 """ | 285 """ |
252 self.host = host | 286 self.host = host |
253 top=parsed_dom.documentElement | 287 top = parsed_dom.documentElement |
254 self.session_id = top.getAttribute("session_id") or None | 288 self.session_id = top.getAttribute("session_id") or None |
255 self.submit_id = top.getAttribute("submit") or None | 289 self.submit_id = top.getAttribute("submit") or None |
256 self.xmlui_title = title or top.getAttribute("title") or u"" | 290 self.xmlui_title = title or top.getAttribute("title") or u"" |
257 if flags is None: | 291 if flags is None: |
258 flags = [] | 292 flags = [] |
296 def submit(self, data): | 330 def submit(self, data): |
297 self._xmluiClose() | 331 self._xmluiClose() |
298 if self.submit_id is None: | 332 if self.submit_id is None: |
299 raise ValueError("Can't submit is self.submit_id is not set") | 333 raise ValueError("Can't submit is self.submit_id is not set") |
300 if "session_id" in data: | 334 if "session_id" in data: |
301 raise ValueError("session_id must no be used in data, it is automaticaly filled with self.session_id if present") | 335 raise ValueError( |
336 "session_id must no be used in data, it is automaticaly filled with self.session_id if present" | |
337 ) | |
302 if self.session_id is not None: | 338 if self.session_id is not None: |
303 data["session_id"] = self.session_id | 339 data["session_id"] = self.session_id |
304 self._xmluiLaunchAction(self.submit_id, data) | 340 self._xmluiLaunchAction(self.submit_id, data) |
305 | 341 |
306 def _xmluiLaunchAction(self, action_id, data): | 342 def _xmluiLaunchAction(self, action_id, data): |
307 self.host.launchAction(action_id, data, callback=self.callback, profile=self.profile) | 343 self.host.launchAction( |
344 action_id, data, callback=self.callback, profile=self.profile | |
345 ) | |
308 | 346 |
309 def _xmluiClose(self): | 347 def _xmluiClose(self): |
310 """Close the window/popup/... where the constructor XMLUI is | 348 """Close the window/popup/... where the constructor XMLUI is |
311 | 349 |
312 this method must be overrided | 350 this method must be overrided |
315 | 353 |
316 | 354 |
317 class ValueGetter(object): | 355 class ValueGetter(object): |
318 """dict like object which return values of widgets""" | 356 """dict like object which return values of widgets""" |
319 | 357 |
320 def __init__(self, widgets, attr='value'): | 358 def __init__(self, widgets, attr="value"): |
321 self.attr = attr | 359 self.attr = attr |
322 self.widgets = widgets | 360 self.widgets = widgets |
323 | 361 |
324 def __getitem__(self, name): | 362 def __getitem__(self, name): |
325 return getattr(self.widgets[name], self.attr) | 363 return getattr(self.widgets[name], self.attr) |
336 | 374 |
337 New frontends can inherit this class to easily implement XMLUI | 375 New frontends can inherit this class to easily implement XMLUI |
338 @property widget_factory: factory to create frontend-specific widgets | 376 @property widget_factory: factory to create frontend-specific widgets |
339 @property dialog_factory: factory to create frontend-specific dialogs | 377 @property dialog_factory: factory to create frontend-specific dialogs |
340 """ | 378 """ |
379 | |
341 widget_factory = None | 380 widget_factory = None |
342 | 381 |
343 def __init__(self, host, parsed_dom, title=None, flags=None, callback=None, ignore=None, whitelist=None, profile=C.PROF_KEY_NONE): | 382 def __init__( |
383 self, | |
384 host, | |
385 parsed_dom, | |
386 title=None, | |
387 flags=None, | |
388 callback=None, | |
389 ignore=None, | |
390 whitelist=None, | |
391 profile=C.PROF_KEY_NONE, | |
392 ): | |
344 """ | 393 """ |
345 | 394 |
346 @param title(unicode, None): title of the | 395 @param title(unicode, None): title of the |
347 @property widgets(dict): widget name => widget map | 396 @property widgets(dict): widget name => widget map |
348 @property widget_value(ValueGetter): retrieve widget value from it's name | 397 @property widget_value(ValueGetter): retrieve widget value from it's name |
349 """ | 398 """ |
350 super(XMLUIPanel, self).__init__(host, parsed_dom, title=title, flags=flags, callback=callback, profile=profile) | 399 super(XMLUIPanel, self).__init__( |
400 host, parsed_dom, title=title, flags=flags, callback=callback, profile=profile | |
401 ) | |
351 self.ctrl_list = {} # input widget, used mainly for forms | 402 self.ctrl_list = {} # input widget, used mainly for forms |
352 self.widgets = {} # allow to access any named widgets | 403 self.widgets = {} # allow to access any named widgets |
353 self.widget_value = ValueGetter(self.widgets) | 404 self.widget_value = ValueGetter(self.widgets) |
354 self._main_cont = None | 405 self._main_cont = None |
355 if ignore is None: | 406 if ignore is None: |
356 ignore = [] | 407 ignore = [] |
357 self._ignore = ignore | 408 self._ignore = ignore |
358 if whitelist is not None: | 409 if whitelist is not None: |
359 if ignore: | 410 if ignore: |
360 raise exceptions.InternalError('ignore and whitelist must not be used at the same time') | 411 raise exceptions.InternalError( |
412 "ignore and whitelist must not be used at the same time" | |
413 ) | |
361 self._whitelist = whitelist | 414 self._whitelist = whitelist |
362 else: | 415 else: |
363 self._whitelist = None | 416 self._whitelist = None |
364 self.constructUI(parsed_dom) | 417 self.constructUI(parsed_dom) |
365 | 418 |
375 def main_cont(self, value): | 428 def main_cont(self, value): |
376 if self._main_cont is not None: | 429 if self._main_cont is not None: |
377 raise ValueError(_("XMLUI can have only one main container")) | 430 raise ValueError(_("XMLUI can have only one main container")) |
378 self._main_cont = value | 431 self._main_cont = value |
379 | 432 |
380 def _parseChilds(self, _xmlui_parent, current_node, wanted = ('container',), data = None): | 433 def _parseChilds(self, _xmlui_parent, current_node, wanted=("container",), data=None): |
381 """Recursively parse childNodes of an element | 434 """Recursively parse childNodes of an element |
382 | 435 |
383 @param _xmlui_parent: widget container with '_xmluiAppend' method | 436 @param _xmlui_parent: widget container with '_xmluiAppend' method |
384 @param current_node: element from which childs will be parsed | 437 @param current_node: element from which childs will be parsed |
385 @param wanted: list of tag names that can be present in the childs to be SàT XMLUI compliant | 438 @param wanted: list of tag names that can be present in the childs to be SàT XMLUI compliant |
387 """ | 440 """ |
388 for node in current_node.childNodes: | 441 for node in current_node.childNodes: |
389 if data is None: | 442 if data is None: |
390 data = {} | 443 data = {} |
391 if wanted and not node.nodeName in wanted: | 444 if wanted and not node.nodeName in wanted: |
392 raise InvalidXMLUI('Unexpected node: [%s]' % node.nodeName) | 445 raise InvalidXMLUI("Unexpected node: [%s]" % node.nodeName) |
393 | 446 |
394 if node.nodeName == "container": | 447 if node.nodeName == "container": |
395 type_ = node.getAttribute('type') | 448 type_ = node.getAttribute("type") |
396 if _xmlui_parent is self and type_ != 'vertical': | 449 if _xmlui_parent is self and type_ != "vertical": |
397 # main container is not a VerticalContainer and we want one, so we create one to wrap it | 450 # main container is not a VerticalContainer and we want one, so we create one to wrap it |
398 _xmlui_parent = self.widget_factory.createVerticalContainer(self) | 451 _xmlui_parent = self.widget_factory.createVerticalContainer(self) |
399 self.main_cont = _xmlui_parent | 452 self.main_cont = _xmlui_parent |
400 if type_ == "tabs": | 453 if type_ == "tabs": |
401 cont = self.widget_factory.createTabsContainer(_xmlui_parent) | 454 cont = self.widget_factory.createTabsContainer(_xmlui_parent) |
402 self._parseChilds(_xmlui_parent, node, ('tab',), {'tabs_cont': cont}) | 455 self._parseChilds(_xmlui_parent, node, ("tab",), {"tabs_cont": cont}) |
403 elif type_ == "vertical": | 456 elif type_ == "vertical": |
404 cont = self.widget_factory.createVerticalContainer(_xmlui_parent) | 457 cont = self.widget_factory.createVerticalContainer(_xmlui_parent) |
405 self._parseChilds(cont, node, ('widget', 'container')) | 458 self._parseChilds(cont, node, ("widget", "container")) |
406 elif type_ == "pairs": | 459 elif type_ == "pairs": |
407 cont = self.widget_factory.createPairsContainer(_xmlui_parent) | 460 cont = self.widget_factory.createPairsContainer(_xmlui_parent) |
408 self._parseChilds(cont, node, ('widget', 'container')) | 461 self._parseChilds(cont, node, ("widget", "container")) |
409 elif type_ == "label": | 462 elif type_ == "label": |
410 cont = self.widget_factory.createLabelContainer(_xmlui_parent) | 463 cont = self.widget_factory.createLabelContainer(_xmlui_parent) |
411 self._parseChilds(cont, node, ('widget', 'container'), {CURRENT_LABEL: None}) | 464 self._parseChilds( |
465 cont, node, ("widget", "container"), {CURRENT_LABEL: None} | |
466 ) | |
412 elif type_ == "advanced_list": | 467 elif type_ == "advanced_list": |
413 try: | 468 try: |
414 columns = int(node.getAttribute('columns')) | 469 columns = int(node.getAttribute("columns")) |
415 except (TypeError, ValueError): | 470 except (TypeError, ValueError): |
416 raise exceptions.DataError("Invalid columns") | 471 raise exceptions.DataError("Invalid columns") |
417 selectable = node.getAttribute('selectable') or 'no' | 472 selectable = node.getAttribute("selectable") or "no" |
418 auto_index = node.getAttribute('auto_index') == C.BOOL_TRUE | 473 auto_index = node.getAttribute("auto_index") == C.BOOL_TRUE |
419 data = {'index': 0} if auto_index else None | 474 data = {"index": 0} if auto_index else None |
420 cont = self.widget_factory.createAdvancedListContainer(_xmlui_parent, columns, selectable) | 475 cont = self.widget_factory.createAdvancedListContainer( |
476 _xmlui_parent, columns, selectable | |
477 ) | |
421 callback_id = node.getAttribute("callback") or None | 478 callback_id = node.getAttribute("callback") or None |
422 if callback_id is not None: | 479 if callback_id is not None: |
423 if selectable == 'no': | 480 if selectable == "no": |
424 raise ValueError("can't have selectable=='no' and callback_id at the same time") | 481 raise ValueError( |
482 "can't have selectable=='no' and callback_id at the same time" | |
483 ) | |
425 cont._xmlui_callback_id = callback_id | 484 cont._xmlui_callback_id = callback_id |
426 cont._xmluiOnSelect(self.onAdvListSelect) | 485 cont._xmluiOnSelect(self.onAdvListSelect) |
427 | 486 |
428 self._parseChilds(cont, node, ('row',), data) | 487 self._parseChilds(cont, node, ("row",), data) |
429 else: | 488 else: |
430 log.warning(_("Unknown container [%s], using default one") % type_) | 489 log.warning(_("Unknown container [%s], using default one") % type_) |
431 cont = self.widget_factory.createVerticalContainer(_xmlui_parent) | 490 cont = self.widget_factory.createVerticalContainer(_xmlui_parent) |
432 self._parseChilds(cont, node, ('widget', 'container')) | 491 self._parseChilds(cont, node, ("widget", "container")) |
433 try: | 492 try: |
434 xmluiAppend = _xmlui_parent._xmluiAppend | 493 xmluiAppend = _xmlui_parent._xmluiAppend |
435 except (AttributeError, TypeError): # XXX: TypeError is here because pyjamas raise a TypeError instead of an AttributeError | 494 except ( |
495 AttributeError, | |
496 TypeError, | |
497 ): # XXX: TypeError is here because pyjamas raise a TypeError instead of an AttributeError | |
436 if _xmlui_parent is self: | 498 if _xmlui_parent is self: |
437 self.main_cont = cont | 499 self.main_cont = cont |
438 else: | 500 else: |
439 raise Exception(_("Internal Error, container has not _xmluiAppend method")) | 501 raise Exception( |
502 _("Internal Error, container has not _xmluiAppend method") | |
503 ) | |
440 else: | 504 else: |
441 xmluiAppend(cont) | 505 xmluiAppend(cont) |
442 | 506 |
443 elif node.nodeName == 'tab': | 507 elif node.nodeName == "tab": |
444 name = node.getAttribute('name') | 508 name = node.getAttribute("name") |
445 label = node.getAttribute('label') | 509 label = node.getAttribute("label") |
446 selected = C.bool(node.getAttribute('selected') or C.BOOL_FALSE) | 510 selected = C.bool(node.getAttribute("selected") or C.BOOL_FALSE) |
447 if not name or not 'tabs_cont' in data: | 511 if not name or not "tabs_cont" in data: |
448 raise InvalidXMLUI | 512 raise InvalidXMLUI |
449 if self.type == 'param': | 513 if self.type == "param": |
450 self._current_category = name #XXX: awful hack because params need category and we don't keep parent | 514 self._current_category = ( |
451 tab_cont = data['tabs_cont'] | 515 name |
516 ) # XXX: awful hack because params need category and we don't keep parent | |
517 tab_cont = data["tabs_cont"] | |
452 new_tab = tab_cont._xmluiAddTab(label or name, selected) | 518 new_tab = tab_cont._xmluiAddTab(label or name, selected) |
453 self._parseChilds(new_tab, node, ('widget', 'container')) | 519 self._parseChilds(new_tab, node, ("widget", "container")) |
454 | 520 |
455 elif node.nodeName == 'row': | 521 elif node.nodeName == "row": |
456 try: | 522 try: |
457 index = str(data['index']) | 523 index = str(data["index"]) |
458 except KeyError: | 524 except KeyError: |
459 index = node.getAttribute('index') or None | 525 index = node.getAttribute("index") or None |
460 else: | 526 else: |
461 data['index'] += 1 | 527 data["index"] += 1 |
462 _xmlui_parent._xmluiAddRow(index) | 528 _xmlui_parent._xmluiAddRow(index) |
463 self._parseChilds(_xmlui_parent, node, ('widget', 'container')) | 529 self._parseChilds(_xmlui_parent, node, ("widget", "container")) |
464 | 530 |
465 elif node.nodeName == "widget": | 531 elif node.nodeName == "widget": |
466 name = node.getAttribute("name") | 532 name = node.getAttribute("name") |
467 if name and (name in self._ignore or self._whitelist is not None and name not in self._whitelist): | 533 if name and ( |
534 name in self._ignore | |
535 or self._whitelist is not None | |
536 and name not in self._whitelist | |
537 ): | |
468 # current widget is ignored, but there may be already a label | 538 # current widget is ignored, but there may be already a label |
469 if CURRENT_LABEL in data: | 539 if CURRENT_LABEL in data: |
470 # if so, we remove it from parent | 540 # if so, we remove it from parent |
471 _xmlui_parent._xmluiRemove(data.pop(CURRENT_LABEL)) | 541 _xmlui_parent._xmluiRemove(data.pop(CURRENT_LABEL)) |
472 continue | 542 continue |
473 type_ = node.getAttribute("type") | 543 type_ = node.getAttribute("type") |
474 value_elt = self._getChildNode(node, "value") | 544 value_elt = self._getChildNode(node, "value") |
475 if value_elt is not None: | 545 if value_elt is not None: |
476 value = getText(value_elt) | 546 value = getText(value_elt) |
477 else: | 547 else: |
478 value = node.getAttribute("value") if node.hasAttribute('value') else u'' | 548 value = ( |
479 if type_=="empty": | 549 node.getAttribute("value") if node.hasAttribute("value") else u"" |
550 ) | |
551 if type_ == "empty": | |
480 ctrl = self.widget_factory.createEmptyWidget(_xmlui_parent) | 552 ctrl = self.widget_factory.createEmptyWidget(_xmlui_parent) |
481 if CURRENT_LABEL in data: | 553 if CURRENT_LABEL in data: |
482 data[CURRENT_LABEL] = None | 554 data[CURRENT_LABEL] = None |
483 elif type_=="text": | 555 elif type_ == "text": |
484 ctrl = self.widget_factory.createTextWidget(_xmlui_parent, value) | 556 ctrl = self.widget_factory.createTextWidget(_xmlui_parent, value) |
485 elif type_=="label": | 557 elif type_ == "label": |
486 ctrl = self.widget_factory.createLabelWidget(_xmlui_parent, value) | 558 ctrl = self.widget_factory.createLabelWidget(_xmlui_parent, value) |
487 data[CURRENT_LABEL] = ctrl | 559 data[CURRENT_LABEL] = ctrl |
488 elif type_=="jid": | 560 elif type_ == "jid": |
489 ctrl = self.widget_factory.createJidWidget(_xmlui_parent, value) | 561 ctrl = self.widget_factory.createJidWidget(_xmlui_parent, value) |
490 elif type_=="divider": | 562 elif type_ == "divider": |
491 style = node.getAttribute("style") or 'line' | 563 style = node.getAttribute("style") or "line" |
492 ctrl = self.widget_factory.createDividerWidget(_xmlui_parent, style) | 564 ctrl = self.widget_factory.createDividerWidget(_xmlui_parent, style) |
493 elif type_=="string": | 565 elif type_ == "string": |
494 ctrl = self.widget_factory.createStringWidget(_xmlui_parent, value, self._isAttrSet("read_only", node)) | 566 ctrl = self.widget_factory.createStringWidget( |
495 self.ctrl_list[name] = ({'type':type_, 'control':ctrl}) | 567 _xmlui_parent, value, self._isAttrSet("read_only", node) |
496 elif type_=="jid_input": | 568 ) |
497 ctrl = self.widget_factory.createJidInputWidget(_xmlui_parent, value, self._isAttrSet("read_only", node)) | 569 self.ctrl_list[name] = {"type": type_, "control": ctrl} |
498 self.ctrl_list[name] = ({'type':type_, 'control':ctrl}) | 570 elif type_ == "jid_input": |
499 elif type_=="password": | 571 ctrl = self.widget_factory.createJidInputWidget( |
500 ctrl = self.widget_factory.createPasswordWidget(_xmlui_parent, value, self._isAttrSet("read_only", node)) | 572 _xmlui_parent, value, self._isAttrSet("read_only", node) |
501 self.ctrl_list[name] = ({'type':type_, 'control':ctrl}) | 573 ) |
502 elif type_=="textbox": | 574 self.ctrl_list[name] = {"type": type_, "control": ctrl} |
503 ctrl = self.widget_factory.createTextBoxWidget(_xmlui_parent, value, self._isAttrSet("read_only", node)) | 575 elif type_ == "password": |
504 self.ctrl_list[name] = ({'type':type_, 'control':ctrl}) | 576 ctrl = self.widget_factory.createPasswordWidget( |
505 elif type_=="bool": | 577 _xmlui_parent, value, self._isAttrSet("read_only", node) |
506 ctrl = self.widget_factory.createBoolWidget(_xmlui_parent, value==C.BOOL_TRUE, self._isAttrSet("read_only", node)) | 578 ) |
507 self.ctrl_list[name] = ({'type':type_, 'control':ctrl}) | 579 self.ctrl_list[name] = {"type": type_, "control": ctrl} |
580 elif type_ == "textbox": | |
581 ctrl = self.widget_factory.createTextBoxWidget( | |
582 _xmlui_parent, value, self._isAttrSet("read_only", node) | |
583 ) | |
584 self.ctrl_list[name] = {"type": type_, "control": ctrl} | |
585 elif type_ == "bool": | |
586 ctrl = self.widget_factory.createBoolWidget( | |
587 _xmlui_parent, | |
588 value == C.BOOL_TRUE, | |
589 self._isAttrSet("read_only", node), | |
590 ) | |
591 self.ctrl_list[name] = {"type": type_, "control": ctrl} | |
508 elif type_ == "int": | 592 elif type_ == "int": |
509 ctrl = self.widget_factory.createIntWidget(_xmlui_parent, value, self._isAttrSet("read_only", node)) | 593 ctrl = self.widget_factory.createIntWidget( |
510 self.ctrl_list[name] = ({'type':type_, 'control':ctrl}) | 594 _xmlui_parent, value, self._isAttrSet("read_only", node) |
595 ) | |
596 self.ctrl_list[name] = {"type": type_, "control": ctrl} | |
511 elif type_ == "list": | 597 elif type_ == "list": |
512 style = [] if node.getAttribute("multi") == 'yes' else ['single'] | 598 style = [] if node.getAttribute("multi") == "yes" else ["single"] |
513 for attr in (u'noselect', u'extensible', u'reducible', u'inline'): | 599 for attr in (u"noselect", u"extensible", u"reducible", u"inline"): |
514 if node.getAttribute(attr) == 'yes': | 600 if node.getAttribute(attr) == "yes": |
515 style.append(attr) | 601 style.append(attr) |
516 _options = [(option.getAttribute("value"), option.getAttribute("label")) for option in node.getElementsByTagName("option")] | 602 _options = [ |
517 _selected = [option.getAttribute("value") for option in node.getElementsByTagName("option") if option.getAttribute('selected') == C.BOOL_TRUE] | 603 (option.getAttribute("value"), option.getAttribute("label")) |
518 ctrl = self.widget_factory.createListWidget(_xmlui_parent, _options, _selected, style) | 604 for option in node.getElementsByTagName("option") |
519 self.ctrl_list[name] = ({'type': type_, 'control': ctrl}) | 605 ] |
606 _selected = [ | |
607 option.getAttribute("value") | |
608 for option in node.getElementsByTagName("option") | |
609 if option.getAttribute("selected") == C.BOOL_TRUE | |
610 ] | |
611 ctrl = self.widget_factory.createListWidget( | |
612 _xmlui_parent, _options, _selected, style | |
613 ) | |
614 self.ctrl_list[name] = {"type": type_, "control": ctrl} | |
520 elif type_ == "jids_list": | 615 elif type_ == "jids_list": |
521 style = [] | 616 style = [] |
522 jids = [getText(jid_) for jid_ in node.getElementsByTagName("jid")] | 617 jids = [getText(jid_) for jid_ in node.getElementsByTagName("jid")] |
523 ctrl = self.widget_factory.createJidsListWidget(_xmlui_parent, jids, style) | 618 ctrl = self.widget_factory.createJidsListWidget( |
524 self.ctrl_list[name] = ({'type': type_, 'control': ctrl}) | 619 _xmlui_parent, jids, style |
525 elif type_=="button": | 620 ) |
621 self.ctrl_list[name] = {"type": type_, "control": ctrl} | |
622 elif type_ == "button": | |
526 callback_id = node.getAttribute("callback") | 623 callback_id = node.getAttribute("callback") |
527 ctrl = self.widget_factory.createButtonWidget(_xmlui_parent, value, self.onButtonPress) | 624 ctrl = self.widget_factory.createButtonWidget( |
528 ctrl._xmlui_param_id = (callback_id, [field.getAttribute('name') for field in node.getElementsByTagName("field_back")]) | 625 _xmlui_parent, value, self.onButtonPress |
626 ) | |
627 ctrl._xmlui_param_id = ( | |
628 callback_id, | |
629 [ | |
630 field.getAttribute("name") | |
631 for field in node.getElementsByTagName("field_back") | |
632 ], | |
633 ) | |
529 else: | 634 else: |
530 log.error(_("FIXME FIXME FIXME: widget type [%s] is not implemented") % type_) | 635 log.error( |
531 raise NotImplementedError(_("FIXME FIXME FIXME: type [%s] is not implemented") % type_) | 636 _("FIXME FIXME FIXME: widget type [%s] is not implemented") |
637 % type_ | |
638 ) | |
639 raise NotImplementedError( | |
640 _("FIXME FIXME FIXME: type [%s] is not implemented") % type_ | |
641 ) | |
532 | 642 |
533 if name: | 643 if name: |
534 self.widgets[name] = ctrl | 644 self.widgets[name] = ctrl |
535 | 645 |
536 if self.type == 'param' and type_ not in ('text', 'button'): | 646 if self.type == "param" and type_ not in ("text", "button"): |
537 try: | 647 try: |
538 ctrl._xmluiOnChange(self.onParamChange) | 648 ctrl._xmluiOnChange(self.onParamChange) |
539 ctrl._param_category = self._current_category | 649 ctrl._param_category = self._current_category |
540 except (AttributeError, TypeError): # XXX: TypeError is here because pyjamas raise a TypeError instead of an AttributeError | 650 except ( |
541 if not isinstance(ctrl, (EmptyWidget, TextWidget, LabelWidget, JidWidget)): | 651 AttributeError, |
652 TypeError, | |
653 ): # XXX: TypeError is here because pyjamas raise a TypeError instead of an AttributeError | |
654 if not isinstance( | |
655 ctrl, (EmptyWidget, TextWidget, LabelWidget, JidWidget) | |
656 ): | |
542 log.warning(_("No change listener on [%s]") % ctrl) | 657 log.warning(_("No change listener on [%s]") % ctrl) |
543 | 658 |
544 elif type_ != 'text': | 659 elif type_ != "text": |
545 callback = node.getAttribute("internal_callback") or None | 660 callback = node.getAttribute("internal_callback") or None |
546 if callback: | 661 if callback: |
547 fields = [field.getAttribute('name') for field in node.getElementsByTagName("internal_field")] | 662 fields = [ |
663 field.getAttribute("name") | |
664 for field in node.getElementsByTagName("internal_field") | |
665 ] | |
548 cb_data = self.getInternalCallbackData(callback, node) | 666 cb_data = self.getInternalCallbackData(callback, node) |
549 ctrl._xmlui_param_internal = (callback, fields, cb_data) | 667 ctrl._xmlui_param_internal = (callback, fields, cb_data) |
550 if type_ == 'button': | 668 if type_ == "button": |
551 ctrl._xmluiOnClick(self.onChangeInternal) | 669 ctrl._xmluiOnClick(self.onChangeInternal) |
552 else: | 670 else: |
553 ctrl._xmluiOnChange(self.onChangeInternal) | 671 ctrl._xmluiOnChange(self.onChangeInternal) |
554 | 672 |
555 ctrl._xmlui_name = name | 673 ctrl._xmlui_name = name |
558 # this key is set in LabelContainer, when present | 676 # this key is set in LabelContainer, when present |
559 # we can associate the label with the widget it is labelling | 677 # we can associate the label with the widget it is labelling |
560 data.pop(CURRENT_LABEL)._xmlui_for_name = name | 678 data.pop(CURRENT_LABEL)._xmlui_for_name = name |
561 | 679 |
562 else: | 680 else: |
563 raise NotImplementedError(_('Unknown tag [%s]') % node.nodeName) | 681 raise NotImplementedError(_("Unknown tag [%s]") % node.nodeName) |
564 | 682 |
565 def constructUI(self, parsed_dom, post_treat=None): | 683 def constructUI(self, parsed_dom, post_treat=None): |
566 """Actually construct the UI | 684 """Actually construct the UI |
567 | 685 |
568 @param parsed_dom: main parsed dom | 686 @param parsed_dom: main parsed dom |
569 @param post_treat: frontend specific treatments to do once the UI is constructed | 687 @param post_treat: frontend specific treatments to do once the UI is constructed |
570 @return: constructed widget | 688 @return: constructed widget |
571 """ | 689 """ |
572 top=parsed_dom.documentElement | 690 top = parsed_dom.documentElement |
573 self.type = top.getAttribute("type") | 691 self.type = top.getAttribute("type") |
574 if top.nodeName != "sat_xmlui" or not self.type in ['form', 'param', 'window', 'popup']: | 692 if top.nodeName != "sat_xmlui" or not self.type in [ |
693 "form", | |
694 "param", | |
695 "window", | |
696 "popup", | |
697 ]: | |
575 raise InvalidXMLUI | 698 raise InvalidXMLUI |
576 | 699 |
577 if self.type == 'param': | 700 if self.type == "param": |
578 self.param_changed = set() | 701 self.param_changed = set() |
579 | 702 |
580 self._parseChilds(self, parsed_dom.documentElement) | 703 self._parseChilds(self, parsed_dom.documentElement) |
581 | 704 |
582 if post_treat is not None: | 705 if post_treat is not None: |
601 for wid in widgets: | 724 for wid in widgets: |
602 try: | 725 try: |
603 name = self.escape(wid._xmlui_name) | 726 name = self.escape(wid._xmlui_name) |
604 value = wid._xmluiGetValue() | 727 value = wid._xmluiGetValue() |
605 data[name] = value | 728 data[name] = value |
606 except (AttributeError, TypeError): # XXX: TypeError is here because pyjamas raise a TypeError instead of an AttributeError | 729 except ( |
730 AttributeError, | |
731 TypeError, | |
732 ): # XXX: TypeError is here because pyjamas raise a TypeError instead of an AttributeError | |
607 pass | 733 pass |
608 idx = ctrl._xmluiGetSelectedIndex() | 734 idx = ctrl._xmluiGetSelectedIndex() |
609 if idx is not None: | 735 if idx is not None: |
610 data['index'] = idx | 736 data["index"] = idx |
611 callback_id = ctrl._xmlui_callback_id | 737 callback_id = ctrl._xmlui_callback_id |
612 if callback_id is None: | 738 if callback_id is None: |
613 log.info(_("No callback_id found")) | 739 log.info(_("No callback_id found")) |
614 return | 740 return |
615 self._xmluiLaunchAction(callback_id, data) | 741 self._xmluiLaunchAction(callback_id, data) |
625 return | 751 return |
626 data = {} | 752 data = {} |
627 for field in fields: | 753 for field in fields: |
628 escaped = self.escape(field) | 754 escaped = self.escape(field) |
629 ctrl = self.ctrl_list[field] | 755 ctrl = self.ctrl_list[field] |
630 if isinstance(ctrl['control'], ListWidget): | 756 if isinstance(ctrl["control"], ListWidget): |
631 data[escaped] = u'\t'.join(ctrl['control']._xmluiGetSelectedValues()) | 757 data[escaped] = u"\t".join(ctrl["control"]._xmluiGetSelectedValues()) |
632 else: | 758 else: |
633 data[escaped] = ctrl['control']._xmluiGetValue() | 759 data[escaped] = ctrl["control"]._xmluiGetValue() |
634 self._xmluiLaunchAction(callback_id, data) | 760 self._xmluiLaunchAction(callback_id, data) |
635 | 761 |
636 def onChangeInternal(self, ctrl): | 762 def onChangeInternal(self, ctrl): |
637 """Called when a widget that has been bound to an internal callback is changed. | 763 """Called when a widget that has been bound to an internal callback is changed. |
638 | 764 |
639 This is used to perform some UI actions without communicating with the backend. | 765 This is used to perform some UI actions without communicating with the backend. |
640 See sat.tools.xml_tools.Widget.setInternalCallback for more details. | 766 See sat.tools.xml_tools.Widget.setInternalCallback for more details. |
641 @param ctrl: widget modified | 767 @param ctrl: widget modified |
642 """ | 768 """ |
643 action, fields, data = ctrl._xmlui_param_internal | 769 action, fields, data = ctrl._xmlui_param_internal |
644 if action not in ('copy', 'move', 'groups_of_contact'): | 770 if action not in ("copy", "move", "groups_of_contact"): |
645 raise NotImplementedError(_("FIXME: XMLUI internal action [%s] is not implemented") % action) | 771 raise NotImplementedError( |
772 _("FIXME: XMLUI internal action [%s] is not implemented") % action | |
773 ) | |
646 | 774 |
647 def copy_move(source, target): | 775 def copy_move(source, target): |
648 """Depending of 'action' value, copy or move from source to target.""" | 776 """Depending of 'action' value, copy or move from source to target.""" |
649 if isinstance(target, ListWidget): | 777 if isinstance(target, ListWidget): |
650 if isinstance(source, ListWidget): | 778 if isinstance(source, ListWidget): |
651 values = source._xmluiGetSelectedValues() | 779 values = source._xmluiGetSelectedValues() |
652 else: | 780 else: |
653 values = [source._xmluiGetValue()] | 781 values = [source._xmluiGetValue()] |
654 if action == 'move': | 782 if action == "move": |
655 source._xmluiSetValue('') | 783 source._xmluiSetValue("") |
656 values = [value for value in values if value] | 784 values = [value for value in values if value] |
657 if values: | 785 if values: |
658 target._xmluiAddValues(values, select=True) | 786 target._xmluiAddValues(values, select=True) |
659 else: | 787 else: |
660 if isinstance(source, ListWidget): | 788 if isinstance(source, ListWidget): |
661 value = u', '.join(source._xmluiGetSelectedValues()) | 789 value = u", ".join(source._xmluiGetSelectedValues()) |
662 else: | 790 else: |
663 value = source._xmluiGetValue() | 791 value = source._xmluiGetValue() |
664 if action == 'move': | 792 if action == "move": |
665 source._xmluiSetValue('') | 793 source._xmluiSetValue("") |
666 target._xmluiSetValue(value) | 794 target._xmluiSetValue(value) |
667 | 795 |
668 def groups_of_contact(source, target): | 796 def groups_of_contact(source, target): |
669 """Select in target the groups of the contact which is selected in source.""" | 797 """Select in target the groups of the contact which is selected in source.""" |
670 assert isinstance(source, ListWidget) | 798 assert isinstance(source, ListWidget) |
676 target._xmluiSelectValues(data[contact_jid_s]) | 804 target._xmluiSelectValues(data[contact_jid_s]) |
677 pass | 805 pass |
678 | 806 |
679 source = None | 807 source = None |
680 for field in fields: | 808 for field in fields: |
681 widget = self.ctrl_list[field]['control'] | 809 widget = self.ctrl_list[field]["control"] |
682 if not source: | 810 if not source: |
683 source = widget | 811 source = widget |
684 continue | 812 continue |
685 if action in ('copy', 'move'): | 813 if action in ("copy", "move"): |
686 copy_move(source, widget) | 814 copy_move(source, widget) |
687 elif action == 'groups_of_contact': | 815 elif action == "groups_of_contact": |
688 groups_of_contact(source, widget) | 816 groups_of_contact(source, widget) |
689 source = None | 817 source = None |
690 | 818 |
691 def getInternalCallbackData(self, action, node): | 819 def getInternalCallbackData(self, action, node): |
692 """Retrieve from node the data needed to perform given action. | 820 """Retrieve from node the data needed to perform given action. |
698 # TODO: it would be better to not have a specific way to retrieve | 826 # TODO: it would be better to not have a specific way to retrieve |
699 # data for each action, but instead to have a generic method to | 827 # data for each action, but instead to have a generic method to |
700 # extract any kind of data structure from the 'internal_data' element. | 828 # extract any kind of data structure from the 'internal_data' element. |
701 | 829 |
702 try: # data is stored in the first 'internal_data' element of the node | 830 try: # data is stored in the first 'internal_data' element of the node |
703 data_elts = node.getElementsByTagName('internal_data')[0].childNodes | 831 data_elts = node.getElementsByTagName("internal_data")[0].childNodes |
704 except IndexError: | 832 except IndexError: |
705 return None | 833 return None |
706 data = {} | 834 data = {} |
707 if action == 'groups_of_contact': # return a dict(key: string, value: list[string]) | 835 if ( |
836 action == "groups_of_contact" | |
837 ): # return a dict(key: string, value: list[string]) | |
708 for elt in data_elts: | 838 for elt in data_elts: |
709 jid_s = elt.getAttribute('name') | 839 jid_s = elt.getAttribute("name") |
710 data[jid_s] = [] | 840 data[jid_s] = [] |
711 for value_elt in elt.childNodes: | 841 for value_elt in elt.childNodes: |
712 data[jid_s].append(value_elt.getAttribute('name')) | 842 data[jid_s].append(value_elt.getAttribute("name")) |
713 return data | 843 return data |
714 | 844 |
715 def onFormSubmitted(self, ignore=None): | 845 def onFormSubmitted(self, ignore=None): |
716 """An XMLUI form has been submited | 846 """An XMLUI form has been submited |
717 | 847 |
719 """ | 849 """ |
720 selected_values = [] | 850 selected_values = [] |
721 for ctrl_name in self.ctrl_list: | 851 for ctrl_name in self.ctrl_list: |
722 escaped = self.escape(ctrl_name) | 852 escaped = self.escape(ctrl_name) |
723 ctrl = self.ctrl_list[ctrl_name] | 853 ctrl = self.ctrl_list[ctrl_name] |
724 if isinstance(ctrl['control'], ListWidget): | 854 if isinstance(ctrl["control"], ListWidget): |
725 selected_values.append((escaped, u'\t'.join(ctrl['control']._xmluiGetSelectedValues()))) | 855 selected_values.append( |
856 (escaped, u"\t".join(ctrl["control"]._xmluiGetSelectedValues())) | |
857 ) | |
726 else: | 858 else: |
727 selected_values.append((escaped, ctrl['control']._xmluiGetValue())) | 859 selected_values.append((escaped, ctrl["control"]._xmluiGetValue())) |
728 if self.submit_id is not None: | 860 if self.submit_id is not None: |
729 data = dict(selected_values) | 861 data = dict(selected_values) |
730 self.submit(data) | 862 self.submit(data) |
731 else: | 863 else: |
732 log.warning(_("The form data is not sent back, the type is not managed properly")) | 864 log.warning( |
865 _("The form data is not sent back, the type is not managed properly") | |
866 ) | |
733 self._xmluiClose() | 867 self._xmluiClose() |
734 | 868 |
735 def onFormCancelled(self, ignore=None): | 869 def onFormCancelled(self, ignore=None): |
736 """Called when a form is cancelled""" | 870 """Called when a form is cancelled""" |
737 log.debug(_("Cancelling form")) | 871 log.debug(_("Cancelling form")) |
738 if self.submit_id is not None: | 872 if self.submit_id is not None: |
739 data = {C.XMLUI_DATA_CANCELLED: C.BOOL_TRUE} | 873 data = {C.XMLUI_DATA_CANCELLED: C.BOOL_TRUE} |
740 self.submit(data) | 874 self.submit(data) |
741 else: | 875 else: |
742 log.warning(_("The form data is not sent back, the type is not managed properly")) | 876 log.warning( |
877 _("The form data is not sent back, the type is not managed properly") | |
878 ) | |
743 self._xmluiClose() | 879 self._xmluiClose() |
744 | 880 |
745 def onSaveParams(self, ignore=None): | 881 def onSaveParams(self, ignore=None): |
746 """Params are saved, we send them to backend | 882 """Params are saved, we send them to backend |
747 | 883 |
748 self.type must be param | 884 self.type must be param |
749 """ | 885 """ |
750 assert self.type == 'param' | 886 assert self.type == "param" |
751 for ctrl in self.param_changed: | 887 for ctrl in self.param_changed: |
752 if isinstance(ctrl, ListWidget): | 888 if isinstance(ctrl, ListWidget): |
753 value = u'\t'.join(ctrl._xmluiGetSelectedValues()) | 889 value = u"\t".join(ctrl._xmluiGetSelectedValues()) |
754 else: | 890 else: |
755 value = ctrl._xmluiGetValue() | 891 value = ctrl._xmluiGetValue() |
756 param_name = ctrl._xmlui_name.split(C.SAT_PARAM_SEPARATOR)[1] | 892 param_name = ctrl._xmlui_name.split(C.SAT_PARAM_SEPARATOR)[1] |
757 self._xmluiSetParam(param_name, value, ctrl._param_category) | 893 self._xmluiSetParam(param_name, value, ctrl._param_category) |
758 | 894 |
763 | 899 |
764 | 900 |
765 class XMLUIDialog(XMLUIBase): | 901 class XMLUIDialog(XMLUIBase): |
766 dialog_factory = None | 902 dialog_factory = None |
767 | 903 |
768 def __init__(self, host, parsed_dom, title=None, flags=None, callback=None, ignore=None, whitelist=None, profile=C.PROF_KEY_NONE): | 904 def __init__( |
769 super(XMLUIDialog, self).__init__(host, parsed_dom, title=title, flags=flags, callback=callback, profile=profile) | 905 self, |
770 top=parsed_dom.documentElement | 906 host, |
771 dlg_elt = self._getChildNode(top, "dialog") | 907 parsed_dom, |
908 title=None, | |
909 flags=None, | |
910 callback=None, | |
911 ignore=None, | |
912 whitelist=None, | |
913 profile=C.PROF_KEY_NONE, | |
914 ): | |
915 super(XMLUIDialog, self).__init__( | |
916 host, parsed_dom, title=title, flags=flags, callback=callback, profile=profile | |
917 ) | |
918 top = parsed_dom.documentElement | |
919 dlg_elt = self._getChildNode(top, "dialog") | |
772 if dlg_elt is None: | 920 if dlg_elt is None: |
773 raise ValueError("Invalid XMLUI: no Dialog element found !") | 921 raise ValueError("Invalid XMLUI: no Dialog element found !") |
774 dlg_type = dlg_elt.getAttribute("type") or C.XMLUI_DIALOG_MESSAGE | 922 dlg_type = dlg_elt.getAttribute("type") or C.XMLUI_DIALOG_MESSAGE |
775 try: | 923 try: |
776 mess_elt = self._getChildNode(dlg_elt, C.XMLUI_DATA_MESS) | 924 mess_elt = self._getChildNode(dlg_elt, C.XMLUI_DATA_MESS) |
777 message = getText(mess_elt) | 925 message = getText(mess_elt) |
778 except (TypeError, AttributeError): # XXX: TypeError is here because pyjamas raise a TypeError instead of an AttributeError | 926 except ( |
927 TypeError, | |
928 AttributeError, | |
929 ): # XXX: TypeError is here because pyjamas raise a TypeError instead of an AttributeError | |
779 message = "" | 930 message = "" |
780 level = dlg_elt.getAttribute(C.XMLUI_DATA_LVL) or C.XMLUI_DATA_LVL_INFO | 931 level = dlg_elt.getAttribute(C.XMLUI_DATA_LVL) or C.XMLUI_DATA_LVL_INFO |
781 | 932 |
782 if dlg_type == C.XMLUI_DIALOG_MESSAGE: | 933 if dlg_type == C.XMLUI_DIALOG_MESSAGE: |
783 self.dlg = self.dialog_factory.createMessageDialog(self, self.xmlui_title, message, level) | 934 self.dlg = self.dialog_factory.createMessageDialog( |
935 self, self.xmlui_title, message, level | |
936 ) | |
784 elif dlg_type == C.XMLUI_DIALOG_NOTE: | 937 elif dlg_type == C.XMLUI_DIALOG_NOTE: |
785 self.dlg = self.dialog_factory.createNoteDialog(self, self.xmlui_title, message, level) | 938 self.dlg = self.dialog_factory.createNoteDialog( |
939 self, self.xmlui_title, message, level | |
940 ) | |
786 elif dlg_type == C.XMLUI_DIALOG_CONFIRM: | 941 elif dlg_type == C.XMLUI_DIALOG_CONFIRM: |
787 try: | 942 try: |
788 buttons_elt = self._getChildNode(dlg_elt, "buttons") | 943 buttons_elt = self._getChildNode(dlg_elt, "buttons") |
789 buttons_set = buttons_elt.getAttribute("set") or C.XMLUI_DATA_BTNS_SET_DEFAULT | 944 buttons_set = ( |
790 except (TypeError, AttributeError): # XXX: TypeError is here because pyjamas raise a TypeError instead of an AttributeError | 945 buttons_elt.getAttribute("set") or C.XMLUI_DATA_BTNS_SET_DEFAULT |
946 ) | |
947 except ( | |
948 TypeError, | |
949 AttributeError, | |
950 ): # XXX: TypeError is here because pyjamas raise a TypeError instead of an AttributeError | |
791 buttons_set = C.XMLUI_DATA_BTNS_SET_DEFAULT | 951 buttons_set = C.XMLUI_DATA_BTNS_SET_DEFAULT |
792 self.dlg = self.dialog_factory.createConfirmDialog(self, self.xmlui_title, message, level, buttons_set) | 952 self.dlg = self.dialog_factory.createConfirmDialog( |
953 self, self.xmlui_title, message, level, buttons_set | |
954 ) | |
793 elif dlg_type == C.XMLUI_DIALOG_FILE: | 955 elif dlg_type == C.XMLUI_DIALOG_FILE: |
794 try: | 956 try: |
795 file_elt = self._getChildNode(dlg_elt, "file") | 957 file_elt = self._getChildNode(dlg_elt, "file") |
796 filetype = file_elt.getAttribute("type") or C.XMLUI_DATA_FILETYPE_DEFAULT | 958 filetype = file_elt.getAttribute("type") or C.XMLUI_DATA_FILETYPE_DEFAULT |
797 except (TypeError, AttributeError): # XXX: TypeError is here because pyjamas raise a TypeError instead of an AttributeError | 959 except ( |
960 TypeError, | |
961 AttributeError, | |
962 ): # XXX: TypeError is here because pyjamas raise a TypeError instead of an AttributeError | |
798 filetype = C.XMLUI_DATA_FILETYPE_DEFAULT | 963 filetype = C.XMLUI_DATA_FILETYPE_DEFAULT |
799 self.dlg = self.dialog_factory.createFileDialog(self, self.xmlui_title, message, level, filetype) | 964 self.dlg = self.dialog_factory.createFileDialog( |
965 self, self.xmlui_title, message, level, filetype | |
966 ) | |
800 else: | 967 else: |
801 raise ValueError("Unknown dialog type [%s]" % dlg_type) | 968 raise ValueError("Unknown dialog type [%s]" % dlg_type) |
802 | 969 |
803 def show(self): | 970 def show(self): |
804 self.dlg._xmluiShow() | 971 self.dlg._xmluiShow() |
817 """ | 984 """ |
818 assert type_ in (CLASS_PANEL, CLASS_DIALOG) | 985 assert type_ in (CLASS_PANEL, CLASS_DIALOG) |
819 class_map[type_] = class_ | 986 class_map[type_] = class_ |
820 | 987 |
821 | 988 |
822 def create(host, xml_data, title=None, flags=None, dom_parse=None, dom_free=None, callback=None, ignore=None, whitelist=None, profile=C.PROF_KEY_NONE): | 989 def create( |
990 host, | |
991 xml_data, | |
992 title=None, | |
993 flags=None, | |
994 dom_parse=None, | |
995 dom_free=None, | |
996 callback=None, | |
997 ignore=None, | |
998 whitelist=None, | |
999 profile=C.PROF_KEY_NONE, | |
1000 ): | |
823 """ | 1001 """ |
824 @param dom_parse: methode equivalent to minidom.parseString (but which must manage unicode), or None to use default one | 1002 @param dom_parse: methode equivalent to minidom.parseString (but which must manage unicode), or None to use default one |
825 @param dom_free: method used to free the parsed DOM | 1003 @param dom_free: method used to free the parsed DOM |
826 @param ignore(list[unicode], None): name of widgets to ignore | 1004 @param ignore(list[unicode], None): name of widgets to ignore |
827 widgets with name in this list and their label will be ignored | 1005 widgets with name in this list and their label will be ignored |
829 when not None, only widgets in this list and their label will be kept | 1007 when not None, only widgets in this list and their label will be kept |
830 mutually exclusive with ignore | 1008 mutually exclusive with ignore |
831 """ | 1009 """ |
832 if dom_parse is None: | 1010 if dom_parse is None: |
833 from xml.dom import minidom | 1011 from xml.dom import minidom |
834 dom_parse = lambda xml_data: minidom.parseString(xml_data.encode('utf-8')) | 1012 |
1013 dom_parse = lambda xml_data: minidom.parseString(xml_data.encode("utf-8")) | |
835 dom_free = lambda parsed_dom: parsed_dom.unlink() | 1014 dom_free = lambda parsed_dom: parsed_dom.unlink() |
836 else: | 1015 else: |
837 dom_parse = dom_parse | 1016 dom_parse = dom_parse |
838 dom_free = dom_free or (lambda parsed_dom: None) | 1017 dom_free = dom_free or (lambda parsed_dom: None) |
839 parsed_dom = dom_parse(xml_data) | 1018 parsed_dom = dom_parse(xml_data) |
840 top=parsed_dom.documentElement | 1019 top = parsed_dom.documentElement |
841 ui_type = top.getAttribute("type") | 1020 ui_type = top.getAttribute("type") |
842 try: | 1021 try: |
843 if ui_type != C.XMLUI_DIALOG: | 1022 if ui_type != C.XMLUI_DIALOG: |
844 cls = class_map[CLASS_PANEL] | 1023 cls = class_map[CLASS_PANEL] |
845 else: | 1024 else: |
846 cls = class_map[CLASS_DIALOG] | 1025 cls = class_map[CLASS_DIALOG] |
847 except KeyError: | 1026 except KeyError: |
848 raise ClassNotRegistedError(_("You must register classes with registerClass before creating a XMLUI")) | 1027 raise ClassNotRegistedError( |
849 | 1028 _("You must register classes with registerClass before creating a XMLUI") |
850 xmlui = cls(host, parsed_dom, | 1029 ) |
851 title = title, | 1030 |
852 flags = flags, | 1031 xmlui = cls( |
853 callback = callback, | 1032 host, |
854 ignore = ignore, | 1033 parsed_dom, |
855 whitelist = whitelist, | 1034 title=title, |
856 profile = profile) | 1035 flags=flags, |
1036 callback=callback, | |
1037 ignore=ignore, | |
1038 whitelist=whitelist, | |
1039 profile=profile, | |
1040 ) | |
857 dom_free(parsed_dom) | 1041 dom_free(parsed_dom) |
858 return xmlui | 1042 return xmlui |