2008-05-05 Paolo Borelli <pborelli@katamail.com>
[nautilus.git] / src / nautilus-query-editor.c
blobc7cc9a0727eed7870bf2e6ed7879d0d85dfb1349
1 /* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
2 /*
3 * Copyright (C) 2005 Red Hat, Inc.
5 * Nautilus is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License as
7 * published by the Free Software Foundation; either version 2 of the
8 * License, or (at your option) any later version.
10 * Nautilus is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * General Public License for more details.
15 * You should have received a copy of the GNU General Public
16 * License along with this program; see the file COPYING. If not,
17 * write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 * Boston, MA 02111-1307, USA.
20 * Author: Alexander Larsson <alexl@redhat.com>
24 #include <config.h>
25 #include "nautilus-query-editor.h"
27 #include <string.h>
28 #include <libnautilus-private/nautilus-marshal.h>
29 #include <glib/gi18n.h>
30 #include <gio/gio.h>
31 #include <eel/eel-gtk-macros.h>
32 #include <eel/eel-glib-extensions.h>
33 #include <gdk/gdkkeysyms.h>
34 #include <gtk/gtkbindings.h>
35 #include <gtk/gtkbutton.h>
36 #include <gtk/gtkentry.h>
37 #include <gtk/gtkframe.h>
38 #include <gtk/gtkhbox.h>
39 #include <gtk/gtklabel.h>
40 #include <gtk/gtkstock.h>
41 #include <gtk/gtkcombobox.h>
42 #include <gtk/gtkdialog.h>
43 #include "gtk/gtkliststore.h"
44 #include "gtk/gtktreeselection.h"
45 #include "gtk/gtkscrolledwindow.h"
46 #include <gtk/gtkfilechooserbutton.h>
47 #include "gtk/gtkcelllayout.h"
48 #include "gtk/gtkcellrenderertext.h"
50 typedef enum {
51 NAUTILUS_QUERY_EDITOR_ROW_LOCATION,
52 NAUTILUS_QUERY_EDITOR_ROW_TYPE,
54 NAUTILUS_QUERY_EDITOR_ROW_LAST
55 } NautilusQueryEditorRowType;
57 typedef struct {
58 NautilusQueryEditorRowType type;
59 NautilusQueryEditor *editor;
60 GtkWidget *hbox;
61 GtkWidget *combo;
63 GtkWidget *type_widget;
65 void *data;
66 } NautilusQueryEditorRow;
69 typedef struct {
70 const char *name;
71 GtkWidget * (*create_widgets) (NautilusQueryEditorRow *row);
72 void (*add_to_query) (NautilusQueryEditorRow *row,
73 NautilusQuery *query);
74 void (*free_data) (NautilusQueryEditorRow *row);
75 void (*add_rows_from_query) (NautilusQueryEditor *editor,
76 NautilusQuery *query);
77 } NautilusQueryEditorRowOps;
79 struct NautilusQueryEditorDetails {
80 gboolean is_indexed;
81 GtkWidget *entry;
82 gboolean change_frozen;
83 guint typing_timeout_id;
84 gboolean is_visible;
85 GtkWidget *invisible_vbox;
86 GtkWidget *visible_vbox;
88 GList *rows;
90 NautilusSearchBar *bar;
93 enum {
94 CHANGED,
95 CANCEL,
96 LAST_SIGNAL
97 };
99 static guint signals[LAST_SIGNAL];
101 static void nautilus_query_editor_class_init (NautilusQueryEditorClass *class);
102 static void nautilus_query_editor_init (NautilusQueryEditor *editor);
104 static void entry_activate_cb (GtkWidget *entry, NautilusQueryEditor *editor);
105 static void entry_changed_cb (GtkWidget *entry, NautilusQueryEditor *editor);
106 static void nautilus_query_editor_changed_force (NautilusQueryEditor *editor,
107 gboolean force);
108 static void nautilus_query_editor_changed (NautilusQueryEditor *editor);
109 static NautilusQueryEditorRow * nautilus_query_editor_add_row (NautilusQueryEditor *editor,
110 NautilusQueryEditorRowType type);
112 static GtkWidget *location_row_create_widgets (NautilusQueryEditorRow *row);
113 static void location_row_add_to_query (NautilusQueryEditorRow *row,
114 NautilusQuery *query);
115 static void location_row_free_data (NautilusQueryEditorRow *row);
116 static void location_add_rows_from_query (NautilusQueryEditor *editor,
117 NautilusQuery *query);
118 static GtkWidget *type_row_create_widgets (NautilusQueryEditorRow *row);
119 static void type_row_add_to_query (NautilusQueryEditorRow *row,
120 NautilusQuery *query);
121 static void type_row_free_data (NautilusQueryEditorRow *row);
122 static void type_add_rows_from_query (NautilusQueryEditor *editor,
123 NautilusQuery *query);
127 static NautilusQueryEditorRowOps row_type[] = {
128 { N_("Location"),
129 location_row_create_widgets,
130 location_row_add_to_query,
131 location_row_free_data,
132 location_add_rows_from_query
134 { N_("File Type"),
135 type_row_create_widgets,
136 type_row_add_to_query,
137 type_row_free_data,
138 type_add_rows_from_query
142 EEL_CLASS_BOILERPLATE (NautilusQueryEditor,
143 nautilus_query_editor,
144 GTK_TYPE_VBOX)
146 static void
147 nautilus_query_editor_finalize (GObject *object)
149 NautilusQueryEditor *editor;
151 editor = NAUTILUS_QUERY_EDITOR (object);
153 g_free (editor->details);
155 EEL_CALL_PARENT (G_OBJECT_CLASS, finalize, (object));
158 static void
159 nautilus_query_editor_dispose (GObject *object)
161 NautilusQueryEditor *editor;
163 editor = NAUTILUS_QUERY_EDITOR (object);
166 if (editor->details->bar != NULL) {
167 g_signal_handlers_disconnect_by_func (editor->details->entry,
168 entry_activate_cb,
169 editor);
170 g_signal_handlers_disconnect_by_func (editor->details->entry,
171 entry_changed_cb,
172 editor);
174 nautilus_search_bar_return_entry (editor->details->bar);
175 eel_remove_weak_pointer (&editor->details->bar);
178 EEL_CALL_PARENT (G_OBJECT_CLASS, dispose, (object));
181 static void
182 nautilus_query_editor_class_init (NautilusQueryEditorClass *class)
184 GObjectClass *gobject_class;
185 GtkBindingSet *binding_set;
187 gobject_class = G_OBJECT_CLASS (class);
188 gobject_class->finalize = nautilus_query_editor_finalize;
189 gobject_class->dispose = nautilus_query_editor_dispose;
191 signals[CHANGED] =
192 g_signal_new ("changed",
193 G_TYPE_FROM_CLASS (class),
194 G_SIGNAL_RUN_LAST,
195 G_STRUCT_OFFSET (NautilusQueryEditorClass, changed),
196 NULL, NULL,
197 nautilus_marshal_VOID__OBJECT_BOOLEAN,
198 G_TYPE_NONE, 2, NAUTILUS_TYPE_QUERY, G_TYPE_BOOLEAN);
200 signals[CANCEL] =
201 g_signal_new ("cancel",
202 G_TYPE_FROM_CLASS (class),
203 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
204 G_STRUCT_OFFSET (NautilusQueryEditorClass, cancel),
205 NULL, NULL,
206 g_cclosure_marshal_VOID__VOID,
207 G_TYPE_NONE, 0);
209 binding_set = gtk_binding_set_by_class (class);
210 gtk_binding_entry_add_signal (binding_set, GDK_Escape, 0, "cancel", 0);
213 static void
214 entry_activate_cb (GtkWidget *entry, NautilusQueryEditor *editor)
216 if (editor->details->typing_timeout_id) {
217 g_source_remove (editor->details->typing_timeout_id);
218 editor->details->typing_timeout_id = 0;
221 nautilus_query_editor_changed_force (editor, TRUE);
224 static gboolean
225 typing_timeout_cb (gpointer user_data)
227 NautilusQueryEditor *editor;
229 editor = NAUTILUS_QUERY_EDITOR (user_data);
231 nautilus_query_editor_changed (editor);
233 editor->details->typing_timeout_id = 0;
235 return FALSE;
238 #define TYPING_TIMEOUT 750
240 static void
241 entry_changed_cb (GtkWidget *entry, NautilusQueryEditor *editor)
243 if (editor->details->change_frozen) {
244 return;
247 if (editor->details->typing_timeout_id) {
248 g_source_remove (editor->details->typing_timeout_id);
251 editor->details->typing_timeout_id =
252 g_timeout_add (TYPING_TIMEOUT,
253 typing_timeout_cb,
254 editor);
257 static void
258 edit_clicked (GtkButton *button, NautilusQueryEditor *editor)
260 nautilus_query_editor_set_visible (editor, TRUE);
261 nautilus_query_editor_grab_focus (editor);
264 /* Location */
266 static GtkWidget *
267 location_row_create_widgets (NautilusQueryEditorRow *row)
269 GtkWidget *chooser;
271 chooser = gtk_file_chooser_button_new (_("Select folder to search in"),
272 GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER);
273 gtk_file_chooser_set_local_only (GTK_FILE_CHOOSER (chooser), TRUE);
274 gtk_file_chooser_set_current_folder (GTK_FILE_CHOOSER (chooser),
275 g_get_home_dir ());
276 gtk_widget_show (chooser);
278 g_signal_connect_swapped (chooser, "current-folder-changed",
279 G_CALLBACK (nautilus_query_editor_changed),
280 row->editor);
282 gtk_box_pack_start (GTK_BOX (row->hbox), chooser, FALSE, FALSE, 0);
284 return chooser;
287 static void
288 location_row_add_to_query (NautilusQueryEditorRow *row,
289 NautilusQuery *query)
291 char *folder, *uri;
293 folder = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (row->type_widget));
294 if (folder == NULL) {
295 /* I don't know why, but i got NULL here on initial search in browser mode
296 even with the location set to the homedir in create_widgets... */
297 folder = g_strdup (g_get_home_dir ());
300 uri = g_filename_to_uri (folder, NULL, NULL);
301 g_free (folder);
303 nautilus_query_set_location (query, uri);
304 g_free (uri);
307 static void
308 location_row_free_data (NautilusQueryEditorRow *row)
312 static void
313 location_add_rows_from_query (NautilusQueryEditor *editor,
314 NautilusQuery *query)
316 NautilusQueryEditorRow *row;
317 char *uri, *folder;
319 uri = nautilus_query_get_location (query);
321 if (uri == NULL) {
322 return;
324 folder = g_filename_from_uri (uri, NULL, NULL);
325 g_free (uri);
326 if (folder == NULL) {
327 return;
330 row = nautilus_query_editor_add_row (editor,
331 NAUTILUS_QUERY_EDITOR_ROW_LOCATION);
332 gtk_file_chooser_set_current_folder (GTK_FILE_CHOOSER (row->type_widget),
333 folder);
335 g_free (folder);
339 /* Type */
341 static gboolean
342 type_separator_func (GtkTreeModel *model,
343 GtkTreeIter *iter,
344 gpointer data)
346 char *text;
347 gboolean res;
349 gtk_tree_model_get (model, iter, 0, &text, -1);
351 res = text != NULL && strcmp (text, "---") == 0;
353 g_free (text);
354 return res;
357 struct {
358 char *name;
359 char *mimetypes[20];
360 } mime_type_groups[] = {
361 { N_("Documents"),
362 { "application/rtf",
363 "application/msword",
364 "application/vnd.sun.xml.writer",
365 "application/vnd.sun.xml.writer.global",
366 "application/vnd.sun.xml.writer.template",
367 "application/vnd.oasis.opendocument.text",
368 "application/vnd.oasis.opendocument.text-template",
369 "application/x-abiword",
370 "application/x-applix-word",
371 "application/x-mswrite",
372 "application/docbook+xml",
373 "application/x-kword",
374 "application/x-kword-crypt",
375 "application/x-lyx",
376 NULL
379 { N_("Music"),
380 { "application/ogg",
381 "audio/ac3",
382 "audio/basic",
383 "audio/midi",
384 "audio/x-flac",
385 "audio/mp4",
386 "audio/mpeg",
387 "audio/x-mpeg",
388 "audio/x-ms-asx",
389 "audio/x-pn-realaudio",
390 NULL
393 { N_("Video"),
394 { "video/mp4",
395 "video/3gpp",
396 "video/mpeg",
397 "video/quicktime",
398 "video/vivo",
399 "video/x-avi",
400 "video/x-mng",
401 "video/x-ms-asf",
402 "video/x-ms-wmv",
403 "video/x-msvideo",
404 "video/x-nsv",
405 "video/x-real-video",
406 NULL
409 { N_("Picture"),
410 { "application/vnd.oasis.opendocument.image",
411 "application/x-krita",
412 "image/bmp",
413 "image/cgm",
414 "image/gif",
415 "image/jpeg",
416 "image/jpeg2000",
417 "image/png",
418 "image/svg+xml",
419 "image/tiff",
420 "image/x-compressed-xcf",
421 "image/x-pcx",
422 "image/x-photo-cd",
423 "image/x-psd",
424 "image/x-tga",
425 "image/x-xcf",
426 NULL
429 { N_("Illustration"),
430 { "application/illustrator",
431 "application/vnd.corel-draw",
432 "application/vnd.stardivision.draw",
433 "application/vnd.oasis.opendocument.graphics",
434 "application/x-dia-diagram",
435 "application/x-karbon",
436 "application/x-killustrator",
437 "application/x-kivio",
438 "application/x-kontour",
439 "application/x-wpg",
440 NULL
443 { N_("Spreadsheet"),
444 { "application/vnd.lotus-1-2-3",
445 "application/vnd.ms-excel",
446 "application/vnd.stardivision.calc",
447 "application/vnd.sun.xml.calc",
448 "application/vnd.oasis.opendocument.spreadsheet",
449 "application/x-applix-spreadsheet",
450 "application/x-gnumeric",
451 "application/x-kspread",
452 "application/x-kspread-crypt",
453 "application/x-quattropro",
454 "application/x-sc",
455 "application/x-siag",
456 NULL
459 { N_("Presentation"),
460 { "application/vnd.ms-powerpoint",
461 "application/vnd.sun.xml.impress",
462 "application/vnd.oasis.opendocument.presentation",
463 "application/x-magicpoint",
464 "application/x-kpresenter",
465 NULL
468 { N_("Pdf / Postscript"),
469 { "application/pdf",
470 "application/postscript",
471 "application/x-dvi",
472 "image/x-eps",
473 NULL
476 { N_("Text File"),
477 { "text/plain",
478 NULL
483 static void
484 type_add_custom_type (NautilusQueryEditorRow *row,
485 const char *mime_type,
486 const char *description,
487 GtkTreeIter *iter)
489 GtkTreeModel *model;
490 GtkListStore *store;
492 model = gtk_combo_box_get_model (GTK_COMBO_BOX (row->type_widget));
493 store = GTK_LIST_STORE (model);
495 gtk_list_store_append (store, iter);
496 gtk_list_store_set (store, iter,
497 0, description,
498 2, mime_type,
499 -1);
503 static void
504 type_combo_changed (GtkComboBox *combo_box, NautilusQueryEditorRow *row)
506 GtkTreeIter iter;
507 gboolean other;
508 GtkTreeModel *model;
510 if (!gtk_combo_box_get_active_iter (GTK_COMBO_BOX (row->type_widget),
511 &iter)) {
512 return;
515 model = gtk_combo_box_get_model (GTK_COMBO_BOX (row->type_widget));
516 gtk_tree_model_get (model, &iter, 3, &other, -1);
518 if (other) {
519 GList *mime_infos, *l;
520 GtkWidget *dialog;
521 GtkWidget *scrolled, *treeview;
522 GtkListStore *store;
523 GtkTreeViewColumn *column;
524 GtkCellRenderer *renderer;
525 GtkWidget *toplevel;
526 GtkTreeSelection *selection;
528 mime_infos = g_content_types_get_registered ();
530 store = gtk_list_store_new (2, G_TYPE_STRING, G_TYPE_STRING);
531 for (l = mime_infos; l != NULL; l = l->next) {
532 GtkTreeIter iter;
533 char *mime_type = l->data;
534 char *description;
536 description = g_content_type_get_description (mime_type);
537 if (description == NULL) {
538 description = g_strdup (mime_type);
541 gtk_list_store_append (store, &iter);
542 gtk_list_store_set (store, &iter,
543 0, description,
544 1, mime_type,
545 -1);
547 g_free (mime_type);
548 g_free (description);
550 g_list_free (mime_infos);
554 toplevel = gtk_widget_get_toplevel (GTK_WIDGET (combo_box));
555 dialog = gtk_dialog_new_with_buttons (_("Select type"),
556 GTK_WINDOW (toplevel),
557 GTK_DIALOG_NO_SEPARATOR,
558 GTK_STOCK_OK, GTK_RESPONSE_OK,
559 NULL);
560 gtk_window_set_default_size (GTK_WINDOW (dialog), 400, 600);
562 scrolled = gtk_scrolled_window_new (NULL, NULL);
563 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled),
564 GTK_POLICY_AUTOMATIC,
565 GTK_POLICY_AUTOMATIC);
566 gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scrolled),
567 GTK_SHADOW_IN);
569 gtk_widget_show (scrolled);
570 gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog)->vbox), scrolled, TRUE, TRUE, 6);
572 treeview = gtk_tree_view_new ();
573 gtk_tree_view_set_model (GTK_TREE_VIEW (treeview),
574 GTK_TREE_MODEL (store));
575 gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (store), 0,
576 GTK_SORT_ASCENDING);
578 selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (treeview));
579 gtk_tree_selection_set_mode (selection, GTK_SELECTION_BROWSE);
582 renderer = gtk_cell_renderer_text_new ();
583 column = gtk_tree_view_column_new_with_attributes ("Name",
584 renderer,
585 "text",
587 NULL);
588 gtk_tree_view_append_column (GTK_TREE_VIEW (treeview), column);
589 gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (treeview), FALSE);
591 gtk_widget_show (treeview);
592 gtk_container_add (GTK_CONTAINER (scrolled), treeview);
594 if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_OK) {
595 char *mimetype, *description;
597 gtk_tree_selection_get_selected (selection, NULL, &iter);
598 gtk_tree_model_get (GTK_TREE_MODEL (store), &iter,
599 0, &description,
600 1, &mimetype,
601 -1);
603 type_add_custom_type (row, mimetype, description, &iter);
604 gtk_combo_box_set_active_iter (GTK_COMBO_BOX (row->type_widget),
605 &iter);
606 } else {
607 gtk_combo_box_set_active (GTK_COMBO_BOX (row->type_widget), 0);
610 gtk_widget_destroy (dialog);
613 nautilus_query_editor_changed (row->editor);
616 static GtkWidget *
617 type_row_create_widgets (NautilusQueryEditorRow *row)
619 GtkWidget *combo;
620 GtkCellRenderer *cell;
621 GtkListStore *store;
622 GtkTreeIter iter;
623 int i;
625 store = gtk_list_store_new (4, G_TYPE_STRING, G_TYPE_POINTER, G_TYPE_STRING, G_TYPE_BOOLEAN);
626 combo = gtk_combo_box_new_with_model (GTK_TREE_MODEL (store));
627 g_object_unref (store);
629 cell = gtk_cell_renderer_text_new ();
630 gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (combo), cell, TRUE);
631 gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (combo), cell,
632 "text", 0,
633 NULL);
634 gtk_combo_box_set_row_separator_func (GTK_COMBO_BOX (combo),
635 type_separator_func,
636 NULL, NULL);
638 gtk_list_store_append (store, &iter);
639 gtk_list_store_set (store, &iter, 0, _("Any"), -1);
640 gtk_list_store_append (store, &iter);
641 gtk_list_store_set (store, &iter, 0, "---", -1);
643 for (i = 0; i < G_N_ELEMENTS (mime_type_groups); i++) {
644 gtk_list_store_append (store, &iter);
645 gtk_list_store_set (store, &iter,
646 0, gettext (mime_type_groups[i].name),
647 1, mime_type_groups[i].mimetypes,
648 -1);
651 gtk_list_store_append (store, &iter);
652 gtk_list_store_set (store, &iter, 0, "---", -1);
653 gtk_list_store_append (store, &iter);
654 gtk_list_store_set (store, &iter, 0, _("Other Type..."), 3, TRUE, -1);
656 gtk_combo_box_set_active (GTK_COMBO_BOX (combo), 0);
658 g_signal_connect (combo, "changed",
659 G_CALLBACK (type_combo_changed),
660 row);
662 gtk_widget_show (combo);
664 gtk_box_pack_start (GTK_BOX (row->hbox), combo, FALSE, FALSE, 0);
666 return combo;
669 static void
670 type_row_add_to_query (NautilusQueryEditorRow *row,
671 NautilusQuery *query)
673 GtkTreeIter iter;
674 char **mimetypes;
675 char *mimetype;
676 GtkTreeModel *model;
678 if (!gtk_combo_box_get_active_iter (GTK_COMBO_BOX (row->type_widget),
679 &iter)) {
680 return;
683 model = gtk_combo_box_get_model (GTK_COMBO_BOX (row->type_widget));
684 gtk_tree_model_get (model, &iter, 1, &mimetypes, 2, &mimetype, -1);
686 if (mimetypes != NULL) {
687 while (*mimetypes != NULL) {
688 nautilus_query_add_mime_type (query, *mimetypes);
689 mimetypes++;
692 if (mimetype) {
693 nautilus_query_add_mime_type (query, mimetype);
694 g_free (mimetype);
698 static void
699 type_row_free_data (NautilusQueryEditorRow *row)
703 static gboolean
704 all_group_types_in_list (char **group_types, GList *mime_types)
706 GList *l;
707 char **group_type;
708 char *mime_type;
709 gboolean found;
711 group_type = group_types;
712 while (*group_type != NULL) {
713 found = FALSE;
715 for (l = mime_types; l != NULL; l = l->next) {
716 mime_type = l->data;
718 if (strcmp (mime_type, *group_type) == 0) {
719 found = TRUE;
720 break;
724 if (!found) {
725 return FALSE;
727 group_type++;
729 return TRUE;
732 static GList *
733 remove_group_types_from_list (char **group_types, GList *mime_types)
735 GList *l, *next;
736 char **group_type;
737 char *mime_type;
738 gboolean found;
740 group_type = group_types;
741 while (*group_type != NULL) {
742 found = FALSE;
744 for (l = mime_types; l != NULL; l = next) {
745 mime_type = l->data;
746 next = l->next;
748 if (strcmp (mime_type, *group_type) == 0) {
749 mime_types = g_list_remove_link (mime_types, l);
750 g_free (mime_type);
751 break;
755 group_type++;
757 return mime_types;
761 static void
762 type_add_rows_from_query (NautilusQueryEditor *editor,
763 NautilusQuery *query)
765 GList *mime_types;
766 char *mime_type;
767 const char *desc;
768 NautilusQueryEditorRow *row;
769 GtkTreeIter iter;
770 int i;
771 GtkTreeModel *model;
772 GList *l;
774 mime_types = nautilus_query_get_mime_types (query);
776 if (mime_types == NULL) {
777 return;
780 for (i = 0; i < G_N_ELEMENTS (mime_type_groups); i++) {
781 if (all_group_types_in_list (mime_type_groups[i].mimetypes,
782 mime_types)) {
783 mime_types = remove_group_types_from_list (mime_type_groups[i].mimetypes,
784 mime_types);
786 row = nautilus_query_editor_add_row (editor,
787 NAUTILUS_QUERY_EDITOR_ROW_TYPE);
789 model = gtk_combo_box_get_model (GTK_COMBO_BOX (row->type_widget));
791 gtk_tree_model_iter_nth_child (model, &iter, NULL, i + 2);
792 gtk_combo_box_set_active_iter (GTK_COMBO_BOX (row->type_widget),
793 &iter);
797 for (l = mime_types; l != NULL; l = l->next) {
798 mime_type = l->data;
800 desc = g_content_type_get_description (mime_type);
801 if (desc == NULL) {
802 desc = mime_type;
805 row = nautilus_query_editor_add_row (editor,
806 NAUTILUS_QUERY_EDITOR_ROW_TYPE);
807 model = gtk_combo_box_get_model (GTK_COMBO_BOX (row->type_widget));
809 type_add_custom_type (row, mime_type, desc, &iter);
810 gtk_combo_box_set_active_iter (GTK_COMBO_BOX (row->type_widget),
811 &iter);
814 eel_g_list_free_deep (mime_types);
818 /* End of row types */
820 static NautilusQueryEditorRowType
821 get_next_free_type (NautilusQueryEditor *editor)
823 NautilusQueryEditorRow *row;
824 NautilusQueryEditorRowType type;
825 gboolean found;
826 GList *l;
829 for (type = 0; type < NAUTILUS_QUERY_EDITOR_ROW_LAST; type++) {
830 found = FALSE;
831 for (l = editor->details->rows; l != NULL; l = l->next) {
832 row = l->data;
833 if (row->type == type) {
834 found = TRUE;
835 break;
838 if (!found) {
839 return type;
842 return NAUTILUS_QUERY_EDITOR_ROW_TYPE;
845 static void
846 remove_row_cb (GtkButton *clicked_button, NautilusQueryEditorRow *row)
848 NautilusQueryEditor *editor;
850 editor = row->editor;
851 gtk_container_remove (GTK_CONTAINER (editor->details->visible_vbox),
852 row->hbox);
854 editor->details->rows = g_list_remove (editor->details->rows, row);
856 row_type[row->type].free_data (row);
857 g_free (row);
859 nautilus_query_editor_changed (editor);
862 static void
863 create_type_widgets (NautilusQueryEditorRow *row)
865 row->type_widget = row_type[row->type].create_widgets (row);
868 static void
869 row_type_combo_changed_cb (GtkComboBox *combo_box, NautilusQueryEditorRow *row)
871 NautilusQueryEditorRowType type;
873 type = gtk_combo_box_get_active (combo_box);
875 if (type == row->type) {
876 return;
879 if (row->type_widget != NULL) {
880 gtk_widget_destroy (row->type_widget);
881 row->type_widget = NULL;
884 row_type[row->type].free_data (row);
885 row->data = NULL;
887 row->type = type;
889 create_type_widgets (row);
891 nautilus_query_editor_changed (row->editor);
894 static NautilusQueryEditorRow *
895 nautilus_query_editor_add_row (NautilusQueryEditor *editor,
896 NautilusQueryEditorRowType type)
898 GtkWidget *hbox, *button, *image, *combo;
899 NautilusQueryEditorRow *row;
900 int i;
902 row = g_new0 (NautilusQueryEditorRow, 1);
903 row->editor = editor;
904 row->type = type;
906 hbox = gtk_hbox_new (FALSE, 6);
907 row->hbox = hbox;
908 gtk_widget_show (hbox);
909 gtk_box_pack_start (GTK_BOX (editor->details->visible_vbox), hbox, FALSE, FALSE, 0);
911 combo = gtk_combo_box_new_text ();
912 row->combo = combo;
913 for (i = 0; i < NAUTILUS_QUERY_EDITOR_ROW_LAST; i++) {
914 gtk_combo_box_append_text (GTK_COMBO_BOX (combo), gettext (row_type[i].name));
916 gtk_widget_show (combo);
917 gtk_box_pack_start (GTK_BOX (hbox), combo, FALSE, FALSE, 0);
919 gtk_combo_box_set_active (GTK_COMBO_BOX (combo), row->type);
921 editor->details->rows = g_list_append (editor->details->rows, row);
923 g_signal_connect (combo, "changed",
924 G_CALLBACK (row_type_combo_changed_cb), row);
926 create_type_widgets (row);
928 button = gtk_button_new ();
929 image = gtk_image_new_from_stock (GTK_STOCK_REMOVE,
930 GTK_ICON_SIZE_SMALL_TOOLBAR);
931 gtk_container_add (GTK_CONTAINER (button), image);
932 gtk_widget_show (image);
933 gtk_button_set_relief (GTK_BUTTON (button), GTK_RELIEF_NONE);
934 gtk_widget_show (button);
936 g_signal_connect (button, "clicked",
937 G_CALLBACK (remove_row_cb), row);
938 gtk_widget_set_tooltip_text (button,
939 _("Remove this criterion from the search"));
941 gtk_box_pack_end (GTK_BOX (hbox), button, FALSE, FALSE, 0);
943 return row;
946 static void
947 go_search_cb (GtkButton *clicked_button, NautilusQueryEditor *editor)
949 nautilus_query_editor_changed_force (editor, TRUE);
952 static void
953 add_new_row_cb (GtkButton *clicked_button, NautilusQueryEditor *editor)
955 nautilus_query_editor_add_row (editor, get_next_free_type (editor));
956 nautilus_query_editor_changed (editor);
959 static void
960 nautilus_query_editor_init (NautilusQueryEditor *editor)
962 GtkWidget *hbox, *label, *button;
963 char *label_markup;
965 editor->details = g_new0 (NautilusQueryEditorDetails, 1);
966 editor->details->is_visible = TRUE;
968 editor->details->invisible_vbox = gtk_vbox_new (FALSE, 6);
969 gtk_box_pack_start (GTK_BOX (editor), editor->details->invisible_vbox,
970 FALSE, FALSE, 0);
971 editor->details->visible_vbox = gtk_vbox_new (FALSE, 6);
972 gtk_box_pack_start (GTK_BOX (editor), editor->details->visible_vbox,
973 FALSE, FALSE, 0);
974 /* Only show visible vbox */
975 gtk_widget_show (editor->details->visible_vbox);
977 /* Create invisible part: */
978 hbox = gtk_hbox_new (FALSE, 6);
979 gtk_box_pack_start (GTK_BOX (editor->details->invisible_vbox),
980 hbox, FALSE, FALSE, 0);
981 gtk_widget_show (hbox);
983 label = gtk_label_new ("");
984 label_markup = g_strconcat ("<b>", _("Search Folder"), "</b>", NULL);
985 gtk_label_set_markup (GTK_LABEL (label), label_markup);
986 g_free (label_markup);
987 gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);
988 gtk_widget_show (label);
990 button = gtk_button_new_with_label (_("Edit"));
991 gtk_box_pack_end (GTK_BOX (hbox), button, FALSE, FALSE, 0);
992 gtk_widget_show (button);
994 g_signal_connect (button, "clicked",
995 G_CALLBACK (edit_clicked), editor);
997 gtk_widget_set_tooltip_text (button,
998 _("Edit the saved search"));
1001 void
1002 nautilus_query_editor_set_default_query (NautilusQueryEditor *editor)
1004 if (!editor->details->is_indexed) {
1005 nautilus_query_editor_add_row (editor, NAUTILUS_QUERY_EDITOR_ROW_LOCATION);
1006 nautilus_query_editor_changed (editor);
1010 static void
1011 finish_first_line (NautilusQueryEditor *editor, GtkWidget *hbox, gboolean use_go)
1013 GtkWidget *button, *image;
1015 button = gtk_button_new ();
1016 image = gtk_image_new_from_stock (GTK_STOCK_ADD,
1017 GTK_ICON_SIZE_SMALL_TOOLBAR);
1018 gtk_container_add (GTK_CONTAINER (button), image);
1019 gtk_widget_show (image);
1020 gtk_button_set_relief (GTK_BUTTON (button), GTK_RELIEF_NONE);
1021 gtk_widget_show (button);
1023 g_signal_connect (button, "clicked",
1024 G_CALLBACK (add_new_row_cb), editor);
1026 gtk_box_pack_end (GTK_BOX (hbox), button, FALSE, FALSE, 0);
1028 gtk_widget_set_tooltip_text (button,
1029 _("Add a new criterion to this search"));
1031 if (!editor->details->is_indexed) {
1032 if (use_go) {
1033 button = gtk_button_new_with_label (_("Go"));
1034 } else {
1035 button = gtk_button_new_with_label (_("Reload"));
1037 gtk_widget_show (button);
1039 gtk_widget_set_tooltip_text (button,
1040 _("Perform or update the search"));
1042 g_signal_connect (button, "clicked",
1043 G_CALLBACK (go_search_cb), editor);
1045 gtk_box_pack_end (GTK_BOX (hbox), button, FALSE, FALSE, 0);
1049 static void
1050 setup_internal_entry (NautilusQueryEditor *editor)
1052 GtkWidget *hbox, *label;
1053 char *label_markup;
1055 /* Create visible part: */
1056 hbox = gtk_hbox_new (FALSE, 6);
1057 gtk_widget_show (hbox);
1058 gtk_box_pack_start (GTK_BOX (editor->details->visible_vbox), hbox, FALSE, FALSE, 0);
1060 label = gtk_label_new ("");
1061 label_markup = g_strconcat ("<b>", _("_Search for:"), "</b>", NULL);
1062 gtk_label_set_markup_with_mnemonic (GTK_LABEL (label), label_markup);
1063 g_free (label_markup);
1064 gtk_widget_show (label);
1065 gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);
1067 editor->details->entry = gtk_entry_new ();
1068 gtk_label_set_mnemonic_widget (GTK_LABEL (label), editor->details->entry);
1069 gtk_box_pack_start (GTK_BOX (hbox), editor->details->entry, TRUE, TRUE, 0);
1071 g_signal_connect (editor->details->entry, "activate",
1072 G_CALLBACK (entry_activate_cb), editor);
1073 g_signal_connect (editor->details->entry, "changed",
1074 G_CALLBACK (entry_changed_cb), editor);
1075 gtk_widget_show (editor->details->entry);
1077 finish_first_line (editor, hbox, TRUE);
1080 static void
1081 setup_external_entry (NautilusQueryEditor *editor, GtkWidget *entry)
1083 GtkWidget *hbox, *label;
1085 /* Create visible part: */
1086 hbox = gtk_hbox_new (FALSE, 6);
1087 gtk_widget_show (hbox);
1088 gtk_box_pack_start (GTK_BOX (editor->details->visible_vbox), hbox, FALSE, FALSE, 0);
1090 label = gtk_label_new (_("Search results"));
1091 gtk_widget_show (label);
1092 gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);
1094 editor->details->entry = entry;
1095 g_signal_connect (editor->details->entry, "activate",
1096 G_CALLBACK (entry_activate_cb), editor);
1097 g_signal_connect (editor->details->entry, "changed",
1098 G_CALLBACK (entry_changed_cb), editor);
1100 finish_first_line (editor, hbox, FALSE);
1104 void
1105 nautilus_query_editor_set_visible (NautilusQueryEditor *editor,
1106 gboolean visible)
1108 editor->details->is_visible = visible;
1109 if (visible) {
1110 gtk_widget_show (editor->details->visible_vbox);
1111 gtk_widget_hide (editor->details->invisible_vbox);
1112 } else {
1113 gtk_widget_hide (editor->details->visible_vbox);
1114 gtk_widget_show (editor->details->invisible_vbox);
1118 static gboolean
1119 query_is_valid (NautilusQueryEditor *editor)
1121 const char *text;
1123 text = gtk_entry_get_text (GTK_ENTRY (editor->details->entry));
1125 return text != NULL && text[0] != '\0';
1128 static void
1129 nautilus_query_editor_changed_force (NautilusQueryEditor *editor, gboolean force_reload)
1131 NautilusQuery *query;
1133 if (editor->details->change_frozen) {
1134 return;
1137 if (query_is_valid (editor)) {
1138 query = nautilus_query_editor_get_query (editor);
1139 g_signal_emit (editor, signals[CHANGED], 0,
1140 query, editor->details->is_indexed || force_reload);
1141 g_object_unref (query);
1145 static void
1146 nautilus_query_editor_changed (NautilusQueryEditor *editor)
1148 nautilus_query_editor_changed_force (editor, FALSE);
1151 void
1152 nautilus_query_editor_grab_focus (NautilusQueryEditor *editor)
1154 if (editor->details->is_visible) {
1155 gtk_widget_grab_focus (editor->details->entry);
1159 NautilusQuery *
1160 nautilus_query_editor_get_query (NautilusQueryEditor *editor)
1162 const char *query_text;
1163 NautilusQuery *query;
1164 GList *l;
1165 NautilusQueryEditorRow *row;
1167 query_text = gtk_entry_get_text (GTK_ENTRY (editor->details->entry));
1169 /* Empty string is a NULL query */
1170 if (query_text && query_text[0] == '\0') {
1171 return NULL;
1174 query = nautilus_query_new ();
1175 nautilus_query_set_text (query, query_text);
1177 for (l = editor->details->rows; l != NULL; l = l->next) {
1178 row = l->data;
1180 row_type[row->type].add_to_query (row, query);
1183 return query;
1186 void
1187 nautilus_query_editor_clear_query (NautilusQueryEditor *editor)
1189 editor->details->change_frozen = TRUE;
1190 gtk_entry_set_text (GTK_ENTRY (editor->details->entry), "");
1191 editor->details->change_frozen = FALSE;
1194 GtkWidget *
1195 nautilus_query_editor_new (gboolean start_hidden, gboolean is_indexed)
1197 GtkWidget *editor;
1199 editor = g_object_new (NAUTILUS_TYPE_QUERY_EDITOR, NULL);
1201 NAUTILUS_QUERY_EDITOR (editor)->details->is_indexed = is_indexed;
1203 nautilus_query_editor_set_visible (NAUTILUS_QUERY_EDITOR (editor),
1204 !start_hidden);
1206 setup_internal_entry (NAUTILUS_QUERY_EDITOR (editor));
1208 return editor;
1211 GtkWidget*
1212 nautilus_query_editor_new_with_bar (gboolean start_hidden,
1213 gboolean is_indexed,
1214 NautilusSearchBar *bar)
1216 GtkWidget *entry;
1217 NautilusQueryEditor *editor;
1219 editor = NAUTILUS_QUERY_EDITOR (g_object_new (NAUTILUS_TYPE_QUERY_EDITOR, NULL));
1220 editor->details->is_indexed = is_indexed;
1222 nautilus_query_editor_set_visible (editor, !start_hidden);
1224 editor->details->bar = bar;
1225 eel_add_weak_pointer (&editor->details->bar);
1227 entry = nautilus_search_bar_borrow_entry (bar);
1228 setup_external_entry (editor, entry);
1230 return GTK_WIDGET (editor);
1233 void
1234 nautilus_query_editor_set_query (NautilusQueryEditor *editor, NautilusQuery *query)
1236 NautilusQueryEditorRowType type;
1237 const char *text;
1239 if (!query) {
1240 nautilus_query_editor_clear_query (editor);
1241 return;
1244 text = nautilus_query_get_text (query);
1245 if (!text) {
1246 text = "";
1249 editor->details->change_frozen = TRUE;
1250 gtk_entry_set_text (GTK_ENTRY (editor->details->entry), text);
1252 for (type = 0; type < NAUTILUS_QUERY_EDITOR_ROW_LAST; type++) {
1253 row_type[type].add_rows_from_query (editor, query);
1256 editor->details->change_frozen = FALSE;