Add button to connect and disconnect cdrom source device for full virt guests.

This commit is contained in:
Hugh O. Brock 2007-09-21 16:28:31 -04:00
parent fcf3a24805
commit c6e284ce03
7 changed files with 757 additions and 80 deletions

130
src/virtManager/choosecd.py Normal file
View File

@ -0,0 +1,130 @@
#
# Copyright (C) 2006 Red Hat, Inc.
# Copyright (C) 2006 Hugh O. Brock <hbrock@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., 675 Mass Ave, Cambridge, MA 02139, USA.
#
import gtk.glade
import gobject
import logging
from virtManager.opticalhelper import vmmOpticalDriveHelper
class vmmChooseCD(gobject.GObject):
__gsignals__ = {"cdrom-chosen": (gobject.SIGNAL_RUN_FIRST,
gobject.TYPE_NONE,
(str, str, str)), # type, source, target
}
def __init__(self, config, target):
self.__gobject_init__()
self.window = gtk.glade.XML(config.get_glade_dir() + "/vmm-choose-cd.glade", "vmm-choose-cd", domain="virt-manager")
self.config = config
self.window.get_widget("vmm-choose-cd").hide()
self.target = target
self.window.signal_autoconnect({
"on_media_toggled": self.media_toggled,
"on_fv_iso_location_browse_clicked": self.browse_fv_iso_location,
"on_cd_path_changed": self.change_cd_path,
"on_ok_clicked": self.ok,
"on_vmm_choose_cd_delete_event": self.cancel,
"on_cancel_clicked": self.cancel,
})
self.window.get_widget("physical-media").set_active(True)
# set up the list for the cd-path widget
cd_list = self.window.get_widget("cd-path")
# Fields are raw device path, volume label, flag indicating
# whether volume is present or not, and HAL path
cd_model = gtk.ListStore(str, str, bool, str)
cd_list.set_model(cd_model)
text = gtk.CellRendererText()
cd_list.pack_start(text, True)
cd_list.add_attribute(text, 'text', 1)
cd_list.add_attribute(text, 'sensitive', 2)
try:
self.optical_helper = vmmOpticalDriveHelper(self.window.get_widget("cd-path"))
self.optical_helper.populate_opt_media()
self.window.get_widget("physical-media").set_sensitive(True)
except Exception, e:
logging.error("Unable to create optical-helper widget: '%s'", e)
self.window.get_widget("physical-media").set_sensitive(False)
def set_target(self, target):
self.target=target
def close(self,ignore1=None,ignore2=None):
self.window.get_widget("vmm-choose-cd").hide()
return 1
def cancel(self,ignore1=None,ignore2=None):
self.close()
def show(self):
win = self.window.get_widget("vmm-choose-cd")
win.show()
def ok(self,ignore1=None, ignore2=None):
if self.window.get_widget("iso-image").get_active():
self.emit("cdrom-chosen", "file", self.window.get_widget("iso-path").get_text(), self.target)
else:
cd = self.window.get_widget("cd-path")
model = cd.get_model()
self.emit("cdrom-chosen", "block", model.get_value(cd.get_active_iter(), 0), self.target)
self.close()
def media_toggled(self, ignore1=None, ignore2=None):
if self.window.get_widget("physical-media").get_active():
self.window.get_widget("cd-path").set_sensitive(True)
self.window.get_widget("iso-path").set_sensitive(False)
self.window.get_widget("iso-file-chooser").set_sensitive(False)
else:
self.window.get_widget("cd-path").set_sensitive(False)
self.window.get_widget("iso-path").set_sensitive(True)
self.window.get_widget("iso-file-chooser").set_sensitive(True)
def change_cd_path(self, ignore1=None, ignore2=None):
pass
def browse_fv_iso_location(self, ignore1=None, ignore2=None):
file = self._browse_file(_("Locate ISO Image"), type="iso")
if file != None:
self.window.get_widget("iso-path").set_text(file)
def _browse_file(self, dialog_name, folder=None, type=None):
# user wants to browse for an ISO
fcdialog = gtk.FileChooserDialog(dialog_name,
self.window.get_widget("vmm-choose-cd"),
gtk.FILE_CHOOSER_ACTION_OPEN,
(gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL,
gtk.STOCK_OPEN, gtk.RESPONSE_ACCEPT),
None)
if type != None:
f = gtk.FileFilter()
f.add_pattern("*." + type)
fcdialog.set_filter(f)
if folder != None:
fcdialog.set_current_folder(folder)
response = fcdialog.run()
fcdialog.hide()
if(response == gtk.RESPONSE_ACCEPT):
filename = fcdialog.get_filename()
fcdialog.destroy()
return filename
else:
fcdialog.destroy()
return None
gobject.type_register(vmmChooseCD)

