2 * viking -- GPS Data and Topo Analyzer, Explorer, and Manager
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>
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.
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.
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
29 #define MAX_SHRINKFACTOR 8.0000001 /* zoom 1 viewing 8-tiles */
30 #define MIN_SHRINKFACTOR 0.0312499 /* zoom 32 viewing 1-tiles */
32 #define REAL_MIN_SHRINKFACTOR 0.0039062499 /* if shrinkfactor is between MAX and REAL_MAX, will only check for existence */
35 #include <gdk-pixbuf/gdk-pixdata.h>
37 #include <glib/gstdio.h>
38 #include <glib/gi18n.h>
51 #include "viktreeview.h"
52 #include "vikviewport.h"
54 #include "vikmapslayer.h"
61 /* only for dialog.h -- ugh */
62 #include "vikwaypoint.h"
64 #include "preferences.h"
66 #include "vikstatus.h"
67 #include "background.h"
69 #include "vikaggregatelayer.h"
70 #include "viklayerspanel.h"
74 #include "icons/icons.h"
76 /****** MAP TYPES ******/
78 static GList *__map_types = NULL;
80 #define NUM_MAP_TYPES g_list_length(__map_types)
82 /* List of label for each map type */
83 static gchar **params_maptypes = NULL;
85 /* Corresponding IDS. (Cf. field uniq_id in VikMapsLayer struct) */
86 static guint *params_maptypes_ids = NULL;
88 /******** MAPZOOMS *********/
90 static gchar *params_mapzooms[] = { N_("Use Viking Zoom Level"), "0.25", "0.5", "1", "2", "4", "8", "16", "32", "64", "128", "256", "512", "1024", "USGS 10k", "USGS 24k", "USGS 25k", "USGS 50k", "USGS 100k", "USGS 200k", "USGS 250k", NULL };
91 static gdouble __mapzooms_x[] = { 0.0, 0.25, 0.5, 1.0, 2.0, 4.0, 8.0, 16.0, 32.0, 64.0, 128.0, 256.0, 512.0, 1024.0, 1.016, 2.4384, 2.54, 5.08, 10.16, 20.32, 25.4 };
92 static gdouble __mapzooms_y[] = { 0.0, 0.25, 0.5, 1.0, 2.0, 4.0, 8.0, 16.0, 32.0, 64.0, 128.0, 256.0, 512.0, 1024.0, 1.016, 2.4384, 2.54, 5.08, 10.16, 20.32, 25.4 };
94 #define NUM_MAPZOOMS (sizeof(params_mapzooms)/sizeof(params_mapzooms[0]) - 1)
96 /**************************/
99 static void maps_layer_post_read (VikLayer *vl, VikViewport *vp, gboolean from_file);
100 static const gchar* maps_layer_tooltip ( VikMapsLayer *vml );
101 static void maps_layer_marshall( VikMapsLayer *vml, guint8 **data, gint *len );
102 static VikMapsLayer *maps_layer_unmarshall( guint8 *data, gint len, VikViewport *vvp );
103 static gboolean maps_layer_set_param ( VikMapsLayer *vml, guint16 id, VikLayerParamData data, VikViewport *vvp, gboolean is_file_operation );
104 static VikLayerParamData maps_layer_get_param ( VikMapsLayer *vml, guint16 id, gboolean is_file_operation );
105 static void maps_layer_draw ( VikMapsLayer *vml, VikViewport *vvp );
106 static VikMapsLayer *maps_layer_new ( VikViewport *vvp );
107 static void maps_layer_free ( VikMapsLayer *vml );
108 static gboolean maps_layer_download_release ( VikMapsLayer *vml, GdkEventButton *event, VikViewport *vvp );
109 static gboolean maps_layer_download_click ( VikMapsLayer *vml, GdkEventButton *event, VikViewport *vvp );
110 static gpointer maps_layer_download_create ( VikWindow *vw, VikViewport *vvp );
111 static void maps_layer_set_cache_dir ( VikMapsLayer *vml, const gchar *dir );
112 static void start_download_thread ( VikMapsLayer *vml, VikViewport *vvp, const VikCoord *ul, const VikCoord *br, gint redownload );
113 static void maps_layer_add_menu_items ( VikMapsLayer *vml, GtkMenu *menu, VikLayersPanel *vlp );
114 static guint map_uniq_id_to_index ( guint uniq_id );
117 static VikLayerParamScale params_scales[] = {
118 /* min, max, step, digits (decimal places) */
119 { 0, 255, 3, 0 }, /* alpha */
122 VikLayerParam maps_layer_params[] = {
123 { "mode", VIK_LAYER_PARAM_UINT, VIK_LAYER_GROUP_NONE, N_("Map Type:"), VIK_LAYER_WIDGET_COMBOBOX, NULL, NULL, NULL },
124 { "directory", VIK_LAYER_PARAM_STRING, VIK_LAYER_GROUP_NONE, N_("Maps Directory:"), VIK_LAYER_WIDGET_FOLDERENTRY, NULL, NULL, NULL },
125 { "alpha", VIK_LAYER_PARAM_UINT, VIK_LAYER_GROUP_NONE, N_("Alpha:"), VIK_LAYER_WIDGET_HSCALE, params_scales, NULL,
126 N_("Control the Alpha value for transparency effects") },
127 { "autodownload", VIK_LAYER_PARAM_BOOLEAN, VIK_LAYER_GROUP_NONE, N_("Autodownload maps:"), VIK_LAYER_WIDGET_CHECKBUTTON, NULL, NULL, NULL },
128 { "adlonlymissing", VIK_LAYER_PARAM_BOOLEAN, VIK_LAYER_GROUP_NONE, N_("Autodownload Only Gets Missing Maps:"), VIK_LAYER_WIDGET_CHECKBUTTON, NULL, NULL,
129 N_("Using this option avoids attempting to update already acquired tiles. This can be useful if you want to restrict the network usage, without having to resort to manual control. Only applies when 'Autodownload Maps' is on.") },
130 { "mapzoom", VIK_LAYER_PARAM_UINT, VIK_LAYER_GROUP_NONE, N_("Zoom Level:"), VIK_LAYER_WIDGET_COMBOBOX, params_mapzooms, NULL,
131 N_("Determines the method of displaying map tiles for the current zoom level. 'Viking Zoom Level' uses the best matching level, otherwise setting a fixed value will always use map tiles of the specified value regardless of the actual zoom level.") },
144 static VikToolInterface maps_tools[] = {
145 { { "MapsDownload", "vik-icon-Maps Download", N_("_Maps Download"), NULL, N_("Maps Download"), 0 },
146 (VikToolConstructorFunc) maps_layer_download_create,
150 (VikToolMouseFunc) maps_layer_download_click,
152 (VikToolMouseFunc) maps_layer_download_release,
155 GDK_CURSOR_IS_PIXMAP, &cursor_mapdl_pixbuf },
158 VikLayerInterface vik_maps_layer_interface = {
162 &vikmapslayer_pixbuf,
165 sizeof(maps_tools) / sizeof(maps_tools[0]),
174 (VikLayerFuncCreate) maps_layer_new,
175 (VikLayerFuncRealize) NULL,
176 (VikLayerFuncPostRead) maps_layer_post_read,
177 (VikLayerFuncFree) maps_layer_free,
179 (VikLayerFuncProperties) NULL,
180 (VikLayerFuncDraw) maps_layer_draw,
181 (VikLayerFuncChangeCoordMode) NULL,
183 (VikLayerFuncSetMenuItemsSelection) NULL,
184 (VikLayerFuncGetMenuItemsSelection) NULL,
186 (VikLayerFuncAddMenuItems) maps_layer_add_menu_items,
187 (VikLayerFuncSublayerAddMenuItems) NULL,
189 (VikLayerFuncSublayerRenameRequest) NULL,
190 (VikLayerFuncSublayerToggleVisible) NULL,
191 (VikLayerFuncSublayerTooltip) NULL,
192 (VikLayerFuncLayerTooltip) maps_layer_tooltip,
193 (VikLayerFuncLayerSelected) NULL,
195 (VikLayerFuncMarshall) maps_layer_marshall,
196 (VikLayerFuncUnmarshall) maps_layer_unmarshall,
198 (VikLayerFuncSetParam) maps_layer_set_param,
199 (VikLayerFuncGetParam) maps_layer_get_param,
201 (VikLayerFuncReadFileData) NULL,
202 (VikLayerFuncWriteFileData) NULL,
204 (VikLayerFuncDeleteItem) NULL,
205 (VikLayerFuncCutItem) NULL,
206 (VikLayerFuncCopyItem) NULL,
207 (VikLayerFuncPasteItem) NULL,
208 (VikLayerFuncFreeCopiedItem) NULL,
209 (VikLayerFuncDragDropRequest) NULL,
211 (VikLayerFuncSelectClick) NULL,
212 (VikLayerFuncSelectMove) NULL,
213 (VikLayerFuncSelectRelease) NULL,
214 (VikLayerFuncSelectedViewportMenu) NULL,
217 struct _VikMapsLayer {
223 gdouble xmapzoom, ymapzoom;
225 gboolean autodownload;
226 gboolean adl_only_missing;
227 VikCoord *last_center;
231 gint dl_tool_x, dl_tool_y;
233 GtkMenu *dl_right_click_menu;
234 VikCoord redownload_ul, redownload_br; /* right click menu only */
235 VikViewport *redownload_vvp;
237 gboolean license_notice_shown; // FALSE for new maps only, otherwise
238 // TRUE for saved maps & other layer changes as we don't need to show it again
241 enum { REDOWNLOAD_NONE = 0, /* download only missing maps */
242 REDOWNLOAD_BAD, /* download missing and bad maps */
243 REDOWNLOAD_NEW, /* download missing maps that are newer on server only */
244 REDOWNLOAD_ALL, /* download all maps */
245 DOWNLOAD_OR_REFRESH }; /* download missing maps and refresh cache */
247 static VikLayerParam prefs[] = {
248 { VIKING_PREFERENCES_NAMESPACE "maplayer_default_dir", VIK_LAYER_PARAM_STRING, VIK_LAYER_GROUP_NONE, N_("Default maplayer directory:"), VIK_LAYER_WIDGET_FOLDERENTRY, NULL, NULL, N_("Choose a directory to store cached Map tiles for this layer") },
251 void maps_layer_init ()
253 VikLayerParamData tmp;
254 tmp.s = maps_layer_default_dir();
255 a_preferences_register(prefs, tmp, VIKING_PREFERENCES_GROUP_KEY);
258 /****************************************/
259 /******** MAPS LAYER TYPES **************/
260 /****************************************/
262 int _get_index_for_id ( guint id )
265 while (params_maptypes_ids[index] != 0)
267 if (params_maptypes_ids[index] == id)
274 void _add_map_source ( guint id, const char *label, VikMapSource *map )
278 len = g_strv_length (params_maptypes);
280 params_maptypes = g_realloc (params_maptypes, (len+2)*sizeof(gchar*));
281 params_maptypes[len] = g_strdup (label);
282 params_maptypes[len+1] = NULL;
285 params_maptypes_ids = g_realloc (params_maptypes_ids, (len+2)*sizeof(guint));
286 params_maptypes_ids[len] = id;
287 params_maptypes_ids[len+1] = 0;
289 /* We have to clone */
290 VikMapSource *clone = VIK_MAP_SOURCE(g_object_ref(map));
291 /* Register the clone in the list */
292 __map_types = g_list_append(__map_types, clone);
295 We have to ensure the mode LayerParam references the up-to-date
299 memcpy(&maps_layer_params[0].widget_data, ¶ms_maptypes, sizeof(gpointer));
300 memcpy(&maps_layer_params[0].extra_widget_data, ¶ms_maptypes_ids, sizeof(gpointer));
302 maps_layer_params[0].widget_data = params_maptypes;
303 maps_layer_params[0].extra_widget_data = params_maptypes_ids;
306 void _update_map_source ( const char *label, VikMapSource *map, int index )
308 GList *item = g_list_nth (__map_types, index);
309 g_object_unref (item->data);
310 item->data = g_object_ref (map);
311 /* Change previous data */
312 g_free (params_maptypes[index]);
313 params_maptypes[index] = g_strdup (label);
317 * maps_layer_register_map_source:
318 * @map: the new VikMapSource
320 * Register a new VikMapSource.
321 * Override existing one (equality of id).
323 void maps_layer_register_map_source ( VikMapSource *map )
325 g_assert(map != NULL);
327 guint id = vik_map_source_get_uniq_id(map);
328 const char *label = vik_map_source_get_label(map);
329 g_assert(label != NULL);
331 int previous = map_uniq_id_to_index (id);
332 if (previous != NUM_MAP_TYPES)
334 _update_map_source (label, map, previous);
338 _add_map_source (id, label, map);
342 #define MAPS_LAYER_NTH_LABEL(n) (params_maptypes[n])
343 #define MAPS_LAYER_NTH_ID(n) (params_maptypes_ids[n])
344 #define MAPS_LAYER_NTH_TYPE(n) (VIK_MAP_SOURCE(g_list_nth_data(__map_types, (n))))
346 gint vik_maps_layer_get_map_type(VikMapsLayer *vml)
348 return(vml->maptype);
351 gchar *vik_maps_layer_get_map_label(VikMapsLayer *vml)
353 return(g_strdup(MAPS_LAYER_NTH_LABEL(vml->maptype)));
356 /****************************************/
357 /******** CACHE DIR STUFF ***************/
358 /****************************************/
360 #define DIRECTDIRACCESS "%s%d" G_DIR_SEPARATOR_S "%d" G_DIR_SEPARATOR_S "%d%s"
361 #define DIRSTRUCTURE "%st%ds%dz%d" G_DIR_SEPARATOR_S "%d" G_DIR_SEPARATOR_S "%d"
362 #define MAPS_CACHE_DIR maps_layer_default_dir()
366 #define GLOBAL_MAPS_DIR "C:\\VIKING-MAPS\\"
367 #define LOCAL_MAPS_DIR "VIKING-MAPS"
368 #elif defined __APPLE__
370 #define GLOBAL_MAPS_DIR "/Library/cache/Viking/maps/"
371 #define LOCAL_MAPS_DIR "/Library/Application Support/Viking/viking-maps"
374 #define GLOBAL_MAPS_DIR "/var/cache/maps/"
375 #define LOCAL_MAPS_DIR ".viking-maps"
378 gchar *maps_layer_default_dir ()
380 static gchar *defaultdir = NULL;
383 /* Thanks to Mike Davison for the $VIKING_MAPS usage */
384 const gchar *mapdir = g_getenv("VIKING_MAPS");
386 defaultdir = g_strdup ( mapdir );
387 } else if ( g_access ( GLOBAL_MAPS_DIR, W_OK ) == 0 ) {
388 defaultdir = g_strdup ( GLOBAL_MAPS_DIR );
390 const gchar *home = g_get_home_dir();
391 if (!home || g_access(home, W_OK))
392 home = g_get_home_dir ();
394 defaultdir = g_build_filename ( home, LOCAL_MAPS_DIR, NULL );
396 defaultdir = g_strdup ( LOCAL_MAPS_DIR );
398 if (defaultdir && (defaultdir[strlen(defaultdir)-1] != G_DIR_SEPARATOR))
400 /* Add the separator at the end */
401 gchar *tmp = defaultdir;
402 defaultdir = g_strconcat(tmp, G_DIR_SEPARATOR_S, NULL);
405 g_debug("%s: defaultdir=%s", __FUNCTION__, defaultdir);
410 static void maps_layer_mkdir_if_default_dir ( VikMapsLayer *vml )
412 if ( vml->cache_dir && strcmp ( vml->cache_dir, MAPS_CACHE_DIR ) == 0 && g_file_test ( vml->cache_dir, G_FILE_TEST_EXISTS ) == FALSE )
414 g_mkdir ( vml->cache_dir, 0777 );
418 static void maps_layer_set_cache_dir ( VikMapsLayer *vml, const gchar *dir )
421 g_assert ( vml != NULL);
422 g_free ( vml->cache_dir );
423 vml->cache_dir = NULL;
425 if ( dir == NULL || dir[0] == '\0' )
427 if ( a_preferences_get(VIKING_PREFERENCES_NAMESPACE "maplayer_default_dir") )
428 vml->cache_dir = g_strdup ( a_preferences_get(VIKING_PREFERENCES_NAMESPACE "maplayer_default_dir")->s );
433 if ( dir[len-1] != G_DIR_SEPARATOR )
435 vml->cache_dir = g_malloc ( len+2 );
436 strncpy ( vml->cache_dir, dir, len );
437 vml->cache_dir[len] = G_DIR_SEPARATOR;
438 vml->cache_dir[len+1] = '\0';
441 vml->cache_dir = g_strdup ( dir );
443 maps_layer_mkdir_if_default_dir ( vml );
446 /****************************************/
447 /******** GOBJECT STUFF *****************/
448 /****************************************/
450 GType vik_maps_layer_get_type ()
452 static GType vml_type = 0;
456 static const GTypeInfo vml_info =
458 sizeof (VikMapsLayerClass),
459 NULL, /* base_init */
460 NULL, /* base_finalize */
461 NULL, /* class init */
462 NULL, /* class_finalize */
463 NULL, /* class_data */
464 sizeof (VikMapsLayer),
466 NULL /* instance init */
468 vml_type = g_type_register_static ( VIK_LAYER_TYPE, "VikMapsLayer", &vml_info, 0 );
474 /****************************************/
475 /************** PARAMETERS **************/
476 /****************************************/
478 static guint map_index_to_uniq_id (guint8 index)
480 g_assert ( index < NUM_MAP_TYPES );
481 return vik_map_source_get_uniq_id(MAPS_LAYER_NTH_TYPE(index));
484 static guint map_uniq_id_to_index ( guint uniq_id )
487 for ( i = 0; i < NUM_MAP_TYPES; i++ )
488 if ( vik_map_source_get_uniq_id(MAPS_LAYER_NTH_TYPE(i)) == uniq_id )
490 return NUM_MAP_TYPES; /* no such thing */
493 static gboolean maps_layer_set_param ( VikMapsLayer *vml, guint16 id, VikLayerParamData data, VikViewport *vvp, gboolean is_file_operation )
495 // When loading from a file don't need the license reminder
496 if ( is_file_operation )
497 vml->license_notice_shown = TRUE;
501 case PARAM_CACHE_DIR: maps_layer_set_cache_dir ( vml, data.s ); break;
502 case PARAM_MAPTYPE: {
503 gint maptype = map_uniq_id_to_index(data.u);
504 if ( maptype == NUM_MAP_TYPES ) g_warning(_("Unknown map type"));
505 else vml->maptype = maptype;
508 case PARAM_ALPHA: if ( data.u <= 255 ) vml->alpha = data.u; break;
509 case PARAM_AUTODOWNLOAD: vml->autodownload = data.b; break;
510 case PARAM_ONLYMISSING: vml->adl_only_missing = data.b; break;
511 case PARAM_MAPZOOM: if ( data.u < NUM_MAPZOOMS ) {
512 vml->mapzoom_id = data.u;
513 vml->xmapzoom = __mapzooms_x [data.u];
514 vml->ymapzoom = __mapzooms_y [data.u];
515 }else g_warning (_("Unknown Map Zoom")); break;
520 static VikLayerParamData maps_layer_get_param ( VikMapsLayer *vml, guint16 id, gboolean is_file_operation )
522 VikLayerParamData rv;
525 case PARAM_CACHE_DIR: rv.s = vml->cache_dir ? vml->cache_dir : ""; break;
526 case PARAM_MAPTYPE: rv.u = map_index_to_uniq_id ( vml->maptype ); break;
527 case PARAM_ALPHA: rv.u = vml->alpha; break;
528 case PARAM_AUTODOWNLOAD: rv.u = vml->autodownload; break;
529 case PARAM_ONLYMISSING: rv.u = vml->adl_only_missing; break;
530 case PARAM_MAPZOOM: rv.u = vml->mapzoom_id; break;
535 /****************************************/
536 /****** CREATING, COPYING, FREEING ******/
537 /****************************************/
539 static VikMapsLayer *maps_layer_new ( VikViewport *vvp )
542 VikMapsLayer *vml = VIK_MAPS_LAYER ( g_object_new ( VIK_MAPS_LAYER_TYPE, NULL ) );
543 vik_layer_set_type ( VIK_LAYER(vml), VIK_LAYER_MAPS );
544 idx = map_uniq_id_to_index(19); /* 19 is id for OSM MapQuest maps */
545 vml->maptype = (idx < NUM_MAP_TYPES) ? idx : 0;
546 vml->maptype = (idx < NUM_MAP_TYPES) ? idx : 0;
549 vml->dl_tool_x = vml->dl_tool_y = -1;
550 maps_layer_set_cache_dir ( vml, NULL );
551 vml->autodownload = FALSE;
552 vml->adl_only_missing = FALSE;
553 vml->last_center = NULL;
554 vml->last_xmpp = 0.0;
555 vml->last_ympp = 0.0;
557 vml->dl_right_click_menu = NULL;
558 vml->license_notice_shown = FALSE;
563 static void maps_layer_free ( VikMapsLayer *vml )
565 g_free ( vml->cache_dir );
566 vml->cache_dir = NULL;
567 if ( vml->dl_right_click_menu )
568 g_object_ref_sink ( G_OBJECT(vml->dl_right_click_menu) );
569 g_free(vml->last_center);
570 vml->last_center = NULL;
573 static void maps_layer_post_read (VikLayer *vl, VikViewport *vp, gboolean from_file)
575 if (from_file != TRUE)
577 /* If this method is not called in file reading context
578 * it is called in GUI context.
579 * So, we can check if we have to inform the user about inconsistency */
580 VikViewportDrawMode vp_drawmode;
581 VikMapsLayer *vml = VIK_MAPS_LAYER(vl);
582 VikMapSource *map = NULL;
584 vp_drawmode = vik_viewport_get_drawmode ( vp );
585 map = MAPS_LAYER_NTH_TYPE(vml->maptype);
586 if (vik_map_source_get_drawmode(map) != vp_drawmode) {
587 const gchar *drawmode_name = vik_viewport_get_drawmode_name (vp, vik_map_source_get_drawmode(map));
588 gchar *msg = g_strdup_printf(_("New map cannot be displayed in the current drawmode.\nSelect \"%s\" from View menu to view it."), drawmode_name);
589 a_dialog_warning_msg ( VIK_GTK_WINDOW_FROM_WIDGET(vp), msg );
593 if (vik_map_source_get_license (map) != NULL) {
594 if ( ! vml->license_notice_shown ) {
595 a_dialog_license (VIK_GTK_WINDOW_FROM_WIDGET(vp), vik_map_source_get_label (map),
596 vik_map_source_get_license (map), vik_map_source_get_license_url (map) );
597 vml->license_notice_shown = TRUE;
603 static const gchar* maps_layer_tooltip ( VikMapsLayer *vml )
605 return vik_maps_layer_get_map_label ( vml );
608 static void maps_layer_marshall( VikMapsLayer *vml, guint8 **data, gint *len )
610 vik_layer_marshall_params ( VIK_LAYER(vml), data, len );
613 static VikMapsLayer *maps_layer_unmarshall( guint8 *data, gint len, VikViewport *vvp )
615 VikMapsLayer *rv = maps_layer_new ( vvp );
616 vik_layer_unmarshall_params ( VIK_LAYER(rv), data, len, vvp );
620 /*********************/
621 /****** DRAWING ******/
622 /*********************/
624 static GdkPixbuf *pixbuf_set_alpha ( GdkPixbuf *pixbuf, guint8 alpha )
627 gint width, height, iii, jjj;
629 if ( ! gdk_pixbuf_get_has_alpha ( pixbuf ) )
631 GdkPixbuf *tmp = gdk_pixbuf_add_alpha(pixbuf,FALSE,0,0,0);
632 g_object_unref(G_OBJECT(pixbuf));
636 pixels = gdk_pixbuf_get_pixels(pixbuf);
637 width = gdk_pixbuf_get_width(pixbuf);
638 height = gdk_pixbuf_get_height(pixbuf);
640 /* r,g,b,a,r,g,b,a.... */
641 for (iii = 0; iii < width; iii++) for (jjj = 0; jjj < height; jjj++)
649 static GdkPixbuf *pixbuf_shrink ( GdkPixbuf *pixbuf, gdouble xshrinkfactor, gdouble yshrinkfactor )
652 guint16 width = gdk_pixbuf_get_width(pixbuf), height = gdk_pixbuf_get_height(pixbuf);
653 tmp = gdk_pixbuf_scale_simple(pixbuf, ceil(width * xshrinkfactor), ceil(height * yshrinkfactor), GDK_INTERP_NEAREST);
654 g_object_unref ( G_OBJECT(pixbuf) );
658 static GdkPixbuf *get_pixbuf( VikMapsLayer *vml, gint mode, MapCoord *mapcoord, gchar *filename_buf, gint buf_len, gdouble xshrinkfactor, gdouble yshrinkfactor )
663 pixbuf = a_mapcache_get ( mapcoord->x, mapcoord->y, mapcoord->z,
664 mode, mapcoord->scale, vml->alpha, xshrinkfactor, yshrinkfactor );
667 if ( vik_map_source_is_direct_file_access (MAPS_LAYER_NTH_TYPE(vml->maptype)) )
668 g_snprintf ( filename_buf, buf_len, DIRECTDIRACCESS,
669 vml->cache_dir, (17 - mapcoord->scale), mapcoord->x, mapcoord->y, ".png" );
671 g_snprintf ( filename_buf, buf_len, DIRSTRUCTURE,
672 vml->cache_dir, mode,
673 mapcoord->scale, mapcoord->z, mapcoord->x, mapcoord->y );
675 if ( g_file_test ( filename_buf, G_FILE_TEST_EXISTS ) == TRUE)
678 pixbuf = gdk_pixbuf_new_from_file ( filename_buf, &gx );
680 /* free the pixbuf on error */
683 if ( gx->domain != GDK_PIXBUF_ERROR || gx->code != GDK_PIXBUF_ERROR_CORRUPT_IMAGE )
684 g_warning ( _("Couldn't open image file: %s"), gx->message );
688 g_object_unref ( G_OBJECT(pixbuf) );
691 if ( vml->alpha < 255 )
692 pixbuf = pixbuf_set_alpha ( pixbuf, vml->alpha );
693 if ( xshrinkfactor != 1.0 || yshrinkfactor != 1.0 )
694 pixbuf = pixbuf_shrink ( pixbuf, xshrinkfactor, yshrinkfactor );
696 a_mapcache_add ( pixbuf, mapcoord->x, mapcoord->y,
697 mapcoord->z, vik_map_source_get_uniq_id(MAPS_LAYER_NTH_TYPE(vml->maptype)),
698 mapcoord->scale, vml->alpha, xshrinkfactor, yshrinkfactor );
705 gboolean should_start_autodownload(VikMapsLayer *vml, VikViewport *vvp)
707 const VikCoord *center = vik_viewport_get_center ( vvp );
709 if (vik_window_get_pan_move (VIK_WINDOW(VIK_GTK_WINDOW_FROM_WIDGET(GTK_WIDGET(vvp)))))
710 /* D'n'D pan in action: do not download */
713 if (vml->last_center == NULL) {
714 VikCoord *new_center = g_malloc(sizeof(VikCoord));
715 *new_center = *center;
716 vml->last_center = new_center;
717 vml->last_xmpp = vik_viewport_get_xmpp(vvp);
718 vml->last_ympp = vik_viewport_get_ympp(vvp);
722 /* TODO: perhaps vik_coord_diff() */
723 if (vik_coord_equals(vml->last_center, center)
724 && (vml->last_xmpp == vik_viewport_get_xmpp(vvp))
725 && (vml->last_ympp == vik_viewport_get_ympp(vvp)))
728 *(vml->last_center) = *center;
729 vml->last_xmpp = vik_viewport_get_xmpp(vvp);
730 vml->last_ympp = vik_viewport_get_ympp(vvp);
734 static void maps_layer_draw_section ( VikMapsLayer *vml, VikViewport *vvp, VikCoord *ul, VikCoord *br )
737 gdouble xzoom = vik_viewport_get_xmpp ( vvp );
738 gdouble yzoom = vik_viewport_get_ympp ( vvp );
739 gdouble xshrinkfactor = 1.0, yshrinkfactor = 1.0;
740 gboolean existence_only = FALSE;
742 if ( vml->xmapzoom && (vml->xmapzoom != xzoom || vml->ymapzoom != yzoom) ) {
743 xshrinkfactor = vml->xmapzoom / xzoom;
744 yshrinkfactor = vml->ymapzoom / yzoom;
745 xzoom = vml->xmapzoom;
746 yzoom = vml->xmapzoom;
747 if ( ! (xshrinkfactor > MIN_SHRINKFACTOR && xshrinkfactor < MAX_SHRINKFACTOR &&
748 yshrinkfactor > MIN_SHRINKFACTOR && yshrinkfactor < MAX_SHRINKFACTOR ) ) {
749 if ( xshrinkfactor > REAL_MIN_SHRINKFACTOR && yshrinkfactor > REAL_MIN_SHRINKFACTOR )
750 existence_only = TRUE;
752 g_warning ( _("Cowardly refusing to draw tiles or existence of tiles beyond %d zoom out factor"), (int)( 1.0/REAL_MIN_SHRINKFACTOR));
759 VikMapSource *map = MAPS_LAYER_NTH_TYPE(vml->maptype);
760 if ( vik_map_source_coord_to_mapcoord ( map, ul, xzoom, yzoom, &ulm ) &&
761 vik_map_source_coord_to_mapcoord ( map, br, xzoom, yzoom, &brm ) ) {
765 gint xmin = MIN(ulm.x, brm.x), xmax = MAX(ulm.x, brm.x);
766 gint ymin = MIN(ulm.y, brm.y), ymax = MAX(ulm.y, brm.y);
767 gint mode = vik_map_source_get_uniq_id(map);
770 gint xx, yy, width, height;
773 guint max_path_len = strlen(vml->cache_dir) + 40;
774 gchar *path_buf = g_malloc ( max_path_len * sizeof(char) );
776 if ( (!existence_only) && vml->autodownload && should_start_autodownload(vml, vvp)) {
777 g_debug("%s: Starting autodownload", __FUNCTION__);
778 if ( !vml->adl_only_missing && vik_map_source_supports_download_only_new (map) )
779 // Try to download newer tiles
780 start_download_thread ( vml, vvp, ul, br, REDOWNLOAD_NEW );
782 // Download only missing tiles
783 start_download_thread ( vml, vvp, ul, br, REDOWNLOAD_NONE );
786 if ( vik_map_source_get_tilesize_x(map) == 0 && !existence_only ) {
787 for ( x = xmin; x <= xmax; x++ ) {
788 for ( y = ymin; y <= ymax; y++ ) {
791 pixbuf = get_pixbuf ( vml, mode, &ulm, path_buf, max_path_len, xshrinkfactor, yshrinkfactor );
793 width = gdk_pixbuf_get_width ( pixbuf );
794 height = gdk_pixbuf_get_height ( pixbuf );
796 vik_map_source_mapcoord_to_center_coord ( map, &ulm, &coord );
797 vik_viewport_coord_to_screen ( vvp, &coord, &xx, &yy );
801 vik_viewport_draw_pixbuf ( vvp, pixbuf, 0, 0, xx, yy, width, height );
805 } else { /* tilesize is known, don't have to keep converting coords */
806 gdouble tilesize_x = vik_map_source_get_tilesize_x(map) * xshrinkfactor;
807 gdouble tilesize_y = vik_map_source_get_tilesize_y(map) * yshrinkfactor;
808 /* ceiled so tiles will be maximum size in the case of funky shrinkfactor */
809 gint tilesize_x_ceil = ceil ( tilesize_x );
810 gint tilesize_y_ceil = ceil ( tilesize_y );
811 gint8 xinc = (ulm.x == xmin) ? 1 : -1;
812 gint8 yinc = (ulm.y == ymin) ? 1 : -1;
813 gdouble xx, yy; gint xx_tmp, yy_tmp;
814 gint base_yy, xend, yend;
816 xend = (xinc == 1) ? (xmax+1) : (xmin-1);
817 yend = (yinc == 1) ? (ymax+1) : (ymin-1);
819 vik_map_source_mapcoord_to_center_coord ( map, &ulm, &coord );
820 vik_viewport_coord_to_screen ( vvp, &coord, &xx_tmp, &yy_tmp );
821 xx = xx_tmp; yy = yy_tmp;
822 /* above trick so xx,yy doubles. this is so shrinkfactors aren't rounded off
823 * eg if tile size 128, shrinkfactor 0.333 */
824 xx -= (tilesize_x/2);
825 base_yy = yy - (tilesize_y/2);
827 for ( x = ((xinc == 1) ? xmin : xmax); x != xend; x+=xinc ) {
829 for ( y = ((yinc == 1) ? ymin : ymax); y != yend; y+=yinc ) {
833 if ( existence_only ) {
834 if ( vik_map_source_is_direct_file_access (MAPS_LAYER_NTH_TYPE(vml->maptype)) )
835 g_snprintf ( path_buf, max_path_len, DIRECTDIRACCESS,
836 vml->cache_dir, (17 - ulm.scale), ulm.x, ulm.y, ".png" );
838 g_snprintf ( path_buf, max_path_len, DIRSTRUCTURE,
839 vml->cache_dir, mode,
840 ulm.scale, ulm.z, ulm.x, ulm.y );
841 if ( g_file_test ( path_buf, G_FILE_TEST_EXISTS ) == TRUE ) {
842 GdkGC *black_gc = GTK_WIDGET(vvp)->style->black_gc;
843 vik_viewport_draw_line ( vvp, black_gc, xx+tilesize_x_ceil, yy, xx, yy+tilesize_y_ceil );
847 for (scale_inc = 0; scale_inc < 4; scale_inc ++) {
848 /* try with correct then smaller zooms */
849 int scale_factor = 1 << scale_inc; /* 2^scale_inc */
851 ulm2.x = ulm.x / scale_factor;
852 ulm2.y = ulm.y / scale_factor;
853 ulm2.scale = ulm.scale + scale_inc;
854 pixbuf = get_pixbuf ( vml, mode, &ulm2, path_buf, max_path_len, xshrinkfactor * scale_factor, yshrinkfactor * scale_factor );
856 gint src_x = (ulm.x % scale_factor) * tilesize_x_ceil;
857 gint src_y = (ulm.y % scale_factor) * tilesize_y_ceil;
859 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);
861 vik_viewport_draw_pixbuf ( vvp, pixbuf, src_x, src_y, xx, yy, tilesize_x_ceil, tilesize_y_ceil );
866 /* retry with bigger zooms */
868 for (scale_dec = 1; scale_dec < 2; scale_dec ++) {
870 int scale_factor = 1 << scale_dec; /* 2^scale_dec */
872 ulm2.x = ulm.x * scale_factor;
873 ulm2.y = ulm.y * scale_factor;
874 ulm2.scale = ulm.scale - scale_dec;
875 for (pict_x = 0; pict_x < scale_factor; pict_x ++) {
876 for (pict_y = 0; pict_y < scale_factor; pict_y ++) {
877 MapCoord ulm3 = ulm2;
880 pixbuf = get_pixbuf ( vml, mode, &ulm3, path_buf, max_path_len, xshrinkfactor / scale_factor, yshrinkfactor / scale_factor );
884 gint dest_x = xx + pict_x * (tilesize_x_ceil / scale_factor);
885 gint dest_y = yy + pict_y * (tilesize_y_ceil / scale_factor);
886 vik_viewport_draw_pixbuf ( vvp, pixbuf, src_x, src_y, dest_x, dest_y, tilesize_x_ceil / scale_factor, tilesize_y_ceil / scale_factor );
904 static void maps_layer_draw ( VikMapsLayer *vml, VikViewport *vvp )
906 if ( vik_map_source_get_drawmode(MAPS_LAYER_NTH_TYPE(vml->maptype)) == vik_viewport_get_drawmode ( vvp ) )
911 gdouble level = vik_viewport_get_zoom ( vvp );
913 vik_viewport_get_min_max_lat_lon ( vvp, &bbox.south, &bbox.north, &bbox.west, &bbox.east );
914 vik_map_source_get_copyright ( MAPS_LAYER_NTH_TYPE(vml->maptype), bbox, level, vik_viewport_add_copyright, vvp );
917 const GdkPixbuf *logo = vik_map_source_get_logo ( MAPS_LAYER_NTH_TYPE(vml->maptype) );
918 vik_viewport_add_logo ( vvp, logo );
920 /* get corner coords */
921 if ( vik_viewport_get_coord_mode ( vvp ) == VIK_COORD_UTM && ! vik_viewport_is_one_zone ( vvp ) ) {
922 /* UTM multi-zone stuff by Kit Transue */
923 gchar leftmost_zone, rightmost_zone, i;
924 leftmost_zone = vik_viewport_leftmost_zone( vvp );
925 rightmost_zone = vik_viewport_rightmost_zone( vvp );
926 for ( i = leftmost_zone; i <= rightmost_zone; ++i ) {
927 vik_viewport_corners_for_zonen ( vvp, i, &ul, &br );
928 maps_layer_draw_section ( vml, vvp, &ul, &br );
932 vik_viewport_screen_to_coord ( vvp, 0, 0, &ul );
933 vik_viewport_screen_to_coord ( vvp, vik_viewport_get_width(vvp), vik_viewport_get_height(vvp), &br );
935 maps_layer_draw_section ( vml, vvp, &ul, &br );
940 /*************************/
941 /****** DOWNLOADING ******/
942 /*************************/
944 /* pass along data to thread, exists even if layer is deleted. */
954 gboolean refresh_display;
957 gboolean map_layer_alive;
961 static void mdi_free ( MapDownloadInfo *mdi )
963 g_mutex_free(mdi->mutex);
964 g_free ( mdi->cache_dir );
965 mdi->cache_dir = NULL;
966 g_free ( mdi->filename_buf );
967 mdi->filename_buf = NULL;
971 static void weak_ref_cb(gpointer ptr, GObject * dead_vml)
973 MapDownloadInfo *mdi = ptr;
974 g_mutex_lock(mdi->mutex);
975 mdi->map_layer_alive = FALSE;
976 g_mutex_unlock(mdi->mutex);
979 static int map_download_thread ( MapDownloadInfo *mdi, gpointer threaddata )
981 void *handle = vik_map_source_download_handle_init(MAPS_LAYER_NTH_TYPE(mdi->maptype));
984 for ( x = mdi->x0; x <= mdi->xf; x++ )
986 for ( y = mdi->y0; y <= mdi->yf; y++ )
988 gboolean remove_mem_cache = FALSE;
989 gboolean need_download = FALSE;
990 g_snprintf ( mdi->filename_buf, mdi->maxlen, DIRSTRUCTURE,
991 mdi->cache_dir, vik_map_source_get_uniq_id(MAPS_LAYER_NTH_TYPE(mdi->maptype)),
992 mdi->mapcoord.scale, mdi->mapcoord.z, x, y );
995 int res = a_background_thread_progress ( threaddata, ((gdouble)donemaps) / mdi->mapstoget ); /* this also calls testcancel */
997 vik_map_source_download_handle_cleanup(MAPS_LAYER_NTH_TYPE(mdi->maptype), handle);
1001 if ( g_file_test ( mdi->filename_buf, G_FILE_TEST_EXISTS ) == FALSE ) {
1002 need_download = TRUE;
1003 remove_mem_cache = TRUE;
1005 } else { /* in case map file already exists */
1006 switch (mdi->redownload) {
1007 case REDOWNLOAD_NONE:
1010 case REDOWNLOAD_BAD:
1012 /* see if this one is bad or what */
1014 GdkPixbuf *pixbuf = gdk_pixbuf_new_from_file ( mdi->filename_buf, &gx );
1015 if (gx || (!pixbuf)) {
1016 g_remove ( mdi->filename_buf );
1017 need_download = TRUE;
1018 remove_mem_cache = TRUE;
1019 g_error_free ( gx );
1022 g_object_unref ( pixbuf );
1027 case REDOWNLOAD_NEW:
1028 need_download = TRUE;
1029 remove_mem_cache = TRUE;
1032 case REDOWNLOAD_ALL:
1033 /* FIXME: need a better way than to erase file in case of server/network problem */
1034 g_remove ( mdi->filename_buf );
1035 need_download = TRUE;
1036 remove_mem_cache = TRUE;
1039 case DOWNLOAD_OR_REFRESH:
1040 remove_mem_cache = TRUE;
1044 g_warning ( "redownload state %d unknown\n", mdi->redownload);
1048 mdi->mapcoord.x = x; mdi->mapcoord.y = y;
1050 if (need_download) {
1051 if ( vik_map_source_download( MAPS_LAYER_NTH_TYPE(mdi->maptype), &(mdi->mapcoord), mdi->filename_buf, handle))
1055 g_mutex_lock(mdi->mutex);
1056 if (remove_mem_cache)
1057 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 );
1058 if (mdi->refresh_display && mdi->map_layer_alive) {
1059 /* TODO: check if it's on visible area */
1060 vik_layer_emit_update ( VIK_LAYER(mdi->vml) ); // NB update display from background
1062 g_mutex_unlock(mdi->mutex);
1063 mdi->mapcoord.x = mdi->mapcoord.y = 0; /* we're temporarily between downloads */
1067 vik_map_source_download_handle_cleanup(MAPS_LAYER_NTH_TYPE(mdi->maptype), handle);
1068 g_mutex_lock(mdi->mutex);
1069 if (mdi->map_layer_alive)
1070 g_object_weak_unref(G_OBJECT(mdi->vml), weak_ref_cb, mdi);
1071 g_mutex_unlock(mdi->mutex);
1075 static void mdi_cancel_cleanup ( MapDownloadInfo *mdi )
1077 if ( mdi->mapcoord.x || mdi->mapcoord.y )
1079 g_snprintf ( mdi->filename_buf, mdi->maxlen, DIRSTRUCTURE,
1080 mdi->cache_dir, vik_map_source_get_uniq_id(MAPS_LAYER_NTH_TYPE(mdi->maptype)),
1081 mdi->mapcoord.scale, mdi->mapcoord.z, mdi->mapcoord.x, mdi->mapcoord.y );
1082 if ( g_file_test ( mdi->filename_buf, G_FILE_TEST_EXISTS ) == TRUE)
1084 g_remove ( mdi->filename_buf );
1089 static void start_download_thread ( VikMapsLayer *vml, VikViewport *vvp, const VikCoord *ul, const VikCoord *br, gint redownload )
1091 gdouble xzoom = vml->xmapzoom ? vml->xmapzoom : vik_viewport_get_xmpp ( vvp );
1092 gdouble yzoom = vml->ymapzoom ? vml->ymapzoom : vik_viewport_get_ympp ( vvp );
1094 VikMapSource *map = MAPS_LAYER_NTH_TYPE(vml->maptype);
1096 // Don't ever attempt download on direct access
1097 if ( vik_map_source_is_direct_file_access ( map ) )
1100 if ( vik_map_source_coord_to_mapcoord ( map, ul, xzoom, yzoom, &ulm )
1101 && vik_map_source_coord_to_mapcoord ( map, br, xzoom, yzoom, &brm ) )
1103 MapDownloadInfo *mdi = g_malloc ( sizeof(MapDownloadInfo) );
1108 mdi->map_layer_alive = TRUE;
1109 mdi->mutex = g_mutex_new();
1110 mdi->refresh_display = TRUE;
1112 /* cache_dir and buffer for dest filename */
1113 mdi->cache_dir = g_strdup ( vml->cache_dir );
1114 mdi->maxlen = strlen ( vml->cache_dir ) + 40;
1115 mdi->filename_buf = g_malloc ( mdi->maxlen * sizeof(gchar) );
1116 mdi->maptype = vml->maptype;
1118 mdi->mapcoord = ulm;
1120 mdi->redownload = redownload;
1122 mdi->x0 = MIN(ulm.x, brm.x);
1123 mdi->xf = MAX(ulm.x, brm.x);
1124 mdi->y0 = MIN(ulm.y, brm.y);
1125 mdi->yf = MAX(ulm.y, brm.y);
1129 if ( mdi->redownload ) {
1130 mdi->mapstoget = (mdi->xf - mdi->x0 + 1) * (mdi->yf - mdi->y0 + 1);
1132 /* calculate how many we need */
1133 for ( a = mdi->x0; a <= mdi->xf; a++ )
1135 for ( b = mdi->y0; b <= mdi->yf; b++ )
1137 g_snprintf ( mdi->filename_buf, mdi->maxlen, DIRSTRUCTURE,
1138 vml->cache_dir, vik_map_source_get_uniq_id(map), ulm.scale,
1140 if ( g_file_test ( mdi->filename_buf, G_FILE_TEST_EXISTS ) == FALSE )
1146 mdi->mapcoord.x = mdi->mapcoord.y = 0; /* for cleanup -- no current map */
1148 if ( mdi->mapstoget )
1150 const gchar *tmp_str;
1155 if (redownload == REDOWNLOAD_BAD)
1156 tmp_str = ngettext("Redownloading up to %d %s map...", "Redownloading up to %d %s maps...", mdi->mapstoget);
1158 tmp_str = ngettext("Redownloading %d %s map...", "Redownloading %d %s maps...", mdi->mapstoget);
1162 tmp_str = ngettext("Downloading %d %s map...", "Downloading %d %s maps...", mdi->mapstoget);
1164 tmp = g_strdup_printf ( tmp_str, mdi->mapstoget, MAPS_LAYER_NTH_LABEL(vml->maptype));
1166 g_object_weak_ref(G_OBJECT(mdi->vml), weak_ref_cb, mdi);
1167 /* launch the thread */
1168 a_background_thread ( VIK_GTK_WINDOW_FROM_LAYER(vml), /* parent window */
1169 tmp, /* description string */
1170 (vik_thr_func) map_download_thread, /* function to call within thread */
1171 mdi, /* pass along data */
1172 (vik_thr_free_func) mdi_free, /* function to free pass along data */
1173 (vik_thr_free_func) mdi_cancel_cleanup,
1182 void maps_layer_download_section ( VikMapsLayer *vml, VikViewport *vvp, VikCoord *ul, VikCoord *br, gdouble zoom)
1185 VikMapSource *map = MAPS_LAYER_NTH_TYPE(vml->maptype);
1187 // Don't ever attempt download on direct access
1188 if ( vik_map_source_is_direct_file_access ( map ) )
1191 if (!vik_map_source_coord_to_mapcoord(map, ul, zoom, zoom, &ulm)
1192 || !vik_map_source_coord_to_mapcoord(map, br, zoom, zoom, &brm)) {
1193 g_warning("%s() coord_to_mapcoord() failed", __PRETTY_FUNCTION__);
1197 MapDownloadInfo *mdi = g_malloc(sizeof(MapDownloadInfo));
1202 mdi->map_layer_alive = TRUE;
1203 mdi->mutex = g_mutex_new();
1204 mdi->refresh_display = TRUE;
1206 mdi->cache_dir = g_strdup ( vml->cache_dir );
1207 mdi->maxlen = strlen ( vml->cache_dir ) + 40;
1208 mdi->filename_buf = g_malloc ( mdi->maxlen * sizeof(gchar) );
1209 mdi->maptype = vml->maptype;
1211 mdi->mapcoord = ulm;
1213 mdi->redownload = REDOWNLOAD_NONE;
1215 mdi->x0 = MIN(ulm.x, brm.x);
1216 mdi->xf = MAX(ulm.x, brm.x);
1217 mdi->y0 = MIN(ulm.y, brm.y);
1218 mdi->yf = MAX(ulm.y, brm.y);
1222 for (i = mdi->x0; i <= mdi->xf; i++) {
1223 for (j = mdi->y0; j <= mdi->yf; j++) {
1224 g_snprintf ( mdi->filename_buf, mdi->maxlen, DIRSTRUCTURE,
1225 vml->cache_dir, vik_map_source_get_uniq_id(map), ulm.scale,
1227 if ( g_file_test ( mdi->filename_buf, G_FILE_TEST_EXISTS ) == FALSE )
1232 mdi->mapcoord.x = mdi->mapcoord.y = 0; /* for cleanup -- no current map */
1234 if (mdi->mapstoget) {
1237 fmt = ngettext("Downloading %d %s map...",
1238 "Downloading %d %s maps...",
1240 tmp = g_strdup_printf ( fmt, mdi->mapstoget, MAPS_LAYER_NTH_LABEL(vml->maptype) );
1242 g_object_weak_ref(G_OBJECT(mdi->vml), weak_ref_cb, mdi);
1243 /* launch the thread */
1244 a_background_thread ( VIK_GTK_WINDOW_FROM_LAYER(vml), /* parent window */
1245 tmp, /* description string */
1246 (vik_thr_func) map_download_thread, /* function to call within thread */
1247 mdi, /* pass along data */
1248 (vik_thr_free_func) mdi_free, /* function to free pass along data */
1249 (vik_thr_free_func) mdi_cancel_cleanup,
1257 static void maps_layer_redownload_bad ( VikMapsLayer *vml )
1259 start_download_thread ( vml, vml->redownload_vvp, &(vml->redownload_ul), &(vml->redownload_br), REDOWNLOAD_BAD );
1262 static void maps_layer_redownload_all ( VikMapsLayer *vml )
1264 start_download_thread ( vml, vml->redownload_vvp, &(vml->redownload_ul), &(vml->redownload_br), REDOWNLOAD_ALL );
1267 static void maps_layer_redownload_new ( VikMapsLayer *vml )
1269 start_download_thread ( vml, vml->redownload_vvp, &(vml->redownload_ul), &(vml->redownload_br), REDOWNLOAD_NEW );
1272 static gboolean maps_layer_download_release ( VikMapsLayer *vml, GdkEventButton *event, VikViewport *vvp )
1274 if (!vml || vml->vl.type != VIK_LAYER_MAPS)
1276 if ( vml->dl_tool_x != -1 && vml->dl_tool_y != -1 )
1278 if ( event->button == 1 )
1281 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 );
1282 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 );
1283 start_download_thread ( vml, vvp, &ul, &br, DOWNLOAD_OR_REFRESH );
1284 vml->dl_tool_x = vml->dl_tool_y = -1;
1289 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) );
1290 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) );
1292 vml->redownload_vvp = vvp;
1294 vml->dl_tool_x = vml->dl_tool_y = -1;
1296 if ( ! vml->dl_right_click_menu ) {
1298 vml->dl_right_click_menu = GTK_MENU ( gtk_menu_new () );
1300 item = gtk_menu_item_new_with_mnemonic ( _("Redownload _Bad Map(s)") );
1301 g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(maps_layer_redownload_bad), vml );
1302 gtk_menu_shell_append ( GTK_MENU_SHELL(vml->dl_right_click_menu), item );
1304 item = gtk_menu_item_new_with_mnemonic ( _("Redownload _New Map(s)") );
1305 g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(maps_layer_redownload_new), vml );
1306 gtk_menu_shell_append ( GTK_MENU_SHELL(vml->dl_right_click_menu), item );
1308 item = gtk_menu_item_new_with_mnemonic ( _("Redownload _All Map(s)") );
1309 g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(maps_layer_redownload_all), vml );
1310 gtk_menu_shell_append ( GTK_MENU_SHELL(vml->dl_right_click_menu), item );
1313 gtk_menu_popup ( vml->dl_right_click_menu, NULL, NULL, NULL, NULL, event->button, event->time );
1314 gtk_widget_show_all ( GTK_WIDGET(vml->dl_right_click_menu) );
1320 static gpointer maps_layer_download_create ( VikWindow *vw, VikViewport *vvp)
1325 static gboolean maps_layer_download_click ( VikMapsLayer *vml, GdkEventButton *event, VikViewport *vvp )
1328 if (!vml || vml->vl.type != VIK_LAYER_MAPS)
1330 VikMapSource *map = MAPS_LAYER_NTH_TYPE(vml->maptype);
1331 if ( vik_map_source_get_drawmode(map) == vik_viewport_get_drawmode ( vvp ) &&
1332 vik_map_source_coord_to_mapcoord ( map, vik_viewport_get_center ( vvp ),
1333 vml->xmapzoom ? vml->xmapzoom : vik_viewport_get_xmpp ( vvp ),
1334 vml->ymapzoom ? vml->ymapzoom : vik_viewport_get_ympp ( vvp ),
1336 vml->dl_tool_x = event->x, vml->dl_tool_y = event->y;
1343 if ( __map_types[vml->maptype].drawmode == vik_viewport_get_drawmode ( vvp ) )
1347 vik_viewport_screen_to_coord ( vvp, event->x, event->y, &coord );
1348 if ( __map_types[vml->maptype].coord_to_mapcoord ( &coord,
1349 vml->xmapzoom ? vml->xmapzoom : vik_viewport_get_xmpp ( vvp ),
1350 vml->ymapzoom ? vml->ymapzoom : vik_viewport_get_ympp ( vvp ),
1352 gchar *filename_buf = g_strdup_printf ( DIRSTRUCTURE,
1353 vml->cache_dir, __map_types[vml->maptype].uniq_id,
1354 mapcoord.scale, mapcoord.z, mapcoord.x, mapcoord.y );
1356 __map_types[vml->maptype].download ( &mapcoord, filename_buf );
1357 g_free ( filename_buf );
1358 vik_layer_emit_update ( VIK_LAYER(vml) );
1366 static void download_onscreen_maps ( gpointer vml_vvp[2], gint redownload )
1368 VikMapsLayer *vml = vml_vvp[0];
1369 VikViewport *vvp = vml_vvp[1];
1370 VikViewportDrawMode vp_drawmode = vik_viewport_get_drawmode ( vvp );
1372 gdouble xzoom = vml->xmapzoom ? vml->xmapzoom : vik_viewport_get_xmpp ( vvp );
1373 gdouble yzoom = vml->ymapzoom ? vml->ymapzoom : vik_viewport_get_ympp ( vvp );
1378 vik_viewport_screen_to_coord ( vvp, 0, 0, &ul );
1379 vik_viewport_screen_to_coord ( vvp, vik_viewport_get_width(vvp), vik_viewport_get_height(vvp), &br );
1381 VikMapSource *map = MAPS_LAYER_NTH_TYPE(vml->maptype);
1382 if ( vik_map_source_get_drawmode(map) == vp_drawmode &&
1383 vik_map_source_coord_to_mapcoord ( map, &ul, xzoom, yzoom, &ulm ) &&
1384 vik_map_source_coord_to_mapcoord ( map, &br, xzoom, yzoom, &brm ) )
1385 start_download_thread ( vml, vvp, &ul, &br, redownload );
1386 else if (vik_map_source_get_drawmode(map) != vp_drawmode) {
1387 const gchar *drawmode_name = vik_viewport_get_drawmode_name (vvp, vik_map_source_get_drawmode(map));
1388 gchar *err = g_strdup_printf(_("Wrong drawmode for this map.\nSelect \"%s\" from View menu and try again."), _(drawmode_name));
1389 a_dialog_error_msg ( VIK_GTK_WINDOW_FROM_LAYER(vml), err );
1393 a_dialog_error_msg ( VIK_GTK_WINDOW_FROM_LAYER(vml), _("Wrong zoom level for this map.") );
1397 static void maps_layer_download_missing_onscreen_maps ( gpointer vml_vvp[2] )
1399 download_onscreen_maps( vml_vvp, REDOWNLOAD_NONE);
1402 static void maps_layer_download_new_onscreen_maps ( gpointer vml_vvp[2] )
1404 download_onscreen_maps( vml_vvp, REDOWNLOAD_NEW);
1407 static void maps_layer_redownload_all_onscreen_maps ( gpointer vml_vvp[2] )
1409 download_onscreen_maps( vml_vvp, REDOWNLOAD_ALL);
1412 static void maps_layer_add_menu_items ( VikMapsLayer *vml, GtkMenu *menu, VikLayersPanel *vlp )
1414 static gpointer pass_along[2];
1416 pass_along[0] = vml;
1417 pass_along[1] = vik_layers_panel_get_viewport( VIK_LAYERS_PANEL(vlp) );
1419 item = gtk_menu_item_new();
1420 gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item );
1421 gtk_widget_show ( item );
1423 /* Now with icons */
1424 item = gtk_image_menu_item_new_with_mnemonic ( _("Download _Missing Onscreen Maps") );
1425 gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_ADD, GTK_ICON_SIZE_MENU) );
1426 g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(maps_layer_download_missing_onscreen_maps), pass_along );
1427 gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
1428 gtk_widget_show ( item );
1430 if ( vik_map_source_supports_download_only_new (MAPS_LAYER_NTH_TYPE(vml->maptype)) ) {
1431 item = gtk_image_menu_item_new_with_mnemonic ( _("Download _New Onscreen Maps") );
1432 gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_REDO, GTK_ICON_SIZE_MENU) );
1433 g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(maps_layer_download_new_onscreen_maps), pass_along );
1434 gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
1435 gtk_widget_show ( item );
1438 item = gtk_image_menu_item_new_with_mnemonic ( _("Reload _All Onscreen Maps") );
1439 gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_REFRESH, GTK_ICON_SIZE_MENU) );
1440 g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(maps_layer_redownload_all_onscreen_maps), pass_along );
1441 gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
1442 gtk_widget_show ( item );
1446 * Enable downloading maps of the current screen area either 'new' or 'everything'
1448 void vik_maps_layer_download ( VikMapsLayer *vml, VikViewport *vvp, gboolean only_new )
1453 static gpointer pass_along[2];
1454 pass_along[0] = vml;
1455 pass_along[1] = vvp;
1458 // Get only new maps
1459 maps_layer_download_new_onscreen_maps ( pass_along );
1461 // Redownload everything
1462 maps_layer_redownload_all_onscreen_maps ( pass_along );