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