[gnome-calendar/wip/pandusonu/week-view: 52/60] week-header: implement merging of consecultive events



commit 92ba507b9ee086b1718685f5e549fb4c7d6bddf4
Author: Georges Basile Stavracas Neto <georges stavracas gmail com>
Date:   Sun Nov 6 19:28:25 2016 -0200

    week-header: implement merging of consecultive events
    
    When an event is placed in the same row consecultively, we must
    guarantee that it's only one widget.

 src/views/gcal-week-header.c |  268 +++++++++++++++++++++++++++++++++++++++---
 1 files changed, 249 insertions(+), 19 deletions(-)
---
diff --git a/src/views/gcal-week-header.c b/src/views/gcal-week-header.c
index 2821b42..00974ce 100644
--- a/src/views/gcal-week-header.c
+++ b/src/views/gcal-week-header.c
@@ -185,6 +185,205 @@ add_event_to_weekday (GcalWeekHeader *self,
   self->events[weekday] = l;
 }
 
+static gint
+merge_events (GcalWeekHeader *self,
+              GtkWidget      *event,
+              GtkWidget      *to_be_removed)
+{
+  gint deleted_width, current_width;
+
+  /* Retrieve the current sizes */
+  gtk_container_child_get (GTK_CONTAINER (self->grid),
+                           to_be_removed,
+                           "width", &deleted_width,
+                           NULL);
+
+  if (event == to_be_removed)
+    goto out;
+
+  gtk_container_child_get (GTK_CONTAINER (self->grid),
+                           event,
+                           "width", &current_width,
+                           NULL);
+
+  gtk_widget_destroy (to_be_removed);
+
+  /* Update the event's size */
+  gtk_container_child_set (GTK_CONTAINER (self->grid),
+                           event,
+                           "width", current_width + deleted_width,
+                           NULL);
+
+out:
+  return deleted_width;
+}
+
+static void
+check_mergeable_events (GcalWeekHeader *self)
+{
+  gint weekday;
+
+  /* We don't need to check the last column */
+  for (weekday = 0; weekday < 6; weekday++)
+    {
+      GList *events_at_weekday, *l;
+      gint index;
+
+      index = 0;
+      events_at_weekday = self->events[weekday];
+
+      for (l = events_at_weekday; l != NULL; l = l->next)
+        {
+          GcalEvent *current_event;
+          gint events_to_merge, i;
+
+          current_event = l->data;
+          events_to_merge = 0;
+
+          /* No need to continue if we're hiding the events */
+          if (!self->expanded && index > 3)
+            break;
+
+          /*
+           * Horizontally check if the next cells have the same event
+           * than the current cell.
+           */
+          for (i = 1; i < 7 - weekday; i++)
+            {
+              GcalEvent *next_event;
+
+              next_event = g_list_nth_data (self->events[weekday + 1], index);
+
+              if (next_event != current_event)
+                break;
+
+              events_to_merge++;
+            }
+
+          /* We found events to merge. Lets merge them */
+          i = 0;
+
+          while (events_to_merge > 0)
+            {
+              GtkWidget *current_widget, *to_be_removed;
+              gint removed_cells;
+
+              current_widget = gtk_grid_get_child_at (GTK_GRID (self->grid), weekday + i, index);
+              to_be_removed = gtk_grid_get_child_at (GTK_GRID (self->grid), weekday + i + 1, index);
+
+              /* First, remove the events from the cells */
+              removed_cells = merge_events (self, current_widget, to_be_removed);
+
+              events_to_merge -= removed_cells;
+              i += removed_cells;
+            }
+
+          index++;
+        }
+    }
+}
+
+static void
+split_event_widget_at_column (GcalWeekHeader *self,
+                              GtkWidget      *widget,
+                              gint            column)
+{
+  GDateTime *week_start, *column_date, *end_column_date;
+  GcalEvent *event;
+  gboolean create_before;
+  gboolean create_after;
+  gint left_attach;
+  gint top_attach;
+  gint new_width;
+  gint old_width;
+
+  week_start = get_start_of_week (self->active_date);
+  column_date = g_date_time_add_days (week_start, column);
+  end_column_date = g_date_time_add_days (column_date, 1);
+  event = gcal_event_widget_get_event (GCAL_EVENT_WIDGET (widget));
+
+  create_before = column > 0 && g_date_time_compare (gcal_event_get_date_start (event), column_date) < 0;
+  create_after = column < 6 && g_date_time_compare (gcal_event_get_date_end (event), end_column_date) >= 0;
+
+  gtk_container_child_get (GTK_CONTAINER (self->grid),
+                           widget,
+                           "top_attach", &top_attach,
+                           "left_attach", &left_attach,
+                           "width", &old_width,
+                           NULL);
+
+
+  g_message ("  -  -  -  breaking event '%s'", gcal_event_get_summary (event));
+
+  if (create_before)
+    {
+      GtkWidget *widget_before;
+
+      g_message ("  -  -  -  -  creating new widget before");
+
+      widget_before = gcal_event_widget_clone (GCAL_EVENT_WIDGET (widget));
+
+      gtk_grid_attach (GTK_GRID (self->grid),
+                       widget_before,
+                       left_attach,
+                       top_attach,
+                       column - left_attach,
+                       1);
+
+      new_width = old_width - column + left_attach;
+      old_width = new_width;
+      left_attach = column;
+
+      /* Update the current event position and size */
+      gtk_container_child_set (GTK_CONTAINER (self->grid),
+                               widget,
+                               "left_attach", left_attach,
+                               "width", new_width,
+                               NULL);
+
+      gtk_widget_show (widget_before);
+    }
+
+  /* Create a new widget after the current widget */
+  if (create_after)
+    {
+      GtkWidget *widget_after;
+
+      g_message ("  -  -  -  -  creating new widget after");
+
+      widget_after = gcal_event_widget_clone (GCAL_EVENT_WIDGET (widget));
+      gcal_event_widget_set_date_start (GCAL_EVENT_WIDGET (widget_after), end_column_date);
+      gcal_event_widget_set_date_end (GCAL_EVENT_WIDGET (widget_after),
+                                      gcal_event_widget_get_date_end (GCAL_EVENT_WIDGET (widget)));
+
+      gtk_grid_attach (GTK_GRID (self->grid),
+                       widget_after,
+                       column + 1,
+                       top_attach,
+                       old_width - 1,
+                       1);
+
+      new_width = old_width - (column - left_attach + 1);
+
+      g_message ("  -  -  -  -  placing new widget at (x: %d, y: %d, w: %d)",
+                 column + 1,
+                 top_attach,
+                 new_width);
+
+      /* Only update the current widget's width */
+      gtk_container_child_set (GTK_CONTAINER (self->grid),
+                               widget,
+                               "width", new_width,
+                               NULL);
+
+      gtk_widget_show (widget_after);
+    }
+
+  g_clear_pointer (&end_column_date, g_date_time_unref);
+  g_clear_pointer (&column_date, g_date_time_unref);
+  g_clear_pointer (&week_start, g_date_time_unref);
+}
+
 static void
 move_events_at_column (GcalWeekHeader *self,
                        gint            column,
@@ -234,16 +433,22 @@ move_events_at_column (GcalWeekHeader *self,
    */
   for (l = found_widgets; l != NULL; l = l->next)
     {
-      gint top_attach;
+      gint top_attach, left_attach, width;
 
       /* Get the widget's current position... */
       gtk_container_child_get (GTK_CONTAINER (self->grid),
                                l->data,
                                "top_attach", &top_attach,
+                               "left_attach", &left_attach,
+                               "width", &width,
                                NULL);
 
       g_message ("  -  -  -  setting top_attach to %d", top_attach + 1);
 
+      /* If this is a multiday event, break it */
+      if (width > 1)
+        split_event_widget_at_column (self, l->data, column);
+
       /* And move it to position + 1 */
       gtk_container_child_set (GTK_CONTAINER (self->grid),
                                l->data,
@@ -251,6 +456,9 @@ move_events_at_column (GcalWeekHeader *self,
                                NULL);
     }
 
+  /* Check if we eventually can merge events */
+  check_mergeable_events (self);
+
   g_clear_pointer (&found_widgets, g_list_free);
 }
 
@@ -260,7 +468,7 @@ add_event_to_grid (GcalWeekHeader *self,
                    gint            start,
                    gint            end)
 {
-  GDateTime *widget_start_dt, *widget_end_dt;
+  GDateTime *week_start, *week_end, *widget_end_dt;
   GtkWidget *widget;
   gint events_at_weekday;
   gint position;
@@ -307,15 +515,15 @@ add_event_to_grid (GcalWeekHeader *self,
   if (!gcal_event_is_multiday (event))
     return;
 
+  week_start = get_start_of_week (self->active_date);
+  week_end = get_end_of_week (self->active_date);
+
   /* Setup the event's start date */
-  widget_start_dt = get_start_of_week (self->active_date);
-  widget_end_dt = g_date_time_add_days (widget_start_dt, 1);
+  widget_end_dt = g_date_time_add_days (week_start, 1);
 
-  gcal_event_widget_set_date_start (GCAL_EVENT_WIDGET (widget), widget_start_dt);
+  gcal_event_widget_set_date_start (GCAL_EVENT_WIDGET (widget), week_start);
   gcal_event_widget_set_date_end (GCAL_EVENT_WIDGET (widget), widget_end_dt);
 
-  g_clear_pointer (&widget_start_dt, g_date_time_unref);
-
   /*
    * In addition to moving the current column's events below, multiday
    * events must also move the events from ~all~ the columns it spans
@@ -323,9 +531,11 @@ add_event_to_grid (GcalWeekHeader *self,
    */
   for (i = start + 1; i <= end; i++)
     {
+      GDateTime *new_widget_end_dt;
       gint new_position;
 
       events_at_weekday = g_list_length (self->events[i]);
+      new_widget_end_dt = g_date_time_add_days (widget_end_dt, 1);
 
       /* Add the event to that day */
       add_event_to_weekday (self, event, i);
@@ -333,7 +543,6 @@ add_event_to_grid (GcalWeekHeader *self,
       g_message ("  -  -  adding event to column %d", i);
       g_message ("  -  -  -  there are %d events in this column", events_at_weekday);
 
-
       /* Check the event position at this weekday */
       new_position = g_list_index (self->events[i], event) + 1;
 
@@ -344,28 +553,49 @@ add_event_to_grid (GcalWeekHeader *self,
       /* Add the event to the grid */
       if (new_position == position)
         {
-          GDateTime *new_widget_end_dt;
-
-          new_widget_end_dt = g_date_time_add_days (widget_end_dt, 1);
-
-          /* Update the widget's end date */
-          gcal_event_widget_set_date_end (GCAL_EVENT_WIDGET (widget), new_widget_end_dt);
-
           gtk_container_child_set (GTK_CONTAINER (self->grid),
                                    widget,
                                    "width", i - start + 1,
                                    NULL);
-
-          g_clear_pointer (&widget_end_dt, g_date_time_unref);
-          widget_end_dt = new_widget_end_dt;
         }
       else
         {
-          /* TODO: clone the widget */
+          GDateTime *cloned_widget_start_dt;
+          GtkWidget *cloned_widget;
+
+          cloned_widget_start_dt = g_date_time_add_days (week_start, i);
+          cloned_widget = gcal_event_widget_clone (GCAL_EVENT_WIDGET (widget));
+
+          g_message ("  -  -  -  -  cloning event");
+
+          gtk_grid_attach (GTK_GRID (self->grid),
+                           cloned_widget,
+                           i,
+                           new_position,
+                           1,
+                           1);
+
+          gcal_event_widget_set_date_start (GCAL_EVENT_WIDGET (cloned_widget), cloned_widget_start_dt);
+
+          /* From now on, let's modify this widget */
+          widget = cloned_widget;
+
+          g_clear_pointer (&cloned_widget_start_dt, g_date_time_unref);
         }
+
+      /* Update the widget's end date */
+      gcal_event_widget_set_date_end (GCAL_EVENT_WIDGET (widget), new_widget_end_dt);
+
+      g_clear_pointer (&widget_end_dt, g_date_time_unref);
+
+      widget_end_dt = new_widget_end_dt;
     }
 
   gtk_widget_show (widget);
+
+  g_clear_pointer (&widget_end_dt, g_date_time_unref);
+  g_clear_pointer (&week_start, g_date_time_unref);
+  g_clear_pointer (&week_end, g_date_time_unref);
 }
 
 static void


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