diff options
Diffstat (limited to 'calendar/gui/calendar-model.c')
-rw-r--r-- | calendar/gui/calendar-model.c | 482 |
1 files changed, 482 insertions, 0 deletions
diff --git a/calendar/gui/calendar-model.c b/calendar/gui/calendar-model.c new file mode 100644 index 0000000000..6562f225e1 --- /dev/null +++ b/calendar/gui/calendar-model.c @@ -0,0 +1,482 @@ +/* Evolution calendar - Data model for ETable + * + * Copyright (C) 2000 Helix Code, Inc. + * + * Authors: Federico Mena-Quintero <federico@helixcode.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. + */ + +#include <config.h> +#include "calendar-model.h" + + + +/* Private part of the ECalendarModel structure */ +typedef struct { + /* Calendar client we are using */ + CalClient *client; + + /* Types of objects we are dealing with */ + CalObjType type; + + /* Array of calendar objects */ + GPtrArray *objects; + + /* UID -> array index hash */ + GHashTable *uid_index_hash; +} CalendarModelPrivate; + + + +static void calendar_model_class_init (CalendarModelClass *class); +static void calendar_model_init (CalendarModel *model); +static void calendar_model_destroy (GtkObject *object); + +static int calendar_model_column_count (ETableModel *etm); +static int calendar_model_row_count (ETableModel *etm); +static void *calendar_model_value_at (ETableModel *etm, int col, int row); +static void calendar_model_set_value_at (ETableModel *etm, int col, int row, const void *value); +static gboolean calendar_model_is_cell_editable (ETableModel *etm, int col, int row); +static void *calendar_model_duplicate_value (ETableModel *etm, int col, const void *value); +static void calendar_model_free_value (ETableModel *etm, int col, void *value); +static void *calendar_model_initialize_value (ETableModel *etm, int col); +static gboolean calendar_model_value_is_empty (ETableModel *etm, int col, const void *value); + +static void calendar_model_freeze (ETableModel *etm); +static void calendar_model_thaw (ETableModel *etm); + +static ETableModelClass *parent_class; + + + +/** + * calendar_model_get_type: + * @void: + * + * Registers the #CalendarModel class if necessary, and returns the type ID + * associated to it. + * + * Return value: The type ID of the #CalendarModel class. + **/ +GtkType +calendar_model_get_type (void) +{ + static GtkType calendar_model_type = 0; + + if (!calendar_model_type) { + static GtkTypeInfo calendar_model_info = { + "CalendarModel", + sizeof (CalendarModel), + sizeof (CalendarModelClass), + (GtkClassInitFunc) calendar_model_class_init, + (GtkObjectInitFunc) calendar_model_init, + NULL, /* reserved_1 */ + NULL, /* reserved_2 */ + (GtkClassInitFunc) NULL + }; + + calendar_model_type = gtk_type_unique (E_TABLE_MODEL_TYPE, &calendar_model_info); + } + + return calendar_model_type; +} + +/* Class initialization function for the calendar table model */ +static void +calendar_model_class_init (CalendarModelClass *class) +{ + GtkObjectClass *object_class; + ETableModelClass *etm_class; + + object_class = (GtkObjectClass *) class; + etm_class = (ETableModelClass *) class; + + parent_class = gtk_type_class (E_TABLE_MODEL_TYPE); + + object_class->destroy = calendar_model_destroy; +} + +/* Object initialization function for the calendar table model */ +static void +calendar_model_init (CalendarModel *model) +{ + CalendarModelPrivate *priv; + + priv = g_new0 (CalendarModelPrivate, 1); + model->priv = priv; + + priv->objects = g_ptr_array_new (); + priv->uid_index_hash = g_hash_table_new (g_str_hash, g_str_equal); +} + +/* Called from g_hash_table_foreach_remove(), frees a stored UID->index + * mapping. + */ +static gboolean +free_uid_index (gpointer key, gpointer value, gpointer data) +{ + int *idx; + + idx = value; + g_free (idx); + + return TRUE; +} + +/* Frees the objects stored in the calendar model */ +static void +free_objects (CalendarModel *model) +{ + CalendarModelPrivate *priv; + int i; + + priv = model->data; + + g_hash_table_foreach_remove (priv->objects, free_uid_index, NULL); + + for (i = 0; i < priv->objects->len; i++) { + iCalObject *ico; + + ico = g_ptr_array_index (priv->objects, i); + g_assert (ico != NULL); + ical_object_unref (ico); + } + + g_ptr_array_set_size (priv->objects, 0); +} + +/* Destroy handler for the calendar table model */ +static void +calendar_model_destroy (GtkObject *object) +{ + CalendarModel *model; + CalendarModelPrivate *priv; + int i; + + g_return_if_fail (object != NULL); + g_return_if_fail (IS_CALENDAR_MODEL (object)); + + model = CALENDAR_MODEL (object); + priv = model->priv; + + /* Free the calendar client interface object */ + + if (priv->client) { + gtk_object_unref (GTK_OBJECT (priv->client)); + priv->client = NULL; + } + + /* Free the uid->index hash data and the array of UIDs */ + + free_objects (model); + + g_hash_table_destroy (priv->uid_index_hash); + priv->uid_index_hash = NULL; + + g_ptr_array_free (priv->objects, TRUE); + priv->objects = NULL; + + /* Free the private structure */ + + g_free (priv); + model->priv = NULL; + + if (GTK_OBJECT_CLASS (parent_class)->destroy) + (* GTK_OBJECT_CLASS (parent_class)->destroy) (object); +} + + + +/* ETableModel methods */ + +/* column_count handler for the calendar table model */ +static int +calendar_model_column_count (ETableModel *etm) +{ + return ICAL_OBJECT_FIELD_NUM_FIELDS; +} + +/* row_count handler for the calendar table model */ +static int +calendar_model_row_count (ETableModel *etm) +{ + CalendarModel *model; + CalendarModelPrivate *priv; + + model = CALENDAR_MODEL (etm); + priv = model->priv; + + return priv->objects->len; +} + +/* value_at handler for the calendar table model */ +static void * +calendar_model_value_at (ETableModel *etm, int col, int row) +{ + CalendarModel *model; + CalendarModelPrivate *priv; + iCalObject *ico; + void *retval; + + model = CALENDAR_MODEL (etm); + priv = model->priv; + + if (row >= priv->objects->len) { + g_message ("calendar_model_value_at(): Requested invalid row index %d", row); + return NULL; + } + + ico = g_ptr_array_index (priv->objects, row); + g_assert (ico != NULL); + + switch (col) { + case ICAL_OBJECT_FIELD_COMMENT: + return ico->comment ? ico->commment : ""; + + case ICAL_OBJECT_FIELD_COMPLETED: + return &ico->completed; + + case ICAL_OBJECT_FIELD_CREATED: + return &ico->created; + + case ICAL_OBJECT_FIELD_DESCRIPTION: + return ico->desc ? ico->desc : ""; + + case ICAL_OBJECT_FIELD_DTSTAMP: + return &ico->dtstamp; + + case ICAL_OBJECT_FIELD_DTSTART: + return &ico->dtstart; + + case ICAL_OBJECT_FIELD_DTEND: + return &ico->dtend; + + case ICAL_OBJECT_FIELD_GEO: + return &ico->geo; + + case ICAL_OBJECT_FIELD_LAST_MOD: + return &ico->last_mod; + + case ICAL_OBJECT_FIELD_LOCATION: + return ico->location ? ico->location : ""; + + case ICAL_OBJECT_FIELD_ORGANIZER: + return ico->organizer; + + case ICAL_OBJECT_FIELD_PERCENT: + return &ico->percent; + + case ICAL_OBJECT_FIELD_PRIORITY: + return &ico->priority; + + case ICAL_OBJECT_FIELD_SUMMARY: + return ico->summary ? ico->summary : ""; + + case ICAL_OBJECT_FIELD_URL: + return ico->url ? ico->url : ""; + + case ICAL_OBJECT_FIELD_HAS_ALARMS: + return (ico->dalarm.enabled || ico->aalarm.enabled + || ico->palarm.enabled || ico->malarm.enabled); + + default: + g_message ("calendar_model_value_at(): Requested invalid column %d", col); + return NULL; + } +} + + + +/** + * calendar_model_new: + * + * Creates a new calendar model. It must be told about the calendar client + * interface object it will monitor with calendar_model_set_cal_client(). + * + * Return value: A newly-created calendar model. + **/ +CalendarModel * +calendar_model_new (void) +{ + return CALENDAR_MODEL (gtk_type_new (TYPE_CALENDAR_MODEL)); +} + +/* Removes an object from the model and updates all the indices that follow. + * Returns the index of the object that was removed, or -1 if no object with + * such UID was found. + */ +static int +remove_object (CalendarModel *model, const char *uid) +{ + CalendarModelPrivate *priv; + int *idx; + iCalObject *orig_ico; + int i; + int n; + + priv = model->priv; + + /* Find the index of the object to be removed */ + + idx = g_hash_table_lookup (priv->uid_index_hash, uid); + if (!idx) + return -1; + + orig_ico = g_ptr_array_index (priv->objects, *idx); + g_assert (orig_ico != NULL); + + /* Decrease the indices of all the objects that follow in the array */ + + for (i = *idx + 1; i < priv->objects->len; i++) { + iCalObject *ico; + int *ico_idx; + + ico = g_ptr_array_index (priv->objects, i); + g_assert (ico != NULL); + + ico_idx = g_hash_table_lookup (priv->uid_index_hash, ico->uid); + g_assert (ico_idx != NULL); + + *ico_idx--; + g_assert (*ico_idx >= 0); + } + + /* Remove this object from the array and hash */ + + g_hash_table_remove (priv->uid_index_hash, uid); + g_array_remove (priv->objects, *idx); + + ical_object_unref (orig_ico); + + n = *idx; + g_free (idx); + + return n; +} + +/* Callback used when an object is updated in the server */ +static void +obj_updated_cb (CalClient *client, const char *uid, gpointer data) +{ + CalendarModel *model; + CalendarModelPrivate *priv; + int orig_idx; + + model = CALENDAR_MODEL (data); + priv = model->priv; + + orig_idx = remove_object (model, uid); + + + +} + +/* Loads the required objects from the calendar client */ +static void +load_objects (CalendarModel *model) +{ + CalendarModelPrivate *priv; + GList *uids; + GList *l; + + priv = model->priv; + + uids = cal_client_get_uids (priv->client, priv->type); + + for (l = uids; l; l = l->next) { + char *uid; + iCalObject *ico; + CalClientGetStatus status; + int *idx; + + uid = l->data; + status = cal_client_get_object (priv->client, uid, &ico); + + switch (status) { + case CAL_CLIENT_GET_SUCCESS: + break; + + case CAL_CLIENT_GET_NOT_FOUND: + /* Nothing; the object may have been removed from the server */ + continue; + + case CAL_CLIENT_GET_SYNTAX_ERROR: + g_message ("load_objects(): Syntax error when getting object %s", uid); + continue; + } + + g_assert (ico->uid != NULL); + + idx = g_new (int, 1); + + g_ptr_array_add (priv->objects, ico); + *idx = priv->objects->len - 1; + + g_hash_table_insert (priv->uid_index_hash, ico->uid, idx); + } + + cal_obj_uid_list_free (uids); +} + +/** + * calendar_model_set_cal_client: + * @model: A calendar model. + * @client: A calendar client interface object. + * @type: Type of objects to present. + * + * Sets the calendar client interface object that a calendar model will monitor. + * It also sets the types of objects this model will present to an #ETable. + **/ +void +calendar_model_set_cal_client (CalendarModel *model, CalClient *client, CalObjType type) +{ + CalendarModelPrivate *priv; + + g_return_if_fail (model != NULL); + g_return_if_fail (IS_CALENDAR_MODEL (model)); + + if (client) + g_return_if_fail (IS_CAL_CLIENT (client)); + + priv = model->priv; + + if (priv->client == client && priv->type == type) + return; + + if (client) + gtk_object_ref (GTK_OBJECT (client)); + + if (priv->client) { + gtk_signal_disconnect_by_data (GTK_OBJECT (priv->client), model); + gtk_object_unref (GTK_OBJECT (priv->client)); + } + + free_objects (model); + + priv->client = client; + priv->type = type; + + if (priv->client) { + gtk_signal_connect (GTK_OBJECT (priv->client), "obj_updated", + GTK_SIGNAL_FUNC (obj_updated_cb), model); + gtk_signal_connect (GTK_OBJECT (priv->clinet), "obj_removed", + GTK_SIGNAL_FUNC (obj_removed_cb), model); + } + + load_objects (model); + + e_table_model_changed (E_TABLE_MODEL (model)); +} |