← Back to team overview

elementary-dev-community team mailing list archive

[Merge] lp:~elementary-dev-community/pantheon-files/search-experiment into lp:pantheon-files

 

Julián Unrrein has proposed merging lp:~elementary-dev-community/pantheon-files/search-experiment into lp:pantheon-files.

Requested reviews:
  elementary Apps team (elementary-apps)

For more details, see:
https://code.launchpad.net/~elementary-dev-community/pantheon-files/search-experiment/+merge/180278

A crappy attempt at a search function for Files.

Basically, when loading a directory, filter out any files/folders that don't match the search words.

It only filters items from the current directory (won't search recursively), though this wouldn't be hard to implement.

This doesn't have any potential for further filtering (by mimetype, by date, for example). At least, it wasn't my intention.

It doesn't work with the first tab opened. Don't know why. Just close it or open a new one.

The only thing that I took care of is that you can search a dir in one tab, while you browse the same dir normally in another tab. Usually (if not searching), the directory objects would be the same for all tabs, but I took care of using separate ones for searching.

This doesn't work for Columns View.

When testing, keep in mind that the Backspace key is always handled by the Location Bar, and will take you to the parent directory when pressed.
-- 
https://code.launchpad.net/~elementary-dev-community/pantheon-files/search-experiment/+merge/180278
Your team elementary Developer Community is subscribed to branch lp:~elementary-dev-community/pantheon-files/search-experiment.
=== modified file 'libcore/gof-directory-async.vala'
--- libcore/gof-directory-async.vala	2013-06-30 15:49:02 +0000
+++ libcore/gof-directory-async.vala	2013-08-15 04:27:35 +0000
@@ -98,6 +98,24 @@
 
         //list_directory (location);
     }
