comparison src/browser/sat_browser/xmlui.py @ 467:97c72fe4a5f2

browser_side: import fixes: - moved browser modules in a sat_browser packages, to avoid import conflicts with std lib (e.g. logging), and let pyjsbuild work normaly - refactored bad import practices: classes are most of time not imported directly, module is imported instead.
author Goffi <goffi@goffi.org>
date Mon, 09 Jun 2014 22:15:26 +0200
parents src/browser/xmlui.py@1a0cec9b0f1e
children 1ce6133993e4
comparison
equal deleted inserted replaced
466:01880aa8ea2d 467:97c72fe4a5f2
1 #!/usr/bin/python
2 # -*- coding: utf-8 -*-
3
4 # Libervia: a Salut à Toi frontend
5 # Copyright (C) 2011, 2012, 2013, 2014 Jérôme Poisson <goffi@goffi.org>
6
7 # This program is free software: you can redistribute it and/or modify
8 # it under the terms of the GNU Affero General Public License as published by
9 # the Free Software Foundation, either version 3 of the License, or
10 # (at your option) any later version.
11
12 # This program is distributed in the hope that it will be useful,
13 # but WITHOUT ANY WARRANTY; without even the implied warranty of
14 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 # GNU Affero General Public License for more details.
16
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/>.
19
20 from sat.core.log import getLogger
21 log = getLogger(__name__)
22 from sat_frontends.tools import xmlui
23
24 from pyjamas.ui.VerticalPanel import VerticalPanel
25 from pyjamas.ui.HorizontalPanel import HorizontalPanel
26 from pyjamas.ui.TabPanel import TabPanel
27 from pyjamas.ui.Grid import Grid
28 from pyjamas.ui.Label import Label
29 from pyjamas.ui.TextBox import TextBox
30 from pyjamas.ui.PasswordTextBox import PasswordTextBox
31 from pyjamas.ui.TextArea import TextArea
32 from pyjamas.ui.CheckBox import CheckBox
33 from pyjamas.ui.ListBox import ListBox
34 from pyjamas.ui.Button import Button
35 from pyjamas.ui.HTML import HTML
36
37 import nativedom
38
39
40 class EmptyWidget(xmlui.EmptyWidget, Label):
41
42 def __init__(self, parent):
43 Label.__init__(self, '')
44
45
46 class TextWidget(xmlui.TextWidget, Label):
47
48 def __init__(self, parent, value):
49 Label.__init__(self, value)
50
51
52 class LabelWidget(xmlui.LabelWidget, TextWidget):
53
54 def __init__(self, parent, value):
55 TextWidget.__init__(self, parent, value + ": ")
56
57
58 class JidWidget(xmlui.JidWidget, TextWidget):
59
60 def __init__(self, parent, value):
61 TextWidget.__init__(self, parent, value)
62
63
64 class DividerWidget(xmlui.DividerWidget, HTML):
65
66 def __init__(self, parent, style='line'):
67 """Add a divider
68
69 @param parent
70 @param style (string): one of:
71 - line: a simple line
72 - dot: a line of dots
73 - dash: a line of dashes
74 - plain: a full thick line
75 - blank: a blank line/space
76 """
77 HTML.__init__(self, "<hr/>")
78 self.addStyleName(style)
79
80
81 class StringWidget(xmlui.StringWidget, TextBox):
82
83 def __init__(self, parent, value):
84 TextBox.__init__(self)
85 self.setText(value)
86
87 def _xmluiSetValue(self, value):
88 self.setText(value)
89
90 def _xmluiGetValue(self):
91 return self.getText()
92
93 def _xmluiOnChange(self, callback):
94 self.addChangeListener(callback)
95
96
97 class PasswordWidget(xmlui.PasswordWidget, PasswordTextBox):
98
99 def __init__(self, parent, value):
100 PasswordTextBox.__init__(self)
101 self.setText(value)
102
103 def _xmluiSetValue(self, value):
104 self.setText(value)
105
106 def _xmluiGetValue(self):
107 return self.getText()
108
109 def _xmluiOnChange(self, callback):
110 self.addChangeListener(callback)
111
112
113 class TextBoxWidget(xmlui.TextBoxWidget, TextArea):
114
115 def __init__(self, parent, value):
116 TextArea.__init__(self)
117 self.setText(value)
118
119 def _xmluiSetValue(self, value):
120 self.setText(value)
121
122 def _xmluiGetValue(self):
123 return self.getText()
124
125 def _xmluiOnChange(self, callback):
126 self.addChangeListener(callback)
127
128
129 class BoolWidget(xmlui.BoolWidget, CheckBox):
130
131 def __init__(self, parent, state):
132 CheckBox.__init__(self)
133 self.setChecked(state)
134
135 def _xmluiSetValue(self, value):
136 self.setChecked(value == "true")
137
138 def _xmluiGetValue(self):
139 return "true" if self.isChecked() else "false"
140
141 def _xmluiOnChange(self, callback):
142 self.addClickListener(callback)
143
144
145 class ButtonWidget(xmlui.ButtonWidget, Button):
146
147 def __init__(self, parent, value, click_callback):
148 Button.__init__(self, value, click_callback)
149
150 def _xmluiOnClick(self, callback):
151 self.addClickListener(callback)
152
153
154 class ListWidget(xmlui.ListWidget, ListBox):
155
156 def __init__(self, parent, options, selected, flags):
157 ListBox.__init__(self)
158 multi_selection = 'single' not in flags
159 self.setMultipleSelect(multi_selection)
160 if multi_selection:
161 self.setVisibleItemCount(5)
162 for option in options:
163 self.addItem(option[1])
164 self._xmlui_attr_map = {label: value for value, label in options}
165 self._xmluiSelectValues(selected)
166
167 def _xmluiSelectValue(self, value):
168 """Select a value checking its item"""
169 try:
170 label = [label for label, _value in self._xmlui_attr_map.items() if _value == value][0]
171 except IndexError:
172 log.warning("Can't find value [%s] to select" % value)
173 return
174 self.selectItem(label)
175
176 def _xmluiSelectValues(self, values):
177 """Select multiple values, ignore the items"""
178 self.setValueSelection(values)
179
180 def _xmluiGetSelectedValues(self):
181 ret = []
182 for label in self.getSelectedItemText():
183 ret.append(self._xmlui_attr_map[label])
184 return ret
185
186 def _xmluiOnChange(self, callback):
187 self.addChangeListener(callback)
188
189 def _xmluiAddValues(self, values, select=True):
190 selected = self._xmluiGetSelectedValues()
191 for value in values:
192 if value not in self._xmlui_attr_map.values():
193 self.addItem(value)
194 self._xmlui_attr_map[value] = value
195 if value not in selected:
196 selected.append(value)
197 self._xmluiSelectValues(selected)
198
199
200 class LiberviaContainer(object):
201
202 def _xmluiAppend(self, widget):
203 self.append(widget)
204
205
206 class AdvancedListContainer(xmlui.AdvancedListContainer, Grid):
207
208 def __init__(self, parent, columns, selectable='no'):
209 Grid.__init__(self, 0, columns)
210 self.columns = columns
211 self.row = -1
212 self.col = 0
213 self._xmlui_rows_idx = []
214 self._xmlui_selectable = selectable != 'no'
215 self._xmlui_selected_row = None
216 self.addTableListener(self)
217 if self._xmlui_selectable:
218 self.addStyleName('AdvancedListSelectable')
219
220 def onCellClicked(self, grid, row, col):
221 if not self._xmlui_selectable:
222 return
223 self._xmlui_selected_row = row
224 try:
225 self._xmlui_select_cb(self)
226 except AttributeError:
227 log.warning("no select callback set")
228
229 def _xmluiAppend(self, widget):
230 self.setWidget(self.row, self.col, widget)
231 self.col += 1
232
233 def _xmluiAddRow(self, idx):
234 self.row += 1
235 self.col = 0
236 self._xmlui_rows_idx.insert(self.row, idx)
237 self.resizeRows(self.row + 1)
238
239 def _xmluiGetSelectedWidgets(self):
240 return [self.getWidget(self._xmlui_selected_row, col) for col in range(self.columns)]
241
242 def _xmluiGetSelectedIndex(self):
243 try:
244 return self._xmlui_rows_idx[self._xmlui_selected_row]
245 except TypeError:
246 return None
247
248 def _xmluiOnSelect(self, callback):
249 self._xmlui_select_cb = callback
250
251
252 class PairsContainer(xmlui.PairsContainer, Grid):
253
254 def __init__(self, parent):
255 Grid.__init__(self, 0, 0)
256 self.row = 0
257 self.col = 0
258
259 def _xmluiAppend(self, widget):
260 if self.col == 0:
261 self.resize(self.row + 1, 2)
262 self.setWidget(self.row, self.col, widget)
263 self.col += 1
264 if self.col == 2:
265 self.row += 1
266 self.col = 0
267
268
269 class TabsContainer(LiberviaContainer, xmlui.TabsContainer, TabPanel):
270
271 def __init__(self, parent):
272 TabPanel.__init__(self)
273 self.setStyleName('liberviaTabPanel')
274
275 def _xmluiAddTab(self, label):
276 tab_panel = VerticalContainer(self)
277 self.add(tab_panel, label)
278 if len(self.getChildren()) == 1:
279 self.selectTab(0)
280 return tab_panel
281
282
283 class VerticalContainer(LiberviaContainer, xmlui.VerticalContainer, VerticalPanel):
284 __bases__ = (LiberviaContainer, xmlui.VerticalContainer, VerticalPanel)
285
286 def __init__(self, parent):
287 VerticalPanel.__init__(self)
288
289
290 class WidgetFactory(object):
291 # XXX: __getattr__ doesn't work here for an unknown reason
292
293 def createVerticalContainer(self, *args, **kwargs):
294 instance = VerticalContainer(*args, **kwargs)
295 instance._xmlui_main = self._xmlui_main
296 return instance
297
298 def createPairsContainer(self, *args, **kwargs):
299 instance = PairsContainer(*args, **kwargs)
300 instance._xmlui_main = self._xmlui_main
301 return instance
302
303 def createTabsContainer(self, *args, **kwargs):
304 instance = TabsContainer(*args, **kwargs)
305 instance._xmlui_main = self._xmlui_main
306 return instance
307
308 def createAdvancedListContainer(self, *args, **kwargs):
309 instance = AdvancedListContainer(*args, **kwargs)
310 instance._xmlui_main = self._xmlui_main
311 return instance
312
313 def createEmptyWidget(self, *args, **kwargs):
314 instance = EmptyWidget(*args, **kwargs)
315 instance._xmlui_main = self._xmlui_main
316 return instance
317
318 def createTextWidget(self, *args, **kwargs):
319 instance = TextWidget(*args, **kwargs)
320 instance._xmlui_main = self._xmlui_main
321 return instance
322
323 def createLabelWidget(self, *args, **kwargs):
324 instance = LabelWidget(*args, **kwargs)
325 instance._xmlui_main = self._xmlui_main
326 return instance
327
328 def createJidWidget(self, *args, **kwargs):
329 instance = JidWidget(*args, **kwargs)
330 instance._xmlui_main = self._xmlui_main
331 return instance
332
333 def createDividerWidget(self, *args, **kwargs):
334 instance = DividerWidget(*args, **kwargs)
335 instance._xmlui_main = self._xmlui_main
336 return instance
337
338 def createStringWidget(self, *args, **kwargs):
339 instance = StringWidget(*args, **kwargs)
340 instance._xmlui_main = self._xmlui_main
341 return instance
342
343 def createPasswordWidget(self, *args, **kwargs):
344 instance = PasswordWidget(*args, **kwargs)
345 instance._xmlui_main = self._xmlui_main
346 return instance
347
348 def createTextBoxWidget(self, *args, **kwargs):
349 instance = TextBoxWidget(*args, **kwargs)
350 instance._xmlui_main = self._xmlui_main
351 return instance
352
353 def createBoolWidget(self, *args, **kwargs):
354 instance = BoolWidget(*args, **kwargs)
355 instance._xmlui_main = self._xmlui_main
356 return instance
357
358 def createButtonWidget(self, *args, **kwargs):
359 instance = ButtonWidget(*args, **kwargs)
360 instance._xmlui_main = self._xmlui_main
361 return instance
362
363 def createListWidget(self, *args, **kwargs):
364 instance = ListWidget(*args, **kwargs)
365 instance._xmlui_main = self._xmlui_main
366 return instance
367
368
369 # def __getattr__(self, attr):
370 # if attr.startswith("create"):
371 # cls = globals()[attr[6:]]
372 # cls._xmlui_main = self._xmlui_main
373 # return cls
374
375
376 class XMLUI(xmlui.XMLUI, VerticalPanel):
377 widget_factory = WidgetFactory()
378
379 def __init__(self, host, xml_data, title=None, flags=None):
380 self.widget_factory._xmlui_main = self
381 self.dom = nativedom.NativeDOM()
382 dom_parse = lambda xml_data: self.dom.parseString(xml_data)
383 VerticalPanel.__init__(self)
384 self.setSize('100%', '100%')
385 xmlui.XMLUI.__init__(self, host, xml_data, title, flags, dom_parse)
386
387 def setCloseCb(self, close_cb):
388 self.close_cb = close_cb
389
390 def _xmluiClose(self):
391 if self.close_cb:
392 self.close_cb()
393 else:
394 log.warning("no close method defined")
395
396 def _xmluiLaunchAction(self, action_id, data):
397 self.host.launchAction(action_id, data)
398
399 def _xmluiSetParam(self, name, value, category):
400 self.host.bridge.call('setParam', None, name, value, category)
401
402 def constructUI(self, xml_data):
403 super(XMLUI, self).constructUI(xml_data)
404 self.add(self.main_cont)
405 self.setCellHeight(self.main_cont, '100%')
406 if self.type == 'form':
407 hpanel = HorizontalPanel()
408 hpanel.setStyleName('marginAuto')
409 hpanel.add(Button('Submit', self.onFormSubmitted))
410 if not 'NO_CANCEL' in self.flags:
411 hpanel.add(Button('Cancel', self.onFormCancelled))
412 self.add(hpanel)
413 elif self.type == 'param':
414 assert(isinstance(self.children[0][0], TabPanel))
415 hpanel = HorizontalPanel()
416 hpanel.add(Button('Save', self.onSaveParams))
417 hpanel.add(Button('Cancel', lambda ignore: self._xmluiClose()))
418 self.add(hpanel)