diff --git a/src/virtManager/details.py b/src/virtManager/details.py
index 3303b8f9a..06d43c1ac 100644
--- a/src/virtManager/details.py
+++ b/src/virtManager/details.py
@@ -226,7 +226,7 @@ class vmmDetails(gobject.GObject):
"on_details_menu_run_activate": self.control_vm_run,
"on_details_menu_poweroff_activate": self.control_vm_shutdown,
"on_details_menu_reboot_activate": self.control_vm_reboot,
- "on_details_menu_save_activate": self.control_vm_save_domain,
+ "on_details_menu_save_activate": self.control_vm_save,
"on_details_menu_destroy_activate": self.control_vm_destroy,
"on_details_menu_pause_activate": self.control_vm_pause,
"on_details_menu_clone_activate": self.control_vm_clone,
@@ -374,7 +374,8 @@ class vmmDetails(gobject.GObject):
self.window.get_widget("control-shutdown"),
self.control_vm_shutdown,
self.control_vm_reboot,
- self.control_vm_destroy)
+ self.control_vm_destroy,
+ self.control_vm_save)
icon_name = self.config.get_shutdown_icon_name()
for name in ["details-menu-shutdown",
@@ -917,7 +918,7 @@ class vmmDetails(gobject.GObject):
def control_vm_console(self, src):
self.emit("action-show-console", self.vm.get_connection().get_uri(), self.vm.get_uuid())
- def control_vm_save_domain(self, src):
+ def control_vm_save(self, src):
self.emit("action-save-domain", self.vm.get_connection().get_uri(), self.vm.get_uuid())
def control_vm_destroy(self, src):
diff --git a/src/virtManager/engine.py b/src/virtManager/engine.py
index 33ec8191a..12e45eab3 100644
--- a/src/virtManager/engine.py
+++ b/src/virtManager/engine.py
@@ -471,6 +471,8 @@ class vmmEngine(gobject.GObject):
self.refresh_console(uri, uuid)
def _do_save_domain(self, src, uri, uuid):
self.save_domain(src, uri, uuid)
+ def _do_restore_domain(self, src, uri):
+ self.restore_domain(src, uri)
def _do_destroy_domain(self, src, uri, uuid):
self.destroy_domain(src, uri, uuid)
def _do_suspend_domain(self, src, uri, uuid):
@@ -520,6 +522,7 @@ class vmmEngine(gobject.GObject):
manager.connect("action-show-help", self._do_show_help)
manager.connect("action-exit-app", self._do_exit_app)
manager.connect("action-view-manager", self._do_show_manager)
+ manager.connect("action-restore-domain", self._do_restore_domain)
self.connections[uri]["windowHost"] = manager
self.connections[uri]["windowHost"].show()
@@ -601,6 +604,7 @@ class vmmEngine(gobject.GObject):
self.windowManager.connect("action-shutdown-domain", self._do_shutdown_domain)
self.windowManager.connect("action-reboot-domain", self._do_reboot_domain)
self.windowManager.connect("action-destroy-domain", self._do_destroy_domain)
+ self.windowManager.connect("action-save-domain", self._do_save_domain)
self.windowManager.connect("action-migrate-domain", self._do_migrate_domain)
self.windowManager.connect("action-clone-domain", self._do_clone_domain)
self.windowManager.connect("action-show-console", self._do_show_console)
@@ -752,6 +756,41 @@ class vmmEngine(gobject.GObject):
except Exception, e:
asyncjob.set_error(str(e), "".join(traceback.format_exc()))
+ def restore_domain(self, src, uri):
+ conn = self._lookup_connection(uri)
+ if conn.is_remote():
+ self.err.val_err(_("Restoring virtual machines over remote "
+ "connections is not yet supported"))
+ return
+
+ path = util.browse_local(src.window.get_widget("vmm-manager"),
+ _("Restore Virtual Machine"),
+ self.config, conn,
+ browse_reason=self.config.CONFIG_DIR_RESTORE)
+
+ if not path:
+ return
+
+ progWin = vmmAsyncJob(self.config, self.restore_saved_callback,
+ [path, conn], _("Restoring Virtual Machine"))
+ progWin.run()
+ error, details = progWin.get_error()
+
+ if error is not None:
+ self.err.show_err(error, details,
+ title=_("Error restoring domain"))
+
+ def restore_saved_callback(self, file_to_load, conn, asyncjob):
+ try:
+ newconn = util.dup_conn(self.config, conn,
+ return_conn_class=True)
+ newconn.restore(file_to_load)
+ except Exception, e:
+ err = (_("Error restoring domain '%s': %s") %
+ (file_to_load, str(e)))
+ details = "".join(traceback.format_exc())
+ asyncjob.set_error(err, details)
+
def destroy_domain(self, src, uri, uuid):
conn = self._lookup_connection(uri)
vm = conn.get_vm(uuid)
diff --git a/src/virtManager/host.py b/src/virtManager/host.py
index 5bd54db46..29f7ff1f5 100644
--- a/src/virtManager/host.py
+++ b/src/virtManager/host.py
@@ -48,6 +48,8 @@ class vmmHost(gobject.GObject):
gobject.TYPE_NONE, []),
"action-view-manager": (gobject.SIGNAL_RUN_FIRST,
gobject.TYPE_NONE, []),
+ "action-restore-domain": (gobject.SIGNAL_RUN_FIRST,
+ gobject.TYPE_NONE, (str,)),
}
def __init__(self, config, conn, engine):
self.__gobject_init__()
@@ -114,6 +116,7 @@ class vmmHost(gobject.GObject):
"on_menu_file_close_activate": self.close,
"on_vmm_host_delete_event": self.close,
+ "on_menu_restore_saved_activate": self.restore_domain,
"on_menu_help_contents_activate": self.show_help,
"on_net_add_clicked": self.add_network,
@@ -320,6 +323,9 @@ class vmmHost(gobject.GObject):
def view_manager(self, src):
self.emit("action-view-manager")
+ def restore_domain(self, src):
+ self.emit("action-restore-domain", self.conn.get_uri())
+
def exit_app(self, src):
self.emit("action-exit-app")
@@ -347,6 +353,7 @@ class vmmHost(gobject.GObject):
def conn_state_changed(self, ignore1=None):
state = (self.conn.get_state() == vmmConnection.STATE_ACTIVE)
+ self.window.get_widget("menu_file_restore_saved").set_sensitive(state)
self.window.get_widget("net-add").set_sensitive(state)
self.window.get_widget("pool-add").set_sensitive(state)
diff --git a/src/virtManager/manager.py b/src/virtManager/manager.py
index 72d8af3d0..ec3b799d7 100644
--- a/src/virtManager/manager.py
+++ b/src/virtManager/manager.py
@@ -23,12 +23,10 @@ import gtk
import gtk.glade
import logging
-import traceback
import virtManager.config as cfg
import virtManager.uihelpers as uihelpers
from virtManager.connection import vmmConnection
-from virtManager.asyncjob import vmmAsyncJob
from virtManager.error import vmmErrorDialog
from virtManager.delete import vmmDeleteDialog
from virtManager.graphwidgets import CellRendererSparkline
@@ -105,6 +103,8 @@ class vmmManager(gobject.GObject):
gobject.TYPE_NONE, (str, str)),
"action-destroy-domain": (gobject.SIGNAL_RUN_FIRST,
gobject.TYPE_NONE, (str, str)),
+ "action-save-domain": (gobject.SIGNAL_RUN_FIRST,
+ gobject.TYPE_NONE, (str, str)),
"action-connect": (gobject.SIGNAL_RUN_FIRST,
gobject.TYPE_NONE, [str]),
"action-show-help": (gobject.SIGNAL_RUN_FIRST,
@@ -165,7 +165,6 @@ class vmmManager(gobject.GObject):
"on_menu_file_add_connection_activate": self.new_connection,
"on_menu_file_quit_activate": self.exit_app,
"on_menu_file_close_activate": self.close,
- "on_menu_restore_saved_activate": self.restore_saved,
"on_vmm_close_clicked": self.close,
"on_vm_open_clicked": self.open_vm_console,
"on_vm_run_clicked": self.start_vm,
@@ -275,7 +274,8 @@ class vmmManager(gobject.GObject):
self.window.get_widget("vm-shutdown"),
self.poweroff_vm,
self.reboot_vm,
- self.destroy_vm)
+ self.destroy_vm,
+ self.save_vm)
tool = self.window.get_widget("vm-toolbar")
util.safe_set_prop(tool, "icon-size", gtk.ICON_SIZE_LARGE_TOOLBAR)
@@ -296,6 +296,7 @@ class vmmManager(gobject.GObject):
destroy_icon = build_icon(icon_name)
run_icon = build_stock(gtk.STOCK_MEDIA_PLAY)
pause_icon = build_stock(gtk.STOCK_MEDIA_PAUSE)
+ save_icon = build_stock(gtk.STOCK_SAVE)
resume_icon = build_stock(gtk.STOCK_MEDIA_PAUSE)
delete_icon = build_stock(gtk.STOCK_DELETE)
@@ -345,6 +346,16 @@ class vmmManager(gobject.GObject):
self.destroy_vm)
self.vmmenushutdown.add(self.vmmenushutdown_items["forcepoweroff"])
+ self.vmmenushutdown_items["sep"] = gtk.SeparatorMenuItem()
+ self.vmmenushutdown_items["sep"].show()
+ self.vmmenushutdown.add(self.vmmenushutdown_items["sep"])
+
+ self.vmmenushutdown_items["save"] = gtk.ImageMenuItem(_("Sa_ve"))
+ self.vmmenushutdown_items["save"].set_image(save_icon)
+ self.vmmenushutdown_items["save"].show()
+ self.vmmenushutdown_items["save"].connect("activate", self.save_vm)
+ self.vmmenushutdown.add(self.vmmenushutdown_items["save"])
+
self.vmmenu_items["hsep1"] = gtk.SeparatorMenuItem()
self.vmmenu_items["hsep1"].show()
self.vmmenu.add(self.vmmenu_items["hsep1"])
@@ -608,41 +619,6 @@ class vmmManager(gobject.GObject):
self.emit("action-show-console",
conn.get_uri(), self.vm.get_uuid())
- def restore_saved(self, src=None):
- conn = self.current_connection()
- if conn.is_remote():
- self.err.val_err(_("Restoring virtual machines over remote "
- "connections is not yet supported"))
- return
-
- path = util.browse_local(self.window.get_widget("vmm-manager"),
- _("Restore Virtual Machine"),
- self.config, conn,
- browse_reason=self.config.CONFIG_DIR_RESTORE)
-
- if not path:
- return
-
- progWin = vmmAsyncJob(self.config, self.restore_saved_callback,
- [path], _("Restoring Virtual Machine"))
- progWin.run()
- error, details = progWin.get_error()
-
- if error is not None:
- self.err.show_err(error, details,
- title=_("Error restoring domain"))
-
- def restore_saved_callback(self, file_to_load, asyncjob):
- try:
- newconn = util.dup_conn(self.config, self.current_connection(),
- return_conn_class=True)
- newconn.restore(file_to_load)
- except Exception, e:
- err = (_("Error restoring domain '%s': %s") %
- (file_to_load, str(e)))
- details = "".join(traceback.format_exc())
- asyncjob.set_error(err, details)
-
def do_delete(self, ignore=None):
conn = self.current_connection()
vm = self.current_vm()
@@ -719,6 +695,12 @@ class vmmManager(gobject.GObject):
self.emit("action-destroy-domain",
vm.get_connection().get_uri(), vm.get_uuid())
+ def save_vm(self, ignore):
+ vm = self.current_vm()
+ if vm is not None:
+ self.emit("action-save-domain",
+ vm.get_connection().get_uri(), vm.get_uuid())
+
def pause_vm(self, ignore):
vm = self.current_vm()
if vm is not None:
@@ -1004,7 +986,6 @@ class vmmManager(gobject.GObject):
else:
show_pause = bool(vm and vm.is_pauseable())
show_shutdown = bool(vm and vm.is_stoppable())
- restore = bool(conn and conn.get_state() == vmmConnection.STATE_ACTIVE)
self.window.get_widget("vm-open").set_sensitive(show_open)
self.window.get_widget("vm-run").set_sensitive(show_run)
@@ -1015,7 +996,6 @@ class vmmManager(gobject.GObject):
self.window.get_widget("menu_edit_details").set_sensitive(show_details)
self.window.get_widget("menu_host_details").set_sensitive(host_details)
self.window.get_widget("menu_edit_delete").set_sensitive(delete)
- self.window.get_widget("menu_file_restore_saved").set_sensitive(restore)
def popup_vm_menu_key(self, widget, event):
if gtk.gdk.keyval_name(event.keyval) != "Menu":
@@ -1065,6 +1045,7 @@ class vmmManager(gobject.GObject):
self.vmmenushutdown_items["poweroff"].set_sensitive(stop)
self.vmmenushutdown_items["reboot"].set_sensitive(stop)
self.vmmenushutdown_items["forcepoweroff"].set_sensitive(destroy)
+ self.vmmenushutdown_items["save"].set_sensitive(destroy)
self.vmmenu.popup(None, None, None, 0, event.time)
else:
# Pop up connection menu
diff --git a/src/virtManager/uihelpers.py b/src/virtManager/uihelpers.py
index 64a6e8b1c..9706d6738 100644
--- a/src/virtManager/uihelpers.py
+++ b/src/virtManager/uihelpers.py
@@ -595,7 +595,7 @@ def mediadev_set_default_selection(widget):
####################################################################
def build_shutdown_button_menu(config, widget, shutdown_cb, reboot_cb,
- destroy_cb):
+ destroy_cb, save_cb):
icon_name = config.get_shutdown_icon_name()
widget.set_icon_name(icon_name)
menu = gtk.Menu()
@@ -604,6 +604,7 @@ def build_shutdown_button_menu(config, widget, shutdown_cb, reboot_cb,
rebootimg = gtk.image_new_from_icon_name(icon_name, gtk.ICON_SIZE_MENU)
shutdownimg = gtk.image_new_from_icon_name(icon_name, gtk.ICON_SIZE_MENU)
destroyimg = gtk.image_new_from_icon_name(icon_name, gtk.ICON_SIZE_MENU)
+ saveimg = gtk.image_new_from_icon_name(gtk.STOCK_SAVE, gtk.ICON_SIZE_MENU)
reboot = gtk.ImageMenuItem(_("_Reboot"))
reboot.set_image(rebootimg)
@@ -623,6 +624,16 @@ def build_shutdown_button_menu(config, widget, shutdown_cb, reboot_cb,
destroy.connect("activate", destroy_cb)
menu.add(destroy)
+ sep = gtk.SeparatorMenuItem()
+ sep.show()
+ menu.add(sep)
+
+ save = gtk.ImageMenuItem(_("Sa_ve"))
+ save.set_image(saveimg)
+ save.show()
+ save.connect("activate", save_cb)
+ menu.add(save)
+
#####################################
# Path permissions checker for qemu #
#####################################
diff --git a/src/vmm-details.glade b/src/vmm-details.glade
index f848ea619..cb53abd69 100644
--- a/src/vmm-details.glade
+++ b/src/vmm-details.glade
@@ -142,6 +142,26 @@
+
+
+
+
+
+
@@ -152,14 +172,6 @@
-
-
-