Invoking commands works. It will be a long way to finish it, though...
As long as the responder uses only text-single, list-single and boolean fields, it is possible to invoke and complete a command. Other field types are not implemented now in dataforms.py.
This commit is contained in:
		
							parent
							
								
									ce9cbe6f21
								
							
						
					
					
						commit
						ecc0403981
					
				
					 3 changed files with 351 additions and 134 deletions
				
			
		| 
						 | 
				
			
			@ -251,14 +251,13 @@
 | 
			
		|||
	  </child>
 | 
			
		||||
 | 
			
		||||
	  <child>
 | 
			
		||||
	    <widget class="GtkVBox" id="form_vbox">
 | 
			
		||||
	    <widget class="GtkTable" id="form_table">
 | 
			
		||||
	      <property name="visible">True</property>
 | 
			
		||||
	      <property name="n_rows">1</property>
 | 
			
		||||
	      <property name="n_columns">3</property>
 | 
			
		||||
	      <property name="homogeneous">False</property>
 | 
			
		||||
	      <property name="spacing">0</property>
 | 
			
		||||
 | 
			
		||||
	      <child>
 | 
			
		||||
		<placeholder/>
 | 
			
		||||
	      </child>
 | 
			
		||||
	      <property name="row_spacing">0</property>
 | 
			
		||||
	      <property name="column_spacing">0</property>
 | 
			
		||||
	    </widget>
 | 
			
		||||
	    <packing>
 | 
			
		||||
	      <property name="padding">0</property>
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -30,6 +30,7 @@ import common.xmpp as xmpp
 | 
			
		|||
import common.gajim as gajim
 | 
			
		||||
 | 
			
		||||
import gtkgui_helpers
 | 
			
		||||
import dataforms
 | 
			
		||||
 | 
			
		||||
