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