No issues found
1 /*
2 * e-shell-searchbar.c
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) version 3.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
13 *
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with the program; if not, see <http://www.gnu.org/licenses/>
16 *
17 *
18 * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
19 *
20 */
21
22 /**
23 * SECTION: e-shell-searchbar
24 * @short_description: quick search interface
25 * @include: shell/e-shell-searchbar.h
26 **/
27
28 #ifdef HAVE_CONFIG_H
29 #include <config.h>
30 #endif
31
32 #include "e-shell-searchbar.h"
33
34 #include <glib/gi18n-lib.h>
35 #include <libebackend/libebackend.h>
36
37 #include "e-util/e-util.h"
38 #include "widgets/misc/e-action-combo-box.h"
39
40 #include "e-shell-window-actions.h"
41
42 #define E_SHELL_SEARCHBAR_GET_PRIVATE(obj) \
43 (G_TYPE_INSTANCE_GET_PRIVATE \
44 ((obj), E_TYPE_SHELL_SEARCHBAR, EShellSearchbarPrivate))
45
46 #define SEARCH_OPTION_ADVANCED (-1)
47
48 /* Default "state key file" group: [Search Bar] */
49 #define STATE_GROUP_DEFAULT "Search Bar"
50
51 #define STATE_KEY_SEARCH_FILTER "SearchFilter"
52 #define STATE_KEY_SEARCH_OPTION "SearchOption"
53 #define STATE_KEY_SEARCH_SCOPE "SearchScope"
54 #define STATE_KEY_SEARCH_TEXT "SearchText"
55
56 struct _EShellSearchbarPrivate {
57
58 gpointer shell_view; /* weak pointer */
59
60 GtkRadioAction *search_option;
61 EFilterRule *search_rule;
62 GtkCssProvider *css_provider;
63
64 /* Child Widgets (not referenced) */
65 GtkWidget *filter_combo_box;
66 GtkWidget *search_entry;
67 GtkWidget *scope_combo_box;
68
69 /* State Key File */
70 gchar *state_group;
71
72 guint express_mode : 1;
73 guint filter_visible : 1;
74 guint labels_visible : 1;
75 guint search_visible : 1;
76 guint scope_visible : 1;
77 guint state_dirty : 1;
78 };
79
80 enum {
81 PROP_0,
82 PROP_EXPRESS_MODE,
83 PROP_FILTER_COMBO_BOX,
84 PROP_FILTER_VISIBLE,
85 PROP_LABELS_VISIBLE,
86 PROP_SEARCH_HINT,
87 PROP_SEARCH_OPTION,
88 PROP_SEARCH_TEXT,
89 PROP_SEARCH_VISIBLE,
90 PROP_SCOPE_COMBO_BOX,
91 PROP_SCOPE_VISIBLE,
92 PROP_SHELL_VIEW,
93 PROP_STATE_GROUP
94 };
95
96 G_DEFINE_TYPE_WITH_CODE (
97 EShellSearchbar,
98 e_shell_searchbar,
99 GTK_TYPE_BOX,
100 G_IMPLEMENT_INTERFACE (
101 E_TYPE_EXTENSIBLE, NULL))
102
103 static void
104 shell_searchbar_save_search_filter (EShellSearchbar *searchbar)
105 {
106 EShellView *shell_view;
107 EActionComboBox *action_combo_box;
108 GtkRadioAction *radio_action;
109 GKeyFile *key_file;
110 const gchar *action_name;
111 const gchar *state_group;
112 const gchar *key;
113
114 shell_view = e_shell_searchbar_get_shell_view (searchbar);
115 state_group = e_shell_searchbar_get_state_group (searchbar);
116 g_return_if_fail (state_group != NULL);
117
118 key = STATE_KEY_SEARCH_FILTER;
119 key_file = e_shell_view_get_state_key_file (shell_view);
120
121 action_combo_box = e_shell_searchbar_get_filter_combo_box (searchbar);
122 radio_action = e_action_combo_box_get_action (action_combo_box);
123
124 if (radio_action != NULL)
125 radio_action = e_radio_action_get_current_action (radio_action);
126
127 if (radio_action != NULL) {
128 action_name = gtk_action_get_name (GTK_ACTION (radio_action));
129 g_key_file_set_string (key_file, state_group, key, action_name);
130 } else
131 g_key_file_remove_key (key_file, state_group, key, NULL);
132
133 e_shell_view_set_state_dirty (shell_view);
134 }
135
136 static void
137 shell_searchbar_save_search_option (EShellSearchbar *searchbar)
138 {
139 EShellView *shell_view;
140 GtkRadioAction *radio_action;
141 GKeyFile *key_file;
142 const gchar *action_name;
143 const gchar *state_group;
144 const gchar *key;
145
146 shell_view = e_shell_searchbar_get_shell_view (searchbar);
147 state_group = e_shell_searchbar_get_state_group (searchbar);
148 g_return_if_fail (state_group != NULL);
149
150 key = STATE_KEY_SEARCH_OPTION;
151 key_file = e_shell_view_get_state_key_file (shell_view);
152
153 radio_action = e_shell_searchbar_get_search_option (searchbar);
154
155 if (radio_action != NULL)
156 radio_action = e_radio_action_get_current_action (radio_action);
157
158 if (radio_action != NULL) {
159 action_name = gtk_action_get_name (GTK_ACTION (radio_action));
160 g_key_file_set_string (key_file, state_group, key, action_name);
161 } else
162 g_key_file_remove_key (key_file, state_group, key, NULL);
163
164 e_shell_view_set_state_dirty (shell_view);
165 }
166
167 static void
168 shell_searchbar_save_search_text (EShellSearchbar *searchbar)
169 {
170 EShellView *shell_view;
171 GKeyFile *key_file;
172 const gchar *search_text;
173 const gchar *state_group;
174 const gchar *key;
175
176 shell_view = e_shell_searchbar_get_shell_view (searchbar);
177 state_group = e_shell_searchbar_get_state_group (searchbar);
178 g_return_if_fail (state_group != NULL);
179
180 key = STATE_KEY_SEARCH_TEXT;
181 key_file = e_shell_view_get_state_key_file (shell_view);
182
183 search_text = e_shell_searchbar_get_search_text (searchbar);
184
185 if (search_text != NULL && *search_text != '\0')
186 g_key_file_set_string (key_file, state_group, key, search_text);
187 else
188 g_key_file_remove_key (key_file, state_group, key, NULL);
189
190 e_shell_view_set_state_dirty (shell_view);
191 }
192
193 static void
194 shell_searchbar_save_search_scope (EShellSearchbar *searchbar)
195 {
196 EShellView *shell_view;
197 EActionComboBox *action_combo_box;
198 GtkRadioAction *radio_action;
199 GKeyFile *key_file;
200 const gchar *action_name;
201 const gchar *state_group;
202 const gchar *key;
203
204 shell_view = e_shell_searchbar_get_shell_view (searchbar);
205
206 /* Search scope is hard-coded to the default state group. */
207 state_group = STATE_GROUP_DEFAULT;
208
209 key = STATE_KEY_SEARCH_SCOPE;
210 key_file = e_shell_view_get_state_key_file (shell_view);
211
212 action_combo_box = e_shell_searchbar_get_scope_combo_box (searchbar);
213 radio_action = e_action_combo_box_get_action (action_combo_box);
214
215 if (radio_action != NULL)
216 radio_action = e_radio_action_get_current_action (radio_action);
217
218 if (radio_action != NULL) {
219 action_name = gtk_action_get_name (GTK_ACTION (radio_action));
220 g_key_file_set_string (key_file, state_group, key, action_name);
221 } else
222 g_key_file_remove_key (key_file, state_group, key, NULL);
223
224 e_shell_view_set_state_dirty (shell_view);
225 }
226
227 static void
228 shell_searchbar_update_search_widgets (EShellSearchbar *searchbar)
229 {
230 EShellView *shell_view;
231 EShellWindow *shell_window;
232 GtkAction *action;
233 GtkWidget *widget;
234 const gchar *search_text;
235 gboolean sensitive;
236
237 /* EShellView subclasses are responsible for actually
238 * executing the search. This is all cosmetic stuff. */
239
240 widget = searchbar->priv->search_entry;
241 shell_view = e_shell_searchbar_get_shell_view (searchbar);
242 shell_window = e_shell_view_get_shell_window (shell_view);
243 search_text = e_shell_searchbar_get_search_text (searchbar);
244
245 sensitive =
246 (search_text != NULL && *search_text != '\0') ||
247 (e_shell_view_get_search_rule (shell_view) != NULL);
248
249 if (sensitive) {
250 GtkStyleContext *style;
251 GdkRGBA bg, fg;
252 gchar *css;
253
254 style = gtk_widget_get_style_context (widget);
255 gtk_style_context_get_background_color (style, GTK_STATE_FLAG_SELECTED, &bg);
256 gtk_style_context_get_color (style, GTK_STATE_FLAG_SELECTED, &fg);
257
258 css = g_strdup_printf ("GtkEntry#searchbar_searchentry_active { "
259 " background:none; "
260 " background-color:#%06x; "
261 " color:#%06x; "
262 "}",
263 e_rgba_to_value (&bg),
264 e_rgba_to_value (&fg));
265 gtk_css_provider_load_from_data (searchbar->priv->css_provider, css, -1, NULL);
266 g_free (css);
267
268 gtk_widget_set_name (widget, "searchbar_searchentry_active");
269 } else {
270 gtk_widget_set_name (widget, "searchbar_searchentry");
271 }
272
273 action = E_SHELL_WINDOW_ACTION_SEARCH_CLEAR (shell_window);
274 gtk_action_set_sensitive (action, sensitive);
275
276 action = E_SHELL_WINDOW_ACTION_SEARCH_SAVE (shell_window);
277 gtk_action_set_sensitive (action, sensitive);
278 }
279
280 static void
281 shell_searchbar_clear_search_cb (EShellView *shell_view,
282 EShellSearchbar *searchbar)
283 {
284 GtkRadioAction *search_option;
285 gint current_value;
286
287 e_shell_searchbar_set_search_text (searchbar, NULL);
288
289 search_option = e_shell_searchbar_get_search_option (searchbar);
290 if (search_option == NULL)
291 return;
292
293 /* Reset the search option if it's set to advanced search. */
294 current_value = gtk_radio_action_get_current_value (search_option);
295 if (current_value == SEARCH_OPTION_ADVANCED)
296 gtk_radio_action_set_current_value (search_option, 0);
297 }
298
299 static void
300 shell_searchbar_custom_search_cb (EShellView *shell_view,
301 EFilterRule *custom_rule,
302 EShellSearchbar *searchbar)
303 {
304 GtkRadioAction *search_option;
305 gint value = SEARCH_OPTION_ADVANCED;
306
307 e_shell_searchbar_set_search_text (searchbar, NULL);
308
309 search_option = e_shell_searchbar_get_search_option (searchbar);
310 if (search_option != NULL)
311 gtk_radio_action_set_current_value (search_option, value);
312 }
313
314 static void
315 shell_searchbar_execute_search_cb (EShellView *shell_view,
316 EShellSearchbar *searchbar)
317 {
318 EShellContent *shell_content;
319
320 shell_searchbar_update_search_widgets (searchbar);
321
322 e_shell_searchbar_save_state (searchbar);
323
324 if (!e_shell_view_is_active (shell_view))
325 return;
326
327 /* Direct the focus away from the search entry, so that a
328 * focus-in event is required before the text can be changed.
329 * This will reset the entry to the appropriate visual state. */
330 if (gtk_widget_is_focus (searchbar->priv->search_entry)) {
331 shell_content = e_shell_view_get_shell_content (shell_view);
332 e_shell_content_focus_search_results (shell_content);
333 }
334 }
335
336 static void
337 shell_searchbar_entry_activate_cb (EShellSearchbar *searchbar)
338 {
339 EShellView *shell_view;
340 EShellWindow *shell_window;
341 GtkAction *action;
342 const gchar *search_text;
343
344 shell_view = e_shell_searchbar_get_shell_view (searchbar);
345 shell_window = e_shell_view_get_shell_window (shell_view);
346
347 search_text = e_shell_searchbar_get_search_text (searchbar);
348 if (search_text != NULL && *search_text != '\0')
349 action = E_SHELL_WINDOW_ACTION_SEARCH_QUICK (shell_window);
350 else
351 action = E_SHELL_WINDOW_ACTION_SEARCH_CLEAR (shell_window);
352
353 gtk_action_activate (action);
354 }
355
356 static void
357 shell_searchbar_entry_changed_cb (EShellSearchbar *searchbar)
358 {
359 EShellView *shell_view;
360 EShellWindow *shell_window;
361 GtkAction *action;
362 const gchar *search_text;
363 gboolean sensitive;
364
365 shell_view = e_shell_searchbar_get_shell_view (searchbar);
366 shell_window = e_shell_view_get_shell_window (shell_view);
367
368 search_text = e_shell_searchbar_get_search_text (searchbar);
369 sensitive = (search_text != NULL && *search_text != '\0');
370
371 action = E_SHELL_WINDOW_ACTION_SEARCH_QUICK (shell_window);
372 gtk_action_set_sensitive (action, sensitive);
373 }
374
375 static void
376 shell_searchbar_entry_icon_press_cb (EShellSearchbar *searchbar,
377 GtkEntryIconPosition icon_pos,
378 GdkEvent *event)
379 {
380 EShellView *shell_view;
381 EShellWindow *shell_window;
382 GtkAction *action;
383
384 /* Show the search options menu when the icon is pressed. */
385
386 if (icon_pos != GTK_ENTRY_ICON_PRIMARY)
387 return;
388
389 shell_view = e_shell_searchbar_get_shell_view (searchbar);
390 shell_window = e_shell_view_get_shell_window (shell_view);
391
392 action = E_SHELL_WINDOW_ACTION_SEARCH_OPTIONS (shell_window);
393 gtk_action_activate (action);
394 }
395
396 static void
397 shell_searchbar_entry_icon_release_cb (EShellSearchbar *searchbar,
398 GtkEntryIconPosition icon_pos,
399 GdkEvent *event)
400 {
401 EShellView *shell_view;
402 EShellWindow *shell_window;
403 GtkAction *action;
404
405 /* Clear the search when the icon is pressed and released. */
406
407 if (icon_pos != GTK_ENTRY_ICON_SECONDARY)
408 return;
409
410 shell_view = e_shell_searchbar_get_shell_view (searchbar);
411 shell_window = e_shell_view_get_shell_window (shell_view);
412
413 action = E_SHELL_WINDOW_ACTION_SEARCH_CLEAR (shell_window);
414 gtk_action_activate (action);
415 }
416
417 static gboolean
418 shell_searchbar_entry_key_press_cb (EShellSearchbar *searchbar,
419 GdkEventKey *key_event,
420 GtkWindow *entry)
421 {
422 EShellView *shell_view;
423 EShellWindow *shell_window;
424 GtkAction *action;
425 guint mask;
426
427 mask = gtk_accelerator_get_default_mod_mask ();
428 if ((key_event->state & mask) != GDK_MOD1_MASK)
429 return FALSE;
430
431 if (key_event->keyval != GDK_KEY_Down)
432 return FALSE;
433
434 shell_view = e_shell_searchbar_get_shell_view (searchbar);
435 shell_window = e_shell_view_get_shell_window (shell_view);
436
437 action = E_SHELL_WINDOW_ACTION_SEARCH_OPTIONS (shell_window);
438 gtk_action_activate (action);
439
440 return TRUE;
441 }
442
443 static void
444 shell_searchbar_option_changed_cb (GtkRadioAction *action,
445 GtkRadioAction *current,
446 EShellSearchbar *searchbar)
447 {
448 EShellView *shell_view;
449 const gchar *search_text;
450 const gchar *label;
451 gint current_value;
452
453 shell_view = e_shell_searchbar_get_shell_view (searchbar);
454
455 label = gtk_action_get_label (GTK_ACTION (current));
456 e_shell_searchbar_set_search_hint (searchbar, label);
457
458 current_value = gtk_radio_action_get_current_value (current);
459 search_text = e_shell_searchbar_get_search_text (searchbar);
460
461 if (current_value != SEARCH_OPTION_ADVANCED) {
462 e_shell_view_set_search_rule (shell_view, NULL);
463 e_shell_searchbar_set_search_text (searchbar, search_text);
464 if (search_text != NULL && *search_text != '\0')
465 e_shell_view_execute_search (shell_view);
466 else {
467 shell_searchbar_save_search_option (searchbar);
468 gtk_widget_grab_focus (searchbar->priv->search_entry);
469 }
470
471 } else if (search_text != NULL)
472 e_shell_searchbar_set_search_text (searchbar, NULL);
473 }
474
475 static gboolean
476 shell_searchbar_entry_focus_in_cb (GtkWidget *entry,
477 GdkEvent *event,
478 EShellSearchbar *searchbar)
479 {
480 /* to not change background when user changes search entry content */
481 gtk_widget_set_name (entry, "searchbar_searchentry");
482
483 return FALSE;
484 }
485
486 static gboolean
487 shell_searchbar_entry_focus_out_cb (GtkWidget *entry,
488 GdkEvent *event,
489 EShellSearchbar *searchbar)
490 {
491 shell_searchbar_update_search_widgets (searchbar);
492
493 return FALSE;
494 }
495
496 static void
497 shell_searchbar_set_shell_view (EShellSearchbar *searchbar,
498 EShellView *shell_view)
499 {
500 g_return_if_fail (searchbar->priv->shell_view == NULL);
501
502 searchbar->priv->shell_view = shell_view;
503
504 g_object_add_weak_pointer (
505 G_OBJECT (shell_view),
506 &searchbar->priv->shell_view);
507 }
508
509 static void
510 shell_searchbar_set_property (GObject *object,
511 guint property_id,
512 const GValue *value,
513 GParamSpec *pspec)
514 {
515 switch (property_id) {
516 case PROP_EXPRESS_MODE:
517 e_shell_searchbar_set_express_mode (
518 E_SHELL_SEARCHBAR (object),
519 g_value_get_boolean (value));
520 return;
521
522 case PROP_FILTER_VISIBLE:
523 e_shell_searchbar_set_filter_visible (
524 E_SHELL_SEARCHBAR (object),
525 g_value_get_boolean (value));
526 return;
527
528 case PROP_LABELS_VISIBLE:
529 e_shell_searchbar_set_labels_visible (
530 E_SHELL_SEARCHBAR (object),
531 g_value_get_boolean (value));
532 return;
533
534 case PROP_SEARCH_HINT:
535 e_shell_searchbar_set_search_hint (
536 E_SHELL_SEARCHBAR (object),
537 g_value_get_string (value));
538 return;
539
540 case PROP_SEARCH_OPTION:
541 e_shell_searchbar_set_search_option (
542 E_SHELL_SEARCHBAR (object),
543 g_value_get_object (value));
544 return;
545
546 case PROP_SEARCH_TEXT:
547 e_shell_searchbar_set_search_text (
548 E_SHELL_SEARCHBAR (object),
549 g_value_get_string (value));
550 return;
551
552 case PROP_SEARCH_VISIBLE:
553 e_shell_searchbar_set_search_visible (
554 E_SHELL_SEARCHBAR (object),
555 g_value_get_boolean (value));
556 return;
557
558 case PROP_SCOPE_VISIBLE:
559 e_shell_searchbar_set_scope_visible (
560 E_SHELL_SEARCHBAR (object),
561 g_value_get_boolean (value));
562 return;
563
564 case PROP_SHELL_VIEW:
565 shell_searchbar_set_shell_view (
566 E_SHELL_SEARCHBAR (object),
567 g_value_get_object (value));
568 return;
569
570 case PROP_STATE_GROUP:
571 e_shell_searchbar_set_state_group (
572 E_SHELL_SEARCHBAR (object),
573 g_value_get_string (value));
574 return;
575 }
576
577 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
578 }
579
580 static void
581 shell_searchbar_get_property (GObject *object,
582 guint property_id,
583 GValue *value,
584 GParamSpec *pspec)
585 {
586 switch (property_id) {
587 case PROP_EXPRESS_MODE:
588 g_value_set_boolean (
589 value, e_shell_searchbar_get_express_mode (
590 E_SHELL_SEARCHBAR (object)));
591 return;
592
593 case PROP_FILTER_COMBO_BOX:
594 g_value_set_object (
595 value, e_shell_searchbar_get_filter_combo_box (
596 E_SHELL_SEARCHBAR (object)));
597 return;
598
599 case PROP_LABELS_VISIBLE:
600 g_value_set_boolean (
601 value, e_shell_searchbar_get_labels_visible (
602 E_SHELL_SEARCHBAR (object)));
603 return;
604
605 case PROP_FILTER_VISIBLE:
606 g_value_set_boolean (
607 value, e_shell_searchbar_get_filter_visible (
608 E_SHELL_SEARCHBAR (object)));
609 return;
610
611 case PROP_SEARCH_HINT:
612 g_value_set_string (
613 value, e_shell_searchbar_get_search_hint (
614 E_SHELL_SEARCHBAR (object)));
615 return;
616
617 case PROP_SEARCH_OPTION:
618 g_value_set_object (
619 value, e_shell_searchbar_get_search_option (
620 E_SHELL_SEARCHBAR (object)));
621 return;
622
623 case PROP_SEARCH_TEXT:
624 g_value_set_string (
625 value, e_shell_searchbar_get_search_text (
626 E_SHELL_SEARCHBAR (object)));
627 return;
628
629 case PROP_SEARCH_VISIBLE:
630 g_value_set_boolean (
631 value, e_shell_searchbar_get_search_visible (
632 E_SHELL_SEARCHBAR (object)));
633 return;
634
635 case PROP_SCOPE_COMBO_BOX:
636 g_value_set_object (
637 value, e_shell_searchbar_get_scope_combo_box (
638 E_SHELL_SEARCHBAR (object)));
639 return;
640
641 case PROP_SCOPE_VISIBLE:
642 g_value_set_boolean (
643 value, e_shell_searchbar_get_scope_visible (
644 E_SHELL_SEARCHBAR (object)));
645 return;
646
647 case PROP_SHELL_VIEW:
648 g_value_set_object (
649 value, e_shell_searchbar_get_shell_view (
650 E_SHELL_SEARCHBAR (object)));
651 return;
652
653 case PROP_STATE_GROUP:
654 g_value_set_string (
655 value, e_shell_searchbar_get_state_group (
656 E_SHELL_SEARCHBAR (object)));
657 return;
658 }
659
660 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
661 }
662
663 static void
664 shell_searchbar_dispose (GObject *object)
665 {
666 EShellSearchbarPrivate *priv;
667
668 priv = E_SHELL_SEARCHBAR_GET_PRIVATE (object);
669
670 if (priv->shell_view != NULL) {
671 g_object_remove_weak_pointer (
672 G_OBJECT (priv->shell_view), &priv->shell_view);
673 priv->shell_view = NULL;
674 }
675
676 if (priv->search_option != NULL) {
677 g_signal_handlers_disconnect_matched (
678 priv->search_option, G_SIGNAL_MATCH_DATA,
679 0, 0, NULL, NULL, object);
680 g_object_unref (priv->search_option);
681 priv->search_option = NULL;
682 }
683
684 if (priv->state_group) {
685 g_free (priv->state_group);
686 priv->state_group = NULL;
687 }
688
689 if (priv->css_provider) {
690 g_object_unref (priv->css_provider);
691 priv->css_provider = NULL;
692 }
693
694 /* Chain up to parent's dispose() method. */
695 G_OBJECT_CLASS (e_shell_searchbar_parent_class)->dispose (object);
696 }
697
698 static void
699 shell_searchbar_constructed (GObject *object)
700 {
701 EShellView *shell_view;
702 EShellWindow *shell_window;
703 EShellSearchbar *searchbar;
704 GtkSizeGroup *size_group;
705 GtkAction *action;
706 GtkWidget *widget;
707
708 searchbar = E_SHELL_SEARCHBAR (object);
709 shell_view = e_shell_searchbar_get_shell_view (searchbar);
710 shell_window = e_shell_view_get_shell_window (shell_view);
711 size_group = e_shell_view_get_size_group (shell_view);
712
713 g_signal_connect (
714 shell_view, "clear-search",
715 G_CALLBACK (shell_searchbar_clear_search_cb), searchbar);
716
717 g_signal_connect (
718 shell_view, "custom-search",
719 G_CALLBACK (shell_searchbar_custom_search_cb), searchbar);
720
721 g_signal_connect_after (
722 shell_view, "execute-search",
723 G_CALLBACK (shell_searchbar_execute_search_cb), searchbar);
724
725 widget = searchbar->priv->filter_combo_box;
726
727 g_signal_connect_swapped (
728 widget, "changed",
729 G_CALLBACK (e_shell_searchbar_set_state_dirty), searchbar);
730
731 /* Use G_CONNECT_AFTER here so the EActionComboBox has a
732 * chance to update its radio actions before we go sifting
733 * through the radio group for the current action. */
734 g_signal_connect_data (
735 widget, "changed",
736 G_CALLBACK (e_shell_view_execute_search),
737 shell_view, (GClosureNotify) NULL,
738 G_CONNECT_AFTER | G_CONNECT_SWAPPED);
739
740 searchbar->priv->css_provider = gtk_css_provider_new ();
741 widget = searchbar->priv->search_entry;
742 gtk_style_context_add_provider (gtk_widget_get_style_context (widget),
743 GTK_STYLE_PROVIDER (searchbar->priv->css_provider), GTK_STYLE_PROVIDER_PRIORITY_APPLICATION);
744
745 action = E_SHELL_WINDOW_ACTION_SEARCH_CLEAR (shell_window);
746
747 g_object_bind_property (
748 action, "sensitive",
749 widget, "secondary-icon-sensitive",
750 G_BINDING_SYNC_CREATE);
751 g_object_bind_property (
752 action, "stock-id",
753 widget, "secondary-icon-stock",
754 G_BINDING_SYNC_CREATE);
755 g_object_bind_property (
756 action, "tooltip",
757 widget, "secondary-icon-tooltip-text",
758 G_BINDING_SYNC_CREATE);
759
760 action = E_SHELL_WINDOW_ACTION_SEARCH_OPTIONS (shell_window);
761
762 g_object_bind_property (
763 action, "sensitive",
764 widget, "primary-icon-sensitive",
765 G_BINDING_SYNC_CREATE);
766 g_object_bind_property (
767 action, "stock-id",
768 widget, "primary-icon-stock",
769 G_BINDING_SYNC_CREATE);
770 g_object_bind_property (
771 action, "tooltip",
772 widget, "primary-icon-tooltip-text",
773 G_BINDING_SYNC_CREATE);
774
775 widget = GTK_WIDGET (searchbar);
776 gtk_size_group_add_widget (size_group, widget);
777
778 e_extensible_load_extensions (E_EXTENSIBLE (object));
779
780 /* Chain up to parent's constructed() method. */
781 G_OBJECT_CLASS (e_shell_searchbar_parent_class)->constructed (object);
782 }
783
784 static void
785 shell_searchbar_map (GtkWidget *widget)
786 {
787 /* Chain up to parent's map() method. */
788 GTK_WIDGET_CLASS (e_shell_searchbar_parent_class)->map (widget);
789
790 /* Load state after constructed() so we don't derail
791 * subclass initialization. We wait until map() so we
792 * have usable style colors for the entry box. */
793 e_shell_searchbar_load_state (E_SHELL_SEARCHBAR (widget));
794 }
795
796 static void
797 e_shell_searchbar_class_init (EShellSearchbarClass *class)
798 {
799 GObjectClass *object_class;
800 GtkWidgetClass *widget_class;
801
802 g_type_class_add_private (class, sizeof (EShellSearchbarPrivate));
803
804 object_class = G_OBJECT_CLASS (class);
805 object_class->set_property = shell_searchbar_set_property;
806 object_class->get_property = shell_searchbar_get_property;
807 object_class->dispose = shell_searchbar_dispose;
808 object_class->constructed = shell_searchbar_constructed;
809
810 widget_class = GTK_WIDGET_CLASS (class);
811 widget_class->map = shell_searchbar_map;
812
813 g_object_class_install_property (
814 object_class,
815 PROP_EXPRESS_MODE,
816 g_param_spec_boolean (
817 "express-mode",
818 NULL,
819 NULL,
820 FALSE,
821 G_PARAM_READWRITE |
822 G_PARAM_CONSTRUCT));
823
824 g_object_class_install_property (
825 object_class,
826 PROP_FILTER_COMBO_BOX,
827 g_param_spec_object (
828 "filter-combo-box",
829 NULL,
830 NULL,
831 E_TYPE_ACTION_COMBO_BOX,
832 G_PARAM_READABLE));
833
834 g_object_class_install_property (
835 object_class,
836 PROP_LABELS_VISIBLE,
837 g_param_spec_boolean (
838 "labels-visible",
839 NULL,
840 NULL,
841 TRUE,
842 G_PARAM_READWRITE |
843 G_PARAM_CONSTRUCT));
844
845 g_object_class_install_property (
846 object_class,
847 PROP_FILTER_VISIBLE,
848 g_param_spec_boolean (
849 "filter-visible",
850 NULL,
851 NULL,
852 TRUE,
853 G_PARAM_READWRITE |
854 G_PARAM_CONSTRUCT));
855
856 g_object_class_install_property (
857 object_class,
858 PROP_SEARCH_HINT,
859 g_param_spec_string (
860 "search-hint",
861 NULL,
862 NULL,
863 NULL,
864 G_PARAM_READWRITE));
865
866 g_object_class_install_property (
867 object_class,
868 PROP_SEARCH_OPTION,
869 g_param_spec_object (
870 "search-option",
871 NULL,
872 NULL,
873 GTK_TYPE_RADIO_ACTION,
874 G_PARAM_READWRITE));
875
876 g_object_class_install_property (
877 object_class,
878 PROP_SEARCH_TEXT,
879 g_param_spec_string (
880 "search-text",
881 NULL,
882 NULL,
883 NULL,
884 G_PARAM_READWRITE));
885
886 g_object_class_install_property (
887 object_class,
888 PROP_SEARCH_VISIBLE,
889 g_param_spec_boolean (
890 "search-visible",
891 NULL,
892 NULL,
893 TRUE,
894 G_PARAM_READWRITE |
895 G_PARAM_CONSTRUCT));
896
897 g_object_class_install_property (
898 object_class,
899 PROP_SCOPE_COMBO_BOX,
900 g_param_spec_object (
901 "scope-combo-box",
902 NULL,
903 NULL,
904 E_TYPE_ACTION_COMBO_BOX,
905 G_PARAM_READABLE));
906
907 g_object_class_install_property (
908 object_class,
909 PROP_SCOPE_VISIBLE,
910 g_param_spec_boolean (
911 "scope-visible",
912 NULL,
913 NULL,
914 FALSE,
915 G_PARAM_READWRITE |
916 G_PARAM_CONSTRUCT));
917
918 /**
919 * EShellSearchbar:shell-view
920 *
921 * The #EShellView to which the searchbar widget belongs.
922 **/
923 g_object_class_install_property (
924 object_class,
925 PROP_SHELL_VIEW,
926 g_param_spec_object (
927 "shell-view",
928 NULL,
929 NULL,
930 E_TYPE_SHELL_VIEW,
931 G_PARAM_READWRITE |
932 G_PARAM_CONSTRUCT_ONLY));
933
934 /**
935 * EShellSearchbar:state-group
936 *
937 * Key file group name to read and write search bar state.
938 **/
939 g_object_class_install_property (
940 object_class,
941 PROP_STATE_GROUP,
942 g_param_spec_string (
943 "state-group",
944 NULL,
945 NULL,
946 STATE_GROUP_DEFAULT,
947 G_PARAM_READWRITE |
948 G_PARAM_CONSTRUCT));
949 }
950
951 static void
952 e_shell_searchbar_init (EShellSearchbar *searchbar)
953 {
954 GtkBox *box;
955 GtkLabel *label;
956 GtkWidget *widget;
957
958 searchbar->priv = E_SHELL_SEARCHBAR_GET_PRIVATE (searchbar);
959
960 gtk_box_set_spacing (GTK_BOX (searchbar), 24);
961
962 /* Filter Combo Widgets */
963
964 box = GTK_BOX (searchbar);
965
966 widget = gtk_hbox_new (FALSE, 3);
967 gtk_box_pack_start (box, widget, FALSE, FALSE, 0);
968
969 g_object_bind_property (
970 searchbar, "filter-visible",
971 widget, "visible",
972 G_BINDING_SYNC_CREATE);
973
974 box = GTK_BOX (widget);
975
976 /* Translators: The "Show:" label precedes a combo box that
977 * allows the user to filter the current view. Examples of
978 * items that appear in the combo box are "Unread Messages",
979 * "Important Messages", or "Active Appointments". */
980 widget = gtk_label_new_with_mnemonic (_("Sho_w:"));
981 gtk_box_pack_start (box, widget, FALSE, FALSE, 0);
982 gtk_widget_show (widget);
983
984 g_object_bind_property (
985 searchbar, "labels-visible",
986 widget, "visible",
987 G_BINDING_SYNC_CREATE);
988
989 label = GTK_LABEL (widget);
990
991 widget = e_action_combo_box_new ();
992 gtk_label_set_mnemonic_widget (label, widget);
993 gtk_box_pack_start (box, widget, FALSE, FALSE, 0);
994 searchbar->priv->filter_combo_box = widget;
995 gtk_widget_show (widget);
996
997 /* Search Entry Widgets */
998
999 box = GTK_BOX (searchbar);
1000
1001 widget = gtk_hbox_new (FALSE, 3);
1002 gtk_box_pack_start (box, widget, TRUE, TRUE, 0);
1003
1004 g_object_bind_property (
1005 searchbar, "search-visible",
1006 widget, "visible",
1007 G_BINDING_SYNC_CREATE);
1008
1009 box = GTK_BOX (widget);
1010
1011 /* Translators: This is part of the quick search interface.
1012 * example: Search: [_______________] in [ Current Folder ] */
1013 widget = gtk_label_new_with_mnemonic (_("Sear_ch:"));
1014 gtk_box_pack_start (box, widget, FALSE, FALSE, 0);
1015 gtk_widget_show (widget);
1016
1017 g_object_bind_property (
1018 searchbar, "labels-visible",
1019 widget, "visible",
1020 G_BINDING_SYNC_CREATE);
1021
1022 label = GTK_LABEL (widget);
1023
1024 widget = gtk_entry_new ();
1025 gtk_label_set_mnemonic_widget (label, widget);
1026 gtk_box_pack_start (box, widget, TRUE, TRUE, 0);
1027 searchbar->priv->search_entry = widget;
1028 gtk_widget_show (widget);
1029
1030 g_signal_connect_swapped (
1031 widget, "activate",
1032 G_CALLBACK (shell_searchbar_entry_activate_cb),
1033 searchbar);
1034
1035 g_signal_connect_swapped (
1036 widget, "changed",
1037 G_CALLBACK (shell_searchbar_entry_changed_cb),
1038 searchbar);
1039
1040 g_signal_connect_swapped (
1041 widget, "changed",
1042 G_CALLBACK (e_shell_searchbar_set_state_dirty),
1043 searchbar);
1044
1045 g_signal_connect_swapped (
1046 widget, "icon-press",
1047 G_CALLBACK (shell_searchbar_entry_icon_press_cb),
1048 searchbar);
1049
1050 g_signal_connect_swapped (
1051 widget, "icon-release",
1052 G_CALLBACK (shell_searchbar_entry_icon_release_cb),
1053 searchbar);
1054
1055 g_signal_connect_swapped (
1056 widget, "key-press-event",
1057 G_CALLBACK (shell_searchbar_entry_key_press_cb),
1058 searchbar);
1059
1060 g_signal_connect (
1061 widget, "focus-in-event",
1062 G_CALLBACK (shell_searchbar_entry_focus_in_cb),
1063 searchbar);
1064
1065 g_signal_connect (
1066 widget, "focus-out-event",
1067 G_CALLBACK (shell_searchbar_entry_focus_out_cb),
1068 searchbar);
1069
1070 /* Scope Combo Widgets */
1071
1072 box = GTK_BOX (searchbar);
1073
1074 widget = gtk_hbox_new (FALSE, 3);
1075 gtk_box_pack_start (box, widget, FALSE, FALSE, 0);
1076
1077 g_object_bind_property (
1078 searchbar, "scope-visible",
1079 widget, "visible",
1080 G_BINDING_SYNC_CREATE);
1081
1082 box = GTK_BOX (widget);
1083
1084 /* Translators: This is part of the quick search interface.
1085 * example: Search: [_______________] in [ Current Folder ] */
1086 widget = gtk_label_new_with_mnemonic (_("i_n"));
1087 gtk_box_pack_start (box, widget, FALSE, FALSE, 0);
1088 gtk_widget_show (widget);
1089
1090 label = GTK_LABEL (widget);
1091
1092 widget = e_action_combo_box_new ();
1093 gtk_label_set_mnemonic_widget (label, widget);
1094 gtk_box_pack_start (box, widget, FALSE, FALSE, 0);
1095 searchbar->priv->scope_combo_box = widget;
1096 gtk_widget_show (widget);
1097
1098 /* Use G_CONNECT_AFTER here so the EActionComboBox has a
1099 * chance to update its radio actions before we go sifting
1100 * through the radio group for the current action. */
1101 g_signal_connect_data (
1102 widget, "changed",
1103 G_CALLBACK (shell_searchbar_save_search_scope),
1104 searchbar, (GClosureNotify) NULL,
1105 G_CONNECT_AFTER | G_CONNECT_SWAPPED);
1106 }
1107
1108 /**
1109 * e_shell_searchbar_new:
1110 * @shell_view: an #EShellView
1111 *
1112 * Creates a new #EShellSearchbar instance.
1113 *
1114 * Returns: a new #EShellSearchbar instance
1115 **/
1116 GtkWidget *
1117 e_shell_searchbar_new (EShellView *shell_view)
1118 {
1119 g_return_val_if_fail (E_IS_SHELL_VIEW (shell_view), NULL);
1120
1121 return g_object_new (
1122 E_TYPE_SHELL_SEARCHBAR, "shell-view", shell_view, NULL);
1123 }
1124
1125 /**
1126 * e_shell_searchbar_get_shell_view:
1127 * @searchbar: an #EShellSearchbar
1128 *
1129 * Returns the #EShellView that was passed to e_shell_searchbar_new().
1130 *
1131 * Returns: the #EShellView to which @searchbar belongs
1132 **/
1133 EShellView *
1134 e_shell_searchbar_get_shell_view (EShellSearchbar *searchbar)
1135 {
1136 g_return_val_if_fail (E_IS_SHELL_SEARCHBAR (searchbar), NULL);
1137
1138 return E_SHELL_VIEW (searchbar->priv->shell_view);
1139 }
1140
1141 gboolean
1142 e_shell_searchbar_get_express_mode (EShellSearchbar *searchbar)
1143 {
1144 g_return_val_if_fail (E_IS_SHELL_SEARCHBAR (searchbar), FALSE);
1145
1146 return searchbar->priv->express_mode;
1147 }
1148
1149 void
1150 e_shell_searchbar_set_express_mode (EShellSearchbar *searchbar,
1151 gboolean express_mode)
1152 {
1153 g_return_if_fail (E_IS_SHELL_SEARCHBAR (searchbar));
1154
1155 if (searchbar->priv->express_mode == express_mode)
1156 return;
1157
1158 searchbar->priv->express_mode = express_mode;
1159
1160 /* Emit "notify" on all the properties we override. */
1161 g_object_freeze_notify (G_OBJECT (searchbar));
1162 g_object_notify (G_OBJECT (searchbar), "express-mode");
1163 g_object_notify (G_OBJECT (searchbar), "labels-visible");
1164 g_object_notify (G_OBJECT (searchbar), "filter-visible");
1165 g_object_notify (G_OBJECT (searchbar), "scope-visible");
1166 g_object_thaw_notify (G_OBJECT (searchbar));
1167 }
1168
1169 EActionComboBox *
1170 e_shell_searchbar_get_filter_combo_box (EShellSearchbar *searchbar)
1171 {
1172 g_return_val_if_fail (E_IS_SHELL_SEARCHBAR (searchbar), NULL);
1173
1174 return E_ACTION_COMBO_BOX (searchbar->priv->filter_combo_box);
1175 }
1176
1177 gboolean
1178 e_shell_searchbar_get_labels_visible (EShellSearchbar *searchbar)
1179 {
1180 g_return_val_if_fail (E_IS_SHELL_SEARCHBAR (searchbar), FALSE);
1181
1182 /* Express mode overrides this. */
1183 if (e_shell_searchbar_get_express_mode (searchbar))
1184 return FALSE;
1185
1186 return searchbar->priv->labels_visible;
1187 }
1188
1189 void
1190 e_shell_searchbar_set_labels_visible (EShellSearchbar *searchbar,
1191 gboolean labels_visible)
1192 {
1193 g_return_if_fail (E_IS_SHELL_SEARCHBAR (searchbar));
1194
1195 if (searchbar->priv->labels_visible == labels_visible)
1196 return;
1197
1198 searchbar->priv->labels_visible = labels_visible;
1199
1200 g_object_notify (G_OBJECT (searchbar), "labels-visible");
1201 }
1202
1203 gboolean
1204 e_shell_searchbar_get_filter_visible (EShellSearchbar *searchbar)
1205 {
1206 g_return_val_if_fail (E_IS_SHELL_SEARCHBAR (searchbar), FALSE);
1207
1208 /* Express mode overrides this. */
1209 if (e_shell_searchbar_get_express_mode (searchbar))
1210 return FALSE;
1211
1212 return searchbar->priv->filter_visible;
1213 }
1214
1215 void
1216 e_shell_searchbar_set_filter_visible (EShellSearchbar *searchbar,
1217 gboolean filter_visible)
1218 {
1219 g_return_if_fail (E_IS_SHELL_SEARCHBAR (searchbar));
1220
1221 if (searchbar->priv->filter_visible == filter_visible)
1222 return;
1223
1224 searchbar->priv->filter_visible = filter_visible;
1225
1226 g_object_notify (G_OBJECT (searchbar), "filter-visible");
1227 }
1228
1229 const gchar *
1230 e_shell_searchbar_get_search_hint (EShellSearchbar *searchbar)
1231 {
1232 GtkEntry *entry;
1233
1234 g_return_val_if_fail (E_IS_SHELL_SEARCHBAR (searchbar), NULL);
1235
1236 entry = GTK_ENTRY (searchbar->priv->search_entry);
1237
1238 return gtk_entry_get_placeholder_text (entry);
1239 }
1240
1241 void
1242 e_shell_searchbar_set_search_hint (EShellSearchbar *searchbar,
1243 const gchar *search_hint)
1244 {
1245 GtkEntry *entry;
1246
1247 g_return_if_fail (E_IS_SHELL_SEARCHBAR (searchbar));
1248
1249 entry = GTK_ENTRY (searchbar->priv->search_entry);
1250
1251 if (g_strcmp0 (gtk_entry_get_placeholder_text (entry), search_hint) == 0)
1252 return;
1253
1254 gtk_entry_set_placeholder_text (entry, search_hint);
1255
1256 g_object_notify (G_OBJECT (searchbar), "search-hint");
1257 }
1258
1259 GtkRadioAction *
1260 e_shell_searchbar_get_search_option (EShellSearchbar *searchbar)
1261 {
1262 g_return_val_if_fail (E_IS_SHELL_SEARCHBAR (searchbar), NULL);
1263
1264 return searchbar->priv->search_option;
1265 }
1266
1267 void
1268 e_shell_searchbar_set_search_option (EShellSearchbar *searchbar,
1269 GtkRadioAction *search_option)
1270 {
1271 g_return_if_fail (E_IS_SHELL_SEARCHBAR (searchbar));
1272
1273 if (searchbar->priv->search_option == search_option)
1274 return;
1275
1276 if (search_option != NULL) {
1277 g_return_if_fail (GTK_IS_RADIO_ACTION (search_option));
1278 g_object_ref (search_option);
1279 }
1280
1281 if (searchbar->priv->search_option != NULL) {
1282 g_signal_handlers_disconnect_matched (
1283 searchbar->priv->search_option,
1284 G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL,
1285 searchbar);
1286 g_object_unref (searchbar->priv->search_option);
1287 }
1288
1289 searchbar->priv->search_option = search_option;
1290
1291 if (search_option != NULL)
1292 g_signal_connect (
1293 search_option, "changed",
1294 G_CALLBACK (shell_searchbar_option_changed_cb),
1295 searchbar);
1296
1297 g_object_notify (G_OBJECT (searchbar), "search-option");
1298 }
1299
1300 const gchar *
1301 e_shell_searchbar_get_search_text (EShellSearchbar *searchbar)
1302 {
1303 GtkEntry *entry;
1304
1305 g_return_val_if_fail (E_IS_SHELL_SEARCHBAR (searchbar), NULL);
1306
1307 entry = GTK_ENTRY (searchbar->priv->search_entry);
1308
1309 return gtk_entry_get_text (entry);
1310 }
1311
1312 void
1313 e_shell_searchbar_set_search_text (EShellSearchbar *searchbar,
1314 const gchar *search_text)
1315 {
1316 GtkEntry *entry;
1317
1318 g_return_if_fail (E_IS_SHELL_SEARCHBAR (searchbar));
1319
1320 entry = GTK_ENTRY (searchbar->priv->search_entry);
1321
1322 /* XXX Really wish gtk_entry_set_text()
1323 * would just learn to accept NULL. */
1324 if (search_text == NULL)
1325 search_text = "";
1326
1327 if (g_strcmp0 (gtk_entry_get_text (entry), search_text) == 0)
1328 return;
1329
1330 gtk_entry_set_text (entry, search_text);
1331
1332 shell_searchbar_update_search_widgets (searchbar);
1333
1334 g_object_notify (G_OBJECT (searchbar), "search-text");
1335 }
1336
1337 gboolean
1338 e_shell_searchbar_get_search_visible (EShellSearchbar *searchbar)
1339 {
1340 g_return_val_if_fail (E_IS_SHELL_SEARCHBAR (searchbar), FALSE);
1341
1342 return searchbar->priv->search_visible;
1343 }
1344
1345 void
1346 e_shell_searchbar_set_search_visible (EShellSearchbar *searchbar,
1347 gboolean search_visible)
1348 {
1349 g_return_if_fail (E_IS_SHELL_SEARCHBAR (searchbar));
1350
1351 if (searchbar->priv->search_visible == search_visible)
1352 return;
1353
1354 searchbar->priv->search_visible = search_visible;
1355
1356 g_object_notify (G_OBJECT (searchbar), "search-visible");
1357 }
1358
1359 GtkWidget *
1360 e_shell_searchbar_get_search_box (EShellSearchbar *searchbar)
1361 {
1362 g_return_val_if_fail (searchbar != NULL, NULL);
1363 g_return_val_if_fail (searchbar->priv != NULL, NULL);
1364 g_return_val_if_fail (searchbar->priv->search_entry != NULL, NULL);
1365
1366 return gtk_widget_get_parent (searchbar->priv->search_entry);
1367 }
1368
1369 EActionComboBox *
1370 e_shell_searchbar_get_scope_combo_box (EShellSearchbar *searchbar)
1371 {
1372 g_return_val_if_fail (E_IS_SHELL_SEARCHBAR (searchbar), NULL);
1373
1374 return E_ACTION_COMBO_BOX (searchbar->priv->scope_combo_box);
1375 }
1376
1377 gboolean
1378 e_shell_searchbar_get_scope_visible (EShellSearchbar *searchbar)
1379 {
1380 g_return_val_if_fail (E_IS_SHELL_SEARCHBAR (searchbar), FALSE);
1381
1382 /* Express mode overrides this. */
1383 if (e_shell_searchbar_get_express_mode (searchbar))
1384 return FALSE;
1385
1386 return searchbar->priv->scope_visible;
1387 }
1388
1389 void
1390 e_shell_searchbar_set_scope_visible (EShellSearchbar *searchbar,
1391 gboolean scope_visible)
1392 {
1393 g_return_if_fail (E_IS_SHELL_SEARCHBAR (searchbar));
1394
1395 if (searchbar->priv->scope_visible == scope_visible)
1396 return;
1397
1398 searchbar->priv->scope_visible = scope_visible;
1399
1400 g_object_notify (G_OBJECT (searchbar), "scope-visible");
1401 }
1402
1403 void
1404 e_shell_searchbar_set_state_dirty (EShellSearchbar *searchbar)
1405 {
1406 g_return_if_fail (E_IS_SHELL_SEARCHBAR (searchbar));
1407
1408 searchbar->priv->state_dirty = TRUE;
1409 }
1410
1411 const gchar *
1412 e_shell_searchbar_get_state_group (EShellSearchbar *searchbar)
1413 {
1414 g_return_val_if_fail (E_IS_SHELL_SEARCHBAR (searchbar), NULL);
1415
1416 return searchbar->priv->state_group;
1417 }
1418
1419 void
1420 e_shell_searchbar_set_state_group (EShellSearchbar *searchbar,
1421 const gchar *state_group)
1422 {
1423 g_return_if_fail (E_IS_SHELL_SEARCHBAR (searchbar));
1424
1425 if (state_group == NULL)
1426 state_group = STATE_GROUP_DEFAULT;
1427
1428 if (g_strcmp0 (searchbar->priv->state_group, state_group) == 0)
1429 return;
1430
1431 g_free (searchbar->priv->state_group);
1432 searchbar->priv->state_group = g_strdup (state_group);
1433
1434 g_object_notify (G_OBJECT (searchbar), "state-group");
1435 }
1436
1437 static gboolean
1438 idle_execute_search (gpointer shell_view)
1439 {
1440 e_shell_view_execute_search (shell_view);
1441 g_object_unref (shell_view);
1442 return FALSE;
1443 }
1444
1445 void
1446 e_shell_searchbar_load_state (EShellSearchbar *searchbar)
1447 {
1448 EShellView *shell_view;
1449 EShellWindow *shell_window;
1450 GKeyFile *key_file;
1451 GtkAction *action;
1452 GtkWidget *widget;
1453 gboolean express_mode;
1454 const gchar *search_text;
1455 const gchar *state_group;
1456 const gchar *key;
1457 gchar *string;
1458 gint value = 0;
1459
1460 g_return_if_fail (E_IS_SHELL_SEARCHBAR (searchbar));
1461
1462 shell_view = e_shell_searchbar_get_shell_view (searchbar);
1463 state_group = e_shell_searchbar_get_state_group (searchbar);
1464 g_return_if_fail (state_group != NULL);
1465
1466 key_file = e_shell_view_get_state_key_file (shell_view);
1467 shell_window = e_shell_view_get_shell_window (shell_view);
1468
1469 express_mode = e_shell_searchbar_get_express_mode (searchbar);
1470
1471 /* Changing the combo boxes triggers searches, so block
1472 * the search action until the state is fully restored. */
1473 action = E_SHELL_WINDOW_ACTION_SEARCH_QUICK (shell_window);
1474 gtk_action_block_activate (action);
1475
1476 e_shell_view_block_execute_search (shell_view);
1477
1478 e_shell_view_set_search_rule (shell_view, NULL);
1479
1480 key = STATE_KEY_SEARCH_FILTER;
1481 string = g_key_file_get_string (key_file, state_group, key, NULL);
1482 if (string != NULL && *string != '\0' && !express_mode)
1483 action = e_shell_window_get_action (shell_window, string);
1484 else
1485 action = NULL;
1486 if (GTK_IS_RADIO_ACTION (action))
1487 gtk_action_activate (action);
1488 else {
1489 /* Pick the first combo box item. */
1490 widget = searchbar->priv->filter_combo_box;
1491 gtk_combo_box_set_active (GTK_COMBO_BOX (widget), 0);
1492 }
1493 g_free (string);
1494
1495 /* Avoid restoring to the "Advanced Search" option, since we
1496 * don't currently save the search rule (TODO but we should). */
1497 key = STATE_KEY_SEARCH_OPTION;
1498 string = g_key_file_get_string (key_file, state_group, key, NULL);
1499 if (string != NULL && *string != '\0')
1500 action = e_shell_window_get_action (shell_window, string);
1501 else
1502 action = NULL;
1503 if (GTK_IS_RADIO_ACTION (action))
1504 g_object_get (action, "value", &value, NULL);
1505 else
1506 value = SEARCH_OPTION_ADVANCED;
1507 if (value != SEARCH_OPTION_ADVANCED)
1508 gtk_action_activate (action);
1509 else if (searchbar->priv->search_option != NULL)
1510 gtk_radio_action_set_current_value (
1511 searchbar->priv->search_option, 0);
1512 g_free (string);
1513
1514 key = STATE_KEY_SEARCH_TEXT;
1515 string = g_key_file_get_string (key_file, state_group, key, NULL);
1516 search_text = e_shell_searchbar_get_search_text (searchbar);
1517 if (search_text != NULL && *search_text == '\0')
1518 search_text = NULL;
1519 if (g_strcmp0 (string, search_text) != 0)
1520 e_shell_searchbar_set_search_text (searchbar, string);
1521 g_free (string);
1522
1523 /* Search scope is hard-coded to the default state group. */
1524 state_group = STATE_GROUP_DEFAULT;
1525
1526 key = STATE_KEY_SEARCH_SCOPE;
1527 string = g_key_file_get_string (key_file, state_group, key, NULL);
1528 if (string != NULL && *string != '\0' && !express_mode)
1529 action = e_shell_window_get_action (shell_window, string);
1530 else
1531 action = NULL;
1532 if (GTK_IS_RADIO_ACTION (action))
1533 gtk_action_activate (action);
1534 else {
1535 /* Pick the first combo box item. */
1536 widget = searchbar->priv->scope_combo_box;
1537 gtk_combo_box_set_active (GTK_COMBO_BOX (widget), 0);
1538 }
1539 g_free (string);
1540
1541 e_shell_view_unblock_execute_search (shell_view);
1542
1543 action = E_SHELL_WINDOW_ACTION_SEARCH_QUICK (shell_window);
1544 gtk_action_unblock_activate (action);
1545
1546 /* Execute the search when we have time. */
1547
1548 g_object_ref (shell_view);
1549 searchbar->priv->state_dirty = FALSE;
1550
1551 /* Prioritize ahead of GTK+ redraws. */
1552 g_idle_add_full (
1553 G_PRIORITY_HIGH_IDLE,
1554 idle_execute_search, shell_view, NULL);
1555 }
1556
1557 void
1558 e_shell_searchbar_save_state (EShellSearchbar *searchbar)
1559 {
1560 g_return_if_fail (E_IS_SHELL_SEARCHBAR (searchbar));
1561
1562 /* Skip saving state if it hasn't changed since it was loaded. */
1563 if (!searchbar->priv->state_dirty)
1564 return;
1565
1566 shell_searchbar_save_search_filter (searchbar);
1567
1568 shell_searchbar_save_search_option (searchbar);
1569
1570 shell_searchbar_save_search_text (searchbar);
1571
1572 shell_searchbar_save_search_scope (searchbar);
1573
1574 searchbar->priv->state_dirty = FALSE;
1575 }