aboutsummaryrefslogtreecommitdiffstats
path: root/shell/e-shell-content.c
diff options
context:
space:
mode:
Diffstat (limited to 'shell/e-shell-content.c')
-rw-r--r--shell/e-shell-content.c1384
1 files changed, 1384 insertions, 0 deletions
diff --git a/shell/e-shell-content.c b/shell/e-shell-content.c
new file mode 100644
index 0000000000..e83bb341ef
--- /dev/null
+++ b/shell/e-shell-content.c
@@ -0,0 +1,1384 @@
+/*
+ * e-shell-content.c
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#include "e-shell-content.h"
+
+#include <glib/gi18n.h>
+
+#include <filter/rule-editor.h>
+#include <widgets/misc/e-action-combo-box.h>
+#include <widgets/misc/e-icon-entry.h>
+
+#include <e-shell-module.h>
+#include <e-shell-view.h>
+#include <e-shell-window-actions.h>
+
+#define E_SHELL_CONTENT_GET_PRIVATE(obj) \
+ (G_TYPE_INSTANCE_GET_PRIVATE \
+ ((obj), E_TYPE_SHELL_CONTENT, EShellContentPrivate))
+
+struct _EShellContentPrivate {
+
+ gpointer shell_view; /* weak pointer */
+
+ RuleContext *search_context;
+ FilterRule *search_rule;
+ gchar *system_filename;
+ gchar *user_filename;
+
+ /* Container for the following widgets */
+ GtkWidget *search_bar;
+
+ /* Search bar widgets */
+ GtkWidget *filter_label;
+ GtkWidget *filter_combo_box;
+ GtkWidget *search_label;
+ GtkWidget *search_entry;
+ GtkWidget *scope_label;
+ GtkWidget *scope_combo_box;
+
+ GtkStateType search_state;
+};
+
+enum {
+ PROP_0,
+ PROP_FILTER_ACTION,
+ PROP_FILTER_VALUE,
+ PROP_FILTER_VISIBLE,
+ PROP_SEARCH_CONTEXT,
+ PROP_SEARCH_RULE,
+ PROP_SEARCH_TEXT,
+ PROP_SEARCH_VISIBLE,
+ PROP_SCOPE_ACTION,
+ PROP_SCOPE_VALUE,
+ PROP_SCOPE_VISIBLE,
+ PROP_SHELL_VIEW
+};
+
+static gpointer parent_class;
+
+static void
+shell_content_dialog_rule_changed (GtkWidget *dialog,
+ FilterRule *rule)
+{
+ gboolean sensitive;
+
+ sensitive = (rule != NULL) && (rule->parts != NULL);
+
+ gtk_dialog_set_response_sensitive (
+ GTK_DIALOG (dialog), GTK_RESPONSE_OK, sensitive);
+ gtk_dialog_set_response_sensitive (
+ GTK_DIALOG (dialog), GTK_RESPONSE_APPLY, sensitive);
+}
+
+static void
+action_search_execute_cb (GtkAction *action,
+ EShellContent *shell_content)
+{
+ EShellView *shell_view;
+ EShellWindow *shell_window;
+ EIconEntry *icon_entry;
+ GtkStateType visual_state;
+ const gchar *search_text;
+
+ /* EShellView subclasses are responsible for actually
+ * executing the search. This is all cosmetic stuff. */
+
+ shell_view = e_shell_content_get_shell_view (shell_content);
+ shell_window = e_shell_view_get_shell_window (shell_view);
+
+ if (!e_shell_view_is_active (shell_view))
+ return;
+
+ icon_entry = E_ICON_ENTRY (shell_content->priv->search_entry);
+ search_text = e_shell_content_get_search_text (shell_content);
+
+ if (search_text != NULL && *search_text != '\0')
+ visual_state = GTK_STATE_SELECTED;
+ else
+ visual_state = GTK_STATE_NORMAL;
+
+ e_icon_entry_set_visual_state (icon_entry, visual_state);
+
+ action = E_SHELL_WINDOW_ACTION_SEARCH_CLEAR (shell_window);
+ gtk_action_set_sensitive (action, TRUE);
+
+ action = E_SHELL_WINDOW_ACTION_SEARCH_SAVE (shell_window);
+ gtk_action_set_sensitive (action, TRUE);
+
+ /* Direct the focus away from the search entry, so that a
+ * focus-in event is required before the text can be changed.
+ * This will reset the entry to the appropriate visual state. */
+ gtk_widget_grab_focus (gtk_bin_get_child (GTK_BIN (shell_content)));
+}
+
+static void
+shell_content_entry_activated_cb (EShellContent *shell_content,
+ GtkWidget *entry)
+{
+ EShellWindow *shell_window;
+ EShellView *shell_view;
+ GtkAction *action;
+
+ shell_view = e_shell_content_get_shell_view (shell_content);
+ shell_window = e_shell_view_get_shell_window (shell_view);
+
+ /* Verify the shell view is active before proceeding. */
+ if (!e_shell_view_is_active (shell_view))
+ return;
+
+ action = E_SHELL_WINDOW_ACTION_SEARCH_EXECUTE (shell_window);
+ gtk_action_activate (action);
+}
+
+static gboolean
+shell_content_entry_focus_in_cb (EShellContent *shell_content,
+ GdkEventFocus *focus_event,
+ GtkWidget *entry)
+{
+ EIconEntry *icon_entry;
+ GtkStateType visual_state;
+
+ icon_entry = E_ICON_ENTRY (shell_content->priv->search_entry);
+ visual_state = e_icon_entry_get_visual_state (icon_entry);
+
+ if (visual_state == GTK_STATE_INSENSITIVE)
+ gtk_entry_set_text (GTK_ENTRY (entry), "");
+
+ e_icon_entry_set_visual_state (icon_entry, GTK_STATE_NORMAL);
+
+ return FALSE;
+}
+
+static gboolean
+shell_content_entry_focus_out_cb (EShellContent *shell_content,
+ GdkEventFocus *focus_event,
+ GtkWidget *entry)
+{
+ /* FIXME */
+ return FALSE;
+}
+
+static gboolean
+shell_content_entry_key_press_cb (EShellContent *shell_content,
+ GdkEventKey *key_event,
+ GtkWidget *entry)
+{
+ EShellView *shell_view;
+ EShellWindow *shell_window;
+ GtkAction *action;
+ guint mask;
+
+ mask = gtk_accelerator_get_default_mod_mask ();
+ if ((key_event->state & mask) != GDK_MOD1_MASK)
+ return FALSE;
+
+ if (key_event->keyval != GDK_Down)
+ return FALSE;
+
+ shell_view = e_shell_content_get_shell_view (shell_content);
+ shell_window = e_shell_view_get_shell_window (shell_view);
+
+ action = E_SHELL_WINDOW_ACTION_SEARCH_OPTIONS (shell_window);
+ gtk_action_activate (action);
+
+ return TRUE;
+}
+
+static void
+shell_content_init_search_context (EShellContent *shell_content)
+{
+ EShellContentClass *shell_content_class;
+ EShellView *shell_view;
+ EShellViewClass *shell_view_class;
+ EShellModule *shell_module;
+ RuleContext *context;
+ FilterRule *rule;
+ FilterPart *part;
+ gchar *system_filename;
+ gchar *user_filename;
+
+ shell_view = e_shell_content_get_shell_view (shell_content);
+ shell_module = e_shell_view_get_shell_module (shell_view);
+ shell_view_class = E_SHELL_VIEW_GET_CLASS (shell_view);
+ g_return_if_fail (shell_view_class->search_rules != NULL);
+
+ shell_content_class = E_SHELL_CONTENT_GET_CLASS (shell_content);
+ g_return_if_fail (shell_content_class->new_search_context != NULL);
+
+ /* The basename for built-in searches is specified in the
+ * shell view class. All built-in search rules live in the
+ * same directory. */
+ system_filename = g_build_filename (
+ EVOLUTION_RULEDIR, shell_view_class->search_rules, NULL);
+
+ /* The filename for custom saved searches is always of
+ * the form "$(shell_module_data_dir)/searches.xml". */
+ user_filename = g_build_filename (
+ e_shell_module_get_data_dir (shell_module),
+ "searches.xml", NULL);
+
+ context = shell_content_class->new_search_context ();
+ rule_context_add_part_set (
+ context, "partset", FILTER_TYPE_PART,
+ rule_context_add_part, rule_context_next_part);
+ rule_context_add_rule_set (
+ context, "ruleset", FILTER_TYPE_RULE,
+ rule_context_add_rule, rule_context_next_rule);
+ rule_context_load (context, system_filename, user_filename);
+
+ /* XXX Not sure why this is necessary. */
+ g_object_set_data_full (
+ G_OBJECT (context), "system",
+ g_strdup (system_filename), g_free);
+ g_object_set_data_full (
+ G_OBJECT (context), "user",
+ g_strdup (user_filename), g_free);
+
+ rule = filter_rule_new ();
+ part = rule_context_next_part (context, NULL);
+ if (part == NULL)
+ g_warning (
+ "Could not load %s search: no parts",
+ e_shell_view_get_name (shell_view));
+ else
+ filter_rule_add_part (rule, filter_part_clone (part));
+
+ shell_content->priv->search_context = context;
+ shell_content->priv->system_filename = system_filename;
+ shell_content->priv->user_filename = user_filename;
+}
+
+static void
+shell_content_set_shell_view (EShellContent *shell_content,
+ EShellView *shell_view)
+{
+ g_return_if_fail (shell_content->priv->shell_view == NULL);
+
+ shell_content->priv->shell_view = shell_view;
+
+ g_object_add_weak_pointer (
+ G_OBJECT (shell_view),
+ &shell_content->priv->shell_view);
+}
+
+static void
+shell_content_set_property (GObject *object,
+ guint property_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ switch (property_id) {
+ case PROP_FILTER_ACTION:
+ e_shell_content_set_filter_action (
+ E_SHELL_CONTENT (object),
+ g_value_get_object (value));
+ return;
+
+ case PROP_FILTER_VALUE:
+ e_shell_content_set_filter_value (
+ E_SHELL_CONTENT (object),
+ g_value_get_int (value));
+ return;
+
+ case PROP_FILTER_VISIBLE:
+ e_shell_content_set_filter_visible (
+ E_SHELL_CONTENT (object),
+ g_value_get_boolean (value));
+ return;
+
+ case PROP_SEARCH_RULE:
+ e_shell_content_set_search_rule (
+ E_SHELL_CONTENT (object),
+ g_value_get_object (value));
+ return;
+
+ case PROP_SEARCH_TEXT:
+ e_shell_content_set_search_text (
+ E_SHELL_CONTENT (object),
+ g_value_get_string (value));
+ return;
+
+ case PROP_SEARCH_VISIBLE:
+ e_shell_content_set_search_visible (
+ E_SHELL_CONTENT (object),
+ g_value_get_boolean (value));
+ return;
+
+ case PROP_SCOPE_ACTION:
+ e_shell_content_set_scope_action (
+ E_SHELL_CONTENT (object),
+ g_value_get_object (value));
+ return;
+
+ case PROP_SCOPE_VALUE:
+ e_shell_content_set_scope_value (
+ E_SHELL_CONTENT (object),
+ g_value_get_int (value));
+ return;
+
+ case PROP_SCOPE_VISIBLE:
+ e_shell_content_set_scope_visible (
+ E_SHELL_CONTENT (object),
+ g_value_get_boolean (value));
+ return;
+
+ case PROP_SHELL_VIEW:
+ shell_content_set_shell_view (
+ E_SHELL_CONTENT (object),
+ g_value_get_object (value));
+ return;
+ }
+
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+}
+
+static void
+shell_content_get_property (GObject *object,
+ guint property_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ switch (property_id) {
+ case PROP_FILTER_ACTION:
+ g_value_set_object (
+ value, e_shell_content_get_filter_action (
+ E_SHELL_CONTENT (object)));
+ return;
+
+ case PROP_FILTER_VALUE:
+ g_value_set_int (
+ value, e_shell_content_get_filter_value (
+ E_SHELL_CONTENT (object)));
+ return;
+
+ case PROP_FILTER_VISIBLE:
+ g_value_set_boolean (
+ value, e_shell_content_get_filter_visible (
+ E_SHELL_CONTENT (object)));
+ return;
+
+ case PROP_SEARCH_CONTEXT:
+ g_value_set_object (
+ value, e_shell_content_get_search_context (
+ E_SHELL_CONTENT (object)));
+ return;
+
+ case PROP_SEARCH_RULE:
+ g_value_set_object (
+ value, e_shell_content_get_search_rule (
+ E_SHELL_CONTENT (object)));
+ return;
+
+ case PROP_SEARCH_TEXT:
+ g_value_set_string (
+ value, e_shell_content_get_search_text (
+ E_SHELL_CONTENT (object)));
+ return;
+
+ case PROP_SEARCH_VISIBLE:
+ g_value_set_boolean (
+ value, e_shell_content_get_search_visible (
+ E_SHELL_CONTENT (object)));
+ return;
+
+ case PROP_SCOPE_ACTION:
+ g_value_set_object (
+ value, e_shell_content_get_scope_action (
+ E_SHELL_CONTENT (object)));
+ return;
+
+ case PROP_SCOPE_VALUE:
+ g_value_set_int (
+ value, e_shell_content_get_scope_value (
+ E_SHELL_CONTENT (object)));
+ return;
+
+ case PROP_SCOPE_VISIBLE:
+ g_value_set_boolean (
+ value, e_shell_content_get_scope_visible (
+ E_SHELL_CONTENT (object)));
+ return;
+
+ case PROP_SHELL_VIEW:
+ g_value_set_object (
+ value, e_shell_content_get_shell_view (
+ E_SHELL_CONTENT (object)));
+ return;
+ }
+
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+}
+
+static void
+shell_content_dispose (GObject *object)
+{
+ EShellContentPrivate *priv;
+
+ priv = E_SHELL_CONTENT_GET_PRIVATE (object);
+
+ if (priv->shell_view != NULL) {
+ g_object_remove_weak_pointer (
+ G_OBJECT (priv->shell_view), &priv->shell_view);
+ priv->shell_view = NULL;
+ }
+
+ if (priv->filter_label != NULL) {
+ g_object_unref (priv->filter_label);
+ priv->filter_label = NULL;
+ }
+
+ if (priv->filter_combo_box != NULL) {
+ g_object_unref (priv->filter_combo_box);
+ priv->filter_combo_box = NULL;
+ }
+
+ if (priv->search_context != NULL) {
+ g_object_unref (priv->search_context);
+ priv->search_context = NULL;
+ }
+
+ if (priv->search_label != NULL) {
+ g_object_unref (priv->search_label);
+ priv->search_label = NULL;
+ }
+
+ if (priv->search_entry != NULL) {
+ g_object_unref (priv->search_entry);
+ priv->search_entry = NULL;
+ }
+
+ if (priv->scope_label != NULL) {
+ g_object_unref (priv->scope_label);
+ priv->scope_label = NULL;
+ }
+
+ if (priv->scope_combo_box != NULL) {
+ g_object_unref (priv->scope_combo_box);
+ priv->scope_combo_box = NULL;
+ }
+
+ /* Chain up to parent's dispose() method. */
+ G_OBJECT_CLASS (parent_class)->dispose (object);
+}
+
+static void
+shell_content_finalize (GObject *object)
+{
+ EShellContentPrivate *priv;
+
+ priv = E_SHELL_CONTENT_GET_PRIVATE (object);
+
+ g_free (priv->system_filename);
+ g_free (priv->user_filename);
+
+ /* Chain up to parent's finalize() method. */
+ G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static void
+shell_content_constructed (GObject *object)
+{
+ EShellView *shell_view;
+ EShellWindow *shell_window;
+ EShellContent *shell_content;
+ EIconEntry *icon_entry;
+ GtkSizeGroup *size_group;
+ GtkAction *action;
+ GtkWidget *widget;
+
+ shell_content = E_SHELL_CONTENT (object);
+ shell_view = e_shell_content_get_shell_view (shell_content);
+ shell_window = e_shell_view_get_shell_window (shell_view);
+ icon_entry = E_ICON_ENTRY (shell_content->priv->search_entry);
+ size_group = e_shell_view_get_size_group (shell_view);
+
+ action = E_SHELL_WINDOW_ACTION_SEARCH_CLEAR (shell_window);
+ e_icon_entry_add_action_end (icon_entry, action);
+
+ action = E_SHELL_WINDOW_ACTION_SEARCH_EXECUTE (shell_window);
+ g_signal_connect (
+ action, "activate",
+ G_CALLBACK (action_search_execute_cb), shell_content);
+
+ action = E_SHELL_WINDOW_ACTION_SEARCH_OPTIONS (shell_window);
+ e_icon_entry_add_action_start (icon_entry, action);
+
+ widget = shell_content->priv->search_bar;
+ gtk_size_group_add_widget (size_group, widget);
+
+ shell_content_init_search_context (shell_content);
+}
+
+static void
+shell_content_size_request (GtkWidget *widget,
+ GtkRequisition *requisition)
+{
+ EShellContentPrivate *priv;
+ GtkRequisition child_requisition;
+ GtkWidget *child;
+
+ priv = E_SHELL_CONTENT_GET_PRIVATE (widget);
+
+ requisition->width = 0;
+ requisition->height = 0;
+
+ child = gtk_bin_get_child (GTK_BIN (widget));
+ gtk_widget_size_request (child, requisition);
+
+ child = priv->search_bar;
+ gtk_widget_size_request (child, &child_requisition);
+ requisition->width = MAX (requisition->width, child_requisition.width);
+ requisition->height += child_requisition.height;
+}
+
+static void
+shell_content_size_allocate (GtkWidget *widget,
+ GtkAllocation *allocation)
+{
+ EShellContentPrivate *priv;
+ GtkAllocation child_allocation;
+ GtkRequisition child_requisition;
+ GtkWidget *child;
+
+ priv = E_SHELL_CONTENT_GET_PRIVATE (widget);
+
+ widget->allocation = *allocation;
+
+ child = priv->search_bar;
+ gtk_widget_size_request (child, &child_requisition);
+
+ child_allocation.x = allocation->x;
+ child_allocation.y = allocation->y;
+ child_allocation.width = allocation->width;
+ child_allocation.height = child_requisition.height;
+
+ gtk_widget_size_allocate (child, &child_allocation);
+
+ child_allocation.y += child_requisition.height;
+ child_allocation.height =
+ allocation->height - child_requisition.height;
+
+ child = gtk_bin_get_child (GTK_BIN (widget));
+ if (child != NULL)
+ gtk_widget_size_allocate (child, &child_allocation);
+}
+
+static void
+shell_content_remove (GtkContainer *container,
+ GtkWidget *widget)
+{
+ EShellContentPrivate *priv;
+
+ priv = E_SHELL_CONTENT_GET_PRIVATE (container);
+
+ /* Look in the internal widgets first. */
+
+ if (widget == priv->search_bar) {
+ gtk_widget_unparent (priv->search_bar);
+ gtk_widget_queue_resize (GTK_WIDGET (container));
+ return;
+ }
+
+ /* Chain up to parent's remove() method. */
+ GTK_CONTAINER_CLASS (parent_class)->remove (container, widget);
+}
+
+static void
+shell_content_forall (GtkContainer *container,
+ gboolean include_internals,
+ GtkCallback callback,
+ gpointer callback_data)
+{
+ EShellContentPrivate *priv;
+
+ priv = E_SHELL_CONTENT_GET_PRIVATE (container);
+
+ if (include_internals)
+ callback (priv->search_bar, callback_data);
+
+ /* Chain up to parent's forall() method. */
+ GTK_CONTAINER_CLASS (parent_class)->forall (
+ container, include_internals, callback, callback_data);
+}
+
+static void
+shell_content_class_init (EShellContentClass *class)
+{
+ GObjectClass *object_class;
+ GtkWidgetClass *widget_class;
+ GtkContainerClass *container_class;
+
+ parent_class = g_type_class_peek_parent (class);
+ g_type_class_add_private (class, sizeof (EShellContentPrivate));
+
+ object_class = G_OBJECT_CLASS (class);
+ object_class->set_property = shell_content_set_property;
+ object_class->get_property = shell_content_get_property;
+ object_class->dispose = shell_content_dispose;
+ object_class->finalize = shell_content_finalize;
+ object_class->constructed = shell_content_constructed;
+
+ widget_class = GTK_WIDGET_CLASS (class);
+ widget_class->size_request = shell_content_size_request;
+ widget_class->size_allocate = shell_content_size_allocate;
+
+ container_class = GTK_CONTAINER_CLASS (class);
+ container_class->remove = shell_content_remove;
+ container_class->forall = shell_content_forall;
+
+ class->new_search_context = rule_context_new;
+
+ g_object_class_install_property (
+ object_class,
+ PROP_FILTER_ACTION,
+ g_param_spec_object (
+ "filter-action",
+ NULL,
+ NULL,
+ GTK_TYPE_RADIO_ACTION,
+ G_PARAM_READWRITE));
+
+ g_object_class_install_property (
+ object_class,
+ PROP_FILTER_VALUE,
+ g_param_spec_int (
+ "filter-value",
+ NULL,
+ NULL,
+ G_MININT,
+ G_MAXINT,
+ 0,
+ G_PARAM_READWRITE));
+
+ g_object_class_install_property (
+ object_class,
+ PROP_FILTER_VISIBLE,
+ g_param_spec_boolean (
+ "filter-visible",
+ NULL,
+ NULL,
+ TRUE,
+ G_PARAM_READWRITE |
+ G_PARAM_CONSTRUCT));
+
+ g_object_class_install_property (
+ object_class,
+ PROP_SEARCH_CONTEXT,
+ g_param_spec_object (
+ "search-context",
+ NULL,
+ NULL,
+ RULE_TYPE_CONTEXT,
+ G_PARAM_READABLE));
+
+ g_object_class_install_property (
+ object_class,
+ PROP_SEARCH_RULE,
+ g_param_spec_object (
+ "search-rule",
+ NULL,
+ NULL,
+ FILTER_TYPE_RULE,
+ G_PARAM_READWRITE));
+
+ g_object_class_install_property (
+ object_class,
+ PROP_SEARCH_TEXT,
+ g_param_spec_string (
+ "search-text",
+ NULL,
+ NULL,
+ NULL,
+ G_PARAM_READWRITE));
+
+ g_object_class_install_property (
+ object_class,
+ PROP_SEARCH_VISIBLE,
+ g_param_spec_boolean (
+ "search-visible",
+ NULL,
+ NULL,
+ TRUE,
+ G_PARAM_READWRITE |
+ G_PARAM_CONSTRUCT));
+
+ g_object_class_install_property (
+ object_class,
+ PROP_SCOPE_ACTION,
+ g_param_spec_object (
+ "scope-action",
+ NULL,
+ NULL,
+ GTK_TYPE_RADIO_ACTION,
+ G_PARAM_READWRITE));
+
+ g_object_class_install_property (
+ object_class,
+ PROP_SCOPE_VALUE,
+ g_param_spec_int (
+ "scope-value",
+ NULL,
+ NULL,
+ G_MININT,
+ G_MAXINT,
+ 0,
+ G_PARAM_READWRITE));
+
+ g_object_class_install_property (
+ object_class,
+ PROP_SCOPE_VISIBLE,
+ g_param_spec_boolean (
+ "scope-visible",
+ NULL,
+ NULL,
+ FALSE,
+ G_PARAM_READWRITE |
+ G_PARAM_CONSTRUCT));
+
+ g_object_class_install_property (
+ object_class,
+ PROP_SHELL_VIEW,
+ g_param_spec_object (
+ "shell-view",
+ NULL,
+ NULL,
+ E_TYPE_SHELL_VIEW,
+ G_PARAM_READWRITE |
+ G_PARAM_CONSTRUCT_ONLY));
+}
+
+static void
+shell_content_init (EShellContent *shell_content)
+{
+ GtkBox *box;
+ GtkLabel *label;
+ GtkWidget *mnemonic;
+ GtkWidget *widget;
+ EIconEntry *icon_entry;
+
+ shell_content->priv = E_SHELL_CONTENT_GET_PRIVATE (shell_content);
+
+ GTK_WIDGET_SET_FLAGS (shell_content, GTK_NO_WINDOW);
+
+ /*** Build the Search Bar ***/
+
+ widget = gtk_hbox_new (FALSE, 3);
+ gtk_widget_set_parent (widget, GTK_WIDGET (shell_content));
+ shell_content->priv->search_bar = g_object_ref_sink (widget);
+ gtk_widget_show (widget);
+
+ box = GTK_BOX (widget);
+
+ /* Filter Combo Widgets */
+
+ /* Translators: The "Show:" label precedes a combo box that
+ * allows the user to filter the current view. Examples of
+ * items that appear in the combo box are "Unread Messages",
+ * "Important Messages", or "Active Appointments". */
+ widget = gtk_label_new_with_mnemonic (_("Sho_w:"));
+ gtk_box_pack_start (box, widget, FALSE, FALSE, 0);
+ shell_content->priv->filter_label = g_object_ref (widget);
+ gtk_widget_show (widget);
+
+ label = GTK_LABEL (widget);
+
+ widget = e_action_combo_box_new ();
+ gtk_label_set_mnemonic_widget (label, widget);
+ gtk_box_pack_start (box, widget, FALSE, FALSE, 0);
+ shell_content->priv->filter_combo_box = g_object_ref (widget);
+ gtk_widget_show (widget);
+
+ /* Scope Combo Widgets */
+
+ widget = e_action_combo_box_new ();
+ gtk_box_pack_end (box, widget, FALSE, FALSE, 0);
+ shell_content->priv->scope_combo_box = g_object_ref (widget);
+ gtk_widget_show (widget);
+
+ mnemonic = widget;
+
+ /* Translators: This is part of the quick search interface.
+ * example: Search: [_______________] in [ Current Folder ] */
+ widget = gtk_label_new_with_mnemonic (_("i_n"));
+ gtk_label_set_mnemonic_widget (GTK_LABEL (widget), mnemonic);
+ gtk_box_pack_end (box, widget, FALSE, FALSE, 0);
+ shell_content->priv->scope_label = g_object_ref (widget);
+ gtk_widget_show (widget);
+
+ /* Search Entry Widgets */
+
+ widget = e_icon_entry_new ();
+ gtk_box_pack_end (box, widget, FALSE, FALSE, 0);
+ shell_content->priv->search_entry = g_object_ref (widget);
+ shell_content->priv->search_state = GTK_STATE_NORMAL;
+ gtk_widget_show (widget);
+
+ icon_entry = E_ICON_ENTRY (widget);
+
+ /* Translators: This is part of the quick search interface.
+ * example: Search: [_______________] in [ Current Folder ] */
+ widget = gtk_label_new_with_mnemonic (_("Sear_ch:"));
+ gtk_box_pack_end (box, widget, FALSE, FALSE, 0);
+ shell_content->priv->search_label = g_object_ref (widget);
+ gtk_widget_show (widget);
+
+ label = GTK_LABEL (widget);
+
+ widget = e_icon_entry_get_entry (icon_entry);
+ gtk_label_set_mnemonic_widget (label, widget);
+ g_signal_connect_swapped (
+ widget, "activate",
+ G_CALLBACK (shell_content_entry_activated_cb), shell_content);
+ g_signal_connect_swapped (
+ widget, "focus-in-event",
+ G_CALLBACK (shell_content_entry_focus_in_cb), shell_content);
+ g_signal_connect_swapped (
+ widget, "focus-out-event",
+ G_CALLBACK (shell_content_entry_focus_out_cb), shell_content);
+ g_signal_connect_swapped (
+ widget, "key-press-event",
+ G_CALLBACK (shell_content_entry_key_press_cb), shell_content);
+}
+
+GType
+e_shell_content_get_type (void)
+{
+ static GType type = 0;
+
+ if (G_UNLIKELY (type == 0)) {
+ static const GTypeInfo type_info = {
+ sizeof (EShellContentClass),
+ (GBaseInitFunc) NULL,
+ (GBaseFinalizeFunc) NULL,
+ (GClassInitFunc) shell_content_class_init,
+ (GClassFinalizeFunc) NULL,
+ NULL, /* class_data */
+ sizeof (EShellContent),
+ 0, /* n_preallocs */
+ (GInstanceInitFunc) shell_content_init,
+ NULL /* value_table */
+ };
+
+ type = g_type_register_static (
+ GTK_TYPE_BIN, "EShellContent", &type_info, 0);
+ }
+
+ return type;
+}
+
+/**
+ * e_shell_content_new:
+ * @shell_view: an #EShellView
+ *
+ * Creates a new #EShellContent instance belonging to @shell_view.
+ *
+ * Returns: a new #EShellContent instance
+ **/
+GtkWidget *
+e_shell_content_new (EShellView *shell_view)
+{
+ g_return_val_if_fail (E_IS_SHELL_VIEW (shell_view), NULL);
+
+ return g_object_new (
+ E_TYPE_SHELL_CONTENT, "shell-view", shell_view, NULL);
+}
+
+/**
+ * e_shell_content_check_state:
+ * @shell_content: an #EShellContent
+ *
+ * #EShellContent subclasses should implement the
+ * <structfield>check_state</structfield> method in #EShellContentClass
+ * to return a set of flags describing the current content selection.
+ * Subclasses are responsible for defining their own flags. This is
+ * primarily used to assist shell views with updating actions (see
+ * e_shell_view_update_actions()).
+ *
+ * Returns: a set of flags describing the current @shell_content selection
+ **/
+guint32
+e_shell_content_check_state (EShellContent *shell_content)
+{
+ EShellContentClass *shell_content_class;
+
+ g_return_val_if_fail (E_IS_SHELL_CONTENT (shell_content), 0);
+
+ shell_content_class = E_SHELL_CONTENT_GET_CLASS (shell_content);
+ g_return_val_if_fail (shell_content_class->check_state != NULL, 0);
+
+ return shell_content_class->check_state (shell_content);
+}
+
+/**
+ * e_shell_content_get_shell_view:
+ * @shell_content: an #EShellContent
+ *
+ * Returns the #EShellView that was passed to e_shell_content_new().
+ *
+ * Returns: the #EShellView to which @shell_content belongs
+ **/
+EShellView *
+e_shell_content_get_shell_view (EShellContent *shell_content)
+{
+ g_return_val_if_fail (E_IS_SHELL_CONTENT (shell_content), NULL);
+
+ return E_SHELL_VIEW (shell_content->priv->shell_view);
+}
+
+GtkRadioAction *
+e_shell_content_get_filter_action (EShellContent *shell_content)
+{
+ EActionComboBox *combo_box;
+
+ g_return_val_if_fail (E_IS_SHELL_CONTENT (shell_content), NULL);
+
+ combo_box = E_ACTION_COMBO_BOX (shell_content->priv->filter_combo_box);
+
+ return e_action_combo_box_get_action (combo_box);
+}
+
+void
+e_shell_content_set_filter_action (EShellContent *shell_content,
+ GtkRadioAction *filter_action)
+{
+ EActionComboBox *combo_box;
+
+ g_return_if_fail (E_IS_SHELL_CONTENT (shell_content));
+
+ combo_box = E_ACTION_COMBO_BOX (shell_content->priv->filter_combo_box);
+
+ e_action_combo_box_set_action (combo_box, filter_action);
+ g_object_notify (G_OBJECT (shell_content), "filter-action");
+}
+
+gint
+e_shell_content_get_filter_value (EShellContent *shell_content)
+{
+ EActionComboBox *combo_box;
+
+ g_return_val_if_fail (E_IS_SHELL_CONTENT (shell_content), 0);
+
+ combo_box = E_ACTION_COMBO_BOX (shell_content->priv->filter_combo_box);
+
+ return e_action_combo_box_get_current_value (combo_box);
+}
+
+void
+e_shell_content_set_filter_value (EShellContent *shell_content,
+ gint filter_value)
+{
+ EActionComboBox *combo_box;
+
+ g_return_if_fail (E_IS_SHELL_CONTENT (shell_content));
+
+ combo_box = E_ACTION_COMBO_BOX (shell_content->priv->filter_combo_box);
+
+ e_action_combo_box_set_current_value (combo_box, filter_value);
+ g_object_notify (G_OBJECT (shell_content), "filter-value");
+}
+
+gboolean
+e_shell_content_get_filter_visible (EShellContent *shell_content)
+{
+ g_return_val_if_fail (E_IS_SHELL_CONTENT (shell_content), FALSE);
+
+ return GTK_WIDGET_VISIBLE (shell_content->priv->filter_combo_box);
+}
+
+void
+e_shell_content_set_filter_visible (EShellContent *shell_content,
+ gboolean filter_visible)
+{
+ g_return_if_fail (E_IS_SHELL_CONTENT (shell_content));
+
+ if (filter_visible) {
+ gtk_widget_show (shell_content->priv->filter_label);
+ gtk_widget_show (shell_content->priv->filter_combo_box);
+ } else {
+ gtk_widget_hide (shell_content->priv->filter_label);
+ gtk_widget_hide (shell_content->priv->filter_combo_box);
+ }
+}
+
+void
+e_shell_content_add_filter_separator_before (EShellContent *shell_content,
+ gint action_value)
+{
+ EActionComboBox *combo_box;
+
+ g_return_if_fail (E_IS_SHELL_CONTENT (shell_content));
+
+ combo_box = E_ACTION_COMBO_BOX (shell_content->priv->filter_combo_box);
+
+ e_action_combo_box_add_separator_before (combo_box, action_value);
+}
+
+void
+e_shell_content_add_filter_separator_after (EShellContent *shell_content,
+ gint action_value)
+{
+ EActionComboBox *combo_box;
+
+ g_return_if_fail (E_IS_SHELL_CONTENT (shell_content));
+
+ combo_box = E_ACTION_COMBO_BOX (shell_content->priv->filter_combo_box);
+
+ e_action_combo_box_add_separator_after (combo_box, action_value);
+}
+
+RuleContext *
+e_shell_content_get_search_context (EShellContent *shell_content)
+{
+ g_return_val_if_fail (E_IS_SHELL_CONTENT (shell_content), NULL);
+
+ return shell_content->priv->search_context;
+}
+
+FilterRule *
+e_shell_content_get_search_rule (EShellContent *shell_content)
+{
+ g_return_val_if_fail (E_IS_SHELL_CONTENT (shell_content), NULL);
+
+ return shell_content->priv->search_rule;
+}
+
+void
+e_shell_content_set_search_rule (EShellContent *shell_content,
+ FilterRule *search_rule)
+{
+ g_return_if_fail (E_IS_SHELL_CONTENT (shell_content));
+
+ if (search_rule != NULL) {
+ g_return_if_fail (IS_FILTER_RULE (search_rule));
+ g_object_ref (search_rule);
+ }
+
+ if (shell_content->priv->search_rule != NULL)
+ g_object_unref (shell_content->priv->search_rule);
+
+ shell_content->priv->search_rule = search_rule;
+ g_object_notify (G_OBJECT (shell_content), "search-rule");
+}
+
+const gchar *
+e_shell_content_get_search_text (EShellContent *shell_content)
+{
+ EIconEntry *icon_entry;
+ GtkWidget *text_entry;
+
+ g_return_val_if_fail (E_IS_SHELL_CONTENT (shell_content), NULL);
+
+ if (shell_content->priv->search_state == GTK_STATE_INSENSITIVE)
+ return "";
+
+ icon_entry = E_ICON_ENTRY (shell_content->priv->search_entry);
+ text_entry = e_icon_entry_get_entry (icon_entry);
+
+ return gtk_entry_get_text (GTK_ENTRY (text_entry));
+}
+
+void
+e_shell_content_set_search_text (EShellContent *shell_content,
+ const gchar *search_text)
+{
+ EIconEntry *icon_entry;
+ GtkWidget *text_entry;
+
+ g_return_if_fail (E_IS_SHELL_CONTENT (shell_content));
+
+ icon_entry = E_ICON_ENTRY (shell_content->priv->search_entry);
+ text_entry = e_icon_entry_get_entry (icon_entry);
+
+ search_text = (search_text != NULL) ? search_text : "";
+ gtk_entry_set_text (GTK_ENTRY (text_entry), search_text);
+ g_object_notify (G_OBJECT (shell_content), "search-text");
+}
+
+gboolean
+e_shell_content_get_search_visible (EShellContent *shell_content)
+{
+ g_return_val_if_fail (E_IS_SHELL_CONTENT (shell_content), FALSE);
+
+ return GTK_WIDGET_VISIBLE (shell_content->priv->search_entry);
+}
+
+void
+e_shell_content_set_search_visible (EShellContent *shell_content,
+ gboolean search_visible)
+{
+ g_return_if_fail (E_IS_SHELL_CONTENT (shell_content));
+
+ if (search_visible) {
+ gtk_widget_show (shell_content->priv->search_label);
+ gtk_widget_show (shell_content->priv->search_entry);
+ } else {
+ gtk_widget_hide (shell_content->priv->search_label);
+ gtk_widget_hide (shell_content->priv->search_entry);
+ }
+}
+
+GtkRadioAction *
+e_shell_content_get_scope_action (EShellContent *shell_content)
+{
+ EActionComboBox *combo_box;
+
+ g_return_val_if_fail (E_IS_SHELL_CONTENT (shell_content), NULL);
+
+ combo_box = E_ACTION_COMBO_BOX (shell_content->priv->scope_combo_box);
+
+ return e_action_combo_box_get_action (combo_box);
+}
+
+void
+e_shell_content_set_scope_action (EShellContent *shell_content,
+ GtkRadioAction *scope_action)
+{
+ EActionComboBox *combo_box;
+
+ g_return_if_fail (E_IS_SHELL_CONTENT (shell_content));
+
+ combo_box = E_ACTION_COMBO_BOX (shell_content->priv->scope_combo_box);
+
+ e_action_combo_box_set_action (combo_box, scope_action);
+ g_object_notify (G_OBJECT (shell_content), "scope-action");
+}
+
+gint
+e_shell_content_get_scope_value (EShellContent *shell_content)
+{
+ EActionComboBox *combo_box;
+
+ g_return_val_if_fail (E_IS_SHELL_CONTENT (shell_content), 0);
+
+ combo_box = E_ACTION_COMBO_BOX (shell_content->priv->scope_combo_box);
+
+ return e_action_combo_box_get_current_value (combo_box);
+}
+
+void
+e_shell_content_set_scope_value (EShellContent *shell_content,
+ gint scope_value)
+{
+ EActionComboBox *combo_box;
+
+ g_return_if_fail (E_IS_SHELL_CONTENT (shell_content));
+
+ combo_box = E_ACTION_COMBO_BOX (shell_content->priv->scope_combo_box);
+
+ e_action_combo_box_set_current_value (combo_box, scope_value);
+ g_object_notify (G_OBJECT (shell_content), "scope-value");
+}
+
+gboolean
+e_shell_content_get_scope_visible (EShellContent *shell_content)
+{
+ g_return_val_if_fail (E_IS_SHELL_CONTENT (shell_content), FALSE);
+
+ return GTK_WIDGET_VISIBLE (shell_content->priv->scope_combo_box);
+}
+
+void
+e_shell_content_set_scope_visible (EShellContent *shell_content,
+ gboolean scope_visible)
+{
+ g_return_if_fail (E_IS_SHELL_CONTENT (shell_content));
+
+ if (scope_visible) {
+ gtk_widget_show (shell_content->priv->scope_label);
+ gtk_widget_show (shell_content->priv->scope_combo_box);
+ } else {
+ gtk_widget_hide (shell_content->priv->scope_label);
+ gtk_widget_hide (shell_content->priv->scope_combo_box);
+ }
+
+ g_object_notify (G_OBJECT (shell_content), "scope-visible");
+}
+
+void
+e_shell_content_run_advanced_search_dialog (EShellContent *shell_content)
+{
+ EShellView *shell_view;
+ EShellWindow *shell_window;
+ GtkAction *action;
+ GtkWidget *dialog;
+ GtkWidget *widget;
+ FilterRule *rule;
+ RuleContext *context;
+ const gchar *user_filename;
+ gint response;
+
+ g_return_if_fail (E_IS_SHELL_CONTENT (shell_content));
+
+ shell_view = e_shell_content_get_shell_view (shell_content);
+ shell_window = e_shell_view_get_shell_window (shell_view);
+ user_filename = shell_content->priv->user_filename;
+
+ rule = e_shell_content_get_search_rule (shell_content);
+
+ if (rule == NULL)
+ rule = filter_rule_new ();
+ else
+ rule = filter_rule_clone (rule);
+
+ context = e_shell_content_get_search_context (shell_content);
+ widget = filter_rule_get_widget (rule, context);
+ filter_rule_set_source (rule, FILTER_SOURCE_INCOMING);
+
+ dialog = gtk_dialog_new_with_buttons (
+ _("Advanced Search"), GTK_WINDOW (shell_window),
+ GTK_DIALOG_DESTROY_WITH_PARENT | GTK_DIALOG_NO_SEPARATOR,
+ GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
+ GTK_STOCK_SAVE, GTK_RESPONSE_APPLY,
+ GTK_STOCK_OK, GTK_RESPONSE_OK, NULL);
+
+ gtk_container_set_border_width (GTK_CONTAINER (dialog), 7);
+ gtk_container_set_border_width (GTK_CONTAINER (widget), 3);
+ gtk_window_set_default_size (GTK_WINDOW (dialog), 600, 300);
+
+ gtk_box_pack_start (
+ GTK_BOX (GTK_DIALOG (dialog)->vbox), widget, TRUE, TRUE, 0);
+
+ g_signal_connect_swapped (
+ rule, "changed", G_CALLBACK (
+ shell_content_dialog_rule_changed), dialog);
+
+ shell_content_dialog_rule_changed (dialog, rule);
+
+run:
+ response = gtk_dialog_run (GTK_DIALOG (dialog));
+
+ if (response != GTK_RESPONSE_OK && response != GTK_RESPONSE_APPLY)
+ goto exit;
+
+ if (!filter_rule_validate (rule))
+ goto run;
+
+ e_shell_content_set_search_rule (shell_content, rule);
+
+ action = E_SHELL_WINDOW_ACTION_SEARCH_EXECUTE (shell_window);
+ gtk_action_activate (action);
+
+ if (response == GTK_RESPONSE_APPLY) {
+ if (!rule_context_find_rule (context, rule->name, rule->source))
+ rule_context_add_rule (context, rule);
+ rule_context_save (context, user_filename);
+ goto run;
+ }
+
+exit:
+ g_object_unref (rule);
+ gtk_widget_destroy (dialog);
+}
+
+void
+e_shell_content_run_edit_searches_dialog (EShellContent *shell_content)
+{
+ RuleContext *context;
+ RuleEditor *editor;
+ const gchar *user_filename;
+
+ g_return_if_fail (E_IS_SHELL_CONTENT (shell_content));
+
+ context = e_shell_content_get_search_context (shell_content);
+ user_filename = shell_content->priv->user_filename;
+
+ editor = rule_editor_new (
+ context, FILTER_SOURCE_INCOMING, _("Searches"));
+ gtk_window_set_title (GTK_WINDOW (editor), _("Searches"));
+
+ if (gtk_dialog_run (GTK_DIALOG (editor)) == GTK_RESPONSE_OK)
+ rule_context_save (context, user_filename);
+
+ gtk_widget_destroy (GTK_WIDGET (editor));
+}
+
+void
+e_shell_content_run_save_search_dialog (EShellContent *shell_content)
+{
+ EShellView *shell_view;
+ EShellWindow *shell_window;
+ GtkWidget *dialog;
+ GtkWidget *widget;
+ FilterRule *rule;
+ RuleContext *context;
+ const gchar *search_text;
+ const gchar *user_filename;
+ gchar *search_name;
+ gint response;
+
+ g_return_if_fail (E_IS_SHELL_CONTENT (shell_content));
+
+ shell_view = e_shell_content_get_shell_view (shell_content);
+ shell_window = e_shell_view_get_shell_window (shell_view);
+ user_filename = shell_content->priv->user_filename;
+
+ rule = e_shell_content_get_search_rule (shell_content);
+ g_return_if_fail (IS_FILTER_RULE (rule));
+ rule = filter_rule_clone (rule);
+
+ search_text = e_shell_content_get_search_text (shell_content);
+ if (search_text == NULL || *search_text == '\0')
+ search_text = "''";
+
+ search_name = g_strdup_printf ("%s %s", rule->name, search_text);
+ filter_rule_set_name (rule, search_name);
+ g_free (search_name);
+
+ context = e_shell_content_get_search_context (shell_content);
+ widget = filter_rule_get_widget (rule, context);
+ filter_rule_set_source (rule, FILTER_SOURCE_INCOMING);
+
+ dialog = gtk_dialog_new_with_buttons (
+ _("Save Search"), GTK_WINDOW (shell_window),
+ GTK_DIALOG_DESTROY_WITH_PARENT | GTK_DIALOG_NO_SEPARATOR,
+ GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
+ GTK_STOCK_OK, GTK_RESPONSE_OK, NULL);
+
+ gtk_container_set_border_width (GTK_CONTAINER (dialog), 7);
+ gtk_container_set_border_width (GTK_CONTAINER (widget), 3);
+ gtk_window_set_default_size (GTK_WINDOW (dialog), 500, 300);
+
+ gtk_box_pack_start (
+ GTK_BOX (GTK_DIALOG (dialog)->vbox), widget, TRUE, TRUE, 0);
+
+ g_signal_connect_swapped (
+ rule, "changed", G_CALLBACK (
+ shell_content_dialog_rule_changed), dialog);
+
+ shell_content_dialog_rule_changed (dialog, rule);
+
+run:
+ response = gtk_dialog_run (GTK_DIALOG (dialog));
+
+ if (response != GTK_RESPONSE_OK)
+ goto exit;
+
+ if (!filter_rule_validate (rule))
+ goto run;
+
+ rule_context_add_rule (context, rule);
+ rule_context_save (context, user_filename);
+
+exit:
+ g_object_unref (rule);
+ gtk_widget_destroy (dialog);
+}