]> git.street.me.uk Git - andy/viking.git/blame - src/vikmapslayer.c
[DOC] Fix some incorrect docbook markup.
[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>
50a14534 6 * UTM multi-zone stuff by Kit Transue <notlostyet@didactek.com>
cdcaf41c 7 * Dynamic map type by Guilhem Bonnefille <guilhem.bonnefille@gmail.com>
50a14534
EB
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 *
23 */
24
4c77d5e0
GB
25#ifdef HAVE_CONFIG_H
26#include "config.h"
27#endif
28
50a14534
EB
29#include <gtk/gtk.h>
30#include <gdk-pixbuf/gdk-pixdata.h>
45acf79e
MA
31#include <glib.h>
32#include <glib/gstdio.h>
4c77d5e0
GB
33#include <glib/gi18n.h>
34
8c00358d 35#ifdef HAVE_STRING_H
50a14534 36#include <string.h>
8c00358d
GB
37#endif
38#ifdef HAVE_MATH_H
50a14534 39#include <math.h>
8c00358d
GB
40#endif
41
45acf79e 42#ifdef HAVE_UNISTD_H
50a14534 43#include <unistd.h>
45acf79e 44#endif
50a14534 45
a7023a1b 46#include "viking.h"
450d8665 47#include "vikmapsourcedefault.h"
9979924f 48#include "maputils.h"
50a14534 49#include "mapcache.h"
50a14534 50#include "background.h"
a7023a1b
RN
51#include "preferences.h"
52#include "vikmapslayer.h"
bce3a7b0
EB
53#include "icons/icons.h"
54
0f7e9133
RN
55#define VIK_SETTINGS_MAP_MAX_TILES "maps_max_tiles"
56static gint MAX_TILES = 1000;
57
58#define VIK_SETTINGS_MAP_MIN_SHRINKFACTOR "maps_min_shrinkfactor"
59#define VIK_SETTINGS_MAP_MAX_SHRINKFACTOR "maps_max_shrinkfactor"
60static gdouble MAX_SHRINKFACTOR = 8.0000001; /* zoom 1 viewing 8-tiles */
61static gdouble MIN_SHRINKFACTOR = 0.0312499; /* zoom 32 viewing 1-tiles */
62
63#define VIK_SETTINGS_MAP_REAL_MIN_SHRINKFACTOR "maps_real_min_shrinkfactor"
64static gdouble REAL_MIN_SHRINKFACTOR = 0.0039062499; /* if shrinkfactor is between MAX and REAL_MAX, will only check for existence */
65
50a14534
EB
66/****** MAP TYPES ******/
67
cdcaf41c
QT
68static GList *__map_types = NULL;
69
70#define NUM_MAP_TYPES g_list_length(__map_types)
50a14534 71
cdcaf41c 72/* List of label for each map type */
a8876892 73static gchar **params_maptypes = NULL;
cdcaf41c
QT
74
75/* Corresponding IDS. (Cf. field uniq_id in VikMapsLayer struct) */
a8876892 76static guint *params_maptypes_ids = NULL;
50a14534
EB
77
78/******** MAPZOOMS *********/
79
fcc2786b
SW
80static 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 };
81static 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 };
82static 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 83
d756fb5c 84#define NUM_MAPZOOMS (sizeof(params_mapzooms)/sizeof(params_mapzooms[0]) - 1)
50a14534
EB
85
86/**************************/
87
88
07059501 89static void maps_layer_post_read (VikLayer *vl, VikViewport *vp, gboolean from_file);
7924723c 90static const gchar* maps_layer_tooltip ( VikMapsLayer *vml );
911400b5
AF
91static void maps_layer_marshall( VikMapsLayer *vml, guint8 **data, gint *len );
92static VikMapsLayer *maps_layer_unmarshall( guint8 *data, gint len, VikViewport *vvp );
158b3642
RN
93static gboolean maps_layer_set_param ( VikMapsLayer *vml, guint16 id, VikLayerParamData data, VikViewport *vvp, gboolean is_file_operation );
94static VikLayerParamData maps_layer_get_param ( VikMapsLayer *vml, guint16 id, gboolean is_file_operation );
50a14534
EB
95static void maps_layer_draw ( VikMapsLayer *vml, VikViewport *vvp );
96static VikMapsLayer *maps_layer_new ( VikViewport *vvp );
97static void maps_layer_free ( VikMapsLayer *vml );
98static gboolean maps_layer_download_release ( VikMapsLayer *vml, GdkEventButton *event, VikViewport *vvp );
99static gboolean maps_layer_download_click ( VikMapsLayer *vml, GdkEventButton *event, VikViewport *vvp );
941aa6e9 100static gpointer maps_layer_download_create ( VikWindow *vw, VikViewport *vvp );
50a14534
EB
101static void maps_layer_set_cache_dir ( VikMapsLayer *vml, const gchar *dir );
102static void start_download_thread ( VikMapsLayer *vml, VikViewport *vvp, const VikCoord *ul, const VikCoord *br, gint redownload );
103static void maps_layer_add_menu_items ( VikMapsLayer *vml, GtkMenu *menu, VikLayersPanel *vlp );
e2cb421f 104static guint map_uniq_id_to_index ( guint uniq_id );
50a14534
EB
105
106
107static VikLayerParamScale params_scales[] = {
108 /* min, max, step, digits (decimal places) */
109 { 0, 255, 3, 0 }, /* alpha */
110};
111
a7023a1b
RN
112static VikLayerParamData mode_default ( void ) { return VIK_LPD_UINT ( 19 ); } // OSM MapQuest maps
113static VikLayerParamData directory_default ( void )
114{
115 VikLayerParamData data;
b781c9db
GB
116 VikLayerParamData *pref = a_preferences_get(VIKING_PREFERENCES_NAMESPACE "maplayer_default_dir");
117 if (pref) data.s = g_strdup ( pref->s );
a7023a1b
RN
118 return data;
119}
120static VikLayerParamData alpha_default ( void ) { return VIK_LPD_UINT ( 255 ); }
121static VikLayerParamData mapzoom_default ( void ) { return VIK_LPD_UINT ( 0 ); }
122
50a14534 123VikLayerParam maps_layer_params[] = {
a7023a1b
RN
124 { VIK_LAYER_MAPS, "mode", VIK_LAYER_PARAM_UINT, VIK_LAYER_GROUP_NONE, N_("Map Type:"), VIK_LAYER_WIDGET_COMBOBOX, NULL, NULL, NULL, mode_default },
125 { VIK_LAYER_MAPS, "directory", VIK_LAYER_PARAM_STRING, VIK_LAYER_GROUP_NONE, N_("Maps Directory:"), VIK_LAYER_WIDGET_FOLDERENTRY, NULL, NULL, NULL, directory_default },
126 { VIK_LAYER_MAPS, "alpha", VIK_LAYER_PARAM_UINT, VIK_LAYER_GROUP_NONE, N_("Alpha:"), VIK_LAYER_WIDGET_HSCALE, params_scales, NULL,
127 N_("Control the Alpha value for transparency effects"), alpha_default },
ece91e76 128 { 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 },
a7023a1b
RN
129 { VIK_LAYER_MAPS, "adlonlymissing", VIK_LAYER_PARAM_BOOLEAN, VIK_LAYER_GROUP_NONE, N_("Autodownload Only Gets Missing Maps:"), VIK_LAYER_WIDGET_CHECKBUTTON, NULL, NULL,
130 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 },
131 { VIK_LAYER_MAPS, "mapzoom", VIK_LAYER_PARAM_UINT, VIK_LAYER_GROUP_NONE, N_("Zoom Level:"), VIK_LAYER_WIDGET_COMBOBOX, params_mapzooms, NULL,
132 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."),
133 mapzoom_default },
50a14534
EB
134};
135
382566c3
RN
136enum {
137 PARAM_MAPTYPE=0,
138 PARAM_CACHE_DIR,
139 PARAM_ALPHA,
140 PARAM_AUTODOWNLOAD,
141 PARAM_ONLYMISSING,
142 PARAM_MAPZOOM,
143 NUM_PARAMS
144};
50a14534 145
0d66c56c
RN
146void maps_layer_set_autodownload_default ( gboolean autodownload )
147{
148 // Set appropriate function
149 if ( autodownload )
150 maps_layer_params[PARAM_AUTODOWNLOAD].default_value = vik_lpd_true_default;
151 else
152 maps_layer_params[PARAM_AUTODOWNLOAD].default_value = vik_lpd_false_default;
153}
154
50a14534 155static VikToolInterface maps_tools[] = {
79dce0cb 156 { { "MapsDownload", "vik-icon-Maps Download", N_("_Maps Download"), NULL, N_("Maps Download"), 0 },
6b59f63d
RN
157 (VikToolConstructorFunc) maps_layer_download_create,
158 NULL,
159 NULL,
160 NULL,
161 (VikToolMouseFunc) maps_layer_download_click,
162 NULL,
163 (VikToolMouseFunc) maps_layer_download_release,
164 NULL,
ef5e8132
RN
165 FALSE,
166 GDK_CURSOR_IS_PIXMAP, &cursor_mapdl_pixbuf },
50a14534
EB
167};
168
169VikLayerInterface vik_maps_layer_interface = {
db386630 170 "Map",
4c77d5e0 171 N_("Map"),
75078768 172 "<control><shift>M",
5bfafde9 173 &vikmapslayer_pixbuf,
50a14534
EB
174
175 maps_tools,
176 sizeof(maps_tools) / sizeof(maps_tools[0]),
177
178 maps_layer_params,
179 NUM_PARAMS,
180 NULL,
181 0,
182
5a4a28bf
QT
183 VIK_MENU_ITEM_ALL,
184
50a14534
EB
185 (VikLayerFuncCreate) maps_layer_new,
186 (VikLayerFuncRealize) NULL,
b112cbf5 187 (VikLayerFuncPostRead) maps_layer_post_read,
50a14534
EB
188 (VikLayerFuncFree) maps_layer_free,
189
190 (VikLayerFuncProperties) NULL,
191 (VikLayerFuncDraw) maps_layer_draw,
192 (VikLayerFuncChangeCoordMode) NULL,
193
20c7a3a0
QT
194 (VikLayerFuncSetMenuItemsSelection) NULL,
195 (VikLayerFuncGetMenuItemsSelection) NULL,
196
50a14534
EB
197 (VikLayerFuncAddMenuItems) maps_layer_add_menu_items,
198 (VikLayerFuncSublayerAddMenuItems) NULL,
199
200 (VikLayerFuncSublayerRenameRequest) NULL,
201 (VikLayerFuncSublayerToggleVisible) NULL,
9da7faf2 202 (VikLayerFuncSublayerTooltip) NULL,
7924723c 203 (VikLayerFuncLayerTooltip) maps_layer_tooltip,
a5dcfdb7 204 (VikLayerFuncLayerSelected) NULL,
50a14534 205
911400b5
AF
206 (VikLayerFuncMarshall) maps_layer_marshall,
207 (VikLayerFuncUnmarshall) maps_layer_unmarshall,
50a14534
EB
208
209 (VikLayerFuncSetParam) maps_layer_set_param,
210 (VikLayerFuncGetParam) maps_layer_get_param,
211
212 (VikLayerFuncReadFileData) NULL,
213 (VikLayerFuncWriteFileData) NULL,
214
33534cd8 215 (VikLayerFuncDeleteItem) NULL,
d5874ef9 216 (VikLayerFuncCutItem) NULL,
50a14534
EB
217 (VikLayerFuncCopyItem) NULL,
218 (VikLayerFuncPasteItem) NULL,
219 (VikLayerFuncFreeCopiedItem) NULL,
70a23263 220 (VikLayerFuncDragDropRequest) NULL,
77ad64fa
RN
221
222 (VikLayerFuncSelectClick) NULL,
08f14055
RN
223 (VikLayerFuncSelectMove) NULL,
224 (VikLayerFuncSelectRelease) NULL,
e46f259a 225 (VikLayerFuncSelectedViewportMenu) NULL,
50a14534
EB
226};
227
228struct _VikMapsLayer {
229 VikLayer vl;
230 guint maptype;
231 gchar *cache_dir;
232 guint8 alpha;
233 guint mapzoom_id;
234 gdouble xmapzoom, ymapzoom;
235
236 gboolean autodownload;
382566c3 237 gboolean adl_only_missing;
10ca2bfe
QT
238 VikCoord *last_center;
239 gdouble last_xmpp;
240 gdouble last_ympp;
50a14534
EB
241
242 gint dl_tool_x, dl_tool_y;
243
244 GtkMenu *dl_right_click_menu;
245 VikCoord redownload_ul, redownload_br; /* right click menu only */
246 VikViewport *redownload_vvp;
8e507445
RN
247
248 gboolean license_notice_shown; // FALSE for new maps only, otherwise
249 // TRUE for saved maps & other layer changes as we don't need to show it again
50a14534
EB
250};
251
6a4a29aa
JJ
252enum { REDOWNLOAD_NONE = 0, /* download only missing maps */
253 REDOWNLOAD_BAD, /* download missing and bad maps */
254 REDOWNLOAD_NEW, /* download missing maps that are newer on server only */
255 REDOWNLOAD_ALL, /* download all maps */
256 DOWNLOAD_OR_REFRESH }; /* download missing maps and refresh cache */
50a14534 257
55ddef4e 258static VikLayerParam prefs[] = {
bbd41664 259 { 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") },
55ddef4e
JJ
260};
261
262void maps_layer_init ()
263{
264 VikLayerParamData tmp;
265 tmp.s = maps_layer_default_dir();
266 a_preferences_register(prefs, tmp, VIKING_PREFERENCES_GROUP_KEY);
0f7e9133
RN
267
268 gint max_tiles = MAX_TILES;
269 if ( a_settings_get_integer ( VIK_SETTINGS_MAP_MAX_TILES, &max_tiles ) )
270 MAX_TILES = max_tiles;
271
272 gdouble gdtmp;
273 if ( a_settings_get_double ( VIK_SETTINGS_MAP_MIN_SHRINKFACTOR, &gdtmp ) )
274 MIN_SHRINKFACTOR = gdtmp;
275
276 if ( a_settings_get_double ( VIK_SETTINGS_MAP_MAX_SHRINKFACTOR, &gdtmp ) )
277 MAX_SHRINKFACTOR = gdtmp;
278
279 if ( a_settings_get_double ( VIK_SETTINGS_MAP_REAL_MIN_SHRINKFACTOR, &gdtmp ) )
280 REAL_MIN_SHRINKFACTOR = gdtmp;
55ddef4e 281}
50a14534 282
cdcaf41c
QT
283/****************************************/
284/******** MAPS LAYER TYPES **************/
285/****************************************/
286
e2cb421f 287int _get_index_for_id ( guint id )
cdcaf41c 288{
e2cb421f
GB
289 int index = 0 ;
290 while (params_maptypes_ids[index] != 0)
291 {
292 if (params_maptypes_ids[index] == id)
293 return index;
294 index++;
295 }
296 return -1;
297}
cdcaf41c 298
e2cb421f
GB
299void _add_map_source ( guint id, const char *label, VikMapSource *map )
300{
a8876892
GB
301 gsize len = 0;
302 if (params_maptypes)
303 len = g_strv_length (params_maptypes);
cdcaf41c 304 /* Add the label */
a8876892
GB
305 params_maptypes = g_realloc (params_maptypes, (len+2)*sizeof(gchar*));
306 params_maptypes[len] = g_strdup (label);
307 params_maptypes[len+1] = NULL;
cdcaf41c
QT
308
309 /* Add the id */
a8876892
GB
310 params_maptypes_ids = g_realloc (params_maptypes_ids, (len+2)*sizeof(guint));
311 params_maptypes_ids[len] = id;
312 params_maptypes_ids[len+1] = 0;
cdcaf41c
QT
313
314 /* We have to clone */
820c59f4 315 VikMapSource *clone = VIK_MAP_SOURCE(g_object_ref(map));
cdcaf41c
QT
316 /* Register the clone in the list */
317 __map_types = g_list_append(__map_types, clone);
318
319 /* Hack
e2cb421f 320 We have to ensure the mode LayerParam references the up-to-date
cdcaf41c
QT
321 GLists.
322 */
323 /*
324 memcpy(&maps_layer_params[0].widget_data, &params_maptypes, sizeof(gpointer));
325 memcpy(&maps_layer_params[0].extra_widget_data, &params_maptypes_ids, sizeof(gpointer));
326 */
327 maps_layer_params[0].widget_data = params_maptypes;
328 maps_layer_params[0].extra_widget_data = params_maptypes_ids;
329}
330
e2cb421f
GB
331void _update_map_source ( const char *label, VikMapSource *map, int index )
332{
333 GList *item = g_list_nth (__map_types, index);
334 g_object_unref (item->data);
335 item->data = g_object_ref (map);
336 /* Change previous data */
337 g_free (params_maptypes[index]);
338 params_maptypes[index] = g_strdup (label);
339}
340
17281ebd
GB
341/**
342 * maps_layer_register_map_source:
343 * @map: the new VikMapSource
344 *
345 * Register a new VikMapSource.
346 * Override existing one (equality of id).
347 */
e2cb421f
GB
348void maps_layer_register_map_source ( VikMapSource *map )
349{
350 g_assert(map != NULL);
351
352 guint id = vik_map_source_get_uniq_id(map);
353 const char *label = vik_map_source_get_label(map);
354 g_assert(label != NULL);
355
356 int previous = map_uniq_id_to_index (id);
357 if (previous != NUM_MAP_TYPES)
358 {
359 _update_map_source (label, map, previous);
360 }
361 else
362 {
363 _add_map_source (id, label, map);
364 }
365}
366
a8876892
GB
367#define MAPS_LAYER_NTH_LABEL(n) (params_maptypes[n])
368#define MAPS_LAYER_NTH_ID(n) (params_maptypes_ids[n])
820c59f4 369#define MAPS_LAYER_NTH_TYPE(n) (VIK_MAP_SOURCE(g_list_nth_data(__map_types, (n))))
cdcaf41c 370
7114e879
QT
371gint vik_maps_layer_get_map_type(VikMapsLayer *vml)
372{
373 return(vml->maptype);
374}
375
376gchar *vik_maps_layer_get_map_label(VikMapsLayer *vml)
377{
378 return(g_strdup(MAPS_LAYER_NTH_LABEL(vml->maptype)));
379}
380
50a14534
EB
381/****************************************/
382/******** CACHE DIR STUFF ***************/
383/****************************************/
384
2673b29d 385#define DIRECTDIRACCESS "%s%d" G_DIR_SEPARATOR_S "%d" G_DIR_SEPARATOR_S "%d%s"
3d9454e6 386#define DIRSTRUCTURE "%st%ds%dz%d" G_DIR_SEPARATOR_S "%d" G_DIR_SEPARATOR_S "%d"
6a27c1bc
MA
387#define MAPS_CACHE_DIR maps_layer_default_dir()
388
50a14534 389#ifdef WINDOWS
6a27c1bc
MA
390#include <io.h>
391#define GLOBAL_MAPS_DIR "C:\\VIKING-MAPS\\"
392#define LOCAL_MAPS_DIR "VIKING-MAPS"
42293fc2
RN
393#elif defined __APPLE__
394#include <stdlib.h>
395#define GLOBAL_MAPS_DIR "/Library/cache/Viking/maps/"
396#define LOCAL_MAPS_DIR "/Library/Application Support/Viking/viking-maps"
50a14534 397#else /* POSIX */
50a14534 398#include <stdlib.h>
50a14534 399#define GLOBAL_MAPS_DIR "/var/cache/maps/"
6a27c1bc
MA
400#define LOCAL_MAPS_DIR ".viking-maps"
401#endif
50a14534 402
0c1044e9 403gchar *maps_layer_default_dir ()
50a14534 404{
3d9454e6
GB
405 static gchar *defaultdir = NULL;
406 if ( ! defaultdir )
50a14534
EB
407 {
408 /* Thanks to Mike Davison for the $VIKING_MAPS usage */
3d9454e6
GB
409 const gchar *mapdir = g_getenv("VIKING_MAPS");
410 if ( mapdir ) {
411 defaultdir = g_strdup ( mapdir );
45acf79e 412 } else if ( g_access ( GLOBAL_MAPS_DIR, W_OK ) == 0 ) {
3d9454e6 413 defaultdir = g_strdup ( GLOBAL_MAPS_DIR );
50a14534 414 } else {
6a27c1bc 415 const gchar *home = g_get_home_dir();
45acf79e 416 if (!home || g_access(home, W_OK))
3d9454e6
GB
417 home = g_get_home_dir ();
418 if ( home )
6a27c1bc 419 defaultdir = g_build_filename ( home, LOCAL_MAPS_DIR, NULL );
50a14534 420 else
6a27c1bc 421 defaultdir = g_strdup ( LOCAL_MAPS_DIR );
50a14534 422 }
3d9454e6
GB
423 if (defaultdir && (defaultdir[strlen(defaultdir)-1] != G_DIR_SEPARATOR))
424 {
425 /* Add the separator at the end */
426 gchar *tmp = defaultdir;
427 defaultdir = g_strconcat(tmp, G_DIR_SEPARATOR_S, NULL);
428 g_free(tmp);
429 }
430 g_debug("%s: defaultdir=%s", __FUNCTION__, defaultdir);
50a14534
EB
431 }
432 return defaultdir;
433}
434
50a14534
EB
435static void maps_layer_mkdir_if_default_dir ( VikMapsLayer *vml )
436{
45acf79e 437 if ( vml->cache_dir && strcmp ( vml->cache_dir, MAPS_CACHE_DIR ) == 0 && g_file_test ( vml->cache_dir, G_FILE_TEST_EXISTS ) == FALSE )
50a14534 438 {
f83131b9 439 g_mkdir ( vml->cache_dir, 0777 );
50a14534
EB
440 }
441}
442
443static void maps_layer_set_cache_dir ( VikMapsLayer *vml, const gchar *dir )
444{
445 guint len;
446 g_assert ( vml != NULL);
e65028db
GB
447 g_free ( vml->cache_dir );
448 vml->cache_dir = NULL;
32f1d63a 449 const gchar *mydir = dir;
50a14534
EB
450
451 if ( dir == NULL || dir[0] == '\0' )
6926d79a
RN
452 {
453 if ( a_preferences_get(VIKING_PREFERENCES_NAMESPACE "maplayer_default_dir") )
32f1d63a 454 mydir = a_preferences_get(VIKING_PREFERENCES_NAMESPACE "maplayer_default_dir")->s;
6926d79a 455 }
32f1d63a
RN
456
457 // Ensure cache_dir always ends with a separator
458 len = strlen(mydir);
459 if ( mydir[len-1] != G_DIR_SEPARATOR )
50a14534 460 {
32f1d63a
RN
461 vml->cache_dir = g_malloc ( len+2 );
462 strncpy ( vml->cache_dir, mydir, len );
463 vml->cache_dir[len] = G_DIR_SEPARATOR;
464 vml->cache_dir[len+1] = '\0';
50a14534 465 }
32f1d63a
RN
466 else
467 vml->cache_dir = g_strdup ( mydir );
468
50a14534
EB
469 maps_layer_mkdir_if_default_dir ( vml );
470}
471
472/****************************************/
473/******** GOBJECT STUFF *****************/
474/****************************************/
475
476GType vik_maps_layer_get_type ()
477{
478 static GType vml_type = 0;
479
480 if (!vml_type)
481 {
482 static const GTypeInfo vml_info =
483 {
484 sizeof (VikMapsLayerClass),
485 NULL, /* base_init */
486 NULL, /* base_finalize */
487 NULL, /* class init */
488 NULL, /* class_finalize */
489 NULL, /* class_data */
490 sizeof (VikMapsLayer),
491 0,
492 NULL /* instance init */
493 };
494 vml_type = g_type_register_static ( VIK_LAYER_TYPE, "VikMapsLayer", &vml_info, 0 );
495 }
496
497 return vml_type;
498}
499
500/****************************************/
501/************** PARAMETERS **************/
502/****************************************/
503
504static guint map_index_to_uniq_id (guint8 index)
505{
506 g_assert ( index < NUM_MAP_TYPES );
820c59f4 507 return vik_map_source_get_uniq_id(MAPS_LAYER_NTH_TYPE(index));
50a14534
EB
508}
509
510static guint map_uniq_id_to_index ( guint uniq_id )
511{
512 gint i;
513 for ( i = 0; i < NUM_MAP_TYPES; i++ )
820c59f4 514 if ( vik_map_source_get_uniq_id(MAPS_LAYER_NTH_TYPE(i)) == uniq_id )
50a14534
EB
515 return i;
516 return NUM_MAP_TYPES; /* no such thing */
517}
518
192e40fc
RN
519void vik_maps_layer_pretend_licence_shown ( VikMapsLayer *vml )
520{
521 vml->license_notice_shown = TRUE;
522}
523
158b3642 524static gboolean maps_layer_set_param ( VikMapsLayer *vml, guint16 id, VikLayerParamData data, VikViewport *vvp, gboolean is_file_operation )
50a14534 525{
8e507445
RN
526 // When loading from a file don't need the license reminder
527 if ( is_file_operation )
528 vml->license_notice_shown = TRUE;
529
50a14534
EB
530 switch ( id )
531 {
532 case PARAM_CACHE_DIR: maps_layer_set_cache_dir ( vml, data.s ); break;
533 case PARAM_MAPTYPE: {
534 gint maptype = map_uniq_id_to_index(data.u);
4c77d5e0 535 if ( maptype == NUM_MAP_TYPES ) g_warning(_("Unknown map type"));
50a14534
EB
536 else vml->maptype = maptype;
537 break;
538 }
539 case PARAM_ALPHA: if ( data.u <= 255 ) vml->alpha = data.u; break;
540 case PARAM_AUTODOWNLOAD: vml->autodownload = data.b; break;
382566c3 541 case PARAM_ONLYMISSING: vml->adl_only_missing = data.b; break;
50a14534
EB
542 case PARAM_MAPZOOM: if ( data.u < NUM_MAPZOOMS ) {
543 vml->mapzoom_id = data.u;
544 vml->xmapzoom = __mapzooms_x [data.u];
545 vml->ymapzoom = __mapzooms_y [data.u];
4c77d5e0 546 }else g_warning (_("Unknown Map Zoom")); break;
50a14534
EB
547 }
548 return TRUE;
549}
550
158b3642 551static VikLayerParamData maps_layer_get_param ( VikMapsLayer *vml, guint16 id, gboolean is_file_operation )
50a14534
EB
552{
553 VikLayerParamData rv;
554 switch ( id )
555 {
cde1e50e 556 case PARAM_CACHE_DIR:
88542aa9
RN
557 {
558 gboolean set = FALSE;
cde1e50e
RN
559 /* Only save a blank when the map cache location equals the default
560 On reading in, when it is blank then the default is reconstructed
561 Since the default changes dependent on the user and OS, it means the resultant file is more portable */
88542aa9 562 if ( is_file_operation && vml->cache_dir && strcmp ( vml->cache_dir, MAPS_CACHE_DIR ) == 0 ) {
cde1e50e 563 rv.s = "";
88542aa9
RN
564 set = TRUE;
565 }
566 else if ( is_file_operation ) {
567 if ( a_vik_get_file_ref_format() == VIK_FILE_REF_FORMAT_RELATIVE ) {
568 gchar *cwd = g_get_current_dir();
569 if ( cwd ) {
570 rv.s = file_GetRelativeFilename ( cwd, vml->cache_dir );
571 if ( !rv.s ) rv.s = "";
572 set = TRUE;
573 }
574 }
575 }
576 if ( !set )
577 rv.s = vml->cache_dir ? vml->cache_dir : "";
cde1e50e 578 break;
88542aa9 579 }
50a14534
EB
580 case PARAM_MAPTYPE: rv.u = map_index_to_uniq_id ( vml->maptype ); break;
581 case PARAM_ALPHA: rv.u = vml->alpha; break;
582 case PARAM_AUTODOWNLOAD: rv.u = vml->autodownload; break;
382566c3 583 case PARAM_ONLYMISSING: rv.u = vml->adl_only_missing; break;
50a14534
EB
584 case PARAM_MAPZOOM: rv.u = vml->mapzoom_id; break;
585 }
586 return rv;
587}
588
589/****************************************/
590/****** CREATING, COPYING, FREEING ******/
591/****************************************/
592
593static VikMapsLayer *maps_layer_new ( VikViewport *vvp )
594{
595 VikMapsLayer *vml = VIK_MAPS_LAYER ( g_object_new ( VIK_MAPS_LAYER_TYPE, NULL ) );
a0c65899 596 vik_layer_set_type ( VIK_LAYER(vml), VIK_LAYER_MAPS );
a7023a1b
RN
597
598 vik_layer_set_defaults ( VIK_LAYER(vml), vvp );
599
50a14534 600 vml->dl_tool_x = vml->dl_tool_y = -1;
10ca2bfe
QT
601 vml->last_center = NULL;
602 vml->last_xmpp = 0.0;
603 vml->last_ympp = 0.0;
50a14534
EB
604
605 vml->dl_right_click_menu = NULL;
8e507445 606 vml->license_notice_shown = FALSE;
50a14534
EB
607
608 return vml;
609}
610
611static void maps_layer_free ( VikMapsLayer *vml )
612{
e65028db
GB
613 g_free ( vml->cache_dir );
614 vml->cache_dir = NULL;
50a14534 615 if ( vml->dl_right_click_menu )
4f14a010 616 g_object_ref_sink ( G_OBJECT(vml->dl_right_click_menu) );
e65028db
GB
617 g_free(vml->last_center);
618 vml->last_center = NULL;
50a14534
EB
619}
620
07059501 621static void maps_layer_post_read (VikLayer *vl, VikViewport *vp, gboolean from_file)
dc5758d3 622{
07059501
GB
623 if (from_file != TRUE)
624 {
625 /* If this method is not called in file reading context
626 * it is called in GUI context.
627 * So, we can check if we have to inform the user about inconsistency */
628 VikViewportDrawMode vp_drawmode;
629 VikMapsLayer *vml = VIK_MAPS_LAYER(vl);
820c59f4 630 VikMapSource *map = NULL;
dc5758d3 631
405b74ed 632 vp_drawmode = vik_viewport_get_drawmode ( vp );
820c59f4
GB
633 map = MAPS_LAYER_NTH_TYPE(vml->maptype);
634 if (vik_map_source_get_drawmode(map) != vp_drawmode) {
405b74ed 635 const gchar *drawmode_name = vik_viewport_get_drawmode_name (vp, vik_map_source_get_drawmode(map));
4c77d5e0 636 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 637 a_dialog_warning_msg ( VIK_GTK_WINDOW_FROM_WIDGET(vp), msg );
07059501
GB
638 g_free(msg);
639 }
53ac8302
GB
640
641 if (vik_map_source_get_license (map) != NULL) {
8e507445
RN
642 if ( ! vml->license_notice_shown ) {
643 a_dialog_license (VIK_GTK_WINDOW_FROM_WIDGET(vp), vik_map_source_get_label (map),
644 vik_map_source_get_license (map), vik_map_source_get_license_url (map) );
645 vml->license_notice_shown = TRUE;
646 }
53ac8302 647 }
dc5758d3
GB
648 }
649}
650
7924723c
RN
651static const gchar* maps_layer_tooltip ( VikMapsLayer *vml )
652{
653 return vik_maps_layer_get_map_label ( vml );
654}
655
911400b5
AF
656static void maps_layer_marshall( VikMapsLayer *vml, guint8 **data, gint *len )
657{
658 vik_layer_marshall_params ( VIK_LAYER(vml), data, len );
659}
660
661static VikMapsLayer *maps_layer_unmarshall( guint8 *data, gint len, VikViewport *vvp )
662{
663 VikMapsLayer *rv = maps_layer_new ( vvp );
664 vik_layer_unmarshall_params ( VIK_LAYER(rv), data, len, vvp );
665 return rv;
666}
667
50a14534
EB
668/*********************/
669/****** DRAWING ******/
670/*********************/
671
672static GdkPixbuf *pixbuf_set_alpha ( GdkPixbuf *pixbuf, guint8 alpha )
673{
674 guchar *pixels;
675 gint width, height, iii, jjj;
676
677 if ( ! gdk_pixbuf_get_has_alpha ( pixbuf ) )
678 {
679 GdkPixbuf *tmp = gdk_pixbuf_add_alpha(pixbuf,FALSE,0,0,0);
680 g_object_unref(G_OBJECT(pixbuf));
681 pixbuf = tmp;
682 }
683
684 pixels = gdk_pixbuf_get_pixels(pixbuf);
685 width = gdk_pixbuf_get_width(pixbuf);
686 height = gdk_pixbuf_get_height(pixbuf);
687
688 /* r,g,b,a,r,g,b,a.... */
689 for (iii = 0; iii < width; iii++) for (jjj = 0; jjj < height; jjj++)
690 {
691 pixels += 3;
692 *pixels++ = alpha;
693 }
694 return pixbuf;
695}
696
697static GdkPixbuf *pixbuf_shrink ( GdkPixbuf *pixbuf, gdouble xshrinkfactor, gdouble yshrinkfactor )
698{
699 GdkPixbuf *tmp;
700 guint16 width = gdk_pixbuf_get_width(pixbuf), height = gdk_pixbuf_get_height(pixbuf);
2d5d32c1 701 tmp = gdk_pixbuf_scale_simple(pixbuf, ceil(width * xshrinkfactor), ceil(height * yshrinkfactor), GDK_INTERP_BILINEAR);
50a14534
EB
702 g_object_unref ( G_OBJECT(pixbuf) );
703 return tmp;
704}
705
706static GdkPixbuf *get_pixbuf( VikMapsLayer *vml, gint mode, MapCoord *mapcoord, gchar *filename_buf, gint buf_len, gdouble xshrinkfactor, gdouble yshrinkfactor )
707{
708 GdkPixbuf *pixbuf;
709
710 /* get the thing */
711 pixbuf = a_mapcache_get ( mapcoord->x, mapcoord->y, mapcoord->z,
712 mode, mapcoord->scale, vml->alpha, xshrinkfactor, yshrinkfactor );
713
714 if ( ! pixbuf ) {
2673b29d
RN
715 if ( vik_map_source_is_direct_file_access (MAPS_LAYER_NTH_TYPE(vml->maptype)) )
716 g_snprintf ( filename_buf, buf_len, DIRECTDIRACCESS,
717 vml->cache_dir, (17 - mapcoord->scale), mapcoord->x, mapcoord->y, ".png" );
718 else
719 g_snprintf ( filename_buf, buf_len, DIRSTRUCTURE,
720 vml->cache_dir, mode,
721 mapcoord->scale, mapcoord->z, mapcoord->x, mapcoord->y );
722
01ecda7e 723 if ( g_file_test ( filename_buf, G_FILE_TEST_EXISTS ) == TRUE)
50a14534
EB
724 {
725 GError *gx = NULL;
726 pixbuf = gdk_pixbuf_new_from_file ( filename_buf, &gx );
727
01ecda7e 728 /* free the pixbuf on error */
50a14534
EB
729 if (gx)
730 {
731 if ( gx->domain != GDK_PIXBUF_ERROR || gx->code != GDK_PIXBUF_ERROR_CORRUPT_IMAGE )
4c77d5e0 732 g_warning ( _("Couldn't open image file: %s"), gx->message );
50a14534 733
01ecda7e
MR
734 g_error_free ( gx );
735 if ( pixbuf )
736 g_object_unref ( G_OBJECT(pixbuf) );
737 pixbuf = NULL;
738 } else {
50a14534
EB
739 if ( vml->alpha < 255 )
740 pixbuf = pixbuf_set_alpha ( pixbuf, vml->alpha );
741 if ( xshrinkfactor != 1.0 || yshrinkfactor != 1.0 )
742 pixbuf = pixbuf_shrink ( pixbuf, xshrinkfactor, yshrinkfactor );
743
744 a_mapcache_add ( pixbuf, mapcoord->x, mapcoord->y,
820c59f4 745 mapcoord->z, vik_map_source_get_uniq_id(MAPS_LAYER_NTH_TYPE(vml->maptype)),
50a14534 746 mapcoord->scale, vml->alpha, xshrinkfactor, yshrinkfactor );
50a14534
EB
747 }
748 }
749 }
750 return pixbuf;
751}
752
9979924f 753static gboolean should_start_autodownload(VikMapsLayer *vml, VikViewport *vvp)
10ca2bfe
QT
754{
755 const VikCoord *center = vik_viewport_get_center ( vvp );
756
bbf2149b 757 if (vik_window_get_pan_move (VIK_WINDOW(VIK_GTK_WINDOW_FROM_WIDGET(GTK_WIDGET(vvp)))))
01da6b4d 758 /* D'n'D pan in action: do not download */
1c6a6010
GB
759 return FALSE;
760
9979924f
RN
761 // TEMPORARY HACK
762 // Prevent requests for downloading tiles at Zoom Level 19 and above for most map types
763 // Allow MapQuest Zoom Level up to 19
764 // TODO: This should be made a property of the map source and then use that value
765 gdouble xzoom = vik_viewport_get_xmpp ( vvp );
766 if ( (vml->maptype != 19 && map_utils_mpp_to_scale (xzoom) < -1) || (vml->maptype == 19 && map_utils_mpp_to_scale (xzoom) < -2) )
767 return FALSE;
768
10ca2bfe
QT
769 if (vml->last_center == NULL) {
770 VikCoord *new_center = g_malloc(sizeof(VikCoord));
771 *new_center = *center;
772 vml->last_center = new_center;
773 vml->last_xmpp = vik_viewport_get_xmpp(vvp);
774 vml->last_ympp = vik_viewport_get_ympp(vvp);
775 return TRUE;
776 }
777
778 /* TODO: perhaps vik_coord_diff() */
779 if (vik_coord_equals(vml->last_center, center)
780 && (vml->last_xmpp == vik_viewport_get_xmpp(vvp))
781 && (vml->last_ympp == vik_viewport_get_ympp(vvp)))
782 return FALSE;
783
784 *(vml->last_center) = *center;
785 vml->last_xmpp = vik_viewport_get_xmpp(vvp);
786 vml->last_ympp = vik_viewport_get_ympp(vvp);
787 return TRUE;
788}
789
50a14534
EB
790static void maps_layer_draw_section ( VikMapsLayer *vml, VikViewport *vvp, VikCoord *ul, VikCoord *br )
791{
792 MapCoord ulm, brm;
793 gdouble xzoom = vik_viewport_get_xmpp ( vvp );
794 gdouble yzoom = vik_viewport_get_ympp ( vvp );
795 gdouble xshrinkfactor = 1.0, yshrinkfactor = 1.0;
2673b29d 796 gboolean existence_only = FALSE;
50a14534
EB
797
798 if ( vml->xmapzoom && (vml->xmapzoom != xzoom || vml->ymapzoom != yzoom) ) {
799 xshrinkfactor = vml->xmapzoom / xzoom;
800 yshrinkfactor = vml->ymapzoom / yzoom;
732d1e25
EB
801 xzoom = vml->xmapzoom;
802 yzoom = vml->xmapzoom;
803 if ( ! (xshrinkfactor > MIN_SHRINKFACTOR && xshrinkfactor < MAX_SHRINKFACTOR &&
804 yshrinkfactor > MIN_SHRINKFACTOR && yshrinkfactor < MAX_SHRINKFACTOR ) ) {
6de95419
RN
805 if ( xshrinkfactor > REAL_MIN_SHRINKFACTOR && yshrinkfactor > REAL_MIN_SHRINKFACTOR ) {
806 g_debug ( "%s: existence_only due to SHRINKFACTORS", __FUNCTION__ );
732d1e25 807 existence_only = TRUE;
6de95419 808 }
732d1e25 809 else {
4c77d5e0 810 g_warning ( _("Cowardly refusing to draw tiles or existence of tiles beyond %d zoom out factor"), (int)( 1.0/REAL_MIN_SHRINKFACTOR));
732d1e25
EB
811 return;
812 }
50a14534
EB
813 }
814 }
815
816 /* coord -> ID */
820c59f4
GB
817 VikMapSource *map = MAPS_LAYER_NTH_TYPE(vml->maptype);
818 if ( vik_map_source_coord_to_mapcoord ( map, ul, xzoom, yzoom, &ulm ) &&
819 vik_map_source_coord_to_mapcoord ( map, br, xzoom, yzoom, &brm ) ) {
50a14534
EB
820
821 /* loop & draw */
822 gint x, y;
823 gint xmin = MIN(ulm.x, brm.x), xmax = MAX(ulm.x, brm.x);
824 gint ymin = MIN(ulm.y, brm.y), ymax = MAX(ulm.y, brm.y);
820c59f4 825 gint mode = vik_map_source_get_uniq_id(map);
50a14534
EB
826
827 VikCoord coord;
828 gint xx, yy, width, height;
829 GdkPixbuf *pixbuf;
830
6de95419
RN
831 // Prevent the program grinding to a halt if trying to deal with thousands of tiles
832 // which can happen when using a small fixed zoom level and viewing large areas.
833 // Also prevents very large number of tile download requests
834 gint tiles = (xmax-xmin) * (ymax-ymin);
835 if ( tiles > MAX_TILES ) {
836 g_debug ( "%s: existence_only due to wanting too many tiles (%d)", __FUNCTION__, tiles );
837 existence_only = TRUE;
838 }
839
50a14534
EB
840 guint max_path_len = strlen(vml->cache_dir) + 40;
841 gchar *path_buf = g_malloc ( max_path_len * sizeof(char) );
842
732d1e25 843 if ( (!existence_only) && vml->autodownload && should_start_autodownload(vml, vvp)) {
33be396e 844 g_debug("%s: Starting autodownload", __FUNCTION__);
382566c3 845 if ( !vml->adl_only_missing && vik_map_source_supports_download_only_new (map) )
245f48f5
GB
846 // Try to download newer tiles
847 start_download_thread ( vml, vvp, ul, br, REDOWNLOAD_NEW );
848 else
849 // Download only missing tiles
850 start_download_thread ( vml, vvp, ul, br, REDOWNLOAD_NONE );
10ca2bfe 851 }
50a14534 852
820c59f4 853 if ( vik_map_source_get_tilesize_x(map) == 0 && !existence_only ) {
50a14534
EB
854 for ( x = xmin; x <= xmax; x++ ) {
855 for ( y = ymin; y <= ymax; y++ ) {
856 ulm.x = x;
857 ulm.y = y;
858 pixbuf = get_pixbuf ( vml, mode, &ulm, path_buf, max_path_len, xshrinkfactor, yshrinkfactor );
859 if ( pixbuf ) {
860 width = gdk_pixbuf_get_width ( pixbuf );
861 height = gdk_pixbuf_get_height ( pixbuf );
862
820c59f4 863 vik_map_source_mapcoord_to_center_coord ( map, &ulm, &coord );
50a14534
EB
864 vik_viewport_coord_to_screen ( vvp, &coord, &xx, &yy );
865 xx -= (width/2);
866 yy -= (height/2);
867
868 vik_viewport_draw_pixbuf ( vvp, pixbuf, 0, 0, xx, yy, width, height );
869 }
870 }
871 }
872 } else { /* tilesize is known, don't have to keep converting coords */
820c59f4
GB
873 gdouble tilesize_x = vik_map_source_get_tilesize_x(map) * xshrinkfactor;
874 gdouble tilesize_y = vik_map_source_get_tilesize_y(map) * yshrinkfactor;
50a14534
EB
875 /* ceiled so tiles will be maximum size in the case of funky shrinkfactor */
876 gint tilesize_x_ceil = ceil ( tilesize_x );
877 gint tilesize_y_ceil = ceil ( tilesize_y );
878 gint8 xinc = (ulm.x == xmin) ? 1 : -1;
879 gint8 yinc = (ulm.y == ymin) ? 1 : -1;
880 gdouble xx, yy; gint xx_tmp, yy_tmp;
881 gint base_yy, xend, yend;
732d1e25 882
50a14534
EB
883 xend = (xinc == 1) ? (xmax+1) : (xmin-1);
884 yend = (yinc == 1) ? (ymax+1) : (ymin-1);
885
820c59f4 886 vik_map_source_mapcoord_to_center_coord ( map, &ulm, &coord );
50a14534
EB
887 vik_viewport_coord_to_screen ( vvp, &coord, &xx_tmp, &yy_tmp );
888 xx = xx_tmp; yy = yy_tmp;
889 /* above trick so xx,yy doubles. this is so shrinkfactors aren't rounded off
890 * eg if tile size 128, shrinkfactor 0.333 */
891 xx -= (tilesize_x/2);
892 base_yy = yy - (tilesize_y/2);
893
894 for ( x = ((xinc == 1) ? xmin : xmax); x != xend; x+=xinc ) {
895 yy = base_yy;
896 for ( y = ((yinc == 1) ? ymin : ymax); y != yend; y+=yinc ) {
897 ulm.x = x;
898 ulm.y = y;
732d1e25
EB
899
900 if ( existence_only ) {
2673b29d
RN
901 if ( vik_map_source_is_direct_file_access (MAPS_LAYER_NTH_TYPE(vml->maptype)) )
902 g_snprintf ( path_buf, max_path_len, DIRECTDIRACCESS,
903 vml->cache_dir, (17 - ulm.scale), ulm.x, ulm.y, ".png" );
904 else
905 g_snprintf ( path_buf, max_path_len, DIRSTRUCTURE,
906 vml->cache_dir, mode,
907 ulm.scale, ulm.z, ulm.x, ulm.y );
45acf79e 908 if ( g_file_test ( path_buf, G_FILE_TEST_EXISTS ) == TRUE ) {
ff37db21 909 GdkGC *black_gc = gtk_widget_get_style(GTK_WIDGET(vvp))->black_gc;
732d1e25
EB
910 vik_viewport_draw_line ( vvp, black_gc, xx+tilesize_x_ceil, yy, xx, yy+tilesize_y_ceil );
911 }
912 } else {
6f0d1bea
JJ
913 int scale_inc;
914 for (scale_inc = 0; scale_inc < 4; scale_inc ++) {
915 /* try with correct then smaller zooms */
916 int scale_factor = 1 << scale_inc; /* 2^scale_inc */
917 MapCoord ulm2 = ulm;
918 ulm2.x = ulm.x / scale_factor;
919 ulm2.y = ulm.y / scale_factor;
920 ulm2.scale = ulm.scale + scale_inc;
921 pixbuf = get_pixbuf ( vml, mode, &ulm2, path_buf, max_path_len, xshrinkfactor * scale_factor, yshrinkfactor * scale_factor );
922 if ( pixbuf ) {
923 gint src_x = (ulm.x % scale_factor) * tilesize_x_ceil;
924 gint src_y = (ulm.y % scale_factor) * tilesize_y_ceil;
40cfc175
JJ
925#ifdef DEBUG
926 printf("maps_layer_draw_section - x=%d, y=%d, z=%d, src_x=%d, src_y=%d, xx=%d, yy=%d - %x\n", ulm.x, ulm.y, ulm.scale, src_x, src_y, (int)xx, (int)yy, vvp);
927#endif
6f0d1bea
JJ
928 vik_viewport_draw_pixbuf ( vvp, pixbuf, src_x, src_y, xx, yy, tilesize_x_ceil, tilesize_y_ceil );
929 break;
930 }
931 }
932 if ( !pixbuf ) {
933 /* retry with bigger zooms */
934 int scale_dec;
935 for (scale_dec = 1; scale_dec < 2; scale_dec ++) {
936 int pict_x, pict_y;
937 int scale_factor = 1 << scale_dec; /* 2^scale_dec */
91dc4449 938 MapCoord ulm2 = ulm;
6f0d1bea
JJ
939 ulm2.x = ulm.x * scale_factor;
940 ulm2.y = ulm.y * scale_factor;
941 ulm2.scale = ulm.scale - scale_dec;
942 for (pict_x = 0; pict_x < scale_factor; pict_x ++) {
943 for (pict_y = 0; pict_y < scale_factor; pict_y ++) {
944 MapCoord ulm3 = ulm2;
945 ulm3.x += pict_x;
946 ulm3.y += pict_y;
947 pixbuf = get_pixbuf ( vml, mode, &ulm3, path_buf, max_path_len, xshrinkfactor / scale_factor, yshrinkfactor / scale_factor );
948 if ( pixbuf ) {
949 gint src_x = 0;
950 gint src_y = 0;
951 gint dest_x = xx + pict_x * (tilesize_x_ceil / scale_factor);
952 gint dest_y = yy + pict_y * (tilesize_y_ceil / scale_factor);
953 vik_viewport_draw_pixbuf ( vvp, pixbuf, src_x, src_y, dest_x, dest_y, tilesize_x_ceil / scale_factor, tilesize_y_ceil / scale_factor );
954 }
955 }
91dc4449
JJ
956 }
957 }
958 }
732d1e25 959 }
50a14534
EB
960
961 yy += tilesize_y;
962 }
963 xx += tilesize_x;
964 }
965 }
966
967 g_free ( path_buf );
968 }
969}
970
971static void maps_layer_draw ( VikMapsLayer *vml, VikViewport *vvp )
972{
820c59f4 973 if ( vik_map_source_get_drawmode(MAPS_LAYER_NTH_TYPE(vml->maptype)) == vik_viewport_get_drawmode ( vvp ) )
50a14534
EB
974 {
975 VikCoord ul, br;
976
82aa018d 977 /* Copyright */
68b1d6c0
GB
978 gdouble level = vik_viewport_get_zoom ( vvp );
979 LatLonBBox bbox;
980 vik_viewport_get_min_max_lat_lon ( vvp, &bbox.south, &bbox.north, &bbox.west, &bbox.east );
981 vik_map_source_get_copyright ( MAPS_LAYER_NTH_TYPE(vml->maptype), bbox, level, vik_viewport_add_copyright, vvp );
82aa018d 982
26336cf0
GB
983 /* Logo */
984 const GdkPixbuf *logo = vik_map_source_get_logo ( MAPS_LAYER_NTH_TYPE(vml->maptype) );
985 vik_viewport_add_logo ( vvp, logo );
986
50a14534
EB
987 /* get corner coords */
988 if ( vik_viewport_get_coord_mode ( vvp ) == VIK_COORD_UTM && ! vik_viewport_is_one_zone ( vvp ) ) {
989 /* UTM multi-zone stuff by Kit Transue */
990 gchar leftmost_zone, rightmost_zone, i;
991 leftmost_zone = vik_viewport_leftmost_zone( vvp );
992 rightmost_zone = vik_viewport_rightmost_zone( vvp );
993 for ( i = leftmost_zone; i <= rightmost_zone; ++i ) {
994 vik_viewport_corners_for_zonen ( vvp, i, &ul, &br );
995 maps_layer_draw_section ( vml, vvp, &ul, &br );
996 }
997 }
998 else {
999 vik_viewport_screen_to_coord ( vvp, 0, 0, &ul );
1000 vik_viewport_screen_to_coord ( vvp, vik_viewport_get_width(vvp), vik_viewport_get_height(vvp), &br );
1001
1002 maps_layer_draw_section ( vml, vvp, &ul, &br );
1003 }
1004 }
1005}
1006
1007/*************************/
1008/****** DOWNLOADING ******/
1009/*************************/
1010
1011/* pass along data to thread, exists even if layer is deleted. */
1012typedef struct {
1013 gchar *cache_dir;
1014 gchar *filename_buf;
1015 gint x0, y0, xf, yf;
1016 MapCoord mapcoord;
1017 gint maptype;
1018 gint maxlen;
1019 gint mapstoget;
1020 gint redownload;
7114e879 1021 gboolean refresh_display;
550fd035
QT
1022 VikMapsLayer *vml;
1023 VikViewport *vvp;
1024 gboolean map_layer_alive;
1025 GMutex *mutex;
50a14534
EB
1026} MapDownloadInfo;
1027
1028static void mdi_free ( MapDownloadInfo *mdi )
1029{
550fd035 1030 g_mutex_free(mdi->mutex);
50a14534 1031 g_free ( mdi->cache_dir );
e65028db 1032 mdi->cache_dir = NULL;
50a14534 1033 g_free ( mdi->filename_buf );
e65028db 1034 mdi->filename_buf = NULL;
50a14534
EB
1035 g_free ( mdi );
1036}
1037
7bb60307 1038static void weak_ref_cb(gpointer ptr, GObject * dead_vml)
550fd035 1039{
7bb60307 1040 MapDownloadInfo *mdi = ptr;
550fd035
QT
1041 g_mutex_lock(mdi->mutex);
1042 mdi->map_layer_alive = FALSE;
1043 g_mutex_unlock(mdi->mutex);
1044}
1045
634eca0a 1046static int map_download_thread ( MapDownloadInfo *mdi, gpointer threaddata )
50a14534 1047{
825413ba 1048 void *handle = vik_map_source_download_handle_init(MAPS_LAYER_NTH_TYPE(mdi->maptype));
50a14534
EB
1049 guint donemaps = 0;
1050 gint x, y;
1051 for ( x = mdi->x0; x <= mdi->xf; x++ )
1052 {
1053 for ( y = mdi->y0; y <= mdi->yf; y++ )
1054 {
94493114 1055 gboolean remove_mem_cache = FALSE;
84628352 1056 gboolean need_download = FALSE;
50a14534 1057 g_snprintf ( mdi->filename_buf, mdi->maxlen, DIRSTRUCTURE,
820c59f4 1058 mdi->cache_dir, vik_map_source_get_uniq_id(MAPS_LAYER_NTH_TYPE(mdi->maptype)),
50a14534
EB
1059 mdi->mapcoord.scale, mdi->mapcoord.z, x, y );
1060
84628352 1061 donemaps++;
634eca0a 1062 int res = a_background_thread_progress ( threaddata, ((gdouble)donemaps) / mdi->mapstoget ); /* this also calls testcancel */
825413ba
SW
1063 if (res != 0) {
1064 vik_map_source_download_handle_cleanup(MAPS_LAYER_NTH_TYPE(mdi->maptype), handle);
634eca0a 1065 return -1;
825413ba 1066 }
84628352 1067
a0058e48 1068 if ( g_file_test ( mdi->filename_buf, G_FILE_TEST_EXISTS ) == FALSE ) {
6a4a29aa
JJ
1069 need_download = TRUE;
1070 remove_mem_cache = TRUE;
a0058e48
JJ
1071
1072 } else { /* in case map file already exists */
1073 switch (mdi->redownload) {
1074 case REDOWNLOAD_NONE:
1075 continue;
1076
1077 case REDOWNLOAD_BAD:
1078 {
1079 /* see if this one is bad or what */
1080 GError *gx = NULL;
1081 GdkPixbuf *pixbuf = gdk_pixbuf_new_from_file ( mdi->filename_buf, &gx );
1082 if (gx || (!pixbuf)) {
1083 g_remove ( mdi->filename_buf );
1084 need_download = TRUE;
1085 remove_mem_cache = TRUE;
1086 g_error_free ( gx );
1087
1088 } else {
1089 g_object_unref ( pixbuf );
1090 }
1091 break;
1092 }
1093
1094 case REDOWNLOAD_NEW:
1095 need_download = TRUE;
1096 remove_mem_cache = TRUE;
1097 break;
1098
1099 case REDOWNLOAD_ALL:
1100 /* FIXME: need a better way than to erase file in case of server/network problem */
1101 g_remove ( mdi->filename_buf );
1102 need_download = TRUE;
1103 remove_mem_cache = TRUE;
1104 break;
1105
1106 case DOWNLOAD_OR_REFRESH:
1107 remove_mem_cache = TRUE;
1108 break;
1109
1110 default:
1111 g_warning ( "redownload state %d unknown\n", mdi->redownload);
1112 }
1113 }
94493114 1114
94493114 1115 mdi->mapcoord.x = x; mdi->mapcoord.y = y;
84628352
QT
1116
1117 if (need_download) {
825413ba 1118 if ( vik_map_source_download( MAPS_LAYER_NTH_TYPE(mdi->maptype), &(mdi->mapcoord), mdi->filename_buf, handle))
94493114 1119 continue;
84628352 1120 }
94493114 1121
94493114
QT
1122 g_mutex_lock(mdi->mutex);
1123 if (remove_mem_cache)
820c59f4 1124 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 );
7114e879 1125 if (mdi->refresh_display && mdi->map_layer_alive) {
94493114 1126 /* TODO: check if it's on visible area */
da121f9b 1127 vik_layer_emit_update ( VIK_LAYER(mdi->vml) ); // NB update display from background
a0b59f2f 1128 }
94493114 1129 g_mutex_unlock(mdi->mutex);
94493114
QT
1130 mdi->mapcoord.x = mdi->mapcoord.y = 0; /* we're temporarily between downloads */
1131
50a14534
EB
1132 }
1133 }
825413ba 1134 vik_map_source_download_handle_cleanup(MAPS_LAYER_NTH_TYPE(mdi->maptype), handle);
04e54492
QT
1135 g_mutex_lock(mdi->mutex);
1136 if (mdi->map_layer_alive)
7bb60307 1137 g_object_weak_unref(G_OBJECT(mdi->vml), weak_ref_cb, mdi);
04e54492 1138 g_mutex_unlock(mdi->mutex);
634eca0a 1139 return 0;
50a14534
EB
1140}
1141
1142static void mdi_cancel_cleanup ( MapDownloadInfo *mdi )
1143{
1144 if ( mdi->mapcoord.x || mdi->mapcoord.y )
1145 {
1146 g_snprintf ( mdi->filename_buf, mdi->maxlen, DIRSTRUCTURE,
820c59f4 1147 mdi->cache_dir, vik_map_source_get_uniq_id(MAPS_LAYER_NTH_TYPE(mdi->maptype)),
50a14534 1148 mdi->mapcoord.scale, mdi->mapcoord.z, mdi->mapcoord.x, mdi->mapcoord.y );
45acf79e 1149 if ( g_file_test ( mdi->filename_buf, G_FILE_TEST_EXISTS ) == TRUE)
50a14534 1150 {
8c060406 1151 g_remove ( mdi->filename_buf );
50a14534
EB
1152 }
1153 }
1154}
1155
1156static void start_download_thread ( VikMapsLayer *vml, VikViewport *vvp, const VikCoord *ul, const VikCoord *br, gint redownload )
1157{
1158 gdouble xzoom = vml->xmapzoom ? vml->xmapzoom : vik_viewport_get_xmpp ( vvp );
1159 gdouble yzoom = vml->ymapzoom ? vml->ymapzoom : vik_viewport_get_ympp ( vvp );
1160 MapCoord ulm, brm;
820c59f4 1161 VikMapSource *map = MAPS_LAYER_NTH_TYPE(vml->maptype);
2673b29d
RN
1162
1163 // Don't ever attempt download on direct access
1164 if ( vik_map_source_is_direct_file_access ( map ) )
1165 return;
1166
820c59f4
GB
1167 if ( vik_map_source_coord_to_mapcoord ( map, ul, xzoom, yzoom, &ulm )
1168 && vik_map_source_coord_to_mapcoord ( map, br, xzoom, yzoom, &brm ) )
50a14534
EB
1169 {
1170 MapDownloadInfo *mdi = g_malloc ( sizeof(MapDownloadInfo) );
1171 gint a, b;
1172
550fd035
QT
1173 mdi->vml = vml;
1174 mdi->vvp = vvp;
1175 mdi->map_layer_alive = TRUE;
1176 mdi->mutex = g_mutex_new();
7114e879 1177 mdi->refresh_display = TRUE;
550fd035 1178
50a14534
EB
1179 /* cache_dir and buffer for dest filename */
1180 mdi->cache_dir = g_strdup ( vml->cache_dir );
1181 mdi->maxlen = strlen ( vml->cache_dir ) + 40;
1182 mdi->filename_buf = g_malloc ( mdi->maxlen * sizeof(gchar) );
1183 mdi->maptype = vml->maptype;
1184
1185 mdi->mapcoord = ulm;
50a14534
EB
1186 mdi->redownload = redownload;
1187
1188 mdi->x0 = MIN(ulm.x, brm.x);
1189 mdi->xf = MAX(ulm.x, brm.x);
1190 mdi->y0 = MIN(ulm.y, brm.y);
1191 mdi->yf = MAX(ulm.y, brm.y);
1192
1193 mdi->mapstoget = 0;
1194
1195 if ( mdi->redownload ) {
1196 mdi->mapstoget = (mdi->xf - mdi->x0 + 1) * (mdi->yf - mdi->y0 + 1);
1197 } else {
1198 /* calculate how many we need */
1199 for ( a = mdi->x0; a <= mdi->xf; a++ )
1200 {
1201 for ( b = mdi->y0; b <= mdi->yf; b++ )
1202 {
1203 g_snprintf ( mdi->filename_buf, mdi->maxlen, DIRSTRUCTURE,
820c59f4 1204 vml->cache_dir, vik_map_source_get_uniq_id(map), ulm.scale,
50a14534 1205 ulm.z, a, b );
45acf79e 1206 if ( g_file_test ( mdi->filename_buf, G_FILE_TEST_EXISTS ) == FALSE )
50a14534
EB
1207 mdi->mapstoget++;
1208 }
1209 }
1210 }
1211
1212 mdi->mapcoord.x = mdi->mapcoord.y = 0; /* for cleanup -- no current map */
1213
1214 if ( mdi->mapstoget )
1215 {
97634600
GB
1216 const gchar *tmp_str;
1217 gchar *tmp;
50a14534 1218
97634600
GB
1219 if (redownload)
1220 {
1221 if (redownload == REDOWNLOAD_BAD)
1222 tmp_str = ngettext("Redownloading up to %d %s map...", "Redownloading up to %d %s maps...", mdi->mapstoget);
1223 else
1224 tmp_str = ngettext("Redownloading %d %s map...", "Redownloading %d %s maps...", mdi->mapstoget);
1225 }
1226 else
1227 {
1228 tmp_str = ngettext("Downloading %d %s map...", "Downloading %d %s maps...", mdi->mapstoget);
1229 }
1230 tmp = g_strdup_printf ( tmp_str, mdi->mapstoget, MAPS_LAYER_NTH_LABEL(vml->maptype));
1231
7bb60307 1232 g_object_weak_ref(G_OBJECT(mdi->vml), weak_ref_cb, mdi);
50a14534
EB
1233 /* launch the thread */
1234 a_background_thread ( VIK_GTK_WINDOW_FROM_LAYER(vml), /* parent window */
1235 tmp, /* description string */
1236 (vik_thr_func) map_download_thread, /* function to call within thread */
1237 mdi, /* pass along data */
1238 (vik_thr_free_func) mdi_free, /* function to free pass along data */
1239 (vik_thr_free_func) mdi_cancel_cleanup,
1240 mdi->mapstoget );
1241 g_free ( tmp );
1242 }
1243 else
1244 mdi_free ( mdi );
1245 }
1246}
1247
3ac548fa 1248static void maps_layer_download_section ( VikMapsLayer *vml, VikViewport *vvp, VikCoord *ul, VikCoord *br, gdouble zoom, gint download_method )
7114e879 1249{
7114e879 1250 MapCoord ulm, brm;
820c59f4 1251 VikMapSource *map = MAPS_LAYER_NTH_TYPE(vml->maptype);
7114e879 1252
2673b29d
RN
1253 // Don't ever attempt download on direct access
1254 if ( vik_map_source_is_direct_file_access ( map ) )
1255 return;
1256
820c59f4
GB
1257 if (!vik_map_source_coord_to_mapcoord(map, ul, zoom, zoom, &ulm)
1258 || !vik_map_source_coord_to_mapcoord(map, br, zoom, zoom, &brm)) {
4258f4e2 1259 g_warning("%s() coord_to_mapcoord() failed", __PRETTY_FUNCTION__);
7114e879
QT
1260 return;
1261 }
1262
1263 MapDownloadInfo *mdi = g_malloc(sizeof(MapDownloadInfo));
1264 gint i, j;
1265
1266 mdi->vml = vml;
1267 mdi->vvp = vvp;
1268 mdi->map_layer_alive = TRUE;
1269 mdi->mutex = g_mutex_new();
903dc0b4 1270 mdi->refresh_display = TRUE;
7114e879
QT
1271
1272 mdi->cache_dir = g_strdup ( vml->cache_dir );
1273 mdi->maxlen = strlen ( vml->cache_dir ) + 40;
1274 mdi->filename_buf = g_malloc ( mdi->maxlen * sizeof(gchar) );
1275 mdi->maptype = vml->maptype;
1276
1277 mdi->mapcoord = ulm;
3ac548fa 1278 mdi->redownload = download_method;
7114e879
QT
1279
1280 mdi->x0 = MIN(ulm.x, brm.x);
1281 mdi->xf = MAX(ulm.x, brm.x);
1282 mdi->y0 = MIN(ulm.y, brm.y);
1283 mdi->yf = MAX(ulm.y, brm.y);
1284
1285 mdi->mapstoget = 0;
1286
1287 for (i = mdi->x0; i <= mdi->xf; i++) {
1288 for (j = mdi->y0; j <= mdi->yf; j++) {
1289 g_snprintf ( mdi->filename_buf, mdi->maxlen, DIRSTRUCTURE,
820c59f4 1290 vml->cache_dir, vik_map_source_get_uniq_id(map), ulm.scale,
7114e879 1291 ulm.z, i, j );
45acf79e 1292 if ( g_file_test ( mdi->filename_buf, G_FILE_TEST_EXISTS ) == FALSE )
7114e879
QT
1293 mdi->mapstoget++;
1294 }
1295 }
1296
1297 mdi->mapcoord.x = mdi->mapcoord.y = 0; /* for cleanup -- no current map */
1298
1299 if (mdi->mapstoget) {
4c77d5e0
GB
1300 gchar *tmp;
1301 const gchar *fmt;
eb6b0125
JJ
1302 fmt = ngettext("Downloading %d %s map...",
1303 "Downloading %d %s maps...",
1304 mdi->mapstoget);
4c77d5e0 1305 tmp = g_strdup_printf ( fmt, mdi->mapstoget, MAPS_LAYER_NTH_LABEL(vml->maptype) );
7114e879
QT
1306
1307 g_object_weak_ref(G_OBJECT(mdi->vml), weak_ref_cb, mdi);
1308 /* launch the thread */
1309 a_background_thread ( VIK_GTK_WINDOW_FROM_LAYER(vml), /* parent window */
1310 tmp, /* description string */
1311 (vik_thr_func) map_download_thread, /* function to call within thread */
1312 mdi, /* pass along data */
1313 (vik_thr_free_func) mdi_free, /* function to free pass along data */
1314 (vik_thr_free_func) mdi_cancel_cleanup,
1315 mdi->mapstoget );
1316 g_free ( tmp );
1317 }
1318 else
1319 mdi_free ( mdi );
1320}
1321
3ac548fa
RN
1322/**
1323 * vik_maps_layer_download_section:
1324 * @vml: The Map Layer
1325 * @vvp: The Viewport that the map is on
1326 * @ul: Upper left coordinate of the area to be downloaded
1327 * @br: Bottom right coordinate of the area to be downloaded
1328 * @zoom: The zoom level at which the maps are to be download
1329 *
1330 * Download a specified map area at a certain zoom level
1331 */
1332void vik_maps_layer_download_section ( VikMapsLayer *vml, VikViewport *vvp, VikCoord *ul, VikCoord *br, gdouble zoom )
1333{
1334 maps_layer_download_section (vml, vvp, ul, br, zoom, REDOWNLOAD_NONE);
1335}
1336
50a14534
EB
1337static void maps_layer_redownload_bad ( VikMapsLayer *vml )
1338{
1339 start_download_thread ( vml, vml->redownload_vvp, &(vml->redownload_ul), &(vml->redownload_br), REDOWNLOAD_BAD );
1340}
a7c1acf1 1341
50a14534
EB
1342static void maps_layer_redownload_all ( VikMapsLayer *vml )
1343{
1344 start_download_thread ( vml, vml->redownload_vvp, &(vml->redownload_ul), &(vml->redownload_br), REDOWNLOAD_ALL );
1345}
1346
a7c1acf1
GB
1347static void maps_layer_redownload_new ( VikMapsLayer *vml )
1348{
1349 start_download_thread ( vml, vml->redownload_vvp, &(vml->redownload_ul), &(vml->redownload_br), REDOWNLOAD_NEW );
1350}
1351
450d8665
RN
1352/**
1353 * Display a simple dialog with information about this particular map tile
1354 */
1355static void maps_layer_tile_info ( VikMapsLayer *vml )
1356{
1357 VikMapSource *map = MAPS_LAYER_NTH_TYPE(vml->maptype);
1358
1359 gdouble xzoom = vml->xmapzoom ? vml->xmapzoom : vik_viewport_get_xmpp ( vml->redownload_vvp );
1360 gdouble yzoom = vml->ymapzoom ? vml->ymapzoom : vik_viewport_get_ympp ( vml->redownload_vvp );
1361 MapCoord ulm;
1362
1363 if ( !vik_map_source_coord_to_mapcoord ( map, &(vml->redownload_ul), xzoom, yzoom, &ulm ) )
1364 return;
1365
1366 gchar *filename = NULL;
1367 gchar *message = NULL;
1368 gchar *source = NULL;
1369
1370 if ( vik_map_source_is_direct_file_access ( map ) ) {
1371 filename = g_strdup_printf ( DIRECTDIRACCESS, vml->cache_dir, ulm.scale, ulm.x, ulm.y, ".png" );
1372 source = g_strconcat ( "file://", filename, NULL );
1373 }
1374 else {
1375 filename = g_strdup_printf ( DIRSTRUCTURE, vml->cache_dir, vik_map_source_get_uniq_id(map), ulm.scale, ulm.z, ulm.x, ulm.y );
1376 source = g_strdup_printf ( "http://%s%s",
1377 vik_map_source_default_get_hostname ( VIK_MAP_SOURCE_DEFAULT(map) ),
1378 vik_map_source_default_get_uri ( VIK_MAP_SOURCE_DEFAULT(map), &ulm ) );
1379 }
1380
1381 if ( g_file_test ( filename, G_FILE_TEST_EXISTS ) ) {
1382
1383 // Get some timestamp information of the tile
1384 struct stat stat_buf;
1385 if ( g_stat ( filename, &stat_buf ) == 0 ) {
6be843d5
RN
1386 gchar time_buf[64];
1387 strftime ( time_buf, sizeof(time_buf), "%c", gmtime((const time_t *)&stat_buf.st_mtime) );
1388 message = g_strdup_printf ( _("\nSource: %s\n\nTile File: %s\nTile File Timestamp: %s"), source, filename, time_buf );
450d8665
RN
1389 }
1390 }
1391 else
1392 message = g_strdup_printf ( _("Source: %s\n\nNo Tile File!"), source );
1393
1394 // Show the info
1395 a_dialog_info_msg ( VIK_GTK_WINDOW_FROM_LAYER(vml), message );
1396
1397 g_free ( message );
1398 g_free ( source );
1399 g_free ( filename );
1400}
1401
50a14534
EB
1402static gboolean maps_layer_download_release ( VikMapsLayer *vml, GdkEventButton *event, VikViewport *vvp )
1403{
941aa6e9
AF
1404 if (!vml || vml->vl.type != VIK_LAYER_MAPS)
1405 return FALSE;
50a14534
EB
1406 if ( vml->dl_tool_x != -1 && vml->dl_tool_y != -1 )
1407 {
1408 if ( event->button == 1 )
1409 {
1410 VikCoord ul, br;
1411 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 );
1412 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 1413 start_download_thread ( vml, vvp, &ul, &br, DOWNLOAD_OR_REFRESH );
50a14534
EB
1414 vml->dl_tool_x = vml->dl_tool_y = -1;
1415 return TRUE;
1416 }
1417 else
1418 {
1419 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) );
1420 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) );
1421
1422 vml->redownload_vvp = vvp;
1423
1424 vml->dl_tool_x = vml->dl_tool_y = -1;
1425
1426 if ( ! vml->dl_right_click_menu ) {
1427 GtkWidget *item;
1428 vml->dl_right_click_menu = GTK_MENU ( gtk_menu_new () );
1429
94ee2264 1430 item = gtk_menu_item_new_with_mnemonic ( _("Redownload _Bad Map(s)") );
50a14534
EB
1431 g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(maps_layer_redownload_bad), vml );
1432 gtk_menu_shell_append ( GTK_MENU_SHELL(vml->dl_right_click_menu), item );
1433
94ee2264 1434 item = gtk_menu_item_new_with_mnemonic ( _("Redownload _New Map(s)") );
a7c1acf1
GB
1435 g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(maps_layer_redownload_new), vml );
1436 gtk_menu_shell_append ( GTK_MENU_SHELL(vml->dl_right_click_menu), item );
1437
94ee2264 1438 item = gtk_menu_item_new_with_mnemonic ( _("Redownload _All Map(s)") );
50a14534
EB
1439 g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(maps_layer_redownload_all), vml );
1440 gtk_menu_shell_append ( GTK_MENU_SHELL(vml->dl_right_click_menu), item );
450d8665
RN
1441
1442 item = gtk_image_menu_item_new_with_mnemonic ( _("_Show Tile Information") );
1443 gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_INFO, GTK_ICON_SIZE_MENU) );
1444 g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(maps_layer_tile_info), vml );
1445 gtk_menu_shell_append (GTK_MENU_SHELL(vml->dl_right_click_menu), item);
50a14534
EB
1446 }
1447
1448 gtk_menu_popup ( vml->dl_right_click_menu, NULL, NULL, NULL, NULL, event->button, event->time );
1449 gtk_widget_show_all ( GTK_WIDGET(vml->dl_right_click_menu) );
1450 }
1451 }
1452 return FALSE;
1453}
1454
941aa6e9
AF
1455static gpointer maps_layer_download_create ( VikWindow *vw, VikViewport *vvp)
1456{
1457 return vvp;
1458}
1459
50a14534
EB
1460static gboolean maps_layer_download_click ( VikMapsLayer *vml, GdkEventButton *event, VikViewport *vvp )
1461{
1462 MapCoord tmp;
941aa6e9
AF
1463 if (!vml || vml->vl.type != VIK_LAYER_MAPS)
1464 return FALSE;
820c59f4
GB
1465 VikMapSource *map = MAPS_LAYER_NTH_TYPE(vml->maptype);
1466 if ( vik_map_source_get_drawmode(map) == vik_viewport_get_drawmode ( vvp ) &&
1467 vik_map_source_coord_to_mapcoord ( map, vik_viewport_get_center ( vvp ),
50a14534
EB
1468 vml->xmapzoom ? vml->xmapzoom : vik_viewport_get_xmpp ( vvp ),
1469 vml->ymapzoom ? vml->ymapzoom : vik_viewport_get_ympp ( vvp ),
1470 &tmp ) ) {
1471 vml->dl_tool_x = event->x, vml->dl_tool_y = event->y;
1472 return TRUE;
1473 }
1474 return FALSE;
1475
1476
1477#if 0
1478 if ( __map_types[vml->maptype].drawmode == vik_viewport_get_drawmode ( vvp ) )
1479 {
1480 VikCoord coord;
1481 MapCoord mapcoord;
1482 vik_viewport_screen_to_coord ( vvp, event->x, event->y, &coord );
1483 if ( __map_types[vml->maptype].coord_to_mapcoord ( &coord,
1484 vml->xmapzoom ? vml->xmapzoom : vik_viewport_get_xmpp ( vvp ),
1485 vml->ymapzoom ? vml->ymapzoom : vik_viewport_get_ympp ( vvp ),
1486 &mapcoord ) ) {
1487 gchar *filename_buf = g_strdup_printf ( DIRSTRUCTURE,
1488 vml->cache_dir, __map_types[vml->maptype].uniq_id,
1489 mapcoord.scale, mapcoord.z, mapcoord.x, mapcoord.y );
1490
1491 __map_types[vml->maptype].download ( &mapcoord, filename_buf );
1492 g_free ( filename_buf );
1493 vik_layer_emit_update ( VIK_LAYER(vml) );
1494 return TRUE;
1495 }
1496 }
1497 return FALSE;
1498#endif
1499}
1500
50817314 1501static void download_onscreen_maps ( gpointer vml_vvp[2], gint redownload )
50a14534
EB
1502{
1503 VikMapsLayer *vml = vml_vvp[0];
1504 VikViewport *vvp = vml_vvp[1];
314c1ccc 1505 VikViewportDrawMode vp_drawmode = vik_viewport_get_drawmode ( vvp );
50a14534
EB
1506
1507 gdouble xzoom = vml->xmapzoom ? vml->xmapzoom : vik_viewport_get_xmpp ( vvp );
1508 gdouble yzoom = vml->ymapzoom ? vml->ymapzoom : vik_viewport_get_ympp ( vvp );
1509
1510 VikCoord ul, br;
1511 MapCoord ulm, brm;
1512
1513 vik_viewport_screen_to_coord ( vvp, 0, 0, &ul );
1514 vik_viewport_screen_to_coord ( vvp, vik_viewport_get_width(vvp), vik_viewport_get_height(vvp), &br );
1515
820c59f4
GB
1516 VikMapSource *map = MAPS_LAYER_NTH_TYPE(vml->maptype);
1517 if ( vik_map_source_get_drawmode(map) == vp_drawmode &&
1518 vik_map_source_coord_to_mapcoord ( map, &ul, xzoom, yzoom, &ulm ) &&
1519 vik_map_source_coord_to_mapcoord ( map, &br, xzoom, yzoom, &brm ) )
50817314 1520 start_download_thread ( vml, vvp, &ul, &br, redownload );
820c59f4
GB
1521 else if (vik_map_source_get_drawmode(map) != vp_drawmode) {
1522 const gchar *drawmode_name = vik_viewport_get_drawmode_name (vvp, vik_map_source_get_drawmode(map));
4c77d5e0 1523 gchar *err = g_strdup_printf(_("Wrong drawmode for this map.\nSelect \"%s\" from View menu and try again."), _(drawmode_name));
314c1ccc
QT
1524 a_dialog_error_msg ( VIK_GTK_WINDOW_FROM_LAYER(vml), err );
1525 g_free(err);
1526 }
50a14534 1527 else
4c77d5e0 1528 a_dialog_error_msg ( VIK_GTK_WINDOW_FROM_LAYER(vml), _("Wrong zoom level for this map.") );
50a14534
EB
1529
1530}
1531
6a4a29aa 1532static void maps_layer_download_missing_onscreen_maps ( gpointer vml_vvp[2] )
50817314
GB
1533{
1534 download_onscreen_maps( vml_vvp, REDOWNLOAD_NONE);
1535}
1536
6a4a29aa
JJ
1537static void maps_layer_download_new_onscreen_maps ( gpointer vml_vvp[2] )
1538{
1539 download_onscreen_maps( vml_vvp, REDOWNLOAD_NEW);
1540}
1541
50817314
GB
1542static void maps_layer_redownload_all_onscreen_maps ( gpointer vml_vvp[2] )
1543{
1544 download_onscreen_maps( vml_vvp, REDOWNLOAD_ALL);
1545}
1546
3ac548fa
RN
1547/**
1548 * maps_layer_how_many_maps:
1549 * Copied from maps_layer_download_section but without the actual download and this returns a value
1550 */
1551static gint maps_layer_how_many_maps ( VikMapsLayer *vml, VikViewport *vvp, VikCoord *ul, VikCoord *br, gdouble zoom, gint redownload )
1552{
1553 MapCoord ulm, brm;
1554 VikMapSource *map = MAPS_LAYER_NTH_TYPE(vml->maptype);
1555
1556 if ( vik_map_source_is_direct_file_access ( map ) )
1557 return 0;
1558
1559 if (!vik_map_source_coord_to_mapcoord(map, ul, zoom, zoom, &ulm)
1560 || !vik_map_source_coord_to_mapcoord(map, br, zoom, zoom, &brm)) {
1561 g_warning("%s() coord_to_mapcoord() failed", __PRETTY_FUNCTION__);
1562 return 0;
1563 }
1564
1565 MapDownloadInfo *mdi = g_malloc(sizeof(MapDownloadInfo));
1566 gint i, j;
1567
1568 mdi->vml = vml;
1569 mdi->vvp = vvp;
1570 mdi->map_layer_alive = TRUE;
1571 mdi->mutex = g_mutex_new();
1572 mdi->refresh_display = FALSE;
1573
1574 mdi->cache_dir = g_strdup ( vml->cache_dir );
1575 mdi->maxlen = strlen ( vml->cache_dir ) + 40;
1576 mdi->filename_buf = g_malloc ( mdi->maxlen * sizeof(gchar) );
1577 mdi->maptype = vml->maptype;
1578
1579 mdi->mapcoord = ulm;
1580 mdi->redownload = redownload;
1581
1582 mdi->x0 = MIN(ulm.x, brm.x);
1583 mdi->xf = MAX(ulm.x, brm.x);
1584 mdi->y0 = MIN(ulm.y, brm.y);
1585 mdi->yf = MAX(ulm.y, brm.y);
1586
1587 mdi->mapstoget = 0;
1588
1589 if ( mdi->redownload == REDOWNLOAD_ALL ) {
1590 mdi->mapstoget = (mdi->xf - mdi->x0 + 1) * (mdi->yf - mdi->y0 + 1);
1591 }
1592 else {
1593 /* calculate how many we need */
1594 for (i = mdi->x0; i <= mdi->xf; i++) {
1595 for (j = mdi->y0; j <= mdi->yf; j++) {
1596 g_snprintf ( mdi->filename_buf, mdi->maxlen, DIRSTRUCTURE,
1597 vml->cache_dir, vik_map_source_get_uniq_id(map), ulm.scale,
1598 ulm.z, i, j );
1599 if ( mdi->redownload == REDOWNLOAD_NEW ) {
1600 // Assume the worst - always a new file
1601 // Absolute value would requires server lookup - but that is too slow
1602 mdi->mapstoget++;
1603 }
1604 else {
1605 if ( g_file_test ( mdi->filename_buf, G_FILE_TEST_EXISTS ) == FALSE ) {
1606 // Missing
1607 mdi->mapstoget++;
1608 }
1609 else {
1610 if ( mdi->redownload == REDOWNLOAD_BAD ) {
1611 /* see if this one is bad or what */
1612 GError *gx = NULL;
1613 GdkPixbuf *pixbuf = gdk_pixbuf_new_from_file ( mdi->filename_buf, &gx );
1614 if (gx || (!pixbuf)) {
1615 mdi->mapstoget++;
1616 }
1617 break;
1618 // Other download cases already considered or just ignored
1619 }
1620 }
1621 }
1622 }
1623 }
1624 }
1625
1626 gint rv = mdi->mapstoget;
1627
1628 mdi_free ( mdi );
1629
1630 return rv;
1631}
1632
1633/**
1634 * maps_dialog_zoom_between:
1635 * This dialog is specific to the map layer, so it's here rather than in dialog.c
1636 */
1637gboolean maps_dialog_zoom_between ( GtkWindow *parent,
1638 gchar *title,
1639 gchar *zoom_list[],
1640 gint default_zoom1,
1641 gint default_zoom2,
1642 gint *selected_zoom1,
1643 gint *selected_zoom2,
1644 gchar *download_list[],
1645 gint default_download,
1646 gint *selected_download )
1647{
1648 GtkWidget *dialog = gtk_dialog_new_with_buttons ( title,
1649 parent,
1650 GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
1651 GTK_STOCK_OK, GTK_RESPONSE_ACCEPT,
1652 GTK_STOCK_CANCEL, GTK_RESPONSE_REJECT,
1653 NULL );
1654 gtk_dialog_set_default_response ( GTK_DIALOG(dialog), GTK_RESPONSE_ACCEPT );
1655 GtkWidget *response_w = NULL;
1656#if GTK_CHECK_VERSION (2, 20, 0)
1657 response_w = gtk_dialog_get_widget_for_response ( GTK_DIALOG(dialog), GTK_RESPONSE_ACCEPT );
1658#endif
1659 GtkWidget *zoom_label1 = gtk_label_new ( _("Zoom Start:") );
1660 GtkWidget *zoom_combo1 = vik_combo_box_text_new();
1661 gchar **s;
1662 for (s = zoom_list; *s; s++)
1663 vik_combo_box_text_append ( zoom_combo1, *s );
1664 gtk_combo_box_set_active ( GTK_COMBO_BOX(zoom_combo1), default_zoom1 );
1665
1666 GtkWidget *zoom_label2 = gtk_label_new ( _("Zoom End:") );
1667 GtkWidget *zoom_combo2 = vik_combo_box_text_new();
1668 for (s = zoom_list; *s; s++)
1669 vik_combo_box_text_append ( zoom_combo2, *s );
1670 gtk_combo_box_set_active ( GTK_COMBO_BOX(zoom_combo2), default_zoom2 );
1671
1672 GtkWidget *download_label = gtk_label_new(_("Download Maps Method:"));
1673 GtkWidget *download_combo = vik_combo_box_text_new();
1674 for (s = download_list; *s; s++)
1675 vik_combo_box_text_append ( download_combo, *s );
1676 gtk_combo_box_set_active ( GTK_COMBO_BOX(download_combo), default_download );
1677
1678 GtkTable *box = GTK_TABLE(gtk_table_new(3, 2, FALSE));
1679 gtk_table_attach_defaults (box, GTK_WIDGET(zoom_label1), 0, 1, 0, 1);
1680 gtk_table_attach_defaults (box, GTK_WIDGET(zoom_combo1), 1, 2, 0, 1);
1681 gtk_table_attach_defaults (box, GTK_WIDGET(zoom_label2), 0, 1, 1, 2);
1682 gtk_table_attach_defaults (box, GTK_WIDGET(zoom_combo2), 1, 2, 1, 2);
1683 gtk_table_attach_defaults (box, GTK_WIDGET(download_label), 0, 1, 2, 3);
1684 gtk_table_attach_defaults (box, GTK_WIDGET(download_combo), 1, 2, 2, 3);
1685
1686 gtk_box_pack_start ( GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(dialog))), GTK_WIDGET(box), FALSE, FALSE, 5 );
1687
1688 if ( response_w )
1689 gtk_widget_grab_focus ( response_w );
1690
1691 gtk_widget_show_all ( dialog );
1692 if ( gtk_dialog_run ( GTK_DIALOG(dialog) ) != GTK_RESPONSE_ACCEPT ) {
1693 gtk_widget_destroy(dialog);
1694 return FALSE;
1695 }
1696
1697 // Return selected options
1698 *selected_zoom1 = gtk_combo_box_get_active ( GTK_COMBO_BOX(zoom_combo1) );
1699 *selected_zoom2 = gtk_combo_box_get_active ( GTK_COMBO_BOX(zoom_combo2) );
1700 *selected_download = gtk_combo_box_get_active ( GTK_COMBO_BOX(download_combo) );
1701
1702 gtk_widget_destroy(dialog);
1703 return TRUE;
1704}
1705
1706// My best guess of sensible limits
1707#define REALLY_LARGE_AMOUNT_OF_TILES 5000
1708#define CONFIRM_LARGE_AMOUNT_OF_TILES 500
1709
1710/**
1711 * Get all maps in the region for zoom levels specified by the user
1712 * Sort of similar to trw_layer_download_map_along_track_cb function
1713 */
1714static void maps_layer_download_all ( gpointer vml_vvp[2] )
1715{
1716 VikMapsLayer *vml = vml_vvp[0];
1717 VikViewport *vvp = vml_vvp[1];
1718
1719 // I don't think we should allow users to hammer the servers too much...
1720 // Delibrately not allowing lowest zoom levels
1721 // Still can give massive numbers to download
1722 // A screen size of 1600x1200 gives around 300,000 tiles between 1..128 when none exist before !!
1723 gchar *zoom_list[] = {"1", "2", "4", "8", "16", "32", "64", "128", "256", "512", "1024", NULL };
1724 gdouble zoom_vals[] = {1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024};
1725
1726 gint selected_zoom1, selected_zoom2, default_zoom, lower_zoom;
1727 gint selected_download_method;
1728
1729 gdouble cur_zoom = vik_viewport_get_zoom(vvp);
1730
1731 for (default_zoom = 0; default_zoom < sizeof(zoom_vals)/sizeof(gdouble); default_zoom++) {
1732 if (cur_zoom == zoom_vals[default_zoom])
1733 break;
1734 }
1735 default_zoom = (default_zoom == sizeof(zoom_vals)/sizeof(gdouble)) ? sizeof(zoom_vals)/sizeof(gdouble) - 1 : default_zoom;
1736
1737 // Default to only 2 zoom levels below the current one
1738 if (default_zoom > 1 )
1739 lower_zoom = default_zoom - 2;
1740 else
1741 lower_zoom = default_zoom;
1742
1743 // redownload method - needs to align with REDOWNLOAD* macro values
1744 gchar *download_list[] = { _("Missing"), _("Bad"), _("New"), _("Reload All"), NULL };
1745
1746 gchar *title = g_strdup_printf ( ("%s: %s"), vik_maps_layer_get_map_label (vml), _("Download for Zoom Levels") );
1747
1748 if ( ! maps_dialog_zoom_between ( VIK_GTK_WINDOW_FROM_LAYER(vml),
1749 title,
1750 zoom_list,
1751 lower_zoom,
1752 default_zoom,
1753 &selected_zoom1,
1754 &selected_zoom2,
1755 download_list,
1756 REDOWNLOAD_NONE, // AKA Missing
1757 &selected_download_method ) ) {
1758 // Cancelled
1759 g_free ( title );
1760 return;
1761 }
1762 g_free ( title );
1763
1764 // Find out new current positions
1765 gdouble min_lat, max_lat, min_lon, max_lon;
1766 VikCoord vc_ul, vc_br;
1767 vik_viewport_get_min_max_lat_lon ( vvp, &min_lat, &max_lat, &min_lon, &max_lon );
1768 struct LatLon ll_ul = { max_lat, min_lon };
1769 struct LatLon ll_br = { min_lat, max_lon };
1770 vik_coord_load_from_latlon ( &vc_ul, vik_viewport_get_coord_mode (vvp), &ll_ul );
1771 vik_coord_load_from_latlon ( &vc_br, vik_viewport_get_coord_mode (vvp), &ll_br );
1772
1773 // Get Maps Count - call for each zoom level (in reverse)
1774 // With REDOWNLOAD_NEW this is a possible maximum
1775 // With REDOWNLOAD_NONE this only missing ones - however still has a server lookup per tile
1776 gint map_count = 0;
1777 gint zz;
1778 for ( zz = selected_zoom2; zz >= selected_zoom1; zz-- ) {
1779 map_count = map_count + maps_layer_how_many_maps ( vml, vvp, &vc_ul, &vc_br, zoom_vals[zz], selected_download_method );
1780 }
1781
1782 g_debug ("vikmapslayer: download request map count %d for method %d", map_count, selected_download_method);
1783
1784 // Absolute protection of hammering a map server
1785 if ( map_count > REALLY_LARGE_AMOUNT_OF_TILES ) {
1786 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);
1787 a_dialog_error_msg ( VIK_GTK_WINDOW_FROM_LAYER(vml), str );
1788 g_free (str);
1789 return;
1790 }
1791
1792 // Confirm really want to do this
1793 if ( map_count > CONFIRM_LARGE_AMOUNT_OF_TILES ) {
1794 gchar *str = g_strdup_printf (_("Do you really want to download %d tiles?"), map_count);
1795 gboolean ans = a_dialog_yes_or_no ( VIK_GTK_WINDOW_FROM_LAYER(vml), str, NULL );
1796 g_free (str);
1797 if ( ! ans )
1798 return;
1799 }
1800
1801 // Get Maps - call for each zoom level (in reverse)
1802 for ( zz = selected_zoom2; zz >= selected_zoom1; zz-- ) {
1803 maps_layer_download_section ( vml, vvp, &vc_ul, &vc_br, zoom_vals[zz], selected_download_method );
1804 }
1805}
1806
50a14534
EB
1807static void maps_layer_add_menu_items ( VikMapsLayer *vml, GtkMenu *menu, VikLayersPanel *vlp )
1808{
1809 static gpointer pass_along[2];
1810 GtkWidget *item;
1811 pass_along[0] = vml;
1812 pass_along[1] = vik_layers_panel_get_viewport( VIK_LAYERS_PANEL(vlp) );
1813
1814 item = gtk_menu_item_new();
1815 gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item );
1816 gtk_widget_show ( item );
1817
555ec6f6
RN
1818 /* Now with icons */
1819 item = gtk_image_menu_item_new_with_mnemonic ( _("Download _Missing Onscreen Maps") );
1820 gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_ADD, GTK_ICON_SIZE_MENU) );
6a4a29aa 1821 g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(maps_layer_download_missing_onscreen_maps), pass_along );
50a14534
EB
1822 gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
1823 gtk_widget_show ( item );
50817314 1824
c81ded98 1825 if ( vik_map_source_supports_download_only_new (MAPS_LAYER_NTH_TYPE(vml->maptype)) ) {
555ec6f6
RN
1826 item = gtk_image_menu_item_new_with_mnemonic ( _("Download _New Onscreen Maps") );
1827 gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_REDO, GTK_ICON_SIZE_MENU) );
6a4a29aa
JJ
1828 g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(maps_layer_download_new_onscreen_maps), pass_along );
1829 gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
1830 gtk_widget_show ( item );
1831 }
1832
555ec6f6
RN
1833 item = gtk_image_menu_item_new_with_mnemonic ( _("Reload _All Onscreen Maps") );
1834 gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_REFRESH, GTK_ICON_SIZE_MENU) );
50817314
GB
1835 g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(maps_layer_redownload_all_onscreen_maps), pass_along );
1836 gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
1837 gtk_widget_show ( item );
3ac548fa
RN
1838
1839 item = gtk_image_menu_item_new_with_mnemonic ( _("Download Maps in _Zoom Levels...") );
1840 gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_DND_MULTIPLE, GTK_ICON_SIZE_MENU) );
1841 g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(maps_layer_download_all), pass_along );
1842 gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
1843 gtk_widget_show ( item );
50a14534 1844}
6b59f63d
RN
1845
1846/**
1847 * Enable downloading maps of the current screen area either 'new' or 'everything'
1848 */
1849void vik_maps_layer_download ( VikMapsLayer *vml, VikViewport *vvp, gboolean only_new )
1850{
1851 if ( !vml ) return;
1852 if ( !vvp ) return;
1853
1854 static gpointer pass_along[2];
1855 pass_along[0] = vml;
1856 pass_along[1] = vvp;
1857
1858 if ( only_new )
1859 // Get only new maps
1860 maps_layer_download_new_onscreen_maps ( pass_along );
1861 else
1862 // Redownload everything
1863 maps_layer_redownload_all_onscreen_maps ( pass_along );
1864}