]> git.street.me.uk Git - andy/viking.git/blame - src/vikmapslayer.c
Increase line reading length
[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
aac9da8c
RN
716 gboolean sensitive = ( MAP_ID_OSM_ON_DISK != vlpd.u &&
717 MAP_ID_MBTILES != vlpd.u &&
718 MAP_ID_OSM_METATILES != vlpd.u );
0fb11294
RN
719 GtkWidget **ww1 = values[UI_CHG_WIDGETS];
720 GtkWidget **ww2 = values[UI_CHG_LABELS];
721 GtkWidget *w1 = ww1[PARAM_ONLYMISSING];
722 GtkWidget *w2 = ww2[PARAM_ONLYMISSING];
723 GtkWidget *w3 = ww1[PARAM_AUTODOWNLOAD];
724 GtkWidget *w4 = ww2[PARAM_AUTODOWNLOAD];
725 // Depends on autodownload value
726 gboolean missing_sense = sensitive && VIK_MAPS_LAYER(values[UI_CHG_LAYER])->autodownload;
727 if ( w1 ) gtk_widget_set_sensitive ( w1, missing_sense );
728 if ( w2 ) gtk_widget_set_sensitive ( w2, missing_sense );
729 if ( w3 ) gtk_widget_set_sensitive ( w3, sensitive );
730 if ( w4 ) gtk_widget_set_sensitive ( w4, sensitive );
731
d281e8b4
RN
732 // Cache type not applicable either
733 GtkWidget *w9 = ww1[PARAM_CACHE_LAYOUT];
734 GtkWidget *w10 = ww2[PARAM_CACHE_LAYOUT];
735 if ( w9 ) gtk_widget_set_sensitive ( w9, sensitive );
736 if ( w10 ) gtk_widget_set_sensitive ( w10, sensitive );
737
0fb11294
RN
738 // File only applicable for MBTiles type
739 // Directory for all other types
249d6a28 740 sensitive = ( MAP_ID_MBTILES == vlpd.u);
0fb11294
RN
741 GtkWidget *w5 = ww1[PARAM_FILE];
742 GtkWidget *w6 = ww2[PARAM_FILE];
743 GtkWidget *w7 = ww1[PARAM_CACHE_DIR];
744 GtkWidget *w8 = ww2[PARAM_CACHE_DIR];
745 if ( w5 ) gtk_widget_set_sensitive ( w5, sensitive );
746 if ( w6 ) gtk_widget_set_sensitive ( w6, sensitive );
747 if ( w7 ) gtk_widget_set_sensitive ( w7, !sensitive );
748 if ( w8 ) gtk_widget_set_sensitive ( w8, !sensitive );
749
750 break;
751 }
752
db43cfa4
RN
753 // Alter sensitivity of 'download only missing' widgets according to the autodownload setting.
754 case PARAM_AUTODOWNLOAD: {
755 // Get new value
756 VikLayerParamData vlpd = a_uibuilder_widget_get_value ( widget, values[UI_CHG_PARAM] );
757 GtkWidget **ww1 = values[UI_CHG_WIDGETS];
758 GtkWidget **ww2 = values[UI_CHG_LABELS];
759 GtkWidget *w1 = ww1[PARAM_ONLYMISSING];
760 GtkWidget *w2 = ww2[PARAM_ONLYMISSING];
761 if ( w1 ) gtk_widget_set_sensitive ( w1, vlpd.b );
762 if ( w2 ) gtk_widget_set_sensitive ( w2, vlpd.b );
763 break;
764 }
765 default: break;
766 }
767}
768
50a14534
EB
769/****************************************/
770/****** CREATING, COPYING, FREEING ******/
771/****************************************/
772
773static VikMapsLayer *maps_layer_new ( VikViewport *vvp )
774{
775 VikMapsLayer *vml = VIK_MAPS_LAYER ( g_object_new ( VIK_MAPS_LAYER_TYPE, NULL ) );
a0c65899 776 vik_layer_set_type ( VIK_LAYER(vml), VIK_LAYER_MAPS );
a7023a1b
RN
777
778 vik_layer_set_defaults ( VIK_LAYER(vml), vvp );
779
50a14534 780 vml->dl_tool_x = vml->dl_tool_y = -1;
10ca2bfe
QT
781 vml->last_center = NULL;
782 vml->last_xmpp = 0.0;
783 vml->last_ympp = 0.0;
50a14534
EB
784
785 vml->dl_right_click_menu = NULL;
0fb11294 786 vml->filename = NULL;
50a14534
EB
787 return vml;
788}
789
790static void maps_layer_free ( VikMapsLayer *vml )
791{
e65028db
GB
792 g_free ( vml->cache_dir );
793 vml->cache_dir = NULL;
50a14534 794 if ( vml->dl_right_click_menu )
4f14a010 795 g_object_ref_sink ( G_OBJECT(vml->dl_right_click_menu) );
e65028db
GB
796 g_free(vml->last_center);
797 vml->last_center = NULL;
0fb11294
RN
798 g_free ( vml->filename );
799 vml->filename = NULL;
800
801#ifdef HAVE_SQLITE3_H
802 VikMapSource *map = MAPS_LAYER_NTH_TYPE(vml->maptype);
803 if ( vik_map_source_is_mbtiles ( map ) ) {
804 if ( vml->mbtiles ) {
805 int ans = sqlite3_close ( vml->mbtiles );
806 if ( ans != SQLITE_OK ) {
807 // Only to console for information purposes only
808 g_warning ( "SQL Close problem: %d", ans );
809 }
810 }
811 }
812#endif
50a14534
EB
813}
814
07059501 815static void maps_layer_post_read (VikLayer *vl, VikViewport *vp, gboolean from_file)
dc5758d3 816{
0fb11294
RN
817 VikMapsLayer *vml = VIK_MAPS_LAYER(vl);
818 VikMapSource *map = MAPS_LAYER_NTH_TYPE(vml->maptype);
819
a8c22c3f 820 if (!from_file)
07059501
GB
821 {
822 /* If this method is not called in file reading context
823 * it is called in GUI context.
824 * So, we can check if we have to inform the user about inconsistency */
825 VikViewportDrawMode vp_drawmode;
405b74ed 826 vp_drawmode = vik_viewport_get_drawmode ( vp );
0fb11294 827
820c59f4 828 if (vik_map_source_get_drawmode(map) != vp_drawmode) {
405b74ed 829 const gchar *drawmode_name = vik_viewport_get_drawmode_name (vp, vik_map_source_get_drawmode(map));
4c77d5e0 830 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 831 a_dialog_warning_msg ( VIK_GTK_WINDOW_FROM_WIDGET(vp), msg );
07059501
GB
832 g_free(msg);
833 }
dc5758d3 834 }
0fb11294
RN
835
836 // Performed in post read as we now know the map type
837#ifdef HAVE_SQLITE3_H
838 // Do some SQL stuff
839 if ( vik_map_source_is_mbtiles ( map ) ) {
840 int ans = sqlite3_open_v2 ( vml->filename,
841 &(vml->mbtiles),
842 SQLITE_OPEN_READONLY,
843 NULL );
844 if ( ans != SQLITE_OK ) {
845 // That didn't work, so here's why:
846 g_warning ( "%s: %s", __FUNCTION__, sqlite3_errmsg ( vml->mbtiles ) );
847
848 a_dialog_error_msg_extra ( VIK_GTK_WINDOW_FROM_WIDGET(vp),
849 _("Failed to open MBTiles file: %s"),
850 vml->filename );
851 vml->mbtiles = NULL;
852 }
853 }
854#endif
df5b2993
RN
855
856 // If the on Disk OSM Tile Layout type
cd7c550b 857 if ( vik_map_source_get_uniq_id(map) == MAP_ID_OSM_ON_DISK ) {
df5b2993
RN
858 // Copy the directory into filename
859 // thus the mapcache look up will be unique when using more than one of these map types
cd7c550b 860 g_free ( vml->filename );
df5b2993 861 vml->filename = g_strdup (vml->cache_dir);
cd7c550b 862 }
dc5758d3
GB
863}
864
7924723c
RN
865static const gchar* maps_layer_tooltip ( VikMapsLayer *vml )
866{
867 return vik_maps_layer_get_map_label ( vml );
868}
869
911400b5
AF
870static void maps_layer_marshall( VikMapsLayer *vml, guint8 **data, gint *len )
871{
872 vik_layer_marshall_params ( VIK_LAYER(vml), data, len );
873}
874
875static VikMapsLayer *maps_layer_unmarshall( guint8 *data, gint len, VikViewport *vvp )
876{
877 VikMapsLayer *rv = maps_layer_new ( vvp );
878 vik_layer_unmarshall_params ( VIK_LAYER(rv), data, len, vvp );
d7e776d0 879 maps_layer_post_read ( VIK_LAYER(rv), vvp, FALSE );
911400b5
AF
880 return rv;
881}
882
50a14534
EB
883/*********************/
884/****** DRAWING ******/
885/*********************/
886
50a14534
EB
887static GdkPixbuf *pixbuf_shrink ( GdkPixbuf *pixbuf, gdouble xshrinkfactor, gdouble yshrinkfactor )
888{
889 GdkPixbuf *tmp;
890 guint16 width = gdk_pixbuf_get_width(pixbuf), height = gdk_pixbuf_get_height(pixbuf);
2d5d32c1 891 tmp = gdk_pixbuf_scale_simple(pixbuf, ceil(width * xshrinkfactor), ceil(height * yshrinkfactor), GDK_INTERP_BILINEAR);
50a14534
EB
892 g_object_unref ( G_OBJECT(pixbuf) );
893 return tmp;
894}
895
0fb11294
RN
896#ifdef HAVE_SQLITE3_H
897/*
898static int sql_select_tile_dump_cb (void *data, int cols, char **fields, char **col_names )
899{
900 g_warning ( "Found %d columns", cols );
901 int i;
902 for ( i = 0; i < cols; i++ ) {
903 g_warning ( "SQL processing %s = %s", col_names[i], fields[i] );
904 }
905 return 0;
906}
907*/
908
909/**
910 *
911 */
912static GdkPixbuf *get_pixbuf_sql_exec ( sqlite3 *sql, gint xx, gint yy, gint zoom )
913{
914 GdkPixbuf *pixbuf = NULL;
915
916 // MBTiles stored internally with the flipping y thingy (i.e. TMS scheme).
917 gint flip_y = (gint) pow(2, zoom)-1 - yy;
918 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 );
919
920 gboolean finished = FALSE;
921
922 sqlite3_stmt *sql_stmt = NULL;
923 int ans = sqlite3_prepare_v2 ( sql, statement, -1, &sql_stmt, NULL );
924 if ( ans != SQLITE_OK ) {
925 g_warning ( "%s: %s - %d", __FUNCTION__, "prepare failure", ans );
926 finished = TRUE;
927 }
928
929 while ( !finished ) {
930 ans = sqlite3_step ( sql_stmt );
931 switch (ans) {
932 case SQLITE_ROW: {
933 // Get tile_data blob
934 int count = sqlite3_column_count(sql_stmt);
935 if ( count != 1 ) {
936 g_warning ( "%s: %s - %d", __FUNCTION__, "count not one", count );
937 finished = TRUE;
938 }
939 else {
940 const void *data = sqlite3_column_blob ( sql_stmt, 0 );
941 int bytes = sqlite3_column_bytes ( sql_stmt, 0 );
942 if ( bytes < 1 ) {
943 g_warning ( "%s: %s (%d)", __FUNCTION__, "not enough bytes", bytes );
944 finished = TRUE;
945 }
946 else {
947 // Convert these blob bytes into a pixbuf via these streaming operations
948 GInputStream *stream = g_memory_input_stream_new_from_data ( data, bytes, NULL );
949 GError *error = NULL;
950 pixbuf = gdk_pixbuf_new_from_stream ( stream, NULL, &error );
0e1b2664 951 if ( error ) {
0fb11294
RN
952 g_warning ( "%s: %s", __FUNCTION__, error->message );
953 g_error_free ( error );
954 }
955 g_input_stream_close ( stream, NULL, NULL );
956 }
957 }
958 break;
959 }
960 default:
961 // e.g. SQLITE_DONE | SQLITE_ERROR | SQLITE_MISUSE | etc...
962 // Finished normally
963 // and give up on any errors
964 if ( ans != SQLITE_DONE )
965 g_warning ( "%s: %s - %d", __FUNCTION__, "step issue", ans );
966 finished = TRUE;
967 break;
968 }
969 }
5263679f 970 (void)sqlite3_finalize ( sql_stmt );
0fb11294
RN
971
972 g_free ( statement );
973
974 return pixbuf;
975}
976#endif
977
978static GdkPixbuf *get_mbtiles_pixbuf ( VikMapsLayer *vml, gint xx, gint yy, gint zoom )
979{
980 GdkPixbuf *pixbuf = NULL;
981
982#ifdef HAVE_SQLITE3_H
983 if ( vml->mbtiles ) {
984 /*
985 gchar *statement = g_strdup_printf ( "SELECT name FROM sqlite_master WHERE type='table';" );
986 char *errMsg = NULL;
987 int ans = sqlite3_exec ( vml->mbtiles, statement, sql_select_tile_dump_cb, pixbuf, &errMsg );
988 if ( ans != SQLITE_OK ) {
989 // Only to console for information purposes only
990 g_warning ( "SQL problem: %d for %s - error: %s", ans, statement, errMsg );
991 sqlite3_free( errMsg );
992 }
993 g_free ( statement );
994 */
995
996 // Reading BLOBS is a bit more involved and so can't use the simpler sqlite3_exec ()
997 // Hence this specific function
998 pixbuf = get_pixbuf_sql_exec ( vml->mbtiles, xx, yy, zoom );
999 }
1000#endif
1001
1002 return pixbuf;
1003}
1004
99f0d7df
RN
1005static GdkPixbuf *get_pixbuf_from_metatile ( VikMapsLayer *vml, gint xx, gint yy, gint zz )
1006{
1007 const int tile_max = METATILE_MAX_SIZE;
1008 char err_msg[PATH_MAX];
1009 char *buf;
1010 int len;
1011 int compressed;
1012
8d7f4b75 1013 buf = g_malloc(tile_max);
99f0d7df
RN
1014 if (!buf) {
1015 return NULL;
1016 }
1017
1018 err_msg[0] = 0;
1019 len = metatile_read(vml->cache_dir, xx, yy, zz, buf, tile_max, &compressed, err_msg);
1020
1021 if (len > 0) {
1022 if (compressed) {
1023 // Not handled yet - I don't think this is used often - so implement later if necessary
1024 g_warning ( "Compressed metatiles not implemented:%s\n", __FUNCTION__);
8d7f4b75 1025 g_free(buf);
99f0d7df
RN
1026 return NULL;
1027 }
1028
1029 // Convert these buf bytes into a pixbuf via these streaming operations
1030 GdkPixbuf *pixbuf = NULL;
1031
1032 GInputStream *stream = g_memory_input_stream_new_from_data ( buf, len, NULL );
1033 GError *error = NULL;
1034 pixbuf = gdk_pixbuf_new_from_stream ( stream, NULL, &error );
8d7f4b75 1035 if (error) {
99f0d7df
RN
1036 g_warning ( "%s: %s", __FUNCTION__, error->message );
1037 g_error_free ( error );
1038 }
1039 g_input_stream_close ( stream, NULL, NULL );
1040
8d7f4b75 1041 g_free(buf);
99f0d7df
RN
1042 return pixbuf;
1043 }
1044 else {
8d7f4b75 1045 g_free(buf);
99f0d7df
RN
1046 g_warning ( "FAILED:%s %s", __FUNCTION__, err_msg);
1047 return NULL;
1048 }
1049}
1050
38597a6d
SB
1051/**
1052 * Caller has to decrease reference counter of returned
1053 * GdkPixbuf, when buffer is no longer needed.
1054 */
0fb11294
RN
1055static GdkPixbuf *pixbuf_apply_settings ( GdkPixbuf *pixbuf, VikMapsLayer *vml, MapCoord *mapcoord, gdouble xshrinkfactor, gdouble yshrinkfactor )
1056{
1057 // Apply alpha setting
1058 if ( pixbuf && vml->alpha < 255 )
5cca6c53 1059 pixbuf = ui_pixbuf_set_alpha ( pixbuf, vml->alpha );
0fb11294
RN
1060
1061 if ( pixbuf && ( xshrinkfactor != 1.0 || yshrinkfactor != 1.0 ) )
1062 pixbuf = pixbuf_shrink ( pixbuf, xshrinkfactor, yshrinkfactor );
1063
1064 if ( pixbuf )
19c3c24c 1065 a_mapcache_add ( pixbuf, (mapcache_extra_t) {0.0}, mapcoord->x, mapcoord->y,
0fb11294 1066 mapcoord->z, vik_map_source_get_uniq_id(MAPS_LAYER_NTH_TYPE(vml->maptype)),
df5b2993 1067 mapcoord->scale, vml->alpha, xshrinkfactor, yshrinkfactor, vml->filename );
0fb11294
RN
1068
1069 return pixbuf;
1070}
1071
2eb18edc
RN
1072static void get_filename ( const gchar *cache_dir,
1073 VikMapsCacheLayout cl,
5a1e5516 1074 guint16 id,
2eb18edc
RN
1075 const gchar *name,
1076 gint scale,
1077 gint z,
1078 gint x,
1079 gint y,
1080 gchar *filename_buf,
14b57d17
RN
1081 gint buf_len,
1082 const gchar* file_extension )
d281e8b4
RN
1083{
1084 switch ( cl ) {
1085 case VIK_MAPS_CACHE_LAYOUT_OSM:
2eb18edc
RN
1086 if ( name ) {
1087 if ( g_strcmp0 ( cache_dir, MAPS_CACHE_DIR ) )
1088 // Cache dir not the default - assume it's been directed somewhere specific
14b57d17 1089 g_snprintf ( filename_buf, buf_len, DIRECTDIRACCESS, cache_dir, (17 - scale), x, y, file_extension );
2eb18edc
RN
1090 else
1091 // Using default cache - so use the map name in the directory path
14b57d17 1092 g_snprintf ( filename_buf, buf_len, DIRECTDIRACCESS_WITH_NAME, cache_dir, name, (17 - scale), x, y, file_extension );
2eb18edc
RN
1093 }
1094 else
14b57d17 1095 g_snprintf ( filename_buf, buf_len, DIRECTDIRACCESS, cache_dir, (17 - scale), x, y, file_extension );
d281e8b4
RN
1096 break;
1097 default:
5a1e5516 1098 g_snprintf ( filename_buf, buf_len, DIRSTRUCTURE, cache_dir, id, scale, z, x, y );
d281e8b4
RN
1099 break;
1100 }
1101}
1102
38597a6d
SB
1103/**
1104 * Caller has to decrease reference counter of returned
1105 * GdkPixbuf, when buffer is no longer needed.
1106 */
5a1e5516 1107static GdkPixbuf *get_pixbuf( VikMapsLayer *vml, guint16 id, const gchar* mapname, MapCoord *mapcoord, gchar *filename_buf, gint buf_len, gdouble xshrinkfactor, gdouble yshrinkfactor )
50a14534
EB
1108{
1109 GdkPixbuf *pixbuf;
1110
1111 /* get the thing */
1112 pixbuf = a_mapcache_get ( mapcoord->x, mapcoord->y, mapcoord->z,
5a1e5516 1113 id, mapcoord->scale, vml->alpha, xshrinkfactor, yshrinkfactor, vml->filename );
50a14534
EB
1114
1115 if ( ! pixbuf ) {
14b57d17
RN
1116 VikMapSource *map = MAPS_LAYER_NTH_TYPE(vml->maptype);
1117 if ( vik_map_source_is_direct_file_access(map) ) {
0fb11294 1118 // ATM MBTiles must be 'a direct access type'
14b57d17 1119 if ( vik_map_source_is_mbtiles(map) ) {
0fb11294
RN
1120 pixbuf = get_mbtiles_pixbuf ( vml, mapcoord->x, mapcoord->y, (17 - mapcoord->scale) );
1121 pixbuf = pixbuf_apply_settings ( pixbuf, vml, mapcoord, xshrinkfactor, yshrinkfactor );
1122 // return now to avoid file tests that aren't appropriate for this map type
1123 return pixbuf;
1124 }
99f0d7df
RN
1125 else if ( vik_map_source_is_osm_meta_tiles(map) ) {
1126 pixbuf = get_pixbuf_from_metatile ( vml, mapcoord->x, mapcoord->y, (17 - mapcoord->scale) );
1127 pixbuf = pixbuf_apply_settings ( pixbuf, vml, mapcoord, xshrinkfactor, yshrinkfactor );
1128 return pixbuf;
1129 }
0fb11294 1130 else
5a1e5516 1131 get_filename ( vml->cache_dir, VIK_MAPS_CACHE_LAYOUT_OSM, id, NULL,
14b57d17
RN
1132 mapcoord->scale, mapcoord->z, mapcoord->x, mapcoord->y, filename_buf, buf_len,
1133 vik_map_source_get_file_extension(map) );
0fb11294 1134 }
2673b29d 1135 else
5a1e5516 1136 get_filename ( vml->cache_dir, vml->cache_layout, id, mapname,
14b57d17
RN
1137 mapcoord->scale, mapcoord->z, mapcoord->x, mapcoord->y, filename_buf, buf_len,
1138 vik_map_source_get_file_extension(map) );
2673b29d 1139
01ecda7e 1140 if ( g_file_test ( filename_buf, G_FILE_TEST_EXISTS ) == TRUE)
50a14534
EB
1141 {
1142 GError *gx = NULL;
1143 pixbuf = gdk_pixbuf_new_from_file ( filename_buf, &gx );
1144
01ecda7e 1145 /* free the pixbuf on error */
50a14534
EB
1146 if (gx)
1147 {
d17be106
RN
1148 if ( gx->domain != GDK_PIXBUF_ERROR || gx->code != GDK_PIXBUF_ERROR_CORRUPT_IMAGE ) {
1149 // Report a warning
1150 if ( IS_VIK_WINDOW ((VikWindow*)VIK_GTK_WINDOW_FROM_LAYER(vml)) ) {
1151 gchar* msg = g_strdup_printf ( _("Couldn't open image file: %s"), gx->message );
1152 vik_window_statusbar_update ( (VikWindow*)VIK_GTK_WINDOW_FROM_LAYER(vml), msg, VIK_STATUSBAR_INFO );
1153 g_free (msg);
1154 }
1155 }
50a14534 1156
01ecda7e
MR
1157 g_error_free ( gx );
1158 if ( pixbuf )
1159 g_object_unref ( G_OBJECT(pixbuf) );
1160 pixbuf = NULL;
1161 } else {
0fb11294 1162 pixbuf = pixbuf_apply_settings ( pixbuf, vml, mapcoord, xshrinkfactor, yshrinkfactor );
50a14534
EB
1163 }
1164 }
1165 }
1166 return pixbuf;
1167}
1168
9979924f 1169static gboolean should_start_autodownload(VikMapsLayer *vml, VikViewport *vvp)
10ca2bfe
QT
1170{
1171 const VikCoord *center = vik_viewport_get_center ( vvp );
1172
bbf2149b 1173 if (vik_window_get_pan_move (VIK_WINDOW(VIK_GTK_WINDOW_FROM_WIDGET(GTK_WIDGET(vvp)))))
01da6b4d 1174 /* D'n'D pan in action: do not download */
1c6a6010
GB
1175 return FALSE;
1176
e633ddef 1177 // Don't attempt to download unsupported zoom levels
9979924f 1178 gdouble xzoom = vik_viewport_get_xmpp ( vvp );
e633ddef
RN
1179 VikMapSource *map = MAPS_LAYER_NTH_TYPE(vml->maptype);
1180 guint8 zl = map_utils_mpp_to_zoom_level ( xzoom );
1181 if ( zl < vik_map_source_get_zoom_min(map) || zl > vik_map_source_get_zoom_max(map) )
9979924f
RN
1182 return FALSE;
1183
10ca2bfe
QT
1184 if (vml->last_center == NULL) {
1185 VikCoord *new_center = g_malloc(sizeof(VikCoord));
1186 *new_center = *center;
1187 vml->last_center = new_center;
1188 vml->last_xmpp = vik_viewport_get_xmpp(vvp);
1189 vml->last_ympp = vik_viewport_get_ympp(vvp);
1190 return TRUE;
1191 }
1192
1193 /* TODO: perhaps vik_coord_diff() */
1194 if (vik_coord_equals(vml->last_center, center)
1195 && (vml->last_xmpp == vik_viewport_get_xmpp(vvp))
1196 && (vml->last_ympp == vik_viewport_get_ympp(vvp)))
1197 return FALSE;
1198
1199 *(vml->last_center) = *center;
1200 vml->last_xmpp = vik_viewport_get_xmpp(vvp);
1201 vml->last_ympp = vik_viewport_get_ympp(vvp);
1202 return TRUE;
1203}
1204
d1871cd2
RN
1205/**
1206 *
1207 */
1208gboolean try_draw_scale_down (VikMapsLayer *vml, VikViewport *vvp, MapCoord ulm, gint xx, gint yy, gint tilesize_x_ceil, gint tilesize_y_ceil,
1209 gdouble xshrinkfactor, gdouble yshrinkfactor, guint id, const gchar *mapname, gchar *path_buf, guint max_path_len)
1210{
1211 GdkPixbuf *pixbuf;
1212 int scale_inc;
1213 for (scale_inc = 1; scale_inc < SCALE_INC_DOWN; scale_inc ++) {
1214 // Try with smaller zooms
1215 int scale_factor = 1 << scale_inc; /* 2^scale_inc */
1216 MapCoord ulm2 = ulm;
1217 ulm2.x = ulm.x / scale_factor;
1218 ulm2.y = ulm.y / scale_factor;
1219 ulm2.scale = ulm.scale + scale_inc;
1220 pixbuf = get_pixbuf ( vml, id, mapname, &ulm2, path_buf, max_path_len, xshrinkfactor * scale_factor, yshrinkfactor * scale_factor );
1221 if ( pixbuf ) {
1222 gint src_x = (ulm.x % scale_factor) * tilesize_x_ceil;
1223 gint src_y = (ulm.y % scale_factor) * tilesize_y_ceil;
1224 vik_viewport_draw_pixbuf ( vvp, pixbuf, src_x, src_y, xx, yy, tilesize_x_ceil, tilesize_y_ceil );
38597a6d 1225 g_object_unref(pixbuf);
d1871cd2
RN
1226 return TRUE;
1227 }
1228 }
1229 return FALSE;
1230}
1231
1232/**
1233 *
1234 */
1235gboolean try_draw_scale_up (VikMapsLayer *vml, VikViewport *vvp, MapCoord ulm, gint xx, gint yy, gint tilesize_x_ceil, gint tilesize_y_ceil,
1236 gdouble xshrinkfactor, gdouble yshrinkfactor, guint id, const gchar *mapname, gchar *path_buf, guint max_path_len)
1237{
1238 GdkPixbuf *pixbuf;
1239 // Try with bigger zooms
1240 int scale_dec;
1241 for (scale_dec = 1; scale_dec < SCALE_INC_UP; scale_dec ++) {
1242 int pict_x, pict_y;
1243 int scale_factor = 1 << scale_dec; /* 2^scale_dec */
1244 MapCoord ulm2 = ulm;
1245 ulm2.x = ulm.x * scale_factor;
1246 ulm2.y = ulm.y * scale_factor;
1247 ulm2.scale = ulm.scale - scale_dec;
1248 for (pict_x = 0; pict_x < scale_factor; pict_x ++) {
1249 for (pict_y = 0; pict_y < scale_factor; pict_y ++) {
1250 MapCoord ulm3 = ulm2;
1251 ulm3.x += pict_x;
1252 ulm3.y += pict_y;
1253 pixbuf = get_pixbuf ( vml, id, mapname, &ulm3, path_buf, max_path_len, xshrinkfactor / scale_factor, yshrinkfactor / scale_factor );
1254 if ( pixbuf ) {
1255 gint src_x = 0;
1256 gint src_y = 0;
1257 gint dest_x = xx + pict_x * (tilesize_x_ceil / scale_factor);
1258 gint dest_y = yy + pict_y * (tilesize_y_ceil / scale_factor);
1259 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 1260 g_object_unref(pixbuf);
d1871cd2
RN
1261 return TRUE;
1262 }
1263 }
1264 }
1265 }
1266 return FALSE;
1267}
1268
50a14534
EB
1269static void maps_layer_draw_section ( VikMapsLayer *vml, VikViewport *vvp, VikCoord *ul, VikCoord *br )
1270{
1271 MapCoord ulm, brm;
1272 gdouble xzoom = vik_viewport_get_xmpp ( vvp );
1273 gdouble yzoom = vik_viewport_get_ympp ( vvp );
1274 gdouble xshrinkfactor = 1.0, yshrinkfactor = 1.0;
2673b29d 1275 gboolean existence_only = FALSE;
50a14534
EB
1276
1277 if ( vml->xmapzoom && (vml->xmapzoom != xzoom || vml->ymapzoom != yzoom) ) {
1278 xshrinkfactor = vml->xmapzoom / xzoom;
1279 yshrinkfactor = vml->ymapzoom / yzoom;
732d1e25
EB
1280 xzoom = vml->xmapzoom;
1281 yzoom = vml->xmapzoom;
1282 if ( ! (xshrinkfactor > MIN_SHRINKFACTOR && xshrinkfactor < MAX_SHRINKFACTOR &&
1283 yshrinkfactor > MIN_SHRINKFACTOR && yshrinkfactor < MAX_SHRINKFACTOR ) ) {
6de95419
RN
1284 if ( xshrinkfactor > REAL_MIN_SHRINKFACTOR && yshrinkfactor > REAL_MIN_SHRINKFACTOR ) {
1285 g_debug ( "%s: existence_only due to SHRINKFACTORS", __FUNCTION__ );
732d1e25 1286 existence_only = TRUE;
6de95419 1287 }
732d1e25 1288 else {
d17be106
RN
1289 // Report the reason for not drawing
1290 if ( IS_VIK_WINDOW ((VikWindow*)VIK_GTK_WINDOW_FROM_LAYER(vml)) ) {
1291 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));
1292 vik_window_statusbar_update ( (VikWindow*)VIK_GTK_WINDOW_FROM_LAYER(vml), msg, VIK_STATUSBAR_INFO );
1293 g_free (msg);
1294 }
732d1e25
EB
1295 return;
1296 }
50a14534
EB
1297 }
1298 }
1299
1300 /* coord -> ID */
820c59f4
GB
1301 VikMapSource *map = MAPS_LAYER_NTH_TYPE(vml->maptype);
1302 if ( vik_map_source_coord_to_mapcoord ( map, ul, xzoom, yzoom, &ulm ) &&
1303 vik_map_source_coord_to_mapcoord ( map, br, xzoom, yzoom, &brm ) ) {
50a14534
EB
1304
1305 /* loop & draw */
1306 gint x, y;
1307 gint xmin = MIN(ulm.x, brm.x), xmax = MAX(ulm.x, brm.x);
1308 gint ymin = MIN(ulm.y, brm.y), ymax = MAX(ulm.y, brm.y);
5a1e5516 1309 guint16 id = vik_map_source_get_uniq_id(map);
2eb18edc 1310 const gchar *mapname = vik_map_source_get_name(map);
50a14534
EB
1311
1312 VikCoord coord;
1313 gint xx, yy, width, height;
1314 GdkPixbuf *pixbuf;
1315
6de95419
RN
1316 // Prevent the program grinding to a halt if trying to deal with thousands of tiles
1317 // which can happen when using a small fixed zoom level and viewing large areas.
1318 // Also prevents very large number of tile download requests
1319 gint tiles = (xmax-xmin) * (ymax-ymin);
1320 if ( tiles > MAX_TILES ) {
1321 g_debug ( "%s: existence_only due to wanting too many tiles (%d)", __FUNCTION__, tiles );
1322 existence_only = TRUE;
1323 }
1324
50a14534
EB
1325 guint max_path_len = strlen(vml->cache_dir) + 40;
1326 gchar *path_buf = g_malloc ( max_path_len * sizeof(char) );
1327
732d1e25 1328 if ( (!existence_only) && vml->autodownload && should_start_autodownload(vml, vvp)) {
33be396e 1329 g_debug("%s: Starting autodownload", __FUNCTION__);
382566c3 1330 if ( !vml->adl_only_missing && vik_map_source_supports_download_only_new (map) )
245f48f5
GB
1331 // Try to download newer tiles
1332 start_download_thread ( vml, vvp, ul, br, REDOWNLOAD_NEW );
1333 else
1334 // Download only missing tiles
1335 start_download_thread ( vml, vvp, ul, br, REDOWNLOAD_NONE );
10ca2bfe 1336 }
50a14534 1337
820c59f4 1338 if ( vik_map_source_get_tilesize_x(map) == 0 && !existence_only ) {
50a14534
EB
1339 for ( x = xmin; x <= xmax; x++ ) {
1340 for ( y = ymin; y <= ymax; y++ ) {
1341 ulm.x = x;
1342 ulm.y = y;
5a1e5516 1343 pixbuf = get_pixbuf ( vml, id, mapname, &ulm, path_buf, max_path_len, xshrinkfactor, yshrinkfactor );
50a14534
EB
1344 if ( pixbuf ) {
1345 width = gdk_pixbuf_get_width ( pixbuf );
1346 height = gdk_pixbuf_get_height ( pixbuf );
1347
820c59f4 1348 vik_map_source_mapcoord_to_center_coord ( map, &ulm, &coord );
50a14534
EB
1349 vik_viewport_coord_to_screen ( vvp, &coord, &xx, &yy );
1350 xx -= (width/2);
1351 yy -= (height/2);
1352
1353 vik_viewport_draw_pixbuf ( vvp, pixbuf, 0, 0, xx, yy, width, height );
38597a6d 1354 g_object_unref(pixbuf);
50a14534
EB
1355 }
1356 }
1357 }
1358 } else { /* tilesize is known, don't have to keep converting coords */
820c59f4
GB
1359 gdouble tilesize_x = vik_map_source_get_tilesize_x(map) * xshrinkfactor;
1360 gdouble tilesize_y = vik_map_source_get_tilesize_y(map) * yshrinkfactor;
50a14534
EB
1361 /* ceiled so tiles will be maximum size in the case of funky shrinkfactor */
1362 gint tilesize_x_ceil = ceil ( tilesize_x );
1363 gint tilesize_y_ceil = ceil ( tilesize_y );
1364 gint8 xinc = (ulm.x == xmin) ? 1 : -1;
1365 gint8 yinc = (ulm.y == ymin) ? 1 : -1;
c60f82df 1366 gint xx_tmp, yy_tmp;
50a14534 1367 gint base_yy, xend, yend;
732d1e25 1368
50a14534
EB
1369 xend = (xinc == 1) ? (xmax+1) : (xmin-1);
1370 yend = (yinc == 1) ? (ymax+1) : (ymin-1);
1371
820c59f4 1372 vik_map_source_mapcoord_to_center_coord ( map, &ulm, &coord );
50a14534
EB
1373 vik_viewport_coord_to_screen ( vvp, &coord, &xx_tmp, &yy_tmp );
1374 xx = xx_tmp; yy = yy_tmp;
1375 /* above trick so xx,yy doubles. this is so shrinkfactors aren't rounded off
1376 * eg if tile size 128, shrinkfactor 0.333 */
1377 xx -= (tilesize_x/2);
1378 base_yy = yy - (tilesize_y/2);
1379
1380 for ( x = ((xinc == 1) ? xmin : xmax); x != xend; x+=xinc ) {
1381 yy = base_yy;
1382 for ( y = ((yinc == 1) ? ymin : ymax); y != yend; y+=yinc ) {
1383 ulm.x = x;
1384 ulm.y = y;
732d1e25
EB
1385
1386 if ( existence_only ) {
d281e8b4 1387 if ( vik_map_source_is_direct_file_access (MAPS_LAYER_NTH_TYPE(vml->maptype)) )
5a1e5516 1388 get_filename ( vml->cache_dir, VIK_MAPS_CACHE_LAYOUT_OSM, id, vik_map_source_get_name(map),
14b57d17 1389 ulm.scale, ulm.z, ulm.x, ulm.y, path_buf, max_path_len, vik_map_source_get_file_extension(map) );
d281e8b4 1390 else
5a1e5516 1391 get_filename ( vml->cache_dir, vml->cache_layout, id, vik_map_source_get_name(map),
14b57d17 1392 ulm.scale, ulm.z, ulm.x, ulm.y, path_buf, max_path_len, vik_map_source_get_file_extension(map) );
d281e8b4 1393
45acf79e 1394 if ( g_file_test ( path_buf, G_FILE_TEST_EXISTS ) == TRUE ) {
ff37db21 1395 GdkGC *black_gc = gtk_widget_get_style(GTK_WIDGET(vvp))->black_gc;
732d1e25
EB
1396 vik_viewport_draw_line ( vvp, black_gc, xx+tilesize_x_ceil, yy, xx, yy+tilesize_y_ceil );
1397 }
1398 } else {
d1871cd2
RN
1399 // Try correct scale first
1400 int scale_factor = 1;
1401 pixbuf = get_pixbuf ( vml, id, mapname, &ulm, path_buf, max_path_len, xshrinkfactor * scale_factor, yshrinkfactor * scale_factor );
1402 if ( pixbuf ) {
1403 gint src_x = (ulm.x % scale_factor) * tilesize_x_ceil;
1404 gint src_y = (ulm.y % scale_factor) * tilesize_y_ceil;
1405 vik_viewport_draw_pixbuf ( vvp, pixbuf, src_x, src_y, xx, yy, tilesize_x_ceil, tilesize_y_ceil );
38597a6d 1406 g_object_unref(pixbuf);
6f0d1bea 1407 }
d1871cd2
RN
1408 else {
1409 // Otherwise try different scales
1410 if ( SCALE_SMALLER_ZOOM_FIRST ) {
1411 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) ) {
1412 try_draw_scale_up(vml,vvp,ulm,xx,yy,tilesize_x_ceil,tilesize_y_ceil,xshrinkfactor,yshrinkfactor,id,mapname,path_buf,max_path_len);
1413 }
1414 }
1415 else {
1416 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) ) {
1417 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
1418 }
1419 }
1420 }
732d1e25 1421 }
50a14534
EB
1422
1423 yy += tilesize_y;
1424 }
1425 xx += tilesize_x;
1426 }
50a14534 1427
33f1dade
RN
1428 // ATM Only show tile grid lines in extreme debug mode
1429 if ( vik_debug && vik_verbose ) {
1430 /* Grid drawing here so it gets drawn on top of the map */
1431 /* Thus loop around x & y again, but this time separately */
1432 /* Only showing grid for the current scale */
1433 GdkGC *black_gc = GTK_WIDGET(vvp)->style->black_gc;
1434 /* Draw single grid lines across the whole screen */
1435 gint width = vik_viewport_get_width(vvp);
1436 gint height = vik_viewport_get_height(vvp);
1437 xx = xx_tmp; yy = yy_tmp;
1438 gint base_xx = xx - (tilesize_x/2);
1439 base_yy = yy - (tilesize_y/2);
1440
1441 xx = base_xx;
1442 for ( x = ((xinc == 1) ? xmin : xmax); x != xend; x+=xinc ) {
1443 vik_viewport_draw_line ( vvp, black_gc, xx, base_yy, xx, height );
1444 xx += tilesize_x;
1445 }
1446
1447 yy = base_yy;
1448 for ( y = ((yinc == 1) ? ymin : ymax); y != yend; y+=yinc ) {
1449 vik_viewport_draw_line ( vvp, black_gc, base_xx, yy, width, yy );
1450 yy += tilesize_y;
1451 }
1452 }
1453
1454 }
50a14534
EB
1455 g_free ( path_buf );
1456 }
1457}
1458
1459static void maps_layer_draw ( VikMapsLayer *vml, VikViewport *vvp )
1460{
820c59f4 1461 if ( vik_map_source_get_drawmode(MAPS_LAYER_NTH_TYPE(vml->maptype)) == vik_viewport_get_drawmode ( vvp ) )
50a14534
EB
1462 {
1463 VikCoord ul, br;
1464
82aa018d 1465 /* Copyright */
68b1d6c0
GB
1466 gdouble level = vik_viewport_get_zoom ( vvp );
1467 LatLonBBox bbox;
1468 vik_viewport_get_min_max_lat_lon ( vvp, &bbox.south, &bbox.north, &bbox.west, &bbox.east );
1469 vik_map_source_get_copyright ( MAPS_LAYER_NTH_TYPE(vml->maptype), bbox, level, vik_viewport_add_copyright, vvp );
82aa018d 1470
26336cf0
GB
1471 /* Logo */
1472 const GdkPixbuf *logo = vik_map_source_get_logo ( MAPS_LAYER_NTH_TYPE(vml->maptype) );
1473 vik_viewport_add_logo ( vvp, logo );
1474
50a14534
EB
1475 /* get corner coords */
1476 if ( vik_viewport_get_coord_mode ( vvp ) == VIK_COORD_UTM && ! vik_viewport_is_one_zone ( vvp ) ) {
1477 /* UTM multi-zone stuff by Kit Transue */
1478 gchar leftmost_zone, rightmost_zone, i;
1479 leftmost_zone = vik_viewport_leftmost_zone( vvp );
1480 rightmost_zone = vik_viewport_rightmost_zone( vvp );
1481 for ( i = leftmost_zone; i <= rightmost_zone; ++i ) {
1482 vik_viewport_corners_for_zonen ( vvp, i, &ul, &br );
1483 maps_layer_draw_section ( vml, vvp, &ul, &br );
1484 }
1485 }
1486 else {
1487 vik_viewport_screen_to_coord ( vvp, 0, 0, &ul );
1488 vik_viewport_screen_to_coord ( vvp, vik_viewport_get_width(vvp), vik_viewport_get_height(vvp), &br );
1489
1490 maps_layer_draw_section ( vml, vvp, &ul, &br );
1491 }
1492 }
1493}
1494
1495/*************************/
1496/****** DOWNLOADING ******/
1497/*************************/
1498
1499/* pass along data to thread, exists even if layer is deleted. */
1500typedef struct {
1501 gchar *cache_dir;
1502 gchar *filename_buf;
d281e8b4 1503 VikMapsCacheLayout cache_layout;
50a14534
EB
1504 gint x0, y0, xf, yf;
1505 MapCoord mapcoord;
1506 gint maptype;
1507 gint maxlen;
1508 gint mapstoget;
1509 gint redownload;
7114e879 1510 gboolean refresh_display;
550fd035
QT
1511 VikMapsLayer *vml;
1512 VikViewport *vvp;
1513 gboolean map_layer_alive;
1514 GMutex *mutex;
50a14534
EB
1515} MapDownloadInfo;
1516
1517static void mdi_free ( MapDownloadInfo *mdi )
1518{
fc6640a9 1519 vik_mutex_free(mdi->mutex);
50a14534 1520 g_free ( mdi->cache_dir );
e65028db 1521 mdi->cache_dir = NULL;
50a14534 1522 g_free ( mdi->filename_buf );
e65028db 1523 mdi->filename_buf = NULL;
50a14534
EB
1524 g_free ( mdi );
1525}
1526
7bb60307 1527static void weak_ref_cb(gpointer ptr, GObject * dead_vml)
550fd035 1528{
7bb60307 1529 MapDownloadInfo *mdi = ptr;
550fd035
QT
1530 g_mutex_lock(mdi->mutex);
1531 mdi->map_layer_alive = FALSE;
1532 g_mutex_unlock(mdi->mutex);
1533}
1534
2113a507
RN
1535static gboolean is_in_area (VikMapSource *map, MapCoord mc)
1536{
1537 VikCoord vc;
1538 vik_map_source_mapcoord_to_center_coord ( map, &mc, &vc );
1539
1540 struct LatLon tl;
1541 tl.lat = vik_map_source_get_lat_max(map);
1542 tl.lon = vik_map_source_get_lon_min(map);
1543 struct LatLon br;
1544 br.lat = vik_map_source_get_lat_min(map);
1545 br.lon = vik_map_source_get_lon_max(map);
1546 VikCoord vctl;
1547 vik_coord_load_from_latlon (&vctl, VIK_COORD_LATLON, &tl);
1548 VikCoord vcbr;
1549 vik_coord_load_from_latlon (&vcbr, VIK_COORD_LATLON, &br);
1550
1551 return vik_coord_inside ( &vc, &vctl, &vcbr );
1552}
1553
634eca0a 1554static int map_download_thread ( MapDownloadInfo *mdi, gpointer threaddata )
50a14534 1555{
825413ba 1556 void *handle = vik_map_source_download_handle_init(MAPS_LAYER_NTH_TYPE(mdi->maptype));
50a14534 1557 guint donemaps = 0;
2113a507 1558 MapCoord mcoord = mdi->mapcoord;
50a14534
EB
1559 gint x, y;
1560 for ( x = mdi->x0; x <= mdi->xf; x++ )
1561 {
2113a507 1562 mcoord.x = x;
50a14534
EB
1563 for ( y = mdi->y0; y <= mdi->yf; y++ )
1564 {
2113a507
RN
1565 mcoord.y = y;
1566 // Only attempt to download a tile from supported areas
1567 if ( is_in_area ( MAPS_LAYER_NTH_TYPE(mdi->maptype), mcoord ) )
1568 {
1569 gboolean remove_mem_cache = FALSE;
1570 gboolean need_download = FALSE;
84628352 1571
2113a507
RN
1572 get_filename ( mdi->cache_dir, mdi->cache_layout,
1573 vik_map_source_get_uniq_id(MAPS_LAYER_NTH_TYPE(mdi->maptype)),
1574 vik_map_source_get_name(MAPS_LAYER_NTH_TYPE(mdi->maptype)),
1575 mdi->mapcoord.scale, mdi->mapcoord.z, x, y, mdi->filename_buf, mdi->maxlen,
1576 vik_map_source_get_file_extension(MAPS_LAYER_NTH_TYPE(mdi->maptype)) );
1577
1578 donemaps++;
1579 int res = a_background_thread_progress ( threaddata, ((gdouble)donemaps) / mdi->mapstoget ); /* this also calls testcancel */
1580 if (res != 0) {
1581 vik_map_source_download_handle_cleanup(MAPS_LAYER_NTH_TYPE(mdi->maptype), handle);
1582 return -1;
1583 }
a0058e48 1584
2113a507
RN
1585 if ( g_file_test ( mdi->filename_buf, G_FILE_TEST_EXISTS ) == FALSE ) {
1586 need_download = TRUE;
1587 remove_mem_cache = TRUE;
a0058e48 1588
2113a507
RN
1589 } else { /* in case map file already exists */
1590 switch (mdi->redownload) {
1591 case REDOWNLOAD_NONE:
1592 continue;
1593
1594 case REDOWNLOAD_BAD:
1595 {
1596 /* see if this one is bad or what */
1597 GError *gx = NULL;
1598 GdkPixbuf *pixbuf = gdk_pixbuf_new_from_file ( mdi->filename_buf, &gx );
1599 if (gx || (!pixbuf)) {
fd437981
RN
1600 if ( g_remove ( mdi->filename_buf ) )
1601 g_warning ( "REDOWNLOAD failed to remove: %s", mdi->filename_buf );
2113a507
RN
1602 need_download = TRUE;
1603 remove_mem_cache = TRUE;
1604 g_error_free ( gx );
a0058e48 1605
2113a507
RN
1606 } else {
1607 g_object_unref ( pixbuf );
1608 }
1609 break;
a0058e48 1610 }
a0058e48 1611
2113a507
RN
1612 case REDOWNLOAD_NEW:
1613 need_download = TRUE;
1614 remove_mem_cache = TRUE;
1615 break;
a0058e48 1616
2113a507
RN
1617 case REDOWNLOAD_ALL:
1618 /* FIXME: need a better way than to erase file in case of server/network problem */
fd437981
RN
1619 if ( g_remove ( mdi->filename_buf ) )
1620 g_warning ( "REDOWNLOAD failed to remove: %s", mdi->filename_buf );
2113a507
RN
1621 need_download = TRUE;
1622 remove_mem_cache = TRUE;
1623 break;
a0058e48 1624
2113a507
RN
1625 case DOWNLOAD_OR_REFRESH:
1626 remove_mem_cache = TRUE;
1627 break;
a0058e48 1628
2113a507
RN
1629 default:
1630 g_warning ( "redownload state %d unknown\n", mdi->redownload);
1631 }
a0058e48 1632 }
94493114 1633
2113a507
RN
1634 mdi->mapcoord.x = x; mdi->mapcoord.y = y;
1635
1636 if (need_download) {
1637 DownloadResult_t dr = vik_map_source_download( MAPS_LAYER_NTH_TYPE(mdi->maptype), &(mdi->mapcoord), mdi->filename_buf, handle);
1638 switch ( dr ) {
1639 case DOWNLOAD_HTTP_ERROR:
1640 case DOWNLOAD_CONTENT_ERROR: {
1641 // TODO: ?? count up the number of download errors somehow...
1642 gchar* msg = g_strdup_printf ( "%s: %s", vik_maps_layer_get_map_label (mdi->vml), _("Failed to download tile") );
1643 vik_window_statusbar_update ( (VikWindow*)VIK_GTK_WINDOW_FROM_LAYER(mdi->vml), msg, VIK_STATUSBAR_INFO );
1644 g_free (msg);
1645 break;
1646 }
1647 case DOWNLOAD_FILE_WRITE_ERROR: {
1648 gchar* msg = g_strdup_printf ( "%s: %s", vik_maps_layer_get_map_label (mdi->vml), _("Unable to save tile") );
1649 vik_window_statusbar_update ( (VikWindow*)VIK_GTK_WINDOW_FROM_LAYER(mdi->vml), msg, VIK_STATUSBAR_INFO );
1650 g_free (msg);
1651 break;
1652 }
1653 case DOWNLOAD_SUCCESS:
1654 case DOWNLOAD_NOT_REQUIRED:
1655 default:
1656 break;
4e815e90 1657 }
4e815e90 1658 }
94493114 1659
2113a507
RN
1660 g_mutex_lock(mdi->mutex);
1661 if (remove_mem_cache)
353996de 1662 a_mapcache_remove_all_shrinkfactors ( x, y, mdi->mapcoord.z, vik_map_source_get_uniq_id(MAPS_LAYER_NTH_TYPE(mdi->maptype)), mdi->mapcoord.scale, mdi->vml->filename );
2113a507
RN
1663 if (mdi->refresh_display && mdi->map_layer_alive) {
1664 /* TODO: check if it's on visible area */
1665 vik_layer_emit_update ( VIK_LAYER(mdi->vml) ); // NB update display from background
1666 }
1667 g_mutex_unlock(mdi->mutex);
1668 mdi->mapcoord.x = mdi->mapcoord.y = 0; /* we're temporarily between downloads */
a0b59f2f 1669 }
50a14534
EB
1670 }
1671 }
825413ba 1672 vik_map_source_download_handle_cleanup(MAPS_LAYER_NTH_TYPE(mdi->maptype), handle);
04e54492
QT
1673 g_mutex_lock(mdi->mutex);
1674 if (mdi->map_layer_alive)
7bb60307 1675 g_object_weak_unref(G_OBJECT(mdi->vml), weak_ref_cb, mdi);
04e54492 1676 g_mutex_unlock(mdi->mutex);
634eca0a 1677 return 0;
50a14534
EB
1678}
1679
1680static void mdi_cancel_cleanup ( MapDownloadInfo *mdi )
1681{
1682 if ( mdi->mapcoord.x || mdi->mapcoord.y )
1683 {
2eb18edc
RN
1684 get_filename ( mdi->cache_dir, mdi->cache_layout,
1685 vik_map_source_get_uniq_id(MAPS_LAYER_NTH_TYPE(mdi->maptype)),
1686 vik_map_source_get_name(MAPS_LAYER_NTH_TYPE(mdi->maptype)),
14b57d17
RN
1687 mdi->mapcoord.scale, mdi->mapcoord.z, mdi->mapcoord.x, mdi->mapcoord.y, mdi->filename_buf, mdi->maxlen,
1688 vik_map_source_get_file_extension(MAPS_LAYER_NTH_TYPE(mdi->maptype)) );
45acf79e 1689 if ( g_file_test ( mdi->filename_buf, G_FILE_TEST_EXISTS ) == TRUE)
50a14534 1690 {
fd437981
RN
1691 if ( g_remove ( mdi->filename_buf ) )
1692 g_warning ( "Cleanup failed to remove: %s", mdi->filename_buf );
50a14534
EB
1693 }
1694 }
1695}
1696
1697static void start_download_thread ( VikMapsLayer *vml, VikViewport *vvp, const VikCoord *ul, const VikCoord *br, gint redownload )
1698{
1699 gdouble xzoom = vml->xmapzoom ? vml->xmapzoom : vik_viewport_get_xmpp ( vvp );
1700 gdouble yzoom = vml->ymapzoom ? vml->ymapzoom : vik_viewport_get_ympp ( vvp );
1701 MapCoord ulm, brm;
820c59f4 1702 VikMapSource *map = MAPS_LAYER_NTH_TYPE(vml->maptype);
2673b29d
RN
1703
1704 // Don't ever attempt download on direct access
1705 if ( vik_map_source_is_direct_file_access ( map ) )
1706 return;
1707
820c59f4
GB
1708 if ( vik_map_source_coord_to_mapcoord ( map, ul, xzoom, yzoom, &ulm )
1709 && vik_map_source_coord_to_mapcoord ( map, br, xzoom, yzoom, &brm ) )
50a14534
EB
1710 {
1711 MapDownloadInfo *mdi = g_malloc ( sizeof(MapDownloadInfo) );
1712 gint a, b;
1713
550fd035
QT
1714 mdi->vml = vml;
1715 mdi->vvp = vvp;
1716 mdi->map_layer_alive = TRUE;
fc6640a9 1717 mdi->mutex = vik_mutex_new();
7114e879 1718 mdi->refresh_display = TRUE;
550fd035 1719
50a14534
EB
1720 /* cache_dir and buffer for dest filename */
1721 mdi->cache_dir = g_strdup ( vml->cache_dir );
1722 mdi->maxlen = strlen ( vml->cache_dir ) + 40;
1723 mdi->filename_buf = g_malloc ( mdi->maxlen * sizeof(gchar) );
d281e8b4 1724 mdi->cache_layout = vml->cache_layout;
50a14534
EB
1725 mdi->maptype = vml->maptype;
1726
1727 mdi->mapcoord = ulm;
50a14534
EB
1728 mdi->redownload = redownload;
1729
1730 mdi->x0 = MIN(ulm.x, brm.x);
1731 mdi->xf = MAX(ulm.x, brm.x);
1732 mdi->y0 = MIN(ulm.y, brm.y);
1733 mdi->yf = MAX(ulm.y, brm.y);
1734
1735 mdi->mapstoget = 0;
1736
2113a507
RN
1737 MapCoord mcoord = mdi->mapcoord;
1738
50a14534
EB
1739 if ( mdi->redownload ) {
1740 mdi->mapstoget = (mdi->xf - mdi->x0 + 1) * (mdi->yf - mdi->y0 + 1);
1741 } else {
1742 /* calculate how many we need */
1743 for ( a = mdi->x0; a <= mdi->xf; a++ )
1744 {
2113a507 1745 mcoord.x = a;
50a14534
EB
1746 for ( b = mdi->y0; b <= mdi->yf; b++ )
1747 {
2113a507
RN
1748 mcoord.y = b;
1749 // Only count tiles from supported areas
1750 if ( is_in_area (map, mcoord) )
1751 {
1752 get_filename ( mdi->cache_dir, mdi->cache_layout,
1753 vik_map_source_get_uniq_id(map),
1754 vik_map_source_get_name(map),
1755 ulm.scale, ulm.z, a, b, mdi->filename_buf, mdi->maxlen,
1756 vik_map_source_get_file_extension(map) );
1757 if ( g_file_test ( mdi->filename_buf, G_FILE_TEST_EXISTS ) == FALSE )
1758 mdi->mapstoget++;
1759 }
50a14534
EB
1760 }
1761 }
1762 }
1763
1764 mdi->mapcoord.x = mdi->mapcoord.y = 0; /* for cleanup -- no current map */
1765
1766 if ( mdi->mapstoget )
1767 {
97634600
GB
1768 const gchar *tmp_str;
1769 gchar *tmp;
50a14534 1770
97634600
GB
1771 if (redownload)
1772 {
1773 if (redownload == REDOWNLOAD_BAD)
1774 tmp_str = ngettext("Redownloading up to %d %s map...", "Redownloading up to %d %s maps...", mdi->mapstoget);
1775 else
1776 tmp_str = ngettext("Redownloading %d %s map...", "Redownloading %d %s maps...", mdi->mapstoget);
1777 }
1778 else
1779 {
1780 tmp_str = ngettext("Downloading %d %s map...", "Downloading %d %s maps...", mdi->mapstoget);
1781 }
1782 tmp = g_strdup_printf ( tmp_str, mdi->mapstoget, MAPS_LAYER_NTH_LABEL(vml->maptype));
1783
7bb60307 1784 g_object_weak_ref(G_OBJECT(mdi->vml), weak_ref_cb, mdi);
50a14534 1785 /* launch the thread */
c75da936
RN
1786 a_background_thread ( BACKGROUND_POOL_REMOTE,
1787 VIK_GTK_WINDOW_FROM_LAYER(vml), /* parent window */
50a14534
EB
1788 tmp, /* description string */
1789 (vik_thr_func) map_download_thread, /* function to call within thread */
1790 mdi, /* pass along data */
1791 (vik_thr_free_func) mdi_free, /* function to free pass along data */
1792 (vik_thr_free_func) mdi_cancel_cleanup,
1793 mdi->mapstoget );
1794 g_free ( tmp );
1795 }
1796 else
1797 mdi_free ( mdi );
1798 }
1799}
1800
3ac548fa 1801static void maps_layer_download_section ( VikMapsLayer *vml, VikViewport *vvp, VikCoord *ul, VikCoord *br, gdouble zoom, gint download_method )
7114e879 1802{
7114e879 1803 MapCoord ulm, brm;
820c59f4 1804 VikMapSource *map = MAPS_LAYER_NTH_TYPE(vml->maptype);
7114e879 1805
2673b29d
RN
1806 // Don't ever attempt download on direct access
1807 if ( vik_map_source_is_direct_file_access ( map ) )
1808 return;
1809
820c59f4
GB
1810 if (!vik_map_source_coord_to_mapcoord(map, ul, zoom, zoom, &ulm)
1811 || !vik_map_source_coord_to_mapcoord(map, br, zoom, zoom, &brm)) {
4258f4e2 1812 g_warning("%s() coord_to_mapcoord() failed", __PRETTY_FUNCTION__);
7114e879
QT
1813 return;
1814 }
1815
1816 MapDownloadInfo *mdi = g_malloc(sizeof(MapDownloadInfo));
1817 gint i, j;
1818
1819 mdi->vml = vml;
1820 mdi->vvp = vvp;
1821 mdi->map_layer_alive = TRUE;
fc6640a9 1822 mdi->mutex = vik_mutex_new();
903dc0b4 1823 mdi->refresh_display = TRUE;
7114e879
QT
1824
1825 mdi->cache_dir = g_strdup ( vml->cache_dir );
1826 mdi->maxlen = strlen ( vml->cache_dir ) + 40;
1827 mdi->filename_buf = g_malloc ( mdi->maxlen * sizeof(gchar) );
1828 mdi->maptype = vml->maptype;
d281e8b4 1829 mdi->cache_layout = vml->cache_layout;
7114e879
QT
1830
1831 mdi->mapcoord = ulm;
3ac548fa 1832 mdi->redownload = download_method;
7114e879
QT
1833
1834 mdi->x0 = MIN(ulm.x, brm.x);
1835 mdi->xf = MAX(ulm.x, brm.x);
1836 mdi->y0 = MIN(ulm.y, brm.y);
1837 mdi->yf = MAX(ulm.y, brm.y);
1838
1839 mdi->mapstoget = 0;
1840
2113a507
RN
1841 MapCoord mcoord = mdi->mapcoord;
1842
7114e879 1843 for (i = mdi->x0; i <= mdi->xf; i++) {
2113a507 1844 mcoord.x = i;
7114e879 1845 for (j = mdi->y0; j <= mdi->yf; j++) {
2113a507
RN
1846 mcoord.y = j;
1847 // Only count tiles from supported areas
1848 if ( is_in_area (map, mcoord) ) {
1849 get_filename ( mdi->cache_dir, mdi->cache_layout,
1850 vik_map_source_get_uniq_id(map),
1851 vik_map_source_get_name(map),
1852 ulm.scale, ulm.z, i, j, mdi->filename_buf, mdi->maxlen,
1853 vik_map_source_get_file_extension(map) );
1854 if ( g_file_test ( mdi->filename_buf, G_FILE_TEST_EXISTS ) == FALSE )
1855 mdi->mapstoget++;
1856 }
7114e879
QT
1857 }
1858 }
1859
1860 mdi->mapcoord.x = mdi->mapcoord.y = 0; /* for cleanup -- no current map */
1861
1862 if (mdi->mapstoget) {
4c77d5e0
GB
1863 gchar *tmp;
1864 const gchar *fmt;
eb6b0125
JJ
1865 fmt = ngettext("Downloading %d %s map...",
1866 "Downloading %d %s maps...",
1867 mdi->mapstoget);
4c77d5e0 1868 tmp = g_strdup_printf ( fmt, mdi->mapstoget, MAPS_LAYER_NTH_LABEL(vml->maptype) );
7114e879
QT
1869
1870 g_object_weak_ref(G_OBJECT(mdi->vml), weak_ref_cb, mdi);
c75da936
RN
1871
1872 // launch the thread
1873 a_background_thread ( BACKGROUND_POOL_REMOTE,
1874 VIK_GTK_WINDOW_FROM_LAYER(vml), /* parent window */
1875 tmp, /* description string */
1876 (vik_thr_func) map_download_thread, /* function to call within thread */
1877 mdi, /* pass along data */
1878 (vik_thr_free_func) mdi_free, /* function to free pass along data */
1879 (vik_thr_free_func) mdi_cancel_cleanup,
1880 mdi->mapstoget );
7114e879
QT
1881 g_free ( tmp );
1882 }
1883 else
1884 mdi_free ( mdi );
1885}
1886
3ac548fa
RN
1887/**
1888 * vik_maps_layer_download_section:
1889 * @vml: The Map Layer
1890 * @vvp: The Viewport that the map is on
1891 * @ul: Upper left coordinate of the area to be downloaded
1892 * @br: Bottom right coordinate of the area to be downloaded
1893 * @zoom: The zoom level at which the maps are to be download
1894 *
1895 * Download a specified map area at a certain zoom level
1896 */
1897void vik_maps_layer_download_section ( VikMapsLayer *vml, VikViewport *vvp, VikCoord *ul, VikCoord *br, gdouble zoom )
1898{
1899 maps_layer_download_section (vml, vvp, ul, br, zoom, REDOWNLOAD_NONE);
1900}
1901
50a14534
EB
1902static void maps_layer_redownload_bad ( VikMapsLayer *vml )
1903{
1904 start_download_thread ( vml, vml->redownload_vvp, &(vml->redownload_ul), &(vml->redownload_br), REDOWNLOAD_BAD );
1905}
a7c1acf1 1906
50a14534
EB
1907static void maps_layer_redownload_all ( VikMapsLayer *vml )
1908{
1909 start_download_thread ( vml, vml->redownload_vvp, &(vml->redownload_ul), &(vml->redownload_br), REDOWNLOAD_ALL );
1910}
1911
a7c1acf1
GB
1912static void maps_layer_redownload_new ( VikMapsLayer *vml )
1913{
1914 start_download_thread ( vml, vml->redownload_vvp, &(vml->redownload_ul), &(vml->redownload_br), REDOWNLOAD_NEW );
1915}
1916
2a708810
RN
1917#if !GLIB_CHECK_VERSION(2,26,0)
1918typedef struct stat GStatBuf;
1919#endif
1920
450d8665
RN
1921/**
1922 * Display a simple dialog with information about this particular map tile
1923 */
1924static void maps_layer_tile_info ( VikMapsLayer *vml )
1925{
1926 VikMapSource *map = MAPS_LAYER_NTH_TYPE(vml->maptype);
1927
1928 gdouble xzoom = vml->xmapzoom ? vml->xmapzoom : vik_viewport_get_xmpp ( vml->redownload_vvp );
1929 gdouble yzoom = vml->ymapzoom ? vml->ymapzoom : vik_viewport_get_ympp ( vml->redownload_vvp );
1930 MapCoord ulm;
1931
1932 if ( !vik_map_source_coord_to_mapcoord ( map, &(vml->redownload_ul), xzoom, yzoom, &ulm ) )
1933 return;
1934
1935 gchar *filename = NULL;
450d8665
RN
1936 gchar *source = NULL;
1937
1938 if ( vik_map_source_is_direct_file_access ( map ) ) {
0fb11294
RN
1939 if ( vik_map_source_is_mbtiles ( map ) ) {
1940 filename = g_strdup ( vml->filename );
1941#ifdef HAVE_SQLITE3_H
1942 // And whether to bother going into the SQL to check it's really there or not...
1943 gchar *exists = NULL;
8c778528 1944 gint zoom = 17 - ulm.scale;
0fb11294 1945 if ( vml->mbtiles ) {
8c778528 1946 GdkPixbuf *pixbuf = get_pixbuf_sql_exec ( vml->mbtiles, ulm.x, ulm.y, zoom );
0fb11294
RN
1947 if ( pixbuf ) {
1948 exists = g_strdup ( _("YES") );
1949 g_object_unref ( G_OBJECT(pixbuf) );
1950 }
1951 else {
1952 exists = g_strdup ( _("NO") );
1953 }
1954 }
1955 else
1956 exists = g_strdup ( _("NO") );
8c778528 1957 gint flip_y = (gint) pow(2, zoom)-1 - ulm.y;
0fb11294 1958 // NB Also handles .jpg automatically due to pixbuf_new_from () support - although just print png for now.
7bad314b 1959 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
1960 g_free ( exists );
1961#else
7bad314b 1962 source = g_strdup ( _("Source: Not available") );
0fb11294
RN
1963#endif
1964 }
99f0d7df
RN
1965 else if ( vik_map_source_is_osm_meta_tiles ( map ) ) {
1966 char path[PATH_MAX];
1967 xyz_to_meta(path, sizeof(path), vml->cache_dir, ulm.x, ulm.y, 17-ulm.scale );
1968 source = g_strdup ( path );
1969 filename = g_strdup ( path );
1970 }
0fb11294 1971 else {
2eb18edc
RN
1972 guint max_path_len = strlen(vml->cache_dir) + 40;
1973 filename = g_malloc ( max_path_len * sizeof(char) );
1974 get_filename ( vml->cache_dir, VIK_MAPS_CACHE_LAYOUT_OSM,
1975 vik_map_source_get_uniq_id(map),
1976 NULL,
14b57d17
RN
1977 ulm.scale, ulm.z, ulm.x, ulm.y, filename, max_path_len,
1978 vik_map_source_get_file_extension(map) );
7bad314b 1979 source = g_strconcat ( "Source: file://", filename, NULL );
0fb11294 1980 }
450d8665
RN
1981 }
1982 else {
d281e8b4
RN
1983 guint max_path_len = strlen(vml->cache_dir) + 40;
1984 filename = g_malloc ( max_path_len * sizeof(char) );
2eb18edc
RN
1985 get_filename ( vml->cache_dir, vml->cache_layout,
1986 vik_map_source_get_uniq_id(map),
1987 vik_map_source_get_name(map),
14b57d17
RN
1988 ulm.scale, ulm.z, ulm.x, ulm.y, filename, max_path_len,
1989 vik_map_source_get_file_extension(map) );
5ba4c3c8
RN
1990 source = g_markup_printf_escaped ( "Source: http://%s%s",
1991 vik_map_source_default_get_hostname ( VIK_MAP_SOURCE_DEFAULT(map) ),
1992 vik_map_source_default_get_uri ( VIK_MAP_SOURCE_DEFAULT(map), &ulm ) );
450d8665
RN
1993 }
1994
7bad314b
RN
1995 GArray *array = g_array_new (FALSE, TRUE, sizeof(gchar*));
1996 g_array_append_val ( array, source );
1997
1998 gchar *filemsg = NULL;
1999 gchar *timemsg = NULL;
450d8665 2000
7bad314b
RN
2001 if ( g_file_test ( filename, G_FILE_TEST_EXISTS ) ) {
2002 filemsg = g_strconcat ( "Tile File: ", filename, NULL );
450d8665 2003 // Get some timestamp information of the tile
2a708810 2004 GStatBuf stat_buf;
450d8665 2005 if ( g_stat ( filename, &stat_buf ) == 0 ) {
6be843d5
RN
2006 gchar time_buf[64];
2007 strftime ( time_buf, sizeof(time_buf), "%c", gmtime((const time_t *)&stat_buf.st_mtime) );
7bad314b 2008 timemsg = g_strdup_printf ( _("Tile File Timestamp: %s"), time_buf );
450d8665 2009 }
0d744b77 2010 else {
7bad314b 2011 timemsg = g_strdup ( _("Tile File Timestamp: Not Available") );
0d744b77 2012 }
7bad314b
RN
2013 g_array_append_val ( array, filemsg );
2014 g_array_append_val ( array, timemsg );
0d744b77
RN
2015 }
2016 else {
7bad314b
RN
2017 filemsg = g_strdup_printf ( "Tile File: %s [Not Available]", filename );
2018 g_array_append_val ( array, filemsg );
450d8665 2019 }
450d8665 2020
7bad314b
RN
2021 a_dialog_list ( VIK_GTK_WINDOW_FROM_LAYER(vml), _("Tile Information"), array, 5 );
2022 g_array_free ( array, FALSE );
2023
2024 g_free ( timemsg );
2025 g_free ( filemsg );
450d8665
RN
2026 g_free ( source );
2027 g_free ( filename );
2028}
2029
50a14534
EB
2030static gboolean maps_layer_download_release ( VikMapsLayer *vml, GdkEventButton *event, VikViewport *vvp )
2031{
941aa6e9
AF
2032 if (!vml || vml->vl.type != VIK_LAYER_MAPS)
2033 return FALSE;
50a14534
EB
2034 if ( vml->dl_tool_x != -1 && vml->dl_tool_y != -1 )
2035 {
2036 if ( event->button == 1 )
2037 {
2038 VikCoord ul, br;
2039 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 );
2040 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 2041 start_download_thread ( vml, vvp, &ul, &br, DOWNLOAD_OR_REFRESH );
50a14534
EB
2042 vml->dl_tool_x = vml->dl_tool_y = -1;
2043 return TRUE;
2044 }
2045 else
2046 {
2047 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) );
2048 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) );
2049
2050 vml->redownload_vvp = vvp;
2051
2052 vml->dl_tool_x = vml->dl_tool_y = -1;
2053
2054 if ( ! vml->dl_right_click_menu ) {
2055 GtkWidget *item;
2056 vml->dl_right_click_menu = GTK_MENU ( gtk_menu_new () );
2057
94ee2264 2058 item = gtk_menu_item_new_with_mnemonic ( _("Redownload _Bad Map(s)") );
50a14534
EB
2059 g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(maps_layer_redownload_bad), vml );
2060 gtk_menu_shell_append ( GTK_MENU_SHELL(vml->dl_right_click_menu), item );
2061
94ee2264 2062 item = gtk_menu_item_new_with_mnemonic ( _("Redownload _New Map(s)") );
a7c1acf1
GB
2063 g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(maps_layer_redownload_new), vml );
2064 gtk_menu_shell_append ( GTK_MENU_SHELL(vml->dl_right_click_menu), item );
2065
94ee2264 2066 item = gtk_menu_item_new_with_mnemonic ( _("Redownload _All Map(s)") );
50a14534
EB
2067 g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(maps_layer_redownload_all), vml );
2068 gtk_menu_shell_append ( GTK_MENU_SHELL(vml->dl_right_click_menu), item );
450d8665
RN
2069
2070 item = gtk_image_menu_item_new_with_mnemonic ( _("_Show Tile Information") );
2071 gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_INFO, GTK_ICON_SIZE_MENU) );
2072 g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(maps_layer_tile_info), vml );
2073 gtk_menu_shell_append (GTK_MENU_SHELL(vml->dl_right_click_menu), item);
50a14534
EB
2074 }
2075
2076 gtk_menu_popup ( vml->dl_right_click_menu, NULL, NULL, NULL, NULL, event->button, event->time );
2077 gtk_widget_show_all ( GTK_WIDGET(vml->dl_right_click_menu) );
2078 }
2079 }
2080 return FALSE;
2081}
2082
941aa6e9
AF
2083static gpointer maps_layer_download_create ( VikWindow *vw, VikViewport *vvp)
2084{
2085 return vvp;
2086}
2087
50a14534
EB
2088static gboolean maps_layer_download_click ( VikMapsLayer *vml, GdkEventButton *event, VikViewport *vvp )
2089{
2090 MapCoord tmp;
941aa6e9
AF
2091 if (!vml || vml->vl.type != VIK_LAYER_MAPS)
2092 return FALSE;
820c59f4
GB
2093 VikMapSource *map = MAPS_LAYER_NTH_TYPE(vml->maptype);
2094 if ( vik_map_source_get_drawmode(map) == vik_viewport_get_drawmode ( vvp ) &&
2095 vik_map_source_coord_to_mapcoord ( map, vik_viewport_get_center ( vvp ),
50a14534
EB
2096 vml->xmapzoom ? vml->xmapzoom : vik_viewport_get_xmpp ( vvp ),
2097 vml->ymapzoom ? vml->ymapzoom : vik_viewport_get_ympp ( vvp ),
2098 &tmp ) ) {
2099 vml->dl_tool_x = event->x, vml->dl_tool_y = event->y;
2100 return TRUE;
2101 }
2102 return FALSE;
50a14534
EB
2103}
2104
7a7ba2f1
RN
2105// A slightly better way of defining the menu callback information
2106// This should be easier to extend/rework compared to previously
2107typedef enum {
2108 MA_VML = 0,
2109 MA_VVP,
2110 MA_LAST
2111} menu_array_index;
2112
2113typedef gpointer menu_array_values[MA_LAST];
2114
2115static void download_onscreen_maps ( menu_array_values values, gint redownload )
50a14534 2116{
7a7ba2f1
RN
2117 VikMapsLayer *vml = VIK_MAPS_LAYER(values[MA_VML]);
2118 VikViewport *vvp = VIK_VIEWPORT(values[MA_VVP]);
314c1ccc 2119 VikViewportDrawMode vp_drawmode = vik_viewport_get_drawmode ( vvp );
50a14534
EB
2120
2121 gdouble xzoom = vml->xmapzoom ? vml->xmapzoom : vik_viewport_get_xmpp ( vvp );
2122 gdouble yzoom = vml->ymapzoom ? vml->ymapzoom : vik_viewport_get_ympp ( vvp );
2123
2124 VikCoord ul, br;
2125 MapCoord ulm, brm;
2126
2127 vik_viewport_screen_to_coord ( vvp, 0, 0, &ul );
2128 vik_viewport_screen_to_coord ( vvp, vik_viewport_get_width(vvp), vik_viewport_get_height(vvp), &br );
2129
820c59f4
GB
2130 VikMapSource *map = MAPS_LAYER_NTH_TYPE(vml->maptype);
2131 if ( vik_map_source_get_drawmode(map) == vp_drawmode &&
2132 vik_map_source_coord_to_mapcoord ( map, &ul, xzoom, yzoom, &ulm ) &&
2133 vik_map_source_coord_to_mapcoord ( map, &br, xzoom, yzoom, &brm ) )
50817314 2134 start_download_thread ( vml, vvp, &ul, &br, redownload );
820c59f4
GB
2135 else if (vik_map_source_get_drawmode(map) != vp_drawmode) {
2136 const gchar *drawmode_name = vik_viewport_get_drawmode_name (vvp, vik_map_source_get_drawmode(map));
4c77d5e0 2137 gchar *err = g_strdup_printf(_("Wrong drawmode for this map.\nSelect \"%s\" from View menu and try again."), _(drawmode_name));
314c1ccc
QT
2138 a_dialog_error_msg ( VIK_GTK_WINDOW_FROM_LAYER(vml), err );
2139 g_free(err);
2140 }
50a14534 2141 else
4c77d5e0 2142 a_dialog_error_msg ( VIK_GTK_WINDOW_FROM_LAYER(vml), _("Wrong zoom level for this map.") );
50a14534
EB
2143
2144}
2145
7a7ba2f1 2146static void maps_layer_download_missing_onscreen_maps ( menu_array_values values )
50817314 2147{
7a7ba2f1 2148 download_onscreen_maps( values, REDOWNLOAD_NONE);
50817314
GB
2149}
2150
7a7ba2f1 2151static void maps_layer_download_new_onscreen_maps ( menu_array_values values )
6a4a29aa 2152{
7a7ba2f1 2153 download_onscreen_maps( values, REDOWNLOAD_NEW);
6a4a29aa
JJ
2154}
2155
7a7ba2f1 2156static void maps_layer_redownload_all_onscreen_maps ( menu_array_values values )
50817314 2157{
7a7ba2f1 2158 download_onscreen_maps( values, REDOWNLOAD_ALL);
50817314
GB
2159}
2160
859412d0 2161static void maps_layer_about ( gpointer vml_vvp[2] )
b03ae39b
RN
2162{
2163 VikMapsLayer *vml = vml_vvp[0];
2164 VikMapSource *map = MAPS_LAYER_NTH_TYPE(vml->maptype);
2165
2166 if ( vik_map_source_get_license (map) )
2167 maps_show_license ( VIK_GTK_WINDOW_FROM_LAYER(vml), map );
2168 else
2169 a_dialog_info_msg ( VIK_GTK_WINDOW_FROM_LAYER(vml),
2170 vik_map_source_get_label (map) );
2171}
2172
3ac548fa
RN
2173/**
2174 * maps_layer_how_many_maps:
2175 * Copied from maps_layer_download_section but without the actual download and this returns a value
2176 */
2177static gint maps_layer_how_many_maps ( VikMapsLayer *vml, VikViewport *vvp, VikCoord *ul, VikCoord *br, gdouble zoom, gint redownload )
2178{
2179 MapCoord ulm, brm;
2180 VikMapSource *map = MAPS_LAYER_NTH_TYPE(vml->maptype);
2181
2182 if ( vik_map_source_is_direct_file_access ( map ) )
2183 return 0;
2184
2185 if (!vik_map_source_coord_to_mapcoord(map, ul, zoom, zoom, &ulm)
2186 || !vik_map_source_coord_to_mapcoord(map, br, zoom, zoom, &brm)) {
2187 g_warning("%s() coord_to_mapcoord() failed", __PRETTY_FUNCTION__);
2188 return 0;
2189 }
2190
2191 MapDownloadInfo *mdi = g_malloc(sizeof(MapDownloadInfo));
2192 gint i, j;
2193
2194 mdi->vml = vml;
2195 mdi->vvp = vvp;
2196 mdi->map_layer_alive = TRUE;
fc6640a9 2197 mdi->mutex = vik_mutex_new();
3ac548fa
RN
2198 mdi->refresh_display = FALSE;
2199
2200 mdi->cache_dir = g_strdup ( vml->cache_dir );
2201 mdi->maxlen = strlen ( vml->cache_dir ) + 40;
2202 mdi->filename_buf = g_malloc ( mdi->maxlen * sizeof(gchar) );
2203 mdi->maptype = vml->maptype;
d281e8b4 2204 mdi->cache_layout = vml->cache_layout;
3ac548fa
RN
2205
2206 mdi->mapcoord = ulm;
2207 mdi->redownload = redownload;
2208
2209 mdi->x0 = MIN(ulm.x, brm.x);
2210 mdi->xf = MAX(ulm.x, brm.x);
2211 mdi->y0 = MIN(ulm.y, brm.y);
2212 mdi->yf = MAX(ulm.y, brm.y);
2213
2214 mdi->mapstoget = 0;
2215
2216 if ( mdi->redownload == REDOWNLOAD_ALL ) {
2217 mdi->mapstoget = (mdi->xf - mdi->x0 + 1) * (mdi->yf - mdi->y0 + 1);
2218 }
2219 else {
2220 /* calculate how many we need */
2113a507 2221 MapCoord mcoord = mdi->mapcoord;
3ac548fa 2222 for (i = mdi->x0; i <= mdi->xf; i++) {
2113a507 2223 mcoord.x = i;
3ac548fa 2224 for (j = mdi->y0; j <= mdi->yf; j++) {
2113a507
RN
2225 mcoord.y = j;
2226 // Only count tiles from supported areas
2227 if ( is_in_area ( map, mcoord ) ) {
2228 get_filename ( mdi->cache_dir, mdi->cache_layout,
2229 vik_map_source_get_uniq_id(map),
2230 vik_map_source_get_name(map),
2231 ulm.scale, ulm.z, i, j, mdi->filename_buf, mdi->maxlen,
2232 vik_map_source_get_file_extension(map) );
2233 if ( mdi->redownload == REDOWNLOAD_NEW ) {
2234 // Assume the worst - always a new file
2235 // Absolute value would require a server lookup - but that is too slow
3ac548fa
RN
2236 mdi->mapstoget++;
2237 }
2238 else {
2113a507
RN
2239 if ( g_file_test ( mdi->filename_buf, G_FILE_TEST_EXISTS ) == FALSE ) {
2240 // Missing
2241 mdi->mapstoget++;
2242 }
2243 else {
2244 if ( mdi->redownload == REDOWNLOAD_BAD ) {
2245 /* see if this one is bad or what */
2246 GError *gx = NULL;
2247 GdkPixbuf *pixbuf = gdk_pixbuf_new_from_file ( mdi->filename_buf, &gx );
2248 if (gx || (!pixbuf)) {
2249 mdi->mapstoget++;
2250 }
2251 break;
2252 // Other download cases already considered or just ignored
3ac548fa 2253 }
3ac548fa
RN
2254 }
2255 }
2256 }
2257 }
2258 }
2259 }
2260
2261 gint rv = mdi->mapstoget;
2262
2263 mdi_free ( mdi );
2264
2265 return rv;
2266}
2267
2268/**
2269 * maps_dialog_zoom_between:
2270 * This dialog is specific to the map layer, so it's here rather than in dialog.c
2271 */
2272gboolean maps_dialog_zoom_between ( GtkWindow *parent,
2273 gchar *title,
2274 gchar *zoom_list[],
2275 gint default_zoom1,
2276 gint default_zoom2,
2277 gint *selected_zoom1,
2278 gint *selected_zoom2,
2279 gchar *download_list[],
2280 gint default_download,
2281 gint *selected_download )
2282{
2283 GtkWidget *dialog = gtk_dialog_new_with_buttons ( title,
2284 parent,
2285 GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
2286 GTK_STOCK_OK, GTK_RESPONSE_ACCEPT,
2287 GTK_STOCK_CANCEL, GTK_RESPONSE_REJECT,
2288 NULL );
2289 gtk_dialog_set_default_response ( GTK_DIALOG(dialog), GTK_RESPONSE_ACCEPT );
2290 GtkWidget *response_w = NULL;
2291#if GTK_CHECK_VERSION (2, 20, 0)
2292 response_w = gtk_dialog_get_widget_for_response ( GTK_DIALOG(dialog), GTK_RESPONSE_ACCEPT );
2293#endif
2294 GtkWidget *zoom_label1 = gtk_label_new ( _("Zoom Start:") );
2295 GtkWidget *zoom_combo1 = vik_combo_box_text_new();
2296 gchar **s;
2297 for (s = zoom_list; *s; s++)
2298 vik_combo_box_text_append ( zoom_combo1, *s );
2299 gtk_combo_box_set_active ( GTK_COMBO_BOX(zoom_combo1), default_zoom1 );
2300
2301 GtkWidget *zoom_label2 = gtk_label_new ( _("Zoom End:") );
2302 GtkWidget *zoom_combo2 = vik_combo_box_text_new();
2303 for (s = zoom_list; *s; s++)
2304 vik_combo_box_text_append ( zoom_combo2, *s );
2305 gtk_combo_box_set_active ( GTK_COMBO_BOX(zoom_combo2), default_zoom2 );
2306
2307 GtkWidget *download_label = gtk_label_new(_("Download Maps Method:"));
2308 GtkWidget *download_combo = vik_combo_box_text_new();
2309 for (s = download_list; *s; s++)
2310 vik_combo_box_text_append ( download_combo, *s );
2311 gtk_combo_box_set_active ( GTK_COMBO_BOX(download_combo), default_download );
2312
2313 GtkTable *box = GTK_TABLE(gtk_table_new(3, 2, FALSE));
2314 gtk_table_attach_defaults (box, GTK_WIDGET(zoom_label1), 0, 1, 0, 1);
2315 gtk_table_attach_defaults (box, GTK_WIDGET(zoom_combo1), 1, 2, 0, 1);
2316 gtk_table_attach_defaults (box, GTK_WIDGET(zoom_label2), 0, 1, 1, 2);
2317 gtk_table_attach_defaults (box, GTK_WIDGET(zoom_combo2), 1, 2, 1, 2);
2318 gtk_table_attach_defaults (box, GTK_WIDGET(download_label), 0, 1, 2, 3);
2319 gtk_table_attach_defaults (box, GTK_WIDGET(download_combo), 1, 2, 2, 3);
2320
2321 gtk_box_pack_start ( GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(dialog))), GTK_WIDGET(box), FALSE, FALSE, 5 );
2322
2323 if ( response_w )
2324 gtk_widget_grab_focus ( response_w );
2325
2326 gtk_widget_show_all ( dialog );
2327 if ( gtk_dialog_run ( GTK_DIALOG(dialog) ) != GTK_RESPONSE_ACCEPT ) {
2328 gtk_widget_destroy(dialog);
2329 return FALSE;
2330 }
2331
2332 // Return selected options
2333 *selected_zoom1 = gtk_combo_box_get_active ( GTK_COMBO_BOX(zoom_combo1) );
2334 *selected_zoom2 = gtk_combo_box_get_active ( GTK_COMBO_BOX(zoom_combo2) );
2335 *selected_download = gtk_combo_box_get_active ( GTK_COMBO_BOX(download_combo) );
2336
2337 gtk_widget_destroy(dialog);
2338 return TRUE;
2339}
2340
2341// My best guess of sensible limits
2342#define REALLY_LARGE_AMOUNT_OF_TILES 5000
2343#define CONFIRM_LARGE_AMOUNT_OF_TILES 500
2344
2345/**
2346 * Get all maps in the region for zoom levels specified by the user
2347 * Sort of similar to trw_layer_download_map_along_track_cb function
2348 */
7a7ba2f1 2349static void maps_layer_download_all ( menu_array_values values )
3ac548fa 2350{
7a7ba2f1
RN
2351 VikMapsLayer *vml = VIK_MAPS_LAYER(values[MA_VML]);
2352 VikViewport *vvp = VIK_VIEWPORT(values[MA_VVP]);
3ac548fa
RN
2353
2354 // I don't think we should allow users to hammer the servers too much...
2355 // Delibrately not allowing lowest zoom levels
2356 // Still can give massive numbers to download
2357 // A screen size of 1600x1200 gives around 300,000 tiles between 1..128 when none exist before !!
2358 gchar *zoom_list[] = {"1", "2", "4", "8", "16", "32", "64", "128", "256", "512", "1024", NULL };
2359 gdouble zoom_vals[] = {1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024};
2360
2361 gint selected_zoom1, selected_zoom2, default_zoom, lower_zoom;
2362 gint selected_download_method;
2363
2364 gdouble cur_zoom = vik_viewport_get_zoom(vvp);
2365
2366 for (default_zoom = 0; default_zoom < sizeof(zoom_vals)/sizeof(gdouble); default_zoom++) {
2367 if (cur_zoom == zoom_vals[default_zoom])
2368 break;
2369 }
2370 default_zoom = (default_zoom == sizeof(zoom_vals)/sizeof(gdouble)) ? sizeof(zoom_vals)/sizeof(gdouble) - 1 : default_zoom;
2371
2372 // Default to only 2 zoom levels below the current one
2373 if (default_zoom > 1 )
2374 lower_zoom = default_zoom - 2;
2375 else
2376 lower_zoom = default_zoom;
2377
2378 // redownload method - needs to align with REDOWNLOAD* macro values
2379 gchar *download_list[] = { _("Missing"), _("Bad"), _("New"), _("Reload All"), NULL };
2380
2381 gchar *title = g_strdup_printf ( ("%s: %s"), vik_maps_layer_get_map_label (vml), _("Download for Zoom Levels") );
2382
2383 if ( ! maps_dialog_zoom_between ( VIK_GTK_WINDOW_FROM_LAYER(vml),
2384 title,
2385 zoom_list,
2386 lower_zoom,
2387 default_zoom,
2388 &selected_zoom1,
2389 &selected_zoom2,
2390 download_list,
2391 REDOWNLOAD_NONE, // AKA Missing
2392 &selected_download_method ) ) {
2393 // Cancelled
2394 g_free ( title );
2395 return;
2396 }
2397 g_free ( title );
2398
2399 // Find out new current positions
2400 gdouble min_lat, max_lat, min_lon, max_lon;
2401 VikCoord vc_ul, vc_br;
2402 vik_viewport_get_min_max_lat_lon ( vvp, &min_lat, &max_lat, &min_lon, &max_lon );
2403 struct LatLon ll_ul = { max_lat, min_lon };
2404 struct LatLon ll_br = { min_lat, max_lon };
2405 vik_coord_load_from_latlon ( &vc_ul, vik_viewport_get_coord_mode (vvp), &ll_ul );
2406 vik_coord_load_from_latlon ( &vc_br, vik_viewport_get_coord_mode (vvp), &ll_br );
2407
2408 // Get Maps Count - call for each zoom level (in reverse)
2409 // With REDOWNLOAD_NEW this is a possible maximum
2410 // With REDOWNLOAD_NONE this only missing ones - however still has a server lookup per tile
2411 gint map_count = 0;
2412 gint zz;
2413 for ( zz = selected_zoom2; zz >= selected_zoom1; zz-- ) {
2414 map_count = map_count + maps_layer_how_many_maps ( vml, vvp, &vc_ul, &vc_br, zoom_vals[zz], selected_download_method );
2415 }
2416
2417 g_debug ("vikmapslayer: download request map count %d for method %d", map_count, selected_download_method);
2418
2419 // Absolute protection of hammering a map server
2420 if ( map_count > REALLY_LARGE_AMOUNT_OF_TILES ) {
2421 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);
2422 a_dialog_error_msg ( VIK_GTK_WINDOW_FROM_LAYER(vml), str );
2423 g_free (str);
2424 return;
2425 }
2426
2427 // Confirm really want to do this
2428 if ( map_count > CONFIRM_LARGE_AMOUNT_OF_TILES ) {
2429 gchar *str = g_strdup_printf (_("Do you really want to download %d tiles?"), map_count);
2430 gboolean ans = a_dialog_yes_or_no ( VIK_GTK_WINDOW_FROM_LAYER(vml), str, NULL );
2431 g_free (str);
2432 if ( ! ans )
2433 return;
2434 }
2435
2436 // Get Maps - call for each zoom level (in reverse)
2437 for ( zz = selected_zoom2; zz >= selected_zoom1; zz-- ) {
2438 maps_layer_download_section ( vml, vvp, &vc_ul, &vc_br, zoom_vals[zz], selected_download_method );
2439 }
2440}
2441
9095ea4c
RN
2442/**
2443 *
2444 */
2445static void maps_layer_flush ( menu_array_values values )
2446{
2447 VikMapsLayer *vml = VIK_MAPS_LAYER(values[MA_VML]);
2448 a_mapcache_flush_type ( vik_map_source_get_uniq_id(MAPS_LAYER_NTH_TYPE(vml->maptype)) );
2449}
2450
50a14534
EB
2451static void maps_layer_add_menu_items ( VikMapsLayer *vml, GtkMenu *menu, VikLayersPanel *vlp )
2452{
50a14534 2453 GtkWidget *item;
7a7ba2f1
RN
2454 static menu_array_values values;
2455 values[MA_VML] = vml;
2456 values[MA_VVP] = vik_layers_panel_get_viewport( VIK_LAYERS_PANEL(vlp) );
50a14534
EB
2457
2458 item = gtk_menu_item_new();
2459 gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item );
2460 gtk_widget_show ( item );
2461
555ec6f6
RN
2462 /* Now with icons */
2463 item = gtk_image_menu_item_new_with_mnemonic ( _("Download _Missing Onscreen Maps") );
2464 gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_ADD, GTK_ICON_SIZE_MENU) );
7a7ba2f1 2465 g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(maps_layer_download_missing_onscreen_maps), values );
50a14534
EB
2466 gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
2467 gtk_widget_show ( item );
50817314 2468
c81ded98 2469 if ( vik_map_source_supports_download_only_new (MAPS_LAYER_NTH_TYPE(vml->maptype)) ) {
555ec6f6
RN
2470 item = gtk_image_menu_item_new_with_mnemonic ( _("Download _New Onscreen Maps") );
2471 gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_REDO, GTK_ICON_SIZE_MENU) );
7a7ba2f1 2472 g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(maps_layer_download_new_onscreen_maps), values );
6a4a29aa
JJ
2473 gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
2474 gtk_widget_show ( item );
2475 }
2476
555ec6f6
RN
2477 item = gtk_image_menu_item_new_with_mnemonic ( _("Reload _All Onscreen Maps") );
2478 gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_REFRESH, GTK_ICON_SIZE_MENU) );
7a7ba2f1 2479 g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(maps_layer_redownload_all_onscreen_maps), values );
50817314
GB
2480 gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
2481 gtk_widget_show ( item );
3ac548fa
RN
2482
2483 item = gtk_image_menu_item_new_with_mnemonic ( _("Download Maps in _Zoom Levels...") );
2484 gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_DND_MULTIPLE, GTK_ICON_SIZE_MENU) );
7a7ba2f1 2485 g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(maps_layer_download_all), values );
3ac548fa
RN
2486 gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
2487 gtk_widget_show ( item );
b03ae39b
RN
2488
2489 item = gtk_image_menu_item_new_from_stock ( GTK_STOCK_ABOUT, NULL );
859412d0 2490 g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(maps_layer_about), values );
b03ae39b
RN
2491 gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
2492 gtk_widget_show ( item );
9095ea4c
RN
2493
2494 // Typical users shouldn't need to use this functionality - so debug only ATM
2495 if ( vik_debug ) {
2496 item = gtk_image_menu_item_new_with_mnemonic ( _("Flush Map Cache") );
2497 gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_REMOVE, GTK_ICON_SIZE_MENU) );
2498 g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(maps_layer_flush), values );
2499 gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
2500 gtk_widget_show ( item );
2501 }
50a14534 2502}
6b59f63d
RN
2503
2504/**
2505 * Enable downloading maps of the current screen area either 'new' or 'everything'
2506 */
2507void vik_maps_layer_download ( VikMapsLayer *vml, VikViewport *vvp, gboolean only_new )
2508{
2509 if ( !vml ) return;
2510 if ( !vvp ) return;
2511
7a7ba2f1
RN
2512 static menu_array_values values;
2513 values[MA_VML] = vml;
2514 values[MA_VVP] = vvp;
6b59f63d
RN
2515
2516 if ( only_new )
2517 // Get only new maps
7a7ba2f1 2518 maps_layer_download_new_onscreen_maps ( values );
6b59f63d
RN
2519 else
2520 // Redownload everything
7a7ba2f1 2521 maps_layer_redownload_all_onscreen_maps ( values );
6b59f63d 2522}