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:
parent
b3fb68cb63
commit
9661c1c2c5
5 changed files with 77 additions and 37 deletions
|
|
@ -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"),
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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")
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
Loading…
Reference in a new issue