]> gitweb.fperrin.net Git - GpsPrune.git/commitdiff
Version 7, February 2009
authoractivityworkshop <mail@activityworkshop.net>
Sat, 14 Feb 2015 14:13:41 +0000 (15:13 +0100)
committeractivityworkshop <mail@activityworkshop.net>
Sat, 14 Feb 2015 14:13:41 +0000 (15:13 +0100)
112 files changed:
tim/prune/App.java
tim/prune/Config.java
tim/prune/DataSubscriber.java
tim/prune/ExternalTools.java
tim/prune/FunctionLibrary.java [new file with mode: 0644]
tim/prune/GenericFunction.java [new file with mode: 0644]
tim/prune/GpsPruner.java
tim/prune/I18nManager.java
tim/prune/configuration.txt
tim/prune/correlate/PhotoCorrelator.java
tim/prune/correlate/PhotoPreviewTableModel.java
tim/prune/correlate/PhotoPreviewTableRow.java
tim/prune/correlate/PhotoSelectionTableModel.java
tim/prune/correlate/TimeIndexPair.java
tim/prune/data/Altitude.java
tim/prune/data/AltitudeRange.java
tim/prune/data/Coordinate.java
tim/prune/data/DataPoint.java
tim/prune/data/Distance.java
tim/prune/data/DoubleRange.java
tim/prune/data/Field.java
tim/prune/data/FieldType.java
tim/prune/data/IntegerRange.java
tim/prune/data/Photo.java
tim/prune/data/PhotoList.java
tim/prune/data/PhotoStatus.java [deleted file]
tim/prune/data/Selection.java
tim/prune/data/Timestamp.java
tim/prune/data/Track.java
tim/prune/data/TrackInfo.java
tim/prune/drew/jpeg/ExifReader.java
tim/prune/drew/jpeg/JpegData.java
tim/prune/drew/jpeg/JpegSegmentData.java
tim/prune/function/AboutScreen.java [moved from tim/prune/gui/AboutScreen.java with 74% similarity]
tim/prune/function/AddTimeOffset.java [moved from tim/prune/gui/TimeOffsetDialog.java with 65% similarity]
tim/prune/function/CheckVersionScreen.java [moved from tim/prune/gui/CheckVersionScreen.java with 74% similarity]
tim/prune/function/HelpScreen.java [new file with mode: 0644]
tim/prune/function/RearrangeWaypointsFunction.java [new file with mode: 0644]
tim/prune/function/SetMapBgFunction.java [new file with mode: 0644]
tim/prune/function/ShowThreeDFunction.java [new file with mode: 0644]
tim/prune/function/browser/BrowserLauncher.java [moved from tim/prune/browser/BrowserLauncher.java with 85% similarity]
tim/prune/function/browser/UrlGenerator.java [moved from tim/prune/browser/UrlGenerator.java with 67% similarity]
tim/prune/function/charts/ChartSeries.java [new file with mode: 0644]
tim/prune/function/charts/Charter.java [new file with mode: 0644]
tim/prune/function/compress/ClosePointsAlgorithm.java [new file with mode: 0644]
tim/prune/function/compress/CompressTrackFunction.java [new file with mode: 0644]
tim/prune/function/compress/CompressionAlgorithm.java [new file with mode: 0644]
tim/prune/function/compress/DuplicatePointAlgorithm.java [new file with mode: 0644]
tim/prune/function/compress/SingleParameterAlgorithm.java [new file with mode: 0644]
tim/prune/function/compress/SingletonAlgorithm.java [new file with mode: 0644]
tim/prune/function/compress/SummaryLabel.java [new file with mode: 0644]
tim/prune/function/compress/TrackDetails.java [new file with mode: 0644]
tim/prune/function/compress/WackyPointAlgorithm.java [new file with mode: 0644]
tim/prune/function/distance/DistanceFunction.java [new file with mode: 0644]
tim/prune/function/distance/DistanceTableModel.java [new file with mode: 0644]
tim/prune/function/distance/FromTableModel.java [new file with mode: 0644]
tim/prune/function/distance/GenericTableModel.java [new file with mode: 0644]
tim/prune/function/edit/EditFieldsTableModel.java [moved from tim/prune/edit/EditFieldsTableModel.java with 97% similarity]
tim/prune/function/edit/FieldEdit.java [moved from tim/prune/edit/FieldEdit.java with 94% similarity]
tim/prune/function/edit/FieldEditList.java [moved from tim/prune/edit/FieldEditList.java with 79% similarity]
tim/prune/function/edit/PointEditor.java [moved from tim/prune/edit/PointEditor.java with 98% similarity]
tim/prune/function/edit/PointNameEditor.java [moved from tim/prune/edit/PointNameEditor.java with 81% similarity]
tim/prune/gui/DetailsDisplay.java
tim/prune/gui/GenericChart.java
tim/prune/gui/MenuManager.java
tim/prune/gui/PhotoThumbnail.java
tim/prune/gui/ProfileChart.java
tim/prune/gui/UndoManager.java
tim/prune/gui/WaypointListModel.java
tim/prune/gui/WholeNumberField.java
tim/prune/gui/map/MapCanvas.java
tim/prune/gui/map/MapPosition.java
tim/prune/gui/map/MapTileCacher.java
tim/prune/gui/map/MapTileConfig.java [new file with mode: 0644]
tim/prune/lang/prune-texts_de.properties
tim/prune/lang/prune-texts_de_CH.properties
tim/prune/lang/prune-texts_en.properties [moved from tim/prune/lang/prune-texts.properties with 86% similarity]
tim/prune/lang/prune-texts_es.properties
tim/prune/lang/prune-texts_fr.properties
tim/prune/lang/prune-texts_in.properties [new file with mode: 0644]
tim/prune/lang/prune-texts_it.properties
tim/prune/lang/prune-texts_pl.properties
tim/prune/lang/prune-texts_pt.properties [new file with mode: 0644]
tim/prune/lang/prune-texts_ro.properties [new file with mode: 0644]
tim/prune/load/FieldSelectionTableModel.java
tim/prune/load/FileCacher.java
tim/prune/load/FileLoader.java
tim/prune/load/GpsLoader.java
tim/prune/load/JpegLoader.java
tim/prune/load/PhotoSorter.java
tim/prune/load/TextFileLoader.java
tim/prune/load/xml/GpxHandler.java
tim/prune/load/xml/KmlHandler.java
tim/prune/load/xml/XmlFileLoader.java
tim/prune/load/xml/ZipFileLoader.java [new file with mode: 0644]
tim/prune/readme.txt
tim/prune/save/ExifSaver.java
tim/prune/save/FieldSelectionTableModel.java
tim/prune/save/FileSaver.java
tim/prune/save/GpsSaver.java [new file with mode: 0644]
tim/prune/save/GpxExporter.java
tim/prune/save/KmlExporter.java
tim/prune/save/PhotoTableEntry.java
tim/prune/save/PhotoTableModel.java
tim/prune/save/PovExporter.java
tim/prune/threedee/Java3DWindow.java
tim/prune/threedee/LineDialog.java
tim/prune/threedee/ThreeDModel.java
tim/prune/threedee/WindowFactory.java
tim/prune/undo/UndoDeleteDuplicates.java [deleted file]
tim/prune/undo/UndoEditPoint.java
tim/prune/undo/UndoInsert.java

index ecde5481a1d269ed23028cb48208d4adcf6abb94..ced255ae111cc194eac8fb0d1db64b2f2b019b36 100644 (file)
@@ -7,10 +7,7 @@ import java.util.Stack;
 import javax.swing.JFrame;
 import javax.swing.JOptionPane;
 
-import tim.prune.browser.BrowserLauncher;
-import tim.prune.browser.UrlGenerator;
-import tim.prune.correlate.PhotoCorrelator;
-import tim.prune.correlate.PointPair;
+import tim.prune.data.Altitude;
 import tim.prune.data.Coordinate;
 import tim.prune.data.DataPoint;
 import tim.prune.data.Field;
@@ -21,31 +18,23 @@ import tim.prune.data.Photo;
 import tim.prune.data.PhotoList;
 import tim.prune.data.Track;
 import tim.prune.data.TrackInfo;
-import tim.prune.edit.FieldEditList;
-import tim.prune.edit.PointEditor;
-import tim.prune.edit.PointNameEditor;
+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.function.edit.PointNameEditor;
 import tim.prune.gui.MenuManager;
-import tim.prune.gui.TimeOffsetDialog;
 import tim.prune.gui.UndoManager;
 import tim.prune.load.FileLoader;
-import tim.prune.load.GpsLoader;
 import tim.prune.load.JpegLoader;
 import tim.prune.save.ExifSaver;
 import tim.prune.save.FileSaver;
-import tim.prune.save.GpxExporter;
-import tim.prune.save.KmlExporter;
-import tim.prune.save.PovExporter;
-import tim.prune.threedee.ThreeDException;
-import tim.prune.threedee.ThreeDWindow;
-import tim.prune.threedee.WindowFactory;
 import tim.prune.undo.UndoAddTimeOffset;
 import tim.prune.undo.UndoCompress;
 import tim.prune.undo.UndoConnectPhoto;
 import tim.prune.undo.UndoConnectPhotoWithClone;
-import tim.prune.undo.UndoCorrelatePhotos;
 import tim.prune.undo.UndoCreatePoint;
 import tim.prune.undo.UndoCutAndMove;
-import tim.prune.undo.UndoDeleteDuplicates;
 import tim.prune.undo.UndoDeletePhoto;
 import tim.prune.undo.UndoDeletePoint;
 import tim.prune.undo.UndoDeleteRange;
@@ -57,7 +46,6 @@ import tim.prune.undo.UndoLoad;
 import tim.prune.undo.UndoLoadPhotos;
 import tim.prune.undo.UndoMergeTrackSegments;
 import tim.prune.undo.UndoOperation;
-import tim.prune.undo.UndoRearrangeWaypoints;
 import tim.prune.undo.UndoReverseSection;
 
 
@@ -74,21 +62,10 @@ public class App
        private MenuManager _menuManager = null;
        private FileLoader _fileLoader = null;
        private JpegLoader _jpegLoader = null;
-       private GpsLoader _gpsLoader = null;
        private FileSaver _fileSaver = null;
-       private KmlExporter _kmlExporter = null;
-       private GpxExporter _gpxExporter = null;
-       private PovExporter _povExporter = null;
-       private BrowserLauncher _browserLauncher = null;
-       private Stack _undoStack = null;
+       private Stack<UndoOperation> _undoStack = null;
        private boolean _mangleTimestampsConfirmed = false;
 
-       // Constants
-       public static final int REARRANGE_TO_START   = 0;
-       public static final int REARRANGE_TO_END     = 1;
-       public static final int REARRANGE_TO_NEAREST = 2;
-
-
        /**
         * Constructor
         * @param inFrame frame object for application
@@ -96,9 +73,10 @@ public class App
        public App(JFrame inFrame)
        {
                _frame = inFrame;
-               _undoStack = new Stack();
+               _undoStack = new Stack<UndoOperation>();
                _track = new Track();
                _trackInfo = new TrackInfo(_track);
+               FunctionLibrary.initialise(this);
        }
 
 
@@ -110,6 +88,14 @@ public class App
                return _trackInfo;
        }
 
+       /**
+        * @return the dialog frame
+        */
+       public JFrame getFrame()
+       {
+               return _frame;
+       }
+
        /**
         * Check if the application has unsaved data
         * @return true if data is unsaved, false otherwise
@@ -123,11 +109,22 @@ public class App
        /**
         * @return the undo stack
         */
-       public Stack getUndoStack()
+       public Stack<UndoOperation> getUndoStack()
        {
                return _undoStack;
        }
 
+       /**
+        * Complete a function execution
+        * @param inUndo undo object to be added to stack
+        * @param inConfirmText confirmation text
+        */
+       public void completeFunction(UndoOperation inUndo, String inConfirmText)
+       {
+               _undoStack.add(inUndo);
+               UpdateMessageBroker.informSubscribers(inConfirmText);
+       }
+
        /**
         * Set the MenuManager object to be informed about changes
         * @param inManager MenuManager object
@@ -159,25 +156,13 @@ public class App
                _jpegLoader.openDialog(new LatLonRectangle(_track.getLatRange(), _track.getLonRange()));
        }
 
-       /**
-        * Start a load from Gps
-        */
-       public void beginLoadFromGps()
-       {
-               if (_gpsLoader == null)
-                       _gpsLoader = new GpsLoader(this, _frame);
-               _gpsLoader.openDialog();
-       }
-
        /**
         * Save the file in the selected format
         */
        public void saveFile()
        {
-               if (_track == null)
-               {
-                       JOptionPane.showMessageDialog(_frame, I18nManager.getText("error.save.nodata"),
-                               I18nManager.getText("error.save.dialogtitle"), JOptionPane.ERROR_MESSAGE);
+               if (_track == null) {
+                       showErrorMessage("error.save.dialogtitle", "error.save.nodata");
                }
                else
                {
@@ -191,105 +176,6 @@ public class App
        }
 
 
-       /**
-        * Export track data as Kml
-        */
-       public void exportKml()
-       {
-               if (_track == null)
-               {
-                       JOptionPane.showMessageDialog(_frame, I18nManager.getText("error.save.nodata"),
-                               I18nManager.getText("error.save.dialogtitle"), JOptionPane.ERROR_MESSAGE);
-               }
-               else
-               {
-                       // Invoke the export
-                       if (_kmlExporter == null)
-                       {
-                               _kmlExporter = new KmlExporter(_frame, _trackInfo);
-                       }
-                       _kmlExporter.showDialog();
-               }
-       }
-
-
-       /**
-        * Export track data as Gpx
-        */
-       public void exportGpx()
-       {
-               if (_track == null)
-               {
-                       JOptionPane.showMessageDialog(_frame, I18nManager.getText("error.save.nodata"),
-                               I18nManager.getText("error.save.dialogtitle"), JOptionPane.ERROR_MESSAGE);
-               }
-               else
-               {
-                       // Invoke the export
-                       if (_gpxExporter == null)
-                       {
-                               _gpxExporter = new GpxExporter(_frame, _trackInfo);
-                       }
-                       _gpxExporter.showDialog();
-               }
-       }
-
-
-       /**
-        * Export track data as Pov without specifying settings
-        */
-       public void exportPov()
-       {
-               exportPov(false, 0.0, 0.0, 0.0, 0);
-       }
-
-       /**
-        * Export track data as Pov and also specify settings
-        * @param inX X component of unit vector
-        * @param inY Y component of unit vector
-        * @param inZ Z component of unit vector
-        * @param inAltitudeCap altitude cap
-        */
-       public void exportPov(double inX, double inY, double inZ, int inAltitudeCap)
-       {
-               exportPov(true, inX, inY, inZ, inAltitudeCap);
-       }
-
-       /**
-        * Export track data as Pov with optional angle specification
-        * @param inDefineAngles true to define angles, false to ignore
-        * @param inX X component of unit vector
-        * @param inY Y component of unit vector
-        * @param inZ Z component of unit vector
-        * @param inAltitudeCap altitude cap
-        */
-       private void exportPov(boolean inDefineSettings, double inX, double inY, double inZ, int inAltitudeCap)
-       {
-               // Check track has data to export
-               if (_track == null || _track.getNumPoints() <= 0)
-               {
-                       JOptionPane.showMessageDialog(_frame, I18nManager.getText("error.save.nodata"),
-                               I18nManager.getText("error.save.dialogtitle"), JOptionPane.ERROR_MESSAGE);
-               }
-               else
-               {
-                       // Make new exporter if necessary
-                       if (_povExporter == null)
-                       {
-                               _povExporter = new PovExporter(_frame, _track);
-                       }
-                       // Specify angles if necessary
-                       if (inDefineSettings)
-                       {
-                               _povExporter.setCameraCoordinates(inX, inY, inZ);
-                               _povExporter.setAltitudeCap(inAltitudeCap);
-                       }
-                       // Initiate export
-                       _povExporter.showDialog();
-               }
-       }
-
-
        /**
         * Exit the application if confirmed
         */
@@ -514,57 +400,13 @@ public class App
 
 
        /**
-        * Delete all the duplicate points in the track
+        * Finish the compression by deleting the marked points
         */
-       public void deleteDuplicates()
-       {
-               if (_track != null)
-               {
-                       // Save undo information
-                       UndoOperation undo = new UndoDeleteDuplicates(_track);
-                       // tell track to do it
-                       int numDeleted = _trackInfo.deleteDuplicates();
-                       if (numDeleted > 0)
-                       {
-                               _undoStack.add(undo);
-                               String message = null;
-                               if (numDeleted == 1)
-                               {
-                                       message = "1 " + I18nManager.getText("confirm.deleteduplicates.single");
-                               }
-                               else
-                               {
-                                       message = "" + numDeleted + " " + I18nManager.getText("confirm.deleteduplicates.multi");
-                               }
-                               // Pass message to broker
-                               UpdateMessageBroker.informSubscribers(message);
-                       }
-                       else
-                       {
-                               // No duplicates found to delete
-                               JOptionPane.showMessageDialog(_frame,
-                                       I18nManager.getText("dialog.deleteduplicates.nonefound"),
-                                       I18nManager.getText("dialog.deleteduplicates.title"), JOptionPane.INFORMATION_MESSAGE);
-                       }
-               }
-       }
-
-
-       /**
-        * Compress the track
-        */
-       public void compressTrack()
+       public void finishCompressTrack()
        {
                UndoCompress undo = new UndoCompress(_track);
-               // Get compression parameter
-               Object compParam = JOptionPane.showInputDialog(_frame,
-                       I18nManager.getText("dialog.compresstrack.parameter.text"),
-                       I18nManager.getText("dialog.compresstrack.title"),
-                       JOptionPane.QUESTION_MESSAGE, null, null, "100");
-               int compNumber = parseNumber(compParam);
-               if (compNumber <= 0) return;
                // call track to do compress
-               int numPointsDeleted = _trackInfo.compress(compNumber);
+               int numPointsDeleted = _trackInfo.deleteMarkedPoints();
                // add to undo stack if successful
                if (numPointsDeleted > 0)
                {
@@ -573,14 +415,11 @@ public class App
                        UpdateMessageBroker.informSubscribers("" + numPointsDeleted + " "
                                 + (numPointsDeleted==1?I18nManager.getText("confirm.deletepoint.single"):I18nManager.getText("confirm.deletepoint.multi")));
                }
-               else
-               {
-                       JOptionPane.showMessageDialog(_frame, I18nManager.getText("dialog.compresstrack.nonefound"),
-                               I18nManager.getText("dialog.compresstrack.title"), JOptionPane.WARNING_MESSAGE);
+               else {
+                       showErrorMessage("function.compress", "dialog.compress.nonefound");
                }
        }
 
-
        /**
         * Reverse the currently selected section of the track
         */
@@ -607,24 +446,6 @@ public class App
                }
        }
 
-       /**
-        * Trigger the dialog to add a time offset to the current selection
-        */
-       public void beginAddTimeOffset()
-       {
-               int selStart = _trackInfo.getSelection().getStart();
-               int selEnd = _trackInfo.getSelection().getEnd();
-               if (!_track.hasData(Field.TIMESTAMP, selStart, selEnd)) {
-                       JOptionPane.showMessageDialog(_frame,
-                               I18nManager.getText("dialog.addtimeoffset.notimestamps"),
-                               I18nManager.getText("dialog.addtimeoffset.title"), JOptionPane.ERROR_MESSAGE);
-               }
-               else {
-                       TimeOffsetDialog timeDialog = new TimeOffsetDialog(this, _frame);
-                       timeDialog.showDialog();
-               }
-       }
-
        /**
         * Complete the add time offset function with the specified offset
         * @param inTimeOffset time offset to add (+ve for add, -ve for subtract)
@@ -690,6 +511,24 @@ public class App
        }
 
 
+       /**
+        * Average the selected points
+        */
+       public void averageSelection()
+       {
+               // Find following track point
+               DataPoint nextPoint = _track.getNextTrackPoint(_trackInfo.getSelection().getEnd() + 1);
+               boolean segFlag = false;
+               if (nextPoint != null) {segFlag = nextPoint.getSegmentStart();}
+               UndoInsert undo = new UndoInsert(_trackInfo.getSelection().getEnd() + 1, 1, nextPoint != null, segFlag);
+               // call track info object to do the averaging
+               if (_trackInfo.average())
+               {
+                       _undoStack.add(undo);
+               }
+       }
+
+
        /**
         * Create a new point at the given lat/long coordinates
         * @param inLat latitude
@@ -711,37 +550,6 @@ public class App
        }
 
 
-       /**
-        * Rearrange the waypoints into track order
-        * @param inFunction nearest point, all to end or all to start
-        */
-       public void rearrangeWaypoints(int inFunction)
-       {
-               UndoRearrangeWaypoints undo = new UndoRearrangeWaypoints(_track);
-               boolean success = false;
-               if (inFunction == REARRANGE_TO_START || inFunction == REARRANGE_TO_END)
-               {
-                       // Collect the waypoints to the start or end of the track
-                       success = _track.collectWaypoints(inFunction == REARRANGE_TO_START);
-               }
-               else
-               {
-                       // Interleave the waypoints into track order
-                       success = _track.interleaveWaypoints();
-               }
-               if (success)
-               {
-                       _undoStack.add(undo);
-                       UpdateMessageBroker.informSubscribers(I18nManager.getText("confirm.rearrangewaypoints"));
-               }
-               else
-               {
-                       JOptionPane.showMessageDialog(_frame, I18nManager.getText("error.rearrange.noop"),
-                               I18nManager.getText("error.function.noop.title"), JOptionPane.WARNING_MESSAGE);
-               }
-       }
-
-
        /**
         * Cut the current selection and move it to before the currently selected point
         */
@@ -782,34 +590,6 @@ public class App
        }
 
 
-       /**
-        * Open a new window with the 3d view
-        */
-       public void show3dWindow()
-       {
-               ThreeDWindow window = WindowFactory.getWindow(this, _frame);
-               if (window == null)
-               {
-                       JOptionPane.showMessageDialog(_frame, I18nManager.getText("error.function.nojava3d"),
-                               I18nManager.getText("error.function.notavailable.title"), JOptionPane.WARNING_MESSAGE);
-               }
-               else
-               {
-                       try
-                       {
-                               // Pass the track object and show the window
-                               window.setTrack(_track);
-                               window.show();
-                       }
-                       catch (ThreeDException e)
-                       {
-                               JOptionPane.showMessageDialog(_frame, I18nManager.getText("error.3d") + ": " + e.getMessage(),
-                                       I18nManager.getText("error.3d.title"), JOptionPane.ERROR_MESSAGE);
-                       }
-               }
-       }
-
-
        /**
         * Select all points
         */
@@ -825,6 +605,7 @@ public class App
        {
                // deselect point, range and photo
                _trackInfo.getSelection().clearAll();
+               _track.clearDeletionMarkers();
        }
 
 
@@ -835,44 +616,25 @@ public class App
         * @param inAltFormat altitude format
         * @param inFilename filename used
         */
-       public void informDataLoaded(Field[] inFieldArray, Object[][] inDataArray, int inAltFormat, String inFilename)
-       {
-               informDataLoaded(inFieldArray, inDataArray, inAltFormat, inFilename, false);
-       }
-
-       /**
-        * Receive loaded data and optionally merge with current Track
-        * @param inFieldArray array of fields
-        * @param inDataArray array of data
-        * @param inAltFormat altitude format
-        * @param inFilename filename used
-        * @param inOverrideAppend true to override append question and always append
-        */
-       public void informDataLoaded(Field[] inFieldArray, Object[][] inDataArray, int inAltFormat,
-               String inFilename, boolean inOverrideAppend)
+       public void informDataLoaded(Field[] inFieldArray, Object[][] inDataArray, Altitude.Format inAltFormat,
+               String inFilename)
        {
                // Check whether loaded array can be properly parsed into a Track
                Track loadedTrack = new Track();
                loadedTrack.load(inFieldArray, inDataArray, inAltFormat);
                if (loadedTrack.getNumPoints() <= 0)
                {
-                       JOptionPane.showMessageDialog(_frame,
-                               I18nManager.getText("error.load.nopoints"),
-                               I18nManager.getText("error.load.dialogtitle"),
-                               JOptionPane.ERROR_MESSAGE);
+                       showErrorMessage("error.load.dialogtitle", "error.load.nopoints");
                        return;
                }
                // Decide whether to load or append
-               if (_track != null && _track.getNumPoints() > 0)
+               if (_track.getNumPoints() > 0)
                {
                        // ask whether to replace or append
-                       int answer = JOptionPane.YES_OPTION;
-                       if (!inOverrideAppend) {
-                               answer = JOptionPane.showConfirmDialog(_frame,
-                                       I18nManager.getText("dialog.openappend.text"),
-                                       I18nManager.getText("dialog.openappend.title"),
-                                       JOptionPane.YES_NO_CANCEL_OPTION);
-                       }
+                       int answer = JOptionPane.showConfirmDialog(_frame,
+                               I18nManager.getText("dialog.openappend.text"),
+                               I18nManager.getText("dialog.openappend.title"),
+                               JOptionPane.YES_NO_CANCEL_OPTION);
                        if (answer == JOptionPane.YES_OPTION)
                        {
                                // append data to current Track
@@ -898,9 +660,8 @@ public class App
                                }
                                _undoStack.add(new UndoLoad(_trackInfo, inDataArray.length, photos));
                                _lastSavePosition = _undoStack.size();
-                               // TODO: Should be possible to reuse the Track object already loaded?
-                               _trackInfo.selectPoint(null);
-                               _trackInfo.loadTrack(inFieldArray, inDataArray, inAltFormat);
+                               _trackInfo.getSelection().clearAll();
+                               _track.load(loadedTrack);
                                _trackInfo.getFileInfo().setFile(inFilename);
                                if (photos != null)
                                {
@@ -910,10 +671,11 @@ public class App
                }
                else
                {
-                       // currently no data held, so use received data
+                       // Currently no data held, so transfer received data
                        _undoStack.add(new UndoLoad(_trackInfo, inDataArray.length, null));
                        _lastSavePosition = _undoStack.size();
-                       _trackInfo.loadTrack(inFieldArray, inDataArray, inAltFormat);
+                       _trackInfo.getSelection().clearAll();
+                       _track.load(loadedTrack);
                        _trackInfo.getFileInfo().setFile(inFilename);
                }
                UpdateMessageBroker.informSubscribers();
@@ -928,7 +690,7 @@ public class App
         * Accept a list of loaded photos
         * @param inPhotoSet Set of Photo objects
         */
-       public void informPhotosLoaded(Set inPhotoSet)
+       public void informPhotosLoaded(Set<Photo> inPhotoSet)
        {
                if (inPhotoSet != null && !inPhotoSet.isEmpty())
                {
@@ -1063,117 +825,6 @@ public class App
        }
 
 
-       /**
-        * Begin the photo correlation process by invoking dialog
-        */
-       public void beginCorrelatePhotos()
-       {
-               PhotoCorrelator correlator = new PhotoCorrelator(this, _frame);
-               // TODO: Do we need to keep a reference to this Photo Correlator object to reuse it later?
-               correlator.begin();
-       }
-
-
-       /**
-        * Finish the photo correlation process
-        * @param inPointPairs array of PointPair objects describing operation
-        */
-       public void finishCorrelatePhotos(PointPair[] inPointPairs)
-       {
-               // TODO: This method is too big for App, but where should it go?
-               if (inPointPairs != null && inPointPairs.length > 0)
-               {
-                       // begin to construct undo information
-                       UndoCorrelatePhotos undo = new UndoCorrelatePhotos(_trackInfo);
-                       // loop over Photos
-                       int arraySize = inPointPairs.length;
-                       int i = 0, numPhotos = 0;
-                       int numPointsToCreate = 0;
-                       PointPair pair = null;
-                       for (i=0; i<arraySize; i++)
-                       {
-                               pair = inPointPairs[i];
-                               if (pair != null && pair.isValid())
-                               {
-                                       if (pair.getMinSeconds() == 0L)
-                                       {
-                                               // exact match
-                                               Photo pointPhoto = pair.getPointBefore().getPhoto();
-                                               if (pointPhoto == null)
-                                               {
-                                                       // photo coincides with photoless point so connect the two
-                                                       pair.getPointBefore().setPhoto(pair.getPhoto());
-                                                       pair.getPhoto().setDataPoint(pair.getPointBefore());
-                                               }
-                                               else if (pointPhoto.equals(pair.getPhoto()))
-                                               {
-                                                       // photo is already connected, nothing to do
-                                               }
-                                               else
-                                               {
-                                                       // point is already connected to a different photo, so need to clone point
-                                                       numPointsToCreate++;
-                                               }
-                                       }
-                                       else
-                                       {
-                                               // photo time falls between two points, so need to interpolate new one
-                                               numPointsToCreate++;
-                                       }
-                                       numPhotos++;
-                               }
-                       }
-                       // Second loop, to create points if necessary
-                       if (numPointsToCreate > 0)
-                       {
-                               // make new array for added points
-                               DataPoint[] addedPoints = new DataPoint[numPointsToCreate];
-                               int pointNum = 0;
-                               DataPoint pointToAdd = null;
-                               for (i=0; i<arraySize; i++)
-                               {
-                                       pair = inPointPairs[i];
-                                       if (pair != null && pair.isValid())
-                                       {
-                                               pointToAdd = null;
-                                               if (pair.getMinSeconds() == 0L && pair.getPointBefore().getPhoto() != null
-                                                && !pair.getPointBefore().getPhoto().equals(pair.getPhoto()))
-                                               {
-                                                       // clone point
-                                                       pointToAdd = pair.getPointBefore().clonePoint();
-                                               }
-                                               else if (pair.getMinSeconds() > 0L)
-                                               {
-                                                       // interpolate point
-                                                       pointToAdd = DataPoint.interpolate(pair.getPointBefore(), pair.getPointAfter(), pair.getFraction());
-                                               }
-                                               if (pointToAdd != null)
-                                               {
-                                                       // link photo to point
-                                                       pointToAdd.setPhoto(pair.getPhoto());
-                                                       pair.getPhoto().setDataPoint(pointToAdd);
-                                                       // set to start of segment so not joined in track
-                                                       pointToAdd.setSegmentStart(true);
-                                                       // add to point array
-                                                       addedPoints[pointNum] = pointToAdd;
-                                                       pointNum++;
-                                               }
-                                       }
-                               }
-                               // expand track
-                               _track.appendPoints(addedPoints);
-                       }
-                       // add undo information to stack
-                       undo.setNumPhotosCorrelated(numPhotos);
-                       _undoStack.add(undo);
-                       // confirm correlation
-                       UpdateMessageBroker.informSubscribers("" + numPhotos + " "
-                                + (numPhotos==1?I18nManager.getText("confirm.correlate.single"):I18nManager.getText("confirm.correlate.multi")));
-                       // observers already informed by track update
-               }
-       }
-
-
        /**
         * Save the coordinates of photos in their exif data
         */
@@ -1246,7 +897,7 @@ public class App
                {
                        for (int i=0; i<inNumUndos; i++)
                        {
-                               ((UndoOperation) _undoStack.pop()).performUndo(_trackInfo);
+                               _undoStack.pop().performUndo(_trackInfo);
                        }
                        String message = "" + inNumUndos + " "
                                 + (inNumUndos==1?I18nManager.getText("confirm.undo.single"):I18nManager.getText("confirm.undo.multi"));
@@ -1254,10 +905,8 @@ public class App
                }
                catch (UndoException ue)
                {
-                       JOptionPane.showMessageDialog(_frame,
-                               I18nManager.getText("error.undofailed.text") + " : " + ue.getMessage(),
-                               I18nManager.getText("error.undofailed.title"),
-                               JOptionPane.ERROR_MESSAGE);
+                       showErrorMessageNoLookup("error.undofailed.title",
+                               I18nManager.getText("error.undofailed.text") + " : " + ue.getMessage());
                        _undoStack.clear();
                        UpdateMessageBroker.informSubscribers();
                }
@@ -1286,29 +935,33 @@ public class App
        }
 
        /**
-        * Show a brief help message
+        * Show a map url in an external browser
+        * @param inSourceIndex index of map source to use
         */
-       public void showHelp()
+       public void showExternalMap(int inSourceIndex)
        {
-               // show the dialog and offer to open home page
-               Object[] buttonTexts = {I18nManager.getText("button.showwebpage"), I18nManager.getText("button.cancel")};
-               if (JOptionPane.showOptionDialog(_frame, I18nManager.getText("dialog.help.help"),
-                               I18nManager.getText("menu.help"), JOptionPane.YES_NO_OPTION,
-                               JOptionPane.INFORMATION_MESSAGE, null, buttonTexts, buttonTexts[1])
-                       == JOptionPane.YES_OPTION)
-               {
-                       // User selected to launch home page
-                       if (_browserLauncher == null) {_browserLauncher = new BrowserLauncher();}
-                       _browserLauncher.launchBrowser("http://activityworkshop.net/software/prune/index.html");
-               }
+               BrowserLauncher.launchBrowser(UrlGenerator.generateUrl(inSourceIndex, _trackInfo));
        }
 
        /**
-        * Show a map url in an external browser
+        * Display a standard error message
+        * @param inTitleKey key to lookup for window title
+        * @param inMessageKey key to lookup for error message
         */
-       public void showExternalMap(int inSourceIndex)
+       public void showErrorMessage(String inTitleKey, String inMessageKey)
+       {
+               JOptionPane.showMessageDialog(_frame, I18nManager.getText(inMessageKey),
+                       I18nManager.getText(inTitleKey), JOptionPane.ERROR_MESSAGE);
+       }
+
+       /**
+        * Display a standard error message
+        * @param inTitleKey key to lookup for window title
+        * @param inMessage error message
+        */
+       public void showErrorMessageNoLookup(String inTitleKey, String inMessage)
        {
-               if (_browserLauncher == null) {_browserLauncher = new BrowserLauncher();}
-               _browserLauncher.launchBrowser(UrlGenerator.generateUrl(inSourceIndex, _trackInfo));
+               JOptionPane.showMessageDialog(_frame, inMessage,
+                       I18nManager.getText(inTitleKey), JOptionPane.ERROR_MESSAGE);
        }
 }
index d667b599e6748ed302d1e2a1f29e6c02d8442525..aa36c158930cc07e0d15a21ec98363cc1988030c 100644 (file)
@@ -21,7 +21,16 @@ public abstract class Config
        private static String _povrayFont = null;
        /** True to use metric units */
        private static boolean _metricUnits = true;
+       /** Path to gnuplot executable */
+       private static String _gnuplotPath = null;
+       /** Index of selected map tile server */
+       private static int _mapTileServerIndex = -1;
+       /** URL for freeform map tile server */
+       private static String _mapTileServerUrl = null;
+       /** File from which Config was loaded */
+       private static File _configFile = null;
 
+       // TODO: Need setters for all these parameters if want to make the config saveable
 
        /** Default config file */
        private static final File DEFAULT_CONFIG_FILE = new File(".pruneconfig");
@@ -38,7 +47,12 @@ public abstract class Config
        private static final String KEY_POVRAY_FONT = "prune.povrayfont";
        /** Key for metric/imperial */
        private static final String KEY_METRIC_UNITS = "prune.metricunits";
-       // TODO: Save config file location so save possible
+       /** Key for gpsbabel path */
+       private static final String KEY_GNUPLOTPATH = "prune.gnuplotpath";
+       /** Key for map server index */
+       private static final String KEY_MAPSERVERINDEX = "prune.mapserverindex";
+       /** Key for map server url */
+       private static final String KEY_MAPSERVERURL = "prune.mapserverurl";
 
 
        /**
@@ -73,6 +87,7 @@ public abstract class Config
        /**
         * Load configuration from file
         * @param inFile file to load
+        * @throws ConfigException if specified file couldn't be read
         */
        public static void loadFile(File inFile) throws ConfigException
        {
@@ -80,14 +95,21 @@ public abstract class Config
                Properties props = getDefaultProperties();
                // Try to load the file into a properties object
                boolean loadFailed = false;
+               FileInputStream fis = null;
                try
                {
-                       props.load(new FileInputStream(inFile));
+                       fis = new FileInputStream(inFile);
+                       props.load(fis);
                }
-               catch (Exception e)
-               {
+               catch (Exception e) {
                        loadFailed = true;
                }
+               finally {
+                       if (fis != null) try {
+                               fis.close();
+                       }
+                       catch (Exception e) {}
+               }
                // Save the properties we know about, ignore the rest
                _langCode = props.getProperty(KEY_LANGUAGE_CODE);
                String dir = props.getProperty(KEY_WORKING_DIR);
@@ -97,9 +119,15 @@ public abstract class Config
                _povrayFont = props.getProperty(KEY_POVRAY_FONT);
                String useMetric = props.getProperty(KEY_METRIC_UNITS);
                _metricUnits = (useMetric == null || useMetric.equals("") || useMetric.toLowerCase().equals("y"));
+               _gnuplotPath = props.getProperty(KEY_GNUPLOTPATH);
+               if (_gnuplotPath == null || _gnuplotPath.equals("")) {_gnuplotPath = "gnuplot";}
+               _mapTileServerIndex = parseInt(props.getProperty(KEY_MAPSERVERINDEX));
+               _mapTileServerUrl = props.getProperty(KEY_MAPSERVERURL);
                if (loadFailed) {
                        throw new ConfigException();
                }
+               // Store location of successfully loaded config file
+               _configFile = inFile;
        }
 
        /**
@@ -115,6 +143,20 @@ public abstract class Config
                return props;
        }
 
+       /**
+        * @param inString String to parse
+        * @return int value of String, or 0 if unparseable
+        */
+       private static int parseInt(String inString)
+       {
+               int val = 0;
+               try {
+                       val = Integer.parseInt(inString);
+               }
+               catch (Exception e) {} // ignore, value stays zero
+               return val;
+       }
+
        /** @return language code */
        public static String getLanguageCode()
        {
@@ -144,4 +186,52 @@ public abstract class Config
        {
                return _metricUnits;
        }
+
+       /** @param inMetric true to use metric units */
+       public static void setUseMetricUnits(boolean inMetric)
+       {
+               _metricUnits = inMetric;
+       }
+
+       /** @return path to gnuplot */
+       public static String getGnuplotPath()
+       {
+               return _gnuplotPath;
+       }
+
+       /** @param inPath path to Gnuplot */
+       public static void setGnuplotPath(String inPath)
+       {
+               _gnuplotPath = inPath;
+       }
+
+       /** @return index of map server */
+       public static int getMapServerIndex()
+       {
+               return _mapTileServerIndex;
+       }
+
+       /** @param inIndex selected index */
+       public static void setMapServerIndex(int inIndex)
+       {
+               _mapTileServerIndex = inIndex;
+       }
+
+       /** @return url of map server */
+       public static String getMapServerUrl()
+       {
+               return _mapTileServerUrl;
+       }
+
+       /** @param inUrl url of map server */
+       public static void setMapServerUrl(String inUrl)
+       {
+               _mapTileServerUrl = inUrl;
+       }
+
+       /** @return File from which config was loaded (or null) */
+       public static File getConfigFile()
+       {
+               return _configFile;
+       }
 }
index ceaed70a5a9903f333edb96573e7f7227f6e3066..128e35fd9d173bee01547b9c3b3e65f03390c3be 100644 (file)
@@ -13,6 +13,8 @@ public interface DataSubscriber
        public static final byte PHOTOS_MODIFIED       = 16;
        public static final byte UNITS_CHANGED         = 32;
        public static final byte ALL                   = 63;
+       public static final byte MAPSERVER_CHANGED     = 64;
+
 
        /**
         * Inform clients that data has been updated
index 36c496a6e24229603769d5ff8405cc397ff645f8..22291fb122968331a6f1a52b28d4f9fc56782cb7 100644 (file)
@@ -37,6 +37,15 @@ public abstract class ExternalTools
                return check("gpsbabel -V");
        }
 
+       /**
+        * Attempt to call gnuplot to see if it's installed / available in path
+        * @return true if found, false otherwise
+        */
+       public static boolean isGnuplotInstalled()
+       {
+               return check(Config.getGnuplotPath() + " -V");
+       }
+
        /**
         * Attempt to call the specified command
         * @return true if found, false otherwise
diff --git a/tim/prune/FunctionLibrary.java b/tim/prune/FunctionLibrary.java
new file mode 100644 (file)
index 0000000..3227c31
--- /dev/null
@@ -0,0 +1,66 @@
+package tim.prune;
+
+import tim.prune.correlate.PhotoCorrelator;
+import tim.prune.function.AboutScreen;
+import tim.prune.function.AddTimeOffset;
+import tim.prune.function.CheckVersionScreen;
+import tim.prune.function.HelpScreen;
+import tim.prune.function.RearrangeWaypointsFunction;
+import tim.prune.function.SetMapBgFunction;
+import tim.prune.function.ShowThreeDFunction;
+import tim.prune.function.charts.Charter;
+import tim.prune.function.compress.CompressTrackFunction;
+import tim.prune.function.distance.DistanceFunction;
+import tim.prune.load.GpsLoader;
+import tim.prune.save.GpsSaver;
+import tim.prune.save.GpxExporter;
+import tim.prune.save.KmlExporter;
+import tim.prune.save.PovExporter;
+
+/**
+ * Class to provide access to functions
+ */
+public abstract class FunctionLibrary
+{
+       public static GenericFunction FUNCTION_GPXEXPORT = null;
+       public static GenericFunction FUNCTION_KMLEXPORT = null;
+       public static PovExporter FUNCTION_POVEXPORT     = null;
+       public static GenericFunction FUNCTION_GPSLOAD  = null;
+       public static GenericFunction FUNCTION_GPSSAVE  = null;
+       public static RearrangeWaypointsFunction FUNCTION_REARRANGE_WAYPOINTS = null;
+       public static GenericFunction FUNCTION_COMPRESS = null;
+       public static GenericFunction FUNCTION_ADD_TIME_OFFSET  = null;
+       public static GenericFunction FUNCTION_CORRELATE_PHOTOS = null;
+       public static GenericFunction FUNCTION_CHARTS = null;
+       public static GenericFunction FUNCTION_3D     = null;
+       public static GenericFunction FUNCTION_DISTANCES  = null;
+       public static GenericFunction FUNCTION_SET_MAP_BG = null;
+       public static GenericFunction FUNCTION_HELP   = null;
+       public static GenericFunction FUNCTION_ABOUT  = null;
+       public static GenericFunction FUNCTION_CHECK_VERSION  = null;
+
+
+       /**
+        * Initialise library of functions
+        * @param inApp App object to give to functions
+        */
+       public static void initialise(App inApp)
+       {
+               FUNCTION_GPXEXPORT = new GpxExporter(inApp);
+               FUNCTION_KMLEXPORT = new KmlExporter(inApp);
+               FUNCTION_POVEXPORT = new PovExporter(inApp);
+               FUNCTION_GPSLOAD   = new GpsLoader(inApp);
+               FUNCTION_GPSSAVE   = new GpsSaver(inApp);
+               FUNCTION_REARRANGE_WAYPOINTS = new RearrangeWaypointsFunction(inApp);
+               FUNCTION_COMPRESS = new CompressTrackFunction(inApp);
+               FUNCTION_ADD_TIME_OFFSET = new AddTimeOffset(inApp);
+               FUNCTION_CORRELATE_PHOTOS = new PhotoCorrelator(inApp);
+               FUNCTION_CHARTS = new Charter(inApp);
+               FUNCTION_3D     = new ShowThreeDFunction(inApp);
+               FUNCTION_DISTANCES = new DistanceFunction(inApp);
+               FUNCTION_SET_MAP_BG = new SetMapBgFunction(inApp);
+               FUNCTION_HELP   = new HelpScreen(inApp);
+               FUNCTION_ABOUT  = new AboutScreen(inApp);
+               FUNCTION_CHECK_VERSION= new CheckVersionScreen(inApp);
+       }
+}
diff --git a/tim/prune/GenericFunction.java b/tim/prune/GenericFunction.java
new file mode 100644 (file)
index 0000000..047ac74
--- /dev/null
@@ -0,0 +1,35 @@
+package tim.prune;
+
+import javax.swing.JFrame;
+
+/**
+ * Generic function class for launching from the app
+ */
+public abstract class GenericFunction
+{
+       /** Reference to app object */
+       protected App _app = null;
+       /** Reference to parent frame */
+       protected JFrame _parentFrame = null;
+
+
+       /**
+        * Constructor
+        * @param inApp app object
+        */
+       public GenericFunction(App inApp)
+       {
+               _app = inApp;
+               _parentFrame = inApp.getFrame();
+       }
+
+       /**
+        * Begin the function
+        */
+       public abstract void begin();
+
+       /**
+        * @return the key for the function name
+        */
+       public abstract String getNameKey();
+}
index eafbf1977de170622e3a8ae3fb1290a59bc126ae..f8e36ad06650109bec383bfee6824e04555ce293 100644 (file)
@@ -19,15 +19,17 @@ import tim.prune.gui.StatusBar;
 import tim.prune.gui.map.MapCanvas;
 
 /**
- * Tool to visualize, edit and prune GPS data
+ * Tool to visualize, edit, convert and prune GPS data
  * Please see the included readme.txt or http://activityworkshop.net
  * This software is copyright activityworkshop.net and made available through the Gnu GPL
  */
 public class GpsPruner
 {
-       // Final build of version 6
-       public static final String VERSION_NUMBER = "6";
-       public static final String BUILD_NUMBER = "117";
+       /** Version number of application, used in about screen and for version check */
+       public static final String VERSION_NUMBER = "7";
+       /** Build number, just used for about screen */
+       public static final String BUILD_NUMBER = "136";
+       /** Static reference to App object */
        private static App APP = null;
 
 
@@ -43,25 +45,28 @@ public class GpsPruner
                boolean showUsage = false;
                for (int i=0; i<args.length; i++)
                {
-                       if (args[i].startsWith("--locale="))
+                       String arg = args[i];
+                       if (arg.startsWith("--locale="))
                        {
-                               locale = getLanguage(args[i].substring(9));
+                               locale = getLanguage(arg.substring(9));
                        }
-                       else if (args[i].startsWith("--lang="))
+                       else if (arg.startsWith("--lang="))
                        {
-                               locale = getLanguage(args[i].substring(7));
+                               locale = getLanguage(arg.substring(7));
                        }
-                       else if (args[i].startsWith("--langfile="))
+                       else if (arg.startsWith("--langfile="))
                        {
-                               langFilename = args[i].substring(11);
+                               langFilename = arg.substring(11);
                        }
-                       else if (args[i].startsWith("--configfile="))
+                       else if (arg.startsWith("--configfile="))
                        {
-                               configFilename = args[i].substring(13);
+                               configFilename = arg.substring(13);
                        }
                        else
                        {
-                               System.out.println("Unknown parameter '" + args[i] + "'.");
+                               if (!arg.startsWith("--help")) {
+                                       System.out.println("Unknown parameter '" + arg + "'.");
+                               }
                                showUsage = true;
                        }
                }
@@ -129,7 +134,7 @@ public class GpsPruner
                APP = new App(frame);
 
                // make menu
-               MenuManager menuManager = new MenuManager(frame, APP, APP.getTrackInfo());
+               MenuManager menuManager = new MenuManager(APP, APP.getTrackInfo());
                frame.setJMenuBar(menuManager.createMenuBar());
                APP.setMenuManager(menuManager);
                UpdateMessageBroker.addSubscriber(menuManager);
@@ -179,7 +184,7 @@ public class GpsPruner
                // finish off and display frame
                frame.pack();
                frame.setSize(650, 450);
-               frame.show();
+               frame.setVisible(true);
                // Set position of map/profile splitter
                midPane.setDividerLocation(0.75);
        }
index 87d1df4997c1ab78f5eb0ac4d0ac7dc95552c5c0..80be52b44f60aa795dbe80039f279334baae7a69 100644 (file)
@@ -53,13 +53,18 @@ public abstract class I18nManager
         */
        public static void addLanguageFile(String inFilename)
        {
+               FileInputStream fis = null;
                try
                {
                        File file = new File(inFilename);
                        ExternalPropsFile = new Properties();
-                       ExternalPropsFile.load(new FileInputStream(file));
+                       fis = new FileInputStream(file);
+                       ExternalPropsFile.load(fis);
                }
                catch (IOException ioe) {}
+               finally { try { fis.close();
+                       } catch (Exception e) {}
+               }
        }
 
 
index 56e7caa87de44d0a1adf4590be0b4c7e503a1e8c..2955efcc69684e6a79002969867d77427e0f97e8 100644 (file)
@@ -49,14 +49,26 @@ A GPS connected to the serial port may appear as /dev/ttyS0.
 This setting controls the default value of the format parameter to gpsbabel.  If you call gpsbabel from the command line, it's the -i parameter.  Example:
    prune.gpsformat=garmin
 
+== Gnuplot path ==
+On linux systems this setting is unnecessary as the gnuplot executable will be found in /usr/bin but on Windows the executable must be called pgnuplot (with an extra p) and may not be in the system path.  This setting controls the default location searched to call gnuplot.
+   prune.gnuplotpath=gnuplot
+
+== Map server ==
+The default map tile server is called Mapnik and shows the maps just like they are in openstreetmap.org.  The following two settings allow other tile servers to be used by default.  The settings are the same as in the dialog View -> Set map background.
+The "mapserverindex" parameter is a number from 0 to 3, where 0=Mapnik, 1=Osma, 2=Opencyclemap and 3=Other.  If the mapserverindex is set to 3, Prune will use the URL given by the "mapserverurl" parameter.
+   prune.mapserverindex=3
+   prune.mapserverurl=http://openpistemap.org/tiles/contours/
+
 == Example file ==
 The following can be used as a template to make your own file.
 
 # Prune configuration file
 prune.directory=/home/user/gps/
-prune.languagecode=ES
+prune.languagecode=EN
 prune.metricunits=y
 prune.povrayfont=crystal.ttf
 prune.gpsdevice=usb:
 prune.gpsformat=garmin
-
+prune.gnuplotpath=gnuplot
+prune.mapserverindex=3
+prune.mapserverurl=http://openpistemap.org/tiles/contours/
index ccf5345103826ee2fb05f9e9b9253562835e2ab2..6c47d0042621e44e2c38d36f867d569533af9663 100644 (file)
@@ -17,7 +17,6 @@ import javax.swing.ButtonGroup;
 import javax.swing.JButton;
 import javax.swing.JComboBox;
 import javax.swing.JDialog;
-import javax.swing.JFrame;
 import javax.swing.JLabel;
 import javax.swing.JOptionPane;
 import javax.swing.JPanel;
@@ -27,6 +26,7 @@ import javax.swing.JTable;
 import javax.swing.JTextField;
 
 import tim.prune.App;
+import tim.prune.GenericFunction;
 import tim.prune.I18nManager;
 import tim.prune.data.DataPoint;
 import tim.prune.data.Distance;
@@ -37,15 +37,14 @@ import tim.prune.data.TimeDifference;
 import tim.prune.data.Timestamp;
 import tim.prune.data.Track;
 import tim.prune.data.TrackInfo;
+import tim.prune.undo.UndoCorrelatePhotos;
 
 /**
  * Class to manage the automatic correlation of photos to points
  * including the GUI stuff to control the correlation options
  */
-public class PhotoCorrelator
+public class PhotoCorrelator extends GenericFunction
 {
-       private App _app;
-       private JFrame _parentFrame;
        private JDialog _dialog;
        private JButton _nextButton = null, _backButton = null;
        private JButton _okButton = null;
@@ -66,19 +65,22 @@ public class PhotoCorrelator
        /**
         * Constructor
         * @param inApp App object to report actions to
-        * @param inFrame parent frame for dialogs
         */
-       public PhotoCorrelator(App inApp, JFrame inFrame)
+       public PhotoCorrelator(App inApp)
        {
-               _app = inApp;
-               _parentFrame = inFrame;
-               _dialog = new JDialog(inFrame, I18nManager.getText("dialog.correlate.title"), true);
-               _dialog.setLocationRelativeTo(inFrame);
+               super(inApp);
+               _dialog = new JDialog(inApp.getFrame(), I18nManager.getText(getNameKey()), true);
+               _dialog.setLocationRelativeTo(inApp.getFrame());
                _dialog.getContentPane().add(makeDialogContents());
                _dialog.pack();
        }
 
 
+       /** Get the name key */
+       public String getNameKey() {
+               return "function.correlatephotos";
+       }
+
        /**
         * Reset dialog and show it
         */
@@ -88,7 +90,7 @@ public class PhotoCorrelator
                if (!_app.getTrackInfo().getTrack().hasData(Field.TIMESTAMP))
                {
                        JOptionPane.showMessageDialog(_parentFrame, I18nManager.getText("dialog.correlate.notimestamps"),
-                               I18nManager.getText("dialog.correlate.title"), JOptionPane.INFORMATION_MESSAGE);
+                               I18nManager.getText(getNameKey()), JOptionPane.INFORMATION_MESSAGE);
                        return;
                }
                // Check for any non-correlated photos, show warning continue/cancel
@@ -96,7 +98,7 @@ public class PhotoCorrelator
                {
                        Object[] buttonTexts = {I18nManager.getText("button.continue"), I18nManager.getText("button.cancel")};
                        if (JOptionPane.showOptionDialog(_parentFrame, I18nManager.getText("dialog.correlate.nouncorrelatedphotos"),
-                                       I18nManager.getText("dialog.correlate.title"), JOptionPane.YES_NO_OPTION,
+                                       I18nManager.getText(getNameKey()), JOptionPane.YES_NO_OPTION,
                                        JOptionPane.WARNING_MESSAGE, null, buttonTexts, buttonTexts[1])
                                == JOptionPane.NO_OPTION)
                        {
@@ -127,7 +129,7 @@ public class PhotoCorrelator
                        _tipLabel.setVisible(true);
                        setupSecondCard(null);
                }
-               _dialog.show();
+               _dialog.setVisible(true);
        }
 
 
@@ -298,7 +300,7 @@ public class PhotoCorrelator
                        {
                                public void actionPerformed(ActionEvent e)
                                {
-                                       _app.finishCorrelatePhotos(getPointPairs());
+                                       finishCorrelation();
                                        _dialog.dispose();
                                }
                        });
@@ -457,7 +459,7 @@ public class PhotoCorrelator
                if (inShowWarning && !model.hasPhotosSelected())
                {
                        JOptionPane.showMessageDialog(_dialog, I18nManager.getText("dialog.correlate.alloutsiderange"),
-                               I18nManager.getText("dialog.correlate.title"), JOptionPane.ERROR_MESSAGE);
+                               I18nManager.getText(getNameKey()), JOptionPane.ERROR_MESSAGE);
                }
        }
 
@@ -503,9 +505,9 @@ public class PhotoCorrelator
        /**
         * @return the selected distance units from the dropdown
         */
-       private int getSelectedDistanceUnits()
+       private Distance.Units getSelectedDistanceUnits()
        {
-               final int[] distUnits = {Distance.UNITS_KILOMETRES, Distance.UNITS_METRES, Distance.UNITS_MILES};
+               final Distance.Units[] distUnits = {Distance.Units.KILOMETRES, Distance.Units.METRES, Distance.Units.MILES};
                return distUnits[_distUnitsDropdown.getSelectedIndex()];
        }
 
@@ -604,7 +606,7 @@ public class PhotoCorrelator
        private static int getMedianIndex(PhotoSelectionTableModel inModel)
        {
                // make sortable list
-               TreeSet set = new TreeSet();
+               TreeSet<TimeIndexPair> set = new TreeSet<TimeIndexPair>();
                // loop through rows of table adding to list
                int numRows = inModel.getRowCount();
                int i;
@@ -615,10 +617,10 @@ public class PhotoCorrelator
                }
                // pull out middle entry and return index
                TimeIndexPair pair = null;
-               Iterator iterator = set.iterator();
+               Iterator<TimeIndexPair> iterator = set.iterator();
                for (i=0; i<(numRows+1)/2; i++)
                {
-                       pair = (TimeIndexPair) iterator.next();
+                       pair = iterator.next();
                }
                return pair.getIndex();
        }
@@ -654,4 +656,101 @@ public class PhotoCorrelator
                // no uncorrelated photos found
                return false;
        }
+
+       /**
+        * Finish the correlation by modifying the track
+        * and passing the Undo information back to the App
+        */
+       private void finishCorrelation()
+       {
+               PointPair[] pointPairs = getPointPairs();
+               if (pointPairs == null || pointPairs.length <= 0) {return;}
+
+               // begin to construct undo information
+               UndoCorrelatePhotos undo = new UndoCorrelatePhotos(_app.getTrackInfo());
+               // loop over Photos
+               int arraySize = pointPairs.length;
+               int i = 0, numPhotos = 0;
+               int numPointsToCreate = 0;
+               PointPair pair = null;
+               for (i=0; i<arraySize; i++)
+               {
+                       pair = pointPairs[i];
+                       if (pair != null && pair.isValid())
+                       {
+                               if (pair.getMinSeconds() == 0L)
+                               {
+                                       // exact match
+                                       Photo pointPhoto = pair.getPointBefore().getPhoto();
+                                       if (pointPhoto == null)
+                                       {
+                                               // photo coincides with photoless point so connect the two
+                                               pair.getPointBefore().setPhoto(pair.getPhoto());
+                                               pair.getPhoto().setDataPoint(pair.getPointBefore());
+                                       }
+                                       else if (pointPhoto.equals(pair.getPhoto()))
+                                       {
+                                               // photo is already connected, nothing to do
+                                       }
+                                       else
+                                       {
+                                               // point is already connected to a different photo, so need to clone point
+                                               numPointsToCreate++;
+                                       }
+                               }
+                               else
+                               {
+                                       // photo time falls between two points, so need to interpolate new one
+                                       numPointsToCreate++;
+                               }
+                               numPhotos++;
+                       }
+               }
+               // Second loop, to create points if necessary
+               if (numPointsToCreate > 0)
+               {
+                       // make new array for added points
+                       DataPoint[] addedPoints = new DataPoint[numPointsToCreate];
+                       int pointNum = 0;
+                       DataPoint pointToAdd = null;
+                       for (i=0; i<arraySize; i++)
+                       {
+                               pair = pointPairs[i];
+                               if (pair != null && pair.isValid())
+                               {
+                                       pointToAdd = null;
+                                       if (pair.getMinSeconds() == 0L && pair.getPointBefore().getPhoto() != null
+                                        && !pair.getPointBefore().getPhoto().equals(pair.getPhoto()))
+                                       {
+                                               // clone point
+                                               pointToAdd = pair.getPointBefore().clonePoint();
+                                       }
+                                       else if (pair.getMinSeconds() > 0L)
+                                       {
+                                               // interpolate point
+                                               pointToAdd = DataPoint.interpolate(pair.getPointBefore(), pair.getPointAfter(), pair.getFraction());
+                                       }
+                                       if (pointToAdd != null)
+                                       {
+                                               // link photo to point
+                                               pointToAdd.setPhoto(pair.getPhoto());
+                                               pair.getPhoto().setDataPoint(pointToAdd);
+                                               // set to start of segment so not joined in track
+                                               pointToAdd.setSegmentStart(true);
+                                               // add to point array
+                                               addedPoints[pointNum] = pointToAdd;
+                                               pointNum++;
+                                       }
+                               }
+                       }
+                       // expand track
+                       _app.getTrackInfo().getTrack().appendPoints(addedPoints);
+               }
+
+               // send undo information back to controlling app
+               undo.setNumPhotosCorrelated(numPhotos);
+               _app.completeFunction(undo, ("" + numPhotos + " "
+                        + (numPhotos==1?I18nManager.getText("confirm.correlate.single"):I18nManager.getText("confirm.correlate.multi"))));
+               // observers already informed by track update
+       }
 }
index aed044dae366bb8df19443e46e0b6a1177cb39f7..47d48b717d9a172eefcf2924d248e35538f12872 100644 (file)
@@ -12,9 +12,9 @@ import tim.prune.data.Distance;
 public class PhotoPreviewTableModel extends AbstractTableModel
 {
        /** ArrayList containing TableRow objects */
-       private ArrayList _list = new ArrayList();
+       private ArrayList<PhotoPreviewTableRow> _list = new ArrayList<PhotoPreviewTableRow>();
        /** Distance units */
-       private int _distanceUnits = Distance.UNITS_KILOMETRES;
+       private Distance.Units _distanceUnits = Distance.Units.KILOMETRES;
        /** Number formatter */
        private static final NumberFormat FORMAT_ONE_DP = NumberFormat.getNumberInstance();
 
@@ -67,8 +67,7 @@ public class PhotoPreviewTableModel extends AbstractTableModel
         */
        public PhotoPreviewTableRow getRow(int inRowIndex)
        {
-               PhotoPreviewTableRow row = (PhotoPreviewTableRow) _list.get(inRowIndex);
-               return row;
+               return _list.get(inRowIndex);
        }
 
 
@@ -80,7 +79,7 @@ public class PhotoPreviewTableModel extends AbstractTableModel
         */
        public Object getValueAt(int inRowIndex, int inColumnIndex)
        {
-               PhotoPreviewTableRow row = (PhotoPreviewTableRow) _list.get(inRowIndex);
+               PhotoPreviewTableRow row = _list.get(inRowIndex);
                if (inColumnIndex == 0) return row.getPhoto().getFile().getName();
                else if (inColumnIndex == 1) {
                        return row.getPhoto().getTimestamp().getText();
@@ -104,7 +103,7 @@ public class PhotoPreviewTableModel extends AbstractTableModel
        /**
         * @param inUnits the distance units to use
         */
-       public void setDistanceUnits(int inUnits)
+       public void setDistanceUnits(Distance.Units inUnits)
        {
                _distanceUnits = inUnits;
        }
@@ -133,7 +132,7 @@ public class PhotoPreviewTableModel extends AbstractTableModel
         * Get the class of objects in the given column
         * @see javax.swing.table.AbstractTableModel#getColumnClass(int)
         */
-       public Class getColumnClass(int inColumnIndex)
+       public Class<?> getColumnClass(int inColumnIndex)
        {
                if (inColumnIndex == 4) {return Boolean.class;}
                return super.getColumnClass(inColumnIndex);
index 9df0b52394ad734331a19fdf450a565857314df9..70955375c2022fdad279dcf1bfeedb266afbd902 100644 (file)
@@ -31,7 +31,7 @@ public class PhotoPreviewTableRow extends PhotoSelectionTableRow
         * @param inUnits units to use
         * @return distance in selected format
         */
-       public double getDistance(int inUnits)
+       public double getDistance(Distance.Units inUnits)
        {
                return Distance.convertRadiansToDistance(_distance, inUnits);
        }
index 2e9d315b283fc276aa44254479f0a1354109fcc4..dbd9d8e572dcdd21b70acb154125c5c2a12c5e9c 100644 (file)
@@ -11,7 +11,7 @@ import tim.prune.data.Photo;
  */
 public class PhotoSelectionTableModel extends AbstractTableModel
 {
-       private ArrayList _list = new ArrayList();
+       private ArrayList<PhotoSelectionTableRow> _list = new ArrayList<PhotoSelectionTableRow>();
 
 
        /**
@@ -53,8 +53,7 @@ public class PhotoSelectionTableModel extends AbstractTableModel
         */
        public PhotoSelectionTableRow getRow(int inRowIndex)
        {
-               PhotoSelectionTableRow row = (PhotoSelectionTableRow) _list.get(inRowIndex);
-               return row;
+               return _list.get(inRowIndex);
        }
 
 
@@ -67,7 +66,7 @@ public class PhotoSelectionTableModel extends AbstractTableModel
        public Object getValueAt(int inRowIndex, int inColumnIndex)
        {
                // TODO: only show time of photos (not date) if dates all identical
-               PhotoSelectionTableRow row = (PhotoSelectionTableRow) _list.get(inRowIndex);
+               PhotoSelectionTableRow row = _list.get(inRowIndex);
                if (inColumnIndex == 0) return row.getPhoto().getFile().getName();
                else if (inColumnIndex == 1) return row.getPhoto().getTimestamp().getText();
                else if (inColumnIndex == 2) return row.getTimeDiff().getDescription();
index 50305d44186892ec460fc8249678bd32acf4e9ca..775b151ac32e92005ae8ca005ba1b8e67ebf5aba 100644 (file)
@@ -4,7 +4,7 @@ package tim.prune.correlate;
  * Simple class to hold a time and an index.
  * Used in a TreeSet for calculating median time difference
  */
-public class TimeIndexPair implements Comparable
+public class TimeIndexPair implements Comparable<TimeIndexPair>
 {
        /** Time as long */
        private long _time = 0L;
@@ -37,9 +37,20 @@ public class TimeIndexPair implements Comparable
         * Compare two TimeIndexPair objects
         * @see java.lang.Comparable#compareTo(java.lang.Object)
         */
-       public int compareTo(Object inOther)
+       public int compareTo(TimeIndexPair inOther)
        {
-               TimeIndexPair other = (TimeIndexPair) inOther;
-               return (int) (_time - other._time);
+               return (int) (_time - inOther._time);
+       }
+
+       /**
+        * Override equals method to match compareTo
+        */
+       public boolean equals(Object inOther)
+       {
+               if (inOther instanceof TimeIndexPair) {
+                       TimeIndexPair otherPair = (TimeIndexPair) inOther;
+                       return _time == otherPair._time;
+               }
+               return false;
        }
 }
index 78a98e04f93fba650517cc79201c8d322c379fa6..495e84491746f4c1c011cb4b0d64cb1c7b0bde91 100644 (file)
@@ -7,20 +7,25 @@ public class Altitude
 {
        private boolean _valid = false;
        private int _value = 0;
-       private int _format = -1;
+       private Format _format = Format.NO_FORMAT;
        private String _stringValue = null;
 
        /** Altitude formats */
-       public static final int FORMAT_NONE   = -1;
-       public static final int FORMAT_METRES = 0;
-       public static final int FORMAT_FEET = 1;
+       public enum Format {
+               /** No format */
+               NO_FORMAT,
+               /** Metres */
+               METRES,
+               /** Feet */
+               FEET
+       }
 
        /** Constants for conversion */
        private static final double CONVERT_FEET_TO_METRES = 0.3048;
        private static final double CONVERT_METRES_TO_FEET = 3.28084;
 
        /** Constant for no altitude value */
-       public static final Altitude NONE = new Altitude(null, FORMAT_NONE);
+       public static final Altitude NONE = new Altitude(null, Format.NO_FORMAT);
 
 
        /**
@@ -28,7 +33,7 @@ public class Altitude
         * @param inString string to parse
         * @param inFormat format of altitude, either metres or feet
         */
-       public Altitude(String inString, int inFormat)
+       public Altitude(String inString, Format inFormat)
        {
                if (inString != null && !inString.equals(""))
                {
@@ -49,7 +54,7 @@ public class Altitude
         * @param inValue int value of altitude
         * @param inFormat format of altitude, either metres or feet
         */
-       public Altitude(int inValue, int inFormat)
+       public Altitude(int inValue, Format inFormat)
        {
                _value = inValue;
                _format = inFormat;
@@ -78,7 +83,7 @@ public class Altitude
        /**
         * @return format of number
         */
-       public int getFormat()
+       public Format getFormat()
        {
                return _format;
        }
@@ -89,14 +94,14 @@ public class Altitude
         * @param inFormat desired format, either FORMAT_METRES or FORMAT_FEET
         * @return value as an int
         */
-       public int getValue(int inFormat)
+       public int getValue(Format inFormat)
        {
                // Note possible rounding errors here if converting to/from units
                if (inFormat == _format)
                        return _value;
-               if (inFormat == FORMAT_METRES)
+               if (inFormat == Format.METRES)
                        return (int) (_value * CONVERT_FEET_TO_METRES);
-               if (inFormat == FORMAT_FEET)
+               if (inFormat == Format.FEET)
                        return (int) (_value * CONVERT_METRES_TO_FEET);
                return _value;
        }
@@ -106,8 +111,9 @@ public class Altitude
         * @param inFormat specified format
         * @return string value, if possible the original one
         */
-       public String getStringValue(int inFormat)
+       public String getStringValue(Format inFormat)
        {
+               if (!_valid) {return "";}
                if (inFormat == _format && _stringValue != null && !_stringValue.equals("")) {
                        return _stringValue;
                }
@@ -140,9 +146,9 @@ public class Altitude
        {
                // Check if altitudes are valid
                if (inStart == null || inEnd == null || !inStart.isValid() || !inEnd.isValid())
-                       return new Altitude(null, FORMAT_NONE);
+                       return Altitude.NONE;
                // Use altitude format of first point
-               int altFormat = inStart.getFormat();
+               Format altFormat = inStart.getFormat();
                int startValue = inStart.getValue();
                int endValue = inEnd.getValue(altFormat);
                // interpolate between start and end
index aff974d1109231707f56397750f2388d5e005b13..98fa20edd5295f0e8097ec3407c98856a8fa0f53 100644 (file)
@@ -7,7 +7,7 @@ package tim.prune.data;
 public class AltitudeRange
 {
        private IntegerRange _range = new IntegerRange();
-       private int _format = Altitude.FORMAT_NONE;
+       private Altitude.Format _format = Altitude.Format.NO_FORMAT;
 
 
        /**
@@ -16,7 +16,7 @@ public class AltitudeRange
        public void clear()
        {
                _range.clear();
-               _format = Altitude.FORMAT_NONE;
+               _format = Altitude.Format.NO_FORMAT;
        }
 
 
@@ -30,7 +30,7 @@ public class AltitudeRange
                {
                        int altValue = inAltitude.getValue(_format);
                        _range.addValue(altValue);
-                       if (_format == Altitude.FORMAT_NONE)
+                       if (_format == Altitude.Format.NO_FORMAT)
                        {
                                _format = inAltitude.getFormat();
                        }
@@ -39,11 +39,11 @@ public class AltitudeRange
 
 
        /**
-        * @return true if positive data values were found
+        * @return true if altitude range found
         */
-       public boolean hasData()
+       public boolean hasRange()
        {
-               return (_range.hasData());
+               return _range.getMaximum() > _range.getMinimum();
        }
 
 
@@ -68,7 +68,7 @@ public class AltitudeRange
        /**
         * @return the altitude format used
         */
-       public int getFormat()
+       public Altitude.Format getFormat()
        {
                return _format;
        }
index 7e52d839cf1dfae49a649df188eac87d902b7928..19a1688ed45cc0d0f99385c0b02ba22d50041259 100644 (file)
@@ -1,5 +1,9 @@
 package tim.prune.data;
 
+import java.text.DecimalFormat;
+import java.text.NumberFormat;
+import java.util.Locale;
+
 /**
  * Class to represent a lat/long coordinate
  * and provide conversion functions
@@ -11,7 +15,7 @@ public abstract class Coordinate
        public static final int EAST = 1;
        public static final int SOUTH = 2;
        public static final int WEST = 3;
-       public static final char[] PRINTABLE_CARDINALS = {'N', 'E', 'S', 'W'};
+       private static final char[] PRINTABLE_CARDINALS = {'N', 'E', 'S', 'W'};
        public static final int FORMAT_DEG_MIN_SEC = 10;
        public static final int FORMAT_DEG_MIN = 11;
        public static final int FORMAT_DEG = 12;
@@ -19,8 +23,16 @@ public abstract class Coordinate
        public static final int FORMAT_DEG_WHOLE_MIN = 14;
        public static final int FORMAT_DEG_MIN_SEC_WITH_SPACES = 15;
        public static final int FORMAT_CARDINAL = 16;
+       public static final int FORMAT_DECIMAL_FORCE_POINT = 17;
        public static final int FORMAT_NONE = 19;
 
+       /** Number formatter for fixed decimals with forced decimal point */
+       private static final NumberFormat EIGHT_DP = NumberFormat.getNumberInstance(Locale.UK);
+       // Select the UK locale for this formatter so that decimal point is always used (not comma)
+       static {
+               if (EIGHT_DP instanceof DecimalFormat) ((DecimalFormat) EIGHT_DP).applyPattern("0.00000000");
+       }
+
        // Instance variables
        private boolean _valid = false;
        protected int _cardinal = NORTH;
@@ -110,6 +122,7 @@ public abstract class Coordinate
                                double numSecs = (numMins - _minutes) * 60.0;
                                _seconds = (int) numSecs;
                                _fracs = (int) ((numSecs - _seconds) * 10);
+                               _asDouble = _degrees + 1.0 * fields[1] / denoms[1];
                        }
                        // Differentiate between d-m.f and d-m-s using . or ,
                        else if (numFields == 3 && (secondDelim.equals(".") || secondDelim.equals(",")))
@@ -120,6 +133,7 @@ public abstract class Coordinate
                                double numSecs = fields[2] * 60.0 / denoms[2];
                                _seconds = (int) numSecs;
                                _fracs = (int) ((numSecs - _seconds) * 10);
+                               _asDouble = 1.0 * _degrees + (_minutes / 60.0) + (numSecs / 3600.0);
                        }
                        else if (numFields == 4 || numFields == 3)
                        {
@@ -130,8 +144,8 @@ public abstract class Coordinate
                                _fracs = (int) fields[3];
                                _fracDenom = (int) denoms[3];
                                if (_fracDenom < 1) {_fracDenom = 1;}
+                               _asDouble = 1.0 * _degrees + (_minutes / 60.0) + (_seconds / 3600.0) + (_fracs / 3600.0 / _fracDenom);
                        }
-                       _asDouble = 1.0 * _degrees + (_minutes / 60.0) + (_seconds / 3600.0) + (_fracs / 3600.0 / _fracDenom);
                        if (_cardinal == WEST || _cardinal == SOUTH || inString.charAt(0) == '-')
                                _asDouble = -_asDouble;
                        // validate fields
@@ -277,6 +291,12 @@ public abstract class Coordinate
                                                + (_degrees + _minutes / 60.0 + _seconds / 3600.0 + _fracs / 3600.0 / _fracDenom);
                                        break;
                                }
+                               case FORMAT_DECIMAL_FORCE_POINT:
+                               {
+                                       // Forcing a decimal point instead of system-dependent commas etc
+                                       answer = EIGHT_DP.format(_asDouble);
+                                       break;
+                               }
                                case FORMAT_DEG_MIN_SEC_WITH_SPACES:
                                {
                                        // Note: cardinal not needed as this format is only for exif, which has cardinal separately
index 4cf7c827952a8c10c8c46adb5602e4fcbbf3d956..2d60ce7e5021916a77390c1d2e875a7062014bc0 100644 (file)
@@ -1,5 +1,7 @@
 package tim.prune.data;
 
+import tim.prune.Config;
+
 /**
  * Class to represent a single data point in the series
  * including all its fields
@@ -18,6 +20,7 @@ public class DataPoint
        private Photo _photo = null;
        private String _waypointName = null;
        private boolean _startOfSegment = false;
+       private boolean _markedForDeletion = false;
 
 
        /**
@@ -26,31 +29,44 @@ public class DataPoint
         * @param inFieldList list of fields
         * @param inAltFormat altitude format
         */
-       public DataPoint(String[] inValueArray, FieldList inFieldList, int inAltFormat)
+       public DataPoint(String[] inValueArray, FieldList inFieldList, Altitude.Format inAltFormat)
        {
                // save data
                _fieldValues = inValueArray;
                // save list of fields
                _fieldList = inFieldList;
                // parse fields into objects
-               parseFields(inAltFormat);
+               parseFields(null, inAltFormat);
        }
 
 
        /**
         * Parse the string values into objects eg Coordinates
+        * @param inField field which has changed, or null for all
         * @param inAltFormat altitude format
         */
-       private void parseFields(int inAltFormat)
+       private void parseFields(Field inField, Altitude.Format inAltFormat)
        {
-               _latitude = new Latitude(getFieldValue(Field.LATITUDE));
-               _longitude = new Longitude(getFieldValue(Field.LONGITUDE));
-               _altitude = new Altitude(getFieldValue(Field.ALTITUDE), inAltFormat);
-               _timestamp = new Timestamp(getFieldValue(Field.TIMESTAMP));
-               _waypointName = getFieldValue(Field.WAYPT_NAME);
-               String segmentStr = getFieldValue(Field.NEW_SEGMENT);
-               if (segmentStr != null) {segmentStr = segmentStr.trim();}
-               _startOfSegment = (segmentStr != null && (segmentStr.equals("1") || segmentStr.toUpperCase().equals("Y")));
+               if (inField == null || inField == Field.LATITUDE) {
+                       _latitude = new Latitude(getFieldValue(Field.LATITUDE));
+               }
+               if (inField == null || inField == Field.LONGITUDE) {
+                       _longitude = new Longitude(getFieldValue(Field.LONGITUDE));
+               }
+               if (inField == null || inField == Field.ALTITUDE) {
+                       _altitude = new Altitude(getFieldValue(Field.ALTITUDE), inAltFormat);
+               }
+               if (inField == null || inField == Field.TIMESTAMP) {
+                       _timestamp = new Timestamp(getFieldValue(Field.TIMESTAMP));
+               }
+               if (inField == null || inField == Field.WAYPT_NAME) {
+                       _waypointName = getFieldValue(Field.WAYPT_NAME);
+               }
+               if (inField == null || inField == Field.NEW_SEGMENT) {
+                       String segmentStr = getFieldValue(Field.NEW_SEGMENT);
+                       if (segmentStr != null) {segmentStr = segmentStr.trim();}
+                       _startOfSegment = (segmentStr != null && (segmentStr.equals("1") || segmentStr.toUpperCase().equals("Y")));
+               }
        }
 
 
@@ -75,7 +91,7 @@ public class DataPoint
                }
                else {
                        _altitude = inAltitude;
-                       _fieldValues[2] = "" + inAltitude.getValue(Altitude.FORMAT_METRES); // units are ignored
+                       _fieldValues[2] = "" + inAltitude.getValue(Altitude.Format.METRES); // units are ignored
                }
                _timestamp = new Timestamp(null);
        }
@@ -133,14 +149,13 @@ public class DataPoint
                // Set field value in array
                _fieldValues[fieldIndex] = inValue;
                // Change Coordinate, Altitude, Name or Timestamp fields after edit
-               if (_altitude != null)
-               {
-                       parseFields(_altitude.getFormat());
+               if (_altitude != null && _altitude.getFormat() != Altitude.Format.NO_FORMAT) {
+                       // Altitude already present so reuse format
+                       parseFields(inField, _altitude.getFormat());
                }
-               else
-               {
-                       // use default altitude format of metres
-                       parseFields(Altitude.FORMAT_METRES);
+               else {
+                       // use default altitude format from config
+                       parseFields(inField, Config.getUseMetricUnits()?Altitude.Format.METRES:Altitude.Format.FEET);
                }
        }
 
@@ -150,6 +165,14 @@ public class DataPoint
                setFieldValue(Field.NEW_SEGMENT, inFlag?"1":null);
        }
 
+       /**
+        * Mark the point for deletion
+        * @param inFlag true to delete, false to keep
+        */
+       public void setMarkedForDeletion(boolean inFlag) {
+               _markedForDeletion = inFlag;
+       }
+
        /** @return latitude */
        public Coordinate getLatitude()
        {
@@ -192,6 +215,12 @@ public class DataPoint
                return _startOfSegment;
        }
 
+       /** @return true if point marked for deletion */
+       public boolean getDeleteFlag()
+       {
+               return _markedForDeletion;
+       }
+
        /**
         * @return true if point has a waypoint name
         */
@@ -353,32 +382,6 @@ public class DataPoint
        }
 
 
-       /**
-        * Restore the contents from another point
-        * @param inOther point containing contents to copy
-        * @return true if successful
-        */
-       public boolean restoreContents(DataPoint inOther)
-       {
-               if (inOther != null)
-               {
-                       // Copy string values across
-                       _fieldValues = inOther._fieldValues;
-                       if (_altitude != null)
-                       {
-                               parseFields(_altitude.getFormat());
-                       }
-                       else
-                       {
-                               // use default altitude format of metres
-                               parseFields(Altitude.FORMAT_METRES);
-                       }
-                       return true;
-               }
-               return false;
-       }
-
-
        /**
         * Get string for debug
         * @see java.lang.Object#toString()
index 311cd886a5af098d8764478d4e5aa1d313b08f44..9909df7edad664841826e842d6287c25e05ec500 100644 (file)
@@ -5,10 +5,18 @@ package tim.prune.data;
  */
 public abstract class Distance
 {
-       // distance formats
-       public static final int UNITS_KILOMETRES = 1;
-       public static final int UNITS_MILES      = 2;
-       public static final int UNITS_METRES     = 3;
+       /** distance units */
+       public enum Units
+       {
+               /** Kilometres */
+               KILOMETRES,
+               /** Miles */
+               MILES,
+               /** Metres */
+               METRES,
+               /** Feet */
+               FEET
+       }
 
        // Geographical constants
        private static final double EARTH_RADIUS_KM = 6372.795;
@@ -22,12 +30,12 @@ public abstract class Distance
         * @param inUnits desired units, eg miles or km
         * @return distance in specified format
         */
-       public static double convertRadiansToDistance(double inAngDist, int inUnits)
+       public static double convertRadiansToDistance(double inAngDist, Units inUnits)
        {
                // Multiply by appropriate factor
-               if (inUnits == UNITS_MILES)
+               if (inUnits == Units.MILES)
                        return inAngDist * EARTH_RADIUS_KM * CONVERT_KM_TO_MILES;
-               else if (inUnits == UNITS_METRES)
+               else if (inUnits == Units.METRES)
                        return inAngDist * EARTH_RADIUS_KM * 1000;
                // default kilometres
                return inAngDist * EARTH_RADIUS_KM;
@@ -39,12 +47,12 @@ public abstract class Distance
         * @param inUnits units, eg miles or km
         * @return angular distance in radians
         */
-       public static double convertDistanceToRadians(double inDist, int inUnits)
+       public static double convertDistanceToRadians(double inDist, Units inUnits)
        {
                // Divide by appropriate factor
-               if (inUnits == UNITS_MILES)
+               if (inUnits == Units.MILES)
                        return inDist / EARTH_RADIUS_KM / CONVERT_KM_TO_MILES;
-               else if (inUnits == UNITS_METRES)
+               else if (inUnits == Units.METRES)
                        return inDist / EARTH_RADIUS_KM / 1000;
                // default kilometres
                return inDist / EARTH_RADIUS_KM;
index e103759fb7eb20d83eb9f7ca6d94cd2ba675d672..b6b8a8fb9cb9c7f1b647c9ef20d1d5779bbad16c 100644 (file)
@@ -71,4 +71,12 @@ public class DoubleRange
        {
                return _max;
        }
+
+       /**
+        * @return range, as maximum - minimum
+        */
+       public double getRange()
+       {
+               return _max - _min;
+       }
 }
index 5f28fc578c3c39debbac07fc4944a1615ed5e72d..089d8cdc2d1a623b89f0d7b7e4615b6524fb128e 100644 (file)
@@ -21,9 +21,9 @@ public class Field
        public static final Field WAYPT_TYPE = new Field("fieldname.waypointtype", FieldType.NONE);
        public static final Field NEW_SEGMENT = new Field("fieldname.newsegment", FieldType.BOOL);
 
-       public static final Field[] ALL_AVAILABLE_FIELDS = {
-                       LATITUDE, LONGITUDE, ALTITUDE, TIMESTAMP, WAYPT_NAME, WAYPT_TYPE, NEW_SEGMENT,
-                       new Field("fieldname.custom", FieldType.NONE)
+       private static final Field[] ALL_AVAILABLE_FIELDS = {
+               LATITUDE, LONGITUDE, ALTITUDE, TIMESTAMP, WAYPT_NAME, WAYPT_TYPE, NEW_SEGMENT,
+               new Field("fieldname.custom", FieldType.NONE)
        };
 
        /**
@@ -95,4 +95,33 @@ public class Field
        {
                return (isBuiltIn() == inOther.isBuiltIn() && getName().equals(inOther.getName()));
        }
+
+       /**
+        * Get the field for the given field name
+        * @param inFieldName name of field to look for
+        * @return Field if found, or null otherwise
+        */
+       public static Field getField(String inFieldName)
+       {
+               for (int i=0; i<ALL_AVAILABLE_FIELDS.length; i++) {
+                       Field field = ALL_AVAILABLE_FIELDS[i];
+                       if (field.getName().equals(inFieldName)) {
+                               return field;
+                       }
+               }
+               // not found
+               return null;
+       }
+
+       /**
+        * @return array of field names
+        */
+       public static String[] getFieldNames()
+       {
+               String[] names = new String[ALL_AVAILABLE_FIELDS.length];
+               for (int i=0; i<ALL_AVAILABLE_FIELDS.length; i++) {
+                       names[i] = ALL_AVAILABLE_FIELDS[i].getName();
+               }
+               return names;
+       }
 }
index fca0ed720f1fd512aaed376530bd94c85e2ceb3a..a92748ae94b12f2767c9a121ec51b9ba491372fe 100644 (file)
@@ -23,4 +23,12 @@ public class FieldType
        {
                _id = inId;
        }
+
+       /**
+        * Method only needed to avoid compiler warnings
+        * @return id
+        */
+       protected char getId() {
+               return _id;
+       }
 }
index b11ba0e5b4993b9b53c39c40e1351dcf2aa1be82..a16f44badb2aec77f10061970e8851de47509cba 100644 (file)
@@ -33,15 +33,6 @@ public class IntegerRange
        }
 
 
-       /**
-        * @return true if positive data values were found
-        */
-       public boolean hasData()
-       {
-               return (_max >= 0);
-       }
-
-
        /**
         * @return minimum value, or -1 if none found
         */
index 2f230cc45dae35db740159724b7bd989002dbfae..805e22ea6254b8f88f78ca9b766d6d6c699590eb 100644 (file)
@@ -19,13 +19,23 @@ public class Photo
        /** Size of original image */
        private Dimension _size = null;
        /** Status of photo when loaded */
-       private byte _originalStatus = PhotoStatus.NOT_CONNECTED;
+       private Status _originalStatus = Status.NOT_CONNECTED;
        /** Current photo status */
-       private byte _currentStatus = PhotoStatus.NOT_CONNECTED;
+       private Status _currentStatus = Status.NOT_CONNECTED;
        // TODO: Need to store caption for image?
        // thumbnail for image (from exif)
        private byte[] _exifThumbnail = null;
 
+       /** Photo status */
+       public enum Status {
+               /** Photo is not connected to any point */
+               NOT_CONNECTED,
+               /** Photo has been connected to a point since it was loaded */
+               TAGGED,
+               /** Photo is connected to a point */
+               CONNECTED
+       };
+
 
        /**
         * Constructor
@@ -56,11 +66,11 @@ public class Photo
                // set status according to point
                if (inPoint == null)
                {
-                       setCurrentStatus(PhotoStatus.NOT_CONNECTED);
+                       setCurrentStatus(Status.NOT_CONNECTED);
                }
                else
                {
-                       setCurrentStatus(PhotoStatus.CONNECTED);
+                       setCurrentStatus(Status.CONNECTED);
                }
        }
 
@@ -143,7 +153,7 @@ public class Photo
        /**
         * @param inStatus status of photo when loaded
         */
-       public void setOriginalStatus(byte inStatus)
+       public void setOriginalStatus(Status inStatus)
        {
                _originalStatus = inStatus;
                _currentStatus = inStatus;
@@ -152,7 +162,7 @@ public class Photo
        /**
         * @return status of photo when it was loaded
         */
-       public byte getOriginalStatus()
+       public Status getOriginalStatus()
        {
                return _originalStatus;
        }
@@ -160,14 +170,14 @@ public class Photo
        /**
         * @return current status of photo
         */
-       public byte getCurrentStatus()
+       public Status getCurrentStatus()
        {
                return _currentStatus;
        }
        /**
         * @param inStatus current status of photo
         */
-       public void setCurrentStatus(byte inStatus)
+       public void setCurrentStatus(Status inStatus)
        {
                _currentStatus = inStatus;
        }
index b7c044da5ad2295b2bd98d677fc1c1a84d1aca2d..18ebe15d179d9f174d2d9ddc8dd1947098c9b10c 100644 (file)
@@ -7,7 +7,7 @@ import java.util.ArrayList;
  */
 public class PhotoList
 {
-       private ArrayList _photos = null;
+       private ArrayList<Photo> _photos = null;
 
        /**
         * Empty constructor
@@ -21,7 +21,7 @@ public class PhotoList
         * Constructor
         * @param inList ArrayList containing Photo objects
         */
-       private PhotoList(ArrayList inList)
+       private PhotoList(ArrayList<Photo> inList)
        {
                _photos = inList;
        }
@@ -48,7 +48,7 @@ public class PhotoList
                        // Make sure array is initialised
                        if (_photos == null)
                        {
-                               _photos = new ArrayList();
+                               _photos = new ArrayList<Photo>();
                        }
                        // Add the photo
                        _photos.add(inPhoto);
@@ -68,7 +68,7 @@ public class PhotoList
                        // Make sure array is initialised
                        if (_photos == null)
                        {
-                               _photos = new ArrayList();
+                               _photos = new ArrayList<Photo>();
                        }
                        // Add the photo
                        _photos.add(inIndex, inPhoto);
@@ -135,7 +135,7 @@ public class PhotoList
        public Photo getPhoto(int inIndex)
        {
                if (inIndex < 0 || inIndex >= getNumPhotos()) return null;
-               return (Photo) _photos.get(inIndex);
+               return _photos.get(inIndex);
        }
 
 
@@ -201,7 +201,7 @@ public class PhotoList
                if (numPhotos > 0)
                {
                        // Construct new list to copy into
-                       ArrayList listCopy = new ArrayList();
+                       ArrayList<Photo> listCopy = new ArrayList<Photo>();
                        // Loop over photos in list
                        for (int i=0; i<numPhotos; i++)
                        {
@@ -227,7 +227,11 @@ public class PhotoList
        public PhotoList cloneList()
        {
                if (_photos == null) return this;
-               return new PhotoList((ArrayList) _photos.clone());
+               ArrayList<Photo> listCopy = new ArrayList<Photo>();
+               for (int i=0; i<_photos.size(); i++) {
+                       listCopy.add(_photos.get(i));
+               }
+               return new PhotoList(listCopy);
        }
 
 
diff --git a/tim/prune/data/PhotoStatus.java b/tim/prune/data/PhotoStatus.java
deleted file mode 100644 (file)
index 831f36f..0000000
+++ /dev/null
@@ -1,11 +0,0 @@
-package tim.prune.data;
-
-/**
- * Interface to hold constants for photo status
- */
-public interface PhotoStatus
-{
-       public static final byte NOT_CONNECTED = 0;
-       public static final byte TAGGED        = 1;
-       public static final byte CONNECTED     = 2;
-}
index 95e0cfbd7ded462f51fb750c79df010e18a2ce20..c07c1a91e3aea422e5b469bef027afe4b2db3247 100644 (file)
@@ -16,7 +16,7 @@ public class Selection
        private int _currentPhotoIndex = -1;
        private IntegerRange _altitudeRange = null;
        private int _climb = -1, _descent = -1;
-       private int _altitudeFormat = Altitude.FORMAT_NONE;
+       private Altitude.Format _altitudeFormat = Altitude.Format.NO_FORMAT;
        private long _totalSeconds = 0L, _movingSeconds = 0L;
        private double _angDistance = -1.0, _angMovingDistance = -1.0;
 
@@ -109,7 +109,7 @@ public class Selection
         */
        private void recalculate()
        {
-               _altitudeFormat = Altitude.FORMAT_NONE;
+               _altitudeFormat = Altitude.Format.NO_FORMAT;
                if (_track.getNumPoints() > 0 && hasRangeSelected())
                {
                        _altitudeRange = new IntegerRange();
@@ -132,7 +132,7 @@ public class Selection
                                if (!currPoint.isWaypoint() && altitude.isValid())
                                {
                                        altValue = altitude.getValue(_altitudeFormat);
-                                       if (_altitudeFormat == Altitude.FORMAT_NONE)
+                                       if (_altitudeFormat == Altitude.Format.NO_FORMAT)
                                                _altitudeFormat = altitude.getFormat();
                                        _altitudeRange.addValue(altValue);
                                        if (foundAlt)
@@ -202,7 +202,7 @@ public class Selection
        /**
         * @return the altitude format, ie feet or metres
         */
-       public int getAltitudeFormat()
+       public Altitude.Format getAltitudeFormat()
        {
                return _altitudeFormat;
        }
@@ -258,7 +258,7 @@ public class Selection
         * @param inUnits distance units to use, from class Distance
         * @return distance of Selection in specified units
         */
-       public double getDistance(int inUnits)
+       public double getDistance(Distance.Units inUnits)
        {
                return Distance.convertRadiansToDistance(_angDistance, inUnits);
        }
@@ -267,7 +267,7 @@ public class Selection
         * @param inUnits distance units to use, from class Distance
         * @return moving distance of Selection in specified units
         */
-       public double getMovingDistance(int inUnits)
+       public double getMovingDistance(Distance.Units inUnits)
        {
                return Distance.convertRadiansToDistance(_angMovingDistance, inUnits);
        }
index 6b7f77b55d361d12de91897f8ee34983d305e9de..f1d056980de680d5343edf25776ebe56402700d1 100644 (file)
@@ -17,9 +17,10 @@ public class Timestamp
        private String _text = null;
        private String _timeText = null;
 
-       private static DateFormat DEFAULT_DATE_FORMAT = DateFormat.getDateTimeInstance();
-       private static DateFormat DEFAULT_TIME_FORMAT = DateFormat.getTimeInstance();
-       private static DateFormat ISO_8601_FORMAT = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'");
+       private static final DateFormat DEFAULT_DATE_FORMAT = DateFormat.getDateTimeInstance();
+       private static final DateFormat DEFAULT_TIME_FORMAT = DateFormat.getTimeInstance();
+       private static final DateFormat ISO_8601_FORMAT = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'");
+       private static final DateFormat ISO_8601_FORMAT_NOZ = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss");
        private static DateFormat[] ALL_DATE_FORMATS = null;
        private static Calendar CALENDAR = null;
        private static long SECS_SINCE_1970 = 0L;
@@ -53,7 +54,7 @@ public class Timestamp
                        new SimpleDateFormat("HH:mm:ss dd MMM yyyy"),
                        new SimpleDateFormat("dd MMM yyyy HH:mm:ss"),
                        new SimpleDateFormat("yyyy MMM dd HH:mm:ss"),
-                       ISO_8601_FORMAT
+                       ISO_8601_FORMAT, ISO_8601_FORMAT_NOZ
                };
        }
 
index eeb5b626bb484e59750b605849d653d77ca2a25b..df51e8f27e3c8963189b664adefc7534861188ea 100644 (file)
@@ -2,9 +2,10 @@ package tim.prune.data;
 
 import java.util.List;
 
+import tim.prune.Config;
 import tim.prune.UpdateMessageBroker;
-import tim.prune.edit.FieldEdit;
-import tim.prune.edit.FieldEditList;
+import tim.prune.function.edit.FieldEdit;
+import tim.prune.function.edit.FieldEditList;
 import tim.prune.gui.map.MapUtils;
 
 
@@ -19,8 +20,6 @@ public class Track
        // Scaled x, y values
        private double[] _xValues = null;
        private double[] _yValues = null;
-       private double[] _xValuesNew = null;
-       private double[] _yValuesNew = null;
        private boolean _scaled = false;
        private int _numPoints = 0;
        private boolean _mixedData = false;
@@ -53,7 +52,7 @@ public class Track
         * @param inPointArray 2d object array containing data
         * @param inAltFormat altitude format
         */
-       public void load(Field[] inFieldArray, Object[][] inPointArray, int inAltFormat)
+       public void load(Field[] inFieldArray, Object[][] inPointArray, Altitude.Format inAltFormat)
        {
                if (inFieldArray == null || inPointArray == null)
                {
@@ -88,6 +87,19 @@ public class Track
        }
 
 
+       /**
+        * Load the track by transferring the contents from a loaded Track object
+        * @param inOther Track object containing loaded data
+        */
+       public void load(Track inOther)
+       {
+               _numPoints = inOther._numPoints;
+               _masterFieldList = inOther._masterFieldList;
+               _dataPoints = inOther._dataPoints;
+               // needs to be scaled
+               _scaled = false;
+       }
+
        ////////////////// Modification methods //////////////////////
 
 
@@ -131,64 +143,22 @@ public class Track
 
 
        /**
-        * Compress the track to the given resolution
-        * @param inResolution resolution
+        * Delete the points marked for deletion
         * @return number of points deleted
         */
-       public int compress(int inResolution)
+       public int deleteMarkedPoints()
        {
-               // (maybe should be separate thread?)
-               // (maybe should be in separate class?)
-               // (maybe should be based on subtended angles instead of distances?)
-               // Suggestion: Find last track point, don't delete it (or maybe preserve first and last of each segment?)
-
-               if (inResolution <= 0) return 0;
                int numCopied = 0;
-               // Establish range of track and minimum range between points
-               scalePoints();
-               double wholeScale = _xRange.getMaximum() - _xRange.getMinimum();
-               double yscale = _yRange.getMaximum() - _yRange.getMinimum();
-               if (yscale > wholeScale) wholeScale = yscale;
-               double minDist = wholeScale / inResolution;
-
-               // Keep track of segment start flags of the deleted points
-               boolean setSegment = false;
                // Copy selected points
                DataPoint[] newPointArray = new DataPoint[_numPoints];
-               int[] pointIndices = new int[_numPoints];
                for (int i=0; i<_numPoints; i++)
                {
                        DataPoint point = _dataPoints[i];
-                       boolean keepPoint = true;
                        // Don't delete waypoints or photo points
-                       if (!point.isWaypoint() && point.getPhoto() == null)
-                       {
-                               // go through newPointArray to check for range
-                               for (int j=0; j<numCopied && keepPoint; j++)
-                               {
-                                       // calculate distance between point j and current point
-                                       double pointDist = Math.abs(_xValues[i] - _xValues[pointIndices[j]])
-                                        + Math.abs(_yValues[i] - _yValues[pointIndices[j]]);
-                                       if (pointDist < minDist)
-                                               keepPoint = false;
-                               }
-                       }
-                       if (keepPoint)
+                       if (point.isWaypoint() || point.getPhoto() != null || !point.getDeleteFlag())
                        {
                                newPointArray[numCopied] = point;
-                               pointIndices[numCopied] = i;
                                numCopied++;
-                               // set segment flag if it's the first track point
-                               if (setSegment && !point.isWaypoint())
-                               {
-                                       point.setSegmentStart(true);
-                                       setSegment = false;
-                               }
-                       }
-                       else
-                       {
-                               // point will be removed, so check segment flag
-                               if (point.getSegmentStart()) {setSegment = true;}
                        }
                }
 
@@ -205,28 +175,6 @@ public class Track
        }
 
 
-       /**
-        * Halve the track by deleting alternate points
-        * @return number of points deleted
-        */
-       public int halve()
-       {
-               if (_numPoints < 100) return 0;
-               int newSize = _numPoints / 2;
-               int numDeleted = _numPoints - newSize;
-               DataPoint[] newPointArray = new DataPoint[newSize];
-               // Delete alternate points
-               for (int i=0; i<newSize; i++)
-                       newPointArray[i] = _dataPoints[i*2];
-               // Copy array references
-               _dataPoints = newPointArray;
-               _numPoints = _dataPoints.length;
-               _scaled = false;
-               UpdateMessageBroker.informSubscribers();
-               return numDeleted;
-       }
-
-
        /**
         * Delete the specified point
         * @param inIndex point index
@@ -285,52 +233,6 @@ public class Track
        }
 
 
-       /**
-        * Delete all the duplicate points in the track
-        * @return number of points deleted
-        */
-       public int deleteDuplicates()
-       {
-               // loop through Track counting duplicates first
-               boolean[] dupes = new boolean[_numPoints];
-               int numDupes = 0;
-               int i, j;
-               for (i=1; i<_numPoints; i++)
-               {
-                       DataPoint p1 = _dataPoints[i];
-                       // Loop through all points before this one
-                       for (j=0; j<i && !dupes[i]; j++)
-                       {
-                               DataPoint p2 = _dataPoints[j];
-                               if (p1.isDuplicate(p2))
-                               {
-                                       dupes[i] = true;
-                                       numDupes++;
-                               }
-                       }
-               }
-               if (numDupes > 0)
-               {
-                       // Make new resized array and copy DataPoints over
-                       DataPoint[] newPointArray = new DataPoint[_numPoints - numDupes];
-                       j = 0;
-                       for (i=0; i<_numPoints; i++)
-                       {
-                               if (!dupes[i])
-                               {
-                                       newPointArray[j] = _dataPoints[i];
-                                       j++;
-                               }
-                       }
-                       // Copy array references
-                       _dataPoints = newPointArray;
-                       _numPoints = _dataPoints.length;
-                       _scaled = false;
-               }
-               return numDupes;
-       }
-
-
        /**
         * Reverse the specified range of points
         * @param inStart start index
@@ -613,6 +515,53 @@ public class Track
        }
 
 
+       /**
+        * Average selected points
+        * @param inStartIndex start index of selection
+        * @param inEndIndex end index of selection
+        * @return true if successful
+        */
+       public boolean average(int inStartIndex, int inEndIndex)
+       {
+               // check parameters
+               if (inStartIndex < 0 || inStartIndex >= _numPoints || inEndIndex <= inStartIndex)
+                       return false;
+
+               DataPoint startPoint = getPoint(inStartIndex);
+               double firstLatitude = startPoint.getLatitude().getDouble();
+               double firstLongitude = startPoint.getLongitude().getDouble();
+               double latitudeDiff = 0.0, longitudeDiff = 0.0;
+               double totalAltitude = 0;
+               int numAltitudes = 0;
+               Altitude.Format altFormat = Config.getUseMetricUnits()?Altitude.Format.METRES:Altitude.Format.FEET;
+               // loop between start and end points
+               for (int i=inStartIndex; i<= inEndIndex; i++)
+               {
+                       DataPoint currPoint = getPoint(i);
+                       latitudeDiff += (currPoint.getLatitude().getDouble() - firstLatitude);
+                       longitudeDiff += (currPoint.getLongitude().getDouble() - firstLongitude);
+                       if (currPoint.hasAltitude()) {
+                               totalAltitude += currPoint.getAltitude().getValue(altFormat);
+                               numAltitudes++;
+                       }
+               }
+               int numPoints = inEndIndex - inStartIndex + 1;
+               double meanLatitude = firstLatitude + (latitudeDiff / numPoints);
+               double meanLongitude = firstLongitude + (longitudeDiff / numPoints);
+               Altitude meanAltitude = null;
+               if (numAltitudes > 0) {meanAltitude = new Altitude((int) (totalAltitude / numAltitudes), altFormat);}
+
+               DataPoint insertedPoint = new DataPoint(new Latitude(meanLatitude, Coordinate.FORMAT_NONE),
+                       new Longitude(meanLongitude, Coordinate.FORMAT_NONE), meanAltitude);
+               // Make into singleton
+               insertedPoint.setSegmentStart(true);
+               DataPoint nextPoint = getNextTrackPoint(inEndIndex+1);
+               if (nextPoint != null) {nextPoint.setSegmentStart(true);}
+               // Insert points into track
+               return insertRange(new DataPoint[] {insertedPoint}, inEndIndex + 1);
+       }
+
+
        /**
         * Append the specified points to the end of the track
         * @param inPoints DataPoint objects to add
@@ -719,26 +668,6 @@ public class Track
                return _yValues[inPointNum];
        }
 
-       /**
-        * @param inPointNum point index, starting at 0
-        * @return scaled x value of specified point
-        */
-       public double getXNew(int inPointNum)
-       {
-               if (!_scaled) scalePoints();
-               return _xValuesNew[inPointNum];
-       }
-
-       /**
-        * @param inPointNum point index, starting at 0
-        * @return scaled y value of specified point
-        */
-       public double getYNew(int inPointNum)
-       {
-               if (!_scaled) scalePoints();
-               return _yValuesNew[inPointNum];
-       }
-
        /**
         * @return the master field list
         */
@@ -768,11 +697,17 @@ public class Track
         */
        public boolean hasData(Field inField, int inStart, int inEnd)
        {
+               // Loop over selected point range
                for (int i=inStart; i<=inEnd; i++)
                {
                        if (_dataPoints[i].getFieldValue(inField) != null)
                        {
-                               return true;
+                               // Check altitudes and timestamps
+                               if ((inField != Field.ALTITUDE || _dataPoints[i].getAltitude().isValid())
+                                       && (inField != Field.TIMESTAMP || _dataPoints[i].getTimestamp().isValid()))
+                               {
+                                       return true;
+                               }
                        }
                }
                return false;
@@ -788,12 +723,41 @@ public class Track
                return _mixedData;
        }
 
+       /**
+        * @return true if track contains any points marked for deletion
+        */
+       public boolean hasMarkedPoints()
+       {
+               if (_numPoints < 1) {
+                       return false;
+               }
+               // Loop over points looking for any marked for deletion
+               for (int i=0; i<=_numPoints-1; i++)
+               {
+                       if (_dataPoints[i] != null && _dataPoints[i].getDeleteFlag()) {
+                               return true;
+                       }
+               }
+               // None found
+               return false;
+       }
+
+       /**
+        * Clear all the deletion markers
+        */
+       public void clearDeletionMarkers()
+       {
+               for (int i=0; i<_numPoints; i++)
+               {
+                       _dataPoints[i].setMarkedForDeletion(false);
+               }
+       }
 
        /**
         * Collect all the waypoints into the given List
         * @param inList List to fill with waypoints
         */
-       public void getWaypoints(List inList)
+       public void getWaypoints(List<DataPoint> inList)
        {
                // clear list
                inList.clear();
@@ -865,16 +829,9 @@ public class Track
                }
                _mixedData = hasWaypoint && hasTrackpoint;
 
-               // Use medians to centre at 0
-               double longMedian = (_longRange.getMaximum() + _longRange.getMinimum()) / 2.0;
-               double latMedian = (_latRange.getMaximum() + _latRange.getMinimum()) / 2.0;
-               double longFactor = Math.cos(latMedian / 180.0 * Math.PI); // Function of median latitude
-
                // Loop over points and calculate scales
                _xValues = new double[getNumPoints()];
                _yValues = new double[getNumPoints()];
-               _xValuesNew = new double[getNumPoints()];
-               _yValuesNew = new double[getNumPoints()];
                _xRange = new DoubleRange();
                _yRange = new DoubleRange();
                for (p=0; p < getNumPoints(); p++)
@@ -882,12 +839,10 @@ public class Track
                        DataPoint point = getPoint(p);
                        if (point != null)
                        {
-                               _xValues[p] = (point.getLongitude().getDouble() - longMedian) * longFactor;
+                               _xValues[p] = MapUtils.getXFromLongitude(point.getLongitude().getDouble());
                                _xRange.addValue(_xValues[p]);
-                               _xValuesNew[p] = MapUtils.getXFromLongitude(point.getLongitude().getDouble());
-                               _yValues[p] = (point.getLatitude().getDouble() - latMedian);
+                               _yValues[p] = MapUtils.getYFromLatitude(point.getLatitude().getDouble());
                                _yRange.addValue(_yValues[p]);
-                               _yValuesNew[p] = MapUtils.getYFromLatitude(point.getLatitude().getDouble());
                        }
                }
                _scaled = true;
@@ -928,41 +883,6 @@ public class Track
                return nearestPoint;
        }
 
-
-       /**
-        * Find the nearest point to the specified x and y coordinates
-        * or -1 if no point is within the specified max distance
-        * @param inX x coordinate
-        * @param inY y coordinate
-        * @param inMaxDist maximum distance from selected coordinates
-        * @param inJustTrackPoints true if waypoints should be ignored
-        * @return index of nearest point or -1 if not found
-        */
-       public int getNearestPointIndexNew(double inX, double inY, double inMaxDist, boolean inJustTrackPoints)
-       {
-               int nearestPoint = 0;
-               double nearestDist = -1.0;
-               double currDist;
-               for (int i=0; i < getNumPoints(); i++)
-               {
-                       if (!inJustTrackPoints || !_dataPoints[i].isWaypoint())
-                       {
-                               currDist = Math.abs(_xValuesNew[i] - inX) + Math.abs(_yValuesNew[i] - inY);
-                               if (currDist < nearestDist || nearestDist < 0.0)
-                               {
-                                       nearestPoint = i;
-                                       nearestDist = currDist;
-                               }
-                       }
-               }
-               // Check whether it's within required distance
-               if (nearestDist > inMaxDist && inMaxDist > 0.0)
-               {
-                       return -1;
-               }
-               return nearestPoint;
-       }
-
        /**
         * Get the next track point starting from the given index
         * @param inStartIndex index to start looking from
@@ -1187,7 +1107,7 @@ public class Track
                        // set photo status if coordinates have changed
                        if (inPoint.getPhoto() != null && coordsChanged)
                        {
-                               inPoint.getPhoto().setCurrentStatus(PhotoStatus.CONNECTED);
+                               inPoint.getPhoto().setCurrentStatus(Photo.Status.CONNECTED);
                        }
                        // point possibly needs to be scaled again
                        _scaled = false;
index 4f3ce27e8f85b79c6b3582d5af20f27593f7fabb..d58cc167d6353239983e846a4e41969d250e7c89 100644 (file)
@@ -82,31 +82,17 @@ public class TrackInfo
        }
 
 
-       /**
-        * Load the specified data into the Track
-        * @param inFieldArray array of Field objects describing fields
-        * @param inPointArray 2d object array containing data
-        * @param inAltFormat altitude format
-        */
-       public void loadTrack(Field[] inFieldArray, Object[][] inPointArray, int inAltFormat)
-       {
-               _track.cropTo(0);
-               _track.load(inFieldArray, inPointArray, inAltFormat);
-               _selection.clearAll();
-       }
-
-
        /**
         * Add a Set of Photos
         * @param inSet Set containing Photo objects
         * @return array containing number of photos and number of points added
         */
-       public int[] addPhotos(Set inSet)
+       public int[] addPhotos(Set<Photo> inSet)
        {
                // Firstly count number of points and photos to add
                int numPhotosToAdd = 0;
                int numPointsToAdd = 0;
-               Iterator iterator = null;
+               Iterator<Photo> iterator = null;
                if (inSet != null && !inSet.isEmpty())
                {
                        iterator = inSet.iterator();
@@ -114,7 +100,7 @@ public class TrackInfo
                        {
                                try
                                {
-                                       Photo photo = (Photo) iterator.next();
+                                       Photo photo = iterator.next();
                                        if (photo != null && !_photoList.contains(photo))
                                        {
                                                numPhotosToAdd++;
@@ -139,7 +125,7 @@ public class TrackInfo
                        {
                                try
                                {
-                                       Photo photo = (Photo) iterator.next();
+                                       Photo photo = iterator.next();
                                        if (photo != null && !_photoList.contains(photo))
                                        {
                                                // Add photo
@@ -240,28 +226,12 @@ public class TrackInfo
 
 
        /**
-        * Compress the track to the given resolution
-        * @param inResolution resolution
-        * @return number of points deleted
-        */
-       public int compress(int inResolution)
-       {
-               int numDeleted = _track.compress(inResolution);
-               if (numDeleted > 0) {
-                       _selection.clearAll();
-                       UpdateMessageBroker.informSubscribers();
-               }
-               return numDeleted;
-       }
-
-
-       /**
-        * Delete all the duplicate points in the track
+        * Delete all the points which have been marked for deletion
         * @return number of points deleted
         */
-       public int deleteDuplicates()
+       public int deleteMarkedPoints()
        {
-               int numDeleted = _track.deleteDuplicates();
+               int numDeleted = _track.deleteMarkedPoints();
                if (numDeleted > 0) {
                        _selection.clearAll();
                        UpdateMessageBroker.informSubscribers();
@@ -295,6 +265,20 @@ public class TrackInfo
        }
 
 
+       /**
+        * Average selected points to create a new one
+        * @return true if successful
+        */
+       public boolean average()
+       {
+               boolean success = _track.average(_selection.getStart(), _selection.getEnd());
+               if (success) {
+                       _selection.selectPoint(_selection.getEnd()+1);
+               }
+               return success;
+       }
+
+
        /**
         * Select the given DataPoint
         * @param inPoint DataPoint object to select
index 1637a9dbc633639d4126c2e892f58ce9f7e03498..9e0fd5980fd0f33fa64a61a46b0db6fc345c53b4 100644 (file)
@@ -25,31 +25,27 @@ public class ExifReader
        /** Thumbnail length */\r
        private int _thumbnailLength = -1;\r
 \r
-       /**\r
-        * The number of bytes used per format descriptor.\r
-        */\r
+       /** The number of bytes used per format descriptor */\r
        private static final int[] BYTES_PER_FORMAT = {0, 1, 1, 2, 4, 8, 1, 1, 2, 4, 8, 4, 8};\r
 \r
-       /**\r
-        * The number of formats known.\r
-        */\r
+       /** The number of formats known */\r
        private static final int MAX_FORMAT_CODE = 12;\r
 \r
        // Format types\r
        // Note: Cannot use the DataFormat enumeration in the case statement that uses these tags.\r
        //         Is there a better way?\r
-       private static final int FMT_BYTE = 1;\r
+       //private static final int FMT_BYTE = 1;\r
        private static final int FMT_STRING = 2;\r
-       private static final int FMT_USHORT = 3;\r
-       private static final int FMT_ULONG = 4;\r
+       //private static final int FMT_USHORT = 3;\r
+       //private static final int FMT_ULONG = 4;\r
        private static final int FMT_URATIONAL = 5;\r
-       private static final int FMT_SBYTE = 6;\r
-       private static final int FMT_UNDEFINED = 7;\r
-       private static final int FMT_SSHORT = 8;\r
-       private static final int FMT_SLONG = 9;\r
+       //private static final int FMT_SBYTE = 6;\r
+       //private static final int FMT_UNDEFINED = 7;\r
+       //private static final int FMT_SSHORT = 8;\r
+       //private static final int FMT_SLONG = 9;\r
        private static final int FMT_SRATIONAL = 10;\r
-       private static final int FMT_SINGLE = 11;\r
-       private static final int FMT_DOUBLE = 12;\r
+       //private static final int FMT_SINGLE = 11;\r
+       //private static final int FMT_DOUBLE = 12;\r
 \r
        public static final int TAG_EXIF_OFFSET = 0x8769;\r
        public static final int TAG_INTEROP_OFFSET = 0xA005;\r
@@ -85,7 +81,7 @@ public class ExifReader
 \r
 \r
        /**\r
-        * Creates an ExifReader for a Jpeg file.\r
+        * Creates an ExifReader for a Jpeg file\r
         * @param inFile File object to attempt to read from\r
         * @throws JpegException on failure\r
         */\r
@@ -144,7 +140,7 @@ public class ExifReader
                        firstDirectoryOffset = 14;\r
                }\r
 \r
-               HashMap processedDirectoryOffsets = new HashMap();\r
+               HashMap<Integer, String> processedDirectoryOffsets = new HashMap<Integer, String>();\r
 \r
                // 0th IFD (we merge with Exif IFD)\r
                processDirectory(metadata, false, processedDirectoryOffsets, firstDirectoryOffset, TIFF_HEADER_START_OFFSET);\r
@@ -179,15 +175,15 @@ public class ExifReader
         *   2 bytes: format code\r
         *   4 bytes: component count\r
         */\r
-       private void processDirectory(JpegData inMetadata, boolean inIsGPS, HashMap inDirectoryOffsets,\r
+       private void processDirectory(JpegData inMetadata, boolean inIsGPS, HashMap<Integer, String> inDirectoryOffsets,\r
                int inDirOffset, int inTiffHeaderOffset)\r
        {\r
                // check for directories we've already visited to avoid stack overflows when recursive/cyclic directory structures exist\r
-               if (inDirectoryOffsets.containsKey(new Integer(inDirOffset)))\r
+               if (inDirectoryOffsets.containsKey(Integer.valueOf(inDirOffset)))\r
                        return;\r
 \r
                // remember that we've visited this directory so that we don't visit it again later\r
-               inDirectoryOffsets.put(new Integer(inDirOffset), "processed");\r
+               inDirectoryOffsets.put(Integer.valueOf(inDirOffset), "processed");\r
 \r
                if (inDirOffset >= _data.length || inDirOffset < 0)\r
                {\r
index 3d16733392d8c394d4e33f3725cd108ef74bea38..f8be61a88f21150032fb74413205ec2f296de74a 100644 (file)
@@ -20,7 +20,7 @@ public class JpegData
        private Rational[] _gpsDatestamp = null;
        private String _originalTimestamp = null;
        private byte[] _thumbnail = null;
-       private ArrayList _errors = null;
+       private ArrayList<String> _errors = null;
 
 
        /**
@@ -190,7 +190,7 @@ public class JpegData
         */
        public void addError(String inError)
        {
-               if (_errors == null) _errors = new ArrayList();
+               if (_errors == null) _errors = new ArrayList<String>();
                _errors.add(inError);
        }
 
@@ -214,7 +214,7 @@ public class JpegData
        /**
         * @return all errors as a list
         */
-       public List getErrors()
+       public List<String> getErrors()
        {
                return _errors;
        }
index 23197f8c1fb105f8e6dc0068f60e3f67110dcfc1..8541a08b9b146eae3ce938b4b9d858b655fed890 100644 (file)
@@ -12,17 +12,9 @@ import java.util.List;
 public class JpegSegmentData\r
 {\r
        /** A map of byte[], keyed by the segment marker */\r
-       private final HashMap _segmentDataMap;\r
+       private final HashMap<Byte, List<byte[]>> _segmentDataMap = new HashMap<Byte, List<byte[]>>(10);\r
 \r
 \r
-       /**\r
-        * Constructor for an empty collection\r
-        */\r
-       public JpegSegmentData()\r
-       {\r
-               _segmentDataMap = new HashMap(10);\r
-       }\r
-\r
        /**\r
         * Add a segment to the collection\r
         * @param inSegmentMarker marker byte\r
@@ -30,7 +22,7 @@ public class JpegSegmentData
         */\r
        public void addSegment(byte inSegmentMarker, byte[] inSegmentBytes)\r
        {\r
-               List segmentList = getOrCreateSegmentList(inSegmentMarker);\r
+               List<byte[]> segmentList = getOrCreateSegmentList(inSegmentMarker);\r
                segmentList.add(inSegmentBytes);\r
        }\r
 \r
@@ -54,12 +46,12 @@ public class JpegSegmentData
         */\r
        public byte[] getSegment(byte inSegmentMarker, int inOccurrence)\r
        {\r
-               final List segmentList = getSegmentList(inSegmentMarker);\r
+               final List<byte[]> segmentList = getSegmentList(inSegmentMarker);\r
 \r
                if (segmentList==null || segmentList.size()<=inOccurrence)\r
                        return null;\r
                else\r
-                       return (byte[]) segmentList.get(inOccurrence);\r
+                       return segmentList.get(inOccurrence);\r
        }\r
 \r
 \r
@@ -70,7 +62,7 @@ public class JpegSegmentData
         */\r
        public int getSegmentCount(byte inSegmentMarker)\r
        {\r
-               final List segmentList = getSegmentList(inSegmentMarker);\r
+               final List<byte[]> segmentList = getSegmentList(inSegmentMarker);\r
                if (segmentList == null)\r
                        return 0;\r
                else\r
@@ -83,9 +75,9 @@ public class JpegSegmentData
         * @param inSegmentMarker marker byte\r
         * @return list of segments\r
         */\r
-       private List getSegmentList(byte inSegmentMarker)\r
+       private List<byte[]> getSegmentList(byte inSegmentMarker)\r
        {\r
-               return (List)_segmentDataMap.get(new Byte(inSegmentMarker));\r
+               return _segmentDataMap.get(Byte.valueOf(inSegmentMarker));\r
        }\r
 \r
 \r
@@ -94,19 +86,19 @@ public class JpegSegmentData
         * @param inSegmentMarker marker byte\r
         * @return list of segments\r
         */\r
-       private List getOrCreateSegmentList(byte inSegmentMarker)\r
+       private List<byte[]> getOrCreateSegmentList(byte inSegmentMarker)\r
        {\r
-               List segmentList = null;\r
-               Byte key = new Byte(inSegmentMarker);\r
+               List<byte[]> segmentList = null;\r
+               Byte key = Byte.valueOf(inSegmentMarker);\r
                if (_segmentDataMap.containsKey(key))\r
                {\r
                        // list already exists\r
-                       segmentList = (List)_segmentDataMap.get(key);\r
+                       segmentList = _segmentDataMap.get(key);\r
                }\r
                else\r
                {\r
                        // create new list and add it\r
-                       segmentList = new ArrayList();\r
+                       segmentList = new ArrayList<byte[]>();\r
                        _segmentDataMap.put(key, segmentList);\r
                }\r
                return segmentList;\r
similarity index 74%
rename from tim/prune/gui/AboutScreen.java
rename to tim/prune/function/AboutScreen.java
index 0d1ef5b7f3bd5cc4fb5c75f8210baf59c2922284..0f20ba00778064254a86ddbf2a1d0681f5d1aeb2 100644 (file)
@@ -1,4 +1,4 @@
-package tim.prune.gui;
+package tim.prune.function;
 
 import java.awt.BorderLayout;
 import java.awt.Component;
@@ -18,14 +18,15 @@ import javax.swing.BoxLayout;
 import javax.swing.JButton;
 import javax.swing.JDialog;
 import javax.swing.JEditorPane;
-import javax.swing.JFrame;
 import javax.swing.JLabel;
 import javax.swing.JPanel;
 import javax.swing.JScrollPane;
 import javax.swing.JTabbedPane;
 import javax.swing.JTextArea;
 
+import tim.prune.App;
 import tim.prune.ExternalTools;
+import tim.prune.GenericFunction;
 import tim.prune.GpsPruner;
 import tim.prune.I18nManager;
 import tim.prune.threedee.WindowFactory;
@@ -33,20 +34,31 @@ import tim.prune.threedee.WindowFactory;
 /**
  * Class to represent the "About" popup window
  */
-public class AboutScreen extends JDialog
+public class AboutScreen extends GenericFunction
 {
-       JButton _okButton = null;
+       private JDialog _dialog = null;
+       private JTabbedPane _tabs = null;
+       private JButton _okButton = null;
+       /** Labels for whether tools installed or not */
+       private JLabel[] _installedLabels = null;
+
 
        /**
         * Constructor
-        * @param inParent parent frame
+        * @param inApp app object
         */
-       public AboutScreen(JFrame inParent)
+       public AboutScreen(App inApp)
        {
-               super(inParent, I18nManager.getText("dialog.about.title"));
-               getContentPane().add(makeContents());
+               super(inApp);
        }
 
+       /**
+        * Return the name key for this function
+        */
+       public String getNameKey()
+       {
+               return "function.about";
+       }
 
        /**
         * @return the contents of the window as a Component
@@ -56,8 +68,8 @@ public class AboutScreen extends JDialog
                JPanel mainPanel = new JPanel();
                mainPanel.setLayout(new BorderLayout());
 
-               JTabbedPane tabPane = new JTabbedPane();
-               mainPanel.add(tabPane, BorderLayout.CENTER);
+               _tabs = new JTabbedPane();
+               mainPanel.add(_tabs, BorderLayout.CENTER);
 
                JPanel aboutPanel = new JPanel();
                aboutPanel.setLayout(new BoxLayout(aboutPanel, BoxLayout.Y_AXIS));
@@ -78,7 +90,8 @@ public class AboutScreen extends JDialog
                descBuffer.append("<p>").append(I18nManager.getText("dialog.about.summarytext2")).append("</p>");
                descBuffer.append("<p>").append(I18nManager.getText("dialog.about.summarytext3")).append("</p>");
                descBuffer.append("<p>").append(I18nManager.getText("dialog.about.languages")).append(" : ")
-                       .append("deutsch, english, español, français, italiano, polski, schwiizerdüütsch").append("</p>");
+                       .append("deutsch, english, español, français, italiano, polski,<br>" +
+                               "schwiizerdüütsch, português, bahasa indonesia, română").append("</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));
@@ -88,7 +101,7 @@ public class AboutScreen extends JDialog
 
                aboutPanel.add(descPane);
                aboutPanel.add(new JLabel(" "));
-               tabPane.add(I18nManager.getText("dialog.about.title"), aboutPanel);
+               _tabs.add(I18nManager.getText("function.about"), aboutPanel);
 
                // Second pane for system info
                JPanel sysInfoPanel = new JPanel();
@@ -108,31 +121,33 @@ public class AboutScreen extends JDialog
                addToGridBagPanel(sysInfoPanel, gridBag, constraints,
                        new JLabel(System.getProperty("java.runtime.version")),
                        1, 1);
+               // Create install labels to be populated later
+               final int NUM_INSTALL_CHECKS = 5;
+               _installedLabels = new JLabel[NUM_INSTALL_CHECKS];
+               for (int i=0; i<NUM_INSTALL_CHECKS; i++) {
+                       _installedLabels[i] = new JLabel("...");
+               }
                addToGridBagPanel(sysInfoPanel, gridBag, constraints,
                        new JLabel(I18nManager.getText("dialog.about.systeminfo.java3d") + " : "),
                        0, 2);
-               addToGridBagPanel(sysInfoPanel, gridBag, constraints,
-                       new JLabel(I18nManager.getText(WindowFactory.isJava3dEnabled()?"dialog.about.yes":"dialog.about.no")),
-                       1, 2);
+               addToGridBagPanel(sysInfoPanel, gridBag, constraints, _installedLabels[0], 1, 2);
                addToGridBagPanel(sysInfoPanel, gridBag, constraints,
                        new JLabel(I18nManager.getText("dialog.about.systeminfo.povray") + " : "),
                        0, 3);
-               addToGridBagPanel(sysInfoPanel, gridBag, constraints,
-                       new JLabel(I18nManager.getText(ExternalTools.isPovrayInstalled()?"dialog.about.yes":"dialog.about.no")),
-                       1, 3);
+               addToGridBagPanel(sysInfoPanel, gridBag, constraints, _installedLabels[1], 1, 3);
                addToGridBagPanel(sysInfoPanel, gridBag, constraints,
                        new JLabel(I18nManager.getText("dialog.about.systeminfo.exiftool") + " : "),
                        0, 4);
-               addToGridBagPanel(sysInfoPanel, gridBag, constraints,
-                       new JLabel(I18nManager.getText(ExternalTools.isExiftoolInstalled()?"dialog.about.yes":"dialog.about.no")),
-                       1, 4);
+               addToGridBagPanel(sysInfoPanel, gridBag, constraints, _installedLabels[2], 1, 4);
                addToGridBagPanel(sysInfoPanel, gridBag, constraints,
                        new JLabel(I18nManager.getText("dialog.about.systeminfo.gpsbabel") + " : "),
                        0, 5);
+               addToGridBagPanel(sysInfoPanel, gridBag, constraints, _installedLabels[3], 1, 5);
                addToGridBagPanel(sysInfoPanel, gridBag, constraints,
-                       new JLabel(I18nManager.getText(ExternalTools.isGpsbabelInstalled()?"dialog.about.yes":"dialog.about.no")),
-                       1, 5);
-               tabPane.add(I18nManager.getText("dialog.about.systeminfo"), sysInfoPanel);
+                       new JLabel(I18nManager.getText("dialog.about.systeminfo.gnuplot") + " : "),
+                       0, 6);
+               addToGridBagPanel(sysInfoPanel, gridBag, constraints, _installedLabels[4], 1, 6);
+               _tabs.add(I18nManager.getText("dialog.about.systeminfo"), sysInfoPanel);
 
                // Third pane for credits
                JPanel creditsPanel = new JPanel();
@@ -163,33 +178,36 @@ public class AboutScreen extends JDialog
                        new JLabel(I18nManager.getText("dialog.about.credits.translators") + " : "),
                        0, 3);
                addToGridBagPanel(creditsPanel, gridBag, constraints,
-                       new JLabel("Ramon, Miguel, Inés, Piotr, Petrovsk, Josatoc"),
+                       new JLabel("Ramon, Miguel, Inés, Piotr, Petrovsk, Josatoc, Weehal,"),
                        1, 3);
+               addToGridBagPanel(creditsPanel, gridBag, constraints,
+                       new JLabel(" theYinYeti, Rothermographer"),
+                       1, 4);
                addToGridBagPanel(creditsPanel, gridBag, constraints,
                        new JLabel(I18nManager.getText("dialog.about.credits.translations") + " : "),
-                       0, 4);
+                       0, 5);
                addToGridBagPanel(creditsPanel, gridBag, constraints,
                        new JLabel("Open Office, Gpsdrive, Babelfish, Leo, Launchpad"),
-                       1, 4);
+                       1, 5);
                addToGridBagPanel(creditsPanel, gridBag, constraints,
                        new JLabel(I18nManager.getText("dialog.about.credits.devtools") + " : "),
-                       0, 5);
+                       0, 6);
                addToGridBagPanel(creditsPanel, gridBag, constraints,
                        new JLabel("Mandriva Linux, Sun Java, Eclipse, Svn, Gimp"),
-                       1, 5);
+                       1, 6);
                addToGridBagPanel(creditsPanel, gridBag, constraints,
                        new JLabel(I18nManager.getText("dialog.about.credits.othertools") + " : "),
-                       0, 6);
+                       0, 7);
                addToGridBagPanel(creditsPanel, gridBag, constraints,
-                       new JLabel("Garble, Kate, Povray, Exiftool, Inkscape, Google Earth"),
-                       1, 6);
+                       new JLabel("Kate, Povray, Exiftool, Inkscape, Google Earth, Gpsbabel, Gnuplot"),
+                       1, 7);
                addToGridBagPanel(creditsPanel, gridBag, constraints,
                        new JLabel(I18nManager.getText("dialog.about.credits.thanks") + " : "),
-                       0, 7);
+                       0, 8);
                addToGridBagPanel(creditsPanel, gridBag, constraints,
                        new JLabel("Friends and loved ones, for encouragement and support"),
-                       1, 7);
-               tabPane.add(I18nManager.getText("dialog.about.credits"), creditsPanel);
+                       1, 8);
+               _tabs.add(I18nManager.getText("dialog.about.credits"), creditsPanel);
 
                // Read me
                JPanel readmePanel = new JPanel();
@@ -201,7 +219,7 @@ public class AboutScreen extends JDialog
                scrollPane.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
                scrollPane.setPreferredSize(new Dimension(600, 130));
                readmePanel.add(scrollPane, BorderLayout.CENTER);
-               tabPane.add(I18nManager.getText("dialog.about.readme"), readmePanel);
+               _tabs.add(I18nManager.getText("dialog.about.readme"), readmePanel);
 
                // OK button at the bottom
                JPanel okPanel = new JPanel();
@@ -211,13 +229,13 @@ public class AboutScreen extends JDialog
                {
                        public void actionPerformed(ActionEvent e)
                        {
-                               dispose();
+                               _dialog.dispose();
                        }
                });
                _okButton.addKeyListener(new KeyListener() {
                        public void keyPressed(KeyEvent e)
                        {
-                               if (e.getKeyCode() == KeyEvent.VK_ESCAPE) {dispose();}
+                               if (e.getKeyCode() == KeyEvent.VK_ESCAPE) {_dialog.dispose();}
                        }
                        public void keyTyped(KeyEvent e) {}
                        public void keyReleased(KeyEvent e) {}
@@ -259,7 +277,7 @@ public class AboutScreen extends JDialog
                try
                {
                        // For some reason using ../readme.txt doesn't work, so need absolute path
-                       InputStream in = getClass().getResourceAsStream("/tim/prune/readme.txt");
+                       InputStream in = AboutScreen.class.getResourceAsStream("/tim/prune/readme.txt");
                        if (in != null) {
                                byte[] buffer = new byte[in.available()];
                                in.read(buffer);
@@ -275,11 +293,31 @@ public class AboutScreen extends JDialog
        /**
         * Show window
         */
-       public void show()
+       public void begin()
        {
-               pack();
-               // setSize(300,200);
-               super.show();
+               if (_dialog == null)
+               {
+                       _dialog = new JDialog(_parentFrame, I18nManager.getText(getNameKey()));
+                       _dialog.getContentPane().add(makeContents());
+                       _dialog.pack();
+               }
+               _tabs.setSelectedIndex(0);
+               checkInstalls();
+               _dialog.setVisible(true);
                _okButton.requestFocus();
        }
+
+       /**
+        * Check the installed components and set the label texts accordingly
+        */
+       private void checkInstalls()
+       {
+               String yesText = I18nManager.getText("dialog.about.yes");
+               String noText = I18nManager.getText("dialog.about.no");
+               _installedLabels[0].setText(WindowFactory.isJava3dEnabled()?yesText:noText);
+               _installedLabels[1].setText(ExternalTools.isPovrayInstalled()?yesText:noText);
+               _installedLabels[2].setText(ExternalTools.isExiftoolInstalled()?yesText:noText);
+               _installedLabels[3].setText(ExternalTools.isGpsbabelInstalled()?yesText:noText);
+               _installedLabels[4].setText(ExternalTools.isGnuplotInstalled()?yesText:noText);
+       }
 }
similarity index 65%
rename from tim/prune/gui/TimeOffsetDialog.java
rename to tim/prune/function/AddTimeOffset.java
index 11524fe633412c14346ad7f2a0ef630d03d35343..8b5d4a82dd548c1472fd7220c3b5d6b2353a2bc2 100644 (file)
@@ -1,4 +1,4 @@
-package tim.prune.gui;
+package tim.prune.function;
 
 import java.awt.BorderLayout;
 import java.awt.Component;
@@ -6,61 +6,74 @@ import java.awt.FlowLayout;
 import java.awt.GridLayout;
 import java.awt.event.ActionEvent;
 import java.awt.event.ActionListener;
+import java.awt.event.KeyAdapter;
+import java.awt.event.KeyEvent;
+import java.awt.event.MouseAdapter;
 
 import javax.swing.BorderFactory;
 import javax.swing.BoxLayout;
 import javax.swing.ButtonGroup;
 import javax.swing.JButton;
 import javax.swing.JDialog;
-import javax.swing.JFrame;
 import javax.swing.JLabel;
 import javax.swing.JPanel;
 import javax.swing.JRadioButton;
 import javax.swing.SwingConstants;
 
 import tim.prune.App;
+import tim.prune.GenericFunction;
 import tim.prune.I18nManager;
+import tim.prune.data.Field;
+import tim.prune.gui.WholeNumberField;
 
 /**
- * Class to show a dialog for adding a time offset to a track range
+ * Class to provide the function to add a time offset to a track range
  */
-public class TimeOffsetDialog
+public class AddTimeOffset extends GenericFunction
 {
-       private App _app = null;
-       private JFrame _parentFrame = null;
        private JDialog _dialog = null;
        private JRadioButton _addRadio = null, _subtractRadio = null;
        private WholeNumberField _dayField = null, _hourField = null;
        private WholeNumberField _minuteField = null;
+       private JButton _okButton = null;
 
 
        /**
         * Constructor
         * @param inApp application object for callback
-        * @param inParentFrame parent frame
         */
-       public TimeOffsetDialog(App inApp, JFrame inParentFrame)
+       public AddTimeOffset(App inApp)
        {
-               _app = inApp;
-               _parentFrame = inParentFrame;
+               super(inApp);
        }
 
+       /** Get the name key */
+       public String getNameKey() {
+               return "function.addtimeoffset";
+       }
 
        /**
-        * Show the dialog to select options and export file
+        * Begin the function
         */
-       public void showDialog()
+       public void begin()
        {
+               int selStart = _app.getTrackInfo().getSelection().getStart();
+               int selEnd = _app.getTrackInfo().getSelection().getEnd();
+               if (!_app.getTrackInfo().getTrack().hasData(Field.TIMESTAMP, selStart, selEnd))
+               {
+                       _app.showErrorMessage(getNameKey(), "dialog.addtimeoffset.notimestamps");
+                       return;
+               }
                // Make dialog window
                if (_dialog == null)
                {
-                       _dialog = new JDialog(_parentFrame, I18nManager.getText("dialog.addtimeoffset.title"), true);
+                       _dialog = new JDialog(_parentFrame, I18nManager.getText(getNameKey()), true);
                        _dialog.setLocationRelativeTo(_parentFrame);
                        _dialog.setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE);
                        _dialog.getContentPane().add(makeDialogComponents());
                        _dialog.pack();
                }
-               _dialog.show();
+               _dialog.setVisible(true);
        }
 
 
@@ -87,8 +100,6 @@ public class TimeOffsetDialog
                radioGroup.add(_subtractRadio);
                mainPanel.add(radioPanel);
 
-               // Make a listener to validate the text boxes during typing (to en/disable OK button)
-
                // Make a central panel with the text boxes
                JPanel descPanel = new JPanel();
                descPanel.setLayout(new GridLayout(0, 2));
@@ -104,18 +115,38 @@ public class TimeOffsetDialog
                mainPanel.add(descPanel);
                dialogPanel.add(mainPanel, BorderLayout.CENTER);
 
+               // Listeners to enable/disable ok button
+               KeyAdapter keyListener = new KeyAdapter() {
+                       /** Key typed */
+                       public void keyTyped(KeyEvent arg0) {
+                               _okButton.setEnabled(getOffsetSecs() != 0L);
+                       }
+               };
+               MouseAdapter mouseListener = new MouseAdapter() {
+                       public void mouseReleased(java.awt.event.MouseEvent arg0) {
+                               _okButton.setEnabled(getOffsetSecs() != 0L);
+                       };
+               };
+               _dayField.addKeyListener(keyListener);
+               _hourField.addKeyListener(keyListener);
+               _minuteField.addKeyListener(keyListener);
+               _dayField.addMouseListener(mouseListener);
+               _hourField.addMouseListener(mouseListener);
+               _minuteField.addMouseListener(mouseListener);
+
                // button panel at bottom
                JPanel buttonPanel = new JPanel();
                buttonPanel.setLayout(new FlowLayout(FlowLayout.RIGHT));
-               JButton okButton = new JButton(I18nManager.getText("button.ok"));
+               _okButton = new JButton(I18nManager.getText("button.ok"));
                ActionListener okListener = new ActionListener() {
                        public void actionPerformed(ActionEvent e)
                        {
                                finish();
                        }
                };
-               okButton.addActionListener(okListener);
-               buttonPanel.add(okButton);
+               _okButton.addActionListener(okListener);
+               _okButton.setEnabled(false);
+               buttonPanel.add(_okButton);
                JButton cancelButton = new JButton(I18nManager.getText("button.cancel"));
                cancelButton.addActionListener(new ActionListener() {
                        public void actionPerformed(ActionEvent e)
@@ -141,6 +172,17 @@ public class TimeOffsetDialog
                return label;
        }
 
+       /**
+        * @return the number of offset seconds entered by the user
+        */
+       private long getOffsetSecs()
+       {
+               long offsetSecs = _minuteField.getValue() * 60L
+               + _hourField.getValue() * 60L * 60L
+               + _dayField.getValue() * 60L * 60L * 24L;
+               if (_subtractRadio.isSelected()) {offsetSecs = -offsetSecs;}
+               return offsetSecs;
+       }
 
        /**
         * Finish the dialog when OK pressed
@@ -148,10 +190,7 @@ public class TimeOffsetDialog
        private void finish()
        {
                // Calculate offset to add or subtract
-               long offsetSecs = _minuteField.getValue() * 60L
-                       + _hourField.getValue() * 60L * 60L
-                       + _dayField.getValue() * 60L * 60L * 24L;
-               if (_subtractRadio.isSelected()) {offsetSecs = -offsetSecs;}
+               long offsetSecs = getOffsetSecs();
                if (offsetSecs != 0L)
                {
                        // Pass offset back to app and close dialog
similarity index 74%
rename from tim/prune/gui/CheckVersionScreen.java
rename to tim/prune/function/CheckVersionScreen.java
index e57b724d77a1942bc865c3f3b3067a2d24dda561..a34319f26e899f68866dbae39b2ba05a64c6bec9 100644 (file)
@@ -1,4 +1,4 @@
-package tim.prune.gui;
+package tim.prune.function;
 
 import java.io.IOException;
 import java.io.InputStream;
@@ -7,24 +7,40 @@ import java.text.DateFormat;
 import java.text.ParseException;
 import java.text.SimpleDateFormat;
 import java.util.Properties;
-import javax.swing.JFrame;
 import javax.swing.JOptionPane;
 
+import tim.prune.App;
+import tim.prune.GenericFunction;
 import tim.prune.GpsPruner;
 import tim.prune.I18nManager;
-import tim.prune.browser.BrowserLauncher;
+import tim.prune.function.browser.BrowserLauncher;
 
 /**
  * Class to check the version of Prune
  * and show an appropriate dialog
  */
-public abstract class CheckVersionScreen
+public class CheckVersionScreen extends GenericFunction
 {
+       /**
+        * Constructor
+        * @param inApp app object
+        */
+       public CheckVersionScreen(App inApp)
+       {
+               super(inApp);
+       }
+
+       /**
+        * Get the name key
+        */
+       public String getNameKey() {
+               return "function.checkversion";
+       }
+
        /**
         * Show the check version dialog
-        * @param inParent parent frame
         */
-       public static void show(JFrame inParent)
+       public void begin()
        {
                final String filePathStart = "http://activityworkshop.net/software/prune/prune_versioncheck_";
                final String filePathEnd = ".txt";
@@ -49,8 +65,8 @@ public abstract class CheckVersionScreen
 
                if (latestVer == null) {
                        // Couldn't get version number, show error message
-                       JOptionPane.showMessageDialog(inParent, I18nManager.getText("dialog.checkversion.error"),
-                               I18nManager.getText("dialog.checkversion.title"), JOptionPane.ERROR_MESSAGE);
+                       JOptionPane.showMessageDialog(_parentFrame, I18nManager.getText("dialog.checkversion.error"),
+                               I18nManager.getText(getNameKey()), JOptionPane.ERROR_MESSAGE);
                }
                else if (latestVer.equals(GpsPruner.VERSION_NUMBER))
                {
@@ -61,8 +77,8 @@ public abstract class CheckVersionScreen
                                displayMessage += "\n\n" + nextVersion;
                        }
                        // Show information message that the current version is already running
-                       JOptionPane.showMessageDialog(inParent, displayMessage,
-                               I18nManager.getText("dialog.checkversion.title"), JOptionPane.INFORMATION_MESSAGE);
+                       JOptionPane.showMessageDialog(_parentFrame, displayMessage,
+                               I18nManager.getText(getNameKey()), JOptionPane.INFORMATION_MESSAGE);
                }
                else
                {
@@ -84,13 +100,13 @@ public abstract class CheckVersionScreen
 
                        // Show information message to download the new version
                        Object[] buttonTexts = {I18nManager.getText("button.showwebpage"), I18nManager.getText("button.cancel")};
-                       if (JOptionPane.showOptionDialog(inParent, displayMessage,
-                                       I18nManager.getText("dialog.checkversion.title"), JOptionPane.YES_NO_OPTION,
+                       if (JOptionPane.showOptionDialog(_parentFrame, displayMessage,
+                                       I18nManager.getText(getNameKey()), JOptionPane.YES_NO_OPTION,
                                        JOptionPane.INFORMATION_MESSAGE, null, buttonTexts, buttonTexts[1])
                                == JOptionPane.YES_OPTION)
                        {
                                // User selected to launch home page
-                               new BrowserLauncher().launchBrowser("http://activityworkshop.net/software/prune/download.html");
+                               BrowserLauncher.launchBrowser("http://activityworkshop.net/software/prune/download.html");
                        }
                }
        }
diff --git a/tim/prune/function/HelpScreen.java b/tim/prune/function/HelpScreen.java
new file mode 100644 (file)
index 0000000..53816dc
--- /dev/null
@@ -0,0 +1,47 @@
+package tim.prune.function;
+
+import javax.swing.JOptionPane;
+
+import tim.prune.App;
+import tim.prune.GenericFunction;
+import tim.prune.I18nManager;
+import tim.prune.function.browser.BrowserLauncher;
+
+/**
+ * Class to show a simple help screen
+ */
+public class HelpScreen extends GenericFunction
+{
+       /**
+        * Constructor
+        * @param inApp app object
+        */
+       public HelpScreen(App inApp)
+       {
+               super(inApp);
+       }
+
+       /**
+        * Get the name key
+        */
+       public String getNameKey() {
+               return "function.help";
+       }
+
+       /**
+        * Show the help screen
+        */
+       public void begin()
+       {
+               // show the dialog and offer to open home page
+               Object[] buttonTexts = {I18nManager.getText("button.showwebpage"), I18nManager.getText("button.cancel")};
+               if (JOptionPane.showOptionDialog(_parentFrame, I18nManager.getText("dialog.help.help"),
+                               I18nManager.getText("function.help"), JOptionPane.YES_NO_OPTION,
+                               JOptionPane.INFORMATION_MESSAGE, null, buttonTexts, buttonTexts[1])
+                       == JOptionPane.YES_OPTION)
+               {
+                       // User selected to launch home page
+                       BrowserLauncher.launchBrowser("http://activityworkshop.net/software/prune/index.html");
+               }
+       }
+}
diff --git a/tim/prune/function/RearrangeWaypointsFunction.java b/tim/prune/function/RearrangeWaypointsFunction.java
new file mode 100644 (file)
index 0000000..9007391
--- /dev/null
@@ -0,0 +1,76 @@
+package tim.prune.function;
+
+import javax.swing.JOptionPane;
+
+import tim.prune.App;
+import tim.prune.GenericFunction;
+import tim.prune.I18nManager;
+import tim.prune.data.Track;
+import tim.prune.undo.UndoRearrangeWaypoints;
+
+/**
+ * Class to provide the function for rearranging waypoints
+ */
+public class RearrangeWaypointsFunction extends GenericFunction
+{
+
+       /** Enumeration for rearrange commands */
+       public enum Rearrange
+       {
+               /** Rearrange all waypoints to start */
+               TO_START,
+               /** Rearrange all waypoints to end */
+               TO_END,
+               /** Rearrange each waypoint to nearest track point */
+               TO_NEAREST
+       }
+
+       /**
+        * Constructor
+        * @param inApp app object
+        */
+       public RearrangeWaypointsFunction(App inApp)
+       {
+               super(inApp);
+       }
+
+       /** Begin the rearrange (not needed) */
+       public void begin() {
+       }
+
+       /** Get the name key (not needed) */
+       public String getNameKey() {
+               return null;
+       }
+
+       /**
+        * Rearrange the waypoints into track order
+        * @param inFunction nearest point, all to end or all to start
+        */
+       public void rearrangeWaypoints(Rearrange inFunction)
+       {
+               Track track = _app.getTrackInfo().getTrack();
+               UndoRearrangeWaypoints undo = new UndoRearrangeWaypoints(track);
+               boolean success = false;
+               if (inFunction == Rearrange.TO_START || inFunction == Rearrange.TO_END)
+               {
+                       // Collect the waypoints to the start or end of the track
+                       success = track.collectWaypoints(inFunction == Rearrange.TO_START);
+               }
+               else
+               {
+                       // Interleave the waypoints into track order
+                       success = track.interleaveWaypoints();
+               }
+               if (success)
+               {
+                       _app.completeFunction(undo, I18nManager.getText("confirm.rearrangewaypoints"));
+               }
+               else
+               {
+                       JOptionPane.showMessageDialog(_parentFrame, I18nManager.getText("error.rearrange.noop"),
+                               I18nManager.getText("error.function.noop.title"), JOptionPane.WARNING_MESSAGE);
+               }
+       }
+
+}
diff --git a/tim/prune/function/SetMapBgFunction.java b/tim/prune/function/SetMapBgFunction.java
new file mode 100644 (file)
index 0000000..7c5df3a
--- /dev/null
@@ -0,0 +1,202 @@
+package tim.prune.function;
+
+import java.awt.BorderLayout;
+import java.awt.Component;
+import java.awt.FlowLayout;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.awt.event.KeyAdapter;
+import java.awt.event.KeyEvent;
+
+import javax.swing.BoxLayout;
+import javax.swing.ButtonGroup;
+import javax.swing.JButton;
+import javax.swing.JDialog;
+import javax.swing.JLabel;
+import javax.swing.JPanel;
+import javax.swing.JRadioButton;
+import javax.swing.JTextField;
+
+import tim.prune.App;
+import tim.prune.Config;
+import tim.prune.DataSubscriber;
+import tim.prune.GenericFunction;
+import tim.prune.I18nManager;
+import tim.prune.UpdateMessageBroker;
+
+/**
+ * Function to set the tile server for the map backgrounds
+ */
+public class SetMapBgFunction extends GenericFunction
+{
+       private JDialog _dialog = null;
+       private JButton _okButton = null;
+       private JRadioButton[] _serverRadios = null;
+       private JTextField _serverUrl = null;
+       /** Index of 'other' server with freeform url */
+       private static final int OTHER_SERVER_NUM = 3;
+
+
+       /**
+        * Constructor
+        * @param inApp app object
+        */
+       public SetMapBgFunction(App inApp)
+       {
+               super(inApp);
+       }
+
+       /** Get the name key */
+       public String getNameKey() {
+               return "function.setmapbg";
+       }
+
+       /**
+        * Begin the function
+        */
+       public void begin()
+       {
+               // Make dialog window
+               if (_dialog == null)
+               {
+                       _dialog = new JDialog(_parentFrame, I18nManager.getText(getNameKey()), true);
+                       _dialog.setLocationRelativeTo(_parentFrame);
+                       _dialog.setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE);
+                       _dialog.getContentPane().add(makeDialogComponents());
+                       initValues();
+                       _dialog.pack();
+               }
+               enableOK();
+               _dialog.setVisible(true);
+       }
+
+
+       /**
+        * Create dialog components
+        * @return Panel containing all gui elements in dialog
+        */
+       private Component makeDialogComponents()
+       {
+               JPanel dialogPanel = new JPanel();
+               dialogPanel.setLayout(new BorderLayout());
+               // Main panel
+               JPanel mainPanel = new JPanel();
+               mainPanel.setLayout(new BoxLayout(mainPanel, BoxLayout.Y_AXIS));
+               _serverRadios = new JRadioButton[4];
+               ButtonGroup serverRadioGroup = new ButtonGroup();
+               String[] serverKeys = {"dialog.setmapbg.mapnik", "dialog.setmapbg.osma",
+                       "dialog.setmapbg.cyclemap", "dialog.setmapbg.other"};
+               // action listener for radios
+               ActionListener changeListener = new ActionListener() {
+                       public void actionPerformed(ActionEvent arg0) {
+                               enableOK();
+                       }
+               };
+               // Create four radio buttons
+               for (int i=0; i<4; i++)
+               {
+                       _serverRadios[i] = new JRadioButton(I18nManager.getText(serverKeys[i]));
+                       _serverRadios[i].addActionListener(changeListener);
+                       serverRadioGroup.add(_serverRadios[i]);
+                       mainPanel.add(_serverRadios[i]);
+               }
+               // entry field for other server urls
+               mainPanel.add(new JLabel(I18nManager.getText("dialog.setmapbg.server")));
+               _serverUrl = new JTextField("", 12);
+               _serverUrl.addKeyListener(new KeyAdapter() {
+                       public void keyReleased(KeyEvent e) {
+                               super.keyReleased(e);
+                               enableOK();
+                       }
+               });
+               mainPanel.add(_serverUrl);
+               dialogPanel.add(mainPanel, BorderLayout.NORTH);
+
+               // button panel at bottom
+               JPanel buttonPanel = new JPanel();
+               buttonPanel.setLayout(new FlowLayout(FlowLayout.RIGHT));
+               _okButton = new JButton(I18nManager.getText("button.ok"));
+               ActionListener okListener = new ActionListener() {
+                       public void actionPerformed(ActionEvent e)
+                       {
+                               finish();
+                       }
+               };
+               _okButton.addActionListener(okListener);
+               buttonPanel.add(_okButton);
+               JButton cancelButton = new JButton(I18nManager.getText("button.cancel"));
+               cancelButton.addActionListener(new ActionListener() {
+                       public void actionPerformed(ActionEvent e)
+                       {
+                               _dialog.dispose();
+                       }
+               });
+               buttonPanel.add(cancelButton);
+               dialogPanel.add(buttonPanel, BorderLayout.SOUTH);
+               return dialogPanel;
+       }
+
+
+       /**
+        * Get the initial values from the Config and set gui values accordingly
+        */
+       private void initValues()
+       {
+               // Get values from config
+               try {
+                       _serverRadios[Config.getMapServerIndex()].setSelected(true);
+               }
+               catch (ArrayIndexOutOfBoundsException e) {} // ignore
+               String url = Config.getMapServerUrl();
+               if (url != null) {_serverUrl.setText(url);}
+               // Choose default if none selected
+               if (getSelectedServer() < 0) {
+                       _serverRadios[0].setSelected(true);
+               }
+       }
+
+       /**
+        * @return index of selected radio button, or -1 if none
+        */
+       private int getSelectedServer()
+       {
+               // Loop over all four radios
+               for (int i=0; i<4; i++) {
+                       if (_serverRadios[i].isSelected()) {return i;}
+               }
+               // None selected
+               return -1;
+       }
+
+       /**
+        * Enable or disable the OK button according to the selection
+        */
+       private void enableOK()
+       {
+               int serverNum = getSelectedServer();
+               _okButton.setEnabled(inputOK());
+               _serverUrl.setEnabled(serverNum == OTHER_SERVER_NUM);
+       }
+
+       /**
+        * @return true if inputs are ok
+        */
+       private boolean inputOK()
+       {
+               int serverNum = getSelectedServer();
+               return serverNum >= 0 && (serverNum != OTHER_SERVER_NUM || _serverUrl.getText().length() > 4);
+       }
+
+       /**
+        * Finish the dialog when OK pressed
+        */
+       private void finish()
+       {
+               int serverNum = getSelectedServer();
+               if (!inputOK()) {serverNum = 0;}
+               Config.setMapServerIndex(serverNum);
+               Config.setMapServerUrl(_serverUrl.getText());
+               UpdateMessageBroker.informSubscribers(DataSubscriber.MAPSERVER_CHANGED);
+               _dialog.dispose();
+       }
+}
diff --git a/tim/prune/function/ShowThreeDFunction.java b/tim/prune/function/ShowThreeDFunction.java
new file mode 100644 (file)
index 0000000..8ba0f41
--- /dev/null
@@ -0,0 +1,58 @@
+package tim.prune.function;
+
+import javax.swing.JOptionPane;
+
+import tim.prune.App;
+import tim.prune.GenericFunction;
+import tim.prune.I18nManager;
+import tim.prune.threedee.ThreeDException;
+import tim.prune.threedee.ThreeDWindow;
+import tim.prune.threedee.WindowFactory;
+
+/**
+ * Class to show the 3d window
+ */
+public class ShowThreeDFunction extends GenericFunction
+{
+       /**
+        * Constructor
+        * @param inApp app object
+        */
+       public ShowThreeDFunction(App inApp)
+       {
+               super(inApp);
+       }
+
+       /**
+        * Get the name key
+        */
+       public String getNameKey() {
+               return "function.show3d";
+       }
+
+       /**
+        * Show the help screen
+        */
+       public void begin()
+       {
+               ThreeDWindow window = WindowFactory.getWindow(_parentFrame);
+               if (window == null)
+               {
+                       JOptionPane.showMessageDialog(_parentFrame, I18nManager.getText("error.function.nojava3d"),
+                               I18nManager.getText("error.function.notavailable.title"), JOptionPane.WARNING_MESSAGE);
+               }
+               else
+               {
+                       try
+                       {
+                               // Pass the track object and show the window
+                               window.setTrack(_app.getTrackInfo().getTrack());
+                               window.show();
+                       }
+                       catch (ThreeDException e)
+                       {
+                               _app.showErrorMessageNoLookup(getNameKey(), I18nManager.getText("error.3d") + ": " + e.getMessage());
+                       }
+               }
+       }
+}
similarity index 85%
rename from tim/prune/browser/BrowserLauncher.java
rename to tim/prune/function/browser/BrowserLauncher.java
index fe4c79a3586a42560f7fca072fadfb509ed1f40f..1decbc3f586de321d7208dad537804af297d4da6 100644 (file)
@@ -1,4 +1,4 @@
-package tim.prune.browser;
+package tim.prune.function.browser;
 
 import javax.swing.JOptionPane;
 
@@ -6,15 +6,17 @@ import javax.swing.JOptionPane;
 /**
  * Class to launch a browser window to show an external map
  */
-public class BrowserLauncher
+public abstract class BrowserLauncher
 {
-       private String[] _browserCommand = null;
-       private boolean _urlNeedsQuotes = false;
+       private static boolean _initialised = false;
+       private static String[] _browserCommand = null;
+       private static boolean _urlNeedsQuotes = false;
+
 
        /**
-        * Constructor to set up browser
+        * Init method to set up browser
         */
-       public BrowserLauncher()
+       private static void init()
        {
                // First check if "which" command is available
                if (commandExists("which"))
@@ -45,8 +47,10 @@ public class BrowserLauncher
                                _urlNeedsQuotes = true;
                        }
                }
+               _initialised = true;
        }
 
+
        /**
         * Check if the specified command exists on the system
         * @param inCommand command to check
@@ -66,12 +70,14 @@ public class BrowserLauncher
                return false;
        }
 
+
        /**
         * Launch a browser window to show the given url
         * @param inUrl url to show
         */
-       public void launchBrowser(String inUrl)
+       public static void launchBrowser(String inUrl)
        {
+               if (!_initialised) {init();}
                if (_browserCommand == null) {
                        JOptionPane.showMessageDialog(null, "Cannot show url: " + inUrl);
                }
similarity index 67%
rename from tim/prune/browser/UrlGenerator.java
rename to tim/prune/function/browser/UrlGenerator.java
index aa78a22344c57167cdb4c9c6d22cb8e05209cfe2..14d15776a8be3d19213cf0419ea240349146b9d6 100644 (file)
@@ -1,4 +1,4 @@
-package tim.prune.browser;
+package tim.prune.function.browser;
 
 import java.text.DecimalFormat;
 import java.text.NumberFormat;
@@ -16,7 +16,7 @@ import tim.prune.data.TrackInfo;
 public abstract class UrlGenerator
 {
        /** Number formatter for five dp */
-       public static final NumberFormat FIVE_DP = NumberFormat.getNumberInstance(Locale.UK);
+       private static final NumberFormat FIVE_DP = NumberFormat.getNumberInstance(Locale.UK);
        // Select the UK locale for this formatter so that decimal point is always used (not comma)
        static {
                if (FIVE_DP instanceof DecimalFormat) ((DecimalFormat) FIVE_DP).applyPattern("0.00000");
@@ -26,8 +26,12 @@ public abstract class UrlGenerator
        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;
 
-       // TODO: Add other map sources, eg Yahoo, MSN, search.ch ?
+       // TODO: Add other map sources, eg MSN, search.ch ?
 
        /**
         * Generate a URL for the given source and track info
@@ -40,6 +44,12 @@ public abstract class UrlGenerator
                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);
+               }
                return generateOpenStreetMapUrl(inTrackInfo);
        }
 
@@ -104,6 +114,47 @@ public abstract class UrlGenerator
        }
 
        /**
+        * Generate a url for Mapquest maps
+        * @param inTrackInfo track information
+        * @return URL
+        */
+       private static String generateMapquestUrl(TrackInfo inTrackInfo)
+       {
+               // Check if any data to display
+               if (inTrackInfo == null || inTrackInfo.getTrack() == null || inTrackInfo.getTrack().getNumPoints() < 1)
+               {
+                       return null;
+               }
+               double medianLat = getMedianValue(inTrackInfo.getTrack().getLatRange());
+               double medianLon = getMedianValue(inTrackInfo.getTrack().getLonRange());
+               // Build basic url with centre position
+               String url = "http://atlas.mapquest.com/maps/map.adp?latlongtype=decimal&latitude="
+                       + FIVE_DP.format(medianLat) + "&longitude=" + FIVE_DP.format(medianLon);
+               return url;
+       }
+
+
+       /**
+        * Generate a url for Yahoo maps
+        * @param inTrackInfo track information
+        * @return URL
+        */
+       private static String generateYahooUrl(TrackInfo inTrackInfo)
+       {
+               // Check if any data to display
+               if (inTrackInfo == null || inTrackInfo.getTrack() == null || inTrackInfo.getTrack().getNumPoints() < 1)
+               {
+                       return null;
+               }
+               double medianLat = getMedianValue(inTrackInfo.getTrack().getLatRange());
+               double medianLon = getMedianValue(inTrackInfo.getTrack().getLonRange());
+               // Build basic url with centre position
+               String url = "http://maps.yahoo.com/#lat=" + FIVE_DP.format(medianLat)
+                       + "&lon=" + FIVE_DP.format(medianLon) + "&zoom=13";
+               return url;
+       }
+
+/**
         * Get the median value from the given lat/long range
         * @param inRange range of values
         * @return median value
diff --git a/tim/prune/function/charts/ChartSeries.java b/tim/prune/function/charts/ChartSeries.java
new file mode 100644 (file)
index 0000000..ea6128f
--- /dev/null
@@ -0,0 +1,51 @@
+package tim.prune.function.charts;
+
+/**
+ * Class to hold a data series for the charts
+ */
+public class ChartSeries
+{
+       /** Array of booleans, true for data existing, false otherwise */
+       private boolean[] _hasData = null;
+       /** Array of data */
+       private double[] _data = null;
+
+       /**
+        * Constructor
+        * @param inNumPoints number of points
+        */
+       public ChartSeries(int inNumPoints)
+       {
+               _hasData = new boolean[inNumPoints];
+               _data = new double[inNumPoints];
+       }
+
+       /**
+        * @param inIndex index of point
+        * @return true if series has data for this point
+        */
+       public boolean hasData(int inIndex)
+       {
+               return _hasData[inIndex];
+       }
+
+       /**
+        * @param inIndex index of point
+        * @return data value for this point
+        */
+       public double getData(int inIndex)
+       {
+               return _data[inIndex];
+       }
+
+       /**
+        * Set the data at the given index
+        * @param inIndex index of point
+        * @param inData data value
+        */
+       public void setData(int inIndex, double inData)
+       {
+               _hasData[inIndex] = true;
+               _data[inIndex] = inData;
+       }
+}
diff --git a/tim/prune/function/charts/Charter.java b/tim/prune/function/charts/Charter.java
new file mode 100644 (file)
index 0000000..a3348c8
--- /dev/null
@@ -0,0 +1,697 @@
+package tim.prune.function.charts;
+
+import java.awt.BorderLayout;
+import java.awt.FlowLayout;
+import java.awt.GridLayout;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.io.File;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.io.OutputStreamWriter;
+
+import javax.swing.BorderFactory;
+import javax.swing.BoxLayout;
+import javax.swing.ButtonGroup;
+import javax.swing.JButton;
+import javax.swing.JCheckBox;
+import javax.swing.JDialog;
+import javax.swing.JFileChooser;
+import javax.swing.JLabel;
+import javax.swing.JOptionPane;
+import javax.swing.JPanel;
+import javax.swing.JRadioButton;
+import javax.swing.JTextField;
+import javax.swing.SwingConstants;
+
+import tim.prune.App;
+import tim.prune.Config;
+import tim.prune.ExternalTools;
+import tim.prune.GenericFunction;
+import tim.prune.I18nManager;
+import tim.prune.data.Altitude;
+import tim.prune.data.DataPoint;
+import tim.prune.data.Distance;
+import tim.prune.data.Field;
+import tim.prune.data.Timestamp;
+import tim.prune.data.Track;
+import tim.prune.data.Distance.Units;
+import tim.prune.load.GenericFileFilter;
+
+/**
+ * Class to manage the generation of charts using gnuplot
+ */
+public class Charter extends GenericFunction
+{
+       /** dialog object, cached */
+       private JDialog _dialog = null;
+       /** radio button for distance axis */
+       private JRadioButton _distanceRadio = null;
+       /** radio button for time axis */
+       private JRadioButton _timeRadio = null;
+       /** array of checkboxes for specifying y axes */
+       private JCheckBox[] _yAxesBoxes = null;
+       /** radio button for svg output */
+       private JRadioButton _svgRadio = null;
+       /** file chooser for saving svg file */
+       private JFileChooser _fileChooser = null;
+       /** text field for svg width */
+       private JTextField _svgWidthField = null;
+       /** text field for svg height */
+       private JTextField _svgHeightField = null;
+
+       /** Default dimensions of Svg file */
+       private static final String DEFAULT_SVG_WIDTH  = "800";
+       private static final String DEFAULT_SVG_HEIGHT = "400";
+
+
+       /**
+        * Constructor from superclass
+        * @param inApp app object
+        */
+       public Charter(App inApp)
+       {
+               super(inApp);
+       }
+
+       /**
+        * @return key for function name
+        */
+       public String getNameKey()
+       {
+               return "function.charts";
+       }
+
+       /**
+        * Show the dialog
+        */
+       public void begin()
+       {
+               // Make dialog window
+               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();
+               }
+               if (setupDialog(_app.getTrackInfo().getTrack())) {
+                       _dialog.setVisible(true);
+               }
+               else {
+                       _app.showErrorMessage(getNameKey(), "dialog.charts.needaltitudeortimes");
+               }
+       }
+
+
+       /**
+        * Make the dialog components
+        * @return panel containing gui elements
+        */
+       private JPanel makeDialogComponents()
+       {
+               JPanel dialogPanel = new JPanel();
+               dialogPanel.setLayout(new BorderLayout());
+
+               JPanel mainPanel = new JPanel();
+               mainPanel.setLayout(new BoxLayout(mainPanel, BoxLayout.Y_AXIS));
+               // x axis choice
+               JPanel axisPanel = new JPanel();
+               axisPanel.setBorder(BorderFactory.createTitledBorder(I18nManager.getText("dialog.charts.xaxis")));
+               _distanceRadio = new JRadioButton(I18nManager.getText("fieldname.distance"));
+               _distanceRadio.setSelected(true);
+               _timeRadio = new JRadioButton(I18nManager.getText("fieldname.time"));
+               ButtonGroup axisGroup = new ButtonGroup();
+               axisGroup.add(_distanceRadio); axisGroup.add(_timeRadio);
+               axisPanel.add(_distanceRadio); axisPanel.add(_timeRadio);
+               mainPanel.add(axisPanel);
+
+               // y axis choices
+               JPanel yPanel = new JPanel();
+               yPanel.setBorder(BorderFactory.createTitledBorder(I18nManager.getText("dialog.charts.yaxis")));
+               _yAxesBoxes = new JCheckBox[4]; // dist altitude speed vertspeed (time not available on y axis)
+               _yAxesBoxes[0] = new JCheckBox(I18nManager.getText("fieldname.distance"));
+               _yAxesBoxes[1] = new JCheckBox(I18nManager.getText("fieldname.altitude"));
+               _yAxesBoxes[1].setSelected(true);
+               _yAxesBoxes[2] = new JCheckBox(I18nManager.getText("fieldname.speed"));
+               _yAxesBoxes[3] = new JCheckBox(I18nManager.getText("fieldname.verticalspeed"));
+               for (int i=0; i<4; i++) {
+                       yPanel.add(_yAxesBoxes[i]);
+               }
+               mainPanel.add(yPanel);
+
+               // Add validation to prevent choosing invalid (ie dist/dist) combinations
+               ActionListener xAxisListener = new ActionListener() {
+                       public void actionPerformed(ActionEvent e) {
+                               enableYbox(0, _timeRadio.isSelected());
+                       }
+               };
+               _timeRadio.addActionListener(xAxisListener);
+               _distanceRadio.addActionListener(xAxisListener);
+
+               // output buttons
+               JPanel outputPanel = new JPanel();
+               outputPanel.setBorder(BorderFactory.createTitledBorder(I18nManager.getText("dialog.charts.output")));
+               outputPanel.setLayout(new BorderLayout());
+               JPanel radiosPanel = new JPanel();
+               JRadioButton screenRadio = new JRadioButton(I18nManager.getText("dialog.charts.screen"));
+               screenRadio.setSelected(true);
+               _svgRadio = new JRadioButton(I18nManager.getText("dialog.charts.svg"));
+               ButtonGroup outputGroup = new ButtonGroup();
+               outputGroup.add(screenRadio); outputGroup.add(_svgRadio);
+               radiosPanel.add(screenRadio); radiosPanel.add(_svgRadio);
+               outputPanel.add(radiosPanel, BorderLayout.NORTH);
+               // panel for svg width, height
+               JPanel sizePanel = new JPanel();
+               sizePanel.setLayout(new GridLayout(2, 2, 10, 1));
+               JLabel widthLabel = new JLabel(I18nManager.getText("dialog.charts.svgwidth"));
+               widthLabel.setHorizontalAlignment(SwingConstants.RIGHT);
+               sizePanel.add(widthLabel);
+               _svgWidthField = new JTextField(DEFAULT_SVG_WIDTH, 5);
+               sizePanel.add(_svgWidthField);
+               JLabel heightLabel = new JLabel(I18nManager.getText("dialog.charts.svgheight"));
+               heightLabel.setHorizontalAlignment(SwingConstants.RIGHT);
+               sizePanel.add(heightLabel);
+               _svgHeightField = new JTextField(DEFAULT_SVG_HEIGHT, 5);
+               sizePanel.add(_svgHeightField);
+
+               outputPanel.add(sizePanel, BorderLayout.EAST);
+               mainPanel.add(outputPanel);
+               dialogPanel.add(mainPanel, BorderLayout.CENTER);
+
+               // button panel on bottom
+               JPanel buttonPanel = new JPanel();
+               buttonPanel.setLayout(new FlowLayout(FlowLayout.RIGHT));
+               // Gnuplot button
+               JButton gnuplotButton = new JButton(I18nManager.getText("button.gnuplotpath"));
+               gnuplotButton.addActionListener(new ActionListener() {
+                       public void actionPerformed(ActionEvent e) {
+                               setGnuplotPath();
+                       }
+               });
+               buttonPanel.add(gnuplotButton);
+               // Cancel button
+               JButton cancelButton = new JButton(I18nManager.getText("button.cancel"));
+               cancelButton.addActionListener(new ActionListener() {
+                       public void actionPerformed(ActionEvent e) {
+                               _dialog.setVisible(false);
+                       }
+               });
+               buttonPanel.add(cancelButton);
+               // ok button
+               JButton okButton = new JButton(I18nManager.getText("button.ok"));
+               okButton.addActionListener(new ActionListener() {
+                       public void actionPerformed(ActionEvent e) {
+                               showChart(_app.getTrackInfo().getTrack());
+                               _dialog.setVisible(false);
+                       }
+               });
+               buttonPanel.add(okButton);
+               dialogPanel.add(buttonPanel, BorderLayout.SOUTH);
+               return dialogPanel;
+       }
+
+
+       /**
+        * Set up the dialog according to the track contents
+        * @param inTrack track object
+        * @return true if it's all ok
+        */
+       private boolean setupDialog(Track inTrack)
+       {
+               boolean hasTimes = inTrack.hasData(Field.TIMESTAMP);
+               boolean hasAltitudes = inTrack.getAltitudeRange().hasRange();
+               _timeRadio.setEnabled(hasTimes);
+
+               // Add checks to prevent choosing unavailable combinations
+               if (!hasTimes) {
+                       _distanceRadio.setSelected(true);
+               }
+               enableYbox(0, !_distanceRadio.isSelected());
+               enableYbox(1, hasAltitudes);
+               enableYbox(2, hasTimes);
+               enableYbox(3, hasTimes && hasAltitudes);
+               return (hasTimes || hasAltitudes);
+       }
+
+
+       /**
+        * Enable or disable the given y axis checkbox
+        * @param inIndex index of checkbox
+        * @param inFlag true to enable
+        */
+       private void enableYbox(int inIndex, boolean inFlag)
+       {
+               _yAxesBoxes[inIndex].setEnabled(inFlag);
+               if (!inFlag) {
+                       _yAxesBoxes[inIndex].setSelected(inFlag);
+               }
+       }
+
+       /**
+        * Show the chart for the specified track
+        * @param inTrack track object containing data
+        */
+       private void showChart(Track inTrack)
+       {
+               int numCharts = 0;
+               for (int i=0; i<_yAxesBoxes.length; i++) {
+                       if (_yAxesBoxes[i].isSelected()) {
+                               numCharts++;
+                       }
+               }
+               // Select default chart if none selected
+               if (numCharts == 0) {
+                       _yAxesBoxes[1].setSelected(true);
+                       numCharts = 1;
+               }
+               int[] heights = getHeights(numCharts);
+
+               boolean showSvg = _svgRadio.isSelected();
+               File svgFile = null;
+               if (showSvg) {
+                       svgFile = selectSvgFile();
+                       if (svgFile == null) {showSvg = false;}
+               }
+               OutputStreamWriter writer = null;
+               try
+               {
+                       Process process = Runtime.getRuntime().exec(Config.getGnuplotPath() + " -persist");
+                       writer = new OutputStreamWriter(process.getOutputStream());
+                       if (showSvg)
+                       {
+                               writer.write("set terminal svg size " + getSvgValue(_svgWidthField, DEFAULT_SVG_WIDTH) + " "
+                                       + getSvgValue(_svgHeightField, DEFAULT_SVG_HEIGHT) + "\n");
+                               writer.write("set out '" + svgFile.getAbsolutePath() + "'\n");
+                       }
+                       if (numCharts > 1) {
+                               writer.write("set multiplot layout " + numCharts + ",1\n");
+                       }
+                       // Loop over possible charts
+                       int chartNum = 0;
+                       for (int c=0; c<_yAxesBoxes.length; c++)
+                       {
+                               if (_yAxesBoxes[c].isSelected())
+                               {
+                                       writer.write("set size 1," + (0.01*heights[chartNum*2+1]) + "\n");
+                                       writer.write("set origin 0," + (0.01*heights[chartNum*2]) + "\n");
+                                       writeChart(writer, inTrack, _distanceRadio.isSelected(), c);
+                                       chartNum++;
+                               }
+                       }
+                       // Close multiplot if open
+                       if (numCharts > 1) {
+                               writer.write("unset multiplot\n");
+                       }
+               }
+               catch (Exception e) {
+                       _app.showErrorMessageNoLookup(getNameKey(), e.getMessage());
+               }
+               finally {
+                       try {
+                               // Close writer
+                               if (writer != null) writer.close();
+                       }
+                       catch (Exception e) {} // ignore
+               }
+       }
+
+
+       /**
+        * Parse the given text field's value and return as string
+        * @param inField text field to read from
+        * @param inDefault default value if not valid
+        * @return value of svg dimension as string
+        */
+       private static String getSvgValue(JTextField inField, String inDefault)
+       {
+               int value = 0;
+               try {
+                       value = Integer.parseInt(inField.getText());
+               }
+               catch (Exception e) {} // ignore, value stays zero
+               if (value > 0) {
+                       return "" + value;
+               }
+               return inDefault;
+       }
+
+
+       /**
+        * Write out the selected chart to the given Writer object
+        * @param inWriter writer object
+        * @param inTrack Track containing data
+        * @param inDistance true if x axis is distance
+        * @param inYaxis index of y axis
+        * @throws IOException if writing error occurred
+        */
+       private static void writeChart(OutputStreamWriter inWriter, Track inTrack, boolean inDistance, int inYaxis)
+       throws IOException
+       {
+               ChartSeries xValues = null, yValues = null;
+               ChartSeries distValues = getDistanceValues(inTrack);
+               // Choose x values according to axis
+               if (inDistance) {
+                       xValues = distValues;
+               }
+               else {
+                       xValues = getTimeValues(inTrack);
+               }
+               // Choose y values according to axis
+               switch (inYaxis)
+               {
+               case 0: // y axis is distance
+                       yValues = distValues;
+                       break;
+               case 1: // y axis is altitude
+                       yValues = getAltitudeValues(inTrack);
+                       break;
+               case 2: // y axis is speed
+                       yValues = getSpeedValues(inTrack);
+                       break;
+               case 3: // y axis is vertical speed
+                       yValues = getVertSpeedValues(inTrack);
+                       break;
+               }
+               // Make a temporary data file for the output (one per subchart)
+               File tempFile = File.createTempFile("prunedata", null);
+               tempFile.deleteOnExit();
+               // write out values for x and y to temporary file
+               FileWriter tempFileWriter = null;
+               try {
+                       tempFileWriter = new FileWriter(tempFile);
+                       tempFileWriter.write("# Temporary data file for Prune charts\n\n");
+                       for (int i=0; i<inTrack.getNumPoints(); i++) {
+                               if (xValues.hasData(i) && yValues.hasData(i)) {
+                                       tempFileWriter.write("" + xValues.getData(i) + ", " + yValues.getData(i) + "\n");
+                               }
+                       }
+               }
+               catch (IOException ioe) { // rethrow
+                       throw ioe;
+               }
+               finally {
+                       try {
+                               tempFileWriter.close();
+                       }
+                       catch (Exception e) {}
+               }
+
+               // Set x axis label
+               if (inDistance) {
+                       inWriter.write("set xlabel '" + I18nManager.getText("fieldname.distance") + " (" + getUnitsLabel("units.kilometres.short", "units.miles.short") + ")'\n");
+               }
+               else {
+                       inWriter.write("set xlabel '" + I18nManager.getText("fieldname.time") + " (" + I18nManager.getText("units.hours") + ")'\n");
+               }
+
+               // set other labels and plot chart
+               String chartTitle = null;
+               switch (inYaxis)
+               {
+               case 0: // y axis is distance
+                       inWriter.write("set ylabel '" + I18nManager.getText("fieldname.distance") + " (" + getUnitsLabel("units.kilometres.short", "units.miles.short") + ")'\n");
+                       chartTitle = I18nManager.getText("fieldname.distance");
+                       break;
+               case 1: // y axis is altitude
+                       inWriter.write("set ylabel '" + I18nManager.getText("fieldname.altitude") + " (" + getUnitsLabel("units.metres.short", "units.feet.short") + ")'\n");
+                       chartTitle = I18nManager.getText("fieldname.altitude");
+                       break;
+               case 2: // y axis is speed
+                       inWriter.write("set ylabel '" + I18nManager.getText("fieldname.speed") + " (" + getUnitsLabel("units.kmh", "units.mph") + ")'\n");
+                       chartTitle = I18nManager.getText("fieldname.speed");
+                       break;
+               case 3: // y axis is vertical speed
+                       inWriter.write("set ylabel '" + I18nManager.getText("fieldname.verticalspeed") + " (" + getUnitsLabel("units.metrespersec", "units.feetpersec") + ")'\n");
+                       chartTitle = I18nManager.getText("fieldname.verticalspeed");
+                       break;
+               }
+               inWriter.write("set style fill solid 0.5 border -1\n");
+               inWriter.write("plot '" + tempFile.getAbsolutePath() + "' title '" + chartTitle + "' with filledcurve y1=0 lt rgb \"#009000\"\n");
+       }
+
+       /**
+        * Get the units label for the given keys
+        * @param inMetric key if metric
+        * @param inImperial key if imperial
+        * @return display label with appropriate text
+        */
+       private static String getUnitsLabel(String inMetric, String inImperial)
+       {
+               String key = Config.getUseMetricUnits()?inMetric:inImperial;
+               return I18nManager.getText(key);
+       }
+
+
+       /**
+        * Calculate the distance values for each point in the given track
+        * @param inTrack track object
+        * @return distance values in a ChartSeries object
+        */
+       private static ChartSeries getDistanceValues(Track inTrack)
+       {
+               // Calculate distances and fill in in values array
+               ChartSeries values = new ChartSeries(inTrack.getNumPoints());
+               double totalRads = 0;
+               DataPoint prevPoint = null, currPoint = null;
+               for (int i=0; i<inTrack.getNumPoints(); i++)
+               {
+                       currPoint = inTrack.getPoint(i);
+                       if (prevPoint != null && !currPoint.isWaypoint() && !currPoint.getSegmentStart())
+                       {
+                               totalRads += DataPoint.calculateRadiansBetween(prevPoint, currPoint);
+                       }
+                       if (Config.getUseMetricUnits()) {
+                               values.setData(i, Distance.convertRadiansToDistance(totalRads, Units.KILOMETRES));
+                       } else {
+                               values.setData(i, Distance.convertRadiansToDistance(totalRads, Units.MILES));
+                       }
+                       prevPoint = currPoint;
+               }
+               return values;
+       }
+
+       /**
+        * Calculate the time values for each point in the given track
+        * @param inTrack track object
+        * @return time values in a ChartSeries object
+        */
+       private static ChartSeries getTimeValues(Track inTrack)
+       {
+               // Calculate times and fill in in values array
+               ChartSeries values = new ChartSeries(inTrack.getNumPoints());
+               double seconds = 0.0;
+               Timestamp prevTimestamp = null;
+               DataPoint currPoint = null;
+               for (int i=0; i<inTrack.getNumPoints(); i++)
+               {
+                       currPoint = inTrack.getPoint(i);
+                       if (currPoint.hasTimestamp())
+                       {
+                               if (!currPoint.getSegmentStart() && prevTimestamp != null) {
+                                       seconds += (currPoint.getTimestamp().getSecondsSince(prevTimestamp));
+                               }
+                               values.setData(i, seconds / 60.0 / 60.0);
+                               prevTimestamp = currPoint.getTimestamp();
+                       }
+               }
+               return values;
+       }
+
+       /**
+        * Calculate the altitude values for each point in the given track
+        * @param inTrack track object
+        * @return altitude values in a ChartSeries object
+        */
+       private static ChartSeries getAltitudeValues(Track inTrack)
+       {
+               ChartSeries values = new ChartSeries(inTrack.getNumPoints());
+               Altitude.Format altFormat = Config.getUseMetricUnits()?Altitude.Format.METRES:Altitude.Format.FEET;
+               for (int i=0; i<inTrack.getNumPoints(); i++) {
+                       if (inTrack.getPoint(i).hasAltitude()) {
+                               values.setData(i, inTrack.getPoint(i).getAltitude().getValue(altFormat));
+                       }
+               }
+               return values;
+       }
+
+       /**
+        * Calculate the speed values for each point in the given track
+        * @param inTrack track object
+        * @return speed values in a ChartSeries object
+        */
+       private static ChartSeries getSpeedValues(Track inTrack)
+       {
+               // Calculate speeds and fill in in values array
+               ChartSeries values = new ChartSeries(inTrack.getNumPoints());
+               DataPoint prevPoint = null, currPoint = null, nextPoint = null;
+               DataPoint[] points = getDataPoints(inTrack, false);
+               // Loop over collected points
+               for (int i=1; i<(points.length-1); i++)
+               {
+                       prevPoint = points[i-1];
+                       currPoint = points[i];
+                       nextPoint = points[i+1];
+                       if (prevPoint != null && currPoint != null && nextPoint != null
+                               && nextPoint.getTimestamp().isAfter(currPoint.getTimestamp())
+                               && currPoint.getTimestamp().isAfter(prevPoint.getTimestamp()))
+                       {
+                               // Calculate average speed between prevPoint and nextPoint
+                               double rads = DataPoint.calculateRadiansBetween(prevPoint, currPoint)
+                                       + DataPoint.calculateRadiansBetween(currPoint, nextPoint);
+                               double time = nextPoint.getTimestamp().getSecondsSince(prevPoint.getTimestamp()) / 60.0 / 60.0;
+                               // Convert to distance and pass to chartseries
+                               if (Config.getUseMetricUnits()) {
+                                       values.setData(i, Distance.convertRadiansToDistance(rads, Units.KILOMETRES) / time);
+                               } else {
+                                       values.setData(i, Distance.convertRadiansToDistance(rads, Units.MILES) / time);
+                               }
+                       }
+               }
+               return values;
+       }
+
+       /**
+        * Calculate the vertical speed values for each point in the given track
+        * @param inTrack track object
+        * @return vertical speed values in a ChartSeries object
+        */
+       private static ChartSeries getVertSpeedValues(Track inTrack)
+       {
+               // Calculate speeds and fill in in values array
+               ChartSeries values = new ChartSeries(inTrack.getNumPoints());
+               Altitude.Format altFormat = Config.getUseMetricUnits()?Altitude.Format.METRES:Altitude.Format.FEET;
+               DataPoint prevPoint = null, currPoint = null, nextPoint = null;
+               DataPoint[] points = getDataPoints(inTrack, true); // require that points have altitudes too
+               // Loop over collected points
+               for (int i=1; i<(points.length-1); i++)
+               {
+                       prevPoint = points[i-1];
+                       currPoint = points[i];
+                       nextPoint = points[i+1];
+                       if (prevPoint != null && currPoint != null && nextPoint != null
+                               && nextPoint.getTimestamp().isAfter(currPoint.getTimestamp())
+                               && currPoint.getTimestamp().isAfter(prevPoint.getTimestamp()))
+                       {
+                               // Calculate average vertical speed between prevPoint and nextPoint
+                               double vspeed = (nextPoint.getAltitude().getValue(altFormat) - prevPoint.getAltitude().getValue(altFormat))
+                                * 1.0 / nextPoint.getTimestamp().getSecondsSince(prevPoint.getTimestamp());
+                               values.setData(i, vspeed);
+                       }
+               }
+               return values;
+       }
+
+
+       /**
+        * Get an array of DataPoints with data for the charts
+        * @param inTrack track object containing points
+        * @param inRequireAltitudes true if only points with altitudes are considered
+        * @return array of points with contiguous non-null elements (<= size) with timestamps
+        */
+       private static DataPoint[] getDataPoints(Track inTrack, boolean inRequireAltitudes)
+       {
+               DataPoint[] points = new DataPoint[inTrack.getNumPoints()];
+               DataPoint currPoint = null;
+               int pointNum = 0;
+               // Loop over all points
+               for (int i=0; i<inTrack.getNumPoints(); i++)
+               {
+                       currPoint = inTrack.getPoint(i);
+                       if (currPoint != null && !currPoint.isWaypoint() && currPoint.hasTimestamp()
+                               && (!inRequireAltitudes || currPoint.hasAltitude()))
+                       {
+                               points[pointNum] = currPoint;
+                               pointNum++;
+                       }
+               }
+               // Any elements at the end of the array will stay null
+               // Also note, chronological order is not checked
+               return points;
+       }
+
+
+       /**
+        * Select a file to write for the SVG output
+        * @return
+        */
+       private File selectSvgFile()
+       {
+               if (_fileChooser == null)
+               {
+                       _fileChooser = new JFileChooser();
+                       _fileChooser.setDialogType(JFileChooser.SAVE_DIALOG);
+                       _fileChooser.setFileFilter(new GenericFileFilter("filetype.svg", new String[] {"svg"}));
+                       _fileChooser.setAcceptAllFileFilterUsed(false);
+                       // start from directory in config which should be set
+                       File configDir = Config.getWorkingDirectory();
+                       if (configDir != null) {_fileChooser.setCurrentDirectory(configDir);}
+               }
+               boolean chooseAgain = true;
+               while (chooseAgain)
+               {
+                       chooseAgain = false;
+                       if (_fileChooser.showSaveDialog(_parentFrame) == JFileChooser.APPROVE_OPTION)
+                       {
+                               // OK pressed and file chosen
+                               File file = _fileChooser.getSelectedFile();
+                               // Check file extension
+                               if (!file.getName().toLowerCase().endsWith(".svg")) {
+                                       file = new File(file.getAbsolutePath() + ".svg");
+                               }
+                               // Check if file exists and if necessary prompt for overwrite
+                               Object[] buttonTexts = {I18nManager.getText("button.overwrite"), I18nManager.getText("button.cancel")};
+                               if (!file.exists() || (file.canWrite() && JOptionPane.showOptionDialog(_parentFrame,
+                                               I18nManager.getText("dialog.save.overwrite.text"),
+                                               I18nManager.getText("dialog.save.overwrite.title"), JOptionPane.YES_NO_OPTION,
+                                               JOptionPane.WARNING_MESSAGE, null, buttonTexts, buttonTexts[1])
+                                       == JOptionPane.YES_OPTION))
+                               {
+                                       return file;
+                               }
+                               else {
+                                       chooseAgain = true;
+                               }
+                       }
+               }
+               // Cancel pressed so no file selected
+               return null;
+       }
+
+
+       /**
+        * @param inNumCharts number of charts to draw
+        * @return array of ints describing position and height of each subchart
+        */
+       private static int[] getHeights(int inNumCharts)
+       {
+               if (inNumCharts <= 1) {return new int[] {0, 100};}
+               if (inNumCharts == 2) {return new int[] {25, 75, 0, 25};}
+               if (inNumCharts == 3) {return new int[] {40, 60, 20, 20, 0, 20};}
+               return new int[] {54, 46, 36, 18, 18, 18, 0, 18};
+       }
+
+       /**
+        * Prompt the user to set/edit the path to gnuplot
+        */
+       private void setGnuplotPath()
+       {
+               String currPath = Config.getGnuplotPath();
+               Object path = JOptionPane.showInputDialog(_dialog,
+                       I18nManager.getText("dialog.charts.gnuplotpath"),
+                       I18nManager.getText(getNameKey()),
+                       JOptionPane.QUESTION_MESSAGE, null, null, "" + currPath);
+               if (path != null)
+               {
+                       String pathString = path.toString().trim();
+                       if (!pathString.equals("") && !pathString.equals(currPath)) {
+                               Config.setGnuplotPath(pathString);
+                               // warn if gnuplot still not found
+                               if (!ExternalTools.isGnuplotInstalled()) {
+                                       _app.showErrorMessage(getNameKey(), "dialog.charts.gnuplotnotfound");
+                               }
+                       }
+               }
+       }
+}
diff --git a/tim/prune/function/compress/ClosePointsAlgorithm.java b/tim/prune/function/compress/ClosePointsAlgorithm.java
new file mode 100644 (file)
index 0000000..69c3635
--- /dev/null
@@ -0,0 +1,107 @@
+package tim.prune.function.compress;
+
+import java.awt.Component;
+import java.awt.event.ActionListener;
+
+import tim.prune.data.DataPoint;
+import tim.prune.data.Track;
+
+/**
+ * Algorithm for detecting close points to compress
+ * Only checks distance to previous point, not any earlier point
+ */
+public class ClosePointsAlgorithm extends SingleParameterAlgorithm
+{
+
+       /**
+        * Constructor
+        * @param inTrack track object
+        * @param inDetails track details object
+        * @param inListener listener to attach to activation control
+        */
+       public ClosePointsAlgorithm(Track inTrack, TrackDetails inDetails, ActionListener inListener)
+       {
+               super(inTrack, inDetails, inListener);
+       }
+
+       /**
+        * Perform the compression and work out which points should be deleted
+        * @param inFlags deletion flags from previous algorithms
+        * @return number of points deleted
+        */
+       protected int compress(boolean[] inFlags)
+       {
+               // Parse parameter
+               double param = getParameter();
+               // Use 1/x if x greater than 1
+               if (param > 1.0) param = 1.0 / param;
+               if (param <= 0.0 || param >= 1.0) {
+                       // Parameter isn't valid, don't delete any
+                       return 0;
+               }
+               double threshold = _trackDetails.getTrackSpan() * param;
+
+               // Loop over all points checking distances to previous point
+               // TODO: Maybe this should also check distance to _next_ point as well!
+               int numPoints = _track.getNumPoints();
+               int prevPointIndex = 0;
+               int prevTrackPointIndex = 0;
+               double pointDist = 0.0;
+               int numDeleted = 0;
+               for (int i=1; i<numPoints; i++)
+               {
+                       // don't delete points already deleted
+                       if (!inFlags[i])
+                       {
+                               DataPoint currPoint = _track.getPoint(i);
+                               // Don't consider waypoints
+                               if (!currPoint.isWaypoint())
+                               {
+                                       // Don't delete any photo points or start/end of segments
+                                       if (currPoint.getPhoto() == null
+                                               && !_trackDetails.isSegmentStart(i) && !_trackDetails.isSegmentEnd(i))
+                                       {
+                                               // Check current point against prevPoint
+                                               pointDist = Math.abs(_track.getX(i) - _track.getX(prevPointIndex))
+                                                + Math.abs(_track.getY(i) - _track.getY(prevPointIndex));
+                                               if (pointDist < threshold) {
+                                                       inFlags[i] = true;
+                                                       numDeleted++;
+                                               }
+                                               else if (prevTrackPointIndex != prevPointIndex)
+                                               {
+                                                       // Check current point against prevTrackPoint
+                                                       pointDist = Math.abs(_track.getX(i) - _track.getX(prevTrackPointIndex))
+                                                        + Math.abs(_track.getY(i) - _track.getY(prevTrackPointIndex));
+                                                       if (pointDist < threshold) {
+                                                               inFlags[i] = true;
+                                                               numDeleted++;
+                                                       }
+                                               }
+                                       }
+                                       if (!inFlags[i]) {prevTrackPointIndex = i;}
+                               }
+                               if (!inFlags[i]) {prevPointIndex = i;}
+                       }
+               }
+               return numDeleted;
+       }
+
+
+       /**
+        * @return specific gui components for dialog
+        */
+       protected Component getSpecificGuiComponents()
+       {
+               return getSpecificGuiComponents("dialog.compress.closepoints.paramdesc", "200");
+       }
+
+       /**
+        * @return title key for box
+        */
+       protected String getTitleTextKey()
+       {
+               return "dialog.compress.closepoints.title";
+       }
+
+}
diff --git a/tim/prune/function/compress/CompressTrackFunction.java b/tim/prune/function/compress/CompressTrackFunction.java
new file mode 100644 (file)
index 0000000..865faeb
--- /dev/null
@@ -0,0 +1,182 @@
+package tim.prune.function.compress;
+
+import java.awt.BorderLayout;
+import java.awt.Dimension;
+import java.awt.FlowLayout;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+
+import javax.swing.BorderFactory;
+import javax.swing.Box;
+import javax.swing.BoxLayout;
+import javax.swing.JButton;
+import javax.swing.JDialog;
+import javax.swing.JPanel;
+
+import tim.prune.App;
+import tim.prune.GenericFunction;
+import tim.prune.I18nManager;
+import tim.prune.UpdateMessageBroker;
+import tim.prune.data.DataPoint;
+import tim.prune.data.Track;
+
+/**
+ * Class to provide the function for track compression
+ */
+public class CompressTrackFunction extends GenericFunction
+{
+       private Track _track = null;
+       private JDialog _dialog = null;
+       private JButton _okButton = null;
+       private CompressionAlgorithm[] _algorithms = null;
+       private SummaryLabel _summaryLabel = null;
+
+
+       /**
+        * Constructor
+        * @param inApp app object
+        */
+       public CompressTrackFunction(App inApp)
+       {
+               super(inApp);
+               _track = inApp.getTrackInfo().getTrack();
+               makeAlgorithms();
+       }
+
+       /** Get the name key */
+       public String getNameKey() {
+               return "function.compress";
+       }
+
+       /**
+        * Show the dialog to select compression parameters
+        */
+       public void begin()
+       {
+               // Make dialog window
+               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();
+               }
+               preview();
+               _dialog.setVisible(true);
+       }
+
+       /**
+        * Preview the compression by calling each algorithm in turn
+        * @return array of delete flags
+        */
+       private boolean[] preview()
+       {
+               // System.out.println("track dialog preview");
+               int numToDelete = 0;
+               boolean[] deleteFlags = new boolean[_track.getNumPoints()];
+               for (int i=0; i<_algorithms.length; i++)
+               {
+                       numToDelete += _algorithms[i].preview(deleteFlags);
+               }
+               _summaryLabel.setValue(numToDelete);
+               _okButton.setEnabled(numToDelete > 0);
+               return deleteFlags;
+       }
+
+
+       /**
+        * Create dialog components
+        * @return Panel containing all gui elements in dialog
+        */
+       private JPanel makeDialogComponents()
+       {
+               JPanel dialogPanel = new JPanel();
+               dialogPanel.setLayout(new BorderLayout());
+
+               // Make a central panel
+               JPanel mainPanel = new JPanel();
+               mainPanel.setLayout(new BoxLayout(mainPanel, BoxLayout.Y_AXIS));
+
+               // Add each of the algorithm components to the panel
+               for (int i=0; i<_algorithms.length; i++)
+               {
+                       mainPanel.add(_algorithms[i].getGuiComponents());
+                       mainPanel.add(Box.createRigidArea(new Dimension(0, 2)));
+               }
+               // Summary label below algorithms
+               JPanel summaryPanel = new JPanel();
+               _summaryLabel = new SummaryLabel(_track);
+               summaryPanel.add(_summaryLabel);
+               mainPanel.add(summaryPanel);
+               dialogPanel.add(mainPanel, BorderLayout.NORTH);
+
+               // button panel at bottom
+               JPanel buttonPanel = new JPanel();
+               buttonPanel.setLayout(new FlowLayout(FlowLayout.RIGHT));
+               _okButton = new JButton(I18nManager.getText("button.ok"));
+               _okButton.setEnabled(false);
+               ActionListener okListener = new ActionListener() {
+                       public void actionPerformed(ActionEvent e)
+                       {
+                               finish();
+                       }
+               };
+               _okButton.addActionListener(okListener);
+               buttonPanel.add(_okButton);
+               JButton cancelButton = new JButton(I18nManager.getText("button.cancel"));
+               cancelButton.addActionListener(new ActionListener() {
+                       public void actionPerformed(ActionEvent e)
+                       {
+                               _dialog.dispose();
+                       }
+               });
+               buttonPanel.add(cancelButton);
+               dialogPanel.add(buttonPanel, BorderLayout.SOUTH);
+               dialogPanel.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 15));
+               return dialogPanel;
+       }
+
+
+       /**
+        * Initialise all the algorithms to use
+        */
+       private void makeAlgorithms()
+       {
+               // make listener to be informed of algorithm activation
+               ActionListener changeListener = new ActionListener() {
+                       public void actionPerformed(ActionEvent arg0)
+                       {
+                               preview();
+                       };
+               };
+               // construct track details to be used by all algorithms
+               TrackDetails details = new TrackDetails(_track);
+               // make array of algorithm objects
+               _algorithms = new CompressionAlgorithm[] {
+                       new DuplicatePointAlgorithm(_track, details, changeListener),
+                       new ClosePointsAlgorithm(_track, details, changeListener),
+                       new WackyPointAlgorithm(_track, details, changeListener),
+                       new SingletonAlgorithm(_track, details, changeListener)
+               };
+       }
+
+
+       /**
+        * Finish the dialog when OK pressed
+        */
+       private void finish()
+       {
+               boolean[] deleteFlags = preview();
+               // All flags are now combined in deleteFlags array
+               for (int i=0; i<deleteFlags.length; i++)
+               {
+                       DataPoint point = _track.getPoint(i);
+                       point.setMarkedForDeletion(deleteFlags[i] && !point.isWaypoint() && point.getPhoto() == null);
+               }
+
+               // Close dialog and inform listeners
+               UpdateMessageBroker.informSubscribers();
+               _dialog.dispose();
+       }
+}
diff --git a/tim/prune/function/compress/CompressionAlgorithm.java b/tim/prune/function/compress/CompressionAlgorithm.java
new file mode 100644 (file)
index 0000000..cd1f9df
--- /dev/null
@@ -0,0 +1,108 @@
+package tim.prune.function.compress;
+
+import java.awt.BorderLayout;
+import java.awt.Component;
+import java.awt.event.ActionListener;
+
+import javax.swing.BorderFactory;
+import javax.swing.JCheckBox;
+import javax.swing.JPanel;
+
+import tim.prune.I18nManager;
+import tim.prune.data.Track;
+
+/**
+ * Abstract class to act as an algorithm for track compression
+ */
+public abstract class CompressionAlgorithm
+{
+       protected JCheckBox _activateCheckBox = null;
+       protected SummaryLabel _summaryLabel = null;
+       protected Track _track = null;
+       protected TrackDetails _trackDetails = null;
+
+
+       /**
+        * Constructor giving Track
+        * @param inTrack track object to use for compression
+        * @param inDetails track details object
+        * @param inListener listener to be informed of activation clicks
+        */
+       public CompressionAlgorithm(Track inTrack, TrackDetails inDetails,
+               ActionListener inListener)
+       {
+               _track = inTrack;
+               _trackDetails = inDetails;
+               _activateCheckBox = new JCheckBox(I18nManager.getText(getTitleTextKey()));
+               _activateCheckBox.setSelected(false);
+               _activateCheckBox.addActionListener(inListener);
+       }
+
+
+       /**
+        * @return true if this algorithm has been activated
+        */
+       public boolean isActivated()
+       {
+               return _activateCheckBox.isSelected();
+       }
+
+
+       /**
+        * @return JPanel containing gui components
+        */
+       public JPanel getGuiComponents()
+       {
+               JPanel panel = new JPanel();
+               panel.setBorder(BorderFactory.createTitledBorder(""));
+               panel.setLayout(new BorderLayout());
+               panel.add(_activateCheckBox, BorderLayout.NORTH);
+               Component specifics = getSpecificGuiComponents();
+               if (specifics != null) {
+                       panel.add(specifics, BorderLayout.CENTER);
+               }
+               // Add label at bottom
+               _summaryLabel = new SummaryLabel(_track);
+               panel.add(_summaryLabel, BorderLayout.SOUTH);
+               return panel;
+       }
+
+       /**
+        * Preview the algorithm by counting the number of points deleted
+        * @param inFlags array of deletion flags from previous algorithms
+        * @return number of points to be deleted by this algorithm
+        */
+       public int preview(boolean[] inFlags)
+       {
+               int numDeleted = 0;
+               if (isActivated())
+               {
+                       // Run the compression and set the deletion flags
+                       numDeleted = compress(inFlags);
+                       _summaryLabel.setValue(numDeleted);
+               }
+               else {
+                       _summaryLabel.clearValue();
+               }
+               return numDeleted;
+       }
+
+
+       /**
+        * @return key to use for title text of algorithm
+        */
+       protected abstract String getTitleTextKey();
+
+       /**
+        * @return gui components controlling algorithm (if any)
+        */
+       protected abstract Component getSpecificGuiComponents();
+
+       /**
+        * Perform the compression and set the results in the given array
+        * @param inFlags deletion flags from previous algorithms
+        * @return number of points deleted by this algorithm
+        */
+       protected abstract int compress(boolean[] inFlags);
+
+}
diff --git a/tim/prune/function/compress/DuplicatePointAlgorithm.java b/tim/prune/function/compress/DuplicatePointAlgorithm.java
new file mode 100644 (file)
index 0000000..3fd2233
--- /dev/null
@@ -0,0 +1,82 @@
+package tim.prune.function.compress;
+
+import java.awt.Component;
+import java.awt.event.ActionListener;
+
+import tim.prune.data.DataPoint;
+import tim.prune.data.Track;
+
+/**
+ * Algorithm for detecting duplicate points to compress
+ */
+public class DuplicatePointAlgorithm extends CompressionAlgorithm
+{
+       /** Number of points before this one to consider as duplicates */
+       private static final int NUM_POINTS_TO_BACKTRACK = 20;
+
+       /**
+        * Constructor
+        * @param inTrack track object
+        * @param inDetails track details object
+        * @param inListener listener to attach to activation control
+        */
+       public DuplicatePointAlgorithm(Track inTrack, TrackDetails inDetails, ActionListener inListener)
+       {
+               super(inTrack, inDetails, inListener);
+       }
+
+       /**
+        * Perform the compression and work out which points should be deleted
+        * @param inFlags deletion flags from previous algorithms
+        * @return number of points deleted
+        */
+       protected int compress(boolean[] inFlags)
+       {
+               int numPoints = _track.getNumPoints();
+               int numDeleted = 0;
+               // Loop over all points looking for duplicates
+               for (int i=1; i<numPoints; i++)
+               {
+                       // Don't delete points which are already marked as deleted
+                       if (!inFlags[i])
+                       {
+                               DataPoint currPoint = _track.getPoint(i);
+                               // Don't delete any waypoints or photo points
+                               if (!currPoint.isWaypoint() && currPoint.getPhoto() == null)
+                               {
+                                       // loop over last few points before this one
+                                       for (int j=i-NUM_POINTS_TO_BACKTRACK; j<i; j++)
+                                       {
+                                               if (j<0) {j=0;} // only look at last few points, but not before 0
+                                               if (currPoint.isDuplicate(_track.getPoint(j)))
+                                               {
+                                                       inFlags[i] = true;
+                                                       numDeleted++;
+                                                       break;
+                                               }
+                                       }
+                               }
+                       }
+               }
+               return numDeleted;
+       }
+
+
+       /**
+        * @return specific gui components for dialog
+        */
+       protected Component getSpecificGuiComponents()
+       {
+               // no parameters to set, so no gui components
+               return null;
+       }
+
+       /**
+        * @return title key for box
+        */
+       protected String getTitleTextKey()
+       {
+               return "dialog.compress.duplicates.title";
+       }
+
+}
diff --git a/tim/prune/function/compress/SingleParameterAlgorithm.java b/tim/prune/function/compress/SingleParameterAlgorithm.java
new file mode 100644 (file)
index 0000000..fbf0ccf
--- /dev/null
@@ -0,0 +1,86 @@
+package tim.prune.function.compress;
+
+import java.awt.Component;
+import java.awt.GridLayout;
+import java.awt.event.ActionListener;
+import java.awt.event.KeyListener;
+
+import javax.swing.JLabel;
+import javax.swing.JPanel;
+import javax.swing.JTextField;
+import javax.swing.SwingConstants;
+
+import tim.prune.I18nManager;
+import tim.prune.data.Track;
+
+/**
+ * Superclass for compression algorithms with a single text field parameter
+ */
+public abstract class SingleParameterAlgorithm extends CompressionAlgorithm
+{
+       /** Text field for entering parameter */
+       private JTextField _parameterField = null;
+       /** Listener from parent dialog */
+       private ActionListener _listener = null;
+
+
+       /**
+        * Constructor
+        * @param inTrack track object
+        * @param inDetails track details object
+        * @param inListener listener to attach to activation control
+        */
+       public SingleParameterAlgorithm(Track inTrack, TrackDetails inDetails, ActionListener inListener)
+       {
+               super(inTrack, inDetails, inListener);
+               _listener = inListener;
+               _parameterField = new JTextField();
+               // Add listener to parameter field to re-run preview (and en/disable ok) when param changed
+               _parameterField.addKeyListener(new KeyListener() {
+                       public void keyTyped(java.awt.event.KeyEvent arg0) {};
+                       public void keyPressed(java.awt.event.KeyEvent arg0) {};
+                       public void keyReleased(java.awt.event.KeyEvent arg0) {if (isActivated()) _listener.actionPerformed(null);};
+               });
+       }
+
+       /**
+        * @return specific gui components for dialog
+        * @param inLabelKey key for label
+        * @param inParamValue initial value of parameter
+        */
+       protected Component getSpecificGuiComponents(String inLabelKey, String inParamValue)
+       {
+               // Create panel with label and text field
+               JPanel panel = new JPanel();
+               panel.setLayout(new GridLayout(0, 2));
+               JLabel label = new JLabel(I18nManager.getText(inLabelKey) + " : ");
+               label.setHorizontalAlignment(SwingConstants.RIGHT);
+               panel.add(label);
+               panel.add(_parameterField);
+               _parameterField.setText(inParamValue);
+               return panel;
+       }
+
+       /**
+        * Parse the text field to get parameter
+        * @return parameter given as double
+        */
+       protected double getParameter()
+       {
+               double param = 0.0;
+               try {
+                       // Parse from string
+                       param = Double.parseDouble(_parameterField.getText());
+               }
+               catch (NumberFormatException nfe) {} // ignore, param stays zero
+               return param;
+       }
+
+       /**
+        * @return the text field component
+        */
+       protected JTextField getTextField()
+       {
+               return _parameterField;
+       }
+}
diff --git a/tim/prune/function/compress/SingletonAlgorithm.java b/tim/prune/function/compress/SingletonAlgorithm.java
new file mode 100644 (file)
index 0000000..7a61d1c
--- /dev/null
@@ -0,0 +1,86 @@
+package tim.prune.function.compress;
+
+import java.awt.Component;
+import java.awt.event.ActionListener;
+
+import tim.prune.data.DataPoint;
+import tim.prune.data.Track;
+
+/**
+ * Algorithm for detecting singleton points to compress
+ */
+public class SingletonAlgorithm extends SingleParameterAlgorithm
+{
+       /**
+        * Constructor
+        * @param inTrack track object
+        * @param inDetails track details object
+        * @param inListener listener to attach to activation control
+        */
+       public SingletonAlgorithm(Track inTrack, TrackDetails inDetails, ActionListener inListener)
+       {
+               super(inTrack, inDetails, inListener);
+       }
+
+       /**
+        * Perform the compression and work out which points should be deleted
+        * @param inFlags deletion flags from previous algorithms
+        * @return number of points deleted
+        */
+       protected int compress(boolean[] inFlags)
+       {
+               double param = getParameter();
+               if (param <= 0.0) return 0;
+               // System.out.println("Singleton algorithm compressing : " + param + ", " + _trackDetails.getMeanRadians());
+               int numPoints = _track.getNumPoints();
+               int numDeleted = 0;
+               double threshold = param * _trackDetails.getMeanRadians();
+               DataPoint currPoint = null, prevPoint = null;
+               // Loop over all points looking for points far away from neighbours
+               for (int i=0; i<numPoints; i++)
+               {
+                       currPoint = _track.getPoint(i);
+                       // Don't delete points which are already marked as deleted
+                       if (!inFlags[i])
+                       {
+                               // Don't delete any waypoints or photo points
+                               // Only interested in start and end of segments
+                               if (!currPoint.isWaypoint() && currPoint.getPhoto() == null
+                                       && _trackDetails.isSegmentStart(i) && _trackDetails.isSegmentEnd(i))
+                               {
+                                       // Measure distance from previous track point
+                                       if (DataPoint.calculateRadiansBetween(prevPoint, currPoint) > threshold)
+                                       {
+                                               // Now need to find next track point, and measure distances
+                                               DataPoint nextPoint = _track.getNextTrackPoint(i+1);
+                                               if (nextPoint != null && DataPoint.calculateRadiansBetween(currPoint, nextPoint) > threshold)
+                                               {
+                                                       // Found a point to delete (hope that next point hasn't been deleted already)
+                                                       inFlags[i] = true;
+                                                       numDeleted++;
+                                               }
+                                       }
+                               }
+                               // Remember last (not-deleted) track point
+                               if (!currPoint.isWaypoint()) {prevPoint = currPoint;}
+                       }
+               }
+               return numDeleted;
+       }
+
+       /**
+        * @return specific gui components for dialog
+        */
+       protected Component getSpecificGuiComponents()
+       {
+               return getSpecificGuiComponents("dialog.compress.singletons.paramdesc", "2");
+       }
+
+       /**
+        * @return title key for box
+        */
+       protected String getTitleTextKey()
+       {
+               return "dialog.compress.singletons.title";
+       }
+}
diff --git a/tim/prune/function/compress/SummaryLabel.java b/tim/prune/function/compress/SummaryLabel.java
new file mode 100644 (file)
index 0000000..57f8ad1
--- /dev/null
@@ -0,0 +1,62 @@
+package tim.prune.function.compress;
+
+import javax.swing.JLabel;
+
+import tim.prune.I18nManager;
+import tim.prune.data.Track;
+
+/**
+ * Summary label for compression
+ */
+public class SummaryLabel extends JLabel
+{
+       /** Track object */
+       private Track _track = null;
+
+
+       /**
+        * Constructor
+        * @param inTrack track object to work out percentages
+        */
+       public SummaryLabel(Track inTrack)
+       {
+               super("...........................");
+               setEnabled(false);
+               _track = inTrack;
+       }
+
+       /**
+        * Set value
+        * @param inNumToDelete number of points to delete
+        */
+       public void setValue(int inNumToDelete)
+       {
+               setText(makeString(inNumToDelete));
+               setEnabled(true);
+       }
+
+       /**
+        * Clear value
+        */
+       public void clearValue()
+       {
+               setText(makeString(0));
+               setEnabled(false);
+       }
+
+       /**
+        * Make a string describing the deletion
+        * @param inNumToDelete number of points to delete
+        * @return String describing number and %age
+        */
+       private String makeString(int inNumToDelete)
+       {
+               String desc = I18nManager.getText("dialog.compress.summarylabel") + ": " + inNumToDelete;
+               if (inNumToDelete > 0)
+               {
+                       long percent = Math.round(100.0 * inNumToDelete / _track.getNumPoints());
+                       desc += " (" + percent + "%)";
+               }
+               return desc;
+       }
+}
diff --git a/tim/prune/function/compress/TrackDetails.java b/tim/prune/function/compress/TrackDetails.java
new file mode 100644 (file)
index 0000000..b218861
--- /dev/null
@@ -0,0 +1,120 @@
+package tim.prune.function.compress;
+
+import tim.prune.data.DataPoint;
+import tim.prune.data.Track;
+
+/**
+ * Class to hold details about a track
+ * which might be useful for compression
+ */
+public class TrackDetails
+{
+       /** Track object */
+       private Track _track = null;
+       /** Range span */
+       private double _trackSpan = -1.0;
+       /** Markers for start of segment */
+       private boolean[] _segmentStarts = null;
+       /** Markers for end of segment */
+       private boolean[] _segmentEnds = null;
+       /** Mean distance between track points in radians */
+       private double _meanRadians = 0.0;
+
+
+       /**
+        * Constructor
+        * @param inTrack track object
+        */
+       public TrackDetails(Track inTrack)
+       {
+               _track = inTrack;
+       }
+
+       /**
+        * Recalculate all details
+        */
+       public void initialise()
+       {
+               // calculate track span
+               double xRange = _track.getXRange().getRange();
+               double yRange = _track.getYRange().getRange();
+               _trackSpan = (xRange > yRange ? xRange : yRange);
+
+               // Calculate segment starts / ends
+               int numPoints = _track.getNumPoints();
+               _segmentStarts = new boolean[numPoints];
+               _segmentEnds = new boolean[numPoints];
+               int prevTrackPointIndex = -1;
+               int numDistances = 0; double totalRadians = 0.0;
+               // Loop over points
+               for (int i=0; i<numPoints; i++)
+               {
+                       DataPoint point = _track.getPoint(i);
+                       if (!point.isWaypoint())
+                       {
+                               // track point, check for segment flag
+                               if (point.getSegmentStart())
+                               {
+                                       // set start of segment and end of previous
+                                       _segmentStarts[i] = true;
+                                       if (prevTrackPointIndex >= 0) {
+                                               _segmentEnds[prevTrackPointIndex] = true;
+                                       }
+                               }
+                               else {
+                                       // Add up distances between points within the same track segment
+                                       if (prevTrackPointIndex >= 0) {
+                                               numDistances++;
+                                               totalRadians += DataPoint.calculateRadiansBetween(_track.getPoint(prevTrackPointIndex), point);
+                                       }
+                               }
+                               prevTrackPointIndex = i;
+                       }
+               }
+               // last segment
+               _segmentEnds[prevTrackPointIndex] = true;
+               // Mean radians between points
+               _meanRadians = totalRadians / numDistances;
+       }
+
+
+       /**
+        * @return the track span
+        */
+       public double getTrackSpan()
+       {
+               if (_trackSpan < 0.0) {initialise();}
+               return _trackSpan;
+       }
+
+       /**
+        * @param inPointIndex index of point to check
+        * @return true if specified point is start of segment
+        */
+       public boolean isSegmentStart(int inPointIndex)
+       {
+               if (_segmentStarts == null ||
+                       _segmentStarts.length != _track.getNumPoints()) {initialise();}
+               return _segmentStarts[inPointIndex];
+       }
+
+       /**
+        * @param inPointIndex index of point to check
+        * @return true if specified point is end of segment
+        */
+       public boolean isSegmentEnd(int inPointIndex)
+       {
+               if (_segmentEnds == null ||
+                       _segmentEnds.length != _track.getNumPoints()) {initialise();}
+               return _segmentEnds[inPointIndex];
+       }
+
+       /**
+        * @return mean radians between adjacent track points
+        */
+       public double getMeanRadians()
+       {
+               if (_meanRadians == 0.0) {initialise();}
+               return _meanRadians;
+       }
+}
diff --git a/tim/prune/function/compress/WackyPointAlgorithm.java b/tim/prune/function/compress/WackyPointAlgorithm.java
new file mode 100644 (file)
index 0000000..d7b5b9f
--- /dev/null
@@ -0,0 +1,86 @@
+package tim.prune.function.compress;
+
+import java.awt.Component;
+import java.awt.event.ActionListener;
+
+import tim.prune.data.DataPoint;
+import tim.prune.data.Track;
+
+/**
+ * Algorithm for detecting wacky points to compress
+ */
+public class WackyPointAlgorithm extends SingleParameterAlgorithm
+{
+       /**
+        * Constructor
+        * @param inTrack track object
+        * @param inDetails track details object
+        * @param inListener listener to attach to activation control
+        */
+       public WackyPointAlgorithm(Track inTrack, TrackDetails inDetails, ActionListener inListener)
+       {
+               super(inTrack, inDetails, inListener);
+       }
+
+       /**
+        * Perform the compression and work out which points should be deleted
+        * @param inFlags deletion flags from previous algorithms
+        * @return number of points deleted
+        */
+       protected int compress(boolean[] inFlags)
+       {
+               double param = getParameter();
+               if (param <= 0.0) return 0;
+               int numPoints = _track.getNumPoints();
+               int numDeleted = 0;
+               double threshold = param * _trackDetails.getMeanRadians();
+               DataPoint currPoint = null, prevPoint = null;
+               // Loop over all points looking for points far away from neighbours
+               for (int i=0; i<numPoints; i++)
+               {
+                       currPoint = _track.getPoint(i);
+                       // Don't delete points which are already marked as deleted
+                       if (!inFlags[i])
+                       {
+                               // Don't delete any waypoints or photo points, or start/end of segments
+                               if (!currPoint.isWaypoint() && currPoint.getPhoto() == null
+                                       && !_trackDetails.isSegmentStart(i) && !_trackDetails.isSegmentEnd(i))
+                               {
+                                       // Measure distance from previous track point
+                                       if (DataPoint.calculateRadiansBetween(prevPoint, currPoint) > threshold)
+                                       {
+                                               // Now need to find next track point, and measure distances
+                                               DataPoint nextPoint = _track.getNextTrackPoint(i+1);
+                                               if (nextPoint != null && DataPoint.calculateRadiansBetween(currPoint, nextPoint) > threshold
+                                                       && DataPoint.calculateRadiansBetween(prevPoint, nextPoint) < threshold)
+                                               {
+                                                       // Found a point to delete (hope that next point hasn't been deleted already)
+                                                       inFlags[i] = true;
+                                                       numDeleted++;
+                                               }
+                                       }
+                               }
+                               // Remember last (not-deleted) track point
+                               if (!currPoint.isWaypoint()) {prevPoint = currPoint;}
+                       }
+               }
+               return numDeleted;
+       }
+
+       /**
+        * @return specific gui components for dialog
+        */
+       protected Component getSpecificGuiComponents()
+       {
+               return getSpecificGuiComponents("dialog.compress.wackypoints.paramdesc", "2");
+       }
+
+       /**
+        * @return title key for box
+        */
+       protected String getTitleTextKey()
+       {
+               return "dialog.compress.wackypoints.title";
+       }
+
+}
diff --git a/tim/prune/function/distance/DistanceFunction.java b/tim/prune/function/distance/DistanceFunction.java
new file mode 100644 (file)
index 0000000..b41ab8b
--- /dev/null
@@ -0,0 +1,153 @@
+package tim.prune.function.distance;
+
+import java.awt.BorderLayout;
+import java.awt.Component;
+import java.awt.Dimension;
+import java.awt.FlowLayout;
+import java.awt.GridLayout;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.util.ArrayList;
+
+import javax.swing.BorderFactory;
+import javax.swing.JButton;
+import javax.swing.JDialog;
+import javax.swing.JLabel;
+import javax.swing.JPanel;
+import javax.swing.JScrollPane;
+import javax.swing.JTable;
+import javax.swing.event.ListSelectionEvent;
+import javax.swing.event.ListSelectionListener;
+
+import tim.prune.App;
+import tim.prune.GenericFunction;
+import tim.prune.I18nManager;
+import tim.prune.data.DataPoint;
+import tim.prune.data.TrackInfo;
+
+/**
+ * Class to provide the distance measuring function between waypoints
+ */
+public class DistanceFunction extends GenericFunction
+{
+       /** Dialog */
+       private JDialog _dialog = null;
+       /** Table for 'from' point selection */
+       private JTable _pointTable = null;
+       /** Model for 'from' table */
+       private FromTableModel _fromModel = null;
+       /** Model for distance table */
+       private DistanceTableModel _distModel = null;
+
+
+       /**
+        * Constructor
+        * @param inApp App object
+        */
+       public DistanceFunction(App inApp)
+       {
+               super(inApp);
+       }
+
+       /** Get the name key */
+       public String getNameKey() {
+               return "function.distances";
+       }
+
+       /**
+        * 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();
+               }
+               ArrayList<DataPoint> pointList = getPointList(_app.getTrackInfo());
+               // Check if point list has size at least 2
+               if (pointList.size() < 2) {
+                       _app.showErrorMessage(getNameKey(), "dialog.distances.toofewpoints");
+                       return;
+               }
+               _fromModel.init(pointList);
+               _distModel.init(pointList);
+               _pointTable.getSelectionModel().setSelectionInterval(0, 0);
+               _distModel.recalculate(0);
+               _dialog.setVisible(true);
+       }
+
+       /**
+        * Create dialog components
+        * @return Panel containing all gui elements in dialog
+        */
+       private Component makeDialogComponents()
+       {
+               JPanel dialogPanel = new JPanel();
+               dialogPanel.setLayout(new BorderLayout(5, 5));
+               // Label at top
+               JLabel topLabel = new JLabel(I18nManager.getText("dialog.distances.intro"));
+               topLabel.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
+               dialogPanel.add(topLabel, BorderLayout.NORTH);
+
+               JPanel mainPanel = new JPanel();
+               mainPanel.setLayout(new GridLayout(1, 2));
+               // First table for 'from point'
+               _fromModel = new FromTableModel();
+               _pointTable = new JTable(_fromModel);
+               _pointTable.getSelectionModel().addListSelectionListener(new ListSelectionListener() {
+                       /** selection changed */
+                       public void valueChanged(ListSelectionEvent e) {
+                               if (!e.getValueIsAdjusting()) {
+                                       _distModel.recalculate(_pointTable.getSelectedRow());
+                               }
+                       }
+               });
+               JScrollPane scrollPane = new JScrollPane(_pointTable);
+               scrollPane.setPreferredSize(new Dimension(100, 250));
+               mainPanel.add(scrollPane);
+               // second table for distances
+               _distModel = new DistanceTableModel();
+               JTable distTable = new JTable(_distModel);
+               distTable.setAutoCreateRowSorter(true);
+               scrollPane = new JScrollPane(distTable);
+               scrollPane.setPreferredSize(new Dimension(200, 250));
+               mainPanel.add(scrollPane);
+               dialogPanel.add(mainPanel, BorderLayout.CENTER);
+
+               // button panel at bottom
+               JPanel buttonPanel = new JPanel();
+               buttonPanel.setLayout(new FlowLayout(FlowLayout.RIGHT));
+               JButton closeButton = new JButton(I18nManager.getText("button.close"));
+               closeButton.addActionListener(new ActionListener() {
+                       public void actionPerformed(ActionEvent e)
+                       {
+                               _dialog.dispose();
+                       }
+               });
+               buttonPanel.add(closeButton);
+               dialogPanel.add(buttonPanel, BorderLayout.SOUTH);
+               return dialogPanel;
+       }
+
+       /**
+        * Get the point list for the tables
+        * @param inTrackInfo TrackInfo object
+        */
+       private static ArrayList<DataPoint> getPointList(TrackInfo inTrackInfo)
+       {
+               // Get the list of waypoints (if any)
+               ArrayList<DataPoint> pointList = new ArrayList<DataPoint>();
+               inTrackInfo.getTrack().getWaypoints(pointList);
+               // Get the current point (if any)
+               DataPoint currPoint = inTrackInfo.getCurrentPoint();
+               if (currPoint != null && !currPoint.isWaypoint()) {
+                       // Add current point to start of list
+                       pointList.add(0, currPoint);
+               }
+               return pointList;
+       }
+}
diff --git a/tim/prune/function/distance/DistanceTableModel.java b/tim/prune/function/distance/DistanceTableModel.java
new file mode 100644 (file)
index 0000000..8adbf69
--- /dev/null
@@ -0,0 +1,108 @@
+package tim.prune.function.distance;
+
+import tim.prune.Config;
+import tim.prune.I18nManager;
+import tim.prune.data.DataPoint;
+import tim.prune.data.Distance;
+
+/**
+ * Class to hold the table model for the distances table
+ */
+public class DistanceTableModel extends GenericTableModel
+{
+       /** Distances */
+       private double[] _distances = null;
+       /** Metric distances? */
+       private boolean _useMetric = true;
+       /** Previous value of metric flag (to spot changes) */
+       private boolean _prevUseMetric = false;
+       /** Column heading */
+       private static final String _toColLabel = I18nManager.getText("dialog.distances.column.to");
+       /** Column heading (depends on metric/imperial settings) */
+       private String _distanceLabel = null;
+
+       /**
+        * @return column count
+        */
+       public int getColumnCount()
+       {
+               return 2;
+       }
+
+       /**
+        * @param inRowIndex row index
+        * @param inColumnIndex column index
+        * @return cell value
+        */
+       public Object getValueAt(int inRowIndex, int inColumnIndex)
+       {
+               if (inColumnIndex == 0) {return getPointName(inRowIndex);}
+               if (_distances == null) {return 0.0;}
+               return new Double(_distances[inRowIndex]);
+       }
+
+       /**
+        * @param inColumnIndex column index
+        * @return column name
+        */
+       public String getColumnName(int inColumnIndex)
+       {
+               if (inColumnIndex == 0) {return _toColLabel;}
+               return _distanceLabel;
+       }
+
+       /**
+        * Get the column class (required for sorting)
+        * @param inColumnIndex column index
+        * @return Class of specified column
+        */
+       public Class<?> getColumnClass(int inColumnIndex)
+       {
+               if (inColumnIndex == 0) return String.class;
+               return Double.class;
+       }
+
+       /**
+        * Recalculate the distances
+        * @param inIndex index of selected 'from' point
+        */
+       public void recalculate(int inIndex)
+       {
+               // Use metric or not?
+               _useMetric = Config.getUseMetricUnits();
+               _distanceLabel = getDistanceLabel(_useMetric);
+               // Initialize array of distances
+               int numRows = getRowCount();
+               if (_distances == null || _distances.length != numRows) {
+                       _distances = new double[numRows];
+               }
+               DataPoint fromPoint = _pointList.get(inIndex);
+               for (int i=0; i<numRows; i++) {
+                       if (i == inIndex) {
+                               _distances[i] = 0.0;
+                       }
+                       else {
+                               double rads = DataPoint.calculateRadiansBetween(fromPoint, _pointList.get(i));
+                               _distances[i] = Distance.convertRadiansToDistance(rads, _useMetric?Distance.Units.KILOMETRES:Distance.Units.MILES);
+                       }
+               }
+               // Let table know that it has to refresh data (and maybe refresh column headings too)
+               if (_useMetric == _prevUseMetric) {
+                       fireTableDataChanged();
+               }
+               else {
+                       fireTableStructureChanged();
+               }
+               _prevUseMetric = _useMetric;
+       }
+
+       /**
+        * @param inMetric true to use metric distances
+        * @return distance label for column heading
+        */
+       private static String getDistanceLabel(boolean inMetric)
+       {
+               return I18nManager.getText("fieldname.distance") + " (" +
+                       I18nManager.getText(inMetric?"units.kilometres.short" : "units.miles.short") + ")";
+       }
+}
diff --git a/tim/prune/function/distance/FromTableModel.java b/tim/prune/function/distance/FromTableModel.java
new file mode 100644 (file)
index 0000000..c88bfc4
--- /dev/null
@@ -0,0 +1,36 @@
+package tim.prune.function.distance;
+
+import tim.prune.I18nManager;
+
+/**
+ * Class to hold table model for "From" list of distance function
+ */
+public class FromTableModel extends GenericTableModel
+{
+       /** Column heading */
+       private static final String _colLabel = I18nManager.getText("dialog.distances.column.from");
+
+       /**
+        * @return column count
+        */
+       public int getColumnCount() {
+               return 1;
+       }
+
+       /**
+        * @param inRowIndex row index
+        * @param inColumnIndex column index
+        * @return cell value
+        */
+       public Object getValueAt(int inRowIndex, int inColumnIndex) {
+               return getPointName(inRowIndex);
+       }
+
+       /**
+        * @param inColumnIndex column index
+        * @return column name
+        */
+       public String getColumnName(int inColumnIndex) {
+               return _colLabel;
+       }
+}
diff --git a/tim/prune/function/distance/GenericTableModel.java b/tim/prune/function/distance/GenericTableModel.java
new file mode 100644 (file)
index 0000000..bc56540
--- /dev/null
@@ -0,0 +1,50 @@
+package tim.prune.function.distance;
+
+import java.util.ArrayList;
+
+import javax.swing.table.AbstractTableModel;
+
+import tim.prune.I18nManager;
+import tim.prune.data.DataPoint;
+
+/**
+ * General table model class for the two models in the distance function
+ */
+public abstract class GenericTableModel extends AbstractTableModel
+{
+       /** list of points */
+       protected ArrayList<DataPoint> _pointList = null;
+       /** Column heading */
+       private static String _currPointLabel = I18nManager.getText("dialog.distances.currentpoint");
+
+       /**
+        * Initialize the table model with the point list
+        * @param inPointList list of points
+        */
+       public void init(ArrayList<DataPoint> inPointList)
+       {
+               _pointList = inPointList;
+       }
+
+       /**
+        * @return row count
+        */
+       public int getRowCount()
+       {
+               if (_pointList == null) {return 0;}
+               return _pointList.size();
+       }
+
+       /**
+        * Get the name of the specified point from the list
+        * @param inIndex index of point
+        * @return waypoint name if waypoint, otherwise "current point"
+        */
+       protected String getPointName(int inIndex)
+       {
+               if (_pointList == null) {return "null";}
+               DataPoint point = _pointList.get(inIndex);
+               if (point.isWaypoint()) {return point.getWaypointName();}
+               return _currPointLabel;
+       }
+}
similarity index 97%
rename from tim/prune/edit/EditFieldsTableModel.java
rename to tim/prune/function/edit/EditFieldsTableModel.java
index fb4a86bf77d9cd0f04f78f50dc6ada65a234a7bf..f4ee5617b22cf7eb3a77d7783b93c3901ebeab22 100644 (file)
@@ -1,4 +1,4 @@
-package tim.prune.edit;
+package tim.prune.function.edit;
 
 import javax.swing.table.AbstractTableModel;
 
@@ -98,7 +98,7 @@ public class EditFieldsTableModel extends AbstractTableModel
        /**
         * @return Class of cell data
         */
-       public Class getColumnClass(int inColumnIndex)
+       public Class<?> getColumnClass(int inColumnIndex)
        {
                if (inColumnIndex <= 1) return String.class;
                return Boolean.class;
similarity index 94%
rename from tim/prune/edit/FieldEdit.java
rename to tim/prune/function/edit/FieldEdit.java
index 5877ab1799a1851e785c5c46a4284c0b3f04fa69..41f38b3c145f266611fb619b0b57e6d0ba7264f4 100644 (file)
@@ -1,4 +1,4 @@
-package tim.prune.edit;
+package tim.prune.function.edit;
 
 import tim.prune.data.Field;
 
similarity index 79%
rename from tim/prune/edit/FieldEditList.java
rename to tim/prune/function/edit/FieldEditList.java
index 70bd26331126816b73f40557a65379c64e0d3ba4..8612e8ae5f9eec2cbabe20243f565be9fa7d4924 100644 (file)
@@ -1,4 +1,4 @@
-package tim.prune.edit;
+package tim.prune.function.edit;
 
 import java.util.ArrayList;
 
@@ -7,7 +7,7 @@ import java.util.ArrayList;
  */
 public class FieldEditList
 {
-       private ArrayList _editList = new ArrayList();
+       private ArrayList<FieldEdit> _editList = new ArrayList<FieldEdit>();
 
 
        /**
@@ -35,6 +35,6 @@ public class FieldEditList
         */
        public FieldEdit getEdit(int inIndex)
        {
-               return (FieldEdit) _editList.get(inIndex);
+               return _editList.get(inIndex);
        }
 }
similarity index 98%
rename from tim/prune/edit/PointEditor.java
rename to tim/prune/function/edit/PointEditor.java
index ea67a0a041ebd053bd4f43631e1c3a9c8e2bc453..6808e6a98837c4b692457a0b3940545c388a0481 100644 (file)
@@ -1,4 +1,4 @@
-package tim.prune.edit;
+package tim.prune.function.edit;
 
 import java.awt.BorderLayout;
 import java.awt.Component;
@@ -78,7 +78,7 @@ public class PointEditor
                // Create Gui and show it
                _dialog.getContentPane().add(makeDialogComponents());
                _dialog.pack();
-               _dialog.show();
+               _dialog.setVisible(true);
        }
 
 
similarity index 81%
rename from tim/prune/edit/PointNameEditor.java
rename to tim/prune/function/edit/PointNameEditor.java
index 3229bc29a00653f778315942b0cccb4849fb2d10..19edfbb80ba37c3f35ae291089a22079f0040693 100644 (file)
@@ -1,4 +1,4 @@
-package tim.prune.edit;
+package tim.prune.function.edit;
 
 import java.awt.Component;
 import java.awt.BorderLayout;
@@ -53,23 +53,26 @@ public class PointNameEditor
        public void showDialog(DataPoint inPoint)
        {
                _point = inPoint;
-               _dialog = new JDialog(_parentFrame, I18nManager.getText("dialog.pointnameedit.title"), true);
-               _dialog.setLocationRelativeTo(_parentFrame);
+               if (_dialog == null)
+               {
+                       _dialog = new JDialog(_parentFrame, I18nManager.getText("dialog.pointnameedit.title"), true);
+                       _dialog.setLocationRelativeTo(_parentFrame);
+                       // Create Gui and show it
+                       _dialog.getContentPane().add(makeDialogComponents());
+                       _dialog.pack();
+               }
                // Check current waypoint name, if any
                String name = _point.getWaypointName();
-               // Create Gui and show it
-               _dialog.getContentPane().add(makeDialogComponents(name));
-               _dialog.pack();
-               _dialog.show();
+               resetDialog(name);
+               _dialog.setVisible(true);
        }
 
 
        /**
         * Make the dialog components
-        * @param inName initial name of point
         * @return the GUI components for the dialog
         */
-       private Component makeDialogComponents(String inName)
+       private Component makeDialogComponents()
        {
                JPanel panel = new JPanel();
                panel.setLayout(new BorderLayout());
@@ -80,16 +83,12 @@ public class PointNameEditor
                ActionListener okActionListener = new ActionListener() {
                        public void actionPerformed(ActionEvent e)
                        {
-                               // Check for empty name
-                               if (_nameField.getText().length() > 0)
-                               {
-                                       // update App with edit
-                                       confirmEdit();
-                                       _dialog.dispose();
-                               }
+                               // update App with edit
+                               confirmEdit();
+                               _dialog.dispose();
                        }
                };
-               _nameField = new JTextField(inName, 12);
+               _nameField = new JTextField("", 12);
                _nameField.addKeyListener(new KeyAdapter() {
                        public void keyReleased(KeyEvent e)
                        {
@@ -98,8 +97,8 @@ public class PointNameEditor
                                {
                                        _dialog.dispose();
                                }
-                               // Enable ok button if name not empty
-                               _okButton.setEnabled(_nameField.getText().length() > 0);
+                               // Enable ok button if name changed
+                               _okButton.setEnabled(hasNameChanged());
                        }
                });
                _nameField.addActionListener(okActionListener);
@@ -158,6 +157,16 @@ public class PointNameEditor
        }
 
 
+       /**
+        * Reset the dialog with the given name
+        * @param inName waypoint name
+        */
+       private void resetDialog(String inName)
+       {
+               _nameField.setText(inName);
+               _okButton.setEnabled(false);
+       }
+
        /**
         * Turn a String into sentence case by capitalizing each word
         * @param inString String to convert
@@ -189,22 +198,31 @@ public class PointNameEditor
        private void confirmEdit()
        {
                // Check whether name has really changed
-               String prevName = _point.getWaypointName();
-               String newName = _nameField.getText().trim();
-               boolean prevNull = (prevName == null || prevName.equals(""));
-               boolean newNull = (newName == null || newName.equals(""));
-               if ( (prevNull && !newNull)
-                       || (!prevNull && newNull)
-                       || (!prevNull && !newNull && !prevName.equals(newName)) )
+               if (hasNameChanged())
                {
                        // Make lists for edit and undo, and add the changed field
                        FieldEditList editList = new FieldEditList();
                        FieldEditList undoList = new FieldEditList();
-                       editList.addEdit(new FieldEdit(Field.WAYPT_NAME, newName));
-                       undoList.addEdit(new FieldEdit(Field.WAYPT_NAME, prevName));
+                       editList.addEdit(new FieldEdit(Field.WAYPT_NAME, _nameField.getText().trim()));
+                       undoList.addEdit(new FieldEdit(Field.WAYPT_NAME, _point.getWaypointName()));
 
                        // Pass back to App to perform edit
                        _app.completePointEdit(editList, undoList);
                }
        }
+
+       /**
+        * Check whether the name has been changed or not
+        * @return true if the new name is different
+        */
+       private boolean hasNameChanged()
+       {
+               String prevName = _point.getWaypointName();
+               String newName = _nameField.getText().trim();
+               boolean prevNull = (prevName == null || prevName.equals(""));
+               boolean newNull = (newName == null || newName.equals(""));
+               return (prevNull && !newNull)
+                       || (!prevNull && newNull)
+                       || (!prevNull && !newNull && !prevName.equals(newName));
+       }
 }
index e153a6cead5feb9dca2a776559e9f163130b3d16..2703c1b0c8924d168546b399f0b94067f8ee2fd2 100644 (file)
@@ -25,7 +25,6 @@ import tim.prune.data.DataPoint;
 import tim.prune.data.Distance;
 import tim.prune.data.IntegerRange;
 import tim.prune.data.Photo;
-import tim.prune.data.PhotoStatus;
 import tim.prune.data.Selection;
 import tim.prune.data.TrackInfo;
 
@@ -75,7 +74,7 @@ public class DetailsDisplay extends GenericDisplay
        private static final String LABEL_RANGE_CLIMB = I18nManager.getText("details.range.climb") + ": ";
        private static final String LABEL_RANGE_DESCENT = ", " + I18nManager.getText("details.range.descent") + ": ";
        private static String LABEL_POINT_ALTITUDE_UNITS = null;
-       private static int LABEL_POINT_ALTITUDE_FORMAT = Altitude.FORMAT_NONE;
+       private static Altitude.Format LABEL_POINT_ALTITUDE_FORMAT = Altitude.Format.NO_FORMAT;
 
 
        /**
@@ -202,6 +201,7 @@ public class DetailsDisplay extends GenericDisplay
                        public void actionPerformed(ActionEvent e)
                        {
                                dataUpdated(DataSubscriber.UNITS_CHANGED);
+                               Config.setUseMetricUnits(_distUnitsDropdown.getSelectedIndex() == 0);
                        }
                });
                lowerPanel.add(_distUnitsDropdown);
@@ -221,7 +221,7 @@ public class DetailsDisplay extends GenericDisplay
                Selection selection = _trackInfo.getSelection();
                int currentPointIndex = selection.getCurrentPointIndex();
                _speedLabel.setText("");
-               int distUnits = _distUnitsDropdown.getSelectedIndex()==0?Distance.UNITS_KILOMETRES:Distance.UNITS_MILES;
+               Distance.Units distUnits = _distUnitsDropdown.getSelectedIndex()==0?Distance.Units.KILOMETRES:Distance.Units.MILES;
                String distUnitsStr = I18nManager.getText(_distUnitsDropdown.getSelectedIndex()==0?"units.kilometres.short":"units.miles.short");
                String speedUnitsStr = I18nManager.getText(_distUnitsDropdown.getSelectedIndex()==0?"units.kmh":"units.mph");
                if (_track == null || currentPoint == null)
@@ -252,12 +252,13 @@ public class DetailsDisplay extends GenericDisplay
                                        {
                                                // use total distance and total time between neighbouring points
                                                long diff = nextPoint.getTimestamp().getSecondsSince(prevPoint.getTimestamp());
-                                               if (diff < 1000) {
+                                               if (diff < 1000 && diff > 0)
+                                               {
                                                        double rads = DataPoint.calculateRadiansBetween(prevPoint, currentPoint) +
                                                                DataPoint.calculateRadiansBetween(currentPoint, nextPoint);
                                                        double dist = Distance.convertRadiansToDistance(rads, distUnits);
                                                        String speed = roundedNumber(3600 * dist / diff) + " " + speedUnitsStr;
-                                                       _speedLabel.setText(I18nManager.getText("details.speed") + ": " + speed);
+                                                       _speedLabel.setText(I18nManager.getText("fieldname.speed") + ": " + speed);
                                                }
                                        }
                                }
@@ -339,7 +340,7 @@ public class DetailsDisplay extends GenericDisplay
                        _photoLabel.setText(I18nManager.getText("details.photofile") + ": " + currentPhoto.getFile().getName());
                        _photoLabel.setText(LABEL_POINT_TIMESTAMP + currentPhoto.getTimestamp().getText());
                        _photoConnectedLabel.setText(I18nManager.getText("details.photo.connected") + ": "
-                               + (currentPhoto.getCurrentStatus() == PhotoStatus.NOT_CONNECTED ?
+                               + (currentPhoto.getCurrentStatus() == Photo.Status.NOT_CONNECTED ?
                                        I18nManager.getText("dialog.about.no"):I18nManager.getText("dialog.about.yes")));
                        _photoThumbnail.setVisible(true);
                        _photoThumbnail.setPhoto(currentPhoto);
@@ -353,12 +354,12 @@ public class DetailsDisplay extends GenericDisplay
         * @param inFormat altitude format
         * @return language-sensitive string
         */
-       private static String getAltitudeUnitsLabel(int inFormat)
+       private static String getAltitudeUnitsLabel(Altitude.Format inFormat)
        {
                if (inFormat == LABEL_POINT_ALTITUDE_FORMAT && LABEL_POINT_ALTITUDE_UNITS != null)
                        return LABEL_POINT_ALTITUDE_UNITS;
                LABEL_POINT_ALTITUDE_FORMAT = inFormat;
-               if (inFormat == Altitude.FORMAT_METRES)
+               if (inFormat == Altitude.Format.METRES)
                        return " " + I18nManager.getText("units.metres.short");
                return " " + I18nManager.getText("units.feet.short");
        }
index 71455eb7ac386cee9bdaa2ab6899bb93ba83b002..731b91c47221b26959751d8e39a3db1f47d3d8d2 100644 (file)
@@ -44,26 +44,29 @@ public abstract class GenericChart extends GenericDisplay implements MouseListen
 
        /**
         * Override paint method to draw map
+        * @param inG graphics object
         */
-       public void paint(Graphics g)
+       public void paint(Graphics inG)
        {
-               super.paint(g);
+               super.paint(inG);
                int width = getWidth();
                int height = getHeight();
                // border background
-               g.setColor(COLOR_BORDER_BG);
-               g.fillRect(0, 0, width, height);
+               inG.setColor(COLOR_BORDER_BG);
+               inG.fillRect(0, 0, width, height);
                if (width < 2*BORDER_WIDTH || height < 2*BORDER_WIDTH) return;
                // blank graph area, with line border
-               g.setColor(COLOR_CHART_BG);
-               g.fillRect(BORDER_WIDTH, BORDER_WIDTH, width - 2*BORDER_WIDTH, height-2*BORDER_WIDTH);
-               g.setColor(COLOR_CHART_LINE);
-               g.drawRect(BORDER_WIDTH, BORDER_WIDTH, width - 2*BORDER_WIDTH, height-2*BORDER_WIDTH);
+               inG.setColor(COLOR_CHART_BG);
+               inG.fillRect(BORDER_WIDTH, BORDER_WIDTH, width - 2*BORDER_WIDTH, height-2*BORDER_WIDTH);
                // Display message if no data to be displayed
                if (_track == null || _track.getNumPoints() <= 0)
                {
-                       g.setColor(COLOR_NODATA_TEXT);
-                       g.drawString(I18nManager.getText("display.nodata"), 50, height/2);
+                       inG.setColor(COLOR_NODATA_TEXT);
+                       inG.drawString(I18nManager.getText("display.nodata"), 50, height/2);
+               }
+               else {
+                       inG.setColor(COLOR_CHART_LINE);
+                       inG.drawRect(BORDER_WIDTH, BORDER_WIDTH, width - 2*BORDER_WIDTH, height-2*BORDER_WIDTH);
                }
        }
 
index e1c8cf0da6470dff921d1329621eaf3cc4807734..7b256ba74248463e8877f3fa7218fdd2dd9135f5 100644 (file)
@@ -5,7 +5,6 @@ import java.awt.event.ActionListener;
 import java.awt.event.InputEvent;
 import java.awt.event.KeyEvent;
 import javax.swing.JButton;
-import javax.swing.JFrame;
 import javax.swing.JMenu;
 import javax.swing.JMenuBar;
 import javax.swing.JMenuItem;
@@ -14,12 +13,15 @@ import javax.swing.KeyStroke;
 
 import tim.prune.App;
 import tim.prune.DataSubscriber;
+import tim.prune.FunctionLibrary;
+import tim.prune.GenericFunction;
 import tim.prune.I18nManager;
-import tim.prune.browser.UrlGenerator;
 import tim.prune.data.PhotoList;
 import tim.prune.data.Selection;
 import tim.prune.data.Track;
 import tim.prune.data.TrackInfo;
+import tim.prune.function.RearrangeWaypointsFunction.Rearrange;
+import tim.prune.function.browser.UrlGenerator;
 
 /**
  * Class to manage the menu bar and tool bar,
@@ -27,13 +29,13 @@ import tim.prune.data.TrackInfo;
  */
 public class MenuManager implements DataSubscriber
 {
-       private JFrame _parent = null;
        private App _app = null;
        private Track _track = null;
        private Selection _selection = null;
        private PhotoList _photos = null;
 
        // Menu items which need enabling/disabling
+       private JMenuItem _sendGpsItem = null;
        private JMenuItem _saveItem = null;
        private JMenuItem _exportKmlItem = null;
        private JMenuItem _exportGpxItem = null;
@@ -44,9 +46,10 @@ public class MenuManager implements DataSubscriber
        private JMenuItem _editWaypointNameItem = null;
        private JMenuItem _deletePointItem = null;
        private JMenuItem _deleteRangeItem = null;
-       private JMenuItem _deleteDuplicatesItem = null;
        private JMenuItem _compressItem = null;
+       private JMenuItem _deleteMarkedPointsItem = null;
        private JMenuItem _interpolateItem = null;
+       private JMenuItem _averageItem = null;
        private JMenuItem _selectAllItem = null;
        private JMenuItem _selectNoneItem = null;
        private JMenuItem _selectStartItem = null;
@@ -58,6 +61,8 @@ public class MenuManager implements DataSubscriber
        private JMenuItem _cutAndMoveItem = null;
        private JMenuItem _show3dItem = null;
        private JMenu     _browserMapMenu = null;
+       private JMenuItem _chartItem = null;
+       private JMenuItem _distanceItem = null;
        private JMenuItem _saveExifItem = null;
        private JMenuItem _connectPhotoItem = null;
        private JMenuItem _deletePhotoItem = null;
@@ -89,13 +94,11 @@ public class MenuManager implements DataSubscriber
 
        /**
         * Constructor
-        * @param inParent parent object for dialogs
         * @param inApp application to call on menu actions
         * @param inTrackInfo track info object
         */
-       public MenuManager(JFrame inParent, App inApp, TrackInfo inTrackInfo)
+       public MenuManager(App inApp, TrackInfo inTrackInfo)
        {
-               _parent = inParent;
                _app = inApp;
                _track = inTrackInfo.getTrack();
                _selection = inTrackInfo.getSelection();
@@ -132,15 +135,26 @@ public class MenuManager implements DataSubscriber
                };
                addPhotosMenuItem.addActionListener(_addPhotoAction);
                fileMenu.add(addPhotosMenuItem);
-               // Add photos
-               JMenuItem loadFromGpsMenuItem = new JMenuItem(I18nManager.getText("menu.file.loadfromgps"));
+               fileMenu.addSeparator();
+               // Load from GPS
+               JMenuItem loadFromGpsMenuItem = makeMenuItem(FunctionLibrary.FUNCTION_GPSLOAD);
                loadFromGpsMenuItem.addActionListener(new ActionListener() {
                        public void actionPerformed(ActionEvent e)
                        {
-                               _app.beginLoadFromGps();
+                               FunctionLibrary.FUNCTION_GPSLOAD.begin();
                        }
                });
                fileMenu.add(loadFromGpsMenuItem);
+               // Save to GPS
+               _sendGpsItem = makeMenuItem(FunctionLibrary.FUNCTION_GPSSAVE);
+               _sendGpsItem.addActionListener(new ActionListener() {
+                       public void actionPerformed(ActionEvent e)
+                       {
+                               FunctionLibrary.FUNCTION_GPSSAVE.begin();
+                       }
+               });
+               _sendGpsItem.setEnabled(false);
+               fileMenu.add(_sendGpsItem);
                fileMenu.addSeparator();
                // Save
                _saveItem = new JMenuItem(I18nManager.getText("menu.file.save"), KeyEvent.VK_S);
@@ -154,31 +168,31 @@ public class MenuManager implements DataSubscriber
                _saveItem.setEnabled(false);
                fileMenu.add(_saveItem);
                // Export - Kml
-               _exportKmlItem = new JMenuItem(I18nManager.getText("menu.file.exportkml"));
+               _exportKmlItem = makeMenuItem(FunctionLibrary.FUNCTION_KMLEXPORT);
                _exportKmlItem.addActionListener(new ActionListener() {
                        public void actionPerformed(ActionEvent e)
                        {
-                               _app.exportKml();
+                               FunctionLibrary.FUNCTION_KMLEXPORT.begin();
                        }
                });
                _exportKmlItem.setEnabled(false);
                fileMenu.add(_exportKmlItem);
                // Gpx
-               _exportGpxItem = new JMenuItem(I18nManager.getText("menu.file.exportgpx"));
+               _exportGpxItem = makeMenuItem(FunctionLibrary.FUNCTION_GPXEXPORT);
                _exportGpxItem.addActionListener(new ActionListener() {
                        public void actionPerformed(ActionEvent e)
                        {
-                               _app.exportGpx();
+                               FunctionLibrary.FUNCTION_GPXEXPORT.begin();
                        }
                });
                _exportGpxItem.setEnabled(false);
                fileMenu.add(_exportGpxItem);
                // Pov
-               _exportPovItem = new JMenuItem(I18nManager.getText("menu.file.exportpov"));
+               _exportPovItem = makeMenuItem(FunctionLibrary.FUNCTION_POVEXPORT);
                _exportPovItem.addActionListener(new ActionListener() {
                        public void actionPerformed(ActionEvent e)
                        {
-                               _app.exportPov();
+                               FunctionLibrary.FUNCTION_POVEXPORT.begin();
                        }
                });
                _exportPovItem.setEnabled(false);
@@ -255,24 +269,25 @@ public class MenuManager implements DataSubscriber
                _deleteRangeItem.addActionListener(_deleteRangeAction);
                _deleteRangeItem.setEnabled(false);
                editMenu.add(_deleteRangeItem);
-               _deleteDuplicatesItem = new JMenuItem(I18nManager.getText("menu.edit.deleteduplicates"));
-               _deleteDuplicatesItem.addActionListener(new ActionListener() {
+               editMenu.addSeparator();
+               _compressItem = makeMenuItem(FunctionLibrary.FUNCTION_COMPRESS);
+               _compressItem.addActionListener(new ActionListener() {
                        public void actionPerformed(ActionEvent e)
                        {
-                               _app.deleteDuplicates();
+                               FunctionLibrary.FUNCTION_COMPRESS.begin();
                        }
                });
-               _deleteDuplicatesItem.setEnabled(false);
-               editMenu.add(_deleteDuplicatesItem);
-               _compressItem = new JMenuItem(I18nManager.getText("menu.edit.compress"));
-               _compressItem.addActionListener(new ActionListener() {
+               _compressItem.setEnabled(false);
+               editMenu.add(_compressItem);
+               _deleteMarkedPointsItem = new JMenuItem(I18nManager.getText("menu.edit.deletemarked"));
+               _deleteMarkedPointsItem.addActionListener(new ActionListener() {
                        public void actionPerformed(ActionEvent e)
                        {
-                               _app.compressTrack();
+                               _app.finishCompressTrack();
                        }
                });
-               _compressItem.setEnabled(false);
-               editMenu.add(_compressItem);
+               _deleteMarkedPointsItem.setEnabled(false);
+               editMenu.add(_deleteMarkedPointsItem);
                editMenu.addSeparator();
                _interpolateItem = new JMenuItem(I18nManager.getText("menu.edit.interpolate"));
                _interpolateItem.addActionListener(new ActionListener() {
@@ -283,6 +298,15 @@ public class MenuManager implements DataSubscriber
                });
                _interpolateItem.setEnabled(false);
                editMenu.add(_interpolateItem);
+               _averageItem = new JMenuItem(I18nManager.getText("menu.edit.average"));
+               _averageItem.addActionListener(new ActionListener() {
+                       public void actionPerformed(ActionEvent e)
+                       {
+                               _app.averageSelection();
+                       }
+               });
+               _averageItem.setEnabled(false);
+               editMenu.add(_averageItem);
                _reverseItem = new JMenuItem(I18nManager.getText("menu.edit.reverse"));
                _reverseItem.addActionListener(new ActionListener() {
                        public void actionPerformed(ActionEvent e)
@@ -292,11 +316,11 @@ public class MenuManager implements DataSubscriber
                });
                _reverseItem.setEnabled(false);
                editMenu.add(_reverseItem);
-               _addTimeOffsetItem = new JMenuItem(I18nManager.getText("menu.edit.addtimeoffset"));
+               _addTimeOffsetItem = makeMenuItem(FunctionLibrary.FUNCTION_ADD_TIME_OFFSET);
                _addTimeOffsetItem.addActionListener(new ActionListener() {
                        public void actionPerformed(ActionEvent e)
                        {
-                               _app.beginAddTimeOffset();
+                               FunctionLibrary.FUNCTION_ADD_TIME_OFFSET.begin();
                        }
                });
                _addTimeOffsetItem.setEnabled(false);
@@ -317,7 +341,7 @@ public class MenuManager implements DataSubscriber
                rearrangeStartItem.addActionListener(new ActionListener() {
                        public void actionPerformed(ActionEvent e)
                        {
-                               _app.rearrangeWaypoints(App.REARRANGE_TO_START);
+                               FunctionLibrary.FUNCTION_REARRANGE_WAYPOINTS.rearrangeWaypoints(Rearrange.TO_START);
                        }
                });
                rearrangeStartItem.setEnabled(true);
@@ -326,7 +350,7 @@ public class MenuManager implements DataSubscriber
                rearrangeEndItem.addActionListener(new ActionListener() {
                        public void actionPerformed(ActionEvent e)
                        {
-                               _app.rearrangeWaypoints(App.REARRANGE_TO_END);
+                               FunctionLibrary.FUNCTION_REARRANGE_WAYPOINTS.rearrangeWaypoints(Rearrange.TO_END);
                        }
                });
                rearrangeEndItem.setEnabled(true);
@@ -335,7 +359,7 @@ public class MenuManager implements DataSubscriber
                rearrangeNearestItem.addActionListener(new ActionListener() {
                        public void actionPerformed(ActionEvent e)
                        {
-                               _app.rearrangeWaypoints(App.REARRANGE_TO_NEAREST);
+                               FunctionLibrary.FUNCTION_REARRANGE_WAYPOINTS.rearrangeWaypoints(Rearrange.TO_NEAREST);
                        }
                });
                rearrangeNearestItem.setEnabled(true);
@@ -397,11 +421,11 @@ public class MenuManager implements DataSubscriber
 
                // Add view menu
                JMenu viewMenu = new JMenu(I18nManager.getText("menu.view"));
-               _show3dItem = new JMenuItem(I18nManager.getText("menu.view.show3d"));
+               _show3dItem = makeMenuItem(FunctionLibrary.FUNCTION_3D);
                _show3dItem.addActionListener(new ActionListener() {
                        public void actionPerformed(ActionEvent e)
                        {
-                               _app.show3dWindow();
+                               FunctionLibrary.FUNCTION_3D.begin();
                        }
                });
                _show3dItem.setEnabled(false);
@@ -425,7 +449,50 @@ public class MenuManager implements DataSubscriber
                        }
                });
                _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);
                viewMenu.add(_browserMapMenu);
+               // Charts
+               _chartItem = makeMenuItem(FunctionLibrary.FUNCTION_CHARTS);
+               _chartItem.addActionListener(new ActionListener() {
+                       public void actionPerformed(ActionEvent e)
+                       {
+                               FunctionLibrary.FUNCTION_CHARTS.begin();
+                       }
+               });
+               _chartItem.setEnabled(false);
+               viewMenu.add(_chartItem);
+               // Distances
+               _distanceItem = makeMenuItem(FunctionLibrary.FUNCTION_DISTANCES);
+               _distanceItem.setEnabled(false);
+               _distanceItem.addActionListener(new ActionListener() {
+                       public void actionPerformed(ActionEvent e) {
+                               FunctionLibrary.FUNCTION_DISTANCES.begin();
+                       }
+               });
+               viewMenu.add(_distanceItem);
+               // Set the map background
+               JMenuItem mapBgItem = makeMenuItem(FunctionLibrary.FUNCTION_SET_MAP_BG);
+               mapBgItem.addActionListener(new ActionListener() {
+                       public void actionPerformed(ActionEvent arg0) {
+                               FunctionLibrary.FUNCTION_SET_MAP_BG.begin();
+                       }
+               });
+               viewMenu.add(mapBgItem);
                menubar.add(viewMenu);
 
                // Add photo menu
@@ -474,11 +541,11 @@ public class MenuManager implements DataSubscriber
                photoMenu.add(_deletePhotoItem);
                photoMenu.addSeparator();
                // correlate all photos
-               _correlatePhotosItem = new JMenuItem(I18nManager.getText("menu.photo.correlate"));
+               _correlatePhotosItem = makeMenuItem(FunctionLibrary.FUNCTION_CORRELATE_PHOTOS);
                _correlatePhotosItem.addActionListener(new ActionListener() {
                        public void actionPerformed(ActionEvent e)
                        {
-                               _app.beginCorrelatePhotos();
+                               FunctionLibrary.FUNCTION_CORRELATE_PHOTOS.begin();
                        }
                });
                _correlatePhotosItem.setEnabled(false);
@@ -487,27 +554,27 @@ public class MenuManager implements DataSubscriber
 
                // Help menu
                JMenu helpMenu = new JMenu(I18nManager.getText("menu.help"));
-               JMenuItem helpItem = new JMenuItem(I18nManager.getText("menu.help"));
+               JMenuItem helpItem = makeMenuItem(FunctionLibrary.FUNCTION_HELP);
                helpItem.addActionListener(new ActionListener() {
                        public void actionPerformed(ActionEvent e)
                        {
-                               _app.showHelp();
+                               FunctionLibrary.FUNCTION_HELP.begin();
                        }
                });
                helpMenu.add(helpItem);
-               JMenuItem aboutItem = new JMenuItem(I18nManager.getText("menu.help.about"));
+               JMenuItem aboutItem = makeMenuItem(FunctionLibrary.FUNCTION_ABOUT);
                aboutItem.addActionListener(new ActionListener() {
                        public void actionPerformed(ActionEvent e)
                        {
-                               new AboutScreen(_parent).show();
+                               FunctionLibrary.FUNCTION_ABOUT.begin();
                        }
                });
                helpMenu.add(aboutItem);
-               JMenuItem checkVersionItem = new JMenuItem(I18nManager.getText("menu.help.checkversion"));
+               JMenuItem checkVersionItem = makeMenuItem(FunctionLibrary.FUNCTION_CHECK_VERSION);
                checkVersionItem.addActionListener(new ActionListener() {
                        public void actionPerformed(ActionEvent e)
                        {
-                               CheckVersionScreen.show(_parent);
+                               FunctionLibrary.FUNCTION_CHECK_VERSION.begin();
                        }
                });
                helpMenu.add(checkVersionItem);
@@ -516,6 +583,15 @@ public class MenuManager implements DataSubscriber
                return menubar;
        }
 
+       /**
+        * Convenience method for making a menu item using a function
+        * @param inFunction function
+        * @return menu item using localized name of function
+        */
+       private static JMenuItem makeMenuItem(GenericFunction inFunction)
+       {
+               return new JMenuItem(I18nManager.getText(inFunction.getNameKey()));
+       }
 
        /**
         * Create a JToolBar containing all toolbar buttons
@@ -592,10 +668,11 @@ public class MenuManager implements DataSubscriber
        public void informFileLoaded()
        {
                // save, undo, delete enabled
+               _sendGpsItem.setEnabled(true);
                _saveItem.setEnabled(true);
                _undoItem.setEnabled(true);
-               _deleteDuplicatesItem.setEnabled(true);
                _compressItem.setEnabled(true);
+               _deleteMarkedPointsItem.setEnabled(false);
        }
 
 
@@ -606,19 +683,21 @@ public class MenuManager implements DataSubscriber
        {
                boolean hasData = (_track != null && _track.getNumPoints() > 0);
                // set functions which require data
+               _sendGpsItem.setEnabled(hasData);
                _saveItem.setEnabled(hasData);
                _saveButton.setEnabled(hasData);
                _exportKmlItem.setEnabled(hasData);
                _exportGpxItem.setEnabled(hasData);
                _exportPovItem.setEnabled(hasData);
-               _deleteDuplicatesItem.setEnabled(hasData);
                _compressItem.setEnabled(hasData);
+               _deleteMarkedPointsItem.setEnabled(hasData && _track.hasMarkedPoints());
                _rearrangeMenu.setEnabled(hasData && _track.hasMixedData());
                _selectAllItem.setEnabled(hasData);
                _selectNoneItem.setEnabled(hasData);
-               if (_show3dItem != null)
-                       _show3dItem.setEnabled(hasData);
+               _show3dItem.setEnabled(hasData);
+               _chartItem.setEnabled(hasData);
                _browserMapMenu.setEnabled(hasData);
+               _distanceItem.setEnabled(hasData);
                // is undo available?
                boolean hasUndo = !_app.getUndoStack().isEmpty();
                _undoItem.setEnabled(hasUndo);
@@ -655,6 +734,7 @@ public class MenuManager implements DataSubscriber
                _deleteRangeButton.setEnabled(hasRange);
                _interpolateItem.setEnabled(hasRange
                        && (_selection.getEnd() - _selection.getStart()) == 1);
+               _averageItem.setEnabled(hasRange);
                _mergeSegmentsItem.setEnabled(hasRange);
                _reverseItem.setEnabled(hasRange);
                _addTimeOffsetItem.setEnabled(hasRange);
index 629389150c8170ed47c872d89d037728b7adfd7e..2ad22fa3a36e00be8979a2b23281490211e7618f 100644 (file)
@@ -21,7 +21,8 @@ public class PhotoThumbnail extends JPanel implements Runnable
        private int _lastWidth = -1;
        private int _lastHeight = -1;
        private boolean _loadingImage = false;
-       private static String _loadingString = null;
+       /** String to show before photo is loaded */
+       private static final String _loadingString = I18nManager.getText("details.photo.loading") + " ...";
 
 
        /**
@@ -31,7 +32,6 @@ public class PhotoThumbnail extends JPanel implements Runnable
        {
                // TODO: Make size of thumbnail dynamic, as big as it can be
                setOpaque(true);
-               _loadingString = I18nManager.getText("details.photo.loading") + " ...";
        }
 
 
index 22724b5f6a431d674396f626393e6c8d2ca1d464..a0adfdbe33b74424ce6432eb8be2e20c052f1cf3 100644 (file)
@@ -6,6 +6,7 @@ import java.awt.Graphics;
 import java.awt.event.MouseEvent;
 
 import tim.prune.I18nManager;
+import tim.prune.data.Altitude;
 import tim.prune.data.AltitudeRange;
 import tim.prune.data.Track;
 import tim.prune.data.TrackInfo;
@@ -86,28 +87,33 @@ public class ProfileChart extends GenericChart
                                }
                        }
 
-                       // loop through points
-                       int chartFormat = altitudeRange.getFormat();
-                       for (int p = 0; p < numPoints; p++)
+                       try
                        {
-                               int x = (int) (_xScaleFactor * p);
-                               if (p == selectedPoint)
+                               // loop through points
+                               Altitude.Format chartFormat = altitudeRange.getFormat();
+                               for (int p = 0; p < numPoints; p++)
                                {
-                                       g.setColor(COLOR_SELECTED_BG);
-                                       g.fillRect(BORDER_WIDTH + x, BORDER_WIDTH+1, barWidth, height-2*BORDER_WIDTH-2);
-                                       g.setColor(COLOR_SELECTED);
-                               }
-                               else
-                               {
-                                       g.setColor(COLOR_ALT_BARS);
-                               }
-                               if (_track.getPoint(p).getAltitude().isValid())
-                               {
-                                       altitude = _track.getPoint(p).getAltitude().getValue(chartFormat);
-                                       y = (int) (yScaleFactor * (altitude - minAltitude));
-                                       g.fillRect(BORDER_WIDTH+x, height-BORDER_WIDTH - y, barWidth, y);
+                                       int x = (int) (_xScaleFactor * p);
+                                       if (p == selectedPoint)
+                                       {
+                                               g.setColor(COLOR_SELECTED_BG);
+                                               g.fillRect(BORDER_WIDTH + x, BORDER_WIDTH+1, barWidth, height-2*BORDER_WIDTH-2);
+                                               g.setColor(COLOR_SELECTED);
+                                       }
+                                       else
+                                       {
+                                               g.setColor(COLOR_ALT_BARS);
+                                       }
+                                       if (_track.getPoint(p).getAltitude().isValid())
+                                       {
+                                               altitude = _track.getPoint(p).getAltitude().getValue(chartFormat);
+                                               y = (int) (yScaleFactor * (altitude - minAltitude));
+                                               g.fillRect(BORDER_WIDTH+x, height-BORDER_WIDTH - y, barWidth, y);
+                                       }
                                }
                        }
+                       catch (NullPointerException npe) { // ignore, probably due to data being changed
+                       }
                        // Draw numbers on top of the graph to mark scale
                        if (lineScale > 1)
                        {
index 46a1c8d9de834f231b7a48f4607d33144665d2c5..1b77fe151136ea8254f60622639a6823ec2c2bd9 100644 (file)
@@ -44,13 +44,13 @@ public class UndoManager
                JPanel mainPanel = new JPanel();
                mainPanel.setLayout(new BorderLayout(3, 3));
                mainPanel.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
-               Stack undoStack = inApp.getUndoStack();
+               Stack<UndoOperation> undoStack = inApp.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] = ((UndoOperation) undoStack.elementAt(undoStack.size()-1-i)).getDescription();
+                       undoActions[i] = undoStack.elementAt(undoStack.size()-1-i).getDescription();
                }
                _actionList = new JList(undoActions);
                _actionList.setSelectionMode(ListSelectionModel.SINGLE_INTERVAL_SELECTION);
@@ -91,7 +91,7 @@ public class UndoManager
                mainPanel.add(buttonPanel, BorderLayout.SOUTH);
                _dialog.getContentPane().add(mainPanel);
                _dialog.pack();
-               _dialog.show();
+               _dialog.setVisible(true);
        }
 
 }
index 10f16a95af7d808891cca2ed247d00fdfb1b5f11..cbab59cbfa162446e4fb5c305adf4d7c8ec55e2e 100644 (file)
@@ -12,7 +12,7 @@ import tim.prune.data.Track;
 public class WaypointListModel extends AbstractListModel
 {
        Track _track = null;
-       ArrayList _waypoints = null;
+       ArrayList<DataPoint> _waypoints = null;
 
        /**
         * Constructor giving Track object
@@ -21,7 +21,7 @@ public class WaypointListModel extends AbstractListModel
        public WaypointListModel(Track inTrack)
        {
                _track = inTrack;
-               _waypoints = new ArrayList();
+               _waypoints = new ArrayList<DataPoint>();
                _track.getWaypoints(_waypoints);
        }
 
@@ -38,7 +38,7 @@ public class WaypointListModel extends AbstractListModel
         */
        public Object getElementAt(int inIndex)
        {
-               return ((DataPoint)_waypoints.get(inIndex)).getWaypointName();
+               return _waypoints.get(inIndex).getWaypointName();
        }
 
        /**
@@ -48,7 +48,7 @@ public class WaypointListModel extends AbstractListModel
         */
        public DataPoint getWaypoint(int inIndex)
        {
-               return (DataPoint) _waypoints.get(inIndex);
+               return _waypoints.get(inIndex);
        }
 
        /**
index dcf6740d960c21d15421cae3fabe1088556f35ba..9a352800e95dfa3a37131167b89eff871601555c 100644 (file)
@@ -13,7 +13,7 @@ public class WholeNumberField extends JTextField
        /**
         * Inner class to act as document for validation
         */
-       protected class WholeNumberDocument extends PlainDocument
+       protected static class WholeNumberDocument extends PlainDocument
        {
                /** Num digits to allow */
                private int _maxDigits = 0;
index e6236cde92a88dcba239635428519de6ba6e02a6..a8df86efec37aedd2cfa77074ad23ddd7876e27b 100644 (file)
@@ -27,7 +27,6 @@ import javax.swing.BoxLayout;
 import javax.swing.JButton;
 import javax.swing.JCheckBox;
 import javax.swing.JMenuItem;
-import javax.swing.JOptionPane;
 import javax.swing.JPanel;
 import javax.swing.JPopupMenu;
 import javax.swing.JSlider;
@@ -36,6 +35,7 @@ import javax.swing.event.ChangeListener;
 
 import tim.prune.App;
 import tim.prune.DataSubscriber;
+import tim.prune.FunctionLibrary;
 import tim.prune.I18nManager;
 import tim.prune.data.DoubleRange;
 import tim.prune.data.Selection;
@@ -109,7 +109,9 @@ public class MapCanvas extends JPanel implements MouseListener, MouseMotionListe
 
        // Colours
        private static final Color COLOR_BG         = Color.WHITE;
+       private static final Color COLOR_MESSAGES   = Color.GRAY;
        private static final Color COLOR_POINT      = Color.BLUE;
+       private static final Color COLOR_POINT_DELETED = Color.RED;
        private static final Color COLOR_CURR_RANGE = Color.GREEN;
        private static final Color COLOR_CROSSHAIRS = Color.RED;
        private static final Color COLOR_WAYPT_NAME = Color.BLACK;
@@ -264,6 +266,16 @@ public class MapCanvas extends JPanel implements MouseListener, MouseMotionListe
                        }});
                zoomFullItem.setEnabled(true);
                _popup.add(zoomFullItem);
+               _popup.addSeparator();
+               // Set background
+               JMenuItem setMapBgItem = new JMenuItem(
+                       I18nManager.getText(FunctionLibrary.FUNCTION_SET_MAP_BG.getNameKey()));
+               setMapBgItem.addActionListener(new ActionListener() {
+                       public void actionPerformed(ActionEvent e)
+                       {
+                               FunctionLibrary.FUNCTION_SET_MAP_BG.begin();
+                       }});
+               _popup.add(setMapBgItem);
                // new point option
                JMenuItem newPointItem = new JMenuItem(I18nManager.getText("menu.map.newpoint"));
                newPointItem.addActionListener(new ActionListener() {
@@ -309,10 +321,10 @@ public class MapCanvas extends JPanel implements MouseListener, MouseMotionListe
                        if (_autopanCheckBox.isSelected())
                        {
                                int selectedPoint = _selection.getCurrentPointIndex();
-                               if (selectedPoint > 0 && _dragFromX == -1 && selectedPoint != _prevSelectedPoint)
+                               if (selectedPoint >= 0 && _dragFromX == -1 && selectedPoint != _prevSelectedPoint)
                                {
-                                       int px = getWidth() / 2 + _mapPosition.getXFromCentre(_track.getXNew(selectedPoint));
-                                       int py = getHeight() / 2 + _mapPosition.getYFromCentre(_track.getYNew(selectedPoint));
+                                       int px = getWidth() / 2 + _mapPosition.getXFromCentre(_track.getX(selectedPoint));
+                                       int py = getHeight() / 2 + _mapPosition.getYFromCentre(_track.getY(selectedPoint));
                                        int panX = 0;
                                        int panY = 0;
                                        if (px < PAN_DISTANCE) {
@@ -356,7 +368,7 @@ public class MapCanvas extends JPanel implements MouseListener, MouseMotionListe
                {
                        inG.setColor(COLOR_BG);
                        inG.fillRect(0, 0, getWidth(), getHeight());
-                       inG.setColor(Color.GRAY);
+                       inG.setColor(COLOR_MESSAGES);
                        inG.drawString(I18nManager.getText("display.nodata"), 50, getHeight()/2);
                }
                // Draw slider etc on top
@@ -391,63 +403,117 @@ public class MapCanvas extends JPanel implements MouseListener, MouseMotionListe
                        boolean loadingFailed = false;
                        if (_mapImage == null) return;
 
-                       // Loop over tiles drawing each one
-                       int[] tileIndices = _mapPosition.getTileIndices(getWidth(), getHeight());
-                       int[] pixelOffsets = _mapPosition.getDisplayOffsets(getWidth(), getHeight());
-                       for (int tileX = tileIndices[0]; tileX <= tileIndices[1] && !loadingFailed; tileX++)
+                       if (_tileCacher.isOverzoomed())
                        {
-                               int x = (tileX - tileIndices[0]) * 256 - pixelOffsets[0];
-                               for (int tileY = tileIndices[2]; tileY <= tileIndices[3]; tileY++)
+                               // display overzoom message
+                               g.setColor(COLOR_MESSAGES);
+                               g.drawString(I18nManager.getText("map.overzoom"), 50, getHeight()/2);
+                       }
+                       else
+                       {
+                               // Loop over tiles drawing each one
+                               int[] tileIndices = _mapPosition.getTileIndices(getWidth(), getHeight());
+                               int[] pixelOffsets = _mapPosition.getDisplayOffsets(getWidth(), getHeight());
+                               for (int tileX = tileIndices[0]; tileX <= tileIndices[1] && !loadingFailed; tileX++)
                                {
-                                       int y = (tileY - tileIndices[2]) * 256 - pixelOffsets[1];
-                                       Image image = _tileCacher.getTile(tileX, tileY);
-                                       if (image != null) {
-                                               g.drawImage(image, x, y, 256, 256, null);
+                                       int x = (tileX - tileIndices[0]) * 256 - pixelOffsets[0];
+                                       for (int tileY = tileIndices[2]; tileY <= tileIndices[3]; tileY++)
+                                       {
+                                               int y = (tileY - tileIndices[2]) * 256 - pixelOffsets[1];
+                                               Image image = _tileCacher.getTile(tileX, tileY);
+                                               if (image != null) {
+                                                       g.drawImage(image, x, y, 256, 256, null);
+                                               }
                                        }
                                }
-                       }
 
-                       // Make maps brighter / fainter
-                       float[] scaleFactors = {1.0f, 1.05f, 1.1f, 1.2f, 1.6f, 2.0f};
-                       float scaleFactor = scaleFactors[_transparencySlider.getValue()];
-                       if (scaleFactor > 1.0f) {
-                               RenderingHints hints = new RenderingHints(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_OFF);
-                               hints.put(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
-                               RescaleOp op = new RescaleOp(scaleFactor, 0, hints);
-                               op.filter(_mapImage, _mapImage);
+                               // Make maps brighter / fainter
+                               float[] scaleFactors = {1.0f, 1.05f, 1.1f, 1.2f, 1.6f, 2.0f};
+                               float scaleFactor = scaleFactors[_transparencySlider.getValue()];
+                               if (scaleFactor > 1.0f) {
+                                       RenderingHints hints = new RenderingHints(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_OFF);
+                                       hints.put(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
+                                       RescaleOp op = new RescaleOp(scaleFactor, 0, hints);
+                                       op.filter(_mapImage, _mapImage);
+                               }
                        }
                }
 
+               // Paint the track points on top
+               int pointsPainted = 1;
+               try
+               {
+                       pointsPainted = paintPoints(g);
+               }
+               catch (NullPointerException npe) { // ignore, probably due to data being changed during drawing
+               }
+
+               // free g
+               g.dispose();
+
+               _recalculate = false;
+               // Zoom to fit if no points found
+               if (pointsPainted <= 0 && _checkBounds) {
+                       zoomToFit();
+                       _recalculate = true;
+                       repaint();
+               }
+               _checkBounds = false;
+               // enable / disable transparency slider
+               _transparencySlider.setEnabled(_mapCheckBox.isSelected());
+       }
+
+
+       /**
+        * Paint the points using the given graphics object
+        * @param inG Graphics object to use for painting
+        * @return number of points painted, if any
+        */
+       private int paintPoints(Graphics inG)
+       {
                int pointsPainted = 0;
                // draw track points
-               g.setColor(COLOR_POINT);
+               inG.setColor(COLOR_POINT);
                int prevX = -1, prevY = -1;
                boolean connectPoints = _connectCheckBox.isSelected();
+               boolean prevPointVisible = false, currPointVisible = false;
                for (int i=0; i<_track.getNumPoints(); i++)
                {
-                       int px = getWidth() / 2 + _mapPosition.getXFromCentre(_track.getXNew(i));
-                       int py = getHeight() / 2 + _mapPosition.getYFromCentre(_track.getYNew(i));
-                       if (px >= 0 && px < getWidth() && py >= 0 && py < getHeight())
+                       int px = getWidth() / 2 + _mapPosition.getXFromCentre(_track.getX(i));
+                       int py = getHeight() / 2 + _mapPosition.getYFromCentre(_track.getY(i));
+                       currPointVisible = px >= 0 && px < getWidth() && py >= 0 && py < getHeight();
+                       if (currPointVisible)
                        {
                                if (!_track.getPoint(i).isWaypoint())
                                {
-                                       g.drawRect(px-2, py-2, 3, 3);
-                                       // Connect track points
-                                       if (connectPoints && prevX != -1 && prevY != -1 && !_track.getPoint(i).getSegmentStart()) {
-                                               g.drawLine(prevX, prevY, px, py);
+                                       // Draw rectangle for track point
+                                       if (_track.getPoint(i).getDeleteFlag()) {
+                                               inG.setColor(COLOR_POINT_DELETED);
                                        }
+                                       else {
+                                               inG.setColor(COLOR_POINT);
+                                       }
+                                       inG.drawRect(px-2, py-2, 3, 3);
                                        pointsPainted++;
-                                       prevX = px; prevY = py;
                                }
                        }
-                       else {
-                               prevX = -1; prevY = -1;
+                       if (!_track.getPoint(i).isWaypoint())
+                       {
+                               // Connect track points if either of them are visible
+                               if (connectPoints && (currPointVisible || prevPointVisible)
+                                && !(prevX == -1 && prevY == -1)
+                                && !_track.getPoint(i).getSegmentStart())
+                               {
+                                       inG.drawLine(prevX, prevY, px, py);
+                               }
+                               prevX = px; prevY = py;
                        }
+                       prevPointVisible = currPointVisible;
                }
 
                // Loop over points, just drawing blobs for waypoints
-               g.setColor(COLOR_WAYPT_NAME);
-               FontMetrics fm = g.getFontMetrics();
+               inG.setColor(COLOR_WAYPT_NAME);
+               FontMetrics fm = inG.getFontMetrics();
                int nameHeight = fm.getHeight();
                int width = getWidth();
                int height = getHeight();
@@ -455,11 +521,11 @@ public class MapCanvas extends JPanel implements MouseListener, MouseMotionListe
                {
                        if (_track.getPoint(i).isWaypoint())
                        {
-                               int px = getWidth() / 2 + _mapPosition.getXFromCentre(_track.getXNew(i));
-                               int py = getHeight() / 2 + _mapPosition.getYFromCentre(_track.getYNew(i));
+                               int px = getWidth() / 2 + _mapPosition.getXFromCentre(_track.getX(i));
+                               int py = getHeight() / 2 + _mapPosition.getYFromCentre(_track.getY(i));
                                if (px >= 0 && px < getWidth() && py >= 0 && py < getHeight())
                                {
-                                       g.fillRect(px-3, py-3, 6, 6);
+                                       inG.fillRect(px-3, py-3, 6, 6);
                                        pointsPainted++;
                                }
                        }
@@ -469,8 +535,8 @@ public class MapCanvas extends JPanel implements MouseListener, MouseMotionListe
                {
                        if (_track.getPoint(i).isWaypoint())
                        {
-                               int px = getWidth() / 2 + _mapPosition.getXFromCentre(_track.getXNew(i));
-                               int py = getHeight() / 2 + _mapPosition.getYFromCentre(_track.getYNew(i));
+                               int px = getWidth() / 2 + _mapPosition.getXFromCentre(_track.getX(i));
+                               int py = getHeight() / 2 + _mapPosition.getYFromCentre(_track.getY(i));
                                if (px >= 0 && px < getWidth() && py >= 0 && py < getHeight())
                                {
                                        // Figure out where to draw waypoint name so it doesn't obscure track
@@ -493,7 +559,7 @@ public class MapCanvas extends JPanel implements MouseListener, MouseMotionListe
                                                                && !overlapsPoints(nameXs[a], nameYs[a], nameWidth, nameHeight))
                                                        {
                                                                // Found a rectangle to fit - draw name here and quit
-                                                               g.drawString(waypointName, nameXs[a], nameYs[a]);
+                                                               inG.drawString(waypointName, nameXs[a], nameYs[a]);
                                                                drawnName = true;
                                                                break;
                                                        }
@@ -503,17 +569,17 @@ public class MapCanvas extends JPanel implements MouseListener, MouseMotionListe
                        }
                }
                // Loop over points, drawing blobs for photo points
-               g.setColor(COLOR_PHOTO_PT);
+               inG.setColor(COLOR_PHOTO_PT);
                for (int i=0; i<_track.getNumPoints(); i++)
                {
                        if (_track.getPoint(i).getPhoto() != null)
                        {
-                               int px = getWidth() / 2 + _mapPosition.getXFromCentre(_track.getXNew(i));
-                               int py = getHeight() / 2 + _mapPosition.getYFromCentre(_track.getYNew(i));
+                               int px = getWidth() / 2 + _mapPosition.getXFromCentre(_track.getX(i));
+                               int py = getHeight() / 2 + _mapPosition.getYFromCentre(_track.getY(i));
                                if (px >= 0 && px < getWidth() && py >= 0 && py < getHeight())
                                {
-                                       g.drawRect(px-1, py-1, 2, 2);
-                                       g.drawRect(px-2, py-2, 4, 4);
+                                       inG.drawRect(px-1, py-1, 2, 2);
+                                       inG.drawRect(px-2, py-2, 4, 4);
                                        pointsPainted++;
                                }
                        }
@@ -522,12 +588,12 @@ public class MapCanvas extends JPanel implements MouseListener, MouseMotionListe
                // Draw selected range
                if (_selection.hasRangeSelected())
                {
-                       g.setColor(COLOR_CURR_RANGE);
+                       inG.setColor(COLOR_CURR_RANGE);
                        for (int i=_selection.getStart(); i<=_selection.getEnd(); i++)
                        {
-                               int px = getWidth() / 2 + _mapPosition.getXFromCentre(_track.getXNew(i));
-                               int py = getHeight() / 2 + _mapPosition.getYFromCentre(_track.getYNew(i));
-                               g.drawRect(px-1, py-1, 2, 2);
+                               int px = getWidth() / 2 + _mapPosition.getXFromCentre(_track.getX(i));
+                               int py = getHeight() / 2 + _mapPosition.getYFromCentre(_track.getY(i));
+                               inG.drawRect(px-1, py-1, 2, 2);
                        }
                }
 
@@ -535,30 +601,18 @@ public class MapCanvas extends JPanel implements MouseListener, MouseMotionListe
                int selectedPoint = _selection.getCurrentPointIndex();
                if (selectedPoint >= 0)
                {
-                       int px = getWidth() / 2 + _mapPosition.getXFromCentre(_track.getXNew(selectedPoint));
-                       int py = getHeight() / 2 + _mapPosition.getYFromCentre(_track.getYNew(selectedPoint));
-                       g.setColor(COLOR_CROSSHAIRS);
+                       int px = getWidth() / 2 + _mapPosition.getXFromCentre(_track.getX(selectedPoint));
+                       int py = getHeight() / 2 + _mapPosition.getYFromCentre(_track.getY(selectedPoint));
+                       inG.setColor(COLOR_CROSSHAIRS);
                        // crosshairs
-                       g.drawLine(px, 0, px, getHeight());
-                       g.drawLine(0, py, getWidth(), py);
+                       inG.drawLine(px, 0, px, getHeight());
+                       inG.drawLine(0, py, getWidth(), py);
                        // oval
-                       g.drawOval(px - 2, py - 2, 4, 4);
-                       g.drawOval(px - 3, py - 3, 6, 6);
-               }
-
-               // free g
-               g.dispose();
-
-               _recalculate = false;
-               // Zoom to fit if no points found
-               if (pointsPainted <= 0 && _checkBounds) {
-                       zoomToFit();
-                       _recalculate = true;
-                       repaint();
+                       inG.drawOval(px - 2, py - 2, 4, 4);
+                       inG.drawOval(px - 3, py - 3, 6, 6);
                }
-               _checkBounds = false;
-               // enable / disable transparency slider
-               _transparencySlider.setEnabled(_mapCheckBox.isSelected());
+               // Return the number of points painted
+               return pointsPainted;
        }
 
 
@@ -601,22 +655,19 @@ public class MapCanvas extends JPanel implements MouseListener, MouseMotionListe
 
        /**
         * Inform that tiles have been updated and the map can be repainted
-        * @param isOK true if data loaded ok, false for error
+        * @param inIsOk true if data loaded ok, false for error
         */
        public synchronized void tilesUpdated(boolean inIsOk)
        {
                // Show message if loading failed (but not too many times)
-               if (!inIsOk && !_shownOsmErrorAlready)
+               if (!inIsOk && !_shownOsmErrorAlready && _mapCheckBox.isSelected())
                {
                        _shownOsmErrorAlready = true;
                        // use separate thread to show message about failing to load osm images
                        new Thread(new Runnable() {
                                public void run() {
                                        try {Thread.sleep(500);} catch (InterruptedException ie) {}
-                                       JOptionPane.showMessageDialog(MapCanvas.this,
-                                               I18nManager.getText("error.osmimage.failed"),
-                                               I18nManager.getText("error.osmimage.dialogtitle"),
-                                               JOptionPane.ERROR_MESSAGE);
+                                       _app.showErrorMessage("error.osmimage.dialogtitle", "error.osmimage.failed");
                                }
                        }).start();
                }
@@ -685,7 +736,7 @@ public class MapCanvas extends JPanel implements MouseListener, MouseMotionListe
                         // select point if it's a left-click
                        if (!inE.isMetaDown())
                        {
-                               int pointIndex = _track.getNearestPointIndexNew(
+                               int pointIndex = _track.getNearestPointIndex(
                                         _mapPosition.getXFromPixels(inE.getX(), getWidth()),
                                         _mapPosition.getYFromPixels(inE.getY(), getHeight()),
                                         _mapPosition.getBoundsFromPixels(CLICK_SENSITIVITY), false);
@@ -806,6 +857,9 @@ public class MapCanvas extends JPanel implements MouseListener, MouseMotionListe
                if ((inUpdateType & DataSubscriber.DATA_ADDED_OR_REMOVED) > 0) {
                        _checkBounds = true;
                }
+               if ((inUpdateType & DataSubscriber.MAPSERVER_CHANGED) > 0) {
+                       _tileCacher.setTileConfig(new MapTileConfig());
+               }
                repaint();
                // enable or disable components
                boolean hasData = _track.getNumPoints() > 0;
index 73c7ed922fe52ea7f0597aa2d75020af9255a1bf..d035f10bb3f8bd74ddff6959e13e2a20bfdd1c36 100644 (file)
@@ -13,10 +13,12 @@ public class MapPosition
        /** y position (scale depends on zoom) */
        private long _yPosition = 0L;
 
-       /** Zoom level, from 2 to 15 */
+       /** Zoom level, from 2 to max */
        private int _zoom = 12;
        /** Factor to zoom by, 2 to the power of zoom */
        private int _zoomFactor = 1 << _zoom;
+       /** Maximum zoom level */
+       private static final int MAX_ZOOM = 21;
 
 
        /**
@@ -35,7 +37,7 @@ public class MapPosition
                double diffY = Math.abs(inMaxY - inMinY);
                // Find out what zoom level to go to
                int requiredZoom = -1;
-               for (int currZoom = 15; currZoom >= 2; currZoom--)
+               for (int currZoom = MAX_ZOOM; currZoom >= 2; currZoom--)
                {
                        if (transformToPixels(diffX, currZoom) < inWidth
                                && transformToPixels(diffY, currZoom) < inHeight)
@@ -69,7 +71,7 @@ public class MapPosition
                // Find out what zoom level to go to
                int requiredZoom = -1;
                int multFactor = 0;
-               for (int currZoom = 16; currZoom >= _zoom; currZoom--)
+               for (int currZoom = MAX_ZOOM; currZoom >= _zoom; currZoom--)
                {
                        multFactor = 1 << (currZoom - _zoom);
                        if ((diffX * multFactor) < inWidth && (diffY * multFactor) < inHeight)
@@ -227,7 +229,7 @@ public class MapPosition
         */
        public void zoomIn()
        {
-               if (_zoom < 16)
+               if (_zoom < MAX_ZOOM)
                {
                        _zoom++;
                        _zoomFactor = 1 << _zoom;
index 50387dd4f9a9c7059d047e0c8347fd646950eada..ea5b6fb769813d7e3c0b4700fc55698454dec2db 100644 (file)
@@ -14,8 +14,6 @@ public class MapTileCacher implements ImageObserver
 {
        /** Parent to be informed of updates */
        private MapCanvas _parent = null;
-       /** Default grid size */
-       private static final int GRID_SIZE = 11;
        /** Array of images to hold tiles */
        private Image[] _tiles = new Image[GRID_SIZE * GRID_SIZE];
        /** Current zoom level */
@@ -28,6 +26,13 @@ public class MapTileCacher implements ImageObserver
        private int _gridCentreX = 0;
        /** Y coord of grid centre */
        private int _gridCentreY = 0;
+       /** Tile configuration */
+       private MapTileConfig _tileConfig = null;
+
+       /** Grid size */
+       private static final int GRID_SIZE = 11;
+       /** max zoom level of map tiles */
+       private static final int MAX_TILE_ZOOM = 18;
 
 
        /**
@@ -82,6 +87,7 @@ public class MapTileCacher implements ImageObserver
         */
        public Image getTile(int inX, int inY)
        {
+               if (_tileConfig == null) {_tileConfig = new MapTileConfig();}
                int arrayIndex = getArrayIndex(inX, inY);
                Image image = _tiles[arrayIndex];
                if (image != null)
@@ -90,13 +96,17 @@ public class MapTileCacher implements ImageObserver
                        return image;
                }
 
+               // Protect against zoom > max
+               if (isOverzoomed()) return null;
+
                // Trigger load if not already triggered
                // Work out tile coords for URL
                int urlX = getUrlCoordinate(inX, _zoom);
                int urlY = getUrlCoordinate(inY, _zoom);
                try
                {
-                       String url = "http://tile.openstreetmap.org/" + _zoom + "/" + urlX + "/" + urlY + ".png";
+                       // Use configured tile server
+                       String url = _tileConfig.getUrl() + _zoom + "/" + urlX + "/" + urlY + ".png";
                        // Load image asynchronously, using observer
                        image = Toolkit.getDefaultToolkit().createImage(new URL(url));
                        _tiles[arrayIndex] = image;
@@ -106,6 +116,13 @@ public class MapTileCacher implements ImageObserver
                return null;
        }
 
+       /**
+        * @return true if zoom is too high for tiles
+        */
+       public boolean isOverzoomed()
+       {
+               return (_zoom > MAX_TILE_ZOOM);
+       }
 
        /**
         * Get the array index for the given coordinates
@@ -193,4 +210,14 @@ public class MapTileCacher implements ImageObserver
                }
                return !loaded;
        }
+
+       /**
+        * Set or reset the tile config
+        * @param inConfig object containing tile config
+        */
+       public void setTileConfig(MapTileConfig inConfig)
+       {
+               _tileConfig = inConfig;
+               clearAll();
+       }
 }
diff --git a/tim/prune/gui/map/MapTileConfig.java b/tim/prune/gui/map/MapTileConfig.java
new file mode 100644 (file)
index 0000000..762baf4
--- /dev/null
@@ -0,0 +1,92 @@
+package tim.prune.gui.map;
+
+import java.net.MalformedURLException;
+import java.net.URL;
+
+import tim.prune.Config;
+
+/**
+ * Class to hold the config for the map tiles
+ * and retrieve the correct URL prefix
+ */
+public class MapTileConfig
+{
+       /** Index of map server */
+       private int _index = 0;
+       /** Url for other */
+       private String _url = null;
+
+       /** server urls for known maps */
+       private static final String[] SERVER_URLS = {
+               "http://tile.openstreetmap.org/", // mapnik
+               "http://tah.openstreetmap.org/Tiles/tile/",      // osma
+               "http://andy.sandbox.cloudmade.com/tiles/cycle/" // cyclemap
+       };
+       /** Index of 'other' server with freeform url */
+       private static final int OTHER_SERVER_NUM = 3;
+
+
+       /**
+        * Default constructor using Config
+        */
+       public MapTileConfig()
+       {
+               _index = Config.getMapServerIndex();
+               _url = fixUrl(Config.getMapServerUrl());
+               // reset index wrong or if other url too short
+               if (_index < 0 || _index > OTHER_SERVER_NUM ||
+                       (_index == OTHER_SERVER_NUM && (_url == null || _url.length() < 5)))
+               {
+                       _index = 0;
+               }
+       }
+
+       /**
+        * @return url
+        */
+       public String getUrl()
+       {
+               if (_index == OTHER_SERVER_NUM) {return _url;}
+               return SERVER_URLS[_index];
+       }
+
+       /**
+        * Checks the given url for having the right prefix and trailing slash
+        * @param inUrl url to check
+        * @return validated url with correct prefix and trailing slash, or null
+        */
+       private static String fixUrl(String inUrl)
+       {
+               if (inUrl == null || inUrl.equals("")) {return null;}
+               String url = inUrl;
+               // check prefix
+               try {
+                       new URL(url);
+               }
+               catch (MalformedURLException e) {
+                       // add the http protocol
+                       url = "http://" + url;
+               }
+               // check trailing /
+               if (!url.endsWith("/")) {
+                       url = url + "/";
+               }
+               return url;
+       }
+
+       /**
+        * @param inOther other config object
+        * @return true if the objects are exactly the same
+        */
+       public boolean equals(MapTileConfig inOther)
+       {
+               // Other object must be non-null and must have same index
+               if (inOther == null || inOther._index != _index) {return false;}
+               // Check url if other selected
+               if (_index == OTHER_SERVER_NUM) {
+                       return inOther._url.equals(_url);
+               }
+               // Not other so must match
+               return true;
+       }
+}
index d01a8724452b55bd8648008b7ca154870028b869..81b2b78410e4fa670ea8ebf0b65d58b3085ae6c8 100644 (file)
@@ -5,11 +5,7 @@
 menu.file=Datei
 menu.file.open=Datei Ã¶ffnen
 menu.file.addphotos=Fotos laden
-menu.file.loadfromgps=Vom GPS laden
 menu.file.save=Speichern
-menu.file.exportkml=KML exportieren
-menu.file.exportgpx=GPX exportieren
-menu.file.exportpov=POV exportieren
 menu.file.exit=Beenden
 menu.edit=Bearbeiten
 menu.edit.undo=Rückgängig
@@ -18,11 +14,10 @@ menu.edit.editpoint=Punkt bearbeiten
 menu.edit.editwaypointname=Waypoint Name bearbeiten
 menu.edit.deletepoint=Punkt löschen
 menu.edit.deleterange=Bereich löschen
-menu.edit.deleteduplicates=Duplikate löschen
-menu.edit.compress=Track komprimieren
+menu.edit.deletemarked=Komprimierten Punkte löschen
 menu.edit.interpolate=Interpolieren
+menu.edit.average=Durchschnitt berechnen
 menu.edit.reverse=Bereich umkehren
-menu.edit.addtimeoffset=Zeitdifferenz addieren
 menu.edit.mergetracksegments=Trackteile verbinden
 menu.edit.rearrange=Waypoints reorganisieren
 menu.edit.rearrange.start=Alle Waypoints zum Anfang
@@ -38,16 +33,14 @@ menu.photo=Foto
 menu.photo.saveexif=Exif Daten speichern
 menu.photo.connect=Mit Punkt verbinden
 menu.photo.disconnect=Vom Punkt trennen
-menu.photo.correlate=Alle Fotos korrelieren
 menu.photo.delete=Foto entfernen
 menu.view=Ansicht
-menu.view.show3d=In 3D zeigen
 menu.view.browser=Karte in Browser
 menu.view.browser.google=Google Maps
 menu.view.browser.openstreetmap=Openstreetmap
+menu.view.browser.mapquest=
+menu.view.browser.yahoo=
 menu.help=Hilfe
-menu.help.about=Ãœber Prune
-menu.help.checkversion=Nach neuen Versionen suchen
 # Popup menu for map
 menu.map.zoomin=Hineinzoomen
 menu.map.zoomout=Herauszoomen
@@ -57,6 +50,23 @@ menu.map.connect=Trackpunkte mit Linie anzeigen
 menu.map.autopan=Autozentrierung
 menu.map.showmap=Karte zeigen
 
+# Functions
+function.loadfromgps=Vom GPS laden
+function.sendtogps=zum GPS schicken
+function.exportkml=KML exportieren
+function.exportgpx=GPX exportieren
+function.exportpov=POV exportieren
+function.compress=Track komprimieren
+function.addtimeoffset=Zeitdifferenz addieren
+function.charts=Diagrammen
+function.show3d=3D Ansicht
+function.distances=Distanzen
+function.setmapbg=Karte Hintergrund setzen
+function.correlatephotos=Fotos korrelieren
+function.help=Hilfe
+function.about=Ãœber Prune
+function.checkversion=Nach neuen Versionen suchen
+
 # Dialogs
 dialog.exit.confirm.title=Prune beenden
 dialog.exit.confirm.text=Ihre Daten wurden nicht gespeichert. Wollen Sie das Programm trotzdem beenden?
@@ -66,11 +76,6 @@ dialog.deletepoint.title=Punkt l
 dialog.deletepoint.deletephoto=Das zu diesem Punkt gehörende Foto ebenfalls löschen?
 dialog.deletephoto.title=Foto entfernen
 dialog.deletephoto.deletepoint=Den zu diesem Foto gehörenden Punkt auch löschen?
-dialog.deleteduplicates.title=Duplikate löschen
-dialog.deleteduplicates.nonefound=Keine Duplikate gefunden
-dialog.compresstrack.title=Track komprimieren
-dialog.compresstrack.parameter.text=Parameter für Komprimierung (niedrige Nummer = höhere Komprimierung)
-dialog.compresstrack.nonefound=Es konnten keine Punkte entfernt werden
 dialog.openoptions.title=Öffnen
 dialog.openoptions.filesnippet=Extrakt von der Datei
 dialog.load.table.field=Feld
@@ -85,19 +90,20 @@ dialog.delimiter.other=Andere
 dialog.openoptions.deliminfo.records=Aufnahmen, mit
 dialog.openoptions.deliminfo.fields=Feldern
 dialog.openoptions.deliminfo.norecords=Keine Rekords
-dialog.openoptions.tabledesc=Extrakt von der Datei
 dialog.openoptions.altitudeunits=Höhe Maßeinheiten
 dialog.jpegload.subdirectories=Unterordner auch durchsuchen
 dialog.jpegload.loadjpegswithoutcoords=Auch Fotos ohne Koordinaten laden
 dialog.jpegload.loadjpegsoutsidearea=Auch Fotos ausserhalb vom Track laden
 dialog.jpegload.progress.title=Fotos werden geladen
 dialog.jpegload.progress=Bitte warten während die Fotos durchgesucht werden
-dialog.gpsload.title=Vom GPS laden
 dialog.gpsload.nogpsbabel=Kein gpsbabel Programm wurde gefunden. Weiter?
 dialog.gpsload.device=Device Name
 dialog.gpsload.format=Format
 dialog.gpsload.getwaypoints=Waypoints laden
 dialog.gpsload.gettracks=Tracks laden
+dialog.gpssend.sendwaypoints=Waypoints schicken
+dialog.gpssend.sendtracks=Tracks schicken
+dialog.gpssend.trackname=Track Name
 dialog.saveoptions.title=Datei speichern
 dialog.save.fieldstosave=Zu speichernde Felder
 dialog.save.table.field=Feld
@@ -109,16 +115,13 @@ dialog.save.altitudeunits=H
 dialog.save.timestampformat=Zeitstempelformat
 dialog.save.overwrite.title=Datei schon vorhanden
 dialog.save.overwrite.text=Diese Datei existiert schon. Wollen Sie die vorhandene Datei Ã¼berschreiben?
-dialog.exportkml.title=KML exportieren
 dialog.exportkml.text=Titel für die Daten
 dialog.exportkml.altitude=Auch Höheninformation (für Luftfahrt)
 dialog.exportkml.kmz=Daten in kmz Datei komprimieren
 dialog.exportkml.exportimages=Bilder in kmz exportieren
-dialog.exportgpx.title=GPX exportieren
 dialog.exportgpx.name=Name
 dialog.exportgpx.desc=Beschreibung
 dialog.exportgpx.includetimestamps=Zeitstempel exportieren
-dialog.exportpov.title=POV exportieren
 dialog.exportpov.text=Geben Sie die Parameter für den POV Export ein
 dialog.exportpov.font=Font
 dialog.exportpov.camerax=Kamera X
@@ -152,7 +155,6 @@ dialog.pointnameedit.name=Waypoint Name
 dialog.pointnameedit.uppercase=GROß geschrieben
 dialog.pointnameedit.lowercase=klein geschrieben
 dialog.pointnameedit.sentencecase=Gemischt geschrieben
-dialog.addtimeoffset.title=Zeitdifferenz addieren
 dialog.addtimeoffset.add=Zeit addieren
 dialog.addtimeoffset.subtract=Zeit subtrahieren
 dialog.addtimeoffset.days=Tage
@@ -172,7 +174,26 @@ dialog.saveexif.photostatus.connected=Verbunden
 dialog.saveexif.photostatus.disconnected=Getrennt
 dialog.saveexif.photostatus.modified=Modifiziert
 dialog.saveexif.overwrite=Dateien Ã¼berschreiben
-dialog.correlate.title=Fotos korrelieren
+dialog.charts.xaxis=X Achse
+dialog.charts.yaxis=Y Achse
+dialog.charts.output=Ausgabe
+dialog.charts.screen=zum Bildschirm
+dialog.charts.svg=zur SVG Datei
+dialog.charts.svgwidth=SVG Breite
+dialog.charts.svgheight=SVG Höhe
+dialog.charts.needaltitudeortimes=Ohne Daten Ã¼ber Höhe und Zeit, kann keine Diagrammen erzeugt werden.
+dialog.charts.gnuplotpath=Gnuplot Pfad
+dialog.charts.gnuplotnotfound=Gnuplot konnte mit diesem Pfad nicht gefunden werden
+dialog.distances.intro=Distanzen per Luftlinie zwischen Punkte
+dialog.distances.column.from=Vom Punkt
+dialog.distances.column.to=Zum Punkt
+dialog.distances.currentpoint=Aktuelle Punkt
+dialog.distances.toofewpoints=Diese Funktion braucht Waypoints um die Distanzen zu berechnen
+dialog.setmapbg.mapnik=
+dialog.setmapbg.osma=
+dialog.setmapbg.cyclemap=Fahrradkarte
+dialog.setmapbg.other=Andere
+dialog.setmapbg.server=Server URL
 dialog.correlate.notimestamps=Die Punkte haben keine Zeitinformation, deswegen ist es nicht möglich die Fotos zu korrelieren.
 dialog.correlate.nouncorrelatedphotos=Alle Photos sind schon korreliert.\nWollen Sie trotzdem fortsetzen?
 dialog.correlate.photoselect.intro=Selektieren Sie einen von diesen Fotos um die Differenz zu berechnen
@@ -195,8 +216,16 @@ dialog.correlate.options.nodistancelimit=Keine Distanzgrenzen
 dialog.correlate.options.distancelimit=Distanzgrenzen
 dialog.correlate.options.correlate=Korrelieren
 dialog.correlate.alloutsiderange=Alle Fotos sind ausserhalb vom Track Zeitraum, so können nicht korreliert werden.\nVersuchen Sie mit einem anderen Offset oder verbinden Sie manuell mindestens ein Foto.
+dialog.compress.nonefound=Es konnten keine Punkte entfernt werden
+dialog.compress.duplicates.title=Duplikate entfernen
+dialog.compress.closepoints.title=Nahegelegene Punkte entfernen
+dialog.compress.closepoints.paramdesc=Span Faktor
+dialog.compress.wackypoints.title=Komische Punkte entfernen
+dialog.compress.wackypoints.paramdesc=Distanz Faktor
+dialog.compress.singletons.title=Singletons entfernen
+dialog.compress.singletons.paramdesc=Distanz Faktor
+dialog.compress.summarylabel=Punkte zu entfernen
 dialog.help.help=Bitte sehen Sie\n http://activityworkshop.net/software/prune/\nfür weitere Information und Benutzeranleitungen.
-dialog.about.title=Ãœber Prune
 dialog.about.version=Version
 dialog.about.build=Build
 dialog.about.summarytext1=Prune ist ein Programm für das Laden, Darstellen und Editieren von Daten von GPS Geräten.
@@ -211,6 +240,7 @@ dialog.about.systeminfo.java3d=Java3d installiert
 dialog.about.systeminfo.povray=Povray installiert
 dialog.about.systeminfo.exiftool=Exiftool installiert
 dialog.about.systeminfo.gpsbabel=Gpsbabel installiert
+dialog.about.systeminfo.gnuplot=Gnuplot installiert
 dialog.about.yes=Ja
 dialog.about.no=Nein
 dialog.about.credits=Credits
@@ -223,7 +253,6 @@ dialog.about.credits.devtools=Entwicklungsprogrammen
 dialog.about.credits.othertools=Andere Programmen
 dialog.about.credits.thanks=Danke an
 dialog.about.readme=Liesmich
-dialog.checkversion.title=Versionnummer prüfen
 dialog.checkversion.error=Die Versionnummer konnte nicht geprüft werden.\nBitte prüfen Sie die Internet Verbindung.
 dialog.checkversion.uptodate=Sie haben schon die letzte Version vom Prune.
 dialog.checkversion.newversion1=Eine neue Version vom Prune ist jetzt verfügbar!  Die neue Version heißt Version
@@ -243,8 +272,6 @@ dialog.3dlines.intro=Hier sind die Linien f
 confirm.loadfile=Daten geladen vom
 confirm.save.ok1=Es wurden
 confirm.save.ok2=Punkte gespeichert nach
-confirm.deleteduplicates.single=Duplikat wurde gelöscht
-confirm.deleteduplicates.multi=Duplikate wurden gelöscht
 confirm.deletepoint.single=Punkt wurde entfernt
 confirm.deletepoint.multi=Punkte wurden entfernt
 confirm.point.edit=Punkt editiert
@@ -288,14 +315,17 @@ button.selectnone=Nichts selektieren
 button.preview=Vorschauen
 button.guessfields=Felder erraten
 button.showwebpage=Webseite anzeigen
+button.gnuplotpath=Gnuplot Pfad setzen
 
 # File types
 filetype.txt=TXT Dateien
 filetype.jpeg=JPG Dateien
 filetype.kmlkmz=KML, KMZ Dateien
 filetype.kml=KML Dateien
+filetype.kmz=KMZ Dateien
 filetype.gpx=GPX Dateien
 filetype.pov=POV Dateien
+filetype.svg=SVG Dateien
 
 # Display components
 display.nodata=Keine Daten geladen
@@ -309,7 +339,6 @@ details.pointdetails=Details vom Punkt
 details.index.selected=Index
 details.index.of=von
 details.nopointselection=Nichts selektiert
-details.speed=Geschwindigkeit
 details.photofile=Foto Datei
 details.norangeselection=Nichts selektiert
 details.rangedetails=Details vom Bereich
@@ -332,12 +361,14 @@ details.photodetails=Details vom Foto
 details.nophoto=Kein Foto selektiert
 details.photo.loading=Laden
 details.photo.connected=Verbunden
+map.overzoom=Keine Karten mit diesem Zoom verfügbar
 
 # Field names
 fieldname.latitude=Breitengrad
 fieldname.longitude=Längengrad
 fieldname.altitude=Höhe
 fieldname.timestamp=Zeitstempel
+fieldname.time=Zeit
 fieldname.waypointname=Name
 fieldname.waypointtype=Typ
 fieldname.newsegment=Segment
@@ -346,20 +377,25 @@ fieldname.prefix=Feld
 fieldname.distance=Länge
 fieldname.movingdistance=Weglänge
 fieldname.duration=Zeitlänge
+fieldname.speed=Geschwindigkeit
+fieldname.verticalspeed=Vertikale Geschwindigkeit
 
 # Measurement units
 units.original=Original
 units.default=Default
 units.metres=Meter
-units.metres.short=m
-units.feet=Füße
-units.feet.short=ft
+units.metres.short=
+units.feet=
+units.feet.short=
 units.kilometres=Kilometer
 units.kilometres.short=km
 units.kmh=km/h
-units.miles=Meilen
-units.miles.short=mi
-units.mph=mi/h
+units.miles=
+units.miles.short=
+units.mph=
+units.metrespersec=m/s
+units.feetpersec=ft/s
+units.hours=Std
 units.degminsec=Grad-Min-Sek
 units.degmin=Grad-Min
 units.deg=Grad
@@ -383,7 +419,6 @@ undo.deletephoto=Photo entfernen
 undo.deleterange=Bereich löschen
 undo.compress=Track komprimieren
 undo.insert=Punkte hinzufügen
-undo.deleteduplicates=Duplikaten löschen
 undo.reverse=Bereich umdrehen
 undo.mergetracksegments=Trackteile verbinden
 undo.addtimeoffset=zeitdifferenz addieren
@@ -405,6 +440,7 @@ error.load.dialogtitle=Fehler beim Laden
 error.load.noread=Datei konnte nicht gelesen werden
 error.load.nopoints=Keine gültigen Daten in Datei gefunden
 error.load.unknownxml=Unbekanntes xml Format:
+error.load.noxmlinzip=Keine xml Datei in Zip Datei gefunden
 error.load.othererror=Fehler beim Lesen von der Datei:
 error.jpegload.dialogtitle=Fehler beim Laden von Fotos
 error.jpegload.nofilesfound=Keine Dateien gefunden
@@ -415,10 +451,8 @@ error.undofailed.title=Undo fehlgeschlagen
 error.undofailed.text=Operation konnte nicht rückgängig gemacht werden
 error.function.noop.title=Funktion hat nichts gemacht
 error.rearrange.noop=Waypoints Reorganisieren hatte keinen Effekt
-error.function.notimplemented=Sorry, diese Funktion wurde noch nicht implementiert.
 error.function.notavailable.title=Funktion nicht verfügbar
 error.function.nojava3d=Diese Funktion braucht den Java3d Library,\nvon Sun.com erhältlich.
-error.3d.title=Fehler mit 3d Darstellung
 error.3d=Ein Fehler ist mit der 3d Darstellung aufgetreten
 error.readme.notfound=Liesmich Datei nicht gefunden
 error.osmimage.dialogtitle=Laden von Karten-Bilder fehlgeschlagen
index acd3c2286bb734ca5ecae79cc7f5b0a0a4a4264e..5cbeed6469ed81e0b866a242052808b8400a223d 100644 (file)
@@ -4,12 +4,8 @@
 # Menu entries
 menu.file=Datei
 menu.file.open=File Ã¶ffne
-menu.file.loadfromgps=uusem GPS lade
 menu.file.addphotos=Fötelis innätue
 menu.file.save=Speichere
-menu.file.exportkml=KML exportiere
-menu.file.exportgpx=GPX exportiere
-menu.file.exportpov=POV exportiere
 menu.file.exit=Beände
 menu.edit=Editiere
 menu.edit.undo=Undo
@@ -18,11 +14,10 @@ menu.edit.editpoint=Punkt editiere
 menu.edit.editwaypointname=Waypoint Name editiere
 menu.edit.deletepoint=Punkt lösche
 menu.edit.deleterange=Beriich lösche
-menu.edit.deleteduplicates=Doppeldate lösche
-menu.edit.compress=Date komprimiere
+menu.edit.deletemarked=Komprimierte Punkte lösche
 menu.edit.interpolate=Interpoliere
+menu.edit.average=Durchschnitt uusrächne
 menu.edit.reverse=Beriich umdrähie
-menu.edit.addtimeoffset=Ziitverschiebig zutue
 menu.edit.mergetracksegments=Track Segmänte merge
 menu.edit.rearrange=Waypoints reorganisiere
 menu.edit.rearrange.start=Alli zum Aafang
@@ -38,25 +33,40 @@ menu.photo=F
 menu.photo.saveexif=Exif Date speicherä
 menu.photo.connect=Mitem Punkt verbindä
 menu.photo.disconnect=Vonem Punkt trännä
-menu.photo.correlate=Alli Fötelis korrelierä
 menu.photo.delete=Föteli entfernä
 menu.view=Aasicht
-menu.view.show3d=In drüü-D zeigä
 menu.view.browser=Karte inem Browser
-menu.view.browser.google=Google maps
-menu.view.browser.openstreetmap=Openstreetmap
+menu.view.browser.google=
+menu.view.browser.openstreetmap=
+menu.view.browser.mapquest=
+menu.view.browser.yahoo=
 menu.help=Hilfe
-menu.help.about=Ãœber Prune
-menu.help.checkversion=Pruef nach ne noie Version
 # Popup menu for map
-menu.map.zoomin=Einzoome
-menu.map.zoomout=Uuszoome
+menu.map.zoomin=Innezoome
+menu.map.zoomout=Uusezoome
 menu.map.zoomfull=Zoome zum ganzes Bild
 menu.map.newpoint=Noii Punkt
 menu.map.connect=Trackpünktli verbindä
 menu.map.autopan=Autopan
 menu.map.showmap=Kate zeigä
 
+# Functions
+function.loadfromgps=uusem GPS lade
+function.sendtogps=zum GPS schicke
+function.exportkml=KML exportierä
+function.exportgpx=GPX exportierä
+function.exportpov=POV exportierä
+function.compress=Track komprimierä
+function.addtimeoffset=Ziitverschiebig zutue
+function.charts=Diagramme
+function.show3d=Drüü-D Aasicht
+function.distances=Distanze
+function.setmapbg=Karte Hintegrund setzä
+function.correlatephotos=Fötelis korrelierä
+function.help=Hilfe
+function.about=Ãœber Prune
+function.checkversion=Pruef nach ne noie Version
+
 # Dialogs
 dialog.exit.confirm.title=Prune beände
 dialog.exit.confirm.text=Ihri Date sind nonig gspeicheret worde. Wend Sie trotzdem s Programm beände?
@@ -66,11 +76,6 @@ dialog.deletepoint.title=Punkt l
 dialog.deletepoint.deletephoto=s Föteli vonem Punkt au löschä?
 dialog.deletephoto.title=Föteli entfernä
 dialog.deletephoto.deletepoint=Punkt vonem Föteli au löschä?
-dialog.deleteduplicates.title=Duplikaten lösche
-dialog.deleteduplicates.nonefound=Keine Duplikaten gefunden
-dialog.compresstrack.title=Track komprimiere
-dialog.compresstrack.parameter.text=Parameter für Komprimierig (niedriger Nummer = höher Komprimierig)
-dialog.compresstrack.nonefound=Kei Punkte hätte gelöscht werde könne
 dialog.openoptions.title=Öffne Optionen
 dialog.openoptions.filesnippet=Extrakt vom File
 dialog.load.table.field=Fäld
@@ -85,19 +90,20 @@ dialog.delimiter.other=Andere
 dialog.openoptions.deliminfo.records=Rekords, mit
 dialog.openoptions.deliminfo.fields=Fäldere
 dialog.openoptions.deliminfo.norecords=Kei Rekords
-dialog.openoptions.tabledesc=Extrakt vom File
 dialog.openoptions.altitudeunits=Höchi Masseiheite
 dialog.jpegload.subdirectories=Subordnern au
 dialog.jpegload.loadjpegswithoutcoords=Au Fötelis ohni Koordinate
 dialog.jpegload.loadjpegsoutsidearea=Au Fötelis uuserhalb vonem Track
 dialog.jpegload.progress.title=Fötelis lade
 dialog.jpegload.progress=Bitte warte während die Fötelis durägsucht werde
-dialog.gpsload.title=Lade uusem GPS
 dialog.gpsload.nogpsbabel=Kei gpsbabel Programm gfunde. Wiiter?
 dialog.gpsload.device=Device Name
 dialog.gpsload.format=Format
 dialog.gpsload.getwaypoints=Waypoints lade
 dialog.gpsload.gettracks=Tracks lade
+dialog.gpssend.sendwaypoints=Waypoints schicke
+dialog.gpssend.sendtracks=Tracks schicke
+dialog.gpssend.trackname=Track Name
 dialog.saveoptions.title=File speicherä
 dialog.save.fieldstosave=Fälder zu speicherä
 dialog.save.table.field=Fäld
@@ -109,16 +115,13 @@ dialog.save.altitudeunits=H
 dialog.save.timestampformat=Ziitstämpelformat
 dialog.save.overwrite.title=s'File existiert scho
 dialog.save.overwrite.text=s'File existiert scho. Sind Sie sicher, Sie wend s'File Ã¼berschriibe?
-dialog.exportkml.title=KML exportierä
 dialog.exportkml.text=Titel für die Date
 dialog.exportkml.altitude=Au Höchiinformation (fürs Fliege)
 dialog.exportkml.kmz=Date ins kmz File komprimierä
 dialog.exportkml.exportimages=Bildli ins Kmz exportierä
-dialog.exportgpx.title=GPX exportierä
 dialog.exportgpx.name=Name
 dialog.exportgpx.desc=Beschriibig
 dialog.exportgpx.includetimestamps=Au Ziitstämpel
-dialog.exportpov.title=POV exportierä
 dialog.exportpov.text=Gäbet Sie die Parameter ii fürs POV Export
 dialog.exportpov.font=Font
 dialog.exportpov.camerax=Kamera X
@@ -152,7 +155,6 @@ dialog.pointnameedit.name=Waypoint Name
 dialog.pointnameedit.uppercase=GROSS gschriebe
 dialog.pointnameedit.lowercase=chli gschriebe
 dialog.pointnameedit.sentencecase=Gmischt Gschriebe
-dialog.addtimeoffset.title=Ziitverschiebig zutue
 dialog.addtimeoffset.add=Ziit zutue
 dialog.addtimeoffset.subtract=Ziit davo neh
 dialog.addtimeoffset.days=Tage
@@ -172,7 +174,26 @@ dialog.saveexif.photostatus.connected=Verbund
 dialog.saveexif.photostatus.disconnected=Gtrännt
 dialog.saveexif.photostatus.modified=Gänderet
 dialog.saveexif.overwrite=Files Ã¼berschriebä
-dialog.correlate.title=Fötelis korrelierä
+dialog.charts.xaxis=X Achse
+dialog.charts.yaxis=Y Achse
+dialog.charts.output=Uusgabe
+dialog.charts.screen=Bildschirm
+dialog.charts.svg=SVG File
+dialog.charts.svgwidth=SVG Breiti
+dialog.charts.svgheight=SVG Höhi
+dialog.charts.needaltitudeortimes=Ohni Höhi Date und au ohne Ziit, isch es nöd möglech, Diagramme z zeigä.
+dialog.charts.gnuplotpath=Gnuplot Pfad
+dialog.charts.gnuplotnotfound=Gnuplot isch mit dem Pfad nöd gfunde worde
+dialog.distances.intro=Dischtanze per Luftlinie zwüschet Punkte
+dialog.distances.column.from=Vom Punkt
+dialog.distances.column.to=Zum Punkt
+dialog.distances.currentpoint=Aktuelli Punkt
+dialog.distances.toofewpoints=d'Funktion bruucht Waypoints um die Dischtanze z berächne
+dialog.setmapbg.mapnik=
+dialog.setmapbg.osma=
+dialog.setmapbg.cyclemap=Velokarte
+dialog.setmapbg.other=Anderi
+dialog.setmapbg.server=Server URL
 dialog.correlate.notimestamps=Es hät kei Ziitstämpel inem Track innä, so s'isch nöd möglech die Fötelis zu korrelierä.
 dialog.correlate.nouncorrelatedphotos=Alle Fötelis sin scho korreliert.\nWend Sie trotzdem fortsetzä?
 dialog.correlate.photoselect.intro=Wählet Sie eini vo deren Föteli uus um die Ziitdifferänz zu berächnä
@@ -195,8 +216,16 @@ dialog.correlate.options.nodistancelimit=Kei Distanzgr
 dialog.correlate.options.distancelimit=Distanzgränzä
 dialog.correlate.options.correlate=Korrelierä
 dialog.correlate.alloutsiderange=Alli Fötelis sin uusserhalb vonem Track Ziitruum, so chönne nöd korreliert werdä.\nVersuechet Sie mitenem anderen Offset oder verbindet Sie manuell mindeschtens eis Föteli.
+dialog.compress.nonefound=Kei Punkte hätte gelöscht werde könne
+dialog.compress.duplicates.title=Duplikate entfärnä
+dialog.compress.closepoints.title=Nöchiglägeni Punkte entfärnä
+dialog.compress.closepoints.paramdesc=Span Faktor
+dialog.compress.wackypoints.title=Komischi Punkte entfärnä
+dialog.compress.wackypoints.paramdesc=Distanz Faktor
+dialog.compress.singletons.title=Singletons entfärnä
+dialog.compress.singletons.paramdesc=Distanz faktor
+dialog.compress.summarylabel=Punkte zu entfärnä
 dialog.help.help=Bitte lueg na\n http://activityworkshop.net/software/prune/\nfür wiitere Information und Benutzeraaleitige.
-dialog.about.title=Ãœber Prune
 dialog.about.version=Version
 dialog.about.build=Build
 dialog.about.summarytext1=Prune isch s Programm fürs Lade, Darstelle und Editiere vo Date von GPS Geräte.
@@ -211,6 +240,7 @@ dialog.about.systeminfo.java3d=Java3d inschtalliert
 dialog.about.systeminfo.povray=Povray inschtalliert
 dialog.about.systeminfo.exiftool=Exiftool inschtalliert
 dialog.about.systeminfo.gpsbabel=Gpsbabel inschtalliert
+dialog.about.systeminfo.gnuplot=Gnuplot inschtalliert
 dialog.about.yes=Ja
 dialog.about.no=Nei
 dialog.about.credits=Credits
@@ -223,7 +253,6 @@ dialog.about.credits.devtools=Entwicklungsw
 dialog.about.credits.othertools=Anderi Wärkzüüge
 dialog.about.credits.thanks=Danke an
 dialog.about.readme=Läsmi
-dialog.checkversion.title=Pruef d'Version
 dialog.checkversion.error=Die Versionnummer könne nöd gefprüft werdä.\nGits ne internet Verbindig?
 dialog.checkversion.uptodate=Sie han die noischti Version vonem Prune scho.
 dialog.checkversion.newversion1=Ne noii Version vonem Prune isch jetzt usse! Die heisst jetzt Version
@@ -243,8 +272,6 @@ dialog.3dlines.intro=Hier sin die Linie f
 confirm.loadfile=Date glade vom
 confirm.save.ok1=Es sin
 confirm.save.ok2=Punkte gspeicheret worde na
-confirm.deleteduplicates.single=Duplikat isch glöscht worde
-confirm.deleteduplicates.multi=Duplikaten sin glöscht worde
 confirm.deletepoint.single=Punkt isch entfernt worde
 confirm.deletepoint.multi=Punkte sin entfernt worde
 confirm.point.edit=Punkt editiert
@@ -288,14 +315,17 @@ button.selectnone=N
 button.preview=Vorschauä
 button.guessfields=Fälde erratä
 button.showwebpage=Websiite aazeigä
+button.gnuplotpath=Gnuplot Pfad setzä
 
 # File types
 filetype.txt=TXT Dateie
 filetype.jpeg=JPG Dateie
 filetype.kmlkmz=KML, KMZ Dateie
 filetype.kml=KML Dateie
+filetype.kmz=KMZ Dateie
 filetype.gpx=GPX Dateie
 filetype.pov=POV Dateie
+filetype.svg=SVG Dateie
 
 # Display components
 display.nodata=Kei Date glade worde
@@ -305,11 +335,10 @@ details.notrack=Kei Track glade worde
 details.track.points=Punkte
 details.track.file=Datei
 details.track.numfiles=Anzahl Dateie
-details.pointdetails=Details vom Punkt
+details.pointdetails=Details vonem Punkt
 details.index.selected=Index
 details.index.of=vo
 details.nopointselection=Nüüt selektiert
-details.speed=Gschwindikeit
 details.photofile=Föteli Datei
 details.norangeselection=Nüüt selektiert
 details.rangedetails=Details vonem Beriich
@@ -328,16 +357,18 @@ details.range.avespeed=Gschwindikeit
 details.range.avemovingspeed=Gschwindikeit ufem Wäg
 details.waypointsphotos.waypoints=Waypoints
 details.waypointsphotos.photos=Fötelis
-details.photodetails=Details vom Föteli
+details.photodetails=Details vonem Föteli
 details.nophoto=Kei föteli selektiert
 details.photo.loading=Ladä
 details.photo.connected=Verbundä
+map.overzoom=Kei Karte mit diesem Zoom
 
 # Field names
 fieldname.latitude=Breitegrad
 fieldname.longitude=Längegrad
 fieldname.altitude=Höchi
 fieldname.timestamp=Ziitstämpel
+fieldname.time=Ziit
 fieldname.waypointname=Name
 fieldname.waypointtype=Typ
 fieldname.newsegment=Segmänt
@@ -346,20 +377,25 @@ fieldname.prefix=F
 fieldname.distance=Längi
 fieldname.movingdistance=Weglängi
 fieldname.duration=Ziitlängi
+fieldname.speed=Gschwindikeit
+fieldname.verticalspeed=Uf/Ab Gschwindikeit
 
 # Measurement units
 units.original=Original
 units.default=Default
 units.metres=Meter
-units.metres.short=m
-units.feet=Fuess
-units.feet.short=ft
+units.metres.short=
+units.feet=
+units.feet.short=
 units.kilometres=Kilometer
 units.kilometres.short=km
 units.kmh=km/h
-units.miles=Meile
-units.miles.short=mi
-units.mph=mi/Std
+units.miles=
+units.miles.short=
+units.mph=
+units.metrespersec=m/s
+units.feetpersec=ft/s
+units.hours=Std
 units.degminsec=Grad-Min-Sek
 units.degmin=Grad-Min
 units.deg=Grad
@@ -383,7 +419,6 @@ undo.deletephoto=F
 undo.deleterange=Beriich löschä
 undo.compress=Track komprimierä
 undo.insert=Punkte innätuä
-undo.deleteduplicates=Duplikaten löschä
 undo.reverse=Beriich umdrähie
 undo.mergetracksegments=track segmänte merge
 undo.addtimeoffset=ziitverschiebig zutue
@@ -405,6 +440,7 @@ error.load.dialogtitle=F
 error.load.noread=File cha nöd glase werde
 error.load.nopoints=Kei gültigi Information inem File gfunde
 error.load.unknownxml=Unbekanntes xml Format:
+error.load.noxmlinzip=Kei xml im Zip File gfunde
 error.load.othererror=Fähle bim Läse:
 error.jpegload.dialogtitle=Fähle bim Lade von Fötelis
 error.jpegload.nofilesfound=Kei Dateie gfunde
@@ -415,10 +451,8 @@ error.undofailed.title=Undo isch fehlgschlage worde
 error.undofailed.text=Operation kann nöd rückgängig gmacht werde
 error.function.noop.title=Funktion hät gar nüüt gmacht
 error.rearrange.noop=Waypoints Reorganisierig hät kei Effäkt gha
-error.function.notimplemented=Sorry, d'Funktion isch nonig implementiert worde.
 error.function.notavailable.title=Funktion nöd verfüegbar
 error.function.nojava3d=Sorry, d'Funktion brucht d Java3d Library,\nvo Sun.com erhältlech.
-error.3d.title=Fähler mitere 3d Darstellig
 error.3d=N Fähler isch mitere 3d Darstellig ufgtrete
 error.readme.notfound=Läs mi File nöd gfunde
 error.osmimage.dialogtitle=Fähle bim Bildli-Lade
similarity index 86%
rename from tim/prune/lang/prune-texts.properties
rename to tim/prune/lang/prune-texts_en.properties
index 53a65b026246171911219cd9637ae3acd640302a..f76bd364b467ce44c22994ac6d9b58860244b225 100644 (file)
@@ -5,11 +5,7 @@
 menu.file=File
 menu.file.open=Open file
 menu.file.addphotos=Add photos
-menu.file.loadfromgps=Load from GPS
 menu.file.save=Save
-menu.file.exportkml=Export KML
-menu.file.exportgpx=Export GPX
-menu.file.exportpov=Export POV
 menu.file.exit=Exit
 menu.edit=Edit
 menu.edit.undo=Undo
@@ -18,11 +14,10 @@ menu.edit.editpoint=Edit point
 menu.edit.editwaypointname=Edit waypoint name
 menu.edit.deletepoint=Delete point
 menu.edit.deleterange=Delete range
-menu.edit.deleteduplicates=Delete duplicates
-menu.edit.compress=Compress track
+menu.edit.deletemarked=Delete marked points
 menu.edit.interpolate=Interpolate
+menu.edit.average=Average selection
 menu.edit.reverse=Reverse range
-menu.edit.addtimeoffset=Add time offset
 menu.edit.mergetracksegments=Merge track segments
 menu.edit.rearrange=Rearrange waypoints
 menu.edit.rearrange.start=All to start of file
@@ -38,16 +33,14 @@ menu.photo=Photo
 menu.photo.saveexif=Save to Exif
 menu.photo.connect=Connect to point
 menu.photo.disconnect=Disconnect from point
-menu.photo.correlate=Correlate all photos
 menu.photo.delete=Remove photo
 menu.view=View
-menu.view.show3d=Show in three-D
 menu.view.browser=Map in browser
 menu.view.browser.google=Google maps
 menu.view.browser.openstreetmap=Openstreetmap
+menu.view.browser.mapquest=Mapquest
+menu.view.browser.yahoo=Yahoo maps
 menu.help=Help
-menu.help.about=About Prune
-menu.help.checkversion=Check for new version
 # Popup menu for map
 menu.map.zoomin=Zoom in
 menu.map.zoomout=Zoom out
@@ -57,6 +50,23 @@ menu.map.connect=Connect track points
 menu.map.autopan=Autopan
 menu.map.showmap=Show map
 
+# Functions
+function.loadfromgps=Load data from GPS
+function.sendtogps=Send data to GPS
+function.exportkml=Export KML
+function.exportgpx=Export GPX
+function.exportpov=Export POV
+function.compress=Compress track
+function.addtimeoffset=Add time offset
+function.charts=Charts
+function.show3d=Three-D view
+function.distances=Distances
+function.setmapbg=Set map background
+function.correlatephotos=Correlate photos
+function.help=Help
+function.about=About Prune
+function.checkversion=Check for new version
+
 # Dialogs
 dialog.exit.confirm.title=Exit Prune
 dialog.exit.confirm.text=Your data is not saved. Are you sure you want to exit?
@@ -66,11 +76,6 @@ dialog.deletepoint.title=Delete Point
 dialog.deletepoint.deletephoto=Delete photo attached to this point?
 dialog.deletephoto.title=Delete Photo
 dialog.deletephoto.deletepoint=Delete point attached to this photo?
-dialog.deleteduplicates.title=Delete Duplicates
-dialog.deleteduplicates.nonefound=No duplicates found
-dialog.compresstrack.title=Compress Track
-dialog.compresstrack.parameter.text=Parameter for compression (lower number = more compression)
-dialog.compresstrack.nonefound=No data points could be removed
 dialog.openoptions.title=Open options
 dialog.openoptions.filesnippet=Extract of file
 dialog.load.table.field=Field
@@ -85,19 +90,20 @@ dialog.delimiter.other=Other
 dialog.openoptions.deliminfo.records=records, with
 dialog.openoptions.deliminfo.fields=fields
 dialog.openoptions.deliminfo.norecords=No records
-dialog.openoptions.tabledesc=Extract of file
 dialog.openoptions.altitudeunits=Altitude units
 dialog.jpegload.subdirectories=Include subdirectories
 dialog.jpegload.loadjpegswithoutcoords=Include photos without coordinates
 dialog.jpegload.loadjpegsoutsidearea=Include photos outside current area
 dialog.jpegload.progress.title=Loading photos
 dialog.jpegload.progress=Please wait while the photos are searched
-dialog.gpsload.title=Load from GPS
 dialog.gpsload.nogpsbabel=No gpsbabel program could be found. Continue?
 dialog.gpsload.device=Device name
 dialog.gpsload.format=Format
 dialog.gpsload.getwaypoints=Load waypoints
 dialog.gpsload.gettracks=Load tracks
+dialog.gpssend.sendwaypoints=Send waypoints
+dialog.gpssend.sendtracks=Send tracks
+dialog.gpssend.trackname=Track name
 dialog.saveoptions.title=Save file
 dialog.save.fieldstosave=Fields to save
 dialog.save.table.field=Field
@@ -109,16 +115,13 @@ dialog.save.altitudeunits=Altitude units
 dialog.save.timestampformat=Timestamp format
 dialog.save.overwrite.title=File already exists
 dialog.save.overwrite.text=This file already exists. Are you sure you want to overwrite the file?
-dialog.exportkml.title=Export KML
 dialog.exportkml.text=Title for the data
 dialog.exportkml.altitude=Include altitudes (for aviation)
 dialog.exportkml.kmz=Compress to make kmz file
 dialog.exportkml.exportimages=Export image thumbnails to kmz
-dialog.exportgpx.title=Export GPX
 dialog.exportgpx.name=Name
 dialog.exportgpx.desc=Description
 dialog.exportgpx.includetimestamps=Include timestamps
-dialog.exportpov.title=Export POV
 dialog.exportpov.text=Please enter the parameters for the POV export
 dialog.exportpov.font=Font
 dialog.exportpov.camerax=Camera X
@@ -152,7 +155,6 @@ dialog.pointnameedit.name=Waypoint name
 dialog.pointnameedit.uppercase=UPPER case
 dialog.pointnameedit.lowercase=lower case
 dialog.pointnameedit.sentencecase=Sentence Case
-dialog.addtimeoffset.title=Add time offset
 dialog.addtimeoffset.add=Add time
 dialog.addtimeoffset.subtract=Subtract time
 dialog.addtimeoffset.days=Days
@@ -172,7 +174,26 @@ dialog.saveexif.photostatus.connected=Connected
 dialog.saveexif.photostatus.disconnected=Disconnected
 dialog.saveexif.photostatus.modified=Modified
 dialog.saveexif.overwrite=Overwrite files
-dialog.correlate.title=Correlate photos
+dialog.charts.xaxis=X axis
+dialog.charts.yaxis=Y axes
+dialog.charts.output=Output
+dialog.charts.screen=Output to screen
+dialog.charts.svg=Output to SVG file
+dialog.charts.svgwidth=SVG width
+dialog.charts.svgheight=SVG height
+dialog.charts.needaltitudeortimes=The track must have either altitudes or time information in order to create charts
+dialog.charts.gnuplotpath=Path to gnuplot
+dialog.charts.gnuplotnotfound=Could not find gnuplot with the given path
+dialog.distances.intro=Straight line distances between points
+dialog.distances.column.from=From point
+dialog.distances.column.to=To point
+dialog.distances.currentpoint=Current point
+dialog.distances.toofewpoints=This function needs waypoints in order to calculate the distances between them
+dialog.setmapbg.mapnik=Mapnik (default)
+dialog.setmapbg.osma=Osma
+dialog.setmapbg.cyclemap=Cyclemap
+dialog.setmapbg.other=Other
+dialog.setmapbg.server=Server URL
 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.photoselect.intro=Select one of these correlated photos to use as the time offset
@@ -195,8 +216,16 @@ dialog.correlate.options.nodistancelimit=No distance limit
 dialog.correlate.options.distancelimit=Distance limit
 dialog.correlate.options.correlate=Correlate
 dialog.correlate.alloutsiderange=All photos are outside the time range of the track, so none can be correlated.\nTry changing the offset or manually correlating at least one photo.
+dialog.compress.nonefound=No data points could be removed
+dialog.compress.duplicates.title=Duplicate removal
+dialog.compress.closepoints.title=Nearby point removal
+dialog.compress.closepoints.paramdesc=Span factor
+dialog.compress.wackypoints.title=Wacky point removal
+dialog.compress.wackypoints.paramdesc=Distance factor
+dialog.compress.singletons.title=Singleton removal
+dialog.compress.singletons.paramdesc=Distance factor
+dialog.compress.summarylabel=Points to delete
 dialog.help.help=Please see\n http://activityworkshop.net/software/prune/\nfor more information and user guides.
-dialog.about.title=About Prune
 dialog.about.version=Version
 dialog.about.build=Build
 dialog.about.summarytext1=Prune is a program for loading, displaying and editing data from GPS receivers.
@@ -211,6 +240,7 @@ dialog.about.systeminfo.java3d=Java3d installed
 dialog.about.systeminfo.povray=Povray installed
 dialog.about.systeminfo.exiftool=Exiftool installed
 dialog.about.systeminfo.gpsbabel=Gpsbabel installed
+dialog.about.systeminfo.gnuplot=Gnuplot installed
 dialog.about.yes=Yes
 dialog.about.no=No
 dialog.about.credits=Credits
@@ -223,7 +253,6 @@ dialog.about.credits.devtools=Development tools
 dialog.about.credits.othertools=Other tools
 dialog.about.credits.thanks=Thanks to
 dialog.about.readme=Readme
-dialog.checkversion.title=Check version
 dialog.checkversion.error=The version number couldn't be checked.\nPlease check the internet connection.
 dialog.checkversion.uptodate=You are using the latest version of Prune.
 dialog.checkversion.newversion1=A new version of Prune is now available!  The latest version is now version
@@ -243,8 +272,6 @@ dialog.3dlines.intro=These are the gridlines for the three-d view
 confirm.loadfile=Data loaded from file
 confirm.save.ok1=Successfully saved
 confirm.save.ok2=points to file
-confirm.deleteduplicates.single=duplicate was deleted
-confirm.deleteduplicates.multi=duplicates were deleted
 confirm.deletepoint.single=data point was removed
 confirm.deletepoint.multi=data points were removed
 confirm.point.edit=point edited
@@ -288,14 +315,17 @@ button.selectnone=Select none
 button.preview=Preview
 button.guessfields=Guess fields
 button.showwebpage=Show webpage
+button.gnuplotpath=Set gnuplot path
 
 # File types
 filetype.txt=TXT files
 filetype.jpeg=JPG files
 filetype.kmlkmz=KML, KMZ files
 filetype.kml=KML files
+filetype.kmz=KMZ files
 filetype.gpx=GPX files
 filetype.pov=POV files
+filetype.svg=SVG files
 
 # Display components
 display.nodata=No data loaded
@@ -309,7 +339,6 @@ details.pointdetails=Point details
 details.index.selected=Index
 details.index.of=of
 details.nopointselection=No point selected
-details.speed=Speed
 details.photofile=Photo file
 details.norangeselection=No range selected
 details.rangedetails=Range details
@@ -332,12 +361,14 @@ details.photodetails=Photo details
 details.nophoto=No photo selected
 details.photo.loading=Loading
 details.photo.connected=Connected
+map.overzoom=No maps available at this zoom level
 
 # Field names
 fieldname.latitude=Latitude
 fieldname.longitude=Longitude
 fieldname.altitude=Altitude
 fieldname.timestamp=Time
+fieldname.time=Time
 fieldname.waypointname=Name
 fieldname.waypointtype=Type
 fieldname.newsegment=Segment
@@ -346,6 +377,8 @@ fieldname.prefix=Field
 fieldname.distance=Distance
 fieldname.movingdistance=Moving distance
 fieldname.duration=Duration
+fieldname.speed=Speed
+fieldname.verticalspeed=Vertical speed
 
 # Measurement units
 units.original=Original
@@ -360,6 +393,9 @@ units.kmh=km/h
 units.miles=Miles
 units.miles.short=mi
 units.mph=mph
+units.metrespersec=m/s
+units.feetpersec=ft/s
+units.hours=hours
 units.degminsec=Deg-min-sec
 units.degmin=Deg-min
 units.deg=Degrees
@@ -383,7 +419,6 @@ undo.deletephoto=remove photo
 undo.deleterange=delete range
 undo.compress=compress track
 undo.insert=insert points
-undo.deleteduplicates=delete duplicates
 undo.reverse=reverse range
 undo.mergetracksegments=merge track segments
 undo.addtimeoffset=add time offset
@@ -405,6 +440,7 @@ error.load.dialogtitle=Error loading data
 error.load.noread=Cannot read file
 error.load.nopoints=No coordinate information found in the file
 error.load.unknownxml=Unrecognised xml format:
+error.load.noxmlinzip=No xml file found inside zip file
 error.load.othererror=Error reading file:
 error.jpegload.dialogtitle=Error loading photos
 error.jpegload.nofilesfound=No files found
@@ -415,10 +451,8 @@ error.undofailed.title=Undo failed
 error.undofailed.text=Failed to undo operation
 error.function.noop.title=Function had no effect
 error.rearrange.noop=Rearranging waypoints had no effect
-error.function.notimplemented=Sorry, this function has not yet been implemented.
 error.function.notavailable.title=Function not available
 error.function.nojava3d=This function requires the Java3d library,\navailable from Sun.com.
-error.3d.title=Error in 3d display
 error.3d=An error occurred with the 3d display
 error.readme.notfound=Readme file not found
 error.osmimage.dialogtitle=Error loading map images
index cfa1a09d6c72faa2b9ec298b9e56be0deec467f8..6dbaddbbef35d0dfe10685adddf10b1f0186b9b1 100644 (file)
@@ -5,11 +5,7 @@
 menu.file=Archivo
 menu.file.open=Abrir archivo
 menu.file.addphotos=Cargar fotos
-menu.file.loadfromgps=Cargar datos del GPS
 menu.file.save=Guardar
-menu.file.exportkml=Exportar KML
-menu.file.exportgpx=Exportar GPX
-menu.file.exportpov=Exportar POV
 menu.file.exit=Salir
 menu.edit=Editar
 menu.edit.undo=Deshacer
@@ -18,11 +14,10 @@ menu.edit.editpoint=Editar punto
 menu.edit.editwaypointname=Editar nombre de waypoint
 menu.edit.deletepoint=Eliminar punto
 menu.edit.deleterange=Eliminar rango
-menu.edit.deleteduplicates=Eliminar duplicados
-menu.edit.compress=Comprimir track
+menu.edit.deletemarked=
 menu.edit.interpolate=Interpolar
+menu.edit.average=Crear punto a la media del rango
 menu.edit.reverse=Invertir rango
-menu.edit.addtimeoffset=
 menu.edit.mergetracksegments=Unir los segmentos de track
 menu.edit.rearrange=Reorganizar waypoints
 menu.edit.rearrange.start=Volver al comienzo
@@ -38,16 +33,14 @@ menu.photo=Foto
 menu.photo.saveexif=Guardar Exif
 menu.photo.connect=Conectar con punto
 menu.photo.disconnect=Desconectar de punto
-menu.photo.correlate=Correlacionar todas las fotos
 menu.photo.delete=Eliminar foto
 menu.view=Ver
-menu.view.show3d=Mostrar en 3-D
 menu.view.browser=Mapa en un navegador
 menu.view.browser.google=Google maps
 menu.view.browser.openstreetmap=Openstreetmap
+menu.view.browser.mapquest=
+menu.view.browser.yahoo=
 menu.help=Ayuda
-menu.help.about=Acerca de Prune
-menu.help.checkversion=Buscar una nueva versión
 # Popup menu for map
 menu.map.zoomin=Ampliar zoom
 menu.map.zoomout=Reducir zoom
@@ -57,6 +50,23 @@ menu.map.connect=Conectar puntos de track
 menu.map.autopan=Posicionar automáticamente
 menu.map.showmap=Mostrar el mapa
 
+# Functions
+function.loadfromgps=Cargar datos del GPS
+function.sendtogps=Enviar datos al GPS
+function.exportkml=Exportar KML
+function.exportgpx=Exportar GPX
+function.exportpov=Exportar POV
+function.compress=Comprimir Track
+function.addtimeoffset=
+function.charts=Diagramas
+function.show3d=Mostrar en 3-D
+function.distances=Distancias
+function.setmapbg=Configurar fondo de mapa
+function.correlatephotos=Correlacionar fotos
+function.help=Ayuda
+function.about=Acerca de Prune
+function.checkversion=Buscar una nueva versión
+
 # Dialogs
 dialog.exit.confirm.title=Salir de Prune
 dialog.exit.confirm.text=Los datos han sido modificados. Desea salir de Prune?
@@ -66,11 +76,6 @@ dialog.deletepoint.title=Borrar punto
 dialog.deletepoint.deletephoto=Borrar la foto tambien?
 dialog.deletephoto.title=Borrar foto
 dialog.deletephoto.deletepoint=Borrar el punto tambien?
-dialog.deleteduplicates.title=Borrar duplicados
-dialog.deleteduplicates.nonefound=Ningún duplicado encontrado
-dialog.compresstrack.title=Comprimir Track
-dialog.compresstrack.parameter.text=Parámetro para comprimir (menor valor => mayor compresión)
-dialog.compresstrack.nonefound=Ningún punto eliminado
 dialog.openoptions.title=Opciones de abrir
 dialog.openoptions.filesnippet=Extraer archivo
 dialog.load.table.field=Campo
@@ -85,19 +90,20 @@ dialog.delimiter.other=Otro
 dialog.openoptions.deliminfo.records=datos, con
 dialog.openoptions.deliminfo.fields=campos
 dialog.openoptions.deliminfo.norecords=Ningun dato
-dialog.openoptions.tabledesc=Extraer archivo
 dialog.openoptions.altitudeunits=Unidades altitud
 dialog.jpegload.subdirectories=Incluir subdirectorios
 dialog.jpegload.loadjpegswithoutcoords=Fotos sin coordenadas tambien
 dialog.jpegload.loadjpegsoutsidearea=
 dialog.jpegload.progress.title=Cargando fotos
 dialog.jpegload.progress=Por favor espere mientras se buscan las fotos
-dialog.gpsload.title=
 dialog.gpsload.nogpsbabel=gpsbabel program no encontrado. Desea continuar?
 dialog.gpsload.device=
 dialog.gpsload.format=
 dialog.gpsload.getwaypoints=
 dialog.gpsload.gettracks=
+dialog.gpssend.sendwaypoints=
+dialog.gpssend.sendtracks=
+dialog.gpssend.trackname=Nombre del track
 dialog.saveoptions.title=Guardar archivo
 dialog.save.fieldstosave=Campos a guardar
 dialog.save.table.field=Campo
@@ -109,16 +115,13 @@ dialog.save.altitudeunits=Unidades de las altitudes
 dialog.save.timestampformat=Format del tiempo
 dialog.save.overwrite.title=El archivo ya existe
 dialog.save.overwrite.text=El archivo ya existe, desea sobreescribirlo?
-dialog.exportkml.title=Exportar KML
 dialog.exportkml.text=Descripción para los datos
 dialog.exportkml.altitude=Incluir altitudes (para aviación)
 dialog.exportkml.kmz=Comprimir al archivo kmz
 dialog.exportkml.exportimages=Exportar fotos al kmz
-dialog.exportgpx.title=Exportar GPX
 dialog.exportgpx.name=Nombre
 dialog.exportgpx.desc=Descripción
 dialog.exportgpx.includetimestamps=Tiempo tambien
-dialog.exportpov.title=Exportar POV
 dialog.exportpov.text=Introdzca los Parametros para exportar
 dialog.exportpov.font=Fuente
 dialog.exportpov.camerax=Cámara X
@@ -152,7 +155,6 @@ dialog.pointnameedit.name=Nombre de waypoint
 dialog.pointnameedit.uppercase=Mayúsculas
 dialog.pointnameedit.lowercase=minúsculas
 dialog.pointnameedit.sentencecase=Mezcla
-dialog.addtimeoffset.title=
 dialog.addtimeoffset.add=
 dialog.addtimeoffset.subtract=
 dialog.addtimeoffset.days=Dias
@@ -172,7 +174,26 @@ dialog.saveexif.photostatus.connected=Conectada
 dialog.saveexif.photostatus.disconnected=Desconectada
 dialog.saveexif.photostatus.modified=Modificada
 dialog.saveexif.overwrite=Sobreescribirlar archivos?
-dialog.correlate.title=Correlacionar fotos
+dialog.charts.xaxis=Eje de abscisas
+dialog.charts.yaxis=Eje vertical
+dialog.charts.output=
+dialog.charts.screen=
+dialog.charts.svg=
+dialog.charts.svgwidth=
+dialog.charts.svgheight=
+dialog.charts.needaltitudeortimes=
+dialog.charts.gnuplotpath=
+dialog.charts.gnuplotnotfound=
+dialog.distances.intro=
+dialog.distances.column.from=De punto
+dialog.distances.column.to=Al punto
+dialog.distances.currentpoint=Punto actual
+dialog.distances.toofewpoints=
+dialog.setmapbg.mapnik=Mapnik (por defecto)
+dialog.setmapbg.osma=
+dialog.setmapbg.cyclemap=
+dialog.setmapbg.other=Otro
+dialog.setmapbg.server=
 dialog.correlate.notimestamps=No hay información de tiempo para los puntos, así que no hay nada que correlacionar con las fotos.
 dialog.correlate.nouncorrelatedphotos=No hay fotos no correlacionadas.\nEstá seguro de que desea continuar?
 dialog.correlate.photoselect.intro=Seleccione una de estas fotos correlacionadas para usar como margen de tiempo
@@ -195,8 +216,16 @@ dialog.correlate.options.nodistancelimit=Sin l
 dialog.correlate.options.distancelimit=Límite de distancia
 dialog.correlate.options.correlate=Correlacionar
 dialog.correlate.alloutsiderange=Todas las fotos están fuera del margen horario del track, por lo que ninguna puede ser correlada.\nIntente cambiar el margen o correle manualmente al menos una foto.
+dialog.compress.nonefound=Ningún punto eliminado
+dialog.compress.duplicates.title=Eliminar duplicados
+dialog.compress.closepoints.title=
+dialog.compress.closepoints.paramdesc=
+dialog.compress.wackypoints.title=
+dialog.compress.wackypoints.paramdesc=
+dialog.compress.singletons.title=
+dialog.compress.singletons.paramdesc=
+dialog.compress.summarylabel=
 dialog.help.help=Por favor, ver\n http://activityworkshop.net/software/prune/\npara más información y guías del usuario.
-dialog.about.title=Acerca de Prune
 dialog.about.version=Versión
 dialog.about.build=Construir
 dialog.about.summarytext1=Prune es un programa para cargar, mostrar y editar datos de receptores GPS.
@@ -211,6 +240,7 @@ dialog.about.systeminfo.java3d=Java3d instalado
 dialog.about.systeminfo.povray=Povray instalado
 dialog.about.systeminfo.exiftool=Exiftool instalado
 dialog.about.systeminfo.gpsbabel=Gpsbabel instalado
+dialog.about.systeminfo.gnuplot=Gnuplot instalado
 dialog.about.yes=Si
 dialog.about.no=No
 dialog.about.credits=Credits
@@ -223,7 +253,6 @@ dialog.about.credits.devtools=Herramientas de desarrollo
 dialog.about.credits.othertools=Otras herramientas
 dialog.about.credits.thanks=Gracias a
 dialog.about.readme=Readme
-dialog.checkversion.title=
 dialog.checkversion.error=
 dialog.checkversion.uptodate=
 dialog.checkversion.newversion1=
@@ -243,8 +272,6 @@ dialog.3dlines.intro=Informaci
 confirm.loadfile=Dato cargado de
 confirm.save.ok1=Guardando
 confirm.save.ok2=puntos al archivo
-confirm.deleteduplicates.single=duplicado eliminado
-confirm.deleteduplicates.multi=duplicados eliminados
 confirm.deletepoint.single=punto eliminado
 confirm.deletepoint.multi=puntos eliminados
 confirm.point.edit=Punto editado
@@ -288,14 +315,17 @@ button.selectnone=Seleccionar nada
 button.preview=Previsualización
 button.guessfields=Adivinar campos
 button.showwebpage=
+button.gnuplotpath=
 
 # File types
 filetype.txt=Archivos TXT
 filetype.jpeg=Archivos JPG
 filetype.kmlkmz=Archivos KML, KMZ
 filetype.kml=Archivos KML
+filetype.kmz=Archivos KMZ
 filetype.gpx=Archivos GPX
 filetype.pov=Archivos POV
+filetype.svg=Archivos SVG
 
 # Display components
 display.nodata=Ningún dato cargado
@@ -309,7 +339,6 @@ details.pointdetails=Detalles del punto
 details.index.selected=Indice seleccionado
 details.index.of=de
 details.nopointselection=Ningún punto seleccionado
-details.speed=Velocidad
 details.photofile=Archivo de fotos
 details.norangeselection=Ningún rango seleccionado
 details.rangedetails=Detalles del rango
@@ -332,12 +361,14 @@ details.photodetails=Detalles del Foto
 details.nophoto=Ninguna foto seleccionada
 details.photo.loading=Cargando
 details.photo.connected=Conectada
+map.overzoom=
 
 # Field names
 fieldname.latitude=Latitud
 fieldname.longitude=Longitud
 fieldname.altitude=Altitud
 fieldname.timestamp=Información de tiempo
+fieldname.time=Tiempo
 fieldname.waypointname=Nombre
 fieldname.waypointtype=Tipo
 fieldname.newsegment=Segmento
@@ -346,6 +377,8 @@ fieldname.prefix=Campo
 fieldname.distance=Distancia
 fieldname.movingdistance=
 fieldname.duration=Duración
+fieldname.speed=Velocidad
+fieldname.verticalspeed=
 
 # Measurement units
 units.original=Original
@@ -360,6 +393,9 @@ units.kmh=km/h
 units.miles=Millas
 units.miles.short=mi
 units.mph=mi/h
+units.metrespersec=m/s
+units.feetpersec=ft/s
+units.hours=horas
 units.degminsec=Gra-min-seg
 units.degmin=Gra-min
 units.deg=Grados
@@ -383,7 +419,6 @@ undo.deletephoto=eliminar foto
 undo.deleterange=eliminar rango
 undo.compress=comprimir track
 undo.insert=insertar puntos
-undo.deleteduplicates=eliminar duplicados
 undo.reverse=invertir rango
 undo.mergetracksegments=unir los segmentos de track
 undo.addtimeoffset=
@@ -405,6 +440,7 @@ error.load.dialogtitle=Fallo al cargar datos
 error.load.noread=No se puede leer el fichero
 error.load.nopoints=Ninguna información coordenadas encontrada
 error.load.unknownxml=Formato xml no reconocido:
+error.load.noxmlinzip=
 error.load.othererror=Fallo al cargar datos:
 error.jpegload.dialogtitle=Error cargando fotos
 error.jpegload.nofilesfound=Ningún archivo encontrado
@@ -415,10 +451,8 @@ error.undofailed.title=Fallo al deshacer
 error.undofailed.text=No ha sido posible deshacer la operación
 error.function.noop.title=La función no se ha efectuado
 error.rearrange.noop=Reordenación de waypoints no se ha efectuado
-error.function.notimplemented=Esta función aún no ha sido implementada
 error.function.notavailable.title=Función no disponible
 error.function.nojava3d=Esta función requiere la librería Java3d, disponible en Sun.com.
-error.3d.title=Fallo al mostrar 3-D
 error.3d=Ha ocurrido un error con la función 3-D
 error.readme.notfound=Archivo readme no encontrado
 error.osmimage.dialogtitle=Error al cargar el mapa
index 0926a554340ba1928582fb3f2208e466942849fa..c76eb66ce48243cde2db31cbfe56a004ac8ff803 100644 (file)
@@ -4,12 +4,8 @@
 # Menu entries
 menu.file=Fichier
 menu.file.open=Ouvrir fichier
-menu.file.addphotos=Ouvrir photos
-menu.file.loadfromgps=Charger Ã  partir du GPS
+menu.file.addphotos=Ajouter photos
 menu.file.save=Enregistrer
-menu.file.exportkml=Exporter en KML
-menu.file.exportgpx=Exporter en GPX
-menu.file.exportpov=Exporter en POV
 menu.file.exit=Quitter
 menu.edit=Édition
 menu.edit.undo=Annuler
@@ -18,17 +14,16 @@ menu.edit.editpoint=Editer le point
 menu.edit.editwaypointname=Editer le nom du waypoint
 menu.edit.deletepoint=Supprimer le point
 menu.edit.deleterange=Supprimer l'étendue
-menu.edit.deleteduplicates=Supprimer les doublons
-menu.edit.compress=Compacter la trace
+menu.edit.deletemarked=Supprimer les points marqués
 menu.edit.interpolate=Interpoler
+menu.edit.average=Créer un point pour la sélection
 menu.edit.reverse=Inverser l'étendue
-menu.edit.addtimeoffset=
 menu.edit.mergetracksegments=Fusionner les segments de trace
 menu.edit.rearrange=Réarranger les waypoints
 menu.edit.rearrange.start=Tous au début du fichier
 menu.edit.rearrange.end=Tous Ã  la fin du fichier
 menu.edit.rearrange.nearest=Chacun au point de trace le plus proche
-menu.edit.cutandmove=
+menu.edit.cutandmove=Couper et bouger la sélection
 menu.select=Sélectionner
 menu.select.all=Tout sélectionner
 menu.select.none=Rien sélectionner
@@ -38,39 +33,49 @@ menu.photo=Photo
 menu.photo.saveexif=Enregistrer dans les Exif
 menu.photo.connect=Relier au point
 menu.photo.disconnect=Détacher du point
-menu.photo.correlate=Corréler toutes les photos
 menu.photo.delete=Retirer la photo
 menu.view=Affichage
-menu.view.show3d=Montrer en 3D
 menu.view.browser=Ouvrir la carte dans le navigateur
 menu.view.browser.google=Google maps
 menu.view.browser.openstreetmap=Openstreetmap
+menu.view.browser.mapquest=Mapquest
+menu.view.browser.yahoo=Yahoo maps
 menu.help=Aide
-menu.help.about=À propos de Prune
-menu.help.checkversion=
 # Popup menu for map
 menu.map.zoomin=Zoom avant
 menu.map.zoomout=Zoom arrière
 menu.map.zoomfull=Adapter Ã  la vue
-menu.map.newpoint=
+menu.map.newpoint=Ajouter un point
 menu.map.connect=Relier les points de trace
 menu.map.autopan=Déplacement automatique
 menu.map.showmap=Montrer la carte
 
+# Functions
+function.loadfromgps=Télécharger du GPS
+function.sendtogps=Envoyer au GPS
+function.exportkml=Exporter en KML
+function.exportgpx=Exporter en GPX
+function.exportpov=Exporter en POV
+function.compress=Compresser la trace
+function.addtimeoffset=Ajouter un décalage d'horaire
+function.charts=Graphiques
+function.show3d=Montrer en 3D
+function.distances=Distances
+function.setmapbg=Définir le fond de carte
+function.correlatephotos=Corréler les photos
+function.help=Aide
+function.about=À propos de Prune
+function.checkversion=Chercher une mise Ã  jour
+
 # Dialogs
 dialog.exit.confirm.title=Quitter Prune
-dialog.exit.confirm.text=Les données ont Ã©té modifiées. Souhaitez-vous quitter Prune sans enregistrer ?
+dialog.exit.confirm.text=Les données ont Ã©té modifiées. Souhaitez-vous quitter Prune sans les enregistrer ?
 dialog.openappend.title=Ajouter aux données existantes
 dialog.openappend.text=Ajouter aux données déjà chargées ?
 dialog.deletepoint.title=Effacer le point
 dialog.deletepoint.deletephoto=Effacer la photo attachée Ã  ce point ?
 dialog.deletephoto.title=Effacer la photo
 dialog.deletephoto.deletepoint=Effacer le point attaché Ã  cette photo ?
-dialog.deleteduplicates.title=Effacer les doublons
-dialog.deleteduplicates.nonefound=Aucun doublon trouvé
-dialog.compresstrack.title=Compresser la trace
-dialog.compresstrack.parameter.text=Paramètre pour la compression (faible chiffre = forte compression)
-dialog.compresstrack.nonefound=Pas de données Ã  effacer
 dialog.openoptions.title=Ouvrir options
 dialog.openoptions.filesnippet=Extrait de fichier
 dialog.load.table.field=Champ
@@ -85,19 +90,20 @@ dialog.delimiter.other=Autres
 dialog.openoptions.deliminfo.records=enregistrements, avec
 dialog.openoptions.deliminfo.fields=champs
 dialog.openoptions.deliminfo.norecords=Pas d'enregistrements
-dialog.openoptions.tabledesc=Extrait de fichier
 dialog.openoptions.altitudeunits=Unités d'altitude
 dialog.jpegload.subdirectories=Inclure les sous-dossiers
 dialog.jpegload.loadjpegswithoutcoords=Inclure les photos sans coordonnées
-dialog.jpegload.loadjpegsoutsidearea=
+dialog.jpegload.loadjpegsoutsidearea=Inclure des photos en dehors de l'endroit actuel
 dialog.jpegload.progress.title=Chargement des photos
 dialog.jpegload.progress=Veuillez patienter pendant la recherche des photos
-dialog.gpsload.title=
 dialog.gpsload.nogpsbabel=Gpsbabel introuvable. Continuer ?
-dialog.gpsload.device=
-dialog.gpsload.format=
-dialog.gpsload.getwaypoints=
-dialog.gpsload.gettracks=
+dialog.gpsload.device=Chemin du périphérique
+dialog.gpsload.format=Format
+dialog.gpsload.getwaypoints=Télécharger les waypoints
+dialog.gpsload.gettracks=Télécharger les traces
+dialog.gpssend.sendwaypoints=Envoyer les waypoints
+dialog.gpssend.sendtracks=Envoyer les traces
+dialog.gpssend.trackname=Nom de trace
 dialog.saveoptions.title=Enregistrer le fichier
 dialog.save.fieldstosave=Champs Ã  enregistrer
 dialog.save.table.field=Champ
@@ -109,29 +115,26 @@ dialog.save.altitudeunits=Unit
 dialog.save.timestampformat=Format de l'heure
 dialog.save.overwrite.title=Le fichier existe déjà
 dialog.save.overwrite.text=Ce fichier existe déjà. ÃŠtes-vous sûr de vouloir Ã©craser ce fichier ?
-dialog.exportkml.title=Exporter en KML
 dialog.exportkml.text=Titre pour les données
 dialog.exportkml.altitude=Inclure les altitudes (pour aviation)
 dialog.exportkml.kmz=Compresser au format kmz
 dialog.exportkml.exportimages=Exporter les vignettes au format kmz
-dialog.exportgpx.title=Exporter en GPX
 dialog.exportgpx.name=Nom
 dialog.exportgpx.desc=Légende
-dialog.exportgpx.includetimestamps=
-dialog.exportpov.title=Exporter en POV
+dialog.exportgpx.includetimestamps=Inclure l'heure pour chaque point
 dialog.exportpov.text=Entrez les paramètres pour l'export POV
 dialog.exportpov.font=Police
-dialog.exportpov.camerax=Camera X
-dialog.exportpov.cameray=Camera Y
-dialog.exportpov.cameraz=Camera Z
-dialog.exportpov.modelstyle=
-dialog.exportpov.ballsandsticks=
-dialog.exportpov.tubesandwalls=
-dialog.exportpov.warningtracksize=Cette trace possède un grand nombre de points, Java3D peut ne pas pouvoir l'afficher.\nEtes-vous sûr de vouloir continuer ?
+dialog.exportpov.camerax=Caméra X
+dialog.exportpov.cameray=Caméra Y
+dialog.exportpov.cameraz=Caméra Z
+dialog.exportpov.modelstyle=Style du modèle
+dialog.exportpov.ballsandsticks=Points et bâtons
+dialog.exportpov.tubesandwalls=Tubes et murs
+dialog.exportpov.warningtracksize=Cette trace possède un grand nombre de points, Java3D peut ne pas pouvoir l'afficher.\nÊtes-vous sûr de vouloir continuer ?
 dialog.confirmreversetrack.title=Confirmer l'inversion
-dialog.confirmreversetrack.text=Cette trace contient des informations temporelles qui seront désordonnées après une inversion.\nEtes-vous sûr de vouloir inverser cette section ?
-dialog.confirmcutandmove.title=Confirmer ...
-dialog.confirmcutandmove.text=Cette trace contient des informations temporelles qui seront désordonnées après une ....\nEtes-vous sûr de vouloir ... cette section ?
+dialog.confirmreversetrack.text=Cette trace contient des informations temporelles qui seront désordonnées après une inversion.\nÊtes-vous sûr de vouloir inverser cette section ?
+dialog.confirmcutandmove.title=Confirmer le déplacement
+dialog.confirmcutandmove.text=Cette trace contient des informations temporelles qui seront désordonnées après un déplacement.\nÊtes-vous sûr de vouloir déplacer cette section ?
 dialog.interpolate.title=Interpoler les points
 dialog.interpolate.parameter.text=Nombre de points Ã  insérer entre les points sélectionnés
 dialog.undo.title=Annuler les actions
@@ -152,15 +155,14 @@ dialog.pointnameedit.name=Nom de waypoint
 dialog.pointnameedit.uppercase=CASSE MAJUSCULES
 dialog.pointnameedit.lowercase=casse minuscules
 dialog.pointnameedit.sentencecase=Casse Phrase
-dialog.addtimeoffset.title=
-dialog.addtimeoffset.add=
-dialog.addtimeoffset.subtract=
+dialog.addtimeoffset.add=Retarder l'heure
+dialog.addtimeoffset.subtract=Avancer l'heure
 dialog.addtimeoffset.days=Jours
 dialog.addtimeoffset.hours=Heures
 dialog.addtimeoffset.minutes=Minutes
-dialog.addtimeoffset.notimestamps=
-dialog.connect.title=
-dialog.connectphoto.clonepoint=
+dialog.addtimeoffset.notimestamps=Ne peut pas décaler l'heure; cette sélection ne contient pas de données d'heure
+dialog.connect.title=Lier la photo au point
+dialog.connectphoto.clonepoint=Ce point est déjà lié Ã  une photo.\nVoulez-vous faire une copie de ce point ?
 dialog.saveexif.title=Enregistrer Exif
 dialog.saveexif.intro=Sélectionner les photos Ã  sauver Ã  l'aide des cases Ã  cocher
 dialog.saveexif.nothingtosave=Coordonnées inchangées, rien Ã  enregistrer
@@ -172,7 +174,26 @@ dialog.saveexif.photostatus.connected=Connect
 dialog.saveexif.photostatus.disconnected=Déconnecté
 dialog.saveexif.photostatus.modified=Modifié
 dialog.saveexif.overwrite=Ecraser les fichiers
-dialog.correlate.title=Corréler les photos
+dialog.charts.xaxis=Axe des x
+dialog.charts.yaxis=Axe des y
+dialog.charts.output=Sortie
+dialog.charts.screen=Sortie sur Ã©cran
+dialog.charts.svg=Sortie dans un fichier SVG
+dialog.charts.svgwidth=Largeur de l'image SVG
+dialog.charts.svgheight=Hauteur de l'image SVG
+dialog.charts.needaltitudeortimes=La trace ne peut générer des graphiques sans disposer d'altitudes ou d'indications temporelles
+dialog.charts.gnuplotpath=Chemin gnuplot
+dialog.charts.gnuplotnotfound=Gnuplot est introuvable dans le chemin indiqué
+dialog.distances.intro=Distances Ã  vol d'oiseau entre des points
+dialog.distances.column.from=Du point
+dialog.distances.column.to=Vers le point
+dialog.distances.currentpoint=Point courant
+dialog.distances.toofewpoints=Cette fonction a besoin de waypoints pour calculer les distances entre eux
+dialog.setmapbg.mapnik=Mapnik (défaut)
+dialog.setmapbg.osma=Osma
+dialog.setmapbg.cyclemap=Cyclemap
+dialog.setmapbg.other=Autres
+dialog.setmapbg.server=URL du serveur
 dialog.correlate.notimestamps=Les points n'ont pas d'indication de temps, il n'est pas possible de les corréler.
 dialog.correlate.nouncorrelatedphotos=Il n'y a pas de photos non-corrélées.\nVoulez-vous continuer ?
 dialog.correlate.photoselect.intro=Sélectionner une de ces photos corrélées pour définir le décalage de temps
@@ -195,15 +216,23 @@ dialog.correlate.options.nodistancelimit=Pas de limite de distance
 dialog.correlate.options.distancelimit=Limite de distance
 dialog.correlate.options.correlate=Corréler
 dialog.correlate.alloutsiderange=Les photos ne correspondent pas Ã  la plage de temps de la trace, aucune ne peut Ãªtre corrélée.\nEssayez de modifier le décalage ou de corréler manuellement au moins une photo.
+dialog.compress.nonefound=Pas de données Ã  effacer
+dialog.compress.duplicates.title=Suppression des doublons
+dialog.compress.closepoints.title=Suppression des points voisins
+dialog.compress.closepoints.paramdesc=Taille du voisinage
+dialog.compress.wackypoints.title=Suppression des points anormaux
+dialog.compress.wackypoints.paramdesc=Distance
+dialog.compress.singletons.title=Suppression des points isolés
+dialog.compress.singletons.paramdesc=Distance
+dialog.compress.summarylabel=Points Ã  supprimer
 dialog.help.help=Consultez la page\n http://activityworkshop.net/software/prune/\npour plus de détails et des manuels utilisateur.
-dialog.about.title=À propos de Prune
 dialog.about.version=Version
 dialog.about.build=Build
 dialog.about.summarytext1=Prune est un programme pour charger, afficher et Ã©diter des données de récepteurs GPS.
 dialog.about.summarytext2=Distribué sous license Gnu GPL pour un usage et une amélioration libres, ouverts et mondiaux.<br>La copie, la redistribution et la modification sont autorisées et encouragées<br>selon les conditions détaillées dans le fichier <code>license.txt</code> inclus.
 dialog.about.summarytext3=Consultez la page <code style="font-weight:bold">http://activityworkshop.net/</code> pour plus de détails et des manuels utilisateur.
-dialog.about.languages=
-dialog.about.translatedby=Texte en français par Petrovsk.
+dialog.about.languages=Langues disponibles
+dialog.about.translatedby=Texte en français par Petrovsk et theYinYeti.
 dialog.about.systeminfo=Info Système
 dialog.about.systeminfo.os=Système d'exploitation
 dialog.about.systeminfo.java=Java Runtime
@@ -211,6 +240,7 @@ dialog.about.systeminfo.java3d=Java3d install
 dialog.about.systeminfo.povray=Povray installé
 dialog.about.systeminfo.exiftool=Exiftool installé
 dialog.about.systeminfo.gpsbabel=Gpsbabel installé
+dialog.about.systeminfo.gnuplot=Gnuplot installé
 dialog.about.yes=Oui
 dialog.about.no=Non
 dialog.about.credits=Crédits
@@ -223,14 +253,13 @@ dialog.about.credits.devtools=Outils de d
 dialog.about.credits.othertools=Autre outils
 dialog.about.credits.thanks=Merci Ã 
 dialog.about.readme=Lisez-moi
-dialog.checkversion.title=
-dialog.checkversion.error=
-dialog.checkversion.uptodate=
-dialog.checkversion.newversion1=
-dialog.checkversion.newversion2=
-dialog.checkversion.releasedate1=
-dialog.checkversion.releasedate2=
-dialog.checkversion.download=To download the new version, go to http://activityworkshop.net/software/prune/download.html.
+dialog.checkversion.error=Ne peut pas vérifier la version.\nVeuillez vérifier votre connexion Internet.
+dialog.checkversion.uptodate=Vous utilisez déjà la version actuelle de Prune.
+dialog.checkversion.newversion1=La version actuelle est maintenant la version
+dialog.checkversion.newversion2=.
+dialog.checkversion.releasedate1=La nouvelle version est sortie le
+dialog.checkversion.releasedate2=.
+dialog.checkversion.download=Pour télécharger la nouvelle version, aller Ã  http://activityworkshop.net/software/prune/download.html.
 
 # 3d window
 dialog.3d.title=Vue 3D de Prune
@@ -243,16 +272,14 @@ dialog.3dlines.intro=Ceci est la grille pour la vue 3D
 confirm.loadfile=Données chargées depuis le fichier
 confirm.save.ok1=Enregistrement réussi de
 confirm.save.ok2=points dans le fichier
-confirm.deleteduplicates.single=doublon a Ã©té effacé
-confirm.deleteduplicates.multi=doublons ont Ã©té effacés
 confirm.deletepoint.single=point a Ã©té effacé
 confirm.deletepoint.multi=points ont Ã©té effacés
 confirm.point.edit=point Ã©dité
 confirm.mergetracksegments=Segments de trace ont Ã©té fusionné
 confirm.reverserange=Etendue inversée
-confirm.addtimeoffset=
-confirm.rearrangewaypoints=
-confirm.cutandmove=
+confirm.addtimeoffset=Décalage ajouté
+confirm.rearrangewaypoints=Waypoints réarrangés
+confirm.cutandmove=Sélection déplacée
 confirm.saveexif.ok1=Enregistrement de
 confirm.saveexif.ok2=fichiers photo
 confirm.undo.single=opération annulée
@@ -263,7 +290,7 @@ confirm.photo.connect=photo reli
 confirm.photo.disconnect=photo détachée
 confirm.correlate.single=photo a Ã©té corrélée
 confirm.correlate.multi=photos ont Ã©té corrélées
-confirm.createpoint=
+confirm.createpoint=Point créé
 
 # Buttons
 button.ok=OK
@@ -287,15 +314,18 @@ button.selectall=Tout s
 button.selectnone=Ne rien sélectionner
 button.preview=Aperçu
 button.guessfields=Deviner les champs
-button.showwebpage=
+button.showwebpage=Montrer page web
+button.gnuplotpath=Localiser gnuplot
 
 # File types
 filetype.txt=Fichiers TXT
 filetype.jpeg=Fichiers JPG
 filetype.kmlkmz=Fichiers KML, KMZ
 filetype.kml=Fichiers KML
+filetype.kmz=Fichiers KMZ
 filetype.gpx=Fichiers GPX
 filetype.pov=Fichiers POV
+filetype.svg=Fichiers SVG
 
 # Display components
 display.nodata=Pas de données chargées
@@ -309,7 +339,6 @@ details.pointdetails=D
 details.index.selected=Index
 details.index.of=sur
 details.nopointselection=Aucun point choisi
-details.speed=Vitesse
 details.photofile=Fichier photo
 details.norangeselection=Aucune Ã©tendue sélectionnée
 details.rangedetails=Détails sur l'étendue
@@ -325,27 +354,31 @@ display.range.time.mins=m
 display.range.time.hours=h
 display.range.time.days=j
 details.range.avespeed=Vitesse moyenne
-details.range.avemovingspeed=
+details.range.avemovingspeed=Moyenne continue
 details.waypointsphotos.waypoints=Waypoints
 details.waypointsphotos.photos=Photos
 details.photodetails=Détails de la photo
 details.nophoto=Pas de photo
 details.photo.loading=Chargement
 details.photo.connected=Reliée
+map.overzoom=Aucune carte disponible Ã  ce niveau de zoom
 
 # Field names
 fieldname.latitude=Latitude
 fieldname.longitude=Longitude
 fieldname.altitude=Altitude
 fieldname.timestamp=Date et heure
+fieldname.time=Temps
 fieldname.waypointname=Nom
 fieldname.waypointtype=Type
 fieldname.newsegment=Segment
 fieldname.custom=Personnalisé
 fieldname.prefix=Champ
 fieldname.distance=Distance
-fieldname.movingdistance=
+fieldname.movingdistance=Distance continue
 fieldname.duration=Durée
+fieldname.speed=Vitesse
+fieldname.verticalspeed=Vitesse verticale
 
 # Measurement units
 units.original=Original
@@ -360,6 +393,9 @@ units.kmh=km/h
 units.miles=Miles
 units.miles.short=mi
 units.mph=mi/h
+units.metrespersec=m/s
+units.feetpersec=ft/s
+units.hours=heures
 units.degminsec=Deg-min-sec
 units.degmin=Deg-min
 units.deg=Degrés
@@ -383,16 +419,15 @@ undo.deletephoto=retirer la photo
 undo.deleterange=effacer l'étendue
 undo.compress=compresser la trace
 undo.insert=insérer les points
-undo.deleteduplicates=effacer les doublons
 undo.reverse=inverser l'étendue
 undo.mergetracksegments=fusionner les segments de trace
-undo.addtimeoffset=
+undo.addtimeoffset=ajouter décalage d'heure
 undo.rearrangewaypoints=réarranger les waypoints
-undo.cutandmove=
+undo.cutandmove=déplacer la sélection
 undo.connectphoto=relier la photo
 undo.disconnectphoto=détacher la photo
 undo.correlate=corréler les photos
-undo.createpoint=
+undo.createpoint=ajouter un point
 
 # Error messages
 error.save.dialogtitle=Erreur Ã  l'enregistrement des données
@@ -405,6 +440,7 @@ error.load.dialogtitle=Erreur au chargement des donn
 error.load.noread=Fichier illisible
 error.load.nopoints=Aucune coordonnée trouvée dans le fichier
 error.load.unknownxml=Format xml non-reconnu :
+error.load.noxmlinzip=
 error.load.othererror=Erreur Ã  la lecture du fichier :
 error.jpegload.dialogtitle=Erreur au chargement des photos
 error.jpegload.nofilesfound=Aucun fichier trouvé
@@ -415,10 +451,8 @@ error.undofailed.title=Echec de l'annulation
 error.undofailed.text=Echec de l'opération d'annulation
 error.function.noop.title=Fonction sans effet
 error.rearrange.noop=Réarrangement des waypoints sans effet
-error.function.notimplemented=Désolé, cette fonction n'a pas encore Ã©té implémentée.
 error.function.notavailable.title=Function non-disponible
 error.function.nojava3d=Cette fonction nécessite la librairie Java3d,\ndisponible sur Sun.com.
-error.3d.title=Erreur dans l'affichage 3D
 error.3d=Un problème est survenu avec l'affichage 3D
 error.readme.notfound=Fichier Lisez-moi introuvable
 error.osmimage.dialogtitle=Erreur au chargement des portions de cartes
diff --git a/tim/prune/lang/prune-texts_in.properties b/tim/prune/lang/prune-texts_in.properties
new file mode 100644 (file)
index 0000000..e1daaf6
--- /dev/null
@@ -0,0 +1,459 @@
+# Text entries for the Prune application
+# Indonesian entries as extra
+
+# Menu entries
+menu.file=Berkas
+menu.file.open=Buka
+menu.file.addphotos=Muat foto
+menu.file.save=Simpan
+menu.file.exit=Keluar
+menu.edit=Ubah
+menu.edit.undo=Batal
+menu.edit.clearundo=
+menu.edit.editpoint=Perbaiki titik
+menu.edit.editwaypointname=Perbaiki Nama waypoint
+menu.edit.deletepoint=Hapus titik
+menu.edit.deleterange=Hapus jarak
+menu.edit.deletemarked=
+menu.edit.interpolate=
+menu.edit.average=
+menu.edit.reverse=
+menu.edit.mergetracksegments=
+menu.edit.rearrange=
+menu.edit.rearrange.start=
+menu.edit.rearrange.end=
+menu.edit.rearrange.nearest=
+menu.edit.cutandmove=
+menu.select=Pilih
+menu.select.all=Pilih semua
+menu.select.none=Tidak memilih
+menu.select.start=
+menu.select.end=
+menu.photo=Foto
+menu.photo.saveexif=Simpan ke Exif
+menu.photo.connect=Hubungkan ke titik
+menu.photo.disconnect=Putuskan dari titik
+menu.photo.delete=
+menu.view=Lihat
+menu.view.browser=
+menu.view.browser.google=
+menu.view.browser.openstreetmap=
+menu.view.browser.mapquest=
+menu.view.browser.yahoo=
+menu.help=Bantuan
+# Popup menu for map
+menu.map.zoomin=Perbesar
+menu.map.zoomout=Perkecil
+menu.map.zoomfull=
+menu.map.newpoint=Buat titik baru
+menu.map.connect=Hubungkan titik jalur
+menu.map.autopan=
+menu.map.showmap=Tampilkan peta
+
+# Functions
+function.loadfromgps=Muat data dari GPS
+function.sendtogps=Kirim data ke GPS
+function.exportkml=Ekspor KML
+function.exportgpx=Ekspor GPX
+function.exportpov=Ekspor POV
+function.compress=Padatkan jalur
+function.addtimeoffset=
+function.charts=Grafik
+function.show3d=Lihat tiga-D
+function.distances=
+function.setmapbg=
+function.correlatephotos=Korelasikan foto
+function.help=Bantuan
+function.about=Tentang Prune
+function.checkversion=
+
+# Dialogs
+dialog.exit.confirm.title=
+dialog.exit.confirm.text=
+dialog.openappend.title=
+dialog.openappend.text=
+dialog.deletepoint.title=
+dialog.deletepoint.deletephoto=
+dialog.deletephoto.title=
+dialog.deletephoto.deletepoint=
+dialog.openoptions.title=
+dialog.openoptions.filesnippet=
+dialog.load.table.field=
+dialog.load.table.datatype=Jenis
+dialog.load.table.description=Keterangan
+dialog.delimiter.label=
+dialog.delimiter.comma=
+dialog.delimiter.tab=
+dialog.delimiter.space=
+dialog.delimiter.semicolon=
+dialog.delimiter.other=
+dialog.openoptions.deliminfo.records=
+dialog.openoptions.deliminfo.fields=
+dialog.openoptions.deliminfo.norecords=
+dialog.openoptions.altitudeunits=
+dialog.jpegload.subdirectories=
+dialog.jpegload.loadjpegswithoutcoords=
+dialog.jpegload.loadjpegsoutsidearea=
+dialog.jpegload.progress.title=
+dialog.jpegload.progress=
+dialog.gpsload.nogpsbabel=
+dialog.gpsload.device=
+dialog.gpsload.format=
+dialog.gpsload.getwaypoints=
+dialog.gpsload.gettracks=
+dialog.gpssend.sendwaypoints=
+dialog.gpssend.sendtracks=
+dialog.gpssend.trackname=
+dialog.saveoptions.title=
+dialog.save.fieldstosave=
+dialog.save.table.field=
+dialog.save.table.hasdata=
+dialog.save.table.save=
+dialog.save.headerrow=
+dialog.save.coordinateunits=
+dialog.save.altitudeunits=
+dialog.save.timestampformat=
+dialog.save.overwrite.title=
+dialog.save.overwrite.text=
+dialog.exportkml.text=
+dialog.exportkml.altitude=
+dialog.exportkml.kmz=
+dialog.exportkml.exportimages=
+dialog.exportgpx.name=
+dialog.exportgpx.desc=
+dialog.exportgpx.includetimestamps=
+dialog.exportpov.text=
+dialog.exportpov.font=
+dialog.exportpov.camerax=
+dialog.exportpov.cameray=
+dialog.exportpov.cameraz=
+dialog.exportpov.modelstyle=
+dialog.exportpov.ballsandsticks=
+dialog.exportpov.tubesandwalls=
+dialog.exportpov.warningtracksize=
+dialog.confirmreversetrack.title=
+dialog.confirmreversetrack.text=
+dialog.confirmcutandmove.title=
+dialog.confirmcutandmove.text=
+dialog.interpolate.title=
+dialog.interpolate.parameter.text=
+dialog.undo.title=
+dialog.undo.pretext=
+dialog.undo.none.title=
+dialog.undo.none.text=
+dialog.clearundo.title=
+dialog.clearundo.text=
+dialog.pointedit.title=
+dialog.pointedit.text=
+dialog.pointedit.table.field=
+dialog.pointedit.table.value=
+dialog.pointedit.table.changed=
+dialog.pointedit.changevalue.text=
+dialog.pointedit.changevalue.title=
+dialog.pointnameedit.title=
+dialog.pointnameedit.name=Nama
+dialog.pointnameedit.uppercase=
+dialog.pointnameedit.lowercase=
+dialog.pointnameedit.sentencecase=
+dialog.addtimeoffset.add=
+dialog.addtimeoffset.subtract=
+dialog.addtimeoffset.days=
+dialog.addtimeoffset.hours=
+dialog.addtimeoffset.minutes=
+dialog.addtimeoffset.notimestamps=
+dialog.connect.title=
+dialog.connectphoto.clonepoint=
+dialog.saveexif.title=
+dialog.saveexif.intro=
+dialog.saveexif.nothingtosave=
+dialog.saveexif.noexiftool=
+dialog.saveexif.table.photoname=
+dialog.saveexif.table.status=
+dialog.saveexif.table.save=
+dialog.saveexif.photostatus.connected=
+dialog.saveexif.photostatus.disconnected=
+dialog.saveexif.photostatus.modified=
+dialog.saveexif.overwrite=
+dialog.charts.xaxis=
+dialog.charts.yaxis=
+dialog.charts.output=
+dialog.charts.screen=
+dialog.charts.svg=
+dialog.charts.svgwidth=
+dialog.charts.svgheight=
+dialog.charts.needaltitudeortimes=
+dialog.charts.gnuplotpath=
+dialog.charts.gnuplotnotfound=
+dialog.distances.intro=
+dialog.distances.column.from=Awal
+dialog.distances.column.to=Akhir
+dialog.distances.currentpoint=
+dialog.distances.toofewpoints=
+dialog.setmapbg.mapnik=
+dialog.setmapbg.osma=
+dialog.setmapbg.cyclemap=
+dialog.setmapbg.other=
+dialog.setmapbg.server=
+dialog.correlate.notimestamps=
+dialog.correlate.nouncorrelatedphotos=
+dialog.correlate.photoselect.intro=
+dialog.correlate.photoselect.photoname=
+dialog.correlate.photoselect.timediff=
+dialog.correlate.photoselect.photolater=
+dialog.correlate.options.tip=
+dialog.correlate.options.intro=
+dialog.correlate.options.offsetpanel=
+dialog.correlate.options.offset=
+dialog.correlate.options.offset.hours=
+dialog.correlate.options.offset.minutes=
+dialog.correlate.options.offset.seconds=
+dialog.correlate.options.photolater=
+dialog.correlate.options.pointlater=
+dialog.correlate.options.limitspanel=
+dialog.correlate.options.notimelimit=
+dialog.correlate.options.timelimit=
+dialog.correlate.options.nodistancelimit=
+dialog.correlate.options.distancelimit=
+dialog.correlate.options.correlate=
+dialog.correlate.alloutsiderange=
+dialog.compress.nonefound=
+dialog.compress.duplicates.title=
+dialog.compress.closepoints.title=
+dialog.compress.closepoints.paramdesc=
+dialog.compress.wackypoints.title=
+dialog.compress.wackypoints.paramdesc=
+dialog.compress.singletons.title=
+dialog.compress.singletons.paramdesc=
+dialog.compress.summarylabel=
+dialog.help.help=
+dialog.about.version=
+dialog.about.build=
+dialog.about.summarytext1=
+dialog.about.summarytext2=
+dialog.about.summarytext3=
+dialog.about.languages=Bahasa
+dialog.about.translatedby=
+dialog.about.systeminfo=
+dialog.about.systeminfo.os=
+dialog.about.systeminfo.java=
+dialog.about.systeminfo.java3d=
+dialog.about.systeminfo.povray=
+dialog.about.systeminfo.exiftool=
+dialog.about.systeminfo.gpsbabel=
+dialog.about.systeminfo.gnuplot=
+dialog.about.yes=Ya
+dialog.about.no=Tidak
+dialog.about.credits=
+dialog.about.credits.code=
+dialog.about.credits.exifcode=
+dialog.about.credits.icons=
+dialog.about.credits.translators=
+dialog.about.credits.translations=
+dialog.about.credits.devtools=
+dialog.about.credits.othertools=
+dialog.about.credits.thanks=
+dialog.about.readme=
+dialog.checkversion.error=
+dialog.checkversion.uptodate=
+dialog.checkversion.newversion1=
+dialog.checkversion.newversion2=
+dialog.checkversion.releasedate1=
+dialog.checkversion.releasedate2=
+dialog.checkversion.download=
+
+# 3d window
+dialog.3d.title=
+dialog.3d.altitudecap=
+dialog.3dlines.title=
+dialog.3dlines.empty=
+dialog.3dlines.intro=
+
+# Confirm messages || These are displayed as confirmation in the status bar
+confirm.loadfile=
+confirm.save.ok1=
+confirm.save.ok2=
+confirm.deletepoint.single=
+confirm.deletepoint.multi=
+confirm.point.edit=
+confirm.mergetracksegments=
+confirm.reverserange=
+confirm.addtimeoffset=
+confirm.rearrangewaypoints=
+confirm.cutandmove=
+confirm.saveexif.ok1=
+confirm.saveexif.ok2=
+confirm.undo.single=
+confirm.undo.multi=
+confirm.jpegload.single=
+confirm.jpegload.multi=
+confirm.photo.connect=
+confirm.photo.disconnect=
+confirm.correlate.single=
+confirm.correlate.multi=
+confirm.createpoint=
+
+# Buttons
+button.ok=
+button.back=Sebelumnya
+button.next=Lanjut
+button.finish=
+button.cancel=
+button.overwrite=
+button.moveup=
+button.movedown=
+button.showlines=
+button.edit=
+button.exit=
+button.close=Tutup
+button.continue=
+button.yes=Ya
+button.no=Tidak
+button.yestoall=
+button.notoall=
+button.selectall=
+button.selectnone=
+button.preview=
+button.guessfields=Deteksi otomatis
+button.showwebpage=
+button.gnuplotpath=
+
+# File types
+filetype.txt=Berkas teks
+filetype.jpeg=Berkas JPG
+filetype.kmlkmz=Berkas KML, KMZ
+filetype.kml=Berkas KML
+filetype.kmz=Berkas KMZ
+filetype.gpx=Berkas GPX
+filetype.pov=Berkas POV
+filetype.svg=Berkas SVG
+
+# Display components
+display.nodata=
+display.noaltitudes=
+details.trackdetails=
+details.notrack=
+details.track.points=
+details.track.file=
+details.track.numfiles=
+details.pointdetails=
+details.index.selected=
+details.index.of=
+details.nopointselection=
+details.photofile=
+details.norangeselection=
+details.rangedetails=
+details.range.selected=
+details.range.to=
+details.altitude.to=
+details.range.climb=
+details.range.descent=
+details.coordformat=
+details.distanceunits=
+display.range.time.secs=
+display.range.time.mins=
+display.range.time.hours=
+display.range.time.days=
+details.range.avespeed=
+details.range.avemovingspeed=
+details.waypointsphotos.waypoints=
+details.waypointsphotos.photos=
+details.photodetails=
+details.nophoto=
+details.photo.loading=Membuka
+details.photo.connected=
+map.overzoom=
+
+# Field names
+fieldname.latitude=
+fieldname.longitude=
+fieldname.altitude=
+fieldname.timestamp=
+fieldname.time=
+fieldname.waypointname=
+fieldname.waypointtype=
+fieldname.newsegment=
+fieldname.custom=
+fieldname.prefix=
+fieldname.distance=
+fieldname.movingdistance=
+fieldname.duration=
+fieldname.speed=
+fieldname.verticalspeed=
+
+# Measurement units
+units.original=
+units.default=
+units.metres=
+units.metres.short=
+units.feet=
+units.feet.short=
+units.kilometres=
+units.kilometres.short=
+units.kmh=
+units.miles=
+units.miles.short=
+units.mph=
+units.metrespersec=
+units.feetpersec=
+units.hours=
+units.degminsec=
+units.degmin=
+units.deg=
+units.iso8601=
+
+# External urls
+url.googlemaps=
+
+# Cardinals for 3d plots
+cardinal.n=
+cardinal.s=
+cardinal.e=
+cardinal.w=
+
+# Undo operations
+undo.load=
+undo.loadphotos=
+undo.editpoint=
+undo.deletepoint=
+undo.deletephoto=
+undo.deleterange=
+undo.compress=
+undo.insert=
+undo.reverse=
+undo.mergetracksegments=
+undo.addtimeoffset=
+undo.rearrangewaypoints=
+undo.cutandmove=
+undo.connectphoto=
+undo.disconnectphoto=
+undo.correlate=
+undo.createpoint=
+
+# Error messages
+error.save.dialogtitle=
+error.save.nodata=
+error.save.failed=
+error.saveexif.filenotfound=
+error.saveexif.cannotoverwrite1=
+error.saveexif.cannotoverwrite2=
+error.load.dialogtitle=
+error.load.noread=
+error.load.nopoints=
+error.load.unknownxml=
+error.load.noxmlinzip=
+error.load.othererror=
+error.jpegload.dialogtitle=
+error.jpegload.nofilesfound=
+error.jpegload.nojpegsfound=
+error.jpegload.noexiffound=
+error.jpegload.nogpsfound=
+error.undofailed.title=
+error.undofailed.text=
+error.function.noop.title=
+error.rearrange.noop=
+error.function.notavailable.title=
+error.function.nojava3d=
+error.3d=
+error.readme.notfound=
+error.osmimage.dialogtitle=
+error.osmimage.failed=
index 8c4e780a1c2b4b62fb217dbcf1e35872215e7aea..628f09db585fa3c17bf97ca1010b7ac500ebce51 100644 (file)
@@ -5,24 +5,19 @@
 menu.file=File
 menu.file.open=Apri file
 menu.file.addphotos=Aggiungi foto
-menu.file.loadfromgps=Carica dati da GPS
 menu.file.save=Salva
-menu.file.exportkml=Esporta in KML
-menu.file.exportgpx=Esporta in GPX
-menu.file.exportpov=Esporta in POV
 menu.file.exit=Esci
 menu.edit=Edita
 menu.edit.undo=Annulla
-menu.edit.clearundo=Cancella la lista annulla
+menu.edit.clearundo=Cancella lista ultime modifiche
 menu.edit.editpoint=Edita punto
 menu.edit.editwaypointname=Edita nome waypoint
 menu.edit.deletepoint=Cancella punto
 menu.edit.deleterange=Cancella la serie
-menu.edit.deleteduplicates=Cancella duplicati
-menu.edit.compress=Comprimi traccia
+menu.edit.deletemarked=Cancella punti marcati
 menu.edit.interpolate=Interpola
+menu.edit.average=Crea punto medio della selezione
 menu.edit.reverse=Inverti la serie
-menu.edit.addtimeoffset=Imposta lo scarto di orario
 menu.edit.mergetracksegments=Unisci segmenti traccia
 menu.edit.rearrange=Riorganizza waypoint
 menu.edit.rearrange.start=Tutti all'inizio del file
@@ -38,25 +33,40 @@ menu.photo=Foto
 menu.photo.saveexif=Salva su Exif
 menu.photo.connect=Collega al punto
 menu.photo.disconnect=Scollega dal punto
-menu.photo.correlate=Correla tutte le foto
 menu.photo.delete=Rimuovi foto
 menu.view=Visualizza
-menu.view.show3d=Mostra in 3D
 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.help=Aiuto
-menu.help.about=Informazioni su Prune
-menu.help.checkversion=Controlla gli aggiornamenti
 # Popup menu for map
 menu.map.zoomin=Zoom +
 menu.map.zoomout=Zoom -
 menu.map.zoomfull=Zoom tutto
-menu.map.newpoint=
+menu.map.newpoint=Crea punto nuovo
 menu.map.connect=Aggancia ai punti
 menu.map.autopan=Autopan
 menu.map.showmap=Mostra sulla mappa
 
+# Functions
+function.loadfromgps=Carica dati da GPS
+function.sendtogps=Invia dati al GPS
+function.exportkml=Esporta in KML
+function.exportgpx=Esporta in GPX
+function.exportpov=Esporta in POV
+function.compress=Comprimi la traccia
+function.addtimeoffset=Aggiungi uno scarto temporale
+function.charts=Diagrammi
+function.show3d=Mostra in 3D
+function.distances=Mostra distanze
+function.setmapbg=Configura sfondo mappa
+function.correlatephotos=Correla le foto
+function.help=Aiuto
+function.about=Informazioni su Prune
+function.checkversion=Controlla gli aggiornamenti
+
 # Dialogs
 dialog.exit.confirm.title=Esci da Prune
 dialog.exit.confirm.text=Le modifiche non sono state salvate. Sei sicuro di voler uscire?
@@ -66,11 +76,6 @@ dialog.deletepoint.title=Cancella Punto
 dialog.deletepoint.deletephoto=Cancella la foto collegata a questo punto?
 dialog.deletephoto.title=Cancella Foto
 dialog.deletephoto.deletepoint=Cancella il punto collegato a questa foto?
-dialog.deleteduplicates.title=Cancella Duplicati
-dialog.deleteduplicates.nonefound=Nessun punto duplicato trovato
-dialog.compresstrack.title=Comprimi la traccia
-dialog.compresstrack.parameter.text=Parametro di compressione (più basso il numero = maggiore la compressione)
-dialog.compresstrack.nonefound=Nessun punto rimosso
 dialog.openoptions.title=Apri opzioni
 dialog.openoptions.filesnippet=Estrai dal file
 dialog.load.table.field=Campo
@@ -85,19 +90,20 @@ dialog.delimiter.other=Altro
 dialog.openoptions.deliminfo.records=registra, con
 dialog.openoptions.deliminfo.fields=campi
 dialog.openoptions.deliminfo.norecords=Nessun record
-dialog.openoptions.tabledesc=Estrai dal file
 dialog.openoptions.altitudeunits=Unità di misura altitudine
 dialog.jpegload.subdirectories=Includi sottocartelle
 dialog.jpegload.loadjpegswithoutcoords=Includi foto senza coordinate
 dialog.jpegload.loadjpegsoutsidearea=Includi foto fuori dall'area corrente
 dialog.jpegload.progress.title=Caricamento foto
 dialog.jpegload.progress=Per favore aspetta, sto cercando le foto
-dialog.gpsload.title=Carica dati da GPS
 dialog.gpsload.nogpsbabel=Non ho trovato il programma gpsbabel. Continuo?
 dialog.gpsload.device=Nome del Dispositivo
 dialog.gpsload.format=Formato
 dialog.gpsload.getwaypoints=Carica waypoint
 dialog.gpsload.gettracks=Carica tracce
+dialog.gpssend.sendwaypoints=Invia waypoints
+dialog.gpssend.sendtracks=Invia tracce
+dialog.gpssend.trackname=Nome del tracce
 dialog.saveoptions.title=Salva il file
 dialog.save.fieldstosave=Campi da salvare
 dialog.save.table.field=Campo
@@ -109,16 +115,13 @@ dialog.save.altitudeunits=Unit
 dialog.save.timestampformat=Formato della data
 dialog.save.overwrite.title=File già esistente
 dialog.save.overwrite.text=Questo file esiste già. Sei sicuro di volerlo sovrascrivere?
-dialog.exportkml.title=Esporta in KML
 dialog.exportkml.text=Titolo dei dati
 dialog.exportkml.altitude=Includi altitudine (per aviazione)
 dialog.exportkml.kmz=Comprimi per file kmz
 dialog.exportkml.exportimages=Esporta le anteprime delle immagini per kmz
-dialog.exportgpx.title=Esporta in GPX
 dialog.exportgpx.name=Nome
 dialog.exportgpx.desc=Descrizione
 dialog.exportgpx.includetimestamps=Includi dati temporali
-dialog.exportpov.title=Esporta in POV
 dialog.exportpov.text=Per favore inserisci i parametri per l'esportazione in POV
 dialog.exportpov.font=Font
 dialog.exportpov.camerax=Camera X
@@ -152,7 +155,6 @@ dialog.pointnameedit.name=Nome del waypoint
 dialog.pointnameedit.uppercase=MAIUSCOLE
 dialog.pointnameedit.lowercase=minuscole
 dialog.pointnameedit.sentencecase=Iniziali Maiuscole
-dialog.addtimeoffset.title=Aggiungi uno scarto temporale
 dialog.addtimeoffset.add=Scarto in aggiunta
 dialog.addtimeoffset.subtract=Scarto in sottrazione
 dialog.addtimeoffset.days=Giorni
@@ -172,7 +174,26 @@ dialog.saveexif.photostatus.connected=Collegata
 dialog.saveexif.photostatus.disconnected=Scollegata
 dialog.saveexif.photostatus.modified=Modificata
 dialog.saveexif.overwrite=Sovrascrivi il file
-dialog.correlate.title=Correla le foto
+dialog.charts.xaxis=Asse X
+dialog.charts.yaxis=Asse Y
+dialog.charts.output=Output
+dialog.charts.screen=Output su schermo
+dialog.charts.svg=Output a file SVG
+dialog.charts.svgwidth=larghezza SVG
+dialog.charts.svgheight=altezza SVG
+dialog.charts.needaltitudeortimes=La traccia necessita di dati altitudine o tempo per creare diagrammi
+dialog.charts.gnuplotpath=Path gnuplot
+dialog.charts.gnuplotnotfound=Gnuplot non trovato nel path indicato
+dialog.distances.intro=Distanze dirette tra punti
+dialog.distances.column.from=Dal punto
+dialog.distances.column.to=Al punto
+dialog.distances.currentpoint=Punto attuale
+dialog.distances.toofewpoints=Questa funzione necessita di waypoints per calcolare le distanze tra loro
+dialog.setmapbg.mapnik=Mapnik (default)
+dialog.setmapbg.osma=Osma
+dialog.setmapbg.cyclemap=Mappa ciclistica
+dialog.setmapbg.other=Altro
+dialog.setmapbg.server=URL server
 dialog.correlate.notimestamps=Non ci sono informazioni temporali tra i dati dei punti, non c'è niente per collegarli con le foto.
 dialog.correlate.nouncorrelatedphotos=Non ci sono foto non correlate.\nSei sicuro di voler continuare?
 dialog.correlate.photoselect.intro=Selezione una delle foto correlate da usare come scarto dell'orario
@@ -195,15 +216,23 @@ dialog.correlate.options.nodistancelimit=Nessun limite di distanza
 dialog.correlate.options.distancelimit=Distanza limite
 dialog.correlate.options.correlate=Correlate
 dialog.correlate.alloutsiderange=Tutte le foto sono fuori dall'orario della traccia, e nessuna può essere correlata.\nProva a cambiare lo scarto o correla manualmente almeno una foto.
+dialog.compress.nonefound=Nessun punto rimosso
+dialog.compress.duplicates.title=Cancella duplicati
+dialog.compress.closepoints.title=Cancella punti vicini
+dialog.compress.closepoints.paramdesc=Fattore vicinanza
+dialog.compress.wackypoints.title=Cancella punti strani
+dialog.compress.wackypoints.paramdesc=Fattore distanza
+dialog.compress.singletons.title=Cancella solitari
+dialog.compress.singletons.paramdesc=Fattore distanza
+dialog.compress.summarylabel=Punti da cancellare
 dialog.help.help=Per favore vedi\n  http://activityworkshop.net/software/prune/\nper maggiori informazioni e per la guida utente.
-dialog.about.title=Informazioni su Prune
 dialog.about.version=Versione
 dialog.about.build=Build
 dialog.about.summarytext1=Prune Ã¨ un programma per il caricamento, la visione e l'edit di dati provenienti da un GPS.
 dialog.about.summarytext2=È rilasciato sotto la licenza Gnu GPL per l'uso gratuito e aperto ed il suo miglioramento, con validità mondiale.<br>La copia, la ridistribuzione sono permesse e incoraggiate<br>in accordo con i termini inclusi nel file <code>license.txt</code>.
 dialog.about.summarytext3=Per favore vedi <code style="font-weight:bold">http://activityworkshop.net/</code> per maggiori informazioni e per la guida utente.
 dialog.about.languages=Lingue disponibili
-dialog.about.translatedby=Testo italiano di Giovanni Sartor
+dialog.about.translatedby=Testo italiano di Giovanni Sartor + altro
 dialog.about.systeminfo=Info di sistema
 dialog.about.systeminfo.os=Sistema operativo
 dialog.about.systeminfo.java=Java Runtime
@@ -211,6 +240,7 @@ dialog.about.systeminfo.java3d=Java3d installato
 dialog.about.systeminfo.povray=Povray installato
 dialog.about.systeminfo.exiftool=Exiftool installato
 dialog.about.systeminfo.gpsbabel=Gpsbabel installato
+dialog.about.systeminfo.gnuplot=Gnuplot installato
 dialog.about.yes=Sì
 dialog.about.no=No
 dialog.about.credits=Crediti
@@ -223,7 +253,6 @@ dialog.about.credits.devtools=Tool di sviluppo
 dialog.about.credits.othertools=Altri tool
 dialog.about.credits.thanks=Grazie a
 dialog.about.readme=Leggimi
-dialog.checkversion.title=Controlla aggiornamenti
 dialog.checkversion.error=Non posso verificare l'aggiornamento.\nPer favore controlla la connessione internet.
 dialog.checkversion.uptodate=Stai usando l'ultima versione di Prune
 dialog.checkversion.newversion1=Una nuova versione di Prune Ã¨ disponibile! L'ultima versione Ã¨ ora la versione
@@ -243,8 +272,6 @@ dialog.3dlines.intro=Queste sono le linee della griglia per la visione 3D
 confirm.loadfile=Dati caricati da file
 confirm.save.ok1=Salvati con successo
 confirm.save.ok2=punti nel file
-confirm.deleteduplicates.single=duplicato Ã¨ stato cancellato
-confirm.deleteduplicates.multi=duplicati sono stati cancellati
 confirm.deletepoint.single=punto Ã¨ stato rimosso
 confirm.deletepoint.multi=punti sono stati rimossi
 confirm.point.edit=punto editato
@@ -263,7 +290,7 @@ confirm.photo.connect=foto collegata
 confirm.photo.disconnect=foto scollegata
 confirm.correlate.single=foto era correlata
 confirm.correlate.multi=foto erano correlate
-confirm.createpoint=
+confirm.createpoint=punto creato
 
 # Buttons
 button.ok=OK
@@ -288,14 +315,17 @@ button.selectnone=Deseleziona tutto
 button.preview=Anteprima
 button.guessfields=Campi soluzione
 button.showwebpage=Mostra pagina
+button.gnuplotpath=Fissa path gnuplot
 
 # File types
 filetype.txt=File TXT
 filetype.jpeg=File JPG
 filetype.kmlkmz=File KML, KMZ
 filetype.kml=File KML
+filetype.kmz=FIle KMZ
 filetype.gpx=File GPX
 filetype.pov=File POV
+filetype.svg=File SVG
 
 # Display components
 display.nodata=Nessun dato caricato
@@ -309,7 +339,6 @@ details.pointdetails=Dettagli punto
 details.index.selected=Indice
 details.index.of=di
 details.nopointselection=Nessun punto selezionato
-details.speed=Velocità
 details.photofile=File della foto
 details.norangeselection=Nessun intervallo selezionato
 details.rangedetails=Dettagli dell'intervallo
@@ -325,27 +354,31 @@ display.range.time.mins=m
 display.range.time.hours=h
 display.range.time.days=g
 details.range.avespeed=Velocità media
-details.range.avemovingspeed=
+details.range.avemovingspeed=Velocità media in movimento
 details.waypointsphotos.waypoints=Waypoint
 details.waypointsphotos.photos=Foto
 details.photodetails=Dettagli foto
 details.nophoto=Nessuna foto selezionata
 details.photo.loading=Caricamento
 details.photo.connected=Collegata
+map.overzoom=Mappa non disponibile a questo livello di zoom
 
 # Field names
 fieldname.latitude=Latitudine
 fieldname.longitude=Longitudine
 fieldname.altitude=Altitudine
 fieldname.timestamp=Dati temporali
+fieldname.time=Tempo
 fieldname.waypointname=Nome
 fieldname.waypointtype=Tipo
 fieldname.newsegment=Segmento
 fieldname.custom=Custom
 fieldname.prefix=Campo
 fieldname.distance=Distanza
-fieldname.movingdistance=
+fieldname.movingdistance=Distanza in movimento
 fieldname.duration=Durata
+fieldname.speed=Velocità
+fieldname.verticalspeed=Velocità verticale
 
 # Measurement units
 units.original=Originale
@@ -360,6 +393,9 @@ units.kmh=km/h
 units.miles=Miglia
 units.miles.short=mi
 units.mph=mph
+units.metrespersec=m/s
+units.feetpersec=ft/s
+units.hours=Ore
 units.degminsec=Deg-min-sec
 units.degmin=Deg-min
 units.deg=Degrees
@@ -383,7 +419,6 @@ undo.deletephoto=rimuovi foto
 undo.deleterange=cancella l'intervallo
 undo.compress=comprimi traccia
 undo.insert=inserisci punti
-undo.deleteduplicates=cancella duplicati
 undo.reverse=inverti l'intervallo
 undo.mergetracksegments=unisci segmenti traccia
 undo.addtimeoffset=aggiungi scarto temporale
@@ -392,7 +427,7 @@ undo.cutandmove=muovi selezione
 undo.connectphoto=collega foto
 undo.disconnectphoto=scollega foto
 undo.correlate=correla foto
-undo.createpoint=
+undo.createpoint=crea punto
 
 # Error messages
 error.save.dialogtitle=Errore nel salvataggio dati
@@ -405,6 +440,7 @@ error.load.dialogtitle=Errore nel caricamento dati
 error.load.noread=Non posso leggere il file
 error.load.nopoints=Non ci sono coordinate nel file
 error.load.unknownxml=Formato xml non riconosciuto:
+error.load.noxmlinzip=File xml non trovato all'interno del zip file
 error.load.othererror=Errore nella lettura del file:
 error.jpegload.dialogtitle=Errore nel caricamento delle foto
 error.jpegload.nofilesfound=File non trovato
@@ -415,10 +451,8 @@ error.undofailed.title=Impossibile annullare
 error.undofailed.text=Impossibile annullare l'operazione
 error.function.noop.title=La funzione non ha avuto effetto
 error.rearrange.noop=La riorganizzazione dei waypoint non ha avuto effetto
-error.function.notimplemented=Mi dispiace, questa funzione non Ã¨ ancora stata implementata.
 error.function.notavailable.title=Funzione non disponibile
 error.function.nojava3d=Questa funzione richiede la libreria Java3d,\ndisponibile all'indirizzo Sun.com.
-error.3d.title=Errore nella visualizzazione 3D
 error.3d=È avvenuto un errore nella visualizzazione 3D
 error.readme.notfound=Non ho trovato il file Leggimi
 error.osmimage.dialogtitle=Errore nel caricamento nelle immagini della mappa
index a16c0377e9016e31cc72d4e7c4d994749688c923..5478bd1a38979cbe872bf64b4354d7cc93d3ab24 100644 (file)
@@ -5,11 +5,7 @@
 menu.file=Plik
 menu.file.open=Otw\u00F3rz
 menu.file.addphotos=Dodaj zdj\u0119cia
-menu.file.loadfromgps=
 menu.file.save=Zapisz
-menu.file.exportkml=Eksportuj jako KML
-menu.file.exportgpx=Eksportuj jako GPX
-menu.file.exportpov=Eksportuj jako POV
 menu.file.exit=Zako\u0144cz
 menu.edit=Edycja
 menu.edit.undo=Cofnij
@@ -18,252 +14,283 @@ menu.edit.editpoint=Edytuj punkt
 menu.edit.editwaypointname=Zmie\u0144 nazw\u0119 punktu po\u015Bredniego
 menu.edit.deletepoint=Usu\u0144 punkt
 menu.edit.deleterange=Usu\u0144 zakres
-menu.edit.deleteduplicates=Usu\u0144 duplikaty
-menu.edit.compress=Skompresuj scie\u017Ck\u0119
+menu.edit.deletemarked=Usu\u0144 zaznaczone punkty
 menu.edit.interpolate=Interpoluj punkty
+menu.edit.average=U\u015Brednij zaznaczenie
 menu.edit.reverse=Odwr\u00F3\u0107 zakres
-menu.edit.addtimeoffset=
-menu.edit.mergetracksegments=
+menu.edit.mergetracksegments=Po\u0142\u0105cz fragmenty \u015Bcie\u017Cek
 menu.edit.rearrange=Zmie\u0144 kolejno\u015B\u0107 punkt\u00F3w po\u015Brednich
 menu.edit.rearrange.start=Wszystkie na pocz\u0105tek \u015Bcie\u017Cki
 menu.edit.rearrange.end=Wszystkie na koniec \u015Bcie\u017Cki
 menu.edit.rearrange.nearest=Do najbli\u017Cszego punktu
-menu.edit.cutandmove=
-menu.select=Zakres
+menu.edit.cutandmove=Wytnij i przesu\u0144 zaznaczenie
+menu.select=Zaznacz
 menu.select.all=Zaznacz wszystko
 menu.select.none=Usu\u0144 zaznaczenie
-menu.select.start=Zaznacz pocz\u0105tek
-menu.select.end=Zaznacz koniec
+menu.select.start=Zaznacz pocz\u0105tek zakresu
+menu.select.end=Zaznacz koniec zakresu
 menu.photo=Zdj\u0119cie
 menu.photo.saveexif=Zapisz Exif
 menu.photo.connect=Przy\u0142\u0105cz do punktu
 menu.photo.disconnect=Od\u0142\u0105cz od punktu
-menu.photo.correlate=Skoreluj wszystkie zdj\u0119cia
 menu.photo.delete=Usu\u0144 zdj\u0119cie
 menu.view=Widok
-menu.view.show3d=Poka\u017C 3D model
-menu.view.browser=
-menu.view.browser.google=
-menu.view.browser.openstreetmap=
+menu.view.browser=Mapa w przegl\u0105darce
+menu.view.browser.google=Mapy Google
+menu.view.browser.openstreetmap=Openstreetmap
+menu.view.browser.mapquest=Mapquest
+menu.view.browser.yahoo=Mapy Yahoo
 menu.help=Pomoc
-menu.help.about=Prune - Informacje
-menu.help.checkversion=
 # Popup menu for map
 menu.map.zoomin=Powi\u0119ksz
 menu.map.zoomout=Zmniejsz
-menu.map.zoomfull=Dostosuj powi\u0119kszenie
-menu.map.newpoint=
-menu.map.connect=Po\u0142\u0105czenie track punkty
+menu.map.zoomfull=Dostosuj powi\u0119kszenie
+menu.map.newpoint=Stw\u00F3rz nowy punkt
+menu.map.connect=Po\u0142\u0105cz punkty \u015Bcie\u017Cki
 menu.map.autopan=Przesuwanie mapy
-menu.map.showmap=
+menu.map.showmap=Poka\u017C map\u0119
+
+# Functions
+function.loadfromgps=\u0141aduj z GPS
+function.sendtogps=Wy\u015Blij dane do urz\u0105dzenia GPS
+function.exportkml=Eksportuj KML
+function.exportgpx=Eksportuj jako GPX
+function.exportpov=Eksportuj jako POV
+function.compress=Skompresuj \u015Bcie\u017Ck\u0119
+function.addtimeoffset=Dodaj przesuni\u0119cie czasu
+function.charts=Wykres
+function.show3d=Poka\u017C model 3D
+function.distances=Odleg\u0142o\u015Bci
+function.setmapbg=Wybierz map\u0119
+function.correlatephotos=Powi\u0105\u017C zdj\u0119cia
+function.help=Pomoc
+function.about=O Prune
+function.checkversion=Sprawd\u017A czy jest nowa wersja
 
 # Dialogs
 dialog.exit.confirm.title=Zako\u0144cz Prune
-dialog.exit.confirm.text=
-dialog.openappend.title=
-dialog.openappend.text=
+dialog.exit.confirm.text=Dane nie s\u0105 zapisane. Czy na pewno chcesz wyj\u015B\u0107?
+dialog.openappend.title=Dodaj do istniej\u0105cych danych
+dialog.openappend.text=Doda\u0107 te dane do ju\u017C za\u0142adowanych?
 dialog.deletepoint.title=Usu\u0144 punkt
-dialog.deletepoint.deletephoto=Usu\u0144 zdj\u0119cie attached to this punkt?
+dialog.deletepoint.deletephoto=Usun\u0105\u0107 zdj\u0119cie do\u0142\u0105czone do tego punktu?
 dialog.deletephoto.title=Usu\u0144 zdj\u0119cie
-dialog.deletephoto.deletepoint=Usu\u0144 punkt attached to this zdj\u0119cie?
-dialog.deleteduplicates.title=Usu\u0144 Duplicates
-dialog.deleteduplicates.nonefound=Brak duplikaty found
-dialog.compresstrack.title=Skompresuj scie\u017Ck\u0119
-dialog.compresstrack.parameter.text=
-dialog.compresstrack.nonefound=No data punkty could be removed
+dialog.deletephoto.deletepoint=Usun\u0105\u0107 punkt do\u0142\u0105czony do tego zdj\u0119cia?
 dialog.openoptions.title=Otw\u00F3rz opcje
-dialog.openoptions.filesnippet=Extract of plik
+dialog.openoptions.filesnippet=Fragment z pliku
 dialog.load.table.field=Pole
-dialog.load.table.datatype=Data Type
+dialog.load.table.datatype=Typ danych
 dialog.load.table.description=Opis
-dialog.delimiter.label=Pole separator
+dialog.delimiter.label=Pole separatora
 dialog.delimiter.comma=Przecinek ,
 dialog.delimiter.tab=Tabulator
 dialog.delimiter.space=Spacja
 dialog.delimiter.semicolon=\u015Arednik ;
 dialog.delimiter.other=Inne
-dialog.openoptions.deliminfo.records=
+dialog.openoptions.deliminfo.records=rekordy, z
 dialog.openoptions.deliminfo.fields=pola
-dialog.openoptions.deliminfo.norecords=
-dialog.openoptions.tabledesc=Extract of plik
-dialog.openoptions.altitudeunits=Wysoko\u015B\u0107 jednostki
-dialog.jpegload.subdirectories=
-dialog.jpegload.loadjpegswithoutcoords=Include zdj\u0119cia without koordinaty
-dialog.jpegload.loadjpegsoutsidearea=
-dialog.jpegload.progress.title=Loading zdj\u0119cia
-dialog.jpegload.progress=Please wait while the zdj\u0119cia are searched
-dialog.gpsload.title=
-dialog.gpsload.nogpsbabel=
-dialog.gpsload.device=
-dialog.gpsload.format=
-dialog.gpsload.getwaypoints=
-dialog.gpsload.gettracks=
+dialog.openoptions.deliminfo.norecords=Brak rekord\u00F3w
+dialog.openoptions.altitudeunits=Jednostki wysoko\u015Bci
+dialog.jpegload.subdirectories=Do\u0142\u0105cz podkatalogi
+dialog.jpegload.loadjpegswithoutcoords=Do\u0142\u0105cz zdj\u0119cia bez wsp\u00F3\u0142rz\u0119dnych
+dialog.jpegload.loadjpegsoutsidearea=Do\u0142\u0105cz zdj\u0119cia spoza bie\u017C\u0105cego obszaru
+dialog.jpegload.progress.title=\u0141aduj\u0119 zdj\u0119cia
+dialog.jpegload.progress=Czekaj, szukam zdj\u0119\u0107
+dialog.gpsload.nogpsbabel=Nie znalezionio programu gpsbabel. Kontynuowa\u0107?
+dialog.gpsload.device=Nazwa urz\u0105dzenia
+dialog.gpsload.format=Format
+dialog.gpsload.getwaypoints=\u0141aduj punkty po\u015Brednie
+dialog.gpsload.gettracks=\u0141aduj \u015Bcie\u017Cki
+dialog.gpssend.sendwaypoints=Wy\u015Blij punkty po\u015Brednie
+dialog.gpssend.sendtracks=Wy\u015Blij \u015Bcie\u017Cki
+dialog.gpssend.trackname=Nazwa \u015Bcie\u017Cki
 dialog.saveoptions.title=Zapisz plik
-dialog.save.fieldstosave=Pola to save
+dialog.save.fieldstosave=Pola do zapisu
 dialog.save.table.field=Pole
-dialog.save.table.hasdata=
+dialog.save.table.hasdata=je\u015Bli s\u0105 dane
 dialog.save.table.save=Zapisz
-dialog.save.headerrow=
-dialog.save.coordinateunits=Wsp\u00f3\u0142rz\u0119dne jednostki
-dialog.save.altitudeunits=Wysoko\u015B\u0107 jednostki
-dialog.save.timestampformat=
+dialog.save.headerrow=Dodaj wiersz nag\u0142\u00F3wka
+dialog.save.coordinateunits=Jednostki wsp\u00F3\u0142rz\u0119dnych
+dialog.save.altitudeunits=Jednostki wysoko\u015Bci
+dialog.save.timestampformat=Format znacznika czasu
 dialog.save.overwrite.title=Plik ju\u017C istnieje
-dialog.save.overwrite.text=This plik already exists. Are you sure you want to overwrite the plik?
-dialog.exportkml.title=Eksportuj KML
-dialog.exportkml.text=Tytu\u0142 for the data
-dialog.exportkml.altitude=
-dialog.exportkml.kmz=
-dialog.exportkml.exportimages=Eksportuj image thumbnails to kmz
-dialog.exportgpx.title=Eksportuj jako GPX
+dialog.save.overwrite.text=Ten plik ju\u017C istnieje. Czy na pewno chcesz go nadpisa\u0107?
+dialog.exportkml.text=Tytu\u0142 dla danych
+dialog.exportkml.altitude=Do\u0142\u0105cz wysoko\u015Bci (dla cel\u00F3w lotniczych)
+dialog.exportkml.kmz=Skompresuj do pliku KMZ
+dialog.exportkml.exportimages=Eksportuj miniaturki zdj\u0119\u0107 do KMZ
 dialog.exportgpx.name=Nazwa
 dialog.exportgpx.desc=Opis
-dialog.exportgpx.includetimestamps=
-dialog.exportpov.title=Eksportuj jako POV
-dialog.exportpov.text=
+dialog.exportgpx.includetimestamps=Do\u0142\u0105cz znaczniki czasu
+dialog.exportpov.text=Wprowad\u017A dodatkowe parametry eksportu do formatu POV
 dialog.exportpov.font=Czcionka
-dialog.exportpov.camerax=Camera X
-dialog.exportpov.cameray=Camera Y
-dialog.exportpov.cameraz=Camera Z
-dialog.exportpov.modelstyle=
-dialog.exportpov.ballsandsticks=
-dialog.exportpov.tubesandwalls=
-dialog.exportpov.warningtracksize=This track has a large number of punkty, which Java3D might not be able to display.\nCzy chcesz kontynuowa\u0107?
-dialog.confirmreversetrack.title=
-dialog.confirmreversetrack.text=
-dialog.confirmcutandmove.title=
-dialog.confirmcutandmove.text=
+dialog.exportpov.camerax=Kamera X
+dialog.exportpov.cameray=Kamera Y
+dialog.exportpov.cameraz=Kamera Z
+dialog.exportpov.modelstyle=Styl modelu
+dialog.exportpov.ballsandsticks=Kule i pa\u0142ki
+dialog.exportpov.tubesandwalls=Rurki i \u015Bciany
+dialog.exportpov.warningtracksize=Ta \u015Bcie\u017Cka ma bardzo wiele punkt\u00F3w, kt\u00F3rych Java3D mo\u017Ce nie wy\u015Bwietli\u0107.\nCzy chcesz kontynuowa\u0107?
+dialog.confirmreversetrack.title=Potwierd\u017A odwr\u00F3cenie
+dialog.confirmreversetrack.text=Ta \u015Bcie\u017Cka zawiera znaczniki czasu, kt\u00F3re po odwr\u00F3ceniu nie b\u0119d\u0105 ustawione w kolejno\u015Bci.\nCzy na pewno chcesz odwr\u00F3ci\u0107 ten fragment?
+dialog.confirmcutandmove.title=Potwierd\u017A wytnij i przesu\u0144
+dialog.confirmcutandmove.text=Ta \u015Bcie\u017Cka zawiera znaczniki czasu, kt\u00F3re po przesuni\u0119ciu nie b\u0119d\u0105 ustawione w kolejno\u015Bci.\nCzy na pewno chcesz przesun\u0105\u0107 ten fragment?
 dialog.interpolate.title=Interpoluj punkty
-dialog.interpolate.parameter.text=Number of punkty to insert between selected punkty
-dialog.undo.title=Cofnij action(s)
-dialog.undo.pretext=
-dialog.undo.none.title=
-dialog.undo.none.text=
+dialog.interpolate.parameter.text=Ilo\u015B\u0107 punkt\u00F3w do wstawienia pomi\u0119dzy wybrane punkty
+dialog.undo.title=Potwierd\u017A akcje
+dialog.undo.pretext=Wybierz akcje kt\u00F3re chcesz cofn\u0105\u0107
+dialog.undo.none.title=Nie mo\u017Cna cofn\u0105\u0107
+dialog.undo.none.text=Brak zmian do cofni\u0119cia
 dialog.clearundo.title=Wyczy\u015B\u0107 list\u0119 zmian
-dialog.clearundo.text=
+dialog.clearundo.text=Czy na pewno chcesz wyczy\u015Bci\u0107 list\u0119 zmian?\nWszystkie informacje o zmianach b\u0119d\u0105 utracone!
 dialog.pointedit.title=Edytuj punkt
-dialog.pointedit.text=
+dialog.pointedit.text=Zaznacz wszystkie pola do edycji i u\u017Cyj przycisku 'Edytuj' by zmieni\u0107 warto\u015Bci
 dialog.pointedit.table.field=Pole
-dialog.pointedit.table.value=
+dialog.pointedit.table.value=Warto\u015B\u0107
 dialog.pointedit.table.changed=Zmieniony
-dialog.pointedit.changevalue.text=
-dialog.pointedit.changevalue.title=Edytuj field
+dialog.pointedit.changevalue.text=Wprowad\u017A now\u0105 warto\u015B\u0107 tego pola
+dialog.pointedit.changevalue.title=Edytuj pole
 dialog.pointnameedit.title=Zmie\u0144 nazw\u0119 punktu po\u015Bredniego
-dialog.pointnameedit.name=Waypoint nazwa
-dialog.pointnameedit.uppercase=
-dialog.pointnameedit.lowercase=
-dialog.pointnameedit.sentencecase=
-dialog.addtimeoffset.title=
-dialog.addtimeoffset.add=
-dialog.addtimeoffset.subtract=
-dialog.addtimeoffset.days=
-dialog.addtimeoffset.hours=
+dialog.pointnameedit.name=Nazwa punktu po\u015Bredniego
+dialog.pointnameedit.uppercase=WIELKIE litery
+dialog.pointnameedit.lowercase=ma\u0142e litery
+dialog.pointnameedit.sentencecase=Jak W Zdaniu
+dialog.addtimeoffset.add=Dodaj czas
+dialog.addtimeoffset.subtract=Odejmij czas
+dialog.addtimeoffset.days=Dni
+dialog.addtimeoffset.hours=Godziny
 dialog.addtimeoffset.minutes=Minuty
-dialog.addtimeoffset.notimestamps=
-dialog.connect.title=
-dialog.connectphoto.clonepoint=
+dialog.addtimeoffset.notimestamps=Nie mo\u017Cna przesun\u0105\u0107 czasu, poniewa\u017C zaznaczenie nie zawiera znacznik\u00F3w czasu
+dialog.connect.title=Po\u0142\u0105cz zdj\u0119cie do punktu
+dialog.connectphoto.clonepoint=Ten punkt ju\u017C ma zdj\u0119cie.\nCzy chcesz zrobi\u0107 kopi\u0119 tego punktu?
 dialog.saveexif.title=Zapisz Exif
-dialog.saveexif.intro=Select the zdj\u0119cia to save using the checkboxes
-dialog.saveexif.nothingtosave=
-dialog.saveexif.noexiftool=
-dialog.saveexif.table.photoname=Nazwa zdj\u0119cie
+dialog.saveexif.intro=Zaznacz zdj\u0119cia do zapisu u\u017Cywaj\u0105c p\u00F3l opcji
+dialog.saveexif.nothingtosave=Wsp\u00F3\u0142rz\u0119dne s\u0105 nie zmienione, Nie ma nic do zapisu
+dialog.saveexif.noexiftool=Nie znaleziono programu exiftool. Kontynuowa\u0107?
+dialog.saveexif.table.photoname=Nazwa zdj\u0119cia
 dialog.saveexif.table.status=Status
 dialog.saveexif.table.save=Zapisz
-dialog.saveexif.photostatus.connected=
-dialog.saveexif.photostatus.disconnected=
+dialog.saveexif.photostatus.connected=Po\u0142\u0105czony
+dialog.saveexif.photostatus.disconnected=Roz\u0142\u0105czony
 dialog.saveexif.photostatus.modified=Zmodyfikowany
-dialog.saveexif.overwrite=Overwrite pliki
-dialog.correlate.title=Skoreluj zdj\u0119cie
-dialog.correlate.notimestamps=There are no timestamps in the data punkty, so there is nothing to correlate with the zdj\u0119cia.
-dialog.correlate.nouncorrelatedphotos=There are no uncorrelated zdj\u0119cia.\nAre you sure you want to continue?
-dialog.correlate.photoselect.intro=Select one of these correlated zdj\u0119cia to use as the time offset
-dialog.correlate.photoselect.photoname=Nazwa zdj\u0119cie
-dialog.correlate.photoselect.timediff=
-dialog.correlate.photoselect.photolater=Zdj\u0119cie later
-dialog.correlate.options.tip=Tip: By manually correlating at least one zdj\u0119cie, the time offset can be calculated for you.
-dialog.correlate.options.intro=
-dialog.correlate.options.offsetpanel=
-dialog.correlate.options.offset=
-dialog.correlate.options.offset.hours=hours,
-dialog.correlate.options.offset.minutes=minuty i
-dialog.correlate.options.offset.seconds=seconds
-dialog.correlate.options.photolater=Zdj\u0119cie po punkt
-dialog.correlate.options.pointlater=Punkt po zdj\u0119cie
-dialog.correlate.options.limitspanel=
-dialog.correlate.options.notimelimit=
-dialog.correlate.options.timelimit=
-dialog.correlate.options.nodistancelimit=
-dialog.correlate.options.distancelimit=
-dialog.correlate.options.correlate=
-dialog.correlate.alloutsiderange=All zdj\u0119cia are outside the time range of the track, so none can be correlated.\nTry changing the offset or manually correlating at least one zdj\u0119cie.
-dialog.help.help=Please see\n http://activityworkshop.net/software/prune/\npo wi\u0119cej informacji and user guides.
-dialog.about.title=Prune Informacje
+dialog.saveexif.overwrite=Nadpisz pliki
+dialog.charts.xaxis=O\u015B X
+dialog.charts.yaxis=O\u015B Y
+dialog.charts.output=Wykres
+dialog.charts.screen=Wy\u015Bwietl na ekranie
+dialog.charts.svg=Zapisz do pliku SVG
+dialog.charts.svgwidth=szeroko\u015B\u0107 SVG
+dialog.charts.svgheight=wysoko\u015B\u0107 SVG
+dialog.charts.needaltitudeortimes=\u015Acie\u017Cka musi posiada\u0107 zapisane wysoko\u015Bci lub znaczniki czasu aby mo\u017Cliwe by\u0142o utworzenie wykres\u00F3w
+dialog.charts.gnuplotpath=\u015Acie\u017Cka do programu gnuplot
+dialog.charts.gnuplotnotfound=Nie znalaz\u0142em programu gnuplot
+dialog.distances.intro=Odleg\u0142o\u015B\u0107 mi\u0119dzy punktami w linii prostej
+dialog.distances.column.from=Z punktu
+dialog.distances.column.to=Do punktu
+dialog.distances.currentpoint=Wybrany punkt
+dialog.distances.toofewpoints=Ta funkcja wymaga przynajmniej dw\u00F3ch punkt\u00F3w po\u015Brednich aby obliczy\u0107 odleg\u0142o\u015Bci
+dialog.setmapbg.mapnik=Mapnik (domy\u015Blny)
+dialog.setmapbg.osma=Osma
+dialog.setmapbg.cyclemap=Cyclemap
+dialog.setmapbg.other=Inne
+dialog.setmapbg.server=Adres URL serwera
+dialog.correlate.notimestamps=Punkty nie maj\u0105 znacznik\u00F3w czasu, nie mo\u017Cna ich powi\u0105za\u0107 ze zdj\u0119ciami.
+dialog.correlate.nouncorrelatedphotos=Nie ma nie powi\u0105zanych zdj\u0119\u0107.\nCzy na pewno chcesz kontynuowa\u0107?
+dialog.correlate.photoselect.intro=Wybierz jedno z powi\u0105zanych zdj\u0119\u0107 i u\u017Cyj go jako wzorca do przesuni\u0119cia czasu
+dialog.correlate.photoselect.photoname=Nazwa zdj\u0119cia
+dialog.correlate.photoselect.timediff=R\u00F3\u017Cnica czasowa
+dialog.correlate.photoselect.photolater=P\u00F3\u017Aniejsze zdj\u0119cie
+dialog.correlate.options.tip=Porada: Gdy powi\u0105\u017Cesz r\u0119cznie przynajmniej jedno zdj\u0119cie, r\u00F3\u017Cnica czasowa zostanie policzona automatycznie.
+dialog.correlate.options.intro=Wybierz opcje dla automatycznej korelacji
+dialog.correlate.options.offsetpanel=Przesuni\u0119cie czasowe
+dialog.correlate.options.offset=Przesuni\u0119cie
+dialog.correlate.options.offset.hours=godzin,
+dialog.correlate.options.offset.minutes=minut i
+dialog.correlate.options.offset.seconds=sekund
+dialog.correlate.options.photolater=Zdj\u0119cie p\u00F3\u017Aniejsze ni\u017C punkt
+dialog.correlate.options.pointlater=Punkt p\u00F3\u017Aniejszy ni\u017C zdj\u0119cie
+dialog.correlate.options.limitspanel=Ograniczenia korelacji
+dialog.correlate.options.notimelimit=Bez limitu czasu
+dialog.correlate.options.timelimit=Limit czasu
+dialog.correlate.options.nodistancelimit=Bez limitu odleg\u0142o\u015Bci
+dialog.correlate.options.distancelimit=Limit odleg\u0142o\u015Bci
+dialog.correlate.options.correlate=Powi\u0105\u017C ze sob\u0105
+dialog.correlate.alloutsiderange=Wszystkie zdj\u0119cia s\u0105 poza zakresem czasu \u015Bcie\u017Cki, tak \u017Ce \u017Cadne nie mo\u017Ce zosta\u0107 z ni\u0105 skorelowane.\nSpr\u00F3buj zmieni\u0107 przesuni\u0119cie lub r\u0119cznie skoreluj przynajmniej jedno zdj\u0119cie.
+dialog.compress.nonefound=Nie mo\u017Cna usun\u0105\u0107 \u017Cadnych punkt\u00F3w
+dialog.compress.duplicates.title=Usuwanie duplikat\u00F3w
+dialog.compress.closepoints.title=Usuwanie bliskich sobie punkt\u00F3w
+dialog.compress.closepoints.paramdesc=Wsp\u00F3\u0142czynnik rozpi\u0119to\u015Bci
+dialog.compress.wackypoints.title=Usuwanie dziwacznych punkt\u00F3w
+dialog.compress.wackypoints.paramdesc=Wsp\u00F3\u0142czynnik odleg\u0142o\u015Bci
+dialog.compress.singletons.title=Usuwanie odosobnionych punkt\u00F3w
+dialog.compress.singletons.paramdesc=Wsp\u00F3\u0142czynnik odleg\u0142o\u015Bci
+dialog.compress.summarylabel=Punkty do usuni\u0119cia
+dialog.help.help=Na stronie\n http://activityworkshop.net/software/prune/ \nznajdziesz wi\u0119cej informacji oraz podr\u0119cznik u\u017Cytkownika
 dialog.about.version=Wersja
 dialog.about.build=Build
-dialog.about.summarytext1=
-dialog.about.summarytext2=
-dialog.about.summarytext3=
-dialog.about.languages=
-dialog.about.translatedby=Tekst po polsku by Piotr.
-dialog.about.systeminfo=
-dialog.about.systeminfo.os=
-dialog.about.systeminfo.java=
+dialog.about.summarytext1=Prune s\u0142u\u017Cy do pobierania, wy\u015Bwietlania i edycji danych z odbiornik\u00F3w GPS.
+dialog.about.summarytext2=Ten program zosta\u0142 udost\u0119pniony na podstawie licencji GNU pozwalaj\u0105cej<br>na jego wolne, nieograniczone i og\u00F3lno\u015Bwiatowe u\u017Cytkowanie i rozszerzanie. <br>Kopiowanie, rozprowadzanie i modyfikowanie s\u0105 dozwolone i zalecane<br>zgodnie z warunkami zawartymi w do\u0142\u0105czonym pliku<code>license.txt</code>
+dialog.about.summarytext3=Na stronie <code style="font-weight:bold">http://activityworkshop.net/</code> znajdziesz wi\u0119cej informacji oraz podr\u0119cznik u\u017Cytkownika.
+dialog.about.languages=Dost\u0119pne j\u0119zyki
+dialog.about.translatedby=Tekst po polsku: Piotr, Weehal
+dialog.about.systeminfo=Informacje o systemie
+dialog.about.systeminfo.os=System operacyjny
+dialog.about.systeminfo.java=Wersja Java Runtime
 dialog.about.systeminfo.java3d=Java3d zainstalowana
-dialog.about.systeminfo.povray=Povray zainstalowana
-dialog.about.systeminfo.exiftool=Exiftool zainstalowana
-dialog.about.systeminfo.gpsbabel=Gpsbabel zainstalowana
+dialog.about.systeminfo.povray=Povray zainstalowany
+dialog.about.systeminfo.exiftool=Exiftool zainstalowany
+dialog.about.systeminfo.gpsbabel=Gpsbabel zainstalowany
+dialog.about.systeminfo.gnuplot=Gnuplot zainstalowany
 dialog.about.yes=Tak
 dialog.about.no=Nie
-dialog.about.credits=
-dialog.about.credits.code=
-dialog.about.credits.exifcode=
-dialog.about.credits.icons=
-dialog.about.credits.translators=
-dialog.about.credits.translations=T\u0142umaczenie helped by
-dialog.about.credits.devtools=
-dialog.about.credits.othertools=
-dialog.about.credits.thanks=Dzi\u0119kuje to
-dialog.about.readme=Readme
-dialog.checkversion.title=
-dialog.checkversion.error=
-dialog.checkversion.uptodate=
-dialog.checkversion.newversion1=
-dialog.checkversion.newversion2=
-dialog.checkversion.releasedate1=
-dialog.checkversion.releasedate2=
-dialog.checkversion.download=To download the new version, go to http://activityworkshop.net/software/prune/download.html.
+dialog.about.credits=Podzi\u0119kowania
+dialog.about.credits.code=Kod Prune napisany przez
+dialog.about.credits.exifcode=Kod Exif przez
+dialog.about.credits.icons=Niekt\u00F3re ikony z
+dialog.about.credits.translators=T\u0142umacze
+dialog.about.credits.translations=Pomoc w t\u0142umaczeniu
+dialog.about.credits.devtools=Narz\u0119dzia deweloperskie
+dialog.about.credits.othertools=Inne narz\u0119dzia
+dialog.about.credits.thanks=Podzi\u0119kowania dla
+dialog.about.readme=Czytaj To
+dialog.checkversion.error=Nie mo\u017Cna sprawdzi\u0107 numeru wersji.\nSprawd\u017A po\u0142\u0105czenie z internetem.
+dialog.checkversion.uptodate=U\u017Cywasz najnowszej wersji Prune.
+dialog.checkversion.newversion1=Dost\u0119pna jest nowa wersja Prune! Najnowsz\u0105 wersj\u0105 jest wersja
+dialog.checkversion.newversion2=.
+dialog.checkversion.releasedate1=Nowa wersja zosta\u0142a opublikowana
+dialog.checkversion.releasedate2=.
+dialog.checkversion.download=Aby \u015Bci\u0105gn\u0105\u0107 now\u0105 wersj\u0119 przejd\u017A na http://activityworkshop.net/software/prune/download.html.
 
 # 3d window
-dialog.3d.title=Prune tr\u00f3jwymiarowa model
-dialog.3d.altitudecap=
-dialog.3dlines.title=
-dialog.3dlines.empty=
-dialog.3dlines.intro=
+dialog.3d.title=Prune widok tr\u00F3jwymiarowy
+dialog.3d.altitudecap=Minimalny zakres wysoko\u015Bci
+dialog.3dlines.title=Linie siatki
+dialog.3dlines.empty=Brak siatki do wy\u015Bwietlenia!
+dialog.3dlines.intro=Linie siatki w widoku 3D
 
 # Confirm messages || These are displayed as confirmation in the status bar
-confirm.loadfile=
-confirm.save.ok1=
-confirm.save.ok2=punkty to plik
-confirm.deleteduplicates.single=
-confirm.deleteduplicates.multi=
-confirm.deletepoint.single=data punkt was removed
-confirm.deletepoint.multi=data punkty were removed
-confirm.undo.single=
-confirm.undo.multi=
-confirm.point.edit=punkt edited
-confirm.mergetracksegments=
-confirm.reverserange=
-confirm.addtimeoffset=
-confirm.rearrangewaypoints=
-confirm.cutandmove=
-confirm.saveexif.ok1=
-confirm.saveexif.ok2=zdj\u0119cia pliki
-confirm.jpegload.single=zdj\u0119cie was added
-confirm.jpegload.multi=zdj\u0119cia were added
-confirm.photo.connect=zdj\u0119cie connected
-confirm.photo.disconnect=zdj\u0119cie disconnected
-confirm.correlate.single=zdj\u0119cie was correlated
-confirm.correlate.multi=zdj\u0119cia were correlated
-confirm.createpoint=
+confirm.loadfile=Za\u0142adowano dane z pliku
+confirm.save.ok1=Zapisano pomy\u015Blnie
+confirm.save.ok2=punkt\u00F3w do pliku
+confirm.deletepoint.single=usuni\u0119to punkt
+confirm.deletepoint.multi=punkt\u00F3w usuni\u0119to
+confirm.point.edit=zmieniono punkt
+confirm.mergetracksegments=Po\u0142\u0105czono fragmenty \u015Bcie\u017Cki
+confirm.reverserange=Odwr\u00F3cono zakres
+confirm.addtimeoffset=Dodano przesuni\u0119cie czasowe
+confirm.rearrangewaypoints=Przestawiono punkty po\u015Brednie
+confirm.cutandmove=Przesuni\u0119to zaznaczenie
+confirm.saveexif.ok1=Zapisano
+confirm.saveexif.ok2=pliki zdj\u0119\u0107
+confirm.undo.single=cofni\u0119to operacj\u0119
+confirm.undo.multi=operacje zosta\u0142y cofni\u0119te
+confirm.jpegload.single=dodano zdj\u0119cie
+confirm.jpegload.multi=zdj\u0119\u0107 dodano
+confirm.photo.connect=przy\u0142\u0105czono zdj\u0119cie
+confirm.photo.disconnect=od\u0142\u0105czono zdj\u0119cie
+confirm.correlate.single=zdj\u0119cie zosta\u0142o po\u0142\u0105czone
+confirm.correlate.multi=zdj\u0119cia zosta\u0142y po\u0142\u0105czone
+confirm.createpoint=stworzono punkt
 
 # Buttons
 button.ok=OK
@@ -271,7 +298,7 @@ button.back=Poprzedni
 button.next=Nast\u0119pny
 button.finish=Koniec
 button.cancel=Anuluj
-button.overwrite=Zapisz Zmiany
+button.overwrite=Nadpisz
 button.moveup=Do g\u00F3ry
 button.movedown=Do d\u00F3\u0142
 button.showlines=Poka\u017C linie
@@ -281,88 +308,97 @@ button.close=Zamknij
 button.continue=Kontynuuj
 button.yes=Tak
 button.no=Nie
-button.yestoall=To wszystko
-button.notoall=Nie wszystko
+button.yestoall=Tak na wszystko
+button.notoall=Nie na wszystko
 button.selectall=Zaznacz wszystko
 button.selectnone=Odznacz
 button.preview=Podgl\u0105d
-button.guessfields=
-button.showwebpage=
+button.guessfields=Zgadnij pola
+button.showwebpage=Poka\u017C stron\u0119 web
+button.gnuplotpath=Podaj \u015Bcie\u017Ck\u0119 do gnuplot
 
 # File types
 filetype.txt=Pliki TXT
 filetype.jpeg=Pliki JPG
 filetype.kmlkmz=Pliki KML, KMZ
 filetype.kml=Pliki KML
+filetype.kmz=Pliki KMZ
 filetype.gpx=Pliki GPX
 filetype.pov=Pliki POV
+filetype.svg=Pliki SVG
 
 # Display components
-display.nodata=Brak za\u0142awadowanych danych
-display.noaltitudes=Track data does not include altitudes
-details.trackdetails=Track szczeg\u00F3\u0142y
-details.notrack=Brak za\u0142awadowanych track
+display.nodata=Nie za\u0142adowano danych
+display.noaltitudes=\u015Acie\u017Cki nie zawieraj\u0105 informacji o wysoko\u015Bci
+details.trackdetails=Szczeg\u00F3\u0142y \u015Bcie\u017Cki
+details.notrack=Brak za\u0142adowanych \u015Bcie\u017Cek
 details.track.points=Punkty
 details.track.file=Plik
-details.track.numfiles=Number ze pliki
-details.pointdetails=Punkt szczeg\u00F3\u0142y
+details.track.numfiles=Ilo\u015B\u0107 plik\u00F3w
+details.pointdetails=Szczeg\u00F3\u0142y punktu
 details.index.selected=Indeks
 details.index.of=z
-details.nopointselection=Brak punkt zaznaczenia
-details.speed=
-details.photofile=Plik zdj\u0119cie
-details.norangeselection=Brak range zaznaczenia
-details.rangedetails=Range szczeg\u00F3\u0142y
-details.range.selected=
-details.range.to=
-details.altitude.to=
-details.range.climb=
-details.range.descent=
-details.coordformat=Format wsp\u00f3\u0142rz\u0119dne
-details.distanceunits=Jednostki dystansowy
+details.nopointselection=\u017Baden punkt nie jest zaznaczony
+details.photofile=Plik zdj\u0119cia
+details.norangeselection=Brak zakresu zaznaczenia
+details.rangedetails=Szczeg\u00F3\u0142y zakresu
+details.range.selected=Wybrany
+details.range.to=do
+details.altitude.to=do
+details.range.climb=Wzniesienie
+details.range.descent=Zst\u0105pienie
+details.coordformat=Format wsp\u00f3\u0142rz\u0119dnych
+details.distanceunits=Jednostki odleg\u0142o\u015Bci
 display.range.time.secs=s
 display.range.time.mins=m
 display.range.time.hours=h
 display.range.time.days=d
-details.range.avespeed=
-details.range.avemovingspeed=
-details.waypointsphotos.waypoints=Waypoints
+details.range.avespeed=\u015Arednia pr\u0119dko\u015B\u0107
+details.range.avemovingspeed=\u015Arednie przesuni\u0119cie
+details.waypointsphotos.waypoints=Punkty po\u015Brednie
 details.waypointsphotos.photos=Zdj\u0119cia
-details.photodetails=Zdj\u0119cie szczeg\u00F3\u0142y
-details.nophoto=Brak zdj\u0119cie zaznaczenia
+details.photodetails=Szczeg\u00F3\u0142y zdj\u0119cia
+details.nophoto=Brak zaznaczonego zdj\u0119cia
 details.photo.loading=Wczytywanie
-details.photo.connected=
+details.photo.connected=Pod\u0142\u0105czony
+map.overzoom=Brak map dla danego powi\u0119kszenia
 
 # Field names
 fieldname.latitude=Szeroko\u015B\u0107
 fieldname.longitude=D\u0142ugo\u015B\u0107
 fieldname.altitude=Wysoko\u015B\u0107
-fieldname.timestamp=
+fieldname.timestamp=Czas
+fieldname.time=Czas
 fieldname.waypointname=Nazwa
-fieldname.waypointtype=Type
-fieldname.newsegment=
+fieldname.waypointtype=Typ
+fieldname.newsegment=Odcinek
 fieldname.custom=U\u017Cytkownika
 fieldname.prefix=Pole
-fieldname.distance=Dystansowy
-fieldname.movingdistance=
-fieldname.duration=
+fieldname.distance=Odleg\u0142o\u015B\u0107
+fieldname.movingdistance=Odleg\u0142o\u015B\u0107 przesuni\u0119cia
+fieldname.duration=Czas trwania
+fieldname.speed=Pr\u0119dko\u015B\u0107
+fieldname.verticalspeed=Pr\u0119dko\u015B\u0107 pionowa
 
 # Measurement units
 units.original=Oryginalny
 units.default=Domy\u015Blny
-units.metres=Metres
+units.metres=Metry
 units.metres.short=m
-units.feet=Feet
+units.feet=Stopy
 units.feet.short=ft
-units.kilometres=Kilometres
+units.kilometres=Kilometry
 units.kilometres.short=km
 units.kmh=km/h
-units.miles=Miles
+units.miles=Mile
 units.miles.short=mi
 units.mph=mi/h
-units.degminsec=Deg-min-sek
-units.degmin=Deg-min
-units.deg=Degrees
+units.metrespersec=m/s
+units.feetpersec=ft/s
+units.hours=Godziny
+units.degminsec=Sto-min-sek
+units.degmin=Sto-min
+units.deg=Stopnie
 units.iso8601=ISO 8601
 
 # External urls
@@ -375,51 +411,49 @@ cardinal.e=E
 cardinal.w=W
 
 # Undo operations
-undo.load=load data
-undo.loadphotos=load zdj\u0119cia
-undo.editpoint=edycja punkt
+undo.load=za\u0142aduj dane
+undo.loadphotos=za\u0142aduj zdj\u0119cia
+undo.editpoint=edycja punktu
 undo.deletepoint=usu\u0144 punkt
-undo.deletephoto=remove zdj\u0119cie
-undo.deleterange=usu\u0144 range
-undo.compress=
-undo.insert=insert punkty
-undo.deleteduplicates=usu\u0144 duplicates
-undo.reverse=
-undo.mergetracksegments=
-undo.addtimeoffset=
-undo.rearrangewaypoints=
-undo.cutandmove=
-undo.connectphoto=connect zdj\u0119cie
-undo.disconnectphoto=disconnect zdj\u0119cie
-undo.correlate=correlate zdj\u0119cia
-undo.createpoint=
+undo.deletephoto=usu\u0144 zdj\u0119cie (nie z dysku)
+undo.deleterange=usu\u0144 zakres
+undo.compress=skompresuj \u015Bcie\u017Ck\u0119
+undo.insert=wstaw punkty
+undo.reverse=odwr\u00F3\u0107 zakres
+undo.mergetracksegments=po\u0142\u0105cz fragmenty \u015Bcie\u017Cki
+undo.addtimeoffset=dodaj przesuni\u0119cie czasowe
+undo.rearrangewaypoints=przestaw punkty po\u015Brednie
+undo.cutandmove=przesu\u0144 fragment
+undo.connectphoto=do\u0142\u0105cz zdj\u0119cie
+undo.disconnectphoto=od\u0142\u0105cz zdj\u0119cie
+undo.correlate=po\u0142\u0105cz ze zdj\u0119ciami
+undo.createpoint=stw\u00F3rz punkt
 
 # Error messages
-error.save.dialogtitle=
-error.save.nodata=
-error.save.failed=Failed to save the data to plik:
-error.saveexif.filenotfound=Failed to find zdj\u0119cie plik
-error.saveexif.cannotoverwrite1=Zdj\u0119cie plik
-error.saveexif.cannotoverwrite2=is read-only and can't be overwritten. Write to copy?
-error.load.dialogtitle=B\u0142\u0105d loading data
-error.load.noread=Cannot read plik
-error.load.nopoints=No koordinaty information found in the plik
-error.load.unknownxml=Nieznany xml format:
-error.load.othererror=B\u0142\u0105d reading plik:
-error.jpegload.dialogtitle=B\u0142\u0105d loading zdj\u0119cia
-error.jpegload.nofilesfound=No pliki found
-error.jpegload.nojpegsfound=No jpeg pliki found
-error.jpegload.noexiffound=No EXIF information found
-error.jpegload.nogpsfound=No GPS information found
-error.undofailed.title=Cofnij failed
+error.save.dialogtitle=B\u0142\u0105d zapisu danych
+error.save.nodata=Brak danych do zapisu
+error.save.failed=Nie powi\u00F3d\u0142 si\u0119 zapis danych do pliku:
+error.saveexif.filenotfound=Nie znaleziono pliku zdj\u0119cia
+error.saveexif.cannotoverwrite1=Plik ze zdj\u0119ciem
+error.saveexif.cannotoverwrite2=jest w trybie tylko do odczytu i nie mo\u017Ce zosta\u0107 nadpisany. Zapisa\u0107 do kopii?
+error.load.dialogtitle=B\u0142\u0105d \u0142adowania danych
+error.load.noread=Nie mo\u017Cna przeczyta\u0107 pliku
+error.load.nopoints=Nie znaleziono informacji o wsp\u00F3\u0142rz\u0119dnych w pliku
+error.load.unknownxml=Nieznany format xml:
+error.load.noxmlinzip=Nie znaleziono pliku xml w pliku zip
+error.load.othererror=B\u0142\u0105d czytania pliku:
+error.jpegload.dialogtitle=B\u0142\u0105d \u0142adowania zdj\u0119cia
+error.jpegload.nofilesfound=Nie znaleziono plik\u00F3w
+error.jpegload.nojpegsfound=Nie znaleziono plik\u00F3w jpeg
+error.jpegload.noexiffound=Nie znaleziono informacji EXIF
+error.jpegload.nogpsfound=Nie znaleziono informacji GPS
+error.undofailed.title=Cofnij nie powiod\u0142o si\u0119
 error.undofailed.text=Nie mo\u017Cna cofn\u0105\u0107
-error.function.noop.title=Funkcji had no effect
-error.rearrange.noop=Rearranging waypoints had no effect
-error.function.notimplemented=
-error.function.notavailable.title=Funkcji nie jest dost\u0119pny
-error.function.nojava3d=This funkcji requires the Java3d library,\navailable from Sun.com.
-error.3d.title=B\u0142\u0105d in 3d display
-error.3d=A b\u0142\u0105d occurred with the 3d display
-error.readme.notfound=
-error.osmimage.dialogtitle=
-error.osmimage.failed=
+error.function.noop.title=Funkcja nie ma skutku
+error.rearrange.noop=Przestawienie punkt\u00F3w po\u015Brednich nie przyniesie skutku
+error.function.notavailable.title=Funkcja nie dost\u0119pna
+error.function.nojava3d=Ta funkcja wymaga biblioteki Java3d,\ndost\u0119pnej na Sun.com.
+error.3d=Nast\u0105pi\u0142 b\u0142\u0105d z wy\u015Bwietlaniem 3D
+error.readme.notfound=Nie znaleziono pliku Readme
+error.osmimage.dialogtitle=B\u0142\u0105d przy \u0142adowaniu obraz\u00F3w map
+error.osmimage.failed=B\u0142\u0105d przy \u0142adowaniu obraz\u00F3w map. Sprawd\u017A po\u0142\u0105czenie z internetem.
diff --git a/tim/prune/lang/prune-texts_pt.properties b/tim/prune/lang/prune-texts_pt.properties
new file mode 100644 (file)
index 0000000..3944ed2
--- /dev/null
@@ -0,0 +1,459 @@
+# Text entries for the Prune application
+# Portuguese entries as extra
+
+# Menu entries
+menu.file=Arquivo
+menu.file.open=Abrir
+menu.file.addphotos=
+menu.file.save=Salvar
+menu.file.exit=Sair
+menu.edit=Editar
+menu.edit.undo=Desfazer
+menu.edit.clearundo=
+menu.edit.editpoint=Editar ponto
+menu.edit.editwaypointname=Editar nome do waypoint
+menu.edit.deletepoint=
+menu.edit.deleterange=
+menu.edit.deletemarked=
+menu.edit.interpolate=
+menu.edit.average=
+menu.edit.reverse=
+menu.edit.mergetracksegments=
+menu.edit.rearrange=
+menu.edit.rearrange.start=
+menu.edit.rearrange.end=
+menu.edit.rearrange.nearest=
+menu.edit.cutandmove=
+menu.select=Selecionar
+menu.select.all=Selectionar tudo
+menu.select.none=Não selecionar nenhuns
+menu.select.start=
+menu.select.end=
+menu.photo=Foto
+menu.photo.saveexif=Salvar exif
+menu.photo.connect=
+menu.photo.disconnect=
+menu.photo.delete=Remover Foto
+menu.view=Exibir
+menu.view.browser=
+menu.view.browser.google=
+menu.view.browser.openstreetmap=
+menu.view.browser.mapquest=
+menu.view.browser.yahoo=
+menu.help=Ajuda
+# Popup menu for map
+menu.map.zoomin=Ampliar zoom
+menu.map.zoomout=Reduzir zoom
+menu.map.zoomfull=
+menu.map.newpoint=
+menu.map.connect=
+menu.map.autopan=
+menu.map.showmap=Mostrar o mapa
+
+# Functions
+function.loadfromgps=
+function.sendtogps=
+function.exportkml=Exportar KML
+function.exportgpx=Exportar GPX
+function.exportpov=Exportar POV
+function.compress=
+function.addtimeoffset=
+function.charts=Diagramas
+function.show3d=Visualizar 3d
+function.distances=Distâncias
+function.setmapbg=
+function.correlatephotos=
+function.help=Ajuda
+function.about=Sobre o Prune
+function.checkversion=
+
+# Dialogs
+dialog.exit.confirm.title=
+dialog.exit.confirm.text=
+dialog.openappend.title=
+dialog.openappend.text=
+dialog.deletepoint.title=
+dialog.deletepoint.deletephoto=
+dialog.deletephoto.title=
+dialog.deletephoto.deletepoint=
+dialog.openoptions.title=
+dialog.openoptions.filesnippet=
+dialog.load.table.field=
+dialog.load.table.datatype=
+dialog.load.table.description=
+dialog.delimiter.label=
+dialog.delimiter.comma=
+dialog.delimiter.tab=
+dialog.delimiter.space=
+dialog.delimiter.semicolon=
+dialog.delimiter.other=
+dialog.openoptions.deliminfo.records=
+dialog.openoptions.deliminfo.fields=
+dialog.openoptions.deliminfo.norecords=
+dialog.openoptions.altitudeunits=
+dialog.jpegload.subdirectories=
+dialog.jpegload.loadjpegswithoutcoords=
+dialog.jpegload.loadjpegsoutsidearea=
+dialog.jpegload.progress.title=
+dialog.jpegload.progress=
+dialog.gpsload.nogpsbabel=
+dialog.gpsload.device=
+dialog.gpsload.format=
+dialog.gpsload.getwaypoints=
+dialog.gpsload.gettracks=
+dialog.gpssend.sendwaypoints=
+dialog.gpssend.sendtracks=
+dialog.gpssend.trackname=
+dialog.saveoptions.title=
+dialog.save.fieldstosave=
+dialog.save.table.field=
+dialog.save.table.hasdata=
+dialog.save.table.save=
+dialog.save.headerrow=
+dialog.save.coordinateunits=
+dialog.save.altitudeunits=
+dialog.save.timestampformat=
+dialog.save.overwrite.title=
+dialog.save.overwrite.text=
+dialog.exportkml.text=
+dialog.exportkml.altitude=
+dialog.exportkml.kmz=
+dialog.exportkml.exportimages=
+dialog.exportgpx.name=
+dialog.exportgpx.desc=
+dialog.exportgpx.includetimestamps=
+dialog.exportpov.text=
+dialog.exportpov.font=
+dialog.exportpov.camerax=
+dialog.exportpov.cameray=
+dialog.exportpov.cameraz=
+dialog.exportpov.modelstyle=
+dialog.exportpov.ballsandsticks=
+dialog.exportpov.tubesandwalls=
+dialog.exportpov.warningtracksize=
+dialog.confirmreversetrack.title=
+dialog.confirmreversetrack.text=
+dialog.confirmcutandmove.title=
+dialog.confirmcutandmove.text=
+dialog.interpolate.title=
+dialog.interpolate.parameter.text=
+dialog.undo.title=
+dialog.undo.pretext=
+dialog.undo.none.title=
+dialog.undo.none.text=
+dialog.clearundo.title=
+dialog.clearundo.text=
+dialog.pointedit.title=
+dialog.pointedit.text=
+dialog.pointedit.table.field=
+dialog.pointedit.table.value=
+dialog.pointedit.table.changed=
+dialog.pointedit.changevalue.text=
+dialog.pointedit.changevalue.title=
+dialog.pointnameedit.title=
+dialog.pointnameedit.name=
+dialog.pointnameedit.uppercase=
+dialog.pointnameedit.lowercase=
+dialog.pointnameedit.sentencecase=
+dialog.addtimeoffset.add=
+dialog.addtimeoffset.subtract=
+dialog.addtimeoffset.days=
+dialog.addtimeoffset.hours=
+dialog.addtimeoffset.minutes=
+dialog.addtimeoffset.notimestamps=
+dialog.connect.title=
+dialog.connectphoto.clonepoint=
+dialog.saveexif.title=
+dialog.saveexif.intro=
+dialog.saveexif.nothingtosave=
+dialog.saveexif.noexiftool=
+dialog.saveexif.table.photoname=
+dialog.saveexif.table.status=
+dialog.saveexif.table.save=
+dialog.saveexif.photostatus.connected=
+dialog.saveexif.photostatus.disconnected=
+dialog.saveexif.photostatus.modified=
+dialog.saveexif.overwrite=
+dialog.charts.xaxis=
+dialog.charts.yaxis=
+dialog.charts.output=
+dialog.charts.screen=
+dialog.charts.svg=
+dialog.charts.svgwidth=
+dialog.charts.svgheight=
+dialog.charts.needaltitudeortimes=
+dialog.charts.gnuplotpath=
+dialog.charts.gnuplotnotfound=
+dialog.distances.intro=
+dialog.distances.column.from=
+dialog.distances.column.to=
+dialog.distances.currentpoint=
+dialog.distances.toofewpoints=
+dialog.setmapbg.mapnik=
+dialog.setmapbg.osma=
+dialog.setmapbg.cyclemap=
+dialog.setmapbg.other=
+dialog.setmapbg.server=
+dialog.correlate.notimestamps=
+dialog.correlate.nouncorrelatedphotos=
+dialog.correlate.photoselect.intro=
+dialog.correlate.photoselect.photoname=
+dialog.correlate.photoselect.timediff=
+dialog.correlate.photoselect.photolater=
+dialog.correlate.options.tip=
+dialog.correlate.options.intro=
+dialog.correlate.options.offsetpanel=
+dialog.correlate.options.offset=
+dialog.correlate.options.offset.hours=
+dialog.correlate.options.offset.minutes=
+dialog.correlate.options.offset.seconds=
+dialog.correlate.options.photolater=
+dialog.correlate.options.pointlater=
+dialog.correlate.options.limitspanel=
+dialog.correlate.options.notimelimit=
+dialog.correlate.options.timelimit=
+dialog.correlate.options.nodistancelimit=
+dialog.correlate.options.distancelimit=
+dialog.correlate.options.correlate=
+dialog.correlate.alloutsiderange=
+dialog.compress.nonefound=
+dialog.compress.duplicates.title=
+dialog.compress.closepoints.title=
+dialog.compress.closepoints.paramdesc=
+dialog.compress.wackypoints.title=
+dialog.compress.wackypoints.paramdesc=
+dialog.compress.singletons.title=
+dialog.compress.singletons.paramdesc=
+dialog.compress.summarylabel=
+dialog.help.help=
+dialog.about.version=
+dialog.about.build=
+dialog.about.summarytext1=
+dialog.about.summarytext2=
+dialog.about.summarytext3=
+dialog.about.languages=
+dialog.about.translatedby=
+dialog.about.systeminfo=
+dialog.about.systeminfo.os=
+dialog.about.systeminfo.java=
+dialog.about.systeminfo.java3d=
+dialog.about.systeminfo.povray=
+dialog.about.systeminfo.exiftool=
+dialog.about.systeminfo.gpsbabel=
+dialog.about.systeminfo.gnuplot=
+dialog.about.yes=Sim
+dialog.about.no=Não
+dialog.about.credits=
+dialog.about.credits.code=
+dialog.about.credits.exifcode=
+dialog.about.credits.icons=
+dialog.about.credits.translators=
+dialog.about.credits.translations=
+dialog.about.credits.devtools=
+dialog.about.credits.othertools=
+dialog.about.credits.thanks=
+dialog.about.readme=
+dialog.checkversion.error=
+dialog.checkversion.uptodate=
+dialog.checkversion.newversion1=
+dialog.checkversion.newversion2=
+dialog.checkversion.releasedate1=
+dialog.checkversion.releasedate2=
+dialog.checkversion.download=
+
+# 3d window
+dialog.3d.title=
+dialog.3d.altitudecap=
+dialog.3dlines.title=
+dialog.3dlines.empty=
+dialog.3dlines.intro=
+
+# Confirm messages || These are displayed as confirmation in the status bar
+confirm.loadfile=
+confirm.save.ok1=
+confirm.save.ok2=
+confirm.deletepoint.single=
+confirm.deletepoint.multi=
+confirm.point.edit=
+confirm.mergetracksegments=
+confirm.reverserange=
+confirm.addtimeoffset=
+confirm.rearrangewaypoints=
+confirm.cutandmove=
+confirm.saveexif.ok1=
+confirm.saveexif.ok2=
+confirm.undo.single=
+confirm.undo.multi=
+confirm.jpegload.single=
+confirm.jpegload.multi=
+confirm.photo.connect=
+confirm.photo.disconnect=
+confirm.correlate.single=
+confirm.correlate.multi=
+confirm.createpoint=
+
+# Buttons
+button.ok=
+button.back=
+button.next=
+button.finish=
+button.cancel=Cancelar
+button.overwrite=
+button.moveup=
+button.movedown=
+button.showlines=
+button.edit=Editar
+button.exit=Sair
+button.close=Fechar
+button.continue=
+button.yes=Sim
+button.no=Não
+button.yestoall=
+button.notoall=
+button.selectall=
+button.selectnone=
+button.preview=
+button.guessfields=
+button.showwebpage=
+button.gnuplotpath=
+
+# File types
+filetype.txt=
+filetype.jpeg=
+filetype.kmlkmz=
+filetype.kml=
+filetype.kmz=
+filetype.gpx=
+filetype.pov=
+filetype.svg=
+
+# Display components
+display.nodata=Nenhum dados foi carregado
+display.noaltitudes=
+details.trackdetails=Detalhes da track
+details.notrack=
+details.track.points=Pontos
+details.track.file=Arquivo
+details.track.numfiles=Número de arquivos
+details.pointdetails=Detalhes da ponto
+details.index.selected=
+details.index.of=de
+details.nopointselection=
+details.photofile=
+details.norangeselection=
+details.rangedetails=Detalhes da range
+details.range.selected=Selecionado
+details.range.to=a
+details.altitude.to=a
+details.range.climb=
+details.range.descent=
+details.coordformat=
+details.distanceunits=
+display.range.time.secs=
+display.range.time.mins=
+display.range.time.hours=
+display.range.time.days=
+details.range.avespeed=
+details.range.avemovingspeed=
+details.waypointsphotos.waypoints=
+details.waypointsphotos.photos=Fotos
+details.photodetails=Detalhes da foto
+details.nophoto=
+details.photo.loading=Carregando
+details.photo.connected=
+map.overzoom=
+
+# Field names
+fieldname.latitude=Latitude
+fieldname.longitude=Longitude
+fieldname.altitude=Altura
+fieldname.timestamp=
+fieldname.time=Tempo
+fieldname.waypointname=
+fieldname.waypointtype=
+fieldname.newsegment=
+fieldname.custom=
+fieldname.prefix=
+fieldname.distance=Distância
+fieldname.movingdistance=
+fieldname.duration=
+fieldname.speed=Velocidade
+fieldname.verticalspeed=
+
+# Measurement units
+units.original=
+units.default=
+units.metres=
+units.metres.short=
+units.feet=
+units.feet.short=
+units.kilometres=
+units.kilometres.short=
+units.kmh=
+units.miles=
+units.miles.short=
+units.mph=
+units.metrespersec=
+units.feetpersec=
+units.hours=
+units.degminsec=
+units.degmin=
+units.deg=
+units.iso8601=
+
+# External urls
+url.googlemaps=maps.google.pt
+
+# Cardinals for 3d plots
+cardinal.n=
+cardinal.s=
+cardinal.e=
+cardinal.w=
+
+# Undo operations
+undo.load=
+undo.loadphotos=
+undo.editpoint=
+undo.deletepoint=
+undo.deletephoto=
+undo.deleterange=
+undo.compress=
+undo.insert=
+undo.reverse=
+undo.mergetracksegments=
+undo.addtimeoffset=
+undo.rearrangewaypoints=
+undo.cutandmove=
+undo.connectphoto=
+undo.disconnectphoto=
+undo.correlate=
+undo.createpoint=
+
+# Error messages
+error.save.dialogtitle=
+error.save.nodata=
+error.save.failed=
+error.saveexif.filenotfound=
+error.saveexif.cannotoverwrite1=
+error.saveexif.cannotoverwrite2=
+error.load.dialogtitle=
+error.load.noread=
+error.load.nopoints=
+error.load.unknownxml=
+error.load.noxmlinzip=
+error.load.othererror=
+error.jpegload.dialogtitle=
+error.jpegload.nofilesfound=
+error.jpegload.nojpegsfound=
+error.jpegload.noexiffound=
+error.jpegload.nogpsfound=
+error.undofailed.title=
+error.undofailed.text=
+error.function.noop.title=
+error.rearrange.noop=
+error.function.notavailable.title=
+error.function.nojava3d=
+error.3d=
+error.readme.notfound=
+error.osmimage.dialogtitle=
+error.osmimage.failed=
diff --git a/tim/prune/lang/prune-texts_ro.properties b/tim/prune/lang/prune-texts_ro.properties
new file mode 100644 (file)
index 0000000..95c1df0
--- /dev/null
@@ -0,0 +1,459 @@
+# Text entries for the Prune application
+# Romanian entries as extra
+
+# Menu entries
+menu.file=Fisier
+menu.file.open=Deschidere fisier
+menu.file.addphotos=Adaugare foto
+menu.file.save=Salvare
+menu.file.exit=Iesire
+menu.edit=Editare
+menu.edit.undo=Anulare
+menu.edit.clearundo=Stergere lista de anulari
+menu.edit.editpoint=Editare punct
+menu.edit.editwaypointname=Editare nume waypoint
+menu.edit.deletepoint=Stergere punct
+menu.edit.deleterange=Stergere gama
+menu.edit.deletemarked=Stergere puncte marcate
+menu.edit.interpolate=Interpolare
+menu.edit.average=Mediere selectie
+menu.edit.reverse=Inversare selectie
+menu.edit.mergetracksegments=Unire segmente traseu
+menu.edit.rearrange=Rearanjare waypoint
+menu.edit.rearrange.start=Toate la inceputul fisierului
+menu.edit.rearrange.end=Toate la sfarsitul fisierului
+menu.edit.rearrange.nearest=Fiecare la punctul cel mai apropiat al traseului
+menu.edit.cutandmove=Taiere si mutare selectie
+menu.select=Selectare
+menu.select.all=Selectare toate
+menu.select.none=Nu selecta niciun punct
+menu.select.start=Seteaza inceputul selectiei
+menu.select.end=Seteaza sfarsitul selectiei
+menu.photo=Foto
+menu.photo.saveexif=Salveaza la Exif
+menu.photo.connect=Conecteaza la punct
+menu.photo.disconnect=Deconecteaza de la punct
+menu.photo.delete=Elimina foto
+menu.view=Vizualizare
+menu.view.browser=Harta in browser
+menu.view.browser.google=Harti Google
+menu.view.browser.openstreetmap=Openstreetmap
+menu.view.browser.mapquest=Mapquest
+menu.view.browser.yahoo=Harti Yahoo
+menu.help=Ajutor
+# Popup menu for map
+menu.map.zoomin=
+menu.map.zoomout=
+menu.map.zoomfull=
+menu.map.newpoint=
+menu.map.connect=
+menu.map.autopan=
+menu.map.showmap=
+
+# Functions
+function.loadfromgps=
+function.sendtogps=
+function.exportkml=
+function.exportgpx=
+function.exportpov=
+function.compress=
+function.addtimeoffset=
+function.charts=
+function.show3d=
+function.distances=
+function.setmapbg=
+function.correlatephotos=
+function.help=
+function.about=
+function.checkversion=
+
+# Dialogs
+dialog.exit.confirm.title=
+dialog.exit.confirm.text=
+dialog.openappend.title=
+dialog.openappend.text=
+dialog.deletepoint.title=
+dialog.deletepoint.deletephoto=
+dialog.deletephoto.title=
+dialog.deletephoto.deletepoint=
+dialog.openoptions.title=
+dialog.openoptions.filesnippet=
+dialog.load.table.field=
+dialog.load.table.datatype=
+dialog.load.table.description=
+dialog.delimiter.label=
+dialog.delimiter.comma=
+dialog.delimiter.tab=
+dialog.delimiter.space=
+dialog.delimiter.semicolon=
+dialog.delimiter.other=
+dialog.openoptions.deliminfo.records=
+dialog.openoptions.deliminfo.fields=
+dialog.openoptions.deliminfo.norecords=
+dialog.openoptions.altitudeunits=
+dialog.jpegload.subdirectories=
+dialog.jpegload.loadjpegswithoutcoords=
+dialog.jpegload.loadjpegsoutsidearea=
+dialog.jpegload.progress.title=
+dialog.jpegload.progress=
+dialog.gpsload.nogpsbabel=
+dialog.gpsload.device=
+dialog.gpsload.format=
+dialog.gpsload.getwaypoints=
+dialog.gpsload.gettracks=
+dialog.gpssend.sendwaypoints=
+dialog.gpssend.sendtracks=
+dialog.gpssend.trackname=
+dialog.saveoptions.title=
+dialog.save.fieldstosave=
+dialog.save.table.field=
+dialog.save.table.hasdata=
+dialog.save.table.save=
+dialog.save.headerrow=
+dialog.save.coordinateunits=
+dialog.save.altitudeunits=
+dialog.save.timestampformat=
+dialog.save.overwrite.title=
+dialog.save.overwrite.text=
+dialog.exportkml.text=
+dialog.exportkml.altitude=
+dialog.exportkml.kmz=
+dialog.exportkml.exportimages=
+dialog.exportgpx.name=
+dialog.exportgpx.desc=
+dialog.exportgpx.includetimestamps=
+dialog.exportpov.text=
+dialog.exportpov.font=
+dialog.exportpov.camerax=
+dialog.exportpov.cameray=
+dialog.exportpov.cameraz=
+dialog.exportpov.modelstyle=
+dialog.exportpov.ballsandsticks=
+dialog.exportpov.tubesandwalls=
+dialog.exportpov.warningtracksize=
+dialog.confirmreversetrack.title=
+dialog.confirmreversetrack.text=
+dialog.confirmcutandmove.title=
+dialog.confirmcutandmove.text=
+dialog.interpolate.title=
+dialog.interpolate.parameter.text=
+dialog.undo.title=
+dialog.undo.pretext=
+dialog.undo.none.title=
+dialog.undo.none.text=
+dialog.clearundo.title=
+dialog.clearundo.text=
+dialog.pointedit.title=
+dialog.pointedit.text=
+dialog.pointedit.table.field=
+dialog.pointedit.table.value=
+dialog.pointedit.table.changed=
+dialog.pointedit.changevalue.text=
+dialog.pointedit.changevalue.title=
+dialog.pointnameedit.title=
+dialog.pointnameedit.name=
+dialog.pointnameedit.uppercase=
+dialog.pointnameedit.lowercase=
+dialog.pointnameedit.sentencecase=
+dialog.addtimeoffset.add=
+dialog.addtimeoffset.subtract=
+dialog.addtimeoffset.days=
+dialog.addtimeoffset.hours=
+dialog.addtimeoffset.minutes=
+dialog.addtimeoffset.notimestamps=
+dialog.connect.title=
+dialog.connectphoto.clonepoint=
+dialog.saveexif.title=
+dialog.saveexif.intro=
+dialog.saveexif.nothingtosave=
+dialog.saveexif.noexiftool=
+dialog.saveexif.table.photoname=
+dialog.saveexif.table.status=
+dialog.saveexif.table.save=
+dialog.saveexif.photostatus.connected=
+dialog.saveexif.photostatus.disconnected=
+dialog.saveexif.photostatus.modified=
+dialog.saveexif.overwrite=
+dialog.charts.xaxis=
+dialog.charts.yaxis=
+dialog.charts.output=
+dialog.charts.screen=
+dialog.charts.svg=
+dialog.charts.svgwidth=
+dialog.charts.svgheight=
+dialog.charts.needaltitudeortimes=
+dialog.charts.gnuplotpath=
+dialog.charts.gnuplotnotfound=
+dialog.distances.intro=
+dialog.distances.column.from=
+dialog.distances.column.to=
+dialog.distances.currentpoint=
+dialog.distances.toofewpoints=
+dialog.setmapbg.mapnik=
+dialog.setmapbg.osma=
+dialog.setmapbg.cyclemap=
+dialog.setmapbg.other=
+dialog.setmapbg.server=
+dialog.correlate.notimestamps=
+dialog.correlate.nouncorrelatedphotos=
+dialog.correlate.photoselect.intro=
+dialog.correlate.photoselect.photoname=
+dialog.correlate.photoselect.timediff=
+dialog.correlate.photoselect.photolater=
+dialog.correlate.options.tip=
+dialog.correlate.options.intro=
+dialog.correlate.options.offsetpanel=
+dialog.correlate.options.offset=
+dialog.correlate.options.offset.hours=
+dialog.correlate.options.offset.minutes=
+dialog.correlate.options.offset.seconds=
+dialog.correlate.options.photolater=
+dialog.correlate.options.pointlater=
+dialog.correlate.options.limitspanel=
+dialog.correlate.options.notimelimit=
+dialog.correlate.options.timelimit=
+dialog.correlate.options.nodistancelimit=
+dialog.correlate.options.distancelimit=
+dialog.correlate.options.correlate=
+dialog.correlate.alloutsiderange=
+dialog.compress.nonefound=
+dialog.compress.duplicates.title=
+dialog.compress.closepoints.title=
+dialog.compress.closepoints.paramdesc=
+dialog.compress.wackypoints.title=
+dialog.compress.wackypoints.paramdesc=
+dialog.compress.singletons.title=
+dialog.compress.singletons.paramdesc=
+dialog.compress.summarylabel=
+dialog.help.help=
+dialog.about.version=
+dialog.about.build=
+dialog.about.summarytext1=
+dialog.about.summarytext2=
+dialog.about.summarytext3=
+dialog.about.languages=
+dialog.about.translatedby=
+dialog.about.systeminfo=
+dialog.about.systeminfo.os=
+dialog.about.systeminfo.java=
+dialog.about.systeminfo.java3d=
+dialog.about.systeminfo.povray=
+dialog.about.systeminfo.exiftool=
+dialog.about.systeminfo.gpsbabel=
+dialog.about.systeminfo.gnuplot=
+dialog.about.yes=
+dialog.about.no=
+dialog.about.credits=
+dialog.about.credits.code=
+dialog.about.credits.exifcode=
+dialog.about.credits.icons=
+dialog.about.credits.translators=
+dialog.about.credits.translations=
+dialog.about.credits.devtools=
+dialog.about.credits.othertools=
+dialog.about.credits.thanks=
+dialog.about.readme=
+dialog.checkversion.error=
+dialog.checkversion.uptodate=
+dialog.checkversion.newversion1=
+dialog.checkversion.newversion2=
+dialog.checkversion.releasedate1=
+dialog.checkversion.releasedate2=
+dialog.checkversion.download=
+
+# 3d window
+dialog.3d.title=
+dialog.3d.altitudecap=
+dialog.3dlines.title=
+dialog.3dlines.empty=
+dialog.3dlines.intro=
+
+# Confirm messages || These are displayed as confirmation in the status bar
+confirm.loadfile=
+confirm.save.ok1=
+confirm.save.ok2=
+confirm.deletepoint.single=
+confirm.deletepoint.multi=
+confirm.point.edit=
+confirm.mergetracksegments=
+confirm.reverserange=
+confirm.addtimeoffset=
+confirm.rearrangewaypoints=
+confirm.cutandmove=
+confirm.saveexif.ok1=
+confirm.saveexif.ok2=
+confirm.undo.single=
+confirm.undo.multi=
+confirm.jpegload.single=
+confirm.jpegload.multi=
+confirm.photo.connect=
+confirm.photo.disconnect=
+confirm.correlate.single=
+confirm.correlate.multi=
+confirm.createpoint=
+
+# Buttons
+button.ok=
+button.back=
+button.next=
+button.finish=
+button.cancel=
+button.overwrite=
+button.moveup=
+button.movedown=
+button.showlines=
+button.edit=
+button.exit=
+button.close=
+button.continue=
+button.yes=
+button.no=
+button.yestoall=
+button.notoall=
+button.selectall=
+button.selectnone=
+button.preview=
+button.guessfields=
+button.showwebpage=
+button.gnuplotpath=
+
+# File types
+filetype.txt=
+filetype.jpeg=
+filetype.kmlkmz=
+filetype.kml=
+filetype.kmz=
+filetype.gpx=
+filetype.pov=
+filetype.svg=
+
+# Display components
+display.nodata=
+display.noaltitudes=
+details.trackdetails=
+details.notrack=
+details.track.points=
+details.track.file=
+details.track.numfiles=
+details.pointdetails=
+details.index.selected=
+details.index.of=
+details.nopointselection=
+details.photofile=
+details.norangeselection=
+details.rangedetails=
+details.range.selected=
+details.range.to=
+details.altitude.to=
+details.range.climb=
+details.range.descent=
+details.coordformat=
+details.distanceunits=
+display.range.time.secs=
+display.range.time.mins=
+display.range.time.hours=
+display.range.time.days=
+details.range.avespeed=
+details.range.avemovingspeed=
+details.waypointsphotos.waypoints=
+details.waypointsphotos.photos=
+details.photodetails=
+details.nophoto=
+details.photo.loading=
+details.photo.connected=
+map.overzoom=
+
+# Field names
+fieldname.latitude=
+fieldname.longitude=
+fieldname.altitude=
+fieldname.timestamp=
+fieldname.time=
+fieldname.waypointname=
+fieldname.waypointtype=
+fieldname.newsegment=
+fieldname.custom=
+fieldname.prefix=
+fieldname.distance=
+fieldname.movingdistance=
+fieldname.duration=
+fieldname.speed=
+fieldname.verticalspeed=
+
+# Measurement units
+units.original=
+units.default=
+units.metres=
+units.metres.short=
+units.feet=
+units.feet.short=
+units.kilometres=
+units.kilometres.short=
+units.kmh=
+units.miles=
+units.miles.short=
+units.mph=
+units.metrespersec=
+units.feetpersec=
+units.hours=
+units.degminsec=
+units.degmin=
+units.deg=
+units.iso8601=
+
+# External urls
+url.googlemaps=
+
+# Cardinals for 3d plots
+cardinal.n=
+cardinal.s=
+cardinal.e=
+cardinal.w=
+
+# Undo operations
+undo.load=
+undo.loadphotos=
+undo.editpoint=
+undo.deletepoint=
+undo.deletephoto=
+undo.deleterange=
+undo.compress=
+undo.insert=
+undo.reverse=
+undo.mergetracksegments=
+undo.addtimeoffset=
+undo.rearrangewaypoints=
+undo.cutandmove=
+undo.connectphoto=
+undo.disconnectphoto=
+undo.correlate=
+undo.createpoint=
+
+# Error messages
+error.save.dialogtitle=
+error.save.nodata=
+error.save.failed=
+error.saveexif.filenotfound=
+error.saveexif.cannotoverwrite1=
+error.saveexif.cannotoverwrite2=
+error.load.dialogtitle=
+error.load.noread=
+error.load.nopoints=
+error.load.unknownxml=
+error.load.noxmlinzip=
+error.load.othererror=
+error.jpegload.dialogtitle=
+error.jpegload.nofilesfound=
+error.jpegload.nojpegsfound=
+error.jpegload.noexiffound=
+error.jpegload.nogpsfound=
+error.undofailed.title=
+error.undofailed.text=
+error.function.noop.title=
+error.rearrange.noop=
+error.function.notavailable.title=
+error.function.nojava3d=
+error.3d=
+error.readme.notfound=
+error.osmimage.dialogtitle=
+error.osmimage.failed=
index 6814e2b093df8aec10b893076cd539287377cdbc..d4d92a0429f239797eb8770bbf419e87e195234e 100644 (file)
@@ -215,9 +215,7 @@ public class FieldSelectionTableModel extends AbstractTableModel
                        if (!hasField(inValue))
                        {
                                // Change is ok - find new Field object corresponding to text
-                               for (int i=0; i<Field.ALL_AVAILABLE_FIELDS.length; i++)
-                                       if (Field.ALL_AVAILABLE_FIELDS[i].getName().equals(inValue))
-                                               _fieldArray[inRow] = Field.ALL_AVAILABLE_FIELDS[i];
+                               _fieldArray[inRow] = Field.getField(inValue);
                        }
                }
                // fire change
index 63c8b24eacfd5a4d9354e35f48a99f6794d9a8a4..de1e7caea8d6b2bd909943f6ad59f34661815096 100644 (file)
@@ -32,7 +32,7 @@ public class FileCacher
         */
        private void loadFile()
        {
-               ArrayList contentList = new ArrayList();
+               ArrayList<String> contentList = new ArrayList<String>();
                if (_file != null && _file.exists() && _file.canRead())
                {
                        BufferedReader reader = null;
@@ -62,7 +62,7 @@ public class FileCacher
                int numLines = contentList.size();
                _contentArray = new String[numLines];
                for (int i=0; i<numLines; i++)
-                       _contentArray[i] = contentList.get(i).toString();
+                       _contentArray[i] = contentList.get(i);
        }
 
 
index 4d9d2be7feb4a06d3e1968b078871352f9e5f087..b3c03b435926411f67f6ab02d164e074d6616fa2 100644 (file)
@@ -4,12 +4,11 @@ import java.io.File;
 
 import javax.swing.JFileChooser;
 import javax.swing.JFrame;
-import javax.swing.JOptionPane;
 
 import tim.prune.App;
 import tim.prune.Config;
-import tim.prune.I18nManager;
 import tim.prune.load.xml.XmlFileLoader;
+import tim.prune.load.xml.ZipFileLoader;
 
 
 /**
@@ -18,10 +17,12 @@ import tim.prune.load.xml.XmlFileLoader;
  */
 public class FileLoader
 {
+       private App _app;
        private JFileChooser _fileChooser = null;
        private JFrame _parentFrame;
        private TextFileLoader _textFileLoader = null;
        private XmlFileLoader _xmlFileLoader = null;
+       private ZipFileLoader _zipFileLoader = null;
 
 
        /**
@@ -31,9 +32,11 @@ public class FileLoader
         */
        public FileLoader(App inApp, JFrame inParentFrame)
        {
+               _app = inApp;
                _parentFrame = inParentFrame;
                _textFileLoader = new TextFileLoader(inApp, inParentFrame);
-               _xmlFileLoader = new XmlFileLoader(inApp, inParentFrame);
+               _xmlFileLoader = new XmlFileLoader(inApp);
+               _zipFileLoader = new ZipFileLoader(inApp, _xmlFileLoader);
        }
 
 
@@ -50,6 +53,7 @@ public class FileLoader
                        _fileChooser.addChoosableFileFilter(new GenericFileFilter("filetype.txt", new String[] {"txt", "text"}));
                        _fileChooser.addChoosableFileFilter(new GenericFileFilter("filetype.gpx", new String[] {"gpx"}));
                        _fileChooser.addChoosableFileFilter(new GenericFileFilter("filetype.kml", new String[] {"kml"}));
+                       _fileChooser.addChoosableFileFilter(new GenericFileFilter("filetype.kmz", new String[] {"kmz"}));
                        _fileChooser.setAcceptAllFileFilterUsed(true);
                        // start from directory in config if already set (by load jpegs)
                        File configDir = Config.getWorkingDirectory();
@@ -74,6 +78,11 @@ public class FileLoader
                                        // Use xml loader for kml, gpx and xml filenames
                                        _xmlFileLoader.openFile(file);
                                }
+                               else if (fileExtension.equals(".kmz") || fileExtension.equals(".zip"))
+                               {
+                                       // Use zip loader for zipped kml (or zipped gpx)
+                                       _zipFileLoader.openFile(file);
+                               }
                                else
                                {
                                        // Use text loader for everything else
@@ -83,8 +92,7 @@ public class FileLoader
                        else
                        {
                                // couldn't read file - show error message
-                               JOptionPane.showMessageDialog(_parentFrame, I18nManager.getText("error.load.noread"),
-                                       I18nManager.getText("error.load.dialogtitle"), JOptionPane.ERROR_MESSAGE);
+                               _app.showErrorMessage("error.load.dialogtitle", "error.load.noread");
                        }
                }
        }
index b803844ea142a0857d997cf8570182779e407032..0d3d8f4dce06b697ba72088040c2470d314ae5fd 100644 (file)
@@ -14,7 +14,6 @@ import javax.swing.BoxLayout;
 import javax.swing.JButton;
 import javax.swing.JCheckBox;
 import javax.swing.JDialog;
-import javax.swing.JFrame;
 import javax.swing.JLabel;
 import javax.swing.JOptionPane;
 import javax.swing.JPanel;
@@ -29,6 +28,7 @@ import javax.xml.parsers.SAXParserFactory;
 import tim.prune.App;
 import tim.prune.Config;
 import tim.prune.ExternalTools;
+import tim.prune.GenericFunction;
 import tim.prune.I18nManager;
 import tim.prune.data.Altitude;
 import tim.prune.load.xml.XmlFileLoader;
@@ -37,48 +37,48 @@ import tim.prune.load.xml.XmlHandler;
 /**
  * Class to manage the loading of GPS data using GpsBabel
  */
-public class GpsLoader implements Runnable
+public class GpsLoader extends GenericFunction implements Runnable
 {
-       private App _app = null;
-       private JFrame _parentFrame = null;
        private boolean _gpsBabelChecked = false;
        private JDialog _dialog = null;
        private JTextField _deviceField = null, _formatField = null;
        private JCheckBox _waypointCheckbox = null, _trackCheckbox = null;
        private JButton _okButton = null;
-       private JProgressBar _waypointProgressBar = null, _trackProgressBar = null;
+       private JProgressBar _progressBar = null;
        private boolean _cancelled = false;
 
 
        /**
         * Constructor
         * @param inApp Application object to inform of data load
-        * @param inParentFrame parent frame to reference for dialogs
         */
-       public GpsLoader(App inApp, JFrame inParentFrame)
+       public GpsLoader(App inApp)
        {
-               _app = inApp;
-               _parentFrame = inParentFrame;
+               super(inApp);
        }
 
+       /** Get the name key */
+       public String getNameKey() {
+               return "function.loadfromgps";
+       }
 
        /**
         * Open the GUI to select options and start the load
         */
-       public void openDialog()
+       public void begin()
        {
                // Check if gpsbabel looks like it's installed
                if (_gpsBabelChecked || ExternalTools.isGpsbabelInstalled()
                        || JOptionPane.showConfirmDialog(_dialog,
                                I18nManager.getText("dialog.gpsload.nogpsbabel"),
-                               I18nManager.getText("dialog.gpsload.title"),
+                               I18nManager.getText(getNameKey()),
                                JOptionPane.YES_NO_OPTION, JOptionPane.WARNING_MESSAGE) == JOptionPane.YES_OPTION)
                {
                        _gpsBabelChecked = true;
                        // Make dialog window
                        if (_dialog == null)
                        {
-                               _dialog = new JDialog(_parentFrame, I18nManager.getText("dialog.gpsload.title"), true);
+                               _dialog = new JDialog(_parentFrame, I18nManager.getText(getNameKey()), true);
                                _dialog.setLocationRelativeTo(_parentFrame);
                                _dialog.setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE);
                                _dialog.getContentPane().add(makeDialogComponents());
@@ -86,8 +86,8 @@ public class GpsLoader implements Runnable
                        }
                        // Initialise progress bars, buttons
                        enableOkButton();
-                       setupProgressBars(true);
-                       _dialog.show();
+                       setupProgressBar(true);
+                       _dialog.setVisible(true);
                }
        }
 
@@ -135,11 +135,9 @@ public class GpsLoader implements Runnable
                _trackCheckbox.addChangeListener(checkboxListener);
                _trackCheckbox.setAlignmentX(Component.CENTER_ALIGNMENT);
                mainPanel.add(_trackCheckbox);
-               // progress bars (initially invisible)
-               _waypointProgressBar = new JProgressBar(0, 10);
-               mainPanel.add(_waypointProgressBar);
-               _trackProgressBar = new JProgressBar(0, 10);
-               mainPanel.add(_trackProgressBar);
+               // progress bar (initially invisible)
+               _progressBar = new JProgressBar(0, 10);
+               mainPanel.add(_progressBar);
                outerPanel.add(mainPanel, BorderLayout.NORTH);
 
                // Lower panel with ok and cancel buttons
@@ -172,16 +170,13 @@ public class GpsLoader implements Runnable
        /**
         * @param inStart true if the dialog is restarting
         */
-       private void setupProgressBars(boolean inStart)
+       private void setupProgressBar(boolean inStart)
        {
                // set visibility
-               _waypointProgressBar.setVisible(!inStart && _waypointCheckbox.isSelected());
-               _trackProgressBar.setVisible(!inStart && _trackCheckbox.isSelected());
+               _progressBar.setVisible(!inStart);
                // set indeterminate flags, initial value
-               _waypointProgressBar.setIndeterminate(false);
-               _waypointProgressBar.setValue(0);
-               _trackProgressBar.setIndeterminate(false);
-               _trackProgressBar.setValue(0);
+               _progressBar.setIndeterminate(false);
+               _progressBar.setValue(0);
        }
 
 
@@ -200,45 +195,23 @@ public class GpsLoader implements Runnable
        public void run()
        {
                _okButton.setEnabled(false);
-               setupProgressBars(false);
-               if (_waypointCheckbox.isSelected())
+               setupProgressBar(false);
+               if (_waypointCheckbox.isSelected() || _trackCheckbox.isSelected())
                {
-                       _waypointProgressBar.setIndeterminate(true);
-                       _trackProgressBar.setIndeterminate(false);
+                       _progressBar.setIndeterminate(true);
                        try
                        {
-                               callGpsBabel(true);
+                               callGpsBabel(_waypointCheckbox.isSelected(), _trackCheckbox.isSelected());
                        }
                        catch (Exception e)
                        {
-                               JOptionPane.showMessageDialog(_dialog, e.getMessage(),
-                                       I18nManager.getText("dialog.gpsload.title"), JOptionPane.ERROR_MESSAGE);
+                               // System.err.println("Error: " + e.getClass().getName());
+                               // System.err.println("Error: " + e.getMessage());
+                               _app.showErrorMessageNoLookup(getNameKey(), e.getMessage());
                                _cancelled = true;
                        }
                }
-               // Exit if cancelled or failed
-               if (_cancelled) {
-                       setupProgressBars(true);
-                       enableOkButton();
-                       return;
-               }
-               if (_trackCheckbox.isSelected())
-               {
-                       _waypointProgressBar.setIndeterminate(false);
-                       _waypointProgressBar.setValue(10);
-                       _trackProgressBar.setIndeterminate(true);
-                       try
-                       {
-                               callGpsBabel(false);
-                       }
-                       catch (Exception e)
-                       {
-                               JOptionPane.showMessageDialog(_dialog, e.getMessage(),
-                                       I18nManager.getText("dialog.gpsload.title"), JOptionPane.ERROR_MESSAGE);
-                               _cancelled = true;
-                       }
-               }
-               setupProgressBars(true);
+               setupProgressBar(true);
                enableOkButton();
 
                // Close dialog
@@ -250,13 +223,27 @@ public class GpsLoader implements Runnable
 
        /**
         * Execute the call to gpsbabel and pass the results back to the app
-        * @param inWaypoints true to get waypoints, false to get track data
+        * @param inWaypoints true to load waypoints
+        * @param inTracks true to load track points
         */
-       private void callGpsBabel(boolean inWaypoints) throws Exception
+       private void callGpsBabel(boolean inWaypoints, boolean inTracks) throws Exception
        {
                // Set up command to call gpsbabel
-               String[] commands = {"gpsbabel", null, "-i", _formatField.getText(), "-f", _deviceField.getText(), "-o", "gpx", "-F", "-"};
-               commands[1] = inWaypoints?"-w":"-t";
+               String[] commands = null;
+               if (inWaypoints && inTracks) {
+                       // Both waypoints and track points selected
+                       commands = new String[] {"gpsbabel", "-w", "-t", "-i", _formatField.getText(),
+                               "-f", _deviceField.getText(), "-o", "gpx", "-F", "-"};
+               }
+               else
+               {
+                       // Only waypoints OR track points selected
+                       commands = new String[] {"gpsbabel", "-w", "-i", _formatField.getText(),
+                               "-f", _deviceField.getText(), "-o", "gpx", "-F", "-"};
+                       if (inTracks) {
+                               commands[1] = "-t";
+                       }
+               }
 
                String errorMessage = "";
                XmlHandler handler = null;
@@ -265,7 +252,7 @@ public class GpsLoader implements Runnable
                // Pass input stream to try to parse the xml
                try
                {
-                       XmlFileLoader xmlLoader = new XmlFileLoader(_app, _parentFrame);
+                       XmlFileLoader xmlLoader = new XmlFileLoader(_app);
                        SAXParser saxParser = SAXParserFactory.newInstance().newSAXParser();
                        saxParser.parse(process.getInputStream(), xmlLoader);
                        handler = xmlLoader.getHandler();
@@ -284,12 +271,16 @@ public class GpsLoader implements Runnable
                while ((line = r.readLine()) != null) {
                        errorMessage2 += line + "\n";
                }
+               // Close error stream
+               try {
+                       r.close();
+               } catch (Exception e) {}
+
                if (errorMessage2.length() > 0) {errorMessage = errorMessage2;}
                if (errorMessage.length() > 0) {throw new Exception(errorMessage);}
 
                // Send data back to app
-               boolean append = _waypointCheckbox.isSelected() && !inWaypoints;
                _app.informDataLoaded(handler.getFieldArray(), handler.getDataArray(),
-                       Altitude.FORMAT_METRES, _deviceField.getText(), append);
+                       Altitude.Format.METRES, _deviceField.getText());
        }
 }
index c506236f44eb3e3e3aa2a37ce6683cd382da85de..7939f1b0080310f28076c6dceff6b317e22d2644 100644 (file)
@@ -13,7 +13,6 @@ import javax.swing.JDialog;
 import javax.swing.JFileChooser;
 import javax.swing.JFrame;
 import javax.swing.JLabel;
-import javax.swing.JOptionPane;
 import javax.swing.JPanel;
 import javax.swing.JProgressBar;
 
@@ -26,7 +25,6 @@ import tim.prune.data.LatLonRectangle;
 import tim.prune.data.Latitude;
 import tim.prune.data.Longitude;
 import tim.prune.data.Photo;
-import tim.prune.data.PhotoStatus;
 import tim.prune.data.Timestamp;
 import tim.prune.drew.jpeg.ExifReader;
 import tim.prune.drew.jpeg.JpegData;
@@ -50,7 +48,7 @@ public class JpegLoader implements Runnable
        private int[] _fileCounts = null;
        private boolean _cancelled = false;
        private LatLonRectangle _trackRectangle = null;
-       private TreeSet _photos = null;
+       private TreeSet<Photo> _photos = null;
 
 
        /**
@@ -136,7 +134,7 @@ public class JpegLoader implements Runnable
                panel.add(cancelButton);
                _progressDialog.getContentPane().add(panel);
                _progressDialog.pack();
-               _progressDialog.show();
+               _progressDialog.setVisible(true);
        }
 
 
@@ -147,7 +145,7 @@ public class JpegLoader implements Runnable
        {
                // Initialise arrays, errors, summaries
                _fileCounts = new int[4]; // files, jpegs, exifs, gps
-               _photos = new TreeSet(new PhotoSorter());
+               _photos = new TreeSet<Photo>(new PhotoSorter());
                File[] files = _fileChooser.getSelectedFiles();
                // Loop recursively over selected files/directories to count files
                int numFiles = countFileList(files, true, _subdirCheckbox.isSelected());
@@ -158,7 +156,7 @@ public class JpegLoader implements Runnable
 
                // Process the files recursively and build lists of photos
                processFileList(files, true, _subdirCheckbox.isSelected());
-               _progressDialog.hide();
+               _progressDialog.setVisible(false);
                if (_cancelled) {return;}
 
                //System.out.println("Finished - counts are: " + _fileCounts[0] + ", " + _fileCounts[1]
@@ -166,26 +164,22 @@ public class JpegLoader implements Runnable
                if (_fileCounts[0] == 0)
                {
                        // No files found at all
-                       JOptionPane.showMessageDialog(_parentFrame, I18nManager.getText("error.jpegload.nofilesfound"),
-                               I18nManager.getText("error.jpegload.dialogtitle"), JOptionPane.ERROR_MESSAGE);
+                       _app.showErrorMessage("error.jpegload.dialogtitle", "error.jpegload.nofilesfound");
                }
                else if (_fileCounts[1] == 0)
                {
                        // No jpegs found
-                       JOptionPane.showMessageDialog(_parentFrame, I18nManager.getText("error.jpegload.nojpegsfound"),
-                               I18nManager.getText("error.jpegload.dialogtitle"), JOptionPane.ERROR_MESSAGE);
+                       _app.showErrorMessage("error.jpegload.dialogtitle", "error.jpegload.nojpegsfound");
                }
                else if (!_noExifCheckbox.isSelected() && _fileCounts[2] == 0)
                {
                        // Need coordinates but no exif found
-                       JOptionPane.showMessageDialog(_parentFrame, I18nManager.getText("error.jpegload.noexiffound"),
-                               I18nManager.getText("error.jpegload.dialogtitle"), JOptionPane.ERROR_MESSAGE);
+                       _app.showErrorMessage("error.jpegload.dialogtitle", "error.jpegload.noexiffound");
                }
                else if (!_noExifCheckbox.isSelected() && _fileCounts[3] == 0)
                {
                        // Need coordinates but no gps information found
-                       JOptionPane.showMessageDialog(_parentFrame, I18nManager.getText("error.jpegload.nogpsfound"),
-                               I18nManager.getText("error.jpegload.dialogtitle"), JOptionPane.ERROR_MESSAGE);
+                       _app.showErrorMessage("error.jpegload.dialogtitle", "error.jpegload.nogpsfound");
                }
                else
                {
@@ -271,7 +265,7 @@ public class JpegLoader implements Runnable
                                point.setPhoto(photo);
                                point.setSegmentStart(true);
                                photo.setDataPoint(point);
-                               photo.setOriginalStatus(PhotoStatus.TAGGED);
+                               photo.setOriginalStatus(Photo.Status.TAGGED);
                                _fileCounts[3]++;
                        }
                        // Use exif timestamp if gps timestamp not available
@@ -352,7 +346,7 @@ public class JpegLoader implements Runnable
                Altitude altitude = null;
                if (inData.getAltitude() != null)
                {
-                       altitude = new Altitude(inData.getAltitude().intValue(), Altitude.FORMAT_METRES);
+                       altitude = new Altitude(inData.getAltitude().intValue(), Altitude.Format.METRES);
                }
                return new DataPoint(latitude, longitude, altitude);
        }
index 7e65cacb1e28d432d85fe8d7e36280833fcdd66c..6da6f64828aa559a858dc83472fced11c4c23f80 100644 (file)
@@ -8,17 +8,17 @@ import tim.prune.data.Photo;
 /**
  * Class to sort photos by name
  */
-public class PhotoSorter implements Comparator
+public class PhotoSorter implements Comparator<Photo>
 {
 
        /**
         * Compare two photos
         * @see java.util.Comparator#compare(java.lang.Object, java.lang.Object)
         */
-       public int compare(Object o1, Object o2)
+       public int compare(Photo o1, Photo o2)
        {
-               File file1 = ((Photo) o1).getFile();
-               File file2 = ((Photo) o2).getFile();
+               File file1 = o1.getFile();
+               File file2 = o2.getFile();
                int nameComp = file1.getName().compareTo(file2.getName());
                if (nameComp == 0)
                {
index 0d7ef481056d515595cedf2ea217f5c2ff66e54e..d4a9aa648bdd31df94288e68d15d6cb286be672f 100644 (file)
@@ -54,7 +54,7 @@ public class TextFileLoader
        // previously selected values
        private char _lastUsedDelimiter = ',';
        private Field[] _lastSelectedFields = null;
-       private int _lastAltitudeFormat = Altitude.FORMAT_NONE;
+       private Altitude.Format _lastAltitudeFormat = Altitude.Format.NO_FORMAT;
 
        // constants
        private static final int SNIPPET_SIZE = 6;
@@ -122,12 +122,11 @@ public class TextFileLoader
                                _delimiterRadios[_delimiterRadios.length-1].setSelected(true);
                        informDelimiterSelected();
                        _dialog.pack();
-                       _dialog.show();
+                       _dialog.setVisible(true);
                }
-               else
-               {
-                       JOptionPane.showMessageDialog(_parentFrame, I18nManager.getText("error.load.noread"),
-                               I18nManager.getText("error.load.dialogtitle"), JOptionPane.ERROR_MESSAGE);
+               else {
+                       // Didn't pass pre-check
+                       _app.showErrorMessage("error.load.dialogtitle", "error.load.noread");
                }
        }
 
@@ -318,7 +317,7 @@ public class TextFileLoader
                JScrollPane tableScrollPane = new JScrollPane(extractTable);
                extractTable.setPreferredScrollableViewportSize(new Dimension(350, 80));
                extractTable.getTableHeader().setReorderingAllowed(false);
-               secondCard.add(makeLabelledPanel("dialog.openoptions.tabledesc", tableScrollPane), BorderLayout.NORTH);
+               secondCard.add(makeLabelledPanel("dialog.openoptions.filesnippet", tableScrollPane), BorderLayout.NORTH);
                JPanel innerPanel2 = new JPanel();
                innerPanel2.setLayout(new BorderLayout());
                innerPanel2.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
@@ -494,16 +493,17 @@ public class TextFileLoader
                _fieldTable.setModel(_fieldTableModel);
                // add dropdowns to second column
                JComboBox fieldTypesBox = new JComboBox();
-               for (int i=0; i<Field.ALL_AVAILABLE_FIELDS.length; i++)
+               String[] fieldNames = Field.getFieldNames();
+               for (int i=0; i<fieldNames.length; i++)
                {
-                       fieldTypesBox.addItem(Field.ALL_AVAILABLE_FIELDS[i].getName());
+                       fieldTypesBox.addItem(fieldNames[i]);
                }
                _fieldTable.getColumnModel().getColumn(1).setCellEditor(new DefaultCellEditor(fieldTypesBox));
 
                // Set altitude format to same as last time if available
-               if (_lastAltitudeFormat == Altitude.FORMAT_METRES)
+               if (_lastAltitudeFormat == Altitude.Format.METRES)
                        _unitsDropDown.setSelectedIndex(0);
-               else if (_lastAltitudeFormat == Altitude.FORMAT_FEET)
+               else if (_lastAltitudeFormat == Altitude.Format.FEET)
                        _unitsDropDown.setSelectedIndex(1);
                // no selection on field list
                selectField(-1);
@@ -518,10 +518,10 @@ public class TextFileLoader
                // Save delimiter, field array and altitude format for later use
                _lastUsedDelimiter = _currentDelimiter;
                _lastSelectedFields = _fieldTableModel.getFieldArray();
-               int altitudeFormat = Altitude.FORMAT_METRES;
+               Altitude.Format altitudeFormat = Altitude.Format.METRES;
                if (_unitsDropDown.getSelectedIndex() == 1)
                {
-                       altitudeFormat = Altitude.FORMAT_FEET;
+                       altitudeFormat = Altitude.Format.FEET;
                }
                _lastAltitudeFormat = altitudeFormat;
                // give data to App
index b58ec3127cc63bab9541d465a339afcb448d9841..3bdfb3ebbcc892e8a494f8fa3d665eb822a506c8 100644 (file)
@@ -21,7 +21,7 @@ public class GpxHandler extends XmlHandler
        private String _name = null, _latitude = null, _longitude = null;
        private String _elevation = null;
        private String _time = null;
-       private ArrayList _pointList = new ArrayList();
+       private ArrayList<String[]> _pointList = new ArrayList<String[]>();
 
 
        /**
@@ -161,7 +161,7 @@ public class GpxHandler extends XmlHandler
                String[][] result = new String[numPoints][];
                for (int i=0; i<numPoints; i++)
                {
-                       result[i] = (String[]) _pointList.get(i);
+                       result[i] = _pointList.get(i);
                }
                return result;
        }
index 02c9be7cfe6b69b932f3e5acc3ea62d24e7943eb..bed877479aa231c5d2a1ae8ef702c5557b27aa26 100644 (file)
@@ -17,7 +17,7 @@ public class KmlHandler extends XmlHandler
        private boolean _insideCoordinates = false;
        private String _name = null;
        private StringBuffer _coordinates = null;
-       private ArrayList _pointList = new ArrayList();
+       private ArrayList<String[]> _pointList = new ArrayList<String[]>();
 
 
        /**
@@ -97,11 +97,16 @@ public class KmlHandler extends XmlHandler
                else if (numPoints > 1)
                {
                        // Add each of the unnamed track points to list
+                       boolean firstPoint = true;
                        for (int p=0; p<numPoints; p++)
                        {
-                               String[] pointArray = makeStringArray(coordArray[p], null);
-                               if (p==0) {pointArray[4] = "1";}
-                               _pointList.add(pointArray);
+                               if (coordArray[p] != null && coordArray[p].trim().length()>3)
+                               {
+                                       String[] pointArray = makeStringArray(coordArray[p], null);
+                                       if (firstPoint) {pointArray[4] = "1";}
+                                       firstPoint = false;
+                                       _pointList.add(pointArray);
+                               }
                        }
                }
        }
@@ -144,7 +149,7 @@ public class KmlHandler extends XmlHandler
                String[][] result = new String[numPoints][];
                for (int i=0; i<numPoints; i++)
                {
-                       result[i] = (String[]) _pointList.get(i);
+                       result[i] = _pointList.get(i);
                }
                return result;
        }
index 8801d00e08f6db1083a7617b9e9f74106f0e0f69..3f1b2eb6fed19246785cf41a883e75a5c4b7f476 100644 (file)
@@ -1,8 +1,6 @@
 package tim.prune.load.xml;
 
 import java.io.File;
-import javax.swing.JFrame;
-import javax.swing.JOptionPane;
 import javax.xml.parsers.SAXParser;
 import javax.xml.parsers.SAXParserFactory;
 
@@ -21,7 +19,6 @@ public class XmlFileLoader extends DefaultHandler implements Runnable
 {
        private File _file = null;
        private App _app = null;
-       private JFrame _parentFrame = null;
        private XmlHandler _handler = null;
        private String _unknownType = null;
 
@@ -29,24 +26,29 @@ public class XmlFileLoader extends DefaultHandler implements Runnable
        /**
         * Constructor
         * @param inApp Application object to inform of track load
-        * @param inParentFrame parent frame to reference for dialogs
         */
-       public XmlFileLoader(App inApp, JFrame inParentFrame)
+       public XmlFileLoader(App inApp)
        {
                _app = inApp;
-               _parentFrame = inParentFrame;
        }
 
+       /**
+        * Reset the handler to ensure data cleared
+        */
+       public void reset()
+       {
+               _handler = null;
+               _unknownType = null;
+       }
 
        /**
-        * Open the selected file and show the GUI dialog to select load options
+        * Open the selected file
         * @param inFile File to open
         */
        public void openFile(File inFile)
        {
                _file = inFile;
-               _handler = null;
-               _unknownType = null;
+               reset();
                // start new thread in case xml parsing is time-consuming
                new Thread(this).start();
        }
@@ -68,23 +70,21 @@ public class XmlFileLoader extends DefaultHandler implements Runnable
                        if (_handler == null)
                        {
                                // Wasn't either kml or gpx
-                               JOptionPane.showMessageDialog(_parentFrame,
-                                       I18nManager.getText("error.load.unknownxml") + " " + _unknownType,
-                                       I18nManager.getText("error.load.dialogtitle"), JOptionPane.ERROR_MESSAGE);
+                               _app.showErrorMessageNoLookup("error.load.dialogtitle",
+                                       I18nManager.getText("error.load.unknownxml") + " " + _unknownType);
                        }
                        else
                        {
                                // Pass information back to app
                                _app.informDataLoaded(_handler.getFieldArray(), _handler.getDataArray(),
-                                       Altitude.FORMAT_METRES, _file.getName());
+                                       Altitude.Format.METRES, _file.getName());
                        }
                }
                catch (Exception e)
                {
                        // Show error dialog
-                       JOptionPane.showMessageDialog(_parentFrame,
-                               I18nManager.getText("error.load.othererror") + " " + e.getMessage(),
-                               I18nManager.getText("error.load.dialogtitle"), JOptionPane.ERROR_MESSAGE);
+                       _app.showErrorMessageNoLookup("error.load.dialogtitle",
+                               I18nManager.getText("error.load.othererror") + " " + e.getMessage());
                }
        }
 
@@ -101,7 +101,7 @@ public class XmlFileLoader extends DefaultHandler implements Runnable
                {
                        if (qName.equals("kml")) {_handler = new KmlHandler();}
                        else if (qName.equals("gpx")) {_handler = new GpxHandler();}
-                       else if (_unknownType == null && qName != null && !qName.equals(""))
+                       else if (_unknownType == null && !qName.equals(""))
                        {
                                _unknownType = qName;
                        }
diff --git a/tim/prune/load/xml/ZipFileLoader.java b/tim/prune/load/xml/ZipFileLoader.java
new file mode 100644 (file)
index 0000000..cf3801c
--- /dev/null
@@ -0,0 +1,82 @@
+package tim.prune.load.xml;
+
+import java.io.File;
+import java.util.Enumeration;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipFile;
+
+import javax.xml.parsers.SAXParser;
+import javax.xml.parsers.SAXParserFactory;
+
+import tim.prune.App;
+import tim.prune.data.Altitude;
+
+/**
+ * Class to handle the loading of zipped xml files
+ */
+public class ZipFileLoader
+{
+       /** App for callback of file loading */
+       private App _app = null;
+       /** Object to do the handling of the xml */
+       XmlFileLoader _xmlLoader = null;
+
+       /**
+        * Constructor
+        * @param inApp App object
+        * @param inXmlLoader object to do the xml handling
+        */
+       public ZipFileLoader(App inApp, XmlFileLoader inXmlLoader)
+       {
+               _app = inApp;
+               _xmlLoader = inXmlLoader;
+       }
+
+       /**
+        * Open the selected file and show the GUI dialog to select load options
+        * @param inFile File to open
+        */
+       public void openFile(File inFile)
+       {
+               try
+               {
+                       ZipFile file = new ZipFile(inFile);
+                       Enumeration<?> entries = file.entries();
+                       boolean xmlFound = false;
+                       while (entries.hasMoreElements() && !xmlFound)
+                       {
+                               ZipEntry entry = (ZipEntry) entries.nextElement();
+                               String entryName = entry.toString();
+                               if (entryName != null && entryName.length() > 4)
+                               {
+                                       String suffix = entryName.substring(entryName.length()-4).toLowerCase();
+                                       if (suffix.equals(".kml") || suffix.equals(".gpx") || suffix.equals(".xml"))
+                                       {
+                                               _xmlLoader.reset();
+                                               SAXParser saxParser = SAXParserFactory.newInstance().newSAXParser();
+                                               saxParser.parse(file.getInputStream(entry), _xmlLoader);
+                                               XmlHandler handler = _xmlLoader.getHandler();
+                                               if (handler == null) {
+                                                       _app.showErrorMessage("error.load.dialogtitle", "error.load.othererror");
+                                               }
+                                               else {
+                                                       // Send back to app
+                                                       _app.informDataLoaded(handler.getFieldArray(), handler.getDataArray(),
+                                                               Altitude.Format.METRES, inFile.getName());
+                                                       xmlFound = true;
+                                               }
+                                       }
+                               }
+                       }
+                       file.close();
+                       // Check whether there was an xml file inside
+                       if (!xmlFound) {
+                               _app.showErrorMessage("error.load.dialogtitle", "error.load.noxmlinzip");
+                       }
+               }
+               catch (Exception e) {
+                       System.err.println("Error: " + e.getMessage());
+               }
+       }
+
+}
index bdc6cae04187d792deac0e6112a553a3c1a42e99..660750a38e579641190d00249c84fbbbcd598ada 100644 (file)
@@ -1,8 +1,9 @@
-Prune version 6
+Prune version 7
 ===============
 
 Prune is an application for viewing, editing and managing coordinate data from GPS systems,
-including format conversion and photo correlation.
+including format conversion, charting and photo correlation.
+Full details can be found at http://activityworkshop.net/software/prune/
 
 Prune is copyright activityworkshop.net and distributed under the terms of the Gnu GPL version 2.
 You may freely use the software, and may help others to freely use it too.  For further information
@@ -16,7 +17,7 @@ Running
 =======
 
 To run Prune from the jar file, simply call it from a command prompt or shell:
-   java -jar prune_06.jar
+   java -jar prune_07.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
@@ -24,9 +25,21 @@ 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 prune_06.jar --lang=DE
+   java -jar prune_07.jar --lang=DE
 
 
+New with version 7
+==================
+
+The following features were added since version 6:
+  - Loading of KMZ files and zipped GPX
+  - Improved compression functions with four configurable algorithms
+  - New function to call gpsbabel to send data directly to GPS receiver
+  - Charting functions (eg altitude or speed against distance) using gnuplot
+  - Map view can now use other OpenStreetMap images such as OpenCycleMap or any other tile server
+  - New function to create an average position from a track section
+  - Display of straight line distances between waypoints
+
 New with version 6
 ==================
 
index a5ae40295054d5eace532c3a542c53d99d510f07..6533fcbed0e39f3043bde1bca12cf22c762374f2 100644 (file)
@@ -27,7 +27,6 @@ import tim.prune.data.Coordinate;
 import tim.prune.data.DataPoint;
 import tim.prune.data.Photo;
 import tim.prune.data.PhotoList;
-import tim.prune.data.PhotoStatus;
 
 /**
  * Class to call Exiftool to save coordinate information in jpg files
@@ -115,7 +114,7 @@ public class ExifSaver implements Runnable
                _dialog.pack();
                // set progress bar and show dialog
                _progressBar.setVisible(false);
-               _dialog.show();
+               _dialog.setVisible(true);
                return true;
        }
 
@@ -291,7 +290,7 @@ public class ExifSaver implements Runnable
                        }
                }
                String[] command = null;
-               if (inPhoto.getCurrentStatus() == PhotoStatus.NOT_CONNECTED)
+               if (inPhoto.getCurrentStatus() == Photo.Status.NOT_CONNECTED)
                {
                        // Photo is no longer connected, so delete gps tags
                        command = getDeleteGpsExifTagsCommand(inPhoto.getFile(), inOverwriteFlag);
@@ -369,7 +368,7 @@ public class ExifSaver implements Runnable
                result[paramOffset + 3] = "-GPSLongitudeRef=" + inPoint.getLongitude().output(Coordinate.FORMAT_CARDINAL);
                // add altitude if it has it
                result[paramOffset + 4] = "-GPSAltitude="
-                + (inPoint.hasAltitude()?inPoint.getAltitude().getValue(Altitude.FORMAT_METRES):0);
+                + (inPoint.hasAltitude()?inPoint.getAltitude().getValue(Altitude.Format.METRES):0);
                result[paramOffset + 5] = "-GPSAltitudeRef='Above Sea Level'";
                // add the filename to modify
                result[paramOffset + 6] = inFile.getAbsolutePath();
index e4a27733aa5e6bad2292a720b8b892d6fc7db7b5..15d568c1b9213c6e2bdbf32e32bb353c5d517699 100644 (file)
@@ -109,7 +109,7 @@ public class FieldSelectionTableModel extends AbstractTableModel
        /**
         * @return Class of cell data
         */
-       public Class getColumnClass(int inColumnIndex)
+       public Class<?> getColumnClass(int inColumnIndex)
        {
                if (inColumnIndex==0) return String.class;
                return Boolean.class;
index 5991b8636ef8b26f99b14a160016f109906f708f..ea4efb87087f0ca33309b1edb2454ba7564018c7 100644 (file)
@@ -70,7 +70,7 @@ public class FileSaver
        private JRadioButton[] _timestampUnitsRadios = null;
        private static final int[] FORMAT_COORDS = {Coordinate.FORMAT_NONE, Coordinate.FORMAT_DEG_MIN_SEC,
                Coordinate.FORMAT_DEG_MIN, Coordinate.FORMAT_DEG};
-       private static final int[] FORMAT_ALTS = {Altitude.FORMAT_NONE, Altitude.FORMAT_METRES, Altitude.FORMAT_FEET};
+       private static final Altitude.Format[] FORMAT_ALTS = {Altitude.Format.NO_FORMAT, Altitude.Format.METRES, Altitude.Format.FEET};
        private static final int[] FORMAT_TIMES = {Timestamp.FORMAT_ORIGINAL, Timestamp.FORMAT_LOCALE, Timestamp.FORMAT_ISO_8601};
 
 
@@ -113,7 +113,7 @@ public class FileSaver
                }
                // Initialise dialog and show it
                initDialog(_model, inDefaultDelimiter);
-               _dialog.show();
+               _dialog.setVisible(true);
        }
 
 
@@ -404,7 +404,7 @@ public class FileSaver
                        for (int i=0; i<_coordUnitsRadios.length; i++)
                                if (_coordUnitsRadios[i].isSelected())
                                        coordFormat = FORMAT_COORDS[i];
-                       int altitudeFormat = Altitude.FORMAT_NONE;
+                       Altitude.Format altitudeFormat = Altitude.Format.NO_FORMAT;
                        for (int i=0; i<_altitudeUnitsRadios.length; i++)
                        {
                                if (_altitudeUnitsRadios[i].isSelected())
@@ -540,10 +540,8 @@ public class FileSaver
                                catch (IOException ioe)
                                {
                                        saveOK = false;
-                                       JOptionPane.showMessageDialog(_parentFrame,
-                                               I18nManager.getText("error.save.failed") + ioe.getMessage(),
-                                               I18nManager.getText("error.save.dialogtitle"),
-                                               JOptionPane.ERROR_MESSAGE);
+                                       _app.showErrorMessageNoLookup("error.save.dialogtitle",
+                                               I18nManager.getText("error.save.failed") + " : " + ioe.getMessage());
                                }
                                finally
                                {
diff --git a/tim/prune/save/GpsSaver.java b/tim/prune/save/GpsSaver.java
new file mode 100644 (file)
index 0000000..e3777a2
--- /dev/null
@@ -0,0 +1,271 @@
+package tim.prune.save;
+
+import java.awt.BorderLayout;
+import java.awt.Component;
+import java.awt.FlowLayout;
+import java.awt.GridLayout;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.io.BufferedReader;
+import java.io.InputStreamReader;
+import java.io.OutputStreamWriter;
+
+import javax.swing.BorderFactory;
+import javax.swing.BoxLayout;
+import javax.swing.JButton;
+import javax.swing.JCheckBox;
+import javax.swing.JDialog;
+import javax.swing.JLabel;
+import javax.swing.JOptionPane;
+import javax.swing.JPanel;
+import javax.swing.JProgressBar;
+import javax.swing.JTextField;
+import javax.swing.SwingConstants;
+import javax.swing.event.ChangeEvent;
+import javax.swing.event.ChangeListener;
+
+import tim.prune.App;
+import tim.prune.Config;
+import tim.prune.ExternalTools;
+import tim.prune.GenericFunction;
+import tim.prune.I18nManager;
+
+/**
+ * Class to manage the loading of GPS data using GpsBabel
+ */
+public class GpsSaver extends GenericFunction implements Runnable
+{
+       private boolean _gpsBabelChecked = false;
+       private JDialog _dialog = null;
+       private JTextField _deviceField = null, _formatField = null;
+       private JTextField _trackNameField = null;
+       private JCheckBox _waypointCheckbox = null, _trackCheckbox = null;
+       private JButton _okButton = null;
+       private JProgressBar _progressBar = null;
+       private boolean _cancelled = false;
+
+
+       /**
+        * Constructor
+        * @param inApp app object
+        */
+       public GpsSaver(App inApp)
+       {
+               super(inApp);
+       }
+
+       /** get name key */
+       public String getNameKey() {
+               return "function.sendtogps";
+       }
+
+       /**
+        * Open the GUI to select options and start the load
+        */
+       public void begin()
+       {
+               // Check if gpsbabel looks like it's installed
+               if (_gpsBabelChecked || ExternalTools.isGpsbabelInstalled()
+                       || JOptionPane.showConfirmDialog(_dialog,
+                               I18nManager.getText("dialog.gpsload.nogpsbabel"),
+                               I18nManager.getText(getNameKey()),
+                               JOptionPane.YES_NO_OPTION, JOptionPane.WARNING_MESSAGE) == JOptionPane.YES_OPTION)
+               {
+                       _gpsBabelChecked = true;
+                       // Make dialog window
+                       if (_dialog == null)
+                       {
+                               _dialog = new JDialog(_parentFrame, I18nManager.getText("function.sendtogps"), true);
+                               _dialog.setLocationRelativeTo(_parentFrame);
+                               _dialog.setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE);
+                               _dialog.getContentPane().add(makeDialogComponents());
+                               _dialog.pack();
+                       }
+                       // Initialise progress bars, buttons
+                       enableOkButton();
+                       setupProgressBar(true);
+                       _dialog.setVisible(true);
+               }
+       }
+
+
+       /**
+        * @return a panel containing the main dialog components
+        */
+       private JPanel makeDialogComponents()
+       {
+               JPanel outerPanel = new JPanel();
+               outerPanel.setLayout(new BorderLayout());
+               // Main panel with options etc
+               JPanel mainPanel = new JPanel();
+               mainPanel.setLayout(new BoxLayout(mainPanel, BoxLayout.Y_AXIS));
+
+               // text fields for options
+               JPanel gridPanel = new JPanel();
+               gridPanel.setLayout(new GridLayout(0, 2, 10, 3));
+               JLabel deviceLabel = new JLabel(I18nManager.getText("dialog.gpsload.device"));
+               deviceLabel.setHorizontalAlignment(SwingConstants.RIGHT);
+               gridPanel.add(deviceLabel);
+               _deviceField = new JTextField(Config.getGpsDevice(), 12);
+               gridPanel.add(_deviceField);
+               JLabel formatLabel = new JLabel(I18nManager.getText("dialog.gpsload.format"));
+               formatLabel.setHorizontalAlignment(SwingConstants.RIGHT);
+               gridPanel.add(formatLabel);
+               _formatField = new JTextField(Config.getGpsFormat(), 12);
+               gridPanel.add(_formatField);
+               JLabel nameLabel = new JLabel(I18nManager.getText("dialog.gpssend.trackname"));
+               nameLabel.setHorizontalAlignment(SwingConstants.RIGHT);
+               gridPanel.add(nameLabel);
+               _trackNameField = new JTextField("", 12);
+               gridPanel.add(_trackNameField);
+               gridPanel.setAlignmentX(Component.CENTER_ALIGNMENT);
+               gridPanel.setBorder(BorderFactory.createEmptyBorder(10, 5, 5, 20));
+               mainPanel.add(gridPanel);
+
+               // checkboxes
+               ChangeListener checkboxListener = new ChangeListener() {
+                       public void stateChanged(ChangeEvent e)
+                       {
+                               enableOkButton();
+                       }
+               };
+               _waypointCheckbox = new JCheckBox(I18nManager.getText("dialog.gpssend.sendwaypoints"), true);
+               _waypointCheckbox.addChangeListener(checkboxListener);
+               _waypointCheckbox.setAlignmentX(Component.CENTER_ALIGNMENT);
+               mainPanel.add(_waypointCheckbox);
+               _trackCheckbox = new JCheckBox(I18nManager.getText("dialog.gpssend.sendtracks"), true);
+               _trackCheckbox.addChangeListener(checkboxListener);
+               _trackCheckbox.setAlignmentX(Component.CENTER_ALIGNMENT);
+               mainPanel.add(_trackCheckbox);
+
+               // progress bar (initially invisible)
+               _progressBar = new JProgressBar(0, 10);
+               mainPanel.add(_progressBar);
+               outerPanel.add(mainPanel, BorderLayout.NORTH);
+
+               // Lower panel with ok and cancel buttons
+               JPanel buttonPanel = new JPanel();
+               buttonPanel.setLayout(new FlowLayout(FlowLayout.RIGHT));
+               _okButton = new JButton(I18nManager.getText("button.ok"));
+               _okButton.addActionListener(new ActionListener() {
+                       public void actionPerformed(ActionEvent e)
+                       {
+                               // start thread to call gpsbabel
+                               _cancelled = false;
+                               new Thread(GpsSaver.this).start();
+                       }
+               });
+               buttonPanel.add(_okButton);
+               JButton cancelButton = new JButton(I18nManager.getText("button.cancel"));
+               cancelButton.addActionListener(new ActionListener() {
+                       public void actionPerformed(ActionEvent e)
+                       {
+                               _cancelled = true;
+                               _dialog.dispose();
+                       }
+               });
+               buttonPanel.add(cancelButton);
+               outerPanel.add(buttonPanel, BorderLayout.SOUTH);
+               return outerPanel;
+       }
+
+
+       /**
+        * @param inStart true if the dialog is restarting
+        */
+       private void setupProgressBar(boolean inStart)
+       {
+               // set visibility
+               _progressBar.setVisible(!inStart);
+               // set indeterminate flags, initial value
+               _progressBar.setIndeterminate(false);
+               _progressBar.setValue(0);
+       }
+
+
+       /**
+        * Enable or disable the ok button
+        */
+       private void enableOkButton()
+       {
+               _okButton.setEnabled(_waypointCheckbox.isSelected() || _trackCheckbox.isSelected());
+       }
+
+
+       /**
+        * Run method for performing tasks in separate thread
+        */
+       public void run()
+       {
+               _okButton.setEnabled(false);
+               setupProgressBar(false);
+
+               _progressBar.setIndeterminate(true);
+               try
+               {
+                       callGpsBabel();
+               }
+               catch (Exception e)
+               {
+                       JOptionPane.showMessageDialog(_dialog, e.getMessage(),
+                               I18nManager.getText("function.sendtogps"), JOptionPane.ERROR_MESSAGE);
+                       _cancelled = true;
+               }
+
+               setupProgressBar(true);
+               enableOkButton();
+
+               // Close dialog
+               if (!_cancelled) {
+                       _dialog.dispose();
+               }
+       }
+
+
+       /**
+        * Execute the call to gpsbabel
+        */
+       private void callGpsBabel() throws Exception
+       {
+               // Set up command to call gpsbabel
+               String[] commands = null;
+               if (_waypointCheckbox.isSelected() && _trackCheckbox.isSelected()) {
+                       // Both waypoints and track points selected
+                       commands = new String[] {"gpsbabel", "-w", "-t", "-i", "gpx", "-f", "-", "-o", _formatField.getText(),
+                               "-F", _deviceField.getText()};
+               }
+               else
+               {
+                       // Only waypoints OR trackpoints selected
+                       commands = new String[] {"gpsbabel", "-w", "-i", "gpx", "-f", "-", "-o", _formatField.getText(),
+                               "-F", _deviceField.getText()};
+                       if (_trackCheckbox.isSelected()) {
+                               commands[1] = "-t";
+                       }
+               }
+
+               String errorMessage = "";
+               Process process = Runtime.getRuntime().exec(commands);
+
+               String trackName = _trackNameField.getText();
+               if (trackName == null || trackName.equals("")) {trackName = "prune";}
+               // Generate the GPX file and send to the GPS
+               OutputStreamWriter writer = new OutputStreamWriter(process.getOutputStream());
+               GpxExporter.exportData(writer, _app.getTrackInfo().getTrack(), trackName, null, true);
+               writer.close();
+
+               // Read the error stream to see if there's a better error message there
+               BufferedReader r = new BufferedReader(new InputStreamReader(process.getErrorStream()));
+               String line = null;
+               String errorMessage2 = "";
+               while ((line = r.readLine()) != null) {
+                       errorMessage2 += line + "\n";
+               }
+               // Close error stream
+               try {
+                       r.close();
+               } catch (Exception e) {}
+               if (errorMessage2.length() > 0) {errorMessage = errorMessage2;}
+               if (errorMessage.length() > 0) {throw new Exception(errorMessage);}
+       }
+}
index 5afdda3a91a66e41d3e2fa1cf8e08ea7600a6ce8..89d40ef2efcb2ca2bc8b8e5ab1a78e9277584878 100644 (file)
@@ -18,13 +18,14 @@ import javax.swing.JButton;
 import javax.swing.JCheckBox;
 import javax.swing.JDialog;
 import javax.swing.JFileChooser;
-import javax.swing.JFrame;
 import javax.swing.JLabel;
 import javax.swing.JOptionPane;
 import javax.swing.JPanel;
 import javax.swing.JTextField;
 
+import tim.prune.App;
 import tim.prune.Config;
+import tim.prune.GenericFunction;
 import tim.prune.GpsPruner;
 import tim.prune.I18nManager;
 import tim.prune.UpdateMessageBroker;
@@ -33,16 +34,14 @@ import tim.prune.data.Coordinate;
 import tim.prune.data.DataPoint;
 import tim.prune.data.Timestamp;
 import tim.prune.data.Track;
-import tim.prune.data.TrackInfo;
 import tim.prune.load.GenericFileFilter;
 
 /**
  * Class to export track information
  * into a specified Gpx file
  */
-public class GpxExporter implements Runnable
+public class GpxExporter extends GenericFunction implements Runnable
 {
-       private JFrame _parentFrame = null;
        private Track _track = null;
        private JDialog _dialog = null;
        private JTextField _nameField = null;
@@ -52,38 +51,41 @@ public class GpxExporter implements Runnable
        private File _exportFile = null;
 
        /** version number of Gpx */
-       private static final String GPX_VERSION_NUMBER = "1.1";
+       private static final String GPX_VERSION_NUMBER = "1.0";
        /** this program name */
        private static final String GPX_CREATOR = "Prune v" + GpsPruner.VERSION_NUMBER + " activityworkshop.net";
 
 
        /**
-        * Constructor giving frame and track
-        * @param inParentFrame parent frame
-        * @param inTrackInfo track info object to save
+        * Constructor
+        * @param inApp app object
         */
-       public GpxExporter(JFrame inParentFrame, TrackInfo inTrackInfo)
+       public GpxExporter(App inApp)
        {
-               _parentFrame = inParentFrame;
-               _track = inTrackInfo.getTrack();
+               super(inApp);
+               _track = inApp.getTrackInfo().getTrack();
        }
 
+       /** Get name key */
+       public String getNameKey() {
+               return "function.exportgpx";
+       }
 
        /**
         * Show the dialog to select options and export file
         */
-       public void showDialog()
+       public void begin()
        {
                // Make dialog window
                if (_dialog == null)
                {
-                       _dialog = new JDialog(_parentFrame, I18nManager.getText("dialog.exportgpx.title"), true);
+                       _dialog = new JDialog(_parentFrame, I18nManager.getText(getNameKey()), true);
                        _dialog.setLocationRelativeTo(_parentFrame);
                        _dialog.setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE);
                        _dialog.getContentPane().add(makeDialogComponents());
                        _dialog.pack();
                }
-               _dialog.show();
+               _dialog.setVisible(true);
        }
 
 
@@ -202,7 +204,8 @@ public class GpxExporter implements Runnable
                        // normal writing to file
                        writer = new OutputStreamWriter(new FileOutputStream(_exportFile));
                        // write file
-                       int numPoints = exportData(writer);
+                       int numPoints = exportData(writer, _track, _nameField.getText(),
+                               _descriptionField.getText(), _timestampsCheckbox.isSelected());
 
                        // close file
                        writer.close();
@@ -235,9 +238,15 @@ public class GpxExporter implements Runnable
        /**
         * Export the information to the given writer
         * @param inWriter writer object
+        * @param inTrack track object containing data
+        * @param inName name of track (optional)
+        * @param inDesc description of track (optional)
+        * @param inTimestamps true to export timestamps
         * @return number of points written
+        * @throws IOException if io errors occur on write
         */
-       private int exportData(OutputStreamWriter inWriter) throws IOException
+       public static int exportData(OutputStreamWriter inWriter, Track inTrack, String inName,
+               String inDesc, boolean inTimestamps) throws IOException
        {
                inWriter.write("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<gpx version=\"");
                inWriter.write(GPX_VERSION_NUMBER);
@@ -247,17 +256,18 @@ public class GpxExporter implements Runnable
                        + " xmlns=\"http://www.topografix.com/GPX/1/0\""
                        + " xsi:schemaLocation=\"http://www.topografix.com/GPX/1/0 http://www.topografix.com/GPX/1/0/gpx.xsd\">\n");
                // Name field
-               if (_nameField != null && _nameField.getText() != null && !_nameField.getText().equals(""))
+               String trackName = "PruneTrack";
+               if (inName != null && !inName.equals(""))
                {
+                       trackName = inName;
                        inWriter.write("\t<name>");
-                       inWriter.write(_nameField.getText());
+                       inWriter.write(trackName);
                        inWriter.write("</name>\n");
                }
                // Description field
                inWriter.write("\t<desc>");
-               if (_descriptionField != null && _descriptionField.getText() != null && !_descriptionField.getText().equals(""))
-               {
-                       inWriter.write(_descriptionField.getText());
+               if (inDesc != null && !inDesc.equals("")) {
+                       inWriter.write(inDesc);
                }
                else
                {
@@ -269,14 +279,14 @@ public class GpxExporter implements Runnable
                DataPoint point = null;
                boolean hasTrackpoints = false;
                // Loop over waypoints
-               int numPoints = _track.getNumPoints();
+               int numPoints = inTrack.getNumPoints();
                for (i=0; i<numPoints; i++)
                {
-                       point = _track.getPoint(i);
+                       point = inTrack.getPoint(i);
                        // Make a wpt element for each waypoint
                        if (point.isWaypoint())
                        {
-                               exportWaypoint(point, inWriter);
+                               exportWaypoint(point, inWriter, inTimestamps);
                        }
                        else
                        {
@@ -287,18 +297,18 @@ public class GpxExporter implements Runnable
                if (hasTrackpoints)
                {
                        boolean firstPoint = true;
-                       inWriter.write("\t<trk><trkseg>\n");
+                       inWriter.write("\t<trk><name>" + trackName + "</name><number>1</number><trkseg>\n");
                        // Loop over track points
                        for (i=0; i<numPoints; i++)
                        {
-                               point = _track.getPoint(i);
+                               point = inTrack.getPoint(i);
                                // restart track segment if necessary
                                if (point.getSegmentStart() && !firstPoint) {
                                        inWriter.write("\t</trkseg>\n\t<trkseg>\n");
                                }
                                if (!point.isWaypoint()) {
                                        // export the track point
-                                       exportTrackpoint(point, inWriter);
+                                       exportTrackpoint(point, inWriter, inTimestamps);
                                        firstPoint = false;
                                }
                        }
@@ -313,27 +323,30 @@ public class GpxExporter implements Runnable
         * Export the specified waypoint into the file
         * @param inPoint waypoint to export
         * @param inWriter writer object
+        * @param inTimestamps true to export timestamps too
         * @throws IOException on write failure
         */
-       private void exportWaypoint(DataPoint inPoint, Writer inWriter) throws IOException
+       private static void exportWaypoint(DataPoint inPoint, Writer inWriter, boolean inTimestamps)
+               throws IOException
        {
                inWriter.write("\t<wpt lat=\"");
-               inWriter.write(inPoint.getLatitude().output(Coordinate.FORMAT_DEG_WITHOUT_CARDINAL));
+               inWriter.write(inPoint.getLatitude().output(Coordinate.FORMAT_DECIMAL_FORCE_POINT));
                inWriter.write("\" lon=\"");
-               inWriter.write(inPoint.getLongitude().output(Coordinate.FORMAT_DEG_WITHOUT_CARDINAL));
+               inWriter.write(inPoint.getLongitude().output(Coordinate.FORMAT_DECIMAL_FORCE_POINT));
                inWriter.write("\">\n");
-               inWriter.write("\t\t<name>");
-               inWriter.write(inPoint.getWaypointName().trim());
-               inWriter.write("</name>\n");
                // altitude if available
                if (inPoint.hasAltitude())
                {
                        inWriter.write("\t\t<ele>");
-                       inWriter.write("" + inPoint.getAltitude().getStringValue(Altitude.FORMAT_METRES));
+                       inWriter.write("" + inPoint.getAltitude().getStringValue(Altitude.Format.METRES));
                        inWriter.write("</ele>\n");
                }
-               // timestamp if available (point might have altitude and then be turned into a waypoint)
-               if (inPoint.hasTimestamp() && _timestampsCheckbox.isSelected())
+               // write waypoint name after elevation
+               inWriter.write("\t\t<name>");
+               inWriter.write(inPoint.getWaypointName().trim());
+               inWriter.write("</name>\n");
+               // timestamp if available (point might have timestamp and then be turned into a waypoint)
+               if (inPoint.hasTimestamp() && inTimestamps)
                {
                        inWriter.write("\t\t<time>");
                        inWriter.write(inPoint.getTimestamp().getText(Timestamp.FORMAT_ISO_8601));
@@ -348,23 +361,25 @@ public class GpxExporter implements Runnable
         * Export the specified trackpoint into the file
         * @param inPoint trackpoint to export
         * @param inWriter writer object
+        * @param inTimestamps true to export timestamps too
         */
-       private void exportTrackpoint(DataPoint inPoint, Writer inWriter) throws IOException
+       private static void exportTrackpoint(DataPoint inPoint, Writer inWriter, boolean inTimestamps)
+               throws IOException
        {
                inWriter.write("\t\t<trkpt lat=\"");
-               inWriter.write(inPoint.getLatitude().output(Coordinate.FORMAT_DEG_WITHOUT_CARDINAL));
+               inWriter.write(inPoint.getLatitude().output(Coordinate.FORMAT_DECIMAL_FORCE_POINT));
                inWriter.write("\" lon=\"");
-               inWriter.write(inPoint.getLongitude().output(Coordinate.FORMAT_DEG_WITHOUT_CARDINAL));
+               inWriter.write(inPoint.getLongitude().output(Coordinate.FORMAT_DECIMAL_FORCE_POINT));
                inWriter.write("\">");
                // altitude
                if (inPoint.hasAltitude())
                {
                        inWriter.write("<ele>");
-                       inWriter.write("" + inPoint.getAltitude().getStringValue(Altitude.FORMAT_METRES));
+                       inWriter.write("" + inPoint.getAltitude().getStringValue(Altitude.Format.METRES));
                        inWriter.write("</ele>");
                }
                // timestamp if available (and selected)
-               if (inPoint.hasTimestamp() && _timestampsCheckbox.isSelected())
+               if (inPoint.hasTimestamp() && inTimestamps)
                {
                        inWriter.write("<time>");
                        inWriter.write(inPoint.getTimestamp().getText(Timestamp.FORMAT_ISO_8601));
index 82b4f1c12ca7cc7f679f8896bbe86555142137a0..67ad261f62a5883583c2697ba4937dee7746aabf 100644 (file)
@@ -25,7 +25,6 @@ import javax.swing.JButton;
 import javax.swing.JCheckBox;
 import javax.swing.JDialog;
 import javax.swing.JFileChooser;
-import javax.swing.JFrame;
 import javax.swing.JLabel;
 import javax.swing.JOptionPane;
 import javax.swing.JPanel;
@@ -33,7 +32,9 @@ import javax.swing.JProgressBar;
 import javax.swing.JTextField;
 import javax.swing.SwingConstants;
 
+import tim.prune.App;
 import tim.prune.Config;
+import tim.prune.GenericFunction;
 import tim.prune.I18nManager;
 import tim.prune.UpdateMessageBroker;
 import tim.prune.data.Altitude;
@@ -49,9 +50,8 @@ import tim.prune.load.GenericFileFilter;
  * Class to export track information
  * into a specified Kml file
  */
-public class KmlExporter implements Runnable
+public class KmlExporter extends GenericFunction implements Runnable
 {
-       private JFrame _parentFrame = null;
        private TrackInfo _trackInfo = null;
        private Track _track = null;
        private JDialog _dialog = null;
@@ -71,27 +71,30 @@ public class KmlExporter implements Runnable
 
 
        /**
-        * Constructor giving frame and track
-        * @param inParentFrame parent frame
-        * @param inTrackInfo track info object to save
+        * Constructor
+        * @param inApp app object
         */
-       public KmlExporter(JFrame inParentFrame, TrackInfo inTrackInfo)
+       public KmlExporter(App inApp)
        {
-               _parentFrame = inParentFrame;
-               _trackInfo = inTrackInfo;
-               _track = inTrackInfo.getTrack();
+               super(inApp);
+               _trackInfo = inApp.getTrackInfo();
+               _track = _trackInfo.getTrack();
        }
 
+       /** Get name key */
+       public String getNameKey() {
+               return "function.exportkml";
+       }
 
        /**
         * Show the dialog to select options and export file
         */
-       public void showDialog()
+       public void begin()
        {
                // Make dialog window including whether to compress to kmz (and include pictures) or not
                if (_dialog == null)
                {
-                       _dialog = new JDialog(_parentFrame, I18nManager.getText("dialog.exportkml.title"), true);
+                       _dialog = new JDialog(_parentFrame, I18nManager.getText(getNameKey()), true);
                        _dialog.setLocationRelativeTo(_parentFrame);
                        _dialog.setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE);
                        _dialog.getContentPane().add(makeDialogComponents());
@@ -99,7 +102,7 @@ public class KmlExporter implements Runnable
                }
                enableCheckboxes();
                _progressBar.setVisible(false);
-               _dialog.show();
+               _dialog.setVisible(true);
        }
 
 
@@ -435,12 +438,12 @@ public class KmlExporter implements Runnable
                        inWriter.write("\t\t\t<altitudeMode>absolute</altitudeMode>\n");
                }
                inWriter.write("\t\t\t<coordinates>");
-               inWriter.write(inPoint.getLongitude().output(Coordinate.FORMAT_DEG_WITHOUT_CARDINAL));
+               inWriter.write(inPoint.getLongitude().output(Coordinate.FORMAT_DECIMAL_FORCE_POINT));
                inWriter.write(',');
-               inWriter.write(inPoint.getLatitude().output(Coordinate.FORMAT_DEG_WITHOUT_CARDINAL));
+               inWriter.write(inPoint.getLatitude().output(Coordinate.FORMAT_DECIMAL_FORCE_POINT));
                inWriter.write(",");
                if (inExportAltitude && inPoint.hasAltitude()) {
-                       inWriter.write("" + inPoint.getAltitude().getStringValue(Altitude.FORMAT_METRES));
+                       inWriter.write("" + inPoint.getAltitude().getStringValue(Altitude.Format.METRES));
                }
                else {
                        inWriter.write("0");
@@ -481,12 +484,12 @@ public class KmlExporter implements Runnable
                        inWriter.write("\t\t\t<altitudeMode>absolute</altitudeMode>\n");
                }
                inWriter.write("\t\t\t<coordinates>");
-               inWriter.write(inPoint.getLongitude().output(Coordinate.FORMAT_DEG_WITHOUT_CARDINAL));
+               inWriter.write(inPoint.getLongitude().output(Coordinate.FORMAT_DECIMAL_FORCE_POINT));
                inWriter.write(',');
-               inWriter.write(inPoint.getLatitude().output(Coordinate.FORMAT_DEG_WITHOUT_CARDINAL));
+               inWriter.write(inPoint.getLatitude().output(Coordinate.FORMAT_DECIMAL_FORCE_POINT));
                inWriter.write(",");
                if (inExportAltitude && inPoint.hasAltitude()) {
-                       inWriter.write("" + inPoint.getAltitude().getStringValue(Altitude.FORMAT_METRES));
+                       inWriter.write("" + inPoint.getAltitude().getStringValue(Altitude.Format.METRES));
                }
                else {
                        inWriter.write("0");
@@ -503,13 +506,13 @@ public class KmlExporter implements Runnable
         */
        private void exportTrackpoint(DataPoint inPoint, Writer inWriter, boolean inExportAltitude) throws IOException
        {
-               inWriter.write(inPoint.getLongitude().output(Coordinate.FORMAT_DEG_WITHOUT_CARDINAL));
+               inWriter.write(inPoint.getLongitude().output(Coordinate.FORMAT_DECIMAL_FORCE_POINT));
                inWriter.write(',');
-               inWriter.write(inPoint.getLatitude().output(Coordinate.FORMAT_DEG_WITHOUT_CARDINAL));
+               inWriter.write(inPoint.getLatitude().output(Coordinate.FORMAT_DECIMAL_FORCE_POINT));
                // Altitude either absolute or locked to ground by Google Earth
                inWriter.write(",");
                if (inExportAltitude && inPoint.hasAltitude()) {
-                       inWriter.write("" + inPoint.getAltitude().getStringValue(Altitude.FORMAT_METRES));
+                       inWriter.write("" + inPoint.getAltitude().getStringValue(Altitude.Format.METRES));
                }
                else {
                        inWriter.write("0");
@@ -525,12 +528,12 @@ public class KmlExporter implements Runnable
        private void exportThumbnails(ZipOutputStream inZipStream) throws IOException
        {
                // set up image writer
-               Iterator writers = ImageIO.getImageWritersByFormatName("jpg");
+               Iterator<ImageWriter> writers = ImageIO.getImageWritersByFormatName("jpg");
                if (writers == null || !writers.hasNext())
                {
                        throw new IOException("no JPEG writer found");
                }
-               ImageWriter imageWriter = (ImageWriter) writers.next();
+               ImageWriter imageWriter = writers.next();
 
                int numPoints = _track.getNumPoints();
                DataPoint point = null;
index 8c44f93b6643ed79d7e3e944b9bd5985950bc526..34fd2b98206a3592a48a24c691cc6e926b5c9dd6 100644 (file)
@@ -2,7 +2,6 @@ package tim.prune.save;
 
 import tim.prune.I18nManager;
 import tim.prune.data.Photo;
-import tim.prune.data.PhotoStatus;
 
 /**
  * Class to represent a row of the photo table for saving exif
@@ -35,16 +34,16 @@ public class PhotoTableEntry
         * @param inCurrentStatus current status of photo
         * @return status string for display
         */
-       private static String getStatusString (byte inOriginalStatus, byte inCurrentStatus)
+       private static String getStatusString (Photo.Status inOriginalStatus, Photo.Status inCurrentStatus)
        {
                if (inOriginalStatus != inCurrentStatus)
                {
-                       if (inOriginalStatus == PhotoStatus.NOT_CONNECTED)
+                       if (inOriginalStatus == Photo.Status.NOT_CONNECTED)
                        {
                                // originally didn't have a point, now it has
                                return I18nManager.getText("dialog.saveexif.photostatus.connected");
                        }
-                       if (inCurrentStatus == PhotoStatus.NOT_CONNECTED)
+                       if (inCurrentStatus == Photo.Status.NOT_CONNECTED)
                        {
                                // originally had a point, now it doesn't
                                return I18nManager.getText("dialog.saveexif.photostatus.disconnected");
index 9b616f239f2d214b523133ed764e6f09ad288391..a39b8c9e5e7f85905f9d8327b7ccb6c90e4e1ca4 100644 (file)
@@ -105,7 +105,7 @@ public class PhotoTableModel extends AbstractTableModel
        /**
         * @return Class of cell data
         */
-       public Class getColumnClass(int inColumnIndex)
+       public Class<?> getColumnClass(int inColumnIndex)
        {
                if (inColumnIndex < 2) return String.class;
                return Boolean.class;
index 6f8a32202ef227633ffa533dc62df2f6159e2007..c96d744dbcfc0c35f6886d5e75fbe752cccc7b7a 100644 (file)
@@ -17,7 +17,6 @@ import javax.swing.ButtonGroup;
 import javax.swing.JButton;
 import javax.swing.JDialog;
 import javax.swing.JFileChooser;
-import javax.swing.JFrame;
 import javax.swing.JLabel;
 import javax.swing.JOptionPane;
 import javax.swing.JPanel;
@@ -25,7 +24,9 @@ import javax.swing.JRadioButton;
 import javax.swing.JTextField;
 import javax.swing.SwingConstants;
 
+import tim.prune.App;
 import tim.prune.Config;
+import tim.prune.GenericFunction;
 import tim.prune.I18nManager;
 import tim.prune.UpdateMessageBroker;
 import tim.prune.data.Track;
@@ -37,9 +38,8 @@ import tim.prune.threedee.ThreeDModel;
  * Class to export track information
  * into a specified Pov file
  */
-public class PovExporter
+public class PovExporter extends GenericFunction
 {
-       private JFrame _parentFrame = null;
        private Track _track = null;
        private JDialog _dialog = null;
        private JFileChooser _fileChooser = null;
@@ -56,17 +56,20 @@ public class PovExporter
 
        /**
         * Constructor giving frame and track
-        * @param inParentFrame parent frame
-        * @param inTrack track object to save
+        * @param inApp App object
         */
-       public PovExporter(JFrame inParentFrame, Track inTrack)
+       public PovExporter(App inApp)
        {
-               _parentFrame = inParentFrame;
-               _track = inTrack;
+               super(inApp);
+               _track = inApp.getTrackInfo().getTrack();
                // Set default camera coordinates
                _cameraX = "17"; _cameraY = "13"; _cameraZ = "-20";
        }
 
+       /** Get the name key */
+       public String getNameKey() {
+               return "function.exportpov";
+       }
 
        /**
         * Set the coordinates for the camera (can be any scale)
@@ -104,12 +107,12 @@ public class PovExporter
        /**
         * Show the dialog to select options and export file
         */
-       public void showDialog()
+       public void begin()
        {
                // Make dialog window to select angles, colours etc
                if (_dialog == null)
                {
-                       _dialog = new JDialog(_parentFrame, I18nManager.getText("dialog.exportpov.title"), true);
+                       _dialog = new JDialog(_parentFrame, I18nManager.getText(getNameKey()), true);
                        _dialog.setLocationRelativeTo(_parentFrame);
                        _dialog.getContentPane().add(makeDialogComponents());
                }
@@ -122,7 +125,7 @@ public class PovExporter
                _altitudeCapField.setText("" + _altitudeCap);
                // Show dialog
                _dialog.pack();
-               _dialog.show();
+               _dialog.setVisible(true);
        }
 
 
@@ -636,11 +639,11 @@ public class PovExporter
                inWriter.write(inLineSeparator);
 
                // Loop over all the track segments
-               ArrayList segmentList = getSegmentList(inModel);
-               Iterator segmentIterator = segmentList.iterator();
+               ArrayList<ModelSegment> segmentList = getSegmentList(inModel);
+               Iterator<ModelSegment> segmentIterator = segmentList.iterator();
                while (segmentIterator.hasNext())
                {
-                       ModelSegment segment = (ModelSegment) segmentIterator.next();
+                       ModelSegment segment = segmentIterator.next();
                        int segLength = segment.getNumTrackPoints();
 
                        // if the track segment is long enough, do a cubic spline sphere sweep
@@ -787,9 +790,9 @@ public class PovExporter
         * @param inModel model containing data
         * @return list of ModelSegment objects
         */
-       private static ArrayList getSegmentList(ThreeDModel inModel)
+       private static ArrayList<ModelSegment> getSegmentList(ThreeDModel inModel)
        {
-               ArrayList segmentList = new ArrayList();
+               ArrayList<ModelSegment> segmentList = new ArrayList<ModelSegment>();
                if (inModel != null && inModel.getNumPoints() > 0)
                {
                        ModelSegment currSegment = null;
index 8d1a476c35e35bc4b7fd67e34d5ff1304a38eff8..e3531f08d6acb3f4914e632c6236a0ef2121fd9d 100644 (file)
@@ -42,7 +42,7 @@ import com.sun.j3d.utils.geometry.Cylinder;
 import com.sun.j3d.utils.geometry.Sphere;
 import com.sun.j3d.utils.universe.SimpleUniverse;
 
-import tim.prune.App;
+import tim.prune.FunctionLibrary;
 import tim.prune.I18nManager;
 import tim.prune.data.Altitude;
 import tim.prune.data.Track;
@@ -53,7 +53,6 @@ import tim.prune.data.Track;
  */
 public class Java3DWindow implements ThreeDWindow
 {
-       private App _app = null;
        private Track _track = null;
        private JFrame _parentFrame = null;
        private JFrame _frame = null;
@@ -73,12 +72,10 @@ public class Java3DWindow implements ThreeDWindow
 
        /**
         * Constructor
-        * @param inApp App object to use for callbacks
         * @param inFrame parent frame
         */
-       public Java3DWindow(App inApp, JFrame inFrame)
+       public Java3DWindow(JFrame inFrame)
        {
-               _app = inApp;
                _parentFrame = inFrame;
        }
 
@@ -133,7 +130,7 @@ public class Java3DWindow implements ThreeDWindow
                {
                        if (JOptionPane.showOptionDialog(_frame,
                                        I18nManager.getText("dialog.exportpov.warningtracksize"),
-                                       I18nManager.getText("dialog.exportpov.title"), JOptionPane.OK_CANCEL_OPTION,
+                                       I18nManager.getText("function.exportpov"), JOptionPane.OK_CANCEL_OPTION,
                                        JOptionPane.WARNING_MESSAGE, null, buttonTexts, buttonTexts[1])
                                == JOptionPane.OK_OPTION)
                        {
@@ -171,11 +168,12 @@ public class Java3DWindow implements ThreeDWindow
                _frame = new JFrame(I18nManager.getText("dialog.3d.title"));
                _frame.getContentPane().setLayout(new BorderLayout());
                _frame.getContentPane().add(canvas, BorderLayout.CENTER);
+               _frame.setIconImage(_parentFrame.getIconImage());
                // Make panel for render, close buttons
                JPanel panel = new JPanel();
                panel.setLayout(new FlowLayout(FlowLayout.RIGHT));
                // Add callback button for render
-               JButton renderButton = new JButton(I18nManager.getText("menu.file.exportpov"));
+               JButton renderButton = new JButton(I18nManager.getText("function.exportpov"));
                renderButton.addActionListener(new ActionListener()
                {
                        /** Render button pressed */
@@ -224,7 +222,7 @@ public class Java3DWindow implements ThreeDWindow
                });
 
                // show frame
-               _frame.show();
+               _frame.setVisible(true);
                if (_frame.getState() == JFrame.ICONIFIED)
                {
                        _frame.setState(JFrame.NORMAL);
@@ -570,8 +568,10 @@ public class Java3DWindow implements ThreeDWindow
                Point3d result = new Point3d();
                secondTran.transform(point, result);
                firstTran.transform(result);
-               // Callback settings to App
-               _app.exportPov(result.x, result.y, result.z, _altitudeCap);
+               // Callback settings to pov export function
+               FunctionLibrary.FUNCTION_POVEXPORT.setCameraCoordinates(result.x, result.y, result.z);
+               FunctionLibrary.FUNCTION_POVEXPORT.setAltitudeCap(_altitudeCap);
+               FunctionLibrary.FUNCTION_POVEXPORT.begin();
        }
 
 
@@ -582,8 +582,8 @@ public class Java3DWindow implements ThreeDWindow
         */
        private static String getAltitudeUnitsLabel(Track inTrack)
        {
-               int altitudeFormat = inTrack.getAltitudeRange().getFormat();
-               if (altitudeFormat == Altitude.FORMAT_METRES)
+               Altitude.Format altitudeFormat = inTrack.getAltitudeRange().getFormat();
+               if (altitudeFormat == Altitude.Format.METRES)
                        return I18nManager.getText("units.metres.short");
                return I18nManager.getText("units.feet.short");
        }
index a11525f4671e14f99d435852f0c695489c018f1e..a0f218a65e82bbcd8fe9221a906b957d894a984f 100644 (file)
@@ -52,7 +52,7 @@ public class LineDialog
                _dialog.setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE);
                _dialog.getContentPane().add(makeDialogComponents());
                _dialog.pack();
-               _dialog.show();
+               _dialog.setVisible(true);
        }
 
 
index 5123f7c83bf65d6ad557b49a96f5065da2ef262e..929659bcd8ee92704bd0949b29d951f5579946a9 100644 (file)
@@ -23,6 +23,7 @@ public class ThreeDModel
        private byte[] _pointHeights = null;
 
        private static final double DEFAULT_MODEL_SIZE = 10.0;
+       /** Minimum altitude cap */
        public static final int MINIMUM_ALTITUDE_CAP = 100;
 
        // Constants for point types
@@ -138,7 +139,7 @@ public class ThreeDModel
                {
                        DataPoint point = _track.getPoint(i);
                        _pointTypes[i] = (point.isWaypoint()?POINT_TYPE_WAYPOINT:(point.getSegmentStart()?POINT_TYPE_SEGMENT_START:POINT_TYPE_NORMAL_POINT));
-                       _pointHeights[i] = (byte) (point.getAltitude().getValue(Altitude.FORMAT_METRES) / 500);
+                       _pointHeights[i] = (byte) (point.getAltitude().getValue(Altitude.Format.METRES) / 500);
                }
        }
 
index 4aef1f613a66fee384e49eaae0948bcdd720d658..9d7f170683773e2e3b6af648b903389bd9d6bebf 100644 (file)
@@ -2,8 +2,6 @@ package tim.prune.threedee;
 
 import javax.swing.JFrame;
 
-import tim.prune.App;
-
 /**
  * Factory class for getting a Window
  */
@@ -13,16 +11,15 @@ public abstract class WindowFactory
 
        /**
         * Get a Window object
-        * @param inApp App object
         * @param inFrame parent frame
         * @return object if available, otherwise null
         */
-       public static ThreeDWindow getWindow(App inApp, JFrame inFrame)
+       public static ThreeDWindow getWindow(JFrame inFrame)
        {
                if (isJava3dEnabled())
                {
                        if (_window == null) {
-                               _window = new Java3DWindow(inApp, inFrame);
+                               _window = new Java3DWindow(inFrame);
                        }
                        else {
                                _window.dispose();
@@ -41,7 +38,7 @@ public abstract class WindowFactory
                boolean has3d = false;
                try
                {
-                       Class universeClass = Class.forName("com.sun.j3d.utils.universe.SimpleUniverse");
+                       Class<?> universeClass = Class.forName("com.sun.j3d.utils.universe.SimpleUniverse");
                        has3d = (universeClass != null);
                }
                catch (ClassNotFoundException e)
diff --git a/tim/prune/undo/UndoDeleteDuplicates.java b/tim/prune/undo/UndoDeleteDuplicates.java
deleted file mode 100644 (file)
index ee11a8f..0000000
+++ /dev/null
@@ -1,32 +0,0 @@
-package tim.prune.undo;
-
-import tim.prune.I18nManager;
-import tim.prune.data.Track;
-
-/**
- * Undo duplicate deletion
- */
-public class UndoDeleteDuplicates extends UndoCompress
-{
-
-       /**
-        * Constructor
-        * @param inTrack Track object
-        */
-       public UndoDeleteDuplicates(Track inTrack)
-       {
-               super(inTrack);
-       }
-
-
-       /**
-        * @return description of operation including parameters
-        */
-       public String getDescription()
-       {
-               String desc = I18nManager.getText("undo.deleteduplicates");
-               if (_numPointsDeleted > 0)
-                       desc = desc + " (" + _numPointsDeleted + ")";
-               return desc;
-       }
-}
index a9f566531a37c3efd11ede111846dee844efedb1..1ee16dc72ea1ae6baa0732838ee80af2b3ed494a 100644 (file)
@@ -3,7 +3,7 @@ package tim.prune.undo;
 import tim.prune.I18nManager;\r
 import tim.prune.data.DataPoint;\r
 import tim.prune.data.TrackInfo;\r
-import tim.prune.edit.FieldEditList;\r
+import tim.prune.function.edit.FieldEditList;\r
 \r
 /**\r
  * Operation to undo the edit of a single point\r
@@ -32,8 +32,11 @@ public class UndoEditPoint implements UndoOperation
        public String getDescription()\r
        {\r
                String desc = I18nManager.getText("undo.editpoint");\r
+               String newName = _undoFieldList.getEdit(0).getValue();\r
                String pointName = _originalPoint.getWaypointName();\r
-               if (pointName != null && !pointName.equals(""))\r
+               if (newName != null && !newName.equals(""))\r
+                       desc = desc + " " + newName;\r
+               else if (pointName != null && !pointName.equals(""))\r
                        desc = desc + " " + pointName;\r
                return desc;\r
        }\r
index 51da59577c25ceb0b57001aba3b8c463c0a41943..1b3f3ef9077746e51ad3d723cc442dc36ad373a3 100644 (file)
@@ -1,26 +1,56 @@
 package tim.prune.undo;\r
 \r
 import tim.prune.I18nManager;\r
+import tim.prune.data.DataPoint;\r
 import tim.prune.data.TrackInfo;\r
 \r
 /**\r
- * Operation to undo an insertion (eg interpolate)\r
+ * Operation to undo an insertion (eg interpolate, average)\r
  */\r
 public class UndoInsert implements UndoOperation\r
 {\r
        private int _startPosition = 0;\r
        private int _numInserted = 0;\r
+       private boolean _hasSegmentFlag = false;\r
+       private boolean _segmentFlag = false;\r
 \r
 \r
        /**\r
-        * Constructor\r
+        * Constructor without segment flag\r
         * @param inStart start of insert\r
         * @param inNumInserted number of points inserted\r
         */\r
        public UndoInsert(int inStart, int inNumInserted)\r
+       {\r
+               this(inStart, inNumInserted, false, false);\r
+       }\r
+\r
+\r
+       /**\r
+        * Constructor with segment flag\r
+        * @param inStart start of insert\r
+        * @param inNumInserted number of points inserted\r
+        * @param inSegmentFlag segment flag of following point\r
+        */\r
+       public UndoInsert(int inStart, int inNumInserted, boolean inSegmentFlag)\r
+       {\r
+               this(inStart, inNumInserted, true, inSegmentFlag);\r
+       }\r
+\r
+\r
+       /**\r
+        * Constructor\r
+        * @param inStart start of insert\r
+        * @param inNumInserted number of points inserted\r
+        * @param inHasFlag is there a segment flag present\r
+        * @param inFlag segment flag, if any\r
+        */\r
+       public UndoInsert(int inStart, int inNumInserted, boolean inHasFlag, boolean inFlag)\r
        {\r
                _startPosition = inStart;\r
                _numInserted = inNumInserted;\r
+               _hasSegmentFlag = inHasFlag;\r
+               _segmentFlag = inFlag;\r
        }\r
 \r
 \r
@@ -41,6 +71,10 @@ public class UndoInsert implements UndoOperation
        {\r
                // restore track to previous values\r
                inTrackInfo.getTrack().deleteRange(_startPosition, _startPosition + _numInserted - 1);\r
+               if (_hasSegmentFlag) {\r
+                       DataPoint nextPoint = inTrackInfo.getTrack().getNextTrackPoint(_startPosition);\r
+                       if (nextPoint != null) {nextPoint.setSegmentStart(_segmentFlag);}\r
+               }\r
                // reset selection\r
                inTrackInfo.getSelection().select(_startPosition-1, _startPosition-1, _startPosition);\r
        }\r