[gnome-boxes] wizard: Offer multiple OSes for download



commit fab8839ecd6626c45ef5b42cad97891447c90aa8
Author: Felipe Borges <felipeborges gnome org>
Date:   Mon Nov 20 12:44:41 2017 +0100

    wizard: Offer multiple OSes for download
    
    Osinfo can provide URLs to download various free operating systems.
    
    These changes exposes new operating systems which are available
    for download directly from the new machine wizard.
    
    https://bugzilla.gnome.org/show_bug.cgi?id=790614

 data/gnome-boxes.gresource.xml       |    1 +
 data/ui/wizard-downloadable-entry.ui |   94 ++++++++++++++++++++++++++++++++++
 data/ui/wizard-source.ui             |   11 +++-
 src/os-database.vala                 |   42 +++++++++++++++
 src/wizard-source.vala               |   90 ++++++++++++++++++++++++++++++++
 5 files changed, 236 insertions(+), 2 deletions(-)
---
diff --git a/data/gnome-boxes.gresource.xml b/data/gnome-boxes.gresource.xml
index 40eaba1..12c462b 100644
--- a/data/gnome-boxes.gresource.xml
+++ b/data/gnome-boxes.gresource.xml
@@ -31,6 +31,7 @@
     <file preprocess="xml-stripblanks">ui/troubleshoot-log.ui</file>
     <file preprocess="xml-stripblanks">ui/unattended-setup-box.ui</file>
     <file preprocess="xml-stripblanks">ui/wizard.ui</file>
+    <file preprocess="xml-stripblanks">ui/wizard-downloadable-entry.ui</file>
     <file preprocess="xml-stripblanks">ui/wizard-media-entry.ui</file>
     <file preprocess="xml-stripblanks">ui/wizard-scrolled.ui</file>
     <file preprocess="xml-stripblanks">ui/wizard-source.ui</file>
diff --git a/data/ui/wizard-downloadable-entry.ui b/data/ui/wizard-downloadable-entry.ui
new file mode 100644
index 0000000..6c24290
--- /dev/null
+++ b/data/ui/wizard-downloadable-entry.ui
@@ -0,0 +1,94 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<interface>
+  <!-- interface-requires gtk+ 3.9 -->
+  <template class="BoxesWizardDownloadableEntry" parent="GtkListBoxRow">
+    <property name="visible">True</property>
+    <style>
+      <class name="boxes-menu-row"/>
+    </style>
+
+    <child>
+      <object class="GtkBox">
+        <property name="visible">True</property>
+        <property name="orientation">vertical</property>
+
+        <child>
+          <object class="GtkBox" id="hbox">
+            <property name="visible">True</property>
+            <property name="margin-start">15</property>
+            <property name="margin-end">15</property>
+            <property name="spacing">20</property>
+            <property name="orientation">horizontal</property>
+            <child>
+              <object class="GtkImage" id="media_image">
+                <property name="visible">True</property>
+                <property name="icon-name">media-optical</property>
+                <property name="icon-size">0</property>
+                <property name="pixel-size">64</property>
+              </object>
+              <packing>
+                <property name="expand">False</property>
+                <property name="fill">False</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkBox" id="vbox">
+                <property name="visible">True</property>
+                <property name="homogeneous">True</property>
+                <property name="spacing">0</property>
+                <property name="orientation">vertical</property>
+                <child>
+                  <object class="GtkLabel" id="title_label">
+                    <property name="visible">True</property>
+                    <property name="ellipsize">end</property>
+                    <property name="halign">start</property>
+                    <property name="valign">end</property>
+                  </object>
+                  <packing>
+                    <property name="expand">True</property>
+                    <property name="fill">True</property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkLabel" id="details_label">
+                    <property name="visible">True</property>
+                    <property name="ellipsize">end</property>
+                    <property name="halign">start</property>
+                    <property name="valign">start</property>
+                    <property name="label" translatable="yes">Unknown media</property>
+                    <style>
+                      <class name="boxes-step-label"/>
+                      <class name="dim-label"/>
+                    </style>
+                  </object>
+                  <packing>
+                    <property name="expand">True</property>
+                    <property name="fill">True</property>
+                  </packing>
+                </child>
+              </object>
+              <packing>
+                <property name="expand">True</property>
+                <property name="fill">True</property>
+              </packing>
+            </child>
+          </object>
+        </child>
+
+        <child>
+          <object class="GtkRevealer" id="revealer">
+            <property name="visible">True</property>
+            <property name="can-focus">False</property>
+            <child>
+              <object class="GtkListBox" id="medias_listbox">
+                <property name="visible">True</property>
+                <signal name="row-activated" handler="on_media_listbox_activated"/>
+              </object>
+            </child>
+          </object>
+        </child>
+
+      </object>
+    </child>
+  </template>
+</interface>
diff --git a/data/ui/wizard-source.ui b/data/ui/wizard-source.ui
index 37e2db0..eb23287 100644
--- a/data/ui/wizard-source.ui
+++ b/data/ui/wizard-source.ui
@@ -195,6 +195,12 @@
         </child>
 
         <child>
+          <object class="GtkListBox" id="available_downloads_listbox">
+            <property name="visible">True</property>
+          </object>
+         </child>
+
+        <child>
           <object class="GtkButton" id="enter_url_button">
             <property name="visible">True</property>
             <signal name="clicked" handler="on_enter_url_button_clicked"/>
@@ -298,13 +304,14 @@
         </child>
       </object>
 
+    </child>
+  </object>
+
       <packing>
         <property name="name">main-page</property>
       </packing>
     </child>
 
-  </object>
-</child>
 
     <!-- RHEL web view page -->
     <child>
