From e91cc8477051b30aa9d0445f85b8f7adb1e880e8 Mon Sep 17 00:00:00 2001 From: Cole Robinson Date: Sun, 22 Sep 2013 15:13:41 -0400 Subject: [PATCH] uihelpers: Add VMActionMenu, share between manager and systray --- virtManager/create.py | 4 +- virtManager/engine.py | 9 ++-- virtManager/manager.py | 107 +++++++-------------------------------- virtManager/systray.py | 88 +++----------------------------- virtManager/uihelpers.py | 103 +++++++++++++++++++++++++++++++------ 5 files changed, 123 insertions(+), 188 deletions(-) diff --git a/virtManager/create.py b/virtManager/create.py index 651f4e3e4..255c55796 100644 --- a/virtManager/create.py +++ b/virtManager/create.py @@ -65,7 +65,7 @@ RHEL6_OS_SUPPORT = [ class vmmCreate(vmmGObjectUI): __gsignals__ = { - "action-show-vm": (GObject.SignalFlags.RUN_FIRST, None, [str, str]), + "action-show-domain": (GObject.SignalFlags.RUN_FIRST, None, [str, str]), } def __init__(self, engine): @@ -1843,7 +1843,7 @@ class vmmCreate(vmmGObjectUI): self.close() # Launch details dialog for new VM - self.emit("action-show-vm", self.conn.get_uri(), self.guest.uuid) + self.emit("action-show-domain", self.conn.get_uri(), self.guest.uuid) def start_install(self, guest): diff --git a/virtManager/engine.py b/virtManager/engine.py index 51e0c794d..ea086378d 100644 --- a/virtManager/engine.py +++ b/virtManager/engine.py @@ -161,7 +161,10 @@ class vmmEngine(vmmGObject): self.systray.connect("action-destroy-domain", self._do_destroy_domain) self.systray.connect("action-reset-domain", self._do_reset_domain) self.systray.connect("action-save-domain", self._do_save_domain) - self.systray.connect("action-show-vm", self._do_show_vm) + self.systray.connect("action-show-domain", self._do_show_vm) + self.systray.connect("action-migrate-domain", self._do_show_migrate) + self.systray.connect("action-delete-domain", self._do_delete_domain) + self.systray.connect("action-clone-domain", self._do_show_clone) self.systray.connect("action-exit-app", self.exit_app) def system_tray_changed(self, *ignore): @@ -773,7 +776,7 @@ class vmmEngine(vmmGObject): obj.connect("action-migrate-domain", self._do_show_migrate) obj.connect("action-delete-domain", self._do_delete_domain) obj.connect("action-clone-domain", self._do_show_clone) - obj.connect("action-show-vm", self._do_show_vm) + obj.connect("action-show-domain", self._do_show_vm) obj.connect("action-show-preferences", self._do_show_preferences) obj.connect("action-show-create", self._do_show_create) obj.connect("action-show-about", self._do_show_about) @@ -812,7 +815,7 @@ class vmmEngine(vmmGObject): return self.windowCreate obj = vmmCreate(self) - obj.connect("action-show-vm", self._do_show_vm) + obj.connect("action-show-domain", self._do_show_vm) self.windowCreate = obj return self.windowCreate diff --git a/virtManager/manager.py b/virtManager/manager.py index 6ec164423..88ff2dfcd 100644 --- a/virtManager/manager.py +++ b/virtManager/manager.py @@ -88,7 +88,7 @@ def _get_inspection_icon_pixbuf(vm, w, h): class vmmManager(vmmGObjectUI): __gsignals__ = { "action-show-connect": (GObject.SignalFlags.RUN_FIRST, None, []), - "action-show-vm": (GObject.SignalFlags.RUN_FIRST, None, [str, str]), + "action-show-domain": (GObject.SignalFlags.RUN_FIRST, None, [str, str]), "action-show-about": (GObject.SignalFlags.RUN_FIRST, None, []), "action-show-host": (GObject.SignalFlags.RUN_FIRST, None, [str]), "action-show-preferences": (GObject.SignalFlags.RUN_FIRST, None, []), @@ -124,9 +124,7 @@ class vmmManager(vmmGObjectUI): self.topwin.set_default_size(w or 550, h or 550) self.prev_position = None - self.vmmenu = Gtk.Menu() - self.vmmenushutdown = uihelpers.VMShutdownMenu(self, self.current_vm) - self.vmmenu_items = {} + self.vmmenu = uihelpers.VMActionMenu(self, self.current_vm) self.connmenu = Gtk.Menu() self.connmenu_items = {} @@ -234,11 +232,8 @@ class vmmManager(vmmGObjectUI): self.hostcpucol = None self.netcol = None - self.vmmenu.destroy() + self.vmmenu.destroy() # pylint: disable=E1101 self.vmmenu = None - self.vmmenu_items = None - self.vmmenushutdown.destroy() # pylint: disable=E1101 - self.vmmenushutdown = None self.connmenu.destroy() self.connmenu = None self.connmenu_items = None @@ -297,67 +292,28 @@ class vmmManager(vmmGObjectUI): c.set_homogeneous(False) def init_context_menus(self): - def build_stock(name): - return Gtk.Image.new_from_stock(name, Gtk.IconSize.MENU) - - shutdownmenu_icon = Gtk.Image.new_from_icon_name( - "system-shutdown", Gtk.IconSize.MENU) - run_icon = build_stock(Gtk.STOCK_MEDIA_PLAY) - pause_icon = build_stock(Gtk.STOCK_MEDIA_PAUSE) - resume_icon = build_stock(Gtk.STOCK_MEDIA_PAUSE) - delete_icon = build_stock(Gtk.STOCK_DELETE) - - def add_to_menu(menu, items, idx, text, icon, cb): + def add_to_menu(idx, text, icon, cb): if text[0:3] == 'gtk': item = Gtk.ImageMenuItem.new_from_stock(text, None) else: item = Gtk.ImageMenuItem.new_with_mnemonic(text) if icon: item.set_image(icon) - item.show() if cb: item.connect("activate", cb) - menu.add(item) - items[idx] = item - - def add_vm_menu(idx, text, icon, cb): - add_to_menu(self.vmmenu, self.vmmenu_items, idx, text, icon, cb) - def add_conn_menu(idx, text, icon, cb): - add_to_menu(self.connmenu, self.connmenu_items, - idx, text, icon, cb) - def add_sep(menu, items, idx): - sep = Gtk.SeparatorMenuItem() - sep.show() - menu.add(sep) - items[idx] = sep - - # Build VM context menu - add_vm_menu("run", _("_Run"), run_icon, self.start_vm) - add_vm_menu("pause", _("_Pause"), pause_icon, self.pause_vm) - add_vm_menu("resume", _("R_esume"), resume_icon, self.resume_vm) - - add_vm_menu("shutdown", _("_Shut Down"), shutdownmenu_icon, None) - self.vmmenu_items["shutdown"].set_submenu(self.vmmenushutdown) - - add_sep(self.vmmenu, self.vmmenu_items, "hsep1") - add_vm_menu("clone", _("_Clone..."), None, self.open_clone_window) - add_vm_menu("migrate", _("_Migrate..."), None, self.migrate_vm) - add_vm_menu("delete", _("_Delete"), delete_icon, self.do_delete) - - add_sep(self.vmmenu, self.vmmenu_items, "hsep2") - add_vm_menu("open", Gtk.STOCK_OPEN, None, self.show_vm) - self.vmmenu.show() + self.connmenu.add(item) + self.connmenu_items[idx] = item # Build connection context menu - add_conn_menu("create", Gtk.STOCK_NEW, None, self.new_vm) - add_conn_menu("connect", Gtk.STOCK_CONNECT, None, self.open_conn) - add_conn_menu("disconnect", Gtk.STOCK_DISCONNECT, None, + add_to_menu("create", Gtk.STOCK_NEW, None, self.new_vm) + add_to_menu("connect", Gtk.STOCK_CONNECT, None, self.open_conn) + add_to_menu("disconnect", Gtk.STOCK_DISCONNECT, None, self.close_conn) - add_sep(self.connmenu, self.connmenu_items, "hsep1") - add_conn_menu("delete", Gtk.STOCK_DELETE, None, self.do_delete) - add_sep(self.connmenu, self.connmenu_items, "hsep2") - add_conn_menu("details", _("D_etails"), None, self.show_host) - self.connmenu.show() + self.connmenu.add(Gtk.SeparatorMenuItem()) + add_to_menu("delete", Gtk.STOCK_DELETE, None, self.do_delete) + self.connmenu.add(Gtk.SeparatorMenuItem()) + add_to_menu("details", _("D_etails"), None, self.show_host) + self.connmenu.show_all() def init_vmlist(self): vmlist = self.widget("vm-list") @@ -536,16 +492,11 @@ class vmmManager(vmmGObjectUI): return if vm: - self.emit("action-show-vm", conn.get_uri(), vm.get_uuid()) + self.emit("action-show-domain", conn.get_uri(), vm.get_uuid()) else: if not self.open_conn(): self.emit("action-show-host", conn.get_uri()) - def open_clone_window(self, ignore1=None, ignore2=None, ignore3=None): - if self.current_vmuuid(): - self.emit("action-clone-domain", self.current_conn_uri(), - self.current_vmuuid()) - def do_delete(self, ignore=None): conn = self.current_conn() vm = self.current_vm() @@ -612,12 +563,6 @@ class vmmManager(vmmGObjectUI): self.emit("action-resume-domain", vm.conn.get_uri(), vm.get_uuid()) - def migrate_vm(self, ignore): - vm = self.current_vm() - if vm is not None: - self.emit("action-migrate-domain", - vm.conn.get_uri(), vm.get_uuid()) - def close_conn(self, ignore): conn = self.current_conn() if conn.get_state() != vmmConnection.STATE_DISCONNECTED: @@ -909,7 +854,7 @@ class vmmManager(vmmGObjectUI): text = _("_Run") strip_text = text.replace("_", "") - self.vmmenu_items["run"].get_child().set_label(text) + self.vmmenu.change_run_text(text) self.widget("vm-run").set_label(strip_text) def update_current_selection(self, ignore=None): @@ -969,23 +914,9 @@ class vmmManager(vmmGObjectUI): if model.iter_parent(_iter) is not None: # Popup the vm menu vm = model.get_value(_iter, ROW_HANDLE) - - run = vm.is_runable() - stop = vm.is_stoppable() - paused = vm.is_paused() - ro = vm.is_read_only() - - self.vmmenu_items["run"].set_sensitive(run) - self.vmmenu_items["shutdown"].set_sensitive(stop) - self.vmmenu_items["pause"].set_visible(not paused) - self.vmmenu_items["pause"].set_sensitive(stop) - self.vmmenu_items["resume"].set_visible(paused) - self.vmmenu_items["resume"].set_sensitive(paused) - self.vmmenu_items["migrate"].set_sensitive(stop) - self.vmmenu_items["clone"].set_sensitive(not ro) - self.vmmenushutdown.update_widget_states(vm) - - self.vmmenu.popup(None, None, None, None, 0, event.time) + self.vmmenu.update_widget_states(vm) + self.vmmenu.popup( # pylint: disable=E1101 + None, None, None, None, 0, event.time) else: # Pop up connection menu conn = model.get_value(_iter, ROW_HANDLE) diff --git a/virtManager/systray.py b/virtManager/systray.py index d90738d48..39b0371cb 100644 --- a/virtManager/systray.py +++ b/virtManager/systray.py @@ -59,8 +59,11 @@ class vmmSystray(vmmGObject): "action-reboot-domain": (GObject.SignalFlags.RUN_FIRST, None, [str, str]), "action-destroy-domain": (GObject.SignalFlags.RUN_FIRST, None, [str, str]), "action-save-domain": (GObject.SignalFlags.RUN_FIRST, None, [str, str]), + "action-migrate-domain": (GObject.SignalFlags.RUN_FIRST, None, [str, str]), + "action-delete-domain": (GObject.SignalFlags.RUN_FIRST, None, [str, str]), + "action-clone-domain": (GObject.SignalFlags.RUN_FIRST, None, [str, str]), "action-show-host": (GObject.SignalFlags.RUN_FIRST, None, [str]), - "action-show-vm": (GObject.SignalFlags.RUN_FIRST, None, [str, str]), + "action-show-domain": (GObject.SignalFlags.RUN_FIRST, None, [str, str]), "action-exit-app": (GObject.SignalFlags.RUN_FIRST, None, []), } @@ -173,60 +176,6 @@ class vmmSystray(vmmGObject): else: self.systray_icon.set_visible(do_show) - def build_vm_menu(self, vm): - icon_size = Gtk.IconSize.MENU - - pause_item = Gtk.ImageMenuItem.new_with_mnemonic(_("_Pause")) - pause_img = Gtk.Image.new_from_stock(Gtk.STOCK_MEDIA_PAUSE, icon_size) - pause_item.set_image(pause_img) - pause_item.connect("activate", self.run_vm_action, - "action-suspend-domain", vm.get_uuid()) - - resume_item = Gtk.ImageMenuItem.new_with_mnemonic(_("_Resume")) - resume_img = Gtk.Image.new_from_stock(Gtk.STOCK_MEDIA_PAUSE, - icon_size) - resume_item.set_image(resume_img) - resume_item.connect("activate", self.run_vm_action, - "action-resume-domain", vm.get_uuid()) - - run_item = Gtk.ImageMenuItem.new_with_mnemonic(_("_Run")) - run_img = Gtk.Image.new_from_stock(Gtk.STOCK_MEDIA_PLAY, icon_size) - run_item.set_image(run_img) - run_item.connect("activate", self.run_vm_action, - "action-run-domain", vm.get_uuid()) - - # Shutdown menu - shutdown_menu = uihelpers.VMShutdownMenu(self, lambda: vm) - shutdown_menu_item = Gtk.ImageMenuItem.new_with_mnemonic( - _("_Shut Down")) - shutdown_menu_item.set_image(Gtk.Image.new_from_icon_name( - "system-shutdown", icon_size)) - shutdown_menu_item.set_submenu(shutdown_menu) - - sep = Gtk.SeparatorMenuItem() - - open_item = Gtk.ImageMenuItem.new_from_stock("gtk-open", None) - open_item.show() - open_item.connect("activate", self.run_vm_action, - "action-show-vm", vm.get_uuid()) - - vm_action_dict = {} - vm_action_dict["run"] = run_item - vm_action_dict["pause"] = pause_item - vm_action_dict["resume"] = resume_item - vm_action_dict["shutdown_menu"] = shutdown_menu_item - vm_action_dict["sep"] = sep - vm_action_dict["open"] = open_item - - menu = Gtk.Menu() - - for key in ["run", "pause", "resume", "shutdown_menu", "sep", "open"]: - item = vm_action_dict[key] - item.show_all() - menu.add(vm_action_dict[key]) - - return menu, vm_action_dict - # Helper functions def _get_vm_menu_item(self, vm): uuid = vm.get_uuid() @@ -354,9 +303,9 @@ class vmmSystray(vmmGObject): # Build VM list entry menu_item = build_image_menu_item(vm.get_name()) vm_mappings[uuid] = menu_item - vm_action_menu, vm_action_dict = self.build_vm_menu(vm) + vm_action_menu = uihelpers.VMActionMenu(self, lambda: vm) menu_item.set_submenu(vm_action_menu) - self.vm_action_dict[uuid] = vm_action_dict + self.vm_action_dict[uuid] = vm_action_menu # Add VM to menu list self.populate_vm_list(conn) @@ -393,29 +342,8 @@ class vmmSystray(vmmGObject): self._set_vm_status_icon(vm, menu_item) # Update action widget states - actions = self.vm_action_dict[vm.get_uuid()] - - is_paused = vm.is_paused() - actions["run"].set_sensitive(vm.is_runable()) - actions["pause"].set_sensitive(vm.is_pauseable()) - actions["resume"].set_sensitive(vm.is_paused()) - actions["shutdown_menu"].set_sensitive(vm.is_active()) - actions["shutdown_menu"].get_submenu().update_widget_states(vm) - - actions["pause"].set_visible(not is_paused) - actions["resume"].set_visible(is_paused) - - def run_vm_action(self, ignore, signal_name, uuid): - uri = None - for tmpuri, vm_mappings in self.conn_vm_menuitems.items(): - if vm_mappings.get(uuid): - uri = tmpuri - break - - if not uri: - return - - self.emit(signal_name, uri, uuid) + menu = self.vm_action_dict[vm.get_uuid()] + menu.update_widget_states(vm) def exit_app(self, ignore): self.emit("action-exit-app") diff --git a/virtManager/uihelpers.py b/virtManager/uihelpers.py index 83507e40a..c44953aa7 100644 --- a/virtManager/uihelpers.py +++ b/virtManager/uihelpers.py @@ -908,7 +908,7 @@ def mediadev_set_default_selection(widget): # Build toolbar shutdown button menu (manager and details toolbar) # #################################################################### -class VMShutdownMenu(Gtk.Menu): +class _VMMenu(Gtk.Menu): # pylint: disable=E1101 # pylint can't detect functions we inheirit from Gtk, ex self.add @@ -918,23 +918,26 @@ class VMShutdownMenu(Gtk.Menu): self._current_vm_cb = current_vm_cb self._init_state() - def _init_state(self): - def _add_action(label, signal, iconname="system-shutdown"): + def _add_action(self, label, signal, + iconname="system-shutdown", addcb=True): + if label.startswith("gtk-"): + item = Gtk.ImageMenuItem.new_from_stock(label, None) + else: item = Gtk.ImageMenuItem.new_with_mnemonic(label) - icon = Gtk.Image.new_from_icon_name(iconname, Gtk.IconSize.MENU) + + if iconname: + if iconname.startswith("gtk-"): + icon = Gtk.Image.new_from_stock(iconname, Gtk.IconSize.MENU) + else: + icon = Gtk.Image.new_from_icon_name(iconname, + Gtk.IconSize.MENU) item.set_image(icon) + + item.vmm_widget_name = signal + if addcb: item.connect("activate", self._action_cb) - item.vmm_widget_name = signal - self.add(item) - - _add_action(_("_Reboot"), "reboot") - _add_action(_("_Shut Down"), "shutdown") - _add_action(_("F_orce Reset"), "reset") - _add_action(_("_Force Off"), "destroy") - self.add(Gtk.SeparatorMenuItem()) - _add_action(_("Sa_ve"), "save", iconname=Gtk.STOCK_SAVE) - - self.show_all() + self.add(item) + return item def _action_cb(self, src): vm = self._current_vm_cb() @@ -943,6 +946,26 @@ class VMShutdownMenu(Gtk.Menu): self._parent.emit("action-%s-domain" % src.vmm_widget_name, vm.conn.get_uri(), vm.get_uuid()) + def _init_state(self): + raise NotImplementedError() + def update_widget_states(self, vm): + raise NotImplementedError() + + +class VMShutdownMenu(_VMMenu): + # pylint: disable=E1101 + # pylint can't detect functions we inheirit from Gtk, ex self.add + + def _init_state(self): + self._add_action(_("_Reboot"), "reboot") + self._add_action(_("_Shut Down"), "shutdown") + self._add_action(_("F_orce Reset"), "reset") + self._add_action(_("_Force Off"), "destroy") + self.add(Gtk.SeparatorMenuItem()) + self._add_action(_("Sa_ve"), "save", iconname=Gtk.STOCK_SAVE) + + self.show_all() + def update_widget_states(self, vm): statemap = { "reboot": bool(vm and vm.is_stoppable()), @@ -958,6 +981,56 @@ class VMShutdownMenu(Gtk.Menu): child.set_sensitive(statemap[name]) +class VMActionMenu(_VMMenu): + # pylint: disable=E1101 + # pylint can't detect functions we inheirit from Gtk, ex self.add + + def _init_state(self): + self._add_action(_("_Run"), "run", Gtk.STOCK_MEDIA_PLAY) + self._add_action(_("_Pause"), "suspend", Gtk.STOCK_MEDIA_PAUSE) + self._add_action(_("R_esume"), "resume", Gtk.STOCK_MEDIA_PAUSE) + s = self._add_action(_("_Shut Down"), "shutdown", addcb=False) + s.set_submenu(VMShutdownMenu(self._parent, self._current_vm_cb)) + + self.add(Gtk.SeparatorMenuItem()) + self._add_action(_("Clone..."), "clone", None) + self._add_action(_("Migrate..."), "migrate", None) + self._add_action(_("_Delete"), "delete", Gtk.STOCK_DELETE) + + self.add(Gtk.SeparatorMenuItem()) + self._add_action(Gtk.STOCK_OPEN, "show", None) + + self.show_all() + + def update_widget_states(self, vm): + statemap = { + "run": bool(vm and vm.is_runable()), + "shutdown": bool(vm and vm.is_stoppable()), + "suspend": bool(vm and vm.is_stoppable()), + "resume": bool(vm and vm.is_paused()), + "migrate": bool(vm and vm.is_stoppable()), + "clone": bool(vm and not vm.is_read_only()), + } + vismap = { + "suspend": bool(vm and not vm.is_paused()), + "resume": bool(vm and vm.is_paused()), + } + + for child in self.get_children(): + name = getattr(child, "vmm_widget_name", None) + if hasattr(child, "update_widget_states"): + child.update_widget_states(vm) + if name in statemap: + child.set_sensitive(statemap[name]) + if name in vismap: + child.set_visible(vismap[name]) + + def change_run_text(self, text): + for child in self.get_children(): + if getattr(child, "vmm_widget_name", None) == "run": + child.get_child().set_label(text) + + ##################################### # Path permissions checker for qemu # #####################################