2 * viking -- GPS Data and Topo Analyzer, Explorer, and Manager
4 * Copyright (C) 2005, Evan Battaglia <viking@greentorch.org>
5 * Copyright (C) 2010, Guilhem Bonnefille <guilhem.bonnefille@gmail.com>
6 * UTM multi-zone stuff by Kit Transue <notlostyet@didactek.com>
7 * Dynamic map type by Guilhem Bonnefille <guilhem.bonnefille@gmail.com>
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
30 #include <gdk-pixbuf/gdk-pixdata.h>
32 #include <glib/gstdio.h>
33 #include <glib/gi18n.h>
47 #include "vikmapsourcedefault.h"
50 #include "background.h"
51 #include "preferences.h"
52 #include "vikmapslayer.h"
53 #include "icons/icons.h"
55 #define VIK_SETTINGS_MAP_MAX_TILES "maps_max_tiles"
56 static gint MAX_TILES = 1000;
58 #define VIK_SETTINGS_MAP_MIN_SHRINKFACTOR "maps_min_shrinkfactor"
59 #define VIK_SETTINGS_MAP_MAX_SHRINKFACTOR "maps_max_shrinkfactor"
60 static gdouble MAX_SHRINKFACTOR = 8.0000001; /* zoom 1 viewing 8-tiles */
61 static gdouble MIN_SHRINKFACTOR = 0.0312499; /* zoom 32 viewing 1-tiles */
63 #define VIK_SETTINGS_MAP_REAL_MIN_SHRINKFACTOR "maps_real_min_shrinkfactor"
64 static gdouble REAL_MIN_SHRINKFACTOR = 0.0039062499; /* if shrinkfactor is between MAX and REAL_MAX, will only check for existence */
66 /****** MAP TYPES ******/
68 static GList *__map_types = NULL;
70 #define NUM_MAP_TYPES g_list_length(__map_types)
72 /* List of label for each map type */
73 static gchar **params_maptypes = NULL;
75 /* Corresponding IDS. (Cf. field uniq_id in VikMapsLayer struct) */
76 static guint *params_maptypes_ids = NULL;
78 /******** MAPZOOMS *********/
80 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 };
81 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 };
82 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 };
84 #define NUM_MAPZOOMS (sizeof(params_mapzooms)/sizeof(params_mapzooms[0]) - 1)
86 /**************************/
89 static void maps_layer_post_read (VikLayer *vl, VikViewport *vp, gboolean from_file);
90 static const gchar* maps_layer_tooltip ( VikMapsLayer *vml );
91 static void maps_layer_marshall( VikMapsLayer *vml, guint8 **data, gint *len );
92 static VikMapsLayer *maps_layer_unmarshall( guint8 *data, gint len, VikViewport *vvp );
93 static gboolean maps_layer_set_param ( VikMapsLayer *vml, guint16 id, VikLayerParamData data, VikViewport *vvp, gboolean is_file_operation );
94 static VikLayerParamData maps_layer_get_param ( VikMapsLayer *vml, guint16 id, gboolean is_file_operation );
95 static void maps_layer_draw ( VikMapsLayer *vml, VikViewport *vvp );
96 static VikMapsLayer *maps_layer_new ( VikViewport *vvp );
97 static void maps_layer_free ( VikMapsLayer *vml );
98 static gboolean maps_layer_download_release ( VikMapsLayer *vml, GdkEventButton *event, VikViewport *vvp );
99 static gboolean maps_layer_download_click ( VikMapsLayer *vml, GdkEventButton *event, VikViewport *vvp );
100 static gpointer maps_layer_download_create ( VikWindow *vw, VikViewport *vvp );
101 static void maps_layer_set_cache_dir ( VikMapsLayer *vml, const gchar *dir );
102 static void start_download_thread ( VikMapsLayer *vml, VikViewport *vvp, const VikCoord *ul, const VikCoord *br, gint redownload );
103 static void maps_layer_add_menu_items ( VikMapsLayer *vml, GtkMenu *menu, VikLayersPanel *vlp );
104 static guint map_uniq_id_to_index ( guint uniq_id );
107 static VikLayerParamScale params_scales[] = {
108 /* min, max, step, digits (decimal places) */
109 { 0, 255, 3, 0 }, /* alpha */
112 static VikLayerParamData mode_default ( void ) { return VIK_LPD_UINT ( 19 ); } // OSM MapQuest maps
113 static VikLayerParamData directory_default ( void )
115 VikLayerParamData data;
116 VikLayerParamData *pref = a_preferences_get(VIKING_PREFERENCES_NAMESPACE "maplayer_default_dir");
117 if (pref) data.s = g_strdup ( pref->s ); else data.s = "";
120 static VikLayerParamData alpha_default ( void ) { return VIK_LPD_UINT ( 255 ); }
121 static VikLayerParamData mapzoom_default ( void ) { return VIK_LPD_UINT ( 0 ); }
123 VikLayerParam maps_layer_params[] = {
124 { VIK_LAYER_MAPS, "mode", VIK_LAYER_PARAM_UINT, VIK_LAYER_GROUP_NONE, N_("Map Type:"), VIK_LAYER_WIDGET_COMBOBOX, NULL, NULL, NULL, mode_default },
125 { VIK_LAYER_MAPS, "directory", VIK_LAYER_PARAM_STRING, VIK_LAYER_GROUP_NONE, N_("Maps Directory:"), VIK_LAYER_WIDGET_FOLDERENTRY, NULL, NULL, NULL, directory_default },
126 { VIK_LAYER_MAPS, "alpha", VIK_LAYER_PARAM_UINT, VIK_LAYER_GROUP_NONE, N_("Alpha:"), VIK_LAYER_WIDGET_HSCALE, params_scales, NULL,
127 N_("Control the Alpha value for transparency effects"), alpha_default },
128 { 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 },
129 { VIK_LAYER_MAPS, "adlonlymissing", VIK_LAYER_PARAM_BOOLEAN, VIK_LAYER_GROUP_NONE, N_("Autodownload Only Gets Missing Maps:"), VIK_LAYER_WIDGET_CHECKBUTTON, NULL, NULL,
130 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 },
131 { VIK_LAYER_MAPS, "mapzoom", VIK_LAYER_PARAM_UINT, VIK_LAYER_GROUP_NONE, N_("Zoom Level:"), VIK_LAYER_WIDGET_COMBOBOX, params_mapzooms, NULL,
132 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."),
146 void maps_layer_set_autodownload_default ( gboolean autodownload )
148 // Set appropriate function
150 maps_layer_params[PARAM_AUTODOWNLOAD].default_value = vik_lpd_true_default;
152 maps_layer_params[PARAM_AUTODOWNLOAD].default_value = vik_lpd_false_default;
155 static VikToolInterface maps_tools[] = {
156 { { "MapsDownload", "vik-icon-Maps Download", N_("_Maps Download"), NULL, N_("Maps Download"), 0 },
157 (VikToolConstructorFunc) maps_layer_download_create,
161 (VikToolMouseFunc) maps_layer_download_click,
163 (VikToolMouseFunc) maps_layer_download_release,
166 GDK_CURSOR_IS_PIXMAP, &cursor_mapdl_pixbuf },
169 VikLayerInterface vik_maps_layer_interface = {
173 &vikmapslayer_pixbuf,
176 sizeof(maps_tools) / sizeof(maps_tools[0]),
185 (VikLayerFuncCreate) maps_layer_new,
186 (VikLayerFuncRealize) NULL,
187 (VikLayerFuncPostRead) maps_layer_post_read,
188 (VikLayerFuncFree) maps_layer_free,
190 (VikLayerFuncProperties) NULL,
191 (VikLayerFuncDraw) maps_layer_draw,
192 (VikLayerFuncChangeCoordMode) NULL,
194 (VikLayerFuncSetMenuItemsSelection) NULL,
195 (VikLayerFuncGetMenuItemsSelection) NULL,
197 (VikLayerFuncAddMenuItems) maps_layer_add_menu_items,
198 (VikLayerFuncSublayerAddMenuItems) NULL,
200 (VikLayerFuncSublayerRenameRequest) NULL,
201 (VikLayerFuncSublayerToggleVisible) NULL,
202 (VikLayerFuncSublayerTooltip) NULL,
203 (VikLayerFuncLayerTooltip) maps_layer_tooltip,
204 (VikLayerFuncLayerSelected) NULL,
206 (VikLayerFuncMarshall) maps_layer_marshall,
207 (VikLayerFuncUnmarshall) maps_layer_unmarshall,
209 (VikLayerFuncSetParam) maps_layer_set_param,
210 (VikLayerFuncGetParam) maps_layer_get_param,
212 (VikLayerFuncReadFileData) NULL,
213 (VikLayerFuncWriteFileData) NULL,
215 (VikLayerFuncDeleteItem) NULL,
216 (VikLayerFuncCutItem) NULL,
217 (VikLayerFuncCopyItem) NULL,
218 (VikLayerFuncPasteItem) NULL,
219 (VikLayerFuncFreeCopiedItem) NULL,
220 (VikLayerFuncDragDropRequest) NULL,
222 (VikLayerFuncSelectClick) NULL,
223 (VikLayerFuncSelectMove) NULL,
224 (VikLayerFuncSelectRelease) NULL,
225 (VikLayerFuncSelectedViewportMenu) NULL,
228 struct _VikMapsLayer {
234 gdouble xmapzoom, ymapzoom;
236 gboolean autodownload;
237 gboolean adl_only_missing;
238 VikCoord *last_center;
242 gint dl_tool_x, dl_tool_y;
244 GtkMenu *dl_right_click_menu;
245 VikCoord redownload_ul, redownload_br; /* right click menu only */
246 VikViewport *redownload_vvp;
248 gboolean license_notice_shown; // FALSE for new maps only, otherwise
249 // TRUE for saved maps & other layer changes as we don't need to show it again
252 enum { REDOWNLOAD_NONE = 0, /* download only missing maps */
253 REDOWNLOAD_BAD, /* download missing and bad maps */
254 REDOWNLOAD_NEW, /* download missing maps that are newer on server only */
255 REDOWNLOAD_ALL, /* download all maps */
256 DOWNLOAD_OR_REFRESH }; /* download missing maps and refresh cache */
258 static VikLayerParam prefs[] = {
259 { 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") },
262 void maps_layer_init ()
264 VikLayerParamData tmp;
265 tmp.s = maps_layer_default_dir();
266 a_preferences_register(prefs, tmp, VIKING_PREFERENCES_GROUP_KEY);
268 gint max_tiles = MAX_TILES;
269 if ( a_settings_get_integer ( VIK_SETTINGS_MAP_MAX_TILES, &max_tiles ) )
270 MAX_TILES = max_tiles;
273 if ( a_settings_get_double ( VIK_SETTINGS_MAP_MIN_SHRINKFACTOR, &gdtmp ) )
274 MIN_SHRINKFACTOR = gdtmp;
276 if ( a_settings_get_double ( VIK_SETTINGS_MAP_MAX_SHRINKFACTOR, &gdtmp ) )
277 MAX_SHRINKFACTOR = gdtmp;
279 if ( a_settings_get_double ( VIK_SETTINGS_MAP_REAL_MIN_SHRINKFACTOR, &gdtmp ) )
280 REAL_MIN_SHRINKFACTOR = gdtmp;
283 /****************************************/
284 /******** MAPS LAYER TYPES **************/
285 /****************************************/
287 int _get_index_for_id ( guint id )
290 while (params_maptypes_ids[index] != 0)
292 if (params_maptypes_ids[index] == id)
299 void _add_map_source ( guint id, const char *label, VikMapSource *map )
303 len = g_strv_length (params_maptypes);
305 params_maptypes = g_realloc (params_maptypes, (len+2)*sizeof(gchar*));
306 params_maptypes[len] = g_strdup (label);
307 params_maptypes[len+1] = NULL;
310 params_maptypes_ids = g_realloc (params_maptypes_ids, (len+2)*sizeof(guint));
311 params_maptypes_ids[len] = id;
312 params_maptypes_ids[len+1] = 0;
314 /* We have to clone */
315 VikMapSource *clone = VIK_MAP_SOURCE(g_object_ref(map));
316 /* Register the clone in the list */
317 __map_types = g_list_append(__map_types, clone);
320 We have to ensure the mode LayerParam references the up-to-date
324 memcpy(&maps_layer_params[0].widget_data, ¶ms_maptypes, sizeof(gpointer));
325 memcpy(&maps_layer_params[0].extra_widget_data, ¶ms_maptypes_ids, sizeof(gpointer));
327 maps_layer_params[0].widget_data = params_maptypes;
328 maps_layer_params[0].extra_widget_data = params_maptypes_ids;
331 void _update_map_source ( const char *label, VikMapSource *map, int index )
333 GList *item = g_list_nth (__map_types, index);
334 g_object_unref (item->data);
335 item->data = g_object_ref (map);
336 /* Change previous data */
337 g_free (params_maptypes[index]);
338 params_maptypes[index] = g_strdup (label);
342 * maps_layer_register_map_source:
343 * @map: the new VikMapSource
345 * Register a new VikMapSource.
346 * Override existing one (equality of id).
348 void maps_layer_register_map_source ( VikMapSource *map )
350 g_assert(map != NULL);
352 guint id = vik_map_source_get_uniq_id(map);
353 const char *label = vik_map_source_get_label(map);
354 g_assert(label != NULL);
356 int previous = map_uniq_id_to_index (id);
357 if (previous != NUM_MAP_TYPES)
359 _update_map_source (label, map, previous);
363 _add_map_source (id, label, map);
367 #define MAPS_LAYER_NTH_LABEL(n) (params_maptypes[n])
368 #define MAPS_LAYER_NTH_ID(n) (params_maptypes_ids[n])
369 #define MAPS_LAYER_NTH_TYPE(n) (VIK_MAP_SOURCE(g_list_nth_data(__map_types, (n))))
371 gint vik_maps_layer_get_map_type(VikMapsLayer *vml)
373 return(vml->maptype);
376 gchar *vik_maps_layer_get_map_label(VikMapsLayer *vml)
378 return(g_strdup(MAPS_LAYER_NTH_LABEL(vml->maptype)));
381 /****************************************/
382 /******** CACHE DIR STUFF ***************/
383 /****************************************/
385 #define DIRECTDIRACCESS "%s%d" G_DIR_SEPARATOR_S "%d" G_DIR_SEPARATOR_S "%d%s"
386 #define DIRSTRUCTURE "%st%ds%dz%d" G_DIR_SEPARATOR_S "%d" G_DIR_SEPARATOR_S "%d"
387 #define MAPS_CACHE_DIR maps_layer_default_dir()
391 #define GLOBAL_MAPS_DIR "C:\\VIKING-MAPS\\"
392 #define LOCAL_MAPS_DIR "VIKING-MAPS"
393 #elif defined __APPLE__
395 #define GLOBAL_MAPS_DIR "/Library/cache/Viking/maps/"
396 #define LOCAL_MAPS_DIR "/Library/Application Support/Viking/viking-maps"
399 #define GLOBAL_MAPS_DIR "/var/cache/maps/"
400 #define LOCAL_MAPS_DIR ".viking-maps"
403 gchar *maps_layer_default_dir ()
405 static gchar *defaultdir = NULL;
408 /* Thanks to Mike Davison for the $VIKING_MAPS usage */
409 const gchar *mapdir = g_getenv("VIKING_MAPS");
411 defaultdir = g_strdup ( mapdir );
412 } else if ( g_access ( GLOBAL_MAPS_DIR, W_OK ) == 0 ) {
413 defaultdir = g_strdup ( GLOBAL_MAPS_DIR );
415 const gchar *home = g_get_home_dir();
416 if (!home || g_access(home, W_OK))
417 home = g_get_home_dir ();
419 defaultdir = g_build_filename ( home, LOCAL_MAPS_DIR, NULL );
421 defaultdir = g_strdup ( LOCAL_MAPS_DIR );
423 if (defaultdir && (defaultdir[strlen(defaultdir)-1] != G_DIR_SEPARATOR))
425 /* Add the separator at the end */
426 gchar *tmp = defaultdir;
427 defaultdir = g_strconcat(tmp, G_DIR_SEPARATOR_S, NULL);
430 g_debug("%s: defaultdir=%s", __FUNCTION__, defaultdir);
435 static void maps_layer_mkdir_if_default_dir ( VikMapsLayer *vml )
437 if ( vml->cache_dir && strcmp ( vml->cache_dir, MAPS_CACHE_DIR ) == 0 && g_file_test ( vml->cache_dir, G_FILE_TEST_EXISTS ) == FALSE )
439 g_mkdir ( vml->cache_dir, 0777 );
443 static void maps_layer_set_cache_dir ( VikMapsLayer *vml, const gchar *dir )
446 g_assert ( vml != NULL);
447 g_free ( vml->cache_dir );
448 vml->cache_dir = NULL;
449 const gchar *mydir = dir;
451 if ( dir == NULL || dir[0] == '\0' )
453 if ( a_preferences_get(VIKING_PREFERENCES_NAMESPACE "maplayer_default_dir") )
454 mydir = a_preferences_get(VIKING_PREFERENCES_NAMESPACE "maplayer_default_dir")->s;
457 // Ensure cache_dir always ends with a separator
459 if ( mydir[len-1] != G_DIR_SEPARATOR )
461 vml->cache_dir = g_malloc ( len+2 );
462 strncpy ( vml->cache_dir, mydir, len );
463 vml->cache_dir[len] = G_DIR_SEPARATOR;
464 vml->cache_dir[len+1] = '\0';
467 vml->cache_dir = g_strdup ( mydir );
469 maps_layer_mkdir_if_default_dir ( vml );
472 /****************************************/
473 /******** GOBJECT STUFF *****************/
474 /****************************************/
476 GType vik_maps_layer_get_type ()
478 static GType vml_type = 0;
482 static const GTypeInfo vml_info =
484 sizeof (VikMapsLayerClass),
485 NULL, /* base_init */
486 NULL, /* base_finalize */
487 NULL, /* class init */
488 NULL, /* class_finalize */
489 NULL, /* class_data */
490 sizeof (VikMapsLayer),
492 NULL /* instance init */
494 vml_type = g_type_register_static ( VIK_LAYER_TYPE, "VikMapsLayer", &vml_info, 0 );
500 /****************************************/
501 /************** PARAMETERS **************/
502 /****************************************/
504 static guint map_index_to_uniq_id (guint16 index)
506 g_assert ( index < NUM_MAP_TYPES );
507 return vik_map_source_get_uniq_id(MAPS_LAYER_NTH_TYPE(index));
510 static guint map_uniq_id_to_index ( guint uniq_id )
513 for ( i = 0; i < NUM_MAP_TYPES; i++ )
514 if ( vik_map_source_get_uniq_id(MAPS_LAYER_NTH_TYPE(i)) == uniq_id )
516 return NUM_MAP_TYPES; /* no such thing */
519 void vik_maps_layer_pretend_licence_shown ( VikMapsLayer *vml )
521 vml->license_notice_shown = TRUE;
524 static gboolean maps_layer_set_param ( VikMapsLayer *vml, guint16 id, VikLayerParamData data, VikViewport *vvp, gboolean is_file_operation )
526 // When loading from a file don't need the license reminder
527 if ( is_file_operation )
528 vml->license_notice_shown = TRUE;
532 case PARAM_CACHE_DIR: maps_layer_set_cache_dir ( vml, data.s ); break;
533 case PARAM_MAPTYPE: {
534 gint maptype = map_uniq_id_to_index(data.u);
535 if ( maptype == NUM_MAP_TYPES ) g_warning(_("Unknown map type"));
536 else vml->maptype = maptype;
539 case PARAM_ALPHA: if ( data.u <= 255 ) vml->alpha = data.u; break;
540 case PARAM_AUTODOWNLOAD: vml->autodownload = data.b; break;
541 case PARAM_ONLYMISSING: vml->adl_only_missing = data.b; break;
542 case PARAM_MAPZOOM: if ( data.u < NUM_MAPZOOMS ) {
543 vml->mapzoom_id = data.u;
544 vml->xmapzoom = __mapzooms_x [data.u];
545 vml->ymapzoom = __mapzooms_y [data.u];
546 }else g_warning (_("Unknown Map Zoom")); break;
551 static VikLayerParamData maps_layer_get_param ( VikMapsLayer *vml, guint16 id, gboolean is_file_operation )
553 VikLayerParamData rv;
556 case PARAM_CACHE_DIR:
558 gboolean set = FALSE;
559 /* Only save a blank when the map cache location equals the default
560 On reading in, when it is blank then the default is reconstructed
561 Since the default changes dependent on the user and OS, it means the resultant file is more portable */
562 if ( is_file_operation && vml->cache_dir && strcmp ( vml->cache_dir, MAPS_CACHE_DIR ) == 0 ) {
566 else if ( is_file_operation ) {
567 if ( a_vik_get_file_ref_format() == VIK_FILE_REF_FORMAT_RELATIVE ) {
568 gchar *cwd = g_get_current_dir();
570 rv.s = file_GetRelativeFilename ( cwd, vml->cache_dir );
571 if ( !rv.s ) rv.s = "";
577 rv.s = vml->cache_dir ? vml->cache_dir : "";
580 case PARAM_MAPTYPE: rv.u = map_index_to_uniq_id ( vml->maptype ); break;
581 case PARAM_ALPHA: rv.u = vml->alpha; break;
582 case PARAM_AUTODOWNLOAD: rv.u = vml->autodownload; break;
583 case PARAM_ONLYMISSING: rv.u = vml->adl_only_missing; break;
584 case PARAM_MAPZOOM: rv.u = vml->mapzoom_id; break;
589 /****************************************/
590 /****** CREATING, COPYING, FREEING ******/
591 /****************************************/
593 static VikMapsLayer *maps_layer_new ( VikViewport *vvp )
595 VikMapsLayer *vml = VIK_MAPS_LAYER ( g_object_new ( VIK_MAPS_LAYER_TYPE, NULL ) );
596 vik_layer_set_type ( VIK_LAYER(vml), VIK_LAYER_MAPS );
598 vik_layer_set_defaults ( VIK_LAYER(vml), vvp );
600 vml->dl_tool_x = vml->dl_tool_y = -1;
601 vml->last_center = NULL;
602 vml->last_xmpp = 0.0;
603 vml->last_ympp = 0.0;
605 vml->dl_right_click_menu = NULL;
606 vml->license_notice_shown = FALSE;
611 static void maps_layer_free ( VikMapsLayer *vml )
613 g_free ( vml->cache_dir );
614 vml->cache_dir = NULL;
615 if ( vml->dl_right_click_menu )
616 g_object_ref_sink ( G_OBJECT(vml->dl_right_click_menu) );
617 g_free(vml->last_center);
618 vml->last_center = NULL;
621 static void maps_layer_post_read (VikLayer *vl, VikViewport *vp, gboolean from_file)
623 if (from_file != TRUE)
625 /* If this method is not called in file reading context
626 * it is called in GUI context.
627 * So, we can check if we have to inform the user about inconsistency */
628 VikViewportDrawMode vp_drawmode;
629 VikMapsLayer *vml = VIK_MAPS_LAYER(vl);
630 VikMapSource *map = NULL;
632 vp_drawmode = vik_viewport_get_drawmode ( vp );
633 map = MAPS_LAYER_NTH_TYPE(vml->maptype);
634 if (vik_map_source_get_drawmode(map) != vp_drawmode) {
635 const gchar *drawmode_name = vik_viewport_get_drawmode_name (vp, vik_map_source_get_drawmode(map));
636 gchar *msg = g_strdup_printf(_("New map cannot be displayed in the current drawmode.\nSelect \"%s\" from View menu to view it."), drawmode_name);
637 a_dialog_warning_msg ( VIK_GTK_WINDOW_FROM_WIDGET(vp), msg );
641 if (vik_map_source_get_license (map) != NULL) {
642 if ( ! vml->license_notice_shown ) {
643 a_dialog_license (VIK_GTK_WINDOW_FROM_WIDGET(vp), vik_map_source_get_label (map),
644 vik_map_source_get_license (map), vik_map_source_get_license_url (map) );
645 vml->license_notice_shown = TRUE;
651 static const gchar* maps_layer_tooltip ( VikMapsLayer *vml )
653 return vik_maps_layer_get_map_label ( vml );
656 static void maps_layer_marshall( VikMapsLayer *vml, guint8 **data, gint *len )
658 vik_layer_marshall_params ( VIK_LAYER(vml), data, len );
661 static VikMapsLayer *maps_layer_unmarshall( guint8 *data, gint len, VikViewport *vvp )
663 VikMapsLayer *rv = maps_layer_new ( vvp );
664 vik_layer_unmarshall_params ( VIK_LAYER(rv), data, len, vvp );
668 /*********************/
669 /****** DRAWING ******/
670 /*********************/
672 static GdkPixbuf *pixbuf_set_alpha ( GdkPixbuf *pixbuf, guint8 alpha )
675 gint width, height, iii, jjj;
677 if ( ! gdk_pixbuf_get_has_alpha ( pixbuf ) )
679 GdkPixbuf *tmp = gdk_pixbuf_add_alpha(pixbuf,FALSE,0,0,0);
680 g_object_unref(G_OBJECT(pixbuf));
684 pixels = gdk_pixbuf_get_pixels(pixbuf);
685 width = gdk_pixbuf_get_width(pixbuf);
686 height = gdk_pixbuf_get_height(pixbuf);
688 /* r,g,b,a,r,g,b,a.... */
689 for (iii = 0; iii < width; iii++) for (jjj = 0; jjj < height; jjj++)
697 static GdkPixbuf *pixbuf_shrink ( GdkPixbuf *pixbuf, gdouble xshrinkfactor, gdouble yshrinkfactor )
700 guint16 width = gdk_pixbuf_get_width(pixbuf), height = gdk_pixbuf_get_height(pixbuf);
701 tmp = gdk_pixbuf_scale_simple(pixbuf, ceil(width * xshrinkfactor), ceil(height * yshrinkfactor), GDK_INTERP_BILINEAR);
702 g_object_unref ( G_OBJECT(pixbuf) );
706 static GdkPixbuf *get_pixbuf( VikMapsLayer *vml, gint mode, MapCoord *mapcoord, gchar *filename_buf, gint buf_len, gdouble xshrinkfactor, gdouble yshrinkfactor )
711 pixbuf = a_mapcache_get ( mapcoord->x, mapcoord->y, mapcoord->z,
712 mode, mapcoord->scale, vml->alpha, xshrinkfactor, yshrinkfactor );
715 if ( vik_map_source_is_direct_file_access (MAPS_LAYER_NTH_TYPE(vml->maptype)) )
716 g_snprintf ( filename_buf, buf_len, DIRECTDIRACCESS,
717 vml->cache_dir, (17 - mapcoord->scale), mapcoord->x, mapcoord->y, ".png" );
719 g_snprintf ( filename_buf, buf_len, DIRSTRUCTURE,
720 vml->cache_dir, mode,
721 mapcoord->scale, mapcoord->z, mapcoord->x, mapcoord->y );
723 if ( g_file_test ( filename_buf, G_FILE_TEST_EXISTS ) == TRUE)
726 pixbuf = gdk_pixbuf_new_from_file ( filename_buf, &gx );
728 /* free the pixbuf on error */
731 if ( gx->domain != GDK_PIXBUF_ERROR || gx->code != GDK_PIXBUF_ERROR_CORRUPT_IMAGE )
732 g_warning ( _("Couldn't open image file: %s"), gx->message );
736 g_object_unref ( G_OBJECT(pixbuf) );
739 if ( vml->alpha < 255 )
740 pixbuf = pixbuf_set_alpha ( pixbuf, vml->alpha );
741 if ( xshrinkfactor != 1.0 || yshrinkfactor != 1.0 )
742 pixbuf = pixbuf_shrink ( pixbuf, xshrinkfactor, yshrinkfactor );
744 a_mapcache_add ( pixbuf, mapcoord->x, mapcoord->y,
745 mapcoord->z, vik_map_source_get_uniq_id(MAPS_LAYER_NTH_TYPE(vml->maptype)),
746 mapcoord->scale, vml->alpha, xshrinkfactor, yshrinkfactor );
753 static gboolean should_start_autodownload(VikMapsLayer *vml, VikViewport *vvp)
755 const VikCoord *center = vik_viewport_get_center ( vvp );
757 if (vik_window_get_pan_move (VIK_WINDOW(VIK_GTK_WINDOW_FROM_WIDGET(GTK_WIDGET(vvp)))))
758 /* D'n'D pan in action: do not download */
762 // Prevent requests for downloading tiles at Zoom Level 19 and above for most map types
763 // Allow MapQuest Zoom Level up to 19
764 // TODO: This should be made a property of the map source and then use that value
765 gdouble xzoom = vik_viewport_get_xmpp ( vvp );
766 if ( (vml->maptype != 19 && map_utils_mpp_to_scale (xzoom) < -1) || (vml->maptype == 19 && map_utils_mpp_to_scale (xzoom) < -2) )
769 if (vml->last_center == NULL) {
770 VikCoord *new_center = g_malloc(sizeof(VikCoord));
771 *new_center = *center;
772 vml->last_center = new_center;
773 vml->last_xmpp = vik_viewport_get_xmpp(vvp);
774 vml->last_ympp = vik_viewport_get_ympp(vvp);
778 /* TODO: perhaps vik_coord_diff() */
779 if (vik_coord_equals(vml->last_center, center)
780 && (vml->last_xmpp == vik_viewport_get_xmpp(vvp))
781 && (vml->last_ympp == vik_viewport_get_ympp(vvp)))
784 *(vml->last_center) = *center;
785 vml->last_xmpp = vik_viewport_get_xmpp(vvp);
786 vml->last_ympp = vik_viewport_get_ympp(vvp);
790 static void maps_layer_draw_section ( VikMapsLayer *vml, VikViewport *vvp, VikCoord *ul, VikCoord *br )
793 gdouble xzoom = vik_viewport_get_xmpp ( vvp );
794 gdouble yzoom = vik_viewport_get_ympp ( vvp );
795 gdouble xshrinkfactor = 1.0, yshrinkfactor = 1.0;
796 gboolean existence_only = FALSE;
798 if ( vml->xmapzoom && (vml->xmapzoom != xzoom || vml->ymapzoom != yzoom) ) {
799 xshrinkfactor = vml->xmapzoom / xzoom;
800 yshrinkfactor = vml->ymapzoom / yzoom;
801 xzoom = vml->xmapzoom;
802 yzoom = vml->xmapzoom;
803 if ( ! (xshrinkfactor > MIN_SHRINKFACTOR && xshrinkfactor < MAX_SHRINKFACTOR &&
804 yshrinkfactor > MIN_SHRINKFACTOR && yshrinkfactor < MAX_SHRINKFACTOR ) ) {
805 if ( xshrinkfactor > REAL_MIN_SHRINKFACTOR && yshrinkfactor > REAL_MIN_SHRINKFACTOR ) {
806 g_debug ( "%s: existence_only due to SHRINKFACTORS", __FUNCTION__ );
807 existence_only = TRUE;
810 g_warning ( _("Cowardly refusing to draw tiles or existence of tiles beyond %d zoom out factor"), (int)( 1.0/REAL_MIN_SHRINKFACTOR));
817 VikMapSource *map = MAPS_LAYER_NTH_TYPE(vml->maptype);
818 if ( vik_map_source_coord_to_mapcoord ( map, ul, xzoom, yzoom, &ulm ) &&
819 vik_map_source_coord_to_mapcoord ( map, br, xzoom, yzoom, &brm ) ) {
823 gint xmin = MIN(ulm.x, brm.x), xmax = MAX(ulm.x, brm.x);
824 gint ymin = MIN(ulm.y, brm.y), ymax = MAX(ulm.y, brm.y);
825 gint mode = vik_map_source_get_uniq_id(map);
828 gint xx, yy, width, height;
831 // Prevent the program grinding to a halt if trying to deal with thousands of tiles
832 // which can happen when using a small fixed zoom level and viewing large areas.
833 // Also prevents very large number of tile download requests
834 gint tiles = (xmax-xmin) * (ymax-ymin);
835 if ( tiles > MAX_TILES ) {
836 g_debug ( "%s: existence_only due to wanting too many tiles (%d)", __FUNCTION__, tiles );
837 existence_only = TRUE;
840 guint max_path_len = strlen(vml->cache_dir) + 40;
841 gchar *path_buf = g_malloc ( max_path_len * sizeof(char) );
843 if ( (!existence_only) && vml->autodownload && should_start_autodownload(vml, vvp)) {
844 g_debug("%s: Starting autodownload", __FUNCTION__);
845 if ( !vml->adl_only_missing && vik_map_source_supports_download_only_new (map) )
846 // Try to download newer tiles
847 start_download_thread ( vml, vvp, ul, br, REDOWNLOAD_NEW );
849 // Download only missing tiles
850 start_download_thread ( vml, vvp, ul, br, REDOWNLOAD_NONE );
853 if ( vik_map_source_get_tilesize_x(map) == 0 && !existence_only ) {
854 for ( x = xmin; x <= xmax; x++ ) {
855 for ( y = ymin; y <= ymax; y++ ) {
858 pixbuf = get_pixbuf ( vml, mode, &ulm, path_buf, max_path_len, xshrinkfactor, yshrinkfactor );
860 width = gdk_pixbuf_get_width ( pixbuf );
861 height = gdk_pixbuf_get_height ( pixbuf );
863 vik_map_source_mapcoord_to_center_coord ( map, &ulm, &coord );
864 vik_viewport_coord_to_screen ( vvp, &coord, &xx, &yy );
868 vik_viewport_draw_pixbuf ( vvp, pixbuf, 0, 0, xx, yy, width, height );
872 } else { /* tilesize is known, don't have to keep converting coords */
873 gdouble tilesize_x = vik_map_source_get_tilesize_x(map) * xshrinkfactor;
874 gdouble tilesize_y = vik_map_source_get_tilesize_y(map) * yshrinkfactor;
875 /* ceiled so tiles will be maximum size in the case of funky shrinkfactor */
876 gint tilesize_x_ceil = ceil ( tilesize_x );
877 gint tilesize_y_ceil = ceil ( tilesize_y );
878 gint8 xinc = (ulm.x == xmin) ? 1 : -1;
879 gint8 yinc = (ulm.y == ymin) ? 1 : -1;
880 gdouble xx, yy; gint xx_tmp, yy_tmp;
881 gint base_yy, xend, yend;
883 xend = (xinc == 1) ? (xmax+1) : (xmin-1);
884 yend = (yinc == 1) ? (ymax+1) : (ymin-1);
886 vik_map_source_mapcoord_to_center_coord ( map, &ulm, &coord );
887 vik_viewport_coord_to_screen ( vvp, &coord, &xx_tmp, &yy_tmp );
888 xx = xx_tmp; yy = yy_tmp;
889 /* above trick so xx,yy doubles. this is so shrinkfactors aren't rounded off
890 * eg if tile size 128, shrinkfactor 0.333 */
891 xx -= (tilesize_x/2);
892 base_yy = yy - (tilesize_y/2);
894 for ( x = ((xinc == 1) ? xmin : xmax); x != xend; x+=xinc ) {
896 for ( y = ((yinc == 1) ? ymin : ymax); y != yend; y+=yinc ) {
900 if ( existence_only ) {
901 if ( vik_map_source_is_direct_file_access (MAPS_LAYER_NTH_TYPE(vml->maptype)) )
902 g_snprintf ( path_buf, max_path_len, DIRECTDIRACCESS,
903 vml->cache_dir, (17 - ulm.scale), ulm.x, ulm.y, ".png" );
905 g_snprintf ( path_buf, max_path_len, DIRSTRUCTURE,
906 vml->cache_dir, mode,
907 ulm.scale, ulm.z, ulm.x, ulm.y );
908 if ( g_file_test ( path_buf, G_FILE_TEST_EXISTS ) == TRUE ) {
909 GdkGC *black_gc = gtk_widget_get_style(GTK_WIDGET(vvp))->black_gc;
910 vik_viewport_draw_line ( vvp, black_gc, xx+tilesize_x_ceil, yy, xx, yy+tilesize_y_ceil );
914 for (scale_inc = 0; scale_inc < 4; scale_inc ++) {
915 /* try with correct then smaller zooms */
916 int scale_factor = 1 << scale_inc; /* 2^scale_inc */
918 ulm2.x = ulm.x / scale_factor;
919 ulm2.y = ulm.y / scale_factor;
920 ulm2.scale = ulm.scale + scale_inc;
921 pixbuf = get_pixbuf ( vml, mode, &ulm2, path_buf, max_path_len, xshrinkfactor * scale_factor, yshrinkfactor * scale_factor );
923 gint src_x = (ulm.x % scale_factor) * tilesize_x_ceil;
924 gint src_y = (ulm.y % scale_factor) * tilesize_y_ceil;
926 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);
928 vik_viewport_draw_pixbuf ( vvp, pixbuf, src_x, src_y, xx, yy, tilesize_x_ceil, tilesize_y_ceil );
933 /* retry with bigger zooms */
935 for (scale_dec = 1; scale_dec < 2; scale_dec ++) {
937 int scale_factor = 1 << scale_dec; /* 2^scale_dec */
939 ulm2.x = ulm.x * scale_factor;
940 ulm2.y = ulm.y * scale_factor;
941 ulm2.scale = ulm.scale - scale_dec;
942 for (pict_x = 0; pict_x < scale_factor; pict_x ++) {
943 for (pict_y = 0; pict_y < scale_factor; pict_y ++) {
944 MapCoord ulm3 = ulm2;
947 pixbuf = get_pixbuf ( vml, mode, &ulm3, path_buf, max_path_len, xshrinkfactor / scale_factor, yshrinkfactor / scale_factor );
951 gint dest_x = xx + pict_x * (tilesize_x_ceil / scale_factor);
952 gint dest_y = yy + pict_y * (tilesize_y_ceil / scale_factor);
953 vik_viewport_draw_pixbuf ( vvp, pixbuf, src_x, src_y, dest_x, dest_y, tilesize_x_ceil / scale_factor, tilesize_y_ceil / scale_factor );
971 static void maps_layer_draw ( VikMapsLayer *vml, VikViewport *vvp )
973 if ( vik_map_source_get_drawmode(MAPS_LAYER_NTH_TYPE(vml->maptype)) == vik_viewport_get_drawmode ( vvp ) )
978 gdouble level = vik_viewport_get_zoom ( vvp );
980 vik_viewport_get_min_max_lat_lon ( vvp, &bbox.south, &bbox.north, &bbox.west, &bbox.east );
981 vik_map_source_get_copyright ( MAPS_LAYER_NTH_TYPE(vml->maptype), bbox, level, vik_viewport_add_copyright, vvp );
984 const GdkPixbuf *logo = vik_map_source_get_logo ( MAPS_LAYER_NTH_TYPE(vml->maptype) );
985 vik_viewport_add_logo ( vvp, logo );
987 /* get corner coords */
988 if ( vik_viewport_get_coord_mode ( vvp ) == VIK_COORD_UTM && ! vik_viewport_is_one_zone ( vvp ) ) {
989 /* UTM multi-zone stuff by Kit Transue */
990 gchar leftmost_zone, rightmost_zone, i;
991 leftmost_zone = vik_viewport_leftmost_zone( vvp );
992 rightmost_zone = vik_viewport_rightmost_zone( vvp );
993 for ( i = leftmost_zone; i <= rightmost_zone; ++i ) {
994 vik_viewport_corners_for_zonen ( vvp, i, &ul, &br );
995 maps_layer_draw_section ( vml, vvp, &ul, &br );
999 vik_viewport_screen_to_coord ( vvp, 0, 0, &ul );
1000 vik_viewport_screen_to_coord ( vvp, vik_viewport_get_width(vvp), vik_viewport_get_height(vvp), &br );
1002 maps_layer_draw_section ( vml, vvp, &ul, &br );
1007 /*************************/
1008 /****** DOWNLOADING ******/
1009 /*************************/
1011 /* pass along data to thread, exists even if layer is deleted. */
1014 gchar *filename_buf;
1015 gint x0, y0, xf, yf;
1021 gboolean refresh_display;
1024 gboolean map_layer_alive;
1028 static void mdi_free ( MapDownloadInfo *mdi )
1030 g_mutex_free(mdi->mutex);
1031 g_free ( mdi->cache_dir );
1032 mdi->cache_dir = NULL;
1033 g_free ( mdi->filename_buf );
1034 mdi->filename_buf = NULL;
1038 static void weak_ref_cb(gpointer ptr, GObject * dead_vml)
1040 MapDownloadInfo *mdi = ptr;
1041 g_mutex_lock(mdi->mutex);
1042 mdi->map_layer_alive = FALSE;
1043 g_mutex_unlock(mdi->mutex);
1046 static int map_download_thread ( MapDownloadInfo *mdi, gpointer threaddata )
1048 void *handle = vik_map_source_download_handle_init(MAPS_LAYER_NTH_TYPE(mdi->maptype));
1051 for ( x = mdi->x0; x <= mdi->xf; x++ )
1053 for ( y = mdi->y0; y <= mdi->yf; y++ )
1055 gboolean remove_mem_cache = FALSE;
1056 gboolean need_download = FALSE;
1057 g_snprintf ( mdi->filename_buf, mdi->maxlen, DIRSTRUCTURE,
1058 mdi->cache_dir, vik_map_source_get_uniq_id(MAPS_LAYER_NTH_TYPE(mdi->maptype)),
1059 mdi->mapcoord.scale, mdi->mapcoord.z, x, y );
1062 int res = a_background_thread_progress ( threaddata, ((gdouble)donemaps) / mdi->mapstoget ); /* this also calls testcancel */
1064 vik_map_source_download_handle_cleanup(MAPS_LAYER_NTH_TYPE(mdi->maptype), handle);
1068 if ( g_file_test ( mdi->filename_buf, G_FILE_TEST_EXISTS ) == FALSE ) {
1069 need_download = TRUE;
1070 remove_mem_cache = TRUE;
1072 } else { /* in case map file already exists */
1073 switch (mdi->redownload) {
1074 case REDOWNLOAD_NONE:
1077 case REDOWNLOAD_BAD:
1079 /* see if this one is bad or what */
1081 GdkPixbuf *pixbuf = gdk_pixbuf_new_from_file ( mdi->filename_buf, &gx );
1082 if (gx || (!pixbuf)) {
1083 g_remove ( mdi->filename_buf );
1084 need_download = TRUE;
1085 remove_mem_cache = TRUE;
1086 g_error_free ( gx );
1089 g_object_unref ( pixbuf );
1094 case REDOWNLOAD_NEW:
1095 need_download = TRUE;
1096 remove_mem_cache = TRUE;
1099 case REDOWNLOAD_ALL:
1100 /* FIXME: need a better way than to erase file in case of server/network problem */
1101 g_remove ( mdi->filename_buf );
1102 need_download = TRUE;
1103 remove_mem_cache = TRUE;
1106 case DOWNLOAD_OR_REFRESH:
1107 remove_mem_cache = TRUE;
1111 g_warning ( "redownload state %d unknown\n", mdi->redownload);
1115 mdi->mapcoord.x = x; mdi->mapcoord.y = y;
1117 if (need_download) {
1118 if ( vik_map_source_download( MAPS_LAYER_NTH_TYPE(mdi->maptype), &(mdi->mapcoord), mdi->filename_buf, handle))
1122 g_mutex_lock(mdi->mutex);
1123 if (remove_mem_cache)
1124 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 );
1125 if (mdi->refresh_display && mdi->map_layer_alive) {
1126 /* TODO: check if it's on visible area */
1127 vik_layer_emit_update ( VIK_LAYER(mdi->vml) ); // NB update display from background
1129 g_mutex_unlock(mdi->mutex);
1130 mdi->mapcoord.x = mdi->mapcoord.y = 0; /* we're temporarily between downloads */
1134 vik_map_source_download_handle_cleanup(MAPS_LAYER_NTH_TYPE(mdi->maptype), handle);
1135 g_mutex_lock(mdi->mutex);
1136 if (mdi->map_layer_alive)
1137 g_object_weak_unref(G_OBJECT(mdi->vml), weak_ref_cb, mdi);
1138 g_mutex_unlock(mdi->mutex);
1142 static void mdi_cancel_cleanup ( MapDownloadInfo *mdi )
1144 if ( mdi->mapcoord.x || mdi->mapcoord.y )
1146 g_snprintf ( mdi->filename_buf, mdi->maxlen, DIRSTRUCTURE,
1147 mdi->cache_dir, vik_map_source_get_uniq_id(MAPS_LAYER_NTH_TYPE(mdi->maptype)),
1148 mdi->mapcoord.scale, mdi->mapcoord.z, mdi->mapcoord.x, mdi->mapcoord.y );
1149 if ( g_file_test ( mdi->filename_buf, G_FILE_TEST_EXISTS ) == TRUE)
1151 g_remove ( mdi->filename_buf );
1156 static void start_download_thread ( VikMapsLayer *vml, VikViewport *vvp, const VikCoord *ul, const VikCoord *br, gint redownload )
1158 gdouble xzoom = vml->xmapzoom ? vml->xmapzoom : vik_viewport_get_xmpp ( vvp );
1159 gdouble yzoom = vml->ymapzoom ? vml->ymapzoom : vik_viewport_get_ympp ( vvp );
1161 VikMapSource *map = MAPS_LAYER_NTH_TYPE(vml->maptype);
1163 // Don't ever attempt download on direct access
1164 if ( vik_map_source_is_direct_file_access ( map ) )
1167 if ( vik_map_source_coord_to_mapcoord ( map, ul, xzoom, yzoom, &ulm )
1168 && vik_map_source_coord_to_mapcoord ( map, br, xzoom, yzoom, &brm ) )
1170 MapDownloadInfo *mdi = g_malloc ( sizeof(MapDownloadInfo) );
1175 mdi->map_layer_alive = TRUE;
1176 mdi->mutex = g_mutex_new();
1177 mdi->refresh_display = TRUE;
1179 /* cache_dir and buffer for dest filename */
1180 mdi->cache_dir = g_strdup ( vml->cache_dir );
1181 mdi->maxlen = strlen ( vml->cache_dir ) + 40;
1182 mdi->filename_buf = g_malloc ( mdi->maxlen * sizeof(gchar) );
1183 mdi->maptype = vml->maptype;
1185 mdi->mapcoord = ulm;
1186 mdi->redownload = redownload;
1188 mdi->x0 = MIN(ulm.x, brm.x);
1189 mdi->xf = MAX(ulm.x, brm.x);
1190 mdi->y0 = MIN(ulm.y, brm.y);
1191 mdi->yf = MAX(ulm.y, brm.y);
1195 if ( mdi->redownload ) {
1196 mdi->mapstoget = (mdi->xf - mdi->x0 + 1) * (mdi->yf - mdi->y0 + 1);
1198 /* calculate how many we need */
1199 for ( a = mdi->x0; a <= mdi->xf; a++ )
1201 for ( b = mdi->y0; b <= mdi->yf; b++ )
1203 g_snprintf ( mdi->filename_buf, mdi->maxlen, DIRSTRUCTURE,
1204 vml->cache_dir, vik_map_source_get_uniq_id(map), ulm.scale,
1206 if ( g_file_test ( mdi->filename_buf, G_FILE_TEST_EXISTS ) == FALSE )
1212 mdi->mapcoord.x = mdi->mapcoord.y = 0; /* for cleanup -- no current map */
1214 if ( mdi->mapstoget )
1216 const gchar *tmp_str;
1221 if (redownload == REDOWNLOAD_BAD)
1222 tmp_str = ngettext("Redownloading up to %d %s map...", "Redownloading up to %d %s maps...", mdi->mapstoget);
1224 tmp_str = ngettext("Redownloading %d %s map...", "Redownloading %d %s maps...", mdi->mapstoget);
1228 tmp_str = ngettext("Downloading %d %s map...", "Downloading %d %s maps...", mdi->mapstoget);
1230 tmp = g_strdup_printf ( tmp_str, mdi->mapstoget, MAPS_LAYER_NTH_LABEL(vml->maptype));
1232 g_object_weak_ref(G_OBJECT(mdi->vml), weak_ref_cb, mdi);
1233 /* launch the thread */
1234 a_background_thread ( VIK_GTK_WINDOW_FROM_LAYER(vml), /* parent window */
1235 tmp, /* description string */
1236 (vik_thr_func) map_download_thread, /* function to call within thread */
1237 mdi, /* pass along data */
1238 (vik_thr_free_func) mdi_free, /* function to free pass along data */
1239 (vik_thr_free_func) mdi_cancel_cleanup,
1248 static void maps_layer_download_section ( VikMapsLayer *vml, VikViewport *vvp, VikCoord *ul, VikCoord *br, gdouble zoom, gint download_method )
1251 VikMapSource *map = MAPS_LAYER_NTH_TYPE(vml->maptype);
1253 // Don't ever attempt download on direct access
1254 if ( vik_map_source_is_direct_file_access ( map ) )
1257 if (!vik_map_source_coord_to_mapcoord(map, ul, zoom, zoom, &ulm)
1258 || !vik_map_source_coord_to_mapcoord(map, br, zoom, zoom, &brm)) {
1259 g_warning("%s() coord_to_mapcoord() failed", __PRETTY_FUNCTION__);
1263 MapDownloadInfo *mdi = g_malloc(sizeof(MapDownloadInfo));
1268 mdi->map_layer_alive = TRUE;
1269 mdi->mutex = g_mutex_new();
1270 mdi->refresh_display = TRUE;
1272 mdi->cache_dir = g_strdup ( vml->cache_dir );
1273 mdi->maxlen = strlen ( vml->cache_dir ) + 40;
1274 mdi->filename_buf = g_malloc ( mdi->maxlen * sizeof(gchar) );
1275 mdi->maptype = vml->maptype;
1277 mdi->mapcoord = ulm;
1278 mdi->redownload = download_method;
1280 mdi->x0 = MIN(ulm.x, brm.x);
1281 mdi->xf = MAX(ulm.x, brm.x);
1282 mdi->y0 = MIN(ulm.y, brm.y);
1283 mdi->yf = MAX(ulm.y, brm.y);
1287 for (i = mdi->x0; i <= mdi->xf; i++) {
1288 for (j = mdi->y0; j <= mdi->yf; j++) {
1289 g_snprintf ( mdi->filename_buf, mdi->maxlen, DIRSTRUCTURE,
1290 vml->cache_dir, vik_map_source_get_uniq_id(map), ulm.scale,
1292 if ( g_file_test ( mdi->filename_buf, G_FILE_TEST_EXISTS ) == FALSE )
1297 mdi->mapcoord.x = mdi->mapcoord.y = 0; /* for cleanup -- no current map */
1299 if (mdi->mapstoget) {
1302 fmt = ngettext("Downloading %d %s map...",
1303 "Downloading %d %s maps...",
1305 tmp = g_strdup_printf ( fmt, mdi->mapstoget, MAPS_LAYER_NTH_LABEL(vml->maptype) );
1307 g_object_weak_ref(G_OBJECT(mdi->vml), weak_ref_cb, mdi);
1308 /* launch the thread */
1309 a_background_thread ( VIK_GTK_WINDOW_FROM_LAYER(vml), /* parent window */
1310 tmp, /* description string */
1311 (vik_thr_func) map_download_thread, /* function to call within thread */
1312 mdi, /* pass along data */
1313 (vik_thr_free_func) mdi_free, /* function to free pass along data */
1314 (vik_thr_free_func) mdi_cancel_cleanup,
1323 * vik_maps_layer_download_section:
1324 * @vml: The Map Layer
1325 * @vvp: The Viewport that the map is on
1326 * @ul: Upper left coordinate of the area to be downloaded
1327 * @br: Bottom right coordinate of the area to be downloaded
1328 * @zoom: The zoom level at which the maps are to be download
1330 * Download a specified map area at a certain zoom level
1332 void vik_maps_layer_download_section ( VikMapsLayer *vml, VikViewport *vvp, VikCoord *ul, VikCoord *br, gdouble zoom )
1334 maps_layer_download_section (vml, vvp, ul, br, zoom, REDOWNLOAD_NONE);
1337 static void maps_layer_redownload_bad ( VikMapsLayer *vml )
1339 start_download_thread ( vml, vml->redownload_vvp, &(vml->redownload_ul), &(vml->redownload_br), REDOWNLOAD_BAD );
1342 static void maps_layer_redownload_all ( VikMapsLayer *vml )
1344 start_download_thread ( vml, vml->redownload_vvp, &(vml->redownload_ul), &(vml->redownload_br), REDOWNLOAD_ALL );
1347 static void maps_layer_redownload_new ( VikMapsLayer *vml )
1349 start_download_thread ( vml, vml->redownload_vvp, &(vml->redownload_ul), &(vml->redownload_br), REDOWNLOAD_NEW );
1353 * Display a simple dialog with information about this particular map tile
1355 static void maps_layer_tile_info ( VikMapsLayer *vml )
1357 VikMapSource *map = MAPS_LAYER_NTH_TYPE(vml->maptype);
1359 gdouble xzoom = vml->xmapzoom ? vml->xmapzoom : vik_viewport_get_xmpp ( vml->redownload_vvp );
1360 gdouble yzoom = vml->ymapzoom ? vml->ymapzoom : vik_viewport_get_ympp ( vml->redownload_vvp );
1363 if ( !vik_map_source_coord_to_mapcoord ( map, &(vml->redownload_ul), xzoom, yzoom, &ulm ) )
1366 gchar *filename = NULL;
1367 gchar *message = NULL;
1368 gchar *source = NULL;
1370 if ( vik_map_source_is_direct_file_access ( map ) ) {
1371 filename = g_strdup_printf ( DIRECTDIRACCESS, vml->cache_dir, ulm.scale, ulm.x, ulm.y, ".png" );
1372 source = g_strconcat ( "file://", filename, NULL );
1375 filename = g_strdup_printf ( DIRSTRUCTURE, vml->cache_dir, vik_map_source_get_uniq_id(map), ulm.scale, ulm.z, ulm.x, ulm.y );
1376 source = g_strdup_printf ( "http://%s%s",
1377 vik_map_source_default_get_hostname ( VIK_MAP_SOURCE_DEFAULT(map) ),
1378 vik_map_source_default_get_uri ( VIK_MAP_SOURCE_DEFAULT(map), &ulm ) );
1381 if ( g_file_test ( filename, G_FILE_TEST_EXISTS ) ) {
1383 // Get some timestamp information of the tile
1384 struct stat stat_buf;
1385 if ( g_stat ( filename, &stat_buf ) == 0 ) {
1387 strftime ( time_buf, sizeof(time_buf), "%c", gmtime((const time_t *)&stat_buf.st_mtime) );
1388 message = g_strdup_printf ( _("\nSource: %s\n\nTile File: %s\nTile File Timestamp: %s"), source, filename, time_buf );
1392 message = g_strdup_printf ( _("Source: %s\n\nNo Tile File!"), source );
1395 a_dialog_info_msg ( VIK_GTK_WINDOW_FROM_LAYER(vml), message );
1399 g_free ( filename );
1402 static gboolean maps_layer_download_release ( VikMapsLayer *vml, GdkEventButton *event, VikViewport *vvp )
1404 if (!vml || vml->vl.type != VIK_LAYER_MAPS)
1406 if ( vml->dl_tool_x != -1 && vml->dl_tool_y != -1 )
1408 if ( event->button == 1 )
1411 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 );
1412 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 );
1413 start_download_thread ( vml, vvp, &ul, &br, DOWNLOAD_OR_REFRESH );
1414 vml->dl_tool_x = vml->dl_tool_y = -1;
1419 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) );
1420 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) );
1422 vml->redownload_vvp = vvp;
1424 vml->dl_tool_x = vml->dl_tool_y = -1;
1426 if ( ! vml->dl_right_click_menu ) {
1428 vml->dl_right_click_menu = GTK_MENU ( gtk_menu_new () );
1430 item = gtk_menu_item_new_with_mnemonic ( _("Redownload _Bad Map(s)") );
1431 g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(maps_layer_redownload_bad), vml );
1432 gtk_menu_shell_append ( GTK_MENU_SHELL(vml->dl_right_click_menu), item );
1434 item = gtk_menu_item_new_with_mnemonic ( _("Redownload _New Map(s)") );
1435 g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(maps_layer_redownload_new), vml );
1436 gtk_menu_shell_append ( GTK_MENU_SHELL(vml->dl_right_click_menu), item );
1438 item = gtk_menu_item_new_with_mnemonic ( _("Redownload _All Map(s)") );
1439 g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(maps_layer_redownload_all), vml );
1440 gtk_menu_shell_append ( GTK_MENU_SHELL(vml->dl_right_click_menu), item );
1442 item = gtk_image_menu_item_new_with_mnemonic ( _("_Show Tile Information") );
1443 gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_INFO, GTK_ICON_SIZE_MENU) );
1444 g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(maps_layer_tile_info), vml );
1445 gtk_menu_shell_append (GTK_MENU_SHELL(vml->dl_right_click_menu), item);
1448 gtk_menu_popup ( vml->dl_right_click_menu, NULL, NULL, NULL, NULL, event->button, event->time );
1449 gtk_widget_show_all ( GTK_WIDGET(vml->dl_right_click_menu) );
1455 static gpointer maps_layer_download_create ( VikWindow *vw, VikViewport *vvp)
1460 static gboolean maps_layer_download_click ( VikMapsLayer *vml, GdkEventButton *event, VikViewport *vvp )
1463 if (!vml || vml->vl.type != VIK_LAYER_MAPS)
1465 VikMapSource *map = MAPS_LAYER_NTH_TYPE(vml->maptype);
1466 if ( vik_map_source_get_drawmode(map) == vik_viewport_get_drawmode ( vvp ) &&
1467 vik_map_source_coord_to_mapcoord ( map, vik_viewport_get_center ( vvp ),
1468 vml->xmapzoom ? vml->xmapzoom : vik_viewport_get_xmpp ( vvp ),
1469 vml->ymapzoom ? vml->ymapzoom : vik_viewport_get_ympp ( vvp ),
1471 vml->dl_tool_x = event->x, vml->dl_tool_y = event->y;
1478 if ( __map_types[vml->maptype].drawmode == vik_viewport_get_drawmode ( vvp ) )
1482 vik_viewport_screen_to_coord ( vvp, event->x, event->y, &coord );
1483 if ( __map_types[vml->maptype].coord_to_mapcoord ( &coord,
1484 vml->xmapzoom ? vml->xmapzoom : vik_viewport_get_xmpp ( vvp ),
1485 vml->ymapzoom ? vml->ymapzoom : vik_viewport_get_ympp ( vvp ),
1487 gchar *filename_buf = g_strdup_printf ( DIRSTRUCTURE,
1488 vml->cache_dir, __map_types[vml->maptype].uniq_id,
1489 mapcoord.scale, mapcoord.z, mapcoord.x, mapcoord.y );
1491 __map_types[vml->maptype].download ( &mapcoord, filename_buf );
1492 g_free ( filename_buf );
1493 vik_layer_emit_update ( VIK_LAYER(vml) );
1501 static void download_onscreen_maps ( gpointer vml_vvp[2], gint redownload )
1503 VikMapsLayer *vml = vml_vvp[0];
1504 VikViewport *vvp = vml_vvp[1];
1505 VikViewportDrawMode vp_drawmode = vik_viewport_get_drawmode ( vvp );
1507 gdouble xzoom = vml->xmapzoom ? vml->xmapzoom : vik_viewport_get_xmpp ( vvp );
1508 gdouble yzoom = vml->ymapzoom ? vml->ymapzoom : vik_viewport_get_ympp ( vvp );
1513 vik_viewport_screen_to_coord ( vvp, 0, 0, &ul );
1514 vik_viewport_screen_to_coord ( vvp, vik_viewport_get_width(vvp), vik_viewport_get_height(vvp), &br );
1516 VikMapSource *map = MAPS_LAYER_NTH_TYPE(vml->maptype);
1517 if ( vik_map_source_get_drawmode(map) == vp_drawmode &&
1518 vik_map_source_coord_to_mapcoord ( map, &ul, xzoom, yzoom, &ulm ) &&
1519 vik_map_source_coord_to_mapcoord ( map, &br, xzoom, yzoom, &brm ) )
1520 start_download_thread ( vml, vvp, &ul, &br, redownload );
1521 else if (vik_map_source_get_drawmode(map) != vp_drawmode) {
1522 const gchar *drawmode_name = vik_viewport_get_drawmode_name (vvp, vik_map_source_get_drawmode(map));
1523 gchar *err = g_strdup_printf(_("Wrong drawmode for this map.\nSelect \"%s\" from View menu and try again."), _(drawmode_name));
1524 a_dialog_error_msg ( VIK_GTK_WINDOW_FROM_LAYER(vml), err );
1528 a_dialog_error_msg ( VIK_GTK_WINDOW_FROM_LAYER(vml), _("Wrong zoom level for this map.") );
1532 static void maps_layer_download_missing_onscreen_maps ( gpointer vml_vvp[2] )
1534 download_onscreen_maps( vml_vvp, REDOWNLOAD_NONE);
1537 static void maps_layer_download_new_onscreen_maps ( gpointer vml_vvp[2] )
1539 download_onscreen_maps( vml_vvp, REDOWNLOAD_NEW);
1542 static void maps_layer_redownload_all_onscreen_maps ( gpointer vml_vvp[2] )
1544 download_onscreen_maps( vml_vvp, REDOWNLOAD_ALL);
1548 * maps_layer_how_many_maps:
1549 * Copied from maps_layer_download_section but without the actual download and this returns a value
1551 static gint maps_layer_how_many_maps ( VikMapsLayer *vml, VikViewport *vvp, VikCoord *ul, VikCoord *br, gdouble zoom, gint redownload )
1554 VikMapSource *map = MAPS_LAYER_NTH_TYPE(vml->maptype);
1556 if ( vik_map_source_is_direct_file_access ( map ) )
1559 if (!vik_map_source_coord_to_mapcoord(map, ul, zoom, zoom, &ulm)
1560 || !vik_map_source_coord_to_mapcoord(map, br, zoom, zoom, &brm)) {
1561 g_warning("%s() coord_to_mapcoord() failed", __PRETTY_FUNCTION__);
1565 MapDownloadInfo *mdi = g_malloc(sizeof(MapDownloadInfo));
1570 mdi->map_layer_alive = TRUE;
1571 mdi->mutex = g_mutex_new();
1572 mdi->refresh_display = FALSE;
1574 mdi->cache_dir = g_strdup ( vml->cache_dir );
1575 mdi->maxlen = strlen ( vml->cache_dir ) + 40;
1576 mdi->filename_buf = g_malloc ( mdi->maxlen * sizeof(gchar) );
1577 mdi->maptype = vml->maptype;
1579 mdi->mapcoord = ulm;
1580 mdi->redownload = redownload;
1582 mdi->x0 = MIN(ulm.x, brm.x);
1583 mdi->xf = MAX(ulm.x, brm.x);
1584 mdi->y0 = MIN(ulm.y, brm.y);
1585 mdi->yf = MAX(ulm.y, brm.y);
1589 if ( mdi->redownload == REDOWNLOAD_ALL ) {
1590 mdi->mapstoget = (mdi->xf - mdi->x0 + 1) * (mdi->yf - mdi->y0 + 1);
1593 /* calculate how many we need */
1594 for (i = mdi->x0; i <= mdi->xf; i++) {
1595 for (j = mdi->y0; j <= mdi->yf; j++) {
1596 g_snprintf ( mdi->filename_buf, mdi->maxlen, DIRSTRUCTURE,
1597 vml->cache_dir, vik_map_source_get_uniq_id(map), ulm.scale,
1599 if ( mdi->redownload == REDOWNLOAD_NEW ) {
1600 // Assume the worst - always a new file
1601 // Absolute value would requires server lookup - but that is too slow
1605 if ( g_file_test ( mdi->filename_buf, G_FILE_TEST_EXISTS ) == FALSE ) {
1610 if ( mdi->redownload == REDOWNLOAD_BAD ) {
1611 /* see if this one is bad or what */
1613 GdkPixbuf *pixbuf = gdk_pixbuf_new_from_file ( mdi->filename_buf, &gx );
1614 if (gx || (!pixbuf)) {
1618 // Other download cases already considered or just ignored
1626 gint rv = mdi->mapstoget;
1634 * maps_dialog_zoom_between:
1635 * This dialog is specific to the map layer, so it's here rather than in dialog.c
1637 gboolean maps_dialog_zoom_between ( GtkWindow *parent,
1642 gint *selected_zoom1,
1643 gint *selected_zoom2,
1644 gchar *download_list[],
1645 gint default_download,
1646 gint *selected_download )
1648 GtkWidget *dialog = gtk_dialog_new_with_buttons ( title,
1650 GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
1651 GTK_STOCK_OK, GTK_RESPONSE_ACCEPT,
1652 GTK_STOCK_CANCEL, GTK_RESPONSE_REJECT,
1654 gtk_dialog_set_default_response ( GTK_DIALOG(dialog), GTK_RESPONSE_ACCEPT );
1655 GtkWidget *response_w = NULL;
1656 #if GTK_CHECK_VERSION (2, 20, 0)
1657 response_w = gtk_dialog_get_widget_for_response ( GTK_DIALOG(dialog), GTK_RESPONSE_ACCEPT );
1659 GtkWidget *zoom_label1 = gtk_label_new ( _("Zoom Start:") );
1660 GtkWidget *zoom_combo1 = vik_combo_box_text_new();
1662 for (s = zoom_list; *s; s++)
1663 vik_combo_box_text_append ( zoom_combo1, *s );
1664 gtk_combo_box_set_active ( GTK_COMBO_BOX(zoom_combo1), default_zoom1 );
1666 GtkWidget *zoom_label2 = gtk_label_new ( _("Zoom End:") );
1667 GtkWidget *zoom_combo2 = vik_combo_box_text_new();
1668 for (s = zoom_list; *s; s++)
1669 vik_combo_box_text_append ( zoom_combo2, *s );
1670 gtk_combo_box_set_active ( GTK_COMBO_BOX(zoom_combo2), default_zoom2 );
1672 GtkWidget *download_label = gtk_label_new(_("Download Maps Method:"));
1673 GtkWidget *download_combo = vik_combo_box_text_new();
1674 for (s = download_list; *s; s++)
1675 vik_combo_box_text_append ( download_combo, *s );
1676 gtk_combo_box_set_active ( GTK_COMBO_BOX(download_combo), default_download );
1678 GtkTable *box = GTK_TABLE(gtk_table_new(3, 2, FALSE));
1679 gtk_table_attach_defaults (box, GTK_WIDGET(zoom_label1), 0, 1, 0, 1);
1680 gtk_table_attach_defaults (box, GTK_WIDGET(zoom_combo1), 1, 2, 0, 1);
1681 gtk_table_attach_defaults (box, GTK_WIDGET(zoom_label2), 0, 1, 1, 2);
1682 gtk_table_attach_defaults (box, GTK_WIDGET(zoom_combo2), 1, 2, 1, 2);
1683 gtk_table_attach_defaults (box, GTK_WIDGET(download_label), 0, 1, 2, 3);
1684 gtk_table_attach_defaults (box, GTK_WIDGET(download_combo), 1, 2, 2, 3);
1686 gtk_box_pack_start ( GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(dialog))), GTK_WIDGET(box), FALSE, FALSE, 5 );
1689 gtk_widget_grab_focus ( response_w );
1691 gtk_widget_show_all ( dialog );
1692 if ( gtk_dialog_run ( GTK_DIALOG(dialog) ) != GTK_RESPONSE_ACCEPT ) {
1693 gtk_widget_destroy(dialog);
1697 // Return selected options
1698 *selected_zoom1 = gtk_combo_box_get_active ( GTK_COMBO_BOX(zoom_combo1) );
1699 *selected_zoom2 = gtk_combo_box_get_active ( GTK_COMBO_BOX(zoom_combo2) );
1700 *selected_download = gtk_combo_box_get_active ( GTK_COMBO_BOX(download_combo) );
1702 gtk_widget_destroy(dialog);
1706 // My best guess of sensible limits
1707 #define REALLY_LARGE_AMOUNT_OF_TILES 5000
1708 #define CONFIRM_LARGE_AMOUNT_OF_TILES 500
1711 * Get all maps in the region for zoom levels specified by the user
1712 * Sort of similar to trw_layer_download_map_along_track_cb function
1714 static void maps_layer_download_all ( gpointer vml_vvp[2] )
1716 VikMapsLayer *vml = vml_vvp[0];
1717 VikViewport *vvp = vml_vvp[1];
1719 // I don't think we should allow users to hammer the servers too much...
1720 // Delibrately not allowing lowest zoom levels
1721 // Still can give massive numbers to download
1722 // A screen size of 1600x1200 gives around 300,000 tiles between 1..128 when none exist before !!
1723 gchar *zoom_list[] = {"1", "2", "4", "8", "16", "32", "64", "128", "256", "512", "1024", NULL };
1724 gdouble zoom_vals[] = {1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024};
1726 gint selected_zoom1, selected_zoom2, default_zoom, lower_zoom;
1727 gint selected_download_method;
1729 gdouble cur_zoom = vik_viewport_get_zoom(vvp);
1731 for (default_zoom = 0; default_zoom < sizeof(zoom_vals)/sizeof(gdouble); default_zoom++) {
1732 if (cur_zoom == zoom_vals[default_zoom])
1735 default_zoom = (default_zoom == sizeof(zoom_vals)/sizeof(gdouble)) ? sizeof(zoom_vals)/sizeof(gdouble) - 1 : default_zoom;
1737 // Default to only 2 zoom levels below the current one
1738 if (default_zoom > 1 )
1739 lower_zoom = default_zoom - 2;
1741 lower_zoom = default_zoom;
1743 // redownload method - needs to align with REDOWNLOAD* macro values
1744 gchar *download_list[] = { _("Missing"), _("Bad"), _("New"), _("Reload All"), NULL };
1746 gchar *title = g_strdup_printf ( ("%s: %s"), vik_maps_layer_get_map_label (vml), _("Download for Zoom Levels") );
1748 if ( ! maps_dialog_zoom_between ( VIK_GTK_WINDOW_FROM_LAYER(vml),
1756 REDOWNLOAD_NONE, // AKA Missing
1757 &selected_download_method ) ) {
1764 // Find out new current positions
1765 gdouble min_lat, max_lat, min_lon, max_lon;
1766 VikCoord vc_ul, vc_br;
1767 vik_viewport_get_min_max_lat_lon ( vvp, &min_lat, &max_lat, &min_lon, &max_lon );
1768 struct LatLon ll_ul = { max_lat, min_lon };
1769 struct LatLon ll_br = { min_lat, max_lon };
1770 vik_coord_load_from_latlon ( &vc_ul, vik_viewport_get_coord_mode (vvp), &ll_ul );
1771 vik_coord_load_from_latlon ( &vc_br, vik_viewport_get_coord_mode (vvp), &ll_br );
1773 // Get Maps Count - call for each zoom level (in reverse)
1774 // With REDOWNLOAD_NEW this is a possible maximum
1775 // With REDOWNLOAD_NONE this only missing ones - however still has a server lookup per tile
1778 for ( zz = selected_zoom2; zz >= selected_zoom1; zz-- ) {
1779 map_count = map_count + maps_layer_how_many_maps ( vml, vvp, &vc_ul, &vc_br, zoom_vals[zz], selected_download_method );
1782 g_debug ("vikmapslayer: download request map count %d for method %d", map_count, selected_download_method);
1784 // Absolute protection of hammering a map server
1785 if ( map_count > REALLY_LARGE_AMOUNT_OF_TILES ) {
1786 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);
1787 a_dialog_error_msg ( VIK_GTK_WINDOW_FROM_LAYER(vml), str );
1792 // Confirm really want to do this
1793 if ( map_count > CONFIRM_LARGE_AMOUNT_OF_TILES ) {
1794 gchar *str = g_strdup_printf (_("Do you really want to download %d tiles?"), map_count);
1795 gboolean ans = a_dialog_yes_or_no ( VIK_GTK_WINDOW_FROM_LAYER(vml), str, NULL );
1801 // Get Maps - call for each zoom level (in reverse)
1802 for ( zz = selected_zoom2; zz >= selected_zoom1; zz-- ) {
1803 maps_layer_download_section ( vml, vvp, &vc_ul, &vc_br, zoom_vals[zz], selected_download_method );
1807 static void maps_layer_add_menu_items ( VikMapsLayer *vml, GtkMenu *menu, VikLayersPanel *vlp )
1809 static gpointer pass_along[2];
1811 pass_along[0] = vml;
1812 pass_along[1] = vik_layers_panel_get_viewport( VIK_LAYERS_PANEL(vlp) );
1814 item = gtk_menu_item_new();
1815 gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item );
1816 gtk_widget_show ( item );
1818 /* Now with icons */
1819 item = gtk_image_menu_item_new_with_mnemonic ( _("Download _Missing Onscreen Maps") );
1820 gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_ADD, GTK_ICON_SIZE_MENU) );
1821 g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(maps_layer_download_missing_onscreen_maps), pass_along );
1822 gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
1823 gtk_widget_show ( item );
1825 if ( vik_map_source_supports_download_only_new (MAPS_LAYER_NTH_TYPE(vml->maptype)) ) {
1826 item = gtk_image_menu_item_new_with_mnemonic ( _("Download _New Onscreen Maps") );
1827 gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_REDO, GTK_ICON_SIZE_MENU) );
1828 g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(maps_layer_download_new_onscreen_maps), pass_along );
1829 gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
1830 gtk_widget_show ( item );
1833 item = gtk_image_menu_item_new_with_mnemonic ( _("Reload _All Onscreen Maps") );
1834 gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_REFRESH, GTK_ICON_SIZE_MENU) );
1835 g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(maps_layer_redownload_all_onscreen_maps), pass_along );
1836 gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
1837 gtk_widget_show ( item );
1839 item = gtk_image_menu_item_new_with_mnemonic ( _("Download Maps in _Zoom Levels...") );
1840 gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_DND_MULTIPLE, GTK_ICON_SIZE_MENU) );
1841 g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(maps_layer_download_all), pass_along );
1842 gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
1843 gtk_widget_show ( item );
1847 * Enable downloading maps of the current screen area either 'new' or 'everything'
1849 void vik_maps_layer_download ( VikMapsLayer *vml, VikViewport *vvp, gboolean only_new )
1854 static gpointer pass_along[2];
1855 pass_along[0] = vml;
1856 pass_along[1] = vvp;
1859 // Get only new maps
1860 maps_layer_download_new_onscreen_maps ( pass_along );
1862 // Redownload everything
1863 maps_layer_redownload_all_onscreen_maps ( pass_along );