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