]> git.street.me.uk Git - andy/viking.git/blobdiff - src/vikmapslayer.c
[QA] Consistent usage of g_stat() GStatBuf parameter type
[andy/viking.git] / src / vikmapslayer.c
index 928e33f2345a35fa420f989f8515c5775c1a0810..6b1f9f9053a0022acaace9e82200fea476a7d155 100644 (file)
@@ -55,6 +55,7 @@
 #include "icons/icons.h"
 #include "metatile.h"
 #include "ui_util.h"
+#include "map_ids.h"
 
 #ifdef HAVE_SQLITE3_H
 #include "sqlite3.h"
@@ -126,7 +127,7 @@ static VikLayerParamScale params_scales[] = {
  { 0, 255, 3, 0 }, /* alpha */
 };
 
-static VikLayerParamData id_default ( void ) { return VIK_LPD_UINT ( 19 ); } // OSM MapQuest maps
+static VikLayerParamData id_default ( void ) { return VIK_LPD_UINT ( MAP_ID_MAPQUEST_OSM ); }
 static VikLayerParamData directory_default ( void )
 {
   VikLayerParamData data;
@@ -231,6 +232,8 @@ VikLayerInterface vik_maps_layer_interface = {
   (VikLayerFuncDraw)                    maps_layer_draw,
   (VikLayerFuncChangeCoordMode)         NULL,
 
+  (VikLayerFuncGetTimestamp)            NULL,
+
   (VikLayerFuncSetMenuItemsSelection)   NULL,
   (VikLayerFuncGetMenuItemsSelection)   NULL,
 
@@ -411,9 +414,40 @@ void maps_layer_register_map_source ( VikMapSource *map )
 #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)
+/**
+ * vik_maps_layer_get_map_type:
+ *
+ * Returns the actual map id (rather than the internal type index value)
+ */
+guint vik_maps_layer_get_map_type(VikMapsLayer *vml)
+{
+  return MAPS_LAYER_NTH_ID(vml->maptype);
+}
+
+/**
+ * vik_maps_layer_set_map_type:
+ *
+ */
+void vik_maps_layer_set_map_type(VikMapsLayer *vml, guint map_type)
+{
+   gint maptype = map_uniq_id_to_index(map_type);
+   if ( maptype == NUM_MAP_TYPES )
+      g_warning(_("Unknown map type"));
+   else
+      vml->maptype = maptype;
+}
+
+/**
+ * vik_maps_layer_get_default_map_type:
+ *
+ */
+guint vik_maps_layer_get_default_map_type ()
 {
-  return(vml->maptype);
+  VikLayerInterface *vli = vik_layer_get_interface ( VIK_LAYER_MAPS );
+  VikLayerParamData vlpd = a_layer_defaults_get ( vli->fixed_layer_name, "mode", VIK_LAYER_PARAM_UINT );
+  if ( vlpd.u == 0 )
+    vlpd = id_default();
+  return vlpd.u;
 }
 
 gchar *vik_maps_layer_get_map_label(VikMapsLayer *vml)
@@ -480,7 +514,8 @@ static void maps_layer_mkdir_if_default_dir ( VikMapsLayer *vml )
 {
   if ( vml->cache_dir && strcmp ( vml->cache_dir, MAPS_CACHE_DIR ) == 0 && g_file_test ( vml->cache_dir, G_FILE_TEST_EXISTS ) == FALSE )
   {
-    g_mkdir ( vml->cache_dir, 0777 );
+    if ( g_mkdir ( vml->cache_dir, 0777 ) != 0 )
+      g_warning ( "%s: Failed to create directory %s", __FUNCTION__, vml->cache_dir );
   }
 }
 
@@ -501,16 +536,20 @@ static void maps_layer_set_cache_dir ( VikMapsLayer *vml, const gchar *dir )
 
   // Ensure cache_dir always ends with a separator
   guint len = strlen(canonical_dir);
-  if ( canonical_dir[len-1] != G_DIR_SEPARATOR )
+  // Unless the dir is not valid
+  if ( len > 0 )
   {
-    vml->cache_dir = g_strconcat ( canonical_dir, G_DIR_SEPARATOR_S, NULL );
-    g_free ( canonical_dir );
-  }
-  else {
-    vml->cache_dir = canonical_dir;
-  }
+    if ( canonical_dir[len-1] != G_DIR_SEPARATOR )
+    {
+      vml->cache_dir = g_strconcat ( canonical_dir, G_DIR_SEPARATOR_S, NULL );
+      g_free ( canonical_dir );
+    }
+    else {
+      vml->cache_dir = canonical_dir;
+    }
 
-  maps_layer_mkdir_if_default_dir ( vml );
+    maps_layer_mkdir_if_default_dir ( vml );
+  }
 }
 
 static void maps_layer_set_file ( VikMapsLayer *vml, const gchar *name )
