[gnome-calendar/wip/flb/weather-forecast: 44/50] month-view: Show weather reports.



commit 6c0d241856486e95245df68633a0a4480c9a8dc1
Author: Florian Brosch <flo brosch gmail com>
Date:   Sun Oct 29 16:38:00 2017 +0100

    month-view: Show weather reports.
    
    This commit triggers two existing issues:
     1. window size calculation
        (this breaks month-cells)
     2. wrong reference counts in views
        (I use :destroy to avoid dangling pointers)

 data/ui/month-cell.ui       |   35 +++++---
 src/gcal-window.c           |    3 +-
 src/views/gcal-month-cell.c |   36 ++++++++-
 src/views/gcal-month-cell.h |    4 +
 src/views/gcal-month-view.c |  193 ++++++++++++++++++++++++++++++++++++++++++-
 src/views/gcal-month-view.h |    6 ++
 6 files changed, 262 insertions(+), 15 deletions(-)
---
diff --git a/data/ui/month-cell.ui b/data/ui/month-cell.ui
index fa4aaf2..78e5e64 100644
--- a/data/ui/month-cell.ui
+++ b/data/ui/month-cell.ui
@@ -38,32 +38,43 @@
                     <property name="can-focus">False</property>
                     <property name="spacing">6</property>
                     <property name="valign">center</property>
-                    <child type="center">
+                    <child>
+                      <object class="GtkImage" id="weather_icon">
+                        <property name="can-focus">False</property>
+                        <property name="visible">True</property>
+                        <property name="pixel_size">16</property>
+                      </object>
+                      <packing>
+                        <property name="expand">False</property>
+                        <property name="fill">True</property>
+                        <property name="position">1</property>
+                      </packing>
+                    </child>
+                    <child>
                       <object class="GtkLabel" id="overflow_label">
                         <property name="visible">True</property>
                         <property name="can-focus">False</property>
                         <property name="ellipsize">end</property>
+                        <property name="hexpand">true</property>
                       </object>
+                      <packing>
+                        <property name="expand">True</property>
+                        <property name="fill">True</property>
+                        <property name="position">3</property>
+                      </packing>
                     </child>
                     <child>
                       <object class="GtkLabel" id="day_label">
                         <property name="visible">True</property>
-                        <property name="can-focus">False</property>
+                        <property name="can-focus">True</property>
                         <style>
                           <class name="day-label" />
                         </style>
                       </object>
                       <packing>
-                        <property name="pack-type">end</property>
-                      </packing>
-                    </child>
-                    <child>
-                      <object class="GtkImage" id="weather_icon">
-                        <property name="can-focus">False</property>
-                        <property name="stock">gtk-missing-image</property>
-                      </object>
-                      <packing>
-                        <property name="pack-type">end</property>
+                        <property name="expand">False</property>
+                        <property name="fill">True</property>
+                        <property name="position">4</property>
                       </packing>
                     </child>
                   </object>
diff --git a/src/gcal-window.c b/src/gcal-window.c
index d95b38e..29f9082 100644
--- a/src/gcal-window.c
+++ b/src/gcal-window.c
@@ -1772,13 +1772,14 @@ gcal_window_init (GcalWindow *self)
    * FIXME: this is a hack around the issue that happens when trying to bind
    * there properties using the GtkBuilder .ui file.
    */
-  g_object_bind_property (self, "weather-service", self->week_view, "weather-service", G_BINDING_DEFAULT);
   g_object_bind_property (self, "manager", self->edit_dialog, "manager", G_BINDING_DEFAULT);
   g_object_bind_property (self, "manager", self->source_dialog, "manager", G_BINDING_DEFAULT);
   g_object_bind_property (self, "manager", self->week_view, "manager", G_BINDING_DEFAULT);
   g_object_bind_property (self, "manager", self->month_view, "manager", G_BINDING_DEFAULT);
   g_object_bind_property (self, "manager", self->year_view, "manager", G_BINDING_DEFAULT);
   g_object_bind_property (self, "manager", self->quick_add_popover, "manager", G_BINDING_DEFAULT);
