Simplify use of cache for ordinary applications
[libchamplain:potyl-perl.git] / champlain / champlain-map-source-factory.c
1 /*
2  * Copyright (C) 2009 Pierre-Luc Beaudoin <pierre-luc@pierlux.com>
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2.1 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
17  */
18
19 /**
20  * SECTION:champlain-map-source-factory
21  * @short_description: Manages #ChamplainMapSource
22  *
23  * This factory manages the create of #ChamplainMapSource. It contains names
24  * and constructor functions for each available map sources in libchamplain.
25  * You can add your own with #champlain_map_source_factory_register.
26  *
27  * To get the wanted map source, use #champlain_map_source_factory_create. It
28  * will return a ready to use #ChamplainMapSource.
29  *
30  * To get the list of registered map sources, use
31  * #champlain_map_source_factory_dup_list.
32  *
33  */
34 #include "config.h"
35
36 #include "champlain-map-source-factory.h"
37
38 #define DEBUG_FLAG CHAMPLAIN_DEBUG_NETWORK
39 #include "champlain-debug.h"
40
41 #include "champlain.h"
42 #include "champlain-file-cache.h"
43 #include "champlain-defines.h"
44 #include "champlain-enum-types.h"
45 #include "champlain-map-source.h"
46 #include "champlain-marshal.h"
47 #include "champlain-private.h"
48 #include "champlain-zoom-level.h"
49 #include "champlain-network-tile-source.h"
50 #include "champlain-map-source-chain.h"
51 #include "champlain-error-tile-source.h"
52
53 #include <glib.h>
54 #include <string.h>
55
56 enum
57 {
58   /* normal signals */
59   LAST_SIGNAL
60 };
61
62 enum
63 {
64   PROP_0,
65 };
66
67 /* static guint champlain_map_source_factory_signals[LAST_SIGNAL] = { 0, }; */
68 static ChamplainMapSourceFactory *instance = NULL;
69
70 G_DEFINE_TYPE (ChamplainMapSourceFactory, champlain_map_source_factory, G_TYPE_OBJECT);
71
72 #define GET_PRIVATE(obj)    (G_TYPE_INSTANCE_GET_PRIVATE((obj), CHAMPLAIN_TYPE_MAP_SOURCE_FACTORY, ChamplainMapSourceFactoryPrivate))
73
74 struct _ChamplainMapSourceFactoryPrivate
75 {
76   GSList *registered_sources;
77 };
78
79 static ChamplainMapSource * champlain_map_source_new_generic (
80      ChamplainMapSourceDesc *desc, gpointer data);
81
82 static ChamplainMapSource * champlain_map_source_new_memphis (
83     ChamplainMapSourceDesc *desc, gpointer user_data);
84
85 static void
86 champlain_map_source_factory_get_property (GObject *object,
87     guint prop_id,
88     GValue *value,
89     GParamSpec *pspec)
90 {
91   //ChamplainMapSourceFactory *map_source_factory = CHAMPLAIN_MAP_SOURCE_FACTORY(object);
92   //ChamplainMapSourceFactoryPrivate *priv = map_source_factory->priv;
93
94   switch(prop_id)
95     {
96       default:
97         G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
98     }
99 }
100
101 static void
102 champlain_map_source_factory_set_property (GObject *object,
103     guint prop_id,
104     const GValue *value,
105     GParamSpec *pspec)
106 {
107   //ChamplainMapSourceFactory *map_source_factory = CHAMPLAIN_MAP_SOURCE_FACTORY(object);
108   //ChamplainMapSourceFactoryPrivate *priv = map_source_factory->priv;
109
110   switch(prop_id)
111     {
112       default:
113         G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
114     }
115 }
116
117 static void
118 champlain_map_source_factory_finalize (GObject *object)
119 {
120   ChamplainMapSourceFactory *factory = CHAMPLAIN_MAP_SOURCE_FACTORY (object);
121
122   g_slist_free (factory->priv->registered_sources);
123
124   G_OBJECT_CLASS (champlain_map_source_factory_parent_class)->finalize (object);
125 }
126
127 static GObject *
128 champlain_map_source_factory_constructor (GType type,
129     guint n_construct_params,
130     GObjectConstructParam *construct_params)
131 {
132   GObject *retval;
133
134   if (instance == NULL)
135     {
136       retval = G_OBJECT_CLASS (champlain_map_source_factory_parent_class)->constructor
137           (type, n_construct_params, construct_params);
138
139       instance = CHAMPLAIN_MAP_SOURCE_FACTORY (retval);
140       g_object_add_weak_pointer (retval, (gpointer) &instance);
141     }
142   else
143     {
144       retval = g_object_ref (instance);
145     }
146
147   return retval;
148 }
149
150 static void
151 champlain_map_source_factory_class_init (ChamplainMapSourceFactoryClass *klass)
152 {
153   g_type_class_add_private (klass, sizeof (ChamplainMapSourceFactoryPrivate));
154
155   GObjectClass *object_class = G_OBJECT_CLASS (klass);
156
157   object_class->constructor = champlain_map_source_factory_constructor;
158   object_class->finalize = champlain_map_source_factory_finalize;
159   object_class->get_property = champlain_map_source_factory_get_property;
160   object_class->set_property = champlain_map_source_factory_set_property;
161 }
162
163 static
164 ChamplainMapSourceDesc OSM_MAPNIK_DESC =
165   {
166     CHAMPLAIN_MAP_SOURCE_OSM_MAPNIK,
167     "OpenStreetMap Mapnik",
168     "Map data is CC-BY-SA 2.0 OpenStreetMap contributors",
169     "http://creativecommons.org/licenses/by-sa/2.0/",
170     0,
171     18,
172     CHAMPLAIN_MAP_PROJECTION_MERCATOR,
173     champlain_map_source_new_generic,
174     "http://tile.openstreetmap.org/#Z#/#X#/#Y#.png",
175     NULL
176   };
177
178 static
179 ChamplainMapSourceDesc OSM_OSMARENDER_DESC =
180   {
181     CHAMPLAIN_MAP_SOURCE_OSM_OSMARENDER,
182     "OpenStreetMap Osmarender",
183     "Map data is CC-BY-SA 2.0 OpenStreetMap contributors",
184     "http://creativecommons.org/licenses/by-sa/2.0/",
185     0,
186     17,
187     CHAMPLAIN_MAP_PROJECTION_MERCATOR,
188     champlain_map_source_new_generic,
189     "http://tah.openstreetmap.org/Tiles/tile/#Z#/#X#/#Y#.png",
190     NULL
191   };
192
193 static
194 ChamplainMapSourceDesc OSM_CYCLEMAP_DESC =
195   {
196     CHAMPLAIN_MAP_SOURCE_OSM_CYCLE_MAP,
197     "OpenStreetMap Cycle Map",
198     "Map data is CC-BY-SA 2.0 OpenStreetMap contributors",
199     "http://creativecommons.org/licenses/by-sa/2.0/",
200     0,
201     18,
202     CHAMPLAIN_MAP_PROJECTION_MERCATOR,
203     champlain_map_source_new_generic,
204     "http://andy.sandbox.cloudmade.com/tiles/cycle/#Z#/#X#/#Y#.png",
205     NULL
206   };
207
208 static
209 ChamplainMapSourceDesc OSM_TRANSPORTMAP_DESC =
210   {
211     CHAMPLAIN_MAP_SOURCE_OSM_TRANSPORT_MAP,
212     "OpenStreetMap Transport Map",
213     "Map data is CC-BY-SA 2.0 OpenStreetMap contributors",
214     "http://creativecommons.org/licenses/by-sa/2.0/",
215     0,
216     18,
217     CHAMPLAIN_MAP_PROJECTION_MERCATOR,
218     champlain_map_source_new_generic,
219     "http://tile.xn--pnvkarte-m4a.de/tilegen/#Z#/#X#/#Y#.png",
220     NULL
221   };
222
223 #if 0
224 /* Disabling until OpenArealMap works again */
225 static
226 ChamplainMapSourceDesc OAM_DESC =
227   {
228     CHAMPLAIN_MAP_SOURCE_OAM,
229     "OpenAerialMap",
230     "(CC) BY 3.0 OpenAerialMap contributors",
231     "http://creativecommons.org/licenses/by/3.0/",
232     0,
233     17,
234     CHAMPLAIN_MAP_PROJECTION_MERCATOR,
235     champlain_map_source_new_generic,
236     "http://tile.openaerialmap.org/tiles/1.0.0/openaerialmap-900913/#Z#/#X#/#Y#.jpg",
237     NULL
238   };
239 #endif
240
241 static
242 ChamplainMapSourceDesc MFF_RELIEF_DESC =
243   {
244     CHAMPLAIN_MAP_SOURCE_MFF_RELIEF,
245     "Maps for Free Relief",
246     "Map data available under GNU Free Documentation license, Version 1.2 or later",
247     "http://www.gnu.org/copyleft/fdl.html",
248     0,
249     11,
250     CHAMPLAIN_MAP_PROJECTION_MERCATOR,
251     champlain_map_source_new_generic,
252     "http://maps-for-free.com/layer/relief/z#Z#/row#Y#/#Z#_#X#-#Y#.jpg",
253     NULL
254   };
255
256 static
257 ChamplainMapSourceDesc MEMPHIS_LOCAL_DESC =
258   {
259     CHAMPLAIN_MAP_SOURCE_MEMPHIS_LOCAL,
260     "OpenStreetMap Memphis Local Map",
261     "(CC) BY 2.0 OpenStreetMap contributors",
262     "http://creativecommons.org/licenses/by/2.0/",
263     12,
264     18,
265     CHAMPLAIN_MAP_PROJECTION_MERCATOR,
266     champlain_map_source_new_memphis,
267     "",
268     NULL
269   };
270
271 static
272 ChamplainMapSourceDesc MEMPHIS_NETWORK_DESC =
273   {
274     CHAMPLAIN_MAP_SOURCE_MEMPHIS_NETWORK,
275     "OpenStreetMap Memphis Network Map",
276     "(CC) BY 2.0 OpenStreetMap contributors",
277     "http://creativecommons.org/licenses/by/2.0/",
278     12,
279     18,
280     CHAMPLAIN_MAP_PROJECTION_MERCATOR,
281     champlain_map_source_new_memphis,
282     "",
283     NULL
284   };
285
286 static void
287 champlain_map_source_factory_init (ChamplainMapSourceFactory *factory)
288 {
289   ChamplainMapSourceFactoryPrivate *priv = GET_PRIVATE (factory);
290
291   factory->priv = priv;
292
293   priv->registered_sources = NULL;
294
295   champlain_map_source_factory_register (factory, &OSM_MAPNIK_DESC,
296       OSM_MAPNIK_DESC.constructor, OSM_MAPNIK_DESC.data);
297   champlain_map_source_factory_register (factory, &OSM_CYCLEMAP_DESC,
298       OSM_CYCLEMAP_DESC.constructor, OSM_CYCLEMAP_DESC.data);
299   champlain_map_source_factory_register (factory, &OSM_TRANSPORTMAP_DESC,
300       OSM_TRANSPORTMAP_DESC.constructor, OSM_TRANSPORTMAP_DESC.data);
301   champlain_map_source_factory_register (factory, &OSM_OSMARENDER_DESC,
302       OSM_OSMARENDER_DESC.constructor, OSM_OSMARENDER_DESC.data);
303 #if 0
304   champlain_map_source_factory_register (factory, &OAM_DESC,
305       OAM_DESC.constructor, OAM_DESC.data);
306 #endif
307   champlain_map_source_factory_register (factory, &MFF_RELIEF_DESC,
308       MFF_RELIEF_DESC.constructor, MFF_RELIEF_DESC.data);
309   champlain_map_source_factory_register (factory, &MEMPHIS_LOCAL_DESC,
310       MEMPHIS_LOCAL_DESC.constructor, MEMPHIS_LOCAL_DESC.data);
311   champlain_map_source_factory_register (factory, &MEMPHIS_NETWORK_DESC,
312       MEMPHIS_NETWORK_DESC.constructor, MEMPHIS_NETWORK_DESC.data);
313 }
314
315 /**
316  * champlain_map_source_factory_dup_default:
317  *
318  * Returns: the singleton #ChamplainMapSourceFactory, it should be freed
319  * using #g_object_unref when not needed.
320  *
321  * Since: 0.4
322  */
323 ChamplainMapSourceFactory *
324 champlain_map_source_factory_dup_default (void)
325 {
326   return g_object_new (CHAMPLAIN_TYPE_MAP_SOURCE_FACTORY, NULL);
327 }
328
329 /**
330  * champlain_map_source_factory_dup_list:
331  *
332  * Returns: the list of registered map sources, the items should not be freed,
333  * the list should be freed with #g_slist_free.
334  *
335  * Since: 0.4
336  */
337 GSList *
338 champlain_map_source_factory_dup_list (ChamplainMapSourceFactory *factory)
339 {
340   return g_slist_copy (factory->priv->registered_sources);
341 }
342
343 /**
344  * champlain_map_source_factory_create:
345  * @factory: the Factory
346  * @id: the wanted map source id
347  *
348  * Returns: a ready to use #ChamplainMapSource matching the given name, returns
349  * NULL is none match.
350  *
351  * The id should not contain any character that can't be in a filename as it
352  * will be used as the cache directory name for that map source.
353  *
354  * Since: 0.4
355  */
356 ChamplainMapSource *
357 champlain_map_source_factory_create (ChamplainMapSourceFactory *factory,
358     const gchar *id)
359 {
360   GSList *item;
361
362   item = factory->priv->registered_sources;
363
364   while (item != NULL)
365     {
366       ChamplainMapSourceDesc *desc = CHAMPLAIN_MAP_SOURCE_DESC (item->data);
367       if (strcmp (desc->id, id) == 0)
368         return desc->constructor (desc, desc->data);
369       item = g_slist_next (item);
370     }
371
372   return NULL;
373 }
374
375 ChamplainMapSource * champlain_map_source_factory_create_cached_source (ChamplainMapSourceFactory *factory,
376     const gchar *id)
377 {
378   ChamplainMapSourceChain *source_chain;
379   ChamplainMapSource *tile_source;
380   ChamplainMapSource *error_source;
381   ChamplainMapSource *file_cache;
382   guint tile_size;
383
384   tile_source = champlain_map_source_factory_create (factory, id);
385
386   tile_size = champlain_map_source_get_tile_size(tile_source);
387   error_source = CHAMPLAIN_MAP_SOURCE(champlain_error_tile_source_new_full (tile_size));
388
389   file_cache = CHAMPLAIN_MAP_SOURCE(champlain_file_cache_new ());
390
391   source_chain = champlain_map_source_chain_new ();
392   champlain_map_source_chain_push(source_chain, error_source);
393   champlain_map_source_chain_push(source_chain, tile_source);
394   champlain_map_source_chain_push(source_chain, file_cache);
395
396   return CHAMPLAIN_MAP_SOURCE(source_chain);
397 }
398
399 /**
400  * champlain_map_source_factory_register:
401  * @factory: A #ChamplainMapSourceFactory
402  * @desc: the description of the map source
403  * @constructor: the new map source constructor function
404  * @data: data to be passed to the constructor function, or NULL
405  *
406  * Registers the new map source with the given constructor.  When this map
407  * source is requested, the given constructor will be used to build the
408  * map source.  #ChamplainMapSourceFactory will take ownership of the passed
409  * #ChamplainMapSourceDesc, so don't free it. They will not be freed either so
410  * you can use static structs here.
411  *
412  * Returns: TRUE if the registration suceeded.
413  *
414  * Since: 0.4
415  */
416 gboolean
417 champlain_map_source_factory_register (ChamplainMapSourceFactory *factory,
418     ChamplainMapSourceDesc *desc, ChamplainMapSourceConstructor constructor,
419     gpointer data)
420 {
421
422   /* FIXME: check for existing factory with that name? */
423   desc->constructor = constructor;
424   desc->data = data;
425   factory->priv->registered_sources = g_slist_append (factory->priv->registered_sources, desc);
426   return TRUE;
427 }
428
429 static ChamplainMapSource *
430 champlain_map_source_new_generic (
431      ChamplainMapSourceDesc *desc, gpointer user_data)
432 {
433   return CHAMPLAIN_MAP_SOURCE (champlain_network_tile_source_new_full (
434       desc->id,
435       desc->name,
436       desc->license,
437       desc->license_uri,
438       desc->min_zoom_level,
439       desc->max_zoom_level,
440       256,
441       desc->projection,
442       desc->uri_format));
443 }
444
445 static ChamplainMapSource *
446 champlain_map_source_new_memphis (ChamplainMapSourceDesc *desc,
447     gpointer user_data)
448 {
449   ChamplainMapDataSource *map_data_source;
450
451   if (g_strcmp0 (desc->id, CHAMPLAIN_MAP_SOURCE_MEMPHIS_LOCAL) == 0)
452     {
453       map_data_source = CHAMPLAIN_MAP_DATA_SOURCE (champlain_local_map_data_source_new ());
454
455       /* Abuse the uri_format field to store an initial data path (optional) */
456       if (desc->uri_format && g_strcmp0 (desc->uri_format, "") != 0)
457         champlain_local_map_data_source_load_map_data (
458             CHAMPLAIN_LOCAL_MAP_DATA_SOURCE (map_data_source),
459             desc->uri_format);
460     }
461   else if (g_strcmp0 (desc->id, CHAMPLAIN_MAP_SOURCE_MEMPHIS_NETWORK) == 0)
462       map_data_source = CHAMPLAIN_MAP_DATA_SOURCE (champlain_network_map_data_source_new ());
463   else
464     return NULL;
465
466   return CHAMPLAIN_MAP_SOURCE (champlain_memphis_tile_source_new_full (
467       desc->id,
468       desc->name,
469       desc->license,
470       desc->license_uri,
471       desc->min_zoom_level,
472       desc->max_zoom_level,
473       256,
474       desc->projection,
475       map_data_source));
476 }