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



commit 598f438cb7b87bd65b414bd36c6dac2bfb80c91a
Author: Zeeshan Ali (Khattak) <zeeshanak gnome org>
Date:   Wed Feb 8 03:17:48 2012 +0200

    wizard: Present bootable medias on 'Source' page
    
    Currently this is limited to hardware media but once this is in place,
    adding support for user's ISO files (based on Tracker) shouldn't be very
    difficult.
    
    https://bugzilla.gnome.org/show_bug.cgi?id=669771

 src/app.vala           |    8 +++--
 src/media-manager.vala |   50 +++++++++++++++++++++++++++++++
 src/vm-creator.vala    |    7 ++--
 src/wizard-source.vala |   76 +++++++++++++++++++++++++++++++++++++++++++++--
 src/wizard.vala        |   21 ++++++++-----
 5 files changed, 144 insertions(+), 18 deletions(-)
---
diff --git a/src/app.vala b/src/app.vala
index 7cc9032..e40fa02 100644
--- a/src/app.vala
+++ b/src/app.vala
@@ -55,6 +55,7 @@ private class Boxes.App: Boxes.UI {
     public App () {
         application = new Gtk.Application ("org.gnome.Boxes", 0);
         settings = new GLib.Settings ("org.gnome.boxes");
+        connections = new HashTable<string, GVir.Connection> (str_hash, str_equal);
 
         var action = new GLib.SimpleAction ("quit", null);
         action.activate.connect (() => { quit (); });
@@ -117,7 +118,6 @@ private class Boxes.App: Boxes.UI {
             setup_ui ();
 
             collection = new Collection (this);
-            connections = new HashTable<string, GVir.Connection> (str_hash, str_equal);
             collection.item_added.connect ((item) => {
                 view.add_item (item);
             });
@@ -172,6 +172,10 @@ private class Boxes.App: Boxes.UI {
             warning (error.message);
         }
 
+        connections.insert (source.name, connection);
+        if (source.name == "QEMU Session")
+            notify_property ("default-connection");
+
         foreach (var domain in connection.get_domains ())
             add_domain (source, connection, domain);
 
@@ -187,8 +191,6 @@ private class Boxes.App: Boxes.UI {
         connection.domain_added.connect ((connection, domain) => {
             add_domain (source, connection, domain);
         });
-
-        connections.insert (source.name, connection);
     }
 
     public async void add_collection_source (CollectionSource source) {
diff --git a/src/media-manager.vala b/src/media-manager.vala
index 80a9ff3..f2c024a 100644
--- a/src/media-manager.vala
+++ b/src/media-manager.vala
@@ -6,6 +6,12 @@ using GUdev;
 private class Boxes.MediaManager : Object {
     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;
 
     public MediaManager () {
         client = new GUdev.Client ({"block"});
@@ -14,6 +20,10 @@ 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);
     }
 
     public async InstallerMedia create_installer_media_for_path (string       path,
@@ -50,4 +60,44 @@ private class Boxes.MediaManager : Object {
 
         return media;
     }
+
+    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 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);
+
+        if (action == "remove" || action == "change") {
+            var media = media_hash.lookup (name);
+            if (media != null) {
+                media_hash.remove (name);
+                media_unavailable (media);
+            }
+        }
+
+        if (action == "add" || action == "change" && device.get_property_as_boolean ("OSINFO_BOOTABLE"))
+            add_device.begin (device);
+    }
+
+    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;
+
+        var path = device.get_device_file ();
+        try {
+            var media = yield create_installer_media_for_path (path, null);
+
+            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);
+        }
+    }
 }