+  g_object_bind_property (self, "weather-service", self->week_view, "weather-service", G_BINDING_DEFAULT);
+  g_object_bind_property (self, "weather-service", self->month_view, "weather-service", G_BINDING_DEFAULT);
 
   /* setup accels */
   app = g_application_get_default ();
diff --git a/src/views/gcal-month-cell.c b/src/views/gcal-month-cell.c
index 623fd3a..68b8355 100644
--- a/src/views/gcal-month-cell.c
+++ b/src/views/gcal-month-cell.c
@@ -31,7 +31,8 @@ struct _GcalMonthCell
   GDateTime          *date;
   guint               n_overflow;
 
-  GtkLabel           *day_label;
+  GtkLabel           *day_label; /* unowned */
+  GtkImage           *weather_icon;
   GtkWidget          *overflow_button;
   GtkWidget          *overflow_label;
   GtkWidget          *overlay;
@@ -422,6 +423,7 @@ gcal_month_cell_class_init (GcalMonthCellClass *klass)
   gtk_widget_class_set_template_from_resource (widget_class, "/org/gnome/calendar/month-cell.ui");
 
   gtk_widget_class_bind_template_child (widget_class, GcalMonthCell, day_label);
+  gtk_widget_class_bind_template_child (widget_class, GcalMonthCell, weather_icon);
   gtk_widget_class_bind_template_child (widget_class, GcalMonthCell, overflow_button);
   gtk_widget_class_bind_template_child (widget_class, GcalMonthCell, overflow_label);
   gtk_widget_class_bind_template_child (widget_class, GcalMonthCell, overlay);
@@ -483,6 +485,38 @@ gcal_month_cell_set_date (GcalMonthCell *self,
   update_style_flags (self);
 }
 
