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.
This commit is contained in:
Matthias Clasen 2015-07-01 12:51:20 -07:00
parent f87f43b622
commit 33b5c26f41
6 changed files with 306 additions and 5 deletions

View File

@ -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 \

View File

@ -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

View File

@ -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);
}
}

View File

@ -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__ */

191
gtk/gtksearchenginemodel.c Normal file
View File

@ -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);
}

View File

@ -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__ */