diff options
author | Damon Chaplin <damon@ximian.com> | 2001-07-03 12:21:37 +0800 |
---|---|---|
committer | Damon Chaplin <damon@src.gnome.org> | 2001-07-03 12:21:37 +0800 |
commit | 642d32d63f226cd1ba049a9d979132e1a1cef94d (patch) | |
tree | be4ef8fb72ca41391007554a6cbe97af41533555 /calendar | |
parent | bacd3a85a434032316b3e63b95282175ce2b0659 (diff) | |
download | gsoc2013-evolution-642d32d63f226cd1ba049a9d979132e1a1cef94d.tar.gz gsoc2013-evolution-642d32d63f226cd1ba049a9d979132e1a1cef94d.tar.zst gsoc2013-evolution-642d32d63f226cd1ba049a9d979132e1a1cef94d.zip |
cal-client/cal-client.[hc] cal-util/cal-component.c
2001-07-03 Damon Chaplin <damon@ximian.com>
* cal-client/cal-client.[hc]
* cal-util/cal-component.c
* cal-util/cal-recur.[hc]
* cal-util/test-recur.c
* cal-util/timeutil.c
* gui/calendar-config.c
* gui/calendar-model.[hc]
* gui/comp-util.[hc]
* gui/e-calendar-table.c
* gui/e-day-view-main-item.c
* gui/e-day-view-top-item.c
* gui/e-day-view.[hc]
* gui/e-itip-control.c
* gui/e-timezone-entry.[hc]
* gui/e-week-view.[hc]
* gui/gnome-cal.[hc]
* gui/goto.c
* gui/tag-calendar.[hc]
* gui/dialogs/cal-prefs-dialog.c
* gui/dialogs/comp-editor-page.[hc]
* gui/dialogs/comp-editor-util.[hc]
* gui/dialogs/comp-editor.c
* gui/dialogs/e-timezone-dialog.[hc]
* gui/dialogs/event-page.c
* gui/dialogs/meeting-page.c
* gui/dialogs/recurrence-page.c
* gui/dialogs/task-details-page.c
* gui/dialogs/task-details-page.glade
* gui/dialogs/task-page.c
* idl/evolution-calendar.idl
* pcs/cal-backend-file.c
* pcs/cal-backend.c
* pcs/cal-backend.h
* pcs/cal.c
* pcs/query.c: timezone changes everywhere. There's still quite a
few things to update, and its not working well at present.
svn path=/trunk/; revision=10729
Diffstat (limited to 'calendar')
48 files changed, 2009 insertions, 537 deletions
diff --git a/calendar/ChangeLog b/calendar/ChangeLog index 02d67a7add..3c93bd6a6b 100644 --- a/calendar/ChangeLog +++ b/calendar/ChangeLog @@ -1,3 +1,42 @@ +2001-07-03 Damon Chaplin <damon@ximian.com> + + * cal-client/cal-client.[hc] + * cal-util/cal-component.c + * cal-util/cal-recur.[hc] + * cal-util/test-recur.c + * cal-util/timeutil.c + * gui/calendar-config.c + * gui/calendar-model.[hc] + * gui/comp-util.[hc] + * gui/e-calendar-table.c + * gui/e-day-view-main-item.c + * gui/e-day-view-top-item.c + * gui/e-day-view.[hc] + * gui/e-itip-control.c + * gui/e-timezone-entry.[hc] + * gui/e-week-view.[hc] + * gui/gnome-cal.[hc] + * gui/goto.c + * gui/tag-calendar.[hc] + * gui/dialogs/cal-prefs-dialog.c + * gui/dialogs/comp-editor-page.[hc] + * gui/dialogs/comp-editor-util.[hc] + * gui/dialogs/comp-editor.c + * gui/dialogs/e-timezone-dialog.[hc] + * gui/dialogs/event-page.c + * gui/dialogs/meeting-page.c + * gui/dialogs/recurrence-page.c + * gui/dialogs/task-details-page.c + * gui/dialogs/task-details-page.glade + * gui/dialogs/task-page.c + * idl/evolution-calendar.idl + * pcs/cal-backend-file.c + * pcs/cal-backend.c + * pcs/cal-backend.h + * pcs/cal.c + * pcs/query.c: timezone changes everywhere. There's still quite a + few things to update, and its not working well at present. + 2001-07-02 JP Rosevear <jpr@ximian.com> * gui/calendar-commands.c (publish_freebusy_cmd): publish diff --git a/calendar/cal-client/cal-client.c b/calendar/cal-client/cal-client.c index a4a0851975..6bef9508b3 100644 --- a/calendar/cal-client/cal-client.c +++ b/calendar/cal-client/cal-client.c @@ -58,6 +58,10 @@ struct _CalClientPrivate { /* The WombatClient */ WombatClient *w_client; + + /* A cache of timezones retrieved from the server, to avoid getting + them repeatedly for each get_object() call. */ + GHashTable *timezones; }; @@ -180,6 +184,7 @@ cal_client_init (CalClient *client) priv->load_state = CAL_CLIENT_LOAD_NOT_LOADED; priv->uri = NULL; priv->factory = CORBA_OBJECT_NIL; + priv->timezones = g_hash_table_new (g_str_hash, g_str_equal); /* create the WombatClient */ priv->w_client = wombat_client_new ( @@ -291,6 +296,14 @@ destroy_cal (CalClient *client) } +static void +free_timezone (gpointer key, gpointer value, gpointer data) +{ + /* Note that the key comes from within the icaltimezone value, so we + don't free that. */ + icaltimezone_free (value); +} + /* Destroy handler for the calendar client */ static void cal_client_destroy (GtkObject *object) @@ -316,6 +329,10 @@ cal_client_destroy (GtkObject *object) priv->uri = NULL; } + g_hash_table_foreach (priv->timezones, free_timezone, NULL); + g_hash_table_destroy (priv->timezones); + priv->timezones = NULL; + g_free (priv); client->priv = NULL; @@ -804,6 +821,109 @@ cal_client_get_object (CalClient *client, const char *uid, CalComponent **comp) return retval; } +CalClientGetStatus +cal_client_get_timezone (CalClient *client, + const char *tzid, + icaltimezone **zone) +{ + CalClientPrivate *priv; + CORBA_Environment ev; + GNOME_Evolution_Calendar_CalObj comp_str; + CalClientGetStatus retval; + icalcomponent *icalcomp; + icaltimezone *tmp_zone; + + g_return_val_if_fail (client != NULL, CAL_CLIENT_GET_NOT_FOUND); + g_return_val_if_fail (IS_CAL_CLIENT (client), CAL_CLIENT_GET_NOT_FOUND); + + 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 (zone != NULL, CAL_CLIENT_GET_NOT_FOUND); + + /* If tzid is NULL or "" we return NULL, since it is a 'local time'. */ + if (!tzid || !tzid[0]) { + *zone = NULL; + return CAL_CLIENT_GET_SUCCESS; + } + + /* If it is UTC, we return the special UTC timezone. */ + if (!strcmp (tzid, "UTC")) { + *zone = icaltimezone_get_utc_timezone (); + return CAL_CLIENT_GET_SUCCESS; + } + + /* See if we already have it in the cache. */ + tmp_zone = g_hash_table_lookup (priv->timezones, tzid); + if (tmp_zone) { + *zone = tmp_zone; + return CAL_CLIENT_GET_SUCCESS; + } + + retval = CAL_CLIENT_GET_NOT_FOUND; + *zone = NULL; + + /* We don't already have it, so we try to get it from the server. */ + CORBA_exception_init (&ev); + comp_str = GNOME_Evolution_Calendar_Cal_getTimezoneObject (priv->cal, (char *) tzid, &ev); + + if (ev._major == CORBA_USER_EXCEPTION + && strcmp (CORBA_exception_id (&ev), ex_GNOME_Evolution_Calendar_Cal_NotFound) == 0) + goto out; + else if (ev._major != CORBA_NO_EXCEPTION) { + g_message ("cal_client_get_timezone(): could not get the object"); + goto out; + } + + icalcomp = icalparser_parse_string (comp_str); + CORBA_free (comp_str); + + if (!icalcomp) { + retval = CAL_CLIENT_GET_SYNTAX_ERROR; + goto out; + } + + tmp_zone = icaltimezone_new (); + if (!tmp_zone) { + /* FIXME: Needs better error code - out of memory. Or just + abort like GTK+ does? */ + retval = CAL_CLIENT_GET_NOT_FOUND; + goto out; + } + + if (!icaltimezone_set_component (tmp_zone, icalcomp)) { + retval = CAL_CLIENT_GET_SYNTAX_ERROR; + goto out; + } + + /* Now add it to the cache, to avoid the server call in future. */ + g_hash_table_insert (priv->timezones, icaltimezone_get_tzid (tmp_zone), + tmp_zone); + + *zone = tmp_zone; + retval = CAL_CLIENT_GET_SUCCESS; + + out: + + CORBA_exception_free (&ev); + return retval; +} + +/* Resolves TZIDs for the recurrence generator. */ +icaltimezone* +cal_client_resolve_tzid (const char *tzid, CalClient *client) +{ + icaltimezone *zone = NULL; + CalClientGetStatus status; + + /* FIXME: Handle errors. */ + status = cal_client_get_timezone (client, tzid, &zone); + + return zone; +} + + /* Builds an UID list out of a CORBA UID sequence */ static GList * build_uid_list (GNOME_Evolution_Calendar_CalObjUIDSeq *seq) @@ -1310,7 +1430,7 @@ cal_client_generate_instances (CalClient *client, CalObjType type, CalComponent *comp; comp = l->data; - cal_recur_generate_instances (comp, start, end, add_instance, &instances); + cal_recur_generate_instances (comp, start, end, add_instance, &instances, (CalRecurResolveTimezoneFn) cal_client_resolve_tzid, client); gtk_object_unref (GTK_OBJECT (comp)); } @@ -1570,6 +1690,135 @@ cal_client_get_alarms_for_object (CalClient *client, const char *uid, return retval; } +typedef struct _ForeachTZIDCallbackData ForeachTZIDCallbackData; +struct _ForeachTZIDCallbackData { + CalClient *client; + GHashTable *timezone_hash; +}; + +/* This adds the VTIMEZONE given by the TZID parameter to the GHashTable in + data. */ +static void +foreach_tzid_callback (icalparameter *param, void *cbdata) +{ + ForeachTZIDCallbackData *data = cbdata; + CalClientPrivate *priv; + const char *tzid; + icaltimezone *zone; + icalcomponent *vtimezone_comp; + char *vtimezone_as_string; + + priv = data->client->priv; + + /* Get the TZID string from the parameter. */ + tzid = icalparameter_get_tzid (param); + if (!tzid) + return; + + /* Check if it is in our cache. If it is, it must already be on the + server so return. */ + if (g_hash_table_lookup (priv->timezones, tzid)) + return; + + /* Check if we've already added it to the GHashTable. */ + if (g_hash_table_lookup (data->timezone_hash, tzid)) + return; + + /* Check if it is a builtin timezone. If it isn't, return. */ + zone = icaltimezone_get_builtin_timezone_from_tzid (tzid); + if (!zone) + return; + + /* Convert it to a string and add it to the hash. */ + vtimezone_comp = icaltimezone_get_component (zone); + if (!vtimezone_comp) + return; + + vtimezone_as_string = icalcomponent_as_ical_string (vtimezone_comp); + + g_hash_table_insert (data->timezone_hash, (char*) tzid, + g_strdup (vtimezone_as_string)); +} + +/* This appends the value string to the GString given in data. */ +static void +append_timezone_string (gpointer key, gpointer value, gpointer data) +{ + GString *vcal_string = data; + + g_string_append (vcal_string, value); + g_free (value); +} + + +/* This converts the VEVENT/VTODO to a string. It checks if we need to send + any builtin timezones to the server along with the object. + To do that we check every TZID in the component to see if it is a builtin + timezone. If it is, we see if it it in our cache. If it is in our cache, + then we know the server already has it and we don't need to send it. + If it isn't in our cache, then we need to send it to the server, and we + can add it to the cache as well. If we need to send any timezones to the + server, then we have to create a complete VCALENDAR object, otherwise + we can just send a single VEVENT/VTODO as before. */ +static char* +cal_client_get_component_as_string (CalClient *client, + CalComponent *comp) +{ + GHashTable *timezone_hash; + GString *vcal_string; + int initial_vcal_string_len; + ForeachTZIDCallbackData cbdata; + char *obj_string; + + CalClientPrivate *priv; + + priv = client->priv; + + timezone_hash = g_hash_table_new (g_str_hash, g_str_equal); + + /* Add any builtin timezones needed to the hash. We use a hash since + we only want to add each timezone once at most. */ + cbdata.client = client; + cbdata.timezone_hash = timezone_hash; + icalcomponent_foreach_tzid (cal_component_get_icalcomponent (comp), + foreach_tzid_callback, &cbdata); + + /* Create the start of a VCALENDAR, to add the VTIMEZONES to, + and remember its length so we know if any VTIMEZONEs get added. */ + vcal_string = g_string_new (NULL); + g_string_append (vcal_string, + "BEGIN:VCALENDAR\n" + "PRODID:-//Ximian//NONSGML Evolution Calendar//EN\n" + "VERSION:2.0\n"); + initial_vcal_string_len = vcal_string->len; + + /* Now concatenate all the timezone strings. This also frees the + timezone strings as it goes. */ + g_hash_table_foreach (timezone_hash, append_timezone_string, + vcal_string); + + /* Get the string for the VEVENT/VTODO. */ + obj_string = cal_component_get_as_string (comp); + + /* If there were any timezones to send, create a complete VCALENDAR, + else just send the VEVENT/VTODO string. */ + if (vcal_string->len == initial_vcal_string_len) { + g_string_free (vcal_string, TRUE); + } else { + g_string_append (vcal_string, obj_string); + g_string_append (vcal_string, "END:VCALENDAR\n"); + g_free (obj_string); + obj_string = vcal_string->str; + g_string_free (vcal_string, FALSE); + } + + g_hash_table_destroy (timezone_hash); + + fprintf (stderr, "Object String:\n=======\n%s======\n", obj_string); + + return obj_string; +} + /** * cal_client_update_object: * @client: A calendar client. @@ -1602,10 +1851,11 @@ cal_client_update_object (CalClient *client, CalComponent *comp) retval = FALSE; cal_component_commit_sequence (comp); - obj_string = cal_component_get_as_string (comp); cal_component_get_uid (comp, &uid); + obj_string = cal_client_get_component_as_string (client, comp); + CORBA_exception_init (&ev); GNOME_Evolution_Calendar_Cal_updateObject (priv->cal, (char *) uid, obj_string, &ev); g_free (obj_string); diff --git a/calendar/cal-client/cal-client.h b/calendar/cal-client/cal-client.h index de06b14eb9..72619074d2 100644 --- a/calendar/cal-client/cal-client.h +++ b/calendar/cal-client/cal-client.h @@ -110,6 +110,10 @@ CalClientGetStatus cal_client_get_object (CalClient *client, const char *uid, CalComponent **comp); +CalClientGetStatus cal_client_get_timezone (CalClient *client, + const char *tzid, + icaltimezone **zone); + GList *cal_client_get_uids (CalClient *client, CalObjType type); GList *cal_client_get_changes (CalClient *client, CalObjType type, const char *change_id); @@ -137,6 +141,10 @@ gboolean cal_client_remove_object (CalClient *client, const char *uid); CalQuery *cal_client_get_query (CalClient *client, const char *sexp); +/* Resolves TZIDs for the recurrence generator. */ +icaltimezone *cal_client_resolve_tzid (const char *tzid, CalClient *client); + + END_GNOME_DECLS diff --git a/calendar/cal-util/cal-component.c b/calendar/cal-util/cal-component.c index 36c6408d59..2669dc5562 100644 --- a/calendar/cal-util/cal-component.c +++ b/calendar/cal-util/cal-component.c @@ -883,7 +883,7 @@ ensure_mandatory_properties (CalComponent *comp) struct icaltimetype t; tim = time (NULL); - t = icaltime_from_timet (tim, FALSE); + t = icaltime_from_timet_with_zone (tim, FALSE, icaltimezone_get_utc_timezone ()); priv->dtstamp = icalproperty_new_dtstamp (t); icalcomponent_add_property (priv->icalcomp, priv->dtstamp); @@ -1822,8 +1822,12 @@ get_datetime (struct datetime *datetime, } else dt->value = NULL; + /* If the icaltimetype has is_utc set, we set "UTC" as the TZID. + This makes the timezone code simpler. */ if (datetime->tzid_param) dt->tzid = icalparameter_get_tzid (datetime->tzid_param); + else if (dt->value && dt->value->is_utc) + dt->tzid = "UTC"; else dt->tzid = NULL; } @@ -1853,6 +1857,10 @@ set_datetime (CalComponent *comp, struct datetime *datetime, g_return_if_fail (dt->value != NULL); + /* If the TZID is set to "UTC", we set the is_utc flag. */ + if (dt->tzid && !strcmp (dt->tzid, "UTC")) + dt->value->is_utc = 1; + if (datetime->prop) (* prop_set_func) (datetime->prop, *dt->value); else { @@ -1860,7 +1868,8 @@ set_datetime (CalComponent *comp, struct datetime *datetime, icalcomponent_add_property (priv->icalcomp, datetime->prop); } - if (dt->tzid) { + /* If the TZID is set to "UTC", we don't want to save the TZID. */ + if (dt->tzid && strcmp (dt->tzid, "UTC")) { g_assert (datetime->prop != NULL); if (datetime->tzid_param) diff --git a/calendar/cal-util/cal-recur.c b/calendar/cal-util/cal-recur.c index 9dcd1579a9..1e21f3109c 100644 --- a/calendar/cal-util/cal-recur.c +++ b/calendar/cal-util/cal-recur.c @@ -257,7 +257,9 @@ static void cal_recur_generate_instances_of_rule (CalComponent *comp, time_t start, time_t end, CalRecurInstanceFn cb, - gpointer cb_data); + gpointer cb_data, + CalRecurResolveTimezoneFn tz_cb, + gpointer tz_cb_data); static CalRecurrence * cal_recur_from_icalproperty (icalproperty *prop, gboolean exception); @@ -465,11 +467,15 @@ static gint cal_obj_date_only_compare_func (const void *arg1, static gboolean cal_recur_ensure_end_dates (CalComponent *comp, - gboolean refresh); + gboolean refresh, + CalRecurResolveTimezoneFn tz_cb, + gpointer tz_cb_data); static gboolean cal_recur_ensure_rule_end_date (CalComponent *comp, icalproperty *prop, gboolean exception, - gboolean refresh); + gboolean refresh, + CalRecurResolveTimezoneFn tz_cb, + gpointer tz_cb_data); static gboolean cal_recur_ensure_rule_end_date_cb (CalComponent *comp, time_t instance_start, time_t instance_end, @@ -598,7 +604,9 @@ cal_recur_generate_instances (CalComponent *comp, time_t start, time_t end, CalRecurInstanceFn cb, - gpointer cb_data) + gpointer cb_data, + CalRecurResolveTimezoneFn tz_cb, + gpointer tz_cb_data) { #if 0 g_print ("In cal_recur_generate_instances comp: %p\n", comp); @@ -606,7 +614,7 @@ cal_recur_generate_instances (CalComponent *comp, g_print (" end : %li - %s", end, ctime (&end)); #endif cal_recur_generate_instances_of_rule (comp, NULL, start, end, - cb, cb_data); + cb, cb_data, tz_cb, tz_cb_data); } @@ -630,7 +638,9 @@ cal_recur_generate_instances_of_rule (CalComponent *comp, time_t start, time_t end, CalRecurInstanceFn cb, - gpointer cb_data) + gpointer cb_data, + CalRecurResolveTimezoneFn tz_cb, + gpointer tz_cb_data) { CalComponentDateTime dtstart, dtend; time_t dtstart_time, dtend_time; @@ -640,6 +650,7 @@ cal_recur_generate_instances_of_rule (CalComponent *comp, CalObjTime chunk_start, chunk_end; gint days, seconds, year; gboolean single_rule; + icaltimezone *start_zone = NULL, *end_zone = NULL; g_return_if_fail (comp != NULL); g_return_if_fail (cb != NULL); @@ -657,15 +668,25 @@ cal_recur_generate_instances_of_rule (CalComponent *comp, goto out; } - dtstart_time = icaltime_as_timet (*dtstart.value); + if (dtstart.tzid && tz_cb) + start_zone = (*tz_cb) (dtstart.tzid, tz_cb_data); + if (dtend.tzid && tz_cb) + end_zone = (*tz_cb) (dtend.tzid, tz_cb_data); + + dtstart_time = icaltime_as_timet_with_zone (*dtstart.value, + start_zone); if (start == -1) start = dtstart_time; /* FIXME: DURATION could be used instead, couldn't it? - Damon */ - if (dtend.value) - dtend_time = icaltime_as_timet (*dtend.value); - else - dtend_time = time_day_end (dtstart_time); + if (!dtend.value) { + *dtend.value = *dtstart.value; + dtend.value->hour = 0; + dtend.value->minute = 0; + dtend.value->second = 0; + icaltime_adjust (dtend.value, 1, 0, 0, 0); + } + dtend_time = icaltime_as_timet_with_zone (*dtend.value, end_zone); /* If there is no recurrence, just call the callback if the event intersects the given interval. */ @@ -690,7 +711,7 @@ cal_recur_generate_instances_of_rule (CalComponent *comp, single_rule = FALSE; /* Make sure all the enddates for the rules are set. */ - cal_recur_ensure_end_dates (comp, FALSE); + cal_recur_ensure_end_dates (comp, FALSE, tz_cb, tz_cb_data); cal_component_get_rrule_property_list (comp, &rrules); cal_component_get_rdate_list (comp, &rdates); @@ -3576,6 +3597,7 @@ cal_object_time_from_time (CalObjTime *cotime, time_t tmp_time_t; tmp_time_t = t; + /* FIXME */ tmp_tm = localtime (&tmp_time_t); cotime->year = tmp_tm->tm_year + 1900; @@ -3619,7 +3641,9 @@ cal_obj_time_to_string (CalObjTime *cotime) or EXRULE. */ static gboolean cal_recur_ensure_end_dates (CalComponent *comp, - gboolean refresh) + gboolean refresh, + CalRecurResolveTimezoneFn tz_cb, + gpointer tz_cb_data) { GSList *rrules, *exrules, *elem; gboolean changed = FALSE; @@ -3628,14 +3652,16 @@ cal_recur_ensure_end_dates (CalComponent *comp, cal_component_get_rrule_property_list (comp, &rrules); for (elem = rrules; elem; elem = elem->next) { changed |= cal_recur_ensure_rule_end_date (comp, elem->data, - FALSE, refresh); + FALSE, refresh, + tz_cb, tz_cb_data); } /* Do the EXRULEs. */ cal_component_get_exrule_property_list (comp, &exrules); for (elem = exrules; elem; elem = elem->next) { changed |= cal_recur_ensure_rule_end_date (comp, elem->data, - TRUE, refresh); + TRUE, refresh, + tz_cb, tz_cb_data); } return changed; @@ -3654,7 +3680,9 @@ static gboolean cal_recur_ensure_rule_end_date (CalComponent *comp, icalproperty *prop, gboolean exception, - gboolean refresh) + gboolean refresh, + CalRecurResolveTimezoneFn tz_cb, + gpointer tz_cb_data) { struct icalrecurrencetype rule; CalRecurEnsureEndDateData cb_data; @@ -3680,7 +3708,7 @@ cal_recur_ensure_rule_end_date (CalComponent *comp, cb_data.instances = 0; cal_recur_generate_instances_of_rule (comp, prop, -1, -1, cal_recur_ensure_rule_end_date_cb, - &cb_data); + &cb_data, tz_cb, tz_cb_data); /* Store the end date in the "X-EVOLUTION-ENDDATE" parameter of the rule. */ diff --git a/calendar/cal-util/cal-recur.h b/calendar/cal-util/cal-recur.h index ad80c3ce1b..921a230de4 100644 --- a/calendar/cal-util/cal-recur.h +++ b/calendar/cal-util/cal-recur.h @@ -35,6 +35,9 @@ typedef gboolean (* CalRecurInstanceFn) (CalComponent *comp, time_t instance_end, gpointer data); +typedef icaltimezone* (* CalRecurResolveTimezoneFn) (const char *tzid, + gpointer data); + /* * Calls the given callback function for each occurrence of the event that * intersects the range between the given start and end times (the end time is @@ -45,12 +48,18 @@ typedef gboolean (* CalRecurInstanceFn) (CalComponent *comp, * * Both start and end can be -1, in which case we start at the events first * instance and continue until it ends, or forever if it has no enddate. + * + * The tz_cb is used to resolve references to timezones. It is passed a TZID + * and should return the icaltimezone* corresponding to that TZID. We need to + * do this as we access timezones in different ways on the client & server. */ void cal_recur_generate_instances (CalComponent *comp, time_t start, time_t end, CalRecurInstanceFn cb, - gpointer cb_data); + gpointer cb_data, + CalRecurResolveTimezoneFn tz_cb, + gpointer tz_cb_data); END_GNOME_DECLS diff --git a/calendar/cal-util/test-recur.c b/calendar/cal-util/test-recur.c index 4fee2d23a9..213017ea0e 100644 --- a/calendar/cal-util/test-recur.c +++ b/calendar/cal-util/test-recur.c @@ -156,10 +156,12 @@ generate_occurrences (icalcomponent *icalcomp) in one of the calendar views. */ #if 0 cal_recur_generate_instances (comp, 982022400, 982108800, - occurrence_cb, &occurrences); + occurrence_cb, &occurrences, + NULL, NULL); #else cal_recur_generate_instances (comp, -1, -1, - occurrence_cb, &occurrences); + occurrence_cb, &occurrences, + NULL, NULL); #endif /* Print the component again so we can see the diff --git a/calendar/cal-util/timeutil.c b/calendar/cal-util/timeutil.c index 07936950c0..3bb254dbf7 100644 --- a/calendar/cal-util/timeutil.c +++ b/calendar/cal-util/timeutil.c @@ -11,6 +11,7 @@ #include <string.h> #include <ctype.h> #include <glib.h> +#include <ical.h> #include "timeutil.h" @@ -39,8 +40,8 @@ isodate_from_time_t (time_t t) struct tm *tm; char isotime[40]; - tm = localtime (&t); - strftime (isotime, sizeof (isotime)-1, "%Y%m%dT%H%M%S", tm); + tm = gmtime (&t); + strftime (isotime, sizeof (isotime)-1, "%Y%m%dT%H%M%SZ", tm); return g_strdup (isotime); } @@ -51,6 +52,7 @@ isodate_from_time_t (time_t t) * Converts an ISO 8601 time string into a time_t value. * * Return value: Time_t corresponding to the specified ISO string. + * Note that we only allow UTC times at present. **/ time_t time_from_isodate (const char *str) @@ -59,6 +61,7 @@ time_from_isodate (const char *str) struct tm my_tm; time_t t; int i; + char *old_tz; g_return_val_if_fail (str != NULL, -1); @@ -93,16 +96,10 @@ time_from_isodate (const char *str) my_tm.tm_isdst = -1; + old_tz = set_tz ("UTC"); t = mktime (&my_tm); + unset_tz (old_tz); - if (len == 16) { -#if defined(HAVE_TM_GMTOFF) - t += my_tm.tm_gmtoff; -#elif defined(HAVE_TIMEZONE) - t -= timezone; -#endif - } - return t; } diff --git a/calendar/gui/calendar-config.c b/calendar/gui/calendar-config.c index f4678ab098..41c55ab91c 100644 --- a/calendar/gui/calendar-config.c +++ b/calendar/gui/calendar-config.c @@ -582,6 +582,8 @@ calendar_config_configure_e_calendar_table (ECalendarTable *cal_table) { CalendarModel *model; gboolean use_24_hour; + char *location; + icaltimezone *zone; g_return_if_fail (E_IS_CALENDAR_TABLE (cal_table)); @@ -590,6 +592,10 @@ calendar_config_configure_e_calendar_table (ECalendarTable *cal_table) model = e_calendar_table_get_model (cal_table); calendar_model_set_use_24_hour_format (model, use_24_hour); + location = calendar_config_get_timezone (); + zone = icaltimezone_get_builtin_timezone (location); + calendar_model_set_timezone (model, zone); + calendar_config_configure_e_cell_date_edit (cal_table->dates_cell); /* This is for changing the colors of the text; they will be re-fetched @@ -636,12 +642,12 @@ on_timezone_set (GnomeDialog *dialog, int button, ETimezoneDialog *etd) { - char *zone; + char *display_name; - zone = e_timezone_dialog_get_timezone (etd); + e_timezone_dialog_get_timezone (etd, &display_name); - if (zone && zone[0]) { - calendar_config_set_timezone (zone); + if (display_name && display_name[0]) { + calendar_config_set_timezone (display_name); calendar_config_write (); update_all_config_settings (); diff --git a/calendar/gui/calendar-model.c b/calendar/gui/calendar-model.c index bcd4d69843..6d1625238d 100644 --- a/calendar/gui/calendar-model.c +++ b/calendar/gui/calendar-model.c @@ -75,6 +75,9 @@ struct _CalendarModelPrivate { /* A balanced tree of the categories used by all the tasks/events. */ GTree *categories; + + /* The current timezone. */ + icaltimezone *zone; }; enum { @@ -201,6 +204,8 @@ calendar_model_init (CalendarModel *model) priv->use_24_hour_format = TRUE; priv->categories = g_tree_new ((GCompareFunc)strcmp); + + priv->zone = NULL; } /* Called from g_hash_table_foreach_remove(), frees a stored UID->index @@ -317,13 +322,26 @@ static char* get_time_t (CalendarModel *model, time_t *t, gboolean show_midnight) { static char buffer[64]; - struct tm *tmp_tm; + struct tm tmp_tm; + struct icaltimetype tt; if (*t <= 0) { buffer[0] = '\0'; } else { - tmp_tm = localtime (t); - e_time_format_date_and_time (tmp_tm, + tt = icaltime_from_timet_with_zone (*t, FALSE, + model->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; + + /* Call mktime() to set the weekday. */ + mktime (&tmp_tm); + + e_time_format_date_and_time (&tmp_tm, model->priv->use_24_hour_format, show_midnight, FALSE, buffer, sizeof (buffer)); @@ -383,12 +401,15 @@ get_completed (CalendarModel *model, struct icaltimetype *completed; time_t t; + /* FIXME: COMPLETED is in UTC, but we probably want to show it in + the current timezone. */ + cal_component_get_completed (comp, &completed); if (!completed) t = 0; else { - t = icaltime_as_timet (*completed); + t = icaltime_as_timet_with_zone (*completed, icaltimezone_get_utc_timezone ()); cal_component_free_icaltimetype (completed); } @@ -840,6 +861,8 @@ show_date_warning (CalendarModel *model) struct tm *tmp_tm; t = time (NULL); + /* We are only using this as an example, so the timezone doesn't + matter. */ tmp_tm = localtime (&t); if (model->priv->use_24_hour_format) @@ -972,6 +995,9 @@ set_completed (CalendarModel *model, CalComponent *comp, const char *value) struct tm tmp_tm; time_t t; + /* FIXME: COMPLETED is in UTC, but we probably want to show it in + the current timezone. */ + status = e_time_parse_date_and_time (value, &tmp_tm); if (status == E_TIME_PARSE_INVALID) { @@ -991,7 +1017,6 @@ set_datetime (CalendarModel *model, CalComponent *comp, const char *value, { ETimeParseStatus status; struct tm tmp_tm; - time_t t; status = e_time_parse_date_and_time (value, &tmp_tm); @@ -1001,12 +1026,18 @@ set_datetime (CalendarModel *model, CalComponent *comp, const char *value, (* set_func) (comp, NULL); } else { CalComponentDateTime dt; - struct icaltimetype itt; + struct icaltimetype itt = icaltime_null_time (); + + itt.year = tmp_tm.tm_year + 1900; + itt.month = tmp_tm.tm_mon + 1; + itt.day = tmp_tm.tm_mday; + itt.hour = tmp_tm.tm_hour; + itt.minute = tmp_tm.tm_min; + itt.second = tmp_tm.tm_sec; - t = mktime (&tmp_tm); - itt = icaltime_from_timet (t, FALSE); dt.value = &itt; - dt.tzid = NULL; + /* We assume it is being set to the current timezone. */ + dt.tzid = icaltimezone_get_tzid (model->priv->zone); (* set_func) (comp, &dt); } @@ -2305,3 +2336,24 @@ calendar_model_get_categories (CalendarModel *model) return model->priv->categories; } + + +/* The current timezone. */ +icaltimezone* +calendar_model_get_timezone (CalendarModel *model) +{ + g_return_val_if_fail (IS_CALENDAR_MODEL (model), NULL); + + return model->priv->zone; +} + + +void +calendar_model_set_timezone (CalendarModel *model, + icaltimezone *zone) +{ + g_return_if_fail (IS_CALENDAR_MODEL (model)); + + if (model->priv->zone != zone) + model->priv->zone = zone; +} diff --git a/calendar/gui/calendar-model.h b/calendar/gui/calendar-model.h index c74a2b41ee..5a47d3752e 100644 --- a/calendar/gui/calendar-model.h +++ b/calendar/gui/calendar-model.h @@ -80,6 +80,11 @@ gboolean calendar_model_get_use_24_hour_format (CalendarModel *model); void calendar_model_set_use_24_hour_format (CalendarModel *model, gboolean use_24_hour_format); +/* The current timezone. */ +icaltimezone* calendar_model_get_timezone (CalendarModel *model); +void calendar_model_set_timezone (CalendarModel *model, + icaltimezone *zone); + GTree* calendar_model_get_categories (CalendarModel *model); void calendar_model_set_default_category (CalendarModel *model, diff --git a/calendar/gui/comp-util.c b/calendar/gui/comp-util.c index 8b612f0ca9..944b5dcdce 100644 --- a/calendar/gui/comp-util.c +++ b/calendar/gui/comp-util.c @@ -37,7 +37,7 @@ * component object. **/ void -cal_comp_util_add_exdate (CalComponent *comp, struct icaltimetype itt) +cal_comp_util_add_exdate (CalComponent *comp, time_t t, icaltimezone *zone) { GSList *list; CalComponentDateTime *cdt; @@ -49,8 +49,8 @@ cal_comp_util_add_exdate (CalComponent *comp, struct icaltimetype itt) cdt = g_new (CalComponentDateTime, 1); cdt->value = g_new (struct icaltimetype, 1); - *cdt->value = itt; - cdt->tzid = NULL; + *cdt->value = icaltime_from_timet_with_zone (t, TRUE, zone); + cdt->tzid = icaltimezone_get_tzid (zone); list = g_slist_append (list, cdt); cal_component_set_exdate_list (comp, list); diff --git a/calendar/gui/comp-util.h b/calendar/gui/comp-util.h index 4da2557f1b..d0c39259ab 100644 --- a/calendar/gui/comp-util.h +++ b/calendar/gui/comp-util.h @@ -25,6 +25,6 @@ #include <cal-util/cal-component.h> -void cal_comp_util_add_exdate (CalComponent *comp, struct icaltimetype itt); +void cal_comp_util_add_exdate (CalComponent *comp, time_t t, icaltimezone *zone); #endif diff --git a/calendar/gui/dialogs/cal-prefs-dialog.c b/calendar/gui/dialogs/cal-prefs-dialog.c index de3cbf2483..59acefc263 100644 --- a/calendar/gui/dialogs/cal-prefs-dialog.c +++ b/calendar/gui/dialogs/cal-prefs-dialog.c @@ -390,14 +390,16 @@ cal_prefs_dialog_show_config (CalPrefsDialog *prefs) CalPrefsDialogPrivate *priv; CalWeekdays working_days; gint mask, day, week_start_day, time_divisions; - char *zone; + char *zone_name; + icaltimezone *zone; priv = prefs->priv; /* Timezone. */ - zone = calendar_config_get_timezone (); + zone_name = calendar_config_get_timezone (); + zone = icaltimezone_get_builtin_timezone (zone_name); e_timezone_entry_set_timezone (E_TIMEZONE_ENTRY (priv->timezone), - zone ? zone : ""); + zone); /* Working Days. */ working_days = calendar_config_get_working_days (); @@ -482,13 +484,13 @@ cal_prefs_dialog_update_config (CalPrefsDialog *prefs) CalPrefsDialogPrivate *priv; CalWeekdays working_days; gint mask, day, week_start_day, time_divisions, hour, minute; - char *zone; + icaltimezone *zone; priv = prefs->priv; /* Timezone. */ zone = e_timezone_entry_get_timezone (E_TIMEZONE_ENTRY (priv->timezone)); - calendar_config_set_timezone (zone); + calendar_config_set_timezone (icaltimezone_get_location (zone)); /* Working Days. */ working_days = 0; diff --git a/calendar/gui/dialogs/comp-editor-page.c b/calendar/gui/dialogs/comp-editor-page.c index afa09177f5..85e7b8c9af 100644 --- a/calendar/gui/dialogs/comp-editor-page.c +++ b/calendar/gui/dialogs/comp-editor-page.c @@ -29,6 +29,8 @@ static void comp_editor_page_class_init (CompEditorPageClass *class); +static void comp_editor_page_init (CompEditorPage *page); +static void comp_editor_page_destroy (GtkObject *object); /* Signal IDs */ @@ -65,7 +67,7 @@ comp_editor_page_get_type (void) sizeof (CompEditorPage), sizeof (CompEditorPageClass), (GtkClassInitFunc) comp_editor_page_class_init, - (GtkObjectInitFunc) NULL, + (GtkObjectInitFunc) comp_editor_page_init, NULL, /* reserved_1 */ NULL, /* reserved_2 */ (GtkClassInitFunc) NULL @@ -136,10 +138,36 @@ comp_editor_page_class_init (CompEditorPageClass *class) class->fill_component = NULL; class->set_summary = NULL; class->set_dates = NULL; + + object_class->destroy = comp_editor_page_destroy; } +static void +comp_editor_page_init (CompEditorPage *page) +{ + page->client = NULL; +} + + +static void +comp_editor_page_destroy (GtkObject *object) +{ + CompEditorPage *page; + + g_return_if_fail (object != NULL); + g_return_if_fail (IS_COMP_EDITOR_PAGE (object)); + + page = COMP_EDITOR_PAGE (object); + + if (page->client) { + gtk_object_ref (GTK_OBJECT (page->client)); + page->client = NULL; + } +} + + /** * comp_editor_page_get_widget: * @page: An editor page. @@ -198,6 +226,27 @@ comp_editor_page_fill_component (CompEditorPage *page, CalComponent *comp) } /** + * comp_editor_page_set_cal_client: + * @page: An editor page + * @client: A #CalClient object + * + * Sets the #CalClient for the dialog page to use. + **/ +void +comp_editor_page_set_cal_client (CompEditorPage *page, CalClient *client) +{ + g_return_if_fail (page != NULL); + g_return_if_fail (IS_COMP_EDITOR_PAGE (page)); + + if (page->client) + gtk_object_unref (GTK_OBJECT (client)); + + page->client = client; + if (page->client) + gtk_object_ref (GTK_OBJECT (client)); +} + +/** * comp_editor_page_set_summary: * @page: An editor page * @summary: The text of the new summary value diff --git a/calendar/gui/dialogs/comp-editor-page.h b/calendar/gui/dialogs/comp-editor-page.h index b544200a76..08fe1d8508 100644 --- a/calendar/gui/dialogs/comp-editor-page.h +++ b/calendar/gui/dialogs/comp-editor-page.h @@ -26,6 +26,7 @@ #include <libgnome/gnome-defs.h> #include <gtk/gtkwidget.h> #include <cal-util/cal-component.h> +#include "cal-client.h" BEGIN_GNOME_DECLS @@ -38,14 +39,17 @@ BEGIN_GNOME_DECLS #define IS_COMP_EDITOR_PAGE_CLASS(klass) (GTK_CHECK_CLASS_TYPE ((obj), TYPE_COMP_EDITOR_PAGE)) typedef struct { - time_t start; - time_t end; - time_t due; - time_t complete; + struct icaltimetype *start; + struct icaltimetype *end; + struct icaltimetype *due; + struct icaltimetype *complete; } CompEditorPageDates; typedef struct { GtkObject object; + + /* Some of the pages need the CalClient to access timezone data. */ + CalClient *client; } CompEditorPage; typedef struct { @@ -77,6 +81,8 @@ void comp_editor_page_fill_widgets (CompEditorPage *page, CalComponent *comp); void comp_editor_page_fill_component (CompEditorPage *page, CalComponent *comp); +void comp_editor_page_set_cal_client (CompEditorPage *page, + CalClient *client); void comp_editor_page_set_summary (CompEditorPage *page, const char *summary); void comp_editor_page_set_dates (CompEditorPage *page, diff --git a/calendar/gui/dialogs/comp-editor-util.c b/calendar/gui/dialogs/comp-editor-util.c index b6c169f6ed..e3cf454e84 100644 --- a/calendar/gui/dialogs/comp-editor-util.c +++ b/calendar/gui/dialogs/comp-editor-util.c @@ -24,6 +24,7 @@ #endif #include <string.h> +#include <ical.h> #include <glib.h> #include <libgnome/gnome-defs.h> #include <libgnome/gnome-i18n.h> @@ -39,50 +40,77 @@ * @comp: The component to extract the dates from * * Extracts the dates from the calendar component into the - * CompEditorPageDates structure + * CompEditorPageDates structure. Note that it returns pointers to static + * structs, so these will be overwritten in the next call. **/ void comp_editor_dates (CompEditorPageDates *dates, CalComponent *comp) { + static struct icaltimetype start; + static struct icaltimetype end; + static struct icaltimetype due; + static struct icaltimetype complete; + CalComponentDateTime dt; - struct icaltimetype *completed; + struct icaltimetype *comp_complete; + - dates->start = 0; - dates->end = 0; - dates->due = 0; - dates->complete = 0; + dates->start = NULL; + dates->end = NULL; + dates->due = NULL; + dates->complete = NULL; cal_component_get_dtstart (comp, &dt); - if (dt.value) - dates->start = icaltime_as_timet (*dt.value); + if (dt.value) { + start = *dt.value; + dates->start = &start; + } + cal_component_free_datetime (&dt); cal_component_get_dtend (comp, &dt); - if (dt.value) - dates->end = icaltime_as_timet (*dt.value); + if (dt.value) { + end = *dt.value; + dates->end = &end; + } + cal_component_free_datetime (&dt); cal_component_get_due (comp, &dt); - if (dt.value) - dates->due = icaltime_as_timet (*dt.value); + if (dt.value) { + due = *dt.value; + dates->due = &due; + } + cal_component_free_datetime (&dt); - cal_component_get_completed (comp, &completed); - if (completed) { - dates->complete = icaltime_as_timet (*completed); - cal_component_free_icaltimetype (completed); + cal_component_get_completed (comp, &comp_complete); + if (comp_complete) { + complete = *comp_complete; + dates->complete = &complete; } + cal_component_free_icaltimetype (comp_complete); } static void -write_label_piece (time_t t, char *buffer, int size, char *stext, char *etext) +write_label_piece (struct icaltimetype *tt, char *buffer, int size, + char *stext, char *etext) { - struct tm *tmp_tm; + struct tm tmp_tm; int len; - tmp_tm = localtime (&t); + /* FIXME: May want to convert the time to an appropriate zone. */ + if (stext != NULL) strcat (buffer, stext); + 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; + len = strlen (buffer); - e_time_format_date_and_time (tmp_tm, + e_time_format_date_and_time (&tmp_tm, calendar_config_get_24_hour_format (), FALSE, FALSE, &buffer[len], size - len); @@ -101,25 +129,36 @@ write_label_piece (time_t t, char *buffer, int size, char *stext, char *etext) void comp_editor_date_label (CompEditorPageDates *dates, GtkWidget *label) { - static char buffer[1024]; + char buffer[1024]; + gboolean start_set = FALSE, end_set = FALSE; + gboolean complete_set = FALSE, due_set = FALSE; buffer[0] = '\0'; - if (dates->start > 0) + if (dates->start && !icaltime_is_null_time (*dates->start)) + start_set = TRUE; + if (dates->end && !icaltime_is_null_time (*dates->end)) + end_set = TRUE; + if (dates->complete && !icaltime_is_null_time (*dates->complete)) + complete_set = TRUE; + if (dates->due && !icaltime_is_null_time (*dates->due)) + due_set = TRUE; + + if (start_set) write_label_piece (dates->start, buffer, 1024, NULL, NULL); - if (dates->end > 0 && dates->start > 0) + if (start_set && end_set) write_label_piece (dates->end, buffer, 1024, _(" to "), NULL); - if (dates->complete > 0) { - if (dates->start > 0) + if (complete_set) { + if (start_set) write_label_piece (dates->complete, buffer, 1024, _(" (Completed "), ")"); else write_label_piece (dates->complete, buffer, 1024, _("Completed "), NULL); } - if (dates->due > 0 && dates->complete == 0) { - if (dates->start > 0) + if (due_set && dates->complete == NULL) { + if (start_set) write_label_piece (dates->due, buffer, 1024, _(" (Due "), ")"); else write_label_piece (dates->due, buffer, 1024, _("Due "), NULL); @@ -151,3 +190,34 @@ comp_editor_new_date_edit (gboolean show_date, gboolean show_time) return GTK_WIDGET (dedit); } + + +/* Returns the current time, for EDateEdit widgets and ECalendar items in the + dialogs. + FIXME: Should probably use the timezone from somewhere in the component + rather than the current timezone. */ +struct tm +comp_editor_get_current_time (GtkObject *object, gpointer data) +{ + char *location; + icaltimezone *zone; + struct icaltimetype tt; + struct tm tmp_tm = { 0 }; + + /* Get the current timezone. */ + location = calendar_config_get_timezone (); + zone = icaltimezone_get_builtin_timezone (location); + + tt = icaltime_from_timet_with_zone (time (NULL), FALSE, zone); + + /* Now copy it to the struct tm and return it. */ + 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; + + return tmp_tm; +} diff --git a/calendar/gui/dialogs/comp-editor-util.h b/calendar/gui/dialogs/comp-editor-util.h index f2299e27c4..4e8e344731 100644 --- a/calendar/gui/dialogs/comp-editor-util.h +++ b/calendar/gui/dialogs/comp-editor-util.h @@ -30,4 +30,6 @@ void comp_editor_date_label (CompEditorPageDates *dates, GtkWidget *label); GtkWidget *comp_editor_new_date_edit (gboolean show_date, gboolean show_time); +struct tm comp_editor_get_current_time (GtkObject *object, gpointer data); + #endif diff --git a/calendar/gui/dialogs/comp-editor.c b/calendar/gui/dialogs/comp-editor.c index 08677260e7..c001207783 100644 --- a/calendar/gui/dialogs/comp-editor.c +++ b/calendar/gui/dialogs/comp-editor.c @@ -364,6 +364,7 @@ void comp_editor_set_cal_client (CompEditor *editor, CalClient *client) { CompEditorPrivate *priv; + GList *elem; g_return_if_fail (editor != NULL); g_return_if_fail (IS_COMP_EDITOR (editor)); @@ -388,6 +389,10 @@ comp_editor_set_cal_client (CompEditor *editor, CalClient *client) priv->client = client; + /* Pass the client to any pages that need it. */ + for (elem = priv->pages; elem; elem = elem->next) + comp_editor_page_set_cal_client (elem->data, client); + gtk_signal_connect (GTK_OBJECT (priv->client), "obj_updated", GTK_SIGNAL_FUNC (obj_updated_cb), editor); diff --git a/calendar/gui/dialogs/e-timezone-dialog.c b/calendar/gui/dialogs/e-timezone-dialog.c index ad9acfb528..70061addd6 100644 --- a/calendar/gui/dialogs/e-timezone-dialog.c +++ b/calendar/gui/dialogs/e-timezone-dialog.c @@ -37,6 +37,11 @@ #define E_TIMEZONE_DIALOG_MAP_POINT_SELECTED_2_RGBA 0x000000ff struct _ETimezoneDialogPrivate { + /* The TZID of the timezone. May be NULL for a 'local time' (i.e. when + the displayed name is "") or for builtin timezones which we haven't + loaded yet. */ + char *tzid; + /* Glade XML data */ GladeXML *xml; @@ -131,6 +136,7 @@ e_timezone_dialog_init (ETimezoneDialog *etd) priv = g_new0 (ETimezoneDialogPrivate, 1); etd->priv = priv; + priv->tzid = NULL; priv->point_selected = NULL; priv->point_hover = NULL; priv->timeout_id = 0; @@ -149,6 +155,9 @@ e_timezone_dialog_destroy (GtkObject *object) etd = E_TIMEZONE_DIALOG (object); priv = etd->priv; + g_free (priv->tzid); + priv->tzid = NULL; + if (priv->timeout_id) { g_source_remove (priv->timeout_id); priv->timeout_id = 0; @@ -460,6 +469,9 @@ on_map_button_pressed (GtkWidget *w, GdkEventButton *event, gpointer data) gtk_entry_set_text (GTK_ENTRY (GTK_COMBO (priv->timezone_combo)->entry), get_zone_from_point (etd, priv->point_selected)); + + g_free (priv->tzid); + priv->tzid = NULL; } return TRUE; @@ -508,8 +520,13 @@ get_zone_from_point (ETimezoneDialog *etd, } +/* Returns the TZID of the timezone set, and optionally its displayed name. + The TZID may be NULL, in which case the builtin timezone with the city name + of display_name should be used. If display_name is also NULL or "", then it + is assumed to be a 'local time'. */ char* -e_timezone_dialog_get_timezone (ETimezoneDialog *etd) +e_timezone_dialog_get_timezone (ETimezoneDialog *etd, + char **display_name) { ETimezoneDialogPrivate *priv; @@ -518,13 +535,21 @@ e_timezone_dialog_get_timezone (ETimezoneDialog *etd) priv = etd->priv; - return gtk_entry_get_text (GTK_ENTRY (GTK_COMBO (priv->timezone_combo)->entry)); + if (display_name) + *display_name = gtk_entry_get_text (GTK_ENTRY (GTK_COMBO (priv->timezone_combo)->entry)); + + return priv->tzid; } +/* Sets the TZID and displayed name of the timezone. The TZID may be NULL for + a 'local time' (i.e. display_name is NULL or "") or if it is a builtin + timezone which hasn't been loaded yet. (This is done so we don't load + timezones until we really need them.) */ void e_timezone_dialog_set_timezone (ETimezoneDialog *etd, - char *timezone) + char *tzid, + char *display_name) { ETimezoneDialogPrivate *priv; @@ -533,8 +558,13 @@ e_timezone_dialog_set_timezone (ETimezoneDialog *etd, priv = etd->priv; + if (priv->tzid) + g_free (priv->tzid); + + priv->tzid = g_strdup (tzid); + gtk_entry_set_text (GTK_ENTRY (GTK_COMBO (priv->timezone_combo)->entry), - timezone); + display_name ? display_name : ""); find_selected_point (etd); } @@ -605,5 +635,12 @@ find_selected_point (ETimezoneDialog *etd) static void on_combo_changed (GtkEditable *entry, ETimezoneDialog *etd) { + ETimezoneDialogPrivate *priv; + + priv = etd->priv; + find_selected_point (etd); + + g_free (priv->tzid); + priv->tzid = NULL; } diff --git a/calendar/gui/dialogs/e-timezone-dialog.h b/calendar/gui/dialogs/e-timezone-dialog.h index 323375c5fc..4f6f9dd934 100644 --- a/calendar/gui/dialogs/e-timezone-dialog.h +++ b/calendar/gui/dialogs/e-timezone-dialog.h @@ -56,9 +56,20 @@ ETimezoneDialog* e_timezone_dialog_construct (ETimezoneDialog *etd); ETimezoneDialog* e_timezone_dialog_new (void); -char* e_timezone_dialog_get_timezone (ETimezoneDialog *etd); +/* Returns the TZID of the timezone set, and optionally its displayed name. + The TZID may be NULL, in which case the builtin timezone with the city name + of display_name should be used. If display_name is also NULL or "", then it + is assumed to be a 'local time'. */ +char* e_timezone_dialog_get_timezone (ETimezoneDialog *etd, + char **display_name); + +/* Sets the TZID and displayed name of the timezone. The TZID may be NULL for + a 'local time' (i.e. display_name is NULL or "") or if it is a builtin + timezone which hasn't been loaded yet. (This is done so we don't load + timezones until we really need them.) */ void e_timezone_dialog_set_timezone (ETimezoneDialog *etd, - char *timezone); + char *tzid, + char *display_name); GtkWidget* e_timezone_dialog_get_toplevel (ETimezoneDialog *etd); diff --git a/calendar/gui/dialogs/event-page.c b/calendar/gui/dialogs/event-page.c index 89835ae4b3..c9f1891fdc 100644 --- a/calendar/gui/dialogs/event-page.c +++ b/calendar/gui/dialogs/event-page.c @@ -232,22 +232,20 @@ static void check_all_day (EventPage *epage) { EventPagePrivate *priv; - time_t ev_start, ev_end; - gboolean all_day = FALSE; + gboolean all_day = FALSE, start_set, end_set; + gint start_hour, start_minute, end_hour, end_minute; priv = epage->priv; - /* Currently we just return if the date is not set or not valid. - I'm not entirely sure this is the corrent thing to do. */ - ev_start = e_date_edit_get_time (E_DATE_EDIT (priv->start_time)); - g_assert (ev_start != -1); + start_set = e_date_edit_get_time_of_day (E_DATE_EDIT (priv->start_time), + &start_hour, &start_minute); - ev_end = e_date_edit_get_time (E_DATE_EDIT (priv->end_time)); - g_assert (ev_end != -1); + end_set = e_date_edit_get_time_of_day (E_DATE_EDIT (priv->end_time), + &end_hour, &end_minute); /* all day event checkbox */ - if (time_day_begin (ev_start) == ev_start - && time_day_begin (ev_end) == ev_end) + if ((!start_set || (start_hour == 0 && start_minute == 0)) + && (!end_set || (end_hour == 0 && end_minute == 0))) all_day = TRUE; gtk_signal_handler_block_by_data (GTK_OBJECT (priv->all_day_event), @@ -265,12 +263,9 @@ static void clear_widgets (EventPage *epage) { EventPagePrivate *priv; - time_t now; priv = epage->priv; - now = time (NULL); - /* Summary, description */ e_dialog_editable_set (priv->summary, NULL); e_dialog_editable_set (priv->description, NULL); @@ -280,8 +275,8 @@ clear_widgets (EventPage *epage) epage); gtk_signal_handler_block_by_data (GTK_OBJECT (priv->end_time), epage); - e_date_edit_set_time (E_DATE_EDIT (priv->start_time), now); - e_date_edit_set_time (E_DATE_EDIT (priv->end_time), now); + e_date_edit_set_time (E_DATE_EDIT (priv->start_time), 0); + e_date_edit_set_time (E_DATE_EDIT (priv->end_time), 0); gtk_signal_handler_unblock_by_data (GTK_OBJECT (priv->start_time), epage); @@ -306,10 +301,14 @@ event_page_fill_widgets (CompEditorPage *page, CalComponent *comp) EventPagePrivate *priv; CalComponentText text; CalComponentClassification cl; - CalComponentDateTime d; + CalComponentDateTime start_date, end_date; GSList *l; - time_t dtstart, dtend; const char *categories; + CalClientGetStatus status; + struct icaltimetype *start_tt, *end_tt; + icaltimezone *start_zone = NULL, *end_zone = NULL; + + g_return_if_fail (page->client != NULL); epage = EVENT_PAGE (page); priv = epage->priv; @@ -334,40 +333,63 @@ event_page_fill_widgets (CompEditorPage *page, CalComponent *comp) /* Start and end times */ + cal_component_get_dtstart (comp, &start_date); + status = cal_client_get_timezone (page->client, start_date.tzid, + &start_zone); + /* FIXME: Handle error better. */ + if (status != CAL_CLIENT_GET_SUCCESS) + g_warning ("Couldn't get timezone from server: %s", + start_date.tzid ? start_date.tzid : ""); + + cal_component_get_dtend (comp, &end_date); + status = cal_client_get_timezone (page->client, end_date.tzid, &end_zone); + /* FIXME: Handle error better. */ + if (status != CAL_CLIENT_GET_SUCCESS) + g_warning ("Couldn't get timezone from server: %s", + end_date.tzid ? end_date.tzid : ""); + /* All-day events are inclusive, i.e. if the end date shown is 2nd Feb then the event includes all of the 2nd Feb. We would normally show 3rd Feb as the end date, since it really ends at midnight on 3rd, so we have to subtract a day so we only show the 2nd. */ - cal_component_get_dtstart (comp, &d); - dtstart = icaltime_as_timet (*d.value); - cal_component_free_datetime (&d); - - cal_component_get_dtend (comp, &d); - dtend = icaltime_as_timet (*d.value); - cal_component_free_datetime (&d); - - if (time_day_begin (dtstart) == dtstart - && time_day_begin (dtend) == dtend) - dtend = time_add_day (dtend, -1); + start_tt = start_date.value; + end_tt = end_date.value; + if (start_tt->hour == 0 && start_tt->minute == 0 && start_tt->second == 0 + && end_tt->hour == 0 && end_tt->minute == 0 && end_tt->second == 0) + icaltime_adjust (end_tt, 1, 0, 0, 0); gtk_signal_handler_block_by_data (GTK_OBJECT (priv->start_time), epage); gtk_signal_handler_block_by_data (GTK_OBJECT (priv->end_time), epage); - e_date_edit_set_time (E_DATE_EDIT (priv->start_time), dtstart); - e_date_edit_set_time (E_DATE_EDIT (priv->end_time), dtend); + e_date_edit_set_date (E_DATE_EDIT (priv->start_time), start_tt->year, + start_tt->month, start_tt->day); + e_date_edit_set_time_of_day (E_DATE_EDIT (priv->start_time), + start_tt->hour, start_tt->minute); + + e_date_edit_set_date (E_DATE_EDIT (priv->end_time), end_tt->year, + end_tt->month, end_tt->day); + e_date_edit_set_time_of_day (E_DATE_EDIT (priv->end_time), + end_tt->hour, end_tt->minute); gtk_signal_handler_unblock_by_data (GTK_OBJECT (priv->start_time), epage); gtk_signal_handler_unblock_by_data (GTK_OBJECT (priv->end_time), epage); + cal_component_free_datetime (&start_date); + cal_component_free_datetime (&end_date); + check_all_day (epage); - /* FIXME: Get the timezones from the event and put them in the - widgets. Set sync_timezones to TRUE if both timezones are the same. - */ - priv->sync_timezones = TRUE; + /* Set the timezones, and set sync_timezones to TRUE if both timezones + are the same. */ + e_timezone_entry_set_timezone (E_TIMEZONE_ENTRY (priv->start_timezone), + start_zone); + e_timezone_entry_set_timezone (E_TIMEZONE_ENTRY (priv->end_timezone), + end_zone); + priv->sync_timezones = (start_zone == end_zone) ? TRUE : FALSE; + /* Classification */ @@ -413,10 +435,10 @@ event_page_fill_component (CompEditorPage *page, CalComponent *comp) EventPagePrivate *priv; CalComponentDateTime date; struct icaltimetype icaltime; - time_t t; - gboolean all_day_event; + gboolean all_day_event, date_set; char *cat, *str; CalComponentClassification classif; + icaltimezone *zone; epage = EVENT_PAGE (page); priv = epage->priv; @@ -463,28 +485,51 @@ event_page_fill_component (CompEditorPage *page, CalComponent *comp) date.value = &icaltime; date.tzid = NULL; - t = e_date_edit_get_time (E_DATE_EDIT (priv->start_time)); - if (t != -1) { - *date.value = icaltime_from_timet (t, FALSE); - cal_component_set_dtstart (comp, &date); - } else { - /* FIXME: What do we do here? */ - } + icaltime.is_utc = 0; + /* FIXME: We should use is_date at some point. */ + icaltime.is_date = 0; + icaltime.is_daylight = 0; + icaltime.second = 0; + + date_set = e_date_edit_get_date (E_DATE_EDIT (priv->start_time), + &icaltime.year, + &icaltime.month, + &icaltime.day); + e_date_edit_get_time_of_day (E_DATE_EDIT (priv->start_time), + &icaltime.hour, + &icaltime.minute); + g_assert (date_set); + zone = e_timezone_entry_get_timezone (E_TIMEZONE_ENTRY (priv->start_timezone)); + if (zone) + date.tzid = icaltimezone_get_tzid (zone); + cal_component_set_dtstart (comp, &date); /* If the all_day toggle is set, the end date is inclusive of the entire day on which it points to. */ all_day_event = e_dialog_toggle_get (priv->all_day_event); - t = e_date_edit_get_time (E_DATE_EDIT (priv->end_time)); - if (t != -1) { - if (all_day_event) - t = time_day_end (t); - *date.value = icaltime_from_timet (t, FALSE); - cal_component_set_dtend (comp, &date); - } else { - /* FIXME: What do we do here? */ + date_set = e_date_edit_get_date (E_DATE_EDIT (priv->end_time), + &icaltime.year, + &icaltime.month, + &icaltime.day); + e_date_edit_get_time_of_day (E_DATE_EDIT (priv->end_time), + &icaltime.hour, + &icaltime.minute); + g_assert (date_set); + + if (all_day_event) { + icaltime.hour = 0; + icaltime.minute = 0; + icaltime.second = 0; + icaltime_adjust (&icaltime, 1, 0, 0, 0); } + zone = e_timezone_entry_get_timezone (E_TIMEZONE_ENTRY (priv->end_timezone)); + if (zone) + date.tzid = icaltimezone_get_tzid (zone); + cal_component_set_dtend (comp, &date); + + /* Categories */ cat = e_dialog_editable_get (priv->categories); @@ -606,9 +651,11 @@ date_changed_cb (EDateEdit *dedit, gpointer data) { EventPage *epage; EventPagePrivate *priv; - time_t start, end; - struct tm tm_start, tm_end; CompEditorPageDates dates; + struct icaltimetype start_tt = icaltime_null_time(); + struct icaltimetype end_tt = icaltime_null_time(); + int cmp; + gboolean date_set; epage = EVENT_PAGE (data); priv = epage->priv; @@ -617,49 +664,67 @@ date_changed_cb (EDateEdit *dedit, gpointer data) return; /* Ensure that start < end */ - start = e_date_edit_get_time (E_DATE_EDIT (priv->start_time)); - g_assert (start != -1); - end = e_date_edit_get_time (E_DATE_EDIT (priv->end_time)); - g_assert (end != -1); - - if (start >= end) { - tm_start = *localtime (&start); - tm_end = *localtime (&end); - - if (start == end && tm_start.tm_hour == 0 - && tm_start.tm_min == 0 && tm_start.tm_sec == 0) { + date_set = e_date_edit_get_date (E_DATE_EDIT (priv->start_time), + &start_tt.year, + &start_tt.month, + &start_tt.day); + e_date_edit_get_time_of_day (E_DATE_EDIT (priv->start_time), + &start_tt.hour, + &start_tt.minute); + g_assert (date_set); + + date_set = e_date_edit_get_date (E_DATE_EDIT (priv->end_time), + &end_tt.year, + &end_tt.month, + &end_tt.day); + e_date_edit_get_time_of_day (E_DATE_EDIT (priv->end_time), + &end_tt.hour, + &end_tt.minute); + g_assert (date_set); + + cmp = icaltime_compare (start_tt, end_tt); + if (cmp >= 0) { + if (cmp == 0 && start_tt.hour == 0 + && start_tt.minute == 0 + && start_tt.second == 0) { /* If the start and end times are the same, but both * are on day boundaries, then that is OK since it * means we have an all-day event lasting 1 day. So * we do nothing here. */ } else if (GTK_WIDGET (dedit) == priv->start_time) { - /* Modify the end time */ + /* Modify the end time, to be the start + 1 hour. */ - tm_end.tm_year = tm_start.tm_year; - tm_end.tm_mon = tm_start.tm_mon; - tm_end.tm_mday = tm_start.tm_mday; - tm_end.tm_hour = tm_start.tm_hour + 1; - tm_end.tm_min = tm_start.tm_min; - tm_end.tm_sec = tm_start.tm_sec; + end_tt = start_tt; + icaltime_adjust (&end_tt, 0, 1, 0, 0); gtk_signal_handler_block_by_data (GTK_OBJECT (priv->end_time), epage); - end = mktime (&tm_end); - e_date_edit_set_time (E_DATE_EDIT (priv->end_time), end); + + e_date_edit_set_date (E_DATE_EDIT (priv->end_time), + end_tt.year, + end_tt.month, + end_tt.day); + e_date_edit_set_time_of_day (E_DATE_EDIT (priv->end_time), + end_tt.hour, + end_tt.minute); + gtk_signal_handler_unblock_by_data (GTK_OBJECT (priv->end_time), epage); } else if (GTK_WIDGET (dedit) == priv->end_time) { - /* Modify the start time */ + /* Modify the start time, to be the end - 1 hour. */ - tm_start.tm_year = tm_end.tm_year; - tm_start.tm_mon = tm_end.tm_mon; - tm_start.tm_mday = tm_end.tm_mday; - tm_start.tm_hour = tm_end.tm_hour - 1; - tm_start.tm_min = tm_end.tm_min; - tm_start.tm_sec = tm_end.tm_sec; + start_tt = end_tt; + icaltime_adjust (&start_tt, 0, -1, 0, 0); gtk_signal_handler_block_by_data (GTK_OBJECT (priv->start_time), epage); - start = mktime (&tm_start); - e_date_edit_set_time (E_DATE_EDIT (priv->start_time), start); + + e_date_edit_set_date (E_DATE_EDIT (priv->start_time), + start_tt.year, + start_tt.month, + start_tt.day); + e_date_edit_set_time_of_day (E_DATE_EDIT (priv->start_time), + start_tt.hour, + start_tt.minute); + gtk_signal_handler_unblock_by_data (GTK_OBJECT (priv->start_time), epage); } else g_assert_not_reached (); @@ -669,10 +734,10 @@ date_changed_cb (EDateEdit *dedit, gpointer data) check_all_day (epage); /* Notify upstream */ - dates.start = start; - dates.end = end; - dates.due = 0; - dates.complete = 0; + dates.start = &start_tt; + dates.end = &end_tt; + dates.due = NULL; + dates.complete = NULL; comp_editor_page_notify_dates_changed (COMP_EDITOR_PAGE (epage), &dates); } @@ -686,7 +751,7 @@ start_timezone_changed_cb (GtkWidget *widget, gpointer data) { EventPage *epage; EventPagePrivate *priv; - char *zone; + icaltimezone *zone; epage = EVENT_PAGE (data); priv = epage->priv; @@ -706,7 +771,7 @@ end_timezone_changed_cb (GtkWidget *widget, gpointer data) { EventPage *epage; EventPagePrivate *priv; - char *start_zone, *end_zone; + icaltimezone *start_zone, *end_zone; epage = EVENT_PAGE (data); priv = epage->priv; @@ -714,7 +779,7 @@ end_timezone_changed_cb (GtkWidget *widget, gpointer data) start_zone = e_timezone_entry_get_timezone (E_TIMEZONE_ENTRY (priv->start_timezone)); end_zone = e_timezone_entry_get_timezone (E_TIMEZONE_ENTRY (priv->end_timezone)); - priv->sync_timezones = (strcmp (start_zone, end_zone)) ? FALSE : TRUE; + priv->sync_timezones = (start_zone == end_zone) ? TRUE : FALSE; } /* Callback: all day event button toggled. @@ -727,11 +792,12 @@ all_day_event_toggled_cb (GtkWidget *toggle, gpointer data) { EventPage *epage; EventPagePrivate *priv; - struct tm start_tm, end_tm; - time_t start_t, end_t; gboolean all_day; CompEditorPageDates dates; - + struct icaltimetype start_tt = icaltime_null_time(); + struct icaltimetype end_tt = icaltime_null_time(); + gboolean date_set; + epage = EVENT_PAGE (data); priv = epage->priv; @@ -755,51 +821,58 @@ all_day_event_toggled_cb (GtkWidget *toggle, gpointer data) /* * Start time. */ - start_t = e_date_edit_get_time (E_DATE_EDIT (priv->start_time)); - g_assert (start_t != -1); - - start_tm = *localtime (&start_t); + date_set = e_date_edit_get_date (E_DATE_EDIT (priv->start_time), + &start_tt.year, + &start_tt.month, + &start_tt.day); + e_date_edit_get_time_of_day (E_DATE_EDIT (priv->start_time), + &start_tt.hour, + &start_tt.minute); + g_assert (date_set); if (all_day) { /* Round down to the start of the day. */ - start_tm.tm_hour = 0; - start_tm.tm_min = 0; - start_tm.tm_sec = 0; + start_tt.hour = 0; + start_tt.minute = 0; + start_tt.second = 0; } else { /* Set to the start of the working day. */ - start_tm.tm_hour = calendar_config_get_day_start_hour (); - start_tm.tm_min = calendar_config_get_day_start_minute (); - start_tm.tm_sec = 0; + start_tt.hour = calendar_config_get_day_start_hour (); + start_tt.minute = calendar_config_get_day_start_minute (); + start_tt.second = 0; } /* * End time. */ - end_t = e_date_edit_get_time (E_DATE_EDIT (priv->end_time)); - g_assert (end_t != -1); - - end_tm = *localtime (&end_t); + date_set = e_date_edit_get_date (E_DATE_EDIT (priv->end_time), + &end_tt.year, + &end_tt.month, + &end_tt.day); + e_date_edit_get_time_of_day (E_DATE_EDIT (priv->end_time), + &end_tt.hour, + &end_tt.minute); + g_assert (date_set); if (all_day) { /* Round down to the start of the day. */ - end_tm.tm_hour = 0; - end_tm.tm_min = 0; - end_tm.tm_sec = 0; + end_tt.hour = 0; + end_tt.minute = 0; + end_tt.second = 0; } else { /* If the event end is now on or before the event start day, - * make it end one hour after the start. mktime() will fix any - * overflows. - */ - if (end_tm.tm_year < start_tm.tm_year - || (end_tm.tm_year == start_tm.tm_year - && end_tm.tm_mon < start_tm.tm_mon) - || (end_tm.tm_year == start_tm.tm_year - && end_tm.tm_mon == start_tm.tm_mon - && end_tm.tm_mday <= start_tm.tm_mday)) { - end_tm.tm_year = start_tm.tm_year; - end_tm.tm_mon = start_tm.tm_mon; - end_tm.tm_mday = start_tm.tm_mday; - end_tm.tm_hour = start_tm.tm_hour + 1; + * make it end one hour after the start. */ + if (end_tt.year < start_tt.year + || (end_tt.year == start_tt.year + && end_tt.month < start_tt.month) + || (end_tt.year == start_tt.year + && end_tt.month == start_tt.month + && end_tt.day <= start_tt.day)) { + end_tt.year = start_tt.year; + end_tt.month = start_tt.month; + end_tt.day = start_tt.day; + end_tt.hour = start_tt.hour; + icaltime_adjust (&end_tt, 0, 1, 0, 0); } } @@ -808,10 +881,15 @@ all_day_event_toggled_cb (GtkWidget *toggle, gpointer data) gtk_signal_handler_block_by_data (GTK_OBJECT (priv->end_time), epage); - start_t = mktime (&start_tm); - end_t = mktime (&end_tm); - e_date_edit_set_time (E_DATE_EDIT (priv->start_time), start_t); - e_date_edit_set_time (E_DATE_EDIT (priv->end_time), end_t); + e_date_edit_set_date (E_DATE_EDIT (priv->start_time), start_tt.year, + start_tt.month, start_tt.day); + e_date_edit_set_time_of_day (E_DATE_EDIT (priv->start_time), + start_tt.hour, start_tt.minute); + + e_date_edit_set_date (E_DATE_EDIT (priv->end_time), end_tt.year, + end_tt.month, end_tt.day); + e_date_edit_set_time_of_day (E_DATE_EDIT (priv->end_time), + end_tt.hour, end_tt.minute); gtk_signal_handler_unblock_by_data (GTK_OBJECT (priv->start_time), epage); @@ -822,9 +900,10 @@ all_day_event_toggled_cb (GtkWidget *toggle, gpointer data) e_date_edit_set_show_time (E_DATE_EDIT (priv->end_time), !all_day); /* Notify upstream */ - dates.start = start_t; - dates.end = end_t; - dates.due = 0; + dates.start = &start_tt; + dates.end = &end_tt; + dates.due = NULL; + dates.complete = NULL; comp_editor_page_notify_dates_changed (COMP_EDITOR_PAGE (epage), &dates); } @@ -868,6 +947,15 @@ init_widgets (EventPage *epage) priv = epage->priv; + /* Make sure the EDateEdit widgets use our timezones to get the + current time. */ + e_date_edit_set_get_time_callback (E_DATE_EDIT (priv->start_time), + (EDateEditGetTimeCallback) comp_editor_get_current_time, + epage, NULL); + e_date_edit_set_get_time_callback (E_DATE_EDIT (priv->end_time), + (EDateEditGetTimeCallback) comp_editor_get_current_time, + epage, NULL); + /* Summary */ gtk_signal_connect (GTK_OBJECT (priv->summary), "changed", GTK_SIGNAL_FUNC (summary_changed_cb), epage); diff --git a/calendar/gui/dialogs/meeting-page.c b/calendar/gui/dialogs/meeting-page.c index 2ef94bafff..566422aa9b 100644 --- a/calendar/gui/dialogs/meeting-page.c +++ b/calendar/gui/dialogs/meeting-page.c @@ -41,7 +41,7 @@ #include <widgets/misc/e-dateedit.h> #include <widgets/meeting-time-sel/e-meeting-time-sel.h> #include <e-util/e-dialog-widgets.h> -#include "../Evolution-Addressbook-SelectNames.h" +#include <addressbook/gui/component/select-names/Evolution-Addressbook-SelectNames.h> #include "comp-editor-util.h" #include "meeting-page.h" diff --git a/calendar/gui/dialogs/recurrence-page.c b/calendar/gui/dialogs/recurrence-page.c index e1656ad83f..4023cd6b5a 100644 --- a/calendar/gui/dialogs/recurrence-page.c +++ b/calendar/gui/dialogs/recurrence-page.c @@ -43,6 +43,10 @@ +/* We set this as the TZID on all exceptions added. When we actually fill + the component, we replace it with the TZID from DTSTART. */ +static char *DUMMY_TZID = "DUMMY"; + enum month_day_options { MONTH_DAY_NTH, MONTH_DAY_MON, @@ -287,10 +291,11 @@ free_exception_clist_data (RecurrencePage *rpage) GtkCList *clist = GTK_CLIST (priv->exception_list); for (i = 0; i < clist->rows; i++) { - gpointer data; + CalComponentDateTime *dt; - data = gtk_clist_get_row_data (clist, i); - g_free (data); + dt = gtk_clist_get_row_data (clist, i); + g_free (dt->value); + g_free (dt); gtk_clist_set_row_data (clist, i, NULL); } @@ -391,42 +396,58 @@ clear_widgets (RecurrencePage *rpage) /* Builds a static string out of an exception date */ static char * -get_exception_string (time_t t) +get_exception_string (CalComponentDateTime *dt) { static char buf[256]; + struct tm tmp_tm; + + tmp_tm.tm_year = dt->value->year - 1900; + tmp_tm.tm_mon = dt->value->month - 1; + tmp_tm.tm_mday = dt->value->day; + tmp_tm.tm_hour = dt->value->hour; + tmp_tm.tm_min = dt->value->minute; + tmp_tm.tm_sec = dt->value->second; + tmp_tm.tm_isdst = -1; - strftime (buf, sizeof (buf), _("%a %b %d %Y"), localtime (&t)); + strftime (buf, sizeof (buf), _("%a %b %d %Y"), &tmp_tm); return buf; } /* Appends an exception date to the list */ static void -append_exception (RecurrencePage *rpage, time_t t) +append_exception (RecurrencePage *rpage, CalComponentDateTime *datetime) { RecurrencePagePrivate *priv; - time_t *tt; + CalComponentDateTime *dt; char *c[1]; int i; GtkCList *clist; + struct icaltimetype *tt; priv = rpage->priv; - tt = g_new (time_t, 1); - *tt = t; + dt = g_new (CalComponentDateTime, 1); + dt->value = g_new (struct icaltimetype, 1); + *dt->value = *datetime->value; + dt->tzid = datetime->tzid; clist = GTK_CLIST (priv->exception_list); gtk_signal_handler_block_by_data (GTK_OBJECT (clist), rpage); - c[0] = get_exception_string (t); + c[0] = get_exception_string (dt); i = gtk_clist_append (clist, c); - gtk_clist_set_row_data (clist, i, tt); + gtk_clist_set_row_data (clist, i, dt); gtk_clist_select_row (clist, i, 0); gtk_signal_handler_unblock_by_data (GTK_OBJECT (clist), rpage); - e_date_edit_set_time (E_DATE_EDIT (priv->exception_date), t); + tt = dt->value; + e_date_edit_set_date (E_DATE_EDIT (priv->exception_date), + tt->year, tt->month, tt->day); + e_date_edit_set_time_of_day (E_DATE_EDIT (priv->exception_date), + tt->hour, tt->minute); gtk_widget_set_sensitive (priv->exception_modify, TRUE); gtk_widget_set_sensitive (priv->exception_delete, TRUE); @@ -448,13 +469,11 @@ fill_exception_widgets (RecurrencePage *rpage, CalComponent *comp) for (l = list; l; l = l->next) { CalComponentDateTime *cdt; - time_t ext; added = TRUE; cdt = l->data; - ext = icaltime_as_timet (*cdt->value); - append_exception (rpage, ext); + append_exception (rpage, cdt); } cal_component_free_exdate_list (list); @@ -475,13 +494,10 @@ get_start_weekday_mask (CalComponent *comp) cal_component_get_dtstart (comp, &dt); if (dt.value) { - time_t t; - struct tm tm; - - t = icaltime_as_timet (*dt.value); - tm = *localtime (&t); + short weekday; - retval = 0x1 << tm.tm_wday; + weekday = icaltime_day_of_week (*dt.value); + retval = 0x1 << (weekday - 1); } else retval = 0; @@ -575,6 +591,8 @@ simple_recur_to_comp (RecurrencePage *rpage, CalComponent *comp) struct icalrecurrencetype r; GSList l; enum ending_type ending_type; + gboolean date_set; + struct icaltimetype icaltime = icaltime_null_time (); priv = rpage->priv; @@ -716,9 +734,21 @@ simple_recur_to_comp (RecurrencePage *rpage, CalComponent *comp) g_assert (priv->ending_date_edit != NULL); g_assert (E_IS_DATE_EDIT (priv->ending_date_edit)); - r.until = icaltime_from_timet ( - e_date_edit_get_time (E_DATE_EDIT (priv->ending_date_edit)), - TRUE); + /* UNTIL must be in UTC, unless it is a date. So we probably + want to convert it to local time when showing. */ + icaltime.is_utc = 0; + icaltime.is_date = 1; + icaltime.is_daylight = 0; + + date_set = e_date_edit_get_date (E_DATE_EDIT (priv->ending_date_edit), + &r.until.year, + &r.until.month, + &r.until.day); + e_date_edit_get_time_of_day (E_DATE_EDIT (priv->ending_date_edit), + &r.until.hour, + &r.until.minute); + g_assert (date_set); + break; case ENDING_FOREVER: @@ -744,9 +774,11 @@ static void fill_component (RecurrencePage *rpage, CalComponent *comp) { RecurrencePagePrivate *priv; + CalComponentDateTime start_date; enum recur_type recur_type; GtkCList *exception_list; GSList *list; + const char *tzid; int i; priv = rpage->priv; @@ -776,19 +808,31 @@ fill_component (RecurrencePage *rpage, CalComponent *comp) /* Set exceptions */ + cal_component_get_dtstart (comp, &start_date); + tzid = start_date.tzid; + cal_component_free_datetime (&start_date); + list = NULL; exception_list = GTK_CLIST (priv->exception_list); for (i = 0; i < exception_list->rows; i++) { - CalComponentDateTime *cdt; - time_t *tim; + CalComponentDateTime *cdt, *dt; cdt = g_new (CalComponentDateTime, 1); cdt->value = g_new (struct icaltimetype, 1); - cdt->tzid = NULL; - tim = gtk_clist_get_row_data (exception_list, i); - g_assert (tim != NULL); - *cdt->value = icaltime_from_timet (*tim, FALSE); + dt = gtk_clist_get_row_data (exception_list, i); + g_assert (dt != NULL); + + *cdt->value = *dt->value; + + /* If the dummy TZID was used, we use the TZID from the + start date. We do this because we don't allow editing + of timezones for RDATEs, so we try to use the same timezone + as the DTSTART for all new exceptions added. */ + if (dt->tzid == DUMMY_TZID) + cdt->tzid = tzid; + else + cdt->tzid = dt->tzid; list = g_slist_prepend (list, cdt); } @@ -849,7 +893,8 @@ preview_recur (RecurrencePage *rpage) fill_component (rpage, comp); - tag_calendar_by_comp (E_CALENDAR (priv->preview_calendar), comp); + tag_calendar_by_comp (E_CALENDAR (priv->preview_calendar), comp, + COMP_EDITOR_PAGE (rpage)->client); gtk_object_unref (GTK_OBJECT (comp)); } @@ -1294,6 +1339,7 @@ fill_ending_date (RecurrencePage *rpage, struct icalrecurrencetype *r) } else { /* Ending date */ + /* FIXME: UNTIL needs to be checked. */ priv->ending_date = icaltime_as_timet (r->until); e_dialog_option_menu_set (priv->ending_menu, ENDING_UNTIL, @@ -1693,7 +1739,7 @@ recurrence_page_set_dates (CompEditorPage *page, CompEditorPageDates *dates) { RecurrencePage *rpage; RecurrencePagePrivate *priv; - CalComponentDateTime dt; + CalComponentDateTime dt, old_dt; struct icaltimetype icaltime; guint8 mask; @@ -1708,13 +1754,32 @@ recurrence_page_set_dates (CompEditorPage *page, CompEditorPageDates *dates) return; dt.value = &icaltime; - dt.tzid = NULL; - *dt.value = icaltime_from_timet (dates->start, FALSE); - cal_component_set_dtstart (priv->comp, &dt); + if (dates->start) { + icaltime = *dates->start; + + /* Copy the TZID from the old property. + FIXME: Should get notified when the TZID changes.*/ + cal_component_get_dtstart (priv->comp, &old_dt); + dt.tzid = NULL; + if (old_dt.tzid) + dt.tzid = old_dt.tzid; + cal_component_free_datetime (&old_dt); + + cal_component_set_dtstart (priv->comp, &dt); + } + + if (dates->end) { + icaltime = *dates->end; + + /* Copy the TZID from the old property. + FIXME: Should get notified when the TZID changes.*/ + cal_component_get_dtend (priv->comp, &old_dt); + dt.tzid = NULL; + if (old_dt.tzid) + dt.tzid = old_dt.tzid; + cal_component_free_datetime (&old_dt); - if (dates->end != 0) { - *dt.value = icaltime_from_timet (dates->end, FALSE); cal_component_set_dtend (priv->comp, &dt); } @@ -1876,15 +1941,32 @@ exception_add_cb (GtkWidget *widget, gpointer data) { RecurrencePage *rpage; RecurrencePagePrivate *priv; - time_t t; + CalComponentDateTime dt; + struct icaltimetype icaltime = icaltime_null_time (); + gboolean date_set; rpage = RECURRENCE_PAGE (data); priv = rpage->priv; field_changed (rpage); - t = e_date_edit_get_time (E_DATE_EDIT (priv->exception_date)); - append_exception (rpage, t); + dt.value = &icaltime; + /* We set this to the dummy TZID for now. When we fill the component + we will replace it with the TZID from DTSTART. */ + dt.tzid = DUMMY_TZID; + + icaltime.is_date = 1; + + date_set = e_date_edit_get_date (E_DATE_EDIT (priv->exception_date), + &icaltime.year, + &icaltime.month, + &icaltime.day); + e_date_edit_get_time_of_day (E_DATE_EDIT (priv->exception_date), + &icaltime.hour, + &icaltime.minute); + g_assert (date_set); + + append_exception (rpage, &dt); preview_recur (rpage); } @@ -1895,7 +1977,8 @@ exception_modify_cb (GtkWidget *widget, gpointer data) RecurrencePage *rpage; RecurrencePagePrivate *priv; GtkCList *clist; - time_t *t; + CalComponentDateTime *dt; + struct icaltimetype *tt; int sel; rpage = RECURRENCE_PAGE (data); @@ -1909,10 +1992,15 @@ exception_modify_cb (GtkWidget *widget, gpointer data) sel = GPOINTER_TO_INT (clist->selection->data); - t = gtk_clist_get_row_data (clist, sel); - *t = e_date_edit_get_time (E_DATE_EDIT (priv->exception_date)); + dt = gtk_clist_get_row_data (clist, sel); + tt = dt->value; + e_date_edit_get_date (E_DATE_EDIT (priv->exception_date), + &tt->year, &tt->month, &tt->day); + e_date_edit_get_time_of_day (E_DATE_EDIT (priv->exception_date), + &tt->hour, &tt->minute); + tt->second = 0; - gtk_clist_set_text (clist, sel, 0, get_exception_string (*t)); + gtk_clist_set_text (clist, sel, 0, get_exception_string (dt)); preview_recur (rpage); } @@ -1925,7 +2013,7 @@ exception_delete_cb (GtkWidget *widget, gpointer data) RecurrencePagePrivate *priv; GtkCList *clist; int sel; - time_t *t; + CalComponentDateTime *dt; rpage = RECURRENCE_PAGE (data); priv = rpage->priv; @@ -1938,9 +2026,10 @@ exception_delete_cb (GtkWidget *widget, gpointer data) sel = GPOINTER_TO_INT (clist->selection->data); - t = gtk_clist_get_row_data (clist, sel); - g_assert (t != NULL); - g_free (t); + dt = gtk_clist_get_row_data (clist, sel); + g_assert (dt != NULL); + g_free (dt->value); + g_free (dt); gtk_clist_remove (clist, sel); if (sel >= clist->rows) @@ -1966,15 +2055,21 @@ exception_select_row_cb (GtkCList *clist, gint row, gint col, { RecurrencePage *rpage; RecurrencePagePrivate *priv; - time_t *t; + CalComponentDateTime *dt; + struct icaltimetype *t; rpage = RECURRENCE_PAGE (data); priv = rpage->priv; - t = gtk_clist_get_row_data (clist, row); - g_assert (t != NULL); + dt = gtk_clist_get_row_data (clist, row); + g_assert (dt != NULL); - e_date_edit_set_time (E_DATE_EDIT (priv->exception_date), *t); + t = dt->value; + + e_date_edit_set_date (E_DATE_EDIT (priv->exception_date), + t->year, t->month, t->day); + e_date_edit_set_time_of_day (E_DATE_EDIT (priv->exception_date), + t->hour, t->minute); } /* This is called when any field is changed; it notifies upstream. */ @@ -2013,6 +2108,18 @@ init_widgets (RecurrencePage *rpage) priv->preview_calendar); gtk_widget_show (priv->preview_calendar); + /* Make sure the EDateEdit widgets and ECalendarItem use our timezones + to get the current time. */ + e_date_edit_set_get_time_callback (E_DATE_EDIT (priv->exception_date), + (EDateEditGetTimeCallback) comp_editor_get_current_time, + rpage, NULL); + e_date_edit_set_get_time_callback (E_DATE_EDIT (priv->ending_date_edit), + (EDateEditGetTimeCallback) comp_editor_get_current_time, + rpage, NULL); + e_calendar_item_set_get_time_callback (ecal->calitem, + (ECalendarItemGetTimeCallback) comp_editor_get_current_time, + rpage, NULL); + /* Recurrence types */ gtk_signal_connect (GTK_OBJECT (priv->none), "toggled", diff --git a/calendar/gui/dialogs/task-details-page.c b/calendar/gui/dialogs/task-details-page.c index 9a1a4b46c6..82d3e14b62 100644 --- a/calendar/gui/dialogs/task-details-page.c +++ b/calendar/gui/dialogs/task-details-page.c @@ -32,6 +32,7 @@ #include <gal/widgets/e-unicode.h> #include <widgets/misc/e-dateedit.h> #include "e-util/e-dialog-widgets.h" +#include "../calendar-config.h" #include "../e-timezone-entry.h" #include "comp-editor-util.h" #include "task-details-page.h" @@ -50,7 +51,6 @@ struct _TaskDetailsPagePrivate { GtkWidget *date_time; GtkWidget *completed_date; - GtkWidget *completed_timezone; GtkWidget *url; @@ -149,7 +149,6 @@ task_details_page_init (TaskDetailsPage *tdpage) priv->summary = NULL; priv->date_time = NULL; priv->completed_date = NULL; - priv->completed_timezone = NULL; priv->url = NULL; priv->updating = FALSE; @@ -277,30 +276,46 @@ task_details_page_fill_component (CompEditorPage *page, CalComponent *comp) { TaskDetailsPage *tdpage; TaskDetailsPagePrivate *priv; + struct icaltimetype icaltime; GSList list; CalComponentDateTime date; CalComponentOrganizer organizer; CalComponentAttendee attendee; - time_t t; char *url; + gboolean date_set; tdpage = TASK_DETAILS_PAGE (page); priv = tdpage->priv; - /* Completed Date. */ - date.value = g_new (struct icaltimetype, 1); - date.tzid = NULL; + /* COMPLETED must be in UTC. */ + icaltime.is_utc = 1; + icaltime.is_date = 0; + icaltime.is_daylight = 0; - t = e_date_edit_get_time (E_DATE_EDIT (priv->completed_date)); - if (t != -1) { - *date.value = icaltime_from_timet (t, FALSE); - cal_component_set_completed (comp, date.value); + /* Completed Date. */ + date_set = e_date_edit_get_date (E_DATE_EDIT (priv->completed_date), + &icaltime.year, + &icaltime.month, + &icaltime.day); + e_date_edit_get_time_of_day (E_DATE_EDIT (priv->completed_date), + &icaltime.hour, + &icaltime.minute); + if (date_set) { + /* COMPLETED must be in UTC, so we assume that the date in the + dialog is in the current timezone, and we now convert it + to UTC. FIXME: We should really use one timezone for the + entire time the dialog is shown. Otherwise if the user + changes the timezone, the COMPLETED date may get changed + as well. */ + char *location = calendar_config_get_timezone (); + icaltimezone *zone = icaltimezone_get_builtin_timezone (location); + icaltimezone_convert_time (&icaltime, zone, + icaltimezone_get_utc_timezone ()); + cal_component_set_completed (comp, &icaltime); } else { cal_component_set_completed (comp, NULL); } - g_free (date.value); - /* URL. */ url = e_dialog_editable_get (priv->url); cal_component_set_url (comp, url); @@ -359,9 +374,30 @@ task_details_page_set_dates (CompEditorPage *page, CompEditorPageDates *dates) priv = tdpage->priv; comp_editor_date_label (dates, priv->date_time); - if (dates->complete != 0) - e_date_edit_set_time (E_DATE_EDIT (priv->completed_date), - dates->complete); + + if (dates->complete) { + if (icaltime_is_null_time (*dates->complete)) { + e_date_edit_set_time (E_DATE_EDIT (priv->completed_date), -1); + } else { + struct icaltimetype *tt = dates->complete; + + /* Convert it from UTC to local time to display. + FIXME: We should really use one timezone for the + entire time the dialog is shown. Otherwise if the + user changes the timezone, the COMPLETED date may + get changed as well. */ + char *location = calendar_config_get_timezone (); + icaltimezone *zone = icaltimezone_get_builtin_timezone (location); + icaltimezone_convert_time (tt, + icaltimezone_get_utc_timezone (), + zone); + + e_date_edit_set_date (E_DATE_EDIT (priv->completed_date), + tt->year, tt->month, tt->day); + e_date_edit_set_time_of_day (E_DATE_EDIT (priv->completed_date), + tt->hour, tt->minute); + } + } } @@ -387,7 +423,6 @@ get_widgets (TaskDetailsPage *tdpage) priv->date_time = GW ("date-time"); priv->completed_date = GW ("completed-date"); - priv->completed_timezone = GW ("completed-timezone"); priv->url = GW ("url"); @@ -403,7 +438,6 @@ get_widgets (TaskDetailsPage *tdpage) return (priv->summary && priv->date_time && priv->completed_date - && priv->completed_timezone && priv->url && priv->organizer && priv->organizer_lbl @@ -422,6 +456,8 @@ date_changed_cb (EDateEdit *dedit, gpointer data) TaskDetailsPage *tdpage; TaskDetailsPagePrivate *priv; CompEditorPageDates dates; + struct icaltimetype completed_tt = icaltime_null_time(); + gboolean date_set; tdpage = TASK_DETAILS_PAGE (data); priv = tdpage->priv; @@ -429,10 +465,20 @@ date_changed_cb (EDateEdit *dedit, gpointer data) if (priv->updating) return; - dates.start = 0; - dates.end = 0; - dates.due = 0; - dates.complete = e_date_edit_get_time (E_DATE_EDIT (priv->completed_date)); + date_set = e_date_edit_get_date (E_DATE_EDIT (priv->completed_date), + &completed_tt.year, + &completed_tt.month, + &completed_tt.day); + e_date_edit_get_time_of_day (E_DATE_EDIT (priv->completed_date), + &completed_tt.hour, + &completed_tt.minute); + if (!date_set) + completed_tt = icaltime_null_time (); + + dates.start = NULL; + dates.end = NULL; + dates.due = NULL; + dates.complete = &completed_tt; /* Notify upstream */ comp_editor_page_notify_dates_changed (COMP_EDITOR_PAGE (tdpage), &dates); @@ -460,13 +506,16 @@ init_widgets (TaskDetailsPage *tdpage) priv = tdpage->priv; + /* Make sure the EDateEdit widgets use our timezones to get the + current time. */ + e_date_edit_set_get_time_callback (E_DATE_EDIT (priv->completed_date), + (EDateEditGetTimeCallback) comp_editor_get_current_time, + tdpage, NULL); + /* Completed Date */ gtk_signal_connect (GTK_OBJECT (priv->completed_date), "changed", GTK_SIGNAL_FUNC (date_changed_cb), tdpage); - gtk_signal_connect (GTK_OBJECT (priv->completed_timezone), "changed", - GTK_SIGNAL_FUNC (field_changed_cb), tdpage); - /* URL */ gtk_signal_connect (GTK_OBJECT (priv->url), "changed", GTK_SIGNAL_FUNC (field_changed_cb), tdpage); diff --git a/calendar/gui/dialogs/task-details-page.glade b/calendar/gui/dialogs/task-details-page.glade index 962906ebb4..c92bd52b8f 100644 --- a/calendar/gui/dialogs/task-details-page.glade +++ b/calendar/gui/dialogs/task-details-page.glade @@ -403,10 +403,12 @@ </widget> <widget> - <class>GtkHBox</class> - <name>hbox1</name> - <homogeneous>False</homogeneous> - <spacing>0</spacing> + <class>Custom</class> + <name>completed-date</name> + <creation_function>task_details_page_create_date_edit</creation_function> + <int1>0</int1> + <int2>0</int2> + <last_modification_time>Fri, 01 Jun 2001 18:58:51 GMT</last_modification_time> <child> <left_attach>1</left_attach> <right_attach>2</right_attach> @@ -421,34 +423,6 @@ <xfill>True</xfill> <yfill>True</yfill> </child> - - <widget> - <class>Custom</class> - <name>completed-date</name> - <creation_function>task_details_page_create_date_edit</creation_function> - <int1>0</int1> - <int2>0</int2> - <last_modification_time>Fri, 01 Jun 2001 18:58:51 GMT</last_modification_time> - <child> - <padding>0</padding> - <expand>True</expand> - <fill>True</fill> - </child> - </widget> - - <widget> - <class>Custom</class> - <name>completed-timezone</name> - <creation_function>make_timezone_entry</creation_function> - <int1>0</int1> - <int2>0</int2> - <last_modification_time>Tue, 19 Jun 2001 04:32:42 GMT</last_modification_time> - <child> - <padding>0</padding> - <expand>True</expand> - <fill>True</fill> - </child> - </widget> </widget> </widget> </widget> diff --git a/calendar/gui/dialogs/task-page.c b/calendar/gui/dialogs/task-page.c index 705477f794..2fc7bbf23e 100644 --- a/calendar/gui/dialogs/task-page.c +++ b/calendar/gui/dialogs/task-page.c @@ -254,19 +254,16 @@ static void clear_widgets (TaskPage *tpage) { TaskPagePrivate *priv; - time_t now; priv = tpage->priv; - now = time (NULL); - /* Summary, description */ e_dialog_editable_set (priv->summary, NULL); e_dialog_editable_set (priv->description, NULL); /* Start, due times */ - e_date_edit_set_time (E_DATE_EDIT (priv->start_date), now); - e_date_edit_set_time (E_DATE_EDIT (priv->due_date), now); + e_date_edit_set_time (E_DATE_EDIT (priv->start_date), 0); + e_date_edit_set_time (E_DATE_EDIT (priv->due_date), 0); /* Classification */ e_dialog_radio_set (priv->classification_public, @@ -341,12 +338,13 @@ task_page_fill_widgets (CompEditorPage *page, CalComponent *comp) CalComponentText text; CalComponentDateTime d; CalComponentClassification cl; + CalClientGetStatus get_tz_status; GSList *l; - time_t t; int *priority_value, *percent; icalproperty_status status; TaskEditorPriority priority; const char *categories; + icaltimezone *zone; tpage = TASK_PAGE (page); priv = tpage->priv; @@ -372,20 +370,50 @@ task_page_fill_widgets (CompEditorPage *page, CalComponent *comp) /* Due Date. */ cal_component_get_due (comp, &d); if (d.value) { - t = icaltime_as_timet (*d.value); + struct icaltimetype *due_tt = d.value; + e_date_edit_set_date (E_DATE_EDIT (priv->due_date), + due_tt->year, due_tt->month, + due_tt->day); + e_date_edit_set_time_of_day (E_DATE_EDIT (priv->due_date), + due_tt->hour, due_tt->minute); } else { - t = -1; + e_date_edit_set_time (E_DATE_EDIT (priv->due_date), -1); } - e_date_edit_set_time (E_DATE_EDIT (priv->due_date), t); + + get_tz_status = cal_client_get_timezone (page->client, d.tzid, &zone); + /* FIXME: Handle error better. */ + if (get_tz_status != CAL_CLIENT_GET_SUCCESS) + g_warning ("Couldn't get timezone from server: %s", + d.tzid ? d.tzid : ""); + e_timezone_entry_set_timezone (E_TIMEZONE_ENTRY (priv->due_timezone), + zone); + + cal_component_free_datetime (&d); + /* Start Date. */ cal_component_get_dtstart (comp, &d); if (d.value) { - t = icaltime_as_timet (*d.value); + struct icaltimetype *start_tt = d.value; + e_date_edit_set_date (E_DATE_EDIT (priv->start_date), + start_tt->year, start_tt->month, + start_tt->day); + e_date_edit_set_time_of_day (E_DATE_EDIT (priv->start_date), + start_tt->hour, start_tt->minute); } else { - t = -1; + e_date_edit_set_time (E_DATE_EDIT (priv->start_date), -1); } - e_date_edit_set_time (E_DATE_EDIT (priv->start_date), t); + + get_tz_status = cal_client_get_timezone (page->client, d.tzid, &zone); + /* FIXME: Handle error better. */ + if (get_tz_status != CAL_CLIENT_GET_SUCCESS) + g_warning ("Couldn't get timezone from server: %s", + d.tzid ? d.tzid : ""); + e_timezone_entry_set_timezone (E_TIMEZONE_ENTRY (priv->start_timezone), + zone); + + cal_component_free_datetime (&d); + /* Percent Complete. */ cal_component_get_percent (comp, &percent); @@ -460,12 +488,14 @@ task_page_fill_component (CompEditorPage *page, CalComponent *comp) TaskPage *tpage; TaskPagePrivate *priv; CalComponentDateTime date; - time_t t; + struct icaltimetype icaltime; icalproperty_status status; TaskEditorPriority priority; int priority_value, percent; char *cat; char *str; + gboolean date_set; + icaltimezone *zone; tpage = TASK_PAGE (page); priv = tpage->priv; @@ -509,22 +539,44 @@ task_page_fill_component (CompEditorPage *page, CalComponent *comp) /* Dates */ - date.value = g_new (struct icaltimetype, 1); + date.value = &icaltime; date.tzid = NULL; + icaltime.is_utc = 0; + /* FIXME: We should use is_date at some point. */ + icaltime.is_date = 0; + icaltime.is_daylight = 0; + icaltime.second = 0; + /* Due Date. */ - t = e_date_edit_get_time (E_DATE_EDIT (priv->due_date)); - if (t != -1) { - *date.value = icaltime_from_timet (t, FALSE); + date_set = e_date_edit_get_date (E_DATE_EDIT (priv->due_date), + &icaltime.year, + &icaltime.month, + &icaltime.day); + e_date_edit_get_time_of_day (E_DATE_EDIT (priv->due_date), + &icaltime.hour, + &icaltime.minute); + if (date_set) { + zone = e_timezone_entry_get_timezone (E_TIMEZONE_ENTRY (priv->due_timezone)); + if (zone) + date.tzid = icaltimezone_get_tzid (zone); cal_component_set_due (comp, &date); } else { cal_component_set_due (comp, NULL); } /* Start Date. */ - t = e_date_edit_get_time (E_DATE_EDIT (priv->start_date)); - if (t != -1) { - *date.value = icaltime_from_timet (t, FALSE); + date_set = e_date_edit_get_date (E_DATE_EDIT (priv->start_date), + &icaltime.year, + &icaltime.month, + &icaltime.day); + e_date_edit_get_time_of_day (E_DATE_EDIT (priv->start_date), + &icaltime.hour, + &icaltime.minute); + if (date_set) { + zone = e_timezone_entry_get_timezone (E_TIMEZONE_ENTRY (priv->start_timezone)); + if (zone) + date.tzid = icaltimezone_get_tzid (zone); cal_component_set_dtstart (comp, &date); } else { cal_component_set_dtstart (comp, NULL); @@ -583,8 +635,8 @@ task_page_set_dates (CompEditorPage *page, CompEditorPageDates *dates) priv->updating = TRUE; - if (dates->complete != 0) { - if (dates->complete == -1) { + if (dates->complete) { + if (icaltime_is_null_time (*dates->complete)) { /* If the 'Completed Date' is set to 'None', we set the status to 'Not Started' and the percent-complete to 0. The task may @@ -698,6 +750,9 @@ date_changed_cb (EDateEdit *dedit, gpointer data) TaskPage *tpage; TaskPagePrivate *priv; CompEditorPageDates dates; + gboolean date_set; + struct icaltimetype start_tt = icaltime_null_time(); + struct icaltimetype due_tt = icaltime_null_time(); tpage = TASK_PAGE (data); priv = tpage->priv; @@ -705,10 +760,30 @@ date_changed_cb (EDateEdit *dedit, gpointer data) if (priv->updating) return; - dates.start = e_date_edit_get_time (E_DATE_EDIT (priv->start_date)); - dates.end = 0; - dates.due = e_date_edit_get_time (E_DATE_EDIT (priv->due_date)); - dates.complete = 0; + date_set = e_date_edit_get_date (E_DATE_EDIT (priv->start_date), + &start_tt.year, + &start_tt.month, + &start_tt.day); + e_date_edit_get_time_of_day (E_DATE_EDIT (priv->start_date), + &start_tt.hour, + &start_tt.minute); + if (!date_set) + start_tt = icaltime_null_time (); + + date_set = e_date_edit_get_date (E_DATE_EDIT (priv->due_date), + &due_tt.year, + &due_tt.month, + &due_tt.day); + e_date_edit_get_time_of_day (E_DATE_EDIT (priv->due_date), + &due_tt.hour, + &due_tt.minute); + if (!date_set) + due_tt = icaltime_null_time (); + + dates.start = &start_tt; + dates.end = NULL; + dates.due = &due_tt; + dates.complete = NULL; /* Notify upstream */ comp_editor_page_notify_dates_changed (COMP_EDITOR_PAGE (tpage), @@ -747,17 +822,24 @@ field_changed_cb (GtkWidget *widget, gpointer data) } static void -complete_date_changed (TaskPage *tpage, time_t complete) +complete_date_changed (TaskPage *tpage, gboolean complete) { TaskPagePrivate *priv; CompEditorPageDates dates; + icaltimezone *zone; + struct icaltimetype completed_tt = icaltime_null_time(); priv = tpage->priv; - dates.start = 0; - dates.end = 0; - dates.due = 0; - dates.complete = complete; + /* Get the current time in UTC. */ + zone = icaltimezone_get_utc_timezone (); + completed_tt = icaltime_from_timet_with_zone (time (NULL), FALSE, zone); + completed_tt.is_utc = TRUE; + + dates.start = NULL; + dates.end = NULL; + dates.due = NULL; + dates.complete = &completed_tt; /* Notify upstream */ comp_editor_page_notify_dates_changed (COMP_EDITOR_PAGE (tpage), @@ -780,13 +862,13 @@ status_changed (GtkMenu *menu, TaskPage *tpage) status = e_dialog_option_menu_get (priv->status, status_map); if (status == ICAL_STATUS_NEEDSACTION) { e_dialog_spin_set (priv->percent_complete, 0); - complete_date_changed (tpage, -1); + complete_date_changed (tpage, FALSE); } else if (status == ICAL_STATUS_INPROCESS) { e_dialog_spin_set (priv->percent_complete, 50); - complete_date_changed (tpage, -1); + complete_date_changed (tpage, FALSE); } else if (status == ICAL_STATUS_COMPLETED) { e_dialog_spin_set (priv->percent_complete, 100); - complete_date_changed (tpage, time (NULL) - (time (NULL) % 60)); + complete_date_changed (tpage, TRUE); } priv->updating = FALSE; @@ -800,7 +882,7 @@ percent_complete_changed (GtkAdjustment *adj, TaskPage *tpage) TaskPagePrivate *priv; gint percent; icalproperty_status status; - time_t date_completed; + gboolean complete; priv = tpage->priv; @@ -811,10 +893,10 @@ percent_complete_changed (GtkAdjustment *adj, TaskPage *tpage) percent = e_dialog_spin_get_int (priv->percent_complete); if (percent == 100) { - date_completed = time (NULL); + complete = TRUE; status = ICAL_STATUS_COMPLETED; } else { - date_completed = -1; + complete = FALSE; if (percent == 0) status = ICAL_STATUS_NEEDSACTION; @@ -823,7 +905,7 @@ percent_complete_changed (GtkAdjustment *adj, TaskPage *tpage) } e_dialog_option_menu_set (priv->status, status, status_map); - complete_date_changed (tpage, date_completed); + complete_date_changed (tpage, complete); priv->updating = FALSE; @@ -839,6 +921,14 @@ init_widgets (TaskPage *tpage) priv = tpage->priv; + /* Make sure the EDateEdit widgets use our timezones to get the + current time. */ + e_date_edit_set_get_time_callback (E_DATE_EDIT (priv->start_date), + (EDateEditGetTimeCallback) comp_editor_get_current_time, + tpage, NULL); + e_date_edit_set_get_time_callback (E_DATE_EDIT (priv->due_date), + (EDateEditGetTimeCallback) comp_editor_get_current_time, + tpage, NULL); /* Summary */ gtk_signal_connect (GTK_OBJECT (priv->summary), "changed", diff --git a/calendar/gui/e-calendar-table.c b/calendar/gui/e-calendar-table.c index 931c721dd4..9f5726b01e 100644 --- a/calendar/gui/e-calendar-table.c +++ b/calendar/gui/e-calendar-table.c @@ -40,6 +40,7 @@ #include <gal/e-table/e-cell-combo.h> #include <widgets/misc/e-cell-date-edit.h> #include "e-calendar-table.h" +#include "calendar-config.h" #include "calendar-model.h" #include "dialogs/delete-comp.h" #include "dialogs/task-editor.h" @@ -107,6 +108,8 @@ static void selection_get (GtkWidget *invisible, ECalendarTable *cal_table); static void invisible_destroyed (GtkWidget *invisible, ECalendarTable *cal_table); +static struct tm e_calendar_table_get_current_time (ECellDateEdit *ecde, + gpointer data); /* The icons to represent the task. */ @@ -396,6 +399,10 @@ e_calendar_table_init (ECalendarTable *cal_table) e_table_extras_add_cell (extras, "dateedit", popup_cell); cal_table->dates_cell = E_CELL_DATE_EDIT (popup_cell); + e_cell_date_edit_set_get_time_callback (E_CELL_DATE_EDIT (popup_cell), + e_calendar_table_get_current_time, + cal_table, NULL); + /* * Combo fields. @@ -1281,3 +1288,33 @@ selection_received (GtkWidget *invisible, gtk_object_unref (GTK_OBJECT (comp)); } } + + +/* Returns the current time, for the ECellDateEdit items. + FIXME: Should probably use the timezone of the item rather than the + current timezone, though that may be difficult to get from here. */ +static struct tm +e_calendar_table_get_current_time (ECellDateEdit *ecde, gpointer data) +{ + char *location; + icaltimezone *zone; + struct tm tmp_tm = { 0 }; + struct icaltimetype tt; + + /* Get the current timezone. */ + location = calendar_config_get_timezone (); + zone = icaltimezone_get_builtin_timezone (location); + + tt = icaltime_from_timet_with_zone (time (NULL), FALSE, zone); + + /* Now copy it to the struct tm and return it. */ + 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; + + return tmp_tm; +} diff --git a/calendar/gui/e-day-view-main-item.c b/calendar/gui/e-day-view-main-item.c index 661f62b702..cc6224987a 100644 --- a/calendar/gui/e-day-view-main-item.c +++ b/calendar/gui/e-day-view-main-item.c @@ -192,7 +192,8 @@ e_day_view_main_item_draw (GnomeCanvasItem *canvas_item, GdkDrawable *drawable, gint work_day_start_y, work_day_end_y; gint day_x, day_w, work_day; gint start_row, end_row, rect_x, rect_y, rect_width, rect_height; - struct tm *day_start; + struct icaltimetype day_start_tt; + gint weekday; #if 0 g_print ("In e_day_view_main_item_draw %i,%i %ix%i\n", @@ -213,9 +214,10 @@ e_day_view_main_item_draw (GnomeCanvasItem *canvas_item, GdkDrawable *drawable, work_day_end_y = work_day_end_row * day_view->row_height - y; for (day = 0; day < day_view->days_shown; day++) { - day_start = localtime (&day_view->day_starts[day]); - - work_day = day_view->working_days & (1 << day_start->tm_wday); + day_start_tt = icaltime_from_timet_with_zone (day_view->day_starts[day], FALSE, day_view->zone); + weekday = icaltime_day_of_week (day_start_tt) - 1; + + work_day = day_view->working_days & (1 << weekday); day_x = day_view->day_offsets[day] - x; day_w = day_view->day_widths[day]; diff --git a/calendar/gui/e-day-view-top-item.c b/calendar/gui/e-day-view-top-item.c index 7f2e8663af..62e58f7ec5 100644 --- a/calendar/gui/e-day-view-top-item.c +++ b/calendar/gui/e-day-view-top-item.c @@ -192,7 +192,8 @@ e_day_view_top_item_draw (GnomeCanvasItem *canvas_item, GdkFont *font; gint canvas_width, canvas_height, left_edge, day, date_width, date_x; gint item_height, event_num; - struct tm *day_start; + struct tm day_start = { 0 }; + struct icaltimetype day_start_tt; #if 0 g_print ("In e_day_view_top_item_draw %i,%i %ix%i\n", @@ -267,7 +268,11 @@ e_day_view_top_item_draw (GnomeCanvasItem *canvas_item, /* Draw the date. Set a clipping rectangle so we don't draw over the next day. */ for (day = 0; day < day_view->days_shown; day++) { - day_start = localtime (&day_view->day_starts[day]); + day_start_tt = icaltime_from_timet_with_zone (day_view->day_starts[day], FALSE, day_view->zone); + day_start.tm_year = day_start_tt.year - 1900; + day_start.tm_mon = day_start_tt.month - 1; + day_start.tm_mday = day_start_tt.day; + day_start.tm_isdst = -1; if (day_view->date_format == E_DAY_VIEW_DATE_FULL) /* strftime format %A = full weekday name, %d = day of month, @@ -284,7 +289,7 @@ e_day_view_top_item_draw (GnomeCanvasItem *canvas_item, else format = "%d"; - strftime (buffer, sizeof (buffer), format, day_start); + strftime (buffer, sizeof (buffer), format, &day_start); clip_rect.x = day_view->day_offsets[day] - x; clip_rect.y = 2 - y; diff --git a/calendar/gui/e-day-view.c b/calendar/gui/e-day-view.c index 38623cdc6d..0cf6704798 100644 --- a/calendar/gui/e-day-view.c +++ b/calendar/gui/e-day-view.c @@ -511,6 +511,8 @@ e_day_view_init (EDayView *day_view) day_view->work_week_view = FALSE; day_view->days_shown = 1; + day_view->zone = NULL; + day_view->mins_per_row = 30; day_view->date_format = E_DAY_VIEW_DATE_FULL; day_view->rows_in_top_display = 0; @@ -1483,8 +1485,8 @@ query_obj_updated_cb (CalQuery *query, const char *uid, /* Add the occurrences of the event. */ cal_recur_generate_instances (comp, day_view->lower, day_view->upper, - e_day_view_add_event, - day_view); + e_day_view_add_event, day_view, + cal_client_resolve_tzid, day_view->client); gtk_object_unref (GTK_OBJECT (comp)); e_day_view_check_layout (day_view); @@ -2496,6 +2498,48 @@ e_day_view_set_show_event_end_times (EDayView *day_view, } +/* The current timezone. */ +icaltimezone* +e_day_view_get_timezone (EDayView *day_view) +{ + g_return_val_if_fail (E_IS_DAY_VIEW (day_view), NULL); + + return day_view->zone; +} + + +void +e_day_view_set_timezone (EDayView *day_view, + icaltimezone *zone) +{ + icaltimezone *old_zone; + struct icaltimetype tt; + time_t lower; + + g_return_if_fail (E_IS_DAY_VIEW (day_view)); + + old_zone = day_view->zone; + if (old_zone == zone) + return; + + day_view->zone = zone; + + /* If our time hasn't been set yet, just return. */ + if (day_view->lower == 0 && day_view->upper == 0) + return; + + /* Recalculate the new start of the first day. We just use exactly + the same time, but with the new timezone. */ + tt = icaltime_from_timet_with_zone (day_view->lower, FALSE, + old_zone); + + lower = icaltime_as_timet_with_zone (tt, zone); + + e_day_view_recalc_day_starts (day_view, lower); + update_query (day_view); +} + + /* This is a callback used to update all day event labels. */ static gboolean e_day_view_set_show_times_cb (EDayView *day_view, @@ -3413,7 +3457,7 @@ e_day_view_on_delete_occurrence (GtkWidget *widget, gpointer data) /* We must duplicate the CalComponent, or we won't know it has changed when we get the "update_event" callback. */ comp = cal_component_clone (event->comp); - cal_comp_util_add_exdate (comp, icaltime_from_timet (event->start, FALSE)); + cal_comp_util_add_exdate (comp, event->start, day_view->zone); if (!cal_client_update_object (day_view->client, comp)) g_message ("e_day_view_on_delete_occurrence(): Could not update the object!"); @@ -3525,7 +3569,7 @@ e_day_view_on_unrecur_appointment (GtkWidget *widget, gpointer data) instance. */ comp = cal_component_clone (event->comp); - cal_comp_util_add_exdate (comp, icaltime_from_timet (event->start, FALSE)); + cal_comp_util_add_exdate (comp, event->start, day_view->zone); /* For the unrecurred instance we duplicate the original object, create a new uid for it, get rid of the recurrence rules, and set @@ -3538,13 +3582,16 @@ e_day_view_on_unrecur_appointment (GtkWidget *widget, gpointer data) cal_component_set_exrule_list (new_comp, NULL); date.value = &itt; - date.tzid = NULL; + date.tzid = icaltimezone_get_tzid (day_view->zone); - *date.value = icaltime_from_timet (event->start, FALSE); + *date.value = icaltime_from_timet_with_zone (event->start, FALSE, + day_view->zone); cal_component_set_dtstart (new_comp, &date); - *date.value = icaltime_from_timet (event->end, FALSE); + *date.value = icaltime_from_timet_with_zone (event->end, FALSE, + day_view->zone); cal_component_set_dtend (new_comp, &date); + /* Now update both CalComponents. Note that we do this last since at * present the updates happen synchronously so our event may disappear. */ @@ -4064,15 +4111,19 @@ e_day_view_finish_long_event_resize (EDayView *day_view) comp = cal_component_clone (event->comp); date.value = &itt; - date.tzid = NULL; + /* FIXME: Should probably keep the timezone of the original start + and end times. */ + date.tzid = icaltimezone_get_tzid (day_view->zone); if (day_view->resize_drag_pos == E_DAY_VIEW_POS_LEFT_EDGE) { dt = day_view->day_starts[day_view->resize_start_row]; - *date.value = icaltime_from_timet (dt, FALSE); + *date.value = icaltime_from_timet_with_zone (dt, FALSE, + day_view->zone); cal_component_set_dtstart (comp, &date); } else { dt = day_view->day_starts[day_view->resize_end_row + 1]; - *date.value = icaltime_from_timet (dt, FALSE); + *date.value = icaltime_from_timet_with_zone (dt, FALSE, + day_view->zone); cal_component_set_dtend (comp, &date); } @@ -4110,15 +4161,19 @@ e_day_view_finish_resize (EDayView *day_view) comp = cal_component_clone (event->comp); date.value = &itt; - date.tzid = NULL; + /* FIXME: Should probably keep the timezone of the original start + and end times. */ + date.tzid = icaltimezone_get_tzid (day_view->zone); if (day_view->resize_drag_pos == E_DAY_VIEW_POS_TOP_EDGE) { dt = e_day_view_convert_grid_position_to_time (day_view, day, day_view->resize_start_row); - *date.value = icaltime_from_timet (dt, FALSE); + *date.value = icaltime_from_timet_with_zone (dt, FALSE, + day_view->zone); cal_component_set_dtstart (comp, &date); } else { dt = e_day_view_convert_grid_position_to_time (day_view, day, day_view->resize_end_row + 1); - *date.value = icaltime_from_timet (dt, FALSE); + *date.value = icaltime_from_timet_with_zone (dt, FALSE, + day_view->zone); cal_component_set_dtend (comp, &date); } @@ -4226,7 +4281,7 @@ e_day_view_add_event (CalComponent *comp, EDayView *day_view; EDayViewEvent event; gint day, offset; - struct tm start_tm, end_tm; + struct icaltimetype start_tt, end_tt; day_view = E_DAY_VIEW (data); @@ -4242,8 +4297,10 @@ e_day_view_add_event (CalComponent *comp, g_return_val_if_fail (start < day_view->upper, TRUE); g_return_val_if_fail (end > day_view->lower, TRUE); - start_tm = *(localtime (&start)); - end_tm = *(localtime (&end)); + start_tt = icaltime_from_timet_with_zone (start, FALSE, + day_view->zone); + end_tt = icaltime_from_timet_with_zone (end, FALSE, + day_view->zone); event.comp = comp; gtk_object_ref (GTK_OBJECT (comp)); @@ -4255,8 +4312,8 @@ e_day_view_add_event (CalComponent *comp, display. */ offset = day_view->first_hour_shown * 60 + day_view->first_minute_shown; - event.start_minute = start_tm.tm_hour * 60 + start_tm.tm_min - offset; - event.end_minute = end_tm.tm_hour * 60 + end_tm.tm_min - offset; + event.start_minute = start_tt.hour * 60 + start_tt.minute - offset; + event.end_minute = end_tt.hour * 60 + end_tt.minute - offset; event.start_row_or_col = -1; event.num_columns = -1; @@ -4836,12 +4893,14 @@ e_day_view_key_press (GtkWidget *widget, GdkEventKey *event) e_day_view_get_selected_time_range (day_view, &dtstart, &dtend); dt.value = &itt; - dt.tzid = NULL; + dt.tzid = icaltimezone_get_tzid (day_view->zone); - *dt.value = icaltime_from_timet (dtstart, FALSE); + *dt.value = icaltime_from_timet_with_zone (dtstart, FALSE, + day_view->zone); cal_component_set_dtstart (comp, &dt); - *dt.value = icaltime_from_timet (dtend, FALSE); + *dt.value = icaltime_from_timet_with_zone (dtend, FALSE, + day_view->zone); cal_component_set_dtend (comp, &dt); /* We add the event locally and start editing it. When we get the @@ -5383,7 +5442,7 @@ e_day_view_convert_grid_position_to_time (EDayView *day_view, gint col, gint row) { - struct tm *tmp_tm; + struct icaltimetype tt; time_t val; gint minutes; @@ -5397,15 +5456,15 @@ e_day_view_convert_grid_position_to_time (EDayView *day_view, if (minutes == 60 * 24) return day_view->day_starts[col + 1]; - /* We convert the start of the day to a struct tm, then set the - hour and minute, then convert it back to a time_t. */ - tmp_tm = localtime (&day_view->day_starts[col]); + /* Create an icaltimetype and convert to a time_t. */ + tt = icaltime_from_timet_with_zone (day_view->day_starts[col], + FALSE, day_view->zone); + tt.hour = minutes / 60; + tt.minute = minutes % 60; + tt.second = 0; + tt.is_daylight = -1; - tmp_tm->tm_hour = minutes / 60; - tmp_tm->tm_min = minutes % 60; - tmp_tm->tm_isdst = -1; - - val = mktime (tmp_tm); + val = icaltime_as_timet_with_zone (tt, day_view->zone); return val; } @@ -5416,7 +5475,7 @@ e_day_view_convert_time_to_grid_position (EDayView *day_view, gint *col, gint *row) { - struct tm *tmp_tm; + struct icaltimetype tt; gint day, minutes; *col = *row = 0; @@ -5432,11 +5491,12 @@ e_day_view_convert_time_to_grid_position (EDayView *day_view, } } - /* To find the row we need to convert the time to a struct tm, + /* To find the row we need to convert the time to an icaltimetype, calculate the offset in minutes from the top of the display and divide it by the mins per row setting. */ - tmp_tm = localtime (&time); - minutes = tmp_tm->tm_hour * 60 + tmp_tm->tm_min; + tt = icaltime_from_timet_with_zone (time, FALSE, day_view->zone); + + minutes = tt.hour * 60 + tt.minute; minutes -= day_view->first_hour_shown * 60 + day_view->first_minute_shown; @@ -6354,16 +6414,20 @@ e_day_view_on_top_canvas_drag_data_received (GtkWidget *widget, comp = cal_component_clone (event->comp); date.value = &itt; - date.tzid = NULL; + /* FIXME: Should probably keep the timezone of the + original start and end times. */ + date.tzid = icaltimezone_get_tzid (day_view->zone); dt = day_view->day_starts[day] + start_offset * 60; - *date.value = icaltime_from_timet (dt, FALSE); + *date.value = icaltime_from_timet_with_zone (dt, FALSE, + day_view->zone); cal_component_set_dtstart (comp, &date); if (end_offset == -1 || end_offset == 0) dt = day_view->day_starts[day + num_days]; else dt = day_view->day_starts[day + num_days - 1] + end_offset * 60; - *date.value = icaltime_from_timet (dt, FALSE); + *date.value = icaltime_from_timet_with_zone (dt, FALSE, + day_view->zone); cal_component_set_dtend (comp, &date); gtk_drag_finish (context, TRUE, TRUE, time); @@ -6458,13 +6522,15 @@ e_day_view_on_main_canvas_drag_data_received (GtkWidget *widget, comp = cal_component_clone (event->comp); date.value = &itt; - date.tzid = NULL; + date.tzid = icaltimezone_get_tzid (day_view->zone); dt = e_day_view_convert_grid_position_to_time (day_view, day, row) + start_offset * 60; - *date.value = icaltime_from_timet (dt, FALSE); + *date.value = icaltime_from_timet_with_zone (dt, FALSE, + day_view->zone); cal_component_set_dtstart (comp, &date); dt = e_day_view_convert_grid_position_to_time (day_view, day, row + num_rows) - end_offset * 60; - *date.value = icaltime_from_timet (dt, FALSE); + *date.value = icaltime_from_timet_with_zone (dt, FALSE, + day_view->zone); cal_component_set_dtend (comp, &date); gtk_drag_finish (context, TRUE, TRUE, time); @@ -6595,10 +6661,14 @@ selection_received (GtkWidget *invisible, if (icalcomp) { e_day_view_get_selected_time_range (day_view, &dtstart, &dtend); - itime = icaltime_from_timet (dtstart, FALSE); + itime = icaltime_from_timet_with_zone (dtstart, FALSE, + day_view->zone); + /* FIXME: Need to set TZID. */ icalcomponent_set_dtstart (icalcomp, itime); - itime = icaltime_from_timet (dtend, FALSE); + itime = icaltime_from_timet_with_zone (dtend, FALSE, + day_view->zone); + /* FIXME: Need to set TZID. */ icalcomponent_set_dtend (icalcomp, itime); comp = cal_component_new (); diff --git a/calendar/gui/e-day-view.h b/calendar/gui/e-day-view.h index 2d3f5104fb..94354244ba 100644 --- a/calendar/gui/e-day-view.h +++ b/calendar/gui/e-day-view.h @@ -254,6 +254,8 @@ struct _EDayView /* The start of each day & an extra element to hold the last time. */ time_t day_starts[E_DAY_VIEW_MAX_DAYS + 1]; + /* The timezone. */ + icaltimezone *zone; /* An array of EDayViewEvent elements for the top view and each day. */ GArray *long_events; @@ -561,6 +563,12 @@ gint e_day_view_get_week_start_day (EDayView *day_view); void e_day_view_set_week_start_day (EDayView *day_view, gint week_start_day); +/* The current timezone. */ +icaltimezone* e_day_view_get_timezone (EDayView *day_view); +void e_day_view_set_timezone (EDayView *day_view, + icaltimezone *zone); + + /* Clipboard-related functions */ void e_day_view_cut_clipboard (EDayView *day_view); void e_day_view_copy_clipboard (EDayView *day_view); diff --git a/calendar/gui/e-itip-control.c b/calendar/gui/e-itip-control.c index 24717b0aa7..3d82632adc 100644 --- a/calendar/gui/e-itip-control.c +++ b/calendar/gui/e-itip-control.c @@ -502,6 +502,7 @@ write_label_piece (time_t t, char *buffer, int size, char *stext, char *etext) struct tm *tmp_tm; int len; + /* FIXME: Convert to an appropriate timezone. */ tmp_tm = localtime (&t); if (stext != NULL) strcat (buffer, stext); @@ -522,6 +523,7 @@ set_date_label (GtkWidget *lbl, CalComponent *comp) time_t start = 0, end = 0, complete = 0, due = 0; static char buffer[1024]; + /* FIXME: timezones. */ cal_component_get_dtstart (comp, &datetime); if (datetime.value) start = icaltime_as_timet (*datetime.value); @@ -905,6 +907,7 @@ send_freebusy (EItipControl *itip) priv = itip->priv; + /* FIXME: timezones. */ cal_component_get_dtstart (priv->comp, &datetime); start = icaltime_as_timet (*datetime.value); cal_component_get_dtend (priv->comp, &datetime); diff --git a/calendar/gui/e-timezone-entry.c b/calendar/gui/e-timezone-entry.c index ff54a92da4..e7e64f0934 100644 --- a/calendar/gui/e-timezone-entry.c +++ b/calendar/gui/e-timezone-entry.c @@ -40,6 +40,17 @@ struct _ETimezoneEntryPrivate { + /* This is the timezone set in e_timezone_entry_set_timezone(). + Note that we don't copy it or use a ref count - we assume it is + never destroyed for the lifetime of this widget. */ + icaltimezone *zone; + + /* This is TRUE if the timezone has been changed since being set. + If it hasn't, we can just return zone, If it has, we return the + builtin timezone with tzid. (It can only be changed to a builtin + timezone, or to 'local time', i.e. no timezone.) */ + gboolean changed; + GtkWidget *entry; GtkWidget *button; }; @@ -60,6 +71,8 @@ static void on_entry_changed (GtkEntry *entry, static void on_button_clicked (GtkWidget *widget, ETimezoneEntry *tentry); +static char* e_timezone_entry_get_display_name (icaltimezone *zone); + static GtkHBoxClass *parent_class; static guint timezone_entry_signals[LAST_SIGNAL] = { 0 }; @@ -127,6 +140,9 @@ e_timezone_entry_init (ETimezoneEntry *tentry) tentry->priv = priv = g_new0 (ETimezoneEntryPrivate, 1); + priv->zone = NULL; + priv->changed = FALSE; + priv->entry = gtk_entry_new (); gtk_entry_set_editable (GTK_ENTRY (priv->entry), FALSE); /*gtk_widget_set_usize (priv->date_entry, 90, 0);*/ @@ -190,19 +206,33 @@ on_button_clicked (GtkWidget *widget, ETimezoneEntryPrivate *priv; ETimezoneDialog *timezone_dialog; GtkWidget *dialog; - char *zone; + char *tzid = NULL, *display_name, *old_display_name; priv = tentry->priv; + display_name = gtk_entry_get_text (GTK_ENTRY (priv->entry)); + + if (priv->zone) + tzid = icaltimezone_get_tzid (priv->zone); + timezone_dialog = e_timezone_dialog_new (); - zone = e_timezone_entry_get_timezone (tentry); - e_timezone_dialog_set_timezone (timezone_dialog, zone); + e_timezone_dialog_set_timezone (timezone_dialog, tzid, display_name); dialog = e_timezone_dialog_get_toplevel (timezone_dialog); if (gnome_dialog_run_and_close (GNOME_DIALOG (dialog)) == 0) { - zone = e_timezone_dialog_get_timezone (E_TIMEZONE_DIALOG (timezone_dialog)); - e_timezone_entry_set_timezone (tentry, zone); + tzid = e_timezone_dialog_get_timezone (E_TIMEZONE_DIALOG (timezone_dialog), &display_name); + old_display_name = gtk_entry_get_text (GTK_ENTRY (priv->entry)); + /* See if the timezone has been changed. It can only have been + changed to a builtin timezone, in which case the returned + TZID will be NULL. */ + if (strcmp (old_display_name, display_name) + || (!tzid && priv->zone)) { + priv->changed = TRUE; + priv->zone = NULL; + } + + gtk_entry_set_text (GTK_ENTRY (priv->entry), display_name); } gtk_object_unref (GTK_OBJECT (timezone_dialog)); @@ -217,20 +247,62 @@ on_entry_changed (GtkEntry *entry, } -char* +icaltimezone* e_timezone_entry_get_timezone (ETimezoneEntry *tentry) { + ETimezoneEntryPrivate *priv; + char *display_name; + g_return_val_if_fail (E_IS_TIMEZONE_ENTRY (tentry), NULL); - return gtk_entry_get_text (GTK_ENTRY (tentry->priv->entry)); + priv = tentry->priv; + + /* If the timezone hasn't been change, we can just return the same + zone we were passed in. */ + if (!priv->changed) + return priv->zone; + + /* If the timezone has changed, it can only have been changed to a + builtin timezone or 'local time' (i.e. no timezone). */ + display_name = gtk_entry_get_text (GTK_ENTRY (priv->entry)); + + if (display_name && display_name[0]) + return icaltimezone_get_builtin_timezone (display_name); + return NULL; } void e_timezone_entry_set_timezone (ETimezoneEntry *tentry, - char *timezone) + icaltimezone *zone) { + ETimezoneEntryPrivate *priv; + g_return_if_fail (E_IS_TIMEZONE_ENTRY (tentry)); - gtk_entry_set_text (GTK_ENTRY (tentry->priv->entry), timezone); + priv = tentry->priv; + + priv->zone = zone; + priv->changed = FALSE; + + gtk_entry_set_text (GTK_ENTRY (priv->entry), + e_timezone_entry_get_display_name (zone)); +} + + +/* Returns the timezone name to display to the user. . We prefer to use the + Olson city name, but fall back on the TZNAME, or finally the TZID. We don't + want to use "" as it may be wrongly interpreted as a 'local time'. */ +static char* +e_timezone_entry_get_display_name (icaltimezone *zone) +{ + char *display_name; + + display_name = icaltimezone_get_location (zone); + if (!display_name) + display_name = icaltimezone_get_tznames (zone); + if (!display_name) + display_name = icaltimezone_get_tzid (zone); + + return display_name; } diff --git a/calendar/gui/e-timezone-entry.h b/calendar/gui/e-timezone-entry.h index 0eadf1bef0..bfc8525f64 100644 --- a/calendar/gui/e-timezone-entry.h +++ b/calendar/gui/e-timezone-entry.h @@ -67,9 +67,9 @@ struct _ETimezoneEntryClass { guint e_timezone_entry_get_type (void); GtkWidget* e_timezone_entry_new (void); -char* e_timezone_entry_get_timezone (ETimezoneEntry *tentry); -void e_timezone_entry_set_timezone (ETimezoneEntry *tentry, - char *timezone); +icaltimezone* e_timezone_entry_get_timezone (ETimezoneEntry *tentry); +void e_timezone_entry_set_timezone (ETimezoneEntry *tentry, + icaltimezone *zone); END_GNOME_DECLS diff --git a/calendar/gui/e-week-view.c b/calendar/gui/e-week-view.c index fbe9ee435a..10655feecb 100644 --- a/calendar/gui/e-week-view.c +++ b/calendar/gui/e-week-view.c @@ -271,6 +271,7 @@ e_week_view_init (EWeekView *week_view) week_view->spans = NULL; + week_view->zone = NULL; week_view->multi_week_view = FALSE; week_view->weeks_shown = 6; week_view->rows = 6; @@ -988,8 +989,8 @@ query_obj_updated_cb (CalQuery *query, const char *uid, cal_recur_generate_instances (comp, week_view->day_starts[0], week_view->day_starts[num_days], - e_week_view_add_event, - week_view); + e_week_view_add_event, week_view, + cal_client_resolve_tzid, week_view->client); gtk_object_unref (GTK_OBJECT (comp)); @@ -1332,7 +1333,7 @@ e_week_view_set_first_day_shown (EWeekView *week_view, gint weekday, day_offset, num_days; gboolean update_adjustment_value = FALSE; guint32 old_selection_start_julian = 0, old_selection_end_julian = 0; - struct tm start_tm; + struct icaltimetype start_tt = icaltime_null_time (); time_t start_time; g_return_if_fail (E_IS_WEEK_VIEW (week_view)); @@ -1369,8 +1370,14 @@ e_week_view_set_first_day_shown (EWeekView *week_view, if (!g_date_valid (&week_view->first_day_shown) || g_date_compare (&week_view->first_day_shown, &base_date)) { week_view->first_day_shown = base_date; - g_date_to_struct_tm (&base_date, &start_tm); - start_time = mktime (&start_tm); + + start_tt.year = g_date_year (&base_date); + start_tt.month = g_date_month (&base_date); + start_tt.day = g_date_day (&base_date); + + start_time = icaltime_as_timet_with_zone (start_tt, + week_view->zone); + e_week_view_recalc_day_starts (week_view, start_time); update_query (week_view); } @@ -1643,6 +1650,51 @@ e_week_view_set_24_hour_format (EWeekView *week_view, gtk_widget_queue_draw (week_view->main_canvas); } + +/* The current timezone. */ +icaltimezone* +e_week_view_get_timezone (EWeekView *week_view) +{ + g_return_val_if_fail (E_IS_WEEK_VIEW (week_view), NULL); + + return week_view->zone; +} + + +void +e_week_view_set_timezone (EWeekView *week_view, + icaltimezone *zone) +{ + icaltimezone *old_zone; + struct icaltimetype tt = icaltime_null_time (); + time_t lower; + + g_return_if_fail (E_IS_WEEK_VIEW (week_view)); + + old_zone = week_view->zone; + if (old_zone == zone) + return; + + week_view->zone = zone; + + /* If we don't have a valid date set yet, just return. */ + if (!g_date_valid (&week_view->first_day_shown)) + return; + + /* Recalculate the new start of the first week. We just use exactly + the same time, but with the new timezone. */ + tt.year = g_date_year (&week_view->first_day_shown); + tt.month = g_date_month (&week_view->first_day_shown); + tt.day = g_date_day (&week_view->first_day_shown); + tt.is_daylight = -1; + + lower = icaltime_as_timet_with_zone (tt, zone); + + e_week_view_recalc_day_starts (week_view, lower); + update_query (week_view); +} + + void e_week_view_cut_clipboard (EWeekView *week_view) { @@ -2186,7 +2238,7 @@ e_week_view_add_event (CalComponent *comp, EWeekView *week_view; EWeekViewEvent event; gint num_days; - struct tm start_tm, end_tm; + struct icaltimetype start_tt, end_tt; week_view = E_WEEK_VIEW (data); @@ -2203,8 +2255,10 @@ e_week_view_add_event (CalComponent *comp, g_return_val_if_fail (start < week_view->day_starts[num_days], TRUE); g_return_val_if_fail (end > week_view->day_starts[0], TRUE); - start_tm = *(localtime (&start)); - end_tm = *(localtime (&end)); + start_tt = icaltime_from_timet_with_zone (start, FALSE, + week_view->zone); + end_tt = icaltime_from_timet_with_zone (end, FALSE, + week_view->zone); event.comp = comp; gtk_object_ref (GTK_OBJECT (event.comp)); @@ -2213,8 +2267,8 @@ e_week_view_add_event (CalComponent *comp, event.spans_index = 0; event.num_spans = 0; - event.start_minute = start_tm.tm_hour * 60 + start_tm.tm_min; - event.end_minute = end_tm.tm_hour * 60 + end_tm.tm_min; + event.start_minute = start_tt.hour * 60 + start_tt.minute; + event.end_minute = end_tt.hour * 60 + end_tt.minute; if (event.end_minute == 0 && start != end) event.end_minute = 24 * 60; @@ -2583,7 +2637,7 @@ e_week_view_on_adjustment_changed (GtkAdjustment *adjustment, { GDate date; gint week_offset; - struct tm tm; + struct icaltimetype start_tt = icaltime_null_time (); time_t lower, start, end; guint32 old_first_day_julian, new_first_day_julian; @@ -2608,9 +2662,11 @@ e_week_view_on_adjustment_changed (GtkAdjustment *adjustment, week_view->first_day_shown = date; /* Convert it to a time_t. */ - g_date_to_struct_tm (&date, &tm); - lower = mktime (&tm); - lower = time_day_begin (lower); + start_tt.year = g_date_year (&date); + start_tt.month = g_date_month (&date); + start_tt.day = g_date_day (&date); + + lower = icaltime_as_timet_with_zone (start_tt, week_view->zone); e_week_view_recalc_day_starts (week_view, lower); update_query (week_view); @@ -3019,11 +3075,13 @@ e_week_view_key_press (GtkWidget *widget, GdkEventKey *event) dtend = week_view->day_starts[week_view->selection_end_day + 1]; date.value = &itt; - date.tzid = NULL; + date.tzid = icaltimezone_get_tzid (week_view->zone); - *date.value = icaltime_from_timet (dtstart, FALSE); + *date.value = icaltime_from_timet_with_zone (dtstart, FALSE, + week_view->zone); cal_component_set_dtstart (comp, &date); - *date.value = icaltime_from_timet (dtend, FALSE); + *date.value = icaltime_from_timet_with_zone (dtend, FALSE, + week_view->zone); cal_component_set_dtend (comp, &date); /* We add the event locally and start editing it. We don't send the @@ -3245,7 +3303,7 @@ e_week_view_on_delete_occurrence (GtkWidget *widget, gpointer data) when we get the "update_event" callback. */ comp = cal_component_clone (event->comp); - cal_comp_util_add_exdate (comp, icaltime_from_timet (event->start, TRUE)); + cal_comp_util_add_exdate (comp, event->start, week_view->zone); if (!cal_client_update_object (week_view->client, comp)) g_message ("e_week_view_on_delete_occurrence(): Could not update the object!"); @@ -3358,7 +3416,7 @@ e_week_view_on_unrecur_appointment (GtkWidget *widget, gpointer data) /* For the recurring object, we add a exception to get rid of the instance. */ comp = cal_component_clone (event->comp); - cal_comp_util_add_exdate (comp, icaltime_from_timet (event->start, TRUE)); + cal_comp_util_add_exdate (comp, event->start, week_view->zone); /* For the unrecurred instance we duplicate the original object, create a new uid for it, get rid of the recurrence rules, and set @@ -3371,11 +3429,13 @@ e_week_view_on_unrecur_appointment (GtkWidget *widget, gpointer data) cal_component_set_exrule_list (new_comp, NULL); date.value = &itt; - date.tzid = NULL; + date.tzid = icaltimezone_get_tzid (week_view->zone); - *date.value = icaltime_from_timet (event->start, TRUE); + *date.value = icaltime_from_timet_with_zone (event->start, FALSE, + week_view->zone); cal_component_set_dtstart (new_comp, &date); - *date.value = icaltime_from_timet (event->end, TRUE); + *date.value = icaltime_from_timet_with_zone (event->end, FALSE, + week_view->zone); cal_component_set_dtend (new_comp, &date); /* Now update both CalComponents. Note that we do this last since at @@ -3527,11 +3587,13 @@ selection_received (GtkWidget *invisible, icalcomp = icalparser_parse_string ((const char *) comp_str); if (icalcomp) { dtstart = week_view->day_starts[week_view->selection_start_day]; - itime = icaltime_from_timet (dtstart, FALSE); + itime = icaltime_from_timet_with_zone (dtstart, FALSE, + week_view->zone); icalcomponent_set_dtstart (icalcomp, itime); dtend = week_view->day_starts[week_view->selection_end_day + 1]; - itime = icaltime_from_timet (dtend, FALSE); + itime = icaltime_from_timet_with_zone (dtend, FALSE, + week_view->zone); icalcomponent_set_dtend (icalcomp, itime); comp = cal_component_new (); diff --git a/calendar/gui/e-week-view.h b/calendar/gui/e-week-view.h index cf1986b3bb..4bbc0477d2 100644 --- a/calendar/gui/e-week-view.h +++ b/calendar/gui/e-week-view.h @@ -209,6 +209,9 @@ struct _EWeekView /* The start of each day displayed. */ time_t day_starts[E_WEEK_VIEW_MAX_WEEKS * 7 + 1]; + /* The timezone. */ + icaltimezone *zone; + /* The base date, where the adjustment value is 0. */ GDate base_date; @@ -418,6 +421,11 @@ gboolean e_week_view_get_24_hour_format (EWeekView *week_view); void e_week_view_set_24_hour_format (EWeekView *week_view, gboolean use_24_hour); +/* The current timezone. */ +icaltimezone* e_week_view_get_timezone (EWeekView *week_view); +void e_week_view_set_timezone (EWeekView *week_view, + icaltimezone *zone); + /* Clipboard related functions */ void e_week_view_cut_clipboard (EWeekView *week_view); void e_week_view_copy_clipboard (EWeekView *week_view); diff --git a/calendar/gui/gnome-cal.c b/calendar/gui/gnome-cal.c index 9c99efaec9..5ea48a4d6e 100644 --- a/calendar/gui/gnome-cal.c +++ b/calendar/gui/gnome-cal.c @@ -133,6 +133,9 @@ struct _GnomeCalendarPrivate { * editor hash table. */ guint in_destroy : 1; + + /* Our current timezone. */ + icaltimezone *zone; }; @@ -343,6 +346,37 @@ search_bar_menu_activated_cb (ESearchBar *search_bar, int item, gpointer data) } } +/* Returns the current time, for the ECalendarItem. */ +static struct tm +get_current_time (ECalendarItem *calitem, gpointer data) +{ + GnomeCalendar *cal = data; + char *location; + icaltimezone *zone; + struct tm tmp_tm = { 0 }; + struct icaltimetype tt; + + g_return_val_if_fail (cal != NULL, tmp_tm); + g_return_val_if_fail (GNOME_IS_CALENDAR (cal), tmp_tm); + + /* Get the current timezone. */ + location = calendar_config_get_timezone (); + zone = icaltimezone_get_builtin_timezone (location); + + tt = icaltime_from_timet_with_zone (time (NULL), FALSE, zone); + + /* Now copy it to the struct tm and return it. */ + 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; + + return tmp_tm; +} + static void setup_widgets (GnomeCalendar *gcal) { @@ -386,6 +420,9 @@ setup_widgets (GnomeCalendar *gcal) e_calendar_item_set_days_start_week_sel (priv->date_navigator->calitem, 9); e_calendar_item_set_max_days_sel (priv->date_navigator->calitem, 42); gtk_widget_show (w); + e_calendar_item_set_get_time_callback (priv->date_navigator->calitem, + (ECalendarItemGetTimeCallback) get_current_time, + gcal, NULL); e_paned_pack1 (E_PANED (priv->vpane), w, FALSE, TRUE); gtk_signal_connect (GTK_OBJECT (priv->date_navigator), @@ -473,6 +510,8 @@ gnome_calendar_init (GnomeCalendar *gcal) priv->view_collection = NULL; priv->view_menus = NULL; + + priv->zone = NULL; } /* Used from g_hash_table_foreach(); frees an UID string */ @@ -1315,6 +1354,7 @@ gnome_calendar_update_config_settings (GnomeCalendar *gcal, gint week_start_day, time_divisions; gint start_hour, start_minute, end_hour, end_minute; gboolean use_24_hour, show_event_end, compress_weekend; + char *location; g_return_if_fail (GNOME_IS_CALENDAR (gcal)); @@ -1388,6 +1428,14 @@ gnome_calendar_update_config_settings (GnomeCalendar *gcal, calendar_config_configure_e_calendar_table (E_CALENDAR_TABLE (priv->todo)); + location = calendar_config_get_timezone (); + priv->zone = icaltimezone_get_builtin_timezone (location); + + e_day_view_set_timezone (E_DAY_VIEW (priv->day_view), priv->zone); + e_day_view_set_timezone (E_DAY_VIEW (priv->work_week_view), priv->zone); + e_week_view_set_timezone (E_WEEK_VIEW (priv->week_view), priv->zone); + e_week_view_set_timezone (E_WEEK_VIEW (priv->month_view), priv->zone); + if (initializing) { priv->hpane_pos = calendar_config_get_hpane_pos (); priv->vpane_pos = calendar_config_get_vpane_pos (); @@ -1537,6 +1585,7 @@ gnome_calendar_new_appointment_for (GnomeCalendar *cal, time_t dtstart, time_t dtend, gboolean all_day) { + GnomeCalendarPrivate *priv; struct icaltimetype itt; CalComponentDateTime dt; CalComponent *comp; @@ -1544,21 +1593,24 @@ gnome_calendar_new_appointment_for (GnomeCalendar *cal, g_return_if_fail (cal != NULL); g_return_if_fail (GNOME_IS_CALENDAR (cal)); - if (all_day){ - dtstart = time_day_begin (dtstart); - dtend = time_day_end (dtend); - } + priv = cal->priv; dt.value = &itt; - dt.tzid = NULL; + dt.tzid = icaltimezone_get_tzid (priv->zone); comp = cal_component_new (); cal_component_set_new_vtype (comp, CAL_COMPONENT_EVENT); - itt = icaltime_from_timet (dtstart, FALSE); + itt = icaltime_from_timet_with_zone (dtstart, FALSE, priv->zone); + if (all_day) + itt.hour = itt.minute = itt.second = 0; cal_component_set_dtstart (comp, &dt); - itt = icaltime_from_timet (dtend, FALSE); + itt = icaltime_from_timet_with_zone (dtend, FALSE, priv->zone); + if (all_day) { + itt.hour = itt.minute = itt.second = 0; + icaltime_adjust (&itt, 1, 0, 0, 0); + } cal_component_set_dtend (comp, &dt); cal_component_commit_sequence (comp); @@ -1705,10 +1757,7 @@ gnome_calendar_on_date_navigator_selection_changed (ECalendarItem *calitem, GnomeCalendarPrivate *priv; GDate start_date, end_date, new_start_date, new_end_date; gint days_shown, new_days_shown; - gint start_year, start_month, start_day; - gint end_year, end_month, end_day; gboolean starts_on_week_start_day; - struct tm tm; priv = gcal->priv; @@ -1750,30 +1799,35 @@ gnome_calendar_on_date_navigator_selection_changed (ECalendarItem *calitem, set_view (gcal, GNOME_CAL_WEEK_VIEW, TRUE, FALSE); gnome_calendar_update_date_navigator (gcal); } else { + gint start_year, start_month, start_day; + gint end_year, end_month, end_day; + struct icaltimetype tt; + start_year = g_date_year (&new_start_date); - start_month = g_date_month (&new_start_date) - 1; + start_month = g_date_month (&new_start_date); start_day = g_date_day (&new_start_date); end_year = g_date_year (&new_end_date); - end_month = g_date_month (&new_end_date) - 1; + end_month = g_date_month (&new_end_date); end_day = g_date_day (&new_end_date); - tm.tm_year = start_year - 1900; - tm.tm_mon = start_month; - tm.tm_mday = start_day; - tm.tm_hour = 0; - tm.tm_min = 0; - tm.tm_sec = 0; - tm.tm_isdst = -1; - priv->selection_start_time = mktime (&tm); - - tm.tm_year = end_year - 1900; - tm.tm_mon = end_month; - tm.tm_mday = end_day + 1; /* mktime() will normalize this. */ - tm.tm_hour = 0; - tm.tm_min = 0; - tm.tm_sec = 0; - tm.tm_isdst = -1; - priv->selection_end_time = mktime (&tm); + tt.year = start_year; + tt.month = start_month; + tt.day = start_day; + tt.hour = 0; + tt.minute = 0; + tt.second = 0; + tt.is_daylight = -1; + priv->selection_start_time = icaltime_as_timet_with_zone (tt, priv->zone); + + tt.year = end_year; + tt.month = end_month; + tt.day = end_day; + tt.hour = 0; + tt.minute = 0; + tt.second = 0; + tt.is_daylight = -1; + icaltime_adjust (&tt, 1, 0, 0, 0); + priv->selection_end_time = icaltime_as_timet_with_zone (tt, priv->zone); e_day_view_set_days_shown (E_DAY_VIEW (priv->day_view), new_days_shown); gnome_calendar_set_view (gcal, GNOME_CAL_DAY_VIEW, TRUE, FALSE); @@ -2033,3 +2087,15 @@ gnome_calendar_paste_clipboard (GnomeCalendar *gcal) break; } } + + +/* Get the current timezone. */ +icaltimezone* +gnome_calendar_get_timezone (GnomeCalendar *gcal) +{ + g_return_val_if_fail (gcal != NULL, NULL); + g_return_val_if_fail (GNOME_IS_CALENDAR (gcal), NULL); + + return gcal->priv->zone; +} + diff --git a/calendar/gui/gnome-cal.h b/calendar/gui/gnome-cal.h index 950d650d1a..4b0dca84e3 100644 --- a/calendar/gui/gnome-cal.h +++ b/calendar/gui/gnome-cal.h @@ -134,6 +134,10 @@ void gnome_calendar_set_view_buttons (GnomeCalendar *gcal, just return without doing anything. */ void gnome_calendar_update_view_buttons (GnomeCalendar *gcal); +/* Get the current timezone. */ +icaltimezone *gnome_calendar_get_timezone (GnomeCalendar *gcal); + + /* Clipboard operations */ void gnome_calendar_cut_clipboard (GnomeCalendar *gcal); void gnome_calendar_copy_clipboard (GnomeCalendar *gcal); diff --git a/calendar/gui/goto.c b/calendar/gui/goto.c index 16c1eecc9f..06250a1a70 100644 --- a/calendar/gui/goto.c +++ b/calendar/gui/goto.c @@ -18,6 +18,7 @@ #include <libgnomeui/gnome-dialog.h> #include <glade/glade.h> #include "calendar-commands.h" +#include "calendar-config.h" #include "tag-calendar.h" #include "goto.h" @@ -83,18 +84,49 @@ ecal_event (ECalendarItem *calitem, gpointer user_data) { GoToDialog *dlg = user_data; GDate start_date, end_date; - struct tm tm; + struct icaltimetype tt = icaltime_null_time (); time_t et; e_calendar_item_get_selection (calitem, &start_date, &end_date); - g_date_to_struct_tm (&start_date, &tm); - et = mktime (&tm); - + + tt.year = g_date_year (&start_date); + tt.month = g_date_month (&start_date); + tt.day = g_date_day (&start_date); + + et = icaltime_as_timet_with_zone (tt, gnome_calendar_get_timezone (dlg->gcal)); + gnome_calendar_goto (dlg->gcal, et); gnome_dialog_close (GNOME_DIALOG (dlg->dialog)); } +/* Returns the current time, for the ECalendarItem. */ +static struct tm +get_current_time (ECalendarItem *calitem, gpointer data) +{ + char *location; + icaltimezone *zone; + struct tm tmp_tm = { 0 }; + struct icaltimetype tt; + + /* Get the current timezone. */ + location = calendar_config_get_timezone (); + zone = icaltimezone_get_builtin_timezone (location); + + tt = icaltime_from_timet_with_zone (time (NULL), FALSE, zone); + + /* Now copy it to the struct tm and return it. */ + 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; + + return tmp_tm; +} + /* Creates the ecalendar */ static void create_ecal (GoToDialog *dlg) @@ -109,6 +141,9 @@ create_ecal (GoToDialog *dlg) gtk_box_pack_start (GTK_BOX (dlg->vbox), GTK_WIDGET (dlg->ecal), TRUE, TRUE, 0); e_calendar_item_set_first_month (calitem, dlg->year_val, dlg->month_val); + e_calendar_item_set_get_time_callback (calitem, + get_current_time, + dlg, NULL); ecal_date_range_changed (calitem, dlg); } @@ -171,7 +206,7 @@ goto_dialog (GnomeCalendar *gcal) { GtkWidget *menu; time_t start_time; - struct tm tm; + struct icaltimetype tt; int b; if (dlg) { @@ -196,10 +231,10 @@ goto_dialog (GnomeCalendar *gcal) dlg->gcal = gcal; gnome_calendar_get_selected_time_range (dlg->gcal, &start_time, NULL); - tm = *localtime (&start_time); - dlg->year_val = tm.tm_year + 1900; - dlg->month_val = tm.tm_mon; - dlg->day_val = tm.tm_mday; + tt = icaltime_from_timet_with_zone (start_time, FALSE, gnome_calendar_get_timezone (gcal)); + dlg->year_val = tt.year; + dlg->month_val = tt.month - 1; + dlg->day_val = tt.day; menu = gtk_option_menu_get_menu (GTK_OPTION_MENU (dlg->month)); gtk_option_menu_set_history (GTK_OPTION_MENU (dlg->month), dlg->month_val); diff --git a/calendar/gui/tag-calendar.c b/calendar/gui/tag-calendar.c index 3d6ba40f45..485e013c4e 100644 --- a/calendar/gui/tag-calendar.c +++ b/calendar/gui/tag-calendar.c @@ -25,12 +25,14 @@ #endif #include <cal-util/timeutil.h> +#include "calendar-config.h" #include "tag-calendar.h" struct calendar_tag_closure { ECalendarItem *calitem; + icaltimezone *zone; time_t start_time; time_t end_time; }; @@ -44,7 +46,9 @@ prepare_tag (ECalendar *ecal, struct calendar_tag_closure *c) { gint start_year, start_month, start_day; gint end_year, end_month, end_day; - struct tm start_tm = { 0 }, end_tm = { 0 }; + struct icaltimetype start_tt = icaltime_null_time (); + struct icaltimetype end_tt = icaltime_null_time (); + char *location; e_calendar_item_clear_marks (ecal->calitem); @@ -54,25 +58,26 @@ prepare_tag (ECalendar *ecal, struct calendar_tag_closure *c) &end_year, &end_month, &end_day)) return FALSE; - start_tm.tm_year = start_year - 1900; - start_tm.tm_mon = start_month; - start_tm.tm_mday = start_day; - start_tm.tm_hour = 0; - start_tm.tm_min = 0; - start_tm.tm_sec = 0; - start_tm.tm_isdst = -1; - - end_tm.tm_year = end_year - 1900; - end_tm.tm_mon = end_month; - end_tm.tm_mday = end_day + 1; - end_tm.tm_hour = 0; - end_tm.tm_min = 0; - end_tm.tm_sec = 0; - end_tm.tm_isdst = -1; + start_tt.year = start_year; + start_tt.month = start_month + 1; + start_tt.day = start_day; + start_tt.is_daylight = -1; + + end_tt.year = end_year; + end_tt.month = end_month + 1; + end_tt.day = end_day; + end_tt.is_daylight = -1; + + icaltime_adjust (&end_tt, 1, 0, 0, 0); c->calitem = ecal->calitem; - c->start_time = mktime (&start_tm); - c->end_time = mktime (&end_tm); + + /* FIXME. It may be better if the timezone is passed in. */ + location = calendar_config_get_timezone (); + c->zone = icaltimezone_get_builtin_timezone (location); + + c->start_time = icaltime_as_timet_with_zone (start_tt, c->zone); + c->end_time = icaltime_as_timet_with_zone (end_tt, c->zone); return TRUE; } @@ -85,21 +90,16 @@ tag_calendar_cb (CalComponent *comp, gpointer data) { struct calendar_tag_closure *c = data; - time_t t; - - t = time_day_begin (istart); - - do { - struct tm tm; - - tm = *localtime (&t); - - e_calendar_item_mark_day (c->calitem, tm.tm_year + 1900, - tm.tm_mon, tm.tm_mday, - E_CALENDAR_ITEM_MARK_BOLD); + struct icaltimetype start_tt, end_tt; - t = time_day_end (t); - } while (t < iend); + start_tt = icaltime_from_timet_with_zone (istart, FALSE, c->zone); + end_tt = icaltime_from_timet_with_zone (iend, FALSE, c->zone); + e_calendar_item_mark_days (c->calitem, + start_tt.year, start_tt.month - 1, + start_tt.day, + end_tt.year, end_tt.month - 1, + end_tt.day, + E_CALENDAR_ITEM_MARK_BOLD); return TRUE; } @@ -149,7 +149,7 @@ tag_calendar_by_client (ECalendar *ecal, CalClient *client) * component that occur within the calendar's current time range. **/ void -tag_calendar_by_comp (ECalendar *ecal, CalComponent *comp) +tag_calendar_by_comp (ECalendar *ecal, CalComponent *comp, CalClient *client) { struct calendar_tag_closure c; @@ -168,5 +168,7 @@ tag_calendar_by_comp (ECalendar *ecal, CalComponent *comp) #if 0 g_print ("DateNavigator generating instances\n"); #endif - cal_recur_generate_instances (comp, c.start_time, c.end_time, tag_calendar_cb, &c); + cal_recur_generate_instances (comp, c.start_time, c.end_time, + tag_calendar_cb, &c, + cal_client_resolve_tzid, client); } diff --git a/calendar/gui/tag-calendar.h b/calendar/gui/tag-calendar.h index 74c669493b..f9b11c1a5a 100644 --- a/calendar/gui/tag-calendar.h +++ b/calendar/gui/tag-calendar.h @@ -27,6 +27,7 @@ #include <cal-client/cal-client.h> void tag_calendar_by_client (ECalendar *ecal, CalClient *client); -void tag_calendar_by_comp (ECalendar *ecal, CalComponent *comp); +void tag_calendar_by_comp (ECalendar *ecal, CalComponent *comp, + CalClient *client); #endif diff --git a/calendar/idl/evolution-calendar.idl b/calendar/idl/evolution-calendar.idl index 5f0d10513f..a855f09cce 100644 --- a/calendar/idl/evolution-calendar.idl +++ b/calendar/idl/evolution-calendar.idl @@ -28,6 +28,12 @@ module Calendar { /* Sequence of unique identifiers */ typedef sequence<CalObjUID> CalObjUIDSeq; + /* A VTIMEZONE component, represented as an iCalendar string. */ + typedef string CalTimezoneObj; + + /* A unique identifier for a VTIMEZONE component, i.e. its TZID. */ + typedef string CalTimezoneObjUID; + /* A unique identifier for an alarm subcomponent */ typedef string CalAlarmUID; @@ -123,6 +129,10 @@ module Calendar { CalObj getObject (in CalObjUID uid) raises (NotFound); + /* Gets a VTIMEZONE component based on its TZID */ + CalTimezoneObj getTimezoneObject (in CalTimezoneObjUID tzid) + raises (NotFound); + /* Gets a list of UIDs based on component type */ CalObjUIDSeq getUIDs (in CalObjType type); @@ -153,7 +163,17 @@ module Calendar { /* Updates a component by adding it if it does not exist or by - * changing an existing one. + * changing an existing one. This can be a simple VEVENT/VTODO + * object if no timezone data is needed for the component or + * it hasn't changed. To add or change the associated VTIMEZONE + * data the calobj should be a VCALENDAR component with + * VTIMEZONE and VEVENT/VTODO subcomponents. The VTIMEZONE data + * will be merged into the calendar, possibly by renaming TZIDs + * (though not for builtin VTIMEZONEs), so don't rely on the + * TZIDs being the same in the new object on the server. + * The client should probably immediately free its copy of the + * object after this call, and call getObject to get the + * updated version. */ void updateObject (in CalObjUID uid, in CalObj calobj) raises (InvalidObject); diff --git a/calendar/pcs/cal-backend-file.c b/calendar/pcs/cal-backend-file.c index 79a6018ec0..17765f918c 100644 --- a/calendar/pcs/cal-backend-file.c +++ b/calendar/pcs/cal-backend-file.c @@ -73,6 +73,7 @@ static gboolean cal_backend_file_is_loaded (CalBackend *backend); static int cal_backend_file_get_n_objects (CalBackend *backend, CalObjType type); static char *cal_backend_file_get_object (CalBackend *backend, const char *uid); +static char *cal_backend_file_get_timezone_object (CalBackend *backend, const char *tzid); static CalObjType cal_backend_file_get_type_by_uid (CalBackend *backend, const char *uid); static GList *cal_backend_file_get_uids (CalBackend *backend, CalObjType type); static GList *cal_backend_file_get_objects_in_range (CalBackend *backend, CalObjType type, @@ -148,6 +149,7 @@ cal_backend_file_class_init (CalBackendFileClass *class) backend_class->is_loaded = cal_backend_file_is_loaded; backend_class->get_n_objects = cal_backend_file_get_n_objects; backend_class->get_object = cal_backend_file_get_object; + backend_class->get_timezone_object = cal_backend_file_get_timezone_object; backend_class->get_type_by_uid = cal_backend_file_get_type_by_uid; backend_class->get_uids = cal_backend_file_get_uids; backend_class->get_objects_in_range = cal_backend_file_get_objects_in_range; @@ -812,6 +814,40 @@ cal_backend_file_get_object (CalBackend *backend, const char *uid) return cal_component_get_as_string (comp); } +/* Get_object handler for the file backend */ +static char * +cal_backend_file_get_timezone_object (CalBackend *backend, const char *tzid) +{ + CalBackendFile *cbfile; + CalBackendFilePrivate *priv; + icaltimezone *icaltz; + icalcomponent *icalcomp; + char *ical_string; + + cbfile = CAL_BACKEND_FILE (backend); + priv = cbfile->priv; + + g_return_val_if_fail (tzid != NULL, NULL); + + g_return_val_if_fail (priv->icalcomp != NULL, NULL); + g_assert (priv->comp_uid_hash != NULL); + + icaltz = icalcomponent_get_timezone (priv->icalcomp, tzid); + if (!icaltz) + return NULL; + + icalcomp = icaltimezone_get_component (icaltz); + if (!icalcomp) + return NULL; + + ical_string = icalcomponent_as_ical_string (icalcomp); + /* We dup the string; libical owns that memory. */ + if (ical_string) + return g_strdup (ical_string); + else + return NULL; +} + static CalObjType cal_backend_file_get_type_by_uid (CalBackend *backend, const char *uid) { @@ -910,6 +946,20 @@ add_instance (CalComponent *comp, time_t start, time_t end, gpointer data) return FALSE; } + +/* FIXME */ +static icaltimezone* +resolve_tzid (const char *tzid, gpointer data) +{ + icalcomponent *vcalendar_comp = data; + + if (!strcmp (tzid, "UTC")) + return icaltimezone_get_utc_timezone (); + else + return icalcomponent_get_timezone (vcalendar_comp, tzid); +} + + /* Populates a hash table with the UIDs of the components that occur or recur * within a specific time range. */ @@ -920,9 +970,17 @@ get_instances_in_range (GHashTable *uid_hash, GList *components, time_t start, t for (l = components; l; l = l->next) { CalComponent *comp; + icalcomponent *icalcomp, *vcalendar_comp; comp = CAL_COMPONENT (l->data); - cal_recur_generate_instances (comp, start, end, add_instance, uid_hash); + + /* Get the parent VCALENDAR component, so we can resolve + TZIDs. */ + icalcomp = cal_component_get_icalcomponent (comp); + vcalendar_comp = icalcomponent_get_parent (icalcomp); + g_assert (vcalendar_comp != NULL); + + cal_recur_generate_instances (comp, start, end, add_instance, uid_hash, resolve_tzid, vcalendar_comp); } } @@ -1346,7 +1404,7 @@ generate_alarms_for_comp (CalComponent *comp, time_t start, time_t end) aod.end = end; aod.triggers = NULL; aod.n_triggers = 0; - cal_recur_generate_instances (comp, alarm_start, alarm_end, add_alarm_occurrences_cb, &aod); + cal_recur_generate_instances (comp, alarm_start, alarm_end, add_alarm_occurrences_cb, &aod, resolve_tzid, NULL); /* We add the ABSOLUTE triggers separately */ generate_absolute_triggers (comp, &aod); @@ -1564,7 +1622,7 @@ cal_backend_file_update_object (CalBackend *backend, const char *uid, const char { CalBackendFile *cbfile; CalBackendFilePrivate *priv; - icalcomponent *icalcomp; + icalcomponent *icalcomp, *vcalendar_comp = NULL; icalcomponent_kind kind; CalComponent *old_comp; CalComponent *comp; @@ -1580,16 +1638,51 @@ cal_backend_file_update_object (CalBackend *backend, const char *uid, const char /* Pull the component from the string and ensure that it is sane */ + fprintf (stderr, "cal_backend_file: Parsing string:\n%s\n", calobj); icalcomp = icalparser_parse_string ((char *) calobj); if (!icalcomp) return FALSE; + fprintf (stderr, "cal_backend_file: Parsed OK.\n"); + kind = icalcomponent_isa (icalcomp); - if (!(kind == ICAL_VEVENT_COMPONENT - || kind == ICAL_VTODO_COMPONENT - || kind == ICAL_VJOURNAL_COMPONENT)) { + if (kind == ICAL_VCALENDAR_COMPONENT) { + int num_found = 0; + icalcomponent_kind child_kind; + icalcomponent *subcomp; + + fprintf (stderr, "cal_backend_file: VCALENDAR found\n"); + + /* We have a VCALENDAR containing the VEVENT/VTODO and the + related timezone data, so we have to step through it to + find the actual VEVENT/VTODO component. */ + vcalendar_comp = icalcomp; + + subcomp = icalcomponent_get_first_component (vcalendar_comp, + ICAL_ANY_COMPONENT); + while (subcomp) { + child_kind = icalcomponent_isa (subcomp); + if (kind == ICAL_VEVENT_COMPONENT + || kind == ICAL_VTODO_COMPONENT + || kind == ICAL_VJOURNAL_COMPONENT) { + icalcomp = subcomp; + num_found++; + } + subcomp = icalcomponent_get_next_component (vcalendar_comp, + ICAL_ANY_COMPONENT); + } + + /* If we didn't find exactly 1 VEVENT/VTODO it is an error. */ + if (num_found != 1) { + icalcomponent_free (icalcomp); + return FALSE; + } + + } else if (!(kind == ICAL_VEVENT_COMPONENT + || kind == ICAL_VTODO_COMPONENT + || kind == ICAL_VJOURNAL_COMPONENT)) { /* We don't support this type of component */ icalcomponent_free (icalcomp); return FALSE; @@ -1618,7 +1711,19 @@ cal_backend_file_update_object (CalBackend *backend, const char *uid, const char if (old_comp) remove_component (cbfile, old_comp); - add_component (cbfile, comp, TRUE); + if (kind == ICAL_VCALENDAR_COMPONENT) { + /* If we have a VCALENDAR component with child VTIMEZONEs and + the VEVENT/VTODO, we have to merge it into the existing + VCALENDAR, resolving any conflicting TZIDs. */ + icalcomponent_merge_component (priv->icalcomp, vcalendar_comp); + + /* Now we add the component to our local cache, but we pass + FALSE as the last argument, since we have already added + the libical component when merging above.*/ + add_component (cbfile, comp, FALSE); + } else { + add_component (cbfile, comp, TRUE); + } mark_dirty (cbfile); diff --git a/calendar/pcs/cal-backend.c b/calendar/pcs/cal-backend.c index 2b14e291db..a9eae9f212 100644 --- a/calendar/pcs/cal-backend.c +++ b/calendar/pcs/cal-backend.c @@ -138,6 +138,7 @@ cal_backend_class_init (CalBackendClass *class) class->is_loaded = NULL; class->get_n_objects = NULL; class->get_object = NULL; + class->get_timezone_object = NULL; class->get_type_by_uid = NULL; class->get_uids = NULL; class->get_objects_in_range = NULL; @@ -281,6 +282,28 @@ cal_backend_get_object (CalBackend *backend, const char *uid) } /** + * cal_backend_get_timezone_object: + * @backend: A calendar backend. + * @tzid: Unique identifier for a calendar VTIMEZONE object. + * + * Queries a calendar backend for a VTIMEZONE calendar object based on its + * unique TZID identifier. + * + * Return value: The string representation of a VTIMEZONE component, or NULL + * if no VTIMEZONE object had the specified TZID. + **/ +char * +cal_backend_get_timezone_object (CalBackend *backend, const char *tzid) +{ + g_return_val_if_fail (backend != NULL, NULL); + g_return_val_if_fail (IS_CAL_BACKEND (backend), NULL); + g_return_val_if_fail (tzid != NULL, NULL); + + g_assert (CLASS (backend)->get_timezone_object != NULL); + return (* CLASS (backend)->get_timezone_object) (backend, tzid); +} + +/** * cal_backend_get_uids: * @backend: A calendar backend. * @type: Bitmask with types of objects to return. diff --git a/calendar/pcs/cal-backend.h b/calendar/pcs/cal-backend.h index c59be8d808..e5d475452b 100644 --- a/calendar/pcs/cal-backend.h +++ b/calendar/pcs/cal-backend.h @@ -84,6 +84,7 @@ struct _CalBackendClass { /* General object acquirement and information related virtual methods */ int (* get_n_objects) (CalBackend *backend, CalObjType type); char *(* get_object) (CalBackend *backend, const char *uid); + char *(* get_timezone_object) (CalBackend *backend, const char *tzid); CalObjType(* get_type_by_uid) (CalBackend *backend, const char *uid); GList *(* get_uids) (CalBackend *backend, CalObjType type); @@ -122,6 +123,8 @@ int cal_backend_get_n_objects (CalBackend *backend, CalObjType type); char *cal_backend_get_object (CalBackend *backend, const char *uid); +char *cal_backend_get_timezone_object (CalBackend *backend, const char *tzid); + GList *cal_backend_get_uids (CalBackend *backend, CalObjType type); GList *cal_backend_get_objects_in_range (CalBackend *backend, CalObjType type, diff --git a/calendar/pcs/cal.c b/calendar/pcs/cal.c index ab815cb3e2..9cd5b5b219 100644 --- a/calendar/pcs/cal.c +++ b/calendar/pcs/cal.c @@ -424,6 +424,35 @@ impl_Cal_get_query (PortableServer_Servant servant, return query_copy; } +/* Cal::get_timezone_object method */ +static GNOME_Evolution_Calendar_CalObj +impl_Cal_get_timezone_object (PortableServer_Servant servant, + const GNOME_Evolution_Calendar_CalTimezoneObjUID tzid, + CORBA_Environment *ev) +{ + Cal *cal; + CalPrivate *priv; + char *calobj; + + cal = CAL (bonobo_object_from_servant (servant)); + priv = cal->priv; + + calobj = cal_backend_get_timezone_object (priv->backend, tzid); + + if (calobj) { + CORBA_char *calobj_copy; + + calobj_copy = CORBA_string_dup (calobj); + g_free (calobj); + return calobj_copy; + } else { + CORBA_exception_set (ev, CORBA_USER_EXCEPTION, + ex_GNOME_Evolution_Calendar_Cal_NotFound, + NULL); + return NULL; + } +} + /** * cal_construct: * @cal: A calendar client interface. @@ -556,6 +585,7 @@ cal_class_init (CalClass *klass) epv->_get_uri = impl_Cal_get_uri; epv->countObjects = impl_Cal_get_n_objects; epv->getObject = impl_Cal_get_object; + epv->getTimezoneObject = impl_Cal_get_timezone_object; epv->getUIDs = impl_Cal_get_uids; epv->getChanges = impl_Cal_get_changes; epv->getObjectsInRange = impl_Cal_get_objects_in_range; diff --git a/calendar/pcs/query.c b/calendar/pcs/query.c index ed391ee667..237b2524e1 100644 --- a/calendar/pcs/query.c +++ b/calendar/pcs/query.c @@ -442,6 +442,20 @@ instance_occur_cb (CalComponent *comp, time_t start, time_t end, gpointer data) return FALSE; } +/* FIXME. This is the same as the function in cal-backend-file.c. It needs + to be added to the backend interface, I think. */ +static icaltimezone* +resolve_tzid (const char *tzid, gpointer data) +{ + icalcomponent *vcalendar_comp = data; + + if (!strcmp (tzid, "UTC")) + return icaltimezone_get_utc_timezone (); + else + return icalcomponent_get_timezone (vcalendar_comp, tzid); +} + + /* (occur-in-time-range? START END) * * START - time_t, start of the time range @@ -459,6 +473,7 @@ func_occur_in_time_range (ESExp *esexp, int argc, ESExpResult **argv, void *data time_t start, end; gboolean occurs; ESExpResult *result; + icalcomponent *icalcomp, *vcalendar_comp; query = QUERY (data); priv = query->priv; @@ -490,7 +505,13 @@ func_occur_in_time_range (ESExp *esexp, int argc, ESExpResult **argv, void *data /* See if there is at least one instance in that range */ occurs = FALSE; - cal_recur_generate_instances (comp, start, end, instance_occur_cb, &occurs); + + /* Get the parent VCALENDAR component, so we can resolve TZIDs. */ + icalcomp = cal_component_get_icalcomponent (comp); + vcalendar_comp = icalcomponent_get_parent (icalcomp); + g_assert (vcalendar_comp != NULL); + + cal_recur_generate_instances (comp, start, end, instance_occur_cb, &occurs, resolve_tzid, vcalendar_comp); result = e_sexp_result_new (esexp, ESEXP_RES_BOOL); result->value.bool = occurs; |