/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ /* * Copyright (C) 2005 Red Hat, Inc. * * Nautilus is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. * * Nautilus is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public * License along with this program; see the file COPYING. If not, * see . * * Author: Alexander Larsson * */ #include #include "nautilus-query-editor.h" #include #include #include #include #include #include #include typedef enum { NAUTILUS_QUERY_EDITOR_ROW_TYPE, NAUTILUS_QUERY_EDITOR_ROW_LAST } NautilusQueryEditorRowType; 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; gboolean change_frozen; guint typing_timeout_id; GtkWidget *search_current_button; GtkWidget *search_all_button; char *current_uri; GList *rows; NautilusQuery *query; }; enum { ACTIVATED, CHANGED, CANCEL, LAST_SIGNAL }; 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); static NautilusQueryEditorRowOps row_type[] = { { N_("File Type"), type_row_create_widgets, type_row_add_to_query, type_add_rows_from_query }, }; G_DEFINE_TYPE (NautilusQueryEditor, nautilus_query_editor, GTK_TYPE_BOX); 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; } /* never handle these events */ if (event->keyval == GDK_KEY_slash || event->keyval == GDK_KEY_Delete) { return FALSE; } /* don't activate search for these events */ if (!gtk_widget_get_visible (GTK_WIDGET (editor)) && event->keyval == GDK_KEY_space) { return FALSE; } /* if it's not printable we don't need it */ if (!g_unichar_isprint (gdk_keyval_to_unicode (event->keyval))) { return FALSE; } if (!gtk_widget_get_realized (editor->details->entry)) { gtk_widget_realize (editor->details->entry); } 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); 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); if (!retval && old_focus) { gtk_widget_grab_focus (old_focus); } return retval; } static void row_destroy (NautilusQueryEditorRow *row) { gtk_widget_destroy (row->toolbar); g_free (row); } static void nautilus_query_editor_dispose (GObject *object) { NautilusQueryEditor *editor; editor = NAUTILUS_QUERY_EDITOR (object); if (editor->details->typing_timeout_id > 0) { g_source_remove (editor->details->typing_timeout_id); editor->details->typing_timeout_id = 0; } g_clear_object (&editor->details->query); g_list_free_full (editor->details->rows, (GDestroyNotify) row_destroy); editor->details->rows = NULL; G_OBJECT_CLASS (nautilus_query_editor_parent_class)->dispose (object); } static void nautilus_query_editor_grab_focus (GtkWidget *widget) { NautilusQueryEditor *editor = NAUTILUS_QUERY_EDITOR (widget); 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); } } static void nautilus_query_editor_class_init (NautilusQueryEditorClass *class) { GObjectClass *gobject_class; GtkWidgetClass *widget_class; GtkBindingSet *binding_set; gobject_class = G_OBJECT_CLASS (class); gobject_class->dispose = nautilus_query_editor_dispose; widget_class = GTK_WIDGET_CLASS (class); widget_class->grab_focus = nautilus_query_editor_grab_focus; signals[CHANGED] = g_signal_new ("changed", G_TYPE_FROM_CLASS (class), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (NautilusQueryEditorClass, changed), NULL, NULL, g_cclosure_marshal_generic, G_TYPE_NONE, 2, NAUTILUS_TYPE_QUERY, G_TYPE_BOOLEAN); signals[CANCEL] = g_signal_new ("cancel", G_TYPE_FROM_CLASS (class), G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION, G_STRUCT_OFFSET (NautilusQueryEditorClass, cancel), NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0); signals[ACTIVATED] = g_signal_new ("activated", G_TYPE_FROM_CLASS (class), G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION, G_STRUCT_OFFSET (NautilusQueryEditorClass, activated), NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0); binding_set = gtk_binding_set_by_class (class); gtk_binding_entry_add_signal (binding_set, GDK_KEY_Escape, 0, "cancel", 0); g_type_class_add_private (class, sizeof (NautilusQueryEditorDetails)); } GFile * nautilus_query_editor_get_location (NautilusQueryEditor *editor) { GFile *file = NULL; if (editor->details->current_uri != NULL) file = g_file_new_for_uri (editor->details->current_uri); return file; } static void entry_activate_cb (GtkWidget *entry, NautilusQueryEditor *editor) { g_signal_emit (editor, signals[ACTIVATED], 0); } static gboolean typing_timeout_cb (gpointer user_data) { NautilusQueryEditor *editor; editor = NAUTILUS_QUERY_EDITOR (user_data); editor->details->typing_timeout_id = 0; nautilus_query_editor_changed (editor); return FALSE; } #define TYPING_TIMEOUT 250 static void entry_changed_cb (GtkWidget *entry, NautilusQueryEditor *editor) { if (editor->details->change_frozen) { return; } if (editor->details->typing_timeout_id > 0) { g_source_remove (editor->details->typing_timeout_id); } editor->details->typing_timeout_id = g_timeout_add (TYPING_TIMEOUT, typing_timeout_cb, editor); } /* Type */ static gboolean type_separator_func (GtkTreeModel *model, GtkTreeIter *iter, gpointer data) { char *text; gboolean res; gtk_tree_model_get (model, iter, 0, &text, -1); res = text != NULL && strcmp (text, "---") == 0; g_free (text); return res; } 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 } } }; 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); } static void type_combo_changed (GtkComboBox *combo_box, NautilusQueryEditorRow *row) { GtkTreeIter iter; gboolean other; GtkTreeModel *model; 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), 0, _("_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_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scrolled), GTK_SHADOW_IN); gtk_widget_show (scrolled); gtk_box_pack_start (GTK_BOX (gtk_dialog_get_content_area (GTK_DIALOG (dialog))), scrolled, TRUE, TRUE, 6); 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); } gtk_widget_destroy (dialog); } nautilus_query_editor_changed (row->editor); } static GtkWidget * type_row_create_widgets (NautilusQueryEditorRow *row) { 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; } static void type_row_add_to_query (NautilusQueryEditorRow *row, NautilusQuery *query) { GtkTreeIter iter; char **mimetypes; char *mimetype; GtkTreeModel *model; 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, 1, &mimetypes, 2, &mimetype, -1); 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); } } 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; } static GList * remove_group_types_from_list (char **group_types, GList *mime_types) { 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; } static void type_add_rows_from_query (NautilusQueryEditor *editor, NautilusQuery *query) { 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) { 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; } } return NAUTILUS_QUERY_EDITOR_ROW_TYPE; } static void remove_row_cb (GtkButton *clicked_button, NautilusQueryEditorRow *row) { NautilusQueryEditor *editor; editor = row->editor; editor->details->rows = g_list_remove (editor->details->rows, row); row_destroy (row); nautilus_query_editor_changed (editor); } static void create_type_widgets (NautilusQueryEditorRow *row) { row->type_widget = row_type[row->type].create_widgets (row); } static void row_type_combo_changed_cb (GtkComboBox *combo_box, NautilusQueryEditorRow *row) { NautilusQueryEditorRowType type; type = gtk_combo_box_get_active (combo_box); if (type == row->type) { return; } if (row->type_widget != NULL) { gtk_widget_destroy (row->type_widget); row->type_widget = NULL; } row->type = type; create_type_widgets (row); nautilus_query_editor_changed (row->editor); } static NautilusQueryEditorRow * nautilus_query_editor_add_row (NautilusQueryEditor *editor, NautilusQueryEditorRowType type) { 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); gtk_combo_box_set_active (GTK_COMBO_BOX (combo), row->type); editor->details->rows = g_list_append (editor->details->rows, row); g_signal_connect (combo, "changed", G_CALLBACK (row_type_combo_changed_cb), row); create_type_widgets (row); /* 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); image = gtk_image_new_from_icon_name ("window-close-symbolic", GTK_ICON_SIZE_MENU); gtk_container_add (GTK_CONTAINER (button), image); g_signal_connect (button, "clicked", G_CALLBACK (remove_row_cb), row); /* show everything */ gtk_widget_show_all (row->toolbar); return row; } 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); } static void nautilus_query_editor_init (NautilusQueryEditor *editor) { editor->details = G_TYPE_INSTANCE_GET_PRIVATE (editor, NAUTILUS_TYPE_QUERY_EDITOR, NautilusQueryEditorDetails); gtk_orientable_set_orientation (GTK_ORIENTABLE (editor), GTK_ORIENTATION_VERTICAL); } static void on_location_button_toggled (GtkToggleButton *button, NautilusQueryEditor *editor) { nautilus_query_editor_changed (editor); } static gboolean entry_key_press_event_cb (GtkWidget *widget, GdkEventKey *event, NautilusQueryEditor *editor) { if (event->keyval == GDK_KEY_Down) { nautilus_window_grab_focus (NAUTILUS_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET (widget)))); } return FALSE; } 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_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_CALLBACK (entry_key_press_event_cb), editor); g_signal_connect (editor->details->entry, "activate", G_CALLBACK (entry_activate_cb), editor); g_signal_connect (editor->details->entry, "changed", G_CALLBACK (entry_changed_cb), 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); /* 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); } static void nautilus_query_editor_changed (NautilusQueryEditor *editor) { nautilus_query_editor_changed_force (editor, TRUE); } static void add_location_to_query (NautilusQueryEditor *editor, NautilusQuery *query) { char *uri; if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (editor->details->search_all_button))) { uri = nautilus_get_home_directory_uri (); } else { uri = g_strdup (editor->details->current_uri); } nautilus_query_set_location (query, uri); g_free (uri); } NautilusQuery * nautilus_query_editor_get_query (NautilusQueryEditor *editor) { const char *query_text; NautilusQuery *query; GList *l; NautilusQueryEditorRow *row; if (editor == NULL || editor->details == NULL || editor->details->entry == 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; } GtkWidget * nautilus_query_editor_new (void) { GtkWidget *editor; editor = g_object_new (NAUTILUS_TYPE_QUERY_EDITOR, NULL); setup_widgets (NAUTILUS_QUERY_EDITOR (editor)); return editor; } static void update_location (NautilusQueryEditor *editor) { NautilusFile *file; GtkWidget *label; file = nautilus_file_get_by_uri (editor->details->current_uri); 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) { g_free (editor->details->current_uri); editor->details->current_uri = g_file_get_uri (location); update_location (editor); } 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) { char *text = NULL; char *current_text = NULL; if (query != NULL) { text = nautilus_query_get_text (query); } if (!text) { text = g_strdup (""); } editor->details->change_frozen = TRUE; current_text = g_strstrip (g_strdup (gtk_entry_get_text (GTK_ENTRY (editor->details->entry)))); if (!g_str_equal (current_text, text)) { gtk_entry_set_text (GTK_ENTRY (editor->details->entry), text); } g_free (current_text); g_free (editor->details->current_uri); editor->details->current_uri = NULL; update_rows (editor, query); g_clear_object (&editor->details->query); if (query != NULL) { editor->details->query = g_object_ref (query); editor->details->current_uri = nautilus_query_get_location (query); update_location (editor); } editor->details->change_frozen = FALSE; g_free (text); }