/* * 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 * * * Authors: * * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com) * */ #ifdef HAVE_CONFIG_H #include #endif #include #include #include #include "e-addressbook-model.h" #include "e-addressbook-table-adapter.h" #include "eab-book-util.h" #include "eab-contact-merging.h" #include "eab-gui-util.h" #include #include #include #define E_ADDRESSBOOK_TABLE_ADAPTER_GET_PRIVATE(obj) \ (G_TYPE_INSTANCE_GET_PRIVATE \ ((obj), E_TYPE_ADDRESSBOOK_TABLE_ADAPTER, EAddressbookTableAdapterPrivate)) struct _EAddressbookTableAdapterPrivate { EAddressbookModel *model; gint create_contact_id, remove_contact_id, modify_contact_id, model_changed_id; GHashTable *emails; }; /* Forward Declarations */ static void e_addressbook_table_adapter_table_model_init (ETableModelInterface *interface); G_DEFINE_TYPE_WITH_CODE ( EAddressbookTableAdapter, e_addressbook_table_adapter, G_TYPE_OBJECT, G_IMPLEMENT_INTERFACE ( E_TYPE_TABLE_MODEL, e_addressbook_table_adapter_table_model_init)) static void unlink_model (EAddressbookTableAdapter *adapter) { EAddressbookTableAdapterPrivate *priv = adapter->priv; g_signal_handler_disconnect (priv->model, priv->create_contact_id); g_signal_handler_disconnect (priv->model, priv->remove_contact_id); g_signal_handler_disconnect (priv->model, priv->modify_contact_id); g_signal_handler_disconnect (priv->model, priv->model_changed_id); priv->create_contact_id = 0; priv->remove_contact_id = 0; priv->modify_contact_id = 0; priv->model_changed_id = 0; g_object_unref (priv->model); priv->model = NULL; } static void addressbook_finalize (GObject *object) { EAddressbookTableAdapter *adapter; adapter = E_ADDRESSBOOK_TABLE_ADAPTER (object); unlink_model (adapter); g_hash_table_destroy (adapter->priv->emails); /* Chain up to parent's finalize() method. */ G_OBJECT_CLASS (e_addressbook_table_adapter_parent_class)->finalize (object); } /* This function returns the number of columns in our ETableModel. */ static gint addressbook_col_count (ETableModel *etc) { return E_CONTACT_FIELD_LAST; } /* This function returns the number of rows in our ETableModel. */ static gint addressbook_row_count (ETableModel *etc) { EAddressbookTableAdapter *adapter = E_ADDRESSBOOK_TABLE_ADAPTER (etc); EAddressbookTableAdapterPrivate *priv = adapter->priv; return e_addressbook_model_contact_count (priv->model); } static void addressbook_append_row (ETableModel *etm, ETableModel *source, gint row) { EAddressbookTableAdapter *adapter = E_ADDRESSBOOK_TABLE_ADAPTER (etm); EAddressbookTableAdapterPrivate *priv = adapter->priv; EClientCache *client_cache; ESourceRegistry *registry; EBookClient *book_client; EContact *contact; gint col; contact = e_contact_new (); for (col = 1; col < E_CONTACT_LAST_SIMPLE_STRING; col++) { gconstpointer val = e_table_model_value_at (source, col, row); e_contact_set (contact, col, (gpointer) val); } client_cache = e_addressbook_model_get_client_cache (priv->model); book_client = e_addressbook_model_get_client (priv->model); registry = e_client_cache_ref_registry (client_cache); eab_merging_book_add_contact ( registry, book_client, contact, NULL, NULL); g_object_unref (registry); g_object_unref (contact); } /* This function returns the value at a particular point in our ETableModel. */ static gpointer addressbook_value_at (ETableModel *etc, gint col, gint row) { EAddressbookTableAdapter *adapter = E_ADDRESSBOOK_TABLE_ADAPTER (etc); EAddressbookTableAdapterPrivate *priv = adapter->priv; EContact *contact; const gchar *value; if (col >= E_CONTACT_FIELD_LAST) return NULL; if (row >= e_addressbook_model_contact_count (priv->model)) return NULL; contact = e_addressbook_model_contact_at (priv->model, row); value = e_contact_get_const (contact, col); if (value && *value && (col == E_CONTACT_EMAIL_1 || col == E_CONTACT_EMAIL_2 || col == E_CONTACT_EMAIL_3)) { gchar *val = g_hash_table_lookup (priv->emails, value); if (val) { /* we have this already cached, so use value from the cache */ value = val; } else { gchar *name = NULL, *mail = NULL; if (eab_parse_qp_email (value, &name, &mail)) val = g_strdup_printf ("%s <%s>", name, mail); else val = g_strdup (value); g_free (name); g_free (mail); g_hash_table_insert (priv->emails, g_strdup (value), val); value = val; } } return (gpointer)(value ? value : ""); } /* This function sets the value at a particular point in our ETableModel. */ static void contact_modified_cb (EBookClient *book_client, const GError *error, gpointer user_data) { if (error) eab_error_dialog (NULL, _("Error modifying card"), error); } static void addressbook_set_value_at (ETableModel *etc, gint col, gint row, gconstpointer val) { EAddressbookTableAdapter *adapter = E_ADDRESSBOOK_TABLE_ADAPTER (etc); EAddressbookTableAdapterPrivate *priv = adapter->priv; if (e_addressbook_model_get_editable (priv->model)) { EClientCache *client_cache; ESourceRegistry *registry; EBookClient *book_client; EContact *contact; if (col >= E_CONTACT_FIELD_LAST) return; if (row >= e_addressbook_model_contact_count (priv->model)) return; contact = e_addressbook_model_get_contact (priv->model, row); if (!contact) return; e_table_model_pre_change (etc); if (col == E_CONTACT_EMAIL_1 || col == E_CONTACT_EMAIL_2 || col == E_CONTACT_EMAIL_3) { const gchar *old_value = e_contact_get_const (contact, col); /* remove old value from cache and use new one */ if (old_value && *old_value) g_hash_table_remove (priv->emails, old_value); } client_cache = e_addressbook_model_get_client_cache (priv->model); book_client = e_addressbook_model_get_client (priv->model); registry = e_client_cache_ref_registry (client_cache); e_contact_set (contact, col, (gpointer) val); eab_merging_book_modify_contact ( registry, book_client, contact, contact_modified_cb, etc); g_object_unref (registry); g_object_unref (contact); /* XXX Do we need this? Shouldn't the commit_contact * generate a changed signal? */ e_table_model_cell_changed (etc, col, row); } } /* This function returns whether a particular cell is editable. */ static gboolean addressbook_is_cell_editable (ETableModel *etc, gint col, gint row) { return FALSE; } /* This function duplicates the value passed to it. */ static gpointer addressbook_duplicate_value (ETableModel *etc, gint col, gconstpointer value) { return g_strdup (value); } /* This function frees the value passed to it. */ static void addressbook_free_value (ETableModel *etc, gint col, gpointer value) { g_free (value); } static gpointer addressbook_initialize_value (ETableModel *etc, gint col) { return g_strdup (""); } static gboolean addressbook_value_is_empty (ETableModel *etc, gint col, gconstpointer value) { return !(value && *(gchar *) value); } static gchar * addressbook_value_to_string (ETableModel *etc, gint col, gconstpointer value) { return g_strdup (value); } static void e_addressbook_table_adapter_class_init (EAddressbookTableAdapterClass *class) { GObjectClass *object_class; g_type_class_add_private ( class, sizeof (EAddressbookTableAdapterPrivate)); object_class = G_OBJECT_CLASS (class); object_class->finalize = addressbook_finalize; } static void e_addressbook_table_adapter_table_model_init (ETableModelInterface *interface) { interface->column_count = addressbook_col_count; interface->row_count = addressbook_row_count; interface->append_row = addressbook_append_row; interface->value_at = addressbook_value_at; interface->set_value_at = addressbook_set_value_at; interface->is_cell_editable = addressbook_is_cell_editable; interface->duplicate_value = addressbook_duplicate_value; interface->free_value = addressbook_free_value; interface->initialize_value = addressbook_initialize_value; interface->value_is_empty = addressbook_value_is_empty; interface->value_to_string = addressbook_value_to_string; } static void e_addressbook_table_adapter_init (EAddressbookTableAdapter *adapter) { adapter->priv = E_ADDRESSBOOK_TABLE_ADAPTER_GET_PRIVATE (adapter); } static void create_contact (EAddressbookModel *model, gint index, gint count, EAddressbookTableAdapter *adapter) { e_table_model_pre_change (E_TABLE_MODEL (adapter)); e_table_model_rows_inserted (E_TABLE_MODEL (adapter), index, count); } static void remove_contacts (EAddressbookModel *model, gpointer data, EAddressbookTableAdapter *adapter) { GArray *indices = (GArray *) data; gint count = indices->len; /* clear whole cache */ g_hash_table_remove_all (adapter->priv->emails); e_table_model_pre_change (E_TABLE_MODEL (adapter)); if (count == 1) e_table_model_rows_deleted ( E_TABLE_MODEL (adapter), g_array_index (indices, gint, 0), 1); else e_table_model_changed (E_TABLE_MODEL (adapter)); } static void modify_contact (EAddressbookModel *model, gint index, EAddressbookTableAdapter *adapter) { /* clear whole cache */ g_hash_table_remove_all (adapter->priv->emails); e_table_model_pre_change (E_TABLE_MODEL (adapter)); e_table_model_row_changed (E_TABLE_MODEL (adapter), index); } static void model_changed (EAddressbookModel *model, EAddressbookTableAdapter *adapter) { /* clear whole cache */ g_hash_table_remove_all (adapter->priv->emails); e_table_model_pre_change (E_TABLE_MODEL (adapter)); e_table_model_changed (E_TABLE_MODEL (adapter)); } void e_addressbook_table_adapter_construct (EAddressbookTableAdapter *adapter, EAddressbookModel *model) { EAddressbookTableAdapterPrivate *priv = adapter->priv; priv->model = model; g_object_ref (priv->model); priv->create_contact_id = g_signal_connect ( priv->model, "contact_added", G_CALLBACK (create_contact), adapter); priv->remove_contact_id = g_signal_connect ( priv->model, "contacts_removed", G_CALLBACK (remove_contacts), adapter); priv->modify_contact_id = g_signal_connect ( priv->model, "contact_changed", G_CALLBACK (modify_contact), adapter); priv->model_changed_id = g_signal_connect ( priv->model, "model_changed", G_CALLBACK (model_changed), adapter); priv->emails = g_hash_table_new_full ( g_str_hash, g_str_equal, (GDestroyNotify) g_free, (GDestroyNotify) g_free); } ETableModel * e_addressbook_table_adapter_new (EAddressbookModel *model) { EAddressbookTableAdapter *et; et = g_object_new (E_TYPE_ADDRESSBOOK_TABLE_ADAPTER, NULL); e_addressbook_table_adapter_construct (et, model); return E_TABLE_MODEL (et); }