Dataforms widget moved to another file, some ui tweaks.
This commit is contained in:
parent
a81aaf8c16
commit
5824d3b873
|
@ -183,7 +183,7 @@
|
|||
</child>
|
||||
</widget>
|
||||
|
||||
<widget class="GtkWindow" id="data_form_fake_window">
|
||||
<widget class="GtkWindow" id="data_form_old_fake_window">
|
||||
<property name="visible">True</property>
|
||||
<property name="title" translatable="yes">window1</property>
|
||||
<property name="type">GTK_WINDOW_TOPLEVEL</property>
|
||||
|
@ -412,4 +412,398 @@
|
|||
</child>
|
||||
</widget>
|
||||
|
||||
<widget class="GtkWindow" id="data_form_fake_window">
|
||||
<property name="visible">True</property>
|
||||
<property name="title" translatable="yes">window1</property>
|
||||
<property name="type">GTK_WINDOW_TOPLEVEL</property>
|
||||
<property name="window_position">GTK_WIN_POS_NONE</property>
|
||||
<property name="modal">False</property>
|
||||
<property name="resizable">True</property>
|
||||
<property name="destroy_with_parent">False</property>
|
||||
<property name="decorated">True</property>
|
||||
<property name="skip_taskbar_hint">False</property>
|
||||
<property name="skip_pager_hint">False</property>
|
||||
<property name="type_hint">GDK_WINDOW_TYPE_HINT_NORMAL</property>
|
||||
<property name="gravity">GDK_GRAVITY_NORTH_WEST</property>
|
||||
<property name="focus_on_map">True</property>
|
||||
|
||||
<child>
|
||||
<widget class="GtkVBox" id="data_form_vbox">
|
||||
<property name="border_width">3</property>
|
||||
<property name="visible">True</property>
|
||||
<property name="homogeneous">False</property>
|
||||
<property name="spacing">3</property>
|
||||
|
||||
<child>
|
||||
<widget class="GtkLabel" id="instructions_label">
|
||||
<property name="visible">True</property>
|
||||
<property name="label" translatable="yes">Fill in the form.</property>
|
||||
<property name="use_underline">False</property>
|
||||
<property name="use_markup">False</property>
|
||||
<property name="justify">GTK_JUSTIFY_LEFT</property>
|
||||
<property name="wrap">False</property>
|
||||
<property name="selectable">False</property>
|
||||
<property name="xalign">0.5</property>
|
||||
<property name="yalign">0.5</property>
|
||||
<property name="xpad">0</property>
|
||||
<property name="ypad">0</property>
|
||||
<property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
|
||||
<property name="width_chars">-1</property>
|
||||
<property name="single_line_mode">False</property>
|
||||
<property name="angle">0</property>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="padding">0</property>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">False</property>
|
||||
</packing>
|
||||
</child>
|
||||
|
||||
<child>
|
||||
<widget class="GtkHSeparator" id="instructions_hseparator">
|
||||
<property name="visible">True</property>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="padding">0</property>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
</packing>
|
||||
</child>
|
||||
|
||||
<child>
|
||||
<widget class="GtkNotebook" id="data_form_types_notebook">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="show_tabs">True</property>
|
||||
<property name="show_border">True</property>
|
||||
<property name="tab_pos">GTK_POS_TOP</property>
|
||||
<property name="scrollable">False</property>
|
||||
<property name="enable_popup">False</property>
|
||||
|
||||
<child>
|
||||
<widget class="GtkScrolledWindow" id="single_form_scrolledwindow">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="hscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
|
||||
<property name="vscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
|
||||
<property name="shadow_type">GTK_SHADOW_NONE</property>
|
||||
<property name="window_placement">GTK_CORNER_TOP_LEFT</property>
|
||||
|
||||
<child>
|
||||
<widget class="GtkViewport" id="single_form_viewport">
|
||||
<property name="visible">True</property>
|
||||
<property name="shadow_type">GTK_SHADOW_IN</property>
|
||||
|
||||
<child>
|
||||
<placeholder/>
|
||||
</child>
|
||||
</widget>
|
||||
</child>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="tab_expand">False</property>
|
||||
<property name="tab_fill">True</property>
|
||||
</packing>
|
||||
</child>
|
||||
|
||||
<child>
|
||||
<widget class="GtkLabel" id="label1">
|
||||
<property name="visible">True</property>
|
||||
<property name="label" translatable="yes"></property>
|
||||
<property name="use_underline">False</property>
|
||||
<property name="use_markup">False</property>
|
||||
<property name="justify">GTK_JUSTIFY_LEFT</property>
|
||||
<property name="wrap">False</property>
|
||||
<property name="selectable">False</property>
|
||||
<property name="xalign">0.5</property>
|
||||
<property name="yalign">0.5</property>
|
||||
<property name="xpad">0</property>
|
||||
<property name="ypad">0</property>
|
||||
<property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
|
||||
<property name="width_chars">-1</property>
|
||||
<property name="single_line_mode">False</property>
|
||||
<property name="angle">0</property>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="type">tab</property>
|
||||
</packing>
|
||||
</child>
|
||||
|
||||
<child>
|
||||
<placeholder/>
|
||||
</child>
|
||||
|
||||
<child>
|
||||
<widget class="GtkLabel" id="label2">
|
||||
<property name="visible">True</property>
|
||||
<property name="label" translatable="yes"></property>
|
||||
<property name="use_underline">False</property>
|
||||
<property name="use_markup">False</property>
|
||||
<property name="justify">GTK_JUSTIFY_LEFT</property>
|
||||
<property name="wrap">False</property>
|
||||
<property name="selectable">False</property>
|
||||
<property name="xalign">0.5</property>
|
||||
<property name="yalign">0.5</property>
|
||||
<property name="xpad">0</property>
|
||||
<property name="ypad">0</property>
|
||||
<property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
|
||||
<property name="width_chars">-1</property>
|
||||
<property name="single_line_mode">False</property>
|
||||
<property name="angle">0</property>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="type">tab</property>
|
||||
</packing>
|
||||
</child>
|
||||
|
||||
<child>
|
||||
<widget class="GtkHBox" id="multiple_form_hbox">
|
||||
<property name="visible">True</property>
|
||||
<property name="homogeneous">False</property>
|
||||
<property name="spacing">0</property>
|
||||
|
||||
<child>
|
||||
<widget class="GtkScrolledWindow" id="scrolledwindow38">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="hscrollbar_policy">GTK_POLICY_ALWAYS</property>
|
||||
<property name="vscrollbar_policy">GTK_POLICY_ALWAYS</property>
|
||||
<property name="shadow_type">GTK_SHADOW_IN</property>
|
||||
<property name="window_placement">GTK_CORNER_TOP_LEFT</property>
|
||||
|
||||
<child>
|
||||
<widget class="GtkTreeView" id="records_treeview">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="headers_visible">True</property>
|
||||
<property name="rules_hint">False</property>
|
||||
<property name="reorderable">False</property>
|
||||
<property name="enable_search">True</property>
|
||||
<property name="fixed_height_mode">False</property>
|
||||
<property name="hover_selection">False</property>
|
||||
<property name="hover_expand">False</property>
|
||||
</widget>
|
||||
</child>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="padding">0</property>
|
||||
<property name="expand">True</property>
|
||||
<property name="fill">True</property>
|
||||
</packing>
|
||||
</child>
|
||||
|
||||
<child>
|
||||
<widget class="GtkVBox" id="vbox114">
|
||||
<property name="visible">True</property>
|
||||
<property name="homogeneous">False</property>
|
||||
<property name="spacing">0</property>
|
||||
|
||||
<child>
|
||||
<widget class="GtkButton" id="add_button">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="label">gtk-add</property>
|
||||
<property name="use_stock">True</property>
|
||||
<property name="relief">GTK_RELIEF_NORMAL</property>
|
||||
<property name="focus_on_click">True</property>
|
||||
<signal name="clicked" handler="on_add_button_clicked" last_modification_time="Mon, 21 Aug 2006 22:32:45 GMT"/>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="padding">0</property>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">False</property>
|
||||
</packing>
|
||||
</child>
|
||||
|
||||
<child>
|
||||
<widget class="GtkButton" id="remove_button">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="label">gtk-remove</property>
|
||||
<property name="use_stock">True</property>
|
||||
<property name="relief">GTK_RELIEF_NORMAL</property>
|
||||
<property name="focus_on_click">True</property>
|
||||
<signal name="clicked" handler="on_remove_button_clicked" last_modification_time="Mon, 21 Aug 2006 22:32:50 GMT"/>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="padding">0</property>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">False</property>
|
||||
</packing>
|
||||
</child>
|
||||
|
||||
<child>
|
||||
<widget class="GtkHSeparator" id="hseparator17">
|
||||
<property name="visible">True</property>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="padding">3</property>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">False</property>
|
||||
</packing>
|
||||
</child>
|
||||
|
||||
<child>
|
||||
<widget class="GtkButton" id="edit_button">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="label">gtk-edit</property>
|
||||
<property name="use_stock">True</property>
|
||||
<property name="relief">GTK_RELIEF_NORMAL</property>
|
||||
<property name="focus_on_click">True</property>
|
||||
<signal name="clicked" handler="on_edit_button_clicked" last_modification_time="Mon, 21 Aug 2006 22:32:54 GMT"/>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="padding">0</property>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">False</property>
|
||||
</packing>
|
||||
</child>
|
||||
|
||||
<child>
|
||||
<widget class="GtkHSeparator" id="hseparator18">
|
||||
<property name="visible">True</property>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="padding">3</property>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
</packing>
|
||||
</child>
|
||||
|
||||
<child>
|
||||
<widget class="GtkButton" id="up_button">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="label">gtk-go-up</property>
|
||||
<property name="use_stock">True</property>
|
||||
<property name="relief">GTK_RELIEF_NORMAL</property>
|
||||
<property name="focus_on_click">True</property>
|
||||
<signal name="clicked" handler="on_up_button_clicked" last_modification_time="Mon, 21 Aug 2006 22:32:59 GMT"/>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="padding">0</property>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">False</property>
|
||||
</packing>
|
||||
</child>
|
||||
|
||||
<child>
|
||||
<widget class="GtkButton" id="down_button">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="label">gtk-go-down</property>
|
||||
<property name="use_stock">True</property>
|
||||
<property name="relief">GTK_RELIEF_NORMAL</property>
|
||||
<property name="focus_on_click">True</property>
|
||||
<signal name="clicked" handler="on_down_button_clicked" last_modification_time="Mon, 21 Aug 2006 22:33:03 GMT"/>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="padding">0</property>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">False</property>
|
||||
</packing>
|
||||
</child>
|
||||
|
||||
<child>
|
||||
<widget class="GtkHSeparator" id="hseparator19">
|
||||
<property name="visible">True</property>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="padding">3</property>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
</packing>
|
||||
</child>
|
||||
|
||||
<child>
|
||||
<widget class="GtkButton" id="clear_button">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="label">gtk-clear</property>
|
||||
<property name="use_stock">True</property>
|
||||
<property name="relief">GTK_RELIEF_NORMAL</property>
|
||||
<property name="focus_on_click">True</property>
|
||||
<signal name="clicked" handler="on_clear_button_clicked" last_modification_time="Mon, 21 Aug 2006 22:33:07 GMT"/>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="padding">0</property>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">False</property>
|
||||
</packing>
|
||||
</child>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="padding">0</property>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
</packing>
|
||||
</child>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="tab_expand">False</property>
|
||||
<property name="tab_fill">True</property>
|
||||
</packing>
|
||||
</child>
|
||||
|
||||
<child>
|
||||
<widget class="GtkLabel" id="label3">
|
||||
<property name="visible">True</property>
|
||||
<property name="label" translatable="yes"></property>
|
||||
<property name="use_underline">False</property>
|
||||
<property name="use_markup">False</property>
|
||||
<property name="justify">GTK_JUSTIFY_LEFT</property>
|
||||
<property name="wrap">False</property>
|
||||
<property name="selectable">False</property>
|
||||
<property name="xalign">0.5</property>
|
||||
<property name="yalign">0.5</property>
|
||||
<property name="xpad">0</property>
|
||||
<property name="ypad">0</property>
|
||||
<property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
|
||||
<property name="width_chars">-1</property>
|
||||
<property name="single_line_mode">False</property>
|
||||
<property name="angle">0</property>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="type">tab</property>
|
||||
</packing>
|
||||
</child>
|
||||
|
||||
<child>
|
||||
<placeholder/>
|
||||
</child>
|
||||
|
||||
<child>
|
||||
<widget class="GtkLabel" id="label4">
|
||||
<property name="visible">True</property>
|
||||
<property name="label" translatable="yes"></property>
|
||||
<property name="use_underline">False</property>
|
||||
<property name="use_markup">False</property>
|
||||
<property name="justify">GTK_JUSTIFY_LEFT</property>
|
||||
<property name="wrap">False</property>
|
||||
<property name="selectable">False</property>
|
||||
<property name="xalign">0.5</property>
|
||||
<property name="yalign">0.5</property>
|
||||
<property name="xpad">0</property>
|
||||
<property name="ypad">0</property>
|
||||
<property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
|
||||
<property name="width_chars">-1</property>
|
||||
<property name="single_line_mode">False</property>
|
||||
<property name="angle">0</property>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="type">tab</property>
|
||||
</packing>
|
||||
</child>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="padding">0</property>
|
||||
<property name="expand">True</property>
|
||||
<property name="fill">True</property>
|
||||
</packing>
|
||||
</child>
|
||||
</widget>
|
||||
</child>
|
||||
</widget>
|
||||
|
||||
</glade-interface>
|
||||
|
|
|
@ -30,7 +30,7 @@ from common import xmpp, gajim, dataforms
|
|||
|
||||
import gtkgui_helpers
|
||||
import dialogs
|
||||
import dataforms as dataformwidget
|
||||
import dataforms_widget
|
||||
|
||||
class CommandWindow:
|
||||
'''Class for a window for single ad-hoc commands session. Note, that
|
||||
|
@ -70,7 +70,7 @@ class CommandWindow:
|
|||
self.__dict__[name] = self.xml.get_widget(name)
|
||||
|
||||
# creating data forms widget
|
||||
self.data_form_widget = dataformwidget.DataFormWidget()
|
||||
self.data_form_widget = dataforms_widget.DataFormWidget()
|
||||
self.data_form_widget.show()
|
||||
self.sending_form_stage_vbox.pack_start(self.data_form_widget)
|
||||
|
||||
|
@ -497,14 +497,18 @@ class CommandWindow:
|
|||
def send_cancel(self):
|
||||
'''Send the command with action='cancel'. '''
|
||||
assert self.commandnode is not None
|
||||
assert self.sessionid is not None
|
||||
if self.sessionid is not None:
|
||||
# we already have sessionid, so the service sent at least one reply.
|
||||
stanza = xmpp.Iq(typ='set', to=self.jid)
|
||||
stanza.addChild('command', attrs={
|
||||
'xmlns':xmpp.NS_COMMANDS,
|
||||
'node':self.commandnode,
|
||||
'sessionid':self.sessionid,
|
||||
'action':'cancel'
|
||||
})
|
||||
|
||||
stanza = xmpp.Iq(typ='set', to=self.jid)
|
||||
stanza.addChild('command', attrs={
|
||||
'xmlns':xmpp.NS_COMMANDS,
|
||||
'node':self.commandnode,
|
||||
'sessionid':self.sessionid,
|
||||
'action':'cancel'
|
||||
})
|
||||
|
||||
self.account.connection.send(stanza)
|
||||
self.account.connection.send(stanza)
|
||||
else:
|
||||
# we did not received any reply from service; TODO: we should wait and
|
||||
# then send cancel; for now we do nothing
|
||||
pass
|
||||
|
|
|
@ -64,13 +64,14 @@ class DataForm(xmpp.Node, object):
|
|||
You can also set 'tofill' to DataForm to get a form of type 'submit' with the
|
||||
same fields as in the form given, but without unnecessary data like
|
||||
instructions or title. Also the type will be set to 'submit' by default."""
|
||||
assert (isinstance(node, xmpp.Node) or node is None)
|
||||
assert (isinstance(tofill, DataForm) or tofill is None)
|
||||
assert not (node is not None and tofill is not None)
|
||||
# assert that exactly one of fields 'node' and 'tofill' is filled
|
||||
assert node is None or isinstance(node, xmpp.Node)
|
||||
assert tofill is None or isinstance(tofill, xmpp.Node)
|
||||
assert node is None or tofill is None
|
||||
|
||||
assert typ in (None, 'form', 'submit', 'cancel', 'result')
|
||||
assert isinstance(title, basestring) or title is None
|
||||
assert isinstance(instructions, basestring) or instructions is None
|
||||
assert title is None or isinstance(title, basestring)
|
||||
assert instructions is None or isinstance(instructions, basestring)
|
||||
assert (fields is None or fields.__iter__)
|
||||
|
||||
xmpp.Node.__init__(self, 'x', node=node)
|
||||
|
@ -186,21 +187,14 @@ class DataForm(xmpp.Node, object):
|
|||
if self.mode is DATAFORM_SINGLE:
|
||||
yield DataRecord(node=self)
|
||||
else:
|
||||
for item in self.getChildren():
|
||||
if not isinstance(item, xmpp.Node): continue
|
||||
if not item.getName()=='item': continue
|
||||
yield DataRecord(node=item)
|
||||
for i in iter_elements(self, 'item'):
|
||||
yield i
|
||||
|
||||
def get_records(self):
|
||||
if self.mode is DATAFORM_SINGLE:
|
||||
return [DataRecord(node=self),]
|
||||
else:
|
||||
items = []
|
||||
for node in self.getChildren():
|
||||
if not isinstance(node, xmpp.Node): continue
|
||||
if not node.getName()=='item': continue
|
||||
items.append(DataRecord(node=node))
|
||||
return items
|
||||
return list(iter_elements(self, 'item'))
|
||||
|
||||
def set_records(self, records):
|
||||
if self.mode is DATAFORM_SINGLE:
|
||||
|
@ -211,10 +205,15 @@ class DataForm(xmpp.Node, object):
|
|||
for field in record.iter_fields():
|
||||
self[field.var]=field.value
|
||||
else:
|
||||
self.del_records(self)
|
||||
self.del_records()
|
||||
for record in records:
|
||||
assert isinstance(record, dict)
|
||||
newitem = self.addChild('item', node=record)
|
||||
newitem = self.addChild('item')
|
||||
for key, value in record.iteritems():
|
||||
newitem.addChild(node=DataField(
|
||||
var=key,
|
||||
value=value,
|
||||
typ=self.get_field(key).type))
|
||||
|
||||
def del_records(self):
|
||||
if self.mode is DATAFORM_SINGLE:
|
||||
|
@ -229,6 +228,22 @@ class DataForm(xmpp.Node, object):
|
|||
"""Records kept in this form; if in DATAFORM_SINGLE mode, there will be exactly
|
||||
one record, otherwise there might be more or less records.""")
|
||||
|
||||
def iter_fields(self):
|
||||
if self.mode is DATAFORM_SINGLE:
|
||||
container = self
|
||||
else:
|
||||
container = self.getTag("recorded")
|
||||
|
||||
for child in container.getChildren():
|
||||
if isinstance(child, DataField):
|
||||
yield child
|
||||
|
||||
def get_field(self, fieldvar):
|
||||
''' Find DataField that has fieldvar as var. '''
|
||||
for field in self.iter_fields():
|
||||
if field.var == fieldvar: return field
|
||||
raise KeyError, "This form does not contain %r field." % fieldvar
|
||||
|
||||
def get_fields(self):
|
||||
if self.mode is DATAFORM_SINGLE:
|
||||
container = self
|
||||
|
@ -260,16 +275,6 @@ class DataForm(xmpp.Node, object):
|
|||
except ValueError:
|
||||
pass
|
||||
|
||||
def iter_fields(self):
|
||||
if self.mode is DATAFORM_SINGLE:
|
||||
container = self
|
||||
else:
|
||||
container = self.getTag("recorded")
|
||||
|
||||
for child in container.getChildren():
|
||||
if isinstance(child, DataField):
|
||||
yield child
|
||||
|
||||
fields = property(get_fields, set_fields, del_fields,
|
||||
"""Fields in this form; a list; if in DATAFORM_SINGLE mode, you should not
|
||||
set their values directly.""")
|
||||
|
|
347
src/dataforms.py
347
src/dataforms.py
|
@ -1,347 +0,0 @@
|
|||
## dataforms.py
|
||||
##
|
||||
## Copyright (C) 2003-2006 Yann Le Boulanger <asterix@lagaule.org>
|
||||
## Copyright (C) 2005-2006 Nikos Kouremenos <nkour@jabber.org>
|
||||
## Copyright (C) 2005 Dimitur Kirov <dkirov@gmail.com>
|
||||
## Copyright (C) 2003-2005 Vincent Hanquez <tab@snarc.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; version 2 only.
|
||||
##
|
||||
## 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.
|
||||
##
|
||||
""" This module contains widget that can display data form (JEP-0004). """
|
||||
|
||||
# TODO: forms of type='result' should be read-only
|
||||
|
||||
import gtk
|
||||
import pango
|
||||
|
||||
import gtkgui_helpers
|
||||
|
||||
import common.xmpp as xmpp
|
||||
import common.dataforms as dataforms
|
||||
|
||||
class DataFormWidget(gtk.Alignment, object):
|
||||
# "public" interface
|
||||
""" Data Form widget. Use like any other widget. """
|
||||
def __init__(self, dataformnode=None):
|
||||
""" Create a widget. """
|
||||
gtk.Alignment.__init__(self, xscale=1.0, yscale=1.0)
|
||||
|
||||
self._data_form = None
|
||||
|
||||
self.xml=gtkgui_helpers.get_glade('data_form_window.glade', 'data_form_scrolledwindow')
|
||||
self.instructions = self.xml.get_widget('form_instructions_label')
|
||||
self.separator = self.xml.get_widget('form_instructions_hseparator')
|
||||
self.container = self.xml.get_widget('container_vbox')
|
||||
|
||||
self.add(self.xml.get_widget('data_form_scrolledwindow'))
|
||||
|
||||
if dataformnode is not None:
|
||||
self.set_data_form(dataformnode)
|
||||
|
||||
def set_data_form(self, dataform=None):
|
||||
""" Set the data form (xmpp.DataForm) displayed in widget.
|
||||
Set to None to erase the form. """
|
||||
assert isinstance(dataform, dataforms.DataForm)
|
||||
|
||||
self.del_data_form()
|
||||
self._data_form = dataform
|
||||
if dataform.mode==dataforms.DATAFORM_SINGLE:
|
||||
self.form = self.__class__.SingleForm(dataform)
|
||||
else:
|
||||
self.form = self.__class__.MultipleForm(dataform)
|
||||
self.form.show()
|
||||
self.container.pack_end(self.form, expand=True, fill=True)
|
||||
|
||||
if dataform.instructions is None:
|
||||
self.instructions.set_no_show_all(True)
|
||||
self.instructions.hide()
|
||||
self.separator.set_no_show_all(True)
|
||||
self.separator.hide()
|
||||
else:
|
||||
self.instructions.set_text(dataform.instructions)
|
||||
self.instructions.set_no_show_all(False)
|
||||
self.instructions.show()
|
||||
self.separator.set_no_show_all(False)
|
||||
self.separator.show()
|
||||
|
||||
def get_data_form(self):
|
||||
""" Data form displayed in the widget or None if no form. """
|
||||
return self._data_form
|
||||
|
||||
def del_data_form(self):
|
||||
if self._data_form is not None:
|
||||
self.container.remove(self.form)
|
||||
self.form = None
|
||||
self._data_form = None
|
||||
|
||||
data_form = property(get_data_form, set_data_form, del_data_form,
|
||||
"Data form presented in a widget")
|
||||
|
||||
def get_title(self):
|
||||
""" Get the title of data form, as a unicode object. If no
|
||||
title or no form, returns u''. Useful for setting window title. """
|
||||
if self._data_form is not None:
|
||||
if self._data_form.has_key('title'):
|
||||
return self._data_form['title'].encode('utf-8')
|
||||
return u''
|
||||
|
||||
title = property(get_title, None, None, "Data form title")
|
||||
|
||||
def show(self):
|
||||
""" Treat 'us' as one widget. """
|
||||
self.show_all()
|
||||
|
||||
# "private" methods
|
||||
|
||||
# we have actually two different kinds of data forms: one is a simple form to fill,
|
||||
# second is a table with several records; we will treat second as read-only, but still
|
||||
# we should have a way to show it
|
||||
|
||||
# we will place both types in two different private classes, so the code will be clean;
|
||||
# both will have the same interface
|
||||
|
||||
class SingleForm(gtk.Table, object):
|
||||
""" Widget that represent DATAFORM_SINGLE mode form. """
|
||||
def __init__(self, dataform):
|
||||
assert dataform.mode==dataforms.DATAFORM_SINGLE
|
||||
|
||||
gtk.Table.__init__(self)
|
||||
self.set_col_spacings(6)
|
||||
self.set_row_spacings(6)
|
||||
|
||||
self._data_form = dataform
|
||||
|
||||
# building widget
|
||||
linecounter = 0
|
||||
|
||||
# for each field...
|
||||
for field in self._data_form.iter_fields():
|
||||
if field.type=='hidden': continue
|
||||
|
||||
commonlabel = True
|
||||
commondesc = True
|
||||
commonwidget = True
|
||||
widget = None
|
||||
|
||||
if field.type=='boolean':
|
||||
widget = gtk.CheckButton()
|
||||
widget.connect('toggled', self.on_boolean_checkbutton_toggled, field)
|
||||
widget.set_active(field.value)
|
||||
|
||||
elif field.type=='fixed':
|
||||
leftattach = 1
|
||||
rightattach = 2
|
||||
if field.label is None:
|
||||
commonlabel = False
|
||||
leftattach = 0
|
||||
if field.description is None:
|
||||
commondesc = False
|
||||
rightattach = 3
|
||||
|
||||
commonwidget=False
|
||||
widget = gtk.Label(field.value)
|
||||
widget.set_line_wrap(True)
|
||||
self.attach(widget, leftattach, rightattach, linecounter, linecounter+1,
|
||||
xoptions=gtk.FILL, yoptions=gtk.FILL)
|
||||
|
||||
elif field.type == 'list-single':
|
||||
# TODO: When more than few choices, make a list
|
||||
# TODO: Think of moving that to another function (it could be used
|
||||
# TODO: in stage2 of adhoc commands too).
|
||||
# TODO: What if we have radio buttons and non-required field?
|
||||
# TODO: We cannot deactivate them all...
|
||||
widget = gtk.VBox()
|
||||
first_radio = None
|
||||
for value, label in field.iter_options():
|
||||
radio = gtk.RadioButton(first_radio, label=label)
|
||||
radio.connect('toggled', self.on_list_single_radiobutton_toggled,
|
||||
field, value)
|
||||
if first_radio is None:
|
||||
first_radio = radio
|
||||
if field.value is None:
|
||||
field.value = value
|
||||
if value == field.value:
|
||||
radio.set_active(True)
|
||||
widget.pack_start(radio, expand=False)
|
||||
|
||||
elif field.type == 'list-multi':
|
||||
# TODO: When more than few choices, make a list
|
||||
widget = gtk.VBox()
|
||||
for value, label in field.iter_options():
|
||||
check = gtk.CheckButton(label, use_underline=False)
|
||||
check.set_active(value in field.value)
|
||||
check.connect('toggled', self.on_list_multi_checkbutton_toggled,
|
||||
field, value)
|
||||
widget.pack_start(check, expand=False)
|
||||
|
||||
elif field.type == 'jid-single':
|
||||
widget = gtk.Entry()
|
||||
widget.connect('changed', self.on_text_single_entry_changed, field)
|
||||
if field.value is None:
|
||||
field.value = u''
|
||||
widget.set_text(field.value)
|
||||
|
||||
elif field.type == 'jid-multi':
|
||||
commonwidget = False
|
||||
|
||||
xml = gtkgui_helpers.get_glade('data_form_window.glade', 'item_list_table')
|
||||
widget = xml.get_widget('item_list_table')
|
||||
treeview = xml.get_widget('item_treeview')
|
||||
|
||||
listmodel = gtk.ListStore(str)
|
||||
for value in field.iter_values():
|
||||
# nobody will create several megabytes long stanza
|
||||
listmodel.insert(999999, (value,))
|
||||
|
||||
treeview.set_model(listmodel)
|
||||
|
||||
renderer = gtk.CellRendererText()
|
||||
renderer.set_property('editable', True)
|
||||
renderer.connect('edited',
|
||||
self.on_jid_multi_cellrenderertext_edited, listmodel, field)
|
||||
|
||||
treeview.append_column(gtk.TreeViewColumn(None, renderer,
|
||||
text=0))
|
||||
|
||||
xml.get_widget('add_button').connect('clicked',
|
||||
self.on_jid_multi_add_button_clicked, treeview, listmodel, field)
|
||||
xml.get_widget('edit_button').connect('clicked',
|
||||
self.on_jid_multi_edit_button_clicked, treeview)
|
||||
xml.get_widget('remove_button').connect('clicked',
|
||||
self.on_jid_multi_remove_button_clicked, treeview, field)
|
||||
xml.get_widget('clear_button').connect('clicked',
|
||||
self.on_jid_multi_clean_button_clicked, listmodel, field)
|
||||
|
||||
self.attach(widget, 1, 2, linecounter, linecounter+1)
|
||||
|
||||
del xml
|
||||
|
||||
elif field.type == 'text-private':
|
||||
widget = gtk.Entry()
|
||||
widget.connect('changed', self.on_text_single_entry_changed, field)
|
||||
widget.set_visibility(False)
|
||||
if field.value is None:
|
||||
field.value = u''
|
||||
widget.set_text(field.value)
|
||||
|
||||
elif field.type == 'text-multi':
|
||||
# TODO: bigger text view
|
||||
commonwidget = False
|
||||
|
||||
textwidget = gtk.TextView()
|
||||
textwidget.set_wrap_mode(gtk.WRAP_WORD)
|
||||
textwidget.get_buffer().connect('changed', self.on_text_multi_textbuffer_changed,
|
||||
field)
|
||||
if field.value is None:
|
||||
field.value = u''
|
||||
textwidget.get_buffer().set_text(field.value)
|
||||
|
||||
widget = gtk.ScrolledWindow()
|
||||
widget.add(textwidget)
|
||||
|
||||
self.attach(widget, 1, 2, linecounter, linecounter+1)
|
||||
|
||||
else:# field.type == 'text-single' or field.type is nonstandard:
|
||||
# JEP says that if we don't understand some type, we
|
||||
# should handle it as text-single
|
||||
widget = gtk.Entry()
|
||||
widget.connect('changed', self.on_text_single_entry_changed, field)
|
||||
if field.value is None:
|
||||
field.value = u''
|
||||
widget.set_text(field.value)
|
||||
|
||||
if commonlabel and field.label is not None:
|
||||
label = gtk.Label(field.label)
|
||||
label.set_alignment(1.0, 0.5)
|
||||
self.attach(label, 0, 1, linecounter, linecounter+1,
|
||||
xoptions=gtk.FILL, yoptions=gtk.FILL)
|
||||
|
||||
if commonwidget:
|
||||
assert widget is not None
|
||||
self.attach(widget, 1, 2, linecounter, linecounter+1,
|
||||
yoptions=gtk.FILL)
|
||||
widget.show_all()
|
||||
|
||||
if commondesc and field.description is not None:
|
||||
label = gtk.Label()
|
||||
label.set_markup('<small>'+\
|
||||
gtkgui_helpers.escape_for_pango_markup(field.description)+\
|
||||
'</small>')
|
||||
label.set_line_wrap(True)
|
||||
self.attach(label, 2, 3, linecounter, linecounter+1,
|
||||
xoptions=gtk.FILL|gtk.SHRINK, yoptions=gtk.FILL|gtk.SHRINK)
|
||||
|
||||
linecounter+=1
|
||||
if self.get_property('visible'):
|
||||
self.show_all()
|
||||
|
||||
def show(self):
|
||||
# simulate that we are one widget
|
||||
self.show_all()
|
||||
|
||||
def on_boolean_checkbutton_toggled(self, widget, field):
|
||||
field.value = widget.get_active()
|
||||
|
||||
def on_list_single_radiobutton_toggled(self, widget, field, value):
|
||||
field.value = value
|
||||
|
||||
def on_list_multi_checkbutton_toggled(self, widget, field, value):
|
||||
# TODO: make some methods like add_value and remove_value
|
||||
if widget.get_active() and value not in field.value:
|
||||
field.value += [value]
|
||||
elif not widget.get_active() and value in field.value:
|
||||
field.value = [v for v in field.value if v!=value]
|
||||
|
||||
def on_text_single_entry_changed(self, widget, field):
|
||||
field.value = widget.get_text()
|
||||
|
||||
def on_text_multi_textbuffer_changed(self, widget, field):
|
||||
field.value = widget.get_text(
|
||||
widget.get_start_iter(),
|
||||
widget.get_end_iter())
|
||||
|
||||
def on_jid_multi_cellrenderertext_edited(self, cell, path, newtext, model, field):
|
||||
old=model[path][0]
|
||||
model[path][0]=newtext
|
||||
|
||||
values = field.value
|
||||
values[values.index(old)]=newtext
|
||||
field.value = values
|
||||
|
||||
def on_jid_multi_add_button_clicked(self, widget, treeview, model, field):
|
||||
iter = model.insert(999999, ("new@jabber.id",))
|
||||
treeview.set_cursor(model.get_path(iter), treeview.get_column(0), True)
|
||||
field.value = field.value + ["new@jabber.id"]
|
||||
|
||||
def on_jid_multi_edit_button_clicked(self, widget, treeview):
|
||||
model, iter = treeview.get_selection().get_selected()
|
||||
assert iter is not None
|
||||
|
||||
treeview.set_cursor(model.get_path(iter), treeview.get_column(0), True)
|
||||
|
||||
def on_jid_multi_remove_button_clicked(self, widget, treeview, field):
|
||||
selection = treeview.get_selection()
|
||||
model = treeview.get_model()
|
||||
deleted = []
|
||||
|
||||
def remove(model, path, iter, deleted):
|
||||
deleted+=model[iter]
|
||||
model.remove(iter)
|
||||
|
||||
selection.selected_foreach(remove, deleted)
|
||||
field.value = (v for v in field.value if v not in deleted)
|
||||
|
||||
def on_jid_multi_clean_button_clicked(self, widget, model, field):
|
||||
model.clear()
|
||||
del field.value
|
||||
|
||||
class MultipleForm(gtk.Alignment, object):
|
||||
def __init__(self, dataform):
|
||||
assert dataform.mode==dataforms.DATAFORM_MULTIPLE
|
|
@ -0,0 +1,417 @@
|
|||
## dataforms.py
|
||||
##
|
||||
## Copyright (C) 2003-2006 Yann Le Boulanger <asterix@lagaule.org>
|
||||
## Copyright (C) 2005-2006 Nikos Kouremenos <nkour@jabber.org>
|
||||
## Copyright (C) 2005 Dimitur Kirov <dkirov@gmail.com>
|
||||
## Copyright (C) 2003-2005 Vincent Hanquez <tab@snarc.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; version 2 only.
|
||||
##
|
||||
## 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.
|
||||
##
|
||||
""" This module contains widget that can display data form (JEP-0004).
|
||||
Words single and multiple refers here to types of data forms:
|
||||
single means these with one record of data (without <recorded/> element),
|
||||
multiple - these that may contain more data (with <recorded/> element)."""
|
||||
|
||||
# TODO: forms of type='result' should be read-only
|
||||
# TODO: remove tabs from dialog
|
||||
|
||||
import gtk
|
||||
import pango
|
||||
|
||||
import gtkgui_helpers
|
||||
|
||||
import common.xmpp as xmpp
|
||||
import common.dataforms as dataforms
|
||||
|
||||
class DataFormWidget(gtk.Alignment, object):
|
||||
# "public" interface
|
||||
""" Data Form widget. Use like any other widget. """
|
||||
def __init__(self, dataformnode=None):
|
||||
""" Create a widget. """
|
||||
gtk.Alignment.__init__(self, xscale=1.0, yscale=1.0)
|
||||
|
||||
self._data_form = None
|
||||
|
||||
self.xml=gtkgui_helpers.get_glade('data_form_window.glade', 'data_form_vbox')
|
||||
for name in ('instructions_label', 'instructions_hseparator',
|
||||
'single_form_viewport', 'data_form_types_notebook',
|
||||
'single_form_scrolledwindow', 'multiple_form_hbox',
|
||||
'records_treeview', 'up_button', 'down_button', 'clear_button'):
|
||||
self.__dict__[name] = self.xml.get_widget(name)
|
||||
|
||||
self.add(self.xml.get_widget('data_form_vbox'))
|
||||
|
||||
if dataformnode is not None:
|
||||
self.set_data_form(dataformnode)
|
||||
|
||||
def set_data_form(self, dataform=None):
|
||||
""" Set the data form (xmpp.DataForm) displayed in widget.
|
||||
Set to None to erase the form. """
|
||||
assert isinstance(dataform, dataforms.DataForm)
|
||||
|
||||
self.del_data_form()
|
||||
self._data_form = dataform
|
||||
if dataform.mode==dataforms.DATAFORM_SINGLE:
|
||||
self.build_single_data_form()
|
||||
else:
|
||||
self.build_multiple_data_form()
|
||||
|
||||
# create appropriate description for instructions field if there isn't any
|
||||
if dataform.instructions is None:
|
||||
if dataform.type=='result':
|
||||
# form is single
|
||||
instructions = _('This is result of query.')
|
||||
else:
|
||||
# form is writable
|
||||
if dataform.mode==dataforms.DATAFORM_SINGLE:
|
||||
instructions = _('Fill in the form.')
|
||||
else:
|
||||
instructions = _('Edit items on the list')
|
||||
else:
|
||||
instructions = dataform.instructions
|
||||
|
||||
self.instructions_label.set_text(dataform.instructions)
|
||||
|
||||
def get_data_form(self):
|
||||
""" Data form displayed in the widget or None if no form. """
|
||||
return self._data_form
|
||||
|
||||
def del_data_form(self):
|
||||
self.clean_data_form()
|
||||
self._data_form = None
|
||||
|
||||
data_form = property(get_data_form, set_data_form, del_data_form,
|
||||
"Data form presented in a widget")
|
||||
|
||||
def get_title(self):
|
||||
""" Get the title of data form, as a unicode object. If no
|
||||
title or no form, returns u''. Useful for setting window title. """
|
||||
if self._data_form is not None:
|
||||
if self._data_form.has_key('title'):
|
||||
# TODO: encode really needed? check this
|
||||
return self._data_form['title'].encode('utf-8')
|
||||
return u''
|
||||
|
||||
title = property(get_title, None, None, "Data form title")
|
||||
|
||||
def show(self):
|
||||
""" Treat 'us' as one widget. """
|
||||
self.show_all()
|
||||
|
||||
# "private" methods
|
||||
|
||||
# we have actually two different kinds of data forms: one is a simple form to fill,
|
||||
# second is a table with several records;
|
||||
|
||||
def clean_data_form(self):
|
||||
'''Remove data about existing form. This metod is empty, because
|
||||
it is rewritten by build_*_data_form, according to type of form
|
||||
which is actually displayed.'''
|
||||
pass
|
||||
|
||||
def build_single_data_form(self):
|
||||
'''Invoked when new single form is to be created.'''
|
||||
assert self._data_form.mode==dataforms.DATAFORM_SINGLE
|
||||
|
||||
self.clean_data_form()
|
||||
|
||||
self.singleform = SingleForm(self._data_form)
|
||||
self.singleform.show()
|
||||
self.single_form_viewport.add(self.singleform)
|
||||
self.data_form_types_notebook.set_current_page(
|
||||
self.data_form_types_notebook.page_num(
|
||||
self.single_form_scrolledwindow))
|
||||
|
||||
self.clean_data_form = self.clean_single_data_form
|
||||
|
||||
def clean_single_data_form(self):
|
||||
'''(Called as clean_data_form, read the docs of clean_data_form()).
|
||||
Remove form from widget.'''
|
||||
self.singleform.destroy()
|
||||
del self.singleform
|
||||
|
||||
def build_multiple_data_form(self):
|
||||
'''Invoked when new multiple form is to be created.'''
|
||||
assert self._data_form.mode==dataforms.DATAFORM_MULTIPLE
|
||||
|
||||
self.clean_data_form()
|
||||
|
||||
# creating model for form...
|
||||
fieldtypes = []
|
||||
for field in self._data_form.iter_fields():
|
||||
# note: we store also text-private and hidden fields,
|
||||
# we just do not display them.
|
||||
# TODO: boolean fields
|
||||
#elif field.type=='boolean': fieldtypes.append(bool)
|
||||
fieldtypes.append(unicode)
|
||||
|
||||
self.multiplemodel = gtk.ListModel(*fieldtypes)
|
||||
|
||||
# moving all data to model
|
||||
for item in self._data_form.iter_records():
|
||||
self.multiplemodel.append(field.value for field in item.iter_fields())
|
||||
|
||||
# contructing columns...
|
||||
for field in self._data_form.iter_fields():
|
||||
self.records_treeview.append(
|
||||
gtk.TreeViewColumn(
|
||||
title=field.label,
|
||||
cell_renderer=gtk.CellRendererText(),
|
||||
text=field.value))
|
||||
|
||||
self.records.show_all()
|
||||
|
||||
self.data_form_types_notebook.set_current_page(
|
||||
self.data_form_types_notebook.page_num(
|
||||
self.multiple_form_hbox))
|
||||
|
||||
self.clean_data_form = self.clean_multiple_data_form
|
||||
|
||||
def clean_multiple_data_form(self):
|
||||
'''(Called as clean_data_form, read the docs of clean_data_form()).
|
||||
Remove form from widget.'''
|
||||
pass
|
||||
|
||||
class SingleForm(gtk.Table, object):
|
||||
""" Widget that represent DATAFORM_SINGLE mode form. Because this is used
|
||||
not only to display single forms, but to form input windows of multiple-type
|
||||
forms, it is in another class."""
|
||||
def __init__(self, dataform):
|
||||
assert dataform.mode==dataforms.DATAFORM_SINGLE
|
||||
|
||||
gtk.Table.__init__(self)
|
||||
self.set_col_spacings(6)
|
||||
self.set_row_spacings(6)
|
||||
|
||||
self._data_form = dataform
|
||||
|
||||
# building widget
|
||||
linecounter = 0
|
||||
|
||||
# for each field...
|
||||
for field in self._data_form.iter_fields():
|
||||
if field.type=='hidden': continue
|
||||
|
||||
commonlabel = True
|
||||
commondesc = True
|
||||
commonwidget = True
|
||||
widget = None
|
||||
|
||||
if field.type=='boolean':
|
||||
widget = gtk.CheckButton()
|
||||
widget.connect('toggled', self.on_boolean_checkbutton_toggled, field)
|
||||
widget.set_active(field.value)
|
||||
|
||||
elif field.type=='fixed':
|
||||
leftattach = 1
|
||||
rightattach = 2
|
||||
if field.label is None:
|
||||
commonlabel = False
|
||||
leftattach = 0
|
||||
if field.description is None:
|
||||
commondesc = False
|
||||
rightattach = 3
|
||||
|
||||
commonwidget=False
|
||||
widget = gtk.Label(field.value)
|
||||
widget.set_line_wrap(True)
|
||||
self.attach(widget, leftattach, rightattach, linecounter, linecounter+1,
|
||||
xoptions=gtk.FILL, yoptions=gtk.FILL)
|
||||
|
||||
elif field.type == 'list-single':
|
||||
# TODO: When more than few choices, make a list
|
||||
# TODO: Think of moving that to another function (it could be used
|
||||
# TODO: in stage2 of adhoc commands too).
|
||||
# TODO: What if we have radio buttons and non-required field?
|
||||
# TODO: We cannot deactivate them all...
|
||||
widget = gtk.VBox()
|
||||
first_radio = None
|
||||
for value, label in field.iter_options():
|
||||
radio = gtk.RadioButton(first_radio, label=label)
|
||||
radio.connect('toggled', self.on_list_single_radiobutton_toggled,
|
||||
field, value)
|
||||
if first_radio is None:
|
||||
first_radio = radio
|
||||
if field.value is None:
|
||||
field.value = value
|
||||
if value == field.value:
|
||||
radio.set_active(True)
|
||||
widget.pack_start(radio, expand=False)
|
||||
|
||||
elif field.type == 'list-multi':
|
||||
# TODO: When more than few choices, make a list
|
||||
widget = gtk.VBox()
|
||||
for value, label in field.iter_options():
|
||||
check = gtk.CheckButton(label, use_underline=False)
|
||||
check.set_active(value in field.value)
|
||||
check.connect('toggled', self.on_list_multi_checkbutton_toggled,
|
||||
field, value)
|
||||
widget.pack_start(check, expand=False)
|
||||
|
||||
elif field.type == 'jid-single':
|
||||
widget = gtk.Entry()
|
||||
widget.connect('changed', self.on_text_single_entry_changed, field)
|
||||
if field.value is None:
|
||||
field.value = u''
|
||||
widget.set_text(field.value)
|
||||
|
||||
elif field.type == 'jid-multi':
|
||||
commonwidget = False
|
||||
|
||||
xml = gtkgui_helpers.get_glade('data_form_window.glade', 'item_list_table')
|
||||
widget = xml.get_widget('item_list_table')
|
||||
treeview = xml.get_widget('item_treeview')
|
||||
|
||||
listmodel = gtk.ListStore(str)
|
||||
for value in field.iter_values():
|
||||
# nobody will create several megabytes long stanza
|
||||
listmodel.insert(999999, (value,))
|
||||
|
||||
treeview.set_model(listmodel)
|
||||
|
||||
renderer = gtk.CellRendererText()
|
||||
renderer.set_property('editable', True)
|
||||
renderer.connect('edited',
|
||||
self.on_jid_multi_cellrenderertext_edited, listmodel, field)
|
||||
|
||||
treeview.append_column(gtk.TreeViewColumn(None, renderer,
|
||||
text=0))
|
||||
|
||||
xml.get_widget('add_button').connect('clicked',
|
||||
self.on_jid_multi_add_button_clicked, treeview, listmodel, field)
|
||||
xml.get_widget('edit_button').connect('clicked',
|
||||
self.on_jid_multi_edit_button_clicked, treeview)
|
||||
xml.get_widget('remove_button').connect('clicked',
|
||||
self.on_jid_multi_remove_button_clicked, treeview, field)
|
||||
xml.get_widget('clear_button').connect('clicked',
|
||||
self.on_jid_multi_clean_button_clicked, listmodel, field)
|
||||
|
||||
self.attach(widget, 1, 2, linecounter, linecounter+1)
|
||||
|
||||
del xml
|
||||
|
||||
elif field.type == 'text-private':
|
||||
widget = gtk.Entry()
|
||||
widget.connect('changed', self.on_text_single_entry_changed, field)
|
||||
widget.set_visibility(False)
|
||||
if field.value is None:
|
||||
field.value = u''
|
||||
widget.set_text(field.value)
|
||||
|
||||
elif field.type == 'text-multi':
|
||||
# TODO: bigger text view
|
||||
commonwidget = False
|
||||
|
||||
textwidget = gtk.TextView()
|
||||
textwidget.set_wrap_mode(gtk.WRAP_WORD)
|
||||
textwidget.get_buffer().connect('changed', self.on_text_multi_textbuffer_changed,
|
||||
field)
|
||||
if field.value is None:
|
||||
field.value = u''
|
||||
textwidget.get_buffer().set_text(field.value)
|
||||
|
||||
widget = gtk.ScrolledWindow()
|
||||
widget.add(textwidget)
|
||||
|
||||
self.attach(widget, 1, 2, linecounter, linecounter+1)
|
||||
|
||||
else:# field.type == 'text-single' or field.type is nonstandard:
|
||||
# JEP says that if we don't understand some type, we
|
||||
# should handle it as text-single
|
||||
widget = gtk.Entry()
|
||||
widget.connect('changed', self.on_text_single_entry_changed, field)
|
||||
if field.value is None:
|
||||
field.value = u''
|
||||
widget.set_text(field.value)
|
||||
|
||||
if commonlabel and field.label is not None:
|
||||
label = gtk.Label(field.label)
|
||||
label.set_alignment(1.0, 0.5)
|
||||
self.attach(label, 0, 1, linecounter, linecounter+1,
|
||||
xoptions=gtk.FILL, yoptions=gtk.FILL)
|
||||
|
||||
if commonwidget:
|
||||
assert widget is not None
|
||||
self.attach(widget, 1, 2, linecounter, linecounter+1,
|
||||
yoptions=gtk.FILL)
|
||||
widget.show_all()
|
||||
|
||||
if commondesc and field.description is not None:
|
||||
label = gtk.Label()
|
||||
label.set_markup('<small>'+\
|
||||
gtkgui_helpers.escape_for_pango_markup(field.description)+\
|
||||
'</small>')
|
||||
label.set_line_wrap(True)
|
||||
self.attach(label, 2, 3, linecounter, linecounter+1,
|
||||
xoptions=gtk.FILL|gtk.SHRINK, yoptions=gtk.FILL|gtk.SHRINK)
|
||||
|
||||
linecounter+=1
|
||||
if self.get_property('visible'):
|
||||
self.show_all()
|
||||
|
||||
def show(self):
|
||||
# simulate that we are one widget
|
||||
self.show_all()
|
||||
|
||||
def on_boolean_checkbutton_toggled(self, widget, field):
|
||||
field.value = widget.get_active()
|
||||
|
||||
def on_list_single_radiobutton_toggled(self, widget, field, value):
|
||||
field.value = value
|
||||
|
||||
def on_list_multi_checkbutton_toggled(self, widget, field, value):
|
||||
# TODO: make some methods like add_value and remove_value
|
||||
if widget.get_active() and value not in field.value:
|
||||
field.value += [value]
|
||||
elif not widget.get_active() and value in field.value:
|
||||
field.value = [v for v in field.value if v!=value]
|
||||
|
||||
def on_text_single_entry_changed(self, widget, field):
|
||||
field.value = widget.get_text()
|
||||
|
||||
def on_text_multi_textbuffer_changed(self, widget, field):
|
||||
field.value = widget.get_text(
|
||||
widget.get_start_iter(),
|
||||
widget.get_end_iter())
|
||||
|
||||
def on_jid_multi_cellrenderertext_edited(self, cell, path, newtext, model, field):
|
||||
old=model[path][0]
|
||||
model[path][0]=newtext
|
||||
|
||||
values = field.value
|
||||
values[values.index(old)]=newtext
|
||||
field.value = values
|
||||
|
||||
def on_jid_multi_add_button_clicked(self, widget, treeview, model, field):
|
||||
iter = model.insert(999999, ("new@jabber.id",))
|
||||
treeview.set_cursor(model.get_path(iter), treeview.get_column(0), True)
|
||||
field.value = field.value + ["new@jabber.id"]
|
||||
|
||||
def on_jid_multi_edit_button_clicked(self, widget, treeview):
|
||||
model, iter = treeview.get_selection().get_selected()
|
||||
assert iter is not None
|
||||
|
||||
treeview.set_cursor(model.get_path(iter), treeview.get_column(0), True)
|
||||
|
||||
def on_jid_multi_remove_button_clicked(self, widget, treeview, field):
|
||||
selection = treeview.get_selection()
|
||||
model = treeview.get_model()
|
||||
deleted = []
|
||||
|
||||
def remove(model, path, iter, deleted):
|
||||
deleted+=model[iter]
|
||||
model.remove(iter)
|
||||
|
||||
selection.selected_foreach(remove, deleted)
|
||||
field.value = (v for v in field.value if v not in deleted)
|
||||
|
||||
def on_jid_multi_clean_button_clicked(self, widget, model, field):
|
||||
model.clear()
|
||||
del field.value
|
Loading…
Reference in New Issue