View File

@ -37,6 +37,7 @@ import traceback
from virtManager.asyncjob import vmmAsyncJob
from virtManager.error import vmmErrorDialog
from virtManager.createmeter import vmmCreateMeter
from virtManager.opticalhelper import vmmOpticalDriveHelper
VM_PARA_VIRT = 1
VM_FULLY_VIRT = 2
@ -136,17 +137,12 @@ class vmmCreate(gobject.GObject):
cd_list.add_attribute(text, 'text', 1)
cd_list.add_attribute(text, 'sensitive', 2)
try:
# Get a connection to the SYSTEM bus
self.bus = dbus.SystemBus()
# Get a handle to the HAL service
hal_object = self.bus.get_object('org.freedesktop.Hal', '/org/freedesktop/Hal/Manager')
self.hal_iface = dbus.Interface(hal_object, 'org.freedesktop.Hal.Manager')
self.populate_opt_media(cd_model)
self.optical_helper = vmmOpticalDriveHelper(self.window.get_widget("cd-path"))
self.optical_helper.populate_opt_media()
self.window.get_widget("media-physical").set_sensitive(True)
except Exception, e:
logging.error("Unable to connect to HAL to list cdrom volumes: '%s'", e)
logging.error("Unable to create optical-helper widget: '%s'", e)
self.window.get_widget("media-physical").set_sensitive(False)
self.bus = None
self.hal_iface = None
if os.getuid() != 0:
self.window.get_widget("media-physical").set_sensitive(False)
@ -1048,75 +1044,6 @@ class vmmCreate(gobject.GObject):
message_box.destroy()
return res
def populate_opt_media(self, model):
# get a list of optical devices with data discs in, for FV installs
vollabel = {}
volpath = {}
# Track device add/removes so we can detect newly inserted CD media
self.hal_iface.connect_to_signal("DeviceAdded", self._device_added)
self.hal_iface.connect_to_signal("DeviceRemoved", self._device_removed)
# Find info about all current present media
for d in self.hal_iface.FindDeviceByCapability("volume"):
vol = self.bus.get_object("org.freedesktop.Hal", d)
if vol.GetPropertyBoolean("volume.is_disc") and \
vol.GetPropertyBoolean("volume.disc.has_data"):
devnode = vol.GetProperty("block.device")
label = vol.GetProperty("volume.label")
if label == None or len(label) == 0:
label = devnode
vollabel[devnode] = label
volpath[devnode] = d
for d in self.hal_iface.FindDeviceByCapability("storage.cdrom"):
dev = self.bus.get_object("org.freedesktop.Hal", d)
devnode = dev.GetProperty("block.device")
if vollabel.has_key(devnode):
model.append([devnode, vollabel[devnode], True, volpath[devnode]])
else:
model.append([devnode, _("No media present"), False, None])
def _device_added(self, path):
vol = self.bus.get_object("org.freedesktop.Hal", path)
if vol.QueryCapability("volume"):
if vol.GetPropertyBoolean("volume.is_disc") and \
vol.GetPropertyBoolean("volume.disc.has_data"):
devnode = vol.GetProperty("block.device")
label = vol.GetProperty("volume.label")
if label == None or len(label) == 0:
label = devnode
cdlist = self.window.get_widget("cd-path")
model = cdlist.get_model()
# Search for the row with matching device node and
# fill in info about inserted media
for row in model:
if row[0] == devnode:
row[1] = label
row[2] = True
row[3] = path
def _device_removed(self, path):
vol = self.bus.get_object("org.freedesktop.Hal", path)
cdlist = self.window.get_widget("cd-path")
model = cdlist.get_model()
active = cdlist.get_active()
idx = 0
# Search for the row containing matching HAL volume path
# and update (clear) it, de-activating it if its currently
# selected
for row in model:
if row[3] == path:
row[1] = _("No media present")
row[2] = False
row[3] = None
if idx == active:
cdlist.set_active(-1)
idx = idx + 1
def populate_url_model(self, model, urls):
model.clear()
for url in urls:

