]> gitweb.fperrin.net Git - GpsPrune.git/commitdiff
Version 18, July 2015
authoractivityworkshop <mail@activityworkshop.net>
Mon, 17 Aug 2015 19:48:48 +0000 (21:48 +0200)
committeractivityworkshop <mail@activityworkshop.net>
Mon, 17 Aug 2015 19:48:48 +0000 (21:48 +0200)
92 files changed:
tim/prune/App.java
tim/prune/DataStatus.java
tim/prune/FunctionLibrary.java
tim/prune/GpsPrune.java
tim/prune/I18nManager.java
tim/prune/config/Config.java
tim/prune/copyright.txt
tim/prune/data/Field.java
tim/prune/data/SourceInfo.java
tim/prune/data/Timestamp.java
tim/prune/data/Track.java
tim/prune/data/TrackInfo.java
tim/prune/function/AboutScreen.java
tim/prune/function/GetWikipediaFunction.java
tim/prune/function/GetWikipediaXmlHandler.java
tim/prune/function/OpenCachingDeXmlHandler.java [new file with mode: 0644]
tim/prune/function/RearrangePhotosFunction.java
tim/prune/function/SearchOpenCachingDeFunction.java [new file with mode: 0644]
tim/prune/function/SearchWikipediaNames.java
tim/prune/function/SetLanguage.java
tim/prune/function/autoplay/AutoplayFunction.java [new file with mode: 0644]
tim/prune/function/autoplay/PointInfo.java [new file with mode: 0644]
tim/prune/function/autoplay/PointList.java [new file with mode: 0644]
tim/prune/function/browser/BrowserLauncher.java
tim/prune/function/browser/UrlGenerator.java
tim/prune/function/browser/WebMapFunction.java [new file with mode: 0644]
tim/prune/function/cache/ManageCacheFunction.java
tim/prune/function/cache/RowInfo.java
tim/prune/function/cache/TileSet.java
tim/prune/function/compress/DeleteMarkedPointsFunction.java [new file with mode: 0644]
tim/prune/function/compress/MarkAndDeleteFunction.java
tim/prune/function/compress/MarkLiftsFunction.java [new file with mode: 0644]
tim/prune/function/gpsies/GetGpsiesFunction.java
tim/prune/function/gpsies/GpsiesXmlHandler.java
tim/prune/function/gpsies/TrackListModel.java
tim/prune/function/search/GenericDownloaderFunction.java [moved from tim/prune/function/gpsies/GenericDownloaderFunction.java with 98% similarity]
tim/prune/function/search/SearchMapillaryFunction.java [new file with mode: 0644]
tim/prune/function/search/SearchResult.java [moved from tim/prune/function/gpsies/GpsiesTrack.java with 68% similarity]
tim/prune/function/srtm/LookupSrtmFunction.java
tim/prune/gui/IconManager.java
tim/prune/gui/MenuManager.java
tim/prune/gui/TripleStateCheckBox.java [new file with mode: 0644]
tim/prune/gui/UndoManager.java
tim/prune/gui/images/add_photo_icon.png [changed mode: 0755->0644]
tim/prune/gui/images/add_textfile_icon.png [changed mode: 0755->0644]
tim/prune/gui/images/pause.png [new file with mode: 0644]
tim/prune/gui/images/play.png [new file with mode: 0644]
tim/prune/gui/images/points_connected.gif [deleted file]
tim/prune/gui/images/points_connected.png [new file with mode: 0644]
tim/prune/gui/images/points_disconnected.gif [deleted file]
tim/prune/gui/images/points_disconnected.png [new file with mode: 0644]
tim/prune/gui/images/points_hidden.png [new file with mode: 0644]
tim/prune/gui/images/rewind.png [new file with mode: 0644]
tim/prune/gui/map/DiskTileCacher.java
tim/prune/gui/map/MapCanvas.java
tim/prune/gui/map/MapSource.java
tim/prune/gui/map/MapSourceLibrary.java
tim/prune/gui/profile/ProfileChart.java
tim/prune/jpeg/ExternalExifLibrary.java
tim/prune/lang/prune-texts_af.properties
tim/prune/lang/prune-texts_cz.properties
tim/prune/lang/prune-texts_da.properties
tim/prune/lang/prune-texts_de.properties
tim/prune/lang/prune-texts_de_CH.properties
tim/prune/lang/prune-texts_en.properties
tim/prune/lang/prune-texts_es.properties
tim/prune/lang/prune-texts_fa.properties
tim/prune/lang/prune-texts_fr.properties
tim/prune/lang/prune-texts_hu.properties
tim/prune/lang/prune-texts_it.properties
tim/prune/lang/prune-texts_ja.properties
tim/prune/lang/prune-texts_ko.properties
tim/prune/lang/prune-texts_nl.properties
tim/prune/lang/prune-texts_pl.properties
tim/prune/lang/prune-texts_pt.properties
tim/prune/lang/prune-texts_ro.properties
tim/prune/lang/prune-texts_ru.properties
tim/prune/lang/prune-texts_sv.properties
tim/prune/lang/prune-texts_tr.properties
tim/prune/lang/prune-texts_uk.properties
tim/prune/lang/prune-texts_zh.properties
tim/prune/load/FileLoader.java
tim/prune/load/xml/GpxHandler.java
tim/prune/load/xml/KmlHandler.java
tim/prune/load/xml/XmlHandler.java
tim/prune/readme.txt
tim/prune/save/BaseImageConfigDialog.java
tim/prune/save/FileSaver.java
tim/prune/save/GpxExporter.java
tim/prune/threedee/TerrainHelper.java
tim/prune/threedee/TerrainPatch.java [new file with mode: 0644]
tim/prune/undo/UndoStack.java

index 7be82425ddc3e1628cf0d2c62343d3d50e7c3e47..81e59cc69b23566e040406ffe6f93f0023e9ea6d 100644 (file)
@@ -4,7 +4,6 @@ import java.io.File;
 import java.util.ArrayList;
 import java.util.EmptyStackException;
 import java.util.Set;
-import java.util.Stack;
 
 import javax.swing.JFrame;
 import javax.swing.JOptionPane;
@@ -27,8 +26,6 @@ import tim.prune.data.Unit;
 import tim.prune.function.AsyncMediaLoader;
 import tim.prune.function.SaveConfig;
 import tim.prune.function.SelectTracksFunction;
-import tim.prune.function.browser.BrowserLauncher;
-import tim.prune.function.browser.UrlGenerator;
 import tim.prune.function.edit.FieldEditList;
 import tim.prune.function.edit.PointEditor;
 import tim.prune.gui.MenuManager;
@@ -121,7 +118,7 @@ public class App
        /**
         * @return the undo stack
         */
-       public Stack<UndoOperation> getUndoStack()
+       public UndoStack getUndoStack()
        {
                return _undoStack;
        }
@@ -303,7 +300,7 @@ public class App
                        // pass to track for completion
                        if (_track.editPoint(currentPoint, inEditList, false))
                        {
-                               _undoStack.push(undo);
+                               _undoStack.add(undo);
                                // Confirm point edit
                                UpdateMessageBroker.informSubscribers(I18nManager.getText("confirm.point.edit"));
                        }
@@ -351,7 +348,7 @@ public class App
                        if (_trackInfo.deletePoint())
                        {
                                // Delete was successful so add undo info to stack
-                               _undoStack.push(undo);
+                               _undoStack.add(undo);
                                if (currentPhoto != null)
                                {
                                        // delete photo if necessary
@@ -378,27 +375,6 @@ public class App
        }
 
 
-       /**
-        * Finish the compression by deleting the marked points
-        */
-       public void finishCompressTrack()
-       {
-               UndoDeleteMarked undo = new UndoDeleteMarked(_track);
-               // call track to do compress
-               int numPointsDeleted = _trackInfo.deleteMarkedPoints();
-               // add to undo stack if successful
-               if (numPointsDeleted > 0)
-               {
-                       undo.setNumPointsDeleted(numPointsDeleted);
-                       _undoStack.add(undo);
-                       UpdateMessageBroker.informSubscribers("" + numPointsDeleted + " "
-                                + (numPointsDeleted==1?I18nManager.getText("confirm.deletepoint.single"):I18nManager.getText("confirm.deletepoint.multi")));
-               }
-               else {
-                       showErrorMessage("function.compress", "dialog.deletemarked.nonefound");
-               }
-       }
-
        /**
         * Reverse the currently selected section of the track
         */
@@ -891,7 +867,7 @@ public class App
                }
                else
                {
-                       new UndoManager(this, _frame);
+                       new UndoManager(this, _frame).show();
                }
        }
 
@@ -931,7 +907,7 @@ public class App
                {
                        for (int i=0; i<inNumUndos; i++)
                        {
-                               _undoStack.pop().performUndo(_trackInfo);
+                               _undoStack.popOperation().performUndo(_trackInfo);
                        }
                        String message = "" + inNumUndos + " "
                                 + (inNumUndos==1?I18nManager.getText("confirm.undo.single"):I18nManager.getText("confirm.undo.multi"));
@@ -950,19 +926,12 @@ public class App
        /**
         * @return the current data status, used for later comparison
         */
-       public DataStatus getCurrentDataStatus() {
-               return new DataStatus(_undoStack.size(), _undoStack.getNumTimesDeleted());
-       }
-
-       /**
-        * Show a map url in an external browser
-        * @param inSourceIndex index of map source to use
-        */
-       public void showExternalMap(int inSourceIndex)
+       public DataStatus getCurrentDataStatus()
        {
-               BrowserLauncher.launchBrowser(UrlGenerator.generateUrl(inSourceIndex, _trackInfo));
+               return new DataStatus(_undoStack.size(), _undoStack.getNumUndos());
        }
 
+
        /**
         * Display a standard error message
         * @param inTitleKey key to lookup for window title
index cacb2880c8125e96f307df7cfa1eae359714506e..80ad838f7cfe147a0fd97cd0baf18ba967d325e4 100644 (file)
@@ -8,17 +8,17 @@ package tim.prune;
 public class DataStatus
 {
        private int _undoSize = 0;
-       private int _deleteCount = 0;
+       private int _numUndos = 0;
 
        /**
         * Constructor
         * @param inUndoSize current size of undo stack
-        * @param inDeleteCount number of times undo stack has been deleted
+        * @param inNumUndos number of operations undone
         */
-       public DataStatus(int inUndoSize, int inDeleteCount)
+       public DataStatus(int inUndoSize, int inNumUndos)
        {
                _undoSize = inUndoSize;
-               _deleteCount = inDeleteCount;
+               _numUndos = inNumUndos;
        }
 
        /**
@@ -29,6 +29,6 @@ public class DataStatus
        public boolean hasDataChanged(DataStatus inPreviousStatus)
        {
                return _undoSize != inPreviousStatus._undoSize
-                       || _deleteCount != inPreviousStatus._deleteCount;
+                       || _numUndos != inPreviousStatus._numUndos;
        }
 }
index a8d7e0e10b3cfa0c6e6f7198be672bc1256a7268..81e5e0f2d20a3518bdce100899d4bc4d46cfe4a9 100644 (file)
@@ -3,8 +3,11 @@ package tim.prune;
 import tim.prune.correlate.AudioCorrelator;
 import tim.prune.correlate.PhotoCorrelator;
 import tim.prune.function.*;
+import tim.prune.function.autoplay.AutoplayFunction;
 import tim.prune.function.charts.Charter;
 import tim.prune.function.compress.CompressTrackFunction;
+import tim.prune.function.compress.DeleteMarkedPointsFunction;
+import tim.prune.function.compress.MarkLiftsFunction;
 import tim.prune.function.compress.MarkPointsInRectangleFunction;
 import tim.prune.function.deletebydate.DeleteByDateFunction;
 import tim.prune.function.distance.DistanceFunction;
@@ -49,6 +52,8 @@ public abstract class FunctionLibrary
        public static GenericFunction FUNCTION_SEW_SEGMENTS = null;
        public static GenericFunction FUNCTION_REARRANGE_PHOTOS = null;
        public static GenericFunction FUNCTION_COMPRESS = null;
+       public static GenericFunction FUNCTION_MARK_LIFTS = null;
+       public static DeleteMarkedPointsFunction FUNCTION_DELETE_MARKED_POINTS = null;
        public static GenericFunction FUNCTION_DELETE_RANGE = null;
        public static GenericFunction FUNCTION_CROP_TRACK = null;
        public static GenericFunction FUNCTION_MARK_IN_RECTANGLE = null;
@@ -56,7 +61,7 @@ public abstract class FunctionLibrary
        public static SingleNumericParameterFunction FUNCTION_INTERPOLATE = null;
        public static GenericFunction FUNCTION_LOOKUP_SRTM = null;
        public static GenericFunction FUNCTION_DOWNLOAD_SRTM = null;
-       public static GenericFunction FUNCTION_LOOKUP_WIKIPEDIA = null;
+       public static GenericFunction FUNCTION_NEARBY_WIKIPEDIA = null;
        public static GenericFunction FUNCTION_SEARCH_WIKIPEDIA = null;
        public static GenericFunction FUNCTION_DOWNLOAD_OSM = null;
        public static GenericFunction FUNCTION_ADD_TIME_OFFSET  = null;
@@ -79,6 +84,7 @@ public abstract class FunctionLibrary
        public static GenericFunction FUNCTION_3D     = null;
        public static GenericFunction FUNCTION_DISTANCES  = null;
        public static GenericFunction FUNCTION_FULL_RANGE_DETAILS = null;
+       public static GenericFunction FUNCTION_AUTOPLAY_TRACK = null;
        public static GenericFunction FUNCTION_ESTIMATE_TIME = null;
        public static GenericFunction FUNCTION_LEARN_ESTIMATION_PARAMS = null;
        public static GenericFunction FUNCTION_GET_GPSIES = null;
@@ -124,6 +130,8 @@ public abstract class FunctionLibrary
                FUNCTION_SEW_SEGMENTS = new SewTrackSegmentsFunction(inApp);
                FUNCTION_REARRANGE_PHOTOS = new RearrangePhotosFunction(inApp);
                FUNCTION_COMPRESS = new CompressTrackFunction(inApp);
+               FUNCTION_MARK_LIFTS = new MarkLiftsFunction(inApp);
+               FUNCTION_DELETE_MARKED_POINTS = new DeleteMarkedPointsFunction(inApp);
                FUNCTION_DELETE_RANGE = new DeleteSelectedRangeFunction(inApp);
                FUNCTION_CROP_TRACK = new CropToSelection(inApp);
                FUNCTION_MARK_IN_RECTANGLE = new MarkPointsInRectangleFunction(inApp);
@@ -131,7 +139,7 @@ public abstract class FunctionLibrary
                FUNCTION_INTERPOLATE = new InterpolateFunction(inApp);
                FUNCTION_LOOKUP_SRTM = new LookupSrtmFunction(inApp);
                FUNCTION_DOWNLOAD_SRTM = new DownloadSrtmFunction(inApp);
-               FUNCTION_LOOKUP_WIKIPEDIA = new GetWikipediaFunction(inApp);
+               FUNCTION_NEARBY_WIKIPEDIA = new GetWikipediaFunction(inApp);
                FUNCTION_SEARCH_WIKIPEDIA = new SearchWikipediaNames(inApp);
                FUNCTION_DOWNLOAD_OSM = new DownloadOsmFunction(inApp);
                FUNCTION_ADD_TIME_OFFSET = new AddTimeOffset(inApp);
@@ -153,6 +161,7 @@ public abstract class FunctionLibrary
                FUNCTION_3D     = new ShowThreeDFunction(inApp);
                FUNCTION_DISTANCES = new DistanceFunction(inApp);
                FUNCTION_FULL_RANGE_DETAILS = new FullRangeDetails(inApp);
+               FUNCTION_AUTOPLAY_TRACK = new AutoplayFunction(inApp);
                FUNCTION_ESTIMATE_TIME = new EstimateTime(inApp);
                FUNCTION_LEARN_ESTIMATION_PARAMS = new LearnParameters(inApp);
                FUNCTION_GET_GPSIES = new GetGpsiesFunction(inApp);
index e8cfad5c1e429343b689d0cb9b34ab8f2084a29e..1f76d168e53434cdd749f4ae7c2b8a5facde35a7 100644 (file)
@@ -36,9 +36,9 @@ import tim.prune.gui.profile.ProfileChart;
 public class GpsPrune
 {
        /** Version number of application, used in about screen and for version check */
-       public static final String VERSION_NUMBER = "17.2";
+       public static final String VERSION_NUMBER = "18";
        /** Build number, just used for about screen */
-       public static final String BUILD_NUMBER = "320b";
+       public static final String BUILD_NUMBER = "334";
        /** Static reference to App object */
        private static App APP = null;
 
index 24a4fde41ab2a73288dcdb7975c9c7791f54cf47..fbf781eb3fef3a79adbdc72548eb5b3c66c83f91 100644 (file)
@@ -4,6 +4,7 @@ import java.io.File;
 import java.io.FileInputStream;
 import java.io.FileNotFoundException;
 import java.io.IOException;
+import java.util.Enumeration;
 import java.util.Locale;
 import java.util.MissingResourceException;
 import java.util.Properties;
@@ -16,11 +17,8 @@ import java.util.ResourceBundle;
  */
 public abstract class I18nManager
 {
-       private static final String BUNDLE_NAME = "tim.prune.lang.prune-texts";
-       private static final Locale BACKUP_LOCALE = new Locale("en", "GB");
-
-       private static ResourceBundle EnglishTexts = null;
-       private static ResourceBundle LocalTexts = null;
+       /** Properties object into which all the texts are copied */
+       private static Properties LocalTexts = null;
 
        /** External properties file for developer testing */
        private static Properties ExternalPropsFile = null;
@@ -32,26 +30,44 @@ public abstract class I18nManager
         */
        public static void init(Locale inLocale)
        {
+               final String BUNDLE_NAME = "tim.prune.lang.prune-texts";
+               final Locale BACKUP_LOCALE = new Locale("en", "GB");
+
+               LocalTexts = new Properties();
                // Load English texts first to use as defaults
-               EnglishTexts = ResourceBundle.getBundle(BUNDLE_NAME, BACKUP_LOCALE);
+               loadFromBundle(ResourceBundle.getBundle(BUNDLE_NAME, BACKUP_LOCALE));
 
                // Get bundle for selected locale, if any
                try
                {
                        if (inLocale != null)
                        {
-                               LocalTexts = ResourceBundle.getBundle(BUNDLE_NAME, inLocale);
+                               loadFromBundle(ResourceBundle.getBundle(BUNDLE_NAME, inLocale));
                        }
                        else
                        {
                                // locale is null so just use the system default
-                               LocalTexts = ResourceBundle.getBundle(BUNDLE_NAME, Locale.getDefault());
+                               loadFromBundle(ResourceBundle.getBundle(BUNDLE_NAME, Locale.getDefault()));
                        }
                }
                catch (MissingResourceException mre) { // ignore error, default to english
                }
        }
 
+       /**
+        * Copy all the translations from the given bundle and store in the Properties object
+        * overwriting the existing translations if necessary
+        * @param inBundle bundle object loaded from file
+        */
+       private static void loadFromBundle(ResourceBundle inBundle)
+       {
+               Enumeration<String> e = inBundle.getKeys();
+               while (e.hasMoreElements())
+               {
+                       String key = e.nextElement();
+                       LocalTexts.setProperty(key, inBundle.getString(key));
+               }
+       }
 
        /**
         * Add a language file
@@ -92,26 +108,16 @@ public abstract class I18nManager
                        String extText = ExternalPropsFile.getProperty(inKey);
                        if (extText != null) return extText;
                }
-               // look in extra texts if available
+               // look in texts if available
                if (LocalTexts != null)
                {
                        try
                        {
-                               String localText = LocalTexts.getString(inKey);
+                               String localText = LocalTexts.getProperty(inKey);
                                if (localText != null) return localText;
                        }
                        catch (MissingResourceException mre) {}
                }
-               // look in english texts
-               if (EnglishTexts != null)
-               {
-                       try
-                       {
-                               String engText = EnglishTexts.getString(inKey);
-                               if (engText != null) return engText;
-                       }
-                       catch (MissingResourceException mre) {}
-               }
                // return the key itself
                return inKey;
        }
index ad3cc9c20169aa98ba781193721d9f5e31cbb0cf..892133273ece60eb7431b3ba60172a125b5628ad 100644 (file)
@@ -81,6 +81,8 @@ public abstract class Config
        public static final String KEY_POINT_COLOURER = "prune.pointcolourer";
        /** Key for line width used for drawing */
        public static final String KEY_LINE_WIDTH = "prune.linewidth";
+       /** Key for whether to use antialiasing or not */
+       public static final String KEY_ANTIALIAS = "prune.antialias";
        /** Key for kml track colour */
        public static final String KEY_KML_TRACK_COLOUR = "prune.kmltrackcolour";
        /** Key for autosaving settings */
@@ -184,6 +186,7 @@ public abstract class Config
                props.put(KEY_GPSBABEL_PATH, "gpsbabel");
                props.put(KEY_IMPORT_FILE_FORMAT, "-1"); // no file format selected
                props.put(KEY_KMZ_IMAGE_SIZE, "240");
+               props.put(KEY_ANTIALIAS, "1"); // antialias on by default
                props.put(KEY_AUTOSAVE_SETTINGS, "0"); // autosave false by default
                props.put(KEY_UNITSET_KEY, "unitset.kilometres"); // metric by default
                props.put(KEY_HEIGHT_EXAGGERATION, "100"); // 100%, no exaggeration
@@ -345,9 +348,9 @@ public abstract class Config
         */
        public static boolean isKeyBoolean(String inKey)
        {
-               // Only one boolean key so far (after metric flag was removed)
                return inKey != null && (
-                       inKey.equals(KEY_SHOW_MAP));
+                       inKey.equals(KEY_SHOW_MAP) || inKey.equals(KEY_AUTOSAVE_SETTINGS) || inKey.equals(KEY_ONLINE_MODE)
+                       || inKey.equals(KEY_ANTIALIAS));
        }
 
        /**
index 7990765fb248319174e9351574d6e059d1d06567..f5bd232cc37637b6488cd950780b61f770dc8849 100644 (file)
@@ -1,4 +1,4 @@
-The source code of GpsPrune is copyright 2006-2014 activityworkshop.net
+The source code of GpsPrune is copyright 2006-2015 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
index d020a7ebdd5789e080e1323dd2459a8796c851cc..7b9d77925c1f39fbd4a1d842d63539245fe93b5b 100644 (file)
@@ -22,8 +22,9 @@ public class Field
 
        public static final Field SPEED          = new Field("fieldname.speed", true);
        public static final Field VERTICAL_SPEED = new Field("fieldname.verticalspeed", true);
+       public static final Field MEDIA_FILENAME = new Field("fieldname.mediafilename", true);
 
-       // TODO: Field for photo filename, ability to load (from text) and save (to text)
+       // TODO: Ability to load media (from text) and save (to text)
 
        /** List of all the available fields */
        private static final Field[] ALL_AVAILABLE_FIELDS = {
index b9609f1ac76cf7a557466b8b836df2f17afb24a9..5e40eee953e1f31bd7c7755a8201665810215b7c 100644 (file)
@@ -9,7 +9,7 @@ import java.io.File;
 public class SourceInfo
 {
        /** File type of source file */
-       public enum FILE_TYPE {TEXT, GPX, KML, NMEA, GPSBABEL, GPSIES};
+       public enum FILE_TYPE {TEXT, GPX, KML, NMEA, GPSBABEL, GPSIES, JSON};
 
        /** Source file */
        private File _sourceFile = null;
index d175c64b6eab8df98fbd7dfdd3e4e867532d2835..cfddffe1e5fb1b146d82caab60318b76eb51d97b 100644 (file)
@@ -62,6 +62,7 @@ public class Timestamp
                FIXED_FORMAT5,
                FIXED_FORMAT6,
                FIXED_FORMAT7,
+               FIXED_FORMAT8,
                GENERAL_STRING
        }
 
@@ -69,7 +70,7 @@ public class Timestamp
        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.GENERAL_STRING};
+               ParseType.FIXED_FORMAT8, ParseType.GENERAL_STRING};
 
        // Static block to initialise offsets
        static
@@ -95,6 +96,7 @@ public class Timestamp
                        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) {
@@ -180,6 +182,7 @@ public class Timestamp
                        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)
index 31c9b4edeeaf3cbb04af8468e8f85b8b33932b8d..4ae47ff03e78bc794bcb89cfd289e30006bfa5e9 100644 (file)
@@ -178,21 +178,30 @@ public class Track
 
        /**
         * Delete the points marked for deletion
+        * @param inSplitSegments true to split segments at deleted points
         * @return number of points deleted
         */