class CommandWindow:
 | 
			
		||||
	'''Class for a window for single ad-hoc commands session. Note, that
 | 
			
		||||
| 
						 | 
				
			
			@ -49,6 +50,11 @@ class CommandWindow:
 | 
			
		|||
		self.pulse_id=None	# to satisfy self.setup_pulsing()
 | 
			
		||||
		self.commandlist=None	# a list of (commandname, commanddescription)
 | 
			
		||||
 | 
			
		||||
		# command's data
 | 
			
		||||
		self.commandnode = None
 | 
			
		||||
		self.sessionid = None
 | 
			
		||||
		self.dataform = None
 | 
			
		||||
 | 
			
		||||
		# retrieving widgets from xml
 | 
			
		||||
		self.xml = gtkgui_helpers.get_glade('adhoc_commands_window.glade')
 | 
			
		||||
		self.window = self.xml.get_widget('adhoc_commands_window')
 | 
			
		||||
| 
						 | 
				
			
			@ -56,10 +62,15 @@ class CommandWindow:
 | 
			
		|||
			'execute_button','stages_notebook',
 | 
			
		||||
			'retrieving_commands_stage_vbox',
 | 
			
		||||
			'command_list_stage_vbox','command_list_vbox',
 | 
			
		||||
			'sending_form_stage_vbox','no_commands_stage_vbox',
 | 
			
		||||
			'error_stage_vbox', 'error_description_label'):
 | 
			
		||||
			'sending_form_stage_vbox','sending_form_progressbar',
 | 
			
		||||
			'no_commands_stage_vbox','error_stage_vbox',
 | 
			
		||||
			'error_description_label'):
 | 
			
		||||
			self.__dict__[name] = self.xml.get_widget(name)
 | 
			
		||||
 | 
			
		||||
		# creating data forms widget
 | 
			
		||||
		self.data_form_widget = dataforms.DataFormWidget()
 | 
			
		||||
		self.sending_form_stage_vbox.pack_start(self.data_form_widget)
 | 
			
		||||
 | 
			
		||||
		# setting initial stage
 | 
			
		||||
		self.stage1()
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -74,12 +85,32 @@ class CommandWindow:
 | 
			
		|||
 | 
			
		||||
# these functions are set up by appropriate stageX methods
 | 
			
		||||
	def stage_finish(self, *anything): pass
 | 
			
		||||
	def on_cancel_button_clicked(self, *anything): pass
 | 
			
		||||
	def on_back_button_clicked(self, *anything): pass
 | 
			
		||||
	def on_forward_button_clicked(self, *anything): pass
 | 
			
		||||
	def on_execute_button_clicked(self, *anything): pass
 | 
			
		||||
	def on_adhoc_commands_window_destroy(self, *anything): pass
 | 
			
		||||
	def do_nothing(self, *anything): pass
 | 
			
		||||
	def stage_cancel_button_clicked(self, *anything): assert False
 | 
			
		||||
	def stage_back_button_clicked(self, *anything): assert False
 | 
			
		||||
	def stage_forward_button_clicked(self, *anything): assert False
 | 
			
		||||
	def stage_execute_button_clicked(self, *anything): assert False
 | 
			
		||||
	def stage_adhoc_commands_window_destroy(self, *anything): assert False
 | 
			
		||||
	def stage_adhoc_commands_window_delete_event(self, *anything): assert False
 | 
			
		||||
	def do_nothing(self, *anything): return False
 | 
			
		||||
 | 
			
		||||
# widget callbacks
 | 
			
		||||
	def on_cancel_button_clicked(self, *anything):
 | 
			
		||||
		return self.stage_cancel_button_clicked(*anything)
 | 
			
		||||
 | 
			
		||||
	def on_back_button_clicked(self, *anything):
 | 
			
		||||
		return self.stage_back_button_clicked(*anything)
 | 
			
		||||
 | 
			
		||||
	def on_forward_button_clicked(self, *anything):
 | 
			
		||||
		return self.stage_forward_button_clicked(*anything)
 | 
			
		||||
 | 
			
		||||
	def on_execute_button_clicked(self, *anything):
 | 
			
		||||
		return self.stage_execute_button_clicked(*anything)
 | 
			
		||||
 | 
			
		||||
	def on_adhoc_commands_window_destroy(self, *anything):
 | 
			
		||||
		return self.stage_adhoc_commands_window_destroy(*anything)
 | 
			
		||||
 | 
			
		||||
	def on_adhoc_commands_window_delete_event(self, *anything):
 | 
			
		||||
		return self.stage_adhoc_commands_window_delete_event(self, *anything)
 | 
			
		||||
 | 
			
		||||
# stage 1: waiting for command list
 | 
			
		||||
	def stage1(self):
 | 
			
		||||
| 
						 | 
				
			
			@ -106,17 +137,23 @@ class CommandWindow:
 | 
			
		|||
 | 
			
		||||
		# setup the callbacks
 | 
			
		||||
		self.stage_finish = self.stage1_finish
 | 
			
		||||
		self.on_cancel_button_clicked = self.stage1_on_cancel_button_clicked
 | 
			
		||||
		self.stage_cancel_button_clicked = self.stage1_cancel_button_clicked
 | 
			
		||||
		self.stage_adhoc_commands_window_delete_event = self.stage1_adhoc_commands_window_delete_event
 | 
			
		||||
		self.stage_adhoc_commands_window_destroy = self.do_nothing
 | 
			
		||||
 | 
			
		||||
	def stage1_finish(self):
 | 
			
		||||
		self.remove_pulsing()
 | 
			
		||||
 | 
			
		||||
	def stage1_on_cancel_button_clicked(self, widget):
 | 
			
		||||
	def stage1_cancel_button_clicked(self, widget):
 | 
			
		||||
		# cancelling in this stage is not critical, so we don't
 | 
			
		||||
		# show any popups to user
 | 
			
		||||
		self.stage1_finish()
 | 
			
		||||
		self.window.destroy()
 | 
			
		||||
 | 
			
		||||
	def stage1_adhoc_commands_window_delete_event(self, widget):
 | 
			
		||||
		self.stage1_finish()
 | 
			
		||||
		return True
 | 
			
		||||
 | 
			
		||||
# stage 2: choosing the command to execute
 | 
			
		||||
	def stage2(self):
 | 
			
		||||
		'''Populate the command list vbox with radiobuttons
 | 
			
		||||
