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
This commit is contained in:
Goffi 2014-08-13 14:48:49 +02:00
commit b6563c596b
11 changed files with 516 additions and 228 deletions

View file

@ -63,6 +63,8 @@ class Const(constants.Const):
# XMLUI # XMLUI
SAT_FORM_PREFIX = "SAT_FORM_" SAT_FORM_PREFIX = "SAT_FORM_"
SAT_PARAM_SEPARATOR = "_XMLUI_PARAM_" # used to have unique elements names SAT_PARAM_SEPARATOR = "_XMLUI_PARAM_" # used to have unique elements names
XMLUI_STATUS_VALIDATED = "validated"
XMLUI_STATUS_CANCELLED = constants.Const.XMLUI_DATA_CANCELLED
# MUC # MUC
ALL_OCCUPANTS = 1 ALL_OCCUPANTS = 1

View file

@ -22,7 +22,7 @@ import urwid
from urwid_satext import sat_widgets from urwid_satext import sat_widgets
from sat_frontends.tools.games import TarotCard from sat_frontends.tools.games import TarotCard
from sat_frontends.quick_frontend.quick_card_game import QuickCardGame from sat_frontends.quick_frontend.quick_card_game import QuickCardGame
from sat_frontends.primitivus.xmlui import XMLUI from sat_frontends.primitivus import xmlui
class CardDisplayer(urwid.Text): class CardDisplayer(urwid.Text):
@ -269,7 +269,7 @@ class CardGame(QuickCardGame, urwid.WidgetWrap):
def chooseContrat(self, xml_data): def chooseContrat(self, xml_data):
"""Called when the player has to select his contrat """Called when the player has to select his contrat
@param xml_data: SàT xml representation of the form""" @param xml_data: SàT xml representation of the form"""
form = XMLUI(self.parent.host, xml_data, title=_('Please choose your contrat'), flags=['NO_CANCEL']) form = xmlui.create(self.parent.host, xml_data, title=_('Please choose your contrat'), flags=['NO_CANCEL'])
form.show(valign='top') form.show(valign='top')
def showCards(self, game_stage, cards, data): def showCards(self, game_stage, cards, data):
@ -288,7 +288,7 @@ class CardGame(QuickCardGame, urwid.WidgetWrap):
title = _("Draw game") title = _("Draw game")
else: else:
title = _('You win \o/') if self.player_nick in winners else _('You loose :(') title = _('You win \o/') if self.player_nick in winners else _('You loose :(')
form = XMLUI(self.parent.host, xml_data, title=title, flags=['NO_CANCEL']) form = xmlui.create(self.parent.host, xml_data, title=title, flags=['NO_CANCEL'])
form.show() form.show()
def invalidCards(self, phase, played_cards, invalid_cards): def invalidCards(self, phase, played_cards, invalid_cards):

View file

@ -24,7 +24,7 @@ from urwid_satext.files_management import FileDialog
from sat_frontends.quick_frontend.quick_chat import QuickChat from sat_frontends.quick_frontend.quick_chat import QuickChat
from sat_frontends.primitivus.card_game import CardGame from sat_frontends.primitivus.card_game import CardGame
from sat_frontends.quick_frontend.quick_utils import escapePrivate, unescapePrivate from sat_frontends.quick_frontend.quick_utils import escapePrivate, unescapePrivate
from sat_frontends.primitivus.xmlui import XMLUI from sat_frontends.primitivus import xmlui
from sat_frontends.primitivus.constants import Const as C from sat_frontends.primitivus.constants import Const as C
import time import time
from sat.tools.jid import JID from sat.tools.jid import JID
@ -352,8 +352,8 @@ class Chat(urwid.WidgetWrap, QuickChat):
self.host.bridge.tarotGameCreate(self.id, list(self.occupants), self.host.profile) self.host.bridge.tarotGameCreate(self.id, list(self.occupants), self.host.profile)
def onConfigureRoom(self, menu): def onConfigureRoom(self, menu):
def gotUI(xmlui): def gotUI(xml_ui):
self.host.addWindow(XMLUI(self.host, xmlui)) self.host.addWindow(xmlui.create(self.host, xml_ui))
def configureError(failure): def configureError(failure):
self.host.showPopUp(sat_widgets.Alert(failure.fullname, failure.message, ok_cb=self.host.removePopUp)) self.host.showPopUp(sat_widgets.Alert(failure.fullname, failure.message, ok_cb=self.host.removePopUp))
self.host.bridge.configureRoom(self.id, self.host.profile, callback=gotUI, errback=configureError) self.host.bridge.configureRoom(self.id, self.host.profile, callback=gotUI, errback=configureError)

View file

@ -33,7 +33,7 @@ from sat_frontends.quick_frontend.quick_utils import getNewPath, unescapePrivate
from sat_frontends.primitivus.profile_manager import ProfileManager from sat_frontends.primitivus.profile_manager import ProfileManager
from sat_frontends.primitivus.contact_list import ContactList from sat_frontends.primitivus.contact_list import ContactList
from sat_frontends.primitivus.chat import Chat from sat_frontends.primitivus.chat import Chat
from sat_frontends.primitivus.xmlui import XMLUI from sat_frontends.primitivus import xmlui
from sat_frontends.primitivus.progress import Progress from sat_frontends.primitivus.progress import Progress
from sat_frontends.primitivus.notify import Notify from sat_frontends.primitivus.notify import Notify
from sat_frontends.tools.misc import InputHistory from sat_frontends.tools.misc import InputHistory
@ -462,7 +462,7 @@ class PrimitivusApp(QuickApp, InputHistory):
# action was a one shot, nothing to do # action was a one shot, nothing to do
pass pass
elif "xmlui" in data: elif "xmlui" in data:
ui = XMLUI(self, xml_data=data['xmlui']) ui = xmlui.create(self, xml_data=data['xmlui'])
ui.show() ui.show()
elif "authenticated_profile" in data: elif "authenticated_profile" in data:
assert("caller" in data) assert("caller" in data)
@ -529,7 +529,7 @@ class PrimitivusApp(QuickApp, InputHistory):
title = _('Registration') title = _('Registration')
misc['target'] = data['target'] misc['target'] = data['target']
misc['action_back'] = self.bridge.gatewayRegister misc['action_back'] = self.bridge.gatewayRegister
ui = XMLUI(self, title=title, xml_data = data['xml'], misc = misc) ui = xmlui.create(self, title=title, xml_data = data['xml'], misc = misc)
if data['type'] == 'registration': if data['type'] == 'registration':
ui.show('popup') ui.show('popup')
else: else:
@ -573,7 +573,7 @@ class PrimitivusApp(QuickApp, InputHistory):
def onParam(self, menu): def onParam(self, menu):
def success(params): def success(params):
self.addWindow(XMLUI(self, xml_data=params)) self.addWindow(xmlui.create(self, xml_data=params))
def failure(error): def failure(error):
self.showPopUp(sat_widgets.Alert(_("Error"), _("Can't get parameters (%s)") % error, ok_cb=self.removePopUp)) self.showPopUp(sat_widgets.Alert(_("Error"), _("Can't get parameters (%s)") % error, ok_cb=self.removePopUp))

View file

@ -19,9 +19,7 @@
from sat.core.i18n import _ from sat.core.i18n import _
import urwid import urwid
import copy
from urwid_satext import sat_widgets from urwid_satext import sat_widgets
from sat_frontends.primitivus.xmlui import XMLUI
from sat_frontends.constants import Const as commonConst from sat_frontends.constants import Const as commonConst
from sat_frontends.primitivus.constants import Const from sat_frontends.primitivus.constants import Const

View file

