]> git.street.me.uk Git - andy/viking.git/blobdiff - src/viktrwlayer.c
Extract a UI module for babel
[andy/viking.git] / src / viktrwlayer.c
index a8070385fb2ac01ffcb3714fea727546708f716d..c085e720220c78829d36856d07ec550f495c4f44 100644 (file)
@@ -33,6 +33,7 @@
 #include "viking.h"
 #include "vikmapslayer.h"
 #include "vikgpslayer.h"
+#include "viktrwlayer_export.h"
 #include "viktrwlayer_tpwin.h"
 #include "viktrwlayer_propwin.h"
 #include "viktrwlayer_analysis.h"
@@ -149,6 +150,9 @@ struct _VikTrwLayer {
   guint8 bg_line_thickness;
   vik_layer_sort_order_t track_sort_order;
 
+  // Metadata
+  VikTRWMetadata *metadata;
+
   PangoLayout *tracklabellayout;
   font_size_t track_font_size;
   gchar *track_fsize_str;
@@ -304,7 +308,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 );
@@ -481,8 +484,8 @@ enum {
 
 /****** PARAMETERS ******/
 
-static gchar *params_groups[] = { N_("Waypoints"), N_("Tracks"), N_("Waypoint Images"), N_("Tracks Advanced") };
-enum { GROUP_WAYPOINTS, GROUP_TRACKS, GROUP_IMAGES, GROUP_TRACKS_ADV };
+static gchar *params_groups[] = { N_("Waypoints"), N_("Tracks"), N_("Waypoint Images"), N_("Tracks Advanced"), N_("Metadata") };
+enum { GROUP_WAYPOINTS, GROUP_TRACKS, GROUP_IMAGES, GROUP_TRACKS_ADV, GROUP_METADATA };
 
 static gchar *params_drawmodes[] = { N_("Draw by Track"), N_("Draw by Speed"), N_("All Tracks Same Color"), NULL };
 static gchar *params_wpsymbols[] = { N_("Filled Square"), N_("Square"), N_("Circle"), N_("X"), 0 };
@@ -560,6 +563,13 @@ static VikLayerParamData image_cache_size_default ( void ) { return VIK_LPD_UINT
 
 static VikLayerParamData sort_order_default ( void ) { return VIK_LPD_UINT ( 0 ); }
 
+static VikLayerParamData string_default ( void )
+{
+  VikLayerParamData data;
+  data.s = "";
+  return data;
+}
+
 VikLayerParam trw_layer_params[] = {
   { VIK_LAYER_TRW, "tracks_visible", VIK_LAYER_PARAM_BOOLEAN, VIK_LAYER_NOT_IN_PROPERTIES, NULL, 0, NULL, NULL, NULL, vik_lpd_true_default, NULL, NULL },
   { VIK_LAYER_TRW, "waypoints_visible", VIK_LAYER_PARAM_BOOLEAN, VIK_LAYER_NOT_IN_PROPERTIES, NULL, 0, NULL, NULL, NULL, vik_lpd_true_default, NULL, NULL },
@@ -604,6 +614,11 @@ VikLayerParam trw_layer_params[] = {
   { VIK_LAYER_TRW, "image_size", VIK_LAYER_PARAM_UINT, GROUP_IMAGES, N_("Image Size (pixels):"), VIK_LAYER_WIDGET_HSCALE, &params_scales[3], NULL, NULL, image_size_default, NULL, NULL },
   { VIK_LAYER_TRW, "image_alpha", VIK_LAYER_PARAM_UINT, GROUP_IMAGES, N_("Image Alpha:"), VIK_LAYER_WIDGET_HSCALE, &params_scales[4], NULL, NULL, image_alpha_default, NULL, NULL },
   { VIK_LAYER_TRW, "image_cache_size", VIK_LAYER_PARAM_UINT, GROUP_IMAGES, N_("Image Memory Cache Size:"), VIK_LAYER_WIDGET_HSCALE, &params_scales[5], NULL, NULL, image_cache_size_default, NULL, NULL },
+
+  { VIK_LAYER_TRW, "metadatadesc", VIK_LAYER_PARAM_STRING, GROUP_METADATA, N_("Description"), VIK_LAYER_WIDGET_ENTRY, NULL, NULL, NULL, string_default, NULL, NULL },
+  { VIK_LAYER_TRW, "metadataauthor", VIK_LAYER_PARAM_STRING, GROUP_METADATA, N_("Author"), VIK_LAYER_WIDGET_ENTRY, NULL, NULL, NULL, string_default, NULL, NULL },
+  { VIK_LAYER_TRW, "metadatatime", VIK_LAYER_PARAM_STRING, GROUP_METADATA, N_("Creation Time"), VIK_LAYER_WIDGET_ENTRY, NULL, NULL, NULL, string_default, NULL, NULL },
+  { VIK_LAYER_TRW, "metadatakeywords", VIK_LAYER_PARAM_STRING, GROUP_METADATA, N_("Keywords"), VIK_LAYER_WIDGET_ENTRY, NULL, NULL, NULL, string_default, NULL, NULL },
 };
 
 // ENUMERATION MUST BE IN THE SAME ORDER AS THE NAMED PARAMS ABOVE
@@ -647,6 +662,11 @@ enum {
   PARAM_IS,
   PARAM_IA,
   PARAM_ICS,
+  // Metadata
+  PARAM_MDDESC,
+  PARAM_MDAUTH,
+  PARAM_MDTIME,
+  PARAM_MDKEYS,
   NUM_PARAMS
 };
 
@@ -775,6 +795,103 @@ GType vik_trw_layer_get_type ()
   return vtl_type;
 }
 
+VikTRWMetadata *vik_trw_metadata_new()
+{
+  return (VikTRWMetadata*)g_malloc0(sizeof(VikTRWMetadata));
+}
+
+void vik_trw_metadata_free ( VikTRWMetadata *metadata)
+{
+  g_free (metadata);
+}
+
+VikTRWMetadata *vik_trw_layer_get_metadata ( VikTrwLayer *vtl )
+{
+  return vtl->metadata;
+}
+
+void vik_trw_layer_set_metadata ( VikTrwLayer *vtl, VikTRWMetadata *metadata)
+{
+  if ( vtl->metadata )
+    vik_trw_metadata_free ( vtl->metadata );
+  vtl->metadata = metadata;
+}
+
+typedef struct {
+  gboolean found;
+  const gchar *date_str;
+  const VikTrack *trk;
+  const VikWaypoint *wpt;
+  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 )
+{
+  gchar date_buf[20];
+  date_buf[0] = '\0';
+  // Might be an easier way to compare dates rather than converting the strings all the time...
+  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)));
+
+    if ( ! g_strcmp0 ( df->date_str, date_buf ) ) {
+      df->found = TRUE;
+      df->trk = trk;
+      df->trk_id = id;
+    }
+  }
+  return df->found;
+}
+
+static gboolean trw_layer_find_date_waypoint ( const gpointer id, const VikWaypoint *wpt, date_finder_type *df )
+{
+  gchar date_buf[20];
+  date_buf[0] = '\0';
+  // Might be an easier way to compare dates rather than converting the strings all the time...
+  if ( wpt->has_timestamp ) {
+    strftime (date_buf, sizeof(date_buf), "%Y-%m-%d", gmtime(&(wpt->timestamp)));
+
+    if ( ! g_strcmp0 ( df->date_str, date_buf ) ) {
+      df->found = TRUE;
+      df->wpt = wpt;
+      df->wpt_id = id;
+    }
+  }
+  return df->found;
+}
+
+/**
+ * Find an item by date
+ */
+gboolean vik_trw_layer_find_date ( VikTrwLayer *vtl, const gchar *date_str, VikCoord *position, VikViewport *vvp, gboolean do_tracks, gboolean select )
+{
+  date_finder_type df;
+  df.found = FALSE;
+  df.date_str = date_str;
+  df.trk = NULL;
+  df.wpt = NULL;
+  // Only tracks ATM
+  if ( do_tracks )
+    g_hash_table_find ( vtl->tracks, (GHRFunc) trw_layer_find_date_track, &df );
+  else
+    g_hash_table_find ( vtl->waypoints, (GHRFunc) trw_layer_find_date_waypoint, &df );
+
+  if ( select && df.found ) {
+    if ( do_tracks && df.trk ) {
+      struct LatLon maxmin[2] = { {0,0}, {0,0} };
+      trw_layer_find_maxmin_tracks ( NULL, df.trk, maxmin );
+      trw_layer_zoom_to_show_latlons ( vtl, vvp, maxmin );
+      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_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) );
+  }
+  return df.found;
+}
+
 static void trw_layer_del_item ( VikTrwLayer *vtl, gint subtype, gpointer sublayer )
 {
   static menu_array_sublayer values;
@@ -1081,6 +1198,12 @@ static gboolean trw_layer_set_param ( VikTrwLayer *vtl, guint16 id, VikLayerPara
       }
       break;
     case PARAM_WPSO: if ( data.u < VL_SO_LAST ) vtl->wp_sort_order = data.u; break;
+    // Metadata
+    case PARAM_MDDESC: if ( data.s && vtl->metadata ) vtl->metadata->description = g_strdup (data.s); break;
+    case PARAM_MDAUTH: if ( data.s && vtl->metadata ) vtl->metadata->author = g_strdup (data.s); break;
+    case PARAM_MDTIME: if ( data.s && vtl->metadata ) vtl->metadata->timestamp = g_strdup (data.s); break;
+    case PARAM_MDKEYS: if ( data.s && vtl->metadata ) vtl->metadata->keywords = g_strdup (data.s); break;
+    default: break;
   }
   return TRUE;
 }
