]> git.street.me.uk Git - andy/viking.git/commitdiff
SF Features#100: Allow 'easy' changing of the time of trackpoints & waypoints.
authorRob Norris <rw_norris@hotmail.com>
Thu, 24 Apr 2014 19:49:04 +0000 (20:49 +0100)
committerRob Norris <rw_norris@hotmail.com>
Fri, 25 Apr 2014 22:42:23 +0000 (23:42 +0100)
Add and use a dialog to get the time and date in the users timezone to allow setting the timestamp.
The dialog uses the calendar widget to get the date and spin boxes for the hours, minutes and seconds.

src/Makefile.am
src/dialog.c
src/vikdatetime_edit_dialog.c [new file with mode: 0644]
src/vikdatetime_edit_dialog.h [new file with mode: 0644]
src/viktrwlayer_tpwin.c

index 7c732dbea01600f705f1a3fdac5a43f04a4fd336..14d2a07583624cceef24ae666517eb3a55a20f0d 100644 (file)
@@ -128,6 +128,7 @@ libviking_a_SOURCES = \
        googlesearch.c googlesearch.h \
        dem.c dem.h \
        vikdemlayer.h vikdemlayer.c \
+       vikdatetime_edit_dialog.c vikdatetime_edit_dialog.h \
        vikfilelist.c vikfilelist.h \
        vikexttool.c vikexttool.h \
        vikexttools.c vikexttools.h \
index 79d0f38b9157987bc904aa1aefd962dbe2760f58..ca6bcdb16c64fd532ec19af3b8a3c8aad310ddb5 100644 (file)
@@ -34,6 +34,7 @@
 #include "vikgoto.h"
 #include "util.h"
 #include "geotag_exif.h"
+#include "vikdatetime_edit_dialog.h"
 
 #include <glib/gi18n.h>
 
@@ -180,6 +181,34 @@ void a_dialog_response_accept ( GtkDialog *dialog )
   gtk_dialog_response ( dialog, GTK_RESPONSE_ACCEPT );
 }
 
+static void update_time ( GtkWidget *widget, time_t timestamp )
+{
+  gchar tmp_str[64];
+  strftime ( tmp_str, sizeof(tmp_str), "%c", localtime(&(timestamp)) );
+  gtk_button_set_label ( GTK_BUTTON(widget), tmp_str );
+}
+
+static VikWaypoint *edit_wp;
+
+static void time_edit_click ( GtkWidget *widget, VikWaypoint *wp )
+{
+  GTimeZone *gtz = g_time_zone_new_local ();
+  time_t mytime = vik_datetime_edit_dialog ( GTK_WINDOW(gtk_widget_get_toplevel(widget)),
+                                             _("Date/Time Edit"),
+                                             wp->timestamp,
+                                             gtz );
+  g_time_zone_unref ( gtz );
+
+  // Was the dialog cancelled?
+  if ( mytime == 0 )
+    return;
+
+  // Otherwise use new value in the edit buffer
+  edit_wp->timestamp = mytime;
+
+  update_time ( widget, edit_wp->timestamp );
+}
+
 static void symbol_entry_changed_cb(GtkWidget *combo, GtkListStore *store)
 {
   GtkTreeIter iter;
@@ -213,7 +242,7 @@ gchar *a_dialog_waypoint ( GtkWindow *parent, gchar *default_name, VikTrwLayer *
   GtkWidget *latlabel, *lonlabel, *namelabel, *latentry, *lonentry, *altentry, *altlabel, *nameentry=NULL;
   GtkWidget *commentlabel, *commententry, *descriptionlabel, *descriptionentry, *imagelabel, *imageentry, *symbollabel, *symbolentry;
   GtkWidget *timelabel = NULL;
-  GtkWidget *timevaluelabel = NULL; // No editing of time allowed ATM
+  GtkWidget *timevaluebutton = NULL;
   GtkWidget *hasGeotagCB = NULL;
   GtkWidget *consistentGeotagCB = NULL;
   GtkListStore *store;
@@ -346,12 +375,15 @@ gchar *a_dialog_waypoint ( GtkWindow *parent, gchar *default_name, VikTrwLayer *
     }
   }
 
+
+  if ( !edit_wp )
+    edit_wp = vik_waypoint_new ();
   if ( !is_new && wp->has_timestamp ) {
-    gchar tmp_str[64];
     timelabel = gtk_label_new ( _("Time:") );
-    timevaluelabel = gtk_label_new ( NULL );
-    strftime ( tmp_str, sizeof(tmp_str), "%c", localtime(&(wp->timestamp)) );
-    gtk_label_set_text ( GTK_LABEL(timevaluelabel), tmp_str );
+    timevaluebutton = gtk_button_new();
+    gtk_button_set_relief ( GTK_BUTTON(timevaluebutton), GTK_RELIEF_NONE );
+    update_time ( timevaluebutton, wp->timestamp );
+    g_signal_connect ( G_OBJECT(timevaluebutton), "clicked", G_CALLBACK(time_edit_click), edit_wp );
   }
 
   gtk_box_pack_start (GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(dialog))), latlabel, FALSE, FALSE, 0);
