X-Git-Url: https://git.street.me.uk/andy/viking.git/blobdiff_plain/bc07590a14b533ff65b0c4e802e160de7816ec0d..a000257bf45acd950c7dbfa380c339532f6f5e1f:/src/viktrwlayer.c diff --git a/src/viktrwlayer.c b/src/viktrwlayer.c index e504fed0..09e30fb7 100644 --- a/src/viktrwlayer.c +++ b/src/viktrwlayer.c @@ -47,6 +47,7 @@ #include "thumbnails.h" #include "background.h" #include "gpx.h" +#include "geojson.h" #include "babel.h" #include "dem.h" #include "dems.h" @@ -202,10 +203,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; @@ -390,8 +389,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 +418,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"), "T", N_("Create Track"), 0 }, (VikToolConstructorFunc) tool_new_track_create, NULL, NULL, NULL, @@ -427,7 +427,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"), "B", N_("Create Route"), 0 }, (VikToolConstructorFunc) tool_new_route_create, NULL, NULL, NULL, @@ -436,7 +436,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"), "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"), "E", N_("Edit Waypoint"), 0 }, (VikToolConstructorFunc) tool_edit_waypoint_create, @@ -446,7 +455,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"), "K", N_("Edit Trackpoint"), 0 }, (VikToolConstructorFunc) tool_edit_trackpoint_create, @@ -456,29 +465,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"), "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"), "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 }; @@ -771,6 +775,51 @@ VikLayerInterface vik_trw_layer_interface = { (VikLayerFuncSelectedViewportMenu) trw_layer_show_selected_viewport_menu, }; +static gboolean have_diary_program = FALSE; +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; + // 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 ) ) { + // 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 ); + + gchar **tokens = NULL; + if ( stdout && g_strcmp0(stdout, "") ) + tokens = g_strsplit(stdout, " ", 0); + else if ( stderr ) + tokens = g_strsplit(stderr, " ", 0); + + 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 ( stdout ); + g_free ( stderr ); + } + + if ( g_find_program_in_path ( a_geojson_program_export() ) ) { + have_geojson_export = TRUE; + } +} + GType vik_trw_layer_get_type () { static GType vtl_type = 0; @@ -782,7 +831,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 +840,6 @@ GType vik_trw_layer_get_type () }; vtl_type = g_type_register_static ( VIK_LAYER_TYPE, "VikTrwLayer", &vtl_info, 0 ); } - return vtl_type; } @@ -884,7 +932,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) ); @@ -1402,7 +1450,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; @@ -2296,6 +2344,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 { @@ -2305,6 +2354,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; } } @@ -2369,11 +2419,13 @@ static void trw_layer_draw_with_highlight ( VikTrwLayer *l, gpointer data, gbool static void trw_layer_draw ( VikTrwLayer *l, gpointer data ) { - // TODO: learn which highlight vtl in dp somehow or just ask vikwindow here, - // then check if highlighted vtl and skip drawing if (highlight mode off) - // as it will then get redrawn - // may seem slightly inefficient - but for very large vtls, this should save redraws... - trw_layer_draw_with_highlight ( l, data, FALSE ) ; + // 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 ) @@ -2682,6 +2734,7 @@ static gboolean trw_layer_sublayer_toggle_visible ( VikTrwLayer *l, gint subtype else return TRUE; } + default: break; } return TRUE; } @@ -2710,31 +2763,32 @@ static void trw_layer_tracks_tooltip ( const gchar *name, VikTrack *tr, tooltip_ 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); + } } } @@ -2762,7 +2816,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 (); @@ -2869,11 +2923,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 ); + if ( dur > 0 ) + g_snprintf ( time_buf2, sizeof(time_buf2), _("- %d:%02d hrs:mins"), (int)round(dur/3600), (int)round((dur/60)%60) ); } // Get length and consider the appropriate distance units gdouble tr_len = vik_track_get_length(tr); @@ -3233,7 +3285,7 @@ void trw_layer_zoom_to_show_latlons ( VikTrwLayer *vtl, VikViewport *vvp, struct 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 ); + vik_viewport_set_center_coord ( vvp, &coord, TRUE ); /* Convert into definite 'smallest' and 'largest' positions */ struct LatLon minmin; @@ -3334,6 +3386,15 @@ static void trw_layer_export_kml ( menu_array_layer values ) g_free ( auto_save_name ); } +static void trw_layer_export_geojson ( menu_array_layer values ) +{ + gchar *auto_save_name = append_file_ext ( vik_layer_get_name(VIK_LAYER(values[MA_VTL])), FILE_TYPE_GEOJSON ); + + 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])); @@ -3418,7 +3479,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 @@ -3562,7 +3623,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 ); } /* @@ -3570,7 +3634,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 ); } @@ -3587,7 +3650,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 ); } @@ -3627,7 +3689,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 @@ -3636,6 +3697,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; @@ -3743,19 +3812,6 @@ 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]); @@ -3837,6 +3893,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) ); } @@ -3856,7 +3913,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 ) @@ -3990,6 +4047,13 @@ 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 ); + 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 ); + } + 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); @@ -4391,9 +4455,19 @@ 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 ( ! 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 { @@ -4534,13 +4608,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; @@ -4589,9 +4661,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; @@ -4762,7 +4831,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); @@ -4780,7 +4848,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); @@ -5048,13 +5115,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) ); } } @@ -5186,15 +5253,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 ); } /** @@ -5572,7 +5637,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) @@ -5580,7 +5645,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; } @@ -5604,34 +5669,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"); @@ -5717,7 +5789,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; @@ -5787,7 +5859,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; } @@ -5823,7 +5895,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); @@ -5900,7 +5972,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); @@ -5993,7 +6065,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); @@ -6033,7 +6105,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 */ @@ -6506,6 +6578,57 @@ static void trw_layer_reverse ( menu_array_sublayer values ) vik_layer_emit_update ( VIK_LAYER(vtl) ); } +/** + * Open a diary at the specified date + */ +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 ); + 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" ); + 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.") ); + } +} + /** * Similar to trw_layer_enum_item, but this uses a sorted method */ @@ -7289,7 +7412,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); @@ -7555,7 +7680,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) ); @@ -8168,6 +8294,17 @@ static gboolean trw_layer_sublayer_add_menu_items ( VikTrwLayer *l, GtkMenu *men } } + // Only made available if a suitable program is installed + if ( have_diary_program ) { + if ( subtype == VIK_TRW_LAYER_SUBLAYER_TRACK || subtype == VIK_TRW_LAYER_SUBLAYER_WAYPOINT ) { + item = gtk_image_menu_item_new_with_mnemonic ( _("Diar_y") ); + 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(menu), item ); + gtk_widget_show ( item ); + } + } + #ifdef VIK_CONFIG_GOOGLE if ( subtype == VIK_TRW_LAYER_SUBLAYER_ROUTE && is_valid_google_route ( l, sublayer ) ) { @@ -8370,7 +8507,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 ); + vik_trw_layer_tpwin_set_tp ( vtl->tpwin, vtl->current_tpl, vtl->current_tp_track->name, vtl->current_tp_track->is_route ); } else if ( response == VIK_TRW_LAYER_TPWIN_DELETE ) { @@ -8384,20 +8521,20 @@ 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 ); + vik_trw_layer_tpwin_set_tp ( vtl->tpwin, vtl->current_tpl, vtl->current_tp_track->name, vtl->current_tp_track->is_route ); 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 ); + vik_trw_layer_tpwin_set_tp ( vtl->tpwin, vtl->current_tpl = vtl->current_tpl->next, vtl->current_tp_track->name, vtl->current_tp_track->is_route ); 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 ); + vik_trw_layer_tpwin_set_tp ( vtl->tpwin, vtl->current_tpl = vtl->current_tpl->prev, vtl->current_tp_track->name, vtl->current_tp_track->is_route ); vik_layer_emit_update(VIK_LAYER(vtl)); } else if ( response == VIK_TRW_LAYER_TPWIN_INSERT && vtl->current_tpl->next ) @@ -8524,7 +8661,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 ); + vik_trw_layer_tpwin_set_tp ( vtl->tpwin, vtl->current_tpl, vtl->current_tp_track->name, vtl->current_tp_track->is_route ); /* set layer name and TP data */ } @@ -8732,7 +8869,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 ); + vik_trw_layer_tpwin_set_tp ( vtl->tpwin, vtl->current_tpl, vtl->current_tp_track->name, vtl->current_tp_track->is_route ); // NB don't reset the selected trackpoint, thus ensuring it's still in the tpwin } } @@ -8847,7 +8984,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 ); + vik_trw_layer_tpwin_set_tp ( vtl->tpwin, vtl->current_tpl, vtl->current_tp_track->name, vtl->current_tp_track->is_route ); vik_layer_emit_update ( VIK_LAYER(vtl) ); return TRUE; @@ -8882,7 +9019,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 ); + vik_trw_layer_tpwin_set_tp ( vtl->tpwin, vtl->current_tpl, vtl->current_tp_track->name, vtl->current_tp_track->is_route ); vik_layer_emit_update ( VIK_LAYER(vtl) ); return TRUE; @@ -9096,7 +9233,10 @@ static gboolean tool_edit_waypoint_click ( VikTrwLayer *vtl, GdkEventButton *eve g_hash_table_foreach ( vtl->waypoints, (GHFunc) waypoint_search_closest_tp, ¶ms); 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 ) @@ -9466,6 +9606,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; @@ -9553,17 +9700,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 ); } @@ -9586,16 +9736,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 ); } @@ -9781,7 +9936,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 ); + vik_trw_layer_tpwin_set_tp ( vtl->tpwin, vtl->current_tpl, vtl->current_tp_track->name, vtl->current_tp_track->is_route ); vik_layer_emit_update ( VIK_LAYER(vtl) ); return TRUE; @@ -9790,77 +9945,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; + } + // 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->route_finder_started || (event->state & GDK_CONTROL_MASK && vtl->route_finder_current_track) ) { + 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) @@ -10384,16 +10583,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; } }