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:
Cole Robinson 2018-10-06 14:26:31 -04:00
parent 8ff5d750da
commit 0638e72f1f
14 changed files with 402 additions and 835 deletions

View File

@ -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 &amp; yeah boii &lt; &gt; 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'/>

View File

@ -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)

View File

@ -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")

View File

@ -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)")

View File

@ -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()

View File

@ -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.

View File

@ -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">&lt;b&gt;Choose Source Device or File&lt;/b&gt;</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>

View File

@ -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>

View File

@ -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>

View File

@ -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)

View File

@ -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

View File

@ -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")

View File

@ -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(

View File

@ -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)