View File

@ -27,6 +27,7 @@ import traceback
from virtManager.error import vmmErrorDialog
from virtManager.addhardware import vmmAddHardware
from virtManager.choosecd import vmmChooseCD
import virtinst
import urlgrabber.progress as progress
@ -86,7 +87,8 @@ class vmmDetails(gobject.GObject):
self.window.get_widget("hw-panel").set_show_tabs(False)
self.addhw = None
self.choose_cd = None
self.cpu_usage_graph = sparkline.Sparkline()
self.window.get_widget("graph-table").attach(self.cpu_usage_graph, 1, 2, 0, 1)
@ -121,6 +123,7 @@ class vmmDetails(gobject.GObject):
"on_config_memory_apply_clicked": self.config_memory_apply,
"on_details_help_activate": self.show_help,
"on_config_cdrom_connect_clicked": self.toggle_cdrom,
"on_config_disk_remove_clicked": self.remove_disk,
"on_config_network_remove_clicked": self.remove_network,
"on_add_hardware_button_clicked": self.add_hardware,
@ -412,6 +415,16 @@ class vmmDetails(gobject.GObject):
self.window.get_widget("disk-source-path").set_text(diskinfo[1])
self.window.get_widget("disk-target-type").set_text(diskinfo[2])
self.window.get_widget("disk-target-device").set_text(diskinfo[3])
button = self.window.get_widget("config-cdrom-connect")
if diskinfo[2] == "cdrom":
if diskinfo[1] == "-":
# source device not connected
button.set_label(gtk.STOCK_CONNECT)
else:
button.set_label(gtk.STOCK_DISCONNECT)
button.show()
else:
button.hide()
def refresh_network_page(self):
vmlist = self.window.get_widget("hw-list")
@ -595,5 +608,20 @@ class vmmDetails(gobject.GObject):
self.addhw.show()
def toggle_cdrom(self, src):
if src.get_label() == gtk.STOCK_DISCONNECT:
#disconnect the cdrom
self.vm.disconnect_cdrom_device(self.window.get_widget("disk-target-device").get_text())
else:
# connect a new cdrom
if self.choose_cd is None:
self.choose_cd = vmmChooseCD(self.config, self.window.get_widget("disk-target-device").get_text())
self.choose_cd.connect("cdrom-chosen", self.connect_cdrom)
else:
self.choose_cd.set_target(self.window.get_widget("disk-target-device").get_text())
self.choose_cd.show()
def connect_cdrom(self, src, type, source, target):
self.vm.connect_cdrom_device(type, source, target)
gobject.type_register(vmmDetails)

View File

@ -514,6 +514,67 @@ class vmmDomain(gobject.GObject):
def add_disk_device(self, xml):
self.vm.attachDevice(xml)
def connect_cdrom_device(self, type, source, target):
xml = self.get_xml()
doc = None
try:
doc = libxml2.parseDoc(xml)
except:
return []
ctx = doc.xpathNewContext()
try:
disk_fragment = ctx.xpathEval("/domain/devices/disk[@device='cdrom' and target/@dev='%s']" % target)
if len(disk_fragment) == 0:
raise RuntimeError("Attmpted to connect cdrom device to %s, but %s does not exist" % (target,target))
if len(disk_fragment) > 1:
raise RuntimeError("Found multiple cdrom devices named %s. This domain's XML is malformed." % target)
disk_fragment[0].setProp("type", type)
elem = disk_fragment[0].newChild(None, "source", None)
if type == "file":
elem.setProp("file", source)
else:
elem.setProp("dev", source)
result = disk_fragment[0].serialize()
logging.debug("connect_cdrom_device produced the following XML: %s" % result)
finally:
if ctx != None:
ctx.xpathFreeContext()
if doc != None:
doc.freeDoc()
self.add_disk_device(result)
def disconnect_cdrom_device(self, target):
xml = self.get_xml()
doc = None
try:
doc = libxml2.parseDoc(xml)
except:
return []
ctx = doc.xpathNewContext()
try:
disk_fragment = ctx.xpathEval("/domain/devices/disk[@device='cdrom' and target/@dev='%s']" % target)
if len(disk_fragment) == 0:
raise RuntimeError("Attmpted to disconnect cdrom device from %s, but %s does not exist" % (target,target))
if len(disk_fragment) > 1:
raise RuntimeError("Found multiple cdrom devices named %s. This domain's XML is malformed." % target)
sourcenode = None
for child in disk_fragment[0].children:
if child.name == "source":
sourcenode = child
break
else:
continue
sourcenode.unlinkNode()
sourcenode.freeNode()
result = disk_fragment[0].serialize()
logging.debug("disconnect_cdrom_device produced the following XML: %s" % result)
finally:
if ctx != None:
ctx.xpathFreeContext()
if doc != None:
doc.freeDoc()
self.add_disk_device(result)
def get_network_devices(self):
xml = self.get_xml()
doc = None

