[gtk+] file chooser: Add and use a model search engine



commit 33b5c26f419aab0c072a7ac49f450e861459b852
Author: Matthias Clasen <mclasen redhat com>
Date:   Wed Jul 1 12:51:20 2015 -0700

    file chooser: Add and use a model search engine
    
    This search engine reuses the GFileInfo that is already loaded
    for the file list, to ensure that hits from the current directory
    always appear promptly.

 gtk/Makefile.am            |    2 +
 gtk/gtkfilechooserwidget.c |   13 +++-
 gtk/gtksearchengine.c      |   57 +++++++++++++-
 gtk/gtksearchengine.h      |    4 +
 gtk/gtksearchenginemodel.c |  191 ++++++++++++++++++++++++++++++++++++++++++++
 gtk/gtksearchenginemodel.h |   44 ++++++++++
 6 files changed, 306 insertions(+), 5 deletions(-)
---
diff --git a/gtk/Makefile.am b/gtk/Makefile.am
index 861f186..4795f84 100644
--- a/gtk/Makefile.am
+++ b/gtk/Makefile.am
@@ -496,6 +496,7 @@ gtk_private_h_sources =             \
        gtkscaleprivate.h       \
        gtksearchengine.h       \
        gtksearchenginesimple.h \
+       gtksearchenginemodel.h  \
        gtksearchentryprivate.h \
        gtkselectionprivate.h   \
        gtksidebarrowprivate.h  \
@@ -545,6 +546,7 @@ gtk_base_c_sources =                \
        gtksearchentry.c        \
        gtksearchengine.c       \
        gtksearchenginesimple.c \
+       gtksearchenginemodel.c  \
        fnmatch.c               \
        gtkaboutdialog.c        \
        gtkaccelgroup.c         \
diff --git a/gtk/gtkfilechooserwidget.c b/gtk/gtkfilechooserwidget.c
index eb34ef7..3293170 100644
--- a/gtk/gtkfilechooserwidget.c
+++ b/gtk/gtkfilechooserwidget.c
@@ -248,6 +248,7 @@ struct _GtkFileChooserWidgetPrivate {
   GtkSearchEngine *search_engine;
   GtkQuery *search_query;
   GtkFileSystemModel *search_model;
+  GtkFileSystemModel *model_for_search;
 
   /* OPERATION_MODE_RECENT */
   GtkRecentManager *recent_manager;
@@ -659,6 +660,7 @@ gtk_file_chooser_widget_finalize (GObject *object)
   stop_loading_and_clear_list_model (impl, FALSE);
   search_clear_model (impl, FALSE);
   recent_clear_model (impl, FALSE);
+  g_clear_object (&impl->priv->model_for_search);
 
   /* stopping the load above should have cleared this */
   g_assert (priv->load_timeout_id == 0);
@@ -2600,6 +2602,7 @@ operation_mode_stop (GtkFileChooserWidget *impl, OperationMode mode)
       break;
 
     case OPERATION_MODE_SEARCH:
+      g_clear_object (&impl->priv->model_for_search);
       search_stop_searching (impl, FALSE);
       search_clear_model (impl, TRUE);
       break;
@@ -3684,6 +3687,8 @@ load_set_model (GtkFileChooserWidget *impl)
   profile_msg ("    gtk_tree_view_set_model end", NULL);
   priv->list_sort_ascending = TRUE;
 
+  g_set_object (&priv->model_for_search, priv->browse_files_model);
+
   profile_end ("end", NULL);
 }
 
@@ -6419,12 +6424,11 @@ search_clear_model (GtkFileChooserWidget *impl,
 {
   GtkFileChooserWidgetPrivate *priv = impl->priv;
 
+  g_clear_object (&priv->search_model);
+
   if (!priv->search_model)
     return;
 
-  g_object_unref (priv->search_model);
-  priv->search_model = NULL;
-  
   if (remove_from_treeview)
     gtk_tree_view_set_model (GTK_TREE_VIEW (priv->browse_files_tree_view), NULL);
 }
@@ -6537,6 +6541,7 @@ search_start_query (GtkFileChooserWidget *impl,
       g_object_unref (file);
     }
 
+  _gtk_search_engine_set_model (priv->search_engine, priv->model_for_search);
   _gtk_search_engine_set_query (priv->search_engine, priv->search_query);
 
   g_signal_connect (priv->search_engine, "hits-added",
@@ -6734,6 +6739,8 @@ populate_model_with_recent_items (GtkFileChooserWidget *impl, GList *items)
       if (limit != -1 && n >= limit)
        break;
     }
+
+  g_set_object (&priv->model_for_search, priv->recent_model);
 }
 
 static void
