]>
Commit | Line | Data |
---|---|---|
50a14534 EB |
1 | /* |
2 | * viking -- GPS Data and Topo Analyzer, Explorer, and Manager | |
3 | * | |
4 | * Copyright (C) 2005, Evan Battaglia <viking@greentorch.org> | |
5 | * UTM multi-zone stuff by Kit Transue <notlostyet@didactek.com> | |
cdcaf41c | 6 | * Dynamic map type by Guilhem Bonnefille <guilhem.bonnefille@gmail.com> |
50a14534 EB |
7 | * |
8 | * This program is free software; you can redistribute it and/or modify | |
9 | * it under the terms of the GNU General Public License as published by | |
10 | * the Free Software Foundation; either version 2 of the License, or | |
11 | * (at your option) any later version. | |
12 | * | |
13 | * This program is distributed in the hope that it will be useful, | |
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
16 | * GNU General Public License for more details. | |
17 | * | |
18 | * You should have received a copy of the GNU General Public License | |
19 | * along with this program; if not, write to the Free Software | |
20 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |
21 | * | |
22 | */ | |
23 | ||
4c77d5e0 GB |
24 | #ifdef HAVE_CONFIG_H |
25 | #include "config.h" | |
26 | #endif | |
27 | ||
50a14534 EB |
28 | #define MAX_SHRINKFACTOR 8.0000001 /* zoom 1 viewing 8-tiles */ |
29 | #define MIN_SHRINKFACTOR 0.0312499 /* zoom 32 viewing 1-tiles */ | |
30 | ||
732d1e25 EB |
31 | #define REAL_MIN_SHRINKFACTOR 0.0039062499 /* if shrinkfactor is between MAX and REAL_MAX, will only check for existence */ |
32 | ||
50a14534 EB |
33 | #include <gtk/gtk.h> |
34 | #include <gdk-pixbuf/gdk-pixdata.h> | |
45acf79e MA |
35 | #include <glib.h> |
36 | #include <glib/gstdio.h> | |
4c77d5e0 GB |
37 | #include <glib/gi18n.h> |
38 | ||
8c00358d | 39 | #ifdef HAVE_STRING_H |
50a14534 | 40 | #include <string.h> |
8c00358d GB |
41 | #endif |
42 | #ifdef HAVE_MATH_H | |
50a14534 | 43 | #include <math.h> |
8c00358d GB |
44 | #endif |
45 | ||
50a14534 EB |
46 | #include "globals.h" |
47 | #include "coords.h" | |
48 | #include "vikcoord.h" | |
49 | #include "viktreeview.h" | |
50 | #include "vikviewport.h" | |
51 | #include "viklayer.h" | |
52 | #include "vikmapslayer.h" | |
50a14534 | 53 | |
45acf79e | 54 | #ifdef HAVE_UNISTD_H |
50a14534 | 55 | #include <unistd.h> |
45acf79e | 56 | #endif |
50a14534 EB |
57 | |
58 | #include "mapcache.h" | |
59 | /* only for dialog.h -- ugh */ | |
60 | #include "vikwaypoint.h" | |
61 | #include "dialog.h" | |
62 | ||
63 | #include "vikstatus.h" | |
64 | #include "background.h" | |
65 | ||
66 | #include "vikaggregatelayer.h" | |
67 | #include "viklayerspanel.h" | |
68 | ||
69 | #include "mapcoord.h" | |
70 | #include "terraserver.h" | |
50a14534 | 71 | |
bce3a7b0 EB |
72 | #include "icons/icons.h" |
73 | ||
50a14534 EB |
74 | /****** MAP TYPES ******/ |
75 | ||
cdcaf41c QT |
76 | static GList *__map_types = NULL; |
77 | ||
78 | #define NUM_MAP_TYPES g_list_length(__map_types) | |
50a14534 | 79 | |
cdcaf41c QT |
80 | /* List of label for each map type */ |
81 | static GList *params_maptypes = NULL; | |
82 | ||
83 | /* Corresponding IDS. (Cf. field uniq_id in VikMapsLayer struct) */ | |
84 | static GList *params_maptypes_ids = NULL; | |
50a14534 EB |
85 | |
86 | /******** MAPZOOMS *********/ | |
87 | ||
4c77d5e0 | 88 | static gchar *params_mapzooms[] = { N_("Use Viking Zoom Level"), "0.25", "1", "2", "4", "8", "16", "32", "64", "128", "256", "512", "1024", "USGS 10k", "USGS 24k", "USGS 25k", "USGS 50k", "USGS 100k", "USGS 200k", "USGS 250k", NULL }; |
50a14534 EB |
89 | static gdouble __mapzooms_x[] = { 0.0, 0.25, 1.0, 2.0, 4.0, 8.0, 16.0, 32.0, 64.0, 128.0, 256.0, 512.0, 1024.0, 1.016, 2.4384, 2.54, 5.08, 10.16, 20.32, 25.4 }; |
90 | static gdouble __mapzooms_y[] = { 0.0, 0.25, 1.0, 2.0, 4.0, 8.0, 16.0, 32.0, 64.0, 128.0, 256.0, 512.0, 1024.0, 1.016, 2.4384, 2.54, 5.08, 10.16, 20.32, 25.4 }; | |
91 | ||
d756fb5c | 92 | #define NUM_MAPZOOMS (sizeof(params_mapzooms)/sizeof(params_mapzooms[0]) - 1) |
50a14534 EB |
93 | |
94 | /**************************/ | |
95 | ||
96 | ||
07059501 | 97 | static void maps_layer_post_read (VikLayer *vl, VikViewport *vp, gboolean from_file); |
911400b5 AF |
98 | static void maps_layer_marshall( VikMapsLayer *vml, guint8 **data, gint *len ); |
99 | static VikMapsLayer *maps_layer_unmarshall( guint8 *data, gint len, VikViewport *vvp ); | |
50a14534 EB |
100 | static gboolean maps_layer_set_param ( VikMapsLayer *vml, guint16 id, VikLayerParamData data, VikViewport *vvp ); |
101 | static VikLayerParamData maps_layer_get_param ( VikMapsLayer *vml, guint16 id ); | |
102 | static void maps_layer_draw ( VikMapsLayer *vml, VikViewport *vvp ); | |
103 | static VikMapsLayer *maps_layer_new ( VikViewport *vvp ); | |
104 | static void maps_layer_free ( VikMapsLayer *vml ); | |
105 | static gboolean maps_layer_download_release ( VikMapsLayer *vml, GdkEventButton *event, VikViewport *vvp ); | |
106 | static gboolean maps_layer_download_click ( VikMapsLayer *vml, GdkEventButton *event, VikViewport *vvp ); | |
941aa6e9 | 107 | static gpointer maps_layer_download_create ( VikWindow *vw, VikViewport *vvp ); |
50a14534 EB |
108 | static void maps_layer_set_cache_dir ( VikMapsLayer *vml, const gchar *dir ); |
109 | static void start_download_thread ( VikMapsLayer *vml, VikViewport *vvp, const VikCoord *ul, const VikCoord *br, gint redownload ); | |
110 | static void maps_layer_add_menu_items ( VikMapsLayer *vml, GtkMenu *menu, VikLayersPanel *vlp ); | |
111 | ||
112 | ||
113 | static VikLayerParamScale params_scales[] = { | |
114 | /* min, max, step, digits (decimal places) */ | |
115 | { 0, 255, 3, 0 }, /* alpha */ | |
116 | }; | |
117 | ||
118 | VikLayerParam maps_layer_params[] = { | |
4c77d5e0 GB |
119 | { "mode", VIK_LAYER_PARAM_UINT, VIK_LAYER_GROUP_NONE, N_("Map Type:"), VIK_LAYER_WIDGET_RADIOGROUP, NULL, NULL }, |
120 | { "directory", VIK_LAYER_PARAM_STRING, VIK_LAYER_GROUP_NONE, N_("Maps Directory (Optional):"), VIK_LAYER_WIDGET_FILEENTRY }, | |
121 | { "alpha", VIK_LAYER_PARAM_UINT, VIK_LAYER_GROUP_NONE, N_("Alpha:"), VIK_LAYER_WIDGET_HSCALE, params_scales }, | |
122 | { "autodownload", VIK_LAYER_PARAM_BOOLEAN, VIK_LAYER_GROUP_NONE, N_("Autodownload maps:"), VIK_LAYER_WIDGET_CHECKBUTTON }, | |
123 | { "mapzoom", VIK_LAYER_PARAM_UINT, VIK_LAYER_GROUP_NONE, N_("Zoom Level:"), VIK_LAYER_WIDGET_COMBOBOX, params_mapzooms }, | |
50a14534 EB |
124 | }; |
125 | ||
126 | enum { PARAM_MAPTYPE=0, PARAM_CACHE_DIR, PARAM_ALPHA, PARAM_AUTODOWNLOAD, PARAM_MAPZOOM, NUM_PARAMS }; | |
127 | ||
128 | static VikToolInterface maps_tools[] = { | |
4c77d5e0 | 129 | { N_("Maps Download"), (VikToolConstructorFunc) maps_layer_download_create, NULL, NULL, NULL, |
bce3a7b0 | 130 | (VikToolMouseFunc) maps_layer_download_click, NULL, (VikToolMouseFunc) maps_layer_download_release, |
5bfafde9 | 131 | (VikToolKeyFunc) NULL, GDK_CURSOR_IS_PIXMAP, &cursor_mapdl_pixbuf }, |
50a14534 EB |
132 | }; |
133 | ||
134 | VikLayerInterface vik_maps_layer_interface = { | |
4c77d5e0 | 135 | N_("Map"), |
5bfafde9 | 136 | &vikmapslayer_pixbuf, |
50a14534 EB |
137 | |
138 | maps_tools, | |
139 | sizeof(maps_tools) / sizeof(maps_tools[0]), | |
140 | ||
141 | maps_layer_params, | |
142 | NUM_PARAMS, | |
143 | NULL, | |
144 | 0, | |
145 | ||
5a4a28bf QT |
146 | VIK_MENU_ITEM_ALL, |
147 | ||
50a14534 EB |
148 | (VikLayerFuncCreate) maps_layer_new, |
149 | (VikLayerFuncRealize) NULL, | |
94933cb8 | 150 | maps_layer_post_read, |
50a14534 EB |
151 | (VikLayerFuncFree) maps_layer_free, |
152 | ||
153 | (VikLayerFuncProperties) NULL, | |
154 | (VikLayerFuncDraw) maps_layer_draw, | |
155 | (VikLayerFuncChangeCoordMode) NULL, | |
156 | ||
20c7a3a0 QT |
157 | (VikLayerFuncSetMenuItemsSelection) NULL, |
158 | (VikLayerFuncGetMenuItemsSelection) NULL, | |
159 | ||
50a14534 EB |
160 | (VikLayerFuncAddMenuItems) maps_layer_add_menu_items, |
161 | (VikLayerFuncSublayerAddMenuItems) NULL, | |
162 | ||
163 | (VikLayerFuncSublayerRenameRequest) NULL, | |
164 | (VikLayerFuncSublayerToggleVisible) NULL, | |
165 | ||
911400b5 AF |
166 | (VikLayerFuncMarshall) maps_layer_marshall, |
167 | (VikLayerFuncUnmarshall) maps_layer_unmarshall, | |
50a14534 EB |
168 | |
169 | (VikLayerFuncSetParam) maps_layer_set_param, | |
170 | (VikLayerFuncGetParam) maps_layer_get_param, | |
171 | ||
172 | (VikLayerFuncReadFileData) NULL, | |
173 | (VikLayerFuncWriteFileData) NULL, | |
174 | ||
33534cd8 | 175 | (VikLayerFuncDeleteItem) NULL, |
50a14534 EB |
176 | (VikLayerFuncCopyItem) NULL, |
177 | (VikLayerFuncPasteItem) NULL, | |
178 | (VikLayerFuncFreeCopiedItem) NULL, | |
70a23263 | 179 | (VikLayerFuncDragDropRequest) NULL, |
50a14534 EB |
180 | }; |
181 | ||
182 | struct _VikMapsLayer { | |
183 | VikLayer vl; | |
184 | guint maptype; | |
185 | gchar *cache_dir; | |
186 | guint8 alpha; | |
187 | guint mapzoom_id; | |
188 | gdouble xmapzoom, ymapzoom; | |
189 | ||
190 | gboolean autodownload; | |
10ca2bfe QT |
191 | VikCoord *last_center; |
192 | gdouble last_xmpp; | |
193 | gdouble last_ympp; | |
50a14534 EB |
194 | |
195 | gint dl_tool_x, dl_tool_y; | |
196 | ||
197 | GtkMenu *dl_right_click_menu; | |
198 | VikCoord redownload_ul, redownload_br; /* right click menu only */ | |
199 | VikViewport *redownload_vvp; | |
200 | }; | |
201 | ||
a0b59f2f | 202 | enum { REDOWNLOAD_NONE = 0, REDOWNLOAD_BAD, REDOWNLOAD_ALL, DOWNLOAD_OR_REFRESH }; |
50a14534 EB |
203 | |
204 | ||
cdcaf41c QT |
205 | /****************************************/ |
206 | /******** MAPS LAYER TYPES **************/ | |
207 | /****************************************/ | |
208 | ||
209 | void maps_layer_register_type ( const char *label, guint id, VikMapsLayer_MapType *map_type ) | |
210 | { | |
211 | g_assert(label != NULL); | |
212 | g_assert(map_type != NULL); | |
213 | g_assert(id == map_type->uniq_id); | |
214 | ||
215 | /* Add the label */ | |
216 | params_maptypes = g_list_append(params_maptypes, g_strdup(label)); | |
217 | ||
218 | /* Add the id */ | |
dc2c040e | 219 | params_maptypes_ids = g_list_append(params_maptypes_ids, GUINT_TO_POINTER (id)); |
cdcaf41c QT |
220 | |
221 | /* We have to clone */ | |
222 | VikMapsLayer_MapType *clone = g_memdup(map_type, sizeof(VikMapsLayer_MapType)); | |
223 | /* Register the clone in the list */ | |
224 | __map_types = g_list_append(__map_types, clone); | |
225 | ||
226 | /* Hack | |
227 | We have to ensure the mode LayerParam reference the up-to-date | |
228 | GLists. | |
229 | */ | |
230 | /* | |
231 | memcpy(&maps_layer_params[0].widget_data, ¶ms_maptypes, sizeof(gpointer)); | |
232 | memcpy(&maps_layer_params[0].extra_widget_data, ¶ms_maptypes_ids, sizeof(gpointer)); | |
233 | */ | |
234 | maps_layer_params[0].widget_data = params_maptypes; | |
235 | maps_layer_params[0].extra_widget_data = params_maptypes_ids; | |
236 | } | |
237 | ||
238 | #define MAPS_LAYER_NTH_LABEL(n) ((gchar*)g_list_nth_data(params_maptypes, (n))) | |
239 | #define MAPS_LAYER_NTH_ID(n) ((guint)g_list_nth_data(params_maptypes_ids, (n))) | |
240 | #define MAPS_LAYER_NTH_TYPE(n) ((VikMapsLayer_MapType*)g_list_nth_data(__map_types, (n))) | |
241 | ||
7114e879 QT |
242 | gint vik_maps_layer_get_map_type(VikMapsLayer *vml) |
243 | { | |
244 | return(vml->maptype); | |
245 | } | |
246 | ||
247 | gchar *vik_maps_layer_get_map_label(VikMapsLayer *vml) | |
248 | { | |
249 | return(g_strdup(MAPS_LAYER_NTH_LABEL(vml->maptype))); | |
250 | } | |
251 | ||
50a14534 EB |
252 | /****************************************/ |
253 | /******** CACHE DIR STUFF ***************/ | |
254 | /****************************************/ | |
255 | ||
3d9454e6 | 256 | #define DIRSTRUCTURE "%st%ds%dz%d" G_DIR_SEPARATOR_S "%d" G_DIR_SEPARATOR_S "%d" |
6a27c1bc MA |
257 | #define MAPS_CACHE_DIR maps_layer_default_dir() |
258 | ||
50a14534 | 259 | #ifdef WINDOWS |
6a27c1bc MA |
260 | #include <io.h> |
261 | #define GLOBAL_MAPS_DIR "C:\\VIKING-MAPS\\" | |
262 | #define LOCAL_MAPS_DIR "VIKING-MAPS" | |
50a14534 | 263 | #else /* POSIX */ |
50a14534 | 264 | #include <stdlib.h> |
50a14534 | 265 | #define GLOBAL_MAPS_DIR "/var/cache/maps/" |
6a27c1bc MA |
266 | #define LOCAL_MAPS_DIR ".viking-maps" |
267 | #endif | |
50a14534 | 268 | |
0c1044e9 | 269 | gchar *maps_layer_default_dir () |
50a14534 | 270 | { |
3d9454e6 GB |
271 | static gchar *defaultdir = NULL; |
272 | if ( ! defaultdir ) | |
50a14534 EB |
273 | { |
274 | /* Thanks to Mike Davison for the $VIKING_MAPS usage */ | |
3d9454e6 GB |
275 | const gchar *mapdir = g_getenv("VIKING_MAPS"); |
276 | if ( mapdir ) { | |
277 | defaultdir = g_strdup ( mapdir ); | |
45acf79e | 278 | } else if ( g_access ( GLOBAL_MAPS_DIR, W_OK ) == 0 ) { |
3d9454e6 | 279 | defaultdir = g_strdup ( GLOBAL_MAPS_DIR ); |
50a14534 | 280 | } else { |
6a27c1bc | 281 | const gchar *home = g_get_home_dir(); |
45acf79e | 282 | if (!home || g_access(home, W_OK)) |
3d9454e6 GB |
283 | home = g_get_home_dir (); |
284 | if ( home ) | |
6a27c1bc | 285 | defaultdir = g_build_filename ( home, LOCAL_MAPS_DIR, NULL ); |
50a14534 | 286 | else |
6a27c1bc | 287 | defaultdir = g_strdup ( LOCAL_MAPS_DIR ); |
50a14534 | 288 | } |
3d9454e6 GB |
289 | if (defaultdir && (defaultdir[strlen(defaultdir)-1] != G_DIR_SEPARATOR)) |
290 | { | |
291 | /* Add the separator at the end */ | |
292 | gchar *tmp = defaultdir; | |
293 | defaultdir = g_strconcat(tmp, G_DIR_SEPARATOR_S, NULL); | |
294 | g_free(tmp); | |
295 | } | |
296 | g_debug("%s: defaultdir=%s", __FUNCTION__, defaultdir); | |
50a14534 EB |
297 | } |
298 | return defaultdir; | |
299 | } | |
300 | ||
50a14534 EB |
301 | static void maps_layer_mkdir_if_default_dir ( VikMapsLayer *vml ) |
302 | { | |
45acf79e | 303 | if ( vml->cache_dir && strcmp ( vml->cache_dir, MAPS_CACHE_DIR ) == 0 && g_file_test ( vml->cache_dir, G_FILE_TEST_EXISTS ) == FALSE ) |
50a14534 | 304 | { |
f83131b9 | 305 | g_mkdir ( vml->cache_dir, 0777 ); |
50a14534 EB |
306 | } |
307 | } | |
308 | ||
309 | static void maps_layer_set_cache_dir ( VikMapsLayer *vml, const gchar *dir ) | |
310 | { | |
311 | guint len; | |
312 | g_assert ( vml != NULL); | |
e65028db GB |
313 | g_free ( vml->cache_dir ); |
314 | vml->cache_dir = NULL; | |
50a14534 EB |
315 | |
316 | if ( dir == NULL || dir[0] == '\0' ) | |
317 | vml->cache_dir = g_strdup ( MAPS_CACHE_DIR ); | |
318 | else | |
319 | { | |
320 | len = strlen(dir); | |
3d9454e6 | 321 | if ( dir[len-1] != G_DIR_SEPARATOR ) |
50a14534 EB |
322 | { |
323 | vml->cache_dir = g_malloc ( len+2 ); | |
324 | strncpy ( vml->cache_dir, dir, len ); | |
3d9454e6 | 325 | vml->cache_dir[len] = G_DIR_SEPARATOR; |
50a14534 EB |
326 | vml->cache_dir[len+1] = '\0'; |
327 | } | |
328 | else | |
329 | vml->cache_dir = g_strdup ( dir ); | |
330 | } | |
331 | maps_layer_mkdir_if_default_dir ( vml ); | |
332 | } | |
333 | ||
334 | /****************************************/ | |
335 | /******** GOBJECT STUFF *****************/ | |
336 | /****************************************/ | |
337 | ||
338 | GType vik_maps_layer_get_type () | |
339 | { | |
340 | static GType vml_type = 0; | |
341 | ||
342 | if (!vml_type) | |
343 | { | |
344 | static const GTypeInfo vml_info = | |
345 | { | |
346 | sizeof (VikMapsLayerClass), | |
347 | NULL, /* base_init */ | |
348 | NULL, /* base_finalize */ | |
349 | NULL, /* class init */ | |
350 | NULL, /* class_finalize */ | |
351 | NULL, /* class_data */ | |
352 | sizeof (VikMapsLayer), | |
353 | 0, | |
354 | NULL /* instance init */ | |
355 | }; | |
356 | vml_type = g_type_register_static ( VIK_LAYER_TYPE, "VikMapsLayer", &vml_info, 0 ); | |
357 | } | |
358 | ||
359 | return vml_type; | |
360 | } | |
361 | ||
362 | /****************************************/ | |
363 | /************** PARAMETERS **************/ | |
364 | /****************************************/ | |
365 | ||
366 | static guint map_index_to_uniq_id (guint8 index) | |
367 | { | |
368 | g_assert ( index < NUM_MAP_TYPES ); | |
cdcaf41c | 369 | return MAPS_LAYER_NTH_TYPE(index)->uniq_id; |
50a14534 EB |
370 | } |
371 | ||
372 | static guint map_uniq_id_to_index ( guint uniq_id ) | |
373 | { | |
374 | gint i; | |
375 | for ( i = 0; i < NUM_MAP_TYPES; i++ ) | |
cdcaf41c | 376 | if ( MAPS_LAYER_NTH_TYPE(i)->uniq_id == uniq_id ) |
50a14534 EB |
377 | return i; |
378 | return NUM_MAP_TYPES; /* no such thing */ | |
379 | } | |
380 | ||
381 | static gboolean maps_layer_set_param ( VikMapsLayer *vml, guint16 id, VikLayerParamData data, VikViewport *vvp ) | |
382 | { | |
383 | switch ( id ) | |
384 | { | |
385 | case PARAM_CACHE_DIR: maps_layer_set_cache_dir ( vml, data.s ); break; | |
386 | case PARAM_MAPTYPE: { | |
387 | gint maptype = map_uniq_id_to_index(data.u); | |
4c77d5e0 | 388 | if ( maptype == NUM_MAP_TYPES ) g_warning(_("Unknown map type")); |
50a14534 EB |
389 | else vml->maptype = maptype; |
390 | break; | |
391 | } | |
392 | case PARAM_ALPHA: if ( data.u <= 255 ) vml->alpha = data.u; break; | |
393 | case PARAM_AUTODOWNLOAD: vml->autodownload = data.b; break; | |
394 | case PARAM_MAPZOOM: if ( data.u < NUM_MAPZOOMS ) { | |
395 | vml->mapzoom_id = data.u; | |
396 | vml->xmapzoom = __mapzooms_x [data.u]; | |
397 | vml->ymapzoom = __mapzooms_y [data.u]; | |
4c77d5e0 | 398 | }else g_warning (_("Unknown Map Zoom")); break; |
50a14534 EB |
399 | } |
400 | return TRUE; | |
401 | } | |
402 | ||
403 | static VikLayerParamData maps_layer_get_param ( VikMapsLayer *vml, guint16 id ) | |
404 | { | |
405 | VikLayerParamData rv; | |
406 | switch ( id ) | |
407 | { | |
408 | case PARAM_CACHE_DIR: rv.s = (vml->cache_dir && strcmp(vml->cache_dir, MAPS_CACHE_DIR) != 0) ? vml->cache_dir : ""; break; | |
409 | case PARAM_MAPTYPE: rv.u = map_index_to_uniq_id ( vml->maptype ); break; | |
410 | case PARAM_ALPHA: rv.u = vml->alpha; break; | |
411 | case PARAM_AUTODOWNLOAD: rv.u = vml->autodownload; break; | |
412 | case PARAM_MAPZOOM: rv.u = vml->mapzoom_id; break; | |
413 | } | |
414 | return rv; | |
415 | } | |
416 | ||
417 | /****************************************/ | |
418 | /****** CREATING, COPYING, FREEING ******/ | |
419 | /****************************************/ | |
420 | ||
421 | static VikMapsLayer *maps_layer_new ( VikViewport *vvp ) | |
422 | { | |
36c78d6d | 423 | int idx; |
50a14534 EB |
424 | VikMapsLayer *vml = VIK_MAPS_LAYER ( g_object_new ( VIK_MAPS_LAYER_TYPE, NULL ) ); |
425 | vik_layer_init ( VIK_LAYER(vml), VIK_LAYER_MAPS ); | |
36c78d6d QT |
426 | idx = map_uniq_id_to_index(7); /* 7 is id for google maps */ |
427 | vml->maptype = (idx < NUM_MAP_TYPES) ? idx : 0; | |
50a14534 EB |
428 | vml->alpha = 255; |
429 | vml->mapzoom_id = 0; | |
430 | vml->dl_tool_x = vml->dl_tool_y = -1; | |
431 | maps_layer_set_cache_dir ( vml, NULL ); | |
432 | vml->autodownload = FALSE; | |
10ca2bfe QT |
433 | vml->last_center = NULL; |
434 | vml->last_xmpp = 0.0; | |
435 | vml->last_ympp = 0.0; | |
50a14534 EB |
436 | |
437 | vml->dl_right_click_menu = NULL; | |
438 | ||
439 | return vml; | |
440 | } | |
441 | ||
442 | static void maps_layer_free ( VikMapsLayer *vml ) | |
443 | { | |
e65028db GB |
444 | g_free ( vml->cache_dir ); |
445 | vml->cache_dir = NULL; | |
50a14534 EB |
446 | if ( vml->dl_right_click_menu ) |
447 | gtk_object_sink ( GTK_OBJECT(vml->dl_right_click_menu) ); | |
e65028db GB |
448 | g_free(vml->last_center); |
449 | vml->last_center = NULL; | |
50a14534 EB |
450 | } |
451 | ||
07059501 | 452 | static void maps_layer_post_read (VikLayer *vl, VikViewport *vp, gboolean from_file) |
dc5758d3 | 453 | { |
07059501 GB |
454 | if (from_file != TRUE) |
455 | { | |
456 | /* If this method is not called in file reading context | |
457 | * it is called in GUI context. | |
458 | * So, we can check if we have to inform the user about inconsistency */ | |
459 | VikViewportDrawMode vp_drawmode; | |
460 | VikMapsLayer *vml = VIK_MAPS_LAYER(vl); | |
461 | VikMapsLayer_MapType *map_type = NULL; | |
dc5758d3 | 462 | |
07059501 GB |
463 | vp_drawmode = vik_viewport_get_drawmode ( VIK_VIEWPORT(vp) ); |
464 | map_type = MAPS_LAYER_NTH_TYPE(vml->maptype); | |
465 | if (map_type->drawmode != vp_drawmode) { | |
466 | const gchar *drawmode_name = vik_viewport_get_drawmode_name (VIK_VIEWPORT(vp), map_type->drawmode); | |
4c77d5e0 | 467 | gchar *msg = g_strdup_printf(_("New map cannot be displayed in the current drawmode.\nSelect \"%s\" from View menu to view it."), drawmode_name); |
07059501 GB |
468 | a_dialog_warning_msg ( VIK_GTK_WINDOW_FROM_LAYER(vml), msg ); |
469 | g_free(msg); | |
470 | } | |
dc5758d3 GB |
471 | } |
472 | } | |
473 | ||
911400b5 AF |
474 | static void maps_layer_marshall( VikMapsLayer *vml, guint8 **data, gint *len ) |
475 | { | |
476 | vik_layer_marshall_params ( VIK_LAYER(vml), data, len ); | |
477 | } | |
478 | ||
479 | static VikMapsLayer *maps_layer_unmarshall( guint8 *data, gint len, VikViewport *vvp ) | |
480 | { | |
481 | VikMapsLayer *rv = maps_layer_new ( vvp ); | |
482 | vik_layer_unmarshall_params ( VIK_LAYER(rv), data, len, vvp ); | |
483 | return rv; | |
484 | } | |
485 | ||
50a14534 EB |
486 | /*********************/ |
487 | /****** DRAWING ******/ | |
488 | /*********************/ | |
489 | ||
490 | static GdkPixbuf *pixbuf_set_alpha ( GdkPixbuf *pixbuf, guint8 alpha ) | |
491 | { | |
492 | guchar *pixels; | |
493 | gint width, height, iii, jjj; | |
494 | ||
495 | if ( ! gdk_pixbuf_get_has_alpha ( pixbuf ) ) | |
496 | { | |
497 | GdkPixbuf *tmp = gdk_pixbuf_add_alpha(pixbuf,FALSE,0,0,0); | |
498 | g_object_unref(G_OBJECT(pixbuf)); | |
499 | pixbuf = tmp; | |
500 | } | |
501 | ||
502 | pixels = gdk_pixbuf_get_pixels(pixbuf); | |
503 | width = gdk_pixbuf_get_width(pixbuf); | |
504 | height = gdk_pixbuf_get_height(pixbuf); | |
505 | ||
506 | /* r,g,b,a,r,g,b,a.... */ | |
507 | for (iii = 0; iii < width; iii++) for (jjj = 0; jjj < height; jjj++) | |
508 | { | |
509 | pixels += 3; | |
510 | *pixels++ = alpha; | |
511 | } | |
512 | return pixbuf; | |
513 | } | |
514 | ||
515 | static GdkPixbuf *pixbuf_shrink ( GdkPixbuf *pixbuf, gdouble xshrinkfactor, gdouble yshrinkfactor ) | |
516 | { | |
517 | GdkPixbuf *tmp; | |
518 | guint16 width = gdk_pixbuf_get_width(pixbuf), height = gdk_pixbuf_get_height(pixbuf); | |
519 | tmp = gdk_pixbuf_scale_simple(pixbuf, ceil(width * xshrinkfactor), ceil(height * yshrinkfactor), GDK_INTERP_BILINEAR); | |
520 | g_object_unref ( G_OBJECT(pixbuf) ); | |
521 | return tmp; | |
522 | } | |
523 | ||
524 | static GdkPixbuf *get_pixbuf( VikMapsLayer *vml, gint mode, MapCoord *mapcoord, gchar *filename_buf, gint buf_len, gdouble xshrinkfactor, gdouble yshrinkfactor ) | |
525 | { | |
526 | GdkPixbuf *pixbuf; | |
527 | ||
528 | /* get the thing */ | |
529 | pixbuf = a_mapcache_get ( mapcoord->x, mapcoord->y, mapcoord->z, | |
530 | mode, mapcoord->scale, vml->alpha, xshrinkfactor, yshrinkfactor ); | |
531 | ||
532 | if ( ! pixbuf ) { | |
533 | g_snprintf ( filename_buf, buf_len, DIRSTRUCTURE, | |
534 | vml->cache_dir, mode, | |
535 | mapcoord->scale, mapcoord->z, mapcoord->x, mapcoord->y ); | |
45acf79e | 536 | if ( g_file_test ( filename_buf, G_FILE_TEST_EXISTS ) == TRUE) { |
50a14534 EB |
537 | { |
538 | GError *gx = NULL; | |
539 | pixbuf = gdk_pixbuf_new_from_file ( filename_buf, &gx ); | |
540 | ||
541 | if (gx) | |
542 | { | |
543 | if ( gx->domain != GDK_PIXBUF_ERROR || gx->code != GDK_PIXBUF_ERROR_CORRUPT_IMAGE ) | |
4c77d5e0 | 544 | g_warning ( _("Couldn't open image file: %s"), gx->message ); |
50a14534 EB |
545 | |
546 | g_error_free ( gx ); | |
547 | if ( pixbuf ) | |
548 | g_object_unref ( G_OBJECT(pixbuf) ); | |
549 | pixbuf = NULL; | |
550 | } else { | |
551 | if ( vml->alpha < 255 ) | |
552 | pixbuf = pixbuf_set_alpha ( pixbuf, vml->alpha ); | |
553 | if ( xshrinkfactor != 1.0 || yshrinkfactor != 1.0 ) | |
554 | pixbuf = pixbuf_shrink ( pixbuf, xshrinkfactor, yshrinkfactor ); | |
555 | ||
556 | a_mapcache_add ( pixbuf, mapcoord->x, mapcoord->y, | |
cdcaf41c | 557 | mapcoord->z, MAPS_LAYER_NTH_TYPE(vml->maptype)->uniq_id, |
50a14534 EB |
558 | mapcoord->scale, vml->alpha, xshrinkfactor, yshrinkfactor ); |
559 | } | |
560 | } | |
561 | } | |
562 | } | |
563 | return pixbuf; | |
564 | } | |
565 | ||
10ca2bfe QT |
566 | gboolean should_start_autodownload(VikMapsLayer *vml, VikViewport *vvp) |
567 | { | |
568 | const VikCoord *center = vik_viewport_get_center ( vvp ); | |
569 | ||
570 | if (vml->last_center == NULL) { | |
571 | VikCoord *new_center = g_malloc(sizeof(VikCoord)); | |
572 | *new_center = *center; | |
573 | vml->last_center = new_center; | |
574 | vml->last_xmpp = vik_viewport_get_xmpp(vvp); | |
575 | vml->last_ympp = vik_viewport_get_ympp(vvp); | |
576 | return TRUE; | |
577 | } | |
578 | ||
579 | /* TODO: perhaps vik_coord_diff() */ | |
580 | if (vik_coord_equals(vml->last_center, center) | |
581 | && (vml->last_xmpp == vik_viewport_get_xmpp(vvp)) | |
582 | && (vml->last_ympp == vik_viewport_get_ympp(vvp))) | |
583 | return FALSE; | |
584 | ||
585 | *(vml->last_center) = *center; | |
586 | vml->last_xmpp = vik_viewport_get_xmpp(vvp); | |
587 | vml->last_ympp = vik_viewport_get_ympp(vvp); | |
588 | return TRUE; | |
589 | } | |
590 | ||
50a14534 EB |
591 | static void maps_layer_draw_section ( VikMapsLayer *vml, VikViewport *vvp, VikCoord *ul, VikCoord *br ) |
592 | { | |
593 | MapCoord ulm, brm; | |
594 | gdouble xzoom = vik_viewport_get_xmpp ( vvp ); | |
595 | gdouble yzoom = vik_viewport_get_ympp ( vvp ); | |
596 | gdouble xshrinkfactor = 1.0, yshrinkfactor = 1.0; | |
732d1e25 | 597 | gdouble existence_only = FALSE; |
50a14534 EB |
598 | |
599 | if ( vml->xmapzoom && (vml->xmapzoom != xzoom || vml->ymapzoom != yzoom) ) { | |
600 | xshrinkfactor = vml->xmapzoom / xzoom; | |
601 | yshrinkfactor = vml->ymapzoom / yzoom; | |
732d1e25 EB |
602 | xzoom = vml->xmapzoom; |
603 | yzoom = vml->xmapzoom; | |
604 | if ( ! (xshrinkfactor > MIN_SHRINKFACTOR && xshrinkfactor < MAX_SHRINKFACTOR && | |
605 | yshrinkfactor > MIN_SHRINKFACTOR && yshrinkfactor < MAX_SHRINKFACTOR ) ) { | |
606 | if ( xshrinkfactor > REAL_MIN_SHRINKFACTOR && yshrinkfactor > REAL_MIN_SHRINKFACTOR ) | |
607 | existence_only = TRUE; | |
608 | else { | |
4c77d5e0 | 609 | g_warning ( _("Cowardly refusing to draw tiles or existence of tiles beyond %d zoom out factor"), (int)( 1.0/REAL_MIN_SHRINKFACTOR)); |
732d1e25 EB |
610 | return; |
611 | } | |
50a14534 EB |
612 | } |
613 | } | |
614 | ||
615 | /* coord -> ID */ | |
cdcaf41c QT |
616 | VikMapsLayer_MapType *map_type = MAPS_LAYER_NTH_TYPE(vml->maptype); |
617 | if ( map_type->coord_to_mapcoord ( ul, xzoom, yzoom, &ulm ) && | |
618 | map_type->coord_to_mapcoord ( br, xzoom, yzoom, &brm ) ) { | |
50a14534 EB |
619 | |
620 | /* loop & draw */ | |
621 | gint x, y; | |
622 | gint xmin = MIN(ulm.x, brm.x), xmax = MAX(ulm.x, brm.x); | |
623 | gint ymin = MIN(ulm.y, brm.y), ymax = MAX(ulm.y, brm.y); | |
cdcaf41c | 624 | gint mode = map_type->uniq_id; |
50a14534 EB |
625 | |
626 | VikCoord coord; | |
627 | gint xx, yy, width, height; | |
628 | GdkPixbuf *pixbuf; | |
629 | ||
630 | guint max_path_len = strlen(vml->cache_dir) + 40; | |
631 | gchar *path_buf = g_malloc ( max_path_len * sizeof(char) ); | |
632 | ||
732d1e25 | 633 | if ( (!existence_only) && vml->autodownload && should_start_autodownload(vml, vvp)) { |
214f9ac2 QT |
634 | #ifdef DEBUG |
635 | fputs(stderr, "DEBUG: Starting autodownload\n"); | |
636 | #endif | |
50a14534 | 637 | start_download_thread ( vml, vvp, ul, br, REDOWNLOAD_NONE ); |
10ca2bfe | 638 | } |
50a14534 | 639 | |
732d1e25 | 640 | if ( map_type->tilesize_x == 0 && !existence_only ) { |
50a14534 EB |
641 | for ( x = xmin; x <= xmax; x++ ) { |
642 | for ( y = ymin; y <= ymax; y++ ) { | |
643 | ulm.x = x; | |
644 | ulm.y = y; | |
645 | pixbuf = get_pixbuf ( vml, mode, &ulm, path_buf, max_path_len, xshrinkfactor, yshrinkfactor ); | |
646 | if ( pixbuf ) { | |
647 | width = gdk_pixbuf_get_width ( pixbuf ); | |
648 | height = gdk_pixbuf_get_height ( pixbuf ); | |
649 | ||
cdcaf41c | 650 | map_type->mapcoord_to_center_coord ( &ulm, &coord ); |
50a14534 EB |
651 | vik_viewport_coord_to_screen ( vvp, &coord, &xx, &yy ); |
652 | xx -= (width/2); | |
653 | yy -= (height/2); | |
654 | ||
655 | vik_viewport_draw_pixbuf ( vvp, pixbuf, 0, 0, xx, yy, width, height ); | |
656 | } | |
657 | } | |
658 | } | |
659 | } else { /* tilesize is known, don't have to keep converting coords */ | |
cdcaf41c QT |
660 | gdouble tilesize_x = map_type->tilesize_x * xshrinkfactor; |
661 | gdouble tilesize_y = map_type->tilesize_y * yshrinkfactor; | |
50a14534 EB |
662 | /* ceiled so tiles will be maximum size in the case of funky shrinkfactor */ |
663 | gint tilesize_x_ceil = ceil ( tilesize_x ); | |
664 | gint tilesize_y_ceil = ceil ( tilesize_y ); | |
665 | gint8 xinc = (ulm.x == xmin) ? 1 : -1; | |
666 | gint8 yinc = (ulm.y == ymin) ? 1 : -1; | |
667 | gdouble xx, yy; gint xx_tmp, yy_tmp; | |
668 | gint base_yy, xend, yend; | |
732d1e25 EB |
669 | |
670 | GdkGC *black_gc = GTK_WIDGET(vvp)->style->black_gc; | |
671 | ||
50a14534 EB |
672 | xend = (xinc == 1) ? (xmax+1) : (xmin-1); |
673 | yend = (yinc == 1) ? (ymax+1) : (ymin-1); | |
674 | ||
cdcaf41c | 675 | map_type->mapcoord_to_center_coord ( &ulm, &coord ); |
50a14534 EB |
676 | vik_viewport_coord_to_screen ( vvp, &coord, &xx_tmp, &yy_tmp ); |
677 | xx = xx_tmp; yy = yy_tmp; | |
678 | /* above trick so xx,yy doubles. this is so shrinkfactors aren't rounded off | |
679 | * eg if tile size 128, shrinkfactor 0.333 */ | |
680 | xx -= (tilesize_x/2); | |
681 | base_yy = yy - (tilesize_y/2); | |
682 | ||
683 | for ( x = ((xinc == 1) ? xmin : xmax); x != xend; x+=xinc ) { | |
684 | yy = base_yy; | |
685 | for ( y = ((yinc == 1) ? ymin : ymax); y != yend; y+=yinc ) { | |
686 | ulm.x = x; | |
687 | ulm.y = y; | |
732d1e25 EB |
688 | |
689 | if ( existence_only ) { | |
690 | g_snprintf ( path_buf, max_path_len, DIRSTRUCTURE, | |
691 | vml->cache_dir, mode, | |
692 | ulm.scale, ulm.z, ulm.x, ulm.y ); | |
45acf79e | 693 | if ( g_file_test ( path_buf, G_FILE_TEST_EXISTS ) == TRUE ) { |
732d1e25 EB |
694 | vik_viewport_draw_line ( vvp, black_gc, xx+tilesize_x_ceil, yy, xx, yy+tilesize_y_ceil ); |
695 | } | |
696 | } else { | |
697 | pixbuf = get_pixbuf ( vml, mode, &ulm, path_buf, max_path_len, xshrinkfactor, yshrinkfactor ); | |
698 | if ( pixbuf ) | |
699 | vik_viewport_draw_pixbuf ( vvp, pixbuf, 0, 0, xx, yy, tilesize_x_ceil, tilesize_y_ceil ); | |
700 | } | |
50a14534 EB |
701 | |
702 | yy += tilesize_y; | |
703 | } | |
704 | xx += tilesize_x; | |
705 | } | |
706 | } | |
707 | ||
708 | g_free ( path_buf ); | |
709 | } | |
710 | } | |
711 | ||
712 | static void maps_layer_draw ( VikMapsLayer *vml, VikViewport *vvp ) | |
713 | { | |
cdcaf41c | 714 | if ( MAPS_LAYER_NTH_TYPE(vml->maptype)->drawmode == vik_viewport_get_drawmode ( vvp ) ) |
50a14534 EB |
715 | { |
716 | VikCoord ul, br; | |
717 | ||
718 | /* get corner coords */ | |
719 | if ( vik_viewport_get_coord_mode ( vvp ) == VIK_COORD_UTM && ! vik_viewport_is_one_zone ( vvp ) ) { | |
720 | /* UTM multi-zone stuff by Kit Transue */ | |
721 | gchar leftmost_zone, rightmost_zone, i; | |
722 | leftmost_zone = vik_viewport_leftmost_zone( vvp ); | |
723 | rightmost_zone = vik_viewport_rightmost_zone( vvp ); | |
724 | for ( i = leftmost_zone; i <= rightmost_zone; ++i ) { | |
725 | vik_viewport_corners_for_zonen ( vvp, i, &ul, &br ); | |
726 | maps_layer_draw_section ( vml, vvp, &ul, &br ); | |
727 | } | |
728 | } | |
729 | else { | |
730 | vik_viewport_screen_to_coord ( vvp, 0, 0, &ul ); | |
731 | vik_viewport_screen_to_coord ( vvp, vik_viewport_get_width(vvp), vik_viewport_get_height(vvp), &br ); | |
732 | ||
733 | maps_layer_draw_section ( vml, vvp, &ul, &br ); | |
734 | } | |
735 | } | |
736 | } | |
737 | ||
738 | /*************************/ | |
739 | /****** DOWNLOADING ******/ | |
740 | /*************************/ | |
741 | ||
742 | /* pass along data to thread, exists even if layer is deleted. */ | |
743 | typedef struct { | |
744 | gchar *cache_dir; | |
745 | gchar *filename_buf; | |
746 | gint x0, y0, xf, yf; | |
747 | MapCoord mapcoord; | |
748 | gint maptype; | |
749 | gint maxlen; | |
750 | gint mapstoget; | |
751 | gint redownload; | |
7114e879 | 752 | gboolean refresh_display; |
550fd035 QT |
753 | VikMapsLayer *vml; |
754 | VikViewport *vvp; | |
755 | gboolean map_layer_alive; | |
756 | GMutex *mutex; | |
50a14534 EB |
757 | } MapDownloadInfo; |
758 | ||
759 | static void mdi_free ( MapDownloadInfo *mdi ) | |
760 | { | |
550fd035 | 761 | g_mutex_free(mdi->mutex); |
50a14534 | 762 | g_free ( mdi->cache_dir ); |
e65028db | 763 | mdi->cache_dir = NULL; |
50a14534 | 764 | g_free ( mdi->filename_buf ); |
e65028db | 765 | mdi->filename_buf = NULL; |
50a14534 EB |
766 | g_free ( mdi ); |
767 | } | |
768 | ||
7bb60307 | 769 | static void weak_ref_cb(gpointer ptr, GObject * dead_vml) |
550fd035 | 770 | { |
7bb60307 | 771 | MapDownloadInfo *mdi = ptr; |
550fd035 QT |
772 | g_mutex_lock(mdi->mutex); |
773 | mdi->map_layer_alive = FALSE; | |
774 | g_mutex_unlock(mdi->mutex); | |
775 | } | |
776 | ||
50a14534 EB |
777 | static void map_download_thread ( MapDownloadInfo *mdi, gpointer threaddata ) |
778 | { | |
779 | guint donemaps = 0; | |
780 | gint x, y; | |
781 | for ( x = mdi->x0; x <= mdi->xf; x++ ) | |
782 | { | |
783 | for ( y = mdi->y0; y <= mdi->yf; y++ ) | |
784 | { | |
94493114 | 785 | gboolean remove_mem_cache = FALSE; |
84628352 | 786 | gboolean need_download = FALSE; |
50a14534 | 787 | g_snprintf ( mdi->filename_buf, mdi->maxlen, DIRSTRUCTURE, |
cdcaf41c | 788 | mdi->cache_dir, MAPS_LAYER_NTH_TYPE(mdi->maptype)->uniq_id, |
50a14534 EB |
789 | mdi->mapcoord.scale, mdi->mapcoord.z, x, y ); |
790 | ||
84628352 QT |
791 | donemaps++; |
792 | a_background_thread_progress ( threaddata, ((gdouble)donemaps) / mdi->mapstoget ); /* this also calls testcancel */ | |
793 | ||
50a14534 | 794 | if ( mdi->redownload == REDOWNLOAD_ALL) |
8c060406 | 795 | g_remove ( mdi->filename_buf ); |
093c5c71 | 796 | |
45acf79e | 797 | else if ( (mdi->redownload == REDOWNLOAD_BAD) && (g_file_test ( mdi->filename_buf, G_FILE_TEST_EXISTS ) == TRUE) ) |
50a14534 EB |
798 | { |
799 | /* see if this one is bad or what */ | |
800 | GError *gx = NULL; | |
801 | GdkPixbuf *pixbuf = gdk_pixbuf_new_from_file ( mdi->filename_buf, &gx ); | |
802 | if (gx || (!pixbuf)) | |
8c060406 | 803 | g_remove ( mdi->filename_buf ); |
50a14534 EB |
804 | if ( pixbuf ) |
805 | g_object_unref ( pixbuf ); | |
806 | if ( gx ) | |
807 | g_error_free ( gx ); | |
808 | } | |
809 | ||
45acf79e | 810 | if ( g_file_test ( mdi->filename_buf, G_FILE_TEST_EXISTS ) == FALSE ) |
50a14534 | 811 | { |
84628352 QT |
812 | need_download = TRUE; |
813 | if (( mdi->redownload != REDOWNLOAD_NONE ) && | |
a0b59f2f | 814 | ( mdi->redownload != DOWNLOAD_OR_REFRESH )) |
94493114 QT |
815 | remove_mem_cache = TRUE; |
816 | } else if ( mdi->redownload == DOWNLOAD_OR_REFRESH ) { | |
817 | remove_mem_cache = TRUE; | |
818 | } else | |
819 | continue; | |
820 | ||
94493114 | 821 | mdi->mapcoord.x = x; mdi->mapcoord.y = y; |
84628352 QT |
822 | |
823 | if (need_download) { | |
824 | if ( MAPS_LAYER_NTH_TYPE(mdi->maptype)->download ( &(mdi->mapcoord), mdi->filename_buf )) | |
94493114 | 825 | continue; |
84628352 | 826 | } |
94493114 QT |
827 | |
828 | gdk_threads_enter(); | |
829 | g_mutex_lock(mdi->mutex); | |
830 | if (remove_mem_cache) | |
50bb3d25 | 831 | a_mapcache_remove_all_shrinkfactors ( x, y, mdi->mapcoord.z, MAPS_LAYER_NTH_TYPE(mdi->maptype)->uniq_id, mdi->mapcoord.scale ); |
7114e879 | 832 | if (mdi->refresh_display && mdi->map_layer_alive) { |
94493114 QT |
833 | /* TODO: check if it's on visible area */ |
834 | vik_layer_emit_update ( VIK_LAYER(mdi->vml) ); | |
a0b59f2f | 835 | } |
94493114 QT |
836 | g_mutex_unlock(mdi->mutex); |
837 | gdk_threads_leave(); | |
838 | mdi->mapcoord.x = mdi->mapcoord.y = 0; /* we're temporarily between downloads */ | |
839 | ||
50a14534 EB |
840 | } |
841 | } | |
04e54492 QT |
842 | g_mutex_lock(mdi->mutex); |
843 | if (mdi->map_layer_alive) | |
7bb60307 | 844 | g_object_weak_unref(G_OBJECT(mdi->vml), weak_ref_cb, mdi); |
04e54492 | 845 | g_mutex_unlock(mdi->mutex); |
50a14534 EB |
846 | } |
847 | ||
848 | static void mdi_cancel_cleanup ( MapDownloadInfo *mdi ) | |
849 | { | |
850 | if ( mdi->mapcoord.x || mdi->mapcoord.y ) | |
851 | { | |
852 | g_snprintf ( mdi->filename_buf, mdi->maxlen, DIRSTRUCTURE, | |
cdcaf41c | 853 | mdi->cache_dir, MAPS_LAYER_NTH_TYPE(mdi->maptype)->uniq_id, |
50a14534 | 854 | mdi->mapcoord.scale, mdi->mapcoord.z, mdi->mapcoord.x, mdi->mapcoord.y ); |
45acf79e | 855 | if ( g_file_test ( mdi->filename_buf, G_FILE_TEST_EXISTS ) == TRUE) |
50a14534 | 856 | { |
8c060406 | 857 | g_remove ( mdi->filename_buf ); |
50a14534 EB |
858 | } |
859 | } | |
860 | } | |
861 | ||
862 | static void start_download_thread ( VikMapsLayer *vml, VikViewport *vvp, const VikCoord *ul, const VikCoord *br, gint redownload ) | |
863 | { | |
864 | gdouble xzoom = vml->xmapzoom ? vml->xmapzoom : vik_viewport_get_xmpp ( vvp ); | |
865 | gdouble yzoom = vml->ymapzoom ? vml->ymapzoom : vik_viewport_get_ympp ( vvp ); | |
866 | MapCoord ulm, brm; | |
cdcaf41c QT |
867 | VikMapsLayer_MapType *map_type = MAPS_LAYER_NTH_TYPE(vml->maptype); |
868 | if ( map_type->coord_to_mapcoord ( ul, xzoom, yzoom, &ulm ) | |
869 | && map_type->coord_to_mapcoord ( br, xzoom, yzoom, &brm ) ) | |
50a14534 EB |
870 | { |
871 | MapDownloadInfo *mdi = g_malloc ( sizeof(MapDownloadInfo) ); | |
872 | gint a, b; | |
873 | ||
550fd035 QT |
874 | mdi->vml = vml; |
875 | mdi->vvp = vvp; | |
876 | mdi->map_layer_alive = TRUE; | |
877 | mdi->mutex = g_mutex_new(); | |
7114e879 | 878 | mdi->refresh_display = TRUE; |
550fd035 | 879 | |
50a14534 EB |
880 | /* cache_dir and buffer for dest filename */ |
881 | mdi->cache_dir = g_strdup ( vml->cache_dir ); | |
882 | mdi->maxlen = strlen ( vml->cache_dir ) + 40; | |
883 | mdi->filename_buf = g_malloc ( mdi->maxlen * sizeof(gchar) ); | |
884 | mdi->maptype = vml->maptype; | |
885 | ||
886 | mdi->mapcoord = ulm; | |
887 | ||
888 | mdi->redownload = redownload; | |
889 | ||
890 | mdi->x0 = MIN(ulm.x, brm.x); | |
891 | mdi->xf = MAX(ulm.x, brm.x); | |
892 | mdi->y0 = MIN(ulm.y, brm.y); | |
893 | mdi->yf = MAX(ulm.y, brm.y); | |
894 | ||
895 | mdi->mapstoget = 0; | |
896 | ||
897 | if ( mdi->redownload ) { | |
898 | mdi->mapstoget = (mdi->xf - mdi->x0 + 1) * (mdi->yf - mdi->y0 + 1); | |
899 | } else { | |
900 | /* calculate how many we need */ | |
901 | for ( a = mdi->x0; a <= mdi->xf; a++ ) | |
902 | { | |
903 | for ( b = mdi->y0; b <= mdi->yf; b++ ) | |
904 | { | |
905 | g_snprintf ( mdi->filename_buf, mdi->maxlen, DIRSTRUCTURE, | |
cdcaf41c | 906 | vml->cache_dir, map_type->uniq_id, ulm.scale, |
50a14534 | 907 | ulm.z, a, b ); |
45acf79e | 908 | if ( g_file_test ( mdi->filename_buf, G_FILE_TEST_EXISTS ) == FALSE ) |
50a14534 EB |
909 | mdi->mapstoget++; |
910 | } | |
911 | } | |
912 | } | |
913 | ||
914 | mdi->mapcoord.x = mdi->mapcoord.y = 0; /* for cleanup -- no current map */ | |
915 | ||
916 | if ( mdi->mapstoget ) | |
917 | { | |
97634600 GB |
918 | const gchar *tmp_str; |
919 | gchar *tmp; | |
50a14534 | 920 | |
97634600 GB |
921 | if (redownload) |
922 | { | |
923 | if (redownload == REDOWNLOAD_BAD) | |
924 | tmp_str = ngettext("Redownloading up to %d %s map...", "Redownloading up to %d %s maps...", mdi->mapstoget); | |
925 | else | |
926 | tmp_str = ngettext("Redownloading %d %s map...", "Redownloading %d %s maps...", mdi->mapstoget); | |
927 | } | |
928 | else | |
929 | { | |
930 | tmp_str = ngettext("Downloading %d %s map...", "Downloading %d %s maps...", mdi->mapstoget); | |
931 | } | |
932 | tmp = g_strdup_printf ( tmp_str, mdi->mapstoget, MAPS_LAYER_NTH_LABEL(vml->maptype)); | |
933 | ||
7bb60307 | 934 | g_object_weak_ref(G_OBJECT(mdi->vml), weak_ref_cb, mdi); |
50a14534 EB |
935 | /* launch the thread */ |
936 | a_background_thread ( VIK_GTK_WINDOW_FROM_LAYER(vml), /* parent window */ | |
937 | tmp, /* description string */ | |
938 | (vik_thr_func) map_download_thread, /* function to call within thread */ | |
939 | mdi, /* pass along data */ | |
940 | (vik_thr_free_func) mdi_free, /* function to free pass along data */ | |
941 | (vik_thr_free_func) mdi_cancel_cleanup, | |
942 | mdi->mapstoget ); | |
943 | g_free ( tmp ); | |
944 | } | |
945 | else | |
946 | mdi_free ( mdi ); | |
947 | } | |
948 | } | |
949 | ||
7114e879 QT |
950 | void maps_layer_download_section_without_redraw( VikMapsLayer *vml, VikViewport *vvp, VikCoord *ul, VikCoord *br, gdouble zoom) |
951 | { | |
7114e879 QT |
952 | MapCoord ulm, brm; |
953 | VikMapsLayer_MapType *map_type = MAPS_LAYER_NTH_TYPE(vml->maptype); | |
954 | ||
955 | if (!map_type->coord_to_mapcoord(ul, zoom, zoom, &ulm) | |
956 | || !map_type->coord_to_mapcoord(br, zoom, zoom, &brm)) { | |
4258f4e2 | 957 | g_warning("%s() coord_to_mapcoord() failed", __PRETTY_FUNCTION__); |
7114e879 QT |
958 | return; |
959 | } | |
960 | ||
961 | MapDownloadInfo *mdi = g_malloc(sizeof(MapDownloadInfo)); | |
962 | gint i, j; | |
963 | ||
964 | mdi->vml = vml; | |
965 | mdi->vvp = vvp; | |
966 | mdi->map_layer_alive = TRUE; | |
967 | mdi->mutex = g_mutex_new(); | |
968 | mdi->refresh_display = FALSE; | |
969 | ||
970 | mdi->cache_dir = g_strdup ( vml->cache_dir ); | |
971 | mdi->maxlen = strlen ( vml->cache_dir ) + 40; | |
972 | mdi->filename_buf = g_malloc ( mdi->maxlen * sizeof(gchar) ); | |
973 | mdi->maptype = vml->maptype; | |
974 | ||
975 | mdi->mapcoord = ulm; | |
976 | ||
977 | mdi->redownload = REDOWNLOAD_NONE; | |
978 | ||
979 | mdi->x0 = MIN(ulm.x, brm.x); | |
980 | mdi->xf = MAX(ulm.x, brm.x); | |
981 | mdi->y0 = MIN(ulm.y, brm.y); | |
982 | mdi->yf = MAX(ulm.y, brm.y); | |
983 | ||
984 | mdi->mapstoget = 0; | |
985 | ||
986 | for (i = mdi->x0; i <= mdi->xf; i++) { | |
987 | for (j = mdi->y0; j <= mdi->yf; j++) { | |
988 | g_snprintf ( mdi->filename_buf, mdi->maxlen, DIRSTRUCTURE, | |
989 | vml->cache_dir, map_type->uniq_id, ulm.scale, | |
990 | ulm.z, i, j ); | |
45acf79e | 991 | if ( g_file_test ( mdi->filename_buf, G_FILE_TEST_EXISTS ) == FALSE ) |
7114e879 QT |
992 | mdi->mapstoget++; |
993 | } | |
994 | } | |
995 | ||
996 | mdi->mapcoord.x = mdi->mapcoord.y = 0; /* for cleanup -- no current map */ | |
997 | ||
998 | if (mdi->mapstoget) { | |
4c77d5e0 GB |
999 | gchar *tmp; |
1000 | const gchar *fmt; | |
eb6b0125 JJ |
1001 | fmt = ngettext("Downloading %d %s map...", |
1002 | "Downloading %d %s maps...", | |
1003 | mdi->mapstoget); | |
4c77d5e0 | 1004 | tmp = g_strdup_printf ( fmt, mdi->mapstoget, MAPS_LAYER_NTH_LABEL(vml->maptype) ); |
7114e879 QT |
1005 | |
1006 | g_object_weak_ref(G_OBJECT(mdi->vml), weak_ref_cb, mdi); | |
1007 | /* launch the thread */ | |
1008 | a_background_thread ( VIK_GTK_WINDOW_FROM_LAYER(vml), /* parent window */ | |
1009 | tmp, /* description string */ | |
1010 | (vik_thr_func) map_download_thread, /* function to call within thread */ | |
1011 | mdi, /* pass along data */ | |
1012 | (vik_thr_free_func) mdi_free, /* function to free pass along data */ | |
1013 | (vik_thr_free_func) mdi_cancel_cleanup, | |
1014 | mdi->mapstoget ); | |
1015 | g_free ( tmp ); | |
1016 | } | |
1017 | else | |
1018 | mdi_free ( mdi ); | |
1019 | } | |
1020 | ||
50a14534 EB |
1021 | static void maps_layer_redownload_bad ( VikMapsLayer *vml ) |
1022 | { | |
1023 | start_download_thread ( vml, vml->redownload_vvp, &(vml->redownload_ul), &(vml->redownload_br), REDOWNLOAD_BAD ); | |
1024 | } | |
1025 | static void maps_layer_redownload_all ( VikMapsLayer *vml ) | |
1026 | { | |
1027 | start_download_thread ( vml, vml->redownload_vvp, &(vml->redownload_ul), &(vml->redownload_br), REDOWNLOAD_ALL ); | |
1028 | } | |
1029 | ||
1030 | static gboolean maps_layer_download_release ( VikMapsLayer *vml, GdkEventButton *event, VikViewport *vvp ) | |
1031 | { | |
941aa6e9 AF |
1032 | if (!vml || vml->vl.type != VIK_LAYER_MAPS) |
1033 | return FALSE; | |
50a14534 EB |
1034 | if ( vml->dl_tool_x != -1 && vml->dl_tool_y != -1 ) |
1035 | { | |
1036 | if ( event->button == 1 ) | |
1037 | { | |
1038 | VikCoord ul, br; | |
1039 | vik_viewport_screen_to_coord ( vvp, MAX(0, MIN(event->x, vml->dl_tool_x)), MAX(0, MIN(event->y, vml->dl_tool_y)), &ul ); | |
1040 | vik_viewport_screen_to_coord ( vvp, MIN(vik_viewport_get_width(vvp), MAX(event->x, vml->dl_tool_x)), MIN(vik_viewport_get_height(vvp), MAX ( event->y, vml->dl_tool_y ) ), &br ); | |
a0b59f2f | 1041 | start_download_thread ( vml, vvp, &ul, &br, DOWNLOAD_OR_REFRESH ); |
50a14534 EB |
1042 | vml->dl_tool_x = vml->dl_tool_y = -1; |
1043 | return TRUE; | |
1044 | } | |
1045 | else | |
1046 | { | |
1047 | vik_viewport_screen_to_coord ( vvp, MAX(0, MIN(event->x, vml->dl_tool_x)), MAX(0, MIN(event->y, vml->dl_tool_y)), &(vml->redownload_ul) ); | |
1048 | vik_viewport_screen_to_coord ( vvp, MIN(vik_viewport_get_width(vvp), MAX(event->x, vml->dl_tool_x)), MIN(vik_viewport_get_height(vvp), MAX ( event->y, vml->dl_tool_y ) ), &(vml->redownload_br) ); | |
1049 | ||
1050 | vml->redownload_vvp = vvp; | |
1051 | ||
1052 | vml->dl_tool_x = vml->dl_tool_y = -1; | |
1053 | ||
1054 | if ( ! vml->dl_right_click_menu ) { | |
1055 | GtkWidget *item; | |
1056 | vml->dl_right_click_menu = GTK_MENU ( gtk_menu_new () ); | |
1057 | ||
4c77d5e0 | 1058 | item = gtk_menu_item_new_with_label ( _("Redownload bad map(s)") ); |
50a14534 EB |
1059 | g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(maps_layer_redownload_bad), vml ); |
1060 | gtk_menu_shell_append ( GTK_MENU_SHELL(vml->dl_right_click_menu), item ); | |
1061 | ||
4c77d5e0 | 1062 | item = gtk_menu_item_new_with_label ( _("Redownload all map(s)") ); |
50a14534 EB |
1063 | g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(maps_layer_redownload_all), vml ); |
1064 | gtk_menu_shell_append ( GTK_MENU_SHELL(vml->dl_right_click_menu), item ); | |
1065 | } | |
1066 | ||
1067 | gtk_menu_popup ( vml->dl_right_click_menu, NULL, NULL, NULL, NULL, event->button, event->time ); | |
1068 | gtk_widget_show_all ( GTK_WIDGET(vml->dl_right_click_menu) ); | |
1069 | } | |
1070 | } | |
1071 | return FALSE; | |
1072 | } | |
1073 | ||
941aa6e9 AF |
1074 | static gpointer maps_layer_download_create ( VikWindow *vw, VikViewport *vvp) |
1075 | { | |
1076 | return vvp; | |
1077 | } | |
1078 | ||
50a14534 EB |
1079 | static gboolean maps_layer_download_click ( VikMapsLayer *vml, GdkEventButton *event, VikViewport *vvp ) |
1080 | { | |
1081 | MapCoord tmp; | |
941aa6e9 AF |
1082 | if (!vml || vml->vl.type != VIK_LAYER_MAPS) |
1083 | return FALSE; | |
cdcaf41c QT |
1084 | VikMapsLayer_MapType *map_type = MAPS_LAYER_NTH_TYPE(vml->maptype); |
1085 | if ( map_type->drawmode == vik_viewport_get_drawmode ( vvp ) && | |
1086 | map_type->coord_to_mapcoord ( vik_viewport_get_center ( vvp ), | |
50a14534 EB |
1087 | vml->xmapzoom ? vml->xmapzoom : vik_viewport_get_xmpp ( vvp ), |
1088 | vml->ymapzoom ? vml->ymapzoom : vik_viewport_get_ympp ( vvp ), | |
1089 | &tmp ) ) { | |
1090 | vml->dl_tool_x = event->x, vml->dl_tool_y = event->y; | |
1091 | return TRUE; | |
1092 | } | |
1093 | return FALSE; | |
1094 | ||
1095 | ||
1096 | #if 0 | |
1097 | if ( __map_types[vml->maptype].drawmode == vik_viewport_get_drawmode ( vvp ) ) | |
1098 | { | |
1099 | VikCoord coord; | |
1100 | MapCoord mapcoord; | |
1101 | vik_viewport_screen_to_coord ( vvp, event->x, event->y, &coord ); | |
1102 | if ( __map_types[vml->maptype].coord_to_mapcoord ( &coord, | |
1103 | vml->xmapzoom ? vml->xmapzoom : vik_viewport_get_xmpp ( vvp ), | |
1104 | vml->ymapzoom ? vml->ymapzoom : vik_viewport_get_ympp ( vvp ), | |
1105 | &mapcoord ) ) { | |
1106 | gchar *filename_buf = g_strdup_printf ( DIRSTRUCTURE, | |
1107 | vml->cache_dir, __map_types[vml->maptype].uniq_id, | |
1108 | mapcoord.scale, mapcoord.z, mapcoord.x, mapcoord.y ); | |
1109 | ||
1110 | __map_types[vml->maptype].download ( &mapcoord, filename_buf ); | |
1111 | g_free ( filename_buf ); | |
1112 | vik_layer_emit_update ( VIK_LAYER(vml) ); | |
1113 | return TRUE; | |
1114 | } | |
1115 | } | |
1116 | return FALSE; | |
1117 | #endif | |
1118 | } | |
1119 | ||
50817314 | 1120 | static void download_onscreen_maps ( gpointer vml_vvp[2], gint redownload ) |
50a14534 EB |
1121 | { |
1122 | VikMapsLayer *vml = vml_vvp[0]; | |
1123 | VikViewport *vvp = vml_vvp[1]; | |
314c1ccc | 1124 | VikViewportDrawMode vp_drawmode = vik_viewport_get_drawmode ( vvp ); |
50a14534 EB |
1125 | |
1126 | gdouble xzoom = vml->xmapzoom ? vml->xmapzoom : vik_viewport_get_xmpp ( vvp ); | |
1127 | gdouble yzoom = vml->ymapzoom ? vml->ymapzoom : vik_viewport_get_ympp ( vvp ); | |
1128 | ||
1129 | VikCoord ul, br; | |
1130 | MapCoord ulm, brm; | |
1131 | ||
1132 | vik_viewport_screen_to_coord ( vvp, 0, 0, &ul ); | |
1133 | vik_viewport_screen_to_coord ( vvp, vik_viewport_get_width(vvp), vik_viewport_get_height(vvp), &br ); | |
1134 | ||
cdcaf41c | 1135 | VikMapsLayer_MapType *map_type = MAPS_LAYER_NTH_TYPE(vml->maptype); |
314c1ccc | 1136 | if ( map_type->drawmode == vp_drawmode && |
cdcaf41c QT |
1137 | map_type->coord_to_mapcoord ( &ul, xzoom, yzoom, &ulm ) && |
1138 | map_type->coord_to_mapcoord ( &br, xzoom, yzoom, &brm ) ) | |
50817314 | 1139 | start_download_thread ( vml, vvp, &ul, &br, redownload ); |
314c1ccc | 1140 | else if (map_type->drawmode != vp_drawmode) { |
94933cb8 | 1141 | const gchar *drawmode_name = vik_viewport_get_drawmode_name (vvp, map_type->drawmode); |
4c77d5e0 | 1142 | gchar *err = g_strdup_printf(_("Wrong drawmode for this map.\nSelect \"%s\" from View menu and try again."), _(drawmode_name)); |
314c1ccc QT |
1143 | a_dialog_error_msg ( VIK_GTK_WINDOW_FROM_LAYER(vml), err ); |
1144 | g_free(err); | |
1145 | } | |
50a14534 | 1146 | else |
4c77d5e0 | 1147 | a_dialog_error_msg ( VIK_GTK_WINDOW_FROM_LAYER(vml), _("Wrong zoom level for this map.") ); |
50a14534 EB |
1148 | |
1149 | } | |
1150 | ||
50817314 GB |
1151 | static void maps_layer_download_onscreen_maps ( gpointer vml_vvp[2] ) |
1152 | { | |
1153 | download_onscreen_maps( vml_vvp, REDOWNLOAD_NONE); | |
1154 | } | |
1155 | ||
1156 | static void maps_layer_redownload_all_onscreen_maps ( gpointer vml_vvp[2] ) | |
1157 | { | |
1158 | download_onscreen_maps( vml_vvp, REDOWNLOAD_ALL); | |
1159 | } | |
1160 | ||
50a14534 EB |
1161 | static void maps_layer_add_menu_items ( VikMapsLayer *vml, GtkMenu *menu, VikLayersPanel *vlp ) |
1162 | { | |
1163 | static gpointer pass_along[2]; | |
1164 | GtkWidget *item; | |
1165 | pass_along[0] = vml; | |
1166 | pass_along[1] = vik_layers_panel_get_viewport( VIK_LAYERS_PANEL(vlp) ); | |
1167 | ||
1168 | item = gtk_menu_item_new(); | |
1169 | gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item ); | |
1170 | gtk_widget_show ( item ); | |
1171 | ||
4c77d5e0 | 1172 | item = gtk_menu_item_new_with_label ( _("Download Onscreen Maps") ); |
50a14534 EB |
1173 | g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(maps_layer_download_onscreen_maps), pass_along ); |
1174 | gtk_menu_shell_append (GTK_MENU_SHELL (menu), item); | |
1175 | gtk_widget_show ( item ); | |
50817314 | 1176 | |
1b86e056 | 1177 | /* TODO Add GTK_STOCK_REFRESH icon */ |
4c77d5e0 | 1178 | item = gtk_menu_item_new_with_label ( _("Refresh Onscreen Tiles") ); |
50817314 GB |
1179 | g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(maps_layer_redownload_all_onscreen_maps), pass_along ); |
1180 | gtk_menu_shell_append (GTK_MENU_SHELL (menu), item); | |
1181 | gtk_widget_show ( item ); | |
50a14534 | 1182 | } |