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 * Copyright (c) 2013, Rob Norris <rw_norris@hotmail.com>
7 * UTM multi-zone stuff by Kit Transue <notlostyet@didactek.com>
8 * Dynamic map type by Guilhem Bonnefille <guilhem.bonnefille@gmail.com>
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
31 #include <gdk-pixbuf/gdk-pixdata.h>
33 #include <glib/gstdio.h>
34 #include <glib/gi18n.h>
48 #include "vikmapsourcedefault.h"
52 #include "background.h"
53 #include "preferences.h"
54 #include "vikmapslayer.h"
55 #include "icons/icons.h"
64 #define VIK_SETTINGS_MAP_MAX_TILES "maps_max_tiles"
65 static gint MAX_TILES = 1000;
67 #define VIK_SETTINGS_MAP_MIN_SHRINKFACTOR "maps_min_shrinkfactor"
68 #define VIK_SETTINGS_MAP_MAX_SHRINKFACTOR "maps_max_shrinkfactor"
69 static gdouble MAX_SHRINKFACTOR = 8.0000001; /* zoom 1 viewing 8-tiles */
70 static gdouble MIN_SHRINKFACTOR = 0.0312499; /* zoom 32 viewing 1-tiles */
72 #define VIK_SETTINGS_MAP_REAL_MIN_SHRINKFACTOR "maps_real_min_shrinkfactor"
73 static gdouble REAL_MIN_SHRINKFACTOR = 0.0039062499; /* if shrinkfactor is between MAX and REAL_MAX, will only check for existence */
75 /****** MAP TYPES ******/
77 static GList *__map_types = NULL;
79 #define NUM_MAP_TYPES g_list_length(__map_types)
81 /* List of label for each map type */
82 static gchar **params_maptypes = NULL;
84 /* Corresponding IDS. (Cf. field uniq_id in VikMapsLayer struct) */
85 static guint *params_maptypes_ids = NULL;
87 /******** MAPZOOMS *********/
89 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 };
90 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 };
91 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 };
93 #define NUM_MAPZOOMS (sizeof(params_mapzooms)/sizeof(params_mapzooms[0]) - 1)
95 /**************************/
98 static void maps_layer_post_read (VikLayer *vl, VikViewport *vp, gboolean from_file);
99 static const gchar* maps_layer_tooltip ( VikMapsLayer *vml );
100 static void maps_layer_marshall( VikMapsLayer *vml, guint8 **data, gint *len );
101 static VikMapsLayer *maps_layer_unmarshall( guint8 *data, gint len, VikViewport *vvp );
102 static gboolean maps_layer_set_param ( VikMapsLayer *vml, guint16 id, VikLayerParamData data, VikViewport *vvp, gboolean is_file_operation );
103 static VikLayerParamData maps_layer_get_param ( VikMapsLayer *vml, guint16 id, gboolean is_file_operation );
104 static void maps_layer_change_param ( GtkWidget *widget, ui_change_values values );
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 static VikLayerParamData id_default ( void ) { return VIK_LPD_UINT ( 19 ); } // OSM MapQuest maps
123 static VikLayerParamData directory_default ( void )
125 VikLayerParamData data;
126 VikLayerParamData *pref = a_preferences_get(VIKING_PREFERENCES_NAMESPACE "maplayer_default_dir");
127 if (pref) data.s = g_strdup ( pref->s ); else data.s = "";
130 static VikLayerParamData file_default ( void )
132 VikLayerParamData data;
136 static VikLayerParamData alpha_default ( void ) { return VIK_LPD_UINT ( 255 ); }
137 static VikLayerParamData mapzoom_default ( void ) { return VIK_LPD_UINT ( 0 ); }
139 static gchar *cache_types[] = { "Viking", N_("OSM"), NULL };
140 static VikMapsCacheLayout cache_layout_default_value = VIK_MAPS_CACHE_LAYOUT_VIKING;
141 static VikLayerParamData cache_layout_default ( void ) { return VIK_LPD_UINT ( cache_layout_default_value ); }
143 VikLayerParam maps_layer_params[] = {
144 // NB mode => id - But can't break file format just to rename something better
145 { VIK_LAYER_MAPS, "mode", VIK_LAYER_PARAM_UINT, VIK_LAYER_GROUP_NONE, N_("Map Type:"), VIK_LAYER_WIDGET_COMBOBOX, NULL, NULL, NULL, id_default, NULL, NULL },
146 { VIK_LAYER_MAPS, "directory", VIK_LAYER_PARAM_STRING, VIK_LAYER_GROUP_NONE, N_("Maps Directory:"), VIK_LAYER_WIDGET_FOLDERENTRY, NULL, NULL, NULL, directory_default, NULL, NULL },
147 { VIK_LAYER_MAPS, "cache_type", VIK_LAYER_PARAM_UINT, VIK_LAYER_GROUP_NONE, N_("Cache Layout:"), VIK_LAYER_WIDGET_COMBOBOX, cache_types, NULL,
148 N_("This determines the tile storage layout on disk"), cache_layout_default, NULL, NULL },
149 { VIK_LAYER_MAPS, "mapfile", VIK_LAYER_PARAM_STRING, VIK_LAYER_GROUP_NONE, N_("Map File:"), VIK_LAYER_WIDGET_FILEENTRY, GINT_TO_POINTER(VF_FILTER_MBTILES), NULL,
150 N_("An MBTiles file. Only applies when the map type method is 'MBTiles'"), file_default, NULL, NULL },
151 { VIK_LAYER_MAPS, "alpha", VIK_LAYER_PARAM_UINT, VIK_LAYER_GROUP_NONE, N_("Alpha:"), VIK_LAYER_WIDGET_HSCALE, params_scales, NULL,
152 N_("Control the Alpha value for transparency effects"), alpha_default, NULL, NULL },
153 { 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, NULL, NULL },
154 { VIK_LAYER_MAPS, "adlonlymissing", VIK_LAYER_PARAM_BOOLEAN, VIK_LAYER_GROUP_NONE, N_("Autodownload Only Gets Missing Maps:"), VIK_LAYER_WIDGET_CHECKBUTTON, NULL, NULL,
155 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, NULL, NULL },
156 { VIK_LAYER_MAPS, "mapzoom", VIK_LAYER_PARAM_UINT, VIK_LAYER_GROUP_NONE, N_("Zoom Level:"), VIK_LAYER_WIDGET_COMBOBOX, params_mapzooms, NULL,
157 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."),
158 mapzoom_default, NULL, NULL },
173 void maps_layer_set_autodownload_default ( gboolean autodownload )
175 // Set appropriate function
177 maps_layer_params[PARAM_AUTODOWNLOAD].default_value = vik_lpd_true_default;
179 maps_layer_params[PARAM_AUTODOWNLOAD].default_value = vik_lpd_false_default;
182 void maps_layer_set_cache_default ( VikMapsCacheLayout layout )
184 // Override default value returned by the default param function
185 cache_layout_default_value = layout;
188 static VikToolInterface maps_tools[] = {
189 { { "MapsDownload", "vik-icon-Maps Download", N_("_Maps Download"), NULL, N_("Maps Download"), 0 },
190 (VikToolConstructorFunc) maps_layer_download_create,
194 (VikToolMouseFunc) maps_layer_download_click,
196 (VikToolMouseFunc) maps_layer_download_release,
199 GDK_CURSOR_IS_PIXMAP, &cursor_mapdl_pixbuf, NULL },
202 VikLayerInterface vik_maps_layer_interface = {
206 &vikmapslayer_pixbuf,
209 sizeof(maps_tools) / sizeof(maps_tools[0]),
218 (VikLayerFuncCreate) maps_layer_new,
219 (VikLayerFuncRealize) NULL,
220 (VikLayerFuncPostRead) maps_layer_post_read,
221 (VikLayerFuncFree) maps_layer_free,
223 (VikLayerFuncProperties) NULL,
224 (VikLayerFuncDraw) maps_layer_draw,
225 (VikLayerFuncChangeCoordMode) NULL,
227 (VikLayerFuncSetMenuItemsSelection) NULL,
228 (VikLayerFuncGetMenuItemsSelection) NULL,
230 (VikLayerFuncAddMenuItems) maps_layer_add_menu_items,
231 (VikLayerFuncSublayerAddMenuItems) NULL,
233 (VikLayerFuncSublayerRenameRequest) NULL,
234 (VikLayerFuncSublayerToggleVisible) NULL,
235 (VikLayerFuncSublayerTooltip) NULL,
236 (VikLayerFuncLayerTooltip) maps_layer_tooltip,
237 (VikLayerFuncLayerSelected) NULL,
239 (VikLayerFuncMarshall) maps_layer_marshall,
240 (VikLayerFuncUnmarshall) maps_layer_unmarshall,
242 (VikLayerFuncSetParam) maps_layer_set_param,
243 (VikLayerFuncGetParam) maps_layer_get_param,
244 (VikLayerFuncChangeParam) maps_layer_change_param,
246 (VikLayerFuncReadFileData) NULL,
247 (VikLayerFuncWriteFileData) NULL,
249 (VikLayerFuncDeleteItem) NULL,
250 (VikLayerFuncCutItem) NULL,
251 (VikLayerFuncCopyItem) NULL,
252 (VikLayerFuncPasteItem) NULL,
253 (VikLayerFuncFreeCopiedItem) NULL,
254 (VikLayerFuncDragDropRequest) NULL,
256 (VikLayerFuncSelectClick) NULL,
257 (VikLayerFuncSelectMove) NULL,
258 (VikLayerFuncSelectRelease) NULL,
259 (VikLayerFuncSelectedViewportMenu) NULL,
262 struct _VikMapsLayer {
266 VikMapsCacheLayout cache_layout;
269 gdouble xmapzoom, ymapzoom;
271 gboolean autodownload;
272 gboolean adl_only_missing;
273 VikCoord *last_center;
277 gint dl_tool_x, dl_tool_y;
279 GtkMenu *dl_right_click_menu;
280 VikCoord redownload_ul, redownload_br; /* right click menu only */
281 VikViewport *redownload_vvp;
283 #ifdef HAVE_SQLITE3_H
288 enum { REDOWNLOAD_NONE = 0, /* download only missing maps */
289 REDOWNLOAD_BAD, /* download missing and bad maps */
290 REDOWNLOAD_NEW, /* download missing maps that are newer on server only */
291 REDOWNLOAD_ALL, /* download all maps */
292 DOWNLOAD_OR_REFRESH }; /* download missing maps and refresh cache */
294 static VikLayerParam prefs[] = {
295 { 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"), NULL, NULL, NULL },
298 void maps_layer_init ()
300 VikLayerParamData tmp;
301 tmp.s = maps_layer_default_dir();
302 a_preferences_register(prefs, tmp, VIKING_PREFERENCES_GROUP_KEY);
304 gint max_tiles = MAX_TILES;
305 if ( a_settings_get_integer ( VIK_SETTINGS_MAP_MAX_TILES, &max_tiles ) )
306 MAX_TILES = max_tiles;
309 if ( a_settings_get_double ( VIK_SETTINGS_MAP_MIN_SHRINKFACTOR, &gdtmp ) )
310 MIN_SHRINKFACTOR = gdtmp;
312 if ( a_settings_get_double ( VIK_SETTINGS_MAP_MAX_SHRINKFACTOR, &gdtmp ) )
313 MAX_SHRINKFACTOR = gdtmp;
315 if ( a_settings_get_double ( VIK_SETTINGS_MAP_REAL_MIN_SHRINKFACTOR, &gdtmp ) )
316 REAL_MIN_SHRINKFACTOR = gdtmp;
319 /****************************************/
320 /******** MAPS LAYER TYPES **************/
321 /****************************************/
323 void _add_map_source ( guint16 id, const char *label, VikMapSource *map )
327 len = g_strv_length (params_maptypes);
329 params_maptypes = g_realloc (params_maptypes, (len+2)*sizeof(gchar*));
330 params_maptypes[len] = g_strdup (label);
331 params_maptypes[len+1] = NULL;
334 params_maptypes_ids = g_realloc (params_maptypes_ids, (len+2)*sizeof(guint));
335 params_maptypes_ids[len] = id;
336 params_maptypes_ids[len+1] = 0;
338 /* We have to clone */
339 VikMapSource *clone = VIK_MAP_SOURCE(g_object_ref(map));
340 /* Register the clone in the list */
341 __map_types = g_list_append(__map_types, clone);
344 We have to ensure the mode LayerParam references the up-to-date
348 memcpy(&maps_layer_params[0].widget_data, ¶ms_maptypes, sizeof(gpointer));
349 memcpy(&maps_layer_params[0].extra_widget_data, ¶ms_maptypes_ids, sizeof(gpointer));
351 maps_layer_params[0].widget_data = params_maptypes;
352 maps_layer_params[0].extra_widget_data = params_maptypes_ids;
355 void _update_map_source ( const char *label, VikMapSource *map, int index )
357 GList *item = g_list_nth (__map_types, index);
358 g_object_unref (item->data);
359 item->data = g_object_ref (map);
360 /* Change previous data */
361 g_free (params_maptypes[index]);
362 params_maptypes[index] = g_strdup (label);
366 * maps_layer_register_map_source:
367 * @map: the new VikMapSource
369 * Register a new VikMapSource.
370 * Override existing one (equality of id).
372 void maps_layer_register_map_source ( VikMapSource *map )
374 g_assert(map != NULL);
376 guint16 id = vik_map_source_get_uniq_id(map);
377 const char *label = vik_map_source_get_label(map);
378 g_assert(label != NULL);
380 int previous = map_uniq_id_to_index (id);
381 if (previous != NUM_MAP_TYPES)
383 _update_map_source (label, map, previous);
387 _add_map_source (id, label, map);
391 #define MAPS_LAYER_NTH_LABEL(n) (params_maptypes[n])
392 #define MAPS_LAYER_NTH_ID(n) (params_maptypes_ids[n])
393 #define MAPS_LAYER_NTH_TYPE(n) (VIK_MAP_SOURCE(g_list_nth_data(__map_types, (n))))
395 gint vik_maps_layer_get_map_type(VikMapsLayer *vml)
397 return(vml->maptype);
400 gchar *vik_maps_layer_get_map_label(VikMapsLayer *vml)
402 return(g_strdup(MAPS_LAYER_NTH_LABEL(vml->maptype)));
405 /****************************************/
406 /******** CACHE DIR STUFF ***************/
407 /****************************************/
409 #define DIRECTDIRACCESS "%s%d" G_DIR_SEPARATOR_S "%d" G_DIR_SEPARATOR_S "%d%s"
410 #define DIRECTDIRACCESS_WITH_NAME "%s%s" G_DIR_SEPARATOR_S "%d" G_DIR_SEPARATOR_S "%d" G_DIR_SEPARATOR_S "%d%s"
411 #define DIRSTRUCTURE "%st%ds%dz%d" G_DIR_SEPARATOR_S "%d" G_DIR_SEPARATOR_S "%d"
412 #define MAPS_CACHE_DIR maps_layer_default_dir()
416 #define GLOBAL_MAPS_DIR "C:\\VIKING-MAPS\\"
417 #define LOCAL_MAPS_DIR "VIKING-MAPS"
418 #elif defined __APPLE__
420 #define GLOBAL_MAPS_DIR "/Library/cache/Viking/maps/"
421 #define LOCAL_MAPS_DIR "/Library/Application Support/Viking/viking-maps"
424 #define GLOBAL_MAPS_DIR "/var/cache/maps/"
425 #define LOCAL_MAPS_DIR ".viking-maps"
428 gchar *maps_layer_default_dir ()
430 static gchar *defaultdir = NULL;
433 /* Thanks to Mike Davison for the $VIKING_MAPS usage */
434 const gchar *mapdir = g_getenv("VIKING_MAPS");
436 defaultdir = g_strdup ( mapdir );
437 } else if ( g_access ( GLOBAL_MAPS_DIR, W_OK ) == 0 ) {
438 defaultdir = g_strdup ( GLOBAL_MAPS_DIR );
440 const gchar *home = g_get_home_dir();
441 if (!home || g_access(home, W_OK))
442 home = g_get_home_dir ();
444 defaultdir = g_build_filename ( home, LOCAL_MAPS_DIR, NULL );
446 defaultdir = g_strdup ( LOCAL_MAPS_DIR );
448 if (defaultdir && (defaultdir[strlen(defaultdir)-1] != G_DIR_SEPARATOR))
450 /* Add the separator at the end */
451 gchar *tmp = defaultdir;
452 defaultdir = g_strconcat(tmp, G_DIR_SEPARATOR_S, NULL);
455 g_debug("%s: defaultdir=%s", __FUNCTION__, defaultdir);
460 static void maps_layer_mkdir_if_default_dir ( VikMapsLayer *vml )
462 if ( vml->cache_dir && strcmp ( vml->cache_dir, MAPS_CACHE_DIR ) == 0 && g_file_test ( vml->cache_dir, G_FILE_TEST_EXISTS ) == FALSE )
464 g_mkdir ( vml->cache_dir, 0777 );
468 static void maps_layer_set_cache_dir ( VikMapsLayer *vml, const gchar *dir )
470 g_assert ( vml != NULL);
471 g_free ( vml->cache_dir );
472 vml->cache_dir = NULL;
473 const gchar *mydir = dir;
475 if ( dir == NULL || dir[0] == '\0' )
477 if ( a_preferences_get(VIKING_PREFERENCES_NAMESPACE "maplayer_default_dir") )
478 mydir = a_preferences_get(VIKING_PREFERENCES_NAMESPACE "maplayer_default_dir")->s;
481 gchar *canonical_dir = vu_get_canonical_filename ( VIK_LAYER(vml), mydir );
483 // Ensure cache_dir always ends with a separator
484 guint len = strlen(canonical_dir);
485 if ( canonical_dir[len-1] != G_DIR_SEPARATOR )
487 vml->cache_dir = g_strconcat ( canonical_dir, G_DIR_SEPARATOR_S, NULL );
488 g_free ( canonical_dir );
491 vml->cache_dir = canonical_dir;
494 maps_layer_mkdir_if_default_dir ( vml );
497 static void maps_layer_set_file ( VikMapsLayer *vml, const gchar *name )
500 g_free (vml->filename);
501 vml->filename = g_strdup (name);
504 /****************************************/
505 /******** GOBJECT STUFF *****************/
506 /****************************************/
508 GType vik_maps_layer_get_type ()
510 static GType vml_type = 0;
514 static const GTypeInfo vml_info =
516 sizeof (VikMapsLayerClass),
517 NULL, /* base_init */
518 NULL, /* base_finalize */
519 NULL, /* class init */
520 NULL, /* class_finalize */
521 NULL, /* class_data */
522 sizeof (VikMapsLayer),
524 NULL /* instance init */
526 vml_type = g_type_register_static ( VIK_LAYER_TYPE, "VikMapsLayer", &vml_info, 0 );
532 /****************************************/
533 /************** PARAMETERS **************/
534 /****************************************/
536 static guint map_index_to_uniq_id (guint16 index)
538 g_assert ( index < NUM_MAP_TYPES );
539 return vik_map_source_get_uniq_id(MAPS_LAYER_NTH_TYPE(index));
542 static guint map_uniq_id_to_index ( guint uniq_id )
545 for ( i = 0; i < NUM_MAP_TYPES; i++ )
546 if ( vik_map_source_get_uniq_id(MAPS_LAYER_NTH_TYPE(i)) == uniq_id )
548 return NUM_MAP_TYPES; /* no such thing */
551 #define VIK_SETTINGS_MAP_LICENSE_SHOWN "map_license_shown"
554 * Convenience function to display the license
556 static void maps_show_license ( GtkWindow *parent, VikMapSource *map )
558 a_dialog_license ( parent,
559 vik_map_source_get_label (map),
560 vik_map_source_get_license (map),
561 vik_map_source_get_license_url (map) );
564 static gboolean maps_layer_set_param ( VikMapsLayer *vml, guint16 id, VikLayerParamData data, VikViewport *vvp, gboolean is_file_operation )
568 case PARAM_CACHE_DIR: maps_layer_set_cache_dir ( vml, data.s ); break;
569 case PARAM_CACHE_LAYOUT: if ( data.u < VIK_MAPS_CACHE_LAYOUT_NUM ) vml->cache_layout = data.u; break;
570 case PARAM_FILE: maps_layer_set_file ( vml, data.s ); break;
571 case PARAM_MAPTYPE: {
572 gint maptype = map_uniq_id_to_index(data.u);
573 if ( maptype == NUM_MAP_TYPES )
574 g_warning(_("Unknown map type"));
576 vml->maptype = maptype;
578 // When loading from a file don't need the license reminder - ensure it's saved into the 'seen' list
579 if ( is_file_operation ) {
580 a_settings_set_integer_list_containing ( VIK_SETTINGS_MAP_LICENSE_SHOWN, data.u );
583 VikMapSource *map = MAPS_LAYER_NTH_TYPE(vml->maptype);
584 if (vik_map_source_get_license (map) != NULL) {
585 // Check if licence for this map type has been shown before
586 if ( ! a_settings_get_integer_list_contains ( VIK_SETTINGS_MAP_LICENSE_SHOWN, data.u ) ) {
588 maps_show_license ( VIK_GTK_WINDOW_FROM_WIDGET(vvp), map );
589 a_settings_set_integer_list_containing ( VIK_SETTINGS_MAP_LICENSE_SHOWN, data.u );
596 case PARAM_ALPHA: if ( data.u <= 255 ) vml->alpha = data.u; break;
597 case PARAM_AUTODOWNLOAD: vml->autodownload = data.b; break;
598 case PARAM_ONLYMISSING: vml->adl_only_missing = data.b; break;
599 case PARAM_MAPZOOM: if ( data.u < NUM_MAPZOOMS ) {
600 vml->mapzoom_id = data.u;
601 vml->xmapzoom = __mapzooms_x [data.u];
602 vml->ymapzoom = __mapzooms_y [data.u];
603 }else g_warning (_("Unknown Map Zoom")); break;
609 static VikLayerParamData maps_layer_get_param ( VikMapsLayer *vml, guint16 id, gboolean is_file_operation )
611 VikLayerParamData rv;
614 case PARAM_CACHE_DIR:
616 gboolean set = FALSE;
617 /* Only save a blank when the map cache location equals the default
618 On reading in, when it is blank then the default is reconstructed
619 Since the default changes dependent on the user and OS, it means the resultant file is more portable */
620 if ( is_file_operation && vml->cache_dir && strcmp ( vml->cache_dir, MAPS_CACHE_DIR ) == 0 ) {
624 else if ( is_file_operation ) {
625 if ( a_vik_get_file_ref_format() == VIK_FILE_REF_FORMAT_RELATIVE ) {
626 gchar *cwd = g_get_current_dir();
628 rv.s = file_GetRelativeFilename ( cwd, vml->cache_dir );
629 if ( !rv.s ) rv.s = "";
635 rv.s = vml->cache_dir ? vml->cache_dir : "";
638 case PARAM_CACHE_LAYOUT: rv.u = vml->cache_layout; break;
639 case PARAM_FILE: rv.s = vml->filename; break;
640 case PARAM_MAPTYPE: rv.u = map_index_to_uniq_id ( vml->maptype ); break;
641 case PARAM_ALPHA: rv.u = vml->alpha; break;
642 case PARAM_AUTODOWNLOAD: rv.u = vml->autodownload; break;
643 case PARAM_ONLYMISSING: rv.u = vml->adl_only_missing; break;
644 case PARAM_MAPZOOM: rv.u = vml->mapzoom_id; break;
650 static void maps_layer_change_param ( GtkWidget *widget, ui_change_values values )
652 switch ( GPOINTER_TO_INT(values[UI_CHG_PARAM_ID]) ) {
653 // Alter sensitivity of download option widgets according to the maptype setting.
654 case PARAM_MAPTYPE: {
656 VikLayerParamData vlpd = a_uibuilder_widget_get_value ( widget, values[UI_CHG_PARAM] );
657 // Is it *not* the OSM On Disk Tile Layout or the MBTiles type or the OSM Metatiles type
658 gboolean sensitive = ( 21 != vlpd.u && 23 != vlpd.u && 24 != vlpd.u );
659 GtkWidget **ww1 = values[UI_CHG_WIDGETS];
660 GtkWidget **ww2 = values[UI_CHG_LABELS];
661 GtkWidget *w1 = ww1[PARAM_ONLYMISSING];
662 GtkWidget *w2 = ww2[PARAM_ONLYMISSING];
663 GtkWidget *w3 = ww1[PARAM_AUTODOWNLOAD];
664 GtkWidget *w4 = ww2[PARAM_AUTODOWNLOAD];
665 // Depends on autodownload value
666 gboolean missing_sense = sensitive && VIK_MAPS_LAYER(values[UI_CHG_LAYER])->autodownload;
667 if ( w1 ) gtk_widget_set_sensitive ( w1, missing_sense );
668 if ( w2 ) gtk_widget_set_sensitive ( w2, missing_sense );
669 if ( w3 ) gtk_widget_set_sensitive ( w3, sensitive );
670 if ( w4 ) gtk_widget_set_sensitive ( w4, sensitive );
672 // Cache type not applicable either
673 GtkWidget *w9 = ww1[PARAM_CACHE_LAYOUT];
674 GtkWidget *w10 = ww2[PARAM_CACHE_LAYOUT];
675 if ( w9 ) gtk_widget_set_sensitive ( w9, sensitive );
676 if ( w10 ) gtk_widget_set_sensitive ( w10, sensitive );
678 // File only applicable for MBTiles type
679 // Directory for all other types
680 sensitive = ( 23 == vlpd.u);
681 GtkWidget *w5 = ww1[PARAM_FILE];
682 GtkWidget *w6 = ww2[PARAM_FILE];
683 GtkWidget *w7 = ww1[PARAM_CACHE_DIR];
684 GtkWidget *w8 = ww2[PARAM_CACHE_DIR];
685 if ( w5 ) gtk_widget_set_sensitive ( w5, sensitive );
686 if ( w6 ) gtk_widget_set_sensitive ( w6, sensitive );
687 if ( w7 ) gtk_widget_set_sensitive ( w7, !sensitive );
688 if ( w8 ) gtk_widget_set_sensitive ( w8, !sensitive );
693 // Alter sensitivity of 'download only missing' widgets according to the autodownload setting.
694 case PARAM_AUTODOWNLOAD: {
696 VikLayerParamData vlpd = a_uibuilder_widget_get_value ( widget, values[UI_CHG_PARAM] );
697 GtkWidget **ww1 = values[UI_CHG_WIDGETS];
698 GtkWidget **ww2 = values[UI_CHG_LABELS];
699 GtkWidget *w1 = ww1[PARAM_ONLYMISSING];
700 GtkWidget *w2 = ww2[PARAM_ONLYMISSING];
701 if ( w1 ) gtk_widget_set_sensitive ( w1, vlpd.b );
702 if ( w2 ) gtk_widget_set_sensitive ( w2, vlpd.b );
709 /****************************************/
710 /****** CREATING, COPYING, FREEING ******/
711 /****************************************/
713 static VikMapsLayer *maps_layer_new ( VikViewport *vvp )
715 VikMapsLayer *vml = VIK_MAPS_LAYER ( g_object_new ( VIK_MAPS_LAYER_TYPE, NULL ) );
716 vik_layer_set_type ( VIK_LAYER(vml), VIK_LAYER_MAPS );
718 vik_layer_set_defaults ( VIK_LAYER(vml), vvp );
720 vml->dl_tool_x = vml->dl_tool_y = -1;
721 vml->last_center = NULL;
722 vml->last_xmpp = 0.0;
723 vml->last_ympp = 0.0;
725 vml->dl_right_click_menu = NULL;
726 vml->filename = NULL;
730 static void maps_layer_free ( VikMapsLayer *vml )
732 g_free ( vml->cache_dir );
733 vml->cache_dir = NULL;
734 if ( vml->dl_right_click_menu )
735 g_object_ref_sink ( G_OBJECT(vml->dl_right_click_menu) );
736 g_free(vml->last_center);
737 vml->last_center = NULL;
738 g_free ( vml->filename );
739 vml->filename = NULL;
741 #ifdef HAVE_SQLITE3_H
742 VikMapSource *map = MAPS_LAYER_NTH_TYPE(vml->maptype);
743 if ( vik_map_source_is_mbtiles ( map ) ) {
744 if ( vml->mbtiles ) {
745 int ans = sqlite3_close ( vml->mbtiles );
746 if ( ans != SQLITE_OK ) {
747 // Only to console for information purposes only
748 g_warning ( "SQL Close problem: %d", ans );
755 static void maps_layer_post_read (VikLayer *vl, VikViewport *vp, gboolean from_file)
757 VikMapsLayer *vml = VIK_MAPS_LAYER(vl);
758 VikMapSource *map = MAPS_LAYER_NTH_TYPE(vml->maptype);
760 if (from_file != TRUE)
762 /* If this method is not called in file reading context
763 * it is called in GUI context.
764 * So, we can check if we have to inform the user about inconsistency */
765 VikViewportDrawMode vp_drawmode;
766 vp_drawmode = vik_viewport_get_drawmode ( vp );
768 if (vik_map_source_get_drawmode(map) != vp_drawmode) {
769 const gchar *drawmode_name = vik_viewport_get_drawmode_name (vp, vik_map_source_get_drawmode(map));
770 gchar *msg = g_strdup_printf(_("New map cannot be displayed in the current drawmode.\nSelect \"%s\" from View menu to view it."), drawmode_name);
771 a_dialog_warning_msg ( VIK_GTK_WINDOW_FROM_WIDGET(vp), msg );
776 // Performed in post read as we now know the map type
777 #ifdef HAVE_SQLITE3_H
779 if ( vik_map_source_is_mbtiles ( map ) ) {
780 int ans = sqlite3_open_v2 ( vml->filename,
782 SQLITE_OPEN_READONLY,
784 if ( ans != SQLITE_OK ) {
785 // That didn't work, so here's why:
786 g_warning ( "%s: %s", __FUNCTION__, sqlite3_errmsg ( vml->mbtiles ) );
788 a_dialog_error_msg_extra ( VIK_GTK_WINDOW_FROM_WIDGET(vp),
789 _("Failed to open MBTiles file: %s"),
796 // If the on Disk OSM Tile Layout type
797 if ( vml->maptype == 21 )
798 // Copy the directory into filename
799 // thus the mapcache look up will be unique when using more than one of these map types
800 vml->filename = g_strdup (vml->cache_dir);
803 static const gchar* maps_layer_tooltip ( VikMapsLayer *vml )
805 return vik_maps_layer_get_map_label ( vml );
808 static void maps_layer_marshall( VikMapsLayer *vml, guint8 **data, gint *len )
810 vik_layer_marshall_params ( VIK_LAYER(vml), data, len );
813 static VikMapsLayer *maps_layer_unmarshall( guint8 *data, gint len, VikViewport *vvp )
815 VikMapsLayer *rv = maps_layer_new ( vvp );
816 vik_layer_unmarshall_params ( VIK_LAYER(rv), data, len, vvp );
820 /*********************/
821 /****** DRAWING ******/
822 /*********************/
824 static GdkPixbuf *pixbuf_shrink ( GdkPixbuf *pixbuf, gdouble xshrinkfactor, gdouble yshrinkfactor )
827 guint16 width = gdk_pixbuf_get_width(pixbuf), height = gdk_pixbuf_get_height(pixbuf);
828 tmp = gdk_pixbuf_scale_simple(pixbuf, ceil(width * xshrinkfactor), ceil(height * yshrinkfactor), GDK_INTERP_BILINEAR);
829 g_object_unref ( G_OBJECT(pixbuf) );
833 #ifdef HAVE_SQLITE3_H
835 static int sql_select_tile_dump_cb (void *data, int cols, char **fields, char **col_names )
837 g_warning ( "Found %d columns", cols );
839 for ( i = 0; i < cols; i++ ) {
840 g_warning ( "SQL processing %s = %s", col_names[i], fields[i] );
849 static GdkPixbuf *get_pixbuf_sql_exec ( sqlite3 *sql, gint xx, gint yy, gint zoom )
851 GdkPixbuf *pixbuf = NULL;
853 // MBTiles stored internally with the flipping y thingy (i.e. TMS scheme).
854 gint flip_y = (gint) pow(2, zoom)-1 - yy;
855 gchar *statement = g_strdup_printf ( "SELECT tile_data FROM tiles WHERE zoom_level=%d AND tile_column=%d AND tile_row=%d;", zoom, xx, flip_y );
857 gboolean finished = FALSE;
859 sqlite3_stmt *sql_stmt = NULL;
860 int ans = sqlite3_prepare_v2 ( sql, statement, -1, &sql_stmt, NULL );
861 if ( ans != SQLITE_OK ) {
862 g_warning ( "%s: %s - %d", __FUNCTION__, "prepare failure", ans );
866 while ( !finished ) {
867 ans = sqlite3_step ( sql_stmt );
870 // Get tile_data blob
871 int count = sqlite3_column_count(sql_stmt);
873 g_warning ( "%s: %s - %d", __FUNCTION__, "count not one", count );
877 const void *data = sqlite3_column_blob ( sql_stmt, 0 );
878 int bytes = sqlite3_column_bytes ( sql_stmt, 0 );
880 g_warning ( "%s: %s (%d)", __FUNCTION__, "not enough bytes", bytes );
884 // Convert these blob bytes into a pixbuf via these streaming operations
885 GInputStream *stream = g_memory_input_stream_new_from_data ( data, bytes, NULL );
886 GError *error = NULL;
887 pixbuf = gdk_pixbuf_new_from_stream ( stream, NULL, &error );
888 if (error || (!pixbuf)) {
889 g_warning ( "%s: %s", __FUNCTION__, error->message );
890 g_error_free ( error );
892 g_input_stream_close ( stream, NULL, NULL );
898 // e.g. SQLITE_DONE | SQLITE_ERROR | SQLITE_MISUSE | etc...
900 // and give up on any errors
901 if ( ans != SQLITE_DONE )
902 g_warning ( "%s: %s - %d", __FUNCTION__, "step issue", ans );
907 ans = sqlite3_finalize ( sql_stmt );
909 g_free ( statement );
915 static GdkPixbuf *get_mbtiles_pixbuf ( VikMapsLayer *vml, gint xx, gint yy, gint zoom )
917 GdkPixbuf *pixbuf = NULL;
919 #ifdef HAVE_SQLITE3_H
920 if ( vml->mbtiles ) {
922 gchar *statement = g_strdup_printf ( "SELECT name FROM sqlite_master WHERE type='table';" );
924 int ans = sqlite3_exec ( vml->mbtiles, statement, sql_select_tile_dump_cb, pixbuf, &errMsg );
925 if ( ans != SQLITE_OK ) {
926 // Only to console for information purposes only
927 g_warning ( "SQL problem: %d for %s - error: %s", ans, statement, errMsg );
928 sqlite3_free( errMsg );
930 g_free ( statement );
933 // Reading BLOBS is a bit more involved and so can't use the simpler sqlite3_exec ()
934 // Hence this specific function
935 pixbuf = get_pixbuf_sql_exec ( vml->mbtiles, xx, yy, zoom );
942 static GdkPixbuf *get_pixbuf_from_metatile ( VikMapsLayer *vml, gint xx, gint yy, gint zz )
944 const int tile_max = METATILE_MAX_SIZE;
945 char err_msg[PATH_MAX];
950 buf = malloc(tile_max);
956 len = metatile_read(vml->cache_dir, xx, yy, zz, buf, tile_max, &compressed, err_msg);
960 // Not handled yet - I don't think this is used often - so implement later if necessary
961 g_warning ( "Compressed metatiles not implemented:%s\n", __FUNCTION__);
965 // Convert these buf bytes into a pixbuf via these streaming operations
966 GdkPixbuf *pixbuf = NULL;
968 GInputStream *stream = g_memory_input_stream_new_from_data ( buf, len, NULL );
969 GError *error = NULL;
970 pixbuf = gdk_pixbuf_new_from_stream ( stream, NULL, &error );
971 if (error || (!pixbuf)) {
972 g_warning ( "%s: %s", __FUNCTION__, error->message );
973 g_error_free ( error );
975 g_input_stream_close ( stream, NULL, NULL );
981 g_warning ( "FAILED:%s %s", __FUNCTION__, err_msg);
987 static GdkPixbuf *pixbuf_apply_settings ( GdkPixbuf *pixbuf, VikMapsLayer *vml, MapCoord *mapcoord, gdouble xshrinkfactor, gdouble yshrinkfactor )
989 // Apply alpha setting
990 if ( pixbuf && vml->alpha < 255 )
991 pixbuf = ui_pixbuf_set_alpha ( pixbuf, vml->alpha );
993 if ( pixbuf && ( xshrinkfactor != 1.0 || yshrinkfactor != 1.0 ) )
994 pixbuf = pixbuf_shrink ( pixbuf, xshrinkfactor, yshrinkfactor );
997 a_mapcache_add ( pixbuf, mapcoord->x, mapcoord->y,
998 mapcoord->z, vik_map_source_get_uniq_id(MAPS_LAYER_NTH_TYPE(vml->maptype)),
999 mapcoord->scale, vml->alpha, xshrinkfactor, yshrinkfactor, vml->filename );
1004 static void get_filename ( const gchar *cache_dir,
1005 VikMapsCacheLayout cl,
1012 gchar *filename_buf,
1014 const gchar* file_extension )
1017 case VIK_MAPS_CACHE_LAYOUT_OSM:
1019 if ( g_strcmp0 ( cache_dir, MAPS_CACHE_DIR ) )
1020 // Cache dir not the default - assume it's been directed somewhere specific
1021 g_snprintf ( filename_buf, buf_len, DIRECTDIRACCESS, cache_dir, (17 - scale), x, y, file_extension );
1023 // Using default cache - so use the map name in the directory path
1024 g_snprintf ( filename_buf, buf_len, DIRECTDIRACCESS_WITH_NAME, cache_dir, name, (17 - scale), x, y, file_extension );
1027 g_snprintf ( filename_buf, buf_len, DIRECTDIRACCESS, cache_dir, (17 - scale), x, y, file_extension );
1030 g_snprintf ( filename_buf, buf_len, DIRSTRUCTURE, cache_dir, id, scale, z, x, y );
1035 static GdkPixbuf *get_pixbuf( VikMapsLayer *vml, guint16 id, const gchar* mapname, MapCoord *mapcoord, gchar *filename_buf, gint buf_len, gdouble xshrinkfactor, gdouble yshrinkfactor )
1040 pixbuf = a_mapcache_get ( mapcoord->x, mapcoord->y, mapcoord->z,
1041 id, mapcoord->scale, vml->alpha, xshrinkfactor, yshrinkfactor, vml->filename );
1044 VikMapSource *map = MAPS_LAYER_NTH_TYPE(vml->maptype);
1045 if ( vik_map_source_is_direct_file_access(map) ) {
1046 // ATM MBTiles must be 'a direct access type'
1047 if ( vik_map_source_is_mbtiles(map) ) {
1048 pixbuf = get_mbtiles_pixbuf ( vml, mapcoord->x, mapcoord->y, (17 - mapcoord->scale) );
1049 pixbuf = pixbuf_apply_settings ( pixbuf, vml, mapcoord, xshrinkfactor, yshrinkfactor );
1050 // return now to avoid file tests that aren't appropriate for this map type
1053 else if ( vik_map_source_is_osm_meta_tiles(map) ) {
1054 pixbuf = get_pixbuf_from_metatile ( vml, mapcoord->x, mapcoord->y, (17 - mapcoord->scale) );
1055 pixbuf = pixbuf_apply_settings ( pixbuf, vml, mapcoord, xshrinkfactor, yshrinkfactor );
1059 get_filename ( vml->cache_dir, VIK_MAPS_CACHE_LAYOUT_OSM, id, NULL,
1060 mapcoord->scale, mapcoord->z, mapcoord->x, mapcoord->y, filename_buf, buf_len,
1061 vik_map_source_get_file_extension(map) );
1064 get_filename ( vml->cache_dir, vml->cache_layout, id, mapname,
1065 mapcoord->scale, mapcoord->z, mapcoord->x, mapcoord->y, filename_buf, buf_len,
1066 vik_map_source_get_file_extension(map) );
1068 if ( g_file_test ( filename_buf, G_FILE_TEST_EXISTS ) == TRUE)
1071 pixbuf = gdk_pixbuf_new_from_file ( filename_buf, &gx );
1073 /* free the pixbuf on error */
1076 if ( gx->domain != GDK_PIXBUF_ERROR || gx->code != GDK_PIXBUF_ERROR_CORRUPT_IMAGE ) {
1078 if ( IS_VIK_WINDOW ((VikWindow*)VIK_GTK_WINDOW_FROM_LAYER(vml)) ) {
1079 gchar* msg = g_strdup_printf ( _("Couldn't open image file: %s"), gx->message );
1080 vik_window_statusbar_update ( (VikWindow*)VIK_GTK_WINDOW_FROM_LAYER(vml), msg, VIK_STATUSBAR_INFO );
1085 g_error_free ( gx );
1087 g_object_unref ( G_OBJECT(pixbuf) );
1090 pixbuf = pixbuf_apply_settings ( pixbuf, vml, mapcoord, xshrinkfactor, yshrinkfactor );
1097 static gboolean should_start_autodownload(VikMapsLayer *vml, VikViewport *vvp)
1099 const VikCoord *center = vik_viewport_get_center ( vvp );
1101 if (vik_window_get_pan_move (VIK_WINDOW(VIK_GTK_WINDOW_FROM_WIDGET(GTK_WIDGET(vvp)))))
1102 /* D'n'D pan in action: do not download */
1105 // Don't attempt to download unsupported zoom levels
1106 gdouble xzoom = vik_viewport_get_xmpp ( vvp );
1107 VikMapSource *map = MAPS_LAYER_NTH_TYPE(vml->maptype);
1108 guint8 zl = map_utils_mpp_to_zoom_level ( xzoom );
1109 if ( zl < vik_map_source_get_zoom_min(map) || zl > vik_map_source_get_zoom_max(map) )
1112 if (vml->last_center == NULL) {
1113 VikCoord *new_center = g_malloc(sizeof(VikCoord));
1114 *new_center = *center;
1115 vml->last_center = new_center;
1116 vml->last_xmpp = vik_viewport_get_xmpp(vvp);
1117 vml->last_ympp = vik_viewport_get_ympp(vvp);
1121 /* TODO: perhaps vik_coord_diff() */
1122 if (vik_coord_equals(vml->last_center, center)
1123 && (vml->last_xmpp == vik_viewport_get_xmpp(vvp))
1124 && (vml->last_ympp == vik_viewport_get_ympp(vvp)))
1127 *(vml->last_center) = *center;
1128 vml->last_xmpp = vik_viewport_get_xmpp(vvp);
1129 vml->last_ympp = vik_viewport_get_ympp(vvp);
1133 static void maps_layer_draw_section ( VikMapsLayer *vml, VikViewport *vvp, VikCoord *ul, VikCoord *br )
1136 gdouble xzoom = vik_viewport_get_xmpp ( vvp );
1137 gdouble yzoom = vik_viewport_get_ympp ( vvp );
1138 gdouble xshrinkfactor = 1.0, yshrinkfactor = 1.0;
1139 gboolean existence_only = FALSE;
1141 if ( vml->xmapzoom && (vml->xmapzoom != xzoom || vml->ymapzoom != yzoom) ) {
1142 xshrinkfactor = vml->xmapzoom / xzoom;
1143 yshrinkfactor = vml->ymapzoom / yzoom;
1144 xzoom = vml->xmapzoom;
1145 yzoom = vml->xmapzoom;
1146 if ( ! (xshrinkfactor > MIN_SHRINKFACTOR && xshrinkfactor < MAX_SHRINKFACTOR &&
1147 yshrinkfactor > MIN_SHRINKFACTOR && yshrinkfactor < MAX_SHRINKFACTOR ) ) {
1148 if ( xshrinkfactor > REAL_MIN_SHRINKFACTOR && yshrinkfactor > REAL_MIN_SHRINKFACTOR ) {
1149 g_debug ( "%s: existence_only due to SHRINKFACTORS", __FUNCTION__ );
1150 existence_only = TRUE;
1153 // Report the reason for not drawing
1154 if ( IS_VIK_WINDOW ((VikWindow*)VIK_GTK_WINDOW_FROM_LAYER(vml)) ) {
1155 gchar* msg = g_strdup_printf ( _("Cowardly refusing to draw tiles or existence of tiles beyond %d zoom out factor"), (int)( 1.0/REAL_MIN_SHRINKFACTOR));
1156 vik_window_statusbar_update ( (VikWindow*)VIK_GTK_WINDOW_FROM_LAYER(vml), msg, VIK_STATUSBAR_INFO );
1165 VikMapSource *map = MAPS_LAYER_NTH_TYPE(vml->maptype);
1166 if ( vik_map_source_coord_to_mapcoord ( map, ul, xzoom, yzoom, &ulm ) &&
1167 vik_map_source_coord_to_mapcoord ( map, br, xzoom, yzoom, &brm ) ) {
1171 gint xmin = MIN(ulm.x, brm.x), xmax = MAX(ulm.x, brm.x);
1172 gint ymin = MIN(ulm.y, brm.y), ymax = MAX(ulm.y, brm.y);
1173 guint16 id = vik_map_source_get_uniq_id(map);
1174 const gchar *mapname = vik_map_source_get_name(map);
1177 gint xx, yy, width, height;
1180 // Prevent the program grinding to a halt if trying to deal with thousands of tiles
1181 // which can happen when using a small fixed zoom level and viewing large areas.
1182 // Also prevents very large number of tile download requests
1183 gint tiles = (xmax-xmin) * (ymax-ymin);
1184 if ( tiles > MAX_TILES ) {
1185 g_debug ( "%s: existence_only due to wanting too many tiles (%d)", __FUNCTION__, tiles );
1186 existence_only = TRUE;
1189 guint max_path_len = strlen(vml->cache_dir) + 40;
1190 gchar *path_buf = g_malloc ( max_path_len * sizeof(char) );
1192 if ( (!existence_only) && vml->autodownload && should_start_autodownload(vml, vvp)) {
1193 g_debug("%s: Starting autodownload", __FUNCTION__);
1194 if ( !vml->adl_only_missing && vik_map_source_supports_download_only_new (map) )
1195 // Try to download newer tiles
1196 start_download_thread ( vml, vvp, ul, br, REDOWNLOAD_NEW );
1198 // Download only missing tiles
1199 start_download_thread ( vml, vvp, ul, br, REDOWNLOAD_NONE );
1202 if ( vik_map_source_get_tilesize_x(map) == 0 && !existence_only ) {
1203 for ( x = xmin; x <= xmax; x++ ) {
1204 for ( y = ymin; y <= ymax; y++ ) {
1207 pixbuf = get_pixbuf ( vml, id, mapname, &ulm, path_buf, max_path_len, xshrinkfactor, yshrinkfactor );
1209 width = gdk_pixbuf_get_width ( pixbuf );
1210 height = gdk_pixbuf_get_height ( pixbuf );
1212 vik_map_source_mapcoord_to_center_coord ( map, &ulm, &coord );
1213 vik_viewport_coord_to_screen ( vvp, &coord, &xx, &yy );
1217 vik_viewport_draw_pixbuf ( vvp, pixbuf, 0, 0, xx, yy, width, height );
1221 } else { /* tilesize is known, don't have to keep converting coords */
1222 gdouble tilesize_x = vik_map_source_get_tilesize_x(map) * xshrinkfactor;
1223 gdouble tilesize_y = vik_map_source_get_tilesize_y(map) * yshrinkfactor;
1224 /* ceiled so tiles will be maximum size in the case of funky shrinkfactor */
1225 gint tilesize_x_ceil = ceil ( tilesize_x );
1226 gint tilesize_y_ceil = ceil ( tilesize_y );
1227 gint8 xinc = (ulm.x == xmin) ? 1 : -1;
1228 gint8 yinc = (ulm.y == ymin) ? 1 : -1;
1229 gint xx_tmp, yy_tmp;
1230 gint base_yy, xend, yend;
1232 xend = (xinc == 1) ? (xmax+1) : (xmin-1);
1233 yend = (yinc == 1) ? (ymax+1) : (ymin-1);
1235 vik_map_source_mapcoord_to_center_coord ( map, &ulm, &coord );
1236 vik_viewport_coord_to_screen ( vvp, &coord, &xx_tmp, &yy_tmp );
1237 xx = xx_tmp; yy = yy_tmp;
1238 /* above trick so xx,yy doubles. this is so shrinkfactors aren't rounded off
1239 * eg if tile size 128, shrinkfactor 0.333 */
1240 xx -= (tilesize_x/2);
1241 base_yy = yy - (tilesize_y/2);
1243 for ( x = ((xinc == 1) ? xmin : xmax); x != xend; x+=xinc ) {
1245 for ( y = ((yinc == 1) ? ymin : ymax); y != yend; y+=yinc ) {
1249 if ( existence_only ) {
1250 if ( vik_map_source_is_direct_file_access (MAPS_LAYER_NTH_TYPE(vml->maptype)) )
1251 get_filename ( vml->cache_dir, VIK_MAPS_CACHE_LAYOUT_OSM, id, vik_map_source_get_name(map),
1252 ulm.scale, ulm.z, ulm.x, ulm.y, path_buf, max_path_len, vik_map_source_get_file_extension(map) );
1254 get_filename ( vml->cache_dir, vml->cache_layout, id, vik_map_source_get_name(map),
1255 ulm.scale, ulm.z, ulm.x, ulm.y, path_buf, max_path_len, vik_map_source_get_file_extension(map) );
1257 if ( g_file_test ( path_buf, G_FILE_TEST_EXISTS ) == TRUE ) {
1258 GdkGC *black_gc = gtk_widget_get_style(GTK_WIDGET(vvp))->black_gc;
1259 vik_viewport_draw_line ( vvp, black_gc, xx+tilesize_x_ceil, yy, xx, yy+tilesize_y_ceil );
1263 for (scale_inc = 0; scale_inc < 4; scale_inc ++) {
1264 /* try with correct then smaller zooms */
1265 int scale_factor = 1 << scale_inc; /* 2^scale_inc */
1266 MapCoord ulm2 = ulm;
1267 ulm2.x = ulm.x / scale_factor;
1268 ulm2.y = ulm.y / scale_factor;
1269 ulm2.scale = ulm.scale + scale_inc;
1270 pixbuf = get_pixbuf ( vml, id, mapname, &ulm2, path_buf, max_path_len, xshrinkfactor * scale_factor, yshrinkfactor * scale_factor );
1272 gint src_x = (ulm.x % scale_factor) * tilesize_x_ceil;
1273 gint src_y = (ulm.y % scale_factor) * tilesize_y_ceil;
1275 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);
1277 vik_viewport_draw_pixbuf ( vvp, pixbuf, src_x, src_y, xx, yy, tilesize_x_ceil, tilesize_y_ceil );
1282 /* retry with bigger zooms */
1284 for (scale_dec = 1; scale_dec < 2; scale_dec ++) {
1286 int scale_factor = 1 << scale_dec; /* 2^scale_dec */
1287 MapCoord ulm2 = ulm;
1288 ulm2.x = ulm.x * scale_factor;
1289 ulm2.y = ulm.y * scale_factor;
1290 ulm2.scale = ulm.scale - scale_dec;
1291 for (pict_x = 0; pict_x < scale_factor; pict_x ++) {
1292 for (pict_y = 0; pict_y < scale_factor; pict_y ++) {
1293 MapCoord ulm3 = ulm2;
1296 pixbuf = get_pixbuf ( vml, id, mapname, &ulm3, path_buf, max_path_len, xshrinkfactor / scale_factor, yshrinkfactor / scale_factor );
1300 gint dest_x = xx + pict_x * (tilesize_x_ceil / scale_factor);
1301 gint dest_y = yy + pict_y * (tilesize_y_ceil / scale_factor);
1302 vik_viewport_draw_pixbuf ( vvp, pixbuf, src_x, src_y, dest_x, dest_y, tilesize_x_ceil / scale_factor, tilesize_y_ceil / scale_factor );
1316 g_free ( path_buf );
1320 static void maps_layer_draw ( VikMapsLayer *vml, VikViewport *vvp )
1322 if ( vik_map_source_get_drawmode(MAPS_LAYER_NTH_TYPE(vml->maptype)) == vik_viewport_get_drawmode ( vvp ) )
1327 gdouble level = vik_viewport_get_zoom ( vvp );
1329 vik_viewport_get_min_max_lat_lon ( vvp, &bbox.south, &bbox.north, &bbox.west, &bbox.east );
1330 vik_map_source_get_copyright ( MAPS_LAYER_NTH_TYPE(vml->maptype), bbox, level, vik_viewport_add_copyright, vvp );
1333 const GdkPixbuf *logo = vik_map_source_get_logo ( MAPS_LAYER_NTH_TYPE(vml->maptype) );
1334 vik_viewport_add_logo ( vvp, logo );
1336 /* get corner coords */
1337 if ( vik_viewport_get_coord_mode ( vvp ) == VIK_COORD_UTM && ! vik_viewport_is_one_zone ( vvp ) ) {
1338 /* UTM multi-zone stuff by Kit Transue */
1339 gchar leftmost_zone, rightmost_zone, i;
1340 leftmost_zone = vik_viewport_leftmost_zone( vvp );
1341 rightmost_zone = vik_viewport_rightmost_zone( vvp );
1342 for ( i = leftmost_zone; i <= rightmost_zone; ++i ) {
1343 vik_viewport_corners_for_zonen ( vvp, i, &ul, &br );
1344 maps_layer_draw_section ( vml, vvp, &ul, &br );
1348 vik_viewport_screen_to_coord ( vvp, 0, 0, &ul );
1349 vik_viewport_screen_to_coord ( vvp, vik_viewport_get_width(vvp), vik_viewport_get_height(vvp), &br );
1351 maps_layer_draw_section ( vml, vvp, &ul, &br );
1356 /*************************/
1357 /****** DOWNLOADING ******/
1358 /*************************/
1360 /* pass along data to thread, exists even if layer is deleted. */
1363 gchar *filename_buf;
1364 VikMapsCacheLayout cache_layout;
1365 gint x0, y0, xf, yf;
1371 gboolean refresh_display;
1374 gboolean map_layer_alive;
1378 static void mdi_free ( MapDownloadInfo *mdi )
1380 g_mutex_free(mdi->mutex);
1381 g_free ( mdi->cache_dir );
1382 mdi->cache_dir = NULL;
1383 g_free ( mdi->filename_buf );
1384 mdi->filename_buf = NULL;
1388 static void weak_ref_cb(gpointer ptr, GObject * dead_vml)
1390 MapDownloadInfo *mdi = ptr;
1391 g_mutex_lock(mdi->mutex);
1392 mdi->map_layer_alive = FALSE;
1393 g_mutex_unlock(mdi->mutex);
1396 static gboolean is_in_area (VikMapSource *map, MapCoord mc)
1399 vik_map_source_mapcoord_to_center_coord ( map, &mc, &vc );
1402 tl.lat = vik_map_source_get_lat_max(map);
1403 tl.lon = vik_map_source_get_lon_min(map);
1405 br.lat = vik_map_source_get_lat_min(map);
1406 br.lon = vik_map_source_get_lon_max(map);
1408 vik_coord_load_from_latlon (&vctl, VIK_COORD_LATLON, &tl);
1410 vik_coord_load_from_latlon (&vcbr, VIK_COORD_LATLON, &br);
1412 return vik_coord_inside ( &vc, &vctl, &vcbr );
1415 static int map_download_thread ( MapDownloadInfo *mdi, gpointer threaddata )
1417 void *handle = vik_map_source_download_handle_init(MAPS_LAYER_NTH_TYPE(mdi->maptype));
1419 MapCoord mcoord = mdi->mapcoord;
1421 for ( x = mdi->x0; x <= mdi->xf; x++ )
1424 for ( y = mdi->y0; y <= mdi->yf; y++ )
1427 // Only attempt to download a tile from supported areas
1428 if ( is_in_area ( MAPS_LAYER_NTH_TYPE(mdi->maptype), mcoord ) )
1430 gboolean remove_mem_cache = FALSE;
1431 gboolean need_download = FALSE;
1433 get_filename ( mdi->cache_dir, mdi->cache_layout,
1434 vik_map_source_get_uniq_id(MAPS_LAYER_NTH_TYPE(mdi->maptype)),
1435 vik_map_source_get_name(MAPS_LAYER_NTH_TYPE(mdi->maptype)),
1436 mdi->mapcoord.scale, mdi->mapcoord.z, x, y, mdi->filename_buf, mdi->maxlen,
1437 vik_map_source_get_file_extension(MAPS_LAYER_NTH_TYPE(mdi->maptype)) );
1440 int res = a_background_thread_progress ( threaddata, ((gdouble)donemaps) / mdi->mapstoget ); /* this also calls testcancel */
1442 vik_map_source_download_handle_cleanup(MAPS_LAYER_NTH_TYPE(mdi->maptype), handle);
1446 if ( g_file_test ( mdi->filename_buf, G_FILE_TEST_EXISTS ) == FALSE ) {
1447 need_download = TRUE;
1448 remove_mem_cache = TRUE;
1450 } else { /* in case map file already exists */
1451 switch (mdi->redownload) {
1452 case REDOWNLOAD_NONE:
1455 case REDOWNLOAD_BAD:
1457 /* see if this one is bad or what */
1459 GdkPixbuf *pixbuf = gdk_pixbuf_new_from_file ( mdi->filename_buf, &gx );
1460 if (gx || (!pixbuf)) {
1461 g_remove ( mdi->filename_buf );
1462 need_download = TRUE;
1463 remove_mem_cache = TRUE;
1464 g_error_free ( gx );
1467 g_object_unref ( pixbuf );
1472 case REDOWNLOAD_NEW:
1473 need_download = TRUE;
1474 remove_mem_cache = TRUE;
1477 case REDOWNLOAD_ALL:
1478 /* FIXME: need a better way than to erase file in case of server/network problem */
1479 g_remove ( mdi->filename_buf );
1480 need_download = TRUE;
1481 remove_mem_cache = TRUE;
1484 case DOWNLOAD_OR_REFRESH:
1485 remove_mem_cache = TRUE;
1489 g_warning ( "redownload state %d unknown\n", mdi->redownload);
1493 mdi->mapcoord.x = x; mdi->mapcoord.y = y;
1495 if (need_download) {
1496 DownloadResult_t dr = vik_map_source_download( MAPS_LAYER_NTH_TYPE(mdi->maptype), &(mdi->mapcoord), mdi->filename_buf, handle);
1498 case DOWNLOAD_HTTP_ERROR:
1499 case DOWNLOAD_CONTENT_ERROR: {
1500 // TODO: ?? count up the number of download errors somehow...
1501 gchar* msg = g_strdup_printf ( "%s: %s", vik_maps_layer_get_map_label (mdi->vml), _("Failed to download tile") );
1502 vik_window_statusbar_update ( (VikWindow*)VIK_GTK_WINDOW_FROM_LAYER(mdi->vml), msg, VIK_STATUSBAR_INFO );
1506 case DOWNLOAD_FILE_WRITE_ERROR: {
1507 gchar* msg = g_strdup_printf ( "%s: %s", vik_maps_layer_get_map_label (mdi->vml), _("Unable to save tile") );
1508 vik_window_statusbar_update ( (VikWindow*)VIK_GTK_WINDOW_FROM_LAYER(mdi->vml), msg, VIK_STATUSBAR_INFO );
1512 case DOWNLOAD_SUCCESS:
1513 case DOWNLOAD_NOT_REQUIRED:
1519 g_mutex_lock(mdi->mutex);
1520 if (remove_mem_cache)
1521 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 );
1522 if (mdi->refresh_display && mdi->map_layer_alive) {
1523 /* TODO: check if it's on visible area */
1524 vik_layer_emit_update ( VIK_LAYER(mdi->vml) ); // NB update display from background
1526 g_mutex_unlock(mdi->mutex);
1527 mdi->mapcoord.x = mdi->mapcoord.y = 0; /* we're temporarily between downloads */
1531 vik_map_source_download_handle_cleanup(MAPS_LAYER_NTH_TYPE(mdi->maptype), handle);
1532 g_mutex_lock(mdi->mutex);
1533 if (mdi->map_layer_alive)
1534 g_object_weak_unref(G_OBJECT(mdi->vml), weak_ref_cb, mdi);
1535 g_mutex_unlock(mdi->mutex);
1539 static void mdi_cancel_cleanup ( MapDownloadInfo *mdi )
1541 if ( mdi->mapcoord.x || mdi->mapcoord.y )
1543 get_filename ( mdi->cache_dir, mdi->cache_layout,
1544 vik_map_source_get_uniq_id(MAPS_LAYER_NTH_TYPE(mdi->maptype)),
1545 vik_map_source_get_name(MAPS_LAYER_NTH_TYPE(mdi->maptype)),
1546 mdi->mapcoord.scale, mdi->mapcoord.z, mdi->mapcoord.x, mdi->mapcoord.y, mdi->filename_buf, mdi->maxlen,
1547 vik_map_source_get_file_extension(MAPS_LAYER_NTH_TYPE(mdi->maptype)) );
1548 if ( g_file_test ( mdi->filename_buf, G_FILE_TEST_EXISTS ) == TRUE)
1550 g_remove ( mdi->filename_buf );
1555 static void start_download_thread ( VikMapsLayer *vml, VikViewport *vvp, const VikCoord *ul, const VikCoord *br, gint redownload )
1557 gdouble xzoom = vml->xmapzoom ? vml->xmapzoom : vik_viewport_get_xmpp ( vvp );
1558 gdouble yzoom = vml->ymapzoom ? vml->ymapzoom : vik_viewport_get_ympp ( vvp );
1560 VikMapSource *map = MAPS_LAYER_NTH_TYPE(vml->maptype);
1562 // Don't ever attempt download on direct access
1563 if ( vik_map_source_is_direct_file_access ( map ) )
1566 if ( vik_map_source_coord_to_mapcoord ( map, ul, xzoom, yzoom, &ulm )
1567 && vik_map_source_coord_to_mapcoord ( map, br, xzoom, yzoom, &brm ) )
1569 MapDownloadInfo *mdi = g_malloc ( sizeof(MapDownloadInfo) );
1574 mdi->map_layer_alive = TRUE;
1575 mdi->mutex = g_mutex_new();
1576 mdi->refresh_display = TRUE;
1578 /* cache_dir and buffer for dest filename */
1579 mdi->cache_dir = g_strdup ( vml->cache_dir );
1580 mdi->maxlen = strlen ( vml->cache_dir ) + 40;
1581 mdi->filename_buf = g_malloc ( mdi->maxlen * sizeof(gchar) );
1582 mdi->cache_layout = vml->cache_layout;
1583 mdi->maptype = vml->maptype;
1585 mdi->mapcoord = ulm;
1586 mdi->redownload = redownload;
1588 mdi->x0 = MIN(ulm.x, brm.x);
1589 mdi->xf = MAX(ulm.x, brm.x);
1590 mdi->y0 = MIN(ulm.y, brm.y);
1591 mdi->yf = MAX(ulm.y, brm.y);
1595 MapCoord mcoord = mdi->mapcoord;
1597 if ( mdi->redownload ) {
1598 mdi->mapstoget = (mdi->xf - mdi->x0 + 1) * (mdi->yf - mdi->y0 + 1);
1600 /* calculate how many we need */
1601 for ( a = mdi->x0; a <= mdi->xf; a++ )
1604 for ( b = mdi->y0; b <= mdi->yf; b++ )
1607 // Only count tiles from supported areas
1608 if ( is_in_area (map, mcoord) )
1610 get_filename ( mdi->cache_dir, mdi->cache_layout,
1611 vik_map_source_get_uniq_id(map),
1612 vik_map_source_get_name(map),
1613 ulm.scale, ulm.z, a, b, mdi->filename_buf, mdi->maxlen,
1614 vik_map_source_get_file_extension(map) );
1615 if ( g_file_test ( mdi->filename_buf, G_FILE_TEST_EXISTS ) == FALSE )
1622 mdi->mapcoord.x = mdi->mapcoord.y = 0; /* for cleanup -- no current map */
1624 if ( mdi->mapstoget )
1626 const gchar *tmp_str;
1631 if (redownload == REDOWNLOAD_BAD)
1632 tmp_str = ngettext("Redownloading up to %d %s map...", "Redownloading up to %d %s maps...", mdi->mapstoget);
1634 tmp_str = ngettext("Redownloading %d %s map...", "Redownloading %d %s maps...", mdi->mapstoget);
1638 tmp_str = ngettext("Downloading %d %s map...", "Downloading %d %s maps...", mdi->mapstoget);
1640 tmp = g_strdup_printf ( tmp_str, mdi->mapstoget, MAPS_LAYER_NTH_LABEL(vml->maptype));
1642 g_object_weak_ref(G_OBJECT(mdi->vml), weak_ref_cb, mdi);
1643 /* launch the thread */
1644 a_background_thread ( VIK_GTK_WINDOW_FROM_LAYER(vml), /* parent window */
1645 tmp, /* description string */
1646 (vik_thr_func) map_download_thread, /* function to call within thread */
1647 mdi, /* pass along data */
1648 (vik_thr_free_func) mdi_free, /* function to free pass along data */
1649 (vik_thr_free_func) mdi_cancel_cleanup,
1658 static void maps_layer_download_section ( VikMapsLayer *vml, VikViewport *vvp, VikCoord *ul, VikCoord *br, gdouble zoom, gint download_method )
1661 VikMapSource *map = MAPS_LAYER_NTH_TYPE(vml->maptype);
1663 // Don't ever attempt download on direct access
1664 if ( vik_map_source_is_direct_file_access ( map ) )
1667 if (!vik_map_source_coord_to_mapcoord(map, ul, zoom, zoom, &ulm)
1668 || !vik_map_source_coord_to_mapcoord(map, br, zoom, zoom, &brm)) {
1669 g_warning("%s() coord_to_mapcoord() failed", __PRETTY_FUNCTION__);
1673 MapDownloadInfo *mdi = g_malloc(sizeof(MapDownloadInfo));
1678 mdi->map_layer_alive = TRUE;
1679 mdi->mutex = g_mutex_new();
1680 mdi->refresh_display = TRUE;
1682 mdi->cache_dir = g_strdup ( vml->cache_dir );
1683 mdi->maxlen = strlen ( vml->cache_dir ) + 40;
1684 mdi->filename_buf = g_malloc ( mdi->maxlen * sizeof(gchar) );
1685 mdi->maptype = vml->maptype;
1686 mdi->cache_layout = vml->cache_layout;
1688 mdi->mapcoord = ulm;
1689 mdi->redownload = download_method;
1691 mdi->x0 = MIN(ulm.x, brm.x);
1692 mdi->xf = MAX(ulm.x, brm.x);
1693 mdi->y0 = MIN(ulm.y, brm.y);
1694 mdi->yf = MAX(ulm.y, brm.y);
1698 MapCoord mcoord = mdi->mapcoord;
1700 for (i = mdi->x0; i <= mdi->xf; i++) {
1702 for (j = mdi->y0; j <= mdi->yf; j++) {
1704 // Only count tiles from supported areas
1705 if ( is_in_area (map, mcoord) ) {
1706 get_filename ( mdi->cache_dir, mdi->cache_layout,
1707 vik_map_source_get_uniq_id(map),
1708 vik_map_source_get_name(map),
1709 ulm.scale, ulm.z, i, j, mdi->filename_buf, mdi->maxlen,
1710 vik_map_source_get_file_extension(map) );
1711 if ( g_file_test ( mdi->filename_buf, G_FILE_TEST_EXISTS ) == FALSE )
1717 mdi->mapcoord.x = mdi->mapcoord.y = 0; /* for cleanup -- no current map */
1719 if (mdi->mapstoget) {
1722 fmt = ngettext("Downloading %d %s map...",
1723 "Downloading %d %s maps...",
1725 tmp = g_strdup_printf ( fmt, mdi->mapstoget, MAPS_LAYER_NTH_LABEL(vml->maptype) );
1727 g_object_weak_ref(G_OBJECT(mdi->vml), weak_ref_cb, mdi);
1728 /* launch the thread */
1729 a_background_thread ( VIK_GTK_WINDOW_FROM_LAYER(vml), /* parent window */
1730 tmp, /* description string */
1731 (vik_thr_func) map_download_thread, /* function to call within thread */
1732 mdi, /* pass along data */
1733 (vik_thr_free_func) mdi_free, /* function to free pass along data */
1734 (vik_thr_free_func) mdi_cancel_cleanup,
1743 * vik_maps_layer_download_section:
1744 * @vml: The Map Layer
1745 * @vvp: The Viewport that the map is on
1746 * @ul: Upper left coordinate of the area to be downloaded
1747 * @br: Bottom right coordinate of the area to be downloaded
1748 * @zoom: The zoom level at which the maps are to be download
1750 * Download a specified map area at a certain zoom level
1752 void vik_maps_layer_download_section ( VikMapsLayer *vml, VikViewport *vvp, VikCoord *ul, VikCoord *br, gdouble zoom )
1754 maps_layer_download_section (vml, vvp, ul, br, zoom, REDOWNLOAD_NONE);
1757 static void maps_layer_redownload_bad ( VikMapsLayer *vml )
1759 start_download_thread ( vml, vml->redownload_vvp, &(vml->redownload_ul), &(vml->redownload_br), REDOWNLOAD_BAD );
1762 static void maps_layer_redownload_all ( VikMapsLayer *vml )
1764 start_download_thread ( vml, vml->redownload_vvp, &(vml->redownload_ul), &(vml->redownload_br), REDOWNLOAD_ALL );
1767 static void maps_layer_redownload_new ( VikMapsLayer *vml )
1769 start_download_thread ( vml, vml->redownload_vvp, &(vml->redownload_ul), &(vml->redownload_br), REDOWNLOAD_NEW );
1773 * Display a simple dialog with information about this particular map tile
1775 static void maps_layer_tile_info ( VikMapsLayer *vml )
1777 VikMapSource *map = MAPS_LAYER_NTH_TYPE(vml->maptype);
1779 gdouble xzoom = vml->xmapzoom ? vml->xmapzoom : vik_viewport_get_xmpp ( vml->redownload_vvp );
1780 gdouble yzoom = vml->ymapzoom ? vml->ymapzoom : vik_viewport_get_ympp ( vml->redownload_vvp );
1783 if ( !vik_map_source_coord_to_mapcoord ( map, &(vml->redownload_ul), xzoom, yzoom, &ulm ) )
1786 gchar *filename = NULL;
1787 gchar *message = NULL;
1788 gchar *source = NULL;
1790 if ( vik_map_source_is_direct_file_access ( map ) ) {
1791 if ( vik_map_source_is_mbtiles ( map ) ) {
1792 filename = g_strdup ( vml->filename );
1793 #ifdef HAVE_SQLITE3_H
1794 // And whether to bother going into the SQL to check it's really there or not...
1795 gchar *exists = NULL;
1796 gint zoom = 17 - ulm.scale;
1797 if ( vml->mbtiles ) {
1798 GdkPixbuf *pixbuf = get_pixbuf_sql_exec ( vml->mbtiles, ulm.x, ulm.y, zoom );
1800 exists = g_strdup ( _("YES") );
1801 g_object_unref ( G_OBJECT(pixbuf) );
1804 exists = g_strdup ( _("NO") );
1808 exists = g_strdup ( _("NO") );
1809 gint flip_y = (gint) pow(2, zoom)-1 - ulm.y;
1810 // NB Also handles .jpg automatically due to pixbuf_new_from () support - although just print png for now.
1811 source = g_strdup_printf ( "%s (%d%s%d%s%d.%s %s)", filename, zoom, G_DIR_SEPARATOR_S, ulm.x, G_DIR_SEPARATOR_S, flip_y, "png", exists );
1814 source = g_strdup ( _("Not available") );
1817 else if ( vik_map_source_is_osm_meta_tiles ( map ) ) {
1818 char path[PATH_MAX];
1819 xyz_to_meta(path, sizeof(path), vml->cache_dir, ulm.x, ulm.y, 17-ulm.scale );
1820 source = g_strdup ( path );
1821 filename = g_strdup ( path );
1824 guint max_path_len = strlen(vml->cache_dir) + 40;
1825 filename = g_malloc ( max_path_len * sizeof(char) );
1826 get_filename ( vml->cache_dir, VIK_MAPS_CACHE_LAYOUT_OSM,
1827 vik_map_source_get_uniq_id(map),
1829 ulm.scale, ulm.z, ulm.x, ulm.y, filename, max_path_len,
1830 vik_map_source_get_file_extension(map) );
1831 source = g_strconcat ( "file://", filename, NULL );
1835 guint max_path_len = strlen(vml->cache_dir) + 40;
1836 filename = g_malloc ( max_path_len * sizeof(char) );
1837 get_filename ( vml->cache_dir, vml->cache_layout,
1838 vik_map_source_get_uniq_id(map),
1839 vik_map_source_get_name(map),
1840 ulm.scale, ulm.z, ulm.x, ulm.y, filename, max_path_len,
1841 vik_map_source_get_file_extension(map) );
1842 source = g_strdup_printf ( "http://%s%s",
1843 vik_map_source_default_get_hostname ( VIK_MAP_SOURCE_DEFAULT(map) ),
1844 vik_map_source_default_get_uri ( VIK_MAP_SOURCE_DEFAULT(map), &ulm ) );
1847 if ( g_file_test ( filename, G_FILE_TEST_EXISTS ) ) {
1849 // Get some timestamp information of the tile
1850 struct stat stat_buf;
1851 if ( g_stat ( filename, &stat_buf ) == 0 ) {
1853 strftime ( time_buf, sizeof(time_buf), "%c", gmtime((const time_t *)&stat_buf.st_mtime) );
1854 message = g_strdup_printf ( _("\nSource: %s\n\nTile File: %s\nTile File Timestamp: %s"), source, filename, time_buf );
1857 message = g_strdup_printf ( _("\nSource: %s\n\nTile File: %s\nTile File Timestamp: Not Available"), source, filename );
1860 a_dialog_info_msg ( VIK_GTK_WINDOW_FROM_LAYER(vml), message );
1863 message = g_strdup_printf ( _("\nSource: %s\n\nTile File: %s [Not Available]"), source, filename );
1864 a_dialog_warning_msg ( VIK_GTK_WINDOW_FROM_LAYER(vml), message );
1869 g_free ( filename );
1872 static gboolean maps_layer_download_release ( VikMapsLayer *vml, GdkEventButton *event, VikViewport *vvp )
1874 if (!vml || vml->vl.type != VIK_LAYER_MAPS)
1876 if ( vml->dl_tool_x != -1 && vml->dl_tool_y != -1 )
1878 if ( event->button == 1 )
1881 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 );
1882 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 );
1883 start_download_thread ( vml, vvp, &ul, &br, DOWNLOAD_OR_REFRESH );
1884 vml->dl_tool_x = vml->dl_tool_y = -1;
1889 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) );
1890 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) );
1892 vml->redownload_vvp = vvp;
1894 vml->dl_tool_x = vml->dl_tool_y = -1;
1896 if ( ! vml->dl_right_click_menu ) {
1898 vml->dl_right_click_menu = GTK_MENU ( gtk_menu_new () );
1900 item = gtk_menu_item_new_with_mnemonic ( _("Redownload _Bad Map(s)") );
1901 g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(maps_layer_redownload_bad), vml );
1902 gtk_menu_shell_append ( GTK_MENU_SHELL(vml->dl_right_click_menu), item );
1904 item = gtk_menu_item_new_with_mnemonic ( _("Redownload _New Map(s)") );
1905 g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(maps_layer_redownload_new), vml );
1906 gtk_menu_shell_append ( GTK_MENU_SHELL(vml->dl_right_click_menu), item );
1908 item = gtk_menu_item_new_with_mnemonic ( _("Redownload _All Map(s)") );
1909 g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(maps_layer_redownload_all), vml );
1910 gtk_menu_shell_append ( GTK_MENU_SHELL(vml->dl_right_click_menu), item );
1912 item = gtk_image_menu_item_new_with_mnemonic ( _("_Show Tile Information") );
1913 gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_INFO, GTK_ICON_SIZE_MENU) );
1914 g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(maps_layer_tile_info), vml );
1915 gtk_menu_shell_append (GTK_MENU_SHELL(vml->dl_right_click_menu), item);
1918 gtk_menu_popup ( vml->dl_right_click_menu, NULL, NULL, NULL, NULL, event->button, event->time );
1919 gtk_widget_show_all ( GTK_WIDGET(vml->dl_right_click_menu) );
1925 static gpointer maps_layer_download_create ( VikWindow *vw, VikViewport *vvp)
1930 static gboolean maps_layer_download_click ( VikMapsLayer *vml, GdkEventButton *event, VikViewport *vvp )
1933 if (!vml || vml->vl.type != VIK_LAYER_MAPS)
1935 VikMapSource *map = MAPS_LAYER_NTH_TYPE(vml->maptype);
1936 if ( vik_map_source_get_drawmode(map) == vik_viewport_get_drawmode ( vvp ) &&
1937 vik_map_source_coord_to_mapcoord ( map, vik_viewport_get_center ( vvp ),
1938 vml->xmapzoom ? vml->xmapzoom : vik_viewport_get_xmpp ( vvp ),
1939 vml->ymapzoom ? vml->ymapzoom : vik_viewport_get_ympp ( vvp ),
1941 vml->dl_tool_x = event->x, vml->dl_tool_y = event->y;
1947 // A slightly better way of defining the menu callback information
1948 // This should be easier to extend/rework compared to previously
1955 typedef gpointer menu_array_values[MA_LAST];
1957 static void download_onscreen_maps ( menu_array_values values, gint redownload )
1959 VikMapsLayer *vml = VIK_MAPS_LAYER(values[MA_VML]);
1960 VikViewport *vvp = VIK_VIEWPORT(values[MA_VVP]);
1961 VikViewportDrawMode vp_drawmode = vik_viewport_get_drawmode ( vvp );
1963 gdouble xzoom = vml->xmapzoom ? vml->xmapzoom : vik_viewport_get_xmpp ( vvp );
1964 gdouble yzoom = vml->ymapzoom ? vml->ymapzoom : vik_viewport_get_ympp ( vvp );
1969 vik_viewport_screen_to_coord ( vvp, 0, 0, &ul );
1970 vik_viewport_screen_to_coord ( vvp, vik_viewport_get_width(vvp), vik_viewport_get_height(vvp), &br );
1972 VikMapSource *map = MAPS_LAYER_NTH_TYPE(vml->maptype);
1973 if ( vik_map_source_get_drawmode(map) == vp_drawmode &&
1974 vik_map_source_coord_to_mapcoord ( map, &ul, xzoom, yzoom, &ulm ) &&
1975 vik_map_source_coord_to_mapcoord ( map, &br, xzoom, yzoom, &brm ) )
1976 start_download_thread ( vml, vvp, &ul, &br, redownload );
1977 else if (vik_map_source_get_drawmode(map) != vp_drawmode) {
1978 const gchar *drawmode_name = vik_viewport_get_drawmode_name (vvp, vik_map_source_get_drawmode(map));
1979 gchar *err = g_strdup_printf(_("Wrong drawmode for this map.\nSelect \"%s\" from View menu and try again."), _(drawmode_name));
1980 a_dialog_error_msg ( VIK_GTK_WINDOW_FROM_LAYER(vml), err );
1984 a_dialog_error_msg ( VIK_GTK_WINDOW_FROM_LAYER(vml), _("Wrong zoom level for this map.") );
1988 static void maps_layer_download_missing_onscreen_maps ( menu_array_values values )
1990 download_onscreen_maps( values, REDOWNLOAD_NONE);
1993 static void maps_layer_download_new_onscreen_maps ( menu_array_values values )
1995 download_onscreen_maps( values, REDOWNLOAD_NEW);
1998 static void maps_layer_redownload_all_onscreen_maps ( menu_array_values values )
2000 download_onscreen_maps( values, REDOWNLOAD_ALL);
2003 static void maps_layer_about ( gpointer vml_vvp[2] )
2005 VikMapsLayer *vml = vml_vvp[0];
2006 VikMapSource *map = MAPS_LAYER_NTH_TYPE(vml->maptype);
2008 if ( vik_map_source_get_license (map) )
2009 maps_show_license ( VIK_GTK_WINDOW_FROM_LAYER(vml), map );
2011 a_dialog_info_msg ( VIK_GTK_WINDOW_FROM_LAYER(vml),
2012 vik_map_source_get_label (map) );
2016 * maps_layer_how_many_maps:
2017 * Copied from maps_layer_download_section but without the actual download and this returns a value
2019 static gint maps_layer_how_many_maps ( VikMapsLayer *vml, VikViewport *vvp, VikCoord *ul, VikCoord *br, gdouble zoom, gint redownload )
2022 VikMapSource *map = MAPS_LAYER_NTH_TYPE(vml->maptype);
2024 if ( vik_map_source_is_direct_file_access ( map ) )
2027 if (!vik_map_source_coord_to_mapcoord(map, ul, zoom, zoom, &ulm)
2028 || !vik_map_source_coord_to_mapcoord(map, br, zoom, zoom, &brm)) {
2029 g_warning("%s() coord_to_mapcoord() failed", __PRETTY_FUNCTION__);
2033 MapDownloadInfo *mdi = g_malloc(sizeof(MapDownloadInfo));
2038 mdi->map_layer_alive = TRUE;
2039 mdi->mutex = g_mutex_new();
2040 mdi->refresh_display = FALSE;
2042 mdi->cache_dir = g_strdup ( vml->cache_dir );
2043 mdi->maxlen = strlen ( vml->cache_dir ) + 40;
2044 mdi->filename_buf = g_malloc ( mdi->maxlen * sizeof(gchar) );
2045 mdi->maptype = vml->maptype;
2046 mdi->cache_layout = vml->cache_layout;
2048 mdi->mapcoord = ulm;
2049 mdi->redownload = redownload;
2051 mdi->x0 = MIN(ulm.x, brm.x);
2052 mdi->xf = MAX(ulm.x, brm.x);
2053 mdi->y0 = MIN(ulm.y, brm.y);
2054 mdi->yf = MAX(ulm.y, brm.y);
2058 if ( mdi->redownload == REDOWNLOAD_ALL ) {
2059 mdi->mapstoget = (mdi->xf - mdi->x0 + 1) * (mdi->yf - mdi->y0 + 1);
2062 /* calculate how many we need */
2063 MapCoord mcoord = mdi->mapcoord;
2064 for (i = mdi->x0; i <= mdi->xf; i++) {
2066 for (j = mdi->y0; j <= mdi->yf; j++) {
2068 // Only count tiles from supported areas
2069 if ( is_in_area ( map, mcoord ) ) {
2070 get_filename ( mdi->cache_dir, mdi->cache_layout,
2071 vik_map_source_get_uniq_id(map),
2072 vik_map_source_get_name(map),
2073 ulm.scale, ulm.z, i, j, mdi->filename_buf, mdi->maxlen,
2074 vik_map_source_get_file_extension(map) );
2075 if ( mdi->redownload == REDOWNLOAD_NEW ) {
2076 // Assume the worst - always a new file
2077 // Absolute value would require a server lookup - but that is too slow
2081 if ( g_file_test ( mdi->filename_buf, G_FILE_TEST_EXISTS ) == FALSE ) {
2086 if ( mdi->redownload == REDOWNLOAD_BAD ) {
2087 /* see if this one is bad or what */
2089 GdkPixbuf *pixbuf = gdk_pixbuf_new_from_file ( mdi->filename_buf, &gx );
2090 if (gx || (!pixbuf)) {
2094 // Other download cases already considered or just ignored
2103 gint rv = mdi->mapstoget;
2111 * maps_dialog_zoom_between:
2112 * This dialog is specific to the map layer, so it's here rather than in dialog.c
2114 gboolean maps_dialog_zoom_between ( GtkWindow *parent,
2119 gint *selected_zoom1,
2120 gint *selected_zoom2,
2121 gchar *download_list[],
2122 gint default_download,
2123 gint *selected_download )
2125 GtkWidget *dialog = gtk_dialog_new_with_buttons ( title,
2127 GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
2128 GTK_STOCK_OK, GTK_RESPONSE_ACCEPT,
2129 GTK_STOCK_CANCEL, GTK_RESPONSE_REJECT,
2131 gtk_dialog_set_default_response ( GTK_DIALOG(dialog), GTK_RESPONSE_ACCEPT );
2132 GtkWidget *response_w = NULL;
2133 #if GTK_CHECK_VERSION (2, 20, 0)
2134 response_w = gtk_dialog_get_widget_for_response ( GTK_DIALOG(dialog), GTK_RESPONSE_ACCEPT );
2136 GtkWidget *zoom_label1 = gtk_label_new ( _("Zoom Start:") );
2137 GtkWidget *zoom_combo1 = vik_combo_box_text_new();
2139 for (s = zoom_list; *s; s++)
2140 vik_combo_box_text_append ( zoom_combo1, *s );
2141 gtk_combo_box_set_active ( GTK_COMBO_BOX(zoom_combo1), default_zoom1 );
2143 GtkWidget *zoom_label2 = gtk_label_new ( _("Zoom End:") );
2144 GtkWidget *zoom_combo2 = vik_combo_box_text_new();
2145 for (s = zoom_list; *s; s++)
2146 vik_combo_box_text_append ( zoom_combo2, *s );
2147 gtk_combo_box_set_active ( GTK_COMBO_BOX(zoom_combo2), default_zoom2 );
2149 GtkWidget *download_label = gtk_label_new(_("Download Maps Method:"));
2150 GtkWidget *download_combo = vik_combo_box_text_new();
2151 for (s = download_list; *s; s++)
2152 vik_combo_box_text_append ( download_combo, *s );
2153 gtk_combo_box_set_active ( GTK_COMBO_BOX(download_combo), default_download );
2155 GtkTable *box = GTK_TABLE(gtk_table_new(3, 2, FALSE));
2156 gtk_table_attach_defaults (box, GTK_WIDGET(zoom_label1), 0, 1, 0, 1);
2157 gtk_table_attach_defaults (box, GTK_WIDGET(zoom_combo1), 1, 2, 0, 1);
2158 gtk_table_attach_defaults (box, GTK_WIDGET(zoom_label2), 0, 1, 1, 2);
2159 gtk_table_attach_defaults (box, GTK_WIDGET(zoom_combo2), 1, 2, 1, 2);
2160 gtk_table_attach_defaults (box, GTK_WIDGET(download_label), 0, 1, 2, 3);
2161 gtk_table_attach_defaults (box, GTK_WIDGET(download_combo), 1, 2, 2, 3);
2163 gtk_box_pack_start ( GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(dialog))), GTK_WIDGET(box), FALSE, FALSE, 5 );
2166 gtk_widget_grab_focus ( response_w );
2168 gtk_widget_show_all ( dialog );
2169 if ( gtk_dialog_run ( GTK_DIALOG(dialog) ) != GTK_RESPONSE_ACCEPT ) {
2170 gtk_widget_destroy(dialog);
2174 // Return selected options
2175 *selected_zoom1 = gtk_combo_box_get_active ( GTK_COMBO_BOX(zoom_combo1) );
2176 *selected_zoom2 = gtk_combo_box_get_active ( GTK_COMBO_BOX(zoom_combo2) );
2177 *selected_download = gtk_combo_box_get_active ( GTK_COMBO_BOX(download_combo) );
2179 gtk_widget_destroy(dialog);
2183 // My best guess of sensible limits
2184 #define REALLY_LARGE_AMOUNT_OF_TILES 5000
2185 #define CONFIRM_LARGE_AMOUNT_OF_TILES 500
2188 * Get all maps in the region for zoom levels specified by the user
2189 * Sort of similar to trw_layer_download_map_along_track_cb function
2191 static void maps_layer_download_all ( menu_array_values values )
2193 VikMapsLayer *vml = VIK_MAPS_LAYER(values[MA_VML]);
2194 VikViewport *vvp = VIK_VIEWPORT(values[MA_VVP]);
2196 // I don't think we should allow users to hammer the servers too much...
2197 // Delibrately not allowing lowest zoom levels
2198 // Still can give massive numbers to download
2199 // A screen size of 1600x1200 gives around 300,000 tiles between 1..128 when none exist before !!
2200 gchar *zoom_list[] = {"1", "2", "4", "8", "16", "32", "64", "128", "256", "512", "1024", NULL };
2201 gdouble zoom_vals[] = {1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024};
2203 gint selected_zoom1, selected_zoom2, default_zoom, lower_zoom;
2204 gint selected_download_method;
2206 gdouble cur_zoom = vik_viewport_get_zoom(vvp);
2208 for (default_zoom = 0; default_zoom < sizeof(zoom_vals)/sizeof(gdouble); default_zoom++) {
2209 if (cur_zoom == zoom_vals[default_zoom])
2212 default_zoom = (default_zoom == sizeof(zoom_vals)/sizeof(gdouble)) ? sizeof(zoom_vals)/sizeof(gdouble) - 1 : default_zoom;
2214 // Default to only 2 zoom levels below the current one
2215 if (default_zoom > 1 )
2216 lower_zoom = default_zoom - 2;
2218 lower_zoom = default_zoom;
2220 // redownload method - needs to align with REDOWNLOAD* macro values
2221 gchar *download_list[] = { _("Missing"), _("Bad"), _("New"), _("Reload All"), NULL };
2223 gchar *title = g_strdup_printf ( ("%s: %s"), vik_maps_layer_get_map_label (vml), _("Download for Zoom Levels") );
2225 if ( ! maps_dialog_zoom_between ( VIK_GTK_WINDOW_FROM_LAYER(vml),
2233 REDOWNLOAD_NONE, // AKA Missing
2234 &selected_download_method ) ) {
2241 // Find out new current positions
2242 gdouble min_lat, max_lat, min_lon, max_lon;
2243 VikCoord vc_ul, vc_br;
2244 vik_viewport_get_min_max_lat_lon ( vvp, &min_lat, &max_lat, &min_lon, &max_lon );
2245 struct LatLon ll_ul = { max_lat, min_lon };
2246 struct LatLon ll_br = { min_lat, max_lon };
2247 vik_coord_load_from_latlon ( &vc_ul, vik_viewport_get_coord_mode (vvp), &ll_ul );
2248 vik_coord_load_from_latlon ( &vc_br, vik_viewport_get_coord_mode (vvp), &ll_br );
2250 // Get Maps Count - call for each zoom level (in reverse)
2251 // With REDOWNLOAD_NEW this is a possible maximum
2252 // With REDOWNLOAD_NONE this only missing ones - however still has a server lookup per tile
2255 for ( zz = selected_zoom2; zz >= selected_zoom1; zz-- ) {
2256 map_count = map_count + maps_layer_how_many_maps ( vml, vvp, &vc_ul, &vc_br, zoom_vals[zz], selected_download_method );
2259 g_debug ("vikmapslayer: download request map count %d for method %d", map_count, selected_download_method);
2261 // Absolute protection of hammering a map server
2262 if ( map_count > REALLY_LARGE_AMOUNT_OF_TILES ) {
2263 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);
2264 a_dialog_error_msg ( VIK_GTK_WINDOW_FROM_LAYER(vml), str );
2269 // Confirm really want to do this
2270 if ( map_count > CONFIRM_LARGE_AMOUNT_OF_TILES ) {
2271 gchar *str = g_strdup_printf (_("Do you really want to download %d tiles?"), map_count);
2272 gboolean ans = a_dialog_yes_or_no ( VIK_GTK_WINDOW_FROM_LAYER(vml), str, NULL );
2278 // Get Maps - call for each zoom level (in reverse)
2279 for ( zz = selected_zoom2; zz >= selected_zoom1; zz-- ) {
2280 maps_layer_download_section ( vml, vvp, &vc_ul, &vc_br, zoom_vals[zz], selected_download_method );
2284 static void maps_layer_add_menu_items ( VikMapsLayer *vml, GtkMenu *menu, VikLayersPanel *vlp )
2287 static menu_array_values values;
2288 values[MA_VML] = vml;
2289 values[MA_VVP] = vik_layers_panel_get_viewport( VIK_LAYERS_PANEL(vlp) );
2291 item = gtk_menu_item_new();
2292 gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item );
2293 gtk_widget_show ( item );
2295 /* Now with icons */
2296 item = gtk_image_menu_item_new_with_mnemonic ( _("Download _Missing Onscreen Maps") );
2297 gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_ADD, GTK_ICON_SIZE_MENU) );
2298 g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(maps_layer_download_missing_onscreen_maps), values );
2299 gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
2300 gtk_widget_show ( item );
2302 if ( vik_map_source_supports_download_only_new (MAPS_LAYER_NTH_TYPE(vml->maptype)) ) {
2303 item = gtk_image_menu_item_new_with_mnemonic ( _("Download _New Onscreen Maps") );
2304 gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_REDO, GTK_ICON_SIZE_MENU) );
2305 g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(maps_layer_download_new_onscreen_maps), values );
2306 gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
2307 gtk_widget_show ( item );
2310 item = gtk_image_menu_item_new_with_mnemonic ( _("Reload _All Onscreen Maps") );
2311 gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_REFRESH, GTK_ICON_SIZE_MENU) );
2312 g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(maps_layer_redownload_all_onscreen_maps), values );
2313 gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
2314 gtk_widget_show ( item );
2316 item = gtk_image_menu_item_new_with_mnemonic ( _("Download Maps in _Zoom Levels...") );
2317 gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_DND_MULTIPLE, GTK_ICON_SIZE_MENU) );
2318 g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(maps_layer_download_all), values );
2319 gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
2320 gtk_widget_show ( item );
2322 item = gtk_image_menu_item_new_from_stock ( GTK_STOCK_ABOUT, NULL );
2323 g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(maps_layer_about), values );
2324 gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
2325 gtk_widget_show ( item );
2329 * Enable downloading maps of the current screen area either 'new' or 'everything'
2331 void vik_maps_layer_download ( VikMapsLayer *vml, VikViewport *vvp, gboolean only_new )
2336 static menu_array_values values;
2337 values[MA_VML] = vml;
2338 values[MA_VVP] = vvp;
2341 // Get only new maps
2342 maps_layer_download_new_onscreen_maps ( values );
2344 // Redownload everything
2345 maps_layer_redownload_all_onscreen_maps ( values );