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