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 // TODO: Make these configurable
30 #define MAX_TILES 1000
32 #define MAX_SHRINKFACTOR 8.0000001 /* zoom 1 viewing 8-tiles */
33 #define MIN_SHRINKFACTOR 0.0312499 /* zoom 32 viewing 1-tiles */
35 #define REAL_MIN_SHRINKFACTOR 0.0039062499 /* if shrinkfactor is between MAX and REAL_MAX, will only check for existence */
38 #include <gdk-pixbuf/gdk-pixdata.h>
40 #include <glib/gstdio.h>
41 #include <glib/gi18n.h>
55 #include "vikmapsourcedefault.h"
58 #include "background.h"
59 #include "preferences.h"
60 #include "vikmapslayer.h"
61 #include "icons/icons.h"
63 /****** MAP TYPES ******/
65 static GList *__map_types = NULL;
67 #define NUM_MAP_TYPES g_list_length(__map_types)
69 /* List of label for each map type */
70 static gchar **params_maptypes = NULL;
72 /* Corresponding IDS. (Cf. field uniq_id in VikMapsLayer struct) */
73 static guint *params_maptypes_ids = NULL;
75 /******** MAPZOOMS *********/
77 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 };
78 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 };
79 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 };
81 #define NUM_MAPZOOMS (sizeof(params_mapzooms)/sizeof(params_mapzooms[0]) - 1)
83 /**************************/
86 static void maps_layer_post_read (VikLayer *vl, VikViewport *vp, gboolean from_file);
87 static const gchar* maps_layer_tooltip ( VikMapsLayer *vml );
88 static void maps_layer_marshall( VikMapsLayer *vml, guint8 **data, gint *len );
89 static VikMapsLayer *maps_layer_unmarshall( guint8 *data, gint len, VikViewport *vvp );
90 static gboolean maps_layer_set_param ( VikMapsLayer *vml, guint16 id, VikLayerParamData data, VikViewport *vvp, gboolean is_file_operation );
91 static VikLayerParamData maps_layer_get_param ( VikMapsLayer *vml, guint16 id, gboolean is_file_operation );
92 static void maps_layer_draw ( VikMapsLayer *vml, VikViewport *vvp );
93 static VikMapsLayer *maps_layer_new ( VikViewport *vvp );
94 static void maps_layer_free ( VikMapsLayer *vml );
95 static gboolean maps_layer_download_release ( VikMapsLayer *vml, GdkEventButton *event, VikViewport *vvp );
96 static gboolean maps_layer_download_click ( VikMapsLayer *vml, GdkEventButton *event, VikViewport *vvp );
97 static gpointer maps_layer_download_create ( VikWindow *vw, VikViewport *vvp );
98 static void maps_layer_set_cache_dir ( VikMapsLayer *vml, const gchar *dir );
99 static void start_download_thread ( VikMapsLayer *vml, VikViewport *vvp, const VikCoord *ul, const VikCoord *br, gint redownload );
100 static void maps_layer_add_menu_items ( VikMapsLayer *vml, GtkMenu *menu, VikLayersPanel *vlp );
101 static guint map_uniq_id_to_index ( guint uniq_id );
104 static VikLayerParamScale params_scales[] = {
105 /* min, max, step, digits (decimal places) */
106 { 0, 255, 3, 0 }, /* alpha */
109 static VikLayerParamData mode_default ( void ) { return VIK_LPD_UINT ( 19 ); } // OSM MapQuest maps
110 static VikLayerParamData directory_default ( void )
112 VikLayerParamData data;
113 VikLayerParamData *pref = a_preferences_get(VIKING_PREFERENCES_NAMESPACE "maplayer_default_dir");
114 if (pref) data.s = g_strdup ( pref->s );
117 static VikLayerParamData alpha_default ( void ) { return VIK_LPD_UINT ( 255 ); }
118 static VikLayerParamData mapzoom_default ( void ) { return VIK_LPD_UINT ( 0 ); }
120 VikLayerParam maps_layer_params[] = {
121 { VIK_LAYER_MAPS, "mode", VIK_LAYER_PARAM_UINT, VIK_LAYER_GROUP_NONE, N_("Map Type:"), VIK_LAYER_WIDGET_COMBOBOX, NULL, NULL, NULL, mode_default },
122 { VIK_LAYER_MAPS, "directory", VIK_LAYER_PARAM_STRING, VIK_LAYER_GROUP_NONE, N_("Maps Directory:"), VIK_LAYER_WIDGET_FOLDERENTRY, NULL, NULL, NULL, directory_default },
123 { VIK_LAYER_MAPS, "alpha", VIK_LAYER_PARAM_UINT, VIK_LAYER_GROUP_NONE, N_("Alpha:"), VIK_LAYER_WIDGET_HSCALE, params_scales, NULL,
124 N_("Control the Alpha value for transparency effects"), alpha_default },
125 { VIK_LAYER_MAPS, "autodownload", VIK_LAYER_PARAM_BOOLEAN, VIK_LAYER_GROUP_NONE, N_("Autodownload maps:"), VIK_LAYER_WIDGET_CHECKBUTTON, NULL, NULL, NULL, vik_lpd_true_default },
126 { VIK_LAYER_MAPS, "adlonlymissing", VIK_LAYER_PARAM_BOOLEAN, VIK_LAYER_GROUP_NONE, N_("Autodownload Only Gets Missing Maps:"), VIK_LAYER_WIDGET_CHECKBUTTON, NULL, NULL,
127 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."), vik_lpd_false_default },
128 { VIK_LAYER_MAPS, "mapzoom", VIK_LAYER_PARAM_UINT, VIK_LAYER_GROUP_NONE, N_("Zoom Level:"), VIK_LAYER_WIDGET_COMBOBOX, params_mapzooms, NULL,
129 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."),
143 static VikToolInterface maps_tools[] = {
144 { { "MapsDownload", "vik-icon-Maps Download", N_("_Maps Download"), NULL, N_("Maps Download"), 0 },
145 (VikToolConstructorFunc) maps_layer_download_create,
149 (VikToolMouseFunc) maps_layer_download_click,
151 (VikToolMouseFunc) maps_layer_download_release,
154 GDK_CURSOR_IS_PIXMAP, &cursor_mapdl_pixbuf },
157 VikLayerInterface vik_maps_layer_interface = {
161 &vikmapslayer_pixbuf,
164 sizeof(maps_tools) / sizeof(maps_tools[0]),
173 (VikLayerFuncCreate) maps_layer_new,
174 (VikLayerFuncRealize) NULL,
175 (VikLayerFuncPostRead) maps_layer_post_read,
176 (VikLayerFuncFree) maps_layer_free,
178 (VikLayerFuncProperties) NULL,
179 (VikLayerFuncDraw) maps_layer_draw,
180 (VikLayerFuncChangeCoordMode) NULL,
182 (VikLayerFuncSetMenuItemsSelection) NULL,
183 (VikLayerFuncGetMenuItemsSelection) NULL,
185 (VikLayerFuncAddMenuItems) maps_layer_add_menu_items,
186 (VikLayerFuncSublayerAddMenuItems) NULL,
188 (VikLayerFuncSublayerRenameRequest) NULL,
189 (VikLayerFuncSublayerToggleVisible) NULL,
190 (VikLayerFuncSublayerTooltip) NULL,
191 (VikLayerFuncLayerTooltip) maps_layer_tooltip,
192 (VikLayerFuncLayerSelected) NULL,
194 (VikLayerFuncMarshall) maps_layer_marshall,
195 (VikLayerFuncUnmarshall) maps_layer_unmarshall,
197 (VikLayerFuncSetParam) maps_layer_set_param,
198 (VikLayerFuncGetParam) maps_layer_get_param,
200 (VikLayerFuncReadFileData) NULL,
201 (VikLayerFuncWriteFileData) NULL,
203 (VikLayerFuncDeleteItem) NULL,
204 (VikLayerFuncCutItem) NULL,
205 (VikLayerFuncCopyItem) NULL,
206 (VikLayerFuncPasteItem) NULL,
207 (VikLayerFuncFreeCopiedItem) NULL,
208 (VikLayerFuncDragDropRequest) NULL,
210 (VikLayerFuncSelectClick) NULL,
211 (VikLayerFuncSelectMove) NULL,
212 (VikLayerFuncSelectRelease) NULL,
213 (VikLayerFuncSelectedViewportMenu) NULL,
216 struct _VikMapsLayer {
222 gdouble xmapzoom, ymapzoom;
224 gboolean autodownload;
225 gboolean adl_only_missing;
226 VikCoord *last_center;
230 gint dl_tool_x, dl_tool_y;
232 GtkMenu *dl_right_click_menu;
233 VikCoord redownload_ul, redownload_br; /* right click menu only */
234 VikViewport *redownload_vvp;
236 gboolean license_notice_shown; // FALSE for new maps only, otherwise
237 // TRUE for saved maps & other layer changes as we don't need to show it again
240 enum { REDOWNLOAD_NONE = 0, /* download only missing maps */
241 REDOWNLOAD_BAD, /* download missing and bad maps */
242 REDOWNLOAD_NEW, /* download missing maps that are newer on server only */
243 REDOWNLOAD_ALL, /* download all maps */
244 DOWNLOAD_OR_REFRESH }; /* download missing maps and refresh cache */
246 static VikLayerParam prefs[] = {
247 { VIK_LAYER_NUM_TYPES, VIKING_PREFERENCES_NAMESPACE "maplayer_default_dir", VIK_LAYER_PARAM_STRING, VIK_LAYER_GROUP_NONE, N_("Default map layer directory:"), VIK_LAYER_WIDGET_FOLDERENTRY, NULL, NULL, N_("Choose a directory to store cached Map tiles for this layer") },
250 void maps_layer_init ()
252 VikLayerParamData tmp;
253 tmp.s = maps_layer_default_dir();
254 a_preferences_register(prefs, tmp, VIKING_PREFERENCES_GROUP_KEY);
257 /****************************************/
258 /******** MAPS LAYER TYPES **************/
259 /****************************************/
261 int _get_index_for_id ( guint id )
264 while (params_maptypes_ids[index] != 0)
266 if (params_maptypes_ids[index] == id)
273 void _add_map_source ( guint id, const char *label, VikMapSource *map )
277 len = g_strv_length (params_maptypes);
279 params_maptypes = g_realloc (params_maptypes, (len+2)*sizeof(gchar*));
280 params_maptypes[len] = g_strdup (label);
281 params_maptypes[len+1] = NULL;
284 params_maptypes_ids = g_realloc (params_maptypes_ids, (len+2)*sizeof(guint));
285 params_maptypes_ids[len] = id;
286 params_maptypes_ids[len+1] = 0;
288 /* We have to clone */
289 VikMapSource *clone = VIK_MAP_SOURCE(g_object_ref(map));
290 /* Register the clone in the list */
291 __map_types = g_list_append(__map_types, clone);
294 We have to ensure the mode LayerParam references the up-to-date
298 memcpy(&maps_layer_params[0].widget_data, ¶ms_maptypes, sizeof(gpointer));
299 memcpy(&maps_layer_params[0].extra_widget_data, ¶ms_maptypes_ids, sizeof(gpointer));
301 maps_layer_params[0].widget_data = params_maptypes;
302 maps_layer_params[0].extra_widget_data = params_maptypes_ids;
305 void _update_map_source ( const char *label, VikMapSource *map, int index )
307 GList *item = g_list_nth (__map_types, index);
308 g_object_unref (item->data);
309 item->data = g_object_ref (map);
310 /* Change previous data */
311 g_free (params_maptypes[index]);
312 params_maptypes[index] = g_strdup (label);
316 * maps_layer_register_map_source:
317 * @map: the new VikMapSource
319 * Register a new VikMapSource.
320 * Override existing one (equality of id).
322 void maps_layer_register_map_source ( VikMapSource *map )
324 g_assert(map != NULL);
326 guint id = vik_map_source_get_uniq_id(map);
327 const char *label = vik_map_source_get_label(map);
328 g_assert(label != NULL);
330 int previous = map_uniq_id_to_index (id);
331 if (previous != NUM_MAP_TYPES)
333 _update_map_source (label, map, previous);
337 _add_map_source (id, label, map);
341 #define MAPS_LAYER_NTH_LABEL(n) (params_maptypes[n])
342 #define MAPS_LAYER_NTH_ID(n) (params_maptypes_ids[n])
343 #define MAPS_LAYER_NTH_TYPE(n) (VIK_MAP_SOURCE(g_list_nth_data(__map_types, (n))))
345 gint vik_maps_layer_get_map_type(VikMapsLayer *vml)
347 return(vml->maptype);
350 gchar *vik_maps_layer_get_map_label(VikMapsLayer *vml)
352 return(g_strdup(MAPS_LAYER_NTH_LABEL(vml->maptype)));
355 /****************************************/
356 /******** CACHE DIR STUFF ***************/
357 /****************************************/
359 #define DIRECTDIRACCESS "%s%d" G_DIR_SEPARATOR_S "%d" G_DIR_SEPARATOR_S "%d%s"
360 #define DIRSTRUCTURE "%st%ds%dz%d" G_DIR_SEPARATOR_S "%d" G_DIR_SEPARATOR_S "%d"
361 #define MAPS_CACHE_DIR maps_layer_default_dir()
365 #define GLOBAL_MAPS_DIR "C:\\VIKING-MAPS\\"
366 #define LOCAL_MAPS_DIR "VIKING-MAPS"
367 #elif defined __APPLE__
369 #define GLOBAL_MAPS_DIR "/Library/cache/Viking/maps/"
370 #define LOCAL_MAPS_DIR "/Library/Application Support/Viking/viking-maps"
373 #define GLOBAL_MAPS_DIR "/var/cache/maps/"
374 #define LOCAL_MAPS_DIR ".viking-maps"
377 gchar *maps_layer_default_dir ()
379 static gchar *defaultdir = NULL;
382 /* Thanks to Mike Davison for the $VIKING_MAPS usage */
383 const gchar *mapdir = g_getenv("VIKING_MAPS");
385 defaultdir = g_strdup ( mapdir );
386 } else if ( g_access ( GLOBAL_MAPS_DIR, W_OK ) == 0 ) {
387 defaultdir = g_strdup ( GLOBAL_MAPS_DIR );
389 const gchar *home = g_get_home_dir();
390 if (!home || g_access(home, W_OK))
391 home = g_get_home_dir ();
393 defaultdir = g_build_filename ( home, LOCAL_MAPS_DIR, NULL );
395 defaultdir = g_strdup ( LOCAL_MAPS_DIR );
397 if (defaultdir && (defaultdir[strlen(defaultdir)-1] != G_DIR_SEPARATOR))
399 /* Add the separator at the end */
400 gchar *tmp = defaultdir;
401 defaultdir = g_strconcat(tmp, G_DIR_SEPARATOR_S, NULL);
404 g_debug("%s: defaultdir=%s", __FUNCTION__, defaultdir);
409 static void maps_layer_mkdir_if_default_dir ( VikMapsLayer *vml )
411 if ( vml->cache_dir && strcmp ( vml->cache_dir, MAPS_CACHE_DIR ) == 0 && g_file_test ( vml->cache_dir, G_FILE_TEST_EXISTS ) == FALSE )
413 g_mkdir ( vml->cache_dir, 0777 );
417 static void maps_layer_set_cache_dir ( VikMapsLayer *vml, const gchar *dir )
420 g_assert ( vml != NULL);
421 g_free ( vml->cache_dir );
422 vml->cache_dir = NULL;
424 if ( dir == NULL || dir[0] == '\0' )
426 if ( a_preferences_get(VIKING_PREFERENCES_NAMESPACE "maplayer_default_dir") )
427 vml->cache_dir = g_strdup ( a_preferences_get(VIKING_PREFERENCES_NAMESPACE "maplayer_default_dir")->s );
432 if ( dir[len-1] != G_DIR_SEPARATOR )
434 vml->cache_dir = g_malloc ( len+2 );
435 strncpy ( vml->cache_dir, dir, len );
436 vml->cache_dir[len] = G_DIR_SEPARATOR;
437 vml->cache_dir[len+1] = '\0';
440 vml->cache_dir = g_strdup ( dir );
442 maps_layer_mkdir_if_default_dir ( vml );
445 /****************************************/
446 /******** GOBJECT STUFF *****************/
447 /****************************************/
449 GType vik_maps_layer_get_type ()
451 static GType vml_type = 0;
455 static const GTypeInfo vml_info =
457 sizeof (VikMapsLayerClass),
458 NULL, /* base_init */
459 NULL, /* base_finalize */
460 NULL, /* class init */
461 NULL, /* class_finalize */
462 NULL, /* class_data */
463 sizeof (VikMapsLayer),
465 NULL /* instance init */
467 vml_type = g_type_register_static ( VIK_LAYER_TYPE, "VikMapsLayer", &vml_info, 0 );
473 /****************************************/
474 /************** PARAMETERS **************/
475 /****************************************/
477 static guint map_index_to_uniq_id (guint8 index)
479 g_assert ( index < NUM_MAP_TYPES );
480 return vik_map_source_get_uniq_id(MAPS_LAYER_NTH_TYPE(index));
483 static guint map_uniq_id_to_index ( guint uniq_id )
486 for ( i = 0; i < NUM_MAP_TYPES; i++ )
487 if ( vik_map_source_get_uniq_id(MAPS_LAYER_NTH_TYPE(i)) == uniq_id )
489 return NUM_MAP_TYPES; /* no such thing */
492 static gboolean maps_layer_set_param ( VikMapsLayer *vml, guint16 id, VikLayerParamData data, VikViewport *vvp, gboolean is_file_operation )
494 // When loading from a file don't need the license reminder
495 if ( is_file_operation )
496 vml->license_notice_shown = TRUE;
500 case PARAM_CACHE_DIR: maps_layer_set_cache_dir ( vml, data.s ); break;
501 case PARAM_MAPTYPE: {
502 gint maptype = map_uniq_id_to_index(data.u);
503 if ( maptype == NUM_MAP_TYPES ) g_warning(_("Unknown map type"));
504 else vml->maptype = maptype;
507 case PARAM_ALPHA: if ( data.u <= 255 ) vml->alpha = data.u; break;
508 case PARAM_AUTODOWNLOAD: vml->autodownload = data.b; break;
509 case PARAM_ONLYMISSING: vml->adl_only_missing = data.b; break;
510 case PARAM_MAPZOOM: if ( data.u < NUM_MAPZOOMS ) {
511 vml->mapzoom_id = data.u;
512 vml->xmapzoom = __mapzooms_x [data.u];
513 vml->ymapzoom = __mapzooms_y [data.u];
514 }else g_warning (_("Unknown Map Zoom")); break;
519 static VikLayerParamData maps_layer_get_param ( VikMapsLayer *vml, guint16 id, gboolean is_file_operation )
521 VikLayerParamData rv;
524 case PARAM_CACHE_DIR:
526 gboolean set = FALSE;
527 /* Only save a blank when the map cache location equals the default
528 On reading in, when it is blank then the default is reconstructed
529 Since the default changes dependent on the user and OS, it means the resultant file is more portable */
530 if ( is_file_operation && vml->cache_dir && strcmp ( vml->cache_dir, MAPS_CACHE_DIR ) == 0 ) {
534 else if ( is_file_operation ) {
535 if ( a_vik_get_file_ref_format() == VIK_FILE_REF_FORMAT_RELATIVE ) {
536 gchar *cwd = g_get_current_dir();
538 rv.s = file_GetRelativeFilename ( cwd, vml->cache_dir );
539 if ( !rv.s ) rv.s = "";
545 rv.s = vml->cache_dir ? vml->cache_dir : "";
548 case PARAM_MAPTYPE: rv.u = map_index_to_uniq_id ( vml->maptype ); break;
549 case PARAM_ALPHA: rv.u = vml->alpha; break;
550 case PARAM_AUTODOWNLOAD: rv.u = vml->autodownload; break;
551 case PARAM_ONLYMISSING: rv.u = vml->adl_only_missing; break;
552 case PARAM_MAPZOOM: rv.u = vml->mapzoom_id; break;
557 /****************************************/
558 /****** CREATING, COPYING, FREEING ******/
559 /****************************************/
561 static VikMapsLayer *maps_layer_new ( VikViewport *vvp )
563 VikMapsLayer *vml = VIK_MAPS_LAYER ( g_object_new ( VIK_MAPS_LAYER_TYPE, NULL ) );
564 vik_layer_set_type ( VIK_LAYER(vml), VIK_LAYER_MAPS );
566 vik_layer_set_defaults ( VIK_LAYER(vml), vvp );
568 vml->dl_tool_x = vml->dl_tool_y = -1;
569 vml->last_center = NULL;
570 vml->last_xmpp = 0.0;
571 vml->last_ympp = 0.0;
573 vml->dl_right_click_menu = NULL;
574 vml->license_notice_shown = FALSE;
579 static void maps_layer_free ( VikMapsLayer *vml )
581 g_free ( vml->cache_dir );
582 vml->cache_dir = NULL;
583 if ( vml->dl_right_click_menu )
584 g_object_ref_sink ( G_OBJECT(vml->dl_right_click_menu) );
585 g_free(vml->last_center);
586 vml->last_center = NULL;
589 static void maps_layer_post_read (VikLayer *vl, VikViewport *vp, gboolean from_file)
591 if (from_file != TRUE)
593 /* If this method is not called in file reading context
594 * it is called in GUI context.
595 * So, we can check if we have to inform the user about inconsistency */
596 VikViewportDrawMode vp_drawmode;
597 VikMapsLayer *vml = VIK_MAPS_LAYER(vl);
598 VikMapSource *map = NULL;
600 vp_drawmode = vik_viewport_get_drawmode ( vp );
601 map = MAPS_LAYER_NTH_TYPE(vml->maptype);
602 if (vik_map_source_get_drawmode(map) != vp_drawmode) {
603 const gchar *drawmode_name = vik_viewport_get_drawmode_name (vp, vik_map_source_get_drawmode(map));
604 gchar *msg = g_strdup_printf(_("New map cannot be displayed in the current drawmode.\nSelect \"%s\" from View menu to view it."), drawmode_name);
605 a_dialog_warning_msg ( VIK_GTK_WINDOW_FROM_WIDGET(vp), msg );
609 if (vik_map_source_get_license (map) != NULL) {
610 if ( ! vml->license_notice_shown ) {
611 a_dialog_license (VIK_GTK_WINDOW_FROM_WIDGET(vp), vik_map_source_get_label (map),
612 vik_map_source_get_license (map), vik_map_source_get_license_url (map) );
613 vml->license_notice_shown = TRUE;
619 static const gchar* maps_layer_tooltip ( VikMapsLayer *vml )
621 return vik_maps_layer_get_map_label ( vml );
624 static void maps_layer_marshall( VikMapsLayer *vml, guint8 **data, gint *len )
626 vik_layer_marshall_params ( VIK_LAYER(vml), data, len );
629 static VikMapsLayer *maps_layer_unmarshall( guint8 *data, gint len, VikViewport *vvp )
631 VikMapsLayer *rv = maps_layer_new ( vvp );
632 vik_layer_unmarshall_params ( VIK_LAYER(rv), data, len, vvp );
636 /*********************/
637 /****** DRAWING ******/
638 /*********************/
640 static GdkPixbuf *pixbuf_set_alpha ( GdkPixbuf *pixbuf, guint8 alpha )
643 gint width, height, iii, jjj;
645 if ( ! gdk_pixbuf_get_has_alpha ( pixbuf ) )
647 GdkPixbuf *tmp = gdk_pixbuf_add_alpha(pixbuf,FALSE,0,0,0);
648 g_object_unref(G_OBJECT(pixbuf));
652 pixels = gdk_pixbuf_get_pixels(pixbuf);
653 width = gdk_pixbuf_get_width(pixbuf);
654 height = gdk_pixbuf_get_height(pixbuf);
656 /* r,g,b,a,r,g,b,a.... */
657 for (iii = 0; iii < width; iii++) for (jjj = 0; jjj < height; jjj++)
665 static GdkPixbuf *pixbuf_shrink ( GdkPixbuf *pixbuf, gdouble xshrinkfactor, gdouble yshrinkfactor )
668 guint16 width = gdk_pixbuf_get_width(pixbuf), height = gdk_pixbuf_get_height(pixbuf);
669 tmp = gdk_pixbuf_scale_simple(pixbuf, ceil(width * xshrinkfactor), ceil(height * yshrinkfactor), GDK_INTERP_BILINEAR);
670 g_object_unref ( G_OBJECT(pixbuf) );
674 static GdkPixbuf *get_pixbuf( VikMapsLayer *vml, gint mode, MapCoord *mapcoord, gchar *filename_buf, gint buf_len, gdouble xshrinkfactor, gdouble yshrinkfactor )
679 pixbuf = a_mapcache_get ( mapcoord->x, mapcoord->y, mapcoord->z,
680 mode, mapcoord->scale, vml->alpha, xshrinkfactor, yshrinkfactor );
683 if ( vik_map_source_is_direct_file_access (MAPS_LAYER_NTH_TYPE(vml->maptype)) )
684 g_snprintf ( filename_buf, buf_len, DIRECTDIRACCESS,
685 vml->cache_dir, (17 - mapcoord->scale), mapcoord->x, mapcoord->y, ".png" );
687 g_snprintf ( filename_buf, buf_len, DIRSTRUCTURE,
688 vml->cache_dir, mode,
689 mapcoord->scale, mapcoord->z, mapcoord->x, mapcoord->y );
691 if ( g_file_test ( filename_buf, G_FILE_TEST_EXISTS ) == TRUE)
694 pixbuf = gdk_pixbuf_new_from_file ( filename_buf, &gx );
696 /* free the pixbuf on error */
699 if ( gx->domain != GDK_PIXBUF_ERROR || gx->code != GDK_PIXBUF_ERROR_CORRUPT_IMAGE )
700 g_warning ( _("Couldn't open image file: %s"), gx->message );
704 g_object_unref ( G_OBJECT(pixbuf) );
707 if ( vml->alpha < 255 )
708 pixbuf = pixbuf_set_alpha ( pixbuf, vml->alpha );
709 if ( xshrinkfactor != 1.0 || yshrinkfactor != 1.0 )
710 pixbuf = pixbuf_shrink ( pixbuf, xshrinkfactor, yshrinkfactor );
712 a_mapcache_add ( pixbuf, mapcoord->x, mapcoord->y,
713 mapcoord->z, vik_map_source_get_uniq_id(MAPS_LAYER_NTH_TYPE(vml->maptype)),
714 mapcoord->scale, vml->alpha, xshrinkfactor, yshrinkfactor );
721 static gboolean should_start_autodownload(VikMapsLayer *vml, VikViewport *vvp)
723 const VikCoord *center = vik_viewport_get_center ( vvp );
725 if (vik_window_get_pan_move (VIK_WINDOW(VIK_GTK_WINDOW_FROM_WIDGET(GTK_WIDGET(vvp)))))
726 /* D'n'D pan in action: do not download */
730 // Prevent requests for downloading tiles at Zoom Level 19 and above for most map types
731 // Allow MapQuest Zoom Level up to 19
732 // TODO: This should be made a property of the map source and then use that value
733 gdouble xzoom = vik_viewport_get_xmpp ( vvp );
734 if ( (vml->maptype != 19 && map_utils_mpp_to_scale (xzoom) < -1) || (vml->maptype == 19 && map_utils_mpp_to_scale (xzoom) < -2) )
737 if (vml->last_center == NULL) {
738 VikCoord *new_center = g_malloc(sizeof(VikCoord));
739 *new_center = *center;
740 vml->last_center = new_center;
741 vml->last_xmpp = vik_viewport_get_xmpp(vvp);
742 vml->last_ympp = vik_viewport_get_ympp(vvp);
746 /* TODO: perhaps vik_coord_diff() */
747 if (vik_coord_equals(vml->last_center, center)
748 && (vml->last_xmpp == vik_viewport_get_xmpp(vvp))
749 && (vml->last_ympp == vik_viewport_get_ympp(vvp)))
752 *(vml->last_center) = *center;
753 vml->last_xmpp = vik_viewport_get_xmpp(vvp);
754 vml->last_ympp = vik_viewport_get_ympp(vvp);
758 static void maps_layer_draw_section ( VikMapsLayer *vml, VikViewport *vvp, VikCoord *ul, VikCoord *br )
761 gdouble xzoom = vik_viewport_get_xmpp ( vvp );
762 gdouble yzoom = vik_viewport_get_ympp ( vvp );
763 gdouble xshrinkfactor = 1.0, yshrinkfactor = 1.0;
764 gboolean existence_only = FALSE;
766 if ( vml->xmapzoom && (vml->xmapzoom != xzoom || vml->ymapzoom != yzoom) ) {
767 xshrinkfactor = vml->xmapzoom / xzoom;
768 yshrinkfactor = vml->ymapzoom / yzoom;
769 xzoom = vml->xmapzoom;
770 yzoom = vml->xmapzoom;
771 if ( ! (xshrinkfactor > MIN_SHRINKFACTOR && xshrinkfactor < MAX_SHRINKFACTOR &&
772 yshrinkfactor > MIN_SHRINKFACTOR && yshrinkfactor < MAX_SHRINKFACTOR ) ) {
773 if ( xshrinkfactor > REAL_MIN_SHRINKFACTOR && yshrinkfactor > REAL_MIN_SHRINKFACTOR ) {
774 g_debug ( "%s: existence_only due to SHRINKFACTORS", __FUNCTION__ );
775 existence_only = TRUE;
778 g_warning ( _("Cowardly refusing to draw tiles or existence of tiles beyond %d zoom out factor"), (int)( 1.0/REAL_MIN_SHRINKFACTOR));
785 VikMapSource *map = MAPS_LAYER_NTH_TYPE(vml->maptype);
786 if ( vik_map_source_coord_to_mapcoord ( map, ul, xzoom, yzoom, &ulm ) &&
787 vik_map_source_coord_to_mapcoord ( map, br, xzoom, yzoom, &brm ) ) {
791 gint xmin = MIN(ulm.x, brm.x), xmax = MAX(ulm.x, brm.x);
792 gint ymin = MIN(ulm.y, brm.y), ymax = MAX(ulm.y, brm.y);
793 gint mode = vik_map_source_get_uniq_id(map);
796 gint xx, yy, width, height;
799 // Prevent the program grinding to a halt if trying to deal with thousands of tiles
800 // which can happen when using a small fixed zoom level and viewing large areas.
801 // Also prevents very large number of tile download requests
802 gint tiles = (xmax-xmin) * (ymax-ymin);
803 if ( tiles > MAX_TILES ) {
804 g_debug ( "%s: existence_only due to wanting too many tiles (%d)", __FUNCTION__, tiles );
805 existence_only = TRUE;
808 guint max_path_len = strlen(vml->cache_dir) + 40;
809 gchar *path_buf = g_malloc ( max_path_len * sizeof(char) );
811 if ( (!existence_only) && vml->autodownload && should_start_autodownload(vml, vvp)) {
812 g_debug("%s: Starting autodownload", __FUNCTION__);
813 if ( !vml->adl_only_missing && vik_map_source_supports_download_only_new (map) )
814 // Try to download newer tiles
815 start_download_thread ( vml, vvp, ul, br, REDOWNLOAD_NEW );
817 // Download only missing tiles
818 start_download_thread ( vml, vvp, ul, br, REDOWNLOAD_NONE );
821 if ( vik_map_source_get_tilesize_x(map) == 0 && !existence_only ) {
822 for ( x = xmin; x <= xmax; x++ ) {
823 for ( y = ymin; y <= ymax; y++ ) {
826 pixbuf = get_pixbuf ( vml, mode, &ulm, path_buf, max_path_len, xshrinkfactor, yshrinkfactor );
828 width = gdk_pixbuf_get_width ( pixbuf );
829 height = gdk_pixbuf_get_height ( pixbuf );
831 vik_map_source_mapcoord_to_center_coord ( map, &ulm, &coord );
832 vik_viewport_coord_to_screen ( vvp, &coord, &xx, &yy );
836 vik_viewport_draw_pixbuf ( vvp, pixbuf, 0, 0, xx, yy, width, height );
840 } else { /* tilesize is known, don't have to keep converting coords */
841 gdouble tilesize_x = vik_map_source_get_tilesize_x(map) * xshrinkfactor;
842 gdouble tilesize_y = vik_map_source_get_tilesize_y(map) * yshrinkfactor;
843 /* ceiled so tiles will be maximum size in the case of funky shrinkfactor */
844 gint tilesize_x_ceil = ceil ( tilesize_x );
845 gint tilesize_y_ceil = ceil ( tilesize_y );
846 gint8 xinc = (ulm.x == xmin) ? 1 : -1;
847 gint8 yinc = (ulm.y == ymin) ? 1 : -1;
848 gdouble xx, yy; gint xx_tmp, yy_tmp;
849 gint base_yy, xend, yend;
851 xend = (xinc == 1) ? (xmax+1) : (xmin-1);
852 yend = (yinc == 1) ? (ymax+1) : (ymin-1);
854 vik_map_source_mapcoord_to_center_coord ( map, &ulm, &coord );
855 vik_viewport_coord_to_screen ( vvp, &coord, &xx_tmp, &yy_tmp );
856 xx = xx_tmp; yy = yy_tmp;
857 /* above trick so xx,yy doubles. this is so shrinkfactors aren't rounded off
858 * eg if tile size 128, shrinkfactor 0.333 */
859 xx -= (tilesize_x/2);
860 base_yy = yy - (tilesize_y/2);
862 for ( x = ((xinc == 1) ? xmin : xmax); x != xend; x+=xinc ) {
864 for ( y = ((yinc == 1) ? ymin : ymax); y != yend; y+=yinc ) {
868 if ( existence_only ) {
869 if ( vik_map_source_is_direct_file_access (MAPS_LAYER_NTH_TYPE(vml->maptype)) )
870 g_snprintf ( path_buf, max_path_len, DIRECTDIRACCESS,
871 vml->cache_dir, (17 - ulm.scale), ulm.x, ulm.y, ".png" );
873 g_snprintf ( path_buf, max_path_len, DIRSTRUCTURE,
874 vml->cache_dir, mode,
875 ulm.scale, ulm.z, ulm.x, ulm.y );
876 if ( g_file_test ( path_buf, G_FILE_TEST_EXISTS ) == TRUE ) {
877 GdkGC *black_gc = gtk_widget_get_style(GTK_WIDGET(vvp))->black_gc;
878 vik_viewport_draw_line ( vvp, black_gc, xx+tilesize_x_ceil, yy, xx, yy+tilesize_y_ceil );
882 for (scale_inc = 0; scale_inc < 4; scale_inc ++) {
883 /* try with correct then smaller zooms */
884 int scale_factor = 1 << scale_inc; /* 2^scale_inc */
886 ulm2.x = ulm.x / scale_factor;
887 ulm2.y = ulm.y / scale_factor;
888 ulm2.scale = ulm.scale + scale_inc;
889 pixbuf = get_pixbuf ( vml, mode, &ulm2, path_buf, max_path_len, xshrinkfactor * scale_factor, yshrinkfactor * scale_factor );
891 gint src_x = (ulm.x % scale_factor) * tilesize_x_ceil;
892 gint src_y = (ulm.y % scale_factor) * tilesize_y_ceil;
894 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);
896 vik_viewport_draw_pixbuf ( vvp, pixbuf, src_x, src_y, xx, yy, tilesize_x_ceil, tilesize_y_ceil );
901 /* retry with bigger zooms */
903 for (scale_dec = 1; scale_dec < 2; scale_dec ++) {
905 int scale_factor = 1 << scale_dec; /* 2^scale_dec */
907 ulm2.x = ulm.x * scale_factor;
908 ulm2.y = ulm.y * scale_factor;
909 ulm2.scale = ulm.scale - scale_dec;
910 for (pict_x = 0; pict_x < scale_factor; pict_x ++) {
911 for (pict_y = 0; pict_y < scale_factor; pict_y ++) {
912 MapCoord ulm3 = ulm2;
915 pixbuf = get_pixbuf ( vml, mode, &ulm3, path_buf, max_path_len, xshrinkfactor / scale_factor, yshrinkfactor / scale_factor );
919 gint dest_x = xx + pict_x * (tilesize_x_ceil / scale_factor);
920 gint dest_y = yy + pict_y * (tilesize_y_ceil / scale_factor);
921 vik_viewport_draw_pixbuf ( vvp, pixbuf, src_x, src_y, dest_x, dest_y, tilesize_x_ceil / scale_factor, tilesize_y_ceil / scale_factor );
939 static void maps_layer_draw ( VikMapsLayer *vml, VikViewport *vvp )
941 if ( vik_map_source_get_drawmode(MAPS_LAYER_NTH_TYPE(vml->maptype)) == vik_viewport_get_drawmode ( vvp ) )
946 gdouble level = vik_viewport_get_zoom ( vvp );
948 vik_viewport_get_min_max_lat_lon ( vvp, &bbox.south, &bbox.north, &bbox.west, &bbox.east );
949 vik_map_source_get_copyright ( MAPS_LAYER_NTH_TYPE(vml->maptype), bbox, level, vik_viewport_add_copyright, vvp );
952 const GdkPixbuf *logo = vik_map_source_get_logo ( MAPS_LAYER_NTH_TYPE(vml->maptype) );
953 vik_viewport_add_logo ( vvp, logo );
955 /* get corner coords */
956 if ( vik_viewport_get_coord_mode ( vvp ) == VIK_COORD_UTM && ! vik_viewport_is_one_zone ( vvp ) ) {
957 /* UTM multi-zone stuff by Kit Transue */
958 gchar leftmost_zone, rightmost_zone, i;
959 leftmost_zone = vik_viewport_leftmost_zone( vvp );
960 rightmost_zone = vik_viewport_rightmost_zone( vvp );
961 for ( i = leftmost_zone; i <= rightmost_zone; ++i ) {
962 vik_viewport_corners_for_zonen ( vvp, i, &ul, &br );
963 maps_layer_draw_section ( vml, vvp, &ul, &br );
967 vik_viewport_screen_to_coord ( vvp, 0, 0, &ul );
968 vik_viewport_screen_to_coord ( vvp, vik_viewport_get_width(vvp), vik_viewport_get_height(vvp), &br );
970 maps_layer_draw_section ( vml, vvp, &ul, &br );
975 /*************************/
976 /****** DOWNLOADING ******/
977 /*************************/
979 /* pass along data to thread, exists even if layer is deleted. */
989 gboolean refresh_display;
992 gboolean map_layer_alive;
996 static void mdi_free ( MapDownloadInfo *mdi )
998 g_mutex_free(mdi->mutex);
999 g_free ( mdi->cache_dir );
1000 mdi->cache_dir = NULL;
1001 g_free ( mdi->filename_buf );
1002 mdi->filename_buf = NULL;
1006 static void weak_ref_cb(gpointer ptr, GObject * dead_vml)
1008 MapDownloadInfo *mdi = ptr;
1009 g_mutex_lock(mdi->mutex);
1010 mdi->map_layer_alive = FALSE;
1011 g_mutex_unlock(mdi->mutex);
1014 static int map_download_thread ( MapDownloadInfo *mdi, gpointer threaddata )
1016 void *handle = vik_map_source_download_handle_init(MAPS_LAYER_NTH_TYPE(mdi->maptype));
1019 for ( x = mdi->x0; x <= mdi->xf; x++ )
1021 for ( y = mdi->y0; y <= mdi->yf; y++ )
1023 gboolean remove_mem_cache = FALSE;
1024 gboolean need_download = FALSE;
1025 g_snprintf ( mdi->filename_buf, mdi->maxlen, DIRSTRUCTURE,
1026 mdi->cache_dir, vik_map_source_get_uniq_id(MAPS_LAYER_NTH_TYPE(mdi->maptype)),
1027 mdi->mapcoord.scale, mdi->mapcoord.z, x, y );
1030 int res = a_background_thread_progress ( threaddata, ((gdouble)donemaps) / mdi->mapstoget ); /* this also calls testcancel */
1032 vik_map_source_download_handle_cleanup(MAPS_LAYER_NTH_TYPE(mdi->maptype), handle);
1036 if ( g_file_test ( mdi->filename_buf, G_FILE_TEST_EXISTS ) == FALSE ) {
1037 need_download = TRUE;
1038 remove_mem_cache = TRUE;
1040 } else { /* in case map file already exists */
1041 switch (mdi->redownload) {
1042 case REDOWNLOAD_NONE:
1045 case REDOWNLOAD_BAD:
1047 /* see if this one is bad or what */
1049 GdkPixbuf *pixbuf = gdk_pixbuf_new_from_file ( mdi->filename_buf, &gx );
1050 if (gx || (!pixbuf)) {
1051 g_remove ( mdi->filename_buf );
1052 need_download = TRUE;
1053 remove_mem_cache = TRUE;
1054 g_error_free ( gx );
1057 g_object_unref ( pixbuf );
1062 case REDOWNLOAD_NEW:
1063 need_download = TRUE;
1064 remove_mem_cache = TRUE;
1067 case REDOWNLOAD_ALL:
1068 /* FIXME: need a better way than to erase file in case of server/network problem */
1069 g_remove ( mdi->filename_buf );
1070 need_download = TRUE;
1071 remove_mem_cache = TRUE;
1074 case DOWNLOAD_OR_REFRESH:
1075 remove_mem_cache = TRUE;
1079 g_warning ( "redownload state %d unknown\n", mdi->redownload);
1083 mdi->mapcoord.x = x; mdi->mapcoord.y = y;
1085 if (need_download) {
1086 if ( vik_map_source_download( MAPS_LAYER_NTH_TYPE(mdi->maptype), &(mdi->mapcoord), mdi->filename_buf, handle))
1090 g_mutex_lock(mdi->mutex);
1091 if (remove_mem_cache)
1092 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 );
1093 if (mdi->refresh_display && mdi->map_layer_alive) {
1094 /* TODO: check if it's on visible area */
1095 vik_layer_emit_update ( VIK_LAYER(mdi->vml) ); // NB update display from background
1097 g_mutex_unlock(mdi->mutex);
1098 mdi->mapcoord.x = mdi->mapcoord.y = 0; /* we're temporarily between downloads */
1102 vik_map_source_download_handle_cleanup(MAPS_LAYER_NTH_TYPE(mdi->maptype), handle);
1103 g_mutex_lock(mdi->mutex);
1104 if (mdi->map_layer_alive)
1105 g_object_weak_unref(G_OBJECT(mdi->vml), weak_ref_cb, mdi);
1106 g_mutex_unlock(mdi->mutex);
1110 static void mdi_cancel_cleanup ( MapDownloadInfo *mdi )
1112 if ( mdi->mapcoord.x || mdi->mapcoord.y )
1114 g_snprintf ( mdi->filename_buf, mdi->maxlen, DIRSTRUCTURE,
1115 mdi->cache_dir, vik_map_source_get_uniq_id(MAPS_LAYER_NTH_TYPE(mdi->maptype)),
1116 mdi->mapcoord.scale, mdi->mapcoord.z, mdi->mapcoord.x, mdi->mapcoord.y );
1117 if ( g_file_test ( mdi->filename_buf, G_FILE_TEST_EXISTS ) == TRUE)
1119 g_remove ( mdi->filename_buf );
1124 static void start_download_thread ( VikMapsLayer *vml, VikViewport *vvp, const VikCoord *ul, const VikCoord *br, gint redownload )
1126 gdouble xzoom = vml->xmapzoom ? vml->xmapzoom : vik_viewport_get_xmpp ( vvp );
1127 gdouble yzoom = vml->ymapzoom ? vml->ymapzoom : vik_viewport_get_ympp ( vvp );
1129 VikMapSource *map = MAPS_LAYER_NTH_TYPE(vml->maptype);
1131 // Don't ever attempt download on direct access
1132 if ( vik_map_source_is_direct_file_access ( map ) )
1135 if ( vik_map_source_coord_to_mapcoord ( map, ul, xzoom, yzoom, &ulm )
1136 && vik_map_source_coord_to_mapcoord ( map, br, xzoom, yzoom, &brm ) )
1138 MapDownloadInfo *mdi = g_malloc ( sizeof(MapDownloadInfo) );
1143 mdi->map_layer_alive = TRUE;
1144 mdi->mutex = g_mutex_new();
1145 mdi->refresh_display = TRUE;
1147 /* cache_dir and buffer for dest filename */
1148 mdi->cache_dir = g_strdup ( vml->cache_dir );
1149 mdi->maxlen = strlen ( vml->cache_dir ) + 40;
1150 mdi->filename_buf = g_malloc ( mdi->maxlen * sizeof(gchar) );
1151 mdi->maptype = vml->maptype;
1153 mdi->mapcoord = ulm;
1154 mdi->redownload = redownload;
1156 mdi->x0 = MIN(ulm.x, brm.x);
1157 mdi->xf = MAX(ulm.x, brm.x);
1158 mdi->y0 = MIN(ulm.y, brm.y);
1159 mdi->yf = MAX(ulm.y, brm.y);
1163 if ( mdi->redownload ) {
1164 mdi->mapstoget = (mdi->xf - mdi->x0 + 1) * (mdi->yf - mdi->y0 + 1);
1166 /* calculate how many we need */
1167 for ( a = mdi->x0; a <= mdi->xf; a++ )
1169 for ( b = mdi->y0; b <= mdi->yf; b++ )
1171 g_snprintf ( mdi->filename_buf, mdi->maxlen, DIRSTRUCTURE,
1172 vml->cache_dir, vik_map_source_get_uniq_id(map), ulm.scale,
1174 if ( g_file_test ( mdi->filename_buf, G_FILE_TEST_EXISTS ) == FALSE )
1180 mdi->mapcoord.x = mdi->mapcoord.y = 0; /* for cleanup -- no current map */
1182 if ( mdi->mapstoget )
1184 const gchar *tmp_str;
1189 if (redownload == REDOWNLOAD_BAD)
1190 tmp_str = ngettext("Redownloading up to %d %s map...", "Redownloading up to %d %s maps...", mdi->mapstoget);
1192 tmp_str = ngettext("Redownloading %d %s map...", "Redownloading %d %s maps...", mdi->mapstoget);
1196 tmp_str = ngettext("Downloading %d %s map...", "Downloading %d %s maps...", mdi->mapstoget);
1198 tmp = g_strdup_printf ( tmp_str, mdi->mapstoget, MAPS_LAYER_NTH_LABEL(vml->maptype));
1200 g_object_weak_ref(G_OBJECT(mdi->vml), weak_ref_cb, mdi);
1201 /* launch the thread */
1202 a_background_thread ( VIK_GTK_WINDOW_FROM_LAYER(vml), /* parent window */
1203 tmp, /* description string */
1204 (vik_thr_func) map_download_thread, /* function to call within thread */
1205 mdi, /* pass along data */
1206 (vik_thr_free_func) mdi_free, /* function to free pass along data */
1207 (vik_thr_free_func) mdi_cancel_cleanup,
1216 static void maps_layer_download_section ( VikMapsLayer *vml, VikViewport *vvp, VikCoord *ul, VikCoord *br, gdouble zoom, gint download_method )
1219 VikMapSource *map = MAPS_LAYER_NTH_TYPE(vml->maptype);
1221 // Don't ever attempt download on direct access
1222 if ( vik_map_source_is_direct_file_access ( map ) )
1225 if (!vik_map_source_coord_to_mapcoord(map, ul, zoom, zoom, &ulm)
1226 || !vik_map_source_coord_to_mapcoord(map, br, zoom, zoom, &brm)) {
1227 g_warning("%s() coord_to_mapcoord() failed", __PRETTY_FUNCTION__);
1231 MapDownloadInfo *mdi = g_malloc(sizeof(MapDownloadInfo));
1236 mdi->map_layer_alive = TRUE;
1237 mdi->mutex = g_mutex_new();
1238 mdi->refresh_display = TRUE;
1240 mdi->cache_dir = g_strdup ( vml->cache_dir );
1241 mdi->maxlen = strlen ( vml->cache_dir ) + 40;
1242 mdi->filename_buf = g_malloc ( mdi->maxlen * sizeof(gchar) );
1243 mdi->maptype = vml->maptype;
1245 mdi->mapcoord = ulm;
1246 mdi->redownload = download_method;
1248 mdi->x0 = MIN(ulm.x, brm.x);
1249 mdi->xf = MAX(ulm.x, brm.x);
1250 mdi->y0 = MIN(ulm.y, brm.y);
1251 mdi->yf = MAX(ulm.y, brm.y);
1255 for (i = mdi->x0; i <= mdi->xf; i++) {
1256 for (j = mdi->y0; j <= mdi->yf; j++) {
1257 g_snprintf ( mdi->filename_buf, mdi->maxlen, DIRSTRUCTURE,
1258 vml->cache_dir, vik_map_source_get_uniq_id(map), ulm.scale,
1260 if ( g_file_test ( mdi->filename_buf, G_FILE_TEST_EXISTS ) == FALSE )
1265 mdi->mapcoord.x = mdi->mapcoord.y = 0; /* for cleanup -- no current map */
1267 if (mdi->mapstoget) {
1270 fmt = ngettext("Downloading %d %s map...",
1271 "Downloading %d %s maps...",
1273 tmp = g_strdup_printf ( fmt, mdi->mapstoget, MAPS_LAYER_NTH_LABEL(vml->maptype) );
1275 g_object_weak_ref(G_OBJECT(mdi->vml), weak_ref_cb, mdi);
1276 /* launch the thread */
1277 a_background_thread ( VIK_GTK_WINDOW_FROM_LAYER(vml), /* parent window */
1278 tmp, /* description string */
1279 (vik_thr_func) map_download_thread, /* function to call within thread */
1280 mdi, /* pass along data */
1281 (vik_thr_free_func) mdi_free, /* function to free pass along data */
1282 (vik_thr_free_func) mdi_cancel_cleanup,
1291 * vik_maps_layer_download_section:
1292 * @vml: The Map Layer
1293 * @vvp: The Viewport that the map is on
1294 * @ul: Upper left coordinate of the area to be downloaded
1295 * @br: Bottom right coordinate of the area to be downloaded
1296 * @zoom: The zoom level at which the maps are to be download
1298 * Download a specified map area at a certain zoom level
1300 void vik_maps_layer_download_section ( VikMapsLayer *vml, VikViewport *vvp, VikCoord *ul, VikCoord *br, gdouble zoom )
1302 maps_layer_download_section (vml, vvp, ul, br, zoom, REDOWNLOAD_NONE);
1305 static void maps_layer_redownload_bad ( VikMapsLayer *vml )
1307 start_download_thread ( vml, vml->redownload_vvp, &(vml->redownload_ul), &(vml->redownload_br), REDOWNLOAD_BAD );
1310 static void maps_layer_redownload_all ( VikMapsLayer *vml )
1312 start_download_thread ( vml, vml->redownload_vvp, &(vml->redownload_ul), &(vml->redownload_br), REDOWNLOAD_ALL );
1315 static void maps_layer_redownload_new ( VikMapsLayer *vml )
1317 start_download_thread ( vml, vml->redownload_vvp, &(vml->redownload_ul), &(vml->redownload_br), REDOWNLOAD_NEW );
1321 * Display a simple dialog with information about this particular map tile
1323 static void maps_layer_tile_info ( VikMapsLayer *vml )
1325 VikMapSource *map = MAPS_LAYER_NTH_TYPE(vml->maptype);
1327 gdouble xzoom = vml->xmapzoom ? vml->xmapzoom : vik_viewport_get_xmpp ( vml->redownload_vvp );
1328 gdouble yzoom = vml->ymapzoom ? vml->ymapzoom : vik_viewport_get_ympp ( vml->redownload_vvp );
1331 if ( !vik_map_source_coord_to_mapcoord ( map, &(vml->redownload_ul), xzoom, yzoom, &ulm ) )
1334 gchar *filename = NULL;
1335 gchar *message = NULL;
1336 gchar *source = NULL;
1338 if ( vik_map_source_is_direct_file_access ( map ) ) {
1339 filename = g_strdup_printf ( DIRECTDIRACCESS, vml->cache_dir, ulm.scale, ulm.x, ulm.y, ".png" );
1340 source = g_strconcat ( "file://", filename, NULL );
1343 filename = g_strdup_printf ( DIRSTRUCTURE, vml->cache_dir, vik_map_source_get_uniq_id(map), ulm.scale, ulm.z, ulm.x, ulm.y );
1344 source = g_strdup_printf ( "http://%s%s",
1345 vik_map_source_default_get_hostname ( VIK_MAP_SOURCE_DEFAULT(map) ),
1346 vik_map_source_default_get_uri ( VIK_MAP_SOURCE_DEFAULT(map), &ulm ) );
1349 if ( g_file_test ( filename, G_FILE_TEST_EXISTS ) ) {
1351 // Get some timestamp information of the tile
1352 struct stat stat_buf;
1353 if ( g_stat ( filename, &stat_buf ) == 0 ) {
1355 strftime ( time_buf, sizeof(time_buf), "%c", gmtime((const time_t *)&stat_buf.st_mtime) );
1356 message = g_strdup_printf ( _("\nSource: %s\n\nTile File: %s\nTile File Timestamp: %s"), source, filename, time_buf );
1360 message = g_strdup_printf ( _("Source: %s\n\nNo Tile File!"), source );
1363 a_dialog_info_msg ( VIK_GTK_WINDOW_FROM_LAYER(vml), message );
1367 g_free ( filename );
1370 static gboolean maps_layer_download_release ( VikMapsLayer *vml, GdkEventButton *event, VikViewport *vvp )
1372 if (!vml || vml->vl.type != VIK_LAYER_MAPS)
1374 if ( vml->dl_tool_x != -1 && vml->dl_tool_y != -1 )
1376 if ( event->button == 1 )
1379 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 );
1380 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 );
1381 start_download_thread ( vml, vvp, &ul, &br, DOWNLOAD_OR_REFRESH );
1382 vml->dl_tool_x = vml->dl_tool_y = -1;
1387 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) );
1388 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) );
1390 vml->redownload_vvp = vvp;
1392 vml->dl_tool_x = vml->dl_tool_y = -1;
1394 if ( ! vml->dl_right_click_menu ) {
1396 vml->dl_right_click_menu = GTK_MENU ( gtk_menu_new () );
1398 item = gtk_menu_item_new_with_mnemonic ( _("Redownload _Bad Map(s)") );
1399 g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(maps_layer_redownload_bad), vml );
1400 gtk_menu_shell_append ( GTK_MENU_SHELL(vml->dl_right_click_menu), item );
1402 item = gtk_menu_item_new_with_mnemonic ( _("Redownload _New Map(s)") );
1403 g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(maps_layer_redownload_new), vml );
1404 gtk_menu_shell_append ( GTK_MENU_SHELL(vml->dl_right_click_menu), item );
1406 item = gtk_menu_item_new_with_mnemonic ( _("Redownload _All Map(s)") );
1407 g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(maps_layer_redownload_all), vml );
1408 gtk_menu_shell_append ( GTK_MENU_SHELL(vml->dl_right_click_menu), item );
1410 item = gtk_image_menu_item_new_with_mnemonic ( _("_Show Tile Information") );
1411 gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_INFO, GTK_ICON_SIZE_MENU) );
1412 g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(maps_layer_tile_info), vml );
1413 gtk_menu_shell_append (GTK_MENU_SHELL(vml->dl_right_click_menu), item);
1416 gtk_menu_popup ( vml->dl_right_click_menu, NULL, NULL, NULL, NULL, event->button, event->time );
1417 gtk_widget_show_all ( GTK_WIDGET(vml->dl_right_click_menu) );
1423 static gpointer maps_layer_download_create ( VikWindow *vw, VikViewport *vvp)
1428 static gboolean maps_layer_download_click ( VikMapsLayer *vml, GdkEventButton *event, VikViewport *vvp )
1431 if (!vml || vml->vl.type != VIK_LAYER_MAPS)
1433 VikMapSource *map = MAPS_LAYER_NTH_TYPE(vml->maptype);
1434 if ( vik_map_source_get_drawmode(map) == vik_viewport_get_drawmode ( vvp ) &&
1435 vik_map_source_coord_to_mapcoord ( map, vik_viewport_get_center ( vvp ),
1436 vml->xmapzoom ? vml->xmapzoom : vik_viewport_get_xmpp ( vvp ),
1437 vml->ymapzoom ? vml->ymapzoom : vik_viewport_get_ympp ( vvp ),
1439 vml->dl_tool_x = event->x, vml->dl_tool_y = event->y;
1446 if ( __map_types[vml->maptype].drawmode == vik_viewport_get_drawmode ( vvp ) )
1450 vik_viewport_screen_to_coord ( vvp, event->x, event->y, &coord );
1451 if ( __map_types[vml->maptype].coord_to_mapcoord ( &coord,
1452 vml->xmapzoom ? vml->xmapzoom : vik_viewport_get_xmpp ( vvp ),
1453 vml->ymapzoom ? vml->ymapzoom : vik_viewport_get_ympp ( vvp ),
1455 gchar *filename_buf = g_strdup_printf ( DIRSTRUCTURE,
1456 vml->cache_dir, __map_types[vml->maptype].uniq_id,
1457 mapcoord.scale, mapcoord.z, mapcoord.x, mapcoord.y );
1459 __map_types[vml->maptype].download ( &mapcoord, filename_buf );
1460 g_free ( filename_buf );
1461 vik_layer_emit_update ( VIK_LAYER(vml) );
1469 static void download_onscreen_maps ( gpointer vml_vvp[2], gint redownload )
1471 VikMapsLayer *vml = vml_vvp[0];
1472 VikViewport *vvp = vml_vvp[1];
1473 VikViewportDrawMode vp_drawmode = vik_viewport_get_drawmode ( vvp );
1475 gdouble xzoom = vml->xmapzoom ? vml->xmapzoom : vik_viewport_get_xmpp ( vvp );
1476 gdouble yzoom = vml->ymapzoom ? vml->ymapzoom : vik_viewport_get_ympp ( vvp );
1481 vik_viewport_screen_to_coord ( vvp, 0, 0, &ul );
1482 vik_viewport_screen_to_coord ( vvp, vik_viewport_get_width(vvp), vik_viewport_get_height(vvp), &br );
1484 VikMapSource *map = MAPS_LAYER_NTH_TYPE(vml->maptype);
1485 if ( vik_map_source_get_drawmode(map) == vp_drawmode &&
1486 vik_map_source_coord_to_mapcoord ( map, &ul, xzoom, yzoom, &ulm ) &&
1487 vik_map_source_coord_to_mapcoord ( map, &br, xzoom, yzoom, &brm ) )
1488 start_download_thread ( vml, vvp, &ul, &br, redownload );
1489 else if (vik_map_source_get_drawmode(map) != vp_drawmode) {
1490 const gchar *drawmode_name = vik_viewport_get_drawmode_name (vvp, vik_map_source_get_drawmode(map));
1491 gchar *err = g_strdup_printf(_("Wrong drawmode for this map.\nSelect \"%s\" from View menu and try again."), _(drawmode_name));
1492 a_dialog_error_msg ( VIK_GTK_WINDOW_FROM_LAYER(vml), err );
1496 a_dialog_error_msg ( VIK_GTK_WINDOW_FROM_LAYER(vml), _("Wrong zoom level for this map.") );
1500 static void maps_layer_download_missing_onscreen_maps ( gpointer vml_vvp[2] )
1502 download_onscreen_maps( vml_vvp, REDOWNLOAD_NONE);
1505 static void maps_layer_download_new_onscreen_maps ( gpointer vml_vvp[2] )
1507 download_onscreen_maps( vml_vvp, REDOWNLOAD_NEW);
1510 static void maps_layer_redownload_all_onscreen_maps ( gpointer vml_vvp[2] )
1512 download_onscreen_maps( vml_vvp, REDOWNLOAD_ALL);
1516 * maps_layer_how_many_maps:
1517 * Copied from maps_layer_download_section but without the actual download and this returns a value
1519 static gint maps_layer_how_many_maps ( VikMapsLayer *vml, VikViewport *vvp, VikCoord *ul, VikCoord *br, gdouble zoom, gint redownload )
1522 VikMapSource *map = MAPS_LAYER_NTH_TYPE(vml->maptype);
1524 if ( vik_map_source_is_direct_file_access ( map ) )
1527 if (!vik_map_source_coord_to_mapcoord(map, ul, zoom, zoom, &ulm)
1528 || !vik_map_source_coord_to_mapcoord(map, br, zoom, zoom, &brm)) {
1529 g_warning("%s() coord_to_mapcoord() failed", __PRETTY_FUNCTION__);
1533 MapDownloadInfo *mdi = g_malloc(sizeof(MapDownloadInfo));
1538 mdi->map_layer_alive = TRUE;
1539 mdi->mutex = g_mutex_new();
1540 mdi->refresh_display = FALSE;
1542 mdi->cache_dir = g_strdup ( vml->cache_dir );
1543 mdi->maxlen = strlen ( vml->cache_dir ) + 40;
1544 mdi->filename_buf = g_malloc ( mdi->maxlen * sizeof(gchar) );
1545 mdi->maptype = vml->maptype;
1547 mdi->mapcoord = ulm;
1548 mdi->redownload = redownload;
1550 mdi->x0 = MIN(ulm.x, brm.x);
1551 mdi->xf = MAX(ulm.x, brm.x);
1552 mdi->y0 = MIN(ulm.y, brm.y);
1553 mdi->yf = MAX(ulm.y, brm.y);
1557 if ( mdi->redownload == REDOWNLOAD_ALL ) {
1558 mdi->mapstoget = (mdi->xf - mdi->x0 + 1) * (mdi->yf - mdi->y0 + 1);
1561 /* calculate how many we need */
1562 for (i = mdi->x0; i <= mdi->xf; i++) {
1563 for (j = mdi->y0; j <= mdi->yf; j++) {
1564 g_snprintf ( mdi->filename_buf, mdi->maxlen, DIRSTRUCTURE,
1565 vml->cache_dir, vik_map_source_get_uniq_id(map), ulm.scale,
1567 if ( mdi->redownload == REDOWNLOAD_NEW ) {
1568 // Assume the worst - always a new file
1569 // Absolute value would requires server lookup - but that is too slow
1573 if ( g_file_test ( mdi->filename_buf, G_FILE_TEST_EXISTS ) == FALSE ) {
1578 if ( mdi->redownload == REDOWNLOAD_BAD ) {
1579 /* see if this one is bad or what */
1581 GdkPixbuf *pixbuf = gdk_pixbuf_new_from_file ( mdi->filename_buf, &gx );
1582 if (gx || (!pixbuf)) {
1586 // Other download cases already considered or just ignored
1594 gint rv = mdi->mapstoget;
1602 * maps_dialog_zoom_between:
1603 * This dialog is specific to the map layer, so it's here rather than in dialog.c
1605 gboolean maps_dialog_zoom_between ( GtkWindow *parent,
1610 gint *selected_zoom1,
1611 gint *selected_zoom2,
1612 gchar *download_list[],
1613 gint default_download,
1614 gint *selected_download )
1616 GtkWidget *dialog = gtk_dialog_new_with_buttons ( title,
1618 GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
1619 GTK_STOCK_OK, GTK_RESPONSE_ACCEPT,
1620 GTK_STOCK_CANCEL, GTK_RESPONSE_REJECT,
1622 gtk_dialog_set_default_response ( GTK_DIALOG(dialog), GTK_RESPONSE_ACCEPT );
1623 GtkWidget *response_w = NULL;
1624 #if GTK_CHECK_VERSION (2, 20, 0)
1625 response_w = gtk_dialog_get_widget_for_response ( GTK_DIALOG(dialog), GTK_RESPONSE_ACCEPT );
1627 GtkWidget *zoom_label1 = gtk_label_new ( _("Zoom Start:") );
1628 GtkWidget *zoom_combo1 = vik_combo_box_text_new();
1630 for (s = zoom_list; *s; s++)
1631 vik_combo_box_text_append ( zoom_combo1, *s );
1632 gtk_combo_box_set_active ( GTK_COMBO_BOX(zoom_combo1), default_zoom1 );
1634 GtkWidget *zoom_label2 = gtk_label_new ( _("Zoom End:") );
1635 GtkWidget *zoom_combo2 = vik_combo_box_text_new();
1636 for (s = zoom_list; *s; s++)
1637 vik_combo_box_text_append ( zoom_combo2, *s );
1638 gtk_combo_box_set_active ( GTK_COMBO_BOX(zoom_combo2), default_zoom2 );
1640 GtkWidget *download_label = gtk_label_new(_("Download Maps Method:"));
1641 GtkWidget *download_combo = vik_combo_box_text_new();
1642 for (s = download_list; *s; s++)
1643 vik_combo_box_text_append ( download_combo, *s );
1644 gtk_combo_box_set_active ( GTK_COMBO_BOX(download_combo), default_download );
1646 GtkTable *box = GTK_TABLE(gtk_table_new(3, 2, FALSE));
1647 gtk_table_attach_defaults (box, GTK_WIDGET(zoom_label1), 0, 1, 0, 1);
1648 gtk_table_attach_defaults (box, GTK_WIDGET(zoom_combo1), 1, 2, 0, 1);
1649 gtk_table_attach_defaults (box, GTK_WIDGET(zoom_label2), 0, 1, 1, 2);
1650 gtk_table_attach_defaults (box, GTK_WIDGET(zoom_combo2), 1, 2, 1, 2);
1651 gtk_table_attach_defaults (box, GTK_WIDGET(download_label), 0, 1, 2, 3);
1652 gtk_table_attach_defaults (box, GTK_WIDGET(download_combo), 1, 2, 2, 3);
1654 gtk_box_pack_start ( GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(dialog))), GTK_WIDGET(box), FALSE, FALSE, 5 );
1657 gtk_widget_grab_focus ( response_w );
1659 gtk_widget_show_all ( dialog );
1660 if ( gtk_dialog_run ( GTK_DIALOG(dialog) ) != GTK_RESPONSE_ACCEPT ) {
1661 gtk_widget_destroy(dialog);
1665 // Return selected options
1666 *selected_zoom1 = gtk_combo_box_get_active ( GTK_COMBO_BOX(zoom_combo1) );
1667 *selected_zoom2 = gtk_combo_box_get_active ( GTK_COMBO_BOX(zoom_combo2) );
1668 *selected_download = gtk_combo_box_get_active ( GTK_COMBO_BOX(download_combo) );
1670 gtk_widget_destroy(dialog);
1674 // My best guess of sensible limits
1675 #define REALLY_LARGE_AMOUNT_OF_TILES 5000
1676 #define CONFIRM_LARGE_AMOUNT_OF_TILES 500
1679 * Get all maps in the region for zoom levels specified by the user
1680 * Sort of similar to trw_layer_download_map_along_track_cb function
1682 static void maps_layer_download_all ( gpointer vml_vvp[2] )
1684 VikMapsLayer *vml = vml_vvp[0];
1685 VikViewport *vvp = vml_vvp[1];
1687 // I don't think we should allow users to hammer the servers too much...
1688 // Delibrately not allowing lowest zoom levels
1689 // Still can give massive numbers to download
1690 // A screen size of 1600x1200 gives around 300,000 tiles between 1..128 when none exist before !!
1691 gchar *zoom_list[] = {"1", "2", "4", "8", "16", "32", "64", "128", "256", "512", "1024", NULL };
1692 gdouble zoom_vals[] = {1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024};
1694 gint selected_zoom1, selected_zoom2, default_zoom, lower_zoom;
1695 gint selected_download_method;
1697 gdouble cur_zoom = vik_viewport_get_zoom(vvp);
1699 for (default_zoom = 0; default_zoom < sizeof(zoom_vals)/sizeof(gdouble); default_zoom++) {
1700 if (cur_zoom == zoom_vals[default_zoom])
1703 default_zoom = (default_zoom == sizeof(zoom_vals)/sizeof(gdouble)) ? sizeof(zoom_vals)/sizeof(gdouble) - 1 : default_zoom;
1705 // Default to only 2 zoom levels below the current one
1706 if (default_zoom > 1 )
1707 lower_zoom = default_zoom - 2;
1709 lower_zoom = default_zoom;
1711 // redownload method - needs to align with REDOWNLOAD* macro values
1712 gchar *download_list[] = { _("Missing"), _("Bad"), _("New"), _("Reload All"), NULL };
1714 gchar *title = g_strdup_printf ( ("%s: %s"), vik_maps_layer_get_map_label (vml), _("Download for Zoom Levels") );
1716 if ( ! maps_dialog_zoom_between ( VIK_GTK_WINDOW_FROM_LAYER(vml),
1724 REDOWNLOAD_NONE, // AKA Missing
1725 &selected_download_method ) ) {
1732 // Find out new current positions
1733 gdouble min_lat, max_lat, min_lon, max_lon;
1734 VikCoord vc_ul, vc_br;
1735 vik_viewport_get_min_max_lat_lon ( vvp, &min_lat, &max_lat, &min_lon, &max_lon );
1736 struct LatLon ll_ul = { max_lat, min_lon };
1737 struct LatLon ll_br = { min_lat, max_lon };
1738 vik_coord_load_from_latlon ( &vc_ul, vik_viewport_get_coord_mode (vvp), &ll_ul );
1739 vik_coord_load_from_latlon ( &vc_br, vik_viewport_get_coord_mode (vvp), &ll_br );
1741 // Get Maps Count - call for each zoom level (in reverse)
1742 // With REDOWNLOAD_NEW this is a possible maximum
1743 // With REDOWNLOAD_NONE this only missing ones - however still has a server lookup per tile
1746 for ( zz = selected_zoom2; zz >= selected_zoom1; zz-- ) {
1747 map_count = map_count + maps_layer_how_many_maps ( vml, vvp, &vc_ul, &vc_br, zoom_vals[zz], selected_download_method );
1750 g_debug ("vikmapslayer: download request map count %d for method %d", map_count, selected_download_method);
1752 // Absolute protection of hammering a map server
1753 if ( map_count > REALLY_LARGE_AMOUNT_OF_TILES ) {
1754 gchar *str = g_strdup_printf (_("You are not allowed to download more than %d tiles in one go (requested %d)"), REALLY_LARGE_AMOUNT_OF_TILES, map_count);
1755 a_dialog_error_msg ( VIK_GTK_WINDOW_FROM_LAYER(vml), str );
1760 // Confirm really want to do this
1761 if ( map_count > CONFIRM_LARGE_AMOUNT_OF_TILES ) {
1762 gchar *str = g_strdup_printf (_("Do you really want to download %d tiles?"), map_count);
1763 gboolean ans = a_dialog_yes_or_no ( VIK_GTK_WINDOW_FROM_LAYER(vml), str, NULL );
1769 // Get Maps - call for each zoom level (in reverse)
1770 for ( zz = selected_zoom2; zz >= selected_zoom1; zz-- ) {
1771 maps_layer_download_section ( vml, vvp, &vc_ul, &vc_br, zoom_vals[zz], selected_download_method );
1775 static void maps_layer_add_menu_items ( VikMapsLayer *vml, GtkMenu *menu, VikLayersPanel *vlp )
1777 static gpointer pass_along[2];
1779 pass_along[0] = vml;
1780 pass_along[1] = vik_layers_panel_get_viewport( VIK_LAYERS_PANEL(vlp) );
1782 item = gtk_menu_item_new();
1783 gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item );
1784 gtk_widget_show ( item );
1786 /* Now with icons */
1787 item = gtk_image_menu_item_new_with_mnemonic ( _("Download _Missing Onscreen Maps") );
1788 gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_ADD, GTK_ICON_SIZE_MENU) );
1789 g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(maps_layer_download_missing_onscreen_maps), pass_along );
1790 gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
1791 gtk_widget_show ( item );
1793 if ( vik_map_source_supports_download_only_new (MAPS_LAYER_NTH_TYPE(vml->maptype)) ) {
1794 item = gtk_image_menu_item_new_with_mnemonic ( _("Download _New Onscreen Maps") );
1795 gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_REDO, GTK_ICON_SIZE_MENU) );
1796 g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(maps_layer_download_new_onscreen_maps), pass_along );
1797 gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
1798 gtk_widget_show ( item );
1801 item = gtk_image_menu_item_new_with_mnemonic ( _("Reload _All Onscreen Maps") );
1802 gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_REFRESH, GTK_ICON_SIZE_MENU) );
1803 g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(maps_layer_redownload_all_onscreen_maps), pass_along );
1804 gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
1805 gtk_widget_show ( item );
1807 item = gtk_image_menu_item_new_with_mnemonic ( _("Download Maps in _Zoom Levels...") );
1808 gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_DND_MULTIPLE, GTK_ICON_SIZE_MENU) );
1809 g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(maps_layer_download_all), pass_along );
1810 gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
1811 gtk_widget_show ( item );
1815 * Enable downloading maps of the current screen area either 'new' or 'everything'
1817 void vik_maps_layer_download ( VikMapsLayer *vml, VikViewport *vvp, gboolean only_new )
1822 static gpointer pass_along[2];
1823 pass_along[0] = vml;
1824 pass_along[1] = vvp;
1827 // Get only new maps
1828 maps_layer_download_new_onscreen_maps ( pass_along );
1830 // Redownload everything
1831 maps_layer_redownload_all_onscreen_maps ( pass_along );