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