| 
						 | 
				
			
			@ -140,30 +177,115 @@ class CommandWindow:
 | 
			
		|||
		first_radio = None
 | 
			
		||||
		for (commandnode, commandname) in self.commandlist:
 | 
			
		||||
			radio = gtk.RadioButton(first_radio, label=commandname)
 | 
			
		||||
			if first_radio is None: first_radio = radio
 | 
			
		||||
			radio.connect("toggled", self.on_command_radiobutton_toggled, commandnode)
 | 
			
		||||
			if first_radio is None:
 | 
			
		||||
				first_radio = radio
 | 
			
		||||
				self.commandnode = commandnode
 | 
			
		||||
			self.command_list_vbox.pack_end(radio, expand=False)
 | 
			
		||||
		self.command_list_vbox.show_all()
 | 
			
		||||
 | 
			
		||||
		self.stage_finish = self.stage2_finish
 | 
			
		||||
		self.on_cancel_button_clicked = self.stage2_on_cancel_button_clicked
 | 
			
		||||
		self.on_forward_button_clicked = self.stage2_on_forward_button_clicked
 | 
			
		||||
		self.stage_cancel_button_clicked = self.stage2_cancel_button_clicked
 | 
			
		||||
		self.stage_forward_button_clicked = self.stage2_forward_button_clicked
 | 
			
		||||
		self.stage_adhoc_commands_window_destroy = self.do_nothing
 | 
			
		||||
		self.stage_adhoc_commands_window_delete_event = self.do_nothing
 | 
			
		||||
 | 
			
		||||
	def stage2_finish(self):
 | 
			
		||||
		'''Remove widgets we created.'''
 | 
			
		||||
		'''Remove widgets we created. Not needed when the window is destroyed.'''
 | 
			
		||||
		def remove_widget(widget):
 | 
			
		||||
			self.command_list_vbox.remove(widget)
 | 
			
		||||
		self.command_list_vbox.foreach(remove_widget)
 | 
			
		||||
 | 
			
		||||
	def stage2_on_cancel_button_clicked(self):
 | 
			
		||||
	def stage2_cancel_button_clicked(self, widget):
 | 
			
		||||
		self.stage_finish()
 | 
			
		||||
		self.window.destroy()
 | 
			
		||||
 | 
			
		||||
	def stage2_on_forward_button_clicked(self):
 | 
			
		||||
		pass
 | 
			
		||||
	def stage2_forward_button_clicked(self, widget):
 | 
			
		||||
		self.stage3()
 | 
			
		||||
 | 
			
		||||
	def on_command_radiobutton_toggled(self, widget, commandnode):
 | 
			
		||||
		self.commandnode = commandnode
 | 
			
		||||
 | 
			
		||||
	def on_check_commands_1_button_clicked(self, widget):
 | 
			
		||||
		self.stage1()
 | 
			
		||||
 | 
			
		||||
# stage 3: command invocation
 | 
			
		||||
	def stage3(self):
 | 
			
		||||
		# close old stage
 | 
			
		||||
		self.stage_finish()
 | 
			
		||||
 | 
			
		||||
		assert isinstance(self.commandnode, unicode)
 | 
			
		||||
 | 
			
		||||
		self.stages_notebook.set_current_page(
 | 
			
		||||
			self.stages_notebook.page_num(
 | 
			
		||||
				self.sending_form_stage_vbox))
 | 
			
		||||
 | 
			
		||||
		self.cancel_button.set_sensitive(True)
 | 
			
		||||
		self.back_button.set_sensitive(False)
 | 
			
		||||
		self.forward_button.set_sensitive(False)
 | 
			
		||||
		self.execute_button.set_sensitive(False)
 | 
			
		||||
 | 
			
		||||
		self.stage3_submit_form()
 | 
			
		||||
 | 
			
		||||
		self.stage_finish = self.stage3_finish
 | 
			
		||||
		self.stage_cancel_button_clicked = self.stage3_cancel_button_clicked
 | 
			
		||||
		self.stage_back_button_clicked = self.stage3_back_button_clicked
 | 
			
		||||
		self.stage_forward_button_clicked = self.stage3_forward_button_clicked
 | 
			
		||||
		self.stage_execute_button_clicked = self.stage3_execute_button_clicked
 | 
			
		||||
		self.stage_adhoc_commands_window_destroy = self.do_nothing
 | 
			
		||||
		self.stage_adhoc_commands_window_delete_event = self.do_nothing
 | 
			
		||||
 | 
			
		||||
	def stage3_finish(self):
 | 
			
		||||
		pass
 | 
			
		||||
 | 
			
		||||
	def stage3_cancel_button_clicked(self, widget):
 | 
			
		||||
		pass
 | 
			
		||||
 | 
			
		||||
	def stage3_back_button_clicked(self, widget):
 | 
			
		||||
		self.stage3_submit_form('prev')
 | 
			
		||||
 | 
			
		||||
	def stage3_forward_button_clicked(self, widget):
 | 
			
		||||
		self.stage3_submit_form('next')
 | 
			
		||||
 | 
			
		||||
	def stage3_execute_button_clicked(self, widget):
 | 
			
		||||
		self.stage3_submit_form('execute')
 | 
			
		||||
 | 
			
		||||
	def stage3_submit_form(self, action='execute'):
 | 
			
		||||
		self.data_form_widget.set_sensitive(False)
 | 
			
		||||
		if self.data_form_widget.get_data_form() is None:
 | 
			
		||||
			self.data_form_widget.hide()
 | 
			
		||||
		self.sending_form_progressbar.show()
 | 
			
		||||
		self.setup_pulsing(self.sending_form_progressbar)
 | 
			
		||||
		self.send_command(action)
 | 
			
		||||
 | 
			
		||||
	def stage3_next_form(self, command):
 | 
			
		||||
		assert isinstance(command, xmpp.Node)
 | 
			
		||||
 | 
			
		||||
		self.remove_pulsing()
 | 
			
		||||
		self.sending_form_progressbar.hide()
 | 
			
		||||
 | 
			
		||||
		self.sessionid = command.getAttr('sessionid')
 | 
			
		||||
 | 
			
		||||
		self.dataform = xmpp.DataForm(node=command.getTag('x'))
 | 
			
		||||
 | 
			
		||||
		self.data_form_widget.show()
 | 
			
		||||
		self.data_form_widget.set_sensitive(True)
 | 
			
		||||
		self.data_form_widget.set_data_form(self.dataform)
 | 
			
		||||
 | 
			
		||||
		action = command.getTag('action')
 | 
			
		||||
		if action is None:
 | 
			
		||||
			# no action tag? that's last stage...
 | 
			
		||||
			self.cancel_button.set_sensitive(False)
 | 
			
		||||
			self.back_button.set_sensitive(False)
 | 
			
		||||
			self.forward_button.set_sensitive(False)
 | 
			
		||||
			self.execute_button.set_sensitive(True)
 | 
			
		||||
		else:
 | 
			
		||||
			# actions, actions, actions...
 | 
			
		||||
			self.cancel_button.set_sensitive(False)
 | 
			
		||||
			self.back_button.set_sensitive(action.getTag('prev') is not None)
 | 
			
		||||
			self.forward_button.set_sensitive(action.getTag('next') is not None)
 | 
			
		||||
			self.execute_button.set_sensitive(True)
 | 
			
		||||
 | 
			
		||||