@@ -640,15 +679,15 @@ static VikLayerParamData maps_layer_get_param ( VikMapsLayer *vml, guint16 id, g
         rv.s = "";
         set = TRUE;
       }
-      else if ( is_file_operation ) {
+      else if ( is_file_operation && vml->cache_dir ) {
         if ( a_vik_get_file_ref_format() == VIK_FILE_REF_FORMAT_RELATIVE ) {
           gchar *cwd = g_get_current_dir();
           if ( cwd ) {
             rv.s = file_GetRelativeFilename ( cwd, vml->cache_dir );
             if ( !rv.s ) rv.s = "";
             set = TRUE;
-         }
-       }
+          }
+        }
       }
       if ( !set )
        rv.s = vml->cache_dir ? vml->cache_dir : "";
@@ -674,7 +713,9 @@ static void maps_layer_change_param ( GtkWidget *widget, ui_change_values values
       // Get new value
       VikLayerParamData vlpd = a_uibuilder_widget_get_value ( widget, values[UI_CHG_PARAM] );
       // Is it *not* the OSM On Disk Tile Layout or the MBTiles type or the OSM Metatiles type
-      gboolean sensitive = ( 21 != vlpd.u && 23 != vlpd.u && 24 != vlpd.u );
+      gboolean sensitive = ( MAP_ID_OSM_ON_DISK != vlpd.u &&
+                             MAP_ID_MBTILES != vlpd.u &&
+                             MAP_ID_OSM_METATILES != vlpd.u );
       GtkWidget **ww1 = values[UI_CHG_WIDGETS];
       GtkWidget **ww2 = values[UI_CHG_LABELS];
       GtkWidget *w1 = ww1[PARAM_ONLYMISSING];
@@ -696,7 +737,7 @@ static void maps_layer_change_param ( GtkWidget *widget, ui_change_values values
 
       // File only applicable for MBTiles type
       // Directory for all other types
-      sensitive = ( 23 == vlpd.u);
+      sensitive = ( MAP_ID_MBTILES == vlpd.u);
       GtkWidget *w5 = ww1[PARAM_FILE];
       GtkWidget *w6 = ww2[PARAM_FILE];
       GtkWidget *w7 = ww1[PARAM_CACHE_DIR];
@@ -776,7 +817,7 @@ static void maps_layer_post_read (VikLayer *vl, VikViewport *vp, gboolean from_f
   VikMapsLayer *vml = VIK_MAPS_LAYER(vl);
   VikMapSource *map = MAPS_LAYER_NTH_TYPE(vml->maptype);
 
-  if (from_file != TRUE)
+  if (!from_file)
   {
     /* If this method is not called in file reading context
      * it is called in GUI context.
@@ -813,10 +854,12 @@ static void maps_layer_post_read (VikLayer *vl, VikViewport *vp, gboolean from_f
 #endif
 
   // If the on Disk OSM Tile Layout type
-  if ( vml->maptype == 21 )
+  if ( vik_map_source_get_uniq_id(map) == MAP_ID_OSM_ON_DISK ) {
     // Copy the directory into filename
     //  thus the mapcache look up will be unique when using more than one of these map types
+    g_free ( vml->filename );
     vml->filename = g_strdup (vml->cache_dir);
+  }
 }
 
 static const gchar* maps_layer_tooltip ( VikMapsLayer *vml )
@@ -833,6 +876,7 @@ static VikMapsLayer *maps_layer_unmarshall( guint8 *data, gint len, VikViewport
 {
   VikMapsLayer *rv = maps_layer_new ( vvp );
   vik_layer_unmarshall_params ( VIK_LAYER(rv), data, len, vvp );
+  maps_layer_post_read ( VIK_LAYER(rv), vvp, FALSE );
   return rv;
 }
 
@@ -904,7 +948,7 @@ static GdkPixbuf *get_pixbuf_sql_exec ( sqlite3 *sql, gint xx, gint yy, gint zoo
             GInputStream *stream = g_memory_input_stream_new_from_data ( data, bytes, NULL );
             GError *error = NULL;
             pixbuf = gdk_pixbuf_new_from_stream ( stream, NULL, &error );
-            if (error || (!pixbuf)) {
+            if ( error ) {
               g_warning ( "%s: %s", __FUNCTION__, error->message );
               g_error_free ( error );
             }
@@ -923,7 +967,7 @@ static GdkPixbuf *get_pixbuf_sql_exec ( sqlite3 *sql, gint xx, gint yy, gint zoo
        break;
     }
   }
-  ans = sqlite3_finalize ( sql_stmt );
+  (void)sqlite3_finalize ( sql_stmt );
   
   g_free ( statement );
 
@@ -966,7 +1010,7 @@ static GdkPixbuf *get_pixbuf_from_metatile ( VikMapsLayer *vml, gint xx, gint yy
   int len;
   int compressed;
 
-  buf = malloc(tile_max);
+  buf = g_malloc(tile_max);
   if (!buf) {
       return NULL;
   }
@@ -978,6 +1022,7 @@ static GdkPixbuf *get_pixbuf_from_metatile ( VikMapsLayer *vml, gint xx, gint yy
     if (compressed) {
       // Not handled yet - I don't think this is used often - so implement later if necessary
       g_warning ( "Compressed metatiles not implemented:%s\n", __FUNCTION__);
+      g_free(buf);
       return NULL;
     }
 
@@ -987,22 +1032,26 @@ static GdkPixbuf *get_pixbuf_from_metatile ( VikMapsLayer *vml, gint xx, gint yy
     GInputStream *stream = g_memory_input_stream_new_from_data ( buf, len, NULL );
     GError *error = NULL;
     pixbuf = gdk_pixbuf_new_from_stream ( stream, NULL, &error );
-    if (error || (!pixbuf)) {
+    if (error) {
       g_warning ( "%s: %s", __FUNCTION__, error->message );
       g_error_free ( error );
     }
     g_input_stream_close ( stream, NULL, NULL );
 
-    free(buf);
+    g_free(buf);
     return pixbuf;
   }
   else {
+    g_free(buf);
     g_warning ( "FAILED:%s %s", __FUNCTION__, err_msg);
     return NULL;
   }
 }
 
-
+/**
+ * Caller has to decrease reference counter of returned
+ * GdkPixbuf, when buffer is no longer needed.
+ */
 static GdkPixbuf *pixbuf_apply_settings ( GdkPixbuf *pixbuf, VikMapsLayer *vml, MapCoord *mapcoord, gdouble xshrinkfactor, gdouble yshrinkfactor )
 {
   // Apply alpha setting
@@ -1013,7 +1062,7 @@ static GdkPixbuf *pixbuf_apply_settings ( GdkPixbuf *pixbuf, VikMapsLayer *vml,
     pixbuf = pixbuf_shrink ( pixbuf, xshrinkfactor, yshrinkfactor );
 
   if ( pixbuf )
-    a_mapcache_add ( pixbuf, mapcoord->x, mapcoord->y,
+    a_mapcache_add ( pixbuf, (mapcache_extra_t) {0.0}, mapcoord->x, mapcoord->y,
                      mapcoord->z, vik_map_source_get_uniq_id(MAPS_LAYER_NTH_TYPE(vml->maptype)),
                      mapcoord->scale, vml->alpha, xshrinkfactor, yshrinkfactor, vml->filename );
 
@@ -1051,6 +1100,10 @@ static void get_filename ( const gchar *cache_dir,
   }
 }
 
+/**
+ * Caller has to decrease reference counter of returned
+ * GdkPixbuf, when buffer is no longer needed.
+ */
 static GdkPixbuf *get_pixbuf( VikMapsLayer *vml, guint16 id, const gchar* mapname, MapCoord *mapcoord, gchar *filename_buf, gint buf_len, gdouble xshrinkfactor, gdouble yshrinkfactor )
 {
   GdkPixbuf *pixbuf;
@@ -1169,6 +1222,7 @@ gboolean try_draw_scale_down (VikMapsLayer *vml, VikViewport *vvp, MapCoord ulm,
       gint src_x = (ulm.x % scale_factor) * tilesize_x_ceil;
       gint src_y = (ulm.y % scale_factor) * tilesize_y_ceil;
       vik_viewport_draw_pixbuf ( vvp, pixbuf, src_x, src_y, xx, yy, tilesize_x_ceil, tilesize_y_ceil );
+      g_object_unref(pixbuf);
       return TRUE;
     }
   }
@@ -1203,6 +1257,7 @@ gboolean try_draw_scale_up (VikMapsLayer *vml, VikViewport *vvp, MapCoord ulm, g
           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 );
+          g_object_unref(pixbuf);
           return TRUE;
         }
       }
@@ -1296,6 +1351,7 @@ static void maps_layer_draw_section ( VikMapsLayer *vml, VikViewport *vvp, VikCo
             yy -= (height/2);
 
             vik_viewport_draw_pixbuf ( vvp, pixbuf, 0, 0, xx, yy, width, height );
+            g_object_unref(pixbuf);
           }
         }
       }
@@ -1347,6 +1403,7 @@ static void maps_layer_draw_section ( VikMapsLayer *vml, VikViewport *vvp, VikCo
               gint src_x = (ulm.x % scale_factor) * tilesize_x_ceil;
               gint src_y = (ulm.y % scale_factor) * tilesize_y_ceil;
               vik_viewport_draw_pixbuf ( vvp, pixbuf, src_x, src_y, xx, yy, tilesize_x_ceil, tilesize_y_ceil );
+              g_object_unref(pixbuf);
             }
             else {
               // Otherwise try different scales
@@ -1540,7 +1597,8 @@ static int map_download_thread ( MapDownloadInfo *mdi, gpointer threaddata )
               GError *gx = NULL;
               GdkPixbuf *pixbuf = gdk_pixbuf_new_from_file ( mdi->filename_buf, &gx );
               if (gx || (!pixbuf)) {
-                g_remove ( mdi->filename_buf );
+                if ( g_remove ( mdi->filename_buf ) )
+                  g_warning ( "REDOWNLOAD failed to remove: %s", mdi->filename_buf );
                 need_download = TRUE;
                 remove_mem_cache = TRUE;
                 g_error_free ( gx );
@@ -1558,7 +1616,8 @@ static int map_download_thread ( MapDownloadInfo *mdi, gpointer threaddata )
 
             case REDOWNLOAD_ALL:
               /* FIXME: need a better way than to erase file in case of server/network problem */
-              g_remove ( mdi->filename_buf );
+              if ( g_remove ( mdi->filename_buf ) )
+                g_warning ( "REDOWNLOAD failed to remove: %s", mdi->filename_buf );
               need_download = TRUE;
               remove_mem_cache = TRUE;
               break;
@@ -1600,7 +1659,7 @@ static int map_download_thread ( MapDownloadInfo *mdi, gpointer threaddata )
 
         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 );
+            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, mdi->vml->filename );
         if (mdi->refresh_display && mdi->map_layer_alive) {
           /* TODO: check if it's on visible area */
           vik_layer_emit_update ( VIK_LAYER(mdi->vml) ); // NB update display from background
@@ -1629,7 +1688,8 @@ static void mdi_cancel_cleanup ( MapDownloadInfo *mdi )
                    vik_map_source_get_file_extension(MAPS_LAYER_NTH_TYPE(mdi->maptype)) );
     if ( g_file_test ( mdi->filename_buf, G_FILE_TEST_EXISTS ) == TRUE)
     {
-      g_remove ( mdi->filename_buf );
+      if ( g_remove ( mdi->filename_buf ) )
+        g_warning ( "Cleanup failed to remove: %s", mdi->filename_buf );
     }
   }
 }
