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"
65 #define VIK_SETTINGS_MAP_MAX_TILES "maps_max_tiles"
66 static gint MAX_TILES = 1000;
68 #define VIK_SETTINGS_MAP_MIN_SHRINKFACTOR "maps_min_shrinkfactor"
69 #define VIK_SETTINGS_MAP_MAX_SHRINKFACTOR "maps_max_shrinkfactor"
70 static gdouble MAX_SHRINKFACTOR = 8.0000001; /* zoom 1 viewing 8-tiles */
71 static gdouble MIN_SHRINKFACTOR = 0.0312499; /* zoom 32 viewing 1-tiles */
73 #define VIK_SETTINGS_MAP_REAL_MIN_SHRINKFACTOR "maps_real_min_shrinkfactor"
74 static gdouble REAL_MIN_SHRINKFACTOR = 0.0039062499; /* if shrinkfactor is between MAX and REAL_MAX, will only check for existence */
76 #define VIK_SETTINGS_MAP_SCALE_INC_UP "maps_scale_inc_up"
77 static guint SCALE_INC_UP = 2;
78 #define VIK_SETTINGS_MAP_SCALE_INC_DOWN "maps_scale_inc_down"
79 static guint SCALE_INC_DOWN = 4;
80 #define VIK_SETTINGS_MAP_SCALE_SMALLER_ZOOM_FIRST "maps_scale_smaller_zoom_first"
81 static gboolean SCALE_SMALLER_ZOOM_FIRST = TRUE;
83 /****** MAP TYPES ******/
85 static GList *__map_types = NULL;
87 #define NUM_MAP_TYPES g_list_length(__map_types)
89 /* List of label for each map type */
90 static gchar **params_maptypes = NULL;
92 /* Corresponding IDS. (Cf. field uniq_id in VikMapsLayer struct) */
93 static guint *params_maptypes_ids = NULL;
95 /******** MAPZOOMS *********/
97 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 };
98 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 };
99 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 };
101 #define NUM_MAPZOOMS (sizeof(params_mapzooms)/sizeof(params_mapzooms[0]) - 1)
103 /**************************/
106 static void maps_layer_post_read (VikLayer *vl, VikViewport *vp, gboolean from_file);
107 static const gchar* maps_layer_tooltip ( VikMapsLayer *vml );
108 static void maps_layer_marshall( VikMapsLayer *vml, guint8 **data, gint *len );
109 static VikMapsLayer *maps_layer_unmarshall( guint8 *data, gint len, VikViewport *vvp );
110 static gboolean maps_layer_set_param ( VikMapsLayer *vml, guint16 id, VikLayerParamData data, VikViewport *vvp, gboolean is_file_operation );
111 static VikLayerParamData maps_layer_get_param ( VikMapsLayer *vml, guint16 id, gboolean is_file_operation );
112 static void maps_layer_change_param ( GtkWidget *widget, ui_change_values values );
113 static void maps_layer_draw ( VikMapsLayer *vml, VikViewport *vvp );
114 static VikMapsLayer *maps_layer_new ( VikViewport *vvp );
115 static void maps_layer_free ( VikMapsLayer *vml );
116 static gboolean maps_layer_download_release ( VikMapsLayer *vml, GdkEventButton *event, VikViewport *vvp );
117 static gboolean maps_layer_download_click ( VikMapsLayer *vml, GdkEventButton *event, VikViewport *vvp );
118 static gpointer maps_layer_download_create ( VikWindow *vw, VikViewport *vvp );
119 static void maps_layer_set_cache_dir ( VikMapsLayer *vml, const gchar *dir );
120 static void start_download_thread ( VikMapsLayer *vml, VikViewport *vvp, const VikCoord *ul, const VikCoord *br, gint redownload );
121 static void maps_layer_add_menu_items ( VikMapsLayer *vml, GtkMenu *menu, VikLayersPanel *vlp );
122 static guint map_uniq_id_to_index ( guint uniq_id );
125 static VikLayerParamScale params_scales[] = {
126 /* min, max, step, digits (decimal places) */
127 { 0, 255, 3, 0 }, /* alpha */
130 static VikLayerParamData id_default ( void ) { return VIK_LPD_UINT ( MAP_ID_MAPQUEST_OSM ); }
131 static VikLayerParamData directory_default ( void )
133 VikLayerParamData data;
134 VikLayerParamData *pref = a_preferences_get(VIKING_PREFERENCES_NAMESPACE "maplayer_default_dir");
135 if (pref) data.s = g_strdup ( pref->s ); else data.s = "";
138 static VikLayerParamData file_default ( void )
140 VikLayerParamData data;
144 static VikLayerParamData alpha_default ( void ) { return VIK_LPD_UINT ( 255 ); }
145 static VikLayerParamData mapzoom_default ( void ) { return VIK_LPD_UINT ( 0 ); }
147 static gchar *cache_types[] = { "Viking", N_("OSM"), NULL };
148 static VikMapsCacheLayout cache_layout_default_value = VIK_MAPS_CACHE_LAYOUT_VIKING;
149 static VikLayerParamData cache_layout_default ( void ) { return VIK_LPD_UINT ( cache_layout_default_value ); }
151 VikLayerParam maps_layer_params[] = {
152 // NB mode => id - But can't break file format just to rename something better
153 { 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 },
154 { 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 },
155 { VIK_LAYER_MAPS, "cache_type", VIK_LAYER_PARAM_UINT, VIK_LAYER_GROUP_NONE, N_("Cache Layout:"), VIK_LAYER_WIDGET_COMBOBOX, cache_types, NULL,
156 N_("This determines the tile storage layout on disk"), cache_layout_default, NULL, NULL },
157 { 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,
158 N_("An MBTiles file. Only applies when the map type method is 'MBTiles'"), file_default, NULL, NULL },
159 { VIK_LAYER_MAPS, "alpha", VIK_LAYER_PARAM_UINT, VIK_LAYER_GROUP_NONE, N_("Alpha:"), VIK_LAYER_WIDGET_HSCALE, params_scales, NULL,
160 N_("Control the Alpha value for transparency effects"), alpha_default, NULL, NULL },
161 { 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 },
162 { VIK_LAYER_MAPS, "adlonlymissing", VIK_LAYER_PARAM_BOOLEAN, VIK_LAYER_GROUP_NONE, N_("Autodownload Only Gets Missing Maps:"), VIK_LAYER_WIDGET_CHECKBUTTON, NULL, NULL,
163 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 },
164 { VIK_LAYER_MAPS, "mapzoom", VIK_LAYER_PARAM_UINT, VIK_LAYER_GROUP_NONE, N_("Zoom Level:"), VIK_LAYER_WIDGET_COMBOBOX, params_mapzooms, NULL,
165 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."),
166 mapzoom_default, NULL, NULL },
181 void maps_layer_set_autodownload_default ( gboolean autodownload )
183 // Set appropriate function
185 maps_layer_params[PARAM_AUTODOWNLOAD].default_value = vik_lpd_true_default;
187 maps_layer_params[PARAM_AUTODOWNLOAD].default_value = vik_lpd_false_default;
190 void maps_layer_set_cache_default ( VikMapsCacheLayout layout )
192 // Override default value returned by the default param function
193 cache_layout_default_value = layout;
196 static VikToolInterface maps_tools[] = {
197 { { "MapsDownload", "vik-icon-Maps Download", N_("_Maps Download"), NULL, N_("Maps Download"), 0 },
198 (VikToolConstructorFunc) maps_layer_download_create,
202 (VikToolMouseFunc) maps_layer_download_click,
204 (VikToolMouseFunc) maps_layer_download_release,
207 GDK_CURSOR_IS_PIXMAP, &cursor_mapdl_pixbuf, NULL },
210 VikLayerInterface vik_maps_layer_interface = {
214 &vikmapslayer_pixbuf,
217 sizeof(maps_tools) / sizeof(maps_tools[0]),
226 (VikLayerFuncCreate) maps_layer_new,
227 (VikLayerFuncRealize) NULL,
228 (VikLayerFuncPostRead) maps_layer_post_read,
229 (VikLayerFuncFree) maps_layer_free,
231 (VikLayerFuncProperties) NULL,
232 (VikLayerFuncDraw) maps_layer_draw,
233 (VikLayerFuncChangeCoordMode) NULL,
235 (VikLayerFuncSetMenuItemsSelection) NULL,
236 (VikLayerFuncGetMenuItemsSelection) NULL,
238 (VikLayerFuncAddMenuItems) maps_layer_add_menu_items,
239 (VikLayerFuncSublayerAddMenuItems) NULL,
241 (VikLayerFuncSublayerRenameRequest) NULL,
242 (VikLayerFuncSublayerToggleVisible) NULL,
243 (VikLayerFuncSublayerTooltip) NULL,
244 (VikLayerFuncLayerTooltip) maps_layer_tooltip,
245 (VikLayerFuncLayerSelected) NULL,
247 (VikLayerFuncMarshall) maps_layer_marshall,
248 (VikLayerFuncUnmarshall) maps_layer_unmarshall,
250 (VikLayerFuncSetParam) maps_layer_set_param,
251 (VikLayerFuncGetParam) maps_layer_get_param,
252 (VikLayerFuncChangeParam) maps_layer_change_param,
254 (VikLayerFuncReadFileData) NULL,
255 (VikLayerFuncWriteFileData) NULL,
257 (VikLayerFuncDeleteItem) NULL,
258 (VikLayerFuncCutItem) NULL,
259 (VikLayerFuncCopyItem) NULL,
260 (VikLayerFuncPasteItem) NULL,
261 (VikLayerFuncFreeCopiedItem) NULL,
262 (VikLayerFuncDragDropRequest) NULL,
264 (VikLayerFuncSelectClick) NULL,
265 (VikLayerFuncSelectMove) NULL,
266 (VikLayerFuncSelectRelease) NULL,
267 (VikLayerFuncSelectedViewportMenu) NULL,
270 struct _VikMapsLayer {
274 VikMapsCacheLayout cache_layout;
277 gdouble xmapzoom, ymapzoom;
279 gboolean autodownload;
280 gboolean adl_only_missing;
281 VikCoord *last_center;
285 gint dl_tool_x, dl_tool_y;
287 GtkMenu *dl_right_click_menu;
288 VikCoord redownload_ul, redownload_br; /* right click menu only */
289 VikViewport *redownload_vvp;
291 #ifdef HAVE_SQLITE3_H
296 enum { REDOWNLOAD_NONE = 0, /* download only missing maps */
297 REDOWNLOAD_BAD, /* download missing and bad maps */
298 REDOWNLOAD_NEW, /* download missing maps that are newer on server only */
299 REDOWNLOAD_ALL, /* download all maps */
300 DOWNLOAD_OR_REFRESH }; /* download missing maps and refresh cache */
302 static VikLayerParam prefs[] = {
303 { 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 },
306 void maps_layer_init ()
308 VikLayerParamData tmp;
309 tmp.s = maps_layer_default_dir();
310 a_preferences_register(prefs, tmp, VIKING_PREFERENCES_GROUP_KEY);
312 gint max_tiles = MAX_TILES;
313 if ( a_settings_get_integer ( VIK_SETTINGS_MAP_MAX_TILES, &max_tiles ) )
314 MAX_TILES = max_tiles;
317 if ( a_settings_get_double ( VIK_SETTINGS_MAP_MIN_SHRINKFACTOR, &gdtmp ) )
318 MIN_SHRINKFACTOR = gdtmp;
320 if ( a_settings_get_double ( VIK_SETTINGS_MAP_MAX_SHRINKFACTOR, &gdtmp ) )
321 MAX_SHRINKFACTOR = gdtmp;
323 if ( a_settings_get_double ( VIK_SETTINGS_MAP_REAL_MIN_SHRINKFACTOR, &gdtmp ) )
324 REAL_MIN_SHRINKFACTOR = gdtmp;
327 if ( a_settings_get_integer ( VIK_SETTINGS_MAP_SCALE_INC_UP, &gitmp ) )
328 SCALE_INC_UP = gitmp;
330 if ( a_settings_get_integer ( VIK_SETTINGS_MAP_SCALE_INC_DOWN, &gitmp ) )
331 SCALE_INC_DOWN = gitmp;
333 gboolean gbtmp = TRUE;
334 if ( a_settings_get_boolean ( VIK_SETTINGS_MAP_SCALE_SMALLER_ZOOM_FIRST, &gbtmp ) )
335 SCALE_SMALLER_ZOOM_FIRST = gbtmp;
339 /****************************************/
340 /******** MAPS LAYER TYPES **************/
341 /****************************************/
343 void _add_map_source ( guint16 id, const char *label, VikMapSource *map )
347 len = g_strv_length (params_maptypes);
349 params_maptypes = g_realloc (params_maptypes, (len+2)*sizeof(gchar*));
350 params_maptypes[len] = g_strdup (label);
351 params_maptypes[len+1] = NULL;
354 params_maptypes_ids = g_realloc (params_maptypes_ids, (len+2)*sizeof(guint));
355 params_maptypes_ids[len] = id;
356 params_maptypes_ids[len+1] = 0;
358 /* We have to clone */
359 VikMapSource *clone = VIK_MAP_SOURCE(g_object_ref(map));
360 /* Register the clone in the list */
361 __map_types = g_list_append(__map_types, clone);
364 We have to ensure the mode LayerParam references the up-to-date
368 memcpy(&maps_layer_params[0].widget_data, ¶ms_maptypes, sizeof(gpointer));
369 memcpy(&maps_layer_params[0].extra_widget_data, ¶ms_maptypes_ids, sizeof(gpointer));
371 maps_layer_params[0].widget_data = params_maptypes;
372 maps_layer_params[0].extra_widget_data = params_maptypes_ids;
375 void _update_map_source ( const char *label, VikMapSource *map, int index )
377 GList *item = g_list_nth (__map_types, index);
378 g_object_unref (item->data);
379 item->data = g_object_ref (map);
380 /* Change previous data */
381 g_free (params_maptypes[index]);
382 params_maptypes[index] = g_strdup (label);
386 * maps_layer_register_map_source:
387 * @map: the new VikMapSource
389 * Register a new VikMapSource.
390 * Override existing one (equality of id).
392 void maps_layer_register_map_source ( VikMapSource *map )
394 g_assert(map != NULL);
396 guint16 id = vik_map_source_get_uniq_id(map);
397 const char *label = vik_map_source_get_label(map);
398 g_assert(label != NULL);
400 int previous = map_uniq_id_to_index (id);
401 if (previous != NUM_MAP_TYPES)
403 _update_map_source (label, map, previous);
407 _add_map_source (id, label, map);
411 #define MAPS_LAYER_NTH_LABEL(n) (params_maptypes[n])
412 #define MAPS_LAYER_NTH_ID(n) (params_maptypes_ids[n])
413 #define MAPS_LAYER_NTH_TYPE(n) (VIK_MAP_SOURCE(g_list_nth_data(__map_types, (n))))
416 * vik_maps_layer_get_map_type:
418 * Returns the actual map id (rather than the internal type index value)
420 guint vik_maps_layer_get_map_type(VikMapsLayer *vml)
422 return MAPS_LAYER_NTH_ID(vml->maptype);
426 * vik_maps_layer_set_map_type:
429 void vik_maps_layer_set_map_type(VikMapsLayer *vml, guint map_type)
431 gint maptype = map_uniq_id_to_index(map_type);
432 if ( maptype == NUM_MAP_TYPES )
433 g_warning(_("Unknown map type"));
435 vml->maptype = maptype;
439 * vik_maps_layer_get_default_map_type:
442 guint vik_maps_layer_get_default_map_type ()
444 VikLayerInterface *vli = vik_layer_get_interface ( VIK_LAYER_MAPS );
445 VikLayerParamData vlpd = a_layer_defaults_get ( vli->fixed_layer_name, "mode", VIK_LAYER_PARAM_UINT );
451 gchar *vik_maps_layer_get_map_label(VikMapsLayer *vml)
453 return(g_strdup(MAPS_LAYER_NTH_LABEL(vml->maptype)));
456 /****************************************/
457 /******** CACHE DIR STUFF ***************/
458 /****************************************/
460 #define DIRECTDIRACCESS "%s%d" G_DIR_SEPARATOR_S "%d" G_DIR_SEPARATOR_S "%d%s"
461 #define DIRECTDIRACCESS_WITH_NAME "%s%s" G_DIR_SEPARATOR_S "%d" G_DIR_SEPARATOR_S "%d" G_DIR_SEPARATOR_S "%d%s"
462 #define DIRSTRUCTURE "%st%ds%dz%d" G_DIR_SEPARATOR_S "%d" G_DIR_SEPARATOR_S "%d"
463 #define MAPS_CACHE_DIR maps_layer_default_dir()
467 #define GLOBAL_MAPS_DIR "C:\\VIKING-MAPS\\"
468 #define LOCAL_MAPS_DIR "VIKING-MAPS"
469 #elif defined __APPLE__
471 #define GLOBAL_MAPS_DIR "/Library/cache/Viking/maps/"
472 #define LOCAL_MAPS_DIR "/Library/Application Support/Viking/viking-maps"
475 #define GLOBAL_MAPS_DIR "/var/cache/maps/"
476 #define LOCAL_MAPS_DIR ".viking-maps"
479 gchar *maps_layer_default_dir ()
481 static gchar *defaultdir = NULL;
484 /* Thanks to Mike Davison for the $VIKING_MAPS usage */
485 const gchar *mapdir = g_getenv("VIKING_MAPS");
487 defaultdir = g_strdup ( mapdir );
488 } else if ( g_access ( GLOBAL_MAPS_DIR, W_OK ) == 0 ) {
489 defaultdir = g_strdup ( GLOBAL_MAPS_DIR );
491 const gchar *home = g_get_home_dir();
492 if (!home || g_access(home, W_OK))
493 home = g_get_home_dir ();
495 defaultdir = g_build_filename ( home, LOCAL_MAPS_DIR, NULL );
497 defaultdir = g_strdup ( LOCAL_MAPS_DIR );
499 if (defaultdir && (defaultdir[strlen(defaultdir)-1] != G_DIR_SEPARATOR))
501 /* Add the separator at the end */
502 gchar *tmp = defaultdir;
503 defaultdir = g_strconcat(tmp, G_DIR_SEPARATOR_S, NULL);
506 g_debug("%s: defaultdir=%s", __FUNCTION__, defaultdir);
511 static void maps_layer_mkdir_if_default_dir ( VikMapsLayer *vml )
513 if ( vml->cache_dir && strcmp ( vml->cache_dir, MAPS_CACHE_DIR ) == 0 && g_file_test ( vml->cache_dir, G_FILE_TEST_EXISTS ) == FALSE )
515 g_mkdir ( vml->cache_dir, 0777 );
519 static void maps_layer_set_cache_dir ( VikMapsLayer *vml, const gchar *dir )
521 g_assert ( vml != NULL);
522 g_free ( vml->cache_dir );
523 vml->cache_dir = NULL;
524 const gchar *mydir = dir;
526 if ( dir == NULL || dir[0] == '\0' )
528 if ( a_preferences_get(VIKING_PREFERENCES_NAMESPACE "maplayer_default_dir") )
529 mydir = a_preferences_get(VIKING_PREFERENCES_NAMESPACE "maplayer_default_dir")->s;
532 gchar *canonical_dir = vu_get_canonical_filename ( VIK_LAYER(vml), mydir );
534 // Ensure cache_dir always ends with a separator
535 guint len = strlen(canonical_dir);
536 if ( canonical_dir[len-1] != G_DIR_SEPARATOR )
538 vml->cache_dir = g_strconcat ( canonical_dir, G_DIR_SEPARATOR_S, NULL );
539 g_free ( canonical_dir );
542 vml->cache_dir = canonical_dir;
545 maps_layer_mkdir_if_default_dir ( vml );
548 static void maps_layer_set_file ( VikMapsLayer *vml, const gchar *name )
551 g_free (vml->filename);
552 vml->filename = g_strdup (name);
555 /****************************************/
556 /******** GOBJECT STUFF *****************/
557 /****************************************/
559 GType vik_maps_layer_get_type ()
561 static GType vml_type = 0;
565 static const GTypeInfo vml_info =
567 sizeof (VikMapsLayerClass),
568 NULL, /* base_init */
569 NULL, /* base_finalize */
570 NULL, /* class init */
571 NULL, /* class_finalize */
572 NULL, /* class_data */
573 sizeof (VikMapsLayer),
575 NULL /* instance init */
577 vml_type = g_type_register_static ( VIK_LAYER_TYPE, "VikMapsLayer", &vml_info, 0 );
583 /****************************************/
584 /************** PARAMETERS **************/
585 /****************************************/
587 static guint map_index_to_uniq_id (guint16 index)
589 g_assert ( index < NUM_MAP_TYPES );
590 return vik_map_source_get_uniq_id(MAPS_LAYER_NTH_TYPE(index));
593 static guint map_uniq_id_to_index ( guint uniq_id )
596 for ( i = 0; i < NUM_MAP_TYPES; i++ )
597 if ( vik_map_source_get_uniq_id(MAPS_LAYER_NTH_TYPE(i)) == uniq_id )
599 return NUM_MAP_TYPES; /* no such thing */
602 #define VIK_SETTINGS_MAP_LICENSE_SHOWN "map_license_shown"
605 * Convenience function to display the license
607 static void maps_show_license ( GtkWindow *parent, VikMapSource *map )
609 a_dialog_license ( parent,
610 vik_map_source_get_label (map),
611 vik_map_source_get_license (map),
612 vik_map_source_get_license_url (map) );
615 static gboolean maps_layer_set_param ( VikMapsLayer *vml, guint16 id, VikLayerParamData data, VikViewport *vvp, gboolean is_file_operation )
619 case PARAM_CACHE_DIR: maps_layer_set_cache_dir ( vml, data.s ); break;
620 case PARAM_CACHE_LAYOUT: if ( data.u < VIK_MAPS_CACHE_LAYOUT_NUM ) vml->cache_layout = data.u; break;
621 case PARAM_FILE: maps_layer_set_file ( vml, data.s ); break;
622 case PARAM_MAPTYPE: {
623 gint maptype = map_uniq_id_to_index(data.u);
624 if ( maptype == NUM_MAP_TYPES )
625 g_warning(_("Unknown map type"));
627 vml->maptype = maptype;
629 // When loading from a file don't need the license reminder - ensure it's saved into the 'seen' list
630 if ( is_file_operation ) {
631 a_settings_set_integer_list_containing ( VIK_SETTINGS_MAP_LICENSE_SHOWN, data.u );
634 VikMapSource *map = MAPS_LAYER_NTH_TYPE(vml->maptype);
635 if (vik_map_source_get_license (map) != NULL) {
636 // Check if licence for this map type has been shown before
637 if ( ! a_settings_get_integer_list_contains ( VIK_SETTINGS_MAP_LICENSE_SHOWN, data.u ) ) {
639 maps_show_license ( VIK_GTK_WINDOW_FROM_WIDGET(vvp), map );
640 a_settings_set_integer_list_containing ( VIK_SETTINGS_MAP_LICENSE_SHOWN, data.u );
647 case PARAM_ALPHA: if ( data.u <= 255 ) vml->alpha = data.u; break;
648 case PARAM_AUTODOWNLOAD: vml->autodownload = data.b; break;
649 case PARAM_ONLYMISSING: vml->adl_only_missing = data.b; break;
650 case PARAM_MAPZOOM: if ( data.u < NUM_MAPZOOMS ) {
651 vml->mapzoom_id = data.u;
652 vml->xmapzoom = __mapzooms_x [data.u];
653 vml->ymapzoom = __mapzooms_y [data.u];
654 }else g_warning (_("Unknown Map Zoom")); break;
660 static VikLayerParamData maps_layer_get_param ( VikMapsLayer *vml, guint16 id, gboolean is_file_operation )
662 VikLayerParamData rv;
665 case PARAM_CACHE_DIR:
667 gboolean set = FALSE;
668 /* Only save a blank when the map cache location equals the default
669 On reading in, when it is blank then the default is reconstructed
670 Since the default changes dependent on the user and OS, it means the resultant file is more portable */
671 if ( is_file_operation && vml->cache_dir && strcmp ( vml->cache_dir, MAPS_CACHE_DIR ) == 0 ) {
675 else if ( is_file_operation ) {
676 if ( a_vik_get_file_ref_format() == VIK_FILE_REF_FORMAT_RELATIVE ) {
677 gchar *cwd = g_get_current_dir();
679 rv.s = file_GetRelativeFilename ( cwd, vml->cache_dir );
680 if ( !rv.s ) rv.s = "";
686 rv.s = vml->cache_dir ? vml->cache_dir : "";
689 case PARAM_CACHE_LAYOUT: rv.u = vml->cache_layout; break;
690 case PARAM_FILE: rv.s = vml->filename; break;
691 case PARAM_MAPTYPE: rv.u = map_index_to_uniq_id ( vml->maptype ); break;
692 case PARAM_ALPHA: rv.u = vml->alpha; break;
693 case PARAM_AUTODOWNLOAD: rv.u = vml->autodownload; break;
694 case PARAM_ONLYMISSING: rv.u = vml->adl_only_missing; break;
695 case PARAM_MAPZOOM: rv.u = vml->mapzoom_id; break;
701 static void maps_layer_change_param ( GtkWidget *widget, ui_change_values values )
703 switch ( GPOINTER_TO_INT(values[UI_CHG_PARAM_ID]) ) {
704 // Alter sensitivity of download option widgets according to the maptype setting.
705 case PARAM_MAPTYPE: {
707 VikLayerParamData vlpd = a_uibuilder_widget_get_value ( widget, values[UI_CHG_PARAM] );
708 // Is it *not* the OSM On Disk Tile Layout or the MBTiles type or the OSM Metatiles type
709 gboolean sensitive = ( 21 != vlpd.u && 23 != vlpd.u && 24 != vlpd.u );
710 GtkWidget **ww1 = values[UI_CHG_WIDGETS];
711 GtkWidget **ww2 = values[UI_CHG_LABELS];
712 GtkWidget *w1 = ww1[PARAM_ONLYMISSING];
713 GtkWidget *w2 = ww2[PARAM_ONLYMISSING];
714 GtkWidget *w3 = ww1[PARAM_AUTODOWNLOAD];
715 GtkWidget *w4 = ww2[PARAM_AUTODOWNLOAD];
716 // Depends on autodownload value
717 gboolean missing_sense = sensitive && VIK_MAPS_LAYER(values[UI_CHG_LAYER])->autodownload;
718 if ( w1 ) gtk_widget_set_sensitive ( w1, missing_sense );
719 if ( w2 ) gtk_widget_set_sensitive ( w2, missing_sense );
720 if ( w3 ) gtk_widget_set_sensitive ( w3, sensitive );
721 if ( w4 ) gtk_widget_set_sensitive ( w4, sensitive );
723 // Cache type not applicable either
724 GtkWidget *w9 = ww1[PARAM_CACHE_LAYOUT];
725 GtkWidget *w10 = ww2[PARAM_CACHE_LAYOUT];
726 if ( w9 ) gtk_widget_set_sensitive ( w9, sensitive );
727 if ( w10 ) gtk_widget_set_sensitive ( w10, sensitive );
729 // File only applicable for MBTiles type
730 // Directory for all other types
731 sensitive = ( 23 == vlpd.u);
732 GtkWidget *w5 = ww1[PARAM_FILE];
733 GtkWidget *w6 = ww2[PARAM_FILE];
734 GtkWidget *w7 = ww1[PARAM_CACHE_DIR];
735 GtkWidget *w8 = ww2[PARAM_CACHE_DIR];
736 if ( w5 ) gtk_widget_set_sensitive ( w5, sensitive );
737 if ( w6 ) gtk_widget_set_sensitive ( w6, sensitive );
738 if ( w7 ) gtk_widget_set_sensitive ( w7, !sensitive );
739 if ( w8 ) gtk_widget_set_sensitive ( w8, !sensitive );
744 // Alter sensitivity of 'download only missing' widgets according to the autodownload setting.
745 case PARAM_AUTODOWNLOAD: {
747 VikLayerParamData vlpd = a_uibuilder_widget_get_value ( widget, values[UI_CHG_PARAM] );
748 GtkWidget **ww1 = values[UI_CHG_WIDGETS];
749 GtkWidget **ww2 = values[UI_CHG_LABELS];
750 GtkWidget *w1 = ww1[PARAM_ONLYMISSING];
751 GtkWidget *w2 = ww2[PARAM_ONLYMISSING];
752 if ( w1 ) gtk_widget_set_sensitive ( w1, vlpd.b );
753 if ( w2 ) gtk_widget_set_sensitive ( w2, vlpd.b );
760 /****************************************/
761 /****** CREATING, COPYING, FREEING ******/
762 /****************************************/
764 static VikMapsLayer *maps_layer_new ( VikViewport *vvp )
766 VikMapsLayer *vml = VIK_MAPS_LAYER ( g_object_new ( VIK_MAPS_LAYER_TYPE, NULL ) );
767 vik_layer_set_type ( VIK_LAYER(vml), VIK_LAYER_MAPS );
769 vik_layer_set_defaults ( VIK_LAYER(vml), vvp );
771 vml->dl_tool_x = vml->dl_tool_y = -1;
772 vml->last_center = NULL;
773 vml->last_xmpp = 0.0;
774 vml->last_ympp = 0.0;
776 vml->dl_right_click_menu = NULL;
777 vml->filename = NULL;
781 static void maps_layer_free ( VikMapsLayer *vml )
783 g_free ( vml->cache_dir );
784 vml->cache_dir = NULL;
785 if ( vml->dl_right_click_menu )
786 g_object_ref_sink ( G_OBJECT(vml->dl_right_click_menu) );
787 g_free(vml->last_center);
788 vml->last_center = NULL;
789 g_free ( vml->filename );
790 vml->filename = NULL;
792 #ifdef HAVE_SQLITE3_H
793 VikMapSource *map = MAPS_LAYER_NTH_TYPE(vml->maptype);
794 if ( vik_map_source_is_mbtiles ( map ) ) {
795 if ( vml->mbtiles ) {
796 int ans = sqlite3_close ( vml->mbtiles );
797 if ( ans != SQLITE_OK ) {
798 // Only to console for information purposes only
799 g_warning ( "SQL Close problem: %d", ans );
806 static void maps_layer_post_read (VikLayer *vl, VikViewport *vp, gboolean from_file)
808 VikMapsLayer *vml = VIK_MAPS_LAYER(vl);
809 VikMapSource *map = MAPS_LAYER_NTH_TYPE(vml->maptype);
813 /* If this method is not called in file reading context
814 * it is called in GUI context.
815 * So, we can check if we have to inform the user about inconsistency */
816 VikViewportDrawMode vp_drawmode;
817 vp_drawmode = vik_viewport_get_drawmode ( vp );
819 if (vik_map_source_get_drawmode(map) != vp_drawmode) {
820 const gchar *drawmode_name = vik_viewport_get_drawmode_name (vp, vik_map_source_get_drawmode(map));
821 gchar *msg = g_strdup_printf(_("New map cannot be displayed in the current drawmode.\nSelect \"%s\" from View menu to view it."), drawmode_name);
822 a_dialog_warning_msg ( VIK_GTK_WINDOW_FROM_WIDGET(vp), msg );
827 // Performed in post read as we now know the map type
828 #ifdef HAVE_SQLITE3_H
830 if ( vik_map_source_is_mbtiles ( map ) ) {
831 int ans = sqlite3_open_v2 ( vml->filename,
833 SQLITE_OPEN_READONLY,
835 if ( ans != SQLITE_OK ) {
836 // That didn't work, so here's why:
837 g_warning ( "%s: %s", __FUNCTION__, sqlite3_errmsg ( vml->mbtiles ) );
839 a_dialog_error_msg_extra ( VIK_GTK_WINDOW_FROM_WIDGET(vp),
840 _("Failed to open MBTiles file: %s"),
847 // If the on Disk OSM Tile Layout type
848 if ( vml->maptype == 21 )
849 // Copy the directory into filename
850 // thus the mapcache look up will be unique when using more than one of these map types
851 vml->filename = g_strdup (vml->cache_dir);
854 static const gchar* maps_layer_tooltip ( VikMapsLayer *vml )
856 return vik_maps_layer_get_map_label ( vml );
859 static void maps_layer_marshall( VikMapsLayer *vml, guint8 **data, gint *len )
861 vik_layer_marshall_params ( VIK_LAYER(vml), data, len );
864 static VikMapsLayer *maps_layer_unmarshall( guint8 *data, gint len, VikViewport *vvp )
866 VikMapsLayer *rv = maps_layer_new ( vvp );
867 vik_layer_unmarshall_params ( VIK_LAYER(rv), data, len, vvp );
868 maps_layer_post_read ( VIK_LAYER(rv), vvp, FALSE );
872 /*********************/
873 /****** DRAWING ******/
874 /*********************/
876 static GdkPixbuf *pixbuf_shrink ( GdkPixbuf *pixbuf, gdouble xshrinkfactor, gdouble yshrinkfactor )
879 guint16 width = gdk_pixbuf_get_width(pixbuf), height = gdk_pixbuf_get_height(pixbuf);
880 tmp = gdk_pixbuf_scale_simple(pixbuf, ceil(width * xshrinkfactor), ceil(height * yshrinkfactor), GDK_INTERP_BILINEAR);
881 g_object_unref ( G_OBJECT(pixbuf) );
885 #ifdef HAVE_SQLITE3_H
887 static int sql_select_tile_dump_cb (void *data, int cols, char **fields, char **col_names )
889 g_warning ( "Found %d columns", cols );
891 for ( i = 0; i < cols; i++ ) {
892 g_warning ( "SQL processing %s = %s", col_names[i], fields[i] );
901 static GdkPixbuf *get_pixbuf_sql_exec ( sqlite3 *sql, gint xx, gint yy, gint zoom )
903 GdkPixbuf *pixbuf = NULL;
905 // MBTiles stored internally with the flipping y thingy (i.e. TMS scheme).
906 gint flip_y = (gint) pow(2, zoom)-1 - yy;
907 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 );
909 gboolean finished = FALSE;
911 sqlite3_stmt *sql_stmt = NULL;
912 int ans = sqlite3_prepare_v2 ( sql, statement, -1, &sql_stmt, NULL );
913 if ( ans != SQLITE_OK ) {
914 g_warning ( "%s: %s - %d", __FUNCTION__, "prepare failure", ans );
918 while ( !finished ) {
919 ans = sqlite3_step ( sql_stmt );
922 // Get tile_data blob
923 int count = sqlite3_column_count(sql_stmt);
925 g_warning ( "%s: %s - %d", __FUNCTION__, "count not one", count );
929 const void *data = sqlite3_column_blob ( sql_stmt, 0 );
930 int bytes = sqlite3_column_bytes ( sql_stmt, 0 );
932 g_warning ( "%s: %s (%d)", __FUNCTION__, "not enough bytes", bytes );
936 // Convert these blob bytes into a pixbuf via these streaming operations
937 GInputStream *stream = g_memory_input_stream_new_from_data ( data, bytes, NULL );
938 GError *error = NULL;
939 pixbuf = gdk_pixbuf_new_from_stream ( stream, NULL, &error );
940 if (error || (!pixbuf)) {
941 g_warning ( "%s: %s", __FUNCTION__, error->message );
942 g_error_free ( error );
944 g_input_stream_close ( stream, NULL, NULL );
950 // e.g. SQLITE_DONE | SQLITE_ERROR | SQLITE_MISUSE | etc...
952 // and give up on any errors
953 if ( ans != SQLITE_DONE )
954 g_warning ( "%s: %s - %d", __FUNCTION__, "step issue", ans );
959 ans = sqlite3_finalize ( sql_stmt );
961 g_free ( statement );
967 static GdkPixbuf *get_mbtiles_pixbuf ( VikMapsLayer *vml, gint xx, gint yy, gint zoom )
969 GdkPixbuf *pixbuf = NULL;
971 #ifdef HAVE_SQLITE3_H
972 if ( vml->mbtiles ) {
974 gchar *statement = g_strdup_printf ( "SELECT name FROM sqlite_master WHERE type='table';" );
976 int ans = sqlite3_exec ( vml->mbtiles, statement, sql_select_tile_dump_cb, pixbuf, &errMsg );
977 if ( ans != SQLITE_OK ) {
978 // Only to console for information purposes only
979 g_warning ( "SQL problem: %d for %s - error: %s", ans, statement, errMsg );
980 sqlite3_free( errMsg );
982 g_free ( statement );
985 // Reading BLOBS is a bit more involved and so can't use the simpler sqlite3_exec ()
986 // Hence this specific function
987 pixbuf = get_pixbuf_sql_exec ( vml->mbtiles, xx, yy, zoom );
994 static GdkPixbuf *get_pixbuf_from_metatile ( VikMapsLayer *vml, gint xx, gint yy, gint zz )
996 const int tile_max = METATILE_MAX_SIZE;
997 char err_msg[PATH_MAX];
1002 buf = malloc(tile_max);
1008 len = metatile_read(vml->cache_dir, xx, yy, zz, buf, tile_max, &compressed, err_msg);
1012 // Not handled yet - I don't think this is used often - so implement later if necessary
1013 g_warning ( "Compressed metatiles not implemented:%s\n", __FUNCTION__);
1017 // Convert these buf bytes into a pixbuf via these streaming operations
1018 GdkPixbuf *pixbuf = NULL;
1020 GInputStream *stream = g_memory_input_stream_new_from_data ( buf, len, NULL );
1021 GError *error = NULL;
1022 pixbuf = gdk_pixbuf_new_from_stream ( stream, NULL, &error );
1023 if (error || (!pixbuf)) {
1024 g_warning ( "%s: %s", __FUNCTION__, error->message );
1025 g_error_free ( error );
1027 g_input_stream_close ( stream, NULL, NULL );
1033 g_warning ( "FAILED:%s %s", __FUNCTION__, err_msg);
1039 static GdkPixbuf *pixbuf_apply_settings ( GdkPixbuf *pixbuf, VikMapsLayer *vml, MapCoord *mapcoord, gdouble xshrinkfactor, gdouble yshrinkfactor )
1041 // Apply alpha setting
1042 if ( pixbuf && vml->alpha < 255 )
1043 pixbuf = ui_pixbuf_set_alpha ( pixbuf, vml->alpha );
1045 if ( pixbuf && ( xshrinkfactor != 1.0 || yshrinkfactor != 1.0 ) )
1046 pixbuf = pixbuf_shrink ( pixbuf, xshrinkfactor, yshrinkfactor );
1049 a_mapcache_add ( pixbuf, mapcoord->x, mapcoord->y,
1050 mapcoord->z, vik_map_source_get_uniq_id(MAPS_LAYER_NTH_TYPE(vml->maptype)),
1051 mapcoord->scale, vml->alpha, xshrinkfactor, yshrinkfactor, vml->filename );
1056 static void get_filename ( const gchar *cache_dir,
1057 VikMapsCacheLayout cl,
1064 gchar *filename_buf,
1066 const gchar* file_extension )
1069 case VIK_MAPS_CACHE_LAYOUT_OSM:
1071 if ( g_strcmp0 ( cache_dir, MAPS_CACHE_DIR ) )
1072 // Cache dir not the default - assume it's been directed somewhere specific
1073 g_snprintf ( filename_buf, buf_len, DIRECTDIRACCESS, cache_dir, (17 - scale), x, y, file_extension );
1075 // Using default cache - so use the map name in the directory path
1076 g_snprintf ( filename_buf, buf_len, DIRECTDIRACCESS_WITH_NAME, cache_dir, name, (17 - scale), x, y, file_extension );
1079 g_snprintf ( filename_buf, buf_len, DIRECTDIRACCESS, cache_dir, (17 - scale), x, y, file_extension );
1082 g_snprintf ( filename_buf, buf_len, DIRSTRUCTURE, cache_dir, id, scale, z, x, y );
1087 static GdkPixbuf *get_pixbuf( VikMapsLayer *vml, guint16 id, const gchar* mapname, MapCoord *mapcoord, gchar *filename_buf, gint buf_len, gdouble xshrinkfactor, gdouble yshrinkfactor )
1092 pixbuf = a_mapcache_get ( mapcoord->x, mapcoord->y, mapcoord->z,
1093 id, mapcoord->scale, vml->alpha, xshrinkfactor, yshrinkfactor, vml->filename );
1096 VikMapSource *map = MAPS_LAYER_NTH_TYPE(vml->maptype);
1097 if ( vik_map_source_is_direct_file_access(map) ) {
1098 // ATM MBTiles must be 'a direct access type'
1099 if ( vik_map_source_is_mbtiles(map) ) {
1100 pixbuf = get_mbtiles_pixbuf ( vml, mapcoord->x, mapcoord->y, (17 - mapcoord->scale) );
1101 pixbuf = pixbuf_apply_settings ( pixbuf, vml, mapcoord, xshrinkfactor, yshrinkfactor );
1102 // return now to avoid file tests that aren't appropriate for this map type
1105 else if ( vik_map_source_is_osm_meta_tiles(map) ) {
1106 pixbuf = get_pixbuf_from_metatile ( vml, mapcoord->x, mapcoord->y, (17 - mapcoord->scale) );
1107 pixbuf = pixbuf_apply_settings ( pixbuf, vml, mapcoord, xshrinkfactor, yshrinkfactor );
1111 get_filename ( vml->cache_dir, VIK_MAPS_CACHE_LAYOUT_OSM, id, NULL,
1112 mapcoord->scale, mapcoord->z, mapcoord->x, mapcoord->y, filename_buf, buf_len,
1113 vik_map_source_get_file_extension(map) );
1116 get_filename ( vml->cache_dir, vml->cache_layout, id, mapname,
1117 mapcoord->scale, mapcoord->z, mapcoord->x, mapcoord->y, filename_buf, buf_len,
1118 vik_map_source_get_file_extension(map) );
1120 if ( g_file_test ( filename_buf, G_FILE_TEST_EXISTS ) == TRUE)
1123 pixbuf = gdk_pixbuf_new_from_file ( filename_buf, &gx );
1125 /* free the pixbuf on error */
1128 if ( gx->domain != GDK_PIXBUF_ERROR || gx->code != GDK_PIXBUF_ERROR_CORRUPT_IMAGE ) {
1130 if ( IS_VIK_WINDOW ((VikWindow*)VIK_GTK_WINDOW_FROM_LAYER(vml)) ) {
1131 gchar* msg = g_strdup_printf ( _("Couldn't open image file: %s"), gx->message );
1132 vik_window_statusbar_update ( (VikWindow*)VIK_GTK_WINDOW_FROM_LAYER(vml), msg, VIK_STATUSBAR_INFO );
1137 g_error_free ( gx );
1139 g_object_unref ( G_OBJECT(pixbuf) );
1142 pixbuf = pixbuf_apply_settings ( pixbuf, vml, mapcoord, xshrinkfactor, yshrinkfactor );
1149 static gboolean should_start_autodownload(VikMapsLayer *vml, VikViewport *vvp)
1151 const VikCoord *center = vik_viewport_get_center ( vvp );
1153 if (vik_window_get_pan_move (VIK_WINDOW(VIK_GTK_WINDOW_FROM_WIDGET(GTK_WIDGET(vvp)))))
1154 /* D'n'D pan in action: do not download */
1157 // Don't attempt to download unsupported zoom levels
1158 gdouble xzoom = vik_viewport_get_xmpp ( vvp );
1159 VikMapSource *map = MAPS_LAYER_NTH_TYPE(vml->maptype);
1160 guint8 zl = map_utils_mpp_to_zoom_level ( xzoom );
1161 if ( zl < vik_map_source_get_zoom_min(map) || zl > vik_map_source_get_zoom_max(map) )
1164 if (vml->last_center == NULL) {
1165 VikCoord *new_center = g_malloc(sizeof(VikCoord));
1166 *new_center = *center;
1167 vml->last_center = new_center;
1168 vml->last_xmpp = vik_viewport_get_xmpp(vvp);
1169 vml->last_ympp = vik_viewport_get_ympp(vvp);
1173 /* TODO: perhaps vik_coord_diff() */
1174 if (vik_coord_equals(vml->last_center, center)
1175 && (vml->last_xmpp == vik_viewport_get_xmpp(vvp))
1176 && (vml->last_ympp == vik_viewport_get_ympp(vvp)))
1179 *(vml->last_center) = *center;
1180 vml->last_xmpp = vik_viewport_get_xmpp(vvp);
1181 vml->last_ympp = vik_viewport_get_ympp(vvp);
1188 gboolean try_draw_scale_down (VikMapsLayer *vml, VikViewport *vvp, MapCoord ulm, gint xx, gint yy, gint tilesize_x_ceil, gint tilesize_y_ceil,
1189 gdouble xshrinkfactor, gdouble yshrinkfactor, guint id, const gchar *mapname, gchar *path_buf, guint max_path_len)
1193 for (scale_inc = 1; scale_inc < SCALE_INC_DOWN; scale_inc ++) {
1194 // Try with smaller zooms
1195 int scale_factor = 1 << scale_inc; /* 2^scale_inc */
1196 MapCoord ulm2 = ulm;
1197 ulm2.x = ulm.x / scale_factor;
1198 ulm2.y = ulm.y / scale_factor;
1199 ulm2.scale = ulm.scale + scale_inc;
1200 pixbuf = get_pixbuf ( vml, id, mapname, &ulm2, path_buf, max_path_len, xshrinkfactor * scale_factor, yshrinkfactor * scale_factor );
1202 gint src_x = (ulm.x % scale_factor) * tilesize_x_ceil;
1203 gint src_y = (ulm.y % scale_factor) * tilesize_y_ceil;
1204 vik_viewport_draw_pixbuf ( vvp, pixbuf, src_x, src_y, xx, yy, tilesize_x_ceil, tilesize_y_ceil );
1214 gboolean try_draw_scale_up (VikMapsLayer *vml, VikViewport *vvp, MapCoord ulm, gint xx, gint yy, gint tilesize_x_ceil, gint tilesize_y_ceil,
1215 gdouble xshrinkfactor, gdouble yshrinkfactor, guint id, const gchar *mapname, gchar *path_buf, guint max_path_len)
1218 // Try with bigger zooms
1220 for (scale_dec = 1; scale_dec < SCALE_INC_UP; scale_dec ++) {
1222 int scale_factor = 1 << scale_dec; /* 2^scale_dec */
1223 MapCoord ulm2 = ulm;
1224 ulm2.x = ulm.x * scale_factor;
1225 ulm2.y = ulm.y * scale_factor;
1226 ulm2.scale = ulm.scale - scale_dec;
1227 for (pict_x = 0; pict_x < scale_factor; pict_x ++) {
1228 for (pict_y = 0; pict_y < scale_factor; pict_y ++) {
1229 MapCoord ulm3 = ulm2;
1232 pixbuf = get_pixbuf ( vml, id, mapname, &ulm3, path_buf, max_path_len, xshrinkfactor / scale_factor, yshrinkfactor / scale_factor );
1236 gint dest_x = xx + pict_x * (tilesize_x_ceil / scale_factor);
1237 gint dest_y = yy + pict_y * (tilesize_y_ceil / scale_factor);
1238 vik_viewport_draw_pixbuf ( vvp, pixbuf, src_x, src_y, dest_x, dest_y, tilesize_x_ceil / scale_factor, tilesize_y_ceil / scale_factor );
1247 static void maps_layer_draw_section ( VikMapsLayer *vml, VikViewport *vvp, VikCoord *ul, VikCoord *br )
1250 gdouble xzoom = vik_viewport_get_xmpp ( vvp );
1251 gdouble yzoom = vik_viewport_get_ympp ( vvp );
1252 gdouble xshrinkfactor = 1.0, yshrinkfactor = 1.0;
1253 gboolean existence_only = FALSE;
1255 if ( vml->xmapzoom && (vml->xmapzoom != xzoom || vml->ymapzoom != yzoom) ) {
1256 xshrinkfactor = vml->xmapzoom / xzoom;
1257 yshrinkfactor = vml->ymapzoom / yzoom;
1258 xzoom = vml->xmapzoom;
1259 yzoom = vml->xmapzoom;
1260 if ( ! (xshrinkfactor > MIN_SHRINKFACTOR && xshrinkfactor < MAX_SHRINKFACTOR &&
1261 yshrinkfactor > MIN_SHRINKFACTOR && yshrinkfactor < MAX_SHRINKFACTOR ) ) {
1262 if ( xshrinkfactor > REAL_MIN_SHRINKFACTOR && yshrinkfactor > REAL_MIN_SHRINKFACTOR ) {
1263 g_debug ( "%s: existence_only due to SHRINKFACTORS", __FUNCTION__ );
1264 existence_only = TRUE;
1267 // Report the reason for not drawing
1268 if ( IS_VIK_WINDOW ((VikWindow*)VIK_GTK_WINDOW_FROM_LAYER(vml)) ) {
1269 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));
1270 vik_window_statusbar_update ( (VikWindow*)VIK_GTK_WINDOW_FROM_LAYER(vml), msg, VIK_STATUSBAR_INFO );
1279 VikMapSource *map = MAPS_LAYER_NTH_TYPE(vml->maptype);
1280 if ( vik_map_source_coord_to_mapcoord ( map, ul, xzoom, yzoom, &ulm ) &&
1281 vik_map_source_coord_to_mapcoord ( map, br, xzoom, yzoom, &brm ) ) {
1285 gint xmin = MIN(ulm.x, brm.x), xmax = MAX(ulm.x, brm.x);
1286 gint ymin = MIN(ulm.y, brm.y), ymax = MAX(ulm.y, brm.y);
1287 guint16 id = vik_map_source_get_uniq_id(map);
1288 const gchar *mapname = vik_map_source_get_name(map);
1291 gint xx, yy, width, height;
1294 // Prevent the program grinding to a halt if trying to deal with thousands of tiles
1295 // which can happen when using a small fixed zoom level and viewing large areas.
1296 // Also prevents very large number of tile download requests
1297 gint tiles = (xmax-xmin) * (ymax-ymin);
1298 if ( tiles > MAX_TILES ) {
1299 g_debug ( "%s: existence_only due to wanting too many tiles (%d)", __FUNCTION__, tiles );
1300 existence_only = TRUE;
1303 guint max_path_len = strlen(vml->cache_dir) + 40;
1304 gchar *path_buf = g_malloc ( max_path_len * sizeof(char) );
1306 if ( (!existence_only) && vml->autodownload && should_start_autodownload(vml, vvp)) {
1307 g_debug("%s: Starting autodownload", __FUNCTION__);
1308 if ( !vml->adl_only_missing && vik_map_source_supports_download_only_new (map) )
1309 // Try to download newer tiles
1310 start_download_thread ( vml, vvp, ul, br, REDOWNLOAD_NEW );
1312 // Download only missing tiles
1313 start_download_thread ( vml, vvp, ul, br, REDOWNLOAD_NONE );
1316 if ( vik_map_source_get_tilesize_x(map) == 0 && !existence_only ) {
1317 for ( x = xmin; x <= xmax; x++ ) {
1318 for ( y = ymin; y <= ymax; y++ ) {
1321 pixbuf = get_pixbuf ( vml, id, mapname, &ulm, path_buf, max_path_len, xshrinkfactor, yshrinkfactor );
1323 width = gdk_pixbuf_get_width ( pixbuf );
1324 height = gdk_pixbuf_get_height ( pixbuf );
1326 vik_map_source_mapcoord_to_center_coord ( map, &ulm, &coord );
1327 vik_viewport_coord_to_screen ( vvp, &coord, &xx, &yy );
1331 vik_viewport_draw_pixbuf ( vvp, pixbuf, 0, 0, xx, yy, width, height );
1335 } else { /* tilesize is known, don't have to keep converting coords */
1336 gdouble tilesize_x = vik_map_source_get_tilesize_x(map) * xshrinkfactor;
1337 gdouble tilesize_y = vik_map_source_get_tilesize_y(map) * yshrinkfactor;
1338 /* ceiled so tiles will be maximum size in the case of funky shrinkfactor */
1339 gint tilesize_x_ceil = ceil ( tilesize_x );
1340 gint tilesize_y_ceil = ceil ( tilesize_y );
1341 gint8 xinc = (ulm.x == xmin) ? 1 : -1;
1342 gint8 yinc = (ulm.y == ymin) ? 1 : -1;
1343 gint xx_tmp, yy_tmp;
1344 gint base_yy, xend, yend;
1346 xend = (xinc == 1) ? (xmax+1) : (xmin-1);
1347 yend = (yinc == 1) ? (ymax+1) : (ymin-1);
1349 vik_map_source_mapcoord_to_center_coord ( map, &ulm, &coord );
1350 vik_viewport_coord_to_screen ( vvp, &coord, &xx_tmp, &yy_tmp );
1351 xx = xx_tmp; yy = yy_tmp;
1352 /* above trick so xx,yy doubles. this is so shrinkfactors aren't rounded off
1353 * eg if tile size 128, shrinkfactor 0.333 */
1354 xx -= (tilesize_x/2);
1355 base_yy = yy - (tilesize_y/2);
1357 for ( x = ((xinc == 1) ? xmin : xmax); x != xend; x+=xinc ) {
1359 for ( y = ((yinc == 1) ? ymin : ymax); y != yend; y+=yinc ) {
1363 if ( existence_only ) {
1364 if ( vik_map_source_is_direct_file_access (MAPS_LAYER_NTH_TYPE(vml->maptype)) )
1365 get_filename ( vml->cache_dir, VIK_MAPS_CACHE_LAYOUT_OSM, id, vik_map_source_get_name(map),
1366 ulm.scale, ulm.z, ulm.x, ulm.y, path_buf, max_path_len, vik_map_source_get_file_extension(map) );
1368 get_filename ( vml->cache_dir, vml->cache_layout, id, vik_map_source_get_name(map),
1369 ulm.scale, ulm.z, ulm.x, ulm.y, path_buf, max_path_len, vik_map_source_get_file_extension(map) );
1371 if ( g_file_test ( path_buf, G_FILE_TEST_EXISTS ) == TRUE ) {
1372 GdkGC *black_gc = gtk_widget_get_style(GTK_WIDGET(vvp))->black_gc;
1373 vik_viewport_draw_line ( vvp, black_gc, xx+tilesize_x_ceil, yy, xx, yy+tilesize_y_ceil );
1376 // Try correct scale first
1377 int scale_factor = 1;
1378 pixbuf = get_pixbuf ( vml, id, mapname, &ulm, path_buf, max_path_len, xshrinkfactor * scale_factor, yshrinkfactor * scale_factor );
1380 gint src_x = (ulm.x % scale_factor) * tilesize_x_ceil;
1381 gint src_y = (ulm.y % scale_factor) * tilesize_y_ceil;
1382 vik_viewport_draw_pixbuf ( vvp, pixbuf, src_x, src_y, xx, yy, tilesize_x_ceil, tilesize_y_ceil );
1385 // Otherwise try different scales
1386 if ( SCALE_SMALLER_ZOOM_FIRST ) {
1387 if ( !try_draw_scale_down(vml,vvp,ulm,xx,yy,tilesize_x_ceil,tilesize_y_ceil,xshrinkfactor,yshrinkfactor,id,mapname,path_buf,max_path_len) ) {
1388 try_draw_scale_up(vml,vvp,ulm,xx,yy,tilesize_x_ceil,tilesize_y_ceil,xshrinkfactor,yshrinkfactor,id,mapname,path_buf,max_path_len);
1392 if ( !try_draw_scale_up(vml,vvp,ulm,xx,yy,tilesize_x_ceil,tilesize_y_ceil,xshrinkfactor,yshrinkfactor,id,mapname,path_buf,max_path_len) ) {
1393 try_draw_scale_down(vml,vvp,ulm,xx,yy,tilesize_x_ceil,tilesize_y_ceil,xshrinkfactor,yshrinkfactor,id,mapname,path_buf,max_path_len);
1404 // ATM Only show tile grid lines in extreme debug mode
1405 if ( vik_debug && vik_verbose ) {
1406 /* Grid drawing here so it gets drawn on top of the map */
1407 /* Thus loop around x & y again, but this time separately */
1408 /* Only showing grid for the current scale */
1409 GdkGC *black_gc = GTK_WIDGET(vvp)->style->black_gc;
1410 /* Draw single grid lines across the whole screen */
1411 gint width = vik_viewport_get_width(vvp);
1412 gint height = vik_viewport_get_height(vvp);
1413 xx = xx_tmp; yy = yy_tmp;
1414 gint base_xx = xx - (tilesize_x/2);
1415 base_yy = yy - (tilesize_y/2);
1418 for ( x = ((xinc == 1) ? xmin : xmax); x != xend; x+=xinc ) {
1419 vik_viewport_draw_line ( vvp, black_gc, xx, base_yy, xx, height );
1424 for ( y = ((yinc == 1) ? ymin : ymax); y != yend; y+=yinc ) {
1425 vik_viewport_draw_line ( vvp, black_gc, base_xx, yy, width, yy );
1431 g_free ( path_buf );
1435 static void maps_layer_draw ( VikMapsLayer *vml, VikViewport *vvp )
1437 if ( vik_map_source_get_drawmode(MAPS_LAYER_NTH_TYPE(vml->maptype)) == vik_viewport_get_drawmode ( vvp ) )
1442 gdouble level = vik_viewport_get_zoom ( vvp );
1444 vik_viewport_get_min_max_lat_lon ( vvp, &bbox.south, &bbox.north, &bbox.west, &bbox.east );
1445 vik_map_source_get_copyright ( MAPS_LAYER_NTH_TYPE(vml->maptype), bbox, level, vik_viewport_add_copyright, vvp );
1448 const GdkPixbuf *logo = vik_map_source_get_logo ( MAPS_LAYER_NTH_TYPE(vml->maptype) );
1449 vik_viewport_add_logo ( vvp, logo );
1451 /* get corner coords */
1452 if ( vik_viewport_get_coord_mode ( vvp ) == VIK_COORD_UTM && ! vik_viewport_is_one_zone ( vvp ) ) {
1453 /* UTM multi-zone stuff by Kit Transue */
1454 gchar leftmost_zone, rightmost_zone, i;
1455 leftmost_zone = vik_viewport_leftmost_zone( vvp );
1456 rightmost_zone = vik_viewport_rightmost_zone( vvp );
1457 for ( i = leftmost_zone; i <= rightmost_zone; ++i ) {
1458 vik_viewport_corners_for_zonen ( vvp, i, &ul, &br );
1459 maps_layer_draw_section ( vml, vvp, &ul, &br );
1463 vik_viewport_screen_to_coord ( vvp, 0, 0, &ul );
1464 vik_viewport_screen_to_coord ( vvp, vik_viewport_get_width(vvp), vik_viewport_get_height(vvp), &br );
1466 maps_layer_draw_section ( vml, vvp, &ul, &br );
1471 /*************************/
1472 /****** DOWNLOADING ******/
1473 /*************************/
1475 /* pass along data to thread, exists even if layer is deleted. */
1478 gchar *filename_buf;
1479 VikMapsCacheLayout cache_layout;
1480 gint x0, y0, xf, yf;
1486 gboolean refresh_display;
1489 gboolean map_layer_alive;
1493 static void mdi_free ( MapDownloadInfo *mdi )
1495 vik_mutex_free(mdi->mutex);
1496 g_free ( mdi->cache_dir );
1497 mdi->cache_dir = NULL;
1498 g_free ( mdi->filename_buf );
1499 mdi->filename_buf = NULL;
1503 static void weak_ref_cb(gpointer ptr, GObject * dead_vml)
1505 MapDownloadInfo *mdi = ptr;
1506 g_mutex_lock(mdi->mutex);
1507 mdi->map_layer_alive = FALSE;
1508 g_mutex_unlock(mdi->mutex);
1511 static gboolean is_in_area (VikMapSource *map, MapCoord mc)
1514 vik_map_source_mapcoord_to_center_coord ( map, &mc, &vc );
1517 tl.lat = vik_map_source_get_lat_max(map);
1518 tl.lon = vik_map_source_get_lon_min(map);
1520 br.lat = vik_map_source_get_lat_min(map);
1521 br.lon = vik_map_source_get_lon_max(map);
1523 vik_coord_load_from_latlon (&vctl, VIK_COORD_LATLON, &tl);
1525 vik_coord_load_from_latlon (&vcbr, VIK_COORD_LATLON, &br);
1527 return vik_coord_inside ( &vc, &vctl, &vcbr );
1530 static int map_download_thread ( MapDownloadInfo *mdi, gpointer threaddata )
1532 void *handle = vik_map_source_download_handle_init(MAPS_LAYER_NTH_TYPE(mdi->maptype));
1534 MapCoord mcoord = mdi->mapcoord;
1536 for ( x = mdi->x0; x <= mdi->xf; x++ )
1539 for ( y = mdi->y0; y <= mdi->yf; y++ )
1542 // Only attempt to download a tile from supported areas
1543 if ( is_in_area ( MAPS_LAYER_NTH_TYPE(mdi->maptype), mcoord ) )
1545 gboolean remove_mem_cache = FALSE;
1546 gboolean need_download = FALSE;
1548 get_filename ( mdi->cache_dir, mdi->cache_layout,
1549 vik_map_source_get_uniq_id(MAPS_LAYER_NTH_TYPE(mdi->maptype)),
1550 vik_map_source_get_name(MAPS_LAYER_NTH_TYPE(mdi->maptype)),
1551 mdi->mapcoord.scale, mdi->mapcoord.z, x, y, mdi->filename_buf, mdi->maxlen,
1552 vik_map_source_get_file_extension(MAPS_LAYER_NTH_TYPE(mdi->maptype)) );
1555 int res = a_background_thread_progress ( threaddata, ((gdouble)donemaps) / mdi->mapstoget ); /* this also calls testcancel */
1557 vik_map_source_download_handle_cleanup(MAPS_LAYER_NTH_TYPE(mdi->maptype), handle);
1561 if ( g_file_test ( mdi->filename_buf, G_FILE_TEST_EXISTS ) == FALSE ) {
1562 need_download = TRUE;
1563 remove_mem_cache = TRUE;
1565 } else { /* in case map file already exists */
1566 switch (mdi->redownload) {
1567 case REDOWNLOAD_NONE:
1570 case REDOWNLOAD_BAD:
1572 /* see if this one is bad or what */
1574 GdkPixbuf *pixbuf = gdk_pixbuf_new_from_file ( mdi->filename_buf, &gx );
1575 if (gx || (!pixbuf)) {
1576 g_remove ( mdi->filename_buf );
1577 need_download = TRUE;
1578 remove_mem_cache = TRUE;
1579 g_error_free ( gx );
1582 g_object_unref ( pixbuf );
1587 case REDOWNLOAD_NEW:
1588 need_download = TRUE;
1589 remove_mem_cache = TRUE;
1592 case REDOWNLOAD_ALL:
1593 /* FIXME: need a better way than to erase file in case of server/network problem */
1594 g_remove ( mdi->filename_buf );
1595 need_download = TRUE;
1596 remove_mem_cache = TRUE;
1599 case DOWNLOAD_OR_REFRESH:
1600 remove_mem_cache = TRUE;
1604 g_warning ( "redownload state %d unknown\n", mdi->redownload);
1608 mdi->mapcoord.x = x; mdi->mapcoord.y = y;
1610 if (need_download) {
1611 DownloadResult_t dr = vik_map_source_download( MAPS_LAYER_NTH_TYPE(mdi->maptype), &(mdi->mapcoord), mdi->filename_buf, handle);
1613 case DOWNLOAD_HTTP_ERROR:
1614 case DOWNLOAD_CONTENT_ERROR: {
1615 // TODO: ?? count up the number of download errors somehow...
1616 gchar* msg = g_strdup_printf ( "%s: %s", vik_maps_layer_get_map_label (mdi->vml), _("Failed to download tile") );
1617 vik_window_statusbar_update ( (VikWindow*)VIK_GTK_WINDOW_FROM_LAYER(mdi->vml), msg, VIK_STATUSBAR_INFO );
1621 case DOWNLOAD_FILE_WRITE_ERROR: {
1622 gchar* msg = g_strdup_printf ( "%s: %s", vik_maps_layer_get_map_label (mdi->vml), _("Unable to save tile") );
1623 vik_window_statusbar_update ( (VikWindow*)VIK_GTK_WINDOW_FROM_LAYER(mdi->vml), msg, VIK_STATUSBAR_INFO );
1627 case DOWNLOAD_SUCCESS:
1628 case DOWNLOAD_NOT_REQUIRED:
1634 g_mutex_lock(mdi->mutex);
1635 if (remove_mem_cache)
1636 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 );
1637 if (mdi->refresh_display && mdi->map_layer_alive) {
1638 /* TODO: check if it's on visible area */
1639 vik_layer_emit_update ( VIK_LAYER(mdi->vml) ); // NB update display from background
1641 g_mutex_unlock(mdi->mutex);
1642 mdi->mapcoord.x = mdi->mapcoord.y = 0; /* we're temporarily between downloads */
1646 vik_map_source_download_handle_cleanup(MAPS_LAYER_NTH_TYPE(mdi->maptype), handle);
1647 g_mutex_lock(mdi->mutex);
1648 if (mdi->map_layer_alive)
1649 g_object_weak_unref(G_OBJECT(mdi->vml), weak_ref_cb, mdi);
1650 g_mutex_unlock(mdi->mutex);
1654 static void mdi_cancel_cleanup ( MapDownloadInfo *mdi )
1656 if ( mdi->mapcoord.x || mdi->mapcoord.y )
1658 get_filename ( mdi->cache_dir, mdi->cache_layout,
1659 vik_map_source_get_uniq_id(MAPS_LAYER_NTH_TYPE(mdi->maptype)),
1660 vik_map_source_get_name(MAPS_LAYER_NTH_TYPE(mdi->maptype)),
1661 mdi->mapcoord.scale, mdi->mapcoord.z, mdi->mapcoord.x, mdi->mapcoord.y, mdi->filename_buf, mdi->maxlen,
1662 vik_map_source_get_file_extension(MAPS_LAYER_NTH_TYPE(mdi->maptype)) );
1663 if ( g_file_test ( mdi->filename_buf, G_FILE_TEST_EXISTS ) == TRUE)
1665 g_remove ( mdi->filename_buf );
1670 static void start_download_thread ( VikMapsLayer *vml, VikViewport *vvp, const VikCoord *ul, const VikCoord *br, gint redownload )
1672 gdouble xzoom = vml->xmapzoom ? vml->xmapzoom : vik_viewport_get_xmpp ( vvp );
1673 gdouble yzoom = vml->ymapzoom ? vml->ymapzoom : vik_viewport_get_ympp ( vvp );
1675 VikMapSource *map = MAPS_LAYER_NTH_TYPE(vml->maptype);
1677 // Don't ever attempt download on direct access
1678 if ( vik_map_source_is_direct_file_access ( map ) )
1681 if ( vik_map_source_coord_to_mapcoord ( map, ul, xzoom, yzoom, &ulm )
1682 && vik_map_source_coord_to_mapcoord ( map, br, xzoom, yzoom, &brm ) )
1684 MapDownloadInfo *mdi = g_malloc ( sizeof(MapDownloadInfo) );
1689 mdi->map_layer_alive = TRUE;
1690 mdi->mutex = vik_mutex_new();
1691 mdi->refresh_display = TRUE;
1693 /* cache_dir and buffer for dest filename */
1694 mdi->cache_dir = g_strdup ( vml->cache_dir );
1695 mdi->maxlen = strlen ( vml->cache_dir ) + 40;
1696 mdi->filename_buf = g_malloc ( mdi->maxlen * sizeof(gchar) );
1697 mdi->cache_layout = vml->cache_layout;
1698 mdi->maptype = vml->maptype;
1700 mdi->mapcoord = ulm;
1701 mdi->redownload = redownload;
1703 mdi->x0 = MIN(ulm.x, brm.x);
1704 mdi->xf = MAX(ulm.x, brm.x);
1705 mdi->y0 = MIN(ulm.y, brm.y);
1706 mdi->yf = MAX(ulm.y, brm.y);
1710 MapCoord mcoord = mdi->mapcoord;
1712 if ( mdi->redownload ) {
1713 mdi->mapstoget = (mdi->xf - mdi->x0 + 1) * (mdi->yf - mdi->y0 + 1);
1715 /* calculate how many we need */
1716 for ( a = mdi->x0; a <= mdi->xf; a++ )
1719 for ( b = mdi->y0; b <= mdi->yf; b++ )
1722 // Only count tiles from supported areas
1723 if ( is_in_area (map, mcoord) )
1725 get_filename ( mdi->cache_dir, mdi->cache_layout,
1726 vik_map_source_get_uniq_id(map),
1727 vik_map_source_get_name(map),
1728 ulm.scale, ulm.z, a, b, mdi->filename_buf, mdi->maxlen,
1729 vik_map_source_get_file_extension(map) );
1730 if ( g_file_test ( mdi->filename_buf, G_FILE_TEST_EXISTS ) == FALSE )
1737 mdi->mapcoord.x = mdi->mapcoord.y = 0; /* for cleanup -- no current map */
1739 if ( mdi->mapstoget )
1741 const gchar *tmp_str;
1746 if (redownload == REDOWNLOAD_BAD)
1747 tmp_str = ngettext("Redownloading up to %d %s map...", "Redownloading up to %d %s maps...", mdi->mapstoget);
1749 tmp_str = ngettext("Redownloading %d %s map...", "Redownloading %d %s maps...", mdi->mapstoget);
1753 tmp_str = ngettext("Downloading %d %s map...", "Downloading %d %s maps...", mdi->mapstoget);
1755 tmp = g_strdup_printf ( tmp_str, mdi->mapstoget, MAPS_LAYER_NTH_LABEL(vml->maptype));
1757 g_object_weak_ref(G_OBJECT(mdi->vml), weak_ref_cb, mdi);
1758 /* launch the thread */
1759 a_background_thread ( VIK_GTK_WINDOW_FROM_LAYER(vml), /* parent window */
1760 tmp, /* description string */
1761 (vik_thr_func) map_download_thread, /* function to call within thread */
1762 mdi, /* pass along data */
1763 (vik_thr_free_func) mdi_free, /* function to free pass along data */
1764 (vik_thr_free_func) mdi_cancel_cleanup,
1773 static void maps_layer_download_section ( VikMapsLayer *vml, VikViewport *vvp, VikCoord *ul, VikCoord *br, gdouble zoom, gint download_method )
1776 VikMapSource *map = MAPS_LAYER_NTH_TYPE(vml->maptype);
1778 // Don't ever attempt download on direct access
1779 if ( vik_map_source_is_direct_file_access ( map ) )
1782 if (!vik_map_source_coord_to_mapcoord(map, ul, zoom, zoom, &ulm)
1783 || !vik_map_source_coord_to_mapcoord(map, br, zoom, zoom, &brm)) {
1784 g_warning("%s() coord_to_mapcoord() failed", __PRETTY_FUNCTION__);
1788 MapDownloadInfo *mdi = g_malloc(sizeof(MapDownloadInfo));
1793 mdi->map_layer_alive = TRUE;
1794 mdi->mutex = vik_mutex_new();
1795 mdi->refresh_display = TRUE;
1797 mdi->cache_dir = g_strdup ( vml->cache_dir );
1798 mdi->maxlen = strlen ( vml->cache_dir ) + 40;
1799 mdi->filename_buf = g_malloc ( mdi->maxlen * sizeof(gchar) );
1800 mdi->maptype = vml->maptype;
1801 mdi->cache_layout = vml->cache_layout;
1803 mdi->mapcoord = ulm;
1804 mdi->redownload = download_method;
1806 mdi->x0 = MIN(ulm.x, brm.x);
1807 mdi->xf = MAX(ulm.x, brm.x);
1808 mdi->y0 = MIN(ulm.y, brm.y);
1809 mdi->yf = MAX(ulm.y, brm.y);
1813 MapCoord mcoord = mdi->mapcoord;
1815 for (i = mdi->x0; i <= mdi->xf; i++) {
1817 for (j = mdi->y0; j <= mdi->yf; j++) {
1819 // Only count tiles from supported areas
1820 if ( is_in_area (map, mcoord) ) {
1821 get_filename ( mdi->cache_dir, mdi->cache_layout,
1822 vik_map_source_get_uniq_id(map),
1823 vik_map_source_get_name(map),
1824 ulm.scale, ulm.z, i, j, mdi->filename_buf, mdi->maxlen,
1825 vik_map_source_get_file_extension(map) );
1826 if ( g_file_test ( mdi->filename_buf, G_FILE_TEST_EXISTS ) == FALSE )
1832 mdi->mapcoord.x = mdi->mapcoord.y = 0; /* for cleanup -- no current map */
1834 if (mdi->mapstoget) {
1837 fmt = ngettext("Downloading %d %s map...",
1838 "Downloading %d %s maps...",
1840 tmp = g_strdup_printf ( fmt, mdi->mapstoget, MAPS_LAYER_NTH_LABEL(vml->maptype) );
1842 g_object_weak_ref(G_OBJECT(mdi->vml), weak_ref_cb, mdi);
1843 /* launch the thread */
1844 a_background_thread ( VIK_GTK_WINDOW_FROM_LAYER(vml), /* parent window */
1845 tmp, /* description string */
1846 (vik_thr_func) map_download_thread, /* function to call within thread */
1847 mdi, /* pass along data */
1848 (vik_thr_free_func) mdi_free, /* function to free pass along data */
1849 (vik_thr_free_func) mdi_cancel_cleanup,
1858 * vik_maps_layer_download_section:
1859 * @vml: The Map Layer
1860 * @vvp: The Viewport that the map is on
1861 * @ul: Upper left coordinate of the area to be downloaded
1862 * @br: Bottom right coordinate of the area to be downloaded
1863 * @zoom: The zoom level at which the maps are to be download
1865 * Download a specified map area at a certain zoom level
1867 void vik_maps_layer_download_section ( VikMapsLayer *vml, VikViewport *vvp, VikCoord *ul, VikCoord *br, gdouble zoom )
1869 maps_layer_download_section (vml, vvp, ul, br, zoom, REDOWNLOAD_NONE);
1872 static void maps_layer_redownload_bad ( VikMapsLayer *vml )
1874 start_download_thread ( vml, vml->redownload_vvp, &(vml->redownload_ul), &(vml->redownload_br), REDOWNLOAD_BAD );
1877 static void maps_layer_redownload_all ( VikMapsLayer *vml )
1879 start_download_thread ( vml, vml->redownload_vvp, &(vml->redownload_ul), &(vml->redownload_br), REDOWNLOAD_ALL );
1882 static void maps_layer_redownload_new ( VikMapsLayer *vml )
1884 start_download_thread ( vml, vml->redownload_vvp, &(vml->redownload_ul), &(vml->redownload_br), REDOWNLOAD_NEW );
1888 * Display a simple dialog with information about this particular map tile
1890 static void maps_layer_tile_info ( VikMapsLayer *vml )
1892 VikMapSource *map = MAPS_LAYER_NTH_TYPE(vml->maptype);
1894 gdouble xzoom = vml->xmapzoom ? vml->xmapzoom : vik_viewport_get_xmpp ( vml->redownload_vvp );
1895 gdouble yzoom = vml->ymapzoom ? vml->ymapzoom : vik_viewport_get_ympp ( vml->redownload_vvp );
1898 if ( !vik_map_source_coord_to_mapcoord ( map, &(vml->redownload_ul), xzoom, yzoom, &ulm ) )
1901 gchar *filename = NULL;
1902 gchar *source = NULL;
1904 if ( vik_map_source_is_direct_file_access ( map ) ) {
1905 if ( vik_map_source_is_mbtiles ( map ) ) {
1906 filename = g_strdup ( vml->filename );
1907 #ifdef HAVE_SQLITE3_H
1908 // And whether to bother going into the SQL to check it's really there or not...
1909 gchar *exists = NULL;
1910 gint zoom = 17 - ulm.scale;
1911 if ( vml->mbtiles ) {
1912 GdkPixbuf *pixbuf = get_pixbuf_sql_exec ( vml->mbtiles, ulm.x, ulm.y, zoom );
1914 exists = g_strdup ( _("YES") );
1915 g_object_unref ( G_OBJECT(pixbuf) );
1918 exists = g_strdup ( _("NO") );
1922 exists = g_strdup ( _("NO") );
1923 gint flip_y = (gint) pow(2, zoom)-1 - ulm.y;
1924 // NB Also handles .jpg automatically due to pixbuf_new_from () support - although just print png for now.
1925 source = g_strdup_printf ( "Source: %s (%d%s%d%s%d.%s %s)", filename, zoom, G_DIR_SEPARATOR_S, ulm.x, G_DIR_SEPARATOR_S, flip_y, "png", exists );
1928 source = g_strdup ( _("Source: Not available") );
1931 else if ( vik_map_source_is_osm_meta_tiles ( map ) ) {
1932 char path[PATH_MAX];
1933 xyz_to_meta(path, sizeof(path), vml->cache_dir, ulm.x, ulm.y, 17-ulm.scale );
1934 source = g_strdup ( path );
1935 filename = g_strdup ( path );
1938 guint max_path_len = strlen(vml->cache_dir) + 40;
1939 filename = g_malloc ( max_path_len * sizeof(char) );
1940 get_filename ( vml->cache_dir, VIK_MAPS_CACHE_LAYOUT_OSM,
1941 vik_map_source_get_uniq_id(map),
1943 ulm.scale, ulm.z, ulm.x, ulm.y, filename, max_path_len,
1944 vik_map_source_get_file_extension(map) );
1945 source = g_strconcat ( "Source: file://", filename, NULL );
1949 guint max_path_len = strlen(vml->cache_dir) + 40;
1950 filename = g_malloc ( max_path_len * sizeof(char) );
1951 get_filename ( vml->cache_dir, vml->cache_layout,
1952 vik_map_source_get_uniq_id(map),
1953 vik_map_source_get_name(map),
1954 ulm.scale, ulm.z, ulm.x, ulm.y, filename, max_path_len,
1955 vik_map_source_get_file_extension(map) );
1956 source = g_strdup_printf ( "Source: http://%s%s",
1957 vik_map_source_default_get_hostname ( VIK_MAP_SOURCE_DEFAULT(map) ),
1958 vik_map_source_default_get_uri ( VIK_MAP_SOURCE_DEFAULT(map), &ulm ) );
1961 GArray *array = g_array_new (FALSE, TRUE, sizeof(gchar*));
1962 g_array_append_val ( array, source );
1964 gchar *filemsg = NULL;
1965 gchar *timemsg = NULL;
1967 if ( g_file_test ( filename, G_FILE_TEST_EXISTS ) ) {
1968 filemsg = g_strconcat ( "Tile File: ", filename, NULL );
1969 // Get some timestamp information of the tile
1970 struct stat stat_buf;
1971 if ( g_stat ( filename, &stat_buf ) == 0 ) {
1973 strftime ( time_buf, sizeof(time_buf), "%c", gmtime((const time_t *)&stat_buf.st_mtime) );
1974 timemsg = g_strdup_printf ( _("Tile File Timestamp: %s"), time_buf );
1977 timemsg = g_strdup ( _("Tile File Timestamp: Not Available") );
1979 g_array_append_val ( array, filemsg );
1980 g_array_append_val ( array, timemsg );
1983 filemsg = g_strdup_printf ( "Tile File: %s [Not Available]", filename );
1984 g_array_append_val ( array, filemsg );
1987 a_dialog_list ( VIK_GTK_WINDOW_FROM_LAYER(vml), _("Tile Information"), array, 5 );
1988 g_array_free ( array, FALSE );
1993 g_free ( filename );
1996 static gboolean maps_layer_download_release ( VikMapsLayer *vml, GdkEventButton *event, VikViewport *vvp )
1998 if (!vml || vml->vl.type != VIK_LAYER_MAPS)
2000 if ( vml->dl_tool_x != -1 && vml->dl_tool_y != -1 )
2002 if ( event->button == 1 )
2005 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 );
2006 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 );
2007 start_download_thread ( vml, vvp, &ul, &br, DOWNLOAD_OR_REFRESH );
2008 vml->dl_tool_x = vml->dl_tool_y = -1;
2013 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) );
2014 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) );
2016 vml->redownload_vvp = vvp;
2018 vml->dl_tool_x = vml->dl_tool_y = -1;
2020 if ( ! vml->dl_right_click_menu ) {
2022 vml->dl_right_click_menu = GTK_MENU ( gtk_menu_new () );
2024 item = gtk_menu_item_new_with_mnemonic ( _("Redownload _Bad Map(s)") );
2025 g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(maps_layer_redownload_bad), vml );
2026 gtk_menu_shell_append ( GTK_MENU_SHELL(vml->dl_right_click_menu), item );
2028 item = gtk_menu_item_new_with_mnemonic ( _("Redownload _New Map(s)") );
2029 g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(maps_layer_redownload_new), vml );
2030 gtk_menu_shell_append ( GTK_MENU_SHELL(vml->dl_right_click_menu), item );
2032 item = gtk_menu_item_new_with_mnemonic ( _("Redownload _All Map(s)") );
2033 g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(maps_layer_redownload_all), vml );
2034 gtk_menu_shell_append ( GTK_MENU_SHELL(vml->dl_right_click_menu), item );
2036 item = gtk_image_menu_item_new_with_mnemonic ( _("_Show Tile Information") );
2037 gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_INFO, GTK_ICON_SIZE_MENU) );
2038 g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(maps_layer_tile_info), vml );
2039 gtk_menu_shell_append (GTK_MENU_SHELL(vml->dl_right_click_menu), item);
2042 gtk_menu_popup ( vml->dl_right_click_menu, NULL, NULL, NULL, NULL, event->button, event->time );
2043 gtk_widget_show_all ( GTK_WIDGET(vml->dl_right_click_menu) );
2049 static gpointer maps_layer_download_create ( VikWindow *vw, VikViewport *vvp)
2054 static gboolean maps_layer_download_click ( VikMapsLayer *vml, GdkEventButton *event, VikViewport *vvp )
2057 if (!vml || vml->vl.type != VIK_LAYER_MAPS)
2059 VikMapSource *map = MAPS_LAYER_NTH_TYPE(vml->maptype);
2060 if ( vik_map_source_get_drawmode(map) == vik_viewport_get_drawmode ( vvp ) &&
2061 vik_map_source_coord_to_mapcoord ( map, vik_viewport_get_center ( vvp ),
2062 vml->xmapzoom ? vml->xmapzoom : vik_viewport_get_xmpp ( vvp ),
2063 vml->ymapzoom ? vml->ymapzoom : vik_viewport_get_ympp ( vvp ),
2065 vml->dl_tool_x = event->x, vml->dl_tool_y = event->y;
2071 // A slightly better way of defining the menu callback information
2072 // This should be easier to extend/rework compared to previously
2079 typedef gpointer menu_array_values[MA_LAST];
2081 static void download_onscreen_maps ( menu_array_values values, gint redownload )
2083 VikMapsLayer *vml = VIK_MAPS_LAYER(values[MA_VML]);
2084 VikViewport *vvp = VIK_VIEWPORT(values[MA_VVP]);
2085 VikViewportDrawMode vp_drawmode = vik_viewport_get_drawmode ( vvp );
2087 gdouble xzoom = vml->xmapzoom ? vml->xmapzoom : vik_viewport_get_xmpp ( vvp );
2088 gdouble yzoom = vml->ymapzoom ? vml->ymapzoom : vik_viewport_get_ympp ( vvp );
2093 vik_viewport_screen_to_coord ( vvp, 0, 0, &ul );
2094 vik_viewport_screen_to_coord ( vvp, vik_viewport_get_width(vvp), vik_viewport_get_height(vvp), &br );
2096 VikMapSource *map = MAPS_LAYER_NTH_TYPE(vml->maptype);
2097 if ( vik_map_source_get_drawmode(map) == vp_drawmode &&
2098 vik_map_source_coord_to_mapcoord ( map, &ul, xzoom, yzoom, &ulm ) &&
2099 vik_map_source_coord_to_mapcoord ( map, &br, xzoom, yzoom, &brm ) )
2100 start_download_thread ( vml, vvp, &ul, &br, redownload );
2101 else if (vik_map_source_get_drawmode(map) != vp_drawmode) {
2102 const gchar *drawmode_name = vik_viewport_get_drawmode_name (vvp, vik_map_source_get_drawmode(map));
2103 gchar *err = g_strdup_printf(_("Wrong drawmode for this map.\nSelect \"%s\" from View menu and try again."), _(drawmode_name));
2104 a_dialog_error_msg ( VIK_GTK_WINDOW_FROM_LAYER(vml), err );
2108 a_dialog_error_msg ( VIK_GTK_WINDOW_FROM_LAYER(vml), _("Wrong zoom level for this map.") );
2112 static void maps_layer_download_missing_onscreen_maps ( menu_array_values values )
2114 download_onscreen_maps( values, REDOWNLOAD_NONE);
2117 static void maps_layer_download_new_onscreen_maps ( menu_array_values values )
2119 download_onscreen_maps( values, REDOWNLOAD_NEW);
2122 static void maps_layer_redownload_all_onscreen_maps ( menu_array_values values )
2124 download_onscreen_maps( values, REDOWNLOAD_ALL);
2127 static void maps_layer_about ( gpointer vml_vvp[2] )
2129 VikMapsLayer *vml = vml_vvp[0];
2130 VikMapSource *map = MAPS_LAYER_NTH_TYPE(vml->maptype);
2132 if ( vik_map_source_get_license (map) )
2133 maps_show_license ( VIK_GTK_WINDOW_FROM_LAYER(vml), map );
2135 a_dialog_info_msg ( VIK_GTK_WINDOW_FROM_LAYER(vml),
2136 vik_map_source_get_label (map) );
2140 * maps_layer_how_many_maps:
2141 * Copied from maps_layer_download_section but without the actual download and this returns a value
2143 static gint maps_layer_how_many_maps ( VikMapsLayer *vml, VikViewport *vvp, VikCoord *ul, VikCoord *br, gdouble zoom, gint redownload )
2146 VikMapSource *map = MAPS_LAYER_NTH_TYPE(vml->maptype);
2148 if ( vik_map_source_is_direct_file_access ( map ) )
2151 if (!vik_map_source_coord_to_mapcoord(map, ul, zoom, zoom, &ulm)
2152 || !vik_map_source_coord_to_mapcoord(map, br, zoom, zoom, &brm)) {
2153 g_warning("%s() coord_to_mapcoord() failed", __PRETTY_FUNCTION__);
2157 MapDownloadInfo *mdi = g_malloc(sizeof(MapDownloadInfo));
2162 mdi->map_layer_alive = TRUE;
2163 mdi->mutex = vik_mutex_new();
2164 mdi->refresh_display = FALSE;
2166 mdi->cache_dir = g_strdup ( vml->cache_dir );
2167 mdi->maxlen = strlen ( vml->cache_dir ) + 40;
2168 mdi->filename_buf = g_malloc ( mdi->maxlen * sizeof(gchar) );
2169 mdi->maptype = vml->maptype;
2170 mdi->cache_layout = vml->cache_layout;
2172 mdi->mapcoord = ulm;
2173 mdi->redownload = redownload;
2175 mdi->x0 = MIN(ulm.x, brm.x);
2176 mdi->xf = MAX(ulm.x, brm.x);
2177 mdi->y0 = MIN(ulm.y, brm.y);
2178 mdi->yf = MAX(ulm.y, brm.y);
2182 if ( mdi->redownload == REDOWNLOAD_ALL ) {
2183 mdi->mapstoget = (mdi->xf - mdi->x0 + 1) * (mdi->yf - mdi->y0 + 1);
2186 /* calculate how many we need */
2187 MapCoord mcoord = mdi->mapcoord;
2188 for (i = mdi->x0; i <= mdi->xf; i++) {
2190 for (j = mdi->y0; j <= mdi->yf; j++) {
2192 // Only count tiles from supported areas
2193 if ( is_in_area ( map, mcoord ) ) {
2194 get_filename ( mdi->cache_dir, mdi->cache_layout,
2195 vik_map_source_get_uniq_id(map),
2196 vik_map_source_get_name(map),
2197 ulm.scale, ulm.z, i, j, mdi->filename_buf, mdi->maxlen,
2198 vik_map_source_get_file_extension(map) );
2199 if ( mdi->redownload == REDOWNLOAD_NEW ) {
2200 // Assume the worst - always a new file
2201 // Absolute value would require a server lookup - but that is too slow
2205 if ( g_file_test ( mdi->filename_buf, G_FILE_TEST_EXISTS ) == FALSE ) {
2210 if ( mdi->redownload == REDOWNLOAD_BAD ) {
2211 /* see if this one is bad or what */
2213 GdkPixbuf *pixbuf = gdk_pixbuf_new_from_file ( mdi->filename_buf, &gx );
2214 if (gx || (!pixbuf)) {
2218 // Other download cases already considered or just ignored
2227 gint rv = mdi->mapstoget;
2235 * maps_dialog_zoom_between:
2236 * This dialog is specific to the map layer, so it's here rather than in dialog.c
2238 gboolean maps_dialog_zoom_between ( GtkWindow *parent,
2243 gint *selected_zoom1,
2244 gint *selected_zoom2,
2245 gchar *download_list[],
2246 gint default_download,
2247 gint *selected_download )
2249 GtkWidget *dialog = gtk_dialog_new_with_buttons ( title,
2251 GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
2252 GTK_STOCK_OK, GTK_RESPONSE_ACCEPT,
2253 GTK_STOCK_CANCEL, GTK_RESPONSE_REJECT,
2255 gtk_dialog_set_default_response ( GTK_DIALOG(dialog), GTK_RESPONSE_ACCEPT );
2256 GtkWidget *response_w = NULL;
2257 #if GTK_CHECK_VERSION (2, 20, 0)
2258 response_w = gtk_dialog_get_widget_for_response ( GTK_DIALOG(dialog), GTK_RESPONSE_ACCEPT );
2260 GtkWidget *zoom_label1 = gtk_label_new ( _("Zoom Start:") );
2261 GtkWidget *zoom_combo1 = vik_combo_box_text_new();
2263 for (s = zoom_list; *s; s++)
2264 vik_combo_box_text_append ( zoom_combo1, *s );
2265 gtk_combo_box_set_active ( GTK_COMBO_BOX(zoom_combo1), default_zoom1 );
2267 GtkWidget *zoom_label2 = gtk_label_new ( _("Zoom End:") );
2268 GtkWidget *zoom_combo2 = vik_combo_box_text_new();
2269 for (s = zoom_list; *s; s++)
2270 vik_combo_box_text_append ( zoom_combo2, *s );
2271 gtk_combo_box_set_active ( GTK_COMBO_BOX(zoom_combo2), default_zoom2 );
2273 GtkWidget *download_label = gtk_label_new(_("Download Maps Method:"));
2274 GtkWidget *download_combo = vik_combo_box_text_new();
2275 for (s = download_list; *s; s++)
2276 vik_combo_box_text_append ( download_combo, *s );
2277 gtk_combo_box_set_active ( GTK_COMBO_BOX(download_combo), default_download );
2279 GtkTable *box = GTK_TABLE(gtk_table_new(3, 2, FALSE));
2280 gtk_table_attach_defaults (box, GTK_WIDGET(zoom_label1), 0, 1, 0, 1);
2281 gtk_table_attach_defaults (box, GTK_WIDGET(zoom_combo1), 1, 2, 0, 1);
2282 gtk_table_attach_defaults (box, GTK_WIDGET(zoom_label2), 0, 1, 1, 2);
2283 gtk_table_attach_defaults (box, GTK_WIDGET(zoom_combo2), 1, 2, 1, 2);
2284 gtk_table_attach_defaults (box, GTK_WIDGET(download_label), 0, 1, 2, 3);
2285 gtk_table_attach_defaults (box, GTK_WIDGET(download_combo), 1, 2, 2, 3);
2287 gtk_box_pack_start ( GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(dialog))), GTK_WIDGET(box), FALSE, FALSE, 5 );
2290 gtk_widget_grab_focus ( response_w );
2292 gtk_widget_show_all ( dialog );
2293 if ( gtk_dialog_run ( GTK_DIALOG(dialog) ) != GTK_RESPONSE_ACCEPT ) {
2294 gtk_widget_destroy(dialog);
2298 // Return selected options
2299 *selected_zoom1 = gtk_combo_box_get_active ( GTK_COMBO_BOX(zoom_combo1) );
2300 *selected_zoom2 = gtk_combo_box_get_active ( GTK_COMBO_BOX(zoom_combo2) );
2301 *selected_download = gtk_combo_box_get_active ( GTK_COMBO_BOX(download_combo) );
2303 gtk_widget_destroy(dialog);
2307 // My best guess of sensible limits
2308 #define REALLY_LARGE_AMOUNT_OF_TILES 5000
2309 #define CONFIRM_LARGE_AMOUNT_OF_TILES 500
2312 * Get all maps in the region for zoom levels specified by the user
2313 * Sort of similar to trw_layer_download_map_along_track_cb function
2315 static void maps_layer_download_all ( menu_array_values values )
2317 VikMapsLayer *vml = VIK_MAPS_LAYER(values[MA_VML]);
2318 VikViewport *vvp = VIK_VIEWPORT(values[MA_VVP]);
2320 // I don't think we should allow users to hammer the servers too much...
2321 // Delibrately not allowing lowest zoom levels
2322 // Still can give massive numbers to download
2323 // A screen size of 1600x1200 gives around 300,000 tiles between 1..128 when none exist before !!
2324 gchar *zoom_list[] = {"1", "2", "4", "8", "16", "32", "64", "128", "256", "512", "1024", NULL };
2325 gdouble zoom_vals[] = {1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024};
2327 gint selected_zoom1, selected_zoom2, default_zoom, lower_zoom;
2328 gint selected_download_method;
2330 gdouble cur_zoom = vik_viewport_get_zoom(vvp);
2332 for (default_zoom = 0; default_zoom < sizeof(zoom_vals)/sizeof(gdouble); default_zoom++) {
2333 if (cur_zoom == zoom_vals[default_zoom])
2336 default_zoom = (default_zoom == sizeof(zoom_vals)/sizeof(gdouble)) ? sizeof(zoom_vals)/sizeof(gdouble) - 1 : default_zoom;
2338 // Default to only 2 zoom levels below the current one
2339 if (default_zoom > 1 )
2340 lower_zoom = default_zoom - 2;
2342 lower_zoom = default_zoom;
2344 // redownload method - needs to align with REDOWNLOAD* macro values
2345 gchar *download_list[] = { _("Missing"), _("Bad"), _("New"), _("Reload All"), NULL };
2347 gchar *title = g_strdup_printf ( ("%s: %s"), vik_maps_layer_get_map_label (vml), _("Download for Zoom Levels") );
2349 if ( ! maps_dialog_zoom_between ( VIK_GTK_WINDOW_FROM_LAYER(vml),
2357 REDOWNLOAD_NONE, // AKA Missing
2358 &selected_download_method ) ) {
2365 // Find out new current positions
2366 gdouble min_lat, max_lat, min_lon, max_lon;
2367 VikCoord vc_ul, vc_br;
2368 vik_viewport_get_min_max_lat_lon ( vvp, &min_lat, &max_lat, &min_lon, &max_lon );
2369 struct LatLon ll_ul = { max_lat, min_lon };
2370 struct LatLon ll_br = { min_lat, max_lon };
2371 vik_coord_load_from_latlon ( &vc_ul, vik_viewport_get_coord_mode (vvp), &ll_ul );
2372 vik_coord_load_from_latlon ( &vc_br, vik_viewport_get_coord_mode (vvp), &ll_br );
2374 // Get Maps Count - call for each zoom level (in reverse)
2375 // With REDOWNLOAD_NEW this is a possible maximum
2376 // With REDOWNLOAD_NONE this only missing ones - however still has a server lookup per tile
2379 for ( zz = selected_zoom2; zz >= selected_zoom1; zz-- ) {
2380 map_count = map_count + maps_layer_how_many_maps ( vml, vvp, &vc_ul, &vc_br, zoom_vals[zz], selected_download_method );
2383 g_debug ("vikmapslayer: download request map count %d for method %d", map_count, selected_download_method);
2385 // Absolute protection of hammering a map server
2386 if ( map_count > REALLY_LARGE_AMOUNT_OF_TILES ) {
2387 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);
2388 a_dialog_error_msg ( VIK_GTK_WINDOW_FROM_LAYER(vml), str );
2393 // Confirm really want to do this
2394 if ( map_count > CONFIRM_LARGE_AMOUNT_OF_TILES ) {
2395 gchar *str = g_strdup_printf (_("Do you really want to download %d tiles?"), map_count);
2396 gboolean ans = a_dialog_yes_or_no ( VIK_GTK_WINDOW_FROM_LAYER(vml), str, NULL );
2402 // Get Maps - call for each zoom level (in reverse)
2403 for ( zz = selected_zoom2; zz >= selected_zoom1; zz-- ) {
2404 maps_layer_download_section ( vml, vvp, &vc_ul, &vc_br, zoom_vals[zz], selected_download_method );
2411 static void maps_layer_flush ( menu_array_values values )
2413 VikMapsLayer *vml = VIK_MAPS_LAYER(values[MA_VML]);
2414 a_mapcache_flush_type ( vik_map_source_get_uniq_id(MAPS_LAYER_NTH_TYPE(vml->maptype)) );
2417 static void maps_layer_add_menu_items ( VikMapsLayer *vml, GtkMenu *menu, VikLayersPanel *vlp )
2420 static menu_array_values values;
2421 values[MA_VML] = vml;
2422 values[MA_VVP] = vik_layers_panel_get_viewport( VIK_LAYERS_PANEL(vlp) );
2424 item = gtk_menu_item_new();
2425 gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item );
2426 gtk_widget_show ( item );
2428 /* Now with icons */
2429 item = gtk_image_menu_item_new_with_mnemonic ( _("Download _Missing Onscreen Maps") );
2430 gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_ADD, GTK_ICON_SIZE_MENU) );
2431 g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(maps_layer_download_missing_onscreen_maps), values );
2432 gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
2433 gtk_widget_show ( item );
2435 if ( vik_map_source_supports_download_only_new (MAPS_LAYER_NTH_TYPE(vml->maptype)) ) {
2436 item = gtk_image_menu_item_new_with_mnemonic ( _("Download _New Onscreen Maps") );
2437 gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_REDO, GTK_ICON_SIZE_MENU) );
2438 g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(maps_layer_download_new_onscreen_maps), values );
2439 gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
2440 gtk_widget_show ( item );
2443 item = gtk_image_menu_item_new_with_mnemonic ( _("Reload _All Onscreen Maps") );
2444 gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_REFRESH, GTK_ICON_SIZE_MENU) );
2445 g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(maps_layer_redownload_all_onscreen_maps), values );
2446 gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
2447 gtk_widget_show ( item );
2449 item = gtk_image_menu_item_new_with_mnemonic ( _("Download Maps in _Zoom Levels...") );
2450 gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_DND_MULTIPLE, GTK_ICON_SIZE_MENU) );
2451 g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(maps_layer_download_all), values );
2452 gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
2453 gtk_widget_show ( item );
2455 item = gtk_image_menu_item_new_from_stock ( GTK_STOCK_ABOUT, NULL );
2456 g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(maps_layer_about), values );
2457 gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
2458 gtk_widget_show ( item );
2460 // Typical users shouldn't need to use this functionality - so debug only ATM
2462 item = gtk_image_menu_item_new_with_mnemonic ( _("Flush Map Cache") );
2463 gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_REMOVE, GTK_ICON_SIZE_MENU) );
2464 g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(maps_layer_flush), values );
2465 gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
2466 gtk_widget_show ( item );
2471 * Enable downloading maps of the current screen area either 'new' or 'everything'
2473 void vik_maps_layer_download ( VikMapsLayer *vml, VikViewport *vvp, gboolean only_new )
2478 static menu_array_values values;
2479 values[MA_VML] = vml;
2480 values[MA_VVP] = vvp;
2483 // Get only new maps
2484 maps_layer_download_new_onscreen_maps ( values );
2486 // Redownload everything
2487 maps_layer_redownload_all_onscreen_maps ( values );