]> git.street.me.uk Git - andy/viking.git/blame - src/viktrwlayer_geotag.c
[QA] Remove spurious commented out code.
[andy/viking.git] / src / viktrwlayer_geotag.c
CommitLineData
b3eb3b98
RN
1/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4 -*- */
2/*
3 * viking -- GPS Data and Topo Analyzer, Explorer, and Manager
4 *
5 * Copyright (C) 2011, Rob Norris <rw_norris@hotmail.com>
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 *
21 */
22/*
23 * Similar to the track and trackpoint properties dialogs,
24 * this is made a separate file for ease of grouping related stuff together
25 */
26#ifdef HAVE_CONFIG_H
27#include "config.h"
28#endif
29#include <math.h>
30#include <time.h>
31#include <string.h>
32#include <stdlib.h>
33#include <gtk/gtk.h>
34#include <glib/gi18n.h>
35#include "viking.h"
36#include "vikfilelist.h"
37#include "geotag_exif.h"
38#include "thumbnails.h"
404328d1 39#include "background.h"
b3eb3b98 40
404328d1 41// Function taken from GPSCorrelate 1.6.1
b3eb3b98
RN
42// ConvertToUnixTime Copyright 2005 Daniel Foote. GPL2+
43
44#define EXIF_DATE_FORMAT "%d:%d:%d %d:%d:%d"
45
46time_t ConvertToUnixTime(char* StringTime, char* Format, int TZOffsetHours, int TZOffsetMinutes)
47{
48 /* Read the time using the specified format.
49 * The format and string being read from must
50 * have the most significant time on the left,
51 * and the least significant on the right:
52 * ie, Year on the left, seconds on the right. */
53
54 /* Sanity check... */
55 if (StringTime == NULL || Format == NULL)
56 {
57 return 0;
58 }
59
60 /* Define and set up our structure. */
61 struct tm Time;
62 Time.tm_wday = 0;
63 Time.tm_yday = 0;
64 Time.tm_isdst = -1;
65
66 /* Read out the time from the string using our format. */
67 sscanf(StringTime, Format, &Time.tm_year, &Time.tm_mon,
68 &Time.tm_mday, &Time.tm_hour,
69 &Time.tm_min, &Time.tm_sec);
70
71 /* Adjust the years for the mktime function to work. */
72 Time.tm_year -= 1900;
73 Time.tm_mon -= 1;
74
75 /* Add our timezone offset to the time.
76 * We don't check to see if it overflowed anything;
77 * mktime does this and fixes it for us. */
78 /* Note also that we SUBTRACT these times. We want the
79 * result to be in UTC. */
80
81 Time.tm_hour -= TZOffsetHours;
82 Time.tm_min -= TZOffsetMinutes;
83
84 /* Calculate and return the unix time. */
85 return mktime(&Time);
86}
87
88// GPSCorrelate END
89
90typedef struct {
91 GtkWidget *dialog;
92 VikFileList *files;
93 VikTrwLayer *vtl; // to pass on
94 VikTrack *track; // Use specified track or all tracks if NULL
95 GtkCheckButton *create_waypoints_b;
cbac0d22
RN
96 GtkLabel *overwrite_waypoints_l; // Referenced so the sensitivity can be changed
97 GtkCheckButton *overwrite_waypoints_b;
b3eb3b98
RN
98 GtkCheckButton *write_exif_b;
99 GtkLabel *overwrite_gps_exif_l; // Referenced so the sensitivity can be changed
100 GtkCheckButton *overwrite_gps_exif_b;
101 GtkLabel *no_change_mtime_l; // Referenced so the sensitivity can be changed
102 GtkCheckButton *no_change_mtime_b;
103 GtkCheckButton *interpolate_segments_b;
104 GtkEntry *time_zone_b; // TODO consider a more user friendly tz widget eg libtimezonemap or similar
105 GtkEntry *time_offset_b;
106} GeoTagWidgets;
107
108static GeoTagWidgets *geotag_widgets_new()
109{
110 GeoTagWidgets *widgets = g_malloc0(sizeof(GeoTagWidgets));
111 return widgets;
112}
113
114static void geotag_widgets_free ( GeoTagWidgets *widgets )
115{
116 // Need to free VikFileList??
117 g_free(widgets);
118}
119
120typedef struct {
121 gboolean create_waypoints;
cbac0d22 122 gboolean overwrite_waypoints;
b3eb3b98
RN
123 gboolean write_exif;
124 gboolean overwrite_gps_exif;
125 gboolean no_change_mtime;
126 gboolean interpolate_segments;
127 gint time_offset;
128 gint TimeZoneHours;
129 gint TimeZoneMins;
130} option_values_t;
131
132typedef struct {
133 VikTrwLayer *vtl;
134 gchar *image;
135 VikTrack *track; // Use specified track or all tracks if NULL
136 // User options...
137 option_values_t ov;
404328d1 138 GList *files;
b3eb3b98
RN
139 time_t PhotoTime;
140 // Store answer from interpolation for an image
141 gboolean found_match;
142 VikCoord coord;
143 gdouble altitude;
144 // If anything has changed
145 gboolean redraw;
146} geotag_options_t;
147
148static option_values_t default_values = {
cbac0d22 149 TRUE,
b3eb3b98
RN
150 TRUE,
151 TRUE,
152 FALSE,
153 TRUE,
154 TRUE,
155 0,
156 0,
157 0,
158};
159
160/**
161 * Correlate the image against the specified track
162 */
89a068d8 163static void trw_layer_geotag_track ( const gpointer id, VikTrack *track, geotag_options_t *options )
b3eb3b98
RN
164{
165 // If already found match then don't need to check this track
166 if ( options->found_match )
167 return;
168
169 VikTrackpoint *trkpt;
170 VikTrackpoint *trkpt_next;
171
5e610fc3
RN
172 GList *mytrkpt;
173 for ( mytrkpt = track->trackpoints; mytrkpt; mytrkpt = mytrkpt->next ) {
b3eb3b98
RN
174
175 // Do something for this trackpoint...
176
177 trkpt = VIK_TRACKPOINT(mytrkpt->data);
178
179 // is it exactly this point?
180 if ( options->PhotoTime == trkpt->timestamp ) {
181 options->coord = trkpt->coord;
182 options->altitude = trkpt->altitude;
183 options->found_match = TRUE;
184 break;
185 }
186
187 // Now need two trackpoints, hence check next is available
188 if ( !mytrkpt->next ) break;
189 trkpt_next = VIK_TRACKPOINT(mytrkpt->next->data);
190
191 // TODO need to use 'has_timestamp' property
192 if ( trkpt->timestamp == trkpt_next->timestamp ) continue;
193 if ( trkpt->timestamp > trkpt_next->timestamp ) continue;
194
195 // When interpolating between segments, no need for any special segment handling
196 if ( !options->ov.interpolate_segments )
197 // Don't check between segments
198 if ( trkpt_next->newsegment )
199 // Simply move on to consider next point
200 continue;
201
202 // Too far
203 if ( trkpt->timestamp > options->PhotoTime ) break;
204
205 // Is is between this and the next point?
206 if ( (options->PhotoTime > trkpt->timestamp) && (options->PhotoTime < trkpt_next->timestamp) ) {
207 options->found_match = TRUE;
208 // Interpolate
209 /* Calculate the "scale": a decimal giving the relative distance
210 * in time between the two points. Ie, a number between 0 and 1 -
211 * 0 is the first point, 1 is the next point, and 0.5 would be
212 * half way. */
213 gdouble scale = (gdouble)trkpt_next->timestamp - (gdouble)trkpt->timestamp;
214 scale = ((gdouble)options->PhotoTime - (gdouble)trkpt->timestamp) / scale;
215
216 struct LatLon ll_result, ll1, ll2;
217
218 vik_coord_to_latlon ( &(trkpt->coord), &ll1 );
219 vik_coord_to_latlon ( &(trkpt_next->coord), &ll2 );
220
221 ll_result.lat = ll1.lat + ((ll2.lat - ll1.lat) * scale);
222
223 // NB This won't cope with going over the 180 degrees longitude boundary
224 ll_result.lon = ll1.lon + ((ll2.lon - ll1.lon) * scale);
225
226 // set coord
227 vik_coord_load_from_latlon ( &(options->coord), VIK_COORD_LATLON, &ll_result );
228
229 // Interpolate elevation
230 options->altitude = trkpt->altitude + ((trkpt_next->altitude - trkpt->altitude) * scale);
231 break;
232 }
233
234 }
235}
236
237/**
238 * Correlate the image to any track within the TrackWaypoint layer
239 */
240static void trw_layer_geotag_process ( geotag_options_t *options )
241{
404328d1 242 if ( !options->vtl || !IS_VIK_LAYER(options->vtl) )
b3eb3b98
RN
243 return;
244
245 if ( !options->image )
246 return;
247
248 gboolean has_gps_exif = FALSE;
249 gchar* datetime = a_geotag_get_exif_date_from_file ( options->image, &has_gps_exif );
250
251 if ( datetime ) {
252
253 // If image already has gps info - don't attempt to change it.
254 if ( !options->ov.overwrite_gps_exif && has_gps_exif ) {
255 if ( options->ov.create_waypoints ) {
256 // Create waypoint with file information
257 gchar *name = NULL;
258 VikWaypoint *wp = a_geotag_create_waypoint_from_file ( options->image, vik_trw_layer_get_coord_mode (options->vtl), &name );
0fb2c85d
RN
259 if ( !wp ) {
260 // Couldn't create Waypoint
261 g_free ( datetime );
262 return;
263 }
b3eb3b98
RN
264 if ( !name )
265 name = g_strdup ( a_file_basename ( options->image ) );
cbac0d22
RN
266
267 gboolean updated_waypoint = FALSE;
268
269 if ( options->ov.overwrite_waypoints ) {
270 VikWaypoint *current_wp = vik_trw_layer_get_waypoint ( options->vtl, name );
271 if ( current_wp ) {
272 // Existing wp found, so set new position, comment and image
273 current_wp = a_geotag_waypoint_positioned ( options->image, wp->coord, wp->altitude, &name, current_wp );
274 updated_waypoint = TRUE;
275 }
276 }
277
278 if ( !updated_waypoint ) {
279 vik_trw_layer_filein_add_waypoint ( options->vtl, name, wp );
280 }
281
b3eb3b98
RN
282 g_free ( name );
283
284 // Mark for redraw
285 options->redraw = TRUE;
286 }
0847b808 287 g_free ( datetime );
b3eb3b98
RN
288 return;
289 }
290
291 options->PhotoTime = ConvertToUnixTime ( datetime, EXIF_DATE_FORMAT, options->ov.TimeZoneHours, options->ov.TimeZoneMins);
292 g_free ( datetime );
293
294 // Apply any offset
295 options->PhotoTime = options->PhotoTime + options->ov.time_offset;
296
297 options->found_match = FALSE;
298
299 if ( options->track ) {
300 // Single specified track
89a068d8 301 // NB Doesn't care about track id
b3eb3b98
RN
302 trw_layer_geotag_track ( NULL, options->track, options );
303 }
304 else {
305 // Try all tracks
306 GHashTable *tracks = vik_trw_layer_get_tracks ( options->vtl );
307 if ( g_hash_table_size (tracks) > 0 ) {
308 g_hash_table_foreach ( tracks, (GHFunc) trw_layer_geotag_track, options );
309 }
310 }
311
312 // Match found ?
313 if ( options->found_match ) {
314
315 if ( options->ov.create_waypoints ) {
316
cbac0d22
RN
317 gboolean updated_waypoint = FALSE;
318
319 if ( options->ov.overwrite_waypoints ) {
b3eb3b98 320
cbac0d22
RN
321 // Update existing WP
322 // Find a WP with current name
323 gchar *name = NULL;
324 name = g_strdup ( a_file_basename ( options->image ) );
325 VikWaypoint *wp = vik_trw_layer_get_waypoint ( options->vtl, name );
326 if ( wp ) {
327 // Found, so set new position, comment and image
328 wp = a_geotag_waypoint_positioned ( options->image, options->coord, options->altitude, &name, wp );
329 updated_waypoint = TRUE;
330 }
331 g_free ( name );
332 }
333
334 if ( !updated_waypoint ) {
335 // Create waypoint with found position
336 gchar *name = NULL;
337 VikWaypoint *wp = a_geotag_waypoint_positioned ( options->image, options->coord, options->altitude, &name, NULL );
338 if ( !name )
339 name = g_strdup ( a_file_basename ( options->image ) );
340 vik_trw_layer_filein_add_waypoint ( options->vtl, name, wp );
341 g_free ( name );
342 }
343
b3eb3b98
RN
344 // Mark for redraw
345 options->redraw = TRUE;
346 }
347
348 // Write EXIF if specified
349 if ( options->ov.write_exif ) {
350 a_geotag_write_exif_gps ( options->image, options->coord, options->altitude, options->ov.no_change_mtime );
351 }
352 }
353 }
354}
355
404328d1
RN
356/*
357 * Tidy up
358 */
359static void trw_layer_geotag_thread_free ( geotag_options_t *gtd )
360{
361 if ( gtd->files )
362 g_list_free ( gtd->files );
363 g_free ( gtd );
364}
365
366/**
367 * Run geotagging process in a separate thread
368 */
369static int trw_layer_geotag_thread ( geotag_options_t *options, gpointer threaddata )
370{
371 guint total = g_list_length(options->files), done = 0;
372
373 // TODO decide how to report any issues to the user ...
374
375 // Foreach file attempt to geotag it
376 while ( options->files ) {
377 options->image = (gchar *) ( options->files->data );
378 trw_layer_geotag_process ( options );
379 options->files = options->files->next;
380
381 // Update thread progress and detect stop requests
382 int result = a_background_thread_progress ( threaddata, ((gdouble) ++done) / total );
383 if ( result != 0 )
384 return -1; /* Abort thread */
385 }
386
387 if ( options->redraw ) {
388 if ( IS_VIK_LAYER(options->vtl) ) {
389 // Ensure any new images get shown
390 trw_layer_verify_thumbnails ( options->vtl, NULL ); // NB second parameter not used ATM
391 // Force redraw as verify only redraws if there are new thumbnails (they may already exist)
da121f9b 392 vik_layer_emit_update ( VIK_LAYER(options->vtl) ); // NB Update from background
404328d1
RN
393 }
394 }
395
396 return 0;
397}
398
b3eb3b98
RN
399/**
400 * Parse user input from dialog response
401 */
402static void trw_layer_geotag_response_cb ( GtkDialog *dialog, gint resp, GeoTagWidgets *widgets )
403{
404 switch (resp) {
405 case GTK_RESPONSE_DELETE_EVENT: /* received delete event (not from buttons) */
406 case GTK_RESPONSE_REJECT:
407 break;
408 default: {
409 //GTK_RESPONSE_ACCEPT:
410 // Get options
404328d1
RN
411 geotag_options_t *options = g_malloc ( sizeof(geotag_options_t) );
412 options->vtl = widgets->vtl;
413 options->track = widgets->track;
b3eb3b98 414 // Values extracted from the widgets:
404328d1 415 options->ov.create_waypoints = gtk_toggle_button_get_active ( GTK_TOGGLE_BUTTON(widgets->create_waypoints_b) );
cbac0d22 416 options->ov.overwrite_waypoints = gtk_toggle_button_get_active ( GTK_TOGGLE_BUTTON(widgets->overwrite_waypoints_b) );
404328d1
RN
417 options->ov.write_exif = gtk_toggle_button_get_active ( GTK_TOGGLE_BUTTON(widgets->write_exif_b) );
418 options->ov.overwrite_gps_exif = gtk_toggle_button_get_active ( GTK_TOGGLE_BUTTON(widgets->overwrite_gps_exif_b) );
419 options->ov.no_change_mtime = gtk_toggle_button_get_active ( GTK_TOGGLE_BUTTON(widgets->no_change_mtime_b) );
420 options->ov.interpolate_segments = gtk_toggle_button_get_active ( GTK_TOGGLE_BUTTON(widgets->interpolate_segments_b) );
421 options->ov.TimeZoneHours = 0;
422 options->ov.TimeZoneMins = 0;
b3eb3b98
RN
423 const gchar* TZString = gtk_entry_get_text(GTK_ENTRY(widgets->time_zone_b));
424 /* Check the string. If there is a colon, then (hopefully) it's a time in xx:xx format.
425 * If not, it's probably just a +/-xx format. In all other cases,
426 * it will be interpreted as +/-xx, which, if given a string, returns 0. */
427 if (strstr(TZString, ":")) {
428 /* Found colon. Split into two. */
404328d1
RN
429 sscanf(TZString, "%d:%d", &options->ov.TimeZoneHours, &options->ov.TimeZoneMins);
430 if (options->ov.TimeZoneHours < 0)
431 options->ov.TimeZoneMins *= -1;
b3eb3b98
RN
432 } else {
433 /* No colon. Just parse. */
404328d1 434 options->ov.TimeZoneHours = atoi(TZString);
b3eb3b98 435 }
404328d1 436 options->ov.time_offset = atoi ( gtk_entry_get_text ( GTK_ENTRY(widgets->time_offset_b) ) );
b3eb3b98 437
404328d1 438 options->redraw = FALSE;
b3eb3b98
RN
439
440 // Save settings for reuse
404328d1 441 default_values = options->ov;
b3eb3b98 442
404328d1
RN
443 options->files = g_list_copy ( vik_file_list_get_files ( widgets->files ) );
444
445 gint len = g_list_length ( options->files );
446 gchar *tmp = g_strdup_printf ( _("Geotagging %d Images..."), len );
447
448 // Processing lots of files can take time - so run a background effort
449 a_background_thread ( VIK_GTK_WINDOW_FROM_LAYER(options->vtl),
450 tmp,
451 (vik_thr_func) trw_layer_geotag_thread,
452 options,
453 (vik_thr_free_func) trw_layer_geotag_thread_free,
454 NULL,
455 len );
456
457 g_free ( tmp );
b3eb3b98
RN
458
459 break;
460 }
461 }
462 geotag_widgets_free ( widgets );
463 gtk_widget_destroy ( GTK_WIDGET(dialog) );
464}
465
466/**
467 * Handle widget sensitivities
468 */
469static void write_exif_b_cb ( GtkWidget *gw, GeoTagWidgets *gtw )
470{
471 // Overwriting & file modification times are irrelevant if not going to write EXIF!
472 if ( gtk_toggle_button_get_active ( GTK_TOGGLE_BUTTON(gtw->write_exif_b) ) ) {
473 gtk_widget_set_sensitive ( GTK_WIDGET(gtw->overwrite_gps_exif_b), TRUE );
474 gtk_widget_set_sensitive ( GTK_WIDGET(gtw->overwrite_gps_exif_l), TRUE );
475 gtk_widget_set_sensitive ( GTK_WIDGET(gtw->no_change_mtime_b), TRUE );
476 gtk_widget_set_sensitive ( GTK_WIDGET(gtw->no_change_mtime_l), TRUE );
477 }
478 else {
479 gtk_widget_set_sensitive ( GTK_WIDGET(gtw->overwrite_gps_exif_b), FALSE );
480 gtk_widget_set_sensitive ( GTK_WIDGET(gtw->overwrite_gps_exif_l), FALSE );
481 gtk_widget_set_sensitive ( GTK_WIDGET(gtw->no_change_mtime_b), FALSE );
482 gtk_widget_set_sensitive ( GTK_WIDGET(gtw->no_change_mtime_l), FALSE );
483 }
484}
485
cbac0d22
RN
486static void create_waypoints_b_cb ( GtkWidget *gw, GeoTagWidgets *gtw )
487{
488 // Overwriting waypoints are irrelevant if not going to create them!
489 if ( gtk_toggle_button_get_active ( GTK_TOGGLE_BUTTON(gtw->create_waypoints_b) ) ) {
490 gtk_widget_set_sensitive ( GTK_WIDGET(gtw->overwrite_waypoints_b), TRUE );
491 gtk_widget_set_sensitive ( GTK_WIDGET(gtw->overwrite_waypoints_l), TRUE );
492 }
493 else {
494 gtk_widget_set_sensitive ( GTK_WIDGET(gtw->overwrite_waypoints_b), FALSE );
495 gtk_widget_set_sensitive ( GTK_WIDGET(gtw->overwrite_waypoints_l), FALSE );
496 }
497}
b3eb3b98
RN
498
499/**
500 * trw_layer_geotag_dialog:
501 * @parent: The Window of the calling process
502 * @vtl: The VikTrwLayer to use for correlating images to tracks
503 * @track: Optional - The particular track to use (if specified) for correlating images
504 * @track_name: Optional - The name of specified track to use
505 */
506void trw_layer_geotag_dialog ( GtkWindow *parent, VikTrwLayer *vtl, VikTrack *track, const gchar *track_name )
507{
508 GeoTagWidgets *widgets = geotag_widgets_new();
509
510 widgets->dialog = gtk_dialog_new_with_buttons ( _("Geotag Images"),
511 parent,
512 GTK_DIALOG_DESTROY_WITH_PARENT,
513 GTK_STOCK_CANCEL, GTK_RESPONSE_REJECT,
514 GTK_STOCK_OK, GTK_RESPONSE_ACCEPT,
515 NULL );
516 widgets->files = VIK_FILE_LIST(vik_file_list_new ( _("Images") )); // TODO would be nice to be able to set a filefilter
517 widgets->vtl = vtl;
518 widgets->track = track;
519 widgets->create_waypoints_b = GTK_CHECK_BUTTON ( gtk_check_button_new () );
cbac0d22
RN
520 widgets->overwrite_waypoints_l = GTK_LABEL ( gtk_label_new ( _("Overwrite Existing Waypoints:") ) );
521 widgets->overwrite_waypoints_b = GTK_CHECK_BUTTON ( gtk_check_button_new () );
b3eb3b98
RN
522 widgets->write_exif_b = GTK_CHECK_BUTTON ( gtk_check_button_new () );
523 widgets->overwrite_gps_exif_l = GTK_LABEL ( gtk_label_new ( _("Overwrite Existing GPS Information:") ) );
524 widgets->overwrite_gps_exif_b = GTK_CHECK_BUTTON ( gtk_check_button_new () );
525 widgets->no_change_mtime_l = GTK_LABEL ( gtk_label_new ( _("Keep File Modification Timestamp:") ) );
526 widgets->no_change_mtime_b = GTK_CHECK_BUTTON ( gtk_check_button_new () );
527 widgets->interpolate_segments_b = GTK_CHECK_BUTTON ( gtk_check_button_new () );
528 widgets->time_zone_b = GTK_ENTRY ( gtk_entry_new () );
529 widgets->time_offset_b = GTK_ENTRY ( gtk_entry_new () );
530
531 gtk_entry_set_width_chars ( widgets->time_zone_b, 7);
532 gtk_entry_set_width_chars ( widgets->time_offset_b, 7);
533
534 // Defaults - TODO restore previous values / save settings somewhere??
535 gtk_toggle_button_set_active ( GTK_TOGGLE_BUTTON(widgets->create_waypoints_b), default_values.create_waypoints );
cbac0d22 536 gtk_toggle_button_set_active ( GTK_TOGGLE_BUTTON(widgets->overwrite_waypoints_b), default_values.overwrite_waypoints );
b3eb3b98
RN
537 gtk_toggle_button_set_active ( GTK_TOGGLE_BUTTON(widgets->write_exif_b), default_values.write_exif );
538 gtk_toggle_button_set_active ( GTK_TOGGLE_BUTTON(widgets->overwrite_gps_exif_b), default_values.overwrite_gps_exif );
539 gtk_toggle_button_set_active ( GTK_TOGGLE_BUTTON(widgets->no_change_mtime_b), default_values.no_change_mtime );
540 gtk_toggle_button_set_active ( GTK_TOGGLE_BUTTON(widgets->interpolate_segments_b), default_values.interpolate_segments );
541 gchar tmp_string[7];
542 snprintf (tmp_string, 7, "%+02d:%02d", default_values.TimeZoneHours, abs (default_values.TimeZoneMins) );
543 gtk_entry_set_text ( widgets->time_zone_b, tmp_string );
544 snprintf (tmp_string, 7, "%d", default_values.time_offset );
545 gtk_entry_set_text ( widgets->time_offset_b, tmp_string );
546
547 // Ensure sensitivities setup
548 write_exif_b_cb ( GTK_WIDGET(widgets->write_exif_b), widgets );
b3eb3b98
RN
549 g_signal_connect ( G_OBJECT(widgets->write_exif_b), "toggled", G_CALLBACK(write_exif_b_cb), widgets );
550
cbac0d22
RN
551 create_waypoints_b_cb ( GTK_WIDGET(widgets->create_waypoints_b), widgets );
552 g_signal_connect ( G_OBJECT(widgets->create_waypoints_b), "toggled", G_CALLBACK(create_waypoints_b_cb), widgets );
553
b3eb3b98
RN
554 GtkWidget *cw_hbox = gtk_hbox_new ( FALSE, 0 );
555 gtk_box_pack_start ( GTK_BOX(cw_hbox), gtk_label_new ( _("Create Waypoints:") ), FALSE, FALSE, 5 );
556 gtk_box_pack_start ( GTK_BOX(cw_hbox), GTK_WIDGET(widgets->create_waypoints_b), FALSE, FALSE, 5 );
557
cbac0d22
RN
558 GtkWidget *ow_hbox = gtk_hbox_new ( FALSE, 0 );
559 gtk_box_pack_start ( GTK_BOX(ow_hbox), GTK_WIDGET(widgets->overwrite_waypoints_l), FALSE, FALSE, 5 );
560 gtk_box_pack_start ( GTK_BOX(ow_hbox), GTK_WIDGET(widgets->overwrite_waypoints_b), FALSE, FALSE, 5 );
561
b3eb3b98
RN
562 GtkWidget *we_hbox = gtk_hbox_new ( FALSE, 0 );
563 gtk_box_pack_start ( GTK_BOX(we_hbox), gtk_label_new ( _("Write EXIF:") ), FALSE, FALSE, 5 );
564 gtk_box_pack_start ( GTK_BOX(we_hbox), GTK_WIDGET(widgets->write_exif_b), FALSE, FALSE, 5 );
565
566 GtkWidget *og_hbox = gtk_hbox_new ( FALSE, 0 );
567 gtk_box_pack_start ( GTK_BOX(og_hbox), GTK_WIDGET(widgets->overwrite_gps_exif_l), FALSE, FALSE, 5 );
568 gtk_box_pack_start ( GTK_BOX(og_hbox), GTK_WIDGET(widgets->overwrite_gps_exif_b), FALSE, FALSE, 5 );
569
570 GtkWidget *fm_hbox = gtk_hbox_new ( FALSE, 0 );
571 gtk_box_pack_start ( GTK_BOX(fm_hbox), GTK_WIDGET(widgets->no_change_mtime_l), FALSE, FALSE, 5 );
572 gtk_box_pack_start ( GTK_BOX(fm_hbox), GTK_WIDGET(widgets->no_change_mtime_b), FALSE, FALSE, 5 );
573
574 GtkWidget *is_hbox = gtk_hbox_new ( FALSE, 0 );
575 gtk_box_pack_start ( GTK_BOX(is_hbox), gtk_label_new ( _("Interpolate Between Track Segments:") ), FALSE, FALSE, 5 );
576 gtk_box_pack_start ( GTK_BOX(is_hbox), GTK_WIDGET(widgets->interpolate_segments_b), FALSE, FALSE, 5 );
577
578 GtkWidget *to_hbox = gtk_hbox_new ( FALSE, 0 );
579 gtk_box_pack_start ( GTK_BOX(to_hbox), gtk_label_new ( _("Image Time Offset (Seconds):") ), FALSE, FALSE, 5 );
580 gtk_box_pack_start ( GTK_BOX(to_hbox), GTK_WIDGET(widgets->time_offset_b), FALSE, FALSE, 5 );
581 gtk_widget_set_tooltip_text ( GTK_WIDGET(widgets->time_offset_b), _("The number of seconds to ADD to the photos time to make it match the GPS data. Calculate this with (GPS - Photo). Can be negative or positive. Useful to adjust times when a camera's timestamp was incorrect.") );
582
583 GtkWidget *tz_hbox = gtk_hbox_new ( FALSE, 0 );
584 gtk_box_pack_start ( GTK_BOX(tz_hbox), gtk_label_new ( _("Image Timezone:") ), FALSE, FALSE, 5 );
585 gtk_box_pack_start ( GTK_BOX(tz_hbox), GTK_WIDGET(widgets->time_zone_b), FALSE, FALSE, 5 );
586 gtk_widget_set_tooltip_text ( GTK_WIDGET(widgets->time_zone_b), _("The timezone that was used when the images were created. For example, if a camera is set to AWST or +8:00 hours. Enter +8:00 here so that the correct adjustment to the images' time can be made. GPS data is always in UTC.") );
587
588 gchar *track_string = NULL;
589 if ( widgets->track )
590 track_string = g_strdup_printf ( _("Using track: %s"), track_name );
591 else
592 track_string = g_strdup_printf ( _("Using all tracks in: %s"), VIK_LAYER(widgets->vtl)->name );
593
9b082b39
RN
594 gtk_box_pack_start ( GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(widgets->dialog))), gtk_label_new ( track_string ), FALSE, FALSE, 5 );
595
596 gtk_box_pack_start ( GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(widgets->dialog))), GTK_WIDGET(widgets->files), TRUE, TRUE, 0 );
597
598 gtk_box_pack_start ( GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(widgets->dialog))), cw_hbox, FALSE, FALSE, 0);
599 gtk_box_pack_start ( GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(widgets->dialog))), ow_hbox, FALSE, FALSE, 0);
600 gtk_box_pack_start ( GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(widgets->dialog))), we_hbox, FALSE, FALSE, 0);
601 gtk_box_pack_start ( GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(widgets->dialog))), og_hbox, FALSE, FALSE, 0);
602 gtk_box_pack_start ( GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(widgets->dialog))), fm_hbox, FALSE, FALSE, 0);
603 gtk_box_pack_start ( GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(widgets->dialog))), is_hbox, FALSE, FALSE, 0);
604 gtk_box_pack_start ( GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(widgets->dialog))), to_hbox, FALSE, FALSE, 0);
605 gtk_box_pack_start ( GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(widgets->dialog))), tz_hbox, FALSE, FALSE, 0);
b3eb3b98
RN
606
607 g_signal_connect ( widgets->dialog, "response", G_CALLBACK(trw_layer_geotag_response_cb), widgets );
608
609 gtk_dialog_set_default_response ( GTK_DIALOG(widgets->dialog), GTK_RESPONSE_REJECT );
610
611 gtk_widget_show_all ( widgets->dialog );
612
613 g_free ( track_string );
614}