# stage 4: no commands are exposed
 | 
			
		||||
	def stage4(self):
 | 
			
		||||
		'''Display the message. Wait for user to close the window'''
 | 
			
		||||
| 
						 | 
				
			
			@ -180,9 +302,11 @@ class CommandWindow:
 | 
			
		|||
		self.execute_button.set_sensitive(False)
 | 
			
		||||
 | 
			
		||||
		self.stage_finish = self.do_nothing
 | 
			
		||||
		self.on_cancel_button_clicked = self.stage4_on_cancel_button_clicked
 | 
			
		||||
		self.stage_cancel_button_clicked = self.stage4_cancel_button_clicked
 | 
			
		||||
		self.stage_adhoc_commands_window_destroy = self.do_nothing
 | 
			
		||||
		self.stage_adhoc_commands_window_delete_event = self.do_nothing
 | 
			
		||||
 | 
			
		||||
	def stage4_on_cancel_button_clicked(self):
 | 
			
		||||
	def stage4_cancel_button_clicked(self, widget):
 | 
			
		||||
		self.window.destroy()
 | 
			
		||||
 | 
			
		||||
	def on_check_commands_2_button_clicked(self, widget):
 | 
			
		||||
| 
						 | 
				
			
			@ -208,9 +332,11 @@ class CommandWindow:
 | 
			
		|||
		self.error_description_label.set_text(error)
 | 
			
		||||
 | 
			
		||||
		self.stage_finish = self.do_nothing
 | 
			
		||||
		self.on_cancel_button_clicked = self.stage5_on_cancel_button_clicked
 | 
			
		||||
		self.stage_cancel_button_clicked = self.stage5_cancel_button_clicked
 | 
			
		||||
		self.stage_adhoc_commands_window_destroy = self.do_nothing
 | 
			
		||||
		self.stage_adhoc_commands_window_delete_event = self.do_nothing
 | 
			
		||||
 | 
			
		||||
	def stage5_on_cancel_button_clicked(self):
 | 
			
		||||
	def stage5_cancel_button_clicked(self, widget):
 | 
			
		||||
		self.window.destroy()
 | 
			
		||||
 | 
			
		||||
# helpers to handle pulsing in progressbar
 | 
			
		||||
| 
						 | 
				
			
			@ -261,3 +387,30 @@ class CommandWindow:
 | 
			
		|||
				self.stage2()
 | 
			
		||||
 | 
			
		||||
		self.account.connection.SendAndCallForResponse(query, callback)
 | 
			
		||||
 | 
			
		||||
	def send_command(self, action='execute'):
 | 
			
		||||
		'''Send the command with data form. Wait for reply.'''
 | 
			
		||||
		# create the stanza
 | 
			
		||||
		assert isinstance(self.commandnode, unicode)
 | 
			
		||||
		assert action in ('execute', 'prev', 'next', 'complete')
 | 
			
		||||
 | 
			
		||||
		stanza = xmpp.Iq(typ='set', to=self.jid)
 | 
			
		||||
		cmdnode = stanza.addChild('command', attrs={
 | 
			
		||||
				'xmlns':xmpp.NS_COMMANDS,
 | 
			
		||||
				'node':self.commandnode,
 | 
			
		||||
				'action':action
 | 
			
		||||
			})
 | 
			
		||||
 | 
			
		||||
		if self.sessionid is not None:
 | 
			
		||||
			cmdnode.setAttr('sessionid', self.sessionid)
 | 
			
		||||
 | 
			
		||||
		if self.data_form_widget.data_form is not None:
 | 
			
		||||
			cmdnode.addChild(node=self.data_form_widget.filled_data_form())
 | 
			
		||||
 | 
			
		||||
		def callback(response):
 | 
			
		||||
			# TODO: error handling
 | 
			
		||||
			self.stage3_next_form(response.getTag('command'))
 | 
			
		||||
 | 
			
		||||
		print stanza
 | 
			
		||||
 | 
			
		||||
		self.account.connection.SendAndCallForResponse(stanza, callback)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										275
									
								
								src/dataforms.py
									
										
									
									
									
								
							
							
						
						
									
										275
									
								
								src/dataforms.py
									
										
									
									
									
								
							| 
						 | 
				
			
			@ -17,6 +17,9 @@
 | 
			
		|||
