[gnome-calendar] event: rewrite timezone support



commit a799678f682d994759e563a4aab55e7926f8fa1f
Author: Georges Basile Stavracas Neto <georges stavracas gmail com>
Date:   Fri Sep 14 17:08:46 2018 -0300

    event: rewrite timezone support
    
    Now with something that hopefully works.
    
    https://gitlab.gnome.org/GNOME/gnome-calendar/issues/43
    https://gitlab.gnome.org/GNOME/gnome-calendar/issues/302

 doc/reference/gnome-calendar-decl-list.txt |   2 -
 doc/reference/gnome-calendar-decl.txt      |  10 --
 doc/reference/gnome-calendar-sections.txt  |   2 -
 src/gcal-edit-dialog.c                     | 253 +++++++++++++++------------
 src/gcal-edit-dialog.h                     |   4 -
 src/gcal-event.c                           | 271 ++++++++++++++++++-----------
 src/gcal-event.h                           |  11 +-
 src/gcal-quick-add-popover.c               |   1 -
 src/views/gcal-month-view.c                |   3 +-
 src/views/gcal-week-header.c               |   2 +-
 10 files changed, 322 insertions(+), 237 deletions(-)
---
diff --git a/doc/reference/gnome-calendar-decl-list.txt b/doc/reference/gnome-calendar-decl-list.txt
index 393afce2..e30e526f 100644
--- a/doc/reference/gnome-calendar-decl-list.txt
+++ b/doc/reference/gnome-calendar-decl-list.txt
@@ -192,8 +192,6 @@ gcal_event_get_source
 gcal_event_set_source
 gcal_event_get_summary
 gcal_event_set_summary
-gcal_event_get_timezone
-gcal_event_set_timezone
 gcal_event_get_uid
 gcal_event_is_multiday
 gcal_event_compare
diff --git a/doc/reference/gnome-calendar-decl.txt b/doc/reference/gnome-calendar-decl.txt
index 77d0ee19..d9ceee01 100644
--- a/doc/reference/gnome-calendar-decl.txt
+++ b/doc/reference/gnome-calendar-decl.txt
@@ -413,16 +413,6 @@ GcalEvent          *self
 GcalEvent          *self, const gchar        *summary
 </FUNCTION>
 <FUNCTION>
-<NAME>gcal_event_get_timezone</NAME>
-<RETURNS>GTimeZone *           </RETURNS>
-GcalEvent          *self
-</FUNCTION>
-<FUNCTION>
-<NAME>gcal_event_set_timezone</NAME>
-<RETURNS>void                  </RETURNS>
-GcalEvent          *self, GTimeZone          *timezone
-</FUNCTION>
-<FUNCTION>
 <NAME>gcal_event_get_uid</NAME>
 <RETURNS>const gchar *         </RETURNS>
 GcalEvent          *self
diff --git a/doc/reference/gnome-calendar-sections.txt b/doc/reference/gnome-calendar-sections.txt
index 8b273956..5ae522d3 100644
--- a/doc/reference/gnome-calendar-sections.txt
+++ b/doc/reference/gnome-calendar-sections.txt
@@ -195,8 +195,6 @@ gcal_event_get_source
 gcal_event_set_source
 gcal_event_get_summary
 gcal_event_set_summary
-gcal_event_get_timezone
-gcal_event_set_timezone
 gcal_event_get_uid
 gcal_event_is_multiday
 gcal_event_compare
diff --git a/src/gcal-edit-dialog.c b/src/gcal-edit-dialog.c
index a2478dc0..1cd467bb 100644
--- a/src/gcal-edit-dialog.c
+++ b/src/gcal-edit-dialog.c
@@ -260,6 +260,132 @@ on_calendar_selected (GSimpleAction *action,
   GCAL_EXIT;
 }
 
