Fetching command list from entity now works.

If the entity has at least one command exposed, it will be displayed as
a radio button. Other changes: run python interpreter without optimalizations,
otherwise asserts doesn't work. Names of widgets in the glade file were
changed a bit.
This commit is contained in:
Tomasz Melcer 2006-06-23 14:38:54 +00:00
parent 23fa0bf8e6
commit 145cdbbf40
3 changed files with 159 additions and 18 deletions

View File

@ -17,6 +17,7 @@
<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>
<signal name="destroy" handler="on_adhoc_commands_window_destroy" last_modification_time="Thu, 22 Jun 2006 22:50:45 GMT"/>
<child>
<widget class="GtkVBox" id="vbox1">
@ -26,7 +27,7 @@
<property name="spacing">0</property>
<child>
<widget class="GtkNotebook" id="mode_notebook">
<widget class="GtkNotebook" id="stages_notebook">
<property name="visible">True</property>
<property name="show_tabs">False</property>
<property name="show_border">False</property>
@ -35,7 +36,7 @@
<property name="enable_popup">False</property>
<child>
<widget class="GtkVBox" id="vbox2">
<widget class="GtkVBox" id="retrieving_commands_stage_vbox">
<property name="visible">True</property>
<property name="homogeneous">False</property>
<property name="spacing">0</property>
@ -114,7 +115,7 @@
</child>
<child>
<widget class="GtkVBox" id="vbox5">
<widget class="GtkVBox" id="command_list_stage_vbox">
<property name="visible">True</property>
<property name="homogeneous">False</property>
<property name="spacing">0</property>
@ -187,7 +188,7 @@
</child>
<child>
<widget class="GtkVBox" id="vbox3">
<widget class="GtkVBox" id="sending_form_stage_vbox">
<property name="visible">True</property>
<property name="homogeneous">False</property>
<property name="spacing">0</property>
@ -314,7 +315,27 @@
</child>
<child>
<placeholder/>
<widget class="GtkLabel" id="label257">
<property name="visible">True</property>
<property name="label" translatable="yes">An error has occured.</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="tab_expand">False</property>
<property name="tab_fill">True</property>
</packing>
</child>
<child>

View File

@ -1,3 +1,3 @@
#!/bin/sh
cd `dirname $0`/src
exec python -OOt gajim.py $@
exec python -t gajim.py $@

View File

