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, NULL, NULL },
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, NULL, NULL },
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, NULL, NULL },
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, NULL, NULL },
129 { VIK_LAYER_MAPS, "adlonlymissing", VIK_LAYER_PARAM_BOOLEAN, VIK_LAYER_GROUP_NONE, N_("Autodownload Only Gets Missing Maps:"), VIK_LAYER_WIDGET_CHECKBUTTON,
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, NULL, NULL },
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."),
133 mapzoom_default, NULL, NULL },
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 void _add_map_source ( guint id, const char *label, VikMapSource *map )
291 len = g_strv_length (params_maptypes);
293 params_maptypes = g_realloc (params_maptypes, (len+2)*sizeof(gchar*));
294 params_maptypes[len] = g_strdup (label);
295 params_maptypes[len+1] = NULL;
298 params_maptypes_ids = g_realloc (params_maptypes_ids, (len+2)*sizeof(guint));
299 params_maptypes_ids[len] = id;
300 params_maptypes_ids[len+1] = 0;
302 /* We have to clone */
303 VikMapSource *clone = VIK_MAP_SOURCE(g_object_ref(map));
304 /* Register the clone in the list */
305 __map_types = g_list_append(__map_types, clone);
308 We have to ensure the mode LayerParam references the up-to-date
312 memcpy(&maps_layer_params[0].widget_data, ¶ms_maptypes, sizeof(gpointer));
313 memcpy(&maps_layer_params[0].extra_widget_data, ¶ms_maptypes_ids, sizeof(gpointer));
315 maps_layer_params[0].widget_data = params_maptypes;
316 maps_layer_params[0].extra_widget_data = params_maptypes_ids;
319 void _update_map_source ( const char *label, VikMapSource *map, int index )
321 GList *item = g_list_nth (__map_types, index);
322 g_object_unref (item->data);
323 item->data = g_object_ref (map);
324 /* Change previous data */
325 g_free (params_maptypes[index]);
326 params_maptypes[index] = g_strdup (label);
330 * maps_layer_register_map_source:
331 * @map: the new VikMapSource
333 * Register a new VikMapSource.
334 * Override existing one (equality of id).
336 void maps_layer_register_map_source ( VikMapSource *map )
338 g_assert(map != NULL);
340 guint id = vik_map_source_get_uniq_id(map);
341 const char *label = vik_map_source_get_label(map);
342 g_assert(label != NULL);
344 int previous = map_uniq_id_to_index (id);
345 if (previous != NUM_MAP_TYPES)
347 _update_map_source (label, map, previous);
351 _add_map_source (id, label, map);
355 #define MAPS_LAYER_NTH_LABEL(n) (params_maptypes[n])
356 #define MAPS_LAYER_NTH_ID(n) (params_maptypes_ids[n])
357 #define MAPS_LAYER_NTH_TYPE(n) (VIK_MAP_SOURCE(g_list_nth_data(__map_types, (n))))
359 gint vik_maps_layer_get_map_type(VikMapsLayer *vml)
361 return(vml->maptype);
364 gchar *vik_maps_layer_get_map_label(VikMapsLayer *vml)
366 return(g_strdup(MAPS_LAYER_NTH_LABEL(vml->maptype)));
369 /****************************************/
370 /******** CACHE DIR STUFF ***************/
371 /****************************************/
373 #define DIRECTDIRACCESS "%s%d" G_DIR_SEPARATOR_S "%d" G_DIR_SEPARATOR_S "%d%s"
374 #define DIRSTRUCTURE "%st%ds%dz%d" G_DIR_SEPARATOR_S "%d" G_DIR_SEPARATOR_S "%d"
375 #define MAPS_CACHE_DIR maps_layer_default_dir()
379 #define GLOBAL_MAPS_DIR "C:\\VIKING-MAPS\\"
380 #define LOCAL_MAPS_DIR "VIKING-MAPS"
381 #elif defined __APPLE__
383 #define GLOBAL_MAPS_DIR "/Library/cache/Viking/maps/"
384 #define LOCAL_MAPS_DIR "/Library/Application Support/Viking/viking-maps"
387 #define GLOBAL_MAPS_DIR "/var/cache/maps/"
388 #define LOCAL_MAPS_DIR ".viking-maps"
391 gchar *maps_layer_default_dir ()
393 static gchar *defaultdir = NULL;
396 /* Thanks to Mike Davison for the $VIKING_MAPS usage */
397 const gchar *mapdir = g_getenv("VIKING_MAPS");
399 defaultdir = g_strdup ( mapdir );
400 } else if ( g_access ( GLOBAL_MAPS_DIR, W_OK ) == 0 ) {
401 defaultdir = g_strdup ( GLOBAL_MAPS_DIR );
403 const gchar *home = g_get_home_dir();
404 if (!home || g_access(home, W_OK))
405 home = g_get_home_dir ();
407 defaultdir = g_build_filename ( home, LOCAL_MAPS_DIR, NULL );
409 defaultdir = g_strdup ( LOCAL_MAPS_DIR );
411 if (defaultdir && (defaultdir[strlen(defaultdir)-1] != G_DIR_SEPARATOR))
413 /* Add the separator at the end */
414 gchar *tmp = defaultdir;
415 defaultdir = g_strconcat(tmp, G_DIR_SEPARATOR_S, NULL);
418 g_debug("%s: defaultdir=%s", __FUNCTION__, defaultdir);
423 static void maps_layer_mkdir_if_default_dir ( VikMapsLayer *vml )
425 if ( vml->cache_dir && strcmp ( vml->cache_dir, MAPS_CACHE_DIR ) == 0 && g_file_test ( vml->cache_dir, G_FILE_TEST_EXISTS ) == FALSE )
427 g_mkdir ( vml->cache_dir, 0777 );
431 static void maps_layer_set_cache_dir ( VikMapsLayer *vml, const gchar *dir )
434 g_assert ( vml != NULL);
435 g_free ( vml->cache_dir );
436 vml->cache_dir = NULL;
437 const gchar *mydir = dir;
439 if ( dir == NULL || dir[0] == '\0' )
441 if ( a_preferences_get(VIKING_PREFERENCES_NAMESPACE "maplayer_default_dir") )
442 mydir = a_preferences_get(VIKING_PREFERENCES_NAMESPACE "maplayer_default_dir")->s;
445 // Ensure cache_dir always ends with a separator
447 if ( mydir[len-1] != G_DIR_SEPARATOR )
449 vml->cache_dir = g_malloc ( len+2 );
450 strncpy ( vml->cache_dir, mydir, len );
451 vml->cache_dir[len] = G_DIR_SEPARATOR;
452 vml->cache_dir[len+1] = '\0';
455 vml->cache_dir = g_strdup ( mydir );
457 maps_layer_mkdir_if_default_dir ( vml );
460 /****************************************/
461 /******** GOBJECT STUFF *****************/
462 /****************************************/
464 GType vik_maps_layer_get_type ()
466 static GType vml_type = 0;
470 static const GTypeInfo vml_info =
472 sizeof (VikMapsLayerClass),
473 NULL, /* base_init */
474 NULL, /* base_finalize */
475 NULL, /* class init */
476 NULL, /* class_finalize */
477 NULL, /* class_data */
478 sizeof (VikMapsLayer),
480 NULL /* instance init */
482 vml_type = g_type_register_static ( VIK_LAYER_TYPE, "VikMapsLayer", &vml_info, 0 );
488 /****************************************/
489 /************** PARAMETERS **************/
490 /****************************************/
492 static guint map_index_to_uniq_id (guint16 index)
494 g_assert ( index < NUM_MAP_TYPES );
495 return vik_map_source_get_uniq_id(MAPS_LAYER_NTH_TYPE(index));
498 static guint map_uniq_id_to_index ( guint uniq_id )
501 for ( i = 0; i < NUM_MAP_TYPES; i++ )
502 if ( vik_map_source_get_uniq_id(MAPS_LAYER_NTH_TYPE(i)) == uniq_id )
504 return NUM_MAP_TYPES; /* no such thing */
507 void vik_maps_layer_pretend_licence_shown ( VikMapsLayer *vml )
509 vml->license_notice_shown = TRUE;
512 static gboolean maps_layer_set_param ( VikMapsLayer *vml, guint16 id, VikLayerParamData data, VikViewport *vvp, gboolean is_file_operation )
514 // When loading from a file don't need the license reminder
515 if ( is_file_operation )
516 vml->license_notice_shown = TRUE;
520 case PARAM_CACHE_DIR: maps_layer_set_cache_dir ( vml, data.s ); break;
521 case PARAM_MAPTYPE: {
522 gint maptype = map_uniq_id_to_index(data.u);
523 if ( maptype == NUM_MAP_TYPES ) g_warning(_("Unknown map type"));
524 else vml->maptype = maptype;
527 case PARAM_ALPHA: if ( data.u <= 255 ) vml->alpha = data.u; break;
528 case PARAM_AUTODOWNLOAD: vml->autodownload = data.b; break;
529 case PARAM_ONLYMISSING: vml->adl_only_missing = data.b; break;
530 case PARAM_MAPZOOM: if ( data.u < NUM_MAPZOOMS ) {
531 vml->mapzoom_id = data.u;
532 vml->xmapzoom = __mapzooms_x [data.u];
533 vml->ymapzoom = __mapzooms_y [data.u];
534 }else g_warning (_("Unknown Map Zoom")); break;
539 static VikLayerParamData maps_layer_get_param ( VikMapsLayer *vml, guint16 id, gboolean is_file_operation )
541 VikLayerParamData rv;
544 case PARAM_CACHE_DIR:
546 gboolean set = FALSE;
547 /* Only save a blank when the map cache location equals the default
548 On reading in, when it is blank then the default is reconstructed
549 Since the default changes dependent on the user and OS, it means the resultant file is more portable */
550 if ( is_file_operation && vml->cache_dir && strcmp ( vml->cache_dir, MAPS_CACHE_DIR ) == 0 ) {
554 else if ( is_file_operation ) {
555 if ( a_vik_get_file_ref_format() == VIK_FILE_REF_FORMAT_RELATIVE ) {
556 gchar *cwd = g_get_current_dir();
558 rv.s = file_GetRelativeFilename ( cwd, vml->cache_dir );
559 if ( !rv.s ) rv.s = "";
565 rv.s = vml->cache_dir ? vml->cache_dir : "";
568 case PARAM_MAPTYPE: rv.u = map_index_to_uniq_id ( vml->maptype ); break;
569 case PARAM_ALPHA: rv.u = vml->alpha; break;
570 case PARAM_AUTODOWNLOAD: rv.u = vml->autodownload; break;
571 case PARAM_ONLYMISSING: rv.u = vml->adl_only_missing; break;
572 case PARAM_MAPZOOM: rv.u = vml->mapzoom_id; break;
577 /****************************************/
578 /****** CREATING, COPYING, FREEING ******/
579 /****************************************/
581 static VikMapsLayer *maps_layer_new ( VikViewport *vvp )
583 VikMapsLayer *vml = VIK_MAPS_LAYER ( g_object_new ( VIK_MAPS_LAYER_TYPE, NULL ) );
584 vik_layer_set_type ( VIK_LAYER(vml), VIK_LAYER_MAPS );
586 vik_layer_set_defaults ( VIK_LAYER(vml), vvp );
588 vml->dl_tool_x = vml->dl_tool_y = -1;
589 vml->last_center = NULL;
590 vml->last_xmpp = 0.0;
591 vml->last_ympp = 0.0;
593 vml->dl_right_click_menu = NULL;
594 vml->license_notice_shown = FALSE;
599 static void maps_layer_free ( VikMapsLayer *vml )
601 g_free ( vml->cache_dir );
602 vml->cache_dir = NULL;
603 if ( vml->dl_right_click_menu )
604 g_object_ref_sink ( G_OBJECT(vml->dl_right_click_menu) );
605 g_free(vml->last_center);
606 vml->last_center = NULL;
609 static void maps_layer_post_read (VikLayer *vl, VikViewport *vp, gboolean from_file)
611 if (from_file != TRUE)
613 /* If this method is not called in file reading context
614 * it is called in GUI context.
615 * So, we can check if we have to inform the user about inconsistency */
616 VikViewportDrawMode vp_drawmode;
617 VikMapsLayer *vml = VIK_MAPS_LAYER(vl);
618 VikMapSource *map = NULL;
620 vp_drawmode = vik_viewport_get_drawmode ( vp );
621 map = MAPS_LAYER_NTH_TYPE(vml->maptype);
622 if (vik_map_source_get_drawmode(map) != vp_drawmode) {
623 const gchar *drawmode_name = vik_viewport_get_drawmode_name (vp, vik_map_source_get_drawmode(map));
624 gchar *msg = g_strdup_printf(_("New map cannot be displayed in the current drawmode.\nSelect \"%s\" from View menu to view it."), drawmode_name);
625 a_dialog_warning_msg ( VIK_GTK_WINDOW_FROM_WIDGET(vp), msg );
629 if (vik_map_source_get_license (map) != NULL) {
630 if ( ! vml->license_notice_shown ) {
631 a_dialog_license (VIK_GTK_WINDOW_FROM_WIDGET(vp), vik_map_source_get_label (map),
632 vik_map_source_get_license (map), vik_map_source_get_license_url (map) );
633 vml->license_notice_shown = TRUE;
639 static const gchar* maps_layer_tooltip ( VikMapsLayer *vml )
641 return vik_maps_layer_get_map_label ( vml );
644 static void maps_layer_marshall( VikMapsLayer *vml, guint8 **data, gint *len )
646 vik_layer_marshall_params ( VIK_LAYER(vml), data, len );
649 static VikMapsLayer *maps_layer_unmarshall( guint8 *data, gint len, VikViewport *vvp )
651 VikMapsLayer *rv = maps_layer_new ( vvp );
652 vik_layer_unmarshall_params ( VIK_LAYER(rv), data, len, vvp );
656 /*********************/
657 /****** DRAWING ******/
658 /*********************/
660 static GdkPixbuf *pixbuf_set_alpha ( GdkPixbuf *pixbuf, guint8 alpha )
663 gint width, height, iii, jjj;
665 if ( ! gdk_pixbuf_get_has_alpha ( pixbuf ) )
667 GdkPixbuf *tmp = gdk_pixbuf_add_alpha(pixbuf,FALSE,0,0,0);
668 g_object_unref(G_OBJECT(pixbuf));
674 pixels = gdk_pixbuf_get_pixels(pixbuf);
675 width = gdk_pixbuf_get_width(pixbuf);
676 height = gdk_pixbuf_get_height(pixbuf);
678 /* r,g,b,a,r,g,b,a.... */
679 for (iii = 0; iii < width; iii++) for (jjj = 0; jjj < height; jjj++)
687 static GdkPixbuf *pixbuf_shrink ( GdkPixbuf *pixbuf, gdouble xshrinkfactor, gdouble yshrinkfactor )
690 guint16 width = gdk_pixbuf_get_width(pixbuf), height = gdk_pixbuf_get_height(pixbuf);
691 tmp = gdk_pixbuf_scale_simple(pixbuf, ceil(width * xshrinkfactor), ceil(height * yshrinkfactor), GDK_INTERP_BILINEAR);
692 g_object_unref ( G_OBJECT(pixbuf) );
696 static GdkPixbuf *get_pixbuf( VikMapsLayer *vml, gint mode, MapCoord *mapcoord, gchar *filename_buf, gint buf_len, gdouble xshrinkfactor, gdouble yshrinkfactor )
701 pixbuf = a_mapcache_get ( mapcoord->x, mapcoord->y, mapcoord->z,
702 mode, mapcoord->scale, vml->alpha, xshrinkfactor, yshrinkfactor );
705 if ( vik_map_source_is_direct_file_access (MAPS_LAYER_NTH_TYPE(vml->maptype)) )
706 g_snprintf ( filename_buf, buf_len, DIRECTDIRACCESS,
707 vml->cache_dir, (17 - mapcoord->scale), mapcoord->x, mapcoord->y, ".png" );
709 g_snprintf ( filename_buf, buf_len, DIRSTRUCTURE,
710 vml->cache_dir, mode,
711 mapcoord->scale, mapcoord->z, mapcoord->x, mapcoord->y );
713 if ( g_file_test ( filename_buf, G_FILE_TEST_EXISTS ) == TRUE)
716 pixbuf = gdk_pixbuf_new_from_file ( filename_buf, &gx );
718 /* free the pixbuf on error */
721 if ( gx->domain != GDK_PIXBUF_ERROR || gx->code != GDK_PIXBUF_ERROR_CORRUPT_IMAGE )
722 g_warning ( _("Couldn't open image file: %s"), gx->message );
726 g_object_unref ( G_OBJECT(pixbuf) );
729 if ( vml->alpha < 255 )
730 pixbuf = pixbuf_set_alpha ( pixbuf, vml->alpha );
731 if ( xshrinkfactor != 1.0 || yshrinkfactor != 1.0 )
732 pixbuf = pixbuf_shrink ( pixbuf, xshrinkfactor, yshrinkfactor );
735 a_mapcache_add ( pixbuf, mapcoord->x, mapcoord->y,
736 mapcoord->z, vik_map_source_get_uniq_id(MAPS_LAYER_NTH_TYPE(vml->maptype)),
737 mapcoord->scale, vml->alpha, xshrinkfactor, yshrinkfactor );
744 static gboolean should_start_autodownload(VikMapsLayer *vml, VikViewport *vvp)
746 const VikCoord *center = vik_viewport_get_center ( vvp );
748 if (vik_window_get_pan_move (VIK_WINDOW(VIK_GTK_WINDOW_FROM_WIDGET(GTK_WIDGET(vvp)))))
749 /* D'n'D pan in action: do not download */
753 // Prevent requests for downloading tiles at Zoom Level 19 and above for most map types
754 // Allow MapQuest Zoom Level up to 19
755 // TODO: This should be made a property of the map source and then use that value
756 gdouble xzoom = vik_viewport_get_xmpp ( vvp );
757 if ( (vml->maptype != 19 && map_utils_mpp_to_scale (xzoom) < -1) || (vml->maptype == 19 && map_utils_mpp_to_scale (xzoom) < -2) )
760 if (vml->last_center == NULL) {
761 VikCoord *new_center = g_malloc(sizeof(VikCoord));
762 *new_center = *center;
763 vml->last_center = new_center;
764 vml->last_xmpp = vik_viewport_get_xmpp(vvp);
765 vml->last_ympp = vik_viewport_get_ympp(vvp);
769 /* TODO: perhaps vik_coord_diff() */
770 if (vik_coord_equals(vml->last_center, center)
771 && (vml->last_xmpp == vik_viewport_get_xmpp(vvp))
772 && (vml->last_ympp == vik_viewport_get_ympp(vvp)))
775 *(vml->last_center) = *center;
776 vml->last_xmpp = vik_viewport_get_xmpp(vvp);
777 vml->last_ympp = vik_viewport_get_ympp(vvp);
781 static void maps_layer_draw_section ( VikMapsLayer *vml, VikViewport *vvp, VikCoord *ul, VikCoord *br )
784 gdouble xzoom = vik_viewport_get_xmpp ( vvp );
785 gdouble yzoom = vik_viewport_get_ympp ( vvp );
786 gdouble xshrinkfactor = 1.0, yshrinkfactor = 1.0;
787 gboolean existence_only = FALSE;
789 if ( vml->xmapzoom && (vml->xmapzoom != xzoom || vml->ymapzoom != yzoom) ) {
790 xshrinkfactor = vml->xmapzoom / xzoom;
791 yshrinkfactor = vml->ymapzoom / yzoom;
792 xzoom = vml->xmapzoom;
793 yzoom = vml->xmapzoom;
794 if ( ! (xshrinkfactor > MIN_SHRINKFACTOR && xshrinkfactor < MAX_SHRINKFACTOR &&
795 yshrinkfactor > MIN_SHRINKFACTOR && yshrinkfactor < MAX_SHRINKFACTOR ) ) {
796 if ( xshrinkfactor > REAL_MIN_SHRINKFACTOR && yshrinkfactor > REAL_MIN_SHRINKFACTOR ) {
797 g_debug ( "%s: existence_only due to SHRINKFACTORS", __FUNCTION__ );
798 existence_only = TRUE;
801 g_warning ( _("Cowardly refusing to draw tiles or existence of tiles beyond %d zoom out factor"), (int)( 1.0/REAL_MIN_SHRINKFACTOR));
808 VikMapSource *map = MAPS_LAYER_NTH_TYPE(vml->maptype);
809 if ( vik_map_source_coord_to_mapcoord ( map, ul, xzoom, yzoom, &ulm ) &&
810 vik_map_source_coord_to_mapcoord ( map, br, xzoom, yzoom, &brm ) ) {
814 gint xmin = MIN(ulm.x, brm.x), xmax = MAX(ulm.x, brm.x);
815 gint ymin = MIN(ulm.y, brm.y), ymax = MAX(ulm.y, brm.y);
816 gint mode = vik_map_source_get_uniq_id(map);
819 gint xx, yy, width, height;
822 // Prevent the program grinding to a halt if trying to deal with thousands of tiles
823 // which can happen when using a small fixed zoom level and viewing large areas.
824 // Also prevents very large number of tile download requests
825 gint tiles = (xmax-xmin) * (ymax-ymin);
826 if ( tiles > MAX_TILES ) {
827 g_debug ( "%s: existence_only due to wanting too many tiles (%d)", __FUNCTION__, tiles );
828 existence_only = TRUE;
831 guint max_path_len = strlen(vml->cache_dir) + 40;
832 gchar *path_buf = g_malloc ( max_path_len * sizeof(char) );
834 if ( (!existence_only) && vml->autodownload && should_start_autodownload(vml, vvp)) {
835 g_debug("%s: Starting autodownload", __FUNCTION__);
836 if ( !vml->adl_only_missing && vik_map_source_supports_download_only_new (map) )
837 // Try to download newer tiles
838 start_download_thread ( vml, vvp, ul, br, REDOWNLOAD_NEW );
840 // Download only missing tiles
841 start_download_thread ( vml, vvp, ul, br, REDOWNLOAD_NONE );
844 if ( vik_map_source_get_tilesize_x(map) == 0 && !existence_only ) {
845 for ( x = xmin; x <= xmax; x++ ) {
846 for ( y = ymin; y <= ymax; y++ ) {
849 pixbuf = get_pixbuf ( vml, mode, &ulm, path_buf, max_path_len, xshrinkfactor, yshrinkfactor );
851 width = gdk_pixbuf_get_width ( pixbuf );
852 height = gdk_pixbuf_get_height ( pixbuf );
854 vik_map_source_mapcoord_to_center_coord ( map, &ulm, &coord );
855 vik_viewport_coord_to_screen ( vvp, &coord, &xx, &yy );
859 vik_viewport_draw_pixbuf ( vvp, pixbuf, 0, 0, xx, yy, width, height );
863 } else { /* tilesize is known, don't have to keep converting coords */
864 gdouble tilesize_x = vik_map_source_get_tilesize_x(map) * xshrinkfactor;
865 gdouble tilesize_y = vik_map_source_get_tilesize_y(map) * yshrinkfactor;
866 /* ceiled so tiles will be maximum size in the case of funky shrinkfactor */
867 gint tilesize_x_ceil = ceil ( tilesize_x );
868 gint tilesize_y_ceil = ceil ( tilesize_y );
869 gint8 xinc = (ulm.x == xmin) ? 1 : -1;
870 gint8 yinc = (ulm.y == ymin) ? 1 : -1;
871 gdouble xx, yy; gint xx_tmp, yy_tmp;
872 gint base_yy, xend, yend;
874 xend = (xinc == 1) ? (xmax+1) : (xmin-1);
875 yend = (yinc == 1) ? (ymax+1) : (ymin-1);
877 vik_map_source_mapcoord_to_center_coord ( map, &ulm, &coord );
878 vik_viewport_coord_to_screen ( vvp, &coord, &xx_tmp, &yy_tmp );
879 xx = xx_tmp; yy = yy_tmp;
880 /* above trick so xx,yy doubles. this is so shrinkfactors aren't rounded off
881 * eg if tile size 128, shrinkfactor 0.333 */
882 xx -= (tilesize_x/2);
883 base_yy = yy - (tilesize_y/2);
885 for ( x = ((xinc == 1) ? xmin : xmax); x != xend; x+=xinc ) {
887 for ( y = ((yinc == 1) ? ymin : ymax); y != yend; y+=yinc ) {
891 if ( existence_only ) {
892 if ( vik_map_source_is_direct_file_access (MAPS_LAYER_NTH_TYPE(vml->maptype)) )
893 g_snprintf ( path_buf, max_path_len, DIRECTDIRACCESS,
894 vml->cache_dir, (17 - ulm.scale), ulm.x, ulm.y, ".png" );
896 g_snprintf ( path_buf, max_path_len, DIRSTRUCTURE,
897 vml->cache_dir, mode,
898 ulm.scale, ulm.z, ulm.x, ulm.y );
899 if ( g_file_test ( path_buf, G_FILE_TEST_EXISTS ) == TRUE ) {
900 GdkGC *black_gc = gtk_widget_get_style(GTK_WIDGET(vvp))->black_gc;
901 vik_viewport_draw_line ( vvp, black_gc, xx+tilesize_x_ceil, yy, xx, yy+tilesize_y_ceil );
905 for (scale_inc = 0; scale_inc < 4; scale_inc ++) {
906 /* try with correct then smaller zooms */
907 int scale_factor = 1 << scale_inc; /* 2^scale_inc */
909 ulm2.x = ulm.x / scale_factor;
910 ulm2.y = ulm.y / scale_factor;
911 ulm2.scale = ulm.scale + scale_inc;
912 pixbuf = get_pixbuf ( vml, mode, &ulm2, path_buf, max_path_len, xshrinkfactor * scale_factor, yshrinkfactor * scale_factor );
914 gint src_x = (ulm.x % scale_factor) * tilesize_x_ceil;
915 gint src_y = (ulm.y % scale_factor) * tilesize_y_ceil;
917 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);
919 vik_viewport_draw_pixbuf ( vvp, pixbuf, src_x, src_y, xx, yy, tilesize_x_ceil, tilesize_y_ceil );
924 /* retry with bigger zooms */
926 for (scale_dec = 1; scale_dec < 2; scale_dec ++) {
928 int scale_factor = 1 << scale_dec; /* 2^scale_dec */
930 ulm2.x = ulm.x * scale_factor;
931 ulm2.y = ulm.y * scale_factor;
932 ulm2.scale = ulm.scale - scale_dec;
933 for (pict_x = 0; pict_x < scale_factor; pict_x ++) {
934 for (pict_y = 0; pict_y < scale_factor; pict_y ++) {
935 MapCoord ulm3 = ulm2;
938 pixbuf = get_pixbuf ( vml, mode, &ulm3, path_buf, max_path_len, xshrinkfactor / scale_factor, yshrinkfactor / scale_factor );
942 gint dest_x = xx + pict_x * (tilesize_x_ceil / scale_factor);
943 gint dest_y = yy + pict_y * (tilesize_y_ceil / scale_factor);
944 vik_viewport_draw_pixbuf ( vvp, pixbuf, src_x, src_y, dest_x, dest_y, tilesize_x_ceil / scale_factor, tilesize_y_ceil / scale_factor );
962 static void maps_layer_draw ( VikMapsLayer *vml, VikViewport *vvp )
964 if ( vik_map_source_get_drawmode(MAPS_LAYER_NTH_TYPE(vml->maptype)) == vik_viewport_get_drawmode ( vvp ) )
969 gdouble level = vik_viewport_get_zoom ( vvp );
971 vik_viewport_get_min_max_lat_lon ( vvp, &bbox.south, &bbox.north, &bbox.west, &bbox.east );
972 vik_map_source_get_copyright ( MAPS_LAYER_NTH_TYPE(vml->maptype), bbox, level, vik_viewport_add_copyright, vvp );
975 const GdkPixbuf *logo = vik_map_source_get_logo ( MAPS_LAYER_NTH_TYPE(vml->maptype) );
976 vik_viewport_add_logo ( vvp, logo );
978 /* get corner coords */
979 if ( vik_viewport_get_coord_mode ( vvp ) == VIK_COORD_UTM && ! vik_viewport_is_one_zone ( vvp ) ) {
980 /* UTM multi-zone stuff by Kit Transue */
981 gchar leftmost_zone, rightmost_zone, i;
982 leftmost_zone = vik_viewport_leftmost_zone( vvp );
983 rightmost_zone = vik_viewport_rightmost_zone( vvp );
984 for ( i = leftmost_zone; i <= rightmost_zone; ++i ) {
985 vik_viewport_corners_for_zonen ( vvp, i, &ul, &br );
986 maps_layer_draw_section ( vml, vvp, &ul, &br );
990 vik_viewport_screen_to_coord ( vvp, 0, 0, &ul );
991 vik_viewport_screen_to_coord ( vvp, vik_viewport_get_width(vvp), vik_viewport_get_height(vvp), &br );
993 maps_layer_draw_section ( vml, vvp, &ul, &br );
998 /*************************/
999 /****** DOWNLOADING ******/
1000 /*************************/
1002 /* pass along data to thread, exists even if layer is deleted. */
1005 gchar *filename_buf;
1006 gint x0, y0, xf, yf;
1012 gboolean refresh_display;
1015 gboolean map_layer_alive;
1019 static void mdi_free ( MapDownloadInfo *mdi )
1021 g_mutex_free(mdi->mutex);
1022 g_free ( mdi->cache_dir );
1023 mdi->cache_dir = NULL;
1024 g_free ( mdi->filename_buf );
1025 mdi->filename_buf = NULL;
1029 static void weak_ref_cb(gpointer ptr, GObject * dead_vml)
1031 MapDownloadInfo *mdi = ptr;
1032 g_mutex_lock(mdi->mutex);
1033 mdi->map_layer_alive = FALSE;
1034 g_mutex_unlock(mdi->mutex);
1037 static int map_download_thread ( MapDownloadInfo *mdi, gpointer threaddata )
1039 void *handle = vik_map_source_download_handle_init(MAPS_LAYER_NTH_TYPE(mdi->maptype));
1042 for ( x = mdi->x0; x <= mdi->xf; x++ )
1044 for ( y = mdi->y0; y <= mdi->yf; y++ )
1046 gboolean remove_mem_cache = FALSE;
1047 gboolean need_download = FALSE;
1048 g_snprintf ( mdi->filename_buf, mdi->maxlen, DIRSTRUCTURE,
1049 mdi->cache_dir, vik_map_source_get_uniq_id(MAPS_LAYER_NTH_TYPE(mdi->maptype)),
1050 mdi->mapcoord.scale, mdi->mapcoord.z, x, y );
1053 int res = a_background_thread_progress ( threaddata, ((gdouble)donemaps) / mdi->mapstoget ); /* this also calls testcancel */
1055 vik_map_source_download_handle_cleanup(MAPS_LAYER_NTH_TYPE(mdi->maptype), handle);
1059 if ( g_file_test ( mdi->filename_buf, G_FILE_TEST_EXISTS ) == FALSE ) {
1060 need_download = TRUE;
1061 remove_mem_cache = TRUE;
1063 } else { /* in case map file already exists */
1064 switch (mdi->redownload) {
1065 case REDOWNLOAD_NONE:
1068 case REDOWNLOAD_BAD:
1070 /* see if this one is bad or what */
1072 GdkPixbuf *pixbuf = gdk_pixbuf_new_from_file ( mdi->filename_buf, &gx );
1073 if (gx || (!pixbuf)) {
1074 g_remove ( mdi->filename_buf );
1075 need_download = TRUE;
1076 remove_mem_cache = TRUE;
1077 g_error_free ( gx );
1080 g_object_unref ( pixbuf );
1085 case REDOWNLOAD_NEW:
1086 need_download = TRUE;
1087 remove_mem_cache = TRUE;
1090 case REDOWNLOAD_ALL:
1091 /* FIXME: need a better way than to erase file in case of server/network problem */
1092 g_remove ( mdi->filename_buf );
1093 need_download = TRUE;
1094 remove_mem_cache = TRUE;
1097 case DOWNLOAD_OR_REFRESH:
1098 remove_mem_cache = TRUE;
1102 g_warning ( "redownload state %d unknown\n", mdi->redownload);
1106 mdi->mapcoord.x = x; mdi->mapcoord.y = y;
1108 if (need_download) {
1109 if ( vik_map_source_download( MAPS_LAYER_NTH_TYPE(mdi->maptype), &(mdi->mapcoord), mdi->filename_buf, handle))
1113 g_mutex_lock(mdi->mutex);
1114 if (remove_mem_cache)
1115 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 );
1116 if (mdi->refresh_display && mdi->map_layer_alive) {
1117 /* TODO: check if it's on visible area */
1118 vik_layer_emit_update ( VIK_LAYER(mdi->vml) ); // NB update display from background
1120 g_mutex_unlock(mdi->mutex);
1121 mdi->mapcoord.x = mdi->mapcoord.y = 0; /* we're temporarily between downloads */
1125 vik_map_source_download_handle_cleanup(MAPS_LAYER_NTH_TYPE(mdi->maptype), handle);
1126 g_mutex_lock(mdi->mutex);
1127 if (mdi->map_layer_alive)
1128 g_object_weak_unref(G_OBJECT(mdi->vml), weak_ref_cb, mdi);
1129 g_mutex_unlock(mdi->mutex);
1133 static void mdi_cancel_cleanup ( MapDownloadInfo *mdi )
1135 if ( mdi->mapcoord.x || mdi->mapcoord.y )
1137 g_snprintf ( mdi->filename_buf, mdi->maxlen, DIRSTRUCTURE,
1138 mdi->cache_dir, vik_map_source_get_uniq_id(MAPS_LAYER_NTH_TYPE(mdi->maptype)),
1139 mdi->mapcoord.scale, mdi->mapcoord.z, mdi->mapcoord.x, mdi->mapcoord.y );
1140 if ( g_file_test ( mdi->filename_buf, G_FILE_TEST_EXISTS ) == TRUE)
1142 g_remove ( mdi->filename_buf );
1147 static void start_download_thread ( VikMapsLayer *vml, VikViewport *vvp, const VikCoord *ul, const VikCoord *br, gint redownload )
1149 gdouble xzoom = vml->xmapzoom ? vml->xmapzoom : vik_viewport_get_xmpp ( vvp );
1150 gdouble yzoom = vml->ymapzoom ? vml->ymapzoom : vik_viewport_get_ympp ( vvp );
1152 VikMapSource *map = MAPS_LAYER_NTH_TYPE(vml->maptype);
1154 // Don't ever attempt download on direct access
1155 if ( vik_map_source_is_direct_file_access ( map ) )
1158 if ( vik_map_source_coord_to_mapcoord ( map, ul, xzoom, yzoom, &ulm )
1159 && vik_map_source_coord_to_mapcoord ( map, br, xzoom, yzoom, &brm ) )
1161 MapDownloadInfo *mdi = g_malloc ( sizeof(MapDownloadInfo) );
1166 mdi->map_layer_alive = TRUE;
1167 mdi->mutex = g_mutex_new();
1168 mdi->refresh_display = TRUE;
1170 /* cache_dir and buffer for dest filename */
1171 mdi->cache_dir = g_strdup ( vml->cache_dir );
1172 mdi->maxlen = strlen ( vml->cache_dir ) + 40;
1173 mdi->filename_buf = g_malloc ( mdi->maxlen * sizeof(gchar) );
1174 mdi->maptype = vml->maptype;
1176 mdi->mapcoord = ulm;
1177 mdi->redownload = redownload;
1179 mdi->x0 = MIN(ulm.x, brm.x);
1180 mdi->xf = MAX(ulm.x, brm.x);
1181 mdi->y0 = MIN(ulm.y, brm.y);
1182 mdi->yf = MAX(ulm.y, brm.y);
1186 if ( mdi->redownload ) {
1187 mdi->mapstoget = (mdi->xf - mdi->x0 + 1) * (mdi->yf - mdi->y0 + 1);
1189 /* calculate how many we need */
1190 for ( a = mdi->x0; a <= mdi->xf; a++ )
1192 for ( b = mdi->y0; b <= mdi->yf; b++ )
1194 g_snprintf ( mdi->filename_buf, mdi->maxlen, DIRSTRUCTURE,
1195 vml->cache_dir, vik_map_source_get_uniq_id(map), ulm.scale,
1197 if ( g_file_test ( mdi->filename_buf, G_FILE_TEST_EXISTS ) == FALSE )
1203 mdi->mapcoord.x = mdi->mapcoord.y = 0; /* for cleanup -- no current map */
1205 if ( mdi->mapstoget )
1207 const gchar *tmp_str;
1212 if (redownload == REDOWNLOAD_BAD)
1213 tmp_str = ngettext("Redownloading up to %d %s map...", "Redownloading up to %d %s maps...", mdi->mapstoget);
1215 tmp_str = ngettext("Redownloading %d %s map...", "Redownloading %d %s maps...", mdi->mapstoget);
1219 tmp_str = ngettext("Downloading %d %s map...", "Downloading %d %s maps...", mdi->mapstoget);
1221 tmp = g_strdup_printf ( tmp_str, mdi->mapstoget, MAPS_LAYER_NTH_LABEL(vml->maptype));
1223 g_object_weak_ref(G_OBJECT(mdi->vml), weak_ref_cb, mdi);
1224 /* launch the thread */
1225 a_background_thread ( VIK_GTK_WINDOW_FROM_LAYER(vml), /* parent window */
1226 tmp, /* description string */
1227 (vik_thr_func) map_download_thread, /* function to call within thread */
1228 mdi, /* pass along data */
1229 (vik_thr_free_func) mdi_free, /* function to free pass along data */
1230 (vik_thr_free_func) mdi_cancel_cleanup,
1239 static void maps_layer_download_section ( VikMapsLayer *vml, VikViewport *vvp, VikCoord *ul, VikCoord *br, gdouble zoom, gint download_method )
1242 VikMapSource *map = MAPS_LAYER_NTH_TYPE(vml->maptype);
1244 // Don't ever attempt download on direct access
1245 if ( vik_map_source_is_direct_file_access ( map ) )
1248 if (!vik_map_source_coord_to_mapcoord(map, ul, zoom, zoom, &ulm)
1249 || !vik_map_source_coord_to_mapcoord(map, br, zoom, zoom, &brm)) {
1250 g_warning("%s() coord_to_mapcoord() failed", __PRETTY_FUNCTION__);
1254 MapDownloadInfo *mdi = g_malloc(sizeof(MapDownloadInfo));
1259 mdi->map_layer_alive = TRUE;
1260 mdi->mutex = g_mutex_new();
1261 mdi->refresh_display = TRUE;
1263 mdi->cache_dir = g_strdup ( vml->cache_dir );
1264 mdi->maxlen = strlen ( vml->cache_dir ) + 40;
1265 mdi->filename_buf = g_malloc ( mdi->maxlen * sizeof(gchar) );
1266 mdi->maptype = vml->maptype;
1268 mdi->mapcoord = ulm;
1269 mdi->redownload = download_method;
1271 mdi->x0 = MIN(ulm.x, brm.x);
1272 mdi->xf = MAX(ulm.x, brm.x);
1273 mdi->y0 = MIN(ulm.y, brm.y);
1274 mdi->yf = MAX(ulm.y, brm.y);
1278 for (i = mdi->x0; i <= mdi->xf; i++) {
1279 for (j = mdi->y0; j <= mdi->yf; j++) {
1280 g_snprintf ( mdi->filename_buf, mdi->maxlen, DIRSTRUCTURE,
1281 vml->cache_dir, vik_map_source_get_uniq_id(map), ulm.scale,
1283 if ( g_file_test ( mdi->filename_buf, G_FILE_TEST_EXISTS ) == FALSE )
1288 mdi->mapcoord.x = mdi->mapcoord.y = 0; /* for cleanup -- no current map */
1290 if (mdi->mapstoget) {
1293 fmt = ngettext("Downloading %d %s map...",
1294 "Downloading %d %s maps...",
1296 tmp = g_strdup_printf ( fmt, mdi->mapstoget, MAPS_LAYER_NTH_LABEL(vml->maptype) );
1298 g_object_weak_ref(G_OBJECT(mdi->vml), weak_ref_cb, mdi);
1299 /* launch the thread */
1300 a_background_thread ( VIK_GTK_WINDOW_FROM_LAYER(vml), /* parent window */
1301 tmp, /* description string */
1302 (vik_thr_func) map_download_thread, /* function to call within thread */
1303 mdi, /* pass along data */
1304 (vik_thr_free_func) mdi_free, /* function to free pass along data */
1305 (vik_thr_free_func) mdi_cancel_cleanup,
1314 * vik_maps_layer_download_section:
1315 * @vml: The Map Layer
1316 * @vvp: The Viewport that the map is on
1317 * @ul: Upper left coordinate of the area to be downloaded
1318 * @br: Bottom right coordinate of the area to be downloaded
1319 * @zoom: The zoom level at which the maps are to be download
1321 * Download a specified map area at a certain zoom level
1323 void vik_maps_layer_download_section ( VikMapsLayer *vml, VikViewport *vvp, VikCoord *ul, VikCoord *br, gdouble zoom )
1325 maps_layer_download_section (vml, vvp, ul, br, zoom, REDOWNLOAD_NONE);
1328 static void maps_layer_redownload_bad ( VikMapsLayer *vml )
1330 start_download_thread ( vml, vml->redownload_vvp, &(vml->redownload_ul), &(vml->redownload_br), REDOWNLOAD_BAD );
1333 static void maps_layer_redownload_all ( VikMapsLayer *vml )
1335 start_download_thread ( vml, vml->redownload_vvp, &(vml->redownload_ul), &(vml->redownload_br), REDOWNLOAD_ALL );
1338 static void maps_layer_redownload_new ( VikMapsLayer *vml )
1340 start_download_thread ( vml, vml->redownload_vvp, &(vml->redownload_ul), &(vml->redownload_br), REDOWNLOAD_NEW );
1344 * Display a simple dialog with information about this particular map tile
1346 static void maps_layer_tile_info ( VikMapsLayer *vml )
1348 VikMapSource *map = MAPS_LAYER_NTH_TYPE(vml->maptype);
1350 gdouble xzoom = vml->xmapzoom ? vml->xmapzoom : vik_viewport_get_xmpp ( vml->redownload_vvp );
1351 gdouble yzoom = vml->ymapzoom ? vml->ymapzoom : vik_viewport_get_ympp ( vml->redownload_vvp );
1354 if ( !vik_map_source_coord_to_mapcoord ( map, &(vml->redownload_ul), xzoom, yzoom, &ulm ) )
1357 gchar *filename = NULL;
1358 gchar *message = NULL;
1359 gchar *source = NULL;
1361 if ( vik_map_source_is_direct_file_access ( map ) ) {
1362 filename = g_strdup_printf ( DIRECTDIRACCESS, vml->cache_dir, ulm.scale, ulm.x, ulm.y, ".png" );
1363 source = g_strconcat ( "file://", filename, NULL );
1366 filename = g_strdup_printf ( DIRSTRUCTURE, vml->cache_dir, vik_map_source_get_uniq_id(map), ulm.scale, ulm.z, ulm.x, ulm.y );
1367 source = g_strdup_printf ( "http://%s%s",
1368 vik_map_source_default_get_hostname ( VIK_MAP_SOURCE_DEFAULT(map) ),
1369 vik_map_source_default_get_uri ( VIK_MAP_SOURCE_DEFAULT(map), &ulm ) );
1372 if ( g_file_test ( filename, G_FILE_TEST_EXISTS ) ) {
1374 // Get some timestamp information of the tile
1375 struct stat stat_buf;
1376 if ( g_stat ( filename, &stat_buf ) == 0 ) {
1378 strftime ( time_buf, sizeof(time_buf), "%c", gmtime((const time_t *)&stat_buf.st_mtime) );
1379 message = g_strdup_printf ( _("\nSource: %s\n\nTile File: %s\nTile File Timestamp: %s"), source, filename, time_buf );
1383 message = g_strdup_printf ( _("Source: %s\n\nNo Tile File!"), source );
1386 a_dialog_info_msg ( VIK_GTK_WINDOW_FROM_LAYER(vml), message );
1390 g_free ( filename );
1393 static gboolean maps_layer_download_release ( VikMapsLayer *vml, GdkEventButton *event, VikViewport *vvp )
1395 if (!vml || vml->vl.type != VIK_LAYER_MAPS)
1397 if ( vml->dl_tool_x != -1 && vml->dl_tool_y != -1 )
1399 if ( event->button == 1 )
1402 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 );
1403 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 );
1404 start_download_thread ( vml, vvp, &ul, &br, DOWNLOAD_OR_REFRESH );
1405 vml->dl_tool_x = vml->dl_tool_y = -1;
1410 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) );
1411 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) );
1413 vml->redownload_vvp = vvp;
1415 vml->dl_tool_x = vml->dl_tool_y = -1;
1417 if ( ! vml->dl_right_click_menu ) {
1419 vml->dl_right_click_menu = GTK_MENU ( gtk_menu_new () );
1421 item = gtk_menu_item_new_with_mnemonic ( _("Redownload _Bad Map(s)") );
1422 g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(maps_layer_redownload_bad), vml );
1423 gtk_menu_shell_append ( GTK_MENU_SHELL(vml->dl_right_click_menu), item );
1425 item = gtk_menu_item_new_with_mnemonic ( _("Redownload _New Map(s)") );
1426 g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(maps_layer_redownload_new), vml );
1427 gtk_menu_shell_append ( GTK_MENU_SHELL(vml->dl_right_click_menu), item );
1429 item = gtk_menu_item_new_with_mnemonic ( _("Redownload _All Map(s)") );
1430 g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(maps_layer_redownload_all), vml );
1431 gtk_menu_shell_append ( GTK_MENU_SHELL(vml->dl_right_click_menu), item );
1433 item = gtk_image_menu_item_new_with_mnemonic ( _("_Show Tile Information") );
1434 gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_INFO, GTK_ICON_SIZE_MENU) );
1435 g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(maps_layer_tile_info), vml );
1436 gtk_menu_shell_append (GTK_MENU_SHELL(vml->dl_right_click_menu), item);
1439 gtk_menu_popup ( vml->dl_right_click_menu, NULL, NULL, NULL, NULL, event->button, event->time );
1440 gtk_widget_show_all ( GTK_WIDGET(vml->dl_right_click_menu) );
1446 static gpointer maps_layer_download_create ( VikWindow *vw, VikViewport *vvp)
1451 static gboolean maps_layer_download_click ( VikMapsLayer *vml, GdkEventButton *event, VikViewport *vvp )
1454 if (!vml || vml->vl.type != VIK_LAYER_MAPS)
1456 VikMapSource *map = MAPS_LAYER_NTH_TYPE(vml->maptype);
1457 if ( vik_map_source_get_drawmode(map) == vik_viewport_get_drawmode ( vvp ) &&
1458 vik_map_source_coord_to_mapcoord ( map, vik_viewport_get_center ( vvp ),
1459 vml->xmapzoom ? vml->xmapzoom : vik_viewport_get_xmpp ( vvp ),
1460 vml->ymapzoom ? vml->ymapzoom : vik_viewport_get_ympp ( vvp ),
1462 vml->dl_tool_x = event->x, vml->dl_tool_y = event->y;
1469 if ( __map_types[vml->maptype].drawmode == vik_viewport_get_drawmode ( vvp ) )
1473 vik_viewport_screen_to_coord ( vvp, event->x, event->y, &coord );
1474 if ( __map_types[vml->maptype].coord_to_mapcoord ( &coord,
1475 vml->xmapzoom ? vml->xmapzoom : vik_viewport_get_xmpp ( vvp ),
1476 vml->ymapzoom ? vml->ymapzoom : vik_viewport_get_ympp ( vvp ),
1478 gchar *filename_buf = g_strdup_printf ( DIRSTRUCTURE,
1479 vml->cache_dir, __map_types[vml->maptype].uniq_id,
1480 mapcoord.scale, mapcoord.z, mapcoord.x, mapcoord.y );
1482 __map_types[vml->maptype].download ( &mapcoord, filename_buf );
1483 g_free ( filename_buf );
1484 vik_layer_emit_update ( VIK_LAYER(vml) );
1492 static void download_onscreen_maps ( gpointer vml_vvp[2], gint redownload )
1494 VikMapsLayer *vml = vml_vvp[0];
1495 VikViewport *vvp = vml_vvp[1];
1496 VikViewportDrawMode vp_drawmode = vik_viewport_get_drawmode ( vvp );
1498 gdouble xzoom = vml->xmapzoom ? vml->xmapzoom : vik_viewport_get_xmpp ( vvp );
1499 gdouble yzoom = vml->ymapzoom ? vml->ymapzoom : vik_viewport_get_ympp ( vvp );
1504 vik_viewport_screen_to_coord ( vvp, 0, 0, &ul );
1505 vik_viewport_screen_to_coord ( vvp, vik_viewport_get_width(vvp), vik_viewport_get_height(vvp), &br );
1507 VikMapSource *map = MAPS_LAYER_NTH_TYPE(vml->maptype);
1508 if ( vik_map_source_get_drawmode(map) == vp_drawmode &&
1509 vik_map_source_coord_to_mapcoord ( map, &ul, xzoom, yzoom, &ulm ) &&
1510 vik_map_source_coord_to_mapcoord ( map, &br, xzoom, yzoom, &brm ) )
1511 start_download_thread ( vml, vvp, &ul, &br, redownload );
1512 else if (vik_map_source_get_drawmode(map) != vp_drawmode) {
1513 const gchar *drawmode_name = vik_viewport_get_drawmode_name (vvp, vik_map_source_get_drawmode(map));
1514 gchar *err = g_strdup_printf(_("Wrong drawmode for this map.\nSelect \"%s\" from View menu and try again."), _(drawmode_name));
1515 a_dialog_error_msg ( VIK_GTK_WINDOW_FROM_LAYER(vml), err );
1519 a_dialog_error_msg ( VIK_GTK_WINDOW_FROM_LAYER(vml), _("Wrong zoom level for this map.") );
1523 static void maps_layer_download_missing_onscreen_maps ( gpointer vml_vvp[2] )
1525 download_onscreen_maps( vml_vvp, REDOWNLOAD_NONE);
1528 static void maps_layer_download_new_onscreen_maps ( gpointer vml_vvp[2] )
1530 download_onscreen_maps( vml_vvp, REDOWNLOAD_NEW);
1533 static void maps_layer_redownload_all_onscreen_maps ( gpointer vml_vvp[2] )
1535 download_onscreen_maps( vml_vvp, REDOWNLOAD_ALL);
1539 * maps_layer_how_many_maps:
1540 * Copied from maps_layer_download_section but without the actual download and this returns a value
1542 static gint maps_layer_how_many_maps ( VikMapsLayer *vml, VikViewport *vvp, VikCoord *ul, VikCoord *br, gdouble zoom, gint redownload )
1545 VikMapSource *map = MAPS_LAYER_NTH_TYPE(vml->maptype);
1547 if ( vik_map_source_is_direct_file_access ( map ) )
1550 if (!vik_map_source_coord_to_mapcoord(map, ul, zoom, zoom, &ulm)
1551 || !vik_map_source_coord_to_mapcoord(map, br, zoom, zoom, &brm)) {
1552 g_warning("%s() coord_to_mapcoord() failed", __PRETTY_FUNCTION__);
1556 MapDownloadInfo *mdi = g_malloc(sizeof(MapDownloadInfo));
1561 mdi->map_layer_alive = TRUE;
1562 mdi->mutex = g_mutex_new();
1563 mdi->refresh_display = FALSE;
1565 mdi->cache_dir = g_strdup ( vml->cache_dir );
1566 mdi->maxlen = strlen ( vml->cache_dir ) + 40;
1567 mdi->filename_buf = g_malloc ( mdi->maxlen * sizeof(gchar) );
1568 mdi->maptype = vml->maptype;
1570 mdi->mapcoord = ulm;
1571 mdi->redownload = redownload;
1573 mdi->x0 = MIN(ulm.x, brm.x);
1574 mdi->xf = MAX(ulm.x, brm.x);
1575 mdi->y0 = MIN(ulm.y, brm.y);
1576 mdi->yf = MAX(ulm.y, brm.y);
1580 if ( mdi->redownload == REDOWNLOAD_ALL ) {
1581 mdi->mapstoget = (mdi->xf - mdi->x0 + 1) * (mdi->yf - mdi->y0 + 1);
1584 /* calculate how many we need */
1585 for (i = mdi->x0; i <= mdi->xf; i++) {
1586 for (j = mdi->y0; j <= mdi->yf; j++) {
1587 g_snprintf ( mdi->filename_buf, mdi->maxlen, DIRSTRUCTURE,
1588 vml->cache_dir, vik_map_source_get_uniq_id(map), ulm.scale,
1590 if ( mdi->redownload == REDOWNLOAD_NEW ) {
1591 // Assume the worst - always a new file
1592 // Absolute value would requires server lookup - but that is too slow
1596 if ( g_file_test ( mdi->filename_buf, G_FILE_TEST_EXISTS ) == FALSE ) {
1601 if ( mdi->redownload == REDOWNLOAD_BAD ) {
1602 /* see if this one is bad or what */
1604 GdkPixbuf *pixbuf = gdk_pixbuf_new_from_file ( mdi->filename_buf, &gx );
1605 if (gx || (!pixbuf)) {
1609 // Other download cases already considered or just ignored
1617 gint rv = mdi->mapstoget;
1625 * maps_dialog_zoom_between:
1626 * This dialog is specific to the map layer, so it's here rather than in dialog.c
1628 gboolean maps_dialog_zoom_between ( GtkWindow *parent,
1633 gint *selected_zoom1,
1634 gint *selected_zoom2,
1635 gchar *download_list[],
1636 gint default_download,
1637 gint *selected_download )
1639 GtkWidget *dialog = gtk_dialog_new_with_buttons ( title,
1641 GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
1642 GTK_STOCK_OK, GTK_RESPONSE_ACCEPT,
1643 GTK_STOCK_CANCEL, GTK_RESPONSE_REJECT,
1645 gtk_dialog_set_default_response ( GTK_DIALOG(dialog), GTK_RESPONSE_ACCEPT );
1646 GtkWidget *response_w = NULL;
1647 #if GTK_CHECK_VERSION (2, 20, 0)
1648 response_w = gtk_dialog_get_widget_for_response ( GTK_DIALOG(dialog), GTK_RESPONSE_ACCEPT );
1650 GtkWidget *zoom_label1 = gtk_label_new ( _("Zoom Start:") );
1651 GtkWidget *zoom_combo1 = vik_combo_box_text_new();
1653 for (s = zoom_list; *s; s++)
1654 vik_combo_box_text_append ( zoom_combo1, *s );
1655 gtk_combo_box_set_active ( GTK_COMBO_BOX(zoom_combo1), default_zoom1 );
1657 GtkWidget *zoom_label2 = gtk_label_new ( _("Zoom End:") );
1658 GtkWidget *zoom_combo2 = vik_combo_box_text_new();
1659 for (s = zoom_list; *s; s++)
1660 vik_combo_box_text_append ( zoom_combo2, *s );
1661 gtk_combo_box_set_active ( GTK_COMBO_BOX(zoom_combo2), default_zoom2 );
1663 GtkWidget *download_label = gtk_label_new(_("Download Maps Method:"));
1664 GtkWidget *download_combo = vik_combo_box_text_new();
1665 for (s = download_list; *s; s++)
1666 vik_combo_box_text_append ( download_combo, *s );
1667 gtk_combo_box_set_active ( GTK_COMBO_BOX(download_combo), default_download );
1669 GtkTable *box = GTK_TABLE(gtk_table_new(3, 2, FALSE));
1670 gtk_table_attach_defaults (box, GTK_WIDGET(zoom_label1), 0, 1, 0, 1);
1671 gtk_table_attach_defaults (box, GTK_WIDGET(zoom_combo1), 1, 2, 0, 1);
1672 gtk_table_attach_defaults (box, GTK_WIDGET(zoom_label2), 0, 1, 1, 2);
1673 gtk_table_attach_defaults (box, GTK_WIDGET(zoom_combo2), 1, 2, 1, 2);
1674 gtk_table_attach_defaults (box, GTK_WIDGET(download_label), 0, 1, 2, 3);
1675 gtk_table_attach_defaults (box, GTK_WIDGET(download_combo), 1, 2, 2, 3);
1677 gtk_box_pack_start ( GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(dialog))), GTK_WIDGET(box), FALSE, FALSE, 5 );
1680 gtk_widget_grab_focus ( response_w );
1682 gtk_widget_show_all ( dialog );
1683 if ( gtk_dialog_run ( GTK_DIALOG(dialog) ) != GTK_RESPONSE_ACCEPT ) {
1684 gtk_widget_destroy(dialog);
1688 // Return selected options
1689 *selected_zoom1 = gtk_combo_box_get_active ( GTK_COMBO_BOX(zoom_combo1) );
1690 *selected_zoom2 = gtk_combo_box_get_active ( GTK_COMBO_BOX(zoom_combo2) );
1691 *selected_download = gtk_combo_box_get_active ( GTK_COMBO_BOX(download_combo) );
1693 gtk_widget_destroy(dialog);
1697 // My best guess of sensible limits
1698 #define REALLY_LARGE_AMOUNT_OF_TILES 5000
1699 #define CONFIRM_LARGE_AMOUNT_OF_TILES 500
1702 * Get all maps in the region for zoom levels specified by the user
1703 * Sort of similar to trw_layer_download_map_along_track_cb function
1705 static void maps_layer_download_all ( gpointer vml_vvp[2] )
1707 VikMapsLayer *vml = vml_vvp[0];
1708 VikViewport *vvp = vml_vvp[1];
1710 // I don't think we should allow users to hammer the servers too much...
1711 // Delibrately not allowing lowest zoom levels
1712 // Still can give massive numbers to download
1713 // A screen size of 1600x1200 gives around 300,000 tiles between 1..128 when none exist before !!
1714 gchar *zoom_list[] = {"1", "2", "4", "8", "16", "32", "64", "128", "256", "512", "1024", NULL };
1715 gdouble zoom_vals[] = {1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024};
1717 gint selected_zoom1, selected_zoom2, default_zoom, lower_zoom;
1718 gint selected_download_method;
1720 gdouble cur_zoom = vik_viewport_get_zoom(vvp);
1722 for (default_zoom = 0; default_zoom < sizeof(zoom_vals)/sizeof(gdouble); default_zoom++) {
1723 if (cur_zoom == zoom_vals[default_zoom])
1726 default_zoom = (default_zoom == sizeof(zoom_vals)/sizeof(gdouble)) ? sizeof(zoom_vals)/sizeof(gdouble) - 1 : default_zoom;
1728 // Default to only 2 zoom levels below the current one
1729 if (default_zoom > 1 )
1730 lower_zoom = default_zoom - 2;
1732 lower_zoom = default_zoom;
1734 // redownload method - needs to align with REDOWNLOAD* macro values
1735 gchar *download_list[] = { _("Missing"), _("Bad"), _("New"), _("Reload All"), NULL };
1737 gchar *title = g_strdup_printf ( ("%s: %s"), vik_maps_layer_get_map_label (vml), _("Download for Zoom Levels") );
1739 if ( ! maps_dialog_zoom_between ( VIK_GTK_WINDOW_FROM_LAYER(vml),
1747 REDOWNLOAD_NONE, // AKA Missing
1748 &selected_download_method ) ) {
1755 // Find out new current positions
1756 gdouble min_lat, max_lat, min_lon, max_lon;
1757 VikCoord vc_ul, vc_br;
1758 vik_viewport_get_min_max_lat_lon ( vvp, &min_lat, &max_lat, &min_lon, &max_lon );
1759 struct LatLon ll_ul = { max_lat, min_lon };
1760 struct LatLon ll_br = { min_lat, max_lon };
1761 vik_coord_load_from_latlon ( &vc_ul, vik_viewport_get_coord_mode (vvp), &ll_ul );
1762 vik_coord_load_from_latlon ( &vc_br, vik_viewport_get_coord_mode (vvp), &ll_br );
1764 // Get Maps Count - call for each zoom level (in reverse)
1765 // With REDOWNLOAD_NEW this is a possible maximum
1766 // With REDOWNLOAD_NONE this only missing ones - however still has a server lookup per tile
1769 for ( zz = selected_zoom2; zz >= selected_zoom1; zz-- ) {
1770 map_count = map_count + maps_layer_how_many_maps ( vml, vvp, &vc_ul, &vc_br, zoom_vals[zz], selected_download_method );
1773 g_debug ("vikmapslayer: download request map count %d for method %d", map_count, selected_download_method);
1775 // Absolute protection of hammering a map server
1776 if ( map_count > REALLY_LARGE_AMOUNT_OF_TILES ) {
1777 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);
1778 a_dialog_error_msg ( VIK_GTK_WINDOW_FROM_LAYER(vml), str );
1783 // Confirm really want to do this
1784 if ( map_count > CONFIRM_LARGE_AMOUNT_OF_TILES ) {
1785 gchar *str = g_strdup_printf (_("Do you really want to download %d tiles?"), map_count);
1786 gboolean ans = a_dialog_yes_or_no ( VIK_GTK_WINDOW_FROM_LAYER(vml), str, NULL );
1792 // Get Maps - call for each zoom level (in reverse)
1793 for ( zz = selected_zoom2; zz >= selected_zoom1; zz-- ) {
1794 maps_layer_download_section ( vml, vvp, &vc_ul, &vc_br, zoom_vals[zz], selected_download_method );
1798 static void maps_layer_add_menu_items ( VikMapsLayer *vml, GtkMenu *menu, VikLayersPanel *vlp )
1800 static gpointer pass_along[2];
1802 pass_along[0] = vml;
1803 pass_along[1] = vik_layers_panel_get_viewport( VIK_LAYERS_PANEL(vlp) );
1805 item = gtk_menu_item_new();
1806 gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item );
1807 gtk_widget_show ( item );
1809 /* Now with icons */
1810 item = gtk_image_menu_item_new_with_mnemonic ( _("Download _Missing Onscreen Maps") );
1811 gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_ADD, GTK_ICON_SIZE_MENU) );
1812 g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(maps_layer_download_missing_onscreen_maps), pass_along );
1813 gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
1814 gtk_widget_show ( item );
1816 if ( vik_map_source_supports_download_only_new (MAPS_LAYER_NTH_TYPE(vml->maptype)) ) {
1817 item = gtk_image_menu_item_new_with_mnemonic ( _("Download _New Onscreen Maps") );
1818 gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_REDO, GTK_ICON_SIZE_MENU) );
1819 g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(maps_layer_download_new_onscreen_maps), pass_along );
1820 gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
1821 gtk_widget_show ( item );
1824 item = gtk_image_menu_item_new_with_mnemonic ( _("Reload _All Onscreen Maps") );
1825 gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_REFRESH, GTK_ICON_SIZE_MENU) );
1826 g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(maps_layer_redownload_all_onscreen_maps), pass_along );
1827 gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
1828 gtk_widget_show ( item );
1830 item = gtk_image_menu_item_new_with_mnemonic ( _("Download Maps in _Zoom Levels...") );
1831 gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_DND_MULTIPLE, GTK_ICON_SIZE_MENU) );
1832 g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(maps_layer_download_all), pass_along );
1833 gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
1834 gtk_widget_show ( item );
1838 * Enable downloading maps of the current screen area either 'new' or 'everything'
1840 void vik_maps_layer_download ( VikMapsLayer *vml, VikViewport *vvp, gboolean only_new )
1845 static gpointer pass_along[2];
1846 pass_along[0] = vml;
1847 pass_along[1] = vvp;
1850 // Get only new maps
1851 maps_layer_download_new_onscreen_maps ( pass_along );
1853 // Redownload everything
1854 maps_layer_redownload_all_onscreen_maps ( pass_along );