""" This module contains widget that can display data form (JEP-0004). """
 | 
			
		||||
 | 
			
		||||
import gtk
 | 
			
		||||
import gtkgui_helpers
 | 
			
		||||
 | 
			
		||||
import common.xmpp as xmpp
 | 
			
		||||
 | 
			
		||||
class DataFormWidget(gtk.Alignment):
 | 
			
		||||
# "public" interface
 | 
			
		||||
| 
						 | 
				
			
			@ -25,17 +28,21 @@ class DataFormWidget(gtk.Alignment):
 | 
			
		|||
		""" Create a widget. """
 | 
			
		||||
		gtk.Alignment.__init__(self)
 | 
			
		||||
 | 
			
		||||
		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.form = self.xml.get_widget('form_vbox')
 | 
			
		||||
		self.form = self.xml.get_widget('form_table')
 | 
			
		||||
 | 
			
		||||
		self.add(self.xml.get_widget('data_form_scrolledwindow')
 | 
			
		||||
		self.add(self.xml.get_widget('data_form_scrolledwindow'))
 | 
			
		||||
 | 
			
		||||
		self.set_data_form(dataform)
 | 
			
		||||
		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, xmpp.Node) or (dataform is None))
 | 
			
		||||
 | 
			
		||||
		if self._data_form is not None: self._cleanWidgets()
 | 
			
		||||
		self._data_form = dataform
 | 
			
		||||
		if self._data_form is not None: self._buildWidgets()
 | 
			
		||||
