]> git.street.me.uk Git - andy/viking.git/blame - src/vikmapslayer.c
Fix: Correctly rotate thumbnail images
[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#define MAX_SHRINKFACTOR 8.0000001 /* zoom 1 viewing 8-tiles */
30#define MIN_SHRINKFACTOR 0.0312499 /* zoom 32 viewing 1-tiles */
31
732d1e25
EB
32#define REAL_MIN_SHRINKFACTOR 0.0039062499 /* if shrinkfactor is between MAX and REAL_MAX, will only check for existence */
33
50a14534
EB
34#include <gtk/gtk.h>
35#include <gdk-pixbuf/gdk-pixdata.h>
45acf79e
MA
36#include <glib.h>
37#include <glib/gstdio.h>
4c77d5e0
GB
38#include <glib/gi18n.h>
39
8c00358d 40#ifdef HAVE_STRING_H
50a14534 41#include <string.h>
8c00358d
GB
42#endif
43#ifdef HAVE_MATH_H
50a14534 44#include <math.h>
8c00358d
GB
45#endif
46
50a14534
EB
47#include "globals.h"
48#include "coords.h"
49#include "vikcoord.h"
50#include "viktreeview.h"
51#include "vikviewport.h"
52#include "viklayer.h"
53#include "vikmapslayer.h"
50a14534 54
45acf79e 55#ifdef HAVE_UNISTD_H
50a14534 56#include <unistd.h>
45acf79e 57#endif
50a14534
EB
58
59#include "mapcache.h"
60/* only for dialog.h -- ugh */
61#include "vikwaypoint.h"
62#include "dialog.h"
55ddef4e 63#include "preferences.h"
50a14534
EB
64
65#include "vikstatus.h"
66#include "background.h"
67
68#include "vikaggregatelayer.h"
69#include "viklayerspanel.h"
70
71#include "mapcoord.h"
72#include "terraserver.h"
50a14534 73
bce3a7b0
EB
74#include "icons/icons.h"
75
50a14534
EB
76/****** MAP TYPES ******/
77
cdcaf41c
QT
78static GList *__map_types = NULL;
79
80#define NUM_MAP_TYPES g_list_length(__map_types)
50a14534 81
cdcaf41c 82/* List of label for each map type */
a8876892 83static gchar **params_maptypes = NULL;
cdcaf41c
QT
84
85/* Corresponding IDS. (Cf. field uniq_id in VikMapsLayer struct) */
a8876892 86static guint *params_maptypes_ids = NULL;
50a14534
EB
87
88/******** MAPZOOMS *********/
89
4c77d5e0 90static gchar *params_mapzooms[] = { N_("Use Viking Zoom Level"), "0.25", "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 };
50a14534
EB
91static gdouble __mapzooms_x[] = { 0.0, 0.25, 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 };
92static gdouble __mapzooms_y[] = { 0.0, 0.25, 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 };
93
d756fb5c 94#define NUM_MAPZOOMS (sizeof(params_mapzooms)/sizeof(params_mapzooms[0]) - 1)
50a14534
EB
95
96/**************************/
97
98
07059501 99static void maps_layer_post_read (VikLayer *vl, VikViewport *vp, gboolean from_file);
911400b5
AF
100static void maps_layer_marshall( VikMapsLayer *vml, guint8 **data, gint *len );
101static VikMapsLayer *maps_layer_unmarshall( guint8 *data, gint len, VikViewport *vvp );
50a14534
EB
102static gboolean maps_layer_set_param ( VikMapsLayer *vml, guint16 id, VikLayerParamData data, VikViewport *vvp );
103static VikLayerParamData maps_layer_get_param ( VikMapsLayer *vml, guint16 id );
104static void maps_layer_draw ( VikMapsLayer *vml, VikViewport *vvp );
105static VikMapsLayer *maps_layer_new ( VikViewport *vvp );
106static void maps_layer_free ( VikMapsLayer *vml );
107static gboolean maps_layer_download_release ( VikMapsLayer *vml, GdkEventButton *event, VikViewport *vvp );
108static gboolean maps_layer_download_click ( VikMapsLayer *vml, GdkEventButton *event, VikViewport *vvp );
941aa6e9 109static gpointer maps_layer_download_create ( VikWindow *vw, VikViewport *vvp );
50a14534
EB
110static void maps_layer_set_cache_dir ( VikMapsLayer *vml, const gchar *dir );
111static void start_download_thread ( VikMapsLayer *vml, VikViewport *vvp, const VikCoord *ul, const VikCoord *br, gint redownload );
112static void maps_layer_add_menu_items ( VikMapsLayer *vml, GtkMenu *menu, VikLayersPanel *vlp );
113
114
115static VikLayerParamScale params_scales[] = {
116 /* min, max, step, digits (decimal places) */
117 { 0, 255, 3, 0 }, /* alpha */
118};
119
120VikLayerParam maps_layer_params[] = {
a8876892 121 { "mode", VIK_LAYER_PARAM_UINT, VIK_LAYER_GROUP_NONE, N_("Map Type:"), VIK_LAYER_WIDGET_COMBOBOX, NULL, NULL },
e6fd9b70 122 { "directory", VIK_LAYER_PARAM_STRING, VIK_LAYER_GROUP_NONE, N_("Maps Directory:"), VIK_LAYER_WIDGET_FOLDERENTRY },
4c77d5e0
GB
123 { "alpha", VIK_LAYER_PARAM_UINT, VIK_LAYER_GROUP_NONE, N_("Alpha:"), VIK_LAYER_WIDGET_HSCALE, params_scales },
124 { "autodownload", VIK_LAYER_PARAM_BOOLEAN, VIK_LAYER_GROUP_NONE, N_("Autodownload maps:"), VIK_LAYER_WIDGET_CHECKBUTTON },
a8876892 125 { "mapzoom", VIK_LAYER_PARAM_UINT, VIK_LAYER_GROUP_NONE, N_("Zoom Level:"), VIK_LAYER_WIDGET_COMBOBOX, params_mapzooms, NULL },
50a14534
EB
126};
127
128enum { PARAM_MAPTYPE=0, PARAM_CACHE_DIR, PARAM_ALPHA, PARAM_AUTODOWNLOAD, PARAM_MAPZOOM, NUM_PARAMS };
129
130static VikToolInterface maps_tools[] = {
4c77d5e0 131 { N_("Maps Download"), (VikToolConstructorFunc) maps_layer_download_create, NULL, NULL, NULL,
bce3a7b0 132 (VikToolMouseFunc) maps_layer_download_click, NULL, (VikToolMouseFunc) maps_layer_download_release,
5bfafde9 133 (VikToolKeyFunc) NULL, GDK_CURSOR_IS_PIXMAP, &cursor_mapdl_pixbuf },
50a14534
EB
134};
135
136VikLayerInterface vik_maps_layer_interface = {
4c77d5e0 137 N_("Map"),
5bfafde9 138 &vikmapslayer_pixbuf,
50a14534
EB
139
140 maps_tools,
141 sizeof(maps_tools) / sizeof(maps_tools[0]),
142
143 maps_layer_params,
144 NUM_PARAMS,
145 NULL,
146 0,
147
5a4a28bf
QT
148 VIK_MENU_ITEM_ALL,
149
50a14534
EB
150 (VikLayerFuncCreate) maps_layer_new,
151 (VikLayerFuncRealize) NULL,
b112cbf5 152 (VikLayerFuncPostRead) maps_layer_post_read,
50a14534
EB
153 (VikLayerFuncFree) maps_layer_free,
154
155 (VikLayerFuncProperties) NULL,
156 (VikLayerFuncDraw) maps_layer_draw,
157 (VikLayerFuncChangeCoordMode) NULL,
158
20c7a3a0
QT
159 (VikLayerFuncSetMenuItemsSelection) NULL,
160 (VikLayerFuncGetMenuItemsSelection) NULL,
161
50a14534
EB
162 (VikLayerFuncAddMenuItems) maps_layer_add_menu_items,
163 (VikLayerFuncSublayerAddMenuItems) NULL,
164
165 (VikLayerFuncSublayerRenameRequest) NULL,
166 (VikLayerFuncSublayerToggleVisible) NULL,
167
911400b5
AF
168 (VikLayerFuncMarshall) maps_layer_marshall,
169 (VikLayerFuncUnmarshall) maps_layer_unmarshall,
50a14534
EB
170
171 (VikLayerFuncSetParam) maps_layer_set_param,
172 (VikLayerFuncGetParam) maps_layer_get_param,
173
174 (VikLayerFuncReadFileData) NULL,
175 (VikLayerFuncWriteFileData) NULL,
176
33534cd8 177 (VikLayerFuncDeleteItem) NULL,
50a14534
EB
178 (VikLayerFuncCopyItem) NULL,
179 (VikLayerFuncPasteItem) NULL,
180 (VikLayerFuncFreeCopiedItem) NULL,
70a23263 181 (VikLayerFuncDragDropRequest) NULL,
50a14534
EB
182};
183
184struct _VikMapsLayer {
185 VikLayer vl;
186 guint maptype;
187 gchar *cache_dir;
188 guint8 alpha;
189 guint mapzoom_id;
190 gdouble xmapzoom, ymapzoom;
191
192 gboolean autodownload;
10ca2bfe
QT
193 VikCoord *last_center;
194 gdouble last_xmpp;
195 gdouble last_ympp;
50a14534
EB
196
197 gint dl_tool_x, dl_tool_y;
198
199 GtkMenu *dl_right_click_menu;
200 VikCoord redownload_ul, redownload_br; /* right click menu only */
201 VikViewport *redownload_vvp;
202};
203
6a4a29aa
JJ
204enum { REDOWNLOAD_NONE = 0, /* download only missing maps */
205 REDOWNLOAD_BAD, /* download missing and bad maps */
206 REDOWNLOAD_NEW, /* download missing maps that are newer on server only */
207 REDOWNLOAD_ALL, /* download all maps */
208 DOWNLOAD_OR_REFRESH }; /* download missing maps and refresh cache */
50a14534 209
55ddef4e
JJ
210static VikLayerParam prefs[] = {
211 { VIKING_PREFERENCES_NAMESPACE "maplayer_default_dir", VIK_LAYER_PARAM_STRING, VIK_LAYER_GROUP_NONE, N_("Default maplayer directory:"), VIK_LAYER_WIDGET_FOLDERENTRY, NULL, NULL },
212};
213
214void maps_layer_init ()
215{
216 VikLayerParamData tmp;
217 tmp.s = maps_layer_default_dir();
218 a_preferences_register(prefs, tmp, VIKING_PREFERENCES_GROUP_KEY);
219}
50a14534 220
cdcaf41c
QT
221/****************************************/
222/******** MAPS LAYER TYPES **************/
223/****************************************/
224
db03733a 225void maps_layer_register_map_source ( VikMapSource *map )
cdcaf41c 226{
820c59f4 227 g_assert(map != NULL);
6846aafb 228
820c59f4 229 guint id = vik_map_source_get_uniq_id(map);
db03733a 230 const char *label = vik_map_source_get_label(map);
cdcaf41c 231 g_assert(label != NULL);
cdcaf41c 232
a8876892
GB
233 gsize len = 0;
234 if (params_maptypes)
235 len = g_strv_length (params_maptypes);
cdcaf41c 236 /* Add the label */
a8876892
GB
237 params_maptypes = g_realloc (params_maptypes, (len+2)*sizeof(gchar*));
238 params_maptypes[len] = g_strdup (label);
239 params_maptypes[len+1] = NULL;
cdcaf41c
QT
240
241 /* Add the id */
a8876892
GB
242 params_maptypes_ids = g_realloc (params_maptypes_ids, (len+2)*sizeof(guint));
243 params_maptypes_ids[len] = id;
244 params_maptypes_ids[len+1] = 0;
cdcaf41c
QT
245
246 /* We have to clone */
820c59f4 247 VikMapSource *clone = VIK_MAP_SOURCE(g_object_ref(map));
cdcaf41c
QT
248 /* Register the clone in the list */
249 __map_types = g_list_append(__map_types, clone);
250
251 /* Hack
252 We have to ensure the mode LayerParam reference the up-to-date
253 GLists.
254 */
255 /*
256 memcpy(&maps_layer_params[0].widget_data, &params_maptypes, sizeof(gpointer));
257 memcpy(&maps_layer_params[0].extra_widget_data, &params_maptypes_ids, sizeof(gpointer));
258 */
259 maps_layer_params[0].widget_data = params_maptypes;
260 maps_layer_params[0].extra_widget_data = params_maptypes_ids;
261}
262
a8876892
GB
263#define MAPS_LAYER_NTH_LABEL(n) (params_maptypes[n])
264#define MAPS_LAYER_NTH_ID(n) (params_maptypes_ids[n])
820c59f4 265#define MAPS_LAYER_NTH_TYPE(n) (VIK_MAP_SOURCE(g_list_nth_data(__map_types, (n))))
cdcaf41c 266
7114e879
QT
267gint vik_maps_layer_get_map_type(VikMapsLayer *vml)
268{
269 return(vml->maptype);
270}
271
272gchar *vik_maps_layer_get_map_label(VikMapsLayer *vml)
273{
274 return(g_strdup(MAPS_LAYER_NTH_LABEL(vml->maptype)));
275}
276
50a14534
EB
277/****************************************/
278/******** CACHE DIR STUFF ***************/
279/****************************************/
280
3d9454e6 281#define DIRSTRUCTURE "%st%ds%dz%d" G_DIR_SEPARATOR_S "%d" G_DIR_SEPARATOR_S "%d"
6a27c1bc
MA
282#define MAPS_CACHE_DIR maps_layer_default_dir()
283
50a14534 284#ifdef WINDOWS
6a27c1bc
MA
285#include <io.h>
286#define GLOBAL_MAPS_DIR "C:\\VIKING-MAPS\\"
287#define LOCAL_MAPS_DIR "VIKING-MAPS"
50a14534 288#else /* POSIX */
50a14534 289#include <stdlib.h>
50a14534 290#define GLOBAL_MAPS_DIR "/var/cache/maps/"
6a27c1bc
MA
291#define LOCAL_MAPS_DIR ".viking-maps"
292#endif
50a14534 293
0c1044e9 294gchar *maps_layer_default_dir ()
50a14534 295{
3d9454e6
GB
296 static gchar *defaultdir = NULL;
297 if ( ! defaultdir )
50a14534
EB
298 {
299 /* Thanks to Mike Davison for the $VIKING_MAPS usage */
3d9454e6
GB
300 const gchar *mapdir = g_getenv("VIKING_MAPS");
301 if ( mapdir ) {
302 defaultdir = g_strdup ( mapdir );
45acf79e 303 } else if ( g_access ( GLOBAL_MAPS_DIR, W_OK ) == 0 ) {
3d9454e6 304 defaultdir = g_strdup ( GLOBAL_MAPS_DIR );
50a14534 305 } else {
6a27c1bc 306 const gchar *home = g_get_home_dir();
45acf79e 307 if (!home || g_access(home, W_OK))
3d9454e6
GB
308 home = g_get_home_dir ();
309 if ( home )
6a27c1bc 310 defaultdir = g_build_filename ( home, LOCAL_MAPS_DIR, NULL );
50a14534 311 else
6a27c1bc 312 defaultdir = g_strdup ( LOCAL_MAPS_DIR );
50a14534 313 }
3d9454e6
GB
314 if (defaultdir && (defaultdir[strlen(defaultdir)-1] != G_DIR_SEPARATOR))
315 {
316 /* Add the separator at the end */
317 gchar *tmp = defaultdir;
318 defaultdir = g_strconcat(tmp, G_DIR_SEPARATOR_S, NULL);
319 g_free(tmp);
320 }
321 g_debug("%s: defaultdir=%s", __FUNCTION__, defaultdir);
50a14534
EB
322 }
323 return defaultdir;
324}
325
50a14534
EB
326static void maps_layer_mkdir_if_default_dir ( VikMapsLayer *vml )
327{
45acf79e 328 if ( vml->cache_dir && strcmp ( vml->cache_dir, MAPS_CACHE_DIR ) == 0 && g_file_test ( vml->cache_dir, G_FILE_TEST_EXISTS ) == FALSE )
50a14534 329 {
f83131b9 330 g_mkdir ( vml->cache_dir, 0777 );
50a14534
EB
331 }
332}
333
334static void maps_layer_set_cache_dir ( VikMapsLayer *vml, const gchar *dir )
335{
336 guint len;
337 g_assert ( vml != NULL);
e65028db
GB
338 g_free ( vml->cache_dir );
339 vml->cache_dir = NULL;
50a14534
EB
340
341 if ( dir == NULL || dir[0] == '\0' )
55ddef4e 342 vml->cache_dir = g_strdup ( a_preferences_get(VIKING_PREFERENCES_NAMESPACE "maplayer_default_dir")->s );
50a14534
EB
343 else
344 {
345 len = strlen(dir);
3d9454e6 346 if ( dir[len-1] != G_DIR_SEPARATOR )
50a14534
EB
347 {
348 vml->cache_dir = g_malloc ( len+2 );
349 strncpy ( vml->cache_dir, dir, len );
3d9454e6 350 vml->cache_dir[len] = G_DIR_SEPARATOR;
50a14534
EB
351 vml->cache_dir[len+1] = '\0';
352 }
353 else
354 vml->cache_dir = g_strdup ( dir );
355 }
356 maps_layer_mkdir_if_default_dir ( vml );
357}
358
359/****************************************/
360/******** GOBJECT STUFF *****************/
361/****************************************/
362
363GType vik_maps_layer_get_type ()
364{
365 static GType vml_type = 0;
366
367 if (!vml_type)
368 {
369 static const GTypeInfo vml_info =
370 {
371 sizeof (VikMapsLayerClass),
372 NULL, /* base_init */
373 NULL, /* base_finalize */
374 NULL, /* class init */
375 NULL, /* class_finalize */
376 NULL, /* class_data */
377 sizeof (VikMapsLayer),
378 0,
379 NULL /* instance init */
380 };
381 vml_type = g_type_register_static ( VIK_LAYER_TYPE, "VikMapsLayer", &vml_info, 0 );
382 }
383
384 return vml_type;
385}
386
387/****************************************/
388/************** PARAMETERS **************/
389/****************************************/
390
391static guint map_index_to_uniq_id (guint8 index)
392{
393 g_assert ( index < NUM_MAP_TYPES );
820c59f4 394 return vik_map_source_get_uniq_id(MAPS_LAYER_NTH_TYPE(index));
50a14534
EB
395}
396
397static guint map_uniq_id_to_index ( guint uniq_id )
398{
399 gint i;
400 for ( i = 0; i < NUM_MAP_TYPES; i++ )
820c59f4 401 if ( vik_map_source_get_uniq_id(MAPS_LAYER_NTH_TYPE(i)) == uniq_id )
50a14534
EB
402 return i;
403 return NUM_MAP_TYPES; /* no such thing */
404}
405
406static gboolean maps_layer_set_param ( VikMapsLayer *vml, guint16 id, VikLayerParamData data, VikViewport *vvp )
407{
408 switch ( id )
409 {
410 case PARAM_CACHE_DIR: maps_layer_set_cache_dir ( vml, data.s ); break;
411 case PARAM_MAPTYPE: {
412 gint maptype = map_uniq_id_to_index(data.u);
4c77d5e0 413 if ( maptype == NUM_MAP_TYPES ) g_warning(_("Unknown map type"));
50a14534
EB
414 else vml->maptype = maptype;
415 break;
416 }
417 case PARAM_ALPHA: if ( data.u <= 255 ) vml->alpha = data.u; break;
418 case PARAM_AUTODOWNLOAD: vml->autodownload = data.b; break;
419 case PARAM_MAPZOOM: if ( data.u < NUM_MAPZOOMS ) {
420 vml->mapzoom_id = data.u;
421 vml->xmapzoom = __mapzooms_x [data.u];
422 vml->ymapzoom = __mapzooms_y [data.u];
4c77d5e0 423 }else g_warning (_("Unknown Map Zoom")); break;
50a14534
EB
424 }
425 return TRUE;
426}
427
428static VikLayerParamData maps_layer_get_param ( VikMapsLayer *vml, guint16 id )
429{
430 VikLayerParamData rv;
431 switch ( id )
432 {
e6fd9b70 433 case PARAM_CACHE_DIR: rv.s = vml->cache_dir ? vml->cache_dir : ""; break;
50a14534
EB
434 case PARAM_MAPTYPE: rv.u = map_index_to_uniq_id ( vml->maptype ); break;
435 case PARAM_ALPHA: rv.u = vml->alpha; break;
436 case PARAM_AUTODOWNLOAD: rv.u = vml->autodownload; break;
437 case PARAM_MAPZOOM: rv.u = vml->mapzoom_id; break;
438 }
439 return rv;
440}
441
442/****************************************/
443/****** CREATING, COPYING, FREEING ******/
444/****************************************/
445
446static VikMapsLayer *maps_layer_new ( VikViewport *vvp )
447{
36c78d6d 448 int idx;
50a14534
EB
449 VikMapsLayer *vml = VIK_MAPS_LAYER ( g_object_new ( VIK_MAPS_LAYER_TYPE, NULL ) );
450 vik_layer_init ( VIK_LAYER(vml), VIK_LAYER_MAPS );
57789c45 451 idx = map_uniq_id_to_index(13); /* 13 is id for OSM Mapnik maps */
36c78d6d 452 vml->maptype = (idx < NUM_MAP_TYPES) ? idx : 0;
50a14534
EB
453 vml->alpha = 255;
454 vml->mapzoom_id = 0;
455 vml->dl_tool_x = vml->dl_tool_y = -1;
456 maps_layer_set_cache_dir ( vml, NULL );
457 vml->autodownload = FALSE;
10ca2bfe
QT
458 vml->last_center = NULL;
459 vml->last_xmpp = 0.0;
460 vml->last_ympp = 0.0;
50a14534
EB
461
462 vml->dl_right_click_menu = NULL;
463
464 return vml;
465}
466
467static void maps_layer_free ( VikMapsLayer *vml )
468{
e65028db
GB
469 g_free ( vml->cache_dir );
470 vml->cache_dir = NULL;
50a14534
EB
471 if ( vml->dl_right_click_menu )
472 gtk_object_sink ( GTK_OBJECT(vml->dl_right_click_menu) );
e65028db
GB
473 g_free(vml->last_center);
474 vml->last_center = NULL;
50a14534
EB
475}
476
07059501 477static void maps_layer_post_read (VikLayer *vl, VikViewport *vp, gboolean from_file)
dc5758d3 478{
07059501
GB
479 if (from_file != TRUE)
480 {
481 /* If this method is not called in file reading context
482 * it is called in GUI context.
483 * So, we can check if we have to inform the user about inconsistency */
484 VikViewportDrawMode vp_drawmode;
485 VikMapsLayer *vml = VIK_MAPS_LAYER(vl);
820c59f4 486 VikMapSource *map = NULL;
dc5758d3 487
07059501 488 vp_drawmode = vik_viewport_get_drawmode ( VIK_VIEWPORT(vp) );
820c59f4
GB
489 map = MAPS_LAYER_NTH_TYPE(vml->maptype);
490 if (vik_map_source_get_drawmode(map) != vp_drawmode) {
491 const gchar *drawmode_name = vik_viewport_get_drawmode_name (VIK_VIEWPORT(vp), vik_map_source_get_drawmode(map));
4c77d5e0 492 gchar *msg = g_strdup_printf(_("New map cannot be displayed in the current drawmode.\nSelect \"%s\" from View menu to view it."), drawmode_name);
07059501
GB
493 a_dialog_warning_msg ( VIK_GTK_WINDOW_FROM_LAYER(vml), msg );
494 g_free(msg);
495 }
dc5758d3
GB
496 }
497}
498
911400b5
AF
499static void maps_layer_marshall( VikMapsLayer *vml, guint8 **data, gint *len )
500{
501 vik_layer_marshall_params ( VIK_LAYER(vml), data, len );
502}
503
504static VikMapsLayer *maps_layer_unmarshall( guint8 *data, gint len, VikViewport *vvp )
505{
506 VikMapsLayer *rv = maps_layer_new ( vvp );
507 vik_layer_unmarshall_params ( VIK_LAYER(rv), data, len, vvp );
508 return rv;
509}
510
50a14534
EB
511/*********************/
512/****** DRAWING ******/
513/*********************/
514
515static GdkPixbuf *pixbuf_set_alpha ( GdkPixbuf *pixbuf, guint8 alpha )
516{
517 guchar *pixels;
518 gint width, height, iii, jjj;
519
520 if ( ! gdk_pixbuf_get_has_alpha ( pixbuf ) )
521 {
522 GdkPixbuf *tmp = gdk_pixbuf_add_alpha(pixbuf,FALSE,0,0,0);
523 g_object_unref(G_OBJECT(pixbuf));
524 pixbuf = tmp;
525 }
526
527 pixels = gdk_pixbuf_get_pixels(pixbuf);
528 width = gdk_pixbuf_get_width(pixbuf);
529 height = gdk_pixbuf_get_height(pixbuf);
530
531 /* r,g,b,a,r,g,b,a.... */
532 for (iii = 0; iii < width; iii++) for (jjj = 0; jjj < height; jjj++)
533 {
534 pixels += 3;
535 *pixels++ = alpha;
536 }
537 return pixbuf;
538}
539
540static GdkPixbuf *pixbuf_shrink ( GdkPixbuf *pixbuf, gdouble xshrinkfactor, gdouble yshrinkfactor )
541{
542 GdkPixbuf *tmp;
543 guint16 width = gdk_pixbuf_get_width(pixbuf), height = gdk_pixbuf_get_height(pixbuf);
9fdb940f 544 tmp = gdk_pixbuf_scale_simple(pixbuf, ceil(width * xshrinkfactor), ceil(height * yshrinkfactor), GDK_INTERP_NEAREST);
50a14534
EB
545 g_object_unref ( G_OBJECT(pixbuf) );
546 return tmp;
547}
548
549static GdkPixbuf *get_pixbuf( VikMapsLayer *vml, gint mode, MapCoord *mapcoord, gchar *filename_buf, gint buf_len, gdouble xshrinkfactor, gdouble yshrinkfactor )
550{
551 GdkPixbuf *pixbuf;
552
553 /* get the thing */
554 pixbuf = a_mapcache_get ( mapcoord->x, mapcoord->y, mapcoord->z,
555 mode, mapcoord->scale, vml->alpha, xshrinkfactor, yshrinkfactor );
556
557 if ( ! pixbuf ) {
558 g_snprintf ( filename_buf, buf_len, DIRSTRUCTURE,
559 vml->cache_dir, mode,
560 mapcoord->scale, mapcoord->z, mapcoord->x, mapcoord->y );
01ecda7e 561 if ( g_file_test ( filename_buf, G_FILE_TEST_EXISTS ) == TRUE)
50a14534
EB
562 {
563 GError *gx = NULL;
564 pixbuf = gdk_pixbuf_new_from_file ( filename_buf, &gx );
565
01ecda7e 566 /* free the pixbuf on error */
50a14534
EB
567 if (gx)
568 {
569 if ( gx->domain != GDK_PIXBUF_ERROR || gx->code != GDK_PIXBUF_ERROR_CORRUPT_IMAGE )
4c77d5e0 570 g_warning ( _("Couldn't open image file: %s"), gx->message );
50a14534 571
01ecda7e
MR
572 g_error_free ( gx );
573 if ( pixbuf )
574 g_object_unref ( G_OBJECT(pixbuf) );
575 pixbuf = NULL;
576 } else {
50a14534
EB
577 if ( vml->alpha < 255 )
578 pixbuf = pixbuf_set_alpha ( pixbuf, vml->alpha );
579 if ( xshrinkfactor != 1.0 || yshrinkfactor != 1.0 )
580 pixbuf = pixbuf_shrink ( pixbuf, xshrinkfactor, yshrinkfactor );
581
582 a_mapcache_add ( pixbuf, mapcoord->x, mapcoord->y,
820c59f4 583 mapcoord->z, vik_map_source_get_uniq_id(MAPS_LAYER_NTH_TYPE(vml->maptype)),
50a14534 584 mapcoord->scale, vml->alpha, xshrinkfactor, yshrinkfactor );
50a14534
EB
585 }
586 }
587 }
588 return pixbuf;
589}
590
10ca2bfe
QT
591gboolean should_start_autodownload(VikMapsLayer *vml, VikViewport *vvp)
592{
593 const VikCoord *center = vik_viewport_get_center ( vvp );
594
595 if (vml->last_center == NULL) {
596 VikCoord *new_center = g_malloc(sizeof(VikCoord));
597 *new_center = *center;
598 vml->last_center = new_center;
599 vml->last_xmpp = vik_viewport_get_xmpp(vvp);
600 vml->last_ympp = vik_viewport_get_ympp(vvp);
601 return TRUE;
602 }
603
604 /* TODO: perhaps vik_coord_diff() */
605 if (vik_coord_equals(vml->last_center, center)
606 && (vml->last_xmpp == vik_viewport_get_xmpp(vvp))
607 && (vml->last_ympp == vik_viewport_get_ympp(vvp)))
608 return FALSE;
609
610 *(vml->last_center) = *center;
611 vml->last_xmpp = vik_viewport_get_xmpp(vvp);
612 vml->last_ympp = vik_viewport_get_ympp(vvp);
613 return TRUE;
614}
615
50a14534
EB
616static void maps_layer_draw_section ( VikMapsLayer *vml, VikViewport *vvp, VikCoord *ul, VikCoord *br )
617{
618 MapCoord ulm, brm;
619 gdouble xzoom = vik_viewport_get_xmpp ( vvp );
620 gdouble yzoom = vik_viewport_get_ympp ( vvp );
621 gdouble xshrinkfactor = 1.0, yshrinkfactor = 1.0;
732d1e25 622 gdouble existence_only = FALSE;
50a14534
EB
623
624 if ( vml->xmapzoom && (vml->xmapzoom != xzoom || vml->ymapzoom != yzoom) ) {
625 xshrinkfactor = vml->xmapzoom / xzoom;
626 yshrinkfactor = vml->ymapzoom / yzoom;
732d1e25
EB
627 xzoom = vml->xmapzoom;
628 yzoom = vml->xmapzoom;
629 if ( ! (xshrinkfactor > MIN_SHRINKFACTOR && xshrinkfactor < MAX_SHRINKFACTOR &&
630 yshrinkfactor > MIN_SHRINKFACTOR && yshrinkfactor < MAX_SHRINKFACTOR ) ) {
631 if ( xshrinkfactor > REAL_MIN_SHRINKFACTOR && yshrinkfactor > REAL_MIN_SHRINKFACTOR )
632 existence_only = TRUE;
633 else {
4c77d5e0 634 g_warning ( _("Cowardly refusing to draw tiles or existence of tiles beyond %d zoom out factor"), (int)( 1.0/REAL_MIN_SHRINKFACTOR));
732d1e25
EB
635 return;
636 }
50a14534
EB
637 }
638 }
639
640 /* coord -> ID */
820c59f4
GB
641 VikMapSource *map = MAPS_LAYER_NTH_TYPE(vml->maptype);
642 if ( vik_map_source_coord_to_mapcoord ( map, ul, xzoom, yzoom, &ulm ) &&
643 vik_map_source_coord_to_mapcoord ( map, br, xzoom, yzoom, &brm ) ) {
50a14534
EB
644
645 /* loop & draw */
646 gint x, y;
647 gint xmin = MIN(ulm.x, brm.x), xmax = MAX(ulm.x, brm.x);
648 gint ymin = MIN(ulm.y, brm.y), ymax = MAX(ulm.y, brm.y);
820c59f4 649 gint mode = vik_map_source_get_uniq_id(map);
50a14534
EB
650
651 VikCoord coord;
652 gint xx, yy, width, height;
653 GdkPixbuf *pixbuf;
654
655 guint max_path_len = strlen(vml->cache_dir) + 40;
656 gchar *path_buf = g_malloc ( max_path_len * sizeof(char) );
657
732d1e25 658 if ( (!existence_only) && vml->autodownload && should_start_autodownload(vml, vvp)) {
214f9ac2
QT
659#ifdef DEBUG
660 fputs(stderr, "DEBUG: Starting autodownload\n");
661#endif
0f08bd0d 662 if ( vik_map_source_supports_if_modified_since (map) )
245f48f5
GB
663 // Try to download newer tiles
664 start_download_thread ( vml, vvp, ul, br, REDOWNLOAD_NEW );
665 else
666 // Download only missing tiles
667 start_download_thread ( vml, vvp, ul, br, REDOWNLOAD_NONE );
10ca2bfe 668 }
50a14534 669
820c59f4 670 if ( vik_map_source_get_tilesize_x(map) == 0 && !existence_only ) {
50a14534
EB
671 for ( x = xmin; x <= xmax; x++ ) {
672 for ( y = ymin; y <= ymax; y++ ) {
673 ulm.x = x;
674 ulm.y = y;
675 pixbuf = get_pixbuf ( vml, mode, &ulm, path_buf, max_path_len, xshrinkfactor, yshrinkfactor );
676 if ( pixbuf ) {
677 width = gdk_pixbuf_get_width ( pixbuf );
678 height = gdk_pixbuf_get_height ( pixbuf );
679
820c59f4 680 vik_map_source_mapcoord_to_center_coord ( map, &ulm, &coord );
50a14534
EB
681 vik_viewport_coord_to_screen ( vvp, &coord, &xx, &yy );
682 xx -= (width/2);
683 yy -= (height/2);
684
685 vik_viewport_draw_pixbuf ( vvp, pixbuf, 0, 0, xx, yy, width, height );
686 }
687 }
688 }
689 } else { /* tilesize is known, don't have to keep converting coords */
820c59f4
GB
690 gdouble tilesize_x = vik_map_source_get_tilesize_x(map) * xshrinkfactor;
691 gdouble tilesize_y = vik_map_source_get_tilesize_y(map) * yshrinkfactor;
50a14534
EB
692 /* ceiled so tiles will be maximum size in the case of funky shrinkfactor */
693 gint tilesize_x_ceil = ceil ( tilesize_x );
694 gint tilesize_y_ceil = ceil ( tilesize_y );
695 gint8 xinc = (ulm.x == xmin) ? 1 : -1;
696 gint8 yinc = (ulm.y == ymin) ? 1 : -1;
697 gdouble xx, yy; gint xx_tmp, yy_tmp;
698 gint base_yy, xend, yend;
732d1e25
EB
699
700 GdkGC *black_gc = GTK_WIDGET(vvp)->style->black_gc;
701
50a14534
EB
702 xend = (xinc == 1) ? (xmax+1) : (xmin-1);
703 yend = (yinc == 1) ? (ymax+1) : (ymin-1);
704
820c59f4 705 vik_map_source_mapcoord_to_center_coord ( map, &ulm, &coord );
50a14534
EB
706 vik_viewport_coord_to_screen ( vvp, &coord, &xx_tmp, &yy_tmp );
707 xx = xx_tmp; yy = yy_tmp;
708 /* above trick so xx,yy doubles. this is so shrinkfactors aren't rounded off
709 * eg if tile size 128, shrinkfactor 0.333 */
710 xx -= (tilesize_x/2);
711 base_yy = yy - (tilesize_y/2);
712
713 for ( x = ((xinc == 1) ? xmin : xmax); x != xend; x+=xinc ) {
714 yy = base_yy;
715 for ( y = ((yinc == 1) ? ymin : ymax); y != yend; y+=yinc ) {
716 ulm.x = x;
717 ulm.y = y;
732d1e25
EB
718
719 if ( existence_only ) {
720 g_snprintf ( path_buf, max_path_len, DIRSTRUCTURE,
721 vml->cache_dir, mode,
722 ulm.scale, ulm.z, ulm.x, ulm.y );
45acf79e 723 if ( g_file_test ( path_buf, G_FILE_TEST_EXISTS ) == TRUE ) {
732d1e25
EB
724 vik_viewport_draw_line ( vvp, black_gc, xx+tilesize_x_ceil, yy, xx, yy+tilesize_y_ceil );
725 }
726 } else {
727 pixbuf = get_pixbuf ( vml, mode, &ulm, path_buf, max_path_len, xshrinkfactor, yshrinkfactor );
728 if ( pixbuf )
729 vik_viewport_draw_pixbuf ( vvp, pixbuf, 0, 0, xx, yy, tilesize_x_ceil, tilesize_y_ceil );
91dc4449
JJ
730 else {
731 /* retry with bigger shrinkfactor */
732 int scale_inc;
733 for (scale_inc = 1; scale_inc < 4; scale_inc ++) {
734 int scale_factor = 1 << scale_inc; /* 2^scale_inc */
735 MapCoord ulm2 = ulm;
736 ulm2.x = ulm.x / scale_factor;
737 ulm2.y = ulm.y / scale_factor;
738 ulm2.scale = ulm.scale + scale_inc;
739 pixbuf = get_pixbuf ( vml, mode, &ulm2, path_buf, max_path_len, xshrinkfactor * scale_factor, yshrinkfactor * scale_factor );
740 if ( pixbuf ) {
741 gint src_x = (ulm.x % scale_factor) * tilesize_x_ceil;
742 gint src_y = (ulm.y % scale_factor) * tilesize_y_ceil;
743 vik_viewport_draw_pixbuf ( vvp, pixbuf, src_x, src_y, xx, yy, tilesize_x_ceil, tilesize_y_ceil );
744 break;
745 }
746 }
747 }
732d1e25 748 }
50a14534
EB
749
750 yy += tilesize_y;
751 }
752 xx += tilesize_x;
753 }
754 }
755
756 g_free ( path_buf );
757 }
758}
759
760static void maps_layer_draw ( VikMapsLayer *vml, VikViewport *vvp )
761{
820c59f4 762 if ( vik_map_source_get_drawmode(MAPS_LAYER_NTH_TYPE(vml->maptype)) == vik_viewport_get_drawmode ( vvp ) )
50a14534
EB
763 {
764 VikCoord ul, br;
765
766 /* get corner coords */
767 if ( vik_viewport_get_coord_mode ( vvp ) == VIK_COORD_UTM && ! vik_viewport_is_one_zone ( vvp ) ) {
768 /* UTM multi-zone stuff by Kit Transue */
769 gchar leftmost_zone, rightmost_zone, i;
770 leftmost_zone = vik_viewport_leftmost_zone( vvp );
771 rightmost_zone = vik_viewport_rightmost_zone( vvp );
772 for ( i = leftmost_zone; i <= rightmost_zone; ++i ) {
773 vik_viewport_corners_for_zonen ( vvp, i, &ul, &br );
774 maps_layer_draw_section ( vml, vvp, &ul, &br );
775 }
776 }
777 else {
778 vik_viewport_screen_to_coord ( vvp, 0, 0, &ul );
779 vik_viewport_screen_to_coord ( vvp, vik_viewport_get_width(vvp), vik_viewport_get_height(vvp), &br );
780
781 maps_layer_draw_section ( vml, vvp, &ul, &br );
782 }
783 }
784}
785
786/*************************/
787/****** DOWNLOADING ******/
788/*************************/
789
790/* pass along data to thread, exists even if layer is deleted. */
791typedef struct {
792 gchar *cache_dir;
793 gchar *filename_buf;
794 gint x0, y0, xf, yf;
795 MapCoord mapcoord;
796 gint maptype;
797 gint maxlen;
798 gint mapstoget;
799 gint redownload;
7114e879 800 gboolean refresh_display;
550fd035
QT
801 VikMapsLayer *vml;
802 VikViewport *vvp;
803 gboolean map_layer_alive;
804 GMutex *mutex;
50a14534
EB
805} MapDownloadInfo;
806
807static void mdi_free ( MapDownloadInfo *mdi )
808{
550fd035 809 g_mutex_free(mdi->mutex);
50a14534 810 g_free ( mdi->cache_dir );
e65028db 811 mdi->cache_dir = NULL;
50a14534 812 g_free ( mdi->filename_buf );
e65028db 813 mdi->filename_buf = NULL;
50a14534
EB
814 g_free ( mdi );
815}
816
7bb60307 817static void weak_ref_cb(gpointer ptr, GObject * dead_vml)
550fd035 818{
7bb60307 819 MapDownloadInfo *mdi = ptr;
550fd035
QT
820 g_mutex_lock(mdi->mutex);
821 mdi->map_layer_alive = FALSE;
822 g_mutex_unlock(mdi->mutex);
823}
824
634eca0a 825static int map_download_thread ( MapDownloadInfo *mdi, gpointer threaddata )
50a14534 826{
825413ba 827 void *handle = vik_map_source_download_handle_init(MAPS_LAYER_NTH_TYPE(mdi->maptype));
50a14534
EB
828 guint donemaps = 0;
829 gint x, y;
830 for ( x = mdi->x0; x <= mdi->xf; x++ )
831 {
832 for ( y = mdi->y0; y <= mdi->yf; y++ )
833 {
94493114 834 gboolean remove_mem_cache = FALSE;
84628352 835 gboolean need_download = FALSE;
50a14534 836 g_snprintf ( mdi->filename_buf, mdi->maxlen, DIRSTRUCTURE,
820c59f4 837 mdi->cache_dir, vik_map_source_get_uniq_id(MAPS_LAYER_NTH_TYPE(mdi->maptype)),
50a14534
EB
838 mdi->mapcoord.scale, mdi->mapcoord.z, x, y );
839
84628352 840 donemaps++;
634eca0a 841 int res = a_background_thread_progress ( threaddata, ((gdouble)donemaps) / mdi->mapstoget ); /* this also calls testcancel */
825413ba
SW
842 if (res != 0) {
843 vik_map_source_download_handle_cleanup(MAPS_LAYER_NTH_TYPE(mdi->maptype), handle);
634eca0a 844 return -1;
825413ba 845 }
84628352 846
50a14534 847 if ( mdi->redownload == REDOWNLOAD_ALL)
8c060406 848 g_remove ( mdi->filename_buf );
093c5c71 849
45acf79e 850 else if ( (mdi->redownload == REDOWNLOAD_BAD) && (g_file_test ( mdi->filename_buf, G_FILE_TEST_EXISTS ) == TRUE) )
50a14534
EB
851 {
852 /* see if this one is bad or what */
853 GError *gx = NULL;
854 GdkPixbuf *pixbuf = gdk_pixbuf_new_from_file ( mdi->filename_buf, &gx );
855 if (gx || (!pixbuf))
8c060406 856 g_remove ( mdi->filename_buf );
50a14534
EB
857 if ( pixbuf )
858 g_object_unref ( pixbuf );
859 if ( gx )
860 g_error_free ( gx );
861 }
862
45acf79e 863 if ( g_file_test ( mdi->filename_buf, G_FILE_TEST_EXISTS ) == FALSE )
50a14534 864 {
84628352
QT
865 need_download = TRUE;
866 if (( mdi->redownload != REDOWNLOAD_NONE ) &&
a0b59f2f 867 ( mdi->redownload != DOWNLOAD_OR_REFRESH ))
94493114
QT
868 remove_mem_cache = TRUE;
869 } else if ( mdi->redownload == DOWNLOAD_OR_REFRESH ) {
870 remove_mem_cache = TRUE;
6a4a29aa
JJ
871 } else if ( mdi->redownload == REDOWNLOAD_NEW) {
872 need_download = TRUE;
873 remove_mem_cache = TRUE;
94493114
QT
874 } else
875 continue;
876
94493114 877 mdi->mapcoord.x = x; mdi->mapcoord.y = y;
84628352
QT
878
879 if (need_download) {
825413ba 880 if ( vik_map_source_download( MAPS_LAYER_NTH_TYPE(mdi->maptype), &(mdi->mapcoord), mdi->filename_buf, handle))
94493114 881 continue;
84628352 882 }
94493114
QT
883
884 gdk_threads_enter();
885 g_mutex_lock(mdi->mutex);
886 if (remove_mem_cache)
820c59f4 887 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 888 if (mdi->refresh_display && mdi->map_layer_alive) {
94493114
QT
889 /* TODO: check if it's on visible area */
890 vik_layer_emit_update ( VIK_LAYER(mdi->vml) );
a0b59f2f 891 }
94493114
QT
892 g_mutex_unlock(mdi->mutex);
893 gdk_threads_leave();
894 mdi->mapcoord.x = mdi->mapcoord.y = 0; /* we're temporarily between downloads */
895
50a14534
EB
896 }
897 }
825413ba 898 vik_map_source_download_handle_cleanup(MAPS_LAYER_NTH_TYPE(mdi->maptype), handle);
04e54492
QT
899 g_mutex_lock(mdi->mutex);
900 if (mdi->map_layer_alive)
7bb60307 901 g_object_weak_unref(G_OBJECT(mdi->vml), weak_ref_cb, mdi);
04e54492 902 g_mutex_unlock(mdi->mutex);
634eca0a 903 return 0;
50a14534
EB
904}
905
906static void mdi_cancel_cleanup ( MapDownloadInfo *mdi )
907{
908 if ( mdi->mapcoord.x || mdi->mapcoord.y )
909 {
910 g_snprintf ( mdi->filename_buf, mdi->maxlen, DIRSTRUCTURE,
820c59f4 911 mdi->cache_dir, vik_map_source_get_uniq_id(MAPS_LAYER_NTH_TYPE(mdi->maptype)),
50a14534 912 mdi->mapcoord.scale, mdi->mapcoord.z, mdi->mapcoord.x, mdi->mapcoord.y );
45acf79e 913 if ( g_file_test ( mdi->filename_buf, G_FILE_TEST_EXISTS ) == TRUE)
50a14534 914 {
8c060406 915 g_remove ( mdi->filename_buf );
50a14534
EB
916 }
917 }
918}
919
920static void start_download_thread ( VikMapsLayer *vml, VikViewport *vvp, const VikCoord *ul, const VikCoord *br, gint redownload )
921{
922 gdouble xzoom = vml->xmapzoom ? vml->xmapzoom : vik_viewport_get_xmpp ( vvp );
923 gdouble yzoom = vml->ymapzoom ? vml->ymapzoom : vik_viewport_get_ympp ( vvp );
924 MapCoord ulm, brm;
820c59f4
GB
925 VikMapSource *map = MAPS_LAYER_NTH_TYPE(vml->maptype);
926 if ( vik_map_source_coord_to_mapcoord ( map, ul, xzoom, yzoom, &ulm )
927 && vik_map_source_coord_to_mapcoord ( map, br, xzoom, yzoom, &brm ) )
50a14534
EB
928 {
929 MapDownloadInfo *mdi = g_malloc ( sizeof(MapDownloadInfo) );
930 gint a, b;
931
550fd035
QT
932 mdi->vml = vml;
933 mdi->vvp = vvp;
934 mdi->map_layer_alive = TRUE;
935 mdi->mutex = g_mutex_new();
7114e879 936 mdi->refresh_display = TRUE;
550fd035 937
50a14534
EB
938 /* cache_dir and buffer for dest filename */
939 mdi->cache_dir = g_strdup ( vml->cache_dir );
940 mdi->maxlen = strlen ( vml->cache_dir ) + 40;
941 mdi->filename_buf = g_malloc ( mdi->maxlen * sizeof(gchar) );
942 mdi->maptype = vml->maptype;
943
944 mdi->mapcoord = ulm;
945
946 mdi->redownload = redownload;
947
948 mdi->x0 = MIN(ulm.x, brm.x);
949 mdi->xf = MAX(ulm.x, brm.x);
950 mdi->y0 = MIN(ulm.y, brm.y);
951 mdi->yf = MAX(ulm.y, brm.y);
952
953 mdi->mapstoget = 0;
954
955 if ( mdi->redownload ) {
956 mdi->mapstoget = (mdi->xf - mdi->x0 + 1) * (mdi->yf - mdi->y0 + 1);
957 } else {
958 /* calculate how many we need */
959 for ( a = mdi->x0; a <= mdi->xf; a++ )
960 {
961 for ( b = mdi->y0; b <= mdi->yf; b++ )
962 {
963 g_snprintf ( mdi->filename_buf, mdi->maxlen, DIRSTRUCTURE,
820c59f4 964 vml->cache_dir, vik_map_source_get_uniq_id(map), ulm.scale,
50a14534 965 ulm.z, a, b );
45acf79e 966 if ( g_file_test ( mdi->filename_buf, G_FILE_TEST_EXISTS ) == FALSE )
50a14534
EB
967 mdi->mapstoget++;
968 }
969 }
970 }
971
972 mdi->mapcoord.x = mdi->mapcoord.y = 0; /* for cleanup -- no current map */
973
974 if ( mdi->mapstoget )
975 {
97634600
GB
976 const gchar *tmp_str;
977 gchar *tmp;
50a14534 978
97634600
GB
979 if (redownload)
980 {
981 if (redownload == REDOWNLOAD_BAD)
982 tmp_str = ngettext("Redownloading up to %d %s map...", "Redownloading up to %d %s maps...", mdi->mapstoget);
983 else
984 tmp_str = ngettext("Redownloading %d %s map...", "Redownloading %d %s maps...", mdi->mapstoget);
985 }
986 else
987 {
988 tmp_str = ngettext("Downloading %d %s map...", "Downloading %d %s maps...", mdi->mapstoget);
989 }
990 tmp = g_strdup_printf ( tmp_str, mdi->mapstoget, MAPS_LAYER_NTH_LABEL(vml->maptype));
991
7bb60307 992 g_object_weak_ref(G_OBJECT(mdi->vml), weak_ref_cb, mdi);
50a14534
EB
993 /* launch the thread */
994 a_background_thread ( VIK_GTK_WINDOW_FROM_LAYER(vml), /* parent window */
995 tmp, /* description string */
996 (vik_thr_func) map_download_thread, /* function to call within thread */
997 mdi, /* pass along data */
998 (vik_thr_free_func) mdi_free, /* function to free pass along data */
999 (vik_thr_free_func) mdi_cancel_cleanup,
1000 mdi->mapstoget );
1001 g_free ( tmp );
1002 }
1003 else
1004 mdi_free ( mdi );
1005 }
1006}
1007
7114e879
QT
1008void maps_layer_download_section_without_redraw( VikMapsLayer *vml, VikViewport *vvp, VikCoord *ul, VikCoord *br, gdouble zoom)
1009{
7114e879 1010 MapCoord ulm, brm;
820c59f4 1011 VikMapSource *map = MAPS_LAYER_NTH_TYPE(vml->maptype);
7114e879 1012
820c59f4
GB
1013 if (!vik_map_source_coord_to_mapcoord(map, ul, zoom, zoom, &ulm)
1014 || !vik_map_source_coord_to_mapcoord(map, br, zoom, zoom, &brm)) {
4258f4e2 1015 g_warning("%s() coord_to_mapcoord() failed", __PRETTY_FUNCTION__);
7114e879
QT
1016 return;
1017 }
1018
1019 MapDownloadInfo *mdi = g_malloc(sizeof(MapDownloadInfo));
1020 gint i, j;
1021
1022 mdi->vml = vml;
1023 mdi->vvp = vvp;
1024 mdi->map_layer_alive = TRUE;
1025 mdi->mutex = g_mutex_new();
1026 mdi->refresh_display = FALSE;
1027
1028 mdi->cache_dir = g_strdup ( vml->cache_dir );
1029 mdi->maxlen = strlen ( vml->cache_dir ) + 40;
1030 mdi->filename_buf = g_malloc ( mdi->maxlen * sizeof(gchar) );
1031 mdi->maptype = vml->maptype;
1032
1033 mdi->mapcoord = ulm;
1034
1035 mdi->redownload = REDOWNLOAD_NONE;
1036
1037 mdi->x0 = MIN(ulm.x, brm.x);
1038 mdi->xf = MAX(ulm.x, brm.x);
1039 mdi->y0 = MIN(ulm.y, brm.y);
1040 mdi->yf = MAX(ulm.y, brm.y);
1041
1042 mdi->mapstoget = 0;
1043
1044 for (i = mdi->x0; i <= mdi->xf; i++) {
1045 for (j = mdi->y0; j <= mdi->yf; j++) {
1046 g_snprintf ( mdi->filename_buf, mdi->maxlen, DIRSTRUCTURE,
820c59f4 1047 vml->cache_dir, vik_map_source_get_uniq_id(map), ulm.scale,
7114e879 1048 ulm.z, i, j );
45acf79e 1049 if ( g_file_test ( mdi->filename_buf, G_FILE_TEST_EXISTS ) == FALSE )
7114e879
QT
1050 mdi->mapstoget++;
1051 }
1052 }
1053
1054 mdi->mapcoord.x = mdi->mapcoord.y = 0; /* for cleanup -- no current map */
1055
1056 if (mdi->mapstoget) {
4c77d5e0
GB
1057 gchar *tmp;
1058 const gchar *fmt;
eb6b0125
JJ
1059 fmt = ngettext("Downloading %d %s map...",
1060 "Downloading %d %s maps...",
1061 mdi->mapstoget);
4c77d5e0 1062 tmp = g_strdup_printf ( fmt, mdi->mapstoget, MAPS_LAYER_NTH_LABEL(vml->maptype) );
7114e879
QT
1063
1064 g_object_weak_ref(G_OBJECT(mdi->vml), weak_ref_cb, mdi);
1065 /* launch the thread */
1066 a_background_thread ( VIK_GTK_WINDOW_FROM_LAYER(vml), /* parent window */
1067 tmp, /* description string */
1068 (vik_thr_func) map_download_thread, /* function to call within thread */
1069 mdi, /* pass along data */
1070 (vik_thr_free_func) mdi_free, /* function to free pass along data */
1071 (vik_thr_free_func) mdi_cancel_cleanup,
1072 mdi->mapstoget );
1073 g_free ( tmp );
1074 }
1075 else
1076 mdi_free ( mdi );
1077}
1078
50a14534
EB
1079static void maps_layer_redownload_bad ( VikMapsLayer *vml )
1080{
1081 start_download_thread ( vml, vml->redownload_vvp, &(vml->redownload_ul), &(vml->redownload_br), REDOWNLOAD_BAD );
1082}
a7c1acf1 1083
50a14534
EB
1084static void maps_layer_redownload_all ( VikMapsLayer *vml )
1085{
1086 start_download_thread ( vml, vml->redownload_vvp, &(vml->redownload_ul), &(vml->redownload_br), REDOWNLOAD_ALL );
1087}
1088
a7c1acf1
GB
1089static void maps_layer_redownload_new ( VikMapsLayer *vml )
1090{
1091 start_download_thread ( vml, vml->redownload_vvp, &(vml->redownload_ul), &(vml->redownload_br), REDOWNLOAD_NEW );
1092}
1093
50a14534
EB
1094static gboolean maps_layer_download_release ( VikMapsLayer *vml, GdkEventButton *event, VikViewport *vvp )
1095{
941aa6e9
AF
1096 if (!vml || vml->vl.type != VIK_LAYER_MAPS)
1097 return FALSE;
50a14534
EB
1098 if ( vml->dl_tool_x != -1 && vml->dl_tool_y != -1 )
1099 {
1100 if ( event->button == 1 )
1101 {
1102 VikCoord ul, br;
1103 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 );
1104 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 1105 start_download_thread ( vml, vvp, &ul, &br, DOWNLOAD_OR_REFRESH );
50a14534
EB
1106 vml->dl_tool_x = vml->dl_tool_y = -1;
1107 return TRUE;
1108 }
1109 else
1110 {
1111 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) );
1112 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) );
1113
1114 vml->redownload_vvp = vvp;
1115
1116 vml->dl_tool_x = vml->dl_tool_y = -1;
1117
1118 if ( ! vml->dl_right_click_menu ) {
1119 GtkWidget *item;
1120 vml->dl_right_click_menu = GTK_MENU ( gtk_menu_new () );
1121
4c77d5e0 1122 item = gtk_menu_item_new_with_label ( _("Redownload bad map(s)") );
50a14534
EB
1123 g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(maps_layer_redownload_bad), vml );
1124 gtk_menu_shell_append ( GTK_MENU_SHELL(vml->dl_right_click_menu), item );
1125
a7c1acf1
GB
1126 item = gtk_menu_item_new_with_label ( _("Redownload new map(s)") );
1127 g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(maps_layer_redownload_new), vml );
1128 gtk_menu_shell_append ( GTK_MENU_SHELL(vml->dl_right_click_menu), item );
1129
4c77d5e0 1130 item = gtk_menu_item_new_with_label ( _("Redownload all map(s)") );
50a14534
EB
1131 g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(maps_layer_redownload_all), vml );
1132 gtk_menu_shell_append ( GTK_MENU_SHELL(vml->dl_right_click_menu), item );
1133 }
1134
1135 gtk_menu_popup ( vml->dl_right_click_menu, NULL, NULL, NULL, NULL, event->button, event->time );
1136 gtk_widget_show_all ( GTK_WIDGET(vml->dl_right_click_menu) );
1137 }
1138 }
1139 return FALSE;
1140}
1141
941aa6e9
AF
1142static gpointer maps_layer_download_create ( VikWindow *vw, VikViewport *vvp)
1143{
1144 return vvp;
1145}
1146
50a14534
EB
1147static gboolean maps_layer_download_click ( VikMapsLayer *vml, GdkEventButton *event, VikViewport *vvp )
1148{
1149 MapCoord tmp;
941aa6e9
AF
1150 if (!vml || vml->vl.type != VIK_LAYER_MAPS)
1151 return FALSE;
820c59f4
GB
1152 VikMapSource *map = MAPS_LAYER_NTH_TYPE(vml->maptype);
1153 if ( vik_map_source_get_drawmode(map) == vik_viewport_get_drawmode ( vvp ) &&
1154 vik_map_source_coord_to_mapcoord ( map, vik_viewport_get_center ( vvp ),
50a14534
EB
1155 vml->xmapzoom ? vml->xmapzoom : vik_viewport_get_xmpp ( vvp ),
1156 vml->ymapzoom ? vml->ymapzoom : vik_viewport_get_ympp ( vvp ),
1157 &tmp ) ) {
1158 vml->dl_tool_x = event->x, vml->dl_tool_y = event->y;
1159 return TRUE;
1160 }
1161 return FALSE;
1162
1163
1164#if 0
1165 if ( __map_types[vml->maptype].drawmode == vik_viewport_get_drawmode ( vvp ) )
1166 {
1167 VikCoord coord;
1168 MapCoord mapcoord;
1169 vik_viewport_screen_to_coord ( vvp, event->x, event->y, &coord );
1170 if ( __map_types[vml->maptype].coord_to_mapcoord ( &coord,
1171 vml->xmapzoom ? vml->xmapzoom : vik_viewport_get_xmpp ( vvp ),
1172 vml->ymapzoom ? vml->ymapzoom : vik_viewport_get_ympp ( vvp ),
1173 &mapcoord ) ) {
1174 gchar *filename_buf = g_strdup_printf ( DIRSTRUCTURE,
1175 vml->cache_dir, __map_types[vml->maptype].uniq_id,
1176 mapcoord.scale, mapcoord.z, mapcoord.x, mapcoord.y );
1177
1178 __map_types[vml->maptype].download ( &mapcoord, filename_buf );
1179 g_free ( filename_buf );
1180 vik_layer_emit_update ( VIK_LAYER(vml) );
1181 return TRUE;
1182 }
1183 }
1184 return FALSE;
1185#endif
1186}
1187
50817314 1188static void download_onscreen_maps ( gpointer vml_vvp[2], gint redownload )
50a14534
EB
1189{
1190 VikMapsLayer *vml = vml_vvp[0];
1191 VikViewport *vvp = vml_vvp[1];
314c1ccc 1192 VikViewportDrawMode vp_drawmode = vik_viewport_get_drawmode ( vvp );
50a14534
EB
1193
1194 gdouble xzoom = vml->xmapzoom ? vml->xmapzoom : vik_viewport_get_xmpp ( vvp );
1195 gdouble yzoom = vml->ymapzoom ? vml->ymapzoom : vik_viewport_get_ympp ( vvp );
1196
1197 VikCoord ul, br;
1198 MapCoord ulm, brm;
1199
1200 vik_viewport_screen_to_coord ( vvp, 0, 0, &ul );
1201 vik_viewport_screen_to_coord ( vvp, vik_viewport_get_width(vvp), vik_viewport_get_height(vvp), &br );
1202
820c59f4
GB
1203 VikMapSource *map = MAPS_LAYER_NTH_TYPE(vml->maptype);
1204 if ( vik_map_source_get_drawmode(map) == vp_drawmode &&
1205 vik_map_source_coord_to_mapcoord ( map, &ul, xzoom, yzoom, &ulm ) &&
1206 vik_map_source_coord_to_mapcoord ( map, &br, xzoom, yzoom, &brm ) )
50817314 1207 start_download_thread ( vml, vvp, &ul, &br, redownload );
820c59f4
GB
1208 else if (vik_map_source_get_drawmode(map) != vp_drawmode) {
1209 const gchar *drawmode_name = vik_viewport_get_drawmode_name (vvp, vik_map_source_get_drawmode(map));
4c77d5e0 1210 gchar *err = g_strdup_printf(_("Wrong drawmode for this map.\nSelect \"%s\" from View menu and try again."), _(drawmode_name));
314c1ccc
QT
1211 a_dialog_error_msg ( VIK_GTK_WINDOW_FROM_LAYER(vml), err );
1212 g_free(err);
1213 }
50a14534 1214 else
4c77d5e0 1215 a_dialog_error_msg ( VIK_GTK_WINDOW_FROM_LAYER(vml), _("Wrong zoom level for this map.") );
50a14534
EB
1216
1217}
1218
6a4a29aa 1219static void maps_layer_download_missing_onscreen_maps ( gpointer vml_vvp[2] )
50817314
GB
1220{
1221 download_onscreen_maps( vml_vvp, REDOWNLOAD_NONE);
1222}
1223
6a4a29aa
JJ
1224static void maps_layer_download_new_onscreen_maps ( gpointer vml_vvp[2] )
1225{
1226 download_onscreen_maps( vml_vvp, REDOWNLOAD_NEW);
1227}
1228
50817314
GB
1229static void maps_layer_redownload_all_onscreen_maps ( gpointer vml_vvp[2] )
1230{
1231 download_onscreen_maps( vml_vvp, REDOWNLOAD_ALL);
1232}
1233
50a14534
EB
1234static void maps_layer_add_menu_items ( VikMapsLayer *vml, GtkMenu *menu, VikLayersPanel *vlp )
1235{
1236 static gpointer pass_along[2];
1237 GtkWidget *item;
1238 pass_along[0] = vml;
1239 pass_along[1] = vik_layers_panel_get_viewport( VIK_LAYERS_PANEL(vlp) );
1240
1241 item = gtk_menu_item_new();
1242 gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item );
1243 gtk_widget_show ( item );
1244
6a4a29aa
JJ
1245 item = gtk_menu_item_new_with_label ( _("Download missing Onscreen Maps") );
1246 g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(maps_layer_download_missing_onscreen_maps), pass_along );
50a14534
EB
1247 gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
1248 gtk_widget_show ( item );
50817314 1249
0f08bd0d 1250 if ( vik_map_source_supports_if_modified_since (MAPS_LAYER_NTH_TYPE(vml->maptype)) ) {
6a4a29aa
JJ
1251 item = gtk_menu_item_new_with_label ( _("Download new Onscreen Maps from server") );
1252 g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(maps_layer_download_new_onscreen_maps), pass_along );
1253 gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
1254 gtk_widget_show ( item );
1255 }
1256
1b86e056 1257 /* TODO Add GTK_STOCK_REFRESH icon */
4c77d5e0 1258 item = gtk_menu_item_new_with_label ( _("Refresh Onscreen Tiles") );
50817314
GB
1259 g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(maps_layer_redownload_all_onscreen_maps), pass_along );
1260 gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
1261 gtk_widget_show ( item );
50a14534 1262}