From 145cdbbf406952e6b944785a5163ec13b6a2dc6c Mon Sep 17 00:00:00 2001 From: Tomasz Melcer Date: Fri, 23 Jun 2006 14:38:54 +0000 Subject: [PATCH] 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. --- data/glade/adhoc_commands_window.glade | 31 +++++- launch.sh | 2 +- src/adhoc_commands.py | 144 ++++++++++++++++++++++--- 3 files changed, 159 insertions(+), 18 deletions(-) diff --git a/data/glade/adhoc_commands_window.glade b/data/glade/adhoc_commands_window.glade index 25c068a39..1339776b9 100644 --- a/data/glade/adhoc_commands_window.glade +++ b/data/glade/adhoc_commands_window.glade @@ -17,6 +17,7 @@ GDK_WINDOW_TYPE_HINT_NORMAL GDK_GRAVITY_NORTH_WEST True + @@ -26,7 +27,7 @@ 0 - + True False False @@ -35,7 +36,7 @@ False - + True False 0 @@ -114,7 +115,7 @@ - + True False 0 @@ -187,7 +188,7 @@ - + True False 0 @@ -314,7 +315,27 @@ - + + True + An error has occured. + False + False + GTK_JUSTIFY_LEFT + False + False + 0.5 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + False + True + diff --git a/launch.sh b/launch.sh index e533dded4..29457c7c6 100755 --- a/launch.sh +++ b/launch.sh @@ -1,3 +1,3 @@ #!/bin/sh cd `dirname $0`/src -exec python -OOt gajim.py $@ +exec python -t gajim.py $@ diff --git a/src/adhoc_commands.py b/src/adhoc_commands.py index f87c1fb19..ec2b7b2b0 100644 --- a/src/adhoc_commands.py +++ b/src/adhoc_commands.py @@ -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)