]> git.street.me.uk Git - andy/viking.git/blobdiff - src/viktrwlayer.c
Make more text translatable
[andy/viking.git] / src / viktrwlayer.c
index 80ecd7459c9e6ffb8e4bda7530a0032ef89790ff..7a1aab78bd19a521df524b0396352081b054fc62 100644 (file)
@@ -5,7 +5,7 @@
  * Copyright (C) 2005-2008, Alex Foobarian <foobarian@gmail.com>
  * Copyright (C) 2007, Quy Tonthat <qtonthat@gmail.com>
  * Copyright (C) 2009, Hein Ragas <viking@ragas.nl>
- * Copyright (c) 2012, Rob Norris <rw_norris@hotmail.com>
+ * Copyright (c) 2012-2015, Rob Norris <rw_norris@hotmail.com>
  * Copyright (c) 2012-2013, Guilhem Bonnefille <guilhem.bonnefille@gmail.com>
  *
  * This program is free software; you can redistribute it and/or modify
@@ -33,7 +33,9 @@
 #include "viking.h"
 #include "vikmapslayer.h"
 #include "vikgpslayer.h"
+#include "viktrwlayer_export.h"
 #include "viktrwlayer_tpwin.h"
+#include "viktrwlayer_wpwin.h"
 #include "viktrwlayer_propwin.h"
 #include "viktrwlayer_analysis.h"
 #include "viktrwlayer_tracklist.h"
@@ -46,6 +48,7 @@
 #include "thumbnails.h"
 #include "background.h"
 #include "gpx.h"
+#include "geojson.h"
 #include "babel.h"
 #include "dem.h"
 #include "dems.h"
@@ -56,8 +59,9 @@
 #include "acquire.h"
 #include "datasources.h"
 #include "datasource_gps.h"
+#include "vikexttools.h"
 #include "vikexttool_datasources.h"
-#include "util.h"
+#include "ui_util.h"
 #include "vikutils.h"
 
 #include "vikrouting.h"
@@ -176,7 +180,6 @@ struct _VikTrwLayer {
   GdkGC *waypoint_text_gc; GdkColor waypoint_text_color;
   GdkGC *waypoint_bg_gc; GdkColor waypoint_bg_color;
   gboolean wpbgand;
-  GdkFont *waypoint_font;
   VikTrack *current_track; // ATM shared between new tracks and new routes
   guint16 ct_x1, ct_y1, ct_x2, ct_y2;
   gboolean draw_sync_done;
@@ -201,10 +204,8 @@ struct _VikTrwLayer {
 
   /* route finder tool */
   gboolean route_finder_started;
-  VikCoord route_finder_coord;
   gboolean route_finder_check_added_track;
   VikTrack *route_finder_added_track;
-  VikTrack *route_finder_current_track;
   gboolean route_finder_append;
 
   gboolean drawlabels;
@@ -249,6 +250,7 @@ struct DrawingParams {
   gboolean one_zone, lat_lon;
   gdouble ce1, ce2, cn1, cn2;
   LatLonBBox bbox;
+  gboolean highlight;
 };
 
 static gboolean trw_layer_delete_waypoint ( VikTrwLayer *vtl, VikWaypoint *wp );
@@ -307,7 +309,6 @@ static void trw_layer_gps_upload_any ( menu_array_sublayer values );
 
 static void trw_layer_centerize ( menu_array_layer values );
 static void trw_layer_auto_view ( menu_array_layer values );
-static void trw_layer_export ( menu_array_layer values, const gchar* title, const gchar* default_name, VikTrack* trk, guint file_type );
 static void trw_layer_goto_wp ( menu_array_layer values );
 static void trw_layer_new_wp ( menu_array_layer values );
 static void trw_layer_new_track ( menu_array_layer values );
@@ -362,13 +363,14 @@ static void trw_layer_waypoint_webpage ( menu_array_sublayer values );
 
 static void trw_layer_realize_waypoint ( gpointer id, VikWaypoint *wp, gpointer pass_along[5] );
 static void trw_layer_realize_track ( gpointer id, VikTrack *track, gpointer pass_along[5] );
-static void init_drawing_params ( struct DrawingParams *dp, VikTrwLayer *vtl, VikViewport *vp );
 
 static void trw_layer_insert_tp_beside_current_tp ( VikTrwLayer *vtl, gboolean );
 static void trw_layer_cancel_current_tp ( VikTrwLayer *vtl, gboolean destroy );
 static void trw_layer_tpwin_response ( VikTrwLayer *vtl, gint response );
 static void trw_layer_tpwin_init ( VikTrwLayer *vtl );
 
+static void trw_layer_sort_all ( VikTrwLayer *vtl );
+
 static gpointer tool_edit_trackpoint_create ( VikWindow *vw, VikViewport *vvp);
 static void tool_edit_trackpoint_destroy ( tool_ed_t *t );
 static gboolean tool_edit_trackpoint_click ( VikTrwLayer *vtl, GdkEventButton *event, gpointer data );
@@ -390,8 +392,9 @@ static void tool_new_track_release ( VikTrwLayer *vtl, GdkEventButton *event, Vi
 static gboolean tool_new_track_key_press ( VikTrwLayer *vtl, GdkEventKey *event, VikViewport *vvp ); 
 static gpointer tool_new_waypoint_create ( VikWindow *vw, VikViewport *vvp);
 static gboolean tool_new_waypoint_click ( VikTrwLayer *vtl, GdkEventButton *event, VikViewport *vvp );
-static gpointer tool_route_finder_create ( VikWindow *vw, VikViewport *vvp);
-static gboolean tool_route_finder_click ( VikTrwLayer *vtl, GdkEventButton *event, VikViewport *vvp );
+static gpointer tool_extended_route_finder_create ( VikWindow *vw, VikViewport *vvp);
+static gboolean tool_extended_route_finder_click ( VikTrwLayer *vtl, GdkEventButton *event, VikViewport *vvp );
+static gboolean tool_extended_route_finder_key_press ( VikTrwLayer *vtl, GdkEventKey *event, VikViewport *vvp );
 
 static void cached_pixbuf_free ( CachedPixbuf *cp );
 static gint cached_pixbuf_cmp ( CachedPixbuf *cp, const gchar *name );
@@ -418,7 +421,7 @@ static VikToolInterface trw_layer_tools[] = {
     (VikToolConstructorFunc) tool_new_waypoint_create,    NULL, NULL, NULL,
     (VikToolMouseFunc) tool_new_waypoint_click,    NULL, NULL, (VikToolKeyFunc) NULL,
     FALSE,
-    GDK_CURSOR_IS_PIXMAP, &cursor_addwp_pixbuf },
+    GDK_CURSOR_IS_PIXMAP, &cursor_addwp_pixbuf, NULL },
 
   { { "CreateTrack", "vik-icon-Create Track", N_("Create _Track"), "<control><shift>T", N_("Create Track"), 0 },
     (VikToolConstructorFunc) tool_new_track_create,       NULL, NULL, NULL,
@@ -427,7 +430,7 @@ static VikToolInterface trw_layer_tools[] = {
     (VikToolMouseFunc) tool_new_track_release,
     (VikToolKeyFunc) tool_new_track_key_press,
     TRUE, // Still need to handle clicks when in PAN mode to disable the potential trackpoint drawing
-    GDK_CURSOR_IS_PIXMAP, &cursor_addtr_pixbuf },
+    GDK_CURSOR_IS_PIXMAP, &cursor_addtr_pixbuf, NULL },
 
   { { "CreateRoute", "vik-icon-Create Route", N_("Create _Route"), "<control><shift>B", N_("Create Route"), 0 },
     (VikToolConstructorFunc) tool_new_route_create,       NULL, NULL, NULL,
@@ -436,7 +439,16 @@ static VikToolInterface trw_layer_tools[] = {
     (VikToolMouseFunc) tool_new_track_release,  //   -> Reuse these track methods on a route
     (VikToolKeyFunc) tool_new_track_key_press,  // -/#
     TRUE, // Still need to handle clicks when in PAN mode to disable the potential trackpoint drawing
-    GDK_CURSOR_IS_PIXMAP, &cursor_new_route_pixbuf },
+    GDK_CURSOR_IS_PIXMAP, &cursor_new_route_pixbuf, NULL },
+
+  { { "ExtendedRouteFinder", "vik-icon-Route Finder", N_("Route _Finder"), "<control><shift>F", N_("Route Finder"), 0 },
+    (VikToolConstructorFunc) tool_extended_route_finder_create,  NULL, NULL, NULL,
+    (VikToolMouseFunc) tool_extended_route_finder_click,
+    (VikToolMouseMoveFunc) tool_new_track_move, // -\#
+    (VikToolMouseFunc) tool_new_track_release,  //   -> Reuse these track methods on a route
+    (VikToolKeyFunc) tool_extended_route_finder_key_press,
+    TRUE, // Still need to handle clicks when in PAN mode to disable the potential trackpoint drawing
+    GDK_CURSOR_IS_PIXMAP, &cursor_route_finder_pixbuf, NULL },
 
   { { "EditWaypoint", "vik-icon-Edit Waypoint", N_("_Edit Waypoint"), "<control><shift>E", N_("Edit Waypoint"), 0 },
     (VikToolConstructorFunc) tool_edit_waypoint_create,
@@ -446,7 +458,7 @@ static VikToolInterface trw_layer_tools[] = {
     (VikToolMouseMoveFunc) tool_edit_waypoint_move,
     (VikToolMouseFunc) tool_edit_waypoint_release, (VikToolKeyFunc) NULL,
     FALSE,
-    GDK_CURSOR_IS_PIXMAP, &cursor_edwp_pixbuf },
+    GDK_CURSOR_IS_PIXMAP, &cursor_edwp_pixbuf, NULL },
 
   { { "EditTrackpoint", "vik-icon-Edit Trackpoint", N_("Edit Trac_kpoint"), "<control><shift>K", N_("Edit Trackpoint"), 0 },
     (VikToolConstructorFunc) tool_edit_trackpoint_create,
@@ -456,29 +468,24 @@ static VikToolInterface trw_layer_tools[] = {
     (VikToolMouseMoveFunc) tool_edit_trackpoint_move,
     (VikToolMouseFunc) tool_edit_trackpoint_release, (VikToolKeyFunc) NULL,
     FALSE,
-    GDK_CURSOR_IS_PIXMAP, &cursor_edtr_pixbuf },
+    GDK_CURSOR_IS_PIXMAP, &cursor_edtr_pixbuf, NULL },
 
   { { "ShowPicture", "vik-icon-Show Picture", N_("Show P_icture"), "<control><shift>I", N_("Show Picture"), 0 },
     (VikToolConstructorFunc) tool_show_picture_create,    NULL, NULL, NULL,
     (VikToolMouseFunc) tool_show_picture_click,    NULL, NULL, (VikToolKeyFunc) NULL,
     FALSE,
-    GDK_CURSOR_IS_PIXMAP, &cursor_showpic_pixbuf },
+    GDK_CURSOR_IS_PIXMAP, &cursor_showpic_pixbuf, NULL },
 
-  { { "RouteFinder", "vik-icon-Route Finder", N_("Route _Finder"), "<control><shift>F", N_("Route Finder"), 0 },
-    (VikToolConstructorFunc) tool_route_finder_create,  NULL, NULL, NULL,
-    (VikToolMouseFunc) tool_route_finder_click, NULL, NULL, (VikToolKeyFunc) NULL,
-    FALSE,
-    GDK_CURSOR_IS_PIXMAP, &cursor_route_finder_pixbuf },
 };
 
 enum {
   TOOL_CREATE_WAYPOINT=0,
   TOOL_CREATE_TRACK,
   TOOL_CREATE_ROUTE,
+  TOOL_ROUTE_FINDER,
   TOOL_EDIT_WAYPOINT,
   TOOL_EDIT_TRACKPOINT,
   TOOL_SHOW_PICTURE,
-  TOOL_ROUTE_FINDER,
   NUM_TOOLS
 };
 
@@ -528,6 +535,8 @@ static gchar* params_sort_order[] = {
   N_("None"),
   N_("Name Ascending"),
   N_("Name Descending"),
+  N_("Date Ascending"),
+  N_("Date Descending"),
   NULL
 };
 
@@ -684,6 +693,7 @@ static void trw_layer_post_read ( VikTrwLayer *vtl, GtkWidget *vvp, gboolean fro
 static void trw_layer_free ( VikTrwLayer *trwlayer );
 static void trw_layer_draw ( VikTrwLayer *l, gpointer data );
 static void trw_layer_change_coord_mode ( VikTrwLayer *vtl, VikCoordMode dest_mode );
+static time_t trw_layer_get_timestamp ( VikTrwLayer *vtl );
 static void trw_layer_set_menu_selection ( VikTrwLayer *vtl, guint16 );
 static guint16 trw_layer_get_menu_selection ( VikTrwLayer *vtl );
 static void trw_layer_add_menu_items ( VikTrwLayer *vtl, GtkMenu *menu, gpointer vlp );
@@ -705,7 +715,7 @@ static gboolean trw_layer_paste_item ( VikTrwLayer *vtl, gint subtype, guint8 *i
 static void trw_layer_free_copied_item ( gint subtype, gpointer item );
 static void trw_layer_drag_drop_request ( VikTrwLayer *vtl_src, VikTrwLayer *vtl_dest, GtkTreeIter *src_item_iter, GtkTreePath *dest_path );
 static gboolean trw_layer_select_click ( VikTrwLayer *vtl, GdkEventButton *event, VikViewport *vvp, tool_ed_t *t );
-static gboolean trw_layer_select_move ( VikTrwLayer *vtl, GdkEventButton *event, VikViewport *vvp, tool_ed_t *t );
+static gboolean trw_layer_select_move ( VikTrwLayer *vtl, GdkEventMotion *event, VikViewport *vvp, tool_ed_t *t );
 static gboolean trw_layer_select_release ( VikTrwLayer *vtl, GdkEventButton *event, VikViewport *vvp, tool_ed_t *t );
 static gboolean trw_layer_show_selected_viewport_menu ( VikTrwLayer *vtl, GdkEventButton *event, VikViewport *vvp );
 /* End Layer Interface function definitions */
@@ -734,6 +744,7 @@ VikLayerInterface vik_trw_layer_interface = {
   (VikLayerFuncProperties)              NULL,
   (VikLayerFuncDraw)                    trw_layer_draw,
   (VikLayerFuncChangeCoordMode)         trw_layer_change_coord_mode,
+  (VikLayerFuncGetTimestamp)            trw_layer_get_timestamp,
 
   (VikLayerFuncSetMenuItemsSelection)   trw_layer_set_menu_selection,
   (VikLayerFuncGetMenuItemsSelection)   trw_layer_get_menu_selection,
@@ -771,6 +782,91 @@ VikLayerInterface vik_trw_layer_interface = {
   (VikLayerFuncSelectedViewportMenu)    trw_layer_show_selected_viewport_menu,
 };
 
+static gboolean have_diary_program = FALSE;
+static gchar *diary_program = NULL;
+#define VIK_SETTINGS_EXTERNAL_DIARY_PROGRAM "external_diary_program"
+
+static gboolean have_geojson_export = FALSE;
+
+static gboolean have_astro_program = FALSE;
+static gchar *astro_program = NULL;
+#define VIK_SETTINGS_EXTERNAL_ASTRO_PROGRAM "external_astro_program"
+
+// NB Only performed once per program run
+static void vik_trwlayer_class_init ( VikTrwLayerClass *klass )
+{
+  if ( ! a_settings_get_string ( VIK_SETTINGS_EXTERNAL_DIARY_PROGRAM, &diary_program ) ) {
+#ifdef WINDOWS
+    //diary_program = g_strdup ( "C:\\Program Files\\Rednotebook\\rednotebook.exe" );
+    diary_program = g_strdup ( "C:/Progra~1/Rednotebook/rednotebook.exe" );
+#else
+    diary_program = g_strdup ( "rednotebook" );
+#endif
+  }
+  else {
+    // User specified so assume it works
+    have_diary_program = TRUE;
+  }
+
+  if ( g_find_program_in_path( diary_program ) ) {
+    gchar *mystdout = NULL;
+    gchar *mystderr = NULL;
+    // Needs RedNotebook 1.7.3+ for support of opening on a specified date
+    gchar *cmd = g_strconcat ( diary_program, " --version", NULL ); // "rednotebook --version"
+    if ( g_spawn_command_line_sync ( cmd, &mystdout, &mystderr, NULL, NULL ) ) {
+      // Annoyingly 1.7.1|2|3 versions of RedNotebook prints the version to stderr!!
+      if ( mystdout )
+        g_debug ("Diary: %s", mystdout ); // Should be something like 'RedNotebook 1.4'
+      if ( mystderr )
+        g_warning ("Diary: stderr: %s", mystderr );
+
+      gchar **tokens = NULL;
+      if ( mystdout && g_strcmp0(mystdout, "") )
+        tokens = g_strsplit(mystdout, " ", 0);
+      else if ( mystderr )
+        tokens = g_strsplit(mystderr, " ", 0);
+
+      if ( tokens ) {
+        gint num = 0;
+        gchar *token = tokens[num];
+        while ( token && num < 2 ) {
+          if (num == 1) {
+            if ( viking_version_to_number(token) >= viking_version_to_number("1.7.3") )
+              have_diary_program = TRUE;
+          }
+          num++;
+          token = tokens[num];
+        }
+      }
+      g_strfreev ( tokens );
+    }
+    g_free ( mystdout );
+    g_free ( mystderr );
+    g_free ( cmd );
+  }
+
+  if ( g_find_program_in_path ( a_geojson_program_export() ) ) {
+    have_geojson_export = TRUE;
+  }
+
+  // Astronomy Domain
+  if ( ! a_settings_get_string ( VIK_SETTINGS_EXTERNAL_ASTRO_PROGRAM, &astro_program ) ) {
+#ifdef WINDOWS
+    //astro_program = g_strdup ( "C:\\Program Files\\Stellarium\\stellarium.exe" );
+    astro_program = g_strdup ( "C:/Progra~1/Stellarium/stellarium.exe" );
+#else
+    astro_program = g_strdup ( "stellarium" );
+#endif
+  }
+  else {
+    // User specified so assume it works
+    have_astro_program = TRUE;
+  }
+  if ( g_find_program_in_path( astro_program ) ) {
+    have_astro_program = TRUE;
+  }
+}
+
 GType vik_trw_layer_get_type ()
 {
   static GType vtl_type = 0;
@@ -782,7 +878,7 @@ GType vik_trw_layer_get_type ()
       sizeof (VikTrwLayerClass),
       NULL, /* base_init */
       NULL, /* base_finalize */
-      NULL, /* class init */
+      (GClassInitFunc) vik_trwlayer_class_init, /* class init */
       NULL, /* class_finalize */
       NULL, /* class_data */
       sizeof (VikTrwLayer),
@@ -791,7 +887,6 @@ GType vik_trw_layer_get_type ()
     };
     vtl_type = g_type_register_static ( VIK_LAYER_TYPE, "VikTrwLayer", &vtl_info, 0 );
   }
-
   return vtl_type;
 }
 
@@ -822,8 +917,8 @@ typedef struct {
   const gchar *date_str;
   const VikTrack *trk;
   const VikWaypoint *wpt;
-  gpointer *trk_id;
-  gpointer *wpt_id;
+  gpointer trk_id;
+  gpointer wpt_id;
 } date_finder_type;
 
 static gboolean trw_layer_find_date_track ( const gpointer id, const VikTrack *trk, date_finder_type *df )
@@ -884,7 +979,7 @@ gboolean vik_trw_layer_find_date ( VikTrwLayer *vtl, const gchar *date_str, VikC
       vik_treeview_select_iter ( VIK_LAYER(vtl)->vt, g_hash_table_lookup (vtl->tracks_iters, df.trk_id), TRUE );
     }
     else if ( df.wpt ) {
-      vik_viewport_set_center_coord ( vvp, &(df.wpt->coord) );
+      vik_viewport_set_center_coord ( vvp, &(df.wpt->coord), TRUE );
       vik_treeview_select_iter ( VIK_LAYER(vtl)->vt, g_hash_table_lookup (vtl->waypoints_iters, df.wpt_id), TRUE );
     }
     vik_layer_emit_update ( VIK_LAYER(vtl) );
@@ -935,7 +1030,7 @@ static void trw_layer_copy_item_cb ( menu_array_sublayer values)
 {
   VikTrwLayer *vtl = VIK_TRW_LAYER(values[MA_VTL]);
   gint subtype = GPOINTER_TO_INT (values[MA_SUBTYPE]);
-  gpointer sublayer = values[MA_SUBLAYER_ID];
+  gpointer sublayer = values[MA_SUBLAYER_ID];
   guint8 *data = NULL;
   guint len;
 
@@ -1078,6 +1173,12 @@ static void trw_layer_free_copied_item ( gint subtype, gpointer item )
   }
 }
 
