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