@@ -1723,7 +1783,8 @@ static void start_download_thread ( VikMapsLayer *vml, VikViewport *vvp, const V
  
       g_object_weak_ref(G_OBJECT(mdi->vml), weak_ref_cb, mdi);
       /* launch the thread */
-      a_background_thread ( VIK_GTK_WINDOW_FROM_LAYER(vml), /* parent window */
+      a_background_thread ( BACKGROUND_POOL_REMOTE,
+                            VIK_GTK_WINDOW_FROM_LAYER(vml), /* parent window */
                             tmp,                                              /* description string */
                             (vik_thr_func) map_download_thread,               /* function to call within thread */
                             mdi,                                              /* pass along data */
@@ -1807,14 +1868,16 @@ static void maps_layer_download_section ( VikMapsLayer *vml, VikViewport *vvp, V
     tmp = g_strdup_printf ( fmt, mdi->mapstoget, MAPS_LAYER_NTH_LABEL(vml->maptype) );
 
     g_object_weak_ref(G_OBJECT(mdi->vml), weak_ref_cb, mdi);
-      /* launch the thread */
-    a_background_thread ( VIK_GTK_WINDOW_FROM_LAYER(vml), /* parent window */
-      tmp,                                /* description string */
-      (vik_thr_func) map_download_thread, /* function to call within thread */
-      mdi,                                /* pass along data */
-      (vik_thr_free_func) mdi_free,       /* function to free pass along data */
-      (vik_thr_free_func) mdi_cancel_cleanup,
-      mdi->mapstoget );
+
+    // launch the thread
+    a_background_thread ( BACKGROUND_POOL_REMOTE,
+                          VIK_GTK_WINDOW_FROM_LAYER(vml), /* parent window */
+                          tmp,                                /* description string */
+                          (vik_thr_func) map_download_thread, /* function to call within thread */
+                          mdi,                                /* pass along data */
+                          (vik_thr_free_func) mdi_free,       /* function to free pass along data */
+                          (vik_thr_free_func) mdi_cancel_cleanup,
+                          mdi->mapstoget );
     g_free ( tmp );
   }
   else
@@ -1851,6 +1914,10 @@ static void maps_layer_redownload_new ( VikMapsLayer *vml )
   start_download_thread ( vml, vml->redownload_vvp, &(vml->redownload_ul), &(vml->redownload_br), REDOWNLOAD_NEW );
 }
 
+#if !GLIB_CHECK_VERSION(2,26,0)
+typedef struct stat GStatBuf;
+#endif
+
 /**
  * Display a simple dialog with information about this particular map tile
  */
@@ -1866,7 +1933,6 @@ static void maps_layer_tile_info ( VikMapsLayer *vml )
     return;
 
   gchar *filename = NULL;
-  gchar *message = NULL;
   gchar *source = NULL;
 
   if ( vik_map_source_is_direct_file_access ( map ) ) {
@@ -1890,10 +1956,10 @@ static void maps_layer_tile_info ( VikMapsLayer *vml )
         exists = g_strdup ( _("NO") );
       gint flip_y = (gint) pow(2, zoom)-1 - ulm.y;
       // NB Also handles .jpg automatically due to pixbuf_new_from () support - although just print png for now.
-      source = g_strdup_printf ( "%s (%d%s%d%s%d.%s %s)", filename, zoom, G_DIR_SEPARATOR_S, ulm.x, G_DIR_SEPARATOR_S, flip_y, "png", exists );
+      source = g_strdup_printf ( "Source: %s (%d%s%d%s%d.%s %s)", filename, zoom, G_DIR_SEPARATOR_S, ulm.x, G_DIR_SEPARATOR_S, flip_y, "png", exists );
       g_free ( exists );
 #else
-      source = g_strdup ( _("Not available") );
+      source = g_strdup ( _("Source: Not available") );
 #endif
     }
     else if ( vik_map_source_is_osm_meta_tiles ( map ) ) {
@@ -1910,7 +1976,7 @@ static void maps_layer_tile_info ( VikMapsLayer *vml )
                      NULL,
                      ulm.scale, ulm.z, ulm.x, ulm.y, filename, max_path_len,
                      vik_map_source_get_file_extension(map) );
-      source = g_strconcat ( "file://", filename, NULL );
+      source = g_strconcat ( "Source: file://", filename, NULL );
     }
   }
   else {
@@ -1921,32 +1987,42 @@ static void maps_layer_tile_info ( VikMapsLayer *vml )
                    vik_map_source_get_name(map),
                    ulm.scale, ulm.z, ulm.x, ulm.y, filename, max_path_len,
                    vik_map_source_get_file_extension(map) );
