evolution-3.6.4/shell/e-shell-searchbar.c

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 }