]> git.street.me.uk Git - andy/viking.git/blame - src/vikmapslayer.c
Make more portable .vik file, as don't save the map cache directory if it's the map...
[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 {
cde1e50e
RN
523 case PARAM_CACHE_DIR:
524 /* Only save a blank when the map cache location equals the default
525 On reading in, when it is blank then the default is reconstructed
526 Since the default changes dependent on the user and OS, it means the resultant file is more portable */
527 if ( is_file_operation && vml->cache_dir && strcmp ( vml->cache_dir, MAPS_CACHE_DIR ) == 0 )
528 rv.s = "";
529 else
530 rv.s = vml->cache_dir ? vml->cache_dir : "";
531 break;
50a14534
EB
532 case PARAM_MAPTYPE: rv.u = map_index_to_uniq_id ( vml->maptype ); break;
533 case PARAM_ALPHA: rv.u = vml->alpha; break;
534 case PARAM_AUTODOWNLOAD: rv.u = vml->autodownload; break;
382566c3 535 case PARAM_ONLYMISSING: rv.u = vml->adl_only_missing; break;
50a14534
EB
536 case PARAM_MAPZOOM: rv.u = vml->mapzoom_id; break;
537 }
538 return rv;
539}
540
541/****************************************/
542/****** CREATING, COPYING, FREEING ******/
543/****************************************/
544
545static VikMapsLayer *maps_layer_new ( VikViewport *vvp )
546{
547 VikMapsLayer *vml = VIK_MAPS_LAYER ( g_object_new ( VIK_MAPS_LAYER_TYPE, NULL ) );
a0c65899 548 vik_layer_set_type ( VIK_LAYER(vml), VIK_LAYER_MAPS );
a7023a1b
RN
549
550 vik_layer_set_defaults ( VIK_LAYER(vml), vvp );
551
50a14534 552 vml->dl_tool_x = vml->dl_tool_y = -1;
10ca2bfe
QT
553 vml->last_center = NULL;
554 vml->last_xmpp = 0.0;
555 vml->last_ympp = 0.0;
50a14534
EB
556
557 vml->dl_right_click_menu = NULL;
8e507445 558 vml->license_notice_shown = FALSE;
50a14534
EB
559
560 return vml;
561}
562
563static void maps_layer_free ( VikMapsLayer *vml )
564{
e65028db
GB
565 g_free ( vml->cache_dir );
566 vml->cache_dir = NULL;
50a14534 567 if ( vml->dl_right_click_menu )
4f14a010 568 g_object_ref_sink ( G_OBJECT(vml->dl_right_click_menu) );
e65028db
GB
569 g_free(vml->last_center);
570 vml->last_center = NULL;
50a14534
EB
571}
572
07059501 573static void maps_layer_post_read (VikLayer *vl, VikViewport *vp, gboolean from_file)
dc5758d3 574{
07059501
GB
575 if (from_file != TRUE)
576 {
577 /* If this method is not called in file reading context
578 * it is called in GUI context.
579 * So, we can check if we have to inform the user about inconsistency */
580 VikViewportDrawMode vp_drawmode;
581 VikMapsLayer *vml = VIK_MAPS_LAYER(vl);
820c59f4 582 VikMapSource *map = NULL;
dc5758d3 583
405b74ed 584 vp_drawmode = vik_viewport_get_drawmode ( vp );
820c59f4
GB
585 map = MAPS_LAYER_NTH_TYPE(vml->maptype);
586 if (vik_map_source_get_drawmode(map) != vp_drawmode) {
405b74ed 587 const gchar *drawmode_name = vik_viewport_get_drawmode_name (vp, vik_map_source_get_drawmode(map));
4c77d5e0 588 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 589 a_dialog_warning_msg ( VIK_GTK_WINDOW_FROM_WIDGET(vp), msg );
07059501
GB
590 g_free(msg);
591 }
53ac8302
GB
592
593 if (vik_map_source_get_license (map) != NULL) {
8e507445
RN
594 if ( ! vml->license_notice_shown ) {
595 a_dialog_license (VIK_GTK_WINDOW_FROM_WIDGET(vp), vik_map_source_get_label (map),
596 vik_map_source_get_license (map), vik_map_source_get_license_url (map) );
597 vml->license_notice_shown = TRUE;
598 }
53ac8302 599 }
dc5758d3
GB
600 }
601}
602
7924723c
RN
603static const gchar* maps_layer_tooltip ( VikMapsLayer *vml )
604{
605 return vik_maps_layer_get_map_label ( vml );
606}
607
911400b5
AF
608static void maps_layer_marshall( VikMapsLayer *vml, guint8 **data, gint *len )
609{
610 vik_layer_marshall_params ( VIK_LAYER(vml), data, len );
611}
612
613static VikMapsLayer *maps_layer_unmarshall( guint8 *data, gint len, VikViewport *vvp )
614{
615 VikMapsLayer *rv = maps_layer_new ( vvp );
616 vik_layer_unmarshall_params ( VIK_LAYER(rv), data, len, vvp );
617 return rv;
618}
619
50a14534
EB
620/*********************/
621/****** DRAWING ******/
622/*********************/
623
624static GdkPixbuf *pixbuf_set_alpha ( GdkPixbuf *pixbuf, guint8 alpha )
625{
626 guchar *pixels;
627 gint width, height, iii, jjj;
628
629 if ( ! gdk_pixbuf_get_has_alpha ( pixbuf ) )
630 {
631 GdkPixbuf *tmp = gdk_pixbuf_add_alpha(pixbuf,FALSE,0,0,0);
632 g_object_unref(G_OBJECT(pixbuf));
633 pixbuf = tmp;
634 }
635
636 pixels = gdk_pixbuf_get_pixels(pixbuf);
637 width = gdk_pixbuf_get_width(pixbuf);
638 height = gdk_pixbuf_get_height(pixbuf);
639
640 /* r,g,b,a,r,g,b,a.... */
641 for (iii = 0; iii < width; iii++) for (jjj = 0; jjj < height; jjj++)
642 {
643 pixels += 3;
644 *pixels++ = alpha;
645 }
646 return pixbuf;
647}
648
649static GdkPixbuf *pixbuf_shrink ( GdkPixbuf *pixbuf, gdouble xshrinkfactor, gdouble yshrinkfactor )
650{
651 GdkPixbuf *tmp;
652 guint16 width = gdk_pixbuf_get_width(pixbuf), height = gdk_pixbuf_get_height(pixbuf);
2d5d32c1 653 tmp = gdk_pixbuf_scale_simple(pixbuf, ceil(width * xshrinkfactor), ceil(height * yshrinkfactor), GDK_INTERP_BILINEAR);
50a14534
EB
654 g_object_unref ( G_OBJECT(pixbuf) );
655 return tmp;
656}
657
658static GdkPixbuf *get_pixbuf( VikMapsLayer *vml, gint mode, MapCoord *mapcoord, gchar *filename_buf, gint buf_len, gdouble xshrinkfactor, gdouble yshrinkfactor )
659{
660 GdkPixbuf *pixbuf;
661
662 /* get the thing */
663 pixbuf = a_mapcache_get ( mapcoord->x, mapcoord->y, mapcoord->z,
664 mode, mapcoord->scale, vml->alpha, xshrinkfactor, yshrinkfactor );
665
666 if ( ! pixbuf ) {
2673b29d
RN
667 if ( vik_map_source_is_direct_file_access (MAPS_LAYER_NTH_TYPE(vml->maptype)) )
668 g_snprintf ( filename_buf, buf_len, DIRECTDIRACCESS,
669 vml->cache_dir, (17 - mapcoord->scale), mapcoord->x, mapcoord->y, ".png" );
670 else
671 g_snprintf ( filename_buf, buf_len, DIRSTRUCTURE,
672 vml->cache_dir, mode,
673 mapcoord->scale, mapcoord->z, mapcoord->x, mapcoord->y );
674
01ecda7e 675 if ( g_file_test ( filename_buf, G_FILE_TEST_EXISTS ) == TRUE)
50a14534
EB
676 {
677 GError *gx = NULL;
678 pixbuf = gdk_pixbuf_new_from_file ( filename_buf, &gx );
679
01ecda7e 680 /* free the pixbuf on error */
50a14534
EB
681 if (gx)
682 {
683 if ( gx->domain != GDK_PIXBUF_ERROR || gx->code != GDK_PIXBUF_ERROR_CORRUPT_IMAGE )
4c77d5e0 684 g_warning ( _("Couldn't open image file: %s"), gx->message );
50a14534 685
01ecda7e
MR
686 g_error_free ( gx );
687 if ( pixbuf )
688 g_object_unref ( G_OBJECT(pixbuf) );
689 pixbuf = NULL;
690 } else {
50a14534
EB
691 if ( vml->alpha < 255 )
692 pixbuf = pixbuf_set_alpha ( pixbuf, vml->alpha );
693 if ( xshrinkfactor != 1.0 || yshrinkfactor != 1.0 )
694 pixbuf = pixbuf_shrink ( pixbuf, xshrinkfactor, yshrinkfactor );
695
696 a_mapcache_add ( pixbuf, mapcoord->x, mapcoord->y,
820c59f4 697 mapcoord->z, vik_map_source_get_uniq_id(MAPS_LAYER_NTH_TYPE(vml->maptype)),
50a14534 698 mapcoord->scale, vml->alpha, xshrinkfactor, yshrinkfactor );
50a14534
EB
699 }
700 }
701 }
702 return pixbuf;
703}
704
9979924f 705static gboolean should_start_autodownload(VikMapsLayer *vml, VikViewport *vvp)
10ca2bfe
QT
706{
707 const VikCoord *center = vik_viewport_get_center ( vvp );
708
bbf2149b 709 if (vik_window_get_pan_move (VIK_WINDOW(VIK_GTK_WINDOW_FROM_WIDGET(GTK_WIDGET(vvp)))))
01da6b4d 710 /* D'n'D pan in action: do not download */
1c6a6010
GB
711 return FALSE;
712
9979924f
RN
713 // TEMPORARY HACK
714 // Prevent requests for downloading tiles at Zoom Level 19 and above for most map types
715 // Allow MapQuest Zoom Level up to 19
716 // TODO: This should be made a property of the map source and then use that value
717 gdouble xzoom = vik_viewport_get_xmpp ( vvp );
718 if ( (vml->maptype != 19 && map_utils_mpp_to_scale (xzoom) < -1) || (vml->maptype == 19 && map_utils_mpp_to_scale (xzoom) < -2) )
719 return FALSE;
720
10ca2bfe
QT
721 if (vml->last_center == NULL) {
722 VikCoord *new_center = g_malloc(sizeof(VikCoord));
723 *new_center = *center;
724 vml->last_center = new_center;
725 vml->last_xmpp = vik_viewport_get_xmpp(vvp);
726 vml->last_ympp = vik_viewport_get_ympp(vvp);
727 return TRUE;
728 }
729
730 /* TODO: perhaps vik_coord_diff() */
731 if (vik_coord_equals(vml->last_center, center)
732 && (vml->last_xmpp == vik_viewport_get_xmpp(vvp))
733 && (vml->last_ympp == vik_viewport_get_ympp(vvp)))
734 return FALSE;
735
736 *(vml->last_center) = *center;
737 vml->last_xmpp = vik_viewport_get_xmpp(vvp);
738 vml->last_ympp = vik_viewport_get_ympp(vvp);
739 return TRUE;
740}
741
50a14534
EB
742static void maps_layer_draw_section ( VikMapsLayer *vml, VikViewport *vvp, VikCoord *ul, VikCoord *br )
743{
744 MapCoord ulm, brm;
745 gdouble xzoom = vik_viewport_get_xmpp ( vvp );
746 gdouble yzoom = vik_viewport_get_ympp ( vvp );
747 gdouble xshrinkfactor = 1.0, yshrinkfactor = 1.0;
2673b29d 748 gboolean existence_only = FALSE;
50a14534
EB
749
750 if ( vml->xmapzoom && (vml->xmapzoom != xzoom || vml->ymapzoom != yzoom) ) {
751 xshrinkfactor = vml->xmapzoom / xzoom;
752 yshrinkfactor = vml->ymapzoom / yzoom;
732d1e25
EB
753 xzoom = vml->xmapzoom;
754 yzoom = vml->xmapzoom;
755 if ( ! (xshrinkfactor > MIN_SHRINKFACTOR && xshrinkfactor < MAX_SHRINKFACTOR &&
756 yshrinkfactor > MIN_SHRINKFACTOR && yshrinkfactor < MAX_SHRINKFACTOR ) ) {
6de95419
RN
757 if ( xshrinkfactor > REAL_MIN_SHRINKFACTOR && yshrinkfactor > REAL_MIN_SHRINKFACTOR ) {
758 g_debug ( "%s: existence_only due to SHRINKFACTORS", __FUNCTION__ );
732d1e25 759 existence_only = TRUE;
6de95419 760 }
732d1e25 761 else {
4c77d5e0 762 g_warning ( _("Cowardly refusing to draw tiles or existence of tiles beyond %d zoom out factor"), (int)( 1.0/REAL_MIN_SHRINKFACTOR));
732d1e25
EB
763 return;
764 }
50a14534
EB
765 }
766 }
767
768 /* coord -> ID */
820c59f4
GB
769 VikMapSource *map = MAPS_LAYER_NTH_TYPE(vml->maptype);
770 if ( vik_map_source_coord_to_mapcoord ( map, ul, xzoom, yzoom, &ulm ) &&
771 vik_map_source_coord_to_mapcoord ( map, br, xzoom, yzoom, &brm ) ) {
50a14534
EB
772
773 /* loop & draw */
774 gint x, y;
775 gint xmin = MIN(ulm.x, brm.x), xmax = MAX(ulm.x, brm.x);
776 gint ymin = MIN(ulm.y, brm.y), ymax = MAX(ulm.y, brm.y);
820c59f4 777 gint mode = vik_map_source_get_uniq_id(map);
50a14534
EB
778
779 VikCoord coord;
780 gint xx, yy, width, height;
781 GdkPixbuf *pixbuf;
782
6de95419
RN
783 // Prevent the program grinding to a halt if trying to deal with thousands of tiles
784 // which can happen when using a small fixed zoom level and viewing large areas.
785 // Also prevents very large number of tile download requests
786 gint tiles = (xmax-xmin) * (ymax-ymin);
787 if ( tiles > MAX_TILES ) {
788 g_debug ( "%s: existence_only due to wanting too many tiles (%d)", __FUNCTION__, tiles );
789 existence_only = TRUE;
790 }
791
50a14534
EB
792 guint max_path_len = strlen(vml->cache_dir) + 40;
793 gchar *path_buf = g_malloc ( max_path_len * sizeof(char) );
794
732d1e25 795 if ( (!existence_only) && vml->autodownload && should_start_autodownload(vml, vvp)) {
33be396e 796 g_debug("%s: Starting autodownload", __FUNCTION__);
382566c3 797 if ( !vml->adl_only_missing && vik_map_source_supports_download_only_new (map) )
245f48f5
GB
798 // Try to download newer tiles
799 start_download_thread ( vml, vvp, ul, br, REDOWNLOAD_NEW );
800 else
801 // Download only missing tiles
802 start_download_thread ( vml, vvp, ul, br, REDOWNLOAD_NONE );
10ca2bfe 803 }
50a14534 804
820c59f4 805 if ( vik_map_source_get_tilesize_x(map) == 0 && !existence_only ) {
50a14534
EB
806 for ( x = xmin; x <= xmax; x++ ) {
807 for ( y = ymin; y <= ymax; y++ ) {
808 ulm.x = x;
809 ulm.y = y;
810 pixbuf = get_pixbuf ( vml, mode, &ulm, path_buf, max_path_len, xshrinkfactor, yshrinkfactor );
811 if ( pixbuf ) {
812 width = gdk_pixbuf_get_width ( pixbuf );
813 height = gdk_pixbuf_get_height ( pixbuf );
814
820c59f4 815 vik_map_source_mapcoord_to_center_coord ( map, &ulm, &coord );
50a14534
EB
816 vik_viewport_coord_to_screen ( vvp, &coord, &xx, &yy );
817 xx -= (width/2);
818 yy -= (height/2);
819
820 vik_viewport_draw_pixbuf ( vvp, pixbuf, 0, 0, xx, yy, width, height );
821 }
822 }
823 }
824 } else { /* tilesize is known, don't have to keep converting coords */
820c59f4
GB
825 gdouble tilesize_x = vik_map_source_get_tilesize_x(map) * xshrinkfactor;
826 gdouble tilesize_y = vik_map_source_get_tilesize_y(map) * yshrinkfactor;
50a14534
EB
827 /* ceiled so tiles will be maximum size in the case of funky shrinkfactor */
828 gint tilesize_x_ceil = ceil ( tilesize_x );
829 gint tilesize_y_ceil = ceil ( tilesize_y );
830 gint8 xinc = (ulm.x == xmin) ? 1 : -1;
831 gint8 yinc = (ulm.y == ymin) ? 1 : -1;
832 gdouble xx, yy; gint xx_tmp, yy_tmp;
833 gint base_yy, xend, yend;
732d1e25 834
50a14534
EB
835 xend = (xinc == 1) ? (xmax+1) : (xmin-1);
836 yend = (yinc == 1) ? (ymax+1) : (ymin-1);
837
820c59f4 838 vik_map_source_mapcoord_to_center_coord ( map, &ulm, &coord );
50a14534
EB
839 vik_viewport_coord_to_screen ( vvp, &coord, &xx_tmp, &yy_tmp );
840 xx = xx_tmp; yy = yy_tmp;
841 /* above trick so xx,yy doubles. this is so shrinkfactors aren't rounded off
842 * eg if tile size 128, shrinkfactor 0.333 */
843 xx -= (tilesize_x/2);
844 base_yy = yy - (tilesize_y/2);
845
846 for ( x = ((xinc == 1) ? xmin : xmax); x != xend; x+=xinc ) {
847 yy = base_yy;
848 for ( y = ((yinc == 1) ? ymin : ymax); y != yend; y+=yinc ) {
849 ulm.x = x;
850 ulm.y = y;
732d1e25
EB
851
852 if ( existence_only ) {
2673b29d
RN
853 if ( vik_map_source_is_direct_file_access (MAPS_LAYER_NTH_TYPE(vml->maptype)) )
854 g_snprintf ( path_buf, max_path_len, DIRECTDIRACCESS,
855 vml->cache_dir, (17 - ulm.scale), ulm.x, ulm.y, ".png" );
856 else
857 g_snprintf ( path_buf, max_path_len, DIRSTRUCTURE,
858 vml->cache_dir, mode,
859 ulm.scale, ulm.z, ulm.x, ulm.y );
45acf79e 860 if ( g_file_test ( path_buf, G_FILE_TEST_EXISTS ) == TRUE ) {
ff37db21 861 GdkGC *black_gc = gtk_widget_get_style(GTK_WIDGET(vvp))->black_gc;
732d1e25
EB
862 vik_viewport_draw_line ( vvp, black_gc, xx+tilesize_x_ceil, yy, xx, yy+tilesize_y_ceil );
863 }
864 } else {
6f0d1bea
JJ
865 int scale_inc;
866 for (scale_inc = 0; scale_inc < 4; scale_inc ++) {
867 /* try with correct then smaller zooms */
868 int scale_factor = 1 << scale_inc; /* 2^scale_inc */
869 MapCoord ulm2 = ulm;
870 ulm2.x = ulm.x / scale_factor;
871 ulm2.y = ulm.y / scale_factor;
872 ulm2.scale = ulm.scale + scale_inc;
873 pixbuf = get_pixbuf ( vml, mode, &ulm2, path_buf, max_path_len, xshrinkfactor * scale_factor, yshrinkfactor * scale_factor );
874 if ( pixbuf ) {
875 gint src_x = (ulm.x % scale_factor) * tilesize_x_ceil;
876 gint src_y = (ulm.y % scale_factor) * tilesize_y_ceil;
40cfc175
JJ
877#ifdef DEBUG
878 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);
879#endif
6f0d1bea
JJ
880 vik_viewport_draw_pixbuf ( vvp, pixbuf, src_x, src_y, xx, yy, tilesize_x_ceil, tilesize_y_ceil );
881 break;
882 }
883 }
884 if ( !pixbuf ) {
885 /* retry with bigger zooms */
886 int scale_dec;
887 for (scale_dec = 1; scale_dec < 2; scale_dec ++) {
888 int pict_x, pict_y;
889 int scale_factor = 1 << scale_dec; /* 2^scale_dec */
91dc4449 890 MapCoord ulm2 = ulm;
6f0d1bea
JJ
891 ulm2.x = ulm.x * scale_factor;
892 ulm2.y = ulm.y * scale_factor;
893 ulm2.scale = ulm.scale - scale_dec;
894 for (pict_x = 0; pict_x < scale_factor; pict_x ++) {
895 for (pict_y = 0; pict_y < scale_factor; pict_y ++) {
896 MapCoord ulm3 = ulm2;
897 ulm3.x += pict_x;
898 ulm3.y += pict_y;
899 pixbuf = get_pixbuf ( vml, mode, &ulm3, path_buf, max_path_len, xshrinkfactor / scale_factor, yshrinkfactor / scale_factor );
900 if ( pixbuf ) {
901 gint src_x = 0;
902 gint src_y = 0;
903 gint dest_x = xx + pict_x * (tilesize_x_ceil / scale_factor);
904 gint dest_y = yy + pict_y * (tilesize_y_ceil / scale_factor);
905 vik_viewport_draw_pixbuf ( vvp, pixbuf, src_x, src_y, dest_x, dest_y, tilesize_x_ceil / scale_factor, tilesize_y_ceil / scale_factor );
906 }
907 }
91dc4449
JJ
908 }
909 }
910 }
732d1e25 911 }
50a14534
EB
912
913 yy += tilesize_y;
914 }
915 xx += tilesize_x;
916 }
917 }
918
919 g_free ( path_buf );
920 }
921}
922
923static void maps_layer_draw ( VikMapsLayer *vml, VikViewport *vvp )
924{
820c59f4 925 if ( vik_map_source_get_drawmode(MAPS_LAYER_NTH_TYPE(vml->maptype)) == vik_viewport_get_drawmode ( vvp ) )
50a14534
EB
926 {
927 VikCoord ul, br;
928
82aa018d 929 /* Copyright */
68b1d6c0
GB
930 gdouble level = vik_viewport_get_zoom ( vvp );
931 LatLonBBox bbox;
932 vik_viewport_get_min_max_lat_lon ( vvp, &bbox.south, &bbox.north, &bbox.west, &bbox.east );
933 vik_map_source_get_copyright ( MAPS_LAYER_NTH_TYPE(vml->maptype), bbox, level, vik_viewport_add_copyright, vvp );
82aa018d 934
26336cf0
GB
935 /* Logo */
936 const GdkPixbuf *logo = vik_map_source_get_logo ( MAPS_LAYER_NTH_TYPE(vml->maptype) );
937 vik_viewport_add_logo ( vvp, logo );
938
50a14534
EB
939 /* get corner coords */
940 if ( vik_viewport_get_coord_mode ( vvp ) == VIK_COORD_UTM && ! vik_viewport_is_one_zone ( vvp ) ) {
941 /* UTM multi-zone stuff by Kit Transue */
942 gchar leftmost_zone, rightmost_zone, i;
943 leftmost_zone = vik_viewport_leftmost_zone( vvp );
944 rightmost_zone = vik_viewport_rightmost_zone( vvp );
945 for ( i = leftmost_zone; i <= rightmost_zone; ++i ) {
946 vik_viewport_corners_for_zonen ( vvp, i, &ul, &br );
947 maps_layer_draw_section ( vml, vvp, &ul, &br );
948 }
949 }
950 else {
951 vik_viewport_screen_to_coord ( vvp, 0, 0, &ul );
952 vik_viewport_screen_to_coord ( vvp, vik_viewport_get_width(vvp), vik_viewport_get_height(vvp), &br );
953
954 maps_layer_draw_section ( vml, vvp, &ul, &br );
955 }
956 }
957}
958
959/*************************/
960/****** DOWNLOADING ******/
961/*************************/
962
963/* pass along data to thread, exists even if layer is deleted. */
964typedef struct {
965 gchar *cache_dir;
966 gchar *filename_buf;
967 gint x0, y0, xf, yf;
968 MapCoord mapcoord;
969 gint maptype;
970 gint maxlen;
971 gint mapstoget;
972 gint redownload;
7114e879 973 gboolean refresh_display;
550fd035
QT
974 VikMapsLayer *vml;
975 VikViewport *vvp;
976 gboolean map_layer_alive;
977 GMutex *mutex;
50a14534
EB
978} MapDownloadInfo;
979
980static void mdi_free ( MapDownloadInfo *mdi )
981{
550fd035 982 g_mutex_free(mdi->mutex);
50a14534 983 g_free ( mdi->cache_dir );
e65028db 984 mdi->cache_dir = NULL;
50a14534 985 g_free ( mdi->filename_buf );
e65028db 986 mdi->filename_buf = NULL;
50a14534
EB
987 g_free ( mdi );
988}
989
7bb60307 990static void weak_ref_cb(gpointer ptr, GObject * dead_vml)
550fd035 991{
7bb60307 992 MapDownloadInfo *mdi = ptr;
550fd035
QT
993 g_mutex_lock(mdi->mutex);
994 mdi->map_layer_alive = FALSE;
995 g_mutex_unlock(mdi->mutex);
996}
997
634eca0a 998static int map_download_thread ( MapDownloadInfo *mdi, gpointer threaddata )
50a14534 999{
825413ba 1000 void *handle = vik_map_source_download_handle_init(MAPS_LAYER_NTH_TYPE(mdi->maptype));
50a14534
EB
1001 guint donemaps = 0;
1002 gint x, y;
1003 for ( x = mdi->x0; x <= mdi->xf; x++ )
1004 {
1005 for ( y = mdi->y0; y <= mdi->yf; y++ )
1006 {
94493114 1007 gboolean remove_mem_cache = FALSE;
84628352 1008 gboolean need_download = FALSE;
50a14534 1009 g_snprintf ( mdi->filename_buf, mdi->maxlen, DIRSTRUCTURE,
820c59f4 1010 mdi->cache_dir, vik_map_source_get_uniq_id(MAPS_LAYER_NTH_TYPE(mdi->maptype)),
50a14534
EB
1011 mdi->mapcoord.scale, mdi->mapcoord.z, x, y );
1012
84628352 1013 donemaps++;
634eca0a 1014 int res = a_background_thread_progress ( threaddata, ((gdouble)donemaps) / mdi->mapstoget ); /* this also calls testcancel */
825413ba
SW
1015 if (res != 0) {
1016 vik_map_source_download_handle_cleanup(MAPS_LAYER_NTH_TYPE(mdi->maptype), handle);
634eca0a 1017 return -1;
825413ba 1018 }
84628352 1019
a0058e48 1020 if ( g_file_test ( mdi->filename_buf, G_FILE_TEST_EXISTS ) == FALSE ) {
6a4a29aa
JJ
1021 need_download = TRUE;
1022 remove_mem_cache = TRUE;
a0058e48
JJ
1023
1024 } else { /* in case map file already exists */
1025 switch (mdi->redownload) {
1026 case REDOWNLOAD_NONE:
1027 continue;
1028
1029 case REDOWNLOAD_BAD:
1030 {
1031 /* see if this one is bad or what */
1032 GError *gx = NULL;
1033 GdkPixbuf *pixbuf = gdk_pixbuf_new_from_file ( mdi->filename_buf, &gx );
1034 if (gx || (!pixbuf)) {
1035 g_remove ( mdi->filename_buf );
1036 need_download = TRUE;
1037 remove_mem_cache = TRUE;
1038 g_error_free ( gx );
1039
1040 } else {
1041 g_object_unref ( pixbuf );
1042 }
1043 break;
1044 }
1045
1046 case REDOWNLOAD_NEW:
1047 need_download = TRUE;
1048 remove_mem_cache = TRUE;
1049 break;
1050
1051 case REDOWNLOAD_ALL:
1052 /* FIXME: need a better way than to erase file in case of server/network problem */
1053 g_remove ( mdi->filename_buf );
1054 need_download = TRUE;
1055 remove_mem_cache = TRUE;
1056 break;
1057
1058 case DOWNLOAD_OR_REFRESH:
1059 remove_mem_cache = TRUE;
1060 break;
1061
1062 default:
1063 g_warning ( "redownload state %d unknown\n", mdi->redownload);
1064 }
1065 }
94493114 1066
94493114 1067 mdi->mapcoord.x = x; mdi->mapcoord.y = y;
84628352
QT
1068
1069 if (need_download) {
825413ba 1070 if ( vik_map_source_download( MAPS_LAYER_NTH_TYPE(mdi->maptype), &(mdi->mapcoord), mdi->filename_buf, handle))
94493114 1071 continue;
84628352 1072 }
94493114 1073
94493114
QT
1074 g_mutex_lock(mdi->mutex);
1075 if (remove_mem_cache)
820c59f4 1076 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 1077 if (mdi->refresh_display && mdi->map_layer_alive) {
94493114 1078 /* TODO: check if it's on visible area */
da121f9b 1079 vik_layer_emit_update ( VIK_LAYER(mdi->vml) ); // NB update display from background
a0b59f2f 1080 }
94493114 1081 g_mutex_unlock(mdi->mutex);
94493114
QT
1082 mdi->mapcoord.x = mdi->mapcoord.y = 0; /* we're temporarily between downloads */
1083
50a14534
EB
1084 }
1085 }
825413ba 1086 vik_map_source_download_handle_cleanup(MAPS_LAYER_NTH_TYPE(mdi->maptype), handle);
04e54492
QT
1087 g_mutex_lock(mdi->mutex);
1088 if (mdi->map_layer_alive)
7bb60307 1089 g_object_weak_unref(G_OBJECT(mdi->vml), weak_ref_cb, mdi);
04e54492 1090 g_mutex_unlock(mdi->mutex);
634eca0a 1091 return 0;
50a14534
EB
1092}
1093
1094static void mdi_cancel_cleanup ( MapDownloadInfo *mdi )
1095{
1096 if ( mdi->mapcoord.x || mdi->mapcoord.y )
1097 {
1098 g_snprintf ( mdi->filename_buf, mdi->maxlen, DIRSTRUCTURE,
820c59f4 1099 mdi->cache_dir, vik_map_source_get_uniq_id(MAPS_LAYER_NTH_TYPE(mdi->maptype)),
50a14534 1100 mdi->mapcoord.scale, mdi->mapcoord.z, mdi->mapcoord.x, mdi->mapcoord.y );
45acf79e 1101 if ( g_file_test ( mdi->filename_buf, G_FILE_TEST_EXISTS ) == TRUE)
50a14534 1102 {
8c060406 1103 g_remove ( mdi->filename_buf );
50a14534
EB
1104 }
1105 }
1106}
1107
1108static void start_download_thread ( VikMapsLayer *vml, VikViewport *vvp, const VikCoord *ul, const VikCoord *br, gint redownload )
1109{
1110 gdouble xzoom = vml->xmapzoom ? vml->xmapzoom : vik_viewport_get_xmpp ( vvp );
1111 gdouble yzoom = vml->ymapzoom ? vml->ymapzoom : vik_viewport_get_ympp ( vvp );
1112 MapCoord ulm, brm;
820c59f4 1113 VikMapSource *map = MAPS_LAYER_NTH_TYPE(vml->maptype);
2673b29d
RN
1114
1115 // Don't ever attempt download on direct access
1116 if ( vik_map_source_is_direct_file_access ( map ) )
1117 return;
1118
820c59f4
GB
1119 if ( vik_map_source_coord_to_mapcoord ( map, ul, xzoom, yzoom, &ulm )
1120 && vik_map_source_coord_to_mapcoord ( map, br, xzoom, yzoom, &brm ) )
50a14534
EB
1121 {
1122 MapDownloadInfo *mdi = g_malloc ( sizeof(MapDownloadInfo) );
1123 gint a, b;
1124
550fd035
QT
1125 mdi->vml = vml;
1126 mdi->vvp = vvp;
1127 mdi->map_layer_alive = TRUE;
1128 mdi->mutex = g_mutex_new();
7114e879 1129 mdi->refresh_display = TRUE;
550fd035 1130
50a14534
EB
1131 /* cache_dir and buffer for dest filename */
1132 mdi->cache_dir = g_strdup ( vml->cache_dir );
1133 mdi->maxlen = strlen ( vml->cache_dir ) + 40;
1134 mdi->filename_buf = g_malloc ( mdi->maxlen * sizeof(gchar) );
1135 mdi->maptype = vml->maptype;
1136
1137 mdi->mapcoord = ulm;
1138
1139 mdi->redownload = redownload;
1140
1141 mdi->x0 = MIN(ulm.x, brm.x);
1142 mdi->xf = MAX(ulm.x, brm.x);
1143 mdi->y0 = MIN(ulm.y, brm.y);
1144 mdi->yf = MAX(ulm.y, brm.y);
1145
1146 mdi->mapstoget = 0;
1147
1148 if ( mdi->redownload ) {
1149 mdi->mapstoget = (mdi->xf - mdi->x0 + 1) * (mdi->yf - mdi->y0 + 1);
1150 } else {
1151 /* calculate how many we need */
1152 for ( a = mdi->x0; a <= mdi->xf; a++ )
1153 {
1154 for ( b = mdi->y0; b <= mdi->yf; b++ )
1155 {
1156 g_snprintf ( mdi->filename_buf, mdi->maxlen, DIRSTRUCTURE,
820c59f4 1157 vml->cache_dir, vik_map_source_get_uniq_id(map), ulm.scale,
50a14534 1158 ulm.z, a, b );
45acf79e 1159 if ( g_file_test ( mdi->filename_buf, G_FILE_TEST_EXISTS ) == FALSE )
50a14534
EB
1160 mdi->mapstoget++;
1161 }
1162 }
1163 }
1164
1165 mdi->mapcoord.x = mdi->mapcoord.y = 0; /* for cleanup -- no current map */
1166
1167 if ( mdi->mapstoget )
1168 {
97634600
GB
1169 const gchar *tmp_str;
1170 gchar *tmp;
50a14534 1171
97634600
GB
1172 if (redownload)
1173 {
1174 if (redownload == REDOWNLOAD_BAD)
1175 tmp_str = ngettext("Redownloading up to %d %s map...", "Redownloading up to %d %s maps...", mdi->mapstoget);
1176 else
1177 tmp_str = ngettext("Redownloading %d %s map...", "Redownloading %d %s maps...", mdi->mapstoget);
1178 }
1179 else
1180 {
1181 tmp_str = ngettext("Downloading %d %s map...", "Downloading %d %s maps...", mdi->mapstoget);
1182 }
1183 tmp = g_strdup_printf ( tmp_str, mdi->mapstoget, MAPS_LAYER_NTH_LABEL(vml->maptype));
1184
7bb60307 1185 g_object_weak_ref(G_OBJECT(mdi->vml), weak_ref_cb, mdi);
50a14534
EB
1186 /* launch the thread */
1187 a_background_thread ( VIK_GTK_WINDOW_FROM_LAYER(vml), /* parent window */
1188 tmp, /* description string */
1189 (vik_thr_func) map_download_thread, /* function to call within thread */
1190 mdi, /* pass along data */
1191 (vik_thr_free_func) mdi_free, /* function to free pass along data */
1192 (vik_thr_free_func) mdi_cancel_cleanup,
1193 mdi->mapstoget );
1194 g_free ( tmp );
1195 }
1196 else
1197 mdi_free ( mdi );
1198 }
1199}
1200
903dc0b4 1201void maps_layer_download_section ( VikMapsLayer *vml, VikViewport *vvp, VikCoord *ul, VikCoord *br, gdouble zoom)
7114e879 1202{
7114e879 1203 MapCoord ulm, brm;
820c59f4 1204 VikMapSource *map = MAPS_LAYER_NTH_TYPE(vml->maptype);
7114e879 1205
2673b29d
RN
1206 // Don't ever attempt download on direct access
1207 if ( vik_map_source_is_direct_file_access ( map ) )
1208 return;
1209
820c59f4
GB
1210 if (!vik_map_source_coord_to_mapcoord(map, ul, zoom, zoom, &ulm)
1211 || !vik_map_source_coord_to_mapcoord(map, br, zoom, zoom, &brm)) {
4258f4e2 1212 g_warning("%s() coord_to_mapcoord() failed", __PRETTY_FUNCTION__);
7114e879
QT
1213 return;
1214 }
1215
1216 MapDownloadInfo *mdi = g_malloc(sizeof(MapDownloadInfo));
1217 gint i, j;
1218
1219 mdi->vml = vml;
1220 mdi->vvp = vvp;
1221 mdi->map_layer_alive = TRUE;
1222 mdi->mutex = g_mutex_new();
903dc0b4 1223 mdi->refresh_display = TRUE;
7114e879
QT
1224
1225 mdi->cache_dir = g_strdup ( vml->cache_dir );
1226 mdi->maxlen = strlen ( vml->cache_dir ) + 40;
1227 mdi->filename_buf = g_malloc ( mdi->maxlen * sizeof(gchar) );
1228 mdi->maptype = vml->maptype;
1229
1230 mdi->mapcoord = ulm;
1231
1232 mdi->redownload = REDOWNLOAD_NONE;
1233
1234 mdi->x0 = MIN(ulm.x, brm.x);
1235 mdi->xf = MAX(ulm.x, brm.x);
1236 mdi->y0 = MIN(ulm.y, brm.y);
1237 mdi->yf = MAX(ulm.y, brm.y);
1238
1239 mdi->mapstoget = 0;
1240
1241 for (i = mdi->x0; i <= mdi->xf; i++) {
1242 for (j = mdi->y0; j <= mdi->yf; j++) {
1243 g_snprintf ( mdi->filename_buf, mdi->maxlen, DIRSTRUCTURE,
820c59f4 1244 vml->cache_dir, vik_map_source_get_uniq_id(map), ulm.scale,
7114e879 1245 ulm.z, i, j );
45acf79e 1246 if ( g_file_test ( mdi->filename_buf, G_FILE_TEST_EXISTS ) == FALSE )
7114e879
QT
1247 mdi->mapstoget++;
1248 }
1249 }
1250
1251 mdi->mapcoord.x = mdi->mapcoord.y = 0; /* for cleanup -- no current map */
1252
1253 if (mdi->mapstoget) {
4c77d5e0
GB
1254 gchar *tmp;
1255 const gchar *fmt;
eb6b0125
JJ
1256 fmt = ngettext("Downloading %d %s map...",
1257 "Downloading %d %s maps...",
1258 mdi->mapstoget);
4c77d5e0 1259 tmp = g_strdup_printf ( fmt, mdi->mapstoget, MAPS_LAYER_NTH_LABEL(vml->maptype) );
7114e879
QT
1260
1261 g_object_weak_ref(G_OBJECT(mdi->vml), weak_ref_cb, mdi);
1262 /* launch the thread */
1263 a_background_thread ( VIK_GTK_WINDOW_FROM_LAYER(vml), /* parent window */
1264 tmp, /* description string */
1265 (vik_thr_func) map_download_thread, /* function to call within thread */
1266 mdi, /* pass along data */
1267 (vik_thr_free_func) mdi_free, /* function to free pass along data */
1268 (vik_thr_free_func) mdi_cancel_cleanup,
1269 mdi->mapstoget );
1270 g_free ( tmp );
1271 }
1272 else
1273 mdi_free ( mdi );
1274}
1275
50a14534
EB
1276static void maps_layer_redownload_bad ( VikMapsLayer *vml )
1277{
1278 start_download_thread ( vml, vml->redownload_vvp, &(vml->redownload_ul), &(vml->redownload_br), REDOWNLOAD_BAD );
1279}
a7c1acf1 1280
50a14534
EB
1281static void maps_layer_redownload_all ( VikMapsLayer *vml )
1282{
1283 start_download_thread ( vml, vml->redownload_vvp, &(vml->redownload_ul), &(vml->redownload_br), REDOWNLOAD_ALL );
1284}
1285
a7c1acf1
GB
1286static void maps_layer_redownload_new ( VikMapsLayer *vml )
1287{
1288 start_download_thread ( vml, vml->redownload_vvp, &(vml->redownload_ul), &(vml->redownload_br), REDOWNLOAD_NEW );
1289}
1290
450d8665
RN
1291/**
1292 * Display a simple dialog with information about this particular map tile
1293 */
1294static void maps_layer_tile_info ( VikMapsLayer *vml )
1295{
1296 VikMapSource *map = MAPS_LAYER_NTH_TYPE(vml->maptype);
1297
1298 gdouble xzoom = vml->xmapzoom ? vml->xmapzoom : vik_viewport_get_xmpp ( vml->redownload_vvp );
1299 gdouble yzoom = vml->ymapzoom ? vml->ymapzoom : vik_viewport_get_ympp ( vml->redownload_vvp );
1300 MapCoord ulm;
1301
1302 if ( !vik_map_source_coord_to_mapcoord ( map, &(vml->redownload_ul), xzoom, yzoom, &ulm ) )
1303 return;
1304
1305 gchar *filename = NULL;
1306 gchar *message = NULL;
1307 gchar *source = NULL;
1308
1309 if ( vik_map_source_is_direct_file_access ( map ) ) {
1310 filename = g_strdup_printf ( DIRECTDIRACCESS, vml->cache_dir, ulm.scale, ulm.x, ulm.y, ".png" );
1311 source = g_strconcat ( "file://", filename, NULL );
1312 }
1313 else {
1314 filename = g_strdup_printf ( DIRSTRUCTURE, vml->cache_dir, vik_map_source_get_uniq_id(map), ulm.scale, ulm.z, ulm.x, ulm.y );
1315 source = g_strdup_printf ( "http://%s%s",
1316 vik_map_source_default_get_hostname ( VIK_MAP_SOURCE_DEFAULT(map) ),
1317 vik_map_source_default_get_uri ( VIK_MAP_SOURCE_DEFAULT(map), &ulm ) );
1318 }
1319
1320 if ( g_file_test ( filename, G_FILE_TEST_EXISTS ) ) {
1321
1322 // Get some timestamp information of the tile
1323 struct stat stat_buf;
1324 if ( g_stat ( filename, &stat_buf ) == 0 ) {
1325 time_t file_time = stat_buf.st_mtime;
445a0ba6 1326#if GLIB_CHECK_VERSION(2,26,0)
450d8665
RN
1327 GDateTime* gdt = g_date_time_new_from_unix_utc ( file_time );
1328 gchar *time = g_date_time_format ( gdt, "%c" );
445a0ba6 1329#else
e9db9279
RN
1330 GDate* gdate = g_date_new ();
1331 g_date_set_time_t ( gdate, file_time );
1332 char time[32];
1333 g_date_strftime ( time, sizeof(time), "%c", gdate );
1334 g_date_free ( gdate );
445a0ba6 1335#endif
450d8665
RN
1336 message = g_strdup_printf ( _("\nSource: %s\n\nTile File: %s\nTile File Timestamp: %s"), source, filename, time );
1337
445a0ba6 1338#if GLIB_CHECK_VERSION(2,26,0)
450d8665
RN
1339 g_free ( time );
1340 g_date_time_unref ( gdt);
445a0ba6 1341#endif
450d8665
RN
1342 }
1343 }
1344 else
1345 message = g_strdup_printf ( _("Source: %s\n\nNo Tile File!"), source );
1346
1347 // Show the info
1348 a_dialog_info_msg ( VIK_GTK_WINDOW_FROM_LAYER(vml), message );
1349
1350 g_free ( message );
1351 g_free ( source );
1352 g_free ( filename );
1353}
1354
50a14534
EB
1355static gboolean maps_layer_download_release ( VikMapsLayer *vml, GdkEventButton *event, VikViewport *vvp )
1356{
941aa6e9
AF
1357 if (!vml || vml->vl.type != VIK_LAYER_MAPS)
1358 return FALSE;
50a14534
EB
1359 if ( vml->dl_tool_x != -1 && vml->dl_tool_y != -1 )
1360 {
1361 if ( event->button == 1 )
1362 {
1363 VikCoord ul, br;
1364 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 );
1365 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 1366 start_download_thread ( vml, vvp, &ul, &br, DOWNLOAD_OR_REFRESH );
50a14534
EB
1367 vml->dl_tool_x = vml->dl_tool_y = -1;
1368 return TRUE;
1369 }
1370 else
1371 {
1372 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) );
1373 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) );
1374
1375 vml->redownload_vvp = vvp;
1376
1377 vml->dl_tool_x = vml->dl_tool_y = -1;
1378
1379 if ( ! vml->dl_right_click_menu ) {
1380 GtkWidget *item;
1381 vml->dl_right_click_menu = GTK_MENU ( gtk_menu_new () );
1382
94ee2264 1383 item = gtk_menu_item_new_with_mnemonic ( _("Redownload _Bad Map(s)") );
50a14534
EB
1384 g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(maps_layer_redownload_bad), vml );
1385 gtk_menu_shell_append ( GTK_MENU_SHELL(vml->dl_right_click_menu), item );
1386
94ee2264 1387 item = gtk_menu_item_new_with_mnemonic ( _("Redownload _New Map(s)") );
a7c1acf1
GB
1388 g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(maps_layer_redownload_new), vml );
1389 gtk_menu_shell_append ( GTK_MENU_SHELL(vml->dl_right_click_menu), item );
1390
94ee2264 1391 item = gtk_menu_item_new_with_mnemonic ( _("Redownload _All Map(s)") );
50a14534
EB
1392 g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(maps_layer_redownload_all), vml );
1393 gtk_menu_shell_append ( GTK_MENU_SHELL(vml->dl_right_click_menu), item );
450d8665
RN
1394
1395 item = gtk_image_menu_item_new_with_mnemonic ( _("_Show Tile Information") );
1396 gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_INFO, GTK_ICON_SIZE_MENU) );
1397 g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(maps_layer_tile_info), vml );
1398 gtk_menu_shell_append (GTK_MENU_SHELL(vml->dl_right_click_menu), item);
50a14534
EB
1399 }
1400
1401 gtk_menu_popup ( vml->dl_right_click_menu, NULL, NULL, NULL, NULL, event->button, event->time );
1402 gtk_widget_show_all ( GTK_WIDGET(vml->dl_right_click_menu) );
1403 }
1404 }
1405 return FALSE;
1406}
1407
941aa6e9
AF
1408static gpointer maps_layer_download_create ( VikWindow *vw, VikViewport *vvp)
1409{
1410 return vvp;
1411}
1412
50a14534
EB
1413static gboolean maps_layer_download_click ( VikMapsLayer *vml, GdkEventButton *event, VikViewport *vvp )
1414{
1415 MapCoord tmp;
941aa6e9
AF
1416 if (!vml || vml->vl.type != VIK_LAYER_MAPS)
1417 return FALSE;
820c59f4
GB
1418 VikMapSource *map = MAPS_LAYER_NTH_TYPE(vml->maptype);
1419 if ( vik_map_source_get_drawmode(map) == vik_viewport_get_drawmode ( vvp ) &&
1420 vik_map_source_coord_to_mapcoord ( map, vik_viewport_get_center ( vvp ),
50a14534
EB
1421 vml->xmapzoom ? vml->xmapzoom : vik_viewport_get_xmpp ( vvp ),
1422 vml->ymapzoom ? vml->ymapzoom : vik_viewport_get_ympp ( vvp ),
1423 &tmp ) ) {
1424 vml->dl_tool_x = event->x, vml->dl_tool_y = event->y;
1425 return TRUE;
1426 }
1427 return FALSE;
1428
1429
1430#if 0
1431 if ( __map_types[vml->maptype].drawmode == vik_viewport_get_drawmode ( vvp ) )
1432 {
1433 VikCoord coord;
1434 MapCoord mapcoord;
1435 vik_viewport_screen_to_coord ( vvp, event->x, event->y, &coord );
1436 if ( __map_types[vml->maptype].coord_to_mapcoord ( &coord,
1437 vml->xmapzoom ? vml->xmapzoom : vik_viewport_get_xmpp ( vvp ),
1438 vml->ymapzoom ? vml->ymapzoom : vik_viewport_get_ympp ( vvp ),
1439 &mapcoord ) ) {
1440 gchar *filename_buf = g_strdup_printf ( DIRSTRUCTURE,
1441 vml->cache_dir, __map_types[vml->maptype].uniq_id,
1442 mapcoord.scale, mapcoord.z, mapcoord.x, mapcoord.y );
1443
1444 __map_types[vml->maptype].download ( &mapcoord, filename_buf );
1445 g_free ( filename_buf );
1446 vik_layer_emit_update ( VIK_LAYER(vml) );
1447 return TRUE;
1448 }
1449 }
1450 return FALSE;
1451#endif
1452}
1453
50817314 1454static void download_onscreen_maps ( gpointer vml_vvp[2], gint redownload )
50a14534
EB
1455{
1456 VikMapsLayer *vml = vml_vvp[0];
1457 VikViewport *vvp = vml_vvp[1];
314c1ccc 1458 VikViewportDrawMode vp_drawmode = vik_viewport_get_drawmode ( vvp );
50a14534
EB
1459
1460 gdouble xzoom = vml->xmapzoom ? vml->xmapzoom : vik_viewport_get_xmpp ( vvp );
1461 gdouble yzoom = vml->ymapzoom ? vml->ymapzoom : vik_viewport_get_ympp ( vvp );
1462
1463 VikCoord ul, br;
1464 MapCoord ulm, brm;
1465
1466 vik_viewport_screen_to_coord ( vvp, 0, 0, &ul );
1467 vik_viewport_screen_to_coord ( vvp, vik_viewport_get_width(vvp), vik_viewport_get_height(vvp), &br );
1468
820c59f4
GB
1469 VikMapSource *map = MAPS_LAYER_NTH_TYPE(vml->maptype);
1470 if ( vik_map_source_get_drawmode(map) == vp_drawmode &&
1471 vik_map_source_coord_to_mapcoord ( map, &ul, xzoom, yzoom, &ulm ) &&
1472 vik_map_source_coord_to_mapcoord ( map, &br, xzoom, yzoom, &brm ) )
50817314 1473 start_download_thread ( vml, vvp, &ul, &br, redownload );
820c59f4
GB
1474 else if (vik_map_source_get_drawmode(map) != vp_drawmode) {
1475 const gchar *drawmode_name = vik_viewport_get_drawmode_name (vvp, vik_map_source_get_drawmode(map));
4c77d5e0 1476 gchar *err = g_strdup_printf(_("Wrong drawmode for this map.\nSelect \"%s\" from View menu and try again."), _(drawmode_name));
314c1ccc
QT
1477 a_dialog_error_msg ( VIK_GTK_WINDOW_FROM_LAYER(vml), err );
1478 g_free(err);
1479 }
50a14534 1480 else
4c77d5e0 1481 a_dialog_error_msg ( VIK_GTK_WINDOW_FROM_LAYER(vml), _("Wrong zoom level for this map.") );
50a14534
EB
1482
1483}
1484
6a4a29aa 1485static void maps_layer_download_missing_onscreen_maps ( gpointer vml_vvp[2] )
50817314
GB
1486{
1487 download_onscreen_maps( vml_vvp, REDOWNLOAD_NONE);
1488}
1489
6a4a29aa
JJ
1490static void maps_layer_download_new_onscreen_maps ( gpointer vml_vvp[2] )
1491{
1492 download_onscreen_maps( vml_vvp, REDOWNLOAD_NEW);
1493}
1494
50817314
GB
1495static void maps_layer_redownload_all_onscreen_maps ( gpointer vml_vvp[2] )
1496{
1497 download_onscreen_maps( vml_vvp, REDOWNLOAD_ALL);
1498}
1499
50a14534
EB
1500static void maps_layer_add_menu_items ( VikMapsLayer *vml, GtkMenu *menu, VikLayersPanel *vlp )
1501{
1502 static gpointer pass_along[2];
1503 GtkWidget *item;
1504 pass_along[0] = vml;
1505 pass_along[1] = vik_layers_panel_get_viewport( VIK_LAYERS_PANEL(vlp) );
1506
1507 item = gtk_menu_item_new();
1508 gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item );
1509 gtk_widget_show ( item );
1510
555ec6f6
RN
1511 /* Now with icons */
1512 item = gtk_image_menu_item_new_with_mnemonic ( _("Download _Missing Onscreen Maps") );
1513 gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_ADD, GTK_ICON_SIZE_MENU) );
6a4a29aa 1514 g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(maps_layer_download_missing_onscreen_maps), pass_along );
50a14534
EB
1515 gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
1516 gtk_widget_show ( item );
50817314 1517
c81ded98 1518 if ( vik_map_source_supports_download_only_new (MAPS_LAYER_NTH_TYPE(vml->maptype)) ) {
555ec6f6
RN
1519 item = gtk_image_menu_item_new_with_mnemonic ( _("Download _New Onscreen Maps") );
1520 gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_REDO, GTK_ICON_SIZE_MENU) );
6a4a29aa
JJ
1521 g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(maps_layer_download_new_onscreen_maps), pass_along );
1522 gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
1523 gtk_widget_show ( item );
1524 }
1525
555ec6f6
RN
1526 item = gtk_image_menu_item_new_with_mnemonic ( _("Reload _All Onscreen Maps") );
1527 gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_REFRESH, GTK_ICON_SIZE_MENU) );
50817314
GB
1528 g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(maps_layer_redownload_all_onscreen_maps), pass_along );
1529 gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
1530 gtk_widget_show ( item );
50a14534 1531}
6b59f63d
RN
1532
1533/**
1534 * Enable downloading maps of the current screen area either 'new' or 'everything'
1535 */
1536void vik_maps_layer_download ( VikMapsLayer *vml, VikViewport *vvp, gboolean only_new )
1537{
1538 if ( !vml ) return;
1539 if ( !vvp ) return;
1540
1541 static gpointer pass_along[2];
1542 pass_along[0] = vml;
1543 pass_along[1] = vvp;
1544
1545 if ( only_new )
1546 // Get only new maps
1547 maps_layer_download_new_onscreen_maps ( pass_along );
1548 else
1549 // Redownload everything
1550 maps_layer_redownload_all_onscreen_maps ( pass_along );
1551}