+    
+    public Async.for_search (GLib.File _file, string initial_search_text) {
+        location = _file;
+        file = GOF.File.get (location);
+        file.exists = true;
+        cancellable = new Cancellable ();
+        
+        this.search_text = initial_search_text;
+
+        if (file.info == null)
+            file.query_update ();
+        file.info_available ();
+
+        this.add_toggle_ref ((ToggleNotify) toggle_ref_notify);
+        this.unref ();
+        debug ("dir %s ref_count %u", this.file.uri, this.ref_count);
+        file_hash = new HashTable<GLib.File,GOF.File> (GLib.file_hash, GLib.file_equal);
+    }
 
     /*~Async () {
         warning ("Async finalize %s", this.file.uri);
@@ -176,9 +194,11 @@
                 
             bool show_hidden = Preferences.get_default ().pref_show_hidden_files;
             foreach (GOF.File gof in file_hash.get_values ()) {
-                if (gof.info != null && (!gof.is_hidden || show_hidden))
+                if (gof.info != null && (!gof.is_hidden || show_hidden) &&
+                        matches_search_text (gof.basename))
                     file_loaded (gof);
             }
+            
             done_loading ();
         }
     }
@@ -255,9 +275,11 @@
                     //debug ("file: %s", gof.name);
 
                     add_to_hash_cache (gof);
-                    if (!gof.is_hidden || Preferences.get_default ().pref_show_hidden_files)
+                    if ((!gof.is_hidden || Preferences.get_default ().pref_show_hidden_files)
+                            && matches_search_text (gof.basename)) {
                         file_loaded (gof);
-
+                    }
+                    
                     //mutex.lock ();
                     files_count++;
                     //mutex.unlock ();
@@ -660,5 +682,54 @@
             warning ("%s", e.message);
         }
     }
+        
+    private string _search_text = "";
+    public string search_text {
+        get {
+            return _search_text;
+        }
+        
+        set {
+            if (search_text != value) {
+                _search_text = value;
+                prepared_words = null;
+            }
+        }
+    }
+    
+    private string[]? prepared_words = null;
+    
+    private bool matches_search_text (string to_search) {
+        if (search_text == "")
+            return true;
+            
+        string prepared_string;
+        bool found = true;
+        
+        if (prepared_words == null) {
+            prepared_string = prepare_string_for_compare (search_text);
+            prepared_words = prepared_string.split (" ", -1);
+        }
+        
+        prepared_string = prepare_string_for_compare (to_search);
+        
+        foreach (string word in prepared_words) {
+            if (prepared_string.index_of (word) == -1) {
+                found = false;
+                break;
+            }
+        }
+        
+        return found;
+    }
+    
+    private string prepare_string_for_compare (string to_prepare) {
+        string normalized, result;
+        
+        normalized = to_prepare.normalize (-1, NormalizeMode.NFD);
+        result = normalized.down (-1);
+        
+        return result;
+    }
 }
 

=== modified file 'src/View/Chrome/TopMenu.vala'
--- src/View/Chrome/TopMenu.vala	2013-06-18 22:12:58 +0000
+++ src/View/Chrome/TopMenu.vala	2013-08-15 04:27:35 +0000
@@ -28,6 +28,7 @@
         public ViewSwitcher? view_switcher;
         public Gtk.Menu toolbar_menu;
         public LocationBar? location_bar;
+        public Granite.Widgets.SearchBar? search_bar;
         public Window win;
 
         public TopMenu (Window window)
@@ -119,6 +120,13 @@
                     }
                 }
             }
+            
+            var search_toolitem = new Gtk.ToolItem ();
+            search_toolitem.margin_left = search_toolitem.margin_right = 6;
+            this.search_bar = new Granite.Widgets.SearchBar (_("Search files..."));
+            search_toolitem.add (this.search_bar);
+            search_toolitem.show_all ();
+            insert (search_toolitem, -1);
 
         }
 

=== modified file 'src/View/ViewContainer.vala'
--- src/View/ViewContainer.vala	2013-06-14 23:37:29 +0000
+++ src/View/ViewContainer.vala	2013-08-15 04:27:35 +0000
@@ -38,7 +38,7 @@
         //private ulong file_info_callback;
         private GLib.List<GLib.File> select_childs = null;
 
-        public signal void path_changed(File file);
+        public signal void path_changed (File file);
         public signal void up();
         public signal void back(int n=1);
         public signal void forward(int n=1);
@@ -183,9 +183,9 @@
             slot.directory.done_loading.disconnect (directory_done_loading);
         }
 
-        public void change_view (int nview, GLib.File? location) {
+        public void change_view (int nview, GLib.File? location,
+                                 bool search = false, string to_search = "") {
             /* if location is null then we have a user change view request */
-            bool user_change_rq = location == null;
             select_childs = null;
             if (location == null) {
                 /* we re just changing view keep the same location */
@@ -213,19 +213,15 @@
                 slot = mwcol.active_slot;
             } else {
                 mwcol = null;
-                slot = new GOF.Window.Slot(location, this);
+                slot = new GOF.Window.Slot(location, this, search, to_search);
             }
 
-            /* automagicly enable icon view for icons keypath */
-            if (!user_change_rq && slot.directory.uri_contain_keypath_icons)
-                nview = 0; /* icon view */
-
             /* Setting up view_mode and its button */
             view_mode = nview;
             if (window.top_menu.view_switcher != null)
                 window.top_menu.view_switcher.mode = (ViewMode) view_mode;
 
-            connect_available_info();
+            connect_available_info ();
             if (slot != null) {
                 slot.directory.done_loading.connect (directory_done_loading);
                 slot.directory.need_reload.connect (reload);
@@ -316,7 +312,18 @@
         {
             return ((Gtk.Widget) window);
         }
+        
+        public void search_text_changed (string to_search) {
+            if (this.slot == null)
+                return;
 
+            if (to_search == "") {
+                change_view (this.view_mode, null);
+            } else {
+                change_view (this.view_mode, null, true, to_search);
+                this.slot.directory.search_text = to_search;
+            }
+        }
     }
 }
 