+static void image_cache_free ( VikTrwLayer *vtl )
+{
+  g_list_foreach ( vtl->image_cache->head, (GFunc)cached_pixbuf_free, NULL );
+  g_queue_free ( vtl->image_cache );
+}
+
 static gboolean trw_layer_set_param ( VikTrwLayer *vtl, guint16 id, VikLayerParamData data, VikViewport *vp, gboolean is_file_operation )
 {
   switch ( id )
@@ -1149,12 +1250,17 @@ static gboolean trw_layer_set_param ( VikTrwLayer *vtl, guint16 id, VikLayerPara
     case PARAM_IS: if ( data.u != vtl->image_size )
       {
         vtl->image_size = data.u;
-        g_list_foreach ( vtl->image_cache->head, (GFunc) cached_pixbuf_free, NULL );
-        g_queue_free ( vtl->image_cache );
+        image_cache_free ( vtl );
+        vtl->image_cache = g_queue_new ();
+      }
+      break;
+    case PARAM_IA: if ( data.u != vtl->image_alpha )
+      {
+        vtl->image_alpha = data.u;
+        image_cache_free ( vtl );
         vtl->image_cache = g_queue_new ();
       }
       break;
-    case PARAM_IA: vtl->image_alpha = data.u; break;
     case PARAM_ICS: vtl->image_cache_size = data.u;
       while ( vtl->image_cache->length > vtl->image_cache_size ) /* if shrinking cache_size, free pixbuf ASAP */
           cached_pixbuf_free ( g_queue_pop_tail ( vtl->image_cache ) );
@@ -1402,7 +1508,7 @@ static void trw_layer_marshall( VikTrwLayer *vtl, guint8 **data, gint *len )
 
 static VikTrwLayer *trw_layer_unmarshall( guint8 *data, gint len, VikViewport *vvp )
 {
-  VikTrwLayer *vtl = VIK_TRW_LAYER(vik_layer_create ( VIK_LAYER_TRW, vvp, NULL, FALSE ));
+  VikTrwLayer *vtl = VIK_TRW_LAYER(vik_layer_create ( VIK_LAYER_TRW, vvp, FALSE ));
   gint pl;
   gint consumed_length;
 
@@ -1431,23 +1537,27 @@ static VikTrwLayer *trw_layer_unmarshall( guint8 *data, gint len, VikViewport *v
       // Reuse pl to read the subtype from the data stream
       memcpy(&pl, data+sizeof(gint), sizeof(pl));
 
+      // Also remember to (attempt to) convert each coordinate in case this is pasted into a different drawmode
       if ( pl == VIK_TRW_LAYER_SUBLAYER_TRACK ) {
         VikTrack *trk = vik_track_unmarshall ( data + sizeof_len_and_subtype, 0 );
         gchar *name = g_strdup ( trk->name );
         vik_trw_layer_add_track ( vtl, name, trk );
         g_free ( name );
+        vik_track_convert (trk, vtl->coord_mode);
       }
       if ( pl == VIK_TRW_LAYER_SUBLAYER_WAYPOINT ) {
         VikWaypoint *wp = vik_waypoint_unmarshall ( data + sizeof_len_and_subtype, 0 );
         gchar *name = g_strdup ( wp->name );
         vik_trw_layer_add_waypoint ( vtl, name, wp );
         g_free ( name );
+        waypoint_convert (NULL, wp, &vtl->coord_mode);
       }
       if ( pl == VIK_TRW_LAYER_SUBLAYER_ROUTE ) {
         VikTrack *trk = vik_track_unmarshall ( data + sizeof_len_and_subtype, 0 );
         gchar *name = g_strdup ( trk->name );
         vik_trw_layer_add_route ( vtl, name, trk );
         g_free ( name );
+        vik_track_convert (trk, vtl->coord_mode);
       }
     }
     consumed_length += tlm_size + sizeof_len_and_subtype;
@@ -1523,6 +1633,7 @@ static VikTrwLayer* trw_layer_new1 ( VikViewport *vvp )
   rv->metadata = vik_trw_metadata_new ();
   rv->draw_sync_done = TRUE;
   rv->draw_sync_do = TRUE;
+  rv->coord_mode = VIK_COORD_LATLON;
   // Everything else is 0, FALSE or NULL
 
   return rv;
@@ -1571,14 +1682,14 @@ static void trw_layer_free ( VikTrwLayer *trwlayer )
   if ( trwlayer->tracks_analysis_dialog != NULL )
     gtk_widget_destroy ( GTK_WIDGET(trwlayer->tracks_analysis_dialog) );
 
-  g_list_foreach ( trwlayer->image_cache->head, (GFunc) cached_pixbuf_free, NULL );
-  g_queue_free ( trwlayer->image_cache );
+  image_cache_free ( trwlayer );
 }
 
-static void init_drawing_params ( struct DrawingParams *dp, VikTrwLayer *vtl, VikViewport *vp )
+static void init_drawing_params ( struct DrawingParams *dp, VikTrwLayer *vtl, VikViewport *vp, gboolean highlight )
 {
   dp->vtl = vtl;
   dp->vp = vp;
+  dp->highlight = highlight;
   dp->vw = (VikWindow *)VIK_GTK_WINDOW_FROM_LAYER(dp->vtl);
   dp->xmpp = vik_viewport_get_xmpp ( vp );
   dp->ympp = vik_viewport_get_ympp ( vp );
@@ -1690,6 +1801,9 @@ static gdouble distance_in_preferred_units ( gdouble dist )
   case VIK_UNITS_DISTANCE_MILES:
     mydist = VIK_METERS_TO_MILES(dist);
     break;
+  case VIK_UNITS_DISTANCE_NAUTICAL_MILES:
+    mydist = VIK_METERS_TO_NAUTICAL_MILES(dist);
+    break;
   // VIK_UNITS_DISTANCE_KILOMETRES:
   default:
     mydist = dist/1000.0;
@@ -1735,6 +1849,9 @@ static void trw_layer_draw_dist_labels ( struct DrawingParams *dp, VikTrack *trk
     case VIK_UNITS_DISTANCE_MILES:
       dist_i = VIK_MILES_TO_METERS(dist_i);
       break;
+    case VIK_UNITS_DISTANCE_NAUTICAL_MILES:
+      dist_i = VIK_NAUTICAL_MILES_TO_METERS(dist_i);
+      break;
       // VIK_UNITS_DISTANCE_KILOMETRES:
     default:
       dist_i = dist_i*1000.0;
@@ -1760,6 +1877,9 @@ static void trw_layer_draw_dist_labels ( struct DrawingParams *dp, VikTrack *trk
       case VIK_UNITS_DISTANCE_MILES:
         units = g_strdup ( _("miles") );
         break;
+      case VIK_UNITS_DISTANCE_NAUTICAL_MILES:
+        units = g_strdup ( _("NM") );
+        break;
         // VIK_UNITS_DISTANCE_KILOMETRES:
       default:
         units = g_strdup ( _("km") );
@@ -1910,6 +2030,40 @@ static void trw_layer_draw_track_name_labels ( struct DrawingParams *dp, VikTrac
   g_free ( ename );
 }
 
+
+/**
+ * trw_layer_draw_point_names:
+ *
+ * Draw a point labels along a track
+ * This might slow things down if there's many tracks being displayed with this on.
+ */
+static void trw_layer_draw_point_names ( struct DrawingParams *dp, VikTrack *trk, gboolean drawing_highlight )
+{
+  GList *list = trk->trackpoints;
+  if (!list) return;
+  VikTrackpoint *tp = VIK_TRACKPOINT(list->data);
+  gchar *fgcolour;
+  if ( dp->vtl->drawmode == DRAWMODE_BY_TRACK )
+    fgcolour = gdk_color_to_string ( &(trk->color) );
+  else
+    fgcolour = gdk_color_to_string ( &(dp->vtl->track_color) );
+  gchar *bgcolour;
+  if ( drawing_highlight )
+    bgcolour = g_strdup ( vik_viewport_get_highlight_color ( dp->vp ) );
+  else
+    bgcolour = gdk_color_to_string ( &(dp->vtl->track_bg_color) );
+  if ( tp->name )
+    trw_layer_draw_track_label ( tp->name, fgcolour, bgcolour, dp, &tp->coord );
+  while ((list = g_list_next(list)))
+  {
+    tp = VIK_TRACKPOINT(list->data);
+    if ( tp->name )
+      trw_layer_draw_track_label ( tp->name, fgcolour, bgcolour, dp, &tp->coord );
+  };
+  g_free ( fgcolour );
+  g_free ( bgcolour );
+}
+
 static void trw_layer_draw_track ( const gpointer id, VikTrack *track, struct DrawingParams *dp, gboolean draw_track_outline )
 {
   if ( ! track->visible )
@@ -1952,18 +2106,11 @@ static void trw_layer_draw_track ( const gpointer id, VikTrack *track, struct Dr
   if ( track == dp->vtl->current_track )
     main_gc = dp->vtl->current_track_gc;
   else {
-    if ( vik_viewport_get_draw_highlight ( dp->vp ) ) {
-      /* Draw all tracks of the layer in special colour */
-      /* if track is member of selected layer or is the current selected track
-        then draw in the highlight colour.
-        NB this supercedes the drawmode */
-      if ( ( dp->vtl == vik_window_get_selected_trw_layer ( dp->vw ) ) ||
-           ( !track->is_route && ( dp->vtl->tracks == vik_window_get_selected_tracks ( dp->vw ) ) ) ||
-           ( track->is_route && ( dp->vtl->routes == vik_window_get_selected_tracks ( dp->vw ) ) ) ||
-           ( track == vik_window_get_selected_track ( dp->vw ) ) ) {
-       main_gc = vik_viewport_get_gc_highlight (dp->vp);
-       drawing_highlight = TRUE;
-      }
+    if ( dp->highlight ) {
+      /* Draw all tracks of the layer in special colour
+         NB this supercedes the drawmode */
+      main_gc = vik_viewport_get_gc_highlight (dp->vp);
+      drawing_highlight = TRUE;
     }
     if ( !drawing_highlight ) {
       // Still need to figure out the gc according to the drawing mode:
@@ -2017,6 +2164,16 @@ static void trw_layer_draw_track ( const gpointer id, VikTrack *track, struct Dr
       tp = VIK_TRACKPOINT(list->data);
       tp_size = (list == dp->vtl->current_tpl) ? tp_size_cur : tp_size_reg;
 
+      VikTrackpoint *tp2 = VIK_TRACKPOINT(list->prev->data);
+      // See if in a different lat/lon 'quadrant' so don't draw massively long lines (presumably wrong way around the Earth)
+      //  Mainly to prevent wrong lines drawn when a track crosses the 180 degrees East-West longitude boundary
+      //  (since vik_viewport_draw_line() only copes with pixel value and has no concept of the globe)
+      if ( dp->lat_lon &&
+           (( tp2->coord.east_west < -90.0 && tp->coord.east_west > 90.0 ) ||
+            ( tp2->coord.east_west > 90.0 && tp->coord.east_west < -90.0 )) ) {
+        useoldvals = FALSE;
+        continue;
+      }
       /* check some stuff -- but only if we're in UTM and there's only ONE ZONE; or lat lon */
       if ( (!dp->one_zone && !dp->lat_lon) ||     /* UTM & zones; do everything */
              ( ((!dp->one_zone) || tp->coord.utm_zone == dp->center->utm_zone) &&   /* only check zones if UTM & one_zone */
@@ -2033,12 +2190,11 @@ static void trw_layer_draw_track ( const gpointer id, VikTrack *track, struct Dr
          // Still need to process points to ensure 'stops' are drawn if required
          if ( drawstops && drawpoints && ! draw_track_outline && list->next &&
               (VIK_TRACKPOINT(list->next->data)->timestamp - VIK_TRACKPOINT(list->data)->timestamp > dp->vtl->stop_length) )
-           vik_viewport_draw_arc ( dp->vp, g_array_index(dp->vtl->track_gc, GdkGC *, 11), TRUE, x-(3*tp_size), y-(3*tp_size), 6*tp_size, 6*tp_size, 0, 360*64 );
+           vik_viewport_draw_arc ( dp->vp, g_array_index(dp->vtl->track_gc, GdkGC *, VIK_TRW_LAYER_TRACK_GC_STOP), TRUE, x-(3*tp_size), y-(3*tp_size), 6*tp_size, 6*tp_size, 0, 360*64 );
 
          goto skip;
        }
 
-        VikTrackpoint *tp2 = VIK_TRACKPOINT(list->prev->data);
         if ( drawpoints || dp->vtl->drawlines ) {
           // setup main_gc for both point and line drawing
           if ( !drawing_highlight && (dp->vtl->drawmode == DRAWMODE_BY_SPEED) ) {
@@ -2136,7 +2292,6 @@ static void trw_layer_draw_track ( const gpointer id, VikTrack *track, struct Dr
       else {
         if (useoldvals && dp->vtl->drawlines && (!tp->newsegment))
         {
-          VikTrackpoint *tp2 = VIK_TRACKPOINT(list->prev->data);
           if ( dp->vtl->coord_mode != VIK_COORD_UTM || tp->coord.utm_zone == dp->center->utm_zone )
           {
             vik_viewport_coord_to_screen ( dp->vp, &(tp->coord), &x, &y );
@@ -2177,6 +2332,7 @@ static void trw_layer_draw_track ( const gpointer id, VikTrack *track, struct Dr
       if ( track->max_number_dist_labels > 0 ) {
         trw_layer_draw_dist_labels ( dp, track, drawing_highlight );
       }
+      trw_layer_draw_point_names (dp, track, drawing_highlight );
 
       if ( track->draw_name_mode != TRACK_DRAWNAME_NO ) {
         trw_layer_draw_track_name_labels ( dp, track, drawing_highlight );
@@ -2249,6 +2405,10 @@ static void trw_layer_draw_waypoint ( const gpointer id, VikWaypoint *wp, struct
           }
           cp->image = g_strdup ( image );
 
+          // Apply alpha setting to the image before the pixbuf gets stored in the cache
+          if ( dp->vtl->image_alpha != 255 )
+            cp->pixbuf = ui_pixbuf_set_alpha ( cp->pixbuf, dp->vtl->image_alpha );
+
           /* needed so 'click picture' tool knows how big the pic is; we don't
            * store it in cp because they may have been freed already. */
           wp->image_width = gdk_pixbuf_get_width ( cp->pixbuf );
@@ -2273,22 +2433,16 @@ static void trw_layer_draw_waypoint ( const gpointer id, VikWaypoint *wp, struct
 
         if ( x+(w/2) > 0 && y+(h/2) > 0 && x-(w/2) < dp->width && y-(h/2) < dp->height ) /* always draw within boundaries */
         {
-         if ( vik_viewport_get_draw_highlight ( dp->vp ) ) {
-            if ( dp->vtl == vik_window_get_selected_trw_layer ( dp->vw ) ||
-                 dp->vtl->waypoints == vik_window_get_selected_waypoints ( dp->vw ) ||
-                 wp == vik_window_get_selected_waypoint ( dp->vw ) ) {
-             // Highlighted - so draw a little border around the chosen one
-             // single line seems a little weak so draw 2 of them
-             vik_viewport_draw_rectangle (dp->vp, vik_viewport_get_gc_highlight (dp->vp), FALSE,
-                                          x - (w/2) - 1, y - (h/2) - 1, w + 2, h + 2 );
-             vik_viewport_draw_rectangle (dp->vp, vik_viewport_get_gc_highlight (dp->vp), FALSE,
-                                          x - (w/2) - 2, y - (h/2) - 2, w + 4, h + 4 );
-           }
-         }
-          if ( dp->vtl->image_alpha == 255 )
-            vik_viewport_draw_pixbuf ( dp->vp, pixbuf, 0, 0, x - (w/2), y - (h/2), w, h );
-          else
-            vik_viewport_draw_pixbuf_with_alpha ( dp->vp, pixbuf, dp->vtl->image_alpha, 0, 0, x - (w/2), y - (h/2), w, h );
+          if ( dp->highlight ) {
+            // Highlighted - so draw a little border around the chosen one
+            // single line seems a little weak so draw 2 of them
+            vik_viewport_draw_rectangle (dp->vp, vik_viewport_get_gc_highlight (dp->vp), FALSE,
+                                         x - (w/2) - 1, y - (h/2) - 1, w + 2, h + 2 );
+            vik_viewport_draw_rectangle (dp->vp, vik_viewport_get_gc_highlight (dp->vp), FALSE,
+                                         x - (w/2) - 2, y - (h/2) - 2, w + 4, h + 4 );
+          }
+
+          vik_viewport_draw_pixbuf ( dp->vp, pixbuf, 0, 0, x - (w/2), y - (h/2), w, h );
         }
         return; /* if failed to draw picture, default to drawing regular waypoint (below) */
       }
@@ -2305,6 +2459,7 @@ static void trw_layer_draw_waypoint ( const gpointer id, VikWaypoint *wp, struct
         case WP_SYMBOL_CIRCLE: vik_viewport_draw_arc ( dp->vp, dp->vtl->waypoint_gc, TRUE, x - dp->vtl->wp_size, y - dp->vtl->wp_size, dp->vtl->wp_size, dp->vtl->wp_size, 0, 360*64 ); break;
         case WP_SYMBOL_X: vik_viewport_draw_line ( dp->vp, dp->vtl->waypoint_gc, x - dp->vtl->wp_size*2, y - dp->vtl->wp_size*2, x + dp->vtl->wp_size*2, y + dp->vtl->wp_size*2 );
                           vik_viewport_draw_line ( dp->vp, dp->vtl->waypoint_gc, x - dp->vtl->wp_size*2, y + dp->vtl->wp_size*2, x + dp->vtl->wp_size*2, y - dp->vtl->wp_size*2 );
+        default: break;
       }
     }
     else {
@@ -2314,6 +2469,7 @@ static void trw_layer_draw_waypoint ( const gpointer id, VikWaypoint *wp, struct
         case WP_SYMBOL_CIRCLE: vik_viewport_draw_arc ( dp->vp, dp->vtl->waypoint_gc, TRUE, x-dp->vtl->wp_size/2, y-dp->vtl->wp_size/2, dp->vtl->wp_size, dp->vtl->wp_size, 0, 360*64 ); break;
         case WP_SYMBOL_X: vik_viewport_draw_line ( dp->vp, dp->vtl->waypoint_gc, x-dp->vtl->wp_size, y-dp->vtl->wp_size, x+dp->vtl->wp_size, y+dp->vtl->wp_size );
                           vik_viewport_draw_line ( dp->vp, dp->vtl->waypoint_gc, x-dp->vtl->wp_size, y+dp->vtl->wp_size, x+dp->vtl->wp_size, y-dp->vtl->wp_size ); break;
+        default: break;
       }
     }
 
@@ -2343,17 +2499,10 @@ static void trw_layer_draw_waypoint ( const gpointer id, VikWaypoint *wp, struct
         label_y = y - dp->vtl->wp_size - height - 2;
 
       /* if highlight mode on, then draw background text in highlight colour */
-      if ( vik_viewport_get_draw_highlight ( dp->vp ) ) {
-       if ( dp->vtl == vik_window_get_selected_trw_layer ( dp->vw ) ||
-             dp->vtl->waypoints == vik_window_get_selected_waypoints ( dp->vw ) ||
-             wp == vik_window_get_selected_waypoint ( dp->vw ) )
-         vik_viewport_draw_rectangle ( dp->vp, vik_viewport_get_gc_highlight (dp->vp), TRUE, label_x - 1, label_y-1,width+2,height+2);
-       else
-         vik_viewport_draw_rectangle ( dp->vp, dp->vtl->waypoint_bg_gc, TRUE, label_x - 1, label_y-1,width+2,height+2);
-      }
-      else {
-       vik_viewport_draw_rectangle ( dp->vp, dp->vtl->waypoint_bg_gc, TRUE, label_x - 1, label_y-1,width+2,height+2);
-      }
+      if ( dp->highlight )
+        vik_viewport_draw_rectangle ( dp->vp, vik_viewport_get_gc_highlight (dp->vp), TRUE, label_x - 1, label_y-1,width+2,height+2);
+      else
+        vik_viewport_draw_rectangle ( dp->vp, dp->vtl->waypoint_bg_gc, TRUE, label_x - 1, label_y-1,width+2,height+2);
       vik_viewport_draw_layout ( dp->vp, dp->vtl->waypoint_text_gc, label_x, label_y, dp->vtl->wplabellayout );
     }
   }
@@ -2366,12 +2515,12 @@ static void trw_layer_draw_waypoint_cb ( gpointer id, VikWaypoint *wp, struct Dr
   }
 }
 
-static void trw_layer_draw ( VikTrwLayer *l, gpointer data )
+static void trw_layer_draw_with_highlight ( VikTrwLayer *l, gpointer data, gboolean highlight )
 {
   static struct DrawingParams dp;
   g_assert ( l != NULL );
 
-  init_drawing_params ( &dp, l, VIK_VIEWPORT(data) );
+  init_drawing_params ( &dp, l, VIK_VIEWPORT(data), highlight );
 
   if ( l->tracks_visible )
     g_hash_table_foreach ( l->tracks, (GHFunc) trw_layer_draw_track_cb, &dp );
@@ -2383,6 +2532,77 @@ static void trw_layer_draw ( VikTrwLayer *l, gpointer data )
     g_hash_table_foreach ( l->waypoints, (GHFunc) trw_layer_draw_waypoint_cb, &dp );
 }
 
+static void trw_layer_draw ( VikTrwLayer *l, gpointer data )
+{
+  // If this layer is to be highlighted - then don't draw now - as it will be drawn later on in the specific highlight draw stage
+  // This may seem slightly inefficient to test each time for every layer
+  //  but for a layer with *lots* of tracks & waypoints this can save some effort by not drawing the items twice
+  if ( vik_viewport_get_draw_highlight ( (VikViewport*)data ) &&
+       vik_window_get_selected_trw_layer ((VikWindow*)VIK_GTK_WINDOW_FROM_LAYER((VikLayer*)l)) == l )
+    return;
+  trw_layer_draw_with_highlight ( l, data, FALSE );
+}
+
+void vik_trw_layer_draw_highlight ( VikTrwLayer *vtl, VikViewport *vvp )
+{
+  // Check the layer for visibility (including all the parents visibilities)
+  if ( !vik_treeview_item_get_visible_tree (VIK_LAYER(vtl)->vt, &(VIK_LAYER(vtl)->iter)) )
+    return;
+  trw_layer_draw_with_highlight ( vtl, vvp, TRUE );
+}
+
+/**
+ * vik_trw_layer_draw_highlight_item:
+ *
+ * Only handles a single track or waypoint ATM
+ * It assumes the track or waypoint belongs to the TRW Layer (it doesn't check this is the case)
+ */
+void vik_trw_layer_draw_highlight_item ( VikTrwLayer *vtl, VikTrack *trk, VikWaypoint *wpt, VikViewport *vvp )
+{
+  // Check the layer for visibility (including all the parents visibilities)
+  if ( !vik_treeview_item_get_visible_tree (VIK_LAYER(vtl)->vt, &(VIK_LAYER(vtl)->iter)) )
+    return;
+
+  static struct DrawingParams dp;
+  init_drawing_params ( &dp, vtl, vvp, TRUE );
+
+  if ( trk ) {
+    gboolean draw = ( trk->is_route && vtl->routes_visible ) || ( !trk->is_route && vtl->tracks_visible );
+    if ( draw )
+      trw_layer_draw_track_cb ( NULL, trk, &dp );
+  }
+  if ( vtl->waypoints_visible && wpt ) {
+    trw_layer_draw_waypoint_cb ( NULL, wpt, &dp );
+  }
+}
+
+/**
+ * vik_trw_layer_draw_highlight_item:
+ *
+ * Generally for drawing all tracks or routes or waypoints
+ * trks may be actually routes
+ * It assumes they belong to the TRW Layer (it doesn't check this is the case)
+ */
+void vik_trw_layer_draw_highlight_items ( VikTrwLayer *vtl, GHashTable *trks, GHashTable *wpts, VikViewport *vvp )
+{
+  // Check the layer for visibility (including all the parents visibilities)
+  if ( !vik_treeview_item_get_visible_tree (VIK_LAYER(vtl)->vt, &(VIK_LAYER(vtl)->iter)) )
+    return;
+
+  static struct DrawingParams dp;
+  init_drawing_params ( &dp, vtl, vvp, TRUE );
+
+  if ( trks ) {
+    gboolean is_routes = (trks == vtl->routes);
+    gboolean draw = ( is_routes && vtl->routes_visible ) || ( !is_routes && vtl->tracks_visible );
+    if ( draw )
+      g_hash_table_foreach ( trks, (GHFunc) trw_layer_draw_track_cb, &dp );
+  }
+
+  if ( vtl->waypoints_visible && wpts )
+    g_hash_table_foreach ( wpts, (GHFunc) trw_layer_draw_waypoint_cb, &dp );
+}
+
 static void trw_layer_free_track_gcs ( VikTrwLayer *vtl )
 {
   int i;
@@ -2518,7 +2738,12 @@ static void trw_layer_realize_track ( gpointer id, VikTrack *track, gpointer pas
     gdk_pixbuf_fill ( pixbuf, pixel );
   }
 
-  vik_treeview_add_sublayer ( (VikTreeview *) pass_along[3], (GtkTreeIter *) pass_along[0], (GtkTreeIter *) pass_along[1], track->name, pass_along[2], id, GPOINTER_TO_INT (pass_along[4]), pixbuf, TRUE, TRUE );
+  time_t timestamp = 0;
+  VikTrackpoint *tpt = vik_track_get_tp_first(track);
+  if ( tpt && tpt->has_timestamp )
+    timestamp = tpt->timestamp;
+
+  vik_treeview_add_sublayer ( (VikTreeview *) pass_along[3], (GtkTreeIter *) pass_along[0], (GtkTreeIter *) pass_along[1], track->name, pass_along[2], id, GPOINTER_TO_INT (pass_along[4]), pixbuf, TRUE, timestamp );
 
   if ( pixbuf )
     g_object_unref (pixbuf);
@@ -2537,7 +2762,11 @@ static void trw_layer_realize_waypoint ( gpointer id, VikWaypoint *wp, gpointer
 {
   GtkTreeIter *new_iter = g_malloc(sizeof(GtkTreeIter));
 
-  vik_treeview_add_sublayer ( (VikTreeview *) pass_along[3], (GtkTreeIter *) pass_along[0], (GtkTreeIter *) pass_along[1], wp->name, pass_along[2], id, GPOINTER_TO_UINT (pass_along[4]), get_wp_sym_small (wp->symbol), TRUE, TRUE );
+  time_t timestamp = 0;
+  if ( wp->has_timestamp )
+    timestamp = wp->timestamp;
+
+  vik_treeview_add_sublayer ( (VikTreeview *) pass_along[3], (GtkTreeIter *) pass_along[0], (GtkTreeIter *) pass_along[1], wp->name, pass_along[2], id, GPOINTER_TO_UINT (pass_along[4]), get_wp_sym_small (wp->symbol), TRUE, timestamp );
 
   *new_iter = *((GtkTreeIter *) pass_along[1]);
   g_hash_table_insert ( VIK_TRW_LAYER(pass_along[2])->waypoints_iters, id, new_iter );
@@ -2548,17 +2777,17 @@ static void trw_layer_realize_waypoint ( gpointer id, VikWaypoint *wp, gpointer
 
 static void trw_layer_add_sublayer_tracks ( VikTrwLayer *vtl, VikTreeview *vt, GtkTreeIter *layer_iter )
 {
-  vik_treeview_add_sublayer ( (VikTreeview *) vt, layer_iter, &(vtl->tracks_iter), _("Tracks"), vtl, NULL, VIK_TRW_LAYER_SUBLAYER_TRACKS, NULL, TRUE, FALSE );
+  vik_treeview_add_sublayer ( (VikTreeview *) vt, layer_iter, &(vtl->tracks_iter), _("Tracks"), vtl, NULL, VIK_TRW_LAYER_SUBLAYER_TRACKS, NULL, FALSE, 0 );
 }
 
 static void trw_layer_add_sublayer_waypoints ( VikTrwLayer *vtl, VikTreeview *vt, GtkTreeIter *layer_iter )
 {
-  vik_treeview_add_sublayer ( (VikTreeview *) vt, layer_iter, &(vtl->waypoints_iter), _("Waypoints"), vtl, NULL, VIK_TRW_LAYER_SUBLAYER_WAYPOINTS, NULL, TRUE, FALSE );
+  vik_treeview_add_sublayer ( (VikTreeview *) vt, layer_iter, &(vtl->waypoints_iter), _("Waypoints"), vtl, NULL, VIK_TRW_LAYER_SUBLAYER_WAYPOINTS, NULL, FALSE, 0 );
 }
 
 static void trw_layer_add_sublayer_routes ( VikTrwLayer *vtl, VikTreeview *vt, GtkTreeIter *layer_iter )
 {
-  vik_treeview_add_sublayer ( (VikTreeview *) vt, layer_iter, &(vtl->routes_iter), _("Routes"), vtl, NULL, VIK_TRW_LAYER_SUBLAYER_ROUTES, NULL, TRUE, FALSE );
+  vik_treeview_add_sublayer ( (VikTreeview *) vt, layer_iter, &(vtl->routes_iter), _("Routes"), vtl, NULL, VIK_TRW_LAYER_SUBLAYER_ROUTES, NULL, FALSE, 0 );
 }
 
 static void trw_layer_realize ( VikTrwLayer *vtl, VikTreeview *vt, GtkTreeIter *layer_iter )
@@ -2596,6 +2825,9 @@ static void trw_layer_realize ( VikTrwLayer *vtl, VikTreeview *vt, GtkTreeIter *
     vik_treeview_item_set_visible ( (VikTreeview *) vt, &(vtl->waypoints_iter), vtl->waypoints_visible );
   }
 
+  trw_layer_verify_thumbnails ( vtl, NULL );
+
+  trw_layer_sort_all ( vtl );
 }
 
 static gboolean trw_layer_sublayer_toggle_visible ( VikTrwLayer *l, gint subtype, gpointer sublayer )
@@ -2629,6 +2861,7 @@ static gboolean trw_layer_sublayer_toggle_visible ( VikTrwLayer *l, gint subtype
       else
         return TRUE;
     }
+    default: break;
   }
   return TRUE;
 }
@@ -2641,6 +2874,14 @@ gint vik_trw_layer_get_property_tracks_line_thickness ( VikTrwLayer *vtl )
   return vtl->line_thickness;
 }
 
+/*
+ * Build up multiple routes information
+ */
+static void trw_layer_routes_tooltip ( const gpointer id, VikTrack *tr, gdouble *length )
+{
+  *length = *length + vik_track_get_length (tr);
+}
+
 // Structure to hold multiple track information for a layer
 typedef struct {
   gdouble length;
@@ -2652,36 +2893,37 @@ typedef struct {
 /*
  * Build up layer multiple track information via updating the tooltip_tracks structure
  */
-static void trw_layer_tracks_tooltip ( const gchar *name, VikTrack *tr, tooltip_tracks *tt )
+static void trw_layer_tracks_tooltip ( const gpointer id, VikTrack *tr, tooltip_tracks *tt )
 {
   tt->length = tt->length + vik_track_get_length (tr);
 
   // Ensure times are available
-  if ( tr->trackpoints &&
-       vik_track_get_tp_first(tr)->has_timestamp &&
-       vik_track_get_tp_last(tr)->has_timestamp ) {
+  if ( tr->trackpoints && vik_track_get_tp_first(tr)->has_timestamp ) {
+    // Get trkpt only once - as using vik_track_get_tp_last() iterates whole track each time
+    VikTrackpoint *trkpt_last = vik_track_get_tp_last(tr);
+    if ( trkpt_last->has_timestamp ) {
+      time_t t1, t2;
+      t1 = vik_track_get_tp_first(tr)->timestamp;
+      t2 = trkpt_last->timestamp;
 
-    time_t t1, t2;
-    t1 = vik_track_get_tp_first(tr)->timestamp;
-    t2 = vik_track_get_tp_last(tr)->timestamp;
+      // Assume never actually have a track with a time of 0 (1st Jan 1970)
+      // Hence initialize to the first 'proper' value
+      if ( tt->start_time == 0 )
+        tt->start_time = t1;
+      if ( tt->end_time == 0 )
+        tt->end_time = t2;
 
-    // Assume never actually have a track with a time of 0 (1st Jan 1970)
-    // Hence initialize to the first 'proper' value
-    if ( tt->start_time == 0 )
-       tt->start_time = t1;
-    if ( tt->end_time == 0 )
-       tt->end_time = t2;
+      // Update find the earliest / last times
+      if ( t1 < tt->start_time )
+        tt->start_time = t1;
+      if ( t2 > tt->end_time )
+        tt->end_time = t2;
 
-    // Update find the earliest / last times
-    if ( t1 < tt->start_time )
-       tt->start_time = t1;
-    if ( t2 > tt->end_time )
-       tt->end_time = t2;
-
-    // Keep track of total time
-    //  there maybe gaps within a track (eg segments)
-    //  but this should be generally good enough for a simple indicator
-    tt->duration = tt->duration + (int)(t2-t1);
+      // Keep track of total time
+      //  there maybe gaps within a track (eg segments)
+      //  but this should be generally good enough for a simple indicator
+      tt->duration = tt->duration + (int)(t2-t1);
+    }
   }
 }
 
@@ -2693,7 +2935,7 @@ static void trw_layer_tracks_tooltip ( const gchar *name, VikTrack *tr, tooltip_
  */
 static const gchar* trw_layer_layer_tooltip ( VikTrwLayer *vtl )
 {
-  gchar tbuf1[32];
+  gchar tbuf1[64];
   gchar tbuf2[64];
   gchar tbuf3[64];
   gchar tbuf4[10];
@@ -2709,7 +2951,7 @@ static const gchar* trw_layer_layer_tooltip ( VikTrwLayer *vtl )
 
   // Safety check - I think these should always be valid
   if ( vtl->tracks && vtl->waypoints ) {
-    tooltip_tracks tt = { 0.0, 0, 0 };
+    tooltip_tracks tt = { 0.0, 0, 0, 0 };
     g_hash_table_foreach ( vtl->tracks, (GHFunc) trw_layer_tracks_tooltip, &tt );
 
     GDate* gdate_start = g_date_new ();
@@ -2735,35 +2977,63 @@ static const gchar* trw_layer_layer_tooltip ( VikTrwLayer *vtl )
       gdouble len_in_units;
 
       // Setup info dependent on distance units
-      if ( a_vik_get_units_distance() == VIK_UNITS_DISTANCE_MILES ) {
-       g_snprintf (tbuf4, sizeof(tbuf4), "miles");
-       len_in_units = VIK_METERS_TO_MILES(tt.length);
-      }
-      else {
-       g_snprintf (tbuf4, sizeof(tbuf4), "kms");
-       len_in_units = tt.length/1000.0;
+      switch ( a_vik_get_units_distance() ) {
+      case VIK_UNITS_DISTANCE_MILES:
+        g_snprintf (tbuf4, sizeof(tbuf4), "miles");
+        len_in_units = VIK_METERS_TO_MILES(tt.length);
+        break;
+      case VIK_UNITS_DISTANCE_NAUTICAL_MILES:
+        g_snprintf (tbuf4, sizeof(tbuf4), "NM");
+        len_in_units = VIK_METERS_TO_NAUTICAL_MILES(tt.length);
+        break;
+      default:
+        g_snprintf (tbuf4, sizeof(tbuf4), "kms");
+        len_in_units = tt.length/1000.0;
+        break;
       }
 
       // Timing information if available
       tbuf1[0] = '\0';
       if ( tt.duration > 0 ) {
-       g_snprintf (tbuf1, sizeof(tbuf1),
-                   _(" in %d:%02d hrs:mins"),
-                   (int)round(tt.duration/3600), (int)round((tt.duration/60)%60));
+        g_snprintf (tbuf1, sizeof(tbuf1),
+                    _(" in %d:%02d hrs:mins"),
+                    (int)(tt.duration/3600), (int)round(tt.duration/60.0)%60);
       }
       g_snprintf (tbuf2, sizeof(tbuf2),
                  _("\n%sTotal Length %.1f %s%s"),
                  tbuf3, len_in_units, tbuf4, tbuf1);
     }
 
+    tbuf1[0] = '\0';
+    gdouble rlength = 0.0;
+    g_hash_table_foreach ( vtl->routes, (GHFunc) trw_layer_routes_tooltip, &rlength );
+    if ( rlength > 0.0 ) {
+      gdouble len_in_units;
+      // Setup info dependent on distance units
+      switch ( a_vik_get_units_distance() ) {
+      case VIK_UNITS_DISTANCE_MILES:
+        g_snprintf (tbuf4, sizeof(tbuf4), "miles");
+        len_in_units = VIK_METERS_TO_MILES(rlength);
+        break;
+      case VIK_UNITS_DISTANCE_NAUTICAL_MILES:
+        g_snprintf (tbuf4, sizeof(tbuf4), "NM");
+        len_in_units = VIK_METERS_TO_NAUTICAL_MILES(rlength);
+        break;
+      default:
+        g_snprintf (tbuf4, sizeof(tbuf4), "kms");
+        len_in_units = rlength/1000.0;
+        break;
+      }
+      g_snprintf (tbuf1, sizeof(tbuf1), _("\nTotal route length %.1f %s"), len_in_units, tbuf4);
+    }
+
     // Put together all the elements to form compact tooltip text
     g_snprintf (tmp_buf, sizeof(tmp_buf),
-               _("Tracks: %d - Waypoints: %d - Routes: %d%s"),
-               g_hash_table_size (vtl->tracks), g_hash_table_size (vtl->waypoints), g_hash_table_size (vtl->routes), tbuf2);
+                _("Tracks: %d - Waypoints: %d - Routes: %d%s%s"),
+                g_hash_table_size (vtl->tracks), g_hash_table_size (vtl->waypoints), g_hash_table_size (vtl->routes), tbuf2, tbuf1);
 
     g_date_free (gdate_start);
     g_date_free (gdate_end);
-
   }
 
   return tmp_buf;
@@ -2816,11 +3086,9 @@ static const gchar* trw_layer_sublayer_tooltip ( VikTrwLayer *l, gint subtype, g
        if ( tr->trackpoints && vik_track_get_tp_first(tr)->has_timestamp ) {
          // %x     The preferred date representation for the current locale without the time.
          strftime (time_buf1, sizeof(time_buf1), "%x: ", gmtime(&(vik_track_get_tp_first(tr)->timestamp)));
-         if ( vik_track_get_tp_last(tr)->has_timestamp ) {
-           gint dur = ( (vik_track_get_tp_last(tr)->timestamp) - (vik_track_get_tp_first(tr)->timestamp) );
-           if ( dur > 0 )
-             g_snprintf ( time_buf2, sizeof(time_buf2), _("- %d:%02d hrs:mins"), (int)round(dur/3600), (int)round((dur/60)%60) );
-         }
+         time_t dur = vik_track_get_duration ( tr, TRUE );
+         if ( dur > 0 )
+           g_snprintf ( time_buf2, sizeof(time_buf2), _("- %d:%02d hrs:mins"), (int)(dur/3600), (int)round(dur/60.0)%60 );
        }
        // Get length and consider the appropriate distance units
        gdouble tr_len = vik_track_get_length(tr);
@@ -2832,6 +3100,9 @@ static const gchar* trw_layer_sublayer_tooltip ( VikTrwLayer *l, gint subtype, g
        case VIK_UNITS_DISTANCE_MILES:
          g_snprintf (tmp_buf, sizeof(tmp_buf), _("%s%.1f miles %s"), time_buf1, VIK_METERS_TO_MILES(tr_len), time_buf2);
          break;
+       case VIK_UNITS_DISTANCE_NAUTICAL_MILES:
+         g_snprintf (tmp_buf, sizeof(tmp_buf), _("%s%.1f NM %s"), time_buf1, VIK_METERS_TO_NAUTICAL_MILES(tr_len), time_buf2);
+         break;
        default:
          break;
        }
@@ -2878,13 +3149,18 @@ static void set_statusbar_msg_info_trkpt ( VikTrwLayer *vtl, VikTrackpoint *trkp
 {
   gchar *statusbar_format_code = NULL;
   gboolean need2free = FALSE;
+  VikTrackpoint *trkpt_prev = NULL;
   if ( !a_settings_get_string ( VIK_SETTINGS_TRKPT_SELECTED_STATUSBAR_FORMAT, &statusbar_format_code ) ) {
     // Otherwise use default
     statusbar_format_code = g_strdup ( "KEATDN" );
     need2free = TRUE;
   }
+  else {
+    // Format code may want to show speed - so may need previous trkpt to work it out
+    trkpt_prev = vik_track_get_tp_prev ( vtl->current_tp_track, trkpt );
+  }
 
-  gchar *msg = vu_trackpoint_formatted_message ( statusbar_format_code, trkpt, NULL, vtl->current_tp_track );
+  gchar *msg = vu_trackpoint_formatted_message ( statusbar_format_code, trkpt, trkpt_prev, vtl->current_tp_track, NAN );
   vik_statusbar_set_message ( vik_window_get_statusbar (VIK_WINDOW(VIK_GTK_WINDOW_FROM_LAYER(vtl))), VIK_STATUSBAR_INFO, msg );
   g_free ( msg );
 
@@ -3047,7 +3323,7 @@ GHashTable *vik_trw_layer_get_routes_iters ( VikTrwLayer *vtl )
 
 GHashTable *vik_trw_layer_get_waypoints_iters ( VikTrwLayer *vtl )
 {
-  return vtl->waypoints;
+  return vtl->waypoints_iters;
 }
 
 gboolean vik_trw_layer_is_empty ( VikTrwLayer *vtl )
@@ -3174,51 +3450,7 @@ static void trw_layer_centerize ( menu_array_layer values )
 
 void trw_layer_zoom_to_show_latlons ( VikTrwLayer *vtl, VikViewport *vvp, struct LatLon maxmin[2] )
 {
-  /* First set the center [in case previously viewing from elsewhere] */
-  /* Then loop through zoom levels until provided positions are in view */
-  /* This method is not particularly fast - but should work well enough */
-  struct LatLon average = { (maxmin[0].lat+maxmin[1].lat)/2, (maxmin[0].lon+maxmin[1].lon)/2 };
-  VikCoord coord;
-  vik_coord_load_from_latlon ( &coord, vtl->coord_mode, &average );
-  vik_viewport_set_center_coord ( vvp, &coord );
-
-  /* Convert into definite 'smallest' and 'largest' positions */
-  struct LatLon minmin;
-  if ( maxmin[0].lat < maxmin[1].lat )
-    minmin.lat = maxmin[0].lat;
-  else
-    minmin.lat = maxmin[1].lat;
-
-  struct LatLon maxmax;
-  if ( maxmin[0].lon > maxmin[1].lon )
-    maxmax.lon = maxmin[0].lon;
-  else
-    maxmax.lon = maxmin[1].lon;
-
-  /* Never zoom in too far - generally not that useful, as too close ! */
-  /* Always recalculate the 'best' zoom level */
-  gdouble zoom = 1.0;
-  vik_viewport_set_zoom ( vvp, zoom );
-
-  gdouble min_lat, max_lat, min_lon, max_lon;
-  /* Should only be a maximum of about 18 iterations from min to max zoom levels */
-  while ( zoom <= VIK_VIEWPORT_MAX_ZOOM ) {
-    vik_viewport_get_min_max_lat_lon ( vvp, &min_lat, &max_lat, &min_lon, &max_lon );
-    /* NB I think the logic used in this test to determine if the bounds is within view
-       fails if track goes across 180 degrees longitude.
-       Hopefully that situation is not too common...
-       Mind you viking doesn't really do edge locations to well anyway */
-    if ( min_lat < minmin.lat &&
-        max_lat > minmin.lat &&
-        min_lon < maxmax.lon &&
-        max_lon > maxmax.lon )
-      /* Found within zoom level */
-      break;
-
-    /* Try next */
-    zoom = zoom * 2;
-    vik_viewport_set_zoom ( vvp, zoom );
-  }
+  vu_zoom_to_show_latlons ( vtl->coord_mode, vvp, maxmin );
 }
 
 gboolean vik_trw_layer_auto_set_view ( VikTrwLayer *vtl, VikViewport *vvp )
@@ -3245,131 +3477,69 @@ static void trw_layer_auto_view ( menu_array_layer values )
     a_dialog_info_msg ( VIK_GTK_WINDOW_FROM_LAYER(vtl), _("This layer has no waypoints or trackpoints.") );
 }
 
-static void trw_layer_export ( menu_array_layer values, const gchar *title, const gchar* default_name, VikTrack* trk, guint file_type )
-{
-  VikTrwLayer *vtl = VIK_TRW_LAYER(values[MA_VTL]);
-  GtkWidget *file_selector;
-  const gchar *fn;
-  gboolean failed = FALSE;
-  file_selector = gtk_file_chooser_dialog_new (title,
-                                              NULL,
-                                              GTK_FILE_CHOOSER_ACTION_SAVE,
-                                              GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
-                                              GTK_STOCK_SAVE, GTK_RESPONSE_ACCEPT,
-                                              NULL);
-  gchar *cwd = g_get_current_dir();
-  if ( cwd ) {
-    gtk_file_chooser_set_current_folder ( GTK_FILE_CHOOSER(file_selector), cwd );
-    g_free ( cwd );
-  }
-
-  gtk_file_chooser_set_current_name (GTK_FILE_CHOOSER(file_selector), default_name);
-
-  while ( gtk_dialog_run ( GTK_DIALOG(file_selector) ) == GTK_RESPONSE_ACCEPT )
-  {
-    fn = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER(file_selector) );
-    if ( g_file_test ( fn, G_FILE_TEST_EXISTS ) == FALSE ||
-         a_dialog_yes_or_no ( GTK_WINDOW(file_selector), _("The file \"%s\" exists, do you wish to overwrite it?"), a_file_basename ( fn ) ) )
-    {
-      gtk_widget_hide ( file_selector );
-      vik_window_set_busy_cursor ( VIK_WINDOW(VIK_GTK_WINDOW_FROM_LAYER(vtl)) );
-      failed = ! a_file_export ( vtl, fn, file_type, trk, TRUE );
-      vik_window_clear_busy_cursor ( VIK_WINDOW(VIK_GTK_WINDOW_FROM_LAYER(vtl)) );
-      break;
-    }
-  }
-  gtk_widget_destroy ( file_selector );
-  if ( failed )
-    a_dialog_error_msg ( VIK_GTK_WINDOW_FROM_LAYER(vtl), _("The filename you requested could not be opened for writing.") );
-}
-
 static void trw_layer_export_gpspoint ( menu_array_layer values )
 {
-  trw_layer_export ( values, _("Export Layer"), vik_layer_get_name(VIK_LAYER(values[MA_VTL])), NULL, FILE_TYPE_GPSPOINT );
+  gchar *auto_save_name = append_file_ext ( vik_layer_get_name(VIK_LAYER(values[MA_VTL])), FILE_TYPE_GPSPOINT );
+
+  vik_trw_layer_export ( VIK_TRW_LAYER (values[MA_VTL]), _("Export Layer"), auto_save_name, NULL, FILE_TYPE_GPSPOINT );
+
+  g_free ( auto_save_name );
 }
 
 static void trw_layer_export_gpsmapper ( menu_array_layer values )
 {
-  trw_layer_export ( values, _("Export Layer"), vik_layer_get_name(VIK_LAYER(values[MA_VTL])), NULL, FILE_TYPE_GPSMAPPER );
+  gchar *auto_save_name = append_file_ext ( vik_layer_get_name(VIK_LAYER(values[MA_VTL])), FILE_TYPE_GPSMAPPER );
+
+  vik_trw_layer_export ( VIK_TRW_LAYER (values[MA_VTL]), _("Export Layer"), auto_save_name, NULL, FILE_TYPE_GPSMAPPER );
+
+  g_free ( auto_save_name );
 }
 
 static void trw_layer_export_gpx ( menu_array_layer values )
 {
-  /* Auto append '.gpx' to track name (providing it's not already there) for the default filename */
-  gchar *auto_save_name = g_strdup ( vik_layer_get_name(VIK_LAYER(values[MA_VTL])) );
-  if ( ! check_file_ext ( auto_save_name, ".gpx" ) )
-    auto_save_name = g_strconcat ( auto_save_name, ".gpx", NULL );
+  gchar *auto_save_name = append_file_ext ( vik_layer_get_name(VIK_LAYER(values[MA_VTL])), FILE_TYPE_GPX );
 
-  trw_layer_export ( values, _("Export Layer"), auto_save_name, NULL, FILE_TYPE_GPX );
+  vik_trw_layer_export ( VIK_TRW_LAYER (values[MA_VTL]), _("Export Layer"), auto_save_name, NULL, FILE_TYPE_GPX );
 
   g_free ( auto_save_name );
 }
 
 static void trw_layer_export_kml ( menu_array_layer values )
 {
-  /* Auto append '.kml' to the name (providing it's not already there) for the default filename */
-  gchar *auto_save_name = g_strdup ( vik_layer_get_name(VIK_LAYER(values[MA_VTL])) );
-  if ( ! check_file_ext ( auto_save_name, ".kml" ) )
-    auto_save_name = g_strconcat ( auto_save_name, ".kml", NULL );
+  gchar *auto_save_name = append_file_ext ( vik_layer_get_name(VIK_LAYER(values[MA_VTL])), FILE_TYPE_KML );
 
-  trw_layer_export ( values, _("Export Layer"), auto_save_name, NULL, FILE_TYPE_KML );
+  vik_trw_layer_export ( VIK_TRW_LAYER (values[MA_VTL]), _("Export Layer"), auto_save_name, NULL, FILE_TYPE_KML );
 
   g_free ( auto_save_name );
 }
 
-/**
- * Convert the given TRW layer into a temporary GPX file and open it with the specified program
- *
- */
-static void trw_layer_export_external_gpx ( menu_array_layer values, const gchar* external_program )
+static void trw_layer_export_geojson ( menu_array_layer values )
 {
-  VikTrwLayer *vtl = VIK_TRW_LAYER(values[MA_VTL]);
-  gchar *name_used = NULL;
-  int fd;
+  gchar *auto_save_name = append_file_ext ( vik_layer_get_name(VIK_LAYER(values[MA_VTL])), FILE_TYPE_GEOJSON );
 
-  if ((fd = g_file_open_tmp("tmp-viking.XXXXXX.gpx", &name_used, NULL)) >= 0) {
-    vik_window_set_busy_cursor ( VIK_WINDOW(VIK_GTK_WINDOW_FROM_LAYER(vtl)) );
-    gboolean failed = ! a_file_export ( vtl, name_used, FILE_TYPE_GPX, NULL, TRUE);
-    vik_window_clear_busy_cursor ( VIK_WINDOW(VIK_GTK_WINDOW_FROM_LAYER(vtl)) );
-    if (failed) {
-      a_dialog_error_msg (VIK_GTK_WINDOW_FROM_LAYER(vtl), _("Could not create temporary file for export.") );
-    }
-    else {
-      GError *err = NULL;
-      gchar *quoted_file = g_shell_quote ( name_used );
-      gchar *cmd = g_strdup_printf ( "%s %s", external_program, quoted_file );
-      g_free ( quoted_file );
-      if ( ! g_spawn_command_line_async ( cmd, &err ) )
-      {
-        a_dialog_error_msg_extra ( VIK_GTK_WINDOW_FROM_LAYER(vtl), _("Could not launch %s."), external_program );
-        g_error_free ( err );
-      }
-      g_free ( cmd );
-    }
-    // Note ATM the 'temporary' file is not deleted, as loading via another program is not instantaneous
-    //g_remove ( name_used );
-    // Perhaps should be deleted when the program ends?
-    // For now leave it to the user to delete it / use system temp cleanup methods.
-    g_free ( name_used );
-  }
+  vik_trw_layer_export ( VIK_TRW_LAYER (values[MA_VTL]), _("Export Layer"), auto_save_name, NULL, FILE_TYPE_GEOJSON );
+
+  g_free ( auto_save_name );
+}
+
+static void trw_layer_export_babel ( gpointer layer_and_vlp[2] )
+{
+  const gchar *auto_save_name = vik_layer_get_name(VIK_LAYER(layer_and_vlp[0]));
+  vik_trw_layer_export_gpsbabel ( VIK_TRW_LAYER (layer_and_vlp[0]), _("Export Layer"), auto_save_name );
 }
 
 static void trw_layer_export_external_gpx_1 ( menu_array_layer values )
 {
-  trw_layer_export_external_gpx ( values, a_vik_get_external_gpx_program_1() );
+  vik_trw_layer_export_external_gpx ( VIK_TRW_LAYER (values[MA_VTL]), a_vik_get_external_gpx_program_1() );
 }
 
 static void trw_layer_export_external_gpx_2 ( menu_array_layer values )
 {
-  trw_layer_export_external_gpx ( values, a_vik_get_external_gpx_program_2() );
+  vik_trw_layer_export_external_gpx ( VIK_TRW_LAYER (values[MA_VTL]), a_vik_get_external_gpx_program_2() );
 }
 
 static void trw_layer_export_gpx_track ( menu_array_sublayer values )
 {
-  menu_array_layer data;
-  data[MA_VTL] = values[MA_VTL];
-  data[MA_VLP] = values[MA_VLP];
-
   VikTrwLayer *vtl = VIK_TRW_LAYER(values[MA_VTL]);
   VikTrack *trk;
   if ( GPOINTER_TO_INT (values[MA_SUBTYPE]) == VIK_TRW_LAYER_SUBLAYER_ROUTE )
@@ -3380,17 +3550,14 @@ static void trw_layer_export_gpx_track ( menu_array_sublayer values )
   if ( !trk || !trk->name )
     return;
 
-  /* Auto append '.gpx' to track name (providing it's not already there) for the default filename */
-  gchar *auto_save_name = g_strdup ( trk->name );
-  if ( ! check_file_ext ( auto_save_name, ".gpx" ) )
-    auto_save_name = g_strconcat ( auto_save_name, ".gpx", NULL );
+  gchar *auto_save_name = append_file_ext ( trk->name, FILE_TYPE_GPX );
 
   gchar *label = NULL;
   if ( GPOINTER_TO_INT (values[MA_SUBTYPE]) == VIK_TRW_LAYER_SUBLAYER_ROUTE )
     label = _("Export Route as GPX");
   else
     label = _("Export Track as GPX");
-  trw_layer_export ( data, label, auto_save_name, trk, FILE_TYPE_GPX );
+  vik_trw_layer_export ( VIK_TRW_LAYER (values[MA_VTL]), label, auto_save_name, trk, FILE_TYPE_GPX );
 
   g_free ( auto_save_name );
 }
@@ -3420,13 +3587,13 @@ static void trw_layer_goto_wp ( menu_array_layer values )
 
   GtkWidget *label, *entry;
   label = gtk_label_new(_("Waypoint Name:"));
-  entry = gtk_entry_new();
+  entry = ui_entry_new ( NULL, GTK_ENTRY_ICON_SECONDARY );
 
   gtk_box_pack_start(GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(dia))), label, FALSE, FALSE, 0);
   gtk_box_pack_start(GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(dia))), entry, FALSE, FALSE, 0);
-  gtk_widget_show_all ( label );
-  gtk_widget_show_all ( entry );
-
+  gtk_widget_show_all ( dia );
+  // 'ok' when press return in the entry
+  g_signal_connect_swapped ( entry, "activate", G_CALLBACK(a_dialog_response_accept), dia );
   gtk_dialog_set_default_response ( GTK_DIALOG(dia), GTK_RESPONSE_ACCEPT );
 
   while ( gtk_dialog_run ( GTK_DIALOG(dia) ) == GTK_RESPONSE_ACCEPT )
@@ -3439,7 +3606,7 @@ static void trw_layer_goto_wp ( menu_array_layer values )
       a_dialog_error_msg ( VIK_GTK_WINDOW_FROM_LAYER(vtl), _("Waypoint not found in this layer.") );
     else
     {
-      vik_viewport_set_center_coord ( vik_layers_panel_get_viewport(vlp), &(wp->coord) );
+      vik_viewport_set_center_coord ( vik_layers_panel_get_viewport(vlp), &(wp->coord), TRUE );
       vik_layers_panel_emit_update ( vlp );
 
       // Find and select on the side panel
@@ -3448,7 +3615,7 @@ static void trw_layer_goto_wp ( menu_array_layer values )
       udata.uuid = NULL;
 
       // Hmmm, want key of it
-      gpointer *wpf = g_hash_table_find ( vtl->waypoints, (GHRFunc) trw_layer_waypoint_find_uuid, (gpointer) &udata );
+      gpointer wpf = g_hash_table_find ( vtl->waypoints, (GHRFunc) trw_layer_waypoint_find_uuid, (gpointer) &udata );
 
       if ( wpf && udata.uuid ) {
         GtkTreeIter *it = g_hash_table_lookup ( vtl->waypoints_iters, udata.uuid );
@@ -3583,7 +3750,10 @@ static void trw_layer_acquire ( menu_array_layer values, VikDataSourceInterface
   VikWindow *vw = (VikWindow *)(VIK_GTK_WINDOW_FROM_LAYER(vtl));
   VikViewport *vvp =  vik_window_viewport(vw);
 
-  a_acquire ( vw, vlp, vvp, datasource, NULL, NULL );
+  vik_datasource_mode_t mode = datasource->mode;
+  if ( mode == VIK_DATASOURCE_AUTO_LAYER_MANAGEMENT )
+    mode = VIK_DATASOURCE_ADDTOLAYER;
+  a_acquire ( vw, vlp, vvp, mode, datasource, NULL, NULL );
 }
 
 /*
@@ -3591,7 +3761,6 @@ static void trw_layer_acquire ( menu_array_layer values, VikDataSourceInterface
  */
 static void trw_layer_acquire_gps_cb ( menu_array_layer values )
 {
-  vik_datasource_gps_interface.mode = VIK_DATASOURCE_ADDTOLAYER;
   trw_layer_acquire ( values, &vik_datasource_gps_interface );
 }
 
@@ -3608,7 +3777,6 @@ static void trw_layer_acquire_routing_cb ( menu_array_layer values )
  */
 static void trw_layer_acquire_url_cb ( menu_array_layer values )
 {
-  vik_datasource_url_interface.mode = VIK_DATASOURCE_ADDTOLAYER;
   trw_layer_acquire ( values, &vik_datasource_url_interface );
 }
 
@@ -3648,7 +3816,6 @@ static void trw_layer_acquire_geotagged_cb ( menu_array_layer values )
 {
   VikTrwLayer *vtl = VIK_TRW_LAYER(values[MA_VTL]);
 
-  vik_datasource_geotag_interface.mode = VIK_DATASOURCE_ADDTOLAYER;
   trw_layer_acquire ( values, &vik_datasource_geotag_interface );
 
   // Reverify thumbnails as they may have changed
@@ -3657,6 +3824,14 @@ static void trw_layer_acquire_geotagged_cb ( menu_array_layer values )
 }
 #endif
 
+/*
+ * Acquire into this TRW Layer from any GPS Babel supported file
+ */
+static void trw_layer_acquire_file_cb ( menu_array_layer values )
+{
+  trw_layer_acquire ( values, &vik_datasource_file_interface );
+}
+
 static void trw_layer_gps_upload ( menu_array_layer values )
 {
   menu_array_sublayer data;
@@ -3764,28 +3939,16 @@ static void trw_layer_gps_upload_any ( menu_array_sublayer values )
                  turn_off );
 }
 
-/*
- * Acquire into this TRW Layer from any GPS Babel supported file
- */
-static void trw_layer_acquire_file_cb ( menu_array_layer values )
-{
-  VikTrwLayer *vtl = VIK_TRW_LAYER(values[MA_VTL]);
-  VikLayersPanel *vlp = VIK_LAYERS_PANEL(values[MA_VLP]);
-  VikWindow *vw = (VikWindow *)(VIK_GTK_WINDOW_FROM_LAYER(vtl));
-  VikViewport *vvp =  vik_window_viewport(vw);
-
-  a_acquire ( vw, vlp, vvp, &vik_datasource_file_interface, NULL, NULL );
-}
-
 static void trw_layer_new_wp ( menu_array_layer values )
 {
   VikTrwLayer *vtl = VIK_TRW_LAYER(values[MA_VTL]);
   VikLayersPanel *vlp = VIK_LAYERS_PANEL(values[MA_VLP]);
   /* TODO longone: okay, if layer above (aggregate) is invisible but vtl->visible is true, this redraws for no reason.
      instead return true if you want to update. */
-  if ( vik_trw_layer_new_waypoint ( vtl, VIK_GTK_WINDOW_FROM_LAYER(vtl), vik_viewport_get_center(vik_layers_panel_get_viewport(vlp))) && VIK_LAYER(vtl)->visible ) {
+  if ( vik_trw_layer_new_waypoint ( vtl, VIK_GTK_WINDOW_FROM_LAYER(vtl), vik_viewport_get_center(vik_layers_panel_get_viewport(vlp))) ) {
     trw_layer_calculate_bounds_waypoints ( vtl );
-    vik_layers_panel_emit_update ( vlp );
+    if ( VIK_LAYER(vtl)->visible )
+      vik_layers_panel_emit_update ( vlp );
   }
 }
 
@@ -3858,6 +4021,7 @@ static void trw_layer_finish_track ( menu_array_layer values )
 {
   VikTrwLayer *vtl = VIK_TRW_LAYER(values[MA_VTL]);
   vtl->current_track = NULL;
+  vtl->route_finder_started = FALSE;
   vik_layer_emit_update ( VIK_LAYER(vtl) );
 }
 
@@ -3877,7 +4041,7 @@ static void trw_layer_auto_tracks_view ( menu_array_layer values )
 static void trw_layer_single_waypoint_jump ( const gpointer id, const VikWaypoint *wp, gpointer vvp )
 {
   /* NB do not care if wp is visible or not */
-  vik_viewport_set_center_coord ( VIK_VIEWPORT(vvp), &(wp->coord) );
+  vik_viewport_set_center_coord ( VIK_VIEWPORT(vvp), &(wp->coord), TRUE );
 }
 
 static void trw_layer_auto_waypoints_view ( menu_array_layer values )
@@ -3917,6 +4081,17 @@ void trw_layer_osm_traces_upload_track_cb ( menu_array_sublayer values )
   }
 }
 
+static GtkWidget* create_external_submenu ( GtkMenu *menu )
+{
+  GtkWidget *external_submenu = gtk_menu_new ();
+  GtkWidget *item = gtk_image_menu_item_new_with_mnemonic ( _("Externa_l") );
+  gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_EXECUTE, GTK_ICON_SIZE_MENU) );
+  gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
+  gtk_widget_show ( item );
+  gtk_menu_item_set_submenu (GTK_MENU_ITEM (item), external_submenu );
+  return external_submenu;
+}
+
 static void trw_layer_add_menu_items ( VikTrwLayer *vtl, GtkMenu *menu, gpointer vlp )
 {
   static menu_array_layer pass_along;
@@ -4006,10 +4181,26 @@ static void trw_layer_add_menu_items ( VikTrwLayer *vtl, GtkMenu *menu, gpointer
   gtk_menu_shell_append (GTK_MENU_SHELL (export_submenu), item);
   gtk_widget_show ( item );
 
-  item = gtk_menu_item_new_with_mnemonic ( _("Export as _KML...") );
-  g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_export_kml), pass_along );
-  gtk_menu_shell_append (GTK_MENU_SHELL (export_submenu), item);
-  gtk_widget_show ( item );
+  if ( a_babel_available () ) {
+    item = gtk_menu_item_new_with_mnemonic ( _("Export as _KML...") );
+    g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_export_kml), pass_along );
+    gtk_menu_shell_append (GTK_MENU_SHELL (export_submenu), item);
+    gtk_widget_show ( item );
+  }
+
+  if ( have_geojson_export ) {
+    item = gtk_menu_item_new_with_mnemonic ( _("Export as GEO_JSON...") );
+    g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_export_geojson), pass_along );
+    gtk_menu_shell_append (GTK_MENU_SHELL (export_submenu), item);
+    gtk_widget_show ( item );
+  }
+
+  if ( a_babel_available () ) {
+    item = gtk_menu_item_new_with_mnemonic ( _("Export via GPSbabel...") );
+    g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_export_babel), pass_along );
+    gtk_menu_shell_append (GTK_MENU_SHELL (export_submenu), item);
+    gtk_widget_show ( item );
+  }
 
   gchar* external1 = g_strdup_printf ( _("Open with External Program_1: %s"), a_vik_get_external_gpx_program_1() );
   item = gtk_menu_item_new_with_mnemonic ( external1 );
@@ -4131,11 +4322,13 @@ static void trw_layer_add_menu_items ( VikTrwLayer *vtl, GtkMenu *menu, gpointer
   gtk_widget_show ( item );
 #endif
 
-  item = gtk_menu_item_new_with_mnemonic ( _("From _File...") );
-  g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_acquire_file_cb), pass_along );
-  gtk_menu_shell_append (GTK_MENU_SHELL (acquire_submenu), item);
-  gtk_widget_set_tooltip_text (item, _("Import File With GPS_Babel..."));
-  gtk_widget_show ( item );
+  if ( a_babel_available () ) {
+    item = gtk_menu_item_new_with_mnemonic ( _("From _File...") );
+    g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_acquire_file_cb), pass_along );
+    gtk_menu_shell_append (GTK_MENU_SHELL (acquire_submenu), item);
+    gtk_widget_set_tooltip_text (item, _("Import File With GPS_Babel..."));
+    gtk_widget_show ( item );
+  }
 
   vik_ext_tool_datasources_add_menu_items_to_menu ( VIK_WINDOW(VIK_GTK_WINDOW_FROM_LAYER(vtl)), GTK_MENU (acquire_submenu) );
 
@@ -4230,6 +4423,10 @@ static void trw_layer_add_menu_items ( VikTrwLayer *vtl, GtkMenu *menu, gpointer
   gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item );
   gtk_widget_show ( item );
   gtk_widget_set_sensitive ( item, (gboolean)(g_hash_table_size (vtl->waypoints)) );
+
+  GtkWidget *external_submenu = create_external_submenu ( menu );
+  // TODO: Should use selected layer's centre - rather than implicitly using the current viewport
+  vik_ext_tools_add_menu_items_to_menu ( VIK_WINDOW(VIK_GTK_WINDOW_FROM_LAYER(vtl)), GTK_MENU (external_submenu), NULL );
 }
 
 // Fake Waypoint UUIDs vi simple increasing integer
@@ -4250,8 +4447,12 @@ void vik_trw_layer_add_waypoint ( VikTrwLayer *vtl, gchar *name, VikWaypoint *wp
 
     GtkTreeIter *iter = g_malloc(sizeof(GtkTreeIter));
 
+    time_t timestamp = 0;
+    if ( wp->has_timestamp )
+      timestamp = wp->timestamp;
+
     // Visibility column always needed for waypoints
-    vik_treeview_add_sublayer ( VIK_LAYER(vtl)->vt, &(vtl->waypoints_iter), iter, name, vtl, GUINT_TO_POINTER(wp_uuid), VIK_TRW_LAYER_SUBLAYER_WAYPOINT, get_wp_sym_small (wp->symbol), TRUE, TRUE );
+    vik_treeview_add_sublayer ( VIK_LAYER(vtl)->vt, &(vtl->waypoints_iter), iter, name, vtl, GUINT_TO_POINTER(wp_uuid), VIK_TRW_LAYER_SUBLAYER_WAYPOINT, get_wp_sym_small (wp->symbol), TRUE, timestamp );
 
     // Actual setting of visibility dependent on the waypoint
     vik_treeview_item_set_visible ( VIK_LAYER(vtl)->vt, iter, wp->visible );
@@ -4284,8 +4485,14 @@ void vik_trw_layer_add_track ( VikTrwLayer *vtl, gchar *name, VikTrack *t )
     }
 
     GtkTreeIter *iter = g_malloc(sizeof(GtkTreeIter));
+
+    time_t timestamp = 0;
+    VikTrackpoint *tpt = vik_track_get_tp_first(t);
+    if ( tpt && tpt->has_timestamp )
+      timestamp = tpt->timestamp;
+
     // Visibility column always needed for tracks
-    vik_treeview_add_sublayer ( VIK_LAYER(vtl)->vt, &(vtl->tracks_iter), iter, name, vtl, GUINT_TO_POINTER(tr_uuid), VIK_TRW_LAYER_SUBLAYER_TRACK, NULL, TRUE, TRUE );
+    vik_treeview_add_sublayer ( VIK_LAYER(vtl)->vt, &(vtl->tracks_iter), iter, name, vtl, GUINT_TO_POINTER(tr_uuid), VIK_TRW_LAYER_SUBLAYER_TRACK, NULL, TRUE, timestamp );
 
     // Actual setting of visibility dependent on the track
     vik_treeview_item_set_visible ( VIK_LAYER(vtl)->vt, iter, t->visible );
@@ -4319,7 +4526,7 @@ void vik_trw_layer_add_route ( VikTrwLayer *vtl, gchar *name, VikTrack *t )
 
     GtkTreeIter *iter = g_malloc(sizeof(GtkTreeIter));
     // Visibility column always needed for routes
-    vik_treeview_add_sublayer ( VIK_LAYER(vtl)->vt, &(vtl->routes_iter), iter, name, vtl, GUINT_TO_POINTER(rt_uuid), VIK_TRW_LAYER_SUBLAYER_ROUTE, NULL, TRUE, TRUE );
+    vik_treeview_add_sublayer ( VIK_LAYER(vtl)->vt, &(vtl->routes_iter), iter, name, vtl, GUINT_TO_POINTER(rt_uuid), VIK_TRW_LAYER_SUBLAYER_ROUTE, NULL, TRUE, 0 ); // Routes don't have times
     // Actual setting of visibility dependent on the route
     vik_treeview_item_set_visible ( VIK_LAYER(vtl)->vt, iter, t->visible );
 
@@ -4388,7 +4595,19 @@ gchar *trw_layer_new_unique_sublayer_name (VikTrwLayer *vtl, gint sublayer_type,
     }
     // If found a name already in use try adding 1 to it and we try again
     if ( id ) {
-      gchar *new_newname = g_strdup_printf("%s#%d", name, i);
+      const gchar *corename = newname;
+      gint newi = i;
+      // If name is already of the form text#N
+      //  set name to text and i to N+1
+      gchar **tokens = g_regex_split_simple ( "#(\\d+)", newname, G_REGEX_CASELESS, 0 );
+      if ( tokens ) {
+        corename = tokens[0];
+        if ( tokens[1] ) {
+          newi = atoi ( tokens[1] ) + 1;
+        }
+      }
+      gchar *new_newname = g_strdup_printf("%s#%d", corename, newi);
+      g_strfreev ( tokens );
       g_free(newname);
       newname = new_newname;
       i++;
@@ -4407,9 +4626,21 @@ void vik_trw_layer_filein_add_waypoint ( VikTrwLayer *vtl, gchar *name, VikWaypo
 
 void vik_trw_layer_filein_add_track ( VikTrwLayer *vtl, gchar *name, VikTrack *tr )
 {
-  if ( vtl->route_finder_append && vtl->route_finder_current_track ) {
+  if ( vtl->route_finder_append && vtl->current_track ) {
     vik_track_remove_dup_points ( tr ); /* make "double point" track work to undo */
-    vik_track_steal_and_append_trackpoints ( vtl->route_finder_current_track, tr );
+
+    // enforce end of current track equal to start of tr
+    VikTrackpoint *cur_end = vik_track_get_tp_last ( vtl->current_track );
+    VikTrackpoint *new_start = vik_track_get_tp_first ( tr );
+    if ( cur_end && new_start ) {
+      if ( ! vik_coord_equals ( &cur_end->coord, &new_start->coord ) ) {
+          vik_track_add_trackpoint ( vtl->current_track,
+                                     vik_trackpoint_copy ( cur_end ),
+                                     FALSE );
+      }
+    }
+
+    vik_track_steal_and_append_trackpoints ( vtl->current_track, tr );
     vik_track_free ( tr );
     vtl->route_finder_append = FALSE; /* this means we have added it */
   } else {
@@ -4437,34 +4668,31 @@ static void trw_layer_enum_item ( gpointer id, GList **tr, GList **l )
  */
 static void trw_layer_move_item ( VikTrwLayer *vtl_src, VikTrwLayer *vtl_dest, gpointer id, gint type )
 {
+  // When an item is moved the name is checked to see if it clashes with an existing name
+  //  in the destination layer and if so then it is allocated a new name
+
   // TODO reconsider strategy when moving within layer (if anything...)
-  gboolean rename = ( vtl_src != vtl_dest );
-  if ( ! rename )
+  if ( vtl_src == vtl_dest )
     return;
 
   if (type == VIK_TRW_LAYER_SUBLAYER_TRACK) {
     VikTrack *trk = g_hash_table_lookup ( vtl_src->tracks, id );
 
-    gchar *newname;
-    if ( rename )
-      newname = trw_layer_new_unique_sublayer_name ( vtl_dest, type, trk->name );
-    else
-      newname = g_strdup ( trk->name );
+    gchar *newname = trw_layer_new_unique_sublayer_name ( vtl_dest, type, trk->name );
 
     VikTrack *trk2 = vik_track_copy ( trk, TRUE );
     vik_trw_layer_add_track ( vtl_dest, newname, trk2 );
     g_free ( newname );
     vik_trw_layer_delete_track ( vtl_src, trk );
+    // Reset layer timestamps in case they have now changed
+    vik_treeview_item_set_timestamp ( vtl_dest->vl.vt, &vtl_dest->vl.iter, trw_layer_get_timestamp(vtl_dest) );
+    vik_treeview_item_set_timestamp ( vtl_src->vl.vt, &vtl_src->vl.iter, trw_layer_get_timestamp(vtl_src) );
   }
 
   if (type == VIK_TRW_LAYER_SUBLAYER_ROUTE) {
     VikTrack *trk = g_hash_table_lookup ( vtl_src->routes, id );
 
-    gchar *newname;
-    if ( rename )
-      newname = trw_layer_new_unique_sublayer_name ( vtl_dest, type, trk->name );
-    else
-      newname = g_strdup ( trk->name );
+    gchar *newname = trw_layer_new_unique_sublayer_name ( vtl_dest, type, trk->name );
 
     VikTrack *trk2 = vik_track_copy ( trk, TRUE );
     vik_trw_layer_add_route ( vtl_dest, newname, trk2 );
@@ -4475,11 +4703,7 @@ static void trw_layer_move_item ( VikTrwLayer *vtl_src, VikTrwLayer *vtl_dest, g
   if (type == VIK_TRW_LAYER_SUBLAYER_WAYPOINT) {
     VikWaypoint *wp = g_hash_table_lookup ( vtl_src->waypoints, id );
 
-    gchar *newname;
-    if ( rename )
-      newname = trw_layer_new_unique_sublayer_name ( vtl_dest, type, wp->name );
-    else
-      newname = g_strdup ( wp->name );
+    gchar *newname = trw_layer_new_unique_sublayer_name ( vtl_dest, type, wp->name );
 
     VikWaypoint *wp2 = vik_waypoint_copy ( wp );
     vik_trw_layer_add_waypoint ( vtl_dest, newname, wp2 );
@@ -4489,6 +4713,9 @@ static void trw_layer_move_item ( VikTrwLayer *vtl_src, VikTrwLayer *vtl_dest, g
     // Recalculate bounds even if not renamed as maybe dragged between layers
     trw_layer_calculate_bounds_waypoints ( vtl_dest );
     trw_layer_calculate_bounds_waypoints ( vtl_src );
+    // Reset layer timestamps in case they have now changed
+    vik_treeview_item_set_timestamp ( vtl_dest->vl.vt, &vtl_dest->vl.iter, trw_layer_get_timestamp(vtl_dest) );
+    vik_treeview_item_set_timestamp ( vtl_src->vl.vt, &vtl_src->vl.iter, trw_layer_get_timestamp(vtl_src) );
   }
 }
 
@@ -4543,7 +4770,6 @@ gboolean trw_layer_track_find_uuid ( const gpointer id, const VikTrack *trk, gpo
 gboolean vik_trw_layer_delete_track ( VikTrwLayer *vtl, VikTrack *trk )
 {
   gboolean was_visible = FALSE;
-
   if ( trk && trk->name ) {
 
     if ( trk == vtl->current_track ) {
@@ -4551,13 +4777,11 @@ gboolean vik_trw_layer_delete_track ( VikTrwLayer *vtl, VikTrack *trk )
       vtl->current_tp_track = NULL;
       vtl->current_tp_id = NULL;
       vtl->moving_tp = FALSE;
+      vtl->route_finder_started = FALSE;
     }
 
     was_visible = trk->visible;
 
-    if ( trk == vtl->route_finder_current_track )
-      vtl->route_finder_current_track = NULL;
-
     if ( trk == vtl->route_finder_added_track )
       vtl->route_finder_added_track = NULL;
 
@@ -4566,7 +4790,7 @@ gboolean vik_trw_layer_delete_track ( VikTrwLayer *vtl, VikTrack *trk )
     udata.uuid = NULL;
 
     // Hmmm, want key of it
-    gpointer *trkf = g_hash_table_find ( vtl->tracks, (GHRFunc) trw_layer_track_find_uuid, &udata );
+    gpointer trkf = g_hash_table_find ( vtl->tracks, (GHRFunc) trw_layer_track_find_uuid, &udata );
 
     if ( trkf && udata.uuid ) {
       /* could be current_tp, so we have to check */
@@ -4584,6 +4808,8 @@ gboolean vik_trw_layer_delete_track ( VikTrwLayer *vtl, VikTrack *trk )
           vik_treeview_item_delete ( VIK_LAYER(vtl)->vt, &(vtl->tracks_iter) );
        }
       }
+      // Incase it was selected (no item delete signal ATM)
+      vik_window_clear_highlight ( VIK_WINDOW(VIK_GTK_WINDOW_FROM_LAYER(vtl)) );
     }
   }
   return was_visible;
@@ -4604,9 +4830,6 @@ gboolean vik_trw_layer_delete_route ( VikTrwLayer *vtl, VikTrack *trk )
 
     was_visible = trk->visible;
 
-    if ( trk == vtl->route_finder_current_track )
-      vtl->route_finder_current_track = NULL;
-
     if ( trk == vtl->route_finder_added_track )
       vtl->route_finder_added_track = NULL;
 
@@ -4615,7 +4838,7 @@ gboolean vik_trw_layer_delete_route ( VikTrwLayer *vtl, VikTrack *trk )
     udata.uuid = NULL;
 
     // Hmmm, want key of it
-    gpointer *trkf = g_hash_table_find ( vtl->routes, (GHRFunc) trw_layer_track_find_uuid, &udata );
+    gpointer trkf = g_hash_table_find ( vtl->routes, (GHRFunc) trw_layer_track_find_uuid, &udata );
 
     if ( trkf && udata.uuid ) {
       /* could be current_tp, so we have to check */
@@ -4633,6 +4856,8 @@ gboolean vik_trw_layer_delete_route ( VikTrwLayer *vtl, VikTrack *trk )
           vik_treeview_item_delete ( VIK_LAYER(vtl)->vt, &(vtl->routes_iter) );
         }
       }
+      // Incase it was selected (no item delete signal ATM)
+      vik_window_clear_highlight ( VIK_WINDOW(VIK_GTK_WINDOW_FROM_LAYER(vtl)) );
     }
   }
   return was_visible;
@@ -4657,7 +4882,7 @@ static gboolean trw_layer_delete_waypoint ( VikTrwLayer *vtl, VikWaypoint *wp )
     udata.uuid = NULL;
 
     // Hmmm, want key of it
-    gpointer *wpf = g_hash_table_find ( vtl->waypoints, (GHRFunc) trw_layer_waypoint_find_uuid, (gpointer) &udata );
+    gpointer wpf = g_hash_table_find ( vtl->waypoints, (GHRFunc) trw_layer_waypoint_find_uuid, (gpointer) &udata );
 
     if ( wpf && udata.uuid ) {
       GtkTreeIter *it = g_hash_table_lookup ( vtl->waypoints_iters, udata.uuid );
@@ -4674,6 +4899,8 @@ static gboolean trw_layer_delete_waypoint ( VikTrwLayer *vtl, VikWaypoint *wp )
           vik_treeview_item_delete ( VIK_LAYER(vtl)->vt, &(vtl->waypoints_iter) );
        }
       }
+      // Incase it was selected (no item delete signal ATM)
+      vik_window_clear_highlight ( VIK_WINDOW(VIK_GTK_WINDOW_FROM_LAYER(vtl)) );
     }
 
   }
@@ -4707,7 +4934,7 @@ static gboolean trw_layer_delete_waypoint_by_name ( VikTrwLayer *vtl, const gcha
   udata.uuid = NULL;
 
   // Hmmm, want key of it
-  gpointer *wpf = g_hash_table_find ( vtl->waypoints, (GHRFunc) trw_layer_waypoint_find_uuid_by_name, (gpointer) &udata );
+  gpointer wpf = g_hash_table_find ( vtl->waypoints, (GHRFunc) trw_layer_waypoint_find_uuid_by_name, (gpointer) &udata );
 
   vik_waypoint_free (udata.wp);
 
@@ -4748,7 +4975,7 @@ static gboolean trw_layer_delete_track_by_name ( VikTrwLayer *vtl, const gchar *
   udata.uuid = NULL;
 
   // Hmmm, want key of it
-  gpointer *trkf = g_hash_table_find ( ht_tracks, (GHRFunc) trw_layer_track_find_uuid_by_name, &udata );
+  gpointer trkf = g_hash_table_find ( ht_tracks, (GHRFunc) trw_layer_track_find_uuid_by_name, &udata );
 
   vik_track_free (udata.trk);
 
@@ -4773,7 +5000,6 @@ void vik_trw_layer_delete_all_routes ( VikTrwLayer *vtl )
 {
 
   vtl->current_track = NULL;
-  vtl->route_finder_current_track = NULL;
   vtl->route_finder_added_track = NULL;
   if (vtl->current_tp_track)
     trw_layer_cancel_current_tp(vtl, FALSE);
@@ -4791,7 +5017,6 @@ void vik_trw_layer_delete_all_tracks ( VikTrwLayer *vtl )
 {
 
   vtl->current_track = NULL;
-  vtl->route_finder_current_track = NULL;
   vtl->route_finder_added_track = NULL;
   if (vtl->current_tp_track)
     trw_layer_cancel_current_tp(vtl, FALSE);
@@ -4868,6 +5093,9 @@ static void trw_layer_delete_item ( menu_array_sublayer values )
             wp->name ) )
           return;
       was_visible = trw_layer_delete_waypoint ( vtl, wp );
+      trw_layer_calculate_bounds_waypoints ( vtl );
+      // Reset layer timestamp in case it has now changed
+      vik_treeview_item_set_timestamp ( vtl->vl.vt, &vtl->vl.iter, trw_layer_get_timestamp(vtl) );
     }
   }
   else if ( GPOINTER_TO_INT (values[MA_SUBTYPE]) == VIK_TRW_LAYER_SUBLAYER_TRACK )
@@ -4881,6 +5109,8 @@ static void trw_layer_delete_item ( menu_array_sublayer values )
                                  trk->name ) )
           return;
       was_visible = vik_trw_layer_delete_track ( vtl, trk );
+      // Reset layer timestamp in case it has now changed
+      vik_treeview_item_set_timestamp ( vtl->vl.vt, &vtl->vl.iter, trw_layer_get_timestamp(vtl) );
     }
   }
   else
@@ -4913,7 +5143,7 @@ void trw_layer_waypoint_rename ( VikTrwLayer *vtl, VikWaypoint *wp, const gchar
   udataU.uuid = NULL;
 
   // Need key of it for treeview update
-  gpointer *wpf = g_hash_table_find ( vtl->waypoints, (GHRFunc) trw_layer_waypoint_find_uuid, &udataU );
+  gpointer wpf = g_hash_table_find ( vtl->waypoints, (GHRFunc) trw_layer_waypoint_find_uuid, &udataU );
 
   if ( wpf && udataU.uuid ) {
     GtkTreeIter *it = g_hash_table_lookup ( vtl->waypoints_iters, udataU.uuid );
@@ -4936,7 +5166,7 @@ void trw_layer_waypoint_reset_icon ( VikTrwLayer *vtl, VikWaypoint *wp )
   udataU.uuid = NULL;
 
   // Need key of it for treeview update
-  gpointer *wpf = g_hash_table_find ( vtl->waypoints, (GHRFunc) trw_layer_waypoint_find_uuid, &udataU );
+  gpointer wpf = g_hash_table_find ( vtl->waypoints, (GHRFunc) trw_layer_waypoint_find_uuid, &udataU );
 
   if ( wpf && udataU.uuid ) {
     GtkTreeIter *it = g_hash_table_lookup ( vtl->waypoints_iters, udataU.uuid );
@@ -5023,7 +5253,7 @@ void trw_layer_update_treeview ( VikTrwLayer *vtl, VikTrack *trk )
   udata.trk  = trk;
   udata.uuid = NULL;
 
-  gpointer *trkf = NULL;
+  gpointer trkf = NULL;
   if ( trk->is_route )
     trkf = g_hash_table_find ( vtl->routes, (GHRFunc) trw_layer_track_find_uuid, &udata );
   else
@@ -5059,13 +5289,13 @@ void trw_layer_update_treeview ( VikTrwLayer *vtl, VikTrack *trk )
 static void goto_coord ( gpointer *vlp, gpointer vl, gpointer vvp, const VikCoord *coord )
 {
   if ( vlp ) {
-    vik_viewport_set_center_coord ( vik_layers_panel_get_viewport (VIK_LAYERS_PANEL(vlp)), coord );
+    vik_viewport_set_center_coord ( vik_layers_panel_get_viewport (VIK_LAYERS_PANEL(vlp)), coord, TRUE );
     vik_layers_panel_emit_update ( VIK_LAYERS_PANEL(vlp) );
   }
   else {
     /* since vlp not set, vl & vvp should be valid instead! */
     if ( vl && vvp ) {
-      vik_viewport_set_center_coord ( VIK_VIEWPORT(vvp), coord );
+      vik_viewport_set_center_coord ( VIK_VIEWPORT(vvp), coord, TRUE );
       vik_layer_emit_update ( VIK_LAYER(vl) );
     }
   }
@@ -5169,6 +5399,19 @@ static void trw_layer_anonymize_times ( menu_array_sublayer values )
     vik_track_anonymize_times ( track );
 }
 
+static void trw_layer_interpolate_times ( menu_array_sublayer values )
+{
+  VikTrwLayer *vtl = (VikTrwLayer *)values[MA_VTL];
+  VikTrack *track;
+  if ( GPOINTER_TO_INT (values[MA_SUBTYPE]) == VIK_TRW_LAYER_SUBLAYER_ROUTE )
+    track = (VikTrack *) g_hash_table_lookup ( vtl->routes, values[MA_SUBLAYER_ID] );
+  else
+    track = (VikTrack *) g_hash_table_lookup ( vtl->tracks, values[MA_SUBLAYER_ID] );
+
+  if ( track )
+    vik_track_interpolate_times ( track );
+}
+
 static void trw_layer_extend_track_end ( menu_array_sublayer values )
 {
   VikTrwLayer *vtl = VIK_TRW_LAYER(values[MA_VTL]);
@@ -5197,15 +5440,13 @@ static void trw_layer_extend_track_end_route_finder ( menu_array_sublayer values
   VikTrack *track = g_hash_table_lookup ( vtl->routes, values[MA_SUBLAYER_ID] );
   if ( !track )
     return;
-  if ( !track->trackpoints )
-    return;
 
   vik_window_enable_layer_tool ( VIK_WINDOW(VIK_GTK_WINDOW_FROM_LAYER(vtl)), VIK_LAYER_TRW, TOOL_ROUTE_FINDER );
-  vtl->route_finder_coord = vik_track_get_tp_last(track)->coord;
-  vtl->route_finder_current_track = track;
+  vtl->current_track = track;
   vtl->route_finder_started = TRUE;
 
-  goto_coord ( values[MA_VLP], vtl, values[MA_VVP], &vtl->route_finder_coord );
+  if ( track->trackpoints )
+      goto_coord ( values[MA_VLP], vtl, values[MA_VVP], &vik_track_get_tp_last(track)->coord );
 }
 
 /**
@@ -5583,7 +5824,7 @@ static void trw_layer_edit_trackpoint ( menu_array_sublayer values )
  */
 typedef struct {
   GList **result;
-  GList  *exclude;
+  VikTrack *exclude;
   gboolean with_timestamps;
 } twt_udata;
 static void find_tracks_with_timestamp_type(gpointer key, gpointer value, gpointer udata)
@@ -5591,7 +5832,7 @@ static void find_tracks_with_timestamp_type(gpointer key, gpointer value, gpoint
   twt_udata *user_data = udata;
   VikTrackpoint *p1, *p2;
   VikTrack *trk = VIK_TRACK(value);
-  if (trk == (VikTrack *)user_data->exclude) {
+  if (trk == user_data->exclude) {
     return;
   }
 
@@ -5615,34 +5856,41 @@ static void find_tracks_with_timestamp_type(gpointer key, gpointer value, gpoint
   *(user_data->result) = g_list_prepend(*(user_data->result), key);
 }
 
-/* called for each key in track hash table. if original track user_data[1] is close enough
- * to the passed one, add it to list in user_data[0] 
+/**
+ * find_nearby_tracks_by_time:
+ *
+ * Called for each track in track hash table.
+ *  If the original track (in user_data[1]) is close enough (threshold period in user_data[2])
+ *  to the current track, then the current track is added to the list in user_data[0]
  */
 static void find_nearby_tracks_by_time (gpointer key, gpointer value, gpointer user_data)
 {
-  time_t t1, t2;
-  VikTrackpoint *p1, *p2;
   VikTrack *trk = VIK_TRACK(value);
 
   GList **nearby_tracks = ((gpointer *)user_data)[0];
-  GList *tpoints = ((gpointer *)user_data)[1];
+  VikTrack *orig_trk = VIK_TRACK(((gpointer *)user_data)[1]);
+
+  if ( !orig_trk || !orig_trk->trackpoints )
+    return;
 
   /* outline: 
    * detect reasons for not merging, and return
    * if no reason is found not to merge, then do it.
    */
 
+  twt_udata *udata = user_data;
   // Exclude the original track from the compiled list
-  if (trk->trackpoints == tpoints) {
+  if (trk == udata->exclude) {
     return;
   }
 
-  t1 = vik_track_get_tp_first(trk)->timestamp;
-  t2 = vik_track_get_tp_last(trk)->timestamp;
+  time_t t1 = vik_track_get_tp_first(orig_trk)->timestamp;
+  time_t t2 = vik_track_get_tp_last(orig_trk)->timestamp;
 
   if (trk->trackpoints) {
-    p1 = vik_track_get_tp_first(trk);
-    p2 = vik_track_get_tp_last(trk);
+
+    VikTrackpoint *p1 = vik_track_get_tp_first(trk);
+    VikTrackpoint *p2 = vik_track_get_tp_last(trk);
 
     if (!p1->has_timestamp || !p2->has_timestamp) {
       //g_print("no timestamp\n");
@@ -5651,11 +5899,11 @@ static void find_nearby_tracks_by_time (gpointer key, gpointer value, gpointer u
 
     guint threshold = GPOINTER_TO_UINT (((gpointer *)user_data)[2]);
     //g_print("Got track named %s, times %d, %d\n", trk->name, p1->timestamp, p2->timestamp);
-    if (! (abs(t1 - p2->timestamp) < threshold ||
-       /*  p1 p2      t1 t2 */
-          abs(p1->timestamp - t2) < threshold)
-       /*  t1 t2      p1 p2 */
-       ) {
+    if (! (labs(t1 - p2->timestamp) < threshold ||
+      /*  p1 p2      t1 t2 */
+      labs(p1->timestamp - t2) < threshold)
+      /*  t1 t2      p1 p2 */
+    ) {
       return;
     }
   }
@@ -5728,7 +5976,7 @@ static void trw_layer_merge_with_other ( menu_array_sublayer values )
 
   twt_udata udata;
   udata.result = &other_tracks;
-  udata.exclude = track->trackpoints;
+  udata.exclude = track;
   // Allow merging with 'similar' time type time tracks
   // i.e. either those times, or those without
   udata.with_timestamps = vik_track_get_tp_first(track)->has_timestamp;
@@ -5798,7 +6046,7 @@ static void trw_layer_sorted_track_id_by_name_list_exclude_self (const gpointer
   twt_udata *user_data = udata;
 
   // Skip self
-  if (trk->trackpoints == user_data->exclude) {
+  if (trk == user_data->exclude) {
     return;
   }
 
@@ -5834,7 +6082,7 @@ static void trw_layer_append_track ( menu_array_sublayer values )
   // TODO: Need to consider how to work best when we can have multiple tracks the same name...
   twt_udata udata;
   udata.result = &other_tracks_names;
-  udata.exclude = trk->trackpoints;
+  udata.exclude = trk;
 
   g_hash_table_foreach(ght_tracks, (GHFunc) trw_layer_sorted_track_id_by_name_list_exclude_self, (gpointer)&udata);
 
@@ -5911,7 +6159,7 @@ static void trw_layer_append_other ( menu_array_sublayer values )
   // TODO: Need to consider how to work best when we can have multiple tracks the same name...
   twt_udata udata;
   udata.result = &other_tracks_names;
-  udata.exclude = trk->trackpoints;
+  udata.exclude = trk;
 
   g_hash_table_foreach(ght_others, (GHFunc) trw_layer_sorted_track_id_by_name_list_exclude_self, (gpointer)&udata);
 
@@ -6004,7 +6252,7 @@ static void trw_layer_merge_by_timestamp ( menu_array_sublayer values )
 
   twt_udata udata;
   udata.result = &tracks_with_timestamp;
-  udata.exclude = orig_trk->trackpoints;
+  udata.exclude = orig_trk;
   udata.with_timestamps = TRUE;
   g_hash_table_foreach(vtl->tracks, find_tracks_with_timestamp_type, (gpointer)&udata);
   tracks_with_timestamp = g_list_reverse(tracks_with_timestamp);
@@ -6044,7 +6292,7 @@ static void trw_layer_merge_by_timestamp ( menu_array_sublayer values )
     }
 
     params[0] = &nearby_tracks;
-    params[1] = (gpointer)trps;
+    params[1] = orig_trk;
     params[2] = GUINT_TO_POINTER (threshold_in_minutes*60); // In seconds
 
     /* get a list of adjacent-in-time tracks */
@@ -6111,7 +6359,7 @@ static void trw_layer_split_at_selected_trackpoint ( VikTrwLayer *vtl, gint subt
       udata.uuid = NULL;
 
       // Also need id of newly created track
-      gpointer *trkf;
+      gpointer trkf;
       if ( tr->is_route )
          trkf = g_hash_table_find ( vtl->routes, (GHRFunc) trw_layer_track_find_uuid, &udata );
       else
@@ -6517,6 +6765,190 @@ static void trw_layer_reverse ( menu_array_sublayer values )
   vik_layer_emit_update ( VIK_LAYER(vtl) );
 }
 
+/**
+ * Open a program at the specified date
+ * Mainly for RedNotebook - http://rednotebook.sourceforge.net/
+ * But could work with any program that accepts a command line of --date=<date>
+ * FUTURE: Allow configuring of command line options + date format
+ */
+static void trw_layer_diary_open ( VikTrwLayer *vtl, const gchar *date_str )
+{
+  GError *err = NULL;
+  gchar *cmd = g_strdup_printf ( "%s %s%s", diary_program, "--date=", date_str );
+  if ( ! g_spawn_command_line_async ( cmd, &err ) ) {
+    a_dialog_error_msg_extra ( VIK_GTK_WINDOW_FROM_LAYER(vtl), _("Could not launch %s to open file."), diary_program );
+    g_error_free ( err );
+  }
+  g_free ( cmd );
+}
+
+/**
+ * Open a diary at the date of the track or waypoint
+ */
+static void trw_layer_diary ( menu_array_sublayer values )
+{
+  VikTrwLayer *vtl = VIK_TRW_LAYER(values[MA_VTL]);
+
+  if ( GPOINTER_TO_INT(values[MA_SUBTYPE]) == VIK_TRW_LAYER_SUBLAYER_TRACK ) {
+    VikTrack *trk = (VikTrack *) g_hash_table_lookup ( vtl->tracks, values[MA_SUBLAYER_ID] );
+    if ( ! trk )
+      return;
+
+    gchar date_buf[20];
+    date_buf[0] = '\0';
+    if ( trk->trackpoints && VIK_TRACKPOINT(trk->trackpoints->data)->has_timestamp ) {
+      strftime (date_buf, sizeof(date_buf), "%Y-%m-%d", gmtime(&(VIK_TRACKPOINT(trk->trackpoints->data)->timestamp)));
+      trw_layer_diary_open ( vtl, date_buf );
+    }
+    else
+      a_dialog_info_msg ( VIK_GTK_WINDOW_FROM_LAYER(vtl), _("This track has no date information.") );
+  }
+  else if ( GPOINTER_TO_INT(values[MA_SUBTYPE]) == VIK_TRW_LAYER_SUBLAYER_WAYPOINT ) {
+    VikWaypoint *wpt = (VikWaypoint *) g_hash_table_lookup ( vtl->waypoints, values[MA_SUBLAYER_ID] );
+    if ( ! wpt )
+      return;
+
+    gchar date_buf[20];
+    date_buf[0] = '\0';
+    if ( wpt->has_timestamp ) {
+      strftime (date_buf, sizeof(date_buf), "%Y-%m-%d", gmtime(&(wpt->timestamp)));
+      trw_layer_diary_open ( vtl, date_buf );
+    }
+    else
+      a_dialog_info_msg ( VIK_GTK_WINDOW_FROM_LAYER(vtl), _("This waypoint has no date information.") );
+  }
+}
+
+/**
+ * Open a program at the specified date
+ * Mainly for Stellarium - http://stellarium.org/
+ * But could work with any program that accepts the same command line options...
+ * FUTURE: Allow configuring of command line options + format or parameters
+ */
+static void trw_layer_astro_open ( VikTrwLayer *vtl, const gchar *date_str, const gchar *time_str, const gchar *lat_str, const gchar *lon_str, const gchar *alt_str )
+{
+  GError *err = NULL;
+  gchar *tmp;
+  gint fd = g_file_open_tmp ( "vik-astro-XXXXXX.ini", &tmp, &err );
+  if (fd < 0) {
+    g_warning ( "%s: Failed to open temporary file: %s", __FUNCTION__, err->message );
+    g_clear_error ( &err );
+    return;
+  }
+  gchar *cmd = g_strdup_printf ( "%s %s %s %s %s %s %s %s %s %s %s %s %s %s",
+                                  astro_program, "-c", tmp, "--full-screen no", "--sky-date", date_str, "--sky-time", time_str, "--latitude", lat_str, "--longitude", lon_str, "--altitude", alt_str );
+  g_warning ( "%s", cmd );
+  if ( ! g_spawn_command_line_async ( cmd, &err ) ) {
+    a_dialog_error_msg_extra ( VIK_GTK_WINDOW_FROM_LAYER(vtl), _("Could not launch %s"), astro_program );
+    g_warning ( "%s", err->message );
+    g_error_free ( err );
+  }
+  util_add_to_deletion_list ( tmp );
+  g_free ( tmp );
+  g_free ( cmd );
+}
+
+// Format of stellarium lat & lon seems designed to be particularly awkward
+//  who uses ' & " in the parameters for the command line?!
+// -1d4'27.48"
+// +53d58'16.65"
+static gchar *convert_to_dms ( gdouble dec )
+{
+  gdouble tmp;
+  gchar sign_c = ' ';
+  gint val_d, val_m;
+  gdouble val_s;
+  gchar *result = NULL;
+
+  if ( dec > 0 )
+    sign_c = '+';
+  else if ( dec < 0 )
+    sign_c = '-';
+  else // Nul value
+    sign_c = ' ';
+
+  // Degrees
+  tmp = fabs(dec);
+  val_d = (gint)tmp;
+
+  // Minutes
+  tmp = (tmp - val_d) * 60;
+  val_m = (gint)tmp;
+
+  // Seconds
+  val_s = (tmp - val_m) * 60;
+
+  // Format
+  result = g_strdup_printf ( "%c%dd%d\\\'%.4f\\\"", sign_c, val_d, val_m, val_s );
+  return result;
+}
+
+/**
+ * Open an astronomy program at the date & position of the track center, trackpoint or waypoint
+ */
+static void trw_layer_astro ( menu_array_sublayer values )
+{
+  VikTrwLayer *vtl = VIK_TRW_LAYER(values[MA_VTL]);
+
+  if ( GPOINTER_TO_INT(values[MA_SUBTYPE]) == VIK_TRW_LAYER_SUBLAYER_TRACK ) {
+    VikTrack *trk = (VikTrack *) g_hash_table_lookup ( vtl->tracks, values[MA_SUBLAYER_ID] );
+    if ( ! trk )
+      return;
+
+    VikTrackpoint *tp = NULL;
+    if ( vtl->current_tpl )
+      // Current Trackpoint
+      tp = VIK_TRACKPOINT(vtl->current_tpl->data);
+    else if ( trk->trackpoints )
+      // Otherwise first trackpoint
+      tp = VIK_TRACKPOINT(trk->trackpoints->data);
+    else
+      // Give up
+      return;
+
+    if ( tp->has_timestamp ) {
+      gchar date_buf[20];
+      strftime (date_buf, sizeof(date_buf), "%Y%m%d", gmtime(&(tp->timestamp)));
+      gchar time_buf[20];
+      strftime (time_buf, sizeof(time_buf), "%H:%M:%S", gmtime(&(tp->timestamp)));
+      struct LatLon ll;
+      vik_coord_to_latlon ( &tp->coord, &ll );
+      gchar *lat_str = convert_to_dms ( ll.lat );
+      gchar *lon_str = convert_to_dms ( ll.lon );
+      gchar alt_buf[20];
+      snprintf (alt_buf, sizeof(alt_buf), "%d", (gint)round(tp->altitude) );
+      trw_layer_astro_open ( vtl, date_buf, time_buf, lat_str, lon_str, alt_buf);
+      g_free ( lat_str );
+      g_free ( lon_str );
+    }
+    else
+      a_dialog_info_msg ( VIK_GTK_WINDOW_FROM_LAYER(vtl), _("This track has no date information.") );
+  }
+  else if ( GPOINTER_TO_INT(values[MA_SUBTYPE]) == VIK_TRW_LAYER_SUBLAYER_WAYPOINT ) {
+    VikWaypoint *wpt = (VikWaypoint *) g_hash_table_lookup ( vtl->waypoints, values[MA_SUBLAYER_ID] );
+    if ( ! wpt )
+      return;
+
+    if ( wpt->has_timestamp ) {
+      gchar date_buf[20];
+      strftime (date_buf, sizeof(date_buf), "%Y%m%d", gmtime(&(wpt->timestamp)));
+      gchar time_buf[20];
+      strftime (time_buf, sizeof(time_buf), "%H:%M:%S", gmtime(&(wpt->timestamp)));
+      struct LatLon ll;
+      vik_coord_to_latlon ( &wpt->coord, &ll );
+      gchar *lat_str = convert_to_dms ( ll.lat );
+      gchar *lon_str = convert_to_dms ( ll.lon );
+      gchar alt_buf[20];
+      snprintf (alt_buf, sizeof(alt_buf), "%d", (gint)round(wpt->altitude) );
+      trw_layer_astro_open ( vtl, date_buf, time_buf, lat_str, lon_str, alt_buf );
+      g_free ( lat_str );
+      g_free ( lon_str );
+    }
+    else
+      a_dialog_info_msg ( VIK_GTK_WINDOW_FROM_LAYER(vtl), _("This waypoint has no date information.") );
+  }
+}
+
 /**
  * Similar to trw_layer_enum_item, but this uses a sorted method
  */
@@ -6659,7 +7091,7 @@ static void vik_trw_layer_uniquify_tracks ( VikTrwLayer *vtl, VikLayersPanel *vl
     udataU.uuid = NULL;
 
     // Need want key of it for treeview update
-    gpointer *trkf = g_hash_table_find ( track_table, (GHRFunc) trw_layer_track_find_uuid, &udataU );
+    gpointer trkf = g_hash_table_find ( track_table, (GHRFunc) trw_layer_track_find_uuid, &udataU );
 
     if ( trkf && udataU.uuid ) {
 
@@ -6672,11 +7104,12 @@ static void vik_trw_layer_uniquify_tracks ( VikTrwLayer *vtl, VikLayersPanel *vl
       if ( it ) {
         vik_treeview_item_set_name ( VIK_LAYER(vtl)->vt, it, newname );
         if ( ontrack )
-          vik_treeview_sort_children ( VIK_LAYER(vtl)->vt, &(vtl->tracks_iter), vtl->wp_sort_order );
-       else
-          vik_treeview_sort_children ( VIK_LAYER(vtl)->vt, &(vtl->routes_iter), vtl->wp_sort_order );
+          vik_treeview_sort_children ( VIK_LAYER(vtl)->vt, &(vtl->tracks_iter), vtl->track_sort_order );
+        else
+          vik_treeview_sort_children ( VIK_LAYER(vtl)->vt, &(vtl->routes_iter), vtl->track_sort_order );
       }
     }
+    g_free ( newname );
 
     // Start trying to find same names again...
     track_names = NULL;
@@ -6693,50 +7126,50 @@ static void vik_trw_layer_uniquify_tracks ( VikTrwLayer *vtl, VikLayersPanel *vl
   vik_layers_panel_emit_update ( vlp );
 }
 
-static void trw_layer_sort_order_a2z ( menu_array_sublayer values )
+static void trw_layer_sort_order_specified ( VikTrwLayer *vtl, guint sublayer_type, vik_layer_sort_order_t order )
 {
-  VikTrwLayer *vtl = VIK_TRW_LAYER(values[MA_VTL]);
   GtkTreeIter *iter;
 
-  switch (GPOINTER_TO_INT (values[MA_SUBTYPE])) {
+  switch (sublayer_type) {
   case VIK_TRW_LAYER_SUBLAYER_TRACKS:
     iter = &(vtl->tracks_iter);
-    vtl->track_sort_order = VL_SO_ALPHABETICAL_ASCENDING;
+    vtl->track_sort_order = order;
     break;
   case VIK_TRW_LAYER_SUBLAYER_ROUTES:
     iter = &(vtl->routes_iter);
-    vtl->track_sort_order = VL_SO_ALPHABETICAL_ASCENDING;
+    vtl->track_sort_order = order;
     break;
   default: // VIK_TRW_LAYER_SUBLAYER_WAYPOINTS:
     iter = &(vtl->waypoints_iter);
-    vtl->wp_sort_order = VL_SO_ALPHABETICAL_ASCENDING;
+    vtl->wp_sort_order = order;
     break;
   }
 
-  vik_treeview_sort_children ( VIK_LAYER(vtl)->vt, iter, VL_SO_ALPHABETICAL_ASCENDING );
+  vik_treeview_sort_children ( VIK_LAYER(vtl)->vt, iter, order );
+}
+
+static void trw_layer_sort_order_a2z ( menu_array_sublayer values )
+{
+  VikTrwLayer *vtl = VIK_TRW_LAYER(values[MA_VTL]);
+  trw_layer_sort_order_specified ( vtl, GPOINTER_TO_INT(values[MA_SUBTYPE]), VL_SO_ALPHABETICAL_ASCENDING );
 }
 
 static void trw_layer_sort_order_z2a ( menu_array_sublayer values )
 {
   VikTrwLayer *vtl = VIK_TRW_LAYER(values[MA_VTL]);
-  GtkTreeIter *iter;
+  trw_layer_sort_order_specified ( vtl, GPOINTER_TO_INT(values[MA_SUBTYPE]), VL_SO_ALPHABETICAL_DESCENDING );
+}
 
-  switch (GPOINTER_TO_INT (values[MA_SUBTYPE])) {
-  case VIK_TRW_LAYER_SUBLAYER_TRACKS:
-    iter = &(vtl->tracks_iter);
-    vtl->track_sort_order = VL_SO_ALPHABETICAL_DESCENDING;
-    break;
-  case VIK_TRW_LAYER_SUBLAYER_ROUTES:
-    iter = &(vtl->routes_iter);
-    vtl->track_sort_order = VL_SO_ALPHABETICAL_DESCENDING;
-    break;
-  default: // VIK_TRW_LAYER_SUBLAYER_WAYPOINTS:
-    iter = &(vtl->waypoints_iter);
-    vtl->wp_sort_order = VL_SO_ALPHABETICAL_DESCENDING;
-    break;
-  }
+static void trw_layer_sort_order_timestamp_ascend ( menu_array_sublayer values )
+{
+  VikTrwLayer *vtl = VIK_TRW_LAYER(values[MA_VTL]);
+  trw_layer_sort_order_specified ( vtl, GPOINTER_TO_INT(values[MA_SUBTYPE]), VL_SO_DATE_ASCENDING );
+}
 
-  vik_treeview_sort_children ( VIK_LAYER(vtl)->vt, iter, VL_SO_ALPHABETICAL_DESCENDING );
+static void trw_layer_sort_order_timestamp_descend ( menu_array_sublayer values )
+{
+  VikTrwLayer *vtl = VIK_TRW_LAYER(values[MA_VTL]);
+  trw_layer_sort_order_specified ( vtl, GPOINTER_TO_INT(values[MA_SUBTYPE]), VL_SO_DATE_DESCENDING );
 }
 
 /**
@@ -6782,6 +7215,9 @@ static void trw_layer_delete_tracks_from_selection ( menu_array_layer values )
       trw_layer_delete_track_by_name (vtl, l->data, vtl->tracks);
     }
     g_list_free(delete_list);
+    // Reset layer timestamps in case they have now changed
+    vik_treeview_item_set_timestamp ( vtl->vl.vt, &vtl->vl.iter, trw_layer_get_timestamp(vtl) );
+
     vik_layer_emit_update( VIK_LAYER(vtl) );
   }
 }
@@ -6932,6 +7368,8 @@ static void vik_trw_layer_uniquify_waypoints ( VikTrwLayer *vtl, VikLayersPanel
 
     trw_layer_waypoint_rename ( vtl, waypoint, newname );
 
+    g_free (newname);
+
     // Start trying to find same names again...
     waypoint_names = NULL;
     g_hash_table_foreach ( vtl->waypoints, (GHFunc) trw_layer_sorted_wp_id_by_name_list, &waypoint_names );
@@ -6993,6 +7431,8 @@ static void trw_layer_delete_waypoints_from_selection ( menu_array_layer values
     g_list_free(delete_list);
 
     trw_layer_calculate_bounds_waypoints ( vtl );
+    // Reset layer timestamp in case it has now changed
+    vik_treeview_item_set_timestamp ( vtl->vl.vt, &vtl->vl.iter, trw_layer_get_timestamp(vtl) );
     vik_layer_emit_update( VIK_LAYER(vtl) );
   }
 
@@ -7300,7 +7740,9 @@ static void trw_layer_waypoint_webpage ( menu_array_sublayer values )
   VikWaypoint *wp = g_hash_table_lookup ( vtl->waypoints, values[MA_SUBLAYER_ID] );
   if ( !wp )
     return;
-  if ( !strncmp(wp->comment, "http", 4) ) {
+  if ( wp->url ) {
+    open_url(VIK_GTK_WINDOW_FROM_LAYER(VIK_LAYER(vtl)), wp->url);
+  } else if ( !strncmp(wp->comment, "http", 4) ) {
     open_url(VIK_GTK_WINDOW_FROM_LAYER(VIK_LAYER(vtl)), wp->comment);
   } else if ( !strncmp(wp->description, "http", 4) ) {
     open_url(VIK_GTK_WINDOW_FROM_LAYER(VIK_LAYER(vtl)), wp->description);
@@ -7421,11 +7863,13 @@ static gboolean is_valid_geocache_name ( gchar *str )
   return len >= 3 && len <= 7 && str[0] == 'G' && str[1] == 'C' && isalnum(str[2]) && (len < 4 || isalnum(str[3])) && (len < 5 || isalnum(str[4])) && (len < 6 || isalnum(str[5])) && (len < 7 || isalnum(str[6]));
 }
 
+#ifndef WINDOWS
 static void trw_layer_track_use_with_filter ( menu_array_sublayer values )
 {
   VikTrack *trk = g_hash_table_lookup ( VIK_TRW_LAYER(values[MA_VTL])->tracks, values[MA_SUBLAYER_ID] );
   a_acquire_set_filter_track ( trk );
 }
+#endif
 
 #ifdef VIK_CONFIG_GOOGLE
 static gboolean is_valid_google_route ( VikTrwLayer *vtl, const gpointer track_id )
@@ -7438,7 +7882,7 @@ static void trw_layer_google_route_webpage ( menu_array_sublayer values )
 {
   VikTrack *tr = g_hash_table_lookup ( VIK_TRW_LAYER(values[MA_VTL])->routes, values[MA_SUBLAYER_ID] );
   if ( tr ) {
-    gchar *escaped = uri_escape ( tr->comment );
+    gchar *escaped = g_uri_escape_string ( tr->comment, NULL, TRUE );
     gchar *webpage = g_strdup_printf("http://maps.google.com/maps?f=q&hl=en&q=%s", escaped );
     open_url(VIK_GTK_WINDOW_FROM_LAYER(VIK_LAYER(values[MA_VTL])), webpage);
     g_free ( escaped );
@@ -7566,7 +8010,8 @@ static gboolean trw_layer_sublayer_add_menu_items ( VikTrwLayer *l, GtkMenu *men
 
       if ( wp )
       {
-        if ( ( wp->comment && !strncmp(wp->comment, "http", 4) ) ||
+        if ( wp->url ||
+             ( wp->comment && !strncmp(wp->comment, "http", 4) ) ||
              ( wp->description && !strncmp(wp->description, "http", 4) )) {
           item = gtk_image_menu_item_new_with_mnemonic ( _("Visit _Webpage") );
           gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_NETWORK, GTK_ICON_SIZE_MENU) );
@@ -7835,6 +8280,18 @@ static gboolean trw_layer_sublayer_add_menu_items ( VikTrwLayer *l, GtkMenu *men
     g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_sort_order_z2a), pass_along );
     gtk_menu_shell_append ( GTK_MENU_SHELL(submenu_sort), item );
     gtk_widget_show ( item );
+
+    item = gtk_image_menu_item_new_with_mnemonic ( _("Date Ascending") );
+    gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_SORT_ASCENDING, GTK_ICON_SIZE_MENU) );
+    g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_sort_order_timestamp_ascend), pass_along );
+    gtk_menu_shell_append ( GTK_MENU_SHELL(submenu_sort), item );
+    gtk_widget_show ( item );
+
+    item = gtk_image_menu_item_new_with_mnemonic ( _("Date Descending") );
+    gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_SORT_DESCENDING, GTK_ICON_SIZE_MENU) );
+    g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_sort_order_timestamp_descend), pass_along );
+    gtk_menu_shell_append ( GTK_MENU_SHELL(submenu_sort), item );
+    gtk_widget_show ( item );
   }
 
   GtkWidget *upload_submenu = gtk_menu_new ();
@@ -8099,13 +8556,19 @@ static gboolean trw_layer_sublayer_add_menu_items ( VikTrwLayer *l, GtkMenu *men
     gtk_menu_shell_append ( GTK_MENU_SHELL(transform_submenu), item );
     gtk_widget_show ( item );
 
-    // Routes don't have timestamps - so this is only available for tracks
+    // Routes don't have timestamps - so these are only available for tracks
     if ( subtype == VIK_TRW_LAYER_SUBLAYER_TRACK ) {
       item = gtk_image_menu_item_new_with_mnemonic ( _("_Anonymize Times") );
       g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_anonymize_times), pass_along );
       gtk_menu_shell_append ( GTK_MENU_SHELL(transform_submenu), item );
       gtk_widget_set_tooltip_text (item, _("Shift timestamps to a relative offset from 1901-01-01"));
       gtk_widget_show ( item );
+
+      item = gtk_image_menu_item_new_with_mnemonic ( _("_Interpolate Times") );
+      g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_interpolate_times), pass_along );
+      gtk_menu_shell_append ( GTK_MENU_SHELL(transform_submenu), item );
+      gtk_widget_set_tooltip_text (item, _("Reset trackpoint timestamps between the first and last points such that track is traveled at equal speed"));
+      gtk_widget_show ( item );
     }
 
     if ( subtype == VIK_TRW_LAYER_SUBLAYER_TRACK )
@@ -8179,6 +8642,46 @@ static gboolean trw_layer_sublayer_add_menu_items ( VikTrwLayer *l, GtkMenu *men
     }
   }
 
+  GtkWidget *external_submenu = create_external_submenu ( menu );
+
+  // These are only made available if a suitable program is installed
+  if ( (have_astro_program || have_diary_program) &&
+       (subtype == VIK_TRW_LAYER_SUBLAYER_TRACK || subtype == VIK_TRW_LAYER_SUBLAYER_WAYPOINT) ) {
+
+    if ( have_diary_program ) {
+      item = gtk_image_menu_item_new_with_mnemonic ( _("_Diary") );
+      gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_SPELL_CHECK, GTK_ICON_SIZE_MENU) );
+      g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_diary), pass_along );
+      gtk_menu_shell_append ( GTK_MENU_SHELL(external_submenu), item );
+      gtk_widget_set_tooltip_text (item, _("Open diary program at this date"));
+      gtk_widget_show ( item );
+    }
+
+    if ( have_astro_program ) {
+      item = gtk_image_menu_item_new_with_mnemonic ( _("_Astronomy") );
+      g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_astro), pass_along );
+      gtk_menu_shell_append ( GTK_MENU_SHELL(external_submenu), item );
+      gtk_widget_set_tooltip_text (item, _("Open astronomy program at this date and location"));
+      gtk_widget_show ( item );
+    }
+  }
+
+  if ( l->current_tpl || l->current_wp ) {
+    // For the selected point
+    VikCoord *vc;
+    if ( l->current_tpl )
+      vc = &(VIK_TRACKPOINT(l->current_tpl->data)->coord);
+    else
+      vc = &(l->current_wp->coord);
+    vik_ext_tools_add_menu_items_to_menu ( VIK_WINDOW(VIK_GTK_WINDOW_FROM_LAYER(l)), GTK_MENU (external_submenu), vc );
+  }
+  else {
+    // Otherwise for the selected sublayer
+    // TODO: Should use selected items centre - rather than implicitly using the current viewport
+    vik_ext_tools_add_menu_items_to_menu ( VIK_WINDOW(VIK_GTK_WINDOW_FROM_LAYER(l)), GTK_MENU (external_submenu), NULL );
+  }
+
+
 #ifdef VIK_CONFIG_GOOGLE
   if ( subtype == VIK_TRW_LAYER_SUBLAYER_ROUTE && is_valid_google_route ( l, sublayer ) )
   {
@@ -8202,11 +8705,14 @@ static gboolean trw_layer_sublayer_add_menu_items ( VikTrwLayer *l, GtkMenu *men
     gtk_widget_show ( item );
 #endif
 
+    // Currently filter with functions all use shellcommands and thus don't work in Windows
+#ifndef WINDOWS
     item = gtk_image_menu_item_new_with_mnemonic ( _("Use with _Filter") );
     gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_INDEX, GTK_ICON_SIZE_MENU) );
     g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_track_use_with_filter), pass_along );
     gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item );
     gtk_widget_show ( item );
+#endif
 
     /* ATM This function is only available via the layers panel, due to needing a vlp */
     if ( vlp ) {
@@ -8369,6 +8875,16 @@ static void trw_layer_cancel_current_tp ( VikTrwLayer *vtl, gboolean destroy )
   }
 }
 
+static void my_tpwin_set_tp ( VikTrwLayer *vtl )
+{
+  VikTrack *trk = vtl->current_tp_track;
+  VikCoord vc;
+  // Notional center of a track is simply an average of the bounding box extremities
+  struct LatLon center = { (trk->bbox.north+trk->bbox.south)/2, (trk->bbox.east+trk->bbox.west)/2 };
+  vik_coord_load_from_latlon ( &vc, vtl->coord_mode, &center );
+  vik_trw_layer_tpwin_set_tp ( vtl->tpwin, vtl->current_tpl, trk->name, vtl->current_tp_track->is_route );
+}
+
 static void trw_layer_tpwin_response ( VikTrwLayer *vtl, gint response )
 {
   g_assert ( vtl->tpwin != NULL );
@@ -8381,7 +8897,7 @@ static void trw_layer_tpwin_response ( VikTrwLayer *vtl, gint response )
   if ( response == VIK_TRW_LAYER_TPWIN_SPLIT && vtl->current_tpl->next && vtl->current_tpl->prev )
   {
     trw_layer_split_at_selected_trackpoint ( vtl, vtl->current_tp_track->is_route ? VIK_TRW_LAYER_SUBLAYER_ROUTE : VIK_TRW_LAYER_SUBLAYER_TRACK );
-    vik_trw_layer_tpwin_set_tp ( vtl->tpwin, vtl->current_tpl, vtl->current_tp_track->name );
+    my_tpwin_set_tp ( vtl );
   }
   else if ( response == VIK_TRW_LAYER_TPWIN_DELETE )
   {
@@ -8395,20 +8911,24 @@ static void trw_layer_tpwin_response ( VikTrwLayer *vtl, gint response )
 
     if ( vtl->current_tpl )
       // Reset dialog with the available adjacent trackpoint
-      vik_trw_layer_tpwin_set_tp ( vtl->tpwin, vtl->current_tpl, vtl->current_tp_track->name );
+      my_tpwin_set_tp ( vtl );
 
     vik_layer_emit_update(VIK_LAYER(vtl));
   }
   else if ( response == VIK_TRW_LAYER_TPWIN_FORWARD && vtl->current_tpl->next )
   {
-    if ( vtl->current_tp_track )
-      vik_trw_layer_tpwin_set_tp ( vtl->tpwin, vtl->current_tpl = vtl->current_tpl->next, vtl->current_tp_track->name );
+    if ( vtl->current_tp_track ) {
+      vtl->current_tpl = vtl->current_tpl->next;
+      my_tpwin_set_tp ( vtl );
+    }
     vik_layer_emit_update(VIK_LAYER(vtl)); /* TODO longone: either move or only update if tp is inside drawing window */
   }
   else if ( response == VIK_TRW_LAYER_TPWIN_BACK && vtl->current_tpl->prev )
   {
-    if ( vtl->current_tp_track )
-      vik_trw_layer_tpwin_set_tp ( vtl->tpwin, vtl->current_tpl = vtl->current_tpl->prev, vtl->current_tp_track->name );
+    if ( vtl->current_tp_track ) {
+      vtl->current_tpl = vtl->current_tpl->prev;
+      my_tpwin_set_tp ( vtl );
+    }
     vik_layer_emit_update(VIK_LAYER(vtl));
   }
   else if ( response == VIK_TRW_LAYER_TPWIN_INSERT && vtl->current_tpl->next )
@@ -8535,7 +9055,7 @@ static void trw_layer_tpwin_init ( VikTrwLayer *vtl )
 
   if ( vtl->current_tpl )
     if ( vtl->current_tp_track )
-      vik_trw_layer_tpwin_set_tp ( vtl->tpwin, vtl->current_tpl, vtl->current_tp_track->name );
+      my_tpwin_set_tp ( vtl );
   /* set layer name and TP data */
 }
 
@@ -8549,7 +9069,7 @@ typedef struct {
   gint x, y;
   gint closest_x, closest_y;
   gboolean draw_images;
-  gpointer *closest_wp_id;
+  gpointer closest_wp_id;
   VikWaypoint *closest_wp;
   VikViewport *vvp;
 } WPSearchParams;
@@ -8664,7 +9184,7 @@ static void marker_moveto ( tool_ed_t *t, gint x, gint y );
 static void marker_end_move ( tool_ed_t *t );
 //
 
-static gboolean trw_layer_select_move ( VikTrwLayer *vtl, GdkEventButton *event, VikViewport *vvp, tool_ed_t* t )
+static gboolean trw_layer_select_move ( VikTrwLayer *vtl, GdkEventMotion *event, VikViewport *vvp, tool_ed_t* t )
 {
   if ( t->holding ) {
     VikCoord new_coord;
@@ -8704,6 +9224,11 @@ static gboolean trw_layer_select_release ( VikTrwLayer *vtl, GdkEventButton *eve
 {
   if ( t->holding && event->button == 1 )
   {
+    // Prevent accidental (small) shifts when specific movement has not been requested
+    //  (as the click release has occurred within the click object detection area)
+    if ( !t->moving )
+      return FALSE;
+
     VikCoord new_coord;
     vik_viewport_screen_to_coord ( vvp, event->x, event->y, &new_coord );
 
@@ -8743,7 +9268,7 @@ static gboolean trw_layer_select_release ( VikTrwLayer *vtl, GdkEventButton *eve
 
         if ( vtl->tpwin )
           if ( vtl->current_tp_track )
-            vik_trw_layer_tpwin_set_tp ( vtl->tpwin, vtl->current_tpl, vtl->current_tp_track->name );
+            my_tpwin_set_tp ( vtl );
         // NB don't reset the selected trackpoint, thus ensuring it's still in the tpwin
       }
     }
@@ -8858,7 +9383,7 @@ static gboolean trw_layer_select_click ( VikTrwLayer *vtl, GdkEventButton *event
       set_statusbar_msg_info_trkpt ( vtl, tp_params.closest_tp );
 
       if ( vtl->tpwin )
-       vik_trw_layer_tpwin_set_tp ( vtl->tpwin, vtl->current_tpl, vtl->current_tp_track->name );
+        my_tpwin_set_tp ( vtl );
 
       vik_layer_emit_update ( VIK_LAYER(vtl) );
       return TRUE;
@@ -8893,7 +9418,7 @@ static gboolean trw_layer_select_click ( VikTrwLayer *vtl, GdkEventButton *event
       set_statusbar_msg_info_trkpt ( vtl, tp_params.closest_tp );
 
       if ( vtl->tpwin )
-       vik_trw_layer_tpwin_set_tp ( vtl->tpwin, vtl->current_tpl, vtl->current_tp_track->name );
+        my_tpwin_set_tp ( vtl );
 
       vik_layer_emit_update ( VIK_LAYER(vtl) );
       return TRUE;
@@ -8939,7 +9464,7 @@ static gboolean trw_layer_show_selected_viewport_menu ( VikTrwLayer *vtl, GdkEve
       udataU.trk  = track;
       udataU.uuid = NULL;
 
-      gpointer *trkf;
+      gpointer trkf;
       if ( track->is_route )
         trkf = g_hash_table_find ( vtl->routes, (GHRFunc) trw_layer_track_find_uuid, &udataU );
       else
@@ -8982,7 +9507,7 @@ static gboolean trw_layer_show_selected_viewport_menu ( VikTrwLayer *vtl, GdkEve
       udata.wp   = waypoint;
       udata.uuid = NULL;
 
-      gpointer *wpf = g_hash_table_find ( vtl->waypoints, (GHRFunc) trw_layer_waypoint_find_uuid, (gpointer) &udata );
+      gpointer wpf = g_hash_table_find ( vtl->waypoints, (GHRFunc) trw_layer_waypoint_find_uuid, (gpointer) &udata );
 
       if ( wpf && udata.uuid ) {
         GtkTreeIter *iter = g_hash_table_lookup ( vtl->waypoints_iters, udata.uuid );
@@ -9026,6 +9551,7 @@ static void marker_begin_move ( tool_ed_t *t, gint x, gint y )
   vik_viewport_sync(t->vvp);
   t->oldx = x;
   t->oldy = y;
+  t->moving = FALSE;
 }
 
 static void marker_moveto ( tool_ed_t *t, gint x, gint y )
@@ -9035,6 +9561,7 @@ static void marker_moveto ( tool_ed_t *t, gint x, gint y )
   vik_viewport_draw_rectangle ( vvp, t->gc, FALSE, x-3, y-3, 6, 6 );
   t->oldx = x;
   t->oldy = y;
+  t->moving = TRUE;
 
   if (tool_sync_done) {
     g_idle_add_full (G_PRIORITY_HIGH_IDLE + 10, tool_sync, vvp, NULL);
@@ -9047,6 +9574,7 @@ static void marker_end_move ( tool_ed_t *t )
   vik_viewport_draw_rectangle ( t->vvp, t->gc, FALSE, t->oldx-3, t->oldy-3, 6, 6 );
   g_object_unref ( t->gc );
   t->holding = FALSE;
+  t->moving = FALSE;
 }
 
 /*** Edit waypoint ****/
@@ -9086,8 +9614,8 @@ static gboolean tool_edit_waypoint_click ( VikTrwLayer *vtl, GdkEventButton *eve
     gint x, y;
     vik_viewport_coord_to_screen ( vvp, &(vtl->current_wp->coord), &x, &y );
 
-    if ( abs(x - event->x) <= WAYPOINT_SIZE_APPROX &&
-         abs(y - event->y) <= WAYPOINT_SIZE_APPROX )
+    if ( abs(x - (int)round(event->x)) <= WAYPOINT_SIZE_APPROX &&
+         abs(y - (int)round(event->y)) <= WAYPOINT_SIZE_APPROX )
     {
       if ( event->button == 3 )
         vtl->waypoint_rightclick = TRUE; /* remember that we're clicking; other layers will ignore release signal */
@@ -9107,7 +9635,10 @@ static gboolean tool_edit_waypoint_click ( VikTrwLayer *vtl, GdkEventButton *eve
   g_hash_table_foreach ( vtl->waypoints, (GHFunc) waypoint_search_closest_tp, &params);
   if ( vtl->current_wp && (vtl->current_wp == params.closest_wp) )
   {
-    marker_begin_move(t, event->x, event->y);
+    if ( event->button == 3 )
+      vtl->waypoint_rightclick = TRUE; /* remember that we're clicking; other layers will ignore release signal */
+    else
+      marker_begin_move(t, event->x, event->y);
     return FALSE;
   }
   else if ( params.closest_wp )
@@ -9277,6 +9808,15 @@ static gchar* distance_string (gdouble distance)
       g_sprintf(str, "%d miles", (int)VIK_METERS_TO_MILES(distance));
     }
     break;
+  case VIK_UNITS_DISTANCE_NAUTICAL_MILES:
+    if (distance >= VIK_NAUTICAL_MILES_TO_METERS(1) && distance < VIK_NAUTICAL_MILES_TO_METERS(100)) {
+      g_sprintf(str, "%3.2f NM", VIK_METERS_TO_NAUTICAL_MILES(distance));
+    } else if (distance < VIK_NAUTICAL_MILES_TO_METERS(1)) {
+      g_sprintf(str, "%d yards", (int)(distance*1.0936133));
+    } else {
+      g_sprintf(str, "%d NM", (int)VIK_METERS_TO_NAUTICAL_MILES(distance));
+    }
+    break;
   default:
     // VIK_UNITS_DISTANCE_KILOMETRES
     if (distance >= 1000 && distance < 100000) {
@@ -9477,6 +10017,13 @@ static void undo_trackpoint_add ( VikTrwLayer *vtl )
 static gboolean tool_new_track_key_press ( VikTrwLayer *vtl, GdkEventKey *event, VikViewport *vvp )
 {
   if ( vtl->current_track && event->keyval == GDK_Escape ) {
+    // Bin track if only one point as it's not very useful
+    if ( vik_track_get_tp_count(vtl->current_track) == 1 ) {
+      if ( vtl->current_track->is_route )
+        vik_trw_layer_delete_route ( vtl, vtl->current_track );
+      else
+        vik_trw_layer_delete_track ( vtl, vtl->current_track );
+    }
     vtl->current_track = NULL;
     vik_layer_emit_update ( VIK_LAYER(vtl) );
     return TRUE;
@@ -9564,17 +10111,20 @@ static gboolean tool_new_track_or_route_click ( VikTrwLayer *vtl, GdkEventButton
 
 static gboolean tool_new_track_click ( VikTrwLayer *vtl, GdkEventButton *event, VikViewport *vvp )
 {
+  // if we were running the route finder, cancel it
+  vtl->route_finder_started = FALSE;
+
   // ----------------------------------------------------- if current is a route - switch to new track
   if ( event->button == 1 && ( ! vtl->current_track || (vtl->current_track && vtl->current_track->is_route ) ))
   {
     gchar *name = trw_layer_new_unique_sublayer_name(vtl, VIK_TRW_LAYER_SUBLAYER_TRACK, _("Track"));
-    if ( ( name = a_dialog_new_track ( VIK_GTK_WINDOW_FROM_LAYER(vtl), name, FALSE ) ) )
-    {
-      new_track_create_common ( vtl, name );
-      g_free ( name );
+    if ( a_vik_get_ask_for_create_track_name() ) {
+      name = a_dialog_new_track ( VIK_GTK_WINDOW_FROM_LAYER(vtl), name, FALSE );
+      if ( !name )
+        return FALSE;
     }
-    else
-      return TRUE;
+    new_track_create_common ( vtl, name );
+    g_free ( name );
   }
   return tool_new_track_or_route_click ( vtl, event, vvp );
 }
@@ -9597,16 +10147,21 @@ static gpointer tool_new_route_create ( VikWindow *vw, VikViewport *vvp)
 
 static gboolean tool_new_route_click ( VikTrwLayer *vtl, GdkEventButton *event, VikViewport *vvp )
 {
-  // -------------------------- if current is a track - switch to new route
-  if ( event->button == 1 && ( ! vtl->current_track || (vtl->current_track && !vtl->current_track->is_route ) ) )
+  // if we were running the route finder, cancel it
+  vtl->route_finder_started = FALSE;
+
+  // -------------------------- if current is a track - switch to new route,
+  if ( event->button == 1 && ( ! vtl->current_track ||
+                               (vtl->current_track && !vtl->current_track->is_route ) ) )
   {
     gchar *name = trw_layer_new_unique_sublayer_name(vtl, VIK_TRW_LAYER_SUBLAYER_ROUTE, _("Route"));
-    if ( ( name = a_dialog_new_track ( VIK_GTK_WINDOW_FROM_LAYER(vtl), name, TRUE ) ) ) {
-      new_route_create_common ( vtl, name );
-      g_free ( name );
+    if ( a_vik_get_ask_for_create_track_name() ) {
+      name = a_dialog_new_track ( VIK_GTK_WINDOW_FROM_LAYER(vtl), name, TRUE );
+      if ( !name )
+        return FALSE;
     }
-    else
-      return TRUE;
+    new_route_create_common ( vtl, name );
+    g_free ( name );
   }
   return tool_new_track_or_route_click ( vtl, event, vvp );
 }
@@ -9624,9 +10179,10 @@ static gboolean tool_new_waypoint_click ( VikTrwLayer *vtl, GdkEventButton *even
   if (!vtl || vtl->vl.type != VIK_LAYER_TRW)
     return FALSE;
   vik_viewport_screen_to_coord ( vvp, event->x, event->y, &coord );
-  if (vik_trw_layer_new_waypoint ( vtl, VIK_GTK_WINDOW_FROM_LAYER(vtl), &coord ) && VIK_LAYER(vtl)->visible) {
+  if ( vik_trw_layer_new_waypoint (vtl, VIK_GTK_WINDOW_FROM_LAYER(vtl), &coord) ) {
     trw_layer_calculate_bounds_waypoints ( vtl );
-    vik_layer_emit_update ( VIK_LAYER(vtl) );
+    if ( VIK_LAYER(vtl)->visible )
+      vik_layer_emit_update ( VIK_LAYER(vtl) );
   }
   return TRUE;
 }
@@ -9647,22 +10203,24 @@ static void tool_edit_trackpoint_destroy ( tool_ed_t *t )
   g_free ( t );
 }
 
+/**
+ * tool_edit_trackpoint_click:
+ *
+ * On 'initial' click: search for the nearest trackpoint or routepoint and store it as the current trackpoint
+ * Then update the viewport, statusbar and edit dialog to draw the point as being selected and it's information.
+ * On subsequent clicks: (as the current trackpoint is defined) and the click is very near the same point
+ *  then initiate the move operation to drag the point to a new destination.
+ * NB The current trackpoint will get reset elsewhere.
+ */
 static gboolean tool_edit_trackpoint_click ( VikTrwLayer *vtl, GdkEventButton *event, gpointer data )
 {
   tool_ed_t *t = data;
   VikViewport *vvp = t->vvp;
   TPSearchParams params;
-  /* OUTDATED DOCUMENTATION:
-   find 5 pixel range on each side. then put these UTM, and a pointer
-   to the winning track name (and maybe the winning track itself), and a
-   pointer to the winning trackpoint, inside an array or struct. pass 
-   this along, do a foreach on the tracks which will do a foreach on the 
-   trackpoints. */
   params.vvp = vvp;
   params.x = event->x;
   params.y = event->y;
   params.closest_track_id = NULL;
-  /* TODO: should get track listitem so we can break it up, make a new track, mess it up, all that. */
   params.closest_tp = NULL;
   params.closest_tpl = NULL;
   vik_viewport_get_min_max_lat_lon ( vvp, &(params.bbox.south), &(params.bbox.north), &(params.bbox.west), &(params.bbox.east) );
@@ -9673,7 +10231,7 @@ static gboolean tool_edit_trackpoint_click ( VikTrwLayer *vtl, GdkEventButton *e
   if (!vtl || vtl->vl.type != VIK_LAYER_TRW)
     return FALSE;
 
-  if ( !vtl->vl.visible || !vtl->tracks_visible || !vtl->routes_visible )
+  if ( !vtl->vl.visible || !(vtl->tracks_visible || vtl->routes_visible) )
     return FALSE;
 
   if ( vtl->current_tpl )
@@ -9681,6 +10239,8 @@ static gboolean tool_edit_trackpoint_click ( VikTrwLayer *vtl, GdkEventButton *e
     /* first check if it is within range of prev. tp. and if current_tp track is shown. (if it is, we are moving that trackpoint.) */
     VikTrackpoint *tp = VIK_TRACKPOINT(vtl->current_tpl->data);
     VikTrack *current_tr = VIK_TRACK(g_hash_table_lookup(vtl->tracks, vtl->current_tp_id));
+    if ( !current_tr )
+      current_tr = VIK_TRACK(g_hash_table_lookup(vtl->routes, vtl->current_tp_id));
     if ( !current_tr )
       return FALSE;
 
@@ -9688,8 +10248,8 @@ static gboolean tool_edit_trackpoint_click ( VikTrwLayer *vtl, GdkEventButton *e
     vik_viewport_coord_to_screen ( vvp, &(tp->coord), &x, &y );
 
     if ( current_tr->visible && 
-         abs(x - event->x) < TRACKPOINT_SIZE_APPROX &&
-         abs(y - event->y) < TRACKPOINT_SIZE_APPROX ) {
+         abs(x - (int)round(event->x)) < TRACKPOINT_SIZE_APPROX &&
+         abs(y - (int)round(event->y)) < TRACKPOINT_SIZE_APPROX ) {
       marker_begin_move ( t, event->x, event->y );
       return TRUE;
     }
@@ -9792,7 +10352,8 @@ static gboolean tool_edit_trackpoint_release ( VikTrwLayer *vtl, GdkEventButton
 
     /* diff dist is diff from orig */
     if ( vtl->tpwin )
-      vik_trw_layer_tpwin_set_tp ( vtl->tpwin, vtl->current_tpl, vtl->current_tp_track->name );
+      if ( vtl->current_tp_track )
+        my_tpwin_set_tp ( vtl );
 
     vik_layer_emit_update ( VIK_LAYER(vtl) );
     return TRUE;
@@ -9801,77 +10362,121 @@ static gboolean tool_edit_trackpoint_release ( VikTrwLayer *vtl, GdkEventButton
 }
 
 
-/*** Route Finder ***/
-static gpointer tool_route_finder_create ( VikWindow *vw, VikViewport *vvp)
+/*** Extended Route Finder ***/
+
+static gpointer tool_extended_route_finder_create ( VikWindow *vw, VikViewport *vvp)
 {
   return vvp;
 }
 
-static gboolean tool_route_finder_click ( VikTrwLayer *vtl, GdkEventButton *event, VikViewport *vvp )
+static void tool_extended_route_finder_undo ( VikTrwLayer *vtl )
+{
+  VikCoord *new_end;
+  new_end = vik_track_cut_back_to_double_point ( vtl->current_track );
+  if ( new_end ) {
+    g_free ( new_end );
+    vik_layer_emit_update ( VIK_LAYER(vtl) );
+
+    /* remove last ' to:...' */
+    if ( vtl->current_track->comment ) {
+      gchar *last_to = strrchr ( vtl->current_track->comment, 't' );
+      if ( last_to && (last_to - vtl->current_track->comment > 1) ) {
+        gchar *new_comment = g_strndup ( vtl->current_track->comment,
+                                         last_to - vtl->current_track->comment - 1);
+        vik_track_set_comment_no_copy ( vtl->current_track, new_comment );
+      }
+    }
+  }
+}
+
+
+static gboolean tool_extended_route_finder_click ( VikTrwLayer *vtl, GdkEventButton *event, VikViewport *vvp )
 {
   VikCoord tmp;
   if ( !vtl ) return FALSE;
   vik_viewport_screen_to_coord ( vvp, event->x, event->y, &tmp );
-  if ( event->button == 3 && vtl->route_finder_current_track ) {
-    VikCoord *new_end;
-    new_end = vik_track_cut_back_to_double_point ( vtl->route_finder_current_track );
-    if ( new_end ) {
-      vtl->route_finder_coord = *new_end;
-      g_free ( new_end );
-      vik_layer_emit_update ( VIK_LAYER(vtl) );
-      /* remove last ' to:...' */
-      if ( vtl->route_finder_current_track->comment ) {
-        gchar *last_to = strrchr ( vtl->route_finder_current_track->comment, 't' );
-        if ( last_to && (last_to - vtl->route_finder_current_track->comment > 1) ) {
-          gchar *new_comment = g_strndup ( vtl->route_finder_current_track->comment,
-                                           last_to - vtl->route_finder_current_track->comment - 1);
-          vik_track_set_comment_no_copy ( vtl->route_finder_current_track, new_comment );
-        }
-      }
-    }
+  if ( event->button == 3 && vtl->current_track ) {
+    tool_extended_route_finder_undo ( vtl );
+  }
+  else if ( event->button == 2 ) {
+     vtl->draw_sync_do = FALSE;
+     return FALSE;
   }
-  else if ( vtl->route_finder_started || (event->state & GDK_CONTROL_MASK && vtl->route_finder_current_track) ) {
+  // if we started the track but via undo deleted all the track points, begin again
+  else if ( vtl->current_track && vtl->current_track->is_route && ! vik_track_get_tp_first ( vtl->current_track ) ) {
+    return tool_new_track_or_route_click ( vtl, event, vvp );
+  }
+  else if ( ( vtl->current_track && vtl->current_track->is_route ) ||
+            ( event->state & GDK_CONTROL_MASK && vtl->current_track ) ) {
     struct LatLon start, end;
 
-    vik_coord_to_latlon ( &(vtl->route_finder_coord), &start );
+    VikTrackpoint *tp_start = vik_track_get_tp_last ( vtl->current_track );
+    vik_coord_to_latlon ( &(tp_start->coord), &start );
     vik_coord_to_latlon ( &(tmp), &end );
-    vtl->route_finder_coord = tmp; /* for continuations */
 
-    /* these are checked when adding a track from a file (vik_trw_layer_filein_add_track) */
-    if ( event->state & GDK_CONTROL_MASK && vtl->route_finder_current_track ) {
-      vtl->route_finder_append = TRUE;  // merge tracks. keep started true.
-    } else {
-      vtl->route_finder_check_added_track = TRUE;
-      vtl->route_finder_started = FALSE;
+    vtl->route_finder_started = TRUE;
+    vtl->route_finder_append = TRUE;  // merge tracks. keep started true.
+
+    // update UI to let user know what's going on
+    VikStatusbar *sb = vik_window_get_statusbar (VIK_WINDOW(VIK_GTK_WINDOW_FROM_LAYER(vtl)));
+    VikRoutingEngine *engine = vik_routing_default_engine ( );
+    if ( ! engine ) {
+        vik_statusbar_set_message ( sb, VIK_STATUSBAR_INFO, "Cannot plan route without a default routing engine." );
+        return TRUE;
     }
+    gchar *msg = g_strdup_printf ( _("Querying %s for route between (%.3f, %.3f) and (%.3f, %.3f)."),
+                                   vik_routing_engine_get_label ( engine ),
+                                   start.lat, start.lon, end.lat, end.lon );
+    vik_statusbar_set_message ( sb, VIK_STATUSBAR_INFO, msg );
+    g_free ( msg );
+    vik_window_set_busy_cursor ( VIK_WINDOW(VIK_GTK_WINDOW_FROM_LAYER(vtl)) );
 
-    vik_routing_default_find ( vtl, start, end);
 
-    /* see if anything was done -- a track was added or appended to */
-    if ( vtl->route_finder_check_added_track && vtl->route_finder_added_track ) {
-      vik_track_set_comment_no_copy ( vtl->route_finder_added_track, g_strdup_printf("from: %f,%f to: %f,%f", start.lat, start.lon, end.lat, end.lon ) );
-    } else if ( vtl->route_finder_append == FALSE && vtl->route_finder_current_track ) {
-      /* route_finder_append was originally TRUE but set to FALSE by filein_add_track */
-      gchar *new_comment = g_strdup_printf("%s to: %f,%f", vtl->route_finder_current_track->comment, end.lat, end.lon );
-      vik_track_set_comment_no_copy ( vtl->route_finder_current_track, new_comment );
-    }
+    /* Give GTK a change to display the new status bar before querying the web */
+    while ( gtk_events_pending ( ) )
+        gtk_main_iteration ( );
 
-    if ( vtl->route_finder_added_track )
-      vik_track_calculate_bounds ( vtl->route_finder_added_track );
+    gboolean find_status = vik_routing_default_find ( vtl, start, end );
 
-    vtl->route_finder_added_track = NULL;
-    vtl->route_finder_check_added_track = FALSE;
-    vtl->route_finder_append = FALSE;
+    /* Update UI to say we're done */
+    vik_window_clear_busy_cursor ( VIK_WINDOW(VIK_GTK_WINDOW_FROM_LAYER(vtl)) );
+    msg = ( find_status ) ? g_strdup_printf ( _("%s returned route between (%.3f, %.3f) and (%.3f, %.3f)."),
+                            vik_routing_engine_get_label ( engine ),
+                            start.lat, start.lon, end.lat, end.lon )
+                          : g_strdup_printf ( _("Error getting route from %s."),
+                                              vik_routing_engine_get_label ( engine ) );
+    vik_statusbar_set_message ( sb, VIK_STATUSBAR_INFO, msg );
+    g_free ( msg );
 
     vik_layer_emit_update ( VIK_LAYER(vtl) );
   } else {
+    vtl->current_track = NULL;
+
+    // create a new route where we will add the planned route to
+    gboolean ret = tool_new_route_click( vtl, event, vvp );
+
     vtl->route_finder_started = TRUE;
-    vtl->route_finder_coord = tmp;
-    vtl->route_finder_current_track = NULL;
+
+    return ret;
   }
   return TRUE;
 }
 
+static gboolean tool_extended_route_finder_key_press ( VikTrwLayer *vtl, GdkEventKey *event, VikViewport *vvp )
+{
+  if ( vtl->current_track && event->keyval == GDK_Escape ) {
+    vtl->route_finder_started = FALSE;
+    vtl->current_track = NULL;
+    vik_layer_emit_update ( VIK_LAYER(vtl) );
+    return TRUE;
+  } else if ( vtl->current_track && event->keyval == GDK_BackSpace ) {
+    tool_extended_route_finder_undo ( vtl );
+  }
+  return FALSE;
+}
+
+
+
 /*** Show picture ****/
 
 static gpointer tool_show_picture_create ( VikWindow *vw, VikViewport *vvp)
@@ -9997,7 +10602,8 @@ void trw_layer_verify_thumbnails ( VikTrwLayer *vtl, GtkWidget *vp )
       thumbnail_create_thread_data *tctd = g_malloc ( sizeof(thumbnail_create_thread_data) );
       tctd->vtl = vtl;
       tctd->pics = pics;
-      a_background_thread ( VIK_GTK_WINDOW_FROM_LAYER(vtl),
+      a_background_thread ( BACKGROUND_POOL_LOCAL,
+                            VIK_GTK_WINDOW_FROM_LAYER(vtl),
                            tmp,
                            (vik_thr_func) create_thumbnails_thread,
                            tctd,
@@ -10145,6 +10751,74 @@ static void trw_layer_sort_all ( VikTrwLayer *vtl )
     vik_treeview_sort_children ( VIK_LAYER(vtl)->vt, &(vtl->waypoints_iter), vtl->wp_sort_order );
 }
 
+/**
+ * Get the earliest timestamp available from all tracks
+ */
+static time_t trw_layer_get_timestamp_tracks ( VikTrwLayer *vtl )
+{
+  time_t timestamp = 0;
+  GList *gl = g_hash_table_get_values ( vtl->tracks );
+  gl = g_list_sort ( gl, vik_track_compare_timestamp );
+  gl = g_list_first ( gl );
+
+  if ( gl ) {
+    // Only need to check the first track as they have been sorted by time
+    VikTrack *trk = (VikTrack*)gl->data;
+    // Assume trackpoints already sorted by time
+    VikTrackpoint *tpt = vik_track_get_tp_first(trk);
+    if ( tpt && tpt->has_timestamp ) {
+      timestamp = tpt->timestamp;
+    }
+    g_list_free ( gl );
+  }
+  return timestamp;
+}
+
+/**
+ * Get the earliest timestamp available from all waypoints
+ */
+static time_t trw_layer_get_timestamp_waypoints ( VikTrwLayer *vtl )
+{
+  time_t timestamp = 0;
+  GList *gl = g_hash_table_get_values ( vtl->waypoints );
+  GList *iter;
+  for (iter = g_list_first (gl); iter != NULL; iter = g_list_next (iter)) {
+    VikWaypoint *wpt = (VikWaypoint*)iter->data;
+    if ( wpt->has_timestamp ) {
+      // When timestamp not set yet - use the first value encountered
+      if ( timestamp == 0 )
+        timestamp = wpt->timestamp;
+      else if ( timestamp > wpt->timestamp )
+        timestamp = wpt->timestamp;
+    }
+  }
+  g_list_free ( gl );
+
+  return timestamp;
+}
+
+/**
+ * Get the earliest timestamp available for this layer
+ */
+static time_t trw_layer_get_timestamp ( VikTrwLayer *vtl )
+{
+  time_t timestamp_tracks = trw_layer_get_timestamp_tracks ( vtl );
+  time_t timestamp_waypoints = trw_layer_get_timestamp_waypoints ( vtl );
+  // NB routes don't have timestamps - hence they are not considered
+
+  if ( !timestamp_tracks && !timestamp_waypoints ) {
+    // Fallback to get time from the metadata when no other timestamps available
+    GTimeVal gtv;
+    if  ( vtl->metadata && vtl->metadata->timestamp && g_time_val_from_iso8601 ( vtl->metadata->timestamp, &gtv ) )
+      return gtv.tv_sec;
+  }
+  if ( timestamp_tracks && !timestamp_waypoints )
+    return timestamp_tracks;
+  if ( timestamp_tracks && timestamp_waypoints && (timestamp_tracks < timestamp_waypoints) )
+    return timestamp_tracks;
+  return timestamp_waypoints;
+}
+
 static void trw_layer_post_read ( VikTrwLayer *vtl, GtkWidget *vvp, gboolean from_file )
 {
   if ( VIK_LAYER(vtl)->realized )
@@ -10172,47 +10846,13 @@ static void trw_layer_post_read ( VikTrwLayer *vtl, GtkWidget *vvp, gboolean fro
     }
 
     if ( need_to_set_time ) {
-      // Could rewrite this as a general get first time of a TRW Layer function
       GTimeVal timestamp;
       timestamp.tv_usec = 0;
-      gboolean has_timestamp = FALSE;
-
-      GList *gl = NULL;
-      gl = g_hash_table_get_values ( vtl->tracks );
-      gl = g_list_sort ( gl, vik_track_compare_timestamp );
-      gl = g_list_first ( gl );
-
-      // Check times of tracks
-      if ( gl ) {
-        // Only need to check the first track as they have been sorted by time
-        VikTrack *trk = (VikTrack*)gl->data;
-        // Assume trackpoints already sorted by time
-        VikTrackpoint *tpt = vik_track_get_tp_first(trk);
-        if ( tpt && tpt->has_timestamp ) {
-          timestamp.tv_sec = tpt->timestamp;
-          has_timestamp = TRUE;
-        }
-        g_list_free ( gl );
-      }
+      timestamp.tv_sec = trw_layer_get_timestamp ( vtl );
 
-      if ( !has_timestamp ) {
-        // 'Last' resort - current time
-        // Get before waypoint tests - so that if a waypoint time value (in the past) is found it should be used
+      // No time found - so use 'now' for the metadata time
+      if ( timestamp.tv_sec == 0 ) {
         g_get_current_time ( &timestamp );
-
-        // Check times of waypoints
-        gl = g_hash_table_get_values ( vtl->waypoints );
-        GList *iter;
-        for (iter = g_list_first (gl); iter != NULL; iter = g_list_next (iter)) {
-          VikWaypoint *wpt = (VikWaypoint*)iter->data;
-          if ( wpt->has_timestamp ) {
-            if ( timestamp.tv_sec > wpt->timestamp ) {
-              timestamp.tv_sec = wpt->timestamp;
-              has_timestamp = TRUE;
-            }
-          }
-        }
-        g_list_free ( gl );
       }
 
       vtl->metadata->timestamp = g_time_val_to_iso8601 ( &timestamp );
@@ -10395,16 +11035,16 @@ void vik_track_download_map(VikTrack *tr, VikMapsLayer *vml, VikViewport *vvp, g
     g_message("%s: this feature works only in Mercator mode", __FUNCTION__);
 
   if (fillins) {
-    GList *iter = fillins;
-    while (iter) {
-      cur_coord = (VikCoord *)(iter->data);
+    GList *fiter = fillins;
+    while (fiter) {
+      cur_coord = (VikCoord *)(fiter->data);
       vik_coord_set_area(cur_coord, &wh, &tl, &br);
       rect = g_malloc(sizeof(Rect));
       rect->tl = tl;
       rect->br = br;
       rect->center = *cur_coord;
       rects_to_download = g_list_prepend(rects_to_download, rect);
-      iter = iter->next;
+      fiter = fiter->next;
     }
   }
 
@@ -10453,8 +11093,8 @@ static void trw_layer_download_map_along_track_cb ( menu_array_sublayer values )
   }
 
   // Convert from list of vmls to list of names. Allowing the user to select one of them
-  gchar **map_names = g_malloc(1 + num_maps * sizeof(gpointer));
-  VikMapsLayer **map_layers = g_malloc(1 + num_maps * sizeof(gpointer));
+  gchar **map_names = g_malloc_n(1 + num_maps, sizeof(gpointer));
+  VikMapsLayer **map_layers = g_malloc_n(1 + num_maps, sizeof(gpointer));
 
   gchar **np = map_names;
   VikMapsLayer **lp = map_layers;