]> git.street.me.uk Git - andy/viking.git/blobdiff - src/vikmapslayer.c
Enable opening background jobs window from the status bar by clicking on the items...
[andy/viking.git] / src / vikmapslayer.c
index 597c823c548a482d63ffd7340c708b9f9be39026..4f903c32498a2200f47aa1389762a19de65f8278 100644 (file)
@@ -2,6 +2,7 @@
  * viking -- GPS Data and Topo Analyzer, Explorer, and Manager
  *
  * Copyright (C) 2005, Evan Battaglia <viking@greentorch.org>
  * viking -- GPS Data and Topo Analyzer, Explorer, and Manager
  *
  * Copyright (C) 2005, Evan Battaglia <viking@greentorch.org>
+ * Copyright (C) 2010, Guilhem Bonnefille <guilhem.bonnefille@gmail.com>
  * UTM multi-zone stuff by Kit Transue <notlostyet@didactek.com>
  * Dynamic map type by Guilhem Bonnefille <guilhem.bonnefille@gmail.com>
  *
  * UTM multi-zone stuff by Kit Transue <notlostyet@didactek.com>
  * Dynamic map type by Guilhem Bonnefille <guilhem.bonnefille@gmail.com>
  *
@@ -25,6 +26,9 @@
 #include "config.h"
 #endif
 
 #include "config.h"
 #endif
 
+// TODO: Make these configurable
+#define MAX_TILES 1000
+
 #define MAX_SHRINKFACTOR 8.0000001 /* zoom 1 viewing 8-tiles */
 #define MIN_SHRINKFACTOR 0.0312499 /* zoom 32 viewing 1-tiles */
 
 #define MAX_SHRINKFACTOR 8.0000001 /* zoom 1 viewing 8-tiles */
 #define MIN_SHRINKFACTOR 0.0312499 /* zoom 32 viewing 1-tiles */
 
 #include <math.h>
 #endif
 
 #include <math.h>
 #endif
 
-#include "globals.h"
-#include "coords.h"
-#include "vikcoord.h"
-#include "viktreeview.h"
-#include "vikviewport.h"
-#include "viklayer.h"
-#include "vikmapslayer.h"
-
 #ifdef HAVE_UNISTD_H
 #include <unistd.h>
 #endif
 
 #ifdef HAVE_UNISTD_H
 #include <unistd.h>
 #endif
 
+#include "viking.h"
+#include "vikmapsourcedefault.h"
+#include "maputils.h"
 #include "mapcache.h"
 #include "mapcache.h"
-/* only for dialog.h -- ugh */
-#include "vikwaypoint.h"
-#include "dialog.h"
-
-#include "vikstatus.h"
 #include "background.h"
 #include "background.h"
-
-#include "vikaggregatelayer.h"
-#include "viklayerspanel.h"
-
-#include "mapcoord.h"
-#include "terraserver.h"
-
+#include "preferences.h"
+#include "vikmapslayer.h"
 #include "icons/icons.h"
 
 /****** MAP TYPES ******/
 #include "icons/icons.h"
 
 /****** MAP TYPES ******/
@@ -78,16 +67,16 @@ static GList *__map_types = NULL;
 #define NUM_MAP_TYPES g_list_length(__map_types)
 
 /* List of label for each map type */
 #define NUM_MAP_TYPES g_list_length(__map_types)
 
 /* List of label for each map type */
-static GList *params_maptypes = NULL;
+static gchar **params_maptypes = NULL;
 
 /* Corresponding IDS. (Cf. field uniq_id in VikMapsLayer struct) */
 
 /* Corresponding IDS. (Cf. field uniq_id in VikMapsLayer struct) */
-static GList *params_maptypes_ids = NULL;
+static guint *params_maptypes_ids = NULL;
 
 /******** MAPZOOMS *********/
 
 
 /******** MAPZOOMS *********/
 
-static gchar *params_mapzooms[] = { N_("Use Viking Zoom Level"), "0.25", "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 };
-static gdouble __mapzooms_x[] = { 0.0, 0.25, 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 };
-static gdouble __mapzooms_y[] = { 0.0, 0.25, 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 };
+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 };
+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 };
+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 };
 
 #define NUM_MAPZOOMS (sizeof(params_mapzooms)/sizeof(params_mapzooms[0]) - 1)
 
 
 #define NUM_MAPZOOMS (sizeof(params_mapzooms)/sizeof(params_mapzooms[0]) - 1)
 
