mirror of
https://gitlab.gnome.org/GNOME/nautilus
synced 2024-11-05 16:04:31 +00:00
ff6ccbaf40
It was working as: - Search directory starts a new search - Search engine starts all search providers, each one in its own thread. - User changes query - Search engine stops all search providers - Searchs providers, since they are in its own thread, cancel in a unknown time. - Search directory starts a new search, even before all providers are finished. - Search engine is marked as need to restart. - Search providers finished. - Search engine emits finished signal, since all search providers now are stopped. - Clients doesn't have a way to know if the engine actually finished searching the current search, or the previous search that the client asked to stop. That might confuse clients if they ask for results. - Search engine restart the search providers without noticing the client, that thinks that the latest search it started was finished already. So to fix this confusion, only report that the engine actually finished if the engine is not going to restart the search providers. In this way a client can start a batch of consecutive searches without the risk of getting search finished signals from previous searches. Clients now will always get the search-finished signal of the latest search they started.
326 lines
9.4 KiB
C
326 lines
9.4 KiB
C
/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
|
|
/*
|
|
* Copyright (C) 2005 Novell, Inc.
|
|
*
|
|
* Nautilus is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU General Public License as
|
|
* published by the Free Software Foundation; either version 2 of the
|
|
* License, or (at your option) any later version.
|
|
*
|
|
* Nautilus 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
|
|
* General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public
|
|
* License along with this program; see the file COPYING. If not,
|
|
* see <http://www.gnu.org/licenses/>.
|
|
*
|
|
* Author: Anders Carlsson <andersca@imendio.com>
|
|
*
|
|
*/
|
|
|
|
#include <config.h>
|
|
|
|
#include <glib/gi18n.h>
|
|
#include "nautilus-search-provider.h"
|
|
#include "nautilus-search-engine.h"
|
|
#include "nautilus-search-engine-simple.h"
|
|
#include "nautilus-search-engine-model.h"
|
|
#define DEBUG_FLAG NAUTILUS_DEBUG_SEARCH
|
|
#include "nautilus-debug.h"
|
|
|
|
#ifdef ENABLE_TRACKER
|
|
#include "nautilus-search-engine-tracker.h"
|
|
#endif
|
|
|
|
struct NautilusSearchEngineDetails
|
|
{
|
|
#ifdef ENABLE_TRACKER
|
|
NautilusSearchEngineTracker *tracker;
|
|
#endif
|
|
NautilusSearchEngineSimple *simple;
|
|
NautilusSearchEngineModel *model;
|
|
|
|
GHashTable *uris;
|
|
guint providers_running;
|
|
guint providers_finished;
|
|
guint providers_error;
|
|
|
|
gboolean running;
|
|
gboolean restart;
|
|
};
|
|
|
|
static void nautilus_search_provider_init (NautilusSearchProviderIface *iface);
|
|
|
|
G_DEFINE_TYPE_WITH_CODE (NautilusSearchEngine,
|
|
nautilus_search_engine,
|
|
G_TYPE_OBJECT,
|
|
G_IMPLEMENT_INTERFACE (NAUTILUS_TYPE_SEARCH_PROVIDER,
|
|
nautilus_search_provider_init))
|
|
|
|
static void
|
|
nautilus_search_engine_set_query (NautilusSearchProvider *provider,
|
|
NautilusQuery *query)
|
|
{
|
|
NautilusSearchEngine *engine = NAUTILUS_SEARCH_ENGINE (provider);
|
|
#ifdef ENABLE_TRACKER
|
|
nautilus_search_provider_set_query (NAUTILUS_SEARCH_PROVIDER (engine->details->tracker), query);
|
|
#endif
|
|
nautilus_search_provider_set_query (NAUTILUS_SEARCH_PROVIDER (engine->details->model), query);
|
|
nautilus_search_provider_set_query (NAUTILUS_SEARCH_PROVIDER (engine->details->simple), query);
|
|
}
|
|
|
|
static void
|
|
search_engine_start_real (NautilusSearchEngine *engine)
|
|
{
|
|
engine->details->providers_running = 0;
|
|
engine->details->providers_finished = 0;
|
|
engine->details->providers_error = 0;
|
|
|
|
engine->details->restart = FALSE;
|
|
|
|
DEBUG ("Search engine start real");
|
|
|
|
g_object_ref (engine);
|
|
|
|
#ifdef ENABLE_TRACKER
|
|
nautilus_search_provider_start (NAUTILUS_SEARCH_PROVIDER (engine->details->tracker));
|
|
engine->details->providers_running++;
|
|
#endif
|
|
if (nautilus_search_engine_model_get_model (engine->details->model)) {
|
|
nautilus_search_provider_start (NAUTILUS_SEARCH_PROVIDER (engine->details->model));
|
|
engine->details->providers_running++;
|
|
}
|
|
|
|
nautilus_search_provider_start (NAUTILUS_SEARCH_PROVIDER (engine->details->simple));
|
|
engine->details->providers_running++;
|
|
}
|
|
|
|
static void
|
|
nautilus_search_engine_start (NautilusSearchProvider *provider)
|
|
{
|
|
NautilusSearchEngine *engine = NAUTILUS_SEARCH_ENGINE (provider);
|
|
gint num_finished;
|
|
|
|
DEBUG ("Search engine start");
|
|
|
|
num_finished = engine->details->providers_error + engine->details->providers_finished;
|
|
|
|
if (engine->details->running) {
|
|
if (num_finished == engine->details->providers_running &&
|
|
engine->details->restart) {
|
|
search_engine_start_real (engine);
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
engine->details->running = TRUE;
|
|
|
|
if (num_finished < engine->details->providers_running) {
|
|
engine->details->restart = TRUE;
|
|
} else {
|
|
search_engine_start_real (engine);
|
|
}
|
|
}
|
|
|
|
static void
|
|
nautilus_search_engine_stop (NautilusSearchProvider *provider)
|
|
{
|
|
NautilusSearchEngine *engine = NAUTILUS_SEARCH_ENGINE (provider);
|
|
|
|
DEBUG ("Search engine stop");
|
|
|
|
#ifdef ENABLE_TRACKER
|
|
nautilus_search_provider_stop (NAUTILUS_SEARCH_PROVIDER (engine->details->tracker));
|
|
#endif
|
|
nautilus_search_provider_stop (NAUTILUS_SEARCH_PROVIDER (engine->details->model));
|
|
nautilus_search_provider_stop (NAUTILUS_SEARCH_PROVIDER (engine->details->simple));
|
|
|
|
engine->details->running = FALSE;
|
|
engine->details->restart = FALSE;
|
|
}
|
|
|
|
static void
|
|
search_provider_hits_added (NautilusSearchProvider *provider,
|
|
GList *hits,
|
|
NautilusSearchEngine *engine)
|
|
{
|
|
GList *added = NULL;
|
|
GList *l;
|
|
|
|
if (!engine->details->running || engine->details->restart) {
|
|
DEBUG ("Ignoring hits-added, since engine is %s",
|
|
!engine->details->running ? "not running" : "waiting to restart");
|
|
return;
|
|
}
|
|
|
|
for (l = hits; l != NULL; l = l->next) {
|
|
NautilusSearchHit *hit = l->data;
|
|
int count;
|
|
const char *uri;
|
|
|
|
uri = nautilus_search_hit_get_uri (hit);
|
|
count = GPOINTER_TO_INT (g_hash_table_lookup (engine->details->uris, uri));
|
|
if (count == 0)
|
|
added = g_list_prepend (added, hit);
|
|
g_hash_table_replace (engine->details->uris, g_strdup (uri), GINT_TO_POINTER (++count));
|
|
}
|
|
if (added != NULL) {
|
|
added = g_list_reverse (added);
|
|
nautilus_search_provider_hits_added (NAUTILUS_SEARCH_PROVIDER (engine), added);
|
|
g_list_free (added);
|
|
}
|
|
}
|
|
|
|
static void
|
|
check_providers_status (NautilusSearchEngine *engine)
|
|
{
|
|
gint num_finished = engine->details->providers_error + engine->details->providers_finished;
|
|
|
|
if (num_finished < engine->details->providers_running) {
|
|
return;
|
|
}
|
|
|
|
if (num_finished == engine->details->providers_error) {
|
|
DEBUG ("Search engine error");
|
|
nautilus_search_provider_error (NAUTILUS_SEARCH_PROVIDER (engine),
|
|
_("Unable to complete the requested search"));
|
|
} else {
|
|
if (engine->details->restart) {
|
|
DEBUG ("Search engine finished and restarting");
|
|
} else {
|
|
DEBUG ("Search engine finished");
|
|
}
|
|
nautilus_search_provider_finished (NAUTILUS_SEARCH_PROVIDER (engine),
|
|
engine->details->restart ? NAUTILUS_SEARCH_PROVIDER_STATUS_RESTARTING :
|
|
NAUTILUS_SEARCH_PROVIDER_STATUS_NORMAL);
|
|
}
|
|
|
|
engine->details->running = FALSE;
|
|
g_hash_table_remove_all (engine->details->uris);
|
|
|
|
if (engine->details->restart) {
|
|
nautilus_search_engine_start (NAUTILUS_SEARCH_PROVIDER (engine));
|
|
}
|
|
|
|
g_object_unref (engine);
|
|
}
|
|
|
|
static void
|
|
search_provider_error (NautilusSearchProvider *provider,
|
|
const char *error_message,
|
|
NautilusSearchEngine *engine)
|
|
|
|
{
|
|
DEBUG ("Search provider error: %s", error_message);
|
|
engine->details->providers_error++;
|
|
|
|
check_providers_status (engine);
|
|
}
|
|
|
|
static void
|
|
search_provider_finished (NautilusSearchProvider *provider,
|
|
NautilusSearchProviderStatus status,
|
|
NautilusSearchEngine *engine)
|
|
|
|
{
|
|
DEBUG ("Search provider finished");
|
|
engine->details->providers_finished++;
|
|
|
|
check_providers_status (engine);
|
|
}
|
|
|
|
static void
|
|
connect_provider_signals (NautilusSearchEngine *engine,
|
|
NautilusSearchProvider *provider)
|
|
{
|
|
g_signal_connect (provider, "hits-added",
|
|
G_CALLBACK (search_provider_hits_added),
|
|
engine);
|
|
g_signal_connect (provider, "finished",
|
|
G_CALLBACK (search_provider_finished),
|
|
engine);
|
|
g_signal_connect (provider, "error",
|
|
G_CALLBACK (search_provider_error),
|
|
engine);
|
|
}
|
|
|
|
static void
|
|
nautilus_search_provider_init (NautilusSearchProviderIface *iface)
|
|
{
|
|
iface->set_query = nautilus_search_engine_set_query;
|
|
iface->start = nautilus_search_engine_start;
|
|
iface->stop = nautilus_search_engine_stop;
|
|
}
|
|
|
|
static void
|
|
nautilus_search_engine_finalize (GObject *object)
|
|
{
|
|
NautilusSearchEngine *engine = NAUTILUS_SEARCH_ENGINE (object);
|
|
|
|
g_hash_table_destroy (engine->details->uris);
|
|
|
|
#ifdef ENABLE_TRACKER
|
|
g_clear_object (&engine->details->tracker);
|
|
#endif
|
|
g_clear_object (&engine->details->model);
|
|
g_clear_object (&engine->details->simple);
|
|
|
|
G_OBJECT_CLASS (nautilus_search_engine_parent_class)->finalize (object);
|
|
}
|
|
|
|
static void
|
|
nautilus_search_engine_class_init (NautilusSearchEngineClass *class)
|
|
{
|
|
GObjectClass *object_class;
|
|
|
|
object_class = (GObjectClass *) class;
|
|
|
|
object_class->finalize = nautilus_search_engine_finalize;
|
|
|
|
g_type_class_add_private (class, sizeof (NautilusSearchEngineDetails));
|
|
}
|
|
|
|
static void
|
|
nautilus_search_engine_init (NautilusSearchEngine *engine)
|
|
{
|
|
engine->details = G_TYPE_INSTANCE_GET_PRIVATE (engine,
|
|
NAUTILUS_TYPE_SEARCH_ENGINE,
|
|
NautilusSearchEngineDetails);
|
|
|
|
engine->details->uris = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
|
|
|
|
#ifdef ENABLE_TRACKER
|
|
engine->details->tracker = nautilus_search_engine_tracker_new ();
|
|
connect_provider_signals (engine, NAUTILUS_SEARCH_PROVIDER (engine->details->tracker));
|
|
#endif
|
|
engine->details->model = nautilus_search_engine_model_new ();
|
|
connect_provider_signals (engine, NAUTILUS_SEARCH_PROVIDER (engine->details->model));
|
|
|
|
engine->details->simple = nautilus_search_engine_simple_new ();
|
|
connect_provider_signals (engine, NAUTILUS_SEARCH_PROVIDER (engine->details->simple));
|
|
}
|
|
|
|
NautilusSearchEngine *
|
|
nautilus_search_engine_new (void)
|
|
{
|
|
NautilusSearchEngine *engine;
|
|
|
|
engine = g_object_new (NAUTILUS_TYPE_SEARCH_ENGINE, NULL);
|
|
|
|
return engine;
|
|
}
|
|
|
|
NautilusSearchEngineModel *
|
|
nautilus_search_engine_get_model_provider (NautilusSearchEngine *engine)
|
|
{
|
|
return engine->details->model;
|
|
}
|
|
|
|
NautilusSearchEngineSimple *
|
|
nautilus_search_engine_get_simple_provider (NautilusSearchEngine *engine)
|
|
{
|
|
return engine->details->simple;
|
|
}
|