addhw: Greatly simply 'Add Network' wizard

Use a single combo box for the source device, and drop the network hints.
Most people likely won't have virtual networking and bridging set up, and if
they do they probably know what they are doing.

This allows us to reuse the UI code from the create wizard.
This commit is contained in:
Cole Robinson 2009-11-24 13:14:55 -05:00
parent 333a37209e
commit 6c968e7944
4 changed files with 197 additions and 397 deletions

View File

@ -31,6 +31,7 @@ import virtinst
from virtinst import VirtualCharDevice, VirtualDevice, VirtualVideoDevice
import virtManager.util as vmmutil
import virtManager.uihelpers as uihelpers
from virtManager.asyncjob import vmmAsyncJob
from virtManager.error import vmmErrorDialog
from virtManager.createmeter import vmmCreateMeter
@ -96,25 +97,30 @@ class vmmAddHardware(gobject.GObject):
self.topwin.hide()
self.window.signal_autoconnect({
"on_hardware_type_changed" : self.hardware_type_changed,
"on_create_pages_switch_page" : self.page_changed,
"on_create_cancel_clicked" : self.close,
"on_vmm_create_delete_event" : self.close,
"on_create_back_clicked" : self.back,
"on_create_forward_clicked" : self.forward,
"on_create_finish_clicked" : self.finish,
"on_create_help_clicked": self.show_help,
"on_hardware_type_changed" : self.hardware_type_changed,
"on_storage_partition_address_browse_clicked" : self.browse_storage_partition_address,
"on_storage_file_address_browse_clicked" : self.browse_storage_file_address,
"on_storage_file_address_changed": self.toggle_storage_size,
"on_storage_toggled" : self.change_storage_type,
"on_network_toggled" : self.change_network_type,
"on_mac_address_clicked" : self.change_macaddr_use,
"on_graphics_type_changed": self.change_graphics_type,
"on_graphics_port_auto_toggled": self.change_port_auto,
"on_graphics_keymap_toggled": self.change_keymap,
"on_host_device_type_changed": self.change_host_device_type,
"on_char_device_type_changed": self.change_char_device_type,
"on_create_help_clicked": self.show_help,
# Char dev info signals
"char_device_type_focus": (self.update_doc, "char_type"),
@ -200,21 +206,8 @@ class vmmAddHardware(gobject.GObject):
hw_list.add_attribute(text, 'sensitive', 3)
# Virtual network list
network_list = self.window.get_widget("net-network")
network_model = gtk.ListStore(str, str)
network_list.set_model(network_model)
text = gtk.CellRendererText()
network_list.pack_start(text, True)
network_list.add_attribute(text, 'text', 1)
# Physical network list
device_list = self.window.get_widget("net-device")
device_model = gtk.ListStore(str, str, bool)
device_list.set_model(device_model)
text = gtk.CellRendererText()
device_list.pack_start(text, True)
device_list.add_attribute(text, 'text', 1)
device_list.add_attribute(text, 'sensitive', 2)
net_list = self.window.get_widget("net-list")
uihelpers.init_network_list(net_list)
# Network model list
netmodel_list = self.window.get_widget("net-model")
@ -313,7 +306,6 @@ class vmmAddHardware(gobject.GObject):
def reset_state(self):
notebook = self.window.get_widget("create-pages")
notebook.set_current_page(0)
is_remote = self.vm.get_connection().is_remote()
# Hide the "finish" button until the appropriate time
self.window.get_widget("create-finish").hide()
@ -338,38 +330,19 @@ class vmmAddHardware(gobject.GObject):
target_list.set_active(0)
# Network init
self.change_network_type()
newmac = uihelpers.generate_macaddr(self.vm.get_connection())
self.window.get_widget("mac-address").set_active(bool(newmac))
self.window.get_widget("create-mac-address").set_text(newmac)
self.change_macaddr_use()
self.window.get_widget("net-type-network").set_active(True)
self.window.get_widget("net-type-device").set_active(False)
self.window.get_widget("mac-address").set_active(False)
self.window.get_widget("create-mac-address").set_text("")
self.window.get_widget("net-model").set_active(0)
net_box = self.window.get_widget("net-network")
self.populate_network_model(net_box.get_model())
net_box.set_active(0)
dev_box = self.window.get_widget("net-device")
res = self.populate_device_model(dev_box.get_model())
if res[0]:
dev_box.set_active(res[1])
else:
dev_box.set_active(-1)
net_list = self.window.get_widget("net-list")
uihelpers.populate_network_list(net_list, self.vm.get_connection())
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)
if is_remote:
self.window.get_widget("net-type-network").set_active(True)
self.window.get_widget("net-type-device").set_active(False)
self.window.get_widget("net-type-device").set_sensitive(False)
self.window.get_widget("net-device").set_active(-1)
else:
self.window.get_widget("net-type-device").set_sensitive(True)
# Input device init
input_box = self.window.get_widget("input-type")
self.populate_input_model(input_box.get_model())
@ -445,27 +418,6 @@ class vmmAddHardware(gobject.GObject):
# UI population methods #
#########################
def populate_network_model(self, model):
model.clear()
for uuid in self.vm.get_connection().list_net_uuids():
net = self.vm.get_connection().get_net(uuid)
model.append([net.get_label(), net.get_name()])
def populate_device_model(self, model):
model.clear()
hasShared = False
brIndex = -1
for name in self.vm.get_connection().list_net_device_paths():
net = self.vm.get_connection().get_net_device(name)
if net.is_shared():
hasShared = True
if brIndex < 0:
brIndex = len(model)
model.append([net.get_bridge(), "%s (%s %s)" % (net.get_name(), _("Bridge"), net.get_bridge()), True])
else:
model.append([net.get_bridge(), "%s (%s)" % (net.get_name(), _("Not bridged")), False])
return (hasShared, brIndex)
def populate_network_model_model(self, model):
model.clear()
@ -645,17 +597,18 @@ class vmmAddHardware(gobject.GObject):
# Network getters
def get_config_network(self):
if self.vm.get_connection().is_qemu_session():
return ["user", None]
net_list = self.window.get_widget("net-list")
selection = net_list.get_active()
model = net_list.get_model()
if self.window.get_widget("net-type-network").get_active():
net = self.window.get_widget("net-network")
model = net.get_model()
return ["network", model.get_value(net.get_active_iter(), 0)]
else:
dev = self.window.get_widget("net-device")
model = dev.get_model()
return ["bridge", model.get_value(dev.get_active_iter(), 0)]
nettype = None
devname = None
if selection >= 0:
row = model[selection]
nettype = row[0]
devname = row[1]
return (nettype, devname)
def get_config_net_model(self):
model = self.window.get_widget("net-model")
@ -981,14 +934,6 @@ class vmmAddHardware(gobject.GObject):
self.toggle_storage_size()
# Network listeners
def change_network_type(self, ignore=None):
if self.window.get_widget("net-type-network").get_active():
self.window.get_widget("net-network").set_sensitive(True)
self.window.get_widget("net-device").set_sensitive(False)
else:
self.window.get_widget("net-network").set_sensitive(False)
self.window.get_widget("net-device").set_sensitive(True)
def change_macaddr_use(self, ignore=None):
if self.window.get_widget("mac-address").get_active():
self.window.get_widget("create-mac-address").set_sensitive(True)
@ -1254,54 +1199,24 @@ class vmmAddHardware(gobject.GObject):
return res
def validate_page_network(self):
net = self.get_config_network()
if self.window.get_widget("net-type-network").get_active():
if self.window.get_widget("net-network").get_active() == -1:
return self.err.val_err(_("Virtual Network Required"),
_("You must select one of the virtual networks."))
else:
if self.window.get_widget("net-device").get_active() == -1:
return self.err.val_err(_("Physical Device Required"),
_("You must select a physical device."))
nettype, devname = self.get_config_network()
mac = self.get_config_macaddr()
if self.window.get_widget("mac-address").get_active():
if mac is None or len(mac) == 0:
return self.err.val_err(_("Invalid MAC address"),
_("No MAC address was entered. Please enter a valid MAC address."))
try:
self._dev = virtinst.VirtualNetworkInterface(macaddr=mac)
except ValueError, e:
return self.err.val_err(_("Invalid MAC address"), str(e))
model = self.get_config_net_model()[0]
try:
if net[0] == "bridge":
self._dev = virtinst.VirtualNetworkInterface(macaddr=mac,
type=net[0],
bridge=net[1])
elif net[0] == "network":
self._dev = virtinst.VirtualNetworkInterface(macaddr=mac,
type=net[0],
network=net[1])
else:
raise ValueError, _("Unsupported networking type") + net[0]
self._dev.model = model
if not nettype:
return self.err.val_err(_("Network selection error."),
_("A network source must be selected."))
except ValueError, e:
return self.err.val_err(_("Invalid Network Parameter"), str(e))
if not mac:
return self.err.val_err(_("Invalid MAC address"),
_("A MAC address must be entered."))
conflict = self._dev.is_conflict_net(self.vm.get_connection().vmm)
if conflict[0]:
return self.err.val_err(_("Mac address collision"),
conflict[1])
elif conflict[1] is not None:
return self.err.yes_no(_("Mac address collision"),
conflict[1] + " " + _("Are you sure you want to use this address?"))
ret = uihelpers.validate_network(self.topwin, self.vm.get_connection(),
nettype, devname, mac, model)
if ret == False:
return False
self._dev = ret
def validate_page_graphics(self):
graphics = self.get_config_graphics()

View File

@ -29,7 +29,6 @@ import threading
import logging
import virtinst
from virtinst import VirtualNetworkInterface
import virtManager.opticalhelper
import virtManager.uihelpers as uihelpers
@ -479,14 +478,8 @@ class vmmCreate(gobject.GObject):
net_list = self.window.get_widget("config-netdev")
uihelpers.populate_network_list(net_list, self.conn)
self.window.get_widget("config-set-macaddr").set_active(True)
newmac = ""
try:
net = VirtualNetworkInterface(conn=self.conn.vmm)
net.setup(self.conn.vmm)
newmac = net.macaddr
except Exception, e:
logging.exception("Generating macaddr failed: %s" % str(e))
newmac = uihelpers.generate_macaddr(self.conn)
self.window.get_widget("config-set-macaddr").set_active(bool(newmac))
self.window.get_widget("config-macaddr").set_text(newmac)
def populate_hv(self):

View File

@ -43,20 +43,31 @@ def init_network_list(net_list):
# [ network type, source name, label, sensitive? ]
net_model = gtk.ListStore(str, str, str, bool)
net_list.set_model(net_model)
if isinstance(net_list, gtk.ComboBox):
net_col = net_list
else:
net_col = gtk.TreeViewColumn()
net_list.append_column(net_col)
text = gtk.CellRendererText()
net_list.pack_start(text, True)
net_list.add_attribute(text, 'text', 2)
net_list.add_attribute(text, 'sensitive', 3)
net_col.pack_start(text, True)
net_col.add_attribute(text, 'text', 2)
net_col.add_attribute(text, 'sensitive', 3)
def populate_network_list(net_list, conn):
model = net_list.get_model()
model.clear()
def set_active(idx):
if isinstance(net_list, gtk.ComboBox):
net_list.set_active(idx)
# For qemu:///session
if conn.is_qemu_session():
model.append([VirtualNetworkInterface.TYPE_USER, None,
_("Usermode Networking"), True])
net_list.set_active(0)
set_active(0)
return
hasNet = False
@ -118,7 +129,7 @@ def populate_network_list(net_list, conn):
model.insert(0, [None, None, _("No networking."), True])
default = 0
net_list.set_active(default)
set_active(default)
def validate_network(parent, conn, nettype, devname, macaddr, model=None):
set_error_parent(parent)
@ -163,7 +174,8 @@ def validate_network(parent, conn, nettype, devname, macaddr, model=None):
net = VirtualNetworkInterface(type = nettype,
bridge = bridge,
network = netname,
macaddr = macaddr)
macaddr = macaddr,
model = model)
except Exception, e:
return err_dial.val_err(_("Error with network parameters."), str(e))
@ -180,3 +192,13 @@ def validate_network(parent, conn, nettype, devname, macaddr, model=None):
return net
def generate_macaddr(conn):
newmac = ""
try:
net = VirtualNetworkInterface(conn=conn.vmm)
net.setup(conn.vmm)
newmac = net.macaddr
except:
pass
return newmac

