Files
virt-manager/virtManager/uihelpers.py
Cole Robinson be2d9ddcb4 Add base conn object and bump minimum libvirt version to 0.6.0
This base connection object will be used to simplify the API in various
places, reduce libvirt API calls, and better share code between virtinst
and virt-manager. For now it just centralizes connection opening.

This also exposed various places where our handling for older libvirt
was busted, so raise our minimum host version to 0.6.0, the first
version that supports threaded client requests.
2013-07-05 16:42:19 -04:00

1072 lines
32 KiB
Python

#
# Copyright (C) 2009, 2013 Red Hat, Inc.
# Copyright (C) 2009 Cole Robinson <crobinso@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
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
# MA 02110-1301 USA.
#
import logging
import os
import statvfs
# pylint: disable=E0611
from gi.repository import Gtk
# pylint: enable=E0611
import virtinst
from virtinst import VirtualNetworkInterface
from virtinst import VirtualDisk
from virtManager import util
from virtManager.error import vmmErrorDialog
OPTICAL_DEV_PATH = 0
OPTICAL_LABEL = 1
OPTICAL_IS_MEDIA_PRESENT = 2
OPTICAL_DEV_KEY = 3
OPTICAL_MEDIA_KEY = 4
OPTICAL_IS_VALID = 5
##############################################################
# Initialize an error object to use for validation functions #
##############################################################
err_dial = vmmErrorDialog()
def set_error_parent(parent):
global err_dial
err_dial.set_parent(parent)
err_dial = err_dial
def cleanup():
global err_dial
err_dial = None
def spin_get_helper(widget):
adj = widget.get_adjustment()
txt = widget.get_text()
try:
ret = int(txt)
except:
ret = adj.get_value()
return ret
############################################################
# Helpers for shared storage UI between create/addhardware #
############################################################
def set_sparse_tooltip(widget):
sparse_str = _("Fully allocating storage may take longer now, "
"but the OS install phase will be quicker. \n\n"
"Skipping allocation can also cause space issues on "
"the host machine, if the maximum image size exceeds "
"available storage space. \n\n"
"Tip: Storage format qcow2 and qed "
"do not support full allocation.")
widget.set_tooltip_text(sparse_str)
def host_disk_space(conn):
pool = util.get_default_pool(conn)
path = util.get_default_dir(conn)
avail = 0
if pool and pool.is_active():
# FIXME: make sure not inactive?
# FIXME: use a conn specific function after we send pool-added
pool.refresh()
avail = int(util.xpath(pool.get_xml(), "/pool/available"))
elif not conn.is_remote() and os.path.exists(path):
vfs = os.statvfs(os.path.dirname(path))
avail = vfs[statvfs.F_FRSIZE] * vfs[statvfs.F_BAVAIL]
return float(avail / 1024.0 / 1024.0 / 1024.0)
def host_space_tick(conn, widget):
try:
max_storage = host_disk_space(conn)
except:
logging.exception("Error determining host disk space")
return 0
def pretty_storage(size):
return "%.1f Gb" % float(size)
hd_label = ("%s available in the default location" %
pretty_storage(max_storage))
hd_label = ("<span color='#484848'>%s</span>" % hd_label)
widget.set_markup(hd_label)
return 1
def check_default_pool_active(topwin, conn):
default_pool = util.get_default_pool(conn)
if default_pool and not default_pool.is_active():
res = err_dial.yes_no(_("Default pool is not active."),
_("Storage pool '%s' is not active. "
"Would you like to start the pool "
"now?") % default_pool.get_name())
if not res:
return False
# Try to start the pool
try:
default_pool.start()
logging.info("Started pool '%s'", default_pool.get_name())
except Exception, e:
return topwin.err.show_err(_("Could not start storage_pool "
"'%s': %s") %
(default_pool.get_name(), str(e)))
return True
#####################################################
# Hardware model list building (for details, addhw) #
#####################################################
def build_video_combo(vm, video_dev, no_default=None):
video_dev_model = Gtk.ListStore(str, str)
video_dev.set_model(video_dev_model)
text = Gtk.CellRendererText()
video_dev.pack_start(text, True)
video_dev.add_attribute(text, 'text', 1)
video_dev_model.set_sort_column_id(1, Gtk.SortType.ASCENDING)
populate_video_combo(vm, video_dev, no_default)
def populate_video_combo(vm, video_dev, no_default=None):
video_dev_model = video_dev.get_model()
has_spice = bool([g for g in vm.get_graphics_devices()
if g.type == g.TYPE_SPICE])
has_qxl = bool([v for v in vm.get_video_devices()
if v.model_type == "qxl"])
video_dev_model.clear()
tmpdev = virtinst.VirtualVideoDevice(vm.conn.get_backend())
for m in tmpdev.model_types:
if not vm.rhel6_defaults():
if m == "qxl" and not has_spice and not has_qxl:
# Only list QXL video option when VM has SPICE video
continue
if m == tmpdev.MODEL_DEFAULT and no_default:
continue
video_dev_model.append([m, tmpdev.pretty_model(m)])
if len(video_dev_model) > 0:
video_dev.set_active(0)
def build_sound_combo(vm, combo, no_default=False):
dev_model = Gtk.ListStore(str)
combo.set_model(dev_model)
text = Gtk.CellRendererText()
combo.pack_start(text, True)
combo.add_attribute(text, 'text', 0)
dev_model.set_sort_column_id(0, Gtk.SortType.ASCENDING)
disable_rhel = not vm.rhel6_defaults()
rhel_soundmodels = ["ich6", "ac97"]
for m in virtinst.VirtualAudio.MODELS:
if m == virtinst.VirtualAudio.MODEL_DEFAULT and no_default:
continue
if (disable_rhel and m not in rhel_soundmodels):
continue
dev_model.append([m])
if len(dev_model) > 0:
combo.set_active(0)
def build_watchdogmodel_combo(vm, combo, no_default=False):
ignore = vm
dev_model = Gtk.ListStore(str)
combo.set_model(dev_model)
text = Gtk.CellRendererText()
combo.pack_start(text, True)
combo.add_attribute(text, 'text', 0)
dev_model.set_sort_column_id(0, Gtk.SortType.ASCENDING)
for m in virtinst.VirtualWatchdog.MODELS:
if m == virtinst.VirtualAudio.MODEL_DEFAULT and no_default:
continue
dev_model.append([m])
if len(dev_model) > 0:
combo.set_active(0)
def build_watchdogaction_combo(vm, combo, no_default=False):
ignore = vm
dev_model = Gtk.ListStore(str, str)
combo.set_model(dev_model)
text = Gtk.CellRendererText()
combo.pack_start(text, True)
combo.add_attribute(text, 'text', 1)
dev_model.set_sort_column_id(0, Gtk.SortType.ASCENDING)
for m in virtinst.VirtualWatchdog.ACTIONS:
if m == virtinst.VirtualWatchdog.ACTION_DEFAULT and no_default:
continue
dev_model.append([m, virtinst.VirtualWatchdog.get_action_desc(m)])
if len(dev_model) > 0:
combo.set_active(0)
def build_source_mode_combo(vm, combo):
source_mode = Gtk.ListStore(str, str)
combo.set_model(source_mode)
text = Gtk.CellRendererText()
combo.pack_start(text, True)
combo.add_attribute(text, 'text', 1)
populate_source_mode_combo(vm, combo)
combo.set_active(0)
def populate_source_mode_combo(vm, combo):
ignore = vm
model = combo.get_model()
model.clear()
# [xml value, label]
model.append([None, "Default"])
model.append(["vepa", "VEPA"])
model.append(["bridge", "Bridge"])
model.append(["private", "Private"])
model.append(["passthrough", "Passthrough"])
def build_smartcard_mode_combo(vm, combo):
dev_model = Gtk.ListStore(str, str)
combo.set_model(dev_model)
text = Gtk.CellRendererText()
combo.pack_start(text, True)
combo.add_attribute(text, 'text', 1)
dev_model.set_sort_column_id(0, Gtk.SortType.ASCENDING)
populate_smartcard_mode_combo(vm, combo)
idx = -1
for rowid in range(len(combo.get_model())):
idx = 0
row = combo.get_model()[rowid]
if row[0] == virtinst.VirtualSmartCardDevice.MODE_DEFAULT:
idx = rowid
break
combo.set_active(idx)
def populate_smartcard_mode_combo(vm, combo):
ignore = vm
model = combo.get_model()
model.clear()
# [xml value, label]
model.append(["passthrough", "Passthrough"])
model.append(["host", "Host"])
def build_redir_type_combo(vm, combo):
source_mode = Gtk.ListStore(str, str, bool)
combo.set_model(source_mode)
text = Gtk.CellRendererText()
combo.pack_start(text, True)
combo.add_attribute(text, 'text', 1)
populate_redir_type_combo(vm, combo)
combo.set_active(0)
def populate_redir_type_combo(vm, combo):
ignore = vm
model = combo.get_model()
model.clear()
# [xml value, label, conn details]
model.append(["spicevmc", "Spice channel", False])
model.append(["tcp", "TCP", True])
def build_tpm_type_combo(vm, combo):
dev_model = Gtk.ListStore(str, str)
combo.set_model(dev_model)
text = Gtk.CellRendererText()
combo.pack_start(text, True)
combo.add_attribute(text, 'text', 1)
dev_model.set_sort_column_id(0, Gtk.SortType.ASCENDING)
populate_tpm_type_combo(vm, combo)
idx = -1
for rowid in range(len(combo.get_model())):
idx = 0
row = combo.get_model()[rowid]
if row[0] == virtinst.VirtualTPMDevice.TYPE_DEFAULT:
idx = rowid
break
combo.set_active(idx)
def populate_tpm_type_combo(vm, combo):
ignore = vm
types = combo.get_model()
types.clear()
# [xml value, label]
types.append(["passthrough", "Passthrough device"])
def build_netmodel_combo(vm, combo):
dev_model = Gtk.ListStore(str, str)
combo.set_model(dev_model)
text = Gtk.CellRendererText()
combo.pack_start(text, True)
combo.add_attribute(text, 'text', 1)
dev_model.set_sort_column_id(0, Gtk.SortType.ASCENDING)
populate_netmodel_combo(vm, combo)
combo.set_active(0)
def populate_netmodel_combo(vm, combo):
model = combo.get_model()
model.clear()
# [xml value, label]
model.append([None, _("Hypervisor default")])
if vm.is_hvm():
mod_list = ["rtl8139", "ne2k_pci", "pcnet", "e1000"]
if vm.get_hv_type() in ["kvm", "qemu", "test"]:
mod_list.append("virtio")
if (vm.get_hv_type() == "kvm" and
vm.get_machtype() == "pseries"):
mod_list.append("spapr-vlan")
if vm.get_hv_type() in ["xen", "test"]:
mod_list.append("netfront")
mod_list.sort()
for m in mod_list:
model.append([m, m])
def build_cache_combo(vm, combo, no_default=False):
ignore = vm
dev_model = Gtk.ListStore(str, str)
combo.set_model(dev_model)
text = Gtk.CellRendererText()
combo.pack_start(text, True)
combo.add_attribute(text, 'text', 1)
dev_model.set_sort_column_id(0, Gtk.SortType.ASCENDING)
combo.set_active(-1)
for m in virtinst.VirtualDisk.cache_types:
dev_model.append([m, m])
if not no_default:
dev_model.append([None, "default"])
combo.set_active(0)
def build_io_combo(vm, combo, no_default=False):
ignore = vm
dev_model = Gtk.ListStore(str, str)
combo.set_model(dev_model)
text = Gtk.CellRendererText()
combo.pack_start(text, True)
combo.add_attribute(text, 'text', 1)
dev_model.set_sort_column_id(0, Gtk.SortType.ASCENDING)
combo.set_active(-1)
for m in virtinst.VirtualDisk.io_modes:
dev_model.append([m, m])
if not no_default:
dev_model.append([None, "default"])
combo.set_active(0)
def build_disk_bus_combo(vm, combo, no_default=False):
ignore = vm
dev_model = Gtk.ListStore(str, str)
combo.set_model(dev_model)
text = Gtk.CellRendererText()
combo.pack_start(text, True)
combo.add_attribute(text, 'text', 1)
dev_model.set_sort_column_id(0, Gtk.SortType.ASCENDING)
if not no_default:
dev_model.append([None, "default"])
combo.set_active(-1)
def build_vnc_keymap_combo(vm, combo, no_default=False):
ignore = vm
model = Gtk.ListStore(str, str)
combo.set_model(model)
text = Gtk.CellRendererText()
combo.pack_start(text, True)
combo.add_attribute(text, 'text', 1)
if not no_default:
model.append([None, "default"])
else:
model.append([None, "Auto"])
model.append([virtinst.VirtualGraphics.KEYMAP_LOCAL,
"Copy local keymap"])
for k in virtinst.VirtualGraphics.valid_keymaps():
model.append([k, k])
combo.set_active(-1)
#####################################
# Storage format list/combo helpers #
#####################################
def build_storage_format_combo(vm, combo):
dev_model = Gtk.ListStore(str)
combo.set_model(dev_model)
combo.set_entry_text_column(0)
formats = ["raw", "qcow2", "qed"]
if vm.rhel6_defaults():
formats.append("vmdk")
formats.append("vdi")
for m in formats:
dev_model.append([m])
combo.set_active(0)
#######################################################################
# Widgets for listing network device options (in create, addhardware) #
#######################################################################
def pretty_network_desc(nettype, source=None, netobj=None):
if nettype == VirtualNetworkInterface.TYPE_USER:
return _("Usermode networking")
extra = None
if nettype == VirtualNetworkInterface.TYPE_BRIDGE:
ret = _("Bridge")
elif nettype == VirtualNetworkInterface.TYPE_VIRTUAL:
ret = _("Virtual network")
if netobj:
extra = ": %s" % netobj.pretty_forward_mode()
else:
ret = nettype.capitalize()
if source:
ret += " '%s'" % source
if extra:
ret += " %s" % extra
return ret
def init_network_list(net_list, bridge_box,
source_mode_box=None, source_mode_label=None,
vport_expander=None):
# [ network type, source name, label, sensitive?, net is active,
# manual bridge, net instance]
net_model = Gtk.ListStore(str, str, str, bool, bool, bool, object)
net_list.set_model(net_model)
net_list.connect("changed", net_list_changed, bridge_box, source_mode_box,
source_mode_label, vport_expander)
text = Gtk.CellRendererText()
net_list.pack_start(text, True)
net_list.add_attribute(text, 'text', 2)
net_list.add_attribute(text, 'sensitive', 3)
def net_list_changed(net_list, bridge_box,
source_mode_box, source_mode_label, vport_expander):
active = net_list.get_active()
if active < 0:
return
if not bridge_box:
return
row = net_list.get_model()[active]
if source_mode_box is not None:
show_source_mode = (row[0] == VirtualNetworkInterface.TYPE_DIRECT)
source_mode_box.set_property("visible", show_source_mode)
source_mode_label.set_property("visible", show_source_mode)
vport_expander.set_property("visible", show_source_mode)
show_bridge = row[5]
bridge_box.set_property("visible", show_bridge)
def get_network_selection(net_list, bridge_entry):
idx = net_list.get_active()
if idx == -1:
return None, None
row = net_list.get_model()[net_list.get_active()]
net_type = row[0]
net_src = row[1]
net_check_bridge = row[5]
if net_check_bridge and bridge_entry:
net_type = VirtualNetworkInterface.TYPE_BRIDGE
net_src = bridge_entry.get_text()
return net_type, net_src
def populate_network_list(net_list, conn, show_direct_interfaces=True):
model = net_list.get_model()
model.clear()
vnet_bridges = []
vnet_dict = {}
bridge_dict = {}
iface_dict = {}
def build_row(nettype, name, label, is_sensitive, is_running,
manual_bridge=False, key=None):
return [nettype, name, label,
is_sensitive, is_running, manual_bridge,
key]
def set_active(idx):
net_list.set_active(idx)
def add_dict(indict, model):
keylist = indict.keys()
keylist.sort()
rowlist = [indict[k] for k in keylist]
for row in rowlist:
model.append(row)
# For qemu:///session
if conn.is_qemu_session():
nettype = VirtualNetworkInterface.TYPE_USER
r = build_row(nettype, None, pretty_network_desc(nettype), True, True)
model.append(r)
set_active(0)
return
hasNet = False
netIdxLabel = None
# Virtual Networks
for uuid in conn.list_net_uuids():
net = conn.get_net(uuid)
nettype = VirtualNetworkInterface.TYPE_VIRTUAL
label = pretty_network_desc(nettype, net.get_name(), net)
if not net.is_active():
label += " (%s)" % _("Inactive")
hasNet = True
# FIXME: Should we use 'default' even if it's inactive?
# FIXME: This preference should be configurable
if net.get_name() == "default":
netIdxLabel = label
vnet_dict[label] = build_row(nettype, net.get_name(), label, True,
net.is_active(), key=net.get_uuid())
# Build a list of vnet bridges, so we know not to list them
# in the physical interface list
vnet_bridge = net.get_bridge_device()
if vnet_bridge:
vnet_bridges.append(vnet_bridge)
if not hasNet:
label = _("No virtual networks available")
vnet_dict[label] = build_row(None, None, label, False, False)
vnet_taps = []
for vm in conn.vms.values():
for nic in vm.get_network_devices(refresh_if_nec=False):
if nic.target_dev and nic.target_dev not in vnet_taps:
vnet_taps.append(nic.target_dev)
# Physical devices
hasShared = False
brIdxLabel = None
for name in conn.list_net_device_paths():
br = conn.get_net_device(name)
bridge_name = br.get_bridge()
nettype = VirtualNetworkInterface.TYPE_BRIDGE
if ((bridge_name in vnet_bridges) or
(br.get_name() in vnet_bridges) or
(br.get_name() in vnet_taps) or
(br.get_name() in [v + "-nic" for v in vnet_bridges])):
# Don't list this, as it is basically duplicating virtual net info
continue
if br.is_shared():
sensitive = True
if br.get_bridge():
hasShared = True
brlabel = "(%s)" % pretty_network_desc(nettype, bridge_name)
else:
bridge_name = name
brlabel = _("(Empty bridge)")
else:
if (show_direct_interfaces and
virtinst.support.check_conn_support(conn.get_backend(),
virtinst.support.SUPPORT_CONN_HV_DIRECT_INTERFACE)):
sensitive = True
nettype = VirtualNetworkInterface.TYPE_DIRECT
bridge_name = name
brlabel = ": %s" % _("macvtap")
else:
sensitive = False
brlabel = "(%s)" % _("Not bridged")
label = _("Host device %s %s") % (br.get_name(), brlabel)
if hasShared and not brIdxLabel:
brIdxLabel = label
row = build_row(nettype, bridge_name, label, sensitive, True,
key=br.get_name())
if sensitive:
bridge_dict[label] = row
else:
iface_dict[label] = row
add_dict(bridge_dict, model)
add_dict(vnet_dict, model)
add_dict(iface_dict, model)
# If there is a bridge device, default to that
# If not, use 'default' network
# If not present, use first list entry
# If list empty, use no network devices
return_warn = False
label = brIdxLabel or netIdxLabel
for idx in range(len(model)):
row = model[idx]
is_inactive = not row[4]
if label:
if row[2] == label:
default = idx
return_warn = is_inactive
break
else:
if row[3] is True:
default = idx
return_warn = is_inactive
break
else:
return_warn = True
row = build_row(None, None, _("No networking"), True, False)
model.insert(0, row)
default = 0
# After all is said and done, add a manual bridge option
manual_row = build_row(None, None, _("Specify shared device name"),
True, False, manual_bridge=True)
model.append(manual_row)
set_active(default)
return return_warn
def validate_network(parent, conn, nettype, devname, macaddr, model=None):
set_error_parent(parent)
net = None
addr = None
if nettype is None:
return None
# Make sure VirtualNetwork is running
if (nettype == VirtualNetworkInterface.TYPE_VIRTUAL and
devname not in conn.get_backend().listNetworks()):
res = err_dial.yes_no(_("Virtual Network is not active."),
_("Virtual Network '%s' is not active. "
"Would you like to start the network "
"now?") % devname)
if not res:
return False
# Try to start the network
try:
virnet = conn.get_backend().networkLookupByName(devname)
virnet.create()
logging.info("Started network '%s'", devname)
except Exception, e:
return err_dial.show_err(_("Could not start virtual network "
"'%s': %s") % (devname, str(e)))
# Create network device
try:
bridge = None
netname = None
if nettype == VirtualNetworkInterface.TYPE_VIRTUAL:
netname = devname
elif nettype == VirtualNetworkInterface.TYPE_BRIDGE:
bridge = devname
elif nettype == VirtualNetworkInterface.TYPE_DIRECT:
bridge = devname
elif nettype == VirtualNetworkInterface.TYPE_USER:
pass
net = VirtualNetworkInterface(conn=conn.get_backend(),
type=nettype,
bridge=bridge,
network=netname,
macaddr=macaddr,
model=model)
if net.model == "spapr-vlan":
addr = "spapr-vio"
net.set_address(addr)
except Exception, e:
return err_dial.val_err(_("Error with network parameters."), e)
# Make sure there is no mac address collision
isfatal, errmsg = net.is_conflict_net(conn.get_backend())
if isfatal:
return err_dial.val_err(_("Mac address collision."), errmsg)
elif errmsg is not None:
retv = err_dial.yes_no(_("Mac address collision."),
_("%s Are you sure you want to use this "
"address?") % errmsg)
if not retv:
return False
return net
def generate_macaddr(conn):
newmac = ""
try:
net = VirtualNetworkInterface(conn=conn.get_backend())
net.setup(conn.get_backend())
newmac = net.macaddr
except:
pass
return newmac
############################################
# Populate media widget (choosecd, create) #
############################################
def init_mediadev_combo(widget):
# [Device path, pretty label, has_media?, device key, media key,
# vmmMediaDevice, is valid device]
model = Gtk.ListStore(str, str, bool, str, str, bool)
widget.set_model(model)
model.clear()
text = Gtk.CellRendererText()
widget.pack_start(text, True)
widget.add_attribute(text, 'text', OPTICAL_LABEL)
widget.add_attribute(text, 'sensitive', OPTICAL_IS_VALID)
def populate_mediadev_combo(conn, widget, devtype):
sigs = []
model = widget.get_model()
model.clear()
set_mediadev_default(model)
sigs.append(conn.connect("mediadev-added", mediadev_added, widget, devtype))
sigs.append(conn.connect("mediadev-removed", mediadev_removed, widget))
widget.set_active(-1)
mediadev_set_default_selection(widget)
return sigs
def set_mediadev_default(model):
if len(model) == 0:
model.append([None, _("No device present"), False, None, None, False])
def set_row_from_object(row, obj):
row[OPTICAL_DEV_PATH] = obj.get_path()
row[OPTICAL_LABEL] = obj.pretty_label()
row[OPTICAL_IS_MEDIA_PRESENT] = obj.has_media()
row[OPTICAL_DEV_KEY] = obj.get_key()
row[OPTICAL_MEDIA_KEY] = obj.get_media_key()
row[OPTICAL_IS_VALID] = True
def mediadev_removed(ignore_helper, key, widget):
model = widget.get_model()
active = widget.get_active()
idx = 0
for row in model:
if row[OPTICAL_DEV_KEY] == key:
# Whole device removed
del(model[idx])
if idx > active and active != -1:
widget.set_active(active - 1)
elif idx == active:
widget.set_active(-1)
idx += 1
set_mediadev_default(model)
mediadev_set_default_selection(widget)
def mediadev_added(ignore_helper, newobj, widget, devtype):
model = widget.get_model()
if newobj.get_media_type() != devtype:
return
if len(model) == 1 and model[0][OPTICAL_IS_VALID] is False:
# Only entry is the 'No device' entry
model.clear()
newobj.connect("media-added", mediadev_media_changed, widget)
newobj.connect("media-removed", mediadev_media_changed, widget)
# Brand new device
row = [None, None, None, None, None, None]
set_row_from_object(row, newobj)
model.append(row)
mediadev_set_default_selection(widget)
def mediadev_media_changed(newobj, widget):
model = widget.get_model()
active = widget.get_active()
idx = 0
# Search for the row with matching device node and
# fill in info about inserted media. If model has no current
# selection, select the new media.
for row in model:
if row[OPTICAL_DEV_PATH] == newobj.get_path():
set_row_from_object(row, newobj)
has_media = row[OPTICAL_IS_MEDIA_PRESENT]
if has_media and active == -1:
widget.set_active(idx)
elif not has_media and active == idx:
widget.set_active(-1)
idx = idx + 1
mediadev_set_default_selection(widget)
def mediadev_set_default_selection(widget):
# Set the first active cdrom device as selected, otherwise none
model = widget.get_model()
idx = 0
active = widget.get_active()
if active != -1:
# already a selection, don't change it
return
for row in model:
if row[OPTICAL_IS_MEDIA_PRESENT] is True:
widget.set_active(idx)
return
idx += 1
widget.set_active(-1)
####################################################################
# Build toolbar shutdown button menu (manager and details toolbar) #
####################################################################
def build_shutdown_button_menu(widget, shutdown_cb, reboot_cb, reset_cb,
destroy_cb, save_cb):
widget.set_icon_name("system-shutdown")
menu = Gtk.Menu()
widget.set_menu(menu)
rebootimg = Gtk.Image.new_from_icon_name("system-shutdown",
Gtk.IconSize.MENU)
shutdownimg = Gtk.Image.new_from_icon_name("system-shutdown",
Gtk.IconSize.MENU)
destroyimg = Gtk.Image.new_from_icon_name("system-shutdown",
Gtk.IconSize.MENU)
resetimg = Gtk.Image.new_from_icon_name("system-shutdown",
Gtk.IconSize.MENU)
saveimg = Gtk.Image.new_from_icon_name(Gtk.STOCK_SAVE, Gtk.IconSize.MENU)
reboot = Gtk.ImageMenuItem.new_with_mnemonic(_("_Reboot"))
reboot.set_image(rebootimg)
reboot.show()
reboot.connect("activate", reboot_cb)
menu.add(reboot)
shutdown = Gtk.ImageMenuItem.new_with_mnemonic(_("_Shut Down"))
shutdown.set_image(shutdownimg)
shutdown.show()
shutdown.connect("activate", shutdown_cb)
menu.add(shutdown)
reset = Gtk.ImageMenuItem.new_with_mnemonic(_("_Force Reset"))
reset.set_image(resetimg)
reset.show()
reset.connect("activate", reset_cb)
menu.add(reset)
destroy = Gtk.ImageMenuItem.new_with_mnemonic(_("_Force Off"))
destroy.set_image(destroyimg)
destroy.show()
destroy.connect("activate", destroy_cb)
menu.add(destroy)
sep = Gtk.SeparatorMenuItem()
sep.show()
menu.add(sep)
save = Gtk.ImageMenuItem.new_with_mnemonic(_("Sa_ve"))
save.set_image(saveimg)
save.show()
save.connect("activate", save_cb)
menu.add(save)
#####################################
# Path permissions checker for qemu #
#####################################
def check_path_search_for_qemu(parent, conn, path):
set_error_parent(parent)
if conn.is_remote() or not conn.is_qemu_system():
return
user = util.running_config.default_qemu_user
skip_paths = util.running_config.get_perms_fix_ignore()
broken_paths = VirtualDisk.check_path_search_for_user(conn.get_backend(),
path, user)
for p in broken_paths:
if p in skip_paths:
broken_paths.remove(p)
if not broken_paths:
return
logging.debug("No search access for dirs: %s", broken_paths)
resp, chkres = err_dial.warn_chkbox(
_("The emulator may not have search permissions "
"for the path '%s'.") % path,
_("Do you want to correct this now?"),
_("Don't ask about these directories again."),
buttons=Gtk.ButtonsType.YES_NO)
if chkres:
util.running_config.add_perms_fix_ignore(broken_paths)
if not resp:
return
logging.debug("Attempting to correct permission issues.")
errors = VirtualDisk.fix_path_search_for_user(conn.get_backend(),
path, user)
if not errors:
return
errmsg = _("Errors were encountered changing permissions for the "
"following directories:")
details = ""
for path, error in errors.items():
if path not in broken_paths:
continue
details += "%s : %s\n" % (path, error)
logging.debug("Permission errors:\n%s", details)
ignore, chkres = err_dial.err_chkbox(errmsg, details,
_("Don't ask about these directories again."))
if chkres:
util.running_config.add_perms_fix_ignore(errors.keys())
######################################
# Interface startmode widget builder #
######################################
def build_startmode_combo(start_list):
start_model = Gtk.ListStore(str)
start_list.set_model(start_model)
text = Gtk.CellRendererText()
start_list.pack_start(text, True)
start_list.add_attribute(text, 'text', 0)
start_model.append(["none"])
start_model.append(["onboot"])
start_model.append(["hotplug"])
#########################
# Console keycombo menu #
#########################
def build_keycombo_menu(cb):
menu = Gtk.Menu()
def make_item(name, combo):
item = Gtk.MenuItem.new_with_mnemonic(name)
item.connect("activate", cb, combo)
menu.add(item)
make_item("Ctrl+Alt+_Backspace", ["Control_L", "Alt_L", "BackSpace"])
make_item("Ctrl+Alt+_Delete", ["Control_L", "Alt_L", "Delete"])
menu.add(Gtk.SeparatorMenuItem())
for i in range(1, 13):
make_item("Ctrl+Alt+F_%d" % i, ["Control_L", "Alt_L", "F%d" % i])
menu.add(Gtk.SeparatorMenuItem())
make_item("_Printscreen", ["Print"])
menu.show_all()
return menu