Simplify use of cache for ordinary applications
[libchamplain:potyl-perl.git] / champlain / champlain-map-source-chain.c
1 /*
2  * Copyright (C) 2010 Jiri Techet <techet@gmail.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 #include "champlain-map-source-chain.h"
20 #include "champlain-tile-cache.h"
21 #include "champlain-tile-source.h"
22
23 G_DEFINE_TYPE (ChamplainMapSourceChain, champlain_map_source_chain, CHAMPLAIN_TYPE_MAP_SOURCE);
24
25 #define GET_PRIVATE(obj)    (G_TYPE_INSTANCE_GET_PRIVATE((obj), CHAMPLAIN_TYPE_MAP_SOURCE_CHAIN, ChamplainMapSourceChainPrivate))
26
27 typedef struct _ChamplainMapSourceChainPrivate ChamplainMapSourceChainPrivate;
28
29 struct _ChamplainMapSourceChainPrivate
30 {
31   ChamplainMapSource *stack_top;
32   gulong sig_handler_id;
33 };
34
35 static const gchar *get_id (ChamplainMapSource *map_source);
36 static const gchar *get_name (ChamplainMapSource *map_source);
37 static const gchar *get_license (ChamplainMapSource *map_source);
38 static const gchar *get_license_uri (ChamplainMapSource *map_source);
39 static guint get_min_zoom_level (ChamplainMapSource *map_source);
40 static guint get_max_zoom_level (ChamplainMapSource *map_source);
41 static guint get_tile_size (ChamplainMapSource *map_source);
42
43 static void fill_tile (ChamplainMapSource *map_source, ChamplainTile *tile);
44
45 static void
46 champlain_map_source_chain_dispose (GObject *object)
47 {
48   ChamplainMapSourceChain *source_chain = CHAMPLAIN_MAP_SOURCE_CHAIN(object);
49   ChamplainMapSourceChainPrivate *priv = GET_PRIVATE(object);
50
51   while (priv->stack_top)
52     champlain_map_source_chain_pop_map_source(source_chain);
53
54   G_OBJECT_CLASS (champlain_map_source_chain_parent_class)->dispose (object);
55 }
56
57 static void
58 champlain_map_source_chain_finalize (GObject *object)
59 {
60   G_OBJECT_CLASS (champlain_map_source_chain_parent_class)->finalize (object);
61 }
62
63 static void
64 champlain_map_source_chain_class_init (ChamplainMapSourceChainClass *klass)
65 {
66   GObjectClass* object_class = G_OBJECT_CLASS (klass);
67
68   g_type_class_add_private (klass, sizeof (ChamplainMapSourceChainPrivate));
69
70   object_class->finalize = champlain_map_source_chain_finalize;
71   object_class->dispose = champlain_map_source_chain_dispose;
72
73   ChamplainMapSourceClass *map_source_class = CHAMPLAIN_MAP_SOURCE_CLASS (klass);
74
75   map_source_class->get_id = get_id;
76   map_source_class->get_name = get_name;
77   map_source_class->get_license = get_license;
78   map_source_class->get_license_uri = get_license_uri;
79   map_source_class->get_min_zoom_level = get_min_zoom_level;
80   map_source_class->get_max_zoom_level = get_max_zoom_level;
81   map_source_class->get_tile_size = get_tile_size;
82
83   map_source_class->fill_tile = fill_tile;
84 }
85
86 static void
87 champlain_map_source_chain_init (ChamplainMapSourceChain *source_chain)
88 {
89   ChamplainMapSourceChainPrivate *priv = GET_PRIVATE(source_chain);
90   priv->stack_top = NULL;
91   priv->sig_handler_id = 0;
92 }
93
94 ChamplainMapSourceChain* champlain_map_source_chain_new (void)
95 {
96   return g_object_new (CHAMPLAIN_TYPE_MAP_SOURCE_CHAIN, NULL);
97 }
98
99 static const gchar *
100 get_id (ChamplainMapSource *map_source)
101 {
102   ChamplainMapSourceChain *source_chain = CHAMPLAIN_MAP_SOURCE_CHAIN (map_source);
103   g_return_val_if_fail (source_chain, NULL);
104
105   ChamplainMapSourceChainPrivate *priv = GET_PRIVATE(source_chain);
106   g_return_val_if_fail (priv->stack_top, NULL);
107
108   return champlain_map_source_get_id(priv->stack_top);
109 }
110
111 static const gchar *
112 get_name (ChamplainMapSource *map_source)
113 {
114   ChamplainMapSourceChain *source_chain = CHAMPLAIN_MAP_SOURCE_CHAIN (map_source);
115   g_return_val_if_fail (source_chain, NULL);
116
117   ChamplainMapSourceChainPrivate *priv = GET_PRIVATE(source_chain);
118   g_return_val_if_fail (priv->stack_top, NULL);
119
120   return champlain_map_source_get_name(priv->stack_top);
121 }
122
123 static const gchar *
124 get_license (ChamplainMapSource *map_source)
125 {
126   ChamplainMapSourceChain *source_chain = CHAMPLAIN_MAP_SOURCE_CHAIN (map_source);
127   g_return_val_if_fail (source_chain, NULL);
128
129   ChamplainMapSourceChainPrivate *priv = GET_PRIVATE(source_chain);
130   g_return_val_if_fail (priv->stack_top, NULL);
131
132   return champlain_map_source_get_license(priv->stack_top);
133 }
134
135 static const gchar *
136 get_license_uri (ChamplainMapSource *map_source)
137 {
138   ChamplainMapSourceChain *source_chain = CHAMPLAIN_MAP_SOURCE_CHAIN (map_source);
139   g_return_val_if_fail (source_chain, NULL);
140
141   ChamplainMapSourceChainPrivate *priv = GET_PRIVATE(source_chain);
142   g_return_val_if_fail (priv->stack_top, NULL);
143
144   return champlain_map_source_get_license_uri(priv->stack_top);
145 }
146
147 static guint
148 get_min_zoom_level (ChamplainMapSource *map_source)
149 {
150   ChamplainMapSourceChain *source_chain = CHAMPLAIN_MAP_SOURCE_CHAIN (map_source);
151   g_return_val_if_fail (source_chain, 0);
152
153   ChamplainMapSourceChainPrivate *priv = GET_PRIVATE(source_chain);
154   g_return_val_if_fail (priv->stack_top, 0);
155
156   return champlain_map_source_get_min_zoom_level(priv->stack_top);
157 }
158
159 static guint
160 get_max_zoom_level (ChamplainMapSource *map_source)
161 {
162   ChamplainMapSourceChain *source_chain = CHAMPLAIN_MAP_SOURCE_CHAIN (map_source);
163   g_return_val_if_fail (source_chain, 0);
164
165   ChamplainMapSourceChainPrivate *priv = GET_PRIVATE(source_chain);
166   g_return_val_if_fail (priv->stack_top, 0);
167
168   return champlain_map_source_get_max_zoom_level(priv->stack_top);
169 }
170
171 static guint
172 get_tile_size (ChamplainMapSource *map_source)
173 {
174   ChamplainMapSourceChain *source_chain = CHAMPLAIN_MAP_SOURCE_CHAIN (map_source);
175   g_return_val_if_fail (source_chain, 0);
176
177   ChamplainMapSourceChainPrivate *priv = GET_PRIVATE(source_chain);
178   g_return_val_if_fail (priv->stack_top, 0);
179
180   return champlain_map_source_get_tile_size(priv->stack_top);
181 }
182
183 static void fill_tile (ChamplainMapSource *map_source,
184                        ChamplainTile *tile)
185 {
186   ChamplainMapSourceChain *source_chain = CHAMPLAIN_MAP_SOURCE_CHAIN (map_source);
187   g_return_if_fail (source_chain);
188
189   ChamplainMapSourceChainPrivate *priv = GET_PRIVATE(source_chain);
190   g_return_if_fail (priv->stack_top);
191
192   champlain_map_source_fill_tile(priv->stack_top, tile);
193 }
194
195 static void assign_cache_of_next_source_sequence(ChamplainMapSource *start_map_source, ChamplainTileCache *tile_cache)
196 {
197   ChamplainMapSource *map_source = start_map_source;
198   ChamplainTileSource *tile_source;
199
200   do
201     {
202       map_source = champlain_map_source_get_next_source(map_source);
203     }
204   while (CHAMPLAIN_IS_TILE_CACHE(map_source));
205
206   tile_source = CHAMPLAIN_TILE_SOURCE(map_source);
207   while (tile_source)
208     {
209       champlain_tile_source_set_cache(tile_source, tile_cache);
210       map_source = champlain_map_source_get_next_source(map_source);
211       tile_source = CHAMPLAIN_TILE_SOURCE(map_source);
212     }
213 }
214
215 static
216 void reload_tiles_cb(ChamplainMapSource *map_source, ChamplainMapSourceChain *source_chain)
217 {
218   /* propagate the signal from the chain that is inside champlain_map_source_chain */
219   g_signal_emit_by_name (source_chain, "reload-tiles", NULL);
220 }
221
222 void champlain_map_source_chain_push(ChamplainMapSourceChain *source_chain, ChamplainMapSource *map_source)
223 {
224   ChamplainMapSourceChainPrivate *priv = GET_PRIVATE(source_chain);
225   gboolean is_cache = FALSE;
226
227   if (CHAMPLAIN_IS_TILE_CACHE(map_source))
228     is_cache = TRUE;
229   else
230     g_return_if_fail (CHAMPLAIN_IS_TILE_SOURCE(map_source));
231
232   g_object_ref_sink(map_source);
233
234   if (!priv->stack_top)
235     {
236       /* tile source has to be last */
237       g_return_if_fail(!is_cache);
238       priv->stack_top = map_source;
239     }
240   else
241     {
242       if (g_signal_handler_is_connected (priv->stack_top, priv->sig_handler_id))
243         g_signal_handler_disconnect (priv->stack_top, priv->sig_handler_id);
244
245       champlain_map_source_set_next_source(map_source, priv->stack_top);
246       priv->stack_top = map_source;
247
248       if (is_cache)
249         {
250           ChamplainTileCache *tile_cache = CHAMPLAIN_TILE_CACHE(map_source);
251           assign_cache_of_next_source_sequence(priv->stack_top, tile_cache);
252         }
253     }
254
255   priv->sig_handler_id = g_signal_connect (priv->stack_top, "reload-tiles",
256                          G_CALLBACK (reload_tiles_cb), source_chain);
257 }
258
259 void champlain_map_source_chain_pop_map_source(ChamplainMapSourceChain *source_chain)
260 {
261   ChamplainMapSourceChainPrivate *priv = GET_PRIVATE(source_chain);
262   ChamplainMapSource *old_stack_top = priv->stack_top;
263
264   g_return_if_fail(priv->stack_top);
265
266   if (g_signal_handler_is_connected (priv->stack_top, priv->sig_handler_id))
267     g_signal_handler_disconnect (priv->stack_top, priv->sig_handler_id);
268
269   if (CHAMPLAIN_IS_TILE_CACHE(priv->stack_top))
270     {
271       ChamplainMapSource *map_source = champlain_map_source_get_next_source(priv->stack_top);
272       ChamplainTileCache *tile_cache = NULL;
273
274       if (CHAMPLAIN_IS_TILE_CACHE(map_source))
275         tile_cache = CHAMPLAIN_TILE_CACHE(map_source);
276
277       assign_cache_of_next_source_sequence(priv->stack_top, tile_cache);
278     }
279
280   priv->stack_top = champlain_map_source_get_next_source(priv->stack_top);
281   if (priv->stack_top)
282     {
283       priv->sig_handler_id = g_signal_connect (priv->stack_top, "reload-tiles",
284                              G_CALLBACK (reload_tiles_cb), source_chain);
285     }
286
287   g_object_unref(old_stack_top);
288 }