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