=== modified file 'src/View/Window.vala'
--- src/View/Window.vala	2013-08-07 20:32:38 +0000
+++ src/View/Window.vala	2013-08-15 04:27:35 +0000
@@ -81,7 +81,7 @@
             int n = action.get_current_value();
             /* change the view only for view_mode real change */
             if (n != current_tab.view_mode)
-                current_tab.change_view(n, null);
+                current_tab.change_view(n, null, false);
         }
 
         public Window (Marlin.Application app, Gdk.Screen myscreen)
@@ -230,6 +230,10 @@
             
             tabs.tab_added.connect ((tab) => {
                 make_new_tab (tab);
+                
+                var view_container = tab.page as ViewContainer;
+                this.top_menu.search_bar.text_changed_pause.connect (
+                    view_container.search_text_changed);
             });
             
             tabs.tab_removed.connect ((tab) => {
@@ -245,6 +249,16 @@
             
             tabs.tab_switched.connect ((old_tab, new_tab) => {
                 change_tab (tabs.get_tab_position (new_tab));
+                
+                if (old_tab != null) {
+                    var old_view_container = old_tab.page as ViewContainer;
+                    this.top_menu.search_bar.text_changed_pause.disconnect (
+                        old_view_container.search_text_changed);
+                }
+                
+                if (current_tab != null)
+                    this.top_menu.search_bar.text_changed_pause.connect (
+                        current_tab.search_text_changed);
             });
             
             tabs.tab_restored.connect ((tab) => {

=== modified file 'src/gof-window-slot.c'
--- src/gof-window-slot.c	2013-06-27 19:34:48 +0000
+++ src/gof-window-slot.c	2013-08-15 04:27:35 +0000
@@ -51,7 +51,7 @@
 }
 
 static void
-real_active (GOFWindowSlot *slot) 
+real_active (GOFWindowSlot *slot)
 {
     marlin_view_view_container_refresh_slot_info (MARLIN_VIEW_VIEW_CONTAINER (slot->ctab));
 }
@@ -100,7 +100,7 @@
 update_total_width (GtkWidget *widget, GtkAllocation *allocation, void *data)
 {
     GOFWindowSlot* slot = data;
-    
+
     if (slot->mwcols->total_width != 0 && slot->width != allocation->width) {
         slot->mwcols->total_width += allocation->width - slot->width;
         slot->width = allocation->width;
@@ -114,11 +114,11 @@
     GtkWidget *hpane = GTK_WIDGET (granite_widgets_thin_paned_new (GTK_ORIENTATION_HORIZONTAL));
     gtk_widget_set_hexpand(hpane, TRUE);
     gtk_widget_show (hpane);
-    
+
     gtk_container_add(GTK_CONTAINER (slot->colpane), hpane);
     gtk_widget_show_all(slot->colpane);
-    
-    GtkWidget *box1 = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);    
+
+    GtkWidget *box1 = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
     gtk_widget_show_all (box1);
 
     slot->colpane = box1;
@@ -139,10 +139,10 @@
     gint current_slot_position = 0;
     gint i;
     GList* list_slot = slot->mwcols->slot;
-   
+
     g_return_if_fail (slot->colpane != NULL);
     gtk_container_foreach (GTK_CONTAINER (slot->colpane), (GtkCallback)gtk_widget_destroy, NULL);
-    
+
     current_slot_position = g_list_index(slot->mwcols->slot, slot);
     if(current_slot_position == -1) {
         g_warning ("Can't find the slot you are viewing, this should *not* happen.");
@@ -158,24 +158,31 @@
         slot->mwcols->slot = l;
     }
     slot->mwcols->total_width += slot->mwcols->preferred_column_width + 100;
-    gtk_widget_set_size_request (slot->mwcols->colpane, slot->mwcols->total_width, -1);    
+    gtk_widget_set_size_request (slot->mwcols->colpane, slot->mwcols->total_width, -1);
     marlin_window_columns_add (slot->mwcols, location);
 }
 
 GOFWindowSlot *
-gof_window_slot_new (GFile *location, GtkOverlay *ctab)
+gof_window_slot_new (GFile *location, GtkOverlay *ctab,
+                     gboolean search, gchar* to_search)
 {
     GOFWindowSlot *slot;
     slot = g_object_new (GOF_TYPE_WINDOW_SLOT, NULL);
     slot->location = g_object_ref (location);
     slot->ctab = ctab;
 
-    slot->directory = gof_directory_async_from_gfile (slot->location);
+    if (search)
+        slot->directory = gof_directory_async_new_for_search (slot->location, to_search);
+    else
+        slot->directory = gof_directory_async_from_gfile (slot->location);
+
     g_debug ("%s %s\n", G_STRFUNC, slot->directory->file->uri);
 
     return slot;
 }
 
+
+
 /**
  * Used to make a view in the list view.
  * It replaces the content of the current tab by it own widget (wich is a list
@@ -191,7 +198,7 @@
     slot->view_box = GTK_WIDGET (g_object_new (FM_TYPE_ICON_VIEW,
                                                "window-slot", slot, NULL));
     gtk_box_pack_start(GTK_BOX (slot->content_box), slot->view_box, TRUE, TRUE, 0);
-    
+
     marlin_view_view_container_set_content ((MarlinViewViewContainer *) slot->ctab, slot->content_box);
     gof_directory_async_load (slot->directory);
 }

=== modified file 'src/gof-window-slot.h'
--- src/gof-window-slot.h	2013-06-27 19:34:48 +0000
+++ src/gof-window-slot.h	2013-08-15 04:27:35 +0000
@@ -68,7 +68,8 @@
 
 GType           gof_window_slot_get_type (void);
 
-GOFWindowSlot   *gof_window_slot_new (GFile *location, GtkOverlay *ctab);
+GOFWindowSlot   *gof_window_slot_new (GFile *location, GtkOverlay *ctab,
+                                      gboolean search, gchar* to_search);
 
 void            gof_window_column_add (GOFWindowSlot *slot, GtkWidget *column);
 void            gof_window_columns_add_location (GOFWindowSlot *slot, GFile *location);

=== modified file 'src/marlin-window-columns.c'
--- src/marlin-window-columns.c	2013-07-05 18:20:51 +0000
+++ src/marlin-window-columns.c	2013-08-15 04:27:35 +0000
@@ -94,7 +94,7 @@
     mwcols->location = g_object_ref (location);
     mwcols->ctab = ctab;
 
-    GOFWindowSlot *slot = gof_window_slot_new (location, mwcols->ctab);
+    GOFWindowSlot *slot = gof_window_slot_new (location, mwcols->ctab, FALSE, NULL);
     slot->mwcols = mwcols;
     mwcols->active_slot = slot;
     mwcols->slot = g_list_append(mwcols->slot, slot);
@@ -155,7 +155,7 @@
 void
 marlin_window_columns_add (MarlinWindowColumns *mwcols, GFile *location)
 {
-    GOFWindowSlot *slot = gof_window_slot_new (location, mwcols->ctab);
+    GOFWindowSlot *slot = gof_window_slot_new (location, mwcols->ctab, FALSE, NULL);
     gof_window_slot_make_column_view (slot);
     slot->mwcols = mwcols;
     slot->colpane = mwcols->active_slot->colpane;

=== modified file 'src/marlin.vapi'
--- src/marlin.vapi	2013-02-10 14:18:21 +0000
+++ src/marlin.vapi	2013-08-15 04:27:35 +0000
@@ -34,7 +34,8 @@
     namespace Window {
         [CCode (cheader_filename = "gof-window-slot.h")]
         public class Slot : GOF.AbstractSlot {
-            public Slot (GLib.File f, Gtk.Overlay ctab);
+            public Slot (GLib.File f, Gtk.Overlay ctab,
+                         bool search, string to_search);
             public void make_icon_view ();
             public void make_list_view ();
             public void make_compact_view ();


References