2006-06-29 03:50:17 +08:00
|
|
|
#
|
2008-04-09 02:30:47 +08:00
|
|
|
# Copyright (C) 2006-2008 Red Hat, Inc.
|
2006-06-29 03:50:17 +08:00
|
|
|
# Copyright (C) 2006 Daniel P. Berrange <berrange@redhat.com>
|
|
|
|
#
|
|
|
|
# This program is free software; you can redistribute it and/or modify
|
|
|
|
# it under the terms of the GNU General Public License as published by
|
|
|
|
# the Free Software Foundation; either version 2 of the License, or
|
|
|
|
# (at your option) any later version.
|
|
|
|
#
|
|
|
|
# This program is distributed in the hope that it will be useful,
|
|
|
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
# GNU General Public License for more details.
|
|
|
|
#
|
|
|
|
# You should have received a copy of the GNU General Public License
|
|
|
|
# along with this program; if not, write to the Free Software
|
2007-11-21 00:12:20 +08:00
|
|
|
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
|
|
|
# MA 02110-1301 USA.
|
2006-06-29 03:50:17 +08:00
|
|
|
#
|
2006-06-14 22:59:40 +08:00
|
|
|
|
2012-02-01 07:16:54 +08:00
|
|
|
import logging
|
|
|
|
|
2013-04-12 05:16:33 +08:00
|
|
|
# pylint: disable=E0611
|
2012-05-14 21:24:56 +08:00
|
|
|
from gi.repository import GObject
|
|
|
|
from gi.repository import Gtk
|
|
|
|
from gi.repository import Gdk
|
|
|
|
from gi.repository import GdkPixbuf
|
2013-04-12 05:16:33 +08:00
|
|
|
# pylint: enable=E0611
|
2011-04-19 00:39:53 +08:00
|
|
|
|
2013-08-09 21:23:01 +08:00
|
|
|
from virtinst import util
|
|
|
|
|
2012-07-09 03:38:52 +08:00
|
|
|
from virtManager import uihelpers
|
2007-09-10 10:57:24 +08:00
|
|
|
from virtManager.connection import vmmConnection
|
2010-12-09 06:26:19 +08:00
|
|
|
from virtManager.baseclass import vmmGObjectUI
|
2009-07-22 22:21:33 +08:00
|
|
|
from virtManager.graphwidgets import CellRendererSparkline
|
2006-07-20 23:16:07 +08:00
|
|
|
|
2013-08-16 21:59:33 +08:00
|
|
|
import libvirt
|
2013-02-17 02:54:45 +08:00
|
|
|
|
2012-05-14 21:24:56 +08:00
|
|
|
# Number of data points for performance graphs
|
|
|
|
GRAPH_LEN = 40
|
2006-06-14 22:59:40 +08:00
|
|
|
|
2007-08-29 05:57:25 +08:00
|
|
|
# fields in the tree model data set
|
2013-04-24 00:42:41 +08:00
|
|
|
(ROW_HANDLE,
|
2013-09-02 06:36:58 +08:00
|
|
|
ROW_SORT_KEY,
|
2013-04-24 00:42:41 +08:00
|
|
|
ROW_MARKUP,
|
|
|
|
ROW_STATUS_ICON,
|
|
|
|
ROW_HINT,
|
|
|
|
ROW_IS_CONN,
|
|
|
|
ROW_IS_CONN_CONNECTED,
|
|
|
|
ROW_IS_VM,
|
|
|
|
ROW_IS_VM_RUNNING,
|
|
|
|
ROW_COLOR,
|
2013-09-02 06:36:58 +08:00
|
|
|
ROW_INSPECTION_OS_ICON) = range(11)
|
2007-08-28 10:22:18 +08:00
|
|
|
|
|
|
|
# Columns in the tree view
|
2013-09-02 22:43:53 +08:00
|
|
|
(COL_NAME,
|
|
|
|
COL_GUEST_CPU,
|
|
|
|
COL_HOST_CPU,
|
|
|
|
COL_DISK,
|
|
|
|
COL_NETWORK) = range(5)
|
2007-08-28 10:22:18 +08:00
|
|
|
|
2013-02-17 02:54:45 +08:00
|
|
|
|
2013-04-21 00:52:25 +08:00
|
|
|
def _style_get_prop(widget, propname):
|
|
|
|
value = GObject.Value()
|
|
|
|
value.init(GObject.TYPE_INT)
|
|
|
|
widget.style_get_property(propname, value)
|
|
|
|
return value.get_int()
|
2009-07-27 04:15:05 +08:00
|
|
|
|
|
|
|
|
2013-09-02 06:36:58 +08:00
|
|
|
def _get_inspection_icon_pixbuf(vm, w, h):
|
|
|
|
# libguestfs gives us the PNG data as a string.
|
|
|
|
png_data = vm.inspection.icon
|
|
|
|
if png_data is None:
|
|
|
|
return None
|
|
|
|
|
|
|
|
try:
|
|
|
|
pb = GdkPixbuf.PixbufLoader()
|
|
|
|
pb.set_size(w, h)
|
|
|
|
pb.write(png_data)
|
|
|
|
pb.close()
|
|
|
|
return pb.get_pixbuf()
|
|
|
|
except:
|
|
|
|
logging.exception("Error loading inspection icon data")
|
|
|
|
vm.inspection.icon = None
|
|
|
|
return None
|
|
|
|
|
|
|
|
|
2010-12-09 06:26:19 +08:00
|
|
|
class vmmManager(vmmGObjectUI):
|
2012-05-14 21:24:56 +08:00
|
|
|
__gsignals__ = {
|
|
|
|
"action-show-connect": (GObject.SignalFlags.RUN_FIRST, None, []),
|
|
|
|
"action-show-vm": (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, []),
|
|
|
|
"action-show-create": (GObject.SignalFlags.RUN_FIRST, None, [str]),
|
|
|
|
"action-suspend-domain": (GObject.SignalFlags.RUN_FIRST, None, [str, str]),
|
|
|
|
"action-resume-domain": (GObject.SignalFlags.RUN_FIRST, None, [str, str]),
|
|
|
|
"action-run-domain": (GObject.SignalFlags.RUN_FIRST, None, [str, str]),
|
|
|
|
"action-shutdown-domain": (GObject.SignalFlags.RUN_FIRST, None, [str, str]),
|
|
|
|
"action-reset-domain": (GObject.SignalFlags.RUN_FIRST, None, [str, str]),
|
|
|
|
"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]),
|
2013-06-18 04:29:51 +08:00
|
|
|
"action-delete-domain": (GObject.SignalFlags.RUN_FIRST, None, [str, str]),
|
2012-05-14 21:24:56 +08:00
|
|
|
"action-clone-domain": (GObject.SignalFlags.RUN_FIRST, None, [str, str]),
|
|
|
|
"action-exit-app": (GObject.SignalFlags.RUN_FIRST, None, []),
|
|
|
|
"manager-closed": (GObject.SignalFlags.RUN_FIRST, None, []),
|
|
|
|
"manager-opened": (GObject.SignalFlags.RUN_FIRST, None, []),
|
|
|
|
"remove-conn": (GObject.SignalFlags.RUN_FIRST, None, [str]),
|
|
|
|
"add-default-conn": (GObject.SignalFlags.RUN_FIRST, None, []),
|
|
|
|
}
|
|
|
|
|
2011-07-23 01:42:20 +08:00
|
|
|
def __init__(self):
|
2012-02-02 06:26:46 +08:00
|
|
|
vmmGObjectUI.__init__(self, "vmm-manager.ui", "vmm-manager")
|
2010-12-01 03:33:21 +08:00
|
|
|
|
2009-07-27 04:15:05 +08:00
|
|
|
self.ignore_pause = False
|
2009-03-10 04:17:09 +08:00
|
|
|
|
2009-11-29 09:49:44 +08:00
|
|
|
# Mapping of VM UUID -> tree model rows to
|
|
|
|
# allow O(1) access instead of O(n)
|
|
|
|
self.rows = {}
|
|
|
|
|
2009-11-29 10:00:46 +08:00
|
|
|
w, h = self.config.get_manager_window_size()
|
2010-02-24 03:18:12 +08:00
|
|
|
self.topwin.set_default_size(w or 550, h or 550)
|
2010-12-14 06:48:19 +08:00
|
|
|
self.prev_position = None
|
2009-11-29 10:00:46 +08:00
|
|
|
|
2012-05-14 21:24:56 +08:00
|
|
|
self.vmmenu = Gtk.Menu()
|
|
|
|
self.vmmenushutdown = Gtk.Menu()
|
2009-11-29 09:49:44 +08:00
|
|
|
self.vmmenu_items = {}
|
|
|
|
self.vmmenushutdown_items = {}
|
2012-05-14 21:24:56 +08:00
|
|
|
self.connmenu = Gtk.Menu()
|
2009-11-29 09:49:44 +08:00
|
|
|
self.connmenu_items = {}
|
2011-04-13 21:27:02 +08:00
|
|
|
|
2013-02-17 02:31:46 +08:00
|
|
|
self.builder.connect_signals({
|
2011-07-12 20:49:47 +08:00
|
|
|
"on_menu_view_guest_cpu_usage_activate":
|
2012-05-14 21:24:56 +08:00
|
|
|
self.toggle_stats_visible_guest_cpu,
|
2011-07-12 20:49:47 +08:00
|
|
|
"on_menu_view_host_cpu_usage_activate":
|
2012-05-14 21:24:56 +08:00
|
|
|
self.toggle_stats_visible_host_cpu,
|
2011-07-12 20:49:47 +08:00
|
|
|
"on_menu_view_disk_io_activate" :
|
2012-05-14 21:24:56 +08:00
|
|
|
self.toggle_stats_visible_disk,
|
2011-07-12 20:49:47 +08:00
|
|
|
"on_menu_view_network_traffic_activate":
|
2012-05-14 21:24:56 +08:00
|
|
|
self.toggle_stats_visible_network,
|
2009-11-29 09:49:44 +08:00
|
|
|
|
|
|
|
"on_vm_manager_delete_event": self.close,
|
2009-11-29 10:00:46 +08:00
|
|
|
"on_vmm_manager_configure_event": self.window_resized,
|
2011-07-23 04:43:26 +08:00
|
|
|
"on_menu_file_add_connection_activate": self.new_conn,
|
2009-11-29 09:49:44 +08:00
|
|
|
"on_menu_file_quit_activate": self.exit_app,
|
|
|
|
"on_menu_file_close_activate": self.close,
|
|
|
|
"on_vmm_close_clicked": self.close,
|
2011-06-09 04:33:20 +08:00
|
|
|
"on_vm_open_clicked": self.show_vm,
|
2009-11-29 09:49:44 +08:00
|
|
|
"on_vm_run_clicked": self.start_vm,
|
|
|
|
"on_vm_new_clicked": self.new_vm,
|
|
|
|
"on_vm_shutdown_clicked": self.poweroff_vm,
|
|
|
|
"on_vm_pause_clicked": self.pause_vm_button,
|
2011-06-09 04:33:20 +08:00
|
|
|
"on_menu_edit_details_activate": self.show_vm,
|
2009-11-29 09:49:44 +08:00
|
|
|
"on_menu_edit_delete_activate": self.do_delete,
|
|
|
|
"on_menu_host_details_activate": self.show_host,
|
|
|
|
|
2011-06-09 04:33:20 +08:00
|
|
|
"on_vm_list_row_activated": self.show_vm,
|
2009-11-29 09:49:44 +08:00
|
|
|
"on_vm_list_button_press_event": self.popup_vm_menu_button,
|
|
|
|
"on_vm_list_key_press_event": self.popup_vm_menu_key,
|
|
|
|
|
|
|
|
"on_menu_edit_preferences_activate": self.show_preferences,
|
|
|
|
"on_menu_help_about_activate": self.show_about,
|
2011-04-13 21:27:02 +08:00
|
|
|
})
|
|
|
|
|
2013-09-02 22:43:53 +08:00
|
|
|
# There seem to be ref counting issues with calling
|
|
|
|
# list.get_column, so avoid it
|
|
|
|
self.diskcol = None
|
|
|
|
self.netcol = None
|
|
|
|
self.guestcpucol = None
|
|
|
|
self.hostcpucol = None
|
|
|
|
self.spacer_txt = None
|
2011-04-13 21:27:02 +08:00
|
|
|
self.init_vmlist()
|
2013-09-02 22:43:53 +08:00
|
|
|
|
2011-04-13 21:27:02 +08:00
|
|
|
self.init_stats()
|
|
|
|
self.init_toolbar()
|
|
|
|
self.init_context_menus()
|
2009-11-29 09:49:44 +08:00
|
|
|
|
2013-09-02 21:09:31 +08:00
|
|
|
self.update_current_selection()
|
|
|
|
self.widget("vm-list").get_selection().connect(
|
|
|
|
"changed", self.update_current_selection)
|
2009-11-29 09:49:44 +08:00
|
|
|
|
2011-07-26 03:09:42 +08:00
|
|
|
self.max_disk_rate = 10.0
|
|
|
|
self.max_net_rate = 10.0
|
|
|
|
|
2009-11-29 09:49:44 +08:00
|
|
|
# Initialize stat polling columns based on global polling
|
|
|
|
# preferences (we want signal handlers for this)
|
2013-04-18 05:39:25 +08:00
|
|
|
self.enable_polling(COL_DISK)
|
|
|
|
self.enable_polling(COL_NETWORK)
|
2009-11-29 09:49:44 +08:00
|
|
|
|
|
|
|
# Select first list entry
|
2011-07-15 01:13:13 +08:00
|
|
|
vmlist = self.widget("vm-list")
|
2010-03-04 05:58:50 +08:00
|
|
|
if len(vmlist.get_model()) != 0:
|
|
|
|
vmlist.get_selection().select_iter(
|
|
|
|
vmlist.get_model().get_iter_first())
|
|
|
|
|
|
|
|
# Queue up the default connection detector
|
2011-07-23 04:43:26 +08:00
|
|
|
self.idle_emit("add-default-conn")
|
2009-11-29 09:49:44 +08:00
|
|
|
|
|
|
|
##################
|
|
|
|
# Common methods #
|
|
|
|
##################
|
|
|
|
|
|
|
|
def show(self):
|
2010-12-09 06:26:19 +08:00
|
|
|
vis = self.is_visible()
|
2010-02-24 03:18:12 +08:00
|
|
|
self.topwin.present()
|
2010-12-09 06:26:19 +08:00
|
|
|
if vis:
|
|
|
|
return
|
2010-02-24 03:18:12 +08:00
|
|
|
|
2013-06-13 21:18:46 +08:00
|
|
|
logging.debug("Showing manager")
|
2010-12-14 06:48:19 +08:00
|
|
|
if self.prev_position:
|
|
|
|
self.topwin.move(*self.prev_position)
|
|
|
|
self.prev_position = None
|
2011-04-13 22:47:31 +08:00
|
|
|
|
|
|
|
self.emit("manager-opened")
|
2009-11-29 09:49:44 +08:00
|
|
|
|
2010-12-10 00:22:35 +08:00
|
|
|
def close(self, src_ignore=None, src2_ignore=None):
|
2010-12-09 06:26:19 +08:00
|
|
|
if not self.is_visible():
|
|
|
|
return
|
|
|
|
|
2013-06-13 21:18:46 +08:00
|
|
|
logging.debug("Closing manager")
|
2010-12-14 06:48:19 +08:00
|
|
|
self.prev_position = self.topwin.get_position()
|
2010-12-09 06:26:19 +08:00
|
|
|
self.topwin.hide()
|
2011-04-13 22:47:31 +08:00
|
|
|
self.emit("manager-closed")
|
|
|
|
|
2010-12-09 06:26:19 +08:00
|
|
|
return 1
|
2009-11-29 09:49:44 +08:00
|
|
|
|
2011-04-13 21:27:02 +08:00
|
|
|
|
2011-07-24 09:16:54 +08:00
|
|
|
def _cleanup(self):
|
|
|
|
self.rows = None
|
2011-04-13 21:27:02 +08:00
|
|
|
|
2011-07-24 09:16:54 +08:00
|
|
|
self.diskcol = None
|
|
|
|
self.guestcpucol = None
|
|
|
|
self.hostcpucol = None
|
|
|
|
self.netcol = None
|
2011-04-13 21:27:02 +08:00
|
|
|
|
2011-07-24 09:16:54 +08:00
|
|
|
self.vmmenu.destroy()
|
|
|
|
self.vmmenu = None
|
|
|
|
self.vmmenu_items = None
|
|
|
|
self.vmmenushutdown.destroy()
|
|
|
|
self.vmmenushutdown = None
|
|
|
|
self.vmmenushutdown_items = None
|
|
|
|
self.connmenu.destroy()
|
|
|
|
self.connmenu = None
|
|
|
|
self.connmenu_items = None
|
2011-04-13 21:27:02 +08:00
|
|
|
|
2009-11-29 09:49:44 +08:00
|
|
|
def is_visible(self):
|
2012-05-14 21:24:56 +08:00
|
|
|
return bool(self.topwin.get_visible())
|
2009-11-29 09:49:44 +08:00
|
|
|
|
2010-03-03 09:35:54 +08:00
|
|
|
def set_startup_error(self, msg):
|
2011-07-15 01:13:13 +08:00
|
|
|
self.widget("vm-notebook").set_current_page(1)
|
|
|
|
self.widget("startup-error-label").set_text(msg)
|
2006-06-14 22:59:40 +08:00
|
|
|
|
2009-11-29 09:49:44 +08:00
|
|
|
################
|
|
|
|
# Init methods #
|
|
|
|
################
|
|
|
|
|
|
|
|
def init_stats(self):
|
2011-04-13 21:27:02 +08:00
|
|
|
self.add_gconf_handle(
|
2011-07-12 20:49:47 +08:00
|
|
|
self.config.on_vmlist_guest_cpu_usage_visible_changed(
|
|
|
|
self.toggle_guest_cpu_usage_visible_widget))
|
|
|
|
self.add_gconf_handle(
|
|
|
|
self.config.on_vmlist_host_cpu_usage_visible_changed(
|
|
|
|
self.toggle_host_cpu_usage_visible_widget))
|
2011-04-13 21:27:02 +08:00
|
|
|
self.add_gconf_handle(
|
|
|
|
self.config.on_vmlist_disk_io_visible_changed(
|
2011-07-12 20:49:47 +08:00
|
|
|
self.toggle_disk_io_visible_widget))
|
2011-04-13 21:27:02 +08:00
|
|
|
self.add_gconf_handle(
|
|
|
|
self.config.on_vmlist_network_traffic_visible_changed(
|
|
|
|
self.toggle_network_traffic_visible_widget))
|
2006-06-14 22:59:40 +08:00
|
|
|
|
2008-12-18 04:27:06 +08:00
|
|
|
# Register callbacks with the global stats enable/disable values
|
|
|
|
# that disable the associated vmlist widgets if reporting is disabled
|
2011-04-13 21:27:02 +08:00
|
|
|
self.add_gconf_handle(
|
|
|
|
self.config.on_stats_enable_disk_poll_changed(self.enable_polling,
|
2011-07-12 20:49:47 +08:00
|
|
|
COL_DISK))
|
2011-04-13 21:27:02 +08:00
|
|
|
self.add_gconf_handle(
|
|
|
|
self.config.on_stats_enable_net_poll_changed(self.enable_polling,
|
2011-07-12 20:49:47 +08:00
|
|
|
COL_NETWORK))
|
2011-04-13 21:27:02 +08:00
|
|
|
|
2013-09-02 09:35:23 +08:00
|
|
|
self.toggle_guest_cpu_usage_visible_widget()
|
|
|
|
self.toggle_host_cpu_usage_visible_widget()
|
|
|
|
self.toggle_disk_io_visible_widget()
|
|
|
|
self.toggle_network_traffic_visible_widget()
|
2008-12-18 04:27:06 +08:00
|
|
|
|
2009-11-12 00:02:57 +08:00
|
|
|
|
2009-11-29 09:49:44 +08:00
|
|
|
def init_toolbar(self):
|
2011-07-15 01:13:13 +08:00
|
|
|
self.widget("vm-new").set_icon_name("vm_new")
|
|
|
|
self.widget("vm-open").set_icon_name("icon_console")
|
|
|
|
uihelpers.build_shutdown_button_menu(self.widget("vm-shutdown"),
|
|
|
|
self.poweroff_vm,
|
|
|
|
self.reboot_vm,
|
2013-03-17 05:59:32 +08:00
|
|
|
self.reset_vm,
|
2011-07-15 01:13:13 +08:00
|
|
|
self.destroy_vm,
|
|
|
|
self.save_vm)
|
|
|
|
|
|
|
|
tool = self.widget("vm-toolbar")
|
2012-05-14 21:24:56 +08:00
|
|
|
tool.set_property("icon-size", Gtk.IconSize.LARGE_TOOLBAR)
|
2009-11-11 01:57:28 +08:00
|
|
|
for c in tool.get_children():
|
2009-07-27 04:25:01 +08:00
|
|
|
c.set_homogeneous(False)
|
|
|
|
|
2009-11-29 09:49:44 +08:00
|
|
|
def init_context_menus(self):
|
2009-11-18 05:20:23 +08:00
|
|
|
def build_icon(name):
|
2012-05-14 21:24:56 +08:00
|
|
|
return Gtk.Image.new_from_icon_name(name, Gtk.IconSize.MENU)
|
2009-11-18 05:20:23 +08:00
|
|
|
|
|
|
|
def build_stock(name):
|
2012-05-14 21:24:56 +08:00
|
|
|
return Gtk.Image.new_from_stock(name, Gtk.IconSize.MENU)
|
2009-11-18 05:20:23 +08:00
|
|
|
|
2013-01-14 03:41:25 +08:00
|
|
|
shutdownmenu_icon = build_icon("system-shutdown")
|
|
|
|
reboot_icon = build_icon("system-shutdown")
|
|
|
|
shutdown_icon = build_icon("system-shutdown")
|
|
|
|
destroy_icon = build_icon("system-shutdown")
|
|
|
|
reset_icon = build_icon("system-shutdown")
|
2012-05-14 21:24:56 +08:00
|
|
|
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)
|
2007-03-09 03:39:22 +08:00
|
|
|
|
2010-05-13 03:31:36 +08:00
|
|
|
def add_to_menu(menu, items, idx, text, icon, cb):
|
2012-05-14 21:24:56 +08:00
|
|
|
if text[0:3] == 'gtk':
|
|
|
|
item = Gtk.ImageMenuItem.new_from_stock(text, None)
|
|
|
|
else:
|
|
|
|
item = Gtk.ImageMenuItem.new_with_mnemonic(text)
|
2010-05-13 03:31:36 +08:00
|
|
|
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_shutdown_menu(idx, text, icon, cb):
|
|
|
|
add_to_menu(self.vmmenushutdown, self.vmmenushutdown_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):
|
2012-05-14 21:24:56 +08:00
|
|
|
sep = Gtk.SeparatorMenuItem()
|
2010-05-13 03:31:36 +08:00
|
|
|
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)
|
2008-05-14 03:59:25 +08:00
|
|
|
self.vmmenu_items["shutdown"].set_submenu(self.vmmenushutdown)
|
2010-05-13 03:31:36 +08:00
|
|
|
add_shutdown_menu("reboot", _("_Reboot"), reboot_icon, self.reboot_vm)
|
|
|
|
add_shutdown_menu("poweroff", _("_Shut Down"), shutdown_icon,
|
|
|
|
self.poweroff_vm)
|
2013-03-17 05:59:32 +08:00
|
|
|
add_shutdown_menu("forcereset", _("_Force Reset"), reset_icon,
|
|
|
|
self.reset_vm)
|
2010-05-13 03:31:36 +08:00
|
|
|
add_shutdown_menu("forcepoweroff", _("_Force Off"), destroy_icon,
|
|
|
|
self.destroy_vm)
|
|
|
|
add_sep(self.vmmenushutdown, self.vmmenushutdown_items, "sep")
|
|
|
|
add_shutdown_menu("save", _("Sa_ve"), save_icon, self.save_vm)
|
|
|
|
|
|
|
|
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")
|
2012-05-14 21:24:56 +08:00
|
|
|
add_vm_menu("open", Gtk.STOCK_OPEN, None, self.show_vm)
|
2007-03-09 03:39:22 +08:00
|
|
|
self.vmmenu.show()
|
2006-06-14 22:59:40 +08:00
|
|
|
|
2010-05-13 03:31:36 +08:00
|
|
|
# Build connection context menu
|
2012-05-14 21:24:56 +08:00
|
|
|
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,
|
2011-07-23 04:43:26 +08:00
|
|
|
self.close_conn)
|
2010-05-13 03:31:36 +08:00
|
|
|
add_sep(self.connmenu, self.connmenu_items, "hsep1")
|
2012-05-14 21:24:56 +08:00
|
|
|
add_conn_menu("delete", Gtk.STOCK_DELETE, None, self.do_delete)
|
2010-05-13 03:31:36 +08:00
|
|
|
add_sep(self.connmenu, self.connmenu_items, "hsep2")
|
2011-07-13 07:20:58 +08:00
|
|
|
add_conn_menu("details", _("D_etails"), None, self.show_host)
|
2007-08-14 05:13:39 +08:00
|
|
|
self.connmenu.show()
|
|
|
|
|
2009-11-29 09:49:44 +08:00
|
|
|
def init_vmlist(self):
|
2011-07-15 01:13:13 +08:00
|
|
|
vmlist = self.widget("vm-list")
|
|
|
|
self.widget("vm-notebook").set_show_tabs(False)
|
2006-06-14 22:59:40 +08:00
|
|
|
|
2013-04-24 00:42:41 +08:00
|
|
|
rowtypes = []
|
|
|
|
rowtypes.insert(ROW_HANDLE, object) # backing object
|
2013-09-02 06:36:58 +08:00
|
|
|
rowtypes.insert(ROW_SORT_KEY, str) # object name
|
2013-04-24 00:42:41 +08:00
|
|
|
rowtypes.insert(ROW_MARKUP, str) # row markup text
|
|
|
|
rowtypes.insert(ROW_STATUS_ICON, str) # status icon name
|
|
|
|
rowtypes.insert(ROW_HINT, str) # row tooltip
|
|
|
|
rowtypes.insert(ROW_IS_CONN, bool) # if object is a connection
|
|
|
|
rowtypes.insert(ROW_IS_CONN_CONNECTED, bool) # if conn is connected
|
|
|
|
rowtypes.insert(ROW_IS_VM, bool) # if row is VM
|
|
|
|
rowtypes.insert(ROW_IS_VM_RUNNING, bool) # if VM is running
|
2013-04-24 01:04:33 +08:00
|
|
|
rowtypes.insert(ROW_COLOR, str) # row markup color string
|
2013-04-24 02:24:52 +08:00
|
|
|
rowtypes.insert(ROW_INSPECTION_OS_ICON, GdkPixbuf.Pixbuf) # OS icon
|
2013-04-24 00:42:41 +08:00
|
|
|
|
|
|
|
model = Gtk.TreeStore(*rowtypes)
|
2009-11-29 09:49:44 +08:00
|
|
|
vmlist.set_model(model)
|
2012-02-02 06:26:46 +08:00
|
|
|
vmlist.set_tooltip_column(ROW_HINT)
|
2009-11-29 09:49:44 +08:00
|
|
|
vmlist.set_headers_visible(True)
|
2013-04-21 00:52:53 +08:00
|
|
|
vmlist.set_level_indentation(
|
|
|
|
-(_style_get_prop(vmlist, "expander-size") + 3))
|
2006-06-14 22:59:40 +08:00
|
|
|
|
2012-05-14 21:24:56 +08:00
|
|
|
nameCol = Gtk.TreeViewColumn(_("Name"))
|
2009-11-29 09:49:44 +08:00
|
|
|
nameCol.set_expand(True)
|
2013-09-10 22:07:11 +08:00
|
|
|
nameCol.set_sizing(Gtk.TreeViewColumnSizing.AUTOSIZE)
|
2009-11-29 09:49:44 +08:00
|
|
|
nameCol.set_spacing(6)
|
2013-09-02 22:43:53 +08:00
|
|
|
nameCol.set_sort_column_id(COL_NAME)
|
2006-11-06 23:34:54 +08:00
|
|
|
|
2009-11-29 09:49:44 +08:00
|
|
|
vmlist.append_column(nameCol)
|
2008-12-18 04:27:06 +08:00
|
|
|
|
2012-05-14 21:24:56 +08:00
|
|
|
status_icon = Gtk.CellRendererPixbuf()
|
|
|
|
status_icon.set_property("stock-size", Gtk.IconSize.DND)
|
2013-09-02 22:43:53 +08:00
|
|
|
nameCol.pack_start(status_icon, False)
|
|
|
|
nameCol.add_attribute(status_icon, 'icon-name', ROW_STATUS_ICON)
|
|
|
|
nameCol.add_attribute(status_icon, 'visible', ROW_IS_VM)
|
2009-03-10 04:22:03 +08:00
|
|
|
|
2012-05-14 21:24:56 +08:00
|
|
|
inspection_os_icon = Gtk.CellRendererPixbuf()
|
2013-09-02 22:43:53 +08:00
|
|
|
nameCol.pack_start(inspection_os_icon, False)
|
|
|
|
nameCol.add_attribute(inspection_os_icon, 'pixbuf',
|
2011-07-19 02:53:56 +08:00
|
|
|
ROW_INSPECTION_OS_ICON)
|
2013-09-02 22:43:53 +08:00
|
|
|
nameCol.add_attribute(inspection_os_icon, 'visible', ROW_IS_VM)
|
2011-07-19 02:53:56 +08:00
|
|
|
|
2012-05-14 21:24:56 +08:00
|
|
|
name_txt = Gtk.CellRendererText()
|
2009-11-29 09:49:44 +08:00
|
|
|
nameCol.pack_start(name_txt, True)
|
|
|
|
nameCol.add_attribute(name_txt, 'markup', ROW_MARKUP)
|
2013-04-24 01:04:33 +08:00
|
|
|
nameCol.add_attribute(name_txt, 'foreground', ROW_COLOR)
|
2013-09-02 22:43:53 +08:00
|
|
|
|
|
|
|
self.spacer_txt = Gtk.CellRendererText()
|
|
|
|
self.spacer_txt.set_property("ypad", 4)
|
|
|
|
self.spacer_txt.set_property("visible", False)
|
|
|
|
nameCol.pack_end(self.spacer_txt, False)
|
2007-09-10 10:57:24 +08:00
|
|
|
|
2013-09-02 09:35:23 +08:00
|
|
|
def make_stats_column(title, colnum):
|
2012-05-14 21:24:56 +08:00
|
|
|
col = Gtk.TreeViewColumn(title)
|
2011-07-12 20:49:47 +08:00
|
|
|
col.set_min_width(140)
|
2013-04-21 02:11:31 +08:00
|
|
|
|
2012-05-14 21:24:56 +08:00
|
|
|
txt = Gtk.CellRendererText()
|
2013-04-21 01:43:21 +08:00
|
|
|
txt.set_property("ypad", 4)
|
2013-04-21 02:11:31 +08:00
|
|
|
col.pack_start(txt, True)
|
|
|
|
col.add_attribute(txt, 'visible', ROW_IS_CONN)
|
|
|
|
|
2011-07-12 20:49:47 +08:00
|
|
|
img = CellRendererSparkline()
|
|
|
|
img.set_property("xpad", 6)
|
|
|
|
img.set_property("ypad", 12)
|
|
|
|
img.set_property("reversed", True)
|
|
|
|
col.pack_start(img, True)
|
|
|
|
col.add_attribute(img, 'visible', ROW_IS_VM)
|
2013-04-21 02:11:31 +08:00
|
|
|
|
2011-07-12 20:49:47 +08:00
|
|
|
col.set_sort_column_id(colnum)
|
|
|
|
vmlist.append_column(col)
|
|
|
|
return col
|
|
|
|
|
2013-09-02 09:35:23 +08:00
|
|
|
self.guestcpucol = make_stats_column(_("CPU usage"), COL_GUEST_CPU)
|
|
|
|
self.hostcpucol = make_stats_column(_("Host CPU usage"), COL_HOST_CPU)
|
|
|
|
self.diskcol = make_stats_column(_("Disk I/O"), COL_DISK)
|
|
|
|
self.netcol = make_stats_column(_("Network I/O"), COL_NETWORK)
|
2006-06-14 22:59:40 +08:00
|
|
|
|
2009-11-29 09:49:44 +08:00
|
|
|
model.set_sort_func(COL_NAME, self.vmlist_name_sorter)
|
2011-07-12 20:49:47 +08:00
|
|
|
model.set_sort_func(COL_GUEST_CPU, self.vmlist_guest_cpu_usage_sorter)
|
|
|
|
model.set_sort_func(COL_HOST_CPU, self.vmlist_host_cpu_usage_sorter)
|
2009-11-29 09:49:44 +08:00
|
|
|
model.set_sort_func(COL_DISK, self.vmlist_disk_io_sorter)
|
|
|
|
model.set_sort_func(COL_NETWORK, self.vmlist_network_usage_sorter)
|
2012-05-14 21:24:56 +08:00
|
|
|
model.set_sort_column_id(COL_NAME, Gtk.SortType.ASCENDING)
|
2009-11-29 09:49:44 +08:00
|
|
|
|
|
|
|
##################
|
|
|
|
# Helper methods #
|
|
|
|
##################
|
|
|
|
|
|
|
|
def current_row(self):
|
2011-07-15 01:13:13 +08:00
|
|
|
vmlist = self.widget("vm-list")
|
2009-11-29 09:49:44 +08:00
|
|
|
selection = vmlist.get_selection()
|
|
|
|
active = selection.get_selected()
|
|
|
|
|
|
|
|
treestore, treeiter = active
|
2012-11-08 21:15:02 +08:00
|
|
|
if treeiter is not None:
|
2009-11-29 09:49:44 +08:00
|
|
|
return treestore[treeiter]
|
|
|
|
return None
|
|
|
|
|
|
|
|
def current_vm(self):
|
|
|
|
row = self.current_row()
|
|
|
|
if not row or row[ROW_IS_CONN]:
|
|
|
|
return None
|
|
|
|
|
|
|
|
return row[ROW_HANDLE]
|
|
|
|
|
2011-07-23 04:43:26 +08:00
|
|
|
def current_conn(self):
|
2009-11-29 09:49:44 +08:00
|
|
|
row = self.current_row()
|
|
|
|
if not row:
|
|
|
|
return None
|
|
|
|
|
|
|
|
handle = row[ROW_HANDLE]
|
|
|
|
if row[ROW_IS_CONN]:
|
|
|
|
return handle
|
|
|
|
else:
|
2011-07-23 04:43:26 +08:00
|
|
|
return handle.conn
|
2009-11-29 09:49:44 +08:00
|
|
|
|
|
|
|
def current_vmuuid(self):
|
|
|
|
vm = self.current_vm()
|
|
|
|
if vm is None:
|
|
|
|
return None
|
|
|
|
return vm.get_uuid()
|
|
|
|
|
2011-07-23 04:43:26 +08:00
|
|
|
def current_conn_uri(self, default_selection=False):
|
2011-07-15 01:13:13 +08:00
|
|
|
vmlist = self.widget("vm-list")
|
2010-08-23 00:50:31 +08:00
|
|
|
model = vmlist.get_model()
|
|
|
|
|
2011-07-23 04:43:26 +08:00
|
|
|
conn = self.current_conn()
|
2010-08-23 00:50:31 +08:00
|
|
|
if conn is None and default_selection:
|
|
|
|
# Nothing selected, use first connection row
|
|
|
|
for row in model:
|
|
|
|
if row[ROW_IS_CONN]:
|
|
|
|
conn = row[ROW_HANDLE]
|
|
|
|
break
|
|
|
|
|
|
|
|
if conn:
|
|
|
|
return conn.get_uri()
|
|
|
|
return None
|
2009-11-29 09:49:44 +08:00
|
|
|
|
|
|
|
####################
|
|
|
|
# Action listeners #
|
|
|
|
####################
|
2006-11-03 23:02:02 +08:00
|
|
|
|
2009-11-29 10:00:46 +08:00
|
|
|
def window_resized(self, ignore, event):
|
|
|
|
# Sometimes dimensions change when window isn't visible
|
|
|
|
if not self.is_visible():
|
|
|
|
return
|
|
|
|
|
|
|
|
self.config.set_manager_window_size(event.width, event.height)
|
|
|
|
|
2010-12-10 00:22:35 +08:00
|
|
|
def exit_app(self, src_ignore=None, src2_ignore=None):
|
2008-06-14 02:40:26 +08:00
|
|
|
self.emit("action-exit-app")
|
2006-06-14 22:59:40 +08:00
|
|
|
|
2011-07-23 04:43:26 +08:00
|
|
|
def new_conn(self, src_ignore=None):
|
2006-06-28 02:16:13 +08:00
|
|
|
self.emit("action-show-connect")
|
2006-06-14 22:59:40 +08:00
|
|
|
|
2010-12-10 00:22:35 +08:00
|
|
|
def new_vm(self, src_ignore=None):
|
2011-07-23 04:43:26 +08:00
|
|
|
self.emit("action-show-create", self.current_conn_uri())
|
2009-11-29 09:49:44 +08:00
|
|
|
|
2010-12-10 00:22:35 +08:00
|
|
|
def show_about(self, src_ignore):
|
2009-11-29 09:49:44 +08:00
|
|
|
self.emit("action-show-about")
|
|
|
|
|
2010-12-10 00:22:35 +08:00
|
|
|
def show_preferences(self, src_ignore):
|
2009-11-29 09:49:44 +08:00
|
|
|
self.emit("action-show-preferences")
|
|
|
|
|
2010-12-10 00:22:35 +08:00
|
|
|
def show_host(self, src_ignore):
|
2011-07-23 04:43:26 +08:00
|
|
|
uri = self.current_conn_uri(default_selection=True)
|
2010-08-23 00:50:31 +08:00
|
|
|
self.emit("action-show-host", uri)
|
2009-11-29 09:49:44 +08:00
|
|
|
|
2011-06-09 04:33:20 +08:00
|
|
|
def show_vm(self, ignore, ignore2=None, ignore3=None):
|
2011-07-23 04:43:26 +08:00
|
|
|
conn = self.current_conn()
|
2011-06-09 04:33:20 +08:00
|
|
|
vm = self.current_vm()
|
|
|
|
if conn is None:
|
|
|
|
return
|
|
|
|
|
|
|
|
if vm:
|
|
|
|
self.emit("action-show-vm", conn.get_uri(), vm.get_uuid())
|
|
|
|
else:
|
2011-07-23 04:43:26 +08:00
|
|
|
if not self.open_conn():
|
2011-06-09 04:33:20 +08:00
|
|
|
self.emit("action-show-host", conn.get_uri())
|
2009-11-29 09:49:44 +08:00
|
|
|
|
|
|
|
def open_clone_window(self, ignore1=None, ignore2=None, ignore3=None):
|
|
|
|
if self.current_vmuuid():
|
2011-07-23 04:43:26 +08:00
|
|
|
self.emit("action-clone-domain", self.current_conn_uri(),
|
2009-11-29 09:49:44 +08:00
|
|
|
self.current_vmuuid())
|
|
|
|
|
|
|
|
def do_delete(self, ignore=None):
|
2011-07-23 04:43:26 +08:00
|
|
|
conn = self.current_conn()
|
2009-11-29 09:49:44 +08:00
|
|
|
vm = self.current_vm()
|
|
|
|
if vm is None:
|
2011-07-23 04:43:26 +08:00
|
|
|
self._do_delete_conn(conn)
|
2009-11-29 09:49:44 +08:00
|
|
|
else:
|
2013-06-18 04:29:51 +08:00
|
|
|
self.emit("action-delete-domain", conn.get_uri(), vm.get_uuid())
|
2009-11-29 09:49:44 +08:00
|
|
|
|
2011-07-23 04:43:26 +08:00
|
|
|
def _do_delete_conn(self, conn):
|
2009-11-29 09:49:44 +08:00
|
|
|
if conn is None:
|
|
|
|
return
|
|
|
|
|
|
|
|
result = self.err.yes_no(_("This will remove the connection:\n\n%s\n\n"
|
|
|
|
"Are you sure?") % conn.get_uri())
|
|
|
|
if not result:
|
|
|
|
return
|
2011-07-23 01:42:20 +08:00
|
|
|
|
2011-07-23 04:43:26 +08:00
|
|
|
self.emit("remove-conn", conn.get_uri())
|
2009-11-29 09:49:44 +08:00
|
|
|
|
|
|
|
def set_pause_state(self, state):
|
2011-07-15 01:13:13 +08:00
|
|
|
src = self.widget("vm-pause")
|
2009-11-29 09:49:44 +08:00
|
|
|
try:
|
|
|
|
self.ignore_pause = True
|
|
|
|
src.set_active(state)
|
|
|
|
finally:
|
|
|
|
self.ignore_pause = False
|
|
|
|
|
|
|
|
def pause_vm_button(self, src):
|
|
|
|
if self.ignore_pause:
|
|
|
|
return
|
|
|
|
|
|
|
|
do_pause = src.get_active()
|
|
|
|
|
2011-04-16 02:49:58 +08:00
|
|
|
# Set button state back to original value: just let the status
|
|
|
|
# update function fix things for us
|
|
|
|
self.set_pause_state(not do_pause)
|
|
|
|
|
2009-11-29 09:49:44 +08:00
|
|
|
if do_pause:
|
|
|
|
self.pause_vm(None)
|
|
|
|
else:
|
|
|
|
self.resume_vm(None)
|
|
|
|
|
|
|
|
def start_vm(self, ignore):
|
|
|
|
vm = self.current_vm()
|
|
|
|
if vm is not None:
|
|
|
|
self.emit("action-run-domain",
|
2011-07-23 04:43:26 +08:00
|
|
|
vm.conn.get_uri(), vm.get_uuid())
|
2009-11-29 09:49:44 +08:00
|
|
|
|
|
|
|
def reboot_vm(self, ignore):
|
|
|
|
vm = self.current_vm()
|
|
|
|
if vm is not None:
|
|
|
|
self.emit("action-reboot-domain",
|
2011-07-23 04:43:26 +08:00
|
|
|
vm.conn.get_uri(), vm.get_uuid())
|
2009-11-29 09:49:44 +08:00
|
|
|
|
|
|
|
def poweroff_vm(self, ignore):
|
|
|
|
vm = self.current_vm()
|
|
|
|
if vm is not None:
|
|
|
|
self.emit("action-shutdown-domain",
|
2011-07-23 04:43:26 +08:00
|
|
|
vm.conn.get_uri(), vm.get_uuid())
|
2009-11-29 09:49:44 +08:00
|
|
|
|
|
|
|
def destroy_vm(self, ignore):
|
|
|
|
vm = self.current_vm()
|
|
|
|
if vm is not None:
|
|
|
|
self.emit("action-destroy-domain",
|
2011-07-23 04:43:26 +08:00
|
|
|
vm.conn.get_uri(), vm.get_uuid())
|
2009-11-29 09:49:44 +08:00
|
|
|
|
2013-03-17 05:59:32 +08:00
|
|
|
def reset_vm(self, ignore):
|
|
|
|
vm = self.current_vm()
|
|
|
|
if vm is not None:
|
|
|
|
self.emit("action-reset-domain",
|
|
|
|
vm.conn.get_uri(), vm.get_uuid())
|
|
|
|
|
2010-05-12 23:42:59 +08:00
|
|
|
def save_vm(self, ignore):
|
|
|
|
vm = self.current_vm()
|
|
|
|
if vm is not None:
|
|
|
|
self.emit("action-save-domain",
|
2011-07-23 04:43:26 +08:00
|
|
|
vm.conn.get_uri(), vm.get_uuid())
|
2010-05-12 23:42:59 +08:00
|
|
|
|
2009-11-29 09:49:44 +08:00
|
|
|
def pause_vm(self, ignore):
|
|
|
|
vm = self.current_vm()
|
|
|
|
if vm is not None:
|
|
|
|
self.emit("action-suspend-domain",
|
2011-07-23 04:43:26 +08:00
|
|
|
vm.conn.get_uri(), vm.get_uuid())
|
2009-11-29 09:49:44 +08:00
|
|
|
|
|
|
|
def resume_vm(self, ignore):
|
|
|
|
vm = self.current_vm()
|
|
|
|
if vm is not None:
|
|
|
|
self.emit("action-resume-domain",
|
2011-07-23 04:43:26 +08:00
|
|
|
vm.conn.get_uri(), vm.get_uuid())
|
2009-11-29 09:49:44 +08:00
|
|
|
|
|
|
|
def migrate_vm(self, ignore):
|
|
|
|
vm = self.current_vm()
|
|
|
|
if vm is not None:
|
|
|
|
self.emit("action-migrate-domain",
|
2011-07-23 04:43:26 +08:00
|
|
|
vm.conn.get_uri(), vm.get_uuid())
|
2009-11-29 09:49:44 +08:00
|
|
|
|
2011-07-23 04:43:26 +08:00
|
|
|
def close_conn(self, ignore):
|
|
|
|
conn = self.current_conn()
|
2009-11-29 09:49:44 +08:00
|
|
|
if conn.get_state() != vmmConnection.STATE_DISCONNECTED:
|
|
|
|
conn.close()
|
|
|
|
|
2011-07-23 04:43:26 +08:00
|
|
|
def open_conn(self, ignore=None):
|
|
|
|
conn = self.current_conn()
|
2009-11-29 09:49:44 +08:00
|
|
|
if conn.get_state() == vmmConnection.STATE_DISCONNECTED:
|
|
|
|
conn.open()
|
|
|
|
return True
|
|
|
|
|
|
|
|
|
|
|
|
####################################
|
|
|
|
# VM add/remove management methods #
|
|
|
|
####################################
|
|
|
|
|
|
|
|
def vm_row_key(self, vm):
|
2011-07-23 04:43:26 +08:00
|
|
|
return vm.get_uuid() + ":" + vm.conn.get_uri()
|
2006-07-20 23:16:07 +08:00
|
|
|
|
2011-07-23 01:54:40 +08:00
|
|
|
def vm_added(self, conn, vmuuid):
|
|
|
|
vm = conn.get_vm(vmuuid)
|
2013-09-02 21:09:31 +08:00
|
|
|
vm.connect("config-changed", self.vm_config_changed)
|
2006-10-11 05:24:59 +08:00
|
|
|
vm.connect("status-changed", self.vm_status_changed)
|
2013-09-02 21:09:31 +08:00
|
|
|
vm.connect("resources-sampled", self.vm_row_updated)
|
2011-07-19 02:53:56 +08:00
|
|
|
vm.connect("inspection-changed", self.vm_inspection_changed)
|
2006-06-15 05:52:49 +08:00
|
|
|
|
2011-07-15 01:13:13 +08:00
|
|
|
vmlist = self.widget("vm-list")
|
2006-10-11 05:24:59 +08:00
|
|
|
model = vmlist.get_model()
|
2006-06-14 22:59:40 +08:00
|
|
|
|
2011-07-23 01:54:40 +08:00
|
|
|
self._append_vm(model, vm, conn)
|
2006-06-14 22:59:40 +08:00
|
|
|
|
2011-07-23 01:54:40 +08:00
|
|
|
def vm_removed(self, conn, vmuuid):
|
2011-07-15 01:13:13 +08:00
|
|
|
vmlist = self.widget("vm-list")
|
2009-11-29 09:49:44 +08:00
|
|
|
model = vmlist.get_model()
|
|
|
|
|
2011-07-23 01:54:40 +08:00
|
|
|
parent = self.rows[conn.get_uri()].iter
|
2009-11-29 09:49:44 +08:00
|
|
|
for row in range(model.iter_n_children(parent)):
|
|
|
|
vm = model.get_value(model.iter_nth_child(parent, row), ROW_HANDLE)
|
|
|
|
if vm.get_uuid() == vmuuid:
|
|
|
|
model.remove(model.iter_nth_child(parent, row))
|
|
|
|
del self.rows[self.vm_row_key(vm)]
|
|
|
|
break
|
|
|
|
|
2009-10-21 22:36:58 +08:00
|
|
|
def _build_conn_hint(self, conn):
|
|
|
|
hint = conn.get_uri()
|
|
|
|
if conn.state == conn.STATE_DISCONNECTED:
|
|
|
|
hint += " (%s)" % _("Double click to connect")
|
|
|
|
return hint
|
|
|
|
|
2013-09-02 06:36:58 +08:00
|
|
|
def _build_conn_markup(self, conn, name):
|
|
|
|
name = util.xml_escape(name)
|
2011-08-30 00:11:43 +08:00
|
|
|
text = name
|
2009-09-18 00:35:41 +08:00
|
|
|
if conn.state == conn.STATE_DISCONNECTED:
|
2011-08-30 00:11:43 +08:00
|
|
|
text += " - " + _("Not Connected")
|
2009-11-11 04:42:07 +08:00
|
|
|
elif conn.state == conn.STATE_CONNECTING:
|
2011-08-30 00:11:43 +08:00
|
|
|
text += " - " + _("Connecting...")
|
2010-12-02 04:22:38 +08:00
|
|
|
|
|
|
|
markup = "<span size='smaller'>%s</span>" % text
|
2009-09-18 00:35:41 +08:00
|
|
|
return markup
|
|
|
|
|
2009-11-11 04:42:07 +08:00
|
|
|
def _build_conn_color(self, conn):
|
2013-04-24 01:04:33 +08:00
|
|
|
color = "#000000"
|
2011-07-13 09:32:56 +08:00
|
|
|
if conn.state == conn.STATE_DISCONNECTED:
|
2013-04-24 01:04:33 +08:00
|
|
|
color = "#5b5b5b"
|
2009-11-11 04:42:07 +08:00
|
|
|
return color
|
|
|
|
|
2013-09-02 06:36:58 +08:00
|
|
|
def _build_vm_markup(self, name, status):
|
2010-12-02 04:22:38 +08:00
|
|
|
domtext = ("<span size='smaller' weight='bold'>%s</span>" %
|
2013-09-02 06:36:58 +08:00
|
|
|
util.xml_escape(name))
|
|
|
|
statetext = "<span size='smaller'>%s</span>" % status
|
2010-12-02 04:22:38 +08:00
|
|
|
return domtext + "\n" + statetext
|
2009-09-18 00:35:41 +08:00
|
|
|
|
2013-09-02 06:36:58 +08:00
|
|
|
def _build_row(self, conn, vm):
|
|
|
|
if conn:
|
|
|
|
name = conn.get_pretty_desc_inactive(False)
|
|
|
|
markup = self._build_conn_markup(conn, name)
|
|
|
|
status = ("<span size='smaller'>%s</span>" %
|
|
|
|
conn.get_state_text())
|
|
|
|
status_icon = None
|
|
|
|
hint = self._build_conn_hint(conn)
|
|
|
|
color = self._build_conn_color(conn)
|
|
|
|
os_icon = None
|
|
|
|
else:
|
|
|
|
name = vm.get_name()
|
|
|
|
status = vm.run_status()
|
|
|
|
markup = self._build_vm_markup(name, status)
|
|
|
|
status_icon = vm.run_status_icon_name()
|
|
|
|
hint = vm.get_description()
|
|
|
|
color = None
|
|
|
|
os_icon = _get_inspection_icon_pixbuf(vm, 16, 16)
|
2011-09-26 23:05:55 +08:00
|
|
|
|
2013-09-02 06:36:58 +08:00
|
|
|
row = []
|
|
|
|
row.insert(ROW_HANDLE, conn or vm)
|
|
|
|
row.insert(ROW_SORT_KEY, name)
|
|
|
|
row.insert(ROW_MARKUP, markup)
|
|
|
|
row.insert(ROW_STATUS_ICON, status_icon)
|
|
|
|
row.insert(ROW_HINT, util.xml_escape(hint))
|
|
|
|
row.insert(ROW_IS_CONN, bool(conn))
|
|
|
|
row.insert(ROW_IS_CONN_CONNECTED,
|
|
|
|
bool(conn) and conn.state != conn.STATE_DISCONNECTED)
|
|
|
|
row.insert(ROW_IS_VM, bool(vm))
|
|
|
|
row.insert(ROW_IS_VM_RUNNING, bool(vm) and vm.is_active())
|
|
|
|
row.insert(ROW_COLOR, color)
|
|
|
|
row.insert(ROW_INSPECTION_OS_ICON, os_icon)
|
2009-09-18 00:35:41 +08:00
|
|
|
|
2011-03-24 04:56:12 +08:00
|
|
|
return row
|
|
|
|
|
|
|
|
def _append_vm(self, model, vm, conn):
|
|
|
|
row_key = self.vm_row_key(vm)
|
|
|
|
if row_key in self.rows:
|
|
|
|
return
|
|
|
|
|
2013-09-02 06:36:58 +08:00
|
|
|
row = self._build_row(None, vm)
|
2011-03-24 04:56:12 +08:00
|
|
|
parent = self.rows[conn.get_uri()].iter
|
|
|
|
|
2008-11-19 04:42:51 +08:00
|
|
|
_iter = model.append(parent, row)
|
|
|
|
path = model.get_path(_iter)
|
2009-11-19 02:51:36 +08:00
|
|
|
self.rows[row_key] = model[path]
|
2011-03-24 04:56:12 +08:00
|
|
|
|
2007-08-15 00:31:24 +08:00
|
|
|
# Expand a connection when adding a vm to it
|
2011-07-15 01:13:13 +08:00
|
|
|
self.widget("vm-list").expand_row(model.get_path(parent), False)
|
2006-06-14 22:59:40 +08:00
|
|
|
|
2013-04-21 01:43:52 +08:00
|
|
|
def _append_conn(self, model, conn):
|
2013-09-02 06:36:58 +08:00
|
|
|
row = self._build_row(conn, None)
|
2013-04-21 01:43:52 +08:00
|
|
|
|
2008-11-19 04:42:51 +08:00
|
|
|
_iter = model.append(None, row)
|
|
|
|
path = model.get_path(_iter)
|
2007-09-10 10:57:24 +08:00
|
|
|
self.rows[conn.get_uri()] = model[path]
|
2009-02-16 06:36:36 +08:00
|
|
|
return _iter
|
2007-08-10 04:19:41 +08:00
|
|
|
|
2011-07-23 04:43:26 +08:00
|
|
|
def add_conn(self, engine_ignore, conn):
|
2010-03-03 09:35:54 +08:00
|
|
|
# Make sure error page isn't showing
|
2011-07-15 01:13:13 +08:00
|
|
|
self.widget("vm-notebook").set_current_page(0)
|
2010-03-03 09:35:54 +08:00
|
|
|
|
2010-12-11 00:47:07 +08:00
|
|
|
if conn.get_uri() in self.rows:
|
2009-11-29 09:49:44 +08:00
|
|
|
return
|
|
|
|
|
|
|
|
conn.connect("vm-added", self.vm_added)
|
|
|
|
conn.connect("vm-removed", self.vm_removed)
|
2013-09-02 21:09:31 +08:00
|
|
|
conn.connect("resources-sampled", self.conn_row_updated)
|
2009-11-29 09:49:44 +08:00
|
|
|
conn.connect("state-changed", self.conn_state_changed)
|
|
|
|
|
|
|
|
# add the connection to the treeModel
|
2011-07-15 01:13:13 +08:00
|
|
|
vmlist = self.widget("vm-list")
|
2011-07-23 04:43:26 +08:00
|
|
|
row = self._append_conn(vmlist.get_model(), conn)
|
2009-11-29 09:49:44 +08:00
|
|
|
vmlist.get_selection().select_iter(row)
|
2006-06-14 22:59:40 +08:00
|
|
|
|
2010-12-12 12:51:20 +08:00
|
|
|
# Try to make sure that 2 row descriptions don't collide
|
|
|
|
connrows = []
|
|
|
|
descs = []
|
|
|
|
for row in self.rows.values():
|
|
|
|
if row[ROW_IS_CONN]:
|
|
|
|
connrows.append(row)
|
|
|
|
for row in connrows:
|
2013-09-02 06:36:58 +08:00
|
|
|
descs.append(row[ROW_SORT_KEY])
|
2010-12-12 12:51:20 +08:00
|
|
|
|
|
|
|
for row in connrows:
|
|
|
|
conn = row[ROW_HANDLE]
|
2013-09-02 06:36:58 +08:00
|
|
|
name = row[ROW_SORT_KEY]
|
2010-12-12 12:51:20 +08:00
|
|
|
if descs.count(name) <= 1:
|
|
|
|
continue
|
|
|
|
|
|
|
|
newname = conn.get_pretty_desc_inactive(False, True)
|
2013-09-02 21:09:31 +08:00
|
|
|
self.conn_state_changed(conn, newname=newname)
|
2010-12-12 12:51:20 +08:00
|
|
|
|
2011-07-23 04:43:26 +08:00
|
|
|
def remove_conn(self, engine_ignore, uri):
|
2011-07-15 01:13:13 +08:00
|
|
|
model = self.widget("vm-list").get_model()
|
2011-04-12 23:50:10 +08:00
|
|
|
parent = self.rows[uri].iter
|
|
|
|
|
|
|
|
if parent is None:
|
|
|
|
return
|
|
|
|
|
|
|
|
child = model.iter_children(parent)
|
|
|
|
while child is not None:
|
|
|
|
del self.rows[self.vm_row_key(model.get_value(child, ROW_HANDLE))]
|
|
|
|
model.remove(child)
|
2009-11-29 09:49:44 +08:00
|
|
|
child = model.iter_children(parent)
|
2011-04-12 23:50:10 +08:00
|
|
|
model.remove(parent)
|
|
|
|
|
|
|
|
del self.rows[uri]
|
2009-11-29 09:49:44 +08:00
|
|
|
|
|
|
|
|
|
|
|
#############################
|
|
|
|
# State/UI updating methods #
|
|
|
|
#############################
|
2006-06-14 22:59:40 +08:00
|
|
|
|
2013-09-02 21:09:31 +08:00
|
|
|
def vm_row_updated(self, vm):
|
|
|
|
row = self.rows.get(self.vm_row_key(vm), None)
|
|
|
|
if row is None:
|
|
|
|
return
|
|
|
|
self.widget("vm-list").get_model().row_changed(row.path, row.iter)
|
2006-06-15 06:42:04 +08:00
|
|
|
|
2013-09-02 21:09:31 +08:00
|
|
|
def vm_config_changed(self, vm):
|
2013-09-02 06:36:58 +08:00
|
|
|
row = self.rows.get(self.vm_row_key(vm), None)
|
|
|
|
if row is None:
|
2006-11-14 04:38:10 +08:00
|
|
|
return
|
|
|
|
|
2013-08-16 21:59:33 +08:00
|
|
|
try:
|
2013-09-02 06:36:58 +08:00
|
|
|
name = vm.get_name()
|
|
|
|
status = vm.run_status()
|
|
|
|
|
|
|
|
row[ROW_SORT_KEY] = name
|
2013-08-16 21:59:33 +08:00
|
|
|
row[ROW_STATUS_ICON] = vm.run_status_icon_name()
|
|
|
|
row[ROW_IS_VM_RUNNING] = vm.is_active()
|
2013-09-02 06:36:58 +08:00
|
|
|
row[ROW_MARKUP] = self._build_vm_markup(name, status)
|
2013-08-16 21:59:33 +08:00
|
|
|
|
2013-09-02 21:09:31 +08:00
|
|
|
desc = vm.get_description()
|
|
|
|
if not uihelpers.can_set_row_none:
|
|
|
|
desc = desc or ""
|
|
|
|
row[ROW_HINT] = util.xml_escape(desc)
|
2013-08-16 21:59:33 +08:00
|
|
|
except libvirt.libvirtError, e:
|
|
|
|
if uihelpers.exception_is_libvirt_error(e, "VIR_ERR_NO_DOMAIN"):
|
|
|
|
return
|
|
|
|
raise
|
2011-07-16 03:38:59 +08:00
|
|
|
|
2013-09-02 21:09:31 +08:00
|
|
|
self.vm_row_updated(vm)
|
|
|
|
|
|
|
|
def vm_status_changed(self, vm, oldstatus, newstatus):
|
|
|
|
ignore = newstatus
|
|
|
|
ignore = oldstatus
|
|
|
|
parent = self.rows[vm.conn.get_uri()].iter
|
|
|
|
vmlist = self.widget("vm-list")
|
|
|
|
model = vmlist.get_model()
|
|
|
|
|
|
|
|
missing = True
|
|
|
|
for row in range(model.iter_n_children(parent)):
|
|
|
|
_iter = model.iter_nth_child(parent, row)
|
|
|
|
if model.get_value(_iter, ROW_HANDLE) == vm:
|
|
|
|
missing = False
|
|
|
|
break
|
|
|
|
|
|
|
|
if missing:
|
|
|
|
self._append_vm(model, vm, vm.conn)
|
|
|
|
|
|
|
|
# Update run/shutdown/pause button states
|
|
|
|
self.update_current_selection()
|
|
|
|
self.vm_config_changed(vm)
|
2006-06-14 22:59:40 +08:00
|
|
|
|
2011-07-19 02:53:56 +08:00
|
|
|
def vm_inspection_changed(self, vm):
|
2013-09-02 06:36:58 +08:00
|
|
|
row = self.rows.get(self.vm_row_key(vm), None)
|
|
|
|
if row is None:
|
2011-07-19 02:53:56 +08:00
|
|
|
return
|
|
|
|
|
2013-09-02 06:36:58 +08:00
|
|
|
new_icon = _get_inspection_icon_pixbuf(vm, 16, 16)
|
Initial snapshot support
This adds initial UI for managing snapshots: list, run/revert, delete,
add, and redefining (for changing <description>) supported, but currently
only for internal snapshots. The UI is mostly in its final form except for
some bells and whistles.
The real remaining question is what do we want to advertise and support.
Internal (qcow2) snapshots are by far the simplest to manage, very
mature, and already have the semantics we want.
However most recent libvirt and qemu work has been to facilitate
external snapshots, which are more extensible and can be performed
live, and with qemu-ga coordination for extra safety. However
they make things much harder for virt-manager at the moment.
Until we have a plan, this work should be considered experimental
and not be relied upon.
2013-08-02 22:18:47 +08:00
|
|
|
if not uihelpers.can_set_row_none:
|
inspection: Check can_set_row_none before setting icon to None.
Previously one could set the icon field of a tree model to None, but
with Gtk3 and older versions of pygobject3 this would fail.
Use can_set_row_none to test for this condition and work around it.
The previous traceback was:
Traceback (most recent call last):
File "/home/rjones/d/virt-manager/virtManager/manager.py", line 981, in vm_inspection_changed
self.get_inspection_icon_pixbuf(vm, 16, 16)
File "/usr/lib64/python2.7/site-packages/gi/overrides/Gtk.py", line 1152, in __setitem__
self.model.set_value(self.iter, key, value)
File "/usr/lib64/python2.7/site-packages/gi/overrides/Gtk.py", line 1298, in set_value
Gtk.TreeStore.set_value(self, treeiter, column, value)
File "/usr/lib64/python2.7/site-packages/gi/types.py", line 47, in function
return info.invoke(*args, **kwargs)
TypeError: Argument 3 does not allow None as a value
2013-06-29 01:45:53 +08:00
|
|
|
new_icon = new_icon or ""
|
|
|
|
row[ROW_INSPECTION_OS_ICON] = new_icon
|
2013-06-14 04:10:28 +08:00
|
|
|
|
2013-09-02 21:09:31 +08:00
|
|
|
self.vm_row_updated(vm)
|
2008-01-03 06:55:26 +08:00
|
|
|
|
2013-09-02 21:09:31 +08:00
|
|
|
def conn_state_changed(self, conn, newname=None):
|
2007-09-10 10:57:24 +08:00
|
|
|
row = self.rows[conn.get_uri()]
|
2010-12-12 12:51:20 +08:00
|
|
|
if newname:
|
2013-09-02 06:36:58 +08:00
|
|
|
row[ROW_SORT_KEY] = newname
|
|
|
|
row[ROW_MARKUP] = self._build_conn_markup(conn, row[ROW_SORT_KEY])
|
2009-07-29 07:21:56 +08:00
|
|
|
row[ROW_IS_CONN_CONNECTED] = conn.state != conn.STATE_DISCONNECTED
|
2009-11-29 09:49:44 +08:00
|
|
|
row[ROW_COLOR] = self._build_conn_color(conn)
|
2011-07-16 03:38:59 +08:00
|
|
|
row[ROW_HINT] = self._build_conn_hint(conn)
|
2006-08-09 05:02:15 +08:00
|
|
|
|
2009-11-29 09:49:44 +08:00
|
|
|
if conn.get_state() in [vmmConnection.STATE_DISCONNECTED,
|
|
|
|
vmmConnection.STATE_CONNECTING]:
|
|
|
|
# Connection went inactive, delete any VM child nodes
|
2013-09-02 21:09:31 +08:00
|
|
|
parent = row.iter
|
2009-11-29 09:49:44 +08:00
|
|
|
if parent is not None:
|
2013-09-02 21:09:31 +08:00
|
|
|
model = self.widget("vm-list").get_model()
|
2009-11-29 09:49:44 +08:00
|
|
|
child = model.iter_children(parent)
|
|
|
|
while child is not None:
|
2013-09-02 21:09:31 +08:00
|
|
|
vm = model[child][ROW_HANDLE]
|
|
|
|
del self.rows[self.vm_row_key(vm)]
|
2009-11-29 09:49:44 +08:00
|
|
|
model.remove(child)
|
|
|
|
child = model.iter_children(parent)
|
2011-07-26 03:09:42 +08:00
|
|
|
|
2013-09-02 21:09:31 +08:00
|
|
|
self.conn_row_updated(conn)
|
|
|
|
self.update_current_selection()
|
|
|
|
|
|
|
|
def conn_row_updated(self, conn):
|
|
|
|
row = self.rows[conn.get_uri()]
|
|
|
|
|
2011-07-26 03:09:42 +08:00
|
|
|
self.max_disk_rate = max(self.max_disk_rate, conn.disk_io_max_rate())
|
|
|
|
self.max_net_rate = max(self.max_net_rate,
|
|
|
|
conn.network_traffic_max_rate())
|
|
|
|
|
2013-09-02 21:09:31 +08:00
|
|
|
self.widget("vm-list").get_model().row_changed(row.path, row.iter)
|
2006-06-14 22:59:40 +08:00
|
|
|
|
2010-05-13 00:57:32 +08:00
|
|
|
def change_run_text(self, can_restore):
|
|
|
|
if can_restore:
|
|
|
|
text = _("_Restore")
|
|
|
|
else:
|
|
|
|
text = _("_Run")
|
|
|
|
strip_text = text.replace("_", "")
|
|
|
|
|
|
|
|
self.vmmenu_items["run"].get_child().set_label(text)
|
2011-07-15 01:13:13 +08:00
|
|
|
self.widget("vm-run").set_label(strip_text)
|
2006-06-14 22:59:40 +08:00
|
|
|
|
2013-09-02 21:09:31 +08:00
|
|
|
def update_current_selection(self, ignore=None):
|
2007-08-10 04:19:41 +08:00
|
|
|
vm = self.current_vm()
|
2009-07-27 04:15:05 +08:00
|
|
|
|
|
|
|
show_open = bool(vm)
|
|
|
|
show_details = bool(vm)
|
2010-08-23 00:50:31 +08:00
|
|
|
host_details = bool(len(self.rows))
|
|
|
|
|
2009-07-27 04:15:05 +08:00
|
|
|
show_run = bool(vm and vm.is_runable())
|
|
|
|
is_paused = bool(vm and vm.is_paused())
|
|
|
|
if is_paused:
|
|
|
|
show_pause = bool(vm and vm.is_unpauseable())
|
2007-08-10 04:19:41 +08:00
|
|
|
else:
|
2009-07-27 04:15:05 +08:00
|
|
|
show_pause = bool(vm and vm.is_pauseable())
|
|
|
|
show_shutdown = bool(vm and vm.is_stoppable())
|
|
|
|
|
2010-05-13 00:57:32 +08:00
|
|
|
if vm and vm.managedsave_supported:
|
|
|
|
self.change_run_text(vm.hasSavedImage())
|
|
|
|
|
2011-07-15 01:13:13 +08:00
|
|
|
self.widget("vm-open").set_sensitive(show_open)
|
|
|
|
self.widget("vm-run").set_sensitive(show_run)
|
|
|
|
self.widget("vm-shutdown").set_sensitive(show_shutdown)
|
2009-07-27 04:15:05 +08:00
|
|
|
self.set_pause_state(is_paused)
|
2011-07-15 01:13:13 +08:00
|
|
|
self.widget("vm-pause").set_sensitive(show_pause)
|
2009-07-27 04:15:05 +08:00
|
|
|
|
2011-07-15 01:13:13 +08:00
|
|
|
self.widget("menu_edit_details").set_sensitive(show_details)
|
|
|
|
self.widget("menu_host_details").set_sensitive(host_details)
|
2009-07-27 04:15:05 +08:00
|
|
|
|
2010-12-10 00:22:35 +08:00
|
|
|
def popup_vm_menu_key(self, widget_ignore, event):
|
2012-05-14 21:24:56 +08:00
|
|
|
if Gdk.keyval_name(event.keyval) != "Menu":
|
2009-11-11 22:49:34 +08:00
|
|
|
return False
|
|
|
|
|
2011-07-15 01:13:13 +08:00
|
|
|
vmlist = self.widget("vm-list")
|
2009-11-11 22:49:34 +08:00
|
|
|
treeselection = vmlist.get_selection()
|
|
|
|
model, _iter = treeselection.get_selected()
|
|
|
|
self.popup_vm_menu(model, _iter, event)
|
|
|
|
return True
|
2007-08-14 05:13:39 +08:00
|
|
|
|
2009-11-11 22:49:34 +08:00
|
|
|
def popup_vm_menu_button(self, widget, event):
|
2009-11-11 05:01:56 +08:00
|
|
|
if event.button != 3:
|
|
|
|
return False
|
|
|
|
|
2008-11-19 04:42:51 +08:00
|
|
|
tup = widget.get_path_at_pos(int(event.x), int(event.y))
|
2012-11-08 21:15:02 +08:00
|
|
|
if tup is None:
|
2007-08-24 05:46:30 +08:00
|
|
|
return False
|
2008-11-19 04:42:51 +08:00
|
|
|
path = tup[0]
|
2007-08-24 05:46:30 +08:00
|
|
|
model = widget.get_model()
|
2008-11-19 04:42:51 +08:00
|
|
|
_iter = model.get_iter(path)
|
2009-11-11 05:01:56 +08:00
|
|
|
|
2009-11-11 22:49:34 +08:00
|
|
|
self.popup_vm_menu(model, _iter, event)
|
2009-12-10 00:28:38 +08:00
|
|
|
return False
|
2009-11-11 22:49:34 +08:00
|
|
|
|
|
|
|
def popup_vm_menu(self, model, _iter, event):
|
2012-11-08 21:15:02 +08:00
|
|
|
if model.iter_parent(_iter) is not None:
|
2009-11-11 05:01:56 +08:00
|
|
|
# Popup the vm menu
|
2008-11-19 04:42:51 +08:00
|
|
|
vm = model.get_value(_iter, ROW_HANDLE)
|
2009-11-11 05:01:56 +08:00
|
|
|
|
|
|
|
destroy = vm.is_destroyable()
|
|
|
|
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)
|
2013-09-02 08:18:14 +08:00
|
|
|
self.vmmenu_items["pause"].set_visible(not paused)
|
2009-11-11 05:01:56 +08:00
|
|
|
self.vmmenu_items["pause"].set_sensitive(stop)
|
2013-09-02 08:18:14 +08:00
|
|
|
self.vmmenu_items["resume"].set_visible(paused)
|
2009-11-11 05:01:56 +08:00
|
|
|
self.vmmenu_items["resume"].set_sensitive(paused)
|
2009-11-16 04:29:42 +08:00
|
|
|
self.vmmenu_items["migrate"].set_sensitive(stop)
|
2009-11-11 05:01:56 +08:00
|
|
|
self.vmmenu_items["clone"].set_sensitive(not ro)
|
|
|
|
|
|
|
|
self.vmmenushutdown_items["poweroff"].set_sensitive(stop)
|
|
|
|
self.vmmenushutdown_items["reboot"].set_sensitive(stop)
|
|
|
|
self.vmmenushutdown_items["forcepoweroff"].set_sensitive(destroy)
|
2010-05-12 23:42:59 +08:00
|
|
|
self.vmmenushutdown_items["save"].set_sensitive(destroy)
|
2012-05-14 21:24:56 +08:00
|
|
|
self.vmmenu.popup(None, None, None, None, 0, event.time)
|
2007-08-24 05:46:30 +08:00
|
|
|
else:
|
2009-11-11 05:01:56 +08:00
|
|
|
# Pop up connection menu
|
2008-11-19 04:42:51 +08:00
|
|
|
conn = model.get_value(_iter, ROW_HANDLE)
|
2009-11-11 05:01:56 +08:00
|
|
|
disconn = (conn.get_state() == vmmConnection.STATE_DISCONNECTED)
|
|
|
|
conning = (conn.get_state() == vmmConnection.STATE_CONNECTING)
|
|
|
|
|
|
|
|
self.connmenu_items["create"].set_sensitive(not disconn)
|
|
|
|
self.connmenu_items["disconnect"].set_sensitive(not (disconn or
|
|
|
|
conning))
|
|
|
|
self.connmenu_items["connect"].set_sensitive(disconn)
|
2009-11-17 05:35:34 +08:00
|
|
|
self.connmenu_items["delete"].set_sensitive(disconn)
|
2009-11-11 05:01:56 +08:00
|
|
|
|
2012-05-14 21:24:56 +08:00
|
|
|
self.connmenu.popup(None, None, None, None, 0, event.time)
|
2009-11-11 05:01:56 +08:00
|
|
|
|
2009-11-12 00:02:57 +08:00
|
|
|
|
2009-11-29 09:49:44 +08:00
|
|
|
#################
|
|
|
|
# Stats methods #
|
|
|
|
#################
|
2006-06-14 22:59:40 +08:00
|
|
|
|
2012-05-14 21:24:56 +08:00
|
|
|
def vmlist_name_sorter(self, model, iter1, iter2, ignore):
|
2013-09-02 06:36:58 +08:00
|
|
|
return cmp(model.get_value(iter1, ROW_SORT_KEY),
|
|
|
|
model.get_value(iter2, ROW_SORT_KEY))
|
2006-06-14 22:59:40 +08:00
|
|
|
|
2012-05-14 21:24:56 +08:00
|
|
|
def vmlist_guest_cpu_usage_sorter(self, model, iter1, iter2, ignore):
|
2011-07-12 20:49:47 +08:00
|
|
|
obj1 = model.get_value(iter1, ROW_HANDLE)
|
|
|
|
obj2 = model.get_value(iter2, ROW_HANDLE)
|
|
|
|
|
|
|
|
return cmp(obj1.guest_cpu_time_percentage(),
|
|
|
|
obj2.guest_cpu_time_percentage())
|
|
|
|
|
2012-05-14 21:24:56 +08:00
|
|
|
def vmlist_host_cpu_usage_sorter(self, model, iter1, iter2, ignore):
|
2011-07-12 09:22:50 +08:00
|
|
|
obj1 = model.get_value(iter1, ROW_HANDLE)
|
|
|
|
obj2 = model.get_value(iter2, ROW_HANDLE)
|
|
|
|
|
|
|
|
return cmp(obj1.host_cpu_time_percentage(),
|
|
|
|
obj2.host_cpu_time_percentage())
|
2006-06-14 22:59:40 +08:00
|
|
|
|
2012-05-14 21:24:56 +08:00
|
|
|
def vmlist_disk_io_sorter(self, model, iter1, iter2, ignore):
|
2011-07-12 09:22:50 +08:00
|
|
|
obj1 = model.get_value(iter1, ROW_HANDLE)
|
|
|
|
obj2 = model.get_value(iter2, ROW_HANDLE)
|
|
|
|
|
|
|
|
return cmp(obj1.disk_io_rate(), obj2.disk_io_rate())
|
2006-06-14 22:59:40 +08:00
|
|
|
|
2012-05-14 21:24:56 +08:00
|
|
|
def vmlist_network_usage_sorter(self, model, iter1, iter2, ignore):
|
2011-07-12 09:22:50 +08:00
|
|
|
obj1 = model.get_value(iter1, ROW_HANDLE)
|
|
|
|
obj2 = model.get_value(iter2, ROW_HANDLE)
|
|
|
|
|
|
|
|
return cmp(obj1.network_traffic_rate(), obj2.network_traffic_rate())
|
2006-06-14 22:59:40 +08:00
|
|
|
|
2013-04-18 05:39:25 +08:00
|
|
|
def enable_polling(self, column):
|
|
|
|
if column == COL_DISK:
|
2009-07-27 04:15:28 +08:00
|
|
|
widgn = "menu_view_stats_disk"
|
2013-04-18 05:39:25 +08:00
|
|
|
do_enable = self.config.get_stats_enable_disk_poll()
|
|
|
|
elif column == COL_NETWORK:
|
2009-07-27 04:15:28 +08:00
|
|
|
widgn = "menu_view_stats_network"
|
2013-04-18 05:39:25 +08:00
|
|
|
do_enable = self.config.get_stats_enable_net_poll()
|
2011-07-15 01:13:13 +08:00
|
|
|
widget = self.widget(widgn)
|
2008-12-18 04:27:06 +08:00
|
|
|
|
2009-01-27 00:12:43 +08:00
|
|
|
tool_text = ""
|
2010-12-14 05:24:49 +08:00
|
|
|
|
2013-04-18 05:39:25 +08:00
|
|
|
if do_enable:
|
2008-12-18 04:27:06 +08:00
|
|
|
widget.set_sensitive(True)
|
|
|
|
else:
|
|
|
|
if widget.get_active():
|
|
|
|
widget.set_active(False)
|
|
|
|
widget.set_sensitive(False)
|
2009-01-27 00:12:43 +08:00
|
|
|
tool_text = _("Disabled in preferences dialog.")
|
|
|
|
|
2012-02-02 06:26:46 +08:00
|
|
|
widget.set_tooltip_text(tool_text)
|
2011-02-16 00:38:35 +08:00
|
|
|
|
2012-02-02 06:26:46 +08:00
|
|
|
disabled_text = _(" (disabled)")
|
|
|
|
current_text = widget.get_label().strip(disabled_text)
|
|
|
|
if tool_text:
|
|
|
|
current_text = current_text + disabled_text
|
|
|
|
widget.set_label(current_text)
|
2008-12-18 04:27:06 +08:00
|
|
|
|
2013-09-02 09:35:23 +08:00
|
|
|
def _toggle_graph_helper(self, do_show, col, datafunc, menu):
|
|
|
|
img = -1
|
|
|
|
for child in col.get_cells():
|
|
|
|
if isinstance(child, CellRendererSparkline):
|
|
|
|
img = child
|
|
|
|
datafunc = do_show and datafunc or None
|
2009-07-27 04:15:28 +08:00
|
|
|
|
2013-09-02 09:35:23 +08:00
|
|
|
col.set_cell_data_func(img, datafunc, None)
|
|
|
|
col.set_visible(do_show)
|
|
|
|
self.widget(menu).set_active(do_show)
|
2011-07-12 20:49:47 +08:00
|
|
|
|
2013-09-02 22:43:53 +08:00
|
|
|
any_visible = any([col.get_visible() for col in
|
|
|
|
[self.netcol, self.diskcol, self.guestcpucol, self.hostcpucol]])
|
|
|
|
self.spacer_txt.set_property("visible", not any_visible)
|
|
|
|
|
2013-09-02 09:35:23 +08:00
|
|
|
def toggle_network_traffic_visible_widget(self):
|
|
|
|
self._toggle_graph_helper(
|
|
|
|
self.config.is_vmlist_network_traffic_visible(), self.netcol,
|
|
|
|
self.network_traffic_img, "menu_view_stats_network")
|
|
|
|
def toggle_disk_io_visible_widget(self):
|
|
|
|
self._toggle_graph_helper(
|
|
|
|
self.config.is_vmlist_disk_io_visible(), self.diskcol,
|
|
|
|
self.disk_io_img, "menu_view_stats_disk")
|
2013-04-18 05:39:25 +08:00
|
|
|
def toggle_guest_cpu_usage_visible_widget(self):
|
2013-09-02 09:35:23 +08:00
|
|
|
self._toggle_graph_helper(
|
|
|
|
self.config.is_vmlist_guest_cpu_usage_visible(), self.guestcpucol,
|
|
|
|
self.guest_cpu_usage_img, "menu_view_stats_guest_cpu")
|
2013-04-18 05:39:25 +08:00
|
|
|
def toggle_host_cpu_usage_visible_widget(self):
|
2013-09-02 09:35:23 +08:00
|
|
|
self._toggle_graph_helper(
|
|
|
|
self.config.is_vmlist_host_cpu_usage_visible(), self.hostcpucol,
|
|
|
|
self.host_cpu_usage_img, "menu_view_stats_host_cpu")
|
2009-11-12 00:02:57 +08:00
|
|
|
|
|
|
|
def toggle_stats_visible(self, src, stats_id):
|
|
|
|
visible = src.get_active()
|
|
|
|
set_stats = {
|
2011-07-12 20:49:47 +08:00
|
|
|
COL_GUEST_CPU: self.config.set_vmlist_guest_cpu_usage_visible,
|
|
|
|
COL_HOST_CPU: self.config.set_vmlist_host_cpu_usage_visible,
|
|
|
|
COL_DISK: self.config.set_vmlist_disk_io_visible,
|
|
|
|
COL_NETWORK: self.config.set_vmlist_network_traffic_visible,
|
2009-11-12 00:02:57 +08:00
|
|
|
}
|
|
|
|
set_stats[stats_id](visible)
|
2006-06-14 22:59:40 +08:00
|
|
|
|
2012-05-14 21:24:56 +08:00
|
|
|
def toggle_stats_visible_guest_cpu(self, src):
|
|
|
|
self.toggle_stats_visible(src, COL_GUEST_CPU)
|
|
|
|
def toggle_stats_visible_host_cpu(self, src):
|
|
|
|
self.toggle_stats_visible(src, COL_HOST_CPU)
|
|
|
|
def toggle_stats_visible_disk(self, src):
|
|
|
|
self.toggle_stats_visible(src, COL_DISK)
|
|
|
|
def toggle_stats_visible_network(self, src):
|
|
|
|
self.toggle_stats_visible(src, COL_NETWORK)
|
|
|
|
|
2011-07-12 20:49:47 +08:00
|
|
|
def guest_cpu_usage_img(self, column_ignore, cell, model, _iter, data):
|
2013-09-02 09:35:23 +08:00
|
|
|
obj = model[_iter][ROW_HANDLE]
|
2012-05-14 21:24:56 +08:00
|
|
|
if obj is None or not hasattr(obj, "conn"):
|
2011-07-12 20:49:47 +08:00
|
|
|
return
|
|
|
|
|
2012-05-14 21:24:56 +08:00
|
|
|
data = obj.guest_cpu_time_vector_limit(GRAPH_LEN)
|
2011-07-12 20:49:47 +08:00
|
|
|
cell.set_property('data_array', data)
|
|
|
|
|
|
|
|
def host_cpu_usage_img(self, column_ignore, cell, model, _iter, data):
|
2013-09-02 09:35:23 +08:00
|
|
|
obj = model[_iter][ROW_HANDLE]
|
2012-05-14 21:24:56 +08:00
|
|
|
if obj is None or not hasattr(obj, "conn"):
|
2007-08-15 04:28:36 +08:00
|
|
|
return
|
2011-07-12 09:22:50 +08:00
|
|
|
|
2012-05-14 21:24:56 +08:00
|
|
|
data = obj.host_cpu_time_vector_limit(GRAPH_LEN)
|
2008-10-19 03:28:57 +08:00
|
|
|
cell.set_property('data_array', data)
|
|
|
|
|
2010-12-10 00:22:35 +08:00
|
|
|
def disk_io_img(self, column_ignore, cell, model, _iter, data):
|
2013-09-02 09:35:23 +08:00
|
|
|
obj = model[_iter][ROW_HANDLE]
|
2012-05-14 21:24:56 +08:00
|
|
|
if obj is None or not hasattr(obj, "conn"):
|
2011-07-26 03:09:42 +08:00
|
|
|
return
|
|
|
|
|
2012-05-14 21:24:56 +08:00
|
|
|
data = obj.disk_io_vector_limit(GRAPH_LEN, self.max_disk_rate)
|
2008-10-19 03:28:57 +08:00
|
|
|
cell.set_property('data_array', data)
|
|
|
|
|
2010-12-10 00:22:35 +08:00
|
|
|
def network_traffic_img(self, column_ignore, cell, model, _iter, data):
|
2013-09-02 09:35:23 +08:00
|
|
|
obj = model[_iter][ROW_HANDLE]
|
2012-05-14 21:24:56 +08:00
|
|
|
if obj is None or not hasattr(obj, "conn"):
|
2011-07-26 03:09:42 +08:00
|
|
|
return
|
|
|
|
|
2012-05-14 21:24:56 +08:00
|
|
|
data = obj.network_traffic_vector_limit(GRAPH_LEN, self.max_net_rate)
|
2006-06-27 05:17:45 +08:00
|
|
|
cell.set_property('data_array', data)
|