-    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 ) );
+    source = g_markup_printf_escaped ( "Source: 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 ) ) {
+  GArray *array = g_array_new (FALSE, TRUE, sizeof(gchar*));
+  g_array_append_val ( array, source );
+
+  gchar *filemsg = NULL;
+  gchar *timemsg = NULL;
 
+  if ( g_file_test ( filename, G_FILE_TEST_EXISTS ) ) {
+    filemsg = g_strconcat ( "Tile File: ", filename, NULL );
     // Get some timestamp information of the tile
-    struct stat stat_buf;
+    GStatBuf stat_buf;
     if ( g_stat ( filename, &stat_buf ) == 0 ) {
       gchar time_buf[64];
       strftime ( time_buf, sizeof(time_buf), "%c", gmtime((const time_t *)&stat_buf.st_mtime) );
-      message = g_strdup_printf ( _("\nSource: %s\n\nTile File: %s\nTile File Timestamp: %s"), source, filename, time_buf );
+      timemsg = g_strdup_printf ( _("Tile File Timestamp: %s"), time_buf );
     }
     else {
-      message = g_strdup_printf ( _("\nSource: %s\n\nTile File: %s\nTile File Timestamp: Not Available"), source, filename );
+      timemsg = g_strdup ( _("Tile File Timestamp: Not Available") );
     }
-    // Show the info
-    a_dialog_info_msg (  VIK_GTK_WINDOW_FROM_LAYER(vml), message );
+    g_array_append_val ( array, filemsg );
+    g_array_append_val ( array, timemsg );
   }
   else {
-    message = g_strdup_printf ( _("\nSource: %s\n\nTile File: %s [Not Available]"), source, filename );
-    a_dialog_warning_msg (  VIK_GTK_WINDOW_FROM_LAYER(vml), message );
+    filemsg = g_strdup_printf ( "Tile File: %s [Not Available]", filename );
+    g_array_append_val ( array, filemsg );
   }
 
-  g_free ( message );
+  a_dialog_list (  VIK_GTK_WINDOW_FROM_LAYER(vml), _("Tile Information"), array, 5 );
+  g_array_free ( array, FALSE );
+
+  g_free ( timemsg );
+  g_free ( filemsg );
   g_free ( source );
   g_free ( filename );
 }
@@ -2363,6 +2439,15 @@ static void maps_layer_download_all ( menu_array_values values )
   }
 }
 
+/**
+ *
+ */
+static void maps_layer_flush ( menu_array_values values )
+{
+  VikMapsLayer *vml = VIK_MAPS_LAYER(values[MA_VML]);
+  a_mapcache_flush_type ( vik_map_source_get_uniq_id(MAPS_LAYER_NTH_TYPE(vml->maptype)) );
+}
+
 static void maps_layer_add_menu_items ( VikMapsLayer *vml, GtkMenu *menu, VikLayersPanel *vlp )
 {
   GtkWidget *item;
@@ -2405,6 +2490,15 @@ static void maps_layer_add_menu_items ( VikMapsLayer *vml, GtkMenu *menu, VikLay
   g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(maps_layer_about), values );
   gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
   gtk_widget_show ( item );
+
+  // Typical users shouldn't need to use this functionality - so debug only ATM
+  if ( vik_debug ) {
+    item = gtk_image_menu_item_new_with_mnemonic ( _("Flush Map Cache") );
+    gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_REMOVE, GTK_ICON_SIZE_MENU) );
+    g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(maps_layer_flush), values );
+    gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
+    gtk_widget_show ( item );
+  }
 }
 
 /**