diff --git a/virtManager/addhardware.py b/virtManager/addhardware.py index 6a2ff926c..542eddb8f 100644 --- a/virtManager/addhardware.py +++ b/virtManager/addhardware.py @@ -893,37 +893,6 @@ class vmmAddHardware(vmmGObjectUI): notebook.get_nth_page(page).show() notebook.set_current_page(page) - def finish(self, ignore=None): - notebook = self.widget("create-pages") - try: - if self.validate(notebook.get_current_page()) is False: - return - except Exception, e: - self.err.show_err(_("Uncaught error validating hardware " - "input: %s") % str(e)) - return - - self.topwin.set_sensitive(False) - self.topwin.get_window().set_cursor(Gdk.Cursor.new(Gdk.CursorType.WATCH)) - - try: - failure, errinfo = self.add_device() - error, details = errinfo or (None, None) - except Exception, e: - failure = True - error = _("Unable to add device: %s") % str(e) - details = "".join(traceback.format_exc()) - - if error is not None: - self.err.show_err(error, details=details) - - self.topwin.set_sensitive(True) - self.topwin.get_window().set_cursor(Gdk.Cursor.new(Gdk.CursorType.TOP_LEFT_ARROW)) - - self._dev = None - if not failure: - self.close() - def show_pair_combo(self, basename, show_combo): combo = self.widget(basename + "-combo") label = self.widget(basename + "-label") @@ -1137,36 +1106,12 @@ class vmmAddHardware(vmmGObjectUI): # Add device methods # ###################### - def _storage_progress(self): - def do_file_allocate(asyncjob, disk): - meter = asyncjob.get_meter() - - logging.debug("Starting background file allocate process") - disk.setup(meter=meter) - logging.debug("Allocation completed") - - progWin = vmmAsyncJob(do_file_allocate, - [self._dev], - _("Creating Storage File"), - _("Allocation of disk storage may take " - "a few minutes to complete."), - self.topwin) - - return progWin.run() - - def setup_device(self): - if (self._dev.virtual_device_type == self._dev.VIRTUAL_DEV_DISK and - self._dev.creating_storage()): - return self._storage_progress() - - return self._dev.setup() + def setup_device(self, asyncjob): + logging.debug("Running setup for device=%s", self._dev) + self._dev.setup(meter=asyncjob.get_meter()) + logging.debug("Setup complete") def add_device(self): - ret = self.setup_device() - if ret and ret[0]: - # Encountered an error - return (True, ret) - self._dev.get_xml_config() logging.debug("Adding device:\n" + self._dev.get_xml_config()) @@ -1197,7 +1142,7 @@ class vmmAddHardware(vmmGObjectUI): modal=True) if not res: - return (False, None) + return False # Alter persistent config try: @@ -1206,9 +1151,52 @@ class vmmAddHardware(vmmGObjectUI): self.vm.add_device(self._dev) except Exception, e: self.err.show_err(_("Error adding device: %s" % str(e))) - return (True, None) + return True - return (False, None) + return False + + def _finish_cb(self, error, details): + failure = True + if not error: + try: + failure = self.add_device() + except Exception, e: + failure = True + error = _("Unable to add device: %s") % str(e) + details = "".join(traceback.format_exc()) + + if error is not None: + self.err.show_err(error, details=details) + + self.topwin.set_sensitive(True) + self.topwin.get_window().set_cursor( + Gdk.Cursor.new(Gdk.CursorType.TOP_LEFT_ARROW)) + + self._dev = None + if not failure: + self.close() + + def finish(self, ignore=None): + notebook = self.widget("create-pages") + try: + if self.validate(notebook.get_current_page()) is False: + return + except Exception, e: + self.err.show_err(_("Uncaught error validating hardware " + "input: %s") % str(e)) + return + + self.topwin.set_sensitive(False) + self.topwin.get_window().set_cursor( + Gdk.Cursor.new(Gdk.CursorType.WATCH)) + + progWin = vmmAsyncJob(self.setup_device, [], + self._finish_cb, [], + _("Creating device"), + _("Depending on the device, this may take " + "a few minutes to complete."), + self.topwin) + progWin.run() ########################### diff --git a/virtManager/asyncjob.py b/virtManager/asyncjob.py index f152f2fa5..f0367d8f9 100644 --- a/virtManager/asyncjob.py +++ b/virtManager/asyncjob.py @@ -86,15 +86,6 @@ class vmmMeter(urlgrabber.progress.BaseMeter): self.started = False -# This thin wrapper only exists so we can put debugging -# code in the run() method every now & then -class asyncJobWorker(threading.Thread): - def __init__(self, callback, args): - args = [callback] + args - threading.Thread.__init__(self, target=cb_wrapper, args=args) - self.daemon = True - - def cb_wrapper(callback, asyncjob, *args, **kwargs): try: callback(asyncjob, *args, **kwargs) @@ -108,8 +99,22 @@ def cb_wrapper(callback, asyncjob, *args, **kwargs): asyncjob.set_error(str(e), "".join(traceback.format_exc())) +def _simple_async_done_cb(error, details, errorintro, + errorcb, parent, finish_cb): + if error: + if errorcb: + errorcb(error, details) + else: + error = errorintro + ": " + error + parent.err.show_err(error, + details=details) + + if finish_cb: + finish_cb() + + def _simple_async(callback, args, title, text, parent, errorintro, - show_progress, simplecb, errorcb): + show_progress, simplecb, errorcb, finish_cb): """ @show_progress: Whether to actually show a progress dialog @simplecb: If true, build a callback wrapper that ignores the asyncjob @@ -122,18 +127,12 @@ def _simple_async(callback, args, title, text, parent, errorintro, callback(*args, **kwargs) docb = tmpcb - asyncjob = vmmAsyncJob(docb, args, title, text, parent.topwin, + asyncjob = vmmAsyncJob(docb, args, + _simple_async_done_cb, + (errorintro, errorcb, parent, finish_cb), + title, text, parent.topwin, show_progress=show_progress) - error, details = asyncjob.run() - if error is None: - return - - if errorcb: - errorcb(error, details) - else: - error = errorintro + ": " + error - parent.err.show_err(error, - details=details) + asyncjob.run() def idle_wrapper(fn): @@ -148,18 +147,22 @@ class vmmAsyncJob(vmmGObjectUI): """ @staticmethod def simple_async(callback, args, title, text, parent, errorintro, - simplecb=True, errorcb=None): - _simple_async(callback, args, title, text, parent, errorintro, True, - simplecb, errorcb) + simplecb=True, errorcb=None, finish_cb=None): + _simple_async(callback, args, + title, text, parent, errorintro, True, + simplecb, errorcb, finish_cb) @staticmethod def simple_async_noshow(callback, args, parent, errorintro, - simplecb=True, errorcb=None): - _simple_async(callback, args, "", "", parent, errorintro, False, - simplecb, errorcb) + simplecb=True, errorcb=None, finish_cb=None): + _simple_async(callback, args, + "", "", parent, errorintro, False, + simplecb, errorcb, finish_cb) - def __init__(self, callback, args, title, text, parent, + def __init__(self, + callback, args, finish_cb, finish_args, + title, text, parent, show_progress=True, cancel_cb=None): """ @show_progress: If False, don't actually show a progress dialog @@ -175,15 +178,19 @@ class vmmAsyncJob(vmmGObjectUI): self.cancel_cb = cancel_cb[0] self.cancel_args = [self] + list(cancel_cb[1:]) self.job_canceled = False + self._finish_cb = finish_cb + self._finish_args = finish_args or () + self._timer = None self._error_info = None self._data = None self._is_pulsing = True self._meter = None - args = [self] + args - self._bg_thread = asyncJobWorker(callback, args) + self._bg_thread = threading.Thread(target=cb_wrapper, + args=[callback, self] + args) + self._bg_thread.daemon = True logging.debug("Creating async job for function cb=%s", callback) self.builder.connect_signals({ @@ -278,8 +285,19 @@ class vmmAsyncJob(vmmGObjectUI): self.widget("warning-box").show() self.widget("warning-text").set_markup(markup) + def _thread_finished(self): + GLib.source_remove(self._timer) + self.topwin.destroy() + self.cleanup() + + error = None + details = None + if self._error_info: + error, details = self._error_info + self._finish_cb(error, details, *self._finish_args) + def run(self): - timer = GLib.timeout_add(100, self._exit_if_necessary) + self._timer = GLib.timeout_add(100, self._exit_if_necessary) if self.show_progress: self.topwin.present() @@ -287,15 +305,7 @@ class vmmAsyncJob(vmmGObjectUI): if not self.cancel_cb and self.show_progress: self.topwin.get_window().set_cursor( Gdk.Cursor.new(Gdk.CursorType.WATCH)) - self._bg_thread.start() - Gtk.main() - - GLib.source_remove(timer) - - self.topwin.destroy() - self.cleanup() - return self._error_info or (None, None) #################################################################### @@ -306,7 +316,7 @@ class vmmAsyncJob(vmmGObjectUI): def _exit_if_necessary(self): if not self._bg_thread.is_alive(): - Gtk.main_quit() + self._thread_finished() return False if not self._is_pulsing or not self.show_progress: diff --git a/virtManager/clone.py b/virtManager/clone.py index 9e20c51a4..96d57a020 100644 --- a/virtManager/clone.py +++ b/virtManager/clone.py @@ -783,6 +783,19 @@ class vmmCloneVM(vmmGObjectUI): self.clone_design = cd return True + def _finish_cb(self, error, details): + self.topwin.set_sensitive(True) + self.topwin.get_window().set_cursor( + Gdk.Cursor.new(Gdk.CursorType.TOP_LEFT_ARROW)) + + if error is not None: + error = (_("Error creating virtual machine clone '%s': %s") % + (self.clone_design.clone_name, error)) + self.err.show_err(error, details=details) + else: + self.close() + self.conn.schedule_priority_tick(pollvm=True) + def finish(self, src_ignore): try: if not self.validate(): @@ -792,7 +805,8 @@ class vmmCloneVM(vmmGObjectUI): return self.topwin.set_sensitive(False) - self.topwin.get_window().set_cursor(Gdk.Cursor.new(Gdk.CursorType.WATCH)) + self.topwin.get_window().set_cursor( + Gdk.Cursor.new(Gdk.CursorType.WATCH)) title = (_("Creating virtual machine clone '%s'") % self.clone_design.clone_name) @@ -800,19 +814,9 @@ class vmmCloneVM(vmmGObjectUI): if self.clone_design.clone_disks: text = title + _(" and selected storage (this may take a while)") - progWin = vmmAsyncJob(self._async_clone, [], title, text, self.topwin) - error, details = progWin.run() - - self.topwin.set_sensitive(True) - self.topwin.get_window().set_cursor(Gdk.Cursor.new(Gdk.CursorType.TOP_LEFT_ARROW)) - - if error is not None: - error = (_("Error creating virtual machine clone '%s': %s") % - (self.clone_design.clone_name, error)) - self.err.show_err(error, details=details) - else: - self.close() - self.conn.schedule_priority_tick(pollvm=True) + progWin = vmmAsyncJob(self._async_clone, [], self._finish_cb, [], + title, text, self.topwin) + progWin.run() def _async_clone(self, asyncjob): try: diff --git a/virtManager/create.py b/virtManager/create.py index c3fe51eca..c80243ceb 100644 --- a/virtManager/create.py +++ b/virtManager/create.py @@ -1778,6 +1778,12 @@ class vmmCreate(vmmGObjectUI): break pagenum = self._get_next_pagenum(pagenum) + def _undo_finish_cursor(self): + self.topwin.set_sensitive(True) + self.topwin.get_window().set_cursor( + Gdk.Cursor.new(Gdk.CursorType.TOP_LEFT_ARROW)) + + def finish(self, src_ignore): # Validate the final page page = self.widget("create-pages").get_current_page() @@ -1792,25 +1798,15 @@ class vmmCreate(vmmGObjectUI): self.topwin.set_sensitive(False) self.topwin.get_window().set_cursor(Gdk.Cursor.new(Gdk.CursorType.WATCH)) - def start_install(): - if not self.get_config_customize(): - self.start_install(guest) + if self.get_config_customize(): + try: + self.customize(guest) + except Exception, e: + self._undo_finish_cursor() + self.err.show_err(_("Error starting installation: ") + str(e)) return - - self.customize(guest) - - self._check_start_error(start_install) - - def _undo_finish(self, ignore=None): - self.topwin.set_sensitive(True) - self.topwin.get_window().set_cursor(Gdk.Cursor.new(Gdk.CursorType.TOP_LEFT_ARROW)) - - def _check_start_error(self, cb, *args, **kwargs): - try: - cb(*args, **kwargs) - except Exception, e: - self._undo_finish() - self.err.show_err(_("Error starting installation: ") + str(e)) + else: + self.start_install(guest) def customize(self, guest): virtinst_guest = vmmDomainVirtinst(self.conn, guest, self.guest.uuid) @@ -1826,11 +1822,11 @@ class vmmCreate(vmmGObjectUI): cleanup_config_window() if not self.is_visible(): return - self._check_start_error(self.start_install, guest) + self.start_install(guest) def details_closed(ignore): cleanup_config_window() - self._undo_finish() + self._undo_finish_cursor() self.widget("summary-customize").set_active(False) cleanup_config_window() @@ -1845,19 +1841,8 @@ class vmmCreate(vmmGObjectUI): details_closed)) self.config_window.show() - def start_install(self, guest): - progWin = vmmAsyncJob(self.do_install, [guest], - _("Creating Virtual Machine"), - _("The virtual machine is now being " - "created. Allocation of disk storage " - "and retrieval of the installation " - "images may take a few minutes to " - "complete."), - self.topwin) - error, details = progWin.run() - - self.topwin.set_sensitive(True) - self.topwin.get_window().set_cursor(Gdk.Cursor.new(Gdk.CursorType.TOP_LEFT_ARROW)) + def _install_finished_cb(self, error, details): + self._undo_finish_cursor() if error: error = (_("Unable to complete install: '%s'") % error) @@ -1869,7 +1854,20 @@ class vmmCreate(vmmGObjectUI): self.close() # Launch details dialog for new VM - self.emit("action-show-vm", self.conn.get_uri(), guest.uuid) + self.emit("action-show-vm", self.conn.get_uri(), self.guest.uuid) + + + def start_install(self, guest): + progWin = vmmAsyncJob(self.do_install, [guest], + self._install_finished_cb, [], + _("Creating Virtual Machine"), + _("The virtual machine is now being " + "created. Allocation of disk storage " + "and retrieval of the installation " + "images may take a few minutes to " + "complete."), + self.topwin) + progWin.run() def do_install(self, asyncjob, guest): meter = asyncjob.get_meter() diff --git a/virtManager/createinterface.py b/virtManager/createinterface.py index 093480bff..e7ca6411a 100644 --- a/virtManager/createinterface.py +++ b/virtManager/createinterface.py @@ -1096,27 +1096,10 @@ class vmmCreateInterface(vmmGObjectUI): # Creation routines # ##################### - def finish(self, src): - - # Validate the final page - page = self.widget("pages").get_current_page() - if self.validate(page) is not True: - return False - - activate = self.widget("interface-activate").get_active() - - # Start the install - self.topwin.set_sensitive(False) - self.topwin.get_window().set_cursor(Gdk.Cursor.new(Gdk.CursorType.WATCH)) - - progWin = vmmAsyncJob(self.do_install, [activate], - _("Creating virtual interface"), - _("The virtual interface is now being created."), - self.topwin) - error, details = progWin.run() - + def _finish_cb(self, error, details): self.topwin.set_sensitive(True) - self.topwin.get_window().set_cursor(Gdk.Cursor.new(Gdk.CursorType.TOP_LEFT_ARROW)) + self.topwin.get_window().set_cursor( + Gdk.Cursor.new(Gdk.CursorType.TOP_LEFT_ARROW)) if error: error = _("Error creating interface: '%s'") % error @@ -1126,6 +1109,26 @@ class vmmCreateInterface(vmmGObjectUI): self.conn.schedule_priority_tick(polliface=True) self.close() + def finish(self, src): + # Validate the final page + page = self.widget("pages").get_current_page() + if self.validate(page) is not True: + return False + + activate = self.widget("interface-activate").get_active() + + # Start the install + self.topwin.set_sensitive(False) + self.topwin.get_window().set_cursor( + Gdk.Cursor.new(Gdk.CursorType.WATCH)) + + progWin = vmmAsyncJob(self.do_install, [activate], + self._finish_cb, [], + _("Creating virtual interface"), + _("The virtual interface is now being created."), + self.topwin) + progWin.run() + def do_install(self, asyncjob, activate): meter = asyncjob.get_meter() self.interface.install(meter, create=activate) diff --git a/virtManager/createpool.py b/virtManager/createpool.py index fd9f805a2..dac436c2c 100644 --- a/virtManager/createpool.py +++ b/virtManager/createpool.py @@ -432,20 +432,10 @@ class vmmCreatePool(vmmGObjectUI): self.widget("pool-forward").show() self.widget("pool-pages").prev_page() - def finish(self): - self.topwin.set_sensitive(False) - self.topwin.get_window().set_cursor(Gdk.Cursor.new(Gdk.CursorType.WATCH)) - build = self.widget("pool-build").get_active() - - progWin = vmmAsyncJob(self._async_pool_create, [build], - _("Creating storage pool..."), - _("Creating the storage pool may take a " - "while..."), - self.topwin) - error, details = progWin.run() - + def _finish_cb(self, error, details): self.topwin.set_sensitive(True) - self.topwin.get_window().set_cursor(Gdk.Cursor.new(Gdk.CursorType.TOP_LEFT_ARROW)) + self.topwin.get_window().set_cursor( + Gdk.Cursor.new(Gdk.CursorType.TOP_LEFT_ARROW)) if error: error = _("Error creating pool: %s") % error @@ -455,6 +445,20 @@ class vmmCreatePool(vmmGObjectUI): self.conn.schedule_priority_tick(pollpool=True) self.close() + def finish(self): + self.topwin.set_sensitive(False) + self.topwin.get_window().set_cursor( + Gdk.Cursor.new(Gdk.CursorType.WATCH)) + build = self.widget("pool-build").get_active() + + progWin = vmmAsyncJob(self._async_pool_create, [build], + self._finish_cb, [], + _("Creating storage pool..."), + _("Creating the storage pool may take a " + "while..."), + self.topwin) + progWin.run() + def _async_pool_create(self, asyncjob, build): meter = asyncjob.get_meter() diff --git a/virtManager/createvol.py b/virtManager/createvol.py index 857b15365..0ba9f0893 100644 --- a/virtManager/createvol.py +++ b/virtManager/createvol.py @@ -217,6 +217,20 @@ class vmmCreateVolume(vmmGObjectUI): if cap < alloc: alloc_widget.set_value(cap) + def _finish_cb(self, error, details): + self.topwin.set_sensitive(True) + self.topwin.get_window().set_cursor( + Gdk.Cursor.new(Gdk.CursorType.TOP_LEFT_ARROW)) + + if error: + error = _("Error creating vol: %s") % error + self.show_err(error, + details=details) + else: + # vol-created will refresh the parent pool + self.emit("vol-created") + self.close() + def finish(self, src_ignore): try: if not self.validate(): @@ -229,26 +243,16 @@ class vmmCreateVolume(vmmGObjectUI): self.vol.get_xml_config()) self.topwin.set_sensitive(False) - self.topwin.get_window().set_cursor(Gdk.Cursor.new(Gdk.CursorType.WATCH)) + self.topwin.get_window().set_cursor( + Gdk.Cursor.new(Gdk.CursorType.WATCH)) progWin = vmmAsyncJob(self._async_vol_create, [], + self._finish_cb, [], _("Creating storage volume..."), _("Creating the storage volume may take a " "while..."), self.topwin) - error, details = progWin.run() - - self.topwin.set_sensitive(True) - self.topwin.get_window().set_cursor(Gdk.Cursor.new(Gdk.CursorType.TOP_LEFT_ARROW)) - - if error: - error = _("Error creating vol: %s") % error - self.show_err(error, - details=details) - else: - # vol-created will refresh the parent pool - self.emit("vol-created") - self.close() + progWin.run() def _async_vol_create(self, asyncjob): conn = self.conn.get_backend() diff --git a/virtManager/delete.py b/virtManager/delete.py index e11acb1ef..64ccdaf1e 100644 --- a/virtManager/delete.py +++ b/virtManager/delete.py @@ -131,6 +131,17 @@ class vmmDeleteDialog(vmmGObjectUI): paths.append(row[STORAGE_ROW_PATH]) return paths + def _finish_cb(self, error, details): + self.topwin.set_sensitive(True) + self.topwin.get_window().set_cursor( + Gdk.Cursor.new(Gdk.CursorType.TOP_LEFT_ARROW)) + + if error is not None: + self.err.show_err(error, details=details) + + self.conn.schedule_priority_tick(pollvm=True) + self.close() + def finish(self, src_ignore): devs = self.get_paths_to_delete() @@ -146,7 +157,8 @@ class vmmDeleteDialog(vmmGObjectUI): return self.topwin.set_sensitive(False) - self.topwin.get_window().set_cursor(Gdk.Cursor.new(Gdk.CursorType.WATCH)) + self.topwin.get_window().set_cursor( + Gdk.Cursor.new(Gdk.CursorType.WATCH)) title = _("Deleting virtual machine '%s'") % self.vm.get_name() text = title @@ -154,17 +166,9 @@ class vmmDeleteDialog(vmmGObjectUI): text = title + _(" and selected storage (this may take a while)") progWin = vmmAsyncJob(self._async_delete, [devs], + self._finish_cb, [], title, text, self.topwin) - error, details = progWin.run() - - self.topwin.set_sensitive(True) - self.topwin.get_window().set_cursor(Gdk.Cursor.new(Gdk.CursorType.TOP_LEFT_ARROW)) - - if error is not None: - self.err.show_err(error, details=details) - - self.conn.schedule_priority_tick(pollvm=True) - self.close() + progWin.run() def _async_delete(self, asyncjob, paths): storage_errors = [] diff --git a/virtManager/engine.py b/virtManager/engine.py index 3ae5b3de5..161860b4e 100644 --- a/virtManager/engine.py +++ b/virtManager/engine.py @@ -912,16 +912,17 @@ class vmmEngine(vmmGObject): def cb(asyncjob): vm.save(path, meter=asyncjob.get_meter()) + def finish_cb(error, details): + if error is not None: + error = _("Error saving domain: %s") % error + src.err.show_err(error, details=details) progWin = vmmAsyncJob(cb, [], + finish_cb, [], _("Saving Virtual Machine"), _("Saving virtual machine memory to disk "), src.topwin, cancel_cb=_cancel_cb) - error, details = progWin.run() - - if error is not None: - error = _("Error saving domain: %s") % error - src.err.show_err(error, details=details) + progWin.run() def _save_cancel(self, asyncjob, vm): logging.debug("Cancelling save job") diff --git a/virtManager/migrate.py b/virtManager/migrate.py index e68efea51..ef42516d1 100644 --- a/virtManager/migrate.py +++ b/virtManager/migrate.py @@ -443,6 +443,20 @@ class vmmMigrateDialog(vmmGObjectUI): return True + def _finish_cb(self, error, details, destconn): + self.topwin.set_sensitive(True) + self.topwin.get_window().set_cursor( + Gdk.Cursor.new(Gdk.CursorType.TOP_LEFT_ARROW)) + + if error: + error = _("Unable to migrate guest: %s") % error + self.err.show_err(error, + details=details) + else: + self.conn.schedule_priority_tick(pollvm=True) + destconn.schedule_priority_tick(pollvm=True) + self.close() + def finish(self, src_ignore): try: if not self.validate(): @@ -467,33 +481,22 @@ class vmmMigrateDialog(vmmGObjectUI): return self.topwin.set_sensitive(False) - self.topwin.get_window().set_cursor(Gdk.Cursor.new(Gdk.CursorType.WATCH)) + self.topwin.get_window().set_cursor( + Gdk.Cursor.new(Gdk.CursorType.WATCH)) cancel_cb = None if self.vm.getjobinfo_supported: cancel_cb = (self.cancel_migration, self.vm) - progWin = vmmAsyncJob(self._async_migrate, - [self.vm, destconn, uri, rate, live, secure, - max_downtime], - _("Migrating VM '%s'" % self.vm.get_name()), - (_("Migrating VM '%s' from %s to %s. " - "This may take a while.") % - (self.vm.get_name(), srchost, dsthost)), - self.topwin, cancel_cb=cancel_cb) - error, details = progWin.run() - - self.topwin.set_sensitive(True) - self.topwin.get_window().set_cursor(Gdk.Cursor.new(Gdk.CursorType.TOP_LEFT_ARROW)) - - if error: - error = _("Unable to migrate guest: %s") % error - self.err.show_err(error, - details=details) - else: - self.conn.schedule_priority_tick(pollvm=True) - destconn.schedule_priority_tick(pollvm=True) - self.close() + progWin = vmmAsyncJob( + self._async_migrate, + [self.vm, destconn, uri, rate, live, secure, max_downtime], + self._finish_cb, [destconn], + _("Migrating VM '%s'" % self.vm.get_name()), + (_("Migrating VM '%s' from %s to %s. This may take a while.") % + (self.vm.get_name(), srchost, dsthost)), + self.topwin, cancel_cb=cancel_cb) + progWin.run() def _async_set_max_downtime(self, vm, max_downtime, migrate_thread): if not migrate_thread.isAlive(): diff --git a/virtManager/snapshots.py b/virtManager/snapshots.py index ec2c50284..61884c515 100644 --- a/virtManager/snapshots.py +++ b/virtManager/snapshots.py @@ -261,6 +261,18 @@ class vmmSnapshotPage(vmmGObjectUI): # XXX refresh in place + def _finish_cb(self, error, details): + self.topwin.set_sensitive(True) + self.topwin.get_window().set_cursor( + Gdk.Cursor.new(Gdk.CursorType.TOP_LEFT_ARROW)) + + if error is not None: + error = _("Error creating snapshot: %s") % error + self.err.show_err(error, details=details) + return + + self._refresh_snapshots() + def _on_new_ok_clicked(self, ignore): name = self.widget("snapshot-new-name").get_text() @@ -278,21 +290,11 @@ class vmmSnapshotPage(vmmGObjectUI): progWin = vmmAsyncJob( lambda ignore, xml: self.vm.create_snapshot(xml), [newsnap.get_xml_config()], + self._finish_cb, [], _("Creating snapshot"), _("Creating virtual machine snapshot"), self.topwin) - - error, details = progWin.run() - self.topwin.set_sensitive(True) - self.topwin.get_window().set_cursor( - Gdk.Cursor.new(Gdk.CursorType.TOP_LEFT_ARROW)) - - if error is not None: - error = _("Error creating snapshot: %s") % error - self.err.show_err(error, details=details) - return - - self._refresh_snapshots() + progWin.run() def _on_add_clicked(self, ignore): snap = self._get_current_snapshot() @@ -327,8 +329,8 @@ class vmmSnapshotPage(vmmGObjectUI): vmmAsyncJob.simple_async_noshow(self.vm.revert_to_snapshot, [snap], self, _("Error reverting to snapshot '%s'") % - snap.get_name()) - self._refresh_snapshots() + snap.get_name(), + finish_cb=self._refresh_snapshots) def _on_delete_clicked(self, ignore): snap = self._get_current_snapshot() @@ -346,8 +348,8 @@ class vmmSnapshotPage(vmmGObjectUI): logging.debug("Deleting snapshot '%s'", snap.get_name()) vmmAsyncJob.simple_async_noshow(snap.delete, [], self, - _("Error deleting snapshot '%s'") % snap.get_name()) - self._refresh_snapshots() + _("Error deleting snapshot '%s'") % snap.get_name(), + finish_cb=self._refresh_snapshots) def _snapshot_selected(self, selection):