[gnome-boxes] wizard: Present bootable ISO files on 'Source' page



commit 02538bd54c89f7302bb7d762d0cb5eed3e293996
Author: Zeeshan Ali (Khattak) <zeeshanak gnome org>
Date:   Fri Feb 10 03:08:15 2012 +0200

    wizard: Present bootable ISO files on 'Source' page
    
    Since for each addition/deletion Tracker, you get an integer ID from
    Tracker against which you use a Sparql query to check what Tracker is
    talking about, the code to handle the these signals will be inefficient
    and unnecessarily complicated. So instead of keeping a list of medias (HW
    and ISO images), we now:
    
    1. Asynchronously fetch list of medias on startup and create the widgets
    for them in the wizard.
    
    2. When the 'Source' page of wizard is activated/shown, we refetch the
    list (again asynchronously) and add/remove widgets accordingly.
    
    https://bugzilla.gnome.org/show_bug.cgi?id=666373

 configure.ac             |    2 +
 src/Makefile.am          |    1 +
 src/installer-media.vala |   13 ++++
 src/media-manager.vala   |  143 +++++++++++++++++++++++++++-------------------
 src/wizard-source.vala   |   66 +++++++++++++--------
 5 files changed, 142 insertions(+), 83 deletions(-)
---
diff --git a/configure.ac b/configure.ac
index 77ba0ac..0b124bf 100644
--- a/configure.ac
+++ b/configure.ac
@@ -51,6 +51,7 @@ LIBXML2_MIN_VERSION=2.7.8
 SPICE_GTK_MIN_VERSION=0.9
 GUDEV_MIN_VERSION=147
 OSINFO_MIN_VERSION=0.0.6
