[gnome-boxes] search: add a search bar



commit f2f969be7e67d29614d763632e21897ead07072c
Author: Marc-Andrà Lureau <marcandre lureau gmail com>
Date:   Wed Jul 25 14:33:33 2012 +0200

    search: add a search bar
    
    The searchbar is based on current gnome-documents behaviour and style,
    as well as the same GtkWidget code shared in libgd.
    
    It will search as you type and filter the boxes. You can activate the
    result if there is only a single match currently (I am not sure that's
    what the design says).
    
    Anyway, it's hopefully a good and useful first iteration.
    
    https://bugzilla.gnome.org/show_bug.cgi?id=681089

 src/Makefile.am    |   15 +++--
 src/app.vala       |   20 ++++++--
 src/searchbar.vala |  140 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 165 insertions(+), 10 deletions(-)
---
diff --git a/src/Makefile.am b/src/Makefile.am
index 324179c..e8b11a6 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -11,11 +11,13 @@ AM_CPPFLAGS =						\
 AM_VALAFLAGS =						\
 	--enable-experimental				\
 	--vapidir=$(srcdir)/				\
+	--vapidir=$(top_srcdir)/libgd                   \
 	--vapidir=$(top_srcdir)/vapi                    \
 	--vapidir=$(top_srcdir)/vapi/upstream           \
 	--pkg clutter-gtk-1.0				\
 	--pkg cogl-1.0					\
 	--pkg config					\
+	--pkg gd-1.0					\
 	--pkg gdk-pixbuf-2.0				\
 	--pkg glib-2.0					\
 	--pkg gtk-vnc-2.0				\
@@ -42,17 +44,19 @@ gnome_boxes_SOURCES =				\
 	display.vala				\
 	editable-entry.vala			\
 	fedora-installer.vala 			\
+	i-properties-provider.vala		\
 	installer-media.vala 			\
 	libvirt-machine.vala			\
 	machine.vala				\
+	main.vala				\
 	media-manager.vala 			\
 	mini-graph.vala				\
-	main.vala				\
+	notificationbar.vala			\
 	os-database.vala 			\
-	i-properties-provider.vala		\
 	properties.vala				\
 	remote-machine.vala			\
 	revealer.vala				\
+	searchbar.vala				\
 	selectionbar.vala			\
 	sidebar.vala				\
 	spice-display.vala			\
@@ -60,18 +64,17 @@ gnome_boxes_SOURCES =				\
 	ui.vala					\
 	unattended-installer.vala 		\
 	util.vala				\
-	vm-creator.vala 			\
 	vm-configurator.vala 			\
+	vm-creator.vala 			\
 	vnc-display.vala			\
-	windows-installer.vala 			\
 	win7-installer.vala 			\
+	windows-installer.vala 			\
 	winxp-installer.vala 			\
 	wizard-source.vala			\
 	wizard.vala				\
-	notificationbar.vala			\
 	$(NULL)
 
-gnome_boxes_LDADD = $(BOXES_LIBS)
+gnome_boxes_LDADD = $(BOXES_LIBS) $(top_builddir)/libgd/libgdprivate-1.0.la
 gnome_boxes_CFLAGS = $(BOXES_CFLAGS)
 
 MAINTAINERCLEANFILES =				\