View File

@ -826,291 +826,161 @@
<child>
<widget class="GtkTable" id="table31">
<property name="visible">True</property>
<property name="n_rows">9</property>
<property name="n_rows">3</property>
<property name="n_columns">2</property>
<property name="column_spacing">6</property>
<property name="row_spacing">6</property>
<child>
<widget class="GtkComboBox" id="net-device">
<property name="visible">True</property>
<accessibility>
<atkproperty name="AtkObject::accessible-name" translatable="yes">Network Device Select</atkproperty>
</accessibility>
</widget>
<packing>
<property name="left_attach">1</property>
<property name="right_attach">2</property>
<property name="top_attach">4</property>
<property name="bottom_attach">5</property>
<property name="x_options">GTK_FILL</property>
<property name="y_options">GTK_FILL</property>
</packing>
</child>
<child>
<widget class="GtkRadioButton" id="net-type-network">
<property name="label" translatable="yes">_Virtual network</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">False</property>
<property name="use_underline">True</property>
<property name="active">True</property>
<property name="draw_indicator">True</property>
<signal name="toggled" handler="on_network_toggled"/>
</widget>
<packing>
<property name="right_attach">2</property>
<property name="x_options">GTK_FILL</property>
<property name="y_options">GTK_FILL</property>
</packing>
</child>
<child>
<widget class="GtkRadioButton" id="net-type-device">
<property name="label" translatable="yes">_Shared physical device</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">False</property>
<property name="use_underline">True</property>
<property name="draw_indicator">True</property>
<property name="group">net-type-network</property>
<signal name="toggled" handler="on_network_toggled"/>
</widget>
<packing>
<property name="right_attach">2</property>
<property name="top_attach">3</property>
<property name="bottom_attach">4</property>
<property name="x_options">GTK_FILL</property>
<property name="y_options">GTK_FILL</property>
</packing>
</child>
<child>
<widget class="GtkAlignment" id="alignment144">
<property name="visible">True</property>
<property name="left_padding">40</property>
<child>
<widget class="GtkHBox" id="hbox63">
<property name="visible">True</property>
<child>
<widget class="GtkImage" id="image104">
<property name="visible">True</property>
<property name="yalign">0</property>
<property name="icon_name">gtk-dialog-info</property>
</widget>
<packing>
<property name="expand">False</property>
<property name="position">0</property>
</packing>
</child>
<child>
<widget class="GtkLabel" id="label374">
<property name="visible">True</property>
<property name="xpad">7</property>
<property name="label" translatable="yes">&lt;small&gt;&lt;b&gt;Tip:&lt;/b&gt; Choose this option if your host is disconnected, connected via wireless, or dynamically configured with NetworkManager.&lt;/small&gt;</property>
<property name="use_markup">True</property>
<property name="wrap">True</property>
</widget>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">1</property>
</packing>
</child>
</widget>
</child>
</widget>
<packing>
<property name="right_attach">2</property>
<property name="top_attach">2</property>
<property name="bottom_attach">3</property>
<property name="x_options">GTK_FILL</property>
</packing>
</child>
<child>
<widget class="GtkAlignment" id="alignment145">
<property name="visible">True</property>
<property name="left_padding">40</property>
<child>
<widget class="GtkHBox" id="hbox61">
<property name="visible">True</property>
<child>
<widget class="GtkImage" id="image102">
<property name="visible">True</property>
<property name="yalign">0</property>
<property name="icon_name">gtk-dialog-info</property>
</widget>
<packing>
<property name="expand">False</property>
<property name="position">0</property>
</packing>
</child>
<child>
<widget class="GtkLabel" id="label372">
<property name="visible">True</property>
<property name="xpad">7</property>
<property name="label" translatable="yes">&lt;small&gt;&lt;b&gt;Tip:&lt;/b&gt; Choose this option if your host is statically connected to wired ethernet, to gain the ability to migrate the virtual machine.&lt;/small&gt;</property>
<property name="use_markup">True</property>
<property name="wrap">True</property>
</widget>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">1</property>
</packing>
</child>
</widget>
</child>
</widget>
<packing>
<property name="right_attach">2</property>
<property name="top_attach">5</property>
<property name="bottom_attach">6</property>
<property name="x_options">GTK_FILL</property>
</packing>
</child>
<child>
<widget class="GtkComboBox" id="net-network">
<property name="visible">True</property>
<accessibility>
<atkproperty name="AtkObject::accessible-name" translatable="yes">Virtual Network Select</atkproperty>
</accessibility>
</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="y_options">GTK_FILL</property>
</packing>
</child>
<child>
<widget class="GtkAlignment" id="alignment146">
<property name="visible">True</property>
<property name="left_padding">40</property>
<child>
<widget class="GtkEventBox" id="eventbox1">
<property name="visible">True</property>
<child>
<widget class="GtkLabel" id="label366">
<property name="visible">True</property>
<property name="xalign">1</property>
<property name="xpad">4</property>
<property name="label" translatable="yes">_Network:</property>
<property name="use_markup">True</property>
<property name="use_underline">True</property>
<property name="mnemonic_widget">storage-partition-address</property>
</widget>
</child>
</widget>
</child>
</widget>
<packing>
<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="GtkAlignment" id="alignment147">
<property name="visible">True</property>
<property name="left_padding">40</property>
<child>
<widget class="GtkEventBox" id="eventbox2">
<property name="visible">True</property>
<child>
<widget class="GtkLabel" id="label368">
<property name="visible">True</property>
<property name="xalign">1</property>
<property name="xpad">4</property>
<property name="label" translatable="yes">_Device:</property>
<property name="use_markup">True</property>
<property name="use_underline">True</property>
<property name="mnemonic_widget">storage-file-address</property>
</widget>
</child>
</widget>
</child>
</widget>
<packing>
<property name="top_attach">4</property>
<property name="bottom_attach">5</property>
<property name="x_options">GTK_FILL</property>
<property name="y_options"></property>
</packing>
</child>
<child>
<widget class="GtkCheckButton" id="mac-address">
<property name="label" translatable="yes">Set fixed MAC _address for this NIC?</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">False</property>
<property name="use_underline">True</property>
<property name="draw_indicator">True</property>
<signal name="clicked" handler="on_mac_address_clicked"/>
</widget>
<packing>
<property name="right_attach">2</property>
<property name="top_attach">6</property>
<property name="bottom_attach">7</property>
<property name="x_options">GTK_FILL</property>
<property name="y_options"></property>
</packing>
</child>
<property name="column_spacing">12</property>
<property name="row_spacing">9</property>
<child>
<widget class="GtkLabel" id="label386">
<property name="visible">True</property>
<property name="xalign">1</property>
<property name="xalign">0</property>
<property name="label" translatable="yes">_MAC address:</property>
<property name="use_markup">True</property>
<property name="use_underline">True</property>
<property name="mnemonic_widget">create-mac-address</property>
</widget>
<packing>
<property name="top_attach">7</property>
<property name="bottom_attach">8</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="GtkEntry" id="create-mac-address">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="max_length">17</property>
<accessibility>
<atkproperty name="AtkObject::accessible-name" translatable="yes">MAC Address Field</atkproperty>
</accessibility>
</widget>
<packing>
<property name="left_attach">1</property>
<property name="right_attach">2</property>
<property name="top_attach">7</property>
<property name="bottom_attach">8</property>
<property name="y_options"></property>
</packing>
</child>
<child>
<widget class="GtkLabel" id="label6">
<property name="visible">True</property>
<property name="xalign">1</property>
<property name="label" translatable="yes">D_evice Model:</property>
<property name="xalign">0</property>
<property name="label" translatable="yes">D_evice model:</property>
<property name="use_underline">True</property>
<property name="mnemonic_widget">net-model</property>
</widget>
<packing>
<property name="top_attach">8</property>
<property name="bottom_attach">9</property>
<property name="top_attach">2</property>
<property name="bottom_attach">3</property>
<property name="x_options">GTK_FILL</property>
</packing>
</child>
<child>
<widget class="GtkComboBox" id="net-model">
<widget class="GtkHBox" id="hbox2">
<property name="visible">True</property>
<property name="spacing">6</property>
<child>
<widget class="GtkCheckButton" id="mac-address">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">False</property>
<property name="use_underline">True</property>
<property name="draw_indicator">True</property>
<signal name="clicked" handler="on_mac_address_clicked"/>
</widget>
<packing>
<property name="expand">False</property>
<property name="position">0</property>
</packing>
</child>
<child>
<widget class="GtkEntry" id="create-mac-address">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="max_length">17</property>
<property name="invisible_char">&#x25CF;</property>
<property name="text" translatable="yes">aa:bb:cc:dd:ee:ff</property>
<accessibility>
<atkproperty name="AtkObject::accessible-name" translatable="yes">MAC Address Field</atkproperty>
</accessibility>
</widget>
<packing>
<property name="expand">False</property>
<property name="position">1</property>
</packing>
</child>
<child>
<widget class="GtkAlignment" id="alignment13">
<property name="visible">True</property>
<child>
<placeholder/>
</child>
</widget>
<packing>
<property name="position">2</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="y_options"></property>
</packing>
</child>
<child>
<widget class="GtkHBox" id="hbox5">
<property name="visible">True</property>
<property name="spacing">6</property>
<child>
<widget class="GtkComboBox" id="net-model">
<property name="visible">True</property>
</widget>
<packing>
<property name="expand">False</property>
<property name="position">0</property>
</packing>
</child>
<child>
<widget class="GtkAlignment" id="alignment14">
<property name="visible">True</property>
<child>
<placeholder/>
</child>
</widget>
<packing>
<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">2</property>
<property name="bottom_attach">3</property>
</packing>
</child>
<child>
<widget class="GtkLabel" id="label22">
<property name="visible">True</property>
<property name="xalign">0</property>
<property name="label" translatable="yes">Host device:</property>
</widget>
<packing>
<property name="x_options">GTK_FILL</property>
</packing>
</child>
<child>
<widget class="GtkHBox" id="hbox6">
<property name="visible">True</property>
<child>
<widget class="GtkComboBox" id="net-list">
<property name="visible">True</property>
</widget>
<packing>
<property name="expand">False</property>
<property name="position">0</property>
</packing>
</child>
<child>
<widget class="GtkAlignment" id="alignment15">
<property name="visible">True</property>
<child>
<placeholder/>
</child>
</widget>
<packing>
<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">8</property>
<property name="bottom_attach">9</property>
</packing>
</child>
</widget>