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