+TRACKER_SPARQL=0.13.0
 
 PKG_CHECK_MODULES(BOXES, [
   clutter-gtk-1.0 >= $CLUTTER_GTK_MIN_VERSION
@@ -64,6 +65,7 @@ PKG_CHECK_MODULES(BOXES, [
   spice-client-gtk-3.0 >= $SPICE_GTK_MIN_VERSION
   gudev-1.0 >= $GUDEV_MIN_VERSION
   libosinfo-1.0 >= $OSINFO_MIN_VERSION
+  tracker-sparql-0.14 >= $TRACKER_SPARQL
 ])
 
 
diff --git a/src/Makefile.am b/src/Makefile.am
index a952370..9b7d686 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -26,6 +26,7 @@ AM_VALAFLAGS =						\
 	--pkg libxml-2.0				\
 	--pkg posix					\
 	--pkg spice-client-gtk-3.0			\
+	--pkg tracker-sparql-0.14			\
 	$(NULL)
 
 bin_PROGRAMS = gnome-boxes
diff --git a/src/installer-media.vala b/src/installer-media.vala
index 5415a02..24f341c 100644
--- a/src/installer-media.vala
+++ b/src/installer-media.vala
@@ -14,6 +14,19 @@ private class Boxes.InstallerMedia : Object {
 
     public bool live { get { return os_media == null || os_media.live; } }
 
+    public InstallerMedia.from_iso_info (string            path,
+                                         string            label,
+                                         Os                os,
+                                         Media             media,
+                                         Osinfo.Resources? resources) {
+        this.device_file = path;
+        this.label = label;
+        this.os = os;
+        this.os_media = media;
+        this.resources = resources;
+        from_image = true;
+    }
+
     public static async InstallerMedia create_for_path (string       path,
                                                         MediaManager media_manager,
                                                         Cancellable? cancellable) throws GLib.Error {
diff --git a/src/media-manager.vala b/src/media-manager.vala
index f2c024a..664f45f 100644
--- a/src/media-manager.vala
+++ b/src/media-manager.vala
@@ -2,16 +2,16 @@
 
 using Osinfo;
 using GUdev;
+using Tracker;
 
 private class Boxes.MediaManager : Object {
+    private const string SPARQL_QUERY = "SELECT nie:url(?iso) nie:title(?iso) osinfo:id(?iso) osinfo:mediaId(?iso)" +
+                                        " { ?iso nfo:isBootable true }";
+
     public OSDatabase os_db { get; private set; }
     public Client client { get; private set; }
-    public GLib.List<InstallerMedia> medias { owned get { return media_hash.get_values (); } }
-
-    public signal void media_available (InstallerMedia media);
-    public signal void media_unavailable (InstallerMedia media);
 
-    private HashTable<string,InstallerMedia> media_hash;
+    private Sparql.Connection connection;
 
     public MediaManager () {
         client = new GUdev.Client ({"block"});
@@ -20,84 +20,109 @@ private class Boxes.MediaManager : Object {
         } catch (GLib.Error error) {
             critical ("Error fetching default OS database: %s", error.message);
         }
-        media_hash = new HashTable<string, InstallerMedia> (str_hash, str_equal);
-        fetch_installer_medias.begin ();
-
-        client.uevent.connect (on_udev_event);
+        try {
+            connection = Sparql.Connection.get ();
+        } catch (GLib.Error error) {
+            critical ("Error connecting to Tracker: %s", error.message);
+        }
     }
 
     public async InstallerMedia create_installer_media_for_path (string       path,
                                                                  Cancellable? cancellable) throws GLib.Error {
         var media = yield InstallerMedia.create_for_path (path, this, cancellable);
 
-        if (media.os == null)
-            return media;
-
-        switch (media.os.short_id) {
-        case "fedora14":
-        case "fedora15":
-        case "fedora16":
-            media = new FedoraInstaller.copy (media);
+        return create_installer_media_from_media (media);
+    }
 
-            break;
+    public async GLib.List<InstallerMedia> list_installer_medias () {
+        var list = new GLib.List<InstallerMedia> ();
 
-        case "win7":
-        case "win2k8":
-            media = new Win7Installer.copy (media);
+        // First HW media
+        var enumerator = new GUdev.Enumerator (client);
+        enumerator.add_match_property ("OSINFO_BOOTABLE", "1");
 
-            break;
+        foreach (var device in enumerator.execute ()) {
+            if (device.get_property ("DEVTYPE") != "disk")
+                // We don't want to deal with partitions to avoid duplicate medias
+                continue;
 
-        case "winxp":
-        case "win2k":
-        case "win2k3":
-            media = new WinXPInstaller.copy (media);
+            var path = device.get_device_file ();
+            try {
+                var media = yield create_installer_media_for_path (path, null);
 
-            break;
+                list.append (media);
+            } catch (GLib.Error error) {
+                warning ("Failed to get information on device '%s': %s. Ignoring..", path, error.message);
+            }
+        }
 
-        default:
-            return media;
+        // Now ISO files
+        try {
+            var cursor = yield connection.query_async (SPARQL_QUERY);
+            while (yield cursor.next_async ()) {
+                var file = File.new_for_uri (cursor.get_string (0));
+                var path = file.get_path ();
+                if (path == null)
+                    continue; // FIXME: Support non-local files as well
+                var title = cursor.get_string (1);
+                var os_id = cursor.get_string (2);
+                var media_id = cursor.get_string (3);
+
+                try {
+                    var media = yield create_installer_media_from_iso_info (path, title, os_id, media_id);
+
+                    list.insert_sorted (media, compare_media);
+                } catch (Error error) {
+                    warning ("Failed to use ISO '%s': %s", path, error.message);
+                }
+            }
+        } catch (GLib.Error error) {
+            warning ("Failed to fetch list of ISOs from Tracker: %s.", error.message);
         }
 
-        return media;
+        return list;
     }
 
-    private async void fetch_installer_medias () {
-        var enumerator = new GUdev.Enumerator (client);
-        enumerator.add_match_property ("OSINFO_BOOTABLE", "1");
-
-        foreach (var device in enumerator.execute ())
-            yield add_device (device);
+    private static int compare_media (InstallerMedia media_a, InstallerMedia media_b) {
+        return strcmp (media_b.label, media_a.label);
     }
 
-    private void on_udev_event (Client client, string action, GUdev.Device device) {
-        var name = device.get_name ();
-        debug ("udev action '%s' for device '%s'", action, name);
+    private async InstallerMedia create_installer_media_from_iso_info (string  path,
+                                                                       string? label,
+                                                                       string? os_id,
+                                                                       string? media_id) throws GLib.Error {
+        if (label == null || os_id == null || media_id == null)
+            return yield create_installer_media_for_path (path, null);
 
-        if (action == "remove" || action == "change") {
-            var media = media_hash.lookup (name);
-            if (media != null) {
-                media_hash.remove (name);
-                media_unavailable (media);
-            }
-        }
+        var os = os_db.get_os_by_id (os_id);
+        var os_media = os_db.get_media_by_id (os, media_id);
+        var resources = os_db.get_resources_for_os (os, os_media.architecture);
+        var media = new InstallerMedia.from_iso_info (path, label, os, os_media, resources);
 
-        if (action == "add" || action == "change" && device.get_property_as_boolean ("OSINFO_BOOTABLE"))
-            add_device.begin (device);
+        return create_installer_media_from_media (media);
     }
 
-    private async void add_device (GUdev.Device device) {
-        if (device.get_property ("DEVTYPE") != "disk")
-            // We don't want to deal with partitions to avoid duplicate medias
-            return;
+    private InstallerMedia create_installer_media_from_media (InstallerMedia media) throws GLib.Error {
+        if (media.os == null)
+            return media;
 
-        var path = device.get_device_file ();
-        try {
-            var media = yield create_installer_media_for_path (path, null);
+        switch (media.os.short_id) {
+        case "fedora14":
+        case "fedora15":
+        case "fedora16":
+            return new FedoraInstaller.copy (media);
 
-            media_hash.insert (device.get_name (), media);
-            media_available (media);
-        } catch (GLib.Error error) {
-            warning ("Failed to get information on device '%s': %s. Ignoring..", path, error.message);
+        case "win7":
+        case "win2k8":
+            return new Win7Installer.copy (media);
+
+        case "winxp":
+        case "win2k":
+        case "win2k3":
+            return new WinXPInstaller.copy (media);
+
+        default:
+            return media;
         }
     }
 }
diff --git a/src/wizard-source.vala b/src/wizard-source.vala
index 0f6c15c..f5977ac 100644
--- a/src/wizard-source.vala
+++ b/src/wizard-source.vala
@@ -19,6 +19,7 @@ private class Boxes.WizardSource: GLib.Object {
             notebook.set_current_page (page);
             switch (page) {
             case SourcePage.MAIN:
+                add_media_entries.begin ();
                 // FIXME: grab first element in the menu list
                 main_menubox.grab_focus ();
                 break;
@@ -104,9 +105,9 @@ private class Boxes.WizardSource: GLib.Object {
         url_label.wrap = true;
         hbox.pack_start (url_label, true, true);
 
-        add_media_entries ();
-
         notebook.show_all ();
+
+        add_media_entries.begin ();
     }
 
     public void update_url_page(string title, string text, string icon_name) {
@@ -115,23 +116,36 @@ private class Boxes.WizardSource: GLib.Object {
     }
 
     private async void add_media_entries () {
-        foreach (var media in media_manager.medias)
-            add_media_entry (media);
+        var medias = yield media_manager.list_installer_medias ();
+
+        foreach (var child in main_menubox.get_children ()) {
+            if (child.name == null || !child.name.has_prefix ("installer-"))
+                continue;
+
+            var obsolete = true;
+            foreach (var media in medias)
+                if (child.name.contains (media.device_file)) {
+                    obsolete = false;
 
-        media_manager.media_available.connect ((media) => {
-            add_media_entry (media);
-        });
+                    break;
+                }
 
-        media_manager.media_unavailable.connect ((media) => {
+            if (obsolete)
+                main_menubox.remove (child);
+        }
+
+        foreach (var media in medias) {
+            var nouveau = true; // Everyone speaks some French, right? :)
             foreach (var child in main_menubox.get_children ())
-                if (child.name != null && child.name.has_prefix (media.device_file))
-                    main_menubox.remove (child);
+                if (child.name != null && child.name.contains (media.device_file)) {
+                    nouveau = false;
 
-            if (install_media != null && install_media.device_file == media.device_file) {
-                install_media = null;
-                uri = media.device_file;
-            }
-        });
+                    break;
+                }
+
+            if (nouveau)
+                add_media_entry (media);
+        }
     }
 
     private void add_media_entry (InstallerMedia media) {
@@ -139,26 +153,30 @@ private class Boxes.WizardSource: GLib.Object {
             install_media = media;
             uri = media.device_file;
             url_entry.activate ();
-        }, 5, 10, true, media.device_file + "-item");
+        }, 15, 5, true, "installer-" + media.device_file + "-item");
 
         var image = new Gtk.Image.from_icon_name ("media-optical", 0);
-        image.pixel_size = 96;
+        image.pixel_size = 64;
         hbox.pack_start (image, false, false);
 
-        var vbox = new Gtk.VBox (false, 0);
+        var vbox = new Gtk.VBox (true, 5);
         hbox.pack_start (vbox, true, true);
 
         var label = new Gtk.Label (media.label);
+        label.get_style_context ().add_class ("boxes-source-label");
         label.xalign = 0.0f;
-        label.yalign = 0.2f;
-        vbox.pack_start (label, true, true);
-        label = new Gtk.Label (_("Local Machine: Will create a new local box"));
-        label.xalign = 0.0f;
-        label.yalign = 0.1f;
         vbox.pack_start (label, true, true);
 
+        if (media.os_media != null) {
+            var architecture = (media.os_media.architecture == "x86") ? _("32-bit x86") : _("64-bit x86");
+            label = new Gtk.Label (architecture);
+            label.get_style_context ().add_class ("boxes-step-label");
+            label.xalign = 0.0f;
+            vbox.pack_start (label, true, true);
+        }
+
         var separator = new Gtk.Separator (Gtk.Orientation.HORIZONTAL);
-        separator.name = media.device_file + "-separator";
+        separator.name =  "installer-" + media.device_file + "-separator";
         main_menubox.pack_start (separator, false, false);
         main_menubox.reorder_child (separator, 1);
 



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