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