diff --git a/gtk/gtksearchengine.c b/gtk/gtksearchengine.c
index 67110f9..8a92a22 100644
--- a/gtk/gtksearchengine.c
+++ b/gtk/gtksearchengine.c
@@ -23,6 +23,7 @@
 #include "gtksearchengine.h"
 #include "gtksearchenginesimple.h"
 #include "gtksearchenginetracker.h"
+#include "gtksearchenginemodel.h"
 #include "gtksearchenginequartz.h"
 
 #include <gdk/gdk.h> /* for GDK_WINDOWING_QUARTZ */
@@ -40,9 +41,15 @@ struct _GtkSearchEnginePrivate {
   gboolean simple_running;
   gchar *simple_error;
 
+  GtkSearchEngine *model;
+  gboolean model_running;
+  gchar *model_error;
+
   gboolean running;
   gboolean recursive;
   GHashTable *hits;
+
+  GtkQuery *query;
 };
 
 enum
@@ -61,11 +68,16 @@ static void
 set_query (GtkSearchEngine *engine,
            GtkQuery        *query)
 {
+  g_set_object (&engine->priv->query, query);
+
   if (engine->priv->native)
     _gtk_search_engine_set_query (engine->priv->native, query);
 
   if (engine->priv->simple)
     _gtk_search_engine_set_query (engine->priv->simple, query);
+
+  if (engine->priv->model)
+    _gtk_search_engine_set_query (engine->priv->model, query);
 }
 
 static void
@@ -87,6 +99,13 @@ start (GtkSearchEngine *engine)
       engine->priv->simple_running = TRUE;
     }
 
+  if (engine->priv->model)
+    {
+      g_clear_pointer (&engine->priv->model_error, g_free);
+      _gtk_search_engine_start (engine->priv->model);
+      engine->priv->model_running = TRUE;
+    }
+
   engine->priv->running = TRUE;
 }
 
@@ -105,6 +124,12 @@ stop (GtkSearchEngine *engine)
       engine->priv->simple_running = FALSE;
     }
 
+  if (engine->priv->model)
+    {
+      _gtk_search_engine_stop (engine->priv->model);
+      engine->priv->model_running = FALSE;
+    }
+
   engine->priv->running = FALSE;
 
   g_hash_table_remove_all (engine->priv->hits);
@@ -121,8 +146,13 @@ finalize (GObject *object)
   g_clear_object (&engine->priv->simple);
   g_free (engine->priv->simple_error);
 
+  g_clear_object (&engine->priv->model);
+  g_free (engine->priv->model_error);
+
   g_clear_pointer (&engine->priv->hits, g_hash_table_unref);
 
+  g_clear_object (&engine->priv->query);
+
   G_OBJECT_CLASS (_gtk_search_engine_parent_class)->finalize (object);
 }
 
@@ -222,6 +252,8 @@ update_status (GtkSearchEngine *engine)
             _gtk_search_engine_error (engine, engine->priv->native_error);
           else if (engine->priv->simple_error)
             _gtk_search_engine_error (engine, engine->priv->simple_error);
+          else if (engine->priv->model_error)
+            _gtk_search_engine_error (engine, engine->priv->model_error);
           else
             _gtk_search_engine_finished (engine);
         }
@@ -238,6 +270,8 @@ finished (GtkSearchEngine *engine,
     composite->priv->native_running = FALSE;
   else if (engine == composite->priv->simple)
     composite->priv->simple_running = FALSE;
+  else if (engine == composite->priv->model)
+    composite->priv->model_running = FALSE;
 
   update_status (composite);
 }
@@ -257,10 +291,16 @@ error (GtkSearchEngine *engine,
     }
   else if (engine == composite->priv->simple)
     {
-      g_free (composite->priv->native_error);
-      composite->priv->native_error = g_strdup (message);
+      g_free (composite->priv->simple_error);
+      composite->priv->simple_error = g_strdup (message);
       composite->priv->simple_running = FALSE;
     }
+  else if (engine == composite->priv->model)
+    {
+      g_free (composite->priv->model_error);
+      composite->priv->model_error = g_strdup (message);
+      composite->priv->model_running = FALSE;
+    }
 
   update_status (composite);
 }
@@ -432,3 +472,16 @@ _gtk_search_engine_get_recursive (GtkSearchEngine *engine)
 
   return engine->priv->recursive;
 }
