# # Window with progress bars in :-, # import gtk import threading class ProgressOutput(gtk.HBox): def __init__(self, progress_win, user): gtk.HBox.__init__(self) self.bar = gtk.ProgressBar() self.pack_start(self.bar) self.bar.show() self.bar.set_fraction(0.0) self.bar.set_text("") #button = gtk.Button(_("Abort")) #self.pack_start(button) #button.connect("clicked", self.set_abort) #button.show() self.progress_win = progress_win self.lock = threading.Lock() # Update these thingy periodically self.log_messages = [] self.bar_message = None self.bar_position = None self.done = 0 self.enabled = None self.do_abort = 0 user.timeout_add (self.timeout_update) def abort(self): return self.do_abort def set_abort(self, _button=None): print "Attempt progress abort" self.do_abort = 1 def timeout_update(self, user): self.lock.acquire() # Bar greyed out if self.enabled != None: self.bar.set_sensitive(self.enabled) self.enabled = None # Print pending log messages while len(self.log_messages) != 0: self.progress_win.msg_print(self.log_messages[0]) del self.log_messages[0] if self.bar_position != None: self.bar.set_fraction(self.bar_position) self.bar_position = None if self.bar_message != None: self.bar.set_text(self.bar_message) self.bar_message = None if self.done == 1: # No more update() calls user.timeout_remove (self.timeout_update) self.lock.release() def log_msg(self, msg): self.lock.acquire() self.log_messages.append(msg) self.lock.release() def bar_msg(self, msg): self.lock.acquire() self.bar_message = msg self.lock.release() def bar_pos(self, pos): self.lock.acquire() self.bar_position = pos self.lock.release() def bar_enable(self, toggle): self.lock.acquire() self.enabled = toggle self.lock.release() def finished(self): # call when you're finished using this progressbar self.lock.acquire() self.done = 1 self.lock.release() class ProgressWin: def silence_output(self, _a=None): # If threads continue to write stuff to the window # after the user has closed it we segfault. Prevent this. # There is probably a good way... like # window->dont_let_user_close_me = 1... self.window_closed = 1 def toggle_text(self, _a): if self.text_hidden == 1: self.swin.show() self.text_hidden = 0 else: self.swin.hide() self.text_hidden = 1 # window should contract self.win.queue_resize() def close(self, _a=None): self.silence_output() self.win.destroy() def __init__(self, title, user, hidetext=None, parent_win=None): """ Set hidetext to the desired label of button to show/hide text widget. """ self.user = user self.win = gtk.Dialog() self.win.set_title(title) self.win.connect("destroy", self.silence_output) if parent_win: self.win.set_transient_for (parent_win) self.win.vbox.set_spacing(5) self.win.vbox.set_border_width(5) self.window_closed = 0 self.win.action_area.set_border_width(0) button_box = gtk.HBox(spacing=5) self.win.action_area.pack_start(button_box) button_box.show() self.close_button = gtk.Button(stock="gtk-close") self.close_button.connect("clicked", self.close) button_box.pack_end(self.close_button, expand=False) self.close_button.show() self.swin = gtk.ScrolledWindow() self.swin.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC) self.swin.set_shadow_type(gtk.SHADOW_IN) self.win.vbox.pack_end(self.swin) if hidetext == None: self.swin.show() self.text_hidden = 0 else: self.details_button = gtk.Button(" "+hidetext+" ") self.details_button.connect("clicked", self.toggle_text) button_box.pack_end(self.details_button, expand=False) self.details_button.show() self.text_hidden = 1 self.textview = gtk.TextView() self.textview.set_editable(False) self.textview.show() self.swin.add(self.textview) self.win.show() # XXX Strange bug(?) in gtk makes first line default colour # and therefore possibly invisible. self.msg_print("") def msg_print(self, message): """ Push a message onto the gtk.Text object. """ textbuffer = self.textview.get_buffer() iter = textbuffer.get_end_iter() if not self.window_closed: textbuffer.insert(iter, message+"\n") def get_progress_bar(self, thread=None): """ Returns a progress bar object. access it as you would normally and .destroy() it when done. If thread!=None a box will be available to kill the thread, too. This doesn't work. Threads can't be killed :-( """ bar = ProgressOutput(self, self.user) self.win.vbox.pack_start(bar, expand=False) bar.show() return bar