]> git.street.me.uk Git - andy/viking.git/blame - src/vikmapslayer.c
Read OSM Metatile capability and basic test with single example metatile.
[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>
0fb11294 6 * Copyright (c) 2013, Rob Norris <rw_norris@hotmail.com>
50a14534 7 * UTM multi-zone stuff by Kit Transue <notlostyet@didactek.com>
cdcaf41c 8 * Dynamic map type by Guilhem Bonnefille <guilhem.bonnefille@gmail.com>
50a14534
EB
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
19 *
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
23 *
24 */
25
4c77d5e0
GB
26#ifdef HAVE_CONFIG_H
27#include "config.h"
28#endif
29
50a14534
EB
30#include <gtk/gtk.h>
31#include <gdk-pixbuf/gdk-pixdata.h>
45acf79e
MA
32#include <glib.h>
33#include <glib/gstdio.h>
4c77d5e0
GB
34#include <glib/gi18n.h>
35
8c00358d 36#ifdef HAVE_STRING_H
50a14534 37#include <string.h>
8c00358d
GB
38#endif
39#ifdef HAVE_MATH_H
50a14534 40#include <math.h>
8c00358d
GB
41#endif
42
45acf79e 43#ifdef HAVE_UNISTD_H
50a14534 44#include <unistd.h>
45acf79e 45#endif
50a14534 46
a7023a1b 47#include "viking.h"
450d8665 48#include "vikmapsourcedefault.h"
1b14d0d2 49#include "vikutils.h"
9979924f 50#include "maputils.h"
50a14534 51#include "mapcache.h"
50a14534 52#include "background.h"
a7023a1b
RN
53#include "preferences.h"
54#include "vikmapslayer.h"
bce3a7b0
EB
55#include "icons/icons.h"
56
0fb11294
RN
57#ifdef HAVE_SQLITE3_H
58#include "sqlite3.h"
59#include <gio/gio.h>
60#endif
61
0f7e9133
RN
62#define VIK_SETTINGS_MAP_MAX_TILES "maps_max_tiles"
63static gint MAX_TILES = 1000;
64
65#define VIK_SETTINGS_MAP_MIN_SHRINKFACTOR "maps_min_shrinkfactor"
66#define VIK_SETTINGS_MAP_MAX_SHRINKFACTOR "maps_max_shrinkfactor"
67static gdouble MAX_SHRINKFACTOR = 8.0000001; /* zoom 1 viewing 8-tiles */
68static gdouble MIN_SHRINKFACTOR = 0.0312499; /* zoom 32 viewing 1-tiles */
69
70#define VIK_SETTINGS_MAP_REAL_MIN_SHRINKFACTOR "maps_real_min_shrinkfactor"
71static gdouble REAL_MIN_SHRINKFACTOR = 0.0039062499; /* if shrinkfactor is between MAX and REAL_MAX, will only check for existence */
72
50a14534
EB
73/****** MAP TYPES ******/
74
cdcaf41c
QT
75static GList *__map_types = NULL;
76
77#define NUM_MAP_TYPES g_list_length(__map_types)
50a14534 78
cdcaf41c 79/* List of label for each map type */
a8876892 80static gchar **params_maptypes = NULL;
cdcaf41c
QT
81
82/* Corresponding IDS. (Cf. field uniq_id in VikMapsLayer struct) */
a8876892 83static guint *params_maptypes_ids = NULL;
50a14534
EB
84
85/******** MAPZOOMS *********/
86
fcc2786b
SW
87static 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 };
88static 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 };
89static 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 90
d756fb5c 91#define NUM_MAPZOOMS (sizeof(params_mapzooms)/sizeof(params_mapzooms[0]) - 1)
50a14534
EB
92
93/**************************/
94
95
07059501 96static void maps_layer_post_read (VikLayer *vl, VikViewport *vp, gboolean from_file);
7924723c 97static const gchar* maps_layer_tooltip ( VikMapsLayer *vml );
911400b5
AF
98static void maps_layer_marshall( VikMapsLayer *vml, guint8 **data, gint *len );
99static VikMapsLayer *maps_layer_unmarshall( guint8 *data, gint len, VikViewport *vvp );
158b3642
RN
100static gboolean maps_layer_set_param ( VikMapsLayer *vml, guint16 id, VikLayerParamData data, VikViewport *vvp, gboolean is_file_operation );
101static VikLayerParamData maps_layer_get_param ( VikMapsLayer *vml, guint16 id, gboolean is_file_operation );
db43cfa4 102static void maps_layer_change_param ( GtkWidget *widget, ui_change_values values );
50a14534
EB
103static void maps_layer_draw ( VikMapsLayer *vml, VikViewport *vvp );
104static VikMapsLayer *maps_layer_new ( VikViewport *vvp );
105static void maps_layer_free ( VikMapsLayer *vml );
106static gboolean maps_layer_download_release ( VikMapsLayer *vml, GdkEventButton *event, VikViewport *vvp );
107static gboolean maps_layer_download_click ( VikMapsLayer *vml, GdkEventButton *event, VikViewport *vvp );
941aa6e9 108static gpointer maps_layer_download_create ( VikWindow *vw, VikViewport *vvp );
50a14534
EB
109static void maps_layer_set_cache_dir ( VikMapsLayer *vml, const gchar *dir );
110static void start_download_thread ( VikMapsLayer *vml, VikViewport *vvp, const VikCoord *ul, const VikCoord *br, gint redownload );
111static void maps_layer_add_menu_items ( VikMapsLayer *vml, GtkMenu *menu, VikLayersPanel *vlp );
e2cb421f 112static guint map_uniq_id_to_index ( guint uniq_id );
50a14534
EB
113
114
115static VikLayerParamScale params_scales[] = {
116 /* min, max, step, digits (decimal places) */
117 { 0, 255, 3, 0 }, /* alpha */
118};
119
5a1e5516 120static VikLayerParamData id_default ( void ) { return VIK_LPD_UINT ( 19 ); } // OSM MapQuest maps
a7023a1b
RN
121static VikLayerParamData directory_default ( void )
122{
123 VikLayerParamData data;
b781c9db 124 VikLayerParamData *pref = a_preferences_get(VIKING_PREFERENCES_NAMESPACE "maplayer_default_dir");
9414408e 125 if (pref) data.s = g_strdup ( pref->s ); else data.s = "";
a7023a1b
RN
126 return data;
127}
0fb11294
RN
128static VikLayerParamData file_default ( void )
129{
130 VikLayerParamData data;
131 data.s = "";
132 return data;
133}
a7023a1b
RN
134static VikLayerParamData alpha_default ( void ) { return VIK_LPD_UINT ( 255 ); }
135static VikLayerParamData mapzoom_default ( void ) { return VIK_LPD_UINT ( 0 ); }
136
d281e8b4
RN
137static gchar *cache_types[] = { "Viking", N_("OSM"), NULL };
138static VikMapsCacheLayout cache_layout_default_value = VIK_MAPS_CACHE_LAYOUT_VIKING;
139static VikLayerParamData cache_layout_default ( void ) { return VIK_LPD_UINT ( cache_layout_default_value ); }
140
50a14534 141VikLayerParam maps_layer_params[] = {
5a1e5516
RN
142 // NB mode => id - But can't break file format just to rename something better
143 { VIK_LAYER_MAPS, "mode", VIK_LAYER_PARAM_UINT, VIK_LAYER_GROUP_NONE, N_("Map Type:"), VIK_LAYER_WIDGET_COMBOBOX, NULL, NULL, NULL, id_default, NULL, NULL },
a87f8fa1 144 { VIK_LAYER_MAPS, "directory", VIK_LAYER_PARAM_STRING, VIK_LAYER_GROUP_NONE, N_("Maps Directory:"), VIK_LAYER_WIDGET_FOLDERENTRY, NULL, NULL, NULL, directory_default, NULL, NULL },
d281e8b4
RN
145 { VIK_LAYER_MAPS, "cache_type", VIK_LAYER_PARAM_UINT, VIK_LAYER_GROUP_NONE, N_("Cache Layout:"), VIK_LAYER_WIDGET_COMBOBOX, cache_types, NULL,
146 N_("This determines the tile storage layout on disk"), cache_layout_default, NULL, NULL },
857baaa3 147 { VIK_LAYER_MAPS, "mapfile", VIK_LAYER_PARAM_STRING, VIK_LAYER_GROUP_NONE, N_("Map File:"), VIK_LAYER_WIDGET_FILEENTRY, GINT_TO_POINTER(VF_FILTER_MBTILES), NULL,
0fb11294 148 N_("An MBTiles file. Only applies when the map type method is 'MBTiles'"), file_default, NULL, NULL },
a7023a1b 149 { VIK_LAYER_MAPS, "alpha", VIK_LAYER_PARAM_UINT, VIK_LAYER_GROUP_NONE, N_("Alpha:"), VIK_LAYER_WIDGET_HSCALE, params_scales, NULL,
a87f8fa1
RN
150 N_("Control the Alpha value for transparency effects"), alpha_default, NULL, NULL },
151 { 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, NULL, NULL },
56c6d6b2 152 { VIK_LAYER_MAPS, "adlonlymissing", VIK_LAYER_PARAM_BOOLEAN, VIK_LAYER_GROUP_NONE, N_("Autodownload Only Gets Missing Maps:"), VIK_LAYER_WIDGET_CHECKBUTTON, NULL, NULL,
a87f8fa1 153 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, NULL, NULL },
a7023a1b
RN
154 { VIK_LAYER_MAPS, "mapzoom", VIK_LAYER_PARAM_UINT, VIK_LAYER_GROUP_NONE, N_("Zoom Level:"), VIK_LAYER_WIDGET_COMBOBOX, params_mapzooms, NULL,
155 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."),
a87f8fa1 156 mapzoom_default, NULL, NULL },
50a14534
EB
157};
158
382566c3
RN
159enum {
160 PARAM_MAPTYPE=0,
161 PARAM_CACHE_DIR,
d281e8b4 162 PARAM_CACHE_LAYOUT,
0fb11294 163 PARAM_FILE,
382566c3
RN
164 PARAM_ALPHA,
165 PARAM_AUTODOWNLOAD,
166 PARAM_ONLYMISSING,
167 PARAM_MAPZOOM,
168 NUM_PARAMS
169};
50a14534 170
0d66c56c
RN
171void maps_layer_set_autodownload_default ( gboolean autodownload )
172{
173 // Set appropriate function
174 if ( autodownload )
175 maps_layer_params[PARAM_AUTODOWNLOAD].default_value = vik_lpd_true_default;
176 else
177 maps_layer_params[PARAM_AUTODOWNLOAD].default_value = vik_lpd_false_default;
178}
179
d281e8b4
RN
180void maps_layer_set_cache_default ( VikMapsCacheLayout layout )
181{
182 // Override default value returned by the default param function
183 cache_layout_default_value = layout;
184}
185
50a14534 186static VikToolInterface maps_tools[] = {
79dce0cb 187 { { "MapsDownload", "vik-icon-Maps Download", N_("_Maps Download"), NULL, N_("Maps Download"), 0 },
6b59f63d
RN
188 (VikToolConstructorFunc) maps_layer_download_create,
189 NULL,
190 NULL,
191 NULL,
192 (VikToolMouseFunc) maps_layer_download_click,
193 NULL,
194 (VikToolMouseFunc) maps_layer_download_release,
195 NULL,
ef5e8132 196 FALSE,
63959706 197 GDK_CURSOR_IS_PIXMAP, &cursor_mapdl_pixbuf, NULL },
50a14534
EB
198};
199
200VikLayerInterface vik_maps_layer_interface = {
db386630 201 "Map",
4c77d5e0 202 N_("Map"),
75078768 203 "<control><shift>M",
5bfafde9 204 &vikmapslayer_pixbuf,
50a14534
EB
205
206 maps_tools,
207 sizeof(maps_tools) / sizeof(maps_tools[0]),
208
209 maps_layer_params,
210 NUM_PARAMS,
211 NULL,
212 0,
213
5a4a28bf
QT
214 VIK_MENU_ITEM_ALL,
215
50a14534
EB
216 (VikLayerFuncCreate) maps_layer_new,
217 (VikLayerFuncRealize) NULL,
b112cbf5 218 (VikLayerFuncPostRead) maps_layer_post_read,
50a14534
EB
219 (VikLayerFuncFree) maps_layer_free,
220
221 (VikLayerFuncProperties) NULL,
222 (VikLayerFuncDraw) maps_layer_draw,
223 (VikLayerFuncChangeCoordMode) NULL,
224
20c7a3a0
QT
225 (VikLayerFuncSetMenuItemsSelection) NULL,
226 (VikLayerFuncGetMenuItemsSelection) NULL,
227
50a14534
EB
228 (VikLayerFuncAddMenuItems) maps_layer_add_menu_items,
229 (VikLayerFuncSublayerAddMenuItems) NULL,
230
231 (VikLayerFuncSublayerRenameRequest) NULL,
232 (VikLayerFuncSublayerToggleVisible) NULL,
9da7faf2 233 (VikLayerFuncSublayerTooltip) NULL,
7924723c 234 (VikLayerFuncLayerTooltip) maps_layer_tooltip,
a5dcfdb7 235 (VikLayerFuncLayerSelected) NULL,
50a14534 236
911400b5
AF
237 (VikLayerFuncMarshall) maps_layer_marshall,
238 (VikLayerFuncUnmarshall) maps_layer_unmarshall,
50a14534
EB
239
240 (VikLayerFuncSetParam) maps_layer_set_param,
241 (VikLayerFuncGetParam) maps_layer_get_param,
db43cfa4 242 (VikLayerFuncChangeParam) maps_layer_change_param,
50a14534
EB
243
244 (VikLayerFuncReadFileData) NULL,
245 (VikLayerFuncWriteFileData) NULL,
246
33534cd8 247 (VikLayerFuncDeleteItem) NULL,
d5874ef9 248 (VikLayerFuncCutItem) NULL,
50a14534
EB
249 (VikLayerFuncCopyItem) NULL,
250 (VikLayerFuncPasteItem) NULL,
251 (VikLayerFuncFreeCopiedItem) NULL,
70a23263 252 (VikLayerFuncDragDropRequest) NULL,
77ad64fa
RN
253
254 (VikLayerFuncSelectClick) NULL,
08f14055
RN
255 (VikLayerFuncSelectMove) NULL,
256 (VikLayerFuncSelectRelease) NULL,
e46f259a 257 (VikLayerFuncSelectedViewportMenu) NULL,
50a14534
EB
258};
259
260struct _VikMapsLayer {
261 VikLayer vl;
262 guint maptype;
263 gchar *cache_dir;
d281e8b4 264 VikMapsCacheLayout cache_layout;
50a14534
EB
265 guint8 alpha;
266 guint mapzoom_id;
267 gdouble xmapzoom, ymapzoom;
268
269 gboolean autodownload;
382566c3 270 gboolean adl_only_missing;
10ca2bfe
QT
271 VikCoord *last_center;
272 gdouble last_xmpp;
273 gdouble last_ympp;
50a14534
EB
274
275 gint dl_tool_x, dl_tool_y;
276
277 GtkMenu *dl_right_click_menu;
278 VikCoord redownload_ul, redownload_br; /* right click menu only */
279 VikViewport *redownload_vvp;
0fb11294
RN
280 gchar *filename;
281#ifdef HAVE_SQLITE3_H
282 sqlite3 *mbtiles;
283#endif
50a14534
EB
284};
285
6a4a29aa
JJ
286enum { REDOWNLOAD_NONE = 0, /* download only missing maps */
287 REDOWNLOAD_BAD, /* download missing and bad maps */
288 REDOWNLOAD_NEW, /* download missing maps that are newer on server only */
289 REDOWNLOAD_ALL, /* download all maps */
290 DOWNLOAD_OR_REFRESH }; /* download missing maps and refresh cache */
50a14534 291
55ddef4e 292static VikLayerParam prefs[] = {
63959706 293 { 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"), NULL, NULL, NULL },
55ddef4e
JJ
294};
295
296void maps_layer_init ()
297{
298 VikLayerParamData tmp;
299 tmp.s = maps_layer_default_dir();
300 a_preferences_register(prefs, tmp, VIKING_PREFERENCES_GROUP_KEY);
0f7e9133
RN
301
302 gint max_tiles = MAX_TILES;
303 if ( a_settings_get_integer ( VIK_SETTINGS_MAP_MAX_TILES, &max_tiles ) )
304 MAX_TILES = max_tiles;
305
306 gdouble gdtmp;
307 if ( a_settings_get_double ( VIK_SETTINGS_MAP_MIN_SHRINKFACTOR, &gdtmp ) )
308 MIN_SHRINKFACTOR = gdtmp;
309
310 if ( a_settings_get_double ( VIK_SETTINGS_MAP_MAX_SHRINKFACTOR, &gdtmp ) )
311 MAX_SHRINKFACTOR = gdtmp;
312
313 if ( a_settings_get_double ( VIK_SETTINGS_MAP_REAL_MIN_SHRINKFACTOR, &gdtmp ) )
314 REAL_MIN_SHRINKFACTOR = gdtmp;
55ddef4e 315}
50a14534 316
cdcaf41c
QT
317/****************************************/
318/******** MAPS LAYER TYPES **************/
319/****************************************/
320
5a1e5516 321void _add_map_source ( guint16 id, const char *label, VikMapSource *map )
e2cb421f 322{
a8876892
GB
323 gsize len = 0;
324 if (params_maptypes)
325 len = g_strv_length (params_maptypes);
cdcaf41c 326 /* Add the label */
a8876892
GB
327 params_maptypes = g_realloc (params_maptypes, (len+2)*sizeof(gchar*));
328 params_maptypes[len] = g_strdup (label);
329 params_maptypes[len+1] = NULL;
cdcaf41c
QT
330
331 /* Add the id */
a8876892
GB
332 params_maptypes_ids = g_realloc (params_maptypes_ids, (len+2)*sizeof(guint));
333 params_maptypes_ids[len] = id;
334 params_maptypes_ids[len+1] = 0;
cdcaf41c
QT
335
336 /* We have to clone */
820c59f4 337 VikMapSource *clone = VIK_MAP_SOURCE(g_object_ref(map));
cdcaf41c
QT
338 /* Register the clone in the list */
339 __map_types = g_list_append(__map_types, clone);
340
341 /* Hack
e2cb421f 342 We have to ensure the mode LayerParam references the up-to-date
cdcaf41c
QT
343 GLists.
344 */
345 /*
346 memcpy(&maps_layer_params[0].widget_data, &params_maptypes, sizeof(gpointer));
347 memcpy(&maps_layer_params[0].extra_widget_data, &params_maptypes_ids, sizeof(gpointer));
348 */
349 maps_layer_params[0].widget_data = params_maptypes;
350 maps_layer_params[0].extra_widget_data = params_maptypes_ids;
351}
352
e2cb421f
GB
353void _update_map_source ( const char *label, VikMapSource *map, int index )
354{
355 GList *item = g_list_nth (__map_types, index);
356 g_object_unref (item->data);
357 item->data = g_object_ref (map);
358 /* Change previous data */
359 g_free (params_maptypes[index]);
360 params_maptypes[index] = g_strdup (label);
361}
362
17281ebd
GB
363/**
364 * maps_layer_register_map_source:
365 * @map: the new VikMapSource
366 *
367 * Register a new VikMapSource.
368 * Override existing one (equality of id).
369 */
e2cb421f
GB
370void maps_layer_register_map_source ( VikMapSource *map )
371{
372 g_assert(map != NULL);
373
5a1e5516 374 guint16 id = vik_map_source_get_uniq_id(map);
e2cb421f
GB
375 const char *label = vik_map_source_get_label(map);
376 g_assert(label != NULL);
377
378 int previous = map_uniq_id_to_index (id);
379 if (previous != NUM_MAP_TYPES)
380 {
381 _update_map_source (label, map, previous);
382 }
383 else
384 {
385 _add_map_source (id, label, map);
386 }
387}
388
a8876892
GB
389#define MAPS_LAYER_NTH_LABEL(n) (params_maptypes[n])
390#define MAPS_LAYER_NTH_ID(n) (params_maptypes_ids[n])
820c59f4 391#define MAPS_LAYER_NTH_TYPE(n) (VIK_MAP_SOURCE(g_list_nth_data(__map_types, (n))))
cdcaf41c 392
7114e879
QT
393gint vik_maps_layer_get_map_type(VikMapsLayer *vml)
394{
395 return(vml->maptype);
396}
397
398gchar *vik_maps_layer_get_map_label(VikMapsLayer *vml)
399{
400 return(g_strdup(MAPS_LAYER_NTH_LABEL(vml->maptype)));
401}
402
50a14534
EB
403/****************************************/
404/******** CACHE DIR STUFF ***************/
405/****************************************/
406
2673b29d 407#define DIRECTDIRACCESS "%s%d" G_DIR_SEPARATOR_S "%d" G_DIR_SEPARATOR_S "%d%s"
2eb18edc 408#define DIRECTDIRACCESS_WITH_NAME "%s%s" G_DIR_SEPARATOR_S "%d" G_DIR_SEPARATOR_S "%d" G_DIR_SEPARATOR_S "%d%s"
3d9454e6 409#define DIRSTRUCTURE "%st%ds%dz%d" G_DIR_SEPARATOR_S "%d" G_DIR_SEPARATOR_S "%d"
6a27c1bc
MA
410#define MAPS_CACHE_DIR maps_layer_default_dir()
411
50a14534 412#ifdef WINDOWS
6a27c1bc
MA
413#include <io.h>
414#define GLOBAL_MAPS_DIR "C:\\VIKING-MAPS\\"
415#define LOCAL_MAPS_DIR "VIKING-MAPS"
42293fc2
RN
416#elif defined __APPLE__
417#include <stdlib.h>
418#define GLOBAL_MAPS_DIR "/Library/cache/Viking/maps/"
419#define LOCAL_MAPS_DIR "/Library/Application Support/Viking/viking-maps"
50a14534 420#else /* POSIX */
50a14534 421#include <stdlib.h>
50a14534 422#define GLOBAL_MAPS_DIR "/var/cache/maps/"
6a27c1bc
MA
423#define LOCAL_MAPS_DIR ".viking-maps"
424#endif
50a14534 425
0c1044e9 426gchar *maps_layer_default_dir ()
50a14534 427{
3d9454e6
GB
428 static gchar *defaultdir = NULL;
429 if ( ! defaultdir )
50a14534
EB
430 {
431 /* Thanks to Mike Davison for the $VIKING_MAPS usage */
3d9454e6
GB
432 const gchar *mapdir = g_getenv("VIKING_MAPS");
433 if ( mapdir ) {
434 defaultdir = g_strdup ( mapdir );
45acf79e 435 } else if ( g_access ( GLOBAL_MAPS_DIR, W_OK ) == 0 ) {
3d9454e6 436 defaultdir = g_strdup ( GLOBAL_MAPS_DIR );
50a14534 437 } else {
6a27c1bc 438 const gchar *home = g_get_home_dir();
45acf79e 439 if (!home || g_access(home, W_OK))
3d9454e6
GB
440 home = g_get_home_dir ();
441 if ( home )
6a27c1bc 442 defaultdir = g_build_filename ( home, LOCAL_MAPS_DIR, NULL );
50a14534 443 else
6a27c1bc 444 defaultdir = g_strdup ( LOCAL_MAPS_DIR );
50a14534 445 }
3d9454e6
GB
446 if (defaultdir && (defaultdir[strlen(defaultdir)-1] != G_DIR_SEPARATOR))
447 {
448 /* Add the separator at the end */
449 gchar *tmp = defaultdir;
450 defaultdir = g_strconcat(tmp, G_DIR_SEPARATOR_S, NULL);
451 g_free(tmp);
452 }
453 g_debug("%s: defaultdir=%s", __FUNCTION__, defaultdir);
50a14534
EB
454 }
455 return defaultdir;
456}
457
50a14534
EB
458static void maps_layer_mkdir_if_default_dir ( VikMapsLayer *vml )
459{
45acf79e 460 if ( vml->cache_dir && strcmp ( vml->cache_dir, MAPS_CACHE_DIR ) == 0 && g_file_test ( vml->cache_dir, G_FILE_TEST_EXISTS ) == FALSE )
50a14534 461 {
f83131b9 462 g_mkdir ( vml->cache_dir, 0777 );
50a14534
EB
463 }
464}
465
466static void maps_layer_set_cache_dir ( VikMapsLayer *vml, const gchar *dir )
467{
50a14534 468 g_assert ( vml != NULL);
e65028db
GB
469 g_free ( vml->cache_dir );
470 vml->cache_dir = NULL;
32f1d63a 471 const gchar *mydir = dir;
50a14534
EB
472
473 if ( dir == NULL || dir[0] == '\0' )
6926d79a
RN
474 {
475 if ( a_preferences_get(VIKING_PREFERENCES_NAMESPACE "maplayer_default_dir") )
32f1d63a 476 mydir = a_preferences_get(VIKING_PREFERENCES_NAMESPACE "maplayer_default_dir")->s;
6926d79a 477 }
32f1d63a 478
1b14d0d2
RN
479 gchar *canonical_dir = vu_get_canonical_filename ( VIK_LAYER(vml), mydir );
480
32f1d63a 481 // Ensure cache_dir always ends with a separator
1b14d0d2
RN
482 guint len = strlen(canonical_dir);
483 if ( canonical_dir[len-1] != G_DIR_SEPARATOR )
50a14534 484 {
1b14d0d2
RN
485 vml->cache_dir = g_strconcat ( canonical_dir, G_DIR_SEPARATOR_S, NULL );
486 g_free ( canonical_dir );
487 }
488 else {
489 vml->cache_dir = canonical_dir;
50a14534 490 }
32f1d63a 491
50a14534
EB
492 maps_layer_mkdir_if_default_dir ( vml );
493}
494
0fb11294
RN
495static void maps_layer_set_file ( VikMapsLayer *vml, const gchar *name )
496{
497 if ( vml->filename )
498 g_free (vml->filename);
499 vml->filename = g_strdup (name);
500}
501
50a14534
EB
502/****************************************/
503/******** GOBJECT STUFF *****************/
504/****************************************/
505
506GType vik_maps_layer_get_type ()
507{
508 static GType vml_type = 0;
509
510 if (!vml_type)
511 {
512 static const GTypeInfo vml_info =
513 {
514 sizeof (VikMapsLayerClass),
515 NULL, /* base_init */
516 NULL, /* base_finalize */
517 NULL, /* class init */
518 NULL, /* class_finalize */
519 NULL, /* class_data */
520 sizeof (VikMapsLayer),
521 0,
522 NULL /* instance init */
523 };
524 vml_type = g_type_register_static ( VIK_LAYER_TYPE, "VikMapsLayer", &vml_info, 0 );
525 }
526
527 return vml_type;
528}
529
530/****************************************/
531/************** PARAMETERS **************/
532/****************************************/
533
d7e495b2 534static guint map_index_to_uniq_id (guint16 index)
50a14534
EB
535{
536 g_assert ( index < NUM_MAP_TYPES );
820c59f4 537 return vik_map_source_get_uniq_id(MAPS_LAYER_NTH_TYPE(index));
50a14534
EB
538}
539
540static guint map_uniq_id_to_index ( guint uniq_id )
541{
542 gint i;
543 for ( i = 0; i < NUM_MAP_TYPES; i++ )
820c59f4 544 if ( vik_map_source_get_uniq_id(MAPS_LAYER_NTH_TYPE(i)) == uniq_id )
50a14534
EB
545 return i;
546 return NUM_MAP_TYPES; /* no such thing */
547}
548
b03ae39b
RN
549#define VIK_SETTINGS_MAP_LICENSE_SHOWN "map_license_shown"
550
551/**
552 * Convenience function to display the license
553 */
554static void maps_show_license ( GtkWindow *parent, VikMapSource *map )
192e40fc 555{
b03ae39b
RN
556 a_dialog_license ( parent,
557 vik_map_source_get_label (map),
558 vik_map_source_get_license (map),
559 vik_map_source_get_license_url (map) );
192e40fc
RN
560}
561
158b3642 562static gboolean maps_layer_set_param ( VikMapsLayer *vml, guint16 id, VikLayerParamData data, VikViewport *vvp, gboolean is_file_operation )
50a14534
EB
563{
564 switch ( id )
565 {
566 case PARAM_CACHE_DIR: maps_layer_set_cache_dir ( vml, data.s ); break;
d281e8b4 567 case PARAM_CACHE_LAYOUT: if ( data.u < VIK_MAPS_CACHE_LAYOUT_NUM ) vml->cache_layout = data.u; break;
0fb11294 568 case PARAM_FILE: maps_layer_set_file ( vml, data.s ); break;
50a14534
EB
569 case PARAM_MAPTYPE: {
570 gint maptype = map_uniq_id_to_index(data.u);
b03ae39b
RN
571 if ( maptype == NUM_MAP_TYPES )
572 g_warning(_("Unknown map type"));
573 else {
574 vml->maptype = maptype;
575
576 // When loading from a file don't need the license reminder - ensure it's saved into the 'seen' list
577 if ( is_file_operation ) {
fad0a3f9 578 a_settings_set_integer_list_containing ( VIK_SETTINGS_MAP_LICENSE_SHOWN, data.u );
b03ae39b
RN
579 }
580 else {
581 VikMapSource *map = MAPS_LAYER_NTH_TYPE(vml->maptype);
582 if (vik_map_source_get_license (map) != NULL) {
583 // Check if licence for this map type has been shown before
fad0a3f9 584 if ( ! a_settings_get_integer_list_contains ( VIK_SETTINGS_MAP_LICENSE_SHOWN, data.u ) ) {
b03ae39b
RN
585 if ( vvp )
586 maps_show_license ( VIK_GTK_WINDOW_FROM_WIDGET(vvp), map );
fad0a3f9 587 a_settings_set_integer_list_containing ( VIK_SETTINGS_MAP_LICENSE_SHOWN, data.u );
b03ae39b
RN
588 }
589 }
590 }
591 }
50a14534
EB
592 break;
593 }
594 case PARAM_ALPHA: if ( data.u <= 255 ) vml->alpha = data.u; break;
595 case PARAM_AUTODOWNLOAD: vml->autodownload = data.b; break;
382566c3 596 case PARAM_ONLYMISSING: vml->adl_only_missing = data.b; break;
50a14534
EB
597 case PARAM_MAPZOOM: if ( data.u < NUM_MAPZOOMS ) {
598 vml->mapzoom_id = data.u;
599 vml->xmapzoom = __mapzooms_x [data.u];
600 vml->ymapzoom = __mapzooms_y [data.u];
4c77d5e0 601 }else g_warning (_("Unknown Map Zoom")); break;
9351abc4 602 default: break;
50a14534
EB
603 }
604 return TRUE;
605}
606
158b3642 607static VikLayerParamData maps_layer_get_param ( VikMapsLayer *vml, guint16 id, gboolean is_file_operation )
50a14534
EB
608{
609 VikLayerParamData rv;
610 switch ( id )
611 {
cde1e50e 612 case PARAM_CACHE_DIR:
88542aa9
RN
613 {
614 gboolean set = FALSE;
cde1e50e
RN
615 /* Only save a blank when the map cache location equals the default
616 On reading in, when it is blank then the default is reconstructed
617 Since the default changes dependent on the user and OS, it means the resultant file is more portable */
88542aa9 618 if ( is_file_operation && vml->cache_dir && strcmp ( vml->cache_dir, MAPS_CACHE_DIR ) == 0 ) {
cde1e50e 619 rv.s = "";
88542aa9
RN
620 set = TRUE;
621 }
622 else if ( is_file_operation ) {
623 if ( a_vik_get_file_ref_format() == VIK_FILE_REF_FORMAT_RELATIVE ) {
624 gchar *cwd = g_get_current_dir();
625 if ( cwd ) {
626 rv.s = file_GetRelativeFilename ( cwd, vml->cache_dir );
627 if ( !rv.s ) rv.s = "";
628 set = TRUE;
629 }
630 }
631 }
632 if ( !set )
633 rv.s = vml->cache_dir ? vml->cache_dir : "";
cde1e50e 634 break;
88542aa9 635 }
d281e8b4 636 case PARAM_CACHE_LAYOUT: rv.u = vml->cache_layout; break;
0fb11294 637 case PARAM_FILE: rv.s = vml->filename; break;
50a14534
EB
638 case PARAM_MAPTYPE: rv.u = map_index_to_uniq_id ( vml->maptype ); break;
639 case PARAM_ALPHA: rv.u = vml->alpha; break;
640 case PARAM_AUTODOWNLOAD: rv.u = vml->autodownload; break;
382566c3 641 case PARAM_ONLYMISSING: rv.u = vml->adl_only_missing; break;
50a14534 642 case PARAM_MAPZOOM: rv.u = vml->mapzoom_id; break;
9351abc4 643 default: break;
50a14534
EB
644 }
645 return rv;
646}
647
db43cfa4
RN
648static void maps_layer_change_param ( GtkWidget *widget, ui_change_values values )
649{
650 switch ( GPOINTER_TO_INT(values[UI_CHG_PARAM_ID]) ) {
0fb11294
RN
651 // Alter sensitivity of download option widgets according to the maptype setting.
652 case PARAM_MAPTYPE: {
653 // Get new value
654 VikLayerParamData vlpd = a_uibuilder_widget_get_value ( widget, values[UI_CHG_PARAM] );
655 // Is it *not* the OSM On Disk Tile Layout or the MBTiles type
656 gboolean sensitive = ( 21 != vlpd.u && 23 != vlpd.u);
657 GtkWidget **ww1 = values[UI_CHG_WIDGETS];
658 GtkWidget **ww2 = values[UI_CHG_LABELS];
659 GtkWidget *w1 = ww1[PARAM_ONLYMISSING];
660 GtkWidget *w2 = ww2[PARAM_ONLYMISSING];
661 GtkWidget *w3 = ww1[PARAM_AUTODOWNLOAD];
662 GtkWidget *w4 = ww2[PARAM_AUTODOWNLOAD];
663 // Depends on autodownload value
664 gboolean missing_sense = sensitive && VIK_MAPS_LAYER(values[UI_CHG_LAYER])->autodownload;
665 if ( w1 ) gtk_widget_set_sensitive ( w1, missing_sense );
666 if ( w2 ) gtk_widget_set_sensitive ( w2, missing_sense );
667 if ( w3 ) gtk_widget_set_sensitive ( w3, sensitive );
668 if ( w4 ) gtk_widget_set_sensitive ( w4, sensitive );
669
d281e8b4
RN
670 // Cache type not applicable either
671 GtkWidget *w9 = ww1[PARAM_CACHE_LAYOUT];
672 GtkWidget *w10 = ww2[PARAM_CACHE_LAYOUT];
673 if ( w9 ) gtk_widget_set_sensitive ( w9, sensitive );
674 if ( w10 ) gtk_widget_set_sensitive ( w10, sensitive );
675
0fb11294
RN
676 // File only applicable for MBTiles type
677 // Directory for all other types
678 sensitive = ( 23 == vlpd.u);
679 GtkWidget *w5 = ww1[PARAM_FILE];
680 GtkWidget *w6 = ww2[PARAM_FILE];
681 GtkWidget *w7 = ww1[PARAM_CACHE_DIR];
682 GtkWidget *w8 = ww2[PARAM_CACHE_DIR];
683 if ( w5 ) gtk_widget_set_sensitive ( w5, sensitive );
684 if ( w6 ) gtk_widget_set_sensitive ( w6, sensitive );
685 if ( w7 ) gtk_widget_set_sensitive ( w7, !sensitive );
686 if ( w8 ) gtk_widget_set_sensitive ( w8, !sensitive );
687
688 break;
689 }
690
db43cfa4
RN
691 // Alter sensitivity of 'download only missing' widgets according to the autodownload setting.
692 case PARAM_AUTODOWNLOAD: {
693 // Get new value
694 VikLayerParamData vlpd = a_uibuilder_widget_get_value ( widget, values[UI_CHG_PARAM] );
695 GtkWidget **ww1 = values[UI_CHG_WIDGETS];
696 GtkWidget **ww2 = values[UI_CHG_LABELS];
697 GtkWidget *w1 = ww1[PARAM_ONLYMISSING];
698 GtkWidget *w2 = ww2[PARAM_ONLYMISSING];
699 if ( w1 ) gtk_widget_set_sensitive ( w1, vlpd.b );
700 if ( w2 ) gtk_widget_set_sensitive ( w2, vlpd.b );
701 break;
702 }
703 default: break;
704 }
705}
706
50a14534
EB
707/****************************************/
708/****** CREATING, COPYING, FREEING ******/
709/****************************************/
710
711static VikMapsLayer *maps_layer_new ( VikViewport *vvp )
712{
713 VikMapsLayer *vml = VIK_MAPS_LAYER ( g_object_new ( VIK_MAPS_LAYER_TYPE, NULL ) );
a0c65899 714 vik_layer_set_type ( VIK_LAYER(vml), VIK_LAYER_MAPS );
a7023a1b
RN
715
716 vik_layer_set_defaults ( VIK_LAYER(vml), vvp );
717
50a14534 718 vml->dl_tool_x = vml->dl_tool_y = -1;
10ca2bfe
QT
719 vml->last_center = NULL;
720 vml->last_xmpp = 0.0;
721 vml->last_ympp = 0.0;
50a14534
EB
722
723 vml->dl_right_click_menu = NULL;
0fb11294 724 vml->filename = NULL;
50a14534
EB
725 return vml;
726}
727
728static void maps_layer_free ( VikMapsLayer *vml )
729{
e65028db
GB
730 g_free ( vml->cache_dir );
731 vml->cache_dir = NULL;
50a14534 732 if ( vml->dl_right_click_menu )
4f14a010 733 g_object_ref_sink ( G_OBJECT(vml->dl_right_click_menu) );
e65028db
GB
734 g_free(vml->last_center);
735 vml->last_center = NULL;
0fb11294
RN
736 g_free ( vml->filename );
737 vml->filename = NULL;
738
739#ifdef HAVE_SQLITE3_H
740 VikMapSource *map = MAPS_LAYER_NTH_TYPE(vml->maptype);
741 if ( vik_map_source_is_mbtiles ( map ) ) {
742 if ( vml->mbtiles ) {
743 int ans = sqlite3_close ( vml->mbtiles );
744 if ( ans != SQLITE_OK ) {
745 // Only to console for information purposes only
746 g_warning ( "SQL Close problem: %d", ans );
747 }
748 }
749 }
750#endif
50a14534
EB
751}
752
07059501 753static void maps_layer_post_read (VikLayer *vl, VikViewport *vp, gboolean from_file)
dc5758d3 754{
0fb11294
RN
755 VikMapsLayer *vml = VIK_MAPS_LAYER(vl);
756 VikMapSource *map = MAPS_LAYER_NTH_TYPE(vml->maptype);
757
07059501
GB
758 if (from_file != TRUE)
759 {
760 /* If this method is not called in file reading context
761 * it is called in GUI context.
762 * So, we can check if we have to inform the user about inconsistency */
763 VikViewportDrawMode vp_drawmode;
405b74ed 764 vp_drawmode = vik_viewport_get_drawmode ( vp );
0fb11294 765
820c59f4 766 if (vik_map_source_get_drawmode(map) != vp_drawmode) {
405b74ed 767 const gchar *drawmode_name = vik_viewport_get_drawmode_name (vp, vik_map_source_get_drawmode(map));
4c77d5e0 768 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 769 a_dialog_warning_msg ( VIK_GTK_WINDOW_FROM_WIDGET(vp), msg );
07059501
GB
770 g_free(msg);
771 }
dc5758d3 772 }
0fb11294
RN
773
774 // Performed in post read as we now know the map type
775#ifdef HAVE_SQLITE3_H
776 // Do some SQL stuff
777 if ( vik_map_source_is_mbtiles ( map ) ) {
778 int ans = sqlite3_open_v2 ( vml->filename,
779 &(vml->mbtiles),
780 SQLITE_OPEN_READONLY,
781 NULL );
782 if ( ans != SQLITE_OK ) {
783 // That didn't work, so here's why:
784 g_warning ( "%s: %s", __FUNCTION__, sqlite3_errmsg ( vml->mbtiles ) );
785
786 a_dialog_error_msg_extra ( VIK_GTK_WINDOW_FROM_WIDGET(vp),
787 _("Failed to open MBTiles file: %s"),
788 vml->filename );
789 vml->mbtiles = NULL;
790 }
791 }
792#endif
df5b2993
RN
793
794 // If the on Disk OSM Tile Layout type
795 if ( vml->maptype == 21 )
796 // Copy the directory into filename
797 // thus the mapcache look up will be unique when using more than one of these map types
798 vml->filename = g_strdup (vml->cache_dir);
dc5758d3
GB
799}
800
7924723c
RN
801static const gchar* maps_layer_tooltip ( VikMapsLayer *vml )
802{
803 return vik_maps_layer_get_map_label ( vml );
804}
805
911400b5
AF
806static void maps_layer_marshall( VikMapsLayer *vml, guint8 **data, gint *len )
807{
808 vik_layer_marshall_params ( VIK_LAYER(vml), data, len );
809}
810
811static VikMapsLayer *maps_layer_unmarshall( guint8 *data, gint len, VikViewport *vvp )
812{
813 VikMapsLayer *rv = maps_layer_new ( vvp );
814 vik_layer_unmarshall_params ( VIK_LAYER(rv), data, len, vvp );
815 return rv;
816}
817
50a14534
EB
818/*********************/
819/****** DRAWING ******/
820/*********************/
821
822static GdkPixbuf *pixbuf_set_alpha ( GdkPixbuf *pixbuf, guint8 alpha )
823{
824 guchar *pixels;
825 gint width, height, iii, jjj;
826
827 if ( ! gdk_pixbuf_get_has_alpha ( pixbuf ) )
828 {
829 GdkPixbuf *tmp = gdk_pixbuf_add_alpha(pixbuf,FALSE,0,0,0);
830 g_object_unref(G_OBJECT(pixbuf));
831 pixbuf = tmp;
45b0031e
RN
832 if ( !pixbuf )
833 return NULL;
50a14534
EB
834 }
835
836 pixels = gdk_pixbuf_get_pixels(pixbuf);
837 width = gdk_pixbuf_get_width(pixbuf);
838 height = gdk_pixbuf_get_height(pixbuf);
839
840 /* r,g,b,a,r,g,b,a.... */
841 for (iii = 0; iii < width; iii++) for (jjj = 0; jjj < height; jjj++)
842 {
843 pixels += 3;
844 *pixels++ = alpha;
845 }
846 return pixbuf;
847}
848
849static GdkPixbuf *pixbuf_shrink ( GdkPixbuf *pixbuf, gdouble xshrinkfactor, gdouble yshrinkfactor )
850{
851 GdkPixbuf *tmp;
852 guint16 width = gdk_pixbuf_get_width(pixbuf), height = gdk_pixbuf_get_height(pixbuf);
2d5d32c1 853 tmp = gdk_pixbuf_scale_simple(pixbuf, ceil(width * xshrinkfactor), ceil(height * yshrinkfactor), GDK_INTERP_BILINEAR);
50a14534
EB
854 g_object_unref ( G_OBJECT(pixbuf) );
855 return tmp;
856}
857
0fb11294
RN
858#ifdef HAVE_SQLITE3_H
859/*
860static int sql_select_tile_dump_cb (void *data, int cols, char **fields, char **col_names )
861{
862 g_warning ( "Found %d columns", cols );
863 int i;
864 for ( i = 0; i < cols; i++ ) {
865 g_warning ( "SQL processing %s = %s", col_names[i], fields[i] );
866 }
867 return 0;
868}
869*/
870
871/**
872 *
873 */
874static GdkPixbuf *get_pixbuf_sql_exec ( sqlite3 *sql, gint xx, gint yy, gint zoom )
875{
876 GdkPixbuf *pixbuf = NULL;
877
878 // MBTiles stored internally with the flipping y thingy (i.e. TMS scheme).
879 gint flip_y = (gint) pow(2, zoom)-1 - yy;
880 gchar *statement = g_strdup_printf ( "SELECT tile_data FROM tiles WHERE zoom_level=%d AND tile_column=%d AND tile_row=%d;", zoom, xx, flip_y );
881
882 gboolean finished = FALSE;
883
884 sqlite3_stmt *sql_stmt = NULL;
885 int ans = sqlite3_prepare_v2 ( sql, statement, -1, &sql_stmt, NULL );
886 if ( ans != SQLITE_OK ) {
887 g_warning ( "%s: %s - %d", __FUNCTION__, "prepare failure", ans );
888 finished = TRUE;
889 }
890
891 while ( !finished ) {
892 ans = sqlite3_step ( sql_stmt );
893 switch (ans) {
894 case SQLITE_ROW: {
895 // Get tile_data blob
896 int count = sqlite3_column_count(sql_stmt);
897 if ( count != 1 ) {
898 g_warning ( "%s: %s - %d", __FUNCTION__, "count not one", count );
899 finished = TRUE;
900 }
901 else {
902 const void *data = sqlite3_column_blob ( sql_stmt, 0 );
903 int bytes = sqlite3_column_bytes ( sql_stmt, 0 );
904 if ( bytes < 1 ) {
905 g_warning ( "%s: %s (%d)", __FUNCTION__, "not enough bytes", bytes );
906 finished = TRUE;
907 }
908 else {
909 // Convert these blob bytes into a pixbuf via these streaming operations
910 GInputStream *stream = g_memory_input_stream_new_from_data ( data, bytes, NULL );
911 GError *error = NULL;
912 pixbuf = gdk_pixbuf_new_from_stream ( stream, NULL, &error );
913 if (error || (!pixbuf)) {
914 g_warning ( "%s: %s", __FUNCTION__, error->message );
915 g_error_free ( error );
916 }
917 g_input_stream_close ( stream, NULL, NULL );
918 }
919 }
920 break;
921 }
922 default:
923 // e.g. SQLITE_DONE | SQLITE_ERROR | SQLITE_MISUSE | etc...
924 // Finished normally
925 // and give up on any errors
926 if ( ans != SQLITE_DONE )
927 g_warning ( "%s: %s - %d", __FUNCTION__, "step issue", ans );
928 finished = TRUE;
929 break;
930 }
931 }
932 ans = sqlite3_finalize ( sql_stmt );
933
934 g_free ( statement );
935
936 return pixbuf;
937}
938#endif
939
940static GdkPixbuf *get_mbtiles_pixbuf ( VikMapsLayer *vml, gint xx, gint yy, gint zoom )
941{
942 GdkPixbuf *pixbuf = NULL;
943
944#ifdef HAVE_SQLITE3_H
945 if ( vml->mbtiles ) {
946 /*
947 gchar *statement = g_strdup_printf ( "SELECT name FROM sqlite_master WHERE type='table';" );
948 char *errMsg = NULL;
949 int ans = sqlite3_exec ( vml->mbtiles, statement, sql_select_tile_dump_cb, pixbuf, &errMsg );
950 if ( ans != SQLITE_OK ) {
951 // Only to console for information purposes only
952 g_warning ( "SQL problem: %d for %s - error: %s", ans, statement, errMsg );
953 sqlite3_free( errMsg );
954 }
955 g_free ( statement );
956 */
957
958 // Reading BLOBS is a bit more involved and so can't use the simpler sqlite3_exec ()
959 // Hence this specific function
960 pixbuf = get_pixbuf_sql_exec ( vml->mbtiles, xx, yy, zoom );
961 }
962#endif
963
964 return pixbuf;
965}
966
967static GdkPixbuf *pixbuf_apply_settings ( GdkPixbuf *pixbuf, VikMapsLayer *vml, MapCoord *mapcoord, gdouble xshrinkfactor, gdouble yshrinkfactor )
968{
969 // Apply alpha setting
970 if ( pixbuf && vml->alpha < 255 )
971 pixbuf = pixbuf_set_alpha ( pixbuf, vml->alpha );
972
973 if ( pixbuf && ( xshrinkfactor != 1.0 || yshrinkfactor != 1.0 ) )
974 pixbuf = pixbuf_shrink ( pixbuf, xshrinkfactor, yshrinkfactor );
975
976 if ( pixbuf )
977 a_mapcache_add ( pixbuf, mapcoord->x, mapcoord->y,
978 mapcoord->z, vik_map_source_get_uniq_id(MAPS_LAYER_NTH_TYPE(vml->maptype)),
df5b2993 979 mapcoord->scale, vml->alpha, xshrinkfactor, yshrinkfactor, vml->filename );
0fb11294
RN
980
981 return pixbuf;
982}
983
2eb18edc
RN
984static void get_filename ( const gchar *cache_dir,
985 VikMapsCacheLayout cl,
5a1e5516 986 guint16 id,
2eb18edc
RN
987 const gchar *name,
988 gint scale,
989 gint z,
990 gint x,
991 gint y,
992 gchar *filename_buf,
14b57d17
RN
993 gint buf_len,
994 const gchar* file_extension )
d281e8b4
RN
995{
996 switch ( cl ) {
997 case VIK_MAPS_CACHE_LAYOUT_OSM:
2eb18edc
RN
998 if ( name ) {
999 if ( g_strcmp0 ( cache_dir, MAPS_CACHE_DIR ) )
1000 // Cache dir not the default - assume it's been directed somewhere specific
14b57d17 1001 g_snprintf ( filename_buf, buf_len, DIRECTDIRACCESS, cache_dir, (17 - scale), x, y, file_extension );
2eb18edc
RN
1002 else
1003 // Using default cache - so use the map name in the directory path
14b57d17 1004 g_snprintf ( filename_buf, buf_len, DIRECTDIRACCESS_WITH_NAME, cache_dir, name, (17 - scale), x, y, file_extension );
2eb18edc
RN
1005 }
1006 else
14b57d17 1007 g_snprintf ( filename_buf, buf_len, DIRECTDIRACCESS, cache_dir, (17 - scale), x, y, file_extension );
d281e8b4
RN
1008 break;
1009 default:
5a1e5516 1010 g_snprintf ( filename_buf, buf_len, DIRSTRUCTURE, cache_dir, id, scale, z, x, y );
d281e8b4
RN
1011 break;
1012 }
1013}
1014
5a1e5516 1015static GdkPixbuf *get_pixbuf( VikMapsLayer *vml, guint16 id, const gchar* mapname, MapCoord *mapcoord, gchar *filename_buf, gint buf_len, gdouble xshrinkfactor, gdouble yshrinkfactor )
50a14534
EB
1016{
1017 GdkPixbuf *pixbuf;
1018
1019 /* get the thing */
1020 pixbuf = a_mapcache_get ( mapcoord->x, mapcoord->y, mapcoord->z,
5a1e5516 1021 id, mapcoord->scale, vml->alpha, xshrinkfactor, yshrinkfactor, vml->filename );
50a14534
EB
1022
1023 if ( ! pixbuf ) {
14b57d17
RN
1024 VikMapSource *map = MAPS_LAYER_NTH_TYPE(vml->maptype);
1025 if ( vik_map_source_is_direct_file_access(map) ) {
0fb11294 1026 // ATM MBTiles must be 'a direct access type'
14b57d17 1027 if ( vik_map_source_is_mbtiles(map) ) {
0fb11294
RN
1028 pixbuf = get_mbtiles_pixbuf ( vml, mapcoord->x, mapcoord->y, (17 - mapcoord->scale) );
1029 pixbuf = pixbuf_apply_settings ( pixbuf, vml, mapcoord, xshrinkfactor, yshrinkfactor );
1030 // return now to avoid file tests that aren't appropriate for this map type
1031 return pixbuf;
1032 }
1033 else
5a1e5516 1034 get_filename ( vml->cache_dir, VIK_MAPS_CACHE_LAYOUT_OSM, id, NULL,
14b57d17
RN
1035 mapcoord->scale, mapcoord->z, mapcoord->x, mapcoord->y, filename_buf, buf_len,
1036 vik_map_source_get_file_extension(map) );
0fb11294 1037 }
2673b29d 1038 else
5a1e5516 1039 get_filename ( vml->cache_dir, vml->cache_layout, id, mapname,
14b57d17
RN
1040 mapcoord->scale, mapcoord->z, mapcoord->x, mapcoord->y, filename_buf, buf_len,
1041 vik_map_source_get_file_extension(map) );
2673b29d 1042
01ecda7e 1043 if ( g_file_test ( filename_buf, G_FILE_TEST_EXISTS ) == TRUE)
50a14534
EB
1044 {
1045 GError *gx = NULL;
1046 pixbuf = gdk_pixbuf_new_from_file ( filename_buf, &gx );
1047
01ecda7e 1048 /* free the pixbuf on error */
50a14534
EB
1049 if (gx)
1050 {
d17be106
RN
1051 if ( gx->domain != GDK_PIXBUF_ERROR || gx->code != GDK_PIXBUF_ERROR_CORRUPT_IMAGE ) {
1052 // Report a warning
1053 if ( IS_VIK_WINDOW ((VikWindow*)VIK_GTK_WINDOW_FROM_LAYER(vml)) ) {
1054 gchar* msg = g_strdup_printf ( _("Couldn't open image file: %s"), gx->message );
1055 vik_window_statusbar_update ( (VikWindow*)VIK_GTK_WINDOW_FROM_LAYER(vml), msg, VIK_STATUSBAR_INFO );
1056 g_free (msg);
1057 }
1058 }
50a14534 1059
01ecda7e
MR
1060 g_error_free ( gx );
1061 if ( pixbuf )
1062 g_object_unref ( G_OBJECT(pixbuf) );
1063 pixbuf = NULL;
1064 } else {
0fb11294 1065 pixbuf = pixbuf_apply_settings ( pixbuf, vml, mapcoord, xshrinkfactor, yshrinkfactor );
50a14534
EB
1066 }
1067 }
1068 }
1069 return pixbuf;
1070}
1071
9979924f 1072static gboolean should_start_autodownload(VikMapsLayer *vml, VikViewport *vvp)
10ca2bfe
QT
1073{
1074 const VikCoord *center = vik_viewport_get_center ( vvp );
1075
bbf2149b 1076 if (vik_window_get_pan_move (VIK_WINDOW(VIK_GTK_WINDOW_FROM_WIDGET(GTK_WIDGET(vvp)))))
01da6b4d 1077 /* D'n'D pan in action: do not download */
1c6a6010
GB
1078 return FALSE;
1079
e633ddef 1080 // Don't attempt to download unsupported zoom levels
9979924f 1081 gdouble xzoom = vik_viewport_get_xmpp ( vvp );
e633ddef
RN
1082 VikMapSource *map = MAPS_LAYER_NTH_TYPE(vml->maptype);
1083 guint8 zl = map_utils_mpp_to_zoom_level ( xzoom );
1084 if ( zl < vik_map_source_get_zoom_min(map) || zl > vik_map_source_get_zoom_max(map) )
9979924f
RN
1085 return FALSE;
1086
10ca2bfe
QT
1087 if (vml->last_center == NULL) {
1088 VikCoord *new_center = g_malloc(sizeof(VikCoord));
1089 *new_center = *center;
1090 vml->last_center = new_center;
1091 vml->last_xmpp = vik_viewport_get_xmpp(vvp);
1092 vml->last_ympp = vik_viewport_get_ympp(vvp);
1093 return TRUE;
1094 }
1095
1096 /* TODO: perhaps vik_coord_diff() */
1097 if (vik_coord_equals(vml->last_center, center)
1098 && (vml->last_xmpp == vik_viewport_get_xmpp(vvp))
1099 && (vml->last_ympp == vik_viewport_get_ympp(vvp)))
1100 return FALSE;
1101
1102 *(vml->last_center) = *center;
1103 vml->last_xmpp = vik_viewport_get_xmpp(vvp);
1104 vml->last_ympp = vik_viewport_get_ympp(vvp);
1105 return TRUE;
1106}
1107
50a14534
EB
1108static void maps_layer_draw_section ( VikMapsLayer *vml, VikViewport *vvp, VikCoord *ul, VikCoord *br )
1109{
1110 MapCoord ulm, brm;
1111 gdouble xzoom = vik_viewport_get_xmpp ( vvp );
1112 gdouble yzoom = vik_viewport_get_ympp ( vvp );
1113 gdouble xshrinkfactor = 1.0, yshrinkfactor = 1.0;
2673b29d 1114 gboolean existence_only = FALSE;
50a14534
EB
1115
1116 if ( vml->xmapzoom && (vml->xmapzoom != xzoom || vml->ymapzoom != yzoom) ) {
1117 xshrinkfactor = vml->xmapzoom / xzoom;
1118 yshrinkfactor = vml->ymapzoom / yzoom;
732d1e25
EB
1119 xzoom = vml->xmapzoom;
1120 yzoom = vml->xmapzoom;
1121 if ( ! (xshrinkfactor > MIN_SHRINKFACTOR && xshrinkfactor < MAX_SHRINKFACTOR &&
1122 yshrinkfactor > MIN_SHRINKFACTOR && yshrinkfactor < MAX_SHRINKFACTOR ) ) {
6de95419
RN
1123 if ( xshrinkfactor > REAL_MIN_SHRINKFACTOR && yshrinkfactor > REAL_MIN_SHRINKFACTOR ) {
1124 g_debug ( "%s: existence_only due to SHRINKFACTORS", __FUNCTION__ );
732d1e25 1125 existence_only = TRUE;
6de95419 1126 }
732d1e25 1127 else {
d17be106
RN
1128 // Report the reason for not drawing
1129 if ( IS_VIK_WINDOW ((VikWindow*)VIK_GTK_WINDOW_FROM_LAYER(vml)) ) {
1130 gchar* msg = g_strdup_printf ( _("Cowardly refusing to draw tiles or existence of tiles beyond %d zoom out factor"), (int)( 1.0/REAL_MIN_SHRINKFACTOR));
1131 vik_window_statusbar_update ( (VikWindow*)VIK_GTK_WINDOW_FROM_LAYER(vml), msg, VIK_STATUSBAR_INFO );
1132 g_free (msg);
1133 }
732d1e25
EB
1134 return;
1135 }
50a14534
EB
1136 }
1137 }
1138
1139 /* coord -> ID */
820c59f4
GB
1140 VikMapSource *map = MAPS_LAYER_NTH_TYPE(vml->maptype);
1141 if ( vik_map_source_coord_to_mapcoord ( map, ul, xzoom, yzoom, &ulm ) &&
1142 vik_map_source_coord_to_mapcoord ( map, br, xzoom, yzoom, &brm ) ) {
50a14534
EB
1143
1144 /* loop & draw */
1145 gint x, y;
1146 gint xmin = MIN(ulm.x, brm.x), xmax = MAX(ulm.x, brm.x);
1147 gint ymin = MIN(ulm.y, brm.y), ymax = MAX(ulm.y, brm.y);
5a1e5516 1148 guint16 id = vik_map_source_get_uniq_id(map);
2eb18edc 1149 const gchar *mapname = vik_map_source_get_name(map);
50a14534
EB
1150
1151 VikCoord coord;
1152 gint xx, yy, width, height;
1153 GdkPixbuf *pixbuf;
1154
6de95419
RN
1155 // Prevent the program grinding to a halt if trying to deal with thousands of tiles
1156 // which can happen when using a small fixed zoom level and viewing large areas.
1157 // Also prevents very large number of tile download requests
1158 gint tiles = (xmax-xmin) * (ymax-ymin);
1159 if ( tiles > MAX_TILES ) {
1160 g_debug ( "%s: existence_only due to wanting too many tiles (%d)", __FUNCTION__, tiles );
1161 existence_only = TRUE;
1162 }
1163
50a14534
EB
1164 guint max_path_len = strlen(vml->cache_dir) + 40;
1165 gchar *path_buf = g_malloc ( max_path_len * sizeof(char) );
1166
732d1e25 1167 if ( (!existence_only) && vml->autodownload && should_start_autodownload(vml, vvp)) {
33be396e 1168 g_debug("%s: Starting autodownload", __FUNCTION__);
382566c3 1169 if ( !vml->adl_only_missing && vik_map_source_supports_download_only_new (map) )
245f48f5
GB
1170 // Try to download newer tiles
1171 start_download_thread ( vml, vvp, ul, br, REDOWNLOAD_NEW );
1172 else
1173 // Download only missing tiles
1174 start_download_thread ( vml, vvp, ul, br, REDOWNLOAD_NONE );
10ca2bfe 1175 }
50a14534 1176
820c59f4 1177 if ( vik_map_source_get_tilesize_x(map) == 0 && !existence_only ) {
50a14534
EB
1178 for ( x = xmin; x <= xmax; x++ ) {
1179 for ( y = ymin; y <= ymax; y++ ) {
1180 ulm.x = x;
1181 ulm.y = y;
5a1e5516 1182 pixbuf = get_pixbuf ( vml, id, mapname, &ulm, path_buf, max_path_len, xshrinkfactor, yshrinkfactor );
50a14534
EB
1183 if ( pixbuf ) {
1184 width = gdk_pixbuf_get_width ( pixbuf );
1185 height = gdk_pixbuf_get_height ( pixbuf );
1186
820c59f4 1187 vik_map_source_mapcoord_to_center_coord ( map, &ulm, &coord );
50a14534
EB
1188 vik_viewport_coord_to_screen ( vvp, &coord, &xx, &yy );
1189 xx -= (width/2);
1190 yy -= (height/2);
1191
1192 vik_viewport_draw_pixbuf ( vvp, pixbuf, 0, 0, xx, yy, width, height );
1193 }
1194 }
1195 }
1196 } else { /* tilesize is known, don't have to keep converting coords */
820c59f4
GB
1197 gdouble tilesize_x = vik_map_source_get_tilesize_x(map) * xshrinkfactor;
1198 gdouble tilesize_y = vik_map_source_get_tilesize_y(map) * yshrinkfactor;
50a14534
EB
1199 /* ceiled so tiles will be maximum size in the case of funky shrinkfactor */
1200 gint tilesize_x_ceil = ceil ( tilesize_x );
1201 gint tilesize_y_ceil = ceil ( tilesize_y );
1202 gint8 xinc = (ulm.x == xmin) ? 1 : -1;
1203 gint8 yinc = (ulm.y == ymin) ? 1 : -1;
c60f82df 1204 gint xx_tmp, yy_tmp;
50a14534 1205 gint base_yy, xend, yend;
732d1e25 1206
50a14534
EB
1207 xend = (xinc == 1) ? (xmax+1) : (xmin-1);
1208 yend = (yinc == 1) ? (ymax+1) : (ymin-1);
1209
820c59f4 1210 vik_map_source_mapcoord_to_center_coord ( map, &ulm, &coord );
50a14534
EB
1211 vik_viewport_coord_to_screen ( vvp, &coord, &xx_tmp, &yy_tmp );
1212 xx = xx_tmp; yy = yy_tmp;
1213 /* above trick so xx,yy doubles. this is so shrinkfactors aren't rounded off
1214 * eg if tile size 128, shrinkfactor 0.333 */
1215 xx -= (tilesize_x/2);
1216 base_yy = yy - (tilesize_y/2);
1217
1218 for ( x = ((xinc == 1) ? xmin : xmax); x != xend; x+=xinc ) {
1219 yy = base_yy;
1220 for ( y = ((yinc == 1) ? ymin : ymax); y != yend; y+=yinc ) {
1221 ulm.x = x;
1222 ulm.y = y;
732d1e25
EB
1223
1224 if ( existence_only ) {
d281e8b4 1225 if ( vik_map_source_is_direct_file_access (MAPS_LAYER_NTH_TYPE(vml->maptype)) )
5a1e5516 1226 get_filename ( vml->cache_dir, VIK_MAPS_CACHE_LAYOUT_OSM, id, vik_map_source_get_name(map),
14b57d17 1227 ulm.scale, ulm.z, ulm.x, ulm.y, path_buf, max_path_len, vik_map_source_get_file_extension(map) );
d281e8b4 1228 else
5a1e5516 1229 get_filename ( vml->cache_dir, vml->cache_layout, id, vik_map_source_get_name(map),
14b57d17 1230 ulm.scale, ulm.z, ulm.x, ulm.y, path_buf, max_path_len, vik_map_source_get_file_extension(map) );
d281e8b4 1231
45acf79e 1232 if ( g_file_test ( path_buf, G_FILE_TEST_EXISTS ) == TRUE ) {
ff37db21 1233 GdkGC *black_gc = gtk_widget_get_style(GTK_WIDGET(vvp))->black_gc;
732d1e25
EB
1234 vik_viewport_draw_line ( vvp, black_gc, xx+tilesize_x_ceil, yy, xx, yy+tilesize_y_ceil );
1235 }
1236 } else {
6f0d1bea
JJ
1237 int scale_inc;
1238 for (scale_inc = 0; scale_inc < 4; scale_inc ++) {
1239 /* try with correct then smaller zooms */
1240 int scale_factor = 1 << scale_inc; /* 2^scale_inc */
1241 MapCoord ulm2 = ulm;
1242 ulm2.x = ulm.x / scale_factor;
1243 ulm2.y = ulm.y / scale_factor;
1244 ulm2.scale = ulm.scale + scale_inc;
5a1e5516 1245 pixbuf = get_pixbuf ( vml, id, mapname, &ulm2, path_buf, max_path_len, xshrinkfactor * scale_factor, yshrinkfactor * scale_factor );
6f0d1bea
JJ
1246 if ( pixbuf ) {
1247 gint src_x = (ulm.x % scale_factor) * tilesize_x_ceil;
1248 gint src_y = (ulm.y % scale_factor) * tilesize_y_ceil;
40cfc175
JJ
1249#ifdef DEBUG
1250 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);
1251#endif
6f0d1bea
JJ
1252 vik_viewport_draw_pixbuf ( vvp, pixbuf, src_x, src_y, xx, yy, tilesize_x_ceil, tilesize_y_ceil );
1253 break;
1254 }
1255 }
1256 if ( !pixbuf ) {
1257 /* retry with bigger zooms */
1258 int scale_dec;
1259 for (scale_dec = 1; scale_dec < 2; scale_dec ++) {
1260 int pict_x, pict_y;
1261 int scale_factor = 1 << scale_dec; /* 2^scale_dec */
91dc4449 1262 MapCoord ulm2 = ulm;
6f0d1bea
JJ
1263 ulm2.x = ulm.x * scale_factor;
1264 ulm2.y = ulm.y * scale_factor;
1265 ulm2.scale = ulm.scale - scale_dec;
1266 for (pict_x = 0; pict_x < scale_factor; pict_x ++) {
1267 for (pict_y = 0; pict_y < scale_factor; pict_y ++) {
1268 MapCoord ulm3 = ulm2;
1269 ulm3.x += pict_x;
1270 ulm3.y += pict_y;
5a1e5516 1271 pixbuf = get_pixbuf ( vml, id, mapname, &ulm3, path_buf, max_path_len, xshrinkfactor / scale_factor, yshrinkfactor / scale_factor );
6f0d1bea
JJ
1272 if ( pixbuf ) {
1273 gint src_x = 0;
1274 gint src_y = 0;
1275 gint dest_x = xx + pict_x * (tilesize_x_ceil / scale_factor);
1276 gint dest_y = yy + pict_y * (tilesize_y_ceil / scale_factor);
1277 vik_viewport_draw_pixbuf ( vvp, pixbuf, src_x, src_y, dest_x, dest_y, tilesize_x_ceil / scale_factor, tilesize_y_ceil / scale_factor );
1278 }
1279 }
91dc4449
JJ
1280 }
1281 }
1282 }
732d1e25 1283 }
50a14534
EB
1284
1285 yy += tilesize_y;
1286 }
1287 xx += tilesize_x;
1288 }
1289 }
1290
1291 g_free ( path_buf );
1292 }
1293}
1294
1295static void maps_layer_draw ( VikMapsLayer *vml, VikViewport *vvp )
1296{
820c59f4 1297 if ( vik_map_source_get_drawmode(MAPS_LAYER_NTH_TYPE(vml->maptype)) == vik_viewport_get_drawmode ( vvp ) )
50a14534
EB
1298 {
1299 VikCoord ul, br;
1300
82aa018d 1301 /* Copyright */
68b1d6c0
GB
1302 gdouble level = vik_viewport_get_zoom ( vvp );
1303 LatLonBBox bbox;
1304 vik_viewport_get_min_max_lat_lon ( vvp, &bbox.south, &bbox.north, &bbox.west, &bbox.east );
1305 vik_map_source_get_copyright ( MAPS_LAYER_NTH_TYPE(vml->maptype), bbox, level, vik_viewport_add_copyright, vvp );
82aa018d 1306
26336cf0
GB
1307 /* Logo */
1308 const GdkPixbuf *logo = vik_map_source_get_logo ( MAPS_LAYER_NTH_TYPE(vml->maptype) );
1309 vik_viewport_add_logo ( vvp, logo );
1310
50a14534
EB
1311 /* get corner coords */
1312 if ( vik_viewport_get_coord_mode ( vvp ) == VIK_COORD_UTM && ! vik_viewport_is_one_zone ( vvp ) ) {
1313 /* UTM multi-zone stuff by Kit Transue */
1314 gchar leftmost_zone, rightmost_zone, i;
1315 leftmost_zone = vik_viewport_leftmost_zone( vvp );
1316 rightmost_zone = vik_viewport_rightmost_zone( vvp );
1317 for ( i = leftmost_zone; i <= rightmost_zone; ++i ) {
1318 vik_viewport_corners_for_zonen ( vvp, i, &ul, &br );
1319 maps_layer_draw_section ( vml, vvp, &ul, &br );
1320 }
1321 }
1322 else {
1323 vik_viewport_screen_to_coord ( vvp, 0, 0, &ul );
1324 vik_viewport_screen_to_coord ( vvp, vik_viewport_get_width(vvp), vik_viewport_get_height(vvp), &br );
1325
1326 maps_layer_draw_section ( vml, vvp, &ul, &br );
1327 }
1328 }
1329}
1330
1331/*************************/
1332/****** DOWNLOADING ******/
1333/*************************/
1334
1335/* pass along data to thread, exists even if layer is deleted. */
1336typedef struct {
1337 gchar *cache_dir;
1338 gchar *filename_buf;
d281e8b4 1339 VikMapsCacheLayout cache_layout;
50a14534
EB
1340 gint x0, y0, xf, yf;
1341 MapCoord mapcoord;
1342 gint maptype;
1343 gint maxlen;
1344 gint mapstoget;
1345 gint redownload;
7114e879 1346 gboolean refresh_display;
550fd035
QT
1347 VikMapsLayer *vml;
1348 VikViewport *vvp;
1349 gboolean map_layer_alive;
1350 GMutex *mutex;
50a14534
EB
1351} MapDownloadInfo;
1352
1353static void mdi_free ( MapDownloadInfo *mdi )
1354{
550fd035 1355 g_mutex_free(mdi->mutex);
50a14534 1356 g_free ( mdi->cache_dir );
e65028db 1357 mdi->cache_dir = NULL;
50a14534 1358 g_free ( mdi->filename_buf );
e65028db 1359 mdi->filename_buf = NULL;
50a14534
EB
1360 g_free ( mdi );
1361}
1362
7bb60307 1363static void weak_ref_cb(gpointer ptr, GObject * dead_vml)
550fd035 1364{
7bb60307 1365 MapDownloadInfo *mdi = ptr;
550fd035
QT
1366 g_mutex_lock(mdi->mutex);
1367 mdi->map_layer_alive = FALSE;
1368 g_mutex_unlock(mdi->mutex);
1369}
1370
634eca0a 1371static int map_download_thread ( MapDownloadInfo *mdi, gpointer threaddata )
50a14534 1372{
825413ba 1373 void *handle = vik_map_source_download_handle_init(MAPS_LAYER_NTH_TYPE(mdi->maptype));
50a14534
EB
1374 guint donemaps = 0;
1375 gint x, y;
1376 for ( x = mdi->x0; x <= mdi->xf; x++ )
1377 {
1378 for ( y = mdi->y0; y <= mdi->yf; y++ )
1379 {
94493114 1380 gboolean remove_mem_cache = FALSE;
84628352 1381 gboolean need_download = FALSE;
d281e8b4 1382
2eb18edc
RN
1383 get_filename ( mdi->cache_dir, mdi->cache_layout,
1384 vik_map_source_get_uniq_id(MAPS_LAYER_NTH_TYPE(mdi->maptype)),
1385 vik_map_source_get_name(MAPS_LAYER_NTH_TYPE(mdi->maptype)),
14b57d17
RN
1386 mdi->mapcoord.scale, mdi->mapcoord.z, x, y, mdi->filename_buf, mdi->maxlen,
1387 vik_map_source_get_file_extension(MAPS_LAYER_NTH_TYPE(mdi->maptype)) );
50a14534 1388
84628352 1389 donemaps++;
634eca0a 1390 int res = a_background_thread_progress ( threaddata, ((gdouble)donemaps) / mdi->mapstoget ); /* this also calls testcancel */
825413ba
SW
1391 if (res != 0) {
1392 vik_map_source_download_handle_cleanup(MAPS_LAYER_NTH_TYPE(mdi->maptype), handle);
634eca0a 1393 return -1;
825413ba 1394 }
84628352 1395
a0058e48 1396 if ( g_file_test ( mdi->filename_buf, G_FILE_TEST_EXISTS ) == FALSE ) {
6a4a29aa
JJ
1397 need_download = TRUE;
1398 remove_mem_cache = TRUE;
a0058e48
JJ
1399
1400 } else { /* in case map file already exists */
1401 switch (mdi->redownload) {
1402 case REDOWNLOAD_NONE:
1403 continue;
1404
1405 case REDOWNLOAD_BAD:
1406 {
1407 /* see if this one is bad or what */
1408 GError *gx = NULL;
1409 GdkPixbuf *pixbuf = gdk_pixbuf_new_from_file ( mdi->filename_buf, &gx );
1410 if (gx || (!pixbuf)) {
1411 g_remove ( mdi->filename_buf );
1412 need_download = TRUE;
1413 remove_mem_cache = TRUE;
1414 g_error_free ( gx );
1415
1416 } else {
1417 g_object_unref ( pixbuf );
1418 }
1419 break;
1420 }
1421
1422 case REDOWNLOAD_NEW:
1423 need_download = TRUE;
1424 remove_mem_cache = TRUE;
1425 break;
1426
1427 case REDOWNLOAD_ALL:
1428 /* FIXME: need a better way than to erase file in case of server/network problem */
1429 g_remove ( mdi->filename_buf );
1430 need_download = TRUE;
1431 remove_mem_cache = TRUE;
1432 break;
1433
1434 case DOWNLOAD_OR_REFRESH:
1435 remove_mem_cache = TRUE;
1436 break;
1437
1438 default:
1439 g_warning ( "redownload state %d unknown\n", mdi->redownload);
1440 }
1441 }
94493114 1442
94493114 1443 mdi->mapcoord.x = x; mdi->mapcoord.y = y;
84628352
QT
1444
1445 if (need_download) {
4e815e90
RN
1446 DownloadResult_t dr = vik_map_source_download( MAPS_LAYER_NTH_TYPE(mdi->maptype), &(mdi->mapcoord), mdi->filename_buf, handle);
1447 switch ( dr ) {
1448 case DOWNLOAD_HTTP_ERROR:
1449 case DOWNLOAD_CONTENT_ERROR: {
1450 // TODO: ?? count up the number of download errors somehow...
1451 gchar* msg = g_strdup_printf ( "%s: %s", vik_maps_layer_get_map_label (mdi->vml), _("Failed to download tile") );
1452 vik_window_statusbar_update ( (VikWindow*)VIK_GTK_WINDOW_FROM_LAYER(mdi->vml), msg, VIK_STATUSBAR_INFO );
1453 g_free (msg);
1454 break;
1455 }
1456 case DOWNLOAD_FILE_WRITE_ERROR: {
1457 gchar* msg = g_strdup_printf ( "%s: %s", vik_maps_layer_get_map_label (mdi->vml), _("Unable to save tile") );
1458 vik_window_statusbar_update ( (VikWindow*)VIK_GTK_WINDOW_FROM_LAYER(mdi->vml), msg, VIK_STATUSBAR_INFO );
1459 g_free (msg);
1460 break;
1461 }
1462 case DOWNLOAD_SUCCESS:
1463 case DOWNLOAD_NOT_REQUIRED:
1464 default:
1465 break;
1466 }
84628352 1467 }
94493114 1468
94493114
QT
1469 g_mutex_lock(mdi->mutex);
1470 if (remove_mem_cache)
820c59f4 1471 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 1472 if (mdi->refresh_display && mdi->map_layer_alive) {
94493114 1473 /* TODO: check if it's on visible area */
da121f9b 1474 vik_layer_emit_update ( VIK_LAYER(mdi->vml) ); // NB update display from background
a0b59f2f 1475 }
94493114 1476 g_mutex_unlock(mdi->mutex);
94493114
QT
1477 mdi->mapcoord.x = mdi->mapcoord.y = 0; /* we're temporarily between downloads */
1478
50a14534
EB
1479 }
1480 }
825413ba 1481 vik_map_source_download_handle_cleanup(MAPS_LAYER_NTH_TYPE(mdi->maptype), handle);
04e54492
QT
1482 g_mutex_lock(mdi->mutex);
1483 if (mdi->map_layer_alive)
7bb60307 1484 g_object_weak_unref(G_OBJECT(mdi->vml), weak_ref_cb, mdi);
04e54492 1485 g_mutex_unlock(mdi->mutex);
634eca0a 1486 return 0;
50a14534
EB
1487}
1488
1489static void mdi_cancel_cleanup ( MapDownloadInfo *mdi )
1490{
1491 if ( mdi->mapcoord.x || mdi->mapcoord.y )
1492 {
2eb18edc
RN
1493 get_filename ( mdi->cache_dir, mdi->cache_layout,
1494 vik_map_source_get_uniq_id(MAPS_LAYER_NTH_TYPE(mdi->maptype)),
1495 vik_map_source_get_name(MAPS_LAYER_NTH_TYPE(mdi->maptype)),
14b57d17
RN
1496 mdi->mapcoord.scale, mdi->mapcoord.z, mdi->mapcoord.x, mdi->mapcoord.y, mdi->filename_buf, mdi->maxlen,
1497 vik_map_source_get_file_extension(MAPS_LAYER_NTH_TYPE(mdi->maptype)) );
45acf79e 1498 if ( g_file_test ( mdi->filename_buf, G_FILE_TEST_EXISTS ) == TRUE)
50a14534 1499 {
8c060406 1500 g_remove ( mdi->filename_buf );
50a14534
EB
1501 }
1502 }
1503}
1504
1505static void start_download_thread ( VikMapsLayer *vml, VikViewport *vvp, const VikCoord *ul, const VikCoord *br, gint redownload )
1506{
1507 gdouble xzoom = vml->xmapzoom ? vml->xmapzoom : vik_viewport_get_xmpp ( vvp );
1508 gdouble yzoom = vml->ymapzoom ? vml->ymapzoom : vik_viewport_get_ympp ( vvp );
1509 MapCoord ulm, brm;
820c59f4 1510 VikMapSource *map = MAPS_LAYER_NTH_TYPE(vml->maptype);
2673b29d
RN
1511
1512 // Don't ever attempt download on direct access
1513 if ( vik_map_source_is_direct_file_access ( map ) )
1514 return;
1515
820c59f4
GB
1516 if ( vik_map_source_coord_to_mapcoord ( map, ul, xzoom, yzoom, &ulm )
1517 && vik_map_source_coord_to_mapcoord ( map, br, xzoom, yzoom, &brm ) )
50a14534
EB
1518 {
1519 MapDownloadInfo *mdi = g_malloc ( sizeof(MapDownloadInfo) );
1520 gint a, b;
1521
550fd035
QT
1522 mdi->vml = vml;
1523 mdi->vvp = vvp;
1524 mdi->map_layer_alive = TRUE;
1525 mdi->mutex = g_mutex_new();
7114e879 1526 mdi->refresh_display = TRUE;
550fd035 1527
50a14534
EB
1528 /* cache_dir and buffer for dest filename */
1529 mdi->cache_dir = g_strdup ( vml->cache_dir );
1530 mdi->maxlen = strlen ( vml->cache_dir ) + 40;
1531 mdi->filename_buf = g_malloc ( mdi->maxlen * sizeof(gchar) );
d281e8b4 1532 mdi->cache_layout = vml->cache_layout;
50a14534
EB
1533 mdi->maptype = vml->maptype;
1534
1535 mdi->mapcoord = ulm;
50a14534
EB
1536 mdi->redownload = redownload;
1537
1538 mdi->x0 = MIN(ulm.x, brm.x);
1539 mdi->xf = MAX(ulm.x, brm.x);
1540 mdi->y0 = MIN(ulm.y, brm.y);
1541 mdi->yf = MAX(ulm.y, brm.y);
1542
1543 mdi->mapstoget = 0;
1544
1545 if ( mdi->redownload ) {
1546 mdi->mapstoget = (mdi->xf - mdi->x0 + 1) * (mdi->yf - mdi->y0 + 1);
1547 } else {
1548 /* calculate how many we need */
1549 for ( a = mdi->x0; a <= mdi->xf; a++ )
1550 {
1551 for ( b = mdi->y0; b <= mdi->yf; b++ )
1552 {
2eb18edc
RN
1553 get_filename ( mdi->cache_dir, mdi->cache_layout,
1554 vik_map_source_get_uniq_id(map),
1555 vik_map_source_get_name(map),
14b57d17
RN
1556 ulm.scale, ulm.z, a, b, mdi->filename_buf, mdi->maxlen,
1557 vik_map_source_get_file_extension(map) );
45acf79e 1558 if ( g_file_test ( mdi->filename_buf, G_FILE_TEST_EXISTS ) == FALSE )
50a14534
EB
1559 mdi->mapstoget++;
1560 }
1561 }
1562 }
1563
1564 mdi->mapcoord.x = mdi->mapcoord.y = 0; /* for cleanup -- no current map */
1565
1566 if ( mdi->mapstoget )
1567 {
97634600
GB
1568 const gchar *tmp_str;
1569 gchar *tmp;
50a14534 1570
97634600
GB
1571 if (redownload)
1572 {
1573 if (redownload == REDOWNLOAD_BAD)
1574 tmp_str = ngettext("Redownloading up to %d %s map...", "Redownloading up to %d %s maps...", mdi->mapstoget);
1575 else
1576 tmp_str = ngettext("Redownloading %d %s map...", "Redownloading %d %s maps...", mdi->mapstoget);
1577 }
1578 else
1579 {
1580 tmp_str = ngettext("Downloading %d %s map...", "Downloading %d %s maps...", mdi->mapstoget);
1581 }
1582 tmp = g_strdup_printf ( tmp_str, mdi->mapstoget, MAPS_LAYER_NTH_LABEL(vml->maptype));
1583
7bb60307 1584 g_object_weak_ref(G_OBJECT(mdi->vml), weak_ref_cb, mdi);
50a14534
EB
1585 /* launch the thread */
1586 a_background_thread ( VIK_GTK_WINDOW_FROM_LAYER(vml), /* parent window */
1587 tmp, /* description string */
1588 (vik_thr_func) map_download_thread, /* function to call within thread */
1589 mdi, /* pass along data */
1590 (vik_thr_free_func) mdi_free, /* function to free pass along data */
1591 (vik_thr_free_func) mdi_cancel_cleanup,
1592 mdi->mapstoget );
1593 g_free ( tmp );
1594 }
1595 else
1596 mdi_free ( mdi );
1597 }
1598}
1599
3ac548fa 1600static void maps_layer_download_section ( VikMapsLayer *vml, VikViewport *vvp, VikCoord *ul, VikCoord *br, gdouble zoom, gint download_method )
7114e879 1601{
7114e879 1602 MapCoord ulm, brm;
820c59f4 1603 VikMapSource *map = MAPS_LAYER_NTH_TYPE(vml->maptype);
7114e879 1604
2673b29d
RN
1605 // Don't ever attempt download on direct access
1606 if ( vik_map_source_is_direct_file_access ( map ) )
1607 return;
1608
820c59f4
GB
1609 if (!vik_map_source_coord_to_mapcoord(map, ul, zoom, zoom, &ulm)
1610 || !vik_map_source_coord_to_mapcoord(map, br, zoom, zoom, &brm)) {
4258f4e2 1611 g_warning("%s() coord_to_mapcoord() failed", __PRETTY_FUNCTION__);
7114e879
QT
1612 return;
1613 }
1614
1615 MapDownloadInfo *mdi = g_malloc(sizeof(MapDownloadInfo));
1616 gint i, j;
1617
1618 mdi->vml = vml;
1619 mdi->vvp = vvp;
1620 mdi->map_layer_alive = TRUE;
1621 mdi->mutex = g_mutex_new();
903dc0b4 1622 mdi->refresh_display = TRUE;
7114e879
QT
1623
1624 mdi->cache_dir = g_strdup ( vml->cache_dir );
1625 mdi->maxlen = strlen ( vml->cache_dir ) + 40;
1626 mdi->filename_buf = g_malloc ( mdi->maxlen * sizeof(gchar) );
1627 mdi->maptype = vml->maptype;
d281e8b4 1628 mdi->cache_layout = vml->cache_layout;
7114e879
QT
1629
1630 mdi->mapcoord = ulm;
3ac548fa 1631 mdi->redownload = download_method;
7114e879
QT
1632
1633 mdi->x0 = MIN(ulm.x, brm.x);
1634 mdi->xf = MAX(ulm.x, brm.x);
1635 mdi->y0 = MIN(ulm.y, brm.y);
1636 mdi->yf = MAX(ulm.y, brm.y);
1637
1638 mdi->mapstoget = 0;
1639
1640 for (i = mdi->x0; i <= mdi->xf; i++) {
1641 for (j = mdi->y0; j <= mdi->yf; j++) {
2eb18edc
RN
1642 get_filename ( mdi->cache_dir, mdi->cache_layout,
1643 vik_map_source_get_uniq_id(map),
1644 vik_map_source_get_name(map),
14b57d17
RN
1645 ulm.scale, ulm.z, i, j, mdi->filename_buf, mdi->maxlen,
1646 vik_map_source_get_file_extension(map) );
45acf79e 1647 if ( g_file_test ( mdi->filename_buf, G_FILE_TEST_EXISTS ) == FALSE )
7114e879
QT
1648 mdi->mapstoget++;
1649 }
1650 }
1651
1652 mdi->mapcoord.x = mdi->mapcoord.y = 0; /* for cleanup -- no current map */
1653
1654 if (mdi->mapstoget) {
4c77d5e0
GB
1655 gchar *tmp;
1656 const gchar *fmt;
eb6b0125
JJ
1657 fmt = ngettext("Downloading %d %s map...",
1658 "Downloading %d %s maps...",
1659 mdi->mapstoget);
4c77d5e0 1660 tmp = g_strdup_printf ( fmt, mdi->mapstoget, MAPS_LAYER_NTH_LABEL(vml->maptype) );
7114e879
QT
1661
1662 g_object_weak_ref(G_OBJECT(mdi->vml), weak_ref_cb, mdi);
1663 /* launch the thread */
1664 a_background_thread ( VIK_GTK_WINDOW_FROM_LAYER(vml), /* parent window */
1665 tmp, /* description string */
1666 (vik_thr_func) map_download_thread, /* function to call within thread */
1667 mdi, /* pass along data */
1668 (vik_thr_free_func) mdi_free, /* function to free pass along data */
1669 (vik_thr_free_func) mdi_cancel_cleanup,
1670 mdi->mapstoget );
1671 g_free ( tmp );
1672 }
1673 else
1674 mdi_free ( mdi );
1675}
1676
3ac548fa
RN
1677/**
1678 * vik_maps_layer_download_section:
1679 * @vml: The Map Layer
1680 * @vvp: The Viewport that the map is on
1681 * @ul: Upper left coordinate of the area to be downloaded
1682 * @br: Bottom right coordinate of the area to be downloaded
1683 * @zoom: The zoom level at which the maps are to be download
1684 *
1685 * Download a specified map area at a certain zoom level
1686 */
1687void vik_maps_layer_download_section ( VikMapsLayer *vml, VikViewport *vvp, VikCoord *ul, VikCoord *br, gdouble zoom )
1688{
1689 maps_layer_download_section (vml, vvp, ul, br, zoom, REDOWNLOAD_NONE);
1690}
1691
50a14534
EB
1692static void maps_layer_redownload_bad ( VikMapsLayer *vml )
1693{
1694 start_download_thread ( vml, vml->redownload_vvp, &(vml->redownload_ul), &(vml->redownload_br), REDOWNLOAD_BAD );
1695}
a7c1acf1 1696
50a14534
EB
1697static void maps_layer_redownload_all ( VikMapsLayer *vml )
1698{
1699 start_download_thread ( vml, vml->redownload_vvp, &(vml->redownload_ul), &(vml->redownload_br), REDOWNLOAD_ALL );
1700}
1701
a7c1acf1
GB
1702static void maps_layer_redownload_new ( VikMapsLayer *vml )
1703{
1704 start_download_thread ( vml, vml->redownload_vvp, &(vml->redownload_ul), &(vml->redownload_br), REDOWNLOAD_NEW );
1705}
1706
450d8665
RN
1707/**
1708 * Display a simple dialog with information about this particular map tile
1709 */
1710static void maps_layer_tile_info ( VikMapsLayer *vml )
1711{
1712 VikMapSource *map = MAPS_LAYER_NTH_TYPE(vml->maptype);
1713
1714 gdouble xzoom = vml->xmapzoom ? vml->xmapzoom : vik_viewport_get_xmpp ( vml->redownload_vvp );
1715 gdouble yzoom = vml->ymapzoom ? vml->ymapzoom : vik_viewport_get_ympp ( vml->redownload_vvp );
1716 MapCoord ulm;
1717
1718 if ( !vik_map_source_coord_to_mapcoord ( map, &(vml->redownload_ul), xzoom, yzoom, &ulm ) )
1719 return;
1720
1721 gchar *filename = NULL;
1722 gchar *message = NULL;
1723 gchar *source = NULL;
1724
1725 if ( vik_map_source_is_direct_file_access ( map ) ) {
0fb11294
RN
1726 if ( vik_map_source_is_mbtiles ( map ) ) {
1727 filename = g_strdup ( vml->filename );
1728#ifdef HAVE_SQLITE3_H
1729 // And whether to bother going into the SQL to check it's really there or not...
1730 gchar *exists = NULL;
8c778528 1731 gint zoom = 17 - ulm.scale;
0fb11294 1732 if ( vml->mbtiles ) {
8c778528 1733 GdkPixbuf *pixbuf = get_pixbuf_sql_exec ( vml->mbtiles, ulm.x, ulm.y, zoom );
0fb11294
RN
1734 if ( pixbuf ) {
1735 exists = g_strdup ( _("YES") );
1736 g_object_unref ( G_OBJECT(pixbuf) );
1737 }
1738 else {
1739 exists = g_strdup ( _("NO") );
1740 }
1741 }
1742 else
1743 exists = g_strdup ( _("NO") );
8c778528 1744 gint flip_y = (gint) pow(2, zoom)-1 - ulm.y;
0fb11294 1745 // NB Also handles .jpg automatically due to pixbuf_new_from () support - although just print png for now.
8c778528 1746 source = g_strdup_printf ( "%s (%d%s%d%s%d.%s %s)", filename, zoom, G_DIR_SEPARATOR_S, ulm.x, G_DIR_SEPARATOR_S, flip_y, "png", exists );
0fb11294
RN
1747 g_free ( exists );
1748#else
1749 source = g_strdup ( _("Not available") );
1750#endif
1751 }
1752 else {
2eb18edc
RN
1753 guint max_path_len = strlen(vml->cache_dir) + 40;
1754 filename = g_malloc ( max_path_len * sizeof(char) );
1755 get_filename ( vml->cache_dir, VIK_MAPS_CACHE_LAYOUT_OSM,
1756 vik_map_source_get_uniq_id(map),
1757 NULL,
14b57d17
RN
1758 ulm.scale, ulm.z, ulm.x, ulm.y, filename, max_path_len,
1759 vik_map_source_get_file_extension(map) );
0fb11294
RN
1760 source = g_strconcat ( "file://", filename, NULL );
1761 }
450d8665
RN
1762 }
1763 else {
d281e8b4
RN
1764 guint max_path_len = strlen(vml->cache_dir) + 40;
1765 filename = g_malloc ( max_path_len * sizeof(char) );
2eb18edc
RN
1766 get_filename ( vml->cache_dir, vml->cache_layout,
1767 vik_map_source_get_uniq_id(map),
1768 vik_map_source_get_name(map),
14b57d17
RN
1769 ulm.scale, ulm.z, ulm.x, ulm.y, filename, max_path_len,
1770 vik_map_source_get_file_extension(map) );
450d8665
RN
1771 source = g_strdup_printf ( "http://%s%s",
1772 vik_map_source_default_get_hostname ( VIK_MAP_SOURCE_DEFAULT(map) ),
1773 vik_map_source_default_get_uri ( VIK_MAP_SOURCE_DEFAULT(map), &ulm ) );
1774 }
1775
1776 if ( g_file_test ( filename, G_FILE_TEST_EXISTS ) ) {
1777
1778 // Get some timestamp information of the tile
1779 struct stat stat_buf;
1780 if ( g_stat ( filename, &stat_buf ) == 0 ) {
6be843d5
RN
1781 gchar time_buf[64];
1782 strftime ( time_buf, sizeof(time_buf), "%c", gmtime((const time_t *)&stat_buf.st_mtime) );
1783 message = g_strdup_printf ( _("\nSource: %s\n\nTile File: %s\nTile File Timestamp: %s"), source, filename, time_buf );
450d8665 1784 }
0d744b77
RN
1785 else {
1786 message = g_strdup_printf ( _("\nSource: %s\n\nTile File: %s\nTile File Timestamp: Not Available"), source, filename );
1787 }
1788 // Show the info
1789 a_dialog_info_msg ( VIK_GTK_WINDOW_FROM_LAYER(vml), message );
1790 }
1791 else {
1792 message = g_strdup_printf ( _("\nSource: %s\n\nTile File: %s [Not Available]"), source, filename );
1793 a_dialog_warning_msg ( VIK_GTK_WINDOW_FROM_LAYER(vml), message );
450d8665 1794 }
450d8665
RN
1795
1796 g_free ( message );
1797 g_free ( source );
1798 g_free ( filename );
1799}
1800
50a14534
EB
1801static gboolean maps_layer_download_release ( VikMapsLayer *vml, GdkEventButton *event, VikViewport *vvp )
1802{
941aa6e9
AF
1803 if (!vml || vml->vl.type != VIK_LAYER_MAPS)
1804 return FALSE;
50a14534
EB
1805 if ( vml->dl_tool_x != -1 && vml->dl_tool_y != -1 )
1806 {
1807 if ( event->button == 1 )
1808 {
1809 VikCoord ul, br;
1810 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 );
1811 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 1812 start_download_thread ( vml, vvp, &ul, &br, DOWNLOAD_OR_REFRESH );
50a14534
EB
1813 vml->dl_tool_x = vml->dl_tool_y = -1;
1814 return TRUE;
1815 }
1816 else
1817 {
1818 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) );
1819 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) );
1820
1821 vml->redownload_vvp = vvp;
1822
1823 vml->dl_tool_x = vml->dl_tool_y = -1;
1824
1825 if ( ! vml->dl_right_click_menu ) {
1826 GtkWidget *item;
1827 vml->dl_right_click_menu = GTK_MENU ( gtk_menu_new () );
1828
94ee2264 1829 item = gtk_menu_item_new_with_mnemonic ( _("Redownload _Bad Map(s)") );
50a14534
EB
1830 g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(maps_layer_redownload_bad), vml );
1831 gtk_menu_shell_append ( GTK_MENU_SHELL(vml->dl_right_click_menu), item );
1832
94ee2264 1833 item = gtk_menu_item_new_with_mnemonic ( _("Redownload _New Map(s)") );
a7c1acf1
GB
1834 g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(maps_layer_redownload_new), vml );
1835 gtk_menu_shell_append ( GTK_MENU_SHELL(vml->dl_right_click_menu), item );
1836
94ee2264 1837 item = gtk_menu_item_new_with_mnemonic ( _("Redownload _All Map(s)") );
50a14534
EB
1838 g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(maps_layer_redownload_all), vml );
1839 gtk_menu_shell_append ( GTK_MENU_SHELL(vml->dl_right_click_menu), item );
450d8665
RN
1840
1841 item = gtk_image_menu_item_new_with_mnemonic ( _("_Show Tile Information") );
1842 gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_INFO, GTK_ICON_SIZE_MENU) );
1843 g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(maps_layer_tile_info), vml );
1844 gtk_menu_shell_append (GTK_MENU_SHELL(vml->dl_right_click_menu), item);
50a14534
EB
1845 }
1846
1847 gtk_menu_popup ( vml->dl_right_click_menu, NULL, NULL, NULL, NULL, event->button, event->time );
1848 gtk_widget_show_all ( GTK_WIDGET(vml->dl_right_click_menu) );
1849 }
1850 }
1851 return FALSE;
1852}
1853
941aa6e9
AF
1854static gpointer maps_layer_download_create ( VikWindow *vw, VikViewport *vvp)
1855{
1856 return vvp;
1857}
1858
50a14534
EB
1859static gboolean maps_layer_download_click ( VikMapsLayer *vml, GdkEventButton *event, VikViewport *vvp )
1860{
1861 MapCoord tmp;
941aa6e9
AF
1862 if (!vml || vml->vl.type != VIK_LAYER_MAPS)
1863 return FALSE;
820c59f4
GB
1864 VikMapSource *map = MAPS_LAYER_NTH_TYPE(vml->maptype);
1865 if ( vik_map_source_get_drawmode(map) == vik_viewport_get_drawmode ( vvp ) &&
1866 vik_map_source_coord_to_mapcoord ( map, vik_viewport_get_center ( vvp ),
50a14534
EB
1867 vml->xmapzoom ? vml->xmapzoom : vik_viewport_get_xmpp ( vvp ),
1868 vml->ymapzoom ? vml->ymapzoom : vik_viewport_get_ympp ( vvp ),
1869 &tmp ) ) {
1870 vml->dl_tool_x = event->x, vml->dl_tool_y = event->y;
1871 return TRUE;
1872 }
1873 return FALSE;
50a14534
EB
1874}
1875
7a7ba2f1
RN
1876// A slightly better way of defining the menu callback information
1877// This should be easier to extend/rework compared to previously
1878typedef enum {
1879 MA_VML = 0,
1880 MA_VVP,
1881 MA_LAST
1882} menu_array_index;
1883
1884typedef gpointer menu_array_values[MA_LAST];
1885
1886static void download_onscreen_maps ( menu_array_values values, gint redownload )
50a14534 1887{
7a7ba2f1
RN
1888 VikMapsLayer *vml = VIK_MAPS_LAYER(values[MA_VML]);
1889 VikViewport *vvp = VIK_VIEWPORT(values[MA_VVP]);
314c1ccc 1890 VikViewportDrawMode vp_drawmode = vik_viewport_get_drawmode ( vvp );
50a14534
EB
1891
1892 gdouble xzoom = vml->xmapzoom ? vml->xmapzoom : vik_viewport_get_xmpp ( vvp );
1893 gdouble yzoom = vml->ymapzoom ? vml->ymapzoom : vik_viewport_get_ympp ( vvp );
1894
1895 VikCoord ul, br;
1896 MapCoord ulm, brm;
1897
1898 vik_viewport_screen_to_coord ( vvp, 0, 0, &ul );
1899 vik_viewport_screen_to_coord ( vvp, vik_viewport_get_width(vvp), vik_viewport_get_height(vvp), &br );
1900
820c59f4
GB
1901 VikMapSource *map = MAPS_LAYER_NTH_TYPE(vml->maptype);
1902 if ( vik_map_source_get_drawmode(map) == vp_drawmode &&
1903 vik_map_source_coord_to_mapcoord ( map, &ul, xzoom, yzoom, &ulm ) &&
1904 vik_map_source_coord_to_mapcoord ( map, &br, xzoom, yzoom, &brm ) )
50817314 1905 start_download_thread ( vml, vvp, &ul, &br, redownload );
820c59f4
GB
1906 else if (vik_map_source_get_drawmode(map) != vp_drawmode) {
1907 const gchar *drawmode_name = vik_viewport_get_drawmode_name (vvp, vik_map_source_get_drawmode(map));
4c77d5e0 1908 gchar *err = g_strdup_printf(_("Wrong drawmode for this map.\nSelect \"%s\" from View menu and try again."), _(drawmode_name));
314c1ccc
QT
1909 a_dialog_error_msg ( VIK_GTK_WINDOW_FROM_LAYER(vml), err );
1910 g_free(err);
1911 }
50a14534 1912 else
4c77d5e0 1913 a_dialog_error_msg ( VIK_GTK_WINDOW_FROM_LAYER(vml), _("Wrong zoom level for this map.") );
50a14534
EB
1914
1915}
1916
7a7ba2f1 1917static void maps_layer_download_missing_onscreen_maps ( menu_array_values values )
50817314 1918{
7a7ba2f1 1919 download_onscreen_maps( values, REDOWNLOAD_NONE);
50817314
GB
1920}
1921
7a7ba2f1 1922static void maps_layer_download_new_onscreen_maps ( menu_array_values values )
6a4a29aa 1923{
7a7ba2f1 1924 download_onscreen_maps( values, REDOWNLOAD_NEW);
6a4a29aa
JJ
1925}
1926
7a7ba2f1 1927static void maps_layer_redownload_all_onscreen_maps ( menu_array_values values )
50817314 1928{
7a7ba2f1 1929 download_onscreen_maps( values, REDOWNLOAD_ALL);
50817314
GB
1930}
1931
b03ae39b
RN
1932static void maps_layers_about ( gpointer vml_vvp[2] )
1933{
1934 VikMapsLayer *vml = vml_vvp[0];
1935 VikMapSource *map = MAPS_LAYER_NTH_TYPE(vml->maptype);
1936
1937 if ( vik_map_source_get_license (map) )
1938 maps_show_license ( VIK_GTK_WINDOW_FROM_LAYER(vml), map );
1939 else
1940 a_dialog_info_msg ( VIK_GTK_WINDOW_FROM_LAYER(vml),
1941 vik_map_source_get_label (map) );
1942}
1943
3ac548fa
RN
1944/**
1945 * maps_layer_how_many_maps:
1946 * Copied from maps_layer_download_section but without the actual download and this returns a value
1947 */
1948static gint maps_layer_how_many_maps ( VikMapsLayer *vml, VikViewport *vvp, VikCoord *ul, VikCoord *br, gdouble zoom, gint redownload )
1949{
1950 MapCoord ulm, brm;
1951 VikMapSource *map = MAPS_LAYER_NTH_TYPE(vml->maptype);
1952
1953 if ( vik_map_source_is_direct_file_access ( map ) )
1954 return 0;
1955
1956 if (!vik_map_source_coord_to_mapcoord(map, ul, zoom, zoom, &ulm)
1957 || !vik_map_source_coord_to_mapcoord(map, br, zoom, zoom, &brm)) {
1958 g_warning("%s() coord_to_mapcoord() failed", __PRETTY_FUNCTION__);
1959 return 0;
1960 }
1961
1962 MapDownloadInfo *mdi = g_malloc(sizeof(MapDownloadInfo));
1963 gint i, j;
1964
1965 mdi->vml = vml;
1966 mdi->vvp = vvp;
1967 mdi->map_layer_alive = TRUE;
1968 mdi->mutex = g_mutex_new();
1969 mdi->refresh_display = FALSE;
1970
1971 mdi->cache_dir = g_strdup ( vml->cache_dir );
1972 mdi->maxlen = strlen ( vml->cache_dir ) + 40;
1973 mdi->filename_buf = g_malloc ( mdi->maxlen * sizeof(gchar) );
1974 mdi->maptype = vml->maptype;
d281e8b4 1975 mdi->cache_layout = vml->cache_layout;
3ac548fa
RN
1976
1977 mdi->mapcoord = ulm;
1978 mdi->redownload = redownload;
1979
1980 mdi->x0 = MIN(ulm.x, brm.x);
1981 mdi->xf = MAX(ulm.x, brm.x);
1982 mdi->y0 = MIN(ulm.y, brm.y);
1983 mdi->yf = MAX(ulm.y, brm.y);
1984
1985 mdi->mapstoget = 0;
1986
1987 if ( mdi->redownload == REDOWNLOAD_ALL ) {
1988 mdi->mapstoget = (mdi->xf - mdi->x0 + 1) * (mdi->yf - mdi->y0 + 1);
1989 }
1990 else {
1991 /* calculate how many we need */
1992 for (i = mdi->x0; i <= mdi->xf; i++) {
1993 for (j = mdi->y0; j <= mdi->yf; j++) {
2eb18edc
RN
1994 get_filename ( mdi->cache_dir, mdi->cache_layout,
1995 vik_map_source_get_uniq_id(map),
1996 vik_map_source_get_name(map),
14b57d17
RN
1997 ulm.scale, ulm.z, i, j, mdi->filename_buf, mdi->maxlen,
1998 vik_map_source_get_file_extension(map) );
3ac548fa
RN
1999 if ( mdi->redownload == REDOWNLOAD_NEW ) {
2000 // Assume the worst - always a new file
2001 // Absolute value would requires server lookup - but that is too slow
2002 mdi->mapstoget++;
d281e8b4 2003 }
3ac548fa
RN
2004 else {
2005 if ( g_file_test ( mdi->filename_buf, G_FILE_TEST_EXISTS ) == FALSE ) {
2006 // Missing
2007 mdi->mapstoget++;
2008 }
2009 else {
2010 if ( mdi->redownload == REDOWNLOAD_BAD ) {
2011 /* see if this one is bad or what */
2012 GError *gx = NULL;
2013 GdkPixbuf *pixbuf = gdk_pixbuf_new_from_file ( mdi->filename_buf, &gx );
2014 if (gx || (!pixbuf)) {
2015 mdi->mapstoget++;
2016 }
2017 break;
2018 // Other download cases already considered or just ignored
2019 }
2020 }
2021 }
2022 }
2023 }
2024 }
2025
2026 gint rv = mdi->mapstoget;
2027
2028 mdi_free ( mdi );
2029
2030 return rv;
2031}
2032
2033/**
2034 * maps_dialog_zoom_between:
2035 * This dialog is specific to the map layer, so it's here rather than in dialog.c
2036 */
2037gboolean maps_dialog_zoom_between ( GtkWindow *parent,
2038 gchar *title,
2039 gchar *zoom_list[],
2040 gint default_zoom1,
2041 gint default_zoom2,
2042 gint *selected_zoom1,
2043 gint *selected_zoom2,
2044 gchar *download_list[],
2045 gint default_download,
2046 gint *selected_download )
2047{
2048 GtkWidget *dialog = gtk_dialog_new_with_buttons ( title,
2049 parent,
2050 GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
2051 GTK_STOCK_OK, GTK_RESPONSE_ACCEPT,
2052 GTK_STOCK_CANCEL, GTK_RESPONSE_REJECT,
2053 NULL );
2054 gtk_dialog_set_default_response ( GTK_DIALOG(dialog), GTK_RESPONSE_ACCEPT );
2055 GtkWidget *response_w = NULL;
2056#if GTK_CHECK_VERSION (2, 20, 0)
2057 response_w = gtk_dialog_get_widget_for_response ( GTK_DIALOG(dialog), GTK_RESPONSE_ACCEPT );
2058#endif
2059 GtkWidget *zoom_label1 = gtk_label_new ( _("Zoom Start:") );
2060 GtkWidget *zoom_combo1 = vik_combo_box_text_new();
2061 gchar **s;
2062 for (s = zoom_list; *s; s++)
2063 vik_combo_box_text_append ( zoom_combo1, *s );
2064 gtk_combo_box_set_active ( GTK_COMBO_BOX(zoom_combo1), default_zoom1 );
2065
2066 GtkWidget *zoom_label2 = gtk_label_new ( _("Zoom End:") );
2067 GtkWidget *zoom_combo2 = vik_combo_box_text_new();
2068 for (s = zoom_list; *s; s++)
2069 vik_combo_box_text_append ( zoom_combo2, *s );
2070 gtk_combo_box_set_active ( GTK_COMBO_BOX(zoom_combo2), default_zoom2 );
2071
2072 GtkWidget *download_label = gtk_label_new(_("Download Maps Method:"));
2073 GtkWidget *download_combo = vik_combo_box_text_new();
2074 for (s = download_list; *s; s++)
2075 vik_combo_box_text_append ( download_combo, *s );
2076 gtk_combo_box_set_active ( GTK_COMBO_BOX(download_combo), default_download );
2077
2078 GtkTable *box = GTK_TABLE(gtk_table_new(3, 2, FALSE));
2079 gtk_table_attach_defaults (box, GTK_WIDGET(zoom_label1), 0, 1, 0, 1);
2080 gtk_table_attach_defaults (box, GTK_WIDGET(zoom_combo1), 1, 2, 0, 1);
2081 gtk_table_attach_defaults (box, GTK_WIDGET(zoom_label2), 0, 1, 1, 2);
2082 gtk_table_attach_defaults (box, GTK_WIDGET(zoom_combo2), 1, 2, 1, 2);
2083 gtk_table_attach_defaults (box, GTK_WIDGET(download_label), 0, 1, 2, 3);
2084 gtk_table_attach_defaults (box, GTK_WIDGET(download_combo), 1, 2, 2, 3);
2085
2086 gtk_box_pack_start ( GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(dialog))), GTK_WIDGET(box), FALSE, FALSE, 5 );
2087
2088 if ( response_w )
2089 gtk_widget_grab_focus ( response_w );
2090
2091 gtk_widget_show_all ( dialog );
2092 if ( gtk_dialog_run ( GTK_DIALOG(dialog) ) != GTK_RESPONSE_ACCEPT ) {
2093 gtk_widget_destroy(dialog);
2094 return FALSE;
2095 }
2096
2097 // Return selected options
2098 *selected_zoom1 = gtk_combo_box_get_active ( GTK_COMBO_BOX(zoom_combo1) );
2099 *selected_zoom2 = gtk_combo_box_get_active ( GTK_COMBO_BOX(zoom_combo2) );
2100 *selected_download = gtk_combo_box_get_active ( GTK_COMBO_BOX(download_combo) );
2101
2102 gtk_widget_destroy(dialog);
2103 return TRUE;
2104}
2105
2106// My best guess of sensible limits
2107#define REALLY_LARGE_AMOUNT_OF_TILES 5000
2108#define CONFIRM_LARGE_AMOUNT_OF_TILES 500
2109
2110/**
2111 * Get all maps in the region for zoom levels specified by the user
2112 * Sort of similar to trw_layer_download_map_along_track_cb function
2113 */
7a7ba2f1 2114static void maps_layer_download_all ( menu_array_values values )
3ac548fa 2115{
7a7ba2f1
RN
2116 VikMapsLayer *vml = VIK_MAPS_LAYER(values[MA_VML]);
2117 VikViewport *vvp = VIK_VIEWPORT(values[MA_VVP]);
3ac548fa
RN
2118
2119 // I don't think we should allow users to hammer the servers too much...
2120 // Delibrately not allowing lowest zoom levels
2121 // Still can give massive numbers to download
2122 // A screen size of 1600x1200 gives around 300,000 tiles between 1..128 when none exist before !!
2123 gchar *zoom_list[] = {"1", "2", "4", "8", "16", "32", "64", "128", "256", "512", "1024", NULL };
2124 gdouble zoom_vals[] = {1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024};
2125
2126 gint selected_zoom1, selected_zoom2, default_zoom, lower_zoom;
2127 gint selected_download_method;
2128
2129 gdouble cur_zoom = vik_viewport_get_zoom(vvp);
2130
2131 for (default_zoom = 0; default_zoom < sizeof(zoom_vals)/sizeof(gdouble); default_zoom++) {
2132 if (cur_zoom == zoom_vals[default_zoom])
2133 break;
2134 }
2135 default_zoom = (default_zoom == sizeof(zoom_vals)/sizeof(gdouble)) ? sizeof(zoom_vals)/sizeof(gdouble) - 1 : default_zoom;
2136
2137 // Default to only 2 zoom levels below the current one
2138 if (default_zoom > 1 )
2139 lower_zoom = default_zoom - 2;
2140 else
2141 lower_zoom = default_zoom;
2142
2143 // redownload method - needs to align with REDOWNLOAD* macro values
2144 gchar *download_list[] = { _("Missing"), _("Bad"), _("New"), _("Reload All"), NULL };
2145
2146 gchar *title = g_strdup_printf ( ("%s: %s"), vik_maps_layer_get_map_label (vml), _("Download for Zoom Levels") );
2147
2148 if ( ! maps_dialog_zoom_between ( VIK_GTK_WINDOW_FROM_LAYER(vml),
2149 title,
2150 zoom_list,
2151 lower_zoom,
2152 default_zoom,
2153 &selected_zoom1,
2154 &selected_zoom2,
2155 download_list,
2156 REDOWNLOAD_NONE, // AKA Missing
2157 &selected_download_method ) ) {
2158 // Cancelled
2159 g_free ( title );
2160 return;
2161 }
2162 g_free ( title );
2163
2164 // Find out new current positions
2165 gdouble min_lat, max_lat, min_lon, max_lon;
2166 VikCoord vc_ul, vc_br;
2167 vik_viewport_get_min_max_lat_lon ( vvp, &min_lat, &max_lat, &min_lon, &max_lon );
2168 struct LatLon ll_ul = { max_lat, min_lon };
2169 struct LatLon ll_br = { min_lat, max_lon };
2170 vik_coord_load_from_latlon ( &vc_ul, vik_viewport_get_coord_mode (vvp), &ll_ul );
2171 vik_coord_load_from_latlon ( &vc_br, vik_viewport_get_coord_mode (vvp), &ll_br );
2172
2173 // Get Maps Count - call for each zoom level (in reverse)
2174 // With REDOWNLOAD_NEW this is a possible maximum
2175 // With REDOWNLOAD_NONE this only missing ones - however still has a server lookup per tile
2176 gint map_count = 0;
2177 gint zz;
2178 for ( zz = selected_zoom2; zz >= selected_zoom1; zz-- ) {
2179 map_count = map_count + maps_layer_how_many_maps ( vml, vvp, &vc_ul, &vc_br, zoom_vals[zz], selected_download_method );
2180 }
2181
2182 g_debug ("vikmapslayer: download request map count %d for method %d", map_count, selected_download_method);
2183
2184 // Absolute protection of hammering a map server
2185 if ( map_count > REALLY_LARGE_AMOUNT_OF_TILES ) {
2186 gchar *str = g_strdup_printf (_("You are not allowed to download more than %d tiles in one go (requested %d)"), REALLY_LARGE_AMOUNT_OF_TILES, map_count);
2187 a_dialog_error_msg ( VIK_GTK_WINDOW_FROM_LAYER(vml), str );
2188 g_free (str);
2189 return;
2190 }
2191
2192 // Confirm really want to do this
2193 if ( map_count > CONFIRM_LARGE_AMOUNT_OF_TILES ) {
2194 gchar *str = g_strdup_printf (_("Do you really want to download %d tiles?"), map_count);
2195 gboolean ans = a_dialog_yes_or_no ( VIK_GTK_WINDOW_FROM_LAYER(vml), str, NULL );
2196 g_free (str);
2197 if ( ! ans )
2198 return;
2199 }
2200
2201 // Get Maps - call for each zoom level (in reverse)
2202 for ( zz = selected_zoom2; zz >= selected_zoom1; zz-- ) {
2203 maps_layer_download_section ( vml, vvp, &vc_ul, &vc_br, zoom_vals[zz], selected_download_method );
2204 }
2205}
2206
50a14534
EB
2207static void maps_layer_add_menu_items ( VikMapsLayer *vml, GtkMenu *menu, VikLayersPanel *vlp )
2208{
50a14534 2209 GtkWidget *item;
7a7ba2f1
RN
2210 static menu_array_values values;
2211 values[MA_VML] = vml;
2212 values[MA_VVP] = vik_layers_panel_get_viewport( VIK_LAYERS_PANEL(vlp) );
50a14534
EB
2213
2214 item = gtk_menu_item_new();
2215 gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item );
2216 gtk_widget_show ( item );
2217
555ec6f6
RN
2218 /* Now with icons */
2219 item = gtk_image_menu_item_new_with_mnemonic ( _("Download _Missing Onscreen Maps") );
2220 gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_ADD, GTK_ICON_SIZE_MENU) );
7a7ba2f1 2221 g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(maps_layer_download_missing_onscreen_maps), values );
50a14534
EB
2222 gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
2223 gtk_widget_show ( item );
50817314 2224
c81ded98 2225 if ( vik_map_source_supports_download_only_new (MAPS_LAYER_NTH_TYPE(vml->maptype)) ) {
555ec6f6
RN
2226 item = gtk_image_menu_item_new_with_mnemonic ( _("Download _New Onscreen Maps") );
2227 gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_REDO, GTK_ICON_SIZE_MENU) );
7a7ba2f1 2228 g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(maps_layer_download_new_onscreen_maps), values );
6a4a29aa
JJ
2229 gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
2230 gtk_widget_show ( item );
2231 }
2232
555ec6f6
RN
2233 item = gtk_image_menu_item_new_with_mnemonic ( _("Reload _All Onscreen Maps") );
2234 gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_REFRESH, GTK_ICON_SIZE_MENU) );
7a7ba2f1 2235 g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(maps_layer_redownload_all_onscreen_maps), values );
50817314
GB
2236 gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
2237 gtk_widget_show ( item );
3ac548fa
RN
2238
2239 item = gtk_image_menu_item_new_with_mnemonic ( _("Download Maps in _Zoom Levels...") );
2240 gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_DND_MULTIPLE, GTK_ICON_SIZE_MENU) );
7a7ba2f1 2241 g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(maps_layer_download_all), values );
3ac548fa
RN
2242 gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
2243 gtk_widget_show ( item );
b03ae39b
RN
2244
2245 item = gtk_image_menu_item_new_from_stock ( GTK_STOCK_ABOUT, NULL );
7a7ba2f1 2246 g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(maps_layers_about), values );
b03ae39b
RN
2247 gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
2248 gtk_widget_show ( item );
50a14534 2249}
6b59f63d
RN
2250
2251/**
2252 * Enable downloading maps of the current screen area either 'new' or 'everything'
2253 */
2254void vik_maps_layer_download ( VikMapsLayer *vml, VikViewport *vvp, gboolean only_new )
2255{
2256 if ( !vml ) return;
2257 if ( !vvp ) return;
2258
7a7ba2f1
RN
2259 static menu_array_values values;
2260 values[MA_VML] = vml;
2261 values[MA_VVP] = vvp;
6b59f63d
RN
2262
2263 if ( only_new )
2264 // Get only new maps
7a7ba2f1 2265 maps_layer_download_new_onscreen_maps ( values );
6b59f63d
RN
2266 else
2267 // Redownload everything
7a7ba2f1 2268 maps_layer_redownload_all_onscreen_maps ( values );
6b59f63d 2269}