diff options
author | Cole Robinson <crobinso@redhat.com> | 2013-06-14 11:04:01 -0400 |
---|---|---|
committer | Cole Robinson <crobinso@redhat.com> | 2013-06-14 11:18:12 -0400 |
commit | cdde7e1d9fe62288dafe835554cb22efc29f6851 (patch) | |
tree | 6722e48646a99a05662939a7a0f6f9be07975e24 | |
parent | 2b3604ceebbc807264142a733be7bc3c29a1ef5d (diff) | |
download | virt-manager-cdde7e1d9fe62288dafe835554cb22efc29f6851.tar.gz |
asyncjob: Some code reorg
Privatize a bunch of things, move code around to be grouped consistently.
-rw-r--r-- | virtManager/asyncjob.py | 190 |
1 files changed, 92 insertions, 98 deletions
diff --git a/virtManager/asyncjob.py b/virtManager/asyncjob.py index ac649825..8cca0b7b 100644 --- a/virtManager/asyncjob.py +++ b/virtManager/asyncjob.py @@ -92,10 +92,7 @@ class asyncJobWorker(threading.Thread): def __init__(self, callback, args): args = [callback] + args threading.Thread.__init__(self, target=cb_wrapper, args=args) - self.setDaemon(True) - - def run(self): - threading.Thread.run(self) + self.daemon = True def cb_wrapper(callback, asyncjob, *args, **kwargs): @@ -185,18 +182,16 @@ class vmmAsyncJob(vmmGObjectUI): self._error_info = None self._data = None - self.stage = self.widget("pbar-stage") - self.pbar = self.widget("pbar") - self.is_pulsing = True + self._is_pulsing = True self._meter = None args = [self] + args - self.bg_thread = asyncJobWorker(callback, args) + self._bg_thread = asyncJobWorker(callback, args) logging.debug("Creating async job for function cb=%s", callback) self.builder.connect_signals({ - "on_async_job_delete_event" : self.delete, - "on_async_job_cancel_clicked" : self.cancel, + "on_async_job_delete_event" : self._on_window_delete, + "on_async_job_cancel_clicked" : self._on_cancel, }) # UI state @@ -205,22 +200,61 @@ class vmmAsyncJob(vmmGObjectUI): self.widget("cancel-async-job").set_visible(bool(self.cancel_cb)) - ############# - # Accessors # - ############# + #################### + # Internal helpers # + #################### - def set_error(self, error, details): - self._error_info = (error, details) + def _cleanup(self): + self._bg_thread = None + self.cancel_cb = None + self.cancel_args = None + self._meter = None - def _get_error(self): - if not self._error_info: - return (None, None) - return self._error_info + def _set_stage_text(self, text, canceling=False): + # This should be thread safe, since it's only ever called from + # pbar idle callbacks and cancel routine which is invoked from the + # main thread + if self.job_canceled and not canceling: + return + self.widget("pbar-stage").set_text(text) + + def _hide_warning(self): + self.widget("warning-box").hide() + + def _is_thread_active(self): + return (self._bg_thread.isAlive() or not self.async) - def set_extra_data(self, data): - self._data = data - def get_extra_data(self): - return self._data + + ################ + # UI listeners # + ################ + + def _on_window_delete(self, ignore1=None, ignore2=None): + thread_active = (self._bg_thread.isAlive() or not self.async) + if not self.cancel_cb or not thread_active: + return + + res = self.err.warn_chkbox( + text1=_("Cancel the job before closing window?"), + buttons=Gtk.ButtonsType.YES_NO) + if not res: + return + + self._on_cancel() + + def _on_cancel(self, ignore1=None, ignore2=None): + if not self.cancel_cb or not self._is_thread_active(): + return + + self.cancel_cb(*self.cancel_args) + if self.job_canceled: + self._hide_warning() + self._set_stage_text(_("Cancelling job..."), canceling=True) + + + ############## + # Public API # + ############## def get_meter(self): if not self._meter: @@ -229,39 +263,25 @@ class vmmAsyncJob(vmmGObjectUI): self._pbar_done) return self._meter - def can_cancel(self): - return bool(self.cancel_cb) - - def _cleanup(self): - self.bg_thread = None - self.cancel_cb = None - self.cancel_args = None - self._meter = None - - #################### - # Internal helpers # - #################### + def set_error(self, error, details): + self._error_info = (error, details) - def set_stage_text(self, text, canceling=False): - if self.job_canceled and not canceling: - return - self.stage.set_text(text) + def set_extra_data(self, data): + self._data = data + def get_extra_data(self): + return self._data - def hide_warning(self): - self.widget("warning-box").hide() + def can_cancel(self): + return bool(self.cancel_cb) def show_warning(self, summary): + # This should only be called from cancel callbacks, not a the thread markup = "<small>%s</small>" % summary self.widget("warning-box").show() self.widget("warning-text").set_markup(markup) - - ########### - # Actions # - ########### - def run(self): - timer = GLib.timeout_add(100, self.exit_if_necessary) + timer = GLib.timeout_add(100, self._exit_if_necessary) if self.show_progress: self.topwin.present() @@ -271,90 +291,64 @@ class vmmAsyncJob(vmmGObjectUI): Gdk.Cursor.new(Gdk.CursorType.WATCH)) if self.async: - self.bg_thread.start() + self._bg_thread.start() Gtk.main() else: - self.bg_thread.run() + self._bg_thread.run() GLib.source_remove(timer) - if self.bg_thread.isAlive(): + if self._bg_thread.isAlive(): # This can happen if the user closes the whole app while the # async dialog is running. This forces us to clean up properly # and not leave a dead process around. logging.debug("Forcing main_quit from async job.") - self.exit_if_necessary(force_exit=True) + self._exit_if_necessary(force_exit=True) self.topwin.destroy() self.cleanup() - return self._get_error() - - def delete(self, ignore1=None, ignore2=None): - thread_active = (self.bg_thread.isAlive() or not self.async) - if not self.cancel_cb or not thread_active: - return - - res = self.err.warn_chkbox( - text1=_("Cancel the job before closing window?"), - buttons=Gtk.ButtonsType.YES_NO) - if not res: - return - - # The job may end after we click 'Yes', so check whether the - # thread is active again - thread_active = (self.bg_thread.isAlive() or not self.async) - if thread_active: - self.cancel() - - - def cancel(self, ignore1=None, ignore2=None): - if not self.cancel_cb: - return - - self.cancel_cb(*self.cancel_args) - if self.job_canceled: - self.hide_warning() - self.set_stage_text(_("Cancelling job..."), canceling=True) + return self._error_info or (None, None) - # All functions after this point are called from the timer loop - # which means we need to be careful and lock threads before doing - # any UI bits - def exit_if_necessary(self, force_exit=False): - thread_active = (self.bg_thread.isAlive() or not self.async) + #################################################################### + # All functions after this point are called from the timer loop or # + # the worker thread, so anything that touches Gtk needs to be # + # dispatches with idle_add # + #################################################################### - if not thread_active or force_exit: + def _exit_if_necessary(self, force_exit=False): + if not self._is_thread_active() or force_exit: if self.async: Gtk.main_quit() return False - if not self.is_pulsing or not self.show_progress: + if not self._is_pulsing or not self.show_progress: return True - self.idle_add(self.pbar.pulse) + self._pbar_pulse() return True @idle_wrapper def _pbar_pulse(self, progress="", stage=None): - self.is_pulsing = True - self.pbar.set_text(progress) - self.set_stage_text(stage or _("Processing...")) + self._is_pulsing = True + self.widget("pbar").set_text(progress) + self._set_stage_text(stage or _("Processing...")) @idle_wrapper def _pbar_fraction(self, frac, progress, stage=None): - self.is_pulsing = False - self.set_stage_text(stage or _("Processing...")) - self.pbar.set_text(progress) + self._is_pulsing = False + self._set_stage_text(stage or _("Processing...")) + self.widget("pbar").set_text(progress) if frac > 1: frac = 1.0 if frac < 0: frac = 0 - self.pbar.set_fraction(frac) + self.widget("pbar").set_fraction(frac) @idle_wrapper def _pbar_done(self, progress, stage=None): - self.is_pulsing = False - self.set_stage_text(stage or _("Completed")) - self.pbar.set_text(progress) - self.pbar.set_fraction(1) + self._is_pulsing = False + self._set_stage_text(stage or _("Completed")) + self.widget("pbar").set_text(progress) + self.widget("pbar").set_fraction(1) |