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



commit e9e403ce7ababa15839bdb9b28046f08c918bc55
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       |   7 +-
 src/gcal-window.c           |   3 +-
 src/views/gcal-month-cell.c |  35 ++++++++
 src/views/gcal-month-cell.h |   4 +
 src/views/gcal-month-view.c | 189 +++++++++++++++++++++++++++++++++++++++++++-
 src/views/gcal-month-view.h |   6 ++
 6 files changed, 240 insertions(+), 4 deletions(-)
---
diff --git a/data/ui/month-cell.ui b/data/ui/month-cell.ui
index 5af53880..3ad9f325 100644
--- a/data/ui/month-cell.ui
+++ b/data/ui/month-cell.ui
@@ -31,7 +31,11 @@
             <child>
               <object class="GtkImage" id="weather_icon">
                 <property name="can-focus">False</property>
-                <property name="stock">gtk-missing-image</property>
+                <property name="visible">True</property>
+                <property name="pixel_size">16</property>
+                <style>
+                  <class name="dim-label" />
+                </style>
               </object>
             </child>
           </object>
@@ -67,7 +71,6 @@
                         <property name="visible">True</property>
                         <property name="can-focus">False</property>
                         <property name="ellipsize">end</property>
-                        <property name="xalign">0.0</property>
                       </object>
                     </child>
                   </object>
diff --git a/src/gcal-window.c b/src/gcal-window.c
index cd13888c..7299af31 100644
--- a/src/gcal-window.c
+++ b/src/gcal-window.c
@@ -1670,13 +1670,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 d55216db..8e476152 100644
--- a/src/views/gcal-month-cell.c
+++ b/src/views/gcal-month-cell.c
@@ -33,6 +33,8 @@ struct _GcalMonthCell
 
   GtkLabel           *day_label;
   GtkWidget          *header_box;
+  GtkImage           *weather_icon;
+
   GtkWidget          *overflow_button;
   GtkWidget          *overflow_label;
   GtkWidget          *overlay;
@@ -427,6 +429,7 @@ gcal_month_cell_class_init (GcalMonthCellClass *klass)
   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);
+  gtk_widget_class_bind_template_child (widget_class, GcalMonthCell, weather_icon);
 
   gtk_widget_class_bind_template_callback (widget_class, enter_notify_event_cb);
   gtk_widget_class_bind_template_callback (widget_class, leave_notify_event_cb);
@@ -485,6 +488,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 bdf32fec..89849b38 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 31dac066..31ba06d5 100644
--- a/src/views/gcal-month-view.c
+++ b/src/views/gcal-month-view.c
@@ -70,7 +70,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),
@@ -132,6 +132,8 @@ struct _GcalMonthView
   icaltimetype       *date;
   GcalManager        *manager;
 
+  GcalWeatherService *weather_service;
+
   gboolean            pending_event_allocation;
 };
 
@@ -141,6 +143,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,
@@ -153,6 +158,7 @@ enum
   PROP_0,
   PROP_DATE,
   PROP_MANAGER,
+  PROP_WEATHER_SERVICE,
   N_PROPS
 };
 
@@ -162,6 +168,7 @@ enum
   NUM_SIGNALS
 };
 
+static gpointer month_view_parent_class = NULL;
 static guint signals[NUM_SIGNALS] = { 0, };
 
 
@@ -195,6 +202,13 @@ event_widget_visibility_changed_cb (GcalMonthView *self)
 }
 
 static void
+weather_changed_cb (GcalWeatherService *weather_service,
+                    GcalMonthView      *self)
+{
+  update_weather (self, TRUE);
+}
+
+static void
 setup_child_widget (GcalMonthView *self,
                     GtkWidget     *widget)
 {
@@ -896,6 +910,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;
+
+              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;
+      GDateTime *firstdt;
+      GSList *weather_infos;
+      GSList *witer;
+      GDate first;
+
+      fstcell = GCAL_MONTH_CELL (self->month_cell[0][0]);
+      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; witer = witer->next)
+        {
+          GcalWeatherInfo *info;
+          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;
+              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)
 {
@@ -928,6 +1012,7 @@ update_month_cells (GcalMonthView *self)
           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 ||
@@ -976,6 +1061,8 @@ update_month_cells (GcalMonthView *self)
         }
     }
 
+  update_weather (self, FALSE);
+
   self->update_grid_id = 0;
 
   return G_SOURCE_REMOVE;
@@ -1685,6 +1772,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;
@@ -1709,17 +1799,48 @@ 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)
+    {
+      g_signal_handlers_disconnect_by_func (self->weather_service, weather_changed_cb, 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)
+    {
+      g_signal_handlers_disconnect_by_func (self->weather_service, weather_changed_cb, 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);
@@ -2086,6 +2207,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,
@@ -2111,6 +2244,10 @@ gcal_month_view_class_init (GcalMonthViewClass *klass)
   gtk_widget_class_set_css_name (widget_class, "calendar-view");
 
   g_type_ensure (GCAL_TYPE_MONTH_POPOVER);
+
+  /* FIXME: 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
@@ -2120,6 +2257,7 @@ 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);
@@ -2189,3 +2327,52 @@ 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 || GCAL_IS_WEATHER_SERVICE (service));
+
+  if (self->weather_service == service)
+    return;
+
+  if (self->weather_service)
+    g_signal_handlers_disconnect_by_func (self->weather_service, weather_changed_cb, self);
+
+  g_set_object (&self->weather_service, service);
+
+  if (service)
+    {
+      g_signal_connect (service,
+                        "weather-changed",
+                        G_CALLBACK (weather_changed_cb),
+                        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 43e9905c..1670aa70 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]