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