diff --git a/src/os-database.vala b/src/os-database.vala
index 461c063..f4914aa 100644
--- a/src/os-database.vala
+++ b/src/os-database.vala
@@ -101,6 +101,48 @@ private class Boxes.OSDatabase : GLib.Object {
         return os;
     }
 
+    public async HashTable<string,Os> list_latest_downloadable_oses () throws OSDatabaseError {
+        if (!yield ensure_db_loaded ())
+            throw new OSDatabaseError.DB_LOADING_FAILED ("Failed to load OS database");
+
+        var os_list = db.get_os_list ();
+        var table = new HashTable<string,Os> (str_hash, str_equal);
+        foreach (var entity in os_list.get_elements ()) {
+            var os = entity as Os;
+
+            var has_url = false;
+            foreach (var media_entity in os.get_media_list ().get_elements ()) {
+                var media = media_entity as Media;
+
+                has_url = (media.url != null);
+            }
+
+            if (!has_url)
+                continue;
+
+            if (os.get_media_list ().get_length () == 0)
+                continue;
+
+            string os_distro = os.get_distro();
+            var distro = table.lookup (os_distro);
+            if (distro == null) {
+                table.insert (os_distro, os);
+                continue;
+            }
+
+            var release_a = os.get_release_date ();
+            var release_b = distro.get_release_date ();
+
+            if ((release_a == null) || (release_b == null))
+                continue;
+
+            if (release_a.compare (release_b) > 0)
+                table.replace (os_distro, os);
+        }
+
+        return table;
+    }
+
     // Returned list is in ascending order by release dates. If release date is
     // unavailable and OS is
     // a. released, we assume that it is older than other OSes and @after.
diff --git a/src/wizard-source.vala b/src/wizard-source.vala
index c88422d..20e0adb 100644
--- a/src/wizard-source.vala
+++ b/src/wizard-source.vala
@@ -57,6 +57,62 @@ private class Boxes.WizardScrolled : Gtk.ScrolledWindow {
     }
 }
 
+private class Boxes.WizardDownloadableMediaEntry : Gtk.ListBoxRow {
+    public Osinfo.Media media;
+
+    public WizardDownloadableMediaEntry (Osinfo.Media media) {
+        this.media = media;
+
+        var file = GLib.File.new_for_uri (media.url);
+        var label = new Gtk.Label (file.get_basename ());
+        label.halign = Gtk.Align.START;
+
+        add (label);
+    }
+}
+
+[GtkTemplate (ui = "/org/gnome/Boxes/ui/wizard-downloadable-entry.ui")]
+private class Boxes.WizardDownloadableEntry : Gtk.ListBoxRow {
+    [GtkChild]
+    private Gtk.Image media_image;
+    [GtkChild]
+    private Gtk.Label title_label;
+    [GtkChild]
+    private Gtk.Label details_label;
+    [GtkChild]
+    private Gtk.Revealer revealer;
+    [GtkChild]
+    private Gtk.ListBox medias_listbox;
+
+    public signal void activated (Osinfo.Media media);
+
+    public WizardDownloadableEntry (Osinfo.Os os) {
+        Downloader.fetch_os_logo.begin (media_image, os, 64);
+
+        title_label.label = os.name;
+        details_label.label = os.vendor;
+
+        foreach (var media_entity in os.get_media_list ().get_elements()) {
+            var media = (media_entity as Osinfo.Media);
+
+            medias_listbox.insert (new WizardDownloadableMediaEntry (media), -1);
+        }
+
+        medias_listbox.show_all ();
+    }
+
+    [GtkCallback]
+    private void on_media_listbox_activated (Gtk.ListBoxRow row) {
+        var entry = row as WizardDownloadableMediaEntry;
+
+        activated (entry.media);
+    }
+
+    public void toggle () {
+        revealer.set_reveal_child (!revealer.child_revealed);
+    }
+}
+
 [GtkTemplate (ui = "/org/gnome/Boxes/ui/wizard-media-entry.ui")]
 private class Boxes.WizardMediaEntry : Gtk.ListBoxRow {
     public InstallerMedia media;
@@ -229,6 +285,8 @@ private class Boxes.WizardSource: Gtk.Stack {
     [GtkChild]
     private Gtk.Label libvirt_sys_import_label;
     [GtkChild]
+    private Gtk.ListBox available_downloads_listbox;
+    [GtkChild]
     private Gtk.Button install_rhel_button;
     [GtkChild]
     private Gtk.Image install_rhel_image;
@@ -341,6 +399,38 @@ private class Boxes.WizardSource: Gtk.Stack {
 
         var os_db = media_manager.os_db;
 
+        var available_downloads_model = new GLib.ListStore (typeof (Osinfo.Os));
+        available_downloads_listbox.bind_model (available_downloads_model, (obj) => {
+            var os = obj as Osinfo.Os;
+
+            var entry = new WizardDownloadableEntry (os);
+            entry.activated.connect ((media) => {
+                this.uri = media.url;
+
+                activated ();
+            });
+
+            return entry;
+        });
+
+        available_downloads_listbox.row_activated.connect ((row) => {
+            var entry = (row as WizardDownloadableEntry);
+
+            entry.toggle();
+
+            selected = entry;
+        });
+
+        os_db.list_latest_downloadable_oses.begin ((db, result) => {
+            try {
+                var table = os_db.list_latest_downloadable_oses.end (result);
+
+                table.get_values ().foreach (available_downloads_model.append);
+            } catch (OSDatabaseError error) {
+                debug ("Failed to populate the list of downloadable OSes: %s", error.message);
+            }
+        });
+
         os_db.get_all_media_urls_as_store.begin ((db, result) => {
             try {
                 media_urls_store = os_db.get_all_media_urls_as_store.end (result);


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]