+static void
+find_best_timezones_for_event (GcalEditDialog  *self,
+                               GTimeZone      **out_tz_start,
+                               GTimeZone      **out_tz_end)
+{
+  gboolean was_all_day;
+  gboolean all_day;
+
+  /* Update all day */
+  all_day = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (self->all_day_check));
+  was_all_day = gcal_event_get_all_day (self->event);
+
+  GCAL_TRACE_MSG ("Finding best timezone with all_day=%d, was_all_day=%d, event_is_new=%d",
+                  all_day,
+                  was_all_day,
+                  self->event_is_new);
+
+  if (!self->event_is_new && was_all_day && !all_day)
+    {
+      GCAL_TRACE_MSG ("Using original event timezones");
+
+      gcal_event_get_original_timezones (self->event, out_tz_start, out_tz_end);
+      return;
+    }
+
+  if (all_day)
+    {
+      GCAL_TRACE_MSG ("Using UTC timezones");
+
+      if (out_tz_start)
+        *out_tz_start = g_time_zone_new_utc ();
+
+      if (out_tz_end)
+        *out_tz_end = g_time_zone_new_utc ();
+    }
+  else
+    {
+      g_autoptr (GTimeZone) tz_start = NULL;
+      g_autoptr (GTimeZone) tz_end = NULL;
+
+      if (self->event_is_new)
+        {
+          GCAL_TRACE_MSG ("Using the local timezone");
+
+          tz_start = g_time_zone_new_local ();
+          tz_end = g_time_zone_new_local ();
+        }
+      else
+        {
+          GCAL_TRACE_MSG ("Using the current timezones");
+
+          tz_start = g_time_zone_ref (g_date_time_get_timezone (gcal_event_get_date_start (self->event)));
+          tz_end = g_time_zone_ref (g_date_time_get_timezone (gcal_event_get_date_end (self->event)));
+        }
+
+      if (out_tz_start)
+        *out_tz_start = g_steal_pointer (&tz_start);
+
+      if (out_tz_end)
+        *out_tz_end = g_steal_pointer (&tz_end);
+    }
+}
+
+static GDateTime*
+return_datetime_for_widgets (GcalEditDialog   *self,
+                             GTimeZone        *timezone,
+                             GcalDateSelector *date_selector,
+                             GcalTimeSelector *time_selector)
+{
+  g_autoptr (GDateTime) date_in_local_tz = NULL;
+  g_autoptr (GDateTime) date_in_best_tz = NULL;
+  GDateTime *date;
+  GDateTime *time;
+  GDateTime *retval;
+  gboolean all_day;
+
+  all_day = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (self->all_day_check));
+  date = gcal_date_selector_get_date (date_selector);
+  time = gcal_time_selector_get_time (time_selector);
+
+  date_in_local_tz = g_date_time_new_local (g_date_time_get_year (date),
+                                            g_date_time_get_month (date),
+                                            g_date_time_get_day_of_month (date),
+                                            all_day ? 0 : g_date_time_get_hour (time),
+                                            all_day ? 0 : g_date_time_get_minute (time),
+                                            0);
+
+  date_in_best_tz = g_date_time_to_timezone (date_in_local_tz, timezone);
+
+  retval = g_date_time_new (timezone,
+                            g_date_time_get_year (date_in_best_tz),
+                            g_date_time_get_month (date_in_best_tz),
+                            g_date_time_get_day_of_month (date_in_best_tz),
+                            all_day ? 0 : g_date_time_get_hour (date_in_best_tz),
+                            all_day ? 0 : g_date_time_get_minute (date_in_best_tz),
+                            0);
+
+  return retval;
+}
+
+static GDateTime*
+get_date_start (GcalEditDialog *self)
+{
+  g_autoptr (GTimeZone) start_tz = NULL;
+
+  find_best_timezones_for_event (self, &start_tz, NULL);
+
+  return return_datetime_for_widgets (self,
+                                      start_tz,
+                                      GCAL_DATE_SELECTOR (self->start_date_selector),
+                                      GCAL_TIME_SELECTOR (self->start_time_selector));
+}
+
+static GDateTime*
+get_date_end (GcalEditDialog *self)
+{
+  g_autoptr (GTimeZone) end_tz = NULL;
+
+  find_best_timezones_for_event (self, NULL, &end_tz);
+
+  return return_datetime_for_widgets (self,
+                                      end_tz,
+                                      GCAL_DATE_SELECTOR (self->end_date_selector),
+                                      GCAL_TIME_SELECTOR (self->end_time_selector));
+}
+
 static void
 gcal_edit_dialog_set_writable (GcalEditDialog *dialog,
                                gboolean        writable)
