[gnome-calendar/wip/flb/weather-forecast: 44/50] month-view: Show weather reports.
- From: Georges Basile Stavracas Neto <gbsneto src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnome-calendar/wip/flb/weather-forecast: 44/50] month-view: Show weather reports.
- Date: Tue, 31 Oct 2017 08:21:31 +0000 (UTC)
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]