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