diff options
Diffstat (limited to 'addressbook/gui/widgets/e-addressbook-model.c')
-rw-r--r-- | addressbook/gui/widgets/e-addressbook-model.c | 1049 |
1 files changed, 595 insertions, 454 deletions
diff --git a/addressbook/gui/widgets/e-addressbook-model.c b/addressbook/gui/widgets/e-addressbook-model.c index 786c4d994d..71de495f13 100644 --- a/addressbook/gui/widgets/e-addressbook-model.c +++ b/addressbook/gui/widgets/e-addressbook-model.c @@ -22,31 +22,45 @@ #include <config.h> #include <string.h> -#include <gtk/gtk.h> #include <glib/gi18n.h> -#include "e-util/e-util.h" #include "e-addressbook-model.h" -#include <libxml/tree.h> -#include <libxml/parser.h> -#include <libxml/xmlmemory.h> +#include <e-util/e-util.h> #include <misc/e-gui-utils.h> #include "eab-gui-util.h" -#define PARENT_TYPE G_TYPE_OBJECT -static GObjectClass *parent_class; - -/* - * EABModel callbacks - * These are the callbacks that define the behavior of our custom model. - */ -static void eab_model_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec); -static void eab_model_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec); +#define E_ADDRESSBOOK_MODEL_GET_PRIVATE(obj) \ + (G_TYPE_INSTANCE_GET_PRIVATE \ + ((obj), E_TYPE_ADDRESSBOOK_MODEL, EAddressbookModelPrivate)) + +struct _EAddressbookModelPrivate { + EBook *book; + EBookQuery *query; + EBookView *book_view; + guint book_view_idle_id; + + /* Query Results */ + GPtrArray *contacts; + + /* Signal Handler IDs */ + gulong create_contact_id; + gulong remove_contact_id; + gulong modify_contact_id; + gulong status_message_id; + gulong writable_status_id; + gulong sequence_complete_id; + gulong backend_died_id; + + guint search_in_progress : 1; + guint editable : 1; + guint editable_set : 1; + guint first_get_view : 1; +}; enum { PROP_0, PROP_BOOK, - PROP_QUERY, - PROP_EDITABLE + PROP_EDITABLE, + PROP_QUERY }; enum { @@ -64,672 +78,799 @@ enum { LAST_SIGNAL }; -static guint eab_model_signals [LAST_SIGNAL] = {0, }; +static gpointer parent_class; +static guint signals[LAST_SIGNAL]; static void -free_data (EABModel *model) +free_data (EAddressbookModel *model) { - if (model->data) { - gint i; - - for ( i = 0; i < model->data_count; i++ ) { - g_object_unref (model->data[i]); - } - - g_free(model->data); - model->data = NULL; - model->data_count = 0; - model->allocated_count = 0; - } -} + GPtrArray *array; -static void -remove_book_view(EABModel *model) -{ - if (model->book_view && model->create_contact_id) - g_signal_handler_disconnect (model->book_view, - model->create_contact_id); - if (model->book_view && model->remove_contact_id) - g_signal_handler_disconnect (model->book_view, - model->remove_contact_id); - if (model->book_view && model->modify_contact_id) - g_signal_handler_disconnect (model->book_view, - model->modify_contact_id); - if (model->book_view && model->status_message_id) - g_signal_handler_disconnect (model->book_view, - model->status_message_id); - if (model->book_view && model->sequence_complete_id) - g_signal_handler_disconnect (model->book_view, - model->sequence_complete_id); - - model->create_contact_id = 0; - model->remove_contact_id = 0; - model->modify_contact_id = 0; - model->status_message_id = 0; - model->sequence_complete_id = 0; - - model->search_in_progress = FALSE; - - if (model->book_view) { - e_book_view_stop (model->book_view); - g_object_unref (model->book_view); - model->book_view = NULL; - } + array = model->priv->contacts; + g_ptr_array_foreach (array, (GFunc) g_object_unref, NULL); + g_ptr_array_set_size (array, 0); } static void -addressbook_dispose(GObject *object) +remove_book_view(EAddressbookModel *model) { - EABModel *model = EAB_MODEL(object); - - remove_book_view(model); - free_data (model); - - if (model->book) { - if (model->writable_status_id) - g_signal_handler_disconnect (model->book, - model->writable_status_id); - model->writable_status_id = 0; - - if (model->backend_died_id) - g_signal_handler_disconnect (model->book, - model->backend_died_id); - model->backend_died_id = 0; - - g_object_unref (model->book); - model->book = NULL; - } - - if (model->query) { - e_book_query_unref (model->query); - model->query = NULL; + if (model->priv->book_view && model->priv->create_contact_id) + g_signal_handler_disconnect ( + model->priv->book_view, + model->priv->create_contact_id); + if (model->priv->book_view && model->priv->remove_contact_id) + g_signal_handler_disconnect ( + model->priv->book_view, + model->priv->remove_contact_id); + if (model->priv->book_view && model->priv->modify_contact_id) + g_signal_handler_disconnect ( + model->priv->book_view, + model->priv->modify_contact_id); + if (model->priv->book_view && model->priv->status_message_id) + g_signal_handler_disconnect ( + model->priv->book_view, + model->priv->status_message_id); + if (model->priv->book_view && model->priv->sequence_complete_id) + g_signal_handler_disconnect ( + model->priv->book_view, + model->priv->sequence_complete_id); + + model->priv->create_contact_id = 0; + model->priv->remove_contact_id = 0; + model->priv->modify_contact_id = 0; + model->priv->status_message_id = 0; + model->priv->sequence_complete_id = 0; + + model->priv->search_in_progress = FALSE; + + if (model->priv->book_view) { + e_book_view_stop (model->priv->book_view); + g_object_unref (model->priv->book_view); + model->priv->book_view = NULL; } - - if (G_OBJECT_CLASS(parent_class)->dispose) - G_OBJECT_CLASS(parent_class)->dispose(object); } static void -update_folder_bar_message (EABModel *model) +update_folder_bar_message (EAddressbookModel *model) { - gint count; + guint count; gchar *message; - count = model->data_count; + count = model->priv->contacts->len; switch (count) { case 0: message = g_strdup (_("No contacts")); break; default: - message = g_strdup_printf (ngettext("%d contact", "%d contacts", count), count); + message = g_strdup_printf ( + ngettext ("%d contact", "%d contacts", count), count); break; } - g_signal_emit (model, - eab_model_signals [FOLDER_BAR_MESSAGE], 0, - message); + g_signal_emit (model, signals[FOLDER_BAR_MESSAGE], 0, message); g_free (message); } static void -create_contact(EBookView *book_view, - const GList *contacts, - EABModel *model) +create_contact (EBookView *book_view, + const GList *contact_list, + EAddressbookModel *model) { - gint old_count = model->data_count; - gint length = g_list_length ((GList *)contacts); + GPtrArray *array; + guint count; + guint index; - if (model->data_count + length > model->allocated_count) { - while (model->data_count + length > model->allocated_count) - model->allocated_count = model->allocated_count * 2 + 1; - model->data = g_renew(EContact *, model->data, model->allocated_count); - } + array = model->priv->contacts; + index = array->len; + count = g_list_length ((GList *) contact_list); - for (; contacts; contacts = contacts->next) { - model->data[model->data_count++] = contacts->data; - g_object_ref (contacts->data); - } + while (contact_list != NULL) { + EContact *contact = contact_list->data; - g_signal_emit (model, - eab_model_signals [CONTACT_ADDED], 0, - old_count, model->data_count - old_count); + g_ptr_array_add (array, g_object_ref (contact)); + contact_list = contact_list->next; + } + g_signal_emit (model, signals[CONTACT_ADDED], 0, index, count); update_folder_bar_message (model); } static void remove_contact(EBookView *book_view, GList *ids, - EABModel *model) + EAddressbookModel *model) { /* XXX we should keep a hash around instead of this O(n*m) loop */ - gint i = 0; - GList *l; + GList *iter; GArray *indices; + GPtrArray *array; + gint ii; + array = model->priv->contacts; indices = g_array_new (FALSE, FALSE, sizeof (gint)); - for (l = ids; l; l = l->next) { - gchar *id = l->data; - for ( i = 0; i < model->data_count; i++) { - if ( !strcmp(e_contact_get_const (model->data[i], E_CONTACT_UID), id) ) { - g_object_unref (model->data[i]); - memmove(model->data + i, model->data + i + 1, (model->data_count - i - 1) * sizeof (EContact *)); - model->data_count--; - g_array_append_val (indices, i); - break; + + for (iter = ids; iter != NULL; iter = iter->next) { + const gchar *target_uid = iter->data; + + for (ii = 0; ii < array->len; ii++) { + EContact *contact; + const gchar *uid; + + contact = array->pdata[ii]; + uid = e_contact_get_const (contact, E_CONTACT_UID); + if (strcmp (uid, target_uid) == 0) { + g_object_unref (contact); + g_array_append_val (indices, ii); } } } - g_signal_emit (model, - eab_model_signals [CONTACTS_REMOVED], 0, - indices); + + for (ii = 0; ii < indices->len; ii++) { + gint index; + + index = g_array_index (indices, gint, ii); + g_ptr_array_remove_index (array, index); + } + + g_signal_emit (model, signals[CONTACTS_REMOVED], 0, indices); g_array_free (indices, FALSE); + update_folder_bar_message (model); } static void modify_contact(EBookView *book_view, - const GList *contacts, - EABModel *model) -{ - for (; contacts; contacts = contacts->next) { - gint i; - for ( i = 0; i < model->data_count; i++) { - if ( !strcmp(e_contact_get_const(model->data[i], E_CONTACT_UID), - e_contact_get_const(E_CONTACT(contacts->data), E_CONTACT_UID)) ) { - g_object_unref (model->data[i]); - model->data[i] = e_contact_duplicate(E_CONTACT(contacts->data)); - g_signal_emit (model, - eab_model_signals [CONTACT_CHANGED], 0, - i); - break; - } + const GList *contact_list, + EAddressbookModel *model) +{ + GPtrArray *array; + + array = model->priv->contacts; + + while (contact_list != NULL) { + EContact *contact = contact_list->data; + const gchar *target_uid; + gint ii; + + target_uid = e_contact_get_const (contact, E_CONTACT_UID); + + for (ii = 0; ii < array->len; ii++) { + const gchar *uid; + + uid = e_contact_get_const ( + array->pdata[ii], E_CONTACT_UID); + + if (strcmp (uid, target_uid) != 0) + continue; + + g_object_unref (array->pdata[ii]); + contact = e_contact_duplicate (contact); + array->pdata[ii] = contact; + + g_signal_emit ( + model, signals[CONTACT_CHANGED], 0, ii); + break; } + + contact_list = contact_list->next; } } static void status_message (EBookView *book_view, gchar * status, - EABModel *model) + EAddressbookModel *model) { - g_signal_emit (model, - eab_model_signals [STATUS_MESSAGE], 0, - status); + g_signal_emit (model, signals[STATUS_MESSAGE], 0, status); } static void sequence_complete (EBookView *book_view, - EBookViewStatus status, - EABModel *model) + EBookViewStatus status, + EAddressbookModel *model) { - model->search_in_progress = FALSE; + model->priv->search_in_progress = FALSE; status_message (book_view, NULL, model); - g_signal_emit (model, - eab_model_signals [SEARCH_RESULT], 0, - status); - g_signal_emit (model, - eab_model_signals [STOP_STATE_CHANGED], 0); + g_signal_emit (model, signals[SEARCH_RESULT], 0, status); + g_signal_emit (model, signals[STOP_STATE_CHANGED], 0); } static void writable_status (EBook *book, gboolean writable, - EABModel *model) + EAddressbookModel *model) { - if (!model->editable_set) { - model->editable = writable; + if (!model->priv->editable_set) { + model->priv->editable = writable; - g_signal_emit (model, - eab_model_signals [WRITABLE_STATUS], 0, - writable); + g_signal_emit (model, signals[WRITABLE_STATUS], 0, writable); } } static void backend_died (EBook *book, - EABModel *model) + EAddressbookModel *model) +{ + g_signal_emit (model, signals[BACKEND_DIED], 0); +} + +static void +book_view_loaded (EBook *book, + EBookStatus status, + EBookView *book_view, + gpointer closure) +{ + EAddressbookModel *model = closure; + + if (status != E_BOOK_ERROR_OK) { + eab_error_dialog (_("Error getting book view"), status); + return; + } + + remove_book_view (model); + free_data (model); + + model->priv->book_view = book_view; + if (model->priv->book_view) + g_object_ref (model->priv->book_view); + + model->priv->create_contact_id = g_signal_connect ( + model->priv->book_view, "contacts-added", + G_CALLBACK (create_contact), model); + model->priv->remove_contact_id = g_signal_connect ( + model->priv->book_view, "contacts-removed", + G_CALLBACK (remove_contact), model); + model->priv->modify_contact_id = g_signal_connect ( + model->priv->book_view, "contacts-changed", + G_CALLBACK (modify_contact), model); + model->priv->status_message_id = g_signal_connect ( + model->priv->book_view, "status-message", + G_CALLBACK (status_message), model); + model->priv->sequence_complete_id = g_signal_connect ( + model->priv->book_view, "sequence-complete", + G_CALLBACK (sequence_complete), model); + + model->priv->search_in_progress = TRUE; + g_signal_emit (model, signals[MODEL_CHANGED], 0); + g_signal_emit (model, signals[SEARCH_STARTED], 0); + g_signal_emit (model, signals[STOP_STATE_CHANGED], 0); + + e_book_view_start (model->priv->book_view); +} + +static gboolean +addressbook_model_idle_cb (EAddressbookModel *model) +{ + model->priv->book_view_idle_id = 0; + + if (model->priv->book && model->priv->query) { + ESource *source; + const gchar *limit_str; + gint limit = -1; + + source = e_book_get_source (model->priv->book); + + limit_str = e_source_get_property (source, "limit"); + if (limit_str && *limit_str) + limit = atoi (limit_str); + + remove_book_view(model); + + if (model->priv->first_get_view) { + model->priv->first_get_view = FALSE; + + if (e_book_check_static_capability (model->priv->book, "do-initial-query")) { + e_book_async_get_book_view ( + model->priv->book, model->priv->query, + NULL, limit, book_view_loaded, model); + } else { + free_data (model); + + g_signal_emit (model, + signals[MODEL_CHANGED], 0); + g_signal_emit (model, + signals[STOP_STATE_CHANGED], 0); + } + } else + e_book_async_get_book_view ( + model->priv->book, model->priv->query, + NULL, limit, book_view_loaded, model); + + } + + g_object_unref (model); + + return FALSE; +} + +static void +addressbook_model_set_property (GObject *object, + guint property_id, + const GValue *value, + GParamSpec *pspec) +{ + switch (property_id) { + case PROP_BOOK: + e_addressbook_model_set_book ( + E_ADDRESSBOOK_MODEL (object), + g_value_get_object (value)); + return; + + case PROP_EDITABLE: + e_addressbook_model_set_editable ( + E_ADDRESSBOOK_MODEL (object), + g_value_get_boolean (value)); + return; + + case PROP_QUERY: + e_addressbook_model_set_query ( + E_ADDRESSBOOK_MODEL (object), + g_value_get_string (value)); + return; + } + + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + +} + +static void +addressbook_model_get_property (GObject *object, + guint property_id, + GValue *value, + GParamSpec *pspec) +{ + switch (property_id) { + case PROP_BOOK: + g_value_set_object ( + value, e_addressbook_model_get_book ( + E_ADDRESSBOOK_MODEL (object))); + return; + + case PROP_EDITABLE: + g_value_set_boolean ( + value, e_addressbook_model_get_editable ( + E_ADDRESSBOOK_MODEL (object))); + return; + + case PROP_QUERY: + g_value_take_string ( + value, e_addressbook_model_get_query ( + E_ADDRESSBOOK_MODEL (object))); + return; + } + + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); +} + +static void +addressbook_model_dispose (GObject *object) +{ + EAddressbookModel *model = E_ADDRESSBOOK_MODEL(object); + + remove_book_view (model); + free_data (model); + + if (model->priv->book) { + if (model->priv->writable_status_id) + g_signal_handler_disconnect ( + model->priv->book, + model->priv->writable_status_id); + model->priv->writable_status_id = 0; + + if (model->priv->backend_died_id) + g_signal_handler_disconnect ( + model->priv->book, + model->priv->backend_died_id); + model->priv->backend_died_id = 0; + + g_object_unref (model->priv->book); + model->priv->book = NULL; + } + + if (model->priv->query) { + e_book_query_unref (model->priv->query); + model->priv->query = NULL; + } + + /* Chain up to parent's dispose() method. */ + G_OBJECT_CLASS (parent_class)->dispose (object); +} + +static void +addressbook_model_finalize (GObject *object) { - g_signal_emit (model, - eab_model_signals [BACKEND_DIED], 0); + EAddressbookModelPrivate *priv; + + priv = E_ADDRESSBOOK_MODEL_GET_PRIVATE (object); + + g_ptr_array_free (priv->contacts, TRUE); + + /* Chain up to parent's finalize() method. */ + G_OBJECT_CLASS (parent_class)->finalize (object); } static void -eab_model_class_init (GObjectClass *object_class) -{ - parent_class = g_type_class_ref (PARENT_TYPE); - - object_class->dispose = addressbook_dispose; - object_class->set_property = eab_model_set_property; - object_class->get_property = eab_model_get_property; - - g_object_class_install_property (object_class, PROP_BOOK, - g_param_spec_object ("book", - _("Book"), - /*_( */"XXX blurb" /*)*/, - E_TYPE_BOOK, - G_PARAM_READWRITE)); - - g_object_class_install_property (object_class, PROP_QUERY, - g_param_spec_string ("query", - _("Query"), - /*_( */"XXX blurb" /*)*/, - NULL, - G_PARAM_READWRITE)); - - g_object_class_install_property (object_class, PROP_EDITABLE, - g_param_spec_boolean ("editable", - _("Editable"), - /*_( */"XXX blurb" /*)*/, - FALSE, - G_PARAM_READWRITE)); - - eab_model_signals [WRITABLE_STATUS] = +addressbook_model_class_init (EAddressbookModelClass *class) +{ + GObjectClass *object_class; + + parent_class = g_type_class_peek_parent (class); + g_type_class_add_private (class, sizeof (EAddressbookModelPrivate)); + + object_class = G_OBJECT_CLASS (class); + object_class->set_property = addressbook_model_set_property; + object_class->get_property = addressbook_model_get_property; + object_class->dispose = addressbook_model_dispose; + object_class->finalize = addressbook_model_finalize; + + g_object_class_install_property ( + object_class, + PROP_BOOK, + g_param_spec_object ( + "book", + _("Book"), + NULL, + E_TYPE_BOOK, + G_PARAM_READWRITE)); + + g_object_class_install_property ( + object_class, + PROP_EDITABLE, + g_param_spec_boolean ( + "editable", + _("Editable"), + NULL, + FALSE, + G_PARAM_READWRITE)); + + g_object_class_install_property ( + object_class, + PROP_QUERY, + g_param_spec_string ( + "query", + _("Query"), + NULL, + NULL, + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT)); + + signals[WRITABLE_STATUS] = g_signal_new ("writable_status", G_OBJECT_CLASS_TYPE (object_class), G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET (EABModelClass, writable_status), + G_STRUCT_OFFSET (EAddressbookModelClass, writable_status), NULL, NULL, g_cclosure_marshal_VOID__BOOLEAN, G_TYPE_NONE, 1, G_TYPE_BOOLEAN); - eab_model_signals [STATUS_MESSAGE] = + signals[STATUS_MESSAGE] = g_signal_new ("status_message", G_OBJECT_CLASS_TYPE (object_class), G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET (EABModelClass, status_message), + G_STRUCT_OFFSET (EAddressbookModelClass, status_message), NULL, NULL, g_cclosure_marshal_VOID__POINTER, G_TYPE_NONE, 1, G_TYPE_POINTER); - eab_model_signals [SEARCH_STARTED] = + signals[SEARCH_STARTED] = g_signal_new ("search_started", G_OBJECT_CLASS_TYPE (object_class), G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET (EABModelClass, search_started), + G_STRUCT_OFFSET (EAddressbookModelClass, search_started), NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0); - eab_model_signals [SEARCH_RESULT] = + signals[SEARCH_RESULT] = g_signal_new ("search_result", G_OBJECT_CLASS_TYPE (object_class), G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET (EABModelClass, search_result), + G_STRUCT_OFFSET (EAddressbookModelClass, search_result), NULL, NULL, g_cclosure_marshal_VOID__INT, G_TYPE_NONE, 1, G_TYPE_INT); - eab_model_signals [FOLDER_BAR_MESSAGE] = + signals[FOLDER_BAR_MESSAGE] = g_signal_new ("folder_bar_message", G_OBJECT_CLASS_TYPE (object_class), G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET (EABModelClass, folder_bar_message), + G_STRUCT_OFFSET (EAddressbookModelClass, folder_bar_message), NULL, NULL, g_cclosure_marshal_VOID__POINTER, G_TYPE_NONE, 1, G_TYPE_POINTER); - eab_model_signals [CONTACT_ADDED] = + signals[CONTACT_ADDED] = g_signal_new ("contact_added", G_OBJECT_CLASS_TYPE (object_class), G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET (EABModelClass, contact_added), + G_STRUCT_OFFSET (EAddressbookModelClass, contact_added), NULL, NULL, e_marshal_NONE__INT_INT, G_TYPE_NONE, 2, G_TYPE_INT, G_TYPE_INT); - eab_model_signals [CONTACTS_REMOVED] = + signals[CONTACTS_REMOVED] = g_signal_new ("contacts_removed", G_OBJECT_CLASS_TYPE (object_class), G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET (EABModelClass, contacts_removed), + G_STRUCT_OFFSET (EAddressbookModelClass, contacts_removed), NULL, NULL, g_cclosure_marshal_VOID__POINTER, G_TYPE_NONE, 1, G_TYPE_POINTER); - eab_model_signals [CONTACT_CHANGED] = + signals[CONTACT_CHANGED] = g_signal_new ("contact_changed", G_OBJECT_CLASS_TYPE (object_class), G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET (EABModelClass, contact_changed), + G_STRUCT_OFFSET (EAddressbookModelClass, contact_changed), NULL, NULL, g_cclosure_marshal_VOID__INT, G_TYPE_NONE, 1, G_TYPE_INT); - eab_model_signals [MODEL_CHANGED] = + signals[MODEL_CHANGED] = g_signal_new ("model_changed", G_OBJECT_CLASS_TYPE (object_class), G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET (EABModelClass, model_changed), + G_STRUCT_OFFSET (EAddressbookModelClass, model_changed), NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0); - eab_model_signals [STOP_STATE_CHANGED] = + signals[STOP_STATE_CHANGED] = g_signal_new ("stop_state_changed", G_OBJECT_CLASS_TYPE (object_class), G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET (EABModelClass, stop_state_changed), + G_STRUCT_OFFSET (EAddressbookModelClass, stop_state_changed), NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0); - eab_model_signals [BACKEND_DIED] = + signals[BACKEND_DIED] = g_signal_new ("backend_died", G_OBJECT_CLASS_TYPE (object_class), G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET (EABModelClass, backend_died), + G_STRUCT_OFFSET (EAddressbookModelClass, backend_died), NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0); } static void -eab_model_init (GObject *object) -{ - EABModel *model = EAB_MODEL(object); - model->book = NULL; - model->query = e_book_query_any_field_contains (""); - model->book_view = NULL; - model->create_contact_id = 0; - model->remove_contact_id = 0; - model->modify_contact_id = 0; - model->status_message_id = 0; - model->writable_status_id = 0; - model->backend_died_id = 0; - model->sequence_complete_id = 0; - model->data = NULL; - model->data_count = 0; - model->allocated_count = 0; - model->search_in_progress = FALSE; - model->editable = FALSE; - model->editable_set = FALSE; - model->first_get_view = TRUE; +addressbook_model_init (EAddressbookModel *model) +{ + model->priv = E_ADDRESSBOOK_MODEL_GET_PRIVATE (model); + + model->priv->contacts = g_ptr_array_new (); + model->priv->first_get_view = TRUE; } -static void -book_view_loaded (EBook *book, EBookStatus status, EBookView *book_view, gpointer closure) +GType +e_addressbook_model_get_type (void) { - EABModel *model = closure; + static GType type = 0; - if (status != E_BOOK_ERROR_OK) { - eab_error_dialog (_("Error getting book view"), status); - return; + if (G_UNLIKELY (type == 0)) { + static const GTypeInfo type_info = { + sizeof (EAddressbookModelClass), + (GBaseInitFunc) NULL, + (GBaseFinalizeFunc) NULL, + (GClassInitFunc) addressbook_model_class_init, + (GClassFinalizeFunc) NULL, + NULL, /* class_data */ + sizeof (EAddressbookModel), + 0, /* n_preallocs */ + (GInstanceInitFunc) addressbook_model_init, + NULL /* value_table */ + }; + + type = g_type_register_static ( + G_TYPE_OBJECT, "EAddressbookModel", &type_info, 0); } - remove_book_view (model); - free_data (model); + return type; +} - model->book_view = book_view; - if (model->book_view) - g_object_ref (model->book_view); - model->create_contact_id = g_signal_connect(model->book_view, - "contacts_added", - G_CALLBACK (create_contact), - model); - model->remove_contact_id = g_signal_connect(model->book_view, - "contacts_removed", - G_CALLBACK (remove_contact), - model); - model->modify_contact_id = g_signal_connect(model->book_view, - "contacts_changed", - G_CALLBACK(modify_contact), - model); - model->status_message_id = g_signal_connect(model->book_view, - "status_message", - G_CALLBACK(status_message), - model); - model->sequence_complete_id = g_signal_connect(model->book_view, - "sequence_complete", - G_CALLBACK(sequence_complete), - model); - - model->search_in_progress = TRUE; - g_signal_emit (model, - eab_model_signals [MODEL_CHANGED], 0); - g_signal_emit (model, - eab_model_signals [SEARCH_STARTED], 0); - g_signal_emit (model, - eab_model_signals [STOP_STATE_CHANGED], 0); - - e_book_view_start (model->book_view); +EAddressbookModel* +e_addressbook_model_new (void) +{ + return g_object_new (E_TYPE_ADDRESSBOOK_MODEL, NULL); } -static void -get_view (EABModel *model) +EContact * +e_addressbook_model_get_contact (EAddressbookModel *model, + gint row) { - /* Should this be checked somehow? */ - gboolean success; + GPtrArray *array; - if (model->book && model->query) { - ESource *source; - const gchar *limit_str; - gint limit = -1; + g_return_val_if_fail (E_IS_ADDRESSBOOK_MODEL (model), NULL); - source = e_book_get_source (model->book); + array = model->priv->contacts; - limit_str = e_source_get_property (source, "limit"); - if (limit_str && *limit_str) - limit = atoi (limit_str); + if (0 <= row && row < array->len) + return e_contact_duplicate (array->pdata[row]); - remove_book_view(model); + return NULL; +} - if (model->first_get_view) { - model->first_get_view = FALSE; +void +e_addressbook_model_stop (EAddressbookModel *model) +{ + const gchar *message; - if (e_book_check_static_capability (model->book, "do-initial-query")) { - success = e_book_async_get_book_view (model->book, model->query, NULL, limit, book_view_loaded, model); - } else { - free_data (model); + g_return_if_fail (E_IS_ADDRESSBOOK_MODEL (model)); - g_signal_emit (model, - eab_model_signals [MODEL_CHANGED], 0); - g_signal_emit (model, - eab_model_signals [STOP_STATE_CHANGED], 0); - return; - } - } - else - success = e_book_async_get_book_view (model->book, model->query, NULL, limit, book_view_loaded, model); + remove_book_view (model); - } + message = _("Search Interrupted"); + g_signal_emit (model, signals[STOP_STATE_CHANGED], 0); + g_signal_emit (model, signals[STATUS_MESSAGE], 0, message); } -static gboolean -get_view_idle (EABModel *model) +gboolean +e_addressbook_model_can_stop (EAddressbookModel *model) { - model->book_view_idle_id = 0; - get_view (model); - g_object_unref (model); - return FALSE; + g_return_val_if_fail (E_IS_ADDRESSBOOK_MODEL (model), FALSE); + + return model->priv->search_in_progress; } -EContact * -eab_model_get_contact(EABModel *model, - gint row) +void +e_addressbook_model_force_folder_bar_message (EAddressbookModel *model) { - if (model->data && 0 <= row && row < model->data_count) { - return e_contact_duplicate (model->data[row]); - } - return NULL; + g_return_if_fail (E_IS_ADDRESSBOOK_MODEL (model)); + + update_folder_bar_message (model); } -static void -eab_model_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) +gint +e_addressbook_model_contact_count (EAddressbookModel *model) { - EABModel *model; - gboolean need_get_book_view = FALSE; + g_return_val_if_fail (E_IS_ADDRESSBOOK_MODEL (model), 0); - model = EAB_MODEL (object); + return model->priv->contacts->len; +} - switch (prop_id) { - case PROP_BOOK: - if (model->book) { - if (model->writable_status_id) - g_signal_handler_disconnect (model->book, - model->writable_status_id); - model->writable_status_id = 0; +EContact * +e_addressbook_model_contact_at (EAddressbookModel *model, + gint index) +{ + g_return_val_if_fail (E_IS_ADDRESSBOOK_MODEL (model), NULL); - if (model->backend_died_id) - g_signal_handler_disconnect (model->book, - model->backend_died_id); - model->backend_died_id = 0; + return model->priv->contacts->pdata[index]; +} - g_object_unref (model->book); - } - model->book = E_BOOK(g_value_get_object (value)); - if (model->book) { - model->writable_status_id = - g_signal_connect (model->book, - "writable_status", - G_CALLBACK (writable_status), model); - model->backend_died_id = - g_signal_connect (model->book, - "backend_died", - G_CALLBACK (backend_died), model); - - if (!model->editable_set) { - model->editable = e_book_is_writable (model->book); +gint +e_addressbook_model_find (EAddressbookModel *model, + EContact *contact) +{ + GPtrArray *array; + gint ii; - g_signal_emit (model, - eab_model_signals [WRITABLE_STATUS], 0, - model->editable); - } + /* XXX This searches for a particular EContact instance, + * as opposed to an equivalent but possibly different + * EContact instance. Might have to revise this in + * the future. */ - model->first_get_view = TRUE; - g_object_ref (model->book); - need_get_book_view = TRUE; - } - break; - case PROP_QUERY: - if (model->query) - e_book_query_unref (model->query); - model->query = e_book_query_from_string (g_value_get_string (value)); - need_get_book_view = TRUE; - break; - case PROP_EDITABLE: - model->editable = g_value_get_boolean (value); - model->editable_set = TRUE; - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } + g_return_val_if_fail (E_IS_ADDRESSBOOK_MODEL (model), -1); + g_return_val_if_fail (E_IS_CONTACT (contact), -1); - if (need_get_book_view) { - if (!model->book_view_idle_id) { - g_object_ref (model); - model->book_view_idle_id = g_idle_add ((GSourceFunc)get_view_idle, model); - } + array = model->priv->contacts; + for (ii = 0; ii < array->len; ii++) { + EContact *candidate = array->pdata[ii]; + + if (contact == candidate) + return ii; } + return -1; } -static void -eab_model_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) +EBook * +e_addressbook_model_get_book (EAddressbookModel *model) { - EABModel *eab_model; - - eab_model = EAB_MODEL (object); + g_return_val_if_fail (E_IS_ADDRESSBOOK_MODEL (model), NULL); - switch (prop_id) { - case PROP_BOOK: - g_value_set_object (value, eab_model->book); - break; - case PROP_QUERY: { - gchar *query_string = e_book_query_to_string (eab_model->query); - g_value_set_string (value, query_string); - break; - } - case PROP_EDITABLE: - g_value_set_boolean (value, eab_model->editable); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } + return model->priv->book; } -GType -eab_model_get_type (void) +void +e_addressbook_model_set_book (EAddressbookModel *model, + EBook *book) { - static GType type = 0; - - if (!type) { - static const GTypeInfo info = { - sizeof (EABModelClass), - NULL, /* base_init */ - NULL, /* base_finalize */ - (GClassInitFunc) eab_model_class_init, - NULL, /* class_finalize */ - NULL, /* class_data */ - sizeof (EABModel), - 0, /* n_preallocs */ - (GInstanceInitFunc) eab_model_init, - }; - - type = g_type_register_static (PARENT_TYPE, "EABModel", &info, 0); + g_return_if_fail (E_IS_ADDRESSBOOK_MODEL (model)); + g_return_if_fail (E_IS_BOOK (book)); + + if (model->priv->book != NULL) { + if (model->priv->writable_status_id != 0) + g_signal_handler_disconnect ( + model->priv->book, + model->priv->writable_status_id); + model->priv->writable_status_id = 0; + + if (model->priv->backend_died_id != 0) + g_signal_handler_disconnect ( + model->priv->book, + model->priv->backend_died_id); + model->priv->backend_died_id = 0; + + g_object_unref (model->priv->book); } - return type; -} + model->priv->book = g_object_ref (book); + model->priv->first_get_view = TRUE; -EABModel* -eab_model_new (void) -{ - EABModel *et; + model->priv->writable_status_id = g_signal_connect ( + book, "writable-status", + G_CALLBACK (writable_status), model); - et = g_object_new (EAB_TYPE_MODEL, NULL); + model->priv->backend_died_id = g_signal_connect ( + book, "backend-died", + G_CALLBACK (backend_died), model); - return et; -} + if (!model->priv->editable_set) { + model->priv->editable = e_book_is_writable (book); + g_signal_emit ( + model, signals[WRITABLE_STATUS], 0, + model->priv->editable); + } -void eab_model_stop (EABModel *model) -{ - remove_book_view(model); - g_signal_emit (model, - eab_model_signals [STOP_STATE_CHANGED], 0); - g_signal_emit (model, - eab_model_signals [STATUS_MESSAGE], 0, - "Search Interrupted."); + if (model->priv->book_view_idle_id == 0) + model->priv->book_view_idle_id = g_idle_add ( + (GSourceFunc) addressbook_model_idle_cb, + g_object_ref (model)); + + g_object_notify (G_OBJECT (model), "book"); } gboolean -eab_model_can_stop (EABModel *model) +e_addressbook_model_get_editable (EAddressbookModel *model) { - return model->search_in_progress; + g_return_val_if_fail (E_IS_ADDRESSBOOK_MODEL (model), FALSE); + + return model->priv->editable; } void -eab_model_force_folder_bar_message (EABModel *model) +e_addressbook_model_set_editable (EAddressbookModel *model, + gboolean editable) { - update_folder_bar_message (model); -} + g_return_if_fail (E_IS_ADDRESSBOOK_MODEL (model)); -gint -eab_model_contact_count (EABModel *model) -{ - return model->data_count; -} + model->priv->editable = editable; + model->priv->editable_set = TRUE; -const EContact * -eab_model_contact_at (EABModel *model, gint index) -{ - return model->data[index]; + g_object_notify (G_OBJECT (model), "editable"); } -gboolean -eab_model_editable (EABModel *model) +gchar * +e_addressbook_model_get_query (EAddressbookModel *model) { - return model->editable; + g_return_val_if_fail (E_IS_ADDRESSBOOK_MODEL (model), NULL); + + return e_book_query_to_string (model->priv->query); } -EBook * -eab_model_get_ebook (EABModel *model) +void +e_addressbook_model_set_query (EAddressbookModel *model, + const gchar *query) { - return model->book; + g_return_if_fail (E_IS_ADDRESSBOOK_MODEL (model)); + + if (model->priv->query != NULL) + e_book_query_unref (model->priv->query); + + if (query == NULL) + model->priv->query = e_book_query_any_field_contains (""); + else + model->priv->query = e_book_query_from_string (query); + + if (model->priv->book_view_idle_id == 0) + model->priv->book_view_idle_id = g_idle_add ( + (GSourceFunc) addressbook_model_idle_cb, + g_object_ref (model)); + + g_object_notify (G_OBJECT (model), "query"); } |