1 /* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
2 /*
3 * Copyright (C) 2005 Red Hat, Inc.
4 *
5 * Caja 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.
9 *
10 * Caja 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.
14 *
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., 51 Franklin St, Fifth Floor,
18 * Boston, MA 02110-1301, USA.
19 *
20 * Author: Alexander Larsson <alexl@redhat.com>
21 *
22 */
23
24 #include <config.h>
25 #include <string.h>
26
27 #include <glib/gi18n.h>
28 #include <gio/gio.h>
29 #include <gdk/gdkkeysyms.h>
30 #include <gtk/gtk.h>
31
32 #include <eel/eel-gtk-macros.h>
33 #include <eel/eel-glib-extensions.h>
34 #include <eel/eel-stock-dialogs.h>
35
36 #include <libcaja-private/caja-global-preferences.h>
37
38 #include "caja-query-editor.h"
39 #include "caja-src-marshal.h"
40 #include "caja-window-slot.h"
41
42 enum
43 {
44 DURATION_INVALID,
45 DURATION_ONE_HOUR,
46 DURATION_ONE_DAY,
47 DURATION_ONE_WEEK,
48 DURATION_ONE_MONTH,
49 DURATION_SIX_MONTHS,
50 DURATION_ONE_YEAR,
51 };
52
53 typedef enum
54 {
55 CAJA_QUERY_EDITOR_ROW_LOCATION,
56 CAJA_QUERY_EDITOR_ROW_TYPE,
57 CAJA_QUERY_EDITOR_ROW_TAGS,
58 CAJA_QUERY_EDITOR_ROW_TIME_MODIFIED,
59 CAJA_QUERY_EDITOR_ROW_SIZE,
60 CAJA_QUERY_EDITOR_ROW_CONTAINED_TEXT,
61
62 CAJA_QUERY_EDITOR_ROW_LAST
63 } CajaQueryEditorRowType;
64
65 typedef struct
66 {
67 CajaQueryEditorRowType type;
68 CajaQueryEditor *editor;
69 GtkWidget *hbox;
70 GtkWidget *combo;
71
72 GtkWidget *type_widget;
73
74 void *data;
75 } CajaQueryEditorRow;
76
77
78 typedef struct
79 {
80 const char *name;
81 GtkWidget * (*create_widgets) (CajaQueryEditorRow *row);
82 void (*add_to_query) (CajaQueryEditorRow *row,
83 CajaQuery *query);
84 void (*free_data) (CajaQueryEditorRow *row);
85 void (*add_rows_from_query) (CajaQueryEditor *editor,
86 CajaQuery *query);
87 } CajaQueryEditorRowOps;
88
89 struct CajaQueryEditorDetails
90 {
91 gboolean is_indexed;
92 GtkWidget *entry;
93 gboolean change_frozen;
94 guint typing_timeout_id;
95 gboolean is_visible;
96 GtkWidget *invisible_vbox;
97 GtkWidget *visible_vbox;
98
99 GList *rows;
100 char *last_set_query_text;
101
102 CajaSearchBar *bar;
103 CajaWindowSlot *slot;
104 };
105
106 enum
107 {
108 CHANGED,
109 CANCEL,
110 LAST_SIGNAL
111 };
112
113 static guint signals[LAST_SIGNAL] = { 0 };
114
115 static void caja_query_editor_class_init (CajaQueryEditorClass *class);
116 static void caja_query_editor_init (CajaQueryEditor *editor);
117
118 static void go_search_cb (GtkButton *clicked_button, CajaQueryEditor *editor);
119
120 static void entry_activate_cb (GtkWidget *entry, CajaQueryEditor *editor);
121 static void entry_changed_cb (GtkWidget *entry, CajaQueryEditor *editor);
122 static void caja_query_editor_changed_force (CajaQueryEditor *editor,
123 gboolean force);
124 static void caja_query_editor_changed (CajaQueryEditor *editor);
125 static CajaQueryEditorRow * caja_query_editor_add_row (CajaQueryEditor *editor,
126 CajaQueryEditorRowType type);
127
128 static GtkWidget *location_row_create_widgets (CajaQueryEditorRow *row);
129 static void location_row_add_to_query (CajaQueryEditorRow *row,
130 CajaQuery *query);
131 static void location_row_free_data (CajaQueryEditorRow *row);
132 static void location_add_rows_from_query (CajaQueryEditor *editor,
133 CajaQuery *query);
134
135 static GtkWidget *tags_row_create_widgets (CajaQueryEditorRow *row);
136 static void tags_row_add_to_query (CajaQueryEditorRow *row,
137 CajaQuery *query);
138 static void tags_row_free_data (CajaQueryEditorRow *row);
139 static void tags_add_rows_from_query (CajaQueryEditor *editor,
140 CajaQuery *query);
141
142 static GtkWidget *type_row_create_widgets (CajaQueryEditorRow *row);
143 static void type_row_add_to_query (CajaQueryEditorRow *row,
144 CajaQuery *query);
145 static void type_row_free_data (CajaQueryEditorRow *row);
146 static void type_add_rows_from_query (CajaQueryEditor *editor,
147 CajaQuery *query);
148 static GtkWidget *modtime_row_create_widgets(CajaQueryEditorRow *row);
149 static void modtime_row_add_to_query(CajaQueryEditorRow *row,
150 CajaQuery *query);
151 static void modtime_row_free_data(CajaQueryEditorRow *row);
152 static void modtime_add_rows_from_query(CajaQueryEditor *editor,
153 CajaQuery *query);
154 static GtkWidget *size_row_create_widgets(CajaQueryEditorRow *row);
155 static void size_row_add_to_query(CajaQueryEditorRow *row,
156 CajaQuery *query);
157 static void size_row_free_data(CajaQueryEditorRow *row);
158 static void size_add_rows_from_query(CajaQueryEditor *editor,
159 CajaQuery *query);
160
161 static GtkWidget *contained_text_row_create_widgets(CajaQueryEditorRow *row);
162 static void contained_text_row_add_to_query(CajaQueryEditorRow *row,
163 CajaQuery *query);
164 static void contained_text_row_free_data(CajaQueryEditorRow *row);
165 static void contained_text_add_rows_from_query(CajaQueryEditor *editor,
166 CajaQuery *query);
167
168 static CajaQueryEditorRowOps row_type[] =
169 {
170 {
171 N_("Location"),
172 location_row_create_widgets,
173 location_row_add_to_query,
174 location_row_free_data,
175 location_add_rows_from_query
176 },
177 {
178 N_("File Type"),
179 type_row_create_widgets,
180 type_row_add_to_query,
181 type_row_free_data,
182 type_add_rows_from_query
183 },
184 {
185 N_("Tags"),
186 tags_row_create_widgets,
187 tags_row_add_to_query,
188 tags_row_free_data,
189 tags_add_rows_from_query
190 },
191 {
192 N_("Modification Time"),
193 modtime_row_create_widgets,
194 modtime_row_add_to_query,
195 modtime_row_free_data,
196 modtime_add_rows_from_query
197 },
198 {
199 N_("Size"),
200 size_row_create_widgets,
201 size_row_add_to_query,
202 size_row_free_data,
203 size_add_rows_from_query
204 },
205 {
206 N_("Contained text"),
207 contained_text_row_create_widgets,
208 contained_text_row_add_to_query,
209 contained_text_row_free_data,
210 contained_text_add_rows_from_query
211 }
212 };
213
EEL_CLASS_BOILERPLATE(CajaQueryEditor,caja_query_editor,GTK_TYPE_BOX)214 EEL_CLASS_BOILERPLATE (CajaQueryEditor,
215 caja_query_editor,
216 GTK_TYPE_BOX)
217
218 static void
219 caja_query_editor_finalize (GObject *object)
220 {
221 CajaQueryEditor *editor;
222
223 editor = CAJA_QUERY_EDITOR (object);
224
225 g_free (editor->details);
226
227 EEL_CALL_PARENT (G_OBJECT_CLASS, finalize, (object));
228 }
229
230 static void
caja_query_editor_dispose(GObject * object)231 caja_query_editor_dispose (GObject *object)
232 {
233 CajaQueryEditor *editor;
234
235 editor = CAJA_QUERY_EDITOR (object);
236
237 if (editor->details->typing_timeout_id)
238 {
239 g_source_remove (editor->details->typing_timeout_id);
240 editor->details->typing_timeout_id = 0;
241 }
242
243 if (editor->details->bar != NULL)
244 {
245 g_signal_handlers_disconnect_by_func (editor->details->entry,
246 entry_activate_cb,
247 editor);
248 g_signal_handlers_disconnect_by_func (editor->details->entry,
249 entry_changed_cb,
250 editor);
251
252 caja_search_bar_return_entry (editor->details->bar);
253 eel_remove_weak_pointer (&editor->details->bar);
254 }
255
256 EEL_CALL_PARENT (G_OBJECT_CLASS, dispose, (object));
257 }
258
259 static void
caja_query_editor_class_init(CajaQueryEditorClass * class)260 caja_query_editor_class_init (CajaQueryEditorClass *class)
261 {
262 GObjectClass *gobject_class;
263 GtkBindingSet *binding_set;
264
265 gobject_class = G_OBJECT_CLASS (class);
266 gobject_class->finalize = caja_query_editor_finalize;
267 gobject_class->dispose = caja_query_editor_dispose;
268
269 signals[CHANGED] =
270 g_signal_new ("changed",
271 G_TYPE_FROM_CLASS (class),
272 G_SIGNAL_RUN_LAST,
273 G_STRUCT_OFFSET (CajaQueryEditorClass, changed),
274 NULL, NULL,
275 caja_src_marshal_VOID__OBJECT_BOOLEAN,
276 G_TYPE_NONE, 2, CAJA_TYPE_QUERY, G_TYPE_BOOLEAN);
277
278 signals[CANCEL] =
279 g_signal_new ("cancel",
280 G_TYPE_FROM_CLASS (class),
281 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
282 G_STRUCT_OFFSET (CajaQueryEditorClass, cancel),
283 NULL, NULL,
284 g_cclosure_marshal_VOID__VOID,
285 G_TYPE_NONE, 0);
286
287 binding_set = gtk_binding_set_by_class (class);
288 gtk_binding_entry_add_signal (binding_set, GDK_KEY_Escape, 0, "cancel", 0);
289 }
290
291 static void
entry_activate_cb(GtkWidget * entry,CajaQueryEditor * editor)292 entry_activate_cb (GtkWidget *entry, CajaQueryEditor *editor)
293 {
294 if (editor->details->typing_timeout_id)
295 {
296 g_source_remove (editor->details->typing_timeout_id);
297 editor->details->typing_timeout_id = 0;
298 }
299
300 caja_query_editor_changed_force (editor, TRUE);
301 }
302
303 static gboolean
typing_timeout_cb(gpointer user_data)304 typing_timeout_cb (gpointer user_data)
305 {
306 CajaQueryEditor *editor;
307
308 editor = CAJA_QUERY_EDITOR (user_data);
309
310 caja_query_editor_changed (editor);
311
312 editor->details->typing_timeout_id = 0;
313
314 return FALSE;
315 }
316
317 #define TYPING_TIMEOUT 750
318
319 static void
entry_changed_cb(GtkWidget * entry,CajaQueryEditor * editor)320 entry_changed_cb (GtkWidget *entry, CajaQueryEditor *editor)
321 {
322 if (editor->details->change_frozen)
323 {
324 return;
325 }
326
327 if (editor->details->typing_timeout_id)
328 {
329 g_source_remove (editor->details->typing_timeout_id);
330 }
331
332 editor->details->typing_timeout_id =
333 g_timeout_add (TYPING_TIMEOUT,
334 typing_timeout_cb,
335 editor);
336 }
337
338 static void
edit_clicked(GtkButton * button,CajaQueryEditor * editor)339 edit_clicked (GtkButton *button, CajaQueryEditor *editor)
340 {
341 caja_query_editor_set_visible (editor, TRUE);
342 caja_query_editor_grab_focus (editor);
343 }
344
345 /* Location */
346
347 static GtkWidget *
location_row_create_widgets(CajaQueryEditorRow * row)348 location_row_create_widgets (CajaQueryEditorRow *row)
349 {
350 GtkWidget *chooser;
351
352 chooser = gtk_file_chooser_button_new (_("Select folder to search in"),
353 GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER);
354 gtk_file_chooser_set_local_only (GTK_FILE_CHOOSER (chooser), TRUE);
355 gtk_file_chooser_set_current_folder (GTK_FILE_CHOOSER (chooser),
356 g_get_home_dir ());
357 gtk_widget_show (chooser);
358
359 g_signal_connect_swapped (chooser, "current-folder-changed",
360 G_CALLBACK (caja_query_editor_changed),
361 row->editor);
362
363 gtk_box_pack_start (GTK_BOX (row->hbox), chooser, FALSE, FALSE, 0);
364
365 return chooser;
366 }
367
368 static void
location_row_add_to_query(CajaQueryEditorRow * row,CajaQuery * query)369 location_row_add_to_query (CajaQueryEditorRow *row,
370 CajaQuery *query)
371 {
372 char *folder, *uri;
373
374 folder = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (row->type_widget));
375 if (folder == NULL)
376 {
377 /* I don't know why, but i got NULL here on initial search in browser mode
378 even with the location set to the homedir in create_widgets... */
379 folder = g_strdup (g_get_home_dir ());
380 }
381
382 uri = g_filename_to_uri (folder, NULL, NULL);
383 g_free (folder);
384
385 caja_query_set_location (query, uri);
386 g_free (uri);
387 }
388
389 static void
location_row_free_data(CajaQueryEditorRow * row)390 location_row_free_data (CajaQueryEditorRow *row)
391 {
392 }
393
394 static void
location_add_rows_from_query(CajaQueryEditor * editor,CajaQuery * query)395 location_add_rows_from_query (CajaQueryEditor *editor,
396 CajaQuery *query)
397 {
398 CajaQueryEditorRow *row;
399 char *uri, *folder;
400
401 uri = caja_query_get_location (query);
402
403 if (uri == NULL)
404 {
405 return;
406 }
407 folder = g_filename_from_uri (uri, NULL, NULL);
408 g_free (uri);
409 if (folder == NULL)
410 {
411 return;
412 }
413
414 row = caja_query_editor_add_row (editor,
415 CAJA_QUERY_EDITOR_ROW_LOCATION);
416 gtk_file_chooser_set_current_folder (GTK_FILE_CHOOSER (row->type_widget),
417 folder);
418
419 g_free (folder);
420 }
421
422 /* Tags */
423 static void
tags_entry_changed_cb(GtkWidget * entry,gpointer * data)424 tags_entry_changed_cb (GtkWidget *entry, gpointer *data)
425 {
426 /* remove commas from string */
427 const gchar *text = gtk_entry_get_text ( GTK_ENTRY (entry));
428 if (g_strrstr (text, ",") == NULL) {
429 return;
430 }
431
432 gchar **words = g_strsplit (text, ",", -1);
433 gchar *sanitized = g_strjoinv ("", words);
434 g_strfreev (words);
435
436 gtk_entry_set_text (GTK_ENTRY (entry), sanitized);
437 g_free(sanitized);
438 }
439
440 #define MAX_TAGS_ENTRY_LEN 4096 // arbitrary value.
441
442 static GtkWidget *
tags_row_create_widgets(CajaQueryEditorRow * row)443 tags_row_create_widgets (CajaQueryEditorRow *row)
444 {
445 GtkWidget *entry = gtk_entry_new();
446 gtk_entry_set_max_length (GTK_ENTRY (entry), MAX_TAGS_ENTRY_LEN);
447 gtk_widget_set_tooltip_text (entry,
448 _("Tags separated by spaces. "
449 "Matches files that contains ALL specified tags."));
450
451 gtk_entry_set_placeholder_text (GTK_ENTRY (entry),
452 _("Tags separated by spaces. "
453 "Matches files that contains ALL specified tags."));
454
455 gtk_widget_show (entry);
456 gtk_box_pack_start (GTK_BOX (row->hbox), entry, TRUE, TRUE, 0);
457 g_signal_connect (entry, "changed", G_CALLBACK (tags_entry_changed_cb), entry);
458 g_signal_connect (entry, "activate", G_CALLBACK (go_search_cb), row->editor);
459
460 return entry;
461 }
462
463 static void
tags_row_add_to_query(CajaQueryEditorRow * row,CajaQuery * query)464 tags_row_add_to_query (CajaQueryEditorRow *row,
465 CajaQuery *query)
466 {
467 GtkEntry *entry = GTK_ENTRY (row->type_widget);
468 const gchar *tags = gtk_entry_get_text (entry);
469
470 char **strv = g_strsplit (tags, " ", -1);
471 guint len = g_strv_length (strv);
472 int i;
473
474 for (i = 0; i < len; ++i) {
475 strv[i] = g_strstrip (strv[i]);
476 if (strlen (strv[i]) > 0) {
477 caja_query_add_tag (query, strv[i]);
478 }
479 }
480 g_strfreev (strv);
481 }
482
483 static void
tags_row_free_data(CajaQueryEditorRow * row)484 tags_row_free_data (CajaQueryEditorRow *row)
485 {
486 }
487
488 static gchar *
xattr_tags_list_to_str(const GList * tags)489 xattr_tags_list_to_str (const GList *tags)
490 {
491 gchar *result = NULL;
492
493 const GList *tags_iter = NULL;
494 for (tags_iter = tags; tags_iter; tags_iter = tags_iter->next) {
495 gchar *tmp;
496
497 if (result != NULL) {
498 tmp = g_strconcat (result, ",", tags_iter->data, NULL);
499 g_free (result);
500 } else {
501 tmp = g_strdup (tags_iter->data);
502 }
503
504 result = tmp;
505 }
506
507 return result;
508 }
509
510 static void
tags_add_rows_from_query(CajaQueryEditor * editor,CajaQuery * query)511 tags_add_rows_from_query (CajaQueryEditor *editor,
512 CajaQuery *query)
513 {
514 GList *tags = caja_query_get_tags (query);
515 if (tags == NULL) {
516 return;
517 }
518
519 CajaQueryEditorRow *row;
520 row = caja_query_editor_add_row (editor, CAJA_QUERY_EDITOR_ROW_TAGS);
521
522 gchar *tags_str = xattr_tags_list_to_str (tags);
523 g_list_free_full (tags, g_free);
524
525 gtk_entry_set_text (GTK_ENTRY (row->type_widget), tags_str);
526 g_free (tags_str);
527 }
528
529
530 /* Type */
531
532 static gboolean
type_separator_func(GtkTreeModel * model,GtkTreeIter * iter,gpointer data)533 type_separator_func (GtkTreeModel *model,
534 GtkTreeIter *iter,
535 gpointer data)
536 {
537 char *text;
538 gboolean res;
539
540 gtk_tree_model_get (model, iter, 0, &text, -1);
541
542 res = text != NULL && strcmp (text, "---") == 0;
543
544 g_free (text);
545 return res;
546 }
547
548 struct
549 {
550 char *name;
551 char *mimetypes[20];
552 } mime_type_groups[] =
553 {
554 {
555 N_("Documents"),
556 {
557 "application/rtf",
558 "application/msword",
559 "application/vnd.sun.xml.writer",
560 "application/vnd.sun.xml.writer.global",
561 "application/vnd.sun.xml.writer.template",
562 "application/vnd.oasis.opendocument.text",
563 "application/vnd.oasis.opendocument.text-template",
564 "application/x-abiword",
565 "application/x-applix-word",
566 "application/x-mswrite",
567 "application/docbook+xml",
568 "application/x-kword",
569 "application/x-kword-crypt",
570 "application/x-lyx",
571 NULL
572 }
573 },
574 {
575 N_("Music"),
576 {
577 "application/ogg",
578 "audio/ac3",
579 "audio/basic",
580 "audio/midi",
581 "audio/x-flac",
582 "audio/mp4",
583 "audio/mpeg",
584 "audio/x-mpeg",
585 "audio/x-ms-asx",
586 "audio/x-pn-realaudio",
587 NULL
588 }
589 },
590 {
591 N_("Video"),
592 {
593 "video/mp4",
594 "video/3gpp",
595 "video/mpeg",
596 "video/quicktime",
597 "video/vivo",
598 "video/x-avi",
599 "video/x-mng",
600 "video/x-ms-asf",
601 "video/x-ms-wmv",
602 "video/x-msvideo",
603 "video/x-nsv",
604 "video/x-real-video",
605 NULL
606 }
607 },
608 {
609 N_("Picture"),
610 {
611 "application/vnd.oasis.opendocument.image",
612 "application/x-krita",
613 "image/bmp",
614 "image/cgm",
615 "image/gif",
616 "image/jpeg",
617 "image/jpeg2000",
618 "image/png",
619 "image/svg+xml",
620 "image/tiff",
621 "image/x-compressed-xcf",
622 "image/x-pcx",
623 "image/x-photo-cd",
624 "image/x-psd",
625 "image/x-tga",
626 "image/x-xcf",
627 NULL
628 }
629 },
630 {
631 N_("Illustration"),
632 {
633 "application/illustrator",
634 "application/vnd.corel-draw",
635 "application/vnd.stardivision.draw",
636 "application/vnd.oasis.opendocument.graphics",
637 "application/x-dia-diagram",
638 "application/x-karbon",
639 "application/x-killustrator",
640 "application/x-kivio",
641 "application/x-kontour",
642 "application/x-wpg",
643 NULL
644 }
645 },
646 {
647 N_("Spreadsheet"),
648 {
649 "application/vnd.lotus-1-2-3",
650 "application/vnd.ms-excel",
651 "application/vnd.stardivision.calc",
652 "application/vnd.sun.xml.calc",
653 "application/vnd.oasis.opendocument.spreadsheet",
654 "application/x-applix-spreadsheet",
655 "application/x-gnumeric",
656 "application/x-kspread",
657 "application/x-kspread-crypt",
658 "application/x-quattropro",
659 "application/x-sc",
660 "application/x-siag",
661 NULL
662 }
663 },
664 {
665 N_("Presentation"),
666 {
667 "application/vnd.ms-powerpoint",
668 "application/vnd.sun.xml.impress",
669 "application/vnd.oasis.opendocument.presentation",
670 "application/x-magicpoint",
671 "application/x-kpresenter",
672 NULL
673 }
674 },
675 {
676 N_("Pdf / Postscript"),
677 {
678 "application/pdf",
679 "application/postscript",
680 "application/x-dvi",
681 "image/x-eps",
682 NULL
683 }
684 },
685 {
686 N_("Text File"),
687 {
688 "text/plain",
689 NULL
690 }
691 }
692 };
693
694 static void
type_add_custom_type(CajaQueryEditorRow * row,const char * mime_type,const char * description,GtkTreeIter * iter)695 type_add_custom_type (CajaQueryEditorRow *row,
696 const char *mime_type,
697 const char *description,
698 GtkTreeIter *iter)
699 {
700 GtkTreeModel *model;
701 GtkListStore *store;
702
703 model = gtk_combo_box_get_model (GTK_COMBO_BOX (row->type_widget));
704 store = GTK_LIST_STORE (model);
705
706 gtk_list_store_append (store, iter);
707 gtk_list_store_set (store, iter,
708 0, description,
709 2, mime_type,
710 -1);
711 }
712
713
714 static void
type_combo_changed(GtkComboBox * combo_box,CajaQueryEditorRow * row)715 type_combo_changed (GtkComboBox *combo_box, CajaQueryEditorRow *row)
716 {
717 GtkTreeIter iter;
718 gboolean other;
719 GtkTreeModel *model;
720
721 if (!gtk_combo_box_get_active_iter (GTK_COMBO_BOX (row->type_widget),
722 &iter))
723 {
724 return;
725 }
726
727 model = gtk_combo_box_get_model (GTK_COMBO_BOX (row->type_widget));
728 gtk_tree_model_get (model, &iter, 3, &other, -1);
729
730 if (other)
731 {
732 GList *mime_infos, *l;
733 GtkWidget *dialog;
734 GtkWidget *scrolled, *treeview;
735 GtkListStore *store;
736 GtkTreeViewColumn *column;
737 GtkCellRenderer *renderer;
738 GtkWidget *toplevel;
739 GtkTreeSelection *selection;
740
741 mime_infos = g_content_types_get_registered ();
742
743 store = gtk_list_store_new (2, G_TYPE_STRING, G_TYPE_STRING);
744 for (l = mime_infos; l != NULL; l = l->next)
745 {
746 GtkTreeIter iter;
747 char *mime_type = l->data;
748 char *description;
749
750 description = g_content_type_get_description (mime_type);
751 if (description == NULL)
752 {
753 description = g_strdup (mime_type);
754 }
755
756 gtk_list_store_append (store, &iter);
757 gtk_list_store_set (store, &iter,
758 0, description,
759 1, mime_type,
760 -1);
761
762 g_free (mime_type);
763 g_free (description);
764 }
765 g_list_free (mime_infos);
766
767
768
769 toplevel = gtk_widget_get_toplevel (GTK_WIDGET (combo_box));
770
771 dialog = gtk_dialog_new ();
772 gtk_window_set_title (GTK_WINDOW (dialog), _("Select type"));
773 gtk_window_set_transient_for (GTK_WINDOW (dialog), GTK_WINDOW (toplevel));
774
775 eel_dialog_add_button (GTK_DIALOG (dialog),
776 _("_OK"),
777 "gtk-ok",
778 GTK_RESPONSE_OK);
779
780 gtk_window_set_default_size (GTK_WINDOW (dialog), 400, 600);
781
782 scrolled = gtk_scrolled_window_new (NULL, NULL);
783 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled),
784 GTK_POLICY_AUTOMATIC,
785 GTK_POLICY_AUTOMATIC);
786 gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scrolled),
787 GTK_SHADOW_IN);
788 gtk_scrolled_window_set_overlay_scrolling (GTK_SCROLLED_WINDOW (scrolled),
789 FALSE);
790
791 gtk_widget_show (scrolled);
792 gtk_box_pack_start (GTK_BOX (gtk_dialog_get_content_area (GTK_DIALOG (dialog))), scrolled, TRUE, TRUE, 6);
793
794 treeview = gtk_tree_view_new ();
795 gtk_tree_view_set_model (GTK_TREE_VIEW (treeview),
796 GTK_TREE_MODEL (store));
797 gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (store), 0,
798 GTK_SORT_ASCENDING);
799
800 selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (treeview));
801 gtk_tree_selection_set_mode (selection, GTK_SELECTION_BROWSE);
802
803
804 renderer = gtk_cell_renderer_text_new ();
805 column = gtk_tree_view_column_new_with_attributes ("Name",
806 renderer,
807 "text",
808 0,
809 NULL);
810 gtk_tree_view_append_column (GTK_TREE_VIEW (treeview), column);
811 gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (treeview), FALSE);
812
813 gtk_widget_show (treeview);
814 gtk_container_add (GTK_CONTAINER (scrolled), treeview);
815
816 if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_OK)
817 {
818 char *mimetype, *description;
819
820 gtk_tree_selection_get_selected (selection, NULL, &iter);
821 gtk_tree_model_get (GTK_TREE_MODEL (store), &iter,
822 0, &description,
823 1, &mimetype,
824 -1);
825
826 type_add_custom_type (row, mimetype, description, &iter);
827 gtk_combo_box_set_active_iter (GTK_COMBO_BOX (row->type_widget),
828 &iter);
829 }
830 else
831 {
832 gtk_combo_box_set_active (GTK_COMBO_BOX (row->type_widget), 0);
833 }
834
835 gtk_widget_destroy (dialog);
836 }
837
838 caja_query_editor_changed (row->editor);
839 }
840
841 static GtkWidget *
type_row_create_widgets(CajaQueryEditorRow * row)842 type_row_create_widgets (CajaQueryEditorRow *row)
843 {
844 GtkWidget *combo;
845 GtkCellRenderer *cell;
846 GtkListStore *store;
847 GtkTreeIter iter;
848 int i;
849
850 store = gtk_list_store_new (4, G_TYPE_STRING, G_TYPE_POINTER, G_TYPE_STRING, G_TYPE_BOOLEAN);
851 combo = gtk_combo_box_new_with_model (GTK_TREE_MODEL (store));
852 g_object_unref (store);
853
854 cell = gtk_cell_renderer_text_new ();
855 gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (combo), cell, TRUE);
856 gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (combo), cell,
857 "text", 0,
858 NULL);
859 gtk_combo_box_set_row_separator_func (GTK_COMBO_BOX (combo),
860 type_separator_func,
861 NULL, NULL);
862
863 gtk_list_store_append (store, &iter);
864 gtk_list_store_set (store, &iter, 0, _("Any"), -1);
865 gtk_list_store_append (store, &iter);
866 gtk_list_store_set (store, &iter, 0, "---", -1);
867
868 for (i = 0; i < G_N_ELEMENTS (mime_type_groups); i++)
869 {
870 gtk_list_store_append (store, &iter);
871 gtk_list_store_set (store, &iter,
872 0, gettext (mime_type_groups[i].name),
873 1, mime_type_groups[i].mimetypes,
874 -1);
875 }
876
877 gtk_list_store_append (store, &iter);
878 gtk_list_store_set (store, &iter, 0, "---", -1);
879 gtk_list_store_append (store, &iter);
880 gtk_list_store_set (store, &iter, 0, _("Other Type..."), 3, TRUE, -1);
881
882 gtk_combo_box_set_active (GTK_COMBO_BOX (combo), 0);
883
884 g_signal_connect (combo, "changed",
885 G_CALLBACK (type_combo_changed),
886 row);
887
888 gtk_widget_show (combo);
889
890 gtk_box_pack_start (GTK_BOX (row->hbox), combo, FALSE, FALSE, 0);
891
892 return combo;
893 }
894
895 static void
type_row_add_to_query(CajaQueryEditorRow * row,CajaQuery * query)896 type_row_add_to_query (CajaQueryEditorRow *row,
897 CajaQuery *query)
898 {
899 GtkTreeIter iter;
900 char **mimetypes;
901 char *mimetype;
902 GtkTreeModel *model;
903
904 if (!gtk_combo_box_get_active_iter (GTK_COMBO_BOX (row->type_widget),
905 &iter))
906 {
907 return;
908 }
909
910 model = gtk_combo_box_get_model (GTK_COMBO_BOX (row->type_widget));
911 gtk_tree_model_get (model, &iter, 1, &mimetypes, 2, &mimetype, -1);
912
913 if (mimetypes != NULL)
914 {
915 while (*mimetypes != NULL)
916 {
917 caja_query_add_mime_type (query, *mimetypes);
918 mimetypes++;
919 }
920 }
921 if (mimetype)
922 {
923 caja_query_add_mime_type (query, mimetype);
924 g_free (mimetype);
925 }
926 }
927
928 static void
type_row_free_data(CajaQueryEditorRow * row)929 type_row_free_data (CajaQueryEditorRow *row)
930 {
931 }
932
933 static gboolean
all_group_types_in_list(char ** group_types,GList * mime_types)934 all_group_types_in_list (char **group_types, GList *mime_types)
935 {
936 GList *l;
937 char **group_type;
938 char *mime_type;
939 gboolean found;
940
941 group_type = group_types;
942 while (*group_type != NULL)
943 {
944 found = FALSE;
945
946 for (l = mime_types; l != NULL; l = l->next)
947 {
948 mime_type = l->data;
949
950 if (strcmp (mime_type, *group_type) == 0)
951 {
952 found = TRUE;
953 break;
954 }
955 }
956
957 if (!found)
958 {
959 return FALSE;
960 }
961 group_type++;
962 }
963 return TRUE;
964 }
965
966 static GList *
remove_group_types_from_list(char ** group_types,GList * mime_types)967 remove_group_types_from_list (char **group_types, GList *mime_types)
968 {
969 GList *l, *next;
970 char **group_type;
971 char *mime_type;
972
973 group_type = group_types;
974 while (*group_type != NULL)
975 {
976 for (l = mime_types; l != NULL; l = next)
977 {
978 mime_type = l->data;
979 next = l->next;
980
981 if (strcmp (mime_type, *group_type) == 0)
982 {
983 mime_types = g_list_remove_link (mime_types, l);
984 g_free (mime_type);
985 break;
986 }
987 }
988
989 group_type++;
990 }
991 return mime_types;
992 }
993
994
995 static void
type_add_rows_from_query(CajaQueryEditor * editor,CajaQuery * query)996 type_add_rows_from_query (CajaQueryEditor *editor,
997 CajaQuery *query)
998 {
999 GList *mime_types;
1000 char *mime_type;
1001 CajaQueryEditorRow *row;
1002 GtkTreeIter iter;
1003 int i;
1004 GtkTreeModel *model;
1005 GList *l;
1006
1007 mime_types = caja_query_get_mime_types (query);
1008
1009 if (mime_types == NULL)
1010 {
1011 return;
1012 }
1013
1014 for (i = 0; i < G_N_ELEMENTS (mime_type_groups); i++)
1015 {
1016 if (all_group_types_in_list (mime_type_groups[i].mimetypes,
1017 mime_types))
1018 {
1019 mime_types = remove_group_types_from_list (mime_type_groups[i].mimetypes,
1020 mime_types);
1021
1022 row = caja_query_editor_add_row (editor,
1023 CAJA_QUERY_EDITOR_ROW_TYPE);
1024
1025 model = gtk_combo_box_get_model (GTK_COMBO_BOX (row->type_widget));
1026
1027 gtk_tree_model_iter_nth_child (model, &iter, NULL, i + 2);
1028 gtk_combo_box_set_active_iter (GTK_COMBO_BOX (row->type_widget),
1029 &iter);
1030 }
1031 }
1032
1033 for (l = mime_types; l != NULL; l = l->next)
1034 {
1035 const char *desc;
1036
1037 mime_type = l->data;
1038
1039 desc = g_content_type_get_description (mime_type);
1040 if (desc == NULL)
1041 {
1042 desc = mime_type;
1043 }
1044
1045 row = caja_query_editor_add_row (editor,
1046 CAJA_QUERY_EDITOR_ROW_TYPE);
1047 model = gtk_combo_box_get_model (GTK_COMBO_BOX (row->type_widget));
1048
1049 type_add_custom_type (row, mime_type, desc, &iter);
1050 gtk_combo_box_set_active_iter (GTK_COMBO_BOX (row->type_widget),
1051 &iter);
1052 }
1053
1054 g_list_free_full (mime_types, g_free);
1055 }
1056
1057 /* End of row types */
1058
1059
modtime_row_create_widgets(CajaQueryEditorRow * row)1060 static GtkWidget *modtime_row_create_widgets(CajaQueryEditorRow *row)
1061 {
1062 GtkWidget *hbox = NULL;
1063 GtkWidget *combo = NULL;
1064 GtkWidget *duration_combo = NULL;
1065 GtkCellRenderer *cell = NULL;
1066 GtkListStore *store = NULL;
1067 GtkListStore *duration_store = NULL;
1068 GtkTreeIter iter;
1069
1070 hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 7);
1071
1072 store = gtk_list_store_new(2, G_TYPE_BOOLEAN, G_TYPE_STRING);
1073 combo = gtk_combo_box_new_with_model(GTK_TREE_MODEL(store));
1074 g_object_unref(store);
1075
1076 cell = gtk_cell_renderer_text_new();
1077 gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(combo), cell, TRUE);
1078 gtk_cell_layout_set_attributes(GTK_CELL_LAYOUT(combo), cell, "text", 1,
1079 NULL);
1080
1081 gtk_list_store_append(store, &iter);
1082 gtk_list_store_set(store, &iter, 0, FALSE, 1, _("Less than or equal to"), -1);
1083 gtk_list_store_append(store, &iter);
1084 gtk_list_store_set(store, &iter, 0, TRUE, 1, _("Greater than or equal to"), -1);
1085
1086 gtk_combo_box_set_active(GTK_COMBO_BOX(combo), 0);
1087
1088 duration_store = gtk_list_store_new(2, G_TYPE_INT, G_TYPE_STRING);
1089 duration_combo = gtk_combo_box_new_with_model(GTK_TREE_MODEL(duration_store));
1090 g_object_unref(duration_store);
1091
1092 gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(duration_combo), cell, TRUE);
1093 gtk_cell_layout_set_attributes(GTK_CELL_LAYOUT(duration_combo), cell,
1094 "text", 1, NULL);
1095
1096 gtk_list_store_append(duration_store, &iter);
1097 gtk_list_store_set(duration_store, &iter, 0, DURATION_ONE_HOUR, 1, _("1 Hour"), -1);
1098 gtk_list_store_append(duration_store, &iter);
1099 gtk_list_store_set(duration_store, &iter, 0, DURATION_ONE_DAY, 1, _("1 Day"), -1);
1100 gtk_list_store_append(duration_store, &iter);
1101 gtk_list_store_set(duration_store, &iter, 0, DURATION_ONE_WEEK, 1, _("1 Week"), -1);
1102 gtk_list_store_append(duration_store, &iter);
1103 gtk_list_store_set(duration_store, &iter, 0, DURATION_ONE_MONTH, 1, _("1 Month"), -1);
1104 gtk_list_store_append(duration_store, &iter);
1105 gtk_list_store_set(duration_store, &iter, 0, DURATION_SIX_MONTHS, 1, _("6 Months"), -1);
1106 gtk_list_store_append(duration_store, &iter);
1107 gtk_list_store_set(duration_store, &iter, 0, DURATION_ONE_YEAR, 1, _("1 Year"), -1);
1108
1109 gtk_combo_box_set_active(GTK_COMBO_BOX(duration_combo), 0);
1110
1111 gtk_box_pack_start(GTK_BOX(hbox), combo, FALSE, FALSE, 0);
1112 gtk_box_pack_start(GTK_BOX(hbox), duration_combo, FALSE, FALSE, 0);
1113 gtk_widget_show_all(hbox);
1114
1115 gtk_box_pack_start(GTK_BOX(row->hbox), hbox, FALSE, FALSE, 0);
1116
1117 return hbox;
1118 }
1119
modtime_row_add_to_query(CajaQueryEditorRow * row,CajaQuery * query)1120 static void modtime_row_add_to_query(CajaQueryEditorRow *row, CajaQuery *query)
1121 {
1122 GList *children = NULL;
1123 GtkWidget *combo = NULL;
1124 GtkWidget *duration_combo = NULL;
1125 GtkTreeModel *model = NULL;
1126 GtkTreeModel *duration_model = NULL;
1127 GtkTreeIter iter;
1128 GtkTreeIter duration_iter;
1129 gboolean is_greater = FALSE;
1130 GDateTime *now, *datetime;
1131 gint duration;
1132 gint64 timestamp;
1133
1134 if (!GTK_IS_CONTAINER(row->type_widget))
1135 return;
1136
1137 children = gtk_container_get_children(GTK_CONTAINER(row->type_widget));
1138 if (g_list_length(children) != 2)
1139 return;
1140
1141 combo = GTK_WIDGET(g_list_nth(children, 0)->data);
1142 duration_combo = GTK_WIDGET(g_list_nth(children, 1)->data);
1143 if (!combo || !duration_combo)
1144 return;
1145
1146 if (!gtk_combo_box_get_active_iter(GTK_COMBO_BOX(combo), &iter) ||
1147 !gtk_combo_box_get_active_iter(GTK_COMBO_BOX(duration_combo), &duration_iter)) {
1148 return;
1149 }
1150
1151 model = gtk_combo_box_get_model(GTK_COMBO_BOX(combo));
1152 gtk_tree_model_get(model, &iter, 0, &is_greater, -1);
1153
1154 duration_model = gtk_combo_box_get_model(GTK_COMBO_BOX(duration_combo));
1155 gtk_tree_model_get(duration_model, &duration_iter, 0, &duration, -1);
1156
1157 now = g_date_time_new_now_local ();
1158 datetime = now;
1159 switch (duration)
1160 {
1161 case DURATION_ONE_HOUR:
1162 datetime = g_date_time_add_hours (now, -1);
1163 break;
1164 case DURATION_ONE_DAY:
1165 datetime = g_date_time_add_days (now, -1);
1166 break;
1167 case DURATION_ONE_WEEK:
1168 datetime = g_date_time_add_weeks (now, -1);
1169 break;
1170 case DURATION_ONE_MONTH:
1171 datetime = g_date_time_add_months (now, -1);
1172 break;
1173 case DURATION_SIX_MONTHS:
1174 datetime = g_date_time_add_months (now, -6);
1175 break;
1176 case DURATION_ONE_YEAR:
1177 datetime = g_date_time_add_years (now, -1);
1178 break;
1179 default:
1180 g_assert_not_reached ();
1181 }
1182
1183 g_date_time_unref (now);
1184 timestamp = g_date_time_to_unix (datetime);
1185 g_date_time_unref (datetime);
1186
1187 caja_query_set_timestamp(query, is_greater ? timestamp: -timestamp);
1188 }
1189
modtime_row_free_data(CajaQueryEditorRow * row)1190 static void modtime_row_free_data(CajaQueryEditorRow *row)
1191 {
1192 }
1193
modtime_add_rows_from_query(CajaQueryEditor * editor,CajaQuery * query)1194 static void modtime_add_rows_from_query(CajaQueryEditor *editor, CajaQuery *query)
1195 {
1196 }
1197
1198
size_row_create_widgets(CajaQueryEditorRow * row)1199 static GtkWidget *size_row_create_widgets(CajaQueryEditorRow *row)
1200 {
1201 GtkWidget *hbox = NULL;
1202 GtkWidget *combo = NULL;
1203 GtkWidget *size_combo = NULL;
1204 GtkCellRenderer *cell = NULL;
1205 GtkListStore *store = NULL;
1206 GtkListStore *size_store = NULL;
1207 GtkTreeIter iter;
1208
1209 hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 7);
1210
1211 store = gtk_list_store_new(2, G_TYPE_BOOLEAN, G_TYPE_STRING);
1212 combo = gtk_combo_box_new_with_model(GTK_TREE_MODEL(store));
1213 g_object_unref(store);
1214
1215 cell = gtk_cell_renderer_text_new();
1216 gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(combo), cell, TRUE);
1217 gtk_cell_layout_set_attributes(GTK_CELL_LAYOUT(combo), cell, "text", 1,
1218 NULL);
1219
1220 gtk_list_store_append(store, &iter);
1221 gtk_list_store_set(store, &iter, 0, FALSE, 1, _("Less than or equal to"), -1);
1222 gtk_list_store_append(store, &iter);
1223 gtk_list_store_set(store, &iter, 0, TRUE, 1, _("Greater than or equal to"), -1);
1224
1225 gtk_combo_box_set_active(GTK_COMBO_BOX(combo), 0);
1226
1227 size_store = gtk_list_store_new(2, G_TYPE_INT64, G_TYPE_STRING);
1228 size_combo = gtk_combo_box_new_with_model(GTK_TREE_MODEL(size_store));
1229 g_object_unref(size_store);
1230
1231 gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(size_combo), cell, TRUE);
1232 gtk_cell_layout_set_attributes(GTK_CELL_LAYOUT(size_combo), cell, "text",
1233 1, NULL);
1234
1235 if (g_settings_get_boolean (caja_preferences, CAJA_PREFERENCES_USE_IEC_UNITS))
1236 {
1237 gtk_list_store_append(size_store, &iter);
1238 gtk_list_store_set(size_store, &iter, 0, 10240, 1, _("10 KiB"), -1);
1239 gtk_list_store_append(size_store, &iter);
1240 gtk_list_store_set(size_store, &iter, 0, 102400, 1, _("100 KiB"), -1);
1241 gtk_list_store_append(size_store, &iter);
1242 gtk_list_store_set(size_store, &iter, 0, 512000, 1, _("500 KiB"), -1);
1243 gtk_list_store_append(size_store, &iter);
1244 gtk_list_store_set(size_store, &iter, 0, 1048576, 1, _("1 MiB"), -1);
1245 gtk_list_store_append(size_store, &iter);
1246 gtk_list_store_set(size_store, &iter, 0, 5242880, 1, _("5 MiB"), -1);
1247 gtk_list_store_append(size_store, &iter);
1248 gtk_list_store_set(size_store, &iter, 0, 10485760, 1, _("10 MiB"), -1);
1249 gtk_list_store_append(size_store, &iter);
1250 gtk_list_store_set(size_store, &iter, 0, 104857600, 1, _("100 MiB"), -1);
1251 gtk_list_store_append(size_store, &iter);
1252 gtk_list_store_set(size_store, &iter, 0, 524288000, 1, _("500 MiB"), -1);
1253 gtk_list_store_append(size_store, &iter);
1254 gtk_list_store_set(size_store, &iter, 0, 1073741824, 1, _("1 GiB"), -1);
1255 gtk_list_store_append(size_store, &iter);
1256 gtk_list_store_set(size_store, &iter, 0, 2147483648, 1, _("2 GiB"), -1);
1257 gtk_list_store_append(size_store, &iter);
1258 gtk_list_store_set(size_store, &iter, 0, 4294967296, 1, _("4 GiB"), -1);
1259 } else {
1260 gtk_list_store_append(size_store, &iter);
1261 gtk_list_store_set(size_store, &iter, 0, 10000, 1, _("10 KB"), -1);
1262 gtk_list_store_append(size_store, &iter);
1263 gtk_list_store_set(size_store, &iter, 0, 100000, 1, _("100 KB"), -1);
1264 gtk_list_store_append(size_store, &iter);
1265 gtk_list_store_set(size_store, &iter, 0, 500000, 1, _("500 KB"), -1);
1266 gtk_list_store_append(size_store, &iter);
1267 gtk_list_store_set(size_store, &iter, 0, 1000000, 1, _("1 MB"), -1);
1268 gtk_list_store_append(size_store, &iter);
1269 gtk_list_store_set(size_store, &iter, 0, 5000000, 1, _("5 MB"), -1);
1270 gtk_list_store_append(size_store, &iter);
1271 gtk_list_store_set(size_store, &iter, 0, 10000000, 1, _("10 MB"), -1);
1272 gtk_list_store_append(size_store, &iter);
1273 gtk_list_store_set(size_store, &iter, 0, 100000000, 1, _("100 MB"), -1);
1274 gtk_list_store_append(size_store, &iter);
1275 gtk_list_store_set(size_store, &iter, 0, 500000000, 1, _("500 MB"), -1);
1276 gtk_list_store_append(size_store, &iter);
1277 gtk_list_store_set(size_store, &iter, 0, 1000000000, 1, _("1 GB"), -1);
1278 gtk_list_store_append(size_store, &iter);
1279 gtk_list_store_set(size_store, &iter, 0, 2000000000, 1, _("2 GB"), -1);
1280 gtk_list_store_append(size_store, &iter);
1281 gtk_list_store_set(size_store, &iter, 0, 4000000000, 1, _("4 GB"), -1);
1282 }
1283
1284 gtk_combo_box_set_active(GTK_COMBO_BOX(size_combo), 0);
1285
1286 gtk_box_pack_start(GTK_BOX(hbox), combo, FALSE, FALSE, 0);
1287 gtk_box_pack_start(GTK_BOX(hbox), size_combo, FALSE, FALSE, 0);
1288 gtk_widget_show_all(hbox);
1289
1290 gtk_box_pack_start(GTK_BOX(row->hbox), hbox, FALSE, FALSE, 0);
1291
1292 return hbox;
1293 }
1294
size_row_add_to_query(CajaQueryEditorRow * row,CajaQuery * query)1295 static void size_row_add_to_query(CajaQueryEditorRow *row, CajaQuery *query)
1296 {
1297 GList *children = NULL;
1298 GtkWidget *combo = NULL;
1299 GtkWidget *size_combo = NULL;
1300 GtkTreeModel *model = NULL;
1301 GtkTreeModel *size_model = NULL;
1302 GtkTreeIter iter;
1303 GtkTreeIter size_iter;
1304 gboolean is_greater = FALSE;
1305 gint64 size;
1306
1307 if (!GTK_IS_CONTAINER(row->type_widget))
1308 return;
1309
1310 children = gtk_container_get_children(GTK_CONTAINER(row->type_widget));
1311 if (g_list_length(children) != 2)
1312 return;
1313
1314 combo = GTK_WIDGET(g_list_nth(children, 0)->data);
1315 size_combo = GTK_WIDGET(g_list_nth(children, 1)->data);
1316 if (!combo || !size_combo)
1317 return;
1318
1319 if (!gtk_combo_box_get_active_iter(GTK_COMBO_BOX(combo), &iter) ||
1320 !gtk_combo_box_get_active_iter(GTK_COMBO_BOX(size_combo), &size_iter)) {
1321 return;
1322 }
1323
1324 model = gtk_combo_box_get_model(GTK_COMBO_BOX(combo));
1325 gtk_tree_model_get(model, &iter, 0, &is_greater, -1);
1326
1327 size_model = gtk_combo_box_get_model(GTK_COMBO_BOX(size_combo));
1328 gtk_tree_model_get(size_model, &size_iter, 0, &size, -1);
1329
1330 caja_query_set_size(query, is_greater ? size : -size);
1331 }
1332
size_row_free_data(CajaQueryEditorRow * row)1333 static void size_row_free_data(CajaQueryEditorRow *row)
1334 {
1335 }
1336
size_add_rows_from_query(CajaQueryEditor * editor,CajaQuery * query)1337 static void size_add_rows_from_query(CajaQueryEditor *editor, CajaQuery *query)
1338 {
1339 }
1340
1341 static GtkWidget *
contained_text_row_create_widgets(CajaQueryEditorRow * row)1342 contained_text_row_create_widgets (CajaQueryEditorRow *row)
1343 {
1344 GtkWidget *entry = gtk_entry_new();
1345 gtk_widget_set_tooltip_text (entry,
1346 _("Matches files that contains specified text."));
1347
1348 gtk_entry_set_placeholder_text (GTK_ENTRY (entry),
1349 _("Matches files that contains specified text."));
1350
1351 gtk_widget_show (entry);
1352 gtk_box_pack_start (GTK_BOX (row->hbox), entry, TRUE, TRUE, 0);
1353 g_signal_connect (entry, "activate", G_CALLBACK (go_search_cb), row->editor);
1354
1355 return entry;
1356 }
1357
1358 static void
contained_text_row_add_to_query(CajaQueryEditorRow * row,CajaQuery * query)1359 contained_text_row_add_to_query (CajaQueryEditorRow *row, CajaQuery *query)
1360 {
1361 GtkEntry *entry = GTK_ENTRY (row->type_widget);
1362 const gchar *text = gtk_entry_get_text (entry);
1363
1364 caja_query_set_contained_text (query, text);
1365 }
1366
1367 static void
contained_text_row_free_data(CajaQueryEditorRow * row)1368 contained_text_row_free_data (CajaQueryEditorRow *row)
1369 {
1370 }
1371
1372 static void
contained_text_add_rows_from_query(CajaQueryEditor * editor,CajaQuery * query)1373 contained_text_add_rows_from_query (CajaQueryEditor *editor, CajaQuery *query)
1374 {
1375 }
1376
1377 static CajaQueryEditorRowType
get_next_free_type(CajaQueryEditor * editor)1378 get_next_free_type (CajaQueryEditor *editor)
1379 {
1380 CajaQueryEditorRow *row;
1381 CajaQueryEditorRowType type;
1382 gboolean found;
1383 GList *l;
1384
1385
1386 for (type = 0; type < CAJA_QUERY_EDITOR_ROW_LAST; type++)
1387 {
1388 found = FALSE;
1389 for (l = editor->details->rows; l != NULL; l = l->next)
1390 {
1391 row = l->data;
1392 if (row->type == type)
1393 {
1394 found = TRUE;
1395 break;
1396 }
1397 }
1398 if (!found)
1399 {
1400 return type;
1401 }
1402 }
1403 return CAJA_QUERY_EDITOR_ROW_TYPE;
1404 }
1405
1406 static void
remove_row_cb(GtkButton * clicked_button,CajaQueryEditorRow * row)1407 remove_row_cb (GtkButton *clicked_button, CajaQueryEditorRow *row)
1408 {
1409 CajaQueryEditor *editor;
1410
1411 editor = row->editor;
1412 gtk_container_remove (GTK_CONTAINER (editor->details->visible_vbox),
1413 row->hbox);
1414
1415 editor->details->rows = g_list_remove (editor->details->rows, row);
1416
1417 row_type[row->type].free_data (row);
1418 g_free (row);
1419
1420 caja_query_editor_changed (editor);
1421 }
1422
1423 static void
create_type_widgets(CajaQueryEditorRow * row)1424 create_type_widgets (CajaQueryEditorRow *row)
1425 {
1426 row->type_widget = row_type[row->type].create_widgets (row);
1427 }
1428
1429 static void
row_type_combo_changed_cb(GtkComboBox * combo_box,CajaQueryEditorRow * row)1430 row_type_combo_changed_cb (GtkComboBox *combo_box, CajaQueryEditorRow *row)
1431 {
1432 CajaQueryEditorRowType type;
1433
1434 type = gtk_combo_box_get_active (combo_box);
1435
1436 if (type == row->type)
1437 {
1438 return;
1439 }
1440
1441 if (row->type_widget != NULL)
1442 {
1443 gtk_widget_destroy (row->type_widget);
1444 row->type_widget = NULL;
1445 }
1446
1447 row_type[row->type].free_data (row);
1448 row->data = NULL;
1449
1450 row->type = type;
1451
1452 create_type_widgets (row);
1453
1454 caja_query_editor_changed (row->editor);
1455 }
1456
1457 static CajaQueryEditorRow *
caja_query_editor_add_row(CajaQueryEditor * editor,CajaQueryEditorRowType type)1458 caja_query_editor_add_row (CajaQueryEditor *editor,
1459 CajaQueryEditorRowType type)
1460 {
1461 GtkWidget *hbox, *button, *image, *combo;
1462 CajaQueryEditorRow *row;
1463 int i;
1464
1465 row = g_new0 (CajaQueryEditorRow, 1);
1466 row->editor = editor;
1467 row->type = type;
1468
1469 hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 6);
1470 row->hbox = hbox;
1471 gtk_widget_show (hbox);
1472 gtk_box_pack_start (GTK_BOX (editor->details->visible_vbox), hbox, FALSE, FALSE, 0);
1473
1474 combo = gtk_combo_box_text_new ();
1475 row->combo = combo;
1476 for (i = 0; i < CAJA_QUERY_EDITOR_ROW_LAST; i++)
1477 {
1478 gtk_combo_box_text_append_text (GTK_COMBO_BOX_TEXT (combo), gettext (row_type[i].name));
1479 }
1480 gtk_widget_show (combo);
1481 gtk_box_pack_start (GTK_BOX (hbox), combo, FALSE, FALSE, 0);
1482
1483 gtk_combo_box_set_active (GTK_COMBO_BOX (combo), row->type);
1484
1485 editor->details->rows = g_list_append (editor->details->rows, row);
1486
1487 g_signal_connect (combo, "changed",
1488 G_CALLBACK (row_type_combo_changed_cb), row);
1489
1490 create_type_widgets (row);
1491
1492 button = gtk_button_new ();
1493 image = gtk_image_new_from_icon_name ("remove",
1494 GTK_ICON_SIZE_SMALL_TOOLBAR);
1495 gtk_container_add (GTK_CONTAINER (button), image);
1496 gtk_widget_show (image);
1497 gtk_button_set_relief (GTK_BUTTON (button), GTK_RELIEF_NONE);
1498 gtk_widget_show (button);
1499
1500 g_signal_connect (button, "clicked",
1501 G_CALLBACK (remove_row_cb), row);
1502 gtk_widget_set_tooltip_text (button,
1503 _("Remove this criterion from the search"));
1504
1505 gtk_box_pack_end (GTK_BOX (hbox), button, FALSE, FALSE, 0);
1506
1507 return row;
1508 }
1509
1510 static void
go_search_cb(GtkButton * clicked_button,CajaQueryEditor * editor)1511 go_search_cb (GtkButton *clicked_button, CajaQueryEditor *editor)
1512 {
1513 caja_query_editor_changed_force (editor, TRUE);
1514 }
1515
1516 static void
add_new_row_cb(GtkButton * clicked_button,CajaQueryEditor * editor)1517 add_new_row_cb (GtkButton *clicked_button, CajaQueryEditor *editor)
1518 {
1519 caja_query_editor_add_row (editor, get_next_free_type (editor));
1520 caja_query_editor_changed (editor);
1521 }
1522
1523 static void
caja_query_editor_init(CajaQueryEditor * editor)1524 caja_query_editor_init (CajaQueryEditor *editor)
1525 {
1526 GtkWidget *hbox, *label, *button;
1527 char *label_markup;
1528
1529 editor->details = g_new0 (CajaQueryEditorDetails, 1);
1530 editor->details->is_visible = TRUE;
1531
1532 editor->details->invisible_vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 6);
1533 gtk_orientable_set_orientation (GTK_ORIENTABLE (editor), GTK_ORIENTATION_VERTICAL);
1534 gtk_box_pack_start (GTK_BOX (editor), editor->details->invisible_vbox,
1535 FALSE, FALSE, 0);
1536 editor->details->visible_vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 6);
1537 gtk_orientable_set_orientation (GTK_ORIENTABLE (editor), GTK_ORIENTATION_VERTICAL);
1538 gtk_box_pack_start (GTK_BOX (editor), editor->details->visible_vbox,
1539 FALSE, FALSE, 0);
1540 /* Only show visible vbox */
1541 gtk_widget_show (editor->details->visible_vbox);
1542
1543 /* Create invisible part: */
1544 hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 6);
1545 gtk_box_pack_start (GTK_BOX (editor->details->invisible_vbox),
1546 hbox, FALSE, FALSE, 0);
1547 gtk_widget_show (hbox);
1548
1549 label = gtk_label_new ("");
1550 label_markup = g_strconcat ("<b>", _("Search Folder"), "</b>", NULL);
1551 gtk_label_set_markup (GTK_LABEL (label), label_markup);
1552 g_free (label_markup);
1553 gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);
1554 gtk_widget_show (label);
1555
1556 button = gtk_button_new_with_label (_("Edit"));
1557 gtk_box_pack_end (GTK_BOX (hbox), button, FALSE, FALSE, 0);
1558 gtk_widget_show (button);
1559
1560 g_signal_connect (button, "clicked",
1561 G_CALLBACK (edit_clicked), editor);
1562
1563 gtk_widget_set_tooltip_text (button,
1564 _("Edit the saved search"));
1565 }
1566
1567 void
caja_query_editor_set_default_query(CajaQueryEditor * editor)1568 caja_query_editor_set_default_query (CajaQueryEditor *editor)
1569 {
1570 if (!editor->details->is_indexed)
1571 {
1572 caja_query_editor_add_row (editor, CAJA_QUERY_EDITOR_ROW_LOCATION);
1573 caja_query_editor_changed (editor);
1574 }
1575 }
1576
1577 static void
finish_first_line(CajaQueryEditor * editor,GtkWidget * hbox,gboolean use_go)1578 finish_first_line (CajaQueryEditor *editor, GtkWidget *hbox, gboolean use_go)
1579 {
1580 GtkWidget *button, *image;
1581
1582 button = gtk_button_new ();
1583 image = gtk_image_new_from_icon_name ("add",
1584 GTK_ICON_SIZE_SMALL_TOOLBAR);
1585 gtk_container_add (GTK_CONTAINER (button), image);
1586 gtk_widget_show (image);
1587 gtk_button_set_relief (GTK_BUTTON (button), GTK_RELIEF_NONE);
1588 gtk_widget_show (button);
1589
1590 g_signal_connect (button, "clicked",
1591 G_CALLBACK (add_new_row_cb), editor);
1592
1593 gtk_box_pack_end (GTK_BOX (hbox), button, FALSE, FALSE, 0);
1594
1595 gtk_widget_set_tooltip_text (button,
1596 _("Add a new criterion to this search"));
1597
1598 if (!editor->details->is_indexed)
1599 {
1600 if (use_go)
1601 {
1602 button = gtk_button_new_with_label (_("Go"));
1603 }
1604 else
1605 {
1606 button = gtk_button_new_with_label (_("Reload"));
1607 }
1608 gtk_widget_show (button);
1609
1610 gtk_widget_set_tooltip_text (button,
1611 _("Perform or update the search"));
1612
1613 g_signal_connect (button, "clicked",
1614 G_CALLBACK (go_search_cb), editor);
1615
1616 gtk_box_pack_end (GTK_BOX (hbox), button, FALSE, FALSE, 0);
1617 }
1618 }
1619
1620 static void
setup_internal_entry(CajaQueryEditor * editor)1621 setup_internal_entry (CajaQueryEditor *editor)
1622 {
1623 GtkWidget *hbox, *label;
1624 char *label_markup;
1625
1626 /* Create visible part: */
1627 hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 6);
1628 gtk_widget_show (hbox);
1629 gtk_box_pack_start (GTK_BOX (editor->details->visible_vbox), hbox, FALSE, FALSE, 0);
1630
1631 label = gtk_label_new ("");
1632 label_markup = g_strconcat ("<b>", _("_Search for:"), "</b>", NULL);
1633 gtk_label_set_markup_with_mnemonic (GTK_LABEL (label), label_markup);
1634 g_free (label_markup);
1635 gtk_widget_show (label);
1636 gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);
1637
1638 editor->details->entry = gtk_entry_new ();
1639 gtk_label_set_mnemonic_widget (GTK_LABEL (label), editor->details->entry);
1640 gtk_box_pack_start (GTK_BOX (hbox), editor->details->entry, TRUE, TRUE, 0);
1641
1642 g_signal_connect (editor->details->entry, "activate",
1643 G_CALLBACK (entry_activate_cb), editor);
1644 g_signal_connect (editor->details->entry, "changed",
1645 G_CALLBACK (entry_changed_cb), editor);
1646 gtk_widget_show (editor->details->entry);
1647
1648 finish_first_line (editor, hbox, TRUE);
1649 }
1650
1651 static void
setup_external_entry(CajaQueryEditor * editor,GtkWidget * entry)1652 setup_external_entry (CajaQueryEditor *editor, GtkWidget *entry)
1653 {
1654 GtkWidget *hbox, *label;
1655
1656 /* Create visible part: */
1657 hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 6);
1658 gtk_widget_show (hbox);
1659 gtk_box_pack_start (GTK_BOX (editor->details->visible_vbox), hbox, FALSE, FALSE, 0);
1660
1661 label = gtk_label_new (_("Search results"));
1662 gtk_widget_show (label);
1663 gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);
1664
1665 editor->details->entry = entry;
1666 g_signal_connect (editor->details->entry, "activate",
1667 G_CALLBACK (entry_activate_cb), editor);
1668 g_signal_connect (editor->details->entry, "changed",
1669 G_CALLBACK (entry_changed_cb), editor);
1670
1671 finish_first_line (editor, hbox, FALSE);
1672
1673 }
1674
1675 void
caja_query_editor_set_visible(CajaQueryEditor * editor,gboolean visible)1676 caja_query_editor_set_visible (CajaQueryEditor *editor,
1677 gboolean visible)
1678 {
1679 editor->details->is_visible = visible;
1680 if (visible)
1681 {
1682 gtk_widget_show (editor->details->visible_vbox);
1683 gtk_widget_hide (editor->details->invisible_vbox);
1684 }
1685 else
1686 {
1687 gtk_widget_hide (editor->details->visible_vbox);
1688 gtk_widget_show (editor->details->invisible_vbox);
1689 }
1690 }
1691
1692 static gboolean
query_is_valid(CajaQueryEditor * editor)1693 query_is_valid (CajaQueryEditor *editor)
1694 {
1695 const char *text;
1696
1697 text = gtk_entry_get_text (GTK_ENTRY (editor->details->entry));
1698
1699 return text != NULL && text[0] != '\0';
1700 }
1701
1702 static void
caja_query_editor_changed_force(CajaQueryEditor * editor,gboolean force_reload)1703 caja_query_editor_changed_force (CajaQueryEditor *editor, gboolean force_reload)
1704 {
1705 if (editor->details->change_frozen)
1706 {
1707 return;
1708 }
1709
1710 if (query_is_valid (editor))
1711 {
1712 CajaQuery *query;
1713
1714 query = caja_query_editor_get_query (editor);
1715 g_signal_emit (editor, signals[CHANGED], 0,
1716 query, editor->details->is_indexed || force_reload);
1717 g_object_unref (query);
1718 }
1719 }
1720
1721 static void
caja_query_editor_changed(CajaQueryEditor * editor)1722 caja_query_editor_changed (CajaQueryEditor *editor)
1723 {
1724 caja_query_editor_changed_force (editor, FALSE);
1725 }
1726
1727 void
caja_query_editor_grab_focus(CajaQueryEditor * editor)1728 caja_query_editor_grab_focus (CajaQueryEditor *editor)
1729 {
1730 if (editor->details->is_visible)
1731 {
1732 gtk_widget_grab_focus (editor->details->entry);
1733 }
1734 }
1735
1736 CajaQuery *
caja_query_editor_get_query(CajaQueryEditor * editor)1737 caja_query_editor_get_query (CajaQueryEditor *editor)
1738 {
1739 const char *query_text;
1740 CajaQuery *query;
1741 GList *l;
1742 CajaQueryEditorRow *row = NULL;
1743
1744 if (editor == NULL || editor->details == NULL || editor->details->entry == NULL)
1745 {
1746 return NULL;
1747 }
1748
1749 query_text = gtk_entry_get_text (GTK_ENTRY (editor->details->entry));
1750
1751 /* Empty string is a NULL query */
1752 if (query_text && query_text[0] == '\0')
1753 {
1754 return NULL;
1755 }
1756
1757 query = caja_query_new ();
1758 caja_query_set_text (query, query_text);
1759
1760 for (l = editor->details->rows; l != NULL; l = l->next)
1761 {
1762 row = l->data;
1763
1764 row_type[row->type].add_to_query (row, query);
1765 }
1766
1767 return query;
1768 }
1769
1770 void
caja_query_editor_clear_query(CajaQueryEditor * editor)1771 caja_query_editor_clear_query (CajaQueryEditor *editor)
1772 {
1773 editor->details->change_frozen = TRUE;
1774 gtk_entry_set_text (GTK_ENTRY (editor->details->entry), "");
1775
1776 g_free (editor->details->last_set_query_text);
1777 editor->details->last_set_query_text = g_strdup ("");
1778
1779 editor->details->change_frozen = FALSE;
1780 }
1781
1782 GtkWidget *
caja_query_editor_new(gboolean start_hidden,gboolean is_indexed)1783 caja_query_editor_new (gboolean start_hidden,
1784 gboolean is_indexed)
1785 {
1786 GtkWidget *editor;
1787
1788 editor = g_object_new (CAJA_TYPE_QUERY_EDITOR, NULL);
1789
1790 CAJA_QUERY_EDITOR (editor)->details->is_indexed = is_indexed;
1791
1792 caja_query_editor_set_visible (CAJA_QUERY_EDITOR (editor),
1793 !start_hidden);
1794
1795 setup_internal_entry (CAJA_QUERY_EDITOR (editor));
1796
1797 return editor;
1798 }
1799
1800 static void
detach_from_external_entry(CajaQueryEditor * editor)1801 detach_from_external_entry (CajaQueryEditor *editor)
1802 {
1803 if (editor->details->bar != NULL)
1804 {
1805 caja_search_bar_return_entry (editor->details->bar);
1806 g_signal_handlers_block_by_func (editor->details->entry,
1807 entry_activate_cb,
1808 editor);
1809 g_signal_handlers_block_by_func (editor->details->entry,
1810 entry_changed_cb,
1811 editor);
1812 }
1813 }
1814
1815 static void
attach_to_external_entry(CajaQueryEditor * editor)1816 attach_to_external_entry (CajaQueryEditor *editor)
1817 {
1818 if (editor->details->bar != NULL)
1819 {
1820 caja_search_bar_borrow_entry (editor->details->bar);
1821 g_signal_handlers_unblock_by_func (editor->details->entry,
1822 entry_activate_cb,
1823 editor);
1824 g_signal_handlers_unblock_by_func (editor->details->entry,
1825 entry_changed_cb,
1826 editor);
1827
1828 editor->details->change_frozen = TRUE;
1829 gtk_entry_set_text (GTK_ENTRY (editor->details->entry),
1830 editor->details->last_set_query_text);
1831 editor->details->change_frozen = FALSE;
1832 }
1833 }
1834
1835 GtkWidget*
caja_query_editor_new_with_bar(gboolean start_hidden,gboolean is_indexed,gboolean start_attached,CajaSearchBar * bar,CajaWindowSlot * slot)1836 caja_query_editor_new_with_bar (gboolean start_hidden,
1837 gboolean is_indexed,
1838 gboolean start_attached,
1839 CajaSearchBar *bar,
1840 CajaWindowSlot *slot)
1841 {
1842 GtkWidget *entry;
1843 CajaQueryEditor *editor;
1844
1845 editor = CAJA_QUERY_EDITOR (g_object_new (CAJA_TYPE_QUERY_EDITOR, NULL));
1846 editor->details->is_indexed = is_indexed;
1847
1848 caja_query_editor_set_visible (editor, !start_hidden);
1849
1850 editor->details->bar = bar;
1851 eel_add_weak_pointer (&editor->details->bar);
1852
1853 editor->details->slot = slot;
1854
1855 entry = caja_search_bar_borrow_entry (bar);
1856 setup_external_entry (editor, entry);
1857 if (!start_attached)
1858 {
1859 detach_from_external_entry (editor);
1860 }
1861
1862 g_signal_connect_object (slot, "active",
1863 G_CALLBACK (attach_to_external_entry),
1864 editor, G_CONNECT_SWAPPED);
1865 g_signal_connect_object (slot, "inactive",
1866 G_CALLBACK (detach_from_external_entry),
1867 editor, G_CONNECT_SWAPPED);
1868
1869 return GTK_WIDGET (editor);
1870 }
1871
1872 void
caja_query_editor_set_query(CajaQueryEditor * editor,CajaQuery * query)1873 caja_query_editor_set_query (CajaQueryEditor *editor, CajaQuery *query)
1874 {
1875 CajaQueryEditorRowType type;
1876 char *text;
1877
1878 if (!query)
1879 {
1880 caja_query_editor_clear_query (editor);
1881 return;
1882 }
1883
1884 text = caja_query_get_text (query);
1885
1886 if (!text)
1887 {
1888 text = g_strdup ("");
1889 }
1890
1891 editor->details->change_frozen = TRUE;
1892 gtk_entry_set_text (GTK_ENTRY (editor->details->entry), text);
1893
1894 for (type = 0; type < CAJA_QUERY_EDITOR_ROW_LAST; type++)
1895 {
1896 row_type[type].add_rows_from_query (editor, query);
1897 }
1898
1899 editor->details->change_frozen = FALSE;
1900
1901 g_free (editor->details->last_set_query_text);
1902 editor->details->last_set_query_text = text;
1903 }
1904