-       public int deleteMarkedPoints()
+       public int deleteMarkedPoints(boolean inSplitSegments)
        {
                int numCopied = 0;
-               // Copy selected points
+               // Copy selected points into a new point array
                DataPoint[] newPointArray = new DataPoint[_numPoints];
+               boolean prevPointDeleted = false;
                for (int i=0; i<_numPoints; i++)
                {
                        DataPoint point = _dataPoints[i];
                        // Don't delete photo points
                        if (point.hasMedia() || !point.getDeleteFlag())
                        {
+                               if (prevPointDeleted && inSplitSegments) {
+                                       point.setSegmentStart(true);
+                               }
                                newPointArray[numCopied] = point;
                                numCopied++;
+                               prevPointDeleted = false;
+                       }
+                       else {
+                               prevPointDeleted = true;
                        }
                }
 
@@ -901,7 +910,7 @@ public class Track
         */
        private static final double getMinXDist(double inX)
        {
-               // TODO: Can use some kind of floor here?
+               // TODO: Should be abs(mod(inX-0.5,1)-0.5) - means two adds, one mod, one abs instead of two adds, 3 abss and two compares
                return Math.min(Math.min(Math.abs(inX), Math.abs(inX-1.0)), Math.abs(inX+1.0));
        }
 
index 7bcbc641e75fcae730f07178d5ad93637486145c..00d658828d38bf70e912d640caf85e4f7b824991 100644 (file)
@@ -272,12 +272,14 @@ public class TrackInfo
 
        /**
         * Delete all the points which have been marked for deletion
+        * @param inSplitSegments true to split segments at deleted points
         * @return number of points deleted
         */
-       public int deleteMarkedPoints()
+       public int deleteMarkedPoints(boolean inSplitSegments)
        {
-               int numDeleted = _track.deleteMarkedPoints();
-               if (numDeleted > 0) {
+               int numDeleted = _track.deleteMarkedPoints(inSplitSegments);
+               if (numDeleted > 0)
+               {
                        _selection.clearAll();
                        UpdateMessageBroker.informSubscribers();
                }
index 109d07eaea188a0d58bf68a383efa2fdf3a27f00..c3a9f5b868a664db695a82fbd6f46cccfb3bba6e 100644 (file)
@@ -98,8 +98,8 @@ public class AboutScreen extends GenericFunction
                descBuffer.append("<p>").append(I18nManager.getText("dialog.about.summarytext3")).append("</p>");
                descBuffer.append("<p>").append(I18nManager.getText("dialog.about.languages")).append(" : ")
                        .append("\u010de\u0161tina, deutsch, english, espa\u00F1ol, fran\u00E7ais, italiano, magyar,<br>" +
-                               " nederlands, polski, portugu\u00EAs, \u0440\u0443\u0441\u0441\u043a\u0438\u0439 (russian), \u4e2d\u6587 (chinese), \u65E5\u672C\u8A9E (japanese),<br>" +
-                               " \uD55C\uAD6D\uC5B4/\uC870\uC120\uB9D0 (korean), schwiizerd\u00FC\u00FCtsch, t\u00FCrk\u00E7e, afrikaans, rom\u00E2n\u0103, ukrainian</p>");
+                               " nederlands, polski, portugu\u00EAs, rom\u00E2n\u0103, \u0440\u0443\u0441\u0441\u043a\u0438\u0439 (russian), \u4e2d\u6587 (chinese),<br>" +
+                               " \u65E5\u672C\u8A9E (japanese), \uD55C\uAD6D\uC5B4/\uC870\uC120\uB9D0 (korean), schwiizerd\u00FC\u00FCtsch, t\u00FCrk\u00E7e, afrikaans, ukrainian</p>");
                descBuffer.append("<p>").append(I18nManager.getText("dialog.about.translatedby")).append("</p>");
                JEditorPane descPane = new JEditorPane("text/html", descBuffer.toString());
                descPane.setBorder(BorderFactory.createEmptyBorder(3, 3, 3, 3));
@@ -200,7 +200,7 @@ public class AboutScreen extends GenericFunction
                        new JLabel(" katpatuka, R\u00E9mi, Marcus, Ali, Javier, Jeroen, prot_d, Gy\u00F6rgy,"),
                        1, 5);
                addToGridBagPanel(creditsPanel, gridBag, constraints,
-                       new JLabel(" HooAU, Sergey, P\u00E9ter, serhijdubyk, Peter"),
+                       new JLabel(" HooAU, Sergey, P\u00E9ter, serhijdubyk, Peter, Cristian"),
                        1, 6);
                addToGridBagPanel(creditsPanel, gridBag, constraints,
                        new JLabel(I18nManager.getText("dialog.about.credits.translations") + " : "),
index 3ffdd06817d87fe984b6063c7e7a63aa3e1ab4d9..be33a95b7ba3266944726b498d5bddf2e84ef8d8 100644 (file)
@@ -13,8 +13,8 @@ import tim.prune.data.DataPoint;
 import tim.prune.data.Field;
 import tim.prune.data.Latitude;
 import tim.prune.data.Longitude;
-import tim.prune.function.gpsies.GenericDownloaderFunction;
-import tim.prune.function.gpsies.GpsiesTrack;
+import tim.prune.function.search.GenericDownloaderFunction;
+import tim.prune.function.search.SearchResult;
 
 /**
  * Function to load nearby point information from Wikipedia
@@ -128,7 +128,7 @@ public class GetWikipediaFunction extends GenericDownloaderFunction
                        inStream.close();
                } catch (Exception e) {}
                // Add track list to model
-               ArrayList<GpsiesTrack> trackList = xmlHandler.getTrackList();
+               ArrayList<SearchResult> trackList = xmlHandler.getTrackList();
                _trackListModel.addTracks(trackList);
 
                // Show error message if any
@@ -157,11 +157,11 @@ public class GetWikipediaFunction extends GenericDownloaderFunction
                        int rowNum = rowNums[i];
                        if (rowNum >= 0 && rowNum < _trackListModel.getRowCount())
                        {
-                               String coords = _trackListModel.getTrack(rowNum).getDownloadLink();
-                               String[] latlon = coords.split(",");
-                               if (latlon.length == 2)
+                               String lat = _trackListModel.getTrack(rowNum).getLatitude();
+                               String lon = _trackListModel.getTrack(rowNum).getLongitude();
+                               if (lat != null && lon != null)
                                {
-                                       DataPoint point = new DataPoint(new Latitude(latlon[0]), new Longitude(latlon[1]), null);
+                                       DataPoint point = new DataPoint(new Latitude(lat), new Longitude(lon), null);
                                        point.setFieldValue(Field.WAYPT_NAME, _trackListModel.getTrack(rowNum).getTrackName(), false);
                                        _app.createPoint(point);
                                }
index f70e5f710da6f8cb5e7304af7c3d8edfe3f1f571..b5cb3f920f7533de8474dbf7e4466c1a78b4ba82 100644 (file)
@@ -6,17 +6,17 @@ import org.xml.sax.Attributes;
 import org.xml.sax.SAXException;
 import org.xml.sax.helpers.DefaultHandler;
 
-import tim.prune.function.gpsies.GpsiesTrack;
+import tim.prune.function.search.SearchResult;
 
 /**
- * XML handler for dealing with XML returned from the geonames api
+ * XML handler for dealing with XML returned from the geonames api,
+ * both from the search by name and search by location
  */
 public class GetWikipediaXmlHandler extends DefaultHandler
 {
        private String _value = null;
-       private ArrayList<GpsiesTrack> _trackList = null;
-       private GpsiesTrack _track = null;
-       private String _lat = null, _lon = null;
+       private ArrayList<SearchResult> _trackList = null;
+       private SearchResult _track = null;
        private String _errorMessage = null;
 
 
@@ -27,12 +27,10 @@ public class GetWikipediaXmlHandler extends DefaultHandler
                Attributes inAttributes) throws SAXException
        {
                if (inTagName.equals("geonames")) {
-                       _trackList = new ArrayList<GpsiesTrack>();
+                       _trackList = new ArrayList<SearchResult>();
                }
                else if (inTagName.equals("entry")) {
-                       _track = new GpsiesTrack();
-                       _lat = null;
-                       _lon = null;
+                       _track = new SearchResult();
                }
                else if (inTagName.equals("status")) {
                        _errorMessage = inAttributes.getValue("message");
@@ -49,7 +47,6 @@ public class GetWikipediaXmlHandler extends DefaultHandler
        {
                if (inTagName.equals("entry")) {
                        // end of the entry
-                       _track.setDownloadLink(_lat + "," + _lon);
                        _trackList.add(_track);
                }
                else if (inTagName.equals("title")) {
@@ -59,10 +56,10 @@ public class GetWikipediaXmlHandler extends DefaultHandler
                        _track.setDescription(_value);
                }
                else if (inTagName.equals("lat")) {
-                       _lat = _value;
+                       _track.setLatitude(_value);
                }
                else if (inTagName.equals("lng")) {
-                       _lon = _value;
+                       _track.setLongitude(_value);
                }
                else if (inTagName.equals("distance")) {
                        try {
@@ -90,7 +87,7 @@ public class GetWikipediaXmlHandler extends DefaultHandler
        /**
         * @return the list of tracks
         */
-       public ArrayList<GpsiesTrack> getTrackList()
+       public ArrayList<SearchResult> getTrackList()
        {
                return _trackList;
        }
diff --git a/tim/prune/function/OpenCachingDeXmlHandler.java b/tim/prune/function/OpenCachingDeXmlHandler.java
new file mode 100644 (file)
index 0000000..b4b28d5
--- /dev/null
@@ -0,0 +1,102 @@
+package tim.prune.function;
+
+import java.util.ArrayList;
+
+import org.xml.sax.Attributes;
+import org.xml.sax.SAXException;
+import org.xml.sax.helpers.DefaultHandler;
+
+import tim.prune.function.search.SearchResult;
+
+/**
+ * XML handler for dealing with XML returned from the opencaching.de api
+ */
+public class OpenCachingDeXmlHandler extends DefaultHandler
+{
+       private String _value = null;
+       private ArrayList<SearchResult> _trackList = null;
+       private SearchResult _track = null;
+       private String _errorMessage = null;
+
+
+       /**
+        * React to the start of an XML tag
+        */
+       public void startElement(String inUri, String inLocalName, String inTagName,
+               Attributes inAttributes) throws SAXException
+       {
+               if (inTagName.equals("result")) {
+                       _trackList = new ArrayList<SearchResult>();
+               }
+               else if (inTagName.equals("cache"))
+               {
+                       _track = new SearchResult();
+               }
+//             else if (inTagName.equals("status")) {
+//                     _errorMessage = inAttributes.getValue("message");
+//             }
+               else _value = null;
+               super.startElement(inUri, inLocalName, inTagName, inAttributes);
+       }
+
+       /**
+        * React to the end of an XML tag
+        */
+       public void endElement(String inUri, String inLocalName, String inTagName)
+       throws SAXException
+       {
+               if (inTagName.equals("cache"))
+               {
+                       // end of the entry
+                       _trackList.add(_track);
+               }
+               else if (inTagName.equals("name")) {
+                       _track.setTrackName(_value);
+               }
+               else if (inTagName.equals("desc")) {
+                       _track.setDescription(_value);
+               }
+               else if (inTagName.equals("lat")) {
+                       _track.setLatitude(_value);
+               }
+               else if (inTagName.equals("lon")) {
+                       _track.setLongitude(_value);
+               }
+               else if (inTagName.equals("distance")) {
+                       try {
+                               _track.setLength(Double.parseDouble(_value) * 1000.0); // convert from km to m
+                       }
+                       catch (NumberFormatException nfe) {}
+               }
+               else if (inTagName.equals("link")) {
+                       _track.setWebUrl(_value);
+               }
+               super.endElement(inUri, inLocalName, inTagName);
+       }
+
+       /**
+        * React to characters received inside tags
+        */
+       public void characters(char[] inCh, int inStart, int inLength)
+       throws SAXException
+       {
+               String value = new String(inCh, inStart, inLength);
+               _value = (_value==null?value:_value+value);
+               super.characters(inCh, inStart, inLength);
+       }
+
+       /**
+        * @return the list of tracks
+        */
+       public ArrayList<SearchResult> getTrackList()
+       {
+               return _trackList;
+       }
+
+       /**
+        * @return error message, if any
+        */
+       public String getErrorMessage() {
+               return _errorMessage;
+       }
+}
index 466cd668230a023705f56b001836a0638b405e3d..e278dbeb71b8e24933a0a4e843bc99c9ddb86075 100644 (file)
@@ -89,7 +89,7 @@ public class RearrangePhotosFunction extends RearrangeFunction
                                System.arraycopy(nonPhotos, 0, neworder, 0, numNonPhotos);
                                System.arraycopy(photos, 0, neworder, numNonPhotos, numPhotos);
                        }
-                       
+
                        // Give track the new point order
                        pointsChanged = track.replaceContents(neworder);
                }
diff --git a/tim/prune/function/SearchOpenCachingDeFunction.java b/tim/prune/function/SearchOpenCachingDeFunction.java
new file mode 100644 (file)
index 0000000..20e2fc8
--- /dev/null
@@ -0,0 +1,152 @@
+package tim.prune.function;
+
+import java.io.InputStream;
+import java.net.URL;
+import java.util.ArrayList;
+
+import javax.xml.parsers.SAXParser;
+import javax.xml.parsers.SAXParserFactory;
+
+import tim.prune.App;
+import tim.prune.I18nManager;
+import tim.prune.data.DataPoint;
+import tim.prune.data.Field;
+import tim.prune.data.Latitude;
+import tim.prune.data.Longitude;
+import tim.prune.function.search.GenericDownloaderFunction;
+import tim.prune.function.search.SearchResult;
+
+/**
+ * Function to load information about geocaches nearby to the current point
+ * using the service at opencaching.de
+ */
+public class SearchOpenCachingDeFunction extends GenericDownloaderFunction
+{
+       /** Maximum distance from point in km */
+       private static final int MAX_DISTANCE = 50;
+
+
+       /**
+        * Constructor
+        * @param inApp App object
+        */
+       public SearchOpenCachingDeFunction(App inApp) {
+               super(inApp);
+       }
+
+       /**
+        * @return name key
+        */
+       public String getNameKey() {
+               return "function.searchopencachingde";
+       }
+
+       /**
+        * @param inColNum index of column, 0 or 1
+        * @return key for this column
+        */
+       protected String getColumnKey(int inColNum)
+       {
+               if (inColNum == 0) return "dialog.wikipedia.column.name";
+               return "dialog.wikipedia.column.distance";
+       }
+
+
+       /**
+        * Run method to call service in a separate thread
+        */
+       public void run()
+       {
+               _statusLabel.setText(I18nManager.getText("confirm.running"));
+               // Get coordinates from current point
+               DataPoint point = _app.getTrackInfo().getCurrentPoint();
+               if (point == null)
+               {
+                       return;
+               }
+
+               final double lat = point.getLatitude().getDouble();
+               final double lon = point.getLongitude().getDouble();
+               submitSearch(lat, lon);
+
+               // Set status label according to error or "none found", leave blank if ok
+               if (_errorMessage == null && _trackListModel.isEmpty()) {
+                       _errorMessage = I18nManager.getText("dialog.geocaching.nonefound");
+               }
+               _statusLabel.setText(_errorMessage == null ? "" : _errorMessage);
+       }
+
+       /**
+        * Submit the search for the given parameters
+        * @param inLat latitude
+        * @param inLon longitude
+        */
+       private void submitSearch(double inLat, double inLon)
+       {
+               // The only parameters are lat and long from the current point
+               String urlString = "http://opencaching.de/search.php?searchto=searchbydistance&showresult=1"
+                       + "&output=XML&sort=bydistance&lat=" + inLat
+                       + "&lon=" + inLon + "&distance=" + MAX_DISTANCE + "&unit=km";
+               // Parse the returned XML with a special handler
+               OpenCachingDeXmlHandler xmlHandler = new OpenCachingDeXmlHandler();
+               InputStream inStream = null;
+
+               try
+               {
+                       URL url = new URL(urlString);
+                       SAXParser saxParser = SAXParserFactory.newInstance().newSAXParser();
+                       inStream = url.openStream();
+                       saxParser.parse(inStream, xmlHandler);
+               }
+               catch (Exception e) {
+                       _errorMessage = e.getClass().getName() + " - " + e.getMessage();
+               }
+               // Close stream and ignore errors
+               try {
+                       inStream.close();
+               } catch (Exception e) {}
+               // Add track list to model
+               ArrayList<SearchResult> trackList = xmlHandler.getTrackList();
+               _trackListModel.addTracks(trackList);
+
+               // Show error message if any
+               if (_trackListModel.isEmpty())
+               {
+                       String error = xmlHandler.getErrorMessage();
+                       if (error != null && !error.equals(""))
+                       {
+                               _app.showErrorMessageNoLookup(getNameKey(), error);
+                               _errorMessage = error;
+                       }
+               }
+       }
+
+       /**
+        * Load the selected point(s)
+        */
+       protected void loadSelected()
+       {
+               // Find the rows selected in the table and get the corresponding coords
+               int numSelected = _trackTable.getSelectedRowCount();
+               if (numSelected < 1) return;
+               int[] rowNums = _trackTable.getSelectedRows();
+               for (int i=0; i<numSelected; i++)
+               {
+                       int rowNum = rowNums[i];
+                       if (rowNum >= 0 && rowNum < _trackListModel.getRowCount())
+                       {
+                               String lat = _trackListModel.getTrack(rowNum).getLatitude();
+                               String lon = _trackListModel.getTrack(rowNum).getLongitude();
+                               if (lat != null && lon != null)
+                               {
+                                       DataPoint point = new DataPoint(new Latitude(lat), new Longitude(lon), null);
+                                       point.setFieldValue(Field.WAYPT_NAME, _trackListModel.getTrack(rowNum).getTrackName(), false);
+                                       _app.createPoint(point);
+                               }
+                       }
+               }
+               // Close the dialog
+               _cancelled = true;
+               _dialog.dispose();
+       }
+}
index 5ab3950f83483ab1b4d4428f8734de14f7ce72e0..20b23deecb918ea0499321e98c81ca68a8a65789 100644 (file)
@@ -16,8 +16,8 @@ import tim.prune.data.DataPoint;
 import tim.prune.data.Field;
 import tim.prune.data.Latitude;
 import tim.prune.data.Longitude;
-import tim.prune.function.gpsies.GenericDownloaderFunction;
-import tim.prune.function.gpsies.GpsiesTrack;
+import tim.prune.function.search.GenericDownloaderFunction;
+import tim.prune.function.search.SearchResult;
 
 /**
  * Function to search Wikipedia for place names
@@ -133,7 +133,7 @@ public class SearchWikipediaNames extends GenericDownloaderFunction
                        inStream.close();
                } catch (Exception e) {}
                // Add track list to model
-               ArrayList<GpsiesTrack> trackList = xmlHandler.getTrackList();
+               ArrayList<SearchResult> trackList = xmlHandler.getTrackList();
                // TODO: Do a better job of sorting replies by relevance - use three different lists
                _trackListModel.addTracks(trackList);
        }
@@ -203,11 +203,11 @@ public class SearchWikipediaNames extends GenericDownloaderFunction
                        int rowNum = rowNums[i];
                        if (rowNum >= 0 && rowNum < _trackListModel.getRowCount())
                        {
-                               String coords = _trackListModel.getTrack(rowNum).getDownloadLink();
-                               String[] latlon = coords.split(",");
-                               if (latlon.length == 2)
+                               String lat = _trackListModel.getTrack(rowNum).getLatitude();
+                               String lon = _trackListModel.getTrack(rowNum).getLongitude();
+                               if (lat != null && lon != null)
                                {
-                                       DataPoint point = new DataPoint(new Latitude(latlon[0]), new Longitude(latlon[1]), null);
+                                       DataPoint point = new DataPoint(new Latitude(lat), new Longitude(lon), null);
                                        point.setFieldValue(Field.WAYPT_NAME, _trackListModel.getTrack(rowNum).getTrackName(), false);
                                        _app.createPoint(point);
                                }
index 27ec94e0a42f61022c69ad8f034a5bff51e8075b..832b5211b67ed0615535754592ee16f7cc17f728 100644 (file)
@@ -41,15 +41,15 @@ public class SetLanguage extends GenericFunction
        private int _startIndex = 0;
 
        /** Names of languages for display in dropdown (not translated) */
-       private static final String[] LANGUAGE_NAMES = {"\u010de\u0161tina", "deutsch", "english", "american english",
-               "espa\u00F1ol", "fran\u00E7ais", "italiano", "magyar", "nederlands", "polski",
-               "portugu\u00EAs", "\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",
-               "afrikaans", "rom\u00E2n\u0103", "\u0443\u043a\u0440\u0430\u0457\u043d\u0441\u044c\u043a\u0430 \u043c\u043e\u0432\u0430 (ukrainian)"
+       private static final String[] LANGUAGE_NAMES = {"afrikaans", "\u010de\u0161tina", "deutsch", "english", "american 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", "\u0443\u043a\u0440\u0430\u0457\u043d\u0441\u044c\u043a\u0430 \u043c\u043e\u0432\u0430 (ukrainian)"
        };
        /** Associated language codes (must be in same order as names!) */
-       private static final String[] LANGUAGE_CODES = {"cz", "de", "en", "en_us", "es", "fr", "it", "hu",
-               "nl", "pl", "pt", "ru", "zh", "ja", "ko", "de_ch", "tr", "af", "ro", "uk"
+       private static final String[] LANGUAGE_CODES = {"af", "cz", "de", "en", "en_us", "es", "fr", "it", "hu",
+               "nl", "pl", "pt", "ro", "ru", "zh", "ja", "ko", "de_ch", "tr", "uk"
        };
 
 
diff --git a/tim/prune/function/autoplay/AutoplayFunction.java b/tim/prune/function/autoplay/AutoplayFunction.java
new file mode 100644 (file)
index 0000000..acb71ee
--- /dev/null
@@ -0,0 +1,334 @@
+package tim.prune.function.autoplay;
+
+import java.awt.Component;
+import java.awt.FlowLayout;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.awt.event.WindowAdapter;
+import java.awt.event.WindowEvent;
+import java.util.Iterator;
+import java.util.TreeSet;
+
+import javax.swing.BoxLayout;
+import javax.swing.JButton;
+import javax.swing.JCheckBox;
+import javax.swing.JDialog;
+import javax.swing.JLabel;
+import javax.swing.JPanel;
+
+import tim.prune.App;
+import tim.prune.GenericFunction;
+import tim.prune.I18nManager;
+import tim.prune.data.Field;
+import tim.prune.data.Timestamp;
+import tim.prune.data.Track;
+import tim.prune.gui.GuiGridLayout;
+import tim.prune.gui.IconManager;
+import tim.prune.gui.WholeNumberField;
+
+/**
+ * Function to handle the autoplay of a track
+ */
+public class AutoplayFunction extends GenericFunction implements Runnable
+{
+       /** Dialog */
+       private JDialog _dialog = null;
+       /** Entry field for number of seconds to autoplay for */
+       private WholeNumberField _durationField = null;
+       /** Checkbox for using point timestamps */
+       private JCheckBox _useTimestampsCheckbox = null;
+       /** Buttons for controlling autoplay */
+       private JButton _rewindButton = null, _pauseButton = null, _playButton = null;
+       /** Flag for recalculating all the times */
+       private boolean _needToRecalculate = true;
+       /** Point list */
+       private PointList _pointList = null;
+       /** Flag to see if we're still running or not */
+       private boolean _running = false;
+       /** Remember the time we started playing */
+       private long _startTime = 0L;
+
+
+       /**
+        * Constructor
+        * @param inApp App object
+        */
+       public AutoplayFunction(App inApp) {
+               super(inApp);
+       }
+
+       @Override
+       public String getNameKey() {
+               return "function.autoplay";
+       }
+
+       /**
+        * 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();
+                       _dialog.setResizable(false);
+                       _dialog.addWindowListener(new WindowAdapter() {
+                               public void windowClosing(WindowEvent e) {
+                                       _running = false;
+                                       super.windowClosing(e);
+                               }
+                       });
+               }
+               // Don't select any point
+               _app.getTrackInfo().selectPoint(-1);
+               // enable buttons
+               enableButtons(false, true); // can't pause, can play
+               // MAYBE: reset duration if it's too long
+               // Disable point checkbox if there aren't any times
+               final boolean hasTimes = _app.getTrackInfo().getTrack().hasData(Field.TIMESTAMP);
+               _useTimestampsCheckbox.setEnabled(hasTimes);
+               if (!hasTimes)
+               {
+                       _useTimestampsCheckbox.setSelected(false);
+               }
+
+               _needToRecalculate = true;
+               _dialog.setVisible(true);
+       }
+
+
+       /**
+        * Create dialog components
+        * @return Panel containing all gui elements in dialog
+        */
+       private Component makeDialogComponents()
+       {
+               JPanel dialogPanel = new JPanel();
+               dialogPanel.setLayout(new BoxLayout(dialogPanel, BoxLayout.Y_AXIS));
+               // Duration panel
+               JPanel durationPanel = new JPanel();
+               GuiGridLayout grid = new GuiGridLayout(durationPanel);
+               grid.add(new JLabel(I18nManager.getText("dialog.autoplay.duration") + " :"));
+               _durationField = new WholeNumberField(3);
+               _durationField.setValue(60); // default is one minute
+               _durationField.addActionListener(new ActionListener() {
+                       public void actionPerformed(ActionEvent e) {
+                               onParamsChanged();
+                       }
+               });
+               grid.add(_durationField);
+               durationPanel.setAlignmentX(Component.CENTER_ALIGNMENT);
+               dialogPanel.add(durationPanel);
+               // Checkbox
+               _useTimestampsCheckbox = new JCheckBox(I18nManager.getText("dialog.autoplay.usetimestamps"));
+               _useTimestampsCheckbox.setAlignmentX(Component.CENTER_ALIGNMENT);
+               dialogPanel.add(_useTimestampsCheckbox);
+               _useTimestampsCheckbox.addActionListener(new ActionListener() {
+                       public void actionPerformed(ActionEvent e) {
+                               onParamsChanged();
+                       }
+               });
+               // Button panel
+               JPanel buttonPanel = new JPanel();
+               buttonPanel.setLayout(new FlowLayout(FlowLayout.CENTER));
+               buttonPanel.add(_rewindButton = new JButton(IconManager.getImageIcon(IconManager.AUTOPLAY_REWIND)));
+               _rewindButton.setToolTipText(I18nManager.getText("dialog.autoplay.rewind"));
+               _rewindButton.addActionListener(new ActionListener() {
+                       public void actionPerformed(ActionEvent arg0) {
+                               onRewindPressed();
+                       }
+               });
+               buttonPanel.add(_pauseButton = new JButton(IconManager.getImageIcon(IconManager.AUTOPLAY_PAUSE)));
+               _pauseButton.setToolTipText(I18nManager.getText("dialog.autoplay.pause"));
+               _pauseButton.addActionListener(new ActionListener() {
+                       public void actionPerformed(ActionEvent arg0) {
+                               onPausePressed();
+                       }
+               });
+               buttonPanel.add(_playButton = new JButton(IconManager.getImageIcon(IconManager.AUTOPLAY_PLAY)));
+               _playButton.setToolTipText(I18nManager.getText("dialog.autoplay.play"));
+               _playButton.addActionListener(new ActionListener() {
+                       public void actionPerformed(ActionEvent arg0) {
+                               onPlayPressed();
+                       }
+               });
+               buttonPanel.setAlignmentX(Component.CENTER_ALIGNMENT);
+               dialogPanel.add(buttonPanel);
+               return dialogPanel;
+       }
+
+       /**
+        * React to a change to either the duration or the checkbox
+        */
+       private void onParamsChanged()
+       {
+               onRewindPressed();
+               enableButtons(false, _durationField.getValue() > 0);
+               _needToRecalculate = true;
+       }
+
+       /**
+        * React to rewind button pressed - stop and go back to the first point
+        */
+       private void onRewindPressed()
+       {
+               //System.out.println("Rewind!  Stop thread if playing");
+               _running = false;
+               if (_pointList != null)
+               {
+                       _pointList.set(0);
+                       _app.getTrackInfo().selectPoint(_pointList.getCurrentPointIndex());
+               }
+       }
+
+       /**
+        * React to pause button pressed - stop scrolling but maintain position
+        */
+       private void onPausePressed()
+       {
+               //System.out.println("Pause!  Stop thread if playing");
+               _running = false;
+               enableButtons(false, true);
+       }
+
+       /**
+        * React to play button being pressed - either start or resume
+        */
+       private void onPlayPressed()
+       {
+               //System.out.println("Play!");
+               if (_needToRecalculate) {
+                       recalculateTimes();
+               }
+               enableButtons(true, false);
+               if (_pointList.isAtStart() || _pointList.isFinished())
+               {
+                       _pointList.set(0);
+                       _startTime = System.currentTimeMillis();
+               }
+               else
+               {
+                       // Get current millis from pointList, reset _startTime
+                       _startTime = System.currentTimeMillis() - _pointList.getCurrentMilliseconds();
+               }
+               new Thread(this).start();
+       }
+
+       /**
+        * Recalculate the times using the dialog settings
+        */
+       private void recalculateTimes()
+       {
+               //System.out.println("Recalculate using params " + _durationField.getValue()
+               //      + " and " + (_useTimestampsCheckbox.isSelected() ? "times" : "indexes"));
+               if (_useTimestampsCheckbox.isSelected()) {
+                       _pointList = generatePointListUsingTimes(_app.getTrackInfo().getTrack(), _durationField.getValue());
+               }
+               else {
+                       _pointList = generatePointListUsingIndexes(_app.getTrackInfo().getTrack().getNumPoints(), _durationField.getValue());
+               }
+               _needToRecalculate = false;
+       }
+
+       /**
+        * Enable and disable the pause and play buttons
+        * @param inCanPause true to enable pause button
+        * @param inCanPlay  true to enable play button
+        */
+       private void enableButtons(boolean inCanPause, boolean inCanPlay)
+       {
+               _pauseButton.setEnabled(inCanPause);
+               _playButton.setEnabled(inCanPlay);
+       }
+
+       /**
+        * Generate a points list based just on the point timestamps
+        * (points without timestamps will be ignored)
+        * @param inTrack track object
+        * @param inDuration number of seconds to play
+        * @return PointList object
+        */
+       private static PointList generatePointListUsingTimes(Track inTrack, int inDuration)
+       {
+               // Make a Set of all the points with timestamps and sort them
+               TreeSet<PointInfo> set = new TreeSet<PointInfo>();
+               int numPoints = inTrack.getNumPoints();
+               for (int i=0; i<numPoints; i++)
+               {
+                       PointInfo info = new PointInfo(inTrack.getPoint(i), i);
+                       if (info.getTimestamp() != null) {
+                               set.add(info);
+                       }
+               }
+               // For each point, keep track of the time since the previous time
+               Timestamp previousTime = null;
+               long trackMillis = 0L;
+               // Copy info to point list
+               numPoints = set.size();
+               PointList list = new PointList(numPoints);
+               Iterator<PointInfo> it = set.iterator();
+               while (it.hasNext())
+               {
+                       PointInfo info = it.next();
+                       if (previousTime != null)
+                       {
+                               if (info.getSegmentFlag()) {
+                                       trackMillis += 1000; // just add a second if it's a new segment
+                               }
+                               else {
+                                       trackMillis += (info.getTimestamp().getMillisecondsSince(previousTime));
+                               }
+                       }
+                       previousTime = info.getTimestamp();
+                       list.setPoint(trackMillis, info.getIndex());
+               }
+               // Now normalize the list to the requested length
+               list.normalize(inDuration);
+               return list;
+       }
+
+
+       /**
+        * Generate a points list based just on indexes, ignoring timestamps
+        * @param inNumPoints number of points in track
+        * @param inDuration number of seconds to play
+        * @return PointList object
+        */
+       private static PointList generatePointListUsingIndexes(int inNumPoints, int inDuration)
+       {
+               // simple case, just take all the points in the track
+               PointList list = new PointList(inNumPoints);
+               // Add each of the points in turn
+               for (int i=0; i<inNumPoints; i++)
+               {
+                       list.setPoint(i, i);
+               }
+               list.normalize(inDuration);
+               return list;
+       }
+
+       /**
+        * Run method, for scrolling in separate thread
+        */
+       public void run()
+       {
+               _running = true;
+               _app.getTrackInfo().selectPoint(_pointList.getCurrentPointIndex());
+               while (_running && !_pointList.isFinished())
+               {
+                       _pointList.set(System.currentTimeMillis() - _startTime);
+                       final int pointIndex = _pointList.getCurrentPointIndex();
+                       //System.out.println("Set point index to " + pointIndex);
+                       _app.getTrackInfo().selectPoint(pointIndex);
+                       long waitInterval = _pointList.getMillisUntilNextPoint(System.currentTimeMillis() - _startTime);
+                       if (waitInterval < 20) {waitInterval = 20;}
+                       try {Thread.sleep(waitInterval);}
+                       catch (InterruptedException ie) {}
+               }
+               _running = false;
+               enableButtons(false, true);
+       }
+}
diff --git a/tim/prune/function/autoplay/PointInfo.java b/tim/prune/function/autoplay/PointInfo.java
new file mode 100644 (file)
index 0000000..1b04995
--- /dev/null
@@ -0,0 +1,98 @@
+package tim.prune.function.autoplay;
+
+import tim.prune.data.DataPoint;
+import tim.prune.data.Timestamp;
+
+/**
+ * Holds the information about a single point required for the sorting
+ */
+public class PointInfo implements Comparable<PointInfo>
+{
+       /** Timestamp of the point, if any */
+       private Timestamp _timestamp  = null;
+       /** Point index in the track */
+       private int       _pointIndex = 0;
+       /** Segment flag of point */
+       private boolean   _segmentFlag = false;
+
+
+       /**
+        * Constructor
+        * @param inPoint point from track
+        * @param inIndex index of point in track
+        */
+       public PointInfo(DataPoint inPoint, int inIndex)
+       {
+               if (inPoint.hasTimestamp())
+               {
+                       _timestamp = inPoint.getTimestamp();
+               }
+               else if (inPoint.getPhoto() != null && inPoint.getPhoto().hasTimestamp())
+               {
+                       _timestamp = inPoint.getPhoto().getTimestamp();
+               }
+               _pointIndex = inIndex;
+               _segmentFlag = inPoint.getSegmentStart();
+       }
+
+       /** @return timestamp */
+       public Timestamp getTimestamp() {
+               return _timestamp;
+       }
+
+       /** @return point index */
+       public int getIndex() {
+               return _pointIndex;
+       }
+
+       /** @return segment flag */
+       public boolean getSegmentFlag() {
+               return _segmentFlag;
+       }
+
+       /**
+        * Sort two objects by timestamp and if times equal then by point index
+        */
+       public int compareTo(PointInfo inOther)
+       {
+               long timeDiff = 0;
+               final boolean thisHasTime = (_timestamp != null);
+               final boolean otherHasTime = (inOther._timestamp != null);
+               if (thisHasTime && otherHasTime)
+               {
+                       timeDiff = _timestamp.getMillisecondsSince(inOther._timestamp);
+               }
+               else if (thisHasTime)
+               {
+                       timeDiff = -1; // points without time to the end
+               }
+               else if (otherHasTime)
+               {
+                       timeDiff = 1;
+               }
+               // If the times are equal (or both missing) then use the point index
+               if (timeDiff == 0) {
+                       return _pointIndex - inOther._pointIndex;
+               }
+               // Otherwise, compare by time
+               return (timeDiff < 0 ? -1 : 1);
+       }
+
+       @Override
+       public boolean equals(Object inOther)
+       {
+               if (inOther == null) return false;
+               try
+               {
+                       PointInfo other = (PointInfo) inOther;
+                       if (_pointIndex != other._pointIndex) return false;
+                       final boolean thisHasTime = (_timestamp != null);
+                       final boolean otherHasTime = (other._timestamp != null);
+                       if (thisHasTime != otherHasTime) {return false;}
+                       if (!thisHasTime && !otherHasTime) {return true;}
+                       return _timestamp.isEqual(other._timestamp);
+               }
+               catch (ClassCastException cce) {}
+               return false;
+       }
+}
diff --git a/tim/prune/function/autoplay/PointList.java b/tim/prune/function/autoplay/PointList.java
new file mode 100644 (file)
index 0000000..13ccf61
--- /dev/null
@@ -0,0 +1,115 @@
+package tim.prune.function.autoplay;
+
+/**
+ * Class to hold a list of points and hold a running position
+ */
+public class PointList
+{
+       /** Array of milliseconds for each point */
+       private long[] _millis = null;
+       /** Array of indexes of corresponding points */
+       private int[]  _indexes = null;
+       /** Array index of current position */
+       private int    _currentItem = 0;
+       /** Max array index */
+       private int    _maxItem = 0;
+
+       /**
+        * Constructor
+        * @param inNumPoints number of points
+        */
+       public PointList(int inNumPoints)
+       {
+               _millis = new long[inNumPoints];
+               _indexes = new int[inNumPoints];
+               _currentItem = 0;
+               _maxItem = inNumPoints - 1;
+       }
+
+       /**
+        * Add a point to the array
+        * @param inMillis milliseconds since start
+        * @param inIndex point index
+        */
+       public void setPoint(long inMillis, int inIndex)
+       {
+               _millis[_currentItem] = inMillis;
+               _indexes[_currentItem] = inIndex;
+               _currentItem++;
+       }
+
+       /**
+        * Set the position using the current milliseconds
+        * @param inMillis milliseconds since start
+        */
+       public void set(long inMillis)
+       {
+               if (isFinished() || inMillis < _millis[_currentItem])
+               {
+                       // must be reset
+                       _currentItem = 0;
+               }
+               while (_currentItem < _maxItem && _millis[_currentItem + 1] < inMillis)
+               {
+                       _currentItem++;
+               }
+       }
+
+       /**
+        * Normalize the list to cover the requested number of seconds duration
+        * @param inSeconds length of autoplay sequence in seconds
+        */
+       public void normalize(int inSeconds)
+       {
+               if (_maxItem <= 0)
+               {
+                       return; // nothing to normalize
+               }
+               long currentDuration = _millis[_maxItem] - _millis[0];
+               if (currentDuration > 0L)
+               {
+                       double multFactor = inSeconds * 1000.0 / currentDuration;
+                       for (int i=0; i<=_maxItem; i++)
+                       {
+                               _millis[i] = (long) (_millis[i] * multFactor);
+                       }
+               }
+       }
+
+       /** @return the milliseconds of the current point */
+       public long getCurrentMilliseconds()
+       {
+               if (isAtStart() || isFinished()) {
+                       return 0L;
+               }
+               return _millis[_currentItem];
+       }
+
+       /** @return the index of the current point */
+       public int getCurrentPointIndex()
+       {
+               return _indexes[_currentItem];
+       }
+
+       /** @return true if we're on the first point */
+       public boolean isAtStart() {
+               return _currentItem == 0;
+       }
+
+       /** @return true if we're on the last point */
+       public boolean isFinished() {
+               return _currentItem >= _maxItem;
+       }
+
+       /**
+        * @param inCurrentMillis current time in milliseconds since start
+        * @return number of milliseconds to wait until next point is due
+        */
+       public long getMillisUntilNextPoint(long inCurrentMillis)
+       {
+               if (isFinished() || _millis[_currentItem+1] < _millis[_currentItem]) {
+                       return 0; // no next point
+               }
+               return _millis[_currentItem+1] - inCurrentMillis;
+       }
+}
index 4ba4b8d6a40cbe08de0864a565552128b91afe7e..7c6fa58056a19279ab7306599c711268412ab45c 100644 (file)
@@ -86,6 +86,7 @@ public abstract class BrowserLauncher
         */
        public static void launchBrowser(String inUrl)
        {
+               if (inUrl == null) {return;}
                // First choice is to try the Desktop library from java 6, if available
                try {
                        Class<?> d = Class.forName("java.awt.Desktop");
index 8d264beb4f5e4098a7e5fd3caf3cb1de3995881c..a0100b104f59732cdf25d27a8dd8d172339cb4cc 100644 (file)
@@ -22,38 +22,46 @@ public abstract class UrlGenerator
                if (FIVE_DP instanceof DecimalFormat) ((DecimalFormat) FIVE_DP).applyPattern("0.00000");
        }
 
-       /** Constant for Google Maps */
-       public static final int MAP_SOURCE_GOOGLE = 0;
-       /** Constant for Open Street Maps */
-       public static final int MAP_SOURCE_OSM    = 1;
-       /** Constant for Mapquest */
-       public static final int MAP_SOURCE_MAPQUEST = 2;
-       /** Constant for Yahoo */
-       public static final int MAP_SOURCE_YAHOO  = 3;
-       /** Constant for Bing */
-       public static final int MAP_SOURCE_BING = 4;
+       public enum WebService
+       {
+               MAP_SOURCE_GOOGLE,     /* Google maps */
+               MAP_SOURCE_OSM,        /* OpenStreetMap */
+               MAP_SOURCE_MAPQUEST,   /* Mapquest */
+               MAP_SOURCE_YAHOO,      /* Yahoo */
+               MAP_SOURCE_BING,       /* Bing */
+               MAP_SOURCE_PEAKFINDER, /* PeakFinder */
+               MAP_SOURCE_GEOHACK,    /* Geohack */
+               MAP_SOURCE_PANORAMIO,  /* Panoramio */
+               MAP_SOURCE_OPENCACHINGCOM, /* Opencaching.com */
+       }
 
        /**
         * Generate a URL for the given source and track info
-        * @param inSource source to use, either google or openstreetmap
+        * @param inSource source to use, from the enum in UrlGenerator
         * @param inTrackInfo track info
         * @return url for map
         */
-       public static String generateUrl(int inSource, TrackInfo inTrackInfo)
+       public static String generateUrl(WebService inSource, TrackInfo inTrackInfo)
        {
-               if (inSource == MAP_SOURCE_GOOGLE) {
-                       return generateGoogleUrl(inTrackInfo);
-               }
-               else if (inSource == MAP_SOURCE_MAPQUEST) {
-                       return generateMapquestUrl(inTrackInfo);
-               }
-               else if (inSource == MAP_SOURCE_YAHOO) {
-                       return generateYahooUrl(inTrackInfo);
-               }
-               else if (inSource == MAP_SOURCE_BING) {
-                       return generateBingUrl(inTrackInfo);
+               switch (inSource)
+               {
+                       case MAP_SOURCE_GOOGLE:
+                               return generateGoogleUrl(inTrackInfo);
+                       case MAP_SOURCE_MAPQUEST:
+                               return generateMapquestUrl(inTrackInfo);
+                       case MAP_SOURCE_YAHOO:
+                               return generateYahooUrl(inTrackInfo);
+                       case MAP_SOURCE_BING:
+                               return generateBingUrl(inTrackInfo);
+                       case MAP_SOURCE_PEAKFINDER:
+                       case MAP_SOURCE_GEOHACK:
+                       case MAP_SOURCE_PANORAMIO:
+                       case MAP_SOURCE_OPENCACHINGCOM:
+                               return generateUrlForPoint(inSource, inTrackInfo);
+                       case MAP_SOURCE_OSM:
+                       default:
+                               return generateOpenStreetMapUrl(inTrackInfo);
                }
-               return generateOpenStreetMapUrl(inTrackInfo);
        }
 
        /**
@@ -88,33 +96,6 @@ public abstract class UrlGenerator
                return url;
        }
 
-       /**
-        * Generate a url for Open Street Map
-        * @param inTrackInfo track information
-        * @return URL
-        */
-       private static String generateOpenStreetMapUrl(TrackInfo inTrackInfo)
-       {
-               // Check if any data to display
-               if (inTrackInfo == null || inTrackInfo.getTrack() == null || inTrackInfo.getTrack().getNumPoints() < 1)
-               {
-                       return null;
-               }
-               DoubleRange latRange = inTrackInfo.getTrack().getLatRange();
-               DoubleRange lonRange = inTrackInfo.getTrack().getLonRange();
-               // Build basic url using min and max lat and long
-               String url = "http://openstreetmap.org/?minlat=" + FIVE_DP.format(latRange.getMinimum())
-                       + "&maxlat=" + FIVE_DP.format(latRange.getMaximum())
-                       + "&minlon=" + FIVE_DP.format(lonRange.getMinimum()) + "&maxlon=" + FIVE_DP.format(lonRange.getMaximum());
-               DataPoint currPoint = inTrackInfo.getCurrentPoint();
-               // Add selected point, if any (no way to add point name?)
-               if (currPoint != null) {
-                       url = url + "&mlat=" + FIVE_DP.format(currPoint.getLatitude().getDouble())
-                               + "&mlon=" + FIVE_DP.format(currPoint.getLongitude().getDouble());
-               }
-               return url;
-       }
-
        /**
         * Generate a url for Mapquest maps
         * @param inTrackInfo track information
@@ -178,6 +159,117 @@ public abstract class UrlGenerator
                return url;
        }
 
+       /**
+        * Generate a url for Open Street Map
+        * @param inTrackInfo track information
+        * @return URL
+        */
+       private static String generateOpenStreetMapUrl(TrackInfo inTrackInfo)
+       {
+               // Check if any data to display
+               if (inTrackInfo == null || inTrackInfo.getTrack() == null || inTrackInfo.getTrack().getNumPoints() < 1)
+               {
+                       return null;
+               }
+               DoubleRange latRange = inTrackInfo.getTrack().getLatRange();
+               DoubleRange lonRange = inTrackInfo.getTrack().getLonRange();
+               // Build basic url using min and max lat and long
+               String url = "http://openstreetmap.org/?minlat=" + FIVE_DP.format(latRange.getMinimum())
+                       + "&maxlat=" + FIVE_DP.format(latRange.getMaximum())
+                       + "&minlon=" + FIVE_DP.format(lonRange.getMinimum()) + "&maxlon=" + FIVE_DP.format(lonRange.getMaximum());
+               DataPoint currPoint = inTrackInfo.getCurrentPoint();
+               // Add selected point, if any (no way to add point name?)
+               if (currPoint != null) {
+                       url = url + "&mlat=" + FIVE_DP.format(currPoint.getLatitude().getDouble())
+                               + "&mlon=" + FIVE_DP.format(currPoint.getLongitude().getDouble());
+               }
+               return url;
+       }
+
+       /**
+        * Generate a URL which only needs the current point
+        * This is just a helper method to simplify the calls to the service-specific methods
+        * @param inSource service to call
+        * @param inTrackInfo track info
+        * @return URL if available, or null
+        */
+       private static String generateUrlForPoint(WebService inService, TrackInfo inTrackInfo)
+       {
+               if (inTrackInfo == null || inTrackInfo.getTrack() == null || inTrackInfo.getTrack().getNumPoints() < 1)
+               {
+                       return null;
+               }
+               // Need a current point
+               DataPoint currPoint = inTrackInfo.getCurrentPoint();
+               if (currPoint == null)
+               {
+                       return null;
+               }
+               switch (inService)
+               {
+                       case MAP_SOURCE_PEAKFINDER:
+                               return generatePeakfinderUrl(currPoint);
+                       case MAP_SOURCE_GEOHACK:
+                               return generateGeohackUrl(currPoint);
+                       case MAP_SOURCE_PANORAMIO:
+                               return generatePanoramioUrl(currPoint);
+                       case MAP_SOURCE_OPENCACHINGCOM:
+                               return generateOpencachingComUrl(currPoint);
+                       default:
+                               return null;
+               }
+       }
+
+
+       /**
+        * Generate a url for PeakFinder
+        * @param inPoint current point, not null
+        * @return URL
+        */
+       private static String generatePeakfinderUrl(DataPoint inPoint)
+       {
+               return "http://peakfinder.org/?lat=" + FIVE_DP.format(inPoint.getLatitude().getDouble())
+                       + "&lng=" + FIVE_DP.format(inPoint.getLongitude().getDouble());
+       }
+
+       /**
+        * Generate a url for Geohack
+        * @param inPoint current point, not null
+        * @return URL
+        */
+       private static String generateGeohackUrl(DataPoint inPoint)
+       {
+               return "https://tools.wmflabs.org/geohack/geohack.php?params=" + FIVE_DP.format(inPoint.getLatitude().getDouble())
+                       + "_N_" + FIVE_DP.format(inPoint.getLongitude().getDouble()) + "_E";
+               // 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";
+       }
+
+
+       /**
+        * Generate a url for OpenCaching.com
+        * @param inPoint current point, not null
+        * @return URL
+        */
+       private static String generateOpencachingComUrl(DataPoint inPoint)
+       {
+               final String occLang = I18nManager.getText("webservice.opencachingcom.lang");
+               final String url = "http://www.opencaching.com/" + occLang
+                       + "/#find?&loc=" + FIVE_DP.format(inPoint.getLatitude().getDouble())
+                       + "," + FIVE_DP.format(inPoint.getLongitude().getDouble());
+               return url;
+       }
+
 
        /**
         * Get the median value from the given lat/long range
diff --git a/tim/prune/function/browser/WebMapFunction.java b/tim/prune/function/browser/WebMapFunction.java
new file mode 100644 (file)
index 0000000..1639c45
--- /dev/null
@@ -0,0 +1,46 @@
+package tim.prune.function.browser;
+
+import tim.prune.App;
+import tim.prune.GenericFunction;
+
+/**
+ * Function to show a webservice for the current area or point
+ */
+public class WebMapFunction extends GenericFunction
+{
+       /** Service to call */
+       private UrlGenerator.WebService _service;
+       /** Key for appearance in menu */
+       private String _nameKey = null;
+
+       /**
+        * Constructor
+        * @param inApp app object
+        * @param inService web service to call
+        * @param inNameKey name key for function
+        */
+       public WebMapFunction(App inApp, UrlGenerator.WebService inService,
+               String inNameKey)
+       {
+               super(inApp);
+               _service = inService;
+               _nameKey = inNameKey;
+       }
+
+       @Override
+       public String getNameKey() {
+               return _nameKey;
+       }
+
+       @Override
+       /**
+        * Do the function call
+        */
+       public void begin()
+       {
+               String url = UrlGenerator.generateUrl(_service, _app.getTrackInfo());
+               if (url != null) {
+                       BrowserLauncher.launchBrowser(url);
+               }
+       }
+}
index 59ef13a9d1248eb9add927dbfe3f8ba53958a487..5431e9eedca9b3c1bce1b5705479e850f4f536d2 100644 (file)
@@ -273,6 +273,7 @@ public class ManageCacheFunction extends GenericFunction implements Runnable
         */
        public void run()
        {
+               // TODO: Maybe this can be speeded up so that it just finds the tilesets first and then gets the details later
                // Check if directory has anything in it
                _model = new TileCacheModel(_cacheDir);
                _model.buildTileSets();
index 8c7ee23d00d39133b269268994f9c1174506d91f..809c572e48979255366e05ef7d2342329a38d1d7 100644 (file)
@@ -10,7 +10,6 @@ public class RowInfo
        private int _minZoom = -1, _maxZoom = -1;
        private int _numTiles = 0;
        private long _totalSize = 0L;
-       private boolean _unexpected = false;
 
 
        /**
@@ -84,20 +83,6 @@ public class RowInfo
                return _totalSize;
        }
 
-       /**
-        * Mark that an unexpected file or directory was found
-        * TODO: Is this needed?
-        */
-       public void foundUnexpected() {
-               _unexpected = true;
-       }
-
-       /**
-        * @return true if any unexpected files or directories were found
-        */
-       public boolean wasUnexpected() {
-               return _unexpected;
-       }
 
        /**
         * Add the given RowInfo object to this one
@@ -117,6 +102,5 @@ public class RowInfo
                        addZoom(inOther._maxZoom);
                if (inOther._zoom > 0)
                        addZoom(inOther._zoom);
-               _unexpected = _unexpected || inOther._unexpected;
        }
 }
index ca2b81a442fdf2b57136a1232132ef0a4b1c644b..525696e518e8566289b90cb11691930fbef9e2fc 100644 (file)
@@ -59,6 +59,35 @@ public class TileSet
                return true;
        }
 
+       /**
+        * Check if a filename is numeric up until the first dot
+        * This appears to be much faster than scanning for a . with indexOf, then
+        * chopping to make a new String, and then calling isNumeric to scan through again
+        * @param inName name of file
+        * @return true if it only contains characters 0-9 before the first dot
+        */
+       public static boolean isNumericUntilDot(String inName)
+       {
+               if (inName == null || inName.equals("") || inName.charAt(0) == '.') {
+                       return false;
+               }
+               try
+               {
+                       char c = '.';
+                       int i = 0;
+                       do
+                       {
+                               c = inName.charAt(i);
+                               if (c == '.') return true; // found the dot, so stop
+                               if (c < '0' || c > '9') return false; // not numeric
+                               i++;
+                       } while (c != '\0');
+               }
+               catch (IndexOutOfBoundsException iobe) {}
+               // Didn't find a dot, so can't be a valid name
+               return false;
+       }
+
        /**
         * Make a RowInfo object from the given directory
         * @param inDir directory for a single zoom level
@@ -78,9 +107,7 @@ public class TileSet
                                {
                                        if (f != null && f.exists() && f.isFile() && f.canRead())
                                        {
-                                               final String filename = f.getName();
-                                               int dotpos = filename.lastIndexOf('.');
-                                               if (dotpos > 0 && isNumeric(filename.substring(0, dotpos))) {
+                                               if (isNumericUntilDot(f.getName())) {
                                                        row.addTile(f.length());
                                                }
                                        }
diff --git a/tim/prune/function/compress/DeleteMarkedPointsFunction.java b/tim/prune/function/compress/DeleteMarkedPointsFunction.java
new file mode 100644 (file)
index 0000000..a604907
--- /dev/null
@@ -0,0 +1,56 @@
+package tim.prune.function.compress;
+
+import tim.prune.App;
+import tim.prune.GenericFunction;
+import tim.prune.I18nManager;
+import tim.prune.undo.UndoDeleteMarked;
+
+/**
+ * Function to delete the marked points in the track
+ */
+public class DeleteMarkedPointsFunction extends GenericFunction
+{
+       private boolean _splitSegments = false;
+       private String  _parentFunctionKey = null;
+
+       /** Constructor */
+       public DeleteMarkedPointsFunction(App inApp) {
+               super(inApp);
+       }
+
+       @Override
+       public String getNameKey() {
+               return "function.deletemarked";
+       }
+
+       /**
+        * Get notification about parent function
+        * @param inKey parent function name key
+        * @param inSplitSegments true to split segment, false to not
+        */
+       public void setParentFunction(String inKey, boolean inSplitSegments)
+       {
+               _parentFunctionKey = inKey;
+               _splitSegments = inSplitSegments;
+       }
+
+       @Override
+       public void begin()
+       {
+               UndoDeleteMarked undo = new UndoDeleteMarked(_app.getTrackInfo().getTrack());
+               // call track to do the actual delete//
+               int numPointsDeleted = _app.getTrackInfo().deleteMarkedPoints(_splitSegments);
+               // add to undo stack if successful
+               if (numPointsDeleted > 0)
+               {
+                       undo.setNumPointsDeleted(numPointsDeleted);
+                       _app.completeFunction(undo, "" + numPointsDeleted + " "
+                                + (numPointsDeleted==1?I18nManager.getText("confirm.deletepoint.single"):I18nManager.getText("confirm.deletepoint.multi")));
+               }
+               else
+               {
+                       final String titleKey = (_parentFunctionKey == null ? getNameKey() : _parentFunctionKey);
+                       _app.showErrorMessage(titleKey, "dialog.deletemarked.nonefound");
+               }
+       }
+}
index 2189ecb8c46d664a0b88ac897f21c0a63481de9f..dddc897480942648b603569c325b226f3831089f 100644 (file)
@@ -3,6 +3,7 @@ package tim.prune.function.compress;
 import javax.swing.JOptionPane;
 
 import tim.prune.App;
+import tim.prune.FunctionLibrary;
 import tim.prune.GenericFunction;
 import tim.prune.I18nManager;
 
@@ -39,13 +40,23 @@ public abstract class MarkAndDeleteFunction extends GenericFunction
                        I18nManager.getText(getNameKey()), JOptionPane.YES_NO_CANCEL_OPTION,
                        JOptionPane.WARNING_MESSAGE, null, buttonTexts, buttonTexts[1]);
                if (answer == JOptionPane.CANCEL_OPTION) {_automaticallyDelete = true;} // "always" is third option
+
+               // Make sure function knows what to do, whether we'll call it now or later
+               FunctionLibrary.FUNCTION_DELETE_MARKED_POINTS.setParentFunction(
+                               getNameKey(), getShouldSplitSegments());
                if (_automaticallyDelete || answer == JOptionPane.YES_OPTION)
                {
                        new Thread(new Runnable() {
-                               public void run() {
-                                       _app.finishCompressTrack();
+                               public void run()
+                               {
+                                       FunctionLibrary.FUNCTION_DELETE_MARKED_POINTS.begin();
                                }
                        }).start();
                }
        }
+
+       /** by default, segments are not split at deleted points */
+       protected boolean getShouldSplitSegments() {
+               return false;
+       }
 }
diff --git a/tim/prune/function/compress/MarkLiftsFunction.java b/tim/prune/function/compress/MarkLiftsFunction.java
new file mode 100644 (file)
index 0000000..5e39866
--- /dev/null
@@ -0,0 +1,143 @@
+package tim.prune.function.compress;
+
+import tim.prune.App;
+import tim.prune.UpdateMessageBroker;
+import tim.prune.data.DataPoint;
+import tim.prune.data.Distance;
+import tim.prune.data.RangeStats;
+import tim.prune.data.Track;
+import tim.prune.data.UnitSetLibrary;
+
+/**
+ * Function to mark all the points going uphill on ski lifts
+ */
+public class MarkLiftsFunction extends MarkAndDeleteFunction
+{
+       /**
+        * Constructor
+        * @param inApp App object
+        */
+       public MarkLiftsFunction(App inApp)
+       {
+               super(inApp);
+       }
+
+       /** @return name key */
+       public String getNameKey() {
+               return "function.marklifts";
+       }
+
+       /** this function _does_ require split at deleted points */
+       protected boolean getShouldSplitSegments() {
+               return true;
+       }
+
+       /**
+        * Begin the function using the set parameters
+        */
+       public void begin()
+       {
+               // TODO: Might need to do this in a separate thread, it might take a while if the track is big
+               // Loop over all points in track
+               int numMarked = 0;
+               final Track track = _app.getTrackInfo().getTrack();
+               final int numPoints = track.getNumPoints();
+               boolean[] markFlags = new boolean[numPoints];
+               int previousStartIndex = -1;
+               for (int i=0; i<numPoints; i++)
+               {
+                       DataPoint currPoint = track.getPoint(i);
+                       if (currPoint != null && !currPoint.isWaypoint() && currPoint.hasAltitude() && currPoint.hasTimestamp())
+                       {
+                               int n = i+1;
+                               DataPoint endPoint = track.getPoint(n);
+                               while (endPoint != null && endPoint.hasAltitude() && endPoint.hasTimestamp() &&
+                                       !endPoint.isWaypoint() && endPoint.getTimestamp().getSecondsSince(currPoint.getTimestamp()) < 120)
+                               {
+                                       n++;
+                                       endPoint = track.getPoint(n);
+                               }
+                               if (endPoint != null && endPoint.hasAltitude() && endPoint.hasTimestamp() && !endPoint.isWaypoint()
+                                       && n > (i+10))
+                               {
+                                       // Found a 2 minute range to test with at least 12 points
+                                       if (looksLikeLiftRange(track, i, n))
+                                       {
+                                               // Passes tests, so we want to mark all points between i and n
+                                               int startIndex = i;
+                                               // First check if we can merge with the previous marked range
+                                               if (previousStartIndex >= 0
+                                                       && (looksLikeLiftRange(track, previousStartIndex, i)
+                                                        || looksLikeLiftRange(track, previousStartIndex, n)))
+                                               {
+                                                       startIndex = previousStartIndex; // merge
+                                               }
+                                               for (int j=startIndex; j<=n; j++)
+                                               {
+                                                       markFlags[j] = true;
+                                               }
+                                               // Remember start point for next one
+                                               previousStartIndex = startIndex;
+                                               // skip forward half the range, don't need to test the same points again
+                                               i = (i+n)/2;
+                                       }
+                               }
+                       }
+               }
+
+               // Copy mark flags to points
+               for (int i=0; i<numPoints; i++)
+               {
+                       DataPoint point = track.getPoint(i);
+                       if (!point.isWaypoint()) point.setMarkedForDeletion(markFlags[i]);
+                       if (markFlags[i]) numMarked++;
+               }
+               // Inform subscribers to update display
+               UpdateMessageBroker.informSubscribers();
+               // Confirm message showing how many marked
+               if (numMarked > 0)
+               {
+                       optionallyDeleteMarkedPoints(numMarked);
+               }
+               else
+               {
+                       // TODO: Show message that no lifts were found
+               }
+       }
+
+
+       /**
+        * Check whether the specified range looks like an uphill lift section or not
+        * Must go at most a little bit downhill, much more uphill than down, and straight
+        * (speed isn't checked yet, but maybe could be?)
+        * @param inTrack track
+        * @param inStartIndex start index of range
+        * @param inEndIndex end index of range
+        * @return true if it looks like a lift
+        */
+       private boolean looksLikeLiftRange(Track inTrack, int inStartIndex, int inEndIndex)
+       {
+               RangeStats stats = new RangeStats(inTrack, inStartIndex, inEndIndex);
+               int descent = stats.getTotalAltitudeRange().getDescent(UnitSetLibrary.UNITS_METRES);
+               if (descent < 20)
+               {
+                       int ascent = stats.getTotalAltitudeRange().getClimb(UnitSetLibrary.UNITS_METRES);
+                       if (ascent > (descent * 10))
+                       {
+                               // Now check distance and compare to distance between start and end
+                               final DataPoint startPoint = inTrack.getPoint(inStartIndex);
+                               final DataPoint endPoint   = inTrack.getPoint(inEndIndex);
+
+                               final double trackDist = stats.getTotalDistance();
+                               final double endToEndDist = Distance.convertRadiansToDistance(
+                                       DataPoint.calculateRadiansBetween(startPoint, endPoint));
+                               if ((trackDist / endToEndDist) < 1.02)  // Straight(ish) line
+                               {
+                                       return true;
+                               }
+                               //else System.out.println("Not straight enough: " + (trackDist / endToEndDist));
+                       }
+               }
+               return false;
+       }
+}
index e60ed7429c4578e2bbfb44f8e3902dd69e102d63..cdcc9a9f4f1dfc613bcb752395fa2dae4853ba18 100644 (file)
@@ -12,6 +12,8 @@ import javax.xml.parsers.SAXParserFactory;
 import tim.prune.App;
 import tim.prune.GpsPrune;
 import tim.prune.I18nManager;
+import tim.prune.function.search.GenericDownloaderFunction;
+import tim.prune.function.search.SearchResult;
 import tim.prune.load.xml.XmlFileLoader;
 import tim.prune.load.xml.ZipFileLoader;
 
@@ -65,7 +67,7 @@ public class GetGpsiesFunction extends GenericDownloaderFunction
                double[] coords = _app.getViewport().getBounds();
                int currPage = 1;
 
-               ArrayList<GpsiesTrack> trackList = null;
+               ArrayList<SearchResult> trackList = null;
                URL url = null;
                String descMessage = "";
                InputStream inStream = null;
index 3d801be5bc845c5e449c486626ef0837d89ba4d6..f90bb037327ed9dce75b756fee199ab174230498 100644 (file)
@@ -6,14 +6,16 @@ import org.xml.sax.Attributes;
 import org.xml.sax.SAXException;
 import org.xml.sax.helpers.DefaultHandler;
 
+import tim.prune.function.search.SearchResult;
+
 /**
  * XML handler for dealing with XML returned from gpsies.com
  */
 public class GpsiesXmlHandler extends DefaultHandler
 {
        private String _value = null;
-       private ArrayList<GpsiesTrack> _trackList = null;
-       private GpsiesTrack _track = null;
+       private ArrayList<SearchResult> _trackList = null;
+       private SearchResult _track = null;
 
 
        /**
@@ -23,10 +25,10 @@ public class GpsiesXmlHandler extends DefaultHandler
                Attributes inAttributes) throws SAXException
        {
                if (inTagName.equals("tracks")) {
-                       _trackList = new ArrayList<GpsiesTrack>();
+                       _trackList = new ArrayList<SearchResult>();
                }
                else if (inTagName.equals("track")) {
-                       _track = new GpsiesTrack();
+                       _track = new SearchResult();
                }
                _value = null;
                super.startElement(inUri, inLocalName, inTagName, inAttributes);
@@ -76,7 +78,7 @@ public class GpsiesXmlHandler extends DefaultHandler
        /**
         * @return the list of tracks
         */
-       public ArrayList<GpsiesTrack> getTrackList()
+       public ArrayList<SearchResult> getTrackList()
        {
                return _trackList;
        }
index 274c0b882a3bf51f1ee7c7dfe278646f756ff235..298578c4330c5dab8eccf8f86da4cff19b33187f 100644 (file)
@@ -8,6 +8,7 @@ import javax.swing.table.AbstractTableModel;
 import tim.prune.I18nManager;
 import tim.prune.config.Config;
 import tim.prune.data.Unit;
+import tim.prune.function.search.SearchResult;
 
 /**
  * Model for list of tracks from gpsies.com
@@ -15,7 +16,7 @@ import tim.prune.data.Unit;
 public class TrackListModel extends AbstractTableModel
 {
        /** List of tracks */
-       private ArrayList<GpsiesTrack> _trackList = null;
+       private ArrayList<SearchResult> _trackList = null;
        /** Column heading for track name */
        private String _nameColLabel = null;
        /** Column heading for length */
@@ -80,7 +81,7 @@ public class TrackListModel extends AbstractTableModel
         */
        public Object getValueAt(int inRowNum, int inColNum)
        {
-               GpsiesTrack track = _trackList.get(inRowNum);
+               SearchResult track = _trackList.get(inRowNum);
                if (inColNum == 0) {return track.getTrackName();}
                double lengthM = track.getLength();
                // convert to current distance units
@@ -94,9 +95,9 @@ public class TrackListModel extends AbstractTableModel
         * Add a list of tracks to this model
         * @param inList list of tracks to add
         */
-       public void addTracks(ArrayList<GpsiesTrack> inList)
+       public void addTracks(ArrayList<SearchResult> inList)
        {
-               if (_trackList == null) {_trackList = new ArrayList<GpsiesTrack>();}
+               if (_trackList == null) {_trackList = new ArrayList<SearchResult>();}
                final int prevCount = _trackList.size();
                if (inList != null && inList.size() > 0) {
                        _trackList.addAll(inList);
@@ -112,7 +113,7 @@ public class TrackListModel extends AbstractTableModel
         * @param inRowNum row number from 0
         * @return track object for this row
         */
-       public GpsiesTrack getTrack(int inRowNum)
+       public SearchResult getTrack(int inRowNum)
        {
                return _trackList.get(inRowNum);
        }
similarity index 98%
rename from tim/prune/function/gpsies/GenericDownloaderFunction.java
rename to tim/prune/function/search/GenericDownloaderFunction.java
index 286ba1aae7bc677cd835e3855ea213d44e206b6d..403a0efb69d28b7d8296ea71db65592edf5ccdf7 100644 (file)
@@ -1,4 +1,4 @@
-package tim.prune.function.gpsies;
+package tim.prune.function.search;
 
 import java.awt.BorderLayout;
 import java.awt.Component;
@@ -25,6 +25,7 @@ import tim.prune.App;
 import tim.prune.GenericFunction;
 import tim.prune.I18nManager;
 import tim.prune.function.browser.BrowserLauncher;
+import tim.prune.function.gpsies.TrackListModel;
 
 /**
  * Function to load track information from any source,
diff --git a/tim/prune/function/search/SearchMapillaryFunction.java b/tim/prune/function/search/SearchMapillaryFunction.java
new file mode 100644 (file)
index 0000000..32c58bd
--- /dev/null
@@ -0,0 +1,231 @@
+package tim.prune.function.search;
+
+import java.io.InputStream;
+import java.net.URL;
+import java.util.ArrayList;
+
+import tim.prune.App;
+import tim.prune.I18nManager;
+import tim.prune.data.DataPoint;
+import tim.prune.data.Distance;
+import tim.prune.data.Field;
+import tim.prune.data.Latitude;
+import tim.prune.data.Longitude;
+import tim.prune.data.SourceInfo;
+import tim.prune.data.UnitSetLibrary;
+import tim.prune.load.MediaLinkInfo;
+
+/**
+ * Function to search mapillary for photos
+ */
+public class SearchMapillaryFunction extends GenericDownloaderFunction
+{
+       /** Maximum number of results to get */
+       private static final int MAX_RESULTS = 20;
+
+
+       /**
+        * Constructor
+        * @param inApp app object
+        */
+       public SearchMapillaryFunction(App inApp)
+       {
+               super(inApp);
+       }
+
+       @Override
+       public String getNameKey() {
+               return "function.mapillary";
+       }
+
+       @Override
+       protected String getColumnKey(int inColNum)
+       {
+               if (inColNum == 0) return "dialog.wikipedia.column.name";
+               return "dialog.wikipedia.column.distance";
+       }
+
+       /**
+        * Run method, for searching in a separate thread
+        */
+       public void run()
+       {
+               _statusLabel.setText(I18nManager.getText("confirm.running"));
+               // Get coordinates from current point (if any) or from centre of screen
+               double lat = 0.0, lon = 0.0;
+               DataPoint currentPoint = _app.getTrackInfo().getCurrentPoint();
+               if (currentPoint == null)
+               {
+                       double[] coords = _app.getViewport().getBounds();
+                       lat = (coords[0] + coords[2]) / 2.0;
+                       lon = (coords[1] + coords[3]) / 2.0;
+               }
+               else
+               {
+                       lat = currentPoint.getLatitude().getDouble();
+                       lon = currentPoint.getLongitude().getDouble();
+               }
+
+               // Construct URL
+               final String urlString = "http://api.mapillary.com/v1/im/close?lat="
+                       + lat + "&lon=" + lon + "&distance=1000&limit=" + MAX_RESULTS;
+               //System.out.println(urlString);
+               InputStream inStream = null;
+               try
+               {
+                       inStream = new URL(urlString).openStream();
+                       StringBuilder sb = new StringBuilder();
+                       int ch = 0;
+                       while ((ch = inStream.read()) >= 0)
+                       {
+                               sb.append((char) ch);
+                       }
+                       //System.out.println("Got answer: '" + sb.toString() + "'");
+
+                       ArrayList<SearchResult> resultList = new ArrayList<SearchResult>();
+                       for (String result : sb.toString().split("\\},\\{"))
+                       {
+                               //System.out.println("Result: '" + result + "'");
+                               SearchResult sr = new SearchResult();
+                               for (String prop : result.split(","))
+                               {
+                                       String key = getKey(prop);
+                                       if (key == null) {continue;}
+                                       if (key.equals("key"))
+                                       {
+                                               final String value = getValue(prop);
+                                               sr.setDownloadLink("http://images.mapillary.com/" + value + "/thumb-1024.jpg");
+                                               sr.setWebUrl("http://www.mapillary.com/map/im/" + value);
+                                               sr.setTrackName(value);
+                                       }
+                                       else if (key.equals("lat")) {
+                                               sr.setLatitude(getValue(prop));
+                                       }
+                                       else if (key.equals("lon")) {
+                                               sr.setLongitude(getValue(prop));
+                                       }
+                               }
+
+                               if (sr.getLatitude() != null && sr.getLongitude() != null && sr.getTrackName() != null)
+                               {
+                                       // Calculate distance away from current point and set this in sr.setLength
+                                       DataPoint resultPoint = new DataPoint(new Latitude(sr.getLatitude()), new Longitude(sr.getLongitude()), null);
+                                       if (resultPoint.isValid() && currentPoint != null && currentPoint.isValid())
+                                       {
+                                               double radianDist = DataPoint.calculateRadiansBetween(currentPoint, resultPoint);
+                                               double metresAway = Distance.convertRadiansToDistance(radianDist, UnitSetLibrary.UNITS_METRES);
+                                               sr.setLength(metresAway);
+                                       }
+
+                                       // If there's a valid result, add it to the temporary list
+                                       if (sr.getTrackName() != null) {
+                                               resultList.add(sr);
+                                       }
+                               }
+                       }
+                       // Add all the results to the table model in one go
+                       if (!resultList.isEmpty()) {
+                               _trackListModel.addTracks(resultList);
+                       }
+               }
+               catch (Exception e) {
+                       _errorMessage = e.getClass().getName() + " - " + e.getMessage();
+               }
+               // Close stream and ignore errors
+               try {
+                       inStream.close();
+               } catch (Exception e) {}
+
+               // Set status label according to error or "none found", leave blank if ok
+               if (_errorMessage == null && _trackListModel.isEmpty()) {
+                       _errorMessage = I18nManager.getText("dialog.mapillary.nonefound");
+               }
+               _statusLabel.setText(_errorMessage == null ? "" : _errorMessage);
+       }
+
+       /**
+        * From a JSON key:value string, return just the key
+        * @param inString string to parse
+        * @return just the key without the surrounding quotes, or null if not found
+        */
+       private static String getKey(String inString)
+       {
+               if (inString == null || inString.equals("")) {return null;}
+               final int colonPos = inString.indexOf(':');
+               if (colonPos <= 0) {return null;}
+               int startPos = 0;
+               char c;
+               while ((c = inString.charAt(startPos)) == '['
+                       || c == '{' || c == '\"')
+               {
+                       startPos++;
+               }
+               int endPos = colonPos;
+               while ((c = inString.charAt(endPos-1)) == '\"')
+               {
+                       endPos--;
+               }
+               return inString.substring(startPos, endPos);
+       }
+
+       /**
+        * From a JSON key:value string, return just the value
+        * @param inString string to parse
+        * @return just the value without the surrounding quotes
+        */
+       private static String getValue(String inString)
+       {
+               final int colonPos = inString.indexOf(':');
+               if (colonPos <= 0 || colonPos >= inString.length()) {return null;}
+               int startPos = colonPos+1;
+               char c;
+               while ((c = inString.charAt(startPos)) == '\"')
+               {
+                       startPos++;
+               }
+               int endPos = inString.length()-1;
+               while ((c = inString.charAt(endPos-1)) == '\"'
+                       || c == '}' || c == ']')
+               {
+                       endPos--;
+               }
+               return inString.substring(startPos, endPos);
+       }
+
+       @Override
+       protected void loadSelected()
+       {
+               // Find the row(s) selected in the table and get the corresponding track
+               int numSelected = _trackTable.getSelectedRowCount();
+               if (numSelected < 1) return;
+               int[] rowNums = _trackTable.getSelectedRows();
+
+               String[][] pointData = new String[numSelected][];
+               String[]   linkArray = new String[numSelected];
+
+               // Loop over each of the selected points
+               for (int i=0; i<numSelected; i++)
+               {
+                       pointData[i] = new String[3]; // lat, long, segment
+                       int rowNum = rowNums[i];
+                       if (rowNum >= 0 && rowNum < _trackListModel.getRowCount())
+                       {
+                               SearchResult result = _trackListModel.getTrack(rowNum);
+                               //String url = result.getDownloadLink();
+                               pointData[i][0] = result.getLatitude();
+                               pointData[i][1] = result.getLongitude();
+                               pointData[i][2] = "1"; // all points have a new segment
+                               linkArray[i]    = result.getDownloadLink();
+                       }
+               }
+               // Prepare the data for the app
+               final Field[] fields = {Field.LATITUDE, Field.LONGITUDE, Field.NEW_SEGMENT};
+               _app.autoAppendNextFile();
+               _app.informDataLoaded(fields, pointData, null, new SourceInfo("mapillary", SourceInfo.FILE_TYPE.JSON),
+                       null, new MediaLinkInfo(linkArray));
+
+               // Close the dialog
+               _cancelled = true;
+               _dialog.dispose();
+       }
+}
similarity index 68%
rename from tim/prune/function/gpsies/GpsiesTrack.java
rename to tim/prune/function/search/SearchResult.java
index da1339ee113883c19788d9df6bfbeb51242bb4f7..2a05a8cf22e7c818e12250fba37ec7b5fb98b065 100644 (file)
@@ -1,9 +1,9 @@
-package tim.prune.function.gpsies;
+package tim.prune.function.search;
 
 /**
- * Class to hold a single track from Gpsies.com
+ * Class to hold a search result from wikipedia / gpsies / panoramio etc
  */
-public class GpsiesTrack
+public class SearchResult
 {
        /** Track name or title */
        private String _trackName = null;
@@ -15,6 +15,8 @@ public class GpsiesTrack
        private double _trackLength = 0.0;
        /** Download link */
        private String _downloadLink = null;
+       /** Coordinates of point */
+       private String _latitude = null, _longitude = null;
 
 
        /**
@@ -96,4 +98,32 @@ public class GpsiesTrack
        {
                return _downloadLink;
        }
+
+       /**
+        * @param inLatitude latitude
+        */
+       public void setLatitude(String inLatitude) {
+               _latitude = inLatitude;
+       }
+
+       /**
+        * @return latitude
+        */
+       public String getLatitude() {
+               return _latitude;
+       }
+
+       /**
+        * @param inLongitude longitude
+        */
+       public void setLongitude(String inLongitude) {
+               _longitude = inLongitude;
+       }
+
+       /**
+        * @return longitude
+        */
+       public String getLongitude() {
+               return _longitude;
+       }
 }
index 2ed145439227af2d7ddf2e37ff2b1262698aece0..011dff66fc913563f959c8d21636fb7a79e019ee 100644 (file)
@@ -228,13 +228,18 @@ public class LookupSrtmFunction extends GenericFunction implements Runnable
                                                                                        + (fouralts[2]==VOID_VAL?1:0) + (fouralts[3]==VOID_VAL?1:0);
                                                                                // if (numVoids > 0) System.out.println(numVoids + " voids found");
                                                                                double altitude = 0.0;
-                                                                               switch (numVoids) {
+                                                                               switch (numVoids)
+                                                                               {
                                                                                        case 0: altitude = bilinearInterpolate(fouralts, x, y); break;
                                                                                        case 1: altitude = bilinearInterpolate(fixVoid(fouralts), x, y); break;
                                                                                        case 2:
                                                                                        case 3: altitude = averageNonVoid(fouralts); break;
                                                                                        default: altitude = VOID_VAL;
                                                                                }
+                                                                               // Special case for terrain tracks, don't interpolate voids yet
+                                                                               if (!_normalTrack && numVoids > 0) {
+                                                                                       altitude = VOID_VAL;
+                                                                               }
                                                                                if (altitude != VOID_VAL)
                                                                                {
                                                                                        point.setFieldValue(Field.ALTITUDE, ""+altitude, false);
index eff471417dd251d57909d4c24c241847fde14f11..fd0a888d111e4805cf020c8adb8ac8653004e3a3 100644 (file)
@@ -25,9 +25,11 @@ public abstract class IconManager
        /** Icon for autopan button on main map display when selected */
        public static final String AUTOPAN_BUTTON_ON = "autopan_on.gif";
        /** Icon for points connected icon on main map display */
-       public static final String POINTS_CONNECTED_BUTTON = "points_connected.gif";
+       public static final String POINTS_CONNECTED_BUTTON = "points_connected.png";
        /** Icon for points disconnected icon on main map display */
-       public static final String POINTS_DISCONNECTED_BUTTON = "points_disconnected.gif";
+       public static final String POINTS_DISCONNECTED_BUTTON = "points_disconnected.png";
+       /** Icon for points hidden, just lines icon on main map display */
+       public static final String POINTS_HIDDEN_BUTTON = "points_hidden.png";
         /** Icon for edit mode button on main map display when not selected */
        public static final String EDIT_MODE_BUTTON = "drag_points_icon.gif";
         /** Icon for edit mode button on main map display when selected */
@@ -70,6 +72,12 @@ public abstract class IconManager
        public static final String PLAY_AUDIO = "play_audio.gif";
        /** Icon for stopping the current audio clip */
        public static final String STOP_AUDIO = "stop_audio.gif";
+       /** Icon for autoplaying a track */
+       public static final String AUTOPLAY_PLAY = "play.png";
+       /** Icon for pausing autoplay of a track */
+       public static final String AUTOPLAY_PAUSE = "pause.png";
+       /** Icon for rewinding the autoplay of a track */
+       public static final String AUTOPLAY_REWIND = "rewind.png";
 
        /** Icon for a given entry being valid (green tick) */
        public static final String ENTRY_VALID = "entry_valid.gif";
index 741425dea2e9b2c63b321e47b15ce4b1c31a5c68..f664f4bc4b9470c5ea6b3cdbe22daa87ede5ff1e 100644 (file)
@@ -30,7 +30,10 @@ import tim.prune.data.Selection;
 import tim.prune.data.Track;
 import tim.prune.data.TrackInfo;
 import tim.prune.function.ChooseSingleParameter;
+import tim.prune.function.SearchOpenCachingDeFunction;
 import tim.prune.function.browser.UrlGenerator;
+import tim.prune.function.browser.WebMapFunction;
+import tim.prune.function.search.SearchMapillaryFunction;
 
 /**
  * Class to manage the menu bar and tool bar,
@@ -60,6 +63,7 @@ public class MenuManager implements DataSubscriber
        private JMenuItem _cropTrackItem = null;
        private JMenuItem _compressItem = null;
        private JMenuItem _markRectangleItem = null;
+       private JMenuItem _markUphillLiftsItem = null;
        private JMenuItem _deleteMarkedPointsItem = null;
        private JMenuItem _deleteByDateItem = null;
        private JMenuItem _interpolateItem = null;
@@ -89,13 +93,20 @@ public class MenuManager implements DataSubscriber
        private JMenuItem _uploadGpsiesItem = null;
        private JMenuItem _lookupSrtmItem = null;
        private JMenuItem _downloadSrtmItem = null;
-       private JMenuItem _lookupWikipediaItem = null;
+       private JMenuItem _nearbyWikipediaItem = null;
+       private JMenuItem _showPeakfinderItem = null;
+       private JMenuItem _showGeohackItem = null;
+       private JMenuItem _showPanoramioItem = null;
+       private JMenuItem _showOpencachingComItem = null;
+       private JMenuItem _searchOpencachingDeItem = null;
+       private JMenuItem _searchMapillaryItem = null;
        private JMenuItem _downloadOsmItem = null;
        private JMenuItem _getWeatherItem = null;
        private JMenuItem _distanceItem = null;
        private JMenuItem _fullRangeDetailsItem = null;
        private JMenuItem _estimateTimeItem = null;
        private JMenuItem _learnEstimationParams = null;
+       private JMenuItem _autoplayTrack = null;
        private JMenuItem _saveExifItem = null;
        private JMenuItem _photoPopupItem = null;
        private JMenuItem _selectNoPhotoItem = null;
@@ -113,6 +124,7 @@ public class MenuManager implements DataSubscriber
        private JMenuItem _correlateAudiosItem = null;
        private JMenuItem _selectNoAudioItem = null;
        private JCheckBoxMenuItem _onlineCheckbox = null;
+       private JCheckBoxMenuItem _antialiasCheckbox = null;
        private JCheckBoxMenuItem _autosaveSettingsCheckbox = null;
 
        // ActionListeners for reuse by menu and toolbar
@@ -257,14 +269,43 @@ public class MenuManager implements DataSubscriber
                // Upload to gpsies
                _uploadGpsiesItem = makeMenuItem(FunctionLibrary.FUNCTION_UPLOAD_GPSIES, false);
                onlineMenu.add(_uploadGpsiesItem);
+
                onlineMenu.addSeparator();
-               _lookupWikipediaItem = makeMenuItem(FunctionLibrary.FUNCTION_LOOKUP_WIKIPEDIA, false);
-               onlineMenu.add(_lookupWikipediaItem);
+               // browser submenu
+               _browserMapMenu = new JMenu(I18nManager.getText("menu.view.browser"));
+               _browserMapMenu.setEnabled(false);
+               JMenuItem googleMapsItem = makeMenuItem(new WebMapFunction(_app, UrlGenerator.WebService.MAP_SOURCE_GOOGLE, "menu.view.browser.google"));
+               _browserMapMenu.add(googleMapsItem);
+               JMenuItem openMapsItem = makeMenuItem(new WebMapFunction(_app, UrlGenerator.WebService.MAP_SOURCE_OSM, "menu.view.browser.openstreetmap"));
+               _browserMapMenu.add(openMapsItem);
+               JMenuItem mapquestMapsItem = makeMenuItem(new WebMapFunction(_app, UrlGenerator.WebService.MAP_SOURCE_MAPQUEST, "menu.view.browser.mapquest"));
+               _browserMapMenu.add(mapquestMapsItem);
+               JMenuItem yahooMapsItem = makeMenuItem(new WebMapFunction(_app, UrlGenerator.WebService.MAP_SOURCE_YAHOO, "menu.view.browser.yahoo"));
+               _browserMapMenu.add(yahooMapsItem);
+               JMenuItem bingMapsItem = makeMenuItem(new WebMapFunction(_app, UrlGenerator.WebService.MAP_SOURCE_BING, "menu.view.browser.bing"));
+               _browserMapMenu.add(bingMapsItem);
+               onlineMenu.add(_browserMapMenu);
+               // wikipedia
+               _nearbyWikipediaItem = makeMenuItem(FunctionLibrary.FUNCTION_NEARBY_WIKIPEDIA, false);
+               onlineMenu.add(_nearbyWikipediaItem);
                JMenuItem searchWikipediaNamesItem = makeMenuItem(FunctionLibrary.FUNCTION_SEARCH_WIKIPEDIA);
                onlineMenu.add(searchWikipediaNamesItem);
+               _showPeakfinderItem = makeMenuItem(new WebMapFunction(_app, UrlGenerator.WebService.MAP_SOURCE_PEAKFINDER, "webservice.peakfinder"), false);
+               onlineMenu.add(_showPeakfinderItem);
+               _showGeohackItem = makeMenuItem(new WebMapFunction(_app, UrlGenerator.WebService.MAP_SOURCE_GEOHACK, "webservice.geohack"), false);
+               onlineMenu.add(_showGeohackItem);
+               _showPanoramioItem = makeMenuItem(new WebMapFunction(_app, UrlGenerator.WebService.MAP_SOURCE_PANORAMIO, "webservice.panoramio"), false);
+               onlineMenu.add(_showPanoramioItem);
+               _showOpencachingComItem = makeMenuItem(new WebMapFunction(_app, UrlGenerator.WebService.MAP_SOURCE_OPENCACHINGCOM, "webservice.opencachingcom"), false);
+               onlineMenu.add(_showOpencachingComItem);
+
+               onlineMenu.addSeparator();
+               _searchOpencachingDeItem = makeMenuItem(new SearchOpenCachingDeFunction(_app), false);
+               onlineMenu.add(_searchOpencachingDeItem);
+               _searchMapillaryItem = makeMenuItem(new SearchMapillaryFunction(_app), false);
+               onlineMenu.add(_searchMapillaryItem);
                _downloadOsmItem = makeMenuItem(FunctionLibrary.FUNCTION_DOWNLOAD_OSM, false);
                onlineMenu.add(_downloadOsmItem);
-               onlineMenu.addSeparator();
                _getWeatherItem = makeMenuItem(FunctionLibrary.FUNCTION_GET_WEATHER_FORECAST, false);
                onlineMenu.add(_getWeatherItem);
                menubar.add(onlineMenu);
@@ -304,13 +345,9 @@ public class MenuManager implements DataSubscriber
                });
                _markRectangleItem.setEnabled(false);
                trackMenu.add(_markRectangleItem);
-               _deleteMarkedPointsItem = new JMenuItem(I18nManager.getText("menu.track.deletemarked"));
-               _deleteMarkedPointsItem.addActionListener(new ActionListener() {
-                       public void actionPerformed(ActionEvent e) {
-                               _app.finishCompressTrack();
-                       }
-               });
-               _deleteMarkedPointsItem.setEnabled(false);
+               _markUphillLiftsItem = makeMenuItem(FunctionLibrary.FUNCTION_MARK_LIFTS, false);
+               trackMenu.add(_markUphillLiftsItem);
+               _deleteMarkedPointsItem = makeMenuItem(FunctionLibrary.FUNCTION_DELETE_MARKED_POINTS, false);
                trackMenu.add(_deleteMarkedPointsItem);
                _deleteByDateItem = makeMenuItem(FunctionLibrary.FUNCTION_DELETE_BY_DATE, false);
                trackMenu.add(_deleteByDateItem);
@@ -483,45 +520,6 @@ public class MenuManager implements DataSubscriber
                // 3d
                _show3dItem = makeMenuItem(FunctionLibrary.FUNCTION_3D, false);
                viewMenu.add(_show3dItem);
-               // browser submenu
-               _browserMapMenu = new JMenu(I18nManager.getText("menu.view.browser"));
-               _browserMapMenu.setEnabled(false);
-               JMenuItem googleMapsItem = new JMenuItem(I18nManager.getText("menu.view.browser.google"));
-               googleMapsItem.addActionListener(new ActionListener() {
-                       public void actionPerformed(ActionEvent e) {
-                               _app.showExternalMap(UrlGenerator.MAP_SOURCE_GOOGLE);
-                       }
-               });
-               _browserMapMenu.add(googleMapsItem);
-               JMenuItem openMapsItem = new JMenuItem(I18nManager.getText("menu.view.browser.openstreetmap"));
-               openMapsItem.addActionListener(new ActionListener() {
-                       public void actionPerformed(ActionEvent e) {
-                               _app.showExternalMap(UrlGenerator.MAP_SOURCE_OSM);
-                       }
-               });
-               _browserMapMenu.add(openMapsItem);
-               JMenuItem mapquestMapsItem = new JMenuItem(I18nManager.getText("menu.view.browser.mapquest"));
-               mapquestMapsItem.addActionListener(new ActionListener() {
-                       public void actionPerformed(ActionEvent e) {
-                               _app.showExternalMap(UrlGenerator.MAP_SOURCE_MAPQUEST);
-                       }
-               });
-               _browserMapMenu.add(mapquestMapsItem);
-               JMenuItem yahooMapsItem = new JMenuItem(I18nManager.getText("menu.view.browser.yahoo"));
-               yahooMapsItem.addActionListener(new ActionListener() {
-                       public void actionPerformed(ActionEvent e) {
-                               _app.showExternalMap(UrlGenerator.MAP_SOURCE_YAHOO);
-                       }
-               });
-               _browserMapMenu.add(yahooMapsItem);
-               JMenuItem bingMapsItem = new JMenuItem(I18nManager.getText("menu.view.browser.bing"));
-               bingMapsItem.addActionListener(new ActionListener() {
-                       public void actionPerformed(ActionEvent e) {
-                               _app.showExternalMap(UrlGenerator.MAP_SOURCE_BING);
-                       }
-               });
-               _browserMapMenu.add(bingMapsItem);
-               viewMenu.add(_browserMapMenu);
                // Charts
                _chartItem = makeMenuItem(FunctionLibrary.FUNCTION_CHARTS, false);
                viewMenu.add(_chartItem);
@@ -535,6 +533,10 @@ public class MenuManager implements DataSubscriber
                // estimate time
                _estimateTimeItem = makeMenuItem(FunctionLibrary.FUNCTION_ESTIMATE_TIME, false);
                viewMenu.add(_estimateTimeItem);
+               viewMenu.addSeparator();
+               // autoplay
+               _autoplayTrack = makeMenuItem(FunctionLibrary.FUNCTION_AUTOPLAY_TRACK, false);
+               viewMenu.add(_autoplayTrack);
                menubar.add(viewMenu);
 
                // Add photo menu
@@ -640,6 +642,16 @@ public class MenuManager implements DataSubscriber
                settingsMenu.add(makeMenuItem(FunctionLibrary.FUNCTION_SET_COLOURS));
                // Set line width used for drawing
                settingsMenu.add(makeMenuItem(new ChooseSingleParameter(_app, FunctionLibrary.FUNCTION_SET_LINE_WIDTH)));
+               // Use antialias or not
+               _antialiasCheckbox = new JCheckBoxMenuItem(I18nManager.getText("menu.settings.antialias"), false);
+               _antialiasCheckbox.setSelected(Config.getConfigBoolean(Config.KEY_ANTIALIAS));
+               _antialiasCheckbox.addActionListener(new ActionListener() {
+                       public void actionPerformed(ActionEvent e) {
+                               Config.setConfigBoolean(Config.KEY_ANTIALIAS, _antialiasCheckbox.isSelected());
+                               UpdateMessageBroker.informSubscribers(MAPSERVER_CHANGED);
+                       }
+               });
+                       settingsMenu.add(_antialiasCheckbox);
                // Set language
                settingsMenu.add(makeMenuItem(FunctionLibrary.FUNCTION_SET_LANGUAGE));
                // Set altitude tolerance
@@ -860,6 +872,7 @@ public class MenuManager implements DataSubscriber
                _exportImageItem.setEnabled(hasMultiplePoints);
                _compressItem.setEnabled(hasData);
                _markRectangleItem.setEnabled(hasData);
+               _markUphillLiftsItem.setEnabled(hasData && _track.hasAltitudeData());
                _deleteMarkedPointsItem.setEnabled(hasData && _track.hasMarkedPoints());
                _rearrangeWaypointsItem.setEnabled(hasData && _track.hasTrackPoints() && _track.hasWaypoints());
                _splitSegmentsItem.setEnabled(hasData && _track.hasTrackPoints() && _track.getNumPoints() > 3);
@@ -870,10 +883,11 @@ public class MenuManager implements DataSubscriber
                _chartItem.setEnabled(hasData);
                _browserMapMenu.setEnabled(hasData);
                _distanceItem.setEnabled(hasData);
+               _autoplayTrack.setEnabled(hasData && _track.getNumPoints() > 3);
                _getGpsiesItem.setEnabled(hasData);
                _uploadGpsiesItem.setEnabled(hasData && _track.hasTrackPoints());
                _lookupSrtmItem.setEnabled(hasData);
-               _lookupWikipediaItem.setEnabled(hasData);
+               _nearbyWikipediaItem.setEnabled(hasData);
                _downloadOsmItem.setEnabled(hasData);
                _getWeatherItem.setEnabled(hasData);
                _findWaypointItem.setEnabled(hasData && _track.hasWaypoints());
@@ -900,6 +914,12 @@ public class MenuManager implements DataSubscriber
                _selectEndItem.setEnabled(hasPoint);
                _selectEndButton.setEnabled(hasPoint);
                _duplicatePointItem.setEnabled(hasPoint);
+               _showPeakfinderItem.setEnabled(hasPoint);
+               _showGeohackItem.setEnabled(hasPoint);
+               _showPanoramioItem.setEnabled(hasPoint);
+               _showOpencachingComItem.setEnabled(hasPoint);
+               _searchOpencachingDeItem.setEnabled(hasPoint);
+               _searchMapillaryItem.setEnabled(hasPoint);
                // is it a waypoint?
                _selectSegmentItem.setEnabled(hasPoint && !currPoint.isWaypoint());
                // are there any photos?
diff --git a/tim/prune/gui/TripleStateCheckBox.java b/tim/prune/gui/TripleStateCheckBox.java
new file mode 100644 (file)
index 0000000..6bd6001
--- /dev/null
@@ -0,0 +1,78 @@
+package tim.prune.gui;
+
+import java.awt.event.ItemEvent;
+import java.awt.event.ItemListener;
+
+import javax.swing.ImageIcon;
+import javax.swing.JCheckBox;
+
+/**
+ * Class to represent a checkbox with three states, through which it cycles
+ * Instead of calling isChecked, need to use getCurrentState which will
+ * return 0, 1 or 2
+ */
+public class TripleStateCheckBox extends JCheckBox implements ItemListener
+{
+       /** Array of icons to be used */
+       private ImageIcon[] _icons = new ImageIcon[3];
+       /** Current state 0, 1 or 2 */
+       private int _currState = 0;
+
+       /** Inner class to proxy the listening events */
+       private class ProxyListener implements ItemListener
+       {
+               /** Listener onto which some of the events will be passed */
+               private ItemListener _listener = null;
+               /** Constructor */
+               ProxyListener(ItemListener inListener) {_listener = inListener;}
+               /** React to events, and only pass on the selected ones */
+               public void itemStateChanged(ItemEvent arg0) {
+                       if (arg0.getStateChange() == ItemEvent.SELECTED) {
+                               _listener.itemStateChanged(arg0);
+                       }
+               }
+       }
+
+       /** Constructor */
+       public TripleStateCheckBox()
+       {
+               addItemListener(this);
+       }
+
+       /** Set the current state */
+       public void setCurrentState(int inState)
+       {
+               _currState = inState % 3;
+               setIcon(_icons[_currState]);
+               setSelected(false);
+               setSelectedIcon(_icons[(_currState+1)%3]);
+       }
+
+       /** @return current state 0, 1 or 2 */
+       public int getCurrentState()
+       {
+               return _currState;
+       }
+
+       /**
+        * Set the icon to use for the given index
+        * @param inIndex index 0, 1 or 2
+        * @param inIcon icon to use for that state
+        */
+       public void setIcon(int inIndex, ImageIcon inIcon)
+       {
+               _icons[inIndex % 3] = inIcon;
+       }
+
+       @Override
+       /** Intercept listener adding by putting a proxy inbetween */
+       public void addItemListener(ItemListener inListener) {
+               super.addItemListener(new ProxyListener(inListener));
+       }
+
+       /** React to a selection event by advancing the state */
+       public void itemStateChanged(ItemEvent inEvent)
+       {
+               setCurrentState(_currState + 1);
+       }
+}
index 48307c1a1f9cc54d107462a7a68f4008d9d938a4..b9d9f32993e51adcdb72957f9e5d309822dc811e 100644 (file)
@@ -4,7 +4,6 @@ import java.awt.FlowLayout;
 import java.awt.BorderLayout;
 import java.awt.event.ActionEvent;
 import java.awt.event.ActionListener;
-import java.util.Stack;
 import javax.swing.BorderFactory;
 import javax.swing.JButton;
 import javax.swing.JDialog;
@@ -19,16 +18,17 @@ import javax.swing.event.ListSelectionListener;
 
 import tim.prune.App;
 import tim.prune.I18nManager;
-import tim.prune.undo.UndoOperation;
+import tim.prune.undo.UndoStack;
 
 /**
  * Class to manage the selection of actions to undo
  */
 public class UndoManager
 {
-       private App _app;
-       private JDialog _dialog;
-       private JList<String> _actionList;
+       private App _app = null;
+       private JFrame _parentFrame = null;
+       private JDialog _dialog = null;
+       private JList<String> _actionList = null;
 
 
        /**
@@ -39,18 +39,26 @@ public class UndoManager
        public UndoManager(App inApp, JFrame inFrame)
        {
                _app = inApp;
-               _dialog = new JDialog(inFrame, I18nManager.getText("dialog.undo.title"), true);
-               _dialog.setLocationRelativeTo(inFrame);
+               _parentFrame = inFrame;
+       }
+
+       /**
+        * Show the dialog to select which actions to undo
+        */
+       public void show()
+       {
+               _dialog = new JDialog(_parentFrame, I18nManager.getText("dialog.undo.title"), true);
+               _dialog.setLocationRelativeTo(_parentFrame);
                JPanel mainPanel = new JPanel();
                mainPanel.setLayout(new BorderLayout(3, 3));
                mainPanel.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
-               Stack<UndoOperation> undoStack = inApp.getUndoStack();
+               UndoStack undoStack = _app.getUndoStack();
                mainPanel.add(new JLabel(I18nManager.getText("dialog.undo.pretext")), BorderLayout.NORTH);
 
                String[] undoActions = new String[undoStack.size()];
                for (int i=0; i<undoStack.size(); i++)
                {
-                       undoActions[i] = undoStack.elementAt(undoStack.size()-1-i).getDescription();
+                       undoActions[i] = undoStack.getOperationAt(undoStack.size()-1-i).getDescription();
                }
                _actionList = new JList<String>(undoActions);
                _actionList.setSelectionMode(ListSelectionModel.SINGLE_INTERVAL_SELECTION);
old mode 100755 (executable)
new mode 100644 (file)
old mode 100755 (executable)
new mode 100644 (file)
diff --git a/tim/prune/gui/images/pause.png b/tim/prune/gui/images/pause.png
new file mode 100644 (file)
index 0000000..b9f48da
Binary files /dev/null and b/tim/prune/gui/images/pause.png differ
diff --git a/tim/prune/gui/images/play.png b/tim/prune/gui/images/play.png
new file mode 100644 (file)
index 0000000..38abef7
Binary files /dev/null and b/tim/prune/gui/images/play.png differ
diff --git a/tim/prune/gui/images/points_connected.gif b/tim/prune/gui/images/points_connected.gif
deleted file mode 100644 (file)
index e6091c1..0000000
Binary files a/tim/prune/gui/images/points_connected.gif and /dev/null differ
diff --git a/tim/prune/gui/images/points_connected.png b/tim/prune/gui/images/points_connected.png
new file mode 100644 (file)
index 0000000..1891af0
Binary files /dev/null and b/tim/prune/gui/images/points_connected.png differ
diff --git a/tim/prune/gui/images/points_disconnected.gif b/tim/prune/gui/images/points_disconnected.gif
deleted file mode 100644 (file)
index 1015169..0000000
Binary files a/tim/prune/gui/images/points_disconnected.gif and /dev/null differ
diff --git a/tim/prune/gui/images/points_disconnected.png b/tim/prune/gui/images/points_disconnected.png
new file mode 100644 (file)
index 0000000..37f2c0f
Binary files /dev/null and b/tim/prune/gui/images/points_disconnected.png differ
diff --git a/tim/prune/gui/images/points_hidden.png b/tim/prune/gui/images/points_hidden.png
new file mode 100644 (file)
index 0000000..452015c
Binary files /dev/null and b/tim/prune/gui/images/points_hidden.png differ
diff --git a/tim/prune/gui/images/rewind.png b/tim/prune/gui/images/rewind.png
new file mode 100644 (file)
index 0000000..bc0fdbd
Binary files /dev/null and b/tim/prune/gui/images/rewind.png differ
index 459b140f2c0108b9adf35805bf1b0451d3f80811..63dc684c346900b3ca1cedda3c3d307a9693149d 100644 (file)
@@ -40,7 +40,6 @@ public class DiskTileCacher implements Runnable
                _url = inUrl;
                _file = inFile;
                _observer = inObserver;
-               new Thread(this).start();
        }
 
        /**
@@ -98,7 +97,7 @@ public class DiskTileCacher implements Runnable
                // Start a new thread to load the image if necessary
                if ((dir.exists() || dir.mkdirs()) && dir.canWrite())
                {
-                       new DiskTileCacher(inUrl, tileFile, inObserver);
+                       new Thread(new DiskTileCacher(inUrl, tileFile, inObserver)).start();
                        return true;
                }
                return false; // couldn't write the file
index 7a6bce81a5dc285050a8a1e97a5ed3db4b84db37..42215209ba3bfccf599fa2d9c000ebe1f89cf49f 100644 (file)
@@ -11,6 +11,7 @@ import java.awt.FontMetrics;
 import java.awt.Graphics;
 import java.awt.Graphics2D;
 import java.awt.Image;
+import java.awt.RenderingHints;
 import java.awt.event.ActionEvent;
 import java.awt.event.ActionListener;
 import java.awt.event.ItemEvent;
@@ -59,6 +60,7 @@ import tim.prune.function.compress.MarkPointsInRectangleFunction;
 import tim.prune.function.edit.FieldEdit;
 import tim.prune.function.edit.FieldEditList;
 import tim.prune.gui.IconManager;
+import tim.prune.gui.TripleStateCheckBox;
 import tim.prune.gui.colour.PointColourer;
 import tim.prune.tips.TipManager;
 
@@ -97,7 +99,7 @@ public class MapCanvas extends JPanel implements MouseListener, MouseMotionListe
        /** Checkbox for autopan */
        private JCheckBox _autopanCheckBox = null;
        /** Checkbox for connecting track points */
-       private JCheckBox _connectCheckBox = null;
+       private TripleStateCheckBox _connectCheckBox = null;
        /** Checkbox for enable edit mode */
        private JCheckBox _editmodeCheckBox = null;
        /** Right-click popup menu */
@@ -241,8 +243,11 @@ public class MapCanvas extends JPanel implements MouseListener, MouseMotionListe
                _autopanCheckBox.setFocusable(false); // stop button from stealing keyboard focus
                _topPanel.add(_autopanCheckBox);
                // Add checkbox button for connecting points or not
-               _connectCheckBox = new JCheckBox(IconManager.getImageIcon(IconManager.POINTS_DISCONNECTED_BUTTON), true);
-               _connectCheckBox.setSelectedIcon(IconManager.getImageIcon(IconManager.POINTS_CONNECTED_BUTTON));
+               _connectCheckBox = new TripleStateCheckBox();
+               _connectCheckBox.setIcon(0, IconManager.getImageIcon(IconManager.POINTS_CONNECTED_BUTTON));
+               _connectCheckBox.setIcon(1, IconManager.getImageIcon(IconManager.POINTS_DISCONNECTED_BUTTON));
+               _connectCheckBox.setIcon(2, IconManager.getImageIcon(IconManager.POINTS_HIDDEN_BUTTON));
+               _connectCheckBox.setCurrentState(0);
                _connectCheckBox.setOpaque(false);
                _connectCheckBox.setToolTipText(I18nManager.getText("menu.map.connect"));
                _connectCheckBox.addItemListener(itemListener);
@@ -509,8 +514,10 @@ public class MapCanvas extends JPanel implements MouseListener, MouseMotionListe
                        _mapImage = new BufferedImage(getWidth(), getHeight(), BufferedImage.TYPE_INT_RGB);
                }
 
-               // Clear map
                Graphics g = _mapImage.getGraphics();
+               // Set antialiasing according to config
+               ((Graphics2D) g).setRenderingHint(RenderingHints.KEY_ANTIALIASING,
+                       Config.getConfigBoolean(Config.KEY_ANTIALIAS) ? RenderingHints.VALUE_ANTIALIAS_ON : RenderingHints.VALUE_ANTIALIAS_OFF);
                // Clear to background
                g.setColor(Config.getColourScheme().getColour(ColourScheme.IDX_BACKGROUND));
                g.fillRect(0, 0, getWidth(), getHeight());
@@ -678,7 +685,9 @@ public class MapCanvas extends JPanel implements MouseListener, MouseMotionListe
                // draw track points
                inG.setColor(pointColour);
                int prevX = -1, prevY = -1;
-               boolean connectPoints = _connectCheckBox.isSelected();
+               final int connectState = _connectCheckBox.getCurrentState();
+               final boolean drawLines = (connectState % 2) == 0; // 0 or 2
+               final boolean drawPoints = (connectState <= 1);    // 0 or 1
                boolean prevPointVisible = false, currPointVisible = false;
                boolean anyWaypoints = false;
                boolean isWaypoint = false;
@@ -696,7 +705,7 @@ public class MapCanvas extends JPanel implements MouseListener, MouseMotionListe
                        anyWaypoints = anyWaypoints || isWaypoint;
                        if (!isWaypoint)
                        {
-                               if (currPointVisible || prevPointVisible)
+                               if ((currPointVisible || prevPointVisible) && drawPoints)
                                {
                                        // For track points, work out which colour to use
                                        if (_track.getPoint(i).getDeleteFlag()) {
@@ -721,7 +730,7 @@ public class MapCanvas extends JPanel implements MouseListener, MouseMotionListe
                                }
 
                                // Connect track points if either of them are visible
-                               if (connectPoints && !(prevX == -1 && prevY == -1)
+                               if (drawLines && !(prevX == -1 && prevY == -1)
                                 && !_track.getPoint(i).getSegmentStart())
                                {
                                        inG.drawLine(prevX, prevY, px, py);
index 88ab85aa5e11eb4f45b22c4a0e4cc20ce7708a03..b7a08fcf8d7d19b2314129ed66900b06bc01f460 100644 (file)
@@ -84,13 +84,19 @@ public abstract class MapSource
        {
                if (inUrl == null || inUrl.equals("")) {return null;}
                String urlstr = inUrl;
+               boolean urlOk = false;
+
                // check prefix
-               try {
-                       new URL(urlstr.replace('[', 'w').replace(']', 'w'));
-                       // There's a warning that this URL object isn't used, but it's enough to know the parse
-                       // was successful without an exception being thrown.
+               try
+               {
+                       urlOk = new URL(urlstr.replace('[', 'w').replace(']', 'w')) != null;
                }
                catch (MalformedURLException e)
+               {
+                       urlOk = false;
+               }
+
+               if (!urlOk)
                {
                        // fail if protocol specified
                        if (urlstr.indexOf("://") >= 0) {return null;}
@@ -102,7 +108,8 @@ public abstract class MapSource
                        urlstr = urlstr + "/";
                }
                // Validate current url, return null if not ok
-               try {
+               try
+               {
                        URL url = new URL(urlstr.replace('[', 'w').replace(']', 'w'));
                        // url host must contain a dot
                        if (url.getHost().indexOf('.') < 0) {return null;}
index b82fd4e7a23e197a80120eb6d2b2e0c7a854f409..e324af1a029114e0e726f19bf3baabb8448f096f 100644 (file)
@@ -43,8 +43,8 @@ public abstract class MapSourceLibrary
                _sourceList.add(new OsmMapSource("Reitkarte", "http://topo[234].wanderreitkarte.de/topo/"));
                _sourceList.add(new MffMapSource("Mapsforfree", "http://maps-for-free.com/layer/relief/", "jpg",
                        "http://maps-for-free.com/layer/water/", "gif", 11));
-               _sourceList.add(new OsmMapSource("Hikebikemap", "http://toolserver.org/tiles/hikebike/",
-                       "http://toolserver.org/~cmarqu/hill/", 18));
+               _sourceList.add(new OsmMapSource("Hikebikemap", "http://[abc].tiles.wmflabs.org/hikebike/",
+                       "http://[abc].tiles.wmflabs.org/hillshading/", 18));
                _sourceList.add(new OsmMapSource("Openseamap", "http://tile.openstreetmap.org/",
                        "http://tiles.openseamap.org/seamark/", 18));
        }
index 0dcabcb66785b06f1dd9730fc7f3a7025e34d89e..b2d0d0df7020c36964f692a4eb1378768b58abee 100644 (file)
@@ -4,10 +4,13 @@ import java.awt.Color;
 import java.awt.Dimension;
 import java.awt.FlowLayout;
 import java.awt.Graphics;
+import java.awt.Graphics2D;
+import java.awt.RenderingHints;
 import java.awt.event.ActionEvent;
 import java.awt.event.ActionListener;
 import java.awt.event.MouseEvent;
 import java.awt.event.MouseListener;
+
 import javax.swing.JLabel;
 import javax.swing.JMenuItem;
 import javax.swing.JPopupMenu;
@@ -86,6 +89,9 @@ public class ProfileChart extends GenericDisplay implements MouseListener
        public void paint(Graphics g)
        {
                super.paint(g);
+               // Set antialiasing depending on Config
+               ((Graphics2D) g).setRenderingHint(RenderingHints.KEY_ANTIALIASING,
+                       Config.getConfigBoolean(Config.KEY_ANTIALIAS) ? RenderingHints.VALUE_ANTIALIAS_ON : RenderingHints.VALUE_ANTIALIAS_OFF);
                ColourScheme colourScheme = Config.getColourScheme();
                paintBackground(g, colourScheme);
                if (_track != null && _track.getNumPoints() > 0)
index 0d94f038479b829f3393ffc1fcbfc76fc795954c..4d06a2728ccfb42d41a83a2486bb98b35b5546ee 100644 (file)
@@ -2,12 +2,14 @@ package tim.prune.jpeg;
 
 import java.io.File;
 
+import com.drew.imaging.ImageMetadataReader;
 import com.drew.lang.Rational;
 import com.drew.metadata.Directory;
 import com.drew.metadata.Metadata;
-import com.drew.metadata.MetadataException;
-import com.drew.metadata.exif.ExifDirectory;
+import com.drew.metadata.exif.ExifSubIFDDirectory;
+import com.drew.metadata.exif.ExifIFD0Directory;
 import com.drew.metadata.exif.ExifReader;
+import com.drew.metadata.exif.ExifThumbnailDirectory;
 import com.drew.metadata.exif.GpsDirectory;
 
 /**
@@ -31,57 +33,52 @@ public class ExternalExifLibrary implements ExifLibrary
                // Read exif data from picture
                try
                {
-                       Metadata metadata = new Metadata();
-                       new ExifReader(inFile).extract(metadata);
+                       Metadata metadata = ImageMetadataReader.readMetadata(inFile);
                        if (metadata.containsDirectory(GpsDirectory.class))
                        {
                                Directory gpsdir = metadata.getDirectory(GpsDirectory.class);
-                               if (gpsdir.containsTag(GpsDirectory.TAG_GPS_LATITUDE)
-                                       && gpsdir.containsTag(GpsDirectory.TAG_GPS_LONGITUDE)
-                                       && gpsdir.containsTag(GpsDirectory.TAG_GPS_LATITUDE_REF)
-                                       && gpsdir.containsTag(GpsDirectory.TAG_GPS_LONGITUDE_REF))
+                               if (gpsdir.containsTag(GpsDirectory.TAG_LATITUDE)
+                                       && gpsdir.containsTag(GpsDirectory.TAG_LONGITUDE)
+                                       && gpsdir.containsTag(GpsDirectory.TAG_LATITUDE_REF)
+                                       && gpsdir.containsTag(GpsDirectory.TAG_LONGITUDE_REF))
                                {
-                                       data.setLatitudeRef(gpsdir.getString(GpsDirectory.TAG_GPS_LATITUDE_REF));
-                                       Rational[] latRats = gpsdir.getRationalArray(GpsDirectory.TAG_GPS_LATITUDE);
+                                       data.setLatitudeRef(gpsdir.getString(GpsDirectory.TAG_LATITUDE_REF));
+                                       Rational[] latRats = gpsdir.getRationalArray(GpsDirectory.TAG_LATITUDE);
                                        double seconds = ExifGateway.convertToPositiveValue(latRats[2].getNumerator(), latRats[2].getDenominator());
                                        data.setLatitude(new double[] {latRats[0].doubleValue(),
                                                latRats[1].doubleValue(), seconds});
-                                       data.setLongitudeRef(gpsdir.getString(GpsDirectory.TAG_GPS_LONGITUDE_REF));
-                                       Rational[] lonRats = gpsdir.getRationalArray(GpsDirectory.TAG_GPS_LONGITUDE);
+                                       data.setLongitudeRef(gpsdir.getString(GpsDirectory.TAG_LONGITUDE_REF));
+                                       Rational[] lonRats = gpsdir.getRationalArray(GpsDirectory.TAG_LONGITUDE);
                                        seconds = ExifGateway.convertToPositiveValue(lonRats[2].getNumerator(), lonRats[2].getDenominator());
                                        data.setLongitude(new double[] {lonRats[0].doubleValue(),
                                                lonRats[1].doubleValue(), seconds});
                                }
 
                                // Altitude (if present)
-                               if (gpsdir.containsTag(GpsDirectory.TAG_GPS_ALTITUDE) && gpsdir.containsTag(GpsDirectory.TAG_GPS_ALTITUDE_REF))
+                               if (gpsdir.containsTag(GpsDirectory.TAG_ALTITUDE) && gpsdir.containsTag(GpsDirectory.TAG_ALTITUDE_REF))
                                {
-                                       data.setAltitude(gpsdir.getRational(GpsDirectory.TAG_GPS_ALTITUDE).intValue());
-                                       byte altRef = (byte) gpsdir.getInt(GpsDirectory.TAG_GPS_ALTITUDE_REF);
+                                       data.setAltitude(gpsdir.getRational(GpsDirectory.TAG_ALTITUDE).intValue());
+                                       byte altRef = (byte) gpsdir.getInt(GpsDirectory.TAG_ALTITUDE_REF);
                                        data.setAltitudeRef(altRef);
                                }
 
-                               try
+                               // Timestamp and datestamp (if present)
+                               final int TAG_DATESTAMP = 0x001d;
+                               if (gpsdir.containsTag(GpsDirectory.TAG_TIME_STAMP) && gpsdir.containsTag(TAG_DATESTAMP))
                                {
-                                       // Timestamp and datestamp (if present)
-                                       final int TAG_GPS_DATESTAMP = 0x001d;
-                                       if (gpsdir.containsTag(GpsDirectory.TAG_GPS_TIME_STAMP) && gpsdir.containsTag(TAG_GPS_DATESTAMP))
-                                       {
-                                               Rational[] times = gpsdir.getRationalArray(GpsDirectory.TAG_GPS_TIME_STAMP);
-                                               data.setGpsTimestamp(new int[] {times[0].intValue(), times[1].intValue(),
-                                                       times[2].intValue()});
-                                               Rational[] dates = gpsdir.getRationalArray(TAG_GPS_DATESTAMP);
-                                               if (dates != null) {
-                                                       data.setGpsDatestamp(new int[] {dates[0].intValue(), dates[1].intValue(), dates[2].intValue()});
-                                               }
+                                       Rational[] times = gpsdir.getRationalArray(GpsDirectory.TAG_TIME_STAMP);
+                                       data.setGpsTimestamp(new int[] {times[0].intValue(), times[1].intValue(),
+                                               times[2].intValue()});
+                                       Rational[] dates = gpsdir.getRationalArray(TAG_DATESTAMP);
+                                       if (dates != null) {
+                                               data.setGpsDatestamp(new int[] {dates[0].intValue(), dates[1].intValue(), dates[2].intValue()});
                                        }
                                }
-                               catch (MetadataException me) {} // ignore, use other tags instead
 
                                // Image bearing (if present)
-                               if (gpsdir.containsTag(GpsDirectory.TAG_GPS_IMG_DIRECTION) && gpsdir.containsTag(GpsDirectory.TAG_GPS_IMG_DIRECTION_REF))
+                               if (gpsdir.containsTag(GpsDirectory.TAG_IMG_DIRECTION) && gpsdir.containsTag(GpsDirectory.TAG_IMG_DIRECTION_REF))
                                {
-                                       Rational bearing = gpsdir.getRational(GpsDirectory.TAG_GPS_IMG_DIRECTION);
+                                       Rational bearing = gpsdir.getRational(GpsDirectory.TAG_IMG_DIRECTION);
                                        if (bearing != null) {
                                                data.setBearing(bearing.doubleValue());
                                        }
@@ -89,30 +86,39 @@ public class ExternalExifLibrary implements ExifLibrary
                        }
 
                        // Tags from Exif directory
-                       if (metadata.containsDirectory(ExifDirectory.class))
+                       if (metadata.containsDirectory(ExifSubIFDDirectory.class))
                        {
-                               Directory exifdir = metadata.getDirectory(ExifDirectory.class);
+                               Directory exifdir = metadata.getDirectory(ExifSubIFDDirectory.class);
 
                                // Take time and date from exif tags
-                               if (exifdir.containsTag(ExifDirectory.TAG_DATETIME_ORIGINAL)) {
-                                       data.setOriginalTimestamp(exifdir.getString(ExifDirectory.TAG_DATETIME_ORIGINAL));
+                               if (exifdir.containsTag(ExifSubIFDDirectory.TAG_DATETIME_ORIGINAL)) {
+                                       data.setOriginalTimestamp(exifdir.getString(ExifSubIFDDirectory.TAG_DATETIME_ORIGINAL));
                                }
                                // Also take "digitized" timestamp
-                               if (exifdir.containsTag(ExifDirectory.TAG_DATETIME_DIGITIZED)) {
-                                       data.setDigitizedTimestamp(exifdir.getString(ExifDirectory.TAG_DATETIME_DIGITIZED));
+                               if (exifdir.containsTag(ExifSubIFDDirectory.TAG_DATETIME_DIGITIZED)) {
+                                       data.setDigitizedTimestamp(exifdir.getString(ExifSubIFDDirectory.TAG_DATETIME_DIGITIZED));
                                }
+                       }
+                       if (metadata.containsDirectory(ExifIFD0Directory.class))
+                       {
+                               Directory exifdir = metadata.getDirectory(ExifIFD0Directory.class);
 
                                // Photo rotation code
-                               if (exifdir.containsTag(ExifDirectory.TAG_ORIENTATION)) {
-                                       data.setOrientationCode(exifdir.getInt(ExifDirectory.TAG_ORIENTATION));
+                               if (exifdir.containsTag(ExifIFD0Directory.TAG_ORIENTATION)) {
+                                       data.setOrientationCode(exifdir.getInt(ExifIFD0Directory.TAG_ORIENTATION));
                                        // NOTE: this presumably takes the _last_ orientation value found, not the first.
                                }
+                       }
+
+                       if (metadata.containsDirectory(ExifThumbnailDirectory.class))
+                       {
+                               ExifThumbnailDirectory exifdir = metadata.getDirectory(ExifThumbnailDirectory.class);
 
-                               // Thumbnail
-                               if (exifdir.containsTag(ExifDirectory.TAG_THUMBNAIL_DATA))
+                               // TODO: Check this thumbnail stuff
+                               if (exifdir.hasThumbnailData())
                                {
-                                       // Make a copy of the byte data rather than keeping a reference to extracted array
-                                       byte[] tdata = exifdir.getByteArray(ExifDirectory.TAG_THUMBNAIL_DATA);
+                                       // Make a copy of the byte data
+                                       byte[] tdata = exifdir.getThumbnailData();
                                        byte[] thumb = new byte[tdata.length];
                                        System.arraycopy(tdata, 0, thumb, 0, tdata.length);
                                        data.setThumbnailImage(thumb);
index 35ef53fbec1ac0a7f2593674ba981d57e98cf4d4..ef735f77cf4def3ca90abc7ddf7ab37e68a1c224 100644 (file)
@@ -12,7 +12,7 @@ menu.track=Baan
 menu.track.undo=Herroep
 menu.track.clearundo=Maak herroep lys skoon
 menu.track.markrectangle=Merk punte
-menu.track.deletemarked=Vee gemerkde punte uit
+function.deletemarked=Vee gemerkde punte uit
 menu.range=Reeks
 menu.range.all=Selekteer alles
 menu.range.none=Selekteer niks
index 2ac7ca669bd2516d7c579081c718d0c98879535a..54093a8f5fd81cade418c59f36cc058a27b68d01 100644 (file)
@@ -12,7 +12,7 @@ menu.track=Stopa
 menu.track.undo=Undo
 menu.track.clearundo=Vypr\u00e1zdnit pam\u011b\u0165 undo
 menu.track.markrectangle=Ozna\u010dit body v obd\u00e9ln\u00edku
-menu.track.deletemarked=Smazat ozna\u010den\u00e9 body
+function.deletemarked=Smazat ozna\u010den\u00e9 body
 function.rearrangewaypoints=P\u0159euspo\u0159\u00e1dat z\u00e1jmov\u00e9 body
 menu.range=Rozmez\u00ed
 menu.range.all=Vybrat v\u0161e
index 8bcf9caca5acd628411c3c7e03ec235bc798a658..e1d29ae25c2edf21bfa7e63643c545b34fe70f15 100644 (file)
@@ -9,7 +9,7 @@ menu.file.save=Gem som tekst
 menu.file.exit=Afslut
 menu.track.undo=Fortryd
 menu.track.clearundo=Nulstil fortrydelsesliste
-menu.track.deletemarked=Slet markerede punkter
+function.deletemarked=Slet markerede punkter
 function.rearrangewaypoints=Omorganis\u00e9r waypoints
 dialog.rearrange.tonearest=Hvert waypoint til n\u00e6rmeste nabo
 menu.range=Omr\u00e5de
index a85515eb3756491ee7b70813a6b0bb5d526183f8..4169c917147a2ba8f4d7f4c238a9bc00d1dbbe96 100644 (file)
@@ -12,7 +12,7 @@ menu.track=Track
 menu.track.undo=R\u00fcckg\u00e4ngig
 menu.track.clearundo=Liste der letzten \u00c4nderungen l\u00f6schen
 menu.track.markrectangle=Punkte im Viereck markieren
-menu.track.deletemarked=Markierte Punkte l\u00f6schen
+function.deletemarked=Markierte Punkte l\u00f6schen
 function.rearrangewaypoints=Wegpunkte neu anordnen
 menu.range=Bereich
 menu.range.all=Alles markieren
@@ -39,6 +39,7 @@ menu.view.browser.yahoo=Yahoo Maps
 menu.view.browser.bing=Bing Maps
 menu.settings=Einstellungen
 menu.settings.onlinemode=Karten aus dem Internet laden
+menu.settings.antialias=Kantengl\u00e4ttung an
 menu.settings.autosave=Einstellungen automatisch speichern
 menu.help=Hilfe
 # Popup menu for map
@@ -86,6 +87,7 @@ function.exportsvg=SVG exportieren
 function.exportimage=Bild exportieren
 function.editwaypointname=Namen des Punkts bearbeiten
 function.compress=Track komprimieren
+function.marklifts=Bergbahnen markieren
 function.deleterange=Bereich l\u00f6schen
 function.croptrack=Track zuschneiden
 function.interpolate=Punkte interpolieren
@@ -102,6 +104,7 @@ function.distances=Entfernungen
 function.fullrangedetails=Zus\u00e4tzliche Bereichdetails
 function.estimatetime=Zeit absch\u00e4tzen
 function.learnestimationparams=Zeitparameter erlernen
+function.autoplay=Track abspielen
 function.setmapbg=Karte Hintergrund setzen
 function.setpaths=Programmpfade setzen
 function.selectsegment=Aktuellen Abschnitt markieren
@@ -112,7 +115,9 @@ function.uploadgpsies=Track zu GPSies.com hochladen
 function.lookupsrtm=H\u00f6hendaten von SRTM nachschlagen
 function.downloadsrtm=SRTM Dateien herunterladen
 function.getwikipedia=Wikipediaartikel in der N\u00e4he nachschlagen
-function.searchwikipedianames=Wikipedia mit Name durchsuchen
+function.searchwikipedianames=Wikipedia nach Namen durchsuchen
+function.searchopencachingde=OpenCaching.de durchsuchen
+function.mapillary=Mapillary nach Fotos durchsuchen
 function.downloadosm=OSM-Daten f\u00fcr dieses Gebiet herunterladen
 function.duplicatepoint=Punkt verdoppeln
 function.setcolours=Farben einstellen
@@ -377,9 +382,11 @@ dialog.gpsies.activity.motorbiking=Motorradfahren
 dialog.gpsies.activity.snowshoe=Schneeschuhwandern
 dialog.gpsies.activity.sailing=Segeln
 dialog.gpsies.activity.skating=Inline-Skating
+dialog.mapillary.nonefound=Keine Fotos gefunden
 dialog.wikipedia.column.name=Artikelname
 dialog.wikipedia.column.distance=Entfernung
 dialog.wikipedia.nonefound=Keine Punkte gefunden
+dialog.geocaching.nonefound=Keine Punkte gefunden
 dialog.correlate.notimestamps=Die Punkte enthalten keine Zeitangaben, deshalb k\u00f6nnen die Fotos nicht zugeordnet werden.
 dialog.correlate.nouncorrelatedphotos=Alle Fotos sind schon zugeordnet.\nWollen Sie trotzdem fortfahren?
 dialog.correlate.nouncorrelatedaudios=Alle Audiodateien sind schon zugeordnet.\nWollen Sie trotzdem fortfahren?
@@ -588,6 +595,11 @@ dialog.deletebydate.column.keep=Behalten
 dialog.deletebydate.column.delete=L\u00f6schen
 dialog.setaltitudetolerance.text.metres=Mindestabweichung (Meter) f\u00fcr H\u00f6henunterschiede
 dialog.setaltitudetolerance.text.feet=Mindestabweichung (Feet) f\u00fcr H\u00f6henunterschiede
+dialog.autoplay.duration=Abspieldauer (Sek)
+dialog.autoplay.usetimestamps=Zeitstempeln verwenden
+dialog.autoplay.rewind=Zum Anfang
+dialog.autoplay.pause=Pause
+dialog.autoplay.play=Abspielen
 
 # 3d window
 dialog.3d.title=GpsPrune-3D-Ansicht
@@ -753,6 +765,7 @@ fieldname.duration=Zeitdauer
 fieldname.speed=Geschwindigkeit
 fieldname.verticalspeed=Vertikale Geschwindigkeit
 fieldname.description=Beschreibung
+fieldname.mediafilename=Foto- / Audioname
 
 # Measurement units
 units.original=Original
@@ -790,6 +803,11 @@ logic.or=oder
 url.googlemaps=maps.google.de
 wikipedia.lang=de
 openweathermap.lang=de
+webservice.peakfinder=Peakfinder.org \u00f6ffnen
+webservice.geohack=Geohack-Seite \u00f6ffnen
+webservice.panoramio=Panoramio Karte \u00f6ffnen
+webservice.opencachingcom=Opencaching.com \u00f6ffnen
+webservice.opencachingcom.lang=de
 
 # Cardinals for 3d plots
 cardinal.n=N
index a0bad3e91ba69fbc1253ebe882b71713057fbf99..d4e0e1ef89efa09cd0f7f216b44a4ba2a5073561 100644 (file)
@@ -12,7 +12,7 @@ menu.track=Track
 menu.track.undo=Undo
 menu.track.clearundo=Undo-Liste l\u00f6sche
 menu.track.markrectangle=P\u00fcnkte inem Viereck markiere
-menu.track.deletemarked=Markierte P\u00fcnkte l\u00f6sche
+function.deletemarked=Markierte P\u00fcnkte l\u00f6sche
 function.rearrangewaypoints=Waypoints reorganisiere
 menu.range=Beriich
 menu.range.all=Alles selektiere
@@ -38,6 +38,7 @@ menu.view.showsidebars=Seiteleischten aazeige
 menu.view.browser=Karte inem Browser
 menu.settings=Iistellige
 menu.settings.onlinemode=Karten uusem Internet lade
+menu.settings.antialias=Kantegl\u00e4ttig aa
 menu.settings.autosave=Iistellige automatisch speichere
 menu.help=Hilfe
 # Popup menu for map
@@ -85,6 +86,7 @@ function.exportsvg=SVG exportier\u00e4
 function.exportimage=Bild exportier\u00e4
 function.editwaypointname=Waypoint Namen editiere
 function.compress=Track komprimier\u00e4
+function.marklifts=Bergb\u00e4hnli markiere
 function.deleterange=Beriich l\u00f6sche
 function.croptrack=Track zuschniide
 function.deletebydate=P\u00fcnkte na Datum l\u00f6sche
@@ -100,6 +102,7 @@ function.distances=Entf\u00e4rnige
 function.fullrangedetails=Zues\u00e4tzlichi Beriichinfos
 function.estimatetime=Ziit absch\u00e4tze
 function.learnestimationparams=Ziitparameter erlerne
+function.autoplay=Track abschpiel\u00e4
 function.setmapbg=Karte Hintegrund setz\u00e4
 function.selectsegment=Aktuelli Segm\u00e4nt selektiere
 function.splitsegments=In Tracksegm\u00e4nte schniide
@@ -109,7 +112,9 @@ function.uploadgpsies=Date zum Gpsies uufalad\u00e4
 function.lookupsrtm=H\u00f6hendate vonem SRTM hole
 function.downloadsrtm=SRTM Files abalade
 function.getwikipedia=Im Wikipedia in dr N\u00f6chi naaluege
-function.searchwikipedianames=Wikipedia mit Name durasueche
+function.searchwikipedianames=Wikipedia nachem Namen durasueche
+function.searchopencachingde=OpenCaching.de durasueche
+function.mapillary=Mapillary nach F\u00f6telis durasueche
 function.downloadosm=OSM-Date f\u00fcr dere Gebiet abalad\u00e4
 function.duplicatepoint=Punkt verdoppl\u00e4
 function.correlatephotos=F\u00f6telis korrelier\u00e4
@@ -275,13 +280,13 @@ dialog.confirmcutandmove.text=Diese Daten enthalte Ziitst\u00e4mpel Informatione
 dialog.interpolate.parameter.text=Aazahl P\u00fcnkte zum inn\u00e4tue zw\u00fcschet den selektierten P\u00fcnkten
 dialog.interpolate.betweenwaypoints=Zw\u00fcschet d Waypoints interpoliere?
 dialog.undo.title=Undo Operation(e)
-dialog.undo.pretext=Selektiere die Operatione die r\u00fcckg\u00e4ngig gmacht s\u00f6llti werde.
+dialog.undo.pretext=Welli Operatione s\u00f6llet r\u00fcckg\u00e4ngig gmacht werde?
 dialog.undo.none.title=Undo n\u00f6d m\u00f6glich
 dialog.undo.none.text=Keini Operatione k\u00f6nne r\u00fcckg\u00e4ngig gmacht werde.
 dialog.clearundo.title=Undo-Liste l\u00f6sch\u00e4
 dialog.clearundo.text=Sind Sie sicher, Sie wend die Undo-Liste l\u00f6sche?\nAlle Undo Infos werdet verlore gah!
 dialog.pointedit.title=Punkt editier\u00e4
-dialog.pointedit.intro=W\u00e4hlet Sie j\u00e4den F\u00e4ld uus, um den Wert z'seh und z'\u00e4ndere
+dialog.pointedit.intro=W\u00e4hlet Sie j\u00e4des F\u00e4ld uus, um den Wert z'seh und z'\u00e4ndere
 dialog.pointedit.table.field=F\u00e4ld
 dialog.pointedit.nofield=Kei F\u00e4ld uusgew\u00e4hlt
 dialog.pointedit.table.value=Wert
@@ -362,7 +367,7 @@ dialog.gpsies.nonefound=Kei Tracks gfunde
 dialog.gpsies.username=Gpsies Username
 dialog.gpsies.password=Gpsies Passwort
 dialog.gpsies.keepprivate=Track privat halte
-dialog.gpsies.confirmopenpage=Websiite f\u00fcrn uufageladenen Track \u00f6ffne?
+dialog.gpsies.confirmopenpage=Websiite f\u00fcrn uufagladenen Track \u00f6ffne?
 dialog.gpsies.activities=Aktivit\u00e4ten
 dialog.gpsies.activity.trekking=Wandere
 dialog.gpsies.activity.walking=Z'Fuess gah
@@ -372,9 +377,11 @@ dialog.gpsies.activity.motorbiking=Motorrad
 dialog.gpsies.activity.snowshoe=Schneeschuh
 dialog.gpsies.activity.sailing=Segle
 dialog.gpsies.activity.skating=Inline-Skate
+dialog.mapillary.nonefound=Kei F\u00f6telis gfunde
 dialog.wikipedia.column.name=Artikelname
 dialog.wikipedia.column.distance=Entf\u00e4rnig
 dialog.wikipedia.nonefound=Kei Wiki-Iitr\u00e4ge gfunde
+dialog.geocaching.nonefound=Kei Cäches gfunde
 dialog.correlate.notimestamps=Es h\u00e4t kei Ziitst\u00e4mpel inem Track inn\u00e4, so s'isch n\u00f6d m\u00f6glech die F\u00f6telis zu korrelier\u00e4.
 dialog.correlate.nouncorrelatedphotos=Alle F\u00f6telis sin scho korreliert.\nWend Sie trotzdem fortsetz\u00e4?
 dialog.correlate.nouncorrelatedaudios=Alle Audios sin scho korreliert.\nWend Sie trotzdem fortsetz\u00e4?
@@ -433,7 +440,7 @@ dialog.deletemarked.nonefound=Kei P\u00fcnkte h\u00e4tte gel\u00f6scht werde k\u
 dialog.pastecoordinates.desc=G\u00e4bet Sie hier die Koordinaten inn\u00e4
 dialog.pastecoordinates.coords=Koordinate
 dialog.pastecoordinates.nothingfound=Pr\u00fcefet Sie die Koordinate und versuechet nomal
-dialog.help.help=Bitte lueg na\n http://gpsprune.activityworkshop.net/\nf\u00fcr wiitere Information und Benutzeraaleitige.
+dialog.help.help=Lueget Sie na\n http://gpsprune.activityworkshop.net/\nf\u00fcr wiitere Information und Benutzeraaleitige.
 dialog.about.version=Version
 dialog.about.build=Build
 dialog.about.summarytext1=GpsPrune isch s Programm f\u00fcrs Lade, Darstelle und Editiere vo Date von GPS Ger\u00e4te.
@@ -477,7 +484,7 @@ dialog.keys.intro=Aastatt d'Muus k\u00f6nnet Sie diese Tastekombinationen nutze
 dialog.keys.keylist=<table><tr><td>Pfiil Taste</td><td>Karte verschiebe</td></tr><tr><td>Strg + links, r\u00e4chts Pfiil</td><td>Vorherigi oder n\u00f6chsti Punkt markiere</td></tr><tr><td>Strg + uuf, aba Pfiil</td><td>Ii- oder Uusezoome</td></tr><tr><td>Strg + Bild uuf, ab</td><td>Vorherigi oder n\u00f6chsti Segm\u00e4nt markiere</td></tr><tr><td>Strg + Pos1, \u00c4nde</td><td>Erschti oder letschti Punkt markiere</td></tr><tr><td>Entf</td><td>Aktuelli Punkt l\u00f6sche</td></tr></table>
 dialog.keys.normalmodifier=Strg
 dialog.keys.macmodifier=Kommando
-dialog.saveconfig.desc=Die folgendi Iinstellige k\u00f6nne gspeicheret werde :
+dialog.saveconfig.desc=Die folgendi Iistellige k\u00f6nne gspeicheret werde :
 dialog.saveconfig.prune.trackdirectory=Trackverzeichnis
 dialog.saveconfig.prune.photodirectory=F\u00f6teliverzeichnis
 dialog.saveconfig.prune.languagecode=Sprochecode (DE_ch)
@@ -526,7 +533,7 @@ dialog.colourer.type.bygradient=Nach Gef\u00e4lle
 dialog.colourer.type.bydate=Nach Datum
 dialog.colourer.start=Aafangsfarb
 dialog.colourer.end=Zielfarb
-dialog.colourer.maxcolours=Maximal Anzahl Farbe
+dialog.colourer.maxcolours=Maximal Aazahl Farbe
 dialog.setlanguage.firstintro=Sie k\u00f6nnet entweder eini vo den iigebouti Sproche<p>oder ne Text-Datei uusw\u00e4hle.
 dialog.setlanguage.secondintro=Sie m\u00fcnt Ihri Iistellige speichere und dann<p>GpsPrune wieder neustarte um die Sproch z'\u00e4ndere.
 dialog.setlanguage.language=Sproch
@@ -582,7 +589,12 @@ dialog.deletebydate.nodate=Ohni Ziitaagab
 dialog.deletebydate.column.keep=Behalte
 dialog.deletebydate.column.delete=L\u00f6sche
 dialog.setaltitudetolerance.text.metres=Mindeschtabweichig (Meter) f\u00fcr H\u00f6chiunterschied
-dialog.setaltitudetolerance.text.feet=Mindeschtabweichig (Feet) f\u00fcr H\u00f6chinunterschied
+dialog.setaltitudetolerance.text.feet=Mindeschtabweichig (Feet) f\u00fcr H\u00f6chiunterschied
+dialog.autoplay.duration=Abspieldauer (Sek)
+dialog.autoplay.usetimestamps=Ziitst\u00e4mple verw\u00e4nde
+dialog.autoplay.rewind=Zum Aafang
+dialog.autoplay.pause=Pause
+dialog.autoplay.play=Abschpiele
 
 # 3d window
 dialog.3d.title=GpsPrune Dr\u00fc\u00fc-d Aasicht
@@ -693,7 +705,7 @@ details.trackdetails=Details vom Track
 details.notrack=Kei Track glade worde
 details.track.points=P\u00fcnkte
 details.track.file=Datei
-details.track.numfiles=Anzahl Dateie
+details.track.numfiles=Aazahl Dateie
 details.pointdetails=Details vonem Punkt
 details.index.selected=Index
 details.index.of=vo
@@ -748,6 +760,7 @@ fieldname.duration=Ziitl\u00e4ngi
 fieldname.speed=Gschwindikeit
 fieldname.verticalspeed=Uf/Ab Gschwindikeit
 fieldname.description=Bschriibig
+fieldname.mediafilename=F\u00f6teli- / Audioname
 
 # Measurement units
 units.original=Original
@@ -785,6 +798,11 @@ logic.or=oder
 url.googlemaps=maps.google.ch
 wikipedia.lang=als
 openweathermap.lang=de
+webservice.peakfinder=Peakfinder.org \u00f6ffne
+webservice.geohack=Geohack-Siite \u00f6ffne
+webservice.panoramio=Panoramio Karte \u00f6ffne
+webservice.opencachingcom=Opencaching.com \u00f6ffne
+webservice.opencachingcom.lang=de
 
 # Cardinals for 3d plots
 cardinal.n=N
index 447ce4dc1f6bf50b96d13db8f6129c5ce67d80e6..785a62ecc04d1083c61912ed7000da847b83e59a 100644 (file)
@@ -12,7 +12,7 @@ menu.track=Track
 menu.track.undo=Undo
 menu.track.clearundo=Clear undo list
 menu.track.markrectangle=Mark points in rectangle
-menu.track.deletemarked=Delete marked points
+function.deletemarked=Delete marked points
 menu.range=Range
 menu.range.all=Select all
 menu.range.none=Select none
@@ -38,6 +38,7 @@ menu.view.browser.yahoo=Yahoo maps
 menu.view.browser.bing=Bing maps
 menu.settings=Settings
 menu.settings.onlinemode=Load maps from internet
+menu.settings.antialias=Use antialiasing
 menu.settings.autosave=Autosave settings on exit
 menu.help=Help
 # Popup menu for map
@@ -85,6 +86,7 @@ function.exportsvg=Export SVG
 function.exportimage=Export image
 function.editwaypointname=Edit waypoint name
 function.compress=Compress track
+function.marklifts=Mark uphill lifts
 function.deleterange=Delete range
 function.croptrack=Crop track
 function.interpolate=Interpolate points
@@ -102,6 +104,7 @@ function.distances=Distances
 function.fullrangedetails=Full range details
 function.estimatetime=Estimate time
 function.learnestimationparams=Learn time estimation parameters
+function.autoplay=Autoplay track
 function.selectsegment=Select current segment
 function.splitsegments=Split track into segments
 function.sewsegments=Sew track segments together
@@ -111,6 +114,8 @@ function.lookupsrtm=Get altitudes from SRTM
 function.downloadsrtm=Download SRTM tiles
 function.getwikipedia=Get nearby Wikipedia articles
 function.searchwikipedianames=Search Wikipedia by name
+function.searchopencachingde=Search OpenCaching.de
+function.mapillary=Search for photos in Mapillary
 function.downloadosm=Download OSM data for area
 function.duplicatepoint=Duplicate point
 function.connecttopoint=Connect to point
@@ -377,9 +382,11 @@ dialog.gpsies.activity.motorbiking=Motorbiking
 dialog.gpsies.activity.snowshoe=Snowshoeing
 dialog.gpsies.activity.sailing=Sailing
 dialog.gpsies.activity.skating=Skating
+dialog.mapillary.nonefound=No photos found
 dialog.wikipedia.column.name=Article name
 dialog.wikipedia.column.distance=Distance
 dialog.wikipedia.nonefound=No wikipedia entries found
+dialog.geocaching.nonefound=No geocaches found
 dialog.correlate.notimestamps=There are no timestamps in the data points, so there is nothing to correlate with the photos.
 dialog.correlate.nouncorrelatedphotos=There are no uncorrelated photos.\nAre you sure you want to continue?
 dialog.correlate.nouncorrelatedaudios=There are no uncorrelated audios.\nAre you sure you want to continue?
@@ -438,12 +445,12 @@ dialog.deletemarked.nonefound=No data points could be removed
 dialog.pastecoordinates.desc=Enter or paste the coordinates here
 dialog.pastecoordinates.coords=Coordinates
 dialog.pastecoordinates.nothingfound=Please check the coordinates and try again
-dialog.help.help=Please see\n http://gpsprune.activityworkshop.net/\nfor more information and tips,\nincluding a new PDF user guide you can buy.
+dialog.help.help=Please see\n http://gpsprune.activityworkshop.net/\nfor more information and tips,\nincluding a PDF user guide you can buy.
 dialog.about.version=Version
 dialog.about.build=Build
 dialog.about.summarytext1=GpsPrune is a program for loading, displaying and editing data from GPS receivers.
 dialog.about.summarytext2=It is released under the Gnu GPL for free, open, worldwide use and enhancement.<br>Copying, redistribution and modification are permitted and encouraged<br>according to the conditions in the included <code>license.txt</code> file.
-dialog.about.summarytext3=Please see <code style="font-weight:bold">http://activityworkshop.net/</code> for more information and tips, including<br>a new PDF user guide you can buy.
+dialog.about.summarytext3=Please see <code style="font-weight:bold">http://activityworkshop.net/</code> for more information and tips, including<br>a PDF user guide you can buy.
 dialog.about.languages=Available languages
 dialog.about.translatedby=English text by activityworkshop.
 dialog.about.systeminfo=System info
@@ -588,6 +595,11 @@ dialog.deletebydate.column.keep=Keep
 dialog.deletebydate.column.delete=Delete
 dialog.setaltitudetolerance.text.metres=Limit (in metres) below which small climbs and descents will be ignored
 dialog.setaltitudetolerance.text.feet=Limit (in feet) below which small climbs and descents will be ignored
+dialog.autoplay.duration=Duration (secs)
+dialog.autoplay.usetimestamps=Use point timestamps
+dialog.autoplay.rewind=Back to beginning
+dialog.autoplay.pause=Pause
+dialog.autoplay.play=Play
 
 # 3d window
 dialog.3d.title=GpsPrune Three-d view
@@ -753,6 +765,7 @@ fieldname.duration=Duration
 fieldname.speed=Speed
 fieldname.verticalspeed=Vertical speed
 fieldname.description=Description
+fieldname.mediafilename=Filename
 
 # Measurement units
 units.original=Original
@@ -796,6 +809,11 @@ logic.or=or
 url.googlemaps=maps.google.co.uk
 wikipedia.lang=en
 openweathermap.lang=en
+webservice.peakfinder=Open Peakfinder.org
+webservice.geohack=Open Geohack page
+webservice.panoramio=Open Panoramio map
+webservice.opencachingcom=Open Opencaching.com
+webservice.opencachingcom.lang=en
 
 # Cardinals for 3d plots
 cardinal.n=N
index 5b920b8e6919f0ff5c9da225fa813dfbae702b1f..a8be1993af760695f80f4c972070972c069fbabe 100644 (file)
@@ -12,7 +12,7 @@ menu.track=Track
 menu.track.undo=Deshacer
 menu.track.clearundo=Despejar la lista de deshacer
 menu.track.markrectangle=Marcar puntos dentro de un rect\u00e1ngulo
-menu.track.deletemarked=Eliminar puntos marcados
+function.deletemarked=Eliminar puntos marcados
 menu.range=Rango
 menu.range.all=Seleccionar todo
 menu.range.none=No seleccionar nada
@@ -38,6 +38,7 @@ menu.view.browser.yahoo=Mapas Yahoo
 menu.view.browser.bing=Mapas Bing
 menu.settings=Preferencias
 menu.settings.onlinemode=Cargar mapas de Internet
+menu.settings.antialias=Usar antialiasing
 menu.settings.autosave=Auto Guardar
 menu.help=Ayuda
 
@@ -114,7 +115,8 @@ function.lookupsrtm=Obtener altitudes de SRTM
 function.downloadsrtm=Descargar datos de SRTM
 function.getwikipedia=Obtener art\u00edculos de Wikipedia cercanos
 function.searchwikipedianames=Buscar en Wikipedia por nombre
-function.searchopencachingde=Buscar OpenCaching.de
+function.searchopencachingde=Buscar en OpenCaching.de
+function.mapillary=Buscar en Mapillary
 function.downloadosm=Descargar datos OSM del \u00e1rea
 function.duplicatepoint=Duplicar punto
 function.setcolours=Establecer color
@@ -377,6 +379,7 @@ dialog.gpsies.activity.motorbiking=En moto
 dialog.gpsies.activity.snowshoe=Raquetas de nieve
 dialog.gpsies.activity.sailing=Vela
 dialog.gpsies.activity.skating=Patinaje
+dialog.mapillary.nonefound=No se encontraron fotos
 dialog.wikipedia.column.name=Nombre del art\u00edculo
 dialog.wikipedia.column.distance=Distancia
 dialog.wikipedia.nonefound=No se encontraron puntos
@@ -583,13 +586,13 @@ dialog.weather.humidity=Humedad
 dialog.deletebydate.nodate=Sin marcas de tiempo
 dialog.deletebydate.column.keep=Mantener
 dialog.deletebydate.column.delete=Eliminar
+dialog.autoplay.duration=Duraci\u00f3n (seg)
 
 ## 3d window
 dialog.3d.title=GpsPrune vista 3-D
 dialog.3d.altitudefactor=Factor de exageraci\u00f3n de altura
 
 ## Confirm messages
-# These are displayed as confirmation in the status bar
 confirm.loadfile=Dato cargado de
 confirm.save.ok1=Guardado correctamente
 confirm.save.ok2=puntos al archivo
@@ -678,7 +681,6 @@ filetype.png=Archivos PNG
 filetype.audio=Archivos MP3, OGG, WAV
 
 ## Display components
-# These are all for the side panels showing point/range details
 display.nodata=Ning\u00fan dato cargado
 display.noaltitudes=Los datos del track no incluyen altitudes
 display.notimestamps=Los datos de recorrido no incluyen marcas de tiempo
@@ -743,6 +745,7 @@ fieldname.duration=Duraci\u00f3n
 fieldname.speed=Velocidad
 fieldname.verticalspeed=Velocidad vertical
 fieldname.description=Descripci\u00f3n
+fieldname.mediafilename=Archivo
 
 ## Measurement units
 units.original=Original
@@ -786,6 +789,10 @@ logic.or=o
 url.googlemaps=maps.google.es
 wikipedia.lang=es
 openweathermap.lang=sp
+webservice.peakfinder=Abrir Peakfinder.org
+webservice.geohack=Abrir Geohack
+webservice.panoramio=Abrir mapa Panoramio
+webservice.opencachingcom=Abrir Opencaching.com
 webservice.opencachingcom.lang=es
 
 ## Cardinals for 3d plots
@@ -795,7 +802,6 @@ cardinal.e=E
 cardinal.w=O
 
 ## Undo operations
-# These will be displayed in the undo list after you've performed the operation, to tell you what you did
 undo.load=cargar datos
 undo.loadphotos=cargar fotos
 undo.loadaudios=cargar archivos de audio
index a70545ba43d9c84f50cda51c3c69de97e1ea72d1..a7637b214ac4bc81148090a529b7dc4f4aa63c3d 100644 (file)
@@ -9,7 +9,7 @@ menu.file.exit=\u062e\u0631\u0648\u062c
 menu.track=\u0645\u0633\u064a\u0631
 menu.track.undo=\u0628\u0627\u0637\u0644 \u06a9\u0631\u062f\u0646 \u06a9\u0627\u0631 \u0642\u0628\u0644\u064a
 menu.track.clearundo=\u067e\u0627\u06a9 \u06a9\u0631\u062f\u0646 \u0644\u064a\u0633\u062a \u06a9\u0627\u0631\u0647\u0627\u06cc \u0627\u0646\u062c\u0627\u0645 \u0634\u062f\u0647
-menu.track.deletemarked=\u067e\u0627\u06a9 \u06a9\u0631\u062f\u0646 \u0646\u0642\u0627\u0637 \u0627\u0646\u062a\u062e\u0627\u0628 \u0634\u062f\u0647
+function.deletemarked=\u067e\u0627\u06a9 \u06a9\u0631\u062f\u0646 \u0646\u0642\u0627\u0637 \u0627\u0646\u062a\u062e\u0627\u0628 \u0634\u062f\u0647
 function.rearrangewaypoints=\u0628\u0627\u0632 \u0686\u064a\u0646\u06cc \u0646\u0642\u0627\u0637 \u0645\u0633\u064a\u0631
 dialog.rearrange.tostart=\u0647\u0645\u0647 \u0646\u0642\u0627\u0637 \u0628\u0647 \u0627\u0628\u062a\u062f\u0627\u06cc \u0645\u0633\u064a\u0631
 dialog.rearrange.toend=\u0647\u0645\u0647 \u0646\u0642\u0627\u0637 \u0628\u0647 \u0627\u0646\u062a\u0647\u0627\u06cc \u0645\u0633\u064a\u0631
index ad05294a2b095d89f5f422890a4568ea1bdc0bb6..5714803a3d5e8fc7ebf288754ef78fcca2884f7f 100644 (file)
@@ -12,7 +12,7 @@ menu.track=Trace
 menu.track.undo=Annuler
 menu.track.clearundo=Purger la liste d'annulation
 menu.track.markrectangle=S\u00e9lectionner les points dans un rectangle
-menu.track.deletemarked=Supprimer les points marqu\u00e9s
+function.deletemarked=Supprimer les points marqu\u00e9s
 function.rearrangewaypoints=R\u00e9arranger les points du navigation
 menu.range=\u00c9tendue
 menu.range.all=Tout s\u00e9lectionner
@@ -39,6 +39,7 @@ menu.view.browser.yahoo=Cartes Yahoo
 menu.view.browser.bing=Cartes Bing
 menu.settings=Pr\u00e9f\u00e9rences
 menu.settings.onlinemode=Charger cartes depuis internet
+menu.settings.antialias=Anticr\u00e9nelage
 menu.settings.autosave=Sauver automatiquement en quittant
 menu.help=Aide
 # Popup menu for map
@@ -114,6 +115,8 @@ function.lookupsrtm=R\u00e9cup\u00e9rer les altitudes depuis SRTM
 function.downloadsrtm=T\u00e9l\u00e9charger les donn\u00e9es SRTM
 function.getwikipedia=Obtenir les articles de Wikip\u00e9dia \u00e0 proximit\u00e9
 function.searchwikipedianames=Rechercher dans Wikip\u00e9dia par nom
+function.searchopencachingde=Rechercher dans OpenCaching.de
+function.mapillary=Rechercher dans Mapillary
 function.downloadosm=T\u00e9l\u00e9charger les donn\u00e9es OSM de la zone
 function.duplicatepoint=Dupliquer le point
 function.setcolours=Choisir les couleurs
@@ -338,6 +341,8 @@ dialog.estimatetime.results.actualtime=Dur\u00e9e en fait
 dialog.estimatetime.error.noaltitudes=L'\u00e9tendue s\u00e9lectionn\u00e9e de contient pas d'altitudes
 dialog.learnestimationparams.averageerror=Erreur en moyenne
 dialog.learnestimationparams.combinedresults=R\u00e9sultats combin\u00e9es
+dialog.learnestimationparams.weight.current=actuel
+dialog.learnestimationparams.weight.calculated=calcul\u00e9
 dialog.setmapbg.intro=S\u00e9lectionnez une source de cartes, ou ajoutez-en une nouvelle
 dialog.addmapsource.title=Ajouter une nouvelle source de cartes
 dialog.addmapsource.sourcename=Nom de la source
@@ -507,6 +512,14 @@ dialog.colourchooser.green=Vert
 dialog.colourchooser.blue=Bleu
 dialog.colourer.type=Crit\u00e8re de coloriste
 dialog.colourer.type.none=Aucun
+dialog.colourer.type.byfile=Selon fichier
+dialog.colourer.type.bysegment=Selon segment
+dialog.colourer.type.byaltitude=Selon altitude
+dialog.colourer.type.byspeed=Selon vitesse
+dialog.colourer.type.byvertspeed=Selon vitesse verticale
+dialog.colourer.type.bygradient=Selon la pente
+dialog.colourer.type.bydate=Selon la date
+dialog.colourer.maxcolours=Nombre de couleurs maximum
 dialog.setlanguage.firstintro=Vous pouvez s\u00e9lectionner l'une des langues disponibles,<p> ou bien un fichier de langue \u00e0 utiliser.
 dialog.setlanguage.secondintro=Vous devez sauvegarder vos param\u00e8tres puis<p>red\u00e9marrer GpsPrune pour changer de langue.
 dialog.setlanguage.language=Langue
@@ -559,6 +572,9 @@ dialog.weather.creditnotice=Ces donn\u00e9es sont fournies par openweathermap.or
 dialog.deletebydate.nodate=Sans horodatage
 dialog.deletebydate.column.keep=Garder
 dialog.deletebydate.column.delete=Supprimer
+dialog.autoplay.duration=Dur\u00e9e (sec)
+dialog.autoplay.pause=Pause
+dialog.autoplay.play=Jouer
 
 # 3d window
 dialog.3d.title=Vue 3D de GpsPrune
@@ -722,6 +738,7 @@ fieldname.duration=Dur\u00e9e
 fieldname.speed=Vitesse
 fieldname.verticalspeed=Vitesse verticale
 fieldname.description=Description
+fieldname.mediafilename=Nom de fichier
 
 # Measurement units
 units.original=Original
@@ -765,6 +782,10 @@ logic.or=ou
 url.googlemaps=maps.google.fr
 wikipedia.lang=fr
 openweathermap.lang=fr
+webservice.peakfinder=Ouvrir Peakfinder.org
+webservice.geohack=Ouvrir la page Geohack
+webservice.panoramio=Ouvrir la carte Panoramio
+webservice.opencachingcom=Ouvrir Opencaching.com
 webservice.opencachingcom.lang=fr
 
 # Cardinals for 3d plots
index 74ba9e42db12ea3a54bdfea058dda7a25ad162f7..c083f63f6644a3532f09cce23e04217c4e764417 100644 (file)
@@ -12,7 +12,7 @@ menu.track=Nyomvonal
 menu.track.undo=Visszavon\u00e1s
 menu.track.clearundo=Visszavon\u00e1si lista t\u00f6rl\u00e9se
 menu.track.markrectangle=N\u00e9gyzeten bel\u00fcli pontok megjel\u00f6l\u00e9se
-menu.track.deletemarked=Jel\u00f6lt pontok t\u00f6rl\u00e9se
+function.deletemarked=Jel\u00f6lt pontok t\u00f6rl\u00e9se
 menu.range=Tartom\u00e1ny
 menu.range.all=Mindet kijel\u00f6l
 menu.range.none=Kijel\u00f6l\u00e9s megsz\u00fcntet\u00e9se
@@ -38,6 +38,7 @@ menu.view.browser.yahoo=Yahoo! Maps
 menu.view.browser.bing=Bing Maps
 menu.settings=Be\u00e1ll\u00edt\u00e1sok
 menu.settings.onlinemode=T\u00e9rk\u00e9pek bet\u00f6lt\u00e9se internetr\u0151l
+menu.settings.antialias=\u00c9lsim\u00edt\u00e1s haszn\u00e1lata
 menu.settings.autosave=Be\u00e1ll\u00edt\u00e1sok automatikus ment\u00e9se kil\u00e9p\u00e9skor
 menu.help=S\u00fag\u00f3
 
@@ -86,6 +87,7 @@ function.exportsvg=Export\u00e1l\u00e1s SVG-be
 function.exportimage=Export\u00e1l\u00e1s k\u00e9pbe
 function.editwaypointname=\u00datpont nev\u00e9nek szerkeszt\u00e9se
 function.compress=Nyomvonal t\u00f6m\u00f6r\u00edt\u00e9se
+function.marklifts=S\u00edliftek megjel\u00f6l\u00e9se
 function.deleterange=Tartom\u00e1ny t\u00f6rl\u00e9se
 function.croptrack=Nyomvonal k\u00f6rbev\u00e1g\u00e1sa
 function.interpolate=Pontok interpol\u00e1l\u00e1sa
@@ -103,6 +105,7 @@ function.distances=T\u00e1vols\u00e1gok
 function.fullrangedetails=Teljes tartom\u00e1ny r\u00e9szletei
 function.estimatetime=Becs\u00fclt id\u0151
 function.learnestimationparams=Id\u0151becsl\u00e9s tanul\u00e1s\u00e1nak param\u00e9terei
+function.autoplay=Nyomvonal lej\u00e1tsz\u00e1sa
 function.setmapbg=H\u00e1tt\u00e9rk\u00e9p be\u00e1ll\u00edt\u00e1sa
 function.setpaths=Program\u00fatvonalak be\u00e1ll\u00edt\u00e1sa
 function.selectsegment=Aktu\u00e1lis szakasz kiv\u00e1laszt\u00e1sa
@@ -115,6 +118,7 @@ function.downloadsrtm=SRTM csemp\u00e9k let\u00f6lt\u00e9se
 function.getwikipedia=K\u00f6zeli Wikip\u00e9dia sz\u00f3cikkek let\u00f6lt\u00e9se
 function.searchwikipedianames=Keres\u00e9s a Wikip\u00e9di\u00e1ban n\u00e9v szerint
 function.searchopencachingde=Keres\u00e9s az OpenCaching.de-n
+function.mapillary=F\u00e9nyk\u00e9pek keres\u00e9se Mapillary-n
 function.downloadosm=OSM adatok let\u00f6lt\u00e9se a ter\u00fcletr\u0151l
 function.duplicatepoint=Pont kett\u0151z\u00e9se
 function.setcolours=Sz\u00ednek be\u00e1ll\u00edt\u00e1sa
@@ -379,6 +383,7 @@ dialog.gpsies.activity.motorbiking=Motorker\u00e9kp\u00e1roz\u00e1s
 dialog.gpsies.activity.snowshoe=H\u00f3talpas s\u00e9ta
 dialog.gpsies.activity.sailing=Vitorl\u00e1z\u00e1s
 dialog.gpsies.activity.skating=Korcsoly\u00e1z\u00e1s
+dialog.mapillary.nonefound=Nem tal\u00e1lhat\u00f3k f\u00e9nyk\u00e9pek
 dialog.wikipedia.column.name=Sz\u00f3cikk neve
 dialog.wikipedia.column.distance=T\u00e1vols\u00e1g
 dialog.wikipedia.nonefound=Nem tal\u00e1lhat\u00f3 Wikip\u00e9dia sz\u00f3cikk
@@ -447,7 +452,7 @@ dialog.about.summarytext1=A GpsPrune egy program GPS vev\u0151kr\u0151l sz\u00e1
 dialog.about.summarytext2=Gnu GPL licenc alatt ker\u00fclt kiad\u00e1sra a szabad, ny\u00edlt, vil\u00e1gm\u00e9ret\u0171 haszn\u00e1lathoz \u00e9s fejleszt\u00e9shez.<br>M\u00e1sol\u00e1sa, terjeszt\u00e9se \u00e9s m\u00f3dos\u00edt\u00e1sa megengedett \u00e9s \u00f6szt\u00f6nz\u00f6tt<br>a mell\u00e9kelt <code>license.txt</code> f\u00e1jlban r\u00f6gz\u00edtett felt\u00e9telek szerint
 dialog.about.summarytext3=Tov\u00e1bbi inform\u00e1ci\u00f3k\u00e9rt \u00e9s kezel\u00e9si \u00fatmutat\u00f3\u00e9rt l\u00e1sd a <code style="font-weight:bold">http://activityworkshop.net/</code> webhelyet.
 dialog.about.languages=El\u00e9rhet\u0151 nyelvek
-dialog.about.translatedby=Magyar sz\u00f6veg: Ball\u00f3 Gy\u00f6rgy, B\u00e1thory P\u00e9ter, Peter Gervai
+dialog.about.translatedby=Magyar sz\u00f6veg: Ball\u00f3 Gy\u00f6rgy \u00e9s B\u00e1thory P\u00e9ter
 dialog.about.systeminfo=Rendszerinform\u00e1ci\u00f3
 dialog.about.systeminfo.os=Oper\u00e1ci\u00f3s rendszer
 dialog.about.systeminfo.java=Java futtat\u00f3k\u00f6rnyezet
@@ -590,6 +595,11 @@ dialog.deletebydate.column.keep=Megtart
 dialog.deletebydate.column.delete=T\u00f6r\u00f6l
 dialog.setaltitudetolerance.text.metres=Az a hat\u00e1r (m\u00e9terben) ami alatt a kis s\u00fcllyed\u00e9seket \u00e9s emelked\u00e9seket figyelmen k\u00edv\u00fcl hagyjuk
 dialog.setaltitudetolerance.text.feet=Az a hat\u00e1r (l\u00e1bban) ami alatt a kis s\u00fcllyed\u00e9seket \u00e9s emelked\u00e9seket figyelmen k\u00edv\u00fcl hagyjuk
+dialog.autoplay.duration=Id\u0151tartam (mp)
+dialog.autoplay.usetimestamps=Nyompontok id\u0151b\u00e9lyege alapj\u00e1n
+dialog.autoplay.rewind=Vissza az elej\u00e9re
+dialog.autoplay.pause=Sz\u00fcnet
+dialog.autoplay.play=Lej\u00e1tsz\u00e1s
 
 # 3d window
 dialog.3d.title=GpsPrune 3D n\u00e9zet
@@ -755,6 +765,7 @@ fieldname.duration=Id\u0151tartam
 fieldname.speed=Sebess\u00e9g
 fieldname.verticalspeed=F\u00fcgg\u0151leges sebess\u00e9g
 fieldname.description=Le\u00edr\u00e1s
+fieldname.mediafilename=F\u00e1jln\u00e9v
 
 # Measurement units
 units.original=Eredeti
index 06eb02985330ad6137a2f62bc12dd20fdc812b5e..69a9c834a13cfd2ef3b864f4d39e1b81acb9957a 100644 (file)
@@ -12,7 +12,7 @@ menu.track=Traccia
 menu.track.undo=Annulla
 menu.track.clearundo=Cancella lista annulla
 menu.track.markrectangle=Segnare i punti nel rettangolo
-menu.track.deletemarked=Cancella punti marcati
+function.deletemarked=Cancella punti marcati
 function.rearrangewaypoints=Riorganizza waypoint
 menu.range=Serie
 menu.range.all=Seleziona tutto
@@ -35,10 +35,11 @@ menu.view.browser=Mappa sul browser
 menu.view.browser.google=Google maps
 menu.view.browser.openstreetmap=Openstreetmap
 menu.view.browser.mapquest=Mapquest
-menu.view.browser.yahoo=mappe Yahoo
-menu.view.browser.bing=mappe Bing
+menu.view.browser.yahoo=Mappe Yahoo
+menu.view.browser.bing=Mappe Bing
 menu.settings=Preferenze
 menu.settings.onlinemode=Carica mappa da internet
+menu.settings.antialias=Usa antialiasing
 menu.settings.autosave=Salva settaggi con chiusura del programma
 menu.help=Aiuto
 # Popup menu for map
@@ -114,6 +115,7 @@ function.downloadsrtm=Scarica file da SRTM
 function.getwikipedia=Ottieni informazioni da Wikipedia
 function.searchwikipedianames=Cerca il nome in Wikipedia
 function.searchopencachingde=Cerca OpenCaching.de
+function.mapillary=Cerca Mapillary.com
 function.downloadosm=Scarica dati OSM dell'area
 function.duplicatepoint=Duplica punto corrente in coda
 function.setcolours=Scegli colori
@@ -754,6 +756,7 @@ fieldname.duration=Durata
 fieldname.speed=Velocit\u00e0
 fieldname.verticalspeed=Velocit\u00e0 verticale
 fieldname.description=Descrizione
+fieldname.mediafilename=File
 
 # Measurement units
 units.original=Originale
@@ -797,6 +800,10 @@ logic.or=o
 url.googlemaps=maps.google.it
 wikipedia.lang=it
 openweathermap.lang=it
+webservice.peakfinder=Apri Peakfinder.org
+webservice.geohack=Apri la pagina Geohack
+webservice.panoramio=Apri la mappa Panoramio
+webservice.opencachingcom=Apri Opencaching.com
 webservice.opencachingcom.lang=it
 
 # Cardinals for 3d plots
index 371eec53da3e4e2cb3eb0d6d506a146edf4f6ccb..087e8f7ab0973661d5565844930813481c5d86d7 100644 (file)
@@ -11,7 +11,7 @@ menu.track=\u30c8\u30e9\u30c3\u30af(T)
 menu.track.undo=\u30a2\u30f3\u30c9\u30a5
 menu.track.clearundo=\u30a2\u30f3\u30c9\u30a5\u30ea\u30b9\u30c8\u3092\u7a7a\u306b\u3059\u308b
 menu.track.markrectangle=\u56db\u89d2\u306e\u4e2d\u306b\u5370\u3092\u3064\u3051\u308b
-menu.track.deletemarked=\u5370\u306e\u4ed8\u3044\u305f\u70b9\u3092\u524a\u9664
+function.deletemarked=\u5370\u306e\u4ed8\u3044\u305f\u70b9\u3092\u524a\u9664
 function.rearrangewaypoints=\u30a6\u30a7\u30a4\u30dd\u30a4\u30f3\u30c8\u3092\u4e26\u3079\u66ff\u3048
 menu.range=\u7bc4\u56f2(R)
 menu.range.all=\u5168\u3066\u9078\u629e
index 69722c941cb9abcb10694c0e9162acd4c73d04bf..e1f1945493de05678b8ff07b7e4aba4a6a6c4661 100644 (file)
@@ -9,7 +9,7 @@ menu.file.exit=\uc885\ub8cc
 menu.track=\ud2b8\ub799
 menu.track.undo=\uc2e4\ud589\ucde8\uc18c
 menu.track.clearundo=\uc2e4\ud589\ucde8\uc18c \ubaa9\ub85d \uc0ad\uc81c
-menu.track.deletemarked=\ud45c\uc2dc\ub41c \uc9c0\uc810 \uc9c0\uc6b0\uae30
+function.deletemarked=\ud45c\uc2dc\ub41c \uc9c0\uc810 \uc9c0\uc6b0\uae30
 function.rearrangewaypoints=\uacbd\uc720\uc9c0 \uc7ac\uc815\ub82c
 menu.range=\uc5f0\uacb0\uc120
 menu.range.all=\ubaa8\ub450 \uc120\ud0dd
index a9431c6425bc770902a2a1b662774840bc16ae28..548f9b611a57fee6da2839ecd6cf2d9028894984 100644 (file)
@@ -12,7 +12,7 @@ menu.track=Route
 menu.track.undo=Ongedaan maken
 menu.track.clearundo=Ongedaan-maken lijst wissen
 menu.track.markrectangle=Makeer alle punten in een vierkant
-menu.track.deletemarked=Verwijderen gemarkeerde punten
+function.deletemarked=Verwijderen gemarkeerde punten
 menu.range=Reeks
 menu.range.all=Selecteer alles
 menu.range.none=Selecteer geen
@@ -38,6 +38,7 @@ menu.view.browser.yahoo=Yahoo maps
 menu.view.browser.bing=Bing maps
 menu.settings=Instellingen
 menu.settings.onlinemode=Kaarten van internet ophalen
+menu.settings.antialias=Anti-kartelvorming
 menu.settings.autosave=Automatisch opslaan bij afsluiten
 menu.help=Help
 # Popup menu for map
@@ -113,6 +114,7 @@ function.lookupsrtm=Hoogtes van SRTM ophalen
 function.downloadsrtm=Downloaden SRTM tegels
 function.getwikipedia=Wikipedia artikelen uit de buurt ophalen
 function.searchwikipedianames=Wikipedia zoeken op naam
+function.searchopencachingde=OpenCaching.de zoeken
 function.downloadosm=Downloaden OSM data voor gebied
 function.duplicatepoint=Dupliceer punt
 function.setcolours=Instellen kleuren
@@ -377,9 +379,11 @@ dialog.gpsies.activity.motorbiking=Motorrijden
 dialog.gpsies.activity.snowshoe=Sneeuwschoen-lopen
 dialog.gpsies.activity.sailing=Zeilen
 dialog.gpsies.activity.skating=Skating
+dialog.mapillary.nonefound=Geen foto's gevonden
 dialog.wikipedia.column.name=Artikelnaam
 dialog.wikipedia.column.distance=Afstand
 dialog.wikipedia.nonefound=Geen punten gevonden
+dialog.geocaching.nonefound=Geen punten gevonden
 dialog.correlate.notimestamps=Er zit geen tijdinformatie in de punten, dus kunnen ze niet aan foto's gekoppeld worden.
 dialog.correlate.nouncorrelatedphotos=Er zijn geen ongekoppelde foto's.\nWeet u zeker dat u wilt doorgaan?
 dialog.correlate.nouncorrelatedaudios=Er zijn geen ongekoppelde geluidsbestanden.\nWeet u zeker dat u wilt doorgaan?
@@ -588,6 +592,7 @@ dialog.deletebydate.column.keep=Behouden
 dialog.deletebydate.column.delete=Verwijderen
 dialog.setaltitudetolerance.text.metres=Grens (in meters) waaronder kleine klimmen en afdalingen worden genegeerd
 dialog.setaltitudetolerance.text.feet=Grens (in feet) waaronder kleine klimmen en afdalingen worden genegeerd
+dialog.autoplay.duration=Duur (sec)
 
 # 3d window
 dialog.3d.title=GpsPrune in 3D
@@ -753,6 +758,7 @@ fieldname.duration=Duur
 fieldname.speed=Snelheid
 fieldname.verticalspeed=Verticale snelheid
 fieldname.description=Omschrijving
+fieldname.mediafilename=Bestandsnaam
 
 # Measurement units
 units.original=Oorspronkelijke
@@ -796,6 +802,10 @@ logic.or=of
 url.googlemaps=maps.google.nl
 wikipedia.lang=nl
 openweathermap.lang=nl
+webservice.peakfinder=Open Peakfinder.org
+webservice.geohack=Open Geohack webpagina
+webservice.panoramio=Open Panoramio map
+webservice.opencachingcom=Open Opencaching.com
 webservice.opencachingcom.lang=nl
 
 # Cardinals for 3d plots
index acf3fe08fb4428962ccf9fc897e4ec390a3ceb42..a2302fec3a7c61883930a504474d475d868e5fc8 100644 (file)
@@ -12,7 +12,7 @@ menu.track=\u015acie\u017cka
 menu.track.undo=Cofnij
 menu.track.clearundo=Wyczy\u015b\u0107 list\u0119 zmian
 menu.track.markrectangle=Zaznaczenie prostok\u0105tne
-menu.track.deletemarked=Usu\u0144 zaznaczone punkty
+function.deletemarked=Usu\u0144 zaznaczone punkty
 menu.range=Zakres
 menu.range.all=Zaznacz wszystko
 menu.range.none=Usu\u0144 zaznaczenie
@@ -588,6 +588,7 @@ dialog.deletebydate.column.keep=Zostaw
 dialog.deletebydate.column.delete=Usu\u0144
 dialog.setaltitudetolerance.text.metres=Limit (w metrach) poni\u017cej kt\u00f3rego, ma\u0142e spadki wzniosy b\u0119d\u0105 ignorowane
 dialog.setaltitudetolerance.text.feet=Limit (w stopach) poni\u017cej kt\u00f3rego, ma\u0142e spadki wzniosy b\u0119d\u0105 ignorowane
+dialog.autoplay.duration=Czas trwania (sek)
 
 # 3d window
 dialog.3d.title=GpsPrune widok tr\u00f3jwymiarowy
@@ -753,6 +754,7 @@ fieldname.duration=Czas trwania
 fieldname.speed=Pr\u0119dko\u015b\u0107
 fieldname.verticalspeed=Pr\u0119dko\u015b\u0107 pionowa
 fieldname.description=Opis
+fieldname.mediafilename=Nazwa pliku
 
 # Measurement units
 units.original=Oryginalny
index 6319688bcabc95c9560ab35623de97d43084715c..8737cd394fafd3368375fb17e37b2a7430ce2511 100644 (file)
@@ -12,7 +12,7 @@ menu.track=Rota
 menu.track.undo=Desfazer
 menu.track.clearundo=Limpar lista de desfazer
 menu.track.markrectangle=Marcar pontos no ret\u00e2ngulo
-menu.track.deletemarked=Remover pontos marcados
+function.deletemarked=Remover pontos marcados
 function.rearrangewaypoints=Rearrumar pontos
 menu.range=Intervalo
 menu.range.all=Selecionar tudo
@@ -113,6 +113,8 @@ function.lookupsrtm=Obter altitudes a partir do SRTM
 function.downloadsrtm=Baixar arquivos SRTM
 function.getwikipedia=Obter artigos da Wikip\u00e9dia das redondezas
 function.searchwikipedianames=Procurar na Wikip\u00e9dia por nome
+function.searchopencachingde=Procurar na OpenCaching.de
+function.mapillary=Procurar na Mapillary.com
 function.downloadosm=Baixar dados OSM para a \u00e1rea
 function.duplicatepoint=Duplicar ponto
 function.setcolours=Definir cores
@@ -393,7 +395,7 @@ dialog.correlate.options.offset.minutes=minutos e
 dialog.correlate.options.offset.seconds=segundos
 dialog.correlate.options.photolater=Foto mais recente que o ponto
 dialog.correlate.options.pointlaterphoto=Ponto mais recente que a foto
-dialog.correlate.options.audiolater=\u00e1udio mais recente que o ponto
+dialog.correlate.options.audiolater=\u00c1udio mais recente que o ponto
 dialog.correlate.options.pointlateraudio=Ponto mais recente que a \u00e1udio
 dialog.correlate.options.limitspanel=Limites de correla\u00e7\u00e3o
 dialog.correlate.options.notimelimit=Nenhum limite de tempo
@@ -565,6 +567,13 @@ dialog.weather.wind=Vento
 dialog.weather.temp=Temp
 dialog.weather.humidity=Umidade
 dialog.weather.creditnotice=Estes dados foram disponibilizados por openweathermap.org. A p\u00e1gina Web possui mais detalhes.
+dialog.deletebydate.column.keep=Guardar
+dialog.deletebydate.column.delete=Remover
+dialog.autoplay.duration=Dura\u00e7\u00e3o (seg)
+dialog.autoplay.usetimestamps=Usar data-hora
+dialog.autoplay.rewind=Rebobinar
+dialog.autoplay.pause=Suspender
+dialog.autoplay.play=Tocar
 
 # 3d window
 dialog.3d.title=Vista 3D do GpsPrune
@@ -719,6 +728,7 @@ fieldname.longitude=Longitude
 fieldname.altitude=Altura
 fieldname.timestamp=Tempo
 fieldname.time=Tempo
+fieldname.date=Data
 fieldname.waypointname=Nome
 fieldname.waypointtype=Tipo
 fieldname.newsegment=Segmento
@@ -729,6 +739,7 @@ fieldname.duration=Dura\u00e7\u00e3o
 fieldname.speed=Velocidade
 fieldname.verticalspeed=Velocidade vertical
 fieldname.description=Descri\u00e7\u00e3o
+fieldname.mediafilename=Arquivo
 
 # Measurement units
 units.original=Original
@@ -772,6 +783,11 @@ logic.or=ou
 url.googlemaps=maps.google.com.br
 wikipedia.lang=pt
 openweathermap.lang=pt
+webservice.peakfinder=Abrir Peakfinder.org
+webservice.geohack=Abrir p\u00e1gina Geohack
+webservice.panoramio=Abrir mapa do Panoramio
+webservice.opencachingcom=Abrir Opencaching.com
+webservice.opencachingcom.lang=pt
 
 # Cardinals for 3d plots
 cardinal.n=N
index e31143085e3908482bf8bc2b8eb2723b1e7044fb..0a1f020a292f5598220d2fc9c7d8f356e928db41 100644 (file)
@@ -1,46 +1,51 @@
 # Text entries for the GpsPrune application
-# Romanian entries as extra
+# Romanian entries thanks to Rothermographer, Oana and Cristian
 
 # Menu entries
 menu.file=Fi\u015fier
 menu.file.addphotos=Adaug\u0103 foto
 menu.file.recentfiles=Fi\u015fiere recente
-menu.file.save=Salvare
+menu.file.save=Salveaz\u0103 ca fi\u0219ier text
 menu.file.exit=Ie\u015fire
 menu.online=Internet
 menu.track=Traseu
 menu.track.undo=Anulare
-menu.track.clearundo=\u015etergere lista de anulari
-menu.track.deletemarked=\u015etergere puncte marcate
+menu.track.clearundo=\u015eterge lista de anul\u0103ri
+menu.track.markrectangle=Selecteaz\u0103 puncte din p\u0103trat
+function.deletemarked=\u015eterge punctele marcate
 menu.range=Interval
-menu.range.all=Selectare toate
+menu.range.all=Selecteaz\u0103 toate punctele
 menu.range.none=Nu selecta niciun punct
-menu.range.start=Seteaza inceputul selectiei
-menu.range.end=Seteaza sfarsitul selectiei
-menu.range.average=Mediere selec\u0163ie
-menu.range.reverse=Inversare selec\u0163ie
-menu.range.mergetracksegments=Unire segmente traseu
-menu.range.cutandmove=Taiere si mutare selec\u0163ie
+menu.range.start=Seteaz\u0103 inceputul intervalului
+menu.range.end=Seteaz\u0103 sfarsitul intervalului
+menu.range.average=Mediaz\u0103 selec\u0163ia
+menu.range.reverse=Inverseaz\u0103 intervalul
+menu.range.mergetracksegments=Une\u0219te segmentele traseului
+menu.range.cutandmove=Taie \u0219i mut\u0103 intervalul
 menu.point=Punct
-menu.point.editpoint=Editare punct
-menu.point.deletepoint=\u015etergere punct
+menu.point.editpoint=Editeaz\u0103 punct
+menu.point.deletepoint=\u015eterge punct
 menu.photo=Foto
-menu.photo.saveexif=Salveaza la Exif
+menu.photo.saveexif=Salveaz\u0103 \u00een Exif
 menu.audio=Audio
 menu.view=Vizualizare
-menu.view.browser=Harta in browser
-menu.view.browser.google=Harti Google
+menu.view.showsidebars=Afi\u0219eaz\u0103 panourile laterale
+menu.view.browser=Harta \u00een browser
+menu.view.browser.google=Harta Google
 menu.view.browser.openstreetmap=Openstreetmap
 menu.view.browser.mapquest=Mapquest
-menu.view.browser.yahoo=Harti Yahoo
-menu.view.browser.bing=Harti Bing
+menu.view.browser.yahoo=Harta Yahoo
+menu.view.browser.bing=Harta Bing
 menu.settings=Set\u0103ri
 menu.settings.onlinemode=\u00cencarc\u0103 h\u0103r\u021bi
+menu.settings.antialias=Folose\u0219te antialiasing
+menu.settings.autosave=Salveaz\u0103 set\u0103rile automat la ie\u0219ire
 menu.help=Ajutor
+
 # Popup menu for map
 menu.map.zoomin=Apropie
-menu.map.zoomout=Departeaza
-menu.map.zoomfull=Departeaza la maxim
+menu.map.zoomout=Dep\u0103rteaz\u0103
+menu.map.zoomfull=Dep\u0103rteaz\u0103 la maxim
 menu.map.newpoint=Creaz\u0103 punct
 menu.map.drawpoints=Creaz\u0103 serie de puncte
 menu.map.connect=Traseaz\u0103 linii \u00eentre puncte
@@ -71,87 +76,116 @@ shortcut.menu.range.all=T
 shortcut.menu.help.help=A
 
 # Functions
-function.open=Deschidere fi\u015fier
-function.importwithgpsbabel=Importare fi\u015fier cu GPSBabel
+function.open=Deschide fi\u015fier
+function.importwithgpsbabel=Import\u0103 fi\u015fier cu GPSBabel
 function.loadfromgps=\u00cencarc\u0103 date de la GPS
 function.sendtogps=Trimite date spre GPS
-function.exportkml=Export\u0103 \u00eentr-un fi\u015fier KML
-function.exportgpx=Export\u0103 \u00eentr-un fi\u015fier GPX
-function.exportpov=Export\u0103 \u00eentr-un fi\u015fier POV
-function.exportsvg=Export\u0103 \u00eentr-un fi\u015fier SVG
+function.exportkml=Export\u0103 \u00een fi\u015fier KML
+function.exportgpx=Export\u0103 \u00een fi\u015fier GPX
+function.exportpov=Export\u0103 \u00een fi\u015fier POV
+function.exportsvg=Export\u0103 \u00een fi\u015fier SVG
 function.exportimage=Export\u0103 imagine
-function.editwaypointname=Editare nume waypoint
-function.compress=Comprima traseu
-function.deleterange=\u015etergere gama
-function.interpolate=Interpolare
+function.editwaypointname=Editeaz\u0103 nume waypoint
+function.compress=Comprim\u0103 traseu
+function.marklifts=Marcheaz\u0103 urc\u0103rile pe instala\u021bii
+function.deleterange=\u015eterge intervalul
+function.croptrack=Decupeaz\u0103 traseul
+function.interpolate=Interpoleaz\u0103
+function.deletebydate=\u0218terge puncte pe criterii de timp
 function.addtimeoffset=Adaug\u0103 decalaj timp
 function.addaltitudeoffset=Adaug\u0103 decalaj altitudine
-function.rearrangewaypoints=Rearanjare waypoint
-function.findwaypoint=Gasire waypoint
+function.rearrangewaypoints=Rearanjeaz\u0103 waypoint
+function.convertnamestotimes=Converte\u0219te numele waypoint-urilor \u00een timpi
+function.deletefieldvalues=\u0218terge valorile c\u00e2mpurilor
+function.findwaypoint=G\u0103se\u0219te waypoint
+function.pastecoordinates=Introdu coordonate noi
 function.charts=Grafice
-function.show3d=Vizualizare arborescenta
+function.show3d=Vizualizare 3D
 function.distances=Distan\u0163e
-function.fullrangedetails=Informa\u0163ie complet
-function.getgpsies=\u00cencarc\u0103 trassee Gpsies
-function.uploadgpsies=Trimite date spre Gpsies
-function.downloadsrtm=\u00cencarc\u0103 date SRTM
+function.fullrangedetails=Informa\u0163ie complet\u0103
 function.estimatetime=Estimare durat\u0103
-function.setmapbg=Seteaza harta
-function.selectsegment=Selectare segment curent
-function.setcolours=Selectare culorile
-function.setlanguage=Selectare limba
-function.connecttopoint=Conecteaza la punct
-function.disconnectfrompoint=Deconecteaza de la punct
-function.removephoto=Elimina foto
-function.correlatephotos=Corelare fotografii
-function.rearrangephotos=Rearanjare fotografii
-function.rotatephotoleft=Roti foto la st\u00e2nga
-function.rotatephotoright=Roti foto la dreapta
+function.learnestimationparams=\u00cenva\u021b\u0103 parametri de estimare timpi
+function.autoplay=Parcurge traseu
+function.setmapbg=Seteaz\u0103 fundalul h\u0103r\u021bii
+function.setpaths=Seteaz\u0103 calea c\u0103tre aplica\u021bii
+function.selectsegment=Selecteaz\u0103 segment curent
+function.splitsegments=Divizeaz\u0103 traseul \u00een segmente
+function.sewsegments=Combin\u0103 segmentele traseului
+function.getgpsies=\u00cencarc\u0103 trasee Gpsies
+function.uploadgpsies=Trimite date spre Gpsies
+function.lookupsrtm=Descarc\u0103 date SRTM \u00een cache
+function.downloadsrtm=Descarc\u0103 date SRTM
+function.getwikipedia=Caut\u0103 articole Wikipedia din proximitate
+function.searchwikipedianames=Caut\u0103 Wikipedia dup\u0103 nume
+function.searchopencachingde=Caut\u0103 OpenCaching.de
+function.mapillary=Caut\u0103 fotografii \u00een Mapillary
+function.downloadosm=Descarc\u0103 date OSM pentru zona traseului
+function.duplicatepoint=Duplic\u0103 punctul
+function.setcolours=Seteaz\u0103 culori
+function.setlinewidth=Seteaz\u0103 grosime linie
+function.setlanguage=Seteaz\u0103 limb\u0103
+function.connecttopoint=Conecteaz\u0103 la punct
+function.disconnectfrompoint=Deconecteaz\u0103 de la punct
+function.removephoto=Elimin\u0103 foto
+function.correlatephotos=Coreleaz\u0103 fotografii
+function.rearrangephotos=Rearanjeaz\u0103 fotografii
+function.rotatephotoleft=Rote\u0219te foto la st\u00e2nga
+function.rotatephotoright=Rote\u0219te foto la dreapta
 function.photopopup=Arat\u0103 foto
+function.ignoreexifthumb=Ignor\u0103 icoana EXIF
 function.loadaudio=Adaug\u0103 audio
-function.removeaudio=Elimina audio
-function.playaudio=Redare audio
+function.removeaudio=Elimin\u0103 audio
+function.correlateaudios=Coreleaz\u0103 clipuri audio
+function.playaudio=Red\u0103 clip audio
+function.stopaudio=Opre\u0219te clip audio
 function.help=Ajutor
-function.showkeys=Arat\u0103 tastele scurt\u0103turi
+function.showkeys=Arat\u0103 scurt\u0103turi
 function.about=Despre GpsPrune
-function.checkversion=Verific\u0103 pentru o versiune noua
+function.checkversion=Verific\u0103 versiune noua
 function.saveconfig=Salvare set\u0103ri
 function.diskcache=Salvare harti
+function.managetilecache=Administreaz\u0103 imaginile salvate
 function.getweatherforecast=Prognoz\u0103 meteo
+function.setaltitudetolerance=Alege toleran\u021ba varia\u021biei altitudinii
 
 # Dialogs
 dialog.exit.confirm.title=Ie\u015fire din programul GpsPrune
-dialog.exit.confirm.text=Datele dumneavoastra nu sunt salvate.\nSunte\u0163i sigur ca\u0103 dori\u0163i s\u0103 ie\u015fiti?
-dialog.openappend.title=Adauga la datele existente
-dialog.openappend.text=Adauga la datele deja incarcate?
+dialog.exit.confirm.text=Datele dumneavoastra nu sunt salvate.\nSunte\u0163i sigur c\u0103 dori\u0163i s\u0103 ie\u015fiti?
+dialog.openappend.title=Adaug\u0103 la datele existente
+dialog.openappend.text=Adaug\u0103 la datele deja incarcate?
 dialog.deletepoint.title=\u015eterge Punct
 dialog.deletepoint.deletephoto=\u015eterg fotografiile atasate acestui punct?
 dialog.deletephoto.title=\u015eterge foto
 dialog.deletephoto.deletepoint=\u015eterg punct atasat acestei fotografii?
 dialog.deleteaudio.deletepoint=\u015eterg punct atasat acestei audio?
-dialog.openoptions.title=Optiuni deschidere
-dialog.load.table.field=Cimp
+dialog.openoptions.title=Op\u021biuni deschidere
+dialog.openoptions.filesnippet=Extras din fi\u0219ier
+dialog.load.table.field=C\u00e2mp
 dialog.load.table.datatype=Tip data
 dialog.load.table.description=Descriere
-dialog.delimiter.label=Delimitator cimp
-dialog.delimiter.comma=Virgula ,
+dialog.delimiter.label=Delimitator c\u00e2mp
+dialog.delimiter.comma=Virgul\u0103 ,
 dialog.delimiter.tab=Tab
-dialog.delimiter.space=Spatiu
-dialog.delimiter.semicolon=Punct si virgula :
-dialog.delimiter.other=Alte
-dialog.openoptions.deliminfo.records=inregistrari, cu
-dialog.openoptions.deliminfo.fields=cimpuri
-dialog.openoptions.deliminfo.norecords=Nu sunt inregistrari
-dialog.openoptions.altitudeunits=Unit\u0103\u0163i de altitudini
-dialog.openoptions.speedunits=Unit\u0103\u0163i de viteza
-dialog.openoptions.vertspeedunits=Unit\u0103\u0163i de viteza vertical\u0103
+dialog.delimiter.space=Spa\u021biu
+dialog.delimiter.semicolon=Punct \u0219i virgul\u0103 ;
+dialog.delimiter.other=Altele
+dialog.openoptions.deliminfo.records=\u00eenregistr\u0103ri, cu
+dialog.openoptions.deliminfo.fields=c\u00e2mpuri
+dialog.openoptions.deliminfo.norecords=Nu sunt \u00eenregistr\u0103ri
+dialog.openoptions.altitudeunits=Unit\u0103\u0163i de altitudine
+dialog.openoptions.speedunits=Unit\u0103\u0163i de vitez\u0103
+dialog.openoptions.vertspeedunits=Unit\u0103\u0163i de vitez\u0103 vertical\u0103
+dialog.openoptions.vspeed.positiveup=Vitezele pozitive \u00een sus
+dialog.openoptions.vspeed.positivedown=Vitezele pozitive \u00een jos
+dialog.open.contentsdoubled=Acest fi\u0219ier con\u021bine dou\u0103 copii ale aceluia\u0219i punct,\nonce ca waypoint-uri \u0219i ca puncte de traseu.
+dialog.selecttracks.intro=Alege\u021bi traseul(traseele) pentru \u00eenc\u0103rcare.
 dialog.selecttracks.noname=F\u0103r\u0103 nume
-dialog.jpegload.subdirectories=Include subdirectori
-dialog.jpegload.loadjpegswithoutcoords=Include fotografii fara coordonate
+dialog.jpegload.subdirectories=Include subdirectoarele
+dialog.jpegload.loadjpegswithoutcoords=Include fotografii f\u0103r\u0103 coordonate
 dialog.jpegload.loadjpegsoutsidearea=Include fotografii din afara zonei curente
 dialog.jpegload.progress.title=\u00cenc\u0103rcare fotografii
-dialog.jpegload.progress=Va rog sa asteptati, caut fotografiile
-dialog.gpsload.nogpsbabel=Nu gasesc programul gpsbabel. Continui ?
+dialog.jpegload.progress=Va rog s\u0103 a\u0219tepta\u021bi, caut fotografiile
+dialog.gpsload.nogpsbabel=Nu g\u0103sesc programul gpsbabel. Continui?
 dialog.gpsload.device=Nume dispozitiv
 dialog.gpsload.format=Format
 dialog.gpsload.getwaypoints=\u00cencarc\u0103 waypoints
@@ -165,128 +199,264 @@ dialog.addfilter.title=Adaug\u0103 filtru
 dialog.gpsbabel.filter.discard=Arunc\u0103
 dialog.gpsbabel.filter.simplify=Simplific\u0103
 dialog.gpsbabel.filter.distance=Distan\u0163\u0103
-dialog.gpsbabel.filter.interpolate=Interpolare
+dialog.gpsbabel.filter.interpolate=Interpoleaz\u0103
 dialog.gpsbabel.filter.discard.intro=Arunc\u0103 puncte dac\u0103
 dialog.gpsbabel.filter.discard.hdop=Hdop >
 dialog.gpsbabel.filter.discard.vdop=Vdop >
 dialog.gpsbabel.filter.discard.numsats=Num\u0103r de sateli\u0163i <
+dialog.gpsbabel.filter.discard.nofix=Punctul nu are fix GPS
+dialog.gpsbabel.filter.discard.unknownfix=Punctul are fix GPS necunoscut
+dialog.gpsbabel.filter.simplify.intro=\u0218terge punctele dac\u0103
 dialog.gpsbabel.filter.simplify.maxpoints=Num\u0103r de puncte <
+dialog.gpsbabel.filter.simplify.maxerror=sau erori de distan\u021b\u0103 <
+dialog.gpsbabel.filter.simplify.crosstrack=\u00een lungul traseului
 dialog.gpsbabel.filter.simplify.length=diferen\u0163\u0103 de lungime
+dialog.gpsbabel.filter.simplify.relative=relativ la HDOP
+dialog.gpsbabel.filter.distance.intro=\u0218terge punctele dac\u0103 sunt aproape de puncte anterioare
 dialog.gpsbabel.filter.distance.distance=Dac\u0103 distan\u0163\u0103 <
 dialog.gpsbabel.filter.distance.time=\u0219i diferen\u0163\u0103 de timp <
-dialog.gpsbabel.filter.interpolate.distance=Dac\u0103 distan\u0163\u0103 >
-dialog.gpsbabel.filter.interpolate.time=sau diferen\u0163\u0103 de timp >
+dialog.gpsbabel.filter.interpolate.intro=Adaug\u0103 puncte \u00eentre punctele existente
+dialog.gpsbabel.filter.interpolate.distance=Dac\u0103 distan\u0163a >
+dialog.gpsbabel.filter.interpolate.time=sau diferen\u0163a de timp >
 dialog.saveoptions.title=Salvare fi\u015fier
-dialog.save.table.field=Cimp
-dialog.save.table.hasdata=Date
+dialog.save.fieldstosave=C\u00e2mpuri ce urmeaz\u0103 a fi salvate
+dialog.save.table.field=C\u00e2mp
+dialog.save.table.hasdata=Con\u021bine date
 dialog.save.table.save=Salvare
+dialog.save.headerrow=Salveaza cap tabel
 dialog.save.coordinateunits=Format coordonate
-dialog.save.altitudeunits=Unit\u0103\u0163i de altitudini
+dialog.save.altitudeunits=Unit\u0103\u0163i de altitudine
 dialog.save.timestampformat=Format de timp
 dialog.save.overwrite.title=Fi\u015fierul exist\u0103
 dialog.save.overwrite.text=Fi\u015fierul exist\u0103. \u00cel suprascriu?
+dialog.save.notypesselected=Niciun tip de punct nu a fost selectat
 dialog.exportkml.text=Titlu
-dialog.exportkml.imagesize=Dimensiune imaginii
+dialog.exportkml.altitude=Altitudini absolute (pentru avia\u021bie)
+dialog.exportkml.kmz=Comprim\u0103 pentru a produce fi\u0219ier KMZ
+dialog.exportkml.exportimages=Export\u0103 icoane pentru imagini \u00een KMZ
+dialog.exportkml.imagesize=Dimensiune icoane imagini \u00een KMZ
 dialog.exportkml.trackcolour=Culoarea liniei
+dialog.exportkml.standardkml=KML standard
+dialog.exportkml.extendedkml=KML extins cu date cronologice
 dialog.exportgpx.name=Nume
 dialog.exportgpx.desc=Descriere
+dialog.exportgpx.includetimestamps=Include date cronologice
+dialog.exportgpx.copysource=Copiaz\u0103 sursa xml
 dialog.exportgpx.encoding=Codare
 dialog.exportgpx.encoding.system=Sistem
 dialog.exportgpx.encoding.utf8=UTF-8
+dialog.exportpov.text=Introduce\u021bi parametrii pentru export POV
 dialog.exportpov.font=Fontul
 dialog.exportpov.camerax=Vedere X
 dialog.exportpov.cameray=Vedere Y
 dialog.exportpov.cameraz=Vedere Z
 dialog.exportpov.modelstyle=Stilul
+dialog.exportpov.ballsandsticks=Bile \u0219i be\u021be
+dialog.exportpov.tubesandwalls=Tuburi \u0219i pere\u021bi
+dialog.3d.warningtracksize=Acest traseu are un num\u0103r mare de puncte pe care Java3D ar putea s\u0103 nu fie capabil s\u0103-l afi\u0219eze. Sigur dori\u021bi s\u0103 continua\u021bi?
 dialog.3d.useterrain=Arat\u0103 teren
-dialog.3d.terraingridsize=Dimensiune a grilei
-dialog.exportpov.baseimage=Imagine cartografice
-dialog.baseimage.title=Imagine cartografice
+dialog.3d.terraingridsize=Dimensiunea grilei
+dialog.exportpov.baseimage=Imagine cartografic\u0103
+dialog.exportpov.cannotmakebaseimage=Imaginea cartografic\u0103 nu poate fi scris\u0103
+dialog.baseimage.title=Imagine cartografic\u0103
+dialog.baseimage.useimage=Folose\u0219te imaginea
+dialog.baseimage.mapsource=Sursa h\u0103r\u021bii
 dialog.baseimage.zoom=Nivel de zoom
 dialog.baseimage.incomplete=Imagine incomplet\u0103
-dialog.baseimage.tiles=Tigla
+dialog.baseimage.tiles=\u021aigle
+dialog.baseimage.size=Dimensiunea imaginii
+dialog.exportsvg.text=Alege\u021bi parametrii pentru export SVG
 dialog.exportsvg.phi=Azimut \u03d5
 dialog.exportsvg.theta=\u00cenclina\u0163ie \u03b8
+dialog.exportsvg.gradients=Folose\u0219te gradien\u021bi pentru umbrire
+dialog.exportimage.noimagepossible=Imaginile hart\u0103 trebuie sa fie salvate \u00een cache pe disc pentru a putea fi folosite la export.
+dialog.exportimage.drawtrack=Deseneaz\u0103 traseu pe hart\u0103
+dialog.exportimage.drawtrackpoints=Deseneaz\u0103 punctele traseului
+dialog.exportimage.textscalepercent=Factor de scalare a textului (%)
+dialog.pointtype.desc=Salveaz\u0103 urm\u0103toarele tipuri de puncte:
 dialog.pointtype.track=Puncte de traseu
-dialog.pointtype.waypoint=Waypoints
+dialog.pointtype.waypoint=Waypoint-uri
 dialog.pointtype.photo=Puncte foto
 dialog.pointtype.audio=Puncte audio
-dialog.pointtype.selection=Doar interval
-dialog.undo.title=Anulare
-dialog.pointedit.title=Editare punct
-dialog.pointedit.intro=V\u0103 rog selecta\u0163i r\u00e2ndul care va fi editat
-dialog.pointedit.table.field=Cimp
+dialog.pointtype.selection=Doar intervalul selectat
+dialog.confirmreversetrack.title=Confirm\u0103 inversarea
+dialog.confirmreversetrack.text=Acest traseu con\u021bine informa\u021bii cronologice a c\u0103ror ordine va fi incorect\u0103 dup\u0103 inversare.\nSigur dori\u021bi s\u0103 inversa\u021bi selec\u021bia?
+dialog.confirmcutandmove.title=Confirm\u0103 t\u0103irea \u0219i mutarea
+dialog.confirmcutandmove.text=Acest traseu con\u021bine informa\u021bii cronologice a c\u0103ror ordine va fi incorect\u0103 dup\u0103 mutare.\n Sigur dori\u021bi mutarea sec\u021biunii?
+dialog.interpolate.parameter.text=Num\u0103rul de puncte de inserat \u00eentre fiecare pereche de puncte
+dialog.interpolate.betweenwaypoints=Interpolez \u00eentre waypoint-uri?
+dialog.undo.title=Anuleaz\u0103
+dialog.undo.pretext=Selecta\u021bi opera\u021biile ce vor fi anulate
+dialog.undo.none.title=Nu se poate anula
+dialog.undo.none.text=Nu exist\u0103 opera\u021bii pentru anulare!
+dialog.clearundo.title=\u0218terge lista de anul\u0103ri
+dialog.clearundo.text=Sigur vre\u021bi s\u0103 \u0219terge\u021bi lista de anul\u0103ri?\nToat\u0103 \u00eenforma\u021bia de anulare va fi pierdut\u0103!
+dialog.pointedit.title=Editeaz\u0103 punct
+dialog.pointedit.intro=Selecta\u0163i r\u00e2ndul care va fi editat
+dialog.pointedit.table.field=C\u00e2mp
+dialog.pointedit.nofield=Niciun c\u00e2mp selectat
 dialog.pointedit.table.value=Valoare
 dialog.pointnameedit.name=Nume de waypoint
 dialog.pointnameedit.uppercase=Litere MARI
 dialog.pointnameedit.lowercase=Litere mici
+dialog.pointnameedit.titlecase=Prima Liter\u0103 Mare
+dialog.addtimeoffset.add=Adaug\u0103 timp
+dialog.addtimeoffset.subtract=Scade timp
 dialog.addtimeoffset.days=Zile
 dialog.addtimeoffset.hours=Ore
 dialog.addtimeoffset.minutes=Minute
+dialog.addtimeoffset.notimestamps=Nu poate fi ad\u0103ugat un decalaj de timp pentru c\u0103 selec\u021bia nu con\u021bine date cronologice
+dialog.findwaypoint.intro=Introduce\u021bi o parte a numelui waypoint-ului
 dialog.findwaypoint.search=C\u0103utare
+dialog.saveexif.title=Salveaz\u0103 Exif
+dialog.saveexif.intro=Selecteaz\u0103 fotografiile ce  urmeaz\u0103 a fi salvate folosind bifele
+dialog.saveexif.nothingtosave=Coordonatele sunte neschimbate, nu e nimic de salvat
+dialog.saveexif.noexiftool=Aplica\u021bia exiftool nu a fost g\u0103sit\u0103. Continui?
 dialog.saveexif.table.photoname=Nume
-dialog.saveexif.title=Salvare Exif
 dialog.saveexif.table.status=Stare
-dialog.saveexif.table.save=Salveaza
+dialog.saveexif.table.save=Salveaz\u0103
 dialog.saveexif.photostatus.connected=Conectat
 dialog.saveexif.photostatus.disconnected=Deconectat
 dialog.saveexif.photostatus.modified=Modificat
 dialog.saveexif.overwrite=Suprascrie fi\u015fiere
+dialog.saveexif.force=Ignor\u0103 erorile minore
 dialog.charts.xaxis=Axa X
 dialog.charts.yaxis=Axa Y
 dialog.charts.output=Rezultat
+dialog.charts.screen=Rezultatul pe ecran
+dialog.charts.svg=Rezultatul \u00een fi\u0219ier SVG
 dialog.charts.svgwidth=L\u0103\u021bime SVG
 dialog.charts.svgheight=\u00cen\u0103l\u021bime SVG
-dialog.distances.column.from=De punct
+dialog.charts.needaltitudeortimes=Traseul trebuie s\u0103 con\u021bina altitudini sau date cronologice pentru a crea grafice
+dialog.charts.gnuplotnotfound=Aplica\u021bia gnuplot nu a fost g\u0103sit\u0103 la calea dat\u0103
+dialog.distances.intro=Distan\u021be \u00een linie dreapt\u0103 \u00eentre puncte
+dialog.distances.column.from=De la punct
 dialog.distances.column.to=Spre punct
 dialog.distances.currentpoint=Punct curent
+dialog.distances.toofewpoints=Aceast\u0103 func\u021bie are nevoie de waypoint-uri pentru a calcula distan\u021ba dintre ele
+dialog.fullrangedetails.intro=Detalii pentru invervalul selectat
+dialog.fullrangedetails.coltotal=Cu tot cu pauze
+dialog.fullrangedetails.colsegments=F\u0103r\u0103 pauze
 dialog.estimatetime.details=Detalii
-dialog.estimatetime.parameters=Parametrii
+dialog.estimatetime.gentle=Domol
+dialog.estimatetime.steep=Abrupt
+dialog.estimatetime.climb=Urcare
+dialog.estimatetime.descent=Cobor\u00e2re
+dialog.estimatetime.parameters=Parametri
 dialog.estimatetime.parameters.timefor=Durata pentru
 dialog.estimatetime.results=Rezultate
 dialog.estimatetime.results.estimatedtime=Durata estimat\u0103
 dialog.estimatetime.results.actualtime=Durata (measured)
-dialog.learnestimationparams.averageerror=Eroare estimat
-dialog.learnestimationparams.combinedresults=Rezultate combinat
+dialog.estimatetime.error.nodistance=Estim\u0103rile de timp necesit\u0103 puncte de traseu conectate, pentru a putea fi calculat\u0103 distan\u021ba
+dialog.estimatetime.error.noaltitudes=Selec\u021bia nu include informa\u021bii de altitudine
+dialog.learnestimationparams.intro=Ace\u0219tia sunt parametrii calcula\u021bi pentru acest traseu
+dialog.learnestimationparams.combine=Ace\u0219ti parametri pot fi combina\u021bi cu valorile curente
+dialog.learnestimationparams.averageerror=Eroare estimat\u0103
+dialog.learnestimationparams.combinedresults=Rezultate combinate
+dialog.learnestimationparams.weight.100pccurrent=P\u0103streaz\u0103 valorile curente
 dialog.learnestimationparams.weight.current=curente
 dialog.learnestimationparams.weight.calculated=calculate
+dialog.learnestimationparams.weight.50pc=Media dintre valorile curente \u0219i cele calculate
+dialog.learnestimationparams.weight.100pccalculated=Folose\u0219te valorile calculate
+dialog.setmapbg.intro=Alege\u021bi una din sursele h\u0103r\u021bii sau ad\u0103uga\u021bi una nou\u0103
+dialog.addmapsource.title=Adaug\u0103 surs\u0103 noua de hart\u0103
 dialog.addmapsource.sourcename=Nume
+dialog.addmapsource.layer1url=URL pentru primul strat
+dialog.addmapsource.layer2url=URL pentru cel de-al doilea strat (op\u021bional)
+dialog.addmapsource.maxzoom=Nivelul de apropiere maxim
 dialog.addmapsource.noname=F\u0103r\u0103 nume
 dialog.gpsies.column.name=Nume
 dialog.gpsies.column.length=Lungime
 dialog.gpsies.description=Descriere
 dialog.gpsies.nodescription=F\u0103r\u0103 descriere
-dialog.gpsies.nonefound=Nu a fost g\u0103sit
+dialog.gpsies.nonefound=Nu a fost g\u0103sit niciun traseu
 dialog.gpsies.username=Gpsies username
 dialog.gpsies.password=Gpsies parol\u0103
 dialog.gpsies.keepprivate=Traseu privat
+dialog.gpsies.confirmopenpage=Deschid pagin\u0103 web pentru traseul \u00eenc\u0103rcat?
 dialog.gpsies.activities=Activit\u0103\u0163i
+dialog.gpsies.activity.trekking=Mers pe munte
+dialog.gpsies.activity.walking=Mers pe jos
+dialog.gpsies.activity.jogging=Alergare
+dialog.gpsies.activity.biking=Biciclet\u0103
+dialog.gpsies.activity.motorbiking=Motociclet\u0103
+dialog.gpsies.activity.snowshoe=Mers cu rachete de z\u0103pad\u0103
+dialog.gpsies.activity.sailing=Navigare
+dialog.gpsies.activity.skating=Role
+dialog.mapillary.nonefound=Nicio fotografie nu a fost g\u0103sit\u0103
 dialog.wikipedia.column.name=Nume
 dialog.wikipedia.column.distance=Distan\u0163\u0103
 dialog.wikipedia.nonefound=Nu a fost g\u0103sit
-dialog.correlate.select.photoname=Nume
-dialog.correlate.select.timediff=Diferenta de timp
+dialog.geocaching.nonefound=Nu a fost g\u0103sit
+dialog.correlate.notimestamps=Corelarea cu fotografiile nu se poate realiza pentru c\u0103 \u00een puncte nu exist\u0103 informa\u021bie cronologic\u0103
+dialog.correlate.nouncorrelatedphotos=Nu exist\u0103 fotografii necorelate. Continui?
+dialog.correlate.nouncorrelatedaudios=Nu exist\u0103 clipuri audio necorelate. Continui?
+dialog.correlate.photoselect.intro=Alege\u021bi una din fotografiile corelate ca referin\u021b\u0103 pentru decalajul de timp
+dialog.correlate.select.photoname=Nume foto
+dialog.correlate.select.timediff=Diferen\u021ba de timp
+dialog.correlate.select.photolater=Foto mai t\u00e2rziu
+dialog.correlate.options.intro=Alege\u021bi op\u021biunile pentru corelare automat\u0103
+dialog.correlate.options.offsetpanel=Decalaj de timp
+dialog.correlate.options.offset=Decalaj
 dialog.correlate.options.offset.hours=ore,
-dialog.correlate.options.offset.minutes=minute,
+dialog.correlate.options.offset.minutes=minute \u0219i
 dialog.correlate.options.offset.seconds=secunde
+dialog.correlate.options.photolater=Foto dup\u0103 punct
+dialog.correlate.options.pointlaterphoto=Punct dup\u0103 foto
+dialog.correlate.options.audiolater=Audio dup\u0103 punct
+dialog.correlate.options.pointlateraudio=Punct dup\u0103 audio
+dialog.correlate.options.limitspanel=Limite corelare
+dialog.correlate.options.notimelimit=F\u0103r\u0103 limit\u0103 de timp
+dialog.correlate.options.timelimit=Limit\u0103 de timp
+dialog.correlate.options.nodistancelimit=F\u0103r\u0103 limit\u0103 de distan\u021b\u0103
+dialog.correlate.options.distancelimit=Limit\u0103 de distan\u021b\u0103
 dialog.correlate.options.correlate=Corelare
-dialog.correlate.timestamp.beginning=\u00cenceptutul
+dialog.correlate.alloutsiderange=Toate elementele sunt \u00een afara intervalului de timp din traseu, deci nu pot fi corelate.\n \u00cencerca\u021bi schimbarea decalajului de timp sau corela\u021bi manual cel pu\u021bin un element.
+dialog.correlate.filetimes=Informa\u021bia cronologic\u0103 din fi\u0219ier arat\u0103:
+dialog.correlate.filetimes2=a clipului audio
+dialog.correlate.correltimes=Pentru corelare folose\u0219te:
+dialog.correlate.timestamp.beginning=\u00cenceputul
 dialog.correlate.timestamp.middle=Mijlocul
 dialog.correlate.timestamp.end=Sf\u00e2r\u015fitul
-dialog.correlate.select.audioname=Nume
+dialog.correlate.audioselect.intro=Alege\u021bi unul din clipurile audio corelate ca referin\u021b\u0103 pentru decalajul de timp
+dialog.correlate.select.audioname=Nume clip
+dialog.correlate.select.audiolater=Audio mai t\u00e2rziu
+dialog.rearrangewaypoints.desc=Alege\u021bi destina\u021bia \u0219i ordinea de sortare a waypoint-urilor
+dialog.rearrangephotos.desc=Alege\u021bi destina\u021bia \u0219i ordinea de sortare a punctelor foto
 dialog.rearrange.tostart=Toate la inceputul fi\u015fierului
-dialog.rearrange.toend=Toate la sfarsitul fi\u015fierului
+dialog.rearrange.toend=Toate la sf\u00e2r\u0219itul fi\u015fierului
 dialog.rearrange.tonearest=Fiecare la punctul cel mai apropiat al traseului
 dialog.rearrange.nosort=Nu sunt sortate
-dialog.rearrange.sortbyfilename=Sorta dup\u0103 nume de fi\u015fier
-dialog.rearrange.sortbyname=Sorta dup\u0103 nume
-dialog.rearrange.sortbytime=Sorta dup\u0103 timp
+dialog.rearrange.sortbyfilename=Sortez\u0103 dup\u0103 nume de fi\u015fier
+dialog.rearrange.sortbyname=Sorteaz\u0103 dup\u0103 nume
+dialog.rearrange.sortbytime=Sorteaz\u0103 dup\u0103 timp
+dialog.compress.closepoints.title=\u0218tergere puncte apropiate
+dialog.compress.closepoints.paramdesc=Anvergur\u0103
+dialog.compress.wackypoints.title=\u0218tergere puncte aberante
+dialog.compress.wackypoints.paramdesc=Factor de distan\u021b\u0103
+dialog.compress.singletons.title=\u0218tergere puncte singulare
+dialog.compress.singletons.paramdesc=Factor de distan\u021b\u0103
+dialog.compress.duplicates.title=\u0218tergerea duplicatelor
+dialog.compress.douglaspeucker.title=Compresie Douglas-Peucker
+dialog.compress.douglaspeucker.paramdesc=Anvergur\u0103
+dialog.compress.summarylabel=Puncte ce vor fi \u0219terse
+dialog.compress.confirm=Au fost marcate %d puncte. \u0218terg aceste puncte?
+dialog.compress.confirmnone=niciun punct nu a fost marcat
+dialog.deletemarked.nonefound=Niciun punct nu a putut fi \u0219ters
+dialog.pastecoordinates.desc=Scrie\u021bi sau copia\u021bi aici coordonatele
 dialog.pastecoordinates.coords=Coordonate
+dialog.pastecoordinates.nothingfound=V\u0103 rug\u0103m verifica\u021bi coordonatele \u0219i \u00eencerca\u021bi din nou.
+dialog.help.help=V\u0103 rug\u0103m vizita\u021bi \n http://gpsprune.activityworkshop.net/\npentru mai multe informa\u021bii, inclusiv un nou manual PDF care poate fi cump\u0103rat.
 dialog.about.version=Versiunea
-dialog.about.build=Construi
-dialog.about.languages=Limbi
-dialog.about.systeminfo=Informa\u0163ii a sistemului
+dialog.about.build=Versiunea minor\u0103
+dialog.about.summarytext1=GpsPrune e o aplica\u021bie pentru \u00eenc\u0103rcarea, afi\u0219area \u0219i editarea datelor salvate de receptoarele GPS.
+dialog.about.summarytext2=Este distribuit\u0103 sub licen\u021b\u0103 Gnu GPL pentru a permite utilizarea gratuit\u0103 \u00een lumea \u00eentreag\u0103<br>\u0219i pentru a permite oricui dore\u0219te \u00eembun\u0103t\u0103\u021biea aplica\u021biei.<br>Copierea, redistribuirea \u0219i modificarea sunt permise \u0219i \u00eencurajate<br>\u00een conformitate cu condi\u021biile descrise \u00een fi\u0219ierul <code>license.txt</code> care este inclus \u00een aplica\u021bie.
+dialog.about.summarytext3=V\u0103 rug\u0103m vizita\u021bi <code style="font-weight:bold">http://activityworkshop.net/</code> pentru mai multe informa\u021bii \u0219i indicii, inclusiv<br>un nou manual \u00een format PDF care poate fi cump\u0103rat.
+dialog.about.languages=Traduceri
+dialog.about.translatedby=Textele romanesti sunt de Rothermographer, Oana \u0219i Cristian
+dialog.about.systeminfo=Informa\u0163ii sistem
 dialog.about.systeminfo.os=Sistem de operare
+dialog.about.systeminfo.java=Java Runtime
 dialog.about.systeminfo.java3d=Java3d instalat
 dialog.about.systeminfo.povray=Povray instalat
 dialog.about.systeminfo.exiftool=Exiftool instalat
@@ -299,33 +469,112 @@ dialog.about.systeminfo.exiflib.external=Extern
 dialog.about.systeminfo.exiflib.external.failed=Extern (absent)
 dialog.about.yes=Da
 dialog.about.no=Nu
+dialog.about.credits=Mul\u021bumiri
+dialog.about.credits.code=Codul GpsPune a fost scris de
+dialog.about.credits.exifcode=Codul Exif de
+dialog.about.credits.icons=Unele icoane au fost luate de la
+dialog.about.credits.translators=Traduc\u0103tori
+dialog.about.credits.translations=La traduceri au ajutat
+dialog.about.credits.devtools=Unelte de dezvoltare
+dialog.about.credits.othertools=Alte unelte
+dialog.about.credits.thanks=Mul\u021bumiri
 dialog.about.readme=Cite\u015fte-m\u0103
-dialog.checkversion.releasedate1=Aceasta versiune noua a fost lansapa pe
+dialog.checkversion.error=Num\u0103rul versiunii nu a putut fi verificat.\nVerifica\u021bi conexiunea Internet.
+dialog.checkversion.uptodate=Folosi\u021bi cea mai recent\u0103 versiune a GpsPrune.
+dialog.checkversion.newversion1=A ap\u0103rut o nou\u0103 versiune GpsPrune. Cea mai nou\u0103 versiune este
+dialog.checkversion.newversion2=.
+dialog.checkversion.releasedate1=Aceast\u0103 versiune nou\u0103 a fost lansat\u0103 la
 dialog.checkversion.releasedate2=.
+dialog.checkversion.download=Pentru a desc\u0103rca noua versiune merge\u021bi la http://gpsprune.activityworkshop.net/download.html.
+dialog.keys.intro=Pute\u021bi folosi urm\u0103toarele scurt\u0103turi \u00een locul mouse-ului
+dialog.keys.keylist=<table><tr><td>Taste s\u0103ge\u021bi</td><td>Mut\u0103 harta st\u00e2nga, dreapta, sus, jos</td></tr><tr><td>Ctrl + s\u0103geat\u0103 st\u00e2nga, dreapta</td><td>Selecteaz\u0103 punctul anterior sau urm\u0103tor</td></tr><tr><td>Ctrl + s\u0103geat\u0103 sus, jos</td><td>Aproprie sau \u00eendep\u0103rteaz\u0103</td></tr><tr><td>Ctrl + PgUp, PgDown</td><td>Selecteaz\u0103 segmentul anterior sau urm\u0103tor</td></tr><tr><td>Ctrl + Home, End</td><td>Selecteaz\u0103 primul, ultimul punct</td></tr><tr><td>Del</td><td>\u0218terge punctul curent</td></tr></table>
+dialog.keys.normalmodifier=Ctrl
+dialog.keys.macmodifier=Command
+dialog.saveconfig.desc=Urm\u0103toarele set\u0103ri pot fi salvate \u00eentr-un fi\u0219ier de configur\u0103ri :
+dialog.saveconfig.prune.trackdirectory=Director trasee
+dialog.saveconfig.prune.photodirectory=Director foto
 dialog.saveconfig.prune.languagecode=Limb\u0103 (RO)
 dialog.saveconfig.prune.languagefile=Fi\u015fier de limba
 dialog.saveconfig.prune.gpsdevice=Dispozitiv GPS
 dialog.saveconfig.prune.gpsformat=Format GPS
-dialog.setcolours.background=Fund
+dialog.saveconfig.prune.povrayfont=Font Povray
+dialog.saveconfig.prune.gnuplotpath=Calea c\u0103tre gnuplot
+dialog.saveconfig.prune.gpsbabelpath=Calea c\u0103tre gpsbabel
+dialog.saveconfig.prune.exiftoolpath=Calea c\u0103tre exiftool
+dialog.saveconfig.prune.mapsource=Surs\u0103 hart\u0103 selectat\u0103
+dialog.saveconfig.prune.mapsourcelist=Surse hart\u0103
+dialog.saveconfig.prune.diskcache=Cache hart\u0103
+dialog.saveconfig.prune.kmzimagewidth=Dimensiuni imagini \u00een KMZ
+dialog.saveconfig.prune.colourscheme=Schem\u0103 de culoare
+dialog.saveconfig.prune.linewidth=Grosime linie
+dialog.saveconfig.prune.kmltrackcolour=Culoar track KML
+dialog.saveconfig.prune.autosavesettings=Set\u0103ri salv\u0103ri automate
+dialog.setpaths.intro=Dac\u0103 dori\u021bi pute\u021bi alege calea c\u0103tre aplica\u021bii externe
+dialog.setpaths.found=Cale g\u0103sit\u0103?
+dialog.addaltitude.noaltitudes=Intervalul nu con\u021bine altitudini
+dialog.addaltitude.desc=Decalaj altitudine
+dialog.lookupsrtm.overwritezeros=Suprascriu altitudinile cu valoare zero?
+dialog.setcolours.intro=Face\u021bi click pe un petec de culoare pentru a schimba culoarea
+dialog.setcolours.background=Fundal
+dialog.setcolours.borders=Margini
 dialog.setcolours.lines=Linii
 dialog.setcolours.primary=Primar
 dialog.setcolours.secondary=Secundar
 dialog.setcolours.point=Puncte
 dialog.setcolours.selection=Selec\u0163ie
 dialog.setcolours.text=Text
-dialog.colourchooser.title=Selectare culoare
+dialog.colourchooser.title=Alege\u021bi culoare
 dialog.colourchooser.red=Ro\u0219u
 dialog.colourchooser.green=Verde
 dialog.colourchooser.blue=Albastru
+dialog.colourer.intro=Un algoritm de colorare poate da punctelor culori diferite
+dialog.colourer.type=Tip algoritm colorare
 dialog.colourer.type.none=Nimic
+dialog.colourer.type.byfile=Dup\u0103 fi\u0219ier
+dialog.colourer.type.bysegment=Dup\u0103 segment
+dialog.colourer.type.byaltitude=Dup\u0103 altitudine
+dialog.colourer.type.byspeed=Dup\u0103 vitez\u0103
+dialog.colourer.type.byvertspeed=Dup\u0103 viteza vertical\u0103
+dialog.colourer.type.bygradient=Dup\u0103 gradient
+dialog.colourer.type.bydate=Dup\u0103 dat\u0103
+dialog.colourer.start=Culoare de \u00eenceput
+dialog.colourer.end=Culoare de sf\u00e2r\u0219it
+dialog.colourer.maxcolours=Num\u0103rul maxim de culori
+dialog.setlanguage.firstintro=Pute\u021bi folosi una din limbile incluse,<p>sau pute\u021bi alege un fi\u0219ier text pe care s\u0103-l folosi\u021bi.
+dialog.setlanguage.secondintro=Trebuie s\u0103 salva\u021bi set\u0103rile \u0219i s\u0103<p>restarta\u021bi GpsPrune pentru a schimba limba
 dialog.setlanguage.language=Limb\u0103
 dialog.setlanguage.languagefile=Fi\u015fier de limba
-dialog.diskcache.table.tiles=Tigla
-dialog.searchwikipedianames.search=C\u0103utare :
+dialog.setlanguage.endmessage=Salva\u021bi set\u0103rile \u0219i restarta\u021bi GpsPrune\npentru ca schimbarea de limb\u0103 s\u0103 aib\u0103 efect.
+dialog.setlanguage.endmessagewithautosave=Restarta\u021bi GpsPrune pentru ca schimbare limbii s\u0103 aib\u0103 efect.
+dialog.diskcache.save=Salveaz\u0103 imaginile h\u0103r\u021bii pe disc
+dialog.diskcache.dir=Director cache
+dialog.diskcache.createdir=Creaz\u0103 director
+dialog.diskcache.nocreate=Directorul cache nu a putut fi creat
+dialog.diskcache.cannotwrite=\u021aiglele h\u0103r\u021bii nu pot fi salvate \u00een directorul selectat
+dialog.diskcache.table.path=Cale
+dialog.diskcache.table.usedby=Folosit de
+dialog.diskcache.table.zoom=Nivel apropiere
+dialog.diskcache.table.tiles=\u021aigle
+dialog.diskcache.table.megabytes=Megabytes
+dialog.diskcache.tileset=Set \u021bigle (tile-uri)
+dialog.diskcache.tileset.multiple=multiple
+dialog.diskcache.deleteold=\u015eterge imaginile vechi
+dialog.diskcache.maximumage=V\u00e2rsta maxim\u0103 (zile)
+dialog.diskcache.deleteall=\u015eterge toate imaginile
+dialog.diskcache.deleted=Au fost \u0219terse %d fi\u0219iere din cache
+dialog.deletefieldvalues.intro=Alege\u021bi c\u00e2mpurile ce urmeaz\u0103 a fi \u0219terse din intervalul curent
+dialog.deletefieldvalues.nofields=Nu poate fi \u0219ters nici un c\u00e2mp pentru intervalul dat
+dialog.setlinewidth.text=Introduce\u021bi grosimea liniilor ce vor fi desenate pentru trasee (1-3)
+dialog.downloadosm.desc=Confirma\u021bi desc\u0103rcarea datelor brute OSM pentru zona specificat\u0103:
+dialog.searchwikipedianames.search=Caut\u0103:
 dialog.weather.location=Loca\u0163ie
+dialog.weather.update=Prognoz\u0103 actualizat\u0103
 dialog.weather.sunrise=R\u0103s\u0103rit
 dialog.weather.sunset=Apus de soare
+dialog.weather.temperatureunits=Temperaturi
 dialog.weather.currentforecast=Vremea curent\u0103
+dialog.weather.dailyforecast=Prognoz\u0103 zilnic\u0103
+dialog.weather.3hourlyforecast=Prognoz\u0103 la fiecare 3 ore
 dialog.weather.day.now=Vremea curent\u0103
 dialog.weather.day.today=Ast\u0103zi
 dialog.weather.day.tomorrow=M\u00e2ine
@@ -336,49 +585,109 @@ dialog.weather.day.thursday=Joi
 dialog.weather.day.friday=Vineri
 dialog.weather.day.saturday=S\u00e2mb\u0103t\u0103
 dialog.weather.day.sunday=Duminic\u0103
+dialog.weather.wind=V\u00e2nt
+dialog.weather.temp=Temp
+dialog.weather.humidity=Umiditate
+dialog.weather.creditnotice=Acest set de date este oferit de openweathermap.org. Site-ul lor de web are mai multe detalii.
+dialog.deletebydate.onlyonedate=Toate punctele au fost \u00eenregistrate la aceea\u0219i dat\u0103.
+dialog.deletebydate.intro=Pentru fiecare dat\u0103 din traseu pute\u021bi alege s\u0103 \u0219terge\u021bi sau s\u0103 p\u0103stra\u021bi punctele
+dialog.deletebydate.nodate=F\u0103r\u0103 info cronologic
+dialog.deletebydate.column.keep=P\u0103streaz\u0103
+dialog.deletebydate.column.delete=\u015eterge
+dialog.setaltitudetolerance.text.metres=Limita (\u00een metri) sub care micile urc\u0103ri \u0219i cobor\u00e2ri vor fi ignorate
+dialog.setaltitudetolerance.text.feet=Limita (\u00een picioare) sub care micile urc\u0103ri \u0219i cobor\u00e2ri vor fi ignorate
+dialog.autoplay.duration=Durat\u0103 (sec)
+dialog.autoplay.usetimestamps=Folose\u0219te puncte cronologice
+dialog.autoplay.rewind=\u00cenapoi la \u00eenceput
+dialog.autoplay.pause=Pauz\u0103
+dialog.autoplay.play=Redare
+
+# 3d window
+dialog.3d.title=Vedere GpsPrune Three-d
+dialog.3d.altitudefactor=Factorul de exagerare a altitudinii
 
 # Confirm messages
-confirm.loadfile=Date incarcate din fi\u015fier
+confirm.loadfile=Date \u00eenc\u0103rcate din fi\u015fier
 confirm.save.ok1=Salvat cu succes
 confirm.save.ok2=puncte \u00een
+confirm.deletepoint.single=punct a fost \u0219ters
+confirm.deletepoint.multi=puncte au fost \u0219terse
+confirm.point.edit=puncte editate
+confirm.mergetracksegments=Segmente traseului au fost unite
+confirm.reverserange=Intervalul a fost inversat
+confirm.addtimeoffset=Decalajele de timp au fost ad\u0103ugate
+confirm.addaltitudeoffset=Decalajele de altitudine au fost ad\u0103ugate
+confirm.rearrangewaypoints=Waypoint-urile au fost rearanjate
+confirm.rearrangephotos=Fotografiile au fost rearanjate
+confirm.splitsegments=Au fost f\u0103cute %d diviz\u0103ri de segmente
+confirm.sewsegments=Au fost combinate %d segmente
+confirm.cutandmove=Selec\u021bia a fost mutat\u0103
+confirm.interpolate=Punctele au fost ad\u0103ugate
+confirm.convertnamestotimes=Numele waypoint-urile au fost convertite
+confirm.saveexif.ok=Au fost salvate %d fi\u0219iere foto
+confirm.undo.single=opera\u021bia a fost anulat\u0103
+confirm.undo.multi=opera\u021biile au fost anulate
+confirm.jpegload.single=foto a fost ad\u0103ugat\u0103
+confirm.jpegload.multi=fotografiile au fost ad\u0103ugate
 confirm.media.connect=foto/audio conectat
 confirm.photo.disconnect=foto deconectat
 confirm.audio.disconnect=audio deconectat
 confirm.media.removed=\u0219ters
+confirm.correlatephotos.single=foto a fost corelat\u0103
+confirm.correlatephotos.multi=fotografiile au fost corelate
+confirm.createpoint=punct creat
+confirm.rotatephoto=foto rotit\u0103
 confirm.running=Executare ...
+confirm.lookupsrtm=Au fost g\u0103site %d valori de altitudine
 confirm.downloadsrtm=S-au desc\u0103rcat %d fi\u015fiere
 confirm.downloadsrtm.1=S-au desc\u0103rcat %d fi\u015fier
+confirm.downloadsrtm.none=Niciun fi\u0219ier nu a fost desc\u0103rcat, ele erau deja prezente \u00een cache
+confirm.deletefieldvalues=Valorile c\u00e2mpurilor au fost \u0219terse
+confirm.audioload=Fi\u0219iere audio au fost ad\u0103ugate
+confirm.correlateaudios.single=clipul audio a fost corelat
+confirm.correlateaudios.multi=clipurile audio au fost corelate
 
-# Tips
+# Tips, shown just once when appropriate
 tip.title=Indiciu
+tip.useamapcache=Prin configurarea unui cache pe disc (Set\u0103ri -> Salvare h\u0103r\u021bi)\npute\u021bi \u00eembun\u0103t\u0103\u021bi viteza de afi\u0219are \u0219i reduce traficul de re\u021bea
+tip.learntimeparams=Rezultatele vor fi mai corecte dac\u0103 folosi\u021bi\nTraseu -> \u00cenva\u021b\u0103 parametri pentru estim\u0103ri de timp\npe traseele deja \u00eenregistrate.
+tip.downloadsrtm=Pute\u021bi \u00eembun\u0103t\u0103\u021bi viteza prin folosirea\nInternet -> Descarc\u0103 date SRTM
+tip.usesrtmfor3d=Acest traseu nu are valori de altitudine.\nPute\u021bi folosi func\u021biile SRTM pentru a aproxima altitudinile \u00een vederea 3D.
+tip.manuallycorrelateone=Decalajul de timp poate fi calculat dac\u0103 cel pu\u021bin un element e conectat.
 
 # Buttons
 button.ok=OK
-button.back=Inapoi
+button.back=\u00cenapoi
 button.next=Urmator
 button.finish=Terminat
 button.cancel=Renun\u0163\u0103
 button.overwrite=Suprascrie
-button.moveup=Muta in sus
-button.movedown=Muta in jos
-button.edit=Editare
-button.exit=Iesire
-button.close=Inchide
-button.continue=Continua
+button.moveup=Mut\u0103 \u00een sus
+button.movedown=Mut\u0103 \u00een jos
+button.edit=Editeaz\u0103
+button.exit=Ie\u0219ire
+button.close=\u00cenchide
+button.continue=Continu\u0103
 button.yes=Da
 button.no=Nu
 button.yestoall=Da pentru tot
 button.notoall=Nu pentru tot
+button.always=\u00centotdeauna
 button.select=Selectare
-button.selectall=Selecteaza tot
-button.selectnone=Deselecteaza tot
-button.load=Descarca
+button.selectall=Selecteaz\u0103 tot
+button.selectnone=Deselecteaz\u0103 tot
+button.preview=Previzualizare
+button.load=Descarc\u0103
 button.upload=Trimite
-button.guessfields=Ghici cimpuri
-button.check=Verifica
-button.delete=\u015etergere
-button.manage=Administra
-button.combine=Combina
+button.guessfields=Ghice\u0219te c\u00e2mpuri
+button.showwebpage=Deschide pagina web
+button.check=Verific\u0103
+button.resettodefaults=Revino la valorile standard
+button.browse=Browse...
+button.addnew=Adaug\u0103
+button.delete=\u015eterge
+button.manage=Administreaz\u0103
+button.combine=Combin\u0103
 
 # File types
 filetype.txt=Fi\u015fiere text
@@ -393,23 +702,32 @@ filetype.png=Fi\u015fiere PNG
 filetype.audio=Fi\u015fiere MP3, OGG, WAV
 
 # Display components
+display.nodata=Nu exist\u0103 date \u00eenc\u0103rcate
+display.noaltitudes=Traseul nu include altitudini
+display.notimestamps=Datele traseului nu includ date cronologice
+display.novalues=Datele traseului nu includ valori pentru acest c\u00e2mp
 details.trackdetails=Detalii traseul
+details.notrack=Niciun traseu \u00eenc\u0103rcat
 details.track.points=Puncte
-details.pointdetails=Detalii punctul
+details.track.file=Fi\u0219ier
+details.track.numfiles=Num\u0103rul de fi\u015fiere
+details.pointdetails=Detalii punct
 details.index.selected=Punct
-details.index.of=de
-details.photofile=Fi\u015fier
-details.rangedetails=Detalii intervalul
-details.range.selected=Selectat
+details.index.of=din
+details.nopointselection=Niciun punct selectat
+details.photofile=Fi\u015fier foto
+details.norangeselection=Niciun interval selectat
+details.rangedetails=Detalii interval
+details.range.selected=Selectat de la
 details.range.to=la
-details.altitude.to=la
+details.altitude.to=p\u00e2n\u0103 la
 details.range.climb=Urcare
 details.range.descent=Cobor\u00e2re
 details.coordformat=Format coordonate
-details.distanceunits=Unit\u0103\u0163i de distan\u0163e
+details.distanceunits=Unitate de distan\u021b\u0103
 display.range.time.secs=s
 display.range.time.mins=m
-display.range.time.hours=o
+display.range.time.hours=h
 display.range.time.days=z
 details.range.avespeed=Viteza medie
 details.range.maxspeed=Viteza maxim\u0103
@@ -417,14 +735,19 @@ details.range.numsegments=Num\u0103r de segmente
 details.range.pace=Ritm
 details.range.gradient=Gradient
 details.lists.waypoints=Waypoints
-details.lists.photos=Foto-uri
+details.lists.photos=Fotografii
 details.lists.audio=Audio
 details.photodetails=Detalii foto
+details.nophoto=Nicio foto selectat\u0103
 details.photo.loading=\u00cenc\u0103rcare
 details.photo.bearing=Direc\u0163ie
 details.media.connected=Conectat
+details.media.fullpath=Cale complet\u0103
 details.audiodetails=Detalii audio
+details.noaudio=Niciun clip audio selectat
 details.audio.file=Fi\u015fier
+details.audio.playing=Redare audio...
+map.overzoom=Nu exist\u0103 h\u0103r\u021bi la acest nivel de apropiere
 
 # Field names
 fieldname.latitude=Latitudine
@@ -436,30 +759,37 @@ fieldname.date=Data
 fieldname.waypointname=Nume
 fieldname.waypointtype=Tip
 fieldname.newsegment=Segment
-fieldname.prefix=Cimp
+fieldname.custom=Personalizat
+fieldname.prefix=C\u00e2mp
 fieldname.distance=Distan\u0163\u0103
 fieldname.duration=Durat\u0103
 fieldname.speed=Vitez\u0103
 fieldname.verticalspeed=Vitez\u0103 vertical\u0103
 fieldname.description=Descriere
+fieldname.mediafilename=Fi\u0219ier
 
 # Measurement units
+units.original=Ini\u021bial
 units.default=Implicit
 units.metres=Metri
 units.metres.short=m
+units.feet=Picioare
+units.feet.short=ft
 units.kilometres=Kilometri
 units.kilometres.short=km
 units.kilometresperhour=km pe or\u0103
-units.kilometresperhour.short=km/o
-units.miles=Mil\u0103
+units.kilometresperhour.short=km/h
+units.miles=Mile
 units.miles.short=mi
-units.milesperhour=mil\u0103 pe or\u0103
-units.milesperhour.short=mpo
-units.nauticalmiles=Mil\u0103 marin\u0103
-units.nauticalmiles.short=mm
+units.milesperhour=mile pe or\u0103
+units.milesperhour.short=mph
+units.nauticalmiles=Mile marine
+units.nauticalmiles.short=N.m.
 units.nauticalmilesperhour.short=kn
-units.metrespersec=metri pe secund
+units.metrespersec=metri pe secund\u0103
 units.metrespersec.short=m/s
+units.feetpersec=picioare pe secund\u0103
+units.feetpersec.short=ft/s
 units.hours=ore
 units.minutes=minute
 units.seconds=secunde
@@ -476,9 +806,15 @@ units.degreesfahrenheit.short=\u00b0F
 logic.and=\u0219i
 logic.or=sau
 
-# External urls
+# External urls and services
+url.googlemaps=maps.google.com
 wikipedia.lang=ro
 openweathermap.lang=ro
+webservice.peakfinder=Deschide Peakfinder.org
+webservice.geohack=Deschide pagina Geohack
+webservice.panoramio=Deschide harta Panoramio
+webservice.opencachingcom=Deschide Opencaching.com
+webservice.opencachingcom.lang=en
 
 # Cardinals for 3d plots
 cardinal.n=N
@@ -487,24 +823,80 @@ cardinal.e=E
 cardinal.w=V
 
 # Undo operations
-undo.load=\u00cencarc\u0103 date
-undo.loadphotos=\u00cencarc\u0103 fotografii
-undo.loadaudios=\u00cencarc\u0103 audio
-undo.editpoint=Editare punct
-undo.deletepoint=\u015eterge punct
-undo.removephoto=Elimina foto
-undo.removeaudio=Elimina audio
-undo.deleterange=\u015eterge interval
-undo.deletemarked=\u015eterge puncte
-undo.connect=conecteaza
-undo.disconnect=deconecteaza
-undo.rotatephoto=roti foto
+undo.load=\u00eencarc\u0103 date
+undo.loadphotos=\u00eencarc\u0103 fotografii
+undo.loadaudios=\u00eencarc\u0103 audio
+undo.editpoint=editare punct
+undo.deletepoint=\u0219terge punct
+undo.removephoto=elimina foto
+undo.removeaudio=elimin\u0103 audio
+undo.deleterange=\u0219tergere interval
+undo.croptrack=decupare traseu
+undo.deletemarked=\u0219tergere puncte
+undo.insert=adaugare puncte
+undo.reverse=inversarea selec\u021biei
+undo.mergetracksegments=unirea segmentelor traseului
+undo.splitsegments=desp\u0103r\u021birea segmentelor traseului
+undo.sewsegments=combinarea segmentelor traseului
+undo.addtimeoffset=ad\u0103ugarea decalajului de timp
+undo.addaltitudeoffset=ad\u0103ugarea decalajului de altitudine
+undo.rearrangewaypoints=rearanjarea waypoint-urilor
+undo.cutandmove=mutarea sec\u021biunii
+undo.connect=conectarea
+undo.disconnect=deconectarea
+undo.correlatephotos=corelarea fotografiilor
+undo.rearrangephotos=rearanjarea fotografiilor
+undo.createpoint=ad\u0103ugarea punctului
+undo.rotatephoto=rotirea fotografiei
+undo.convertnamestotimes=conversia numelor \u00een timpi
+undo.lookupsrtm=calcularea altitudinilor din SRTM
+undo.deletefieldvalues=\u0219tergerea valorilor c\u00e2mpurilor
+undo.correlateaudios=corelarea clipurilor audio
 
 # Error messages
-error.saveexif.cannotoverwrite1=Fi\u0219ier
-error.jpegload.nofilesfound=Nu au fost g\u0103site fi\u0219iere
-error.jpegload.nojpegsfound=Nu au fost g\u0103site fi\u0219iere jpeg
-error.jpegload.nogpsfound=Nu a fost g\u0103sit informa\u021Bii GPS
-error.audioload.nofilesfound=Nu au fost g\u0103site fi\u0219iere audio
+error.save.dialogtitle=Eroare la salvarea datelor
+error.save.nodata=Nu exist\u0103 nimic de salvat
+error.save.failed=Salvarea datelor \u00een fi\u0219ier a e\u0219uat
+error.saveexif.filenotfound=Cautarea foto a e\u0219uat
+error.saveexif.cannotoverwrite1=Fi\u0219ierul foto
+error.saveexif.cannotoverwrite2=este read only \u0219i nu poate fi suprascris. Salvez o copie?
+error.saveexif.failed=Salvarea a %d imagini a e\u0219uat
+error.saveexif.forced=%d imagini au necesitat salvare for\u021bat\u0103
+error.load.dialogtitle=Eroare la \u00eencarcarea datelor
+error.load.noread=Fi\u0219ierul nu poate fi citit
+error.load.nopoints=\u00cen fi\u0219ier nu au fost g\u0103site coordonate geografice
+error.load.unknownxml=Formatul XML nu poate fi recunoscut
+error.load.noxmlinzip=\u00cen interiorul fi\u0219ierului ZIP sau KMZ nu a fost g\u0103sit con\u021binut XML
+error.load.othererror=Eroare la citirea fi\u0219ierului:
+error.jpegload.dialogtitle=Eroare la \u00eenc\u0103rcarea fotografiilor
+error.jpegload.nofilesfound=Nu a fost g\u0103sit niciun fi\u0219ier
+error.jpegload.nojpegsfound=Nu a fost g\u0103sit niciun fi\u0219ier jpeg
+error.jpegload.nogpsfound=\u00cen EXIF-ul fi\u0219ierelor JPEG nu a fost g\u0103sit\u0103 informa\u021bie GPS
+error.jpegload.exifreadfailed=Citirea informa\u021biei EXIF a e\u0219uat. Informa\u021bia EXIF nu poate fi citit\u0103 far\u0103 o bibliotec\u0103 extern\u0103 sau intern\u0103.
+error.audioload.nofilesfound=Nu a fost g\u0103sit niciun clip audio.
+error.gpsload.unknown=Eroare cu cauz\u0103 necunoscut\u0103
+error.undofailed.title=Anularea a e\u0219uat
+error.undofailed.text=\u00cencercarea de anulare a e\u0219uat
+error.function.noop.title=Func\u021bia nu a avut niciun efect
+error.rearrange.noop=Rearanjarea punctelor nu a avut niciun efect
 error.function.notavailable.title=Func\u021bie indisponibil\u0103
-error.readme.notfound=Fi\u015Fierul "cite\u015Fte-m\u0103" nu a fost g\u0103sit
+error.function.nojava3d=Aceast\u0103 func\u021bie necesit\u0103 biblioteca Java3d
+error.3d=Eroare la afi\u0219area 3d
+error.readme.notfound=Fi\u0219erul "Cite\u015fte-m\u0103" nu a fost g\u0103sit
+error.osmimage.dialogtitle=Eroarea la \u00eenc\u0103rcarea imaginilor h\u0103r\u021bii
+error.osmimage.failed=\u00cenc\u0103rcarea imaginilor h\u0103r\u021bii a e\u0219uat. Verifica\u021bi conexiunea la internet.
+error.language.wrongfile=Fi\u0219ierul selectat nu pare a fi un fi\u0219ier de limb\u0103 pentru GpsPrune
+error.convertnamestotimes.nonames=Niciun nume de waypoint nu a fost g\u0103sit sau nu au putut fi convertite
+error.lookupsrtm.nonefound=Pentru aceste puncte nu exist\u0103 valori de altitudine
+error.lookupsrtm.nonerequired=Toate punctele au deja altitudine, nu e nimic de calculat
+error.gpsies.uploadnotok=Server-ul gpsies a \u00eentors mesajul
+error.gpsies.uploadfailed=Upload-ul a e\u0219uat cu eroarea
+error.showphoto.failed=\u00cenc\u0103rcarea foto a e\u0219uat
+error.playaudiofailed=\u00cencercarea de a reda clipul audio a e\u0219uat
+error.cache.notthere=Directorul tile cache nu a fost g\u0103sit
+error.cache.empty=Directorul tile cache e gol
+error.cache.cannotdelete=Tile-urile (imaginile hart\u0103) nu au putut fi \u0219terse
+error.learnestimationparams.failed=Nu pot fi \u00eenv\u0103\u021ba\u021bi parametrii din acest traseu.\n\u00cencerca\u021bi s\u0103 \u00eenc\u0103rca\u021bi mai multe trasee.
+error.tracksplit.nosplit=Traseul nu a putut fi spart
+error.downloadsrtm.nocache=Fi\u0219ierele nu au putut fi salvate.\nV\u0103 rug\u0103m verifica\u021bi setarea cache-ului.
+error.sewsegments.nothingdone=Segmentele nu au putut fi combinate.\n\u00cen traseu sunt acum %d segmente.
index ec306381c093d9748411080d8419bf80fb9d395c..ea96aa80d1152abae7b87cc2187e7f08bfc4838f 100644 (file)
@@ -12,7 +12,7 @@ menu.track=\u0422\u0440\u0435\u043a
 menu.track.undo=\u041e\u0442\u043c\u0435\u043d\u0438\u0442\u044c
 menu.track.clearundo=\u041e\u0447\u0438\u0441\u0442\u0438\u0442\u044c \u0441\u043f\u0438\u0441\u043e\u043a \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u0439
 menu.track.markrectangle=\u041e\u0442\u043c\u0435\u0442\u0438\u0442\u044c \u0442\u043e\u0447\u043a\u0438 \u0432 \u043a\u0432\u0430\u0434\u0440\u0430\u0442\u0435
-menu.track.deletemarked=\u0423\u0434\u0430\u043b\u0438\u0442\u044c \u043e\u0442\u043c\u0435\u0447\u0435\u043d\u043d\u044b\u0435 \u0442\u043e\u0447\u043a\u0438
+function.deletemarked=\u0423\u0434\u0430\u043b\u0438\u0442\u044c \u043e\u0442\u043c\u0435\u0447\u0435\u043d\u043d\u044b\u0435 \u0442\u043e\u0447\u043a\u0438
 function.rearrangewaypoints=\u041f\u0435\u0440\u0435\u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0438\u0442\u044c \u0438\u043d\u0442\u0435\u0440\u0432\u0430\u043b\u044b
 menu.range=\u0418\u043d\u0442\u0435\u0440\u0432\u0430\u043b
 menu.range.all=\u0412\u044b\u0431\u0440\u0430\u0442\u044c \u0432\u0441\u0435
@@ -108,7 +108,7 @@ function.sewsegments=\u0421\u043a\u043b\u0435\u0438\u0442\u044c \u0441\u0435\u04
 function.getgpsies=\u0417\u0430\u0433\u0440\u0443\u0437\u0438\u0442\u044c \u0442\u0440\u0435\u043a\u0438
 function.uploadgpsies=\u0412\u044b\u0433\u0440\u0443\u0437\u0438\u0442\u044c \u0442\u0440\u0435\u043a \u043d\u0430 gpsies.com
 function.lookupsrtm=\u0412\u044b\u0441\u043e\u0442\u044b \u0432 SRTM
-function.downloadsrtm=\u0417\u0430\u0433\u0440\u0443\u0437\u0438\u0442\u044c STRM 
+function.downloadsrtm=\u0417\u0430\u0433\u0440\u0443\u0437\u0438\u0442\u044c STRM
 function.getwikipedia=\u0421\u0442\u0430\u0442\u044c\u044f \u043e \u0431\u043b\u0438\u0436\u0430\u0439\u0448\u0435\u0439 \u043e\u0431\u043b\u0430\u0441\u0442\u0438 \u0432 \u0412\u0438\u043a\u0438
 function.searchwikipedianames=\u041f\u043e\u0438\u0441\u043a \u0441\u0442\u0430\u0442\u0435\u0439 \u0432 \u0412\u0438\u043a\u0438 \u043f\u043e \u0438\u043c\u0435\u043d\u0438
 function.downloadosm=\u0417\u0430\u0433\u0440\u0443\u0437\u0438\u0442\u044c OSM \u0434\u0430\u043d\u043d\u044b\u0435 \u043d\u0430 \u0442\u0435\u0440\u0440\u0438\u0442\u043e\u0440\u0438\u044e
@@ -694,6 +694,7 @@ fieldname.duration=\u041f\u0440\u043e\u0434\u043e\u043b\u0436\u0438\u0442\u0435\
 fieldname.speed=\u0421\u043a\u043e\u0440\u043e\u0441\u0442\u044c
 fieldname.verticalspeed=\u0412\u0435\u0440\u0442\u0438\u043a\u0430\u043b\u044c\u043d\u0430\u044f \u0441\u043a\u043e\u0440\u043e\u0441\u0442\u044c
 fieldname.description=\u041e\u043f\u0438\u0441\u0430\u043d\u0438\u0435
+fieldname.mediafilename=\u0424\u0430\u0439\u043b
 
 # Measurement units
 units.original=\u041e\u0440\u0438\u0433\u0438\u043d\u0430\u043b\u044c\u043d\u044b\u0439
@@ -737,6 +738,7 @@ logic.or=\u0438\u043b\u0438
 url.googlemaps=maps.google.ru
 wikipedia.lang=ru
 openweathermap.lang=ru
+webservice.opencachingcom.lang=ru
 
 # Cardinals for 3d plots
 cardinal.n=\u0421\u0435\u0432\u0435\u0440
index ecde4b72fe5147e657cabc13187a2b7294ba7425..59a84af085fa5cf7ebb430dece7151b308dc1a45 100644 (file)
@@ -11,7 +11,7 @@ menu.track=Sp\u00e5r
 menu.track.undo=\u00c5ngra
 menu.track.clearundo=Rensa \u00e5ngra-historik
 menu.track.markrectangle=Markera punkter i rektangel
-menu.track.deletemarked=Radera markerade punkter
+function.deletemarked=Radera markerade punkter
 function.rearrangewaypoints=Ordna waypoints
 dialog.rearrange.tostart=Alla till b\u00f6rjan av fil
 dialog.rearrange.toend=Alla till slut av fil
index d236ff39e3b0db5b7ed7c3edf9d377e50a16d52b..68eca8023d564530b859b24c6f24936465fbc086 100644 (file)
@@ -12,7 +12,7 @@ menu.track.clearundo=Geri alma listesi s\u0131f\u0131rla
 menu.point.editpoint=Nokta d\u00fczenle
 menu.point.deletepoint=Noktay\u0131 sil
 function.deleterange=S\u0131ray\u0131 sil
-menu.track.deletemarked=Se\u00e7ili noktalar\u0131 sil
+function.deletemarked=Se\u00e7ili noktalar\u0131 sil
 function.interpolate=\u0130nterpolasyon
 menu.range.average=Se\u00e7me ortala
 menu.range.reverse=S\u0131ra tersine \u00e7evir
index 3b47eeaa310eebf75288f17d90b9f8baab17e0bf..380e5647774f2a95881be297bf45d67ae4fb120b 100644 (file)
@@ -11,7 +11,7 @@ menu.track=\u0422\u0440\u0435\u043a
 menu.track.undo=\u0421\u043a\u0430\u0441\u0443\u0432\u0430\u0442\u0438
 menu.track.clearundo=\u041e\u0447\u0438\u0441\u0442\u0438\u0442\u0438 \u0441\u043f\u0438\u0441\u043e\u043a \u0437\u043c\u0456\u043d
 menu.track.markrectangle=\u041f\u043e\u0437\u043d\u0430\u0447\u0438\u0442\u0438 \u0442\u043e\u0447\u043a\u0438 \u0443 \u043f\u0440\u044f\u043c\u043e\u043a\u0443\u0442\u043d\u0438\u043a\u0443
-menu.track.deletemarked=\u0412\u0438\u043b\u0443\u0447\u0438\u0442\u0438 \u043f\u043e\u0437\u043d\u0430\u0447\u0435\u043d\u0456 \u0442\u043e\u0447\u043a\u0438
+function.deletemarked=\u0412\u0438\u043b\u0443\u0447\u0438\u0442\u0438 \u043f\u043e\u0437\u043d\u0430\u0447\u0435\u043d\u0456 \u0442\u043e\u0447\u043a\u0438
 function.rearrangewaypoints=\u041f\u0435\u0440\u0435\u0432\u0438\u0437\u043d\u0430\u0447\u0438\u0442\u0438 \u0456\u043d\u0442\u0435\u0440\u0432\u0430\u043b\u0438
 dialog.rearrange.tostart=\u0423\u0441\u0435 \u043d\u0430 \u043f\u043e\u0447\u0430\u0442\u043e\u043a \u0444\u0430\u0439\u043b\u0443
 dialog.rearrange.toend=\u0423\u0441\u0435 \u043d\u0430 \u043a\u0456\u043d\u0435\u0446\u044c \u0444\u0430\u0439\u043b\u0443
index 40319fa8ea93367e8c24a3e42cf3aeff11422bd7..a2344e4b5228a8eeb5e92e3019e51986dbbb8664 100644 (file)
@@ -12,7 +12,7 @@ menu.track=\u8f68\u8ff9
 menu.track.undo=\u64a4\u9500
 menu.track.clearundo=\u6e05\u9664\u64a4\u9500\u6e05\u5355
 menu.track.markrectangle=\u6807\u8bb0\u9009\u53d6\u533a\u57df\u5185\u7684\u70b9
-menu.track.deletemarked=\u5220\u9664\u5df2\u6807\u8bb0\u8f68\u8ff9\u70b9
+function.deletemarked=\u5220\u9664\u5df2\u6807\u8bb0\u8f68\u8ff9\u70b9
 menu.range=\u822a\u6bb5
 menu.range.all=\u5168\u9009
 menu.range.none=\u64a4\u9500\u9009\u62e9
index 8669e189c94043b4e3ab91889c4acf4b5e52dc0e..cf60f9ec9136da3898262f31681135eba51f05e2 100644 (file)
@@ -63,6 +63,7 @@ public class FileLoader
                        _fileChooser.addChoosableFileFilter(new GenericFileFilter("filetype.kml", new String[] {"kml"}));
                        _fileChooser.addChoosableFileFilter(new GenericFileFilter("filetype.kmz", new String[] {"kmz"}));
                        _fileChooser.setAcceptAllFileFilterUsed(true);
+                       _fileChooser.setFileFilter(_fileChooser.getAcceptAllFileFilter()); // For some reason seems necessary
                        // start from directory in config if already set (by load jpegs)
                        String configDir = Config.getConfigString(Config.KEY_TRACK_DIR);
                        if (configDir == null) {configDir = Config.getConfigString(Config.KEY_PHOTO_DIR);}
index 4208014e44c1e9e8c9df262c0caa3083f3bd76f3..225a667870033caa90b3a681e71f923a412a5887 100644 (file)
@@ -70,7 +70,7 @@ public class GpxHandler extends XmlHandler
                else if (tag.equals("type")) {
                        _currentTag = _type;
                }
-               else if (tag.equals("description")) {
+               else if (tag.equals("description") || tag.equals("desc")) {
                        _currentTag = _description;
                }
                else if (tag.equals("link")) {
index 2ddd1cdb4aeb402c4b263d9cb2c14c2d90d20de1..e8f2c6a463fab9d2d8eda416dacaa8e88fef175c 100644 (file)
@@ -13,9 +13,10 @@ import tim.prune.data.Field;
 public class KmlHandler extends XmlHandler
 {
        private boolean _insideCoordinates = false;
+       private boolean _insideGxTrack = false;
        private String _value = null;
        private String _name = null, _desc = null;
-       private String _imgLink = null;
+       private String _timestamp = null, _imgLink = null;
        private StringBuffer _coordinates = null;
        private ArrayList<String> _coordinateList = null;
        private ArrayList<String[]> _pointList = new ArrayList<String[]>();
@@ -34,13 +35,21 @@ public class KmlHandler extends XmlHandler
        {
                String tagName = localName;
                if (tagName == null || tagName.equals("")) {tagName = qName;}
-               if (tagName.equalsIgnoreCase("Placemark")) {
+               tagName = tagName.toLowerCase();
+
+               if (tagName.equals("placemark"))
+               {
                        _coordinateList = new ArrayList<String>();
                }
-               else if (tagName.equalsIgnoreCase("coordinates")) {
+               else if (tagName.equals("coordinates"))
+               {
                        _insideCoordinates = true;
                        _coordinates = null;
                }
+               else if (tagName.equals("gx:track"))
+               {
+                       _insideGxTrack = true;
+               }
                _value = null;
                super.startElement(uri, localName, qName, attributes);
        }
@@ -55,28 +64,44 @@ public class KmlHandler extends XmlHandler
        {
                String tagName = localName;
                if (tagName == null || tagName.equals("")) {tagName = qName;}
-               if (tagName.equalsIgnoreCase("Placemark"))
+               tagName = tagName.toLowerCase();
+
+               if (tagName.equals("placemark"))
                {
                        processPlacemark();
-                       _name = _desc = _imgLink = null;
+                       _name = _desc = _imgLink = _timestamp = null;
                }
-               else if (tagName.equalsIgnoreCase("coordinates")) {
+               else if (tagName.equals("coordinates"))
+               {
                        _insideCoordinates = false;
                        if (_coordinates != null) _coordinateList.add(_coordinates.toString().trim());
                }
-               else if (tagName.equalsIgnoreCase("name")) _name = _value;
-               else if (tagName.equalsIgnoreCase("description")) {
+               else if (tagName.equals("name"))
+               {
+                       _name = _value;
+               }
+               else if (tagName.equals("description"))
+               {
                        _desc = _value;
                        _imgLink = getImgLink(_desc);
                }
-               else if (tagName.equalsIgnoreCase("when")) {
-                       _whenList.add(_value);
+               else if (tagName.equals("when"))
+               {
+                       if (!_insideGxTrack)
+                               _timestamp = _value;
+                       else
+                               _whenList.add(_value);
                }
-               else if (tagName.equalsIgnoreCase("gx:coord")) {
-                       _whereList.add(_value);
+               else if (tagName.equals("gx:coord"))
+               {
+                       if (_insideGxTrack) {
+                               _whereList.add(_value);
+                       }
                }
-               else if (tagName.equalsIgnoreCase("gx:Track")) {
+               else if (tagName.equals("gx:track"))
+               {
                        processGxTrack();
+                       _insideGxTrack = false;
                }
                super.endElement(uri, localName, qName);
        }
@@ -123,7 +148,7 @@ public class KmlHandler extends XmlHandler
                        {
                                // Add single point to list
                                final String name = (isSingleSelection ? _name : null);
-                               _pointList.add(makeStringArray(coords, name, _desc));
+                               _pointList.add(makeStringArray(coords, name, _desc, _timestamp));
                                _linkList.add(_imgLink);
                        }
                        else if (numPoints > 1)
@@ -134,7 +159,7 @@ public class KmlHandler extends XmlHandler
                                {
                                        if (coordArray[p] != null && coordArray[p].trim().length()>3)
                                        {
-                                               String[] pointArray = makeStringArray(coordArray[p], null, null);
+                                               String[] pointArray = makeStringArray(coordArray[p], null, null, null);
                                                if (firstPoint) {pointArray[5] = "1";} // start of segment flag
                                                firstPoint = false;
                                                _pointList.add(pointArray);
@@ -150,14 +175,17 @@ public class KmlHandler extends XmlHandler
         */
        private void processGxTrack()
        {
-               if (_whenList.size() > 0 && _whenList.size() == _whereList.size())
+               if (!_whereList.isEmpty())
                {
+                       // If the whens don't match, then throw them all away
+                       if (_whenList.size() != _whereList.size()) {System.out.println("clearing!"); _whenList.clear();}
+
                        // Add each of the unnamed track points to list
                        boolean firstPoint = true;
                        final int numPoints = _whenList.size();
                        for (int p=0; p < numPoints; p++)
                        {
-                               String when  = _whenList.get(p);
+                               String when  = (_whenList.isEmpty() ? null : _whenList.get(p));
                                String where = _whereList.get(p);
                                if (where != null)
                                {
@@ -210,10 +238,11 @@ public class KmlHandler extends XmlHandler
         * @param inCoordinates coordinate string in Kml format
         * @param inName name of waypoint, or null if track point
         * @param inDesc description of waypoint, if any
+        * @param inDesc timestamp of waypoint, if any
         * @return String array for point
         */
        private static String[] makeStringArray(String inCoordinates,
-               String inName, String inDesc)
+               String inName, String inDesc, String inTimestamp)
        {
                String[] result = new String[7];
                String[] values = inCoordinates.split(",");
@@ -223,6 +252,7 @@ public class KmlHandler extends XmlHandler
                }
                result[3] = inName;
                result[4] = inDesc;
+               result[6] = inTimestamp;
                return result;
        }
 
index b604fde4d0d04b35695344ec6cf6d30db855854c..fa51ebf1118e7b3c8b697bc8a31138dd47094a55 100644 (file)
@@ -22,7 +22,7 @@ public abstract class XmlHandler extends DefaultHandler
        public abstract Field[] getFieldArray();
 
        /**
-        * Can be overriden (eg by gpx handler) to provide a track name list
+        * Can be overridden (eg by gpx handler) to provide a track name list
         * @return track name list object if any, or null
         */
        public TrackNameList getTrackNameList() {
@@ -30,7 +30,7 @@ public abstract class XmlHandler extends DefaultHandler
        }
 
        /**
-        * Can be overriden (eg by gpx handler) to provide an array of links to media
+        * Can be overridden (eg by gpx handler) to provide an array of links to media
         * @return array of Strings if any, or null
         */
        public String[] getLinkArray() {
index eae9fe373ffb32e8770d95c9d35d5961cac93b35..8c926946e5d4a0dfd8da1b1f71a3aa7392ddd654 100644 (file)
@@ -1,8 +1,8 @@
-GpsPrune version 17.2
-=====================
+GpsPrune version 18
+===================
 
 GpsPrune is an application for viewing, editing and managing coordinate data from GPS systems,
-including format conversion, charting and photo correlation.
+including format conversion, charting, 3d visualisation, audio and photo correlation, and online resource lookup.
 Full details can be found at http://gpsprune.activityworkshop.net/
 
 GpsPrune is copyright 2006-2015 activityworkshop.net and distributed under the terms of the Gnu GPL version 2.
@@ -17,7 +17,7 @@ Running
 =======
 
 To run GpsPrune from the jar file, simply call it from a command prompt or shell:
-   java -jar gpsprune_17.2.jar
+   java -jar gpsprune_18.jar
 
 If the jar file is saved in a different directory, you will need to include the path.
 Depending on your system settings, you may be able to click or double-click on the jar file
@@ -25,21 +25,18 @@ in a file manager window to execute it.  A shortcut, menu item, alias, desktop i
 or other link can of course be made should you wish.
 
 To specify a language other than the default, use an additional parameter, eg:
-   java -jar gpsprune_17.2.jar --lang=DE
+   java -jar gpsprune_18.jar --lang=DE
 
 
-New with version 17.2
-=====================
-The following fixes were added since version 17.1:
-  - Speed up the cache management dialog
-  - Translation improvements
-
-New with version 17.1
-=====================
-The following fixes were added since version 17:
-  - Fix the decimal precision of coordinates calculated by interpolation and averaging
-  - Fix the selection adjustment when midpoints within the selection are dragged
-  - Minor translation improvements
+New with version 18
+===================
+The following features were added since version 17:
+  - New search options using opencaching.de and mapillary
+  - New web options using peakfinder, geohack and panoramio
+  - Autoplay function for automatically scrolling through the track
+  - Marking uphill lift sections of skiing / snowboarding tracks
+  - Configurable anti-aliasing for map view and profile view
+  - Allow showing just the lines between track points but not the track points
 
 New with version 17
 ===================
@@ -50,7 +47,7 @@ The following features were added since version 16:
   - Select the current segment
   - Adding an altitude tolerance to the climb and descent calculations
   - Sorting waypoints by name or by timestamp
-  
+
 New with version 16
 ===================
 The following features were added since version 15:
@@ -244,7 +241,7 @@ Further information and updates
 ===============================
 
 To obtain the source code (if it wasn't included in your jar file), or for further information,
-please visit the website:  http://activityworkshop.net/
+please visit the website:  http://gpsprune.activityworkshop.net/
 
 You will find there user guides, screenshots and demo videos illustrating the major features.
 As GpsPrune is further developed, subsequent versions of the program will also be made freely
index 026556924f06408d3b735dcce2dce98ecf1757e6..8e7e9ae39ddeebd905f9561d78c34f7d1de20945 100644 (file)
@@ -471,7 +471,7 @@ public class BaseImageConfigDialog implements Runnable
                {
                        _previewPanel.setImage(groutedImage);
                        final int numTilesRemaining = groutedImage.getNumTilesTotal() - groutedImage.getNumTilesUsed();
-                       final boolean offerDownload = numTilesRemaining > 0 && numTilesRemaining < 50;
+                       final boolean offerDownload = numTilesRemaining > 0 && numTilesRemaining < 50 && Config.getConfigBoolean(Config.KEY_ONLINE_MODE);
                        // Set values of labels
                        _downloadTilesButton.setVisible(offerDownload);
                        _downloadTilesButton.setEnabled(offerDownload);
@@ -502,6 +502,7 @@ public class BaseImageConfigDialog implements Runnable
                try {
                        zoomLevel = Integer.parseInt(_zoomDropdown.getSelectedItem().toString());
                }
+               catch (NullPointerException npe) {}
                catch (Exception e) {
                        System.err.println("Exception: " + e.getClass().getName() + " : " + e.getMessage());
                }
index ecf61d393907e4085926f0bfbefbfd76076ccc6c..1e199d9e7bb387ee6dafdbdb903772fb4d1ff9ac 100644 (file)
@@ -102,17 +102,25 @@ public class FileSaver
                        _dialog.getContentPane().add(makeDialogComponents());
                        _dialog.pack();
                }
+               // Has the track got media?
+               final boolean hasMedia = _app.getTrackInfo().getPhotoList().hasCorrelatedPhotos()
+                       || _app.getTrackInfo().getAudioList().hasCorrelatedAudios();
                // Check field list
                Track track = _app.getTrackInfo().getTrack();
                FieldList fieldList = track.getFieldList();
                int numFields = fieldList.getNumFields();
-               _model = new FieldSelectionTableModel(numFields);
+               _model = new FieldSelectionTableModel(numFields + (hasMedia ? 1 : 0));
                for (int i=0; i<numFields; i++)
                {
                        Field field = fieldList.getField(i);
                        FieldInfo info = new FieldInfo(field, track.hasData(field));
                        _model.addFieldInfo(info, i);
                }
+               // Add a field for photos / audio if any present
+               if (hasMedia)
+               {
+                       _model.addFieldInfo(new FieldInfo(Field.MEDIA_FILENAME, true), numFields);
+               }
                // Initialise dialog and show it
                initDialog(_model, inDefaultDelimiter);
                _dialog.setVisible(true);
@@ -599,6 +607,13 @@ public class FileSaver
                                inBuffer.append(inPoint.getTimestamp().getText(inTimestampFormat));
                        }
                }
+               else if (inField == Field.MEDIA_FILENAME)
+               {
+                       if (inPoint.hasMedia())
+                       {
+                               inBuffer.append(inPoint.getMediaName());
+                       }
+               }
                else
                {
                        String value = inPoint.getFieldValue(inField);
index 0f038b77ce60f473a50a64b068c68b698f5b2050..584d9ba5e7ab628129d3002077bc4648f4a059ac 100644 (file)
@@ -539,7 +539,11 @@ public class GpxExporter extends GenericFunction implements Runnable
                if (inPoint.isWaypoint())
                {
                        source = replaceGpxTags(source, "<name>", "</name>", inPoint.getWaypointName());
-                       source = replaceGpxTags(source, "<description>", "</description>",
+                       if (source != null)
+                       {
+                               source = source.replaceAll("<description>", "<desc>").replaceAll("</description>", "</desc>");
+                       }
+                       source = replaceGpxTags(source, "<desc>", "</desc>",
                                XmlUtils.fixCdata(inPoint.getFieldValue(Field.DESCRIPTION)));
                }
                // photo / audio links
@@ -696,9 +700,9 @@ public class GpxExporter extends GenericFunction implements Runnable
                String desc = XmlUtils.fixCdata(inPoint.getFieldValue(Field.DESCRIPTION));
                if (desc != null && !desc.equals(""))
                {
-                       inWriter.write("\t\t<description>");
+                       inWriter.write("\t\t<desc>");
                        inWriter.write(desc);
-                       inWriter.write("</description>\n");
+                       inWriter.write("</desc>\n");
                }
                // Media links, if any
                if (inPhoto && inPoint.getPhoto() != null)
index 16e63edbc43c57f84a320563030ee5a625ff804b..ffe9db888d1ea443ebf1f488d9d4e0e0cc9d9106 100644 (file)
@@ -371,6 +371,7 @@ public class TerrainHelper
                                // System.out.println("Averaging values " + alt1.getMetricValue() + " and " + alt2.getMetricValue());
                                int newAltitude = (int) ((alt1.getMetricValue() + alt2.getMetricValue()) / 2.0);
                                corner.setFieldValue(Field.ALTITUDE, "" + newAltitude, false);
+                               // TODO: Check forcing metres?  Is there a nicer way?
                        }
                }
        }
@@ -394,14 +395,19 @@ public class TerrainHelper
                                if (prevIndexWithAlt >= 0 && prevIndexWithAlt < (i-1))
                                {
                                        final int gapLen = i - prevIndexWithAlt;
-                                       final double alt1 = inTerrainTrack.getPoint(prevIndexWithAlt).getAltitude().getMetricValue();
-                                       final double alt2 = inTerrainTrack.getPoint(i).getAltitude().getMetricValue();
+                                       final int cellIndex1 = inCornerIndex + prevIndexWithAlt * inInc;
+                                       final double alt1 = inTerrainTrack.getPoint(cellIndex1).getAltitude().getMetricValue();
+                                       final int cellIndex2 = inCornerIndex + i * inInc;
+                                       final double alt2 = inTerrainTrack.getPoint(cellIndex2).getAltitude().getMetricValue();
+                                       //System.out.println("Altitude along edge goes from " + alt1 + " (at " + prevIndexWithAlt + ") to " +
+                                       //              alt2 + " (at " + i + ")");
                                        for (int j = 1; j < gapLen; j++)
                                        {
-                                               // System.out.println("Fill in " + (prevIndexWithAlt + j) + " using " + prevIndexWithAlt + " and " + i);
                                                final double alt = alt1 + (alt2-alt1) * j / gapLen;
+                                               //System.out.println("Fill in " + (prevIndexWithAlt + j) + "(" + (inCornerIndex + (prevIndexWithAlt + j) * inInc) + ")  with alt " + (int) alt);
                                                final DataPoint p = inTerrainTrack.getPoint(inCornerIndex + (prevIndexWithAlt + j) * inInc);
                                                p.setFieldValue(Field.ALTITUDE, "" + (int) alt, false);
+                                               // TODO: Check forcing metres?
                                        }
                                }
                                prevIndexWithAlt = i;
@@ -415,7 +421,7 @@ public class TerrainHelper
         */
        private void fixBiggerHoles(Track inTerrainTrack)
        {
-               double[] altitudes = new double[inTerrainTrack.getNumPoints()];
+               TerrainPatch patch = new TerrainPatch(_gridSize);
                for (int i=0; i<_gridSize; i++)
                {
                        int prevHoriz = -1, prevVert = -1;
@@ -425,18 +431,13 @@ public class TerrainHelper
                                {
                                        if (prevHoriz > -1 && prevHoriz != (j-1))
                                        {
-//                                             System.out.println("Found a gap for y=" + i +" between x=" + prevHoriz + " and " + j + " (" + (j-prevHoriz-1) + ")");
+                                               //System.out.println("Found a gap for y=" + i +" between x=" + prevHoriz + " and " + j + " (" + (j-prevHoriz-1) + ")");
                                                double startVal = inTerrainTrack.getPoint(i * _gridSize + prevHoriz).getAltitude().getMetricValue();
                                                double endVal   = inTerrainTrack.getPoint(i * _gridSize + j).getAltitude().getMetricValue();
                                                for (int k=prevHoriz + 1; k< j; k++)
                                                {
                                                        double val = startVal + (k-prevHoriz) * (endVal-startVal) / (j-prevHoriz);
-                                                       if (altitudes[i * _gridSize + k] > 0.0) {
-                                                               altitudes[i * _gridSize + k] = (altitudes[i * _gridSize + k] + val) / 2.0;
-                                                       }
-                                                       else {
-                                                               altitudes[i * _gridSize + k] = val;
-                                                       }
+                                                       patch.addAltitude(i * _gridSize + k, val, k-prevHoriz, j-prevHoriz);
                                                }
                                        }
                                        prevHoriz = j;
@@ -445,32 +446,31 @@ public class TerrainHelper
                                {
                                        if (prevVert > -1 && prevVert != (j-1))
                                        {
-//                                             System.out.println("Found a gap for x=" + i +" between y=" + prevVert + " and " + j + " (" + (j-prevVert-1) + ")");
+                                               //System.out.println("Found a gap for x=" + i +" between y=" + prevVert + " and " + j + " (" + (j-prevVert-1) + ")");
                                                double startVal = inTerrainTrack.getPoint(prevVert * _gridSize + i).getAltitude().getMetricValue();
                                                double endVal   = inTerrainTrack.getPoint(j * _gridSize + i).getAltitude().getMetricValue();
                                                for (int k=prevVert + 1; k< j; k++)
                                                {
                                                        double val = startVal + (k-prevVert) * (endVal-startVal) / (j-prevVert);
-                                                       if (altitudes[k * _gridSize + i] > 0.0) {
-                                                               altitudes[k * _gridSize + i] = (altitudes[k * _gridSize + i] + val) / 2.0;
-                                                       }
-                                                       else {
-                                                               altitudes[k * _gridSize + i] = val;
-                                                       }
+                                                       patch.addAltitude(k * _gridSize + i, val, k-prevVert, j-prevVert);
                                                }
                                        }
                                        prevVert = j;
                                }
                        }
                }
-               // Now the doubles have been set and/or averaged, we can set the values in the points
+               // Smooth the patch to reduce the blocky effect from the voids
+               patch.smooth();
+
+               // Now the doubles have been set and averaged, we can set the values in the points
                for (int i=0; i<inTerrainTrack.getNumPoints(); i++)
                {
                        DataPoint p = inTerrainTrack.getPoint(i);
-                       if (!p.hasAltitude() && altitudes[i] > 0.0)
+                       if (!p.hasAltitude())
                        {
-                               p.setFieldValue(Field.ALTITUDE, "" + altitudes[i], false);
-                               p.getAltitude().reset(new Altitude((int) altitudes[i], UnitSetLibrary.UNITS_METRES));
+                               final double altitude = patch.getAltitude(i);
+                               p.setFieldValue(Field.ALTITUDE, "" + altitude, false);
+                               p.getAltitude().reset(new Altitude((int) altitude, UnitSetLibrary.UNITS_METRES));
                        }
                }
        }
diff --git a/tim/prune/threedee/TerrainPatch.java b/tim/prune/threedee/TerrainPatch.java
new file mode 100644 (file)
index 0000000..10f0b6e
--- /dev/null
@@ -0,0 +1,116 @@
+package tim.prune.threedee;
+
+public class TerrainPatch
+{
+       private int      _gridSize = 0;
+       private double[] _altitudes = null;
+       private int[]    _tempDists = null;
+
+       /**
+        * Constructor
+        * @param inGridSize size of grid edge
+        */
+       public TerrainPatch(int inGridSize)
+       {
+               _gridSize = inGridSize;
+               int numNodes = inGridSize * inGridSize;
+               _altitudes = new double[numNodes];
+               _tempDists = new int[numNodes];
+       }
+
+       /**
+        * Add an altitude interpolation to the mix
+        * @param inPointIndex point index to array
+        * @param inValue altitude value in metres
+        * @param inGapIndex index of point within gap, from 1 to gapLength-1
+        * @param inGapLength length of gap, minimum 2
+        */
+       public void addAltitude(int inPointIndex, double inValue, int inGapIndex, int inGapLength)
+       {
+               final int dist = Math.min(inGapIndex, inGapLength-inGapIndex);
+               if (_tempDists[inPointIndex] == 0)
+               {
+                       if (_altitudes[inPointIndex] > 0.0) System.err.println("Altitude shouldn't be 0 if dist is 0!");
+                       // first point
+                       _altitudes[inPointIndex] = inValue;
+                       _tempDists[inPointIndex] = dist;
+               }
+               else
+               {
+                       // second point
+                       final double firstValue = _altitudes[inPointIndex];
+                       final int firstDist     = _tempDists[inPointIndex];
+                       final double firstWeight = dist * 1.0 / (dist + firstDist);
+                       final double secondWeight= firstDist * 1.0 / (dist + firstDist);
+                       _altitudes[inPointIndex] = firstWeight * firstValue + secondWeight * inValue;
+                       _tempDists[inPointIndex] = 0;
+               }
+       }
+
+       /**
+        * Smooth the patch to reduce blockiness
+        */
+       public void smooth()
+       {
+               double[] altCopy = new double[_altitudes.length];
+               for (int i=0; i<_gridSize; i++)
+               {
+                       for (int j=0; j<_gridSize; j++)
+                       {
+                               if (hasAltitude(i, j) && hasAltitude(i-1, j) && hasAltitude(i+1, j)
+                                       && hasAltitude(i, j+1) && hasAltitude(i-1, j+1) && hasAltitude(i+1, j+1)
+                                       && hasAltitude(i, j-1) && hasAltitude(i-1, j-1) && hasAltitude(i+1, j-1))
+                               {
+                                       // got a 3x3 square, can do a blur
+                                       double alt = (getAltitude(i, j) + getAltitude(i-1, j) + getAltitude(i+1, j)
+                                               + getAltitude(i, j+1) + getAltitude(i-1, j+1) + getAltitude(i+1, j+1)
+                                               + getAltitude(i, j-1) + getAltitude(i-1, j-1) + getAltitude(i+1, j-1)) / 9.0;
+                                       altCopy[i * _gridSize + j] = alt;
+                               }
+                       }
+               }
+               // Copy results back
+               for (int k=0; k<altCopy.length; k++)
+               {
+                       if (altCopy[k] > 0.0)
+                       {
+                               _altitudes[k] = altCopy[k];
+                       }
+               }
+       }
+
+       /**
+        * @param inI first index
+        * @param inJ second index
+        * @return true if there is an altitude in the patch in this position
+        */
+       private boolean hasAltitude(int inI, int inJ)
+       {
+               return inI >= 0 && inI < _gridSize && inJ >= 0 && inJ < _gridSize
+                       && _altitudes[inI * _gridSize + inJ] > 0.0;
+       }
+
+       /**
+        * @param inI first index
+        * @param inJ second index
+        * @return true if there is an altitude in the patch in this position
+        */
+       private double getAltitude(int inI, int inJ)
+       {
+               if (inI >= 0 && inI < _gridSize && inJ >= 0 && inJ < _gridSize)
+               {
+                       return _altitudes[inI * _gridSize + inJ];
+               }
+               return 0.0;
+       }
+
+       /**
+        * @param inPointIndex point index
+        * @return altitude value
+        */
+       public double getAltitude(int inPointIndex)
+       {
+               if (_tempDists[inPointIndex] != 0) System.err.println("Dists should be 0 if we're retrieving!");
+               return _altitudes[inPointIndex];
+       }
+}
index bca92b11119114e930bd28a95785e2cc1cff2130..d3e85e02e3f5d078eb49ac612e084528d34eae1c 100644 (file)
@@ -3,22 +3,60 @@ package tim.prune.undo;
 import java.util.Stack;
 
 /**
- * Stack of undo operations
- * which also remembers how many times it's been cleared
+ * Class to hold an undo operation together with a counter
  */
-public class UndoStack extends Stack<UndoOperation>
+class UndoOpWithState
 {
-       private int _numTimesDeleted = 0;
-
-       /** @return number of times this stack has been deleted */
-       public int getNumTimesDeleted() {
-               return _numTimesDeleted;
+       public UndoOperation _undoOperation = null;
+       public int           _undoCounter = 0;
+       /** Constructor */
+       public UndoOpWithState(UndoOperation inOp, int inCounter)
+       {
+               _undoOperation = inOp;
+               _undoCounter   = inCounter;
        }
+}
+
+/**
+ * Stack of undo operations
+ * which also remembers how many undos have been performed
+ */
+public class UndoStack extends Stack<UndoOpWithState>
+{
+       /** Number of undos (and clears) already performed */
+       private int _numUndos = 0;
 
        @Override
        public void clear()
        {
-               _numTimesDeleted++;
+               _numUndos++;
                super.clear();
        }
+
+       /** Add an undo operation to the stack */
+       public synchronized boolean add(UndoOperation inOp)
+       {
+               return super.add(new UndoOpWithState(inOp, _numUndos));
+       }
+
+       /** Pop the latest operation from the stack */
+       public synchronized UndoOperation popOperation()
+       {
+               _numUndos++;
+               return super.pop()._undoOperation;
+       }
+
+       /** Get the operation at the given index */
+       public UndoOperation getOperationAt(int inIndex)
+       {
+               return super.elementAt(inIndex)._undoOperation;
+       }
+
+       /** @return number of undos */
+       public int getNumUndos()
+       {
+               if (isEmpty()) {return 0;}
+               // Get the number of undos stored by the last operation on the stack
+               return peek()._undoCounter;
+       }
 }