diff options
author | Georges Basile Stavracas Neto <georges.stavracas@gmail.com> | 2015-10-05 21:07:25 -0300 |
---|---|---|
committer | Carlos Soriano <csoriano@gnome.org> | 2016-02-02 20:43:04 +0100 |
commit | cb7c77a8acf857c3bf16e73bc7beba4b9d09faac (patch) | |
tree | 075cafcda4eb92313de7e2681aa183a3e1fe982d | |
parent | 2e72a3a0f3de75f2df5943133e8d70a4ba0aa3fa (diff) | |
download | nautilus-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.am | 3 | ||||
-rw-r--r-- | src/nautilus-query-editor.c | 1209 | ||||
-rw-r--r-- | src/nautilus-query-editor.h | 26 | ||||
-rw-r--r-- | src/nautilus-search-popover.c | 1105 | ||||
-rw-r--r-- | src/nautilus-search-popover.h | 54 | ||||
-rw-r--r-- | src/nautilus-window-slot.c | 31 | ||||
-rw-r--r-- | src/resources/nautilus.gresource.xml | 1 | ||||
-rw-r--r-- | src/resources/ui/nautilus-search-popover.ui | 454 |
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> |