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