diff --git a/src/vm-creator.vala b/src/vm-creator.vala
index 075d099..5ce6150 100644
--- a/src/vm-creator.vala
+++ b/src/vm-creator.vala
@@ -4,12 +4,13 @@ using Osinfo;
 using GVir;
 
 private class Boxes.VMCreator {
-    private Connection connection;
+    private App app;
+    private Connection connection { get { return app.default_connection; } }
     private VMConfigurator configurator;
 
-    public VMCreator (App app) throws GLib.Error {
-        connection = app.default_connection;
+    public VMCreator (App app) {
         configurator = new VMConfigurator ();
+        this.app = app;
     }
 
     public async Domain create_and_launch_vm (InstallerMedia install_media,
diff --git a/src/wizard-source.vala b/src/wizard-source.vala
index 015b77e..b5f3802 100644
--- a/src/wizard-source.vala
+++ b/src/wizard-source.vala
@@ -33,6 +33,7 @@ private class Boxes.WizardSource: GLib.Object {
         get { return url_entry.get_text (); }
         set { url_entry.set_text (value); }
     }
+    public InstallerMedia? install_media { get; private set; }
 
     private Boxes.MenuBox main_menubox;
     private Gtk.Notebook notebook;
@@ -40,7 +41,11 @@ private class Boxes.WizardSource: GLib.Object {
     private Gtk.Image url_image;
     public Gtk.Entry url_entry;
 
-    public WizardSource () {
+    MediaManager media_manager;
+
+    public WizardSource (MediaManager media_manager) {
+        this.media_manager = media_manager;
+
         notebook = new Gtk.Notebook ();
         notebook.width_request = 500;
         notebook.get_style_context ().add_class ("boxes-source-nb");
@@ -99,6 +104,8 @@ private class Boxes.WizardSource: GLib.Object {
         url_label.wrap = true;
         hbox.pack_start (url_label, true, true);
 
+        add_media_entries ();
+
         notebook.show_all ();
     }
 
@@ -107,12 +114,73 @@ private class Boxes.WizardSource: GLib.Object {
         url_image.icon_name = icon_name;
     }
 
-    private Gtk.HBox add_entry (MenuBox box, ClickedFunc? clicked = null) {
+    private async void add_media_entries () {
+        foreach (var media in media_manager.medias)
+            add_media_entry (media);
+
+        media_manager.media_available.connect ((media) => {
+            add_media_entry (media);
+        });
+
+        media_manager.media_unavailable.connect ((media) => {
+            foreach (var child in main_menubox.get_children ())
+                if (child.name != null && child.name.has_prefix (media.device_file))
+                    main_menubox.remove (child);
+
+            if (install_media != null && install_media.device_file == media.device_file) {
+                install_media = null;
+                uri = media.device_file;
+            }
+        });
+    }
+
+    private void add_media_entry (InstallerMedia media) {
+        var hbox = add_entry (main_menubox, () => {
+            install_media = media;
+            uri = media.device_file;
+            page = SourcePage.URL;
+        }, 5, 10, true, media.device_file + "-item");
+
+        var image = new Gtk.Image.from_icon_name ("media-optical", 0);
+        image.pixel_size = 96;
+        hbox.pack_start (image, false, false);
+
+        var vbox = new Gtk.VBox (false, 0);
+        hbox.pack_start (vbox, true, true);
+
+        var label = new Gtk.Label (media.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);
+
+        var separator = new Gtk.Separator (Gtk.Orientation.HORIZONTAL);
+        separator.name = media.device_file + "-separator";
+        main_menubox.pack_start (separator, false, false);
+        main_menubox.reorder_child (separator, 1);
+
+        main_menubox.show_all ();
+    }
+
+    private Gtk.HBox add_entry (MenuBox            box,
+                                owned ClickedFunc? clicked = null,
+                                int                h_margin = 20,
+                                int                v_margin = 10,
+                                bool               beginning = false,
+                                string?            name = null) {
         var hbox = new Gtk.HBox (false, 20);
         var item = new MenuBox.Item (hbox);
         box.add (item);
-        hbox.margin_left = hbox.margin_right = 20;
-        hbox.margin_top = hbox.margin_bottom = 10;
+        if (beginning)
+            main_menubox.reorder_child (item, 0);
+        if (name != null)
+            item.name = name;
+
+        hbox.margin_left = hbox.margin_right = h_margin;
+        hbox.margin_top = hbox.margin_bottom = v_margin;
 
         if (clicked != null) {
             item.selectable = true;
diff --git a/src/wizard.vala b/src/wizard.vala
index b436457..2f6325c 100644
--- a/src/wizard.vala
+++ b/src/wizard.vala
@@ -102,7 +102,8 @@ private class Boxes.Wizard: Boxes.UI {
     construct {
         steps = new GenericArray<Gtk.Label> ();
         steps.length = WizardPage.LAST;
-        wizard_source = new Boxes.WizardSource ();
+        media_manager = new MediaManager ();
+        wizard_source = new Boxes.WizardSource (media_manager);
         wizard_source.notify["page"].connect(() => {
             if (wizard_source.page == Boxes.SourcePage.MAIN)
                 next_button.sensitive = false;
@@ -131,12 +132,11 @@ private class Boxes.Wizard: Boxes.UI {
         wizard_source.url_entry.activate.connect(() => {
             page = page + 1;
         });
-
-        media_manager = new MediaManager ();
     }
 
     public Wizard (App app) {
         this.app = app;
+        vm_creator = new VMCreator (app);
 
         setup_ui ();
     }
@@ -210,10 +210,6 @@ private class Boxes.Wizard: Boxes.UI {
     }
 
     private void prepare_for_installer (string path) throws GLib.Error {
-        if (vm_creator == null) {
-            vm_creator = new VMCreator (app);
-        }
-
         next_button.sensitive = false;
         media_manager.create_installer_media_for_path.begin (path, null, on_installer_media_instantiated);
     }
@@ -233,7 +229,16 @@ private class Boxes.Wizard: Boxes.UI {
 
     private void prepare () throws GLib.Error {
         if (this.wizard_source.page == Boxes.SourcePage.URL)
-            prepare_for_location (this.wizard_source.uri);
+            if (this.wizard_source.install_media != null) {
+                install_media = this.wizard_source.install_media;
+                prep_progress.fraction = 1.0;
+                Idle.add (() => {
+                    page = page + 1;
+
+                    return false;
+                });
+            } else
+                prepare_for_location (this.wizard_source.uri);
     }
 
     private bool setup () {



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