diff --git a/src/ProgressDialog.py b/src/ProgressDialog.py index 72dbf3c09..047018e22 100644 --- a/src/ProgressDialog.py +++ b/src/ProgressDialog.py @@ -101,11 +101,12 @@ class GtkProgressDialog(gtk.Dialog): self.vbox.pack_start(pbar, expand=False, fill=False) pbar.show() - - self.resize_children() - self._process_events() + # this seems to cause an infinite loop: + #self.resize_children() self._progress_bars.append(pbar) + # This is a bad idea; could cause deletes while adding: + #self._process_events() return len(self._progress_bars)-1 def remove(self, pbar_idx): @@ -114,9 +115,10 @@ class GtkProgressDialog(gtk.Dialog): :param pbar_idx: the index as returned from L{add} :type pbar_idx: int """ - pbar = self._progress_bars[pbar_idx] - self.vbox.remove(pbar) - del self._progress_bars[pbar_idx] + if pbar_idx is not None: + pbar = self._progress_bars[pbar_idx] + self.vbox.remove(pbar) + del self._progress_bars[pbar_idx] def step(self, pbar_idx): """Click the progress bar over to the next value. Be paranoid @@ -158,31 +160,41 @@ if __name__ == '__main__': def test(a, b): d = ProgressMonitor(GtkProgressDialog) - s = LongOpStatus("Doing very long operation", 100, 10) + s = LongOpStatus("Doing very long operation", 100, 10, can_cancel=True) d.add_op(s) for i in xrange(0, 99): + if s.should_cancel(): + break time.sleep(0.1) if i == 30: t = LongOpStatus("doing a shorter one", 100, 10, can_cancel=True) d.add_op(t) for j in xrange(0, 99): + if s.should_cancel(): + t.cancel() + break if t.should_cancel(): break time.sleep(0.1) t.heartbeat() - t.end() + if not t.was_cancelled(): + t.end() if i == 60: t = LongOpStatus("doing another shorter one", 100, 10) d.add_op(t) for j in xrange(0, 99): + if s.should_cancel(): + t.cancel() + break time.sleep(0.1) t.heartbeat() t.end() s.heartbeat() - s.end() + if not s.was_cancelled(): + s.end() w = gtk.Window(gtk.WINDOW_TOPLEVEL) w.connect('destroy', gtk.main_quit) diff --git a/src/gui/utils.py b/src/gui/utils.py index 3773550a3..654f8b151 100644 --- a/src/gui/utils.py +++ b/src/gui/utils.py @@ -88,7 +88,8 @@ class ProgressMeter(object): MODE_FRACTION = 0 MODE_ACTIVITY = 1 - def __init__(self, title, header=''): + def __init__(self, title, header='', can_cancel=False, + cancel_callback=None): """ Specify the title and the current pass header. """ @@ -97,9 +98,18 @@ class ProgressMeter(object): self.__pbar_max = 100.0 self.__pbar_index = 0.0 self.__old_val = -1 + self.__can_cancel = can_cancel + self.__cancelled = False + if cancel_callback: + self.__cancel_callback = cancel_callback + else: + self.__cancel_callback = self.handle_cancel self.__dialog = gtk.Dialog() - self.__dialog.connect('delete_event', self.__warn) + if self.__can_cancel: + self.__dialog.connect('delete_event', self.__cancel_callback) + else: + self.__dialog.connect('delete_event', self.__warn) self.__dialog.set_has_separator(False) self.__dialog.set_title(title) self.__dialog.set_border_width(12) @@ -117,11 +127,32 @@ class ProgressMeter(object): self.__pbar = gtk.ProgressBar() self.__dialog.vbox.add(self.__pbar) + + if self.__can_cancel: + self.__dialog.set_size_request(350, 170) + self.__cancel_button = gtk.Button(stock=gtk.STOCK_CANCEL) + self.__cancel_button.connect('clicked', self.__cancel_callback) + self.__dialog.vbox.add(self.__cancel_button) self.__dialog.show_all() if header == '': self.__lbl.hide() + def handle_cancel(self, *args, **kwargs): + """ + Default cancel handler (if enabled). + """ + self.__cancel_button.set_sensitive(False) + self.__lbl.set_label(_("Cancelling...")) + self.__cancelled = True + + def get_cancelled(self): + """ + Returns cancelled setting. True if progress meter has been + cancelled. + """ + return self.__cancelled + def set_pass(self, header="", total=100, mode=MODE_FRACTION): """ Reset for another pass. Provide a new header and define number @@ -132,11 +163,13 @@ class ProgressMeter(object): self.__pbar_max = total self.__pbar_index = 0.0 - self.__lbl.set_text(header) - if header == '': - self.__lbl.hide() - else: - self.__lbl.show() + # If it is cancelling, don't overwite that message: + if not self.__cancelled: + self.__lbl.set_text(header) + if header == '': + self.__lbl.hide() + else: + self.__lbl.show() if self.__mode is ProgressMeter.MODE_FRACTION: self.__pbar.set_fraction(0.0) @@ -171,6 +204,8 @@ class ProgressMeter(object): while gtk.events_pending(): gtk.main_iteration() + return self.__cancelled + def set_header(self, text): self.__lbl.set_text(text) while gtk.events_pending():