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)