# Copyright (C) 2014 Red Hat, Inc. # # This work is licensed under the GNU GPLv2 or later. # See the COPYING file in the top-level directory. from gi.repository import Gtk from ..lib import uiutil from ..baseclass import vmmGObject, vmmGObjectUI class vmmMediaCombo(vmmGObjectUI): __gsignals__ = { "changed": (vmmGObject.RUN_FIRST, None, [object]), "activate": (vmmGObject.RUN_FIRST, None, [object]), } MEDIA_TYPE_FLOPPY = "floppy" MEDIA_TYPE_CDROM = "cdrom" 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.top_box = 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() 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._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() # [path, label, has_media?, device key] store = Gtk.ListStore(str, str, bool, str) self._combo.set_model(store) 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("storage"): if not (nodedev.xmlobj.device_type == "storage" and nodedev.xmlobj.drive_type in ["cdrom", "floppy"]): continue if nodedev.xmlobj.drive_type != media_type: continue media_label = nodedev.xmlobj.media_label or _("Media Unknown") if not nodedev.xmlobj.media_available: media_label = _("No media detected") label = "%s (%s)" % (media_label, nodedev.xmlobj.block) row = self._make_row(nodedev.xmlobj.block, label, nodedev.xmlobj.media_available, nodedev.xmlobj.name) rows.append(row) return rows 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 set_conn(self, conn): if conn == self.conn: return self.conn = conn self._init_rows() def reset_state(self, is_floppy=False): if not self._rows_inited: self._init_rows() 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)