From ba505cf681ccb51f5500eaab1d720aef9f81103b Mon Sep 17 00:00:00 2001 From: David Soulayrol <david.soulayrol@gmail.com> Date: Wed, 17 Nov 2010 13:25:48 +0100 Subject: [PATCH] Added a ready status to the panes. --- wizpym.py | 55 ++++++++++++++++++++++++++++++++++++++++++------------- 1 file changed, 42 insertions(+), 13 deletions(-) diff --git a/wizpym.py b/wizpym.py index 1af7ce9..31342d1 100644 --- a/wizpym.py +++ b/wizpym.py @@ -60,15 +60,19 @@ class Pane(gtk.VBox): object that forwards data from one pane to the other and can be a simple string as well as a complex structure. It is initially set by the wizard Frame when the first pane is created. + + A pane can also state that it is not ready to fulfill the next + pane requirements. The frame will grey the Next button as long as + its ready attribute is set to False. """ def __init__(self, frame): """Constructor. - A fresh pane has no successors nor predecessor. The - constructor doesn't either set the subject: the wizard frame - takes care of setting it, and passing it from one pane to the - other. + A fresh pane is in a ready state and has no successors nor + predecessor. The constructor doesn't either set the subject: + the wizard frame takes care of setting it, and passing it from + one pane to the other. Note that all wizard panes constructors should take no parameter since they are called automatically by the wizard @@ -81,6 +85,7 @@ class Pane(gtk.VBox): self._subject = None self._switch = None self._successors = {} + self._ready = True def link_to(self, klass): """Add a successor to this pane. @@ -143,7 +148,15 @@ class Pane(gtk.VBox): def _set_subject(self, s): self._subject = s + def _is_ready(self): + return self._ready + + def _set_ready(self, v): + self._ready = v + self._frame.update() + subject = property(_get_subject, _set_subject, None, 'This pane subject') + ready = property(_is_ready, _set_ready, None, 'Whether the next pane can be called') class ActivePane(Pane): @@ -211,9 +224,11 @@ class Frame(gtk.Dialog): """ gtk.Dialog.__init__(self, title) - start_pane = start_klass(self) - start_pane.subject = subject - self._track = [start_pane] + # Members are all defined before calling the First pane so as + # to be ready if the start pane constructor invokes the frame + # (such as the ready attribute setting) + self._locked = False + self._track = [] self._prev_button = gtk.Button('Previous') self._prev_button.set_sensitive(False) @@ -230,6 +245,10 @@ class Frame(gtk.Dialog): self.connect('destroy', gtk.main_quit) self.connect("response", self._on_button) + start_pane = start_klass(self) + start_pane.subject = subject + self._track = [start_pane] + self._enter_pane(start_pane, True) def lock(self): @@ -238,8 +257,8 @@ class Frame(gtk.Dialog): This method is called by ActivePane instances when their background task is started. """ - self._prev_button.set_sensitive(False) - self._next_button.set_sensitive(False) + self._lock = True + self.update() def unlock(self): """Unfreeze the previous and next buttons. @@ -247,8 +266,19 @@ class Frame(gtk.Dialog): This method is called by ActivePane instances when their background task is terminated. """ - self._prev_button.set_sensitive(len(self._track) > 1) - self._next_button.set_sensitive(not self._track[-1].is_terminal()) + self._lock = False + self.update() + + def update(self): + """Update the frame buttons display.""" + # Beware that this method can be code early, before the track + # contains the first pane + if len(self._track): + pane = self._track[-1] + self._prev_button.set_sensitive( + not self._locked and len(self._track) > 1) + self._next_button.set_sensitive( + not self._locked and pane.ready and not pane.is_terminal()) def _on_button(self, w, response_id): """The frame buttons handler.""" @@ -270,8 +300,7 @@ class Frame(gtk.Dialog): """Handle a new pane display.""" if forward: pane.enter() - self._prev_button.set_sensitive(len(self._track) > 1) - self._next_button.set_sensitive(not pane.is_terminal()) + self.update() self.vbox.pack_start(self._track[-1], True, True) self.vbox.show_all()