Mercurial > libervia-backend
view frontends/src/wix/xmlui.py @ 817:c39117d00f35
jp: refactoring:
- imports from sat_frontends.jp instead of local imports
- added __init__.py
- commands now inherits from a base class: each base.CommandBase instance is a subcommand
- new arguments are added in CommandBase.add_parser_options methods, starting point si CommandBase.run or CommandBase.connected if a profile connection is needed
- commands are exported using a __commands__ variable at the top of the module
- sub-subcommand are easily added by using an other CommandBase instance as parent instead of using a Jp instance. In this case, the parent subcommand must be the one exported, and have a subcommands iterable (see cmd_file or cmd_pipe for examples).
- options which are often used (like --profile) are automatically added on demand (use_profile=True, use_progress=True)
- commands are automatically loaded when there are in a module named cmd_XXX
- restored --connect option
- restored progress bar
- restored getVersion bridge call on jp --version
- fixed file and pipe commands
- fixed forgotten translations
- fixed non SàT compliant docstrings
- better about/version dialog
author | Goffi <goffi@goffi.org> |
---|---|
date | Mon, 10 Feb 2014 13:44:09 +0100 |
parents | 1fe00f0c9a91 |
children | 3ee2ec7ec010 |
line wrap: on
line source
#!/usr/bin/python # -*- coding: utf-8 -*- # wix: a SAT frontend # Copyright (C) 2009, 2010, 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.i18n import _ import wx from logging import debug, info, warning, error from sat.tools.jid import JID from sat_frontends.tools import xmlui class EventWidget(object): """ Used to manage change event of widgets """ def _xmluiOnChange(self, callback): """ Call callback with widget as only argument """ def change_cb(event): callback(self) self.Bind(self._xmlui_change_event, change_cb) class WixWidget(object): _xmlui_proportion = 0 class ValueWidget(WixWidget): def _xmluiGetValue(self): return self.GetValue() class EmptyWidget(WixWidget, xmlui.EmptyWidget, wx.Window): def __init__(self, parent): wx.Window.__init__(self, parent, -1) class TextWidget(WixWidget, xmlui.TextWidget, wx.StaticText): def __init__(self, parent, value): wx.StaticText.__init__(self, parent, -1, value) class LabelWidget(xmlui.LabelWidget, TextWidget): def __init__(self, parent, value): super(LabelWidget, self).__init__(parent, value+": ") class JidWidget(xmlui.JidWidget, TextWidget): pass class DividerWidget(WixWidget, xmlui.DividerWidget, wx.StaticLine): def __init__(self, parent, style='line'): wx.StaticLine.__init__(self, parent, -1) class StringWidget(EventWidget, ValueWidget, xmlui.StringWidget, wx.TextCtrl): _xmlui_change_event = wx.EVT_TEXT def __init__(self, parent, value): wx.TextCtrl.__init__(self, parent, -1, value) self._xmlui_proportion = 1 class PasswordWidget(EventWidget, ValueWidget, xmlui.PasswordWidget, wx.TextCtrl): _xmlui_change_event = wx.EVT_TEXT def __init__(self, parent, value): wx.TextCtrl.__init__(self, parent, -1, value, style=wx.TE_PASSWORD) self._xmlui_proportion = 1 class TextBoxWidget(EventWidget, ValueWidget, xmlui.TextBoxWidget, wx.TextCtrl): _xmlui_change_event = wx.EVT_TEXT def __init__(self, parent, value): wx.TextCtrl.__init__(self, parent, -1, value, style=wx.TE_MULTILINE) self._xmlui_proportion = 1 class BoolWidget(EventWidget, ValueWidget, xmlui.BoolWidget, wx.CheckBox): _xmlui_change_event = wx.EVT_CHECKBOX def __init__(self, parent, state): wx.CheckBox.__init__(self, parent, -1, "", style=wx.CHK_2STATE) self.SetValue(state) self._xmlui_proportion = 1 def _xmluiGetValue(self): return "true" if self.GetValue() else "false" class ButtonWidget(EventWidget, WixWidget, xmlui.ButtonWidget, wx.Button): _xmlui_change_event = wx.EVT_BUTTON def __init__(self, parent, value, click_callback): wx.Button.__init__(self, parent, -1, value) self._xmlui_click_callback = click_callback parent.Bind(wx.EVT_BUTTON, lambda evt: click_callback(evt.GetEventObject()), self) def _xmluiOnClick(self, event): self._xmlui_click_callback(event.GetEventObject()) event.Skip() class ListWidget(EventWidget, WixWidget, xmlui.ListWidget, wx.ListBox): _xmlui_change_event = wx.EVT_LISTBOX def __init__(self, parent, options, flags): styles = wx.LB_MULTIPLE if not 'single' in flags else wx.LB_SINGLE wx.ListBox.__init__(self, parent, -1, choices=[option[1] for option in options], style=styles) self._xmlui_attr_map = {label: value for value, label in options} self._xmlui_proportion = 1 def _xmluiSelectValue(self, value): try: label = [label for label, _value in self._xmlui_attr_map.items() if _value == value][0] except IndexError: warning(_("Can't find value [%s] to select" % value)) return for idx in xrange(self.GetCount()): self.SetSelection(idx, self.GetString(idx) == label) def _xmluiGetSelectedValues(self): ret = [] labels = [self.GetString(idx) for idx in self.GetSelections()] for label in labels: ret.append(self._xmlui_attr_map[label]) return ret class WixContainer(object): _xmlui_proportion = 1 def _xmluiAppend(self, widget): self.sizer.Add(widget, self._xmlui_proportion, flag=wx.EXPAND) class AdvancedListContainer(WixContainer, xmlui.AdvancedListContainer, wx.ScrolledWindow): def __init__(self, parent, columns, selectable='no'): wx.ScrolledWindow.__init__(self, parent) self._xmlui_selectable = selectable != 'no' if selectable: columns += 1 self.sizer = wx.FlexGridSizer(cols=columns) self.SetSizer(self.sizer) self._xmlui_select_cb = None self._xmlui_select_idx = None self._xmlui_select_widgets = [] def _xmluiAddRow(self, idx): # XXX: select_button is a Q&D way to implement row selection # FIXME: must be done properly if not self._xmlui_selectable: return select_button = wx.Button(self, wx.ID_OK, label=_("select")) self.sizer.Add(select_button) def click_cb(event, idx=idx): cb = self._xmlui_select_cb self._xmlui_select_idx = idx # TODO: fill self._xmlui_select_widgets if cb is not None: cb(self) event.Skip() self.Bind(wx.EVT_BUTTON, click_cb) def _xmluiGetSelectedWidgets(self): return self._xmlui_select_widgets def _xmluiGetSelectedIndex(self): return self._xmlui_select_idx def _xmluiOnSelect(self, callback): self._xmlui_select_cb = callback class PairsContainer(WixContainer, xmlui.PairsContainer, wx.Panel): def __init__(self, parent): wx.Panel.__init__(self, parent) self.sizer = wx.FlexGridSizer(cols=2) self.sizer.AddGrowableCol(1) #The growable column need most of time to be the right one in pairs self.SetSizer(self.sizer) class TabsContainer(WixContainer, xmlui.TabsContainer, wx.Notebook): def __init__(self, parent): wx.Notebook.__init__(self, parent, -1, style=wx.NB_LEFT if self._xmlui_main.type=='param' else 0) def _xmluiAddTab(self, label): tab_panel = wx.Panel(self, -1) tab_panel.sizer = wx.BoxSizer(wx.VERTICAL) tab_panel.SetSizer(tab_panel.sizer) self.AddPage(tab_panel, label) VerticalContainer._xmluiAdapt(tab_panel) return tab_panel class VerticalContainer(WixContainer, xmlui.VerticalContainer, wx.Panel): def __init__(self, parent): wx.Panel.__init__(self, parent) self.sizer = wx.BoxSizer(wx.VERTICAL) self.SetSizer(self.sizer) class WidgetFactory(object): def __getattr__(self, attr): if attr.startswith("create"): cls = globals()[attr[6:]] cls._xmlui_main = self._xmlui_main return cls class XMLUI(xmlui.XMLUI, wx.Frame): """Create an user interface from a SàT XML""" widget_factory = WidgetFactory() def __init__(self, host, xml_data, title=None, flags = None,): self.widget_factory._xmlui_main = self xmlui.XMLUI.__init__(self, host, xml_data, title, flags) def constructUI(self, xml_data): style = wx.DEFAULT_FRAME_STYLE & ~wx.CLOSE_BOX if 'NO_CANCEL' in self.flags else wx.DEFAULT_FRAME_STYLE wx.Frame.__init__(self, None, style=style) self.sizer = wx.BoxSizer(wx.VERTICAL) self.SetSizer(self.sizer) def postTreat(): if self.title: self.SetTitle(self.title) if self.type == 'form': dialogButtons = wx.StdDialogButtonSizer() submitButton = wx.Button(self.main_cont,wx.ID_OK, label=_("Submit")) dialogButtons.AddButton(submitButton) self.main_cont.Bind(wx.EVT_BUTTON, self.onFormSubmitted, submitButton) if not 'NO_CANCEL' in self.flags: cancelButton = wx.Button(self.main_cont,wx.ID_CANCEL) dialogButtons.AddButton(cancelButton) self.main_cont.Bind(wx.EVT_BUTTON, self.onFormCancelled, cancelButton) dialogButtons.Realize() self.main_cont.sizer.Add(dialogButtons, flag=wx.ALIGN_CENTER_HORIZONTAL) self.sizer.Add(self.main_cont, 1, flag=wx.EXPAND) self.sizer.Fit(self) self.Show() super(XMLUI, self).constructUI(xml_data, postTreat) if not 'NO_CANCEL' in self.flags: self.Bind(wx.EVT_CLOSE, self.onClose, self) self.MakeModal() def _xmluiClose(self): self.MakeModal(False) self.Destroy() ###events def onParamChange(self, ctrl): super(XMLUI, self).onParamChange(ctrl) ### FIXME # Some hacks for better presentation, should be generic # FIXME ### if (ctrl._param_category, ctrl._param_name) == ('Connection', 'JabberID'): domain = JID(ctrl._xmluiGetValue()).domain for widget in (ctl['control'] for ctl in self.ctrl_list.values()): if (widget._param_category, widget._param_name) == ('Connection', 'Server'): widget.SetValue(domain) break def onFormSubmitted(self, event): """Called when submit button is clicked""" button = event.GetEventObject() super(XMLUI, self).onFormSubmitted(button) def onClose(self, event): """Close event: we have to send the form.""" debug(_("close")) if self.type == 'param': self.onSaveParams() else: self._xmluiClose() event.Skip()