aboutsummaryrefslogtreecommitdiffstats
path: root/calendar
diff options
context:
space:
mode:
authorDamon Chaplin <damon@ximian.com>2001-10-23 08:23:42 +0800
committerDamon Chaplin <damon@src.gnome.org>2001-10-23 08:23:42 +0800
commit04bda8ad1e0cb676d711dbf0f22ff9f4fb615891 (patch)
tree7f1ff1303c52e9b48a0006c500b204902b9d77c5 /calendar
parent68de308a89a844dcc579e1d9f24d7813d645c956 (diff)
downloadgsoc2013-evolution-04bda8ad1e0cb676d711dbf0f22ff9f4fb615891.tar.gz
gsoc2013-evolution-04bda8ad1e0cb676d711dbf0f22ff9f4fb615891.tar.zst
gsoc2013-evolution-04bda8ad1e0cb676d711dbf0f22ff9f4fb615891.zip
added setDefaultTimezone() method.
2001-10-22 Damon Chaplin <damon@ximian.com> * idl/evolution-calendar.idl: added setDefaultTimezone() method. * pcs/cal-backend.c (cal_backend_get_default_timezone): (cal_backend_set_default_timezone): new functions to call class methods. * pcs/cal-backend-file.c: lots of changes to handle the default timezone and use it. * pcs/query.c: use the default timezone. * gui/dialogs/task-details-page.c (date_changed_cb): initialized completed_tt. * gui/dialogs/event-page.c: changed it to handle DATE values. The 'All Day Event' checkbox is only set now when the DTSTART and DTEND are DATE values. * gui/dialogs/comp-editor-util.c (comp_editor_free_dates): free the CalComponentDateTime structs as well. * gui/e-tasks.c: set the default timezone on the server. * gui/tag-calendar.c: * gui/gnome-cal.c: * gui/e-week-view.c: * gui/e-day-view.c: updates to handle DATE values. * gui/e-calendar-table.c (date_compare_cb): updated to use the new ECellDateEditValue values, so it now works. (percent_compare_cb): updated to use GPOINTER_TO_INT values. (e_calendar_table_init): use an ECellPercent for the percent field and an ECellDateEditText for the date fields. * gui/comp-util.c (cal_comp_util_compare_event_timezones): return TRUE if the DTSTART or DTEND is a DATE value. We don't want to show the timezone icons for DATE values. * gui/comp-editor-factory.c (resolve_pending_requests): set the default timezone on the server. * gui/calendar-model.c: major changes to support sorting properly. For date and percent fields we now use subclasses of ECellText, so we don't use a char* as the model value. For the percent field we now use a GINT_TO_POINTER. For the date fields we now use a ECellDateEditValue* as the value. * gui/calendar-config.c (calendar_config_configure_e_cell_date_edit): set the timezone and use_24_hour flags of the new ECellDateEditText. * conduits/todo/todo-conduit.c (pre_sync): * conduits/calendar/calendar-conduit.c (pre_sync): set the default timezone on the server. * cal-util/timeutil.c (time_days_in_month): removed debug message. * cal-util/test-recur.c: try to handle timezones in the iCalendar file properly, and updated to pass default timezone. * cal-util/cal-util.c (cal_util_generate_alarms_for_comp): (cal_util_generate_alarms_for_list): added default timezone argument. * cal-util/cal-recur.c: changed many of the functions to take a default timezone, to use to resolve DATE and floating DATE-TIME values. * cal-client/cal-client.c (cal_client_set_default_timezone): new function to set the default timezone. (cal_client_ensure_timezone_on_server): new function to ensure that a given timezone is on the server. * gui/e-cell-date-edit-text.c: new subclass of ECellText to display and edit a date value. * cal-util/cal-recur.c (cal_obj_byday_expand_monthly): changed week_num to -week_num when calculating the weeks to go back from the end of the month for things like BYDAY=-2WE. Fixes bug #11525. (cal_recur_generate_instances_of_rule): only go up to MAX_YEAR (2037). We can't really handle anything past that anyway. (cal_recur_ensure_rule_end_date): initialize cb_date.end_date to 0, so if the RULE doesn't generate COUNT instances we save 0 as the time_t. svn path=/trunk/; revision=13920
Diffstat (limited to 'calendar')
-rw-r--r--calendar/ChangeLog84
-rw-r--r--calendar/cal-client/cal-client.c131
-rw-r--r--calendar/cal-client/cal-client.h6
-rw-r--r--calendar/cal-util/cal-component.c12
-rw-r--r--calendar/cal-util/cal-recur.c123
-rw-r--r--calendar/cal-util/cal-recur.h6
-rw-r--r--calendar/cal-util/cal-util.c15
-rw-r--r--calendar/cal-util/cal-util.h6
-rw-r--r--calendar/cal-util/test-recur.c27
-rw-r--r--calendar/cal-util/timeutil.c2
-rw-r--r--calendar/conduits/calendar/calendar-conduit.c4
-rw-r--r--calendar/conduits/todo/todo-conduit.c4
-rw-r--r--calendar/gui/Makefile.am2
-rw-r--r--calendar/gui/calendar-config.c14
-rw-r--r--calendar/gui/calendar-model.c480
-rw-r--r--calendar/gui/comp-editor-factory.c8
-rw-r--r--calendar/gui/comp-util.c8
-rw-r--r--calendar/gui/dialogs/comp-editor-util.c17
-rw-r--r--calendar/gui/dialogs/event-page.c408
-rw-r--r--calendar/gui/dialogs/task-details-page.c2
-rw-r--r--calendar/gui/e-calendar-table.c48
-rw-r--r--calendar/gui/e-cell-date-edit-text.c234
-rw-r--r--calendar/gui/e-cell-date-edit-text.h75
-rw-r--r--calendar/gui/e-day-view.c76
-rw-r--r--calendar/gui/e-tasks.c21
-rw-r--r--calendar/gui/e-week-view.c15
-rw-r--r--calendar/gui/gnome-cal.c38
-rw-r--r--calendar/gui/tag-calendar.c4
-rw-r--r--calendar/idl/evolution-calendar.idl22
-rw-r--r--calendar/pcs/cal-backend-file.c259
-rw-r--r--calendar/pcs/cal-backend.c49
-rw-r--r--calendar/pcs/cal-backend.h5
-rw-r--r--calendar/pcs/cal.c21
-rw-r--r--calendar/pcs/query.c8
34 files changed, 1592 insertions, 642 deletions
diff --git a/calendar/ChangeLog b/calendar/ChangeLog
index abd0b9cff0..0d3cafaabe 100644
--- a/calendar/ChangeLog
+++ b/calendar/ChangeLog
@@ -1,3 +1,87 @@
+2001-10-22 Damon Chaplin <damon@ximian.com>
+
+ * idl/evolution-calendar.idl: added setDefaultTimezone() method.
+
+ * pcs/cal-backend.c (cal_backend_get_default_timezone):
+ (cal_backend_set_default_timezone): new functions to call class
+ methods.
+
+ * pcs/cal-backend-file.c: lots of changes to handle the default
+ timezone and use it.
+
+ * pcs/query.c: use the default timezone.
+
+ * gui/dialogs/task-details-page.c (date_changed_cb): initialized
+ completed_tt.
+
+ * gui/dialogs/event-page.c: changed it to handle DATE values. The
+ 'All Day Event' checkbox is only set now when the DTSTART and DTEND
+ are DATE values.
+
+ * gui/dialogs/comp-editor-util.c (comp_editor_free_dates): free the
+ CalComponentDateTime structs as well.
+
+ * gui/e-tasks.c: set the default timezone on the server.
+
+ * gui/tag-calendar.c:
+ * gui/gnome-cal.c:
+ * gui/e-week-view.c:
+ * gui/e-day-view.c: updates to handle DATE values.
+
+ * gui/e-calendar-table.c (date_compare_cb): updated to use the new
+ ECellDateEditValue values, so it now works.
+ (percent_compare_cb): updated to use GPOINTER_TO_INT values.
+ (e_calendar_table_init): use an ECellPercent for the percent field
+ and an ECellDateEditText for the date fields.
+
+ * gui/comp-util.c (cal_comp_util_compare_event_timezones): return TRUE
+ if the DTSTART or DTEND is a DATE value. We don't want to show the
+ timezone icons for DATE values.
+
+ * gui/comp-editor-factory.c (resolve_pending_requests): set the default
+ timezone on the server.
+
+ * gui/calendar-model.c: major changes to support sorting properly.
+ For date and percent fields we now use subclasses of ECellText, so
+ we don't use a char* as the model value. For the percent field we now
+ use a GINT_TO_POINTER. For the date fields we now use a
+ ECellDateEditValue* as the value.
+
+ * gui/calendar-config.c (calendar_config_configure_e_cell_date_edit):
+ set the timezone and use_24_hour flags of the new ECellDateEditText.
+
+ * conduits/todo/todo-conduit.c (pre_sync):
+ * conduits/calendar/calendar-conduit.c (pre_sync): set the default
+ timezone on the server.
+
+ * cal-util/timeutil.c (time_days_in_month): removed debug message.
+
+ * cal-util/test-recur.c: try to handle timezones in the iCalendar
+ file properly, and updated to pass default timezone.
+
+ * cal-util/cal-util.c (cal_util_generate_alarms_for_comp):
+ (cal_util_generate_alarms_for_list): added default timezone argument.
+
+ * cal-util/cal-recur.c: changed many of the functions to take a default
+ timezone, to use to resolve DATE and floating DATE-TIME values.
+
+ * cal-client/cal-client.c (cal_client_set_default_timezone): new
+ function to set the default timezone.
+ (cal_client_ensure_timezone_on_server): new function to ensure that
+ a given timezone is on the server.
+
+ * gui/e-cell-date-edit-text.c: new subclass of ECellText to display
+ and edit a date value.
+
+ * cal-util/cal-recur.c (cal_obj_byday_expand_monthly): changed week_num
+ to -week_num when calculating the weeks to go back from the end of the
+ month for things like BYDAY=-2WE. Fixes bug #11525.
+ (cal_recur_generate_instances_of_rule): only go up to MAX_YEAR (2037).
+ We can't really handle anything past that anyway.
+ (cal_recur_ensure_rule_end_date): initialize cb_date.end_date to 0,
+ so if the RULE doesn't generate COUNT instances we save 0 as the
+ time_t.
+
2001-10-22 Federico Mena Quintero <federico@ximian.com>
* gui/tasks-control-factory.c (tasks_control_factory_fn): Put up a
diff --git a/calendar/cal-client/cal-client.c b/calendar/cal-client/cal-client.c
index f8ce2ff71b..79bfae2b1a 100644
--- a/calendar/cal-client/cal-client.c
+++ b/calendar/cal-client/cal-client.c
@@ -63,6 +63,10 @@ struct _CalClientPrivate {
/* A cache of timezones retrieved from the server, to avoid getting
them repeatedly for each get_object() call. */
GHashTable *timezones;
+
+ /* The default timezone to use to resolve DATE and floating DATE-TIME
+ values. */
+ icaltimezone *default_zone;
};
@@ -215,6 +219,7 @@ cal_client_init (CalClient *client)
priv->uri = NULL;
priv->factories = NULL;
priv->timezones = g_hash_table_new (g_str_hash, g_str_equal);
+ priv->default_zone = icaltimezone_get_utc_timezone ();
/* create the WombatClient */
priv->w_client = wombat_client_new (
@@ -1714,7 +1719,8 @@ cal_client_generate_instances (CalClient *client, CalObjType type,
comp = l->data;
cal_recur_generate_instances (comp, start, end, add_instance, &instances,
- cal_client_resolve_tzid_cb, client);
+ cal_client_resolve_tzid_cb, client,
+ priv->default_zone);
gtk_object_unref (GTK_OBJECT (comp));
}
@@ -2285,3 +2291,126 @@ cal_client_get_query (CalClient *client, const char *sexp)
return cal_query_new (priv->cal, sexp);
}
+
+
+/* This ensures that the given timezone is on the server. We use this to pass
+ the default timezone to the server, so it can resolve DATE and floating
+ DATE-TIME values into specific times. (Most of our IDL interface uses
+ time_t values to pass specific times from the server to the client.) */
+static gboolean
+cal_client_ensure_timezone_on_server (CalClient *client, icaltimezone *zone)
+{
+ CalClientPrivate *priv;
+ char *tzid, *obj_string;
+ icaltimezone *tmp_zone;
+ GString *vcal_string;
+ gboolean retval = FALSE;
+ icalcomponent *vtimezone_comp;
+ char *vtimezone_as_string;
+ CORBA_Environment ev;
+
+ priv = client->priv;
+
+ /* If the zone is NULL or UTC we don't need to do anything. */
+ if (!zone)
+ return TRUE;
+
+ tzid = icaltimezone_get_tzid (zone);
+
+ if (!strcmp (tzid, "UTC"))
+ return TRUE;
+
+ /* See if we already have it in the cache. If we do, it must be on
+ the server already. */
+ tmp_zone = g_hash_table_lookup (priv->timezones, tzid);
+ if (tmp_zone)
+ return TRUE;
+
+ /* Now we have to send it to the server, in case it doesn't already
+ have it. */
+
+ 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");
+
+ /* Convert the timezone to a string and add it. */
+ vtimezone_comp = icaltimezone_get_component (zone);
+ if (!vtimezone_comp) {
+ g_string_free (vcal_string, TRUE);
+ return FALSE;
+ }
+
+ /* We don't need to free this string as libical owns it. */
+ vtimezone_as_string = icalcomponent_as_ical_string (vtimezone_comp);
+ g_string_append (vcal_string, vtimezone_as_string);
+
+ g_string_append (vcal_string, "END:VCALENDAR\n");
+
+ obj_string = vcal_string->str;
+ g_string_free (vcal_string, FALSE);
+
+ CORBA_exception_init (&ev);
+ GNOME_Evolution_Calendar_Cal_updateObjects (priv->cal, obj_string, &ev);
+ g_free (obj_string);
+
+ if (BONOBO_USER_EX (&ev, ex_GNOME_Evolution_Calendar_Cal_InvalidObject))
+ goto out;
+ else if (BONOBO_EX (&ev)) {
+ g_message ("cal_client_ensure_timezone_on_server(): could not add the timezone to the server");
+ goto out;
+ }
+
+ retval = TRUE;
+
+ out:
+ CORBA_exception_free (&ev);
+ return retval;
+}
+
+
+gboolean
+cal_client_set_default_timezone (CalClient *client, icaltimezone *zone)
+{
+ CalClientPrivate *priv;
+ gboolean retval = FALSE;
+ CORBA_Environment ev;
+ const char *tzid;
+
+ g_return_val_if_fail (client != NULL, FALSE);
+ g_return_val_if_fail (IS_CAL_CLIENT (client), FALSE);
+ g_return_val_if_fail (zone != NULL, FALSE);
+
+ priv = client->priv;
+
+ g_return_val_if_fail (priv->load_state == CAL_CLIENT_LOAD_LOADED,
+ FALSE);
+
+ /* Make sure the server has the VTIMEZONE data. */
+ if (!cal_client_ensure_timezone_on_server (client, zone))
+ return FALSE;
+
+ /* Now set the default timezone on the server. */
+ CORBA_exception_init (&ev);
+ tzid = icaltimezone_get_tzid (zone);
+ GNOME_Evolution_Calendar_Cal_setDefaultTimezone (priv->cal,
+ (char *) tzid, &ev);
+
+ if (BONOBO_USER_EX (&ev, ex_GNOME_Evolution_Calendar_Cal_NotFound))
+ goto out;
+ else if (BONOBO_EX (&ev)) {
+ g_message ("cal_client_set_default_timezone(): could not set the default timezone");
+ goto out;
+ }
+
+ retval = TRUE;
+
+ priv->default_zone = zone;
+
+ out:
+
+ CORBA_exception_free (&ev);
+ return retval;
+}
+
diff --git a/calendar/cal-client/cal-client.h b/calendar/cal-client/cal-client.h
index 10614ef83f..36ff410fe1 100644
--- a/calendar/cal-client/cal-client.h
+++ b/calendar/cal-client/cal-client.h
@@ -108,6 +108,12 @@ CalClient *cal_client_new (void);
void cal_client_set_auth_func (CalClient *client, CalClientAuthFunc func, gpointer data);
+/* Sets the default timezone to use to resolve DATE and floating DATE-TIME
+ values. This will typically be from the user's timezone setting. Call this
+ before using any other functions. It will pass the default timezone on to
+ the server. Returns TRUE on success. */
+gboolean cal_client_set_default_timezone (CalClient *client, icaltimezone *zone);
+
gboolean cal_client_open_calendar (CalClient *client, const char *str_uri, gboolean only_if_exists);
GList *cal_client_uri_list (CalClient *client, CalMode mode);
diff --git a/calendar/cal-util/cal-component.c b/calendar/cal-util/cal-component.c
index 312556fd54..fb7c30f95b 100644
--- a/calendar/cal-util/cal-component.c
+++ b/calendar/cal-util/cal-component.c
@@ -1925,6 +1925,8 @@ set_datetime (CalComponent *comp, struct datetime *datetime,
priv = comp->priv;
+ /* If we are setting the property to NULL (i.e. removing it), then
+ we remove it if it exists. */
if (!dt) {
if (datetime->prop) {
icalcomponent_remove_property (priv->icalcomp, datetime->prop);
@@ -1942,10 +1944,12 @@ set_datetime (CalComponent *comp, struct datetime *datetime,
/* 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;
+ else
+ dt->value->is_utc = 0;
- if (datetime->prop)
+ if (datetime->prop) {
(* prop_set_func) (datetime->prop, *dt->value);
- else {
+ } else {
datetime->prop = (* prop_new_func) (*dt->value);
icalcomponent_add_property (priv->icalcomp, datetime->prop);
}
@@ -1954,9 +1958,9 @@ set_datetime (CalComponent *comp, struct datetime *datetime,
if (dt->tzid && strcmp (dt->tzid, "UTC")) {
g_assert (datetime->prop != NULL);
- if (datetime->tzid_param)
+ if (datetime->tzid_param) {
icalparameter_set_tzid (datetime->tzid_param, (char *) dt->tzid);
- else {
+ } else {
datetime->tzid_param = icalparameter_new_tzid ((char *) dt->tzid);
icalproperty_add_parameter (datetime->prop, datetime->tzid_param);
}
diff --git a/calendar/cal-util/cal-recur.c b/calendar/cal-util/cal-recur.c
index 83a0bccae9..28b1be9aec 100644
--- a/calendar/cal-util/cal-recur.c
+++ b/calendar/cal-util/cal-recur.c
@@ -104,8 +104,13 @@
* spec.
*/
+/* This is the maximum year we will go up to (inclusive). Since we use time_t
+ values we can't go past 2037 anyway, and some of our VTIMEZONEs may stop
+ at 2037 as well. */
+#define MAX_YEAR 2037
+
/* Define this for some debugging output. */
-#if 0
+#if 1
#define CAL_OBJ_DEBUG 1
#endif
@@ -264,11 +269,13 @@ static void cal_recur_generate_instances_of_rule (CalComponent *comp,
CalRecurInstanceFn cb,
gpointer cb_data,
CalRecurResolveTimezoneFn tz_cb,
- gpointer tz_cb_data);
+ gpointer tz_cb_data,
+ icaltimezone *default_timezone);
static CalRecurrence * cal_recur_from_icalproperty (icalproperty *prop,
gboolean exception,
- icaltimezone *zone);
+ icaltimezone *zone,
+ gboolean convert_end_date);
static gint cal_recur_ical_weekday_to_weekday (enum icalrecurrencetype_weekday day);
static void cal_recur_free (CalRecurrence *r);
@@ -294,6 +301,7 @@ static gboolean generate_instances_for_chunk (CalComponent *comp,
CalObjTime *chunk_end,
gint duration_days,
gint duration_seconds,
+ gboolean convert_end_date,
CalRecurInstanceFn cb,
gpointer cb_data);
@@ -487,7 +495,8 @@ static gboolean cal_recur_ensure_rule_end_date_cb (CalComponent *comp,
time_t instance_start,
time_t instance_end,
gpointer data);
-static time_t cal_recur_get_rule_end_date (icalproperty *prop);
+static time_t cal_recur_get_rule_end_date (icalproperty *prop,
+ icaltimezone *default_timezone);
static void cal_recur_set_rule_end_date (icalproperty *prop,
time_t end_date);
@@ -613,7 +622,8 @@ cal_recur_generate_instances (CalComponent *comp,
CalRecurInstanceFn cb,
gpointer cb_data,
CalRecurResolveTimezoneFn tz_cb,
- gpointer tz_cb_data)
+ gpointer tz_cb_data,
+ icaltimezone *default_timezone)
{
#if 0
g_print ("In cal_recur_generate_instances comp: %p\n", comp);
@@ -621,7 +631,8 @@ 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, tz_cb, tz_cb_data);
+ cb, cb_data, tz_cb, tz_cb_data,
+ default_timezone);
}
@@ -647,7 +658,8 @@ cal_recur_generate_instances_of_rule (CalComponent *comp,
CalRecurInstanceFn cb,
gpointer cb_data,
CalRecurResolveTimezoneFn tz_cb,
- gpointer tz_cb_data)
+ gpointer tz_cb_data,
+ icaltimezone *default_timezone)
{
CalComponentDateTime dtstart, dtend;
time_t dtstart_time, dtend_time;
@@ -656,11 +668,12 @@ cal_recur_generate_instances_of_rule (CalComponent *comp,
CalObjTime interval_start, interval_end, event_start, event_end;
CalObjTime chunk_start, chunk_end;
gint days, seconds, year;
- gboolean single_rule;
+ gboolean single_rule, convert_end_date = FALSE;
icaltimezone *start_zone = NULL, *end_zone = NULL;
g_return_if_fail (comp != NULL);
g_return_if_fail (cb != NULL);
+ g_return_if_fail (tz_cb != NULL);
g_return_if_fail (start >= -1);
g_return_if_fail (end >= -1);
@@ -675,15 +688,18 @@ cal_recur_generate_instances_of_rule (CalComponent *comp,
goto out;
}
- /* FIXME: All floating times, including those from recurrence rules,
- should be converted to the current timezone, otherwise the time_t
- values may be outside the given range. This may also mean that
- we need to add a timezone argument to the IDL method. */
-
- if (dtstart.tzid && tz_cb)
+ /* For DATE-TIME values with a TZID, we use the supplied callback to
+ resolve the TZID. For DATE values and DATE-TIME values without a
+ TZID (i.e. floating times) we use the default timezone. */
+ if (dtstart.tzid && !dtstart.value->is_date) {
start_zone = (*tz_cb) (dtstart.tzid, tz_cb_data);
- if (dtend.tzid && tz_cb)
- end_zone = (*tz_cb) (dtend.tzid, tz_cb_data);
+ } else {
+ start_zone = default_timezone;
+
+ /* Flag that we need to convert the saved ENDDATE property
+ to the default timezone. */
+ convert_end_date = TRUE;
+ }
dtstart_time = icaltime_as_timet_with_zone (*dtstart.value,
start_zone);
@@ -691,8 +707,22 @@ cal_recur_generate_instances_of_rule (CalComponent *comp,
start = dtstart_time;
/* FIXME: DURATION could be used instead, couldn't it? - Damon */
- if (!dtend.value) {
+
+ /* If there is no DTEND, then use the same as the DTSTART. For
+ DATE-TIME values that means we will just have a single point in
+ time. For DATE values it means we end up with the entire day. */
+ if (!dtend.value)
*dtend.value = *dtstart.value;
+
+ if (dtend.tzid && !dtend.value->is_date) {
+ end_zone = (*tz_cb) (dtend.tzid, tz_cb_data);
+ } else {
+ end_zone = default_timezone;
+ }
+
+ /* If DTEND is a DATE value, we add 1 day to it so that it includes
+ the entire day. */
+ if (dtend.value->is_date) {
dtend.value->hour = 0;
dtend.value->minute = 0;
dtend.value->second = 0;
@@ -768,7 +798,7 @@ cal_recur_generate_instances_of_rule (CalComponent *comp,
Though this does mean that we sometimes do a lot more work than
is necessary, e.g. if COUNT is set to something quite low. */
for (year = interval_start.year;
- end == -1 || year <= interval_end.year;
+ (end == -1 || year <= interval_end.year) && year <= MAX_YEAR;
year++) {
chunk_start = interval_start;
chunk_start.year = year;
@@ -801,6 +831,7 @@ cal_recur_generate_instances_of_rule (CalComponent *comp,
start,
&chunk_start, &chunk_end,
days, seconds,
+ convert_end_date,
cb, cb_data))
break;
}
@@ -833,9 +864,13 @@ array_to_list (short *array, int max_elements)
/**
* cal_recur_from_icalproperty:
- * @ir: An RRULE or EXRULE #icalproperty.
+ * @prop: An RRULE or EXRULE #icalproperty.
+ * @exception: TRUE if this is an EXRULE rather than an RRULE.
* @zone: The DTSTART timezone, used for converting the UNTIL property if it
* is given as a DATE value.
+ * @convert_end_date: TRUE if the saved end date needs to be converted to the
+ * given @zone timezone. This is needed if the DTSTART is a DATE or floating
+ * time.
*
* Converts an #icalproperty to a #CalRecurrence. This should be
* freed using the cal_recur_free() function.
@@ -844,7 +879,7 @@ array_to_list (short *array, int max_elements)
**/
static CalRecurrence *
cal_recur_from_icalproperty (icalproperty *prop, gboolean exception,
- icaltimezone *zone)
+ icaltimezone *zone, gboolean convert_end_date)
{
struct icalrecurrencetype ir;
CalRecurrence *r;
@@ -863,8 +898,10 @@ cal_recur_from_icalproperty (icalproperty *prop, gboolean exception,
r->interval = ir.interval;
if (ir.count != 0) {
- /* If COUNT is set, we use the pre-calculated enddate. */
- r->enddate = cal_recur_get_rule_end_date (prop);
+ /* If COUNT is set, we use the pre-calculated enddate.
+ Note that this can be 0 if the RULE doesn't actually
+ generate COUNT instances. */
+ r->enddate = cal_recur_get_rule_end_date (prop, convert_end_date ? zone : NULL);
} else {
if (icaltime_is_null_time (ir.until)) {
/* If neither COUNT or UNTIL is set, the event
@@ -1033,6 +1070,7 @@ generate_instances_for_chunk (CalComponent *comp,
CalObjTime *chunk_end,
gint duration_days,
gint duration_seconds,
+ gboolean convert_end_date,
CalRecurInstanceFn cb,
gpointer cb_data)
{
@@ -1079,7 +1117,8 @@ generate_instances_for_chunk (CalComponent *comp,
CalRecurrence *r;
prop = elem->data;
- r = cal_recur_from_icalproperty (prop, FALSE, zone);
+ r = cal_recur_from_icalproperty (prop, FALSE, zone,
+ convert_end_date);
tmp_occs = cal_obj_expand_recurrence (event_start, zone, r,
chunk_start,
@@ -1146,7 +1185,8 @@ generate_instances_for_chunk (CalComponent *comp,
CalRecurrence *r;
prop = elem->data;
- r = cal_recur_from_icalproperty (prop, FALSE, zone);
+ r = cal_recur_from_icalproperty (prop, FALSE, zone,
+ convert_end_date);
tmp_occs = cal_obj_expand_recurrence (event_start, zone, r,
chunk_start,
@@ -2986,8 +3026,15 @@ cal_obj_byday_expand_monthly (RecurData *recur_data,
occ->day = time_days_in_month (occ->year,
occ->month);
last_weekday = cal_obj_time_weekday (occ);
+
+ /* This calculates the number of days to step
+ backwards from the last day of the month
+ to the weekday we want. */
offset = (last_weekday + 7 - weekday) % 7;
- offset += (week_num - 1) * 7;
+
+ /* This adds on the weeks. */
+ offset += (-week_num - 1) * 7;
+
cal_obj_time_add_days (occ, -offset);
if (occ->year == year && occ->month == month)
g_array_append_vals (new_occs, occ, 1);
@@ -3780,16 +3827,22 @@ cal_recur_ensure_rule_end_date (CalComponent *comp,
/* If refresh is FALSE, we check if the enddate is already set, and
if it is we just return. */
if (!refresh) {
- if (cal_recur_get_rule_end_date (prop) != -1)
+ if (cal_recur_get_rule_end_date (prop, NULL) != -1)
return FALSE;
}
- /* Calculate the end date. */
+ /* Calculate the end date. Note that we initialize end_date to 0, so
+ if the RULE doesn't generate COUNT instances we save a time_t of 0.
+ Also note that we use the UTC timezone as the default timezone.
+ In get_end_date() if the DTSTART is a DATE or floating time, we will
+ convert the ENDDATE to the current timezone. */
cb_data.count = rule.count;
cb_data.instances = 0;
+ cb_data.end_date = 0;
cal_recur_generate_instances_of_rule (comp, prop, -1, -1,
cal_recur_ensure_rule_end_date_cb,
- &cb_data, tz_cb, tz_cb_data);
+ &cb_data, tz_cb, tz_cb_data,
+ icaltimezone_get_utc_timezone ());
/* Store the end date in the "X-EVOLUTION-ENDDATE" parameter of the
rule. */
@@ -3820,14 +3873,19 @@ cal_recur_ensure_rule_end_date_cb (CalComponent *comp,
}
+/* If default_timezone is set, the saved ENDDATE parameter is assumed to be
+ in that timezone. This is used when the DTSTART is a DATE or floating
+ value, since the RRULE end date will change depending on the timezone that
+ it is evaluated in. */
static time_t
-cal_recur_get_rule_end_date (icalproperty *prop)
+cal_recur_get_rule_end_date (icalproperty *prop,
+ icaltimezone *default_timezone)
{
icalparameter *param;
const char *xname, *xvalue;
icalvalue *value;
struct icaltimetype icaltime;
- icaltimezone *utc_zone;
+ icaltimezone *zone;
param = icalproperty_get_first_parameter (prop, ICAL_X_PARAMETER);
while (param) {
@@ -3840,9 +3898,10 @@ cal_recur_get_rule_end_date (icalproperty *prop)
icaltime = icalvalue_get_datetime (value);
icalvalue_free (value);
- utc_zone = icaltimezone_get_utc_timezone ();
+ zone = default_timezone ? default_timezone :
+ icaltimezone_get_utc_timezone ();
return icaltime_as_timet_with_zone (icaltime,
- utc_zone);
+ zone);
}
}
diff --git a/calendar/cal-util/cal-recur.h b/calendar/cal-util/cal-recur.h
index 921a230de4..3527368cba 100644
--- a/calendar/cal-util/cal-recur.h
+++ b/calendar/cal-util/cal-recur.h
@@ -52,6 +52,9 @@ typedef icaltimezone* (* CalRecurResolveTimezoneFn) (const char *tzid,
* 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.
+ *
+ * The default_timezone argument is used for DTSTART or DTEND properties that
+ * are DATE values or do not have a TZID (i.e. floating times).
*/
void cal_recur_generate_instances (CalComponent *comp,
time_t start,
@@ -59,7 +62,8 @@ void cal_recur_generate_instances (CalComponent *comp,
CalRecurInstanceFn cb,
gpointer cb_data,
CalRecurResolveTimezoneFn tz_cb,
- gpointer tz_cb_data);
+ gpointer tz_cb_data,
+ icaltimezone *default_timezone);
END_GNOME_DECLS
diff --git a/calendar/cal-util/cal-util.c b/calendar/cal-util/cal-util.c
index 774b9aca11..0819a56481 100644
--- a/calendar/cal-util/cal-util.c
+++ b/calendar/cal-util/cal-util.c
@@ -312,6 +312,8 @@ compare_alarm_instance (gconstpointer a, gconstpointer b)
* @end: end time
* @resolve_tzid: callback for resolving timezones
* @user_data: data to be passed to the resolve_tzid callback
+ * @default_timezone: the timezone used to resolve DATE and floating DATE-TIME
+ * values.
*
* Generates alarm instances for a calendar component. Returns the instances
* structure, or NULL if no alarm instances occurred in the specified time
@@ -322,7 +324,8 @@ cal_util_generate_alarms_for_comp (CalComponent *comp,
time_t start,
time_t end,
CalRecurResolveTimezoneFn resolve_tzid,
- gpointer user_data)
+ gpointer user_data,
+ icaltimezone *default_timezone)
{
GList *alarm_uids;
time_t alarm_start, alarm_end;
@@ -343,7 +346,8 @@ cal_util_generate_alarms_for_comp (CalComponent *comp,
cal_recur_generate_instances (comp, alarm_start, alarm_end,
add_alarm_occurrences_cb, &aod,
- resolve_tzid, user_data);
+ resolve_tzid, user_data,
+ default_timezone);
/* We add the ABSOLUTE triggers separately */
generate_absolute_triggers (comp, &aod);
@@ -369,6 +373,8 @@ cal_util_generate_alarms_for_comp (CalComponent *comp,
* @comp_alarms: list to be returned
* @resolve_tzid: callback for resolving timezones
* @user_data: data to be passed to the resolve_tzid callback
+ * @default_timezone: the timezone used to resolve DATE and floating DATE-TIME
+ * values.
*
* Iterates through all the components in the comps list and generates alarm
* instances for them; putting them in the comp_alarms list.
@@ -381,7 +387,8 @@ cal_util_generate_alarms_for_list (GList *comps,
time_t end,
GSList **comp_alarms,
CalRecurResolveTimezoneFn resolve_tzid,
- gpointer user_data)
+ gpointer user_data,
+ icaltimezone *default_timezone)
{
GList *l;
int n;
@@ -393,7 +400,7 @@ cal_util_generate_alarms_for_list (GList *comps,
CalComponentAlarms *alarms;
comp = CAL_COMPONENT (l->data);
- alarms = cal_util_generate_alarms_for_comp (comp, start, end, resolve_tzid, user_data);
+ alarms = cal_util_generate_alarms_for_comp (comp, start, end, resolve_tzid, user_data, default_timezone);
if (alarms) {
*comp_alarms = g_slist_prepend (*comp_alarms, alarms);
diff --git a/calendar/cal-util/cal-util.h b/calendar/cal-util/cal-util.h
index 9e7c7ce5e4..da16a61822 100644
--- a/calendar/cal-util/cal-util.h
+++ b/calendar/cal-util/cal-util.h
@@ -69,13 +69,15 @@ CalComponentAlarms *cal_util_generate_alarms_for_comp (CalComponent *comp,
time_t start,
time_t end,
CalRecurResolveTimezoneFn resolve_tzid,
- gpointer user_data);
+ gpointer user_data,
+ icaltimezone *default_timezone);
int cal_util_generate_alarms_for_list (GList *comps,
time_t start,
time_t end,
GSList **comp_alarms,
CalRecurResolveTimezoneFn resolve_tzid,
- gpointer user_data);
+ gpointer user_data,
+ icaltimezone *default_timezone);
icaltimezone *cal_util_resolve_tzid (const char *tzid, gpointer data);
diff --git a/calendar/cal-util/test-recur.c b/calendar/cal-util/test-recur.c
index 213017ea0e..de8cf23dc2 100644
--- a/calendar/cal-util/test-recur.c
+++ b/calendar/cal-util/test-recur.c
@@ -121,10 +121,31 @@ get_line (char *s,
}
+/* This resolves any TZIDs in the components. The VTIMEZONEs must be in the
+ file we are reading. */
+static icaltimezone*
+resolve_tzid_cb (const char *tzid,
+ gpointer user_data)
+{
+ icalcomponent *vcalendar_comp = user_data;
+
+ if (!tzid || !tzid[0])
+ return NULL;
+ else if (!strcmp (tzid, "UTC"))
+ return icaltimezone_get_utc_timezone ();
+
+ return icalcomponent_get_timezone (vcalendar_comp, tzid);
+}
+
+
static void
generate_occurrences (icalcomponent *icalcomp)
{
icalcompiter iter;
+ icaltimezone *default_timezone;
+
+ /* This is the timezone we will use for DATE and floating values. */
+ default_timezone = icaltimezone_get_utc_timezone ();
for (iter = icalcomponent_begin_component (icalcomp, ICAL_ANY_COMPONENT);
icalcompiter_deref (&iter) != NULL;
@@ -157,11 +178,13 @@ generate_occurrences (icalcomponent *icalcomp)
#if 0
cal_recur_generate_instances (comp, 982022400, 982108800,
occurrence_cb, &occurrences,
- NULL, NULL);
+ resolve_tzid_cb, icalcomp,
+ default_timezone);
#else
cal_recur_generate_instances (comp, -1, -1,
occurrence_cb, &occurrences,
- NULL, NULL);
+ resolve_tzid_cb, icalcomp,
+ default_timezone);
#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 aff465b8df..f960346477 100644
--- a/calendar/cal-util/timeutil.c
+++ b/calendar/cal-util/timeutil.c
@@ -367,8 +367,6 @@ time_days_in_month (int year, int month)
{
int days;
- g_print ("Year: %i Month: %i\n", year, month);
-
g_return_val_if_fail (year >= 1900, 0);
g_return_val_if_fail ((month >= 0) && (month < 12), 0);
diff --git a/calendar/conduits/calendar/calendar-conduit.c b/calendar/conduits/calendar/calendar-conduit.c
index 81c66041b6..b9f19489e7 100644
--- a/calendar/conduits/calendar/calendar-conduit.c
+++ b/calendar/conduits/calendar/calendar-conduit.c
@@ -948,6 +948,10 @@ pre_sync (GnomePilotConduit *conduit,
return -1;
LOG (" Using timezone: %s", icaltimezone_get_tzid (ctxt->timezone));
+ /* Set the default timezone on the backend. */
+ if (ctxt->timezone)
+ cal_client_set_default_timezone (ctxt->client, ctxt->timezone);
+
/* Load the uid <--> pilot id mapping */
filename = map_name (ctxt);
e_pilot_map_read (filename, &ctxt->map);
diff --git a/calendar/conduits/todo/todo-conduit.c b/calendar/conduits/todo/todo-conduit.c
index e2256904c6..ca59b04bd6 100644
--- a/calendar/conduits/todo/todo-conduit.c
+++ b/calendar/conduits/todo/todo-conduit.c
@@ -647,6 +647,10 @@ pre_sync (GnomePilotConduit *conduit,
return -1;
LOG (" Using timezone: %s", icaltimezone_get_tzid (ctxt->timezone));
+ /* Set the default timezone on the backend. */
+ if (ctxt->timezone)
+ cal_client_set_default_timezone (ctxt->client, ctxt->timezone);
+
/* Load the uid <--> pilot id map */
filename = map_name (ctxt);
e_pilot_map_read (filename, &ctxt->map);
diff --git a/calendar/gui/Makefile.am b/calendar/gui/Makefile.am
index 8b70da7f10..1a155efcd7 100644
--- a/calendar/gui/Makefile.am
+++ b/calendar/gui/Makefile.am
@@ -96,6 +96,8 @@ evolution_calendar_SOURCES = \
component-factory.h \
e-calendar-table.h \
e-calendar-table.c \
+ e-cell-date-edit-text.h \
+ e-cell-date-edit-text.c \
e-day-view-layout.c \
e-day-view-layout.h \
e-day-view-main-item.c \
diff --git a/calendar/gui/calendar-config.c b/calendar/gui/calendar-config.c
index 995eac2fb3..c4a3e12510 100644
--- a/calendar/gui/calendar-config.c
+++ b/calendar/gui/calendar-config.c
@@ -36,6 +36,7 @@
#include "component-factory.h"
#include "calendar-commands.h"
#include "e-tasks.h"
+#include "e-cell-date-edit-text.h"
#include "calendar-config.h"
#include <bonobo/bonobo-exception.h>
#include <bonobo/bonobo-moniker-util.h>
@@ -719,9 +720,19 @@ calendar_config_configure_e_cell_date_edit (ECellDateEdit *ecde)
{
gboolean use_24_hour;
gint start_hour, end_hour;
+ ECellPopup *ecp;
+ ECellDateEditText *ecd;
+ char *location;
+ icaltimezone *zone;
g_return_if_fail (E_IS_CELL_DATE_EDIT (ecde));
+ ecp = E_CELL_POPUP (ecde);
+ ecd = E_CELL_DATE_EDIT_TEXT (ecp->child);
+
+ location = calendar_config_get_timezone ();
+ zone = icaltimezone_get_builtin_timezone (location);
+
calendar_config_configure_e_calendar (E_CALENDAR (ecde->calendar));
use_24_hour = calendar_config_get_24_hour_format ();
@@ -743,6 +754,9 @@ calendar_config_configure_e_cell_date_edit (ECellDateEdit *ecde)
#endif
NULL);
e_cell_date_edit_thaw (ecde);
+
+ e_cell_date_edit_text_set_timezone (ecd, zone);
+ e_cell_date_edit_text_set_use_24_hour_format (ecd, use_24_hour);
}
diff --git a/calendar/gui/calendar-model.c b/calendar/gui/calendar-model.c
index 6b0dd31540..bb57586767 100644
--- a/calendar/gui/calendar-model.c
+++ b/calendar/gui/calendar-model.c
@@ -40,6 +40,7 @@
#include "itip-utils.h"
#include "calendar-model.h"
#include "evolution-activity-client.h"
+#include "e-cell-date-edit-text.h"
/* This specifies how often we refresh the list, so that completed tasks are
hidden according to the config setting, and overdue tasks change color etc.
@@ -48,6 +49,19 @@
lose their edit, so this isn't ideal. */
#define CALENDAR_MODEL_REFRESH_TIMEOUT 1000 * 60 * 10
+/* These hold the date values of the objects, so we can free the values when
+ we no longer need them. */
+typedef struct _CalendarModelObjectData CalendarModelObjectData;
+struct _CalendarModelObjectData {
+ ECellDateEditValue *dtstart;
+ ECellDateEditValue *dtend;
+ ECellDateEditValue *due;
+ ECellDateEditValue *completed;
+};
+
+/* We use a pointer to this value to indicate that the property is not set. */
+static ECellDateEditValue unset_date_edit_value;
+
/* Private part of the ECalendarModel structure */
struct _CalendarModelPrivate {
/* Calendar client we are using */
@@ -63,6 +77,10 @@ struct _CalendarModelPrivate {
/* Array of pointers to calendar objects */
GArray *objects;
+ /* Array of CalendarModelObjectData* holding data for each of the
+ objects in the objects array above. */
+ GArray *objects_data;
+
/* UID -> array index hash */
GHashTable *uid_index_hash;
@@ -207,6 +225,7 @@ calendar_model_init (CalendarModel *model)
priv->query = NULL;
priv->objects = g_array_new (FALSE, TRUE, sizeof (CalComponent *));
+ priv->objects_data = g_array_new (FALSE, FALSE, sizeof (CalendarModelObjectData));
priv->uid_index_hash = g_hash_table_new (g_str_hash, g_str_equal);
priv->new_comp_vtype = CAL_COMPONENT_EVENT;
priv->use_24_hour_format = TRUE;
@@ -221,6 +240,23 @@ calendar_model_init (CalendarModel *model)
priv->activity = NULL;
}
+static void
+calendar_model_free_object_data (CalendarModel *model,
+ CalendarModelObjectData *object_data)
+{
+ if (object_data->dtstart != &unset_date_edit_value)
+ g_free (object_data->dtstart);
+
+ if (object_data->dtend != &unset_date_edit_value)
+ g_free (object_data->dtend);
+
+ if (object_data->due != &unset_date_edit_value)
+ g_free (object_data->due);
+
+ if (object_data->completed != &unset_date_edit_value)
+ g_free (object_data->completed);
+}
+
/* Called from g_hash_table_foreach_remove(), frees a stored UID->index
* mapping.
*/
@@ -248,13 +284,19 @@ free_objects (CalendarModel *model)
for (i = 0; i < priv->objects->len; i++) {
CalComponent *comp;
+ CalendarModelObjectData *object_data;
comp = g_array_index (priv->objects, CalComponent *, i);
g_assert (comp != NULL);
gtk_object_unref (GTK_OBJECT (comp));
+
+ object_data = &g_array_index (priv->objects_data,
+ CalendarModelObjectData, i);
+ calendar_model_free_object_data (model, object_data);
}
g_array_set_size (priv->objects, 0);
+ g_array_set_size (priv->objects_data, 0);
}
/* Destroy handler for the calendar table model */
@@ -304,6 +346,9 @@ calendar_model_destroy (GtkObject *object)
g_array_free (priv->objects, TRUE);
priv->objects = NULL;
+ g_array_free (priv->objects_data, TRUE);
+ priv->objects_data = NULL;
+
g_free (priv->default_category);
itip_addresses_free (priv->addresses);
@@ -346,44 +391,6 @@ calendar_model_row_count (ETableModel *etm)
return priv->objects->len;
}
-/* Creates a nice string representation of a time value. If show_midnight is
- FALSE, and the time is midnight, then we just show the date. */
-static char*
-get_time_t (CalendarModel *model, time_t *t, gboolean show_midnight)
-{
- static char buffer[64];
- struct tm tmp_tm;
- struct icaltimetype tt;
-
- if (*t <= 0) {
- buffer[0] = '\0';
- } else {
- /* Note that although the property may be in a different
- timezone, we convert it to the current timezone to display
- it in the table. If the user actually edits the value,
- it will be set to the current timezone. See set_datetime. */
- 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;
-
- tmp_tm.tm_wday = time_day_of_week (tt.day, tt.month - 1,
- tt.year);
-
- e_time_format_date_and_time (&tmp_tm,
- model->priv->use_24_hour_format,
- show_midnight, FALSE,
- buffer, sizeof (buffer));
- }
-
- return buffer;
-}
-
/* Builds a string based on the list of CATEGORIES properties of a calendar
* component.
*/
@@ -417,79 +424,92 @@ get_classification (CalComponent *comp)
}
}
-/* Builds a string for the COMPLETED property of a calendar component */
-static char *
+/* Returns an ECellDateEditValue* for a COMPLETED property of a
+ calendar component. Note that we cache these in the objects_data array so
+ we can free them eventually. */
+static ECellDateEditValue*
get_completed (CalendarModel *model,
- CalComponent *comp)
+ CalComponent *comp,
+ int row)
{
+ CalendarModelPrivate *priv;
+ CalComponentDateTime dt;
+ CalendarModelObjectData *object_data;
struct icaltimetype *completed;
- time_t t;
- cal_component_get_completed (comp, &completed);
+ priv = model->priv;
+
+ object_data = &g_array_index (priv->objects_data,
+ CalendarModelObjectData, row);
- if (!completed)
- t = 0;
- else {
- /* Note that COMPLETED is stored in UTC, though we show it in
- the current timezone. */
- t = icaltime_as_timet_with_zone (*completed, icaltimezone_get_utc_timezone ());
- cal_component_free_icaltimetype (completed);
+ if (!object_data->completed) {
+ cal_component_get_completed (comp, &completed);
+
+ if (completed) {
+ object_data->completed = g_new (ECellDateEditValue, 1);
+ object_data->completed->tt = *dt.value;
+ object_data->completed->zone = icaltimezone_get_utc_timezone ();
+ cal_component_free_icaltimetype (completed);
+ } else {
+ object_data->completed = &unset_date_edit_value;
+ }
}
- return get_time_t (model, &t, TRUE);
+ return (object_data->completed == &unset_date_edit_value)
+ ? NULL : object_data->completed;
}
-/* Builds a string for and frees a date/time value */
-static char *
-get_and_free_datetime (CalendarModel *model, CalComponentDateTime dt)
+/* Returns an ECellDateEditValue* for a DTSTART, DTEND or DUE property of a
+ calendar component. Note that we cache these in the objects_data array so
+ we can free them eventually. */
+static ECellDateEditValue*
+get_date_edit_value (CalendarModel *model, CalComponent *comp,
+ int col, int row)
{
- time_t t;
-
- if (!dt.value)
- t = 0;
- else {
- CalClientGetStatus status;
- icaltimezone *zone;
+ CalendarModelPrivate *priv;
+ CalComponentDateTime dt;
+ CalendarModelObjectData *object_data;
+ ECellDateEditValue **value;
- /* FIXME: TIMEZONES: Handle error. */
- status = cal_client_get_timezone (model->priv->client, dt.tzid,
- &zone);
- t = icaltime_as_timet_with_zone (*dt.value, zone);
- }
+ priv = model->priv;
- cal_component_free_datetime (&dt);
+ object_data = &g_array_index (priv->objects_data,
+ CalendarModelObjectData, row);
- return get_time_t (model, &t, TRUE);
-}
+ if (col == CAL_COMPONENT_FIELD_DTSTART)
+ value = &object_data->dtstart;
+ else if (col == CAL_COMPONENT_FIELD_DTEND)
+ value = &object_data->dtend;
+ else
+ value = &object_data->due;
-/* Builds a string for the DTEND property of a calendar component */
-static char *
-get_dtend (CalendarModel *model, CalComponent *comp)
-{
- CalComponentDateTime dt;
+ if (!(*value)) {
+ if (col == CAL_COMPONENT_FIELD_DTSTART)
+ cal_component_get_dtstart (comp, &dt);
+ else if (col == CAL_COMPONENT_FIELD_DTEND)
+ cal_component_get_dtend (comp, &dt);
+ else
+ cal_component_get_due (comp, &dt);
- cal_component_get_dtend (comp, &dt);
- return get_and_free_datetime (model, dt);
-}
+ if (dt.value) {
+ CalClientGetStatus status;
+ icaltimezone *zone;
-/* Builds a string for the DTSTART property of a calendar component */
-static char *
-get_dtstart (CalendarModel *model, CalComponent *comp)
-{
- CalComponentDateTime dt;
+ *value = g_new (ECellDateEditValue, 1);
+ (*value)->tt = *dt.value;
- cal_component_get_dtstart (comp, &dt);
- return get_and_free_datetime (model, dt);
-}
+ /* FIXME: TIMEZONES: Handle error. */
+ status = cal_client_get_timezone (model->priv->client,
+ dt.tzid, &zone);
+ (*value)->zone = zone;
+ } else {
+ *value = &unset_date_edit_value;
+ }
-/* Builds a string for the DUE property of a calendar component */
-static char *
-get_due (CalendarModel *model, CalComponent *comp)
-{
- CalComponentDateTime dt;
+ cal_component_free_datetime (&dt);
+ }
- cal_component_get_due (comp, &dt);
- return get_and_free_datetime (model, dt);
+ return (*value == &unset_date_edit_value) ? NULL : *value;
}
/* Builds a string for the GEO property of a calendar component */
@@ -516,22 +536,21 @@ get_geo (CalComponent *comp)
}
/* Builds a string for the PERCENT property of a calendar component */
-static char *
+static int
get_percent (CalComponent *comp)
{
- int *percent;
- static char buf[32];
+ int *percent, retval;
cal_component_get_percent (comp, &percent);
- if (!percent)
- buf[0] = '\0';
- else {
- g_snprintf (buf, sizeof (buf), "%d%%", *percent);
+ if (percent) {
+ retval = *percent;
cal_component_free_percent (percent);
+ } else {
+ retval = -1;
}
- return buf;
+ return retval;
}
/* Builds a string for the PRIORITY property of a calendar component */
@@ -748,7 +767,7 @@ get_location (CalComponent *comp)
const char *location;
cal_component_get_location (comp, &location);
- return location;
+ return (void*) location;
}
/* value_at handler for the calendar table model */
@@ -780,22 +799,18 @@ calendar_model_value_at (ETableModel *etm, int col, int row)
return get_classification (comp);
case CAL_COMPONENT_FIELD_COMPLETED:
- return get_completed (model, comp);
+ return get_completed (model, comp, row);
case CAL_COMPONENT_FIELD_DTEND:
- return get_dtend (model, comp);
-
case CAL_COMPONENT_FIELD_DTSTART:
- return get_dtstart (model, comp);
-
case CAL_COMPONENT_FIELD_DUE:
- return get_due (model, comp);
+ return get_date_edit_value (model, comp, col, row);
case CAL_COMPONENT_FIELD_GEO:
return get_geo (comp);
case CAL_COMPONENT_FIELD_PERCENT:
- return get_percent (comp);
+ return GINT_TO_POINTER (get_percent (comp));
case CAL_COMPONENT_FIELD_PRIORITY:
return get_priority (comp);
@@ -900,7 +915,7 @@ string_is_empty (const char *value)
if (value) {
p = value;
while (*p) {
- if (!isspace (*p)) {
+ if (!isspace ((unsigned char) *p)) {
empty = FALSE;
break;
}
@@ -911,40 +926,6 @@ string_is_empty (const char *value)
}
-/* FIXME: We need to set the "transient_for" property for the dialog, but
- the model doesn't know anything about the windows. */
-static void
-show_date_warning (CalendarModel *model)
-{
- GtkWidget *dialog;
- char buffer[64], message[256], *format;
- time_t t;
- 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)
- /* strftime format of a weekday, a date and a time, 24-hour. */
- format = _("%a %m/%d/%Y %H:%M:%S");
- else
- /* strftime format of a weekday, a date and a time, 12-hour. */
- format = _("%a %m/%d/%Y %I:%M:%S %p");
-
- strftime (buffer, sizeof (buffer), format, tmp_tm);
-
- g_snprintf (message, 256,
- _("The date must be entered in the format: \n\n%s"),
- buffer);
-
- dialog = gnome_message_box_new (message,
- GNOME_MESSAGE_BOX_ERROR,
- GNOME_STOCK_BUTTON_OK, NULL);
- gtk_widget_show (dialog);
-}
-
/* Builds a list of categories from a comma-delimited string */
static GSList *
categories_from_string (const char *value)
@@ -1028,31 +1009,18 @@ set_classification (CalComponent *comp,
/* Called to set the "Date Completed" field. We also need to update the
Status and Percent fields to make sure they match. */
static void
-set_completed (CalendarModel *model, CalComponent *comp, const char *value)
+set_completed (CalendarModel *model, CalComponent *comp, const void *value)
{
- ETimeParseStatus status;
- struct tm tmp_tm;
- time_t t;
+ ECellDateEditValue *dv = (ECellDateEditValue*) value;
- status = e_time_parse_date_and_time (value, &tmp_tm);
-
- if (status == E_TIME_PARSE_INVALID) {
- show_date_warning (model);
- } else if (status == E_TIME_PARSE_NONE) {
+ if (!dv) {
ensure_task_not_complete (comp);
} else {
- 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;
+ time_t t;
/* We assume that COMPLETED is entered in the current timezone,
even though it gets stored in UTC. */
- t = icaltime_as_timet_with_zone (itt, model->priv->zone);
+ t = icaltime_as_timet_with_zone (dv->tt, dv->zone);
ensure_task_complete (comp, t);
}
@@ -1060,33 +1028,18 @@ set_completed (CalendarModel *model, CalComponent *comp, const char *value)
/* Sets a CalComponentDateTime value */
static void
-set_datetime (CalendarModel *model, CalComponent *comp, const char *value,
+set_datetime (CalendarModel *model, CalComponent *comp, const void *value,
void (* set_func) (CalComponent *comp, CalComponentDateTime *dt))
{
- ETimeParseStatus status;
- struct tm tmp_tm;
+ ECellDateEditValue *dv = (ECellDateEditValue*) value;
- status = e_time_parse_date_and_time (value, &tmp_tm);
-
- if (status == E_TIME_PARSE_INVALID) {
- show_date_warning (model);
- } else if (status == E_TIME_PARSE_NONE) {
+ if (!dv) {
(* set_func) (comp, NULL);
} else {
CalComponentDateTime dt;
- 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;
- dt.value = &itt;
- /* FIXME: We assume it is being set to the current timezone.
- Is that OK? */
- dt.tzid = icaltimezone_get_tzid (model->priv->zone);
+ dt.value = &dv->tt;
+ dt.tzid = icaltimezone_get_tzid (dv->zone);
(* set_func) (comp, &dt);
}
@@ -1132,45 +1085,27 @@ set_geo (CalComponent *comp, const char *value)
cal_component_set_geo (comp, &geo);
}
-/* FIXME: We need to set the "transient_for" property for the dialog, but the
- * model doesn't know anything about the windows.
- */
-static void
-show_percent_warning (void)
-{
- GtkWidget *dialog;
-
- dialog = gnome_message_box_new (_("The percent value must be between 0 and 100, inclusive"),
- GNOME_MESSAGE_BOX_ERROR,
- GNOME_STOCK_BUTTON_OK, NULL);
- gtk_widget_show (dialog);
-}
-
/* Sets the percent value of a calendar component */
static void
-set_percent (CalComponent *comp, const char *value)
+set_percent (CalComponent *comp, const void *value)
{
- int matched, percent;
+ gint percent = GPOINTER_TO_INT (value);
- if (string_is_empty (value)) {
+ g_return_if_fail (percent >= -1);
+ g_return_if_fail (percent <= 100);
+
+ /* A value of -1 means it isn't set. */
+ if (percent == -1) {
cal_component_set_percent (comp, NULL);
ensure_task_not_complete (comp);
- return;
- }
-
- matched = sscanf (value, "%i", &percent);
+ } else {
+ cal_component_set_percent (comp, &percent);
- if (matched != 1 || percent < 0 || percent > 100) {
- show_percent_warning ();
- return;
+ if (percent == 100)
+ ensure_task_complete (comp, -1);
+ else
+ ensure_task_not_complete (comp);
}
-
- cal_component_set_percent (comp, &percent);
-
- if (percent == 100)
- ensure_task_complete (comp, -1);
- else
- ensure_task_not_complete (comp);
}
/* Sets the priority of a calendar component */
@@ -1476,6 +1411,19 @@ dup_string (const char *value)
return g_strdup (value);
}
+static void*
+dup_date_edit_value (const void *value)
+{
+ ECellDateEditValue *dv, *orig_dv;
+
+ orig_dv = (ECellDateEditValue*) value;
+
+ dv = g_new (ECellDateEditValue, 1);
+ *dv = *orig_dv;
+
+ return dv;
+}
+
/* duplicate_value handler for the calendar table model */
static void *
calendar_model_duplicate_value (ETableModel *etm, int col, const void *value)
@@ -1489,12 +1437,7 @@ calendar_model_duplicate_value (ETableModel *etm, int col, const void *value)
switch (col) {
case CAL_COMPONENT_FIELD_CATEGORIES:
case CAL_COMPONENT_FIELD_CLASSIFICATION:
- case CAL_COMPONENT_FIELD_COMPLETED:
- case CAL_COMPONENT_FIELD_DTEND:
- case CAL_COMPONENT_FIELD_DTSTART:
- case CAL_COMPONENT_FIELD_DUE:
case CAL_COMPONENT_FIELD_GEO:
- case CAL_COMPONENT_FIELD_PERCENT:
case CAL_COMPONENT_FIELD_PRIORITY:
case CAL_COMPONENT_FIELD_SUMMARY:
case CAL_COMPONENT_FIELD_TRANSPARENCY:
@@ -1502,9 +1445,16 @@ calendar_model_duplicate_value (ETableModel *etm, int col, const void *value)
case CAL_COMPONENT_FIELD_STATUS:
return dup_string (value);
+ case CAL_COMPONENT_FIELD_COMPLETED:
+ case CAL_COMPONENT_FIELD_DTEND:
+ case CAL_COMPONENT_FIELD_DTSTART:
+ case CAL_COMPONENT_FIELD_DUE:
+ return dup_date_edit_value (value);
+
case CAL_COMPONENT_FIELD_HAS_ALARMS:
case CAL_COMPONENT_FIELD_ICON:
case CAL_COMPONENT_FIELD_COMPLETE:
+ case CAL_COMPONENT_FIELD_PERCENT:
case CAL_COMPONENT_FIELD_RECURRING:
case CAL_COMPONENT_FIELD_OVERDUE:
case CAL_COMPONENT_FIELD_COLOR:
@@ -1544,7 +1494,6 @@ calendar_model_free_value (ETableModel *etm, int col, void *value)
case CAL_COMPONENT_FIELD_DTSTART:
case CAL_COMPONENT_FIELD_DUE:
case CAL_COMPONENT_FIELD_GEO:
- case CAL_COMPONENT_FIELD_PERCENT:
case CAL_COMPONENT_FIELD_PRIORITY:
case CAL_COMPONENT_FIELD_SUMMARY:
case CAL_COMPONENT_FIELD_STATUS:
@@ -1560,6 +1509,7 @@ calendar_model_free_value (ETableModel *etm, int col, void *value)
g_free (value);
break;
+ case CAL_COMPONENT_FIELD_PERCENT:
case CAL_COMPONENT_FIELD_HAS_ALARMS:
case CAL_COMPONENT_FIELD_ICON:
case CAL_COMPONENT_FIELD_COMPLETE:
@@ -1600,12 +1550,7 @@ calendar_model_initialize_value (ETableModel *etm, int col)
return g_strdup (model->priv->default_category ? model->priv->default_category : "");
case CAL_COMPONENT_FIELD_CLASSIFICATION:
- case CAL_COMPONENT_FIELD_COMPLETED:
- case CAL_COMPONENT_FIELD_DTEND:
- case CAL_COMPONENT_FIELD_DTSTART:
- case CAL_COMPONENT_FIELD_DUE:
case CAL_COMPONENT_FIELD_GEO:
- case CAL_COMPONENT_FIELD_PERCENT:
case CAL_COMPONENT_FIELD_PRIORITY:
case CAL_COMPONENT_FIELD_SUMMARY:
case CAL_COMPONENT_FIELD_TRANSPARENCY:
@@ -1613,6 +1558,10 @@ calendar_model_initialize_value (ETableModel *etm, int col)
case CAL_COMPONENT_FIELD_STATUS:
return init_string ();
+ case CAL_COMPONENT_FIELD_COMPLETED:
+ case CAL_COMPONENT_FIELD_DTEND:
+ case CAL_COMPONENT_FIELD_DTSTART:
+ case CAL_COMPONENT_FIELD_DUE:
case CAL_COMPONENT_FIELD_HAS_ALARMS:
case CAL_COMPONENT_FIELD_ICON:
case CAL_COMPONENT_FIELD_COMPLETE:
@@ -1622,6 +1571,9 @@ calendar_model_initialize_value (ETableModel *etm, int col)
case CAL_COMPONENT_FIELD_COMPONENT:
return NULL;
+ case CAL_COMPONENT_FIELD_PERCENT:
+ return GINT_TO_POINTER (-1);
+
default:
g_message ("calendar_model_initialize_value(): Requested invalid column %d", col);
return NULL;
@@ -1657,12 +1609,7 @@ calendar_model_value_is_empty (ETableModel *etm, int col, const void *value)
return string_is_empty (value);
case CAL_COMPONENT_FIELD_CLASSIFICATION: /* actually goes here, not by itself */
- case CAL_COMPONENT_FIELD_COMPLETED:
- case CAL_COMPONENT_FIELD_DTEND:
- case CAL_COMPONENT_FIELD_DTSTART:
- case CAL_COMPONENT_FIELD_DUE:
case CAL_COMPONENT_FIELD_GEO:
- case CAL_COMPONENT_FIELD_PERCENT:
case CAL_COMPONENT_FIELD_PRIORITY:
case CAL_COMPONENT_FIELD_SUMMARY:
case CAL_COMPONENT_FIELD_TRANSPARENCY:
@@ -1670,6 +1617,15 @@ calendar_model_value_is_empty (ETableModel *etm, int col, const void *value)
case CAL_COMPONENT_FIELD_STATUS:
return string_is_empty (value);
+ case CAL_COMPONENT_FIELD_COMPLETED:
+ case CAL_COMPONENT_FIELD_DTEND:
+ case CAL_COMPONENT_FIELD_DTSTART:
+ case CAL_COMPONENT_FIELD_DUE:
+ return value ? FALSE : TRUE;
+
+ case CAL_COMPONENT_FIELD_PERCENT:
+ return (GPOINTER_TO_INT (value) < 0) ? TRUE : FALSE;
+
case CAL_COMPONENT_FIELD_HAS_ALARMS:
case CAL_COMPONENT_FIELD_ICON:
case CAL_COMPONENT_FIELD_COMPLETE:
@@ -1685,6 +1641,43 @@ calendar_model_value_is_empty (ETableModel *etm, int col, const void *value)
}
}
+static char*
+date_value_to_string (ETableModel *etm, const void *value)
+{
+ CalendarModel *model;
+ CalendarModelPrivate *priv;
+ ECellDateEditValue *dv = (ECellDateEditValue *) value;
+ struct icaltimetype tt;
+ struct tm tmp_tm;
+ char buffer[64];
+
+ model = CALENDAR_MODEL (etm);
+ priv = model->priv;
+
+ if (!dv)
+ return g_strdup ("");
+
+ /* We currently convert all the dates to the current timezone. */
+ tt = dv->tt;
+ icaltimezone_convert_time (&tt, dv->zone, priv->zone);
+
+ tmp_tm.tm_year = tt.year - 1900;
+ tmp_tm.tm_mon = tt.month - 1;
+ tmp_tm.tm_mday = tt.day;
+ tmp_tm.tm_hour = tt.hour;
+ tmp_tm.tm_min = tt.minute;
+ tmp_tm.tm_sec = tt.second;
+ tmp_tm.tm_isdst = -1;
+
+ tmp_tm.tm_wday = time_day_of_week (tt.day, tt.month - 1, tt.year);
+
+ e_time_format_date_and_time (&tmp_tm, priv->use_24_hour_format,
+ TRUE, FALSE,
+ buffer, sizeof (buffer));
+ return g_strdup (buffer);
+}
+
+
static char *
calendar_model_value_to_string (ETableModel *etm, int col, const void *value)
{
@@ -1693,12 +1686,7 @@ calendar_model_value_to_string (ETableModel *etm, int col, const void *value)
switch (col) {
case CAL_COMPONENT_FIELD_CATEGORIES:
case CAL_COMPONENT_FIELD_CLASSIFICATION:
- case CAL_COMPONENT_FIELD_COMPLETED:
- case CAL_COMPONENT_FIELD_DTEND:
- case CAL_COMPONENT_FIELD_DTSTART:
- case CAL_COMPONENT_FIELD_DUE:
case CAL_COMPONENT_FIELD_GEO:
- case CAL_COMPONENT_FIELD_PERCENT:
case CAL_COMPONENT_FIELD_PRIORITY:
case CAL_COMPONENT_FIELD_SUMMARY:
case CAL_COMPONENT_FIELD_TRANSPARENCY:
@@ -1706,10 +1694,16 @@ calendar_model_value_to_string (ETableModel *etm, int col, const void *value)
case CAL_COMPONENT_FIELD_STATUS:
return e_utf8_from_locale_string (value);
+ case CAL_COMPONENT_FIELD_COMPLETED:
+ case CAL_COMPONENT_FIELD_DTEND:
+ case CAL_COMPONENT_FIELD_DTSTART:
+ case CAL_COMPONENT_FIELD_DUE:
+ return date_value_to_string (etm, value);
+
case CAL_COMPONENT_FIELD_ICON:
- if ((int)value == 0)
+ if (GPOINTER_TO_INT (value) == 0)
return e_utf8_from_locale_string (_("Normal"));
- else if ((int)value == 1)
+ else if (GPOINTER_TO_INT (value) == 1)
return e_utf8_from_locale_string (_("Recurring"));
else
return e_utf8_from_locale_string (_("Assigned"));
@@ -1726,6 +1720,12 @@ calendar_model_value_to_string (ETableModel *etm, int col, const void *value)
case CAL_COMPONENT_FIELD_COMPONENT:
return NULL;
+ case CAL_COMPONENT_FIELD_PERCENT:
+ if (GPOINTER_TO_INT (value) < 0)
+ return NULL;
+ else
+ return g_strdup_printf ("%i%%", GPOINTER_TO_INT (value));
+
default:
g_message ("calendar_model_value_as_string(): Requested invalid column %d", col);
return NULL;
@@ -1762,6 +1762,7 @@ query_obj_updated_cb (CalQuery *query, const char *uid,
const char *new_comp_uid;
int *new_idx;
CalClientGetStatus status;
+ CalendarModelObjectData new_object_data = { NULL, NULL, NULL, NULL };
model = CALENDAR_MODEL (data);
priv = model->priv;
@@ -1780,6 +1781,7 @@ query_obj_updated_cb (CalQuery *query, const char *uid,
/* The object not in the model originally, so we just append it */
g_array_append_val (priv->objects, new_comp);
+ g_array_append_val (priv->objects_data, new_object_data);
new_idx = g_new (int, 1);
*new_idx = priv->objects->len - 1;
@@ -1792,6 +1794,8 @@ query_obj_updated_cb (CalQuery *query, const char *uid,
/* Insert the new version of the object in its old position */
g_array_insert_val (priv->objects, orig_idx, new_comp);
+ g_array_insert_val (priv->objects_data, orig_idx,
+ new_object_data);
new_idx = g_new (int, 1);
*new_idx = orig_idx;
@@ -2053,6 +2057,7 @@ remove_object (CalendarModel *model, const char *uid)
CalComponent *orig_comp;
int i;
int n;
+ CalendarModelObjectData *object_data;
priv = model->priv;
@@ -2089,6 +2094,11 @@ remove_object (CalendarModel *model, const char *uid)
g_hash_table_remove (priv->uid_index_hash, uid);
g_array_remove_index (priv->objects, *idx);
+ object_data = &g_array_index (priv->objects_data,
+ CalendarModelObjectData, *idx);
+ calendar_model_free_object_data (model, object_data);
+ g_array_remove_index (priv->objects_data, *idx);
+
gtk_object_unref (GTK_OBJECT (orig_comp));
n = *idx;
diff --git a/calendar/gui/comp-editor-factory.c b/calendar/gui/comp-editor-factory.c
index 2c74649647..23920c1592 100644
--- a/calendar/gui/comp-editor-factory.c
+++ b/calendar/gui/comp-editor-factory.c
@@ -419,12 +419,20 @@ resolve_pending_requests (OpenClient *oc)
CompEditorFactory *factory;
CompEditorFactoryPrivate *priv;
GSList *l;
+ char *location;
+ icaltimezone *zone;
factory = oc->factory;
priv = factory->priv;
g_assert (oc->pending != NULL);
+ /* Set the default timezone in the backend. */
+ location = calendar_config_get_timezone ();
+ zone = icaltimezone_get_builtin_timezone (location);
+ if (zone)
+ cal_client_set_default_timezone (oc->client, zone);
+
for (l = oc->pending; l; l = l->next) {
Request *request;
diff --git a/calendar/gui/comp-util.c b/calendar/gui/comp-util.c
index 995e69a270..f9a6c0efec 100644
--- a/calendar/gui/comp-util.c
+++ b/calendar/gui/comp-util.c
@@ -105,6 +105,14 @@ cal_comp_util_compare_event_timezones (CalComponent *comp,
cal_component_get_dtstart (comp, &start_datetime);
cal_component_get_dtend (comp, &end_datetime);
+ /* If either the DTSTART or the DTEND is a DATE value, we return TRUE.
+ Maybe if one was a DATE-TIME we should check that, but that should
+ not happen often. */
+ if (start_datetime.value->is_date || end_datetime.value->is_date) {
+ retval = TRUE;
+ goto out;
+ }
+
/* FIXME: DURATION may be used instead. */
if (cal_component_compare_tzid (tzid, start_datetime.tzid)
&& cal_component_compare_tzid (tzid, end_datetime.tzid)) {
diff --git a/calendar/gui/dialogs/comp-editor-util.c b/calendar/gui/dialogs/comp-editor-util.c
index 5d10942a5e..77939beee8 100644
--- a/calendar/gui/dialogs/comp-editor-util.c
+++ b/calendar/gui/dialogs/comp-editor-util.c
@@ -59,6 +59,9 @@ comp_editor_dates (CompEditorPageDates *dates, CalComponent *comp)
dates->due = NULL;
dates->complete = NULL;
+ /* Note that the CalComponentDateTime's returned contain allocated
+ icaltimetype and tzid values, so we just take over ownership of
+ those. */
cal_component_get_dtstart (comp, &dt);
if (dt.value) {
dates->start = g_new (CalComponentDateTime, 1);
@@ -87,14 +90,22 @@ comp_editor_dates (CompEditorPageDates *dates, CalComponent *comp)
void
comp_editor_free_dates (CompEditorPageDates *dates)
{
- if (dates->start)
+ /* Note that cal_component_free_datetime() only frees the fields in
+ the struct. It doesn't free the struct itself, so we do that. */
+ if (dates->start) {
cal_component_free_datetime (dates->start);
+ g_free (dates->start);
+ }
- if (dates->end)
+ if (dates->end) {
cal_component_free_datetime (dates->end);
+ g_free (dates->end);
+ }
- if (dates->due)
+ if (dates->due) {
cal_component_free_datetime (dates->due);
+ g_free (dates->due);
+ }
if (dates->complete)
cal_component_free_icaltimetype (dates->complete);
diff --git a/calendar/gui/dialogs/event-page.c b/calendar/gui/dialogs/event-page.c
index a3c8041933..f4a849db11 100644
--- a/calendar/gui/dialogs/event-page.c
+++ b/calendar/gui/dialogs/event-page.c
@@ -268,29 +268,15 @@ event_page_focus_main_widget (CompEditorPage *page)
gtk_widget_grab_focus (priv->summary);
}
-/* Checks if the event's time starts and ends at midnight, and sets the
- *"all day event" box accordingly.
- */
+/* Sets the 'All Day Event' flag to the given value (without emitting signals),
+ * and shows or hides the widgets as appropriate. */
static void
-check_all_day (EventPage *epage)
+set_all_day (EventPage *epage, gboolean all_day)
{
EventPagePrivate *priv;
- gboolean all_day = FALSE, start_set, end_set;
- gint start_hour, start_minute, end_hour, end_minute;
priv = epage->priv;
- start_set = e_date_edit_get_time_of_day (E_DATE_EDIT (priv->start_time),
- &start_hour, &start_minute);
-
- end_set = e_date_edit_get_time_of_day (E_DATE_EDIT (priv->end_time),
- &end_hour, &end_minute);
-
- /* all day event checkbox */
- 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),
epage);
e_dialog_toggle_set (priv->all_day_event, all_day);
@@ -300,8 +286,7 @@ check_all_day (EventPage *epage)
e_date_edit_set_show_time (E_DATE_EDIT (priv->start_time), !all_day);
e_date_edit_set_show_time (E_DATE_EDIT (priv->end_time), !all_day);
- /* We will use DATE values for all-day events eventually, in which
- case timezones can't be used. */
+ /* DATE values do not have timezones, so we hide the fields. */
if (all_day) {
gtk_widget_hide (priv->start_timezone);
gtk_widget_hide (priv->end_timezone);
@@ -318,6 +303,7 @@ update_time (EventPage *epage, CalComponentDateTime *start_date, CalComponentDat
struct icaltimetype *start_tt, *end_tt;
icaltimezone *start_zone = NULL, *end_zone = NULL;
CalClientGetStatus status;
+ gboolean all_day_event;
priv = epage->priv;
@@ -346,15 +332,28 @@ update_time (EventPage *epage, CalComponentDateTime *start_date, CalComponentDat
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. */
+ /* If both times are DATE values, we set the 'All Day Event' checkbox.
+ If not, if the end time is a DATE we convert it to the end of the
+ day. */
+ all_day_event = FALSE;
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);
+ if (start_tt->is_date && end_tt->is_date) {
+ all_day_event = TRUE;
+ } else if (end_tt->is_date) {
+ icaltime_adjust (end_tt, 1, 0, 0, 0);
+ }
+
+ set_all_day (epage, all_day_event);
+
+ /* If it is an all day event, we set both timezones to the current
+ timezone, so that if the user toggles the 'All Day Event' checkbox
+ the event uses the current timezone rather than none at all. */
+ if (all_day_event) {
+ char *location = calendar_config_get_timezone ();
+ start_zone = end_zone = icaltimezone_get_builtin_timezone (location);
+ }
+
gtk_signal_handler_block_by_data (GTK_OBJECT (priv->start_time),
epage);
@@ -377,13 +376,20 @@ update_time (EventPage *epage, CalComponentDateTime *start_date, CalComponentDat
/* Set the timezones, and set sync_timezones to TRUE if both timezones
are the same. */
+ /* FIXME: JPR - why did you add the if check here? It looks like it
+ won't work for floating times, where start_zone or end_zone may be
+ NULL. */
+#if 0
if (start_zone && end_zone) {
+#endif
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;
+#if 0
}
+#endif
}
/* Fills the widgets with default values */
@@ -411,7 +417,7 @@ clear_widgets (EventPage *epage)
gtk_signal_handler_unblock_by_data (GTK_OBJECT (priv->end_time),
epage);
- check_all_day (epage);
+ set_all_day (epage, FALSE);
/* Classification */
e_dialog_radio_set (priv->classification_public,
@@ -486,13 +492,12 @@ event_page_fill_widgets (CompEditorPage *page, CalComponent *comp)
cal_component_get_dtstart (comp, &start_date);
cal_component_get_dtend (comp, &end_date);
+
update_time (epage, &start_date, &end_date);
cal_component_free_datetime (&start_date);
cal_component_free_datetime (&end_date);
- check_all_day (epage);
-
/* Classification */
cal_component_get_classification (comp, &cl);
@@ -549,7 +554,7 @@ event_page_fill_widgets (CompEditorPage *page, CalComponent *comp)
comp_editor_contacts_to_widget (priv->contacts_entry, comp);
/* We connect the contacts changed signal here, as we have to be a bit
- more careful with it due to the use or Corba. The priv->updating
+ more careful with it due to the use of Corba. The priv->updating
flag won't work as we won't get the changed event immediately.
FIXME: Unfortunately this doesn't work either. We never get the
changed event now. */
@@ -565,13 +570,12 @@ event_page_fill_component (CompEditorPage *page, CalComponent *comp)
{
EventPage *epage;
EventPagePrivate *priv;
- CalComponentDateTime date;
- struct icaltimetype icaltime;
- gboolean all_day_event, date_set;
+ CalComponentDateTime start_date, end_date;
+ struct icaltimetype start_tt, end_tt;
+ gboolean all_day_event, start_date_set, end_date_set;
char *cat, *str;
CalComponentClassification classif;
CalComponentTransparency transparency;
- icaltimezone *start_zone, *end_zone;
epage = EVENT_PAGE (page);
priv = epage->priv;
@@ -615,56 +619,50 @@ event_page_fill_component (CompEditorPage *page, CalComponent *comp)
/* Dates */
- icaltime = icaltime_null_time ();
+ start_tt = icaltime_null_time ();
+ start_date.value = &start_tt;
+ start_date.tzid = NULL;
+
+ end_tt = icaltime_null_time ();
+ end_date.value = &end_tt;
+ end_date.tzid = NULL;
- date.value = &icaltime;
- date.tzid = NULL;
+ start_date_set = e_date_edit_get_date (E_DATE_EDIT (priv->start_time),
+ &start_tt.year,
+ &start_tt.month,
+ &start_tt.day);
+ g_assert (start_date_set);
- /* FIXME: We should use is_date at some point. */
+ end_date_set = e_date_edit_get_date (E_DATE_EDIT (priv->end_time),
+ &end_tt.year,
+ &end_tt.month,
+ &end_tt.day);
+ g_assert (end_date_set);
- /* If the all_day toggle is set, the end date is inclusive of the
- entire day on which it points to. Also, we will use DATE values
- eventually, which can't have timezones. So for now we just use
- the default timezone. */
+ /* If the all_day toggle is set, we use DATE values for DTSTART and
+ DTEND. If not, we fetch the hour & minute from the widgets. */
all_day_event = e_dialog_toggle_get (priv->all_day_event);
if (all_day_event) {
- char *location = calendar_config_get_timezone ();
- start_zone = end_zone = icaltimezone_get_builtin_timezone (location);
+ start_tt.is_date = TRUE;
+ end_tt.is_date = TRUE;
} else {
+ icaltimezone *start_zone, *end_zone;
+
+ e_date_edit_get_time_of_day (E_DATE_EDIT (priv->start_time),
+ &start_tt.hour,
+ &start_tt.minute);
+ e_date_edit_get_time_of_day (E_DATE_EDIT (priv->end_time),
+ &end_tt.hour,
+ &end_tt.minute);
start_zone = e_timezone_entry_get_timezone (E_TIMEZONE_ENTRY (priv->start_timezone));
+ start_date.tzid = icaltimezone_get_tzid (start_zone);
end_zone = e_timezone_entry_get_timezone (E_TIMEZONE_ENTRY (priv->end_timezone));
+ end_date.tzid = icaltimezone_get_tzid (end_zone);
}
- 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);
- date.tzid = icaltimezone_get_tzid (start_zone);
- cal_component_set_dtstart (comp, &date);
-
- 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);
- }
-
- date.tzid = icaltimezone_get_tzid (end_zone);
- cal_component_set_dtend (comp, &date);
+ cal_component_set_dtstart (comp, &start_date);
+ cal_component_set_dtend (comp, &end_date);
/* Categories */
@@ -802,7 +800,7 @@ notify_dates_changed (EventPage *epage, struct icaltimetype *start_tt,
CompEditorPageDates dates;
CalComponentDateTime start_dt, end_dt;
gboolean all_day_event;
- icaltimezone *start_zone, *end_zone;
+ icaltimezone *start_zone = NULL, *end_zone = NULL;
priv = epage->priv;
@@ -811,14 +809,7 @@ notify_dates_changed (EventPage *epage, struct icaltimetype *start_tt,
start_dt.value = start_tt;
end_dt.value = end_tt;
- if (all_day_event) {
- /* FIXME: When we switch to using DATE values we'll set the
- TZIDs to NULL. */
- char *location;
-
- location = calendar_config_get_timezone ();
- start_zone = end_zone = icaltimezone_get_builtin_timezone (location);
- } else {
+ if (!all_day_event) {
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));
}
@@ -836,12 +827,48 @@ notify_dates_changed (EventPage *epage, struct icaltimetype *start_tt,
}
+static gboolean
+check_start_before_end (struct icaltimetype *start_tt,
+ icaltimezone *start_zone,
+ struct icaltimetype *end_tt,
+ icaltimezone *end_zone,
+ gboolean adjust_end_time)
+{
+ struct icaltimetype end_tt_copy;
+ int cmp;
+
+ /* Convert the end time to the same timezone as the start time. */
+ end_tt_copy = *end_tt;
+ icaltimezone_convert_time (&end_tt_copy, end_zone, start_zone);
+
+ /* Now check if the start time is after the end time. If it is,
+ we need to modify one of the times. */
+ cmp = icaltime_compare (*start_tt, end_tt_copy);
+ if (cmp > 0) {
+ if (adjust_end_time) {
+ /* Modify the end time, to be the start + 1 hour. */
+ *end_tt = *start_tt;
+ icaltime_adjust (end_tt, 0, 1, 0, 0);
+ icaltimezone_convert_time (end_tt, start_zone,
+ end_zone);
+ } else {
+ /* Modify the start time, to be the end - 1 hour. */
+ *start_tt = *end_tt;
+ icaltime_adjust (start_tt, 0, -1, 0, 0);
+ icaltimezone_convert_time (start_tt, end_zone,
+ start_zone);
+ }
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+
/*
* This is called whenever the start or end dates or timezones is changed.
- * It makes sure that the start date < end date, and currently sets the
- * "all day event" checkbox as appropriate (but won't when we use DATE values).
- * It also emits the notification signals so the other event editor pages
- * update their labels etc.
+ * It makes sure that the start date < end date. It also emits the notification
+ * signals so the other event editor pages update their labels etc.
*
* If adjust_end_time is TRUE, if the start time < end time it will adjust
* the end time. If FALSE it will adjust the start time. If the user sets the
@@ -853,9 +880,8 @@ times_updated (EventPage *epage, gboolean adjust_end_time)
EventPagePrivate *priv;
struct icaltimetype start_tt = icaltime_null_time();
struct icaltimetype end_tt = icaltime_null_time();
- struct icaltimetype end_tt_copy;
- int cmp;
gboolean date_set, all_day_event;
+ gboolean set_start_date = FALSE, set_end_date = FALSE;
icaltimezone *start_zone, *end_zone;
priv = epage->priv;
@@ -870,88 +896,69 @@ times_updated (EventPage *epage, gboolean adjust_end_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);
if (all_day_event) {
- char *location = calendar_config_get_timezone ();
- start_zone = end_zone = icaltimezone_get_builtin_timezone (location);
+ /* All Day Events are simple. We just compare the dates and if
+ start > end we copy one of them to the other. */
+ int cmp = icaltime_compare_date_only (start_tt, end_tt);
+ if (cmp > 0) {
+ if (adjust_end_time) {
+ end_tt = start_tt;
+ set_end_date = TRUE;
+ } else {
+ start_tt = end_tt;
+ set_start_date = TRUE;
+ }
+ }
} else {
+ /* For DATE-TIME events, we have to convert to the same
+ timezone before comparing. */
+ e_date_edit_get_time_of_day (E_DATE_EDIT (priv->start_time),
+ &start_tt.hour,
+ &start_tt.minute);
+ e_date_edit_get_time_of_day (E_DATE_EDIT (priv->end_time),
+ &end_tt.hour,
+ &end_tt.minute);
+
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));
- }
-
-
- /* Convert the end time to the same timezone as the start time. */
- end_tt_copy = end_tt;
- icaltimezone_convert_time (&end_tt_copy, end_zone, start_zone);
- /* Now check if the start time is after the end time. If it is, we need
- to modify one of the times. */
- cmp = icaltime_compare (start_tt, end_tt_copy);
- if (cmp > 0) {
- if (adjust_end_time) {
- /* Modify the end time, to be the start + 1 hour,
- or the same as the start time for all-day events.
- We copy the start time, add on one hour, then
- convert it to the original end timezone. */
- end_tt = start_tt;
- if (!all_day_event) {
- icaltime_adjust (&end_tt, 0, 1, 0, 0);
- icaltimezone_convert_time (&end_tt, start_zone,
- end_zone);
- }
-
- gtk_signal_handler_block_by_data (GTK_OBJECT (priv->end_time), epage);
-
- 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 {
- /* Modify the start time, to be the end - 1 hour,
- or the same as the start time for all-day events.
- We copy the end time, subtract one hour, then
- convert it to the original start timezone. */
- start_tt = end_tt;
- if (!all_day_event) {
- icaltime_adjust (&start_tt, 0, -1, 0, 0);
- icaltimezone_convert_time (&start_tt, end_zone,
- start_zone);
- }
-
- gtk_signal_handler_block_by_data (GTK_OBJECT (priv->start_time), epage);
+ if (check_start_before_end (&start_tt, start_zone,
+ &end_tt, end_zone,
+ adjust_end_time)) {
+ if (adjust_end_time)
+ set_end_date = TRUE;
+ else
+ set_start_date = TRUE;
+ }
+ }
- 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);
- }
+ if (set_start_date) {
+ gtk_signal_handler_block_by_data (GTK_OBJECT (priv->start_time), epage);
+ 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);
}
- /* Set the "all day event" button as appropriate */
- check_all_day (epage);
+ if (set_end_date) {
+ gtk_signal_handler_block_by_data (GTK_OBJECT (priv->end_time), epage);
+ 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);
+ }
/* Notify upstream */
notify_dates_changed (epage, &start_tt, &end_tt);
@@ -1040,21 +1047,22 @@ all_day_event_toggled_cb (GtkWidget *toggle, gpointer data)
* rounded down to the start of the day on which the event
* ends. The event is then taken to be inclusive of the days
* between the start and end days. Note that if the event end
- * is at midnight, we do not round it down to the previous
- * day, since if we do that and the user repeatedly turns the
- * all_day toggle on and off, the event keeps shrinking.
- * (We'd also need to make sure we didn't adjust the time when
- * the radio button is initially set.)
+ * is at midnight, we round it down to the previous day, so the
+ * event times stay the same.
+ *
+ * When the all_day_toggle is turned off, then if the event is within
+ * one day, we set the event start to the start of the working day,
+ * and set the event end to one hour after it. If the event is longer
+ * than one day, we set the event end to the end of the day it is on,
+ * so that the actual event times remain the same.
*
- * When the all_day_toggle is turned off, we set the event start to the
- * start of the working day, and if the event end is on or before the
- * day of the event start we set it to one hour after the event start.
+ * This may need tweaking to work well with different timezones used
+ * in the event start & end.
*/
all_day = GTK_TOGGLE_BUTTON (toggle)->active;
- /*
- * Start time.
- */
+ set_all_day (epage, all_day);
+
date_set = e_date_edit_get_date (E_DATE_EDIT (priv->start_time),
&start_tt.year,
&start_tt.month,
@@ -1064,21 +1072,6 @@ all_day_event_toggled_cb (GtkWidget *toggle, gpointer data)
&start_tt.minute);
g_assert (date_set);
- if (all_day) {
- /* Round down to the start of the day. */
- start_tt.hour = 0;
- start_tt.minute = 0;
- start_tt.second = 0;
- } else {
- /* Set to the start of the working day. */
- start_tt.hour = calendar_config_get_day_start_hour ();
- start_tt.minute = calendar_config_get_day_start_minute ();
- start_tt.second = 0;
- }
-
- /*
- * End time.
- */
date_set = e_date_edit_get_date (E_DATE_EDIT (priv->end_time),
&end_tt.year,
&end_tt.month,
@@ -1090,24 +1083,44 @@ all_day_event_toggled_cb (GtkWidget *toggle, gpointer data)
if (all_day) {
/* Round down to the start of the day. */
+ start_tt.hour = 0;
+ start_tt.minute = 0;
+ start_tt.second = 0;
+
+ /* Round down to the start of the day, or the start of the
+ previous day if it is midnight. */
+ icaltime_adjust (&end_tt, 0, 0, 0, -1);
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. */
- 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;
+ icaltimezone *start_zone, *end_zone;
+
+ if (end_tt.year == start_tt.year
+ && end_tt.month == start_tt.month
+ && end_tt.day == start_tt.day) {
+ /* The event is within one day, so we set the event
+ start to the start of the working day, and the end
+ to one hour later. */
+ start_tt.hour = calendar_config_get_day_start_hour ();
+ start_tt.minute = calendar_config_get_day_start_minute ();
+ start_tt.second = 0;
+
+ end_tt = start_tt;
icaltime_adjust (&end_tt, 0, 1, 0, 0);
+ } else {
+ /* The event is longer than 1 day, so we keep exactly
+ the same times, just using DATE-TIME rather than
+ DATE. */
+ icaltime_adjust (&end_tt, 1, 0, 0, 0);
}
+
+ /* Make sure that end > start using the timezones. */
+ 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));
+ check_start_before_end (&start_tt, start_zone,
+ &end_tt, end_zone,
+ TRUE);
}
gtk_signal_handler_block_by_data (GTK_OBJECT (priv->start_time),
@@ -1130,19 +1143,6 @@ all_day_event_toggled_cb (GtkWidget *toggle, gpointer data)
gtk_signal_handler_unblock_by_data (GTK_OBJECT (priv->end_time),
epage);
- e_date_edit_set_show_time (E_DATE_EDIT (priv->start_time), !all_day);
- e_date_edit_set_show_time (E_DATE_EDIT (priv->end_time), !all_day);
-
- /* We will use DATE values for all-day events eventually, in which
- case timezones can't be used. */
- if (all_day) {
- gtk_widget_hide (priv->start_timezone);
- gtk_widget_hide (priv->end_timezone);
- } else {
- gtk_widget_show (priv->start_timezone);
- gtk_widget_show (priv->end_timezone);
- }
-
/* Notify upstream */
notify_dates_changed (epage, &start_tt, &end_tt);
}
diff --git a/calendar/gui/dialogs/task-details-page.c b/calendar/gui/dialogs/task-details-page.c
index 1128d54deb..474b80da12 100644
--- a/calendar/gui/dialogs/task-details-page.c
+++ b/calendar/gui/dialogs/task-details-page.c
@@ -509,7 +509,7 @@ date_changed_cb (EDateEdit *dedit, gpointer data)
TaskDetailsPage *tdpage;
TaskDetailsPagePrivate *priv;
CompEditorPageDates dates = {NULL, NULL, NULL, NULL};
- struct icaltimetype completed_tt;
+ struct icaltimetype completed_tt = icaltime_null_time ();
icalproperty_status status;
gboolean date_set;
diff --git a/calendar/gui/e-calendar-table.c b/calendar/gui/e-calendar-table.c
index 8d8856ed2a..9002811f09 100644
--- a/calendar/gui/e-calendar-table.c
+++ b/calendar/gui/e-calendar-table.c
@@ -40,7 +40,9 @@
#include <gal/e-table/e-cell-combo.h>
#include <gal/widgets/e-popup-menu.h>
#include <widgets/misc/e-cell-date-edit.h>
+#include <widgets/misc/e-cell-percent.h>
#include "e-calendar-table.h"
+#include "e-cell-date-edit-text.h"
#include "calendar-config.h"
#include "calendar-model.h"
#include "dialogs/delete-comp.h"
@@ -244,26 +246,46 @@ task_compare_cb (gconstpointer a, gconstpointer b)
static gint
date_compare_cb (gconstpointer a, gconstpointer b)
{
- const char *value1 = a, *value2 = b;
+ ECellDateEditValue *dv1 = (ECellDateEditValue *) a;
+ ECellDateEditValue *dv2 = (ECellDateEditValue *) b;
+ struct icaltimetype tt;
+
+ /* First check if either is NULL. NULL dates sort last. */
+ if (!dv1 || !dv2) {
+ if (dv1 == dv2)
+ return 0;
+ else if (dv1)
+ return -1;
+ else
+ return 1;
+ }
+
+ /* Copy the 2nd value and convert it to the same timezone as the
+ first. */
+ tt = dv2->tt;
+
+ icaltimezone_convert_time (&tt, dv2->zone, dv1->zone);
- g_print ("In date_compare_cb '%s' '%s'\n", value1, value2);
+ /* Now we can compare them. */
- return 0;
+ return icaltime_compare (dv1->tt, tt);
}
static gint
percent_compare_cb (gconstpointer a, gconstpointer b)
{
- const char *value1 = a, *value2 = b;
-
- /* FIXME: Currently this isn't working as the ETableSorter caches
- all the values in the table before sorting, but our get_value()
- function returns a pointer to a static buffer. So all the cached
- pointers point to the same buffer. */
+ int percent1 = GPOINTER_TO_INT (a);
+ int percent2 = GPOINTER_TO_INT (b);
+ int retval;
- g_print ("In percent_compare_cb '%s' '%s'\n", value1, value2);
+ if (percent1 > percent2)
+ retval = 1;
+ else if (percent1 < percent2)
+ retval = -1;
+ else
+ retval = 0;
- return 0;
+ return retval;
}
static gint
@@ -324,7 +346,7 @@ e_calendar_table_init (ECalendarTable *cal_table)
/*
* Date fields.
*/
- cell = e_cell_text_new (NULL, GTK_JUSTIFY_LEFT);
+ cell = e_cell_date_edit_text_new (NULL, GTK_JUSTIFY_LEFT);
gtk_object_set (GTK_OBJECT (cell),
"strikeout_column", CAL_COMPONENT_FIELD_COMPLETE,
"bold_column", CAL_COMPONENT_FIELD_OVERDUE,
@@ -392,7 +414,7 @@ e_calendar_table_init (ECalendarTable *cal_table)
e_table_extras_add_cell (extras, "priority", popup_cell);
/* Percent field. */
- cell = e_cell_text_new (NULL, GTK_JUSTIFY_LEFT);
+ cell = e_cell_percent_new (NULL, GTK_JUSTIFY_LEFT);
gtk_object_set (GTK_OBJECT (cell),
"strikeout_column", CAL_COMPONENT_FIELD_COMPLETE,
"bold_column", CAL_COMPONENT_FIELD_OVERDUE,
diff --git a/calendar/gui/e-cell-date-edit-text.c b/calendar/gui/e-cell-date-edit-text.c
new file mode 100644
index 0000000000..d0b9d2bf7a
--- /dev/null
+++ b/calendar/gui/e-cell-date-edit-text.c
@@ -0,0 +1,234 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+
+/*
+ * Author :
+ * Damon Chaplin <damon@ximian.com>
+ *
+ * Copyright 2001, Ximian, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ * USA
+ */
+
+/*
+ * ECellDateEditText - a subclass of ECellText used to show and edit the text
+ * representation of the date, from a CalComponentDateTime* model value.
+ */
+
+#include <config.h>
+
+#include <sys/time.h>
+#include <time.h>
+#include <unistd.h>
+#include <string.h>
+#include <libgnomeui/gnome-messagebox.h>
+#include <libgnomeui/gnome-stock.h>
+#include <libgnome/gnome-i18n.h>
+#include <gal/util/e-util.h>
+#include <gal/widgets/e-unicode.h>
+#include <e-util/e-time-utils.h>
+#include <cal-util/timeutil.h>
+
+#include "e-cell-date-edit-text.h"
+
+
+#define PARENT_TYPE e_cell_text_get_type ()
+
+static ECellTextClass *parent_class;
+
+
+void
+e_cell_date_edit_text_set_timezone (ECellDateEditText *ecd,
+ icaltimezone *zone)
+{
+ g_return_if_fail (E_IS_CELL_DATE_EDIT_TEXT (ecd));
+
+ ecd->zone = zone;
+}
+
+
+void
+e_cell_date_edit_text_set_use_24_hour_format (ECellDateEditText *ecd,
+ gboolean use_24_hour)
+{
+ g_return_if_fail (E_IS_CELL_DATE_EDIT_TEXT (ecd));
+
+ ecd->use_24_hour_format = use_24_hour;
+}
+
+
+static char *
+ecd_get_text (ECellText *cell, ETableModel *model, int col, int row)
+{
+ ECellDateEditText *ecd = E_CELL_DATE_EDIT_TEXT (cell);
+ ECellDateEditValue *dv = e_table_model_value_at (model, col, row);
+ struct icaltimetype tt;
+ struct tm tmp_tm;
+ char buffer[64];
+
+ if (!dv)
+ return g_strdup ("");
+
+ /* Note that although the property may be in a different
+ timezone, we convert it to the current timezone to display
+ it in the table. If the user actually edits the value,
+ it will be set to the current timezone. See set_value(). */
+ tt = dv->tt;
+ icaltimezone_convert_time (&tt, dv->zone, ecd->zone);
+
+ tmp_tm.tm_year = tt.year - 1900;
+ tmp_tm.tm_mon = tt.month - 1;
+ tmp_tm.tm_mday = tt.day;
+ tmp_tm.tm_hour = tt.hour;
+ tmp_tm.tm_min = tt.minute;
+ tmp_tm.tm_sec = tt.second;
+ tmp_tm.tm_isdst = -1;
+
+ tmp_tm.tm_wday = time_day_of_week (tt.day, tt.month - 1, tt.year);
+
+ e_time_format_date_and_time (&tmp_tm, ecd->use_24_hour_format,
+ TRUE, FALSE,
+ buffer, sizeof (buffer));
+ return g_strdup (buffer);
+}
+
+
+static void
+ecd_free_text (ECellText *cell, char *text)
+{
+ g_free (text);
+}
+
+
+/* FIXME: We need to set the "transient_for" property for the dialog. */
+static void
+show_date_warning (ECellDateEditText *ecd)
+{
+ GtkWidget *dialog;
+ char buffer[64], message[256], *format;
+ time_t t;
+ 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 (ecd->use_24_hour_format)
+ /* strftime format of a weekday, a date and a time, 24-hour. */
+ format = _("%a %m/%d/%Y %H:%M:%S");
+ else
+ /* strftime format of a weekday, a date and a time, 12-hour. */
+ format = _("%a %m/%d/%Y %I:%M:%S %p");
+
+ strftime (buffer, sizeof (buffer), format, tmp_tm);
+
+ g_snprintf (message, 256,
+ _("The date must be entered in the format: \n\n%s"),
+ buffer);
+
+ dialog = gnome_message_box_new (message,
+ GNOME_MESSAGE_BOX_ERROR,
+ GNOME_STOCK_BUTTON_OK, NULL);
+ gtk_widget_show (dialog);
+}
+
+
+static void
+ecd_set_value (ECellText *cell, ETableModel *model, int col, int row,
+ const char *text)
+{
+ ECellDateEditText *ecd = E_CELL_DATE_EDIT_TEXT (cell);
+ ETimeParseStatus status;
+ struct tm tmp_tm;
+ ECellDateEditValue *value;
+
+ status = e_time_parse_date_and_time (text, &tmp_tm);
+
+ if (status == E_TIME_PARSE_INVALID) {
+ show_date_warning (ecd);
+ return;
+ } else if (status == E_TIME_PARSE_NONE) {
+ value = NULL;
+ } else {
+ ECellDateEditValue dv;
+
+ dv.tt = icaltime_null_time ();
+
+ dv.tt.year = tmp_tm.tm_year + 1900;
+ dv.tt.month = tmp_tm.tm_mon + 1;
+ dv.tt.day = tmp_tm.tm_mday;
+ dv.tt.hour = tmp_tm.tm_hour;
+ dv.tt.minute = tmp_tm.tm_min;
+ dv.tt.second = tmp_tm.tm_sec;
+
+ /* FIXME: We assume it is being set to the current timezone.
+ Is that OK? */
+ dv.zone = ecd->zone;
+
+ value = &dv;
+ }
+
+ e_table_model_set_value_at (model, col, row, value);
+}
+
+
+static void
+e_cell_date_edit_text_class_init (GtkObjectClass *object_class)
+{
+ ECellTextClass *ectc = (ECellTextClass *) object_class;
+
+ parent_class = gtk_type_class (PARENT_TYPE);
+
+ ectc->get_text = ecd_get_text;
+ ectc->free_text = ecd_free_text;
+ ectc->set_value = ecd_set_value;
+}
+
+
+static void
+e_cell_date_edit_text_init (GtkObject *object)
+{
+ ECellDateEditText *ecd = E_CELL_DATE_EDIT_TEXT (object);
+
+ ecd->zone = icaltimezone_get_utc_timezone ();
+ ecd->use_24_hour_format = TRUE;
+}
+
+
+/**
+ * e_cell_date_edit_text_new:
+ *
+ * Creates a new ECell renderer that can be used to render and edit dates that
+ * that come from the model. The value returned from the model is
+ * interpreted as being a CalComponentDateTime*.
+ *
+ * Returns: an ECell object that can be used to render dates.
+ */
+ECell *
+e_cell_date_edit_text_new (const char *fontname,
+ GtkJustification justify)
+{
+ ECellDateEditText *ecd = gtk_type_new (e_cell_date_edit_text_get_type ());
+
+ e_cell_text_construct (E_CELL_TEXT (ecd), fontname, justify);
+
+ return (ECell *) ecd;
+}
+
+
+E_MAKE_TYPE (e_cell_date_edit_text, "ECellDateEditText", ECellDateEditText,
+ e_cell_date_edit_text_class_init, e_cell_date_edit_text_init,
+ PARENT_TYPE);
diff --git a/calendar/gui/e-cell-date-edit-text.h b/calendar/gui/e-cell-date-edit-text.h
new file mode 100644
index 0000000000..527f75b16e
--- /dev/null
+++ b/calendar/gui/e-cell-date-edit-text.h
@@ -0,0 +1,75 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+
+/*
+ * Author :
+ * Damon Chaplin <damon@ximian.com>
+ *
+ * Copyright 2001, Ximian, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ * USA
+ */
+
+/*
+ * ECellDateEditText - a subclass of ECellText used to show and edit the text
+ * representation of the date, from a CalComponentDateTime* model value.
+ */
+
+#ifndef _E_CELL_DATE_EDIT_TEXT_H_
+#define _E_CELL_DATE_EDIT_TEXT_H_
+
+#include <ical.h>
+#include <gal/e-table/e-cell-text.h>
+
+BEGIN_GNOME_DECLS
+
+#define E_CELL_DATE_EDIT_TEXT_TYPE (e_cell_date_edit_text_get_type ())
+#define E_CELL_DATE_EDIT_TEXT(o) (GTK_CHECK_CAST ((o), E_CELL_DATE_EDIT_TEXT_TYPE, ECellDateEditText))
+#define E_CELL_DATE_EDIT_TEXT_CLASS(k) (GTK_CHECK_CLASS_CAST((k), E_CELL_DATE_EDIT_TEXT_TYPE, ECellDateEditTextClass))
+#define E_IS_CELL_DATE_EDIT_TEXT(o) (GTK_CHECK_TYPE ((o), E_CELL_DATE_EDIT_TEXT_TYPE))
+#define E_IS_CELL_DATE_EDIT_TEXT_CLASS(k) (GTK_CHECK_CLASS_TYPE ((k), E_CELL_DATE_EDIT_TEXT_TYPE))
+
+typedef struct _ECellDateEditValue ECellDateEditValue;
+struct _ECellDateEditValue {
+ struct icaltimetype tt;
+ icaltimezone *zone;
+};
+
+typedef struct {
+ ECellText base;
+
+ /* The timezone to display the date in. */
+ icaltimezone *zone;
+
+ /* Whether to display in 24-hour format. */
+ gboolean use_24_hour_format;
+} ECellDateEditText;
+
+typedef struct {
+ ECellTextClass parent_class;
+} ECellDateEditTextClass;
+
+GtkType e_cell_date_edit_text_get_type (void);
+ECell *e_cell_date_edit_text_new (const char *fontname,
+ GtkJustification justify);
+
+
+void e_cell_date_edit_text_set_timezone (ECellDateEditText *ecd,
+ icaltimezone *zone);
+void e_cell_date_edit_text_set_use_24_hour_format (ECellDateEditText *ecd,
+ gboolean use_24_hour);
+END_GNOME_DECLS
+
+#endif /* _E_CELL_DATE_EDIT_TEXT_H_ */
diff --git a/calendar/gui/e-day-view.c b/calendar/gui/e-day-view.c
index 7aaee07062..a6bd101d46 100644
--- a/calendar/gui/e-day-view.c
+++ b/calendar/gui/e-day-view.c
@@ -1555,7 +1555,8 @@ query_obj_updated_cb (CalQuery *query, const char *uid,
cal_recur_generate_instances (comp, day_view->lower,
day_view->upper,
e_day_view_add_event, day_view,
- cal_client_resolve_tzid_cb, day_view->client);
+ cal_client_resolve_tzid_cb, day_view->client,
+ day_view->zone);
gtk_object_unref (GTK_OBJECT (comp));
e_day_view_queue_layout (day_view);
@@ -5012,8 +5013,8 @@ e_day_view_key_press (GtkWidget *widget, GdkEventKey *event)
guint keyval;
gboolean stop_emission;
time_t dtstart, dtend;
- CalComponentDateTime dt;
- struct icaltimetype itt;
+ CalComponentDateTime start_dt, end_dt;
+ struct icaltimetype start_tt, end_tt;
const char *uid;
g_return_val_if_fail (widget != NULL, FALSE);
@@ -5108,16 +5109,27 @@ 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 = icaltimezone_get_tzid (day_view->zone);
+ start_tt = icaltime_from_timet_with_zone (dtstart, FALSE,
+ day_view->zone);
+
+ end_tt = icaltime_from_timet_with_zone (dtend, FALSE,
+ day_view->zone);
- *dt.value = icaltime_from_timet_with_zone (dtstart, FALSE,
- day_view->zone);
- cal_component_set_dtstart (comp, &dt);
+ if (day_view->selection_in_top_canvas) {
+ start_dt.tzid = NULL;
+ start_tt.is_date = 1;
+ end_tt.is_date = 1;
+ /* We have to take a day off the end time as it is a DATE. */
+ icaltime_adjust (&end_tt, -1, 0, 0, 0);
+ } else {
+ start_dt.tzid = icaltimezone_get_tzid (day_view->zone);
+ }
- *dt.value = icaltime_from_timet_with_zone (dtend, FALSE,
- day_view->zone);
- cal_component_set_dtend (comp, &dt);
+ start_dt.value = &start_tt;
+ end_dt.value = &end_tt;
+ end_dt.tzid = start_dt.tzid;
+ cal_component_set_dtstart (comp, &start_dt);
+ cal_component_set_dtend (comp, &end_dt);
cal_component_set_categories (comp, day_view->default_category);
@@ -6595,6 +6607,7 @@ e_day_view_on_top_canvas_drag_data_received (GtkWidget *widget,
CalComponentDateTime date;
struct icaltimetype itt;
time_t dt;
+ gboolean all_day_event;
/* Note that we only support DnD within the EDayView at present. */
if ((data->length >= 0) && (data->format == 8)
@@ -6606,7 +6619,7 @@ e_day_view_on_top_canvas_drag_data_received (GtkWidget *widget,
const char *uid;
num_days = 1;
start_offset = 0;
- end_offset = -1;
+ end_offset = 0;
if (day_view->drag_event_day == E_DAY_VIEW_LONG_EVENT) {
event = &g_array_index (day_view->long_events, EDayViewEvent,
@@ -6638,28 +6651,47 @@ e_day_view_on_top_canvas_drag_data_received (GtkWidget *widget,
if (!event_uid || !uid || strcmp (event_uid, uid))
g_warning ("Unexpected event UID");
- /* We use a temporary shallow of the comp since we
- don't want to change the original comp here.
+ /* We clone the event since we don't want to change
+ the original comp here.
Otherwise we would not detect that the event's time
had changed in the "update_event" callback. */
comp = cal_component_clone (event->comp);
+ if (start_offset == 0 && end_offset == 0)
+ all_day_event = TRUE;
+ else
+ all_day_event = FALSE;
+
date.value = &itt;
- /* 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_with_zone (dt, FALSE,
- day_view->zone);
+ itt = icaltime_from_timet_with_zone (dt, FALSE,
+ day_view->zone);
+ if (all_day_event) {
+ itt.is_date = TRUE;
+ date.tzid = NULL;
+ } else {
+ /* FIXME: Should probably keep the timezone of
+ the original start and end times. */
+ date.tzid = icaltimezone_get_tzid (day_view->zone);
+ }
cal_component_set_dtstart (comp, &date);
- if (end_offset == -1 || end_offset == 0)
+
+ if (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_with_zone (dt, FALSE,
- day_view->zone);
+ itt = icaltime_from_timet_with_zone (dt, FALSE,
+ day_view->zone);
+ if (all_day_event) {
+ itt.is_date = TRUE;
+ date.tzid = NULL;
+ } else {
+ /* FIXME: Should probably keep the timezone of
+ the original start and end times. */
+ date.tzid = icaltimezone_get_tzid (day_view->zone);
+ }
cal_component_set_dtend (comp, &date);
gtk_drag_finish (context, TRUE, TRUE, time);
diff --git a/calendar/gui/e-tasks.c b/calendar/gui/e-tasks.c
index 02cf6b3f47..d6c0f4a64e 100644
--- a/calendar/gui/e-tasks.c
+++ b/calendar/gui/e-tasks.c
@@ -328,7 +328,7 @@ e_tasks_open (ETasks *tasks,
message = g_strdup_printf (_("Opening tasks at %s"), file);
calendar_model_set_status_message (
- e_calendar_table_get_model (priv->tasks_view),
+ e_calendar_table_get_model (E_CALENDAR_TABLE (priv->tasks_view)),
message);
g_free (message);
@@ -378,16 +378,24 @@ cal_opened_cb (CalClient *client,
{
ETasks *tasks;
ETasksPrivate *priv;
+ char *location;
+ icaltimezone *zone;
tasks = E_TASKS (data);
priv = tasks->priv;
calendar_model_set_status_message (
- e_calendar_table_get_model (priv->tasks_view), NULL);
+ e_calendar_table_get_model (E_CALENDAR_TABLE (priv->tasks_view)), NULL);
switch (status) {
case CAL_CLIENT_OPEN_SUCCESS:
/* Everything is OK */
+
+ /* Set the client's default timezone, if we have one. */
+ location = calendar_config_get_timezone ();
+ zone = icaltimezone_get_builtin_timezone (location);
+ if (zone)
+ cal_client_set_default_timezone (client, zone);
return;
case CAL_CLIENT_OPEN_ERROR:
@@ -632,10 +640,19 @@ e_tasks_update_all_config_settings (void)
ETasks *tasks;
ETasksPrivate *priv;
GList *elem;
+ char *location;
+ icaltimezone *zone;
+
+ location = calendar_config_get_timezone ();
+ zone = icaltimezone_get_builtin_timezone (location);
for (elem = all_tasks; elem; elem = elem->next) {
tasks = E_TASKS (elem->data);
priv = tasks->priv;
+
calendar_config_configure_e_calendar_table (E_CALENDAR_TABLE (priv->tasks_view));
+
+ if (zone)
+ cal_client_set_default_timezone (priv->client, zone);
}
}
diff --git a/calendar/gui/e-week-view.c b/calendar/gui/e-week-view.c
index 3fb334905a..0af180da9a 100644
--- a/calendar/gui/e-week-view.c
+++ b/calendar/gui/e-week-view.c
@@ -1059,7 +1059,8 @@ query_obj_updated_cb (CalQuery *query, const char *uid,
week_view->day_starts[0],
week_view->day_starts[num_days],
e_week_view_add_event, week_view,
- cal_client_resolve_tzid_cb, week_view->client);
+ cal_client_resolve_tzid_cb, week_view->client,
+ week_view->zone);
gtk_object_unref (GTK_OBJECT (comp));
@@ -3232,13 +3233,19 @@ 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 = icaltimezone_get_tzid (week_view->zone);
+ date.tzid = NULL;
+
+ /* We use DATE values now, so we don't need the timezone. */
+ /*date.tzid = icaltimezone_get_tzid (week_view->zone);*/
- *date.value = icaltime_from_timet_with_zone (dtstart, FALSE,
+ *date.value = icaltime_from_timet_with_zone (dtstart, TRUE,
week_view->zone);
cal_component_set_dtstart (comp, &date);
- *date.value = icaltime_from_timet_with_zone (dtend, FALSE,
+
+ /* We have to take a day off the end time as it is a DATE value. */
+ *date.value = icaltime_from_timet_with_zone (dtend, TRUE,
week_view->zone);
+ icaltime_adjust (date.value, -1, 0, 0, 0);
cal_component_set_dtend (comp, &date);
cal_component_set_categories (comp, week_view->default_category);
diff --git a/calendar/gui/gnome-cal.c b/calendar/gui/gnome-cal.c
index b1f7c9470c..1790739853 100644
--- a/calendar/gui/gnome-cal.c
+++ b/calendar/gui/gnome-cal.c
@@ -1345,9 +1345,15 @@ client_cal_opened_cb (CalClient *client, CalClientOpenStatus status, gpointer da
switch (status) {
case CAL_CLIENT_OPEN_SUCCESS:
- if (client == priv->client)
+ /* If this is the main CalClient, update the Date Navigator. */
+ if (client == priv->client) {
update_query (gcal);
+ }
+ /* Set the client's default timezone, if we have one. */
+ if (priv->zone) {
+ cal_client_set_default_timezone (client, priv->zone);
+ }
break;
case CAL_CLIENT_OPEN_ERROR:
@@ -1826,6 +1832,16 @@ gnome_calendar_update_config_settings (GnomeCalendar *gcal,
location = calendar_config_get_timezone ();
priv->zone = icaltimezone_get_builtin_timezone (location);
+ if (priv->client
+ && cal_client_get_load_state (priv->client) == CAL_CLIENT_LOAD_LOADED) {
+ cal_client_set_default_timezone (priv->client, priv->zone);
+ }
+ if (priv->task_pad_client
+ && cal_client_get_load_state (priv->task_pad_client) == CAL_CLIENT_LOAD_LOADED) {
+ cal_client_set_default_timezone (priv->task_pad_client,
+ priv->zone);
+ }
+
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);
@@ -1996,7 +2012,10 @@ gnome_calendar_new_appointment_for (GnomeCalendar *cal,
priv = cal->priv;
dt.value = &itt;
- dt.tzid = icaltimezone_get_tzid (priv->zone);
+ if (all_day)
+ dt.tzid = NULL;
+ else
+ dt.tzid = icaltimezone_get_tzid (priv->zone);
/* Component type */
@@ -2006,18 +2025,21 @@ gnome_calendar_new_appointment_for (GnomeCalendar *cal,
/* DTSTART, DTEND */
itt = icaltime_from_timet_with_zone (dtstart, FALSE, priv->zone);
- if (all_day)
+ if (all_day) {
itt.hour = itt.minute = itt.second = 0;
+ itt.is_date = TRUE;
+ }
cal_component_set_dtstart (comp, &dt);
itt = icaltime_from_timet_with_zone (dtend, FALSE, priv->zone);
if (all_day) {
- /* If we want an all-day event and the end time isn't on a
- day boundary, we move it to the end of the day it is in. */
- if (itt.hour != 0 || itt.minute != 0 || itt.second != 0) {
- itt.hour = itt.minute = itt.second = 0;
- icaltime_adjust (&itt, 1, 0, 0, 0);
+ /* We round it down to the start of the day, or the start of
+ the previous day if it is midnight. */
+ if (itt.hour == 0 && itt.minute == 0 && itt.second == 0) {
+ icaltime_adjust (&itt, -1, 0, 0, 0);
}
+ itt.hour = itt.minute = itt.second = 0;
+ itt.is_date = TRUE;
}
cal_component_set_dtend (comp, &dt);
diff --git a/calendar/gui/tag-calendar.c b/calendar/gui/tag-calendar.c
index 08a2636ec0..747e1e1cb1 100644
--- a/calendar/gui/tag-calendar.c
+++ b/calendar/gui/tag-calendar.c
@@ -218,11 +218,11 @@ tag_calendar_by_comp (ECalendar *ecal, CalComponent *comp, CalClient *client, gb
cal_recur_generate_instances (comp, c.start_time, c.end_time,
tag_calendar_cb, &c,
cal_client_resolve_tzid_cb,
- client);
+ client, c.zone);
} else {
cal_recur_generate_instances (comp, c.start_time, c.end_time,
tag_calendar_cb, &c,
resolve_tzid_cb,
- client);
+ client, c.zone);
}
}
diff --git a/calendar/idl/evolution-calendar.idl b/calendar/idl/evolution-calendar.idl
index ca63d3c52c..43bb818eff 100644
--- a/calendar/idl/evolution-calendar.idl
+++ b/calendar/idl/evolution-calendar.idl
@@ -145,6 +145,11 @@ module Calendar {
CalObj getObject (in CalObjUID uid)
raises (NotFound);
+ /* Sets the default timezone to be used for resolving DATE
+ and floating DATE-TIME values. */
+ void setDefaultTimezone (in CalTimezoneObjUID tzid)
+ raises (NotFound);
+
/* Gets a VTIMEZONE component based on its TZID */
CalTimezoneObj getTimezoneObject (in CalTimezoneObjUID tzid)
raises (NotFound);
@@ -179,15 +184,16 @@ module Calendar {
raises (NotFound, InvalidRange);
- /* Updates a component by adding it if it does not exist or by
- * 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
+ /* Adds or updates one or more VEVENT/VTODO/VTIMEZONE
+ * components. The calobj should be a string representation of
+ * a complete VCALENDAR object (we also support single
+ * VEVENT/VTODO strings, but that is deprecated).
+ *
+ * The VTIMEZONE data will be merged into the calendar,
+ * possibly by renaming TZIDs (though not for builtin
+ * VTIMEZONEs, which have unique TZIDs), 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.
diff --git a/calendar/pcs/cal-backend-file.c b/calendar/pcs/cal-backend-file.c
index 471dba3fa2..adf323023a 100644
--- a/calendar/pcs/cal-backend-file.c
+++ b/calendar/pcs/cal-backend-file.c
@@ -79,6 +79,10 @@ struct _CalBackendFilePrivate {
/* Idle handler for saving the calendar when it is dirty */
guint idle_id;
+
+ /* The calendar's default timezone, used for resolving DATE and
+ floating DATE-TIME values. */
+ icaltimezone *default_zone;
};
@@ -118,6 +122,9 @@ static gboolean cal_backend_file_update_objects (CalBackend *backend, const char
static gboolean cal_backend_file_remove_object (CalBackend *backend, const char *uid);
static icaltimezone* cal_backend_file_get_timezone (CalBackend *backend, const char *tzid);
+static icaltimezone* cal_backend_file_get_default_timezone (CalBackend *backend);
+static gboolean cal_backend_file_set_default_timezone (CalBackend *backend,
+ const char *tzid);
static void notify_categories_changed (CalBackendFile *cbfile);
@@ -190,6 +197,8 @@ cal_backend_file_class_init (CalBackendFileClass *class)
backend_class->remove_object = cal_backend_file_remove_object;
backend_class->get_timezone = cal_backend_file_get_timezone;
+ backend_class->get_default_timezone = cal_backend_file_get_default_timezone;
+ backend_class->set_default_timezone = cal_backend_file_set_default_timezone;
}
static Bonobo_ConfigDatabase
@@ -235,6 +244,9 @@ cal_backend_file_init (CalBackendFile *cbfile)
priv->categories = g_hash_table_new (g_str_hash, g_str_equal);
priv->removed_categories = g_hash_table_new (g_str_hash, g_str_equal);
+ /* The timezone defaults to UTC. */
+ priv->default_zone = icaltimezone_get_utc_timezone ();
+
priv->db = load_db ();
gtk_signal_connect (GTK_OBJECT (cbfile), "cal_added",
@@ -1015,7 +1027,7 @@ cal_backend_file_get_timezone_object (CalBackend *backend, const char *tzid)
{
CalBackendFile *cbfile;
CalBackendFilePrivate *priv;
- icaltimezone *icaltz;
+ icaltimezone *zone;
icalcomponent *icalcomp;
char *ical_string;
@@ -1027,11 +1039,11 @@ cal_backend_file_get_timezone_object (CalBackend *backend, const char *tzid)
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)
+ zone = icalcomponent_get_timezone (priv->icalcomp, tzid);
+ if (!zone)
return NULL;
- icalcomp = icaltimezone_get_component (icaltz);
+ icalcomp = icaltimezone_get_component (zone);
if (!icalcomp)
return NULL;
@@ -1131,7 +1143,7 @@ add_instance (CalComponent *comp, time_t start, time_t end, gpointer data)
* within a specific time range.
*/
static void
-get_instances_in_range (GHashTable *uid_hash, GList *components, time_t start, time_t end)
+get_instances_in_range (GHashTable *uid_hash, GList *components, time_t start, time_t end, icaltimezone *default_zone)
{
GList *l;
@@ -1147,7 +1159,7 @@ get_instances_in_range (GHashTable *uid_hash, GList *components, time_t start, t
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);
+ cal_recur_generate_instances (comp, start, end, add_instance, uid_hash, resolve_tzid, vcalendar_comp, default_zone);
}
}
@@ -1188,13 +1200,16 @@ cal_backend_file_get_objects_in_range (CalBackend *backend, CalObjType type,
uid_hash = g_hash_table_new (g_str_hash, g_str_equal);
if (type & CALOBJ_TYPE_EVENT)
- get_instances_in_range (uid_hash, priv->events, start, end);
+ get_instances_in_range (uid_hash, priv->events, start, end,
+ priv->default_zone);
if (type & CALOBJ_TYPE_TODO)
- get_instances_in_range (uid_hash, priv->todos, start, end);
+ get_instances_in_range (uid_hash, priv->todos, start, end,
+ priv->default_zone);
if (type & CALOBJ_TYPE_JOURNAL)
- get_instances_in_range (uid_hash, priv->journals, start, end);
+ get_instances_in_range (uid_hash, priv->journals, start, end,
+ priv->default_zone);
event_list = NULL;
g_hash_table_foreach (uid_hash, add_uid_to_list, &event_list);
@@ -1232,6 +1247,7 @@ create_user_free_busy (CalBackendFile *cbfile, const char *address, const char *
icalcomponent_set_dtend (vfb, icaltime_from_timet (end, 1));
/* add all objects in the given interval */
+
uids = cal_backend_get_objects_in_range (CAL_BACKEND (cbfile),
CALOBJ_TYPE_ANY, start, end);
for (l = uids; l != NULL; l = l->next) {
@@ -1466,7 +1482,8 @@ cal_backend_file_get_changes (CalBackend *backend, CalObjType type, const char *
/* Get_alarms_in_range handler for the file backend */
static GNOME_Evolution_Calendar_CalComponentAlarmsSeq *
-cal_backend_file_get_alarms_in_range (CalBackend *backend, time_t start, time_t end)
+cal_backend_file_get_alarms_in_range (CalBackend *backend,
+ time_t start, time_t end)
{
CalBackendFile *cbfile;
CalBackendFilePrivate *priv;
@@ -1491,10 +1508,12 @@ cal_backend_file_get_alarms_in_range (CalBackend *backend, time_t start, time_t
n_comp_alarms += cal_util_generate_alarms_for_list (priv->events, start, end,
&comp_alarms, resolve_tzid,
- priv->icalcomp);
+ priv->icalcomp,
+ priv->default_zone);
n_comp_alarms += cal_util_generate_alarms_for_list (priv->todos, start, end,
&comp_alarms, resolve_tzid,
- priv->icalcomp);
+ priv->icalcomp,
+ priv->default_zone);
seq = GNOME_Evolution_Calendar_CalComponentAlarmsSeq__alloc ();
CORBA_sequence_set_release (seq, TRUE);
@@ -1525,7 +1544,8 @@ cal_backend_file_get_alarms_in_range (CalBackend *backend, time_t start, time_t
/* Get_alarms_for_object handler for the file backend */
static GNOME_Evolution_Calendar_CalComponentAlarms *
cal_backend_file_get_alarms_for_object (CalBackend *backend, const char *uid,
- time_t start, time_t end, gboolean *object_found)
+ time_t start, time_t end,
+ gboolean *object_found)
{
CalBackendFile *cbfile;
CalBackendFilePrivate *priv;
@@ -1558,7 +1578,7 @@ cal_backend_file_get_alarms_for_object (CalBackend *backend, const char *uid,
corba_alarms->calobj = CORBA_string_dup (comp_str);
g_free (comp_str);
- alarms = cal_util_generate_alarms_for_comp (comp, start, end, resolve_tzid, priv->icalcomp);
+ alarms = cal_util_generate_alarms_for_comp (comp, start, end, resolve_tzid, priv->icalcomp, priv->default_zone);
if (alarms) {
cal_backend_util_fill_alarm_instances_seq (&corba_alarms->alarms, alarms->alarms);
cal_component_alarms_free (alarms);
@@ -1632,6 +1652,48 @@ clean_removed_categories (CalBackendFile *cbfile)
NULL);
}
+
+/* Creates a CalComponent for the given icalcomponent and adds it to our
+ cache. Note that the icalcomponent is not added to the toplevel
+ icalcomponent here. That needs to be done elsewhere. It returns the uid
+ of the added component, or NULL if it failed. */
+static const char*
+cal_backend_file_update_object (CalBackendFile *cbfile,
+ icalcomponent *icalcomp)
+{
+ CalComponent *old_comp;
+ CalComponent *comp;
+ const char *comp_uid;
+
+ /* Create a CalComponent wrapper for the icalcomponent. */
+ comp = cal_component_new ();
+ if (!cal_component_set_icalcomponent (comp, icalcomp)) {
+ gtk_object_unref (GTK_OBJECT (comp));
+ return NULL;
+ }
+
+ /* Get the UID, and check it isn't empty. */
+ cal_component_get_uid (comp, &comp_uid);
+ if (!comp_uid || !comp_uid[0]) {
+ gtk_object_unref (GTK_OBJECT (comp));
+ return NULL;
+ }
+
+ /* Remove any old version of the component. */
+ old_comp = lookup_component (cbfile, comp_uid);
+ if (old_comp)
+ remove_component (cbfile, old_comp);
+
+ /* Now add the component to our local cache, but we pass FALSE as
+ the last argument, since the libical component is assumed to have
+ been added already. */
+ add_component (cbfile, comp, FALSE);
+
+ return comp_uid;
+}
+
+
+
/* Update_objects handler for the file backend. */
static gboolean
cal_backend_file_update_objects (CalBackend *backend, const char *calobj)
@@ -1640,10 +1702,10 @@ cal_backend_file_update_objects (CalBackend *backend, const char *calobj)
CalBackendFilePrivate *priv;
icalcomponent *toplevel_comp, *icalcomp = NULL;
icalcomponent_kind kind;
- CalComponent *old_comp;
- CalComponent *comp;
- const char *comp_uid;
int old_n_categories, new_n_categories;
+ icalcomponent *subcomp;
+ gboolean retval = TRUE;
+ GList *comp_uid_list = NULL, *elem;
cbfile = CAL_BACKEND_FILE (backend);
priv = cbfile->priv;
@@ -1661,62 +1723,20 @@ cal_backend_file_update_objects (CalBackend *backend, const char *calobj)
kind = icalcomponent_isa (toplevel_comp);
- if (kind == ICAL_VCALENDAR_COMPONENT) {
- int num_found = 0;
- icalcomponent_kind child_kind;
- icalcomponent *subcomp;
-
- /* 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. */
- subcomp = icalcomponent_get_first_component (toplevel_comp,
- ICAL_ANY_COMPONENT);
- while (subcomp) {
- child_kind = icalcomponent_isa (subcomp);
- if (child_kind == ICAL_VEVENT_COMPONENT
- || child_kind == ICAL_VTODO_COMPONENT
- || child_kind == ICAL_VJOURNAL_COMPONENT) {
- icalcomp = subcomp;
- num_found++;
- }
- subcomp = icalcomponent_get_next_component (toplevel_comp,
- ICAL_ANY_COMPONENT);
- }
-
- /* If we didn't find exactly 1 VEVENT/VTODO it is an error. */
- if (num_found != 1) {
- icalcomponent_free (toplevel_comp);
- return FALSE;
- }
-
- } else if (kind == ICAL_VEVENT_COMPONENT
- || kind == ICAL_VTODO_COMPONENT
- || kind == ICAL_VJOURNAL_COMPONENT) {
+ if (kind == ICAL_VEVENT_COMPONENT
+ || kind == ICAL_VTODO_COMPONENT
+ || kind == ICAL_VJOURNAL_COMPONENT) {
+ /* Create a temporary toplevel component and put the VEVENT
+ or VTODO in it, to simplify the code below. */
icalcomp = toplevel_comp;
- } else {
+ toplevel_comp = cal_util_new_top_level ();
+ icalcomponent_add_component (toplevel_comp, icalcomp);
+ } else if (kind != ICAL_VCALENDAR_COMPONENT) {
/* We don't support this type of component */
icalcomponent_free (toplevel_comp);
return FALSE;
}
- comp = cal_component_new ();
- if (!cal_component_set_icalcomponent (comp, icalcomp)) {
- gtk_object_unref (GTK_OBJECT (comp));
- icalcomponent_free (toplevel_comp);
- return FALSE;
- }
-
- /* Get the UID, and check it isn't empty. */
-
- cal_component_get_uid (comp, &comp_uid);
-
- if (!comp_uid || !comp_uid[0]) {
- gtk_object_unref (GTK_OBJECT (comp));
- if (kind == ICAL_VCALENDAR_COMPONENT)
- icalcomponent_free (toplevel_comp);
- return FALSE;
- }
-
/* The list of removed categories must be empty because we are about to
* start a new scanning process.
*/
@@ -1724,32 +1744,54 @@ cal_backend_file_update_objects (CalBackend *backend, const char *calobj)
old_n_categories = g_hash_table_size (priv->categories);
- /* Update the component */
-
- old_comp = lookup_component (cbfile, comp_uid);
-
- if (old_comp)
- remove_component (cbfile, old_comp);
-
- 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, toplevel_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);
+ /* Step throught the VEVENT/VTODOs being added, create CalComponents
+ for them, and add them to our cache. */
+ subcomp = icalcomponent_get_first_component (toplevel_comp,
+ ICAL_ANY_COMPONENT);
+ while (subcomp) {
+ /* We ignore anything except VEVENT, VTODO and VJOURNAL
+ components. */
+ icalcomponent_kind child_kind = icalcomponent_isa (icalcomp);
+ if (child_kind == ICAL_VEVENT_COMPONENT
+ || child_kind == ICAL_VTODO_COMPONENT
+ || child_kind == ICAL_VJOURNAL_COMPONENT) {
+ const char *comp_uid;
+
+ comp_uid = cal_backend_file_update_object (cbfile,
+ icalcomp);
+ if (comp_uid) {
+ /* We add a copy of the UID to a list, so we
+ can emit notification signals later. We do
+ a g_strdup() in case any of the components
+ get removed while we are emitting
+ notification signals. */
+ comp_uid_list = g_list_prepend (comp_uid_list,
+ g_strdup (comp_uid));
+ } else {
+ retval = FALSE;
+ }
+ }
+ subcomp = icalcomponent_get_next_component (toplevel_comp,
+ ICAL_ANY_COMPONENT);
}
+ /* Merge the iCalendar components with our existing VCALENDAR,
+ resolving any conflicting TZIDs. */
+ icalcomponent_merge_component (priv->icalcomp, toplevel_comp);
+
new_n_categories = g_hash_table_size (priv->categories);
mark_dirty (cbfile);
- notify_update (cbfile, comp_uid);
+ /* Now emit notification signals for all of the added components.
+ We do this after adding them all to make sure the calendar is in a
+ stable state before emitting signals. */
+ for (elem = comp_uid_list; elem; elem = elem->next) {
+ char *comp_uid = elem->data;
+ notify_update (cbfile, comp_uid);
+ g_free (comp_uid);
+ }
+ g_list_free (comp_uid_list);
if (old_n_categories != new_n_categories ||
g_hash_table_size (priv->removed_categories) != 0) {
@@ -1757,9 +1799,10 @@ cal_backend_file_update_objects (CalBackend *backend, const char *calobj)
notify_categories_changed (cbfile);
}
- return TRUE;
+ return retval;
}
+
/* Remove_object handler for the file backend */
static gboolean
cal_backend_file_remove_object (CalBackend *backend, const char *uid)
@@ -1816,3 +1859,43 @@ cal_backend_file_get_timezone (CalBackend *backend, const char *tzid)
return icalcomponent_get_timezone (priv->icalcomp, tzid);
}
+
+static icaltimezone*
+cal_backend_file_get_default_timezone (CalBackend *backend)
+{
+ CalBackendFile *cbfile;
+ CalBackendFilePrivate *priv;
+
+ cbfile = CAL_BACKEND_FILE (backend);
+ priv = cbfile->priv;
+
+ g_return_val_if_fail (priv->icalcomp != NULL, NULL);
+
+ return priv->default_zone;
+}
+
+
+static gboolean
+cal_backend_file_set_default_timezone (CalBackend *backend,
+ const char *tzid)
+{
+ CalBackendFile *cbfile;
+ CalBackendFilePrivate *priv;
+ icaltimezone *zone;
+
+ cbfile = CAL_BACKEND_FILE (backend);
+ priv = cbfile->priv;
+
+ g_return_val_if_fail (priv->icalcomp != NULL, FALSE);
+
+ /* Look up the VTIMEZONE in our icalcomponent. */
+ zone = icalcomponent_get_timezone (priv->icalcomp, tzid);
+ if (!zone)
+ return FALSE;
+
+ /* Set the default timezone to it. */
+ priv->default_zone = zone;
+
+ return TRUE;
+}
+
diff --git a/calendar/pcs/cal-backend.c b/calendar/pcs/cal-backend.c
index d123f17ec6..149467ecd4 100644
--- a/calendar/pcs/cal-backend.c
+++ b/calendar/pcs/cal-backend.c
@@ -575,7 +575,8 @@ cal_backend_get_changes (CalBackend *backend, CalObjType type, const char *chang
* if @valid_range returns FALSE.
**/
GNOME_Evolution_Calendar_CalComponentAlarmsSeq *
-cal_backend_get_alarms_in_range (CalBackend *backend, time_t start, time_t end, gboolean *valid_range)
+cal_backend_get_alarms_in_range (CalBackend *backend, time_t start, time_t end,
+ gboolean *valid_range)
{
g_return_val_if_fail (backend != NULL, NULL);
g_return_val_if_fail (IS_CAL_BACKEND (backend), NULL);
@@ -764,8 +765,7 @@ cal_backend_obj_removed (CalBackend *backend, const char *uid)
* Returns the icaltimezone* corresponding to the TZID, or NULL if the TZID
* can't be found.
*
- * Return value: TRUE on success, FALSE on being passed an UID for an object
- * that does not exist in the backend.
+ * Returns: The icaltimezone* corresponding to the given TZID, or NULL.
**/
icaltimezone*
cal_backend_get_timezone (CalBackend *backend, const char *tzid)
@@ -778,3 +778,46 @@ cal_backend_get_timezone (CalBackend *backend, const char *tzid)
return (* CLASS (backend)->get_timezone) (backend, tzid);
}
+
+/**
+ * cal_backend_get_default_timezone:
+ * @backend: A calendar backend.
+ *
+ * Returns the default timezone for the calendar, which is used to resolve
+ * DATE and floating DATE-TIME values.
+ *
+ * Returns: The default icaltimezone* for the calendar.
+ **/
+icaltimezone*
+cal_backend_get_default_timezone (CalBackend *backend)
+{
+ g_return_val_if_fail (backend != NULL, NULL);
+ g_return_val_if_fail (IS_CAL_BACKEND (backend), NULL);
+
+ g_assert (CLASS (backend)->get_default_timezone != NULL);
+ return (* CLASS (backend)->get_default_timezone) (backend);
+}
+
+
+/**
+ * cal_backend_set_default_timezone:
+ * @backend: A calendar backend.
+ * @tzid: The TZID identifying the timezone.
+ *
+ * Sets the default timezone for the calendar, which is used to resolve
+ * DATE and floating DATE-TIME values.
+ *
+ * Returns: TRUE if the VTIMEZONE data for the timezone was found, or FALSE if
+ * not.
+ **/
+gboolean
+cal_backend_set_default_timezone (CalBackend *backend, const char *tzid)
+{
+ g_return_val_if_fail (backend != NULL, FALSE);
+ g_return_val_if_fail (IS_CAL_BACKEND (backend), FALSE);
+ g_return_val_if_fail (tzid != NULL, FALSE);
+
+ g_assert (CLASS (backend)->set_default_timezone != NULL);
+ return (* CLASS (backend)->set_default_timezone) (backend, tzid);
+}
+
diff --git a/calendar/pcs/cal-backend.h b/calendar/pcs/cal-backend.h
index 669de43f8e..e3aa6d55e0 100644
--- a/calendar/pcs/cal-backend.h
+++ b/calendar/pcs/cal-backend.h
@@ -113,6 +113,8 @@ struct _CalBackendClass {
/* Timezone related virtual methods */
icaltimezone *(* get_timezone) (CalBackend *backend, const char *tzid);
+ icaltimezone *(* get_default_timezone) (CalBackend *backend);
+ gboolean (* set_default_timezone) (CalBackend *backend, const char *tzid);
};
GtkType cal_backend_get_type (void);
@@ -135,6 +137,8 @@ char *cal_backend_get_object (CalBackend *backend, const char *uid);
CalComponent *cal_backend_get_object_component (CalBackend *backend, const char *uid);
+gboolean cal_backend_set_default_timezone (CalBackend *backend, const char *tzid);
+
char *cal_backend_get_timezone_object (CalBackend *backend, const char *tzid);
CalObjType cal_backend_get_type_by_uid (CalBackend *backend, const char *uid);
@@ -163,6 +167,7 @@ gboolean cal_backend_update_objects (CalBackend *backend, const char *calobj);
gboolean cal_backend_remove_object (CalBackend *backend, const char *uid);
icaltimezone* cal_backend_get_timezone (CalBackend *backend, const char *tzid);
+icaltimezone* cal_backend_get_default_timezone (CalBackend *backend);
void cal_backend_last_client_gone (CalBackend *backend);
void cal_backend_opened (CalBackend *backend, CalBackendOpenStatus status);
diff --git a/calendar/pcs/cal.c b/calendar/pcs/cal.c
index 0d0e8e4a8b..cee41fd6d9 100644
--- a/calendar/pcs/cal.c
+++ b/calendar/pcs/cal.c
@@ -448,6 +448,26 @@ impl_Cal_get_query (PortableServer_Servant servant,
return query_copy;
}
+/* Cal::set_default_timezone method */
+static void
+impl_Cal_set_default_timezone (PortableServer_Servant servant,
+ const GNOME_Evolution_Calendar_CalTimezoneObjUID tzid,
+ CORBA_Environment *ev)
+{
+ Cal *cal;
+ CalPrivate *priv;
+ gboolean zone_set;
+
+ cal = CAL (bonobo_object_from_servant (servant));
+ priv = cal->priv;
+
+ zone_set = cal_backend_set_default_timezone (priv->backend, tzid);
+
+ if (!zone_set) {
+ bonobo_exception_set (ev, ex_GNOME_Evolution_Calendar_Cal_NotFound);
+ }
+}
+
/* Cal::get_timezone_object method */
static GNOME_Evolution_Calendar_CalObj
impl_Cal_get_timezone_object (PortableServer_Servant servant,
@@ -609,6 +629,7 @@ cal_class_init (CalClass *klass)
epv->setMode = impl_Cal_set_mode;
epv->countObjects = impl_Cal_get_n_objects;
epv->getObject = impl_Cal_get_object;
+ epv->setDefaultTimezone = impl_Cal_set_default_timezone;
epv->getTimezoneObject = impl_Cal_get_timezone_object;
epv->getUIDs = impl_Cal_get_uids;
epv->getChanges = impl_Cal_get_changes;
diff --git a/calendar/pcs/query.c b/calendar/pcs/query.c
index 0fd8a8a847..e3a77d0dc4 100644
--- a/calendar/pcs/query.c
+++ b/calendar/pcs/query.c
@@ -50,6 +50,9 @@ struct _QueryPrivate {
/* The backend we are monitoring */
CalBackend *backend;
+ /* The default timezone for the calendar. */
+ icaltimezone *default_zone;
+
/* Listener to which we report changes in the live query */
GNOME_Evolution_Calendar_QueryListener ql;
@@ -117,6 +120,7 @@ query_init (Query *query)
query->priv = priv;
priv->backend = NULL;
+ priv->default_zone = NULL;
priv->ql = CORBA_OBJECT_NIL;
priv->sexp = NULL;
@@ -526,7 +530,7 @@ func_occur_in_time_range (ESExp *esexp, int argc, ESExpResult **argv, void *data
cal_recur_generate_instances (comp, start, end,
instance_occur_cb, &occurs,
- resolve_tzid, query);
+ resolve_tzid, query, priv->default_zone);
result = e_sexp_result_new (esexp, ESEXP_RES_BOOL);
result->value.bool = occurs;
@@ -1383,6 +1387,8 @@ query_construct (Query *query,
priv->backend = backend;
gtk_object_ref (GTK_OBJECT (priv->backend));
+ priv->default_zone = cal_backend_get_default_timezone (backend);
+
gtk_signal_connect (GTK_OBJECT (priv->backend), "obj_updated",
GTK_SIGNAL_FUNC (backend_obj_updated_cb),
query);