diff options
author | Matthias Clasen <mclasen@redhat.com> | 2015-07-01 12:51:20 -0700 |
---|---|---|
committer | Matthias Clasen <mclasen@redhat.com> | 2015-07-04 00:29:25 -0400 |
commit | 33b5c26f419aab0c072a7ac49f450e861459b852 (patch) | |
tree | 04cbbc3a282a446a6dd4120c08ed80d93cec5c60 /gtk | |
parent | f87f43b6229d2314523c925d0f3584ab23c7adf9 (diff) | |
download | gtk+-33b5c26f419aab0c072a7ac49f450e861459b852.tar.gz |
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.
Diffstat (limited to 'gtk')
-rw-r--r-- | gtk/Makefile.am | 2 | ||||
-rw-r--r-- | gtk/gtkfilechooserwidget.c | 13 | ||||
-rw-r--r-- | gtk/gtksearchengine.c | 57 | ||||
-rw-r--r-- | gtk/gtksearchengine.h | 4 | ||||
-rw-r--r-- | gtk/gtksearchenginemodel.c | 191 | ||||
-rw-r--r-- | gtk/gtksearchenginemodel.h | 44 |
6 files changed, 306 insertions, 5 deletions
diff --git a/gtk/Makefile.am b/gtk/Makefile.am index 861f186370..4795f84222 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 eb34ef7eb7..32931702cf 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 67110f936b..8a92a220c1 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 9e92e3185d..e49eeb8c79 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 0000000000..93003b5b55 --- /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 0000000000..a7cedab2a0 --- /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__ */ |