comparison frontends/src/primitivus/xmlui.py @ 1106:e2e1e27a3680

frontends: XMLUI refactoring + dialogs: - there are now XMLUIPanel and XMLUIDialog both inheriting from XMLUIBase - following dialogs are managed: - MessageDialog - NoteDialog - ConfirmDialog - FileDialog - XMLUI creation is now made using xmlui.create(...) instead of instanciating directly XMLUI - classes must be registed in frontends - "parent" attribute renamed to "_xmlui_parent" to avoid name conflicts with frontends toolkits
author Goffi <goffi@goffi.org>
date Wed, 13 Aug 2014 14:48:49 +0200
parents 7a39ae3950f7
children 6184779544c7
comparison
equal deleted inserted replaced
1105:018bdd687747 1106:e2e1e27a3680
19 19
20 from sat.core.i18n import _ 20 from sat.core.i18n import _
21 import urwid 21 import urwid
22 import copy 22 import copy
23 from urwid_satext import sat_widgets 23 from urwid_satext import sat_widgets
24 from urwid_satext import files_management
24 from sat.core.log import getLogger 25 from sat.core.log import getLogger
25 log = getLogger(__name__) 26 log = getLogger(__name__)
27 from sat_frontends.primitivus.constants import Const as C
26 from sat_frontends.tools import xmlui 28 from sat_frontends.tools import xmlui
27 29
28 30
29 class PrimitivusEvents(object): 31 class PrimitivusEvents(object):
30 """ Used to manage change event of Primitivus widgets """ 32 """ Used to manage change event of Primitivus widgets """
31 33
32 def _event_callback(self, ctrl, *args, **ktkwargs): 34 def _event_callback(self, ctrl, *args, **kwargs):
33 """" Call xmlui callback and ignore any extra argument """ 35 """" Call xmlui callback and ignore any extra argument """
34 args[-1](ctrl) 36 args[-1](ctrl)
35 37
36 def _xmluiOnChange(self, callback): 38 def _xmluiOnChange(self, callback):
37 """ Call callback with widget as only argument """ 39 """ Call callback with widget as only argument """
38 urwid.connect_signal(self, 'change', self._event_callback, callback) 40 urwid.connect_signal(self, 'change', self._event_callback, callback)
39 41
40 42
41 class PrimitivusEmptyWidget(xmlui.EmptyWidget, urwid.Text): 43 class PrimitivusEmptyWidget(xmlui.EmptyWidget, urwid.Text):
42 44
43 def __init__(self, parent): 45 def __init__(self, _xmlui_parent):
44 urwid.Text.__init__(self, '') 46 urwid.Text.__init__(self, '')
45 47
46 48
47 class PrimitivusTextWidget(xmlui.TextWidget, urwid.Text): 49 class PrimitivusTextWidget(xmlui.TextWidget, urwid.Text):
48 50
49 def __init__(self, parent, value, read_only=False): 51 def __init__(self, _xmlui_parent, value, read_only=False):
50 urwid.Text.__init__(self, value) 52 urwid.Text.__init__(self, value)
51 53
52 54
53 class PrimitivusLabelWidget(xmlui.LabelWidget, PrimitivusTextWidget): 55 class PrimitivusLabelWidget(xmlui.LabelWidget, PrimitivusTextWidget):
54 56
55 def __init__(self, parent, value): 57 def __init__(self, _xmlui_parent, value):
56 super(PrimitivusLabelWidget, self).__init__(parent, value+": ") 58 super(PrimitivusLabelWidget, self).__init__(_xmlui_parent, value+": ")
57 59
58 60
59 class PrimitivusJidWidget(xmlui.JidWidget, PrimitivusTextWidget): 61 class PrimitivusJidWidget(xmlui.JidWidget, PrimitivusTextWidget):
60 pass 62 pass
61 63
62 64
63 class PrimitivusDividerWidget(xmlui.DividerWidget, urwid.Divider): 65 class PrimitivusDividerWidget(xmlui.DividerWidget, urwid.Divider):
64 66
65 def __init__(self, parent, style='line'): 67 def __init__(self, _xmlui_parent, style='line'):
66 if style == 'line': 68 if style == 'line':
67 div_char = u'─' 69 div_char = u'─'
68 elif style == 'dot': 70 elif style == 'dot':
69 div_char = u'·' 71 div_char = u'·'
70 elif style == 'dash': 72 elif style == 'dash':
80 urwid.Divider.__init__(self, div_char) 82 urwid.Divider.__init__(self, div_char)
81 83
82 84
83 class PrimitivusStringWidget(xmlui.StringWidget, sat_widgets.AdvancedEdit, PrimitivusEvents): 85 class PrimitivusStringWidget(xmlui.StringWidget, sat_widgets.AdvancedEdit, PrimitivusEvents):
84 86
85 def __init__(self, parent, value, read_only=False): 87 def __init__(self, _xmlui_parent, value, read_only=False):
86 sat_widgets.AdvancedEdit.__init__(self, edit_text=value) 88 sat_widgets.AdvancedEdit.__init__(self, edit_text=value)
87 self.read_only = read_only 89 self.read_only = read_only
88 90
89 def selectable(self): 91 def selectable(self):
90 if self.read_only: 92 if self.read_only:
98 return self.get_edit_text() 100 return self.get_edit_text()
99 101
100 102
101 class PrimitivusPasswordWidget(xmlui.PasswordWidget, sat_widgets.Password, PrimitivusEvents): 103 class PrimitivusPasswordWidget(xmlui.PasswordWidget, sat_widgets.Password, PrimitivusEvents):
102 104
103 def __init__(self, parent, value, read_only=False): 105 def __init__(self, _xmlui_parent, value, read_only=False):
104 sat_widgets.Password.__init__(self, edit_text=value) 106 sat_widgets.Password.__init__(self, edit_text=value)
105 self.read_only = read_only 107 self.read_only = read_only
106 108
107 def selectable(self): 109 def selectable(self):
108 if self.read_only: 110 if self.read_only:
116 return self.get_edit_text() 118 return self.get_edit_text()
117 119
118 120
119 class PrimitivusTextBoxWidget(xmlui.TextBoxWidget, sat_widgets.AdvancedEdit, PrimitivusEvents): 121 class PrimitivusTextBoxWidget(xmlui.TextBoxWidget, sat_widgets.AdvancedEdit, PrimitivusEvents):
120 122
121 def __init__(self, parent, value, read_only=False): 123 def __init__(self, _xmlui_parent, value, read_only=False):
122 sat_widgets.AdvancedEdit.__init__(self, edit_text=value, multiline=True) 124 sat_widgets.AdvancedEdit.__init__(self, edit_text=value, multiline=True)
123 self.read_only = read_only 125 self.read_only = read_only
124 126
125 def selectable(self): 127 def selectable(self):
126 if self.read_only: 128 if self.read_only:
134 return self.get_edit_text() 136 return self.get_edit_text()
135 137
136 138
137 class PrimitivusBoolWidget(xmlui.BoolWidget, urwid.CheckBox, PrimitivusEvents): 139 class PrimitivusBoolWidget(xmlui.BoolWidget, urwid.CheckBox, PrimitivusEvents):
138 140
139 def __init__(self, parent, state, read_only=False): 141 def __init__(self, _xmlui_parent, state, read_only=False):
140 urwid.CheckBox.__init__(self, '', state=state) 142 urwid.CheckBox.__init__(self, '', state=state)
141 self.read_only = read_only 143 self.read_only = read_only
142 144
143 def selectable(self): 145 def selectable(self):
144 if self.read_only: 146 if self.read_only:
152 return "true" if self.get_state() else "false" 154 return "true" if self.get_state() else "false"
153 155
154 156
155 class PrimitivusButtonWidget(xmlui.ButtonWidget, sat_widgets.CustomButton, PrimitivusEvents): 157 class PrimitivusButtonWidget(xmlui.ButtonWidget, sat_widgets.CustomButton, PrimitivusEvents):
156 158
157 def __init__(self, parent, value, click_callback): 159 def __init__(self, _xmlui_parent, value, click_callback):
158 sat_widgets.CustomButton.__init__(self, value, on_press=click_callback) 160 sat_widgets.CustomButton.__init__(self, value, on_press=click_callback)
159 161
160 def _xmluiOnClick(self, callback): 162 def _xmluiOnClick(self, callback):
161 urwid.connect_signal(self, 'click', callback) 163 urwid.connect_signal(self, 'click', callback)
162 164
163 165
164 class PrimitivusListWidget(xmlui.ListWidget, sat_widgets.List, PrimitivusEvents): 166 class PrimitivusListWidget(xmlui.ListWidget, sat_widgets.List, PrimitivusEvents):
165 167
166 def __init__(self, parent, options, selected, flags): 168 def __init__(self, _xmlui_parent, options, selected, flags):
167 sat_widgets.List.__init__(self, options=options, style=flags) 169 sat_widgets.List.__init__(self, options=options, style=flags)
168 self._xmluiSelectValues(selected) 170 self._xmluiSelectValues(selected)
169 171
170 def _xmluiSelectValue(self, value): 172 def _xmluiSelectValue(self, value):
171 return self.selectValue(value) 173 return self.selectValue(value)
192 self._xmluiSelectValues(selected) 194 self._xmluiSelectValues(selected)
193 195
194 196
195 class PrimitivusAdvancedListContainer(xmlui.AdvancedListContainer, sat_widgets.TableContainer, PrimitivusEvents): 197 class PrimitivusAdvancedListContainer(xmlui.AdvancedListContainer, sat_widgets.TableContainer, PrimitivusEvents):
196 198
197 def __init__(self, parent, columns, selectable='no'): 199 def __init__(self, _xmlui_parent, columns, selectable='no'):
198 options = {'ADAPT':()} 200 options = {'ADAPT':()}
199 if selectable != 'no': 201 if selectable != 'no':
200 options['HIGHLIGHT'] = () 202 options['HIGHLIGHT'] = ()
201 sat_widgets.TableContainer.__init__(self, columns=columns, options=options, row_selectable = selectable!='no') 203 sat_widgets.TableContainer.__init__(self, columns=columns, options=options, row_selectable = selectable!='no')
202 204
217 urwid.connect_signal(self, 'click', self._event_callback, callback) 219 urwid.connect_signal(self, 'click', self._event_callback, callback)
218 220
219 221
220 class PrimitivusPairsContainer(xmlui.PairsContainer, sat_widgets.TableContainer): 222 class PrimitivusPairsContainer(xmlui.PairsContainer, sat_widgets.TableContainer):
221 223
222 def __init__(self, parent): 224 def __init__(self, _xmlui_parent):
223 options = {'ADAPT':(0,), 'HIGHLIGHT':(0,)} 225 options = {'ADAPT':(0,), 'HIGHLIGHT':(0,)}
224 if self._xmlui_main.type == 'param': 226 if self._xmlui_main.type == 'param':
225 options['FOCUS_ATTR'] = 'param_selected' 227 options['FOCUS_ATTR'] = 'param_selected'
226 sat_widgets.TableContainer.__init__(self, columns=2, options=options) 228 sat_widgets.TableContainer.__init__(self, columns=2, options=options)
227 229
232 self.addWidget(widget) 234 self.addWidget(widget)
233 235
234 236
235 class PrimitivusTabsContainer(xmlui.TabsContainer, sat_widgets.TabsContainer): 237 class PrimitivusTabsContainer(xmlui.TabsContainer, sat_widgets.TabsContainer):
236 238
237 def __init__(self, parent): 239 def __init__(self, _xmlui_parent):
238 sat_widgets.TabsContainer.__init__(self) 240 sat_widgets.TabsContainer.__init__(self)
239 241
240 def _xmluiAppend(self, widget): 242 def _xmluiAppend(self, widget):
241 self.body.append(widget) 243 self.body.append(widget)
242 244
247 249
248 250
249 class PrimitivusVerticalContainer(xmlui.VerticalContainer, urwid.ListBox): 251 class PrimitivusVerticalContainer(xmlui.VerticalContainer, urwid.ListBox):
250 BOX_HEIGHT = 5 252 BOX_HEIGHT = 5
251 253
252 def __init__(self, parent): 254 def __init__(self, _xmlui_parent):
253 urwid.ListBox.__init__(self, urwid.SimpleListWalker([])) 255 urwid.ListBox.__init__(self, urwid.SimpleListWalker([]))
254 self._last_size = None 256 self._last_size = None
255 257
256 def _xmluiAppend(self, widget): 258 def _xmluiAppend(self, widget):
257 if 'flow' not in widget.sizing(): 259 if 'flow' not in widget.sizing():
267 widget.height = maxrow 269 widget.height = maxrow
268 self._last_size = size 270 self._last_size = size
269 return super(PrimitivusVerticalContainer, self).render(size, focus) 271 return super(PrimitivusVerticalContainer, self).render(size, focus)
270 272
271 273
272 class WidgetFactory(object): 274 ### Dialogs ###
275
276
277 class PrimitivusDialog(object):
278
279 def __init__(self, _xmlui_parent):
280 self.host = _xmlui_parent.host
281
282 def _xmluiShow(self):
283 self.host.showPopUp(self)
284
285 def _xmluiClose(self):
286 self.host.removePopUp()
287
288
289 class PrimitivusMessageDialog(PrimitivusDialog, xmlui.MessageDialog, sat_widgets.Alert):
290
291 def __init__(self, _xmlui_parent, title, message, level):
292 PrimitivusDialog.__init__(self, _xmlui_parent)
293 xmlui.MessageDialog.__init__(self, _xmlui_parent)
294 sat_widgets.Alert.__init__(self, title, message, ok_cb=lambda dummy: self._xmluiValidated())
295
296
297 class PrimitivusNoteDialog(xmlui.NoteDialog, PrimitivusMessageDialog):
298 # TODO: separate NoteDialog
299 pass
300
301
302 class PrimitivusConfirmDialog(PrimitivusDialog, xmlui.ConfirmDialog, sat_widgets.ConfirmDialog):
303
304 def __init__(self, _xmlui_parent, title, message, level, buttons_set):
305 PrimitivusDialog.__init__(self, _xmlui_parent)
306 xmlui.ConfirmDialog.__init__(self, _xmlui_parent)
307 sat_widgets.ConfirmDialog.__init__(self, title, message, no_cb=lambda dummy: self._xmluiCancelled(), yes_cb=lambda dummy: self._xmluiValidated())
308
309
310 class PrimitivusFileDialog(PrimitivusDialog, xmlui.FileDialog, files_management.FileDialog):
311
312 def __init__(self, _xmlui_parent, title, message, level, filetype):
313 # TODO: message is not managed yet
314 PrimitivusDialog.__init__(self, _xmlui_parent)
315 xmlui.FileDialog.__init__(self, _xmlui_parent)
316 style = []
317 if filetype == C.XMLUI_DATA_FILETYPE_DIR:
318 style.append('dir')
319 files_management.FileDialog.__init__(self, ok_cb=lambda path: self._xmluiValidated({'path': path}), cancel_cb=lambda dummy: self._xmluiCancelled(), title=title)
320
321
322 class GenericFactory(object):
273 323
274 def __getattr__(self, attr): 324 def __getattr__(self, attr):
275 if attr.startswith("create"): 325 if attr.startswith("create"):
276 cls = globals()["Primitivus" + attr[6:]] # XXX: we prefix with "Primitivus" to work around an Urwid bug, WidgetMeta in Urwid don't manage multiple inheritance with same names 326 cls = globals()["Primitivus" + attr[6:]] # XXX: we prefix with "Primitivus" to work around an Urwid bug, WidgetMeta in Urwid don't manage multiple inheritance with same names
327 return cls
328
329
330 class WidgetFactory(GenericFactory):
331
332 def __getattr__(self, attr):
333 if attr.startswith("create"):
334 cls = GenericFactory.__getattr__(self, attr)
277 cls._xmlui_main = self._xmlui_main 335 cls._xmlui_main = self._xmlui_main
278 return cls 336 return cls
279 337
280 class XMLUI(xmlui.XMLUI, urwid.WidgetWrap): 338
339 class XMLUIPanel(xmlui.XMLUIPanel, urwid.WidgetWrap):
281 widget_factory = WidgetFactory() 340 widget_factory = WidgetFactory()
282 341
283 def __init__(self, host, xml_data, title = None, flags = None): 342 def __init__(self, host, parsed_xml, title = None, flags = None):
284 self.widget_factory._xmlui_main = self 343 self.widget_factory._xmlui_main = self
285 self._dest = None 344 self._dest = None
286 xmlui.XMLUI.__init__(self, host, xml_data, title, flags) 345 xmlui.XMLUIPanel.__init__(self, host, parsed_xml, title, flags)
287 urwid.WidgetWrap.__init__(self, self.main_cont) 346 urwid.WidgetWrap.__init__(self, self.main_cont)
288 347
289 def constructUI(self, xml_data): 348 def constructUI(self, parsed_dom):
290 def postTreat(): 349 def postTreat():
291 assert self.main_cont.body 350 assert self.main_cont.body
292 351
293 if self.type in ('form', 'popup'): 352 if self.type in ('form', 'popup'):
294 buttons = [] 353 buttons = []
309 buttons.append(sat_widgets.CustomButton(_('Cancel'),lambda x:self.host.removeWindow())) 368 buttons.append(sat_widgets.CustomButton(_('Cancel'),lambda x:self.host.removeWindow()))
310 max_len = max([button.getSize() for button in buttons]) 369 max_len = max([button.getSize() for button in buttons])
311 grid_wid = urwid.GridFlow(buttons,max_len,1,0,'center') 370 grid_wid = urwid.GridFlow(buttons,max_len,1,0,'center')
312 tabs_cont.addFooter(grid_wid) 371 tabs_cont.addFooter(grid_wid)
313 372
314 super(XMLUI, self).constructUI(xml_data, postTreat) 373 xmlui.XMLUIPanel.constructUI(self, parsed_dom, postTreat)
315 urwid.WidgetWrap.__init__(self, self.main_cont) 374 urwid.WidgetWrap.__init__(self, self.main_cont)
316 375
317 def show(self, show_type=None, valign='middle'): 376 def show(self, show_type=None, valign='middle'):
318 """Show the constructed UI 377 """Show the constructed UI
319 @param show_type: how to show the UI: 378 @param show_type: how to show the UI:
320 - None (follow XMLUI's recommendation) 379 - None (follow XMLUI's recommendation)
321 - 'popup' 380 - 'popup'
322 - 'window' 381 - 'window'
323 @param valign: vertical alignment when show_type is 'popup'. 382 @param valign: vertical alignment when show_type is 'popup'.
324 Ignored when show_type is 'window'. 383 Ignored when show_type is 'window'.
325 384
326 """ 385 """
327 if show_type is None: 386 if show_type is None:
328 if self.type in ('window', 'param'): 387 if self.type in ('window', 'param'):
329 show_type = 'window' 388 show_type = 'window'
341 self.host.addWindow(decorated) 400 self.host.addWindow(decorated)
342 else: 401 else:
343 assert(False) 402 assert(False)
344 self.host.redraw() 403 self.host.redraw()
345 404
346
347 def _xmluiClose(self): 405 def _xmluiClose(self):
348 if self._dest == 'window': 406 if self._dest == 'window':
349 self.host.removeWindow() 407 self.host.removeWindow()
350 else: 408 else:
351 self.host.removePopUp() 409 self.host.removePopUp()
410
411
412 class XMLUIDialog(xmlui.XMLUIDialog):
413 dialog_factory = GenericFactory()
414
415
416 xmlui.registerClass(xmlui.CLASS_PANEL, XMLUIPanel)
417 xmlui.registerClass(xmlui.CLASS_DIALOG, XMLUIDialog)
418 create = xmlui.create