@@ -360,7 +392,7 @@ gchar *a_dialog_waypoint ( GtkWindow *parent, gchar *default_name, VikTrwLayer *
   gtk_box_pack_start (GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(dialog))), lonentry, FALSE, FALSE, 0);
   if ( timelabel ) {
     gtk_box_pack_start (GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(dialog))), timelabel, FALSE, FALSE, 0);
-    gtk_box_pack_start (GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(dialog))), timevaluelabel, FALSE, FALSE, 0);
+    gtk_box_pack_start (GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(dialog))), timevaluebutton, FALSE, FALSE, 0);
   }
   gtk_box_pack_start (GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(dialog))), altlabel, FALSE, FALSE, 0);
   gtk_box_pack_start (GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(dialog))), altentry, FALSE, FALSE, 0);
@@ -420,6 +452,10 @@ gchar *a_dialog_waypoint ( GtkWindow *parent, gchar *default_name, VikTrwLayer *
         vik_waypoint_set_image ( wp, vik_file_entry_get_filename ( VIK_FILE_ENTRY(imageentry) ) );
       if ( wp->image && *(wp->image) && (!a_thumbnails_exists(wp->image)) )
         a_thumbnails_create ( wp->image );
+      if ( edit_wp->timestamp ) {
+        wp->timestamp = edit_wp->timestamp;
+        wp->has_timestamp = TRUE;
+      }
 
       GtkTreeIter iter, first;
       gtk_tree_model_get_iter_first ( GTK_TREE_MODEL(store), &first );
diff --git a/src/vikdatetime_edit_dialog.c b/src/vikdatetime_edit_dialog.c
new file mode 100644 (file)
index 0000000..528b441
--- /dev/null
@@ -0,0 +1,138 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4 -*- */
+/*
+ * viking -- GPS Data and Topo Analyzer, Explorer, and Manager
+ *
+ * Copyright (C) 2014, Rob Norris <rw_norris@hotmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+#include "vikdatetime_edit_dialog.h"
+
+// Show leading zeros
+static gboolean on_output ( GtkSpinButton *spin, gpointer data )
+{
+       GtkAdjustment *adjustment = gtk_spin_button_get_adjustment ( spin );
+       gint value = (gint)gtk_adjustment_get_value ( adjustment );
+       gchar *text = g_strdup_printf ( "%02d", value );
+       gtk_entry_set_text ( GTK_ENTRY (spin), text );
+       g_free ( text );
+
+       return TRUE;
+}
+
+/**
+ * vik_datetime_edit_dialog:
+ * @parent:         The parent window
+ * @title:          The title to use for the dialog
+ * @initial_time:   The inital date/time to be shown
+ * @tz:             The #GTimeZone this dialog will operate in
+ *
+ * Returns: A time selected by the user via this dialog
+ *          Even though a time of zero is notionally valid - consider it unlikely to be actually wanted!
+ *          Thus if the time is zero then the dialog was cancelled or somehow an invalid date was encountered.
+ */
+time_t vik_datetime_edit_dialog ( GtkWindow *parent, const gchar *title, time_t initial_time, GTimeZone *tz )
+{
+       g_return_val_if_fail ( tz, 0 );
+
+       GtkWidget *dialog = gtk_dialog_new_with_buttons ( title,
+                                                         parent,
+                                                         GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
+                                                         GTK_STOCK_CANCEL, GTK_RESPONSE_REJECT,
+                                                         GTK_STOCK_OK,     GTK_RESPONSE_ACCEPT,
+                                                         NULL );
+
+       gtk_dialog_set_default_response ( GTK_DIALOG(dialog), GTK_RESPONSE_ACCEPT );
+       GtkWidget *response_w = NULL;
+#if GTK_CHECK_VERSION (2, 20, 0)
+       response_w = gtk_dialog_get_widget_for_response ( GTK_DIALOG(dialog), GTK_RESPONSE_ACCEPT );
+#endif
+
+       GtkWidget *label;
+       GtkWidget *cal = gtk_calendar_new ();
+
+       // Set according to the given date/time + timezone for display
+       GDateTime *gdt_in = g_date_time_new_from_unix_utc ( (gint64)initial_time );
+       GDateTime *gdt_tz = g_date_time_to_timezone ( gdt_in, tz );
+       g_date_time_unref ( gdt_in );
+
+       gtk_calendar_select_month ( GTK_CALENDAR(cal), g_date_time_get_month(gdt_tz)-1, g_date_time_get_year (gdt_tz) );
+       gtk_calendar_select_day ( GTK_CALENDAR(cal), g_date_time_get_day_of_month(gdt_tz) );
+
+       GtkWidget *hbox_time = gtk_hbox_new ( FALSE, 1 );
+
+       label = gtk_label_new ( g_date_time_get_timezone_abbreviation(gdt_tz) );
+       gtk_box_pack_start ( GTK_BOX(hbox_time), label, FALSE, FALSE, 5 );
+
+       GtkWidget *sb_hours = gtk_spin_button_new_with_range ( 0.0, 23.0, 1.0 );
+       gtk_box_pack_start ( GTK_BOX(hbox_time), sb_hours, FALSE, FALSE, 0 );
+       gtk_spin_button_set_value ( GTK_SPIN_BUTTON(sb_hours), g_date_time_get_hour(gdt_tz) );
+       g_signal_connect ( sb_hours, "output", G_CALLBACK(on_output), NULL );
+
+       label = gtk_label_new ( ":" );
+       gtk_box_pack_start ( GTK_BOX(hbox_time), label, FALSE, FALSE, 0 );
+
+       GtkWidget *sb_minutes = gtk_spin_button_new_with_range ( 0.0, 59.0, 1.0 );
+       gtk_box_pack_start ( GTK_BOX(hbox_time), sb_minutes, FALSE, FALSE, 0);
+       gtk_spin_button_set_value ( GTK_SPIN_BUTTON(sb_minutes), g_date_time_get_minute(gdt_tz) );
+       g_signal_connect ( sb_minutes, "output", G_CALLBACK(on_output), NULL );
+
+       label = gtk_label_new ( ":" );
+       gtk_box_pack_start(GTK_BOX(hbox_time), label, FALSE, FALSE, 0);
+
+       GtkWidget *sb_seconds = gtk_spin_button_new_with_range ( 0.0, 59.0, 1.0 );
+       gtk_box_pack_start ( GTK_BOX(hbox_time), sb_seconds, FALSE, FALSE, 0 );
+       gtk_spin_button_set_value ( GTK_SPIN_BUTTON(sb_seconds), g_date_time_get_second(gdt_tz) );
+       g_signal_connect ( sb_seconds, "output", G_CALLBACK(on_output), NULL );
+
+       gtk_box_pack_start ( GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(dialog))), cal, FALSE, FALSE, 0 );
+       gtk_box_pack_start ( GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(dialog))), hbox_time, FALSE, FALSE, 5 );
+
+       if ( response_w )
+               gtk_widget_grab_focus ( response_w );
+
+       g_date_time_unref ( gdt_tz );
+
+       gtk_widget_show_all ( dialog );
+       if ( gtk_dialog_run ( GTK_DIALOG(dialog) ) != GTK_RESPONSE_ACCEPT ) {
+               gtk_widget_destroy ( dialog );
+               return 0;
+       }
+
+       // Read values
+       guint year = 0;
+       guint month = 0;
+       guint day = 0;
+       guint hours = 0;
+       guint minutes = 0;
+       guint seconds = 0;
+
+       gtk_calendar_get_date ( GTK_CALENDAR(cal), &year, &month, &day );
+       hours = gtk_spin_button_get_value_as_int ( GTK_SPIN_BUTTON(sb_hours) );
+       minutes = gtk_spin_button_get_value_as_int ( GTK_SPIN_BUTTON(sb_minutes) );
+       seconds = gtk_spin_button_get_value_as_int ( GTK_SPIN_BUTTON(sb_seconds) );
+
+       gtk_widget_destroy(dialog);
+
+       time_t ans = initial_time;
+       GDateTime *gdt_ans = g_date_time_new ( tz, year, month+1, day, hours, minutes, (gdouble)seconds );
+       if ( gdt_ans ) {
+               ans = g_date_time_to_unix ( gdt_ans );
+               g_date_time_unref ( gdt_ans );
+       }
+
+       return ans;
+}
diff --git a/src/vikdatetime_edit_dialog.h b/src/vikdatetime_edit_dialog.h
new file mode 100644 (file)
index 0000000..d513e2b
--- /dev/null
@@ -0,0 +1,35 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4 -*- */
+/*
+ * viking -- GPS Data and Topo Analyzer, Explorer, and Manager
+ *
+ * Copyright (C) 2014, Rob Norris <rw_norris@hotmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+#ifndef _VIK_DATE_TIME_EDIT_H
+#define _VIK_DATE_TIME_EDIT_H
+
+#include <time.h>
+#include <glib.h>
+#include <gtk/gtk.h>
+
+G_BEGIN_DECLS
+
+time_t vik_datetime_edit_dialog ( GtkWindow *parent, const gchar *title, time_t initial_time, GTimeZone *tz );
+
+G_END_DECLS
+
+#endif
index 5f7bf812bf297660c6dfd896aaa3f97f98809bba..45d2359117ae605da992ef9c9220d6a2b6814615 100644 (file)
 #include "vikwaypoint.h"
 #include "dialog.h"
 #include "globals.h"
+#include "vikdatetime_edit_dialog.h"
 
 struct _VikTrwLayerTpwin {
   GtkDialog parent;
   GtkSpinButton *lat, *lon, *alt, *ts;
   GtkWidget *trkpt_name;
-  GtkLabel *course, *localtime, *diff_dist, *diff_time, *diff_speed, *speed, *hdop, *vdop, *pdop, *sat;
+  GtkWidget *localtime;
+  GtkLabel *course, *diff_dist, *diff_time, *diff_speed, *speed, *hdop, *vdop, *pdop, *sat;
   // Previously these buttons were in a glist, however I think the ordering behaviour is implicit
   //  thus control manually to ensure operating on the correct button
   GtkWidget *button_close;
@@ -87,11 +89,11 @@ static void tpwin_update_times ( VikTrwLayerTpwin *tpwin, VikTrackpoint *tp )
   if ( tp->has_timestamp ) {
     gtk_spin_button_set_value ( tpwin->ts, tp->timestamp );
     strftime ( tmp_str, sizeof(tmp_str), "%c", localtime(&(tp->timestamp)) );
-    gtk_label_set_text ( tpwin->localtime, tmp_str );
+    gtk_button_set_label ( GTK_BUTTON(tpwin->localtime), tmp_str );
   }
   else {
     gtk_spin_button_set_value ( tpwin->ts, 0 );
-    gtk_label_set_text (tpwin->localtime, NULL );
+    gtk_button_set_label ( GTK_BUTTON(tpwin->localtime), "" );
   }
 }
 
@@ -145,6 +147,36 @@ static void tpwin_sync_ts_to_tp ( VikTrwLayerTpwin *tpwin )
   }
 }
 
+/**
+ * tpwin_sync_time_to_tp:
+ *
+ */
+static void tpwin_sync_time_to_tp ( VikTrwLayerTpwin *tpwin )
+{
+  if ( !tpwin->cur_tp || tpwin->sync_to_tp_block )
+    return;
+  // Currently disable setting the time via this way when the point doesn't have one
+  if ( !tpwin->cur_tp->has_timestamp )
+    return;
+
+  GTimeZone *gtz = g_time_zone_new_local ();
+  guint mytime = vik_datetime_edit_dialog ( GTK_WINDOW(gtk_widget_get_toplevel(GTK_WIDGET(&tpwin->parent))),
+                                            _("Date/Time Edit"),
+                                            tpwin->cur_tp->timestamp,
+                                            gtz );
+  g_time_zone_unref ( gtz );
+
+  // Was the dialog cancelled?
+  if ( mytime == 0 )
+    return;
+
+  // Otherwise use the new value
+  tpwin->cur_tp->timestamp = mytime;
+  // TODO: consider warning about unsorted times?
+
+  tpwin_update_times ( tpwin, tpwin->cur_tp );
+}
+
 static gboolean tpwin_set_name ( VikTrwLayerTpwin *tpwin )
 {
   if ( tpwin->cur_tp && (!tpwin->sync_to_tp_block) ) {
@@ -204,7 +236,9 @@ VikTrwLayerTpwin *vik_trw_layer_tpwin_new ( GtkWindow *parent )
   g_signal_connect_swapped ( G_OBJECT(tpwin->trkpt_name), "focus-out-event", G_CALLBACK(tpwin_set_name), tpwin );
 
   tpwin->course = GTK_LABEL(gtk_label_new(NULL));
-  tpwin->localtime = GTK_LABEL(gtk_label_new(NULL));
+  tpwin->localtime = gtk_button_new();
+  gtk_button_set_relief ( GTK_BUTTON(tpwin->localtime), GTK_RELIEF_NONE );
+  g_signal_connect_swapped ( G_OBJECT(tpwin->localtime), "clicked", G_CALLBACK(tpwin_sync_time_to_tp), tpwin );
 
   tpwin->lat = GTK_SPIN_BUTTON(gtk_spin_button_new( GTK_ADJUSTMENT(gtk_adjustment_new (
                                  0, -90, 90, 0.00005, 0.01, 0 )), 0.00005, 6));
@@ -281,13 +315,14 @@ void vik_trw_layer_tpwin_set_empty ( VikTrwLayerTpwin *tpwin )
   gtk_editable_delete_text ( GTK_EDITABLE(tpwin->trkpt_name), 0, -1 );
   gtk_widget_set_sensitive ( tpwin->trkpt_name, FALSE );
 
-  gtk_label_set_text ( tpwin->localtime, NULL );
+  gtk_button_set_label ( GTK_BUTTON(tpwin->localtime), "" );
   gtk_label_set_text ( tpwin->course, NULL );
 
   gtk_widget_set_sensitive ( GTK_WIDGET(tpwin->lat), FALSE );
   gtk_widget_set_sensitive ( GTK_WIDGET(tpwin->lon), FALSE );
   gtk_widget_set_sensitive ( GTK_WIDGET(tpwin->alt), FALSE );
   gtk_widget_set_sensitive ( GTK_WIDGET(tpwin->ts), FALSE );
+  gtk_widget_set_sensitive ( GTK_WIDGET(tpwin->localtime), FALSE );
 
   // Only keep close button enabled
   gtk_widget_set_sensitive ( tpwin->button_insert, FALSE );
@@ -334,6 +369,7 @@ void vik_trw_layer_tpwin_set_tp ( VikTrwLayerTpwin *tpwin, GList *tpl, const gch
   gtk_widget_set_sensitive ( GTK_WIDGET(tpwin->lon), TRUE );
   gtk_widget_set_sensitive ( GTK_WIDGET(tpwin->alt), TRUE );
   gtk_widget_set_sensitive ( GTK_WIDGET(tpwin->ts), tp->has_timestamp );
+  gtk_widget_set_sensitive ( GTK_WIDGET(tpwin->localtime), tp->has_timestamp );
 
   vik_trw_layer_tpwin_set_track_name ( tpwin, track_name );