@@ -1125,6 +1248,12 @@ static VikLayerParamData trw_layer_get_param ( VikTrwLayer *vtl, guint16 id, gbo
     case PARAM_WPSYMS: rv.b = vtl->wp_draw_symbols; break;
     case PARAM_WPFONTSIZE: rv.u = vtl->wp_font_size; break;
     case PARAM_WPSO: rv.u = vtl->wp_sort_order; break;
+    // Metadata
+    case PARAM_MDDESC: if (vtl->metadata) { rv.s = vtl->metadata->description; } break;
+    case PARAM_MDAUTH: if (vtl->metadata) { rv.s = vtl->metadata->author; } break;
+    case PARAM_MDTIME: if (vtl->metadata) { rv.s = vtl->metadata->timestamp; } break;
+    case PARAM_MDKEYS: if (vtl->metadata) { rv.s = vtl->metadata->keywords; } break;
+    default: break;
   }
   return rv;
 }
@@ -1192,6 +1321,12 @@ static void trw_layer_change_param ( GtkWidget *widget, ui_change_values values
       if ( w2 ) gtk_widget_set_sensitive ( w2, sensitive );
       break;
     }
+    case PARAM_MDTIME: {
+      // Force metadata->timestamp to be always read-only for now.
+      GtkWidget **ww = values[UI_CHG_WIDGETS];
+      GtkWidget *w1 = ww[OFFSET + PARAM_MDTIME];
+      if ( w1 ) gtk_widget_set_sensitive ( w1, FALSE );
+    }
     // NB Since other track settings have been split across tabs,
     // I don't think it's useful to set sensitivities on widgets you can't immediately see
     default: break;