@@ -95,10 +84,11 @@ static gdouble __mapzooms_y[] = { 0.0, 0.25, 1.0, 2.0, 4.0, 8.0, 16.0, 32.0, 64.
 
 
 static void maps_layer_post_read (VikLayer *vl, VikViewport *vp, gboolean from_file);
 
 
 static void maps_layer_post_read (VikLayer *vl, VikViewport *vp, gboolean from_file);
+static const gchar* maps_layer_tooltip ( VikMapsLayer *vml );
 static void maps_layer_marshall( VikMapsLayer *vml, guint8 **data, gint *len );
 static VikMapsLayer *maps_layer_unmarshall( guint8 *data, gint len, VikViewport *vvp );
 static void maps_layer_marshall( VikMapsLayer *vml, guint8 **data, gint *len );
 static VikMapsLayer *maps_layer_unmarshall( guint8 *data, gint len, VikViewport *vvp );
-static gboolean maps_layer_set_param ( VikMapsLayer *vml, guint16 id, VikLayerParamData data, VikViewport *vvp );
-static VikLayerParamData maps_layer_get_param ( VikMapsLayer *vml, guint16 id );
+static gboolean maps_layer_set_param ( VikMapsLayer *vml, guint16 id, VikLayerParamData data, VikViewport *vvp, gboolean is_file_operation );
+static VikLayerParamData maps_layer_get_param ( VikMapsLayer *vml, guint16 id, gboolean is_file_operation );
 static void maps_layer_draw ( VikMapsLayer *vml, VikViewport *vvp );
 static VikMapsLayer *maps_layer_new ( VikViewport *vvp );
 static void maps_layer_free ( VikMapsLayer *vml );
 static void maps_layer_draw ( VikMapsLayer *vml, VikViewport *vvp );
 static VikMapsLayer *maps_layer_new ( VikViewport *vvp );
 static void maps_layer_free ( VikMapsLayer *vml );
@@ -108,6 +98,7 @@ static gpointer maps_layer_download_create ( VikWindow *vw, VikViewport *vvp );
 static void maps_layer_set_cache_dir ( VikMapsLayer *vml, const gchar *dir );
 static void start_download_thread ( VikMapsLayer *vml, VikViewport *vvp, const VikCoord *ul, const VikCoord *br, gint redownload );
 static void maps_layer_add_menu_items ( VikMapsLayer *vml, GtkMenu *menu, VikLayersPanel *vlp );
 static void maps_layer_set_cache_dir ( VikMapsLayer *vml, const gchar *dir );
 static void start_download_thread ( VikMapsLayer *vml, VikViewport *vvp, const VikCoord *ul, const VikCoord *br, gint redownload );
 static void maps_layer_add_menu_items ( VikMapsLayer *vml, GtkMenu *menu, VikLayersPanel *vlp );
+static guint map_uniq_id_to_index ( guint uniq_id );
 
 
 static VikLayerParamScale params_scales[] = {
 
 
 static VikLayerParamScale params_scales[] = {
@@ -115,24 +106,57 @@ static VikLayerParamScale params_scales[] = {
  { 0, 255, 3, 0 }, /* alpha */
 };
 
  { 0, 255, 3, 0 }, /* alpha */
 };
 
+static VikLayerParamData mode_default ( void ) { return VIK_LPD_UINT ( 19 ); } // OSM MapQuest maps
+static VikLayerParamData directory_default ( void )
+{
+  VikLayerParamData data;
+  data.s = g_strdup ( a_preferences_get(VIKING_PREFERENCES_NAMESPACE "maplayer_default_dir")->s );
+  return data;
+}
+static VikLayerParamData alpha_default ( void ) { return VIK_LPD_UINT ( 255 ); }
+static VikLayerParamData mapzoom_default ( void ) { return VIK_LPD_UINT ( 0 ); }
+
 VikLayerParam maps_layer_params[] = {
 VikLayerParam maps_layer_params[] = {
-  { "mode", VIK_LAYER_PARAM_UINT, VIK_LAYER_GROUP_NONE, N_("Map Type:"), VIK_LAYER_WIDGET_RADIOGROUP, NULL, NULL },
-  { "directory", VIK_LAYER_PARAM_STRING, VIK_LAYER_GROUP_NONE, N_("Maps Directory:"), VIK_LAYER_WIDGET_FOLDERENTRY },
-  { "alpha", VIK_LAYER_PARAM_UINT, VIK_LAYER_GROUP_NONE, N_("Alpha:"), VIK_LAYER_WIDGET_HSCALE, params_scales },
-  { "autodownload", VIK_LAYER_PARAM_BOOLEAN, VIK_LAYER_GROUP_NONE, N_("Autodownload maps:"), VIK_LAYER_WIDGET_CHECKBUTTON },
-  { "mapzoom", VIK_LAYER_PARAM_UINT, VIK_LAYER_GROUP_NONE, N_("Zoom Level:"), VIK_LAYER_WIDGET_COMBOBOX, params_mapzooms },
+  { VIK_LAYER_MAPS, "mode", VIK_LAYER_PARAM_UINT, VIK_LAYER_GROUP_NONE, N_("Map Type:"), VIK_LAYER_WIDGET_COMBOBOX, NULL, NULL, NULL, mode_default },
+  { VIK_LAYER_MAPS, "directory", VIK_LAYER_PARAM_STRING, VIK_LAYER_GROUP_NONE, N_("Maps Directory:"), VIK_LAYER_WIDGET_FOLDERENTRY, NULL, NULL, NULL, directory_default },
+  { VIK_LAYER_MAPS, "alpha", VIK_LAYER_PARAM_UINT, VIK_LAYER_GROUP_NONE, N_("Alpha:"), VIK_LAYER_WIDGET_HSCALE, params_scales, NULL,
+    N_("Control the Alpha value for transparency effects"), alpha_default },
+  { 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 },
+  { VIK_LAYER_MAPS, "adlonlymissing", VIK_LAYER_PARAM_BOOLEAN, VIK_LAYER_GROUP_NONE, N_("Autodownload Only Gets Missing Maps:"), VIK_LAYER_WIDGET_CHECKBUTTON, NULL, NULL,
+    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 },
+  { VIK_LAYER_MAPS, "mapzoom", VIK_LAYER_PARAM_UINT, VIK_LAYER_GROUP_NONE, N_("Zoom Level:"), VIK_LAYER_WIDGET_COMBOBOX, params_mapzooms, NULL,
+    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."),
+    mapzoom_default },
 };
 
 };
 
-enum { PARAM_MAPTYPE=0, PARAM_CACHE_DIR, PARAM_ALPHA, PARAM_AUTODOWNLOAD, PARAM_MAPZOOM, NUM_PARAMS };
+enum {
+  PARAM_MAPTYPE=0,
+  PARAM_CACHE_DIR,
+  PARAM_ALPHA,
+  PARAM_AUTODOWNLOAD,
+  PARAM_ONLYMISSING,
+  PARAM_MAPZOOM,
+  NUM_PARAMS
+};
 
 static VikToolInterface maps_tools[] = {
 
 static VikToolInterface maps_tools[] = {
-  { N_("Maps Download"), (VikToolConstructorFunc) maps_layer_download_create, NULL, NULL, NULL,  
-    (VikToolMouseFunc) maps_layer_download_click, NULL,  (VikToolMouseFunc) maps_layer_download_release,
-    (VikToolKeyFunc) NULL, GDK_CURSOR_IS_PIXMAP, &cursor_mapdl_pixbuf },
+  { { "MapsDownload", "vik-icon-Maps Download", N_("_Maps Download"), NULL, N_("Maps Download"), 0 },
+    (VikToolConstructorFunc) maps_layer_download_create,
+    NULL,
+    NULL,
+    NULL,
+    (VikToolMouseFunc) maps_layer_download_click,
+    NULL,
+    (VikToolMouseFunc) maps_layer_download_release,
+    NULL,
+    FALSE,
+    GDK_CURSOR_IS_PIXMAP, &cursor_mapdl_pixbuf },
 };
 
 VikLayerInterface vik_maps_layer_interface = {
 };
 
 VikLayerInterface vik_maps_layer_interface = {
+  "Map",
   N_("Map"),
   N_("Map"),
+  "<control><shift>M",
   &vikmapslayer_pixbuf,
 
   maps_tools,
   &vikmapslayer_pixbuf,
 
   maps_tools,
@@ -162,6 +186,9 @@ VikLayerInterface vik_maps_layer_interface = {
 
   (VikLayerFuncSublayerRenameRequest)   NULL,
   (VikLayerFuncSublayerToggleVisible)   NULL,
 
   (VikLayerFuncSublayerRenameRequest)   NULL,
   (VikLayerFuncSublayerToggleVisible)   NULL,
+  (VikLayerFuncSublayerTooltip)         NULL,
+  (VikLayerFuncLayerTooltip)            maps_layer_tooltip,
+  (VikLayerFuncLayerSelected)           NULL,
 
   (VikLayerFuncMarshall)               maps_layer_marshall,
   (VikLayerFuncUnmarshall)             maps_layer_unmarshall,
 
   (VikLayerFuncMarshall)               maps_layer_marshall,
   (VikLayerFuncUnmarshall)             maps_layer_unmarshall,
@@ -173,10 +200,16 @@ VikLayerInterface vik_maps_layer_interface = {
   (VikLayerFuncWriteFileData)           NULL,
 
   (VikLayerFuncDeleteItem)              NULL,
   (VikLayerFuncWriteFileData)           NULL,
 
   (VikLayerFuncDeleteItem)              NULL,
+  (VikLayerFuncCutItem)                 NULL,
   (VikLayerFuncCopyItem)                NULL,
   (VikLayerFuncPasteItem)               NULL,
   (VikLayerFuncFreeCopiedItem)          NULL,
   (VikLayerFuncDragDropRequest)                NULL,
   (VikLayerFuncCopyItem)                NULL,
   (VikLayerFuncPasteItem)               NULL,
   (VikLayerFuncFreeCopiedItem)          NULL,
   (VikLayerFuncDragDropRequest)                NULL,
+
+  (VikLayerFuncSelectClick)             NULL,
+  (VikLayerFuncSelectMove)              NULL,
+  (VikLayerFuncSelectRelease)           NULL,
+  (VikLayerFuncSelectedViewportMenu)    NULL,
 };
 
 struct _VikMapsLayer {
 };
 
 struct _VikMapsLayer {
@@ -188,6 +221,7 @@ struct _VikMapsLayer {
   gdouble xmapzoom, ymapzoom;
 
   gboolean autodownload;
   gdouble xmapzoom, ymapzoom;
 
   gboolean autodownload;
+  gboolean adl_only_missing;
   VikCoord *last_center;
   gdouble last_xmpp;
   gdouble last_ympp;
   VikCoord *last_center;
   gdouble last_xmpp;
   gdouble last_ympp;
@@ -197,28 +231,58 @@ struct _VikMapsLayer {
   GtkMenu *dl_right_click_menu;
   VikCoord redownload_ul, redownload_br; /* right click menu only */
   VikViewport *redownload_vvp;
   GtkMenu *dl_right_click_menu;
   VikCoord redownload_ul, redownload_br; /* right click menu only */
   VikViewport *redownload_vvp;
+
+  gboolean license_notice_shown; // FALSE for new maps only, otherwise
+                                 // TRUE for saved maps & other layer changes as we don't need to show it again
 };
 
 };
 
-enum { REDOWNLOAD_NONE = 0, REDOWNLOAD_BAD, REDOWNLOAD_ALL, DOWNLOAD_OR_REFRESH };
+enum { REDOWNLOAD_NONE = 0,    /* download only missing maps */
+       REDOWNLOAD_BAD,         /* download missing and bad maps */
+       REDOWNLOAD_NEW,         /* download missing maps that are newer on server only */
+       REDOWNLOAD_ALL,         /* download all maps */
+       DOWNLOAD_OR_REFRESH };  /* download missing maps and refresh cache */
 
 
+static VikLayerParam prefs[] = {
+  { 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") },
+};
+
+void maps_layer_init ()
+{
+  VikLayerParamData tmp;
+  tmp.s = maps_layer_default_dir();
+  a_preferences_register(prefs, tmp, VIKING_PREFERENCES_GROUP_KEY);
+}
 
 /****************************************/
 /******** MAPS LAYER TYPES **************/
 /****************************************/
 
 
 /****************************************/
 /******** MAPS LAYER TYPES **************/
 /****************************************/
 
-void maps_layer_register_map_source ( VikMapSource *map )
+int _get_index_for_id ( guint id )
 {
 {
-  g_assert(map != NULL);
-  
-  guint id = vik_map_source_get_uniq_id(map);
-  const char *label = vik_map_source_get_label(map);
-  g_assert(label != NULL);
+  int index = 0 ;
+  while (params_maptypes_ids[index] != 0)
+  {
+    if (params_maptypes_ids[index] == id)
+      return index;
+    index++;
+  }
+  return -1;
+}
 
 
+void _add_map_source ( guint id, const char *label, VikMapSource *map )
+{
+  gsize len = 0;
+  if (params_maptypes)
+    len = g_strv_length (params_maptypes);
   /* Add the label */
   /* Add the label */
-  params_maptypes = g_list_append(params_maptypes, g_strdup(label));
+  params_maptypes = g_realloc (params_maptypes, (len+2)*sizeof(gchar*));
+  params_maptypes[len] = g_strdup (label);
+  params_maptypes[len+1] = NULL;
 
   /* Add the id */
 
   /* Add the id */
-  params_maptypes_ids = g_list_append(params_maptypes_ids, GUINT_TO_POINTER (id));
+  params_maptypes_ids = g_realloc (params_maptypes_ids, (len+2)*sizeof(guint));
+  params_maptypes_ids[len] = id;
+  params_maptypes_ids[len+1] = 0;
 
   /* We have to clone */
   VikMapSource *clone = VIK_MAP_SOURCE(g_object_ref(map));
 
   /* We have to clone */
   VikMapSource *clone = VIK_MAP_SOURCE(g_object_ref(map));
@@ -226,7 +290,7 @@ void maps_layer_register_map_source ( VikMapSource *map )
   __map_types = g_list_append(__map_types, clone);
 
   /* Hack
   __map_types = g_list_append(__map_types, clone);
 
   /* Hack
-     We have to ensure the mode LayerParam reference the up-to-date
+     We have to ensure the mode LayerParam references the up-to-date
      GLists.
   */
   /*
      GLists.
   */
   /*
@@ -237,8 +301,44 @@ void maps_layer_register_map_source ( VikMapSource *map )
   maps_layer_params[0].extra_widget_data = params_maptypes_ids;
 }
 
   maps_layer_params[0].extra_widget_data = params_maptypes_ids;
 }
 
-#define MAPS_LAYER_NTH_LABEL(n) ((gchar*)g_list_nth_data(params_maptypes, (n)))
-#define MAPS_LAYER_NTH_ID(n) ((guint)g_list_nth_data(params_maptypes_ids, (n)))
+void _update_map_source ( const char *label, VikMapSource *map, int index )
+{
+  GList *item = g_list_nth (__map_types, index);
+  g_object_unref (item->data);
+  item->data = g_object_ref (map);
+  /* Change previous data */
+  g_free (params_maptypes[index]);
+  params_maptypes[index] = g_strdup (label);
+}
+
+/**
+ * maps_layer_register_map_source:
+ * @map: the new VikMapSource
+ *
+ * Register a new VikMapSource.
+ * Override existing one (equality of id).
+ */
+void maps_layer_register_map_source ( VikMapSource *map )
+{
+  g_assert(map != NULL);
+  
+  guint id = vik_map_source_get_uniq_id(map);
+  const char *label = vik_map_source_get_label(map);
+  g_assert(label != NULL);
+
+  int previous = map_uniq_id_to_index (id);
+  if (previous != NUM_MAP_TYPES)
+  {
+    _update_map_source (label, map, previous);
+  }
+  else
+  {
+    _add_map_source (id, label, map);
+  }
+}
+
+#define MAPS_LAYER_NTH_LABEL(n) (params_maptypes[n])
+#define MAPS_LAYER_NTH_ID(n) (params_maptypes_ids[n])
 #define MAPS_LAYER_NTH_TYPE(n) (VIK_MAP_SOURCE(g_list_nth_data(__map_types, (n))))
 
 gint vik_maps_layer_get_map_type(VikMapsLayer *vml)
 #define MAPS_LAYER_NTH_TYPE(n) (VIK_MAP_SOURCE(g_list_nth_data(__map_types, (n))))
 
 gint vik_maps_layer_get_map_type(VikMapsLayer *vml)
@@ -255,6 +355,7 @@ gchar *vik_maps_layer_get_map_label(VikMapsLayer *vml)
 /******** CACHE DIR STUFF ***************/
 /****************************************/
 
 /******** CACHE DIR STUFF ***************/
 /****************************************/
 
+#define DIRECTDIRACCESS "%s%d" G_DIR_SEPARATOR_S "%d" G_DIR_SEPARATOR_S "%d%s"
 #define DIRSTRUCTURE "%st%ds%dz%d" G_DIR_SEPARATOR_S "%d" G_DIR_SEPARATOR_S "%d"
 #define MAPS_CACHE_DIR maps_layer_default_dir()
 
 #define DIRSTRUCTURE "%st%ds%dz%d" G_DIR_SEPARATOR_S "%d" G_DIR_SEPARATOR_S "%d"
 #define MAPS_CACHE_DIR maps_layer_default_dir()
 
@@ -262,6 +363,10 @@ gchar *vik_maps_layer_get_map_label(VikMapsLayer *vml)
 #include <io.h>
 #define GLOBAL_MAPS_DIR "C:\\VIKING-MAPS\\"
 #define LOCAL_MAPS_DIR "VIKING-MAPS"
 #include <io.h>
 #define GLOBAL_MAPS_DIR "C:\\VIKING-MAPS\\"
 #define LOCAL_MAPS_DIR "VIKING-MAPS"
+#elif defined __APPLE__
+#include <stdlib.h>
+#define GLOBAL_MAPS_DIR "/Library/cache/Viking/maps/"
+#define LOCAL_MAPS_DIR "/Library/Application Support/Viking/viking-maps"
 #else /* POSIX */
 #include <stdlib.h>
 #define GLOBAL_MAPS_DIR "/var/cache/maps/"
 #else /* POSIX */
 #include <stdlib.h>
 #define GLOBAL_MAPS_DIR "/var/cache/maps/"
@@ -316,7 +421,10 @@ static void maps_layer_set_cache_dir ( VikMapsLayer *vml, const gchar *dir )
   vml->cache_dir = NULL;
 
   if ( dir == NULL || dir[0] == '\0' )
   vml->cache_dir = NULL;
 
   if ( dir == NULL || dir[0] == '\0' )
-    vml->cache_dir = g_strdup ( MAPS_CACHE_DIR );
+  {
+    if ( a_preferences_get(VIKING_PREFERENCES_NAMESPACE "maplayer_default_dir") )
+      vml->cache_dir = g_strdup ( a_preferences_get(VIKING_PREFERENCES_NAMESPACE "maplayer_default_dir")->s );
+  }
   else
   {
     len = strlen(dir);
   else
   {
     len = strlen(dir);
@@ -380,8 +488,12 @@ static guint map_uniq_id_to_index ( guint uniq_id )
   return NUM_MAP_TYPES; /* no such thing */
 }
 
   return NUM_MAP_TYPES; /* no such thing */
 }
 
-static gboolean maps_layer_set_param ( VikMapsLayer *vml, guint16 id, VikLayerParamData data, VikViewport *vvp )
+static gboolean maps_layer_set_param ( VikMapsLayer *vml, guint16 id, VikLayerParamData data, VikViewport *vvp, gboolean is_file_operation )
 {
 {
+  // When loading from a file don't need the license reminder
+  if ( is_file_operation )
+    vml->license_notice_shown = TRUE;
+
   switch ( id )
   {
     case PARAM_CACHE_DIR: maps_layer_set_cache_dir ( vml, data.s ); break;
   switch ( id )
   {
     case PARAM_CACHE_DIR: maps_layer_set_cache_dir ( vml, data.s ); break;
@@ -393,6 +505,7 @@ static gboolean maps_layer_set_param ( VikMapsLayer *vml, guint16 id, VikLayerPa
     }
     case PARAM_ALPHA: if ( data.u <= 255 ) vml->alpha = data.u; break;
     case PARAM_AUTODOWNLOAD: vml->autodownload = data.b; break;
     }
     case PARAM_ALPHA: if ( data.u <= 255 ) vml->alpha = data.u; break;
     case PARAM_AUTODOWNLOAD: vml->autodownload = data.b; break;
+    case PARAM_ONLYMISSING: vml->adl_only_missing = data.b; break;
     case PARAM_MAPZOOM: if ( data.u < NUM_MAPZOOMS ) {
                           vml->mapzoom_id = data.u;
                           vml->xmapzoom = __mapzooms_x [data.u];
     case PARAM_MAPZOOM: if ( data.u < NUM_MAPZOOMS ) {
                           vml->mapzoom_id = data.u;
                           vml->xmapzoom = __mapzooms_x [data.u];
@@ -402,7 +515,7 @@ static gboolean maps_layer_set_param ( VikMapsLayer *vml, guint16 id, VikLayerPa
   return TRUE;
 }
 
   return TRUE;
 }
 
-static VikLayerParamData maps_layer_get_param ( VikMapsLayer *vml, guint16 id )
+static VikLayerParamData maps_layer_get_param ( VikMapsLayer *vml, guint16 id, gboolean is_file_operation )
 {
   VikLayerParamData rv;
   switch ( id )
 {
   VikLayerParamData rv;
   switch ( id )
@@ -411,6 +524,7 @@ static VikLayerParamData maps_layer_get_param ( VikMapsLayer *vml, guint16 id )
     case PARAM_MAPTYPE: rv.u = map_index_to_uniq_id ( vml->maptype ); break;
     case PARAM_ALPHA: rv.u = vml->alpha; break;
     case PARAM_AUTODOWNLOAD: rv.u = vml->autodownload; break;
     case PARAM_MAPTYPE: rv.u = map_index_to_uniq_id ( vml->maptype ); break;
     case PARAM_ALPHA: rv.u = vml->alpha; break;
     case PARAM_AUTODOWNLOAD: rv.u = vml->autodownload; break;
+    case PARAM_ONLYMISSING: rv.u = vml->adl_only_missing; break;
     case PARAM_MAPZOOM: rv.u = vml->mapzoom_id; break;
   }
   return rv;
     case PARAM_MAPZOOM: rv.u = vml->mapzoom_id; break;
   }
   return rv;
@@ -422,21 +536,18 @@ static VikLayerParamData maps_layer_get_param ( VikMapsLayer *vml, guint16 id )
 
 static VikMapsLayer *maps_layer_new ( VikViewport *vvp )
 {
 
 static VikMapsLayer *maps_layer_new ( VikViewport *vvp )
 {
-  int idx;
   VikMapsLayer *vml = VIK_MAPS_LAYER ( g_object_new ( VIK_MAPS_LAYER_TYPE, NULL ) );
   VikMapsLayer *vml = VIK_MAPS_LAYER ( g_object_new ( VIK_MAPS_LAYER_TYPE, NULL ) );
-  vik_layer_init ( VIK_LAYER(vml), VIK_LAYER_MAPS );
-  idx = map_uniq_id_to_index(7); /* 7 is id for google maps */
-    vml->maptype = (idx < NUM_MAP_TYPES) ? idx : 0;
-  vml->alpha = 255;
-  vml->mapzoom_id = 0;
+  vik_layer_set_type ( VIK_LAYER(vml), VIK_LAYER_MAPS );
+
+  vik_layer_set_defaults ( VIK_LAYER(vml), vvp );
+
   vml->dl_tool_x = vml->dl_tool_y = -1;
   vml->dl_tool_x = vml->dl_tool_y = -1;
-  maps_layer_set_cache_dir ( vml, NULL );
-  vml->autodownload = FALSE;
   vml->last_center = NULL;
   vml->last_xmpp = 0.0;
   vml->last_ympp = 0.0;
 
   vml->dl_right_click_menu = NULL;
   vml->last_center = NULL;
   vml->last_xmpp = 0.0;
   vml->last_ympp = 0.0;
 
   vml->dl_right_click_menu = NULL;
+  vml->license_notice_shown = FALSE;
 
   return vml;
 }
 
   return vml;
 }
@@ -446,7 +557,7 @@ static void maps_layer_free ( VikMapsLayer *vml )
   g_free ( vml->cache_dir );
   vml->cache_dir = NULL;
   if ( vml->dl_right_click_menu )
   g_free ( vml->cache_dir );
   vml->cache_dir = NULL;
   if ( vml->dl_right_click_menu )
-    gtk_object_sink ( GTK_OBJECT(vml->dl_right_click_menu) );
+    g_object_ref_sink ( G_OBJECT(vml->dl_right_click_menu) );
   g_free(vml->last_center);
   vml->last_center = NULL;
 }
   g_free(vml->last_center);
   vml->last_center = NULL;
 }
@@ -462,17 +573,30 @@ static void maps_layer_post_read (VikLayer *vl, VikViewport *vp, gboolean from_f
     VikMapsLayer *vml = VIK_MAPS_LAYER(vl);
     VikMapSource *map = NULL;
  
     VikMapsLayer *vml = VIK_MAPS_LAYER(vl);
     VikMapSource *map = NULL;
  
-    vp_drawmode = vik_viewport_get_drawmode ( VIK_VIEWPORT(vp) );
+    vp_drawmode = vik_viewport_get_drawmode ( vp );
     map = MAPS_LAYER_NTH_TYPE(vml->maptype);
     if (vik_map_source_get_drawmode(map) != vp_drawmode) {
     map = MAPS_LAYER_NTH_TYPE(vml->maptype);
     if (vik_map_source_get_drawmode(map) != vp_drawmode) {
-      const gchar *drawmode_name = vik_viewport_get_drawmode_name (VIK_VIEWPORT(vp), vik_map_source_get_drawmode(map));
+      const gchar *drawmode_name = vik_viewport_get_drawmode_name (vp, vik_map_source_get_drawmode(map));
       gchar *msg = g_strdup_printf(_("New map cannot be displayed in the current drawmode.\nSelect \"%s\" from View menu to view it."), drawmode_name);
       gchar *msg = g_strdup_printf(_("New map cannot be displayed in the current drawmode.\nSelect \"%s\" from View menu to view it."), drawmode_name);
-      a_dialog_warning_msg ( VIK_GTK_WINDOW_FROM_LAYER(vml), msg );
+      a_dialog_warning_msg ( VIK_GTK_WINDOW_FROM_WIDGET(vp), msg );
       g_free(msg);
     }
       g_free(msg);
     }
+
+    if (vik_map_source_get_license (map) != NULL) {
+      if ( ! vml->license_notice_shown ) {
+       a_dialog_license (VIK_GTK_WINDOW_FROM_WIDGET(vp), vik_map_source_get_label (map),
+                         vik_map_source_get_license (map), vik_map_source_get_license_url (map) );
+       vml->license_notice_shown = TRUE;
+      }
+    }
   }
 }
 
   }
 }
 
+static const gchar* maps_layer_tooltip ( VikMapsLayer *vml )
+{
+  return vik_maps_layer_get_map_label ( vml );
+}
+
 static void maps_layer_marshall( VikMapsLayer *vml, guint8 **data, gint *len )
 {
   vik_layer_marshall_params ( VIK_LAYER(vml), data, len );
 static void maps_layer_marshall( VikMapsLayer *vml, guint8 **data, gint *len )
 {
   vik_layer_marshall_params ( VIK_LAYER(vml), data, len );
@@ -532,24 +656,30 @@ static GdkPixbuf *get_pixbuf( VikMapsLayer *vml, gint mode, MapCoord *mapcoord,
                             mode, mapcoord->scale, vml->alpha, xshrinkfactor, yshrinkfactor );
 
   if ( ! pixbuf ) {
                             mode, mapcoord->scale, vml->alpha, xshrinkfactor, yshrinkfactor );
 
   if ( ! pixbuf ) {
-    g_snprintf ( filename_buf, buf_len, DIRSTRUCTURE,
-                     vml->cache_dir, mode,
-                     mapcoord->scale, mapcoord->z, mapcoord->x, mapcoord->y );
-    if ( g_file_test ( filename_buf, G_FILE_TEST_EXISTS ) == TRUE) {
+    if ( vik_map_source_is_direct_file_access (MAPS_LAYER_NTH_TYPE(vml->maptype)) )
+      g_snprintf ( filename_buf, buf_len, DIRECTDIRACCESS,
+                  vml->cache_dir, (17 - mapcoord->scale), mapcoord->x, mapcoord->y, ".png" );
+    else
+      g_snprintf ( filename_buf, buf_len, DIRSTRUCTURE,
+                  vml->cache_dir, mode,
+                  mapcoord->scale, mapcoord->z, mapcoord->x, mapcoord->y );
+
+    if ( g_file_test ( filename_buf, G_FILE_TEST_EXISTS ) == TRUE)
     {
       GError *gx = NULL;
       pixbuf = gdk_pixbuf_new_from_file ( filename_buf, &gx );
 
     {
       GError *gx = NULL;
       pixbuf = gdk_pixbuf_new_from_file ( filename_buf, &gx );
 
+      /* free the pixbuf on error */
       if (gx)
       {
         if ( gx->domain != GDK_PIXBUF_ERROR || gx->code != GDK_PIXBUF_ERROR_CORRUPT_IMAGE )
           g_warning ( _("Couldn't open image file: %s"), gx->message );
 
       if (gx)
       {
         if ( gx->domain != GDK_PIXBUF_ERROR || gx->code != GDK_PIXBUF_ERROR_CORRUPT_IMAGE )
           g_warning ( _("Couldn't open image file: %s"), gx->message );
 
-          g_error_free ( gx );
-          if ( pixbuf )
-            g_object_unref ( G_OBJECT(pixbuf) );
-          pixbuf = NULL;
-        } else {
+        g_error_free ( gx );
+        if ( pixbuf )
+          g_object_unref ( G_OBJECT(pixbuf) );
+        pixbuf = NULL;
+      } else {
           if ( vml->alpha < 255 )
             pixbuf = pixbuf_set_alpha ( pixbuf, vml->alpha );
           if ( xshrinkfactor != 1.0 || yshrinkfactor != 1.0 )
           if ( vml->alpha < 255 )
             pixbuf = pixbuf_set_alpha ( pixbuf, vml->alpha );
           if ( xshrinkfactor != 1.0 || yshrinkfactor != 1.0 )
@@ -558,17 +688,28 @@ static GdkPixbuf *get_pixbuf( VikMapsLayer *vml, gint mode, MapCoord *mapcoord,
           a_mapcache_add ( pixbuf, mapcoord->x, mapcoord->y, 
               mapcoord->z, vik_map_source_get_uniq_id(MAPS_LAYER_NTH_TYPE(vml->maptype)),
               mapcoord->scale, vml->alpha, xshrinkfactor, yshrinkfactor );
           a_mapcache_add ( pixbuf, mapcoord->x, mapcoord->y, 
               mapcoord->z, vik_map_source_get_uniq_id(MAPS_LAYER_NTH_TYPE(vml->maptype)),
               mapcoord->scale, vml->alpha, xshrinkfactor, yshrinkfactor );
-        }
       }
     }
   }
   return pixbuf;
 }
 
       }
     }
   }
   return pixbuf;
 }
 
-gboolean should_start_autodownload(VikMapsLayer *vml, VikViewport *vvp)
+static gboolean should_start_autodownload(VikMapsLayer *vml, VikViewport *vvp)
 {
   const VikCoord *center = vik_viewport_get_center ( vvp );
 
 {
   const VikCoord *center = vik_viewport_get_center ( vvp );
 
+  if (vik_window_get_pan_move (VIK_WINDOW(VIK_GTK_WINDOW_FROM_WIDGET(GTK_WIDGET(vvp)))))
+    /* D'n'D pan in action: do not download */
+    return FALSE;
+
+  // TEMPORARY HACK
+  // Prevent requests for downloading tiles at Zoom Level 19 and above for most map types
+  // Allow MapQuest Zoom Level up to 19
+  // TODO: This should be made a property of the map source and then use that value
+  gdouble xzoom = vik_viewport_get_xmpp ( vvp );
+  if ( (vml->maptype != 19 && map_utils_mpp_to_scale (xzoom) < -1) || (vml->maptype == 19 && map_utils_mpp_to_scale (xzoom) < -2) )
+    return FALSE;
+
   if (vml->last_center == NULL) {
     VikCoord *new_center = g_malloc(sizeof(VikCoord));
     *new_center = *center;
   if (vml->last_center == NULL) {
     VikCoord *new_center = g_malloc(sizeof(VikCoord));
     *new_center = *center;
@@ -596,7 +737,7 @@ static void maps_layer_draw_section ( VikMapsLayer *vml, VikViewport *vvp, VikCo
   gdouble xzoom = vik_viewport_get_xmpp ( vvp );
   gdouble yzoom = vik_viewport_get_ympp ( vvp );
   gdouble xshrinkfactor = 1.0, yshrinkfactor = 1.0;
   gdouble xzoom = vik_viewport_get_xmpp ( vvp );
   gdouble yzoom = vik_viewport_get_ympp ( vvp );
   gdouble xshrinkfactor = 1.0, yshrinkfactor = 1.0;
-  gdouble existence_only = FALSE;
+  gboolean existence_only = FALSE;
 
   if ( vml->xmapzoom && (vml->xmapzoom != xzoom || vml->ymapzoom != yzoom) ) {
     xshrinkfactor = vml->xmapzoom / xzoom;
 
   if ( vml->xmapzoom && (vml->xmapzoom != xzoom || vml->ymapzoom != yzoom) ) {
     xshrinkfactor = vml->xmapzoom / xzoom;
@@ -605,8 +746,10 @@ static void maps_layer_draw_section ( VikMapsLayer *vml, VikViewport *vvp, VikCo
     yzoom = vml->xmapzoom;
     if ( ! (xshrinkfactor > MIN_SHRINKFACTOR && xshrinkfactor < MAX_SHRINKFACTOR &&
          yshrinkfactor > MIN_SHRINKFACTOR && yshrinkfactor < MAX_SHRINKFACTOR ) ) {
     yzoom = vml->xmapzoom;
     if ( ! (xshrinkfactor > MIN_SHRINKFACTOR && xshrinkfactor < MAX_SHRINKFACTOR &&
          yshrinkfactor > MIN_SHRINKFACTOR && yshrinkfactor < MAX_SHRINKFACTOR ) ) {
-      if ( xshrinkfactor > REAL_MIN_SHRINKFACTOR && yshrinkfactor > REAL_MIN_SHRINKFACTOR )
+      if ( xshrinkfactor > REAL_MIN_SHRINKFACTOR && yshrinkfactor > REAL_MIN_SHRINKFACTOR ) {
+        g_debug ( "%s: existence_only due to SHRINKFACTORS", __FUNCTION__ );
         existence_only = TRUE;
         existence_only = TRUE;
+      }
       else {
         g_warning ( _("Cowardly refusing to draw tiles or existence of tiles beyond %d zoom out factor"), (int)( 1.0/REAL_MIN_SHRINKFACTOR));
         return;
       else {
         g_warning ( _("Cowardly refusing to draw tiles or existence of tiles beyond %d zoom out factor"), (int)( 1.0/REAL_MIN_SHRINKFACTOR));
         return;
@@ -629,14 +772,26 @@ static void maps_layer_draw_section ( VikMapsLayer *vml, VikViewport *vvp, VikCo
     gint xx, yy, width, height;
     GdkPixbuf *pixbuf;
 
     gint xx, yy, width, height;
     GdkPixbuf *pixbuf;
 
+    // Prevent the program grinding to a halt if trying to deal with thousands of tiles
+    //  which can happen when using a small fixed zoom level and viewing large areas.
+    // Also prevents very large number of tile download requests
+    gint tiles = (xmax-xmin) * (ymax-ymin);
+    if ( tiles > MAX_TILES ) {
+      g_debug ( "%s: existence_only due to wanting too many tiles (%d)", __FUNCTION__, tiles );
+      existence_only = TRUE;
+    }
+
     guint max_path_len = strlen(vml->cache_dir) + 40;
     gchar *path_buf = g_malloc ( max_path_len * sizeof(char) );
 
     if ( (!existence_only) && vml->autodownload  && should_start_autodownload(vml, vvp)) {
     guint max_path_len = strlen(vml->cache_dir) + 40;
     gchar *path_buf = g_malloc ( max_path_len * sizeof(char) );
 
     if ( (!existence_only) && vml->autodownload  && should_start_autodownload(vml, vvp)) {
-#ifdef DEBUG
-      fputs(stderr, "DEBUG: Starting autodownload\n");
-#endif
-      start_download_thread ( vml, vvp, ul, br, REDOWNLOAD_NONE );
+      g_debug("%s: Starting autodownload", __FUNCTION__);
+      if ( !vml->adl_only_missing && vik_map_source_supports_download_only_new (map) )
+        // Try to download newer tiles
+        start_download_thread ( vml, vvp, ul, br, REDOWNLOAD_NEW );
+      else
+        // Download only missing tiles
+        start_download_thread ( vml, vvp, ul, br, REDOWNLOAD_NONE );
     }
 
     if ( vik_map_source_get_tilesize_x(map) == 0 && !existence_only ) {
     }
 
     if ( vik_map_source_get_tilesize_x(map) == 0 && !existence_only ) {
@@ -669,8 +824,6 @@ static void maps_layer_draw_section ( VikMapsLayer *vml, VikViewport *vvp, VikCo
       gdouble xx, yy; gint xx_tmp, yy_tmp;
       gint base_yy, xend, yend;
 
       gdouble xx, yy; gint xx_tmp, yy_tmp;
       gint base_yy, xend, yend;
 
-      GdkGC *black_gc = GTK_WIDGET(vvp)->style->black_gc;
-
       xend = (xinc == 1) ? (xmax+1) : (xmin-1);
       yend = (yinc == 1) ? (ymax+1) : (ymin-1);
 
       xend = (xinc == 1) ? (xmax+1) : (xmin-1);
       yend = (yinc == 1) ? (ymax+1) : (ymin-1);
 
@@ -689,16 +842,64 @@ static void maps_layer_draw_section ( VikMapsLayer *vml, VikViewport *vvp, VikCo
           ulm.y = y;
 
           if ( existence_only ) {
           ulm.y = y;
 
           if ( existence_only ) {
-            g_snprintf ( path_buf, max_path_len, DIRSTRUCTURE,
-                     vml->cache_dir, mode,
-                     ulm.scale, ulm.z, ulm.x, ulm.y );
+           if ( vik_map_source_is_direct_file_access (MAPS_LAYER_NTH_TYPE(vml->maptype)) )
+             g_snprintf ( path_buf, max_path_len, DIRECTDIRACCESS,
+                          vml->cache_dir, (17 - ulm.scale), ulm.x, ulm.y, ".png" );
+           else
+             g_snprintf ( path_buf, max_path_len, DIRSTRUCTURE,
+                          vml->cache_dir, mode,
+                          ulm.scale, ulm.z, ulm.x, ulm.y );
             if ( g_file_test ( path_buf, G_FILE_TEST_EXISTS ) == TRUE ) {
             if ( g_file_test ( path_buf, G_FILE_TEST_EXISTS ) == TRUE ) {
+             GdkGC *black_gc = gtk_widget_get_style(GTK_WIDGET(vvp))->black_gc;
               vik_viewport_draw_line ( vvp, black_gc, xx+tilesize_x_ceil, yy, xx, yy+tilesize_y_ceil );
             }
           } else {
               vik_viewport_draw_line ( vvp, black_gc, xx+tilesize_x_ceil, yy, xx, yy+tilesize_y_ceil );
             }
           } else {
-            pixbuf = get_pixbuf ( vml, mode, &ulm, path_buf, max_path_len, xshrinkfactor, yshrinkfactor );
-            if ( pixbuf )
-              vik_viewport_draw_pixbuf ( vvp, pixbuf, 0, 0, xx, yy, tilesize_x_ceil, tilesize_y_ceil );
+            int scale_inc;
+            for (scale_inc = 0; scale_inc < 4; scale_inc ++) {
+              /* try with correct then smaller zooms */
+              int scale_factor = 1 << scale_inc;  /*  2^scale_inc */
+              MapCoord ulm2 = ulm;
+              ulm2.x = ulm.x / scale_factor;
+              ulm2.y = ulm.y / scale_factor;
+              ulm2.scale = ulm.scale + scale_inc;
+              pixbuf = get_pixbuf ( vml, mode, &ulm2, path_buf, max_path_len, xshrinkfactor * scale_factor, yshrinkfactor * scale_factor );
+              if ( pixbuf ) {
+                gint src_x = (ulm.x % scale_factor) * tilesize_x_ceil;
+                gint src_y = (ulm.y % scale_factor) * tilesize_y_ceil;
+#ifdef DEBUG
+                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);
+#endif
+                vik_viewport_draw_pixbuf ( vvp, pixbuf, src_x, src_y, xx, yy, tilesize_x_ceil, tilesize_y_ceil );
+                break;
+              }
+            }
+            if ( !pixbuf ) {
+              /* retry with bigger zooms */
+              int scale_dec;
+              for (scale_dec = 1; scale_dec < 2; scale_dec ++) {
+                int pict_x, pict_y;
+                int scale_factor = 1 << scale_dec;  /*  2^scale_dec */
+                MapCoord ulm2 = ulm;
+                ulm2.x = ulm.x * scale_factor;
+                ulm2.y = ulm.y * scale_factor;
+                ulm2.scale = ulm.scale - scale_dec;
+                for (pict_x = 0; pict_x < scale_factor; pict_x ++) {
+                  for (pict_y = 0; pict_y < scale_factor; pict_y ++) {
+                    MapCoord ulm3 = ulm2;
+                    ulm3.x += pict_x;
+                    ulm3.y += pict_y;
+                    pixbuf = get_pixbuf ( vml, mode, &ulm3, path_buf, max_path_len, xshrinkfactor / scale_factor, yshrinkfactor / scale_factor );
+                    if ( pixbuf ) {
+                      gint src_x = 0;
+                      gint src_y = 0;
+                      gint dest_x = xx + pict_x * (tilesize_x_ceil / scale_factor);
+                      gint dest_y = yy + pict_y * (tilesize_y_ceil / scale_factor);
+                      vik_viewport_draw_pixbuf ( vvp, pixbuf, src_x, src_y, dest_x, dest_y, tilesize_x_ceil / scale_factor, tilesize_y_ceil / scale_factor );
+                    }
+                  }
+                }
+              }
+            }
           }
 
           yy += tilesize_y;
           }
 
           yy += tilesize_y;
@@ -717,6 +918,16 @@ static void maps_layer_draw ( VikMapsLayer *vml, VikViewport *vvp )
   {
     VikCoord ul, br;
 
   {
     VikCoord ul, br;
 
+    /* Copyright */
+    gdouble level = vik_viewport_get_zoom ( vvp );
+    LatLonBBox bbox;
+    vik_viewport_get_min_max_lat_lon ( vvp, &bbox.south, &bbox.north, &bbox.west, &bbox.east );
+    vik_map_source_get_copyright ( MAPS_LAYER_NTH_TYPE(vml->maptype), bbox, level, vik_viewport_add_copyright, vvp );
+
+    /* Logo */
+    const GdkPixbuf *logo = vik_map_source_get_logo ( MAPS_LAYER_NTH_TYPE(vml->maptype) );
+    vik_viewport_add_logo ( vvp, logo );
+
     /* get corner coords */
     if ( vik_viewport_get_coord_mode ( vvp ) == VIK_COORD_UTM && ! vik_viewport_is_one_zone ( vvp ) ) {
       /* UTM multi-zone stuff by Kit Transue */
     /* get corner coords */
     if ( vik_viewport_get_coord_mode ( vvp ) == VIK_COORD_UTM && ! vik_viewport_is_one_zone ( vvp ) ) {
       /* UTM multi-zone stuff by Kit Transue */
@@ -778,6 +989,7 @@ static void weak_ref_cb(gpointer ptr, GObject * dead_vml)
 
 static int map_download_thread ( MapDownloadInfo *mdi, gpointer threaddata )
 {
 
 static int map_download_thread ( MapDownloadInfo *mdi, gpointer threaddata )
 {
+  void *handle = vik_map_source_download_handle_init(MAPS_LAYER_NTH_TYPE(mdi->maptype));
   guint donemaps = 0;
   gint x, y;
   for ( x = mdi->x0; x <= mdi->xf; x++ )
   guint donemaps = 0;
   gint x, y;
   for ( x = mdi->x0; x <= mdi->xf; x++ )
@@ -792,57 +1004,78 @@ static int map_download_thread ( MapDownloadInfo *mdi, gpointer threaddata )
 
       donemaps++;
       int res = a_background_thread_progress ( threaddata, ((gdouble)donemaps) / mdi->mapstoget ); /* this also calls testcancel */
 
       donemaps++;
       int res = a_background_thread_progress ( threaddata, ((gdouble)donemaps) / mdi->mapstoget ); /* this also calls testcancel */
-      if (res != 0)
+      if (res != 0) {
+        vik_map_source_download_handle_cleanup(MAPS_LAYER_NTH_TYPE(mdi->maptype), handle);
         return -1;
         return -1;
-
-      if ( mdi->redownload == REDOWNLOAD_ALL)
-        g_remove ( mdi->filename_buf );
-
-      else if ( (mdi->redownload == REDOWNLOAD_BAD) && (g_file_test ( mdi->filename_buf, G_FILE_TEST_EXISTS ) == TRUE) )
-      {
-        /* see if this one is bad or what */
-        GError *gx = NULL;
-        GdkPixbuf *pixbuf = gdk_pixbuf_new_from_file ( mdi->filename_buf, &gx );
-        if (gx || (!pixbuf))
-          g_remove ( mdi->filename_buf );
-        if ( pixbuf )
-          g_object_unref ( pixbuf );
-        if ( gx )
-          g_error_free ( gx );
       }
 
       }
 
-      if ( g_file_test ( mdi->filename_buf, G_FILE_TEST_EXISTS ) == FALSE )
-      {
+      if ( g_file_test ( mdi->filename_buf, G_FILE_TEST_EXISTS ) == FALSE ) {
         need_download = TRUE;
         need_download = TRUE;
-        if (( mdi->redownload != REDOWNLOAD_NONE ) &&
-            ( mdi->redownload != DOWNLOAD_OR_REFRESH ))
-          remove_mem_cache = TRUE;
-      } else if ( mdi->redownload == DOWNLOAD_OR_REFRESH ) {
         remove_mem_cache = TRUE;
         remove_mem_cache = TRUE;
-      } else
-        continue;
+
+      } else {  /* in case map file already exists */
+        switch (mdi->redownload) {
+          case REDOWNLOAD_NONE:
+            continue;
+
+          case REDOWNLOAD_BAD:
+          {
+            /* see if this one is bad or what */
+            GError *gx = NULL;
+            GdkPixbuf *pixbuf = gdk_pixbuf_new_from_file ( mdi->filename_buf, &gx );
+            if (gx || (!pixbuf)) {
+              g_remove ( mdi->filename_buf );
+              need_download = TRUE;
+              remove_mem_cache = TRUE;
+              g_error_free ( gx );
+
+            } else {
+              g_object_unref ( pixbuf );
+            }
+            break;
+          }
+
+          case REDOWNLOAD_NEW:
+            need_download = TRUE;
+            remove_mem_cache = TRUE;
+            break;
+
+          case REDOWNLOAD_ALL:
+            /* FIXME: need a better way than to erase file in case of server/network problem */
+            g_remove ( mdi->filename_buf );
+            need_download = TRUE;
+            remove_mem_cache = TRUE;
+            break;
+
+          case DOWNLOAD_OR_REFRESH:
+            remove_mem_cache = TRUE;
+            break;
+
+          default:
+            g_warning ( "redownload state %d unknown\n", mdi->redownload);
+        }
+      }
 
       mdi->mapcoord.x = x; mdi->mapcoord.y = y;
 
       if (need_download) {
 
       mdi->mapcoord.x = x; mdi->mapcoord.y = y;
 
       if (need_download) {
-        if ( vik_map_source_download( MAPS_LAYER_NTH_TYPE(mdi->maptype), &(mdi->mapcoord), mdi->filename_buf ))
+        if ( vik_map_source_download( MAPS_LAYER_NTH_TYPE(mdi->maptype), &(mdi->mapcoord), mdi->filename_buf, handle))
           continue;
       }
 
           continue;
       }
 
-      gdk_threads_enter();
       g_mutex_lock(mdi->mutex);
       if (remove_mem_cache)
           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 );
       if (mdi->refresh_display && mdi->map_layer_alive) {
         /* TODO: check if it's on visible area */
       g_mutex_lock(mdi->mutex);
       if (remove_mem_cache)
           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 );
       if (mdi->refresh_display && mdi->map_layer_alive) {
         /* TODO: check if it's on visible area */
-        vik_layer_emit_update ( VIK_LAYER(mdi->vml) );
+        vik_layer_emit_update ( VIK_LAYER(mdi->vml) ); // NB update display from background
       }
       g_mutex_unlock(mdi->mutex);
       }
       g_mutex_unlock(mdi->mutex);
-      gdk_threads_leave();
       mdi->mapcoord.x = mdi->mapcoord.y = 0; /* we're temporarily between downloads */
 
     }
   }
       mdi->mapcoord.x = mdi->mapcoord.y = 0; /* we're temporarily between downloads */
 
     }
   }
+  vik_map_source_download_handle_cleanup(MAPS_LAYER_NTH_TYPE(mdi->maptype), handle);
   g_mutex_lock(mdi->mutex);
   if (mdi->map_layer_alive)
     g_object_weak_unref(G_OBJECT(mdi->vml), weak_ref_cb, mdi);
   g_mutex_lock(mdi->mutex);
   if (mdi->map_layer_alive)
     g_object_weak_unref(G_OBJECT(mdi->vml), weak_ref_cb, mdi);
@@ -870,6 +1103,11 @@ static void start_download_thread ( VikMapsLayer *vml, VikViewport *vvp, const V
   gdouble yzoom = vml->ymapzoom ? vml->ymapzoom : vik_viewport_get_ympp ( vvp );
   MapCoord ulm, brm;
   VikMapSource *map = MAPS_LAYER_NTH_TYPE(vml->maptype);
   gdouble yzoom = vml->ymapzoom ? vml->ymapzoom : vik_viewport_get_ympp ( vvp );
   MapCoord ulm, brm;
   VikMapSource *map = MAPS_LAYER_NTH_TYPE(vml->maptype);
+
+  // Don't ever attempt download on direct access
+  if ( vik_map_source_is_direct_file_access ( map ) )
+    return;
+
   if ( vik_map_source_coord_to_mapcoord ( map, ul, xzoom, yzoom, &ulm ) 
     && vik_map_source_coord_to_mapcoord ( map, br, xzoom, yzoom, &brm ) )
   {
   if ( vik_map_source_coord_to_mapcoord ( map, ul, xzoom, yzoom, &ulm ) 
     && vik_map_source_coord_to_mapcoord ( map, br, xzoom, yzoom, &brm ) )
   {
@@ -952,11 +1190,15 @@ static void start_download_thread ( VikMapsLayer *vml, VikViewport *vvp, const V
   }
 }
 
   }
 }
 
-void maps_layer_download_section_without_redraw( VikMapsLayer *vml, VikViewport *vvp, VikCoord *ul, VikCoord *br, gdouble zoom)
+void maps_layer_download_section ( VikMapsLayer *vml, VikViewport *vvp, VikCoord *ul, VikCoord *br, gdouble zoom)
 {
   MapCoord ulm, brm;
   VikMapSource *map = MAPS_LAYER_NTH_TYPE(vml->maptype);
 
 {
   MapCoord ulm, brm;
   VikMapSource *map = MAPS_LAYER_NTH_TYPE(vml->maptype);
 
+  // Don't ever attempt download on direct access
+  if ( vik_map_source_is_direct_file_access ( map ) )
+    return;
+
   if (!vik_map_source_coord_to_mapcoord(map, ul, zoom, zoom, &ulm) 
     || !vik_map_source_coord_to_mapcoord(map, br, zoom, zoom, &brm)) {
     g_warning("%s() coord_to_mapcoord() failed", __PRETTY_FUNCTION__);
   if (!vik_map_source_coord_to_mapcoord(map, ul, zoom, zoom, &ulm) 
     || !vik_map_source_coord_to_mapcoord(map, br, zoom, zoom, &brm)) {
     g_warning("%s() coord_to_mapcoord() failed", __PRETTY_FUNCTION__);
@@ -970,7 +1212,7 @@ void maps_layer_download_section_without_redraw( VikMapsLayer *vml, VikViewport
   mdi->vvp = vvp;
   mdi->map_layer_alive = TRUE;
   mdi->mutex = g_mutex_new();
   mdi->vvp = vvp;
   mdi->map_layer_alive = TRUE;
   mdi->mutex = g_mutex_new();
-  mdi->refresh_display = FALSE;
+  mdi->refresh_display = TRUE;
 
   mdi->cache_dir = g_strdup ( vml->cache_dir );
   mdi->maxlen = strlen ( vml->cache_dir ) + 40;
 
   mdi->cache_dir = g_strdup ( vml->cache_dir );
   mdi->maxlen = strlen ( vml->cache_dir ) + 40;
@@ -1027,11 +1269,81 @@ static void maps_layer_redownload_bad ( VikMapsLayer *vml )
 {
   start_download_thread ( vml, vml->redownload_vvp, &(vml->redownload_ul), &(vml->redownload_br), REDOWNLOAD_BAD );
 }
 {
   start_download_thread ( vml, vml->redownload_vvp, &(vml->redownload_ul), &(vml->redownload_br), REDOWNLOAD_BAD );
 }
+
 static void maps_layer_redownload_all ( VikMapsLayer *vml )
 {
   start_download_thread ( vml, vml->redownload_vvp, &(vml->redownload_ul), &(vml->redownload_br), REDOWNLOAD_ALL );
 }
 
 static void maps_layer_redownload_all ( VikMapsLayer *vml )
 {
   start_download_thread ( vml, vml->redownload_vvp, &(vml->redownload_ul), &(vml->redownload_br), REDOWNLOAD_ALL );
 }
 
+static void maps_layer_redownload_new ( VikMapsLayer *vml )
+{
+  start_download_thread ( vml, vml->redownload_vvp, &(vml->redownload_ul), &(vml->redownload_br), REDOWNLOAD_NEW );
+}
+
+/**
+ * Display a simple dialog with information about this particular map tile
+ */
+static void maps_layer_tile_info ( VikMapsLayer *vml )
+{
+  VikMapSource *map = MAPS_LAYER_NTH_TYPE(vml->maptype);
+
+  gdouble xzoom = vml->xmapzoom ? vml->xmapzoom : vik_viewport_get_xmpp ( vml->redownload_vvp );
+  gdouble yzoom = vml->ymapzoom ? vml->ymapzoom : vik_viewport_get_ympp ( vml->redownload_vvp );
+  MapCoord ulm;
+
+  if ( !vik_map_source_coord_to_mapcoord ( map, &(vml->redownload_ul), xzoom, yzoom, &ulm ) )
+    return;
+
+  gchar *filename = NULL;
+  gchar *message = NULL;
+  gchar *source = NULL;
+
+  if ( vik_map_source_is_direct_file_access ( map ) ) {
+    filename = g_strdup_printf ( DIRECTDIRACCESS, vml->cache_dir, ulm.scale, ulm.x, ulm.y, ".png" );
+    source = g_strconcat ( "file://", filename, NULL );
+  }
+  else {
+       filename = g_strdup_printf ( DIRSTRUCTURE, vml->cache_dir, vik_map_source_get_uniq_id(map), ulm.scale, ulm.z, ulm.x, ulm.y );
+    source = g_strdup_printf ( "http://%s%s",
+                               vik_map_source_default_get_hostname ( VIK_MAP_SOURCE_DEFAULT(map) ),
+                               vik_map_source_default_get_uri ( VIK_MAP_SOURCE_DEFAULT(map), &ulm ) );
+  }
+
+  if ( g_file_test ( filename, G_FILE_TEST_EXISTS ) ) {
+
+    // Get some timestamp information of the tile
+    struct stat stat_buf;
+    if ( g_stat ( filename, &stat_buf ) == 0 ) {
+      time_t file_time = stat_buf.st_mtime;
+#if GLIB_CHECK_VERSION(2,26,0)
+      GDateTime* gdt = g_date_time_new_from_unix_utc ( file_time );
+      gchar *time = g_date_time_format ( gdt, "%c" );
+#else
+      GDate* gdate = g_date_new ();
+      g_date_set_time_t ( gdate, file_time );
+      char time[32];
+      g_date_strftime ( time, sizeof(time), "%c", gdate );
+      g_date_free ( gdate );
+#endif
+      message = g_strdup_printf ( _("\nSource: %s\n\nTile File: %s\nTile File Timestamp: %s"), source, filename, time );
+
+#if GLIB_CHECK_VERSION(2,26,0)
+      g_free ( time );
+      g_date_time_unref ( gdt);
+#endif
+    }
+  }
+  else
+    message = g_strdup_printf ( _("Source: %s\n\nNo Tile File!"), source );
+
+  // Show the info
+  a_dialog_info_msg (  VIK_GTK_WINDOW_FROM_LAYER(vml), message );
+
+  g_free ( message );
+  g_free ( source );
+  g_free ( filename );
+}
+
 static gboolean maps_layer_download_release ( VikMapsLayer *vml, GdkEventButton *event, VikViewport *vvp )
 {
   if (!vml || vml->vl.type != VIK_LAYER_MAPS)
 static gboolean maps_layer_download_release ( VikMapsLayer *vml, GdkEventButton *event, VikViewport *vvp )
 {
   if (!vml || vml->vl.type != VIK_LAYER_MAPS)
@@ -1060,13 +1372,22 @@ static gboolean maps_layer_download_release ( VikMapsLayer *vml, GdkEventButton
         GtkWidget *item;
         vml->dl_right_click_menu = GTK_MENU ( gtk_menu_new () );
 
         GtkWidget *item;
         vml->dl_right_click_menu = GTK_MENU ( gtk_menu_new () );
 
-        item = gtk_menu_item_new_with_label ( _("Redownload bad map(s)") );
+        item = gtk_menu_item_new_with_mnemonic ( _("Redownload _Bad Map(s)") );
         g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(maps_layer_redownload_bad), vml );
         gtk_menu_shell_append ( GTK_MENU_SHELL(vml->dl_right_click_menu), item );
 
         g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(maps_layer_redownload_bad), vml );
         gtk_menu_shell_append ( GTK_MENU_SHELL(vml->dl_right_click_menu), item );
 
-        item = gtk_menu_item_new_with_label ( _("Redownload all map(s)") );
+        item = gtk_menu_item_new_with_mnemonic ( _("Redownload _New Map(s)") );
+        g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(maps_layer_redownload_new), vml );
+        gtk_menu_shell_append ( GTK_MENU_SHELL(vml->dl_right_click_menu), item );
+
+        item = gtk_menu_item_new_with_mnemonic ( _("Redownload _All Map(s)") );
         g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(maps_layer_redownload_all), vml );
         gtk_menu_shell_append ( GTK_MENU_SHELL(vml->dl_right_click_menu), item );
         g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(maps_layer_redownload_all), vml );
         gtk_menu_shell_append ( GTK_MENU_SHELL(vml->dl_right_click_menu), item );
+
+        item = gtk_image_menu_item_new_with_mnemonic ( _("_Show Tile Information") );
+        gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_INFO, GTK_ICON_SIZE_MENU) );
+        g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(maps_layer_tile_info), vml );
+        gtk_menu_shell_append (GTK_MENU_SHELL(vml->dl_right_click_menu), item);
       }
 
       gtk_menu_popup ( vml->dl_right_click_menu, NULL, NULL, NULL, NULL, event->button, event->time );
       }
 
       gtk_menu_popup ( vml->dl_right_click_menu, NULL, NULL, NULL, NULL, event->button, event->time );
@@ -1153,11 +1474,16 @@ static void download_onscreen_maps ( gpointer vml_vvp[2], gint redownload )
 
 }
 
 
 }
 
-static void maps_layer_download_onscreen_maps ( gpointer vml_vvp[2] )
+static void maps_layer_download_missing_onscreen_maps ( gpointer vml_vvp[2] )
 {
   download_onscreen_maps( vml_vvp, REDOWNLOAD_NONE);
 }
 
 {
   download_onscreen_maps( vml_vvp, REDOWNLOAD_NONE);
 }
 
+static void maps_layer_download_new_onscreen_maps ( gpointer vml_vvp[2] )
+{
+  download_onscreen_maps( vml_vvp, REDOWNLOAD_NEW);
+}
+
 static void maps_layer_redownload_all_onscreen_maps ( gpointer vml_vvp[2] )
 {
   download_onscreen_maps( vml_vvp, REDOWNLOAD_ALL);
 static void maps_layer_redownload_all_onscreen_maps ( gpointer vml_vvp[2] )
 {
   download_onscreen_maps( vml_vvp, REDOWNLOAD_ALL);
@@ -1174,14 +1500,44 @@ static void maps_layer_add_menu_items ( VikMapsLayer *vml, GtkMenu *menu, VikLay
   gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item );
   gtk_widget_show ( item );
 
   gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item );
   gtk_widget_show ( item );
 
-  item = gtk_menu_item_new_with_label ( _("Download Onscreen Maps") );
-  g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(maps_layer_download_onscreen_maps), pass_along );
+  /* Now with icons */
+  item = gtk_image_menu_item_new_with_mnemonic ( _("Download _Missing Onscreen Maps") );
+    gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_ADD, GTK_ICON_SIZE_MENU) );
+  g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(maps_layer_download_missing_onscreen_maps), pass_along );
   gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
   gtk_widget_show ( item );
 
   gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
   gtk_widget_show ( item );
 
-  /* TODO Add GTK_STOCK_REFRESH icon */
-  item = gtk_menu_item_new_with_label ( _("Refresh Onscreen Tiles") );
+  if ( vik_map_source_supports_download_only_new (MAPS_LAYER_NTH_TYPE(vml->maptype)) ) {
+    item = gtk_image_menu_item_new_with_mnemonic ( _("Download _New Onscreen Maps") );
+    gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_REDO, GTK_ICON_SIZE_MENU) );
+    g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(maps_layer_download_new_onscreen_maps), pass_along );
+    gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
+    gtk_widget_show ( item );
+  }
+
+  item = gtk_image_menu_item_new_with_mnemonic ( _("Reload _All Onscreen Maps") );
+  gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_REFRESH, GTK_ICON_SIZE_MENU) );
   g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(maps_layer_redownload_all_onscreen_maps), pass_along );
   gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
   gtk_widget_show ( item );
 }
   g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(maps_layer_redownload_all_onscreen_maps), pass_along );
   gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
   gtk_widget_show ( item );
 }
+
+/**
+ * Enable downloading maps of the current screen area either 'new' or 'everything'
+ */
+void vik_maps_layer_download ( VikMapsLayer *vml, VikViewport *vvp, gboolean only_new )
+{
+  if ( !vml ) return;
+  if ( !vvp ) return;
+
+  static gpointer pass_along[2];
+  pass_along[0] = vml;
+  pass_along[1] = vvp;
+
+  if ( only_new )
+    // Get only new maps
+    maps_layer_download_new_onscreen_maps ( pass_along );
+  else
+    // Redownload everything
+    maps_layer_redownload_all_onscreen_maps ( pass_along );
+}