diff -Nru gpsprune-18.6/build.sh gpsprune-19/build.sh
--- gpsprune-18.6/build.sh 2016-12-18 18:50:24.000000000 +0000
+++ gpsprune-19/build.sh 2018-05-09 18:41:18.000000000 +0000
@@ -1,6 +1,6 @@
-# Build script using external exif library
+# Build script
# Version number
-PRUNENAME=gpsprune_18.6
+PRUNENAME=gpsprune_19
# remove compile directory
rm -rf compile
# remove dist directory
@@ -8,7 +8,7 @@
# create compile directory
mkdir compile
# compile java
-javac -cp /usr/share/java/metadata-extractor.jar -d compile $( find tim -name "*.java" -print )
+javac -d compile $( find tim -name "*.java" -print )
# add other required resources
cp -r tim/prune/lang compile/tim/prune/
cp -r tim/prune/*.txt compile/tim/prune/
diff -Nru gpsprune-18.6/debian/changelog gpsprune-19/debian/changelog
--- gpsprune-18.6/debian/changelog 2017-07-21 17:55:16.000000000 +0000
+++ gpsprune-19/debian/changelog 2018-08-26 15:25:08.000000000 +0000
@@ -1,3 +1,28 @@
+gpsprune (19-2~bionic0) bionic; urgency=medium
+
+ * No change rebuild for Bionic.
+
+ -- Angelos Tzotsos Sun, 26 Aug 2018 18:00:00 +0200
+
+gpsprune (19-2) unstable; urgency=medium
+
+ * Bump Standards-Version to 4.1.5, no changes.
+ * Drop autopkgtest to test installability.
+ * Add lintian override for testsuite-autopkgtest-missing.
+
+ -- Bas Couwenberg Tue, 31 Jul 2018 18:15:08 +0200
+
+gpsprune (19-1) unstable; urgency=medium
+
+ * New upstream release.
+ * Strip trailing whitespace from changelog & rules files.
+ * Bump Standards-Version to 4.1.4, no changes.
+ * Update Vcs-* URLs for Salsa.
+ * Add license & copyright for metadata-extractor sources.
+ * Drop metadata-extractor dependencies & patches.
+
+ -- Bas Couwenberg Sun, 13 May 2018 08:14:05 +0200
+
gpsprune (18.6-2) unstable; urgency=medium
* Add patches to fix FTBFS with metadata extractor 2.10.1.
@@ -110,7 +135,7 @@
gpsprune (17-1) unstable; urgency=medium
- * New upstream release.
+ * New upstream release.
-- Mònica Ramírez Arceda Thu, 25 Sep 2014 10:28:51 +0200
diff -Nru gpsprune-18.6/debian/control gpsprune-19/debian/control
--- gpsprune-18.6/debian/control 2017-07-21 17:54:02.000000000 +0000
+++ gpsprune-19/debian/control 2018-07-05 08:08:32.000000000 +0000
@@ -11,11 +11,10 @@
default-jdk,
fastjar,
libjava3d-java,
- libvecmath-java,
- libmetadata-extractor-java (>= 2.10.1)
-Standards-Version: 4.0.0
-Vcs-Browser: https://anonscm.debian.org/cgit/pkg-grass/gpsprune.git
-Vcs-Git: https://anonscm.debian.org/git/pkg-grass/gpsprune.git
+ libvecmath-java
+Standards-Version: 4.1.5
+Vcs-Browser: https://salsa.debian.org/debian-gis-team/gpsprune
+Vcs-Git: https://salsa.debian.org/debian-gis-team/gpsprune.git
Homepage: https://activityworkshop.net/software/gpsprune/index.html
Package: gpsprune
@@ -58,4 +57,3 @@
coordinates yet, GpsPrune can be used to connect them (either manually or
automatically using the photo timestamps) to data points, and write
these coordinates into the EXIF tags.
-
diff -Nru gpsprune-18.6/debian/copyright gpsprune-19/debian/copyright
--- gpsprune-18.6/debian/copyright 2017-07-21 17:54:02.000000000 +0000
+++ gpsprune-19/debian/copyright 2018-05-13 05:59:42.000000000 +0000
@@ -4,12 +4,12 @@
Source: https://activityworkshop.net/software/gpsprune/download.html
Files: *
-Copyright: 2006-2016, activityworkshop.net
+Copyright: 2006-2018, activityworkshop.net
License: GPL-2
-Files: debian/*
-Copyright: 2010-2014, David Paleino
-License: GPL-2
+Files: tim/prune/jpeg/drew/*
+Copyright: 2002-2015, Drew Noakes
+License: Apache-2.0
Files: tim/prune/function/srtm/gen/tiles*.txt
tim/prune/function/srtm/srtmtiles.dat
@@ -27,6 +27,10 @@
The tiles*.txt files can be re-generated with the debian/scripts/get-tiles.py
script.
+Files: debian/*
+Copyright: 2010-2014, David Paleino
+License: GPL-2
+
License: GPL-2
This package is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License version 2 as
@@ -44,3 +48,19 @@
On Debian systems, the complete text of the GNU General Public License
version 2 can be found in `/usr/share/common-licenses/GPL-2'.
+License: Apache-2.0
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+ .
+ http://www.apache.org/licenses/LICENSE-2.0
+ .
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ .
+ On Debian systems, the complete text of the Apache License can be found
+ in `/usr/share/common-licenses/Apache-2.0'.
+
diff -Nru gpsprune-18.6/debian/manifest gpsprune-19/debian/manifest
--- gpsprune-18.6/debian/manifest 2017-07-21 17:54:02.000000000 +0000
+++ gpsprune-19/debian/manifest 2018-05-13 06:01:57.000000000 +0000
@@ -1,4 +1,4 @@
usr/share/gpsprune/gpsprune.jar:
Main-Class: tim.prune.GpsPrune
Debian-Java-Home: /usr/lib/jvm/default-java
- Class-Path: /usr/share/java/j3dcore.jar /usr/share/java/j3dutils.jar /usr/share/java/vecmath.jar /usr/share/gpsprune/gpsprune.jar /usr/share/java/metadata-extractor.jar
+ Class-Path: /usr/share/java/j3dcore.jar /usr/share/java/j3dutils.jar /usr/share/java/vecmath.jar /usr/share/gpsprune/gpsprune.jar
diff -Nru gpsprune-18.6/debian/patches/metadata-extractor-2.10.1-disable-hasThumbnail.patch gpsprune-19/debian/patches/metadata-extractor-2.10.1-disable-hasThumbnail.patch
--- gpsprune-18.6/debian/patches/metadata-extractor-2.10.1-disable-hasThumbnail.patch 2017-07-21 17:54:02.000000000 +0000
+++ gpsprune-19/debian/patches/metadata-extractor-2.10.1-disable-hasThumbnail.patch 1970-01-01 00:00:00.000000000 +0000
@@ -1,34 +0,0 @@
-Description: Disable hasThumbnailData() call.
- metadata extractor 2.10.1 no longer provides this method.
-Author: Bas Couwenberg
-Bug-Debian: https://bugs.debian.org/866762
-
---- a/tim/prune/jpeg/ExternalExifLibrary.java
-+++ b/tim/prune/jpeg/ExternalExifLibrary.java
-@@ -110,6 +110,7 @@ public class ExternalExifLibrary impleme
- }
- }
-
-+ /* hasThumbnailData() is no longer support in metadata extractor 2.10.1
- if (metadata.containsDirectoryOfType(ExifThumbnailDirectory.class))
- {
- ExifThumbnailDirectory exifdir = metadata.getFirstDirectoryOfType(ExifThumbnailDirectory.class);
-@@ -124,6 +125,7 @@ public class ExternalExifLibrary impleme
- data.setThumbnailImage(thumb);
- }
- }
-+ */
-
- }
- catch (Exception e) {
---- a/tim/prune/load/JpegLoader.java
-+++ b/tim/prune/load/JpegLoader.java
-@@ -245,7 +245,7 @@ public class JpegLoader implements Runna
- if (timestamp == null && jpegData.getDigitizedTimestamp() != null) {
- timestamp = createTimestamp(jpegData.getDigitizedTimestamp());
- }
-- photo.setExifThumbnail(jpegData.getThumbnailImage());
-+ //photo.setExifThumbnail(jpegData.getThumbnailImage());
- // Also extract orientation tag for setting rotation state of photo
- photo.setRotation(jpegData.getRequiredRotation());
- // Set bearing, if any
diff -Nru gpsprune-18.6/debian/patches/metadata-extractor-2.10.1.patch gpsprune-19/debian/patches/metadata-extractor-2.10.1.patch
--- gpsprune-18.6/debian/patches/metadata-extractor-2.10.1.patch 2017-07-21 17:54:02.000000000 +0000
+++ gpsprune-19/debian/patches/metadata-extractor-2.10.1.patch 1970-01-01 00:00:00.000000000 +0000
@@ -1,55 +0,0 @@
-Description: metadata extractor 2.10.1 support.
-Author: Markus Koschany
-Bug-Debian: https://bugs.debian.org/866762
-Bug: https://github.com/activityworkshop/GpsPrune/issues/13
-
---- a/tim/prune/jpeg/ExternalExifLibrary.java
-+++ b/tim/prune/jpeg/ExternalExifLibrary.java
-@@ -34,9 +34,9 @@ public class ExternalExifLibrary impleme
- try
- {
- Metadata metadata = ImageMetadataReader.readMetadata(inFile);
-- if (metadata.containsDirectory(GpsDirectory.class))
-+ if (metadata.containsDirectoryOfType(GpsDirectory.class))
- {
-- Directory gpsdir = metadata.getDirectory(GpsDirectory.class);
-+ Directory gpsdir = metadata.getFirstDirectoryOfType(GpsDirectory.class);
- if (gpsdir.containsTag(GpsDirectory.TAG_LATITUDE)
- && gpsdir.containsTag(GpsDirectory.TAG_LONGITUDE)
- && gpsdir.containsTag(GpsDirectory.TAG_LATITUDE_REF)
-@@ -86,9 +86,9 @@ public class ExternalExifLibrary impleme
- }
-
- // Tags from Exif directory
-- if (metadata.containsDirectory(ExifSubIFDDirectory.class))
-+ if (metadata.containsDirectoryOfType(ExifSubIFDDirectory.class))
- {
-- Directory exifdir = metadata.getDirectory(ExifSubIFDDirectory.class);
-+ Directory exifdir = metadata.getFirstDirectoryOfType(ExifSubIFDDirectory.class);
-
- // Take time and date from exif tags
- if (exifdir.containsTag(ExifSubIFDDirectory.TAG_DATETIME_ORIGINAL)) {
-@@ -99,9 +99,9 @@ public class ExternalExifLibrary impleme
- data.setDigitizedTimestamp(exifdir.getString(ExifSubIFDDirectory.TAG_DATETIME_DIGITIZED));
- }
- }
-- if (metadata.containsDirectory(ExifIFD0Directory.class))
-+ if (metadata.containsDirectoryOfType(ExifIFD0Directory.class))
- {
-- Directory exifdir = metadata.getDirectory(ExifIFD0Directory.class);
-+ Directory exifdir = metadata.getFirstDirectoryOfType(ExifIFD0Directory.class);
-
- // Photo rotation code
- if (exifdir.containsTag(ExifIFD0Directory.TAG_ORIENTATION)) {
-@@ -110,9 +110,9 @@ public class ExternalExifLibrary impleme
- }
- }
-
-- if (metadata.containsDirectory(ExifThumbnailDirectory.class))
-+ if (metadata.containsDirectoryOfType(ExifThumbnailDirectory.class))
- {
-- ExifThumbnailDirectory exifdir = metadata.getDirectory(ExifThumbnailDirectory.class);
-+ ExifThumbnailDirectory exifdir = metadata.getFirstDirectoryOfType(ExifThumbnailDirectory.class);
-
- // TODO: Check this thumbnail stuff
- if (exifdir.hasThumbnailData())
diff -Nru gpsprune-18.6/debian/patches/series gpsprune-19/debian/patches/series
--- gpsprune-18.6/debian/patches/series 2017-07-21 17:54:02.000000000 +0000
+++ gpsprune-19/debian/patches/series 1970-01-01 00:00:00.000000000 +0000
@@ -1,2 +0,0 @@
-metadata-extractor-2.10.1.patch
-metadata-extractor-2.10.1-disable-hasThumbnail.patch
diff -Nru gpsprune-18.6/debian/rules gpsprune-19/debian/rules
--- gpsprune-18.6/debian/rules 2017-07-21 17:54:02.000000000 +0000
+++ gpsprune-19/debian/rules 2018-05-13 06:01:43.000000000 +0000
@@ -5,7 +5,7 @@
#export DH_VERBOSE=1
export JAVA_HOME=/usr/lib/jvm/default-java
-export CLASSPATH=/usr/share/java/j3dcore.jar:/usr/share/java/j3dutils.jar:/usr/share/java/vecmath.jar:/usr/share/java/metadata-extractor.jar
+export CLASSPATH=/usr/share/java/j3dcore.jar:/usr/share/java/j3dutils.jar:/usr/share/java/vecmath.jar
export JH_JAR_EXTRA=$(shell find tim/prune/lang/ tim/prune/gui/images -type f) tim/prune/function/srtm/srtmtiles.dat
@@ -37,4 +37,3 @@
install -o root -g root -d $(CURDIR)/debian/gpsprune/usr/share/icons/hicolor/$${size}x$${size}/apps ; \
install -o root -g root -m 644 $(CURDIR)/tim/prune/gui/images/window_icon_$${size}.png $(CURDIR)/debian/gpsprune/usr/share/icons/hicolor/$${size}x$${size}/apps/gpsprune.png ; \
done
-
diff -Nru gpsprune-18.6/debian/source/lintian-overrides gpsprune-19/debian/source/lintian-overrides
--- gpsprune-18.6/debian/source/lintian-overrides 1970-01-01 00:00:00.000000000 +0000
+++ gpsprune-19/debian/source/lintian-overrides 2018-07-31 16:14:59.000000000 +0000
@@ -0,0 +1,3 @@
+# Not worth the effort
+testsuite-autopkgtest-missing
+
diff -Nru gpsprune-18.6/debian/tests/control gpsprune-19/debian/tests/control
--- gpsprune-18.6/debian/tests/control 2017-07-21 17:54:02.000000000 +0000
+++ gpsprune-19/debian/tests/control 1970-01-01 00:00:00.000000000 +0000
@@ -1,3 +0,0 @@
-# Test installability
-Depends: @
-Test-Command: /bin/true
diff -Nru gpsprune-18.6/tim/prune/App.java gpsprune-19/tim/prune/App.java
--- gpsprune-18.6/tim/prune/App.java 2016-12-18 18:50:24.000000000 +0000
+++ gpsprune-19/tim/prune/App.java 2018-05-09 18:41:18.000000000 +0000
@@ -24,10 +24,10 @@
import tim.prune.data.SourceInfo.FILE_TYPE;
import tim.prune.data.Unit;
import tim.prune.function.AsyncMediaLoader;
-import tim.prune.function.SaveConfig;
import tim.prune.function.SelectTracksFunction;
import tim.prune.function.edit.FieldEditList;
import tim.prune.function.edit.PointEditor;
+import tim.prune.function.settings.SaveConfig;
import tim.prune.gui.MenuManager;
import tim.prune.gui.SidebarController;
import tim.prune.gui.UndoManager;
@@ -402,16 +402,16 @@
}
/**
- * Complete the add time offset function with the specified offset
+ * Complete the add time offset function with the specified offset in seconds
* @param inTimeOffset time offset to add (+ve for add, -ve for subtract)
*/
- public void finishAddTimeOffset(long inTimeOffset)
+ public void finishAddTimeOffsetSeconds(long inTimeOffset)
{
// Construct undo information
int selStart = _trackInfo.getSelection().getStart();
int selEnd = _trackInfo.getSelection().getEnd();
UndoAddTimeOffset undo = new UndoAddTimeOffset(selStart, selEnd, inTimeOffset);
- if (_trackInfo.getTrack().addTimeOffset(selStart, selEnd, inTimeOffset, false))
+ if (_trackInfo.getTrack().addTimeOffsetSeconds(selStart, selEnd, inTimeOffset, false))
{
_undoStack.add(undo);
UpdateMessageBroker.informSubscribers(DataSubscriber.DATA_EDITED);
diff -Nru gpsprune-18.6/tim/prune/config/Config.java gpsprune-19/tim/prune/config/Config.java
--- gpsprune-18.6/tim/prune/config/Config.java 2016-12-18 18:50:24.000000000 +0000
+++ gpsprune-19/tim/prune/config/Config.java 2018-05-09 18:41:18.000000000 +0000
@@ -99,6 +99,12 @@
public static final String KEY_TERRAIN_GRID_SIZE = "prune.terraingridsize";
/** Key for altitude tolerance */
public static final String KEY_ALTITUDE_TOLERANCE = "prune.altitudetolerance";
+ /** Key for waypoint icons to use */
+ public static final String KEY_WAYPOINT_ICONS = "prune.waypointicons";
+ /** Size of waypoint icons to use */
+ public static final String KEY_WAYPOINT_ICON_SIZE = "prune.waypointiconsize";
+ /** Id of selected timezone */
+ public static final String KEY_TIMEZONE_ID = "prune.timezoneid";
/** Initialise the default properties */
@@ -194,6 +200,7 @@
props.put(KEY_HEIGHT_EXAGGERATION, "100"); // 100%, no exaggeration
props.put(KEY_TERRAIN_GRID_SIZE, "50");
props.put(KEY_ALTITUDE_TOLERANCE, "0"); // 0, all exact as before
+ props.put(KEY_WAYPOINT_ICON_SIZE, "1"); // medium size
return props;
}
diff -Nru gpsprune-18.6/tim/prune/config/TimezoneHelper.java gpsprune-19/tim/prune/config/TimezoneHelper.java
--- gpsprune-18.6/tim/prune/config/TimezoneHelper.java 1970-01-01 00:00:00.000000000 +0000
+++ gpsprune-19/tim/prune/config/TimezoneHelper.java 2018-05-09 18:41:18.000000000 +0000
@@ -0,0 +1,22 @@
+package tim.prune.config;
+
+import java.util.TimeZone;
+
+public abstract class TimezoneHelper
+{
+
+ /**
+ * @return the timezone selected in the Config
+ */
+ public static TimeZone getSelectedTimezone()
+ {
+ final String zoneId = Config.getConfigString(Config.KEY_TIMEZONE_ID);
+ if (zoneId == null || zoneId.equals("")) {
+ return TimeZone.getDefault();
+ }
+ else {
+ return TimeZone.getTimeZone(zoneId);
+ }
+ }
+
+}
diff -Nru gpsprune-18.6/tim/prune/copyright.txt gpsprune-19/tim/prune/copyright.txt
--- gpsprune-18.6/tim/prune/copyright.txt 2016-12-18 18:50:24.000000000 +0000
+++ gpsprune-19/tim/prune/copyright.txt 2018-05-09 18:41:18.000000000 +0000
@@ -1,9 +1,9 @@
-The source code of GpsPrune is copyright 2006-2016 activityworkshop.net
+The source code of GpsPrune is copyright 2006-2018 activityworkshop.net
and is distributed under the terms of the Gnu GPL version 2.
-Portions of the package jpeg.drew (if included in this package) were taken
-from Drew Noakes' "Metadata extractor" v2.3.1 which is
-copyright Drew Noakes 2002-2006 and was placed in the public domain.
+Portions of the package jpeg.drew were taken
+from Drew Noakes' "Metadata extractor" v2.7.2 which is
+copyright Drew Noakes 2002-2015 and released under Apache 2.0.
Translations are copyright various contributors, some of whom are named
in the source code and some preferred to remain anonymous.
\ No newline at end of file
diff -Nru gpsprune-18.6/tim/prune/correlate/AudioCorrelator.java gpsprune-19/tim/prune/correlate/AudioCorrelator.java
--- gpsprune-18.6/tim/prune/correlate/AudioCorrelator.java 2016-12-18 18:50:23.000000000 +0000
+++ gpsprune-19/tim/prune/correlate/AudioCorrelator.java 2018-05-09 18:41:18.000000000 +0000
@@ -11,6 +11,7 @@
import tim.prune.DataSubscriber;
import tim.prune.I18nManager;
import tim.prune.UpdateMessageBroker;
+import tim.prune.config.TimezoneHelper;
import tim.prune.data.AudioClip;
import tim.prune.data.AudioList;
import tim.prune.data.DataPoint;
@@ -18,6 +19,7 @@
import tim.prune.data.MediaList;
import tim.prune.data.TimeDifference;
import tim.prune.data.Timestamp;
+import tim.prune.data.TimestampUtc;
import tim.prune.undo.UndoCorrelateAudios;
/**
@@ -164,14 +166,19 @@
protected Timestamp getMediaTimestamp(MediaObject inMedia)
{
Timestamp tstamp = super.getMediaTimestamp(inMedia);
+ long mediaMillis = tstamp.getMilliseconds(TimezoneHelper.getSelectedTimezone());
try {
AudioClip audio = (AudioClip) inMedia;
int audioLength = audio.getLengthInSeconds();
// Each option is worth half the length of the audio clip, so need to divide by 2
int secsToAdd = audioLength *
(_correlTimesSelector.getSelectedOption() - _fileTimesSelector.getSelectedOption()) / 2;
- if (audioLength > 0 && secsToAdd != 0) {
- tstamp = tstamp.createPlusOffset(secsToAdd);
+ if (audioLength > 0 && secsToAdd != 0)
+ {
+ mediaMillis += (secsToAdd * 1000L);
+ tstamp = new TimestampUtc(mediaMillis);
+ // Here we create a Utc timestamp but it's only temporary for the correlation
+ // so it will never have to react to timezone changes
}
}
catch (ClassCastException cce) {}
diff -Nru gpsprune-18.6/tim/prune/correlate/Correlator.java gpsprune-19/tim/prune/correlate/Correlator.java
--- gpsprune-18.6/tim/prune/correlate/Correlator.java 2016-12-18 18:50:23.000000000 +0000
+++ gpsprune-19/tim/prune/correlate/Correlator.java 2018-05-09 18:41:18.000000000 +0000
@@ -6,8 +6,8 @@
import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
-import java.util.Calendar;
import java.util.Iterator;
+import java.util.TimeZone;
import java.util.TreeSet;
import javax.swing.BorderFactory;
@@ -27,6 +27,7 @@
import tim.prune.App;
import tim.prune.GenericFunction;
import tim.prune.I18nManager;
+import tim.prune.config.TimezoneHelper;
import tim.prune.data.DataPoint;
import tim.prune.data.Distance;
import tim.prune.data.Field;
@@ -50,6 +51,7 @@
protected JTable _previewTable = null;
private boolean _previewEnabled = false; // flag required to enable preview function on final panel
private boolean[] _cardEnabled = null; // flag for each card
+ private TimeZone _timezone = null;
private JTextField _offsetHourBox = null, _offsetMinBox = null, _offsetSecBox = null;
private JRadioButton _mediaLaterOption = null, _pointLaterOption = null;
private JRadioButton _timeLimitRadio = null, _distLimitRadio = null;
@@ -59,6 +61,7 @@
private JButton _nextButton = null, _backButton = null;
protected JButton _okButton = null;
+
/**
* Constructor
* @param inApp App object to report actions to
@@ -110,13 +113,17 @@
_dialog.getContentPane().add(makeDialogContents());
_dialog.pack();
}
+ _okButton.setEnabled(false);
+ // Init timezone to the currently selected one
+ _timezone = TimezoneHelper.getSelectedTimezone();
// Go to first available card
int card = 0;
_cardEnabled = null;
- while (!isCardEnabled(card)) {card++;}
+ while (!isCardEnabled(card)) {
+ card++;
+ }
_cards.showCard(card);
showCard(0); // does set up and next/prev enabling
- _okButton.setEnabled(false);
if (!isCardEnabled(1)) {
_app.showTip(TipManager.Tip_ManuallyCorrelateOne);
}
@@ -205,7 +212,7 @@
&& media.getOriginalStatus() == MediaObject.Status.NOT_CONNECTED)
{
// Calculate time difference, add to table model
- long timeDiff = getMediaTimestamp(media).getSecondsSince(media.getDataPoint().getTimestamp());
+ long timeDiff = getMediaTimestamp(media).getSecondsSince(media.getDataPoint().getTimestamp(), _timezone);
model.addMedia(media, timeDiff);
}
}
@@ -243,27 +250,6 @@
/**
- * @param inFirstTimestamp timestamp of first photo / audio object, or null if not available
- * @return time difference of local time zone from UTC when the first photo was taken
- */
- private static TimeDifference getTimezoneOffset(Timestamp inFirstTimestamp)
- {
- Calendar cal = null;
- // Use first timestamp if available
- if (inFirstTimestamp != null) {
- cal = inFirstTimestamp.getCalendar();
- }
- else {
- // No photo or no timestamp, just use current time
- cal = Calendar.getInstance();
- }
- // Both time zone offset and dst offset are based on milliseconds, so convert to seconds
- TimeDifference timeDiff = new TimeDifference((cal.get(Calendar.ZONE_OFFSET) + cal.get(Calendar.DST_OFFSET)) / 1000);
- return timeDiff;
- }
-
-
- /**
* Calculate the median index to select from the table
* @param inModel table model
* @return index of entry to select from table
@@ -478,7 +464,9 @@
*/
private boolean isCardEnabled(int inCardNum)
{
- if (_cardEnabled == null) {_cardEnabled = getCardEnabledFlags();}
+ if (_cardEnabled == null) {
+ _cardEnabled = getCardEnabledFlags();
+ }
return (inCardNum >= 0 && inCardNum < _cardEnabled.length && _cardEnabled[inCardNum]);
}
@@ -595,7 +583,9 @@
public void createPreview(boolean inFromButton)
{
// Exit if still on first panel
- if (!_previewEnabled) {return;}
+ if (!_previewEnabled) {
+ return;
+ }
// Create a TimeDifference based on the edit boxes
int numHours = getValue(_offsetHourBox.getText());
int numMins = getValue(_offsetMinBox.getText());
@@ -615,12 +605,8 @@
TimeDifference timeDiff = inTimeDiff;
if (timeDiff == null)
{
- // No time difference available, so calculate based on computer's time zone
- Timestamp tstamp = null;
- if (inFirstMedia != null) {
- tstamp = inFirstMedia.getTimestamp();
- }
- timeDiff = getTimezoneOffset(tstamp);
+ // No time difference available, so try with zero
+ timeDiff = new TimeDifference(0L);
}
// Use time difference to set edit boxes
_offsetHourBox.setText("" + timeDiff.getNumHours());
@@ -664,7 +650,7 @@
if (inMedia.hasTimestamp())
{
// Add/subtract offset to media timestamp
- Timestamp mediaStamp = getMediaTimestamp(inMedia).createMinusOffset(inOffset);
+ Timestamp mediaStamp = getMediaTimestamp(inMedia);
int numPoints = inTrack.getNumPoints();
for (int i=0; i _list = new ArrayList();
/** Distance units */
private Unit _distanceUnits = UnitSetLibrary.UNITS_KILOMETRES;
+ /** Current timezone */
+ private TimeZone _timezone = null;
/**
* Constructor
* @param inFirstColumnKey key for first column heading
*/
- public MediaPreviewTableModel(String inFirstColumnKey) {
+ public MediaPreviewTableModel(String inFirstColumnKey)
+ {
_firstColumnHeading = I18nManager.getText(inFirstColumnKey);
+ _timezone = TimezoneHelper.getSelectedTimezone();
}
/**
@@ -83,7 +90,7 @@
if (inColumnIndex == 0) return row.getMedia().getName();
else if (inColumnIndex == 1) {
if (row.getMedia().hasTimestamp()) {
- return row.getMedia().getTimestamp().getText();
+ return row.getMedia().getTimestamp().getText(_timezone);
}
return ""; // media doesn't have a timestamp
}
diff -Nru gpsprune-18.6/tim/prune/correlate/MediaSelectionTableModel.java gpsprune-19/tim/prune/correlate/MediaSelectionTableModel.java
--- gpsprune-18.6/tim/prune/correlate/MediaSelectionTableModel.java 2016-12-18 18:50:23.000000000 +0000
+++ gpsprune-19/tim/prune/correlate/MediaSelectionTableModel.java 2018-05-09 18:41:18.000000000 +0000
@@ -1,8 +1,11 @@
package tim.prune.correlate;
import java.util.ArrayList;
+import java.util.TimeZone;
+
import javax.swing.table.AbstractTableModel;
import tim.prune.I18nManager;
+import tim.prune.config.TimezoneHelper;
import tim.prune.data.MediaObject;
@@ -18,6 +21,8 @@
private String _lastColumnHeading = null;
/** List of rows */
private ArrayList _list = new ArrayList();
+ /** Current timezone */
+ private TimeZone _timezone = null;
/**
@@ -29,6 +34,7 @@
{
_firstColumnHeading = I18nManager.getText(inFirstColumnKey);
_lastColumnHeading = I18nManager.getText(inLastColumnKey);
+ _timezone = TimezoneHelper.getSelectedTimezone();
}
/**
@@ -84,7 +90,8 @@
MediaSelectionTableRow row = _list.get(inRowIndex);
if (inColumnIndex == 0) return row.getMedia().getName();
else if (inColumnIndex == 1) {
- return (row.getMedia().hasTimestamp() ? row.getMedia().getTimestamp().getText() : "");
+ return (row.getMedia().hasTimestamp() ?
+ row.getMedia().getTimestamp().getText(_timezone) : "");
}
else if (inColumnIndex == 2) return row.getTimeDiff().getDescription();
return (row.getTimeDiff().getIsPositive() ? I18nManager.getText("dialog.about.yes") :
diff -Nru gpsprune-18.6/tim/prune/data/AltitudeRange.java gpsprune-19/tim/prune/data/AltitudeRange.java
--- gpsprune-18.6/tim/prune/data/AltitudeRange.java 2016-12-18 18:50:23.000000000 +0000
+++ gpsprune-19/tim/prune/data/AltitudeRange.java 2018-05-09 18:41:18.000000000 +0000
@@ -170,27 +170,25 @@
*/
public boolean hasRange()
{
- return _range.getMaximum() > _range.getMinimum();
+ return _range.hasValues();
}
/**
* @param inUnit altitude units to use
- * @return minimum value, or -1 if none found
+ * @return minimum value
*/
public int getMinimum(Unit inUnit)
{
- if (_range.getMinimum() <= 0) return _range.getMinimum();
return (int) (_range.getMinimum() * inUnit.getMultFactorFromStd());
}
/**
* @param inUnit altitude units to use
- * @return maximum value, or -1 if none found
+ * @return maximum value
*/
public int getMaximum(Unit inUnit)
{
- if (_range.getMaximum() <= 0) return _range.getMaximum();
return (int) (_range.getMaximum() * inUnit.getMultFactorFromStd());
}
diff -Nru gpsprune-18.6/tim/prune/data/AudioClip.java gpsprune-19/tim/prune/data/AudioClip.java
--- gpsprune-18.6/tim/prune/data/AudioClip.java 2016-12-18 18:50:23.000000000 +0000
+++ gpsprune-19/tim/prune/data/AudioClip.java 2018-05-09 18:41:18.000000000 +0000
@@ -23,7 +23,7 @@
public AudioClip(File inFile)
{
// Timestamp is always just taken from the file modification stamp
- super(inFile, new Timestamp(inFile.lastModified()));
+ super(inFile, new TimestampUtc(inFile.lastModified()));
}
/**
diff -Nru gpsprune-18.6/tim/prune/data/DataPoint.java gpsprune-19/tim/prune/data/DataPoint.java
--- gpsprune-18.6/tim/prune/data/DataPoint.java 2016-12-18 18:50:23.000000000 +0000
+++ gpsprune-19/tim/prune/data/DataPoint.java 2018-05-09 18:41:18.000000000 +0000
@@ -81,7 +81,7 @@
}
}
if (inField == null || inField == Field.TIMESTAMP) {
- _timestamp = new Timestamp(getFieldValue(Field.TIMESTAMP));
+ _timestamp = new TimestampUtc(getFieldValue(Field.TIMESTAMP));
}
if (inField == null || inField == Field.WAYPT_NAME) {
_waypointName = getFieldValue(Field.WAYPT_NAME);
@@ -118,7 +118,7 @@
_altitude = inAltitude;
_fieldValues[2] = "" + inAltitude.getValue();
}
- _timestamp = new Timestamp(null);
+ _timestamp = new TimestampUtc(null);
}
@@ -369,12 +369,12 @@
* Add a time offset to this point
* @param inOffset offset to add (-ve to subtract)
*/
- public void addTimeOffset(long inOffset)
+ public void addTimeOffsetSeconds(long inOffset)
{
if (hasTimestamp())
{
- _timestamp.addOffset(inOffset);
- _fieldValues[_fieldList.getFieldIndex(Field.TIMESTAMP)] = _timestamp.getText();
+ _timestamp.addOffsetSeconds(inOffset);
+ _fieldValues[_fieldList.getFieldIndex(Field.TIMESTAMP)] = _timestamp.getText(null);
setModified(false);
}
}
diff -Nru gpsprune-18.6/tim/prune/data/GradientCalculator.java gpsprune-19/tim/prune/data/GradientCalculator.java
--- gpsprune-18.6/tim/prune/data/GradientCalculator.java 2016-12-18 18:50:23.000000000 +0000
+++ gpsprune-19/tim/prune/data/GradientCalculator.java 2018-05-09 18:41:18.000000000 +0000
@@ -40,7 +40,7 @@
&& p.hasAltitude() && q.hasAltitude())
{
final double horizRads = DataPoint.calculateRadiansBetween(p, point) +
- DataPoint.calculateRadiansBetween(point, q);
+ DataPoint.calculateRadiansBetween(point, q);
final double horizDist = Distance.convertRadiansToDistance(horizRads, UnitSetLibrary.UNITS_METRES);
final double heightDiff = q.getAltitude().getMetricValue() - p.getAltitude().getMetricValue();
// Get gradient in radians
diff -Nru gpsprune-18.6/tim/prune/data/IntegerRange.java gpsprune-19/tim/prune/data/IntegerRange.java
--- gpsprune-18.6/tim/prune/data/IntegerRange.java 2016-12-18 18:50:23.000000000 +0000
+++ gpsprune-19/tim/prune/data/IntegerRange.java 2018-05-09 18:41:18.000000000 +0000
@@ -2,11 +2,12 @@
/**
* Represents a range of integers, holding the maximum and
- * minimum values. Values assumed to be >= 0.
+ * minimum values.
*/
public class IntegerRange
{
private int _min = -1, _max = -1;
+ private boolean _foundValues = false;
/**
@@ -16,22 +17,31 @@
{
_min = -1;
_max = -1;
+ _foundValues = false;
}
/**
* Add a value to the range
- * @param inValue value to add, only positive values considered
+ * @param inValue value to add
*/
public void addValue(int inValue)
{
- if (inValue >= 0)
- {
- if (inValue < _min || _min < 0) _min = inValue;
- if (inValue > _max) _max = inValue;
+ if (inValue < _min || !_foundValues) {
+ _min = inValue;
}
+ if (inValue > _max || !_foundValues) {
+ _max = inValue;
+ }
+ _foundValues = true;
}
+ /**
+ * @return true if any values added to the range
+ */
+ public boolean hasValues() {
+ return _foundValues;
+ }
/**
* @return minimum value, or -1 if none found
diff -Nru gpsprune-18.6/tim/prune/data/SpeedCalculator.java gpsprune-19/tim/prune/data/SpeedCalculator.java
--- gpsprune-18.6/tim/prune/data/SpeedCalculator.java 2016-12-18 18:50:23.000000000 +0000
+++ gpsprune-19/tim/prune/data/SpeedCalculator.java 2018-05-09 18:41:18.000000000 +0000
@@ -79,7 +79,7 @@
lateStamp = p.getTimestamp();
}
- stop = (p == null) || p.getSegmentStart() || hasSufficientTimeDifference(point, p);
+ stop = (p == null) || p.getSegmentStart() || hasSufficientTimeDifference(point, p);
index++;
if (p != null && !p.isWaypoint()) {
q = p;
@@ -153,7 +153,7 @@
if (p.hasAltitude()) firstAlt = p.getAltitude();
}
- stop = (p == null) || p.getSegmentStart() || hasSufficientTimeDifference(p, point);
+ stop = (p == null) || p.getSegmentStart() || hasSufficientTimeDifference(p, point);
index--;
}
while (!stop);
@@ -173,7 +173,7 @@
if (p.hasAltitude()) lastAlt = p.getAltitude();
}
- stop = (p == null) || p.getSegmentStart() || hasSufficientTimeDifference(point, p);
+ stop = (p == null) || p.getSegmentStart() || hasSufficientTimeDifference(point, p);
index++;
}
while (!stop);
diff -Nru gpsprune-18.6/tim/prune/data/Timestamp.java gpsprune-19/tim/prune/data/Timestamp.java
--- gpsprune-18.6/tim/prune/data/Timestamp.java 2016-12-18 18:50:23.000000000 +0000
+++ gpsprune-19/tim/prune/data/Timestamp.java 2018-05-09 18:41:18.000000000 +0000
@@ -1,44 +1,29 @@
package tim.prune.data;
+
import java.text.DateFormat;
-import java.text.ParsePosition;
import java.text.SimpleDateFormat;
import java.util.Calendar;
-import java.util.Date;
import java.util.TimeZone;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
+
/**
- * Class to hold the timestamp of a track point
- * and provide conversion functions
+ * Superclass of all timestamp implementations
*/
-public class Timestamp
+public abstract class Timestamp
{
- private boolean _valid = false;
- private long _milliseconds = 0L;
- private String _text = null;
-
- private static final DateFormat DEFAULT_DATETIME_FORMAT = DateFormat.getDateTimeInstance();
private static final DateFormat DEFAULT_DATE_FORMAT = DateFormat.getDateInstance();
private static final DateFormat DEFAULT_TIME_FORMAT = DateFormat.getTimeInstance();
+
+ protected static final DateFormat DEFAULT_DATETIME_FORMAT = DateFormat.getDateTimeInstance();
+
+ protected static final DateFormat ISO_8601_FORMAT
+ = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'");
+ protected static final DateFormat ISO_8601_FORMAT_WITH_MILLIS
+ = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'");
+
private static boolean MillisAddedToTimeFormat = false;
- private static final DateFormat ISO_8601_FORMAT = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'");
- private static final DateFormat ISO_8601_FORMAT_WITH_MILLIS = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'");
- private static final DateFormat ISO_8601_FORMAT_NOZ = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss");
- private static DateFormat[] ALL_DATE_FORMATS = null;
- private static Calendar CALENDAR = null;
- private static final Pattern ISO8601_FRACTIONAL_PATTERN
- = Pattern.compile("(\\d{4})-(\\d{2})-(\\d{2})T(\\d{2}):(\\d{2}):(\\d{2})(?:[\\.,](\\d{1,3}))?(Z|[\\+-]\\d{2}(?::?\\d{2})?)?");
- // year month day T hour minute sec millisec Z or +/- hours : minutes
- private static final Pattern GENERAL_TIMESTAMP_PATTERN
- = Pattern.compile("(\\d{4})\\D(\\d{2})\\D(\\d{2})\\D(\\d{2})\\D(\\d{2})\\D(\\d{2})");
- private static long SECS_SINCE_1970 = 0L;
- private static long SECS_SINCE_GARTRIP = 0L;
- private static long MSECS_SINCE_1970 = 0L;
- private static long MSECS_SINCE_1990 = 0L;
- private static long TWENTY_YEARS_IN_SECS = 0L;
- private static final long GARTRIP_OFFSET = 631065600L;
+
/** Possible formats for parsing and displaying timestamps */
public enum Format
@@ -48,451 +33,110 @@
ISO8601
}
- /** Identifier for the parsing strategy to use */
- private enum ParseType
- {
- NONE,
- ISO8601_FRACTIONAL,
- LONG,
- FIXED_FORMAT0,
- FIXED_FORMAT1,
- FIXED_FORMAT2,
- FIXED_FORMAT3,
- FIXED_FORMAT4,
- FIXED_FORMAT5,
- FIXED_FORMAT6,
- FIXED_FORMAT7,
- FIXED_FORMAT8,
- GENERAL_STRING
- }
-
- /** Array of parse types to loop through (first one is changed to last successful type) */
- private static ParseType[] ALL_PARSE_TYPES = {ParseType.NONE, ParseType.ISO8601_FRACTIONAL, ParseType.LONG,
- ParseType.FIXED_FORMAT0, ParseType.FIXED_FORMAT1, ParseType.FIXED_FORMAT2, ParseType.FIXED_FORMAT3,
- ParseType.FIXED_FORMAT4, ParseType.FIXED_FORMAT5, ParseType.FIXED_FORMAT6, ParseType.FIXED_FORMAT7,
- ParseType.FIXED_FORMAT8, ParseType.GENERAL_STRING};
- // Static block to initialise offsets
+ // Static block to initialise date formats
static
{
- CALENDAR = Calendar.getInstance();
- TimeZone gmtZone = TimeZone.getTimeZone("GMT");
- CALENDAR.setTimeZone(gmtZone);
- MSECS_SINCE_1970 = CALENDAR.getTimeInMillis();
- SECS_SINCE_1970 = MSECS_SINCE_1970 / 1000L;
- SECS_SINCE_GARTRIP = SECS_SINCE_1970 - GARTRIP_OFFSET;
- CALENDAR.add(Calendar.YEAR, -20);
- MSECS_SINCE_1990 = CALENDAR.getTimeInMillis();
- TWENTY_YEARS_IN_SECS = (MSECS_SINCE_1970 - MSECS_SINCE_1990) / 1000L;
// Set timezone for output
+ TimeZone gmtZone = TimeZone.getTimeZone("GMT");
ISO_8601_FORMAT.setTimeZone(gmtZone);
ISO_8601_FORMAT_WITH_MILLIS.setTimeZone(gmtZone);
DEFAULT_DATETIME_FORMAT.setTimeZone(gmtZone);
- // Date formats
- ALL_DATE_FORMATS = new DateFormat[] {
- DEFAULT_DATETIME_FORMAT,
- new SimpleDateFormat("EEE MMM dd HH:mm:ss yyyy"),
- new SimpleDateFormat("HH:mm:ss dd MMM yyyy"),
- new SimpleDateFormat("dd MMM yyyy HH:mm:ss"),
- new SimpleDateFormat("dd-MMM-yyyy HH:mm:ss"),
- new SimpleDateFormat("yyyy MMM dd HH:mm:ss"),
- new SimpleDateFormat("MMM dd, yyyy hh:mm:ss aa"),
- ISO_8601_FORMAT, ISO_8601_FORMAT_NOZ
- };
- for (DateFormat df : ALL_DATE_FORMATS) {
- df.setLenient(false);
- }
- }
-
-
- /**
- * Constructor
- * @param inString String containing timestamp
- */
- public Timestamp(String inString)
- {
- _valid = false;
- _text = null;
- if (inString != null && !inString.equals(""))
- {
- // Try each of the parse types in turn
- for (ParseType type : ALL_PARSE_TYPES)
- {
- if (parseString(inString, type))
- {
- ALL_PARSE_TYPES[0] = type;
- _valid = true;
- _text = inString;
- return;
- }
- }
- }
- }
-
- /**
- * Try to parse the given string in the specified way
- * @param inString String to parse
- * @param inType parse type to use
- * @return true if successful
- */
- private boolean parseString(String inString, ParseType inType)
- {
- if (inString == null || inString.equals("")) {
- return false;
- }
- switch (inType)
- {
- case NONE: return false;
- case LONG:
- // Try to parse into a long
- try
- {
- long rawValue = Long.parseLong(inString.trim());
- _milliseconds = getMilliseconds(rawValue);
- return true;
- }
- catch (NumberFormatException nfe)
- {}
- break;
-
- case ISO8601_FRACTIONAL:
- final Matcher fmatcher = ISO8601_FRACTIONAL_PATTERN.matcher(inString);
- if (fmatcher.matches())
- {
- try {
- _milliseconds = getMilliseconds(Integer.parseInt(fmatcher.group(1)), // year
- Integer.parseInt(fmatcher.group(2)), // month
- Integer.parseInt(fmatcher.group(3)), // day
- Integer.parseInt(fmatcher.group(4)), // hour
- Integer.parseInt(fmatcher.group(5)), // minute
- Integer.parseInt(fmatcher.group(6)), // second
- fmatcher.group(7), // fractional seconds
- fmatcher.group(8)); // timezone, if any
- return true;
- }
- catch (NumberFormatException nfe) {}
- }
- break;
-
- case FIXED_FORMAT0: return parseString(inString, ALL_DATE_FORMATS[0]);
- case FIXED_FORMAT1: return parseString(inString, ALL_DATE_FORMATS[1]);
- case FIXED_FORMAT2: return parseString(inString, ALL_DATE_FORMATS[2]);
- case FIXED_FORMAT3: return parseString(inString, ALL_DATE_FORMATS[3]);
- case FIXED_FORMAT4: return parseString(inString, ALL_DATE_FORMATS[4]);
- case FIXED_FORMAT5: return parseString(inString, ALL_DATE_FORMATS[5]);
- case FIXED_FORMAT6: return parseString(inString, ALL_DATE_FORMATS[6]);
- case FIXED_FORMAT7: return parseString(inString, ALL_DATE_FORMATS[7]);
- case FIXED_FORMAT8: return parseString(inString, ALL_DATE_FORMATS[8]);
-
- case GENERAL_STRING:
- if (inString.length() == 19)
- {
- final Matcher matcher = GENERAL_TIMESTAMP_PATTERN.matcher(inString);
- if (matcher.matches())
- {
- try {
- _milliseconds = getMilliseconds(Integer.parseInt(matcher.group(1)),
- Integer.parseInt(matcher.group(2)),
- Integer.parseInt(matcher.group(3)),
- Integer.parseInt(matcher.group(4)),
- Integer.parseInt(matcher.group(5)),
- Integer.parseInt(matcher.group(6)),
- null, null); // no fractions of a second and no timezone
- return true;
- }
- catch (NumberFormatException nfe2) {} // parse shouldn't fail if matcher matched
- }
- }
- return false;
- }
- return false;
}
/**
- * Try to parse the given string with the given date format
- * @param inString String to parse
- * @param inDateFormat Date format to use
- * @return true if successful
+ * @return true if valid
*/
- private boolean parseString(String inString, DateFormat inDateFormat)
- {
- ParsePosition pPos = new ParsePosition(0);
- Date date = inDateFormat.parse(inString, pPos);
- if (date != null && inString.length() == pPos.getIndex()) // require use of _all_ the string, not just the beginning
- {
- CALENDAR.setTime(date);
- _milliseconds = CALENDAR.getTimeInMillis();
- return true;
- }
-
- return false;
- }
-
-
- /**
- * Constructor giving each field value individually
- * @param inYear year
- * @param inMonth month, beginning with 1
- * @param inDay day of month, beginning with 1
- * @param inHour hour of day, 0-24
- * @param inMinute minute
- * @param inSecond seconds
- */
- public Timestamp(int inYear, int inMonth, int inDay, int inHour, int inMinute, int inSecond)
- {
- _milliseconds = getMilliseconds(inYear, inMonth, inDay, inHour, inMinute, inSecond, null, null);
- _valid = true;
- }
-
+ public abstract boolean isValid();
/**
- * Constructor giving millis
- * @param inMillis milliseconds since 1970
+ * Get a calendar representing this timestamp
*/
- public Timestamp(long inMillis)
- {
- _milliseconds = inMillis;
- _valid = true;
- }
-
+ public abstract Calendar getCalendar(TimeZone inZone);
/**
- * Convert the given timestamp parameters into a number of milliseconds
- * @param inYear year
- * @param inMonth month, beginning with 1
- * @param inDay day of month, beginning with 1
- * @param inHour hour of day, 0-24
- * @param inMinute minute
- * @param inSecond seconds
- * @param inFraction fractions of a second
- * @param inTimezone timezone, if any
- * @return number of milliseconds
+ * @return the milliseconds according to the given timezone
*/
- private static long getMilliseconds(int inYear, int inMonth, int inDay,
- int inHour, int inMinute, int inSecond, String inFraction, String inTimezone)
- {
- Calendar cal = Calendar.getInstance();
- // Timezone, if any
- if (inTimezone == null || inTimezone.equals("") || inTimezone.equals("Z")) {
- // No timezone, use zulu
- cal.setTimeZone(TimeZone.getTimeZone("GMT"));
- }
- else {
- // Timezone specified, pass to calendar
- cal.setTimeZone(TimeZone.getTimeZone("GMT" + inTimezone));
- }
- cal.set(Calendar.YEAR, inYear);
- cal.set(Calendar.MONTH, inMonth - 1);
- cal.set(Calendar.DAY_OF_MONTH, inDay);
- cal.set(Calendar.HOUR_OF_DAY, inHour);
- cal.set(Calendar.MINUTE, inMinute);
- cal.set(Calendar.SECOND, inSecond);
- int millis = 0;
- if (inFraction != null)
- {
- try {
- int frac = Integer.parseInt(inFraction);
- final int fracLen = inFraction.length();
- switch (fracLen) {
- case 1: millis = frac * 100; break;
- case 2: millis = frac * 10; break;
- case 3: millis = frac; break;
- }
- }
- catch (NumberFormatException nfe) {} // ignore errors, millis stay at 0
- }
- cal.set(Calendar.MILLISECOND, millis);
- return cal.getTimeInMillis();
- }
+ public abstract long getMilliseconds(TimeZone inZone);
/**
- * Convert the given long parameters into a number of millisseconds
- * @param inRawValue long value representing seconds / milliseconds
- * @return number of milliseconds
+ * @return true if this timestamp is after the other one
*/
- private static long getMilliseconds(long inRawValue)
+ public boolean isAfter(Timestamp inOther)
{
- // check for each format possibility and pick nearest
- long diff1 = Math.abs(SECS_SINCE_1970 - inRawValue);
- long diff2 = Math.abs(MSECS_SINCE_1970 - inRawValue);
- long diff3 = Math.abs(MSECS_SINCE_1990 - inRawValue);
- long diff4 = Math.abs(SECS_SINCE_GARTRIP - inRawValue);
-
- // Start off with "seconds since 1970" format
- long smallestDiff = diff1;
- long millis = inRawValue * 1000;
- // Now check millis since 1970
- if (diff2 < smallestDiff)
- {
- // milliseconds since 1970
- millis = inRawValue;
- smallestDiff = diff2;
- }
- // Now millis since 1990
- if (diff3 < smallestDiff)
- {
- // milliseconds since 1990
- millis = inRawValue + TWENTY_YEARS_IN_SECS * 1000L;
- smallestDiff = diff3;
- }
- // Lastly, check gartrip offset
- if (diff4 < smallestDiff)
- {
- // seconds since gartrip offset
- millis = (inRawValue + GARTRIP_OFFSET) * 1000L;
- }
- return millis;
+ return getMillisecondsSince(inOther) > 0;
}
/**
- * @return true if timestamp is valid
+ * @return true if this timestamp is before the other one
*/
- public boolean isValid()
+ public boolean isBefore(Timestamp inOther)
{
- return _valid;
+ return getMillisecondsSince(inOther) < 0;
}
/**
- * @return true if the timestamp has non-zero milliseconds
+ * @return true if this timestamp is equal to the other one
*/
- public boolean hasMilliseconds()
- {
- return isValid() && (_milliseconds % 1000L) > 0;
- }
- /**
- * @param inOther other Timestamp
- * @return true if this one is at least a millisecond after the other
- */
- public boolean isAfter(Timestamp inOther)
+ public boolean isEqual(Timestamp inOther)
{
- return getMillisecondsSince(inOther) > 0L;
+ return getMillisecondsSince(inOther) == 0;
}
/**
- * Calculate the difference between two Timestamps in seconds
- * @param inOther other, earlier Timestamp
- * @return number of seconds since other timestamp
+ * @return the number of seconds since the other timestamp
*/
public long getSecondsSince(Timestamp inOther)
{
- return (_milliseconds - inOther._milliseconds) / 1000L;
+ return getMillisecondsSince(inOther) / 1000L;
}
/**
* Calculate the difference between two Timestamps in milliseconds
* @param inOther other, earlier Timestamp
- * @return number of millisseconds since other timestamp
+ * @return number of milliseconds since other timestamp
*/
public long getMillisecondsSince(Timestamp inOther)
{
- return _milliseconds - inOther._milliseconds;
- }
-
- /**
- * @param inOther other timestamp to compare
- * @return true if they're equal to the nearest millisecond
- */
- public boolean isEqual(Timestamp inOther)
- {
- return inOther != null && _milliseconds == inOther._milliseconds;
+ return getMilliseconds(null) - inOther.getMilliseconds(null);
}
/**
- * @param inOther other Timestamp
- * @return true if this one is before the other
+ * @return the number of seconds since the other timestamp using the given timezone
*/
- public boolean isBefore(Timestamp inOther)
+ public long getSecondsSince(Timestamp inOther, TimeZone inTimezone)
{
- return getMillisecondsSince(inOther) < 0L;
+ return (getMilliseconds(inTimezone) - inOther.getMilliseconds(inTimezone)) / 1000L;
}
/**
* Add the given number of seconds offset
* @param inOffset number of seconds to add/subtract
*/
- public void addOffset(long inOffset)
- {
- _milliseconds += (inOffset * 1000L);
- _text = null;
- }
-
- /**
- * Add the given TimeDifference to this Timestamp
- * @param inOffset TimeDifference to add
- * @return new Timestamp object
- */
- public Timestamp createPlusOffset(TimeDifference inOffset)
- {
- return createPlusOffset(inOffset.getTotalSeconds());
- }
-
- /**
- * Add the given number of seconds to this Timestamp
- * @param inSeconds number of seconds to add
- * @return new Timestamp object
- */
- public Timestamp createPlusOffset(long inSeconds)
- {
- return new Timestamp(_milliseconds + (inSeconds * 1000L));
- }
-
-
- /**
- * Subtract the given TimeDifference from this Timestamp
- * @param inOffset TimeDifference to subtract
- * @return new Timestamp object
- */
- public Timestamp createMinusOffset(TimeDifference inOffset)
- {
- return new Timestamp(_milliseconds - (inOffset.getTotalSeconds() * 1000L));
- }
-
+ public abstract void addOffsetSeconds(long inOffset);
/**
- * @return Description of timestamp in locale-specific format
+ * @return true if the timestamp has non-zero milliseconds
*/
- public String getText()
- {
- return getText(Format.LOCALE);
- }
+ protected abstract boolean hasMilliseconds();
- /**
- * @param inFormat format of timestamp
- * @return Description of timestamp in required format
- */
- public String getText(Format inFormat)
- {
- if (!_valid) {return "";}
- switch (inFormat)
- {
- case ORIGINAL:
- if (_text != null) {return _text;}
- // otherwise fallthrough to default
- //$FALL-THROUGH$
- case LOCALE:
- return format(DEFAULT_DATETIME_FORMAT);
- case ISO8601:
- return format(hasMilliseconds() ? ISO_8601_FORMAT_WITH_MILLIS : ISO_8601_FORMAT);
- }
- return _text;
- }
/**
* @return date part of timestamp in locale-specific format
*/
- public String getDateText()
+ public String getDateText(TimeZone inTimezone)
{
- if (!_valid) return "";
- return format(DEFAULT_DATE_FORMAT);
+ if (!isValid()) return "";
+ return format(DEFAULT_DATE_FORMAT, inTimezone);
}
/**
* @return Description of time part of timestamp in locale-specific format
*/
- public String getTimeText()
+ public String getTimeText(TimeZone inTimezone)
{
- if (!_valid) return "";
+ if (!isValid()) return "";
// Maybe we should add milliseconds to this format?
if (hasMilliseconds() && !MillisAddedToTimeFormat)
{
@@ -508,29 +152,42 @@
}
catch (ClassCastException cce) {}
}
- return format(DEFAULT_TIME_FORMAT);
+ return format(DEFAULT_TIME_FORMAT, inTimezone);
}
/**
* Utility method for formatting dates / times
- * @param inFormat formatter object
- * @return formatted String
*/
- private String format(DateFormat inFormat)
+ protected abstract String format(DateFormat inFormat, TimeZone inTimezone);
+
+
+ /**
+ * @return Description of timestamp in locale-specific format
+ */
+ public String getText(TimeZone inTimezone)
{
- CALENDAR.setTimeZone(TimeZone.getTimeZone("GMT"));
- CALENDAR.setTimeInMillis(_milliseconds);
- return inFormat.format(CALENDAR.getTime());
+ return getText(Format.LOCALE, inTimezone);
}
/**
- * @return a Calendar object representing this timestamp
+ * @param inFormat format of timestamp
+ * @return Description of timestamp in required format
*/
- public Calendar getCalendar()
+ public String getText(Format inFormat, TimeZone inTimezone)
{
- Calendar cal = Calendar.getInstance();
- cal.setTimeZone(TimeZone.getTimeZone("GMT"));
- cal.setTimeInMillis(_milliseconds);
- return cal;
+ if (!isValid()) {
+ return "";
+ }
+ switch (inFormat)
+ {
+ case ORIGINAL:
+ case LOCALE:
+ default:
+ return format(DEFAULT_DATETIME_FORMAT, inTimezone);
+ case ISO8601:
+ return format(hasMilliseconds() ? ISO_8601_FORMAT_WITH_MILLIS : ISO_8601_FORMAT,
+ inTimezone);
+ }
}
+
}
diff -Nru gpsprune-18.6/tim/prune/data/TimestampLocal.java gpsprune-19/tim/prune/data/TimestampLocal.java
--- gpsprune-18.6/tim/prune/data/TimestampLocal.java 1970-01-01 00:00:00.000000000 +0000
+++ gpsprune-19/tim/prune/data/TimestampLocal.java 2018-05-09 18:41:18.000000000 +0000
@@ -0,0 +1,104 @@
+package tim.prune.data;
+
+import java.text.DateFormat;
+import java.util.Calendar;
+import java.util.TimeZone;
+
+
+/**
+ * Class to hold a timestamp based on a local timezone, for example
+ * from a camera or audio recorder.
+ * When the selected timezone changes, this timestamp will keep its
+ * date and time but the numerical value will change accordingly.
+ */
+public class TimestampLocal extends Timestamp
+{
+ private boolean _valid = false;
+ private int _year=0, _month=0, _day=0;
+ private int _hour=0, _minute=0, _second=0;
+
+
+ /**
+ * Constructor giving each field value individually
+ * @param inYear year
+ * @param inMonth month, beginning with 1
+ * @param inDay day of month, beginning with 1
+ * @param inHour hour of day, 0-24
+ * @param inMinute minute
+ * @param inSecond seconds
+ */
+ public TimestampLocal(int inYear, int inMonth, int inDay, int inHour, int inMinute, int inSecond)
+ {
+ _valid = inYear > 0 && inYear < 3000
+ && inMonth > 0 && inMonth < 13
+ && inDay > 0 && inDay < 32
+ && inHour >= 0 && inHour < 24
+ && inMinute >= 0 && inMinute < 60
+ && inSecond >= 0 && inSecond < 60;
+ if (_valid)
+ {
+ _year = inYear;
+ _month = inMonth;
+ _day = inDay;
+ _hour = inHour;
+ _minute = inMinute;
+ _second = inSecond;
+ }
+ }
+
+
+ /** @return true if valid */
+ public boolean isValid()
+ {
+ return _valid;
+ }
+
+ @Override
+ public Calendar getCalendar(TimeZone inZone)
+ {
+ Calendar cal = Calendar.getInstance();
+ if (inZone != null) {
+ cal.setTimeZone(inZone);
+ }
+ cal.set(Calendar.YEAR, _year);
+ cal.set(Calendar.MONTH, _month - 1);
+ cal.set(Calendar.DAY_OF_MONTH, _day);
+ cal.set(Calendar.HOUR_OF_DAY, _hour);
+ cal.set(Calendar.MINUTE, _minute);
+ cal.set(Calendar.SECOND, _second);
+ cal.set(Calendar.MILLISECOND, 0);
+ return cal;
+ }
+
+ @Override
+ public long getMilliseconds(TimeZone inZone)
+ {
+ return getCalendar(inZone).getTimeInMillis();
+ }
+
+ @Override
+ public void addOffsetSeconds(long inOffset)
+ {
+ System.err.println("Local timestamps don't support offsets.");
+ }
+
+ @Override
+ protected boolean hasMilliseconds()
+ {
+ return false;
+ }
+
+ /**
+ * Utility method for formatting dates / times
+ * @param inFormat formatter object
+ * @param inTimezone timezone to use
+ * @return formatted String
+ */
+ @Override
+ protected String format(DateFormat inFormat, TimeZone inTimezone)
+ {
+ Calendar cal = getCalendar(inTimezone);
+ inFormat.setTimeZone(inTimezone);
+ return inFormat.format(cal.getTime());
+ }
+}
diff -Nru gpsprune-18.6/tim/prune/data/TimestampUtc.java gpsprune-19/tim/prune/data/TimestampUtc.java
--- gpsprune-18.6/tim/prune/data/TimestampUtc.java 1970-01-01 00:00:00.000000000 +0000
+++ gpsprune-19/tim/prune/data/TimestampUtc.java 2018-05-09 18:41:18.000000000 +0000
@@ -0,0 +1,399 @@
+package tim.prune.data;
+
+import java.text.DateFormat;
+import java.text.ParsePosition;
+import java.text.SimpleDateFormat;
+import java.util.Calendar;
+import java.util.Date;
+import java.util.TimeZone;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+
+/**
+ * Class to hold a UTC-based timestamp, for example of a track point.
+ * When the selected timezone changes, this timestamp will keep its
+ * numerical value but the date and time will change accordingly.
+ */
+public class TimestampUtc extends Timestamp
+{
+ private boolean _valid = false;
+ private long _milliseconds = 0L;
+ private String _text = null;
+
+ private static final DateFormat ISO_8601_FORMAT_NOZ = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss");
+ private static DateFormat[] ALL_DATE_FORMATS = null;
+ private static Calendar CALENDAR = null;
+ private static final Pattern ISO8601_FRACTIONAL_PATTERN
+ = Pattern.compile("(\\d{4})-(\\d{2})-(\\d{2})T(\\d{2}):(\\d{2}):(\\d{2})(?:[\\.,](\\d{1,3}))?(Z|[\\+-]\\d{2}(?::?\\d{2})?)?");
+ // year month day T hour minute sec millisec Z or +/- hours : minutes
+ private static final Pattern GENERAL_TIMESTAMP_PATTERN
+ = Pattern.compile("(\\d{4})\\D(\\d{2})\\D(\\d{2})\\D(\\d{2})\\D(\\d{2})\\D(\\d{2})");
+ private static long SECS_SINCE_1970 = 0L;
+ private static long SECS_SINCE_GARTRIP = 0L;
+ private static long MSECS_SINCE_1970 = 0L;
+ private static long MSECS_SINCE_1990 = 0L;
+ private static long TWENTY_YEARS_IN_SECS = 0L;
+ private static final long GARTRIP_OFFSET = 631065600L;
+
+ /** Identifier for the parsing strategy to use */
+ private enum ParseType
+ {
+ NONE,
+ ISO8601_FRACTIONAL,
+ LONG,
+ FIXED_FORMAT0,
+ FIXED_FORMAT1,
+ FIXED_FORMAT2,
+ FIXED_FORMAT3,
+ FIXED_FORMAT4,
+ FIXED_FORMAT5,
+ FIXED_FORMAT6,
+ FIXED_FORMAT7,
+ FIXED_FORMAT8,
+ GENERAL_STRING
+ }
+
+ /** Array of parse types to loop through (first one is changed to last successful type) */
+ private static ParseType[] ALL_PARSE_TYPES = {ParseType.NONE, ParseType.ISO8601_FRACTIONAL, ParseType.LONG,
+ ParseType.FIXED_FORMAT0, ParseType.FIXED_FORMAT1, ParseType.FIXED_FORMAT2, ParseType.FIXED_FORMAT3,
+ ParseType.FIXED_FORMAT4, ParseType.FIXED_FORMAT5, ParseType.FIXED_FORMAT6, ParseType.FIXED_FORMAT7,
+ ParseType.FIXED_FORMAT8, ParseType.GENERAL_STRING};
+
+ // Static block to initialise offsets
+ static
+ {
+ CALENDAR = Calendar.getInstance();
+ TimeZone gmtZone = TimeZone.getTimeZone("GMT");
+ CALENDAR.setTimeZone(gmtZone);
+ MSECS_SINCE_1970 = CALENDAR.getTimeInMillis();
+ SECS_SINCE_1970 = MSECS_SINCE_1970 / 1000L;
+ SECS_SINCE_GARTRIP = SECS_SINCE_1970 - GARTRIP_OFFSET;
+ CALENDAR.add(Calendar.YEAR, -20);
+ MSECS_SINCE_1990 = CALENDAR.getTimeInMillis();
+ TWENTY_YEARS_IN_SECS = (MSECS_SINCE_1970 - MSECS_SINCE_1990) / 1000L;
+ // Date formats
+ ALL_DATE_FORMATS = new DateFormat[]
+ {
+ DEFAULT_DATETIME_FORMAT,
+ new SimpleDateFormat("EEE MMM dd HH:mm:ss yyyy"),
+ new SimpleDateFormat("HH:mm:ss dd MMM yyyy"),
+ new SimpleDateFormat("dd MMM yyyy HH:mm:ss"),
+ new SimpleDateFormat("dd-MMM-yyyy HH:mm:ss"),
+ new SimpleDateFormat("yyyy MMM dd HH:mm:ss"),
+ new SimpleDateFormat("MMM dd, yyyy hh:mm:ss aa"),
+ ISO_8601_FORMAT, ISO_8601_FORMAT_NOZ
+ };
+ for (DateFormat df : ALL_DATE_FORMATS)
+ {
+ df.setLenient(false);
+ df.setTimeZone(gmtZone);
+ }
+ }
+
+
+ /**
+ * Constructor
+ * @param inString String containing timestamp
+ */
+ public TimestampUtc(String inString)
+ {
+ _valid = false;
+ _text = null;
+ if (inString != null && !inString.equals(""))
+ {
+ // Try each of the parse types in turn
+ for (ParseType type : ALL_PARSE_TYPES)
+ {
+ if (parseString(inString, type))
+ {
+ ALL_PARSE_TYPES[0] = type;
+ _valid = true;
+ _text = inString;
+ return;
+ }
+ }
+ }
+ }
+
+ /**
+ * Try to parse the given string in the specified way
+ * @param inString String to parse
+ * @param inType parse type to use
+ * @return true if successful
+ */
+ private boolean parseString(String inString, ParseType inType)
+ {
+ if (inString == null || inString.equals("")) {
+ return false;
+ }
+ switch (inType)
+ {
+ case NONE: return false;
+ case LONG:
+ // Try to parse into a long
+ try
+ {
+ long rawValue = Long.parseLong(inString.trim());
+ _milliseconds = getMilliseconds(rawValue);
+ return true;
+ }
+ catch (NumberFormatException nfe)
+ {}
+ break;
+
+ case ISO8601_FRACTIONAL:
+ final Matcher fmatcher = ISO8601_FRACTIONAL_PATTERN.matcher(inString);
+ if (fmatcher.matches())
+ {
+ try {
+ _milliseconds = getMilliseconds(Integer.parseInt(fmatcher.group(1)), // year
+ Integer.parseInt(fmatcher.group(2)), // month
+ Integer.parseInt(fmatcher.group(3)), // day
+ Integer.parseInt(fmatcher.group(4)), // hour
+ Integer.parseInt(fmatcher.group(5)), // minute
+ Integer.parseInt(fmatcher.group(6)), // second
+ fmatcher.group(7), // fractional seconds
+ fmatcher.group(8)); // timezone, if any
+ return true;
+ }
+ catch (NumberFormatException nfe) {}
+ }
+ break;
+
+ case FIXED_FORMAT0: return parseString(inString, ALL_DATE_FORMATS[0]);
+ case FIXED_FORMAT1: return parseString(inString, ALL_DATE_FORMATS[1]);
+ case FIXED_FORMAT2: return parseString(inString, ALL_DATE_FORMATS[2]);
+ case FIXED_FORMAT3: return parseString(inString, ALL_DATE_FORMATS[3]);
+ case FIXED_FORMAT4: return parseString(inString, ALL_DATE_FORMATS[4]);
+ case FIXED_FORMAT5: return parseString(inString, ALL_DATE_FORMATS[5]);
+ case FIXED_FORMAT6: return parseString(inString, ALL_DATE_FORMATS[6]);
+ case FIXED_FORMAT7: return parseString(inString, ALL_DATE_FORMATS[7]);
+ case FIXED_FORMAT8: return parseString(inString, ALL_DATE_FORMATS[8]);
+
+ case GENERAL_STRING:
+ if (inString.length() == 19)
+ {
+ final Matcher matcher = GENERAL_TIMESTAMP_PATTERN.matcher(inString);
+ if (matcher.matches())
+ {
+ try {
+ _milliseconds = getMilliseconds(Integer.parseInt(matcher.group(1)),
+ Integer.parseInt(matcher.group(2)),
+ Integer.parseInt(matcher.group(3)),
+ Integer.parseInt(matcher.group(4)),
+ Integer.parseInt(matcher.group(5)),
+ Integer.parseInt(matcher.group(6)),
+ null, null); // no fractions of a second and no timezone
+ return true;
+ }
+ catch (NumberFormatException nfe2) {} // parse shouldn't fail if matcher matched
+ }
+ }
+ return false;
+ }
+ return false;
+ }
+
+
+ /**
+ * Try to parse the given string with the given date format
+ * @param inString String to parse
+ * @param inDateFormat Date format to use
+ * @return true if successful
+ */
+ private boolean parseString(String inString, DateFormat inDateFormat)
+ {
+ ParsePosition pPos = new ParsePosition(0);
+ Date date = inDateFormat.parse(inString, pPos);
+ if (date != null && inString.length() == pPos.getIndex()) // require use of _all_ the string, not just the beginning
+ {
+ CALENDAR.setTime(date);
+ _milliseconds = CALENDAR.getTimeInMillis();
+ return true;
+ }
+
+ return false;
+ }
+
+
+ /**
+ * Constructor giving millis
+ * @param inMillis milliseconds since 1970
+ */
+ public TimestampUtc(long inMillis)
+ {
+ _milliseconds = inMillis;
+ _valid = true;
+ }
+
+
+ /**
+ * Convert the given timestamp parameters into a number of milliseconds
+ * @param inYear year
+ * @param inMonth month, beginning with 1
+ * @param inDay day of month, beginning with 1
+ * @param inHour hour of day, 0-24
+ * @param inMinute minute
+ * @param inSecond seconds
+ * @param inFraction fractions of a second
+ * @param inTimezone timezone, if any
+ * @return number of milliseconds
+ */
+ private static long getMilliseconds(int inYear, int inMonth, int inDay,
+ int inHour, int inMinute, int inSecond, String inFraction, String inTimezone)
+ {
+ Calendar cal = Calendar.getInstance();
+ // Timezone, if any
+ if (inTimezone == null || inTimezone.equals("") || inTimezone.equals("Z")) {
+ // No timezone, use zulu
+ cal.setTimeZone(TimeZone.getTimeZone("GMT"));
+ }
+ else {
+ // Timezone specified, pass to calendar
+ cal.setTimeZone(TimeZone.getTimeZone("GMT" + inTimezone));
+ }
+ cal.set(Calendar.YEAR, inYear);
+ cal.set(Calendar.MONTH, inMonth - 1);
+ cal.set(Calendar.DAY_OF_MONTH, inDay);
+ cal.set(Calendar.HOUR_OF_DAY, inHour);
+ cal.set(Calendar.MINUTE, inMinute);
+ cal.set(Calendar.SECOND, inSecond);
+ int millis = 0;
+ if (inFraction != null)
+ {
+ try {
+ int frac = Integer.parseInt(inFraction);
+ final int fracLen = inFraction.length();
+ switch (fracLen) {
+ case 1: millis = frac * 100; break;
+ case 2: millis = frac * 10; break;
+ case 3: millis = frac; break;
+ }
+ }
+ catch (NumberFormatException nfe) {} // ignore errors, millis stay at 0
+ }
+ cal.set(Calendar.MILLISECOND, millis);
+ return cal.getTimeInMillis();
+ }
+
+ /**
+ * Convert the given long parameters into a number of milliseconds
+ * @param inRawValue long value representing seconds / milliseconds
+ * @return number of milliseconds
+ */
+ private static long getMilliseconds(long inRawValue)
+ {
+ // check for each format possibility and pick nearest
+ long diff1 = Math.abs(SECS_SINCE_1970 - inRawValue);
+ long diff2 = Math.abs(MSECS_SINCE_1970 - inRawValue);
+ long diff3 = Math.abs(MSECS_SINCE_1990 - inRawValue);
+ long diff4 = Math.abs(SECS_SINCE_GARTRIP - inRawValue);
+
+ // Start off with "seconds since 1970" format
+ long smallestDiff = diff1;
+ long millis = inRawValue * 1000;
+ // Now check millis since 1970
+ if (diff2 < smallestDiff)
+ {
+ // milliseconds since 1970
+ millis = inRawValue;
+ smallestDiff = diff2;
+ }
+ // Now millis since 1990
+ if (diff3 < smallestDiff)
+ {
+ // milliseconds since 1990
+ millis = inRawValue + TWENTY_YEARS_IN_SECS * 1000L;
+ smallestDiff = diff3;
+ }
+ // Lastly, check gartrip offset
+ if (diff4 < smallestDiff)
+ {
+ // seconds since gartrip offset
+ millis = (inRawValue + GARTRIP_OFFSET) * 1000L;
+ }
+ return millis;
+ }
+
+ /**
+ * @return true if timestamp is valid
+ */
+ public boolean isValid()
+ {
+ return _valid;
+ }
+
+ /**
+ * @return true if the timestamp has non-zero milliseconds
+ */
+ protected boolean hasMilliseconds()
+ {
+ return isValid() && (_milliseconds % 1000L) > 0;
+ }
+
+ /**
+ * @return the milliseconds according to the given timezone
+ */
+ public long getMilliseconds(TimeZone inZone)
+ {
+ return _milliseconds;
+ }
+
+
+ /**
+ * Add the given number of seconds offset
+ * @param inOffset number of seconds to add/subtract
+ */
+ public void addOffsetSeconds(long inOffset)
+ {
+ _milliseconds += (inOffset * 1000L);
+ _text = null;
+ }
+
+
+ /**
+ * @param inFormat format of timestamp
+ * @param inTimezone timezone to use
+ * @return Description of timestamp in required format
+ */
+ public String getText(Format inFormat, TimeZone inTimezone)
+ {
+ // Use the cached text if possible
+ if (isValid()
+ && _text != null
+ && inFormat == Format.ORIGINAL)
+ {
+ return _text;
+ }
+
+ // Nothing cached, so use the regular one
+ return super.getText(inFormat, inTimezone);
+ }
+
+ /**
+ * Utility method for formatting dates / times
+ * @param inFormat formatter object
+ * @param inTimezone timezone to use
+ * @return formatted String
+ */
+ protected String format(DateFormat inFormat, TimeZone inTimezone)
+ {
+ CALENDAR.setTimeZone(TimeZone.getTimeZone("GMT"));
+ inFormat.setTimeZone(inTimezone == null ? TimeZone.getTimeZone("GMT") : inTimezone);
+
+ CALENDAR.setTimeInMillis(_milliseconds);
+ return inFormat.format(CALENDAR.getTime());
+ }
+
+ /**
+ * @return a Calendar object representing this timestamp
+ */
+ public Calendar getCalendar(TimeZone inZone)
+ {
+ Calendar cal = Calendar.getInstance();
+ cal.setTimeZone(TimeZone.getTimeZone("GMT"));
+ cal.setTimeInMillis(_milliseconds);
+ return cal;
+ }
+}
diff -Nru gpsprune-18.6/tim/prune/data/Track.java gpsprune-19/tim/prune/data/Track.java
--- gpsprune-18.6/tim/prune/data/Track.java 2016-12-18 18:50:23.000000000 +0000
+++ gpsprune-19/tim/prune/data/Track.java 2018-05-09 18:41:18.000000000 +0000
@@ -320,7 +320,7 @@
* @param inUndo true for undo operation
* @return true on success
*/
- public boolean addTimeOffset(int inStart, int inEnd, long inOffset, boolean inUndo)
+ public boolean addTimeOffsetSeconds(int inStart, int inEnd, long inOffset, boolean inUndo)
{
// sanity check
if (inStart < 0 || inEnd < 0 || inStart >= inEnd || inEnd >= _numPoints) {
@@ -335,7 +335,7 @@
{
// This point has a timestamp so add the offset to it
foundTimestamp = true;
- p.addTimeOffset(inOffset);
+ p.addTimeOffsetSeconds(inOffset);
p.setModified(inUndo);
}
}
diff -Nru gpsprune-18.6/tim/prune/function/AboutScreen.java gpsprune-19/tim/prune/function/AboutScreen.java
--- gpsprune-18.6/tim/prune/function/AboutScreen.java 2016-12-18 18:50:23.000000000 +0000
+++ gpsprune-19/tim/prune/function/AboutScreen.java 2018-05-09 18:41:18.000000000 +0000
@@ -34,7 +34,6 @@
import tim.prune.GenericFunction;
import tim.prune.GpsPrune;
import tim.prune.I18nManager;
-import tim.prune.jpeg.ExifGateway;
import tim.prune.threedee.WindowFactory;
/**
@@ -98,8 +97,8 @@
descBuffer.append("").append(I18nManager.getText("dialog.about.summarytext3")).append("
");
descBuffer.append("").append(I18nManager.getText("dialog.about.languages")).append(" : ")
.append("afrikaans, \u010de\u0161tina, deutsch, english, espa\u00F1ol, fran\u00E7ais, italiano,
" +
- " magyar, nederlands, polski, portugu\u00EAs, rom\u00E2n\u0103, \u0440\u0443\u0441\u0441\u043a\u0438\u0439 (russian), \u4e2d\u6587 (chinese),
" +
- " \u65E5\u672C\u8A9E (japanese), \uD55C\uAD6D\uC5B4/\uC870\uC120\uB9D0 (korean), schwiizerd\u00FC\u00FCtsch, t\u00FCrk\u00E7e, ukrainian
");
+ " magyar, nederlands, polski, portugu\u00EAs, rom\u00E2n\u0103, suomi, \u0440\u0443\u0441\u0441\u043a\u0438\u0439 (russian),
" +
+ " \u4e2d\u6587 (chinese), \u65E5\u672C\u8A9E (japanese), \uD55C\uAD6D\uC5B4/\uC870\uC120\uB9D0 (korean), schwiizerd\u00FC\u00FCtsch, ukrainian
");
descBuffer.append("").append(I18nManager.getText("dialog.about.translatedby")).append("
");
JEditorPane descPane = new JEditorPane("text/html", descBuffer.toString());
descPane.setBorder(BorderFactory.createEmptyBorder(3, 3, 3, 3));
@@ -153,13 +152,6 @@
addToGridBagPanel(sysInfoPanel, gridBag, constraints, _installedLabels[3], 1, 5);
addToGridBagPanel(sysInfoPanel, gridBag, constraints, new JLabel("Xerces : "), 0, 6);
addToGridBagPanel(sysInfoPanel, gridBag, constraints, _installedLabels[4], 1, 6);
- // Exif library
- addToGridBagPanel(sysInfoPanel, gridBag, constraints,
- new JLabel(I18nManager.getText("dialog.about.systeminfo.exiflib") + " : "),
- 0, 7);
- final String exiflibkey = "dialog.about.systeminfo.exiflib." + ExifGateway.getDescriptionKey();
- addToGridBagPanel(sysInfoPanel, gridBag, constraints,
- new JLabel(I18nManager.getText(exiflibkey)), 1, 7);
_tabs.add(I18nManager.getText("dialog.about.systeminfo"), sysInfoPanel);
// Third pane for credits
@@ -198,35 +190,38 @@
new JLabel(" theYinYeti, Rothermographer, Sam, Rudolph, nazotoko,"),
1, 4);
addToGridBagPanel(creditsPanel, gridBag, constraints,
- new JLabel(" katpatuka, R\u00E9mi, Marcus, Ali, Javier, Jeroen, prot_d, Gy\u00F6rgy,"),
+ new JLabel(" katpatuka, R\u00E9mi, Marcus, Ali, Javier, Jeroen, prot_d,"),
1, 5);
addToGridBagPanel(creditsPanel, gridBag, constraints,
- new JLabel(" HooAU, Sergey, P\u00E9ter, serhijdubyk, Peter, Cristian, Roman"),
+ new JLabel(" Gy\u00F6rgy, HooAU, Sergey, P\u00E9ter, serhijdubyk, Peter, Cristian,"),
1, 6);
addToGridBagPanel(creditsPanel, gridBag, constraints,
+ new JLabel(" Roman, Erkki"),
+ 1, 7);
+ addToGridBagPanel(creditsPanel, gridBag, constraints,
new JLabel(I18nManager.getText("dialog.about.credits.translations") + " : "),
- 0, 7);
+ 0, 8);
addToGridBagPanel(creditsPanel, gridBag, constraints,
new JLabel("Open Office, Gpsdrive, Babelfish, Leo, Launchpad"),
- 1, 7);
+ 1, 8);
addToGridBagPanel(creditsPanel, gridBag, constraints,
new JLabel(I18nManager.getText("dialog.about.credits.devtools") + " : "),
- 0, 8);
+ 0, 9);
addToGridBagPanel(creditsPanel, gridBag, constraints,
new JLabel("Debian Linux, Sun Java, OpenJDK, Eclipse, Svn, Gimp, Inkscape"),
- 1, 8);
+ 1, 9);
addToGridBagPanel(creditsPanel, gridBag, constraints,
new JLabel(I18nManager.getText("dialog.about.credits.othertools") + " : "),
- 0, 9);
+ 0, 10);
addToGridBagPanel(creditsPanel, gridBag, constraints,
new JLabel("Openstreetmap, Povray, Exiftool, Gpsbabel, Gnuplot"),
- 1, 9);
+ 1, 10);
addToGridBagPanel(creditsPanel, gridBag, constraints,
new JLabel(I18nManager.getText("dialog.about.credits.thanks") + " : "),
- 0, 10);
+ 0, 11);
addToGridBagPanel(creditsPanel, gridBag, constraints,
new JLabel("Friends and loved ones, for encouragement and support"),
- 1, 10);
+ 1, 11);
_tabs.add(I18nManager.getText("dialog.about.credits"), creditsPanel);
// Read me
diff -Nru gpsprune-18.6/tim/prune/function/AddMapSourceDialog.java gpsprune-19/tim/prune/function/AddMapSourceDialog.java
--- gpsprune-18.6/tim/prune/function/AddMapSourceDialog.java 2016-12-18 18:50:23.000000000 +0000
+++ gpsprune-19/tim/prune/function/AddMapSourceDialog.java 1970-01-01 00:00:00.000000000 +0000
@@ -1,383 +0,0 @@
-package tim.prune.function;
-
-import java.awt.BorderLayout;
-import java.awt.Component;
-import java.awt.FlowLayout;
-import java.awt.GridBagConstraints;
-import java.awt.GridBagLayout;
-import java.awt.Insets;
-import java.awt.event.ActionEvent;
-import java.awt.event.ActionListener;
-import java.awt.event.KeyAdapter;
-import java.awt.event.KeyEvent;
-
-import javax.swing.BorderFactory;
-import javax.swing.ButtonGroup;
-import javax.swing.JButton;
-import javax.swing.JComboBox;
-import javax.swing.JDialog;
-import javax.swing.JLabel;
-import javax.swing.JPanel;
-import javax.swing.JRadioButton;
-import javax.swing.JTextField;
-
-import tim.prune.I18nManager;
-import tim.prune.gui.map.MapSource;
-import tim.prune.gui.map.MapSourceLibrary;
-import tim.prune.gui.map.OsmMapSource;
-
-/**
- * Class to handle the adding of a new map source
- */
-public class AddMapSourceDialog
-{
- private SetMapBgFunction _parent = null;
- private JDialog _addDialog = null;
- private MapSource _originalSource = null;
- // controls for osm panel
- private JTextField _oNameField = null;
- private JTextField _baseUrlField = null, _topUrlField = null;
- private JRadioButton[] _baseTypeRadios = null, _topTypeRadios = null;
- private JComboBox _oZoomCombo = null;
- private JButton _okButton = null;
-
- /** array of file types */
- private static final String[] FILE_TYPES = {"png", "jpg", "gif"};
-
-
- /**
- * Constructor
- * @param inParent parent dialog
- */
- public AddMapSourceDialog(JDialog inParentDialog, SetMapBgFunction inParentFunction)
- {
- _parent = inParentFunction;
- _addDialog = new JDialog(inParentDialog, I18nManager.getText("dialog.addmapsource.title"), true);
- _addDialog.add(makeDialogComponents());
- _addDialog.setLocationRelativeTo(inParentDialog);
- _addDialog.pack();
- }
-
-
- /**
- * Create dialog components
- * @return Panel containing all gui elements in dialog
- */
- private Component makeDialogComponents()
- {
- JPanel dialogPanel = new JPanel();
- dialogPanel.setLayout(new BorderLayout());
- // Top panel with spacer
- dialogPanel.add(new JLabel(" "), BorderLayout.NORTH);
-
- // listener
- KeyAdapter keyListener = new KeyAdapter() {
- public void keyReleased(KeyEvent e) {
- super.keyReleased(e);
- if (e.getKeyCode() == KeyEvent.VK_ESCAPE) {
- _addDialog.dispose();
- }
- else {
- enableOK();
- }
- }
- };
- // Listener for any gui changes (to enable ok when anything changes on an edit)
- ActionListener okEnabler = new ActionListener() {
- public void actionPerformed(ActionEvent arg0) {
- enableOK();
- }
- };
-
- // openstreetmap panel
- JPanel osmPanel = new JPanel();
- osmPanel.setLayout(new BorderLayout());
- osmPanel.setBorder(BorderFactory.createEmptyBorder(6, 3, 4, 3));
- JPanel gbPanel = new JPanel();
- GridBagLayout gridbag = new GridBagLayout();
- GridBagConstraints c = new GridBagConstraints();
- gbPanel.setLayout(gridbag);
- c.gridx = 0; c.gridy = 0;
- c.gridheight = 1; c.gridwidth = 1;
- c.weightx = 0.0; c.weighty = 0.0;
- c.ipadx = 3; c.ipady = 5;
- c.insets = new Insets(0, 0, 5, 0);
- c.anchor = GridBagConstraints.FIRST_LINE_START;
- gbPanel.add(new JLabel(I18nManager.getText("dialog.addmapsource.sourcename")), c);
- _oNameField = new JTextField(18);
- _oNameField.addKeyListener(keyListener);
- c.gridx = 1; c.weightx = 1.0;
- gbPanel.add(_oNameField, c);
- // Base layer
- c.gridx = 0; c.gridy = 1;
- c.weightx = 0.0;
- c.insets = new Insets(0, 0, 0, 0);
- gbPanel.add(new JLabel(I18nManager.getText("dialog.addmapsource.layer1url")), c);
- _baseUrlField = new JTextField(18);
- _baseUrlField.addKeyListener(keyListener);
- c.gridx = 1; c.weightx = 1.0;
- gbPanel.add(_baseUrlField, c);
- _baseTypeRadios = new JRadioButton[3];
- ButtonGroup radioGroup = new ButtonGroup();
- for (int i=0; i<3; i++)
- {
- _baseTypeRadios[i] = new JRadioButton(FILE_TYPES[i]);
- radioGroup.add(_baseTypeRadios[i]);
- c.gridx = 2+i; c.weightx = 0.0;
- gbPanel.add(_baseTypeRadios[i], c);
- // Each type radio needs listener to call enableOk()
- _baseTypeRadios[i].addActionListener(okEnabler);
- }
-
- // Top layer
- c.gridx = 0; c.gridy = 2;
- gbPanel.add(new JLabel(I18nManager.getText("dialog.addmapsource.layer2url")), c);
- _topUrlField = new JTextField(18);
- _topUrlField.addKeyListener(keyListener);
- c.gridx = 1; c.weightx = 1.0;
- gbPanel.add(_topUrlField, c);
- _topTypeRadios = new JRadioButton[3];
- radioGroup = new ButtonGroup();
- for (int i=0; i<3; i++)
- {
- _topTypeRadios[i] = new JRadioButton(FILE_TYPES[i]);
- radioGroup.add(_topTypeRadios[i]);
- c.gridx = 2+i; c.weightx = 0.0;
- gbPanel.add(_topTypeRadios[i], c);
- // Each type radio needs listener to call enableOk()
- _topTypeRadios[i].addActionListener(okEnabler);
- }
- // Max zoom
- c.gridx = 0; c.gridy = 3;
- gbPanel.add(new JLabel(I18nManager.getText("dialog.addmapsource.maxzoom")), c);
- _oZoomCombo = new JComboBox();
- for (int i=10; i<=20; i++) {
- _oZoomCombo.addItem(i);
- }
- // zoom dropdown needs listener to call enableOk()
- _oZoomCombo.addActionListener(okEnabler);
- c.gridx = 1;
- gbPanel.add(_oZoomCombo, c);
- osmPanel.add(gbPanel, BorderLayout.NORTH);
-
- // cards
- JPanel holderPanel = new JPanel();
- holderPanel.setLayout(new BorderLayout());
- holderPanel.add(osmPanel, BorderLayout.NORTH);
- dialogPanel.add(holderPanel, BorderLayout.CENTER);
-
- // button panel at bottom
- JPanel buttonPanel = new JPanel();
- buttonPanel.setLayout(new FlowLayout(FlowLayout.RIGHT));
- _okButton = new JButton(I18nManager.getText("button.ok"));
- ActionListener okListener = new ActionListener() {
- public void actionPerformed(ActionEvent e)
- {
- finish();
- }
- };
- _okButton.addActionListener(okListener);
- buttonPanel.add(_okButton);
- JButton cancelButton = new JButton(I18nManager.getText("button.cancel"));
- cancelButton.addActionListener(new ActionListener() {
- public void actionPerformed(ActionEvent e)
- {
- _addDialog.dispose();
- }
- });
- buttonPanel.add(cancelButton);
- dialogPanel.add(buttonPanel, BorderLayout.SOUTH);
- return dialogPanel;
- }
-
-
- /**
- * Init and show the dialog
- * @param inSource source object before edit, or null to add
- */
- public void showDialog(MapSource inSource)
- {
- _originalSource = inSource;
- populateFields();
- }
-
- /**
- * Clear all the dialog fields to prepare for an add
- */
- private void clearAllFields()
- {
- _oNameField.setText("");
- _baseUrlField.setText("");
- _baseTypeRadios[0].setSelected(true);
- _topUrlField.setText("");
- _topTypeRadios[0].setSelected(true);
- _oZoomCombo.setSelectedIndex(8);
- _okButton.setEnabled(false);
- _addDialog.setVisible(true);
- }
-
- /**
- * Init the dialog fields from the given source object
- */
- private void populateFields()
- {
- if (_originalSource == null)
- {
- clearAllFields();
- return;
- }
-
- // See if it's an osm source
- try
- {
- OsmMapSource osmSource = (OsmMapSource) _originalSource;
- _oNameField.setText(osmSource.getName());
- _baseUrlField.setText(osmSource.getBaseUrl(0));
- int baseType = getBaseType(osmSource.getFileExtension(0));
- _baseTypeRadios[baseType].setSelected(true);
- _topUrlField.setText(osmSource.getNumLayers()==0?"":osmSource.getBaseUrl(1));
- int topType = getBaseType(osmSource.getFileExtension(1));
- _topTypeRadios[topType].setSelected(true);
- _oZoomCombo.setSelectedIndex(getZoomIndex(osmSource.getMaxZoomLevel()));
- }
- catch (ClassCastException cce) {} // ignore, sourceFound flag stays false
-
- _okButton.setEnabled(false);
- _addDialog.setVisible(true);
- }
-
- /**
- * Check the currently entered details and enable the OK button if it looks OK
- */
- private void enableOK()
- {
- _okButton.setEnabled(isOsmPanelOk());
- }
-
- /**
- * Check the openstreetmap panel if all details are complete
- * @return true if details look ok
- */
- private boolean isOsmPanelOk()
- {
- boolean ok = _oNameField.getText().trim().length() > 1;
- String baseUrl = null, topUrl = null;
- // Try to parse base url if given
- String baseText = _baseUrlField.getText().trim();
- baseUrl = MapSource.fixBaseUrl(baseText);
- if (baseText.length() > 0 && baseUrl == null) {ok = false;}
- // Same again for top url if given
- String topText = _topUrlField.getText().trim();
- topUrl = MapSource.fixBaseUrl(topText);
- if (topText.length() > 0 && topUrl == null) {ok = false;}
- // looks ok if at least one url given
- return (ok && (baseUrl != null || topUrl != null));
- }
-
- /**
- * Finish by adding the requested source and refreshing the parent
- */
- private void finish()
- {
- MapSource newSource = null;
- String origName = (_originalSource == null ? null : _originalSource.getName());
-
- if (isOsmPanelOk())
- {
- // Openstreetmap source
- String sourceName = getValidSourcename(_oNameField.getText(), origName);
- String url1 = _baseUrlField.getText().trim();
- String ext1 = getFileExtension(_baseTypeRadios);
- String url2 = _topUrlField.getText().trim();
- String ext2 = getFileExtension(_topTypeRadios);
- newSource = new OsmMapSource(sourceName, url1, ext1, url2, ext2, _oZoomCombo.getSelectedIndex()+10);
- }
-
- // Add new source if ok
- if (newSource != null)
- {
- if (_originalSource == null) {
- MapSourceLibrary.addSource(newSource);
- }
- else {
- MapSourceLibrary.editSource(_originalSource, newSource);
- }
- // inform setmapbg dialog
- _parent.updateList();
- _addDialog.setVisible(false);
- }
- }
-
- /**
- * Check the given source name is valid and whether it exists in library already
- * @param inName name to check
- * @param inOriginalName name of source before edit (or null for new source)
- * @return valid name for the new source
- */
- private static String getValidSourcename(String inName, String inOriginalName)
- {
- String name = inName;
- if (name == null) {name = "";}
- else {name = name.trim();}
- if (name.equals("")) {
- name = I18nManager.getText("dialog.addmapsource.noname");
- }
- // Check there isn't already a map source with this name
- if (inOriginalName == null || !inOriginalName.equals(name))
- {
- if (MapSourceLibrary.hasSourceName(name))
- {
- int suffix = 1;
- while (MapSourceLibrary.hasSourceName(name + suffix)) {
- suffix++;
- }
- name += suffix;
- }
- }
- return name;
- }
-
- /**
- * Get the selected file extension
- * @param inRadios array of radio buttons for selection
- * @return selected file extension
- */
- private String getFileExtension(JRadioButton[] inRadios)
- {
- if (inRadios != null)
- {
- for (int i=0; i= 0;
+ _okButton.setEnabled(isNumber || getOffsetSecs() != 0L);
}
};
MouseAdapter mouseListener = new MouseAdapter() {
@@ -194,7 +195,7 @@
if (offsetSecs != 0L)
{
// Pass offset back to app and close dialog
- _app.finishAddTimeOffset(offsetSecs);
+ _app.finishAddTimeOffsetSeconds(offsetSecs);
_dialog.dispose();
}
}
diff -Nru gpsprune-18.6/tim/prune/function/browser/UrlGenerator.java gpsprune-19/tim/prune/function/browser/UrlGenerator.java
--- gpsprune-18.6/tim/prune/function/browser/UrlGenerator.java 2016-12-18 18:50:23.000000000 +0000
+++ gpsprune-19/tim/prune/function/browser/UrlGenerator.java 2018-05-09 18:41:18.000000000 +0000
@@ -31,7 +31,6 @@
MAP_SOURCE_BING, /* Bing */
MAP_SOURCE_PEAKFINDER, /* PeakFinder */
MAP_SOURCE_GEOHACK, /* Geohack */
- MAP_SOURCE_PANORAMIO, /* Panoramio */
}
/**
@@ -54,7 +53,6 @@
return generateBingUrl(inTrackInfo);
case MAP_SOURCE_PEAKFINDER:
case MAP_SOURCE_GEOHACK:
- case MAP_SOURCE_PANORAMIO:
return generateUrlForPoint(inSource, inTrackInfo);
case MAP_SOURCE_OSM:
default:
@@ -209,8 +207,6 @@
return generatePeakfinderUrl(currPoint);
case MAP_SOURCE_GEOHACK:
return generateGeohackUrl(currPoint);
- case MAP_SOURCE_PANORAMIO:
- return generatePanoramioUrl(currPoint);
default:
return null;
}
@@ -240,17 +236,6 @@
// TODO: Could use absolute values and S, W but this seems to work
}
- /**
- * Generate a url for Panoramio.com
- * @param inPoint current point, not null
- * @return URL
- */
- private static String generatePanoramioUrl(DataPoint inPoint)
- {
- return "http://panoramio.com/map/#lt=" + FIVE_DP.format(inPoint.getLatitude().getDouble())
- + "&ln=" + FIVE_DP.format(inPoint.getLongitude().getDouble()) + "&z=1&k=0";
- }
-
/**
* Get the median value from the given lat/long range
diff -Nru gpsprune-18.6/tim/prune/function/CheckVersionScreen.java gpsprune-19/tim/prune/function/CheckVersionScreen.java
--- gpsprune-18.6/tim/prune/function/CheckVersionScreen.java 2016-12-18 18:50:23.000000000 +0000
+++ gpsprune-19/tim/prune/function/CheckVersionScreen.java 2018-05-09 18:41:18.000000000 +0000
@@ -106,7 +106,7 @@
== JOptionPane.YES_OPTION)
{
// User selected to launch home page
- BrowserLauncher.launchBrowser("http://activityworkshop.net/software/gpsprune/download.html");
+ BrowserLauncher.launchBrowser("https://activityworkshop.net/software/gpsprune/download.html");
}
}
}
diff -Nru gpsprune-18.6/tim/prune/function/ConvertNamesToTimes.java gpsprune-19/tim/prune/function/ConvertNamesToTimes.java
--- gpsprune-18.6/tim/prune/function/ConvertNamesToTimes.java 2016-12-18 18:50:24.000000000 +0000
+++ gpsprune-19/tim/prune/function/ConvertNamesToTimes.java 2018-05-09 18:41:18.000000000 +0000
@@ -7,7 +7,7 @@
import tim.prune.UpdateMessageBroker;
import tim.prune.data.DataPoint;
import tim.prune.data.Field;
-import tim.prune.data.Timestamp;
+import tim.prune.data.TimestampUtc;
import tim.prune.data.Track;
import tim.prune.undo.UndoConvertNamesToTimes;
@@ -51,8 +51,9 @@
DataPoint point = track.getPoint(i);
if (point.isWaypoint())
{
- Timestamp tstamp = new Timestamp(point.getWaypointName());
- if (tstamp.isValid()) {
+ TimestampUtc tstamp = new TimestampUtc(point.getWaypointName());
+ if (tstamp.isValid())
+ {
// timestamp could be parsed!
point.setFieldValue(Field.TIMESTAMP, point.getWaypointName(), false);
// set waypoint name to nothing (track point)
diff -Nru gpsprune-18.6/tim/prune/function/CreateMarkerWaypointsFunction.java gpsprune-19/tim/prune/function/CreateMarkerWaypointsFunction.java
--- gpsprune-18.6/tim/prune/function/CreateMarkerWaypointsFunction.java 1970-01-01 00:00:00.000000000 +0000
+++ gpsprune-19/tim/prune/function/CreateMarkerWaypointsFunction.java 2018-05-09 18:41:18.000000000 +0000
@@ -0,0 +1,145 @@
+package tim.prune.function;
+
+import java.util.ArrayList;
+
+import tim.prune.App;
+import tim.prune.I18nManager;
+import tim.prune.UpdateMessageBroker;
+import tim.prune.data.DataPoint;
+import tim.prune.data.Field;
+import tim.prune.data.FieldList;
+import tim.prune.data.Track;
+import tim.prune.undo.UndoAppendPoints;
+
+/**
+ * Function to create waypoints marking either
+ * at regular distance intervals or time intervals
+ */
+public class CreateMarkerWaypointsFunction extends DistanceTimeLimitFunction
+{
+ /** ArrayList of points to append to the track */
+ private ArrayList _pointsToAdd = new ArrayList();
+ /** Counter of previously used multiple */
+ private int _previousMultiple = 0;
+
+
+ /**
+ * Constructor
+ */
+ public CreateMarkerWaypointsFunction(App inApp) {
+ super(inApp);
+ }
+
+ /**
+ * @return name key
+ */
+ public String getNameKey() {
+ return "function.createmarkerwaypoints";
+ }
+
+ /**
+ * Init the state to start collecting a new set of points
+ */
+ private void initMemory()
+ {
+ _pointsToAdd.clear();
+ _previousMultiple = 0;
+ }
+
+ /**
+ * The dialog has been completed and OK pressed, so do the point creation
+ */
+ protected void performFunction()
+ {
+ // Distribute either by distance or time
+ final int timeLimitSeconds = getTimeLimitInSeconds();
+ final boolean createByTime = (timeLimitSeconds > 0);
+ final double distLimitRadians = getDistanceLimitRadians();
+ final boolean createByDistance = (distLimitRadians > 0.0);
+ if (!createByTime && !createByDistance) {
+ return; // neither option selected
+ }
+
+ // Make undo object
+ final int numPoints = _app.getTrackInfo().getTrack().getNumPoints();
+ UndoAppendPoints undo = new UndoAppendPoints(numPoints);
+
+ // set up the memory from scratch to collect the created points
+ initMemory();
+
+ // Make new waypoints, looping through the points in the track
+ DataPoint currPoint = null, prevPoint = null;
+ double currValue = 0.0, prevValue = 0.0;
+ for (int i=0; i 0);
- }
-
- /**
* @return number of entries in the list, including dateless points
*/
public int getNumEntries()
diff -Nru gpsprune-18.6/tim/prune/function/deletebydate/DeleteByDateFunction.java gpsprune-19/tim/prune/function/deletebydate/DeleteByDateFunction.java
--- gpsprune-18.6/tim/prune/function/deletebydate/DeleteByDateFunction.java 2016-12-18 18:50:24.000000000 +0000
+++ gpsprune-19/tim/prune/function/deletebydate/DeleteByDateFunction.java 2018-05-09 18:41:18.000000000 +0000
@@ -22,12 +22,13 @@
import tim.prune.DataSubscriber;
import tim.prune.I18nManager;
import tim.prune.UpdateMessageBroker;
+import tim.prune.config.TimezoneHelper;
import tim.prune.data.DataPoint;
import tim.prune.function.compress.MarkAndDeleteFunction;
/**
* Function to select a date or dates,
- * and delete the corresponding points
+ * and mark the corresponding points for deletion
*/
public class DeleteByDateFunction extends MarkAndDeleteFunction
{
@@ -56,6 +57,9 @@
@Override
public void begin()
{
+ // Select the current timezone
+ DateInfo.setTimezone(TimezoneHelper.getSelectedTimezone());
+
// Make a list of which dates are present in the track
_infoList.clearAll();
final int numPoints = _app.getTrackInfo().getTrack().getNumPoints();
@@ -65,29 +69,14 @@
if (point != null)
{
if (point.hasTimestamp()) {
- _infoList.addPoint(point.getTimestamp().getCalendar().getTime());
+ _infoList.addPoint(point.getTimestamp()
+ .getCalendar(TimezoneHelper.getSelectedTimezone()).getTime());
}
else {
_infoList.addPoint(null); // no timestamp available
}
}
}
-// System.out.println("Debug: info list has dateless points? " + (_infoList.hasDatelessPoints() ? "yes":"no"));
-// System.out.println("Debug: info list has " + _infoList.getNumEntries() + " different entries");
-// System.out.println("Debug: info list has " + _infoList.getTotalNumPoints() + " total points");
-// final boolean checkOk = (_infoList.getTotalNumPoints() == numPoints);
-// System.out.println("Debug: which " + (checkOk?"IS":"ISN'T!") + " the same as track: " + numPoints);
-
- // Loop over entries for debug
-// if (!checkOk)
-// {
-// for (int i=0; i<_infoList.getNumEntries(); i++)
-// {
-// DateInfo info = _infoList.getDateInfo(i);
-// System.out.println(" " + i + " (" + info.getPointCount() + " points) - " +
-// (info.isDateless() ? "no date" : "date"));
-// }
-// }
// Complain if there is only one entry in the list - this means all points are on the same day
if (_infoList.getNumEntries() < 2)
@@ -182,7 +171,9 @@
DataPoint point = _app.getTrackInfo().getTrack().getPoint(p);
if (point != null)
{
- Date date = (point.hasTimestamp() ? point.getTimestamp().getCalendar().getTime() : null);
+ final Date date = (point.hasTimestamp() ?
+ point.getTimestamp().getCalendar(TimezoneHelper.getSelectedTimezone()).getTime()
+ : null);
boolean pointMarked = false;
// Try to match each of the date info objects in the list
for (int d=0; d 0) {
optionallyDeleteMarkedPoints(numMarked);
}
- else {
+ else
+ {
// Do nothing //System.out.println("Nothing selected to delete!");
// delete flags might have been reset, so refresh display
UpdateMessageBroker.informSubscribers(DataSubscriber.SELECTION_CHANGED);
diff -Nru gpsprune-18.6/tim/prune/function/deletebydate/DeletionTableModel.java gpsprune-19/tim/prune/function/deletebydate/DeletionTableModel.java
--- gpsprune-18.6/tim/prune/function/deletebydate/DeletionTableModel.java 2016-12-18 18:50:24.000000000 +0000
+++ gpsprune-19/tim/prune/function/deletebydate/DeletionTableModel.java 2018-05-09 18:41:18.000000000 +0000
@@ -1,6 +1,5 @@
package tim.prune.function.deletebydate;
-import java.text.DateFormat;
import javax.swing.table.AbstractTableModel;
import tim.prune.I18nManager;
@@ -12,8 +11,6 @@
/** info list, one for each row of table */
private DateInfoList _infoList = null;
- /** Formatter, determining how dates appear in the table */
- private static final DateFormat DEFAULT_DATE_FORMAT = DateFormat.getDateInstance();
/** Column heading for date */
private static final String COLUMN_HEADING_DATE = I18nManager.getText("fieldname.date");
/** Column heading for number of points */
@@ -110,7 +107,7 @@
}
/**
- * @return cell contents at the given row, column inded
+ * @return cell contents at the given row, column index
*/
public Object getValueAt(int inRowIndex, int inColIndex)
{
@@ -124,7 +121,7 @@
if (info.isDateless()) {
return I18nManager.getText("dialog.deletebydate.nodate");
}
- return DEFAULT_DATE_FORMAT.format(info.getDate());
+ return info.getString();
case 1: // number of points
return info.getPointCount();
case 2: // keep
diff -Nru gpsprune-18.6/tim/prune/function/DistanceTimeLimitFunction.java gpsprune-19/tim/prune/function/DistanceTimeLimitFunction.java
--- gpsprune-18.6/tim/prune/function/DistanceTimeLimitFunction.java 1970-01-01 00:00:00.000000000 +0000
+++ gpsprune-19/tim/prune/function/DistanceTimeLimitFunction.java 2018-05-09 18:41:18.000000000 +0000
@@ -0,0 +1,275 @@
+package tim.prune.function;
+
+import java.awt.BorderLayout;
+import java.awt.Component;
+import java.awt.FlowLayout;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.awt.event.ItemEvent;
+import java.awt.event.ItemListener;
+import java.awt.event.KeyAdapter;
+import java.awt.event.KeyEvent;
+
+import javax.swing.Box;
+import javax.swing.BoxLayout;
+import javax.swing.ButtonGroup;
+import javax.swing.JButton;
+import javax.swing.JComboBox;
+import javax.swing.JDialog;
+import javax.swing.JLabel;
+import javax.swing.JPanel;
+import javax.swing.JRadioButton;
+
+import tim.prune.App;
+import tim.prune.GenericFunction;
+import tim.prune.I18nManager;
+import tim.prune.data.Distance;
+import tim.prune.data.Field;
+import tim.prune.data.TimeDifference;
+import tim.prune.data.Unit;
+import tim.prune.data.UnitSetLibrary;
+import tim.prune.gui.WholeNumberField;
+
+/**
+ * Superclass for functions which act on a defined
+ * distance limit or time limit
+ */
+public abstract class DistanceTimeLimitFunction extends GenericFunction
+{
+ /** Dialog */
+ protected JDialog _dialog = null;
+ /** Radio buttons for splitting by distance and time */
+ private JRadioButton _distLimitRadio = null, _timeLimitRadio = null;
+ /** Dropdown for selecting distance units */
+ private JComboBox _distUnitsDropdown = null;
+ /** Text field for entering distance */
+ private WholeNumberField _distanceField = null;
+ /** Text fields for entering distance */
+ private WholeNumberField _limitHourField = null, _limitMinField = null;
+ /** Ok and cancel buttons */
+ private JButton _okButton = null;
+ private JButton _cancelButton = null;
+
+
+ /**
+ * React to item changes and key presses
+ */
+ private abstract class ChangeListener extends KeyAdapter implements ItemListener
+ {
+ /** Method to be implemented */
+ public abstract void optionsChanged();
+
+ /** Item changed in ItemListener */
+ public void itemStateChanged(ItemEvent arg0) {
+ optionsChanged();
+ }
+
+ /** Key released in KeyListener */
+ public void keyReleased(KeyEvent arg0) {
+ optionsChanged();
+ }
+ }
+
+ /**
+ * Constructor
+ */
+ public DistanceTimeLimitFunction(App inApp) {
+ super(inApp);
+ }
+
+ /**
+ * Begin the function
+ */
+ public void begin()
+ {
+ if (_dialog == null)
+ {
+ _dialog = new JDialog(_parentFrame, I18nManager.getText(getNameKey()), true);
+ _dialog.setLocationRelativeTo(_parentFrame);
+ _dialog.setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE);
+ _dialog.getContentPane().add(makeDialogComponents());
+ _dialog.pack();
+ }
+ enableOkButton();
+ // TODO: Maybe set distance units according to current Config setting?
+ final boolean hasTimestamps = _app.getTrackInfo().getTrack().hasData(Field.TIMESTAMP);
+ _timeLimitRadio.setEnabled(hasTimestamps);
+ if (!hasTimestamps)
+ {
+ _distLimitRadio.setSelected(true);
+ }
+ // set focus to Cancel button so that pressing "Esc" works
+ _cancelButton.requestFocus();
+ _dialog.setVisible(true);
+ }
+
+ /**
+ * Create dialog components
+ * @return Panel containing all gui elements in dialog
+ */
+ private Component makeDialogComponents()
+ {
+ JPanel dialogPanel = new JPanel();
+ dialogPanel.setLayout(new BorderLayout(5, 5));
+
+ // Make radio buttons for three different options
+ _distLimitRadio = new JRadioButton(I18nManager.getText("dialog.correlate.options.distancelimit") + ": ");
+ _timeLimitRadio = new JRadioButton(I18nManager.getText("dialog.correlate.options.timelimit") + ": ");
+ ButtonGroup radioGroup = new ButtonGroup();
+ radioGroup.add(_distLimitRadio);
+ radioGroup.add(_timeLimitRadio);
+
+ // central panel for limits
+ JPanel limitsPanel = new JPanel();
+ limitsPanel.setLayout(new BoxLayout(limitsPanel, BoxLayout.Y_AXIS));
+ limitsPanel.add(Box.createVerticalStrut(8));
+ ChangeListener optionsChangedListener = new ChangeListener() {
+ public void optionsChanged() {
+ enableOkButton();
+ }
+ };
+ // distance limits
+ JPanel distLimitPanel = new JPanel();
+ distLimitPanel.setLayout(new FlowLayout());
+ _distLimitRadio.setSelected(true);
+ _distLimitRadio.addItemListener(optionsChangedListener);
+ distLimitPanel.add(_distLimitRadio);
+ _distanceField = new WholeNumberField(3);
+ _distanceField.addKeyListener(optionsChangedListener);
+ distLimitPanel.add(_distanceField);
+ String[] distUnitsOptions = {I18nManager.getText("units.kilometres"), I18nManager.getText("units.metres"),
+ I18nManager.getText("units.miles")};
+ _distUnitsDropdown = new JComboBox(distUnitsOptions);
+ _distUnitsDropdown.addItemListener(optionsChangedListener);
+ distLimitPanel.add(_distUnitsDropdown);
+ distLimitPanel.setAlignmentX(Component.LEFT_ALIGNMENT);
+ limitsPanel.add(distLimitPanel);
+
+ // time limit panel
+ JPanel timeLimitPanel = new JPanel();
+ timeLimitPanel.setLayout(new FlowLayout());
+ _timeLimitRadio.addItemListener(optionsChangedListener);
+ timeLimitPanel.add(_timeLimitRadio);
+ _limitHourField = new WholeNumberField(2);
+ _limitHourField.addKeyListener(optionsChangedListener);
+ timeLimitPanel.add(_limitHourField);
+ timeLimitPanel.add(new JLabel(I18nManager.getText("dialog.correlate.options.offset.hours")));
+ _limitMinField = new WholeNumberField(3);
+ _limitMinField.addKeyListener(optionsChangedListener);
+ timeLimitPanel.add(_limitMinField);
+ timeLimitPanel.add(new JLabel(I18nManager.getText("units.minutes")));
+ timeLimitPanel.setAlignmentX(Component.LEFT_ALIGNMENT);
+ limitsPanel.add(timeLimitPanel);
+
+ dialogPanel.add(limitsPanel, BorderLayout.NORTH);
+
+ // button panel at bottom
+ JPanel buttonPanel = new JPanel();
+ buttonPanel.setLayout(new FlowLayout(FlowLayout.RIGHT));
+ // OK button
+ _okButton = new JButton(I18nManager.getText("button.ok"));
+ _okButton.addActionListener(new ActionListener() {
+ public void actionPerformed(ActionEvent e) {
+ performFunction();
+ }
+ });
+ buttonPanel.add(_okButton);
+ // Cancel button
+ _cancelButton = new JButton(I18nManager.getText("button.cancel"));
+ _cancelButton.addActionListener(new ActionListener() {
+ public void actionPerformed(ActionEvent e) {
+ _dialog.dispose();
+ }
+ });
+ _cancelButton.addKeyListener(new KeyAdapter() {
+ public void keyPressed(KeyEvent inE) {
+ if (inE.getKeyCode() == KeyEvent.VK_ESCAPE) {_dialog.dispose();}
+ }
+ });
+ buttonPanel.add(_cancelButton);
+ dialogPanel.add(buttonPanel, BorderLayout.SOUTH);
+ return dialogPanel;
+ }
+
+ /**
+ * Enable or disable the OK button according to the inputs
+ */
+ private void enableOkButton()
+ {
+ boolean enabled = false;
+ if (_distLimitRadio.isSelected()) {
+ enabled = _distanceField.getValue() > 0;
+ }
+ else if (_timeLimitRadio.isSelected()) {
+ enabled = _limitHourField.getValue() > 0 || _limitMinField.getValue() > 0;
+ }
+ _okButton.setEnabled(enabled);
+
+ // Also enable/disable the other fields
+ _distanceField.setEnabled(_distLimitRadio.isSelected());
+ _distUnitsDropdown.setEnabled(_distLimitRadio.isSelected());
+ _limitHourField.setEnabled(_timeLimitRadio.isSelected());
+ _limitMinField.setEnabled(_timeLimitRadio.isSelected());
+ }
+
+ /**
+ * @return selected time limit in seconds, or 0
+ */
+ protected int getTimeLimitInSeconds()
+ {
+ if (_timeLimitRadio.isSelected()
+ && (_limitHourField.getValue() > 0 || _limitMinField.getValue() > 0))
+ {
+ int timeLimitSeconds = _limitHourField.getValue() * 60 * 60
+ + _limitMinField.getValue() * 60;
+ if (timeLimitSeconds > 0)
+ return timeLimitSeconds;
+ }
+ return 0;
+ }
+
+ /**
+ * @return selected distance limit in radians, or 0.0
+ */
+ protected double getDistanceLimitRadians()
+ {
+ if (_distLimitRadio.isSelected()
+ && _distanceField.getValue() > 0)
+ {
+ final Unit[] distUnits = {UnitSetLibrary.UNITS_KILOMETRES,
+ UnitSetLibrary.UNITS_METRES, UnitSetLibrary.UNITS_MILES};
+ Unit distUnit = distUnits[_distUnitsDropdown.getSelectedIndex()];
+ double distLimitRadians = Distance.convertDistanceToRadians(_distanceField.getValue(), distUnit);
+ return distLimitRadians;
+ }
+ return 0.0;
+ }
+
+ /**
+ * The dialog has been completed and OK pressed, so do the corresponding function
+ */
+ protected abstract void performFunction();
+
+ /**
+ * Create a description for the given multiple of the configured limit
+ * @param inMultiple multiple of selected limit
+ * @return language-specific String description for waypoint names
+ */
+ protected String createLimitDescription(int inMultiple)
+ {
+ if (_distLimitRadio.isSelected()
+ && _distanceField.getValue() > 0)
+ {
+ final int distLimit = inMultiple * _distanceField.getValue();
+ final String[] distUnits = {"kilometres", "metres", "miles"};
+ final String unitKey = "units." + distUnits[_distUnitsDropdown.getSelectedIndex()] + ".short";
+ return "" + distLimit + " " + I18nManager.getText(unitKey);
+ }
+ else if (_timeLimitRadio.isSelected())
+ {
+ final long timeLimitSecs = (long) getTimeLimitInSeconds() * inMultiple;
+ return new TimeDifference(timeLimitSecs).getDescription();
+ }
+ return null;
+ }
+}
diff -Nru gpsprune-18.6/tim/prune/function/DownloadOsmFunction.java gpsprune-19/tim/prune/function/DownloadOsmFunction.java
--- gpsprune-18.6/tim/prune/function/DownloadOsmFunction.java 2016-12-18 18:50:23.000000000 +0000
+++ gpsprune-19/tim/prune/function/DownloadOsmFunction.java 2018-05-09 18:41:18.000000000 +0000
@@ -243,9 +243,10 @@
*/
public void run()
{
- final String url = "http://www.overpass-api.de/api/xapi?map?bbox=" +
- _latLonLabels[1].getText() + "," + _latLonLabels[3].getText() + "," +
- _latLonLabels[2].getText() + "," + _latLonLabels[0].getText();
+ String url = "http://overpass-api.de/api/interpreter?data=(node(" +
+ _latLonLabels[3].getText() + "," + _latLonLabels[1].getText() + "," +
+ _latLonLabels[0].getText() + "," + _latLonLabels[2].getText() + ");<;);out%20qt;";
+ // System.out.println(url);
byte[] buffer = new byte[1024];
InputStream inStream = null;
diff -Nru gpsprune-18.6/tim/prune/function/estimate/jama/QRDecomposition.java gpsprune-19/tim/prune/function/estimate/jama/QRDecomposition.java
--- gpsprune-18.6/tim/prune/function/estimate/jama/QRDecomposition.java 2016-12-18 18:50:23.000000000 +0000
+++ gpsprune-19/tim/prune/function/estimate/jama/QRDecomposition.java 2018-05-09 18:41:18.000000000 +0000
@@ -96,79 +96,6 @@
return true;
}
- /**
- * Return the Householder vectors
- * @deprecated
- * @return Lower trapezoidal matrix whose columns define the reflections
- */
- private Matrix getH()
- {
- Matrix X = new Matrix(_m, _n);
- double[][] H = X.getArray();
- for (int i = 0; i < _m; i++) {
- for (int j = 0; j < _n; j++) {
- if (i >= j) {
- H[i][j] = _QR[i][j];
- } else {
- H[i][j] = 0.0;
- }
- }
- }
- return X;
- }
-
- /**
- * Return the upper triangular factor
- * @deprecated
- * @return R
- */
- private Matrix getR()
- {
- Matrix X = new Matrix(_n, _n);
- double[][] R = X.getArray();
- for (int i = 0; i < _n; i++) {
- for (int j = 0; j < _n; j++) {
- if (i < j) {
- R[i][j] = _QR[i][j];
- } else if (i == j) {
- R[i][j] = _Rdiag[i];
- } else {
- R[i][j] = 0.0;
- }
- }
- }
- return X;
- }
-
- /**
- * Generate and return the (economy-sized) orthogonal factor
- * @deprecated
- * @return Q
- */
- private Matrix getQ()
- {
- Matrix X = new Matrix(_m, _n);
- double[][] Q = X.getArray();
- for (int k = _n - 1; k >= 0; k--) {
- for (int i = 0; i < _m; i++) {
- Q[i][k] = 0.0;
- }
- Q[k][k] = 1.0;
- for (int j = k; j < _n; j++) {
- if (_QR[k][k] != 0) {
- double s = 0.0;
- for (int i = k; i < _m; i++) {
- s += _QR[i][k] * Q[i][j];
- }
- s = -s / _QR[k][k];
- for (int i = k; i < _m; i++) {
- Q[i][j] += s * _QR[i][k];
- }
- }
- }
- }
- return X;
- }
/**
* Least squares solution of A*X = B
diff -Nru gpsprune-18.6/tim/prune/function/Export3dFunction.java gpsprune-19/tim/prune/function/Export3dFunction.java
--- gpsprune-18.6/tim/prune/function/Export3dFunction.java 2016-12-18 18:50:23.000000000 +0000
+++ gpsprune-19/tim/prune/function/Export3dFunction.java 2018-05-09 18:41:18.000000000 +0000
@@ -6,7 +6,7 @@
import tim.prune.threedee.TerrainDefinition;
/**
- * Abstract superclass for pov and svg export functions
+ * Abstract superclass of any 3d export function, currently only the PovExporter
*/
public abstract class Export3dFunction extends GenericFunction
{
diff -Nru gpsprune-18.6/tim/prune/function/gpsies/GpsiesXmlHandler.java gpsprune-19/tim/prune/function/gpsies/GpsiesXmlHandler.java
--- gpsprune-18.6/tim/prune/function/gpsies/GpsiesXmlHandler.java 2016-12-18 18:50:24.000000000 +0000
+++ gpsprune-19/tim/prune/function/gpsies/GpsiesXmlHandler.java 2018-05-09 18:41:18.000000000 +0000
@@ -50,7 +50,7 @@
_track.setDescription(_value);
}
else if (inTagName.equals("fileId")) {
- _track.setWebUrl("http://gpsies.com/map.do?fileId=" + _value);
+ _track.setWebUrl("https://gpsies.com/map.do?fileId=" + _value);
}
else if (inTagName.equals("trackLengthM")) {
try {
diff -Nru gpsprune-18.6/tim/prune/function/gpsies/TrackListModel.java gpsprune-19/tim/prune/function/gpsies/TrackListModel.java
--- gpsprune-18.6/tim/prune/function/gpsies/TrackListModel.java 2016-12-18 18:50:24.000000000 +0000
+++ gpsprune-19/tim/prune/function/gpsies/TrackListModel.java 2018-05-09 18:41:18.000000000 +0000
@@ -12,7 +12,7 @@
import tim.prune.function.search.SearchResult;
/**
- * Model for list of tracks from gpsies.com
+ * Model for list of tracks from a search result (eg gpsies.com, geonames, overpass)
*/
public class TrackListModel extends AbstractTableModel
{
@@ -24,6 +24,8 @@
private String _lengthColLabel = null;
/** Number of columns */
private int _numColumns = 2;
+ /** Normally this model shows distances / lengths, except when this flag is true */
+ private boolean _showPointTypes = false;
/** Formatter for distances */
private NumberFormat _distanceFormatter = NumberFormat.getInstance();
@@ -76,6 +78,14 @@
}
/**
+ * @param inShowTypes true to show point types, false for distances
+ */
+ public void setShowPointTypes(boolean inShowTypes)
+ {
+ _showPointTypes = inShowTypes;
+ }
+
+ /**
* @param inRowNum row number
* @param inColNum column number
* @return cell entry at given row and column
@@ -83,7 +93,13 @@
public Object getValueAt(int inRowNum, int inColNum)
{
SearchResult track = _trackList.get(inRowNum);
- if (inColNum == 0) {return track.getTrackName();}
+ if (inColNum == 0) {
+ return track.getTrackName();
+ }
+ if (_showPointTypes)
+ {
+ return track.getPointType();
+ }
double lengthM = track.getLength();
// convert to current distance units
Unit distUnit = Config.getUnitSet().getDistanceUnit();
diff -Nru gpsprune-18.6/tim/prune/function/HelpScreen.java gpsprune-19/tim/prune/function/HelpScreen.java
--- gpsprune-18.6/tim/prune/function/HelpScreen.java 2016-12-18 18:50:23.000000000 +0000
+++ gpsprune-19/tim/prune/function/HelpScreen.java 2018-05-09 18:41:18.000000000 +0000
@@ -41,7 +41,7 @@
== JOptionPane.YES_OPTION)
{
// User selected to launch home page
- BrowserLauncher.launchBrowser("http://activityworkshop.net/software/gpsprune/index.html");
+ BrowserLauncher.launchBrowser("https://activityworkshop.net/software/gpsprune/index.html");
}
}
}
diff -Nru gpsprune-18.6/tim/prune/function/MapSourceListModel.java gpsprune-19/tim/prune/function/MapSourceListModel.java
--- gpsprune-18.6/tim/prune/function/MapSourceListModel.java 2016-12-18 18:50:23.000000000 +0000
+++ gpsprune-19/tim/prune/function/MapSourceListModel.java 1970-01-01 00:00:00.000000000 +0000
@@ -1,47 +0,0 @@
-package tim.prune.function;
-
-import javax.swing.AbstractListModel;
-
-import tim.prune.gui.map.MapSource;
-import tim.prune.gui.map.MapSourceLibrary;
-
-/**
- * Class to act as list model for the map source list
- */
-public class MapSourceListModel extends AbstractListModel
-{
- /**
- * @see javax.swing.ListModel#getSize()
- */
- public int getSize()
- {
- return MapSourceLibrary.getNumSources();
- }
-
- /**
- * @see javax.swing.ListModel#getElementAt(int)
- */
- public String getElementAt(int inIndex)
- {
- if (inIndex < 0 || inIndex >= getSize()) return "";
- return MapSourceLibrary.getSource(inIndex).getName();
- }
-
- /**
- * @param inIndex index in list
- * @return corresponding map source object
- */
- public MapSource getSource(int inIndex)
- {
- if (inIndex < 0 || inIndex >= getSize()) return null;
- return MapSourceLibrary.getSource(inIndex);
- }
-
- /**
- * Fire event to notify that contents have changed
- */
- public void fireChanged()
- {
- this.fireContentsChanged(this, 0, getSize()-1);
- }
-}
diff -Nru gpsprune-18.6/tim/prune/function/SaveConfig.java gpsprune-19/tim/prune/function/SaveConfig.java
--- gpsprune-18.6/tim/prune/function/SaveConfig.java 2016-12-18 18:50:24.000000000 +0000
+++ gpsprune-19/tim/prune/function/SaveConfig.java 1970-01-01 00:00:00.000000000 +0000
@@ -1,184 +0,0 @@
-package tim.prune.function;
-
-import java.awt.BorderLayout;
-import java.awt.Component;
-import java.awt.FlowLayout;
-import java.awt.GridLayout;
-import java.awt.Rectangle;
-import java.awt.event.ActionEvent;
-import java.awt.event.ActionListener;
-import java.io.File;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.util.Enumeration;
-import java.util.Properties;
-
-import javax.swing.BorderFactory;
-import javax.swing.JButton;
-import javax.swing.JDialog;
-import javax.swing.JFileChooser;
-import javax.swing.JLabel;
-import javax.swing.JPanel;
-
-import tim.prune.App;
-import tim.prune.GenericFunction;
-import tim.prune.I18nManager;
-import tim.prune.config.Config;
-
-/**
- * Class to provide the function to save the config settings
- */
-public class SaveConfig extends GenericFunction
-{
- private JDialog _dialog = null;
-
- /**
- * Constructor
- * @param inApp application object for callback
- */
- public SaveConfig(App inApp)
- {
- super(inApp);
- }
-
- /** Get the name key */
- public String getNameKey() {
- return "function.saveconfig";
- }
-
- /**
- * Begin the function
- */
- public void begin()
- {
- // Make new dialog window (don't reuse it)
- _dialog = new JDialog(_parentFrame, I18nManager.getText(getNameKey()), true);
- _dialog.setLocationRelativeTo(_parentFrame);
- _dialog.setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE);
- _dialog.getContentPane().add(makeDialogComponents());
- _dialog.pack();
- _dialog.setVisible(true);
- }
-
-
- /**
- * Create dialog components
- * @return Panel containing all gui elements in dialog
- */
- private Component makeDialogComponents()
- {
- JPanel dialogPanel = new JPanel();
- dialogPanel.setLayout(new BorderLayout());
- dialogPanel.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 15));
- JLabel descLabel = new JLabel(I18nManager.getText("dialog.saveconfig.desc"));
- dialogPanel.add(descLabel, BorderLayout.NORTH);
-
- // Grid panel in centre
- JPanel mainPanel = new JPanel();
- mainPanel.setLayout(new GridLayout(0, 2, 15, 2));
- mainPanel.setBorder(BorderFactory.createEmptyBorder(5, 15, 5, 15));
- Properties conf = Config.getAllConfig();
- Enumeration