diff --git a/src/app.vala b/src/app.vala
index f15576b..77afad3 100644
--- a/src/app.vala
+++ b/src/app.vala
@@ -29,10 +29,11 @@ private class Boxes.App: Boxes.UI {
     public Clutter.Actor overlay_bin_actor;
     public Clutter.BinLayout overlay_bin;
     public CollectionItem current_item; // current object/vm manipulated
+    public Searchbar searchbar;
     public Topbar topbar;
     public Notificationbar notificationbar;
     public Boxes.Revealer sidebar_revealer;
-    public Boxes.Revealer topbar_revealer;
+    public Boxes.Revealer searchbar_revealer;
     public Sidebar sidebar;
     public Selectionbar selectionbar;
     public uint duration;
@@ -50,7 +51,7 @@ private class Boxes.App: Boxes.UI {
     public signal void ready (bool first_time);
     public signal void item_selected (CollectionItem item);
     private Gtk.Application application;
-    private CollectionView view;
+    public CollectionView view;
 
     private HashTable<string,GVir.Connection> connections;
     private HashTable<string,CollectionSource> sources;
@@ -419,6 +420,7 @@ private class Boxes.App: Boxes.UI {
 
         sidebar = new Sidebar ();
         view = new CollectionView ();
+        searchbar = new Searchbar ();
         topbar = new Topbar ();
         notificationbar = new Notificationbar ();
         selectionbar = new Selectionbar ();
@@ -435,11 +437,18 @@ private class Boxes.App: Boxes.UI {
                        Clutter.BinAlignment.FILL,
                        Clutter.BinAlignment.FILL);
 
-        topbar_revealer = new Boxes.Revealer (true);
+        var topbar_revealer = new Boxes.Revealer (true);
         topbar_revealer.name = "topbar-revealer";
         vbox.pack (topbar_revealer, false, true, true, Clutter.BoxAlignment.START, Clutter.BoxAlignment.START);
         topbar_revealer.add (topbar.actor);
 
+        searchbar_revealer = new Boxes.Revealer (true);
+        searchbar_revealer.resize = true;
+        searchbar_revealer.unreveal ();
+        searchbar_revealer.name = "searchbar-revealer";
+        vbox.pack (searchbar_revealer, false, true, true, Clutter.BoxAlignment.START, Clutter.BoxAlignment.START);
+        searchbar_revealer.add (searchbar.actor);
+
         var below_bin_actor = new Clutter.Actor ();
         below_bin_actor.name = "below-bin";
         var below_bin = new Clutter.BinLayout (Clutter.BinAlignment.FIXED,
@@ -506,7 +515,7 @@ private class Boxes.App: Boxes.UI {
         action_properties.set_enabled (ui_state == UIState.DISPLAY);
         action_shutdown.set_enabled (ui_state == UIState.DISPLAY && current_item is LibvirtMachine);
 
-        foreach (var ui in new Boxes.UI[] { sidebar, topbar, view, wizard, properties }) {
+        foreach (var ui in new Boxes.UI[] { sidebar, searchbar, topbar, view, wizard, properties }) {
             ui.ui_state = ui_state;
         }
 
@@ -520,11 +529,14 @@ private class Boxes.App: Boxes.UI {
             }
             fullscreen = false;
             view.visible = true;
+            searchbar_revealer.revealed = searchbar.visible;
+
             break;
 
         case UIState.CREDS:
         case UIState.PROPERTIES:
         case UIState.WIZARD:
+            searchbar_revealer.revealed = false;
             set_main_ui_state ();
             break;
 
diff --git a/src/searchbar.vala b/src/searchbar.vala
new file mode 100644
index 0000000..33aa71f
--- /dev/null
+++ b/src/searchbar.vala
@@ -0,0 +1,140 @@
+// This file is part of GNOME Boxes. License: LGPLv2+
+
+private class Boxes.Searchbar: Boxes.UI {
+    public override Clutter.Actor actor { get { return gtk_actor; } }
+    private GtkClutter.Actor gtk_actor;
+    private Gd.TaggedEntry entry;
+
+    private uint refilter_delay_id;
+    static const uint refilter_delay = 200; // in ms
+
+    public Searchbar () {
+        setup_searchbar ();
+
+        App.app.window.key_press_event.connect (on_app_key_pressed);
+        entry.notify["text"].connect ( () => {
+                if (refilter_delay_id != 0)
+                    Source.remove (refilter_delay_id);
+
+                if (text == "")
+                    refilter ();
+                else
+                    refilter_delay_id = Timeout.add (refilter_delay, refilter);
+        });
+        entry.activate.connect ( () => {
+            App.app.view.activate ();
+        });
+    }
+
+    private bool refilter () {
+        App.app.filter.text = text;
+        App.app.view.refilter ();
+        refilter_delay_id = 0;
+
+        return false;
+    }
+
+    private bool _visible;
+    public bool visible {
+        get {
+            return _visible;
+        }
+        set {
+            if (_visible == value)
+                return;
+
+            App.app.searchbar_revealer.revealed = value;
+            if (value)
+                grab_focus ();
+
+            _visible = value;
+        }
+    }
+
+    public string text {
+        get { return entry.text; }
+        set { entry.set_text (value); }
+    }
+
+    public void grab_focus () {
+        Gd.entry_focus_hack (entry, Gtk.get_current_event_device ());
+    }
+
+    private bool on_app_key_pressed (Gtk.Widget widget, Gdk.EventKey event) {
+        var handled = false;
+
+        if (ui_state != UIState.COLLECTION)
+            return handled;
+
+        if (!entry.get_realized ())
+            // This will realize the widget so it can receive events, but
+            // won't actually show it
+            actor.show ();
+
+        var preedit_changed = false;
+        var preedit_changed_id =
+            entry.preedit_changed.connect (() => { preedit_changed = true; });
+
+        var old_text = text;
+        if (!visible)
+            text = "";
+
+        if (visible && event.keyval == Gdk.Key.Escape) {
+            text = "";
+            visible = false;
+            return true;
+        }
+
+        var res = entry.event ((Gdk.Event)(&event));
+        var new_text = text;
+
+        entry.disconnect (preedit_changed_id);
+
+        if (((res && (new_text != old_text)) || preedit_changed)) {
+            handled = true;
+            if (!visible)
+                visible = true;
+            else
+                grab_focus ();
+        }
+
+        return handled;
+    }
+
+    private void setup_searchbar () {
+        var toolbar = new Gtk.Toolbar ();
+        var widget = toolbar;
+        toolbar.get_style_context ().add_class (Gtk.STYLE_CLASS_PRIMARY_TOOLBAR);
+
+        var item = new Gtk.ToolItem ();
+        toolbar.insert(item, 0);
+        item.set_expand (true);
+
+        // FIXME: https://bugzilla.gnome.org/show_bug.cgi?id=680595
+        var margin = new Gd.MarginContainer ();
+        item.add (margin);
+        margin.min_margin = 6;
+        margin.max_margin = 64;
+
+        var box = new Gtk.Box (Gtk.Orientation.HORIZONTAL, 0);
+        margin.add (box);
+
+        entry = new Gd.TaggedEntry ();
+        entry.width_request = 260;
+        entry.hexpand = true;
+        box.add (entry);
+
+        widget.show_all ();
+        gtk_actor = new GtkClutter.Actor.with_contents (widget);
+        gtk_actor.name = "searchbar";
+    }
+
+    public override void ui_state_changed () {
+        switch (ui_state) {
+        case UIState.COLLECTION:
+            break;
+        default:
+            break;
+        }
+    }
+}



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