comparison src/browser/sat_browser/xmlui.py @ 500:67a4e8383b70

browser side (XMLUI): XMLUI update to follow core changes: - Dialogs are now managed - FileDialog raise a NotImplementedError, it's not yet possible in Libervia - XMLUIPanel.show is implemented - following core changes, we now create an XMLUI with xmlui.create(...) - WidgetFactory now inherit from GenericFactory - workaround for __getattr__ bug in pyjamas, now createXXX are automaticaly created with inspection
author Goffi <goffi@goffi.org>
date Wed, 13 Aug 2014 14:09:09 +0200
parents 1ce6133993e4
children f030491cff75
comparison
equal deleted inserted replaced
499:ec3f30253040 500:67a4e8383b70
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.log import getLogger 20 from sat.core.log import getLogger
21 log = getLogger(__name__) 21 log = getLogger(__name__)
22 from sat_frontends.tools import xmlui 22 from sat_frontends.tools import xmlui
23 from sat_browser.constants import Const as C
24 from sat_browser import dialog
23 25
24 from pyjamas.ui.VerticalPanel import VerticalPanel 26 from pyjamas.ui.VerticalPanel import VerticalPanel
25 from pyjamas.ui.HorizontalPanel import HorizontalPanel 27 from pyjamas.ui.HorizontalPanel import HorizontalPanel
26 from pyjamas.ui.TabPanel import TabPanel 28 from pyjamas.ui.TabPanel import TabPanel
27 from pyjamas.ui.Grid import Grid 29 from pyjamas.ui.Grid import Grid
37 import nativedom 39 import nativedom
38 40
39 41
40 class EmptyWidget(xmlui.EmptyWidget, Label): 42 class EmptyWidget(xmlui.EmptyWidget, Label):
41 43
42 def __init__(self, parent): 44 def __init__(self, _xmlui_parent):
43 Label.__init__(self, '') 45 Label.__init__(self, '')
44 46
45 47
46 class TextWidget(xmlui.TextWidget, Label): 48 class TextWidget(xmlui.TextWidget, Label):
47 49
48 def __init__(self, parent, value): 50 def __init__(self, _xmlui_parent, value):
49 Label.__init__(self, value) 51 Label.__init__(self, value)
50 52
51 53
52 class LabelWidget(xmlui.LabelWidget, TextWidget): 54 class LabelWidget(xmlui.LabelWidget, TextWidget):
53 55
54 def __init__(self, parent, value): 56 def __init__(self, _xmlui_parent, value):
55 TextWidget.__init__(self, parent, value + ": ") 57 TextWidget.__init__(self, _xmlui_parent, value + ": ")
56 58
57 59
58 class JidWidget(xmlui.JidWidget, TextWidget): 60 class JidWidget(xmlui.JidWidget, TextWidget):
59 61
60 def __init__(self, parent, value): 62 def __init__(self, _xmlui_parent, value):
61 TextWidget.__init__(self, parent, value) 63 TextWidget.__init__(self, _xmlui_parent, value)
62 64
63 65
64 class DividerWidget(xmlui.DividerWidget, HTML): 66 class DividerWidget(xmlui.DividerWidget, HTML):
65 67
66 def __init__(self, parent, style='line'): 68 def __init__(self, _xmlui_parent, style='line'):
67 """Add a divider 69 """Add a divider
68 70
69 @param parent 71 @param _xmlui_parent
70 @param style (string): one of: 72 @param style (string): one of:
71 - line: a simple line 73 - line: a simple line
72 - dot: a line of dots 74 - dot: a line of dots
73 - dash: a line of dashes 75 - dash: a line of dashes
74 - plain: a full thick line 76 - plain: a full thick line
78 self.addStyleName(style) 80 self.addStyleName(style)
79 81
80 82
81 class StringWidget(xmlui.StringWidget, TextBox): 83 class StringWidget(xmlui.StringWidget, TextBox):
82 84
83 def __init__(self, parent, value, read_only=False): 85 def __init__(self, _xmlui_parent, value, read_only=False):
84 TextBox.__init__(self) 86 TextBox.__init__(self)
85 self.setText(value) 87 self.setText(value)
86 self.setReadonly(read_only) 88 self.setReadonly(read_only)
87 89
88 def _xmluiSetValue(self, value): 90 def _xmluiSetValue(self, value):
95 self.addChangeListener(callback) 97 self.addChangeListener(callback)
96 98
97 99
98 class PasswordWidget(xmlui.PasswordWidget, PasswordTextBox): 100 class PasswordWidget(xmlui.PasswordWidget, PasswordTextBox):
99 101
100 def __init__(self, parent, value, read_only=False): 102 def __init__(self, _xmlui_parent, value, read_only=False):
101 PasswordTextBox.__init__(self) 103 PasswordTextBox.__init__(self)
102 self.setText(value) 104 self.setText(value)
103 self.setReadonly(read_only) 105 self.setReadonly(read_only)
104 106
105 def _xmluiSetValue(self, value): 107 def _xmluiSetValue(self, value):
112 self.addChangeListener(callback) 114 self.addChangeListener(callback)
113 115
114 116
115 class TextBoxWidget(xmlui.TextBoxWidget, TextArea): 117 class TextBoxWidget(xmlui.TextBoxWidget, TextArea):
116 118
117 def __init__(self, parent, value, read_only=False): 119 def __init__(self, _xmlui_parent, value, read_only=False):
118 TextArea.__init__(self) 120 TextArea.__init__(self)
119 self.setText(value) 121 self.setText(value)
120 self.setReadonly(read_only) 122 self.setReadonly(read_only)
121 123
122 def _xmluiSetValue(self, value): 124 def _xmluiSetValue(self, value):
129 self.addChangeListener(callback) 131 self.addChangeListener(callback)
130 132
131 133
132 class BoolWidget(xmlui.BoolWidget, CheckBox): 134 class BoolWidget(xmlui.BoolWidget, CheckBox):
133 135
134 def __init__(self, parent, state, read_only=False): 136 def __init__(self, _xmlui_parent, state, read_only=False):
135 CheckBox.__init__(self) 137 CheckBox.__init__(self)
136 self.setChecked(state) 138 self.setChecked(state)
137 self.setReadonly(read_only) 139 self.setReadonly(read_only)
138 140
139 def _xmluiSetValue(self, value): 141 def _xmluiSetValue(self, value):
146 self.addClickListener(callback) 148 self.addClickListener(callback)
147 149
148 150
149 class ButtonWidget(xmlui.ButtonWidget, Button): 151 class ButtonWidget(xmlui.ButtonWidget, Button):
150 152
151 def __init__(self, parent, value, click_callback): 153 def __init__(self, _xmlui_parent, value, click_callback):
152 Button.__init__(self, value, click_callback) 154 Button.__init__(self, value, click_callback)
153 155
154 def _xmluiOnClick(self, callback): 156 def _xmluiOnClick(self, callback):
155 self.addClickListener(callback) 157 self.addClickListener(callback)
156 158
157 159
158 class ListWidget(xmlui.ListWidget, ListBox): 160 class ListWidget(xmlui.ListWidget, ListBox):
159 161
160 def __init__(self, parent, options, selected, flags): 162 def __init__(self, _xmlui_parent, options, selected, flags):
161 ListBox.__init__(self) 163 ListBox.__init__(self)
162 multi_selection = 'single' not in flags 164 multi_selection = 'single' not in flags
163 self.setMultipleSelect(multi_selection) 165 self.setMultipleSelect(multi_selection)
164 if multi_selection: 166 if multi_selection:
165 self.setVisibleItemCount(5) 167 self.setVisibleItemCount(5)
207 self.append(widget) 209 self.append(widget)
208 210
209 211
210 class AdvancedListContainer(xmlui.AdvancedListContainer, Grid): 212 class AdvancedListContainer(xmlui.AdvancedListContainer, Grid):
211 213
212 def __init__(self, parent, columns, selectable='no'): 214 def __init__(self, _xmlui_parent, columns, selectable='no'):
213 Grid.__init__(self, 0, columns) 215 Grid.__init__(self, 0, columns)
214 self.columns = columns 216 self.columns = columns
215 self.row = -1 217 self.row = -1
216 self.col = 0 218 self.col = 0
217 self._xmlui_rows_idx = [] 219 self._xmlui_rows_idx = []
253 self._xmlui_select_cb = callback 255 self._xmlui_select_cb = callback
254 256
255 257
256 class PairsContainer(xmlui.PairsContainer, Grid): 258 class PairsContainer(xmlui.PairsContainer, Grid):
257 259
258 def __init__(self, parent): 260 def __init__(self, _xmlui_parent):
259 Grid.__init__(self, 0, 0) 261 Grid.__init__(self, 0, 0)
260 self.row = 0 262 self.row = 0
261 self.col = 0 263 self.col = 0
262 264
263 def _xmluiAppend(self, widget): 265 def _xmluiAppend(self, widget):
270 self.col = 0 272 self.col = 0
271 273
272 274
273 class TabsContainer(LiberviaContainer, xmlui.TabsContainer, TabPanel): 275 class TabsContainer(LiberviaContainer, xmlui.TabsContainer, TabPanel):
274 276
275 def __init__(self, parent): 277 def __init__(self, _xmlui_parent):
276 TabPanel.__init__(self) 278 TabPanel.__init__(self)
277 self.setStyleName('liberviaTabPanel') 279 self.setStyleName('liberviaTabPanel')
278 280
279 def _xmluiAddTab(self, label): 281 def _xmluiAddTab(self, label):
280 tab_panel = VerticalContainer(self) 282 tab_panel = VerticalContainer(self)
285 287
286 288
287 class VerticalContainer(LiberviaContainer, xmlui.VerticalContainer, VerticalPanel): 289 class VerticalContainer(LiberviaContainer, xmlui.VerticalContainer, VerticalPanel):
288 __bases__ = (LiberviaContainer, xmlui.VerticalContainer, VerticalPanel) 290 __bases__ = (LiberviaContainer, xmlui.VerticalContainer, VerticalPanel)
289 291
290 def __init__(self, parent): 292 def __init__(self, _xmlui_parent):
291 VerticalPanel.__init__(self) 293 VerticalPanel.__init__(self)
292 294
293 295
294 class WidgetFactory(object): 296 ## Dialogs ##
295 # XXX: __getattr__ doesn't work here for an unknown reason 297
296 298
297 def createVerticalContainer(self, *args, **kwargs): 299 class Dlg(object):
298 instance = VerticalContainer(*args, **kwargs) 300
299 instance._xmlui_main = self._xmlui_main 301 def _xmluiShow(self):
302 self.show()
303
304 def _xmluiClose(self):
305 pass
306
307
308 class MessageDialog(Dlg, xmlui.MessageDialog, dialog.InfoDialog):
309
310 def __init__(self, _xmlui_parent, title, message, level):
311 #TODO: level is not managed
312 Dlg.__init__(self)
313 xmlui.MessageDialog.__init__(self, _xmlui_parent)
314 dialog.InfoDialog.__init__(self, title, message, self._xmluiValidated())
315
316
317 class NoteDialog(xmlui.NoteDialog, MessageDialog):
318 # TODO: separate NoteDialog
319
320 def __init__(self, _xmlui_parent, title, message, level):
321 xmlui.NoteDialog.__init__(self, _xmlui_parent)
322 MessageDialog.__init__(self, _xmlui_parent, title, message, level)
323
324
325 class ConfirmDialog(xmlui.ConfirmDialog, Dlg, dialog.ConfirmDialog):
326
327 def __init__(self, _xmlui_parent, title, message, level):
328 #TODO: level is not managed
329 xmlui.ConfirmDialog.__init__(self, _xmlui_parent)
330 print "self.parent = %s" % self._xmlui_parent
331 Dlg.__init__(self)
332 dialog.ConfirmDialog.__init__(self, self.answered, message, title)
333
334 def answered(self, validated):
335 if validated:
336 self._xmluiValidated()
337 else:
338 self._xmluiCancelled()
339
340
341 class FileDialog(xmlui.FileDialog, Dlg):
342 #TODO:
343
344 def __init__(self, _xmlui_parent, title, message, level, filetype):
345 raise NotImplementedError("FileDialog is not implemented in Libervia yet")
346
347
348 class GenericFactory(object):
349 # XXX: __getattr__ doens't work here with pyjamas for an unknown reason
350 # so an introspection workaround is used
351
352 def __init__(self):
353
354 for name, cls in globals().items():
355 if name.endswith("Widget") or name.endswith("Container") or name.endswith("Dialog"):
356 log.info("registering: %s" % name)
357 def createCreater(cls):
358 return lambda *args, **kwargs: self._genericCreate(cls, *args, **kwargs)
359 setattr(self, "create%s" % name, createCreater(cls))
360
361 def _genericCreate(self, cls, *args, **kwargs):
362 instance = cls(*args, **kwargs)
300 return instance 363 return instance
301
302 def createPairsContainer(self, *args, **kwargs):
303 instance = PairsContainer(*args, **kwargs)
304 instance._xmlui_main = self._xmlui_main
305 return instance
306
307 def createTabsContainer(self, *args, **kwargs):
308 instance = TabsContainer(*args, **kwargs)
309 instance._xmlui_main = self._xmlui_main
310 return instance
311
312 def createAdvancedListContainer(self, *args, **kwargs):
313 instance = AdvancedListContainer(*args, **kwargs)
314 instance._xmlui_main = self._xmlui_main
315 return instance
316
317 def createEmptyWidget(self, *args, **kwargs):
318 instance = EmptyWidget(*args, **kwargs)
319 instance._xmlui_main = self._xmlui_main
320 return instance
321
322 def createTextWidget(self, *args, **kwargs):
323 instance = TextWidget(*args, **kwargs)
324 instance._xmlui_main = self._xmlui_main
325 return instance
326
327 def createLabelWidget(self, *args, **kwargs):
328 instance = LabelWidget(*args, **kwargs)
329 instance._xmlui_main = self._xmlui_main
330 return instance
331
332 def createJidWidget(self, *args, **kwargs):
333 instance = JidWidget(*args, **kwargs)
334 instance._xmlui_main = self._xmlui_main
335 return instance
336
337 def createDividerWidget(self, *args, **kwargs):
338 instance = DividerWidget(*args, **kwargs)
339 instance._xmlui_main = self._xmlui_main
340 return instance
341
342 def createStringWidget(self, *args, **kwargs):
343 instance = StringWidget(*args, **kwargs)
344 instance._xmlui_main = self._xmlui_main
345 return instance
346
347 def createPasswordWidget(self, *args, **kwargs):
348 instance = PasswordWidget(*args, **kwargs)
349 instance._xmlui_main = self._xmlui_main
350 return instance
351
352 def createTextBoxWidget(self, *args, **kwargs):
353 instance = TextBoxWidget(*args, **kwargs)
354 instance._xmlui_main = self._xmlui_main
355 return instance
356
357 def createBoolWidget(self, *args, **kwargs):
358 instance = BoolWidget(*args, **kwargs)
359 instance._xmlui_main = self._xmlui_main
360 return instance
361
362 def createButtonWidget(self, *args, **kwargs):
363 instance = ButtonWidget(*args, **kwargs)
364 instance._xmlui_main = self._xmlui_main
365 return instance
366
367 def createListWidget(self, *args, **kwargs):
368 instance = ListWidget(*args, **kwargs)
369 instance._xmlui_main = self._xmlui_main
370 return instance
371
372 364
373 # def __getattr__(self, attr): 365 # def __getattr__(self, attr):
374 # if attr.startswith("create"): 366 # if attr.startswith("create"):
375 # cls = globals()[attr[6:]] 367 # cls = globals()[attr[6:]]
376 # cls._xmlui_main = self._xmlui_main 368 # cls._xmlui_main = self._xmlui_main
377 # return cls 369 # return cls
378 370
379 371
380 class XMLUI(xmlui.XMLUI, VerticalPanel): 372 class WidgetFactory(GenericFactory):
373
374 def _genericCreate(self, cls, *args, **kwargs):
375 instance = GenericFactory._genericCreate(self, cls, *args, **kwargs)
376 instance._xmlui_main = self._xmlui_main
377 return instance
378
379 class LiberviaXMLUIBase(object):
380
381 def _xmluiLaunchAction(self, action_id, data):
382 self.host.launchAction(action_id, data)
383
384
385 class XMLUIPanel(LiberviaXMLUIBase, xmlui.XMLUIPanel, VerticalPanel):
381 widget_factory = WidgetFactory() 386 widget_factory = WidgetFactory()
382 387
383 def __init__(self, host, xml_data, title=None, flags=None): 388 def __init__(self, host, parsed_xml, title=None, flags=None):
384 self.widget_factory._xmlui_main = self 389 self.widget_factory._xmlui_main = self
385 self.dom = nativedom.NativeDOM()
386 dom_parse = lambda xml_data: self.dom.parseString(xml_data)
387 VerticalPanel.__init__(self) 390 VerticalPanel.__init__(self)
388 self.setSize('100%', '100%') 391 self.setSize('100%', '100%')
389 xmlui.XMLUI.__init__(self, host, xml_data, title, flags, dom_parse) 392 xmlui.XMLUIPanel.__init__(self, host, parsed_xml, title, flags)
390 393
391 def setCloseCb(self, close_cb): 394 def setCloseCb(self, close_cb):
392 self.close_cb = close_cb 395 self.close_cb = close_cb
393 396
394 def _xmluiClose(self): 397 def _xmluiClose(self):
395 if self.close_cb: 398 if self.close_cb:
396 self.close_cb() 399 self.close_cb()
397 else: 400 else:
398 log.warning("no close method defined") 401 log.warning("no close method defined")
399 402
400 def _xmluiLaunchAction(self, action_id, data):
401 self.host.launchAction(action_id, data)
402
403 def _xmluiSetParam(self, name, value, category): 403 def _xmluiSetParam(self, name, value, category):
404 self.host.bridge.call('setParam', None, name, value, category) 404 self.host.bridge.call('setParam', None, name, value, category)
405 405
406 def constructUI(self, xml_data): 406 def constructUI(self, parsed_dom):
407 super(XMLUI, self).constructUI(xml_data) 407 super(XMLUIPanel, self).constructUI(parsed_dom)
408 self.add(self.main_cont) 408 self.add(self.main_cont)
409 self.setCellHeight(self.main_cont, '100%') 409 self.setCellHeight(self.main_cont, '100%')
410 if self.type == 'form': 410 if self.type == 'form':
411 hpanel = HorizontalPanel() 411 hpanel = HorizontalPanel()
412 hpanel.setStyleName('marginAuto') 412 hpanel.setStyleName('marginAuto')
418 assert(isinstance(self.children[0][0], TabPanel)) 418 assert(isinstance(self.children[0][0], TabPanel))
419 hpanel = HorizontalPanel() 419 hpanel = HorizontalPanel()
420 hpanel.add(Button('Save', self.onSaveParams)) 420 hpanel.add(Button('Save', self.onSaveParams))
421 hpanel.add(Button('Cancel', lambda ignore: self._xmluiClose())) 421 hpanel.add(Button('Cancel', lambda ignore: self._xmluiClose()))
422 self.add(hpanel) 422 self.add(hpanel)
423
424 def show(self):
425 options = ['NO_CLOSE'] if self.type == C.XMLUI_FORM else []
426 _dialog = dialog.GenericDialog(self.title, self, options=options)
427 self.setCloseCb(_dialog.close)
428 _dialog.show()
429
430
431 class XMLUIDialog(LiberviaXMLUIBase, xmlui.XMLUIDialog):
432 dialog_factory = GenericFactory()
433
434 def __init__(self, host, parsed_dom, title = None, flags = None):
435 xmlui.XMLUIDialog.__init__(self, host, parsed_dom, title, flags)
436
437 xmlui.registerClass(xmlui.CLASS_PANEL, XMLUIPanel)
438 xmlui.registerClass(xmlui.CLASS_DIALOG, XMLUIDialog)
439
440 def create(*args, **kwargs):
441 dom = nativedom.NativeDOM()
442 kwargs['dom_parse'] = lambda xml_data: dom.parseString(xml_data)
443 return xmlui.create(*args, **kwargs)