Mercurial > libervia-web
diff 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 |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/browser/sat_browser/xmlui.py Mon Jun 09 22:15:26 2014 +0200 @@ -0,0 +1,418 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- + +# Libervia: a Salut à Toi frontend +# Copyright (C) 2011, 2012, 2013, 2014 Jérôme Poisson <goffi@goffi.org> + +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. + +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + +from sat.core.log import getLogger +log = getLogger(__name__) +from sat_frontends.tools import xmlui + +from pyjamas.ui.VerticalPanel import VerticalPanel +from pyjamas.ui.HorizontalPanel import HorizontalPanel +from pyjamas.ui.TabPanel import TabPanel +from pyjamas.ui.Grid import Grid +from pyjamas.ui.Label import Label +from pyjamas.ui.TextBox import TextBox +from pyjamas.ui.PasswordTextBox import PasswordTextBox +from pyjamas.ui.TextArea import TextArea +from pyjamas.ui.CheckBox import CheckBox +from pyjamas.ui.ListBox import ListBox +from pyjamas.ui.Button import Button +from pyjamas.ui.HTML import HTML + +import nativedom + + +class EmptyWidget(xmlui.EmptyWidget, Label): + + def __init__(self, parent): + Label.__init__(self, '') + + +class TextWidget(xmlui.TextWidget, Label): + + def __init__(self, parent, value): + Label.__init__(self, value) + + +class LabelWidget(xmlui.LabelWidget, TextWidget): + + def __init__(self, parent, value): + TextWidget.__init__(self, parent, value + ": ") + + +class JidWidget(xmlui.JidWidget, TextWidget): + + def __init__(self, parent, value): + TextWidget.__init__(self, parent, value) + + +class DividerWidget(xmlui.DividerWidget, HTML): + + def __init__(self, parent, style='line'): + """Add a divider + + @param parent + @param style (string): one of: + - line: a simple line + - dot: a line of dots + - dash: a line of dashes + - plain: a full thick line + - blank: a blank line/space + """ + HTML.__init__(self, "<hr/>") + self.addStyleName(style) + + +class StringWidget(xmlui.StringWidget, TextBox): + + def __init__(self, parent, value): + TextBox.__init__(self) + self.setText(value) + + def _xmluiSetValue(self, value): + self.setText(value) + + def _xmluiGetValue(self): + return self.getText() + + def _xmluiOnChange(self, callback): + self.addChangeListener(callback) + + +class PasswordWidget(xmlui.PasswordWidget, PasswordTextBox): + + def __init__(self, parent, value): + PasswordTextBox.__init__(self) + self.setText(value) + + def _xmluiSetValue(self, value): + self.setText(value) + + def _xmluiGetValue(self): + return self.getText() + + def _xmluiOnChange(self, callback): + self.addChangeListener(callback) + + +class TextBoxWidget(xmlui.TextBoxWidget, TextArea): + + def __init__(self, parent, value): + TextArea.__init__(self) + self.setText(value) + + def _xmluiSetValue(self, value): + self.setText(value) + + def _xmluiGetValue(self): + return self.getText() + + def _xmluiOnChange(self, callback): + self.addChangeListener(callback) + + +class BoolWidget(xmlui.BoolWidget, CheckBox): + + def __init__(self, parent, state): + CheckBox.__init__(self) + self.setChecked(state) + + def _xmluiSetValue(self, value): + self.setChecked(value == "true") + + def _xmluiGetValue(self): + return "true" if self.isChecked() else "false" + + def _xmluiOnChange(self, callback): + self.addClickListener(callback) + + +class ButtonWidget(xmlui.ButtonWidget, Button): + + def __init__(self, parent, value, click_callback): + Button.__init__(self, value, click_callback) + + def _xmluiOnClick(self, callback): + self.addClickListener(callback) + + +class ListWidget(xmlui.ListWidget, ListBox): + + def __init__(self, parent, options, selected, flags): + ListBox.__init__(self) + multi_selection = 'single' not in flags + self.setMultipleSelect(multi_selection) + if multi_selection: + self.setVisibleItemCount(5) + for option in options: + self.addItem(option[1]) + self._xmlui_attr_map = {label: value for value, label in options} + self._xmluiSelectValues(selected) + + def _xmluiSelectValue(self, value): + """Select a value checking its item""" + try: + label = [label for label, _value in self._xmlui_attr_map.items() if _value == value][0] + except IndexError: + log.warning("Can't find value [%s] to select" % value) + return + self.selectItem(label) + + def _xmluiSelectValues(self, values): + """Select multiple values, ignore the items""" + self.setValueSelection(values) + + def _xmluiGetSelectedValues(self): + ret = [] + for label in self.getSelectedItemText(): + ret.append(self._xmlui_attr_map[label]) + return ret + + def _xmluiOnChange(self, callback): + self.addChangeListener(callback) + + def _xmluiAddValues(self, values, select=True): + selected = self._xmluiGetSelectedValues() + for value in values: + if value not in self._xmlui_attr_map.values(): + self.addItem(value) + self._xmlui_attr_map[value] = value + if value not in selected: + selected.append(value) + self._xmluiSelectValues(selected) + + +class LiberviaContainer(object): + + def _xmluiAppend(self, widget): + self.append(widget) + + +class AdvancedListContainer(xmlui.AdvancedListContainer, Grid): + + def __init__(self, parent, columns, selectable='no'): + Grid.__init__(self, 0, columns) + self.columns = columns + self.row = -1 + self.col = 0 + self._xmlui_rows_idx = [] + self._xmlui_selectable = selectable != 'no' + self._xmlui_selected_row = None + self.addTableListener(self) + if self._xmlui_selectable: + self.addStyleName('AdvancedListSelectable') + + def onCellClicked(self, grid, row, col): + if not self._xmlui_selectable: + return + self._xmlui_selected_row = row + try: + self._xmlui_select_cb(self) + except AttributeError: + log.warning("no select callback set") + + def _xmluiAppend(self, widget): + self.setWidget(self.row, self.col, widget) + self.col += 1 + + def _xmluiAddRow(self, idx): + self.row += 1 + self.col = 0 + self._xmlui_rows_idx.insert(self.row, idx) + self.resizeRows(self.row + 1) + + def _xmluiGetSelectedWidgets(self): + return [self.getWidget(self._xmlui_selected_row, col) for col in range(self.columns)] + + def _xmluiGetSelectedIndex(self): + try: + return self._xmlui_rows_idx[self._xmlui_selected_row] + except TypeError: + return None + + def _xmluiOnSelect(self, callback): + self._xmlui_select_cb = callback + + +class PairsContainer(xmlui.PairsContainer, Grid): + + def __init__(self, parent): + Grid.__init__(self, 0, 0) + self.row = 0 + self.col = 0 + + def _xmluiAppend(self, widget): + if self.col == 0: + self.resize(self.row + 1, 2) + self.setWidget(self.row, self.col, widget) + self.col += 1 + if self.col == 2: + self.row += 1 + self.col = 0 + + +class TabsContainer(LiberviaContainer, xmlui.TabsContainer, TabPanel): + + def __init__(self, parent): + TabPanel.__init__(self) + self.setStyleName('liberviaTabPanel') + + def _xmluiAddTab(self, label): + tab_panel = VerticalContainer(self) + self.add(tab_panel, label) + if len(self.getChildren()) == 1: + self.selectTab(0) + return tab_panel + + +class VerticalContainer(LiberviaContainer, xmlui.VerticalContainer, VerticalPanel): + __bases__ = (LiberviaContainer, xmlui.VerticalContainer, VerticalPanel) + + def __init__(self, parent): + VerticalPanel.__init__(self) + + +class WidgetFactory(object): + # XXX: __getattr__ doesn't work here for an unknown reason + + def createVerticalContainer(self, *args, **kwargs): + instance = VerticalContainer(*args, **kwargs) + instance._xmlui_main = self._xmlui_main + return instance + + def createPairsContainer(self, *args, **kwargs): + instance = PairsContainer(*args, **kwargs) + instance._xmlui_main = self._xmlui_main + return instance + + def createTabsContainer(self, *args, **kwargs): + instance = TabsContainer(*args, **kwargs) + instance._xmlui_main = self._xmlui_main + return instance + + def createAdvancedListContainer(self, *args, **kwargs): + instance = AdvancedListContainer(*args, **kwargs) + instance._xmlui_main = self._xmlui_main + return instance + + def createEmptyWidget(self, *args, **kwargs): + instance = EmptyWidget(*args, **kwargs) + instance._xmlui_main = self._xmlui_main + return instance + + def createTextWidget(self, *args, **kwargs): + instance = TextWidget(*args, **kwargs) + instance._xmlui_main = self._xmlui_main + return instance + + def createLabelWidget(self, *args, **kwargs): + instance = LabelWidget(*args, **kwargs) + instance._xmlui_main = self._xmlui_main + return instance + + def createJidWidget(self, *args, **kwargs): + instance = JidWidget(*args, **kwargs) + instance._xmlui_main = self._xmlui_main + return instance + + def createDividerWidget(self, *args, **kwargs): + instance = DividerWidget(*args, **kwargs) + instance._xmlui_main = self._xmlui_main + return instance + + def createStringWidget(self, *args, **kwargs): + instance = StringWidget(*args, **kwargs) + instance._xmlui_main = self._xmlui_main + return instance + + def createPasswordWidget(self, *args, **kwargs): + instance = PasswordWidget(*args, **kwargs) + instance._xmlui_main = self._xmlui_main + return instance + + def createTextBoxWidget(self, *args, **kwargs): + instance = TextBoxWidget(*args, **kwargs) + instance._xmlui_main = self._xmlui_main + return instance + + def createBoolWidget(self, *args, **kwargs): + instance = BoolWidget(*args, **kwargs) + instance._xmlui_main = self._xmlui_main + return instance + + def createButtonWidget(self, *args, **kwargs): + instance = ButtonWidget(*args, **kwargs) + instance._xmlui_main = self._xmlui_main + return instance + + def createListWidget(self, *args, **kwargs): + instance = ListWidget(*args, **kwargs) + instance._xmlui_main = self._xmlui_main + return instance + + + # def __getattr__(self, attr): + # if attr.startswith("create"): + # cls = globals()[attr[6:]] + # cls._xmlui_main = self._xmlui_main + # return cls + + +class XMLUI(xmlui.XMLUI, VerticalPanel): + widget_factory = WidgetFactory() + + def __init__(self, host, xml_data, title=None, flags=None): + self.widget_factory._xmlui_main = self + self.dom = nativedom.NativeDOM() + dom_parse = lambda xml_data: self.dom.parseString(xml_data) + VerticalPanel.__init__(self) + self.setSize('100%', '100%') + xmlui.XMLUI.__init__(self, host, xml_data, title, flags, dom_parse) + + def setCloseCb(self, close_cb): + self.close_cb = close_cb + + def _xmluiClose(self): + if self.close_cb: + self.close_cb() + else: + log.warning("no close method defined") + + def _xmluiLaunchAction(self, action_id, data): + self.host.launchAction(action_id, data) + + def _xmluiSetParam(self, name, value, category): + self.host.bridge.call('setParam', None, name, value, category) + + def constructUI(self, xml_data): + super(XMLUI, self).constructUI(xml_data) + self.add(self.main_cont) + self.setCellHeight(self.main_cont, '100%') + if self.type == 'form': + hpanel = HorizontalPanel() + hpanel.setStyleName('marginAuto') + hpanel.add(Button('Submit', self.onFormSubmitted)) + if not 'NO_CANCEL' in self.flags: + hpanel.add(Button('Cancel', self.onFormCancelled)) + self.add(hpanel) + elif self.type == 'param': + assert(isinstance(self.children[0][0], TabPanel)) + hpanel = HorizontalPanel() + hpanel.add(Button('Save', self.onSaveParams)) + hpanel.add(Button('Cancel', lambda ignore: self._xmluiClose())) + self.add(hpanel)