+
+void
+_gtk_search_engine_set_model (GtkSearchEngine    *engine,
+                              GtkFileSystemModel *model)
+{
+  g_clear_object (&engine->priv->model);
+  if (model)
+    {
+      engine->priv->model = _gtk_search_engine_model_new (model);
+      if (engine->priv->query)
+        _gtk_search_engine_set_query (engine->priv->model, engine->priv->query);
+    }
+}
diff --git a/gtk/gtksearchengine.h b/gtk/gtksearchengine.h
index 9e92e31..e49eeb8 100644
--- a/gtk/gtksearchengine.h
+++ b/gtk/gtksearchengine.h
@@ -23,6 +23,7 @@
 #define __GTK_SEARCH_ENGINE_H__
 
 #include "gtkquery.h"
+#include "gtkfilesystemmodel.h"
 #include <gio/gio.h>
 
 G_BEGIN_DECLS
@@ -91,6 +92,9 @@ gboolean         _gtk_search_engine_get_recursive   (GtkSearchEngine *engine);
 void             _gtk_search_hit_free (GtkSearchHit *hit);
 GtkSearchHit    *_gtk_search_hit_dup (GtkSearchHit *hit);
 
+void             _gtk_search_engine_set_model       (GtkSearchEngine    *engine,
+                                                     GtkFileSystemModel *model);
+
 G_END_DECLS
 
 #endif /* __GTK_SEARCH_ENGINE_H__ */
