uihelpers: Add VMActionMenu, share between manager and systray

This commit is contained in:
Cole Robinson 2013-09-22 15:13:41 -04:00
parent 268b462126
commit e91cc84770
5 changed files with 123 additions and 188 deletions

View File

@ -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):

View File

@ -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

View File

@ -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)

View File

@ -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")

View File

@ -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 #
#####################################