View File

@ -0,0 +1,106 @@
#
# Copyright (C) 2007 Red Hat, Inc.
#
# 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., 675 Mass Ave, Cambridge, MA 02139, USA.
#
import gobject
import dbus
class vmmOpticalDriveHelper(gobject.GObject):
__gsignals__ = {}
def __init__(self, widget):
self.__gobject_init__()
self.widget = widget
self.model = self.widget.get_model()
try:
# Get a connection to the SYSTEM bus
self.bus = dbus.SystemBus()
# Get a handle to the HAL service
hal_object = self.bus.get_object('org.freedesktop.Hal', '/org/freedesktop/Hal/Manager')
self.hal_iface = dbus.Interface(hal_object, 'org.freedesktop.Hal.Manager')
self.populate_opt_media()
except Exception, e:
logging.error("Unable to connect to HAL to list cdrom volumes: '%s'", e)
self.bus = None
self.hal_iface = None
raise
def populate_opt_media(self):
# get a list of optical devices with data discs in, for FV installs
vollabel = {}
volpath = {}
# Track device add/removes so we can detect newly inserted CD media
self.hal_iface.connect_to_signal("DeviceAdded", self._device_added)
self.hal_iface.connect_to_signal("DeviceRemoved", self._device_removed)
# Find info about all current present media
for d in self.hal_iface.FindDeviceByCapability("volume"):
vol = self.bus.get_object("org.freedesktop.Hal", d)
if vol.GetPropertyBoolean("volume.is_disc") and \
vol.GetPropertyBoolean("volume.disc.has_data"):
devnode = vol.GetProperty("block.device")
label = vol.GetProperty("volume.label")
if label == None or len(label) == 0:
label = devnode
vollabel[devnode] = label
volpath[devnode] = d
for d in self.hal_iface.FindDeviceByCapability("storage.cdrom"):
dev = self.bus.get_object("org.freedesktop.Hal", d)
devnode = dev.GetProperty("block.device")
if vollabel.has_key(devnode):
self.model.append([devnode, vollabel[devnode], True, volpath[devnode]])
else:
self.model.append([devnode, _("No media present"), False, None])
def _device_added(self, path):
vol = self.bus.get_object("org.freedesktop.Hal", path)
if vol.QueryCapability("volume"):
if vol.GetPropertyBoolean("volume.is_disc") and \
vol.GetPropertyBoolean("volume.disc.has_data"):
devnode = vol.GetProperty("block.device")
label = vol.GetProperty("volume.label")
if label == None or len(label) == 0:
label = devnode
# Search for the row with matching device node and
# fill in info about inserted media
for row in self.model:
if row[0] == devnode:
row[1] = label
row[2] = True
row[3] = path
def _device_removed(self, path):
vol = self.bus.get_object("org.freedesktop.Hal", path)
active = self.widget.get_active()
idx = 0
# Search for the row containing matching HAL volume path
# and update (clear) it, de-activating it if its currently
# selected
for row in self.model:
if row[3] == path:
row[1] = _("No media present")
row[2] = False
row[3] = None
if idx == active:
self.widget.set_active(-1)
idx = idx + 1
gobject.type_register(vmmOpticalDriveHelper)

404
src/vmm-choose-cd.glade Normal file
View File

