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