| 
						 | 
				
			
			@ -56,6 +63,39 @@ class DataFormWidget(gtk.Alignment):
 | 
			
		|||
		""" Treat 'us' as one widget. """
 | 
			
		||||
		self.show_all()
 | 
			
		||||
 | 
			
		||||
	def filled_data_form(self):
 | 
			
		||||
		""" Generates form that contains values filled by user. This
 | 
			
		||||
		won't be DataForm object, as the DataFields seem to be uncapable
 | 
			
		||||
		of some things. """
 | 
			
		||||
		assert isinstance(self._data_form, xmpp.DataForm)
 | 
			
		||||
 | 
			
		||||
		form = xmpp.Node('x', {'xmlns':xmpp.NS_DATA, 'type':'submit'})
 | 
			
		||||
		for field in self._data_form.kids:
 | 
			
		||||
			if not isinstance(field, xmpp.DataField): continue
 | 
			
		||||
			
 | 
			
		||||
			ftype = field.getType()
 | 
			
		||||
			if ftype not in ('boolean', 'fixed', 'hidden', 'jid-multi',
 | 
			
		||||
				'jid-single', 'list-multi', 'list-single',
 | 
			
		||||
				'text-multi', 'text-private', 'text-single'):
 | 
			
		||||
				ftype = 'text-single'
 | 
			
		||||
 | 
			
		||||
			if ftype in ('fixed',):
 | 
			
		||||
				continue
 | 
			
		||||
 | 
			
		||||
			newfield = xmpp.Node('field', {'var': field.getVar()})
 | 
			
		||||
 | 
			
		||||
			if ftype in ('jid-multi', 'list-multi', 'text-multi'):
 | 
			
		||||
				for value in field.getValues():
 | 
			
		||||
					newvalue = xmpp.Node('value', {}, [value])
 | 
			
		||||
					newfield.addChild(node=newvalue)
 | 
			
		||||
			else:
 | 
			
		||||
				newvalue = xmpp.Node('value', {}, [field.getValue()])
 | 
			
		||||
				newfield.addChild(node=newvalue)
 | 
			
		||||
 | 
			
		||||
			form.addChild(node=newfield)
 | 
			
		||||
 | 
			
		||||
		return form
 | 
			
		||||
 | 
			
		||||
	data_form = property(get_data_form, set_data_form, None, "Data form presented in a widget")
 | 
			
		||||
	title = property(get_title, None, None, "Data form title")
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -64,99 +104,131 @@ class DataFormWidget(gtk.Alignment):
 | 
			
		|||
		""" Create all sub-widgets according to self._data_form and
 | 
			
		||||
		JEP-0004. """
 | 
			
		||||
		assert self._data_form is not None
 | 
			
		||||
		assert length(self.form.get_children())==0
 | 
			
		||||
		assert len(self.form.get_children())==0
 | 
			
		||||
 | 
			
		||||
		# it is *very* often used here
 | 
			
		||||
		df = self._data_form
 | 
			
		||||
 | 
			
		||||
		if df.has_key('instructions'):
 | 
			
		||||
			self.instructions.set_text(df['instructions'])
 | 
			
		||||
		instructions = df.getInstructions()
 | 
			
		||||
		if instructions is not None:
 | 
			
		||||
			self.instructions.set_text(instructions)
 | 
			
		||||
 | 
			
		||||
		i = -1
 | 
			
		||||
		while df.has_key(i+1):
 | 
			
		||||
			i += 1
 | 
			
		||||
			if not df[i].has_key['type']:
 | 
			
		||||
				continue
 | 
			
		||||
		linecounter = 0
 | 
			
		||||
 | 
			
		||||
			ctype = df[i]['type']
 | 
			
		||||
			if ctype = 'hidden':
 | 
			
		||||
				continue
 | 
			
		||||
		for field in df.kids:
 | 
			
		||||
			if not isinstance(field, xmpp.DataField): continue
 | 
			
		||||
 | 
			
		||||
			hbox = gtk.HBox(spacing = 5)
 | 
			
		||||
			label = gtk.Label('')
 | 
			
		||||
			label.set_line_wrap(True)
 | 
			
		||||
			label.set_alignment(0.0, 0.5)
 | 
			
		||||
			label.set_property('width_request', 150)
 | 
			
		||||
			hbox.pack_start(label, False)
 | 
			
		||||
			if df[i].has_key('label'):
 | 
			
		||||
				label.set_text(df[i]['label'])
 | 
			
		||||
			if ctype == 'boolean':
 | 
			
		||||
				desc = None
 | 
			
		||||
				if df[i].has_key('desc'):
 | 
			
		||||
					desc = df[i]['desc']
 | 
			
		||||
				widget = gtk.CheckButton(desc, False)
 | 
			
		||||
				activ = False
 | 
			
		||||
				if df[i].has_key('values'):
 | 
			
		||||
					activ = df[i]['values'][0]
 | 
			
		||||
				widget.set_active(activ)
 | 
			
		||||
				widget.connect('toggled', self.on_checkbutton_toggled, i)
 | 
			
		||||
			elif ctype == 'fixed':
 | 
			
		||||
				widget = gtk.Label('\n'.join(df[i]['values']))
 | 
			
		||||
			# TODO: rewrite that when xmpp.DataField will be rewritten
 | 
			
		||||
			ftype = field.getType()
 | 
			
		||||
			if ftype not in ('boolean', 'fixed', 'hidden', 'jid-multi',
 | 
			
		||||
				'jid-single', 'list-multi', 'list-single',
 | 
			
		||||
				'text-multi', 'text-private', 'text-single'):
 | 
			
		||||
				ftype = 'text-single'
 | 
			
		||||
 | 
			
		||||
			if ftype == 'hidden': continue
 | 
			
		||||
 | 
			
		||||
			# field label
 | 
			
		||||
			flabel = field.getAttr('label')
 | 
			
		||||
			if flabel is None:
 | 
			
		||||
				flabel = field.getVar()
 | 
			
		||||
 | 
			
		||||
			# field description
 | 
			
		||||
			fdesc = field.getDesc()
 | 
			
		||||
 | 
			
		||||
			# field value (if one)
 | 
			
		||||
			fvalue = field.getValue()
 | 
			
		||||
 | 
			
		||||
			# field values (if one or more)
 | 
			
		||||
			fvalues = field.getValues()
 | 
			
		||||
 | 
			
		||||
			# field options
 | 
			
		||||
			foptions = field.getOptions()
 | 
			
		||||
 | 
			
		||||
			commonlabel = True
 | 
			
		||||
			commondesc = True
 | 
			
		||||
			commonwidget = True
 | 
			
		||||
 | 
			
		||||
			if ftype == 'boolean':
 | 
			
		||||
				widget = gtk.CheckButton()
 | 
			
		||||
				widget.connect('toggled', self.on_boolean_checkbutton_toggled, field)
 | 
			
		||||
				if fvalue in ('1', 'true'):
 | 
			
		||||
					widget.set_active(True)
 | 
			
		||||
				else:
 | 
			
		||||
					field.setValue('0')
 | 
			
		||||
 | 
			
		||||
			elif ftype == 'fixed':
 | 
			
		||||
				leftattach = 1
 | 
			
		||||
				rightattach = 2
 | 
			
		||||
				if flabel is None:
 | 
			
		||||
					commonlabel = False
 | 
			
		||||
					leftattach = 0
 | 
			
		||||
				if fdesc is None:
 | 
			
		||||
					commondesc = False
 | 
			
		||||
					rightattach = 3
 | 
			
		||||
				commonwidget = False
 | 
			
		||||
				widget = gtk.Label(fvalue)
 | 
			
		||||
				widget.set_line_wrap(True)
 | 
			
		||||
				widget.set_alignment(0.0, 0.5)
 | 
			
		||||
			elif ctype == 'jid-multi':
 | 
			
		||||
				#FIXME
 | 
			
		||||
				widget = gtk.Label('')
 | 
			
		||||
			elif ctype == 'jid-single':
 | 
			
		||||
				#FIXME
 | 
			
		||||
				widget = gtk.Label('')
 | 
			
		||||
			elif ctype == 'list-multi':
 | 
			
		||||
				j = 0
 | 
			
		||||
				widget = gtk.Table(1, 1)
 | 
			
		||||
				while df[i]['options'].has_key(j):
 | 
			
		||||
					widget.resize(j + 1, 1)
 | 
			
		||||
					child = gtk.CheckButton(df[i]['options'][j]['label'],
 | 
			
		||||
						False)
 | 
			
		||||
					if df[i]['options'][j]['values'][0] in \
 | 
			
		||||
					df[i]['values']:
 | 
			
		||||
						child.set_active(True)
 | 
			
		||||
					child.connect('toggled', self.on_checkbutton_toggled2, i, j)
 | 
			
		||||
					widget.attach(child, 0, 1, j, j+1)
 | 
			
		||||
					j += 1
 | 
			
		||||
			elif ctype == 'list-single':
 | 
			
		||||
				widget = gtk.combo_box_new_text()
 | 
			
		||||
				widget.connect('changed', self.on_combobox_changed, i)
 | 
			
		||||
				index = 0
 | 
			
		||||
				j = 0
 | 
			
		||||
				while df[i]['options'].has_key(j):
 | 
			
		||||
					if df[i]['options'][j]['values'][0] == \
 | 
			
		||||
						df[i]['values'][0]:
 | 
			
		||||
						index = j
 | 
			
		||||
					widget.append_text(df[i]['options'][j]['label'])
 | 
			
		||||
					j += 1
 | 
			
		||||
				widget.set_active(index)
 | 
			
		||||
			elif ctype == 'text-multi':
 | 
			
		||||
				widget = gtk.TextView()
 | 
			
		||||
				widget.set_size_request(100, -1)
 | 
			
		||||
				widget.get_buffer().connect('changed', self.on_textbuffer_changed, \
 | 
			
		||||
					i)
 | 
			
		||||
				widget.get_buffer().set_text('\n'.join(df[i]['values']))
 | 
			
		||||
			elif ctype == 'text-private':
 | 
			
		||||
				self.form.attach(widget, leftattach, rightattach, linecounter, linecounter+1)
 | 
			
		||||
 | 
			
		||||
			elif ftype == 'jid-multi':
 | 
			
		||||
				widget = gtk.Label('jid-multi field')
 | 
			
		||||
 | 
			
		||||
			elif ftype == 'jid-single':
 | 
			
		||||
				widget = gtk.Label('jid-single field')
 | 
			
		||||
 | 
			
		||||
			elif ftype == 'list-multi':
 | 
			
		||||
				widget = gtk.Label('list-multi field')
 | 
			
		||||
 | 
			
		||||
			elif ftype == 'list-single':
 | 
			
		||||
				# TODO: When more than few choices, make a list
 | 
			
		||||
				widget = gtk.VBox()
 | 
			
		||||
				first_radio = None
 | 
			
		||||
				right_value = False
 | 
			
		||||
				for label, value in foptions:
 | 
			
		||||
					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
 | 
			
		||||
						first_value = value
 | 
			
		||||
					if value == fvalue:
 | 
			
		||||
						right_value = True
 | 
			
		||||
					widget.pack_end(radio, expand=False)
 | 
			
		||||
				if not right_value:
 | 
			
		||||
					field.setValue(first_value)
 | 
			
		||||
 | 
			
		||||
			elif ftype == 'text-multi':
 | 
			
		||||
				widget = gtk.Label('text-multi field')
 | 
			
		||||
 | 
			
		||||
			elif ftype == 'text-private':
 | 
			
		||||
				widget = gtk.Label('text-private field')
 | 
			
		||||
 | 
			
		||||
			elif ftype == 'text-single':
 | 
			
		||||
				widget = gtk.Entry()
 | 
			
		||||
				widget.connect('changed', self.on_entry_changed, i)
 | 
			
		||||
				if not df[i].has_key('values'):
 | 
			
		||||
					df[i]['values'] = ['']
 | 
			
		||||
				widget.set_text(df[i]['values'][0])
 | 
			
		||||
				widget.set_visibility(False)
 | 
			
		||||
			elif ctype == 'text-single':
 | 
			
		||||
				widget = gtk.Entry()
 | 
			
		||||
				widget.connect('changed', self.on_entry_changed, i)
 | 
			
		||||
				if not df[i].has_key('values'):
 | 
			
		||||
					df[i]['values'] = ['']
 | 
			
		||||
				widget.set_text(df[i]['values'][0])
 | 
			
		||||
			hbox.pack_start(widget, False)
 | 
			
		||||
			hbox.pack_start(gtk.Label('')) # So that widhet doesn't take all space
 | 
			
		||||
			self.form.pack_start(hbox, False)
 | 
			
		||||
				widget.connect('changed', self.on_text_single_entry_changed, field)
 | 
			
		||||
				if fvalue is None:
 | 
			
		||||
					field.setValue('')
 | 
			
		||||
					fvalue = ''
 | 
			
		||||
				widget.set_text(fvalue)
 | 
			
		||||
			
 | 
			
		||||
			else:
 | 
			
		||||
				widget = gtk.Label('Unhandled widget type!')
 | 
			
		||||
 | 
			
		||||
			if commonlabel and flabel is not None:
 | 
			
		||||
				label = gtk.Label(flabel)
 | 
			
		||||
				label.set_justify(gtk.JUSTIFY_RIGHT)
 | 
			
		||||
				self.form.attach(label, 0, 1, linecounter, linecounter+1)
 | 
			
		||||
 | 
			
		||||
			if commonwidget:
 | 
			
		||||
				self.form.attach(widget, 1, 2, linecounter, linecounter+1)
 | 
			
		||||
 | 
			
		||||
			if commondesc and fdesc is not None:
 | 
			
		||||
				label = gtk.Label(fdesc)
 | 
			
		||||
				label.set_line_wrap(True)
 | 
			
		||||
				self.form.attach(label, 2, 3, linecounter, linecounter+1)
 | 
			
		||||
 | 
			
		||||
			linecounter += 1
 | 
			
		||||
 | 
			
		||||
		self.form.show_all()
 | 
			
		||||
 | 
			
		||||
	def _cleanWidgets(self):
 | 
			
		||||