@ -0,0 +1,404 @@
<?xml version="1.0" standalone="no"?> <!--*- mode: xml -*-->
<!DOCTYPE glade-interface SYSTEM "http://glade.gnome.org/glade-2.0.dtd">
<glade-interface>
<widget class="GtkDialog" id="vmm-choose-cd">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="has_focus">True</property>
<property name="title" translatable="yes">Choose A CD Source Device</property>
<property name="type">GTK_WINDOW_TOPLEVEL</property>
<property name="window_position">GTK_WIN_POS_CENTER_ON_PARENT</property>
<property name="modal">False</property>
<property name="resizable">True</property>
<property name="destroy_with_parent">False</property>
<property name="decorated">True</property>
<property name="skip_taskbar_hint">False</property>
<property name="skip_pager_hint">False</property>
<property name="type_hint">GDK_WINDOW_TYPE_HINT_DIALOG</property>
<property name="gravity">GDK_GRAVITY_CENTER</property>
<property name="focus_on_map">True</property>
<property name="urgency_hint">False</property>
<property name="has_separator">False</property>
<signal name="delete_event" handler="on_vmm_choose_cd_delete_event" last_modification_time="Thu, 13 Sep 2007 20:53:31 GMT"/>
<child internal-child="vbox">
<widget class="GtkVBox" id="dialog-vbox1">
<property name="visible">True</property>
<property name="homogeneous">False</property>
<property name="spacing">0</property>
<child internal-child="action_area">
<widget class="GtkHButtonBox" id="dialog-action_area1">
<property name="visible">True</property>
<property name="layout_style">GTK_BUTTONBOX_END</property>
<child>
<widget class="GtkButton" id="OK">
<property name="visible">True</property>
<property name="can_default">True</property>
<property name="can_focus">True</property>
<property name="label">gtk-ok</property>
<property name="use_stock">True</property>
<property name="relief">GTK_RELIEF_NORMAL</property>
<property name="focus_on_click">True</property>
<property name="response_id">-5</property>
<signal name="clicked" handler="on_ok_clicked" last_modification_time="Thu, 13 Sep 2007 20:52:09 GMT"/>
</widget>
</child>
<child>
<widget class="GtkButton" id="Cancel">
<property name="visible">True</property>
<property name="can_default">True</property>
<property name="can_focus">True</property>
<property name="label">gtk-cancel</property>
<property name="use_stock">True</property>
<property name="relief">GTK_RELIEF_NORMAL</property>
<property name="focus_on_click">True</property>
<property name="response_id">-6</property>
<signal name="clicked" handler="on_cancel_clicked" last_modification_time="Thu, 13 Sep 2007 20:52:01 GMT"/>
</widget>
</child>
</widget>
<packing>
<property name="padding">0</property>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="pack_type">GTK_PACK_END</property>
</packing>
</child>
<child>
<widget class="GtkVBox" id="vbox4">
<property name="visible">True</property>
<property name="homogeneous">False</property>
<property name="spacing">0</property>
<child>
<widget class="GtkFrame" id="frame1">
<property name="border_width">3</property>
<property name="visible">True</property>
<property name="label_xalign">0</property>
<property name="label_yalign">0.5</property>
<property name="shadow_type">GTK_SHADOW_ETCHED_IN</property>
<child>
<widget class="GtkAlignment" id="alignment2">
<property name="visible">True</property>
<property name="xalign">0.5</property>
<property name="yalign">0.5</property>
<property name="xscale">1</property>
<property name="yscale">1</property>
<property name="top_padding">0</property>
<property name="bottom_padding">0</property>
<property name="left_padding">12</property>
<property name="right_padding">0</property>
<child>
<widget class="GtkAlignment" id="alignment3">
<property name="visible">True</property>
<property name="xalign">0.5</property>
<property name="yalign">0.5</property>
<property name="xscale">1</property>
<property name="yscale">1</property>
<property name="top_padding">0</property>
<property name="bottom_padding">0</property>
<property name="left_padding">25</property>
<property name="right_padding">0</property>
<child>
<widget class="GtkTable" id="table1">
<property name="visible">True</property>
<property name="n_rows">4</property>
<property name="n_columns">3</property>
<property name="homogeneous">False</property>
<property name="row_spacing">2</property>
<property name="column_spacing">0</property>
<child>
<widget class="GtkAlignment" id="alignment4">
<property name="visible">True</property>
<property name="xalign">0.5</property>
<property name="yalign">0</property>
<property name="xscale">1</property>
<property name="yscale">0</property>
<property name="top_padding">0</property>
<property name="bottom_padding">0</property>
<property name="left_padding">0</property>
<property name="right_padding">0</property>
<child>
<placeholder/>
</child>
</widget>
<packing>
<property name="left_attach">0</property>
<property name="right_attach">1</property>
<property name="top_attach">1</property>
<property name="bottom_attach">2</property>
<property name="x_options">fill</property>
<property name="y_options">fill</property>
</packing>
</child>
<child>
<widget class="GtkAlignment" id="alignment5">
<property name="visible">True</property>
<property name="xalign">0.5</property>
<property name="yalign">0</property>
<property name="xscale">1</property>
<property name="yscale">0</property>
<property name="top_padding">0</property>
<property name="bottom_padding">0</property>
<property name="left_padding">0</property>
<property name="right_padding">0</property>
<child>
<widget class="GtkRadioButton" id="iso-image">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="label" translatable="yes">_ISO Image Location:</property>
<property name="use_underline">True</property>
<property name="relief">GTK_RELIEF_NORMAL</property>
<property name="focus_on_click">True</property>
<property name="active">False</property>
<property name="inconsistent">False</property>
<property name="draw_indicator">True</property>
<signal name="toggled" handler="on_media_toggled" last_modification_time="Tue, 12 Sep 2006 21:35:57 GMT"/>
</widget>
</child>
</widget>
<packing>
<property name="left_attach">0</property>
<property name="right_attach">2</property>
<property name="top_attach">0</property>
<property name="bottom_attach">1</property>
<property name="x_options">fill</property>
<property name="y_options">fill</property>
</packing>
</child>
<child>
<widget class="GtkAlignment" id="alignment6">
<property name="visible">True</property>
<property name="xalign">0.5</property>
<property name="yalign">0</property>
<property name="xscale">1</property>
<property name="yscale">0</property>
<property name="top_padding">0</property>
<property name="bottom_padding">0</property>
<property name="left_padding">0</property>
<property name="right_padding">0</property>
<child>
<widget class="GtkRadioButton" id="physical-media">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="label" translatable="yes">_CD-ROM or DVD:</property>
<property name="use_underline">True</property>
<property name="relief">GTK_RELIEF_NORMAL</property>
<property name="focus_on_click">True</property>
<property name="active">True</property>
<property name="inconsistent">False</property>
<property name="draw_indicator">True</property>
<property name="group">iso-image</property>
<signal name="toggled" handler="on_media_toggled" last_modification_time="Tue, 12 Sep 2006 21:36:05 GMT"/>
</widget>
</child>
</widget>
<packing>
<property name="left_attach">0</property>
<property name="right_attach">3</property>
<property name="top_attach">2</property>
<property name="bottom_attach">3</property>
<property name="x_options">fill</property>
<property name="y_options">fill</property>
</packing>
</child>
<child>
<widget class="GtkHBox" id="hbox1">
<property name="visible">True</property>
<property name="homogeneous">False</property>
<property name="spacing">0</property>
<child>
<widget class="GtkEntry" id="iso-path">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="editable">True</property>
<property name="visibility">True</property>
<property name="max_length">0</property>
<property name="text" translatable="yes"></property>
<property name="has_frame">True</property>
<property name="invisible_char">•</property>
<property name="activates_default">False</property>
</widget>
<packing>
<property name="padding">0</property>
<property name="expand">True</property>
<property name="fill">True</property>
</packing>
</child>
<child>
<widget class="GtkButton" id="iso-file-chooser">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="label" translatable="yes">_Browse...</property>
<property name="use_underline">True</property>
<property name="relief">GTK_RELIEF_NORMAL</property>
<property name="focus_on_click">True</property>
<signal name="clicked" handler="on_fv_iso_location_browse_clicked" last_modification_time="Thu, 10 Aug 2006 15:47:24 GMT"/>
</widget>
<packing>
<property name="padding">0</property>
<property name="expand">False</property>
<property name="fill">False</property>
</packing>
</child>
</widget>
<packing>
<property name="left_attach">2</property>
<property name="right_attach">3</property>
<property name="top_attach">1</property>
<property name="bottom_attach">2</property>
<property name="x_options">fill</property>
<property name="y_options">fill</property>
</packing>
</child>
<child>
<widget class="GtkLabel" id="label36">
<property name="visible">True</property>
<property name="label" translatable="yes">ISO _Location:</property>
<property name="use_underline">True</property>
<property name="use_markup">False</property>
<property name="justify">GTK_JUSTIFY_LEFT</property>
<property name="wrap">False</property>
<property name="selectable">False</property>
<property name="xalign">1</property>
<property name="yalign">0.5</property>
<property name="xpad">0</property>
<property name="ypad">0</property>
<property name="mnemonic_widget">iso-path</property>
<property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
<property name="width_chars">-1</property>
<property name="single_line_mode">False</property>
<property name="angle">0</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_padding">3</property>
<property name="x_options">fill</property>
<property name="y_options"></property>
</packing>
</child>
<child>
<widget class="GtkHBox" id="hbox2">
<property name="visible">True</property>
<property name="homogeneous">False</property>
<property name="spacing">0</property>
<child>
<widget class="GtkLabel" id="label38">
<property name="visible">True</property>
<property name="label" translatable="yes">_Path to install media:</property>
<property name="use_underline">True</property>
<property name="use_markup">False</property>
<property name="justify">GTK_JUSTIFY_LEFT</property>
<property name="wrap">False</property>
<property name="selectable">False</property>
<property name="xalign">0.5</property>
<property name="yalign">0.5</property>
<property name="xpad">5</property>
<property name="ypad">0</property>
<property name="mnemonic_widget">cd-path</property>
<property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
<property name="width_chars">-1</property>
<property name="single_line_mode">False</property>
<property name="angle">0</property>
</widget>
<packing>
<property name="padding">0</property>
<property name="expand">False</property>
<property name="fill">False</property>
</packing>
</child>
<child>
<widget class="GtkComboBox" id="cd-path">
<property name="visible">True</property>
<property name="add_tearoffs">False</property>
<property name="focus_on_click">True</property>
<signal name="changed" handler="on_cd_path_changed" last_modification_time="Wed, 23 Aug 2006 20:46:09 GMT"/>
</widget>
<packing>
<property name="padding">0</property>
<property name="expand">True</property>
<property name="fill">True</property>
</packing>
</child>
</widget>
<packing>
<property name="left_attach">1</property>
<property name="right_attach">3</property>
<property name="top_attach">3</property>
<property name="bottom_attach">4</property>
<property name="x_options">fill</property>
</packing>
</child>
</widget>
</child>
</widget>
</child>
</widget>
</child>
<child>
<widget class="GtkLabel" id="label35">
<property name="visible">True</property>
<property name="label" translatable="yes">&lt;b&gt;CD Source Device Or File&lt;/b&gt;</property>
<property name="use_underline">False</property>
<property name="use_markup">True</property>
<property name="justify">GTK_JUSTIFY_LEFT</property>
<property name="wrap">False</property>
<property name="selectable">False</property>
<property name="xalign">0.5</property>
<property name="yalign">0.5</property>
<property name="xpad">0</property>
<property name="ypad">0</property>
<property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
<property name="width_chars">-1</property>
<property name="single_line_mode">False</property>
<property name="angle">0</property>
</widget>
<packing>
<property name="type">label_item</property>
</packing>
</child>
</widget>
<packing>
<property name="padding">0</property>
<property name="expand">True</property>
<property name="fill">True</property>
</packing>
</child>
</widget>
<packing>
<property name="padding">0</property>
<property name="expand">True</property>
<property name="fill">True</property>
</packing>
</child>
</widget>
</child>
</widget>
</glade-interface>

View File

@ -1924,7 +1924,7 @@
<property name="border_width">3</property>
<property name="visible">True</property>
<property name="n_rows">4</property>
<property name="n_columns">2</property>
<property name="n_columns">3</property>
<property name="homogeneous">False</property>
<property name="row_spacing">3</property>
<property name="column_spacing">3</property>
@ -2152,6 +2152,27 @@
<property name="y_options"></property>
</packing>
</child>
<child>
<widget class="GtkButton" id="config-cdrom-connect">
<property name="visible">True</property>
<property name="can_default">True</property>
<property name="can_focus">True</property>
<property name="label">gtk-connect</property>
<property name="use_stock">True</property>
<property name="relief">GTK_RELIEF_NORMAL</property>
<property name="focus_on_click">True</property>
<signal name="clicked" handler="on_config_cdrom_connect_clicked" last_modification_time="Wed, 12 Sep 2007 18:54:06 GMT"/>
</widget>
<packing>
<property name="left_attach">2</property>
<property name="right_attach">3</property>
<property name="top_attach">1</property>
<property name="bottom_attach">2</property>
<property name="x_options">fill</property>
<property name="y_options"></property>
</packing>
</child>
</widget>
</child>
</widget>