@ -21,15 +21,17 @@ from sat.core.i18n import _
import urwid import urwid
import copy import copy
from urwid_satext import sat_widgets from urwid_satext import sat_widgets
from urwid_satext import files_management
from sat.core.log import getLogger from sat.core.log import getLogger
log = getLogger(__name__) log = getLogger(__name__)
from sat_frontends.primitivus.constants import Const as C
from sat_frontends.tools import xmlui from sat_frontends.tools import xmlui
class PrimitivusEvents(object): class PrimitivusEvents(object):
""" Used to manage change event of Primitivus widgets """ """ Used to manage change event of Primitivus widgets """
def _event_callback(self, ctrl, *args, **ktkwargs): def _event_callback(self, ctrl, *args, **kwargs):
"""" Call xmlui callback and ignore any extra argument """ """" Call xmlui callback and ignore any extra argument """
args[-1](ctrl) args[-1](ctrl)
@ -40,20 +42,20 @@ class PrimitivusEvents(object):
class PrimitivusEmptyWidget(xmlui.EmptyWidget, urwid.Text): class PrimitivusEmptyWidget(xmlui.EmptyWidget, urwid.Text):
def __init__(self, parent): def __init__(self, _xmlui_parent):
urwid.Text.__init__(self, '') urwid.Text.__init__(self, '')
class PrimitivusTextWidget(xmlui.TextWidget, urwid.Text): class PrimitivusTextWidget(xmlui.TextWidget, urwid.Text):
def __init__(self, parent, value, read_only=False): def __init__(self, _xmlui_parent, value, read_only=False):
urwid.Text.__init__(self, value) urwid.Text.__init__(self, value)
class PrimitivusLabelWidget(xmlui.LabelWidget, PrimitivusTextWidget): class PrimitivusLabelWidget(xmlui.LabelWidget, PrimitivusTextWidget):
def __init__(self, parent, value): def __init__(self, _xmlui_parent, value):
super(PrimitivusLabelWidget, self).__init__(parent, value+": ") super(PrimitivusLabelWidget, self).__init__(_xmlui_parent, value+": ")
class PrimitivusJidWidget(xmlui.JidWidget, PrimitivusTextWidget): class PrimitivusJidWidget(xmlui.JidWidget, PrimitivusTextWidget):
@ -62,7 +64,7 @@ class PrimitivusJidWidget(xmlui.JidWidget, PrimitivusTextWidget):
class PrimitivusDividerWidget(xmlui.DividerWidget, urwid.Divider): class PrimitivusDividerWidget(xmlui.DividerWidget, urwid.Divider):
def __init__(self, parent, style='line'): def __init__(self, _xmlui_parent, style='line'):
if style == 'line': if style == 'line':
div_char = u'─' div_char = u'─'
elif style == 'dot': elif style == 'dot':
@ -82,7 +84,7 @@ class PrimitivusDividerWidget(xmlui.DividerWidget, urwid.Divider):
class PrimitivusStringWidget(xmlui.StringWidget, sat_widgets.AdvancedEdit, PrimitivusEvents): class PrimitivusStringWidget(xmlui.StringWidget, sat_widgets.AdvancedEdit, PrimitivusEvents):
def __init__(self, parent, value, read_only=False): def __init__(self, _xmlui_parent, value, read_only=False):
sat_widgets.AdvancedEdit.__init__(self, edit_text=value) sat_widgets.AdvancedEdit.__init__(self, edit_text=value)
self.read_only = read_only self.read_only = read_only
@ -100,7 +102,7 @@ class PrimitivusStringWidget(xmlui.StringWidget, sat_widgets.AdvancedEdit, Primi
class PrimitivusPasswordWidget(xmlui.PasswordWidget, sat_widgets.Password, PrimitivusEvents): class PrimitivusPasswordWidget(xmlui.PasswordWidget, sat_widgets.Password, PrimitivusEvents):
def __init__(self, parent, value, read_only=False): def __init__(self, _xmlui_parent, value, read_only=False):
sat_widgets.Password.__init__(self, edit_text=value) sat_widgets.Password.__init__(self, edit_text=value)
self.read_only = read_only self.read_only = read_only
@ -118,7 +120,7 @@ class PrimitivusPasswordWidget(xmlui.PasswordWidget, sat_widgets.Password, Primi
class PrimitivusTextBoxWidget(xmlui.TextBoxWidget, sat_widgets.AdvancedEdit, PrimitivusEvents): class PrimitivusTextBoxWidget(xmlui.TextBoxWidget, sat_widgets.AdvancedEdit, PrimitivusEvents):
def __init__(self, parent, value, read_only=False): def __init__(self, _xmlui_parent, value, read_only=False):
sat_widgets.AdvancedEdit.__init__(self, edit_text=value, multiline=True) sat_widgets.AdvancedEdit.__init__(self, edit_text=value, multiline=True)
self.read_only = read_only self.read_only = read_only
@ -136,7 +138,7 @@ class PrimitivusTextBoxWidget(xmlui.TextBoxWidget, sat_widgets.AdvancedEdit, Pri
class PrimitivusBoolWidget(xmlui.BoolWidget, urwid.CheckBox, PrimitivusEvents): class PrimitivusBoolWidget(xmlui.BoolWidget, urwid.CheckBox, PrimitivusEvents):
def __init__(self, parent, state, read_only=False): def __init__(self, _xmlui_parent, state, read_only=False):
urwid.CheckBox.__init__(self, '', state=state) urwid.CheckBox.__init__(self, '', state=state)
self.read_only = read_only self.read_only = read_only
@ -154,7 +156,7 @@ class PrimitivusBoolWidget(xmlui.BoolWidget, urwid.CheckBox, PrimitivusEvents):
class PrimitivusButtonWidget(xmlui.ButtonWidget, sat_widgets.CustomButton, PrimitivusEvents): class PrimitivusButtonWidget(xmlui.ButtonWidget, sat_widgets.CustomButton, PrimitivusEvents):
def __init__(self, parent, value, click_callback): def __init__(self, _xmlui_parent, value, click_callback):
sat_widgets.CustomButton.__init__(self, value, on_press=click_callback) sat_widgets.CustomButton.__init__(self, value, on_press=click_callback)
def _xmluiOnClick(self, callback): def _xmluiOnClick(self, callback):
@ -163,7 +165,7 @@ class PrimitivusButtonWidget(xmlui.ButtonWidget, sat_widgets.CustomButton, Primi
class PrimitivusListWidget(xmlui.ListWidget, sat_widgets.List, PrimitivusEvents): class PrimitivusListWidget(xmlui.ListWidget, sat_widgets.List, PrimitivusEvents):
def __init__(self, parent, options, selected, flags): def __init__(self, _xmlui_parent, options, selected, flags):
sat_widgets.List.__init__(self, options=options, style=flags) sat_widgets.List.__init__(self, options=options, style=flags)
self._xmluiSelectValues(selected) self._xmluiSelectValues(selected)
@ -194,7 +196,7 @@ class PrimitivusListWidget(xmlui.ListWidget, sat_widgets.List, PrimitivusEvents)
class PrimitivusAdvancedListContainer(xmlui.AdvancedListContainer, sat_widgets.TableContainer, PrimitivusEvents): class PrimitivusAdvancedListContainer(xmlui.AdvancedListContainer, sat_widgets.TableContainer, PrimitivusEvents):
def __init__(self, parent, columns, selectable='no'): def __init__(self, _xmlui_parent, columns, selectable='no'):
options = {'ADAPT':()} options = {'ADAPT':()}
if selectable != 'no': if selectable != 'no':
options['HIGHLIGHT'] = () options['HIGHLIGHT'] = ()
@ -219,7 +221,7 @@ class PrimitivusAdvancedListContainer(xmlui.AdvancedListContainer, sat_widgets.T
class PrimitivusPairsContainer(xmlui.PairsContainer, sat_widgets.TableContainer): class PrimitivusPairsContainer(xmlui.PairsContainer, sat_widgets.TableContainer):
def __init__(self, parent): def __init__(self, _xmlui_parent):
options = {'ADAPT':(0,), 'HIGHLIGHT':(0,)} options = {'ADAPT':(0,), 'HIGHLIGHT':(0,)}
if self._xmlui_main.type == 'param': if self._xmlui_main.type == 'param':
options['FOCUS_ATTR'] = 'param_selected' options['FOCUS_ATTR'] = 'param_selected'
@ -234,7 +236,7 @@ class PrimitivusPairsContainer(xmlui.PairsContainer, sat_widgets.TableContainer)
class PrimitivusTabsContainer(xmlui.TabsContainer, sat_widgets.TabsContainer): class PrimitivusTabsContainer(xmlui.TabsContainer, sat_widgets.TabsContainer):
def __init__(self, parent): def __init__(self, _xmlui_parent):
sat_widgets.TabsContainer.__init__(self) sat_widgets.TabsContainer.__init__(self)
def _xmluiAppend(self, widget): def _xmluiAppend(self, widget):
@ -249,7 +251,7 @@ class PrimitivusTabsContainer(xmlui.TabsContainer, sat_widgets.TabsContainer):
class PrimitivusVerticalContainer(xmlui.VerticalContainer, urwid.ListBox): class PrimitivusVerticalContainer(xmlui.VerticalContainer, urwid.ListBox):
BOX_HEIGHT = 5 BOX_HEIGHT = 5
def __init__(self, parent): def __init__(self, _xmlui_parent):
urwid.ListBox.__init__(self, urwid.SimpleListWalker([])) urwid.ListBox.__init__(self, urwid.SimpleListWalker([]))
self._last_size = None self._last_size = None
@ -269,24 +271,81 @@ class PrimitivusVerticalContainer(xmlui.VerticalContainer, urwid.ListBox):
return super(PrimitivusVerticalContainer, self).render(size, focus) return super(PrimitivusVerticalContainer, self).render(size, focus)
class WidgetFactory(object): ### Dialogs ###
class PrimitivusDialog(object):
def __init__(self, _xmlui_parent):
self.host = _xmlui_parent.host
def _xmluiShow(self):
self.host.showPopUp(self)
def _xmluiClose(self):
self.host.removePopUp()
class PrimitivusMessageDialog(PrimitivusDialog, xmlui.MessageDialog, sat_widgets.Alert):
def __init__(self, _xmlui_parent, title, message, level):
PrimitivusDialog.__init__(self, _xmlui_parent)
xmlui.MessageDialog.__init__(self, _xmlui_parent)
sat_widgets.Alert.__init__(self, title, message, ok_cb=lambda dummy: self._xmluiValidated())
class PrimitivusNoteDialog(xmlui.NoteDialog, PrimitivusMessageDialog):
# TODO: separate NoteDialog
pass
class PrimitivusConfirmDialog(PrimitivusDialog, xmlui.ConfirmDialog, sat_widgets.ConfirmDialog):
def __init__(self, _xmlui_parent, title, message, level, buttons_set):
PrimitivusDialog.__init__(self, _xmlui_parent)
xmlui.ConfirmDialog.__init__(self, _xmlui_parent)
sat_widgets.ConfirmDialog.__init__(self, title, message, no_cb=lambda dummy: self._xmluiCancelled(), yes_cb=lambda dummy: self._xmluiValidated())
class PrimitivusFileDialog(PrimitivusDialog, xmlui.FileDialog, files_management.FileDialog):
def __init__(self, _xmlui_parent, title, message, level, filetype):
# TODO: message is not managed yet
PrimitivusDialog.__init__(self, _xmlui_parent)
xmlui.FileDialog.__init__(self, _xmlui_parent)
style = []
if filetype == C.XMLUI_DATA_FILETYPE_DIR:
style.append('dir')
files_management.FileDialog.__init__(self, ok_cb=lambda path: self._xmluiValidated({'path': path}), cancel_cb=lambda dummy: self._xmluiCancelled(), title=title)
class GenericFactory(object):
def __getattr__(self, attr): def __getattr__(self, attr):
if attr.startswith("create"): if attr.startswith("create"):
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 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
return cls
class WidgetFactory(GenericFactory):
def __getattr__(self, attr):
if attr.startswith("create"):
cls = GenericFactory.__getattr__(self, attr)
cls._xmlui_main = self._xmlui_main cls._xmlui_main = self._xmlui_main
return cls return cls
class XMLUI(xmlui.XMLUI, urwid.WidgetWrap):
class XMLUIPanel(xmlui.XMLUIPanel, urwid.WidgetWrap):
widget_factory = WidgetFactory() widget_factory = WidgetFactory()
def __init__(self, host, xml_data, title = None, flags = None): def __init__(self, host, parsed_xml, title = None, flags = None):
self.widget_factory._xmlui_main = self self.widget_factory._xmlui_main = self
self._dest = None self._dest = None
xmlui.XMLUI.__init__(self, host, xml_data, title, flags) xmlui.XMLUIPanel.__init__(self, host, parsed_xml, title, flags)
urwid.WidgetWrap.__init__(self, self.main_cont) urwid.WidgetWrap.__init__(self, self.main_cont)
def constructUI(self, xml_data): def constructUI(self, parsed_dom):
def postTreat(): def postTreat():
assert self.main_cont.body assert self.main_cont.body
@ -311,7 +370,7 @@ class XMLUI(xmlui.XMLUI, urwid.WidgetWrap):
grid_wid = urwid.GridFlow(buttons,max_len,1,0,'center') grid_wid = urwid.GridFlow(buttons,max_len,1,0,'center')
tabs_cont.addFooter(grid_wid) tabs_cont.addFooter(grid_wid)
super(XMLUI, self).constructUI(xml_data, postTreat) xmlui.XMLUIPanel.constructUI(self, parsed_dom, postTreat)
urwid.WidgetWrap.__init__(self, self.main_cont) urwid.WidgetWrap.__init__(self, self.main_cont)
def show(self, show_type=None, valign='middle'): def show(self, show_type=None, valign='middle'):
@ -321,7 +380,7 @@ class XMLUI(xmlui.XMLUI, urwid.WidgetWrap):
- 'popup' - 'popup'
- 'window' - 'window'
@param valign: vertical alignment when show_type is 'popup'. @param valign: vertical alignment when show_type is 'popup'.
Ignored when show_type is 'window'. Ignored when show_type is 'window'.
""" """
if show_type is None: if show_type is None:
@ -343,9 +402,17 @@ class XMLUI(xmlui.XMLUI, urwid.WidgetWrap):
assert(False) assert(False)
self.host.redraw() self.host.redraw()
def _xmluiClose(self): def _xmluiClose(self):
if self._dest == 'window': if self._dest == 'window':
self.host.removeWindow() self.host.removeWindow()
else: else:
self.host.removePopUp() self.host.removePopUp()
class XMLUIDialog(xmlui.XMLUIDialog):
dialog_factory = GenericFactory()
xmlui.registerClass(xmlui.CLASS_PANEL, XMLUIPanel)
xmlui.registerClass(xmlui.CLASS_DIALOG, XMLUIDialog)
create = xmlui.create

View file

@ -20,14 +20,21 @@
from sat.core.i18n import _ from sat.core.i18n import _
from sat.core.log import getLogger from sat.core.log import getLogger
log = getLogger(__name__) log = getLogger(__name__)
from sat_frontends.constants import Const from sat_frontends.constants import Const as C
from sat.core.exceptions import DataError from sat.core.exceptions import DataError
class_map = {}
CLASS_PANEL = 'panel'
CLASS_DIALOG = 'dialog'
class InvalidXMLUI(Exception): class InvalidXMLUI(Exception):
pass pass
class ClassNotRegistedError(Exception):
pass
def getText(node): def getText(node):
"""Get child text nodes """Get child text nodes
@param node: dom Node @param node: dom Node
@ -42,166 +49,179 @@ def getText(node):
class Widget(object): class Widget(object):
""" base Widget """ """base Widget"""
pass pass
class EmptyWidget(Widget): class EmptyWidget(Widget):
""" Just a placeholder widget """ """Just a placeholder widget"""
pass pass
class TextWidget(Widget): class TextWidget(Widget):
""" Non interactive text """ """Non interactive text"""
pass pass
class LabelWidget(Widget): class LabelWidget(Widget):
""" Non interactive text """ """Non interactive text"""
pass pass
class JidWidget(Widget): class JidWidget(Widget):
""" Jabber ID """ """Jabber ID"""
pass pass
class DividerWidget(Widget): class DividerWidget(Widget):
""" Separator """ """Separator"""
pass pass
class StringWidget(Widget): class StringWidget(Widget):
""" Input widget with require a string """Input widget wich require a string
often called Edit in toolkits
often called Edit in toolkits
""" """
class PasswordWidget(Widget): class PasswordWidget(Widget):
""" Input widget with require a masked string """Input widget with require a masked string"""
"""
class TextBoxWidget(Widget): class TextBoxWidget(Widget):
""" Input widget with require a long, possibly multilines string """Input widget with require a long, possibly multilines string
often called TextArea in toolkits often called TextArea in toolkits
""" """
class BoolWidget(Widget): class BoolWidget(Widget):
""" Input widget with require a boolean value """Input widget with require a boolean value
often called CheckBox in toolkits often called CheckBox in toolkits
""" """
class ButtonWidget(Widget): class ButtonWidget(Widget):
""" A clickable widget """ """A clickable widget"""
class ListWidget(Widget): class ListWidget(Widget):
""" A widget able to show/choose one or several strings in a list """ """A widget able to show/choose one or several strings in a list"""
class Container(Widget): class Container(Widget):
""" Widget which can contain other ones with a specific layout """ """Widget which can contain other ones with a specific layout"""
@classmethod @classmethod
def _xmluiAdapt(cls, instance): def _xmluiAdapt(cls, instance):
""" Make cls as instance.__class__ """Make cls as instance.__class__
cls must inherit from original instance class cls must inherit from original instance class
Usefull when you get a class from UI toolkit Usefull when you get a class from UI toolkit
""" """
assert instance.__class__ in cls.__bases__ assert instance.__class__ in cls.__bases__
instance.__class__ = type(cls.__name__, cls.__bases__, dict(cls.__dict__)) instance.__class__ = type(cls.__name__, cls.__bases__, dict(cls.__dict__))
class PairsContainer(Container): class PairsContainer(Container):
""" Widgets are disposed in rows of two (usually label/input) """ """Widgets are disposed in rows of two (usually label/input) """
pass
class TabsContainer(Container): class TabsContainer(Container):
""" A container which several other containers in tabs """A container which several other containers in tabs
Often called Notebook in toolkits
Often called Notebook in toolkits
""" """
class VerticalContainer(Container): class VerticalContainer(Container):
""" Widgets are disposed vertically """ """Widgets are disposed vertically"""
pass
class AdvancedListContainer(Container): class AdvancedListContainer(Container):
""" Widgets are disposed in rows with advaned features """ """Widgets are disposed in rows with advaned features"""
pass
class XMLUI(object): class Dialog(object):
""" Base class to construct SàT XML User Interface """base dialog"""
New frontends can inherite this class to easily implement XMLUI
@property widget_factory: factory to create frontend-specific widgets
@proporety dialog_factory: factory to create frontend-specific dialogs
def __init__(self, _xmlui_parent):
self._xmlui_parent = _xmlui_parent
def _xmluiValidated(self, data=None):
if data is None:
data = {}
self._xmluiSetData(C.XMLUI_STATUS_VALIDATED, data)
self._xmluiSubmit(data)
self._xmluiClose()
def _xmluiCancelled(self):
data = {C.XMLUI_DATA_CANCELLED: C.BOOL_TRUE}
self._xmluiSetData(C.XMLUI_STATUS_CANCELLED, data)
self._xmluiSubmit(data)
self._xmluiClose()
def _xmluiSubmit(self, data):
self._xmlui_parent.submit(data)
def _xmluiSetData(self, status, data):
pass
class MessageDialog(Dialog):
"""Dialog with a OK/Cancel type configuration"""
class NoteDialog(Dialog):
"""Dialog with a OK/Cancel type configuration"""
class ConfirmDialog(Dialog):
"""Dialog with a OK/Cancel type configuration"""
def _xmluiSetData(self, status, data):
if status == C.XMLUI_STATUS_VALIDATED:
data[C.XMLUI_DATA_ANSWER] = C.BOOL_TRUE
elif status == C.XMLUI_STATUS_CANCELLED:
data[C.XMLUI_DATA_ANSWER] = C.BOOL_FALSE
class FileDialog(Dialog):
"""Dialog with a OK/Cancel type configuration"""
class XMLUIBase(object):
"""Base class to construct SàT XML User Interface
This class must not be instancied directly
""" """
widget_factory = None
dialog_factory = None # TODO
def __init__(self, host, xml_data, title = None, flags = None, dom_parse=None, dom_free=None): def __init__(self, host, parsed_dom, title = None, flags = None):
""" Initialise the XMLUI instance """Initialise the XMLUI instance
@param host: %(doc_host)s @param host: %(doc_host)s
@param xml_data: the raw XML containing the UI @param parsed_dom: main parsed dom
@param title: force the title, or use XMLUI one if None @param title: force the title, or use XMLUI one if None
@param flags: list of string which can be: @param flags: list of string which can be:
- NO_CANCEL: the UI can't be cancelled - NO_CANCEL: the UI can't be cancelled
@param dom_parse: methode equivalent to minidom.parseString (but which must manage unicode), or None to use default one
@param dom_free: method used to free the parsed DOM
""" """
if dom_parse is None:
from xml.dom import minidom
self.dom_parse = lambda xml_data: minidom.parseString(xml_data.encode('utf-8'))
self.dom_free = lambda cat_dom: cat_dom.unlink()
else:
self.dom_parse = dom_parse
self.dom_free = dom_free or (lambda cat_dom: None)
self.host = host self.host = host
self.title = title or "" top=parsed_dom.documentElement
self.session_id = top.getAttribute("session_id") or None
self.submit_id = top.getAttribute("submit") or None
self.title = title or top.getAttribute("title") or u""
if flags is None: if flags is None:
flags = [] flags = []
self.flags = flags self.flags = flags
self.ctrl_list = {} # usefull to access ctrl
self._main_cont = None
self.constructUI(xml_data)
def escape(self, name):
""" return escaped name for forms """
return u"%s%s" % (Const.SAT_FORM_PREFIX, name)
@property
def main_cont(self):
return self._main_cont
@main_cont.setter
def main_cont(self, value):
if self._main_cont is not None:
raise ValueError(_("XMLUI can have only one main container"))
self._main_cont = value
def _isAttrSet(self, name, node): def _isAttrSet(self, name, node):
"""Returnw widget boolean attribute status """Returnw widget boolean attribute status
@param name: name of the attribute (e.g. "read_only") @param name: name of the attribute (e.g. "read_only")
@param node: Node instance @param node: Node instance
@return (bool): True if widget's attribute is set ("true") @return (bool): True if widget's attribute is set (C.BOOL_TRUE)
""" """
read_only = node.getAttribute(name) or "false" read_only = node.getAttribute(name) or C.BOOL_FALSE
return read_only.lower().strip() == "true" return read_only.lower().strip() == C.BOOL_TRUE
def _getChildNode(self, node, name): def _getChildNode(self, node, name):
"""Return the first child node with the given name """Return the first child node with the given name
@ -216,13 +236,55 @@ class XMLUI(object):
return child return child
return None return None
def _parseChilds(self, parent, current_node, wanted = ('container',), data = None): def submit(self, data):
if self.submit_id is None:
raise ValueError("Can't submit is self.submit_id is not set")
if "session_id" in data:
raise ValueError("session_id must no be used in data, it is automaticaly filled with self.session_id if present")
if self.session_id is not None:
data["session_id"] = self.session_id
self._xmluiLaunchAction(self.submit_id, data)
def _xmluiLaunchAction(self, action_id, data):
self.host.launchAction(action_id, data, profile_key = self.host.profile)
class XMLUIPanel(XMLUIBase):
"""XMLUI Panel
New frontends can inherite this class to easily implement XMLUI
@property widget_factory: factory to create frontend-specific widgets
@proporety dialog_factory: factory to create frontend-specific dialogs
"""
widget_factory = None
def __init__(self, host, parsed_dom, title = None, flags = None):
super(XMLUIPanel, self).__init__(host, parsed_dom, title = None, flags = None)
self.ctrl_list = {} # usefull to access ctrl
self._main_cont = None
self.constructUI(parsed_dom)
def escape(self, name):
"""Return escaped name for forms"""
return u"%s%s" % (C.SAT_FORM_PREFIX, name)
@property
def main_cont(self):
return self._main_cont
@main_cont.setter
def main_cont(self, value):
if self._main_cont is not None:
raise ValueError(_("XMLUI can have only one main container"))
self._main_cont = value
def _parseChilds(self, _xmlui_parent, current_node, wanted = ('container',), data = None):
"""Recursively parse childNodes of an elemen """Recursively parse childNodes of an elemen
@param parent: widget container with '_xmluiAppend' method
@param _xmlui_parent: widget container with '_xmluiAppend' method
@param current_node: element from which childs will be parsed @param current_node: element from which childs will be parsed
@param wanted: list of tag names that can be present in the childs to be SàT XMLUI compliant @param wanted: list of tag names that can be present in the childs to be SàT XMLUI compliant
@param data: additionnal data which are needed in some cases @param data: additionnal data which are needed in some cases
""" """
for node in current_node.childNodes: for node in current_node.childNodes:
if wanted and not node.nodeName in wanted: if wanted and not node.nodeName in wanted:
@ -230,18 +292,18 @@ class XMLUI(object):
if node.nodeName == "container": if node.nodeName == "container":
type_ = node.getAttribute('type') type_ = node.getAttribute('type')
if parent is self and type_ != 'vertical': if _xmlui_parent is self and type_ != 'vertical':
# main container is not a VerticalContainer and we want one, so we create one to wrap it # main container is not a VerticalContainer and we want one, so we create one to wrap it
parent = self.widget_factory.createVerticalContainer(self) _xmlui_parent = self.widget_factory.createVerticalContainer(self)
self.main_cont = parent self.main_cont = _xmlui_parent
if type_ == "tabs": if type_ == "tabs":
cont = self.widget_factory.createTabsContainer(parent) cont = self.widget_factory.createTabsContainer(_xmlui_parent)
self._parseChilds(parent, node, ('tab',), cont) self._parseChilds(_xmlui_parent, node, ('tab',), cont)
elif type_ == "vertical": elif type_ == "vertical":
cont = self.widget_factory.createVerticalContainer(parent) cont = self.widget_factory.createVerticalContainer(_xmlui_parent)
self._parseChilds(cont, node, ('widget', 'container')) self._parseChilds(cont, node, ('widget', 'container'))
elif type_ == "pairs": elif type_ == "pairs":
cont = self.widget_factory.createPairsContainer(parent) cont = self.widget_factory.createPairsContainer(_xmlui_parent)
self._parseChilds(cont, node, ('widget', 'container')) self._parseChilds(cont, node, ('widget', 'container'))
elif type_ == "advanced_list": elif type_ == "advanced_list":
try: try:
@ -249,9 +311,9 @@ class XMLUI(object):
except (TypeError, ValueError): except (TypeError, ValueError):
raise DataError("Invalid columns") raise DataError("Invalid columns")
selectable = node.getAttribute('selectable') or 'no' selectable = node.getAttribute('selectable') or 'no'
auto_index = node.getAttribute('auto_index') == 'true' auto_index = node.getAttribute('auto_index') == C.BOOL_TRUE
data = {'index': 0} if auto_index else None data = {'index': 0} if auto_index else None
cont = self.widget_factory.createAdvancedListContainer(parent, columns, selectable) cont = self.widget_factory.createAdvancedListContainer(_xmlui_parent, columns, selectable)
callback_id = node.getAttribute("callback") or None callback_id = node.getAttribute("callback") or None
if callback_id is not None: if callback_id is not None:
if selectable == 'no': if selectable == 'no':
@ -262,12 +324,12 @@ class XMLUI(object):
self._parseChilds(cont, node, ('row',), data) self._parseChilds(cont, node, ('row',), data)
else: else:
log.warning(_("Unknown container [%s], using default one") % type_) log.warning(_("Unknown container [%s], using default one") % type_)
cont = self.widget_factory.createVerticalContainer(parent) cont = self.widget_factory.createVerticalContainer(_xmlui_parent)
self._parseChilds(cont, node, ('widget', 'container')) self._parseChilds(cont, node, ('widget', 'container'))
try: try:
parent._xmluiAppend(cont) _xmlui_parent._xmluiAppend(cont)
except (AttributeError, TypeError): # XXX: TypeError is here because pyjamas raise a TypeError instead of an AttributeError except (AttributeError, TypeError): # XXX: TypeError is here because pyjamas raise a TypeError instead of an AttributeError
if parent is self: if _xmlui_parent is self:
self.main_cont = cont self.main_cont = cont
else: else:
raise Exception(_("Internal Error, container has not _xmluiAppend method")) raise Exception(_("Internal Error, container has not _xmluiAppend method"))
@ -289,11 +351,10 @@ class XMLUI(object):
data['index'] += 1 data['index'] += 1
except TypeError: except TypeError:
index = node.getAttribute('index') or None index = node.getAttribute('index') or None
parent._xmluiAddRow(index) _xmlui_parent._xmluiAddRow(index)
self._parseChilds(parent, node, ('widget', 'container')) self._parseChilds(_xmlui_parent, node, ('widget', 'container'))
elif node.nodeName == "widget": elif node.nodeName == "widget":
id_ = node.getAttribute("id")
name = node.getAttribute("name") name = node.getAttribute("name")
type_ = node.getAttribute("type") type_ = node.getAttribute("type")
value_elt = self._getChildNode(node, "value") value_elt = self._getChildNode(node, "value")
@ -302,37 +363,37 @@ class XMLUI(object):
else: else:
value = node.getAttribute("value") if node.hasAttribute('value') else u'' value = node.getAttribute("value") if node.hasAttribute('value') else u''
if type_=="empty": if type_=="empty":
ctrl = self.widget_factory.createEmptyWidget(parent) ctrl = self.widget_factory.createEmptyWidget(_xmlui_parent)
elif type_=="text": elif type_=="text":
ctrl = self.widget_factory.createTextWidget(parent, value) ctrl = self.widget_factory.createTextWidget(_xmlui_parent, value)
elif type_=="label": elif type_=="label":
ctrl = self.widget_factory.createLabelWidget(parent, value) ctrl = self.widget_factory.createLabelWidget(_xmlui_parent, value)
elif type_=="jid": elif type_=="jid":
ctrl = self.widget_factory.createJidWidget(parent, value) ctrl = self.widget_factory.createJidWidget(_xmlui_parent, value)
elif type_=="divider": elif type_=="divider":
style = node.getAttribute("style") or 'line' style = node.getAttribute("style") or 'line'
ctrl = self.widget_factory.createDividerWidget(parent, style) ctrl = self.widget_factory.createDividerWidget(_xmlui_parent, style)
elif type_=="string": elif type_=="string":
ctrl = self.widget_factory.createStringWidget(parent, value, self._isAttrSet("read_only", node)) ctrl = self.widget_factory.createStringWidget(_xmlui_parent, value, self._isAttrSet("read_only", node))
self.ctrl_list[name] = ({'type':type_, 'control':ctrl}) self.ctrl_list[name] = ({'type':type_, 'control':ctrl})
elif type_=="password": elif type_=="password":
ctrl = self.widget_factory.createPasswordWidget(parent, value, self._isAttrSet("read_only", node)) ctrl = self.widget_factory.createPasswordWidget(_xmlui_parent, value, self._isAttrSet("read_only", node))
self.ctrl_list[name] = ({'type':type_, 'control':ctrl}) self.ctrl_list[name] = ({'type':type_, 'control':ctrl})
elif type_=="textbox": elif type_=="textbox":
ctrl = self.widget_factory.createTextBoxWidget(parent, value, self._isAttrSet("read_only", node)) ctrl = self.widget_factory.createTextBoxWidget(_xmlui_parent, value, self._isAttrSet("read_only", node))
self.ctrl_list[name] = ({'type':type_, 'control':ctrl}) self.ctrl_list[name] = ({'type':type_, 'control':ctrl})
elif type_=="bool": elif type_=="bool":
ctrl = self.widget_factory.createBoolWidget(parent, value=='true', self._isAttrSet("read_only", node)) ctrl = self.widget_factory.createBoolWidget(_xmlui_parent, value==C.BOOL_TRUE, self._isAttrSet("read_only", node))
self.ctrl_list[name] = ({'type':type_, 'control':ctrl}) self.ctrl_list[name] = ({'type':type_, 'control':ctrl})
elif type_ == "list": elif type_ == "list":
style = [] if node.getAttribute("multi") == 'yes' else ['single'] style = [] if node.getAttribute("multi") == 'yes' else ['single']
_options = [(option.getAttribute("value"), option.getAttribute("label")) for option in node.getElementsByTagName("option")] _options = [(option.getAttribute("value"), option.getAttribute("label")) for option in node.getElementsByTagName("option")]
_selected = [option.getAttribute("value") for option in node.getElementsByTagName("option") if option.getAttribute('selected') == 'true'] _selected = [option.getAttribute("value") for option in node.getElementsByTagName("option") if option.getAttribute('selected') == C.BOOL_TRUE]
ctrl = self.widget_factory.createListWidget(parent, _options, _selected, style) ctrl = self.widget_factory.createListWidget(_xmlui_parent, _options, _selected, style)
self.ctrl_list[name] = ({'type': type_, 'control': ctrl}) self.ctrl_list[name] = ({'type': type_, 'control': ctrl})
elif type_=="button": elif type_=="button":
callback_id = node.getAttribute("callback") callback_id = node.getAttribute("callback")
ctrl = self.widget_factory.createButtonWidget(parent, value, self.onButtonPress) ctrl = self.widget_factory.createButtonWidget(_xmlui_parent, value, self.onButtonPress)
ctrl._xmlui_param_id = (callback_id, [field.getAttribute('name') for field in node.getElementsByTagName("field_back")]) ctrl._xmlui_param_id = (callback_id, [field.getAttribute('name') for field in node.getElementsByTagName("field_back")])
else: else:
log.error(_("FIXME FIXME FIXME: widget type [%s] is not implemented") % type_) log.error(_("FIXME FIXME FIXME: widget type [%s] is not implemented") % type_)
@ -358,55 +419,47 @@ class XMLUI(object):
ctrl._xmluiOnChange(self.onChangeInternal) ctrl._xmluiOnChange(self.onChangeInternal)
ctrl._xmlui_name = name ctrl._xmlui_name = name
parent._xmluiAppend(ctrl) _xmlui_parent._xmluiAppend(ctrl)
else: else:
raise NotImplementedError(_('Unknown tag [%s]') % node.nodeName) raise NotImplementedError(_('Unknown tag [%s]') % node.nodeName)
def constructUI(self, xml_data, post_treat=None): def constructUI(self, parsed_dom, post_treat=None):
""" Actually construct the UI """Actually construct the UI
@param xml_data: raw XMLUI
@param parsed_dom: main parsed dom
@param post_treat: frontend specific treatments to do once the UI is constructed @param post_treat: frontend specific treatments to do once the UI is constructed
@return: constructed widget @return: constructed widget
""" """
cat_dom = self.dom_parse(xml_data) top=parsed_dom.documentElement
top=cat_dom.documentElement
self.type = top.getAttribute("type") self.type = top.getAttribute("type")
self.title = self.title or top.getAttribute("title") or u""
self.session_id = top.getAttribute("session_id") or None
self.submit_id = top.getAttribute("submit") or None
if top.nodeName != "sat_xmlui" or not self.type in ['form', 'param', 'window', 'popup']: if top.nodeName != "sat_xmlui" or not self.type in ['form', 'param', 'window', 'popup']:
raise InvalidXMLUI raise InvalidXMLUI
if self.type == 'param': if self.type == 'param':
self.param_changed = set() self.param_changed = set()
self._parseChilds(self, cat_dom.documentElement) self._parseChilds(self, parsed_dom.documentElement)
if post_treat is not None: if post_treat is not None:
post_treat() post_treat()
self.dom_free(cat_dom)
def _xmluiClose(self): def _xmluiClose(self):
""" Close the window/popup/... where the constructeur XMLUI is """Close the window/popup/... where the constructeur XMLUI is
this method must be overrided
this method must be overrided
""" """
raise NotImplementedError raise NotImplementedError
def _xmluiLaunchAction(self, action_id, data):
self.host.launchAction(action_id, data, profile_key = self.host.profile)
def _xmluiSetParam(self, name, value, category): def _xmluiSetParam(self, name, value, category):
self.host.bridge.setParam(name, value, category, profile_key=self.host.profile) self.host.bridge.setParam(name, value, category, profile_key=self.host.profile)
##EVENTS## ##EVENTS##
def onParamChange(self, ctrl): def onParamChange(self, ctrl):
""" Called when type is param and a widget to save is modified """Called when type is param and a widget to save is modified
@param ctrl: widget modified
@param ctrl: widget modified
""" """
assert(self.type == "param") assert(self.type == "param")
self.param_changed.add(ctrl) self.param_changed.add(ctrl)
@ -431,10 +484,10 @@ class XMLUI(object):
self._xmluiLaunchAction(callback_id, data) self._xmluiLaunchAction(callback_id, data)
def onButtonPress(self, button): def onButtonPress(self, button):
""" Called when an XMLUI button is clicked """Called when an XMLUI button is clicked
Launch the action associated to the button Launch the action associated to the button
@param button: the button clicked @param button: the button clicked
""" """
callback_id, fields = button._xmlui_param_id callback_id, fields = button._xmlui_param_id
if not callback_id: # the button is probably bound to an internal action if not callback_id: # the button is probably bound to an internal action
@ -450,7 +503,7 @@ class XMLUI(object):
self._xmluiLaunchAction(callback_id, data) self._xmluiLaunchAction(callback_id, data)
def onChangeInternal(self, ctrl): def onChangeInternal(self, ctrl):
""" Called when a widget that has been bound to an internal callback is changed. """Called when a widget that has been bound to an internal callback is changed.
This is used to perform some UI actions without communicating with the backend. This is used to perform some UI actions without communicating with the backend.
See sat.tools.xml_tools.Widget.setInternalCallback for more details. See sat.tools.xml_tools.Widget.setInternalCallback for more details.
@ -507,14 +560,14 @@ class XMLUI(object):
def getInternalCallbackData(self, action, node): def getInternalCallbackData(self, action, node):
"""Retrieve from node the data needed to perform given action. """Retrieve from node the data needed to perform given action.
TODO: it would be better to not have a specific way to retrieve
data for each action, but instead to have a generic method to
extract any kind of data structure from the 'internal_data' element.
@param action (string): a value from the one that can be passed to the @param action (string): a value from the one that can be passed to the
'callback' parameter of sat.tools.xml_tools.Widget.setInternalCallback 'callback' parameter of sat.tools.xml_tools.Widget.setInternalCallback
@param node (DOM Element): the node of the widget that triggers the callback @param node (DOM Element): the node of the widget that triggers the callback
""" """
# TODO: it would be better to not have a specific way to retrieve
# data for each action, but instead to have a generic method to
# extract any kind of data structure from the 'internal_data' element.
try: # data is stored in the first 'internal_data' element of the node try: # data is stored in the first 'internal_data' element of the node
data_elts = node.getElementsByTagName('internal_data')[0].childNodes data_elts = node.getElementsByTagName('internal_data')[0].childNodes
except IndexError: except IndexError:
@ -529,9 +582,9 @@ class XMLUI(object):
return data return data
def onFormSubmitted(self, ignore=None): def onFormSubmitted(self, ignore=None):
""" An XMLUI form has been submited """An XMLUI form has been submited
call the submit action associated with this form
call the submit action associated with this form
""" """
selected_values = [] selected_values = []
for ctrl_name in self.ctrl_list: for ctrl_name in self.ctrl_list:
@ -543,23 +596,20 @@ class XMLUI(object):
selected_values.append((escaped, ctrl['control']._xmluiGetValue())) selected_values.append((escaped, ctrl['control']._xmluiGetValue()))
if self.submit_id is not None: if self.submit_id is not None:
data = dict(selected_values) data = dict(selected_values)
if self.session_id is not None: self.submit(data)
data["session_id"] = self.session_id
self._xmluiLaunchAction(self.submit_id, data)
else: else:
log.warning(_("The form data is not sent back, the type is not managed properly")) log.warning(_("The form data is not sent back, the type is not managed properly"))
self._xmluiClose() self._xmluiClose()
def onFormCancelled(self, ignore=None): def onFormCancelled(self, ignore=None):
""" Called when a form is cancelled """ """Called when a form is cancelled"""
log.debug(_("Cancelling form")) log.debug(_("Cancelling form"))
self._xmluiClose() self._xmluiClose()
def onSaveParams(self, ignore=None): def onSaveParams(self, ignore=None):
""" Params are saved, we send them to backend """Params are saved, we send them to backend
self.type must be param
self.type must be param
""" """
assert(self.type == 'param') assert(self.type == 'param')
for ctrl in self.param_changed: for ctrl in self.param_changed:
@ -567,7 +617,92 @@ class XMLUI(object):
value = u'\t'.join(ctrl._xmluiGetSelectedValues()) value = u'\t'.join(ctrl._xmluiGetSelectedValues())
else: else:
value = ctrl._xmluiGetValue() value = ctrl._xmluiGetValue()
param_name = ctrl._xmlui_name.split(Const.SAT_PARAM_SEPARATOR)[1] param_name = ctrl._xmlui_name.split(C.SAT_PARAM_SEPARATOR)[1]
self._xmluiSetParam(param_name, value, ctrl._param_category) self._xmluiSetParam(param_name, value, ctrl._param_category)
self._xmluiClose() self._xmluiClose()
def show(self, *args, **kwargs):
pass
class XMLUIDialog(XMLUIBase):
dialog_factory = None
def __init__(self, host, parsed_dom, title = None, flags = None):
super(XMLUIDialog, self).__init__(host, parsed_dom, title = None, flags = None)
top=parsed_dom.documentElement
dlg_elt = self._getChildNode(top, "dialog")
if dlg_elt is None:
raise ValueError("Invalid XMLUI: no Dialog element found !")
dlg_type = dlg_elt.getAttribute("type") or C.XMLUI_DIALOG_MESSAGE
try:
mess_elt = self._getChildNode(dlg_elt, C.XMLUI_DATA_MESS)
message = getText(mess_elt)
except (TypeError, AttributeError): # XXX: TypeError is here because pyjamas raise a TypeError instead of an AttributeError
message = ""
level = dlg_elt.getAttribute(C.XMLUI_DATA_LVL) or C.XMLUI_DATA_LVL_INFO
if dlg_type == C.XMLUI_DIALOG_MESSAGE:
self.dlg = self.dialog_factory.createMessageDialog(self, self.title, message, level)
elif dlg_type == C.XMLUI_DIALOG_NOTE:
self.dlg = self.dialog_factory.createNoteDialog(self, self.title, message, level)
elif dlg_type == C.XMLUI_DIALOG_CONFIRM:
try:
buttons_elt = self._getChildNode(dlg_elt, "buttons")
buttons_set = buttons_elt.getAttribute("set") or C.XMLUI_DATA_BTNS_SET_DEFAULT
except (TypeError, AttributeError): # XXX: TypeError is here because pyjamas raise a TypeError instead of an AttributeError
buttons_set = C.XMLUI_DATA_BTNS_SET_DEFAULT
self.dlg = self.dialog_factory.createConfirmDialog(self, self.title, message, level, buttons_set)
elif dlg_type == C.XMLUI_DIALOG_FILE:
try:
file_elt = self._getChildNode(dlg_elt, "file")
filetype = file_elt.getAttribute("type") or C.XMLUI_DATA_FILETYPE_DEFAULT
except (TypeError, AttributeError): # XXX: TypeError is here because pyjamas raise a TypeError instead of an AttributeError
filetype = C.XMLUI_DATA_FILETYPE_DEFAULT
self.dlg = self.dialog_factory.createFileDialog(self, self.title, message, level, filetype)
else:
raise ValueError("Unknown dialog type [%s]" % dlg_type)
def show(self):
self.dlg._xmluiShow()
def registerClass(type_, class_):
"""Register the class to use with the factory
@param type_: one of:
CLASS_PANEL: classical XMLUI interface
CLASS_DIALOG: XMLUI dialog
@param class_: the class to use to instanciate given type
"""
assert type_ in (CLASS_PANEL, CLASS_DIALOG)
class_map[type_] = class_
def create(host, xml_data, title = None, flags = None, dom_parse=None, dom_free=None):
"""
@param dom_parse: methode equivalent to minidom.parseString (but which must manage unicode), or None to use default one
@param dom_free: method used to free the parsed DOM
"""
if dom_parse is None:
from xml.dom import minidom
dom_parse = lambda xml_data: minidom.parseString(xml_data.encode('utf-8'))
dom_free = lambda parsed_dom: parsed_dom.unlink()
else:
dom_parse = dom_parse
dom_free = dom_free or (lambda parsed_dom: None)
parsed_dom = dom_parse(xml_data)
top=parsed_dom.documentElement
ui_type = top.getAttribute("type")
try:
if ui_type != C.XMLUI_DIALOG:
cls = class_map[CLASS_PANEL]
else:
cls = class_map[CLASS_DIALOG]
except KeyError:
raise ClassNotRegistedError(_("You must register classes with registerClass before creating a XMLUI"))
xmlui = cls(host, parsed_dom, title, flags)
dom_free(parsed_dom)
return xmlui

View file

@ -25,7 +25,7 @@ from sat.core.log import getLogger
log = getLogger(__name__) log = getLogger(__name__)
from sat_frontends.tools.games import TarotCard from sat_frontends.tools.games import TarotCard
from sat_frontends.quick_frontend.quick_card_game import QuickCardGame from sat_frontends.quick_frontend.quick_card_game import QuickCardGame
from sat_frontends.wix.xmlui import XMLUI from sat_frontends.wix import xmlui
CARD_WIDTH = 74 CARD_WIDTH = 74
CARD_HEIGHT = 136 CARD_HEIGHT = 136
@ -103,7 +103,7 @@ class CardPanel(QuickCardGame, wx.Panel):
def chooseContrat(self, xml_data): def chooseContrat(self, xml_data):
"""Called when the player has to select his contrat """Called when the player has to select his contrat
@param xml_data: SàT xml representation of the form""" @param xml_data: SàT xml representation of the form"""
XMLUI(self.parent.host, xml_data, title=_('Please choose your contrat'), flags=['NO_CANCEL']) xmlui.create(self.parent.host, xml_data, title=_('Please choose your contrat'), flags=['NO_CANCEL'])
def showScores(self, xml_data, winners, loosers): def showScores(self, xml_data, winners, loosers):
"""Called when the round is over, display the scores """Called when the round is over, display the scores
@ -112,7 +112,7 @@ class CardPanel(QuickCardGame, wx.Panel):
title = _("Draw game") title = _("Draw game")
else: else:
title = _('You win \o/') if self.player_nick in winners else _('You loose :(') title = _('You win \o/') if self.player_nick in winners else _('You loose :(')
XMLUI(self.parent.host, xml_data, title=title, flags=['NO_CANCEL']) xmlui.create(self.parent.host, xml_data, title=title, flags=['NO_CANCEL'])
def cardsPlayed(self, player, cards): def cardsPlayed(self, player, cards):
"""A card has been played by player""" """A card has been played by player"""

View file

@ -25,7 +25,7 @@ from sat_frontends.quick_frontend.quick_app import QuickApp
import wx import wx
from sat_frontends.wix.contact_list import ContactList from sat_frontends.wix.contact_list import ContactList
from sat_frontends.wix.chat import Chat from sat_frontends.wix.chat import Chat
from sat_frontends.wix.xmlui import XMLUI from sat_frontends.wix import xmlui
from sat_frontends.wix.profile import Profile from sat_frontends.wix.profile import Profile
from sat_frontends.wix.profile_manager import ProfileManager from sat_frontends.wix.profile_manager import ProfileManager
import os.path import os.path
@ -192,16 +192,16 @@ class MainWindow(wx.Frame, QuickApp):
popup.Show() popup.Show()
wx.CallLater(5000,popup.Destroy) wx.CallLater(5000,popup.Destroy)
def showDialog(self, message, title="", type="info", answer_cb = None, answer_data = None): def showDialog(self, message, title="", type_="info", answer_cb = None, answer_data = None):
if type == 'info': if type_ == 'info':
flags = wx.OK | wx.ICON_INFORMATION flags = wx.OK | wx.ICON_INFORMATION
elif type == 'error': elif type_ == 'error':
flags = wx.OK | wx.ICON_ERROR flags = wx.OK | wx.ICON_ERROR
elif type == 'yes/no': elif type_ == 'yes/no':
flags = wx.YES_NO | wx.ICON_QUESTION flags = wx.YES_NO | wx.ICON_QUESTION
else: else:
flags = wx.OK | wx.ICON_INFORMATION flags = wx.OK | wx.ICON_INFORMATION
log.error(_('unmanaged dialog type: %s'), type) log.error(_('unmanaged dialog type: %s'), type_)
dlg = wx.MessageDialog(self, message, title, flags) dlg = wx.MessageDialog(self, message, title, flags)
answer = dlg.ShowModal() answer = dlg.ShowModal()
dlg.Destroy() dlg.Destroy()
@ -243,7 +243,8 @@ class MainWindow(wx.Frame, QuickApp):
pass pass
elif "xmlui" in data: elif "xmlui" in data:
log.debug (_("XML user interface received")) log.debug (_("XML user interface received"))
XMLUI(self, xml_data = data['xmlui']) ui = xmlui.create(self, xml_data = data['xmlui'])
ui.show()
elif "authenticated_profile" in data: elif "authenticated_profile" in data:
assert("caller" in data) assert("caller" in data)
if data["caller"] == "profile_manager": if data["caller"] == "profile_manager":
@ -345,7 +346,7 @@ class MainWindow(wx.Frame, QuickApp):
title = _('Registration') title = _('Registration')
misc['target'] = data['target'] misc['target'] = data['target']
misc['action_back'] = self.bridge.gatewayRegister misc['action_back'] = self.bridge.gatewayRegister
XMLUI(self, title=title, xml_data = data['xml'], misc = misc) xmlui.create(self, title=title, xml_data = data['xml'], misc = misc)
elif type_ == "RESULT": elif type_ == "RESULT":
self.current_action_ids.remove(id_) self.current_action_ids.remove(id_)
if self.current_action_ids_cb.has_key(id_): if self.current_action_ids_cb.has_key(id_):
@ -413,7 +414,7 @@ class MainWindow(wx.Frame, QuickApp):
def onParam(self, e): def onParam(self, e):
log.debug(_("Param request")) log.debug(_("Param request"))
def success(params): def success(params):
XMLUI(self, xml_data=params, title=_("Configuration")) xmlui.create(self, xml_data=params, title=_("Configuration"))
def failure(error): def failure(error):
dlg = wx.MessageDialog(self, error.message, dlg = wx.MessageDialog(self, error.message,

View file

@ -24,7 +24,6 @@ from sat_frontends.primitivus.constants import Const as C
import wx import wx
from sat.core.log import getLogger from sat.core.log import getLogger
log = getLogger(__name__) log = getLogger(__name__)
from sat.tools.jid import JID
NO_SELECTION_ENTRY = ' ' NO_SELECTION_ENTRY = ' '
@ -147,7 +146,7 @@ class ProfileManager(wx.Panel):
return return
if self.selected_profile: if self.selected_profile:
self.profile_name.SetValue(self.selected_profile) self.profile_name.SetValue(self.selected_profile)
self.host.profile = profile_name # FIXME: EXTREMELY DIRTY, needed for sat_frontends.tools.xmlui.XMLUI._xmluiLaunchAction self.host.profile = profile_name # FIXME: EXTREMELY DIRTY, needed for sat_frontends.tools.xmlui.XMLUI.submit
self.host.launchAction(C.AUTHENTICATE_PROFILE_ID, {'caller': 'profile_manager'}, profile_key=profile_name) self.host.launchAction(C.AUTHENTICATE_PROFILE_ID, {'caller': 'profile_manager'}, profile_key=profile_name)
def onConnectButton(self, event): def onConnectButton(self, event):

View file

@ -23,9 +23,8 @@ from sat.core.i18n import _
import wx import wx
from sat.core.log import getLogger from sat.core.log import getLogger
log = getLogger(__name__) log = getLogger(__name__)
from sat.tools.jid import JID
from sat_frontends.tools import xmlui from sat_frontends.tools import xmlui
from sat_frontends.constants import Const from sat_frontends.constants import Const as C
class EventWidget(object): class EventWidget(object):
@ -53,20 +52,20 @@ class ValueWidget(WixWidget):
class EmptyWidget(WixWidget, xmlui.EmptyWidget, wx.Window): class EmptyWidget(WixWidget, xmlui.EmptyWidget, wx.Window):
def __init__(self, parent): def __init__(self, _xmlui_parent):
wx.Window.__init__(self, parent, -1) wx.Window.__init__(self, _xmlui_parent, -1)
class TextWidget(WixWidget, xmlui.TextWidget, wx.StaticText): class TextWidget(WixWidget, xmlui.TextWidget, wx.StaticText):
def __init__(self, parent, value): def __init__(self, _xmlui_parent, value):
wx.StaticText.__init__(self, parent, -1, value) wx.StaticText.__init__(self, _xmlui_parent, -1, value)
class LabelWidget(xmlui.LabelWidget, TextWidget): class LabelWidget(xmlui.LabelWidget, TextWidget):
def __init__(self, parent, value): def __init__(self, _xmlui_parent, value):
super(LabelWidget, self).__init__(parent, value+": ") super(LabelWidget, self).__init__(_xmlui_parent, value+": ")
class JidWidget(xmlui.JidWidget, TextWidget): class JidWidget(xmlui.JidWidget, TextWidget):
@ -75,49 +74,49 @@ class JidWidget(xmlui.JidWidget, TextWidget):
class DividerWidget(WixWidget, xmlui.DividerWidget, wx.StaticLine): class DividerWidget(WixWidget, xmlui.DividerWidget, wx.StaticLine):
def __init__(self, parent, style='line'): def __init__(self, _xmlui_parent, style='line'):
wx.StaticLine.__init__(self, parent, -1) wx.StaticLine.__init__(self, _xmlui_parent, -1)
class StringWidget(EventWidget, ValueWidget, xmlui.StringWidget, wx.TextCtrl): class StringWidget(EventWidget, ValueWidget, xmlui.StringWidget, wx.TextCtrl):
_xmlui_change_event = wx.EVT_TEXT _xmlui_change_event = wx.EVT_TEXT
def __init__(self, parent, value, read_only=False): def __init__(self, _xmlui_parent, value, read_only=False):
style = wx.TE_READONLY if read_only else 0 style = wx.TE_READONLY if read_only else 0
wx.TextCtrl.__init__(self, parent, -1, value, style=style) wx.TextCtrl.__init__(self, _xmlui_parent, -1, value, style=style)
self._xmlui_proportion = 1 self._xmlui_proportion = 1
class PasswordWidget(EventWidget, ValueWidget, xmlui.PasswordWidget, wx.TextCtrl): class PasswordWidget(EventWidget, ValueWidget, xmlui.PasswordWidget, wx.TextCtrl):
_xmlui_change_event = wx.EVT_TEXT _xmlui_change_event = wx.EVT_TEXT
def __init__(self, parent, value, read_only=False): def __init__(self, _xmlui_parent, value, read_only=False):
style = wx.TE_PASSWORD style = wx.TE_PASSWORD
if read_only: if read_only:
style |= wx.TE_READONLY style |= wx.TE_READONLY
wx.TextCtrl.__init__(self, parent, -1, value, style=style) wx.TextCtrl.__init__(self, _xmlui_parent, -1, value, style=style)
self._xmlui_proportion = 1 self._xmlui_proportion = 1
class TextBoxWidget(EventWidget, ValueWidget, xmlui.TextBoxWidget, wx.TextCtrl): class TextBoxWidget(EventWidget, ValueWidget, xmlui.TextBoxWidget, wx.TextCtrl):
_xmlui_change_event = wx.EVT_TEXT _xmlui_change_event = wx.EVT_TEXT
def __init__(self, parent, value, read_only=False): def __init__(self, _xmlui_parent, value, read_only=False):
style = wx.TE_MULTILINE style = wx.TE_MULTILINE
if read_only: if read_only:
style |= wx.TE_READONLY style |= wx.TE_READONLY
wx.TextCtrl.__init__(self, parent, -1, value, style=style) wx.TextCtrl.__init__(self, _xmlui_parent, -1, value, style=style)
self._xmlui_proportion = 1 self._xmlui_proportion = 1
class BoolWidget(EventWidget, ValueWidget, xmlui.BoolWidget, wx.CheckBox): class BoolWidget(EventWidget, ValueWidget, xmlui.BoolWidget, wx.CheckBox):
_xmlui_change_event = wx.EVT_CHECKBOX _xmlui_change_event = wx.EVT_CHECKBOX
def __init__(self, parent, state, read_only=False): def __init__(self, _xmlui_parent, state, read_only=False):
style = wx.CHK_2STATE style = wx.CHK_2STATE
if read_only: if read_only:
style |= wx.TE_READONLY style |= wx.TE_READONLY
wx.CheckBox.__init__(self, parent, -1, "", style=wx.CHK_2STATE) wx.CheckBox.__init__(self, _xmlui_parent, -1, "", style=wx.CHK_2STATE)
self.SetValue(state) self.SetValue(state)
self._xmlui_proportion = 1 self._xmlui_proportion = 1
@ -131,22 +130,22 @@ class BoolWidget(EventWidget, ValueWidget, xmlui.BoolWidget, wx.CheckBox):
class ButtonWidget(EventWidget, WixWidget, xmlui.ButtonWidget, wx.Button): class ButtonWidget(EventWidget, WixWidget, xmlui.ButtonWidget, wx.Button):
_xmlui_change_event = wx.EVT_BUTTON _xmlui_change_event = wx.EVT_BUTTON
def __init__(self, parent, value, click_callback): def __init__(self, _xmlui_parent, value, click_callback):
wx.Button.__init__(self, parent, -1, value) wx.Button.__init__(self, _xmlui_parent, -1, value)
self._xmlui_click_callback = click_callback self._xmlui_click_callback = click_callback
parent.Bind(wx.EVT_BUTTON, lambda evt: click_callback(evt.GetEventObject()), self) _xmlui_parent.Bind(wx.EVT_BUTTON, lambda evt: click_callback(evt.GetEventObject()), self)
self.parent = parent self._xmlui_parent = _xmlui_parent
def _xmluiOnClick(self, callback): def _xmluiOnClick(self, callback):
self.parent.Bind(wx.EVT_BUTTON, lambda evt: callback(evt.GetEventObject()), self) self._xmlui_parent.Bind(wx.EVT_BUTTON, lambda evt: callback(evt.GetEventObject()), self)
class ListWidget(EventWidget, WixWidget, xmlui.ListWidget, wx.ListBox): class ListWidget(EventWidget, WixWidget, xmlui.ListWidget, wx.ListBox):
_xmlui_change_event = wx.EVT_LISTBOX _xmlui_change_event = wx.EVT_LISTBOX
def __init__(self, parent, options, selected, flags): def __init__(self, _xmlui_parent, options, selected, flags):
styles = wx.LB_MULTIPLE if not 'single' in flags else wx.LB_SINGLE 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) wx.ListBox.__init__(self, _xmlui_parent, -1, choices=[option[1] for option in options], style=styles)
self._xmlui_attr_map = {label: value for value, label in options} self._xmlui_attr_map = {label: value for value, label in options}
self._xmlui_proportion = 1 self._xmlui_proportion = 1
self._xmluiSelectValues(selected) self._xmluiSelectValues(selected)
@ -192,8 +191,8 @@ class WixContainer(object):
class AdvancedListContainer(WixContainer, xmlui.AdvancedListContainer, wx.ScrolledWindow): class AdvancedListContainer(WixContainer, xmlui.AdvancedListContainer, wx.ScrolledWindow):
def __init__(self, parent, columns, selectable='no'): def __init__(self, _xmlui_parent, columns, selectable='no'):
wx.ScrolledWindow.__init__(self, parent) wx.ScrolledWindow.__init__(self, _xmlui_parent)
self._xmlui_selectable = selectable != 'no' self._xmlui_selectable = selectable != 'no'
if selectable: if selectable:
columns += 1 columns += 1
@ -230,8 +229,8 @@ class AdvancedListContainer(WixContainer, xmlui.AdvancedListContainer, wx.Scroll
class PairsContainer(WixContainer, xmlui.PairsContainer, wx.Panel): class PairsContainer(WixContainer, xmlui.PairsContainer, wx.Panel):
def __init__(self, parent): def __init__(self, _xmlui_parent):
wx.Panel.__init__(self, parent) wx.Panel.__init__(self, _xmlui_parent)
self.sizer = wx.FlexGridSizer(cols=2) 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.sizer.AddGrowableCol(1) #The growable column need most of time to be the right one in pairs
self.SetSizer(self.sizer) self.SetSizer(self.sizer)
@ -239,8 +238,8 @@ class PairsContainer(WixContainer, xmlui.PairsContainer, wx.Panel):
class TabsContainer(WixContainer, xmlui.TabsContainer, wx.Notebook): class TabsContainer(WixContainer, xmlui.TabsContainer, wx.Notebook):
def __init__(self, parent): def __init__(self, _xmlui_parent):
wx.Notebook.__init__(self, parent, -1, style=wx.NB_LEFT if self._xmlui_main.type=='param' else 0) wx.Notebook.__init__(self, _xmlui_parent, -1, style=wx.NB_LEFT if self._xmlui_main.type=='param' else 0)
def _xmluiAddTab(self, label): def _xmluiAddTab(self, label):
tab_panel = wx.Panel(self, -1) tab_panel = wx.Panel(self, -1)
@ -253,30 +252,109 @@ class TabsContainer(WixContainer, xmlui.TabsContainer, wx.Notebook):
class VerticalContainer(WixContainer, xmlui.VerticalContainer, wx.Panel): class VerticalContainer(WixContainer, xmlui.VerticalContainer, wx.Panel):
def __init__(self, parent): def __init__(self, _xmlui_parent):
wx.Panel.__init__(self, parent) wx.Panel.__init__(self, _xmlui_parent)
self.sizer = wx.BoxSizer(wx.VERTICAL) self.sizer = wx.BoxSizer(wx.VERTICAL)
self.SetSizer(self.sizer) self.SetSizer(self.sizer)
class WidgetFactory(object): ## Dialogs ##
class WixDialog(object):
def __init__(self, _xmlui_parent, level):
self.host = _xmlui_parent.host
self.ok_cb = None
self.cancel_cb = None
if level == C.XMLUI_DATA_LVL_INFO:
self.flags = wx.ICON_INFORMATION
elif level == C.XMLUI_DATA_LVL_ERROR:
self.flags = wx.ICON_ERROR
else:
self.flags = wx.ICON_INFORMATION
log.warning(_("Unmanaged dialog level: %s") % level)
def _xmluiShow(self):
answer = self.ShowModal()
if answer == wx.ID_YES or answer == wx.ID_OK:
self._xmluiValidated()
else:
self._xmluiCancelled()
def _xmluiClose(self):
self.Destroy()
class MessageDialog(WixDialog, xmlui.MessageDialog, wx.MessageDialog):
def __init__(self, _xmlui_parent, title, message, level):
WixDialog.__init__(self, _xmlui_parent, level)
xmlui.MessageDialog.__init__(self, _xmlui_parent)
self.flags |= wx.OK
wx.MessageDialog.__init__(self, _xmlui_parent.host, message, title, style = self.flags)
class NoteDialog(xmlui.NoteDialog, MessageDialog):
# TODO: separate NoteDialog
pass
class ConfirmDialog(WixDialog, xmlui.ConfirmDialog, wx.MessageDialog):
def __init__(self, _xmlui_parent, title, message, level, buttons_set):
WixDialog.__init__(self, _xmlui_parent, level)
xmlui.ConfirmDialog.__init__(self, _xmlui_parent)
if buttons_set == C.XMLUI_DATA_BTNS_SET_YESNO:
self.flags |= wx.YES_NO
else:
self.flags |= wx.OK | wx.CANCEL
wx.MessageDialog.__init__(self, _xmlui_parent.host, message, title, style = self.flags)
class FileDialog(WixDialog, xmlui.FileDialog, wx.FileDialog):
def __init__(self, _xmlui_parent, title, message, level, filetype):
# TODO: message and filetype are not managed yet
WixDialog.__init__(self, _xmlui_parent, level)
self.flags = wx.FD_SAVE | wx.FD_OVERWRITE_PROMPT # FIXME: use the legacy flags, but must manage cases like dir or open
xmlui.FileDialog.__init__(self, _xmlui_parent)
wx.FileDialog.__init__(self, _xmlui_parent.host, title, style = self.flags)
def _xmluiShow(self):
answer = self.ShowModal()
if answer == wx.ID_OK:
self._xmluiValidated({'path': self.GetPath()})
else:
self._xmluiCancelled()
class GenericFactory(object):
def __getattr__(self, attr): def __getattr__(self, attr):
if attr.startswith("create"): if attr.startswith("create"):
cls = globals()[attr[6:]] cls = globals()[attr[6:]]
return cls
class WidgetFactory(GenericFactory):
def __getattr__(self, attr):
if attr.startswith("create"):
cls = GenericFactory.__getattr__(self, attr)
cls._xmlui_main = self._xmlui_main cls._xmlui_main = self._xmlui_main
return cls return cls
class XMLUI(xmlui.XMLUI, wx.Frame): class XMLUIPanel(xmlui.XMLUIPanel, wx.Frame):
"""Create an user interface from a SàT XML""" """Create an user interface from a SàT XML"""
widget_factory = WidgetFactory() widget_factory = WidgetFactory()
def __init__(self, host, xml_data, title=None, flags = None,): def __init__(self, host, parsed_xml, title=None, flags = None,):
self.widget_factory._xmlui_main = self self.widget_factory._xmlui_main = self
xmlui.XMLUI.__init__(self, host, xml_data, title, flags) xmlui.XMLUIPanel.__init__(self, host, parsed_xml, title, flags)
def constructUI(self, xml_data): def constructUI(self, parsed_dom):
style = wx.DEFAULT_FRAME_STYLE & ~wx.CLOSE_BOX if 'NO_CANCEL' in self.flags else wx.DEFAULT_FRAME_STYLE 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) wx.Frame.__init__(self, None, style=style)
self.sizer = wx.BoxSizer(wx.VERTICAL) self.sizer = wx.BoxSizer(wx.VERTICAL)
@ -302,7 +380,7 @@ class XMLUI(xmlui.XMLUI, wx.Frame):
self.sizer.Fit(self) self.sizer.Fit(self)
self.Show() self.Show()
super(XMLUI, self).constructUI(xml_data, postTreat) super(XMLUIPanel, self).constructUI(parsed_dom, postTreat)
if not 'NO_CANCEL' in self.flags: if not 'NO_CANCEL' in self.flags:
self.Bind(wx.EVT_CLOSE, self.onClose, self) self.Bind(wx.EVT_CLOSE, self.onClose, self)
self.MakeModal() self.MakeModal()
@ -314,12 +392,12 @@ class XMLUI(xmlui.XMLUI, wx.Frame):
###events ###events
def onParamChange(self, ctrl): def onParamChange(self, ctrl):
super(XMLUI, self).onParamChange(ctrl) super(XMLUIPanel, self).onParamChange(ctrl)
def onFormSubmitted(self, event): def onFormSubmitted(self, event):
"""Called when submit button is clicked""" """Called when submit button is clicked"""
button = event.GetEventObject() button = event.GetEventObject()
super(XMLUI, self).onFormSubmitted(button) super(XMLUIPanel, self).onFormSubmitted(button)
def onClose(self, event): def onClose(self, event):
"""Close event: we have to send the form.""" """Close event: we have to send the form."""
@ -330,3 +408,11 @@ class XMLUI(xmlui.XMLUI, wx.Frame):
self._xmluiClose() self._xmluiClose()
event.Skip() event.Skip()
class XMLUIDialog(xmlui.XMLUIDialog):
dialog_factory = WidgetFactory()
xmlui.registerClass(xmlui.CLASS_PANEL, XMLUIPanel)
xmlui.registerClass(xmlui.CLASS_DIALOG, XMLUIDialog)
create = xmlui.create