diff --git a/gtk/gtksearchenginemodel.c b/gtk/gtksearchenginemodel.c
new file mode 100644
index 0000000..93003b5
--- /dev/null
+++ b/gtk/gtksearchenginemodel.c
@@ -0,0 +1,191 @@
+/*
+ * Copyright (C) 2015 Red Hat, Inc
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Author: Matthias Clasen <mclasen redhat com>
+ */
+
+#include "config.h"
+
+#include <gio/gio.h>
+
+#include <gdk/gdk.h>
+
+#include "gtksearchenginemodel.h"
+#include "gtkprivate.h"
+
+#include <string.h>
+
+#define BATCH_SIZE 500
+
+struct _GtkSearchEngineModel
+{
+  GtkSearchEngine parent;
+
+  GtkFileSystemModel *model;
+  GtkQuery *query;
+
+  gboolean query_finished;
+  guint idle;
+};
+
+struct _GtkSearchEngineModelClass
+{
+  GtkSearchEngineClass parent_class;
+};
+
+G_DEFINE_TYPE (GtkSearchEngineModel, _gtk_search_engine_model, GTK_TYPE_SEARCH_ENGINE)
+
+static void
+gtk_search_engine_model_dispose (GObject *object)
+{
+  GtkSearchEngineModel *model = GTK_SEARCH_ENGINE_MODEL (object);
+
+  g_clear_object (&model->query);
+  g_clear_object (&model->model);
+
+  G_OBJECT_CLASS (_gtk_search_engine_model_parent_class)->dispose (object);
+}
+
+gboolean
+info_matches_query (GtkQuery  *query,
+                    GFileInfo *info)
+{
+  const gchar *display_name;
+
+  display_name = g_file_info_get_display_name (info);
+  if (display_name == NULL)
+    return FALSE;
+
+  if (g_file_info_get_is_hidden (info))
+    return FALSE;
+
+  if (!gtk_query_matches_string (query, display_name))
+    return FALSE;
+
+  return TRUE;
+}
+
+static gboolean
+do_search (gpointer data)
+{
+  GtkSearchEngineModel *model = data;
+  GtkTreeIter iter;
+  GList *hits = NULL;
+
+  if (gtk_tree_model_get_iter_first (GTK_TREE_MODEL (model->model), &iter))
+    {
+      do
+        {
+          GFileInfo *info;
+          GFile *file;
+          gchar *uri;
+
+          info = _gtk_file_system_model_get_info (model->model, &iter);
+          if (info_matches_query (model->query, info))
+            {
+              file = _gtk_file_system_model_get_file (model->model, &iter);
+              uri = g_file_get_uri (file);
+              hits = g_list_prepend (hits, uri);
+            }
+          }
+        while (gtk_tree_model_iter_next (GTK_TREE_MODEL (model->model), &iter));
+
+      if (hits)
+        {
+          _gtk_search_engine_hits_added (GTK_SEARCH_ENGINE (model), hits);
+          g_list_free_full (hits, g_free);
+        }
+    }
+
+  model->idle = 0;
+
+  return G_SOURCE_REMOVE;
+}
+
+static void
+gtk_search_engine_model_start (GtkSearchEngine *engine)
+{
+  GtkSearchEngineModel *model;
+
+  model = GTK_SEARCH_ENGINE_MODEL (engine);
+
+  if (model->query == NULL)
+    return;
+
+  model->idle = g_idle_add (do_search, engine);
+}
+
+static void
+gtk_search_engine_model_stop (GtkSearchEngine *engine)
+{
+  GtkSearchEngineModel *model;
+
+  model = GTK_SEARCH_ENGINE_MODEL (engine);
+
+  if (model->idle != 0)
+    {
+      g_source_remove (model->idle);
+      model->idle = 0;
+    }
+}
+
+static void
+gtk_search_engine_model_set_query (GtkSearchEngine *engine,
+                                   GtkQuery        *query)
+{
+  GtkSearchEngineModel *model;
+
+  model = GTK_SEARCH_ENGINE_MODEL (engine);
+
+  if (query)
+    g_object_ref (query);
+
+  if (model->query)
+    g_object_unref (model->query);
+
+  model->query = query;
+}
+
+static void
+_gtk_search_engine_model_class_init (GtkSearchEngineModelClass *class)
+{
+  GObjectClass *gobject_class;
+  GtkSearchEngineClass *engine_class;
+
+  gobject_class = G_OBJECT_CLASS (class);
+  gobject_class->dispose = gtk_search_engine_model_dispose;
+
+  engine_class = GTK_SEARCH_ENGINE_CLASS (class);
+  engine_class->set_query = gtk_search_engine_model_set_query;
+  engine_class->start = gtk_search_engine_model_start;
+  engine_class->stop = gtk_search_engine_model_stop;
+}
+
+static void
+_gtk_search_engine_model_init (GtkSearchEngineModel *engine)
+{
+}
+
+GtkSearchEngine *
+_gtk_search_engine_model_new (GtkFileSystemModel *model)
+{
+  GtkSearchEngineModel *engine;
+
+  engine = GTK_SEARCH_ENGINE_MODEL (g_object_new (GTK_TYPE_SEARCH_ENGINE_MODEL, NULL));
+  engine->model = g_object_ref (model);
+
+  return GTK_SEARCH_ENGINE (engine);
+}
diff --git a/gtk/gtksearchenginemodel.h b/gtk/gtksearchenginemodel.h
new file mode 100644
index 0000000..a7cedab
--- /dev/null
+++ b/gtk/gtksearchenginemodel.h
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2015 Red Hat, Inc
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Author: Matthias Clasen
+ */
+
+#ifndef __GTK_SEARCH_ENGINE_MODEL_H__
+#define __GTK_SEARCH_ENGINE_MODEL_H__
+
+#include "gtksearchengine.h"
+#include "gtkfilesystemmodel.h"
+
+G_BEGIN_DECLS
+
+#define GTK_TYPE_SEARCH_ENGINE_MODEL           (_gtk_search_engine_model_get_type ())
+#define GTK_SEARCH_ENGINE_MODEL(obj)           (G_TYPE_CHECK_INSTANCE_CAST ((obj), 
GTK_TYPE_SEARCH_ENGINE_MODEL, GtkSearchEngineModel))
+#define GTK_SEARCH_ENGINE_MODEL_CLASS(klass)   (G_TYPE_CHECK_CLASS_CAST ((klass), 
GTK_TYPE_SEARCH_ENGINE_MODEL, GtkSearchEngineModelClass))
+#define GTK_IS_SEARCH_ENGINE_MODEL(obj)                (G_TYPE_CHECK_INSTANCE_TYPE ((obj), 
GTK_TYPE_SEARCH_ENGINE_MODEL))
+#define GTK_IS_SEARCH_ENGINE_MODEL_CLASS(klass)        (G_TYPE_CHECK_CLASS_TYPE ((klass), 
GTK_TYPE_SEARCH_ENGINE_MODEL))
+#define GTK_SEARCH_ENGINE_MODEL_GET_CLASS(obj)    (G_TYPE_INSTANCE_GET_CLASS ((obj), 
GTK_TYPE_SEARCH_ENGINE_MODEL, GtkSearchEngineModelClass))
+
+typedef struct _GtkSearchEngineModel GtkSearchEngineModel;
+typedef struct _GtkSearchEngineModelClass GtkSearchEngineModelClass;
+
+GType            _gtk_search_engine_model_get_type (void);
+
+GtkSearchEngine *_gtk_search_engine_model_new      (GtkFileSystemModel *model);
+
+G_END_DECLS
+
+#endif /* __GTK_SEARCH_ENGINE_MODEL_H__ */


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