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