details: Allow changing network and sound model on the fly

This commit is contained in:
Cole Robinson 2010-03-23 22:15:53 -04:00
parent 910d51e6b8
commit 929571a8ae
5 changed files with 255 additions and 110 deletions

View File

@ -62,18 +62,6 @@ char_widget_mappings = {
"protocol" : "char-use-telnet",
}
def build_video_combo(vm, video_dev):
video_dev_model = gtk.ListStore(str)
video_dev.set_model(video_dev_model)
text = gtk.CellRendererText()
video_dev.pack_start(text, True)
video_dev.add_attribute(text, 'text', 0)
video_dev_model.set_sort_column_id(0, gtk.SORT_ASCENDING)
for m in VirtualVideoDevice(vm.get_connection().vmm).model_types:
video_dev_model.append([m])
if len(video_dev_model) > 0:
video_dev.set_active(0)
class vmmAddHardware(gobject.GObject):
__gsignals__ = {
"action-show-help": (gobject.SIGNAL_RUN_FIRST,
@ -222,11 +210,7 @@ class vmmAddHardware(gobject.GObject):
# Network model list
netmodel_list = self.window.get_widget("net-model")
netmodel_model = gtk.ListStore(str, str)
netmodel_list.set_model(netmodel_model)
text = gtk.CellRendererText()
netmodel_list.pack_start(text, True)
netmodel_list.add_attribute(text, 'text', 1)
uihelpers.build_netmodel_combo(self.vm, netmodel_list)
# Disk device type / bus
target_list = self.window.get_widget("config-storage-devtype")
@ -264,11 +248,7 @@ class vmmAddHardware(gobject.GObject):
# Sound model list
sound_list = self.window.get_widget("sound-model")
sound_lmodel = gtk.ListStore(str)
sound_list.set_model(sound_lmodel)
text = gtk.CellRendererText()
sound_list.pack_start(text, True)
sound_list.add_attribute(text, 'text', 0)
uihelpers.build_sound_combo(self.vm, sound_list)
host_devtype = self.window.get_widget("host-device-type")
# Description, nodedev type, specific type capability, sub type,
@ -290,7 +270,7 @@ class vmmAddHardware(gobject.GObject):
# Video device
video_dev = self.window.get_widget("video-model")
build_video_combo(self.vm, video_dev)
uihelpers.build_video_combo(self.vm, video_dev)
char_devtype = self.window.get_widget("char-device-type")
# Type name, desc
@ -372,9 +352,8 @@ class vmmAddHardware(gobject.GObject):
net_warn.hide()
netmodel = self.window.get_widget("net-model")
self.populate_network_model_model(netmodel.get_model())
if len(netmodel.get_model()) > 0:
netmodel.set_active(0)
uihelpers.populate_netmodel_combo(self.vm, netmodel)
netmodel.set_active(0)
# Input device init
input_box = self.window.get_widget("input-type")
@ -394,9 +373,8 @@ class vmmAddHardware(gobject.GObject):
# Sound init
sound_box = self.window.get_widget("sound-model")
self.populate_sound_model_model(sound_box.get_model())
sound_box.set_active(0)
# Hostdev init
host_devtype = self.window.get_widget("host-device-type")
self.populate_host_device_type_model(host_devtype.get_model())
@ -452,21 +430,6 @@ class vmmAddHardware(gobject.GObject):
# UI population methods #
#########################
def populate_network_model_model(self, model):
model.clear()
# [xml value, label]
model.append([None, _("Hypervisor default")])
if self.vm.is_hvm():
mod_list = [ "rtl8139", "ne2k_pci", "pcnet" ]
if self.vm.get_hv_type() == "kvm":
mod_list.append("e1000")
mod_list.append("virtio")
mod_list.sort()
for m in mod_list:
model.append([m, m])
def populate_target_device_model(self, model):
model.clear()
#[bus, device, icon, desc, iconsize]
@ -503,13 +466,6 @@ class vmmAddHardware(gobject.GObject):
model.append([_("VNC server"), "vnc"])
model.append([_("Local SDL window"), "sdl"])
def populate_sound_model_model(self, model):
model.clear()
lst = virtinst.VirtualAudio.MODELS
lst.sort()
for m in lst:
model.append([m])
def populate_host_device_type_model(self, model):
model.clear()
for m in [ ["PCI Device", "pci", None, "net", "80203"],

View File

@ -26,7 +26,6 @@ import logging
import traceback
import os
import virtManager.addhardware
import virtManager.uihelpers as uihelpers
from virtManager.error import vmmErrorDialog
from virtManager.addhardware import vmmAddHardware
@ -259,6 +258,10 @@ class vmmDetails(gobject.GObject):
"on_disk_readonly_changed": self.config_enable_apply,
"on_disk_shareable_changed": self.config_enable_apply,
"on_network_model_combo_changed": self.config_enable_apply,
"on_sound_model_combo_changed": self.config_enable_apply,
"on_video_model_combo_changed": self.config_enable_apply,
"on_config_apply_clicked": self.config_apply,
@ -547,9 +550,33 @@ class vmmDetails(gobject.GObject):
txtCol.add_attribute(text, 'text', BOOT_LABEL)
txtCol.add_attribute(text, 'sensitive', BOOT_ACTIVE)
no_default= not self.is_customize_dialog
# Network model
net_model = self.window.get_widget("network-model-combo")
uihelpers.build_netmodel_combo(self.vm, net_model)
# Sound model
sound_dev = self.window.get_widget("sound-model-combo")
uihelpers.build_sound_combo(self.vm, sound_dev, no_default=no_default)
# Video model combo
video_dev = self.window.get_widget("video-model-combo")
virtManager.addhardware.build_video_combo(self.vm, video_dev)
uihelpers.build_video_combo(self.vm, video_dev, no_default=no_default)
# Helper function to handle the combo/label pattern used for
# video model, sound model, network model, etc.
def set_combo_label(self, prefix, model_idx, value):
model_label = self.window.get_widget(prefix + "-label")
model_combo = self.window.get_widget(prefix + "-combo")
model_list = map(lambda x: x[model_idx], model_combo.get_model())
model_in_list = (value in model_list)
model_label.set_property("visible", not model_in_list)
model_combo.set_property("visible", model_in_list)
model_label.set_text(value or "")
if model_in_list:
model_combo.set_active(model_list.index(value))
##########################
# Window state listeners #
@ -1160,6 +1187,10 @@ class vmmDetails(gobject.GObject):
ret = self.config_boot_options_apply()
elif pagetype is HW_LIST_TYPE_DISK:
ret = self.config_disk_apply(info[1])
elif pagetype is HW_LIST_TYPE_NIC:
ret = self.config_network_apply(info[1])
elif pagetype is HW_LIST_TYPE_SOUND:
ret = self.config_sound_apply(info[1])
elif pagetype is HW_LIST_TYPE_VIDEO:
ret = self.config_video_apply(info[1])
else:
@ -1168,6 +1199,16 @@ class vmmDetails(gobject.GObject):
if ret is not False:
self.window.get_widget("config-apply").set_sensitive(False)
# Helper for accessing value of combo/label pattern
def get_combo_label_value(self, prefix, model_idx=0):
combo = self.window.get_widget(prefix + "-combo")
value = None
if combo.get_property("visible"):
value = combo.get_model()[combo.get_active()][model_idx]
return value
# Overview section
def config_overview_apply(self):
# Machine details
@ -1299,14 +1340,22 @@ class vmmDetails(gobject.GObject):
[(dev_id_info, do_readonly),
(dev_id_info, do_shareable)])
# Audio options
def config_sound_apply(self, dev_id_info):
model = self.get_combo_label_value("sound-model")
if model:
return self._change_config_helper(self.vm.define_sound_model,
(dev_id_info, model))
# Network options
def config_network_apply(self, dev_id_info):
model = self.get_combo_label_value("network-model")
return self._change_config_helper(self.vm.define_network_model,
(dev_id_info, model))
# Video options
def config_video_apply(self, dev_id_info):
model_combo = self.window.get_widget("video-model-combo")
model = None
if model_combo.get_property("visible"):
model = model_combo.get_model()[model_combo.get_active()][0]
model = self.get_combo_label_value("video-model")
if model:
return self._change_config_helper(self.vm.define_video_model,
(dev_id_info, model))
@ -1475,20 +1524,10 @@ class vmmDetails(gobject.GObject):
self.window.get_widget("overview-acpi").set_active(acpi)
self.window.get_widget("overview-apic").set_active(apic)
if not clock:
clock = _("Same as host")
clock_combo = self.window.get_widget("overview-clock-combo")
clock_label = self.window.get_widget("overview-clock-label")
clock_list = map(lambda x: x[0], clock_combo.get_model())
clock_in_combo = (clock in clock_list)
clock_combo.set_property("visible", clock_in_combo)
clock_label.set_property("visible", not clock_in_combo)
if clock_in_combo:
clock_combo.set_active(clock_list.index(clock))
else:
clock_label.set_text(clock)
self.set_combo_label("overview-clock", 0, clock)
# Security details
vmmodel, ignore, vmlabel = self.vm.get_seclabel()
@ -1697,6 +1736,7 @@ class vmmDetails(gobject.GObject):
nettype = netinfo[5]
source = netinfo[3]
model = netinfo[6] or None
netobj = None
if nettype == virtinst.VirtualNetworkInterface.TYPE_VIRTUAL:
@ -1714,8 +1754,9 @@ class vmmDetails(gobject.GObject):
self.window.get_widget("network-mac-address").set_text(netinfo[2])
self.window.get_widget("network-source-device").set_text(desc)
model = netinfo[6] or _("Hypervisor default")
self.window.get_widget("network-source-model").set_text(model)
uihelpers.populate_netmodel_combo(self.vm,
self.window.get_widget("network-model-combo"))
self.set_combo_label("network-model", 0, model)
def refresh_input_page(self):
inputinfo = self.get_hw_selection(HW_LIST_COL_DEVICE)
@ -1781,7 +1822,9 @@ class vmmDetails(gobject.GObject):
if not soundinfo:
return
self.window.get_widget("sound-model").set_text(soundinfo[2])
model = soundinfo[2]
self.set_combo_label("sound-model", 0, model)
def refresh_char_page(self):
charinfo = self.get_hw_selection(HW_LIST_COL_DEVICE)
@ -1892,17 +1935,7 @@ class vmmDetails(gobject.GObject):
self.window.get_widget("video-ram").set_text(ramlabel)
self.window.get_widget("video-heads").set_text(heads and heads or "-")
model_label = self.window.get_widget("video-model-label")
model_combo = self.window.get_widget("video-model-combo")
model_list = map(lambda x: x[0], model_combo.get_model())
model_in_list = (model in model_list)
model_label.set_property("visible", not model_in_list)
model_combo.set_property("visible", model_in_list)
model_label.set_text(model)
if model_in_list:
model_combo.set_active(model_list.index(model))
self.set_combo_label("video-model", 0, model)
def refresh_boot_page(self):
# Refresh autostart

View File

@ -171,6 +171,10 @@ class vmmDomainBase(vmmLibvirtObject):
def define_disk_shareable(self, dev_id_info, do_shareable):
raise NotImplementedError()
def define_network_model(self, dev_id_info, newmodel):
raise NotImplementedError()
def define_sound_model(self, dev_id_info, newmodel):
raise NotImplementedError()
def define_video_model(self, dev_id_info, newmodel):
raise NotImplementedError()
@ -1785,6 +1789,46 @@ class vmmDomain(vmmDomainBase):
return self._redefine(util.xml_parse_wrapper, self._change_disk_param,
dev_id_info, "shareable", do_shareable)
# Network properties
def define_network_model(self, dev_id_info, newmodel):
devtype = "interface"
if not self._check_device_is_present(devtype, dev_id_info):
return
def change_model(doc, ctx):
dev_node = self._get_device_xml_nodes(ctx, devtype, dev_id_info)[0]
model_node = dev_node.xpathEval("./model")
model_node = model_node and model_node[0] or None
if not model_node:
if newmodel:
model_node = dev_node.newChild(None, "model", None)
if newmodel:
model_node.setProp("type", newmodel)
else:
model_node.unlinkNode()
model_node.freeNode()
return doc.serialize()
return self._redefine(util.xml_parse_wrapper, change_model)
# Sound properties
def define_sound_model(self, dev_id_info, newmodel):
devtype = "sound"
if not self._check_device_is_present(devtype, dev_id_info):
return
def change_model(doc, ctx):
dev_node = self._get_device_xml_nodes(ctx, devtype, dev_id_info)[0]
dev_node.setProp("model", newmodel)
return doc.serialize()
return self._redefine(util.xml_parse_wrapper, change_model)
# Video properties
def define_video_model(self, dev_id_info, newmodel):
if not self._check_device_is_present("video", dev_id_info):
return
@ -1799,7 +1843,7 @@ class vmmDomain(vmmDomainBase):
return doc.serialize()
return self._redefine(util.xml_parse_wrapper, change_model,
dev_id_info, newmodel)
dev_id_info, newmodel)
########################
# End XML Altering API #
@ -2056,6 +2100,20 @@ class vmmDomainVirtinst(vmmDomainBase):
dev.shareable = do_shareable
self._redefine(change_shareable)
def define_network_model(self, dev_id_info, newmodel):
dev = self._get_device_xml_object(VirtualDevice.VIRTUAL_DEV_NET,
dev_id_info)
def change_model():
dev.model = newmodel
self._redefine(change_model)
def define_sound_model(self, dev_id_info, newmodel):
dev = self._get_device_xml_object(VirtualDevice.VIRTUAL_DEV_AUDIO,
dev_id_info)
def change_model():
dev.model = newmodel
self._redefine(change_model)
def define_video_model(self, dev_id_info, newmodel):
dev = self._get_device_xml_object(VirtualDevice.VIRTUAL_DEV_VIDEO,
dev_id_info)

View File

@ -103,6 +103,67 @@ def host_space_tick(conn, config, widget):
return 1
#####################################################
# Hardware model list building (for details, addhw) #
#####################################################
def build_video_combo(vm, video_dev, no_default=False):
video_dev_model = gtk.ListStore(str)
video_dev.set_model(video_dev_model)
text = gtk.CellRendererText()
video_dev.pack_start(text, True)
video_dev.add_attribute(text, 'text', 0)
video_dev_model.set_sort_column_id(0, gtk.SORT_ASCENDING)
tmpdev = virtinst.VirtualVideoDevice(vm.get_connection().vmm)
for m in tmpdev.model_types:
if m == tmpdev.MODEL_DEFAULT and no_default:
continue
video_dev_model.append([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.SORT_ASCENDING)
for m in virtinst.VirtualAudio.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_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.SORT_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" ]
if vm.get_hv_type() == "kvm":
mod_list.append("e1000")
mod_list.append("virtio")
mod_list.sort()
for m in mod_list:
model.append([m, m])
#######################################################################
# Widgets for listing network device options (in create, addhardware) #

View File

@ -2704,12 +2704,6 @@ I/O:</property>
<property name="y_options"></property>
</packing>
</child>
<child>
<placeholder/>
</child>
<child>
<placeholder/>
</child>
<child>
<widget class="GtkLabel" id="label4">
<property name="visible">True</property>
@ -2735,6 +2729,12 @@ I/O:</property>
<property name="bottom_attach">5</property>
</packing>
</child>
<child>
<placeholder/>
</child>
<child>
<placeholder/>
</child>
</widget>
</child>
</widget>
@ -2906,21 +2906,6 @@ I/O:</property>
<property name="y_options"></property>
</packing>
</child>
<child>
<widget class="GtkLabel" id="network-source-model">
<property name="visible">True</property>
<property name="xalign">0</property>
<property name="selectable">True</property>
</widget>
<packing>
<property name="left_attach">1</property>
<property name="right_attach">2</property>
<property name="top_attach">1</property>
<property name="bottom_attach">2</property>
<property name="x_options">GTK_FILL</property>
<property name="y_options"></property>
</packing>
</child>
<child>
<widget class="GtkLabel" id="network-mac-address">
<property name="visible">True</property>
@ -2934,6 +2919,41 @@ I/O:</property>
<property name="bottom_attach">3</property>
</packing>
</child>
<child>
<widget class="GtkHBox" id="hbox4">
<property name="visible">True</property>
<child>
<widget class="GtkComboBox" id="network-model-combo">
<property name="visible">True</property>
<signal name="changed" handler="on_network_model_combo_changed"/>
</widget>
<packing>
<property name="expand">False</property>
<property name="position">0</property>
</packing>
</child>
<child>
<widget class="GtkLabel" id="network-model-label">
<property name="visible">True</property>
<property name="xalign">0</property>
<property name="label">unknown model</property>
<property name="selectable">True</property>
</widget>
<packing>
<property name="expand">False</property>
<property name="position">1</property>
</packing>
</child>
</widget>
<packing>
<property name="left_attach">1</property>
<property name="right_attach">2</property>
<property name="top_attach">1</property>
<property name="bottom_attach">2</property>
<property name="x_options">GTK_FILL</property>
<property name="y_options"></property>
</packing>
</child>
</widget>
</child>
</widget>
@ -3365,11 +3385,28 @@ I/O:</property>
</packing>
</child>
<child>
<widget class="GtkLabel" id="sound-model">
<widget class="GtkHBox" id="hbox11">
<property name="visible">True</property>
<property name="xalign">0</property>
<property name="label">insert sound model</property>
<property name="selectable">True</property>
<child>
<widget class="GtkComboBox" id="sound-model-combo">
<property name="visible">True</property>
<signal name="changed" handler="on_sound_model_combo_changed"/>
</widget>
<packing>
<property name="position">0</property>
</packing>
</child>
<child>
<widget class="GtkLabel" id="sound-model-label">
<property name="visible">True</property>
<property name="xalign">0</property>
<property name="label">insert sound model</property>
<property name="selectable">True</property>
</widget>
<packing>
<property name="position">1</property>
</packing>
</child>
</widget>
<packing>
<property name="left_attach">1</property>