Move shared cdrom media UI to mediacombo.py

This commit is contained in:
Cole Robinson 2014-01-28 13:51:59 -05:00
parent 745ec7cb96
commit 8bb9853ec8
7 changed files with 287 additions and 274 deletions

View File

@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- Generated with glade 3.15.4 on Fri Sep 27 13:37:45 2013 -->
<!-- Generated with glade 3.16.1 -->
<interface>
<!-- interface-requires gtk+ 3.0 -->
<requires lib="gtk+" version="3.0"/>
<object class="GtkDialog" id="vmm-choose-cd">
<property name="can_focus">True</property>
<property name="has_focus">True</property>
@ -216,33 +216,13 @@
</packing>
</child>
<child>
<object class="GtkHBox" id="hbox2">
<object class="GtkAlignment" id="media-combo-align">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="spacing">6</property>
<property name="hexpand">False</property>
<property name="vexpand">False</property>
<child>
<object class="GtkComboBox" id="cd-path">
<property name="visible">True</property>
<property name="can_focus">False</property>
<signal name="changed" handler="on_cd_path_changed" swapped="no"/>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkImage" id="cd-path-warn">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="stock">gtk-dialog-warning</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
<placeholder/>
</child>
</object>
<packing>
@ -250,6 +230,7 @@
<property name="right_attach">2</property>
<property name="top_attach">3</property>
<property name="bottom_attach">4</property>
<property name="x_options">GTK_FILL</property>
<property name="y_options">GTK_FILL</property>
</packing>
</child>

View File

@ -687,40 +687,12 @@ bar</property>
</packing>
</child>
<child>
<object class="GtkAlignment" id="alignment12">
<object class="GtkAlignment" id="install-local-cdrom-align">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="left_padding">20</property>
<child>
<object class="GtkHBox" id="hbox10">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="spacing">6</property>
<child>
<object class="GtkComboBox" id="install-local-cdrom-combo">
<property name="visible">True</property>
<property name="can_focus">False</property>
<signal name="changed" handler="on_install_local_cdrom_combo_changed" swapped="no"/>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkImage" id="install-local-cdrom-warn">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="stock">gtk-dialog-warning</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
</object>
<placeholder/>
</child>
</object>
<packing>

View File

@ -93,6 +93,10 @@ class vmmGObject(GObject.GObject):
ret = GObject.GObject.disconnect(self, handle)
self._gobject_handles.remove(handle)
return ret
def disconnect_by_func(self, *args, **kwargs):
handle = GObject.GObject.disconnect_by_func(*args, **kwargs)
self._gobject_handles.remove(handle)
return handle
def add_gconf_handle(self, handle):
self._gconf_handles.append(handle)

View File

@ -24,10 +24,10 @@ import logging
from gi.repository import GObject
# pylint: enable=E0611
from virtManager import uiutil
from virtManager import sharedui
from virtManager.baseclass import vmmGObjectUI
from virtManager.mediadev import MEDIA_FLOPPY
from virtManager.mediacombo import vmmMediaCombo
from virtManager.storagebrowse import vmmStorageBrowser
@ -47,18 +47,20 @@ class vmmChooseCD(vmmGObjectUI):
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_cd_path_changed": self.change_cd_path,
"on_ok_clicked": self.ok,
"on_vmm_choose_cd_delete_event": self.close,
"on_cancel_clicked": self.close,
})
self.widget("iso-image").set_active(True)
self.initialize_opt_media()
self.reset_state()
def close(self, ignore1=None, ignore2=None):
@ -84,23 +86,27 @@ class vmmChooseCD(vmmGObjectUI):
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 == MEDIA_FLOPPY:
self.widget("physical-media").set_label(_("Floppy D_rive"))
self.widget("iso-image").set_label(_("Floppy _Image"))
def reset_state(self):
cd_path = self.widget("cd-path")
use_cdrom = (cd_path.get_active() > -1)
self.mediacombo.reset_state()
use_cdrom = (self.mediacombo.has_media())
if use_cdrom:
self.widget("physical-media").set_active(True)
else:
self.widget("iso-image").set_active(True)
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 = uiutil.get_list_selection(self.widget("cd-path"),
sharedui.OPTICAL_DEV_PATH)
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."))
@ -125,41 +131,14 @@ class vmmChooseCD(vmmGObjectUI):
self.close()
def media_toggled(self, ignore1=None, ignore2=None):
if self.widget("physical-media").get_active():
self.widget("cd-path").set_sensitive(True)
self.widget("iso-path").set_sensitive(False)
self.widget("iso-file-chooser").set_sensitive(False)
else:
self.widget("cd-path").set_sensitive(False)
self.widget("iso-path").set_sensitive(True)
self.widget("iso-file-chooser").set_sensitive(True)
def change_cd_path(self, ignore1=None, ignore2=None):
pass
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 initialize_opt_media(self):
widget = self.widget("cd-path")
warn = self.widget("cd-path-warn")
error = self.conn.mediadev_error
sharedui.build_mediadev_combo(widget)
sharedui.populate_mediadev_combo(self.conn, widget, self.media_type)
if error:
warn.show()
warn.set_tooltip_text(error)
else:
warn.hide()
self.widget("physical-media").set_sensitive(not bool(error))
if self.media_type == MEDIA_FLOPPY:
self.widget("physical-media").set_label(_("Floppy D_rive"))
self.widget("iso-image").set_label(_("Floppy _Image"))
def set_storage_path(self, src_ignore, path):
self.widget("iso-path").set_text(path)

