gtk2/gtk+-2.10.8-search.patch

4434 lines
132 KiB
Diff
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

--- /dev/null 2007-01-30 22:42:40.851021051 -0500
+++ gtk+-2.10.9/gtk/gtksearchenginetracker.h 2007-01-30 23:27:42.000000000 -0500
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2005 Mr Jamie McCracken
+ *
+ * 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, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ *
+ * Author: Jamie McCracken (jamiemcc@gnome.org)
+ *
+ * Based on nautilus-search-engine-tracker.h
+ */
+
+#ifndef __GTK_SEARCH_ENGINE_TRACKER_H__
+#define __GTK_SEARCH_ENGINE_TRACKER_H__
+
+#include "gtksearchengine.h"
+
+G_BEGIN_DECLS
+
+#define GTK_TYPE_SEARCH_ENGINE_TRACKER (_gtk_search_engine_tracker_get_type ())
+#define GTK_SEARCH_ENGINE_TRACKER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GTK_TYPE_SEARCH_ENGINE_TRACKER, GtkSearchEngineTracker))
+#define GTK_SEARCH_ENGINE_TRACKER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GTK_TYPE_SEARCH_ENGINE_TRACKER, GtkSearchEngineTrackerClass))
+#define GTK_IS_SEARCH_ENGINE_TRACKER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GTK_TYPE_SEARCH_ENGINE_TRACKER))
+#define GTK_IS_SEARCH_ENGINE_TRACKER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GTK_TYPE_SEARCH_ENGINE_TRACKER))
+#define GTK_SEARCH_ENGINE_TRACKER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GTK_TYPE_SEARCH_ENGINE_TRACKER, GtkSearchEngineTrackerClass))
+
+typedef struct _GtkSearchEngineTracker GtkSearchEngineTracker;
+typedef struct _GtkSearchEngineTrackerClass GtkSearchEngineTrackerClass;
+typedef struct _GtkSearchEngineTrackerPrivate GtkSearchEngineTrackerPrivate;
+
+struct _GtkSearchEngineTracker
+{
+ GtkSearchEngine parent;
+
+ GtkSearchEngineTrackerPrivate *priv;
+};
+
+struct _GtkSearchEngineTrackerClass
+{
+ GtkSearchEngineClass parent_class;
+};
+
+GType _gtk_search_engine_tracker_get_type (void);
+
+GtkSearchEngine* _gtk_search_engine_tracker_new (void);
+
+G_END_DECLS
+
+#endif /* __GTK_SEARCH_ENGINE_TRACKER_H__ */
--- /dev/null 2007-01-30 22:42:40.851021051 -0500
+++ gtk+-2.10.9/gtk/gtksearchengine.h 2007-01-30 23:27:42.000000000 -0500
@@ -0,0 +1,91 @@
+/*
+ * Copyright (C) 2005 Novell, 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, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ *
+ * Author: Anders Carlsson <andersca@imendio.com>
+ *
+ * Based on nautilus-search-engine.h
+ */
+
+#ifndef __GTK_SEARCH_ENGINE_H__
+#define __GTK_SEARCH_ENGINE_H__
+
+#include <glib-object.h>
+#include "gtkquery.h"
+
+G_BEGIN_DECLS
+
+#define GTK_TYPE_SEARCH_ENGINE (_gtk_search_engine_get_type ())
+#define GTK_SEARCH_ENGINE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GTK_TYPE_SEARCH_ENGINE, GtkSearchEngine))
+#define GTK_SEARCH_ENGINE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GTK_TYPE_SEARCH_ENGINE, GtkSearchEngineClass))
+#define GTK_IS_SEARCH_ENGINE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GTK_TYPE_SEARCH_ENGINE))
+#define GTK_IS_SEARCH_ENGINE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GTK_TYPE_SEARCH_ENGINE))
+#define GTK_SEARCH_ENGINE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GTK_TYPE_SEARCH_ENGINE, GtkSearchEngineClass))
+
+typedef struct _GtkSearchEngine GtkSearchEngine;
+typedef struct _GtkSearchEngineClass GtkSearchEngineClass;
+typedef struct _GtkSearchEnginePrivate GtkSearchEnginePrivate;
+
+struct _GtkSearchEngine
+{
+ GObject parent;
+
+ GtkSearchEnginePrivate *priv;
+};
+
+struct _GtkSearchEngineClass
+{
+ GObjectClass parent_class;
+
+ /* VTable */
+ void (*set_query) (GtkSearchEngine *engine,
+ GtkQuery *query);
+ void (*start) (GtkSearchEngine *engine);
+ void (*stop) (GtkSearchEngine *engine);
+ gboolean (*is_indexed) (GtkSearchEngine *engine);
+
+ /* Signals */
+ void (*hits_added) (GtkSearchEngine *engine,
+ GList *hits);
+ void (*hits_subtracted) (GtkSearchEngine *engine,
+ GList *hits);
+ void (*finished) (GtkSearchEngine *engine);
+ void (*error) (GtkSearchEngine *engine,
+ const gchar *error_message);
+};
+
+GType _gtk_search_engine_get_type (void);
+gboolean _gtk_search_engine_enabled (void);
+
+GtkSearchEngine* _gtk_search_engine_new (void);
+
+void _gtk_search_engine_set_query (GtkSearchEngine *engine,
+ GtkQuery *query);
+void _gtk_search_engine_start (GtkSearchEngine *engine);
+void _gtk_search_engine_stop (GtkSearchEngine *engine);
+gboolean _gtk_search_engine_is_indexed (GtkSearchEngine *engine);
+
+void _gtk_search_engine_hits_added (GtkSearchEngine *engine,
+ GList *hits);
+void _gtk_search_engine_hits_subtracted (GtkSearchEngine *engine,
+ GList *hits);
+void _gtk_search_engine_finished (GtkSearchEngine *engine);
+void _gtk_search_engine_error (GtkSearchEngine *engine,
+ const gchar *error_message);
+
+G_END_DECLS
+
+#endif /* __GTK_SEARCH_ENGINE_H__ */
--- /dev/null 2007-01-30 22:42:40.851021051 -0500
+++ gtk+-2.10.9/gtk/gtksearchenginebeagle.h 2007-01-30 23:27:42.000000000 -0500
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2005 Novell, 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, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ *
+ * Author: Anders Carlsson <andersca@imendio.com>
+ *
+ * Based on nautilus-search-engine-beagle.h
+ */
+
+#ifndef __GTK_SEARCH_ENGINE_BEAGLE_H__
+#define __GTK_SEARCH_ENGINE_BEAGLE_H__
+
+#include "gtksearchengine.h"
+
+G_BEGIN_DECLS
+
+#define GTK_TYPE_SEARCH_ENGINE_BEAGLE (_gtk_search_engine_beagle_get_type ())
+#define GTK_SEARCH_ENGINE_BEAGLE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GTK_TYPE_SEARCH_ENGINE_BEAGLE, GtkSearchEngineBeagle))
+#define GTK_SEARCH_ENGINE_BEAGLE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GTK_TYPE_SEARCH_ENGINE_BEAGLE, GtkSearchEngineBeagleClass))
+#define GTK_IS_SEARCH_ENGINE_BEAGLE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GTK_TYPE_SEARCH_ENGINE_BEAGLE))
+#define GTK_IS_SEARCH_ENGINE_BEAGLE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GTK_TYPE_SEARCH_ENGINE_BEAGLE))
+#define GTK_SEARCH_ENGINE_BEAGLE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GTK_TYPE_SEARCH_ENGINE_BEAGLE, GtkSearchEngineBeagleClass))
+
+typedef struct _GtkSearchEngineBeagle GtkSearchEngineBeagle;
+typedef struct _GtkSearchEngineBeagleClass GtkSearchEngineBeagleClass;
+typedef struct _GtkSearchEngineBeaglePrivate GtkSearchEngineBeaglePrivate;
+
+struct _GtkSearchEngineBeagle
+{
+ GtkSearchEngine parent;
+
+ GtkSearchEngineBeaglePrivate *priv;
+};
+
+struct _GtkSearchEngineBeagleClass
+{
+ GtkSearchEngineClass parent_class;
+};
+
+GType _gtk_search_engine_beagle_get_type (void);
+
+GtkSearchEngine* _gtk_search_engine_beagle_new (void);
+
+G_END_DECLS
+
+#endif /* __GTK_SEARCH_ENGINE_BEAGLE_H__ */
--- /dev/null 2007-01-30 22:42:40.851021051 -0500
+++ gtk+-2.10.9/gtk/gtksearchengine.c 2007-01-30 23:27:42.000000000 -0500
@@ -0,0 +1,197 @@
+/*
+ * Copyright (C) 2005 Novell, 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, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ *
+ * Author: Anders Carlsson <andersca@imendio.com>
+ *
+ * Based on nautilus-search-engine.c
+ */
+
+#include <config.h>
+#include "gtksearchengine.h"
+#include "gtksearchenginebeagle.h"
+#include "gtksearchenginesimple.h"
+#include "gtksearchenginetracker.h"
+
+#define HAVE_BEAGLE 1
+#define HAVE_TRACKER 1
+
+enum
+{
+ HITS_ADDED,
+ HITS_SUBTRACTED,
+ FINISHED,
+ ERROR,
+ LAST_SIGNAL
+};
+
+static guint signals[LAST_SIGNAL];
+
+G_DEFINE_ABSTRACT_TYPE (GtkSearchEngine, _gtk_search_engine, G_TYPE_OBJECT);
+
+static void
+finalize (GObject *object)
+{
+ G_OBJECT_CLASS (_gtk_search_engine_parent_class)->finalize (object);
+}
+
+static void
+_gtk_search_engine_class_init (GtkSearchEngineClass *class)
+{
+ GObjectClass *gobject_class;
+
+ gobject_class = G_OBJECT_CLASS (class);
+ gobject_class->finalize = finalize;
+
+ signals[HITS_ADDED] =
+ g_signal_new ("hits-added",
+ G_TYPE_FROM_CLASS (class),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (GtkSearchEngineClass, hits_added),
+ NULL, NULL,
+ g_cclosure_marshal_VOID__POINTER,
+ G_TYPE_NONE, 1,
+ G_TYPE_POINTER);
+
+ signals[HITS_SUBTRACTED] =
+ g_signal_new ("hits-subtracted",
+ G_TYPE_FROM_CLASS (class),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (GtkSearchEngineClass, hits_subtracted),
+ NULL, NULL,
+ g_cclosure_marshal_VOID__POINTER,
+ G_TYPE_NONE, 1,
+ G_TYPE_POINTER);
+
+ signals[FINISHED] =
+ g_signal_new ("finished",
+ G_TYPE_FROM_CLASS (class),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (GtkSearchEngineClass, finished),
+ NULL, NULL,
+ g_cclosure_marshal_VOID__VOID,
+ G_TYPE_NONE, 0);
+
+ signals[ERROR] =
+ g_signal_new ("error",
+ G_TYPE_FROM_CLASS (class),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (GtkSearchEngineClass, error),
+ NULL, NULL,
+ g_cclosure_marshal_VOID__STRING,
+ G_TYPE_NONE, 1,
+ G_TYPE_STRING);
+}
+
+static void
+_gtk_search_engine_init (GtkSearchEngine *engine)
+{
+}
+
+GtkSearchEngine *
+_gtk_search_engine_new (void)
+{
+ GtkSearchEngine *engine;
+
+#ifdef HAVE_BEAGLE
+ engine = _gtk_search_engine_beagle_new ();
+ if (engine)
+ return engine;
+#endif
+
+#ifdef HAVE_TRACKER
+ engine = _gtk_search_engine_tracker_new ();
+ if (engine)
+ return engine;
+#endif
+
+ engine = _gtk_search_engine_simple_new ();
+ return engine;
+}
+
+void
+_gtk_search_engine_set_query (GtkSearchEngine *engine,
+ GtkQuery *query)
+{
+ g_return_if_fail (GTK_IS_SEARCH_ENGINE (engine));
+ g_return_if_fail (GTK_SEARCH_ENGINE_GET_CLASS (engine)->set_query != NULL);
+
+ GTK_SEARCH_ENGINE_GET_CLASS (engine)->set_query (engine, query);
+}
+
+void
+_gtk_search_engine_start (GtkSearchEngine *engine)
+{
+ g_return_if_fail (GTK_IS_SEARCH_ENGINE (engine));
+ g_return_if_fail (GTK_SEARCH_ENGINE_GET_CLASS (engine)->start != NULL);
+
+ GTK_SEARCH_ENGINE_GET_CLASS (engine)->start (engine);
+}
+
+void
+_gtk_search_engine_stop (GtkSearchEngine *engine)
+{
+ g_return_if_fail (GTK_IS_SEARCH_ENGINE (engine));
+ g_return_if_fail (GTK_SEARCH_ENGINE_GET_CLASS (engine)->stop != NULL);
+
+ GTK_SEARCH_ENGINE_GET_CLASS (engine)->stop (engine);
+}
+
+gboolean
+_gtk_search_engine_is_indexed (GtkSearchEngine *engine)
+{
+ g_return_val_if_fail (GTK_IS_SEARCH_ENGINE (engine), FALSE);
+ g_return_val_if_fail (GTK_SEARCH_ENGINE_GET_CLASS (engine)->is_indexed != NULL, FALSE);
+
+ return GTK_SEARCH_ENGINE_GET_CLASS (engine)->is_indexed (engine);
+}
+
+void
+_gtk_search_engine_hits_added (GtkSearchEngine *engine,
+ GList *hits)
+{
+ g_return_if_fail (GTK_IS_SEARCH_ENGINE (engine));
+
+ g_signal_emit (engine, signals[HITS_ADDED], 0, hits);
+}
+
+
+void
+_gtk_search_engine_hits_subtracted (GtkSearchEngine *engine,
+ GList *hits)
+{
+ g_return_if_fail (GTK_IS_SEARCH_ENGINE (engine));
+
+ g_signal_emit (engine, signals[HITS_SUBTRACTED], 0, hits);
+}
+
+
+void
+_gtk_search_engine_finished (GtkSearchEngine *engine)
+{
+ g_return_if_fail (GTK_IS_SEARCH_ENGINE (engine));
+
+ g_signal_emit (engine, signals[FINISHED], 0);
+}
+
+void
+_gtk_search_engine_error (GtkSearchEngine *engine,
+ const gchar *error_message)
+{
+ g_return_if_fail (GTK_IS_SEARCH_ENGINE (engine));
+
+ g_signal_emit (engine, signals[ERROR], 0, error_message);
+}
--- /dev/null 2007-01-30 22:42:40.851021051 -0500
+++ gtk+-2.10.9/gtk/gtksearchenginetracker.c 2007-01-30 23:27:42.000000000 -0500
@@ -0,0 +1,362 @@
+/*
+ * Copyright (C) 2005 Mr Jamie McCracken
+ *
+ * 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, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ *
+ * Author: Jamie McCracken <jamiemcc@gnome.org>
+ *
+ * Based on nautilus-search-engine-tracker.c
+ */
+
+#include <config.h>
+#include <gmodule.h>
+#include "gtksearchenginetracker.h"
+#if 0
+#include <tracker.h>
+#endif
+
+typedef struct _TrackerClient TrackerClient;
+
+typedef void (*TrackerArrayReply) (char **result, GError *error, gpointer user_data);
+
+static TrackerClient * (*tracker_connect) (gboolean enable_warnings) = NULL;
+static void (*tracker_disconnect) (TrackerClient *client) = NULL;
+static void (*tracker_cancel_last_call) (TrackerClient *client) = NULL;
+
+static void (*tracker_search_metadata_by_text_async) (TrackerClient *client,
+ const char *query,
+ TrackerArrayReply callback,
+ gpointer user_data) = NULL;
+static void (*tracker_search_metadata_by_text_and_mime_async) (TrackerClient *client,
+ const char *query,
+ const char **mimes,
+ TrackerArrayReply callback,
+ gpointer user_data) = NULL;
+static void (*tracker_search_metadata_by_text_and_location_async) (TrackerClient *client,
+ const char *query,
+ const char *location,
+ TrackerArrayReply callback,
+ gpointer user_data) = NULL;
+static void (*tracker_search_metadata_by_text_and_mime_and_location_async) (TrackerClient *client,
+ const char *query,
+ const char **mimes,
+ const char *location,
+ TrackerArrayReply callback,
+ gpointer user_data) = NULL;
+
+static struct TrackerDlMapping
+{
+ const char *fn_name;
+ gpointer *fn_ptr_ref;
+} tracker_dl_mapping[] =
+{
+#define MAP(a) { #a, (gpointer *)&a }
+ MAP (tracker_connect),
+ MAP (tracker_disconnect),
+ MAP (tracker_cancel_last_call),
+ MAP (tracker_search_metadata_by_text_async),
+ MAP (tracker_search_metadata_by_text_and_mime_async),
+ MAP (tracker_search_metadata_by_text_and_location_async),
+ MAP (tracker_search_metadata_by_text_and_mime_and_location_async)
+#undef MAP
+};
+
+static void
+open_libtracker (void)
+{
+ static gboolean done = FALSE;
+
+ if (!done)
+ {
+ int i;
+ GModule *tracker;
+
+ done = TRUE;
+
+ tracker = g_module_open ("libtracker.so.0", G_MODULE_BIND_LAZY | G_MODULE_BIND_LOCAL);
+ if (!tracker)
+ return;
+
+ for (i = 0; i < G_N_ELEMENTS (tracker_dl_mapping); i++)
+ {
+ if (!g_module_symbol (tracker, tracker_dl_mapping[i].fn_name,
+ tracker_dl_mapping[i].fn_ptr_ref))
+ {
+ g_warning ("Missing symbol '%s' in libtracker\n",
+ tracker_dl_mapping[i].fn_name);
+ g_module_close (tracker);
+
+ for (i = 0; i < G_N_ELEMENTS (tracker_dl_mapping); i++)
+ tracker_dl_mapping[i].fn_ptr_ref = NULL;
+
+ return;
+ }
+ }
+ }
+}
+
+struct _GtkSearchEngineTrackerPrivate
+{
+ GtkQuery *query;
+ TrackerClient *client;
+ gboolean query_pending;
+};
+
+G_DEFINE_TYPE (GtkSearchEngineTracker, _gtk_search_engine_tracker, GTK_TYPE_SEARCH_ENGINE);
+
+
+static void
+finalize (GObject *object)
+{
+ GtkSearchEngineTracker *tracker;
+
+ tracker = GTK_SEARCH_ENGINE_TRACKER (object);
+
+ if (tracker->priv->query)
+ {
+ g_object_unref (tracker->priv->query);
+ tracker->priv->query = NULL;
+ }
+
+ tracker_disconnect (tracker->priv->client);
+
+ G_OBJECT_CLASS (_gtk_search_engine_tracker_parent_class)->finalize (object);
+}
+
+
+static void
+search_callback (gchar **results,
+ GError *error,
+ gpointer user_data)
+{
+ GtkSearchEngineTracker *tracker;
+ gchar **results_p;
+ GList *hit_uris;
+
+ tracker = GTK_SEARCH_ENGINE_TRACKER (user_data);
+ hit_uris = NULL;
+
+ tracker->priv->query_pending = FALSE;
+
+ if (error)
+ {
+ _gtk_search_engine_error ( GTK_SEARCH_ENGINE (tracker), error->message);
+ g_error_free (error);
+ return;
+ }
+
+ if (!results)
+ return;
+
+ for (results_p = results; *results_p; results_p++)
+ {
+ gchar *uri;
+
+ uri = g_filename_to_uri ((char *)*results_p, NULL, NULL);
+ if (uri)
+ hit_uris = g_list_prepend (hit_uris, (char *)uri);
+ }
+
+ _gtk_search_engine_hits_added (GTK_SEARCH_ENGINE (tracker), hit_uris);
+ _gtk_search_engine_finished (GTK_SEARCH_ENGINE (tracker));
+
+ g_strfreev (results);
+ g_list_foreach (hit_uris, (GFunc)g_free, NULL);
+ g_list_free (hit_uris);
+}
+
+
+static void
+gtk_search_engine_tracker_start (GtkSearchEngine *engine)
+{
+ GtkSearchEngineTracker *tracker;
+ GList *mimetypes, *l;
+ gchar *search_text, *location, *location_uri;
+ gchar **mimes;
+ gint i, mime_count;
+
+ tracker = GTK_SEARCH_ENGINE_TRACKER (engine);
+
+ if (tracker->priv->query_pending)
+ return;
+
+ if (tracker->priv->query == NULL)
+ return;
+
+ search_text = _gtk_query_get_text (tracker->priv->query);
+
+ mimetypes = _gtk_query_get_mime_types (tracker->priv->query);
+
+ location_uri = _gtk_query_get_location (tracker->priv->query);
+
+ if (location_uri)
+ {
+ location = g_filename_from_uri (location_uri, NULL, NULL);
+ g_free (location_uri);
+ }
+ else
+ {
+ location = NULL;
+ }
+
+ mime_count = g_list_length (mimetypes);
+
+ i = 0;
+
+ /* convert list into array */
+ if (mime_count > 0)
+ {
+ mimes = g_new (gchar *, (mime_count + 1));
+
+ for (l = mimetypes; l != NULL; l = l->next)
+ {
+ mimes[i] = g_strdup (l->data);
+ i++;
+ }
+
+ mimes[mime_count] = NULL;
+
+ if (location)
+ {
+ tracker_search_metadata_by_text_and_mime_and_location_async (tracker->priv->client,
+ search_text, (const char **)mimes, location,
+ search_callback,
+ tracker);
+ g_free (location);
+ }
+ else
+ {
+ tracker_search_metadata_by_text_and_mime_async (tracker->priv->client,
+ search_text, (const char**)mimes,
+ search_callback,
+ tracker);
+ }
+
+ g_strfreev (mimes);
+
+
+ }
+ else
+ {
+ if (location)
+ {
+ tracker_search_metadata_by_text_and_location_async (tracker->priv->client,
+ search_text,
+ location,
+ search_callback,
+ tracker);
+ g_free (location);
+ }
+ else
+ {
+ tracker_search_metadata_by_text_async (tracker->priv->client,
+ search_text,
+ search_callback,
+ tracker);
+ }
+ }
+
+ tracker->priv->query_pending = TRUE;
+ g_free (search_text);
+ g_list_foreach (mimetypes, (GFunc)g_free, NULL);
+ g_list_free (mimetypes);
+}
+
+static void
+gtk_search_engine_tracker_stop (GtkSearchEngine *engine)
+{
+ GtkSearchEngineTracker *tracker;
+
+ tracker = GTK_SEARCH_ENGINE_TRACKER (engine);
+
+ if (tracker->priv->query && tracker->priv->query_pending)
+ {
+ tracker_cancel_last_call (tracker->priv->client);
+ tracker->priv->query_pending = FALSE;
+ }
+}
+
+static gboolean
+gtk_search_engine_tracker_is_indexed (GtkSearchEngine *engine)
+{
+ return TRUE;
+}
+
+static void
+gtk_search_engine_tracker_set_query (GtkSearchEngine *engine,
+ GtkQuery *query)
+{
+ GtkSearchEngineTracker *tracker;
+
+ tracker = GTK_SEARCH_ENGINE_TRACKER (engine);
+
+ if (query)
+ g_object_ref (query);
+
+ if (tracker->priv->query)
+ g_object_unref (tracker->priv->query);
+
+ tracker->priv->query = query;
+}
+
+static void
+_gtk_search_engine_tracker_class_init (GtkSearchEngineTrackerClass *class)
+{
+ GObjectClass *gobject_class;
+ GtkSearchEngineClass *engine_class;
+
+ gobject_class = G_OBJECT_CLASS (class);
+ gobject_class->finalize = finalize;
+
+ engine_class = GTK_SEARCH_ENGINE_CLASS (class);
+ engine_class->set_query = gtk_search_engine_tracker_set_query;
+ engine_class->start = gtk_search_engine_tracker_start;
+ engine_class->stop = gtk_search_engine_tracker_stop;
+ engine_class->is_indexed = gtk_search_engine_tracker_is_indexed;
+
+ g_type_class_add_private (gobject_class, sizeof (GtkSearchEngineTrackerPrivate));
+}
+
+static void
+_gtk_search_engine_tracker_init (GtkSearchEngineTracker *engine)
+{
+ engine->priv = G_TYPE_INSTANCE_GET_PRIVATE (engine, GTK_TYPE_SEARCH_ENGINE_TRACKER, GtkSearchEngineTrackerPrivate);
+}
+
+
+GtkSearchEngine *
+_gtk_search_engine_tracker_new (void)
+{
+ GtkSearchEngineTracker *engine;
+ TrackerClient *tracker_client;
+
+ open_libtracker ();
+
+ if (!tracker_connect)
+ return NULL;
+
+ tracker_client = tracker_connect (FALSE);
+
+ if (!tracker_client)
+ return NULL;
+
+ engine = g_object_new (GTK_TYPE_SEARCH_ENGINE_TRACKER, NULL);
+
+ engine->priv->client = tracker_client;
+
+ engine->priv->query_pending = FALSE;
+
+ return GTK_SEARCH_ENGINE (engine);
+}
--- gtk+-2.10.9/gtk/Makefile.am.search 2007-01-22 10:48:04.000000000 -0500
+++ gtk+-2.10.9/gtk/Makefile.am 2007-01-30 23:27:42.000000000 -0500
@@ -332,6 +332,11 @@
# GTK+ header files that don't get installed
gtk_private_h_sources = \
+ gtkquery.h \
+ gtksearchengine.h \
+ gtksearchenginebeagle.h \
+ gtksearchenginetracker.h\
+ gtksearchenginesimple.h \
gtkdndcursors.h \
gtkentryprivate.h \
gtkfilechooserdefault.h \
@@ -374,6 +379,11 @@
# GTK+ C sources to build the library from
gtk_base_c_sources = \
+ gtkquery.c \
+ gtksearchengine.c \
+ gtksearchenginebeagle.c \
+ gtksearchenginetracker.c\
+ gtksearchenginesimple.c \
fnmatch.c \
gtkaboutdialog.c \
gtkaccelgroup.c \
--- gtk+-2.10.9/gtk/gtkfilechooserdefault.c.search 2007-01-22 10:48:04.000000000 -0500
+++ gtk+-2.10.9/gtk/gtkfilechooserdefault.c 2007-01-30 23:27:42.000000000 -0500
@@ -78,6 +78,8 @@
#include <errno.h>
#include <string.h>
#include <time.h>
+#include <sys/stat.h>
+#include <sys/types.h>
@@ -171,13 +173,20 @@
SHORTCUTS_COL_PIXBUF,
SHORTCUTS_COL_NAME,
SHORTCUTS_COL_DATA,
- SHORTCUTS_COL_IS_VOLUME,
+ SHORTCUTS_COL_TYPE,
SHORTCUTS_COL_REMOVABLE,
SHORTCUTS_COL_PIXBUF_VISIBLE,
SHORTCUTS_COL_HANDLE,
SHORTCUTS_COL_NUM_COLUMNS
};
+typedef enum {
+ SHORTCUT_TYPE_PATH,
+ SHORTCUT_TYPE_VOLUME,
+ SHORTCUT_TYPE_SEPARATOR,
+ SHORTCUT_TYPE_SEARCH
+} ShortcutType;
+
/* Column numbers for the file list */
enum {
FILE_LIST_COL_NAME,
@@ -186,6 +195,16 @@
FILE_LIST_COL_NUM_COLUMNS
};
+/* Column numbers for the search model.
+ * Keep this in sync with search_setup_model()
+ */
+enum {
+ SEARCH_MODEL_COL_PATH,
+ SEARCH_MODEL_COL_DISPLAY_NAME,
+ SEARCH_MODEL_COL_COLLATION_KEY,
+ SEARCH_MODEL_COL_STAT
+};
+
/* Identifiers for target types */
enum {
GTK_TREE_MODEL_ROW,
@@ -225,9 +244,19 @@
static const int num_file_list_dest_targets = (sizeof (file_list_dest_targets)
/ sizeof (file_list_dest_targets[0]));
+static gboolean
+search_is_possible (GtkFileChooserDefault *impl)
+{
+ if (impl->search_engine == NULL)
+ impl->search_engine = _gtk_search_engine_new ();
+
+ return impl->search_engine != NULL;
+}
/* Interesting places in the shortcuts bar */
typedef enum {
+ SHORTCUTS_SEARCH,
+ SHORTCUTS_SEARCH_SEPARATOR,
SHORTCUTS_HOME,
SHORTCUTS_DESKTOP,
SHORTCUTS_VOLUMES,
@@ -419,6 +448,14 @@
GtkFileChooserDefault *impl);
static void location_switch_to_path_bar (GtkFileChooserDefault *impl);
+static void search_stop_searching (GtkFileChooserDefault *impl);
+static void search_clear_model (GtkFileChooserDefault *impl,
+ gboolean remove_from_treeview);
+static gboolean search_should_respond (GtkFileChooserDefault *impl);
+static void search_switch_to_browse_mode (GtkFileChooserDefault *impl);
+static GSList *search_get_selected_paths (GtkFileChooserDefault *impl);
+static void search_entry_activate_cb (GtkEntry *entry,
+ gpointer data);
@@ -428,26 +465,26 @@
GtkTreeModelFilter parent;
GtkFileChooserDefault *impl;
-} ShortcutsModelFilter;
+} ShortcutsPaneModelFilter;
typedef struct {
GtkTreeModelFilterClass parent_class;
-} ShortcutsModelFilterClass;
+} ShortcutsPaneModelFilterClass;
-#define SHORTCUTS_MODEL_FILTER_TYPE (_shortcuts_model_filter_get_type ())
-#define SHORTCUTS_MODEL_FILTER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), SHORTCUTS_MODEL_FILTER_TYPE, ShortcutsModelFilter))
+#define SHORTCUTS_PANE_MODEL_FILTER_TYPE (_shortcuts_pane_model_filter_get_type ())
+#define SHORTCUTS_PANE_MODEL_FILTER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), SHORTCUTS_PANE_MODEL_FILTER_TYPE, ShortcutsPaneModelFilter))
-static void shortcuts_model_filter_drag_source_iface_init (GtkTreeDragSourceIface *iface);
+static void shortcuts_pane_model_filter_drag_source_iface_init (GtkTreeDragSourceIface *iface);
-G_DEFINE_TYPE_WITH_CODE (ShortcutsModelFilter,
- _shortcuts_model_filter,
+G_DEFINE_TYPE_WITH_CODE (ShortcutsPaneModelFilter,
+ _shortcuts_pane_model_filter,
GTK_TYPE_TREE_MODEL_FILTER,
G_IMPLEMENT_INTERFACE (GTK_TYPE_TREE_DRAG_SOURCE,
- shortcuts_model_filter_drag_source_iface_init))
+ shortcuts_pane_model_filter_drag_source_iface_init))
-static GtkTreeModel *shortcuts_model_filter_new (GtkFileChooserDefault *impl,
- GtkTreeModel *child_model,
- GtkTreePath *root);
+static GtkTreeModel *shortcuts_pane_model_filter_new (GtkFileChooserDefault *impl,
+ GtkTreeModel *child_model,
+ GtkTreePath *root);
@@ -663,6 +700,7 @@
impl->reload_state = RELOAD_EMPTY;
impl->pending_select_paths = NULL;
impl->location_mode = LOCATION_MODE_PATH_BAR;
+ impl->operation_mode = OPERATION_MODE_BROWSE;
gtk_box_set_spacing (GTK_BOX (impl), 12);
@@ -678,22 +716,24 @@
GtkTreeIter *iter)
{
gpointer col_data;
- gboolean is_volume;
+ ShortcutType shortcut_type;
GtkFileSystemHandle *handle;
gtk_tree_model_get (GTK_TREE_MODEL (impl->shortcuts_model), iter,
SHORTCUTS_COL_DATA, &col_data,
- SHORTCUTS_COL_IS_VOLUME, &is_volume,
+ SHORTCUTS_COL_TYPE, &shortcut_type,
SHORTCUTS_COL_HANDLE, &handle,
-1);
if (handle)
gtk_file_system_cancel_operation (handle);
- if (!col_data)
+ if (!(shortcut_type == SHORTCUT_TYPE_PATH ||
+ shortcut_type == SHORTCUT_TYPE_VOLUME) ||
+ !col_data)
return;
- if (is_volume)
+ if (shortcut_type == SHORTCUT_TYPE_VOLUME)
{
GtkFileSystemVolume *volume;
@@ -704,6 +744,8 @@
{
GtkFilePath *path;
+ g_assert (shortcut_type == SHORTCUT_TYPE_PATH);
+
path = col_data;
gtk_file_path_free (path);
}
@@ -790,8 +832,11 @@
GtkFileChooserDefault *impl = GTK_FILE_CHOOSER_DEFAULT (object);
GSList *l;
- if (impl->shortcuts_filter_model)
- g_object_unref (impl->shortcuts_filter_model);
+ if (impl->shortcuts_pane_filter_model)
+ g_object_unref (impl->shortcuts_pane_filter_model);
+
+ if (impl->shortcuts_combo_filter_model)
+ g_object_unref (impl->shortcuts_combo_filter_model);
shortcuts_free (impl);
@@ -829,6 +874,8 @@
if (impl->sort_model)
g_object_unref (impl->sort_model);
+ search_clear_model (impl, FALSE);
+
g_free (impl->preview_display_name);
g_free (impl->edited_new_text);
@@ -1080,6 +1127,14 @@
update_preview_widget_visibility (impl);
}
+/* Renders a "Search" icon at an appropriate size for a tree view */
+static GdkPixbuf *
+render_search_icon (GtkFileChooserDefault *impl)
+{
+ return gtk_widget_render_icon (GTK_WIDGET (impl), GTK_STOCK_FIND, GTK_ICON_SIZE_SMALL_TOOLBAR, NULL);
+}
+
+
/* Re-reads all the icons for the shortcuts, used when the theme changes */
struct ReloadIconsData
{
@@ -1150,19 +1205,20 @@
do
{
gpointer data;
- gboolean is_volume;
+ ShortcutType shortcut_type;
gboolean pixbuf_visible;
GdkPixbuf *pixbuf;
gtk_tree_model_get (GTK_TREE_MODEL (impl->shortcuts_model), &iter,
SHORTCUTS_COL_DATA, &data,
- SHORTCUTS_COL_IS_VOLUME, &is_volume,
+ SHORTCUTS_COL_TYPE, &shortcut_type,
SHORTCUTS_COL_PIXBUF_VISIBLE, &pixbuf_visible,
-1);
- if (pixbuf_visible && data)
+ pixbuf = NULL;
+ if (pixbuf_visible)
{
- if (is_volume)
+ if (shortcut_type == SHORTCUT_TYPE_VOLUME)
{
GtkFileSystemVolume *volume;
@@ -1177,46 +1233,53 @@
if (pixbuf)
g_object_unref (pixbuf);
}
- else if (gtk_file_system_path_is_local (impl->file_system, (GtkFilePath *)data))
- {
- const GtkFilePath *path;
- struct ReloadIconsData *info;
- GtkTreePath *tree_path;
- GtkFileSystemHandle *handle;
-
- path = data;
-
- info = g_new0 (struct ReloadIconsData, 1);
- info->impl = g_object_ref (impl);
- tree_path = gtk_tree_model_get_path (GTK_TREE_MODEL (impl->shortcuts_model), &iter);
- info->row_ref = gtk_tree_row_reference_new (GTK_TREE_MODEL (impl->shortcuts_model), tree_path);
- gtk_tree_path_free (tree_path);
-
- handle = gtk_file_system_get_info (impl->file_system, path,
- GTK_FILE_INFO_ICON,
- shortcuts_reload_icons_get_info_cb,
- info);
- impl->reload_icon_handles = g_slist_append (impl->reload_icon_handles, handle);
- }
- else
+ else if (shortcut_type == SHORTCUT_TYPE_PATH)
+ {
+ if (gtk_file_system_path_is_local (impl->file_system, (GtkFilePath *)data))
+ {
+ const GtkFilePath *path;
+ struct ReloadIconsData *info;
+ GtkTreePath *tree_path;
+ GtkFileSystemHandle *handle;
+
+ path = data;
+
+ info = g_new0 (struct ReloadIconsData, 1);
+ info->impl = g_object_ref (impl);
+ tree_path = gtk_tree_model_get_path (GTK_TREE_MODEL (impl->shortcuts_model), &iter);
+ info->row_ref = gtk_tree_row_reference_new (GTK_TREE_MODEL (impl->shortcuts_model), tree_path);
+ gtk_tree_path_free (tree_path);
+
+ handle = gtk_file_system_get_info (impl->file_system, path,
+ GTK_FILE_INFO_ICON,
+ shortcuts_reload_icons_get_info_cb,
+ info);
+ impl->reload_icon_handles = g_slist_append (impl->reload_icon_handles, handle);
+ }
+ else
+ {
+ GtkIconTheme *icon_theme;
+
+ /* Don't call get_info for remote paths to avoid latency and
+ * auth dialogs.
+ * If we switch to a better bookmarks file format (XBEL), we
+ * should use mime info to get a better icon.
+ */
+ icon_theme = gtk_icon_theme_get_for_screen (gtk_widget_get_screen (GTK_WIDGET (impl)));
+ pixbuf = gtk_icon_theme_load_icon (icon_theme, "gnome-fs-directory",
+ impl->icon_size, 0, NULL);
+
+ gtk_list_store_set (impl->shortcuts_model, &iter,
+ SHORTCUTS_COL_PIXBUF, pixbuf,
+ -1);
+
+ if (pixbuf)
+ g_object_unref (pixbuf);
+ }
+ }
+ else if (shortcut_type == SHORTCUT_TYPE_SEARCH)
{
- GtkIconTheme *icon_theme;
-
- /* Don't call get_info for remote paths to avoid latency and
- * auth dialogs.
- * If we switch to a better bookmarks file format (XBEL), we
- * should use mime info to get a better icon.
- */
- icon_theme = gtk_icon_theme_get_for_screen (gtk_widget_get_screen (GTK_WIDGET (impl)));
- pixbuf = gtk_icon_theme_load_icon (icon_theme, "gnome-fs-directory",
- impl->icon_size, 0, NULL);
-
- gtk_list_store_set (impl->shortcuts_model, &iter,
- SHORTCUTS_COL_PIXBUF, pixbuf,
- -1);
-
- if (pixbuf)
- g_object_unref (pixbuf);
+ pixbuf = render_search_icon (impl);
}
}
}
@@ -1348,7 +1411,6 @@
{
gint pos = -1;
gboolean cancelled = handle->cancelled;
- gboolean is_volume = FALSE;
GdkPixbuf *pixbuf;
GtkTreePath *path;
GtkTreeIter iter;
@@ -1413,12 +1475,15 @@
SHORTCUTS_COL_PIXBUF, pixbuf,
SHORTCUTS_COL_PIXBUF_VISIBLE, TRUE,
SHORTCUTS_COL_NAME, request->label_copy,
- SHORTCUTS_COL_IS_VOLUME, is_volume,
+ SHORTCUTS_COL_TYPE, SHORTCUT_TYPE_PATH,
SHORTCUTS_COL_REMOVABLE, request->removable,
-1);
- if (request->impl->shortcuts_filter_model)
- gtk_tree_model_filter_refilter (GTK_TREE_MODEL_FILTER (request->impl->shortcuts_filter_model));
+ if (request->impl->shortcuts_pane_filter_model)
+ gtk_tree_model_filter_refilter (GTK_TREE_MODEL_FILTER (request->impl->shortcuts_pane_filter_model));
+
+ if (request->impl->shortcuts_combo_filter_model)
+ gtk_tree_model_filter_refilter (GTK_TREE_MODEL_FILTER (request->impl->shortcuts_combo_filter_model));
if (request->type == SHORTCUTS_CURRENT_FOLDER
&& request->impl->save_folder_combo != NULL)
@@ -1430,7 +1495,7 @@
g_signal_handlers_block_by_func (request->impl->save_folder_combo,
G_CALLBACK (save_folder_combo_changed_cb),
request->impl);
- gtk_combo_box_set_active (GTK_COMBO_BOX (request->impl->save_folder_combo), pos);
+ gtk_combo_box_set_active (GTK_COMBO_BOX (request->impl->save_folder_combo), request->impl->has_search ? pos - 2 : pos);
g_signal_handlers_unblock_by_func (request->impl->save_folder_combo,
G_CALLBACK (save_folder_combo_changed_cb),
request->impl);
@@ -1504,7 +1569,7 @@
static void
shortcuts_insert_path (GtkFileChooserDefault *impl,
int pos,
- gboolean is_volume,
+ ShortcutType shortcut_type,
GtkFileSystemVolume *volume,
const GtkFilePath *path,
const char *label,
@@ -1517,79 +1582,89 @@
GtkTreeIter iter;
GtkIconTheme *icon_theme;
- profile_start ("start", is_volume ? "volume" : (char *) path);
+ profile_start ("start", (shortcut_type == SHORTCUT_TYPE_VOLUME) ? "volume"
+ : ((shortcut_type == SHORTCUT_TYPE_PATH) ? (char *) path : NULL));
- if (is_volume)
+ if (shortcut_type == SHORTCUT_TYPE_VOLUME)
{
data = volume;
label_copy = gtk_file_system_volume_get_display_name (impl->file_system, volume);
pixbuf = gtk_file_system_volume_render_icon (impl->file_system, volume, GTK_WIDGET (impl),
impl->icon_size, NULL);
}
- else if (gtk_file_system_path_is_local (impl->file_system, path))
+ else if (shortcut_type == SHORTCUT_TYPE_PATH)
{
- struct ShortcutsInsertRequest *request;
- GtkFileSystemHandle *handle;
- GtkTreePath *p;
-
- request = g_new0 (struct ShortcutsInsertRequest, 1);
- request->impl = g_object_ref (impl);
- request->path = gtk_file_path_copy (path);
- request->name_only = TRUE;
- request->removable = removable;
- request->pos = pos;
- request->type = type;
- if (label)
- request->label_copy = g_strdup (label);
+ if (gtk_file_system_path_is_local (impl->file_system, path))
+ {
+ struct ShortcutsInsertRequest *request;
+ GtkFileSystemHandle *handle;
+ GtkTreePath *p;
+
+ request = g_new0 (struct ShortcutsInsertRequest, 1);
+ request->impl = g_object_ref (impl);
+ request->path = gtk_file_path_copy (path);
+ request->name_only = TRUE;
+ request->removable = removable;
+ request->pos = pos;
+ request->type = type;
+ if (label)
+ request->label_copy = g_strdup (label);
+
+ if (pos == -1)
+ gtk_list_store_append (impl->shortcuts_model, &iter);
+ else
+ gtk_list_store_insert (impl->shortcuts_model, &iter, pos);
+
+ p = gtk_tree_model_get_path (GTK_TREE_MODEL (impl->shortcuts_model), &iter);
+ request->row_ref = gtk_tree_row_reference_new (GTK_TREE_MODEL (impl->shortcuts_model), p);
+ gtk_tree_path_free (p);
+
+ handle = gtk_file_system_get_info (request->impl->file_system, request->path,
+ GTK_FILE_INFO_DISPLAY_NAME | GTK_FILE_INFO_IS_HIDDEN | GTK_FILE_INFO_ICON,
+ get_file_info_finished, request);
+
+ gtk_list_store_set (impl->shortcuts_model, &iter,
+ SHORTCUTS_COL_DATA, gtk_file_path_copy (path),
+ SHORTCUTS_COL_TYPE, SHORTCUT_TYPE_PATH,
+ SHORTCUTS_COL_HANDLE, handle,
+ -1);
- if (pos == -1)
- gtk_list_store_append (impl->shortcuts_model, &iter);
+ shortcuts_update_count (impl, type, 1);
+
+ return;
+ }
else
- gtk_list_store_insert (impl->shortcuts_model, &iter, pos);
+ {
+ /* Don't call get_info for remote paths to avoid latency and
+ * auth dialogs.
+ */
+ data = gtk_file_path_copy (path);
+ if (label)
+ label_copy = g_strdup (label);
+ else
+ {
+ gchar *uri;
- p = gtk_tree_model_get_path (GTK_TREE_MODEL (impl->shortcuts_model), &iter);
- request->row_ref = gtk_tree_row_reference_new (GTK_TREE_MODEL (impl->shortcuts_model), p);
- gtk_tree_path_free (p);
-
- handle = gtk_file_system_get_info (request->impl->file_system, request->path,
- GTK_FILE_INFO_DISPLAY_NAME | GTK_FILE_INFO_IS_HIDDEN | GTK_FILE_INFO_ICON,
- get_file_info_finished, request);
-
- gtk_list_store_set (impl->shortcuts_model, &iter,
- SHORTCUTS_COL_DATA, gtk_file_path_copy (path),
- SHORTCUTS_COL_IS_VOLUME, is_volume,
- SHORTCUTS_COL_HANDLE, handle,
- -1);
+ uri = gtk_file_system_path_to_uri (impl->file_system, path);
- shortcuts_update_count (impl, type, 1);
+ label_copy = _gtk_file_chooser_label_for_uri (uri);
- return;
+ g_free (uri);
+ }
+
+ /* If we switch to a better bookmarks file format (XBEL), we
+ * should use mime info to get a better icon.
+ */
+ icon_theme = gtk_icon_theme_get_for_screen (gtk_widget_get_screen (GTK_WIDGET (impl)));
+ pixbuf = gtk_icon_theme_load_icon (icon_theme, "gnome-fs-directory",
+ impl->icon_size, 0, NULL);
+ }
}
- else
+ else
{
- /* Don't call get_info for remote paths to avoid latency and
- * auth dialogs.
- */
- data = gtk_file_path_copy (path);
- if (label)
- label_copy = g_strdup (label);
- else
- {
- gchar *uri;
-
- uri = gtk_file_system_path_to_uri (impl->file_system, path);
-
- label_copy = _gtk_file_chooser_label_for_uri (uri);
+ g_assert_not_reached ();
- g_free (uri);
- }
-
- /* If we switch to a better bookmarks file format (XBEL), we
- * should use mime info to get a better icon.
- */
- icon_theme = gtk_icon_theme_get_for_screen (gtk_widget_get_screen (GTK_WIDGET (impl)));
- pixbuf = gtk_icon_theme_load_icon (icon_theme, "gnome-fs-directory",
- impl->icon_size, 0, NULL);
+ return;
}
if (pos == -1)
@@ -1604,13 +1679,16 @@
SHORTCUTS_COL_PIXBUF_VISIBLE, TRUE,
SHORTCUTS_COL_NAME, label_copy,
SHORTCUTS_COL_DATA, data,
- SHORTCUTS_COL_IS_VOLUME, is_volume,
+ SHORTCUTS_COL_TYPE, shortcut_type,
SHORTCUTS_COL_REMOVABLE, removable,
SHORTCUTS_COL_HANDLE, NULL,
-1);
- if (impl->shortcuts_filter_model)
- gtk_tree_model_filter_refilter (GTK_TREE_MODEL_FILTER (impl->shortcuts_filter_model));
+ if (impl->shortcuts_pane_filter_model)
+ gtk_tree_model_filter_refilter (GTK_TREE_MODEL_FILTER (impl->shortcuts_pane_filter_model));
+
+ if (impl->shortcuts_combo_filter_model)
+ gtk_tree_model_filter_refilter (GTK_TREE_MODEL_FILTER (impl->shortcuts_combo_filter_model));
if (type == SHORTCUTS_CURRENT_FOLDER && impl->save_folder_combo != NULL)
{
@@ -1622,7 +1700,8 @@
g_signal_handlers_block_by_func (impl->save_folder_combo,
G_CALLBACK (save_folder_combo_changed_cb),
impl);
- gtk_combo_box_set_active (GTK_COMBO_BOX (impl->save_folder_combo), combo_pos);
+ gtk_combo_box_set_active (GTK_COMBO_BOX (impl->save_folder_combo),
+ impl->has_search ? combo_pos - 2 : combo_pos);
g_signal_handlers_unblock_by_func (impl->save_folder_combo,
G_CALLBACK (save_folder_combo_changed_cb),
impl);
@@ -1636,6 +1715,30 @@
profile_end ("end", NULL);
}
+static void
+shortcuts_append_search (GtkFileChooserDefault *impl)
+{
+ GdkPixbuf *pixbuf;
+ GtkTreeIter iter;
+
+ pixbuf = render_search_icon (impl);
+
+ gtk_list_store_append (impl->shortcuts_model, &iter);
+ gtk_list_store_set (impl->shortcuts_model, &iter,
+ SHORTCUTS_COL_PIXBUF, pixbuf,
+ SHORTCUTS_COL_PIXBUF_VISIBLE, TRUE,
+ SHORTCUTS_COL_NAME, _("Search"),
+ SHORTCUTS_COL_DATA, NULL,
+ SHORTCUTS_COL_TYPE, SHORTCUT_TYPE_SEARCH,
+ SHORTCUTS_COL_REMOVABLE, FALSE,
+ -1);
+
+ if (pixbuf)
+ g_object_unref (pixbuf);
+
+ impl->has_search = TRUE;
+}
+
/* Appends an item for the user's home directory to the shortcuts model */
static void
shortcuts_append_home (GtkFileChooserDefault *impl)
@@ -1654,7 +1757,8 @@
home_path = gtk_file_system_filename_to_path (impl->file_system, home);
- shortcuts_insert_path (impl, -1, FALSE, NULL, home_path, NULL, FALSE, SHORTCUTS_HOME);
+ shortcuts_insert_path (impl, -1, SHORTCUT_TYPE_PATH, NULL, home_path, NULL, FALSE, SHORTCUTS_HOME);
+ impl->has_home = TRUE;
gtk_file_path_free (home_path);
@@ -1687,7 +1791,9 @@
path = gtk_file_system_filename_to_path (impl->file_system, name);
g_free (name);
- shortcuts_insert_path (impl, -1, FALSE, NULL, path, _("Desktop"), FALSE, SHORTCUTS_DESKTOP);
+ shortcuts_insert_path (impl, -1, SHORTCUT_TYPE_PATH, NULL, path, _("Desktop"), FALSE, SHORTCUTS_DESKTOP);
+ impl->has_desktop = TRUE;
+
/* We do not actually pop up an error dialog if there is no desktop directory
* because some people may really not want to have one.
*/
@@ -1726,7 +1832,7 @@
label = gtk_file_system_get_bookmark_label (impl->file_system, path);
/* NULL GError, but we don't really want to show error boxes here */
- shortcuts_insert_path (impl, start_row + num_inserted, FALSE, NULL, path, label, TRUE, SHORTCUTS_BOOKMARKS);
+ shortcuts_insert_path (impl, start_row + num_inserted, SHORTCUT_TYPE_PATH, NULL, path, label, TRUE, SHORTCUTS_BOOKMARKS);
num_inserted++;
g_free (label);
@@ -1745,6 +1851,16 @@
int n;
n = 0;
+
+ if (where == SHORTCUTS_SEARCH)
+ goto out;
+
+ n += impl->has_search ? 1 : 0;
+
+ if (where == SHORTCUTS_SEARCH_SEPARATOR)
+ goto out;
+
+ n += impl->has_search ? 1 : 0;
if (where == SHORTCUTS_HOME)
goto out;
@@ -1842,15 +1958,18 @@
}
}
- shortcuts_insert_path (impl, start_row + n, TRUE, volume, NULL, NULL, FALSE, SHORTCUTS_VOLUMES);
+ shortcuts_insert_path (impl, start_row + n, SHORTCUT_TYPE_VOLUME, volume, NULL, NULL, FALSE, SHORTCUTS_VOLUMES);
n++;
}
impl->num_volumes = n;
g_slist_free (list);
- if (impl->shortcuts_filter_model)
- gtk_tree_model_filter_refilter (GTK_TREE_MODEL_FILTER (impl->shortcuts_filter_model));
+ if (impl->shortcuts_pane_filter_model)
+ gtk_tree_model_filter_refilter (GTK_TREE_MODEL_FILTER (impl->shortcuts_pane_filter_model));
+
+ if (impl->shortcuts_combo_filter_model)
+ gtk_tree_model_filter_refilter (GTK_TREE_MODEL_FILTER (impl->shortcuts_combo_filter_model));
impl->changing_folder = old_changing_folders;
@@ -1860,11 +1979,13 @@
/* Inserts a separator node in the shortcuts list */
static void
shortcuts_insert_separator (GtkFileChooserDefault *impl,
- ShortcutsIndex where)
+ ShortcutsIndex where)
{
GtkTreeIter iter;
- g_assert (where == SHORTCUTS_BOOKMARKS_SEPARATOR || where == SHORTCUTS_CURRENT_FOLDER_SEPARATOR);
+ g_assert (where == SHORTCUTS_SEARCH_SEPARATOR ||
+ where == SHORTCUTS_BOOKMARKS_SEPARATOR ||
+ where == SHORTCUTS_CURRENT_FOLDER_SEPARATOR);
gtk_list_store_insert (impl->shortcuts_model, &iter,
shortcuts_get_index (impl, where));
@@ -1873,6 +1994,7 @@
SHORTCUTS_COL_PIXBUF_VISIBLE, FALSE,
SHORTCUTS_COL_NAME, NULL,
SHORTCUTS_COL_DATA, NULL,
+ SHORTCUTS_COL_TYPE, SHORTCUT_TYPE_SEPARATOR,
-1);
}
@@ -1885,7 +2007,7 @@
GtkTreeIter iter;
GtkFilePath *list_selected = NULL;
GtkFilePath *combo_selected = NULL;
- gboolean is_volume;
+ ShortcutType shortcut_type;
gpointer col_data;
profile_start ("start", NULL);
@@ -1898,10 +2020,10 @@
gtk_tree_model_get (GTK_TREE_MODEL (impl->shortcuts_model),
&iter,
SHORTCUTS_COL_DATA, &col_data,
- SHORTCUTS_COL_IS_VOLUME, &is_volume,
+ SHORTCUTS_COL_TYPE, &shortcut_type,
-1);
- if (col_data && !is_volume)
+ if (col_data && shortcut_type == SHORTCUT_TYPE_PATH)
list_selected = gtk_file_path_copy (col_data);
}
@@ -1909,13 +2031,18 @@
gtk_combo_box_get_active_iter (GTK_COMBO_BOX (impl->save_folder_combo),
&iter))
{
+ GtkTreeIter child_iter;
+
+ gtk_tree_model_filter_convert_iter_to_child_iter (GTK_TREE_MODEL_FILTER (impl->shortcuts_combo_filter_model),
+ &child_iter,
+ &iter);
gtk_tree_model_get (GTK_TREE_MODEL (impl->shortcuts_model),
- &iter,
+ &child_iter,
SHORTCUTS_COL_DATA, &col_data,
- SHORTCUTS_COL_IS_VOLUME, &is_volume,
+ SHORTCUTS_COL_TYPE, &shortcut_type,
-1);
- if (col_data && !is_volume)
+ if (col_data && shortcut_type == SHORTCUT_TYPE_PATH)
combo_selected = gtk_file_path_copy (col_data);
}
@@ -1933,8 +2060,11 @@
if (impl->num_bookmarks > 0)
shortcuts_insert_separator (impl, SHORTCUTS_BOOKMARKS_SEPARATOR);
- if (impl->shortcuts_filter_model)
- gtk_tree_model_filter_refilter (GTK_TREE_MODEL_FILTER (impl->shortcuts_filter_model));
+ if (impl->shortcuts_pane_filter_model)
+ gtk_tree_model_filter_refilter (GTK_TREE_MODEL_FILTER (impl->shortcuts_pane_filter_model));
+
+ if (impl->shortcuts_combo_filter_model)
+ gtk_tree_model_filter_refilter (GTK_TREE_MODEL_FILTER (impl->shortcuts_combo_filter_model));
if (list_selected)
{
@@ -1948,8 +2078,8 @@
pos = shortcut_find_position (impl, combo_selected);
if (pos != -1)
- gtk_combo_box_set_active (GTK_COMBO_BOX (impl->save_folder_combo),
- pos);
+ gtk_combo_box_set_active (GTK_COMBO_BOX (impl->save_folder_combo),
+ impl->has_search ? pos - 2 : pos);
gtk_file_path_free (combo_selected);
}
@@ -1994,11 +2124,11 @@
if (base_path &&
strcmp (gtk_file_path_get_string (base_path), gtk_file_path_get_string (impl->current_folder)) == 0)
{
- shortcuts_insert_path (impl, pos, TRUE, volume, NULL, NULL, FALSE, SHORTCUTS_CURRENT_FOLDER);
+ shortcuts_insert_path (impl, pos, SHORTCUT_TYPE_VOLUME, volume, NULL, NULL, FALSE, SHORTCUTS_CURRENT_FOLDER);
}
else
{
- shortcuts_insert_path (impl, pos, FALSE, NULL, impl->current_folder, NULL, FALSE, SHORTCUTS_CURRENT_FOLDER);
+ shortcuts_insert_path (impl, pos, SHORTCUT_TYPE_PATH, NULL, impl->current_folder, NULL, FALSE, SHORTCUTS_CURRENT_FOLDER);
if (volume)
gtk_file_system_volume_free (impl->file_system, volume);
}
@@ -2007,7 +2137,8 @@
gtk_file_path_free (base_path);
}
else if (impl->save_folder_combo != NULL)
- gtk_combo_box_set_active (GTK_COMBO_BOX (impl->save_folder_combo), pos);
+ gtk_combo_box_set_active (GTK_COMBO_BOX (impl->save_folder_combo),
+ impl->has_search ? pos - 2 : pos);
}
/* Updates the current folder row in the shortcuts model */
@@ -2029,9 +2160,9 @@
/* Filter function used for the shortcuts filter model */
static gboolean
-shortcuts_filter_cb (GtkTreeModel *model,
- GtkTreeIter *iter,
- gpointer data)
+shortcuts_pane_filter_cb (GtkTreeModel *model,
+ GtkTreeIter *iter,
+ gpointer data)
{
GtkFileChooserDefault *impl;
GtkTreePath *path;
@@ -2058,11 +2189,17 @@
GDK_TYPE_PIXBUF, /* pixbuf */
G_TYPE_STRING, /* name */
G_TYPE_POINTER, /* path or volume */
- G_TYPE_BOOLEAN, /* is the previous column a volume? */
+ G_TYPE_INT, /* ShortcutType */
G_TYPE_BOOLEAN, /* removable */
G_TYPE_BOOLEAN, /* pixbuf cell visibility */
G_TYPE_POINTER); /* GtkFileSystemHandle */
+ if (search_is_possible (impl))
+ {
+ shortcuts_append_search (impl);
+ shortcuts_insert_separator (impl, SHORTCUTS_SEARCH_SEPARATOR);
+ }
+
if (impl->file_system)
{
shortcuts_append_home (impl);
@@ -2070,12 +2207,12 @@
shortcuts_add_volumes (impl);
}
- impl->shortcuts_filter_model = shortcuts_model_filter_new (impl,
- GTK_TREE_MODEL (impl->shortcuts_model),
- NULL);
+ impl->shortcuts_pane_filter_model = shortcuts_pane_model_filter_new (impl,
+ GTK_TREE_MODEL (impl->shortcuts_model),
+ NULL);
- gtk_tree_model_filter_set_visible_func (GTK_TREE_MODEL_FILTER (impl->shortcuts_filter_model),
- shortcuts_filter_cb,
+ gtk_tree_model_filter_set_visible_func (GTK_TREE_MODEL_FILTER (impl->shortcuts_pane_filter_model),
+ shortcuts_pane_filter_cb,
impl,
NULL);
}
@@ -2293,16 +2430,16 @@
for (i = 0; i < current_folder_separator_idx; i++)
{
gpointer col_data;
- gboolean is_volume;
+ ShortcutType shortcut_type;
gtk_tree_model_get (GTK_TREE_MODEL (impl->shortcuts_model), &iter,
SHORTCUTS_COL_DATA, &col_data,
- SHORTCUTS_COL_IS_VOLUME, &is_volume,
+ SHORTCUTS_COL_TYPE, &shortcut_type,
-1);
if (col_data)
{
- if (is_volume)
+ if (shortcut_type == SHORTCUT_TYPE_VOLUME)
{
GtkFileSystemVolume *volume;
GtkFilePath *base_path;
@@ -2318,7 +2455,7 @@
if (exists)
return i;
}
- else
+ else if (shortcut_type == SHORTCUT_TYPE_PATH)
{
GtkFilePath *model_path;
@@ -2424,7 +2561,7 @@
if (!gtk_tree_selection_get_selected (selection, NULL, &parent_iter))
return FALSE;
- gtk_tree_model_filter_convert_iter_to_child_iter (GTK_TREE_MODEL_FILTER (impl->shortcuts_filter_model),
+ gtk_tree_model_filter_convert_iter_to_child_iter (GTK_TREE_MODEL_FILTER (impl->shortcuts_pane_filter_model),
iter,
&parent_iter);
return TRUE;
@@ -2447,11 +2584,12 @@
SHORTCUTS_COL_DATA, &col_data,
SHORTCUTS_COL_REMOVABLE, &removable,
-1);
- g_assert (col_data != NULL);
if (!removable)
return;
+ g_assert (col_data != NULL);
+
path = col_data;
error = NULL;
@@ -2608,6 +2746,16 @@
gboolean active;
gchar *tip;
+ if (impl->operation_mode == OPERATION_MODE_SEARCH)
+ {
+ gtk_widget_set_sensitive (impl->browse_shortcuts_add_button, FALSE);
+
+ if (impl->browse_files_popup_menu_add_shortcut_item)
+ gtk_widget_set_sensitive (impl->browse_files_popup_menu_add_shortcut_item, FALSE);
+
+ return;
+ }
+
selection_check (impl, &num_selected, NULL, &all_folders);
if (num_selected == 0)
@@ -3121,7 +3269,7 @@
{
GtkTreeIter iter;
gpointer col_data;
- gboolean is_volume;
+ ShortcutType shortcut_type;
GtkTreePath *path;
int old_position;
int bookmarks_index;
@@ -3146,10 +3294,10 @@
gtk_tree_model_get (GTK_TREE_MODEL (impl->shortcuts_model), &iter,
SHORTCUTS_COL_NAME, &name,
SHORTCUTS_COL_DATA, &col_data,
- SHORTCUTS_COL_IS_VOLUME, &is_volume,
+ SHORTCUTS_COL_TYPE, &shortcut_type,
-1);
g_assert (col_data != NULL);
- g_assert (!is_volume);
+ g_assert (shortcut_type == SHORTCUT_TYPE_PATH);
file_path = col_data;
file_path_copy = gtk_file_path_copy (file_path); /* removal below will free file_path, so we need a copy */
@@ -3233,17 +3381,11 @@
GtkTreeIter *iter,
gpointer data)
{
- gint column = GPOINTER_TO_INT (data);
- gchar *text;
+ ShortcutType shortcut_type;
- gtk_tree_model_get (model, iter, column, &text, -1);
+ gtk_tree_model_get (model, iter, SHORTCUTS_COL_TYPE, &shortcut_type, -1);
- if (!text)
- return TRUE;
-
- g_free (text);
-
- return FALSE;
+ return shortcut_type == SHORTCUT_TYPE_SEPARATOR;
}
/* Since GtkTreeView has a keybinding attached to '/', we need to catch
@@ -3488,7 +3630,7 @@
/* Accessible object name for the file chooser's shortcuts pane */
atk_object_set_name (gtk_widget_get_accessible (impl->browse_shortcuts_tree_view), _("Places"));
- gtk_tree_view_set_model (GTK_TREE_VIEW (impl->browse_shortcuts_tree_view), impl->shortcuts_filter_model);
+ gtk_tree_view_set_model (GTK_TREE_VIEW (impl->browse_shortcuts_tree_view), impl->shortcuts_pane_filter_model);
gtk_tree_view_enable_model_drag_source (GTK_TREE_VIEW (impl->browse_shortcuts_tree_view),
GDK_BUTTON1_MASK,
@@ -3561,8 +3703,7 @@
gtk_tree_view_set_row_separator_func (GTK_TREE_VIEW (impl->browse_shortcuts_tree_view),
shortcuts_row_separator_func,
- GINT_TO_POINTER (SHORTCUTS_COL_NAME),
- NULL);
+ NULL, NULL);
gtk_tree_view_append_column (GTK_TREE_VIEW (impl->browse_shortcuts_tree_view), column);
@@ -3933,6 +4074,8 @@
{
file_list_build_popup_menu (impl);
+ /* FMQ: handle OPERATION_MODE_SEARCH */
+
/* The sensitivity of the Add to Bookmarks item is set in
* bookmarks_check_add_sensitivity()
*/
@@ -4032,6 +4175,28 @@
return TRUE;
}
+/* Sets the sort column IDs for the file list based on the operation mode */
+static void
+file_list_set_sort_column_ids (GtkFileChooserDefault *impl)
+{
+ int name_id, mtime_id;
+
+ if (impl->operation_mode == OPERATION_MODE_BROWSE)
+ {
+ name_id = FILE_LIST_COL_NAME;
+ mtime_id = FILE_LIST_COL_MTIME;
+ }
+ else
+ {
+ name_id = SEARCH_MODEL_COL_PATH;
+ mtime_id = SEARCH_MODEL_COL_STAT;
+ }
+
+ gtk_tree_view_column_set_sort_column_id (impl->list_name_column, name_id);
+ gtk_tree_view_column_set_sort_column_id (impl->list_mtime_column, mtime_id);
+}
+
+
/* Creates the widgets for the file list */
static GtkWidget *
create_file_list (GtkFileChooserDefault *impl)
@@ -4045,7 +4210,7 @@
swin = gtk_scrolled_window_new (NULL, NULL);
gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (swin),
- GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
+ GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS);
gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (swin),
GTK_SHADOW_IN);
@@ -4135,6 +4300,7 @@
gtk_tree_view_column_set_sort_column_id (column, FILE_LIST_COL_SIZE);
gtk_tree_view_append_column (GTK_TREE_VIEW (impl->browse_files_tree_view), column);
#endif
+
/* Modification time column */
column = gtk_tree_view_column_new ();
@@ -4145,8 +4311,11 @@
gtk_tree_view_column_pack_start (column, renderer, TRUE);
gtk_tree_view_column_set_cell_data_func (column, renderer,
list_mtime_data_func, impl, NULL);
- gtk_tree_view_column_set_sort_column_id (column, FILE_LIST_COL_MTIME);
gtk_tree_view_append_column (GTK_TREE_VIEW (impl->browse_files_tree_view), column);
+ impl->list_mtime_column = column;
+
+ file_list_set_sort_column_ids (impl);
+
gtk_widget_show_all (swin);
return swin;
@@ -4254,9 +4423,59 @@
return;
if (gtk_combo_box_get_active_iter (combo, &iter))
- shortcuts_activate_iter (impl, &iter);
+ {
+ GtkTreeIter child_iter;
+
+ gtk_tree_model_filter_convert_iter_to_child_iter (GTK_TREE_MODEL_FILTER (impl->shortcuts_combo_filter_model),
+ &child_iter,
+ &iter);
+ shortcuts_activate_iter (impl, &child_iter);
+ }
}
+/* Filter function used to filter out the Search item and its separator.
+ * Used for the "Save in folder" combo box, so that these items do not appear in it.
+ */
+static gboolean
+shortcuts_combo_filter_func (GtkTreeModel *model,
+ GtkTreeIter *iter,
+ gpointer data)
+{
+ GtkFileChooserDefault *impl;
+ GtkTreePath *tree_path;
+ gint *indices;
+ int idx;
+ gboolean retval;
+
+ impl = GTK_FILE_CHOOSER_DEFAULT (data);
+
+ g_assert (model == GTK_TREE_MODEL (impl->shortcuts_model));
+
+ tree_path = gtk_tree_model_get_path (GTK_TREE_MODEL (impl->shortcuts_model), iter);
+ g_assert (tree_path != NULL);
+
+ indices = gtk_tree_path_get_indices (tree_path);
+
+ retval = TRUE;
+
+ if (impl->has_search)
+ {
+ idx = shortcuts_get_index (impl, SHORTCUTS_SEARCH);
+ if (idx == indices[0])
+ retval = FALSE;
+ else
+ {
+ idx = shortcuts_get_index (impl, SHORTCUTS_SEARCH_SEPARATOR);
+ if (idx == indices[0])
+ retval = FALSE;
+ }
+ }
+
+ gtk_tree_path_free (tree_path);
+
+ return retval;
+ }
+
/* Creates the combo box with the save folders */
static GtkWidget *
save_folder_combo_create (GtkFileChooserDefault *impl)
@@ -4264,8 +4483,14 @@
GtkWidget *combo;
GtkCellRenderer *cell;
+ impl->shortcuts_combo_filter_model = gtk_tree_model_filter_new (GTK_TREE_MODEL (impl->shortcuts_model), NULL);
+ gtk_tree_model_filter_set_visible_func (GTK_TREE_MODEL_FILTER (impl->shortcuts_combo_filter_model),
+ shortcuts_combo_filter_func,
+ impl,
+ NULL);
+
combo = g_object_new (GTK_TYPE_COMBO_BOX,
- "model", impl->shortcuts_model,
+ "model", impl->shortcuts_combo_filter_model,
"focus-on-click", FALSE,
NULL);
gtk_widget_show (combo);
@@ -4287,8 +4512,7 @@
gtk_combo_box_set_row_separator_func (GTK_COMBO_BOX (combo),
shortcuts_row_separator_func,
- GINT_TO_POINTER (SHORTCUTS_COL_NAME),
- NULL);
+ NULL, NULL);
g_signal_connect (combo, "changed",
G_CALLBACK (save_folder_combo_changed_cb), impl);
@@ -4622,6 +4846,7 @@
hbox = gtk_hbox_new (FALSE, 12);
gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0);
gtk_widget_show (hbox);
+ impl->browse_path_bar_hbox = hbox;
location_button_create (impl);
gtk_box_pack_start (GTK_BOX (hbox), impl->location_button, FALSE, FALSE, 0);
@@ -5210,6 +5435,9 @@
impl->shortcuts_activate_iter_handle = NULL;
}
+ if (impl->operation_mode == OPERATION_MODE_SEARCH)
+ search_stop_searching (impl);
+
remove_settings_signal (impl, gtk_widget_get_screen (GTK_WIDGET (impl)));
G_OBJECT_CLASS (_gtk_file_chooser_default_parent_class)->dispose (object);
@@ -5487,31 +5715,32 @@
GTK_WIDGET_CLASS (_gtk_file_chooser_default_parent_class)->map (widget);
- switch (impl->reload_state)
- {
- case RELOAD_EMPTY:
- /* The user didn't explicitly give us a folder to display, so we'll use the cwd */
- current_working_dir = g_get_current_dir ();
- gtk_file_chooser_set_current_folder (GTK_FILE_CHOOSER (impl), current_working_dir);
- g_free (current_working_dir);
- break;
-
- case RELOAD_HAS_FOLDER:
- /* Nothing; we are already loading or loaded, so we don't need to reload */
- break;
-
- case RELOAD_WAS_UNMAPPED:
- /* Just reload the current folder; else continue the pending load. */
- if (impl->current_folder)
- {
- pending_select_paths_store_selection (impl);
- change_folder_and_display_error (impl, impl->current_folder);
- }
- break;
-
- default:
- g_assert_not_reached ();
- }
+ if (impl->operation_mode == OPERATION_MODE_BROWSE)
+ switch (impl->reload_state)
+ {
+ case RELOAD_EMPTY:
+ /* The user didn't explicitly give us a folder to display, so we'll use the cwd */
+ current_working_dir = g_get_current_dir ();
+ gtk_file_chooser_set_current_folder (GTK_FILE_CHOOSER (impl), current_working_dir);
+ g_free (current_working_dir);
+ break;
+
+ case RELOAD_HAS_FOLDER:
+ /* Nothing; we are already loading or loaded, so we don't need to reload */
+ break;
+
+ case RELOAD_WAS_UNMAPPED:
+ /* Just reload the current folder; else continue the pending load. */
+ if (impl->current_folder)
+ {
+ pending_select_paths_store_selection (impl);
+ change_folder_and_display_error (impl, impl->current_folder);
+ }
+ break;
+
+ default:
+ g_assert_not_reached ();
+ }
bookmarks_changed_cb (impl->file_system, impl);
@@ -5982,12 +6211,6 @@
* but rather on behalf of something else like GtkFileChooserButton. In
* that case, the chooser's selection should be what the caller expects,
* as the user can't see that something else got selected. See bug #165264.
- *
- * Also, we don't select the first file if we are not in OPEN mode. Doing
- * so would change the contents of the filename entry for SAVE or
- * CREATE_FOLDER, which is undesired; in SELECT_FOLDER, we don't want to
- * select a *different* folder from the one into which the user just
- * navigated.
*/
if (GTK_WIDGET_MAPPED (impl) && impl->action == GTK_FILE_CHOOSER_ACTION_OPEN)
browse_files_select_first_row (impl);
@@ -6034,17 +6257,11 @@
profile_end ("end", NULL);
}
-/* Gets rid of the old list model and creates a new one for the current folder */
-static gboolean
-set_list_model (GtkFileChooserDefault *impl,
- GError **error)
+static void
+stop_loading_and_clear_list_model (GtkFileChooserDefault *impl)
{
- g_assert (impl->current_folder != NULL);
-
- profile_start ("start", NULL);
-
load_remove_timer (impl); /* This changes the state to LOAD_EMPTY */
-
+
if (impl->browse_files_model)
{
g_object_unref (impl->browse_files_model);
@@ -6056,6 +6273,20 @@
g_object_unref (impl->sort_model);
impl->sort_model = NULL;
}
+
+ gtk_tree_view_set_model (GTK_TREE_VIEW (impl->browse_files_tree_view), NULL);
+}
+
+/* Gets rid of the old list model and creates a new one for the current folder */
+static gboolean
+set_list_model (GtkFileChooserDefault *impl,
+ GError **error)
+{
+ g_assert (impl->current_folder != NULL);
+
+ profile_start ("start", NULL);
+
+ stop_loading_and_clear_list_model (impl);
set_busy_cursor (impl, TRUE);
gtk_tree_view_set_model (GTK_TREE_VIEW (impl->browse_files_tree_view), NULL);
@@ -6130,6 +6361,9 @@
struct update_chooser_entry_selected_foreach_closure closure;
const char *file_part;
+ if (impl->operation_mode == OPERATION_MODE_SEARCH || !impl->location_entry)
+ return;
+
if (!(impl->action == GTK_FILE_CHOOSER_ACTION_SAVE
|| impl->action == GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER
|| ((impl->action == GTK_FILE_CHOOSER_ACTION_OPEN
@@ -6151,35 +6385,40 @@
}
else if (closure.num_selected == 1)
{
- GtkTreeIter child_iter;
- const GtkFileInfo *info;
- gboolean change_entry;
-
- gtk_tree_model_sort_convert_iter_to_child_iter (impl->sort_model,
- &child_iter,
- &closure.first_selected_iter);
-
- info = _gtk_file_system_model_get_info (impl->browse_files_model, &child_iter);
-
- /* If the cursor moved to the row of the newly created folder,
- * retrieving info will return NULL.
- */
- if (!info)
- return;
-
- g_free (impl->browse_files_last_selected_name);
- impl->browse_files_last_selected_name = g_strdup (gtk_file_info_get_display_name (info));
-
- if (impl->action == GTK_FILE_CHOOSER_ACTION_OPEN
- || impl->action == GTK_FILE_CHOOSER_ACTION_SAVE)
- change_entry = !gtk_file_info_get_is_folder (info); /* We don't want the name to change when clicking on a folder... */
- else
- change_entry = TRUE; /* ... unless we are in one of the folder modes */
-
- if (change_entry)
- _gtk_file_chooser_entry_set_file_part (GTK_FILE_CHOOSER_ENTRY (impl->location_entry), impl->browse_files_last_selected_name);
+ if (impl->operation_mode == OPERATION_MODE_BROWSE)
+ {
+ GtkTreeIter child_iter;
+ const GtkFileInfo *info;
+ gboolean change_entry;
+
+ gtk_tree_model_sort_convert_iter_to_child_iter (impl->sort_model,
+ &child_iter,
+ &closure.first_selected_iter);
+
+ info = _gtk_file_system_model_get_info (impl->browse_files_model, &child_iter);
+
+ /* If the cursor moved to the row of the newly created folder,
+ * retrieving info will return NULL.
+ */
+ if (!info)
+ return;
- return;
+ if (impl->action == GTK_FILE_CHOOSER_ACTION_OPEN
+ || impl->action == GTK_FILE_CHOOSER_ACTION_SAVE
+ || impl->action == GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER)
+ change_entry = !gtk_file_info_get_is_folder (info); /* We don't want the name to change when clicking on a folder... */
+ else
+ change_entry = TRUE; /* ... unless we are in CREATE_FOLDER mode */
+
+ if (change_entry)
+ file_part = gtk_file_info_get_display_name (info);
+ }
+ else
+ {
+ gtk_tree_model_get (GTK_TREE_MODEL (impl->search_model), &closure.first_selected_iter,
+ SEARCH_MODEL_COL_DISPLAY_NAME, &file_part,
+ -1);
+ }
}
else
{
@@ -6386,6 +6625,8 @@
profile_start ("start", (char *) path);
+ search_switch_to_browse_mode (impl);
+
g_assert (path != NULL);
if (impl->local_only &&
@@ -6427,6 +6668,9 @@
{
GtkFileChooserDefault *impl = GTK_FILE_CHOOSER_DEFAULT (chooser);
+ if (impl->operation_mode == OPERATION_MODE_SEARCH)
+ return NULL;
+
if (impl->reload_state == RELOAD_EMPTY)
{
char *current_working_dir;
@@ -6487,9 +6731,9 @@
return FALSE;
if (!parent_path)
- return _gtk_file_chooser_set_current_folder_path (chooser, path, error);
+ return _gtk_file_chooser_set_current_folder_path (chooser, path, error);
- if (impl->load_state == LOAD_EMPTY)
+ if (impl->operation_mode == OPERATION_MODE_SEARCH || impl->load_state == LOAD_EMPTY)
same_path = FALSE;
else
{
@@ -6585,6 +6829,16 @@
gtk_file_chooser_default_select_all (GtkFileChooser *chooser)
{
GtkFileChooserDefault *impl = GTK_FILE_CHOOSER_DEFAULT (chooser);
+
+ if (impl->operation_mode == OPERATION_MODE_SEARCH)
+ {
+ GtkTreeSelection *selection;
+
+ selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (impl->browse_files_tree_view));
+ gtk_tree_selection_select_all (selection);
+ return;
+ }
+
if (impl->select_multiple)
gtk_tree_model_foreach (GTK_TREE_MODEL (impl->sort_model),
maybe_select, impl);
@@ -6714,6 +6968,10 @@
struct get_paths_closure info;
GtkWindow *toplevel;
GtkWidget *current_focus;
+ gboolean file_list_seen;
+
+ if (impl->operation_mode == OPERATION_MODE_SEARCH)
+ return search_get_selected_paths (impl);
info.impl = impl;
info.result = NULL;
@@ -6725,12 +6983,14 @@
else
current_focus = NULL;
+ file_list_seen = FALSE;
if (current_focus == impl->browse_files_tree_view)
{
GtkTreeSelection *selection;
file_list:
+ file_list_seen = TRUE;
selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (impl->browse_files_tree_view));
gtk_tree_selection_selected_foreach (selection, get_paths_foreach, &info);
@@ -6765,8 +7025,12 @@
return NULL;
}
- g_assert (info.path_from_entry != NULL);
- info.result = g_slist_prepend (info.result, info.path_from_entry);
+ if (info.path_from_entry)
+ info.result = g_slist_prepend (info.result, info.path_from_entry);
+ else if (!file_list_seen)
+ goto file_list;
+ else
+ return NULL;
}
else if (impl->toplevel_last_focus_widget == impl->browse_files_tree_view)
goto file_list;
@@ -6935,7 +7199,7 @@
pos = shortcuts_get_pos_for_shortcut_folder (data->impl, data->impl->num_shortcuts);
- shortcuts_insert_path (data->impl, pos, FALSE, NULL, data->path, NULL, FALSE, SHORTCUTS_SHORTCUTS);
+ shortcuts_insert_path (data->impl, pos, SHORTCUT_TYPE_PATH, NULL, data->path, NULL, FALSE, SHORTCUTS_SHORTCUTS);
out:
g_object_unref (data->impl);
@@ -7049,15 +7313,15 @@
for (i = 0; i < impl->num_shortcuts; i++)
{
gpointer col_data;
- gboolean is_volume;
+ ShortcutType shortcut_type;
GtkFilePath *shortcut;
gtk_tree_model_get (GTK_TREE_MODEL (impl->shortcuts_model), &iter,
SHORTCUTS_COL_DATA, &col_data,
- SHORTCUTS_COL_IS_VOLUME, &is_volume,
+ SHORTCUTS_COL_TYPE, &shortcut_type,
-1);
g_assert (col_data != NULL);
- g_assert (!is_volume);
+ g_assert (shortcut_type == SHORTCUT_TYPE_PATH);
shortcut = col_data;
if (gtk_file_path_compare (shortcut, path) == 0)
@@ -7106,15 +7370,15 @@
for (i = 0; i < impl->num_shortcuts; i++)
{
gpointer col_data;
- gboolean is_volume;
+ ShortcutType shortcut_type;
GtkFilePath *shortcut;
gtk_tree_model_get (GTK_TREE_MODEL (impl->shortcuts_model), &iter,
SHORTCUTS_COL_DATA, &col_data,
- SHORTCUTS_COL_IS_VOLUME, &is_volume,
+ SHORTCUTS_COL_TYPE, &shortcut_type,
-1);
g_assert (col_data != NULL);
- g_assert (!is_volume);
+ g_assert (shortcut_type == SHORTCUT_TYPE_PATH);
shortcut = col_data;
list = g_slist_prepend (list, gtk_file_path_copy (shortcut));
@@ -7449,6 +7713,23 @@
}
}
+/* Gives the focus to the browse tree view only if it is visible */
+static void
+focus_browse_tree_view_if_possible (GtkFileChooserDefault *impl)
+{
+ gboolean do_focus;
+
+ if ((impl->action == GTK_FILE_CHOOSER_ACTION_SAVE
+ || impl->action == GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER)
+ && !gtk_expander_get_expanded (GTK_EXPANDER (impl->save_expander)))
+ do_focus = FALSE;
+ else
+ do_focus = TRUE;
+
+ if (do_focus)
+ gtk_widget_grab_focus (impl->browse_files_tree_view);
+}
+
static void
action_create_folder_cb (GtkFileSystemHandle *handle,
const GtkFilePath *path,
@@ -7714,6 +7995,9 @@
g_assert (impl->action >= GTK_FILE_CHOOSER_ACTION_OPEN && impl->action <= GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER);
+ if (impl->operation_mode == OPERATION_MODE_SEARCH)
+ return search_should_respond (impl);
+
selection_check (impl, &num_selected, &all_files, &all_folders);
if (num_selected > 2)
@@ -7850,7 +8134,7 @@
{
shortcuts_activate_iter (impl, &iter);
- gtk_widget_grab_focus (impl->browse_files_tree_view);
+ focus_browse_tree_view_if_possible (impl);
}
else
goto file_list;
@@ -7864,6 +8148,11 @@
*/
goto file_list;
}
+ else if (impl->operation_mode == OPERATION_MODE_SEARCH && impl->toplevel_last_focus_widget == impl->search_entry)
+ {
+ search_entry_activate_cb (GTK_ENTRY (impl->search_entry), impl);
+ return FALSE;
+ }
else if (impl->location_entry && impl->toplevel_last_focus_widget == impl->location_entry)
{
/* The focus is on a dialog's action area button, *and* the widget that
@@ -7913,15 +8202,453 @@
gtk_widget_grab_focus (widget);
}
+/* Callback used from gtk_tree_selection_selected_foreach(); gets the selected GtkFilePaths */
static void
-set_current_filter (GtkFileChooserDefault *impl,
- GtkFileFilter *filter)
+search_selected_foreach_get_path_cb (GtkTreeModel *model,
+ GtkTreePath *path,
+ GtkTreeIter *iter,
+ gpointer data)
{
- if (impl->current_filter != filter)
- {
- int filter_index;
+ GSList **list;
+ const GtkFilePath *file_path;
+ GtkFilePath *file_path_copy;
- /* NULL filters are allowed to reset to non-filtered status
+ list = data;
+
+ gtk_tree_model_get (model, iter, SEARCH_MODEL_COL_PATH, &file_path, -1);
+ file_path_copy = gtk_file_path_copy (file_path);
+ *list = g_slist_prepend (*list, file_path_copy);
+}
+
+/* Constructs a list of the selected paths in search mode */
+static GSList *
+search_get_selected_paths (GtkFileChooserDefault *impl)
+{
+ GSList *result;
+ GtkTreeSelection *selection;
+
+ result = NULL;
+
+ selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (impl->browse_files_tree_view));
+ gtk_tree_selection_selected_foreach (selection, search_selected_foreach_get_path_cb, &result);
+ result = g_slist_reverse (result);
+
+ return result;
+}
+
+/* Called from ::should_respond(). We return whether there are selected files
+ * in the search list.
+ */
+static gboolean
+search_should_respond (GtkFileChooserDefault *impl)
+{
+ GtkTreeSelection *selection;
+
+ g_assert (impl->operation_mode == OPERATION_MODE_SEARCH);
+
+ selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (impl->browse_files_tree_view));
+ return (gtk_tree_selection_count_selected_rows (selection) != 0);
+}
+
+
+/* Adds one hit from the search engine to the search_model */
+static void
+search_add_hit (GtkFileChooserDefault *impl,
+ gchar *uri)
+{
+ GtkFilePath *path;
+ char *filename;
+ char *display_name;
+ char *collation_key;
+ struct stat statbuf;
+ struct stat *statbuf_copy;
+ GtkTreeIter iter;
+
+ path = gtk_file_system_uri_to_path (impl->file_system, uri);
+ if (!path)
+ return;
+
+ filename = gtk_file_system_path_to_filename (impl->file_system, path);
+ if (!filename)
+ {
+ gtk_file_path_free (path);
+ return;
+ }
+
+ if (stat (filename, &statbuf) != 0)
+ {
+ gtk_file_path_free (path);
+ g_free (filename);
+ return;
+ }
+
+ statbuf_copy = g_new (struct stat, 1);
+ *statbuf_copy = statbuf;
+
+ display_name = g_filename_display_name (filename);
+ collation_key = g_utf8_collate_key_for_filename (display_name, -1);
+
+ gtk_list_store_insert_with_values (impl->search_model, &iter, -1,
+ SEARCH_MODEL_COL_PATH, path,
+ SEARCH_MODEL_COL_DISPLAY_NAME, display_name,
+ SEARCH_MODEL_COL_COLLATION_KEY, collation_key,
+ SEARCH_MODEL_COL_STAT, statbuf_copy,
+ -1);
+}
+
+/* Callback used from GtkSearchEngine when we get new hits */
+static void
+search_engine_hits_added_cb (GtkSearchEngine *engine,
+ GList *hits,
+ gpointer data)
+{
+ GtkFileChooserDefault *impl;
+ GList *l;
+
+ impl = GTK_FILE_CHOOSER_DEFAULT (data);
+
+ for (l = hits; l; l = l->next)
+ search_add_hit (impl, (gchar*)l->data);
+}
+
+/* Callback used from GtkSearchEngine when the query is done running */
+static void
+search_engine_finished_cb (GtkSearchEngine *engine,
+ gpointer data)
+{
+ GtkFileChooserDefault *impl;
+
+ impl = GTK_FILE_CHOOSER_DEFAULT (data);
+
+ /* FMQ: if search was empty, say that we got no hits */
+
+ set_busy_cursor (impl, FALSE);
+}
+
+/* Displays a generic error when we cannot create a GtkSearchEngine.
+ * It would be better if _gtk_search_engine_new() gave us a GError
+ * with a better message, but it doesn't do that right now.
+ */
+static void
+search_error_could_not_create_client (GtkFileChooserDefault *impl)
+{
+ error_message (impl,
+ _("Could not start the search process"),
+ _("The program was not able to create a connection to the indexer "
+ "daemon. Please make sure it is running."));
+}
+
+static void
+search_engine_error_cb (GtkSearchEngine *engine,
+ const gchar *message,
+ gpointer data)
+{
+ GtkFileChooserDefault *impl;
+
+ impl = GTK_FILE_CHOOSER_DEFAULT (data);
+
+ search_stop_searching (impl);
+ error_message (impl, _("Could not send the search request"), message);
+
+ set_busy_cursor (impl, FALSE);
+}
+
+/* Frees the data in the search_model */
+static void
+search_clear_model (GtkFileChooserDefault *impl,
+ gboolean remove_from_treeview)
+{
+ GtkTreeIter iter;
+
+ if (!impl->search_model)
+ return;
+
+ if (gtk_tree_model_get_iter_first (GTK_TREE_MODEL (impl->search_model), &iter))
+ do
+ {
+ GtkFilePath *path;
+ char *display_name;
+ char *collation_key;
+ struct stat *statbuf;
+
+ gtk_tree_model_get (GTK_TREE_MODEL (impl->search_model), &iter,
+ SEARCH_MODEL_COL_PATH, &path,
+ SEARCH_MODEL_COL_DISPLAY_NAME, &display_name,
+ SEARCH_MODEL_COL_COLLATION_KEY, &collation_key,
+ SEARCH_MODEL_COL_STAT, &statbuf,
+ -1);
+
+ gtk_file_path_free (path);
+ g_free (display_name);
+ g_free (collation_key);
+ g_free (statbuf);
+ }
+ while (gtk_tree_model_iter_next (GTK_TREE_MODEL (impl->search_model), &iter));
+
+ g_object_unref (impl->search_model);
+ impl->search_model = NULL;
+
+ if (remove_from_treeview)
+ gtk_tree_view_set_model (GTK_TREE_VIEW (impl->browse_files_tree_view), NULL);
+}
+
+/* Stops any ongoing searches; does not touch the search_model */
+static void
+search_stop_searching (GtkFileChooserDefault *impl)
+{
+ if (impl->search_query)
+ {
+ g_object_unref (impl->search_query);
+ impl->search_query = NULL;
+ }
+
+ if (impl->search_engine)
+ {
+ g_object_unref (impl->search_engine);
+ impl->search_engine = NULL;
+ }
+}
+
+/* Stops any pending searches, clears the file list, and switches back to OPERATION_MODE_BROWSE */
+static void
+search_switch_to_browse_mode (GtkFileChooserDefault *impl)
+{
+ if (impl->operation_mode == OPERATION_MODE_BROWSE)
+ return;
+
+ search_stop_searching (impl);
+ search_clear_model (impl, TRUE);
+
+ gtk_widget_destroy (impl->search_hbox);
+ impl->search_hbox = NULL;
+ impl->search_entry = NULL;
+
+ gtk_widget_show (impl->browse_path_bar);
+ gtk_widget_show (impl->browse_new_folder_button);
+
+ if (impl->action == GTK_FILE_CHOOSER_ACTION_OPEN
+ || impl->action == GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER)
+ {
+ gtk_widget_show (impl->location_button);
+
+ if (impl->location_mode == LOCATION_MODE_FILENAME_ENTRY)
+ gtk_widget_show (impl->location_entry_box);
+ }
+
+ impl->operation_mode = OPERATION_MODE_BROWSE;
+
+ file_list_set_sort_column_ids (impl);
+}
+
+/* Sort callback from the path column */
+static gint
+search_column_path_sort_func (GtkTreeModel *model,
+ GtkTreeIter *a,
+ GtkTreeIter *b,
+ gpointer user_data)
+{
+ const char *collation_key_a, *collation_key_b;
+
+ gtk_tree_model_get (model, a, SEARCH_MODEL_COL_COLLATION_KEY, &collation_key_a, -1);
+ gtk_tree_model_get (model, b, SEARCH_MODEL_COL_COLLATION_KEY, &collation_key_b, -1);
+
+ return strcmp (collation_key_a, collation_key_b);
+}
+
+/* Sort callback from the modification time column */
+static gint
+search_column_mtime_sort_func (GtkTreeModel *model,
+ GtkTreeIter *a,
+ GtkTreeIter *b,
+ gpointer user_data)
+{
+ const struct stat *statbuf_a, *statbuf_b;
+
+ /* Note that although we store a whole struct stat in the model, we only
+ * compare the mtime here. If we add another column relative to a struct stat
+ * (e.g. a file size column), we'll want another sort callback similar to this
+ * one as well.
+ */
+
+ gtk_tree_model_get (model, a, SEARCH_MODEL_COL_STAT, &statbuf_a, -1);
+ gtk_tree_model_get (model, b, SEARCH_MODEL_COL_STAT, &statbuf_b, -1);
+
+ if (statbuf_a->st_mtime < statbuf_b->st_mtime)
+ return -1;
+ else if (statbuf_a->st_mtime > statbuf_b->st_mtime)
+ return 1;
+ else
+ return 0;
+}
+
+/* Creates the search_model and puts it in the tree view */
+static void
+search_setup_model (GtkFileChooserDefault *impl)
+{
+ g_assert (impl->search_model == NULL);
+
+ /* We store these columns in the search model:
+ *
+ * SEARCH_MODEL_COL_PATH - a GtkFilePath for the hit's URI (stored as a pointer, not as a GTK_TYPE_FILE_PATH)
+ * SEARCH_MODEL_COL_DISPLAY_NAME - a string with the display name (stored as a pointer, not as a G_TYPE_STRING)
+ * SEARCH_MODEL_COL_COLLATION_KEY - collation key for the filename (stored as a pointer, not as a G_TYPE_STRING)
+ * SEARCH_MODEL_COL_STAT - pointer to a struct stat
+ *
+ * Keep this in sync with the enumeration defined near the beginning of this file.
+ */
+ impl->search_model = gtk_list_store_new (4,
+ G_TYPE_POINTER,
+ G_TYPE_POINTER,
+ G_TYPE_POINTER,
+ G_TYPE_POINTER);
+ gtk_tree_sortable_set_sort_func (GTK_TREE_SORTABLE (impl->search_model),
+ SEARCH_MODEL_COL_PATH,
+ search_column_path_sort_func,
+ impl,
+ NULL);
+ gtk_tree_sortable_set_sort_func (GTK_TREE_SORTABLE (impl->search_model),
+ SEARCH_MODEL_COL_STAT,
+ search_column_mtime_sort_func,
+ impl,
+ NULL);
+
+ gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (impl->search_model),
+ SEARCH_MODEL_COL_STAT,
+ GTK_SORT_DESCENDING);
+
+ gtk_tree_view_set_model (GTK_TREE_VIEW (impl->browse_files_tree_view), GTK_TREE_MODEL (impl->search_model));
+}
+
+/* Creates a new query with the specified text and launches it */
+static void
+search_start_query (GtkFileChooserDefault *impl,
+ const gchar *query_text)
+{
+ search_stop_searching (impl);
+ search_clear_model (impl, TRUE);
+ search_setup_model (impl);
+ set_busy_cursor (impl, TRUE);
+
+ if (impl->search_engine == NULL)
+ impl->search_engine = _gtk_search_engine_new ();
+
+ if (!impl->search_engine)
+ {
+ set_busy_cursor (impl, FALSE);
+ search_error_could_not_create_client (impl); /* lame; we don't get an error code or anything */
+ return;
+ }
+
+ impl->search_query = _gtk_query_new ();
+ _gtk_query_set_text (impl->search_query, query_text);
+ _gtk_search_engine_set_query (impl->search_engine, impl->search_query);
+
+ g_signal_connect (impl->search_engine, "hits-added",
+ G_CALLBACK (search_engine_hits_added_cb), impl);
+ g_signal_connect (impl->search_engine, "finished",
+ G_CALLBACK (search_engine_finished_cb), impl);
+ g_signal_connect (impl->search_engine, "error",
+ G_CALLBACK (search_engine_error_cb), impl);
+
+ _gtk_search_engine_start (impl->search_engine);
+}
+
+/* Callback used when the user presses Enter while typing on the search entry; starts the query */
+static void
+search_entry_activate_cb (GtkEntry *entry,
+ gpointer data)
+{
+ GtkFileChooserDefault *impl;
+ const char *text;
+
+ impl = GTK_FILE_CHOOSER_DEFAULT (data);
+
+ text = gtk_entry_get_text (GTK_ENTRY (impl->search_entry));
+ if (strlen (text) == 0)
+ return;
+
+ search_start_query (impl, text);
+}
+
+/* Hides the path bar and creates the search entry */
+static void
+search_setup_widgets (GtkFileChooserDefault *impl)
+{
+ GtkWidget *label;
+ gchar *text;
+
+ impl->search_hbox = gtk_hbox_new (FALSE, 12);
+
+ /* Label */
+
+ label = gtk_label_new (NULL);
+ text = g_strdup_printf ("<b>%s</b>", _("Search:"));
+ gtk_label_set_markup (GTK_LABEL (label), text);
+ g_free (text);
+ gtk_box_pack_start (GTK_BOX (impl->search_hbox), label, FALSE, FALSE, 0);
+
+ /* Entry */
+
+ impl->search_entry = gtk_entry_new ();
+ g_signal_connect (impl->search_entry, "activate",
+ G_CALLBACK (search_entry_activate_cb),
+ impl);
+ gtk_box_pack_start (GTK_BOX (impl->search_hbox), impl->search_entry, TRUE, TRUE, 0);
+
+ gtk_widget_hide (impl->browse_path_bar);
+ gtk_widget_hide (impl->browse_new_folder_button);
+
+ /* Box for search widgets */
+
+ gtk_box_pack_start (GTK_BOX (impl->browse_path_bar_hbox), impl->search_hbox, TRUE, TRUE, 0);
+ gtk_widget_show_all (impl->search_hbox);
+
+ /* Hide the location widgets temporarily */
+
+ if (impl->action == GTK_FILE_CHOOSER_ACTION_OPEN
+ || impl->action == GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER)
+ {
+ gtk_widget_hide (impl->location_button);
+ gtk_widget_hide (impl->location_entry_box);
+ }
+
+ gtk_widget_grab_focus (impl->search_entry);
+
+ /* FMQ: hide the filter combo? */
+}
+
+/* Main entry point to the searching functions; this gets called when the user
+ * activates the Search shortcut.
+ */
+static void
+search_activate (GtkFileChooserDefault *impl)
+{
+ if (impl->operation_mode == OPERATION_MODE_SEARCH)
+ {
+ gtk_widget_grab_focus (impl->search_entry);
+ return;
+ }
+
+ impl->operation_mode = OPERATION_MODE_SEARCH;
+
+ g_assert (impl->search_hbox == NULL);
+ g_assert (impl->search_entry == NULL);
+ g_assert (impl->search_model == NULL);
+
+ stop_loading_and_clear_list_model (impl);
+ search_setup_widgets (impl);
+ file_list_set_sort_column_ids (impl);
+}
+
+static void
+set_current_filter (GtkFileChooserDefault *impl,
+ GtkFileFilter *filter)
+{
+ if (impl->current_filter != filter)
+ {
+ int filter_index;
+
+ /* NULL filters are allowed to reset to non-filtered status
*/
filter_index = g_slist_index (impl->filters, filter);
if (impl->filters && filter && filter_index < 0)
@@ -7961,28 +8688,44 @@
{
GtkTreePath *cursor_path;
const GtkFilePath *new_path;
- const GtkFileInfo *new_info;
+ const char *new_display_name;
gtk_tree_view_get_cursor (GTK_TREE_VIEW (impl->browse_files_tree_view), &cursor_path, NULL);
- if (cursor_path && impl->sort_model)
+ new_path = NULL;
+ new_display_name = NULL;
+ if (cursor_path)
{
- GtkTreeIter iter;
- GtkTreeIter child_iter;
-
- if (!gtk_tree_model_get_iter (GTK_TREE_MODEL (impl->sort_model), &iter, cursor_path))
- g_assert_not_reached ();
-
- gtk_tree_path_free (cursor_path);
+ if (impl->operation_mode == OPERATION_MODE_BROWSE)
+ {
+ if (impl->sort_model)
+ {
+ GtkTreeIter iter;
+ GtkTreeIter child_iter;
+ const GtkFileInfo *new_info;
+
+ gtk_tree_model_get_iter (GTK_TREE_MODEL (impl->sort_model), &iter, cursor_path);
+ gtk_tree_path_free (cursor_path);
+
+ gtk_tree_model_sort_convert_iter_to_child_iter (impl->sort_model, &child_iter, &iter);
+
+ new_path = _gtk_file_system_model_get_path (impl->browse_files_model, &child_iter);
+ new_info = _gtk_file_system_model_get_info (impl->browse_files_model, &child_iter);
+ if (new_info)
+ new_display_name = gtk_file_info_get_display_name (new_info);
+ }
+ }
+ else
+ {
+ GtkTreeIter iter;
- gtk_tree_model_sort_convert_iter_to_child_iter (impl->sort_model, &child_iter, &iter);
+ gtk_tree_model_get_iter (GTK_TREE_MODEL (impl->search_model), &iter, cursor_path);
+ gtk_tree_path_free (cursor_path);
- new_path = _gtk_file_system_model_get_path (impl->browse_files_model, &child_iter);
- new_info = _gtk_file_system_model_get_info (impl->browse_files_model, &child_iter);
- }
- else
- {
- new_path = NULL;
- new_info = NULL;
+ gtk_tree_model_get (GTK_TREE_MODEL (impl->search_model), &iter,
+ SEARCH_MODEL_COL_PATH, &new_path,
+ SEARCH_MODEL_COL_DISPLAY_NAME, &new_display_name,
+ -1);
+ }
}
if (new_path != impl->preview_path &&
@@ -7998,7 +8741,7 @@
if (new_path)
{
impl->preview_path = gtk_file_path_copy (new_path);
- impl->preview_display_name = g_strdup (gtk_file_info_get_display_name (new_info));
+ impl->preview_display_name = g_strdup (new_display_name);
}
else
{
@@ -8067,6 +8810,8 @@
{
GtkFilePath *path;
+ search_switch_to_browse_mode (impl);
+
/* We ref the file chooser since volume_mount() may run a main loop, and the
* user could close the file chooser window in the meantime.
*/
@@ -8087,6 +8832,8 @@
if (path != NULL)
{
change_folder_and_display_error (impl, path);
+ focus_browse_tree_view_if_possible (impl);
+
gtk_file_path_free (path);
}
}
@@ -8119,7 +8866,10 @@
goto out;
if (!error && gtk_file_info_get_is_folder (info))
- change_folder_and_display_error (data->impl, data->path);
+ {
+ change_folder_and_display_error (data->impl, data->path);
+ focus_browse_tree_view_if_possible (data->impl);
+ }
else
gtk_file_chooser_default_select_path (GTK_FILE_CHOOSER (data->impl), data->path, NULL);
@@ -8136,26 +8886,25 @@
GtkTreeIter *iter)
{
gpointer col_data;
- gboolean is_volume;
+ ShortcutType shortcut_type;
if (impl->location_mode == LOCATION_MODE_FILENAME_ENTRY && impl->action != GTK_FILE_CHOOSER_ACTION_SAVE)
_gtk_file_chooser_entry_set_file_part (GTK_FILE_CHOOSER_ENTRY (impl->location_entry), "");
gtk_tree_model_get (GTK_TREE_MODEL (impl->shortcuts_model), iter,
SHORTCUTS_COL_DATA, &col_data,
- SHORTCUTS_COL_IS_VOLUME, &is_volume,
+ SHORTCUTS_COL_TYPE, &shortcut_type,
-1);
- if (!col_data)
- return; /* We are on a separator */
-
if (impl->shortcuts_activate_iter_handle)
{
gtk_file_system_cancel_operation (impl->shortcuts_activate_iter_handle);
impl->shortcuts_activate_iter_handle = NULL;
}
- if (is_volume)
+ if (shortcut_type == SHORTCUT_TYPE_SEPARATOR)
+ return;
+ else if (shortcut_type == SHORTCUT_TYPE_VOLUME)
{
GtkFileSystemVolume *volume;
@@ -8163,7 +8912,7 @@
shortcuts_activate_volume (impl, volume);
}
- else
+ else if (shortcut_type == SHORTCUT_TYPE_PATH)
{
struct ShortcutsActivateData *data;
@@ -8176,6 +8925,10 @@
GTK_FILE_INFO_IS_FOLDER,
shortcuts_activate_get_info_cb, data);
}
+ else if (shortcut_type == SHORTCUT_TYPE_SEARCH)
+ {
+ search_activate (impl);
+ }
}
/* Callback used when a row in the shortcuts list is activated */
@@ -8188,15 +8941,13 @@
GtkTreeIter iter;
GtkTreeIter child_iter;
- if (!gtk_tree_model_get_iter (impl->shortcuts_filter_model, &iter, path))
+ if (!gtk_tree_model_get_iter (impl->shortcuts_pane_filter_model, &iter, path))
return;
- gtk_tree_model_filter_convert_iter_to_child_iter (GTK_TREE_MODEL_FILTER (impl->shortcuts_filter_model),
+ gtk_tree_model_filter_convert_iter_to_child_iter (GTK_TREE_MODEL_FILTER (impl->shortcuts_pane_filter_model),
&child_iter,
&iter);
shortcuts_activate_iter (impl, &child_iter);
-
- gtk_widget_grab_focus (impl->browse_files_tree_view);
}
/* Handler for GtkWidget::key-press-event on the shortcuts list */
@@ -8236,8 +8987,15 @@
gpointer data)
{
GtkFileChooserDefault *impl = data;
+ GtkTreeIter filter_iter;
+ ShortcutType shortcut_type;
- return (*gtk_tree_path_get_indices (path) != shortcuts_get_index (impl, SHORTCUTS_BOOKMARKS_SEPARATOR));
+ if (!gtk_tree_model_get_iter (impl->shortcuts_pane_filter_model, &filter_iter, path))
+ g_assert_not_reached ();
+
+ gtk_tree_model_get (impl->shortcuts_pane_filter_model, &filter_iter, SHORTCUTS_COL_TYPE, &shortcut_type, -1);
+
+ return shortcut_type != SHORTCUT_TYPE_SEPARATOR;
}
static gboolean
@@ -8249,6 +9007,9 @@
{
GtkFileChooserDefault *impl = data;
+ if (impl->operation_mode == OPERATION_MODE_SEARCH)
+ return TRUE;
+
if (impl->action == GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER ||
impl->action == GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER)
{
@@ -8274,7 +9035,7 @@
GtkFileChooserDefault *impl)
{
/* See if we are in the new folder editable row for Save mode */
- if (impl->action == GTK_FILE_CHOOSER_ACTION_SAVE)
+ if (impl->operation_mode == OPERATION_MODE_BROWSE && impl->action == GTK_FILE_CHOOSER_ACTION_SAVE)
{
const GtkFileInfo *info;
gboolean had_selection;
@@ -8289,6 +9050,8 @@
out:
+ /* AQUI: cambiar las siguientes funciones para que acepten SEARCH */
+
update_chooser_entry (impl);
check_preview_change (impl);
bookmarks_check_add_sensitivity (impl);
@@ -8306,6 +9069,12 @@
GtkTreeIter iter, child_iter;
const GtkFileInfo *info;
+ if (impl->operation_mode == OPERATION_MODE_SEARCH)
+ {
+ g_signal_emit_by_name (impl, "file-activated");
+ return;
+ }
+
if (!gtk_tree_model_get_iter (GTK_TREE_MODEL (impl->sort_model), &iter, path))
return;
@@ -8376,6 +9145,15 @@
const GtkFileInfo *info;
gboolean sensitive = TRUE;
+ if (impl->operation_mode == OPERATION_MODE_SEARCH)
+ {
+ g_object_set (cell,
+ "pixbuf", NULL,
+ "sensitive", TRUE,
+ NULL);
+ return;
+ }
+
profile_start ("start", NULL);
info = get_list_file_info (impl, iter);
@@ -8425,13 +9203,33 @@
gpointer data)
{
GtkFileChooserDefault *impl = data;
- const GtkFileInfo *info = get_list_file_info (impl, iter);
- gboolean sensitive = TRUE;
+ const GtkFileInfo *info;
+ gboolean sensitive;
+
+ if (impl->operation_mode == OPERATION_MODE_SEARCH)
+ {
+ char *display_name;
+
+ gtk_tree_model_get (GTK_TREE_MODEL (impl->search_model), iter,
+ SEARCH_MODEL_COL_DISPLAY_NAME, &display_name,
+ -1);
+ g_object_set (cell,
+ "text", display_name,
+ "sensitive", TRUE,
+ "ellipsize", PANGO_ELLIPSIZE_START,
+ NULL);
+ return;
+ }
+
+ info = get_list_file_info (impl, iter);
+ sensitive = TRUE;
if (!info)
{
g_object_set (cell,
"text", _("Type name of new folder"),
+ "sensitive", TRUE,
+ "ellipsize", PANGO_ELLIPSIZE_NONE,
NULL);
return;
@@ -8447,6 +9245,7 @@
g_object_set (cell,
"text", gtk_file_info_get_display_name (info),
"sensitive", sensitive,
+ "ellipsize", PANGO_ELLIPSIZE_END,
NULL);
}
@@ -8508,7 +9307,6 @@
gpointer data)
{
GtkFileChooserDefault *impl;
- const GtkFileInfo *info;
GtkFileTime time_mtime;
GDate mtime, now;
int days_diff;
@@ -8517,17 +9315,35 @@
impl = data;
- info = get_list_file_info (impl, iter);
- if (!info)
+ if (impl->operation_mode == OPERATION_MODE_SEARCH)
{
- g_object_set (cell,
- "text", "",
- "sensitive", TRUE,
- NULL);
- return;
+ struct stat *statbuf;
+
+ gtk_tree_model_get (GTK_TREE_MODEL (impl->search_model), iter,
+ SEARCH_MODEL_COL_STAT, &statbuf,
+ -1);
+ time_mtime = statbuf->st_mtime;
}
+ else
+ {
+ const GtkFileInfo *info;
- time_mtime = gtk_file_info_get_modification_time (info);
+ info = get_list_file_info (impl, iter);
+ if (!info)
+ {
+ g_object_set (cell,
+ "text", "",
+ "sensitive", TRUE,
+ NULL);
+ return;
+ }
+
+ time_mtime = gtk_file_info_get_modification_time (info);
+
+ if (impl->action == GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER ||
+ impl->action == GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER)
+ sensitive = gtk_file_info_get_is_folder (info);
+ }
if (time_mtime == 0)
strcpy (buf, _("Unknown"));
@@ -8558,10 +9374,6 @@
}
}
- if (impl->action == GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER ||
- impl->action == GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER)
- sensitive = gtk_file_info_get_is_folder (info);
-
g_object_set (cell,
"text", buf,
"sensitive", sensitive,
@@ -8587,7 +9399,23 @@
static void
location_popup_handler (GtkFileChooserDefault *impl,
const gchar *path)
-{
+{
+ if (impl->operation_mode == OPERATION_MODE_SEARCH)
+ {
+ GtkWidget *widget_to_focus;
+
+ search_switch_to_browse_mode (impl); /* This will give us the location widgets back */
+ if (impl->current_folder)
+ change_folder_and_display_error (impl, impl->current_folder);
+
+ if (impl->location_mode == LOCATION_MODE_PATH_BAR)
+ widget_to_focus = impl->browse_files_tree_view;
+ else
+ widget_to_focus = impl->location_entry;
+
+ gtk_widget_grab_focus (widget_to_focus);
+ return;
+ }
if (impl->action == GTK_FILE_CHOOSER_ACTION_OPEN
|| impl->action == GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER)
{
@@ -8656,6 +9484,7 @@
g_assert_not_reached ();
shortcuts_activate_iter (impl, &iter);
+ focus_browse_tree_view_if_possible (impl);
}
/* Handler for the "home-folder" keybinding signal */
@@ -8700,26 +9529,26 @@
/* Drag and drop interfaces */
static void
-_shortcuts_model_filter_class_init (ShortcutsModelFilterClass *class)
+_shortcuts_pane_model_filter_class_init (ShortcutsPaneModelFilterClass *class)
{
}
static void
-_shortcuts_model_filter_init (ShortcutsModelFilter *model)
+_shortcuts_pane_model_filter_init (ShortcutsPaneModelFilter *model)
{
model->impl = NULL;
}
/* GtkTreeDragSource::row_draggable implementation for the shortcuts filter model */
static gboolean
-shortcuts_model_filter_row_draggable (GtkTreeDragSource *drag_source,
- GtkTreePath *path)
+shortcuts_pane_model_filter_row_draggable (GtkTreeDragSource *drag_source,
+ GtkTreePath *path)
{
- ShortcutsModelFilter *model;
+ ShortcutsPaneModelFilter *model;
int pos;
int bookmarks_pos;
- model = SHORTCUTS_MODEL_FILTER (drag_source);
+ model = SHORTCUTS_PANE_MODEL_FILTER (drag_source);
pos = *gtk_tree_path_get_indices (path);
bookmarks_pos = shortcuts_get_index (model->impl, SHORTCUTS_BOOKMARKS);
@@ -8729,13 +9558,13 @@
/* GtkTreeDragSource::drag_data_get implementation for the shortcuts filter model */
static gboolean
-shortcuts_model_filter_drag_data_get (GtkTreeDragSource *drag_source,
- GtkTreePath *path,
- GtkSelectionData *selection_data)
+shortcuts_pane_model_filter_drag_data_get (GtkTreeDragSource *drag_source,
+ GtkTreePath *path,
+ GtkSelectionData *selection_data)
{
- ShortcutsModelFilter *model;
+ ShortcutsPaneModelFilter *model;
- model = SHORTCUTS_MODEL_FILTER (drag_source);
+ model = SHORTCUTS_PANE_MODEL_FILTER (drag_source);
/* FIXME */
@@ -8744,30 +9573,30 @@
/* Fill the GtkTreeDragSourceIface vtable */
static void
-shortcuts_model_filter_drag_source_iface_init (GtkTreeDragSourceIface *iface)
+shortcuts_pane_model_filter_drag_source_iface_init (GtkTreeDragSourceIface *iface)
{
- iface->row_draggable = shortcuts_model_filter_row_draggable;
- iface->drag_data_get = shortcuts_model_filter_drag_data_get;
+ iface->row_draggable = shortcuts_pane_model_filter_row_draggable;
+ iface->drag_data_get = shortcuts_pane_model_filter_drag_data_get;
}
#if 0
/* Fill the GtkTreeDragDestIface vtable */
static void
-shortcuts_model_filter_drag_dest_iface_init (GtkTreeDragDestIface *iface)
+shortcuts_pane_model_filter_drag_dest_iface_init (GtkTreeDragDestIface *iface)
{
- iface->drag_data_received = shortcuts_model_filter_drag_data_received;
- iface->row_drop_possible = shortcuts_model_filter_row_drop_possible;
+ iface->drag_data_received = shortcuts_pane_model_filter_drag_data_received;
+ iface->row_drop_possible = shortcuts_pane_model_filter_row_drop_possible;
}
#endif
static GtkTreeModel *
-shortcuts_model_filter_new (GtkFileChooserDefault *impl,
- GtkTreeModel *child_model,
- GtkTreePath *root)
+shortcuts_pane_model_filter_new (GtkFileChooserDefault *impl,
+ GtkTreeModel *child_model,
+ GtkTreePath *root)
{
- ShortcutsModelFilter *model;
+ ShortcutsPaneModelFilter *model;
- model = g_object_new (SHORTCUTS_MODEL_FILTER_TYPE,
+ model = g_object_new (SHORTCUTS_PANE_MODEL_FILTER_TYPE,
"child-model", child_model,
"virtual-root", root,
NULL);
--- gtk+-2.10.9/gtk/gtkfilechooserprivate.h.search 2007-01-22 10:48:04.000000000 -0500
+++ gtk+-2.10.9/gtk/gtkfilechooserprivate.h 2007-01-30 23:27:42.000000000 -0500
@@ -25,6 +25,8 @@
#include "gtkfilesystem.h"
#include "gtkfilesystemmodel.h"
#include "gtkliststore.h"
+#include "gtksearchengine.h"
+#include "gtkquery.h"
#include "gtktooltips.h"
#include "gtktreemodelsort.h"
#include "gtktreestore.h"
@@ -147,6 +149,11 @@
LOCATION_MODE_FILENAME_ENTRY
} LocationMode;
+typedef enum {
+ OPERATION_MODE_BROWSE,
+ OPERATION_MODE_SEARCH
+} OperationMode;
+
struct _GtkFileChooserDefault
{
GtkVBox parent_instance;
@@ -175,11 +182,19 @@
GtkWidget *browse_files_popup_menu_add_shortcut_item;
GtkWidget *browse_files_popup_menu_hidden_files_item;
GtkWidget *browse_new_folder_button;
+ GtkWidget *browse_path_bar_hbox;
GtkWidget *browse_path_bar;
GtkFileSystemModel *browse_files_model;
char *browse_files_last_selected_name;
+ /* Widgets for searching */
+ GtkWidget *search_hbox;
+ GtkWidget *search_entry;
+ GtkSearchEngine *search_engine;
+ GtkQuery *search_query;
+ GtkListStore *search_model;
+
GtkWidget *filter_combo_hbox;
GtkWidget *filter_combo;
GtkWidget *preview_box;
@@ -195,7 +210,16 @@
LocationMode location_mode;
GtkListStore *shortcuts_model;
- GtkTreeModel *shortcuts_filter_model;
+
+ /* Filter for the shortcuts pane. We filter out the "current folder" row and
+ * the separator that we use for the "Save in folder" combo.
+ */
+ GtkTreeModel *shortcuts_pane_filter_model;
+
+ /* Filter for the "Save in folder" combo. We filter out the Search row and
+ * its separator.
+ */
+ GtkTreeModel *shortcuts_combo_filter_model;
GtkTreeModelSort *sort_model;
@@ -215,6 +239,8 @@
ReloadState reload_state;
guint load_timeout_id;
+ OperationMode operation_mode;
+
GSList *pending_select_paths;
GtkFileFilter *current_filter;
@@ -222,9 +248,6 @@
GtkTooltips *tooltips;
- gboolean has_home;
- gboolean has_desktop;
-
int num_volumes;
int num_shortcuts;
int num_bookmarks;
@@ -239,6 +262,7 @@
GtkTreeViewColumn *list_name_column;
GtkCellRenderer *list_name_renderer;
+ GtkTreeViewColumn *list_mtime_column;
GSource *edited_idle;
char *edited_new_text;
@@ -265,6 +289,9 @@
guint list_sort_ascending : 1;
guint changing_folder : 1;
guint shortcuts_current_folder_active : 1;
+ guint has_home : 1;
+ guint has_desktop : 1;
+ guint has_search : 1;
guint expand_folders : 1;
#if 0
--- /dev/null 2007-01-30 22:42:40.851021051 -0500
+++ gtk+-2.10.9/gtk/gtksearchenginesimple.h 2007-01-30 23:27:42.000000000 -0500
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2005 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, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ *
+ * Author: Alexander Larsson <alexl@redhat.com>
+ *
+ * Based on nautilus-search-engine-simple.h
+ */
+
+#ifndef __GTK_SEARCH_ENGINE_SIMPLE_H__
+#define __GTK_SEARCH_ENGINE_SIMPLE_H__
+
+#include "gtksearchengine.h"
+
+G_END_DECLS
+
+#define GTK_TYPE_SEARCH_ENGINE_SIMPLE (_gtk_search_engine_simple_get_type ())
+#define GTK_SEARCH_ENGINE_SIMPLE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GTK_TYPE_SEARCH_ENGINE_SIMPLE, GtkSearchEngineSimple))
+#define GTK_SEARCH_ENGINE_SIMPLE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GTK_TYPE_SEARCH_ENGINE_SIMPLE, GtkSearchEngineSimpleClass))
+#define GTK_IS_SEARCH_ENGINE_SIMPLE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GTK_TYPE_SEARCH_ENGINE_SIMPLE))
+#define GTK_IS_SEARCH_ENGINE_SIMPLE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GTK_TYPE_SEARCH_ENGINE_SIMPLE))
+#define GTK_SEARCH_ENGINE_SIMPLE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GTK_TYPE_SEARCH_ENGINE_SIMPLE, GtkSearchEngineSimpleClass))
+
+typedef struct _GtkSearchEngineSimple GtkSearchEngineSimple;
+typedef struct _GtkSearchEngineSimpleClass GtkSearchEngineSimpleClass;
+typedef struct _GtkSearchEngineSimplePrivate GtkSearchEngineSimplePrivate;
+
+struct _GtkSearchEngineSimple
+{
+ GtkSearchEngine parent;
+
+ GtkSearchEngineSimplePrivate *priv;
+};
+
+struct _GtkSearchEngineSimpleClass
+{
+ GtkSearchEngineClass parent_class;
+};
+
+GType _gtk_search_engine_simple_get_type (void);
+
+GtkSearchEngine* _gtk_search_engine_simple_new (void);
+
+G_END_DECLS
+
+#endif /* __GTK_SEARCH_ENGINE_SIMPLE_H__ */
--- /dev/null 2007-01-30 22:42:40.851021051 -0500
+++ gtk+-2.10.9/gtk/gtksearchenginesimple.c 2007-01-30 23:29:14.000000000 -0500
@@ -0,0 +1,376 @@
+/*
+ * Copyright (C) 2005 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, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ *
+ * Author: Alexander Larsson <alexl@redhat.com>
+ *
+ * Based on nautilus-search-engine-simple.c
+ */
+
+#define _XOPEN_SOURCE 500
+#define _GNU_SOURCE
+
+#include <config.h>
+#include "gtksearchenginesimple.h"
+
+#define XDG_PREFIX _gtk_xdg
+#include "xdgmime/xdgmime.h"
+
+#include <string.h>
+#include <ftw.h>
+#include <glib/gstrfuncs.h>
+
+#define BATCH_SIZE 500
+
+typedef struct
+{
+ GtkSearchEngineSimple *engine;
+
+ gchar *path;
+ GList *mime_types;
+ gchar **words;
+ GList *found_list;
+
+ gint n_processed_files;
+ GList *uri_hits;
+
+ /* accessed on both threads: */
+ volatile gboolean cancelled;
+} SearchThreadData;
+
+
+struct _GtkSearchEngineSimplePrivate
+{
+ GtkQuery *query;
+
+ SearchThreadData *active_search;
+
+ gboolean query_finished;
+};
+
+
+G_DEFINE_TYPE (GtkSearchEngineSimple, _gtk_search_engine_simple, GTK_TYPE_SEARCH_ENGINE);
+
+static void
+finalize (GObject *object)
+{
+ GtkSearchEngineSimple *simple;
+
+ simple = GTK_SEARCH_ENGINE_SIMPLE (object);
+
+ if (simple->priv->query)
+ {
+ g_object_unref (simple->priv->query);
+ simple->priv->query = NULL;
+ }
+
+ G_OBJECT_CLASS (_gtk_search_engine_simple_parent_class)->finalize (object);
+}
+
+static SearchThreadData *
+search_thread_data_new (GtkSearchEngineSimple *engine,
+ GtkQuery *query)
+{
+ SearchThreadData *data;
+ char *text, *lower, *uri;
+
+ data = g_new0 (SearchThreadData, 1);
+
+ data->engine = engine;
+ uri = _gtk_query_get_location (query);
+ if (uri != NULL)
+ {
+ data->path = g_filename_from_uri (uri, NULL, NULL);
+ g_free (uri);
+ }
+ if (data->path == NULL)
+ data->path = g_strdup (g_get_home_dir ());
+
+ text = _gtk_query_get_text (query);
+ lower = g_ascii_strdown (text, -1);
+ data->words = g_strsplit (lower, " ", -1);
+ g_free (text);
+ g_free (lower);
+
+ data->mime_types = _gtk_query_get_mime_types (query);
+
+ return data;
+}
+
+static void
+search_thread_data_free (SearchThreadData *data)
+{
+ g_free (data->path);
+ g_strfreev (data->words);
+ g_list_foreach (data->mime_types, (GFunc)g_free, NULL);
+ g_list_free (data->mime_types);
+ g_free (data);
+}
+
+static gboolean
+search_thread_done_idle (gpointer user_data)
+{
+ SearchThreadData *data;
+
+ data = user_data;
+
+ if (!data->cancelled)
+ {
+ _gtk_search_engine_finished (GTK_SEARCH_ENGINE (data->engine));
+ data->engine->priv->active_search = NULL;
+ }
+
+ search_thread_data_free (data);
+
+ return FALSE;
+}
+
+typedef struct
+{
+ GList *uris;
+ SearchThreadData *thread_data;
+} SearchHits;
+
+
+static gboolean
+search_thread_add_hits_idle (gpointer user_data)
+{
+ SearchHits *hits;
+
+ hits = user_data;
+
+ if (!hits->thread_data->cancelled)
+ {
+ _gtk_search_engine_hits_added (GTK_SEARCH_ENGINE (hits->thread_data->engine),
+ hits->uris);
+ }
+
+ g_list_foreach (hits->uris, (GFunc)g_free, NULL);
+ g_list_free (hits->uris);
+ g_free (hits);
+
+ return FALSE;
+}
+
+static void
+send_batch (SearchThreadData *data)
+{
+ SearchHits *hits;
+
+ data->n_processed_files = 0;
+
+ if (data->uri_hits)
+ {
+ hits = g_new (SearchHits, 1);
+ hits->uris = data->uri_hits;
+ hits->thread_data = data;
+ g_idle_add (search_thread_add_hits_idle, hits);
+ }
+ data->uri_hits = NULL;
+}
+
+static GStaticPrivate search_thread_data = G_STATIC_PRIVATE_INIT;
+
+static int
+search_visit_func (const char *fpath,
+ const struct stat *sb,
+ int typeflag,
+ struct FTW *ftwbuf)
+{
+ SearchThreadData *data;
+ gint i;
+ const gchar *name;
+ gchar *lower_name, *path, *mime_type;
+ gchar *uri;
+ gboolean hit;
+ GList *l;
+ gboolean is_hidden;
+
+ data = (SearchThreadData*)g_static_private_get (&search_thread_data);
+
+ if (data->cancelled)
+ return FTW_STOP;
+
+ name = strrchr (fpath, '/');
+ if (name)
+ name++;
+ else
+ name = fpath;
+
+ path = g_build_filename (data->path, fpath, NULL);
+
+ is_hidden = *name == '.';
+
+ hit = FALSE;
+
+ if (!is_hidden)
+ {
+ lower_name = g_ascii_strdown (name, -1);
+
+ hit = TRUE;
+ for (i = 0; data->words[i] != NULL; i++)
+ {
+ if (strstr (lower_name, data->words[i]) == NULL)
+ {
+ hit = FALSE;
+ break;
+ }
+ }
+ g_free (lower_name);
+ }
+
+ if (hit && data->mime_types != NULL)
+ {
+ hit = FALSE;
+ mime_type = xdg_mime_get_mime_type_for_file (path, (struct stat *)sb);
+ for (l = data->mime_types; l != NULL; l = l->next)
+ {
+ if (strcmp (mime_type, l->data) == 0)
+ {
+ hit = TRUE;
+ break;
+ }
+ }
+
+ g_free (mime_type);
+ }
+
+ if (hit)
+ {
+ uri = g_filename_to_uri (path, NULL, NULL);
+ data->uri_hits = g_list_prepend (data->uri_hits, uri);
+ }
+
+ data->n_processed_files++;
+
+ if (data->n_processed_files > BATCH_SIZE)
+ send_batch (data);
+
+ if (is_hidden)
+ return FTW_SKIP_SUBTREE;
+ else
+ return FTW_CONTINUE;
+}
+
+static gpointer
+search_thread_func (gpointer user_data)
+{
+ SearchThreadData *data;
+
+ data = user_data;
+
+ g_static_private_set (&search_thread_data, data, NULL);
+
+ nftw (data->path, search_visit_func, 20, FTW_ACTIONRETVAL | FTW_PHYS);
+
+ send_batch (data);
+
+ g_idle_add (search_thread_done_idle, data);
+
+ return NULL;
+}
+
+static void
+gtk_search_engine_simple_start (GtkSearchEngine *engine)
+{
+ GtkSearchEngineSimple *simple;
+ SearchThreadData *data;
+
+ simple = GTK_SEARCH_ENGINE_SIMPLE (engine);
+
+ if (simple->priv->active_search != NULL)
+ return;
+
+ if (simple->priv->query == NULL)
+ return;
+
+ data = search_thread_data_new (simple, simple->priv->query);
+
+ g_thread_create (search_thread_func, data, FALSE, NULL);
+
+ simple->priv->active_search = data;
+}
+
+static void
+gtk_search_engine_simple_stop (GtkSearchEngine *engine)
+{
+ GtkSearchEngineSimple *simple;
+
+ simple = GTK_SEARCH_ENGINE_SIMPLE (engine);
+
+ if (simple->priv->active_search != NULL)
+ {
+ simple->priv->active_search->cancelled = TRUE;
+ simple->priv->active_search = NULL;
+ }
+}
+
+static gboolean
+gtk_search_engine_simple_is_indexed (GtkSearchEngine *engine)
+{
+ return FALSE;
+}
+
+static void
+gtk_search_engine_simple_set_query (GtkSearchEngine *engine,
+ GtkQuery *query)
+{
+ GtkSearchEngineSimple *simple;
+
+ simple = GTK_SEARCH_ENGINE_SIMPLE (engine);
+
+ if (query)
+ g_object_ref (query);
+
+ if (simple->priv->query)
+ g_object_unref (simple->priv->query);
+
+ simple->priv->query = query;
+}
+
+static void
+_gtk_search_engine_simple_class_init (GtkSearchEngineSimpleClass *class)
+{
+ GObjectClass *gobject_class;
+ GtkSearchEngineClass *engine_class;
+
+ gobject_class = G_OBJECT_CLASS (class);
+ gobject_class->finalize = finalize;
+
+ engine_class = GTK_SEARCH_ENGINE_CLASS (class);
+ engine_class->set_query = gtk_search_engine_simple_set_query;
+ engine_class->start = gtk_search_engine_simple_start;
+ engine_class->stop = gtk_search_engine_simple_stop;
+ engine_class->is_indexed = gtk_search_engine_simple_is_indexed;
+
+ g_type_class_add_private (gobject_class, sizeof (GtkSearchEngineSimplePrivate));
+}
+
+static void
+_gtk_search_engine_simple_init (GtkSearchEngineSimple *engine)
+{
+ engine->priv = G_TYPE_INSTANCE_GET_PRIVATE (engine, GTK_TYPE_SEARCH_ENGINE_SIMPLE, GtkSearchEngineSimplePrivate);
+}
+
+GtkSearchEngine *
+_gtk_search_engine_simple_new (void)
+{
+ GtkSearchEngine *engine;
+
+ engine = g_object_new (GTK_TYPE_SEARCH_ENGINE_SIMPLE, NULL);
+
+ return engine;
+}
--- /dev/null 2007-01-30 22:42:40.851021051 -0500
+++ gtk+-2.10.9/gtk/gtksearchenginebeagle.c 2007-01-30 23:27:42.000000000 -0500
@@ -0,0 +1,420 @@
+/*
+ * Copyright (C) 2005 Novell, 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, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ *
+ * Author: Anders Carlsson <andersca@imendio.com>
+ *
+ * Based on nautilus-search-engine-beagle.c
+ */
+
+#include <config.h>
+#include <gmodule.h>
+#include "gtksearchenginebeagle.h"
+#if 0
+#include <beagle/beagle.h>
+#endif
+
+/* We dlopen() all the following from libbeagle at runtime */
+
+typedef struct _BeagleHit BeagleHit;
+typedef struct _BeagleQuery BeagleQuery;
+typedef struct _BeagleClient BeagleClient;
+typedef struct _BeagleRequest BeagleRequest;
+typedef struct _BeagleFinishedResponse BeagleFinishedResponse;
+typedef struct _BeagleHitsAddedResponse BeagleHitsAddedResponse;
+typedef struct _BeagleHitsSubtractedResponse BeagleHitsSubtractedResponse;
+typedef struct _BeagleQueryPartProperty BeagleQueryPartProperty;
+typedef struct _BeagleQueryPart BeagleQueryPart;
+
+#define BEAGLE_HIT(x) ((BeagleHit *)(x))
+#define BEAGLE_REQUEST(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), beagle_request_get_type(), BeagleRequest))
+#define BEAGLE_QUERY_PART(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), beagle_query_part_get_type(), BeagleQueryPart))
+
+typedef enum
+{
+ BEAGLE_QUERY_PART_LOGIC_REQUIRED = 1,
+ BEAGLE_QUERY_PART_LOGIC_PROHIBITED = 2
+} BeagleQueryPartLogic;
+
+typedef enum
+ {
+ BEAGLE_PROPERTY_TYPE_UNKNOWN = 0,
+ BEAGLE_PROPERTY_TYPE_TEXT = 1,
+ BEAGLE_PROPERTY_TYPE_KEYWORD = 2,
+ BEAGLE_PROPERTY_TYPE_DATE = 3,
+ BEAGLE_PROPERTY_TYPE_LAST = 4
+} BeaglePropertyType;
+
+/* *static* wrapper function pointers */
+static gboolean (*beagle_client_send_request_async) (BeagleClient *client,
+ BeagleRequest *request,
+ GError **err) = NULL;
+static G_CONST_RETURN char *(*beagle_hit_get_uri) (BeagleHit *hit) = NULL;
+static GSList *(*beagle_hits_added_response_get_hits) (BeagleHitsAddedResponse *response) = NULL;
+static GSList *(*beagle_hits_subtracted_response_get_uris) (BeagleHitsSubtractedResponse *response) = NULL;
+static BeagleQuery *(*beagle_query_new) (void) = NULL;
+static void (*beagle_query_add_text) (BeagleQuery *query,
+ const char *str) = NULL;
+static void (*beagle_query_add_hit_type) (BeagleQuery *query,
+ const char *hit_type) = NULL;
+static void (*beagle_query_add_mime_type) (BeagleQuery *query,
+ const char *mime_type) = NULL;
+static void (*beagle_query_set_max_hits) (BeagleQuery *query,
+ gint max_hits) = NULL;
+static BeagleQueryPartProperty *(*beagle_query_part_property_new) (void) = NULL;
+static void (*beagle_query_part_set_logic) (BeagleQueryPart *part,
+ BeagleQueryPartLogic logic) = NULL;
+static void (*beagle_query_part_property_set_key) (BeagleQueryPartProperty *part,
+ const char *key) = NULL;
+static void (*beagle_query_part_property_set_value) (BeagleQueryPartProperty *part,
+ const char * value) = NULL;
+static void (*beagle_query_part_property_set_property_type) (BeagleQueryPartProperty *part,
+ BeaglePropertyType prop_type) = NULL;
+static void (*beagle_query_add_part) (BeagleQuery *query,
+ BeagleQueryPart *part) = NULL;
+static GType (*beagle_request_get_type) (void) = NULL;
+static GType (*beagle_query_part_get_type) (void) = NULL;
+static gboolean (*beagle_util_daemon_is_running) (void) = NULL;
+static BeagleClient *(*beagle_client_new) (const char *client_name) = NULL;
+
+static struct BeagleDlMapping
+{
+ const char *fn_name;
+ gpointer *fn_ptr_ref;
+} beagle_dl_mapping[] =
+{
+#define MAP(a) { #a, (gpointer *)&a }
+ MAP (beagle_client_send_request_async),
+ MAP (beagle_hit_get_uri),
+ MAP (beagle_hits_added_response_get_hits),
+ MAP (beagle_hits_subtracted_response_get_uris),
+ MAP (beagle_query_new),
+ MAP (beagle_query_add_text),
+ MAP (beagle_query_add_hit_type),
+ MAP (beagle_query_add_mime_type),
+ MAP (beagle_query_set_max_hits),
+ MAP (beagle_query_part_property_new),
+ MAP (beagle_query_part_set_logic),
+ MAP (beagle_query_part_property_set_key),
+ MAP (beagle_query_part_property_set_value),
+ MAP (beagle_query_part_property_set_property_type),
+ MAP (beagle_query_add_part),
+ MAP (beagle_request_get_type),
+ MAP (beagle_query_part_get_type),
+ MAP (beagle_util_daemon_is_running),
+ MAP (beagle_client_new)
+#undef MAP
+};
+
+static void
+open_libbeagle (void)
+{
+ static gboolean done = FALSE;
+
+ if (!done)
+ {
+ int i;
+ GModule *beagle;
+
+ done = TRUE;
+
+ beagle = g_module_open ("libbeagle.so.0", G_MODULE_BIND_LAZY | G_MODULE_BIND_LOCAL);
+ if (!beagle)
+ return;
+
+ for (i = 0; i < G_N_ELEMENTS (beagle_dl_mapping); i++)
+ {
+ if (!g_module_symbol (beagle, beagle_dl_mapping[i].fn_name,
+ beagle_dl_mapping[i].fn_ptr_ref))
+ {
+ g_warning ("Missing symbol '%s' in libbeagle\n",
+ beagle_dl_mapping[i].fn_name);
+ g_module_close (beagle);
+
+ for (i = 0; i < G_N_ELEMENTS (beagle_dl_mapping); i++)
+ beagle_dl_mapping[i].fn_ptr_ref = NULL;
+
+ return;
+ }
+ }
+ }
+}
+
+
+struct _GtkSearchEngineBeaglePrivate
+{
+ BeagleClient *client;
+ GtkQuery *query;
+
+ BeagleQuery *current_query;
+ char *current_query_uri_prefix;
+ gboolean query_finished;
+};
+
+
+G_DEFINE_TYPE (GtkSearchEngineBeagle, _gtk_search_engine_beagle, GTK_TYPE_SEARCH_ENGINE);
+
+static void
+finalize (GObject *object)
+{
+ GtkSearchEngineBeagle *beagle;
+
+ beagle = GTK_SEARCH_ENGINE_BEAGLE (object);
+
+ if (beagle->priv->current_query)
+ {
+ g_object_unref (beagle->priv->current_query);
+ beagle->priv->current_query = NULL;
+ g_free (beagle->priv->current_query_uri_prefix);
+ beagle->priv->current_query_uri_prefix = NULL;
+ }
+
+ if (beagle->priv->query)
+ {
+ g_object_unref (beagle->priv->query);
+ beagle->priv->query = NULL;
+ }
+
+ if (beagle->priv->client)
+ {
+ g_object_unref (beagle->priv->client);
+ beagle->priv->client = NULL;
+ }
+
+ G_OBJECT_CLASS (_gtk_search_engine_beagle_parent_class)->finalize (object);
+}
+
+static void
+beagle_hits_added (BeagleQuery *query,
+ BeagleHitsAddedResponse *response,
+ GtkSearchEngineBeagle *engine)
+{
+ GSList *hits, *list;
+ GList *hit_uris;
+ const gchar *uri;
+
+ hit_uris = NULL;
+
+ hits = beagle_hits_added_response_get_hits (response);
+
+ for (list = hits; list != NULL; list = list->next)
+ {
+ BeagleHit *hit = BEAGLE_HIT (list->data);
+
+ uri = beagle_hit_get_uri (hit);
+
+ if (engine->priv->current_query_uri_prefix &&
+ !g_str_has_prefix (uri, engine->priv->current_query_uri_prefix))
+ continue;
+
+ hit_uris = g_list_prepend (hit_uris, (char *)uri);
+ }
+
+ _gtk_search_engine_hits_added (GTK_SEARCH_ENGINE (engine), hit_uris);
+ g_list_free (hit_uris);
+}
+
+static void
+beagle_hits_subtracted (BeagleQuery *query,
+ BeagleHitsSubtractedResponse *response,
+ GtkSearchEngineBeagle *engine)
+{
+ GSList *uris, *list;
+ GList *hit_uris;
+
+ hit_uris = NULL;
+
+ uris = beagle_hits_subtracted_response_get_uris (response);
+
+ for (list = uris; list != NULL; list = list->next)
+ {
+ hit_uris = g_list_prepend (hit_uris, (char *)list->data);
+ }
+
+ _gtk_search_engine_hits_subtracted (GTK_SEARCH_ENGINE (engine), hit_uris);
+ g_list_free (hit_uris);
+}
+
+static void
+beagle_finished (BeagleQuery *query,
+ BeagleFinishedResponse *response,
+ GtkSearchEngineBeagle *engine)
+{
+ /* For some reason we keep getting finished events,
+ * only emit finished once */
+ if (engine->priv->query_finished)
+ return;
+
+ engine->priv->query_finished = TRUE;
+ _gtk_search_engine_finished (GTK_SEARCH_ENGINE (engine));
+}
+
+static void
+beagle_error (BeagleQuery *query,
+ GError *error,
+ GtkSearchEngineBeagle *engine)
+{
+ _gtk_search_engine_error (GTK_SEARCH_ENGINE (engine), error->message);
+}
+
+static void
+gtk_search_engine_beagle_start (GtkSearchEngine *engine)
+{
+ GtkSearchEngineBeagle *beagle;
+ GError *error;
+ GList *mimetypes, *l;
+ gchar *text, *mimetype;
+
+ error = NULL;
+ beagle = GTK_SEARCH_ENGINE_BEAGLE (engine);
+
+ if (beagle->priv->current_query)
+ return;
+
+ beagle->priv->query_finished = FALSE;
+ beagle->priv->current_query = beagle_query_new ();
+ g_signal_connect (beagle->priv->current_query,
+ "hits-added", G_CALLBACK (beagle_hits_added), engine);
+ g_signal_connect (beagle->priv->current_query,
+ "hits-subtracted", G_CALLBACK (beagle_hits_subtracted), engine);
+ g_signal_connect (beagle->priv->current_query,
+ "finished", G_CALLBACK (beagle_finished), engine);
+ g_signal_connect (beagle->priv->current_query,
+ "error", G_CALLBACK (beagle_error), engine);
+
+ /* We only want files */
+ beagle_query_add_hit_type (beagle->priv->current_query,
+ "File");
+ beagle_query_set_max_hits (beagle->priv->current_query,
+ 1000);
+
+ text = _gtk_query_get_text (beagle->priv->query);
+ beagle_query_add_text (beagle->priv->current_query,
+ text);
+
+ mimetypes = _gtk_query_get_mime_types (beagle->priv->query);
+ for (l = mimetypes; l != NULL; l = l->next)
+ {
+ mimetype = l->data;
+ beagle_query_add_mime_type (beagle->priv->current_query, mimetype);
+ }
+
+ beagle->priv->current_query_uri_prefix = _gtk_query_get_location (beagle->priv->query);
+
+ if (!beagle_client_send_request_async (beagle->priv->client,
+ BEAGLE_REQUEST (beagle->priv->current_query), &error))
+ {
+ _gtk_search_engine_error (engine, error->message);
+ g_error_free (error);
+ }
+
+ /* These must live during the lifetime of the query */
+ g_free (text);
+ g_list_foreach (mimetypes, (GFunc)g_free, NULL);
+ g_list_free (mimetypes);
+}
+
+static void
+gtk_search_engine_beagle_stop (GtkSearchEngine *engine)
+{
+ GtkSearchEngineBeagle *beagle;
+
+ beagle = GTK_SEARCH_ENGINE_BEAGLE (engine);
+
+ if (beagle->priv->current_query)
+ {
+ g_object_unref (beagle->priv->current_query);
+ beagle->priv->current_query = NULL;
+ g_free (beagle->priv->current_query_uri_prefix);
+ beagle->priv->current_query_uri_prefix = NULL;
+ }
+}
+
+static gboolean
+gtk_search_engine_beagle_is_indexed (GtkSearchEngine *engine)
+{
+ return TRUE;
+}
+
+static void
+gtk_search_engine_beagle_set_query (GtkSearchEngine *engine,
+ GtkQuery *query)
+{
+ GtkSearchEngineBeagle *beagle;
+
+ beagle = GTK_SEARCH_ENGINE_BEAGLE (engine);
+
+ if (query)
+ g_object_ref (query);
+
+ if (beagle->priv->query)
+ g_object_unref (beagle->priv->query);
+
+ beagle->priv->query = query;
+}
+
+static void
+_gtk_search_engine_beagle_class_init (GtkSearchEngineBeagleClass *class)
+{
+ GObjectClass *gobject_class;
+ GtkSearchEngineClass *engine_class;
+
+ gobject_class = G_OBJECT_CLASS (class);
+ gobject_class->finalize = finalize;
+
+ engine_class = GTK_SEARCH_ENGINE_CLASS (class);
+ engine_class->set_query = gtk_search_engine_beagle_set_query;
+ engine_class->start = gtk_search_engine_beagle_start;
+ engine_class->stop = gtk_search_engine_beagle_stop;
+ engine_class->is_indexed = gtk_search_engine_beagle_is_indexed;
+
+ g_type_class_add_private (gobject_class, sizeof (GtkSearchEngineBeaglePrivate));
+}
+
+static void
+_gtk_search_engine_beagle_init (GtkSearchEngineBeagle *engine)
+{
+ engine->priv = G_TYPE_INSTANCE_GET_PRIVATE (engine, GTK_TYPE_SEARCH_ENGINE_BEAGLE, GtkSearchEngineBeaglePrivate);
+}
+
+
+GtkSearchEngine *
+_gtk_search_engine_beagle_new (void)
+{
+ GtkSearchEngineBeagle *engine;
+ BeagleClient *client;
+
+ open_libbeagle ();
+
+ if (!beagle_util_daemon_is_running)
+ return NULL;
+
+ /* check whether daemon is running as beagle_client_new
+ * doesn't fail when a stale socket file exists */
+ if (!beagle_util_daemon_is_running ())
+ return NULL;
+
+ client = beagle_client_new (NULL);
+
+ if (client == NULL)
+ return NULL;
+
+ engine = g_object_new (GTK_TYPE_SEARCH_ENGINE_BEAGLE, NULL);
+
+ engine->priv->client = client;
+
+ return GTK_SEARCH_ENGINE (engine);
+}
--- /dev/null 2007-01-30 22:42:40.851021051 -0500
+++ gtk+-2.10.9/gtk/gtkquery.c 2007-01-30 23:27:42.000000000 -0500
@@ -0,0 +1,142 @@
+/*
+ * Copyright (C) 2005 Novell, 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, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ *
+ * Author: Anders Carlsson <andersca@imendio.com>
+ *
+ * Based on nautilus-query.c
+ */
+
+#include <config.h>
+#include <string.h>
+
+#include "gtkquery.h"
+
+struct _GtkQueryPrivate
+{
+ gchar *text;
+ gchar *location_uri;
+ GList *mime_types;
+};
+
+G_DEFINE_TYPE (GtkQuery, _gtk_query, G_TYPE_OBJECT);
+
+static void
+finalize (GObject *object)
+{
+ GtkQuery *query;
+
+ query = GTK_QUERY (object);
+
+ g_free (query->priv->text);
+
+ G_OBJECT_CLASS (_gtk_query_parent_class)->finalize (object);
+}
+
+static void
+_gtk_query_class_init (GtkQueryClass *class)
+{
+ GObjectClass *gobject_class;
+
+ gobject_class = G_OBJECT_CLASS (class);
+ gobject_class->finalize = finalize;
+
+ g_type_class_add_private (gobject_class, sizeof (GtkQueryPrivate));
+}
+
+static void
+_gtk_query_init (GtkQuery *query)
+{
+ query->priv = G_TYPE_INSTANCE_GET_PRIVATE (query, GTK_TYPE_QUERY, GtkQueryPrivate);
+}
+
+GtkQuery *
+_gtk_query_new (void)
+{
+ return g_object_new (GTK_TYPE_QUERY, NULL);
+}
+
+
+gchar *
+_gtk_query_get_text (GtkQuery *query)
+{
+ return g_strdup (query->priv->text);
+}
+
+void
+_gtk_query_set_text (GtkQuery *query,
+ const gchar *text)
+{
+ g_free (query->priv->text);
+ query->priv->text = g_strdup (text);
+}
+
+gchar *
+_gtk_query_get_location (GtkQuery *query)
+{
+ return g_strdup (query->priv->location_uri);
+}
+
+void
+_gtk_query_set_location (GtkQuery *query,
+ const gchar *uri)
+{
+ g_free (query->priv->location_uri);
+ query->priv->location_uri = g_strdup (uri);
+}
+
+GList *
+_gtk_query_get_mime_types (GtkQuery *query)
+{
+ GList *list, *l;
+ gchar *mime_type;
+
+ list = NULL;
+ for (l = query->priv->mime_types; l; l = l->next)
+ {
+ mime_type = (gchar*)l->data;
+ list = g_list_prepend (list, g_strdup (mime_type));
+ }
+
+ return list;
+}
+
+void
+_gtk_query_set_mime_types (GtkQuery *query,
+ GList *mime_types)
+{
+ GList *l;
+ gchar *mime_type;
+
+ g_list_foreach (query->priv->mime_types, (GFunc)g_free, NULL);
+ g_list_free (query->priv->mime_types);
+ query->priv->mime_types = NULL;
+
+ for (l = mime_types; l; l = l->next)
+ {
+ mime_type = (gchar*)l->data;
+ query->priv->mime_types = g_list_prepend (query->priv->mime_types, g_strdup (mime_type));
+ }
+}
+
+void
+_gtk_query_add_mime_type (GtkQuery *query,
+ const gchar *mime_type)
+{
+ query->priv->mime_types = g_list_prepend (query->priv->mime_types,
+ g_strdup (mime_type));
+}
+
--- /dev/null 2007-01-30 22:42:40.851021051 -0500
+++ gtk+-2.10.9/gtk/gtkquery.h 2007-01-30 23:27:42.000000000 -0500
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2005 Novell, 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, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ *
+ * Author: Anders Carlsson <andersca@imendio.com>
+ *
+ * Based on nautilus-query.h
+ */
+
+#ifndef __GTK_QUERY_H__
+#define __GTK_QUERY_H__
+
+#include <glib-object.h>
+
+G_BEGIN_DECLS
+
+#define GTK_TYPE_QUERY (_gtk_query_get_type ())
+#define GTK_QUERY(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GTK_TYPE_QUERY, GtkQuery))
+#define GTK_QUERY_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GTK_TYPE_QUERY, GtkQueryClass))
+#define GTK_IS_QUERY(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GTK_TYPE_QUERY))
+#define GTK_IS_QUERY_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GTK_TYPE_QUERY))
+#define GTK_QUERY_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GTK_TYPE_QUERY, GtkQueryClass))
+
+typedef struct _GtkQuery GtkQuery;
+typedef struct _GtkQueryClass GtkQueryClass;
+typedef struct _GtkQueryPrivate GtkQueryPrivate;
+
+struct _GtkQuery
+{
+ GObject parent;
+
+ GtkQueryPrivate *priv;
+};
+
+struct _GtkQueryClass
+{
+ GObjectClass parent_class;
+};
+
+GType _gtk_query_get_type (void);
+gboolean _gtk_query_enabled (void);
+
+GtkQuery* _gtk_query_new (void);
+
+gchar* _gtk_query_get_text (GtkQuery *query);
+void _gtk_query_set_text (GtkQuery *query,
+ const gchar *text);
+
+gchar* _gtk_query_get_location (GtkQuery *query);
+void _gtk_query_set_location (GtkQuery *query,
+ const gchar *uri);
+
+GList* _gtk_query_get_mime_types (GtkQuery *query);
+void _gtk_query_set_mime_types (GtkQuery *query,
+ GList *mime_types);
+void _gtk_query_add_mime_type (GtkQuery *query,
+ const gchar *mime_type);
+
+G_END_DECLS
+
+#endif /* __GTK_QUERY_H__ */