diff options
-rw-r--r-- | calendar/ChangeLog | 107 | ||||
-rw-r--r-- | calendar/cal-client/cal-client.c | 86 | ||||
-rw-r--r-- | calendar/cal-client/cal-client.h | 5 | ||||
-rw-r--r-- | calendar/cal-client/cal-query.c | 25 | ||||
-rw-r--r-- | calendar/cal-client/cal-query.h | 18 | ||||
-rw-r--r-- | calendar/conduits/calendar/calendar-conduit.c | 20 | ||||
-rw-r--r-- | calendar/conduits/todo/todo-conduit.c | 20 | ||||
-rw-r--r-- | calendar/gui/Makefile.am | 6 | ||||
-rw-r--r-- | calendar/gui/calendar-model.c | 15 | ||||
-rw-r--r-- | calendar/gui/comp-editor-factory.c | 10 | ||||
-rw-r--r-- | calendar/gui/comp-util.c | 27 | ||||
-rw-r--r-- | calendar/gui/dialogs/comp-editor.c | 16 | ||||
-rw-r--r-- | calendar/gui/e-cal-model-calendar.c | 447 | ||||
-rw-r--r-- | calendar/gui/e-cal-model-calendar.h | 58 | ||||
-rw-r--r-- | calendar/gui/e-cal-model-tasks.c | 904 | ||||
-rw-r--r-- | calendar/gui/e-cal-model-tasks.h | 64 | ||||
-rw-r--r-- | calendar/gui/e-cal-model.c | 1303 | ||||
-rw-r--r-- | calendar/gui/e-cal-model.h | 95 | ||||
-rw-r--r-- | calendar/gui/e-day-view.c | 14 | ||||
-rw-r--r-- | calendar/gui/e-itip-control.c | 79 | ||||
-rw-r--r-- | calendar/gui/e-week-view.c | 14 | ||||
-rw-r--r-- | calendar/gui/gnome-cal.c | 26 |
22 files changed, 3242 insertions, 117 deletions
diff --git a/calendar/ChangeLog b/calendar/ChangeLog index b24f477cc5..6d3099d53a 100644 --- a/calendar/ChangeLog +++ b/calendar/ChangeLog @@ -1,13 +1,120 @@ +2003-08-06 Rodrigo Moya <rodrigo@ximian.com> + + * gui/e-cal-model.[ch]: removed 'create_component_with_defaults' + virtual method. + (e_cal_component_create_component_with_defaults): + (e_cal_component_get_color_for_component): new functions. + +2003-08-06 Rodrigo Moya <rodrigo@ximian.com> + + * gui/e-cal-model.[ch] (e_cal_model_set_query): new function. + (e_cal_model_remove_all_clients): implemented. + (remove_client): also remove all objects belonging to the + client being removed. + +2003-08-06 Rodrigo Moya <rodrigo@ximian.com> + + * gui/e-cal-model.c (get_dtstart, set_dtstart): implemented. + (ecm_value_at, ecm_set_value_at, ecm_duplicate_value, + ecm_free_value, ecm_value_to_string): added case for DTSTART + field. + (free_comp_data): free also the other date values in the + ECalModelComponent struct. + (e_cal_model_date_value_to_string): new function. + + * gui/e-cal-model.h: added new prototypes. + + * gui/e-cal-model-calendar.[ch]: new ECalModel-based class for + containing events. + + * gui/e-cal-model-tasks.c (ecmt_value_to_string): implemented + the case for date fields. + +2003-08-05 Rodrigo Moya <rodrigo@ximian.com> + + * cal-client/cal-client.c (generate_instances_obj_updated_cb): fixed + parameters in call to cal_client_get_object(). + (get_objects_atomatically): same. + + * gui/e-cal-model.[ch]: added "get_color_for_component" virtual method. + (get_color): new function to return the color. It calls the virtual + method of the current class. + (ecm_value_at): return a value for the color and icon columns. + (e_cal_model_class_init): initialize virtual methods. + + * gui/e-cal-model-tasks.c (ecmt_get_color_for_component): implemented + new class' virtual method. + 2003-08-05 Jack Jia <jack.jia@sun.com> * gui/dialogs/event-page.glade: changed one of the "Con_fidential" to "Co_nfidential" since we already have "File" using the same 'F' key. +2003-08-05 Rodrigo Moya <rodrigo@ximian.com> + + * cal-client_/cal-client.c (cal_client_get_default_object): use + correctly the pointer to pointer. + + * gui/e-week-view.c (query_obj_updated_cb): fixed the call to + cal_client_get_object(). + +2003-08-04 Rodrigo Moya <rodrigo@ximian.com> + + * cal-client/cal-client.[ch] (cal_client_get_default_object): + (cal_client_get_object): use icalcomponent instead of CalComponent. + + * gui/e-cal-model.c (get_dtstart): implemented. + (query_obj_updated_cb): + (query_obj_removed_cb): + (query_done_cb): + (query_eval_error_cb): implemented missing functions. + + * gui/calendar-model.c: + * gui/comp-editor-factory.c: + * gui/comp-util.c: + * gui/e-day-view.c: + * gui/e-itip-control.c: + * gui/e-week-view.c: + * gui/gnome-cal.c: + * gui/dialogs/comp-editor.c: + * conduits/todo/todo-conduit.c: + * conduits/calendar/calendar-conduit.c: adapted to changes + in CalClient API. + +2003-08-04 Rodrigo Moya <rodrigo@ximian.com> + + * cal-client/cal-query.[ch] (cal_query_new): added a 'CalClient' + argument to this function. + (cal_query_get_client): new function. + + * cal-client/cal-client.c (cal_client_get_query): added new parameter + in call to cal_query_new (). + +2003-08-01 Lorenzo Gil <lgs@sicem.biz> + + * gui/e-alarm-list.c: added the include <config.h> line at the + beginning to enable gettext. + +2003-08-01 Rodrigo Moya <rodrigo@ximian.com> + + * gui/e-cal-model.[ch] (e_cal_model_get_component_at): new function. + (ecm_append_row): use the client from the source model. + (e_cal_model_get_timezone, e_cal_model_set_timezone): new functions. + + * gui/e-cal-model-tasks.[ch]: new class for the tasks model. + 2003-08-01 Lorenzo Gil <lgs@sicem.biz> * gui/e-alarm-list.c: added the include <config.h> line at the beginning to enable gettext. +2003-07-31 Rodrigo Moya <rodrigo@ximian.com> + + * gui/e-cal-model.[ch]: new class, based on CalendarModel to be + an abstract class for calendar models. + + * gui/Makefile.am: added new files to build. + 2003-07-30 Rodrigo Moya <rodrigo@ximian.com> * cal-client/cal-client-multi.[ch]: diff --git a/calendar/cal-client/cal-client.c b/calendar/cal-client/cal-client.c index 0854d75b61..740d8f4062 100644 --- a/calendar/cal-client/cal-client.c +++ b/calendar/cal-client/cal-client.c @@ -1354,13 +1354,12 @@ struct _CalClientGetTimezonesData { }; CalClientGetStatus -cal_client_get_default_object (CalClient *client, CalObjType type, CalComponent **comp) +cal_client_get_default_object (CalClient *client, CalObjType type, icalcomponent **icalcomp) { CalClientPrivate *priv; CORBA_Environment ev; GNOME_Evolution_Calendar_CalObj comp_str; CalClientGetStatus retval; - icalcomponent *icalcomp; CalClientGetTimezonesData cb_data; g_return_val_if_fail (client != NULL, CAL_CLIENT_GET_NOT_FOUND); @@ -1369,10 +1368,10 @@ cal_client_get_default_object (CalClient *client, CalObjType type, CalComponent priv = client->priv; g_return_val_if_fail (priv->load_state == CAL_CLIENT_LOAD_LOADED, CAL_CLIENT_GET_NOT_FOUND); - g_return_val_if_fail (comp != NULL, CAL_CLIENT_GET_NOT_FOUND); + g_return_val_if_fail (icalcomp != NULL, CAL_CLIENT_GET_NOT_FOUND); retval = CAL_CLIENT_GET_NOT_FOUND; - *comp = NULL; + *icalcomp = NULL; CORBA_exception_init (&ev); comp_str = GNOME_Evolution_Calendar_Cal_getDefaultObject (priv->cal, type, &ev); @@ -1380,24 +1379,14 @@ cal_client_get_default_object (CalClient *client, CalObjType type, CalComponent if (BONOBO_USER_EX (&ev, ex_GNOME_Evolution_Calendar_Cal_NotFound)) goto out; else if (BONOBO_EX (&ev)) { - g_message ("cal_client_get_object(): could not get the object"); + g_message ("cal_client_get_default_object(): could not get the object"); goto out; } - icalcomp = icalparser_parse_string (comp_str); + *icalcomp = icalparser_parse_string (comp_str); CORBA_free (comp_str); - if (!icalcomp) { - retval = CAL_CLIENT_GET_SYNTAX_ERROR; - goto out; - } - - *comp = cal_component_new (); - if (!cal_component_set_icalcomponent (*comp, icalcomp)) { - icalcomponent_free (icalcomp); - g_object_unref (*comp); - *comp = NULL; - + if (!*icalcomp) { retval = CAL_CLIENT_GET_SYNTAX_ERROR; goto out; } @@ -1411,7 +1400,7 @@ cal_client_get_default_object (CalClient *client, CalObjType type, CalComponent resize pending, which leads to an assert failure and an abort. */ cb_data.client = client; cb_data.status = CAL_CLIENT_GET_SUCCESS; - icalcomponent_foreach_tzid (icalcomp, + icalcomponent_foreach_tzid (*icalcomp, cal_client_get_object_timezones_cb, &cb_data); @@ -1427,7 +1416,7 @@ cal_client_get_default_object (CalClient *client, CalObjType type, CalComponent * cal_client_get_object: * @client: A calendar client. * @uid: Unique identifier for a calendar component. - * @comp: Return value for the calendar component object. + * @icalcomp: Return value for the calendar component object. * * Queries a calendar for a calendar component object based on its unique * identifier. @@ -1435,13 +1424,12 @@ cal_client_get_default_object (CalClient *client, CalObjType type, CalComponent * Return value: Result code based on the status of the operation. **/ CalClientGetStatus -cal_client_get_object (CalClient *client, const char *uid, CalComponent **comp) +cal_client_get_object (CalClient *client, const char *uid, icalcomponent **icalcomp) { CalClientPrivate *priv; CORBA_Environment ev; GNOME_Evolution_Calendar_CalObj comp_str; CalClientGetStatus retval; - icalcomponent *icalcomp; CalClientGetTimezonesData cb_data; g_return_val_if_fail (client != NULL, CAL_CLIENT_GET_NOT_FOUND); @@ -1451,10 +1439,10 @@ cal_client_get_object (CalClient *client, const char *uid, CalComponent **comp) g_return_val_if_fail (priv->load_state == CAL_CLIENT_LOAD_LOADED, CAL_CLIENT_GET_NOT_FOUND); g_return_val_if_fail (uid != NULL, CAL_CLIENT_GET_NOT_FOUND); - g_return_val_if_fail (comp != NULL, CAL_CLIENT_GET_NOT_FOUND); + g_return_val_if_fail (icalcomp != NULL, CAL_CLIENT_GET_NOT_FOUND); retval = CAL_CLIENT_GET_NOT_FOUND; - *comp = NULL; + *icalcomp = NULL; CORBA_exception_init (&ev); comp_str = GNOME_Evolution_Calendar_Cal_getObject (priv->cal, (char *) uid, &ev); @@ -1466,20 +1454,10 @@ cal_client_get_object (CalClient *client, const char *uid, CalComponent **comp) goto out; } - icalcomp = icalparser_parse_string (comp_str); + *icalcomp = icalparser_parse_string (comp_str); CORBA_free (comp_str); - if (!icalcomp) { - retval = CAL_CLIENT_GET_SYNTAX_ERROR; - goto out; - } - - *comp = cal_component_new (); - if (!cal_component_set_icalcomponent (*comp, icalcomp)) { - icalcomponent_free (icalcomp); - g_object_unref (G_OBJECT (*comp)); - *comp = NULL; - + if (!*icalcomp) { retval = CAL_CLIENT_GET_SYNTAX_ERROR; goto out; } @@ -1493,7 +1471,7 @@ cal_client_get_object (CalClient *client, const char *uid, CalComponent **comp) resize pending, which leads to an assert failure and an abort. */ cb_data.client = client; cb_data.status = CAL_CLIENT_GET_SUCCESS; - icalcomponent_foreach_tzid (icalcomp, + icalcomponent_foreach_tzid (*icalcomp, cal_client_get_object_timezones_cb, &cb_data); @@ -1936,6 +1914,7 @@ generate_instances_obj_updated_cb (CalClient *client, const char *uid, gpointer { GHashTable *uid_comp_hash; CalComponent *comp; + icalcomponent *icalcomp; CalClientGetStatus status; const char *comp_uid; @@ -1953,13 +1932,19 @@ generate_instances_obj_updated_cb (CalClient *client, const char *uid, gpointer g_hash_table_remove (uid_comp_hash, uid); g_object_unref (G_OBJECT (comp)); - status = cal_client_get_object (client, uid, &comp); + status = cal_client_get_object (client, uid, &icalcomp); switch (status) { case CAL_CLIENT_GET_SUCCESS: - /* The hash key comes from the component's internal data */ - cal_component_get_uid (comp, &comp_uid); - g_hash_table_insert (uid_comp_hash, (char *) comp_uid, comp); + comp = cal_component_new (); + if (cal_component_set_icalcomponent (comp, icalcomp)) { + /* The hash key comes from the component's internal data */ + cal_component_get_uid (comp, &comp_uid); + g_hash_table_insert (uid_comp_hash, (char *) comp_uid, comp); + } else { + g_object_unref (comp); + icalcomponent_free (icalcomp); + } break; case CAL_CLIENT_GET_NOT_FOUND: @@ -2037,21 +2022,28 @@ get_objects_atomically (CalClient *client, CalObjType type, time_t start, time_t for (l = uids; l; l = l->next) { CalComponent *comp; + icalcomponent *icalcomp; CalClientGetStatus status; char *uid; const char *comp_uid; uid = l->data; - status = cal_client_get_object (client, uid, &comp); + status = cal_client_get_object (client, uid, &icalcomp); switch (status) { case CAL_CLIENT_GET_SUCCESS: - /* The hash key comes from the component's internal data - * instead of the duped UID from the list of UIDS. - */ - cal_component_get_uid (comp, &comp_uid); - g_hash_table_insert (uid_comp_hash, (char *) comp_uid, comp); + comp = cal_component_new (); + if (cal_component_set_icalcomponent (comp, icalcomp)) { + /* The hash key comes from the component's internal data + * instead of the duped UID from the list of UIDS. + */ + cal_component_get_uid (comp, &comp_uid); + g_hash_table_insert (uid_comp_hash, (char *) comp_uid, comp); + } else { + g_object_unref (comp); + icalcomponent_free (icalcomp); + } break; case CAL_CLIENT_GET_NOT_FOUND: @@ -2912,7 +2904,7 @@ cal_client_get_query (CalClient *client, const char *sexp) g_return_val_if_fail (sexp != NULL, NULL); - return cal_query_new (priv->cal, sexp); + return cal_query_new (client, priv->cal, sexp); } diff --git a/calendar/cal-client/cal-client.h b/calendar/cal-client/cal-client.h index 556049f831..baf2072868 100644 --- a/calendar/cal-client/cal-client.h +++ b/calendar/cal-client/cal-client.h @@ -40,7 +40,6 @@ G_BEGIN_DECLS #define CAL_CLIENT_SET_MODE_STATUS_ENUM_TYPE (cal_client_set_mode_status_enum_get_type ()) #define CAL_MODE_ENUM_TYPE (cal_mode_enum_get_type ()) -typedef struct _CalClient CalClient; typedef struct _CalClientClass CalClientClass; typedef struct _CalClientPrivate CalClientPrivate; @@ -169,11 +168,11 @@ int cal_client_get_n_objects (CalClient *client, CalObjType type); CalClientGetStatus cal_client_get_default_object (CalClient *client, CalObjType type, - CalComponent **comp); + icalcomponent **icalcomp); CalClientGetStatus cal_client_get_object (CalClient *client, const char *uid, - CalComponent **comp); + icalcomponent **icalcomp); CalClientGetStatus cal_client_get_timezone (CalClient *client, const char *tzid, diff --git a/calendar/cal-client/cal-query.c b/calendar/cal-client/cal-query.c index 77b18af1ff..914af5db28 100644 --- a/calendar/cal-client/cal-query.c +++ b/calendar/cal-client/cal-query.c @@ -37,6 +37,9 @@ struct _CalQueryPrivate { /* Handle to the query in the server */ GNOME_Evolution_Calendar_Query corba_query; + + /* The CalClient associated with this query */ + CalClient *client; }; @@ -366,6 +369,7 @@ cal_query_construct (CalQuery *query, /** * cal_query_new: + * @client: Client from which the query is being created. * @cal: Handle to an open calendar. * @sexp: S-expression that defines the query. * @@ -375,7 +379,8 @@ cal_query_construct (CalQuery *query, * Return value: A newly-created query object, or NULL if the request failed. **/ CalQuery * -cal_query_new (GNOME_Evolution_Calendar_Cal cal, +cal_query_new (CalClient *client, + GNOME_Evolution_Calendar_Cal cal, const char *sexp) { CalQuery *query; @@ -387,5 +392,23 @@ cal_query_new (GNOME_Evolution_Calendar_Cal cal, return NULL; } + query->priv->client = client; + return query; } + +/** + * cal_query_get_client + * @query: A #CalQuery object. + * + * Get the #CalClient associated with this query. + * + * Returns: the associated client. + */ +CalClient * +cal_query_get_client (CalQuery *query) +{ + g_return_val_if_fail (IS_CAL_QUERY (query), NULL); + + return query->priv->client; +} diff --git a/calendar/cal-client/cal-query.h b/calendar/cal-client/cal-query.h index 9464e7ae6e..77429035fa 100644 --- a/calendar/cal-client/cal-query.h +++ b/calendar/cal-client/cal-query.h @@ -27,6 +27,8 @@ G_BEGIN_DECLS +typedef struct _CalClient CalClient; + #define CAL_QUERY_TYPE (cal_query_get_type ()) @@ -66,16 +68,18 @@ typedef struct { void (* eval_error) (CalQuery *query, const char *error_str); } CalQueryClass; -GType cal_query_get_type (void); +GType cal_query_get_type (void); -GType cal_query_done_status_enum_get_type (void); +GType cal_query_done_status_enum_get_type (void); -CalQuery *cal_query_construct (CalQuery *query, - GNOME_Evolution_Calendar_Cal cal, - const char *sexp); +CalQuery *cal_query_construct (CalQuery *query, + GNOME_Evolution_Calendar_Cal cal, + const char *sexp); -CalQuery *cal_query_new (GNOME_Evolution_Calendar_Cal cal, - const char *sexp); +CalQuery *cal_query_new (CalClient *client, + GNOME_Evolution_Calendar_Cal cal, + const char *sexp); +CalClient *cal_query_get_client (CalQuery *query); diff --git a/calendar/conduits/calendar/calendar-conduit.c b/calendar/conduits/calendar/calendar-conduit.c index 0171ea4b70..1893e6b34c 100644 --- a/calendar/conduits/calendar/calendar-conduit.c +++ b/calendar/conduits/calendar/calendar-conduit.c @@ -1006,13 +1006,21 @@ local_record_from_uid (ECalLocalRecord *local, ECalConduitContext *ctxt) { CalComponent *comp; + icalcomponent *icalcomp; CalClientGetStatus status; g_assert(local!=NULL); - status = cal_client_get_object (ctxt->client, uid, &comp); + status = cal_client_get_object (ctxt->client, uid, &icalcomp); if (status == CAL_CLIENT_GET_SUCCESS) { + comp = cal_component_new (); + if (!cal_component_set_icalcomponent (comp, icalcomp)) { + g_object_unref (comp); + icalcomponent_free (icalcomp); + return; + } + local_record_from_comp (local, comp, ctxt); g_object_unref (comp); } else if (status == CAL_CLIENT_GET_NOT_FOUND) { @@ -1328,6 +1336,7 @@ pre_sync (GnomePilotConduit *conduit, int len; unsigned char *buf; char *filename, *change_id; + icalcomponent *icalcomp; gint num_records, add_records = 0, mod_records = 0, del_records = 0; abs_conduit = GNOME_PILOT_CONDUIT_SYNC_ABS (conduit); @@ -1355,9 +1364,16 @@ pre_sync (GnomePilotConduit *conduit, cal_client_set_default_timezone (ctxt->client, ctxt->timezone); /* Get the default component */ - if (cal_client_get_default_object (ctxt->client, CALOBJ_TYPE_EVENT, &ctxt->default_comp) != CAL_CLIENT_GET_SUCCESS) + if (cal_client_get_default_object (ctxt->client, CALOBJ_TYPE_EVENT, &icalcomp) != CAL_CLIENT_GET_SUCCESS) return -1; + ctxt->default_comp = cal_component_new (); + if (!cal_component_set_icalcomponent (ctxt->default_comp, icalcomp)) { + g_object_unref (ctxt->default_comp); + icalcomponent_free (icalcomp); + return -1; + } + /* Load the uid <--> pilot id mapping */ filename = map_name (ctxt); e_pilot_map_read (filename, &ctxt->map); diff --git a/calendar/conduits/todo/todo-conduit.c b/calendar/conduits/todo/todo-conduit.c index a27beffb9d..6868368129 100644 --- a/calendar/conduits/todo/todo-conduit.c +++ b/calendar/conduits/todo/todo-conduit.c @@ -675,13 +675,21 @@ local_record_from_uid (EToDoLocalRecord *local, EToDoConduitContext *ctxt) { CalComponent *comp; + icalcomponent *icalcomp; CalClientGetStatus status; g_assert(local!=NULL); - status = cal_client_get_object (ctxt->client, uid, &comp); + status = cal_client_get_object (ctxt->client, uid, &icalcomp); if (status == CAL_CLIENT_GET_SUCCESS) { + comp = cal_component_new (); + if (!cal_component_set_icalcomponent (comp, icalcomp)) { + g_object_unref (comp); + icalcomponent_free (icalcomp); + return; + } + local_record_from_comp (local, comp, ctxt); g_object_unref (comp); } else if (status == CAL_CLIENT_GET_NOT_FOUND) { @@ -869,6 +877,7 @@ pre_sync (GnomePilotConduit *conduit, int len; unsigned char *buf; char *filename, *change_id; + icalcomponent *icalcomp; gint num_records, add_records = 0, mod_records = 0, del_records = 0; abs_conduit = GNOME_PILOT_CONDUIT_SYNC_ABS (conduit); @@ -897,9 +906,16 @@ pre_sync (GnomePilotConduit *conduit, cal_client_set_default_timezone (ctxt->client, ctxt->timezone); /* Get the default component */ - if (cal_client_get_default_object (ctxt->client, CALOBJ_TYPE_TODO, &ctxt->default_comp) != CAL_CLIENT_GET_SUCCESS) + if (cal_client_get_default_object (ctxt->client, CALOBJ_TYPE_TODO, &icalcomp) != CAL_CLIENT_GET_SUCCESS) return -1; + ctxt->default_comp = cal_component_new (); + if (!cal_component_set_icalcomponent (ctxt->default_comp, icalcomp)) { + g_object_unref (ctxt->default_comp); + icalcomponent_free (icalcomp); + return -1; + } + /* Load the uid <--> pilot id map */ filename = map_name (ctxt); e_pilot_map_read (filename, &ctxt->map); diff --git a/calendar/gui/Makefile.am b/calendar/gui/Makefile.am index 09d1db57f8..d40c2da78c 100644 --- a/calendar/gui/Makefile.am +++ b/calendar/gui/Makefile.am @@ -114,6 +114,12 @@ libevolution_calendar_la_SOURCES = \ control-factory.h \ e-alarm-list.c \ e-alarm-list.h \ + e-cal-model-calendar.c \ + e-cal-model-calendar.h \ + e-cal-model-tasks.c \ + e-cal-model-tasks.h \ + e-cal-model.c \ + e-cal-model.h \ e-cal-view.c \ e-cal-view.h \ e-calendar-table.h \ diff --git a/calendar/gui/calendar-model.c b/calendar/gui/calendar-model.c index 2724a0a19c..b5d0738729 100644 --- a/calendar/gui/calendar-model.c +++ b/calendar/gui/calendar-model.c @@ -1763,6 +1763,7 @@ query_obj_updated_cb (CalQuery *query, const char *uid, CalendarModelPrivate *priv; int orig_idx; CalComponent *new_comp; + icalcomponent *icalcomp; const char *new_comp_uid; int *new_idx; CalClientGetStatus status; @@ -1775,10 +1776,22 @@ query_obj_updated_cb (CalQuery *query, const char *uid, orig_idx = remove_object (model, uid); - status = cal_client_get_object (priv->client, uid, &new_comp); + status = cal_client_get_object (priv->client, uid, &icalcomp); switch (status) { case CAL_CLIENT_GET_SUCCESS: + new_comp = cal_component_new (); + if (!cal_component_set_icalcomponent (new_comp, icalcomp)) { + g_object_unref (new_comp); + icalcomponent_free (icalcomp); + + if (orig_idx != -1) + e_table_model_row_deleted (E_TABLE_MODEL (model), orig_idx); + else + e_table_model_no_change (E_TABLE_MODEL (model)); + break; + } + /* Insert the object into the model */ cal_component_get_uid (new_comp, &new_comp_uid); diff --git a/calendar/gui/comp-editor-factory.c b/calendar/gui/comp-editor-factory.c index 6c40a0d644..af52c8f4e2 100644 --- a/calendar/gui/comp-editor-factory.c +++ b/calendar/gui/comp-editor-factory.c @@ -240,6 +240,7 @@ static void edit_existing (OpenClient *oc, const char *uid) { CalComponent *comp; + icalcomponent *icalcomp; CalClientGetStatus status; CompEditor *editor; CalComponentVType vtype; @@ -248,11 +249,16 @@ edit_existing (OpenClient *oc, const char *uid) /* Get the object */ - status = cal_client_get_object (oc->client, uid, &comp); + status = cal_client_get_object (oc->client, uid, &icalcomp); switch (status) { case CAL_CLIENT_GET_SUCCESS: - /* see below */ + comp = cal_component_new (); + if (!cal_component_set_icalcomponent (comp, icalcomp)) { + g_object_unref (comp); + icalcomponent_free (icalcomp); + return; + } break; case CAL_CLIENT_GET_NOT_FOUND: diff --git a/calendar/gui/comp-util.c b/calendar/gui/comp-util.c index fc3496be67..28bc66bd54 100644 --- a/calendar/gui/comp-util.c +++ b/calendar/gui/comp-util.c @@ -211,7 +211,7 @@ cal_comp_is_on_server (CalComponent *comp, CalClient *client) { const char *uid; CalClientGetStatus status; - CalComponent *server_comp; + icalcomponent *icalcomp; g_return_val_if_fail (comp != NULL, FALSE); g_return_val_if_fail (IS_CAL_COMPONENT (comp), FALSE); @@ -226,11 +226,11 @@ cal_comp_is_on_server (CalComponent *comp, CalClient *client) */ cal_component_get_uid (comp, &uid); - status = cal_client_get_object (client, uid, &server_comp); + status = cal_client_get_object (client, uid, &icalcomp); switch (status) { case CAL_CLIENT_GET_SUCCESS: - g_object_unref (server_comp); + icalcomponent_free (icalcomp); return TRUE; case CAL_CLIENT_GET_SYNTAX_ERROR: @@ -260,16 +260,23 @@ cal_comp_is_on_server (CalComponent *comp, CalClient *client) CalComponent * cal_comp_event_new_with_defaults (CalClient *client) { + icalcomponent *icalcomp; CalComponent *comp; int interval; CalUnits units; CalComponentAlarm *alarm; - icalcomponent *icalcomp; icalproperty *icalprop; CalAlarmTrigger trigger; - if (cal_client_get_default_object (client, CALOBJ_TYPE_EVENT, &comp) != CAL_CLIENT_GET_SUCCESS) + if (cal_client_get_default_object (client, CALOBJ_TYPE_EVENT, &icalcomp) != CAL_CLIENT_GET_SUCCESS) + return NULL; + + comp = cal_component_new (); + if (!cal_component_set_icalcomponent (comp, icalcomp)) { + g_object_unref (comp); + icalcomponent_free (icalcomp); return NULL; + } if (!calendar_config_get_use_default_reminder ()) return comp; @@ -325,9 +332,17 @@ CalComponent * cal_comp_task_new_with_defaults (CalClient *client) { CalComponent *comp; + icalcomponent *icalcomp; - if (cal_client_get_default_object (client, CALOBJ_TYPE_TODO, &comp) != CAL_CLIENT_GET_SUCCESS) + if (cal_client_get_default_object (client, CALOBJ_TYPE_TODO, &icalcomp) != CAL_CLIENT_GET_SUCCESS) return NULL; + comp = cal_component_new (); + if (!cal_component_set_icalcomponent (comp, icalcomp)) { + g_object_unref (comp); + icalcomponent_free (icalcomp); + return NULL; + } + return comp; } diff --git a/calendar/gui/dialogs/comp-editor.c b/calendar/gui/dialogs/comp-editor.c index 62612975d2..1b3afd118b 100644 --- a/calendar/gui/dialogs/comp-editor.c +++ b/calendar/gui/dialogs/comp-editor.c @@ -1450,9 +1450,21 @@ obj_updated_cb (CalClient *client, const char *uid, gpointer data) if (!strcmp (uid, edit_uid) && !priv->updating) { if (changed_component_dialog ((GtkWindow *) editor, priv->comp, FALSE, priv->changed)) { - status = cal_client_get_object (priv->client, uid, &comp); + icalcomponent *icalcomp; + + status = cal_client_get_object (priv->client, uid, &icalcomp); if (status == CAL_CLIENT_GET_SUCCESS) { - comp_editor_edit_comp (editor, comp); + comp = cal_component_new (); + if (cal_component_set_icalcomponent (comp, icalcomp)) + comp_editor_edit_comp (editor, comp); + else { + GtkWidget *dlg; + + dlg = gnome_error_dialog (_("Unable to obtain current version!")); + gnome_dialog_run_and_close (GNOME_DIALOG (dlg)); + icalcomponent_free (icalcomp); + } + g_object_unref((comp)); } else { GtkWidget *dlg; diff --git a/calendar/gui/e-cal-model-calendar.c b/calendar/gui/e-cal-model-calendar.c new file mode 100644 index 0000000000..246d1c5ca8 --- /dev/null +++ b/calendar/gui/e-cal-model-calendar.c @@ -0,0 +1,447 @@ +/* Evolution calendar - Data model for ETable + * + * Copyright (C) 2000 Ximian, Inc. + * Copyright (C) 2000 Ximian, Inc. + * + * Authors: Rodrigo Moya <rodrigo@ximian.com> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of version 2 of the GNU General Public + * License as published by the Free Software Foundation. + * + * 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 <string.h> +#include <libgnome/gnome-i18n.h> +#include <gal/util/e-util.h> +#include "e-cal-model-calendar.h" +#include "e-cell-date-edit-text.h" +#include "misc.h" + +struct _ECalModelCalendarPrivate { +}; + +static void ecmc_class_init (ECalModelCalendarClass *klass); +static void ecmc_init (ECalModelCalendar *model, ECalModelCalendarClass *klass); +static void ecmc_finalize (GObject *object); +static int ecmc_column_count (ETableModel *etm); +static void *ecmc_value_at (ETableModel *etm, int col, int row); +static void ecmc_set_value_at (ETableModel *etm, int col, int row, const void *value); +static gboolean ecmc_is_cell_editable (ETableModel *etm, int col, int row); +static void ecmc_append_row (ETableModel *etm, ETableModel *source, int row); +static void *ecmc_duplicate_value (ETableModel *etm, int col, const void *value); +static void ecmc_free_value (ETableModel *etm, int col, void *value); +static void *ecmc_initialize_value (ETableModel *etm, int col); +static gboolean ecmc_value_is_empty (ETableModel *etm, int col, const void *value); +static char *ecmc_value_to_string (ETableModel *etm, int col, const void *value); + +static GObjectClass *parent_class = NULL; + +E_MAKE_TYPE (e_cal_model_calendar, "ECalModelCalendar", ECalModelCalendar, ecmc_class_init, + ecmc_init, E_TYPE_CAL_MODEL); + +static void +ecmc_class_init (ECalModelCalendarClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + ETableModelClass *etm_class = E_TABLE_MODEL_CLASS (klass); + + parent_class = g_type_class_peek_parent (klass); + + object_class->finalize = ecmc_finalize; + + etm_class->column_count = ecmc_column_count; + etm_class->value_at = ecmc_value_at; + etm_class->set_value_at = ecmc_set_value_at; + etm_class->is_cell_editable = ecmc_is_cell_editable; + etm_class->append_row = ecmc_append_row; + etm_class->duplicate_value = ecmc_duplicate_value; + etm_class->free_value = ecmc_free_value; + etm_class->initialize_value = ecmc_initialize_value; + etm_class->value_is_empty = ecmc_value_is_empty; + etm_class->value_to_string = ecmc_value_to_string; +} + +static void +ecmc_init (ECalModelCalendar *model, ECalModelCalendarClass *klass) +{ + ECalModelCalendarPrivate *priv; + + priv = g_new0 (ECalModelCalendarPrivate, 1); + model->priv = priv; + + e_cal_model_set_component_kind (E_CAL_MODEL (model), ICAL_VEVENT_COMPONENT); +} + +static void +ecmc_finalize (GObject *object) +{ + ECalModelCalendarPrivate *priv; + ECalModelCalendar *model = (ECalModelCalendar *) object; + + g_return_if_fail (E_IS_CAL_MODEL_CALENDAR (model)); + + priv = model->priv; + if (priv) { + g_free (priv); + model->priv = NULL; + } + + if (parent_class->finalize) + parent_class->finalize (object); +} + +/* ETableModel methods */ +static int +ecmc_column_count (ETableModel *etm) +{ + return E_CAL_MODEL_CALENDAR_FIELD_LAST; +} + +static ECellDateEditValue * +get_dtend (ECalModelComponent *comp_data) +{ + struct icaltimetype tt_end; + + if (!comp_data->dtend) { + icaltimezone *zone; + + tt_end = icalcomponent_get_dtend (comp_data->icalcomp); + if (!icaltime_is_valid_time (tt_end)) + return NULL; + + comp_data->dtend = g_new0 (ECellDateEditValue, 1); + comp_data->dtend->tt = tt_end; + + /* FIXME: handle errors */ + cal_client_get_timezone (comp_data->client, + icaltimezone_get_tzid (icaltimezone_get_builtin_timezone (tt_end.zone)), + &zone); + comp_data->dtend->zone = zone; + } + + return comp_data->dtend; +} + +static void * +get_location (ECalModelComponent *comp_data) +{ + icalproperty *prop; + + prop = icalcomponent_get_first_property (comp_data->icalcomp, ICAL_LOCATION_PROPERTY); + if (prop) + return (void *) icalproperty_get_location (prop); + + return NULL; +} + +static void * +get_transparency (ECalModelComponent *comp_data) +{ + icalproperty *prop; + + prop = icalcomponent_get_first_property (comp_data->icalcomp, ICAL_TRANSP_PROPERTY); + if (prop) { + const char *transp; + + transp = icalproperty_get_transp (prop); + if (strcasecmp (transp, "TRANSPARENT") == 0) + return _("Free"); + else if (strcasecmp (transp, "OPAQUE") == 0) + return _("Busy"); + } + + return NULL; +} + +static void * +ecmc_value_at (ETableModel *etm, int col, int row) +{ + ECalModelComponent *comp_data; + ECalModelCalendarPrivate *priv; + ECalModelCalendar *model = (ECalModelCalendar *) etm; + + g_return_val_if_fail (E_IS_CAL_MODEL_CALENDAR (model), NULL); + + priv = model->priv; + + g_return_val_if_fail (col >= 0 && col < E_CAL_MODEL_CALENDAR_FIELD_LAST, NULL); + g_return_val_if_fail (row >= 0 && row < e_table_model_row_count (etm), NULL); + + if (col < E_CAL_MODEL_FIELD_LAST) + return E_TABLE_MODEL_CLASS (parent_class)->value_at (etm, col, row); + + comp_data = e_cal_model_get_component_at (E_CAL_MODEL (model), row); + if (!comp_data) + return ""; + + switch (col) { + case E_CAL_MODEL_CALENDAR_FIELD_DTEND : + return get_dtend (comp_data); + case E_CAL_MODEL_CALENDAR_FIELD_LOCATION : + return get_location (comp_data); + case E_CAL_MODEL_CALENDAR_FIELD_TRANSPARENCY : + return get_transparency (comp_data); + } + + return ""; +} + +static void +set_dtend (ECalModelComponent *comp_data, const void *value) +{ + icalproperty *prop; + ECellDateEditValue *dv = (ECellDateEditValue *) value; + + prop = icalcomponent_get_first_property (comp_data->icalcomp, ICAL_DTEND_PROPERTY); + if (!dv) { + if (prop) { + icalcomponent_remove_property (comp_data->icalcomp, prop); + icalproperty_free (prop); + } + } else + icalcomponent_set_dtend (comp_data->icalcomp, dv->tt); +} + +static void +set_location (ECalModelComponent *comp_data, const void *value) +{ + icalproperty *prop; + + prop = icalcomponent_get_first_property (comp_data->icalcomp, ICAL_LOCATION_PROPERTY); + + if (string_is_empty (value)) { + if (prop) { + icalcomponent_remove_property (comp_data->icalcomp, prop); + icalproperty_free (prop); + } + } else { + if (prop) + icalproperty_set_location (prop, (const char *) value); + else { + prop = icalproperty_new_location ((const char *) value); + icalcomponent_add_property (comp_data->icalcomp, prop); + } + } +} + +static void +set_transparency (ECalModelComponent *comp_data, const void *value) +{ + icalproperty *prop; + + prop = icalcomponent_get_first_property (comp_data->icalcomp, ICAL_TRANSP_PROPERTY); + + if (string_is_empty (value)) { + if (prop) { + icalcomponent_remove_property (comp_data->icalcomp, prop); + icalproperty_free (prop); + } + } else { + const char *transp; + + if (strcasecmp (value, "FREE")) + transp = "TRANSPARENT"; + else if (strcasecmp (value, "OPAQUE")) + transp = "OPAQUE"; + else { + if (prop) { + icalcomponent_remove_property (comp_data->icalcomp, prop); + icalproperty_free (prop); + } + + return; + } + + if (prop) + icalproperty_set_transp (prop, transp); + else { + prop = icalproperty_new_transp (transp); + icalcomponent_add_property (comp_data->icalcomp, prop); + } + } +} + +static void +ecmc_set_value_at (ETableModel *etm, int col, int row, const void *value) +{ + ECalModelComponent *comp_data; + ECalModelCalendar *model = (ECalModelCalendar *) etm; + + g_return_if_fail (E_IS_CAL_MODEL_CALENDAR (model)); + g_return_if_fail (col >= 0 && col < E_CAL_MODEL_CALENDAR_FIELD_LAST); + g_return_if_fail (row >= 0 && row < e_table_model_row_count (etm)); + + if (col < E_CAL_MODEL_FIELD_LAST) { + E_TABLE_MODEL_CLASS (parent_class)->set_value_at (etm, col, row, value); + return; + } + + comp_data = e_cal_model_get_component_at (E_CAL_MODEL (model), row); + if (!comp_data) + return; + + switch (col) { + case E_CAL_MODEL_CALENDAR_FIELD_DTEND : + set_dtend (comp_data, value); + break; + case E_CAL_MODEL_CALENDAR_FIELD_LOCATION : + set_location (comp_data, value); + break; + case E_CAL_MODEL_CALENDAR_FIELD_TRANSPARENCY : + set_transparency (comp_data, value); + break; + } + + if (cal_client_update_objects (comp_data->client, comp_data->icalcomp) != CAL_CLIENT_RESULT_SUCCESS) + g_message ("ecmc_set_value_at(): Could not update the object!"); +} + +static gboolean +ecmc_is_cell_editable (ETableModel *etm, int col, int row) +{ + ECalModelCalendar *model = (ECalModelCalendar *) etm; + + g_return_val_if_fail (E_IS_CAL_MODEL_CALENDAR (model), FALSE); + g_return_val_if_fail (col >= 0 && col < E_CAL_MODEL_CALENDAR_FIELD_LAST, FALSE); + + /* FIXME: We can't check this as 'click-to-add' passes row 0. */ + /* g_return_val_if_fail (row >= 0 && row < e_table_model_get_row_count (etm), FALSE); */ + + if (col < E_CAL_MODEL_FIELD_LAST) + return E_TABLE_MODEL_CLASS (parent_class)->is_cell_editable (etm, col, row); + + switch (col) { + case E_CAL_MODEL_CALENDAR_FIELD_DTEND : + case E_CAL_MODEL_CALENDAR_FIELD_LOCATION : + case E_CAL_MODEL_CALENDAR_FIELD_TRANSPARENCY : + return TRUE; + } + + return FALSE; +} + +static void +ecmc_append_row (ETableModel *etm, ETableModel *source, gint row) +{ + ECalModelCalendar *model = (ECalModelCalendar *) etm; + + g_return_if_fail (E_IS_CAL_MODEL_CALENDAR (model)); + + /* FIXME: how to chain to ecm_append_row? */ +} + +static void * +ecmc_duplicate_value (ETableModel *etm, int col, const void *value) +{ + g_return_val_if_fail (col >= 0 && col < E_CAL_MODEL_CALENDAR_FIELD_LAST, NULL); + + if (col < E_CAL_MODEL_FIELD_LAST) + return E_TABLE_MODEL_CLASS (parent_class)->duplicate_value (etm, col, value); + + switch (col) { + case E_CAL_MODEL_CALENDAR_FIELD_DTEND : + /* FIXME */ + break; + case E_CAL_MODEL_CALENDAR_FIELD_LOCATION : + case E_CAL_MODEL_CALENDAR_FIELD_TRANSPARENCY : + return g_strdup (value); + } + + return NULL; +} + +static void +ecmc_free_value (ETableModel *etm, int col, void *value) +{ + g_return_if_fail (col >= 0 && col < E_CAL_MODEL_CALENDAR_FIELD_LAST); + + if (col < E_CAL_MODEL_FIELD_LAST) { + E_TABLE_MODEL_CLASS (parent_class)->free_value (etm, col, value); + return; + } + + switch (col) { + case E_CAL_MODEL_CALENDAR_FIELD_DTEND : + case E_CAL_MODEL_CALENDAR_FIELD_LOCATION : + case E_CAL_MODEL_CALENDAR_FIELD_TRANSPARENCY : + if (value) + g_free (value); + break; + } +} + +static void * +ecmc_initialize_value (ETableModel *etm, int col) +{ + g_return_val_if_fail (col >= 0 && col < E_CAL_MODEL_CALENDAR_FIELD_LAST, NULL); + + if (col < E_CAL_MODEL_FIELD_LAST) + return E_TABLE_MODEL_CLASS (parent_class)->initialize_value (etm, col); + + switch (col) { + case E_CAL_MODEL_CALENDAR_FIELD_DTEND : + return NULL; + case E_CAL_MODEL_CALENDAR_FIELD_LOCATION : + case E_CAL_MODEL_CALENDAR_FIELD_TRANSPARENCY : + return g_strdup (""); + } + + return NULL; +} + +static gboolean +ecmc_value_is_empty (ETableModel *etm, int col, const void *value) +{ + g_return_val_if_fail (col >= 0 && col < E_CAL_MODEL_CALENDAR_FIELD_LAST, TRUE); + + if (col < E_CAL_MODEL_FIELD_LAST) + return E_TABLE_MODEL_CLASS (parent_class)->value_is_empty (etm, col, value); + + switch (col) { + case E_CAL_MODEL_CALENDAR_FIELD_DTEND : + return value ? FALSE : TRUE; + case E_CAL_MODEL_CALENDAR_FIELD_LOCATION : + case E_CAL_MODEL_CALENDAR_FIELD_TRANSPARENCY : + return string_is_empty (value); + } + + return TRUE; +} + +static char * +ecmc_value_to_string (ETableModel *etm, int col, const void *value) +{ + g_return_val_if_fail (col >= 0 && col < E_CAL_MODEL_CALENDAR_FIELD_LAST, NULL); + + if (col < E_CAL_MODEL_FIELD_LAST) + return E_TABLE_MODEL_CLASS (parent_class)->value_to_string (etm, col, value); + + switch (col) { + case E_CAL_MODEL_CALENDAR_FIELD_DTEND : + return e_cal_model_date_value_to_string (E_CAL_MODEL (etm), value); + case E_CAL_MODEL_CALENDAR_FIELD_LOCATION : + case E_CAL_MODEL_CALENDAR_FIELD_TRANSPARENCY : + return g_strdup (value); + } + + return NULL; +} + +/** + * e_cal_model_calendar_new + */ +ECalModelCalendar * +e_cal_model_calendar_new (void) +{ + return g_object_new (E_TYPE_CAL_MODEL_CALENDAR, NULL); +} diff --git a/calendar/gui/e-cal-model-calendar.h b/calendar/gui/e-cal-model-calendar.h new file mode 100644 index 0000000000..6ddf312a27 --- /dev/null +++ b/calendar/gui/e-cal-model-calendar.h @@ -0,0 +1,58 @@ +/* Evolution calendar - Data model for ETable + * + * Copyright (C) 2000 Ximian, Inc. + * Copyright (C) 2000 Ximian, Inc. + * + * Authors: Rodrigo Moya <rodrigo@ximian.com> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of version 2 of the GNU General Public + * License as published by the Free Software Foundation. + * + * 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. + */ + +#ifndef E_CAL_MODEL_CALENDAR_H +#define E_CAL_MODEL_CALENDAR_H + +#include "e-cal-model.h" + +G_BEGIN_DECLS + +#define E_TYPE_CAL_MODEL_CALENDAR (e_cal_model_calendar_get_type ()) +#define E_CAL_MODEL_CALENDAR(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), E_TYPE_CAL_MODEL_CALENDAR, ECalModelCalendar)) +#define E_CAL_MODEL_CALENDAR_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), E_TYPE_CAL_MODEL_CALENDAR, ECalModelCalendarClass)) +#define E_IS_CAL_MODEL_CALENDAR(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), E_TYPE_CAL_MODEL_CALENDAR)) +#define E_IS_CAL_MODEL_CALENDAR_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), E_TYPE_CAL_MODEL_CALENDAR)) + +typedef struct _ECalModelCalendarPrivate ECalModelCalendarPrivate; + +typedef enum { + E_CAL_MODEL_CALENDAR_FIELD_DTEND = E_CAL_MODEL_FIELD_LAST, + E_CAL_MODEL_CALENDAR_FIELD_LOCATION, + E_CAL_MODEL_CALENDAR_FIELD_TRANSPARENCY, + E_CAL_MODEL_CALENDAR_FIELD_LAST +} ECalModelCalendarField; + +typedef struct { + ECalModel model; + ECalModelCalendarPrivate *priv; +} ECalModelCalendar; + +typedef struct { + ECalModelClass parent_class; +} ECalModelCalendarClass; + +GType e_cal_model_calendar_get_type (void); +ECalModelCalendar *e_cal_model_calendar_new (void); + +G_END_DECLS + +#endif diff --git a/calendar/gui/e-cal-model-tasks.c b/calendar/gui/e-cal-model-tasks.c new file mode 100644 index 0000000000..7c97f5ba01 --- /dev/null +++ b/calendar/gui/e-cal-model-tasks.c @@ -0,0 +1,904 @@ +/* Evolution calendar - Data model for ETable + * + * Copyright (C) 2000 Ximian, Inc. + * Copyright (C) 2000 Ximian, Inc. + * + * Authors: Rodrigo Moya <rodrigo@ximian.com> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of version 2 of the GNU General Public + * License as published by the Free Software Foundation. + * + * 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 <math.h> +#include <gtk/gtkmessagedialog.h> +#include <libgnome/gnome-i18n.h> +#include <gal/util/e-util.h> +#include "e-cal-model-tasks.h" +#include "e-cell-date-edit-text.h" +#include "misc.h" + +struct _ECalModelTasksPrivate { +}; + +static void ecmt_class_init (ECalModelTasksClass *klass); +static void ecmt_init (ECalModelTasks *model, ECalModelTasksClass *klass); +static void ecmt_finalize (GObject *object); + +static int ecmt_column_count (ETableModel *etm); +static void *ecmt_value_at (ETableModel *etm, int col, int row); +static void ecmt_set_value_at (ETableModel *etm, int col, int row, const void *value); +static gboolean ecmt_is_cell_editable (ETableModel *etm, int col, int row); +static void ecmt_append_row (ETableModel *etm, ETableModel *source, int row); +static void *ecmt_duplicate_value (ETableModel *etm, int col, const void *value); +static void ecmt_free_value (ETableModel *etm, int col, void *value); +static void *ecmt_initialize_value (ETableModel *etm, int col); +static gboolean ecmt_value_is_empty (ETableModel *etm, int col, const void *value); +static char *ecmt_value_to_string (ETableModel *etm, int col, const void *value); +static const char *ecmt_get_color_for_component (ECalModel *model, ECalModelComponent *comp_data); + +static GObjectClass *parent_class = NULL; + +E_MAKE_TYPE (e_cal_model_tasks, "ECalModelTasks", ECalModelTasks, ecmt_class_init, + ecmt_init, E_TYPE_CAL_MODEL); + +static void +ecmt_class_init (ECalModelTasksClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + ETableModelClass *etm_class = E_TABLE_MODEL_CLASS (klass); + + parent_class = g_type_class_peek_parent (klass); + + object_class->finalize = ecmt_finalize; + + etm_class->column_count = ecmt_column_count; + etm_class->value_at = ecmt_value_at; + etm_class->set_value_at = ecmt_set_value_at; + etm_class->is_cell_editable = ecmt_is_cell_editable; + etm_class->append_row = ecmt_append_row; + etm_class->duplicate_value = ecmt_duplicate_value; + etm_class->free_value = ecmt_free_value; + etm_class->initialize_value = ecmt_initialize_value; + etm_class->value_is_empty = ecmt_value_is_empty; + etm_class->value_to_string = ecmt_value_to_string; +} + +static void +ecmt_init (ECalModelTasks *model, ECalModelTasksClass *klass) +{ + ECalModelTasksPrivate *priv; + + priv = g_new0 (ECalModelTasksPrivate, 1); + model->priv = priv; + + e_cal_model_set_component_kind (E_CAL_MODEL (model), ICAL_VTODO_COMPONENT); +} + +static void +ecmt_finalize (GObject *object) +{ + ECalModelTasksPrivate *priv; + ECalModelTasks *model = (ECalModelTasks *) object; + + g_return_if_fail (E_IS_CAL_MODEL_TASKS (model)); + + priv = model->priv; + if (priv) { + g_free (priv); + model->priv = NULL; + } + + if (parent_class->finalize) + parent_class->finalize (object); +} + +/* ETableModel methods */ +static int +ecmt_column_count (ETableModel *etm) +{ + return E_CAL_MODEL_TASKS_FIELD_LAST; +} + +/* This makes sure a task is marked as complete. + It makes sure the "Date Completed" property is set. If the completed_date + is not -1, then that is used, otherwise if the "Date Completed" property + is not already set it is set to the current time. + It makes sure the percent is set to 100, and that the status is "Completed". + Note that this doesn't update the component on the server. */ +static void +ensure_task_complete (ECalModelComponent *comp_data, time_t completed_date) +{ + icalproperty *prop; + gboolean set_completed = TRUE; + + prop = icalcomponent_get_first_property (comp_data->icalcomp, ICAL_COMPLETED_PROPERTY); + + /* Date Completed. */ + if (completed_date == -1) { + if (prop) + set_completed = FALSE; + else + completed_date = time (NULL); + } + + if (set_completed) { + icaltimezone *utc_zone; + struct icaltimetype new_completed; + + /* COMPLETED is stored in UTC. */ + utc_zone = icaltimezone_get_utc_timezone (); + new_completed = icaltime_from_timet_with_zone (completed_date, + FALSE, + utc_zone); + if (prop) + icalproperty_set_completed (prop, new_completed); + else { + prop = icalproperty_new_completed (new_completed); + icalcomponent_add_property (comp_data->icalcomp, prop); + } + } + + /* Percent. */ + prop = icalcomponent_get_first_property (comp_data->icalcomp, ICAL_PERCENTCOMPLETE_PROPERTY); + if (!prop) + icalcomponent_add_property (comp_data->icalcomp, icalproperty_new_percentcomplete (100)); + else + icalproperty_set_percentcomplete (prop, 100); + + /* Status. */ + prop = icalcomponent_get_first_property (comp_data->icalcomp, ICAL_STATUS_PROPERTY); + if (prop) + icalproperty_set_status (prop, ICAL_STATUS_COMPLETED); + else + icalcomponent_add_property (comp_data->icalcomp, icalproperty_new_status (ICAL_STATUS_COMPLETED)); +} + + +/* This makes sure a task is marked as incomplete. It clears the + "Date Completed" property. If the percent is set to 100 it removes it, + and if the status is "Completed" it sets it to "Needs Action". + Note that this doesn't update the component on the client. */ +static void +ensure_task_not_complete (ECalModelComponent *comp_data) +{ + icalproperty *prop; + + /* Date Completed. */ + prop = icalcomponent_get_first_property (comp_data->icalcomp, ICAL_COMPLETED_PROPERTY); + if (prop) { + icalcomponent_remove_property (comp_data->icalcomp, prop); + icalproperty_free (prop); + } + + /* Percent. */ + prop = icalcomponent_get_first_property (comp_data->icalcomp, ICAL_PERCENTCOMPLETE_PROPERTY); + if (prop) { + icalcomponent_remove_property (comp_data->icalcomp, prop); + icalproperty_free (prop); + } + + /* Status. */ + prop = icalcomponent_get_first_property (comp_data->icalcomp, ICAL_PERCENTCOMPLETE_PROPERTY); + if (prop) + icalproperty_set_status (prop, ICAL_STATUS_NEEDSACTION); +} + +static ECellDateEditValue * +get_completed (ECalModelComponent *comp_data) +{ + /* FIXME */ + + return NULL; +} + +static char * +get_geo (ECalModelComponent *comp_data) +{ + icalproperty *prop; + struct icalgeotype geo; + static gchar buf[32]; + + prop = icalcomponent_get_first_property (comp_data->icalcomp, ICAL_GEO_PROPERTY); + if (prop) { + geo = icalproperty_get_geo (prop); + g_snprintf (buf, sizeof (buf), "%g %s, %g %s", + fabs (geo.lat), + geo.lat >= 0.0 ? _("N") : _("S"), + fabs (geo.lon), + geo.lon >= 0.0 ? _("E") : _("W")); + return buf; + } + + return ""; +} + +static int +get_percent (ECalModelComponent *comp_data) +{ + icalproperty *prop; + + prop = icalcomponent_get_first_property (comp_data->icalcomp, ICAL_PERCENTCOMPLETE_PROPERTY); + if (prop) + return icalproperty_get_percentcomplete (prop); + + return 0; +} + +static char * +get_priority (ECalModelComponent *comp_data) +{ + icalproperty *prop; + + prop = icalcomponent_get_first_property (comp_data->icalcomp, ICAL_PRIORITY_PROPERTY); + if (prop) + return cal_util_priority_to_string (icalproperty_get_priority (prop)); + + return ""; +} + +static char * +get_status (ECalModelComponent *comp_data) +{ + icalproperty *prop; + + prop = icalcomponent_get_first_property (comp_data->icalcomp, ICAL_STATUS_PROPERTY); + if (prop) { + switch (icalproperty_get_status (prop)) { + case ICAL_STATUS_NONE: + return ""; + case ICAL_STATUS_NEEDSACTION: + return _("Not Started"); + case ICAL_STATUS_INPROCESS: + return _("In Progress"); + case ICAL_STATUS_COMPLETED: + return _("Completed"); + case ICAL_STATUS_CANCELLED: + return _("Cancelled"); + default: + g_assert_not_reached (); + return NULL; + } + } + + return ""; +} + +static char * +get_url (ECalModelComponent *comp_data) +{ + icalproperty *prop; + + prop = icalcomponent_get_first_property (comp_data->icalcomp, ICAL_URL_PROPERTY); + if (prop) + return (char *) icalproperty_get_url (prop); + + return ""; +} + +static gboolean +is_complete (ECalModelComponent *comp_data) +{ + icalproperty *prop; + + prop = icalcomponent_get_first_property (comp_data->icalcomp, ICAL_COMPLETED_PROPERTY); + + return prop ? TRUE : FALSE; +} + +typedef enum { + E_CAL_MODEL_TASKS_DUE_NEVER, + E_CAL_MODEL_TASKS_DUE_FUTURE, + E_CAL_MODEL_TASKS_DUE_TODAY, + E_CAL_MODEL_TASKS_DUE_OVERDUE, + E_CAL_MODEL_TASKS_DUE_COMPLETE +} ECalModelTasksDueStatus; + + +static ECalModelTasksDueStatus +get_due_status (ECalModelTasks *model, ECalModelComponent *comp_data) +{ + icalproperty *prop; + + /* First, do we have a due date? */ + prop = icalcomponent_get_first_property (comp_data->icalcomp, ICAL_DUE_PROPERTY); + if (!prop) + return E_CAL_MODEL_TASKS_DUE_NEVER; + else { + struct icaltimetype now_tt, due_tt; + CalClientGetStatus status; + icaltimezone *zone; + + /* Second, is it already completed? */ + if (is_complete (comp_data)) + return E_CAL_MODEL_TASKS_DUE_COMPLETE; + + /* Third, are we overdue as of right now? */ + due_tt = icalproperty_get_due (prop); + if (due_tt.is_date) { + int cmp; + + now_tt = icaltime_current_time_with_zone (e_cal_model_get_timezone (E_CAL_MODEL (model))); + cmp = icaltime_compare_date_only (due_tt, now_tt); + + if (cmp < 0) + return E_CAL_MODEL_TASKS_DUE_OVERDUE; + else if (cmp == 0) + return E_CAL_MODEL_TASKS_DUE_TODAY; + else + return E_CAL_MODEL_TASKS_DUE_FUTURE; + } else { + /* Get the current time in the same timezone as the DUE date.*/ + status = cal_client_get_timezone (comp_data->client, + icaltimezone_get_tzid (icaltimezone_get_builtin_timezone (due_tt.zone)), + &zone); + if (status != CAL_CLIENT_GET_SUCCESS) + return E_CAL_MODEL_TASKS_DUE_FUTURE; + + now_tt = icaltime_current_time_with_zone (zone); + + if (icaltime_compare (due_tt, now_tt) <= 0) + return E_CAL_MODEL_TASKS_DUE_OVERDUE; + else + if (icaltime_compare_date_only (due_tt, now_tt) == 0) + return E_CAL_MODEL_TASKS_DUE_TODAY; + else + return E_CAL_MODEL_TASKS_DUE_FUTURE; + } + } + + return E_CAL_MODEL_TASKS_DUE_NEVER; +} + +static gboolean +is_overdue (ECalModelTasks *model, ECalModelComponent *comp_data) +{ + switch (get_due_status (model, comp_data)) { + case E_CAL_MODEL_TASKS_DUE_NEVER: + case E_CAL_MODEL_TASKS_DUE_FUTURE: + case E_CAL_MODEL_TASKS_DUE_COMPLETE: + return FALSE; + case E_CAL_MODEL_TASKS_DUE_TODAY: + case E_CAL_MODEL_TASKS_DUE_OVERDUE: + return TRUE; + } + + return FALSE; +} + +static void * +ecmt_value_at (ETableModel *etm, int col, int row) +{ + ECalModelTasksPrivate *priv; + ECalModelComponent *comp_data; + ECalModelTasks *model = (ECalModelTasks *) etm; + + g_return_val_if_fail (E_IS_CAL_MODEL_TASKS (model), NULL); + + priv = model->priv; + + g_return_val_if_fail (col >= 0 && col < E_CAL_MODEL_TASKS_FIELD_LAST, NULL); + g_return_val_if_fail (row >= 0 && row < e_table_model_row_count (etm), NULL); + + if (col < E_CAL_MODEL_FIELD_LAST) + return E_TABLE_MODEL_CLASS (parent_class)->value_at (etm, col, row); + + comp_data = e_cal_model_get_component_at (E_CAL_MODEL (model), row); + if (!comp_data) + return ""; + + switch (col) { + case E_CAL_MODEL_TASKS_FIELD_COMPLETED : + return get_completed (comp_data); + case E_CAL_MODEL_TASKS_FIELD_COMPLETE : + return GINT_TO_POINTER (is_complete (comp_data)); + case E_CAL_MODEL_TASKS_FIELD_DUE : + /* FIXME */ + break; + case E_CAL_MODEL_TASKS_FIELD_GEO : + return get_geo (comp_data); + case E_CAL_MODEL_TASKS_FIELD_OVERDUE : + return GINT_TO_POINTER (is_overdue (model, comp_data)); + case E_CAL_MODEL_TASKS_FIELD_PERCENT : + return GINT_TO_POINTER (get_percent (comp_data)); + case E_CAL_MODEL_TASKS_FIELD_PRIORITY : + return get_priority (comp_data); + case E_CAL_MODEL_TASKS_FIELD_STATUS : + return get_status (comp_data); + case E_CAL_MODEL_TASKS_FIELD_URL : + return get_url (comp_data); + } + + return ""; +} + +static void +set_completed (ECalModelTasks *model, ECalModelComponent *comp_data, const void *value) +{ + ECellDateEditValue *dv = (ECellDateEditValue *) value; + + if (!dv) + ensure_task_not_complete (comp_data); + else { + time_t t; + + if (dv->tt.is_date) { + /* if it's a date, it will be floating, + but completed needs a date time value */ + dv->tt.is_date = FALSE; + t = icaltime_as_timet_with_zone (dv->tt, e_cal_model_get_timezone (E_CAL_MODEL (model))); + } else { + /* we assume that COMPLETED is entered in the current timezone, + even though it gets stored in UTC */ + t = icaltime_as_timet_with_zone (dv->tt, dv->zone); + } + + ensure_task_complete (comp_data, t); + } +} + +static void +set_complete (ECalModelComponent *comp_data, const void *value) +{ + gint state = GPOINTER_TO_INT (value); + + if (state) + ensure_task_complete (comp_data, -1); + else + ensure_task_not_complete (comp_data); +} + +/* FIXME: We need to set the "transient_for" property for the dialog, but the + * model doesn't know anything about the windows. + */ +static void +show_geo_warning (void) +{ + GtkWidget *dialog; + + dialog = gtk_message_dialog_new (NULL, 0, GTK_MESSAGE_ERROR, GTK_BUTTONS_OK, + _("The geographical position must be entered " + "in the format: \n\n45.436845,125.862501")); + gtk_widget_show (dialog); +} + +static void +set_geo (ECalModelComponent *comp_data, const char *value) +{ + double latitude, longitude; + int matched; + struct icalgeotype geo; + icalproperty *prop; + + prop = icalcomponent_get_first_property (comp_data->icalcomp, ICAL_GEO_PROPERTY); + + if (string_is_empty (value)) { + if (prop) { + icalcomponent_remove_property (comp_data->icalcomp, prop); + icalproperty_free (prop); + } + } else { + matched = sscanf (value, "%lg , %lg", &latitude, &longitude); + if (matched != 2) + show_geo_warning (); + + geo.lat = latitude; + geo.lon = longitude; + if (prop) + icalproperty_set_geo (prop, geo); + else { + prop = icalproperty_new_geo (geo); + icalcomponent_add_property (comp_data->icalcomp, prop); + } + + } +} + +static void +set_status (ECalModelComponent *comp_data, const char *value) +{ + icalproperty_status status; + icalproperty *prop; + + prop = icalcomponent_get_first_property (comp_data->icalcomp, ICAL_STATUS_PROPERTY); + + /* an empty string is the same as 'None' */ + if (!value[0] || !g_strcasecmp (value, _("None"))) + status = ICAL_STATUS_NONE; + else if (!g_strcasecmp (value, _("Not Started"))) + status = ICAL_STATUS_NEEDSACTION; + else if (!g_strcasecmp (value, _("In Progress"))) + status = ICAL_STATUS_INPROCESS; + else if (!g_strcasecmp (value, _("Completed"))) + status = ICAL_STATUS_COMPLETED; + else if (!g_strcasecmp (value, _("Cancelled"))) + status = ICAL_STATUS_CANCELLED; + else { + g_warning ("Invalid status: %s\n", value); + return; + } + + if (prop) + icalproperty_set_status (prop, status); + else { + prop = icalproperty_new_status (status); + icalcomponent_add_property (comp_data->icalcomp, prop); + } + +/* if (status == ICAL_STATUS_NEEDSACTION) { */ +/* percent = 0; */ +/* cal_component_set_percent (comp, &percent); */ +/* cal_component_set_completed (comp, NULL); */ +/* } else if (status == ICAL_STATUS_INPROCESS) { */ +/* ensure_task_not_complete (comp); */ +/* percent = 50; */ +/* cal_component_set_percent (comp, &percent); */ +/* } else if (status == ICAL_STATUS_COMPLETED) { */ +/* ensure_task_complete (comp, -1); */ +/* } */ +} + +static void +set_percent (ECalModelComponent *comp_data, const void *value) +{ + icalproperty *prop; + gint percent = GPOINTER_TO_INT (value); + + g_return_if_fail (percent >= -1); + g_return_if_fail (percent <= 100); + + prop = icalcomponent_get_first_property (comp_data->icalcomp, ICAL_PERCENTCOMPLETE_PROPERTY); + + /* A value of -1 means it isn't set */ + if (percent == -1) { + if (prop) { + icalcomponent_remove_property (comp_data->icalcomp, prop); + icalproperty_free (prop); + } + ensure_task_not_complete (comp_data); + } else { + if (prop) + icalproperty_set_percentcomplete (prop, percent); + else { + prop = icalproperty_new_percentcomplete (percent); + icalcomponent_add_property (comp_data->icalcomp, prop); + } + + if (percent == 100) + ensure_task_complete (comp_data, -1); + else { + ensure_task_not_complete (comp_data); + if (percent > 0) + set_status (comp_data, _("In Progress")); + } + } + +} + +static void +set_priority (ECalModelComponent *comp_data, const char *value) +{ + icalproperty *prop; + int priority; + + prop = icalcomponent_get_first_property (comp_data->icalcomp, ICAL_PRIORITY_PROPERTY); + + priority = cal_util_priority_from_string (value); + if (priority == -1) { + g_warning ("Invalid priority"); + priority = 0; + } + + if (prop) + icalproperty_set_priority (prop, priority); + else { + prop = icalproperty_new_priority (priority); + icalcomponent_add_property (comp_data->icalcomp, prop); + } +} + +static void +set_url (ECalModelComponent *comp_data, const char *value) +{ + icalproperty *prop; + + prop = icalcomponent_get_first_property (comp_data->icalcomp, ICAL_URL_PROPERTY); + + if (string_is_empty (value)) { + if (prop) { + icalcomponent_remove_property (comp_data->icalcomp, prop); + icalproperty_free (prop); + } + } else { + if (prop) + icalproperty_set_url (prop, value); + else { + prop = icalproperty_new_url (value); + icalcomponent_add_property (comp_data->icalcomp, prop); + } + } +} + +static void +ecmt_set_value_at (ETableModel *etm, int col, int row, const void *value) +{ + ECalModelTasksPrivate *priv; + ECalModelComponent *comp_data; + ECalModelTasks *model = (ECalModelTasks *) etm; + + g_return_if_fail (E_IS_CAL_MODEL_TASKS (model)); + + priv = model->priv; + + g_return_if_fail (col >= 0 && col < E_CAL_MODEL_TASKS_FIELD_LAST); + g_return_if_fail (row >= 0 && row < e_table_model_row_count (etm)); + + if (col < E_CAL_MODEL_FIELD_LAST) { + E_TABLE_MODEL_CLASS (parent_class)->set_value_at (etm, col, row, value); + return; + } + + comp_data = e_cal_model_get_component_at (E_CAL_MODEL (model), row); + if (!comp_data) + return; + + switch (col) { + case E_CAL_MODEL_TASKS_FIELD_COMPLETED : + set_completed (model, comp_data, value); + break; + case E_CAL_MODEL_TASKS_FIELD_COMPLETE : + set_complete (comp_data, value); + break; + case E_CAL_MODEL_TASKS_FIELD_DUE : + /* FIXME */ + break; + case E_CAL_MODEL_TASKS_FIELD_GEO : + set_geo (comp_data, value); + break; + case E_CAL_MODEL_TASKS_FIELD_PERCENT : + set_percent (comp_data, value); + break; + case E_CAL_MODEL_TASKS_FIELD_PRIORITY : + set_priority (comp_data, value); + break; + case E_CAL_MODEL_TASKS_FIELD_URL : + set_url (comp_data, value); + break; + } + + if (cal_client_update_objects (comp_data->client, comp_data->icalcomp) != CAL_CLIENT_RESULT_SUCCESS) + g_message ("ecmt_set_value_at(): Could not update the object!"); +} + +static gboolean +ecmt_is_cell_editable (ETableModel *etm, int col, int row) +{ + ECalModelTasksPrivate *priv; + ECalModelTasks *model = (ECalModelTasks *) etm; + + g_return_val_if_fail (E_IS_CAL_MODEL_TASKS (model), FALSE); + + priv = model->priv; + + g_return_val_if_fail (col >= 0 && col < E_CAL_MODEL_TASKS_FIELD_LAST, FALSE); + + /* FIXME: We can't check this as 'click-to-add' passes row 0. */ + /* g_return_val_if_fail (row >= 0 && row < e_table_model_get_row_count (etm), FALSE); */ + + if (col < E_CAL_MODEL_FIELD_LAST) + return E_TABLE_MODEL_CLASS (parent_class)->is_cell_editable (etm, col, row); + + switch (col) { + case E_CAL_MODEL_TASKS_FIELD_COMPLETED : + case E_CAL_MODEL_TASKS_FIELD_COMPLETE : + case E_CAL_MODEL_TASKS_FIELD_DUE : + case E_CAL_MODEL_TASKS_FIELD_GEO : + case E_CAL_MODEL_TASKS_FIELD_PERCENT : + case E_CAL_MODEL_TASKS_FIELD_PRIORITY : + case E_CAL_MODEL_TASKS_FIELD_URL : + return TRUE; + } + + return FALSE; +} + +static void +ecmt_append_row (ETableModel *etm, ETableModel *source, gint row) +{ + ECalModelTasksPrivate *priv; + ECalModelTasks *model = (ECalModelTasks *) etm; + + g_return_if_fail (E_IS_CAL_MODEL_TASKS (model)); + + priv = model->priv; + + /* FIXME: how to chain to ecm_append_row? */ +} + +static void * +ecmt_duplicate_value (ETableModel *etm, int col, const void *value) +{ + g_return_val_if_fail (col >= 0 && col < E_CAL_MODEL_TASKS_FIELD_LAST, NULL); + + if (col < E_CAL_MODEL_FIELD_LAST) + return E_TABLE_MODEL_CLASS (parent_class)->duplicate_value (etm, col, value); + + switch (col) { + case E_CAL_MODEL_TASKS_FIELD_GEO : + case E_CAL_MODEL_TASKS_FIELD_PRIORITY : + case E_CAL_MODEL_TASKS_FIELD_STATUS : + case E_CAL_MODEL_TASKS_FIELD_URL : + return g_strdup (value); + case E_CAL_MODEL_TASKS_FIELD_COMPLETED : + case E_CAL_MODEL_TASKS_FIELD_DUE : + /* FIXME */ + break; + case E_CAL_MODEL_TASKS_FIELD_COMPLETE : + case E_CAL_MODEL_TASKS_FIELD_PERCENT : + case E_CAL_MODEL_TASKS_FIELD_OVERDUE : + return (void *) value; + } + + return NULL; +} + +static void +ecmt_free_value (ETableModel *etm, int col, void *value) +{ + g_return_if_fail (col >= 0 && col < E_CAL_MODEL_TASKS_FIELD_LAST); + + if (col < E_CAL_MODEL_FIELD_LAST) { + E_TABLE_MODEL_CLASS (parent_class)->free_value (etm, col, value); + return; + } + + switch (col) { + case E_CAL_MODEL_TASKS_FIELD_COMPLETED : + case E_CAL_MODEL_TASKS_FIELD_DUE : + case E_CAL_MODEL_TASKS_FIELD_GEO : + case E_CAL_MODEL_TASKS_FIELD_PRIORITY : + case E_CAL_MODEL_TASKS_FIELD_STATUS : + case E_CAL_MODEL_TASKS_FIELD_URL : + if (value) + g_free (value); + break; + case E_CAL_MODEL_TASKS_FIELD_PERCENT : + case E_CAL_MODEL_TASKS_FIELD_COMPLETE : + case E_CAL_MODEL_TASKS_FIELD_OVERDUE : + break; + } +} + +static void * +ecmt_initialize_value (ETableModel *etm, int col) +{ + ECalModelTasks *model = (ECalModelTasks *) etm; + + g_return_val_if_fail (E_IS_CAL_MODEL_TASKS (model), NULL); + g_return_val_if_fail (col >= 0 && col < E_CAL_MODEL_TASKS_FIELD_LAST, NULL); + + if (col < E_CAL_MODEL_FIELD_LAST) + return E_TABLE_MODEL_CLASS (parent_class)->initialize_value (etm, col); + + switch (col) { + case E_CAL_MODEL_TASKS_FIELD_GEO : + case E_CAL_MODEL_TASKS_FIELD_PRIORITY : + case E_CAL_MODEL_TASKS_FIELD_STATUS : + case E_CAL_MODEL_TASKS_FIELD_URL : + return g_strdup (""); + case E_CAL_MODEL_TASKS_FIELD_COMPLETED : + case E_CAL_MODEL_TASKS_FIELD_DUE : + case E_CAL_MODEL_TASKS_FIELD_COMPLETE : + case E_CAL_MODEL_TASKS_FIELD_OVERDUE : + return NULL; + case E_CAL_MODEL_TASKS_FIELD_PERCENT : + return GINT_TO_POINTER (-1); + } + + return NULL; +} + +static gboolean +ecmt_value_is_empty (ETableModel *etm, int col, const void *value) +{ + ECalModelTasksPrivate *priv; + ECalModelTasks *model = (ECalModelTasks *) etm; + + g_return_val_if_fail (E_IS_CAL_MODEL_TASKS (model), TRUE); + g_return_val_if_fail (col >= 0 && col < E_CAL_MODEL_TASKS_FIELD_LAST, TRUE); + + priv = model->priv; + + if (col < E_CAL_MODEL_FIELD_LAST) + return E_TABLE_MODEL_CLASS (parent_class)->value_is_empty (etm, col, value); + + switch (col) { + case E_CAL_MODEL_TASKS_FIELD_GEO : + case E_CAL_MODEL_TASKS_FIELD_PRIORITY : + case E_CAL_MODEL_TASKS_FIELD_STATUS : + case E_CAL_MODEL_TASKS_FIELD_URL : + return string_is_empty (value); + case E_CAL_MODEL_TASKS_FIELD_COMPLETED : + case E_CAL_MODEL_TASKS_FIELD_DUE : + return value ? FALSE : TRUE; + case E_CAL_MODEL_TASKS_FIELD_PERCENT : + return (GPOINTER_TO_INT (value) < 0) ? TRUE : FALSE; + case E_CAL_MODEL_TASKS_FIELD_COMPLETE : + case E_CAL_MODEL_TASKS_FIELD_OVERDUE : + return TRUE; + } + + return TRUE; +} + +static char * +ecmt_value_to_string (ETableModel *etm, int col, const void *value) +{ + ECalModelTasks *model = (ECalModelTasks *) etm; + + g_return_val_if_fail (E_IS_CAL_MODEL_TASKS (model), NULL); + g_return_val_if_fail (col >= 0 && col < E_CAL_MODEL_TASKS_FIELD_LAST, NULL); + + if (col < E_CAL_MODEL_FIELD_LAST) + return E_TABLE_MODEL_CLASS (parent_class)->value_to_string (etm, col, value); + + switch (col) { + case E_CAL_MODEL_TASKS_FIELD_GEO : + case E_CAL_MODEL_TASKS_FIELD_PRIORITY : + case E_CAL_MODEL_TASKS_FIELD_STATUS : + case E_CAL_MODEL_TASKS_FIELD_URL : + return g_strdup (value); + case E_CAL_MODEL_TASKS_FIELD_COMPLETED : + case E_CAL_MODEL_TASKS_FIELD_DUE : + return e_cal_model_date_value_to_string (E_CAL_MODEL (model), value); + case E_CAL_MODEL_TASKS_FIELD_COMPLETE : + case E_CAL_MODEL_TASKS_FIELD_OVERDUE : + return value ? _("Yes") : _("No"); + case E_CAL_MODEL_TASKS_FIELD_PERCENT : + if (GPOINTER_TO_INT (value) < 0) + return g_strdup ("N/A"); + else + return g_strdup_printf ("%i%%", GPOINTER_TO_INT (value)); + } + + return NULL; +} + +static const char * +ecmt_get_color_for_component (ECalModel *model, ECalModelComponent *comp_data) +{ + g_return_val_if_fail (E_IS_CAL_MODEL_TASKS (model), NULL); + g_return_val_if_fail (comp_data != NULL, NULL); + + switch (get_due_status ((ECalModelTasks *) model, comp_data)) { + case E_CAL_MODEL_TASKS_DUE_NEVER: + case E_CAL_MODEL_TASKS_DUE_FUTURE: + case E_CAL_MODEL_TASKS_DUE_COMPLETE: + return NULL; + case E_CAL_MODEL_TASKS_DUE_TODAY: + return calendar_config_get_tasks_due_today_color (); + case E_CAL_MODEL_TASKS_DUE_OVERDUE: + return calendar_config_get_tasks_overdue_color (); + } + + return NULL; +} + +/** + * e_cal_model_tasks_new + */ +ECalModelTasks * +e_cal_model_tasks_new (void) +{ + return g_object_new (E_TYPE_CAL_MODEL_TASKS, NULL); +} diff --git a/calendar/gui/e-cal-model-tasks.h b/calendar/gui/e-cal-model-tasks.h new file mode 100644 index 0000000000..852484dcc6 --- /dev/null +++ b/calendar/gui/e-cal-model-tasks.h @@ -0,0 +1,64 @@ +/* Evolution calendar - Data model for ETable + * + * Copyright (C) 2000 Ximian, Inc. + * Copyright (C) 2000 Ximian, Inc. + * + * Authors: Rodrigo Moya <rodrigo@ximian.com> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of version 2 of the GNU General Public + * License as published by the Free Software Foundation. + * + * 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. + */ + +#ifndef E_CAL_MODEL_TASKS_H +#define E_CAL_MODEL_TASKS_H + +#include "e-cal-model.h" + +G_BEGIN_DECLS + +#define E_TYPE_CAL_MODEL_TASKS (e_cal_model_tasks_get_type ()) +#define E_CAL_MODEL_TASKS(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), E_TYPE_CAL_MODEL_TASKS, ECalModelTasks)) +#define E_CAL_MODEL_TASKS_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), E_TYPE_CAL_MODEL_TASKS, ECalModelTasksClass)) +#define E_IS_CAL_MODEL_TASKS(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), E_TYPE_CAL_MODEL_TASKS)) +#define E_IS_CAL_MODEL_TASKS_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), E_TYPE_CAL_MODEL_TASKS)) + +typedef struct _ECalModelTasksPrivate ECalModelTasksPrivate; + +typedef enum { + E_CAL_MODEL_TASKS_FIELD_COMPLETED = E_CAL_MODEL_FIELD_LAST, + E_CAL_MODEL_TASKS_FIELD_COMPLETE, + E_CAL_MODEL_TASKS_FIELD_DUE, + E_CAL_MODEL_TASKS_FIELD_GEO, + E_CAL_MODEL_TASKS_FIELD_OVERDUE, + E_CAL_MODEL_TASKS_FIELD_PERCENT, + E_CAL_MODEL_TASKS_FIELD_PRIORITY, + E_CAL_MODEL_TASKS_FIELD_STATUS, + E_CAL_MODEL_TASKS_FIELD_URL, + E_CAL_MODEL_TASKS_FIELD_LAST +} ECalModelTasksField; + +typedef struct { + ECalModel model; + ECalModelTasksPrivate *priv; +} ECalModelTasks; + +typedef struct { + ECalModelClass parent_class; +} ECalModelTasksClass; + +GType e_cal_model_tasks_get_type (void); +ECalModelTasks *e_cal_model_tasks_new (void); + +G_END_DECLS + +#endif diff --git a/calendar/gui/e-cal-model.c b/calendar/gui/e-cal-model.c new file mode 100644 index 0000000000..a184fabe48 --- /dev/null +++ b/calendar/gui/e-cal-model.c @@ -0,0 +1,1303 @@ +/* Evolution calendar - Data model for ETable + * + * Copyright (C) 2000 Ximian, Inc. + * Copyright (C) 2000 Ximian, Inc. + * + * Authors: Rodrigo Moya <rodrigo@ximian.com> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of version 2 of the GNU General Public + * License as published by the Free Software Foundation. + * + * 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 <string.h> +#include <glib/garray.h> +#include <libgnome/gnome-i18n.h> +#include <gal/util/e-util.h> +#include <e-util/e-time-utils.h> +#include <cal-util/timeutil.h> +#include "calendar-config.h" +#include "e-cal-model.h" +#include "itip-utils.h" +#include "misc.h" + +typedef struct { + CalClient *client; + CalQuery *query; +} ECalModelClient; + +struct _ECalModelPrivate { + /* The list of clients we are managing. Each element is of type ECalModelClient */ + GList *clients; + + /* Array for storing the objects. Each element is of type ECalModelComponent */ + GPtrArray *objects; + + icalcomponent_kind kind; + icaltimezone *zone; + + /* The search regular expression */ + gchar *sexp; + + /* The default category */ + gchar *default_category; + + /* Addresses for determining icons */ + EAccountList *accounts; +}; + +static void e_cal_model_class_init (ECalModelClass *klass); +static void e_cal_model_init (ECalModel *model, ECalModelClass *klass); +static void e_cal_model_finalize (GObject *object); + +static int ecm_column_count (ETableModel *etm); +static int ecm_row_count (ETableModel *etm); +static void *ecm_value_at (ETableModel *etm, int col, int row); +static void ecm_set_value_at (ETableModel *etm, int col, int row, const void *value); +static gboolean ecm_is_cell_editable (ETableModel *etm, int col, int row); +static void ecm_append_row (ETableModel *etm, ETableModel *source, int row); +static void *ecm_duplicate_value (ETableModel *etm, int col, const void *value); +static void ecm_free_value (ETableModel *etm, int col, void *value); +static void *ecm_initialize_value (ETableModel *etm, int col); +static gboolean ecm_value_is_empty (ETableModel *etm, int col, const void *value); +static char *ecm_value_to_string (ETableModel *etm, int col, const void *value); + +static const char *ecm_get_color_for_component (ECalModel *model, ECalModelComponent *comp_data); + +static GObjectClass *parent_class = NULL; + +E_MAKE_TYPE (e_cal_model, "ECalModel", ECalModel, e_cal_model_class_init, + e_cal_model_init, E_TABLE_MODEL_TYPE); + +static void +e_cal_model_class_init (ECalModelClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + ETableModelClass *etm_class = E_TABLE_MODEL_CLASS (klass); + + parent_class = g_type_class_peek_parent (klass); + + object_class->finalize = e_cal_model_finalize; + + etm_class->column_count = ecm_column_count; + etm_class->row_count = ecm_row_count; + etm_class->value_at = ecm_value_at; + etm_class->set_value_at = ecm_set_value_at; + etm_class->is_cell_editable = ecm_is_cell_editable; + etm_class->append_row = ecm_append_row; + etm_class->duplicate_value = ecm_duplicate_value; + etm_class->free_value = ecm_free_value; + etm_class->initialize_value = ecm_initialize_value; + etm_class->value_is_empty = ecm_value_is_empty; + etm_class->value_to_string = ecm_value_to_string; + + klass->get_color_for_component = ecm_get_color_for_component; +} + +static void +e_cal_model_init (ECalModel *model, ECalModelClass *klass) +{ + ECalModelPrivate *priv; + + priv = g_new0 (ECalModelPrivate, 1); + model->priv = priv; + + priv->sexp = g_strdup ("#t"); /* match all by default */ + + priv->objects = g_ptr_array_new (); + priv->kind = ICAL_NO_COMPONENT; + + priv->accounts = itip_addresses_get (); +} + +static void +free_comp_data (ECalModelComponent *comp_data) +{ + g_return_if_fail (comp_data != NULL); + + comp_data->client = NULL; + + if (comp_data->icalcomp) { + icalcomponent_free (comp_data->icalcomp); + comp_data->icalcomp = NULL; + } + + if (comp_data->dtstart) { + g_free (comp_data->dtstart); + comp_data->dtstart = NULL; + } + + if (comp_data->dtend) { + g_free (comp_data->dtend); + comp_data->dtend = NULL; + } + + g_free (comp_data); +} + +static void +clear_objects_array (ECalModelPrivate *priv) +{ + gint i; + + for (i = 0; i < priv->objects->len; i++) { + ECalModelComponent *comp_data; + + comp_data = g_ptr_array_index (priv->objects, i); + g_assert (comp_data != NULL); + free_comp_data (comp_data); + } + + + g_ptr_array_set_size (priv->objects, 0); +} + +static void +e_cal_model_finalize (GObject *object) +{ + ECalModelPrivate *priv; + ECalModel *model = (ECalModel *) object; + + g_return_if_fail (E_IS_CAL_MODEL (model)); + + priv = model->priv; + if (priv) { + if (priv->clients) { + e_cal_model_remove_all_clients (model); + priv->clients = NULL; + } + + if (priv->sexp) { + g_free (priv->sexp); + priv->sexp = NULL; + } + + if (priv->default_category) { + g_free (priv->default_category); + priv->default_category = NULL; + } + + if (priv->objects) { + clear_objects_array (priv); + g_ptr_array_free (priv->objects, FALSE); + priv->objects = NULL; + } + + if (priv->accounts) { + g_object_unref (priv->accounts); + priv->accounts = NULL; + } + + g_free (priv); + model->priv = NULL; + } + + if (parent_class->finalize) + parent_class->finalize (object); +} + +/* ETableModel methods */ + +static int +ecm_column_count (ETableModel *etm) +{ + return E_CAL_MODEL_FIELD_LAST; +} + +static int +ecm_row_count (ETableModel *etm) +{ + ECalModelPrivate *priv; + ECalModel *model = (ECalModel *) etm; + + g_return_val_if_fail (E_IS_CAL_MODEL (model), -1); + + priv = model->priv; + + return priv->objects->len; +} + +static char * +get_categories (ECalModelComponent *comp_data) +{ + icalproperty *prop; + + prop = icalcomponent_get_first_property (comp_data->icalcomp, ICAL_CATEGORIES_PROPERTY); + if (prop) + return (char *) icalproperty_get_categories (prop); + + return ""; +} + +static char * +get_classification (ECalModelComponent *comp_data) +{ + icalproperty *prop; + + prop = icalcomponent_get_first_property (comp_data->icalcomp, ICAL_CLASS_PROPERTY); + + if (prop) + return (char *) icalproperty_get_class (prop); + + return _("Public"); +} + +static const char * +get_color (ECalModel *model, ECalModelComponent *comp_data) +{ + g_return_val_if_fail (E_IS_CAL_MODEL (model), NULL); + + return e_cal_model_get_color_for_component (model, comp_data); +} + +static char * +get_description (ECalModelComponent *comp_data) +{ + icalproperty *prop; + static GString *str = NULL; + + if (str) + g_string_free (str, TRUE); + + prop = icalcomponent_get_first_property (comp_data->icalcomp, ICAL_DESCRIPTION_PROPERTY); + if (prop) { + str = g_string_new (""); + do { + str = g_string_append (str, icalproperty_get_description (prop)); + } while ((prop = icalcomponent_get_next_property (comp_data->icalcomp, ICAL_DESCRIPTION_PROPERTY))); + + return str->str; + } + + return ""; +} + +static ECellDateEditValue* +get_dtstart (ECalModel *model, ECalModelComponent *comp_data) +{ + ECalModelPrivate *priv; + struct icaltimetype tt_start; + + priv = model->priv; + + if (!comp_data->dtstart) { + icaltimezone *zone; + + tt_start = icalcomponent_get_dtstart (comp_data->icalcomp); + if (!icaltime_is_valid_time (tt_start)) + return NULL; + + comp_data->dtstart = g_new0 (ECellDateEditValue, 1); + comp_data->dtstart->tt = tt_start; + + /* FIXME: handle errors */ + cal_client_get_timezone (comp_data->client, + icaltimezone_get_tzid (icaltimezone_get_builtin_timezone (tt_start.zone)), + &zone); + comp_data->dtstart->zone = zone; + } + + return comp_data->dtstart; +} + +static char * +get_summary (ECalModelComponent *comp_data) +{ + icalproperty *prop; + + prop = icalcomponent_get_first_property (comp_data->icalcomp, ICAL_SUMMARY_PROPERTY); + if (prop) + return (char *) icalproperty_get_summary (prop); + + return ""; +} + +static char * +get_uid (ECalModelComponent *comp_data) +{ + return (char *) icalcomponent_get_uid (comp_data->icalcomp); +} + +static void * +ecm_value_at (ETableModel *etm, int col, int row) +{ + ECalModelPrivate *priv; + ECalModelComponent *comp_data; + ECalModel *model = (ECalModel *) etm; + + g_return_val_if_fail (E_IS_CAL_MODEL (model), NULL); + + priv = model->priv; + + g_return_val_if_fail (col >= 0 && col < E_CAL_MODEL_FIELD_LAST, NULL); + g_return_val_if_fail (row >= 0 && row < priv->objects->len, NULL); + + comp_data = g_ptr_array_index (priv->objects, row); + g_assert (comp_data != NULL); + + switch (col) { + case E_CAL_MODEL_FIELD_CATEGORIES : + return get_categories (comp_data); + case E_CAL_MODEL_FIELD_CLASSIFICATION : + return get_classification (comp_data); + case E_CAL_MODEL_FIELD_COLOR : + return GINT_TO_POINTER (get_color (model, comp_data)); + case E_CAL_MODEL_FIELD_COMPONENT : + return comp_data->icalcomp; + case E_CAL_MODEL_FIELD_DESCRIPTION : + return get_description (comp_data); + case E_CAL_MODEL_FIELD_DTSTART : + return get_dtstart (model, comp_data); + case E_CAL_MODEL_FIELD_HAS_ALARMS : + return GINT_TO_POINTER ((icalcomponent_get_first_component (comp_data->icalcomp, + ICAL_VALARM_COMPONENT) != NULL)); + case E_CAL_MODEL_FIELD_ICON : + { + CalComponent *comp; + icalcomponent *icalcomp; + gint retval = 0; + + comp = cal_component_new (); + icalcomp = icalcomponent_new_clone (comp_data->icalcomp); + if (cal_component_set_icalcomponent (comp, icalcomp)) { + if (cal_component_has_recurrences (comp)) + retval = 1; + else if (itip_organizer_is_user (comp, comp_data->client)) + retval = 3; + else { + GSList *attendees = NULL, *sl; + + cal_component_get_attendee_list (comp, &attendees); + for (sl = attendees; sl != NULL; sl = sl->next) { + CalComponentAttendee *ca = sl->data; + const char *text; + + text = itip_strip_mailto (ca->value); + if (e_account_list_find (priv->accounts, E_ACCOUNT_FIND_ID_ADDRESS, text) != NULL) { + if (ca->delto != NULL) + retval = 3; + else + retval = 2; + break; + } + } + + cal_component_free_attendee_list (attendees); + } + } else + icalcomponent_free (icalcomp); + + g_object_unref (comp); + + return GINT_TO_POINTER (retval); + } + case E_CAL_MODEL_FIELD_SUMMARY : + return get_summary (comp_data); + case E_CAL_MODEL_FIELD_UID : + return get_uid (comp_data); + } + + return ""; +} + +static void +set_categories (icalcomponent *icalcomp, const char *value) +{ + icalproperty *prop; + + prop = icalcomponent_get_first_property (icalcomp, ICAL_CATEGORIES_PROPERTY); + if (!value || !(*value)) { + if (prop) { + icalcomponent_remove_property (icalcomp, prop); + icalproperty_free (prop); + } + } else { + if (!prop) { + prop = icalproperty_new_categories (value); + icalcomponent_add_property (icalcomp, prop); + } else + icalproperty_set_categories (prop, value); + } +} + +static void +set_classification (icalcomponent *icalcomp, const char *value) +{ + icalproperty *prop; + + prop = icalcomponent_get_first_property (icalcomp, ICAL_CLASS_PROPERTY); + if (!value || !(*value)) { + if (prop) { + icalcomponent_remove_property (icalcomp, prop); + icalproperty_free (prop); + } + } else { + if (!prop) { + prop = icalproperty_new_class (value); + icalcomponent_add_property (icalcomp, prop); + } else + icalproperty_set_class (prop, value); + } +} + +static void +set_description (icalcomponent *icalcomp, const char *value) +{ + icalproperty *prop; + + /* remove old description(s) */ + prop = icalcomponent_get_first_property (icalcomp, ICAL_DESCRIPTION_PROPERTY); + while (prop) { + icalproperty *next; + + next = icalcomponent_get_next_property (icalcomp, ICAL_DESCRIPTION_PROPERTY); + + icalcomponent_remove_property (icalcomp, prop); + icalproperty_free (prop); + + prop = next; + } + + /* now add the new description */ + if (!value || !(*value)) + return; + + prop = icalproperty_new_description (value); + icalcomponent_add_property (icalcomp, prop); +} + +static void +set_dtstart (ECalModel *model, ECalModelComponent *comp_data, const void *value) +{ + icalproperty *prop; + ECellDateEditValue *dv = (ECellDateEditValue *) value; + + prop = icalcomponent_get_first_property (comp_data->icalcomp, ICAL_DTSTART_PROPERTY); + if (!dv) { + if (prop) { + icalcomponent_remove_property (comp_data->icalcomp, prop); + icalproperty_free (prop); + } + } else + icalcomponent_set_dtstart (comp_data->icalcomp, dv->tt); +} + +static void +set_summary (icalcomponent *icalcomp, const char *value) +{ + icalcomponent_set_summary (icalcomp, value); +} + +static void +ecm_set_value_at (ETableModel *etm, int col, int row, const void *value) +{ + ECalModelPrivate *priv; + ECalModelComponent *comp_data; + ECalModel *model = (ECalModel *) etm; + + g_return_if_fail (E_IS_CAL_MODEL (model)); + + priv = model->priv; + + g_return_if_fail (col >= 0 && col < E_CAL_MODEL_FIELD_LAST); + g_return_if_fail (row >= 0 && row < priv->objects->len); + + comp_data = g_ptr_array_index (priv->objects, row); + g_assert (comp_data != NULL); + + switch (col) { + case E_CAL_MODEL_FIELD_CATEGORIES : + set_categories (comp_data, value); + case E_CAL_MODEL_FIELD_CLASSIFICATION : + set_classification (comp_data, value); + case E_CAL_MODEL_FIELD_DESCRIPTION : + set_description (comp_data, value); + case E_CAL_MODEL_FIELD_DTSTART : + set_dtstart (model, comp_data, value); + case E_CAL_MODEL_FIELD_SUMMARY : + set_summary (comp_data, value); + } + + if (cal_client_update_objects (comp_data->client, comp_data->icalcomp) != CAL_CLIENT_RESULT_SUCCESS) + g_message ("ecm_set_value_at(): Could not update the object!"); +} + +static gboolean +ecm_is_cell_editable (ETableModel *etm, int col, int row) +{ + ECalModelPrivate *priv; + ECalModel *model = (ECalModel *) etm; + + g_return_val_if_fail (E_IS_CAL_MODEL (model), FALSE); + + priv = model->priv; + + g_return_val_if_fail (col >= 0 && col <= E_CAL_MODEL_FIELD_LAST, FALSE); + + /* FIXME: We can't check this as 'click-to-add' passes row 0. */ + /*g_return_val_if_fail (row >= 0 && row < priv->objects->len, FALSE);*/ + + switch (col) { + case E_CAL_MODEL_FIELD_CATEGORIES : + case E_CAL_MODEL_FIELD_CLASSIFICATION : + case E_CAL_MODEL_FIELD_DESCRIPTION : + case E_CAL_MODEL_FIELD_DTSTART : + case E_CAL_MODEL_FIELD_SUMMARY : + return TRUE; + } + + return FALSE; +} + +static void +ecm_append_row (ETableModel *etm, ETableModel *source, int row) +{ + ECalModelComponent *comp_data; + icalcomponent *icalcomp; + ECalModel *source_model = (ECalModel *) source; + ECalModel *model = (ECalModel *) etm; + + g_return_if_fail (E_IS_CAL_MODEL (model)); + g_return_if_fail (E_IS_CAL_MODEL (source_model)); + + comp_data = g_ptr_array_index (source_model->priv->objects, row); + g_assert (comp_data != NULL); + + /* guard against saving before the calendar is open */ + if (!(comp_data->client && cal_client_get_load_state (comp_data->client) == CAL_CLIENT_LOAD_LOADED)) + return; + + icalcomp = e_cal_model_create_component_with_defaults (model); + + set_categories (icalcomp, e_table_model_value_at (source, E_CAL_MODEL_FIELD_CATEGORIES, row)); + set_classification (icalcomp, e_table_model_value_at (source, E_CAL_MODEL_FIELD_CLASSIFICATION, row)); + set_description (icalcomp, e_table_model_value_at (source, E_CAL_MODEL_FIELD_DESCRIPTION, row)); + set_summary (icalcomp, e_table_model_value_at (source, E_CAL_MODEL_FIELD_SUMMARY, row)); + + if (cal_client_update_objects (comp_data->client, icalcomp) != CAL_CLIENT_RESULT_SUCCESS) { + /* FIXME: show error dialog */ + } + + icalcomponent_free (icalcomp); +} + +static void * +ecm_duplicate_value (ETableModel *etm, int col, const void *value) +{ + g_return_val_if_fail (col >= 0 && col < E_CAL_MODEL_FIELD_LAST, NULL); + + switch (col) { + case E_CAL_MODEL_FIELD_CATEGORIES : + case E_CAL_MODEL_FIELD_CLASSIFICATION : + case E_CAL_MODEL_FIELD_SUMMARY : + return g_strdup (value); + case E_CAL_MODEL_FIELD_HAS_ALARMS : + case E_CAL_MODEL_FIELD_ICON : + case E_CAL_MODEL_FIELD_COLOR : + return (void *) value; + case E_CAL_MODEL_FIELD_COMPONENT : + return icalcomponent_new_clone ((icalcomponent *) value); + case E_CAL_MODEL_FIELD_DTSTART : + if (value) { + ECellDateEditValue *dv, *orig_dv; + + orig_dv = (ECellDateEditValue *) value; + dv = g_new0 (ECellDateEditValue, 1); + *dv = *orig_dv; + + return dv; + } + break; + } + + return NULL; +} + +static void +ecm_free_value (ETableModel *etm, int col, void *value) +{ + g_return_if_fail (col >= 0 && col < E_CAL_MODEL_FIELD_LAST); + + switch (col) { + case E_CAL_MODEL_FIELD_CATEGORIES : + case E_CAL_MODEL_FIELD_DESCRIPTION : + case E_CAL_MODEL_FIELD_SUMMARY : + if (value) + g_free (value); + break; + case E_CAL_MODEL_FIELD_CLASSIFICATION : + case E_CAL_MODEL_FIELD_HAS_ALARMS : + case E_CAL_MODEL_FIELD_ICON : + case E_CAL_MODEL_FIELD_COLOR : + break; + case E_CAL_MODEL_FIELD_DTSTART : + if (value) + g_free (value); + break; + case E_CAL_MODEL_FIELD_COMPONENT : + if (value) + icalcomponent_free ((icalcomponent *) value); + break; + } +} + +static void * +ecm_initialize_value (ETableModel *etm, int col) +{ + ECalModelPrivate *priv; + ECalModel *model = (ECalModel *) etm; + + g_return_val_if_fail (E_IS_CAL_MODEL (model), NULL); + g_return_val_if_fail (col >= 0 && col < E_CAL_MODEL_FIELD_LAST, NULL); + + priv = model->priv; + + switch (col) { + case E_CAL_MODEL_FIELD_CATEGORIES : + return g_strdup (priv->default_category); + case E_CAL_MODEL_FIELD_CLASSIFICATION : + case E_CAL_MODEL_FIELD_DESCRIPTION : + case E_CAL_MODEL_FIELD_SUMMARY : + return g_strdup (""); + case E_CAL_MODEL_FIELD_DTSTART : + case E_CAL_MODEL_FIELD_HAS_ALARMS : + case E_CAL_MODEL_FIELD_ICON : + case E_CAL_MODEL_FIELD_COLOR : + case E_CAL_MODEL_FIELD_COMPONENT : + return NULL; + } + + return NULL; +} + +static gboolean +ecm_value_is_empty (ETableModel *etm, int col, const void *value) +{ + ECalModelPrivate *priv; + ECalModel *model = (ECalModel *) etm; + + g_return_val_if_fail (E_IS_CAL_MODEL (model), TRUE); + g_return_val_if_fail (col >= 0 && col < E_CAL_MODEL_FIELD_LAST, TRUE); + + priv = model->priv; + + switch (col) { + case E_CAL_MODEL_FIELD_CATEGORIES : + /* This could be a hack or not. If the categories field only + * contains the default category, then it possibly means that + * the user has not entered anything at all in the click-to-add; + * the category is in the value because we put it there in + * calendar_model_initialize_value(). + */ + if (priv->default_category && value && strcmp (priv->default_category, value) == 0) + return TRUE; + else + return string_is_empty (value); + case E_CAL_MODEL_FIELD_CLASSIFICATION : + case E_CAL_MODEL_FIELD_DESCRIPTION : + case E_CAL_MODEL_FIELD_SUMMARY : + return string_is_empty (value); + case E_CAL_MODEL_FIELD_DTSTART : + return value ? FALSE : TRUE; + case E_CAL_MODEL_FIELD_HAS_ALARMS : + case E_CAL_MODEL_FIELD_ICON : + case E_CAL_MODEL_FIELD_COLOR : + case E_CAL_MODEL_FIELD_COMPONENT : + return TRUE; + } + + return TRUE; +} + +static char * +ecm_value_to_string (ETableModel *etm, int col, const void *value) +{ + g_return_val_if_fail (col >= 0 && col < E_CAL_MODEL_FIELD_LAST, NULL); + + switch (col) { + case E_CAL_MODEL_FIELD_CATEGORIES : + case E_CAL_MODEL_FIELD_CLASSIFICATION : + case E_CAL_MODEL_FIELD_DESCRIPTION : + case E_CAL_MODEL_FIELD_SUMMARY : + return g_strdup (value); + case E_CAL_MODEL_FIELD_DTSTART : + return e_cal_model_date_value_to_string (E_CAL_MODEL (etm), value); + case E_CAL_MODEL_FIELD_ICON : + if (GPOINTER_TO_INT (value) == 0) + return _("Normal"); + else if (GPOINTER_TO_INT (value) == 1) + return _("Recurring"); + else + return _("Assigned"); + case E_CAL_MODEL_FIELD_HAS_ALARMS : + return value ? _("Yes") : _("No"); + case E_CAL_MODEL_FIELD_COLOR : + case E_CAL_MODEL_FIELD_COMPONENT : + return NULL; + } + + return NULL; +} + +/* ECalModel class methods */ + +static const char * +ecm_get_color_for_component (ECalModel *model, ECalModelComponent *comp_data) +{ + ECalModelPrivate *priv; + gint i, pos; + GList *l; + gchar *colors[] = { "gray", "green", "darkblue" }; + + g_return_val_if_fail (E_IS_CAL_MODEL (model), NULL); + g_return_val_if_fail (comp_data != NULL, NULL); + + priv = model->priv; + + for (l = priv->clients, i = 0; l != NULL; l = l->next, i++) { + ECalModelClient *client_data = (ECalModelClient *) l->data; + + if (client_data->client == comp_data->client) { + pos = i % G_N_ELEMENTS (colors); + return colors[pos]; + } + } + + return NULL; +} + +/** + * e_cal_model_get_component_kind + */ +icalcomponent_kind +e_cal_model_get_component_kind (ECalModel *model) +{ + ECalModelPrivate *priv; + + g_return_val_if_fail (E_IS_CAL_MODEL (model), ICAL_NO_COMPONENT); + + priv = model->priv; + return priv->kind; +} + +/** + * e_cal_model_set_component_kind + */ +void +e_cal_model_set_component_kind (ECalModel *model, icalcomponent_kind kind) +{ + ECalModelPrivate *priv; + + g_return_if_fail (E_IS_CAL_MODEL (model)); + + priv = model->priv; + priv->kind = kind; +} + +/** + * e_cal_model_get_timezone + */ +icaltimezone * +e_cal_model_get_timezone (ECalModel *model) +{ + g_return_val_if_fail (E_IS_CAL_MODEL (model), NULL); + return model->priv->zone; +} + +/** + * e_cal_model_set_timezone + */ +void +e_cal_model_set_timezone (ECalModel *model, icaltimezone *zone) +{ + ECalModelPrivate *priv; + + g_return_if_fail (E_IS_CAL_MODEL (model)); + + priv = model->priv; + if (priv->zone != zone) { + e_table_model_pre_change (E_TABLE_MODEL (model)); + priv->zone = zone; + + /* the timezone affects the times shown for date fields, + so we need to redisplay everything */ + e_table_model_changed (E_TABLE_MODEL (model)); + } +} + +static ECalModelComponent * +search_by_uid_and_client (ECalModelPrivate *priv, CalClient *client, const char *uid) +{ + gint i; + + for (i = 0; i < priv->objects->len; i++) { + ECalModelComponent *comp_data = g_ptr_array_index (priv->objects, i); + + if (comp_data) { + const char *tmp_uid; + + tmp_uid = icalcomponent_get_uid (comp_data->icalcomp); + if (tmp_uid && *tmp_uid) { + if (comp_data->client == client && !strcmp (uid, tmp_uid)) + return comp_data; + } + } + } + + return NULL; +} + +static gint +get_position_in_array (GPtrArray *objects, gpointer item) +{ + gint i; + + for (i = 0; i < objects->len; i++) { + if (g_ptr_array_index (objects, i) == item) + return i; + } + + return -1; +} + +static void +query_obj_updated_cb (CalQuery *query, const char *uid, + gboolean query_in_progress, + int n_scanned, int total, + gpointer user_data) +{ + ECalModelPrivate *priv; + icalcomponent *new_icalcomp; + CalClientGetStatus status; + ECalModelComponent *comp_data; + gint pos; + ECalModel *model = (ECalModel *) user_data; + + g_return_if_fail (E_IS_CAL_MODEL (model)); + + priv = model->priv; + + e_table_model_pre_change (E_TABLE_MODEL (model)); + + comp_data = search_by_uid_and_client (priv, cal_query_get_client (query), uid); + status = cal_client_get_object (cal_query_get_client (query), uid, &new_icalcomp); + switch (status) { + case CAL_CLIENT_GET_SUCCESS : + if (comp_data) { + if (comp_data->icalcomp) + icalcomponent_free (comp_data->icalcomp); + comp_data->icalcomp = new_icalcomp; + + e_table_model_row_changed (E_TABLE_MODEL (model), get_position_in_array (priv->objects, comp_data)); + } else { + comp_data = g_new0 (ECalModelComponent, 1); + comp_data->client = cal_query_get_client (query); + comp_data->icalcomp = new_icalcomp; + + g_ptr_array_add (priv->objects, comp_data); + e_table_model_row_inserted (E_TABLE_MODEL (model), priv->objects->len - 1); + } + break; + case CAL_CLIENT_GET_NOT_FOUND : + case CAL_CLIENT_GET_SYNTAX_ERROR : + if (comp_data) { + /* Nothing; the object may have been removed from the server. We just + notify that the old object was deleted. + */ + pos = get_position_in_array (priv->objects, comp_data); + + g_ptr_array_remove (priv->objects, comp_data); + free_comp_data (comp_data); + + e_table_model_row_deleted (E_TABLE_MODEL (model), pos); + } else + e_table_model_no_change (E_TABLE_MODEL (model)); + break; + default : + g_assert_not_reached (); + } +} + +static void +query_obj_removed_cb (CalQuery *query, const char *uid, gpointer user_data) +{ + ECalModelComponent *comp_data; + ECalModelPrivate *priv; + ECalModel *model = (ECalModel *) user_data; + + g_return_if_fail (E_IS_CAL_MODEL (model)); + + priv = model->priv; + + e_table_model_pre_change (E_TABLE_MODEL (model)); + + comp_data = search_by_uid_and_client (priv, cal_query_get_client (query), uid); + if (comp_data) { + gint pos = get_position_in_array (priv->objects, comp_data); + + g_ptr_array_remove (priv->objects, comp_data); + free_comp_data (comp_data); + + e_table_model_row_deleted (E_TABLE_MODEL (model), pos); + } else + e_table_model_no_change (E_TABLE_MODEL (model)); +} + +static void +query_done_cb (CalQuery *query, CalQueryDoneStatus status, const char *error_str, gpointer user_data) +{ + ECalModel *model = (ECalModel *) user_data; + + g_return_if_fail (E_IS_CAL_MODEL (model)); + + if (status != CAL_QUERY_DONE_SUCCESS) + g_warning ("query done: %s\n", error_str); +} + +static void +query_eval_error_cb (CalQuery *query, const char *error_str, gpointer user_data) +{ + ECalModel *model = (ECalModel *) user_data; + + g_return_if_fail (E_IS_CAL_MODEL (model)); + + g_warning ("eval error: %s\n", error_str); +} + +/* Builds a complete query sexp for the calendar model by adding the predicates + * to filter only for the type of objects that the model supports, and + * whether we want completed tasks. + */ +static char * +adjust_query_sexp (ECalModel *model, const char *sexp) +{ + ECalModelPrivate *priv; + char *type_sexp, *new_sexp; + + priv = model->priv; + + if (priv->kind == ICAL_NO_COMPONENT) + type_sexp = g_strdup ("#t"); + else { + if (priv->kind == ICAL_VEVENT_COMPONENT) + type_sexp = g_strdup ("(or (= (get-vtype) \"VEVENT\"))"); + else if (priv->kind == ICAL_VTODO_COMPONENT) + type_sexp = g_strdup ("(or (= (get-vtype) \"VTODO\"))"); + else if (priv->kind == ICAL_VJOURNAL_COMPONENT) + type_sexp = g_strdup ("(or (= (get-vtype) \"VJOURNAL\"))"); + else + type_sexp = g_strdup ("#t"); + } + + new_sexp = g_strdup_printf ("(and %s %s)", type_sexp, sexp); + g_free (type_sexp); + + return new_sexp; +} + +static void +update_query_for_client (ECalModel *model, ECalModelClient *client_data) +{ + ECalModelPrivate *priv; + gchar *real_sexp; + + priv = model->priv; + + /* free the previous query, if any */ + if (client_data->query) { + g_signal_handlers_disconnect_matched (client_data->query, G_SIGNAL_MATCH_DATA, + 0, 0, NULL, NULL, model); + g_object_unref (client_data->query); + } + + /* prepare the query */ + g_assert (priv->sexp != NULL); + real_sexp = adjust_query_sexp (model, priv->sexp); + + client_data->query = cal_client_get_query (client_data->client, real_sexp); + g_free (real_sexp); + + if (!client_data->query) { + g_message ("update_query_for_client(): Could not create the query"); + return; + } + + g_signal_connect (client_data->query, "obj_updated", G_CALLBACK (query_obj_updated_cb), model); + g_signal_connect (client_data->query, "obj_removed", G_CALLBACK (query_obj_removed_cb), model); + g_signal_connect (client_data->query, "query_done", G_CALLBACK (query_done_cb), model); + g_signal_connect (client_data->query, "eval_error", G_CALLBACK (query_eval_error_cb), model); +} + +static void +add_new_client (ECalModel *model, CalClient *client) +{ + ECalModelPrivate *priv; + ECalModelClient *client_data; + + priv = model->priv; + + client_data = g_new0 (ECalModelClient, 1); + client_data->client = client; + client_data->query = NULL; + g_object_ref (client_data->client); + + priv->clients = g_list_append (priv->clients, client_data); + + update_query_for_client (model, client_data); +} + +static void +cal_opened_cb (CalClient *client, CalClientOpenStatus status, gpointer user_data) +{ + ECalModel *model = (ECalModel *) user_data; + + if (status != CAL_CLIENT_OPEN_SUCCESS) { + e_cal_model_remove_client (model, client); + return; + } + + add_new_client (model, client); +} + +/** + * e_cal_model_add_client + */ +void +e_cal_model_add_client (ECalModel *model, CalClient *client) +{ + ECalModelPrivate *priv; + + g_return_if_fail (E_IS_CAL_MODEL (model)); + g_return_if_fail (IS_CAL_CLIENT (client)); + + priv = model->priv; + + if (cal_client_get_load_state (client) == CAL_CLIENT_LOAD_LOADED) + add_new_client (model, client); + else + g_signal_connect (client, "cal_opened", G_CALLBACK (cal_opened_cb), model); +} + +static void +remove_client (ECalModel *model, ECalModelClient *client_data) +{ + gint i; + + g_signal_handlers_disconnect_matched (client_data->client, G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL, model); + g_signal_handlers_disconnect_matched (client_data->query, G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL, model); + + model->priv->clients = g_list_remove (model->priv->clients, client_data); + + /* remove all objects belonging to this client */ + e_table_model_pre_change (E_TABLE_MODEL (model)); + for (i = 0; i < model->priv->objects->len; i++) { + ECalModelComponent *comp_data = (ECalModelComponent *) g_ptr_array_index (model->priv->objects, i); + + g_assert (comp_data != NULL); + + if (comp_data->client == client_data->client) { + g_ptr_array_remove (model->priv->objects, comp_data); + free_comp_data (comp_data); + } + } + e_table_model_changed (E_TABLE_MODEL (model)); + + /* free all remaining memory */ + g_object_unref (client_data->client); + g_object_unref (client_data->query); + g_free (client_data); + +} + +/** + * e_cal_model_remove_client + */ +void +e_cal_model_remove_client (ECalModel *model, CalClient *client) +{ + GList *l; + ECalModelPrivate *priv; + + g_return_if_fail (E_IS_CAL_MODEL (model)); + g_return_if_fail (IS_CAL_CLIENT (client)); + + priv = model->priv; + for (l = priv->clients; l != NULL; l = l->next) { + ECalModelClient *client_data = (ECalModelClient *) l->data; + + if (client_data->client == client) { + remove_client (model, client_data); + break; + } + } +} + +/** + * e_cal_model_remove_all_clients + */ +void +e_cal_model_remove_all_clients (ECalModel *model) +{ + ECalModelPrivate *priv; + + g_return_if_fail (E_IS_CAL_MODEL (model)); + + priv = model->priv; + while (priv->clients != NULL) { + ECalModelClient *client_data = (ECalModelClient *) priv->clients->data; + remove_client (model, client_data); + } +} + +/** + * e_cal_model_set_query + */ +void +e_cal_model_set_query (ECalModel *model, const char *sexp) +{ + ECalModelPrivate *priv; + GList *l; + + g_return_if_fail (E_IS_CAL_MODEL (model)); + g_return_if_fail (sexp != NULL); + + priv = model->priv; + + if (priv->sexp) + g_free (priv->sexp); + + priv->sexp = g_strdup (sexp); + + /* clean up the current contents */ + e_table_model_pre_change (E_TABLE_MODEL (model)); + clear_objects_array (priv); + e_table_model_changed (E_TABLE_MODEL (model)); + + /* update the query for all clients */ + for (l = priv->clients; l != NULL; l = l->next) { + ECalModelClient *client_data; + + client_data = (ECalModelClient *) l->data; + update_query_for_client (model, client_data); + } +} + +/** + * e_cal_model_create_component_with_defaults + */ +icalcomponent * +e_cal_model_create_component_with_defaults (ECalModel *model) +{ + ECalModelPrivate *priv; + CalComponent *comp; + icalcomponent *icalcomp; + + g_return_val_if_fail (E_IS_CAL_MODEL (model), NULL); + + priv = model->priv; + + g_return_val_if_fail (priv->clients != NULL, NULL); + + switch (priv->kind) { + case ICAL_VEVENT_COMPONENT : + comp = cal_comp_event_new_with_defaults ((CalClient *) priv->clients->data); + break; + case ICAL_VTODO_COMPONENT : + comp = cal_comp_task_new_with_defaults ((CalClient *) priv->clients->data); + break; + default: + return NULL; + } + + icalcomp = icalcomponent_new_clone (cal_component_get_icalcomponent (comp)); + g_object_unref (comp); + + return icalcomp; +} + +/** + * e_cal_model_get_color_for_component + */ +const gchar * +e_cal_model_get_color_for_component (ECalModel *model, ECalModelComponent *comp_data) +{ + ECalModelClass *model_class; + const gchar *color = NULL; + + g_return_val_if_fail (E_IS_CAL_MODEL (model), NULL); + g_return_val_if_fail (comp_data != NULL, NULL); + + model_class = (ECalModelClass *) G_OBJECT_GET_CLASS (model); + if (model_class->get_color_for_component != NULL) + color = model_class->get_color_for_component (model, comp_data); + + if (!color) + color = ecm_get_color_for_component (model, comp_data); + + return color; +} + +/** + * e_cal_model_get_component_at + */ +ECalModelComponent * +e_cal_model_get_component_at (ECalModel *model, gint row) +{ + ECalModelPrivate *priv; + + g_return_val_if_fail (E_IS_CAL_MODEL (model), NULL); + + priv = model->priv; + + g_return_val_if_fail (row >= 0 && row < priv->objects->len, NULL); + + return g_ptr_array_index (priv->objects, row); +} + +/** + * e_cal_model_date_value_to_string + */ +gchar* +e_cal_model_date_value_to_string (ECalModel *model, const void *value) +{ + ECalModelPrivate *priv; + ECellDateEditValue *dv = (ECellDateEditValue *) value; + struct icaltimetype tt; + struct tm tmp_tm; + char buffer[64]; + + g_return_val_if_fail (E_IS_CAL_MODEL (model), NULL); + + priv = model->priv; + + if (!dv) + return g_strdup (""); + + /* We currently convert all the dates to the current timezone. */ + tt = dv->tt; + icaltimezone_convert_time (&tt, dv->zone, priv->zone); + + tmp_tm.tm_year = tt.year - 1900; + tmp_tm.tm_mon = tt.month - 1; + tmp_tm.tm_mday = tt.day; + tmp_tm.tm_hour = tt.hour; + tmp_tm.tm_min = tt.minute; + tmp_tm.tm_sec = tt.second; + tmp_tm.tm_isdst = -1; + + tmp_tm.tm_wday = time_day_of_week (tt.day, tt.month - 1, tt.year); + + e_time_format_date_and_time (&tmp_tm, calendar_config_get_24_hour_format (), + TRUE, FALSE, + buffer, sizeof (buffer)); + return g_strdup (buffer); +} diff --git a/calendar/gui/e-cal-model.h b/calendar/gui/e-cal-model.h new file mode 100644 index 0000000000..69d9e785ba --- /dev/null +++ b/calendar/gui/e-cal-model.h @@ -0,0 +1,95 @@ +/* Evolution calendar - Data model for ETable + * + * Copyright (C) 2000 Ximian, Inc. + * Copyright (C) 2000 Ximian, Inc. + * + * Authors: Rodrigo Moya <rodrigo@ximian.com> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of version 2 of the GNU General Public + * License as published by the Free Software Foundation. + * + * 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. + */ + +#ifndef E_CAL_MODEL_H +#define E_CAL_MODEL_H + +#include <gal/e-table/e-table-model.h> +#include <cal-client/cal-client.h> +#include "e-cell-date-edit-text.h" + +G_BEGIN_DECLS + +#define E_TYPE_CAL_MODEL (e_cal_model_get_type ()) +#define E_CAL_MODEL(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), E_TYPE_CAL_MODEL, ECalModel)) +#define E_CAL_MODEL_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), E_TYPE_CAL_MODEL, ECalModelClass)) +#define E_IS_CAL_MODEL(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), E_TYPE_CAL_MODEL)) +#define E_IS_CAL_MODEL_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), E_TYPE_CAL_MODEL)) + +typedef struct _ECalModelPrivate ECalModelPrivate; + +typedef enum { + E_CAL_MODEL_FIELD_CATEGORIES, + E_CAL_MODEL_FIELD_CLASSIFICATION, + E_CAL_MODEL_FIELD_COLOR, /* not a real field */ + E_CAL_MODEL_FIELD_COMPONENT, /* not a real field */ + E_CAL_MODEL_FIELD_DESCRIPTION, + E_CAL_MODEL_FIELD_DTSTART, + E_CAL_MODEL_FIELD_HAS_ALARMS, /* not a real field */ + E_CAL_MODEL_FIELD_ICON, /* not a real field */ + E_CAL_MODEL_FIELD_SUMMARY, + E_CAL_MODEL_FIELD_UID, + E_CAL_MODEL_FIELD_LAST +} ECalModelField; + +typedef struct { + CalClient *client; + icalcomponent *icalcomp; + + /* private data */ + ECellDateEditValue *dtstart; + ECellDateEditValue *dtend; +} ECalModelComponent; + +typedef struct { + ETableModel model; + ECalModelPrivate *priv; +} ECalModel; + +typedef struct { + ETableModelClass parent_class; + + /* virtual methods */ + const gchar * (* get_color_for_component) (ECalModel *model, ECalModelComponent *comp_data); +} ECalModelClass; + +GType e_cal_model_get_type (void); + +icalcomponent_kind e_cal_model_get_component_kind (ECalModel *model); +void e_cal_model_set_component_kind (ECalModel *model, icalcomponent_kind kind); +icaltimezone *e_cal_model_get_timezone (ECalModel *model); +void e_cal_model_set_timezone (ECalModel *model, icaltimezone *zone); + +void e_cal_model_add_client (ECalModel *model, CalClient *client); +void e_cal_model_remove_client (ECalModel *model, CalClient *client); +void e_cal_model_remove_all_clients (ECalModel *model); + +void e_cal_model_set_query (ECalModel *model, const gchar *sexp); + +icalcomponent *e_cal_model_create_component_with_defaults (ECalModel *model); +const gchar *e_cal_model_get_color_for_component (ECalModel *model, ECalModelComponent *comp_data); +ECalModelComponent *e_cal_model_get_component_at (ECalModel *model, gint row); + +gchar *e_cal_model_date_value_to_string (ECalModel *model, const void *value); + +G_END_DECLS + +#endif diff --git a/calendar/gui/e-day-view.c b/calendar/gui/e-day-view.c index 5acd71965b..1ef6f9c07b 100644 --- a/calendar/gui/e-day-view.c +++ b/calendar/gui/e-day-view.c @@ -5,7 +5,7 @@ * Damon Chaplin <damon@ximian.com> * Rodrigo Moya <rodrigo@ximian.com> * - * Copyright 1999, Ximian, Inc. + * Copyright 1999-2003, Ximian, Inc. * * This program is free software; you can redistribute it and/or * modify it under the terms of version 2 of the GNU General Public @@ -1434,6 +1434,7 @@ query_obj_updated_cb (CalQuery *query, const char *uid, EDayView *day_view; EDayViewEvent *event; CalComponent *comp; + icalcomponent *icalcomp; CalClientGetStatus status; gint day, event_num; @@ -1444,11 +1445,18 @@ query_obj_updated_cb (CalQuery *query, const char *uid, return; /* Get the event from the server. */ - status = cal_client_get_object (e_cal_view_get_cal_client (E_CAL_VIEW (day_view)), uid, &comp); + status = cal_client_get_object (e_cal_view_get_cal_client (E_CAL_VIEW (day_view)), uid, &icalcomp); switch (status) { case CAL_CLIENT_GET_SUCCESS: - /* Everything is fine */ + comp = cal_component_new (); + if (!cal_component_set_icalcomponent (comp, icalcomp)) { + g_object_unref (comp); + icalcomponent_free (icalcomp); + + g_message ("query_obj_updated_cb(): Invalid object %s", uid); + return; + } break; case CAL_CLIENT_GET_SYNTAX_ERROR: diff --git a/calendar/gui/e-itip-control.c b/calendar/gui/e-itip-control.c index 2e1ff4cb67..91a355f269 100644 --- a/calendar/gui/e-itip-control.c +++ b/calendar/gui/e-itip-control.c @@ -304,13 +304,13 @@ find_server (GPtrArray *servers, CalComponent *comp) cal_component_get_uid (comp, &uid); for (i = 0; i < servers->len; i++) { CalClient *client; - CalComponent *found_comp; + icalcomponent *icalcomp; CalClientGetStatus status; client = g_ptr_array_index (servers, i); - status = cal_client_get_object (client, uid, &found_comp); + status = cal_client_get_object (client, uid, &icalcomp); if (status == CAL_CLIENT_GET_SUCCESS) { - g_object_unref (found_comp); + icalcomponent_free (icalcomp); g_object_ref (client); return client; @@ -1248,6 +1248,7 @@ get_real_item (EItipControl *itip) { EItipControlPrivate *priv; CalComponent *comp; + icalcomponent *icalcomp; CalComponentVType type; CalClientGetStatus status = CAL_CLIENT_GET_NOT_FOUND; const char *uid; @@ -1260,11 +1261,11 @@ get_real_item (EItipControl *itip) switch (type) { case CAL_COMPONENT_EVENT: if (priv->event_client != NULL) - status = cal_client_get_object (priv->event_client, uid, &comp); + status = cal_client_get_object (priv->event_client, uid, &icalcomp); break; case CAL_COMPONENT_TODO: if (priv->task_client != NULL) - status = cal_client_get_object (priv->task_client, uid, &comp); + status = cal_client_get_object (priv->task_client, uid, &icalcomp); break; default: status = CAL_CLIENT_GET_NOT_FOUND; @@ -1273,6 +1274,13 @@ get_real_item (EItipControl *itip) if (status != CAL_CLIENT_GET_SUCCESS) return NULL; + comp = cal_component_new (); + if (!cal_component_set_icalcomponent (comp, icalcomp)) { + g_object_unref (comp); + icalcomponent_free (icalcomp); + return NULL; + } + return comp; } @@ -1936,6 +1944,7 @@ update_attendee_status (EItipControl *itip) CalClient *client; CalClientGetStatus status; CalComponent *comp = NULL; + icalcomponent *icalcomp = NULL; CalComponentVType type; const char *uid; GtkWidget *dialog; @@ -1957,41 +1966,47 @@ update_attendee_status (EItipControl *itip) /* Obtain our version */ cal_component_get_uid (priv->comp, &uid); - status = cal_client_get_object (client, uid, &comp); + status = cal_client_get_object (client, uid, &icalcomp); if (status == CAL_CLIENT_GET_SUCCESS) { GSList *attendees; - cal_component_get_attendee_list (priv->comp, &attendees); - if (attendees != NULL) { - CalComponentAttendee *a = attendees->data; - icalproperty *prop; + comp = cal_component_new (); + if (!cal_component_set_icalcomponent (comp, icalcomp)) { + icalcomponent_free (icalcomp); - prop = find_attendee (cal_component_get_icalcomponent (comp), - itip_strip_mailto (a->value)); - - if (prop == NULL) { - dialog = gnome_question_dialog_modal (_("This response is not from a current " - "attendee. Add as an attendee?"), - NULL, NULL); - if (gnome_dialog_run_and_close (GNOME_DIALOG (dialog)) == GNOME_YES) { - change_status (cal_component_get_icalcomponent (comp), + dialog = gnome_warning_dialog (_("Object is invalid and cannot be updated\n")); + } else { + cal_component_get_attendee_list (priv->comp, &attendees); + if (attendees != NULL) { + CalComponentAttendee *a = attendees->data; + icalproperty *prop; + + prop = find_attendee (icalcomp, itip_strip_mailto (a->value)); + + if (prop == NULL) { + dialog = gnome_question_dialog_modal (_("This response is not from a current " + "attendee. Add as an attendee?"), + NULL, NULL); + if (gnome_dialog_run_and_close (GNOME_DIALOG (dialog)) == GNOME_YES) { + change_status (icalcomp, + itip_strip_mailto (a->value), + a->status); + cal_component_rescan (comp); + } else { + goto cleanup; + } + } else if (a->status == ICAL_PARTSTAT_NONE || a->status == ICAL_PARTSTAT_X) { + dialog = gnome_warning_dialog (_("Attendee status could " + "not be updated because " + "of an invalid status!\n")); + goto cleanup; + } else { + change_status (icalcomp, itip_strip_mailto (a->value), a->status); - cal_component_rescan (comp); - } else { - goto cleanup; + cal_component_rescan (comp); } - } else if (a->status == ICAL_PARTSTAT_NONE || a->status == ICAL_PARTSTAT_X) { - dialog = gnome_warning_dialog (_("Attendee status could " - "not be updated because " - "of an invalid status!\n")); - goto cleanup; - } else { - change_status (cal_component_get_icalcomponent (comp), - itip_strip_mailto (a->value), - a->status); - cal_component_rescan (comp); } } diff --git a/calendar/gui/e-week-view.c b/calendar/gui/e-week-view.c index 9beb123b95..19ef3147e4 100644 --- a/calendar/gui/e-week-view.c +++ b/calendar/gui/e-week-view.c @@ -1065,7 +1065,8 @@ query_obj_updated_cb (CalQuery *query, const char *uid, EWeekView *week_view; EWeekViewEvent *event; gint event_num, num_days; - CalComponent *comp; + CalComponent *comp = NULL; + icalcomponent *icalcomp; CalClientGetStatus status; week_view = E_WEEK_VIEW (data); @@ -1075,11 +1076,18 @@ query_obj_updated_cb (CalQuery *query, const char *uid, return; /* Get the event from the server. */ - status = cal_client_get_object (e_cal_view_get_cal_client (E_CAL_VIEW (week_view)), uid, &comp); + status = cal_client_get_object (e_cal_view_get_cal_client (E_CAL_VIEW (week_view)), uid, &icalcomp); switch (status) { case CAL_CLIENT_GET_SUCCESS: - /* Everything is fine */ + comp = cal_component_new (); + if (!cal_component_set_icalcomponent (comp, icalcomp)) { + g_object_unref (comp); + icalcomponent_free (icalcomp); + + g_message ("query_obj_updated_cb(): Could not set icalcomponent on CalComponent"); + return; + } break; case CAL_CLIENT_GET_SYNTAX_ERROR: diff --git a/calendar/gui/gnome-cal.c b/calendar/gui/gnome-cal.c index 7598aecd8d..4dab508ffc 100644 --- a/calendar/gui/gnome-cal.c +++ b/calendar/gui/gnome-cal.c @@ -363,7 +363,8 @@ dn_query_obj_updated_cb (CalQuery *query, const char *uid, { GnomeCalendar *gcal; GnomeCalendarPrivate *priv; - CalComponent *comp; + CalComponent *comp = NULL; + icalcomponent *icalcomp; CalClientGetStatus status; gcal = GNOME_CALENDAR (data); @@ -379,20 +380,25 @@ dn_query_obj_updated_cb (CalQuery *query, const char *uid, return; } - status = cal_client_get_object (priv->client, uid, &comp); + status = cal_client_get_object (priv->client, uid, &icalcomp); switch (status) { case CAL_CLIENT_GET_SUCCESS: - /* Everything is fine */ + comp = cal_component_new (); + if (!cal_component_set_icalcomponent (comp, icalcomp)) { + g_object_unref (comp); + icalcomponent_free (icalcomp); + return; + } break; case CAL_CLIENT_GET_SYNTAX_ERROR: g_message ("dn_query_obj_updated_cb(): Syntax error while getting object `%s'", uid); - break; + return; case CAL_CLIENT_GET_NOT_FOUND: /* The object is no longer in the server, so do nothing */ - break; + return; default: g_assert_not_reached (); @@ -3001,14 +3007,22 @@ purging_obj_updated_cb (CalQuery *query, const char *uid, GnomeCalendarPrivate *priv; GnomeCalendar *gcal = data; CalComponent *comp; + icalcomponent *icalcomp; obj_updated_closure closure; gchar *msg; priv = gcal->priv; - if (cal_client_get_object (priv->client, uid, &comp) != CAL_CLIENT_GET_SUCCESS) + if (cal_client_get_object (priv->client, uid, &icalcomp) != CAL_CLIENT_GET_SUCCESS) return; + comp = cal_component_new (); + if (!cal_component_set_icalcomponent (comp, icalcomp)) { + g_object_unref (comp); + icalcomponent_free (icalcomp); + return; + } + msg = g_strdup_printf (_("Purging event %s"), uid); /* further filter the event, to check the last recurrence end date */ |