4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms of the GNU Lesser General Public License as published by
6 * the Free Software Foundation.
8 * This program is distributed in the hope that it will be useful, but
9 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
10 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
13 * You should have received a copy of the GNU Lesser General Public License
14 * along with this program; if not, see <http://www.gnu.org/licenses/>.
17 * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
22 * SECTION: e-shell-searchbar
23 * @short_description: quick search interface
24 * @include: shell/e-shell-searchbar.h
27 #include "evolution-config.h"
29 #include "e-shell-searchbar.h"
31 #include <glib/gi18n-lib.h>
32 #include <libebackend/libebackend.h>
34 #include "e-shell-window-actions.h"
36 #define E_SHELL_SEARCHBAR_GET_PRIVATE(obj) \
37 (G_TYPE_INSTANCE_GET_PRIVATE \
38 ((obj), E_TYPE_SHELL_SEARCHBAR, EShellSearchbarPrivate))
40 #define SEARCH_OPTION_ADVANCED (-1)
42 /* Default "state key file" group: [Search Bar] */
43 #define STATE_GROUP_DEFAULT "Search Bar"
45 #define STATE_KEY_SEARCH_FILTER "SearchFilter"
46 #define STATE_KEY_SEARCH_OPTION "SearchOption"
47 #define STATE_KEY_SEARCH_SCOPE "SearchScope"
48 #define STATE_KEY_SEARCH_TEXT "SearchText"
50 struct _EShellSearchbarPrivate
{
52 gpointer shell_view
; /* weak pointer */
54 GtkRadioAction
*search_option
;
55 EFilterRule
*search_rule
;
56 GtkCssProvider
*css_provider
;
58 /* Child Widgets (not referenced) */
59 GtkWidget
*filter_combo_box
;
60 GtkWidget
*search_entry
;
61 GtkWidget
*scope_combo_box
;
66 gboolean filter_visible
;
67 gboolean scope_visible
;
73 PROP_FILTER_COMBO_BOX
,
84 G_DEFINE_TYPE_WITH_CODE (
88 G_IMPLEMENT_INTERFACE (
89 E_TYPE_EXTENSIBLE
, NULL
))
92 shell_searchbar_save_search_filter (EShellSearchbar
*searchbar
)
94 EShellView
*shell_view
;
95 EActionComboBox
*action_combo_box
;
96 GtkRadioAction
*radio_action
;
98 const gchar
*action_name
;
99 const gchar
*state_group
;
102 shell_view
= e_shell_searchbar_get_shell_view (searchbar
);
103 state_group
= e_shell_searchbar_get_state_group (searchbar
);
104 g_return_if_fail (state_group
!= NULL
);
106 key
= STATE_KEY_SEARCH_FILTER
;
107 key_file
= e_shell_view_get_state_key_file (shell_view
);
109 action_combo_box
= e_shell_searchbar_get_filter_combo_box (searchbar
);
110 radio_action
= e_action_combo_box_get_action (action_combo_box
);
112 if (radio_action
!= NULL
)
113 radio_action
= e_radio_action_get_current_action (radio_action
);
115 if (radio_action
!= NULL
) {
116 action_name
= gtk_action_get_name (GTK_ACTION (radio_action
));
117 g_key_file_set_string (key_file
, state_group
, key
, action_name
);
119 g_key_file_remove_key (key_file
, state_group
, key
, NULL
);
121 e_shell_view_set_state_dirty (shell_view
);
125 shell_searchbar_save_search_option (EShellSearchbar
*searchbar
)
127 EShellView
*shell_view
;
128 GtkRadioAction
*radio_action
;
130 const gchar
*action_name
;
131 const gchar
*state_group
;
134 shell_view
= e_shell_searchbar_get_shell_view (searchbar
);
135 state_group
= e_shell_searchbar_get_state_group (searchbar
);
136 g_return_if_fail (state_group
!= NULL
);
138 key
= STATE_KEY_SEARCH_OPTION
;
139 key_file
= e_shell_view_get_state_key_file (shell_view
);
141 radio_action
= e_shell_searchbar_get_search_option (searchbar
);
143 if (radio_action
!= NULL
)
144 radio_action
= e_radio_action_get_current_action (radio_action
);
146 if (radio_action
!= NULL
) {
147 action_name
= gtk_action_get_name (GTK_ACTION (radio_action
));
148 g_key_file_set_string (key_file
, state_group
, key
, action_name
);
150 g_key_file_remove_key (key_file
, state_group
, key
, NULL
);
152 e_shell_view_set_state_dirty (shell_view
);
156 shell_searchbar_save_search_text (EShellSearchbar
*searchbar
)
158 EShellView
*shell_view
;
160 const gchar
*search_text
;
161 const gchar
*state_group
;
164 shell_view
= e_shell_searchbar_get_shell_view (searchbar
);
165 state_group
= e_shell_searchbar_get_state_group (searchbar
);
166 g_return_if_fail (state_group
!= NULL
);
168 key
= STATE_KEY_SEARCH_TEXT
;
169 key_file
= e_shell_view_get_state_key_file (shell_view
);
171 search_text
= e_shell_searchbar_get_search_text (searchbar
);
173 if (search_text
!= NULL
&& *search_text
!= '\0')
174 g_key_file_set_string (key_file
, state_group
, key
, search_text
);
176 g_key_file_remove_key (key_file
, state_group
, key
, NULL
);
178 e_shell_view_set_state_dirty (shell_view
);
182 shell_searchbar_save_search_scope (EShellSearchbar
*searchbar
)
184 EShellView
*shell_view
;
185 EActionComboBox
*action_combo_box
;
186 GtkRadioAction
*radio_action
;
188 const gchar
*action_name
;
189 const gchar
*state_group
;
192 shell_view
= e_shell_searchbar_get_shell_view (searchbar
);
194 /* Search scope is hard-coded to the default state group. */
195 state_group
= STATE_GROUP_DEFAULT
;
197 key
= STATE_KEY_SEARCH_SCOPE
;
198 key_file
= e_shell_view_get_state_key_file (shell_view
);
200 action_combo_box
= e_shell_searchbar_get_scope_combo_box (searchbar
);
201 radio_action
= e_action_combo_box_get_action (action_combo_box
);
203 if (radio_action
!= NULL
)
204 radio_action
= e_radio_action_get_current_action (radio_action
);
206 if (radio_action
!= NULL
) {
207 action_name
= gtk_action_get_name (GTK_ACTION (radio_action
));
208 g_key_file_set_string (key_file
, state_group
, key
, action_name
);
210 g_key_file_remove_key (key_file
, state_group
, key
, NULL
);
212 e_shell_view_set_state_dirty (shell_view
);
216 shell_searchbar_update_search_widgets (EShellSearchbar
*searchbar
)
218 EShellView
*shell_view
;
219 EShellWindow
*shell_window
;
222 const gchar
*search_text
;
225 /* EShellView subclasses are responsible for actually
226 * executing the search. This is all cosmetic stuff. */
228 widget
= searchbar
->priv
->search_entry
;
229 shell_view
= e_shell_searchbar_get_shell_view (searchbar
);
230 shell_window
= e_shell_view_get_shell_window (shell_view
);
231 search_text
= e_shell_searchbar_get_search_text (searchbar
);
234 (search_text
!= NULL
&& *search_text
!= '\0') ||
235 (e_shell_view_get_search_rule (shell_view
) != NULL
);
241 e_utils_get_theme_color (widget
, "theme_selected_bg_color", E_UTILS_DEFAULT_THEME_SELECTED_BG_COLOR
, &bg
);
242 e_utils_get_theme_color (widget
, "theme_selected_fg_color", E_UTILS_DEFAULT_THEME_SELECTED_FG_COLOR
, &fg
);
244 css
= g_strdup_printf (
245 "GtkEntry#searchbar_searchentry_active { "
247 " background-color:#%06x; "
250 e_rgba_to_value (&bg
),
251 e_rgba_to_value (&fg
));
252 gtk_css_provider_load_from_data (
253 searchbar
->priv
->css_provider
, css
, -1, NULL
);
256 gtk_widget_set_name (widget
, "searchbar_searchentry_active");
258 gtk_widget_set_name (widget
, "searchbar_searchentry");
261 action
= E_SHELL_WINDOW_ACTION_SEARCH_CLEAR (shell_window
);
262 gtk_action_set_sensitive (action
, sensitive
);
264 action
= E_SHELL_WINDOW_ACTION_SEARCH_SAVE (shell_window
);
265 gtk_action_set_visible (action
, sensitive
&& e_shell_view_get_search_rule (shell_view
) != NULL
);
269 shell_searchbar_clear_search_cb (EShellView
*shell_view
,
270 EShellSearchbar
*searchbar
)
272 GtkRadioAction
*search_option
;
275 e_shell_searchbar_set_search_text (searchbar
, NULL
);
277 search_option
= e_shell_searchbar_get_search_option (searchbar
);
278 if (search_option
== NULL
)
281 /* Reset the search option if it's set to advanced search. */
282 current_value
= gtk_radio_action_get_current_value (search_option
);
283 if (current_value
== SEARCH_OPTION_ADVANCED
)
284 gtk_radio_action_set_current_value (search_option
, 0);
288 shell_searchbar_custom_search_cb (EShellView
*shell_view
,
289 EFilterRule
*custom_rule
,
290 EShellSearchbar
*searchbar
)
292 GtkRadioAction
*search_option
;
293 gint value
= SEARCH_OPTION_ADVANCED
;
295 e_shell_searchbar_set_search_text (searchbar
, NULL
);
297 search_option
= e_shell_searchbar_get_search_option (searchbar
);
298 if (search_option
!= NULL
)
299 gtk_radio_action_set_current_value (search_option
, value
);
303 shell_searchbar_execute_search_cb (EShellView
*shell_view
,
304 EShellSearchbar
*searchbar
)
306 EShellContent
*shell_content
;
308 shell_searchbar_update_search_widgets (searchbar
);
310 e_shell_searchbar_save_state (searchbar
);
312 if (!e_shell_view_is_active (shell_view
))
315 /* Direct the focus away from the search entry, so that a
316 * focus-in event is required before the text can be changed.
317 * This will reset the entry to the appropriate visual state. */
318 if (gtk_widget_is_focus (searchbar
->priv
->search_entry
)) {
319 shell_content
= e_shell_view_get_shell_content (shell_view
);
320 e_shell_content_focus_search_results (shell_content
);
325 shell_searchbar_filter_changed_cb (GtkComboBox
*filter_combo_box
,
326 EShellSearchbar
*searchbar
)
328 EShellView
*shell_view
;
330 shell_view
= e_shell_searchbar_get_shell_view (searchbar
);
332 e_shell_view_execute_search (shell_view
);
336 shell_searchbar_entry_activate_cb (EShellSearchbar
*searchbar
)
338 EShellView
*shell_view
;
339 EShellWindow
*shell_window
;
341 const gchar
*search_text
;
343 shell_view
= e_shell_searchbar_get_shell_view (searchbar
);
344 shell_window
= e_shell_view_get_shell_window (shell_view
);
346 search_text
= e_shell_searchbar_get_search_text (searchbar
);
347 if (search_text
!= NULL
&& *search_text
!= '\0')
348 action
= E_SHELL_WINDOW_ACTION_SEARCH_QUICK (shell_window
);
350 action
= E_SHELL_WINDOW_ACTION_SEARCH_CLEAR (shell_window
);
352 gtk_action_activate (action
);
356 shell_searchbar_entry_changed_cb (EShellSearchbar
*searchbar
)
358 EShellView
*shell_view
;
359 EShellWindow
*shell_window
;
361 const gchar
*search_text
;
364 shell_view
= e_shell_searchbar_get_shell_view (searchbar
);
365 shell_window
= e_shell_view_get_shell_window (shell_view
);
367 search_text
= e_shell_searchbar_get_search_text (searchbar
);
368 sensitive
= (search_text
!= NULL
&& *search_text
!= '\0');
370 action
= E_SHELL_WINDOW_ACTION_SEARCH_QUICK (shell_window
);
371 gtk_action_set_sensitive (action
, sensitive
);
375 shell_searchbar_entry_icon_press_cb (EShellSearchbar
*searchbar
,
376 GtkEntryIconPosition icon_pos
,
379 EShellView
*shell_view
;
380 EShellWindow
*shell_window
;
383 /* Show the search options menu when the icon is pressed. */
385 if (icon_pos
!= GTK_ENTRY_ICON_PRIMARY
)
388 shell_view
= e_shell_searchbar_get_shell_view (searchbar
);
389 shell_window
= e_shell_view_get_shell_window (shell_view
);
391 action
= E_SHELL_WINDOW_ACTION_SEARCH_OPTIONS (shell_window
);
392 gtk_action_activate (action
);
396 shell_searchbar_entry_icon_release_cb (EShellSearchbar
*searchbar
,
397 GtkEntryIconPosition icon_pos
,
400 EShellView
*shell_view
;
401 EShellWindow
*shell_window
;
404 /* Clear the search when the icon is pressed and released. */
406 if (icon_pos
!= GTK_ENTRY_ICON_SECONDARY
)
409 shell_view
= e_shell_searchbar_get_shell_view (searchbar
);
410 shell_window
= e_shell_view_get_shell_window (shell_view
);
412 action
= E_SHELL_WINDOW_ACTION_SEARCH_CLEAR (shell_window
);
413 gtk_action_activate (action
);
417 shell_searchbar_entry_key_press_cb (EShellSearchbar
*searchbar
,
418 GdkEventKey
*key_event
,
421 EShellView
*shell_view
;
422 EShellWindow
*shell_window
;
426 mask
= gtk_accelerator_get_default_mod_mask ();
427 if ((key_event
->state
& mask
) != GDK_MOD1_MASK
)
430 if (key_event
->keyval
!= GDK_KEY_Down
)
433 shell_view
= e_shell_searchbar_get_shell_view (searchbar
);
434 shell_window
= e_shell_view_get_shell_window (shell_view
);
436 action
= E_SHELL_WINDOW_ACTION_SEARCH_OPTIONS (shell_window
);
437 gtk_action_activate (action
);
443 shell_searchbar_option_changed_cb (GtkRadioAction
*action
,
444 GtkRadioAction
*current
,
445 EShellSearchbar
*searchbar
)
447 EShellView
*shell_view
;
448 const gchar
*search_text
;
452 shell_view
= e_shell_searchbar_get_shell_view (searchbar
);
454 label
= gtk_action_get_label (GTK_ACTION (current
));
455 e_shell_searchbar_set_search_hint (searchbar
, label
);
457 current_value
= gtk_radio_action_get_current_value (current
);
458 search_text
= e_shell_searchbar_get_search_text (searchbar
);
460 if (current_value
!= SEARCH_OPTION_ADVANCED
) {
461 e_shell_view_set_search_rule (shell_view
, NULL
);
462 e_shell_searchbar_set_search_text (searchbar
, search_text
);
463 if (search_text
!= NULL
&& *search_text
!= '\0') {
464 e_shell_view_execute_search (shell_view
);
466 shell_searchbar_save_search_option (searchbar
);
469 } else if (search_text
!= NULL
)
470 e_shell_searchbar_set_search_text (searchbar
, NULL
);
474 shell_searchbar_entry_focus_in_cb (GtkWidget
*entry
,
476 EShellSearchbar
*searchbar
)
478 /* to not change background when user changes search entry content */
479 gtk_widget_set_name (entry
, "searchbar_searchentry");
485 shell_searchbar_entry_focus_out_cb (GtkWidget
*entry
,
487 EShellSearchbar
*searchbar
)
489 shell_searchbar_update_search_widgets (searchbar
);
495 shell_searchbar_set_shell_view (EShellSearchbar
*searchbar
,
496 EShellView
*shell_view
)
498 g_return_if_fail (searchbar
->priv
->shell_view
== NULL
);
500 searchbar
->priv
->shell_view
= shell_view
;
502 g_object_add_weak_pointer (
503 G_OBJECT (shell_view
),
504 &searchbar
->priv
->shell_view
);
508 shell_searchbar_set_property (GObject
*object
,
513 switch (property_id
) {
514 case PROP_FILTER_VISIBLE
:
515 e_shell_searchbar_set_filter_visible (
516 E_SHELL_SEARCHBAR (object
),
517 g_value_get_boolean (value
));
520 case PROP_SEARCH_HINT
:
521 e_shell_searchbar_set_search_hint (
522 E_SHELL_SEARCHBAR (object
),
523 g_value_get_string (value
));
526 case PROP_SEARCH_OPTION
:
527 e_shell_searchbar_set_search_option (
528 E_SHELL_SEARCHBAR (object
),
529 g_value_get_object (value
));
532 case PROP_SEARCH_TEXT
:
533 e_shell_searchbar_set_search_text (
534 E_SHELL_SEARCHBAR (object
),
535 g_value_get_string (value
));
538 case PROP_SCOPE_VISIBLE
:
539 e_shell_searchbar_set_scope_visible (
540 E_SHELL_SEARCHBAR (object
),
541 g_value_get_boolean (value
));
544 case PROP_SHELL_VIEW
:
545 shell_searchbar_set_shell_view (
546 E_SHELL_SEARCHBAR (object
),
547 g_value_get_object (value
));
550 case PROP_STATE_GROUP
:
551 e_shell_searchbar_set_state_group (
552 E_SHELL_SEARCHBAR (object
),
553 g_value_get_string (value
));
557 G_OBJECT_WARN_INVALID_PROPERTY_ID (object
, property_id
, pspec
);
561 shell_searchbar_get_property (GObject
*object
,
566 switch (property_id
) {
567 case PROP_FILTER_COMBO_BOX
:
569 value
, e_shell_searchbar_get_filter_combo_box (
570 E_SHELL_SEARCHBAR (object
)));
573 case PROP_FILTER_VISIBLE
:
574 g_value_set_boolean (
575 value
, e_shell_searchbar_get_filter_visible (
576 E_SHELL_SEARCHBAR (object
)));
579 case PROP_SEARCH_HINT
:
581 value
, e_shell_searchbar_get_search_hint (
582 E_SHELL_SEARCHBAR (object
)));
585 case PROP_SEARCH_OPTION
:
587 value
, e_shell_searchbar_get_search_option (
588 E_SHELL_SEARCHBAR (object
)));
591 case PROP_SEARCH_TEXT
:
593 value
, e_shell_searchbar_get_search_text (
594 E_SHELL_SEARCHBAR (object
)));
597 case PROP_SCOPE_COMBO_BOX
:
599 value
, e_shell_searchbar_get_scope_combo_box (
600 E_SHELL_SEARCHBAR (object
)));
603 case PROP_SCOPE_VISIBLE
:
604 g_value_set_boolean (
605 value
, e_shell_searchbar_get_scope_visible (
606 E_SHELL_SEARCHBAR (object
)));
609 case PROP_SHELL_VIEW
:
611 value
, e_shell_searchbar_get_shell_view (
612 E_SHELL_SEARCHBAR (object
)));
615 case PROP_STATE_GROUP
:
617 value
, e_shell_searchbar_get_state_group (
618 E_SHELL_SEARCHBAR (object
)));
622 G_OBJECT_WARN_INVALID_PROPERTY_ID (object
, property_id
, pspec
);
626 shell_searchbar_dispose (GObject
*object
)
628 EShellSearchbarPrivate
*priv
;
630 priv
= E_SHELL_SEARCHBAR_GET_PRIVATE (object
);
632 if (priv
->shell_view
!= NULL
) {
633 g_object_remove_weak_pointer (
634 G_OBJECT (priv
->shell_view
), &priv
->shell_view
);
635 priv
->shell_view
= NULL
;
638 if (priv
->search_option
!= NULL
) {
639 g_signal_handlers_disconnect_matched (
640 priv
->search_option
, G_SIGNAL_MATCH_DATA
,
641 0, 0, NULL
, NULL
, object
);
642 g_clear_object (&priv
->search_option
);
645 g_clear_object (&priv
->css_provider
);
647 /* Chain up to parent's dispose() method. */
648 G_OBJECT_CLASS (e_shell_searchbar_parent_class
)->dispose (object
);
652 shell_searchbar_finalize (GObject
*object
)
654 EShellSearchbarPrivate
*priv
;
656 priv
= E_SHELL_SEARCHBAR_GET_PRIVATE (object
);
658 g_free (priv
->state_group
);
660 /* Chain up to parent's finalize() method. */
661 G_OBJECT_CLASS (e_shell_searchbar_parent_class
)->finalize (object
);
665 shell_searchbar_constructed (GObject
*object
)
667 EShellView
*shell_view
;
668 EShellWindow
*shell_window
;
669 EShellSearchbar
*searchbar
;
670 GtkSizeGroup
*size_group
;
674 searchbar
= E_SHELL_SEARCHBAR (object
);
675 shell_view
= e_shell_searchbar_get_shell_view (searchbar
);
676 shell_window
= e_shell_view_get_shell_window (shell_view
);
677 size_group
= e_shell_view_get_size_group (shell_view
);
680 shell_view
, "clear-search",
681 G_CALLBACK (shell_searchbar_clear_search_cb
), searchbar
);
684 shell_view
, "custom-search",
685 G_CALLBACK (shell_searchbar_custom_search_cb
), searchbar
);
687 g_signal_connect_after (
688 shell_view
, "execute-search",
689 G_CALLBACK (shell_searchbar_execute_search_cb
), searchbar
);
691 widget
= searchbar
->priv
->filter_combo_box
;
693 g_signal_connect_swapped (
695 G_CALLBACK (e_shell_searchbar_set_state_dirty
), searchbar
);
697 /* Use G_CONNECT_AFTER here so the EActionComboBox has a
698 * chance to update its radio actions before we go sifting
699 * through the radio group for the current action. */
700 g_signal_connect_after (
702 G_CALLBACK (shell_searchbar_filter_changed_cb
), searchbar
);
704 searchbar
->priv
->css_provider
= gtk_css_provider_new ();
705 widget
= searchbar
->priv
->search_entry
;
706 gtk_style_context_add_provider (
707 gtk_widget_get_style_context (widget
),
708 GTK_STYLE_PROVIDER (searchbar
->priv
->css_provider
),
709 GTK_STYLE_PROVIDER_PRIORITY_APPLICATION
);
711 action
= E_SHELL_WINDOW_ACTION_SEARCH_CLEAR (shell_window
);
713 e_binding_bind_property (
715 widget
, "secondary-icon-sensitive",
716 G_BINDING_SYNC_CREATE
);
717 e_binding_bind_property (
719 widget
, "secondary-icon-name",
720 G_BINDING_SYNC_CREATE
);
721 e_binding_bind_property (
723 widget
, "secondary-icon-tooltip-text",
724 G_BINDING_SYNC_CREATE
);
726 action
= E_SHELL_WINDOW_ACTION_SEARCH_OPTIONS (shell_window
);
728 e_binding_bind_property (
730 widget
, "primary-icon-sensitive",
731 G_BINDING_SYNC_CREATE
);
732 e_binding_bind_property (
734 widget
, "primary-icon-name",
735 G_BINDING_SYNC_CREATE
);
736 e_binding_bind_property (
738 widget
, "primary-icon-tooltip-text",
739 G_BINDING_SYNC_CREATE
);
741 widget
= GTK_WIDGET (searchbar
);
742 gtk_size_group_add_widget (size_group
, widget
);
744 e_extensible_load_extensions (E_EXTENSIBLE (object
));
746 /* Chain up to parent's constructed() method. */
747 G_OBJECT_CLASS (e_shell_searchbar_parent_class
)->constructed (object
);
751 shell_searchbar_map (GtkWidget
*widget
)
753 /* Chain up to parent's map() method. */
754 GTK_WIDGET_CLASS (e_shell_searchbar_parent_class
)->map (widget
);
756 /* Load state after constructed() so we don't derail
757 * subclass initialization. We wait until map() so we
758 * have usable style colors for the entry box. */
759 e_shell_searchbar_load_state (E_SHELL_SEARCHBAR (widget
));
763 e_shell_searchbar_class_init (EShellSearchbarClass
*class)
765 GObjectClass
*object_class
;
766 GtkWidgetClass
*widget_class
;
768 g_type_class_add_private (class, sizeof (EShellSearchbarPrivate
));
770 object_class
= G_OBJECT_CLASS (class);
771 object_class
->set_property
= shell_searchbar_set_property
;
772 object_class
->get_property
= shell_searchbar_get_property
;
773 object_class
->dispose
= shell_searchbar_dispose
;
774 object_class
->finalize
= shell_searchbar_finalize
;
775 object_class
->constructed
= shell_searchbar_constructed
;
777 widget_class
= GTK_WIDGET_CLASS (class);
778 widget_class
->map
= shell_searchbar_map
;
780 g_object_class_install_property (
782 PROP_FILTER_COMBO_BOX
,
783 g_param_spec_object (
787 E_TYPE_ACTION_COMBO_BOX
,
789 G_PARAM_STATIC_STRINGS
));
791 g_object_class_install_property (
794 g_param_spec_boolean (
801 G_PARAM_STATIC_STRINGS
));
803 g_object_class_install_property (
806 g_param_spec_string (
812 G_PARAM_STATIC_STRINGS
));
814 g_object_class_install_property (
817 g_param_spec_object (
821 GTK_TYPE_RADIO_ACTION
,
823 G_PARAM_STATIC_STRINGS
));
825 g_object_class_install_property (
828 g_param_spec_string (
834 G_PARAM_STATIC_STRINGS
));
836 g_object_class_install_property (
838 PROP_SCOPE_COMBO_BOX
,
839 g_param_spec_object (
843 E_TYPE_ACTION_COMBO_BOX
,
845 G_PARAM_STATIC_STRINGS
));
847 g_object_class_install_property (
850 g_param_spec_boolean (
857 G_PARAM_STATIC_STRINGS
));
860 * EShellSearchbar:shell-view
862 * The #EShellView to which the searchbar widget belongs.
864 g_object_class_install_property (
867 g_param_spec_object (
873 G_PARAM_CONSTRUCT_ONLY
|
874 G_PARAM_STATIC_STRINGS
));
877 * EShellSearchbar:state-group
879 * Key file group name to read and write search bar state.
881 g_object_class_install_property (
884 g_param_spec_string (
891 G_PARAM_STATIC_STRINGS
));
895 e_shell_searchbar_init (EShellSearchbar
*searchbar
)
901 searchbar
->priv
= E_SHELL_SEARCHBAR_GET_PRIVATE (searchbar
);
903 gtk_box_set_spacing (GTK_BOX (searchbar
), 6);
904 gtk_style_context_add_class (gtk_widget_get_style_context (GTK_WIDGET (searchbar
)),
907 /* Filter Combo Widgets */
909 box
= GTK_BOX (searchbar
);
911 widget
= gtk_box_new (GTK_ORIENTATION_HORIZONTAL
, 3);
912 gtk_box_pack_start (box
, widget
, FALSE
, FALSE
, 0);
914 e_binding_bind_property (
915 searchbar
, "filter-visible",
917 G_BINDING_SYNC_CREATE
);
919 box
= GTK_BOX (widget
);
921 /* Translators: The "Show:" label precedes a combo box that
922 * allows the user to filter the current view. Examples of
923 * items that appear in the combo box are "Unread Messages",
924 * "Important Messages", or "Active Appointments". */
925 widget
= gtk_label_new_with_mnemonic (_("Sho_w:"));
926 gtk_box_pack_start (box
, widget
, FALSE
, FALSE
, 0);
927 gtk_widget_show (widget
);
929 label
= GTK_LABEL (widget
);
931 widget
= e_action_combo_box_new ();
932 gtk_label_set_mnemonic_widget (label
, widget
);
933 gtk_box_pack_start (box
, widget
, FALSE
, FALSE
, 0);
934 searchbar
->priv
->filter_combo_box
= widget
;
935 gtk_widget_show (widget
);
937 /* Search Entry Widgets */
939 box
= GTK_BOX (searchbar
);
941 widget
= gtk_box_new (GTK_ORIENTATION_HORIZONTAL
, 3);
942 gtk_widget_set_margin_left (widget
, 12);
943 gtk_box_pack_start (box
, widget
, TRUE
, TRUE
, 0);
944 gtk_widget_show (widget
);
946 box
= GTK_BOX (widget
);
948 /* Translators: This is part of the quick search interface.
949 * example: Search: [_______________] in [ Current Folder ] */
950 widget
= gtk_label_new_with_mnemonic (_("Sear_ch:"));
951 gtk_box_pack_start (box
, widget
, FALSE
, FALSE
, 0);
952 gtk_widget_show (widget
);
954 label
= GTK_LABEL (widget
);
956 widget
= gtk_entry_new ();
957 gtk_label_set_mnemonic_widget (label
, widget
);
958 gtk_box_pack_start (box
, widget
, TRUE
, TRUE
, 0);
959 searchbar
->priv
->search_entry
= widget
;
960 gtk_widget_show (widget
);
962 g_signal_connect_swapped (
964 G_CALLBACK (shell_searchbar_entry_activate_cb
),
967 g_signal_connect_swapped (
969 G_CALLBACK (shell_searchbar_entry_changed_cb
),
972 g_signal_connect_swapped (
974 G_CALLBACK (e_shell_searchbar_set_state_dirty
),
977 g_signal_connect_swapped (
978 widget
, "icon-press",
979 G_CALLBACK (shell_searchbar_entry_icon_press_cb
),
982 g_signal_connect_swapped (
983 widget
, "icon-release",
984 G_CALLBACK (shell_searchbar_entry_icon_release_cb
),
987 g_signal_connect_swapped (
988 widget
, "key-press-event",
989 G_CALLBACK (shell_searchbar_entry_key_press_cb
),
993 widget
, "focus-in-event",
994 G_CALLBACK (shell_searchbar_entry_focus_in_cb
),
998 widget
, "focus-out-event",
999 G_CALLBACK (shell_searchbar_entry_focus_out_cb
),
1002 /* Scope Combo Widgets */
1004 box
= GTK_BOX (searchbar
);
1006 widget
= gtk_box_new (GTK_ORIENTATION_HORIZONTAL
, 3);
1007 gtk_box_pack_start (box
, widget
, FALSE
, FALSE
, 0);
1009 e_binding_bind_property (
1010 searchbar
, "scope-visible",
1012 G_BINDING_SYNC_CREATE
);
1014 box
= GTK_BOX (widget
);
1016 /* Translators: This is part of the quick search interface.
1017 * example: Search: [_______________] in [ Current Folder ] */
1018 widget
= gtk_label_new_with_mnemonic (_("i_n"));
1019 gtk_box_pack_start (box
, widget
, FALSE
, FALSE
, 0);
1020 gtk_widget_show (widget
);
1022 label
= GTK_LABEL (widget
);
1024 widget
= e_action_combo_box_new ();
1025 gtk_label_set_mnemonic_widget (label
, widget
);
1026 gtk_box_pack_start (box
, widget
, FALSE
, FALSE
, 0);
1027 searchbar
->priv
->scope_combo_box
= widget
;
1028 gtk_widget_show (widget
);
1030 /* Use G_CONNECT_AFTER here so the EActionComboBox has a
1031 * chance to update its radio actions before we go sifting
1032 * through the radio group for the current action. */
1033 g_signal_connect_data (
1035 G_CALLBACK (shell_searchbar_save_search_scope
),
1036 searchbar
, (GClosureNotify
) NULL
,
1037 G_CONNECT_AFTER
| G_CONNECT_SWAPPED
);
1041 * e_shell_searchbar_new:
1042 * @shell_view: an #EShellView
1044 * Creates a new #EShellSearchbar instance.
1046 * Returns: a new #EShellSearchbar instance
1049 e_shell_searchbar_new (EShellView
*shell_view
)
1051 g_return_val_if_fail (E_IS_SHELL_VIEW (shell_view
), NULL
);
1053 return g_object_new (
1054 E_TYPE_SHELL_SEARCHBAR
,
1055 "shell-view", shell_view
,
1056 "orientation", GTK_ORIENTATION_HORIZONTAL
,
1061 * e_shell_searchbar_get_shell_view:
1062 * @searchbar: an #EShellSearchbar
1064 * Returns the #EShellView that was passed to e_shell_searchbar_new().
1066 * Returns: the #EShellView to which @searchbar belongs
1069 e_shell_searchbar_get_shell_view (EShellSearchbar
*searchbar
)
1071 g_return_val_if_fail (E_IS_SHELL_SEARCHBAR (searchbar
), NULL
);
1073 return E_SHELL_VIEW (searchbar
->priv
->shell_view
);
1077 e_shell_searchbar_get_filter_combo_box (EShellSearchbar
*searchbar
)
1079 g_return_val_if_fail (E_IS_SHELL_SEARCHBAR (searchbar
), NULL
);
1081 return E_ACTION_COMBO_BOX (searchbar
->priv
->filter_combo_box
);
1085 e_shell_searchbar_get_filter_visible (EShellSearchbar
*searchbar
)
1087 g_return_val_if_fail (E_IS_SHELL_SEARCHBAR (searchbar
), FALSE
);
1089 return searchbar
->priv
->filter_visible
;
1093 e_shell_searchbar_set_filter_visible (EShellSearchbar
*searchbar
,
1094 gboolean filter_visible
)
1096 g_return_if_fail (E_IS_SHELL_SEARCHBAR (searchbar
));
1098 if (searchbar
->priv
->filter_visible
== filter_visible
)
1101 searchbar
->priv
->filter_visible
= filter_visible
;
1103 /* If we're hiding the filter combo box, reset it to its
1104 * first item so that no content gets permanently hidden. */
1105 if (!filter_visible
) {
1106 EActionComboBox
*combo_box
;
1108 combo_box
= e_shell_searchbar_get_filter_combo_box (searchbar
);
1109 gtk_combo_box_set_active (GTK_COMBO_BOX (combo_box
), 0);
1112 g_object_notify (G_OBJECT (searchbar
), "filter-visible");
1116 e_shell_searchbar_get_search_hint (EShellSearchbar
*searchbar
)
1120 g_return_val_if_fail (E_IS_SHELL_SEARCHBAR (searchbar
), NULL
);
1122 entry
= GTK_ENTRY (searchbar
->priv
->search_entry
);
1124 return gtk_entry_get_placeholder_text (entry
);
1128 e_shell_searchbar_set_search_hint (EShellSearchbar
*searchbar
,
1129 const gchar
*search_hint
)
1133 g_return_if_fail (E_IS_SHELL_SEARCHBAR (searchbar
));
1135 entry
= GTK_ENTRY (searchbar
->priv
->search_entry
);
1137 if (g_strcmp0 (gtk_entry_get_placeholder_text (entry
), search_hint
) == 0)
1140 gtk_entry_set_placeholder_text (entry
, search_hint
);
1142 g_object_notify (G_OBJECT (searchbar
), "search-hint");
1146 e_shell_searchbar_get_search_option (EShellSearchbar
*searchbar
)
1148 g_return_val_if_fail (E_IS_SHELL_SEARCHBAR (searchbar
), NULL
);
1150 return searchbar
->priv
->search_option
;
1154 e_shell_searchbar_set_search_option (EShellSearchbar
*searchbar
,
1155 GtkRadioAction
*search_option
)
1157 g_return_if_fail (E_IS_SHELL_SEARCHBAR (searchbar
));
1159 if (searchbar
->priv
->search_option
== search_option
)
1162 if (search_option
!= NULL
) {
1163 g_return_if_fail (GTK_IS_RADIO_ACTION (search_option
));
1164 g_object_ref (search_option
);
1167 if (searchbar
->priv
->search_option
!= NULL
) {
1168 g_signal_handlers_disconnect_matched (
1169 searchbar
->priv
->search_option
,
1170 G_SIGNAL_MATCH_DATA
, 0, 0, NULL
, NULL
,
1172 g_object_unref (searchbar
->priv
->search_option
);
1175 searchbar
->priv
->search_option
= search_option
;
1177 if (search_option
!= NULL
)
1179 search_option
, "changed",
1180 G_CALLBACK (shell_searchbar_option_changed_cb
),
1183 g_object_notify (G_OBJECT (searchbar
), "search-option");
1187 e_shell_searchbar_get_search_text (EShellSearchbar
*searchbar
)
1191 g_return_val_if_fail (E_IS_SHELL_SEARCHBAR (searchbar
), NULL
);
1193 entry
= GTK_ENTRY (searchbar
->priv
->search_entry
);
1195 return gtk_entry_get_text (entry
);
1199 e_shell_searchbar_set_search_text (EShellSearchbar
*searchbar
,
1200 const gchar
*search_text
)
1204 g_return_if_fail (E_IS_SHELL_SEARCHBAR (searchbar
));
1206 entry
= GTK_ENTRY (searchbar
->priv
->search_entry
);
1208 /* XXX Really wish gtk_entry_set_text()
1209 * would just learn to accept NULL. */
1210 if (search_text
== NULL
)
1213 if (g_strcmp0 (gtk_entry_get_text (entry
), search_text
) == 0)
1216 gtk_entry_set_text (entry
, search_text
);
1218 shell_searchbar_update_search_widgets (searchbar
);
1220 g_object_notify (G_OBJECT (searchbar
), "search-text");
1224 e_shell_searchbar_get_search_box (EShellSearchbar
*searchbar
)
1226 g_return_val_if_fail (searchbar
!= NULL
, NULL
);
1227 g_return_val_if_fail (searchbar
->priv
!= NULL
, NULL
);
1228 g_return_val_if_fail (searchbar
->priv
->search_entry
!= NULL
, NULL
);
1230 return gtk_widget_get_parent (searchbar
->priv
->search_entry
);
1234 e_shell_searchbar_get_scope_combo_box (EShellSearchbar
*searchbar
)
1236 g_return_val_if_fail (E_IS_SHELL_SEARCHBAR (searchbar
), NULL
);
1238 return E_ACTION_COMBO_BOX (searchbar
->priv
->scope_combo_box
);
1242 e_shell_searchbar_get_scope_visible (EShellSearchbar
*searchbar
)
1244 g_return_val_if_fail (E_IS_SHELL_SEARCHBAR (searchbar
), FALSE
);
1246 return searchbar
->priv
->scope_visible
;
1250 e_shell_searchbar_set_scope_visible (EShellSearchbar
*searchbar
,
1251 gboolean scope_visible
)
1253 g_return_if_fail (E_IS_SHELL_SEARCHBAR (searchbar
));
1255 if (searchbar
->priv
->scope_visible
== scope_visible
)
1258 searchbar
->priv
->scope_visible
= scope_visible
;
1260 g_object_notify (G_OBJECT (searchbar
), "scope-visible");
1264 e_shell_searchbar_set_state_dirty (EShellSearchbar
*searchbar
)
1266 g_return_if_fail (E_IS_SHELL_SEARCHBAR (searchbar
));
1268 searchbar
->priv
->state_dirty
= TRUE
;
1272 e_shell_searchbar_get_state_group (EShellSearchbar
*searchbar
)
1274 g_return_val_if_fail (E_IS_SHELL_SEARCHBAR (searchbar
), NULL
);
1276 return searchbar
->priv
->state_group
;
1280 e_shell_searchbar_set_state_group (EShellSearchbar
*searchbar
,
1281 const gchar
*state_group
)
1283 g_return_if_fail (E_IS_SHELL_SEARCHBAR (searchbar
));
1285 if (state_group
== NULL
)
1286 state_group
= STATE_GROUP_DEFAULT
;
1288 if (g_strcmp0 (searchbar
->priv
->state_group
, state_group
) == 0)
1291 g_free (searchbar
->priv
->state_group
);
1292 searchbar
->priv
->state_group
= g_strdup (state_group
);
1294 g_object_notify (G_OBJECT (searchbar
), "state-group");
1298 idle_execute_search (gpointer shell_view
)
1300 e_shell_view_execute_search (shell_view
);
1301 g_object_unref (shell_view
);
1306 e_shell_searchbar_load_state (EShellSearchbar
*searchbar
)
1308 EShellView
*shell_view
;
1309 EShellWindow
*shell_window
;
1313 const gchar
*search_text
;
1314 const gchar
*state_group
;
1319 g_return_if_fail (E_IS_SHELL_SEARCHBAR (searchbar
));
1321 shell_view
= e_shell_searchbar_get_shell_view (searchbar
);
1322 state_group
= e_shell_searchbar_get_state_group (searchbar
);
1323 g_return_if_fail (state_group
!= NULL
);
1325 key_file
= e_shell_view_get_state_key_file (shell_view
);
1326 shell_window
= e_shell_view_get_shell_window (shell_view
);
1328 /* Changing the combo boxes triggers searches, so block
1329 * the search action until the state is fully restored. */
1330 action
= E_SHELL_WINDOW_ACTION_SEARCH_QUICK (shell_window
);
1331 gtk_action_block_activate (action
);
1333 e_shell_view_block_execute_search (shell_view
);
1335 e_shell_view_set_search_rule (shell_view
, NULL
);
1337 key
= STATE_KEY_SEARCH_FILTER
;
1338 string
= g_key_file_get_string (key_file
, state_group
, key
, NULL
);
1339 if (string
!= NULL
&& *string
!= '\0')
1340 action
= e_shell_window_get_action (shell_window
, string
);
1343 if (GTK_IS_RADIO_ACTION (action
))
1344 gtk_action_activate (action
);
1346 /* Pick the first combo box item. */
1347 widget
= searchbar
->priv
->filter_combo_box
;
1348 gtk_combo_box_set_active (GTK_COMBO_BOX (widget
), 0);
1352 /* Avoid restoring to the "Advanced Search" option, since we
1353 * don't currently save the search rule (TODO but we should). */
1354 key
= STATE_KEY_SEARCH_OPTION
;
1355 string
= g_key_file_get_string (key_file
, state_group
, key
, NULL
);
1356 if (string
!= NULL
&& *string
!= '\0')
1357 action
= e_shell_window_get_action (shell_window
, string
);
1360 if (GTK_IS_RADIO_ACTION (action
))
1361 g_object_get (action
, "value", &value
, NULL
);
1363 value
= SEARCH_OPTION_ADVANCED
;
1364 if (value
!= SEARCH_OPTION_ADVANCED
)
1365 gtk_action_activate (action
);
1366 else if (searchbar
->priv
->search_option
!= NULL
)
1367 gtk_radio_action_set_current_value (
1368 searchbar
->priv
->search_option
, 0);
1371 key
= STATE_KEY_SEARCH_TEXT
;
1372 string
= g_key_file_get_string (key_file
, state_group
, key
, NULL
);
1373 search_text
= e_shell_searchbar_get_search_text (searchbar
);
1374 if (search_text
!= NULL
&& *search_text
== '\0')
1376 if (g_strcmp0 (string
, search_text
) != 0)
1377 e_shell_searchbar_set_search_text (searchbar
, string
);
1380 /* Search scope is hard-coded to the default state group. */
1381 state_group
= STATE_GROUP_DEFAULT
;
1383 key
= STATE_KEY_SEARCH_SCOPE
;
1384 string
= g_key_file_get_string (key_file
, state_group
, key
, NULL
);
1385 if (string
!= NULL
&& *string
!= '\0')
1386 action
= e_shell_window_get_action (shell_window
, string
);
1389 if (GTK_IS_RADIO_ACTION (action
))
1390 gtk_action_activate (action
);
1392 /* Pick the first combo box item. */
1393 widget
= searchbar
->priv
->scope_combo_box
;
1394 gtk_combo_box_set_active (GTK_COMBO_BOX (widget
), 0);
1398 e_shell_view_unblock_execute_search (shell_view
);
1400 action
= E_SHELL_WINDOW_ACTION_SEARCH_QUICK (shell_window
);
1401 gtk_action_unblock_activate (action
);
1403 /* Execute the search when we have time. */
1405 g_object_ref (shell_view
);
1406 searchbar
->priv
->state_dirty
= FALSE
;
1408 /* Prioritize ahead of GTK+ redraws. */
1410 G_PRIORITY_HIGH_IDLE
,
1411 idle_execute_search
, shell_view
, NULL
);
1415 e_shell_searchbar_save_state (EShellSearchbar
*searchbar
)
1417 g_return_if_fail (E_IS_SHELL_SEARCHBAR (searchbar
));
1419 /* Skip saving state if it hasn't changed since it was loaded. */
1420 if (!searchbar
->priv
->state_dirty
)
1423 shell_searchbar_save_search_filter (searchbar
);
1425 shell_searchbar_save_search_option (searchbar
);
1427 shell_searchbar_save_search_text (searchbar
);
1429 shell_searchbar_save_search_scope (searchbar
);
1431 searchbar
->priv
->state_dirty
= FALSE
;
1435 e_shell_searchbar_search_entry_grab_focus (EShellSearchbar
*searchbar
)
1437 g_return_if_fail (E_IS_SHELL_SEARCHBAR (searchbar
));
1438 g_return_if_fail (searchbar
->priv
->search_entry
);
1440 gtk_widget_grab_focus (searchbar
->priv
->search_entry
);