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"
63 #define VIK_SETTINGS_MAP_MAX_TILES "maps_max_tiles"
64 static gint MAX_TILES = 1000;
66 #define VIK_SETTINGS_MAP_MIN_SHRINKFACTOR "maps_min_shrinkfactor"
67 #define VIK_SETTINGS_MAP_MAX_SHRINKFACTOR "maps_max_shrinkfactor"
68 static gdouble MAX_SHRINKFACTOR = 8.0000001; /* zoom 1 viewing 8-tiles */
69 static gdouble MIN_SHRINKFACTOR = 0.0312499; /* zoom 32 viewing 1-tiles */
71 #define VIK_SETTINGS_MAP_REAL_MIN_SHRINKFACTOR "maps_real_min_shrinkfactor"
72 static gdouble REAL_MIN_SHRINKFACTOR = 0.0039062499; /* if shrinkfactor is between MAX and REAL_MAX, will only check for existence */
74 /****** MAP TYPES ******/
76 static GList *__map_types = NULL;
78 #define NUM_MAP_TYPES g_list_length(__map_types)
80 /* List of label for each map type */
81 static gchar **params_maptypes = NULL;
83 /* Corresponding IDS. (Cf. field uniq_id in VikMapsLayer struct) */
84 static guint *params_maptypes_ids = NULL;
86 /******** MAPZOOMS *********/
88 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 };
89 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 };
90 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 };
92 #define NUM_MAPZOOMS (sizeof(params_mapzooms)/sizeof(params_mapzooms[0]) - 1)
94 /**************************/
97 static void maps_layer_post_read (VikLayer *vl, VikViewport *vp, gboolean from_file);
98 static const gchar* maps_layer_tooltip ( VikMapsLayer *vml );
99 static void maps_layer_marshall( VikMapsLayer *vml, guint8 **data, gint *len );
100 static VikMapsLayer *maps_layer_unmarshall( guint8 *data, gint len, VikViewport *vvp );
101 static gboolean maps_layer_set_param ( VikMapsLayer *vml, guint16 id, VikLayerParamData data, VikViewport *vvp, gboolean is_file_operation );
102 static VikLayerParamData maps_layer_get_param ( VikMapsLayer *vml, guint16 id, gboolean is_file_operation );
103 static void maps_layer_change_param ( GtkWidget *widget, ui_change_values values );
104 static void maps_layer_draw ( VikMapsLayer *vml, VikViewport *vvp );
105 static VikMapsLayer *maps_layer_new ( VikViewport *vvp );
106 static void maps_layer_free ( VikMapsLayer *vml );
107 static gboolean maps_layer_download_release ( VikMapsLayer *vml, GdkEventButton *event, VikViewport *vvp );
108 static gboolean maps_layer_download_click ( VikMapsLayer *vml, GdkEventButton *event, VikViewport *vvp );
109 static gpointer maps_layer_download_create ( VikWindow *vw, VikViewport *vvp );
110 static void maps_layer_set_cache_dir ( VikMapsLayer *vml, const gchar *dir );
111 static void start_download_thread ( VikMapsLayer *vml, VikViewport *vvp, const VikCoord *ul, const VikCoord *br, gint redownload );
112 static void maps_layer_add_menu_items ( VikMapsLayer *vml, GtkMenu *menu, VikLayersPanel *vlp );
113 static guint map_uniq_id_to_index ( guint uniq_id );
116 static VikLayerParamScale params_scales[] = {
117 /* min, max, step, digits (decimal places) */
118 { 0, 255, 3, 0 }, /* alpha */
121 static VikLayerParamData id_default ( void ) { return VIK_LPD_UINT ( 19 ); } // OSM MapQuest maps
122 static VikLayerParamData directory_default ( void )
124 VikLayerParamData data;
125 VikLayerParamData *pref = a_preferences_get(VIKING_PREFERENCES_NAMESPACE "maplayer_default_dir");
126 if (pref) data.s = g_strdup ( pref->s ); else data.s = "";
129 static VikLayerParamData file_default ( void )
131 VikLayerParamData data;
135 static VikLayerParamData alpha_default ( void ) { return VIK_LPD_UINT ( 255 ); }
136 static VikLayerParamData mapzoom_default ( void ) { return VIK_LPD_UINT ( 0 ); }
138 static gchar *cache_types[] = { "Viking", N_("OSM"), NULL };
139 static VikMapsCacheLayout cache_layout_default_value = VIK_MAPS_CACHE_LAYOUT_VIKING;
140 static VikLayerParamData cache_layout_default ( void ) { return VIK_LPD_UINT ( cache_layout_default_value ); }
142 VikLayerParam maps_layer_params[] = {
143 // NB mode => id - But can't break file format just to rename something better
144 { 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 },
145 { 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 },
146 { VIK_LAYER_MAPS, "cache_type", VIK_LAYER_PARAM_UINT, VIK_LAYER_GROUP_NONE, N_("Cache Layout:"), VIK_LAYER_WIDGET_COMBOBOX, cache_types, NULL,
147 N_("This determines the tile storage layout on disk"), cache_layout_default, NULL, NULL },
148 { 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,
149 N_("An MBTiles file. Only applies when the map type method is 'MBTiles'"), file_default, NULL, NULL },
150 { VIK_LAYER_MAPS, "alpha", VIK_LAYER_PARAM_UINT, VIK_LAYER_GROUP_NONE, N_("Alpha:"), VIK_LAYER_WIDGET_HSCALE, params_scales, NULL,
151 N_("Control the Alpha value for transparency effects"), alpha_default, NULL, NULL },
152 { 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 },
153 { VIK_LAYER_MAPS, "adlonlymissing", VIK_LAYER_PARAM_BOOLEAN, VIK_LAYER_GROUP_NONE, N_("Autodownload Only Gets Missing Maps:"), VIK_LAYER_WIDGET_CHECKBUTTON, NULL, NULL,
154 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 },
155 { VIK_LAYER_MAPS, "mapzoom", VIK_LAYER_PARAM_UINT, VIK_LAYER_GROUP_NONE, N_("Zoom Level:"), VIK_LAYER_WIDGET_COMBOBOX, params_mapzooms, NULL,
156 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."),
157 mapzoom_default, NULL, NULL },
172 void maps_layer_set_autodownload_default ( gboolean autodownload )
174 // Set appropriate function
176 maps_layer_params[PARAM_AUTODOWNLOAD].default_value = vik_lpd_true_default;
178 maps_layer_params[PARAM_AUTODOWNLOAD].default_value = vik_lpd_false_default;
181 void maps_layer_set_cache_default ( VikMapsCacheLayout layout )
183 // Override default value returned by the default param function
184 cache_layout_default_value = layout;
187 static VikToolInterface maps_tools[] = {
188 { { "MapsDownload", "vik-icon-Maps Download", N_("_Maps Download"), NULL, N_("Maps Download"), 0 },
189 (VikToolConstructorFunc) maps_layer_download_create,
193 (VikToolMouseFunc) maps_layer_download_click,
195 (VikToolMouseFunc) maps_layer_download_release,
198 GDK_CURSOR_IS_PIXMAP, &cursor_mapdl_pixbuf, NULL },
201 VikLayerInterface vik_maps_layer_interface = {
205 &vikmapslayer_pixbuf,
208 sizeof(maps_tools) / sizeof(maps_tools[0]),
217 (VikLayerFuncCreate) maps_layer_new,
218 (VikLayerFuncRealize) NULL,
219 (VikLayerFuncPostRead) maps_layer_post_read,
220 (VikLayerFuncFree) maps_layer_free,
222 (VikLayerFuncProperties) NULL,
223 (VikLayerFuncDraw) maps_layer_draw,
224 (VikLayerFuncChangeCoordMode) NULL,
226 (VikLayerFuncSetMenuItemsSelection) NULL,
227 (VikLayerFuncGetMenuItemsSelection) NULL,
229 (VikLayerFuncAddMenuItems) maps_layer_add_menu_items,
230 (VikLayerFuncSublayerAddMenuItems) NULL,
232 (VikLayerFuncSublayerRenameRequest) NULL,
233 (VikLayerFuncSublayerToggleVisible) NULL,
234 (VikLayerFuncSublayerTooltip) NULL,
235 (VikLayerFuncLayerTooltip) maps_layer_tooltip,
236 (VikLayerFuncLayerSelected) NULL,
238 (VikLayerFuncMarshall) maps_layer_marshall,
239 (VikLayerFuncUnmarshall) maps_layer_unmarshall,
241 (VikLayerFuncSetParam) maps_layer_set_param,
242 (VikLayerFuncGetParam) maps_layer_get_param,
243 (VikLayerFuncChangeParam) maps_layer_change_param,
245 (VikLayerFuncReadFileData) NULL,
246 (VikLayerFuncWriteFileData) NULL,
248 (VikLayerFuncDeleteItem) NULL,
249 (VikLayerFuncCutItem) NULL,
250 (VikLayerFuncCopyItem) NULL,
251 (VikLayerFuncPasteItem) NULL,
252 (VikLayerFuncFreeCopiedItem) NULL,
253 (VikLayerFuncDragDropRequest) NULL,
255 (VikLayerFuncSelectClick) NULL,
256 (VikLayerFuncSelectMove) NULL,
257 (VikLayerFuncSelectRelease) NULL,
258 (VikLayerFuncSelectedViewportMenu) NULL,
261 struct _VikMapsLayer {
265 VikMapsCacheLayout cache_layout;
268 gdouble xmapzoom, ymapzoom;
270 gboolean autodownload;
271 gboolean adl_only_missing;
272 VikCoord *last_center;
276 gint dl_tool_x, dl_tool_y;
278 GtkMenu *dl_right_click_menu;
279 VikCoord redownload_ul, redownload_br; /* right click menu only */
280 VikViewport *redownload_vvp;
282 #ifdef HAVE_SQLITE3_H
287 enum { REDOWNLOAD_NONE = 0, /* download only missing maps */
288 REDOWNLOAD_BAD, /* download missing and bad maps */
289 REDOWNLOAD_NEW, /* download missing maps that are newer on server only */
290 REDOWNLOAD_ALL, /* download all maps */
291 DOWNLOAD_OR_REFRESH }; /* download missing maps and refresh cache */
293 static VikLayerParam prefs[] = {
294 { 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 },
297 void maps_layer_init ()
299 VikLayerParamData tmp;
300 tmp.s = maps_layer_default_dir();
301 a_preferences_register(prefs, tmp, VIKING_PREFERENCES_GROUP_KEY);
303 gint max_tiles = MAX_TILES;
304 if ( a_settings_get_integer ( VIK_SETTINGS_MAP_MAX_TILES, &max_tiles ) )
305 MAX_TILES = max_tiles;
308 if ( a_settings_get_double ( VIK_SETTINGS_MAP_MIN_SHRINKFACTOR, &gdtmp ) )
309 MIN_SHRINKFACTOR = gdtmp;
311 if ( a_settings_get_double ( VIK_SETTINGS_MAP_MAX_SHRINKFACTOR, &gdtmp ) )
312 MAX_SHRINKFACTOR = gdtmp;
314 if ( a_settings_get_double ( VIK_SETTINGS_MAP_REAL_MIN_SHRINKFACTOR, &gdtmp ) )
315 REAL_MIN_SHRINKFACTOR = gdtmp;
318 /****************************************/
319 /******** MAPS LAYER TYPES **************/
320 /****************************************/
322 void _add_map_source ( guint16 id, const char *label, VikMapSource *map )
326 len = g_strv_length (params_maptypes);
328 params_maptypes = g_realloc (params_maptypes, (len+2)*sizeof(gchar*));
329 params_maptypes[len] = g_strdup (label);
330 params_maptypes[len+1] = NULL;
333 params_maptypes_ids = g_realloc (params_maptypes_ids, (len+2)*sizeof(guint));
334 params_maptypes_ids[len] = id;
335 params_maptypes_ids[len+1] = 0;
337 /* We have to clone */
338 VikMapSource *clone = VIK_MAP_SOURCE(g_object_ref(map));
339 /* Register the clone in the list */
340 __map_types = g_list_append(__map_types, clone);
343 We have to ensure the mode LayerParam references the up-to-date
347 memcpy(&maps_layer_params[0].widget_data, ¶ms_maptypes, sizeof(gpointer));
348 memcpy(&maps_layer_params[0].extra_widget_data, ¶ms_maptypes_ids, sizeof(gpointer));
350 maps_layer_params[0].widget_data = params_maptypes;
351 maps_layer_params[0].extra_widget_data = params_maptypes_ids;
354 void _update_map_source ( const char *label, VikMapSource *map, int index )
356 GList *item = g_list_nth (__map_types, index);
357 g_object_unref (item->data);
358 item->data = g_object_ref (map);
359 /* Change previous data */
360 g_free (params_maptypes[index]);
361 params_maptypes[index] = g_strdup (label);
365 * maps_layer_register_map_source:
366 * @map: the new VikMapSource
368 * Register a new VikMapSource.
369 * Override existing one (equality of id).
371 void maps_layer_register_map_source ( VikMapSource *map )
373 g_assert(map != NULL);
375 guint16 id = vik_map_source_get_uniq_id(map);
376 const char *label = vik_map_source_get_label(map);
377 g_assert(label != NULL);
379 int previous = map_uniq_id_to_index (id);
380 if (previous != NUM_MAP_TYPES)
382 _update_map_source (label, map, previous);
386 _add_map_source (id, label, map);
390 #define MAPS_LAYER_NTH_LABEL(n) (params_maptypes[n])
391 #define MAPS_LAYER_NTH_ID(n) (params_maptypes_ids[n])
392 #define MAPS_LAYER_NTH_TYPE(n) (VIK_MAP_SOURCE(g_list_nth_data(__map_types, (n))))
394 gint vik_maps_layer_get_map_type(VikMapsLayer *vml)
396 return(vml->maptype);
399 gchar *vik_maps_layer_get_map_label(VikMapsLayer *vml)
401 return(g_strdup(MAPS_LAYER_NTH_LABEL(vml->maptype)));
404 /****************************************/
405 /******** CACHE DIR STUFF ***************/
406 /****************************************/
408 #define DIRECTDIRACCESS "%s%d" G_DIR_SEPARATOR_S "%d" G_DIR_SEPARATOR_S "%d%s"
409 #define DIRECTDIRACCESS_WITH_NAME "%s%s" G_DIR_SEPARATOR_S "%d" G_DIR_SEPARATOR_S "%d" G_DIR_SEPARATOR_S "%d%s"
410 #define DIRSTRUCTURE "%st%ds%dz%d" G_DIR_SEPARATOR_S "%d" G_DIR_SEPARATOR_S "%d"
411 #define MAPS_CACHE_DIR maps_layer_default_dir()
415 #define GLOBAL_MAPS_DIR "C:\\VIKING-MAPS\\"
416 #define LOCAL_MAPS_DIR "VIKING-MAPS"
417 #elif defined __APPLE__
419 #define GLOBAL_MAPS_DIR "/Library/cache/Viking/maps/"
420 #define LOCAL_MAPS_DIR "/Library/Application Support/Viking/viking-maps"
423 #define GLOBAL_MAPS_DIR "/var/cache/maps/"
424 #define LOCAL_MAPS_DIR ".viking-maps"
427 gchar *maps_layer_default_dir ()
429 static gchar *defaultdir = NULL;
432 /* Thanks to Mike Davison for the $VIKING_MAPS usage */
433 const gchar *mapdir = g_getenv("VIKING_MAPS");
435 defaultdir = g_strdup ( mapdir );
436 } else if ( g_access ( GLOBAL_MAPS_DIR, W_OK ) == 0 ) {
437 defaultdir = g_strdup ( GLOBAL_MAPS_DIR );
439 const gchar *home = g_get_home_dir();
440 if (!home || g_access(home, W_OK))
441 home = g_get_home_dir ();
443 defaultdir = g_build_filename ( home, LOCAL_MAPS_DIR, NULL );
445 defaultdir = g_strdup ( LOCAL_MAPS_DIR );
447 if (defaultdir && (defaultdir[strlen(defaultdir)-1] != G_DIR_SEPARATOR))
449 /* Add the separator at the end */
450 gchar *tmp = defaultdir;
451 defaultdir = g_strconcat(tmp, G_DIR_SEPARATOR_S, NULL);
454 g_debug("%s: defaultdir=%s", __FUNCTION__, defaultdir);
459 static void maps_layer_mkdir_if_default_dir ( VikMapsLayer *vml )
461 if ( vml->cache_dir && strcmp ( vml->cache_dir, MAPS_CACHE_DIR ) == 0 && g_file_test ( vml->cache_dir, G_FILE_TEST_EXISTS ) == FALSE )
463 g_mkdir ( vml->cache_dir, 0777 );
467 static void maps_layer_set_cache_dir ( VikMapsLayer *vml, const gchar *dir )
469 g_assert ( vml != NULL);
470 g_free ( vml->cache_dir );
471 vml->cache_dir = NULL;
472 const gchar *mydir = dir;
474 if ( dir == NULL || dir[0] == '\0' )
476 if ( a_preferences_get(VIKING_PREFERENCES_NAMESPACE "maplayer_default_dir") )
477 mydir = a_preferences_get(VIKING_PREFERENCES_NAMESPACE "maplayer_default_dir")->s;
480 gchar *canonical_dir = vu_get_canonical_filename ( VIK_LAYER(vml), mydir );
482 // Ensure cache_dir always ends with a separator
483 guint len = strlen(canonical_dir);
484 if ( canonical_dir[len-1] != G_DIR_SEPARATOR )
486 vml->cache_dir = g_strconcat ( canonical_dir, G_DIR_SEPARATOR_S, NULL );
487 g_free ( canonical_dir );
490 vml->cache_dir = canonical_dir;
493 maps_layer_mkdir_if_default_dir ( vml );
496 static void maps_layer_set_file ( VikMapsLayer *vml, const gchar *name )
499 g_free (vml->filename);
500 vml->filename = g_strdup (name);
503 /****************************************/
504 /******** GOBJECT STUFF *****************/
505 /****************************************/
507 GType vik_maps_layer_get_type ()
509 static GType vml_type = 0;
513 static const GTypeInfo vml_info =
515 sizeof (VikMapsLayerClass),
516 NULL, /* base_init */
517 NULL, /* base_finalize */
518 NULL, /* class init */
519 NULL, /* class_finalize */
520 NULL, /* class_data */
521 sizeof (VikMapsLayer),
523 NULL /* instance init */
525 vml_type = g_type_register_static ( VIK_LAYER_TYPE, "VikMapsLayer", &vml_info, 0 );
531 /****************************************/
532 /************** PARAMETERS **************/
533 /****************************************/
535 static guint map_index_to_uniq_id (guint16 index)
537 g_assert ( index < NUM_MAP_TYPES );
538 return vik_map_source_get_uniq_id(MAPS_LAYER_NTH_TYPE(index));
541 static guint map_uniq_id_to_index ( guint uniq_id )
544 for ( i = 0; i < NUM_MAP_TYPES; i++ )
545 if ( vik_map_source_get_uniq_id(MAPS_LAYER_NTH_TYPE(i)) == uniq_id )
547 return NUM_MAP_TYPES; /* no such thing */
550 #define VIK_SETTINGS_MAP_LICENSE_SHOWN "map_license_shown"
553 * Convenience function to display the license
555 static void maps_show_license ( GtkWindow *parent, VikMapSource *map )
557 a_dialog_license ( parent,
558 vik_map_source_get_label (map),
559 vik_map_source_get_license (map),
560 vik_map_source_get_license_url (map) );
563 static gboolean maps_layer_set_param ( VikMapsLayer *vml, guint16 id, VikLayerParamData data, VikViewport *vvp, gboolean is_file_operation )
567 case PARAM_CACHE_DIR: maps_layer_set_cache_dir ( vml, data.s ); break;
568 case PARAM_CACHE_LAYOUT: if ( data.u < VIK_MAPS_CACHE_LAYOUT_NUM ) vml->cache_layout = data.u; break;
569 case PARAM_FILE: maps_layer_set_file ( vml, data.s ); break;
570 case PARAM_MAPTYPE: {
571 gint maptype = map_uniq_id_to_index(data.u);
572 if ( maptype == NUM_MAP_TYPES )
573 g_warning(_("Unknown map type"));
575 vml->maptype = maptype;
577 // When loading from a file don't need the license reminder - ensure it's saved into the 'seen' list
578 if ( is_file_operation ) {
579 a_settings_set_integer_list_containing ( VIK_SETTINGS_MAP_LICENSE_SHOWN, data.u );
582 VikMapSource *map = MAPS_LAYER_NTH_TYPE(vml->maptype);
583 if (vik_map_source_get_license (map) != NULL) {
584 // Check if licence for this map type has been shown before
585 if ( ! a_settings_get_integer_list_contains ( VIK_SETTINGS_MAP_LICENSE_SHOWN, data.u ) ) {
587 maps_show_license ( VIK_GTK_WINDOW_FROM_WIDGET(vvp), map );
588 a_settings_set_integer_list_containing ( VIK_SETTINGS_MAP_LICENSE_SHOWN, data.u );
595 case PARAM_ALPHA: if ( data.u <= 255 ) vml->alpha = data.u; break;
596 case PARAM_AUTODOWNLOAD: vml->autodownload = data.b; break;
597 case PARAM_ONLYMISSING: vml->adl_only_missing = data.b; break;
598 case PARAM_MAPZOOM: if ( data.u < NUM_MAPZOOMS ) {
599 vml->mapzoom_id = data.u;
600 vml->xmapzoom = __mapzooms_x [data.u];
601 vml->ymapzoom = __mapzooms_y [data.u];
602 }else g_warning (_("Unknown Map Zoom")); break;
608 static VikLayerParamData maps_layer_get_param ( VikMapsLayer *vml, guint16 id, gboolean is_file_operation )
610 VikLayerParamData rv;
613 case PARAM_CACHE_DIR:
615 gboolean set = FALSE;
616 /* Only save a blank when the map cache location equals the default
617 On reading in, when it is blank then the default is reconstructed
618 Since the default changes dependent on the user and OS, it means the resultant file is more portable */
619 if ( is_file_operation && vml->cache_dir && strcmp ( vml->cache_dir, MAPS_CACHE_DIR ) == 0 ) {
623 else if ( is_file_operation ) {
624 if ( a_vik_get_file_ref_format() == VIK_FILE_REF_FORMAT_RELATIVE ) {
625 gchar *cwd = g_get_current_dir();
627 rv.s = file_GetRelativeFilename ( cwd, vml->cache_dir );
628 if ( !rv.s ) rv.s = "";
634 rv.s = vml->cache_dir ? vml->cache_dir : "";
637 case PARAM_CACHE_LAYOUT: rv.u = vml->cache_layout; break;
638 case PARAM_FILE: rv.s = vml->filename; break;
639 case PARAM_MAPTYPE: rv.u = map_index_to_uniq_id ( vml->maptype ); break;
640 case PARAM_ALPHA: rv.u = vml->alpha; break;
641 case PARAM_AUTODOWNLOAD: rv.u = vml->autodownload; break;
642 case PARAM_ONLYMISSING: rv.u = vml->adl_only_missing; break;
643 case PARAM_MAPZOOM: rv.u = vml->mapzoom_id; break;
649 static void maps_layer_change_param ( GtkWidget *widget, ui_change_values values )
651 switch ( GPOINTER_TO_INT(values[UI_CHG_PARAM_ID]) ) {
652 // Alter sensitivity of download option widgets according to the maptype setting.
653 case PARAM_MAPTYPE: {
655 VikLayerParamData vlpd = a_uibuilder_widget_get_value ( widget, values[UI_CHG_PARAM] );
656 // Is it *not* the OSM On Disk Tile Layout or the MBTiles type or the OSM Metatiles type
657 gboolean sensitive = ( 21 != vlpd.u && 23 != vlpd.u && 24 != vlpd.u );
658 GtkWidget **ww1 = values[UI_CHG_WIDGETS];
659 GtkWidget **ww2 = values[UI_CHG_LABELS];
660 GtkWidget *w1 = ww1[PARAM_ONLYMISSING];
661 GtkWidget *w2 = ww2[PARAM_ONLYMISSING];
662 GtkWidget *w3 = ww1[PARAM_AUTODOWNLOAD];
663 GtkWidget *w4 = ww2[PARAM_AUTODOWNLOAD];
664 // Depends on autodownload value
665 gboolean missing_sense = sensitive && VIK_MAPS_LAYER(values[UI_CHG_LAYER])->autodownload;
666 if ( w1 ) gtk_widget_set_sensitive ( w1, missing_sense );
667 if ( w2 ) gtk_widget_set_sensitive ( w2, missing_sense );
668 if ( w3 ) gtk_widget_set_sensitive ( w3, sensitive );
669 if ( w4 ) gtk_widget_set_sensitive ( w4, sensitive );
671 // Cache type not applicable either
672 GtkWidget *w9 = ww1[PARAM_CACHE_LAYOUT];
673 GtkWidget *w10 = ww2[PARAM_CACHE_LAYOUT];
674 if ( w9 ) gtk_widget_set_sensitive ( w9, sensitive );
675 if ( w10 ) gtk_widget_set_sensitive ( w10, sensitive );
677 // File only applicable for MBTiles type
678 // Directory for all other types
679 sensitive = ( 23 == vlpd.u);
680 GtkWidget *w5 = ww1[PARAM_FILE];
681 GtkWidget *w6 = ww2[PARAM_FILE];
682 GtkWidget *w7 = ww1[PARAM_CACHE_DIR];
683 GtkWidget *w8 = ww2[PARAM_CACHE_DIR];
684 if ( w5 ) gtk_widget_set_sensitive ( w5, sensitive );
685 if ( w6 ) gtk_widget_set_sensitive ( w6, sensitive );
686 if ( w7 ) gtk_widget_set_sensitive ( w7, !sensitive );
687 if ( w8 ) gtk_widget_set_sensitive ( w8, !sensitive );
692 // Alter sensitivity of 'download only missing' widgets according to the autodownload setting.
693 case PARAM_AUTODOWNLOAD: {
695 VikLayerParamData vlpd = a_uibuilder_widget_get_value ( widget, values[UI_CHG_PARAM] );
696 GtkWidget **ww1 = values[UI_CHG_WIDGETS];
697 GtkWidget **ww2 = values[UI_CHG_LABELS];
698 GtkWidget *w1 = ww1[PARAM_ONLYMISSING];
699 GtkWidget *w2 = ww2[PARAM_ONLYMISSING];
700 if ( w1 ) gtk_widget_set_sensitive ( w1, vlpd.b );
701 if ( w2 ) gtk_widget_set_sensitive ( w2, vlpd.b );
708 /****************************************/
709 /****** CREATING, COPYING, FREEING ******/
710 /****************************************/
712 static VikMapsLayer *maps_layer_new ( VikViewport *vvp )
714 VikMapsLayer *vml = VIK_MAPS_LAYER ( g_object_new ( VIK_MAPS_LAYER_TYPE, NULL ) );
715 vik_layer_set_type ( VIK_LAYER(vml), VIK_LAYER_MAPS );
717 vik_layer_set_defaults ( VIK_LAYER(vml), vvp );
719 vml->dl_tool_x = vml->dl_tool_y = -1;
720 vml->last_center = NULL;
721 vml->last_xmpp = 0.0;
722 vml->last_ympp = 0.0;
724 vml->dl_right_click_menu = NULL;
725 vml->filename = NULL;
729 static void maps_layer_free ( VikMapsLayer *vml )
731 g_free ( vml->cache_dir );
732 vml->cache_dir = NULL;
733 if ( vml->dl_right_click_menu )
734 g_object_ref_sink ( G_OBJECT(vml->dl_right_click_menu) );
735 g_free(vml->last_center);
736 vml->last_center = NULL;
737 g_free ( vml->filename );
738 vml->filename = NULL;
740 #ifdef HAVE_SQLITE3_H
741 VikMapSource *map = MAPS_LAYER_NTH_TYPE(vml->maptype);
742 if ( vik_map_source_is_mbtiles ( map ) ) {
743 if ( vml->mbtiles ) {
744 int ans = sqlite3_close ( vml->mbtiles );
745 if ( ans != SQLITE_OK ) {
746 // Only to console for information purposes only
747 g_warning ( "SQL Close problem: %d", ans );
754 static void maps_layer_post_read (VikLayer *vl, VikViewport *vp, gboolean from_file)
756 VikMapsLayer *vml = VIK_MAPS_LAYER(vl);
757 VikMapSource *map = MAPS_LAYER_NTH_TYPE(vml->maptype);
759 if (from_file != TRUE)
761 /* If this method is not called in file reading context
762 * it is called in GUI context.
763 * So, we can check if we have to inform the user about inconsistency */
764 VikViewportDrawMode vp_drawmode;
765 vp_drawmode = vik_viewport_get_drawmode ( vp );
767 if (vik_map_source_get_drawmode(map) != vp_drawmode) {
768 const gchar *drawmode_name = vik_viewport_get_drawmode_name (vp, vik_map_source_get_drawmode(map));
769 gchar *msg = g_strdup_printf(_("New map cannot be displayed in the current drawmode.\nSelect \"%s\" from View menu to view it."), drawmode_name);
770 a_dialog_warning_msg ( VIK_GTK_WINDOW_FROM_WIDGET(vp), msg );
775 // Performed in post read as we now know the map type
776 #ifdef HAVE_SQLITE3_H
778 if ( vik_map_source_is_mbtiles ( map ) ) {
779 int ans = sqlite3_open_v2 ( vml->filename,
781 SQLITE_OPEN_READONLY,
783 if ( ans != SQLITE_OK ) {
784 // That didn't work, so here's why:
785 g_warning ( "%s: %s", __FUNCTION__, sqlite3_errmsg ( vml->mbtiles ) );
787 a_dialog_error_msg_extra ( VIK_GTK_WINDOW_FROM_WIDGET(vp),
788 _("Failed to open MBTiles file: %s"),
795 // If the on Disk OSM Tile Layout type
796 if ( vml->maptype == 21 )
797 // Copy the directory into filename
798 // thus the mapcache look up will be unique when using more than one of these map types
799 vml->filename = g_strdup (vml->cache_dir);
802 static const gchar* maps_layer_tooltip ( VikMapsLayer *vml )
804 return vik_maps_layer_get_map_label ( vml );
807 static void maps_layer_marshall( VikMapsLayer *vml, guint8 **data, gint *len )
809 vik_layer_marshall_params ( VIK_LAYER(vml), data, len );
812 static VikMapsLayer *maps_layer_unmarshall( guint8 *data, gint len, VikViewport *vvp )
814 VikMapsLayer *rv = maps_layer_new ( vvp );
815 vik_layer_unmarshall_params ( VIK_LAYER(rv), data, len, vvp );
819 /*********************/
820 /****** DRAWING ******/
821 /*********************/
823 static GdkPixbuf *pixbuf_set_alpha ( GdkPixbuf *pixbuf, guint8 alpha )
826 gint width, height, iii, jjj;
828 if ( ! gdk_pixbuf_get_has_alpha ( pixbuf ) )
830 GdkPixbuf *tmp = gdk_pixbuf_add_alpha(pixbuf,FALSE,0,0,0);
831 g_object_unref(G_OBJECT(pixbuf));
837 pixels = gdk_pixbuf_get_pixels(pixbuf);
838 width = gdk_pixbuf_get_width(pixbuf);
839 height = gdk_pixbuf_get_height(pixbuf);
841 /* r,g,b,a,r,g,b,a.... */
842 for (iii = 0; iii < width; iii++) for (jjj = 0; jjj < height; jjj++)
850 static GdkPixbuf *pixbuf_shrink ( GdkPixbuf *pixbuf, gdouble xshrinkfactor, gdouble yshrinkfactor )
853 guint16 width = gdk_pixbuf_get_width(pixbuf), height = gdk_pixbuf_get_height(pixbuf);
854 tmp = gdk_pixbuf_scale_simple(pixbuf, ceil(width * xshrinkfactor), ceil(height * yshrinkfactor), GDK_INTERP_BILINEAR);
855 g_object_unref ( G_OBJECT(pixbuf) );
859 #ifdef HAVE_SQLITE3_H
861 static int sql_select_tile_dump_cb (void *data, int cols, char **fields, char **col_names )
863 g_warning ( "Found %d columns", cols );
865 for ( i = 0; i < cols; i++ ) {
866 g_warning ( "SQL processing %s = %s", col_names[i], fields[i] );
875 static GdkPixbuf *get_pixbuf_sql_exec ( sqlite3 *sql, gint xx, gint yy, gint zoom )
877 GdkPixbuf *pixbuf = NULL;
879 // MBTiles stored internally with the flipping y thingy (i.e. TMS scheme).
880 gint flip_y = (gint) pow(2, zoom)-1 - yy;
881 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 );
883 gboolean finished = FALSE;
885 sqlite3_stmt *sql_stmt = NULL;
886 int ans = sqlite3_prepare_v2 ( sql, statement, -1, &sql_stmt, NULL );
887 if ( ans != SQLITE_OK ) {
888 g_warning ( "%s: %s - %d", __FUNCTION__, "prepare failure", ans );
892 while ( !finished ) {
893 ans = sqlite3_step ( sql_stmt );
896 // Get tile_data blob
897 int count = sqlite3_column_count(sql_stmt);
899 g_warning ( "%s: %s - %d", __FUNCTION__, "count not one", count );
903 const void *data = sqlite3_column_blob ( sql_stmt, 0 );
904 int bytes = sqlite3_column_bytes ( sql_stmt, 0 );
906 g_warning ( "%s: %s (%d)", __FUNCTION__, "not enough bytes", bytes );
910 // Convert these blob bytes into a pixbuf via these streaming operations
911 GInputStream *stream = g_memory_input_stream_new_from_data ( data, bytes, NULL );
912 GError *error = NULL;
913 pixbuf = gdk_pixbuf_new_from_stream ( stream, NULL, &error );
914 if (error || (!pixbuf)) {
915 g_warning ( "%s: %s", __FUNCTION__, error->message );
916 g_error_free ( error );
918 g_input_stream_close ( stream, NULL, NULL );
924 // e.g. SQLITE_DONE | SQLITE_ERROR | SQLITE_MISUSE | etc...
926 // and give up on any errors
927 if ( ans != SQLITE_DONE )
928 g_warning ( "%s: %s - %d", __FUNCTION__, "step issue", ans );
933 ans = sqlite3_finalize ( sql_stmt );
935 g_free ( statement );
941 static GdkPixbuf *get_mbtiles_pixbuf ( VikMapsLayer *vml, gint xx, gint yy, gint zoom )
943 GdkPixbuf *pixbuf = NULL;
945 #ifdef HAVE_SQLITE3_H
946 if ( vml->mbtiles ) {
948 gchar *statement = g_strdup_printf ( "SELECT name FROM sqlite_master WHERE type='table';" );
950 int ans = sqlite3_exec ( vml->mbtiles, statement, sql_select_tile_dump_cb, pixbuf, &errMsg );
951 if ( ans != SQLITE_OK ) {
952 // Only to console for information purposes only
953 g_warning ( "SQL problem: %d for %s - error: %s", ans, statement, errMsg );
954 sqlite3_free( errMsg );
956 g_free ( statement );
959 // Reading BLOBS is a bit more involved and so can't use the simpler sqlite3_exec ()
960 // Hence this specific function
961 pixbuf = get_pixbuf_sql_exec ( vml->mbtiles, xx, yy, zoom );
968 static GdkPixbuf *get_pixbuf_from_metatile ( VikMapsLayer *vml, gint xx, gint yy, gint zz )
970 const int tile_max = METATILE_MAX_SIZE;
971 char err_msg[PATH_MAX];
976 buf = malloc(tile_max);
982 len = metatile_read(vml->cache_dir, xx, yy, zz, buf, tile_max, &compressed, err_msg);
986 // Not handled yet - I don't think this is used often - so implement later if necessary
987 g_warning ( "Compressed metatiles not implemented:%s\n", __FUNCTION__);
991 // Convert these buf bytes into a pixbuf via these streaming operations
992 GdkPixbuf *pixbuf = NULL;
994 GInputStream *stream = g_memory_input_stream_new_from_data ( buf, len, NULL );
995 GError *error = NULL;
996 pixbuf = gdk_pixbuf_new_from_stream ( stream, NULL, &error );
997 if (error || (!pixbuf)) {
998 g_warning ( "%s: %s", __FUNCTION__, error->message );
999 g_error_free ( error );
1001 g_input_stream_close ( stream, NULL, NULL );
1007 g_warning ( "FAILED:%s %s", __FUNCTION__, err_msg);
1013 static GdkPixbuf *pixbuf_apply_settings ( GdkPixbuf *pixbuf, VikMapsLayer *vml, MapCoord *mapcoord, gdouble xshrinkfactor, gdouble yshrinkfactor )
1015 // Apply alpha setting
1016 if ( pixbuf && vml->alpha < 255 )
1017 pixbuf = pixbuf_set_alpha ( pixbuf, vml->alpha );
1019 if ( pixbuf && ( xshrinkfactor != 1.0 || yshrinkfactor != 1.0 ) )
1020 pixbuf = pixbuf_shrink ( pixbuf, xshrinkfactor, yshrinkfactor );
1023 a_mapcache_add ( pixbuf, mapcoord->x, mapcoord->y,
1024 mapcoord->z, vik_map_source_get_uniq_id(MAPS_LAYER_NTH_TYPE(vml->maptype)),
1025 mapcoord->scale, vml->alpha, xshrinkfactor, yshrinkfactor, vml->filename );
1030 static void get_filename ( const gchar *cache_dir,
1031 VikMapsCacheLayout cl,
1038 gchar *filename_buf,
1040 const gchar* file_extension )
1043 case VIK_MAPS_CACHE_LAYOUT_OSM:
1045 if ( g_strcmp0 ( cache_dir, MAPS_CACHE_DIR ) )
1046 // Cache dir not the default - assume it's been directed somewhere specific
1047 g_snprintf ( filename_buf, buf_len, DIRECTDIRACCESS, cache_dir, (17 - scale), x, y, file_extension );
1049 // Using default cache - so use the map name in the directory path
1050 g_snprintf ( filename_buf, buf_len, DIRECTDIRACCESS_WITH_NAME, cache_dir, name, (17 - scale), x, y, file_extension );
1053 g_snprintf ( filename_buf, buf_len, DIRECTDIRACCESS, cache_dir, (17 - scale), x, y, file_extension );
1056 g_snprintf ( filename_buf, buf_len, DIRSTRUCTURE, cache_dir, id, scale, z, x, y );
1061 static GdkPixbuf *get_pixbuf( VikMapsLayer *vml, guint16 id, const gchar* mapname, MapCoord *mapcoord, gchar *filename_buf, gint buf_len, gdouble xshrinkfactor, gdouble yshrinkfactor )
1066 pixbuf = a_mapcache_get ( mapcoord->x, mapcoord->y, mapcoord->z,
1067 id, mapcoord->scale, vml->alpha, xshrinkfactor, yshrinkfactor, vml->filename );
1070 VikMapSource *map = MAPS_LAYER_NTH_TYPE(vml->maptype);
1071 if ( vik_map_source_is_direct_file_access(map) ) {
1072 // ATM MBTiles must be 'a direct access type'
1073 if ( vik_map_source_is_mbtiles(map) ) {
1074 pixbuf = get_mbtiles_pixbuf ( vml, mapcoord->x, mapcoord->y, (17 - mapcoord->scale) );
1075 pixbuf = pixbuf_apply_settings ( pixbuf, vml, mapcoord, xshrinkfactor, yshrinkfactor );
1076 // return now to avoid file tests that aren't appropriate for this map type
1079 else if ( vik_map_source_is_osm_meta_tiles(map) ) {
1080 pixbuf = get_pixbuf_from_metatile ( vml, mapcoord->x, mapcoord->y, (17 - mapcoord->scale) );
1081 pixbuf = pixbuf_apply_settings ( pixbuf, vml, mapcoord, xshrinkfactor, yshrinkfactor );
1085 get_filename ( vml->cache_dir, VIK_MAPS_CACHE_LAYOUT_OSM, id, NULL,
1086 mapcoord->scale, mapcoord->z, mapcoord->x, mapcoord->y, filename_buf, buf_len,
1087 vik_map_source_get_file_extension(map) );
1090 get_filename ( vml->cache_dir, vml->cache_layout, id, mapname,
1091 mapcoord->scale, mapcoord->z, mapcoord->x, mapcoord->y, filename_buf, buf_len,
1092 vik_map_source_get_file_extension(map) );
1094 if ( g_file_test ( filename_buf, G_FILE_TEST_EXISTS ) == TRUE)
1097 pixbuf = gdk_pixbuf_new_from_file ( filename_buf, &gx );
1099 /* free the pixbuf on error */
1102 if ( gx->domain != GDK_PIXBUF_ERROR || gx->code != GDK_PIXBUF_ERROR_CORRUPT_IMAGE ) {
1104 if ( IS_VIK_WINDOW ((VikWindow*)VIK_GTK_WINDOW_FROM_LAYER(vml)) ) {
1105 gchar* msg = g_strdup_printf ( _("Couldn't open image file: %s"), gx->message );
1106 vik_window_statusbar_update ( (VikWindow*)VIK_GTK_WINDOW_FROM_LAYER(vml), msg, VIK_STATUSBAR_INFO );
1111 g_error_free ( gx );
1113 g_object_unref ( G_OBJECT(pixbuf) );
1116 pixbuf = pixbuf_apply_settings ( pixbuf, vml, mapcoord, xshrinkfactor, yshrinkfactor );
1123 static gboolean should_start_autodownload(VikMapsLayer *vml, VikViewport *vvp)
1125 const VikCoord *center = vik_viewport_get_center ( vvp );
1127 if (vik_window_get_pan_move (VIK_WINDOW(VIK_GTK_WINDOW_FROM_WIDGET(GTK_WIDGET(vvp)))))
1128 /* D'n'D pan in action: do not download */
1131 // Don't attempt to download unsupported zoom levels
1132 gdouble xzoom = vik_viewport_get_xmpp ( vvp );
1133 VikMapSource *map = MAPS_LAYER_NTH_TYPE(vml->maptype);
1134 guint8 zl = map_utils_mpp_to_zoom_level ( xzoom );
1135 if ( zl < vik_map_source_get_zoom_min(map) || zl > vik_map_source_get_zoom_max(map) )
1138 if (vml->last_center == NULL) {
1139 VikCoord *new_center = g_malloc(sizeof(VikCoord));
1140 *new_center = *center;
1141 vml->last_center = new_center;
1142 vml->last_xmpp = vik_viewport_get_xmpp(vvp);
1143 vml->last_ympp = vik_viewport_get_ympp(vvp);
1147 /* TODO: perhaps vik_coord_diff() */
1148 if (vik_coord_equals(vml->last_center, center)
1149 && (vml->last_xmpp == vik_viewport_get_xmpp(vvp))
1150 && (vml->last_ympp == vik_viewport_get_ympp(vvp)))
1153 *(vml->last_center) = *center;
1154 vml->last_xmpp = vik_viewport_get_xmpp(vvp);
1155 vml->last_ympp = vik_viewport_get_ympp(vvp);
1159 static void maps_layer_draw_section ( VikMapsLayer *vml, VikViewport *vvp, VikCoord *ul, VikCoord *br )
1162 gdouble xzoom = vik_viewport_get_xmpp ( vvp );
1163 gdouble yzoom = vik_viewport_get_ympp ( vvp );
1164 gdouble xshrinkfactor = 1.0, yshrinkfactor = 1.0;
1165 gboolean existence_only = FALSE;
1167 if ( vml->xmapzoom && (vml->xmapzoom != xzoom || vml->ymapzoom != yzoom) ) {
1168 xshrinkfactor = vml->xmapzoom / xzoom;
1169 yshrinkfactor = vml->ymapzoom / yzoom;
1170 xzoom = vml->xmapzoom;
1171 yzoom = vml->xmapzoom;
1172 if ( ! (xshrinkfactor > MIN_SHRINKFACTOR && xshrinkfactor < MAX_SHRINKFACTOR &&
1173 yshrinkfactor > MIN_SHRINKFACTOR && yshrinkfactor < MAX_SHRINKFACTOR ) ) {
1174 if ( xshrinkfactor > REAL_MIN_SHRINKFACTOR && yshrinkfactor > REAL_MIN_SHRINKFACTOR ) {
1175 g_debug ( "%s: existence_only due to SHRINKFACTORS", __FUNCTION__ );
1176 existence_only = TRUE;
1179 // Report the reason for not drawing
1180 if ( IS_VIK_WINDOW ((VikWindow*)VIK_GTK_WINDOW_FROM_LAYER(vml)) ) {
1181 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));
1182 vik_window_statusbar_update ( (VikWindow*)VIK_GTK_WINDOW_FROM_LAYER(vml), msg, VIK_STATUSBAR_INFO );
1191 VikMapSource *map = MAPS_LAYER_NTH_TYPE(vml->maptype);
1192 if ( vik_map_source_coord_to_mapcoord ( map, ul, xzoom, yzoom, &ulm ) &&
1193 vik_map_source_coord_to_mapcoord ( map, br, xzoom, yzoom, &brm ) ) {
1197 gint xmin = MIN(ulm.x, brm.x), xmax = MAX(ulm.x, brm.x);
1198 gint ymin = MIN(ulm.y, brm.y), ymax = MAX(ulm.y, brm.y);
1199 guint16 id = vik_map_source_get_uniq_id(map);
1200 const gchar *mapname = vik_map_source_get_name(map);
1203 gint xx, yy, width, height;
1206 // Prevent the program grinding to a halt if trying to deal with thousands of tiles
1207 // which can happen when using a small fixed zoom level and viewing large areas.
1208 // Also prevents very large number of tile download requests
1209 gint tiles = (xmax-xmin) * (ymax-ymin);
1210 if ( tiles > MAX_TILES ) {
1211 g_debug ( "%s: existence_only due to wanting too many tiles (%d)", __FUNCTION__, tiles );
1212 existence_only = TRUE;
1215 guint max_path_len = strlen(vml->cache_dir) + 40;
1216 gchar *path_buf = g_malloc ( max_path_len * sizeof(char) );
1218 if ( (!existence_only) && vml->autodownload && should_start_autodownload(vml, vvp)) {
1219 g_debug("%s: Starting autodownload", __FUNCTION__);
1220 if ( !vml->adl_only_missing && vik_map_source_supports_download_only_new (map) )
1221 // Try to download newer tiles
1222 start_download_thread ( vml, vvp, ul, br, REDOWNLOAD_NEW );
1224 // Download only missing tiles
1225 start_download_thread ( vml, vvp, ul, br, REDOWNLOAD_NONE );
1228 if ( vik_map_source_get_tilesize_x(map) == 0 && !existence_only ) {
1229 for ( x = xmin; x <= xmax; x++ ) {
1230 for ( y = ymin; y <= ymax; y++ ) {
1233 pixbuf = get_pixbuf ( vml, id, mapname, &ulm, path_buf, max_path_len, xshrinkfactor, yshrinkfactor );
1235 width = gdk_pixbuf_get_width ( pixbuf );
1236 height = gdk_pixbuf_get_height ( pixbuf );
1238 vik_map_source_mapcoord_to_center_coord ( map, &ulm, &coord );
1239 vik_viewport_coord_to_screen ( vvp, &coord, &xx, &yy );
1243 vik_viewport_draw_pixbuf ( vvp, pixbuf, 0, 0, xx, yy, width, height );
1247 } else { /* tilesize is known, don't have to keep converting coords */
1248 gdouble tilesize_x = vik_map_source_get_tilesize_x(map) * xshrinkfactor;
1249 gdouble tilesize_y = vik_map_source_get_tilesize_y(map) * yshrinkfactor;
1250 /* ceiled so tiles will be maximum size in the case of funky shrinkfactor */
1251 gint tilesize_x_ceil = ceil ( tilesize_x );
1252 gint tilesize_y_ceil = ceil ( tilesize_y );
1253 gint8 xinc = (ulm.x == xmin) ? 1 : -1;
1254 gint8 yinc = (ulm.y == ymin) ? 1 : -1;
1255 gint xx_tmp, yy_tmp;
1256 gint base_yy, xend, yend;
1258 xend = (xinc == 1) ? (xmax+1) : (xmin-1);
1259 yend = (yinc == 1) ? (ymax+1) : (ymin-1);
1261 vik_map_source_mapcoord_to_center_coord ( map, &ulm, &coord );
1262 vik_viewport_coord_to_screen ( vvp, &coord, &xx_tmp, &yy_tmp );
1263 xx = xx_tmp; yy = yy_tmp;
1264 /* above trick so xx,yy doubles. this is so shrinkfactors aren't rounded off
1265 * eg if tile size 128, shrinkfactor 0.333 */
1266 xx -= (tilesize_x/2);
1267 base_yy = yy - (tilesize_y/2);
1269 for ( x = ((xinc == 1) ? xmin : xmax); x != xend; x+=xinc ) {
1271 for ( y = ((yinc == 1) ? ymin : ymax); y != yend; y+=yinc ) {
1275 if ( existence_only ) {
1276 if ( vik_map_source_is_direct_file_access (MAPS_LAYER_NTH_TYPE(vml->maptype)) )
1277 get_filename ( vml->cache_dir, VIK_MAPS_CACHE_LAYOUT_OSM, id, vik_map_source_get_name(map),
1278 ulm.scale, ulm.z, ulm.x, ulm.y, path_buf, max_path_len, vik_map_source_get_file_extension(map) );
1280 get_filename ( vml->cache_dir, vml->cache_layout, id, vik_map_source_get_name(map),
1281 ulm.scale, ulm.z, ulm.x, ulm.y, path_buf, max_path_len, vik_map_source_get_file_extension(map) );
1283 if ( g_file_test ( path_buf, G_FILE_TEST_EXISTS ) == TRUE ) {
1284 GdkGC *black_gc = gtk_widget_get_style(GTK_WIDGET(vvp))->black_gc;
1285 vik_viewport_draw_line ( vvp, black_gc, xx+tilesize_x_ceil, yy, xx, yy+tilesize_y_ceil );
1289 for (scale_inc = 0; scale_inc < 4; scale_inc ++) {
1290 /* try with correct then smaller zooms */
1291 int scale_factor = 1 << scale_inc; /* 2^scale_inc */
1292 MapCoord ulm2 = ulm;
1293 ulm2.x = ulm.x / scale_factor;
1294 ulm2.y = ulm.y / scale_factor;
1295 ulm2.scale = ulm.scale + scale_inc;
1296 pixbuf = get_pixbuf ( vml, id, mapname, &ulm2, path_buf, max_path_len, xshrinkfactor * scale_factor, yshrinkfactor * scale_factor );
1298 gint src_x = (ulm.x % scale_factor) * tilesize_x_ceil;
1299 gint src_y = (ulm.y % scale_factor) * tilesize_y_ceil;
1301 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);
1303 vik_viewport_draw_pixbuf ( vvp, pixbuf, src_x, src_y, xx, yy, tilesize_x_ceil, tilesize_y_ceil );
1308 /* retry with bigger zooms */
1310 for (scale_dec = 1; scale_dec < 2; scale_dec ++) {
1312 int scale_factor = 1 << scale_dec; /* 2^scale_dec */
1313 MapCoord ulm2 = ulm;
1314 ulm2.x = ulm.x * scale_factor;
1315 ulm2.y = ulm.y * scale_factor;
1316 ulm2.scale = ulm.scale - scale_dec;
1317 for (pict_x = 0; pict_x < scale_factor; pict_x ++) {
1318 for (pict_y = 0; pict_y < scale_factor; pict_y ++) {
1319 MapCoord ulm3 = ulm2;
1322 pixbuf = get_pixbuf ( vml, id, mapname, &ulm3, path_buf, max_path_len, xshrinkfactor / scale_factor, yshrinkfactor / scale_factor );
1326 gint dest_x = xx + pict_x * (tilesize_x_ceil / scale_factor);
1327 gint dest_y = yy + pict_y * (tilesize_y_ceil / scale_factor);
1328 vik_viewport_draw_pixbuf ( vvp, pixbuf, src_x, src_y, dest_x, dest_y, tilesize_x_ceil / scale_factor, tilesize_y_ceil / scale_factor );
1342 g_free ( path_buf );
1346 static void maps_layer_draw ( VikMapsLayer *vml, VikViewport *vvp )
1348 if ( vik_map_source_get_drawmode(MAPS_LAYER_NTH_TYPE(vml->maptype)) == vik_viewport_get_drawmode ( vvp ) )
1353 gdouble level = vik_viewport_get_zoom ( vvp );
1355 vik_viewport_get_min_max_lat_lon ( vvp, &bbox.south, &bbox.north, &bbox.west, &bbox.east );
1356 vik_map_source_get_copyright ( MAPS_LAYER_NTH_TYPE(vml->maptype), bbox, level, vik_viewport_add_copyright, vvp );
1359 const GdkPixbuf *logo = vik_map_source_get_logo ( MAPS_LAYER_NTH_TYPE(vml->maptype) );
1360 vik_viewport_add_logo ( vvp, logo );
1362 /* get corner coords */
1363 if ( vik_viewport_get_coord_mode ( vvp ) == VIK_COORD_UTM && ! vik_viewport_is_one_zone ( vvp ) ) {
1364 /* UTM multi-zone stuff by Kit Transue */
1365 gchar leftmost_zone, rightmost_zone, i;
1366 leftmost_zone = vik_viewport_leftmost_zone( vvp );
1367 rightmost_zone = vik_viewport_rightmost_zone( vvp );
1368 for ( i = leftmost_zone; i <= rightmost_zone; ++i ) {
1369 vik_viewport_corners_for_zonen ( vvp, i, &ul, &br );
1370 maps_layer_draw_section ( vml, vvp, &ul, &br );
1374 vik_viewport_screen_to_coord ( vvp, 0, 0, &ul );
1375 vik_viewport_screen_to_coord ( vvp, vik_viewport_get_width(vvp), vik_viewport_get_height(vvp), &br );
1377 maps_layer_draw_section ( vml, vvp, &ul, &br );
1382 /*************************/
1383 /****** DOWNLOADING ******/
1384 /*************************/
1386 /* pass along data to thread, exists even if layer is deleted. */
1389 gchar *filename_buf;
1390 VikMapsCacheLayout cache_layout;
1391 gint x0, y0, xf, yf;
1397 gboolean refresh_display;
1400 gboolean map_layer_alive;
1404 static void mdi_free ( MapDownloadInfo *mdi )
1406 g_mutex_free(mdi->mutex);
1407 g_free ( mdi->cache_dir );
1408 mdi->cache_dir = NULL;
1409 g_free ( mdi->filename_buf );
1410 mdi->filename_buf = NULL;
1414 static void weak_ref_cb(gpointer ptr, GObject * dead_vml)
1416 MapDownloadInfo *mdi = ptr;
1417 g_mutex_lock(mdi->mutex);
1418 mdi->map_layer_alive = FALSE;
1419 g_mutex_unlock(mdi->mutex);
1422 static gboolean is_in_area (VikMapSource *map, MapCoord mc)
1425 vik_map_source_mapcoord_to_center_coord ( map, &mc, &vc );
1428 tl.lat = vik_map_source_get_lat_max(map);
1429 tl.lon = vik_map_source_get_lon_min(map);
1431 br.lat = vik_map_source_get_lat_min(map);
1432 br.lon = vik_map_source_get_lon_max(map);
1434 vik_coord_load_from_latlon (&vctl, VIK_COORD_LATLON, &tl);
1436 vik_coord_load_from_latlon (&vcbr, VIK_COORD_LATLON, &br);
1438 return vik_coord_inside ( &vc, &vctl, &vcbr );
1441 static int map_download_thread ( MapDownloadInfo *mdi, gpointer threaddata )
1443 void *handle = vik_map_source_download_handle_init(MAPS_LAYER_NTH_TYPE(mdi->maptype));
1445 MapCoord mcoord = mdi->mapcoord;
1447 for ( x = mdi->x0; x <= mdi->xf; x++ )
1450 for ( y = mdi->y0; y <= mdi->yf; y++ )
1453 // Only attempt to download a tile from supported areas
1454 if ( is_in_area ( MAPS_LAYER_NTH_TYPE(mdi->maptype), mcoord ) )
1456 gboolean remove_mem_cache = FALSE;
1457 gboolean need_download = FALSE;
1459 get_filename ( mdi->cache_dir, mdi->cache_layout,
1460 vik_map_source_get_uniq_id(MAPS_LAYER_NTH_TYPE(mdi->maptype)),
1461 vik_map_source_get_name(MAPS_LAYER_NTH_TYPE(mdi->maptype)),
1462 mdi->mapcoord.scale, mdi->mapcoord.z, x, y, mdi->filename_buf, mdi->maxlen,
1463 vik_map_source_get_file_extension(MAPS_LAYER_NTH_TYPE(mdi->maptype)) );
1466 int res = a_background_thread_progress ( threaddata, ((gdouble)donemaps) / mdi->mapstoget ); /* this also calls testcancel */
1468 vik_map_source_download_handle_cleanup(MAPS_LAYER_NTH_TYPE(mdi->maptype), handle);
1472 if ( g_file_test ( mdi->filename_buf, G_FILE_TEST_EXISTS ) == FALSE ) {
1473 need_download = TRUE;
1474 remove_mem_cache = TRUE;
1476 } else { /* in case map file already exists */
1477 switch (mdi->redownload) {
1478 case REDOWNLOAD_NONE:
1481 case REDOWNLOAD_BAD:
1483 /* see if this one is bad or what */
1485 GdkPixbuf *pixbuf = gdk_pixbuf_new_from_file ( mdi->filename_buf, &gx );
1486 if (gx || (!pixbuf)) {
1487 g_remove ( mdi->filename_buf );
1488 need_download = TRUE;
1489 remove_mem_cache = TRUE;
1490 g_error_free ( gx );
1493 g_object_unref ( pixbuf );
1498 case REDOWNLOAD_NEW:
1499 need_download = TRUE;
1500 remove_mem_cache = TRUE;
1503 case REDOWNLOAD_ALL:
1504 /* FIXME: need a better way than to erase file in case of server/network problem */
1505 g_remove ( mdi->filename_buf );
1506 need_download = TRUE;
1507 remove_mem_cache = TRUE;
1510 case DOWNLOAD_OR_REFRESH:
1511 remove_mem_cache = TRUE;
1515 g_warning ( "redownload state %d unknown\n", mdi->redownload);
1519 mdi->mapcoord.x = x; mdi->mapcoord.y = y;
1521 if (need_download) {
1522 DownloadResult_t dr = vik_map_source_download( MAPS_LAYER_NTH_TYPE(mdi->maptype), &(mdi->mapcoord), mdi->filename_buf, handle);
1524 case DOWNLOAD_HTTP_ERROR:
1525 case DOWNLOAD_CONTENT_ERROR: {
1526 // TODO: ?? count up the number of download errors somehow...
1527 gchar* msg = g_strdup_printf ( "%s: %s", vik_maps_layer_get_map_label (mdi->vml), _("Failed to download tile") );
1528 vik_window_statusbar_update ( (VikWindow*)VIK_GTK_WINDOW_FROM_LAYER(mdi->vml), msg, VIK_STATUSBAR_INFO );
1532 case DOWNLOAD_FILE_WRITE_ERROR: {
1533 gchar* msg = g_strdup_printf ( "%s: %s", vik_maps_layer_get_map_label (mdi->vml), _("Unable to save tile") );
1534 vik_window_statusbar_update ( (VikWindow*)VIK_GTK_WINDOW_FROM_LAYER(mdi->vml), msg, VIK_STATUSBAR_INFO );
1538 case DOWNLOAD_SUCCESS:
1539 case DOWNLOAD_NOT_REQUIRED:
1545 g_mutex_lock(mdi->mutex);
1546 if (remove_mem_cache)
1547 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 );
1548 if (mdi->refresh_display && mdi->map_layer_alive) {
1549 /* TODO: check if it's on visible area */
1550 vik_layer_emit_update ( VIK_LAYER(mdi->vml) ); // NB update display from background
1552 g_mutex_unlock(mdi->mutex);
1553 mdi->mapcoord.x = mdi->mapcoord.y = 0; /* we're temporarily between downloads */
1557 vik_map_source_download_handle_cleanup(MAPS_LAYER_NTH_TYPE(mdi->maptype), handle);
1558 g_mutex_lock(mdi->mutex);
1559 if (mdi->map_layer_alive)
1560 g_object_weak_unref(G_OBJECT(mdi->vml), weak_ref_cb, mdi);
1561 g_mutex_unlock(mdi->mutex);
1565 static void mdi_cancel_cleanup ( MapDownloadInfo *mdi )
1567 if ( mdi->mapcoord.x || mdi->mapcoord.y )
1569 get_filename ( mdi->cache_dir, mdi->cache_layout,
1570 vik_map_source_get_uniq_id(MAPS_LAYER_NTH_TYPE(mdi->maptype)),
1571 vik_map_source_get_name(MAPS_LAYER_NTH_TYPE(mdi->maptype)),
1572 mdi->mapcoord.scale, mdi->mapcoord.z, mdi->mapcoord.x, mdi->mapcoord.y, mdi->filename_buf, mdi->maxlen,
1573 vik_map_source_get_file_extension(MAPS_LAYER_NTH_TYPE(mdi->maptype)) );
1574 if ( g_file_test ( mdi->filename_buf, G_FILE_TEST_EXISTS ) == TRUE)
1576 g_remove ( mdi->filename_buf );
1581 static void start_download_thread ( VikMapsLayer *vml, VikViewport *vvp, const VikCoord *ul, const VikCoord *br, gint redownload )
1583 gdouble xzoom = vml->xmapzoom ? vml->xmapzoom : vik_viewport_get_xmpp ( vvp );
1584 gdouble yzoom = vml->ymapzoom ? vml->ymapzoom : vik_viewport_get_ympp ( vvp );
1586 VikMapSource *map = MAPS_LAYER_NTH_TYPE(vml->maptype);
1588 // Don't ever attempt download on direct access
1589 if ( vik_map_source_is_direct_file_access ( map ) )
1592 if ( vik_map_source_coord_to_mapcoord ( map, ul, xzoom, yzoom, &ulm )
1593 && vik_map_source_coord_to_mapcoord ( map, br, xzoom, yzoom, &brm ) )
1595 MapDownloadInfo *mdi = g_malloc ( sizeof(MapDownloadInfo) );
1600 mdi->map_layer_alive = TRUE;
1601 mdi->mutex = g_mutex_new();
1602 mdi->refresh_display = TRUE;
1604 /* cache_dir and buffer for dest filename */
1605 mdi->cache_dir = g_strdup ( vml->cache_dir );
1606 mdi->maxlen = strlen ( vml->cache_dir ) + 40;
1607 mdi->filename_buf = g_malloc ( mdi->maxlen * sizeof(gchar) );
1608 mdi->cache_layout = vml->cache_layout;
1609 mdi->maptype = vml->maptype;
1611 mdi->mapcoord = ulm;
1612 mdi->redownload = redownload;
1614 mdi->x0 = MIN(ulm.x, brm.x);
1615 mdi->xf = MAX(ulm.x, brm.x);
1616 mdi->y0 = MIN(ulm.y, brm.y);
1617 mdi->yf = MAX(ulm.y, brm.y);
1621 MapCoord mcoord = mdi->mapcoord;
1623 if ( mdi->redownload ) {
1624 mdi->mapstoget = (mdi->xf - mdi->x0 + 1) * (mdi->yf - mdi->y0 + 1);
1626 /* calculate how many we need */
1627 for ( a = mdi->x0; a <= mdi->xf; a++ )
1630 for ( b = mdi->y0; b <= mdi->yf; b++ )
1633 // Only count tiles from supported areas
1634 if ( is_in_area (map, mcoord) )
1636 get_filename ( mdi->cache_dir, mdi->cache_layout,
1637 vik_map_source_get_uniq_id(map),
1638 vik_map_source_get_name(map),
1639 ulm.scale, ulm.z, a, b, mdi->filename_buf, mdi->maxlen,
1640 vik_map_source_get_file_extension(map) );
1641 if ( g_file_test ( mdi->filename_buf, G_FILE_TEST_EXISTS ) == FALSE )
1648 mdi->mapcoord.x = mdi->mapcoord.y = 0; /* for cleanup -- no current map */
1650 if ( mdi->mapstoget )
1652 const gchar *tmp_str;
1657 if (redownload == REDOWNLOAD_BAD)
1658 tmp_str = ngettext("Redownloading up to %d %s map...", "Redownloading up to %d %s maps...", mdi->mapstoget);
1660 tmp_str = ngettext("Redownloading %d %s map...", "Redownloading %d %s maps...", mdi->mapstoget);
1664 tmp_str = ngettext("Downloading %d %s map...", "Downloading %d %s maps...", mdi->mapstoget);
1666 tmp = g_strdup_printf ( tmp_str, mdi->mapstoget, MAPS_LAYER_NTH_LABEL(vml->maptype));
1668 g_object_weak_ref(G_OBJECT(mdi->vml), weak_ref_cb, mdi);
1669 /* launch the thread */
1670 a_background_thread ( VIK_GTK_WINDOW_FROM_LAYER(vml), /* parent window */
1671 tmp, /* description string */
1672 (vik_thr_func) map_download_thread, /* function to call within thread */
1673 mdi, /* pass along data */
1674 (vik_thr_free_func) mdi_free, /* function to free pass along data */
1675 (vik_thr_free_func) mdi_cancel_cleanup,
1684 static void maps_layer_download_section ( VikMapsLayer *vml, VikViewport *vvp, VikCoord *ul, VikCoord *br, gdouble zoom, gint download_method )
1687 VikMapSource *map = MAPS_LAYER_NTH_TYPE(vml->maptype);
1689 // Don't ever attempt download on direct access
1690 if ( vik_map_source_is_direct_file_access ( map ) )
1693 if (!vik_map_source_coord_to_mapcoord(map, ul, zoom, zoom, &ulm)
1694 || !vik_map_source_coord_to_mapcoord(map, br, zoom, zoom, &brm)) {
1695 g_warning("%s() coord_to_mapcoord() failed", __PRETTY_FUNCTION__);
1699 MapDownloadInfo *mdi = g_malloc(sizeof(MapDownloadInfo));
1704 mdi->map_layer_alive = TRUE;
1705 mdi->mutex = g_mutex_new();
1706 mdi->refresh_display = TRUE;
1708 mdi->cache_dir = g_strdup ( vml->cache_dir );
1709 mdi->maxlen = strlen ( vml->cache_dir ) + 40;
1710 mdi->filename_buf = g_malloc ( mdi->maxlen * sizeof(gchar) );
1711 mdi->maptype = vml->maptype;
1712 mdi->cache_layout = vml->cache_layout;
1714 mdi->mapcoord = ulm;
1715 mdi->redownload = download_method;
1717 mdi->x0 = MIN(ulm.x, brm.x);
1718 mdi->xf = MAX(ulm.x, brm.x);
1719 mdi->y0 = MIN(ulm.y, brm.y);
1720 mdi->yf = MAX(ulm.y, brm.y);
1724 MapCoord mcoord = mdi->mapcoord;
1726 for (i = mdi->x0; i <= mdi->xf; i++) {
1728 for (j = mdi->y0; j <= mdi->yf; j++) {
1730 // Only count tiles from supported areas
1731 if ( is_in_area (map, mcoord) ) {
1732 get_filename ( mdi->cache_dir, mdi->cache_layout,
1733 vik_map_source_get_uniq_id(map),
1734 vik_map_source_get_name(map),
1735 ulm.scale, ulm.z, i, j, mdi->filename_buf, mdi->maxlen,
1736 vik_map_source_get_file_extension(map) );
1737 if ( g_file_test ( mdi->filename_buf, G_FILE_TEST_EXISTS ) == FALSE )
1743 mdi->mapcoord.x = mdi->mapcoord.y = 0; /* for cleanup -- no current map */
1745 if (mdi->mapstoget) {
1748 fmt = ngettext("Downloading %d %s map...",
1749 "Downloading %d %s maps...",
1751 tmp = g_strdup_printf ( fmt, mdi->mapstoget, MAPS_LAYER_NTH_LABEL(vml->maptype) );
1753 g_object_weak_ref(G_OBJECT(mdi->vml), weak_ref_cb, mdi);
1754 /* launch the thread */
1755 a_background_thread ( VIK_GTK_WINDOW_FROM_LAYER(vml), /* parent window */
1756 tmp, /* description string */
1757 (vik_thr_func) map_download_thread, /* function to call within thread */
1758 mdi, /* pass along data */
1759 (vik_thr_free_func) mdi_free, /* function to free pass along data */
1760 (vik_thr_free_func) mdi_cancel_cleanup,
1769 * vik_maps_layer_download_section:
1770 * @vml: The Map Layer
1771 * @vvp: The Viewport that the map is on
1772 * @ul: Upper left coordinate of the area to be downloaded
1773 * @br: Bottom right coordinate of the area to be downloaded
1774 * @zoom: The zoom level at which the maps are to be download
1776 * Download a specified map area at a certain zoom level
1778 void vik_maps_layer_download_section ( VikMapsLayer *vml, VikViewport *vvp, VikCoord *ul, VikCoord *br, gdouble zoom )
1780 maps_layer_download_section (vml, vvp, ul, br, zoom, REDOWNLOAD_NONE);
1783 static void maps_layer_redownload_bad ( VikMapsLayer *vml )
1785 start_download_thread ( vml, vml->redownload_vvp, &(vml->redownload_ul), &(vml->redownload_br), REDOWNLOAD_BAD );
1788 static void maps_layer_redownload_all ( VikMapsLayer *vml )
1790 start_download_thread ( vml, vml->redownload_vvp, &(vml->redownload_ul), &(vml->redownload_br), REDOWNLOAD_ALL );
1793 static void maps_layer_redownload_new ( VikMapsLayer *vml )
1795 start_download_thread ( vml, vml->redownload_vvp, &(vml->redownload_ul), &(vml->redownload_br), REDOWNLOAD_NEW );
1799 * Display a simple dialog with information about this particular map tile
1801 static void maps_layer_tile_info ( VikMapsLayer *vml )
1803 VikMapSource *map = MAPS_LAYER_NTH_TYPE(vml->maptype);
1805 gdouble xzoom = vml->xmapzoom ? vml->xmapzoom : vik_viewport_get_xmpp ( vml->redownload_vvp );
1806 gdouble yzoom = vml->ymapzoom ? vml->ymapzoom : vik_viewport_get_ympp ( vml->redownload_vvp );
1809 if ( !vik_map_source_coord_to_mapcoord ( map, &(vml->redownload_ul), xzoom, yzoom, &ulm ) )
1812 gchar *filename = NULL;
1813 gchar *message = NULL;
1814 gchar *source = NULL;
1816 if ( vik_map_source_is_direct_file_access ( map ) ) {
1817 if ( vik_map_source_is_mbtiles ( map ) ) {
1818 filename = g_strdup ( vml->filename );
1819 #ifdef HAVE_SQLITE3_H
1820 // And whether to bother going into the SQL to check it's really there or not...
1821 gchar *exists = NULL;
1822 gint zoom = 17 - ulm.scale;
1823 if ( vml->mbtiles ) {
1824 GdkPixbuf *pixbuf = get_pixbuf_sql_exec ( vml->mbtiles, ulm.x, ulm.y, zoom );
1826 exists = g_strdup ( _("YES") );
1827 g_object_unref ( G_OBJECT(pixbuf) );
1830 exists = g_strdup ( _("NO") );
1834 exists = g_strdup ( _("NO") );
1835 gint flip_y = (gint) pow(2, zoom)-1 - ulm.y;
1836 // NB Also handles .jpg automatically due to pixbuf_new_from () support - although just print png for now.
1837 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 );
1840 source = g_strdup ( _("Not available") );
1843 else if ( vik_map_source_is_osm_meta_tiles ( map ) ) {
1844 char path[PATH_MAX];
1845 xyz_to_meta(path, sizeof(path), vml->cache_dir, ulm.x, ulm.y, 17-ulm.scale );
1846 source = g_strdup ( path );
1847 filename = g_strdup ( path );
1850 guint max_path_len = strlen(vml->cache_dir) + 40;
1851 filename = g_malloc ( max_path_len * sizeof(char) );
1852 get_filename ( vml->cache_dir, VIK_MAPS_CACHE_LAYOUT_OSM,
1853 vik_map_source_get_uniq_id(map),
1855 ulm.scale, ulm.z, ulm.x, ulm.y, filename, max_path_len,
1856 vik_map_source_get_file_extension(map) );
1857 source = g_strconcat ( "file://", filename, NULL );
1861 guint max_path_len = strlen(vml->cache_dir) + 40;
1862 filename = g_malloc ( max_path_len * sizeof(char) );
1863 get_filename ( vml->cache_dir, vml->cache_layout,
1864 vik_map_source_get_uniq_id(map),
1865 vik_map_source_get_name(map),
1866 ulm.scale, ulm.z, ulm.x, ulm.y, filename, max_path_len,
1867 vik_map_source_get_file_extension(map) );
1868 source = g_strdup_printf ( "http://%s%s",
1869 vik_map_source_default_get_hostname ( VIK_MAP_SOURCE_DEFAULT(map) ),
1870 vik_map_source_default_get_uri ( VIK_MAP_SOURCE_DEFAULT(map), &ulm ) );
1873 if ( g_file_test ( filename, G_FILE_TEST_EXISTS ) ) {
1875 // Get some timestamp information of the tile
1876 struct stat stat_buf;
1877 if ( g_stat ( filename, &stat_buf ) == 0 ) {
1879 strftime ( time_buf, sizeof(time_buf), "%c", gmtime((const time_t *)&stat_buf.st_mtime) );
1880 message = g_strdup_printf ( _("\nSource: %s\n\nTile File: %s\nTile File Timestamp: %s"), source, filename, time_buf );
1883 message = g_strdup_printf ( _("\nSource: %s\n\nTile File: %s\nTile File Timestamp: Not Available"), source, filename );
1886 a_dialog_info_msg ( VIK_GTK_WINDOW_FROM_LAYER(vml), message );
1889 message = g_strdup_printf ( _("\nSource: %s\n\nTile File: %s [Not Available]"), source, filename );
1890 a_dialog_warning_msg ( VIK_GTK_WINDOW_FROM_LAYER(vml), message );
1895 g_free ( filename );
1898 static gboolean maps_layer_download_release ( VikMapsLayer *vml, GdkEventButton *event, VikViewport *vvp )
1900 if (!vml || vml->vl.type != VIK_LAYER_MAPS)
1902 if ( vml->dl_tool_x != -1 && vml->dl_tool_y != -1 )
1904 if ( event->button == 1 )
1907 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 );
1908 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 );
1909 start_download_thread ( vml, vvp, &ul, &br, DOWNLOAD_OR_REFRESH );
1910 vml->dl_tool_x = vml->dl_tool_y = -1;
1915 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) );
1916 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) );
1918 vml->redownload_vvp = vvp;
1920 vml->dl_tool_x = vml->dl_tool_y = -1;
1922 if ( ! vml->dl_right_click_menu ) {
1924 vml->dl_right_click_menu = GTK_MENU ( gtk_menu_new () );
1926 item = gtk_menu_item_new_with_mnemonic ( _("Redownload _Bad Map(s)") );
1927 g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(maps_layer_redownload_bad), vml );
1928 gtk_menu_shell_append ( GTK_MENU_SHELL(vml->dl_right_click_menu), item );
1930 item = gtk_menu_item_new_with_mnemonic ( _("Redownload _New Map(s)") );
1931 g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(maps_layer_redownload_new), vml );
1932 gtk_menu_shell_append ( GTK_MENU_SHELL(vml->dl_right_click_menu), item );
1934 item = gtk_menu_item_new_with_mnemonic ( _("Redownload _All Map(s)") );
1935 g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(maps_layer_redownload_all), vml );
1936 gtk_menu_shell_append ( GTK_MENU_SHELL(vml->dl_right_click_menu), item );
1938 item = gtk_image_menu_item_new_with_mnemonic ( _("_Show Tile Information") );
1939 gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_INFO, GTK_ICON_SIZE_MENU) );
1940 g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(maps_layer_tile_info), vml );
1941 gtk_menu_shell_append (GTK_MENU_SHELL(vml->dl_right_click_menu), item);
1944 gtk_menu_popup ( vml->dl_right_click_menu, NULL, NULL, NULL, NULL, event->button, event->time );
1945 gtk_widget_show_all ( GTK_WIDGET(vml->dl_right_click_menu) );
1951 static gpointer maps_layer_download_create ( VikWindow *vw, VikViewport *vvp)
1956 static gboolean maps_layer_download_click ( VikMapsLayer *vml, GdkEventButton *event, VikViewport *vvp )
1959 if (!vml || vml->vl.type != VIK_LAYER_MAPS)
1961 VikMapSource *map = MAPS_LAYER_NTH_TYPE(vml->maptype);
1962 if ( vik_map_source_get_drawmode(map) == vik_viewport_get_drawmode ( vvp ) &&
1963 vik_map_source_coord_to_mapcoord ( map, vik_viewport_get_center ( vvp ),
1964 vml->xmapzoom ? vml->xmapzoom : vik_viewport_get_xmpp ( vvp ),
1965 vml->ymapzoom ? vml->ymapzoom : vik_viewport_get_ympp ( vvp ),
1967 vml->dl_tool_x = event->x, vml->dl_tool_y = event->y;
1973 // A slightly better way of defining the menu callback information
1974 // This should be easier to extend/rework compared to previously
1981 typedef gpointer menu_array_values[MA_LAST];
1983 static void download_onscreen_maps ( menu_array_values values, gint redownload )
1985 VikMapsLayer *vml = VIK_MAPS_LAYER(values[MA_VML]);
1986 VikViewport *vvp = VIK_VIEWPORT(values[MA_VVP]);
1987 VikViewportDrawMode vp_drawmode = vik_viewport_get_drawmode ( vvp );
1989 gdouble xzoom = vml->xmapzoom ? vml->xmapzoom : vik_viewport_get_xmpp ( vvp );
1990 gdouble yzoom = vml->ymapzoom ? vml->ymapzoom : vik_viewport_get_ympp ( vvp );
1995 vik_viewport_screen_to_coord ( vvp, 0, 0, &ul );
1996 vik_viewport_screen_to_coord ( vvp, vik_viewport_get_width(vvp), vik_viewport_get_height(vvp), &br );
1998 VikMapSource *map = MAPS_LAYER_NTH_TYPE(vml->maptype);
1999 if ( vik_map_source_get_drawmode(map) == vp_drawmode &&
2000 vik_map_source_coord_to_mapcoord ( map, &ul, xzoom, yzoom, &ulm ) &&
2001 vik_map_source_coord_to_mapcoord ( map, &br, xzoom, yzoom, &brm ) )
2002 start_download_thread ( vml, vvp, &ul, &br, redownload );
2003 else if (vik_map_source_get_drawmode(map) != vp_drawmode) {
2004 const gchar *drawmode_name = vik_viewport_get_drawmode_name (vvp, vik_map_source_get_drawmode(map));
2005 gchar *err = g_strdup_printf(_("Wrong drawmode for this map.\nSelect \"%s\" from View menu and try again."), _(drawmode_name));
2006 a_dialog_error_msg ( VIK_GTK_WINDOW_FROM_LAYER(vml), err );
2010 a_dialog_error_msg ( VIK_GTK_WINDOW_FROM_LAYER(vml), _("Wrong zoom level for this map.") );
2014 static void maps_layer_download_missing_onscreen_maps ( menu_array_values values )
2016 download_onscreen_maps( values, REDOWNLOAD_NONE);
2019 static void maps_layer_download_new_onscreen_maps ( menu_array_values values )
2021 download_onscreen_maps( values, REDOWNLOAD_NEW);
2024 static void maps_layer_redownload_all_onscreen_maps ( menu_array_values values )
2026 download_onscreen_maps( values, REDOWNLOAD_ALL);
2029 static void maps_layers_about ( gpointer vml_vvp[2] )
2031 VikMapsLayer *vml = vml_vvp[0];
2032 VikMapSource *map = MAPS_LAYER_NTH_TYPE(vml->maptype);
2034 if ( vik_map_source_get_license (map) )
2035 maps_show_license ( VIK_GTK_WINDOW_FROM_LAYER(vml), map );
2037 a_dialog_info_msg ( VIK_GTK_WINDOW_FROM_LAYER(vml),
2038 vik_map_source_get_label (map) );
2042 * maps_layer_how_many_maps:
2043 * Copied from maps_layer_download_section but without the actual download and this returns a value
2045 static gint maps_layer_how_many_maps ( VikMapsLayer *vml, VikViewport *vvp, VikCoord *ul, VikCoord *br, gdouble zoom, gint redownload )
2048 VikMapSource *map = MAPS_LAYER_NTH_TYPE(vml->maptype);
2050 if ( vik_map_source_is_direct_file_access ( map ) )
2053 if (!vik_map_source_coord_to_mapcoord(map, ul, zoom, zoom, &ulm)
2054 || !vik_map_source_coord_to_mapcoord(map, br, zoom, zoom, &brm)) {
2055 g_warning("%s() coord_to_mapcoord() failed", __PRETTY_FUNCTION__);
2059 MapDownloadInfo *mdi = g_malloc(sizeof(MapDownloadInfo));
2064 mdi->map_layer_alive = TRUE;
2065 mdi->mutex = g_mutex_new();
2066 mdi->refresh_display = FALSE;
2068 mdi->cache_dir = g_strdup ( vml->cache_dir );
2069 mdi->maxlen = strlen ( vml->cache_dir ) + 40;
2070 mdi->filename_buf = g_malloc ( mdi->maxlen * sizeof(gchar) );
2071 mdi->maptype = vml->maptype;
2072 mdi->cache_layout = vml->cache_layout;
2074 mdi->mapcoord = ulm;
2075 mdi->redownload = redownload;
2077 mdi->x0 = MIN(ulm.x, brm.x);
2078 mdi->xf = MAX(ulm.x, brm.x);
2079 mdi->y0 = MIN(ulm.y, brm.y);
2080 mdi->yf = MAX(ulm.y, brm.y);
2084 if ( mdi->redownload == REDOWNLOAD_ALL ) {
2085 mdi->mapstoget = (mdi->xf - mdi->x0 + 1) * (mdi->yf - mdi->y0 + 1);
2088 /* calculate how many we need */
2089 MapCoord mcoord = mdi->mapcoord;
2090 for (i = mdi->x0; i <= mdi->xf; i++) {
2092 for (j = mdi->y0; j <= mdi->yf; j++) {
2094 // Only count tiles from supported areas
2095 if ( is_in_area ( map, mcoord ) ) {
2096 get_filename ( mdi->cache_dir, mdi->cache_layout,
2097 vik_map_source_get_uniq_id(map),
2098 vik_map_source_get_name(map),
2099 ulm.scale, ulm.z, i, j, mdi->filename_buf, mdi->maxlen,
2100 vik_map_source_get_file_extension(map) );
2101 if ( mdi->redownload == REDOWNLOAD_NEW ) {
2102 // Assume the worst - always a new file
2103 // Absolute value would require a server lookup - but that is too slow
2107 if ( g_file_test ( mdi->filename_buf, G_FILE_TEST_EXISTS ) == FALSE ) {
2112 if ( mdi->redownload == REDOWNLOAD_BAD ) {
2113 /* see if this one is bad or what */
2115 GdkPixbuf *pixbuf = gdk_pixbuf_new_from_file ( mdi->filename_buf, &gx );
2116 if (gx || (!pixbuf)) {
2120 // Other download cases already considered or just ignored
2129 gint rv = mdi->mapstoget;
2137 * maps_dialog_zoom_between:
2138 * This dialog is specific to the map layer, so it's here rather than in dialog.c
2140 gboolean maps_dialog_zoom_between ( GtkWindow *parent,
2145 gint *selected_zoom1,
2146 gint *selected_zoom2,
2147 gchar *download_list[],
2148 gint default_download,
2149 gint *selected_download )
2151 GtkWidget *dialog = gtk_dialog_new_with_buttons ( title,
2153 GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
2154 GTK_STOCK_OK, GTK_RESPONSE_ACCEPT,
2155 GTK_STOCK_CANCEL, GTK_RESPONSE_REJECT,
2157 gtk_dialog_set_default_response ( GTK_DIALOG(dialog), GTK_RESPONSE_ACCEPT );
2158 GtkWidget *response_w = NULL;
2159 #if GTK_CHECK_VERSION (2, 20, 0)
2160 response_w = gtk_dialog_get_widget_for_response ( GTK_DIALOG(dialog), GTK_RESPONSE_ACCEPT );
2162 GtkWidget *zoom_label1 = gtk_label_new ( _("Zoom Start:") );
2163 GtkWidget *zoom_combo1 = vik_combo_box_text_new();
2165 for (s = zoom_list; *s; s++)
2166 vik_combo_box_text_append ( zoom_combo1, *s );
2167 gtk_combo_box_set_active ( GTK_COMBO_BOX(zoom_combo1), default_zoom1 );
2169 GtkWidget *zoom_label2 = gtk_label_new ( _("Zoom End:") );
2170 GtkWidget *zoom_combo2 = vik_combo_box_text_new();
2171 for (s = zoom_list; *s; s++)
2172 vik_combo_box_text_append ( zoom_combo2, *s );
2173 gtk_combo_box_set_active ( GTK_COMBO_BOX(zoom_combo2), default_zoom2 );
2175 GtkWidget *download_label = gtk_label_new(_("Download Maps Method:"));
2176 GtkWidget *download_combo = vik_combo_box_text_new();
2177 for (s = download_list; *s; s++)
2178 vik_combo_box_text_append ( download_combo, *s );
2179 gtk_combo_box_set_active ( GTK_COMBO_BOX(download_combo), default_download );
2181 GtkTable *box = GTK_TABLE(gtk_table_new(3, 2, FALSE));
2182 gtk_table_attach_defaults (box, GTK_WIDGET(zoom_label1), 0, 1, 0, 1);
2183 gtk_table_attach_defaults (box, GTK_WIDGET(zoom_combo1), 1, 2, 0, 1);
2184 gtk_table_attach_defaults (box, GTK_WIDGET(zoom_label2), 0, 1, 1, 2);
2185 gtk_table_attach_defaults (box, GTK_WIDGET(zoom_combo2), 1, 2, 1, 2);
2186 gtk_table_attach_defaults (box, GTK_WIDGET(download_label), 0, 1, 2, 3);
2187 gtk_table_attach_defaults (box, GTK_WIDGET(download_combo), 1, 2, 2, 3);
2189 gtk_box_pack_start ( GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(dialog))), GTK_WIDGET(box), FALSE, FALSE, 5 );
2192 gtk_widget_grab_focus ( response_w );
2194 gtk_widget_show_all ( dialog );
2195 if ( gtk_dialog_run ( GTK_DIALOG(dialog) ) != GTK_RESPONSE_ACCEPT ) {
2196 gtk_widget_destroy(dialog);
2200 // Return selected options
2201 *selected_zoom1 = gtk_combo_box_get_active ( GTK_COMBO_BOX(zoom_combo1) );
2202 *selected_zoom2 = gtk_combo_box_get_active ( GTK_COMBO_BOX(zoom_combo2) );
2203 *selected_download = gtk_combo_box_get_active ( GTK_COMBO_BOX(download_combo) );
2205 gtk_widget_destroy(dialog);
2209 // My best guess of sensible limits
2210 #define REALLY_LARGE_AMOUNT_OF_TILES 5000
2211 #define CONFIRM_LARGE_AMOUNT_OF_TILES 500
2214 * Get all maps in the region for zoom levels specified by the user
2215 * Sort of similar to trw_layer_download_map_along_track_cb function
2217 static void maps_layer_download_all ( menu_array_values values )
2219 VikMapsLayer *vml = VIK_MAPS_LAYER(values[MA_VML]);
2220 VikViewport *vvp = VIK_VIEWPORT(values[MA_VVP]);
2222 // I don't think we should allow users to hammer the servers too much...
2223 // Delibrately not allowing lowest zoom levels
2224 // Still can give massive numbers to download
2225 // A screen size of 1600x1200 gives around 300,000 tiles between 1..128 when none exist before !!
2226 gchar *zoom_list[] = {"1", "2", "4", "8", "16", "32", "64", "128", "256", "512", "1024", NULL };
2227 gdouble zoom_vals[] = {1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024};
2229 gint selected_zoom1, selected_zoom2, default_zoom, lower_zoom;
2230 gint selected_download_method;
2232 gdouble cur_zoom = vik_viewport_get_zoom(vvp);
2234 for (default_zoom = 0; default_zoom < sizeof(zoom_vals)/sizeof(gdouble); default_zoom++) {
2235 if (cur_zoom == zoom_vals[default_zoom])
2238 default_zoom = (default_zoom == sizeof(zoom_vals)/sizeof(gdouble)) ? sizeof(zoom_vals)/sizeof(gdouble) - 1 : default_zoom;
2240 // Default to only 2 zoom levels below the current one
2241 if (default_zoom > 1 )
2242 lower_zoom = default_zoom - 2;
2244 lower_zoom = default_zoom;
2246 // redownload method - needs to align with REDOWNLOAD* macro values
2247 gchar *download_list[] = { _("Missing"), _("Bad"), _("New"), _("Reload All"), NULL };
2249 gchar *title = g_strdup_printf ( ("%s: %s"), vik_maps_layer_get_map_label (vml), _("Download for Zoom Levels") );
2251 if ( ! maps_dialog_zoom_between ( VIK_GTK_WINDOW_FROM_LAYER(vml),
2259 REDOWNLOAD_NONE, // AKA Missing
2260 &selected_download_method ) ) {
2267 // Find out new current positions
2268 gdouble min_lat, max_lat, min_lon, max_lon;
2269 VikCoord vc_ul, vc_br;
2270 vik_viewport_get_min_max_lat_lon ( vvp, &min_lat, &max_lat, &min_lon, &max_lon );
2271 struct LatLon ll_ul = { max_lat, min_lon };
2272 struct LatLon ll_br = { min_lat, max_lon };
2273 vik_coord_load_from_latlon ( &vc_ul, vik_viewport_get_coord_mode (vvp), &ll_ul );
2274 vik_coord_load_from_latlon ( &vc_br, vik_viewport_get_coord_mode (vvp), &ll_br );
2276 // Get Maps Count - call for each zoom level (in reverse)
2277 // With REDOWNLOAD_NEW this is a possible maximum
2278 // With REDOWNLOAD_NONE this only missing ones - however still has a server lookup per tile
2281 for ( zz = selected_zoom2; zz >= selected_zoom1; zz-- ) {
2282 map_count = map_count + maps_layer_how_many_maps ( vml, vvp, &vc_ul, &vc_br, zoom_vals[zz], selected_download_method );
2285 g_debug ("vikmapslayer: download request map count %d for method %d", map_count, selected_download_method);
2287 // Absolute protection of hammering a map server
2288 if ( map_count > REALLY_LARGE_AMOUNT_OF_TILES ) {
2289 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);
2290 a_dialog_error_msg ( VIK_GTK_WINDOW_FROM_LAYER(vml), str );
2295 // Confirm really want to do this
2296 if ( map_count > CONFIRM_LARGE_AMOUNT_OF_TILES ) {
2297 gchar *str = g_strdup_printf (_("Do you really want to download %d tiles?"), map_count);
2298 gboolean ans = a_dialog_yes_or_no ( VIK_GTK_WINDOW_FROM_LAYER(vml), str, NULL );
2304 // Get Maps - call for each zoom level (in reverse)
2305 for ( zz = selected_zoom2; zz >= selected_zoom1; zz-- ) {
2306 maps_layer_download_section ( vml, vvp, &vc_ul, &vc_br, zoom_vals[zz], selected_download_method );
2310 static void maps_layer_add_menu_items ( VikMapsLayer *vml, GtkMenu *menu, VikLayersPanel *vlp )
2313 static menu_array_values values;
2314 values[MA_VML] = vml;
2315 values[MA_VVP] = vik_layers_panel_get_viewport( VIK_LAYERS_PANEL(vlp) );
2317 item = gtk_menu_item_new();
2318 gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item );
2319 gtk_widget_show ( item );
2321 /* Now with icons */
2322 item = gtk_image_menu_item_new_with_mnemonic ( _("Download _Missing Onscreen Maps") );
2323 gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_ADD, GTK_ICON_SIZE_MENU) );
2324 g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(maps_layer_download_missing_onscreen_maps), values );
2325 gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
2326 gtk_widget_show ( item );
2328 if ( vik_map_source_supports_download_only_new (MAPS_LAYER_NTH_TYPE(vml->maptype)) ) {
2329 item = gtk_image_menu_item_new_with_mnemonic ( _("Download _New Onscreen Maps") );
2330 gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_REDO, GTK_ICON_SIZE_MENU) );
2331 g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(maps_layer_download_new_onscreen_maps), values );
2332 gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
2333 gtk_widget_show ( item );
2336 item = gtk_image_menu_item_new_with_mnemonic ( _("Reload _All Onscreen Maps") );
2337 gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_REFRESH, GTK_ICON_SIZE_MENU) );
2338 g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(maps_layer_redownload_all_onscreen_maps), values );
2339 gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
2340 gtk_widget_show ( item );
2342 item = gtk_image_menu_item_new_with_mnemonic ( _("Download Maps in _Zoom Levels...") );
2343 gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_DND_MULTIPLE, GTK_ICON_SIZE_MENU) );
2344 g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(maps_layer_download_all), values );
2345 gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
2346 gtk_widget_show ( item );
2348 item = gtk_image_menu_item_new_from_stock ( GTK_STOCK_ABOUT, NULL );
2349 g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(maps_layers_about), values );
2350 gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
2351 gtk_widget_show ( item );
2355 * Enable downloading maps of the current screen area either 'new' or 'everything'
2357 void vik_maps_layer_download ( VikMapsLayer *vml, VikViewport *vvp, gboolean only_new )
2362 static menu_array_values values;
2363 values[MA_VML] = vml;
2364 values[MA_VVP] = vvp;
2367 // Get only new maps
2368 maps_layer_download_new_onscreen_maps ( values );
2370 // Redownload everything
2371 maps_layer_redownload_all_onscreen_maps ( values );