@@ -1385,6 +1520,7 @@ static VikTrwLayer* trw_layer_new1 ( VikViewport *vvp )
   // Force to on after processing params (which defaults them to off with a zero value)
   rv->waypoints_visible = rv->tracks_visible = rv->routes_visible = TRUE;
 
+  rv->metadata = vik_trw_metadata_new ();
   rv->draw_sync_done = TRUE;
   rv->draw_sync_do = TRUE;
   // Everything else is 0, FALSE or NULL
@@ -3109,123 +3245,51 @@ 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 )
-{
-  VikTrwLayer *vtl = VIK_TRW_LAYER(values[MA_VTL]);
-  gchar *name_used = NULL;
-  int fd;
-
-  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 );
-  }
-}
 
 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 )
@@ -3244,17 +3308,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 );
 }
@@ -3773,11 +3834,11 @@ void trw_layer_osm_traces_upload_cb ( menu_array_layer values )
   osm_traces_upload_viktrwlayer(VIK_TRW_LAYER(values[MA_VTL]), NULL);
 }
 
-void trw_layer_osm_traces_upload_track_cb ( gpointer pass_along[8] )
+void trw_layer_osm_traces_upload_track_cb ( menu_array_sublayer values )
 {
-  if ( pass_along[7] ) {
-    VikTrack *trk = VIK_TRACK(pass_along[7]);
-    osm_traces_upload_viktrwlayer(VIK_TRW_LAYER(pass_along[0]), trk);
+  if ( values[MA_MISC] ) {
+    VikTrack *trk = VIK_TRACK(values[MA_MISC]);
+    osm_traces_upload_viktrwlayer(VIK_TRW_LAYER(values[MA_VTL]), trk);
   }
 }
 
@@ -8058,8 +8119,8 @@ static gboolean trw_layer_sublayer_add_menu_items ( VikTrwLayer *l, GtkMenu *men
   if ( subtype == VIK_TRW_LAYER_SUBLAYER_TRACK ) {
 #ifdef VIK_CONFIG_OPENSTREETMAP
     item = gtk_image_menu_item_new_with_mnemonic ( _("Upload to _OSM...") );
-    // Convert internal pointer into actual track for usage outside this file
-    pass_along[7] = g_hash_table_lookup ( l->tracks, sublayer);
+    // Convert internal pointer into track
+    pass_along[MA_MISC] = g_hash_table_lookup ( l->tracks, sublayer);
     gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_GO_UP, GTK_ICON_SIZE_MENU) );
     g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_osm_traces_upload_track_cb), pass_along );
     gtk_menu_shell_append ( GTK_MENU_SHELL(upload_submenu), item );
