[gnome-boxes/tell-us-what-os-this-is] assistant: Let users pick the OS from a list if it is unknown
- From: Felipe Borges <felipeborges src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnome-boxes/tell-us-what-os-this-is] assistant: Let users pick the OS from a list if it is unknown
- Date: Fri, 31 Jul 2020 14:48:43 +0000 (UTC)
commit 856362b3bd7cfb28506819a96a2c8242b3d1d7e8
Author: Felipe Borges <felipeborges gnome org>
Date: Fri Jun 26 12:57:50 2020 +0200
assistant: Let users pick the OS from a list if it is unknown
When we fail to detect an operating system with libosinfo, we often
go with our default settings. Those work for the majority of OSes
but not for all. By allowing users to enter which operating system
they intend to install, we can cover many more installations by
offering better support for unrecognized medias.
data/ui/assistant/pages/preparation-page.ui | 218 ++++++++++++++++++++--------
src/assistant/preparation-page.vala | 89 +++++++++++-
src/media-manager.vala | 5 +-
src/os-database.vala | 27 +++-
4 files changed, 274 insertions(+), 65 deletions(-)
---
diff --git a/data/ui/assistant/pages/preparation-page.ui b/data/ui/assistant/pages/preparation-page.ui
index 9ddec630..70a497be 100644
--- a/data/ui/assistant/pages/preparation-page.ui
+++ b/data/ui/assistant/pages/preparation-page.ui
@@ -5,78 +5,178 @@
<property name="title" translatable="yes">Preparing…</property>
<child>
- <object class="GtkGrid">
+ <object class="GtkStack" id="stack">
<property name="visible">True</property>
- <property name="expand">True</property>
- <property name="halign">center</property>
- <property name="valign">center</property>
- <property name="column-spacing">10</property>
<child>
- <object class="GtkLabel">
+ <object class="GtkGrid">
<property name="visible">True</property>
- <property name="wrap">True</property>
- <property name="halign">start</property>
- <property name="label" translatable="yes">Preparing to create a new box</property>
- <property name="margin-bottom">20</property>
- </object>
- <packing>
- <property name="left-attach">0</property>
- <property name="top-attach">0</property>
- <property name="width">2</property>
- </packing>
- </child>
+ <property name="expand">True</property>
+ <property name="halign">center</property>
+ <property name="valign">center</property>
+ <property name="column-spacing">10</property>
- <child>
- <object class="GtkImage" id="installer_image">
- <property name="visible">True</property>
- <property name="icon-size">0</property>
- <property name="pixel-size">128</property>
- <property name="icon-name">media-optical</property>
- </object>
- <packing>
- <property name="left-attach">0</property>
- <property name="top-attach">1</property>
- <property name="height">3</property>
- </packing>
- </child>
+ <child>
+ <object class="GtkLabel">
+ <property name="visible">True</property>
+ <property name="wrap">True</property>
+ <property name="halign">start</property>
+ <property name="label" translatable="yes">Preparing to create a new box</property>
+ <property name="margin-bottom">20</property>
+ </object>
+ <packing>
+ <property name="left-attach">0</property>
+ <property name="top-attach">0</property>
+ <property name="width">2</property>
+ </packing>
+ </child>
- <child>
- <object class="GtkLabel" id="media_label">
- <property name="visible">True</property>
- <property name="halign">start</property>
- <property name="valign">end</property>
- <style>
- <class name="boxes-wizard-media-os-label"/>
- </style>
- </object>
- <packing>
- <property name="left-attach">1</property>
- <property name="top-attach">1</property>
- </packing>
- </child>
+ <child>
+ <object class="GtkImage" id="installer_image">
+ <property name="visible">True</property>
+ <property name="icon-size">0</property>
+ <property name="pixel-size">128</property>
+ <property name="icon-name">media-optical</property>
+ </object>
+ <packing>
+ <property name="left-attach">0</property>
+ <property name="top-attach">1</property>
+ <property name="height">3</property>
+ </packing>
+ </child>
- <child>
- <object class="GtkLabel" id="status_label">
- <property name="visible">True</property>
- <property name="halign">start</property>
- <property name="valign">center</property>
+ <child>
+ <object class="GtkLabel" id="media_label">
+ <property name="visible">True</property>
+ <property name="halign">start</property>
+ <property name="valign">end</property>
+ <style>
+ <class name="boxes-wizard-media-os-label"/>
+ </style>
+ </object>
+ <packing>
+ <property name="left-attach">1</property>
+ <property name="top-attach">1</property>
+ </packing>
+ </child>
+
+ <child>
+ <object class="GtkLabel" id="status_label">
+ <property name="visible">True</property>
+ <property name="halign">start</property>
+ <property name="valign">center</property>
+ </object>
+ <packing>
+ <property name="left-attach">1</property>
+ <property name="top-attach">2</property>
+ </packing>
+ </child>
+
+ <child>
+ <object class="GtkProgressBar" id="progress_bar">
+ <property name="visible">True</property>
+ <property name="valign">start</property>
+ </object>
+ <packing>
+ <property name="left-attach">1</property>
+ <property name="top-attach">3</property>
+ </packing>
+ </child>
</object>
- <packing>
- <property name="left-attach">1</property>
- <property name="top-attach">2</property>
- </packing>
</child>
<child>
- <object class="GtkProgressBar" id="progress_bar">
+ <object class="GtkBox" id="unknown_os_view">
<property name="visible">True</property>
- <property name="valign">start</property>
+ <property name="orientation">vertical</property>
+ <property name="margin">30</property>
+ <property name="spacing">20</property>
+
+ <child>
+ <object class="GtkLabel">
+ <property name="visible">True</property>
+ <property name="wrap">True</property>
+ <property name="xalign">0</property>
+ <property name="halign">start</property>
+ <property name="max-width-chars">80</property>
+ <property name="label" translatable="yes">Boxes couldn't detect the operating system of this
file. Please, search below for the operating system you intend to install.</property>
+ </object>
+ </child>
+
+ <child>
+ <object class="GtkInfoBar">
+ <property name="visible">True</property>
+ <property name="halign">fill</property>
+ <property name="spacing">0</property>
+ <property name="message-type">warning</property>
+
+ <child internal-child="content_area">
+ <object class="GtkContainer">
+ <property name="visible">True</property>
+
+ <child>
+ <object class="GtkImage">
+ <property name="visible">True</property>
+ <property name="icon-name">dialog-information-symbolic</property>
+ <property name="icon-size">3</property>
+ <property name="pixel-size">48</property>
+ </object>
+ </child>
+
+ <child>
+ <object class="GtkLabel">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Can't find the operating system you are
looking for? Click the <b>Next</b> button and let Boxes pick the default settings for
you.</property>
+ <property name="wrap">True</property>
+ <property name="xalign">0</property>
+ <property name="max-width-chars">70</property>
+ <property name="halign">start</property>
+ <property name="hexpand">True</property>
+ <property name="use-markup">True</property>
+ </object>
+ </child>
+ </object>
+ </child>
+ </object>
+
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <object class="GtkBox">
+ <property name="visible">True</property>
+ <property name="orientation">vertical</property>
+
+ <child>
+ <object class="GtkSearchEntry" id="os_id_entry">
+ <property name="visible">True</property>
+ <property name="placeholder-text" translatable="yes">Search for an OS name</property>
+ <signal name="changed" handler="on_os_id_entry_changed"/>
+ </object>
+ </child>
+
+ <child>
+ <object class="GtkScrolledWindow">
+ <property name="visible">True</property>
+ <property name="vexpand">True</property>
+ <style>
+ <class name="frame"/>
+ </style>
+
+ <child>
+ <object class="GtkListBox" id="listbox">
+ <property name="visible">True</property>
+ </object>
+ </child>
+ </object>
+ </child>
+ </object>
+ </child>
+
</object>
- <packing>
- <property name="left-attach">1</property>
- <property name="top-attach">3</property>
- </packing>
</child>
</object>
</child>
diff --git a/src/assistant/preparation-page.vala b/src/assistant/preparation-page.vala
index 2579284a..f9f15b9e 100644
--- a/src/assistant/preparation-page.vala
+++ b/src/assistant/preparation-page.vala
@@ -2,6 +2,15 @@
[GtkTemplate (ui = "/org/gnome/Boxes/ui/assistant/pages/preparation-page.ui")]
private class Boxes.AssistantPreparationPage : AssistantPage {
+ [GtkChild]
+ private Gtk.Stack stack;
+ [GtkChild]
+ private Gtk.Box unknown_os_view;
+ [GtkChild]
+ private Gtk.Entry os_id_entry;
+ [GtkChild]
+ private Gtk.ListBox listbox;
+
[GtkChild]
private Gtk.Label media_label;
[GtkChild]
@@ -26,20 +35,87 @@
}
}
- public void setup (InstallerMedia media) {
+ public void setup (InstallerMedia media, Osinfo.Os? os = null) {
try {
var media_manager = MediaManager.get_instance ();
- media = media_manager.create_installer_media_from_media (media);
+ this.media = media_manager.create_installer_media_from_media (media, os);
+
} catch (GLib.Error error) {
warning ("Failed to setup installation media '%s': %s", media.device_file, error.message);
}
- prepare.begin (media);
+ if (media.os == null) {
+ stack.visible_child = unknown_os_view;
+ setup_pick_os_view.begin ();
+ } else {
+ prepare.begin (media);
+ }
+ }
- skip = true;
+ public async override void next () {
+ var media_manager = MediaManager.get_instance ();
+ var row = listbox.get_selected_row ();
+ if (row == null) {
+ prepare.begin (media);
+
+ return;
+ }
+
+ var item = row.get_child () as SearchResult;
+ try {
+ var os = yield media_manager.os_db.get_os_by_id (item.os.id);
+
+ setup (media, os);
+ } catch (GLib.Error error) {
+ warning ("OS not found! %s", error.message);
+ }
+ }
+
+ private async void setup_pick_os_view () {
+ var os_db = MediaManager.get_instance ().os_db;
+ var model = yield os_db.get_all_oses_sorted_by_release_date ();
+
+ listbox.set_filter_func (model_filter);
+ listbox.bind_model (model, create_listbox_entries);
+
+ os_id_entry.grab_focus ();
+ }
+
+ private Gtk.Widget create_listbox_entries (Object item) {
+ var os_item = item as Osinfo.Os;
+
+ var os_name = os_item.get_name ();
+ if (os_name != null)
+ os_name.replace ("Unknown", "");
+
+ return new SearchResult () {
+ os = os_item,
+ label = os_name,
+ visible = (os_name != null),
+ margin = 5,
+ halign = Gtk.Align.START,
+ xalign = 0
+ };
+ }
+
+ private bool model_filter (Gtk.ListBoxRow row) {
+ if (row == null)
+ return false;
+
+ var os = row.get_child () as SearchResult;
+ if (os == null)
+ return false;
+
+ return (os.get_text ().down ().contains (os_id_entry.get_text ().down ()));
+ }
+
+ [GtkCallback]
+ private void on_os_id_entry_changed () {
+ listbox.invalidate_filter ();
}
public async void prepare (InstallerMedia media) {
+ skip = true;
var progress = create_preparation_progress ();
if (!yield media.prepare (progress, cancellable)) // add cancellable
return;
@@ -65,5 +141,10 @@ private ActivityProgress create_preparation_progress () {
public override void cleanup () {
cancellable.reset ();
+ os_id_entry.set_text ("");
}
}
+
+class SearchResult : Gtk.Label {
+ public Osinfo.Os os;
+}
diff --git a/src/media-manager.vala b/src/media-manager.vala
index fee4b4c3..79b198c3 100644
--- a/src/media-manager.vala
+++ b/src/media-manager.vala
@@ -206,7 +206,10 @@ private static InstallerMedia create_unattended_installer (InstallerMedia media)
return install_media;
}
- public InstallerMedia create_installer_media_from_media (InstallerMedia media) throws GLib.Error {
+ public InstallerMedia create_installer_media_from_media (InstallerMedia media, Os? os = null) throws
GLib.Error {
+ if (os != null)
+ media.os = os;
+
if (media.os == null)
return media;
diff --git a/src/os-database.vala b/src/os-database.vala
index 41fd8e70..3ec1f072 100644
--- a/src/os-database.vala
+++ b/src/os-database.vala
@@ -26,7 +26,7 @@
// dependent on the OS/guest.
private const int64 DEFAULT_STORAGE = 20 * (int64) GIBIBYTES;
- private Db? db;
+ public Db? db;
private bool db_loading;
@@ -101,6 +101,31 @@ public async Os get_os_by_id (string id) throws OSDatabaseError {
return os;
}
+ public async GLib.ListModel get_all_oses_sorted_by_release_date () {
+ if (!yield ensure_db_loaded ())
+ throw new OSDatabaseError.DB_LOADING_FAILED ("Failed to load OS database");
+
+ var os_list = db.get_os_list ().get_elements ();
+ os_list.sort ((os_a, os_b) => {
+ var release_a = (os_a as Os).get_release_date ();
+ var release_b = (os_b as Os).get_release_date ();
+
+ if (release_a == null)
+ return -1;
+ else if (release_b == null)
+ return 1;
+
+ return release_b.compare (release_a);
+ });
+
+ var model = new GLib.ListStore (typeof (Osinfo.Os));
+ foreach (var os in os_list) {
+ model.append (os as Os);
+ }
+
+ return model;
+ }
+
public async GLib.List<Osinfo.Media> list_downloadable_oses () throws OSDatabaseError {
if (!yield ensure_db_loaded ())
throw new OSDatabaseError.DB_LOADING_FAILED ("Failed to load OS database");
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]