@@ -382,8 +508,8 @@ sync_datetimes (GcalEditDialog *self,
 
   is_start = (widget == self->start_time_selector || widget == self->start_date_selector);
   is_all_day = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (self->all_day_check));
-  start = gcal_edit_dialog_get_date_start (self);
-  end = gcal_edit_dialog_get_date_end (self);
+  start = get_date_start (self);
+  end = get_date_end (self);
 
   /* The date is valid, no need to update the fields */
   if (g_date_time_compare (end, start) >= 0)
@@ -469,28 +595,30 @@ action_button_clicked (GtkWidget *widget,
       gcal_event_set_description (dialog->event, note_text);
       g_free (note_text);
 
-      /* Update all day */
       all_day = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (dialog->all_day_check));
       was_all_day = gcal_event_get_all_day (dialog->event);
 
-      gcal_event_set_all_day (dialog->event, all_day);
-
-      /* By definition, all day events are always UTC */
-      if (all_day)
-        {
-          GTimeZone *utc = g_time_zone_new_utc ();
-
-          gcal_event_set_timezone (dialog->event, utc);
-
-          g_clear_pointer (&utc, g_time_zone_unref);
-        }
+      if (!was_all_day && all_day)
+        gcal_event_save_original_timezones (dialog->event);
 
       /*
        * Update start & end dates. The dates are already translated to the current
        * timezone (unless the event used to be all day, but no longer is).
        */
