mirror of
https://github.com/virt-manager/virt-manager.git
synced 2024-12-22 13:34:07 +03:00
Redesign OS distro selection UI to be faster to use
The current OS distro selection UI is fairly cumbersome to use. First you need to decide on a variant, then decide a distro and then look for the version you want. The list is filtered by default so only a subset of OS are displayed. So for less common distros you'll then need to start again and tell it to show all OS to try to find the one you want. The core problem is that we have an incredibly large list and want to make it easy for the user to find a specific entry. The modern UI paradigm for this problem is to provide interactive search with live updated results. The current UI does provide an interactive search facility on the OS version results, but you still have to first select a variant to be able to use the search which is unhelpful. This patch attempts to better apply the search UI design to the OS selection problem. We get rid of the notion of variants, distros and version, and provide a single text entry box in which the user can type a few letters of the OS name. As they type, a popover displays the matching results filtered on OS name. By default end of life OS will be hidden, so in general there will only be a small handful of results left after just typing a few characters. This makes it very quick to find and select the desired OS, without needing to provide a mutli-step navigation hierarchy. https://bugzilla.redhat.com/show_bug.cgi?id=1464306 Signed-off-by: Daniel P. Berrangé <berrange@redhat.com> (crobinso: fix some pylint)
This commit is contained in:
parent
b1460ba065
commit
d52d9885c8
@ -45,29 +45,3 @@ class TestOSDB(unittest.TestCase):
|
||||
guest.type = "qemu"
|
||||
res = OSDB.lookup_os("fedora21").get_recommended_resources(guest)
|
||||
assert res["n-cpus"] == 1
|
||||
|
||||
def test_list_os(self):
|
||||
full_list = OSDB.list_os()
|
||||
pref_list = OSDB.list_os(typename="linux", sortpref=["fedora", "rhel"])
|
||||
support_list = OSDB.list_os(only_supported=True)
|
||||
|
||||
assert full_list[0] is not pref_list[0]
|
||||
assert len(full_list) > len(support_list)
|
||||
assert len(OSDB.list_os(typename="generic")) == 1
|
||||
|
||||
# Verify that sort order actually worked
|
||||
found_fedora = False
|
||||
found_rhel = False
|
||||
for idx, osobj in enumerate(pref_list[:]):
|
||||
if osobj.name.startswith("fedora"):
|
||||
found_fedora = True
|
||||
continue
|
||||
|
||||
for osobj2 in pref_list[idx:]:
|
||||
if osobj2.name.startswith("rhel"):
|
||||
found_rhel = True
|
||||
continue
|
||||
break
|
||||
break
|
||||
|
||||
assert found_fedora and found_rhel
|
||||
|
256
ui/create.ui
256
ui/create.ui
@ -1,5 +1,5 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!-- Generated with glade 3.20.3 -->
|
||||
<!-- Generated with glade 3.20.4 -->
|
||||
<interface>
|
||||
<requires lib="gtk+" version="3.14"/>
|
||||
<object class="GtkAdjustment" id="adjustment2">
|
||||
@ -18,8 +18,8 @@
|
||||
<property name="stock">gtk-new</property>
|
||||
</object>
|
||||
<object class="GtkWindow" id="vmm-create">
|
||||
<property name="width_request">400</property>
|
||||
<property name="height_request">400</property>
|
||||
<property name="width_request">600</property>
|
||||
<property name="height_request">500</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="title" translatable="yes">New VM</property>
|
||||
<property name="resizable">False</property>
|
||||
@ -2027,184 +2027,89 @@ connections is not yet supported.</small></property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkBox" id="install-os-distro-box">
|
||||
<object class="GtkFrame" id="install-os-distro-box">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="orientation">vertical</property>
|
||||
<property name="spacing">6</property>
|
||||
<property name="label_xalign">0</property>
|
||||
<property name="shadow_type">none</property>
|
||||
<child>
|
||||
<object class="GtkBox" id="install-detect-os-box">
|
||||
<object class="GtkAlignment">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="orientation">vertical</property>
|
||||
<signal name="hide" handler="on_install_detect_os_box_hide" swapped="no"/>
|
||||
<signal name="show" handler="on_install_detect_os_box_show" swapped="no"/>
|
||||
<property name="top_padding">6</property>
|
||||
<property name="bottom_padding">6</property>
|
||||
<property name="left_padding">12</property>
|
||||
<child>
|
||||
<object class="GtkCheckButton" id="install-detect-os">
|
||||
<property name="label" translatable="yes">A_utomatically detect operating system based on install media</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_detect_os_toggled" swapped="no"/>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">0</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="GtkLabel" id="install-nodetect-label">
|
||||
<property name="can_focus">False</property>
|
||||
<property name="halign">start</property>
|
||||
<property name="label" translatable="yes">Choose an operating system type and version</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">False</property>
|
||||
<property name="position">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkAlignment" id="alignment9">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="left_padding">15</property>
|
||||
<child>
|
||||
<object class="GtkGrid" id="table1">
|
||||
<object class="GtkBox">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="row_spacing">4</property>
|
||||
<property name="column_spacing">6</property>
|
||||
<property name="orientation">vertical</property>
|
||||
<property name="spacing">6</property>
|
||||
<child>
|
||||
<object class="GtkLabel" id="install-os-version-label">
|
||||
<object class="GtkSearchEntry" id="install-os-name">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="halign">start</property>
|
||||
<property name="valign">center</property>
|
||||
<property name="label">-</property>
|
||||
<child internal-child="accessible">
|
||||
<object class="AtkObject" id="install-os-version-label-atkobject">
|
||||
<property name="AtkObject::accessible-name">install-os-version-label</property>
|
||||
</object>
|
||||
</child>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="primary_icon_name">edit-find-symbolic</property>
|
||||
<property name="primary_icon_activatable">False</property>
|
||||
<property name="primary_icon_sensitive">False</property>
|
||||
<signal name="search-changed" handler="on_install_os_name_search_changed" swapped="no"/>
|
||||
<signal name="stop-search" handler="on_install_os_name_stop_search" swapped="no"/>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="left_attach">2</property>
|
||||
<property name="top_attach">1</property>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">0</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkLabel" id="install-os-type-label">
|
||||
<object class="GtkBox" id="install-detect-os-box">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="halign">start</property>
|
||||
<property name="valign">center</property>
|
||||
<property name="label">-</property>
|
||||
<child internal-child="accessible">
|
||||
<object class="AtkObject" id="install-os-type-label-atkobject">
|
||||
<property name="AtkObject::accessible-name">install-os-type-label</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="left_attach">2</property>
|
||||
<property name="top_attach">0</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkComboBox" id="install-os-type">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="valign">center</property>
|
||||
<signal name="changed" handler="on_install_os_type_changed" swapped="no"/>
|
||||
<child internal-child="accessible">
|
||||
<object class="AtkObject" id="install-os-type-atkobject">
|
||||
<property name="AtkObject::accessible-name">install-os-type</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="left_attach">1</property>
|
||||
<property name="top_attach">0</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkLabel" id="label17">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="halign">start</property>
|
||||
<property name="valign">center</property>
|
||||
<property name="label" translatable="yes">_Version:</property>
|
||||
<property name="use_underline">True</property>
|
||||
<property name="mnemonic_widget">install-os-version</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="left_attach">0</property>
|
||||
<property name="top_attach">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkLabel" id="label16">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="halign">end</property>
|
||||
<property name="valign">center</property>
|
||||
<property name="label" translatable="yes">OS _type:</property>
|
||||
<property name="use_underline">True</property>
|
||||
<property name="mnemonic_widget">install-os-type</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="left_attach">0</property>
|
||||
<property name="top_attach">0</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkComboBox" id="install-os-version">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="valign">center</property>
|
||||
<property name="has_entry">True</property>
|
||||
<signal name="changed" handler="on_install_os_version_changed" swapped="no"/>
|
||||
<child internal-child="entry">
|
||||
<object class="GtkEntry" id="install-os-version-entry">
|
||||
<child>
|
||||
<object class="GtkCheckButton" id="install-detect-os">
|
||||
<property name="label" translatable="yes">A_utomatically detect from the installation media / source</property>
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<child internal-child="accessible">
|
||||
<object class="AtkObject" id="install-os-version-entry-atkobject">
|
||||
<property name="AtkObject::accessible-name">install-os-version-entry</property>
|
||||
</object>
|
||||
</child>
|
||||
<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_detect_os_toggled" swapped="no"/>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">0</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child internal-child="accessible">
|
||||
<object class="AtkObject" id="install-os-version-atkobject">
|
||||
<property name="AtkObject::accessible-name">install-os-version</property>
|
||||
<child>
|
||||
<object class="GtkSpinner" id="install-detect-os-spinner">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="left_attach">1</property>
|
||||
<property name="top_attach">1</property>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">False</property>
|
||||
<property name="position">2</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child type="label">
|
||||
<object class="GtkLabel">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="label" translatable="yes">Operating system distribution:</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
@ -2753,50 +2658,6 @@ connections is not yet supported.</small></property>
|
||||
<property name="position">0</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkAlignment" id="finish-warn-os-align">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="left_padding">6</property>
|
||||
<child>
|
||||
<object class="GtkBox" id="finish-warn-os">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="spacing">3</property>
|
||||
<child>
|
||||
<object class="GtkImage" id="image4">
|
||||
<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">0</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkLabel" id="label47">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="label" translatable="yes"><small>Specifying an operating system is required for best performance</small></property>
|
||||
<property name="use_markup">True</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkExpander" id="advanced-expander">
|
||||
<property name="visible">True</property>
|
||||
@ -2884,14 +2745,13 @@ connections is not yet supported.</small></property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="label" translatable="yes">N_etwork selection</property>
|
||||
<property name="use_underline">True</property>
|
||||
<property name="mnemonic_widget">advanced-expander</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">False</property>
|
||||
<property name="position">2</property>
|
||||
<property name="position">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
</object>
|
||||
|
104
ui/oslist.ui
Normal file
104
ui/oslist.ui
Normal file
@ -0,0 +1,104 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!-- Generated with glade 3.20.4 -->
|
||||
<interface>
|
||||
<requires lib="gtk+" version="3.14"/>
|
||||
<object class="GtkPopover" id="vmm-oslist">
|
||||
<property name="width_request">400</property>
|
||||
<property name="height_request">300</property>
|
||||
<property name="can_focus">False</property>
|
||||
<child>
|
||||
<object class="GtkBox">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="margin_left">6</property>
|
||||
<property name="margin_right">6</property>
|
||||
<property name="margin_top">6</property>
|
||||
<property name="margin_bottom">6</property>
|
||||
<property name="orientation">vertical</property>
|
||||
<property name="spacing">6</property>
|
||||
<child>
|
||||
<object class="GtkBox">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="spacing">6</property>
|
||||
<child>
|
||||
<object class="GtkImage">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="stock">gtk-info</property>
|
||||
<property name="icon_size">3</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">0</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkLabel">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="label" translatable="yes">Can't find the operating system you are looking for ?
|
||||
Try selecting the next most recent version displayed,
|
||||
or use the "Generic" entry.</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">True</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">0</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkScrolledWindow">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="vscrollbar_policy">always</property>
|
||||
<property name="shadow_type">in</property>
|
||||
<child>
|
||||
<object class="GtkTreeView" id="os-list">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="headers_visible">False</property>
|
||||
<property name="enable_search">False</property>
|
||||
<property name="hover_selection">True</property>
|
||||
<property name="enable_grid_lines">horizontal</property>
|
||||
<property name="activate_on_single_click">True</property>
|
||||
<child internal-child="selection">
|
||||
<object class="GtkTreeSelection"/>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">True</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkCheckButton" id="include-eol">
|
||||
<property name="label" translatable="yes">Include end of life operating systems</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="draw_indicator">True</property>
|
||||
<signal name="toggled" handler="on_include_eol_toggled" swapped="no"/>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">2</property>
|
||||
</packing>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</interface>
|
@ -29,6 +29,7 @@ from .engine import vmmEngine
|
||||
from .mediacombo import vmmMediaCombo
|
||||
from .netlist import vmmNetworkList
|
||||
from .storagebrowse import vmmStorageBrowser
|
||||
from .oslist import vmmOSList
|
||||
|
||||
# Number of seconds to wait for media detection
|
||||
DETECT_TIMEOUT = 20
|
||||
@ -124,6 +125,7 @@ class vmmCreate(vmmGObjectUI):
|
||||
|
||||
self._guest = None
|
||||
self._failed_guest = None
|
||||
self._os = None
|
||||
|
||||
# Distro detection state variables
|
||||
self._detect_os_in_progress = False
|
||||
@ -171,10 +173,6 @@ class vmmCreate(vmmGObjectUI):
|
||||
"on_install_container_source_toggle": self._container_source_toggle,
|
||||
|
||||
"on_install_detect_os_toggled": self._toggle_detect_os,
|
||||
"on_install_os_type_changed": self._change_os_type,
|
||||
"on_install_os_version_changed": self._change_os_version,
|
||||
"on_install_detect_os_box_show": self._os_detect_visibility_changed,
|
||||
"on_install_detect_os_box_hide": self._os_detect_visibility_changed,
|
||||
|
||||
"on_kernel_browse_clicked": self._browse_kernel,
|
||||
"on_initrd_browse_clicked": self._browse_initrd,
|
||||
@ -183,6 +181,9 @@ class vmmCreate(vmmGObjectUI):
|
||||
"on_enable_storage_toggled": self._toggle_enable_storage,
|
||||
|
||||
"on_create_vm_name_changed": self._name_changed,
|
||||
|
||||
"on_install_os_name_search_changed": self._os_name_search_changed,
|
||||
"on_install_os_name_stop_search": self._os_name_stop_search,
|
||||
})
|
||||
self.bind_escape_key_close()
|
||||
|
||||
@ -294,46 +295,6 @@ class vmmCreate(vmmGObjectUI):
|
||||
# Lists for OS container bootstrap
|
||||
set_model_list("install-oscontainer-source-url-combo")
|
||||
|
||||
def sep_func(model, it, combo):
|
||||
ignore = combo
|
||||
return model[it][OS_COL_IS_SEP]
|
||||
|
||||
def make_os_model():
|
||||
# [os value, os label, is seperator, is 'show all']
|
||||
cols = []
|
||||
cols.insert(OS_COL_ID, str)
|
||||
cols.insert(OS_COL_LABEL, str)
|
||||
cols.insert(OS_COL_IS_SEP, bool)
|
||||
cols.insert(OS_COL_IS_SHOW_ALL, bool)
|
||||
return Gtk.TreeStore(*cols)
|
||||
|
||||
def make_completion_model():
|
||||
# [os value, os label]
|
||||
cols = []
|
||||
cols.insert(OS_COL_ID, str)
|
||||
cols.insert(OS_COL_LABEL, str)
|
||||
return Gtk.ListStore(*cols)
|
||||
|
||||
# Lists for distro type + variant
|
||||
os_type_list = self.widget("install-os-type")
|
||||
os_type_model = make_os_model()
|
||||
os_type_list.set_model(os_type_model)
|
||||
uiutil.init_combo_text_column(os_type_list, 1)
|
||||
os_type_list.set_row_separator_func(sep_func, os_type_list)
|
||||
|
||||
os_variant_list = self.widget("install-os-version")
|
||||
os_variant_model = make_os_model()
|
||||
os_variant_list.set_model(os_variant_model)
|
||||
uiutil.init_combo_text_column(os_variant_list, 1)
|
||||
os_variant_list.set_row_separator_func(sep_func, os_variant_list)
|
||||
|
||||
entry = self.widget("install-os-version-entry")
|
||||
completion = Gtk.EntryCompletion()
|
||||
entry.set_completion(completion)
|
||||
completion.set_text_column(1)
|
||||
completion.set_inline_completion(True)
|
||||
completion.set_model(make_completion_model())
|
||||
|
||||
# Archtecture
|
||||
archList = self.widget("arch")
|
||||
# [label, guest.os.arch value]
|
||||
@ -365,6 +326,16 @@ class vmmCreate(vmmGObjectUI):
|
||||
lst.set_model(model)
|
||||
uiutil.init_combo_text_column(lst, 0)
|
||||
|
||||
self._os_list = vmmOSList()
|
||||
self._os_list.connect("os-selected", self._os_name_selected)
|
||||
|
||||
def _os_name_selected(self, ignore, osobj):
|
||||
name = self.widget("install-os-name")
|
||||
self._os = osobj
|
||||
self._os_list.hide()
|
||||
|
||||
if self._os is not None:
|
||||
name.set_text(self._os.label)
|
||||
|
||||
def _reset_state(self, urihint=None):
|
||||
"""
|
||||
@ -395,8 +366,6 @@ class vmmCreate(vmmGObjectUI):
|
||||
|
||||
# Distro/Variant
|
||||
self._toggle_detect_os(self.widget("install-detect-os"))
|
||||
self._populate_os_type_model()
|
||||
self.widget("install-os-type").set_active(0)
|
||||
|
||||
def _populate_media_model(media_model, urls):
|
||||
media_model.clear()
|
||||
@ -415,7 +384,6 @@ class vmmCreate(vmmGObjectUI):
|
||||
self.widget("install-url-options").set_expanded(False)
|
||||
urlmodel = self.widget("install-url-combo").get_model()
|
||||
_populate_media_model(urlmodel, self.config.get_media_urls())
|
||||
self._set_distro_labels("-", "-")
|
||||
|
||||
# Install import
|
||||
self.widget("install-import-entry").set_text("")
|
||||
@ -970,183 +938,6 @@ class vmmCreate(vmmGObjectUI):
|
||||
# Helpers for populating OS type/variant UI #
|
||||
#############################################
|
||||
|
||||
def _add_os_row(self, model, name="", label="",
|
||||
sep=False, action=False, parent=None):
|
||||
"""
|
||||
Helper for building an os type/version row and adding it to
|
||||
the list model if necessary
|
||||
"""
|
||||
|
||||
row = []
|
||||
row.insert(OS_COL_ID, name)
|
||||
row.insert(OS_COL_LABEL, label)
|
||||
row.insert(OS_COL_IS_SEP, sep)
|
||||
row.insert(OS_COL_IS_SHOW_ALL, action)
|
||||
|
||||
return model.append(parent, row)
|
||||
|
||||
def _add_completion_row(self, model, name, label):
|
||||
row = []
|
||||
row.insert(OS_COL_ID, name)
|
||||
row.insert(OS_COL_LABEL, label)
|
||||
model.append(row)
|
||||
|
||||
def _populate_os_type_model(self):
|
||||
widget = self.widget("install-os-type")
|
||||
model = widget.get_model()
|
||||
model.clear()
|
||||
|
||||
# Kind of a hack, just show linux + windows by default since
|
||||
# that's all 98% of people care about
|
||||
supported = {"generic", "linux", "windows"}
|
||||
|
||||
# Move 'generic' to the front of the list
|
||||
types = virtinst.OSDB.list_types()
|
||||
types.remove("generic")
|
||||
types.insert(0, "generic")
|
||||
|
||||
# Pretty names for OSes. If a new OS is not found here,
|
||||
# its capitalized name is used.
|
||||
oses = {
|
||||
"bsd": _("BSD"),
|
||||
"generic": _("Generic"),
|
||||
"linux": _("Linux"),
|
||||
"macos": _("macOS"),
|
||||
"other": _("Others"),
|
||||
"solaris": _("Solaris"),
|
||||
"windows": _("Windows"),
|
||||
}
|
||||
|
||||
# When only the "supported" types are requested,
|
||||
# filter them.
|
||||
if not self._show_all_os_was_selected:
|
||||
types = [t for t in types if t in supported]
|
||||
|
||||
for typename in types:
|
||||
try:
|
||||
typelabel = oses[typename]
|
||||
except KeyError:
|
||||
typelabel = typename.capitalize()
|
||||
|
||||
self._add_os_row(model, typename, typelabel)
|
||||
|
||||
if not self._show_all_os_was_selected:
|
||||
self._add_os_row(model, sep=True)
|
||||
self._add_os_row(model, label=_("Show all OS options"), action=True)
|
||||
|
||||
# Select 'generic' by default
|
||||
widget.set_active(0)
|
||||
|
||||
def _populate_os_variant_model(self, _type):
|
||||
widget = self.widget("install-os-version")
|
||||
model = widget.get_model()
|
||||
model.clear()
|
||||
|
||||
completion_model = self.widget("install-os-version-entry").get_completion().get_model()
|
||||
completion_model.clear()
|
||||
|
||||
preferred = self.config.preferred_distros
|
||||
|
||||
# All the subgroups for top-level types. Distributions not
|
||||
# belonging to these groups will be shown either in a "Others"
|
||||
# group, or top-level if there are no other groups.
|
||||
groups = {
|
||||
"altlinux": _("ALT Linux"),
|
||||
"centos": _("CentOS"),
|
||||
"debian": _("Debian"),
|
||||
"fedora": _("Fedora"),
|
||||
"freebsd": _("FreeBSD"),
|
||||
"mageia": _("Mageia"),
|
||||
"netbsd": _("NetBSD"),
|
||||
"openbsd": _("OpenBSD"),
|
||||
"opensuse": _("openSUSE"),
|
||||
"rhel": _("Red Hat Enterprise Linux"),
|
||||
"sled": _("SUSE Linux Enterprise Desktop"),
|
||||
"sles": _("SUSE Linux Enterprise Server"),
|
||||
"ubuntu": _("Ubuntu"),
|
||||
}
|
||||
|
||||
if self._show_all_os_was_selected:
|
||||
# List all the OSes, and determine which OSes have groups,
|
||||
# and which do not.
|
||||
variants = virtinst.OSDB.list_os(typename=_type,
|
||||
sortpref=preferred)
|
||||
all_distros = set([_os.distro for _os in variants])
|
||||
distros = [_os for _os in all_distros if _os in groups]
|
||||
distros.sort()
|
||||
other_distros = [_os for _os in all_distros if _os not in groups]
|
||||
parents = dict()
|
||||
if len(distros) > 0:
|
||||
# We have groups for the OSes, so create them.
|
||||
for d in distros:
|
||||
parents[d] = self._add_os_row(model, "", groups[d])
|
||||
# Create the "Others" group at the end, for the OSes
|
||||
# without a group.
|
||||
if len(other_distros):
|
||||
others_parent = self._add_os_row(model, "", _('Others'))
|
||||
for d in other_distros:
|
||||
parents[d] = others_parent
|
||||
else:
|
||||
# No groups, so assume the top-level will be the parent
|
||||
# all the OSes.
|
||||
for d in other_distros:
|
||||
parents[d] = None
|
||||
for v in variants:
|
||||
self._add_os_row(model, v.name, v.label,
|
||||
parent=parents[v.distro])
|
||||
self._add_completion_row(completion_model, v.name, v.label)
|
||||
else:
|
||||
# We are showing only the supported systems, so query them,
|
||||
# and add them directly to their type.
|
||||
variants = virtinst.OSDB.list_os(typename=_type,
|
||||
sortpref=preferred, only_supported=True)
|
||||
for v in variants:
|
||||
self._add_os_row(model, v.name, v.label)
|
||||
self._add_completion_row(completion_model, v.name, v.label)
|
||||
|
||||
# Add the menu entries to show all the OSes
|
||||
self._add_os_row(model, sep=True)
|
||||
self._add_os_row(model, label=_("Show all OS options"), action=True)
|
||||
|
||||
widget.set_active(0)
|
||||
|
||||
def _set_distro_labels(self, distro, ver):
|
||||
self.widget("install-os-type-label").set_text(distro)
|
||||
self.widget("install-os-version-label").set_text(ver)
|
||||
|
||||
def _set_os_id_in_ui(self, os_widget, os_id):
|
||||
"""
|
||||
Helper method to set the os type/version widgets to the passed
|
||||
OS ID value
|
||||
"""
|
||||
model = os_widget.get_model()
|
||||
def find_row():
|
||||
def cmp_func(model, path, it, user_data):
|
||||
ignore = path
|
||||
if model.get_value(it, OS_COL_ID) == os_id:
|
||||
os_widget.set_active_iter(it)
|
||||
user_data[0] = model.get_value(it, OS_COL_LABEL)
|
||||
return True
|
||||
return False
|
||||
data = [None]
|
||||
model.foreach(cmp_func, data)
|
||||
label = data[0]
|
||||
if not label:
|
||||
os_widget.set_active(0)
|
||||
return label
|
||||
|
||||
label = None
|
||||
if os_id:
|
||||
label = find_row()
|
||||
|
||||
if not label and not self._show_all_os_was_selected:
|
||||
# We didn't find the OS in the variant UI, but we are only
|
||||
# showing the reduced OS list. Trigger the _show_all_os option,
|
||||
# and try again.
|
||||
os_widget.set_active(len(model) - 1)
|
||||
label = find_row()
|
||||
return label or _("Unknown")
|
||||
|
||||
def _set_distro_selection(self, variant):
|
||||
"""
|
||||
Update the UI with the distro that was detected from the detection
|
||||
@ -1157,18 +948,16 @@ class vmmCreate(vmmGObjectUI):
|
||||
# update the UI
|
||||
return
|
||||
|
||||
distro_type = None
|
||||
distro_var = None
|
||||
name = self.widget("install-os-name")
|
||||
if variant:
|
||||
osclass = virtinst.OSDB.lookup_os(variant)
|
||||
distro_type = osclass.get_typename()
|
||||
distro_var = osclass.name
|
||||
self._os = virtinst.OSDB.lookup_os(variant)
|
||||
else:
|
||||
self._os = None
|
||||
|
||||
dl = self._set_os_id_in_ui(
|
||||
self.widget("install-os-type"), distro_type)
|
||||
vl = self._set_os_id_in_ui(
|
||||
self.widget("install-os-version"), distro_var)
|
||||
self._set_distro_labels(dl, vl)
|
||||
if self._os is None:
|
||||
name.set_text(_("None detected"))
|
||||
else:
|
||||
name.set_text(self._os.label)
|
||||
|
||||
|
||||
###############################
|
||||
@ -1200,7 +989,6 @@ class vmmCreate(vmmGObjectUI):
|
||||
self.widget("summary-storage-path").set_markup(storagepath)
|
||||
|
||||
def _populate_summary(self):
|
||||
distro, version, ignore1, dlabel, vlabel = self._get_config_os_info()
|
||||
mem = _pretty_memory(int(self._guest.memory))
|
||||
cpu = str(int(self._guest.vcpus))
|
||||
|
||||
@ -1221,21 +1009,7 @@ class vmmCreate(vmmGObjectUI):
|
||||
elif instmethod == INSTALL_PAGE_VZ_TEMPLATE:
|
||||
install = _("Virtuozzo container")
|
||||
|
||||
osstr = ""
|
||||
have_os = True
|
||||
if self._guest.os.is_container():
|
||||
osstr = _("Linux")
|
||||
elif not distro:
|
||||
osstr = _("Generic")
|
||||
have_os = False
|
||||
elif not version:
|
||||
osstr = _("Generic") + " " + dlabel
|
||||
have_os = False
|
||||
else:
|
||||
osstr = vlabel
|
||||
|
||||
self.widget("finish-warn-os").set_visible(not have_os)
|
||||
self.widget("summary-os").set_text(osstr)
|
||||
self.widget("summary-os").set_text(self._os and self._os.label or _("Unknown"))
|
||||
self.widget("summary-install").set_text(install)
|
||||
self.widget("summary-mem").set_text(mem)
|
||||
self.widget("summary-cpu").set_text(cpu)
|
||||
@ -1317,31 +1091,6 @@ class vmmCreate(vmmGObjectUI):
|
||||
INSTALL_PAGE_CONTAINER_OS,
|
||||
INSTALL_PAGE_VZ_TEMPLATE]
|
||||
|
||||
def _get_config_os_info(self):
|
||||
drow = uiutil.get_list_selected_row(self.widget("install-os-type"))
|
||||
distro = None
|
||||
dlabel = None
|
||||
variant = None
|
||||
entry = self.widget("install-os-version-entry")
|
||||
vlabel = entry.get_text()
|
||||
|
||||
for row in entry.get_completion().get_model():
|
||||
if row[OS_COL_LABEL] == vlabel:
|
||||
variant = row[OS_COL_ID]
|
||||
break
|
||||
|
||||
if not variant:
|
||||
return (None, None, False, None, None)
|
||||
|
||||
if drow:
|
||||
distro = drow[OS_COL_ID]
|
||||
dlabel = drow[OS_COL_LABEL]
|
||||
|
||||
return (distro and str(distro),
|
||||
str(variant),
|
||||
True,
|
||||
str(dlabel), str(vlabel))
|
||||
|
||||
def _get_config_local_media(self, store_media=False):
|
||||
if self.widget("install-cdrom-radio").get_active():
|
||||
return self._mediacombo.get_path()
|
||||
@ -1506,56 +1255,30 @@ class vmmCreate(vmmGObjectUI):
|
||||
def _toggle_detect_os(self, src):
|
||||
dodetect = src.get_active()
|
||||
|
||||
self.widget("install-os-type-label").set_visible(dodetect)
|
||||
self.widget("install-os-version-label").set_visible(dodetect)
|
||||
self.widget("install-os-type").set_visible(not dodetect)
|
||||
self.widget("install-os-version").set_visible(not dodetect)
|
||||
self.widget("install-os-name").set_sensitive(not dodetect)
|
||||
self.widget("install-os-name").set_text("")
|
||||
self._os = None
|
||||
|
||||
if dodetect:
|
||||
self.widget("install-os-version-entry").set_text("")
|
||||
self._os_already_detected_for_media = False
|
||||
self._start_detect_os_if_needed()
|
||||
|
||||
def _selected_os_row(self):
|
||||
return uiutil.get_list_selected_row(self.widget("install-os-type"))
|
||||
def _os_name_search_changed(self, src):
|
||||
searchname = src.get_text().strip()
|
||||
if self._os is None:
|
||||
if src.get_sensitive() and searchname != "":
|
||||
self._os_list.filter_name(searchname)
|
||||
self._os_list.show(src)
|
||||
else:
|
||||
self._os_list.hide()
|
||||
else:
|
||||
if self._os.label != searchname:
|
||||
self._os = None
|
||||
self._os_list.hide()
|
||||
|
||||
def _change_os_type(self, box):
|
||||
ignore = box
|
||||
row = self._selected_os_row()
|
||||
if not row:
|
||||
return
|
||||
|
||||
_type = row[OS_COL_ID]
|
||||
self._populate_os_variant_model(_type)
|
||||
if not row[OS_COL_IS_SHOW_ALL]:
|
||||
return
|
||||
|
||||
self._show_all_os_was_selected = True
|
||||
self._populate_os_type_model()
|
||||
|
||||
def _change_os_version(self, box):
|
||||
show_all = uiutil.get_list_selection(box,
|
||||
column=OS_COL_IS_SHOW_ALL, check_entry=False)
|
||||
if not show_all:
|
||||
return
|
||||
|
||||
# 'show all OS' was clicked
|
||||
# Get previous type to reselect it later
|
||||
type_row = self._selected_os_row()
|
||||
if not type_row:
|
||||
return
|
||||
old_type = type_row[OS_COL_ID]
|
||||
|
||||
self._show_all_os_was_selected = True
|
||||
self._populate_os_type_model()
|
||||
|
||||
# Reselect previous type row
|
||||
os_type_list = self.widget("install-os-type")
|
||||
os_type_model = os_type_list.get_model()
|
||||
for idx, row in enumerate(os_type_model):
|
||||
if row[OS_COL_ID] == old_type:
|
||||
os_type_list.set_active(idx)
|
||||
break
|
||||
def _os_name_stop_search(self, src):
|
||||
src.set_text("")
|
||||
self._os_list.hide()
|
||||
|
||||
def _local_media_toggled(self, src):
|
||||
usecdrom = src.get_active()
|
||||
@ -1568,19 +1291,6 @@ class vmmCreate(vmmGObjectUI):
|
||||
else:
|
||||
self._iso_changed(self.widget("install-iso-entry"))
|
||||
|
||||
def _os_detect_visibility_changed(self, src, ignore=None):
|
||||
is_visible = src.get_visible()
|
||||
detect_chkbox = self.widget("install-detect-os")
|
||||
nodetect_label = self.widget("install-nodetect-label")
|
||||
|
||||
detect_chkbox.set_active(is_visible)
|
||||
detect_chkbox.toggled()
|
||||
|
||||
if is_visible:
|
||||
nodetect_label.hide()
|
||||
else:
|
||||
nodetect_label.show()
|
||||
|
||||
def _browse_oscontainer(self, ignore):
|
||||
self._browse_file("install-oscontainer-fs", is_dir=True)
|
||||
def _browse_app(self, ignore):
|
||||
@ -1666,7 +1376,7 @@ class vmmCreate(vmmGObjectUI):
|
||||
fs_dir = [os.environ['HOME'],
|
||||
'.local/share/libvirt/filesystems/']
|
||||
|
||||
fs = fs_dir + [self._generate_default_name(None, None)]
|
||||
fs = fs_dir + [self._generate_default_name(None)]
|
||||
self.widget("install-oscontainer-fs").set_text(os.path.join(*fs))
|
||||
|
||||
|
||||
@ -1737,7 +1447,9 @@ class vmmCreate(vmmGObjectUI):
|
||||
def _set_install_page(self):
|
||||
instnotebook = self.widget("install-method-pages")
|
||||
detectbox = self.widget("install-detect-os-box")
|
||||
detect = self.widget("install-detect-os")
|
||||
osbox = self.widget("install-os-distro-box")
|
||||
name = self.widget("install-os-name")
|
||||
instpage = self._get_config_install_page()
|
||||
|
||||
# Setting OS value for a container guest doesn't really matter
|
||||
@ -1752,6 +1464,13 @@ class vmmCreate(vmmGObjectUI):
|
||||
self._get_config_install_page() == INSTALL_PAGE_URL)
|
||||
|
||||
detectbox.set_visible(enabledetect)
|
||||
autodetect = detectbox.get_visible() and detect.get_active()
|
||||
name.set_sensitive(not autodetect)
|
||||
if enabledetect:
|
||||
self._os = None
|
||||
else:
|
||||
if self._os is None:
|
||||
name.set_text("")
|
||||
|
||||
if instpage == INSTALL_PAGE_PXE:
|
||||
# Hide the install notebook for pxe, since there isn't anything
|
||||
@ -1915,18 +1634,16 @@ class vmmCreate(vmmGObjectUI):
|
||||
return False
|
||||
return True
|
||||
|
||||
def _generate_default_name(self, distro, variant):
|
||||
def _generate_default_name(self, osobj):
|
||||
force_num = False
|
||||
if self._guest.os.is_container():
|
||||
basename = "container"
|
||||
force_num = True
|
||||
elif not distro:
|
||||
elif not osobj or not osobj.distro:
|
||||
basename = "vm"
|
||||
force_num = True
|
||||
elif not variant:
|
||||
basename = distro
|
||||
else:
|
||||
basename = variant
|
||||
basename = osobj.distro
|
||||
|
||||
if self._guest.os.arch != self.conn.caps.host.cpu.arch:
|
||||
basename += "-%s" % _pretty_arch(self._guest.os.arch)
|
||||
@ -1949,9 +1666,8 @@ class vmmCreate(vmmGObjectUI):
|
||||
init = None
|
||||
fs = None
|
||||
template = None
|
||||
distro, variant, valid, ignore1, ignore2 = self._get_config_os_info()
|
||||
|
||||
if not valid:
|
||||
if self._os is None:
|
||||
return self.err.val_err(_("Please specify a valid OS variant."))
|
||||
|
||||
if instmethod == INSTALL_PAGE_ISO:
|
||||
@ -2050,7 +1766,7 @@ class vmmCreate(vmmGObjectUI):
|
||||
try:
|
||||
# Overwrite the guest
|
||||
installer = instclass(self.conn.get_backend())
|
||||
self._guest = self._build_guest(variant or distro)
|
||||
self._guest = self._build_guest(self._os.name)
|
||||
if not self._guest:
|
||||
return False
|
||||
self._guest.installer = installer
|
||||
@ -2114,7 +1830,7 @@ class vmmCreate(vmmGObjectUI):
|
||||
self._capsinfo.arch)
|
||||
|
||||
try:
|
||||
name = self._generate_default_name(distro, variant)
|
||||
name = self._generate_default_name(self._os)
|
||||
self.widget("create-vm-name").set_text(name)
|
||||
self._guest.name = name
|
||||
except Exception as e:
|
||||
@ -2138,11 +1854,10 @@ class vmmCreate(vmmGObjectUI):
|
||||
self, self.conn, path)
|
||||
|
||||
res = None
|
||||
osobj = virtinst.OSDB.lookup_os(variant)
|
||||
if osobj:
|
||||
res = osobj.get_recommended_resources(self._guest)
|
||||
logging.debug("Recommended resources for variant=%s: %s",
|
||||
variant, res)
|
||||
if self._os is not None:
|
||||
res = self._os.get_recommended_resources(self._guest)
|
||||
logging.debug("Recommended resources for os=%s: %s",
|
||||
self._os.label, res)
|
||||
|
||||
# Change the default values suggested to the user.
|
||||
ram_size = DEFAULT_MEM
|
||||
@ -2313,6 +2028,9 @@ class vmmCreate(vmmGObjectUI):
|
||||
if check_install_page and not is_install_page:
|
||||
return
|
||||
if not media:
|
||||
name = self.widget("install-os-name")
|
||||
if not name.get_sensitive():
|
||||
name.set_text(_("Waiting for install media / source"))
|
||||
return
|
||||
if not self._is_os_detect_active():
|
||||
return
|
||||
@ -2357,6 +2075,9 @@ class vmmCreate(vmmGObjectUI):
|
||||
detectThread.setDaemon(True)
|
||||
detectThread.start()
|
||||
|
||||
spin = self.widget("install-detect-os-spinner")
|
||||
spin.start()
|
||||
|
||||
self._report_detect_os_progress(0, thread_results,
|
||||
forward_after_finish)
|
||||
|
||||
@ -2385,15 +2106,10 @@ class vmmCreate(vmmGObjectUI):
|
||||
chance of the detection hanging (like slow URL lookup)
|
||||
"""
|
||||
try:
|
||||
base = _("Detecting")
|
||||
|
||||
if (thread_results.in_progress() and
|
||||
(idx < (DETECT_TIMEOUT * 2))):
|
||||
# Thread is still going and we haven't hit the timeout yet,
|
||||
# so update the UI labels and reschedule this function
|
||||
detect_str = base + ("." * ((idx % 3) + 1))
|
||||
self._set_distro_labels(detect_str, detect_str)
|
||||
|
||||
self.timeout_add(500, self._report_detect_os_progress,
|
||||
idx + 1, thread_results, forward_after_finish)
|
||||
return
|
||||
@ -2403,6 +2119,8 @@ class vmmCreate(vmmGObjectUI):
|
||||
distro = None
|
||||
logging.exception("Error in distro detect timeout")
|
||||
|
||||
spin = self.widget("install-detect-os-spinner")
|
||||
spin.stop()
|
||||
logging.debug("Finished UI OS detection.")
|
||||
|
||||
self.widget("create-forward").set_sensitive(True)
|
||||
|
106
virtManager/oslist.py
Normal file
106
virtManager/oslist.py
Normal file
@ -0,0 +1,106 @@
|
||||
# Copyright (C) 2018 Red Hat, Inc.
|
||||
#
|
||||
# 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
|
||||
|
||||
import virtinst
|
||||
|
||||
from .baseclass import vmmGObjectUI
|
||||
|
||||
|
||||
class vmmOSList(vmmGObjectUI):
|
||||
__gsignals__ = {
|
||||
"os-selected": (vmmGObjectUI.RUN_FIRST, None, [object])
|
||||
}
|
||||
|
||||
def __init__(self):
|
||||
vmmGObjectUI.__init__(self, "oslist.ui", "vmm-oslist")
|
||||
self._cleanup_on_app_close()
|
||||
|
||||
self._filter_name = None
|
||||
self._filter_eol = True
|
||||
|
||||
self.builder.connect_signals({
|
||||
"on_include_eol_toggled": self._eol_toggled,
|
||||
})
|
||||
|
||||
self._init_state()
|
||||
|
||||
def _init_state(self):
|
||||
|
||||
self.topwin.set_modal(False)
|
||||
os_list = self.widget("os-list")
|
||||
|
||||
# (os object, label)
|
||||
os_list_model = Gtk.ListStore(object, str)
|
||||
|
||||
all_os = virtinst.OSDB.list_os()
|
||||
|
||||
for os in all_os:
|
||||
os_list_model.append([os, "%s (%s)" % (os.label, os.name)])
|
||||
|
||||
self._os_list_model = Gtk.TreeModelFilter(child_model=os_list_model)
|
||||
self._os_list_model.set_visible_func(self._filter_os)
|
||||
|
||||
os_list.set_model(self._os_list_model)
|
||||
|
||||
nameCol = Gtk.TreeViewColumn(_("Name"))
|
||||
nameCol.set_spacing(6)
|
||||
|
||||
text = Gtk.CellRendererText()
|
||||
nameCol.pack_start(text, True)
|
||||
nameCol.add_attribute(text, 'text', 1)
|
||||
os_list.append_column(nameCol)
|
||||
|
||||
os_list.connect("row_activated", self._os_selected_cb)
|
||||
|
||||
def _eol_toggled(self, src):
|
||||
self._filter_eol = not src.get_active()
|
||||
self._refilter()
|
||||
|
||||
def _os_selected_cb(self, tree_view, path, column):
|
||||
model, titer = tree_view.get_selection().get_selected()
|
||||
if titer is None:
|
||||
self.emit("os-selected", None)
|
||||
else:
|
||||
self.emit("os-selected", model[titer][0])
|
||||
|
||||
def _filter_os(self, model, titer, ignore1):
|
||||
os = model.get(titer, 0)[0]
|
||||
if self._filter_eol:
|
||||
if os.eol:
|
||||
return False
|
||||
|
||||
if self._filter_name is not None and self._filter_name != "":
|
||||
label = os.label.lower()
|
||||
name = os.name.lower()
|
||||
if (label.find(self._filter_name) == -1 and
|
||||
name.find(self._filter_name) == -1):
|
||||
return False
|
||||
|
||||
return True
|
||||
|
||||
def _refilter(self):
|
||||
os_list = self.widget("os-list")
|
||||
sel = os_list.get_selection()
|
||||
sel.unselect_all()
|
||||
self._os_list_model.refilter()
|
||||
|
||||
def filter_name(self, partial_name):
|
||||
self._filter_name = partial_name.lower()
|
||||
self._refilter()
|
||||
|
||||
def show(self, parent):
|
||||
logging.debug("Showing oslist")
|
||||
self.topwin.set_relative_to(parent)
|
||||
self.topwin.popup()
|
||||
|
||||
def hide(self):
|
||||
self.topwin.popdown()
|
||||
|
||||
def _cleanup(self):
|
||||
pass
|
@ -10,62 +10,22 @@
|
||||
import datetime
|
||||
import logging
|
||||
import re
|
||||
import time
|
||||
|
||||
import gi
|
||||
gi.require_version('Libosinfo', '1.0')
|
||||
from gi.repository import Libosinfo as libosinfo
|
||||
from gi.repository import GLib
|
||||
|
||||
|
||||
###################
|
||||
# Sorting helpers #
|
||||
###################
|
||||
|
||||
def _remove_older_point_releases(distro_list):
|
||||
ret = distro_list[:]
|
||||
|
||||
def _get_minor_version(osobj):
|
||||
return int(osobj.name.rsplit(".", 1)[-1])
|
||||
|
||||
def _find_latest(prefix):
|
||||
"""
|
||||
Given a prefix like 'rhel4', find the latest 'rhel4.X',
|
||||
and remove the rest from the os list
|
||||
"""
|
||||
latest_os = None
|
||||
first_id = None
|
||||
for osobj in ret[:]:
|
||||
if not re.match("%s\.\d+" % prefix, osobj.name):
|
||||
continue
|
||||
|
||||
if first_id is None:
|
||||
first_id = ret.index(osobj)
|
||||
ret.remove(osobj)
|
||||
|
||||
if (latest_os and
|
||||
_get_minor_version(latest_os) > _get_minor_version(osobj)):
|
||||
continue
|
||||
latest_os = osobj
|
||||
|
||||
if latest_os:
|
||||
ret.insert(first_id, latest_os)
|
||||
|
||||
_find_latest("rhel4")
|
||||
_find_latest("rhel5")
|
||||
_find_latest("rhel6")
|
||||
_find_latest("rhel7")
|
||||
_find_latest("freebsd9")
|
||||
_find_latest("freebsd10")
|
||||
_find_latest("freebsd11")
|
||||
_find_latest("centos6")
|
||||
_find_latest("centos7")
|
||||
return ret
|
||||
|
||||
|
||||
def _sort(tosort, sortpref=None, limit_point_releases=False):
|
||||
def _sort(tosort):
|
||||
sortby_mappings = {}
|
||||
distro_mappings = {}
|
||||
retlist = []
|
||||
sortpref = sortpref or []
|
||||
|
||||
for key, osinfo in tosort.items():
|
||||
# Libosinfo has some duplicate version numbers here, so append .1
|
||||
@ -90,15 +50,8 @@ def _sort(tosort, sortpref=None, limit_point_releases=False):
|
||||
distro_list.sort()
|
||||
distro_list.reverse()
|
||||
|
||||
# Move the sortpref values to the front of the list
|
||||
sorted_distro_list = list(distro_mappings.keys())
|
||||
sorted_distro_list.sort()
|
||||
sortpref.reverse()
|
||||
for prefer in sortpref:
|
||||
if prefer not in sorted_distro_list:
|
||||
continue
|
||||
sorted_distro_list.remove(prefer)
|
||||
sorted_distro_list.insert(0, prefer)
|
||||
|
||||
# Build the final list of sorted os objects
|
||||
for distro in sorted_distro_list:
|
||||
@ -107,10 +60,6 @@ def _sort(tosort, sortpref=None, limit_point_releases=False):
|
||||
orig_key = sortby_mappings[key]
|
||||
retlist.append(tosort[orig_key])
|
||||
|
||||
# Filter out older point releases
|
||||
if limit_point_releases:
|
||||
retlist = _remove_older_point_releases(retlist)
|
||||
|
||||
return retlist
|
||||
|
||||
|
||||
@ -236,25 +185,16 @@ class _OSDB(object):
|
||||
"solaris", "other", "generic"]
|
||||
return approved_types
|
||||
|
||||
def list_os(self, typename=None, only_supported=False, sortpref=None):
|
||||
def list_os(self):
|
||||
"""
|
||||
List all OSes in the DB
|
||||
|
||||
:param typename: Only list OSes of this type
|
||||
:param only_supported: Only list OSses where self.supported == True
|
||||
:param sortpref: Sort these OSes at the front of the list
|
||||
"""
|
||||
sortmap = {}
|
||||
|
||||
for name, osobj in self._all_variants.items():
|
||||
if typename and typename != osobj.get_typename():
|
||||
continue
|
||||
if only_supported and not osobj.get_supported():
|
||||
continue
|
||||
sortmap[name] = osobj
|
||||
|
||||
return _sort(sortmap, sortpref=sortpref,
|
||||
limit_point_releases=only_supported)
|
||||
return _sort(sortmap)
|
||||
|
||||
def latest_regex(self, regex):
|
||||
"""
|
||||
@ -282,6 +222,24 @@ class _OsVariant(object):
|
||||
self.label = self._os and self._os.get_name() or "Generic"
|
||||
self.codename = self._os and self._os.get_codename() or ""
|
||||
self.distro = self._os and self._os.get_distro() or ""
|
||||
self.eol = False
|
||||
|
||||
eol = self._os and self._os.get_eol_date() or None
|
||||
rel = self._os and self._os.get_release_date() or None
|
||||
|
||||
# End of life if an EOL date is present and has past,
|
||||
# or if the release date is present and was 5 years or more
|
||||
if eol is not None:
|
||||
now = GLib.Date()
|
||||
now.set_time_t(time.time())
|
||||
if eol.compare(now) < 0:
|
||||
self.eol = True
|
||||
elif rel is not None:
|
||||
then = GLib.Date()
|
||||
then.set_time_t(time.time())
|
||||
then.subtract_years(5)
|
||||
if rel.compare(then) < 0:
|
||||
self.eol = True
|
||||
|
||||
self.sortby = self._get_sortby()
|
||||
self.urldistro = self._get_urldistro()
|
||||
|
Loading…
Reference in New Issue
Block a user