Remove 'Choose CD', rework details and create media change
The new UI is handled in mediacombo. It's a combobox+entry. The combobox is prepopulated with host cdrom/floppy devices, and previously used media paths from gsettings The new VM wizard no longer has separate UI for cdrom device vs ISO media. The choosecd dialog is gone all together, and media is changed with the 'apply' button like all other details changes
This commit is contained in:
parent
8ff5d750da
commit
0638e72f1f
|
@ -167,7 +167,7 @@ Foo bar baz & yeah boii < > yeahfoo
|
|||
|
||||
<!-- bus fdc -->
|
||||
<disk type='block' device='floppy'>
|
||||
<source dev='/dev/null'>
|
||||
<source dev='/dev/fda'>
|
||||
<seclabel model='selinux' relabel='no'/>
|
||||
<seclabel model='dac' relabel='no'/>
|
||||
</source>
|
||||
|
@ -206,7 +206,7 @@ Foo bar baz & yeah boii < > yeahfoo
|
|||
|
||||
<disk type='file' device='disk'>
|
||||
<driver name="qemu" type="qcow2" cache="none"/>
|
||||
<source file='/tmp/foobar2'/>
|
||||
<source file='/tmp/foobar2/this_is_a_really_long_path_to_see_how_the_ui_handles_it/hopefully_it_doesnt_mess_things_up_too_bad/i_guess_we_will_see/in_fact_can_we_see_this_filename.img'/>
|
||||
<target dev='sda' bus='scsi'/>
|
||||
<boot order='1'/>
|
||||
<address type='drive' controller='9' bus='0' target='0' unit='0'/>
|
||||
|
|
|
@ -1,95 +0,0 @@
|
|||
# This work is licensed under the GNU GPLv2 or later.
|
||||
# See the COPYING file in the top-level directory.
|
||||
|
||||
from tests.uitests import utils as uiutils
|
||||
|
||||
|
||||
class ChooseCD(uiutils.UITestCase):
|
||||
"""
|
||||
UI tests for the choosecd dialog
|
||||
"""
|
||||
|
||||
###################
|
||||
# Private helpers #
|
||||
###################
|
||||
|
||||
##############
|
||||
# Test cases #
|
||||
##############
|
||||
|
||||
def testChooseCD(self):
|
||||
win = self._open_details_window(shutdown=True)
|
||||
hw = win.find("hw-list")
|
||||
tab = win.find("disk-tab")
|
||||
|
||||
# Floppy + physical
|
||||
hw.find("Floppy 1", "table cell").click()
|
||||
tab.find("Disconnect", "push button").click()
|
||||
tab.find("Connect", "push button").click()
|
||||
cm = self.app.root.find("Choose Media", "dialog")
|
||||
cm.find("OK", "push button").click()
|
||||
self.assertTrue("/dev/fdb" in tab.find("disk-source-path").text)
|
||||
|
||||
# Floppy + image
|
||||
hw.find("Floppy 2", "table cell").click()
|
||||
tab.find("Disconnect", "push button").click()
|
||||
tab.find("Connect", "push button").click()
|
||||
cm = self.app.root.find("Choose Media", "dialog")
|
||||
cm.find("Image Location", "radio button").click()
|
||||
cm.find("Location:", "text").text = "/dev/default-pool/bochs-vol"
|
||||
cm.find("OK", "push button").click()
|
||||
self.assertTrue("bochs-vol" in tab.find("disk-source-path").text)
|
||||
|
||||
# CDROM + physical
|
||||
hw.find("IDE CDROM 1", "table cell").click()
|
||||
tab.find("Connect", "push button").click()
|
||||
cm = self.app.root.find("Choose Media", "dialog")
|
||||
cm.find("Physical Device", "radio button").click()
|
||||
cm.find("physical-device-combo").click()
|
||||
cm.find_fuzzy("/dev/sr1", "menu item").click()
|
||||
cm.find("OK", "push button").click()
|
||||
self.assertTrue("/dev/sr1" in tab.find("disk-source-path").text)
|
||||
|
||||
# CDROM + image
|
||||
hw.find("SCSI CDROM 1", "table cell").click()
|
||||
tab.find("Connect", "push button").click()
|
||||
cm = self.app.root.find("Choose Media", "dialog")
|
||||
cm.find("Image Location", "radio button").click()
|
||||
cm.find("Browse...", "push button").click()
|
||||
browsewin = self.app.root.find(
|
||||
"Choose Storage Volume", "frame")
|
||||
browsewin.find_fuzzy("default-pool", "table cell").click()
|
||||
browsewin.find_fuzzy("backingl1.img", "table cell").click()
|
||||
browsewin.find("Choose Volume", "push button").click()
|
||||
cm.find("OK", "push button").click()
|
||||
alert = self.app.root.find("vmm dialog", "alert")
|
||||
alert.find_fuzzy("already in use by", "label")
|
||||
alert.find("Yes", "push button").click()
|
||||
self.assertTrue(lambda: not cm.showing)
|
||||
self.assertTrue("backing" in tab.find("disk-source-path").text)
|
||||
tab.find("Disconnect", "push button").click()
|
||||
self.assertTrue("-" in tab.find("disk-source-path").text)
|
||||
|
||||
def testChooseCDHotplug(self):
|
||||
"""
|
||||
Test in the case of a running VM
|
||||
"""
|
||||
win = self._open_details_window()
|
||||
hw = win.find("hw-list")
|
||||
tab = win.find("disk-tab")
|
||||
|
||||
# CDROM + physical
|
||||
hw.find("IDE CDROM 1", "table cell").click()
|
||||
tab.find("Connect", "push button").click()
|
||||
cm = self.app.root.find("Choose Media", "dialog")
|
||||
cm.find("OK", "push button").click()
|
||||
alert = self.app.root.find("vmm dialog", "alert")
|
||||
alert.find_fuzzy("changes will take effect", "label")
|
||||
alert.find("OK", "push button").click()
|
||||
self.assertTrue("-" in tab.find("disk-source-path").text)
|
||||
|
||||
# Shutdown the VM, verify change shows up
|
||||
win.find("Shut Down", "push button").click()
|
||||
run = win.find("Run", "push button")
|
||||
uiutils.check_in_loop(lambda: run.sensitive)
|
||||
self.assertTrue("/dev/sr0" in tab.find("disk-source-path").text)
|
|
@ -195,15 +195,17 @@ class Console(uiutils.UITestCase):
|
|||
# Change CDROM
|
||||
win.find("IDE CDROM 1", "table cell").click()
|
||||
tab = win.find("disk-tab", None)
|
||||
entry = win.find("media-entry")
|
||||
appl = win.find("config-apply")
|
||||
uiutils.check_in_loop(lambda: tab.showing)
|
||||
tab.find("Connect", "push button").click()
|
||||
cm = self.app.root.find("Choose Media", "dialog")
|
||||
cm.find("Image Location", "radio button").click()
|
||||
cm.find("Location:", "text").text = fname
|
||||
cm.find("OK", "push button").click()
|
||||
self.assertTrue(tab.find("disk-source-path").text == fname)
|
||||
tab.find("Disconnect", "push button").click()
|
||||
self.assertTrue("-" in tab.find("disk-source-path").text)
|
||||
entry.text = fname
|
||||
appl.click()
|
||||
uiutils.check_in_loop(lambda: not appl.sensitive)
|
||||
self.assertTrue(entry.text == fname)
|
||||
entry.click_secondary_icon()
|
||||
appl.click()
|
||||
uiutils.check_in_loop(lambda: not appl.sensitive)
|
||||
self.assertTrue(not entry.text)
|
||||
|
||||
|
||||
@_vm_wrapper("uitests-hotplug")
|
||||
|
|
|
@ -0,0 +1,104 @@
|
|||
# This work is licensed under the GNU GPLv2 or later.
|
||||
# See the COPYING file in the top-level directory.
|
||||
|
||||
from tests.uitests import utils as uiutils
|
||||
|
||||
|
||||
class MediaChange(uiutils.UITestCase):
|
||||
"""
|
||||
UI tests for details storage media change
|
||||
"""
|
||||
|
||||
##############
|
||||
# Test cases #
|
||||
##############
|
||||
|
||||
def testMediaChange(self):
|
||||
win = self._open_details_window(shutdown=True)
|
||||
hw = win.find("hw-list")
|
||||
tab = win.find("disk-tab")
|
||||
combo = win.find("media-combo")
|
||||
entry = win.find("media-entry")
|
||||
appl = win.find("config-apply")
|
||||
|
||||
# Floppy + physical
|
||||
hw.find("Floppy 1", "table cell").click()
|
||||
combo.click_combo_entry()
|
||||
combo.find(r"Floppy_install_label \(/dev/fdb\)")
|
||||
self.assertTrue(entry.text == "No media detected (/dev/fda)")
|
||||
entry.click()
|
||||
entry.click_secondary_icon()
|
||||
self.assertTrue(not entry.text)
|
||||
appl.click()
|
||||
uiutils.check_in_loop(lambda: not appl.sensitive)
|
||||
self.assertTrue(not entry.text)
|
||||
appl.click()
|
||||
|
||||
# Enter /dev/fdb, after apply it should change to pretty label
|
||||
entry.text = "/dev/fdb"
|
||||
appl.click()
|
||||
uiutils.check_in_loop(lambda: not appl.sensitive)
|
||||
self.assertTrue(entry.text == "Floppy_install_label (/dev/fdb)")
|
||||
|
||||
# Specify manual path
|
||||
path = "/tmp/aaaaaaaaaaaaaaaaaaaaaaa.img"
|
||||
entry.text = path
|
||||
appl.click()
|
||||
uiutils.check_in_loop(lambda: not appl.sensitive)
|
||||
self.assertTrue(entry.text == path)
|
||||
|
||||
# Go to Floppy 2, make sure previous path is in recent list
|
||||
hw.find("Floppy 2", "table cell").click()
|
||||
combo.click_combo_entry()
|
||||
combo.find(path)
|
||||
entry.click()
|
||||
|
||||
# Browse for image
|
||||
hw.find("IDE CDROM 1", "table cell").click()
|
||||
combo.click_combo_entry()
|
||||
combo.find(r"Fedora12_media \(/dev/sr0\)")
|
||||
entry.click()
|
||||
tab.find("Browse", "push button").click()
|
||||
browsewin = self.app.root.find(
|
||||
"Choose Storage Volume", "frame")
|
||||
browsewin.find_fuzzy("default-pool", "table cell").click()
|
||||
browsewin.find_fuzzy("backingl1.img", "table cell").click()
|
||||
browsewin.find("Choose Volume", "push button").click()
|
||||
appl.click()
|
||||
# Check 'already in use' dialog
|
||||
alert = self.app.root.find("vmm dialog", "alert")
|
||||
alert.find_fuzzy("already in use by", "label")
|
||||
alert.find("Yes", "push button").click()
|
||||
uiutils.check_in_loop(lambda: not appl.sensitive)
|
||||
self.assertTrue("backing" in entry.text)
|
||||
entry.text = ""
|
||||
appl.click()
|
||||
uiutils.check_in_loop(lambda: not appl.sensitive)
|
||||
self.assertTrue(not entry.text)
|
||||
|
||||
|
||||
def testMediaHotplug(self):
|
||||
"""
|
||||
Test in the case of a running VM
|
||||
"""
|
||||
win = self._open_details_window()
|
||||
hw = win.find("hw-list")
|
||||
entry = win.find("media-entry")
|
||||
appl = win.find("config-apply")
|
||||
|
||||
# CDROM + physical
|
||||
hw.find("IDE CDROM 1", "table cell").click()
|
||||
self.assertTrue(not entry.text)
|
||||
entry.text = "/dev/sr0"
|
||||
appl.click()
|
||||
alert = self.app.root.find("vmm dialog", "alert")
|
||||
alert.find_fuzzy("changes will take effect", "label")
|
||||
alert.find("OK", "push button").click()
|
||||
uiutils.check_in_loop(lambda: not appl.sensitive)
|
||||
self.assertTrue(not entry.text)
|
||||
|
||||
# Shutdown the VM, verify change shows up
|
||||
win.find("Shut Down", "push button").click()
|
||||
run = win.find("Run", "push button")
|
||||
uiutils.check_in_loop(lambda: run.sensitive)
|
||||
self.assertTrue(entry.text == "Fedora12_media (/dev/sr0)")
|
|
@ -100,8 +100,13 @@ class NewVM(uiutils.UITestCase):
|
|||
newvm.find_fuzzy("Local install media", "radio").click()
|
||||
newvm.find_fuzzy("Forward", "button").click()
|
||||
|
||||
# check prepopulated cdrom media
|
||||
combo = newvm.find("media-combo")
|
||||
combo.click_combo_entry()
|
||||
combo.find(r"No media detected \(/dev/sr1\)")
|
||||
combo.find(r"Fedora12_media \(/dev/sr0\)").click()
|
||||
|
||||
# Select a fake iso
|
||||
newvm.find_fuzzy("Use ISO", "radio").click()
|
||||
newvm.find_fuzzy("install-iso-browse", "button").click()
|
||||
browser = self.app.root.find_fuzzy("Choose Storage", "frame")
|
||||
browser.find_fuzzy("default-pool", "table cell").click()
|
||||
|
|
|
@ -234,6 +234,15 @@ class VMMDogtailNode(dogtail.tree.Node):
|
|||
self.position[1] > 0 and
|
||||
self.position[1] + self.size[1] < screen.get_height())
|
||||
|
||||
def click_secondary_icon(self):
|
||||
"""
|
||||
Helper for clicking the secondary icon of a text entry
|
||||
"""
|
||||
button = 1
|
||||
clickX = self.position[0] + self.size[0] - 10
|
||||
clickY = self.position[1] + (self.size[1] / 2)
|
||||
dogtail.rawinput.click(clickX, clickY, button)
|
||||
|
||||
def click_combo_entry(self):
|
||||
"""
|
||||
Helper for clicking the arrow of a combo entry, to expose the menu.
|
||||
|
|
251
ui/choosecd.ui
251
ui/choosecd.ui
|
@ -1,251 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!-- Generated with glade 3.20.2 -->
|
||||
<interface>
|
||||
<requires lib="gtk+" version="3.14"/>
|
||||
<object class="GtkDialog" id="vmm-choose-cd">
|
||||
<property name="can_focus">True</property>
|
||||
<property name="has_focus">True</property>
|
||||
<property name="border_width">6</property>
|
||||
<property name="title" translatable="yes">Choose Media</property>
|
||||
<property name="resizable">False</property>
|
||||
<property name="window_position">center-on-parent</property>
|
||||
<property name="type_hint">dialog</property>
|
||||
<property name="gravity">center</property>
|
||||
<signal name="delete-event" handler="on_vmm_choose_cd_delete_event" swapped="no"/>
|
||||
<child internal-child="vbox">
|
||||
<object class="GtkBox" id="dialog-vbox1">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="orientation">vertical</property>
|
||||
<property name="spacing">6</property>
|
||||
<child internal-child="action_area">
|
||||
<object class="GtkButtonBox" id="dialog-action_area1">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="layout_style">end</property>
|
||||
<child>
|
||||
<object class="GtkButton" id="Cancel">
|
||||
<property name="label">gtk-cancel</property>
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="can_default">True</property>
|
||||
<property name="receives_default">False</property>
|
||||
<property name="use_stock">True</property>
|
||||
<signal name="clicked" handler="on_cancel_clicked" swapped="no"/>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">False</property>
|
||||
<property name="position">0</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkButton" id="OK">
|
||||
<property name="label">gtk-ok</property>
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="can_default">True</property>
|
||||
<property name="receives_default">False</property>
|
||||
<property name="use_stock">True</property>
|
||||
<signal name="clicked" handler="on_ok_clicked" swapped="no"/>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">False</property>
|
||||
<property name="position">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="pack_type">end</property>
|
||||
<property name="position">0</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkFrame" id="frame1">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="border_width">3</property>
|
||||
<property name="label_xalign">0</property>
|
||||
<property name="shadow_type">none</property>
|
||||
<child>
|
||||
<object class="GtkAlignment" id="alignment2">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="top_padding">6</property>
|
||||
<property name="left_padding">10</property>
|
||||
<child>
|
||||
<object class="GtkGrid" id="table1">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="row_spacing">6</property>
|
||||
<property name="column_spacing">6</property>
|
||||
<child>
|
||||
<object class="GtkBox" id="hbox1">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="hexpand">True</property>
|
||||
<property name="spacing">6</property>
|
||||
<child>
|
||||
<object class="GtkEntry" id="iso-path">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="invisible_char">●</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">True</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">0</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkButton" id="iso-file-chooser">
|
||||
<property name="label" translatable="yes">_Browse...</property>
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="receives_default">True</property>
|
||||
<property name="use_underline">True</property>
|
||||
<signal name="clicked" handler="on_fv_iso_location_browse_clicked" swapped="no"/>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">False</property>
|
||||
<property name="position">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="left_attach">1</property>
|
||||
<property name="top_attach">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkRadioButton" id="physical-media">
|
||||
<property name="label" translatable="yes">P_hysical 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="active">True</property>
|
||||
<property name="draw_indicator">True</property>
|
||||
<signal name="toggled" handler="on_media_toggled" swapped="no"/>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="left_attach">0</property>
|
||||
<property name="top_attach">2</property>
|
||||
<property name="width">2</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkAlignment" id="alignment5">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="valign">start</property>
|
||||
<property name="yscale">0</property>
|
||||
<child>
|
||||
<object class="GtkRadioButton" id="iso-image">
|
||||
<property name="label" translatable="yes">_Image Location</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">physical-media</property>
|
||||
<signal name="toggled" handler="on_media_toggled" swapped="no"/>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="left_attach">0</property>
|
||||
<property name="top_attach">0</property>
|
||||
<property name="width">2</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkAlignment" id="alignment1">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="left_padding">21</property>
|
||||
<child>
|
||||
<object class="GtkLabel" id="label36">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="halign">start</property>
|
||||
<property name="label" translatable="yes">_Location:</property>
|
||||
<property name="use_underline">True</property>
|
||||
<property name="mnemonic_widget">iso-path</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="left_attach">0</property>
|
||||
<property name="top_attach">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkAlignment" id="alignment3">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="left_padding">21</property>
|
||||
<child>
|
||||
<object class="GtkLabel" id="label38">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="halign">start</property>
|
||||
<property name="label" translatable="yes">_Device Media:</property>
|
||||
<property name="use_underline">True</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="left_attach">0</property>
|
||||
<property name="top_attach">3</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkAlignment" id="media-combo-align">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="hexpand">False</property>
|
||||
<property name="vexpand">False</property>
|
||||
<child>
|
||||
<placeholder/>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="left_attach">1</property>
|
||||
<property name="top_attach">3</property>
|
||||
</packing>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
<child type="label">
|
||||
<object class="GtkLabel" id="title-label">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="label" translatable="yes"><b>Choose Source Device or File</b></property>
|
||||
<property name="use_markup">True</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
<action-widgets>
|
||||
<action-widget response="-6">Cancel</action-widget>
|
||||
<action-widget response="-5">OK</action-widget>
|
||||
</action-widgets>
|
||||
<child>
|
||||
<placeholder/>
|
||||
</child>
|
||||
</object>
|
||||
</interface>
|
79
ui/create.ui
79
ui/create.ui
|
@ -776,67 +776,19 @@ bar</property>
|
|||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="orientation">vertical</property>
|
||||
<property name="spacing">4</property>
|
||||
<property name="spacing">6</property>
|
||||
<child>
|
||||
<object class="GtkBox" id="vbox123">
|
||||
<object class="GtkLabel" id="install-iso-label">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="orientation">vertical</property>
|
||||
<property name="spacing">4</property>
|
||||
<child>
|
||||
<object class="GtkRadioButton" id="install-cdrom-radio">
|
||||
<property name="label" translatable="yes">Use CD_ROM or DVD</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_install_cdrom_radio_toggled" swapped="no"/>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">0</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkAlignment" id="install-cdrom-align">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="left_padding">20</property>
|
||||
<child>
|
||||
<placeholder/>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">False</property>
|
||||
<property name="position">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">False</property>
|
||||
<property name="position">0</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkRadioButton" id="install-iso-radio">
|
||||
<property name="label" translatable="yes">Use _ISO image:</property>
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="receives_default">False</property>
|
||||
<property name="halign">start</property>
|
||||
<property name="label" translatable="yes">Choose _ISO or CDROM install media:</property>
|
||||
<property name="use_underline">True</property>
|
||||
<property name="active">True</property>
|
||||
<property name="draw_indicator">True</property>
|
||||
<property name="group">install-cdrom-radio</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">1</property>
|
||||
<property name="position">0</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
|
@ -845,36 +797,23 @@ bar</property>
|
|||
<property name="can_focus">False</property>
|
||||
<property name="spacing">5</property>
|
||||
<child>
|
||||
<object class="GtkAlignment" id="alignment8">
|
||||
<object class="GtkAlignment" id="install-iso-align">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="left_padding">20</property>
|
||||
<child>
|
||||
<object class="GtkComboBox" id="install-iso-combo">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="has_entry">True</property>
|
||||
<child internal-child="entry">
|
||||
<object class="GtkEntry" id="install-iso-entry">
|
||||
<property name="can_focus">True</property>
|
||||
<signal name="activate" handler="on_install_iso_entry_activate" swapped="no"/>
|
||||
<signal name="changed" handler="on_install_iso_entry_changed" swapped="no"/>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
<placeholder/>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">True</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">-1</property>
|
||||
<property name="position">0</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkButton" id="install-iso-browse">
|
||||
<property name="label" translatable="yes">Bro_wse...</property>
|
||||
<property name="visible">True</property>
|
||||
<property name="sensitive">False</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="receives_default">True</property>
|
||||
<property name="use_underline">True</property>
|
||||
|
@ -895,7 +834,7 @@ bar</property>
|
|||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">2</property>
|
||||
<property name="position">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
</object>
|
||||
|
|
|
@ -3315,11 +3315,11 @@
|
|||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkLabel" id="label392">
|
||||
<object class="GtkLabel" id="disk-source-mnemonic">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="halign">end</property>
|
||||
<property name="label" translatable="yes">Source path:</property>
|
||||
<property name="label" translatable="yes">Source _path:</property>
|
||||
<property name="use_underline">True</property>
|
||||
</object>
|
||||
<packing>
|
||||
|
@ -3344,17 +3344,18 @@
|
|||
<object class="GtkBox" id="box9">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="hexpand">True</property>
|
||||
<property name="spacing">6</property>
|
||||
<child>
|
||||
<object class="GtkLabel" id="disk-source-path">
|
||||
<object class="GtkLabel" id="disk-source-label">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="halign">start</property>
|
||||
<property name="label">path</property>
|
||||
<property name="label">pathlabel</property>
|
||||
<property name="selectable">True</property>
|
||||
<property name="ellipsize">start</property>
|
||||
<child internal-child="accessible">
|
||||
<object class="AtkObject" id="disk-source-path-atkobject">
|
||||
<object class="AtkObject" id="disk-source-label-atkobject">
|
||||
<property name="AtkObject::accessible-name">disk-source-path</property>
|
||||
</object>
|
||||
</child>
|
||||
|
@ -3366,19 +3367,42 @@
|
|||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkButton" id="disk-cdrom-connect">
|
||||
<property name="label">gtk-connect</property>
|
||||
<object class="GtkBox" id="disk-source-box">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="can_default">True</property>
|
||||
<property name="receives_default">True</property>
|
||||
<property name="has_tooltip">True</property>
|
||||
<property name="tooltip_text" translatable="yes">Connect or disconnect media</property>
|
||||
<property name="use_stock">True</property>
|
||||
<signal name="clicked" handler="on_disk_cdrom_connect_clicked" swapped="no"/>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="spacing">6</property>
|
||||
<child>
|
||||
<object class="GtkAlignment" id="disk-source-align">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<child>
|
||||
<placeholder/>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">0</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkButton" id="disk-source-browse">
|
||||
<property name="label" translatable="yes">_Browse</property>
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="receives_default">True</property>
|
||||
<property name="use_underline">True</property>
|
||||
<signal name="clicked" handler="on_disk_source_browse_clicked" swapped="no"/>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="expand">True</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">1</property>
|
||||
</packing>
|
||||
|
|
|
@ -1,145 +0,0 @@
|
|||
# Copyright (C) 2006, 2013, 2014 Red Hat, Inc.
|
||||
# Copyright (C) 2006 Hugh O. Brock <hbrock@redhat.com>
|
||||
#
|
||||
# This work is licensed under the GNU GPLv2 or later.
|
||||
# See the COPYING file in the top-level directory.
|
||||
|
||||
import logging
|
||||
|
||||
from virtinst import DeviceDisk
|
||||
|
||||
from .baseclass import vmmGObjectUI
|
||||
from .mediacombo import vmmMediaCombo
|
||||
from .storagebrowse import vmmStorageBrowser
|
||||
from .addstorage import vmmAddStorage
|
||||
|
||||
|
||||
class vmmChooseCD(vmmGObjectUI):
|
||||
__gsignals__ = {
|
||||
"cdrom-chosen": (vmmGObjectUI.RUN_FIRST, None, [object, str])
|
||||
}
|
||||
|
||||
def __init__(self, vm, disk):
|
||||
vmmGObjectUI.__init__(self, "choosecd.ui", "vmm-choose-cd")
|
||||
|
||||
self.vm = vm
|
||||
self.conn = self.vm.conn
|
||||
self.storage_browser = None
|
||||
|
||||
# This is also overwritten from details.py when targeting a new disk
|
||||
self.disk = disk
|
||||
self.media_type = disk.device
|
||||
|
||||
self.mediacombo = vmmMediaCombo(self.conn, self.builder, self.topwin,
|
||||
self.media_type)
|
||||
self.widget("media-combo-align").add(self.mediacombo.top_box)
|
||||
|
||||
self.builder.connect_signals({
|
||||
"on_vmm_choose_cd_delete_event": self.close,
|
||||
|
||||
"on_media_toggled": self.media_toggled,
|
||||
"on_fv_iso_location_browse_clicked": self.browse_fv_iso_location,
|
||||
|
||||
"on_ok_clicked": self.ok,
|
||||
"on_cancel_clicked": self.close,
|
||||
})
|
||||
|
||||
self.reset_state()
|
||||
|
||||
def close(self, ignore1=None, ignore2=None):
|
||||
logging.debug("Closing media chooser")
|
||||
self.topwin.hide()
|
||||
if self.storage_browser:
|
||||
self.storage_browser.close()
|
||||
|
||||
return 1
|
||||
|
||||
def show(self, parent):
|
||||
logging.debug("Showing media chooser")
|
||||
self.reset_state()
|
||||
self.topwin.set_transient_for(parent)
|
||||
self.topwin.present()
|
||||
self.conn.schedule_priority_tick(pollnodedev=True)
|
||||
|
||||
def _cleanup(self):
|
||||
self.vm = None
|
||||
self.conn = None
|
||||
self.disk = None
|
||||
|
||||
if self.storage_browser:
|
||||
self.storage_browser.cleanup()
|
||||
self.storage_browser = None
|
||||
if self.mediacombo:
|
||||
self.mediacombo.cleanup()
|
||||
self.mediacombo = None
|
||||
|
||||
def _init_ui(self):
|
||||
if self.media_type == vmmMediaCombo.MEDIA_FLOPPY:
|
||||
self.widget("physical-media").set_label(_("Floppy D_rive"))
|
||||
self.widget("iso-image").set_label(_("Floppy _Image"))
|
||||
|
||||
def reset_state(self):
|
||||
self.mediacombo.reset_state()
|
||||
|
||||
enable_phys = not self.vm.xmlobj.stable_defaults()
|
||||
self.widget("physical-media").set_sensitive(enable_phys)
|
||||
self.widget("physical-media").set_tooltip_text("" if enable_phys else
|
||||
_("Physical CDROM passthrough not supported with this hypervisor"))
|
||||
|
||||
use_cdrom = (self.mediacombo.has_media()) and enable_phys
|
||||
|
||||
self.widget("physical-media").set_active(use_cdrom)
|
||||
self.widget("iso-image").set_active(not use_cdrom)
|
||||
|
||||
def ok(self, ignore1=None, ignore2=None):
|
||||
if self.widget("iso-image").get_active():
|
||||
path = self.widget("iso-path").get_text()
|
||||
else:
|
||||
path = self.mediacombo.get_path()
|
||||
if path == "" or path is None:
|
||||
return self.err.val_err(_("Invalid Media Path"),
|
||||
_("A media path must be specified."))
|
||||
|
||||
names = DeviceDisk.path_in_use_by(self.disk.conn, path)
|
||||
if names:
|
||||
res = self.err.yes_no(
|
||||
_('Disk "%s" is already in use by other guests %s') %
|
||||
(path, names),
|
||||
_("Do you really want to use the disk?"))
|
||||
if not res:
|
||||
return False
|
||||
|
||||
vmmAddStorage.check_path_search(self, self.conn, path)
|
||||
|
||||
try:
|
||||
self.disk.path = path
|
||||
except Exception as e:
|
||||
return self.err.val_err(_("Invalid Media Path"), e)
|
||||
|
||||
self.close()
|
||||
self.emit("cdrom-chosen", self.disk, path)
|
||||
|
||||
def media_toggled(self, ignore1=None, ignore2=None):
|
||||
is_phys = bool(self.widget("physical-media").get_active())
|
||||
self.mediacombo.combo.set_sensitive(is_phys)
|
||||
self.widget("iso-path").set_sensitive(not is_phys)
|
||||
self.widget("iso-file-chooser").set_sensitive(not is_phys)
|
||||
|
||||
def browse_fv_iso_location(self, ignore1=None, ignore2=None):
|
||||
self._browse_file()
|
||||
|
||||
def set_storage_path(self, src_ignore, path):
|
||||
self.widget("iso-path").set_text(path)
|
||||
|
||||
def _browse_file(self):
|
||||
if self.storage_browser is None:
|
||||
self.storage_browser = vmmStorageBrowser(self.conn)
|
||||
self.storage_browser.set_finish_cb(self.set_storage_path)
|
||||
|
||||
if self.media_type == vmmMediaCombo.MEDIA_FLOPPY:
|
||||
self.storage_browser.set_browse_reason(
|
||||
self.config.CONFIG_DIR_FLOPPY_MEDIA)
|
||||
else:
|
||||
self.storage_browser.set_browse_reason(
|
||||
self.config.CONFIG_DIR_ISO_MEDIA)
|
||||
self.storage_browser.show(self.topwin)
|
|
@ -542,17 +542,20 @@ class vmmConfig(object):
|
|||
|
||||
def add_container_url(self, url):
|
||||
self._url_add_helper("/urls/containers", url)
|
||||
def get_container_urls(self):
|
||||
return self.conf.get("/urls/containers") or []
|
||||
|
||||
def add_media_url(self, url):
|
||||
self._url_add_helper("/urls/urls", url)
|
||||
def get_media_urls(self):
|
||||
return self.conf.get("/urls/urls") or []
|
||||
|
||||
def add_iso_path(self, path):
|
||||
self._url_add_helper("/urls/isos", path)
|
||||
|
||||
def get_container_urls(self):
|
||||
return self.conf.get("/urls/containers")
|
||||
def get_media_urls(self):
|
||||
return self.conf.get("/urls/urls")
|
||||
def get_iso_paths(self):
|
||||
return self.conf.get("/urls/isos")
|
||||
return self.conf.get("/urls/isos") or []
|
||||
def on_iso_paths_changed(self, cb):
|
||||
return self.conf.notify_add("/urls/isos", cb)
|
||||
|
||||
|
||||
# Whether to ask about fixing path permissions
|
||||
|
|
|
@ -134,7 +134,6 @@ class vmmCreate(vmmGObjectUI):
|
|||
|
||||
self._storage_browser = None
|
||||
self._netlist = None
|
||||
self._mediacombo = None
|
||||
|
||||
self._addstorage = vmmAddStorage(self.conn, self.builder, self.topwin)
|
||||
self.widget("storage-align").add(self._addstorage.top_box)
|
||||
|
@ -142,6 +141,13 @@ class vmmCreate(vmmGObjectUI):
|
|||
self._browse_file(widget)
|
||||
self._addstorage.connect("browse-clicked", _browse_file_cb)
|
||||
|
||||
self._mediacombo = vmmMediaCombo(self.conn, self.builder, self.topwin)
|
||||
self._mediacombo.connect("changed", self._iso_changed_cb)
|
||||
self._mediacombo.connect("activate", self._iso_activated_cb)
|
||||
self._mediacombo.set_mnemonic_label(
|
||||
self.widget("install-iso-label"))
|
||||
self.widget("install-iso-align").add(self._mediacombo.top_box)
|
||||
|
||||
self.builder.connect_signals({
|
||||
"on_vmm_newcreate_delete_event": self._close_requested,
|
||||
|
||||
|
@ -159,9 +165,6 @@ class vmmCreate(vmmGObjectUI):
|
|||
"on_machine_changed": self._machine_changed,
|
||||
"on_vz_virt_type_changed": self._vz_virt_type_changed,
|
||||
|
||||
"on_install_cdrom_radio_toggled": self._local_media_toggled,
|
||||
"on_install_iso_entry_changed": self._iso_changed,
|
||||
"on_install_iso_entry_activate": self._iso_activated,
|
||||
"on_install_iso_browse_clicked": self._browse_iso,
|
||||
"on_install_url_entry_changed": self._url_changed,
|
||||
"on_install_url_entry_activate": self._url_activated,
|
||||
|
@ -281,9 +284,6 @@ class vmmCreate(vmmGObjectUI):
|
|||
lst.set_model(model)
|
||||
lst.set_entry_text_column(0)
|
||||
|
||||
# ISO media list
|
||||
set_model_list("install-iso-combo")
|
||||
|
||||
# Lists for the install urls
|
||||
set_model_list("install-url-combo")
|
||||
|
||||
|
@ -363,9 +363,8 @@ class vmmCreate(vmmGObjectUI):
|
|||
for url in urls:
|
||||
media_model.append([url])
|
||||
|
||||
self.widget("install-iso-entry").set_text("")
|
||||
iso_model = self.widget("install-iso-combo").get_model()
|
||||
_populate_media_model(iso_model, self.config.get_iso_paths())
|
||||
# Install local
|
||||
self._mediacombo.reset_state()
|
||||
|
||||
# Install URL
|
||||
self.widget("install-urlopts-entry").set_text("")
|
||||
|
@ -527,6 +526,7 @@ class vmmCreate(vmmGObjectUI):
|
|||
self._capsinfo = None
|
||||
self.conn.invalidate_caps()
|
||||
self._change_caps()
|
||||
is_local = not self.conn.is_remote()
|
||||
|
||||
if not self._capsinfo.guest.has_install_options():
|
||||
error = _("No hypervisor options were found for this "
|
||||
|
@ -584,39 +584,10 @@ class vmmCreate(vmmGObjectUI):
|
|||
self.widget("vz-virt-type-exe").set_active(
|
||||
not has_hvm_guests and has_exe_guests)
|
||||
|
||||
# Install local
|
||||
iso_option = self.widget("install-iso-radio")
|
||||
cdrom_option = self.widget("install-cdrom-radio")
|
||||
|
||||
if self._mediacombo:
|
||||
self.widget("install-cdrom-align").remove(
|
||||
self._mediacombo.top_box)
|
||||
self._mediacombo.cleanup()
|
||||
self._mediacombo = None
|
||||
|
||||
self._mediacombo = vmmMediaCombo(self.conn, self.builder, self.topwin,
|
||||
vmmMediaCombo.MEDIA_CDROM)
|
||||
|
||||
self._mediacombo.combo.connect("changed", self._cdrom_changed)
|
||||
# ISO media
|
||||
# Dependent on connection so we need to do this here
|
||||
self._mediacombo.set_conn(self.conn)
|
||||
self._mediacombo.reset_state()
|
||||
self.widget("install-cdrom-align").add(
|
||||
self._mediacombo.top_box)
|
||||
|
||||
# Don't select physical CDROM if no valid media is present
|
||||
cdrom_option.set_active(self._mediacombo.has_media())
|
||||
iso_option.set_active(not self._mediacombo.has_media())
|
||||
|
||||
enable_phys = not self._stable_defaults()
|
||||
cdrom_option.set_sensitive(enable_phys)
|
||||
cdrom_option.set_tooltip_text("" if enable_phys else
|
||||
_("Physical CDROM passthrough not supported with this hypervisor"))
|
||||
|
||||
# Only allow ISO option for remote VM
|
||||
is_local = not self.conn.is_remote()
|
||||
if not is_local or not enable_phys:
|
||||
iso_option.set_active(True)
|
||||
|
||||
self._local_media_toggled(cdrom_option)
|
||||
|
||||
# Allow container bootstrap only for local connection and
|
||||
# only if virt-bootstrap is installed. Otherwise, show message.
|
||||
|
@ -1058,13 +1029,7 @@ class vmmCreate(vmmGObjectUI):
|
|||
INSTALL_PAGE_VZ_TEMPLATE]
|
||||
|
||||
def _get_config_local_media(self, store_media=False):
|
||||
if self.widget("install-cdrom-radio").get_active():
|
||||
return self._mediacombo.get_path()
|
||||
else:
|
||||
ret = self.widget("install-iso-entry").get_text()
|
||||
if ret and store_media:
|
||||
self.config.add_iso_path(ret)
|
||||
return ret
|
||||
return self._mediacombo.get_path(store_media=store_media)
|
||||
|
||||
def _get_config_detectable_media(self):
|
||||
instpage = self._get_config_install_page()
|
||||
|
@ -1207,12 +1172,10 @@ class vmmCreate(vmmGObjectUI):
|
|||
self._detectable_media_widget_changed(src)
|
||||
def _url_activated(self, src):
|
||||
self._detectable_media_widget_changed(src, checkfocus=False)
|
||||
def _iso_changed(self, src):
|
||||
self._detectable_media_widget_changed(src)
|
||||
def _iso_activated(self, src):
|
||||
self._detectable_media_widget_changed(src, checkfocus=False)
|
||||
def _cdrom_changed(self, src):
|
||||
self._detectable_media_widget_changed(src)
|
||||
def _iso_changed_cb(self, mediacombo, entry):
|
||||
self._detectable_media_widget_changed(entry)
|
||||
def _iso_activated_cb(self, mediacombo, entry):
|
||||
self._detectable_media_widget_changed(entry, checkfocus=False)
|
||||
|
||||
def _detect_os_toggled_cb(self, src):
|
||||
if not src.is_visible():
|
||||
|
@ -1225,17 +1188,6 @@ class vmmCreate(vmmGObjectUI):
|
|||
self._os_already_detected_for_media = False
|
||||
self._start_detect_os_if_needed()
|
||||
|
||||
def _local_media_toggled(self, src):
|
||||
usecdrom = src.get_active()
|
||||
self.widget("install-cdrom-align").set_sensitive(usecdrom)
|
||||
self.widget("install-iso-combo").set_sensitive(not usecdrom)
|
||||
self.widget("install-iso-browse").set_sensitive(not usecdrom)
|
||||
|
||||
if usecdrom:
|
||||
self._cdrom_changed(self._mediacombo.combo)
|
||||
else:
|
||||
self._iso_changed(self.widget("install-iso-entry"))
|
||||
|
||||
def _browse_oscontainer(self, ignore):
|
||||
self._browse_file("install-oscontainer-fs", is_dir=True)
|
||||
def _browse_app(self, ignore):
|
||||
|
@ -1244,7 +1196,7 @@ class vmmCreate(vmmGObjectUI):
|
|||
self._browse_file("install-import-entry")
|
||||
def _browse_iso(self, ignore):
|
||||
def set_path(ignore, path):
|
||||
self.widget("install-iso-entry").set_text(path)
|
||||
self._mediacombo.set_path(path)
|
||||
self._browse_file(None, cb=set_path, is_media=True)
|
||||
def _browse_kernel(self, ignore):
|
||||
self._browse_file("kernel")
|
||||
|
|
|
@ -18,12 +18,13 @@ from virtinst import util
|
|||
from . import vmmenu
|
||||
from . import uiutil
|
||||
from .addhardware import vmmAddHardware
|
||||
from .addstorage import vmmAddStorage
|
||||
from .baseclass import vmmGObjectUI
|
||||
from .choosecd import vmmChooseCD
|
||||
from .engine import vmmEngine
|
||||
from .fsdetails import vmmFSDetails
|
||||
from .gfxdetails import vmmGraphicsDetails
|
||||
from .graphwidgets import Sparkline
|
||||
from .mediacombo import vmmMediaCombo
|
||||
from .netlist import vmmNetworkList
|
||||
from .oslist import vmmOSList
|
||||
from .snapshots import vmmSnapshotPage
|
||||
|
@ -64,6 +65,7 @@ from .storagebrowse import vmmStorageBrowser
|
|||
EDIT_DISK_SERIAL,
|
||||
EDIT_DISK_FORMAT,
|
||||
EDIT_DISK_SGIO,
|
||||
EDIT_DISK_PATH,
|
||||
|
||||
EDIT_SOUND_MODEL,
|
||||
|
||||
|
@ -98,7 +100,7 @@ from .storagebrowse import vmmStorageBrowser
|
|||
|
||||
EDIT_FS,
|
||||
|
||||
EDIT_HOSTDEV_ROMBAR) = range(1, 54)
|
||||
EDIT_HOSTDEV_ROMBAR) = range(1, 55)
|
||||
|
||||
|
||||
# Columns in hw list model
|
||||
|
@ -395,8 +397,8 @@ class vmmDetails(vmmGObjectUI):
|
|||
self.active_edits = []
|
||||
|
||||
self.addhw = None
|
||||
self.media_choosers = {"cdrom": None, "floppy": None}
|
||||
self.storage_browser = None
|
||||
self._mediacombo = None
|
||||
|
||||
self.ignoreDetails = False
|
||||
|
||||
|
@ -405,6 +407,14 @@ class vmmDetails(vmmGObjectUI):
|
|||
self.snapshots = vmmSnapshotPage(self.vm, self.builder, self.topwin)
|
||||
self.widget("snapshot-placeholder").add(self.snapshots.top_box)
|
||||
|
||||
self._mediacombo = vmmMediaCombo(self.conn, self.builder, self.topwin)
|
||||
self.widget("disk-source-align").add(self._mediacombo.top_box)
|
||||
self._mediacombo.set_mnemonic_label(
|
||||
self.widget("disk-source-mnemonic"))
|
||||
self._mediacombo.connect("changed",
|
||||
lambda *x: self.enable_apply(x, EDIT_DISK_PATH))
|
||||
self._mediacombo.show_clear_icon()
|
||||
|
||||
self.fsDetails = vmmFSDetails(self.vm, self.builder, self.topwin)
|
||||
self.widget("fs-alignment").add(self.fsDetails.top_box)
|
||||
self.fsDetails.connect("changed",
|
||||
|
@ -537,7 +547,8 @@ class vmmDetails(vmmGObjectUI):
|
|||
"on_boot_init_path_changed": lambda *x: self.enable_apply(x, EDIT_INIT),
|
||||
"on_boot_init_args_changed": lambda *x: self.enable_apply(x, EDIT_INIT),
|
||||
|
||||
"on_disk_cdrom_connect_clicked": self.toggle_storage_media,
|
||||
|
||||
"on_disk_source_browse_clicked": self._disk_source_browse_clicked_cb,
|
||||
"on_disk_readonly_changed": lambda *x: self.enable_apply(x, EDIT_DISK_RO),
|
||||
"on_disk_shareable_changed": lambda *x: self.enable_apply(x, EDIT_DISK_SHARE),
|
||||
"on_disk_removable_changed": lambda *x: self.enable_apply(x, EDIT_DISK_REMOVABLE),
|
||||
|
@ -631,16 +642,12 @@ class vmmDetails(vmmGObjectUI):
|
|||
if self.addhw:
|
||||
self.addhw.cleanup()
|
||||
self.addhw = None
|
||||
|
||||
if self.storage_browser:
|
||||
self.storage_browser.cleanup()
|
||||
self.storage_browser = None
|
||||
|
||||
for key in self.media_choosers:
|
||||
if self.media_choosers[key]:
|
||||
self.media_choosers[key].cleanup()
|
||||
self.media_choosers = {}
|
||||
|
||||
self._mediacombo.cleanup()
|
||||
self._mediacombo = None
|
||||
self.console.cleanup()
|
||||
self.console = None
|
||||
self.snapshots.cleanup()
|
||||
|
@ -1596,11 +1603,11 @@ class vmmDetails(vmmGObjectUI):
|
|||
# Details/Hardware listeners #
|
||||
##############################
|
||||
|
||||
def _browse_file(self, callback, is_media=False):
|
||||
if is_media:
|
||||
reason = self.config.CONFIG_DIR_ISO_MEDIA
|
||||
else:
|
||||
def _browse_file(self, callback, is_media=False, reason=None):
|
||||
if not reason:
|
||||
reason = self.config.CONFIG_DIR_IMAGE
|
||||
if is_media:
|
||||
reason = self.config.CONFIG_DIR_ISO_MEDIA
|
||||
|
||||
if self.storage_browser is None:
|
||||
self.storage_browser = vmmStorageBrowser(self.conn)
|
||||
|
@ -1819,50 +1826,22 @@ class vmmDetails(vmmGObjectUI):
|
|||
boot_list.get_selection().emit("changed")
|
||||
self.enable_apply(EDIT_BOOTORDER)
|
||||
|
||||
|
||||
# Disk callbacks
|
||||
def disk_format_changed(self, ignore):
|
||||
self.widget("disk-format-warn").show()
|
||||
self.enable_apply(EDIT_DISK_FORMAT)
|
||||
|
||||
|
||||
# CDROM Eject/Connect
|
||||
def _change_storage_media(self, devobj, newpath):
|
||||
kwargs = {"path": newpath}
|
||||
return vmmAddHardware.change_config_helper(self.vm.define_disk,
|
||||
kwargs, self.vm, self.err, devobj=devobj)
|
||||
|
||||
def _eject_media(self, disk):
|
||||
try:
|
||||
self._change_storage_media(disk, None)
|
||||
except Exception as e:
|
||||
self.err.show_err((_("Error disconnecting media: %s") % e))
|
||||
|
||||
def _insert_media(self, disk):
|
||||
try:
|
||||
devtype = disk.device
|
||||
|
||||
def change_cdrom_wrapper(src_ignore, devobj, newpath):
|
||||
return self._change_storage_media(devobj, newpath)
|
||||
|
||||
# Launch 'Choose CD' dialog
|
||||
if self.media_choosers[devtype] is None:
|
||||
ret = vmmChooseCD(self.vm, disk)
|
||||
|
||||
ret.connect("cdrom-chosen", change_cdrom_wrapper)
|
||||
self.media_choosers[devtype] = ret
|
||||
|
||||
dialog = self.media_choosers[devtype]
|
||||
dialog.disk = disk
|
||||
|
||||
dialog.show(self.topwin)
|
||||
except Exception as e:
|
||||
self.err.show_err((_("Error launching media dialog: %s") % e))
|
||||
return
|
||||
|
||||
def toggle_storage_media(self, src_ignore):
|
||||
def _disk_source_browse_clicked_cb(self, src):
|
||||
disk = self.get_hw_row()[HW_LIST_COL_DEVICE]
|
||||
if disk.path:
|
||||
return self._eject_media(disk)
|
||||
return self._insert_media(disk)
|
||||
if disk.is_floppy():
|
||||
reason = self.config.CONFIG_DIR_FLOPPY_MEDIA
|
||||
else:
|
||||
reason = self.config.CONFIG_DIR_ISO_MEDIA
|
||||
|
||||
def cb(ignore, path):
|
||||
self._mediacombo.set_path(path)
|
||||
self._browse_file(cb, reason=reason)
|
||||
|
||||
|
||||
# Net IP refresh
|
||||
|
@ -2121,6 +2100,21 @@ class vmmDetails(vmmGObjectUI):
|
|||
def config_disk_apply(self, devobj):
|
||||
kwargs = {}
|
||||
|
||||
if self.edited(EDIT_DISK_PATH):
|
||||
path = self._mediacombo.get_path()
|
||||
|
||||
names = virtinst.DeviceDisk.path_in_use_by(devobj.conn, path)
|
||||
if names:
|
||||
res = self.err.yes_no(
|
||||
_('Disk "%s" is already in use by other guests %s') %
|
||||
(path, names),
|
||||
_("Do you really want to use the disk?"))
|
||||
if not res:
|
||||
return False
|
||||
|
||||
vmmAddStorage.check_path_search(self, self.conn, path)
|
||||
kwargs["path"] = path or None
|
||||
|
||||
if self.edited(EDIT_DISK_RO):
|
||||
kwargs["readonly"] = self.widget("disk-readonly").get_active()
|
||||
|
||||
|
@ -2676,8 +2670,6 @@ class vmmDetails(vmmGObjectUI):
|
|||
if vol:
|
||||
size = vol.get_pretty_capacity()
|
||||
|
||||
is_cdrom = (devtype == virtinst.DeviceDisk.DEVICE_CDROM)
|
||||
is_floppy = (devtype == virtinst.DeviceDisk.DEVICE_FLOPPY)
|
||||
is_usb = (bus == "usb")
|
||||
|
||||
can_set_removable = (is_usb and (self.conn.is_qemu() or
|
||||
|
@ -2689,11 +2681,10 @@ class vmmDetails(vmmGObjectUI):
|
|||
|
||||
pretty_name = _label_for_device(disk)
|
||||
|
||||
self.widget("disk-source-path").set_text(path or "-")
|
||||
self.widget("disk-target-type").set_text(pretty_name)
|
||||
|
||||
self.widget("disk-readonly").set_active(ro)
|
||||
self.widget("disk-readonly").set_sensitive(not is_cdrom)
|
||||
self.widget("disk-readonly").set_sensitive(not disk.is_cdrom())
|
||||
self.widget("disk-shareable").set_active(share)
|
||||
self.widget("disk-removable").set_active(removable)
|
||||
uiutil.set_grid_row_visible(self.widget("disk-removable"),
|
||||
|
@ -2720,16 +2711,14 @@ class vmmDetails(vmmGObjectUI):
|
|||
uiutil.set_list_selection(self.widget("disk-bus"), bus)
|
||||
self.widget("disk-serial").set_text(serial or "")
|
||||
|
||||
button = self.widget("disk-cdrom-connect")
|
||||
if is_cdrom or is_floppy:
|
||||
if not path:
|
||||
# source device not connected
|
||||
button.set_label(Gtk.STOCK_CONNECT)
|
||||
else:
|
||||
button.set_label(Gtk.STOCK_DISCONNECT)
|
||||
button.show()
|
||||
else:
|
||||
button.hide()
|
||||
is_removable = disk.is_cdrom() or disk.is_floppy()
|
||||
self.widget("disk-source-box").set_visible(is_removable)
|
||||
self.widget("disk-source-label").set_visible(not is_removable)
|
||||
|
||||
self.widget("disk-source-label").set_text(path or "-")
|
||||
if is_removable:
|
||||
self._mediacombo.reset_state(is_floppy=disk.is_floppy())
|
||||
self._mediacombo.set_path(path or "")
|
||||
|
||||
def refresh_network_page(self, net):
|
||||
vmmAddHardware.populate_network_model_combo(
|
||||
|
|
|
@ -3,35 +3,45 @@
|
|||
# This work is licensed under the GNU GPLv2 or later.
|
||||
# See the COPYING file in the top-level directory.
|
||||
|
||||
import logging
|
||||
|
||||
from gi.repository import Gtk
|
||||
|
||||
from . import uiutil
|
||||
from .baseclass import vmmGObjectUI
|
||||
from .baseclass import vmmGObject, vmmGObjectUI
|
||||
|
||||
|
||||
class vmmMediaCombo(vmmGObjectUI):
|
||||
MEDIA_FLOPPY = "floppy"
|
||||
MEDIA_CDROM = "cdrom"
|
||||
__gsignals__ = {
|
||||
"changed": (vmmGObject.RUN_FIRST, None, [object]),
|
||||
"activate": (vmmGObject.RUN_FIRST, None, [object]),
|
||||
}
|
||||
|
||||
OPTICAL_FIELDS = 4
|
||||
(OPTICAL_DEV_PATH,
|
||||
OPTICAL_LABEL,
|
||||
OPTICAL_HAS_MEDIA,
|
||||
OPTICAL_DEV_KEY) = range(OPTICAL_FIELDS)
|
||||
MEDIA_TYPE_FLOPPY = "floppy"
|
||||
MEDIA_TYPE_CDROM = "cdrom"
|
||||
|
||||
def __init__(self, conn, builder, topwin, media_type):
|
||||
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.media_type = media_type
|
||||
|
||||
self.top_box = None
|
||||
self.combo = None
|
||||
self._warn_icon = 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()
|
||||
|
@ -46,117 +56,138 @@ class vmmMediaCombo(vmmGObjectUI):
|
|||
self.top_box = Gtk.Box()
|
||||
self.top_box.set_spacing(6)
|
||||
self.top_box.set_orientation(Gtk.Orientation.HORIZONTAL)
|
||||
self._warn_icon = Gtk.Image()
|
||||
self._warn_icon.set_from_stock(
|
||||
Gtk.STOCK_DIALOG_WARNING, Gtk.IconSize.MENU)
|
||||
self.combo = Gtk.ComboBox()
|
||||
self.top_box.add(self.combo)
|
||||
self.top_box.add(self._warn_icon)
|
||||
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()
|
||||
|
||||
# [Device path, pretty label, has_media?, device key]
|
||||
fields = []
|
||||
fields.insert(self.OPTICAL_DEV_PATH, str)
|
||||
fields.insert(self.OPTICAL_LABEL, str)
|
||||
fields.insert(self.OPTICAL_HAS_MEDIA, bool)
|
||||
fields.insert(self.OPTICAL_DEV_KEY, str)
|
||||
self.combo.set_model(Gtk.ListStore(*fields))
|
||||
# [path, label, has_media?, device key]
|
||||
store = Gtk.ListStore(str, str, bool, str)
|
||||
self._combo.set_model(store)
|
||||
|
||||
text = Gtk.CellRendererText()
|
||||
self.combo.pack_start(text, True)
|
||||
self.combo.add_attribute(text, 'text', self.OPTICAL_LABEL)
|
||||
self.combo.get_accessible().set_name("physical-device-combo")
|
||||
|
||||
error = None
|
||||
if not self.conn.is_nodedev_capable():
|
||||
error = _("Libvirt version does not support media listing.")
|
||||
self._warn_icon.set_tooltip_text(error)
|
||||
self._warn_icon.set_visible(bool(error))
|
||||
|
||||
|
||||
def _set_mediadev_default(self):
|
||||
model = self.combo.get_model()
|
||||
if len(model) != 0:
|
||||
return
|
||||
|
||||
row = [None] * self.OPTICAL_FIELDS
|
||||
row[self.OPTICAL_DEV_PATH] = None
|
||||
row[self.OPTICAL_LABEL] = _("No device present")
|
||||
row[self.OPTICAL_HAS_MEDIA] = False
|
||||
row[self.OPTICAL_DEV_KEY] = None
|
||||
model.append(row)
|
||||
|
||||
def _pretty_label(self, nodedev):
|
||||
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")
|
||||
|
||||
return "%s (%s)" % (media_label, nodedev.xmlobj.block)
|
||||
|
||||
def _mediadev_set_default_selection(self):
|
||||
# Set the first active cdrom device as selected, otherwise none
|
||||
widget = self.combo
|
||||
model = widget.get_model()
|
||||
idx = 0
|
||||
active = widget.get_active()
|
||||
|
||||
if active != -1:
|
||||
# already a selection, don't change it
|
||||
return
|
||||
|
||||
for row in model:
|
||||
if row[self.OPTICAL_HAS_MEDIA] is True:
|
||||
widget.set_active(idx)
|
||||
return
|
||||
idx += 1
|
||||
|
||||
widget.set_active(0)
|
||||
|
||||
def _populate_media(self):
|
||||
if self._populated:
|
||||
return
|
||||
|
||||
widget = self.combo
|
||||
model = widget.get_model()
|
||||
model.clear()
|
||||
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(devtype="storage"):
|
||||
if not (nodedev.xmlobj.device_type == "storage" and
|
||||
nodedev.xmlobj.drive_type in ["cdrom", "floppy"]):
|
||||
continue
|
||||
if nodedev.xmlobj.drive_type != self.media_type:
|
||||
if nodedev.xmlobj.drive_type != media_type:
|
||||
continue
|
||||
|
||||
row = [None] * self.OPTICAL_FIELDS
|
||||
row[self.OPTICAL_DEV_PATH] = nodedev.xmlobj.block
|
||||
row[self.OPTICAL_LABEL] = self._pretty_label(nodedev)
|
||||
row[self.OPTICAL_HAS_MEDIA] = nodedev.xmlobj.media_available
|
||||
row[self.OPTICAL_DEV_KEY] = nodedev.xmlobj.name
|
||||
model.append(row)
|
||||
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)
|
||||
|
||||
self._set_mediadev_default()
|
||||
row = self._make_row(nodedev.xmlobj.block, label,
|
||||
nodedev.xmlobj.media_available,
|
||||
nodedev.xmlobj.name)
|
||||
rows.append(row)
|
||||
return rows
|
||||
|
||||
widget.set_active(-1)
|
||||
self._mediadev_set_default_selection()
|
||||
self._populated = True
|
||||
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 reset_state(self):
|
||||
try:
|
||||
self._populate_media()
|
||||
except Exception:
|
||||
logging.debug("Error populating mediadev combo", exc_info=True)
|
||||
def set_conn(self, conn):
|
||||
if conn == self.conn:
|
||||
return
|
||||
self.conn = conn
|
||||
self._init_rows()
|
||||
|
||||
def get_path(self):
|
||||
return uiutil.get_list_selection(
|
||||
self.combo, column=self.OPTICAL_DEV_PATH)
|
||||
def reset_state(self, is_floppy=False):
|
||||
if not self._rows_inited:
|
||||
self._init_rows()
|
||||
|
||||
def has_media(self):
|
||||
return uiutil.get_list_selection(
|
||||
self.combo, column=self.OPTICAL_HAS_MEDIA) or False
|
||||
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)
|
||||
|
|
Loading…
Reference in New Issue