+/**
+ * gcal_month_cell_set_weather:
+ * @self: The #GcalMonthCell instance.
+ * @info: (nullable): The weather information to display.
+ *
+ * Sets the weather information to display for this day.
+ *
+ * Note that this function does not check dates nor
+ * manages weather information changes on its own.
+ */
+void
+gcal_month_cell_set_weather (GcalMonthCell   *self,
+                             GcalWeatherInfo *info)
+{
+  g_return_if_fail (GCAL_IS_MONTH_CELL (self));
+  g_return_if_fail (info == NULL || GCAL_IS_WEATHER_INFO (info));
+
+  if (info == NULL)
+    {
+      gtk_image_clear (self->weather_icon);
+    }
+  else
+    {
+      const gchar* icon_name; /* unowned */
+
+      icon_name = gcal_weather_info_get_icon_name (info);
+      gtk_image_set_from_icon_name (self->weather_icon, icon_name, GTK_ICON_SIZE_SMALL_TOOLBAR);
+    }
+
+  gtk_widget_show (GTK_WIDGET (self->weather_icon));
+}
+
 gboolean
 gcal_month_cell_get_different_month (GcalMonthCell *self)
 {
diff --git a/src/views/gcal-month-cell.h b/src/views/gcal-month-cell.h
index ccea347..e95c209 100644
--- a/src/views/gcal-month-cell.h
+++ b/src/views/gcal-month-cell.h
@@ -20,6 +20,7 @@
 #define GCAL_MONTH_CELL_H
 
 #include "gcal-manager.h"
+#include "gcal-weather-info.h"
 
 #include <gtk/gtk.h>
 
@@ -36,6 +37,9 @@ GDateTime*           gcal_month_cell_get_date                    (GcalMonthCell
 void                 gcal_month_cell_set_date                    (GcalMonthCell      *self,
                                                                   GDateTime          *date);
 
+void                 gcal_month_cell_set_weather                 (GcalMonthCell      *self,
+                                                                  GcalWeatherInfo    *info);
+
 gboolean             gcal_month_cell_get_different_month         (GcalMonthCell      *self);
 
 void                 gcal_month_cell_set_different_month         (GcalMonthCell      *self,
diff --git a/src/views/gcal-month-view.c b/src/views/gcal-month-view.c
index a148515..bf2fe5d 100644
--- a/src/views/gcal-month-view.c
+++ b/src/views/gcal-month-view.c
@@ -63,7 +63,7 @@ struct _GcalMonthView
 
   /* Grid widgets */
   GtkWidget          *grid;
-  GtkWidget          *month_cell[6][7];
+  GtkWidget          *month_cell[6][7]; /* unowned */
 
   /*
    * Hash to keep children widgets (all of them, parent widgets and its parts if there's any),
@@ -133,6 +133,7 @@ struct _GcalMonthView
   /* property */
   icaltimetype       *date;
   GcalManager        *manager;
+  GcalWeatherService *weather_service; /* owned, nullable */
 };
 
 #define MIRROR(val,start,end) (start + (val / end) * end + (end - val % end))
@@ -143,6 +144,9 @@ static void          gtk_buildable_interface_init                (GtkBuildableIf
 
 static void          e_data_model_subscriber_interface_init      (ECalDataModelSubscriberInterface *iface);
 
+static void          update_weather                              (GcalMonthView      *self,
+                                                                  gboolean            clear_old);
+
 G_DEFINE_TYPE_WITH_CODE (GcalMonthView, gcal_month_view, GTK_TYPE_CONTAINER,
                          G_IMPLEMENT_INTERFACE (GCAL_TYPE_VIEW, gcal_view_interface_init)
                          G_IMPLEMENT_INTERFACE (E_TYPE_CAL_DATA_MODEL_SUBSCRIBER,
@@ -155,6 +159,7 @@ enum
   PROP_0,
   PROP_DATE,
   PROP_MANAGER,
+  PROP_WEATHER_SERVICE,
   N_PROPS
 };
 
@@ -164,12 +169,22 @@ enum
   NUM_SIGNALS
 };
 
+static gpointer month_view_parent_class = NULL;
 static guint signals[NUM_SIGNALS] = { 0, };
 
 
 /*
  * Auxiliary functions
  */
+static void
+weather_changed (GcalWeatherService *weather_service,
+                 GcalMonthView      *self)
+{
+  g_return_if_fail (GCAL_IS_WEATHER_SERVICE (weather_service));
+  g_return_if_fail (GCAL_IS_MONTH_VIEW (self));
+
+  update_weather (self, TRUE);
+}
 
 static inline gint
 real_cell (gint     cell,
@@ -470,6 +485,76 @@ setup_month_grid (GcalMonthView *self,
     }
 }
 
+static void
+update_weather (GcalMonthView *self,
+                gboolean       clear_old)
+{
+  g_return_if_fail (GCAL_IS_MONTH_VIEW (self));
+
+  /* Drop old weather information */
+  if (clear_old)
+    {
+      guint row;
+      guint col;
+
+      for (row = 0; row < 6; row++)
+        {
+          for (col = 0; col < 7; col++)
+            {
+              GcalMonthCell *cell; /* unowned */
+
+              cell = GCAL_MONTH_CELL (self->month_cell[row][col]);
+              gcal_month_cell_set_weather (cell,  NULL);
+            }
+        }
+    }
+
+
+  /* Set new one */
+  if (self->weather_service != NULL)
+    {
+      GcalMonthCell *fstcell; /* unowned */
+      GSList *weather_infos;  /* unowned */
+      GSList *witer;          /* unowned */
+      GDateTime *firstdt;     /* unowned */
+      GDate first;
+
+      fstcell = GCAL_MONTH_CELL (self->month_cell[0][0]);
+      g_return_if_fail (fstcell != NULL);
+
+      firstdt = gcal_month_cell_get_date (fstcell);
+      g_date_set_dmy (&first,
+                      g_date_time_get_day_of_month (firstdt),
+                      g_date_time_get_month (firstdt),
+                      g_date_time_get_year (firstdt));
+
+      weather_infos = gcal_weather_service_get_weather_infos (self->weather_service);
+      for (witer = weather_infos; witer != NULL; witer = witer->next)
+        {
+          GcalWeatherInfo *info; /* unowned */
+          GDate weather_date;
+          gint day_difference;
+
+          info = GCAL_WEATHER_INFO (witer->data);
+          gcal_weather_info_get_date (info, &weather_date);
+          day_difference = g_date_days_between (&first, &weather_date);
+
+          if (day_difference >= 0 && day_difference < 6*7)
+            {
+              GcalMonthCell *wcell; /* unowned */
+              guint row;
+              guint column;
+
+              row = day_difference / 7;
+              column = day_difference % 7;
+              wcell = GCAL_MONTH_CELL (self->month_cell[row][column]);
+              gcal_month_cell_set_weather (wcell, info);
+            }
+        }
+    }
+
+}
+
 static gboolean
 update_month_cells (GcalMonthView *self)
 {
@@ -499,6 +584,7 @@ update_month_cells (GcalMonthView *self)
           /* Cell date */
           cell_date = g_date_time_add_days (dt, row * 7 + col - self->days_delay);
           gcal_month_cell_set_date (cell, cell_date);
+          gcal_month_cell_set_weather (cell, NULL);
 
           /* Different month */
           different_month = day < self->days_delay ||
@@ -544,6 +630,8 @@ update_month_cells (GcalMonthView *self)
         }
     }
 
+  update_weather (self, FALSE);
+
   self->update_grid_id = 0;
 
   return G_SOURCE_REMOVE;
@@ -1257,6 +1345,9 @@ gcal_month_view_set_property (GObject       *object,
       g_object_notify (object, "manager");
       break;
 
+    case PROP_WEATHER_SERVICE:
+        gcal_month_view_set_weather_service (self, g_value_get_object (value));
+        break;
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
       break;
@@ -1281,17 +1372,51 @@ gcal_month_view_get_property (GObject       *object,
       g_value_set_object (value, self->manager);
       break;
 
+    case PROP_WEATHER_SERVICE:
+      g_value_set_boxed (value, gcal_month_view_get_weather_service (self));
+      break;
+
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
       break;
     }
 }
 
+/* Called when self is destroyed.
+ *
+ * WARNING: This is a workaround. This is one of the views where
+ * reference counts are off. We overwrite destroy to avoid dangling
+ * pointers. This issue needs to be addressed and this function removed.
+ */
+static void
+gcal_month_view_destroyed (GtkWidget *widget)
+{
+  GcalMonthView *self = GCAL_MONTH_VIEW (widget);
+
+  if (self->weather_service != NULL)
+    {
+      g_signal_handlers_disconnect_by_func (self->weather_service,
+                                            (GCallback) weather_changed,
+                                            self);
+      g_clear_object (&self->weather_service);
+    }
+
+  GTK_WIDGET_CLASS (month_view_parent_class)->destroy ((GtkWidget*) G_TYPE_CHECK_INSTANCE_CAST (self, 
GTK_TYPE_GRID, GtkGrid));
+}
+
 static void
 gcal_month_view_finalize (GObject *object)
 {
   GcalMonthView *self = GCAL_MONTH_VIEW (object);
 
+  if (self->weather_service != NULL)
+    {
+      g_signal_handlers_disconnect_by_func (self->weather_service,
+                                            (GCallback) weather_changed,
+                                            self);
+      g_clear_object (&self->weather_service);
+    }
+
   g_clear_pointer (&self->date, g_free);
   g_clear_pointer (&self->children, g_hash_table_destroy);
   g_clear_pointer (&self->single_cell_children, g_hash_table_destroy);
@@ -1954,6 +2079,18 @@ gcal_month_view_class_init (GcalMonthViewClass *klass)
   g_object_class_override_property (object_class, PROP_DATE, "active-date");
   g_object_class_override_property (object_class, PROP_MANAGER, "manager");
 
+  /**
+   * GcalWeekView:weather-service:
+   *
+   * Sets the weather service to use.
+   */
+  g_object_class_install_property
+      (object_class,
+       PROP_WEATHER_SERVICE,
+       g_param_spec_object ("weather-service", "weather-service", "weather-service",
+                            GCAL_TYPE_WEATHER_SERVICE,
+                            G_PARAM_STATIC_STRINGS | G_PARAM_READWRITE));
+
   signals[EVENT_ACTIVATED] = g_signal_new ("event-activated",
                                            GCAL_TYPE_MONTH_VIEW,
                                            G_SIGNAL_RUN_LAST,
@@ -1981,6 +2118,10 @@ gcal_month_view_class_init (GcalMonthViewClass *klass)
   gtk_widget_class_bind_template_callback (widget_class, cancel_dnd_from_overflow_popover);
 
   gtk_widget_class_set_css_name (widget_class, "calendar-view");
+
+  /* Hack to deal with broken reference counts: */
+  month_view_parent_class = g_type_class_peek_parent (klass);
+  ((GtkWidgetClass *) klass)->destroy = (void (*) (GtkWidget *)) gcal_month_view_destroyed;
 }
 
 static void
@@ -1990,6 +2131,8 @@ gcal_month_view_init (GcalMonthView *self)
 
   gtk_widget_set_has_window (GTK_WIDGET (self), FALSE);
 
+  self->weather_service = NULL;
+
   self->children = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, (GDestroyNotify) g_list_free);
   self->single_cell_children = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, (GDestroyNotify) 
g_list_free);
   self->overflow_cells = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, (GDestroyNotify) 
g_list_free);
@@ -2058,3 +2201,51 @@ gcal_month_view_set_use_24h_format (GcalMonthView *self,
 {
   self->use_24h_format = use_24h;
 }
+
+/**
+ * gcal_month_view_set_weather_service:
+ * @self: The #GcalWeatherView instance.
+ * @service: (nullable): The weather service to query.
+ *
+ * Sets the service to query for weather reports.
+ */
+void
+gcal_month_view_set_weather_service (GcalMonthView      *self,
+                                     GcalWeatherService *service)
+{
+  g_return_if_fail (GCAL_IS_MONTH_VIEW (self));
+  g_return_if_fail (service == NULL || GCAL_IS_WEATHER_SERVICE (service));
+
+  if (self->weather_service != service)
+    {
+      if (self->weather_service != NULL)
+        g_signal_handlers_disconnect_by_func (self->weather_service,
+                                              (GCallback) weather_changed,
+                                              self);
+
+      g_set_object (&self->weather_service, service);
+
+      if (self->weather_service != NULL)
+        g_signal_connect (self->weather_service,
+                          "weather-changed",
+                          (GCallback) weather_changed,
+                          self);
+
+      update_weather (self, TRUE);
+      g_object_notify (G_OBJECT (self), "weather-service");
+    }
+}
+
+/**
+ * gcal_month_view_get_weather_service:
+ * @self: The #GcalWeatherView instance.
+ *
+ * Returns: (transfer none): The internal weather service object.
+ */
+GcalWeatherService*
+gcal_month_view_get_weather_service (GcalMonthView *self)
+{
+  g_return_val_if_fail (GCAL_IS_MONTH_VIEW (self), NULL);
+
+  return self->weather_service;
+}
diff --git a/src/views/gcal-month-view.h b/src/views/gcal-month-view.h
index 43e9905..1670aa7 100644
--- a/src/views/gcal-month-view.h
+++ b/src/views/gcal-month-view.h
@@ -21,6 +21,7 @@
 #define __GCAL_MONTH_VIEW_H__
 
 #include "gcal-manager.h"
+#include "gcal-weather-service.h"
 
 G_BEGIN_DECLS
 
@@ -34,6 +35,11 @@ void                 gcal_month_view_set_first_weekday           (GcalMonthView
 void                 gcal_month_view_set_use_24h_format          (GcalMonthView      *self,
                                                                   gboolean            use_24h);
 
+void                 gcal_month_view_set_weather_service         (GcalMonthView      *self,
+                                                                  GcalWeatherService *service);
+
+GcalWeatherService*  gcal_month_view_get_weather_service         (GcalMonthView      *self);
+
 G_END_DECLS
 
 #endif /* __GCAL_MONTH_VIEW_H__ */


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