-      start_date = gcal_edit_dialog_get_date_start (dialog);
-      end_date = gcal_edit_dialog_get_date_end (dialog);
+      start_date = get_date_start (dialog);
+      end_date = get_date_end (dialog);
+
+#ifdef GCAL_ENABLE_TRACE
+        {
+          g_autofree gchar *start_dt_string = g_date_time_format (start_date, "%x %X %z");
+          g_autofree gchar *end_dt_string = g_date_time_format (end_date, "%x %X %z");
+
+          g_debug ("New start date: %s", start_dt_string);
+          g_debug ("New end date: %s", end_dt_string);
+        }
+#endif
+
+      gcal_event_set_all_day (dialog->event, all_day);
 
       /*
        * The end date for multi-day events is exclusive, so we bump it by a day.
@@ -1454,99 +1582,6 @@ gcal_edit_dialog_set_manager (GcalEditDialog *dialog,
     g_object_notify_by_pspec (G_OBJECT (dialog), properties[PROP_MANAGER]);
 }
 
-static GDateTime*
-return_datetime_for_widgets (GcalEditDialog   *dialog,
-                             GcalDateSelector *date_selector,
-                             GcalTimeSelector *time_selector)
-{
-  GTimeZone *tz;
-  GDateTime *date;
-  GDateTime *time;
-  GDateTime *retval;
-  gboolean all_day;
-
-  /* Use UTC timezone for All Day events, otherwise use the event's timezone */
-  all_day = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (dialog->all_day_check));
-  if (all_day)
-    {
-      tz = g_time_zone_new_utc ();
-    }
-  else
-    {
-      if (gcal_event_get_timezone (dialog->event))
-        tz = g_time_zone_ref (gcal_event_get_timezone (dialog->event));
-      else
-        tz = g_time_zone_new_local ();
-    }
-
-  date = gcal_date_selector_get_date (date_selector);
-  time = gcal_time_selector_get_time (time_selector);
-
-  retval = g_date_time_new (tz,
-                            g_date_time_get_year (date),
-                            g_date_time_get_month (date),
-                            g_date_time_get_day_of_month (date),
-                            g_date_time_get_hour (time),
-                            g_date_time_get_minute (time),
-                            0);
-
-  /*
-   * If the event is not all day, the timezone may be different from UTC or
-   * local. In any case, since we're editing the event in the current timezone,
-   * we should always correct the timezone to the event's timezone.
-   */
-  if (!all_day)
-    {
-      GDateTime *aux = retval;
-
-      retval = g_date_time_to_timezone (aux, gcal_event_get_timezone (dialog->event));
-
-      g_clear_pointer (&aux, g_date_time_unref);
-    }
-
-  g_clear_pointer (&tz, g_time_zone_unref);
-
-  return retval;
-}
-
-/**
- * gcal_edit_dialog_get_date_start:
- * @dialog: a #GcalEditDialog
- *
- * Retrieves the start date of the edit dialog.
- *
- * Returns: (transfer full): a #GDateTime
- */
-GDateTime*
-gcal_edit_dialog_get_date_start (GcalEditDialog *dialog)
-{
-
-  g_return_val_if_fail (GCAL_IS_EDIT_DIALOG (dialog), NULL);
-
-  return return_datetime_for_widgets (dialog,
-                                      GCAL_DATE_SELECTOR (dialog->start_date_selector),
-                                      GCAL_TIME_SELECTOR (dialog->start_time_selector));
-}
-
-/**
- * gcal_edit_dialog_get_date_end:
- * @dialog: a #GcalEditDialog
- *
- * Retrieves the end date of the edit dialog.
- *
- * Returns: (transfer full): a #GDateTime
- */
-GDateTime*
-gcal_edit_dialog_get_date_end (GcalEditDialog *dialog)
-{
-  g_return_val_if_fail (GCAL_IS_EDIT_DIALOG (dialog), NULL);
-
-  return return_datetime_for_widgets (dialog,
-                                      GCAL_DATE_SELECTOR (dialog->end_date_selector),
-                                      GCAL_TIME_SELECTOR (dialog->end_time_selector));
-}
-
-
 gboolean
 gcal_edit_dialog_get_recurrence_changed (GcalEditDialog *self)
 {
diff --git a/src/gcal-edit-dialog.h b/src/gcal-edit-dialog.h
index 73222d21..dfac6b52 100644
--- a/src/gcal-edit-dialog.h
+++ b/src/gcal-edit-dialog.h
@@ -51,10 +51,6 @@ void                 gcal_edit_dialog_set_manager             (GcalEditDialog *d
 void                 gcal_edit_dialog_set_time_format         (GcalEditDialog *dialog,
                                                                GcalTimeFormat  time_format);
 
-GDateTime*           gcal_edit_dialog_get_date_end            (GcalEditDialog *dialog);
-
-GDateTime*           gcal_edit_dialog_get_date_start          (GcalEditDialog *dialog);
-
 gboolean             gcal_edit_dialog_get_recurrence_changed   (GcalEditDialog *self);
 
 GcalRecurrenceModType gcal_edit_dialog_get_recurrence_mod_type (GcalEditDialog *self);
diff --git a/src/gcal-event.c b/src/gcal-event.c
index c318f830..e8eada98 100644
--- a/src/gcal-event.c
+++ b/src/gcal-event.c
@@ -19,6 +19,7 @@
 #define G_LOG_DOMAIN "GcalEvent"
 
 #include "gconstructor.h"
+#include "gcal-debug.h"
 #include "gcal-event.h"
 #include "gcal-utils.h"
 #include "gcal-recurrence.h"
@@ -45,19 +46,6 @@
  * can generate an error. At the moment, the only error that
  * can be generate is #GCAL_EVENT_ERROR_INVALID_START_DATE.
  *
- * ## Timezones
- *
- * When a #GcalEvent is created, the timezone is parsed from
- * the #ECalComponent. The start and end dates can possibly
- * have different timezones, e.g. when the user is traveling
- * across timezones and the departure time is in a different
- * timezone of the arrival time.
- *
- * For the sake of sanity, gcal_event_get_timezone() returns
- * the timezone of the start date. If you need to precisely
- * check the timezones of the start and end dates, you have
- * to use g_date_time_get_timezone_identifier().
- *
  * ## Example:
  * |[<!-- language="C" -->
  * GcalEvent *event;
@@ -91,7 +79,6 @@ struct _GcalEvent
    */
   gchar              *description;
 
-  GTimeZone          *timezone;
   GDateTime          *dt_start;
   GDateTime          *dt_end;
 
@@ -177,8 +164,11 @@ destroy_event_cache_map (void)
 static GTimeZone*
 get_timezone_from_ical (ECalComponentDateTime *comp)
 {
+  const icaltimezone *zone;
   GTimeZone *tz;
 
+  zone = icaltime_get_timezone (*comp->value);
+
   if (comp->value->is_date)
     {
       /*
@@ -188,30 +178,25 @@ get_timezone_from_ical (ECalComponentDateTime *comp)
        */
       tz = g_time_zone_new_utc ();
     }
-  else if (icaltime_get_timezone (*comp->value))
+  else if (comp->tzid)
     {
-      g_autofree gchar *tzid = NULL;
-      gint offset;
+      const gchar *real_tzid;
 
-      offset = icaltimezone_get_utc_offset ((icaltimezone*) icaltime_get_timezone (*comp->value),
-                                            comp->value, NULL);
-      tzid = format_utc_offset (offset);
-      tz = g_time_zone_new (tzid);
+      real_tzid = comp->tzid;
+
+      if (g_str_has_prefix (comp->tzid, LIBICAL_TZID_PREFIX))
+        real_tzid += strlen (LIBICAL_TZID_PREFIX);
+
+      tz = g_time_zone_new (real_tzid);
     }
-  else if (comp->tzid)
+  else if (zone)
     {
       g_autofree gchar *tzid = NULL;
-      icaltimezone *zone;
       gint offset;
 
-      if (g_str_has_prefix (comp->tzid, LIBICAL_TZID_PREFIX))
-        zone = icaltimezone_get_builtin_timezone_from_tzid (comp->tzid);
-      else
-        zone = icaltimezone_get_builtin_timezone (comp->tzid);
-
-      offset = icaltimezone_get_utc_offset (zone, comp->value, NULL);
+      offset = icaltimezone_get_utc_offset ((icaltimezone*) icaltime_get_timezone (*comp->value),
+                                            comp->value, NULL);
       tzid = format_utc_offset (offset);
-
       tz = g_time_zone_new (tzid);
     }
   else
@@ -219,6 +204,10 @@ get_timezone_from_ical (ECalComponentDateTime *comp)
       tz = g_time_zone_new_utc ();
     }
 
+  g_assert (tz != NULL);
+
+  GCAL_TRACE_MSG ("%s (%p)", g_time_zone_get_identifier (tz), tz);
+
   return tz;
 }
 
@@ -360,6 +349,8 @@ gcal_event_set_component_internal (GcalEvent     *self,
           *start.value = icaltime_today ();
         }
 
+      GCAL_TRACE_MSG ("Retrieving start timezone");
+
       date = icaltime_normalize (*start.value);
       zone_start = get_timezone_from_ical (&start);
       date_start = g_date_time_new (zone_start,
@@ -371,10 +362,6 @@ gcal_event_set_component_internal (GcalEvent     *self,
 
       self->dt_start = date_start;
 
-
-      /* The timezone of the event is the timezone of the start date */
-      self->timezone = g_time_zone_ref (zone_start);
-
       /* Setup end date */
       e_cal_component_get_dtend (component, &end);
 
@@ -384,6 +371,8 @@ gcal_event_set_component_internal (GcalEvent     *self,
         }
       else
         {
+          GCAL_TRACE_MSG ("Retrieving end timezone");
+
           date = icaltime_normalize (*end.value);
           zone_end = get_timezone_from_ical (&end);
           date_end = g_date_time_new (zone_end,
@@ -473,7 +462,6 @@ gcal_event_finalize (GObject *object)
 
   g_clear_pointer (&self->dt_start, g_date_time_unref);
   g_clear_pointer (&self->dt_end, g_date_time_unref);
-  g_clear_pointer (&self->timezone, g_time_zone_unref);
   g_clear_pointer (&self->description, g_free);
   g_clear_pointer (&self->alarms, g_hash_table_unref);
   g_clear_pointer (&self->uid, g_free);
@@ -531,10 +519,6 @@ gcal_event_get_property (GObject    *object,
       g_value_set_string (value, gcal_event_get_summary (self));
       break;
 
-    case PROP_TIMEZONE:
-      g_value_set_boxed (value, self->timezone);
-      break;
-
     case PROP_UID:
       g_value_set_string (value, self->uid);
       break;
@@ -598,10 +582,6 @@ gcal_event_set_property (GObject      *object,
       gcal_event_set_summary (self, g_value_get_string (value));
       break;
 
-    case PROP_TIMEZONE:
-      gcal_event_set_timezone (self, g_value_get_boxed (value));
-      break;
-
     case PROP_RECURRENCE:
       gcal_event_set_recurrence (self, g_value_get_boxed (value));
       break;
@@ -1410,65 +1390,6 @@ gcal_event_set_summary (GcalEvent   *self,
     }
 }
 
-/**
- * gcal_event_get_timezone:
- * @self: a #GcalEvent
- *
- * Retrieves the event's timezone.
- *
- * Returns: (transfer none): a #GTimeZone
- */
-GTimeZone*
-gcal_event_get_timezone (GcalEvent *self)
-{
-  g_return_val_if_fail (GCAL_IS_EVENT (self), NULL);
-
-  return self->timezone;
-}
-
-/**
- * gcal_event_set_timezone:
- * @self: a #GcalEvent
- * @timezone: a #GTimeZone
- *
- * Sets the timezone of the event to @timezone.
- */
-void
-gcal_event_set_timezone (GcalEvent *self,
-                         GTimeZone *timezone)
-{
-  g_return_if_fail (GCAL_IS_EVENT (self));
-
-  if (self->timezone != timezone)
-    {
-      g_clear_pointer (&self->timezone, g_time_zone_unref);
-      self->timezone = g_time_zone_ref (timezone);
-
-      /* Swap the timezone from the component start & end dates*/
-      if (!self->all_day)
-        {
-          GDateTime *new_dtstart;
-
-          new_dtstart = g_date_time_to_timezone (self->dt_start, timezone);
-          gcal_event_set_date_start (self, new_dtstart);
-
-          if (self->dt_end)
-            {
-              GDateTime *new_dtend;
-
-              new_dtend = g_date_time_to_timezone (self->dt_end, timezone);
-              gcal_event_set_date_end (self, new_dtend);
-
-              g_clear_pointer (&new_dtend, g_date_time_unref);
-            }
-
-          g_clear_pointer (&new_dtstart, g_date_time_unref);
-        }
-
-      g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_TIMEZONE]);
-    }
-}
-
 /**
  * gcal_event_get_uid:
  * @self: a #GcalEvent
@@ -1705,3 +1626,149 @@ gcal_event_get_recurrence (GcalEvent *self)
 
   return self->recurrence;
 }
+
+/**
+ * gcal_event_get_original_timezones:
+ * @self: a #GcalEvent
+ * @out_start_timezone: (direction out)(nullable): the return location for the
+ * previously stored start date timezone
+ * @out_end_timezone: (direction out)(nullable): the return location for the
+ * previously stored end date timezone
+ *
+ * Retrieves the start and end date timezones previously stored by
+ * gcal_event_save_original_timezones().
+ *
+ * If gcal_event_save_original_timezones() wasn't called before,
+ * it will use local timezones instead.
+ */
+void
+gcal_event_get_original_timezones (GcalEvent  *self,
+                                   GTimeZone **out_start_timezone,
+                                   GTimeZone **out_end_timezone)
+{
+  g_autoptr (GTimeZone) original_start_tz = NULL;
+  g_autoptr (GTimeZone) original_end_tz = NULL;
+  icalcomponent *ical_comp;
+  icalproperty *property;
+
+  g_return_if_fail (GCAL_IS_EVENT (self));
+  g_assert (self->component != NULL);
+
+  ical_comp = e_cal_component_get_icalcomponent (self->component);
+
+  for (property = icalcomponent_get_first_property (ical_comp, ICAL_X_PROPERTY);
+       property;
+       property = icalcomponent_get_next_property (ical_comp, ICAL_X_PROPERTY))
+    {
+      const gchar *value;
+
+      if (original_start_tz && original_end_tz)
+        break;
+
+      if (g_strcmp0 (icalproperty_get_x_name (property), "X-GNOME-CALENDAR-ORIGINAL-TZ-START") == 0)
+        {
+          value = icalproperty_get_x (property);
+          original_start_tz = g_time_zone_new (value);
+
+          GCAL_TRACE_MSG ("Found X-GNOME-CALENDAR-ORIGINAL-TZ-START=%s", value);
+        }
+      else if (g_strcmp0 (icalproperty_get_x_name (property), "X-GNOME-CALENDAR-ORIGINAL-TZ-END") == 0)
+        {
+          value = icalproperty_get_x (property);
+          original_end_tz = g_time_zone_new (value);
+
+          GCAL_TRACE_MSG ("Found X-GNOME-CALENDAR-ORIGINAL-TZ-END=%s", value);
+        }
+    }
+
+  if (!original_start_tz)
+    original_start_tz = g_time_zone_new_local ();
+
+  if (!original_end_tz)
+    original_end_tz = g_time_zone_new_local ();
+
+  g_assert (original_start_tz != NULL);
+  g_assert (original_end_tz != NULL);
+
+  if (out_start_timezone)
+    *out_start_timezone = g_steal_pointer (&original_start_tz);
+
+  if (out_end_timezone)
+    *out_end_timezone = g_steal_pointer (&original_end_tz);
+}
+
+/**
+ * gcal_event_save_original_timezones:
+ * @self: a #GcalEvent
+ *
+ * Stores the current timezones of the start and end dates of @self
+ * into separate, GNOME Calendar specific fields. These fields can
+ * be used by gcal_event_get_original_timezones() to retrieve the
+ * previous timezones of the event later.
+ */
+void
+gcal_event_save_original_timezones (GcalEvent *self)
+{
+  icalcomponent *ical_comp;
+  icalproperty *property;
+  GTimeZone *tz;
+  gboolean has_original_start_tz;
+  gboolean has_original_end_tz;
+
+  GCAL_ENTRY;
+
+  g_return_if_fail (GCAL_IS_EVENT (self));
+  g_assert (self->component != NULL);
+
+  has_original_start_tz = FALSE;
+  has_original_end_tz = FALSE;
+  ical_comp = e_cal_component_get_icalcomponent (self->component);
+
+  for (property = icalcomponent_get_first_property (ical_comp, ICAL_X_PROPERTY);
+       property;
+       property = icalcomponent_get_next_property (ical_comp, ICAL_X_PROPERTY))
+    {
+      if (g_strcmp0 (icalproperty_get_x_name (property), "X-GNOME-CALENDAR-ORIGINAL-TZ-START") == 0)
+        {
+          tz = g_date_time_get_timezone (self->dt_start);
+          icalproperty_set_x (property, g_time_zone_get_identifier (tz));
+
+          GCAL_TRACE_MSG ("Reusing X-GNOME-CALENDAR-ORIGINAL-TZ-START property with %s", icalproperty_get_x 
(property));
+
+          has_original_start_tz = TRUE;
+        }
+      else if (g_strcmp0 (icalproperty_get_x_name (property), "X-GNOME-CALENDAR-ORIGINAL-TZ-END") == 0)
+        {
+          tz = g_date_time_get_timezone (self->dt_end);
+          icalproperty_set_x (property, g_time_zone_get_identifier (tz));
+
+          GCAL_TRACE_MSG ("Reusing X-GNOME-CALENDAR-ORIGINAL-TZ-END property with %s", icalproperty_get_x 
(property));
+
+          has_original_end_tz = TRUE;
+        }
+    }
+
+  if (!has_original_start_tz)
+    {
+      tz = g_date_time_get_timezone (self->dt_start);
+      property = icalproperty_new_x (g_time_zone_get_identifier (tz));
+      icalproperty_set_x_name (property, "X-GNOME-CALENDAR-ORIGINAL-TZ-START");
+
+      icalcomponent_add_property (ical_comp, property);
+
+      GCAL_TRACE_MSG ("Added new X-GNOME-CALENDAR-ORIGINAL-TZ-START property with %s", icalproperty_get_x 
(property));
+    }
+
+  if (!has_original_end_tz)
+    {
+      tz = g_date_time_get_timezone (self->dt_end);
+      property = icalproperty_new_x (g_time_zone_get_identifier (tz));
+      icalproperty_set_x_name (property, "X-GNOME-CALENDAR-ORIGINAL-TZ-END");
+
+      icalcomponent_add_property (ical_comp, property);
+
+      GCAL_TRACE_MSG ("Added new X-GNOME-CALENDAR-ORIGINAL-TZ-END property with %s", icalproperty_get_x 
(property));
+    }
+
+  GCAL_EXIT;
+}
diff --git a/src/gcal-event.h b/src/gcal-event.h
index f5514d0a..dd6b26ff 100644
--- a/src/gcal-event.h
+++ b/src/gcal-event.h
@@ -106,11 +106,6 @@ const gchar*         gcal_event_get_summary                      (GcalEvent
 void                 gcal_event_set_summary                      (GcalEvent          *self,
                                                                   const gchar        *summary);
 
-GTimeZone*           gcal_event_get_timezone                     (GcalEvent          *self);
-
-void                 gcal_event_set_timezone                     (GcalEvent          *self,
-                                                                  GTimeZone          *timezone);
-
 const gchar*         gcal_event_get_uid                          (GcalEvent          *self);
 
 /* Utilities */
@@ -129,6 +124,12 @@ void                 gcal_event_set_recurrence                   (GcalEvent
 
 GcalRecurrence*      gcal_event_get_recurrence                   (GcalEvent          *self);
 
+void                 gcal_event_save_original_timezones          (GcalEvent          *self);
+
+void                 gcal_event_get_original_timezones           (GcalEvent          *self,
+                                                                  GTimeZone         **start_tz,
+                                                                  GTimeZone         **end_tz);
+
 G_END_DECLS
 
 #endif /* GCAL_EVENT_H */
diff --git a/src/gcal-quick-add-popover.c b/src/gcal-quick-add-popover.c
index f5fd7ada..59567a62 100644
--- a/src/gcal-quick-add-popover.c
+++ b/src/gcal-quick-add-popover.c
@@ -686,7 +686,6 @@ edit_or_create_event (GcalQuickAddPopover *self,
 
   event = gcal_event_new (source, component, NULL);
   gcal_event_set_all_day (event, all_day);
-  gcal_event_set_timezone (event, tz);
 
   /* If we clicked edit button, send a signal; otherwise, create the event */
   if (button == self->add_button)
diff --git a/src/views/gcal-month-view.c b/src/views/gcal-month-view.c
index 18d27044..9f2c6201 100644
--- a/src/views/gcal-month-view.c
+++ b/src/views/gcal-month-view.c
@@ -687,12 +687,13 @@ allocate_multiday_events (GcalMonthView *self,
            * have to worry about the dates, since GcalEventWidget performs
            * some checks and only applies the dates when it's valid.
            */
-          dt_start = g_date_time_new (gcal_event_get_timezone (event),
+          dt_start = g_date_time_new (g_date_time_get_timezone (gcal_event_get_date_start (event)),
                                       self->date->year,
                                       self->date->month,
                                       day,
                                       0, 0, 0);
 
+          /* FIXME: use end date's timezone here */
           dt_end = g_date_time_add_days (dt_start, length);
 
           gcal_event_widget_set_date_start (GCAL_EVENT_WIDGET (child_widget), dt_start);
diff --git a/src/views/gcal-week-header.c b/src/views/gcal-week-header.c
index c2ef011d..d9b3084a 100644
--- a/src/views/gcal-week-header.c
+++ b/src/views/gcal-week-header.c
@@ -1547,7 +1547,7 @@ gcal_week_header_drag_drop (GtkWidget      *widget,
        * The only case where we don't touch the timezone is for
        * timed, multiday events.
        */
-      tmp_dt = g_date_time_new (gcal_event_get_timezone (event),
+      tmp_dt = g_date_time_new (g_date_time_get_timezone (start_date),
                                 g_date_time_get_year (week_start),
                                 g_date_time_get_month (week_start),
                                 g_date_time_get_day_of_month (week_start),


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]