From fa008d79eb89528277e0c370746f38eca609502c Mon Sep 17 00:00:00 2001 From: Matthew Barnes Date: Tue, 23 Nov 2010 17:39:27 -0500 Subject: [PATCH] Add an ESource extension for the weather backend. --- calendar/backends/weather/Makefile.am | 2 + .../weather/e-cal-backend-weather-factory.c | 2 + calendar/backends/weather/e-cal-backend-weather.c | 109 ++++----- calendar/backends/weather/e-source-weather.c | 252 +++++++++++++++++++++ calendar/backends/weather/e-source-weather.h | 83 +++++++ calendar/backends/weather/e-weather-source-ccf.c | 23 +- calendar/backends/weather/e-weather-source-ccf.h | 2 +- calendar/backends/weather/e-weather-source.c | 6 +- calendar/backends/weather/e-weather-source.h | 2 +- 9 files changed, 413 insertions(+), 68 deletions(-) create mode 100644 calendar/backends/weather/e-source-weather.c create mode 100644 calendar/backends/weather/e-source-weather.h diff --git a/calendar/backends/weather/Makefile.am b/calendar/backends/weather/Makefile.am index 5b0afa4..8f74137 100644 --- a/calendar/backends/weather/Makefile.am +++ b/calendar/backends/weather/Makefile.am @@ -21,6 +21,8 @@ libecalbackendweather_la_SOURCES = \ e-cal-backend-weather-factory.c \ e-cal-backend-weather.c \ e-cal-backend-weather.h \ + e-source-weather.c \ + e-source-weather.h \ e-weather-source.c \ e-weather-source.h \ e-weather-source-ccf.c \ diff --git a/calendar/backends/weather/e-cal-backend-weather-factory.c b/calendar/backends/weather/e-cal-backend-weather-factory.c index f68113d..fd81ca9 100644 --- a/calendar/backends/weather/e-cal-backend-weather-factory.c +++ b/calendar/backends/weather/e-cal-backend-weather-factory.c @@ -22,6 +22,7 @@ #include #include "e-cal-backend-weather.h" +#include "e-source-weather.h" #define FACTORY_NAME "weather" @@ -61,6 +62,7 @@ e_cal_backend_weather_events_factory_init (ECalBackendFactory *factory) G_MODULE_EXPORT void e_module_load (GTypeModule *type_module) { + e_source_weather_type_register (type_module); e_cal_backend_weather_events_factory_register_type (type_module); } diff --git a/calendar/backends/weather/e-cal-backend-weather.c b/calendar/backends/weather/e-cal-backend-weather.c index bcd4329..aac8328 100644 --- a/calendar/backends/weather/e-cal-backend-weather.c +++ b/calendar/backends/weather/e-cal-backend-weather.c @@ -23,9 +23,11 @@ #include #include #include +#include #include #include #include "e-cal-backend-weather.h" +#include "e-source-weather.h" #include "e-weather-source.h" #define GWEATHER_I_KNOW_THIS_IS_UNSTABLE @@ -60,7 +62,6 @@ struct _ECalBackendWeatherPrivate { /* Reload */ guint reload_timeout_id; - guint source_changed_id; guint is_loading : 1; /* Flags */ @@ -92,21 +93,13 @@ reload_cb (ECalBackendWeather *cbw) } static void -source_changed (ESource *source, - ECalBackendWeather *cbw) -{ - /* FIXME - * We should force a reload of the data when this gets called. Unfortunately, - * this signal isn't getting through from evolution to the backend - */ -} - -static void maybe_start_reload_timeout (ECalBackendWeather *cbw) { ECalBackendWeatherPrivate *priv; ESource *source; - const gchar *refresh_str; + ESourceRefresh *extension; + const gchar *extension_name; + guint interval_in_minutes = 0; priv = cbw->priv; @@ -114,27 +107,25 @@ maybe_start_reload_timeout (ECalBackendWeather *cbw) return; source = e_backend_get_source (E_BACKEND (cbw)); - if (!source) { - g_warning ("Could not get source for ECalBackendWeather reload."); - return; - } - if (priv->source_changed_id == 0) - priv->source_changed_id = g_signal_connect (G_OBJECT (source), - "changed", - G_CALLBACK (source_changed), - cbw); - - refresh_str = e_source_get_property (source, "refresh"); + extension_name = E_SOURCE_EXTENSION_REFRESH; + extension = e_source_get_extension (source, extension_name); /* By default, reload every 4 hours. At least for CCF, the forecasts * only come out twice a day, and chances are while the NWS and similar * organizations have some serious bandwidth, they would appreciate it * if we didn't hammer their servers. */ - priv->reload_timeout_id = g_timeout_add ( - (refresh_str ? atoi (refresh_str) : 240) * 60000, - (GSourceFunc) reload_cb, cbw); + if (e_source_refresh_get_enabled (extension)) { + interval_in_minutes = + e_source_refresh_get_interval_minutes (extension); + if (interval_in_minutes == 0) + interval_in_minutes = 240; + } + if (interval_in_minutes > 0) + priv->reload_timeout_id = g_timeout_add_seconds ( + interval_in_minutes * 60, + (GSourceFunc) reload_cb, cbw); } /* TODO Do not replicate this in every backend */ @@ -237,20 +228,29 @@ static gboolean begin_retrieval_cb (ECalBackendWeather *cbw) { ECalBackendWeatherPrivate *priv = cbw->priv; + ESource *e_source; GSource *source; + /* XXX Too much overloading of the word 'source' here! */ + if (!e_backend_get_online (E_BACKEND (cbw))) return TRUE; maybe_start_reload_timeout (cbw); + e_source = e_backend_get_source (E_BACKEND (cbw)); + if (priv->source == NULL) { - ESource *e_source; - const gchar *uri; + ESourceWeather *extension; + const gchar *extension_name; + gchar *location; + + extension_name = E_SOURCE_EXTENSION_WEATHER_BACKEND; + extension = e_source_get_extension (e_source, extension_name); - e_source = e_backend_get_source (E_BACKEND (cbw)); - uri = e_source_get_uri (e_source); - priv->source = e_weather_source_new (uri); + location = e_source_weather_dup_location (extension); + priv->source = e_weather_source_new (location); + g_free (location); } source = g_main_current_source (); @@ -319,11 +319,13 @@ create_weather (ECalBackendWeather *cbw, GSList *text_list = NULL; ECalComponentText *description; ESource *source; - gboolean metric; - const gchar *tmp; + const gchar *tmp; time_t update_time; icaltimezone *update_zone = NULL; + ESourceWeather *extension; + const gchar *extension_name; const WeatherLocation *location; + ESourceWeatherUnits units; g_return_val_if_fail (E_IS_CAL_BACKEND_WEATHER (cbw), NULL); @@ -333,21 +335,16 @@ create_weather (ECalBackendWeather *cbw, priv = cbw->priv; source = e_backend_get_source (E_BACKEND (cbw)); - tmp = e_source_get_property (source, "units"); - if (tmp == NULL) { - tmp = e_source_get_property (source, "temperature"); - if (tmp == NULL) - metric = FALSE; - else - metric = (strcmp (tmp, "fahrenheit") != 0); - } else { - metric = (strcmp (tmp, "metric") == 0); - } - if (metric) - weather_info_to_metric (report); - else + extension_name = E_SOURCE_EXTENSION_WEATHER_BACKEND; + extension = e_source_get_extension (source, extension_name); + units = e_source_weather_get_units (extension); + + /* Prefer metric if units is invalid. */ + if (units == E_SOURCE_WEATHER_UNITS_IMPERIAL) weather_info_to_imperial (report); + else + weather_info_to_metric (report); /* create the component and event object */ ical_comp = icalcomponent_new (ICAL_VEVENT_COMPONENT); @@ -496,21 +493,26 @@ e_cal_backend_weather_open (ECalBackendSync *backend, ECalBackendWeather *cbw; ECalBackendWeatherPrivate *priv; ESource *source; + ESourceWeather *extension; + const gchar *extension_name; const gchar *cache_dir; - const gchar *uri; + gchar *location; gboolean online; cbw = E_CAL_BACKEND_WEATHER (backend); priv = cbw->priv; source = e_backend_get_source (E_BACKEND (backend)); - uri = e_source_get_uri (source); - cache_dir = e_cal_backend_get_cache_dir (E_CAL_BACKEND (backend)); - if (priv->city) - g_free (priv->city); - priv->city = g_strdup (strrchr (uri, '/') + 1); + extension_name = E_SOURCE_EXTENSION_WEATHER_BACKEND; + extension = e_source_get_extension (source, extension_name); + + g_free (priv->city); + + location = e_source_weather_dup_location (extension); + priv->city = g_strdup (strrchr (location, '/') + 1); + g_free (location); e_cal_backend_notify_readonly (E_CAL_BACKEND (backend), TRUE); @@ -903,4 +905,7 @@ e_cal_backend_weather_class_init (ECalBackendWeatherClass *class) backend_class->start_view = e_cal_backend_weather_start_view; backend_class->internal_get_timezone = e_cal_backend_weather_internal_get_timezone; + + /* Register our ESource extension. */ + E_TYPE_SOURCE_WEATHER; } diff --git a/calendar/backends/weather/e-source-weather.c b/calendar/backends/weather/e-source-weather.c new file mode 100644 index 0000000..0f7e581 --- /dev/null +++ b/calendar/backends/weather/e-source-weather.c @@ -0,0 +1,252 @@ +/* + * e-source-weather.c + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) version 3. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with the program; if not, see + * + */ + +#include "e-source-weather.h" + +#include + +#define E_SOURCE_WEATHER_GET_PRIVATE(obj) \ + (G_TYPE_INSTANCE_GET_PRIVATE \ + ((obj), E_TYPE_SOURCE_WEATHER, ESourceWeatherPrivate)) + +struct _ESourceWeatherPrivate { + GMutex *property_lock; + ESourceWeatherUnits units; + gchar *location; +}; + +enum { + PROP_0, + PROP_LOCATION, + PROP_UNITS +}; + +static GType e_source_weather_units_type = G_TYPE_INVALID; + +G_DEFINE_DYNAMIC_TYPE ( + ESourceWeather, + e_source_weather, + E_TYPE_SOURCE_EXTENSION) + +static void +source_weather_set_property (GObject *object, + guint property_id, + const GValue *value, + GParamSpec *pspec) +{ + switch (property_id) { + case PROP_LOCATION: + e_source_weather_set_location ( + E_SOURCE_WEATHER (object), + g_value_get_string (value)); + return; + + case PROP_UNITS: + e_source_weather_set_units ( + E_SOURCE_WEATHER (object), + g_value_get_enum (value)); + return; + } + + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); +} + +static void +source_weather_get_property (GObject *object, + guint property_id, + GValue *value, + GParamSpec *pspec) +{ + switch (property_id) { + case PROP_LOCATION: + g_value_take_string ( + value, + e_source_weather_dup_location ( + E_SOURCE_WEATHER (object))); + return; + + case PROP_UNITS: + g_value_set_enum ( + value, + e_source_weather_get_units ( + E_SOURCE_WEATHER (object))); + return; + } + + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); +} + +static void +source_weather_finalize (GObject *object) +{ + ESourceWeatherPrivate *priv; + + priv = E_SOURCE_WEATHER_GET_PRIVATE (object); + + g_mutex_free (priv->property_lock); + + g_free (priv->location); + + /* Chain up to parent's finalize() method. */ + G_OBJECT_CLASS (e_source_weather_parent_class)->finalize (object); +} + +static void +e_source_weather_class_init (ESourceWeatherClass *class) +{ + GObjectClass *object_class; + ESourceExtensionClass *extension_class; + + g_type_class_add_private (class, sizeof (ESourceWeatherPrivate)); + + object_class = G_OBJECT_CLASS (class); + object_class->set_property = source_weather_set_property; + object_class->get_property = source_weather_get_property; + object_class->finalize = source_weather_finalize; + + extension_class = E_SOURCE_EXTENSION_CLASS (class); + extension_class->name = E_SOURCE_EXTENSION_WEATHER_BACKEND; + + g_object_class_install_property ( + object_class, + PROP_LOCATION, + g_param_spec_string ( + "location", + "Location", + "Weather location code", + NULL, + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT | + E_SOURCE_PARAM_SETTING)); + + g_object_class_install_property ( + object_class, + PROP_UNITS, + g_param_spec_enum ( + "units", + "Units", + "Metric or imperial units", + E_TYPE_SOURCE_WEATHER_UNITS, + E_SOURCE_WEATHER_UNITS_METRIC, + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT | + E_SOURCE_PARAM_SETTING)); +} + +static void +e_source_weather_class_finalize (ESourceWeatherClass *class) +{ +} + +static void +e_source_weather_init (ESourceWeather *extension) +{ + extension->priv = E_SOURCE_WEATHER_GET_PRIVATE (extension); + extension->priv->property_lock = g_mutex_new (); +} + +void +e_source_weather_type_register (GTypeModule *type_module) +{ + static const GEnumValue e_source_weather_units_values[] = { + { E_SOURCE_WEATHER_UNITS_METRIC, + "E_SOURCE_WEATHER_UNITS_METRIC", + "metric" }, + { E_SOURCE_WEATHER_UNITS_IMPERIAL, + "E_SOURCE_WEATHER_UNITS_IMPERIAL", + "imperial" }, + { 0, NULL, NULL } + }; + + e_source_weather_units_type = + g_type_module_register_enum ( + type_module, "ESourceWeatherUnits", + e_source_weather_units_values); + + /* XXX G_DEFINE_DYNAMIC_TYPE declares a static type registration + * function, so we have to wrap it with a public function in + * order to register types from a separate compilation unit. */ + e_source_weather_register_type (type_module); +} + +const gchar * +e_source_weather_get_location (ESourceWeather *extension) +{ + g_return_val_if_fail (E_IS_SOURCE_WEATHER (extension), NULL); + + return extension->priv->location; +} + +gchar * +e_source_weather_dup_location (ESourceWeather *extension) +{ + const gchar *protected; + gchar *duplicate; + + g_return_val_if_fail (E_IS_SOURCE_WEATHER (extension), NULL); + + g_mutex_lock (extension->priv->property_lock); + + protected = e_source_weather_get_location (extension); + duplicate = g_strdup (protected); + + g_mutex_unlock (extension->priv->property_lock); + + return duplicate; +} + +void +e_source_weather_set_location (ESourceWeather *extension, + const gchar *location) +{ + g_return_if_fail (E_IS_SOURCE_WEATHER (extension)); + + g_mutex_lock (extension->priv->property_lock); + + g_free (extension->priv->location); + extension->priv->location = e_util_strdup_strip (location); + + g_mutex_unlock (extension->priv->property_lock); + + g_object_notify (G_OBJECT (extension), "location"); +} + +ESourceWeatherUnits +e_source_weather_get_units (ESourceWeather *extension) +{ + g_return_val_if_fail (E_IS_SOURCE_WEATHER (extension), 0); + + return extension->priv->units; +} + +void +e_source_weather_set_units (ESourceWeather *extension, + ESourceWeatherUnits units) +{ + g_return_if_fail (E_IS_SOURCE_WEATHER (extension)); + + extension->priv->units = units; + + g_object_notify (G_OBJECT (extension), "units"); +} + +ESourceWeatherUnits +e_source_weather_units_get_type (void) +{ + return e_source_weather_units_type; +} diff --git a/calendar/backends/weather/e-source-weather.h b/calendar/backends/weather/e-source-weather.h new file mode 100644 index 0000000..85ad991 --- /dev/null +++ b/calendar/backends/weather/e-source-weather.h @@ -0,0 +1,83 @@ +/* + * e-source-weather.h + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) version 3. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with the program; if not, see + * + */ + +#ifndef E_SOURCE_WEATHER_H +#define E_SOURCE_WEATHER_H + +#include + +/* Standard GObject macros */ +#define E_TYPE_SOURCE_WEATHER \ + (e_source_weather_get_type ()) +#define E_SOURCE_WEATHER(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST \ + ((obj), E_TYPE_SOURCE_WEATHER, ESourceWeather)) +#define E_SOURCE_WEATHER_CLASS(cls) \ + (G_TYPE_CHECK_CLASS_CAST \ + ((cls), E_TYPE_SOURCE_WEATHER, ESourceWeatherClass)) +#define E_IS_SOURCE_WEATHER(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE \ + ((obj), E_TYPE_SOURCE_WEATHER)) +#define E_IS_SOURCE_WEATHER_CLASS(cls) \ + (G_TYPE_CHECK_CLASS_TYPE \ + ((cls), E_TYPE_SOURCE_WEATHER)) +#define E_SOURCE_WEATHER_GET_CLASS(obj) \ + (G_TYPE_INSTANCE_GET_CLASS \ + ((obj), E_TYPE_SOURCE_WEATHER, ESourceWeatherClass)) + +#define E_TYPE_SOURCE_WEATHER_UNITS \ + (e_source_weather_units_get_type ()) + +#define E_SOURCE_EXTENSION_WEATHER_BACKEND "Weather Backend" + +G_BEGIN_DECLS + +typedef struct _ESourceWeather ESourceWeather; +typedef struct _ESourceWeatherClass ESourceWeatherClass; +typedef struct _ESourceWeatherPrivate ESourceWeatherPrivate; + +struct _ESourceWeather { + ESourceExtension parent; + ESourceWeatherPrivate *priv; +}; + +struct _ESourceWeatherClass { + ESourceExtensionClass parent_class; +}; + +typedef enum { + E_SOURCE_WEATHER_UNITS_METRIC, + E_SOURCE_WEATHER_UNITS_IMPERIAL +} ESourceWeatherUnits; + +GType e_source_weather_get_type (void); +void e_source_weather_type_register (GTypeModule *type_module); +const gchar * e_source_weather_get_location (ESourceWeather *extension); +gchar * e_source_weather_dup_location (ESourceWeather *extension); +void e_source_weather_set_location (ESourceWeather *extension, + const gchar *location); +ESourceWeatherUnits + e_source_weather_get_units (ESourceWeather *extension); +void e_source_weather_set_units (ESourceWeather *extension, + ESourceWeatherUnits units); + +GType e_source_weather_units_get_type (void); + +G_END_DECLS + +#endif /* E_SOURCE_WEATHER_H */ diff --git a/calendar/backends/weather/e-weather-source-ccf.c b/calendar/backends/weather/e-weather-source-ccf.c index a5c23b5..18f6b5f 100644 --- a/calendar/backends/weather/e-weather-source-ccf.c +++ b/calendar/backends/weather/e-weather-source-ccf.c @@ -437,26 +437,27 @@ e_weather_source_ccf_init (EWeatherSourceCCF *source) } EWeatherSource * -e_weather_source_ccf_new (const gchar *uri) +e_weather_source_ccf_new (const gchar *location) { - /* Old URI is formatted as weather://ccf/AAA[/BBB] - AAA is the 3-letter station - * code for identifying the providing station (subdirectory within the crh data - * repository). BBB is an optional additional station ID for the station within - * the CCF file. If not present, BBB is assumed to be the same station as AAA. - * But the new URI is as weather://code/name, where code is 4-letter code. - * So if got the old URI, then migrate to the new one, if possible. + /* Old location is formatted as ccf/AAA[/BBB] - AAA is the 3-letter + * station code for identifying the providing station (subdirectory + * within the crh data repository). BBB is an optional additional + * station ID for the station within the CCF file. If not present, + * BBB is assumed to be the same station as AAA. But the new + * location is code/name, where code is 4-letter code. So if we + * got the old format, then migrate to the new one, if possible. */ WeatherLocation *wl; EWeatherSourceCCF *source; - if (uri == NULL) + if (location == NULL) return NULL; - if (strncmp (uri, "ccf/", 4) == 0) - wl = find_location (uri + 4, TRUE); + if (strncmp (location, "ccf/", 4) == 0) + wl = find_location (location + 4, TRUE); else - wl = find_location (uri, FALSE); + wl = find_location (location, FALSE); if (wl == NULL) return NULL; diff --git a/calendar/backends/weather/e-weather-source-ccf.h b/calendar/backends/weather/e-weather-source-ccf.h index 1832b72..e0ae161 100644 --- a/calendar/backends/weather/e-weather-source-ccf.h +++ b/calendar/backends/weather/e-weather-source-ccf.h @@ -69,7 +69,7 @@ struct _EWeatherSourceCCFClass { }; GType e_weather_source_ccf_get_type (void); -EWeatherSource *e_weather_source_ccf_new (const gchar *uri); +EWeatherSource *e_weather_source_ccf_new (const gchar *location); G_END_DECLS diff --git a/calendar/backends/weather/e-weather-source.c b/calendar/backends/weather/e-weather-source.c index 74ea669..3dd3431 100644 --- a/calendar/backends/weather/e-weather-source.c +++ b/calendar/backends/weather/e-weather-source.c @@ -53,9 +53,9 @@ e_weather_source_init (EWeatherSource *source) } EWeatherSource * -e_weather_source_new (const gchar *uri) +e_weather_source_new (const gchar *location) { - const gchar *base = uri + 10; /* skip weather:// */ + g_return_val_if_fail (location != NULL, NULL); - return e_weather_source_ccf_new (base); + return e_weather_source_ccf_new (location); } diff --git a/calendar/backends/weather/e-weather-source.h b/calendar/backends/weather/e-weather-source.h index e5e94cc..e36793e 100644 --- a/calendar/backends/weather/e-weather-source.h +++ b/calendar/backends/weather/e-weather-source.h @@ -100,7 +100,7 @@ struct _EWeatherSourceClass { }; GType e_weather_source_get_type (void); -EWeatherSource *e_weather_source_new (const gchar *uri); +EWeatherSource *e_weather_source_new (const gchar *location); void e_weather_source_parse (EWeatherSource *source, EWeatherSourceFinished done, gpointer data); -- 2.7.4