Mercurial > libervia-backend
view frontends/primitivus/xmlui.py @ 157:13888bdb72b6
primitivus: button are now working with XMLUI
author | Goffi <goffi@goffi.org> |
---|---|
date | Wed, 04 Aug 2010 12:01:07 +0800 |
parents | b1f1955d96b3 |
children | ae50b53ff868 |
line wrap: on
line source
#!/usr/bin/python # -*- coding: utf-8 -*- """ Primitivus: a SAT frontend Copyright (C) 2009, 2010 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 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 General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses/>. """ import urwid import custom_widgets from xml.dom import minidom class Pairs(urwid.WidgetWrap): def __init__(self, weight_0='1', weight_1='1'): self.idx = 0 self.weight_0 = weight_0 self.weight_1 = weight_1 columns = urwid.Columns([urwid.Text(''), urwid.Text('')]) #XXX: empty Text hack needed because Pile doesn't support empty list urwid.WidgetWrap.__init__(self,columns) def append(self, widget): pile = self._w.widget_list[self.idx] if isinstance(pile, urwid.Text): self._w.widget_list[self.idx] = urwid.Pile([widget]) if self.idx == 1: self._w.set_focus(1) else: pile.widget_list.append(widget) pile.item_types.append(('weight',getattr(self,'weight_'+str(self.idx)))) self.idx = (self.idx + 1) % 2 class InvalidXMLUI(Exception): pass class XMLUI(urwid.WidgetWrap): def __init__(self, host, xml_data, title = None, options = [], misc={}): self.host = host self.title = title self.options = options self.misc = misc self.ctrl_list = {} # usefull to access ctrl widget = self.constructUI(xml_data) urwid.WidgetWrap.__init__(self,widget) def __parseElems(self, node, parent): """Parse elements inside a <layout> tags, and add them to the parent""" for elem in node.childNodes: if elem.nodeName != "elem": message=_("Unmanaged tag") error(message) raise Exception(message) 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 = urwid.Text('') elif type=="text": try: value = elem.childNodes[0].wholeText except IndexError: warning (_("text node has no child !")) ctrl = urwid.Text(value) elif type=="label": ctrl = urwid.Text(value+": ") elif type=="string": ctrl = custom_widgets.AdvancedEdit(edit_text = value) self.ctrl_list[name] = ({'type':type, 'control':ctrl}) elif type=="password": ctrl = custom_widgets.Password(edit_text = value) self.ctrl_list[name] = ({'type':type, 'control':ctrl}) elif type=="textbox": ctrl = custom_widgets.AdvancedEdit(edit_text = value, multiline=True) self.ctrl_list[name] = ({'type':type, 'control':ctrl}) elif type=="list": style=[] if elem.getAttribute("multi")=='yes' else ['single'] ctrl = custom_widgets.List(options=[option.getAttribute("value") for option in elem.getElementsByTagName("option")], style=style) self.ctrl_list[name] = ({'type':type, 'control':ctrl}) elif type=="button": callback_id = elem.getAttribute("callback_id") ctrl = custom_widgets.CustomButton(value, on_press=self.onButtonPress) ctrl.param_id = (callback_id,[field.getAttribute('name') for field in elem.getElementsByTagName("field_back")]) else: error(_("FIXME FIXME FIXME: type [%s] is not implemented") % type) #FIXME ! raise NotImplementedError parent.append(ctrl) def __parseChilds(self, current, elem, wanted = ['layout'], data = None): """Recursively parse childNodes of an elemen @param current: widget container with 'append' method @param elem: 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""" for node in elem.childNodes: if wanted and not node.nodeName in wanted: raise InvalidXMLUI if node.nodeName == "layout": type = node.getAttribute('type') if type == "tabs": tab_cont = custom_widgets.TabsContainer() self.__parseChilds(current, node, ['category'], tab_cont) current.append(tab_cont) elif type == "vertical": self.__parseElems(node, current) elif type == "pairs": pairs = Pairs() self.__parseElems(node, pairs) current.append(pairs) else: warning(_("Unknown layout, using default one")) self.__parseElems(node, current) elif node.nodeName == "category": name = node.getAttribute('name') if not name or not isinstance(data,custom_widgets.TabsContainer): raise InvalidXMLUI tab_cont = data listbox = tab_cont.addTab(name) self.__parseChilds(listbox.body, node, ['layout']) else: message=_("Unknown tag") error(message) raise NotImplementedError def constructUI(self, xml_data): list_box = urwid.ListBox(urwid.SimpleListWalker([])) cat_dom = minidom.parseString(xml_data.encode('utf-8')) top=cat_dom.documentElement self.type = top.getAttribute("type") if not self.title: self.title = top.getAttribute("title") #TODO: manage title if top.nodeName != "sat_xmlui" or not self.type in ['form', 'param', 'window']: raise InvalidXMLUI self.__parseChilds(list_box.body, cat_dom.documentElement) assert list_box.body if isinstance(list_box.body[0],custom_widgets.TabsContainer): return list_box.body[0] #xxx: awfull hack cause TabsContainer is a BoxWidget, can't be inside a ListBox if self.type == 'form': buttons = [] buttons.append(urwid.Button(_('Submit'),self.onFormSubmitted)) if not 'NO_CANCEL' in self.options: buttons.append(urwid.Button(_('Cancel'),self.onFormCancelled)) max_len = max([len(button.get_label()) for button in buttons]) grid_wid = urwid.GridFlow(buttons,max_len+4,1,0,'center') list_box.body.append(grid_wid) return list_box def show(self): """Show the constructed UI""" decorated = custom_widgets.LabelLine(self, custom_widgets.SurroundedText(self.title or '')) self.host.showPopUp(decorated) self.host.redraw() ##EVENTS## def onButtonPress(self, button): callback_id, fields = button.param_id data = {"callback_id":callback_id} for field in fields: ctrl = self.ctrl_list[field] if isinstance(ctrl['control'],custom_widgets.List): data[field] = '\t'.join(ctrl['control'].getSelectedValues()) else: data[field] = ctrl['control'].getValue() id = self.host.bridge.launchAction("button", data, profile_key = self.host.profile) self.host.current_action_ids.add(id) def onFormSubmitted(self, button): data = [] for ctrl_name in self.ctrl_list: ctrl = self.ctrl_list[ctrl_name] if isinstance(ctrl['control'], custom_widgets.List): data.append((ctrl_name, ctrl['control'].getSelectedValue())) else: data.append((ctrl_name, ctrl['control'].get_edit_text())) if self.misc.has_key('action_back'): #FIXME FIXME FIXME: WTF ! Must be cleaned raise NotImplementedError self.host.debug() elif self.misc.has_key('callback'): self.misc['callback'](data) else: warning (_("The form data is not sent back, the type is not managed properly")) self.host.removePopUp() def onFormCancelled(self, button): self.host.removePopUp()