Mercurial > libervia-backend
comparison sat_frontends/tools/xmlui.py @ 2668:c274201cea94
core, frontends (xmlui): added "hidden" widget, to specify a value to be returned unmodified
author | Goffi <goffi@goffi.org> |
---|---|
date | Fri, 31 Aug 2018 15:57:11 +0200 |
parents | 56f94936df1e |
children | bdb8276fd2da |
comparison
equal
deleted
inserted
replaced
2667:8dd9db785ac8 | 2668:c274201cea94 |
---|---|
27 | 27 |
28 class_map = {} | 28 class_map = {} |
29 CLASS_PANEL = "panel" | 29 CLASS_PANEL = "panel" |
30 CLASS_DIALOG = "dialog" | 30 CLASS_DIALOG = "dialog" |
31 CURRENT_LABEL = "current_label" | 31 CURRENT_LABEL = "current_label" |
32 HIDDEN = "hidden" | |
32 | 33 |
33 | 34 |
34 class InvalidXMLUI(Exception): | 35 class InvalidXMLUI(Exception): |
35 pass | 36 pass |
36 | 37 |
259 """Base class to construct SàT XML User Interface | 260 """Base class to construct SàT XML User Interface |
260 | 261 |
261 This class must not be instancied directly | 262 This class must not be instancied directly |
262 """ | 263 """ |
263 | 264 |
264 def __init__( | 265 def __init__(self, host, parsed_dom, title=None, flags=None, callback=None, |
265 self, | 266 profile=C.PROF_KEY_NONE): |
266 host, | |
267 parsed_dom, | |
268 title=None, | |
269 flags=None, | |
270 callback=None, | |
271 profile=C.PROF_KEY_NONE, | |
272 ): | |
273 """Initialise the XMLUI instance | 267 """Initialise the XMLUI instance |
274 | 268 |
275 @param host: %(doc_host)s | 269 @param host: %(doc_host)s |
276 @param parsed_dom: main parsed dom | 270 @param parsed_dom: main parsed dom |
277 @param title: force the title, or use XMLUI one if None | 271 @param title: force the title, or use XMLUI one if None |
278 @param flags: list of string which can be: | 272 @param flags: list of string which can be: |
279 - NO_CANCEL: the UI can't be cancelled | 273 - NO_CANCEL: the UI can't be cancelled |
280 - FROM_BACKEND: the UI come from backend (i.e. it's not the direct result of user operation) | 274 - FROM_BACKEND: the UI come from backend (i.e. it's not the direct result of |
275 user operation) | |
281 @param callback(callable, None): if not None, will be used with launchAction: | 276 @param callback(callable, None): if not None, will be used with launchAction: |
282 - if None is used, default behaviour will be used (closing the dialog and calling host.actionManager) | 277 - if None is used, default behaviour will be used (closing the dialog and |
278 calling host.actionManager) | |
283 - if a callback is provided, it will be used instead, so you'll have to manage | 279 - if a callback is provided, it will be used instead, so you'll have to manage |
284 dialog closing or new xmlui to display, or other action (you can call host.actionManager) | 280 dialog closing or new xmlui to display, or other action (you can call |
281 host.actionManager) | |
282 The callback will have data, callback_id and profile as arguments | |
285 """ | 283 """ |
286 self.host = host | 284 self.host = host |
287 top = parsed_dom.documentElement | 285 top = parsed_dom.documentElement |
288 self.session_id = top.getAttribute("session_id") or None | 286 self.session_id = top.getAttribute("session_id") or None |
289 self.submit_id = top.getAttribute("submit") or None | 287 self.submit_id = top.getAttribute("submit") or None |
290 self.xmlui_title = title or top.getAttribute("title") or u"" | 288 self.xmlui_title = title or top.getAttribute("title") or u"" |
289 self.hidden = {} | |
291 if flags is None: | 290 if flags is None: |
292 flags = [] | 291 flags = [] |
293 self.flags = flags | 292 self.flags = flags |
294 self.callback = callback or self._defaultCb | 293 self.callback = callback or self._defaultCb |
295 self.profile = profile | 294 self.profile = profile |
331 self._xmluiClose() | 330 self._xmluiClose() |
332 if self.submit_id is None: | 331 if self.submit_id is None: |
333 raise ValueError("Can't submit is self.submit_id is not set") | 332 raise ValueError("Can't submit is self.submit_id is not set") |
334 if "session_id" in data: | 333 if "session_id" in data: |
335 raise ValueError( | 334 raise ValueError( |
336 "session_id must no be used in data, it is automaticaly filled with self.session_id if present" | 335 u"session_id must no be used in data, it is automaticaly filled with " |
336 u"self.session_id if present" | |
337 ) | 337 ) |
338 if self.session_id is not None: | 338 if self.session_id is not None: |
339 data["session_id"] = self.session_id | 339 data["session_id"] = self.session_id |
340 self._xmluiLaunchAction(self.submit_id, data) | 340 self._xmluiLaunchAction(self.submit_id, data) |
341 | 341 |
377 @property dialog_factory: factory to create frontend-specific dialogs | 377 @property dialog_factory: factory to create frontend-specific dialogs |
378 """ | 378 """ |
379 | 379 |
380 widget_factory = None | 380 widget_factory = None |
381 | 381 |
382 def __init__( | 382 def __init__(self, host, parsed_dom, title=None, flags=None, callback=None, |
383 self, | 383 ignore=None, whitelist=None, profile=C.PROF_KEY_NONE): |
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 ): | |
393 """ | 384 """ |
394 | 385 |
395 @param title(unicode, None): title of the | 386 @param title(unicode, None): title of the |
396 @property widgets(dict): widget name => widget map | 387 @property widgets(dict): widget name => widget map |
397 @property widget_value(ValueGetter): retrieve widget value from it's name | 388 @property widget_value(ValueGetter): retrieve widget value from it's name |
414 self._whitelist = whitelist | 405 self._whitelist = whitelist |
415 else: | 406 else: |
416 self._whitelist = None | 407 self._whitelist = None |
417 self.constructUI(parsed_dom) | 408 self.constructUI(parsed_dom) |
418 | 409 |
419 def escape(self, name): | 410 @staticmethod |
411 def escape(name): | |
420 """Return escaped name for forms""" | 412 """Return escaped name for forms""" |
421 return u"%s%s" % (C.SAT_FORM_PREFIX, name) | 413 return u"%s%s" % (C.SAT_FORM_PREFIX, name) |
422 | 414 |
423 @property | 415 @property |
424 def main_cont(self): | 416 def main_cont(self): |
433 def _parseChilds(self, _xmlui_parent, current_node, wanted=("container",), data=None): | 425 def _parseChilds(self, _xmlui_parent, current_node, wanted=("container",), data=None): |
434 """Recursively parse childNodes of an element | 426 """Recursively parse childNodes of an element |
435 | 427 |
436 @param _xmlui_parent: widget container with '_xmluiAppend' method | 428 @param _xmlui_parent: widget container with '_xmluiAppend' method |
437 @param current_node: element from which childs will be parsed | 429 @param current_node: element from which childs will be parsed |
438 @param wanted: list of tag names that can be present in the childs to be SàT XMLUI compliant | 430 @param wanted: list of tag names that can be present in the childs to be SàT XMLUI |
431 compliant | |
439 @param data(None, dict): additionnal data which are needed in some cases | 432 @param data(None, dict): additionnal data which are needed in some cases |
440 """ | 433 """ |
441 for node in current_node.childNodes: | 434 for node in current_node.childNodes: |
442 if data is None: | 435 if data is None: |
443 data = {} | 436 data = {} |
445 raise InvalidXMLUI("Unexpected node: [%s]" % node.nodeName) | 438 raise InvalidXMLUI("Unexpected node: [%s]" % node.nodeName) |
446 | 439 |
447 if node.nodeName == "container": | 440 if node.nodeName == "container": |
448 type_ = node.getAttribute("type") | 441 type_ = node.getAttribute("type") |
449 if _xmlui_parent is self and type_ != "vertical": | 442 if _xmlui_parent is self and type_ != "vertical": |
450 # main container is not a VerticalContainer and we want one, so we create one to wrap it | 443 # main container is not a VerticalContainer and we want one, |
444 # so we create one to wrap it | |
451 _xmlui_parent = self.widget_factory.createVerticalContainer(self) | 445 _xmlui_parent = self.widget_factory.createVerticalContainer(self) |
452 self.main_cont = _xmlui_parent | 446 self.main_cont = _xmlui_parent |
453 if type_ == "tabs": | 447 if type_ == "tabs": |
454 cont = self.widget_factory.createTabsContainer(_xmlui_parent) | 448 cont = self.widget_factory.createTabsContainer(_xmlui_parent) |
455 self._parseChilds(_xmlui_parent, node, ("tab",), {"tabs_cont": cont}) | 449 self._parseChilds(_xmlui_parent, node, ("tab",), {"tabs_cont": cont}) |
555 elif type_ == "text": | 549 elif type_ == "text": |
556 ctrl = self.widget_factory.createTextWidget(_xmlui_parent, value) | 550 ctrl = self.widget_factory.createTextWidget(_xmlui_parent, value) |
557 elif type_ == "label": | 551 elif type_ == "label": |
558 ctrl = self.widget_factory.createLabelWidget(_xmlui_parent, value) | 552 ctrl = self.widget_factory.createLabelWidget(_xmlui_parent, value) |
559 data[CURRENT_LABEL] = ctrl | 553 data[CURRENT_LABEL] = ctrl |
554 elif type_ == "hidden": | |
555 if name in self.hidden: | |
556 raise exceptions.ConflictError(u"Conflict on hidden value with " | |
557 u"name {name}".format(name=name)) | |
558 self.hidden[name] = value | |
559 continue | |
560 elif type_ == "jid": | 560 elif type_ == "jid": |
561 ctrl = self.widget_factory.createJidWidget(_xmlui_parent, value) | 561 ctrl = self.widget_factory.createJidWidget(_xmlui_parent, value) |
562 elif type_ == "divider": | 562 elif type_ == "divider": |
563 style = node.getAttribute("style") or "line" | 563 style = node.getAttribute("style") or "line" |
564 ctrl = self.widget_factory.createDividerWidget(_xmlui_parent, style) | 564 ctrl = self.widget_factory.createDividerWidget(_xmlui_parent, style) |
648 ctrl._xmluiOnChange(self.onParamChange) | 648 ctrl._xmluiOnChange(self.onParamChange) |
649 ctrl._param_category = self._current_category | 649 ctrl._param_category = self._current_category |
650 except ( | 650 except ( |
651 AttributeError, | 651 AttributeError, |
652 TypeError, | 652 TypeError, |
653 ): # XXX: TypeError is here because pyjamas raise a TypeError instead of an AttributeError | 653 ): # XXX: TypeError is here because pyjamas raise a TypeError instead |
654 # of an AttributeError | |
654 if not isinstance( | 655 if not isinstance( |
655 ctrl, (EmptyWidget, TextWidget, LabelWidget, JidWidget) | 656 ctrl, (EmptyWidget, TextWidget, LabelWidget, JidWidget) |
656 ): | 657 ): |
657 log.warning(_("No change listener on [%s]") % ctrl) | 658 log.warning(_("No change listener on [%s]") % ctrl) |
658 | 659 |
855 selected_values.append( | 856 selected_values.append( |
856 (escaped, u"\t".join(ctrl["control"]._xmluiGetSelectedValues())) | 857 (escaped, u"\t".join(ctrl["control"]._xmluiGetSelectedValues())) |
857 ) | 858 ) |
858 else: | 859 else: |
859 selected_values.append((escaped, ctrl["control"]._xmluiGetValue())) | 860 selected_values.append((escaped, ctrl["control"]._xmluiGetValue())) |
861 data = dict(selected_values) | |
862 for key, value in self.hidden.iteritems(): | |
863 data[self.escape(key)] = value | |
864 | |
860 if self.submit_id is not None: | 865 if self.submit_id is not None: |
861 data = dict(selected_values) | |
862 self.submit(data) | 866 self.submit(data) |
863 else: | 867 else: |
864 log.warning( | 868 log.warning( |
865 _("The form data is not sent back, the type is not managed properly") | 869 _("The form data is not sent back, the type is not managed properly") |
866 ) | 870 ) |