virtManager: move device UI files to virtManager/device/

This commit is contained in:
Cole Robinson
2019-06-17 00:12:32 -04:00
parent a6c07fbfdc
commit 9be836102e
11 changed files with 31 additions and 29 deletions
View File
+233
View File
@@ -0,0 +1,233 @@
# Copyright (C) 2014 Red Hat, Inc.
#
# This work is licensed under the GNU GPLv2 or later.
# See the COPYING file in the top-level directory.
import os
from gi.repository import Gtk
import virtinst
from virtinst import log
from .. import uiutil
from ..baseclass import vmmGObjectUI
class vmmAddStorage(vmmGObjectUI):
__gsignals__ = {
"browse-clicked": (vmmGObjectUI.RUN_FIRST, None, [object]),
"storage-toggled": (vmmGObjectUI.RUN_FIRST, None, [object])
}
def __init__(self, conn, builder, topwin):
vmmGObjectUI.__init__(self, "addstorage.ui", None,
builder=builder, topwin=topwin)
self.conn = conn
self.builder.connect_signals({
"on_storage_browse_clicked": self._browse_storage,
"on_storage_select_toggled": self._toggle_storage_select,
})
self.top_box = self.widget("storage-box")
def _cleanup(self):
self.conn = None
##########################
# Initialization methods #
##########################
def _host_disk_space(self):
try:
pool = self.conn.get_default_pool()
if pool and pool.is_active():
# Rate limit this, since it can be spammed at dialog startup time
if pool.secs_since_last_refresh() > 10:
pool.refresh()
avail = int(pool.get_available())
return float(avail / 1024.0 / 1024.0 / 1024.0)
except Exception:
log.exception("Error determining host disk space")
return -1
def _update_host_space(self):
widget = self.widget("phys-hd-label")
max_storage = self._host_disk_space()
def pretty_storage(size):
if size == -1:
return "Unknown GiB"
return "%.1f GiB" % 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)
##############
# Public API #
##############
@staticmethod
def check_path_search(src, conn, path):
skip_paths = src.config.get_perms_fix_ignore()
searchdata = virtinst.DeviceDisk.check_path_search(
conn.get_backend(), path)
broken_paths = searchdata.fixlist[:]
for p in broken_paths[:]:
if p in skip_paths:
broken_paths.remove(p)
if not broken_paths:
return
log.debug("No search access for dirs: %s", broken_paths)
resp, chkres = src.err.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:
src.config.add_perms_fix_ignore(broken_paths)
if not resp:
return
log.debug("Attempting to correct permission issues.")
errors = virtinst.DeviceDisk.fix_path_search(
conn.get_backend(), searchdata)
if not errors:
return
errmsg = _("Errors were encountered changing permissions for the "
"following directories:")
details = ""
for p, error in errors.items():
if p not in broken_paths:
continue
details += "%s : %s\n" % (p, error)
details += "\nIt is very likely the VM will fail to start up."
log.debug("Permission errors:\n%s", details)
ignore, chkres = src.err.err_chkbox(errmsg, details,
_("Don't ask about these directories again."))
if chkres:
src.config.add_perms_fix_ignore(list(errors.keys()))
def reset_state(self):
self._update_host_space()
self.widget("storage-create").set_active(True)
self.widget("storage-size").set_value(20)
self.widget("storage-entry").set_text("")
self.widget("storage-create-box").set_sensitive(True)
storage_tooltip = None
can_storage = (not self.conn.is_remote() or
self.conn.is_storage_capable())
use_storage = self.widget("storage-select")
storage_area = self.widget("storage-box")
storage_area.set_sensitive(can_storage)
if not can_storage:
storage_tooltip = _("Connection does not support storage"
" management.")
use_storage.set_sensitive(True)
storage_area.set_tooltip_text(storage_tooltip or "")
def get_default_path(self, name, collideguest=None):
pool = self.conn.get_default_pool()
if not pool:
return
fmt = self.conn.get_default_storage_format()
suffix = virtinst.StorageVolume.get_file_extension_for_format(fmt)
suffix = suffix or ".img"
path = virtinst.StorageVolume.find_free_name(
self.conn.get_backend(), pool.get_backend(), name,
suffix=suffix, collideguest=collideguest)
return os.path.join(pool.xmlobj.target_path, path)
def is_default_storage(self):
return self.widget("storage-create").get_active()
def build_device(self, vmname,
path=None, device="disk", collideguest=None):
if path is None:
if self.is_default_storage():
path = self.get_default_path(vmname, collideguest=collideguest)
else:
path = self.widget("storage-entry").get_text().strip()
disk = virtinst.DeviceDisk(self.conn.get_backend())
disk.path = path or None
disk.device = device
if disk.wants_storage_creation():
pool = disk.get_parent_pool()
size = uiutil.spin_get_helper(self.widget("storage-size"))
sparse = False
vol_install = virtinst.DeviceDisk.build_vol_install(
disk.conn, os.path.basename(disk.path), pool,
size, sparse)
disk.set_vol_install(vol_install)
fmt = self.conn.get_default_storage_format()
if disk.get_vol_install().supports_property("format"):
log.debug("Using default prefs format=%s for path=%s",
fmt, disk.path)
disk.get_vol_install().format = fmt
else:
log.debug("path=%s can not use default prefs format=%s, "
"not setting it", disk.path, fmt)
return disk
def validate_device(self, disk):
if not disk.path and disk.device in ["disk", "lun"]:
return self.err.val_err(_("A storage path must be specified."))
disk.validate()
isfatal, errmsg = disk.is_size_conflict()
if not isfatal and errmsg:
# Fatal errors are reported when setting 'size'
res = self.err.ok_cancel(_("Not Enough Free Space"), errmsg)
if not res:
return False
# Disk collision
names = disk.is_conflict_disk()
if names:
res = self.err.yes_no(
_('Disk "%s" is already in use by other guests %s') %
(disk.path, names),
_("Do you really want to use the disk?"))
if not res:
return False
self.check_path_search(self, self.conn, disk.path)
#############
# Listeners #
#############
def _browse_storage(self, ignore):
self.emit("browse-clicked", self.widget("storage-entry"))
def _toggle_storage_select(self, src):
act = src.get_active()
self.widget("storage-browse-box").set_sensitive(act)
self.emit("storage-toggled", src)
+317
View File
@@ -0,0 +1,317 @@
# Copyright (C) 2006-2007, 2013, 2014 Red Hat, Inc.
# Copyright (C) 2006 Hugh O. Brock <hbrock@redhat.com>
# Copyright (C) 2014 SUSE LINUX Products GmbH, Nuernberg, Germany.
#
# This work is licensed under the GNU GPLv2 or later.
# See the COPYING file in the top-level directory.
from gi.repository import Gtk
from virtinst import DeviceFilesystem
from .. import uiutil
from ..baseclass import vmmGObjectUI
from ..storagebrowse import vmmStorageBrowser
class vmmFSDetails(vmmGObjectUI):
__gsignals__ = {
"changed": (vmmGObjectUI.RUN_FIRST, None, [])
}
def __init__(self, vm, builder, topwin):
vmmGObjectUI.__init__(self, "fsdetails.ui",
None, builder=builder, topwin=topwin)
self.vm = vm
self.conn = vm.conn
self._dev = None
self.storage_browser = None
self.builder.connect_signals({
"on_fs_type_combo_changed": self.change_field,
"on_fs_driver_combo_changed": self.change_field,
"on_fs_source_browse_clicked": self.browse_fs_source,
"on_fs_mode_combo_changed": self.notify_change,
"on_fs_wrpolicy_combo_changed": self.notify_change,
"on_fs_readonly_toggled": self.notify_change,
"on_fs_format_combo_changed": self.notify_change,
"on_fs_source_changed": self.notify_change,
"on_fs_ram_source_changed": self.notify_change,
"on_fs_target_changed": self.notify_change,
})
self.set_initial_state()
self.top_box = self.widget("vmm-fs-details")
def _cleanup(self):
self.vm = None
self.conn = None
self._dev = None
if self.storage_browser:
self.storage_browser.cleanup()
self.storage_browser = None
def show_pair_combo(self, basename, show_combo):
combo = self.widget(basename + "-combo")
label = self.widget(basename + "-label")
combo.set_visible(show_combo)
label.set_visible(not show_combo)
def show_check_button(self, basename, show):
check = self.widget(basename)
check.set_visible(show)
##########################
# Initialization methods #
##########################
def set_initial_state(self):
def simple_store_set(comboname, values, sort=True, capitalize=True):
combo = self.widget(comboname)
# [XML value, label]
model = Gtk.ListStore(str, str)
combo.set_model(model)
uiutil.init_combo_text_column(combo, 1)
if sort:
model.set_sort_column_id(0, Gtk.SortType.ASCENDING)
for xmlval in values:
label = xmlval
if xmlval is None:
label = "Default"
if capitalize:
label = label.capitalize()
model.append([xmlval, label])
# Filesystem widgets
if self.conn.is_openvz():
simple_store_set("fs-type-combo",
[DeviceFilesystem.TYPE_MOUNT,
DeviceFilesystem.TYPE_TEMPLATE], sort=False)
elif self.conn.is_lxc():
simple_store_set("fs-type-combo",
[DeviceFilesystem.TYPE_MOUNT,
DeviceFilesystem.TYPE_FILE,
DeviceFilesystem.TYPE_BLOCK,
DeviceFilesystem.TYPE_RAM], sort=False)
else:
simple_store_set("fs-type-combo", [DeviceFilesystem.TYPE_MOUNT])
self.widget("fs-type-label").set_text(DeviceFilesystem.TYPE_MOUNT)
simple_store_set("fs-mode-combo", DeviceFilesystem.MODES + [None])
drivers = []
if self.conn.is_qemu() or self.conn.is_test():
drivers += [DeviceFilesystem.DRIVER_PATH,
DeviceFilesystem.DRIVER_HANDLE]
if self.conn.is_lxc() or self.conn.is_test():
drivers += [DeviceFilesystem.DRIVER_LOOP,
DeviceFilesystem.DRIVER_NBD]
simple_store_set("fs-driver-combo", drivers + [None])
simple_store_set("fs-format-combo", ["raw", "qcow2"], capitalize=False)
simple_store_set("fs-wrpolicy-combo",
DeviceFilesystem.WRPOLICIES + [None])
self.show_pair_combo("fs-type",
self.conn.is_openvz() or self.conn.is_lxc())
self.show_check_button("fs-readonly",
self.conn.is_qemu() or
self.conn.is_test() or
self.conn.is_lxc())
def reset_state(self):
self.widget("fs-type-combo").set_active(0)
self.widget("fs-mode-combo").set_active(0)
self.widget("fs-driver-combo").set_active(0)
self.widget("fs-format-combo").set_active(0)
self.widget("fs-wrpolicy-combo").set_active(0)
self.widget("fs-source").set_text("")
self.widget("fs-target").set_text("")
self.widget("fs-readonly").set_active(False)
# Getters
def get_dev(self):
return self._dev
def get_config_fs_mode(self):
return uiutil.get_list_selection(self.widget("fs-mode-combo"),
check_visible=True)
def get_config_fs_wrpolicy(self):
return uiutil.get_list_selection(self.widget("fs-wrpolicy-combo"),
check_visible=True)
def get_config_fs_type(self):
if self.widget("fs-type-label").is_visible():
return self.widget("fs-type-label").get_text()
return uiutil.get_list_selection(self.widget("fs-type-combo"),
check_visible=True)
def get_config_fs_readonly(self):
if not self.widget("fs-readonly").is_visible():
return None
return self.widget("fs-readonly").get_active()
def get_config_fs_driver(self):
return uiutil.get_list_selection(self.widget("fs-driver-combo"),
check_visible=True)
def get_config_fs_format(self):
return uiutil.get_list_selection(self.widget("fs-format-combo"),
check_visible=True)
# Setters
def set_dev(self, dev):
self._dev = dev
self.set_config_value("fs-type", dev.type)
self.set_config_value("fs-mode", dev.accessmode)
self.set_config_value("fs-driver", dev.driver)
self.set_config_value("fs-wrpolicy", dev.wrpolicy)
self.set_config_value("fs-format", dev.format)
if dev.type != DeviceFilesystem.TYPE_RAM:
self.widget("fs-source").set_text(dev.source)
else:
self.widget("fs-ram-source-spin").set_value(int(dev.source) // 1024)
self.widget("fs-target").set_text(dev.target or "")
self.widget("fs-readonly").set_active(dev.readonly)
self.show_pair_combo("fs-type",
self.conn.is_openvz() or self.conn.is_lxc())
def set_config_value(self, name, value):
combo = self.widget("%s-combo" % name)
label = self.widget("%s-label" % name)
uiutil.set_list_selection(combo, value)
if label:
label.set_text(value or "default")
# listeners
def notify_change(self, ignore):
self.emit("changed")
def browse_fs_source(self, ignore1):
self._browse_file(self.widget("fs-source"), isdir=True)
def update_fs_rows(self):
fstype = self.get_config_fs_type()
fsdriver = self.get_config_fs_driver()
ismount = bool(
fstype == DeviceFilesystem.TYPE_MOUNT or
self.conn.is_qemu() or self.conn.is_test())
show_mode = bool(ismount and
(fsdriver == DeviceFilesystem.DRIVER_PATH or
fsdriver is None))
uiutil.set_grid_row_visible(self.widget("fs-mode-box"), show_mode)
show_wrpol = bool(ismount and
fsdriver and (fsdriver == DeviceFilesystem.DRIVER_PATH or
fsdriver == DeviceFilesystem.DRIVER_HANDLE))
uiutil.set_grid_row_visible(self.widget("fs-wrpolicy-box"),
show_wrpol)
show_ram_source = fstype == DeviceFilesystem.TYPE_RAM
uiutil.set_grid_row_visible(
self.widget("fs-ram-source-box"), show_ram_source)
uiutil.set_grid_row_visible(
self.widget("fs-source-box"), not show_ram_source)
show_format = bool(
fsdriver == DeviceFilesystem.DRIVER_NBD)
uiutil.set_grid_row_visible(self.widget("fs-format-box"), show_format)
self.show_pair_combo("fs-format", True)
show_mode_combo = False
show_driver_combo = False
show_wrpolicy_combo = self.conn.is_qemu() or self.conn.is_test()
if fstype == DeviceFilesystem.TYPE_TEMPLATE:
source_text = _("Te_mplate:")
else:
source_text = _("_Source path:")
show_mode_combo = self.conn.is_qemu() or self.conn.is_test()
show_driver_combo = (self.conn.is_qemu() or
self.conn.is_lxc() or
self.conn.is_test())
self.widget("fs-source-title").set_text(source_text)
self.widget("fs-source-title").set_use_underline(True)
self.show_pair_combo("fs-mode", show_mode_combo)
self.show_pair_combo("fs-driver", show_driver_combo)
self.show_pair_combo("fs-wrpolicy", show_wrpolicy_combo)
def change_field(self, src):
self.update_fs_rows()
self.notify_change(src)
# Page validation method
def validate_page_filesystem(self):
conn = self.conn.get_backend()
source = self.widget("fs-source").get_text()
target = self.widget("fs-target").get_text()
usage = uiutil.spin_get_helper(self.widget("fs-ram-source-spin"))
mode = self.get_config_fs_mode()
fstype = self.get_config_fs_type()
readonly = self.get_config_fs_readonly()
driver = self.get_config_fs_driver()
fsformat = self.get_config_fs_format()
wrpolicy = self.get_config_fs_wrpolicy()
if not source and fstype != DeviceFilesystem.TYPE_RAM:
return self.err.val_err(_("A filesystem source must be specified"))
elif usage == 0 and fstype == DeviceFilesystem.TYPE_RAM:
return self.err.val_err(
_("A RAM filesystem usage must be specified"))
if not target:
return self.err.val_err(_("A filesystem target must be specified"))
try:
self._dev = DeviceFilesystem(conn)
if fstype == DeviceFilesystem.TYPE_RAM:
self._dev.source = usage
self._dev.units = 'MiB'
else:
self._dev.source = source
self._dev.target = target
self._dev.validate_target(target)
if mode:
self._dev.accessmode = mode
if fstype:
self._dev.type = fstype
if readonly:
self._dev.readonly = readonly
if driver:
self._dev.driver = driver
if driver == DeviceFilesystem.DRIVER_LOOP:
self._dev.format = "raw"
elif driver == DeviceFilesystem.DRIVER_NBD:
self._dev.format = fsformat
if wrpolicy:
self._dev.wrpolicy = wrpolicy
except Exception as e:
return self.err.val_err(_("Filesystem parameter error"), e)
def _browse_file(self, textent, isdir=False):
def set_storage_cb(src, path):
if path:
textent.set_text(path)
reason = (isdir and
self.config.CONFIG_DIR_FS or
self.config.CONFIG_DIR_IMAGE)
if self.storage_browser and self.storage_browser.conn != self.conn:
self.storage_browser.cleanup()
self.storage_browser = None
if self.storage_browser is None:
self.storage_browser = vmmStorageBrowser(self.conn)
self.storage_browser.set_finish_cb(set_storage_cb)
self.storage_browser.set_browse_reason(reason)
self.storage_browser.show(self.topwin.get_ancestor(Gtk.Window))
+386
View File
@@ -0,0 +1,386 @@
# Copyright (C) 2006-2007, 2013, 2014 Red Hat, Inc.
# Copyright (C) 2006 Hugh O. Brock <hbrock@redhat.com>
# Copyright (C) 2014 SUSE LINUX Products GmbH, Nuernberg, Germany.
#
# This work is licensed under the GNU GPLv2 or later.
# See the COPYING file in the top-level directory.
from gi.repository import Gtk
import virtinst
from .. import uiutil
from ..baseclass import vmmGObjectUI
class vmmGraphicsDetails(vmmGObjectUI):
__gsignals__ = {
"changed-password": (vmmGObjectUI.RUN_FIRST, None, []),
"changed-port": (vmmGObjectUI.RUN_FIRST, None, []),
"changed-tlsport": (vmmGObjectUI.RUN_FIRST, None, []),
"changed-type": (vmmGObjectUI.RUN_FIRST, None, []),
"changed-listen": (vmmGObjectUI.RUN_FIRST, None, []),
"changed-address": (vmmGObjectUI.RUN_FIRST, None, []),
"changed-keymap": (vmmGObjectUI.RUN_FIRST, None, []),
"changed-opengl": (vmmGObjectUI.RUN_FIRST, None, []),
"changed-rendernode": (vmmGObjectUI.RUN_FIRST, None, []),
}
def __init__(self, vm, builder, topwin):
vmmGObjectUI.__init__(self, "gfxdetails.ui",
None, builder=builder, topwin=topwin)
self.vm = vm
self.conn = vm.conn
self.builder.connect_signals({
"on_graphics_type_changed": self._change_graphics_type,
"on_graphics_port_auto_toggled": self._change_port_auto,
"on_graphics_tlsport_auto_toggled": self._change_tlsport_auto,
"on_graphics_use_password": self._change_password_chk,
"on_graphics_show_password": self._show_password_chk,
"on_graphics_listen_type_changed": self._change_graphics_listen,
"on_graphics_password_changed": lambda ignore: self.emit("changed-password"),
"on_graphics_address_changed": lambda ignore: self.emit("changed-address"),
"on_graphics_tlsport_changed": lambda ignore: self.emit("changed-tlsport"),
"on_graphics_port_changed": lambda ignore: self.emit("changed-port"),
"on_graphics_keymap_changed": lambda ignore: self.emit("changed-keymap"),
"on_graphics_opengl_toggled": self._change_opengl,
"on_graphics_rendernode_changed": lambda ignore: self.emit("changed-rendernode")
})
self._init_ui()
self.top_box = self.widget("graphics-box")
def _cleanup(self):
self.vm = None
self.conn = None
#####################
# Pretty UI helpers #
#####################
@staticmethod
def graphics_pretty_type_simple(gtype):
if (gtype in [virtinst.DeviceGraphics.TYPE_VNC,
virtinst.DeviceGraphics.TYPE_SDL,
virtinst.DeviceGraphics.TYPE_RDP]):
return str(gtype).upper()
return str(gtype).capitalize()
##########################
# Initialization methods #
##########################
def _init_ui(self):
graphics_list = self.widget("graphics-type")
graphics_model = Gtk.ListStore(str, str)
graphics_list.set_model(graphics_model)
uiutil.init_combo_text_column(graphics_list, 1)
graphics_model.clear()
graphics_model.append(["spice", _("Spice server")])
graphics_model.append(["vnc", _("VNC server")])
graphics_listen_list = self.widget("graphics-listen-type")
graphics_listen_model = Gtk.ListStore(str, str)
graphics_listen_list.set_model(graphics_listen_model)
uiutil.init_combo_text_column(graphics_listen_list, 1)
graphics_listen_model.clear()
graphics_listen_model.append(["address", _("Address")])
graphics_listen_model.append(["none", _("None")])
self.widget("graphics-address").set_model(Gtk.ListStore(str, str))
uiutil.init_combo_text_column(self.widget("graphics-address"), 1)
model = self.widget("graphics-address").get_model()
model.clear()
model.append([None, _("Hypervisor default")])
model.append(["127.0.0.1", _("Localhost only")])
model.append(["0.0.0.0", _("All interfaces")])
# Keymap
combo = self.widget("graphics-keymap")
model = Gtk.ListStore(str, str)
combo.set_model(model)
uiutil.init_combo_text_column(combo, 1)
model.append(["auto", _("Auto")])
model.append([virtinst.DeviceGraphics.KEYMAP_LOCAL,
_("Copy local keymap")])
for k in virtinst.DeviceGraphics.valid_keymaps():
model.append([k, k])
# Host GPU rendernode
combo = self.widget("graphics-rendernode")
model = Gtk.ListStore(str, str)
combo.set_model(model)
uiutil.init_combo_text_column(combo, 1)
model.append([None, _("Auto")])
devs = self.conn.filter_nodedevs("drm")
for i in devs:
drm = i.xmlobj
if not drm.is_drm_render():
continue
rendernode = drm.get_devnode().path
model.append([rendernode, i.pretty_name()])
def _get_config_graphics_ports(self):
port = uiutil.spin_get_helper(self.widget("graphics-port"))
tlsport = uiutil.spin_get_helper(self.widget("graphics-tlsport"))
gtype = uiutil.get_list_selection(self.widget("graphics-type"))
if self.widget("graphics-port-auto").get_active():
port = -1
if self.widget("graphics-tlsport-auto").get_active():
tlsport = -1
if gtype != "spice":
tlsport = None
return port, tlsport
##############
# Public API #
##############
def reset_state(self):
uiutil.set_grid_row_visible(self.widget("graphics-display"), False)
uiutil.set_grid_row_visible(self.widget("graphics-xauth"), False)
self.widget("graphics-type").set_active(0)
self.widget("graphics-listen-type").set_active(0)
self.widget("graphics-address").set_active(0)
self.widget("graphics-keymap").set_active(0)
# Select last entry in the list, which should be a rendernode path
rendermodel = self.widget("graphics-rendernode").get_model()
self.widget("graphics-rendernode").set_active_iter(rendermodel[-1].iter)
self._change_ports()
self.widget("graphics-port-auto").set_active(True)
self.widget("graphics-tlsport-auto").set_active(True)
self.widget("graphics-password").set_text("")
self.widget("graphics-password").set_sensitive(False)
self.widget("graphics-password-chk").set_active(False)
def get_values(self):
gtype = uiutil.get_list_selection(self.widget("graphics-type"))
port, tlsport = self._get_config_graphics_ports()
listen = uiutil.get_list_selection(self.widget("graphics-listen-type"))
addr = uiutil.get_list_selection(self.widget("graphics-address"))
keymap = uiutil.get_list_selection(self.widget("graphics-keymap"))
if keymap == "auto":
keymap = None
passwd = self.widget("graphics-password").get_text()
if not self.widget("graphics-password-chk").get_active():
passwd = None
gl = self.widget("graphics-opengl").get_active()
rendernode = uiutil.get_list_selection(self.widget("graphics-rendernode"))
return gtype, port, tlsport, listen, addr, passwd, keymap, gl, rendernode
def set_dev(self, gfx):
self.reset_state()
def set_port(basename, val):
auto = self.widget(basename + "-auto")
widget = self.widget(basename)
auto.set_inconsistent(False)
label = auto.get_label().split(" (")[0]
if val == -1 or gfx.autoport:
auto.set_active(True)
if val and val != -1:
label += " (%s %s)" % (_("Port"), val)
elif val is None:
auto.set_inconsistent(True)
else:
auto.set_active(False)
widget.set_value(val)
auto.set_label(label)
gtype = gfx.type
is_vnc = (gtype == "vnc")
is_sdl = (gtype == "sdl")
is_spice = (gtype == "spice")
pretty_type = vmmGraphicsDetails.graphics_pretty_type_simple(gtype)
title = (_("%(graphicstype)s Server") % {"graphicstype": pretty_type})
if is_vnc or is_spice:
use_passwd = gfx.passwd is not None
set_port("graphics-port", gfx.port)
listentype = gfx.get_first_listen_type()
if listentype and listentype == 'none':
uiutil.set_list_selection(self.widget("graphics-listen-type"), 'none')
else:
uiutil.set_list_selection(self.widget("graphics-listen-type"), 'address')
uiutil.set_list_selection(
self.widget("graphics-address"), gfx.listen)
uiutil.set_list_selection(
self.widget("graphics-keymap"), gfx.keymap or None)
self.widget("graphics-password").set_text(gfx.passwd or "")
self.widget("graphics-password-chk").set_active(use_passwd)
self.widget("graphics-password").set_sensitive(use_passwd)
if is_spice:
set_port("graphics-tlsport", gfx.tlsPort)
opengl_warning = ""
rendernode_warning = ""
opengl_supported = self.conn.support.conn_spice_gl()
rendernode_supported = self.conn.support.conn_spice_rendernode()
# * If spicegl isn't supported, show a warning icon and
# and desensitive everything
# * If qemu:///system and rendernode isn't supported,
# show a warning icon and desensitize everything, since
# rendernode support is needed for it to work out of the box.
# * Otherwise, enable all UI, but show warning icons anyways
# for potential config issues
glval = False
renderval = None
glsensitive = False
if not opengl_supported:
opengl_warning = (
_("Hypervisor/libvirt does not support spice GL"))
elif not rendernode_supported:
rendernode_warning = (
_("Hypervisor/libvirt does not support manual rendernode"))
if self.conn.is_qemu_system():
opengl_warning = rendernode_warning
if not opengl_warning:
glval = bool(gfx.gl)
glsensitive = True
if not rendernode_warning:
renderval = gfx.rendernode or None
if opengl_warning:
pass
elif not [v for v in self.vm.xmlobj.devices.video if
(v.model == "virtio" and v.accel3d)]:
opengl_warning = _("Spice GL requires "
"virtio graphics configured with accel3d.")
elif gfx.get_first_listen_type() not in ["none", "socket"]:
opengl_warning = _("Graphics listen type does not support "
"spice GL.")
self.widget("graphics-opengl").set_active(glval)
if glval:
# Only sync rendernode UI with XML, if gl=on, otherwise
# we want to preserve the suggested rendernode already
# selected in the UI
uiutil.set_list_selection(
self.widget("graphics-rendernode"), renderval)
self.widget("graphics-opengl").set_sensitive(glsensitive)
self.widget("graphics-opengl-warn").set_tooltip_text(
opengl_warning or None)
self.widget("graphics-opengl-warn").set_visible(
bool(opengl_warning))
self.widget("graphics-rendernode").set_sensitive(
rendernode_supported)
self.widget("graphics-rendernode-warn").set_tooltip_text(
rendernode_warning or None)
self.widget("graphics-rendernode-warn").set_visible(
bool(rendernode_warning))
if is_sdl:
title = _("Local SDL Window")
self.widget("graphics-display").set_text(
gfx.display or _("Unknown"))
self.widget("graphics-xauth").set_text(
gfx.xauth or _("Unknown"))
uiutil.set_list_selection(self.widget("graphics-type"), gtype)
return title
#############
# Listeners #
#############
def _show_rows_from_type(self):
hide_all = ["graphics-xauth", "graphics-display", "graphics-address",
"graphics-password-box", "graphics-keymap", "graphics-port-box",
"graphics-tlsport-box", "graphics-opengl-box"]
gtype = uiutil.get_list_selection(self.widget("graphics-type"))
listen = uiutil.get_list_selection(self.widget("graphics-listen-type"))
sdl_rows = ["graphics-xauth", "graphics-display"]
vnc_rows = ["graphics-password-box", "graphics-keymap"]
if listen == 'address':
vnc_rows.extend(["graphics-port-box", "graphics-address"])
spice_rows = vnc_rows[:]
if listen == 'address':
spice_rows.extend(["graphics-tlsport-box"])
spice_rows.extend(["graphics-opengl-box"])
rows = []
if gtype == "sdl":
rows = sdl_rows
elif gtype == "vnc":
rows = vnc_rows
elif gtype == "spice":
rows = spice_rows
for row in hide_all:
uiutil.set_grid_row_visible(self.widget(row), row in rows)
def _change_graphics_type(self, ignore):
self._show_rows_from_type()
self.emit("changed-type")
def _change_graphics_listen(self, ignore):
self._show_rows_from_type()
self.emit("changed-listen")
def _change_opengl(self, ignore):
uiutil.set_grid_row_visible(
self.widget("graphics-rendernode-box"),
self.widget("graphics-opengl").get_active())
self.emit("changed-opengl")
def _change_port_auto(self, ignore):
self.widget("graphics-port-auto").set_inconsistent(False)
self._change_ports()
self.emit("changed-port")
def _change_tlsport_auto(self, ignore):
self.widget("graphics-tlsport-auto").set_inconsistent(False)
self._change_ports()
self.emit("changed-tlsport")
def _change_ports(self):
is_auto = (self.widget("graphics-port-auto").get_active() or
self.widget("graphics-port-auto").get_inconsistent())
is_tlsauto = (self.widget("graphics-tlsport-auto").get_active() or
self.widget("graphics-tlsport-auto").get_inconsistent())
self.widget("graphics-port").set_visible(not is_auto)
self.widget("graphics-tlsport").set_visible(not is_tlsauto)
def _change_password_chk(self, ignore=None):
if self.widget("graphics-password-chk").get_active():
self.widget("graphics-password").set_sensitive(True)
else:
self.widget("graphics-password").set_text("")
self.widget("graphics-password").set_sensitive(False)
self.emit("changed-password")
def _show_password_chk(self, ignore=None):
if self.widget("graphics-visiblity-chk").get_active():
self.widget("graphics-password").set_visibility(True)
else:
self.widget("graphics-password").set_visibility(False)
+193
View File
@@ -0,0 +1,193 @@
# Copyright (C) 2014 Red Hat, Inc.
#
# This work is licensed under the GNU GPLv2 or later.
# See the COPYING file in the top-level directory.
from gi.repository import Gtk
from .. import uiutil
from ..baseclass import vmmGObject, vmmGObjectUI
class vmmMediaCombo(vmmGObjectUI):
__gsignals__ = {
"changed": (vmmGObject.RUN_FIRST, None, [object]),
"activate": (vmmGObject.RUN_FIRST, None, [object]),
}
MEDIA_TYPE_FLOPPY = "floppy"
MEDIA_TYPE_CDROM = "cdrom"
MEDIA_FIELDS_NUM = 4
(MEDIA_FIELD_PATH,
MEDIA_FIELD_LABEL,
MEDIA_FIELD_HAS_MEDIA,
MEDIA_FIELD_KEY) = range(MEDIA_FIELDS_NUM)
def __init__(self, conn, builder, topwin):
vmmGObjectUI.__init__(self, None, None, builder=builder, topwin=topwin)
self.conn = conn
self.top_box = None
self._combo = None
self._populated = False
self._init_ui()
self._iso_rows = []
self._cdrom_rows = []
self._floppy_rows = []
self._rows_inited = False
self.add_gsettings_handle(
self.config.on_iso_paths_changed(self._iso_paths_changed_cb))
def _cleanup(self):
self.conn = None
self.top_box.destroy()
self.top_box = None
##########################
# Initialization methods #
##########################
def _init_ui(self):
self.top_box = Gtk.Box()
self.top_box.set_spacing(6)
self.top_box.set_orientation(Gtk.Orientation.HORIZONTAL)
self._combo = Gtk.ComboBox(has_entry=True)
self._combo.set_entry_text_column(self.MEDIA_FIELD_LABEL)
self._combo.get_accessible().set_name("media-combo")
def separator_cb(_model, _iter):
return _model[_iter][self.MEDIA_FIELD_PATH] is None
self._combo.set_row_separator_func(separator_cb)
self._entry = self._combo.get_child()
self._entry.set_placeholder_text(_("No media selected"))
self._entry.set_hexpand(True)
self._entry.get_accessible().set_name("media-entry")
self._entry.connect("changed", self._on_entry_changed_cb)
self._entry.connect("activate", self._on_entry_activated_cb)
self._entry.connect("icon-press", self._on_entry_icon_press_cb)
self._browse = Gtk.Button()
self.top_box.add(self._combo)
self.top_box.show_all()
# [path, label, has_media?, device key]
store = Gtk.ListStore(str, str, bool, str)
self._combo.set_model(store)
def _make_row(self, path, label, has_media, key):
row = [None] * self.MEDIA_FIELDS_NUM
row[self.MEDIA_FIELD_PATH] = path
row[self.MEDIA_FIELD_LABEL] = label
row[self.MEDIA_FIELD_HAS_MEDIA] = has_media
row[self.MEDIA_FIELD_KEY] = key
return row
def _make_nodedev_rows(self, media_type):
rows = []
for nodedev in self.conn.filter_nodedevs("storage"):
if not (nodedev.xmlobj.device_type == "storage" and
nodedev.xmlobj.drive_type in ["cdrom", "floppy"]):
continue
if nodedev.xmlobj.drive_type != media_type:
continue
media_label = nodedev.xmlobj.media_label
if not nodedev.xmlobj.media_available:
media_label = _("No media detected")
elif not nodedev.xmlobj.media_label:
media_label = _("Media Unknown")
label = "%s (%s)" % (media_label, nodedev.xmlobj.block)
row = self._make_row(nodedev.xmlobj.block, label,
nodedev.xmlobj.media_available,
nodedev.xmlobj.name)
rows.append(row)
return rows
def _make_iso_rows(self):
rows = []
for path in self.config.get_iso_paths():
row = self._make_row(path, path, True, path)
rows.append(row)
return rows
def _init_rows(self):
self._cdrom_rows = self._make_nodedev_rows("cdrom")
self._floppy_rows = self._make_nodedev_rows("floppy")
self._iso_rows = self._make_iso_rows()
self._rows_inited = True
################
# UI callbacks #
################
def _on_entry_changed_cb(self, src):
self.emit("changed", self._entry)
def _on_entry_activated_cb(self, src):
self.emit("activate", self._entry)
def _on_entry_icon_press_cb(self, src, icon_pos, event):
self._entry.set_text("")
def _iso_paths_changed_cb(self):
self._iso_rows = self._make_iso_rows()
##############
# Public API #
##############
def set_conn(self, conn):
if conn == self.conn:
return
self.conn = conn
self._init_rows()
def reset_state(self, is_floppy=False):
if not self._rows_inited:
self._init_rows()
model = self._combo.get_model()
model.clear()
for row in self._iso_rows:
model.append(row)
nodedev_rows = self._cdrom_rows
if is_floppy:
nodedev_rows = self._floppy_rows
if len(model) and nodedev_rows:
model.append(self._make_row(None, None, False, None))
for row in nodedev_rows:
model.append(row)
self._combo.set_active(-1)
def get_path(self, store_media=True):
ret = uiutil.get_list_selection(
self._combo, column=self.MEDIA_FIELD_PATH)
if store_media and not ret.startswith("/dev"):
self.config.add_iso_path(ret)
return ret
def set_path(self, path):
uiutil.set_list_selection(
self._combo, path, column=self.MEDIA_FIELD_PATH)
self._entry.set_position(-1)
def set_mnemonic_label(self, label):
label.set_mnemonic_widget(self._entry)
def show_clear_icon(self):
pos = Gtk.EntryIconPosition.SECONDARY
self._entry.set_icon_from_icon_name(pos, "edit-clear-symbolic")
self._entry.set_icon_activatable(pos, True)
+545
View File
@@ -0,0 +1,545 @@
# Copyright (C) 2014 Red Hat, Inc.
#
# This work is licensed under the GNU GPLv2 or later.
# See the COPYING file in the top-level directory.
import collections
from gi.repository import Gtk
import virtinst
from virtinst import log
from .. import uiutil
from ..baseclass import vmmGObjectUI
NetDev = collections.namedtuple('Netdev', ['name', 'is_bridge', 'slave_names'])
class vmmNetworkList(vmmGObjectUI):
__gsignals__ = {
"changed": (vmmGObjectUI.RUN_FIRST, None, []),
"changed-vport": (vmmGObjectUI.RUN_FIRST, None, [])
}
def __init__(self, conn, builder, topwin):
vmmGObjectUI.__init__(self, "netlist.ui",
None, builder=builder, topwin=topwin)
self.conn = conn
self.builder.connect_signals({
"on_net_source_changed": self._on_net_source_changed,
"on_net_source_mode_changed": self._emit_changed,
"on_net_portgroup_changed": self._emit_changed,
"on_net_bridge_name_changed": self._emit_changed,
"on_vport_type_changed": self._emit_vport_changed,
"on_vport_managerid_changed": self._emit_vport_changed,
"on_vport_typeid_changed": self._emit_vport_changed,
"on_vport_typeidversion_changed": self._emit_vport_changed,
"on_vport_instanceid_changed": self._emit_vport_changed,
})
self._init_ui()
self.top_label = self.widget("net-source-label")
self.top_box = self.widget("net-source-box")
self.top_vport = self.widget("vport-expander")
def _cleanup(self):
self.conn.disconnect_by_obj(self)
self.conn = None
self.top_label.destroy()
self.top_box.destroy()
self.top_vport.destroy()
##########################
# Initialization methods #
##########################
def _init_ui(self):
# [ network type, source name, label, sensitive?, net is active,
# manual bridge, net instance]
model = Gtk.ListStore(str, str, str, bool, bool, bool, object)
combo = self.widget("net-source")
combo.set_model(model)
text = Gtk.CellRendererText()
combo.pack_start(text, True)
combo.add_attribute(text, 'text', 2)
combo.add_attribute(text, 'sensitive', 3)
combo = self.widget("net-source-mode")
# [xml value, label]
model = Gtk.ListStore(str, str)
combo.set_model(model)
uiutil.init_combo_text_column(combo, 1)
model.append(["bridge", _("Bridge")])
model.append(["vepa", "VEPA"])
model.append(["private", _("Private")])
model.append(["passthrough", _("Passthrough")])
combo.set_active(0)
combo = self.widget("net-portgroup")
# [xml value, label]
model = Gtk.ListStore(str, str)
combo.set_model(model)
uiutil.init_combo_text_column(combo, 1)
self.conn.connect("net-added", self._repopulate_network_list)
self.conn.connect("net-removed", self._repopulate_network_list)
self.conn.connect("interface-added", self._repopulate_network_list)
self.conn.connect("interface-removed", self._repopulate_network_list)
def _pretty_network_desc(self, nettype, source=None, netobj=None):
if nettype == virtinst.DeviceInterface.TYPE_USER:
return _("Usermode networking")
extra = None
if nettype == virtinst.DeviceInterface.TYPE_BRIDGE:
ret = _("Bridge")
elif nettype == virtinst.DeviceInterface.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 _build_source_row(self, nettype, source_name,
label, is_sensitive, is_running, manual_bridge=False, key=None):
return [nettype, source_name, label,
is_sensitive, is_running, manual_bridge,
key]
def _find_virtual_networks(self):
rows = []
vnet_bridges = []
default_label = None
for net in self.conn.list_nets():
nettype = virtinst.DeviceInterface.TYPE_VIRTUAL
label = self._pretty_network_desc(nettype, net.get_name(), net)
if not net.is_active():
label += " (%s)" % _("Inactive")
if net.get_xmlobj().virtualport_type == "openvswitch":
label += " (OpenVSwitch)"
if net.get_name() == "default":
default_label = label
rows.append(self._build_source_row(
nettype, net.get_name(), label, True,
net.is_active(), key=net.get_connkey()))
# 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 rows:
label = _("No virtual networks available")
rows.append(self._build_source_row(
None, None, label, False, False))
return rows, vnet_bridges, default_label
def _find_physical_devices(self, vnet_bridges):
rows = []
can_default = False
default_label = None
skip_ifaces = ["lo"]
vnet_taps = []
for vm in self.conn.list_vms():
for nic in vm.get_interface_devices_norefresh():
if nic.target_dev and nic.target_dev not in vnet_taps:
vnet_taps.append(nic.target_dev)
netdevs = {}
for iface in self.conn.list_interfaces():
name = iface.get_name()
netdevs[name] = NetDev(name, iface.is_bridge(),
iface.get_interface_names())
for nodedev in self.conn.filter_nodedevs("net"):
if nodedev.xmlobj.interface not in netdevs:
netdev = NetDev(nodedev.xmlobj.interface, False, [])
netdevs[nodedev.xmlobj.interface] = netdev
# For every bridge used by a virtual network, and any slaves of
# those devices, don't list them.
for vnet_bridge in vnet_bridges:
slave_names = netdevs.pop(vnet_bridge,
NetDev(None, None, [])).slave_names
for slave in slave_names:
netdevs.pop(slave, None)
for name, is_bridge, slave_names in list(netdevs.values()):
if ((name in vnet_taps) or
(name in [v + "-nic" for v in vnet_bridges]) or
(name in skip_ifaces)):
# Don't list this, as it is basically duplicating
# virtual net info
continue
sensitive = True
source_name = name
label = _("Host device %s") % (name)
if is_bridge:
nettype = virtinst.DeviceInterface.TYPE_BRIDGE
if slave_names:
extra = (_("Host device %s") % slave_names[0])
can_default = True
else:
extra = _("Empty bridge")
label = _("Bridge %s: %s") % (name, extra)
elif self.conn.is_qemu() or self.conn.is_test():
nettype = virtinst.DeviceInterface.TYPE_DIRECT
label += (": %s" % _("macvtap"))
else:
nettype = None
sensitive = False
source_name = None
label += (": %s" % _("Not bridged"))
if can_default and not default_label:
default_label = label
rows.append(self._build_source_row(
nettype, source_name, label, sensitive, True,
key=name))
return rows, default_label
def _populate_network_model(self, model):
model.clear()
def _add_manual_bridge_row():
manual_row = self._build_source_row(
None, None, _("Specify shared device name"),
True, False, manual_bridge=True)
model.append(manual_row)
if self.conn.is_qemu_session():
nettype = virtinst.DeviceInterface.TYPE_USER
r = self._build_source_row(
nettype, None, self._pretty_network_desc(nettype), True, True)
model.append(r)
_add_manual_bridge_row()
return
(vnets, vnet_bridges, default_net) = self._find_virtual_networks()
(iface_rows, default_bridge) = self._find_physical_devices(
vnet_bridges)
# Sorting is:
# 1) Bridges
# 2) Virtual networks
# 3) direct/macvtap
# 4) Disabled list entries
# Each category sorted alphabetically
bridges = [row for row in iface_rows if row[0] == "bridge"]
direct = [row for row in iface_rows if row[0] == "direct"]
disabled = [row for row in iface_rows if row[0] is None]
for rows in [bridges, vnets, direct, disabled]:
rows.sort(key=lambda r: r[2])
for row in rows:
model.append(row)
# 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
label = default_bridge or default_net
default = 0
if not len(model):
row = self._build_source_row(
None, None, _("No networking"), True, False)
model.insert(0, row)
default = 0
elif label:
default = [idx for idx, model_label in enumerate(model) if
model_label[2] == label][0]
_add_manual_bridge_row()
return default
def _check_network_is_running(self, net):
# Make sure VirtualNetwork is running
if not net.type == virtinst.DeviceInterface.TYPE_VIRTUAL:
return
devname = net.source
netobj = None
if net.type == virtinst.DeviceInterface.TYPE_VIRTUAL:
for n in self.conn.list_nets():
if n.get_name() == devname:
netobj = n
break
if not netobj or netobj.is_active():
return
res = self.err.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
# Try to start the network
try:
netobj.start()
log.debug("Started network '%s'", devname)
except Exception as e:
return self.err.show_err(_("Could not start virtual network "
"'%s': %s") % (devname, str(e)))
###############
# Public APIs #
###############
def get_network_row(self):
return uiutil.get_list_selected_row(self.widget("net-source"))
def get_network_selection(self):
bridge_entry = self.widget("net-bridge-name")
row = self.get_network_row()
if not row:
return None, None, None, None
net_type = row[0]
net_src = row[1]
net_check_bridge = row[5]
if net_check_bridge and bridge_entry:
net_type = virtinst.DeviceInterface.TYPE_BRIDGE
net_src = bridge_entry.get_text() or None
mode = None
if self.widget("net-source-mode").is_visible():
mode = uiutil.get_list_selection(self.widget("net-source-mode"))
portgroup = None
if self.widget("net-portgroup").is_visible():
portgroup = uiutil.get_list_selection(self.widget("net-portgroup"))
return net_type, net_src, mode, portgroup or None
def get_vport(self):
vport_type = self.widget("vport-type").get_text()
vport_managerid = self.widget("vport-managerid").get_text()
vport_typeid = self.widget("vport-typeid").get_text()
vport_idver = self.widget("vport-typeidversion").get_text()
vport_instid = self.widget("vport-instanceid").get_text()
return (vport_type, vport_managerid, vport_typeid,
vport_idver, vport_instid)
def build_device(self, macaddr, model=None):
nettype, devname, mode, portgroup = self.get_network_selection()
net = virtinst.DeviceInterface(self.conn.get_backend())
net.type = nettype
net.source = devname
net.macaddr = macaddr
net.model = model
net.source_mode = mode
net.portgroup = portgroup
if net.model == "spapr-vlan":
net.address.set_addrstr("spapr-vio")
if net.type == "direct":
(vport_type, vport_managerid, vport_typeid,
vport_idver, vport_instid) = self.get_vport()
net.virtualport.type = vport_type or None
net.virtualport.managerid = vport_managerid or None
net.virtualport.typeid = vport_typeid or None
net.virtualport.typeidversion = vport_idver or None
net.virtualport.instanceid = vport_instid or None
return net
def validate_device(self, net):
self._check_network_is_running(net)
net.validate()
def reset_state(self):
self._repopulate_network_list()
net_err = None
if (not self.conn.is_nodedev_capable() or
not self.conn.is_interface_capable()):
net_err = _("Libvirt version does not support "
"physical interface listing.")
net_warn = self.widget("net-source-warn")
net_warn.set_visible(bool(net_err))
net_warn.set_tooltip_text(net_err or "")
self.widget("net-bridge-name").set_text("")
self.widget("net-source-mode").set_active(0)
self.widget("net-portgroup").get_child().set_text("")
self.widget("vport-type").set_text("")
self.widget("vport-managerid").set_text("")
self.widget("vport-typeid").set_text("")
self.widget("vport-typeidversion").set_text("")
self.widget("vport-instanceid").set_text("")
def set_dev(self, net):
self.reset_state()
nettype = net.type
source = net.source
if net.network:
# If using type=network with a forward mode=bridge network,
# on domain startup the runtime XML will be changed to
# type=bridge and both source/@bridge and source/@network will
# be filled in. For our purposes, treat this as a type=network
source = net.network
nettype = "network"
source_mode = net.source_mode
is_direct = (net.type == "direct")
uiutil.set_list_selection(self.widget("net-source-mode"), source_mode)
# Virtualport config
self.widget("vport-expander").set_visible(is_direct)
vport = net.virtualport
self.widget("vport-type").set_text(vport.type or "")
self.widget("vport-managerid").set_text(str(vport.managerid or ""))
self.widget("vport-typeid").set_text(str(vport.typeid or ""))
self.widget("vport-typeidversion").set_text(
str(vport.typeidversion or ""))
self.widget("vport-instanceid").set_text(vport.instanceid or "")
# Find the matching row in the net list
combo = self.widget("net-source")
rowiter = None
for row in combo.get_model():
if row[0] == nettype and row[1] == source:
rowiter = row.iter
break
if not rowiter:
if nettype == "bridge":
rowiter = combo.get_model()[-1].iter
self.widget("net-bridge-name").set_text(source)
if not rowiter:
desc = self._pretty_network_desc(nettype, source)
combo.get_model().insert(0,
self._build_source_row(nettype, source, desc, True, True))
rowiter = combo.get_model()[0].iter
combo.set_active_iter(rowiter)
combo.emit("changed")
if net.portgroup:
uiutil.set_list_selection(self.widget("net-portgroup"), net.portgroup)
#############
# Listeners #
#############
def _emit_changed(self, *args, **kwargs):
ignore1 = args
ignore2 = kwargs
self.emit("changed")
def _emit_vport_changed(self, *args, **kwargs):
ignore1 = args
ignore2 = kwargs
self.emit("changed-vport")
def _repopulate_network_list(self, *args, **kwargs):
ignore1 = args
ignore2 = kwargs
netlist = self.widget("net-source")
current_label = uiutil.get_list_selection(netlist, column=2)
model = netlist.get_model()
if not model:
return
try:
if model:
netlist.set_model(None)
default_idx = self._populate_network_model(model)
finally:
netlist.set_model(model)
for row in netlist.get_model():
if current_label and row[2] == current_label:
netlist.set_active_iter(row.iter)
return
if default_idx is None:
default_idx = 0
netlist.set_active(default_idx)
def _populate_portgroups(self, portgroups):
combo = self.widget("net-portgroup")
model = combo.get_model()
model.clear()
default = None
for p in portgroups:
model.append([p.name, p.name])
if p.default:
default = p.name
uiutil.set_list_selection(combo, default)
def _on_net_source_changed(self, src):
ignore = src
self._emit_changed()
row = self.get_network_row()
if not row:
return
is_openvswitch = row[2].endswith("(OpenVSwitch)")
is_direct = (row[0] == virtinst.DeviceInterface.TYPE_DIRECT)
self.widget("vport-expander").set_visible(is_direct or is_openvswitch)
uiutil.set_grid_row_visible(self.widget("net-source-mode"), is_direct)
uiutil.set_grid_row_visible(
self.widget("net-macvtap-warn-box"), is_direct)
if is_direct and self.widget("net-source-mode").get_active() == -1:
self.widget("net-source-mode").set_active(0)
show_bridge = row[5]
uiutil.set_grid_row_visible(
self.widget("net-bridge-name"), show_bridge)
portgroups = []
connkey = row[6]
if connkey and row[0] == virtinst.DeviceInterface.TYPE_VIRTUAL:
portgroups = self.conn.get_net(connkey).get_xmlobj().portgroups
uiutil.set_grid_row_visible(
self.widget("net-portgroup"), bool(portgroups))
self._populate_portgroups(portgroups)
+76
View File
@@ -0,0 +1,76 @@
# Copyright (C) 2018 VMware, Inc.
#
# This work is licensed under the GNU GPLv2 or later.
# See the COPYING file in the top-level directory.
from .. import uiutil
from ..baseclass import vmmGObjectUI
class vmmVsockDetails(vmmGObjectUI):
__gsignals__ = {
"changed-auto-cid": (vmmGObjectUI.RUN_FIRST, None, []),
"changed-cid": (vmmGObjectUI.RUN_FIRST, None, []),
}
MIN_GUEST_CID = 3
def __init__(self, vm, builder, topwin):
super().__init__("vsockdetails.ui", None,
builder=builder, topwin=topwin)
self.vm = vm
self.conn = vm.conn
self.builder.connect_signals({
"on_vsock_auto_toggled": self._vsock_auto_toggled,
"on_vsock_cid_changed": lambda ignore: self.emit("changed-cid"),
})
self.top_box = self.widget("vsock-box")
def _cleanup(self):
self.vm = None
self.conn = None
##############
# Public API #
##############
def reset_state(self):
self.widget("vsock-auto").set_active(True)
self.widget("vsock-cid").set_value(self.MIN_GUEST_CID)
self.widget("vsock-cid").set_visible(False)
def get_values(self):
auto_cid = self.widget("vsock-auto").get_active()
cid = uiutil.spin_get_helper(self.widget("vsock-cid"))
return auto_cid, cid
def set_dev(self, dev):
self.reset_state()
is_auto = bool(dev.auto_cid)
if dev.cid is not None:
cid = int(dev.cid)
else:
cid = self.MIN_GUEST_CID
label = self.widget("vsock-auto").get_label().split(" (")[0]
if is_auto and self.vm.is_active():
label += " (%s %s)" % (_("CID"), cid)
self.widget("vsock-auto").set_label(label)
self.widget("vsock-auto").set_active(is_auto)
self.widget("vsock-cid").set_value(cid)
self.widget("vsock-cid").set_visible(not is_auto)
#############
# Listeners #
#############
def _vsock_auto_toggled(self, ignore):
is_auto = self.widget("vsock-auto").get_active()
self.widget("vsock-cid").set_visible(not is_auto)
self.emit("changed-auto-cid")