| 
						 | 
				
			
			@ -165,24 +237,17 @@ class DataFormWidget(gtk.Alignment):
 | 
			
		|||
			self.form.remove(widget)
 | 
			
		||||
 | 
			
		||||
		self.form.foreach(remove)
 | 
			
		||||
		self.instructions.set_text(u"")
 | 
			
		||||
 | 
			
		||||
	def on_checkbutton_toggled(self, widget, index):
 | 
			
		||||
		self.config[index]['values'][0] = widget.get_active()
 | 
			
		||||
	def on_boolean_checkbutton_toggled(self, widget, field):
 | 
			
		||||
		if widget.get_active():
 | 
			
		||||
			field.setValue('true')
 | 
			
		||||
		else:
 | 
			
		||||
			field.setValue('false')
 | 
			
		||||
 | 
			
		||||
	def on_checkbutton_toggled2(self, widget, index1, index2):
 | 
			
		||||
		val = self._data_form[index1]['options'][index2]['values'][0]
 | 
			
		||||
		if widget.get_active() and val not in self._data_form[index1]['values']:
 | 
			
		||||
			self._data_form[index1]['values'].append(val)
 | 
			
		||||
		elif not widget.get_active() and val in self._data_form[index1]['values']:
 | 
			
		||||
			self._data_form[index1]['values'].remove(val)
 | 
			
		||||
	def on_list_single_radiobutton_toggled(self, widget, field, value):
 | 
			
		||||
		field.setValue(value)
 | 
			
		||||
 | 
			
		||||
	def on_combobox_changed(self, widget, index):
 | 
			
		||||
		self._data_form[index]['values'][0] = self.config[index]['options'][ \
 | 
			
		||||
			widget.get_active()]['values'][0]
 | 
			
		||||
 | 
			
		||||
	def on_entry_changed(self, widget, index):
 | 
			
		||||
		self._data_form[index]['values'][0] = widget.get_text().decode('utf-8')
 | 
			
		||||
 | 
			
		||||
	def on_textbuffer_changed(self, widget, index):
 | 
			
		||||
		begin, end = widget.get_bounds()
 | 
			
		||||
		self._data_form[index]['values'][0] = widget.get_text(begin, end)
 | 
			
		||||
	def on_text_single_entry_changed(self, widget, field):
 | 
			
		||||
		# TODO: check for encoding?
 | 
			
		||||
		field.setValue(widget.get_text())
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		
		Reference in a new issue