Mercurial > libervia-backend
diff frontends/src/tools/xmlui.py @ 802:9007bb133009
core, frontends: XMLUI refactoring:
- XMLUI now use objects with 2 main classes: widgets (button, label, etc), and container which contain widgets according to a layout
- widgets and containers classes are found through introspection, thereby it's really easy to add a new one
- there is still the AddWidgetName helper, for example AddText('jid', 'test@example.net') will add a StringWidget with name "jid" and default value "test@example.net"
- container can be inside other containers. changeContainer change the first parent container
author | Goffi <goffi@goffi.org> |
---|---|
date | Tue, 04 Feb 2014 18:19:00 +0100 |
parents | 46aa5ada61bf |
children | f100fd8d279f |
line wrap: on
line diff
--- a/frontends/src/tools/xmlui.py Tue Feb 04 18:06:12 2014 +0100 +++ b/frontends/src/tools/xmlui.py Tue Feb 04 18:19:00 2014 +0100 @@ -89,9 +89,6 @@ """ A widget able to show/choose one or several strings in a list """ -class AdvancedListWidget(Widget): - pass #TODO - class Container(Widget): """ Widget which can contain other ones with a specific layout """ @@ -157,103 +154,60 @@ flags = [] self.flags = flags self.ctrl_list = {} # usefull to access ctrl + self._main_cont = None self.constructUI(xml_data) - def _parseElems(self, node, parent, post_treat=None): - """ Parse elements inside a <layout> tags, and add them to the parent - @param node: current XMLUI node - @param parent: parent container - @param post_treat: frontend specific treatments do to on each element + @property + def main_cont(self): + return self._main_cont - """ - for elem in node.childNodes: - if elem.nodeName != "elem": - raise NotImplementedError(_('Unknown tag [%s]') % elem.nodeName) - id_ = elem.getAttribute("id") - name = elem.getAttribute("name") - type_ = elem.getAttribute("type") - value = elem.getAttribute("value") if elem.hasAttribute('value') else u'' - if type_=="empty": - ctrl = self.widget_factory.createEmptyWidget(parent) - elif type_=="text": - try: - value = elem.childNodes[0].wholeText - except IndexError: - warning (_("text node has no child !")) - ctrl = self.widget_factory.createTextWidget(parent, value) - elif type_=="label": - ctrl = self.widget_factory.createTextWidget(parent, value+": ") - elif type_=="string": - ctrl = self.widget_factory.createStringWidget(parent, value) - self.ctrl_list[name] = ({'type':type_, 'control':ctrl}) - elif type_=="password": - ctrl = self.widget_factory.createPasswordWidget(parent, value) - self.ctrl_list[name] = ({'type':type_, 'control':ctrl}) - elif type_=="textbox": - ctrl = self.widget_factory.createTextBoxWidget(parent, value) - self.ctrl_list[name] = ({'type':type_, 'control':ctrl}) - elif type_=="bool": - ctrl = self.widget_factory.createBoolWidget(parent, value=='true') - self.ctrl_list[name] = ({'type':type_, 'control':ctrl}) - elif type_=="list": - style=[] if elem.getAttribute("multi")=='yes' else ['single'] - _options = [(option.getAttribute("value"), option.getAttribute("label")) for option in elem.getElementsByTagName("option")] - ctrl = self.widget_factory.createListWidget(parent, _options, style) - ctrl._xmluiSelectValue(elem.getAttribute("value")) - self.ctrl_list[name] = ({'type':type_, 'control':ctrl}) - elif type_=="button": - callback_id = elem.getAttribute("callback") - ctrl = self.widget_factory.createButtonWidget(parent, value, self.onButtonPress) - ctrl._xmlui_param_id = (callback_id,[field.getAttribute('name') for field in elem.getElementsByTagName("field_back")]) - elif type_=="advanced_list": - _options = [getText(txt_elt) for txt_elt in elem.getElementsByTagName("text")] - ctrl = self.widget_factory.createListWidget(parent, _options, ['can_select_none']) - ctrl._xmluiSelectValue(elem.getAttribute("value")) - self.ctrl_list[name] = ({'type':type_, 'control':ctrl}) - else: - error(_("FIXME FIXME FIXME: type [%s] is not implemented") % type_) - raise NotImplementedError(_("FIXME FIXME FIXME: type [%s] is not implemented") % type_) + @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 - if self.type == 'param': - try: - ctrl._xmluiOnChange(self.onParamChange) - ctrl._param_category = self._current_category - ctrl._param_name = name.split(Const.SAT_PARAM_SEPARATOR)[1] - except AttributeError: - if not isinstance(ctrl, (EmptyWidget, TextWidget)): - warning(_("No change listener on [%s]" % ctrl)) - if post_treat is not None: - post_treat(ctrl, id_, name, type_, value) - parent._xmluiAppend(ctrl) - - def _parseChilds(self, current, elem, wanted = ['layout'], data = None): + def _parseChilds(self, parent, current_node, wanted = ('container',), data = None): """ Recursively parse childNodes of an elemen - @param current: widget container with '_xmluiAppend' method - @param elem: element from which childs will be parsed + @param parent: widget container with '_xmluiAppend' method + @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 data: additionnal data which are needed in some cases """ - for node in elem.childNodes: + for node in current_node.childNodes: if wanted and not node.nodeName in wanted: raise InvalidXMLUI - if node.nodeName == "layout": + + if node.nodeName == "container": type_ = node.getAttribute('type') + if parent is self and type_ != 'vertical': + # main container is not a VerticalContainer and we want one, so we create one to wrap it + parent = self.widget_factory.createVerticalContainer(self) + self.main_cont = parent if type_ == "tabs": - tab_cont = self.widget_factory.createTabsContainer(current) - self._parseChilds(current, node, ['category'], tab_cont) - current._xmluiAppend(tab_cont) + cont = self.widget_factory.createTabsContainer(parent) + self._parseChilds(parent, node, ('tab',), cont) elif type_ == "vertical": - self._parseElems(node, current) + cont = self.widget_factory.createVerticalContainer(parent) + self._parseChilds(cont, node, ('widget', 'container')) elif type_ == "pairs": - pairs = self.widget_factory.createPairsContainer(current) - self._parseElems(node, pairs) - current._xmluiAppend(pairs) + cont = self.widget_factory.createPairsContainer(parent) + self._parseChilds(cont, node, ('widget', 'container')) else: - warning(_("Unknown layout [%s], using default one") % type_) - self._parseElems(node, current) - elif node.nodeName == "category": + warning(_("Unknown container [%s], using default one") % type_) + cont = self.widget_factory.createVerticalContainer(parent) + self._parseChilds(cont, node, ('widget', 'container')) + try: + parent._xmluiAppend(cont) + except AttributeError: + if parent is self: + self.main_cont = cont + else: + raise Exception(_("Internal Error, container has not _xmluiAppend method")) + + elif node.nodeName == "tab": name = node.getAttribute('name') label = node.getAttribute('label') if not name or not isinstance(data, TabsContainer): @@ -262,9 +216,62 @@ self._current_category = name #XXX: awful hack because params need category and we don't keep parent tab_cont = data new_tab = tab_cont._xmluiAddTab(label or name) - self._parseChilds(new_tab, node, ['layout']) + self._parseChilds(new_tab, node, ('widget', 'container')) + + elif node.nodeName == "widget": + id_ = node.getAttribute("id") + name = node.getAttribute("name") + type_ = node.getAttribute("type") + value = node.getAttribute("value") if node.hasAttribute('value') else u'' + if type_=="empty": + ctrl = self.widget_factory.createEmptyWidget(parent) + elif type_=="text": + try: + value = node.childNodes[0].wholeText + except IndexError: + warning (_("text node has no child !")) + ctrl = self.widget_factory.createTextWidget(parent, value) + elif type_=="label": + ctrl = self.widget_factory.createTextWidget(parent, value+": ") + elif type_=="string": + ctrl = self.widget_factory.createStringWidget(parent, value) + self.ctrl_list[name] = ({'type':type_, 'control':ctrl}) + elif type_=="password": + ctrl = self.widget_factory.createPasswordWidget(parent, value) + self.ctrl_list[name] = ({'type':type_, 'control':ctrl}) + elif type_=="textbox": + ctrl = self.widget_factory.createTextBoxWidget(parent, value) + self.ctrl_list[name] = ({'type':type_, 'control':ctrl}) + elif type_=="bool": + ctrl = self.widget_factory.createBoolWidget(parent, value=='true') + self.ctrl_list[name] = ({'type':type_, 'control':ctrl}) + elif type_=="list": + style=[] if node.getAttribute("multi")=='yes' else ['single'] + _options = [(option.getAttribute("value"), option.getAttribute("label")) for option in node.getElementsByTagName("option")] + ctrl = self.widget_factory.createListWidget(parent, _options, style) + ctrl._xmluiSelectValue(node.getAttribute("value")) + self.ctrl_list[name] = ({'type':type_, 'control':ctrl}) + elif type_=="button": + callback_id = node.getAttribute("callback") + ctrl = self.widget_factory.createButtonWidget(parent, value, self.onButtonPress) + ctrl._xmlui_param_id = (callback_id,[field.getAttribute('name') for field in node.getElementsByTagName("field_back")]) + else: + error(_("FIXME FIXME FIXME: widget type [%s] is not implemented") % type_) + raise NotImplementedError(_("FIXME FIXME FIXME: type [%s] is not implemented") % type_) + + if self.type == 'param': + try: + ctrl._xmluiOnChange(self.onParamChange) + ctrl._param_category = self._current_category + ctrl._param_name = name.split(Const.SAT_PARAM_SEPARATOR)[1] + except AttributeError: + if not isinstance(ctrl, (EmptyWidget, TextWidget)): + warning(_("No change listener on [%s]" % ctrl)) + + parent._xmluiAppend(ctrl) + else: - raise NotImplementedError(_('Unknown tag')) + raise NotImplementedError(_('Unknown tag [%s]') % node.nodeName) def constructUI(self, xml_data, post_treat=None): """ Actually construct the UI @@ -272,8 +279,6 @@ @param post_treat: frontend specific treatments to do once the UI is constructed @return: constructed widget """ - ret_wid = self.widget_factory.createVerticalContainer(self) - cat_dom = self.dom_parse(xml_data) top=cat_dom.documentElement self.type = top.getAttribute("type") @@ -286,16 +291,13 @@ if self.type == 'param': self.param_changed = set() - self._parseChilds(ret_wid, cat_dom.documentElement) + self._parseChilds(self, cat_dom.documentElement) if post_treat is not None: - ret_wid = post_treat(ret_wid) + post_treat() self.dom_free(cat_dom) - return ret_wid - - def _xmluiClose(self): """ Close the window/popup/... where the constructeur XMLUI is this method must be overrided