[gnome-calendar/wip/flb/weather-forecast: 15/50] weather: Integrate weather into our main windows.
- From: Georges Basile Stavracas Neto <gbsneto src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnome-calendar/wip/flb/weather-forecast: 15/50] weather: Integrate weather into our main windows.
- Date: Tue, 31 Oct 2017 08:19:05 +0000 (UTC)
commit 09017ef94c81e65b0ba221151625be6c35a24273
Author: Florian Brosch <flo brosch gmail com>
Date: Thu Oct 12 23:51:57 2017 +0200
weather: Integrate weather into our main windows.
data/org.gnome.calendar.gschema.xml | 5 +
data/ui/menus.ui | 165 ++++++++++-
src/gcal-window.c | 532 ++++++++++++++++++++++++++++++++++-
src/views/gcal-week-view.c | 48 +++-
4 files changed, 725 insertions(+), 25 deletions(-)
---
diff --git a/data/org.gnome.calendar.gschema.xml b/data/org.gnome.calendar.gschema.xml
index e938690..62b8e9a 100644
--- a/data/org.gnome.calendar.gschema.xml
+++ b/data/org.gnome.calendar.gschema.xml
@@ -21,5 +21,10 @@
<summary>Type of the active view</summary>
<description>Type of the active window view, default value is: monthly view</description>
</key>
+ <key name="weather-settings" type="(bbsmv)">
+ <default>(true, true, '', nothing)</default>
+ <summary>Weather Service Configuration</summary>
+ <description>Whether weather reports are shown, automatic locations are used and a
location-name</description>
+ </key>
</schema>
</schemalist>
diff --git a/data/ui/menus.ui b/data/ui/menus.ui
index cea2f5d..d5ed908 100644
--- a/data/ui/menus.ui
+++ b/data/ui/menus.ui
@@ -30,19 +30,158 @@
</item>
</section>
</menu>
- <menu id="win-menu">
- <section>
- <item>
- <attribute name="label" translatable="yes">Add Eve_nt…</attribute>
- <attribute name="action">app.new</attribute>
- </item>
- <item>
- <attribute name="label" translatable="yes">_Synchronize</attribute>
- <attribute name="action">app.sync</attribute>
- <attribute name="accel">F5</attribute>
- </item>
- </section>
- </menu>
+ <object class="GtkPopoverMenu" id="win-menu">
+ <child>
+ <object class="GtkStack" id="win-menu-stack">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="vhomogeneous">False</property>
+ <child>
+ <!-- Initial user menu: -->
+ <object class="GtkBox">
+ <property name="margin">12</property>
+ <property name="visible">True</property>
+ <property name="orientation">vertical</property>
+ <child>
+ <object class="GtkModelButton">
+ <property name="text" translatable="yes">Add Eve_nt</property>
+ <property name="action-name">app.new</property>
+ <property name="visible">True</property>
+ </object>
+ </child>
+ <child>
+ <object class="GtkModelButton">
+ <property name="text" translatable="yes">_Synchronize</property>
+ <property name="action-name">app.sync</property>
+ <property name="visible">True</property>
+ </object>
+ </child>
+ <child>
+ <object class="GtkModelButton" id="win-menu-open-weather">
+ <property name="text" translatable="yes">_Weather</property>
+ <property name="menu-name" translatable="yes">win-menu-weather</property>
+ <property name="visible">True</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="name">win-menu-main</property>
+ </packing>
+ </child>
+ <child>
+ <!-- Weather Box: -> name this weather-settings -->
+ <object class="GtkBox">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="orientation">vertical</property>
+ <property name="margin">12</property>
+ <property name="spacing">5</property> <!-- TODO: check HIG for right value -->
+ <child>
+ <object class="GtkModelButton" id="win-menu-close-weather">
+ <property name="text" translatable="yes">_Weather</property>
+ <property name="menu-name" translatable="yes">win-menu-main</property>
+ <property name="inverted">True</property>
+ <property name="centered">True</property>
+ <property name="visible">True</property>
+ </object>
+ <packing>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkBox">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="spacing">5</property> <!-- TODO: check HIG for right value -->
+ <child>
+ <object class="GtkLabel">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="halign">start</property>
+ <property name="label" translatable="yes">Show Weather</property>
+ </object>
+ <packing>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkSwitch" id="show-weather-switch">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkBox">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="spacing">5</property> <!-- TODO: check HIG for right value -->
+ <child>
+ <object class="GtkLabel">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="halign">start</property>
+ <property name="label" translatable="yes">Automatic Location</property>
+ </object>
+ <packing>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkSwitch" id="auto-location-switch">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">2</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GWeatherLocationEntry" id="fixed-weather-location">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="primary_icon_name">edit-find-symbolic</property>
+ <property name="primary_icon_activatable">False</property>
+ <property name="primary_icon_sensitive">False</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">3</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="name">win-menu-weather</property>
+ </packing>
+ </child>
+ </object>
+ </child>
+ </object>
<menu id="add-source-menu">
<section>
<item>
diff --git a/src/gcal-window.c b/src/gcal-window.c
index 9202920..c4468c6 100644
--- a/src/gcal-window.c
+++ b/src/gcal-window.c
@@ -33,9 +33,10 @@
#include "gcal-week-view.h"
#include "gcal-window.h"
#include "gcal-year-view.h"
+#include "gcal-weather-service.h"
#include <glib/gi18n.h>
-
+#include <libgweather/gweather.h>
#include <libecal/libecal.h>
#include <libical/icaltime.h>
@@ -95,6 +96,21 @@ typedef struct
gchar *uuid;
} OpenEditDialogData;
+/* WeatherSigs:
+ * @instance: (transfer none) Instance this signal is connected to.
+ * @sig_id: Signal uid
+ *
+ * Describes a signal used in weather-menu that triggers
+ * weather service or weather menu changes.
+ *
+ * Used to block signals when loading settings.
+ */
+typedef struct
+{
+ GObject *obj; /* unowned */
+ gulong id;
+} WeatherSigs;
+
struct _GcalWindow
{
GtkApplicationWindow parent;
@@ -161,12 +177,18 @@ struct _GcalWindow
gint refresh_timeout_id;
gint open_edit_dialog_timeout_id;
+ /* weather management */
+ GcalWeatherService *weather_service; /* owned */
+ GtkSwitch *weather; /* unowned */
+ GtkSwitch *auto_location; /* unowned */
+ GWeatherLocationEntry *location_entry; /* unowned */
+ WeatherSigs weather_cb_ids[5];
+
/* temp to keep event_creation */
gboolean open_edit_dialog;
/* handler for the searh_view */
gint click_outside_handler_id;
-
};
enum
@@ -174,6 +196,7 @@ enum
PROP_0,
PROP_ACTIVE_VIEW,
PROP_MANAGER,
+ PROP_WEATHER_SERVICE,
PROP_ACTIVE_DATE,
PROP_NEW_EVENT_MODE
};
@@ -200,6 +223,49 @@ static void on_view_action_activated (GSimpleAction *a
GVariant *param,
gpointer user_data);
+static void on_menu_button_clicked (GtkMenuButton *menu,
+ GtkStack *stack);
+
+static void on_view_menu_open_sub (GtkModelButton *button,
+ GtkStack *stack);
+
+static void on_view_menu_open_parent (GtkModelButton *button,
+ GtkStack *stack);
+
+static void on_weather_location_searchbox_change (GWeatherLocationEntry *entry,
+ GcalWindow *self);
+
+static void on_show_weather_change (GtkSwitch *wswitch,
+ GParamSpec *pspec,
+ GcalWindow *self);
+
+static void on_auto_location_change (GtkSwitch *lswitch,
+ GParamSpec *pspec,
+ GcalWindow *self);
+
+static gboolean on_weather_location_searchbox_match_selected
+ (GtkEntryCompletion *sender,
+ GtkTreeModel *model,
+ GtkTreeIter *iter,
+ GcalWindow *self);
+
+static void set_model_button_animation (GtkBuilder *builder,
+ GtkStack *stack,
+ const char *id,
+ gboolean go_back);
+static void update_menu_weather_sensitivity (GcalWindow *self);
+
+
+static void close_menu (GcalWindow *self);
+
+static void safe_weather_settings (GcalWindow *self);
+
+static void load_weather_settings (GcalWindow *self);
+
+static void manage_weather_service (GcalWindow *self);
+
+static GWeatherLocation* get_checked_fixed_location (GcalWindow *self);
+
G_DEFINE_TYPE (GcalWindow, gcal_window, GTK_TYPE_APPLICATION_WINDOW)
static const GActionEntry actions[] = {
@@ -1305,9 +1371,11 @@ gcal_window_finalize (GObject *object)
g_clear_object (&window->views_switcher);
g_clear_pointer (&window->active_date, g_free);
-
G_OBJECT_CLASS (gcal_window_parent_class)->finalize (object);
+ gcal_weather_service_stop (window->weather_service);
+ g_clear_object (&window->weather_service);
+
GCAL_EXIT;
}
@@ -1370,6 +1438,19 @@ gcal_window_set_property (GObject *object,
}
return;
+ case PROP_WEATHER_SERVICE:
+ {
+ GcalWeatherService *service; /* unowned */
+
+ service = GCAL_WEATHER_SERVICE (g_value_get_object (value));
+ g_return_if_fail (service != NULL);
+
+ g_return_if_fail (self->weather_service == NULL);
+ self->weather_service = (GcalWeatherService*) g_object_ref (service);
+ g_object_notify (object, "weather-service");
+ return ;
+ }
+
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
}
@@ -1395,6 +1476,10 @@ gcal_window_get_property (GObject *object,
g_value_set_object (value, self->manager);
return;
+ case PROP_WEATHER_SERVICE:
+ g_value_set_object (value, self->weather_service);
+ return;
+
case PROP_ACTIVE_DATE:
g_value_set_boxed (value, self->active_date);
return;
@@ -1500,6 +1585,15 @@ gcal_window_class_init (GcalWindowClass *klass)
g_object_class_install_property (
object_class,
+ PROP_WEATHER_SERVICE,
+ g_param_spec_object ("weather-service",
+ "The weather service object",
+ "The weather service object",
+ GCAL_TYPE_WEATHER_SERVICE,
+ G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE));
+
+ g_object_class_install_property (
+ object_class,
PROP_ACTIVE_DATE,
g_param_spec_boxed ("active-date",
"Date",
@@ -1582,7 +1676,9 @@ gcal_window_init (GcalWindow *self)
{
GApplication *app;
GtkBuilder *builder;
- GMenuModel *winmenu;
+ GtkPopoverMenu *winmenu; /* unowned */
+ GtkStack *winmenustack; /* unowned */
+ GtkEntryCompletion *location_completion; /* unowned */
GSettings *helper_settings;
gchar *clock_format;
gboolean use_24h_format;
@@ -1611,9 +1707,32 @@ gcal_window_init (GcalWindow *self)
"/org/gnome/calendar/gtk/menus.ui",
NULL);
- winmenu = (GMenuModel *)gtk_builder_get_object (builder, "win-menu");
- gtk_menu_button_set_menu_model (GTK_MENU_BUTTON (self->menu_button),
- winmenu);
+ winmenu = (GtkPopoverMenu *)gtk_builder_get_object (builder, "win-menu");
+ gtk_menu_button_set_popover (GTK_MENU_BUTTON (self->menu_button),
+ GTK_WIDGET (winmenu));
+ /* Set-up menu animations: */
+ winmenustack = GTK_STACK (gtk_builder_get_object (builder, "win-menu-stack"));
+ g_signal_connect (GTK_BUTTON (self->menu_button), "clicked", (GCallback) on_menu_button_clicked,
winmenustack);
+ set_model_button_animation (builder, winmenustack, "win-menu-open-weather", TRUE);
+ set_model_button_animation (builder, winmenustack, "win-menu-close-weather", FALSE);
+
+ /* Weather menu: */
+ self->weather_service = NULL;
+ self->weather = GTK_SWITCH(gtk_builder_get_object (builder, "show-weather-switch"));
+ self->auto_location = GTK_SWITCH(gtk_builder_get_object (builder, "auto-location-switch"));
+ self->location_entry = GWEATHER_LOCATION_ENTRY (gtk_builder_get_object (builder,
"fixed-weather-location"));
+ location_completion = gtk_entry_get_completion (GTK_ENTRY (self->location_entry));
+ /* Store signals that need to be blocked when loading weather information */
+ self->weather_cb_ids[0].id = g_signal_connect (self->location_entry, "changed", (GCallback)
on_weather_location_searchbox_change, self);
+ self->weather_cb_ids[0].obj = G_OBJECT (self->location_entry);
+ self->weather_cb_ids[1].id = g_signal_connect (self->location_entry, "activate", (GCallback)
on_weather_location_searchbox_change, self);
+ self->weather_cb_ids[1].obj = G_OBJECT (self->location_entry);
+ self->weather_cb_ids[2].id = g_signal_connect (location_completion, "match-selected", (GCallback)
on_weather_location_searchbox_match_selected, self);
+ self->weather_cb_ids[2].obj = G_OBJECT (location_completion);
+ self->weather_cb_ids[3].id = g_signal_connect (self->weather, "notify::active", (GCallback)
on_show_weather_change, self);
+ self->weather_cb_ids[3].obj = G_OBJECT (self->weather);
+ self->weather_cb_ids[4].id = g_signal_connect (self->auto_location, "notify::active", (GCallback)
on_auto_location_change, self);
+ self->weather_cb_ids[4].obj = G_OBJECT (self->auto_location);
g_object_unref (builder);
@@ -1651,6 +1770,7 @@ 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);
@@ -1672,6 +1792,392 @@ gcal_window_init (GcalWindow *self)
gcal_window_add_accelerator (app, "win.change-view(3)", "<Ctrl>3");
}
+
+/* set_model_button_animation:
+ * @builder: Builder including menu buttons
+ * @id: name of the menu button to modify
+ * @go_back: Whether this button jumps back to a parent menu
+ *
+ * Used to set right stack animations for hand-written menus.
+ */
+static void
+set_model_button_animation (GtkBuilder *builder,
+ GtkStack *stack,
+ const char *button_id,
+ gboolean go_back)
+{
+ g_return_if_fail (GTK_IS_BUILDER (builder));
+ g_return_if_fail (GTK_IS_STACK (stack));
+ g_return_if_fail (button_id != NULL);
+
+ GtkMenuButton *mbutton; /* unowned */
+
+ mbutton = GTK_MENU_BUTTON (gtk_builder_get_object (builder, button_id));
+ g_return_if_fail (mbutton != NULL);
+
+ if (go_back)
+ g_signal_connect (mbutton, "clicked", (GCallback) on_view_menu_open_parent, stack);
+ else
+ g_signal_connect (mbutton, "clicked", (GCallback) on_view_menu_open_sub, stack);
+}
+
+/* on_menu_button_clicked:
+ * @menu: primary menu button
+ * @stack: main menu popover stack
+ *
+ * Resets menu stack state before opening menu-popovers.
+ */
+static void
+on_menu_button_clicked (GtkMenuButton *menu,
+ GtkStack *stack)
+{
+ g_return_if_fail (GTK_IS_MENU_BUTTON (menu));
+ g_return_if_fail (GTK_IS_STACK (stack));
+
+ gtk_stack_set_visible_child_name (stack, "win-menu-main");
+ gtk_stack_set_transition_type (stack, GTK_STACK_TRANSITION_TYPE_SLIDE_LEFT);
+}
+
+/* on_view_menu_open_sub:
+ * @button: clicked menu entry
+ * @stack: main menu popover stack
+ *
+ * Callback used to set right stack animations for sub-menus.
+ */
+static void
+on_view_menu_open_sub (GtkModelButton *button,
+ GtkStack *stack)
+{
+ g_return_if_fail (GTK_IS_MODEL_BUTTON (button));
+ g_return_if_fail (GTK_IS_STACK (stack));
+
+ gtk_stack_set_transition_type (stack, GTK_STACK_TRANSITION_TYPE_SLIDE_LEFT);
+}
+
+/* on_view_menu_open_sub:
+ * @button: clicked menu entry
+ * @stack: Main menu popover stack
+ *
+ * Callback used to select right stack animation when jumping back to a parent menu.
+ */
+static void
+on_view_menu_open_parent (GtkModelButton *button,
+ GtkStack *stack)
+{
+ g_return_if_fail (GTK_IS_MODEL_BUTTON (button));
+ g_return_if_fail (GTK_IS_STACK (stack));
+
+ gtk_stack_set_transition_type (stack, GTK_STACK_TRANSITION_TYPE_SLIDE_RIGHT);
+}
+
+/* on_show_weather_change:
+ * @lswitch: The "show-weather" switch owned by @self
+ * @pspec: spec of changed property.
+ * @self: The #GcalWindow
+ *
+ * Handles show-weather on/off switch changes.
+ */
+static void
+on_show_weather_change (GtkSwitch *wswitch,
+ GParamSpec *pspec,
+ GcalWindow *self)
+{
+ g_return_if_fail (GTK_IS_SWITCH (wswitch));
+ g_return_if_fail (pspec != NULL);
+ g_return_if_fail (GCAL_IS_WINDOW (self));
+
+ safe_weather_settings (self);
+
+ if (!gtk_switch_get_active (wswitch))
+ close_menu (self);
+
+ update_menu_weather_sensitivity (self);
+ manage_weather_service (self);
+}
+
+/* on_auto_location_change:
+ * @lswitch: The "auto-location" switch owned by @self
+ * @pspec: spec of changed property.
+ * @self: The #GcalWindow
+ *
+ * Handles auto-location on/off switch changes.
+ */
+static void
+on_auto_location_change (GtkSwitch *lswitch,
+ GParamSpec *pspec,
+ GcalWindow *self)
+{
+ g_return_if_fail (GTK_IS_SWITCH (lswitch));
+ g_return_if_fail (pspec != NULL);
+ g_return_if_fail (GCAL_IS_WINDOW (self));
+
+ safe_weather_settings (self);
+
+ if (gtk_switch_get_active (lswitch))
+ close_menu (self);
+
+ update_menu_weather_sensitivity (self);
+ manage_weather_service (self);
+}
+
+/* on_weather_location_searchbox_change:
+ * @entry: the #GweatherLocationEntry owned by @self
+ * @self: a #GcalWindow.
+ *
+ * Handles location search-box changes.
+ */
+static void
+on_weather_location_searchbox_change (GWeatherLocationEntry *entry,
+ GcalWindow *self)
+{
+ GWeatherLocation *location; /* owned */
+
+ g_return_if_fail (GWEATHER_IS_LOCATION_ENTRY (entry));
+ g_return_if_fail (GCAL_IS_WINDOW (self));
+
+ safe_weather_settings (self);
+
+ location = get_checked_fixed_location (self);
+ if (location != NULL)
+ {
+ close_menu (self);
+ manage_weather_service (self);
+ gweather_location_unref (location);
+ }
+}
+
+/* on_weather_location_searchbox_match_selected:
+ * @sender: the #GWeatherLocationEntry of @self.
+ * @model: underlining location model
+ * @iter: current position
+ * @self: a #GcalWindow as user data.
+ *
+ * Wrapper around on_weather_location_searchbox_change().
+ *
+ * Returns: %FALSE
+ */
+static gboolean
+on_weather_location_searchbox_match_selected (GtkEntryCompletion *sender,
+ GtkTreeModel *model,
+ GtkTreeIter *iter,
+ GcalWindow *self)
+{
+ g_return_val_if_fail (GTK_IS_ENTRY_COMPLETION (sender), FALSE);
+ g_return_val_if_fail (GTK_IS_TREE_MODEL (model), FALSE);
+ g_return_val_if_fail (iter != NULL, FALSE);
+ g_return_val_if_fail (GCAL_IS_WINDOW (self), FALSE);
+
+ GWeatherLocationEntry *entry; /* unowned */
+
+ entry = GWEATHER_LOCATION_ENTRY (gtk_entry_completion_get_entry (sender));
+
+ on_weather_location_searchbox_change (entry, self);
+ return FALSE;
+}
+
+/* update_menu_weather_sensitivity:
+ * @self: A #GcalWindow
+ *
+ * Greys-out weather settings based on active settings.
+ */
+static void
+update_menu_weather_sensitivity (GcalWindow *self)
+{
+ g_return_if_fail (GCAL_IS_WINDOW (self));
+
+ gboolean weather_enabled;
+ gboolean autoloc_enabled;
+
+ weather_enabled = gtk_switch_get_active (self->weather);
+ autoloc_enabled = gtk_switch_get_active (self->auto_location);
+
+ gtk_widget_set_sensitive (GTK_WIDGET (self->auto_location), weather_enabled);
+ gtk_widget_set_sensitive (GTK_WIDGET (self->location_entry), weather_enabled && !autoloc_enabled);
+}
+
+/* close_menu:
+ * @self: A #GcalWindow
+ *
+ * Closes the main menu ("burger") if open.
+ */
+static void
+close_menu (GcalWindow *self)
+{
+ g_return_if_fail (GCAL_IS_WINDOW (self));
+
+ gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (self->menu_button), FALSE);
+}
+
+/* safe_weather_settings.
+ * @self: A #GcalWindow
+ *
+ * Stores current weather settings. This
+ * includes invalid states.
+ */
+static void
+safe_weather_settings (GcalWindow *self)
+{
+ g_return_if_fail (GCAL_IS_WINDOW (self));
+
+ GSettings *settings; /* unowned */
+ GVariant *value = NULL; /* floating */
+ GVariant *vlocation = NULL; /* floating */
+ GWeatherLocation *location; /* owned */
+ gboolean res;
+
+ location = gweather_location_entry_get_location (self->location_entry);
+ if (location != NULL)
+ {
+ vlocation = gweather_location_serialize (location);
+ gweather_location_unref (location);
+ location = NULL;
+ }
+
+ settings = gcal_manager_get_settings (self->manager);
+ value = g_variant_new ("(bbsmv)",
+ gtk_switch_get_active (self->weather),
+ gtk_switch_get_active (self->auto_location),
+ gtk_entry_get_text (GTK_ENTRY (self->location_entry)),
+ vlocation);
+
+ res = g_settings_set_value (settings, "weather-settings", value);
+
+ if (!res)
+ g_warning ("Could not persist weather settings");
+}
+
+/* load_weather_settings:
+ * @self: A #GcalWindow.
+ *
+ * Loads registered user settings.
+ *
+ * Does not start weather-services on its own.
+ */
+static void
+load_weather_settings (GcalWindow *self)
+{
+ g_return_if_fail (GCAL_IS_WINDOW (self));
+
+ GSettings *settings; /* unowned */
+ g_autoptr (GVariant) value = NULL;
+ gboolean show_weather;
+ gboolean auto_location;
+ g_autoptr (GVariant) location = NULL;
+ g_autofree gchar *location_name = NULL;
+
+ settings = gcal_manager_get_settings (self->manager);
+ value = g_settings_get_value (settings, "weather-settings");
+
+ g_variant_get (value,
+ "(bbsmv)",
+ &show_weather,
+ &auto_location,
+ &location_name,
+ &location);
+
+
+ for (int i = 0; i < G_N_ELEMENTS (self->weather_cb_ids); i++)
+ {
+ g_assert (self->weather_cb_ids[i].obj != NULL);
+ g_assert (self->weather_cb_ids[i].id > 0);
+
+ g_signal_handler_block (self->weather_cb_ids[i].obj, self->weather_cb_ids[i].id);
+ }
+
+ gtk_switch_set_active (self->weather, show_weather);
+ gtk_switch_set_active (self->auto_location, auto_location);
+ if (location == NULL)
+ {
+ gtk_entry_set_text (GTK_ENTRY (self->location_entry), location_name);
+ }
+ else
+ {
+ GWeatherLocation *world; /* unowned */
+ GWeatherLocation *loc; /* owned */
+
+ world = gweather_location_get_world ();
+ loc = gweather_location_deserialize (world, location);
+ gweather_location_entry_set_location (self->location_entry, loc);
+ gweather_location_unref (loc);
+ }
+
+ for (int i = 0; i < G_N_ELEMENTS (self->weather_cb_ids); i++)
+ g_signal_handler_unblock (self->weather_cb_ids[i].obj, self->weather_cb_ids[i].id);
+}
+
+/* manage_weather_service:
+ * @self: A #GcalWindow
+ *
+ * Starts or stops weather service based on current
+ * settings.
+ */
+static void
+manage_weather_service (GcalWindow *self)
+{
+ g_return_if_fail (GCAL_IS_WINDOW (self));
+
+ gboolean show_weather;
+ gboolean auto_location;
+ GWeatherLocation* location; /* owned */
+
+ gcal_weather_service_stop (self->weather_service);
+
+ show_weather = gtk_switch_get_active (self->weather);
+ if (!show_weather)
+ return;
+
+ auto_location = gtk_switch_get_active (self->auto_location);
+ if (auto_location)
+ {
+ gcal_weather_service_run (self->weather_service, NULL);
+ return;
+ }
+
+ location = get_checked_fixed_location (self);
+ if (location == NULL)
+ {
+ /* TODO: this one should get reported to users */
+ g_warning ("Unknown location '%s' selected",
+ gtk_entry_get_text (GTK_ENTRY (self->location_entry)));
+ }
+ else
+ {
+ gcal_weather_service_run (self->weather_service, location);
+ gweather_location_unref (location);
+ }
+}
+
+/* get_checked_fixed_location:
+ * @self: A #GcalWindow
+ *
+ * Returns user defined location or %NULL
+ * for invalid entries.
+ *
+ * Returns: (transfer full) (nullable): A #GweatherLocation.
+ */
+static GWeatherLocation*
+get_checked_fixed_location (GcalWindow *self)
+{
+ g_return_val_if_fail (GCAL_IS_WINDOW (self), NULL);
+
+ GWeatherLocation *location; /* owned */
+
+ location = gweather_location_entry_get_location (self->location_entry);
+
+ // NOTE: This check feels shabby. However,
+ // I couldn't find a better one without iterating
+ // the model. has-custom-text does not work properly.
+ // Lets go with it for now.
+ if (location != NULL && gweather_location_get_name (location) != NULL)
+ return location;
+
+ if (location != NULL)
+ gweather_location_unref (location);
+
+ return NULL;
+}
+
+
/* Public API */
/**
* gcal_window_new_with_date:
@@ -1686,12 +2192,15 @@ GtkWidget*
gcal_window_new_with_date (GcalApplication *app,
icaltimetype *date)
{
- GcalManager *manager;
- GcalWindow *win;
+ GcalWeatherService *weather_service; /* unowned */
+ GcalManager *manager; /* unowned */
+ GcalWindow *win; /* owned */
+ weather_service = gcal_application_get_weather_service (GCAL_APPLICATION (app));
manager = gcal_application_get_manager (GCAL_APPLICATION (app));
win = g_object_new (GCAL_TYPE_WINDOW,
"application", GTK_APPLICATION (app),
+ "weather-service", weather_service,
"manager", manager,
"active-date", date,
NULL);
@@ -1699,6 +2208,11 @@ gcal_window_new_with_date (GcalApplication *app,
/* loading size */
load_geometry (win);
+ /* Recover weather settings */
+ load_weather_settings (win);
+ update_menu_weather_sensitivity (win);
+ manage_weather_service (win);
+
return GTK_WIDGET (win);
}
diff --git a/src/views/gcal-week-view.c b/src/views/gcal-week-view.c
index 0d2fc51..5e65d47 100644
--- a/src/views/gcal-week-view.c
+++ b/src/views/gcal-week-view.c
@@ -27,6 +27,7 @@
#include "gcal-week-header.h"
#include "gcal-week-grid.h"
#include "gcal-week-view.h"
+#include "gcal-weather-service.h"
#include <glib/gi18n.h>
@@ -61,8 +62,9 @@ struct _GcalWeekView
gboolean use_24h_format;
/* property */
- icaltimetype *date;
- GcalManager *manager; /* owned */
+ icaltimetype *date;
+ GcalManager *manager; /* owned */
+ GcalWeatherService *weather_service; /* owned */
guint scroll_grid_timeout_id;
@@ -86,6 +88,7 @@ enum
PROP_0,
PROP_DATE,
PROP_MANAGER,
+ PROP_WEATHER_SERVICE,
NUM_PROPS
};
@@ -522,6 +525,9 @@ gcal_week_view_finalize (GObject *object)
g_clear_object (&self->manager);
+ if (self->weather_service != NULL)
+ g_clear_object (&self->weather_service);
+
/* Chain up to parent's finalize() method. */
G_OBJECT_CLASS (gcal_week_view_parent_class)->finalize (object);
}
@@ -545,10 +551,28 @@ gcal_week_view_set_property (GObject *object,
gcal_week_grid_set_manager (GCAL_WEEK_GRID (self->week_grid), self->manager);
gcal_week_header_set_manager (GCAL_WEEK_HEADER (self->header), self->manager);
-
g_object_notify (object, "manager");
break;
+ case PROP_WEATHER_SERVICE:
+ {
+ GcalWeatherService* weather_service; /* unowned */
+ weather_service = g_value_get_object (value);
+
+ g_return_if_fail (weather_service == NULL || GCAL_IS_WEATHER_SERVICE (weather_service));
+
+ if (self->weather_service != weather_service)
+ {
+ g_set_object (&self->weather_service, weather_service);
+
+ gcal_week_header_set_weather_service (GCAL_WEEK_HEADER (self->header),
+ self->weather_service);
+
+ g_object_notify (object, "weather-service");
+ }
+ break;
+ }
+
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
break;
@@ -576,6 +600,10 @@ gcal_week_view_get_property (GObject *object,
g_value_set_object (value, self->manager);
break;
+ case PROP_WEATHER_SERVICE:
+ g_value_set_object (value, self->weather_service);
+ break;
+
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
break;
@@ -598,6 +626,18 @@ gcal_week_view_class_init (GcalWeekViewClass *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_WEEK_VIEW,
G_SIGNAL_RUN_FIRST,
@@ -625,6 +665,8 @@ gcal_week_view_init (GcalWeekView *self)
gtk_widget_init_template (GTK_WIDGET (self));
update_hours_sidebar_size (self);
+
+ self->weather_service = NULL;
}
/* Public API */
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]