]> git.street.me.uk Git - andy/viking.git/blobdiff - src/viktrwlayer.c
Slightly more configurable support for RedNotebook.
[andy/viking.git] / src / viktrwlayer.c
index e647d887dc8cec4e83e16bbd722529292f7bfb20..4b9806d363cc7645325dcfa747ec47ebc6021504 100644 (file)
@@ -35,6 +35,7 @@
 #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"
@@ -59,7 +60,7 @@
 #include "datasources.h"
 #include "datasource_gps.h"
 #include "vikexttool_datasources.h"
-#include "util.h"
+#include "ui_util.h"
 #include "vikutils.h"
 
 #include "vikrouting.h"
@@ -709,7 +710,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 */
@@ -776,28 +777,44 @@ VikLayerInterface vik_trw_layer_interface = {
 };
 
 static gboolean have_diary_program = FALSE;
-static gboolean have_geojson_export = FALSE;
+static gchar *diary_program = NULL;
+#define VIK_SETTINGS_EXTERNAL_DIARY_PROGRAM "external_diary_program"
 
+static gboolean have_geojson_export = FALSE;
 
 // NB Only performed once per program run
 static void vik_trwlayer_class_init ( VikTrwLayerClass *klass )
 {
-  if ( g_find_program_in_path( "rednotebook" ) ) {
-    gchar *stdout = NULL;
-    gchar *stderr = NULL;
+  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
-    if ( g_spawn_command_line_sync ( "rednotebook --version", &stdout, &stderr, NULL, NULL ) ) {
+    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 ( stdout )
-        g_debug ("Diary: %s", stdout ); // Should be something like 'RedNotebook 1.4'
-      if ( stderr )
-        g_warning ("Diary: stderr: %s", 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 ( stdout && g_strcmp0(stdout, "") )
-        tokens = g_strsplit(stdout, " ", 0);
-      else if ( stderr )
-        tokens = g_strsplit(stderr, " ", 0);
+      if ( mystdout && g_strcmp0(mystdout, "") )
+        tokens = g_strsplit(mystdout, " ", 0);
+      else if ( mystderr )
+        tokens = g_strsplit(mystderr, " ", 0);
 
       gint num = 0;
       gchar *token = tokens[num];
@@ -811,8 +828,9 @@ static void vik_trwlayer_class_init ( VikTrwLayerClass *klass )
       }
       g_strfreev ( tokens );
     }
-    g_free ( stdout );
-    g_free ( stderr );
+    g_free ( mystdout );
+    g_free ( mystderr );
+    g_free ( cmd );
   }
 
   if ( g_find_program_in_path ( a_geojson_program_export() ) ) {
@@ -1739,6 +1757,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;
@@ -1784,6 +1805,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;
@@ -2842,13 +2866,19 @@ 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
@@ -2937,6 +2967,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;
        }
@@ -2983,13 +3016,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 );
 
@@ -4924,6 +4962,7 @@ 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 );
     }
   }
   else if ( GPOINTER_TO_INT (values[MA_SUBTYPE]) == VIK_TRW_LAYER_SUBLAYER_TRACK )
@@ -6579,14 +6618,17 @@ static void trw_layer_reverse ( menu_array_sublayer values )
 }
 
 /**
- * Open a diary at the specified date
+ * 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", "rednotebook --date=", date_str );
+  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."), "rednotebook" );
+    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 );
@@ -8495,6 +8537,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 );
@@ -8507,7 +8559,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 )
   {
@@ -8521,20 +8573,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 )
@@ -8661,7 +8717,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 */
 }
 
@@ -8790,7 +8846,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;
@@ -8830,6 +8886,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 );
 
@@ -8869,7 +8930,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
       }
     }
@@ -8984,7 +9045,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;
@@ -9019,7 +9080,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;
@@ -9152,6 +9213,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 )
@@ -9161,6 +9223,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);
@@ -9173,6 +9236,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 ****/
@@ -9406,6 +9470,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) {
@@ -9606,6 +9679,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;
@@ -9700,13 +9780,13 @@ static gboolean tool_new_track_click ( VikTrwLayer *vtl, GdkEventButton *event,
   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 );
 }
@@ -9737,12 +9817,13 @@ static gboolean tool_new_route_click ( VikTrwLayer *vtl, GdkEventButton *event,
                                (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 );
 }
@@ -9928,7 +10009,7 @@ 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 );
+      my_tpwin_set_tp ( vtl );
 
     vik_layer_emit_update ( VIK_LAYER(vtl) );
     return TRUE;