@@ -8670,6 +8731,15 @@ static gboolean trw_layer_select_click ( VikTrwLayer *vtl, GdkEventButton *event
       vtl->current_wp =    wp_params.closest_wp;
       vtl->current_wp_id = wp_params.closest_wp_id;
 
+      if ( event->type == GDK_2BUTTON_PRESS ) {
+        if ( vtl->current_wp->image ) {
+          menu_array_sublayer values;
+          values[MA_VTL] = vtl;
+          values[MA_MISC] = vtl->current_wp->image;
+          trw_layer_show_picture ( values );
+        }
+      }
+
       vik_layer_emit_update ( VIK_LAYER(vtl) );
 
       return TRUE;
@@ -10015,6 +10085,64 @@ static void trw_layer_post_read ( VikTrwLayer *vtl, GtkWidget *vvp, gboolean fro
   //  since the sorting of a treeview section is now very quick
   // NB sorting is also performed after every name change as well to maintain the list order
   trw_layer_sort_all ( vtl );
+
+  // Setting metadata time if not otherwise set
+  if ( vtl->metadata ) {
+
+    gboolean need_to_set_time = TRUE;
+    if ( vtl->metadata->timestamp ) {
+      need_to_set_time = FALSE;
+      if ( !g_strcmp0(vtl->metadata->timestamp, "" ) )
+        need_to_set_time = TRUE;
+    }
+
+    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 );
+      }
+
+      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
+        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 );
+    }
+  }
 }
 
 VikCoordMode vik_trw_layer_get_coord_mode ( VikTrwLayer *vtl )