core, frontends: implementation of AdvancedListContainer first draft + misc:

/!\ Urwid SàText must be updated as the new TableContainer is used /!\
    - fixed button value in paramsXML2XMLUI
    - new Urwid SàText TabContainer is used in Primitivus for PairsContainer and AdvancedListContainer
    - fixed in core's XMLUI AdvanceListContainer
This commit is contained in:
Goffi 2014-02-04 18:19:29 +01:00
commit 9661c1c2c5
5 changed files with 77 additions and 37 deletions

View file

@ -69,6 +69,8 @@ class Const(constants.Const):
('show_xa_focus', 'dark red, bold', 'default'),
('status', 'yellow', 'default'),
('status_focus', 'yellow, bold', 'default'),
('param_selected','default, bold', 'dark red'),
('table_selected','default, bold', 'default'),
]
PRESENCE = {"unavailable": (u'⨯', "show_disconnected"),
"": (u'✔', "show_normal"),

View file

@ -103,25 +103,31 @@ class PrimitivusListWidget(xmlui.ListWidget, sat_widgets.List, PrimitivusEvents)
return [option.value for option in self.getSelectedValues()]
class PrimitivusPairsContainer(xmlui.PairsContainer, urwid.WidgetWrap):
class PrimitivusAdvancedListContainer(xmlui.AdvancedListContainer, sat_widgets.TableContainer):
def __init__(self, parent, 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 __init__(self, parent, columns):
options = {'ADAPT':(), 'HIGHLIGHT':()}
sat_widgets.TableContainer.__init__(self, columns=columns, options=options)
def _xmluiAppend(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.contents.append((widget,('weight',getattr(self,'weight_'+str(self.idx)))))
self.idx = (self.idx + 1) % 2
self.addWidget(widget)
def _xmluiAddRow(self):
pass
class PrimitivusPairsContainer(xmlui.PairsContainer, sat_widgets.TableContainer):
def __init__(self, parent):
options = {'ADAPT':(0,), 'HIGHLIGHT':(0,)}
if self._xmlui_main.type == 'param':
options['FOCUS_ATTR'] = 'param_selected'
sat_widgets.TableContainer.__init__(self, columns=2, options=options)
def _xmluiAppend(self, widget):
if isinstance(widget, PrimitivusEmptyWidget):
# we don't want highlight on empty widgets
widget = urwid.AttrMap(widget, 'default')
self.addWidget(widget)
class PrimitivusTabsContainer(xmlui.TabsContainer, sat_widgets.TabsContainer):
@ -153,13 +159,15 @@ class WidgetFactory(object):
def __getattr__(self, attr):
if attr.startswith("create"):
return 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
cls._xmlui_main = self._xmlui_main
return cls
class XMLUI(xmlui.XMLUI, urwid.WidgetWrap):
widget_factory = WidgetFactory()
def __init__(self, host, xml_data, title = None, flags = None):
self.widget_factory._xmlui_main = self
self._dest = "window"
xmlui.XMLUI.__init__(self, host, xml_data, title, flags)
urwid.WidgetWrap.__init__(self, self.main_cont)

View file

@ -120,6 +120,10 @@ class VerticalContainer(Container):
pass
class AdvancedListContainer(Container):
""" Widgets are disposed in rows with advaned features """
pass
class XMLUI(object):
""" Base class to construct SàT XML User Interface
New frontends can inherite this class to easily implement XMLUI
@ -178,7 +182,7 @@ class XMLUI(object):
"""
for node in current_node.childNodes:
if wanted and not node.nodeName in wanted:
raise InvalidXMLUI
raise InvalidXMLUI('Unexpected node: [%s]' % node.nodeName)
if node.nodeName == "container":
type_ = node.getAttribute('type')
@ -195,6 +199,13 @@ class XMLUI(object):
elif type_ == "pairs":
cont = self.widget_factory.createPairsContainer(parent)
self._parseChilds(cont, node, ('widget', 'container'))
elif type_ == "advanced_list":
try:
columns = int(node.getAttribute('columns'))
except (TypeError, ValueError):
raise DataError("Invalid columns")
cont = self.widget_factory.createAdvancedListContainer(parent, columns)
self._parseChilds(cont, node, ('row',))
else:
warning(_("Unknown container [%s], using default one") % type_)
cont = self.widget_factory.createVerticalContainer(parent)
@ -207,7 +218,7 @@ class XMLUI(object):
else:
raise Exception(_("Internal Error, container has not _xmluiAppend method"))
elif node.nodeName == "tab":
elif node.nodeName == 'tab':
name = node.getAttribute('name')
label = node.getAttribute('label')
if not name or not isinstance(data, TabsContainer):
@ -218,6 +229,10 @@ class XMLUI(object):
new_tab = tab_cont._xmluiAddTab(label or name)
self._parseChilds(new_tab, node, ('widget', 'container'))
elif node.nodeName == 'row':
parent._xmluiAddRow()
self._parseChilds(parent, node, ('widget', 'container'))
elif node.nodeName == "widget":
id_ = node.getAttribute("id")
name = node.getAttribute("name")

View file

@ -138,9 +138,20 @@ class WixContainer(object):
self.sizer.Add(widget, self._xmlui_proportion, flag=wx.EXPAND)
class AdvancedListContainer(WixContainer, xmlui.AdvancedListContainer, wx.Panel):
def __init__(self, parent, columns):
wx.Panel.__init__(self, parent)
self.sizer = wx.FlexGridSizer(cols=columns)
self.SetSizer(self.sizer)
def _xmluiAddRow(self):
pass
class PairsContainer(WixContainer, xmlui.PairsContainer, wx.Panel):
def __init__(self, parent, weight_0='1', weight_1='1'):
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

View file

@ -92,10 +92,10 @@ def dataForm2XMLUI(form, submit_id, session_id=None):
return form_ui
def dataFormResult2AdvancedList(form_ui, form_xml):
def dataFormResult2AdvancedList(xmlui, form_xml):
"""Take a raw data form (not parsed by XEP-0004) and convert it to an advanced list
raw data form is used because Wokkel doesn't manage result items parsing yet
@param form_ui: the XMLUI where the AdvancedList will be added
@param xmlui: the XMLUI where the AdvancedList will be added
@param form_xml: domish.Element of the data form
@return: AdvancedList element
"""
@ -116,8 +116,8 @@ def dataFormResult2AdvancedList(form_ui, form_xml):
if not headers:
raise exceptions.DataError("No reported fields (see XEP-0004 §3.4)")
adv_list = AdvancedListContainer(form_ui, headers=headers, columns=len(headers), parent=form_ui.current_container)
form_ui.changeContainer(adv_list)
adv_list = AdvancedListContainer(xmlui, headers=headers, columns=len(headers), parent=xmlui.current_container)
xmlui.changeContainer(adv_list)
item_elts = form_xml.elements('jabber:x:data', 'item')
@ -129,9 +129,9 @@ def dataFormResult2AdvancedList(form_ui, form_xml):
field = data_form.Field.fromElement(elt)
widget_type, widget_args, widget_kwargs = _dataFormField2XMLUIData(field)
form_ui.addWidget(widget_type, *widget_args, **widget_kwargs)
xmlui.addWidget(widget_type, *widget_args, **widget_kwargs)
return form_ui
return xmlui
def dataFormResult2XMLUI(form_xml, session_id=None):
"""Take a raw data form (not parsed by XEP-0004) and convert it to a SàT XMLUI
@ -140,9 +140,9 @@ def dataFormResult2XMLUI(form_xml, session_id=None):
@return: XMLUI interface
"""
form_ui = XMLUI("window", "vertical", session_id=session_id)
dataFormResult2AdvancedList(form_ui, form_xml)
return form_ui
xmlui = XMLUI("window", "vertical", session_id=session_id)
dataFormResult2AdvancedList(xmlui, form_xml)
return xmlui
def XMLUIResult2DataFormResult(xmlui_data):
""" Extract form data from a XMLUI return
@ -202,6 +202,7 @@ def paramsXML2XMLUI(xml):
if type_ == "button":
param_ui.addEmpty()
value = param_label
else:
param_ui.addLabel(param_label or param_name)
@ -249,8 +250,7 @@ class Element(object):
self.xmlui = xmlui
if parent is not None:
parent.append(self)
else:
self.parent = parent
self.parent = parent
def append(self, child):
self.elem.appendChild(child.elem)
@ -409,7 +409,7 @@ class AdvancedListContainer(Container):
if columns is None:
columns = len(items[0])
self._columns = columns
self._current_column = 0
self._item_idx = 0
self.current_row = None
if headers:
if len(headers) != self._columns:
@ -417,6 +417,7 @@ class AdvancedListContainer(Container):
self.addHeaders(headers)
if items:
self.addItems(items)
self.elem.setAttribute('columns', str(self._columns))
def addHeaders(self, headers):
for header in headers:
@ -427,12 +428,15 @@ class AdvancedListContainer(Container):
def addItems(self, items):
for item in items:
self.addItem(item)
self.append(item)
def addItem(self, item):
if self._current_column % self._columns == 0:
def append(self, child):
if isinstance(child, RowElement):
return super(AdvancedListContainer, self).append(child)
if self._item_idx % self._columns == 0:
self.current_row = RowElement(self)
self.current_row.append(item)
self.current_row.append(child)
self._item_idx += 1
def end(self):
""" Called when we have finished list