From: Pierre-Luc Beaudoin Date: Fri, 6 Mar 2009 08:09:58 +0000 (+0200) Subject: Introduce ChamplainNetworkMapSource X-Git-Url: https://err.no/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=544e65b4231eb97a6a6375fdee09a1328e3fdbad;p=libchamplain Introduce ChamplainNetworkMapSource It will contain network specific settings too --- diff --git a/champlain/Makefile.am b/champlain/Makefile.am index 281aae0..8d2ca15 100644 --- a/champlain/Makefile.am +++ b/champlain/Makefile.am @@ -24,6 +24,7 @@ libchamplain_headers = \ champlain-enum-types.h \ champlain-tile.h \ champlain-map-source.h \ + champlain-network-map-source.h \ champlain-settings.h @@ -38,6 +39,7 @@ libchamplain_0_3_la_SOURCES = \ champlain-zoom-level.c \ champlain-tile.c \ champlain-map-source.c \ + champlain-network-map-source.c \ champlain-settings.c noinst_HEADERS = \ @@ -49,7 +51,8 @@ noinst_HEADERS = \ champlain-zoom-level.h \ champlain-tile.h \ champlain-enum-types.h \ - champlain-map-source.h + champlain-map-source.h \ + champlain-network-map-source.h libchamplain_include_HEADERS = \ champlain.h \ @@ -57,6 +60,7 @@ libchamplain_include_HEADERS = \ champlain-defines.h \ champlain-layer.h \ champlain-map-source.h \ + champlain-network-map-source.h \ champlain-tile.h \ champlain-zoom-level.h \ champlain-marker.h \ diff --git a/champlain/champlain-map-source.c b/champlain/champlain-map-source.c index 56bdbcb..77915e0 100644 --- a/champlain/champlain-map-source.c +++ b/champlain/champlain-map-source.c @@ -30,12 +30,8 @@ #include "champlain-settings.h" #include "champlain-zoom-level.h" -#include -#include -#include #include #include -#include #include #include @@ -55,7 +51,6 @@ enum PROP_MIN_ZOOM_LEVEL, PROP_TILE_SIZE, PROP_MAP_PROJECTION, - PROP_URI_FORMAT }; /* static guint champlain_map_source_signals[LAST_SIGNAL] = { 0, }; */ @@ -64,9 +59,6 @@ G_DEFINE_TYPE (ChamplainMapSource, champlain_map_source, G_TYPE_OBJECT); #define GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE((obj), CHAMPLAIN_TYPE_MAP_SOURCE, ChamplainMapSourcePrivate)) -#define CACHE_SUBDIR "champlain" -static SoupSession * soup_session; - struct _ChamplainMapSourcePrivate { gchar *name; @@ -76,7 +68,6 @@ struct _ChamplainMapSourcePrivate guint min_zoom_level; guint tile_size; ChamplainMapProjection map_projection; - gchar *uri_format; }; static void @@ -111,9 +102,6 @@ champlain_map_source_get_property (GObject *object, case PROP_MAP_PROJECTION: g_value_set_enum (value, priv->map_projection); break; - case PROP_URI_FORMAT: - g_value_set_string (value, priv->uri_format); - break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec); } @@ -131,7 +119,8 @@ champlain_map_source_set_property (GObject *object, switch(prop_id) { case PROP_NAME: - priv->name = g_value_dup_string (value); + champlain_map_source_set_name (map_source, + g_value_get_string (value)); break; case PROP_LICENSE: priv->license = g_value_dup_string (value); @@ -151,9 +140,6 @@ champlain_map_source_set_property (GObject *object, case PROP_MAP_PROJECTION: priv->map_projection = g_value_get_enum (value); break; - case PROP_URI_FORMAT: - priv->uri_format = g_value_dup_string (value); - break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec); } @@ -162,10 +148,12 @@ champlain_map_source_set_property (GObject *object, static void champlain_map_source_finalize (GObject *object) { - /* ChamplainMapSource *map_source = CHAMPLAIN_MAP_SOURCE (object); - * ChamplainMapSourcePrivate *priv = GET_PRIVATE (map_source); - */ + ChamplainMapSource *map_source = CHAMPLAIN_MAP_SOURCE (object); + ChamplainMapSourcePrivate *priv = GET_PRIVATE (map_source); + g_free (priv->name); + g_free (priv->license); + g_free (priv->license_uri); G_OBJECT_CLASS (champlain_map_source_parent_class)->finalize (object); } @@ -181,6 +169,8 @@ champlain_map_source_class_init (ChamplainMapSourceClass *klass) object_class->get_property = champlain_map_source_get_property; object_class->set_property = champlain_map_source_set_property; + klass->get_tile = champlain_map_source_get_tile; + /** * ChamplainMapSource:name: * @@ -285,21 +275,6 @@ champlain_map_source_class_init (ChamplainMapSourceClass *klass) CHAMPLAIN_MAP_PROJECTION_MERCATOR, (G_PARAM_READWRITE | G_PARAM_CONSTRUCT)); g_object_class_install_property (object_class, PROP_MAP_PROJECTION, pspec); - - /** - * ChamplainMapSource:uri-format - * - * The uri format for the map source - * - * Since: 0.4 - */ - pspec = g_param_spec_string ("uri-format", - "URI Format", - "The URI format", - "", - (G_PARAM_READWRITE | G_PARAM_CONSTRUCT)); - g_object_class_install_property (object_class, PROP_URI_FORMAT, pspec); - } static void @@ -329,112 +304,6 @@ champlain_map_source_get_tile_size (ChamplainMapSource *map_source) return priv->tile_size; } -ChamplainMapSource* -champlain_map_source_new_network (gchar *name, - gchar *license, - gchar *license_uri, - guint min_zoom, - guint max_zoom, - guint tile_size, - ChamplainMapProjection projection, - gchar *uri_format) -{ - - ChamplainMapSource * map_source; - map_source = g_object_new (CHAMPLAIN_TYPE_MAP_SOURCE, "name", name, - "license", license, "license-uri", license_uri, - "min-zoom-level", min_zoom, "max-zoom-level", max_zoom, - "tile-size", tile_size, "map-projection", projection, - "uri-format", uri_format, NULL); - return map_source; -} - -gchar * -champlain_map_source_get_tile_uri (ChamplainMapSource *map_source, - gint x, - gint y, - gint z) -{ - ChamplainMapSourcePrivate *priv = GET_PRIVATE (map_source); - - gchar **tokens; - gchar *token; - GString *ret; - gint i = 0; - - tokens = g_strsplit (priv->uri_format, "#", 20); - token = tokens[i]; - ret = g_string_sized_new (strlen (priv->uri_format)); - - while (token != NULL) - { - gint number = G_MAXINT; - gchar value[3]; - - if (strcmp (token, "X") == 0) - number = x; - if (strcmp (token, "Y") == 0) - number = y; - if (strcmp (token, "Z") == 0) - number = z; - - if (number != G_MAXINT) - { - g_sprintf (value, "%d", number); - g_string_append (ret, value); - } - else - g_string_append (ret, token); - - token = tokens[++i]; - } - token = ret->str; - g_string_free (ret, FALSE); - g_strfreev (tokens); - - return token; -} - -void -champlain_map_source_set_tile_uri (ChamplainMapSource *map_source, - const gchar *uri_format) -{ - ChamplainMapSourcePrivate *priv = GET_PRIVATE (map_source); - - priv->uri_format = g_strdup (uri_format); -} - -ChamplainMapSource * -champlain_map_source_new_osm_mapnik () -{ - champlain_map_source_new_network ("OpenStreetMap Mapnik", - "(CC) BY 2.0 OpenStreetMap contributors", - "http://creativecommons.org/licenses/by/2.0/", 0, 18, 256, - CHAMPLAIN_MAP_PROJECTION_MERCATOR, - "http://tile.openstreetmap.org/#Z#/#X#/#Y#.png"); -} - -ChamplainMapSource * -champlain_map_source_new_oam () -{ - champlain_map_source_new_network ("OpenArialMap", - "(CC) BY 3.0 OpenArialMap contributors", - "http://creativecommons.org/licenses/by/3.0/", 0, 17, 256, - CHAMPLAIN_MAP_PROJECTION_MERCATOR, - "http://tile.openaerialmap.org/tiles/1.0.0/openaerialmap-900913/#Z#/#X#/#Y#.jpg"); -} - -//FIXME: the API isn't enough flexible for mff's url! -ChamplainMapSource * -champlain_map_source_new_mff_relief () -{ - champlain_map_source_new_network ("MapsForFree Relief", - "Map data available under GNU Free Documentation license, Version 1.2 or later", - "http://www.gnu.org/copyleft/fdl.html", 0, 11, 256, - CHAMPLAIN_MAP_PROJECTION_MERCATOR, - "http://maps-for-free.com/layer/relief/z#Z#/row#Y#/#Z#_#X#-#Y#.jpg"); -} - guint champlain_map_source_get_x (ChamplainMapSource *map_source, gint zoom_level, @@ -475,200 +344,13 @@ champlain_map_source_get_column_count (ChamplainMapSource *map_source, return pow (2, zoom_level); } -static gchar * -get_filename (ChamplainMapSource *map_source, - ChamplainZoomLevel *level, - ChamplainTile *tile) -{ - ChamplainMapSourcePrivate *priv = GET_PRIVATE (map_source); - return g_strdup_printf ("%s" G_DIR_SEPARATOR_S "%s" G_DIR_SEPARATOR_S - "%s" G_DIR_SEPARATOR_S "%d" G_DIR_SEPARATOR_S - "%d" G_DIR_SEPARATOR_S "%d.png", g_get_user_cache_dir (), - CACHE_SUBDIR, priv->name, - champlain_zoom_level_get_zoom_level (level), - champlain_tile_get_x (tile), champlain_tile_get_y (tile), - NULL); -} - -typedef struct { - ChamplainView *view; - ChamplainZoomLevel *zoom_level; - ChamplainTile *tile; -} FileLoadedCallbackContext; - -static void -create_error_tile (ChamplainTile* tile) -{ - ClutterActor *actor; - actor = clutter_texture_new_from_file (DATADIR "/champlain/error.svg", NULL); - if (!actor) - return; - - champlain_tile_set_actor (tile, actor); - clutter_actor_show (actor); - - champlain_tile_set_state (tile, CHAMPLAIN_STATE_DONE); -} - -static void -file_loaded_cb (SoupSession *session, - SoupMessage *msg, - gpointer user_data) -{ - FileLoadedCallbackContext *ctx = (FileLoadedCallbackContext*) user_data; - GdkPixbufLoader* loader; - GError *error = NULL; - gchar* path, *filename; - - if (!SOUP_STATUS_IS_SUCCESSFUL (msg->status_code)) - { - g_warning ("Unable to download tile %d, %d: %s", - champlain_tile_get_x (ctx->tile), - champlain_tile_get_y (ctx->tile), - soup_status_get_phrase(msg->status_code)); - g_object_unref (ctx->tile); - create_error_tile (ctx->tile); - return; - } - - loader = gdk_pixbuf_loader_new(); - if (!gdk_pixbuf_loader_write (loader, - (const guchar *) msg->response_body->data, - msg->response_body->length, - &error)) - { - if (error) - { - g_warning ("Unable to load the pixbuf: %s", error->message); - g_error_free (error); - create_error_tile (ctx->tile); - goto finish; - } - - g_object_unref (loader); - } - - gdk_pixbuf_loader_close (loader, &error); - if (error) - { - g_warning ("Unable to close the pixbuf loader: %s", error->message); - g_error_free (error); - create_error_tile (ctx->tile); - goto finish; - } - - filename = champlain_tile_get_filename (ctx->tile); - path = g_path_get_dirname (filename); - - if (g_mkdir_with_parents (path, 0700) == -1) - { - if (errno != EEXIST) - { - g_warning ("Unable to create the image cache: %s", - g_strerror (errno)); - g_object_unref (loader); - } - } - - g_file_set_contents (filename, msg->response_body->data, - msg->response_body->length, NULL); - - /* If the tile has been marked to be deleted, don't go any further */ - /*if (tile->to_destroy) - { - g_object_unref (loader); - g_free (filename); - g_free (map_filename); - g_free (tile); - return; - } -*/ - GdkPixbuf* pixbuf = gdk_pixbuf_loader_get_pixbuf(loader); - ClutterActor *actor = clutter_texture_new(); - clutter_texture_set_from_rgb_data (CLUTTER_TEXTURE (actor), - gdk_pixbuf_get_pixels (pixbuf), - gdk_pixbuf_get_has_alpha (pixbuf), - gdk_pixbuf_get_width (pixbuf), - gdk_pixbuf_get_height (pixbuf), - gdk_pixbuf_get_rowstride (pixbuf), - 3, 0, NULL); - champlain_tile_set_actor (ctx->tile, actor); - DEBUG ("Tile loaded from network"); - -finish: - champlain_tile_set_state (ctx->tile, CHAMPLAIN_STATE_DONE); - - g_object_unref (loader); - g_free (path); - - champlain_view_tile_ready (ctx->view, ctx->zoom_level, ctx->tile, TRUE); - g_object_unref (ctx->tile); - g_object_unref (ctx->zoom_level); - g_free (ctx); -} - void champlain_map_source_get_tile (ChamplainMapSource *map_source, ChamplainView *view, ChamplainZoomLevel *zoom_level, ChamplainTile *tile) { - gchar* filename; - - ChamplainMapSourcePrivate *priv = GET_PRIVATE (map_source); - - /* Ref the tile as it may be freeing during the loading - * Unref when the loading is done. - */ - g_object_ref (tile); - g_object_ref (zoom_level); - - /* Try the cached version first */ - filename = get_filename (map_source, zoom_level, tile); - champlain_tile_set_filename (tile, filename); - champlain_tile_set_size (tile, champlain_map_source_get_tile_size (map_source)); - - if (g_file_test (filename, G_FILE_TEST_EXISTS)) - { - GError *error = NULL; - ClutterActor *actor; - - actor = clutter_texture_new_from_file (filename, &error); - champlain_tile_set_actor (tile, actor); - clutter_actor_show (actor); - - champlain_tile_set_state (tile, CHAMPLAIN_STATE_DONE); - DEBUG ("Tile loaded from cache"); - champlain_view_tile_ready (view, zoom_level, tile, FALSE); - g_object_unref (tile); - g_object_unref (zoom_level); - } - else if (champlain_settings_is_online ()) - { - SoupMessage *msg; - gchar *uri; - FileLoadedCallbackContext *ctx = g_new0 (FileLoadedCallbackContext, 1); - ctx->view = view; - ctx->zoom_level = zoom_level; - ctx->tile = tile; - - if (!soup_session) - soup_session = soup_session_async_new (); - - uri = champlain_map_source_get_tile_uri (map_source, - champlain_tile_get_x (tile), champlain_tile_get_y (tile), - champlain_zoom_level_get_zoom_level (zoom_level)); - champlain_tile_set_uri (tile, uri); - champlain_tile_set_state (tile, CHAMPLAIN_STATE_LOADING); - msg = soup_message_new (SOUP_METHOD_GET, uri); - - soup_session_queue_message (soup_session, msg, - file_loaded_cb, - ctx); - } - /* If a tile is neither in cache or can be fetched, do nothing, it'll show up - * as empty - */ + CHAMPLAIN_MAP_SOURCE_GET_CLASS (map_source)->get_tile (map_source, view, zoom_level, tile); } gdouble @@ -694,3 +376,19 @@ champlain_map_source_get_latitude (ChamplainMapSource *map_source, return 180.0 / M_PI * atan (0.5 * (exp (n) - exp (-n))); } +const gchar * +champlain_map_source_get_name (ChamplainMapSource *map_source) +{ + ChamplainMapSourcePrivate *priv = GET_PRIVATE (map_source); + return priv->name; +} + +void +champlain_map_source_set_name (ChamplainMapSource *map_source, + char *name) +{ + ChamplainMapSourcePrivate *priv = GET_PRIVATE (map_source); + + priv->name = g_strdup (name); +} + diff --git a/champlain/champlain-map-source.h b/champlain/champlain-map-source.h index cc0d240..e70e97b 100644 --- a/champlain/champlain-map-source.h +++ b/champlain/champlain-map-source.h @@ -45,13 +45,6 @@ typedef enum CHAMPLAIN_MAP_PROJECTION_MERCATOR } ChamplainMapProjection; -typedef enum -{ - CHAMPLAIN_MAP_SOURCE_PARAMETER_X, - CHAMPLAIN_MAP_SOURCE_PARAMETER_Y, - CHAMPLAIN_MAP_SOURCE_PARAMETER_Z, -} ChamplainMapSourceParameter; - struct _ChamplainMapSource { GObject parent; @@ -61,13 +54,16 @@ struct _ChamplainMapSource struct _ChamplainMapSourceClass { GObjectClass parent_class; + + void (*get_tile) (ChamplainMapSource *map_source, + ChamplainView *view, + ChamplainZoomLevel *zoom_level, + ChamplainTile *tile); }; GType champlain_map_source_get_type (void); -ChamplainMapSource* champlain_map_source_new_network (gchar *name, - gchar *license, gchar *license_uri, guint min_zoom, guint map_zoom, - guint tile_size, ChamplainMapProjection projection, gchar *uri_format); +const gchar * champlain_map_source_get_name (ChamplainMapSource *map_source); gint champlain_map_source_get_min_zoom_level (ChamplainMapSource *map_source); @@ -75,16 +71,6 @@ gint champlain_map_source_get_max_zoom_level (ChamplainMapSource *map_source); guint champlain_map_source_get_tile_size (ChamplainMapSource *map_source); -gchar * champlain_map_source_get_tile_uri (ChamplainMapSource *source, - gint x, gint y, gint z); - -void champlain_map_source_set_tile_uri (ChamplainMapSource *map_source, - const gchar *uri_format); - -ChamplainMapSource * champlain_map_source_new_osm_mapnik (); -ChamplainMapSource * champlain_map_source_new_oam (); -ChamplainMapSource * champlain_map_source_new_mff_relief (); - guint champlain_map_source_get_x (ChamplainMapSource *map_source, gint zoom_level, gdouble longitude); @@ -102,8 +88,8 @@ guint champlain_map_source_get_row_count (ChamplainMapSource *map_source, guint champlain_map_source_get_column_count (ChamplainMapSource *map_source, gint zoom_level); -/* + void champlain_map_source_get_tile (ChamplainMapSource *map_source, - ChamplainEngine *engine, ChamplainZoomLevel *level, ChamplainTile *tile); -*/ + ChamplainView *view, ChamplainZoomLevel *level, ChamplainTile *tile); + #endif diff --git a/champlain/champlain-network-map-source.c b/champlain/champlain-network-map-source.c new file mode 100644 index 0000000..6b4c7f4 --- /dev/null +++ b/champlain/champlain-network-map-source.c @@ -0,0 +1,455 @@ +/* + * Copyright (C) 2008 Pierre-Luc Beaudoin + * + * This library 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.1 of the License, or (at your option) any later version. + * + * This library 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 this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "config.h" + +#include "champlain-network-map-source.h" + +#define DEBUG_FLAG CHAMPLAIN_DEBUG_LOADING +#include "champlain-debug.h" + +#include "champlain.h" +#include "champlain-defines.h" +#include "champlain-enum-types.h" +#include "champlain-map-source.h" +#include "champlain-marshal.h" +#include "champlain-private.h" +#include "champlain-settings.h" +#include "champlain-zoom-level.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +enum +{ + /* normal signals */ + LAST_SIGNAL +}; + +enum +{ + PROP_0, + PROP_URI_FORMAT +}; + +/* static guint champlain_network_map_source_signals[LAST_SIGNAL] = { 0, }; */ + +G_DEFINE_TYPE (ChamplainNetworkMapSource, champlain_network_map_source, CHAMPLAIN_TYPE_MAP_SOURCE); + +#define GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE((obj), CHAMPLAIN_TYPE_NETWORK_MAP_SOURCE, ChamplainNetworkMapSourcePrivate)) + +#define CACHE_SUBDIR "champlain" +static SoupSession * soup_session; + +struct _ChamplainNetworkMapSourcePrivate +{ + gchar *uri_format; +}; + +static void +champlain_network_map_source_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + ChamplainNetworkMapSource *network_map_source = CHAMPLAIN_NETWORK_MAP_SOURCE(object); + ChamplainNetworkMapSourcePrivate *priv = GET_PRIVATE (network_map_source); + + switch(prop_id) + { + case PROP_URI_FORMAT: + g_value_set_string (value, priv->uri_format); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec); + } +} + +static void +champlain_network_map_source_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + ChamplainNetworkMapSource *network_map_source = CHAMPLAIN_NETWORK_MAP_SOURCE(object); + ChamplainNetworkMapSourcePrivate *priv = GET_PRIVATE (network_map_source); + + switch(prop_id) + { + case PROP_URI_FORMAT: + priv->uri_format = g_value_dup_string (value); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec); + } +} + +static void +champlain_network_map_source_finalize (GObject *object) +{ + /* ChamplainNetworkMapSource *network_map_source = CHAMPLAIN_NETWORK_MAP_SOURCE (object); + * ChamplainNetworkMapSourcePrivate *priv = GET_PRIVATE (network_map_source); + */ + + G_OBJECT_CLASS (champlain_network_map_source_parent_class)->finalize (object); +} + +static void +champlain_network_map_source_class_init (ChamplainNetworkMapSourceClass *klass) +{ + GParamSpec *pspec; + + g_type_class_add_private (klass, sizeof (ChamplainNetworkMapSourcePrivate)); + + GObjectClass *object_class = G_OBJECT_CLASS (klass); + object_class->finalize = champlain_network_map_source_finalize; + object_class->get_property = champlain_network_map_source_get_property; + object_class->set_property = champlain_network_map_source_set_property; + + ChamplainMapSourceClass *map_source_class = CHAMPLAIN_MAP_SOURCE_CLASS (klass); + map_source_class->get_tile = champlain_network_map_source_get_tile; + + /** + * ChamplainNetworkMapSource:uri-format + * + * The uri format for the map source + * + * Since: 0.4 + */ + pspec = g_param_spec_string ("uri-format", + "URI Format", + "The URI format", + "", + (G_PARAM_READWRITE | G_PARAM_CONSTRUCT)); + g_object_class_install_property (object_class, PROP_URI_FORMAT, pspec); + +} + +static void +champlain_network_map_source_init (ChamplainNetworkMapSource *champlainMapSource) +{ + ChamplainNetworkMapSourcePrivate *priv = GET_PRIVATE (champlainMapSource); +} + +ChamplainNetworkMapSource* +champlain_network_map_source_new_full (gchar *name, + gchar *license, + gchar *license_uri, + guint min_zoom, + guint max_zoom, + guint tile_size, + ChamplainMapProjection projection, + gchar *uri_format) +{ + ChamplainNetworkMapSource * network_map_source; + network_map_source = g_object_new (CHAMPLAIN_TYPE_NETWORK_MAP_SOURCE, "name", name, + "license", license, "license-uri", license_uri, + "min-zoom-level", min_zoom, "max-zoom-level", max_zoom, + "tile-size", tile_size, "map-projection", projection, + "uri-format", uri_format, NULL); + return network_map_source; +} + +gchar * +champlain_network_map_source_get_tile_uri (ChamplainNetworkMapSource *network_map_source, + gint x, + gint y, + gint z) +{ + ChamplainNetworkMapSourcePrivate *priv = GET_PRIVATE (network_map_source); + + gchar **tokens; + gchar *token; + GString *ret; + gint i = 0; + + tokens = g_strsplit (priv->uri_format, "#", 20); + token = tokens[i]; + ret = g_string_sized_new (strlen (priv->uri_format)); + + while (token != NULL) + { + gint number = G_MAXINT; + gchar value[3]; + + if (strcmp (token, "X") == 0) + number = x; + if (strcmp (token, "Y") == 0) + number = y; + if (strcmp (token, "Z") == 0) + number = z; + + if (number != G_MAXINT) + { + g_sprintf (value, "%d", number); + g_string_append (ret, value); + } + else + g_string_append (ret, token); + + token = tokens[++i]; + } + token = ret->str; + g_string_free (ret, FALSE); + g_strfreev (tokens); + + return token; +} + +void +champlain_network_map_source_set_tile_uri (ChamplainNetworkMapSource *network_map_source, + const gchar *uri_format) +{ + ChamplainNetworkMapSourcePrivate *priv = GET_PRIVATE (network_map_source); + + priv->uri_format = g_strdup (uri_format); +} + +ChamplainMapSource * +champlain_map_source_new_osm_mapnik () +{ + return CHAMPLAIN_MAP_SOURCE (champlain_network_map_source_new_full ("OpenStreetMap Mapnik", + "(CC) BY 2.0 OpenStreetMap contributors", + "http://creativecommons.org/licenses/by/2.0/", 0, 18, 256, + CHAMPLAIN_MAP_PROJECTION_MERCATOR, + "http://tile.openstreetmap.org/#Z#/#X#/#Y#.png")); +} + +ChamplainMapSource * +champlain_map_source_new_oam () +{ + return CHAMPLAIN_MAP_SOURCE (champlain_network_map_source_new_full ("OpenArialMap", + "(CC) BY 3.0 OpenArialMap contributors", + "http://creativecommons.org/licenses/by/3.0/", 0, 17, 256, + CHAMPLAIN_MAP_PROJECTION_MERCATOR, + "http://tile.openaerialmap.org/tiles/1.0.0/openaerialmap-900913/#Z#/#X#/#Y#.jpg")); +} + +ChamplainMapSource * +champlain_map_source_new_mff_relief () +{ + return CHAMPLAIN_MAP_SOURCE (champlain_network_map_source_new_full ("MapsForFree Relief", + "Map data available under GNU Free Documentation license, Version 1.2 or later", + "http://www.gnu.org/copyleft/fdl.html", 0, 11, 256, + CHAMPLAIN_MAP_PROJECTION_MERCATOR, + "http://maps-for-free.com/layer/relief/z#Z#/row#Y#/#Z#_#X#-#Y#.jpg")); +} + +static gchar * +get_filename (ChamplainNetworkMapSource *network_map_source, + ChamplainZoomLevel *level, + ChamplainTile *tile) +{ + ChamplainNetworkMapSourcePrivate *priv = GET_PRIVATE (network_map_source); + return g_strdup_printf ("%s" G_DIR_SEPARATOR_S "%s" G_DIR_SEPARATOR_S + "%s" G_DIR_SEPARATOR_S "%d" G_DIR_SEPARATOR_S + "%d" G_DIR_SEPARATOR_S "%d.png", g_get_user_cache_dir (), + CACHE_SUBDIR, champlain_map_source_get_name (CHAMPLAIN_MAP_SOURCE (network_map_source)), + champlain_zoom_level_get_zoom_level (level), + champlain_tile_get_x (tile), champlain_tile_get_y (tile), + NULL); +} + +typedef struct { + ChamplainView *view; + ChamplainZoomLevel *zoom_level; + ChamplainTile *tile; +} FileLoadedCallbackContext; + +static void +create_error_tile (ChamplainTile* tile) +{ + ClutterActor *actor; + actor = clutter_texture_new_from_file (DATADIR "/champlain/error.svg", NULL); + if (!actor) + return; + + champlain_tile_set_actor (tile, actor); + clutter_actor_show (actor); + + champlain_tile_set_state (tile, CHAMPLAIN_STATE_DONE); +} + +static void +file_loaded_cb (SoupSession *session, + SoupMessage *msg, + gpointer user_data) +{ + FileLoadedCallbackContext *ctx = (FileLoadedCallbackContext*) user_data; + GdkPixbufLoader* loader; + GError *error = NULL; + gchar* path, *filename; + + if (!SOUP_STATUS_IS_SUCCESSFUL (msg->status_code)) + { + g_warning ("Unable to download tile %d, %d: %s", + champlain_tile_get_x (ctx->tile), + champlain_tile_get_y (ctx->tile), + soup_status_get_phrase(msg->status_code)); + g_object_unref (ctx->tile); + create_error_tile (ctx->tile); + return; + } + + loader = gdk_pixbuf_loader_new(); + if (!gdk_pixbuf_loader_write (loader, + (const guchar *) msg->response_body->data, + msg->response_body->length, + &error)) + { + if (error) + { + g_warning ("Unable to load the pixbuf: %s", error->message); + g_error_free (error); + create_error_tile (ctx->tile); + goto finish; + } + + g_object_unref (loader); + } + + gdk_pixbuf_loader_close (loader, &error); + if (error) + { + g_warning ("Unable to close the pixbuf loader: %s", error->message); + g_error_free (error); + create_error_tile (ctx->tile); + goto finish; + } + + filename = champlain_tile_get_filename (ctx->tile); + path = g_path_get_dirname (filename); + + if (g_mkdir_with_parents (path, 0700) == -1) + { + if (errno != EEXIST) + { + g_warning ("Unable to create the image cache: %s", + g_strerror (errno)); + g_object_unref (loader); + } + } + + g_file_set_contents (filename, msg->response_body->data, + msg->response_body->length, NULL); + + /* If the tile has been marked to be deleted, don't go any further */ + /*if (tile->to_destroy) + { + g_object_unref (loader); + g_free (filename); + g_free (map_filename); + g_free (tile); + return; + } +*/ + GdkPixbuf* pixbuf = gdk_pixbuf_loader_get_pixbuf(loader); + ClutterActor *actor = clutter_texture_new(); + clutter_texture_set_from_rgb_data (CLUTTER_TEXTURE (actor), + gdk_pixbuf_get_pixels (pixbuf), + gdk_pixbuf_get_has_alpha (pixbuf), + gdk_pixbuf_get_width (pixbuf), + gdk_pixbuf_get_height (pixbuf), + gdk_pixbuf_get_rowstride (pixbuf), + 3, 0, NULL); + champlain_tile_set_actor (ctx->tile, actor); + DEBUG ("Tile loaded from network"); + +finish: + champlain_tile_set_state (ctx->tile, CHAMPLAIN_STATE_DONE); + + g_object_unref (loader); + g_free (path); + + champlain_view_tile_ready (ctx->view, ctx->zoom_level, ctx->tile, TRUE); + g_object_unref (ctx->tile); + g_object_unref (ctx->zoom_level); + g_free (ctx); +} + +void +champlain_network_map_source_get_tile (ChamplainMapSource *map_source, + ChamplainView *view, + ChamplainZoomLevel *zoom_level, + ChamplainTile *tile) +{ + gchar* filename; + + ChamplainNetworkMapSource *network_map_source = CHAMPLAIN_NETWORK_MAP_SOURCE (map_source); + ChamplainNetworkMapSourcePrivate *priv = GET_PRIVATE (network_map_source); + + /* Ref the tile as it may be freeing during the loading + * Unref when the loading is done. + */ + g_object_ref (tile); + g_object_ref (zoom_level); + + /* Try the cached version first */ + filename = get_filename (network_map_source, zoom_level, tile); + champlain_tile_set_filename (tile, filename); + champlain_tile_set_size (tile, champlain_map_source_get_tile_size (map_source)); + + if (g_file_test (filename, G_FILE_TEST_EXISTS)) + { + GError *error = NULL; + ClutterActor *actor; + + actor = clutter_texture_new_from_file (filename, &error); + champlain_tile_set_actor (tile, actor); + clutter_actor_show (actor); + + champlain_tile_set_state (tile, CHAMPLAIN_STATE_DONE); + DEBUG ("Tile loaded from cache"); + champlain_view_tile_ready (view, zoom_level, tile, FALSE); + g_object_unref (tile); + g_object_unref (zoom_level); + } + else if (champlain_settings_is_online ()) + { + SoupMessage *msg; + gchar *uri; + FileLoadedCallbackContext *ctx = g_new0 (FileLoadedCallbackContext, 1); + ctx->view = view; + ctx->zoom_level = zoom_level; + ctx->tile = tile; + + if (!soup_session) + soup_session = soup_session_async_new (); + + uri = champlain_network_map_source_get_tile_uri (network_map_source, + champlain_tile_get_x (tile), champlain_tile_get_y (tile), + champlain_zoom_level_get_zoom_level (zoom_level)); + champlain_tile_set_uri (tile, uri); + champlain_tile_set_state (tile, CHAMPLAIN_STATE_LOADING); + msg = soup_message_new (SOUP_METHOD_GET, uri); + + soup_session_queue_message (soup_session, msg, + file_loaded_cb, + ctx); + } + /* If a tile is neither in cache or can be fetched, do nothing, it'll show up + * as empty + */ +} + diff --git a/champlain/champlain-network-map-source.h b/champlain/champlain-network-map-source.h new file mode 100644 index 0000000..642d734 --- /dev/null +++ b/champlain/champlain-network-map-source.h @@ -0,0 +1,73 @@ +/* + * Copyright (C) 2008-2009 Pierre-Luc Beaudoin + * + * This library 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.1 of the License, or (at your option) any later version. + * + * This library 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 this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#if !defined (__CHAMPLAIN_CHAMPLAIN_H_INSIDE__) && !defined (CHAMPLAIN_COMPILATION) +#error "Only can be included directly." +#endif + +#ifndef CHAMPLAIN_NETWORK_MAP_SOURCE_H +#define CHAMPLAIN_NETWORK_MAP_SOURCE_H + +#include +#include + +#include + +#define CHAMPLAIN_TYPE_NETWORK_MAP_SOURCE (champlain_network_map_source_get_type()) +#define CHAMPLAIN_NETWORK_MAP_SOURCE(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), CHAMPLAIN_TYPE_NETWORK_MAP_SOURCE, ChamplainNetworkMapSource)) +#define CHAMPLAIN_NETWORK_MAP_SOURCE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), CHAMPLAIN_TYPE_NETWORK_MAP_SOURCE, ChamplainNetworkMapSourceClass)) +#define CHAMPLAIN_IS_NETWORK_MAP_SOURCE(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), CHAMPLAIN_TYPE_NETWORK_MAP_SOURCE)) +#define CHAMPLAIN_IS_NETWORK_MAP_SOURCE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), CHAMPLAIN_TYPE_NETWORK_MAP_SOURCE)) +#define CHAMPLAIN_NETWORK_MAP_SOURCE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), CHAMPLAIN_TYPE_NETWORK_MAP_SOURCE, ChamplainNetworkMapSourceClass)) + +typedef struct _ChamplainNetworkMapSource ChamplainNetworkMapSource; +typedef struct _ChamplainNetworkMapSourceClass ChamplainNetworkMapSourceClass; +typedef struct _ChamplainNetworkMapSourcePrivate ChamplainNetworkMapSourcePrivate; + +struct _ChamplainNetworkMapSource +{ + ChamplainMapSource parent; + ChamplainNetworkMapSourcePrivate *priv; +}; + +struct _ChamplainNetworkMapSourceClass +{ + ChamplainMapSourceClass parent_class; +}; + +GType champlain_network_map_source_get_type (void); + +ChamplainNetworkMapSource* champlain_network_map_source_new_full (gchar *name, + gchar *license, gchar *license_uri, guint min_zoom, guint map_zoom, + guint tile_size, ChamplainMapProjection projection, gchar *uri_format); + +ChamplainMapSource * champlain_map_source_new_osm_mapnik (); +ChamplainMapSource * champlain_map_source_new_oam (); +ChamplainMapSource * champlain_map_source_new_mff_relief (); + +gchar * champlain_network_map_source_get_tile_uri (ChamplainNetworkMapSource *source, + gint x, gint y, gint z); + +void champlain_network_map_source_set_tile_uri (ChamplainNetworkMapSource *network_map_source, + const gchar *uri_format); + +void champlain_network_map_source_get_tile (ChamplainMapSource *map_source, + ChamplainView *view, ChamplainZoomLevel *level, ChamplainTile *tile); + + +#endif diff --git a/champlain/champlain.h b/champlain/champlain.h index 0128fb5..9df678b 100644 --- a/champlain/champlain.h +++ b/champlain/champlain.h @@ -34,6 +34,7 @@ #include "champlain/champlain-view.h" #include "champlain/champlain-enum-types.h" #include "champlain/champlain-map-source.h" +#include "champlain/champlain-network-map-source.h" #include "champlain/champlain-settings.h" #undef __CHAMPLAIN_CHAMPLAIN_H_INSIDE__ diff --git a/demos/launcher-gtk.c b/demos/launcher-gtk.c index d878fe7..69c35b0 100644 --- a/demos/launcher-gtk.c +++ b/demos/launcher-gtk.c @@ -77,17 +77,17 @@ map_source_changed (GtkWidget *widget, ChamplainView *view) { gchar* selection = gtk_combo_box_get_active_text(GTK_COMBO_BOX(widget)); - if (g_strcmp0(selection, OSM_MAP) == 0) + if (g_strcmp0 (selection, OSM_MAP) == 0) { - g_object_set(G_OBJECT(view), "map-source", champlain_map_source_new_osm_mapnik (), NULL); + g_object_set (G_OBJECT (view), "map-source", champlain_map_source_new_osm_mapnik (), NULL); } - else if (g_strcmp0(selection, OAM_MAP) == 0) + else if (g_strcmp0 (selection, OAM_MAP) == 0) { - g_object_set(G_OBJECT(view), "map-source", champlain_map_source_new_oam (), NULL); + g_object_set (G_OBJECT (view), "map-source", champlain_map_source_new_oam (), NULL); } - else if (g_strcmp0(selection, MFF_MAP) == 0) + else if (g_strcmp0 (selection, MFF_MAP) == 0) { - g_object_set(G_OBJECT(view), "map-source", champlain_map_source_new_mff_relief (), NULL); + g_object_set (G_OBJECT (view), "map-source", champlain_map_source_new_mff_relief (), NULL); } }