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