View File

@ -40,6 +40,7 @@ from virtManager.storagebrowse import vmmStorageBrowser
from virtManager.details import vmmDetails
from virtManager.domain import vmmDomainVirtinst
from virtManager.netlist import vmmNetworkList
from virtManager.mediacombo import vmmMediaCombo
# Number of seconds to wait for media detection
DETECT_TIMEOUT = 20
@ -109,6 +110,7 @@ class vmmCreate(vmmGObjectUI):
self.config_window_signals = []
self.netlist = None
self.mediacombo = None
self.builder.connect_signals({
"on_vmm_newcreate_delete_event" : self.close,
@ -199,6 +201,13 @@ class vmmCreate(vmmGObjectUI):
self.netlist.cleanup()
self.netlist = None
if self.netlist:
self.netlist.cleanup()
self.netlist = None
if self.mediacombo:
self.mediacombo.cleanup()
self.mediacombo = None
def remove_conn(self):
if not self.conn:
return
@ -288,11 +297,6 @@ class vmmCreate(vmmGObjectUI):
uiutil.set_combo_text_column(os_variant_list, 1)
os_variant_list.set_row_separator_func(sep_func, os_variant_list)
# Physical CD-ROM model
cd_list = self.widget("install-local-cdrom-combo")
sharedui.build_mediadev_combo(cd_list)
# Archtecture
# [value, label]
archList = self.widget("config-arch")
@ -550,26 +554,22 @@ class vmmCreate(vmmGObjectUI):
# Install local
iso_option = self.widget("install-local-iso")
cdrom_option = self.widget("install-local-cdrom")
cdrom_list = self.widget("install-local-cdrom-combo")
cdrom_warn = self.widget("install-local-cdrom-warn")
sigs = sharedui.populate_mediadev_combo(self.conn, cdrom_list,
MEDIA_CDROM)
self.conn_signals.extend(sigs)
if self.mediacombo:
self.widget("install-local-cdrom-align").remove(
self.mediacombo.top_box)
self.mediacombo.cleanup()
self.mediacombo = None
if self.conn.mediadev_error:
cdrom_warn.show()
cdrom_option.set_sensitive(False)
cdrom_warn.set_tooltip_text(self.conn.mediadev_error)
else:
cdrom_warn.hide()
self.mediacombo = vmmMediaCombo(self.conn, self.builder, self.topwin,
MEDIA_CDROM)
self.mediacombo.reset_state()
self.widget("install-local-cdrom-align").add(
self.mediacombo.top_box)
# Don't select physical CDROM if no valid media is present
use_cd = (cdrom_list.get_active() >= 0)
if use_cd:
cdrom_option.set_active(True)
else:
iso_option.set_active(True)
cdrom_option.set_active(self.mediacombo.has_media())
iso_option.set_active(not self.mediacombo.has_media())
# Only allow ISO option for remote VM
is_local = not self.conn.is_remote()
@ -1012,9 +1012,7 @@ class vmmCreate(vmmGObjectUI):
def get_config_local_media(self, store_media=False):
if self.widget("install-local-cdrom").get_active():
return uiutil.get_list_selection(
self.widget("install-local-cdrom-combo"),
sharedui.OPTICAL_DEV_PATH)
return self.mediacombo.get_path()
else:
ret = self.widget("install-local-box").get_child().get_text()
if ret and store_media:
@ -1229,14 +1227,12 @@ class vmmCreate(vmmGObjectUI):
break
def toggle_local_cdrom(self, src):
combo = self.widget("install-local-cdrom-combo")
is_active = src.get_active()
if is_active:
if combo.get_active() != -1:
# Local CDROM was selected with media preset, detect distro
self.detect_media_os()
if is_active and self.mediacombo.get_path():
# Local CDROM was selected with media preset, detect distro
self.detect_media_os()
self.widget("install-local-cdrom-combo").set_sensitive(is_active)
self.widget("install-local-cdrom-align").set_sensitive(is_active)
def toggle_local_iso(self, src):
uselocal = src.get_active()

223
virtManager/mediacombo.py Normal file
View File

@ -0,0 +1,223 @@
#
# Copyright (C) 2014 Red Hat, Inc.
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
# MA 02110-1301 USA.
#
# pylint: disable=E0611
from gi.repository import Gtk
# pylint: enable=E0611
from virtManager import uiutil
from virtManager.baseclass import vmmGObjectUI
class vmmMediaCombo(vmmGObjectUI):
OPTICAL_FIELDS = 4
(OPTICAL_DEV_PATH,
OPTICAL_LABEL,
OPTICAL_HAS_MEDIA,
OPTICAL_DEV_KEY) = range(OPTICAL_FIELDS)
def __init__(self, conn, builder, topwin, media_type):
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._populated = False
self._init_ui()
def _cleanup(self):
try:
self.conn.disconnect_by_func(self._mediadev_added)
self.conn.disconnect_by_func(self._mediadev_removed)
except:
pass
self.conn = None
self.top_box.destroy()
self.top_box = None
##########################
# Initialization methods #
##########################
def _init_ui(self):
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.top_box.show_all()
# [Device path, pretty label, has_media?, device key, media key,
# vmmMediaDevice, is valid device]
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))
text = Gtk.CellRendererText()
self.combo.pack_start(text, True)
self.combo.add_attribute(text, 'text', self.OPTICAL_LABEL)
error = self.conn.mediadev_error
self._warn_icon.set_visible(bool(error))
self._warn_icon.set_tooltip_text(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 _set_mediadev_row_from_object(self, row, obj):
row[self.OPTICAL_DEV_PATH] = obj.get_path()
row[self.OPTICAL_LABEL] = obj.pretty_label()
row[self.OPTICAL_HAS_MEDIA] = obj.has_media()
row[self.OPTICAL_DEV_KEY] = obj.get_key()
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 _mediadev_media_changed(self, newobj):
widget = self.combo
model = widget.get_model()
active = widget.get_active()
idx = 0
# Search for the row with matching device node and
# fill in info about inserted media. If model has no current
# selection, select the new media.
for row in model:
if row[self.OPTICAL_DEV_PATH] == newobj.get_path():
self._set_mediadev_row_from_object(row, newobj)
has_media = row[self.OPTICAL_HAS_MEDIA]
if has_media and active == -1:
widget.set_active(idx)
elif not has_media and active == idx:
widget.set_active(-1)
idx = idx + 1
self._mediadev_set_default_selection()
def _mediadev_added(self, ignore, newobj):
widget = self.combo
model = widget.get_model()
if newobj.get_media_type() != self.media_type:
return
if model is None:
return
if len(model) == 1 and model[0][self.OPTICAL_DEV_PATH] is None:
# Only entry is the 'No device' entry
model.clear()
newobj.connect("media-added", self._mediadev_media_changed)
newobj.connect("media-removed", self._mediadev_media_changed)
# Brand new device
row = [None] * self.OPTICAL_FIELDS
self._set_mediadev_row_from_object(row, newobj)
model.append(row)
self._mediadev_set_default_selection()
def _mediadev_removed(self, ignore, key):
widget = self.combo
model = widget.get_model()
active = widget.get_active()
idx = 0
for row in model:
if row[self.OPTICAL_DEV_KEY] == key:
# Whole device removed
del(model[idx])
if idx > active and active != -1:
widget.set_active(active - 1)
elif idx == active:
widget.set_active(-1)
idx += 1
self._set_mediadev_default()
self._mediadev_set_default_selection()
def _populate_media(self):
if self._populated:
return
widget = self.combo
model = widget.get_model()
model.clear()
self._set_mediadev_default()
self.conn.connect("mediadev-added", self._mediadev_added)
self.conn.connect("mediadev-removed", self._mediadev_removed)
widget.set_active(-1)
self._mediadev_set_default_selection()
self._populated = True
##############
# Public API #
##############
def reset_state(self):
self._populate_media()
def get_path(self):
return uiutil.get_list_selection(self.combo, self.OPTICAL_DEV_PATH)
def has_media(self):
return uiutil.get_list_selection(self.combo, self.OPTICAL_HAS_MEDIA)

View File

@ -223,148 +223,6 @@ def check_path_search_for_qemu(err, conn, path):
config.running_config.add_perms_fix_ignore(errors.keys())
############################################
# Populate media widget (choosecd, create) #
############################################
OPTICAL_DEV_PATH = 0
OPTICAL_LABEL = 1
OPTICAL_IS_MEDIA_PRESENT = 2
OPTICAL_DEV_KEY = 3
OPTICAL_MEDIA_KEY = 4
OPTICAL_IS_VALID = 5
def _set_mediadev_default(model):
if len(model) == 0:
model.append([None, _("No device present"), False, None, None, False])
def _set_mediadev_row_from_object(row, obj):
row[OPTICAL_DEV_PATH] = obj.get_path()
row[OPTICAL_LABEL] = obj.pretty_label()
row[OPTICAL_IS_MEDIA_PRESENT] = obj.has_media()
row[OPTICAL_DEV_KEY] = obj.get_key()
row[OPTICAL_MEDIA_KEY] = obj.get_media_key()
row[OPTICAL_IS_VALID] = True
def _mediadev_set_default_selection(widget):
# Set the first active cdrom device as selected, otherwise none
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[OPTICAL_IS_MEDIA_PRESENT] is True:
widget.set_active(idx)
return
idx += 1
widget.set_active(-1)
def _mediadev_media_changed(newobj, widget):
model = widget.get_model()
active = widget.get_active()
idx = 0
# Search for the row with matching device node and
# fill in info about inserted media. If model has no current
# selection, select the new media.
for row in model:
if row[OPTICAL_DEV_PATH] == newobj.get_path():
_set_mediadev_row_from_object(row, newobj)
has_media = row[OPTICAL_IS_MEDIA_PRESENT]
if has_media and active == -1:
widget.set_active(idx)
elif not has_media and active == idx:
widget.set_active(-1)
idx = idx + 1
_mediadev_set_default_selection(widget)
def _mediadev_added(ignore_helper, newobj, widget, devtype):
model = widget.get_model()
if newobj.get_media_type() != devtype:
return
if model is None:
return
if len(model) == 1 and model[0][OPTICAL_IS_VALID] is False:
# Only entry is the 'No device' entry
model.clear()
newobj.connect("media-added", _mediadev_media_changed, widget)
newobj.connect("media-removed", _mediadev_media_changed, widget)
# Brand new device
row = [None, None, None, None, None, None]
_set_mediadev_row_from_object(row, newobj)
model.append(row)
_mediadev_set_default_selection(widget)
def _mediadev_removed(ignore_helper, key, widget):
model = widget.get_model()
active = widget.get_active()
idx = 0
for row in model:
if row[OPTICAL_DEV_KEY] == key:
# Whole device removed
del(model[idx])
if idx > active and active != -1:
widget.set_active(active - 1)
elif idx == active:
widget.set_active(-1)
idx += 1
_set_mediadev_default(model)
_mediadev_set_default_selection(widget)
def build_mediadev_combo(widget):
# [Device path, pretty label, has_media?, device key, media key,
# vmmMediaDevice, is valid device]
model = Gtk.ListStore(str, str, bool, str, str, bool)
widget.set_model(model)
model.clear()
text = Gtk.CellRendererText()
widget.pack_start(text, True)
widget.add_attribute(text, 'text', OPTICAL_LABEL)
widget.add_attribute(text, 'sensitive', OPTICAL_IS_VALID)
def populate_mediadev_combo(conn, widget, devtype):
sigs = []
model = widget.get_model()
model.clear()
_set_mediadev_default(model)
sigs.append(conn.connect("mediadev-added",
_mediadev_added, widget, devtype))
sigs.append(conn.connect("mediadev-removed", _mediadev_removed, widget))
widget.set_active(-1)
_mediadev_set_default_selection(widget)
return sigs
####################################################################
# Build toolbar shutdown button menu (manager and details toolbar) #
####################################################################