@ -19,9 +19,16 @@
## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
## GNU General Public License for more details.
# TODO: think if we need caching command list. it may be wrong if there will
# TODO: be entities that often change the list, it may be slow to fetch it
# TODO: every time
import gobject
import gtk
import common.xmpp as xmpp
import common.gajim as gajim
import gtkgui_helpers
class CommandWindow:
@ -35,45 +42,158 @@ class CommandWindow:
def __init__(self, account, jid):
'''Create new window.'''
self.pulse_id=None # to satisfy self..setup_pulsing()
# an account object
self.account = gajim.connections[account]
self.jid = jid
# connecting to handlers
self.pulse_id=None # to satisfy self.setup_pulsing()
self.commandlist=None # a list of (commandname, commanddescription)
# retrieving widgets from xml
self.xml = gtkgui_helpers.get_glade('adhoc_commands_window.glade')
self.window = self.xml.get_widget('adhoc_commands_window')
for name in ('cancel_button', 'back_button', 'forward_button',
'execute_button','stages_notebook',
'retrieving_commands_stage_vbox',
'command_list_stage_vbox','command_list_vbox',
'sending_form_stage_vbox'):
self.__dict__[name] = self.xml.get_widget(name)
# setting initial state of widgets
self.setup_pulsing(self.xml.get_widget('retrieving_commands_progressbar'))
# invoking disco to find commands
# setting initial stage
self.stage1()
# displaying the window
self.xml.signal_autoconnect(self)
self.window.show_all()
def on_adhoc_commands_window_destroy(self, window):
''' The window dissappeared somehow... clean the environment,
Stop pulsing.'''
self.remove_pulsing()
# 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
# stage 1: waiting for command list
def stage1(self):
'''Prepare the first stage. Request command list,
set appropriate state of widgets.'''
# close old stage...
self.stage_finish()
# show the stage
self.stages_notebook.set_current_page(
self.stages_notebook.page_num(
self.retrieving_commands_stage_vbox))
# set widgets' state
self.cancel_button.set_sensitive(True)
self.back_button.set_sensitive(False)
self.forward_button.set_sensitive(False)
self.execute_button.set_sensitive(False)
# request command list
self.request_command_list()
self.setup_pulsing(
self.xml.get_widget('retrieving_commands_progressbar'))
# setup the callbacks
self.stage_finish = self.stage1_finish
self.on_cancel_button_clicked = self.stage1_on_cancel_button_clicked
def stage1_finish(self):
self.remove_pulsing()
def stage1_on_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()
# stage 2: choosing the command to execute
def stage2(self):
'''Populate the command list vbox with radiobuttons
(TODO: if there is more commands, maybe some kind of list?),
set widgets' state.'''
# close old stage
self.stage_finish()
assert len(self.commandlist)>0
self.stages_notebook.set_current_page(
self.stages_notebook.page_num(
self.command_list_stage_vbox))
self.cancel_button.set_sensitive(True)
self.back_button.set_sensitive(False)
self.forward_button.set_sensitive(True)
self.execute_button.set_sensitive(False)
# build the commands list radiobuttons
first_radio = None
for (commandnode, commandname) in self.commandlist:
radio = gtk.RadioButton(first_radio, label=commandname)
if first_radio is None: first_radio = radio
self.command_list_vbox.pack_end(radio, expand=False)
self.command_list_vbox.show_all()
self.stage_finish = self.stage_finish
self.on_cancel_button_clicked = self.stage2_on_cancel_button_clicked
self.on_forward_button_clicked = self.stage2_on_forward_button_clicked
def stage2_on_cancel_button_clicked(self):
self.stage_finish()
self.window.destroy()
def stage2_on_forward_button_clicked(self):
pass
# helpers to handle pulsing in progressbar
def setup_pulsing(self, progressbar):
'''Useful to set the progressbar to pulse. Makes a custom
'''Set the progressbar to pulse. Makes a custom
function to repeatedly call progressbar.pulse() method.'''
assert self.pulse_id is None
assert isinstance(progressbar, Gtk.ProgressBar)
assert False
assert isinstance(progressbar, gtk.ProgressBar)
def callback():
progressbar.pulse()
return True # important to keep callback be called back!
# 12 times per second (40 miliseconds)
# 12 times per second (80 miliseconds)
self.pulse_id = gobject.timeout_add(80, callback)
progressbar.pulse() # start from now!
def remove_pulsing(self):
'''Useful to stop pulsing, especially when removing widget.'''
'''Stop pulsing, useful when especially when removing widget.'''
if self.pulse_id is not None:
gobject.source_remove(self.pulse_id)
self.pulse_id=None
# handling xml stanzas
def request_command_list(self):
'''Request the command list. Change stage on delivery.'''
query = xmpp.Iq(typ='get', to=xmpp.JID(self.jid), xmlns=xmpp.NS_DISCO_ITEMS)
query.setQuerynode(xmpp.NS_COMMANDS)
def callback(response):
'''Called on response to query.'''
# is error => error stage
error = response.getError()
if error is not None:
pass
# no commands => no commands stage
# commands => command selection stage
items = response.getTag('query').getTags('item')
if len(items)==0:
self.commandlist = []
self.stage2() # stageX, where X is the number for error page
else:
self.commandlist = [(t.getAttr('node'), t.getAttr('name')) for t in items]
self.stage2()
self.account.connection.SendAndCallForResponse(query, callback)