summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGeorges Basile Stavracas Neto <georges.stavracas@gmail.com>2015-10-05 21:07:25 -0300
committerCarlos Soriano <csoriano@gnome.org>2016-02-02 20:43:04 +0100
commitcb7c77a8acf857c3bf16e73bc7beba4b9d09faac (patch)
tree075cafcda4eb92313de7e2681aa183a3e1fe982d
parent2e72a3a0f3de75f2df5943133e8d70a4ba0aa3fa (diff)
downloadnautilus-cb7c77a8acf857c3bf16e73bc7beba4b9d09faac.tar.gz
search-popover: add popover to edit search filters
The newest mockups for Nautilus search shows a popover that contains all the necessary options to edit search filters. This commit implements it. The following commits will adapt NautilusQueryEditor to match the latest mockups and display this popover.
-rw-r--r--src/Makefile.am3
-rw-r--r--src/nautilus-query-editor.c1209
-rw-r--r--src/nautilus-query-editor.h26
-rw-r--r--src/nautilus-search-popover.c1105
-rw-r--r--src/nautilus-search-popover.h54
-rw-r--r--src/nautilus-window-slot.c31
-rw-r--r--src/resources/nautilus.gresource.xml1
-rw-r--r--src/resources/ui/nautilus-search-popover.ui454
8 files changed, 1959 insertions, 924 deletions
diff --git a/src/Makefile.am b/src/Makefile.am
index 445720bf7..20fe984ab 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -75,6 +75,7 @@ $(dbus_shell_search_provider_built_sources) : Makefile.am $(top_srcdir)/data/she
$(NULL)
headers = \
+ nautilus-search-popover.h \
nautilus-special-location-bar.h \
$(NULL)
@@ -196,6 +197,8 @@ nautilus_SOURCES = \
nautilus-properties-window.h \
nautilus-query-editor.c \
nautilus-query-editor.h \
+ nautilus-search-popover.c \
+ nautilus-search-popover.h \
nautilus-self-check-functions.c \
nautilus-self-check-functions.h \
nautilus-shell-search-provider.h \
diff --git a/src/nautilus-query-editor.c b/src/nautilus-query-editor.c
index 7ac85e084..5883c66d0 100644
--- a/src/nautilus-query-editor.c
+++ b/src/nautilus-query-editor.c
@@ -1,4 +1,4 @@
-/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
+/* -*- Mode: C; indent-tabs-mode: s; c-basic-offset: 8; tab-width: 8 -*- */
/*
* Copyright (C) 2005 Red Hat, Inc.
*
@@ -17,11 +17,13 @@
* see <http://www.gnu.org/licenses/>.
*
* Author: Alexander Larsson <alexl@redhat.com>
+ * Georges Basile Stavracas Neto <gbsneto@gnome.org>
*
*/
#include <config.h>
#include "nautilus-query-editor.h"
+#include "nautilus-search-popover.h"
#include <string.h>
#include <glib/gi18n.h>
@@ -31,170 +33,149 @@
#include <eel/eel-glib-extensions.h>
#include <libnautilus-private/nautilus-file-utilities.h>
-
-typedef enum {
- NAUTILUS_QUERY_EDITOR_ROW_TYPE,
-
- NAUTILUS_QUERY_EDITOR_ROW_LAST
-} NautilusQueryEditorRowType;
+#include <libnautilus-private/nautilus-global-preferences.h>
typedef struct {
- NautilusQueryEditorRowType type;
- NautilusQueryEditor *editor;
- GtkWidget *toolbar;
- GtkWidget *hbox;
- GtkWidget *combo;
-
- GtkWidget *type_widget;
-} NautilusQueryEditorRow;
-
-
-typedef struct {
- const char *name;
- GtkWidget * (*create_widgets) (NautilusQueryEditorRow *row);
- void (*add_to_query) (NautilusQueryEditorRow *row,
- NautilusQuery *query);
- void (*add_rows_from_query) (NautilusQueryEditor *editor,
- NautilusQuery *query);
-} NautilusQueryEditorRowOps;
-
-struct NautilusQueryEditorDetails {
GtkWidget *entry;
+ GtkWidget *popover;
+ GtkWidget *label;
+ GtkWidget *spinner;
gboolean change_frozen;
- GtkWidget *search_current_button;
- GtkWidget *search_all_button;
- GFile *current_location;
+ GBinding *spinner_active_binding;
- GList *rows;
+ GFile *location;
NautilusQuery *query;
-};
+} NautilusQueryEditorPrivate;
enum {
ACTIVATED,
CHANGED,
CANCEL,
LAST_SIGNAL
-};
+};
+
+enum {
+ PROP_0,
+ PROP_LOCATION,
+ PROP_QUERY,
+ LAST_PROP
+};
static guint signals[LAST_SIGNAL];
static void entry_activate_cb (GtkWidget *entry, NautilusQueryEditor *editor);
static void entry_changed_cb (GtkWidget *entry, NautilusQueryEditor *editor);
-static void nautilus_query_editor_changed_force (NautilusQueryEditor *editor,
- gboolean force);
static void nautilus_query_editor_changed (NautilusQueryEditor *editor);
-static NautilusQueryEditorRow * nautilus_query_editor_add_row (NautilusQueryEditor *editor,
- NautilusQueryEditorRowType type);
-
-static GtkWidget *type_row_create_widgets (NautilusQueryEditorRow *row);
-static void type_row_add_to_query (NautilusQueryEditorRow *row,
- NautilusQuery *query);
-static void type_add_rows_from_query (NautilusQueryEditor *editor,
- NautilusQuery *query);
+G_DEFINE_TYPE_WITH_PRIVATE (NautilusQueryEditor, nautilus_query_editor, GTK_TYPE_SEARCH_BAR);
-static NautilusQueryEditorRowOps row_type[] = {
- { N_("File Type"),
- type_row_create_widgets,
- type_row_add_to_query,
- type_add_rows_from_query
- },
-};
+static void
+query_recursive_changed (GObject *object,
+ GParamSpec *pspec,
+ NautilusQueryEditor *editor)
+{
+ NautilusQueryEditorPrivate *priv;
+ gchar *key;
-G_DEFINE_TYPE (NautilusQueryEditor, nautilus_query_editor, GTK_TYPE_BOX);
+ priv = nautilus_query_editor_get_instance_private (editor);
+ key = "enable-recursive-search";
-gboolean
-nautilus_query_editor_handle_event (NautilusQueryEditor *editor,
- GdkEventKey *event)
-{
- GtkWidget *toplevel;
- GtkWidget *old_focus;
- GdkEvent *new_event;
- gboolean retval;
-
- /* if we're focused already, no need to handle the event manually */
- if (gtk_widget_has_focus (editor->details->entry)) {
- return FALSE;
- }
+ if (priv->location) {
+ NautilusFile *file;
- /* never handle these events */
- if (event->keyval == GDK_KEY_slash || event->keyval == GDK_KEY_Delete) {
- return FALSE;
- }
+ file = nautilus_file_get (priv->location);
- /* don't activate search for these events */
- if (!gtk_widget_get_visible (GTK_WIDGET (editor)) && event->keyval == GDK_KEY_space) {
- return FALSE;
- }
+ if (!nautilus_file_is_local (file)) {
+ key = "enable-remote-recursive-search";
+ }
- /* if it's not printable we don't need it */
- if (!g_unichar_isprint (gdk_keyval_to_unicode (event->keyval))) {
- return FALSE;
- }
+ nautilus_file_unref (file);
+ }
- if (!gtk_widget_get_realized (editor->details->entry)) {
- gtk_widget_realize (editor->details->entry);
- }
+ g_settings_set_boolean (nautilus_preferences,
+ key,
+ nautilus_query_get_recursive (NAUTILUS_QUERY (object)));
+}
- toplevel = gtk_widget_get_toplevel (GTK_WIDGET (editor));
- if (gtk_widget_is_toplevel (toplevel)) {
- old_focus = gtk_window_get_focus (GTK_WINDOW (toplevel));
- } else {
- old_focus = NULL;
- }
- /* input methods will typically only process events after getting focus */
- gtk_widget_grab_focus (editor->details->entry);
+static void
+nautilus_query_editor_dispose (GObject *object)
+{
+ NautilusQueryEditorPrivate *priv;
- new_event = gdk_event_copy ((GdkEvent *) event);
- g_object_unref (((GdkEventKey *) new_event)->window);
- ((GdkEventKey *) new_event)->window = g_object_ref
- (gtk_widget_get_window (editor->details->entry));
- retval = gtk_widget_event (editor->details->entry, new_event);
- gdk_event_free (new_event);
+ priv = nautilus_query_editor_get_instance_private (NAUTILUS_QUERY_EDITOR (object));
- if (!retval && old_focus) {
- gtk_widget_grab_focus (old_focus);
- }
+ g_clear_object (&priv->location);
+ g_clear_object (&priv->query);
- return retval;
+ G_OBJECT_CLASS (nautilus_query_editor_parent_class)->dispose (object);
}
static void
-row_destroy (NautilusQueryEditorRow *row)
+nautilus_query_editor_grab_focus (GtkWidget *widget)
{
- gtk_widget_destroy (row->toolbar);
- g_free (row);
+ NautilusQueryEditorPrivate *priv;
+
+ priv = nautilus_query_editor_get_instance_private (NAUTILUS_QUERY_EDITOR (widget));
+
+ if (gtk_widget_get_visible (widget) && !gtk_widget_is_focus (priv->entry)) {
+ /* avoid selecting the entry text */
+ gtk_widget_grab_focus (priv->entry);
+ gtk_editable_set_position (GTK_EDITABLE (priv->entry), -1);
+ }
}
static void
-nautilus_query_editor_dispose (GObject *object)
+nautilus_query_editor_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
{
- NautilusQueryEditor *editor;
+ NautilusQueryEditorPrivate *priv;
- editor = NAUTILUS_QUERY_EDITOR (object);
+ priv = nautilus_query_editor_get_instance_private (NAUTILUS_QUERY_EDITOR (object));
- g_clear_object (&editor->details->query);
+ switch (prop_id)
+ {
+ case PROP_LOCATION:
+ g_value_set_object (value, priv->location);
+ break;
- g_list_free_full (editor->details->rows, (GDestroyNotify) row_destroy);
- editor->details->rows = NULL;
+ case PROP_QUERY:
+ g_value_set_object (value, priv->query);
+ break;
- G_OBJECT_CLASS (nautilus_query_editor_parent_class)->dispose (object);
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ }
}
static void
-nautilus_query_editor_grab_focus (GtkWidget *widget)
+nautilus_query_editor_set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec)
{
- NautilusQueryEditor *editor = NAUTILUS_QUERY_EDITOR (widget);
+ NautilusQueryEditor *self;
- if (gtk_widget_get_visible (widget) && !gtk_widget_is_focus (editor->details->entry)) {
- /* avoid selecting the entry text */
- gtk_widget_grab_focus (editor->details->entry);
- gtk_editable_set_position (GTK_EDITABLE (editor->details->entry), -1);
- }
+ self = NAUTILUS_QUERY_EDITOR (object);
+
+ switch (prop_id)
+ {
+ case PROP_LOCATION:
+ nautilus_query_editor_set_location (self, g_value_get_object (value));
+ break;
+
+ case PROP_QUERY:
+ nautilus_query_editor_set_query (self, g_value_get_object (value));
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ }
}
static void
@@ -205,6 +186,8 @@ nautilus_query_editor_class_init (NautilusQueryEditorClass *class)
gobject_class = G_OBJECT_CLASS (class);
gobject_class->dispose = nautilus_query_editor_dispose;
+ gobject_class->get_property = nautilus_query_editor_get_property;
+ gobject_class->set_property = nautilus_query_editor_set_property;
widget_class = GTK_WIDGET_CLASS (class);
widget_class->grab_focus = nautilus_query_editor_grab_focus;
@@ -236,815 +219,279 @@ nautilus_query_editor_class_init (NautilusQueryEditorClass *class)
g_cclosure_marshal_VOID__VOID,
G_TYPE_NONE, 0);
- g_type_class_add_private (class, sizeof (NautilusQueryEditorDetails));
+ /**
+ * NautilusQueryEditor::location:
+ *
+ * The current location of the query editor.
+ */
+ g_object_class_install_property (gobject_class,
+ PROP_LOCATION,
+ g_param_spec_object ("location",
+ "Location of the search",
+ "The current location of the editor",
+ G_TYPE_FILE,
+ G_PARAM_READWRITE));
+
+ /**
+ * NautilusQueryEditor::query:
+ *
+ * The current query of the query editor. It it always synchronized
+ * with the filter popover's query.
+ */
+ g_object_class_install_property (gobject_class,
+ PROP_QUERY,
+ g_param_spec_object ("query",
+ "Query of the search",
+ "The query that the editor is handling",
+ NAUTILUS_TYPE_QUERY,
+ G_PARAM_READWRITE));
}
GFile *
nautilus_query_editor_get_location (NautilusQueryEditor *editor)
{
- GFile *file = NULL;
- if (editor->details->current_location != NULL)
- file = g_object_ref (editor->details->current_location);
- return file;
-}
+ NautilusQueryEditorPrivate *priv;
-static void
-entry_activate_cb (GtkWidget *entry, NautilusQueryEditor *editor)
-{
- g_signal_emit (editor, signals[ACTIVATED], 0);
-}
+ g_return_val_if_fail (NAUTILUS_IS_QUERY_EDITOR (editor), NULL);
-static void
-entry_changed_cb (GtkWidget *entry, NautilusQueryEditor *editor)
-{
- if (editor->details->change_frozen) {
- return;
- }
+ priv = nautilus_query_editor_get_instance_private (editor);
- nautilus_query_editor_changed (editor);
+ return g_object_ref (priv->location);
}
-static void
-nautilus_query_editor_on_stop_search (GtkWidget *entry,
- NautilusQueryEditor *editor)
+static NautilusQuery*
+create_and_get_query (NautilusQueryEditor *editor)
{
- g_signal_emit (editor, signals[CANCEL], 0);
-}
+ NautilusQueryEditorPrivate *priv;
-/* Type */
+ priv = nautilus_query_editor_get_instance_private (editor);
-static gboolean
-type_separator_func (GtkTreeModel *model,
- GtkTreeIter *iter,
- gpointer data)
-{
- char *text;
- gboolean res;
-
- gtk_tree_model_get (model, iter, 0, &text, -1);
+ if (!priv->query) {
+ NautilusQuery *query;
+ NautilusFile *file;
+ gboolean recursive;
- res = text != NULL && strcmp (text, "---") == 0;
-
- g_free (text);
- return res;
-}
+ file = nautilus_file_get (priv->location);
+ query = nautilus_query_new ();
-struct {
- char *name;
- char *mimetypes[20];
-} mime_type_groups[] = {
- { N_("Documents"),
- { "application/rtf",
- "application/msword",
- "application/vnd.sun.xml.writer",
- "application/vnd.sun.xml.writer.global",
- "application/vnd.sun.xml.writer.template",
- "application/vnd.oasis.opendocument.text",
- "application/vnd.oasis.opendocument.text-template",
- "application/x-abiword",
- "application/x-applix-word",
- "application/x-mswrite",
- "application/docbook+xml",
- "application/x-kword",
- "application/x-kword-crypt",
- "application/x-lyx",
- NULL
- }
- },
- { N_("Music"),
- { "application/ogg",
- "audio/x-vorbis+ogg",
- "audio/ac3",
- "audio/basic",
- "audio/midi",
- "audio/x-flac",
- "audio/mp4",
- "audio/mpeg",
- "audio/x-mpeg",
- "audio/x-ms-asx",
- "audio/x-pn-realaudio",
- NULL
- }
- },
- { N_("Video"),
- { "video/mp4",
- "video/3gpp",
- "video/mpeg",
- "video/quicktime",
- "video/vivo",
- "video/x-avi",
- "video/x-mng",
- "video/x-ms-asf",
- "video/x-ms-wmv",
- "video/x-msvideo",
- "video/x-nsv",
- "video/x-real-video",
- NULL
- }
- },
- { N_("Picture"),
- { "application/vnd.oasis.opendocument.image",
- "application/x-krita",
- "image/bmp",
- "image/cgm",
- "image/gif",
- "image/jpeg",
- "image/jpeg2000",
- "image/png",
- "image/svg+xml",
- "image/tiff",
- "image/x-compressed-xcf",
- "image/x-pcx",
- "image/x-photo-cd",
- "image/x-psd",
- "image/x-tga",
- "image/x-xcf",
- NULL
- }
- },
- { N_("Illustration"),
- { "application/illustrator",
- "application/vnd.corel-draw",
- "application/vnd.stardivision.draw",
- "application/vnd.oasis.opendocument.graphics",
- "application/x-dia-diagram",
- "application/x-karbon",
- "application/x-killustrator",
- "application/x-kivio",
- "application/x-kontour",
- "application/x-wpg",
- NULL
- }
- },
- { N_("Spreadsheet"),
- { "application/vnd.lotus-1-2-3",
- "application/vnd.ms-excel",
- "application/vnd.stardivision.calc",
- "application/vnd.sun.xml.calc",
- "application/vnd.oasis.opendocument.spreadsheet",
- "application/x-applix-spreadsheet",
- "application/x-gnumeric",
- "application/x-kspread",
- "application/x-kspread-crypt",
- "application/x-quattropro",
- "application/x-sc",
- "application/x-siag",
- NULL
- }
- },
- { N_("Presentation"),
- { "application/vnd.ms-powerpoint",
- "application/vnd.sun.xml.impress",
- "application/vnd.oasis.opendocument.presentation",
- "application/x-magicpoint",
- "application/x-kpresenter",
- NULL
- }
- },
- { N_("PDF / PostScript"),
- { "application/pdf",
- "application/postscript",
- "application/x-dvi",
- "image/x-eps",
- NULL
- }
- },
- { N_("Text File"),
- { "text/plain",
- NULL
- }
- }
-};
+ if (nautilus_file_is_remote (file)) {
+ recursive = g_settings_get_boolean (nautilus_preferences,
+ "enable-remote-recursive-search");
+ } else {
+ recursive = g_settings_get_boolean (nautilus_preferences,
+ "enable-recursive-search");
+ }
-static void
-type_add_custom_type (NautilusQueryEditorRow *row,
- const char *mime_type,
- const char *description,
- GtkTreeIter *iter)
-{
- GtkTreeModel *model;
- GtkListStore *store;
-
- model = gtk_combo_box_get_model (GTK_COMBO_BOX (row->type_widget));
- store = GTK_LIST_STORE (model);
-
- gtk_list_store_append (store, iter);
- gtk_list_store_set (store, iter,
- 0, description,
- 2, mime_type,
- -1);
-}
+ nautilus_query_set_text (query, gtk_entry_get_text (GTK_ENTRY (priv->entry)));
+ nautilus_query_set_location (query, priv->location);
+ nautilus_query_set_recursive (query, recursive);
+ nautilus_query_editor_set_query (editor, query);
-static void
-type_combo_changed (GtkComboBox *combo_box, NautilusQueryEditorRow *row)
-{
- GtkTreeIter iter;
- gboolean other;
- GtkTreeModel *model;
+ g_signal_connect (query,
+ "notify::recursive",
+ G_CALLBACK (query_recursive_changed),
+ editor);
- if (!gtk_combo_box_get_active_iter (GTK_COMBO_BOX (row->type_widget),
- &iter)) {
- return;
- }
- model = gtk_combo_box_get_model (GTK_COMBO_BOX (row->type_widget));
- gtk_tree_model_get (model, &iter, 3, &other, -1);
-
- if (other) {
- GList *mime_infos, *l;
- GtkWidget *dialog;
- GtkWidget *scrolled, *treeview;
- GtkListStore *store;
- GtkTreeViewColumn *column;
- GtkCellRenderer *renderer;
- GtkWidget *toplevel;
- GtkTreeSelection *selection;
-
- mime_infos = g_content_types_get_registered ();
-
- store = gtk_list_store_new (2, G_TYPE_STRING, G_TYPE_STRING);
- for (l = mime_infos; l != NULL; l = l->next) {
- GtkTreeIter iter;
- char *mime_type = l->data;
- char *description;
-
- description = g_content_type_get_description (mime_type);
- if (description == NULL) {
- description = g_strdup (mime_type);
- }
-
- gtk_list_store_append (store, &iter);
- gtk_list_store_set (store, &iter,
- 0, description,
- 1, mime_type,
- -1);
-
- g_free (mime_type);
- g_free (description);
- }
- g_list_free (mime_infos);
-
-
-
- toplevel = gtk_widget_get_toplevel (GTK_WIDGET (combo_box));
- dialog = gtk_dialog_new_with_buttons (_("Select type"),
- GTK_WINDOW (toplevel),
- GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT | GTK_DIALOG_USE_HEADER_BAR,
- _("_Cancel"), GTK_RESPONSE_CANCEL,
- _("Select"), GTK_RESPONSE_OK,
- NULL);
- gtk_window_set_default_size (GTK_WINDOW (dialog), 400, 600);
-
- scrolled = gtk_scrolled_window_new (NULL, NULL);
- gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled),
- GTK_POLICY_AUTOMATIC,
- GTK_POLICY_AUTOMATIC);
-
- gtk_widget_show (scrolled);
- gtk_container_set_border_width (GTK_CONTAINER (gtk_dialog_get_content_area (GTK_DIALOG (dialog))), 0);
- gtk_box_pack_start (GTK_BOX (gtk_dialog_get_content_area (GTK_DIALOG (dialog))), scrolled, TRUE, TRUE, 0);
-
- treeview = gtk_tree_view_new ();
- gtk_tree_view_set_model (GTK_TREE_VIEW (treeview),
- GTK_TREE_MODEL (store));
- gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (store), 0,
- GTK_SORT_ASCENDING);
-
- selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (treeview));
- gtk_tree_selection_set_mode (selection, GTK_SELECTION_BROWSE);
-
-
- renderer = gtk_cell_renderer_text_new ();
- column = gtk_tree_view_column_new_with_attributes ("Name",
- renderer,
- "text",
- 0,
- NULL);
- gtk_tree_view_append_column (GTK_TREE_VIEW (treeview), column);
- gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (treeview), FALSE);
-
- gtk_widget_show (treeview);
- gtk_container_add (GTK_CONTAINER (scrolled), treeview);
-
- if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_OK) {
- char *mimetype, *description;
-
- gtk_tree_selection_get_selected (selection, NULL, &iter);
- gtk_tree_model_get (GTK_TREE_MODEL (store), &iter,
- 0, &description,
- 1, &mimetype,
- -1);
-
- type_add_custom_type (row, mimetype, description, &iter);
- gtk_combo_box_set_active_iter (GTK_COMBO_BOX (row->type_widget),
- &iter);
- } else {
- gtk_combo_box_set_active (GTK_COMBO_BOX (row->type_widget), 0);
- }
+ nautilus_file_unref (file);
+ }
- gtk_widget_destroy (dialog);
- }
-
- nautilus_query_editor_changed (row->editor);
+ return priv->query;
}
-static GtkWidget *
-type_row_create_widgets (NautilusQueryEditorRow *row)
+static void
+entry_activate_cb (GtkWidget *entry, NautilusQueryEditor *editor)
{
- GtkWidget *combo;
- GtkCellRenderer *cell;
- GtkListStore *store;
- GtkTreeIter iter;
- int i;
-
- store = gtk_list_store_new (4, G_TYPE_STRING, G_TYPE_POINTER, G_TYPE_STRING, G_TYPE_BOOLEAN);
- combo = gtk_combo_box_new_with_model (GTK_TREE_MODEL (store));
- g_object_unref (store);
-
- cell = gtk_cell_renderer_text_new ();
- gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (combo), cell, TRUE);
- gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (combo), cell,
- "text", 0,
- NULL);
- gtk_combo_box_set_row_separator_func (GTK_COMBO_BOX (combo),
- type_separator_func,
- NULL, NULL);
-
- gtk_list_store_append (store, &iter);
- gtk_list_store_set (store, &iter, 0, _("Any"), -1);
- gtk_list_store_append (store, &iter);
- gtk_list_store_set (store, &iter, 0, "---", -1);
-
- for (i = 0; i < G_N_ELEMENTS (mime_type_groups); i++) {
- gtk_list_store_append (store, &iter);
- gtk_list_store_set (store, &iter,
- 0, gettext (mime_type_groups[i].name),
- 1, mime_type_groups[i].mimetypes,
- -1);
- }
-
- gtk_list_store_append (store, &iter);
- gtk_list_store_set (store, &iter, 0, "---", -1);
- gtk_list_store_append (store, &iter);
- gtk_list_store_set (store, &iter, 0, _("Other Type…"), 3, TRUE, -1);
-
- gtk_combo_box_set_active (GTK_COMBO_BOX (combo), 0);
-
- g_signal_connect (combo, "changed",
- G_CALLBACK (type_combo_changed),
- row);
-
- gtk_widget_show (combo);
-
- gtk_box_pack_start (GTK_BOX (row->hbox), combo, FALSE, FALSE, 0);
-
- return combo;
+ g_signal_emit (editor, signals[ACTIVATED], 0);
}
static void
-type_row_add_to_query (NautilusQueryEditorRow *row,
- NautilusQuery *query)
+entry_changed_cb (GtkWidget *entry, NautilusQueryEditor *editor)
{
- GtkTreeIter iter;
- char **mimetypes;
- char *mimetype;
- GtkTreeModel *model;
+ NautilusQueryEditorPrivate *priv;
+ NautilusQuery *query;
+ gchar *text;
+
+ priv = nautilus_query_editor_get_instance_private (editor);
- if (!gtk_combo_box_get_active_iter (GTK_COMBO_BOX (row->type_widget),
- &iter)) {
+ if (priv->change_frozen || !gtk_search_bar_get_search_mode (GTK_SEARCH_BAR (editor))) {
return;
}
- model = gtk_combo_box_get_model (GTK_COMBO_BOX (row->type_widget));
- gtk_tree_model_get (model, &iter, 1, &mimetypes, 2, &mimetype, -1);
+ text = g_strstrip (g_strdup (gtk_entry_get_text (GTK_ENTRY (priv->entry))));
+ query = create_and_get_query (editor);
- if (mimetypes != NULL) {
- while (*mimetypes != NULL) {
- nautilus_query_add_mime_type (query, *mimetypes);
- mimetypes++;
- }
- }
- if (mimetype) {
- nautilus_query_add_mime_type (query, mimetype);
- g_free (mimetype);
- }
-}
+ nautilus_query_set_text (query, text);
+ nautilus_query_editor_changed (editor);
-static gboolean
-all_group_types_in_list (char **group_types, GList *mime_types)
-{
- GList *l;
- char **group_type;
- char *mime_type;
- gboolean found;
-
- group_type = group_types;
- while (*group_type != NULL) {
- found = FALSE;
-
- for (l = mime_types; l != NULL; l = l->next) {
- mime_type = l->data;
-
- if (strcmp (mime_type, *group_type) == 0) {
- found = TRUE;
- break;
- }
- }
-
- if (!found) {
- return FALSE;
- }
- group_type++;
- }
- return TRUE;
+ g_free (text);
}
-static GList *
-remove_group_types_from_list (char **group_types, GList *mime_types)
+static void
+nautilus_query_editor_on_stop_search (GtkWidget *entry,
+ NautilusQueryEditor *editor)
{
- GList *l, *next;
- char **group_type;
- char *mime_type;
-
- group_type = group_types;
- while (*group_type != NULL) {
- for (l = mime_types; l != NULL; l = next) {
- mime_type = l->data;
- next = l->next;
-
- if (strcmp (mime_type, *group_type) == 0) {
- mime_types = g_list_remove_link (mime_types, l);
- g_free (mime_type);
- break;
- }
- }
-
- group_type++;
- }
- return mime_types;
+ g_signal_emit (editor, signals[CANCEL], 0);
}
+/* Type */
static void
-type_add_rows_from_query (NautilusQueryEditor *editor,
- NautilusQuery *query)
+nautilus_query_editor_init (NautilusQueryEditor *editor)
{
- GList *mime_types;
- char *mime_type;
- const char *desc;
- NautilusQueryEditorRow *row;
- GtkTreeIter iter;
- int i;
- GtkTreeModel *model;
- GList *l;
-
- mime_types = nautilus_query_get_mime_types (query);
-
- if (mime_types == NULL) {
- return;
- }
-
- for (i = 0; i < G_N_ELEMENTS (mime_type_groups); i++) {
- if (all_group_types_in_list (mime_type_groups[i].mimetypes,
- mime_types)) {
- mime_types = remove_group_types_from_list (mime_type_groups[i].mimetypes,
- mime_types);
-
- row = nautilus_query_editor_add_row (editor,
- NAUTILUS_QUERY_EDITOR_ROW_TYPE);
-
- model = gtk_combo_box_get_model (GTK_COMBO_BOX (row->type_widget));
-
- gtk_tree_model_iter_nth_child (model, &iter, NULL, i + 2);
- gtk_combo_box_set_active_iter (GTK_COMBO_BOX (row->type_widget),
- &iter);
- }
- }
-
- for (l = mime_types; l != NULL; l = l->next) {
- mime_type = l->data;
-
- desc = g_content_type_get_description (mime_type);
- if (desc == NULL) {
- desc = mime_type;
- }
-
- row = nautilus_query_editor_add_row (editor,
- NAUTILUS_QUERY_EDITOR_ROW_TYPE);
-
- type_add_custom_type (row, mime_type, desc, &iter);
- gtk_combo_box_set_active_iter (GTK_COMBO_BOX (row->type_widget),
- &iter);
- }
-
- g_list_free_full (mime_types, g_free);
}
-/* End of row types */
-
-static NautilusQueryEditorRowType
-get_next_free_type (NautilusQueryEditor *editor)
+static gboolean
+entry_key_press_event_cb (GtkWidget *widget,
+ GdkEventKey *event,
+ NautilusQueryEditor *editor)
{
- NautilusQueryEditorRow *row;
- NautilusQueryEditorRowType type;
- gboolean found;
- GList *l;
-
-
- for (type = 0; type < NAUTILUS_QUERY_EDITOR_ROW_LAST; type++) {
- found = FALSE;
- for (l = editor->details->rows; l != NULL; l = l->next) {
- row = l->data;
- if (row->type == type) {
- found = TRUE;
- break;
- }
- }
- if (!found) {
- return type;
- }
+ if (event->keyval == GDK_KEY_Down) {
+ gtk_widget_grab_focus (gtk_widget_get_toplevel (GTK_WIDGET (widget)));
}
- return NAUTILUS_QUERY_EDITOR_ROW_TYPE;
+ return FALSE;
}
static void
-remove_row_cb (GtkButton *clicked_button, NautilusQueryEditorRow *row)
+search_mode_changed_cb (GObject *editor,
+ GParamSpec *pspec,
+ gpointer user_data)
{
- NautilusQueryEditor *editor;
+ NautilusQueryEditorPrivate *priv;
- editor = row->editor;
- editor->details->rows = g_list_remove (editor->details->rows, row);
- row_destroy (row);
+ priv = nautilus_query_editor_get_instance_private (NAUTILUS_QUERY_EDITOR (editor));
- nautilus_query_editor_changed (editor);
-}
-
-static void
-create_type_widgets (NautilusQueryEditorRow *row)
-{
- row->type_widget = row_type[row->type].create_widgets (row);
+ if (!gtk_search_bar_get_search_mode (GTK_SEARCH_BAR (editor))) {
+ g_signal_emit (editor, signals[CANCEL], 0);
+ gtk_widget_hide (priv->popover);
+ }
}
static void
-row_type_combo_changed_cb (GtkComboBox *combo_box, NautilusQueryEditorRow *row)
+search_popover_changed_cb (NautilusSearchPopover *popover,
+ NautilusSearchFilter filter,
+ gpointer data,
+ NautilusQueryEditor *editor)
{
- NautilusQueryEditorRowType type;
+ NautilusQuery *query;
- type = gtk_combo_box_get_active (combo_box);
+ query = create_and_get_query (editor);
- if (type == row->type) {
- return;
- }
+ switch (filter) {
+ case NAUTILUS_SEARCH_FILTER_DATE:
+ nautilus_query_set_date (query, data);
+ break;
- if (row->type_widget != NULL) {
- gtk_widget_destroy (row->type_widget);
- row->type_widget = NULL;
- }
+ case NAUTILUS_SEARCH_FILTER_TYPE:
+ nautilus_query_set_mime_types (query, data);
+ break;
- row->type = type;
-
- create_type_widgets (row);
+ default:
+ break;
+ }
- nautilus_query_editor_changed (row->editor);
+ nautilus_query_editor_changed (editor);
}
-static NautilusQueryEditorRow *
-nautilus_query_editor_add_row (NautilusQueryEditor *editor,
- NautilusQueryEditorRowType type)
+static void
+setup_widgets (NautilusQueryEditor *editor)
{
- GtkWidget *hbox, *button, *image, *combo;
- GtkToolItem *item;
- NautilusQueryEditorRow *row;
- int i;
-
- row = g_new0 (NautilusQueryEditorRow, 1);
- row->editor = editor;
- row->type = type;
-
- /* create the toolbar and the box container for its contents */
- row->toolbar = gtk_toolbar_new ();
- gtk_style_context_add_class (gtk_widget_get_style_context (row->toolbar),
- "search-bar");
- gtk_box_pack_start (GTK_BOX (editor), row->toolbar, TRUE, TRUE, 0);
-
- item = gtk_tool_item_new ();
- gtk_tool_item_set_expand (item, TRUE);
- gtk_toolbar_insert (GTK_TOOLBAR (row->toolbar), item, -1);
-
- hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 6);
- gtk_container_add (GTK_CONTAINER (item), hbox);
- row->hbox = hbox;
-
- /* create the criterion selector combobox */
- combo = gtk_combo_box_text_new ();
- row->combo = combo;
- for (i = 0; i < NAUTILUS_QUERY_EDITOR_ROW_LAST; i++) {
- gtk_combo_box_text_append_text (GTK_COMBO_BOX_TEXT (combo), gettext (row_type[i].name));
- }
- gtk_box_pack_start (GTK_BOX (hbox), combo, FALSE, FALSE, 0);
+ NautilusQueryEditorPrivate *priv;
+ GtkWidget *button, *hbox, *vbox;
- gtk_combo_box_set_active (GTK_COMBO_BOX (combo), row->type);
+ priv = nautilus_query_editor_get_instance_private (editor);
- editor->details->rows = g_list_append (editor->details->rows, row);
+ /* Spinner for when the search is happening */
+ priv->spinner = gtk_spinner_new ();
+ gtk_widget_set_margin_end (priv->spinner, 18);
+ gtk_widget_show (priv->spinner);
- g_signal_connect (combo, "changed",
- G_CALLBACK (row_type_combo_changed_cb), row);
-
- create_type_widgets (row);
+ /* HACK: we're invasively adding the spinner to GtkSearchBar > GtkRevealer > GtkBox */
+ gtk_box_pack_end (GTK_BOX (gtk_bin_get_child (GTK_BIN (gtk_bin_get_child (GTK_BIN (editor))))), priv->spinner, FALSE, TRUE, 0);
- /* create the remove row button */
- button = gtk_button_new ();
- gtk_style_context_add_class (gtk_widget_get_style_context (button),
- GTK_STYLE_CLASS_RAISED);
- gtk_widget_set_tooltip_text (button,
- _("Remove this criterion from the search"));
- gtk_box_pack_end (GTK_BOX (hbox), button, FALSE, FALSE, 0);
+ /* vertical box that holds the search entry and the label below */
+ vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 6);
+ gtk_container_add (GTK_CONTAINER (editor), vbox);
- image = gtk_image_new_from_icon_name ("window-close-symbolic",
- GTK_ICON_SIZE_MENU);
- gtk_container_add (GTK_CONTAINER (button), image);
+ /* horizontal box */
+ hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
+ gtk_style_context_add_class (gtk_widget_get_style_context (hbox), "linked");
+ gtk_container_add (GTK_CONTAINER (vbox), hbox);
- g_signal_connect (button, "clicked",
- G_CALLBACK (remove_row_cb), row);
+ /* create the search entry */
+ priv->entry = gtk_search_entry_new ();
+ gtk_entry_set_width_chars (GTK_ENTRY (priv->entry), 40);
+ gtk_search_bar_connect_entry (GTK_SEARCH_BAR (editor), GTK_ENTRY (priv->entry));
- /* show everything */
- gtk_widget_show_all (row->toolbar);
+ gtk_container_add (GTK_CONTAINER (hbox), priv->entry);
- return row;
-}
+ /* additional information label */
+ priv->label = gtk_label_new (NULL);
+ gtk_widget_set_no_show_all (priv->label, TRUE);
+ gtk_style_context_add_class (gtk_widget_get_style_context (priv->label), "dim-label");
-static void
-add_new_row_cb (GtkButton *clicked_button, NautilusQueryEditor *editor)
-{
- nautilus_query_editor_add_row (editor, get_next_free_type (editor));
- nautilus_query_editor_changed (editor);
-}
+ gtk_container_add (GTK_CONTAINER (vbox), priv->label);
-static void
-nautilus_query_editor_init (NautilusQueryEditor *editor)
-{
- editor->details = G_TYPE_INSTANCE_GET_PRIVATE (editor, NAUTILUS_TYPE_QUERY_EDITOR,
- NautilusQueryEditorDetails);
+ /* setup the search popover */
+ priv->popover = nautilus_search_popover_new ();
- gtk_orientable_set_orientation (GTK_ORIENTABLE (editor), GTK_ORIENTATION_VERTICAL);
-}
+ g_object_bind_property (editor, "location",
+ priv->popover, "location",
+ G_BINDING_DEFAULT);
-static void
-on_location_button_toggled (GtkToggleButton *button,
- NautilusQueryEditor *editor)
-{
- nautilus_query_editor_changed (editor);
-}
+ g_object_bind_property (editor, "query",
+ priv->popover, "query",
+ G_BINDING_DEFAULT);
-static gboolean
-entry_key_press_event_cb (GtkWidget *widget,
- GdkEventKey *event,
- NautilusQueryEditor *editor)
-{
- if (event->keyval == GDK_KEY_Down) {
- gtk_widget_grab_focus (gtk_widget_get_toplevel (GTK_WIDGET (widget)));
- }
- return FALSE;
-}
+ /* setup the filter menu button */
+ button = gtk_menu_button_new ();
+ gtk_menu_button_set_popover (GTK_MENU_BUTTON (button), priv->popover);
+ gtk_container_add (GTK_CONTAINER (hbox), button);
-static void
-setup_widgets (NautilusQueryEditor *editor)
-{
- GtkToolItem *item;
- GtkWidget *toolbar, *button_box, *hbox;
- GtkWidget *button, *image;
-
- /* create the toolbar and the box container for its contents */
- toolbar = gtk_toolbar_new ();
- gtk_toolbar_set_show_arrow (GTK_TOOLBAR (toolbar), FALSE);
- gtk_style_context_add_class (gtk_widget_get_style_context (toolbar),
- "search-bar");
- gtk_box_pack_start (GTK_BOX (editor), toolbar, TRUE, TRUE, 0);
-
- item = gtk_tool_item_new ();
- gtk_tool_item_set_expand (item, TRUE);
- gtk_toolbar_insert (GTK_TOOLBAR (toolbar), item, -1);
-
- hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 6);
- gtk_container_add (GTK_CONTAINER (item), hbox);
-
- /* create the search entry */
- editor->details->entry = gtk_search_entry_new ();
- gtk_box_pack_start (GTK_BOX (hbox), editor->details->entry, TRUE, TRUE, 0);
-
- g_signal_connect (editor->details->entry, "key-press-event",
+ g_signal_connect (editor, "notify::search-mode-enabled",
+ G_CALLBACK (search_mode_changed_cb), NULL);
+ g_signal_connect (priv->entry, "key-press-event",
G_CALLBACK (entry_key_press_event_cb), editor);
- g_signal_connect (editor->details->entry, "activate",
+ g_signal_connect (priv->entry, "activate",
G_CALLBACK (entry_activate_cb), editor);
- g_signal_connect (editor->details->entry, "search-changed",
+ g_signal_connect (priv->entry, "search-changed",
G_CALLBACK (entry_changed_cb), editor);
- g_signal_connect (editor->details->entry, "stop-search",
+ g_signal_connect (priv->entry, "stop-search",
G_CALLBACK (nautilus_query_editor_on_stop_search), editor);
-
- /* create the Current/All Files selector */
- editor->details->search_current_button = gtk_radio_button_new_with_label (NULL, _("Current"));
- gtk_toggle_button_set_mode (GTK_TOGGLE_BUTTON (editor->details->search_current_button), FALSE);
- editor->details->search_all_button = gtk_radio_button_new_with_label_from_widget (GTK_RADIO_BUTTON (editor->details->search_current_button),
- _("All Files"));
- gtk_toggle_button_set_mode (GTK_TOGGLE_BUTTON (editor->details->search_all_button), FALSE);
-
- /* connect to the signal only on one of the two, since they're mutually exclusive */
- g_signal_connect (editor->details->search_current_button, "toggled",
- G_CALLBACK (on_location_button_toggled), editor);
-
- button_box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
- gtk_box_pack_start (GTK_BOX (hbox), button_box, FALSE, FALSE, 0);
- gtk_style_context_add_class (gtk_widget_get_style_context (button_box),
- GTK_STYLE_CLASS_LINKED);
- gtk_style_context_add_class (gtk_widget_get_style_context (button_box),
- GTK_STYLE_CLASS_RAISED);
-
- gtk_box_pack_start (GTK_BOX (button_box), editor->details->search_current_button, FALSE, FALSE, 0);
- gtk_box_pack_start (GTK_BOX (button_box), editor->details->search_all_button, FALSE, FALSE, 0);
-
- /* finally, create the add new row button */
- button = gtk_button_new ();
- gtk_style_context_add_class (gtk_widget_get_style_context (button),
- GTK_STYLE_CLASS_RAISED);
- gtk_widget_set_tooltip_text (button,
- _("Add a new criterion to this search"));
- gtk_box_pack_start (GTK_BOX (hbox), button, FALSE, FALSE, 0);
-
- image = gtk_image_new_from_icon_name ("list-add-symbolic",
- GTK_ICON_SIZE_MENU);
- gtk_container_add (GTK_CONTAINER (button), image);
-
- g_signal_connect (button, "clicked",
- G_CALLBACK (add_new_row_cb), editor);
+ g_signal_connect (priv->popover, "changed",
+ G_CALLBACK (search_popover_changed_cb), editor);
/* show everything */
- gtk_widget_show_all (toolbar);
-}
-
-static void
-nautilus_query_editor_changed_force (NautilusQueryEditor *editor, gboolean force_reload)
-{
- NautilusQuery *query;
-
- if (editor->details->change_frozen) {
- return;
- }
-
- query = nautilus_query_editor_get_query (editor);
- g_signal_emit (editor, signals[CHANGED], 0,
- query, force_reload);
- g_object_unref (query);
+ gtk_widget_show_all (vbox);
}
static void
nautilus_query_editor_changed (NautilusQueryEditor *editor)
{
- nautilus_query_editor_changed_force (editor, TRUE);
-}
+ NautilusQueryEditorPrivate *priv;
-static void
-add_location_to_query (NautilusQueryEditor *editor,
- NautilusQuery *query)
-{
- GFile *location;
+ priv = nautilus_query_editor_get_instance_private (editor);
- if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (editor->details->search_all_button))) {
- location = g_file_new_for_uri (nautilus_get_home_directory_uri ());
- } else {
- location = nautilus_query_editor_get_location (editor);
+ if (priv->change_frozen) {
+ return;
}
- nautilus_query_set_location (query, location);
- g_clear_object (&location);
+ g_signal_emit (editor, signals[CHANGED], 0, priv->query, TRUE);
}
NautilusQuery *
nautilus_query_editor_get_query (NautilusQueryEditor *editor)
{
- const char *query_text;
- NautilusQuery *query;
- GList *l;
- NautilusQueryEditorRow *row;
+ NautilusQueryEditorPrivate *priv;
+
+ priv = nautilus_query_editor_get_instance_private (editor);
- if (editor == NULL || editor->details == NULL || editor->details->entry == NULL) {
+ if (editor == NULL || priv->entry == NULL || priv->query == NULL) {
return NULL;
}
- query_text = gtk_entry_get_text (GTK_ENTRY (editor->details->entry));
-
- query = nautilus_query_new ();
- nautilus_query_set_text (query, query_text);
-
- add_location_to_query (editor, query);
-
- for (l = editor->details->rows; l != NULL; l = l->next) {
- row = l->data;
-
- row_type[row->type].add_to_query (row, query);
- }
-
- return query;
+ return g_object_ref (priv->query);
}
GtkWidget *
@@ -1058,41 +505,17 @@ nautilus_query_editor_new (void)
return editor;
}
-static void
-update_location (NautilusQueryEditor *editor)
-{
- NautilusFile *file;
- GtkWidget *label;
-
- file = nautilus_file_get (editor->details->current_location);
-
- if (file != NULL) {
- char *name;
- if (nautilus_file_is_home (file)) {
- name = g_strdup (_("Home"));
- } else {
- name = nautilus_file_get_display_name (file);
- }
-
- gtk_button_set_label (GTK_BUTTON (editor->details->search_current_button), name);
- g_free (name);
-
- label = gtk_bin_get_child (GTK_BIN (editor->details->search_current_button));
- gtk_label_set_ellipsize (GTK_LABEL (label), PANGO_ELLIPSIZE_MIDDLE);
- g_object_set (label, "max-width-chars", 30, NULL);
-
- nautilus_file_unref (file);
- }
-}
-
void
nautilus_query_editor_set_location (NautilusQueryEditor *editor,
GFile *location)
{
+ NautilusQueryEditorPrivate *priv;
NautilusDirectory *directory;
NautilusDirectory *base_model;
+ gboolean should_notify;
- g_clear_object (&editor->details->current_location);
+ priv = nautilus_query_editor_get_instance_private (editor);
+ should_notify = FALSE;
/* The client could set us a location that is actually a search directory,
* like what happens with the slot when updating the query editor location.
@@ -1100,42 +523,62 @@ nautilus_query_editor_set_location (NautilusQueryEditor *editor,
* not the search directory invented uri. */
directory = nautilus_directory_get (location);
if (NAUTILUS_IS_SEARCH_DIRECTORY (directory)) {
+ GFile *real_location;
+
base_model = nautilus_search_directory_get_base_model (NAUTILUS_SEARCH_DIRECTORY (directory));
- editor->details->current_location = nautilus_directory_get_location (base_model);
+ real_location = nautilus_directory_get_location (base_model);
+
+ should_notify = g_set_object (&priv->location, real_location);
+
+ g_object_unref (real_location);
} else {
- editor->details->current_location = g_object_ref (location);
+ should_notify = g_set_object (&priv->location, location);
+ }
+
+ /* Update label if needed */
+ if (priv->location) {
+ NautilusFile *file;
+ gchar *label;
+ gchar *uri;
+
+ file = nautilus_file_get (priv->location);
+ label = NULL;
+ uri = g_file_get_uri (priv->location);
+
+ if (nautilus_file_is_other_locations (file)) {
+ label = _("Searching locations only");
+ } else if (g_str_has_prefix (uri, "computer://")) {
+ label = _("Searching devices only");
+ } else if (g_str_has_prefix (uri, "network://")) {
+ label = _("Searching network locations only");
+ } else if (!nautilus_file_is_local (file)) {
+ label = _("Remote location - only searching the current folder");
+ }
+
+ gtk_widget_set_visible (priv->label, label != NULL);
+ gtk_label_set_label (GTK_LABEL (priv->label), label);
+
+ g_free (uri);
+ }
+
+ if (should_notify) {
+ g_object_notify (G_OBJECT (editor), "location");
}
- update_location (editor);
g_clear_object (&directory);
-}
-static void
-update_rows (NautilusQueryEditor *editor,
- NautilusQuery *query)
-{
- NautilusQueryEditorRowType type;
-
- /* if we were just created, set the rows from query,
- * otherwise, re-use the query setting we have already.
- */
- if (query != NULL && editor->details->query == NULL) {
- for (type = 0; type < NAUTILUS_QUERY_EDITOR_ROW_LAST; type++) {
- row_type[type].add_rows_from_query (editor, query);
- }
- } else if (query == NULL && editor->details->query != NULL) {
- g_list_free_full (editor->details->rows, (GDestroyNotify) row_destroy);
- editor->details->rows = NULL;
- }
}
void
nautilus_query_editor_set_query (NautilusQueryEditor *editor,
NautilusQuery *query)
{
+ NautilusQueryEditorPrivate *priv;
char *text = NULL;
char *current_text = NULL;
+ priv = nautilus_query_editor_get_instance_private (editor);
+
if (query != NULL) {
text = nautilus_query_get_text (query);
}
@@ -1144,26 +587,28 @@ nautilus_query_editor_set_query (NautilusQueryEditor *editor,
text = g_strdup ("");
}
- editor->details->change_frozen = TRUE;
+ priv->change_frozen = TRUE;
- current_text = g_strstrip (g_strdup (gtk_entry_get_text (GTK_ENTRY (editor->details->entry))));
+ current_text = g_strstrip (g_strdup (gtk_entry_get_text (GTK_ENTRY (priv->entry))));
if (!g_str_equal (current_text, text)) {
- gtk_entry_set_text (GTK_ENTRY (editor->details->entry), text);
+ gtk_entry_set_text (GTK_ENTRY (priv->entry), text);
}
g_free (current_text);
- g_clear_object (&editor->details->current_location);
+ /* Clear bindings */
+ g_clear_pointer (&priv->spinner_active_binding, g_binding_unbind);
- update_rows (editor, query);
- g_clear_object (&editor->details->query);
+ if (g_set_object (&priv->query, query)) {
+ if (query) {
+ priv->spinner_active_binding = g_object_bind_property (query, "searching",
+ priv->spinner, "active",
+ G_BINDING_DEFAULT | G_BINDING_SYNC_CREATE);
+ }
- if (query != NULL) {
- editor->details->query = g_object_ref (query);
- editor->details->current_location = nautilus_query_get_location (query);
- update_location (editor);
- }
+ g_object_notify (G_OBJECT (editor), "query");
+ }
- editor->details->change_frozen = FALSE;
+ priv->change_frozen = FALSE;
g_free (text);
}
diff --git a/src/nautilus-query-editor.h b/src/nautilus-query-editor.h
index 4733953af..d166c6d00 100644
--- a/src/nautilus-query-editor.h
+++ b/src/nautilus-query-editor.h
@@ -28,42 +28,24 @@
#include <libnautilus-private/nautilus-query.h>
#define NAUTILUS_TYPE_QUERY_EDITOR nautilus_query_editor_get_type()
-#define NAUTILUS_QUERY_EDITOR(obj) \
- (G_TYPE_CHECK_INSTANCE_CAST ((obj), NAUTILUS_TYPE_QUERY_EDITOR, NautilusQueryEditor))
-#define NAUTILUS_QUERY_EDITOR_CLASS(klass) \
- (G_TYPE_CHECK_CLASS_CAST ((klass), NAUTILUS_TYPE_QUERY_EDITOR, NautilusQueryEditorClass))
-#define NAUTILUS_IS_QUERY_EDITOR(obj) \
- (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NAUTILUS_TYPE_QUERY_EDITOR))
-#define NAUTILUS_IS_QUERY_EDITOR_CLASS(klass) \
- (G_TYPE_CHECK_CLASS_TYPE ((klass), NAUTILUS_TYPE_QUERY_EDITOR))
-#define NAUTILUS_QUERY_EDITOR_GET_CLASS(obj) \
- (G_TYPE_INSTANCE_GET_CLASS ((obj), NAUTILUS_TYPE_QUERY_EDITOR, NautilusQueryEditorClass))
-typedef struct NautilusQueryEditorDetails NautilusQueryEditorDetails;
+G_DECLARE_DERIVABLE_TYPE (NautilusQueryEditor, nautilus_query_editor, NAUTILUS, QUERY_EDITOR, GtkSearchBar)
-typedef struct NautilusQueryEditor {
- GtkBox parent;
- NautilusQueryEditorDetails *details;
-} NautilusQueryEditor;
-
-typedef struct {
- GtkBoxClass parent_class;
+struct _NautilusQueryEditorClass {
+ GtkSearchBarClass parent_class;
void (* changed) (NautilusQueryEditor *editor,
NautilusQuery *query,
gboolean reload);
void (* cancel) (NautilusQueryEditor *editor);
void (* activated) (NautilusQueryEditor *editor);
-} NautilusQueryEditorClass;
+};
#include "nautilus-window-slot.h"
GType nautilus_query_editor_get_type (void);
GtkWidget* nautilus_query_editor_new (void);
-gboolean nautilus_query_editor_handle_event (NautilusQueryEditor *editor,
- GdkEventKey *event);
-
NautilusQuery *nautilus_query_editor_get_query (NautilusQueryEditor *editor);
void nautilus_query_editor_set_query (NautilusQueryEditor *editor,
NautilusQuery *query);
diff --git a/src/nautilus-search-popover.c b/src/nautilus-search-popover.c
new file mode 100644
index 000000000..9140be17b
--- /dev/null
+++ b/src/nautilus-search-popover.c
@@ -0,0 +1,1105 @@
+/* nautilus-search-popover.c
+ *
+ * Copyright (C) 2015 Georges Basile Stavracas Neto <georges.stavracas@gmail.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "nautilus-enum-types.h"
+#include "nautilus-search-popover.h"
+
+#include <glib/gi18n.h>
+#include <libnautilus-private/nautilus-file.h>
+#include <libnautilus-private/nautilus-global-preferences.h>
+
+struct _NautilusSearchPopover
+{
+ GtkPopover parent;
+
+ GtkWidget *around_revealer;
+ GtkWidget *around_stack;
+ GtkWidget *calendar;
+ GtkWidget *clear_date_button;
+ GtkWidget *dates_listbox;
+ GtkWidget *date_entry;
+ GtkWidget *date_stack;
+ GtkWidget *recursive_switch;
+ GtkWidget *select_date_button;
+ GtkWidget *select_date_button_label;
+ GtkWidget *type_label;
+ GtkWidget *type_listbox;
+ GtkWidget *type_stack;
+
+ GFile *location;
+ NautilusQuery *query;
+ GBinding *recursive_binding;
+};
+
+const gchar* get_text_for_day (gint days);
+
+static void emit_date_changes_for_day (NautilusSearchPopover *popover,
+ gint days);
+
+static void show_date_selection_widgets (NautilusSearchPopover *popover,
+ gboolean visible);
+
+static void show_other_types_dialog (NautilusSearchPopover *popover);
+
+static void update_date_label (NautilusSearchPopover *popover,
+ guint days);
+
+G_DEFINE_TYPE (NautilusSearchPopover, nautilus_search_popover, GTK_TYPE_POPOVER)
+
+enum {
+ PROP_0,
+ PROP_LOCATION,
+ PROP_QUERY,
+ LAST_PROP
+};
+
+enum {
+ CHANGED,
+ LAST_SIGNAL
+};
+
+static guint signals[LAST_SIGNAL];
+
+struct {
+ char *name;
+ char *mimetypes[20];
+} mimetype_groups[] = {
+ {
+ N_("Anything"),
+ { NULL }
+ },
+ {
+ N_("Files"),
+ { "application/octet-stream",
+ "text/plain",
+ NULL
+ }
+ },
+ {
+ N_("Folders"),
+ { "inode/directory",
+ NULL
+ }
+ },
+ { N_("Documents"),
+ { "application/rtf",
+ "application/msword",
+ "application/vnd.sun.xml.writer",
+ "application/vnd.sun.xml.writer.global",
+ "application/vnd.sun.xml.writer.template",
+ "application/vnd.oasis.opendocument.text",
+ "application/vnd.oasis.opendocument.text-template",
+ "application/x-abiword",
+ "application/x-applix-word",
+ "application/x-mswrite",
+ "application/docbook+xml",
+ "application/x-kword",
+ "application/x-kword-crypt",
+ "application/x-lyx",
+ NULL
+ }
+ },
+ { N_("Illustration"),
+ { "application/illustrator",
+ "application/vnd.corel-draw",
+ "application/vnd.stardivision.draw",
+ "application/vnd.oasis.opendocument.graphics",
+ "application/x-dia-diagram",
+ "application/x-karbon",
+ "application/x-killustrator",
+ "application/x-kivio",
+ "application/x-kontour",
+ "application/x-wpg",
+ NULL
+ }
+ },
+ { N_("Music"),
+ { "application/ogg",
+ "audio/x-vorbis+ogg",
+ "audio/ac3",
+ "audio/basic",
+ "audio/midi",
+ "audio/x-flac",
+ "audio/mp4",
+ "audio/mpeg",
+ "audio/x-mpeg",
+ "audio/x-ms-asx",
+ "audio/x-pn-realaudio",
+ NULL
+ }
+ },
+ { N_("PDF / Postscript"),
+ { "application/pdf",
+ "application/postscript",
+ "application/x-dvi",
+ "image/x-eps",
+ NULL
+ }
+ },
+ { N_("Picture"),
+ { "application/vnd.oasis.opendocument.image",
+ "application/x-krita",
+ "image/bmp",
+ "image/cgm",
+ "image/gif",
+ "image/jpeg",
+ "image/jpeg2000",
+ "image/png",
+ "image/svg+xml",
+ "image/tiff",
+ "image/x-compressed-xcf",
+ "image/x-pcx",
+ "image/x-photo-cd",
+ "image/x-psd",
+ "image/x-tga",
+ "image/x-xcf",
+ NULL
+ }
+ },
+ { N_("Presentation"),
+ { "application/vnd.ms-powerpoint",
+ "application/vnd.sun.xml.impress",
+ "application/vnd.oasis.opendocument.presentation",
+ "application/x-magicpoint",
+ "application/x-kpresenter",
+ NULL
+ }
+ },
+ { N_("Spreadsheet"),
+ { "application/vnd.lotus-1-2-3",
+ "application/vnd.ms-excel",
+ "application/vnd.stardivision.calc",
+ "application/vnd.sun.xml.calc",
+ "application/vnd.oasis.opendocument.spreadsheet",
+ "application/x-applix-spreadsheet",
+ "application/x-gnumeric",
+ "application/x-kspread",
+ "application/x-kspread-crypt",
+ "application/x-quattropro",
+ "application/x-sc",
+ "application/x-siag",
+ NULL
+ }
+ },
+ { N_("Text File"),
+ { "text/plain",
+ NULL
+ }
+ },
+ { N_("Video"),
+ { "video/mp4",
+ "video/3gpp",
+ "video/mpeg",
+ "video/quicktime",
+ "video/vivo",
+ "video/x-avi",
+ "video/x-mng",
+ "video/x-ms-asf",
+ "video/x-ms-wmv",
+ "video/x-msvideo",
+ "video/x-nsv",
+ "video/x-real-video",
+ NULL
+ }
+ },
+ { NULL,
+ {
+ NULL
+ }
+ }
+};
+
+
+/* Callbacks */
+
+static void
+calendar_day_selected (GtkCalendar *calendar,
+ NautilusSearchPopover *popover)
+{
+ GDateTime *now;
+ GDateTime *dt;
+ guint year, month, day;
+
+ now = g_date_time_new_now_local ();
+
+ gtk_calendar_get_date (calendar,
+ &year,
+ &month,
+ &day);
+
+ dt = g_date_time_new_local (year, month + 1, day, 0, 0, 0);
+
+ if (g_date_time_compare (dt, now) < 1) {
+ guint days;
+
+ days = g_date_time_difference (now, dt) / G_TIME_SPAN_DAY;
+
+ if (days > 0) {
+ update_date_label (popover, days);
+ emit_date_changes_for_day (popover, days);
+ }
+ }
+
+ g_date_time_unref (now);
+ g_date_time_unref (dt);
+}
+
+static void
+setup_date (NautilusSearchPopover *popover,
+ NautilusQuery *query)
+{
+ GDateTime *dt;
+ GDateTime *now;
+
+ now = g_date_time_new_now_local ();
+ dt = nautilus_query_get_date (query);
+
+ /* Update date */
+ if (dt && g_date_time_compare (dt, now) < 1) {
+ guint days;
+
+ days = g_date_time_difference (now, dt) / G_TIME_SPAN_DAY;
+
+ if (days > 0) {
+ g_signal_handlers_block_by_func (popover->calendar, calendar_day_selected, popover);
+
+ gtk_calendar_select_month (GTK_CALENDAR (popover->calendar),
+ g_date_time_get_month (dt) - 1,
+ g_date_time_get_year (dt));
+
+ gtk_calendar_select_day (GTK_CALENDAR (popover->calendar),
+ g_date_time_get_day_of_month (dt));
+
+ update_date_label (popover, days);
+
+ g_signal_handlers_unblock_by_func (popover->calendar, calendar_day_selected, popover);
+ }
+ }
+
+ g_clear_pointer (&now, g_date_time_unref);
+}
+
+static void
+query_date_changed (GObject *object,
+ GParamSpec *pspec,
+ NautilusSearchPopover *popover)
+{
+ setup_date (popover, NAUTILUS_QUERY (object));
+}
+
+static void
+clear_date_button_clicked (GtkButton *button,
+ NautilusSearchPopover *popover)
+{
+ gtk_label_set_label (GTK_LABEL (popover->select_date_button_label), _("Select Dates..."));
+ gtk_widget_hide (popover->clear_date_button);
+ emit_date_changes_for_day (popover, 0);
+}
+
+static void
+date_entry_activate (GtkEntry *entry,
+ NautilusSearchPopover *popover)
+{
+ if (gtk_entry_get_text_length (entry) > 0) {
+ GDateTime *now;
+ GDateTime *dt;
+ guint days;
+ GDate *date;
+
+ date = g_date_new ();
+ g_date_set_parse (date, gtk_entry_get_text (entry));
+
+ /* Invalid date silently does nothing */
+ if (!g_date_valid (date)) {
+ g_date_free (date);
+ return;
+ }
+
+ now = g_date_time_new_now_local ();
+ dt = g_date_time_new_local (g_date_get_year (date),
+ g_date_get_month (date),
+ g_date_get_day (date),
+ 0,
+ 0,
+ 0);
+
+ /* Future dates also silently fails */
+ if (g_date_time_compare (dt, now) == 1)
+ goto out;
+
+ days = g_date_time_difference (now, dt) / G_TIME_SPAN_DAY;
+
+ if (days > 0) {
+ update_date_label (popover, days);
+ show_date_selection_widgets (popover, FALSE);
+ emit_date_changes_for_day (popover, days);
+ }
+
+out:
+ g_date_time_unref (now);
+ g_date_time_unref (dt);
+ g_date_free (date);
+ }
+}
+
+static void
+dates_listbox_row_activated (GtkListBox *listbox,
+ GtkListBoxRow *row,
+ NautilusSearchPopover *popover)
+{
+ gint days;
+
+ days = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (row), "days"));
+
+ update_date_label (popover, days);
+ show_date_selection_widgets (popover, FALSE);
+ emit_date_changes_for_day (popover, days);
+}
+
+static void
+listbox_header_func (GtkListBoxRow *row,
+ GtkListBoxRow *before,
+ NautilusSearchPopover *popover)
+{
+ gboolean show_separator;
+
+ show_separator = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (row), "show-separator"));
+
+ if (show_separator) {
+ GtkWidget *separator;
+
+ separator = gtk_separator_new (GTK_ORIENTATION_HORIZONTAL);
+ gtk_widget_show (separator);
+
+ gtk_list_box_row_set_header (row, separator);
+ }
+}
+
+static void
+select_date_button_clicked (GtkButton *button,
+ NautilusSearchPopover *popover)
+{
+
+ /* Hide the type selection widgets when date selection
+ * widgets are shown.
+ */
+ gtk_stack_set_visible_child_name (GTK_STACK (popover->type_stack), "type-button");
+
+ show_date_selection_widgets (popover, TRUE);
+}
+
+static void
+select_type_button_clicked (GtkButton *button,
+ NautilusSearchPopover *popover)
+{
+ gtk_stack_set_visible_child_name (GTK_STACK (popover->type_stack), "type-list");
+
+ /* Hide the date selection widgets when the type selection
+ * listbox is shown.
+ */
+ show_date_selection_widgets (popover, FALSE);
+}
+
+static void
+toggle_calendar_icon_clicked (GtkEntry *entry,
+ GtkEntryIconPosition position,
+ GdkEvent *event,
+ NautilusSearchPopover *popover)
+{
+ const gchar *current_visible_child;
+ const gchar *child;
+ const gchar *icon_name;
+ const gchar *tooltip;
+
+ current_visible_child = gtk_stack_get_visible_child_name (GTK_STACK (popover->around_stack));
+
+ if (g_strcmp0 (current_visible_child, "date-list") == 0) {
+ child = "date-calendar";
+ icon_name = "view-list-symbolic";
+ tooltip = _("Show a list to select the date");
+ } else {
+ child = "date-list";
+ icon_name = "x-office-calendar-symbolic";
+ tooltip = _("Show a calendar to select the date");
+ }
+
+ gtk_stack_set_visible_child_name (GTK_STACK (popover->around_stack), child);
+ gtk_entry_set_icon_from_icon_name (entry, GTK_ENTRY_ICON_SECONDARY, icon_name);
+ gtk_entry_set_icon_tooltip_text (entry, GTK_ENTRY_ICON_SECONDARY, tooltip);
+}
+
+static void
+types_listbox_row_activated (GtkListBox *listbox,
+ GtkListBoxRow *row,
+ NautilusSearchPopover *popover)
+{
+ gint group;
+
+ group = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (row), "mimetype-group"));
+
+ /* The -1 group stands for the "Other Types" group, for which
+ * we should show the mimetype dialog.
+ */
+ if (group == -1) {
+ show_other_types_dialog (popover);
+ }
+ else {
+ GList *mimetypes;
+ gint i;
+
+ mimetypes = NULL;
+
+ /* Setup the new mimetypes set */
+ for (i = 0; mimetype_groups[group].mimetypes[i]; i++) {
+ mimetypes = g_list_append (mimetypes, mimetype_groups[group].mimetypes[i]);
+ }
+
+ gtk_label_set_label (GTK_LABEL (popover->type_label), gettext (mimetype_groups[group].name));
+
+ g_signal_emit (popover, signals[CHANGED], 0, NAUTILUS_SEARCH_FILTER_TYPE, mimetypes);
+
+ g_list_free (mimetypes);
+ }
+
+ gtk_stack_set_visible_child_name (GTK_STACK (popover->type_stack), "type-button");
+}
+
+/* Auxiliary methods */
+
+static GtkWidget*
+create_row_for_label (const gchar *text,
+ gboolean show_separator)
+{
+ GtkWidget *row;
+ GtkWidget *label;
+
+ row = gtk_list_box_row_new ();
+
+ g_object_set_data (G_OBJECT (row), "show-separator", GINT_TO_POINTER (show_separator));
+
+ label = g_object_new (GTK_TYPE_LABEL,
+ "label", text,
+ "hexpand", TRUE,
+ "xalign", 0.0,
+ "margin-start", 6,
+ NULL);
+
+ gtk_container_add (GTK_CONTAINER (row), label);
+ gtk_widget_show_all (row);
+
+ return row;
+}
+
+static void
+emit_date_changes_for_day (NautilusSearchPopover *popover,
+ gint days)
+{
+ GDateTime *dt;
+
+ dt = NULL;
+
+ if (days > 0) {
+ GDateTime *now;
+
+ now = g_date_time_new_now_local ();
+ dt = g_date_time_add_days (now, -days);
+
+ g_date_time_unref (now);
+ }
+
+ g_signal_emit (popover, signals[CHANGED], 0, NAUTILUS_SEARCH_FILTER_DATE, dt);
+
+ g_clear_pointer (&dt, g_date_time_unref);
+}
+
+static void
+fill_fuzzy_dates_listbox (NautilusSearchPopover *popover)
+{
+ GDateTime *maximum_dt, *now;
+ GtkWidget *row;
+ gint days, max_days;
+
+ days = 0;
+
+ maximum_dt = g_date_time_new_from_unix_local (0);
+ now = g_date_time_new_now_local ();
+ max_days = (g_date_time_get_year (now) - g_date_time_get_year (maximum_dt)) * 365;
+
+ /* This is a tricky loop. The main intention here is that each
+ * timeslice (day, week, month) have 2 or 3 entries. Years,
+ * however, are exceptions and should show many entries.
+ */
+ while (days < max_days) {
+ gchar *label;
+ gint n, step;
+
+ if (days == 0) {
+ n = 0;
+ step = 1;
+ } else if (days < 7) {
+ /* days */
+ n = days;
+ step = 2;
+ } else if (days < 30) {
+ /* weeks */
+ n = days / 7;
+ step = 7;
+ } else if (days < 365) {
+ /* months */
+ n = days / 30;
+ step = 84;
+ } else if (days < 1825) {
+ /* years */
+ n = days / 365;
+ step = 365;
+ } else {
+ /* after the first 5 years, jump at a 5-year pace */
+ n = days / 365;
+ step = 1825;
+ }
+
+ label = g_strdup_printf (get_text_for_day (days), n);
+
+ row = create_row_for_label (label, n == 1);
+ g_object_set_data (G_OBJECT (row), "days", GINT_TO_POINTER (days));
+
+ gtk_container_add (GTK_CONTAINER (popover->dates_listbox), row);
+
+ g_free (label);
+
+ days += step;
+ }
+
+ g_date_time_unref (maximum_dt);
+ g_date_time_unref (now);
+}
+
+static void
+fill_types_listbox (NautilusSearchPopover *popover)
+{
+ GtkWidget *row;
+ int i;
+
+ /* Mimetypes */
+ for (i = 0; i < G_N_ELEMENTS (mimetype_groups); i++) {
+
+ /* On the third row, which is right below "Folders", there should be an
+ * separator to logically group the types.
+ */
+ row = create_row_for_label (gettext (mimetype_groups[i].name), i == 3);
+ g_object_set_data (G_OBJECT (row), "mimetype-group", GINT_TO_POINTER (i));
+
+ gtk_container_add (GTK_CONTAINER (popover->type_listbox), row);
+ }
+
+ /* Other types */
+ row = create_row_for_label (_("Other Type…"), TRUE);
+ g_object_set_data (G_OBJECT (row), "mimetype-group", GINT_TO_POINTER (-1));
+ gtk_container_add (GTK_CONTAINER (popover->type_listbox), row);
+}
+
+const gchar*
+get_text_for_day (gint days)
+{
+ if (days == 0) {
+ return _("Any time");
+ } else if (days < 7) {
+ /* days */
+ return ngettext ("%d day ago", "%d days ago", days);
+ } else if (days < 30) {
+ /* weeks */
+ return ngettext ("Last week", "%d weeks ago", days / 7);
+ } else if (days < 365) {
+ /* months */
+ return ngettext ("Last month", "%d months ago", days / 30);
+ } else {
+ /* years */
+ return ngettext ("Last year", "%d years ago", days / 365);
+ }
+}
+
+static void
+show_date_selection_widgets (NautilusSearchPopover *popover,
+ gboolean visible)
+{
+ gtk_stack_set_visible_child_name (GTK_STACK (popover->date_stack), visible ? "date-entry" : "date-button");
+ gtk_stack_set_visible_child_name (GTK_STACK (popover->around_stack), "date-list");
+ gtk_entry_set_icon_from_icon_name (GTK_ENTRY (popover->date_entry),
+ GTK_ENTRY_ICON_SECONDARY,
+ "x-office-calendar-symbolic");
+
+ gtk_widget_set_visible (popover->around_revealer, visible);
+
+ gtk_revealer_set_reveal_child (GTK_REVEALER (popover->around_revealer), visible);
+
+ /* Only update the date button when we're not editing a query.
+ * Otherwise, when we select a date and try to select a mimetype,
+ * the label is unwantedly reset.
+ */
+ if (!popover->query)
+ update_date_label (popover, 0);
+}
+
+static void
+show_other_types_dialog (NautilusSearchPopover *popover)
+{
+ GList *mime_infos, *l;
+ GtkWidget *dialog;
+ GtkWidget *scrolled, *treeview;
+ GtkListStore *store;
+ GtkTreeViewColumn *column;
+ GtkCellRenderer *renderer;
+ GtkWidget *toplevel;
+ GtkTreeSelection *selection;
+
+ mime_infos = g_content_types_get_registered ();
+
+ store = gtk_list_store_new (2, G_TYPE_STRING, G_TYPE_STRING);
+ for (l = mime_infos; l != NULL; l = l->next) {
+ GtkTreeIter iter;
+ char *mime_type = l->data;
+ char *description;
+
+ description = g_content_type_get_description (mime_type);
+ if (description == NULL) {
+ description = g_strdup (mime_type);
+ }
+
+ gtk_list_store_append (store, &iter);
+ gtk_list_store_set (store, &iter,
+ 0, description,
+ 1, mime_type,
+ -1);
+
+ g_free (mime_type);
+ g_free (description);
+ }
+ g_list_free (mime_infos);
+
+ toplevel = gtk_widget_get_toplevel (GTK_WIDGET (popover));
+ dialog = gtk_dialog_new_with_buttons (_("Select type"),
+ GTK_WINDOW (toplevel),
+ GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT | GTK_DIALOG_USE_HEADER_BAR,
+ _("_Cancel"), GTK_RESPONSE_CANCEL,
+ _("Select"), GTK_RESPONSE_OK,
+ NULL);
+ gtk_window_set_default_size (GTK_WINDOW (dialog), 400, 600);
+
+ scrolled = gtk_scrolled_window_new (NULL, NULL);
+ gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled),
+ GTK_POLICY_AUTOMATIC,
+ GTK_POLICY_AUTOMATIC);
+
+ gtk_widget_show (scrolled);
+ gtk_container_set_border_width (GTK_CONTAINER (gtk_dialog_get_content_area (GTK_DIALOG (dialog))), 0);
+ gtk_box_pack_start (GTK_BOX (gtk_dialog_get_content_area (GTK_DIALOG (dialog))), scrolled, TRUE, TRUE, 0);
+
+ treeview = gtk_tree_view_new ();
+ gtk_tree_view_set_model (GTK_TREE_VIEW (treeview), GTK_TREE_MODEL (store));
+ gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (store), 0, GTK_SORT_ASCENDING);
+
+ selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (treeview));
+ gtk_tree_selection_set_mode (selection, GTK_SELECTION_BROWSE);
+
+
+ renderer = gtk_cell_renderer_text_new ();
+ column = gtk_tree_view_column_new_with_attributes ("Name",
+ renderer,
+ "text",
+ 0,
+ NULL);
+ gtk_tree_view_append_column (GTK_TREE_VIEW (treeview), column);
+ gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (treeview), FALSE);
+
+ gtk_widget_show (treeview);
+ gtk_container_add (GTK_CONTAINER (scrolled), treeview);
+
+ if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_OK) {
+ GtkTreeIter iter;
+ GList *mimetypes;
+ char *mimetype, *description;
+
+ gtk_tree_selection_get_selected (selection, NULL, &iter);
+ gtk_tree_model_get (GTK_TREE_MODEL (store), &iter,
+ 0, &description,
+ 1, &mimetype,
+ -1);
+
+ mimetypes = g_list_append (NULL, mimetype);
+
+ gtk_label_set_label (GTK_LABEL (popover->type_label), description);
+
+ g_signal_emit (popover, signals[CHANGED], 0, NAUTILUS_SEARCH_FILTER_TYPE, mimetypes);
+
+ gtk_stack_set_visible_child_name (GTK_STACK (popover->type_stack), "type-button");
+ }
+
+ gtk_widget_destroy (dialog);
+}
+
+static void
+update_date_label (NautilusSearchPopover *popover,
+ guint days)
+{
+ if (days > 0) {
+ GDateTime *now;
+ GDateTime *dt;
+ gchar *formatted_date;
+ gchar *label;
+ guint n;
+
+ if (days < 7) {
+ n = days;
+ } else if (days < 30) {
+ n = days / 7;
+ } else if (days < 365) {
+ n = days / 30;
+ } else {
+ n = days / 365;
+ }
+
+ label = g_strdup_printf (get_text_for_day (days), n);
+
+ now = g_date_time_new_now_local ();
+ dt = g_date_time_add_days (now, -days);
+ formatted_date = g_date_time_format (dt, "%x");
+
+ gtk_entry_set_text (GTK_ENTRY (popover->date_entry), formatted_date);
+
+ gtk_widget_show (popover->clear_date_button);
+ gtk_label_set_label (GTK_LABEL (popover->select_date_button_label), label);
+
+ g_date_time_unref (now);
+ g_date_time_unref (dt);
+ g_free (formatted_date);
+ g_free (label);
+ } else {
+ gtk_label_set_label (GTK_LABEL (popover->select_date_button_label), _("Select Dates..."));
+ gtk_widget_hide (popover->clear_date_button);
+ }
+}
+
+/* Overrides */
+
+static void
+nautilus_search_popover_closed (GtkPopover *popover)
+{
+ NautilusSearchPopover *self = NAUTILUS_SEARCH_POPOVER (popover);
+ GDateTime *now;
+
+ /* Always switch back to the initial states */
+ gtk_stack_set_visible_child_name (GTK_STACK (self->type_stack), "type-button");
+ show_date_selection_widgets (self, FALSE);
+
+ /* If we're closing an ongoing query, the popover must not
+ * clear the current settings.
+ */
+ if (self->query)
+ return;
+
+ now = g_date_time_new_now_local ();
+
+ /* Reselect today at the calendar */
+ g_signal_handlers_block_by_func (self->calendar, calendar_day_selected, self);
+
+ gtk_calendar_select_month (GTK_CALENDAR (self->calendar),
+ g_date_time_get_month (now) - 1,
+ g_date_time_get_year (now));
+
+ gtk_calendar_select_day (GTK_CALENDAR (self->calendar),
+ g_date_time_get_day_of_month (now));
+
+ g_signal_handlers_unblock_by_func (self->calendar, calendar_day_selected, self);
+}
+
+static void
+nautilus_search_popover_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ NautilusSearchPopover *self;
+
+ self = NAUTILUS_SEARCH_POPOVER (object);
+
+ switch (prop_id)
+ {
+ case PROP_LOCATION:
+ g_value_set_object (value, self->location);
+ break;
+
+ case PROP_QUERY:
+ g_value_set_object (value, self->query);
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ }
+}
+
+static void
+nautilus_search_popover_set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ NautilusSearchPopover *self;
+
+ self = NAUTILUS_SEARCH_POPOVER (object);
+
+ switch (prop_id)
+ {
+ case PROP_LOCATION:
+ nautilus_search_popover_set_location (self, g_value_get_object (value));
+ break;
+
+ case PROP_QUERY:
+ nautilus_search_popover_set_query (self, g_value_get_object (value));
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ }
+}
+
+
+static void
+nautilus_search_popover_class_init (NautilusSearchPopoverClass *klass)
+{
+ GtkPopoverClass *popover_class = GTK_POPOVER_CLASS (klass);
+ GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ object_class->get_property = nautilus_search_popover_get_property;
+ object_class->set_property = nautilus_search_popover_set_property;
+
+ popover_class->closed = nautilus_search_popover_closed;
+
+ signals[CHANGED] = g_signal_new ("changed",
+ NAUTILUS_TYPE_SEARCH_POPOVER,
+ G_SIGNAL_RUN_LAST,
+ 0,
+ NULL,
+ NULL,
+ g_cclosure_marshal_generic,
+ G_TYPE_NONE,
+ 2,
+ NAUTILUS_TYPE_SEARCH_FILTER,
+ G_TYPE_POINTER);
+
+ /**
+ * NautilusSearchPopover::location:
+ *
+ * The current location of the search.
+ */
+ g_object_class_install_property (object_class,
+ PROP_LOCATION,
+ g_param_spec_object ("location",
+ "Location of the popover",
+ "The current location of the search",
+ G_TYPE_FILE,
+ G_PARAM_READWRITE));
+
+ /**
+ * NautilusSearchPopover::query:
+ *
+ * The current #NautilusQuery being edited.
+ */
+ g_object_class_install_property (object_class,
+ PROP_QUERY,
+ g_param_spec_object ("query",
+ "Query of the popover",
+ "The current query being edited",
+ NAUTILUS_TYPE_QUERY,
+ G_PARAM_READWRITE));
+
+ gtk_widget_class_set_template_from_resource (widget_class, "/org/gnome/nautilus/ui/nautilus-search-popover.ui");
+
+ gtk_widget_class_bind_template_child (widget_class, NautilusSearchPopover, around_revealer);
+ gtk_widget_class_bind_template_child (widget_class, NautilusSearchPopover, around_stack);
+ gtk_widget_class_bind_template_child (widget_class, NautilusSearchPopover, clear_date_button);
+ gtk_widget_class_bind_template_child (widget_class, NautilusSearchPopover, calendar);
+ gtk_widget_class_bind_template_child (widget_class, NautilusSearchPopover, dates_listbox);
+ gtk_widget_class_bind_template_child (widget_class, NautilusSearchPopover, date_entry);
+ gtk_widget_class_bind_template_child (widget_class, NautilusSearchPopover, date_stack);
+ gtk_widget_class_bind_template_child (widget_class, NautilusSearchPopover, recursive_switch);
+ gtk_widget_class_bind_template_child (widget_class, NautilusSearchPopover, select_date_button);
+ gtk_widget_class_bind_template_child (widget_class, NautilusSearchPopover, select_date_button_label);
+ gtk_widget_class_bind_template_child (widget_class, NautilusSearchPopover, type_label);
+ gtk_widget_class_bind_template_child (widget_class, NautilusSearchPopover, type_listbox);
+ gtk_widget_class_bind_template_child (widget_class, NautilusSearchPopover, type_stack);
+
+ gtk_widget_class_bind_template_callback (widget_class, calendar_day_selected);
+ gtk_widget_class_bind_template_callback (widget_class, clear_date_button_clicked);
+ gtk_widget_class_bind_template_callback (widget_class, date_entry_activate);
+ gtk_widget_class_bind_template_callback (widget_class, dates_listbox_row_activated);
+ gtk_widget_class_bind_template_callback (widget_class, select_date_button_clicked);
+ gtk_widget_class_bind_template_callback (widget_class, select_type_button_clicked);
+ gtk_widget_class_bind_template_callback (widget_class, toggle_calendar_icon_clicked);
+ gtk_widget_class_bind_template_callback (widget_class, types_listbox_row_activated);
+}
+
+static void
+nautilus_search_popover_init (NautilusSearchPopover *self)
+{
+ gtk_widget_init_template (GTK_WIDGET (self));
+
+ /* Fuzzy dates listbox */
+ gtk_list_box_set_header_func (GTK_LIST_BOX (self->dates_listbox),
+ (GtkListBoxUpdateHeaderFunc) listbox_header_func,
+ self, NULL);
+
+ fill_fuzzy_dates_listbox (self);
+
+ /* Types listbox */
+ gtk_list_box_set_header_func (GTK_LIST_BOX (self->type_listbox),
+ (GtkListBoxUpdateHeaderFunc) listbox_header_func,
+ self, NULL);
+
+ fill_types_listbox (self);
+}
+
+GtkWidget*
+nautilus_search_popover_new (void)
+{
+ return g_object_new (NAUTILUS_TYPE_SEARCH_POPOVER, NULL);
+}
+
+/**
+ * nautilus_search_popover_get_location:
+ *
+ * Retrieves the current directory as a #GFile.
+ *
+ * Returns: (transfer none): a #GFile.
+ */
+GFile*
+nautilus_search_popover_get_location (NautilusSearchPopover *popover)
+{
+ g_return_val_if_fail (NAUTILUS_IS_SEARCH_POPOVER (popover), NULL);
+
+ return popover->location;
+}
+
+/**
+ * nautilus_search_popover_set_location:
+ *
+ * Sets the current location that the search is being
+ * performed on.
+ *
+ * Returns:
+ */
+void
+nautilus_search_popover_set_location (NautilusSearchPopover *popover,
+ GFile *location)
+{
+ g_return_if_fail (NAUTILUS_IS_SEARCH_POPOVER (popover));
+
+ if (g_set_object (&popover->location, location))
+ {
+ if (!popover->query && location)
+ {
+ NautilusFile *file;
+ gboolean active;
+
+ file = nautilus_file_get (location);
+
+ if (!nautilus_file_is_local (file))
+ {
+ active = g_settings_get_boolean (nautilus_preferences,
+ "enable-remote-recursive-search");
+ }
+ else
+ {
+ active = g_settings_get_boolean (nautilus_preferences,
+ "enable-recursive-search");
+ }
+
+ gtk_switch_set_active (GTK_SWITCH (popover->recursive_switch), active);
+ }
+
+ g_object_notify (G_OBJECT (popover), "location");
+ }
+}
+
+/**
+ * nautilus_search_popover_get_query:
+ * @popover: a #NautilusSearchPopover
+ *
+ * Gets the current query for @popover.
+ *
+ * Returns: (transfer none): the current #NautilusQuery from @popover.
+ */
+NautilusQuery*
+nautilus_search_popover_get_query (NautilusSearchPopover *popover)
+{
+ g_return_val_if_fail (NAUTILUS_IS_SEARCH_POPOVER (popover), NULL);
+
+ return popover->query;
+}
+
+/**
+ * nautilus_search_popover_set_query:
+ * @popover: a #NautilusSearchPopover
+ * @query (nullable): a #NautilusQuery
+ *
+ * Sets the current query for @popover.
+ *
+ * Returns:
+ */
+void
+nautilus_search_popover_set_query (NautilusSearchPopover *popover,
+ NautilusQuery *query)
+{
+ NautilusQuery *previous_query;
+
+ g_return_if_fail (NAUTILUS_IS_SEARCH_POPOVER (popover));
+
+ previous_query = popover->query;
+
+ if (popover->query != query) {
+ /* Disconnect signals and bindings from the old query */
+ if (previous_query) {
+ g_signal_handlers_disconnect_by_func (query, query_date_changed, popover);
+ g_clear_pointer (&popover->recursive_binding, g_binding_unbind);
+ }
+
+ g_set_object (&popover->query, query);
+
+ if (query) {
+ /* Date */
+ setup_date (popover, query);
+
+ g_signal_connect (query,
+ "notify::date",
+ G_CALLBACK (query_date_changed),
+ popover);
+ /* Recursive */
+ gtk_switch_set_active (GTK_SWITCH (popover->recursive_switch),
+ nautilus_query_get_recursive (query));
+
+ popover->recursive_binding = g_object_bind_property (query,
+ "recursive",
+ popover->recursive_switch,
+ "active",
+ G_BINDING_BIDIRECTIONAL);
+ } else {
+ update_date_label (popover, 0);
+ gtk_label_set_label (GTK_LABEL (popover->type_label), _("Anything"));
+ }
+ }
+}
diff --git a/src/nautilus-search-popover.h b/src/nautilus-search-popover.h
new file mode 100644
index 000000000..a733b2cdb
--- /dev/null
+++ b/src/nautilus-search-popover.h
@@ -0,0 +1,54 @@
+/* nautilus-search-popover.h
+ *
+ * Copyright (C) 2015 Georges Basile Stavracas Neto <georges.stavracas@gmail.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef NAUTILUS_SEARCH_POPOVER_H
+#define NAUTILUS_SEARCH_POPOVER_H
+
+#include <glib.h>
+#include <gtk/gtk.h>
+
+#include <libnautilus-private/nautilus-query.h>
+
+G_BEGIN_DECLS
+
+typedef enum {
+ NAUTILUS_SEARCH_FILTER_CONTENT, /* Full text or filename */
+ NAUTILUS_SEARCH_FILTER_DATE, /* When */
+ NAUTILUS_SEARCH_FILTER_LAST, /* Last modified or last used */
+ NAUTILUS_SEARCH_FILTER_TYPE /* What */
+} NautilusSearchFilter;
+
+#define NAUTILUS_TYPE_SEARCH_POPOVER (nautilus_search_popover_get_type())
+
+G_DECLARE_FINAL_TYPE (NautilusSearchPopover, nautilus_search_popover, NAUTILUS, SEARCH_POPOVER, GtkPopover)
+
+GtkWidget* nautilus_search_popover_new (void);
+
+GFile* nautilus_search_popover_get_location (NautilusSearchPopover *popover);
+
+void nautilus_search_popover_set_location (NautilusSearchPopover *popover,
+ GFile *location);
+
+NautilusQuery* nautilus_search_popover_get_query (NautilusSearchPopover *popover);
+
+void nautilus_search_popover_set_query (NautilusSearchPopover *popover,
+ NautilusQuery *query);
+
+G_END_DECLS
+
+#endif /* NAUTILUS_SEARCH_POPOVER_H */
diff --git a/src/nautilus-window-slot.c b/src/nautilus-window-slot.c
index 8b4475832..7b3dcfcf9 100644
--- a/src/nautilus-window-slot.c
+++ b/src/nautilus-window-slot.c
@@ -100,7 +100,6 @@ struct NautilusWindowSlotDetails {
/* Query editor */
NautilusQueryEditor *query_editor;
- GtkWidget *query_editor_revealer;
gulong qe_changed_id;
gulong qe_cancel_id;
gulong qe_activated_id;
@@ -357,8 +356,7 @@ hide_query_editor (NautilusWindowSlot *slot)
view = nautilus_window_slot_get_current_view (slot);
- gtk_revealer_set_reveal_child (GTK_REVEALER (slot->details->query_editor_revealer),
- FALSE);
+ gtk_search_bar_set_search_mode (GTK_SEARCH_BAR (slot->details->query_editor), FALSE);
if (slot->details->qe_changed_id > 0) {
g_signal_handler_disconnect (slot->details->query_editor, slot->details->qe_changed_id);
@@ -412,11 +410,9 @@ static void
show_query_editor (NautilusWindowSlot *slot)
{
NautilusView *view;
- GFile *location;
view = nautilus_window_slot_get_current_view (slot);
- location = nautilus_window_slot_get_current_location (slot);
if (nautilus_view_is_searching (view)) {
NautilusQuery *query;
@@ -425,13 +421,9 @@ show_query_editor (NautilusWindowSlot *slot)
if (query != NULL) {
nautilus_query_editor_set_query (slot->details->query_editor, query);
}
- } else {
- /* In this way, when the query changes it will open the actual search */
- nautilus_query_editor_set_location (slot->details->query_editor, location);
}
- gtk_revealer_set_reveal_child (GTK_REVEALER (slot->details->query_editor_revealer),
- TRUE);
+ gtk_search_bar_set_search_mode (GTK_SEARCH_BAR (slot->details->query_editor), TRUE);
gtk_widget_grab_focus (GTK_WIDGET (slot->details->query_editor));
if (slot->details->qe_changed_id == 0) {
@@ -489,7 +481,8 @@ nautilus_window_slot_handle_event (NautilusWindowSlot *slot,
retval = FALSE;
window = nautilus_window_slot_get_window (slot);
if (!NAUTILUS_IS_DESKTOP_WINDOW (window)) {
- retval = nautilus_query_editor_handle_event (slot->details->query_editor, event);
+ retval = gtk_search_bar_handle_event (GTK_SEARCH_BAR (slot->details->query_editor),
+ (GdkEvent*) event);
}
if (retval) {
@@ -540,7 +533,7 @@ remove_all_extra_location_widgets (GtkWidget *widget,
NautilusDirectory *directory;
directory = nautilus_directory_get (slot->details->location);
- if (widget != GTK_WIDGET (slot->details->query_editor_revealer)) {
+ if (widget != GTK_WIDGET (slot->details->query_editor)) {
gtk_container_remove (GTK_CONTAINER (slot->details->extra_location_widgets), widget);
}
@@ -639,11 +632,12 @@ nautilus_window_slot_constructed (GObject *object)
gtk_widget_show (extras_vbox);
slot->details->query_editor = NAUTILUS_QUERY_EDITOR (nautilus_query_editor_new ());
- slot->details->query_editor_revealer = gtk_revealer_new ();
- gtk_container_add (GTK_CONTAINER (slot->details->query_editor_revealer),
- GTK_WIDGET (slot->details->query_editor));
- gtk_widget_show_all (slot->details->query_editor_revealer);
- nautilus_window_slot_add_extra_location_widget (slot, slot->details->query_editor_revealer);
+ gtk_widget_show (GTK_WIDGET (slot->details->query_editor));
+ nautilus_window_slot_add_extra_location_widget (slot, GTK_WIDGET (slot->details->query_editor));
+
+ g_object_bind_property (slot, "location",
+ slot->details->query_editor, "location",
+ G_BINDING_DEFAULT);
slot->details->title = g_strdup (_("Loading…"));
}
@@ -973,8 +967,6 @@ nautilus_window_slot_set_location (NautilusWindowSlot *slot,
nautilus_window_slot_update_title (slot);
- nautilus_query_editor_set_location (slot->details->query_editor, location);
-
if (old_location) {
g_object_unref (old_location);
}
@@ -2033,7 +2025,6 @@ view_started_loading (NautilusWindowSlot *slot,
nautilus_window_slot_set_allow_stop (slot, TRUE);
}
- nautilus_query_editor_set_location (slot->details->query_editor, nautilus_view_get_location (view));
gtk_widget_grab_focus (GTK_WIDGET (slot->details->window));
gtk_widget_show (GTK_WIDGET (slot->details->window));
diff --git a/src/resources/nautilus.gresource.xml b/src/resources/nautilus.gresource.xml
index 1e668f85f..c961c5f50 100644
--- a/src/resources/nautilus.gresource.xml
+++ b/src/resources/nautilus.gresource.xml
@@ -2,6 +2,7 @@
<gresources>
<gresource prefix="/org/gnome/nautilus">
<file compressed="true">ui/nautilus-preferences-dialog.ui</file>
+ <file compressed="true">ui/nautilus-search-popover.ui</file>
<file>gtk/menus.ui</file>
<file>ui/nautilus-pathbar-context-menu.ui</file>
<file>ui/nautilus-toolbar.ui</file>
diff --git a/src/resources/ui/nautilus-search-popover.ui b/src/resources/ui/nautilus-search-popover.ui
new file mode 100644
index 000000000..1e20571f2
--- /dev/null
+++ b/src/resources/ui/nautilus-search-popover.ui
@@ -0,0 +1,454 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<interface>
+ <requires lib="gtk+" version="3.16"/>
+ <template class="NautilusSearchPopover" parent="GtkPopover">
+ <property name="can_focus">False</property>
+ <property name="modal">False</property>
+ <child>
+ <object class="GtkGrid" >
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="border_width">20</property>
+ <property name="row_spacing">8</property>
+ <property name="column_spacing">18</property>
+ <child>
+ <object class="GtkLabel" id="when_dim_label">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes">When</property>
+ <property name="xalign">0</property>
+ <style>
+ <class name="dim-label"/>
+ </style>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">0</property>
+ <property name="width">2</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkStack" id="date_stack">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="transition_type">crossfade</property>
+ <property name="transition_duration">250</property>
+ <child>
+ <object class="GtkBox">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <child>
+ <object class="GtkButton" id="select_date_button">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ <property name="tooltip_text" translatable="yes">Select a date</property>
+ <property name="hexpand">True</property>
+ <child>
+ <object class="GtkLabel" id="select_date_button_label">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes">Select Dates...</property>
+ <property name="xalign">0</property>
+ </object>
+ </child>
+ <signal name="clicked" handler="select_date_button_clicked" object="NautilusSearchPopover" swapped="no" />
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkButton" id="clear_date_button">
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ <property name="tooltip_text" translatable="yes">Clear the currently selected date</property>
+ <signal name="clicked" handler="clear_date_button_clicked" object="NautilusSearchPopover" swapped="no" />
+ <child>
+ <object class="GtkImage" id="clear_date_button_image">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="icon_name">edit-clear-symbolic</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <style>
+ <class name="linked"/>
+ </style>
+ </object>
+ <packing>
+ <property name="name">date-button</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkEntry" id="date_entry">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="secondary_icon_name">x-office-calendar-symbolic</property>
+ <property name="secondary_icon_tooltip_text" translatable="yes">Show a calendar to select the date</property>
+ <signal name="icon-release" handler="toggle_calendar_icon_clicked" object="NautilusSearchPopover" swapped="no" />
+ <signal name="activate" handler="date_entry_activate" object="NautilusSearchPopover" swapped="no" />
+ </object>
+ <packing>
+ <property name="name">date-entry</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">1</property>
+ <property name="width">2</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkRevealer" id="around_revealer">
+ <property name="can_focus">False</property>
+ <property name="transition_type">slide-down</property>
+ <child>
+ <object class="GtkGrid">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="row_spacing">8</property>
+ <property name="column_spacing">12</property>
+ <child>
+ <object class="GtkLabel" id="around_dim_label">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="margin_top">10</property>
+ <property name="label" translatable="yes">Around...</property>
+ <property name="xalign">0</property>
+ <style>
+ <class name="dim-label"/>
+ </style>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">0</property>
+ <property name="width">2</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkStack" id="around_stack">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="vhomogeneous">False</property>
+ <property name="transition_type">crossfade</property>
+ <property name="transition_duration">250</property>
+ <child>
+ <object class="GtkScrolledWindow">
+ <property name="height_request">200</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="hexpand">True</property>
+ <property name="shadow_type">in</property>
+ <child>
+ <object class="GtkViewport">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <child>
+ <object class="GtkListBox" id="dates_listbox">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="selection_mode">none</property>
+ <signal name="row-activated" handler="dates_listbox_row_activated" object="NautilusSearchPopover" swapped="no" />
+ </object>
+ </child>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="name">date-list</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkCalendar" id="calendar">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="valign">start</property>
+ <property name="show_week_numbers">True</property>
+ <signal name="day_selected" handler="calendar_day_selected" object="NautilusSearchPopover" swapped="no" />
+ </object>
+ <packing>
+ <property name="name">date-calendar</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">1</property>
+ <property name="width">2</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkRadioButton" id="last_modified_button">
+ <property name="label" translatable="yes">Last modified</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ <property name="xalign">0</property>
+ <property name="active">True</property>
+ <property name="draw_indicator">True</property>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">2</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkRadioButton" id="last_used_button">
+ <property name="label" translatable="yes">Last used</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ <property name="xalign">0</property>
+ <property name="draw_indicator">True</property>
+ <property name="group">last_modified_button</property>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="top_attach">2</property>
+ </packing>
+ </child>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">2</property>
+ <property name="width">2</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="what_dim_label">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="margin_top">10</property>
+ <property name="label" translatable="yes">What</property>
+ <property name="xalign">0</property>
+ <style>
+ <class name="dim-label"/>
+ </style>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">3</property>
+ <property name="width">2</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkStack" id="type_stack">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="vhomogeneous">False</property>
+ <property name="transition_type">crossfade</property>
+ <property name="transition_duration">250</property>
+ <child>
+ <object class="GtkButton" id="select_type_button">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ <property name="tooltip_text" translatable="yes">Which file types will be searched</property>
+ <signal name="clicked" handler="select_type_button_clicked" object="NautilusSearchPopover" swapped="no" />
+ <child>
+ <object class="GtkBox">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <child>
+ <object class="GtkLabel" id="type_label">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="hexpand">True</property>
+ <property name="label" translatable="yes">Anything</property>
+ <property name="width_chars">30</property>
+ <property name="xalign">0</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkImage">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="icon_name">pan-down-symbolic</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="name">type-button</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkScrolledWindow">
+ <property name="height_request">250</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="shadow_type">in</property>
+ <child>
+ <object class="GtkViewport">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <child>
+ <object class="GtkListBox" id="type_listbox">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="selection_mode">none</property>
+ <signal name="row-activated" handler="types_listbox_row_activated" object="NautilusSearchPopover" swapped="no" />
+ </object>
+ </child>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="name">type-list</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">4</property>
+ <property name="width">2</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="search_dim_label">
+ <property name="can_focus">False</property>
+ <property name="margin_top">10</property>
+ <property name="label" translatable="yes">Search</property>
+ <property name="xalign">0</property>
+ <style>
+ <class name="dim-label"/>
+ </style>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">5</property>
+ <property name="width">2</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkBox">
+ <property name="can_focus">False</property>
+ <property name="hexpand">True</property>
+ <child>
+ <object class="GtkRadioButton" id="full_text_search_button">
+ <property name="label" translatable="yes">Full Text</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ <property name="tooltip_text" translatable="yes">Search on the file content and name</property>
+ <property name="hexpand">True</property>
+ <property name="xalign">0</property>
+ <property name="active">True</property>
+ <property name="draw_indicator">False</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkRadioButton" id="filename_search_button">
+ <property name="label" translatable="yes">File Name</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ <property name="tooltip_text" translatable="yes">Search only on the file name</property>
+ <property name="hexpand">True</property>
+ <property name="xalign">0</property>
+ <property name="draw_indicator">False</property>
+ <property name="group">full_text_search_button</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <style>
+ <class name="linked"/>
+ </style>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">6</property>
+ <property name="width">2</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="subfolders_dim_label">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes">Search Subfolders</property>
+ <property name="margin_top">10</property>
+ <property name="xalign">0</property>
+ <property name="yalign">0.5</property>
+ <style>
+ <class name="dim-label"/>
+ </style>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">7</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkSwitch" id="recursive_switch">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="hexpand">True</property>
+ <property name="margin_top">10</property>
+ <property name="tooltip_text" translatable="yes">When on, the search will be performed on subfolders of the current folder</property>
+ <property name="halign">end</property>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="top_attach">7</property>
+ </packing>
+ </child>
+ </object>
+ </child>
+ </template>
+ <object class="GtkSizeGroup">
+ <property name="mode">vertical</property>
+ <property name="ignore_hidden">True</property>
+ <widgets>
+ <widget name="full_text_search_button"/>
+ <widget name="filename_search_button"/>
+ <widget name="select_date_button"/>
+ <widget name="clear_date_button"/>
+ </widgets>
+ </object>
+ <object class="GtkSizeGroup">
+ <property name="mode">horizontal</property>
+ <property name="ignore_hidden">True</property>
+ <widgets>
+ <widget name="search_dim_label"/>
+ <widget name="when_dim_label"/>
+ <widget name="around_dim_label"/>
+ <widget name="what_dim_label"/>
+ <widget name="subfolders_dim_label"/>
+ </widgets>
+ </object>
+</interface>