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