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