aboutsummaryrefslogtreecommitdiffstats
path: root/addressbook/gui/component/e-book-shell-view-private.c
diff options
context:
space:
mode:
Diffstat (limited to 'addressbook/gui/component/e-book-shell-view-private.c')
-rw-r--r--addressbook/gui/component/e-book-shell-view-private.c621
1 files changed, 621 insertions, 0 deletions
diff --git a/addressbook/gui/component/e-book-shell-view-private.c b/addressbook/gui/component/e-book-shell-view-private.c
new file mode 100644
index 0000000000..ec3562e87a
--- /dev/null
+++ b/addressbook/gui/component/e-book-shell-view-private.c
@@ -0,0 +1,621 @@
+/*
+ * e-book-shell-view-private.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-book-shell-view-private.h"
+
+#include "widgets/menus/gal-view-factory-etable.h"
+#include "addressbook/gui/widgets/gal-view-factory-minicard.h"
+
+#include "addressbook.h"
+
+static void
+open_contact (EBookShellView *book_shell_view,
+ EContact *contact,
+ gboolean is_new_contact,
+ EAddressbookView *view)
+{
+ EAddressbookModel *model;
+ GtkWidget *editor;
+ EBook *book;
+ gboolean editable;
+
+ model = e_addressbook_view_get_model (view);
+ book = e_addressbook_model_get_book (model);
+ editable = e_addressbook_model_get_editable (model);
+
+ if (e_contact_get (contact, E_CONTACT_IS_LIST))
+ editor = e_contact_list_editor_new (
+ book, contact, is_new_contact, editable);
+ else
+ editor = e_contact_editor_new (
+ book, contact, is_new_contact, editable);
+
+ eab_editor_show (EAB_EDITOR (editor));
+}
+
+static void
+popup_event (EBookShellView *book_shell_view,
+ GdkEventButton *event)
+{
+ EShellView *shell_view;
+ const gchar *widget_path;
+
+ widget_path = "/contact-popup";
+ shell_view = E_SHELL_VIEW (book_shell_view);
+
+ e_shell_view_show_popup_menu (shell_view, widget_path, event);
+}
+
+static void
+book_shell_view_selection_change_foreach (gint row,
+ EBookShellView *book_shell_view)
+{
+ EBookShellContent *book_shell_content;
+ EAddressbookView *view;
+ EAddressbookModel *model;
+ EContact *contact;
+
+ /* XXX A "foreach" function is kind of a silly way to retrieve
+ * the one and only selected contact, but this is the only
+ * means that ESelectionModel provides. */
+
+ book_shell_content = book_shell_view->priv->book_shell_content;
+ view = e_book_shell_content_get_current_view (book_shell_content);
+ model = e_addressbook_view_get_model (view);
+ contact = e_addressbook_model_get_contact (model, row);
+
+ e_book_shell_content_set_preview_contact (book_shell_content, contact);
+}
+
+static void
+selection_change (EBookShellView *book_shell_view,
+ EAddressbookView *view)
+{
+ EBookShellContent *book_shell_content;
+ EAddressbookView *current_view;
+ ESelectionModel *selection_model;
+ EShellView *shell_view;
+ gint n_selected;
+
+ shell_view = E_SHELL_VIEW (book_shell_view);
+ book_shell_content = book_shell_view->priv->book_shell_content;
+ current_view = e_book_shell_content_get_current_view (book_shell_content);
+
+ if (view != current_view)
+ return;
+
+ e_shell_view_update_actions (shell_view);
+
+ selection_model = e_addressbook_view_get_selection_model (view);
+
+ n_selected = (selection_model != NULL) ?
+ e_selection_model_selected_count (selection_model) : 0;
+
+ if (n_selected == 1)
+ e_selection_model_foreach (
+ selection_model, (EForeachFunc)
+ book_shell_view_selection_change_foreach,
+ book_shell_view);
+ else
+ e_book_shell_content_set_preview_contact (
+ book_shell_content, NULL);
+}
+
+static void
+contact_changed (EBookShellView *book_shell_view,
+ EContact *contact)
+{
+ EBookShellContent *book_shell_content;
+ EContact *preview_contact;
+
+ book_shell_content = book_shell_view->priv->book_shell_content;
+
+ preview_contact =
+ e_book_shell_content_get_preview_contact (book_shell_content);
+
+ if (contact != preview_contact)
+ return;
+
+ /* Re-render the same contact. */
+ e_book_shell_content_set_preview_contact (book_shell_content, contact);
+}
+
+static void
+contacts_removed (EBookShellView *book_shell_view,
+ GArray *removed_indices,
+ EAddressbookModel *model)
+{
+ EBookShellContent *book_shell_content;
+ EContact *preview_contact;
+
+ book_shell_content = book_shell_view->priv->book_shell_content;
+
+ preview_contact =
+ e_book_shell_content_get_preview_contact (book_shell_content);
+
+ if (preview_contact == NULL)
+ return;
+
+ /* Is the displayed contact still in the model? */
+ if (e_addressbook_model_find (model, preview_contact) < 0)
+ return;
+
+ /* If not, clear the contact display. */
+ e_book_shell_content_set_preview_contact (book_shell_content, NULL);
+}
+
+static void
+book_open_cb (EBook *book,
+ EBookStatus status,
+ gpointer user_data)
+{
+ EAddressbookView *view = user_data;
+ EAddressbookModel *model;
+ ESource *source;
+
+ source = e_book_get_source (book);
+ model = e_addressbook_view_get_model (view);
+
+ if (status == E_BOOK_ERROR_OK) {
+ e_addressbook_model_set_book (model, book);
+ e_addressbook_model_force_folder_bar_message (model);
+ } else if (status != E_BOOK_ERROR_CANCELLED)
+ eab_load_error_dialog (NULL /* XXX */, source, status);
+}
+
+static void
+book_shell_view_activate_selected_source (EBookShellView *book_shell_view,
+ ESourceSelector *selector)
+{
+ EShellView *shell_view;
+ EBookShellContent *book_shell_content;
+ EAddressbookView *view;
+ EAddressbookModel *model;
+ ESource *source;
+ GalViewInstance *view_instance;
+ GHashTable *hash_table;
+ GtkWidget *widget;
+ const gchar *uid;
+ gchar *view_id;
+
+ shell_view = E_SHELL_VIEW (book_shell_view);
+ book_shell_content = book_shell_view->priv->book_shell_content;
+ source = e_source_selector_peek_primary_selection (selector);
+
+ if (source == NULL)
+ return;
+
+ uid = e_source_peek_uid (source);
+ hash_table = book_shell_view->priv->uid_to_view;
+ widget = g_hash_table_lookup (hash_table, uid);
+
+ if (widget != NULL) {
+ EBook *book;
+
+ /* There is a view for this UID. Make sure the view
+ * actually contains an EBook. The absence of an EBook
+ * suggests a previous load failed, so try again. */
+ view = E_ADDRESSBOOK_VIEW (widget);
+ model = e_addressbook_view_get_model (view);
+ source = e_addressbook_view_get_source (view);
+
+ if (e_addressbook_model_get_book (model) == NULL) {
+ book = e_book_new (source, NULL);
+
+ if (book != NULL)
+ addressbook_load (book, book_open_cb, view);
+ }
+
+ } else {
+ EBook *book;
+
+ /* Create a view for this UID. */
+ widget = e_addressbook_view_new (shell_view, source);
+ gtk_widget_show (widget);
+
+ e_book_shell_content_insert_view (
+ book_shell_content,
+ E_ADDRESSBOOK_VIEW (widget));
+
+ g_hash_table_insert (
+ hash_table, g_strdup (uid),
+ g_object_ref (widget));
+
+ g_signal_connect_swapped (
+ widget, "open-contact",
+ G_CALLBACK (open_contact), book_shell_view);
+
+ g_signal_connect_swapped (
+ widget, "popup-event",
+ G_CALLBACK (popup_event), book_shell_view);
+
+ g_signal_connect_swapped (
+ widget, "command-state-change",
+ G_CALLBACK (e_shell_view_update_actions),
+ book_shell_view);
+
+ g_signal_connect_swapped (
+ widget, "selection-change",
+ G_CALLBACK (selection_change), book_shell_view);
+
+ book = e_book_new (source, NULL);
+ view = E_ADDRESSBOOK_VIEW (widget);
+
+ if (book != NULL)
+ addressbook_load (book, book_open_cb, view);
+
+ model = e_addressbook_view_get_model (view);
+
+ g_signal_connect_swapped (
+ model, "contact-changed",
+ G_CALLBACK (contact_changed), book_shell_view);
+
+ g_signal_connect_swapped (
+ model, "contacts-removed",
+ G_CALLBACK (contacts_removed), book_shell_view);
+ }
+
+ e_book_shell_content_set_current_view (
+ book_shell_content, E_ADDRESSBOOK_VIEW (widget));
+
+ /* XXX We have to keep the addressbook selector informed of the
+ * current view so it can move contacts via drag-and-drop. */
+ e_addressbook_selector_set_current_view (
+ E_ADDRESSBOOK_SELECTOR (selector),
+ E_ADDRESSBOOK_VIEW (widget));
+
+ view_instance = e_addressbook_view_get_view_instance (view);
+ view_id = gal_view_instance_get_current_view_id (view_instance);
+ e_shell_view_set_view_id (shell_view, view_id);
+ g_free (view_id);
+
+ e_addressbook_model_force_folder_bar_message (model);
+ selection_change (book_shell_view, view);
+}
+
+static gboolean
+book_shell_view_show_popup_menu (GdkEventButton *event,
+ EShellView *shell_view)
+{
+ const gchar *widget_path;
+
+ widget_path = "/address-book-popup";
+ e_shell_view_show_popup_menu (shell_view, widget_path, event);
+
+ return TRUE;
+}
+
+static gboolean
+book_shell_view_selector_button_press_event_cb (EShellView *shell_view,
+ GdkEventButton *event)
+{
+ /* XXX Use ESourceSelector's "popup-event" signal instead. */
+
+ if (event->button == 3 && event->type == GDK_BUTTON_PRESS)
+ return book_shell_view_show_popup_menu (event, shell_view);
+
+ return FALSE;
+}
+
+static gboolean
+book_shell_view_selector_popup_menu_cb (EShellView *shell_view)
+{
+ /* XXX Use ESourceSelector's "popup-event" signal instead. */
+
+ return book_shell_view_show_popup_menu (NULL, shell_view);
+}
+
+static gboolean
+book_shell_view_selector_key_press_event_cb (EShellView *shell_view,
+ GdkEventKey *event)
+{
+ EShellWindow *shell_window;
+
+ /* Needed for the ACTION() macro. */
+ shell_window = e_shell_view_get_shell_window (shell_view);
+
+ if (event->keyval == GDK_Delete) {
+ gtk_action_activate (ACTION (ADDRESS_BOOK_DELETE));
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+static void
+book_shell_view_load_view_collection (EShellViewClass *shell_view_class)
+{
+ GalViewCollection *collection;
+ GalViewFactory *factory;
+ ETableSpecification *spec;
+ const gchar *base_dir;
+ gchar *filename;
+
+ collection = shell_view_class->view_collection;
+
+ base_dir = EVOLUTION_ETSPECDIR;
+ spec = e_table_specification_new ();
+ filename = g_build_filename (base_dir, ETSPEC_FILENAME, NULL);
+ if (!e_table_specification_load_from_file (spec, filename))
+ g_critical ("Unable to load ETable specification file "
+ "for address book");
+ g_free (filename);
+
+ factory = gal_view_factory_etable_new (spec);
+ gal_view_collection_add_factory (collection, factory);
+ g_object_unref (factory);
+ g_object_unref (spec);
+
+ factory = gal_view_factory_minicard_new ();
+ gal_view_collection_add_factory (collection, factory);
+ g_object_unref (factory);
+
+ gal_view_collection_load (collection);
+}
+
+static void
+book_shell_view_notify_view_id_cb (EBookShellView *book_shell_view)
+{
+ EBookShellContent *book_shell_content;
+ EAddressbookView *address_view;
+ GalViewInstance *view_instance;
+ const gchar *view_id;
+
+ book_shell_content = book_shell_view->priv->book_shell_content;
+ address_view = e_book_shell_content_get_current_view (book_shell_content);
+ view_instance = e_addressbook_view_get_view_instance (address_view);
+ view_id = e_shell_view_get_view_id (E_SHELL_VIEW (book_shell_view));
+
+ /* A NULL view ID implies we're in a custom view. But you can
+ * only get to a custom view via the "Define Views" dialog, which
+ * would have already modified the view instance appropriately.
+ * Furthermore, there's no way to refer to a custom view by ID
+ * anyway, since custom views have no IDs. */
+ if (view_id == NULL)
+ return;
+
+ gal_view_instance_set_current_view_id (view_instance, view_id);
+}
+
+void
+e_book_shell_view_private_init (EBookShellView *book_shell_view,
+ EShellViewClass *shell_view_class)
+{
+ EBookShellViewPrivate *priv = book_shell_view->priv;
+ GHashTable *uid_to_view;
+ GHashTable *uid_to_editor;
+
+ uid_to_view = g_hash_table_new_full (
+ g_str_hash, g_str_equal,
+ (GDestroyNotify) g_free,
+ (GDestroyNotify) g_object_unref);
+
+ uid_to_editor = g_hash_table_new_full (
+ g_str_hash, g_str_equal,
+ (GDestroyNotify) g_free,
+ (GDestroyNotify) g_free);
+
+ priv->uid_to_view = uid_to_view;
+ priv->uid_to_editor = uid_to_editor;
+
+ if (!gal_view_collection_loaded (shell_view_class->view_collection))
+ book_shell_view_load_view_collection (shell_view_class);
+
+ g_signal_connect (
+ book_shell_view, "notify::view-id",
+ G_CALLBACK (book_shell_view_notify_view_id_cb), NULL);
+}
+
+void
+e_book_shell_view_private_constructed (EBookShellView *book_shell_view)
+{
+ EBookShellViewPrivate *priv = book_shell_view->priv;
+ EShellContent *shell_content;
+ EShellSidebar *shell_sidebar;
+ EShellBackend *shell_backend;
+ EShellView *shell_view;
+ EShellWindow *shell_window;
+ ESourceSelector *selector;
+
+ shell_view = E_SHELL_VIEW (book_shell_view);
+ shell_backend = e_shell_view_get_shell_backend (shell_view);
+ shell_content = e_shell_view_get_shell_content (shell_view);
+ shell_sidebar = e_shell_view_get_shell_sidebar (shell_view);
+ shell_window = e_shell_view_get_shell_window (shell_view);
+
+ e_shell_window_add_action_group (shell_window, "contacts");
+ e_shell_window_add_action_group (shell_window, "contacts-filter");
+
+ /* Cache these to avoid lots of awkward casting. */
+ priv->book_shell_backend = g_object_ref (shell_backend);
+ priv->book_shell_content = g_object_ref (shell_content);
+ priv->book_shell_sidebar = g_object_ref (shell_sidebar);
+
+ selector = e_book_shell_sidebar_get_selector (
+ E_BOOK_SHELL_SIDEBAR (shell_sidebar));
+
+ g_signal_connect_swapped (
+ selector, "button-press-event",
+ G_CALLBACK (book_shell_view_selector_button_press_event_cb),
+ book_shell_view);
+
+ g_signal_connect_swapped (
+ selector, "key-press-event",
+ G_CALLBACK (book_shell_view_selector_key_press_event_cb),
+ book_shell_view);
+
+ g_signal_connect_swapped (
+ selector, "popup-menu",
+ G_CALLBACK (book_shell_view_selector_popup_menu_cb),
+ book_shell_view);
+
+ g_signal_connect_swapped (
+ selector, "primary-selection-changed",
+ G_CALLBACK (book_shell_view_activate_selected_source),
+ book_shell_view);
+
+ e_categories_register_change_listener (
+ G_CALLBACK (e_book_shell_view_update_search_filter),
+ book_shell_view);
+
+ e_book_shell_view_actions_init (book_shell_view);
+ book_shell_view_activate_selected_source (book_shell_view, selector);
+ e_book_shell_view_update_search_filter (book_shell_view);
+}
+
+void
+e_book_shell_view_private_dispose (EBookShellView *book_shell_view)
+{
+ EBookShellViewPrivate *priv = book_shell_view->priv;
+
+ DISPOSE (priv->book_shell_backend);
+ DISPOSE (priv->book_shell_content);
+ DISPOSE (priv->book_shell_sidebar);
+
+ g_hash_table_remove_all (priv->uid_to_view);
+ g_hash_table_remove_all (priv->uid_to_editor);
+}
+
+void
+e_book_shell_view_private_finalize (EBookShellView *book_shell_view)
+{
+ EBookShellViewPrivate *priv = book_shell_view->priv;
+
+ g_hash_table_destroy (priv->uid_to_view);
+ g_hash_table_destroy (priv->uid_to_editor);
+}
+
+void
+e_book_shell_view_execute_search (EBookShellView *book_shell_view)
+{
+ EBookShellContent *book_shell_content;
+ EShellView *shell_view;
+ EShellWindow *shell_window;
+ EShellContent *shell_content;
+ GtkAction *action;
+ GString *string;
+ EAddressbookView *view;
+ EAddressbookModel *model;
+ FilterRule *rule;
+ const gchar *format;
+ const gchar *text;
+ gchar *query;
+ gchar *temp;
+ gint value;
+
+ shell_view = E_SHELL_VIEW (book_shell_view);
+ if (!e_shell_view_is_active (shell_view))
+ return;
+
+ shell_content = e_shell_view_get_shell_content (shell_view);
+ text = e_shell_content_get_search_text (shell_content);
+
+ shell_window = e_shell_view_get_shell_window (shell_view);
+ action = ACTION (CONTACT_SEARCH_ANY_FIELD_CONTAINS);
+ value = gtk_radio_action_get_current_value (GTK_RADIO_ACTION (action));
+
+ if (text == NULL || *text == '\0') {
+ text = "";
+ value = CONTACT_SEARCH_ANY_FIELD_CONTAINS;
+ }
+
+ switch (value) {
+ case CONTACT_SEARCH_NAME_CONTAINS:
+ format = "(contains \"full_name\" %s)";
+ break;
+
+ case CONTACT_SEARCH_EMAIL_BEGINS_WITH:
+ format = "(beginswith \"email\" %s)";
+ break;
+
+ default:
+ text = "";
+ /* fall through */
+
+ case CONTACT_SEARCH_ANY_FIELD_CONTAINS:
+ format = "(contains \"x-evolution-any-field\" %s)";
+ break;
+ }
+
+ /* Build the query. */
+ string = g_string_new ("");
+ e_sexp_encode_string (string, text);
+ query = g_strdup_printf (format, string->str);
+ g_string_free (string, TRUE);
+
+ /* Apply selected filter. */
+ value = e_shell_content_get_filter_value (shell_content);
+ switch (value) {
+ case CONTACT_FILTER_ANY_CATEGORY:
+ break;
+
+ case CONTACT_FILTER_UNMATCHED:
+ temp = g_strdup_printf (
+ "(and (not (and (exists \"CATEGORIES\") "
+ "(not (is \"CATEGORIES\" \"\")))) %s)",
+ query);
+ g_free (query);
+ query = temp;
+ break;
+
+ default:
+ {
+ GList *categories;
+ const gchar *category_name;
+
+ categories = e_categories_get_list ();
+ category_name = g_list_nth_data (categories, value);
+ g_list_free (categories);
+
+ temp = g_strdup_printf (
+ "(and (is \"category_list\" \"%s\") %s)",
+ category_name, query);
+ g_free (query);
+ query = temp;
+ }
+ }
+
+ /* XXX This is wrong. We need to programmatically construct a
+ * FilterRule, tell it to build code, and pass the resulting
+ * expression string to EAddressbookModel. */
+ rule = filter_rule_new ();
+ e_shell_content_set_search_rule (shell_content, rule);
+ g_object_unref (rule);
+
+ /* Submit the query. */
+ book_shell_content = book_shell_view->priv->book_shell_content;
+ view = e_book_shell_content_get_current_view (book_shell_content);
+ model = e_addressbook_view_get_model (view);
+ e_addressbook_model_set_query (model, query);
+ g_free (query);
+
+ e_book_shell_content_set_preview_contact (book_shell_content, NULL);
+}
+
+void
+e_book_shell_view_editor_weak_notify (EditorUidClosure *closure,
+ GObject *where_the_object_was)
+{
+ GHashTable *hash_table;
+
+ hash_table = closure->view->priv->uid_to_editor;
+ g_hash_table_remove (hash_table, closure->uid);
+}