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