]> gitweb.fperrin.net Git - GpsPrune.git/commitdiff
Version 5, May 2008
authoractivityworkshop <mail@activityworkshop.net>
Sat, 14 Feb 2015 13:58:43 +0000 (14:58 +0100)
committeractivityworkshop <mail@activityworkshop.net>
Sat, 14 Feb 2015 13:58:43 +0000 (14:58 +0100)
49 files changed:
tim/prune/App.java
tim/prune/DataSubscriber.java
tim/prune/ExternalTools.java
tim/prune/GpsPruner.java
tim/prune/UpdateMessageBroker.java
tim/prune/browser/BrowserLauncher.java [new file with mode: 0644]
tim/prune/browser/UrlGenerator.java [new file with mode: 0644]
tim/prune/correlate/PhotoCorrelator.java
tim/prune/data/DataPoint.java
tim/prune/data/DoubleRange.java
tim/prune/data/Selection.java
tim/prune/data/Track.java
tim/prune/data/TrackInfo.java
tim/prune/gui/AboutScreen.java
tim/prune/gui/DetailsDisplay.java
tim/prune/gui/GenericDisplay.java
tim/prune/gui/MapChart.java
tim/prune/gui/MenuManager.java
tim/prune/gui/PhotoThumbnail.java
tim/prune/gui/StatusBar.java [new file with mode: 0644]
tim/prune/gui/images/window_icon.png [new file with mode: 0644]
tim/prune/gui/map/MapCanvas.java [new file with mode: 0644]
tim/prune/gui/map/MapWindow.java [new file with mode: 0644]
tim/prune/lang/prune-texts.properties
tim/prune/lang/prune-texts_de.properties
tim/prune/lang/prune-texts_de_CH.properties
tim/prune/lang/prune-texts_es.properties
tim/prune/lang/prune-texts_fr.properties
tim/prune/lang/prune-texts_pl.properties
tim/prune/load/FieldGuesser.java
tim/prune/load/FileSplitter.java
tim/prune/load/JpegLoader.java
tim/prune/load/TextFileLoader.java
tim/prune/load/xml/GpxHandler.java
tim/prune/load/xml/KmlHandler.java
tim/prune/readme.txt
tim/prune/save/ExifSaver.java
tim/prune/save/FileSaver.java
tim/prune/save/GpxExporter.java
tim/prune/save/KmlExporter.java
tim/prune/save/PovExporter.java
tim/prune/undo/UndoCompress.java
tim/prune/undo/UndoConnectPhoto.java
tim/prune/undo/UndoDeletePhoto.java
tim/prune/undo/UndoDeletePoint.java
tim/prune/undo/UndoDeleteRange.java
tim/prune/undo/UndoDisconnectPhoto.java
tim/prune/undo/UndoMergeTrackSegments.java [new file with mode: 0644]
tim/prune/undo/UndoReverseSection.java

index 18a2e79a60fa737cde270045cb0d3b6263dc278f..cb532dbf9d6bcb10a0dfb72ea756b1ac26f1a2b3 100644 (file)
@@ -7,6 +7,8 @@ import java.util.Stack;
 import javax.swing.JFrame;
 import javax.swing.JOptionPane;
 
 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.DataPoint;
 import tim.prune.correlate.PhotoCorrelator;
 import tim.prune.correlate.PointPair;
 import tim.prune.data.DataPoint;
@@ -20,6 +22,7 @@ import tim.prune.edit.PointEditor;
 import tim.prune.edit.PointNameEditor;
 import tim.prune.gui.MenuManager;
 import tim.prune.gui.UndoManager;
 import tim.prune.edit.PointNameEditor;
 import tim.prune.gui.MenuManager;
 import tim.prune.gui.UndoManager;
+import tim.prune.gui.map.MapWindow;
 import tim.prune.load.FileLoader;
 import tim.prune.load.JpegLoader;
 import tim.prune.save.ExifSaver;
 import tim.prune.load.FileLoader;
 import tim.prune.load.JpegLoader;
 import tim.prune.save.ExifSaver;
@@ -43,6 +46,7 @@ import tim.prune.undo.UndoException;
 import tim.prune.undo.UndoInsert;
 import tim.prune.undo.UndoLoad;
 import tim.prune.undo.UndoLoadPhotos;
 import tim.prune.undo.UndoInsert;
 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;
 import tim.prune.undo.UndoOperation;
 import tim.prune.undo.UndoRearrangeWaypoints;
 import tim.prune.undo.UndoReverseSection;
@@ -65,8 +69,8 @@ public class App
        private KmlExporter _kmlExporter = null;
        private GpxExporter _gpxExporter = null;
        private PovExporter _povExporter = null;
        private KmlExporter _kmlExporter = null;
        private GpxExporter _gpxExporter = null;
        private PovExporter _povExporter = null;
+       private BrowserLauncher _browserLauncher = null;
        private Stack _undoStack = null;
        private Stack _undoStack = null;
-       private UpdateMessageBroker _broker = null;
        private boolean _reversePointsConfirmed = false;
 
        // Constants
        private boolean _reversePointsConfirmed = false;
 
        // Constants
@@ -78,15 +82,13 @@ public class App
        /**
         * Constructor
         * @param inFrame frame object for application
        /**
         * Constructor
         * @param inFrame frame object for application
-        * @param inBroker message broker
         */
         */
-       public App(JFrame inFrame, UpdateMessageBroker inBroker)
+       public App(JFrame inFrame)
        {
                _frame = inFrame;
                _undoStack = new Stack();
        {
                _frame = inFrame;
                _undoStack = new Stack();
-               _broker = inBroker;
-               _track = new Track(_broker);
-               _trackInfo = new TrackInfo(_track, _broker);
+               _track = new Track();
+               _trackInfo = new TrackInfo(_track);
        }
 
 
        }
 
 
@@ -138,13 +140,13 @@ public class App
 
 
        /**
 
 
        /**
-        * Add a photo or a directory of photos which are already correlated
+        * Add a photo or a directory of photos
         */
        public void addPhotos()
        {
                if (_jpegLoader == null)
                        _jpegLoader = new JpegLoader(this, _frame);
         */
        public void addPhotos()
        {
                if (_jpegLoader == null)
                        _jpegLoader = new JpegLoader(this, _frame);
-               _jpegLoader.openFile();
+               _jpegLoader.openDialog();
        }
 
 
        }
 
 
@@ -322,6 +324,8 @@ public class App
                        if (_track.editPoint(currentPoint, inEditList))
                        {
                                _undoStack.push(undo);
                        if (_track.editPoint(currentPoint, inEditList))
                        {
                                _undoStack.push(undo);
+                               // Confirm point edit
+                               UpdateMessageBroker.informSubscribers(I18nManager.getText("confirm.point.edit"));
                        }
                }
        }
                        }
                }
        }
@@ -350,50 +354,53 @@ public class App
         */
        public void deleteCurrentPoint()
        {
         */
        public void deleteCurrentPoint()
        {
-               if (_track != null)
+               if (_track == null) {return;}
+               DataPoint currentPoint = _trackInfo.getCurrentPoint();
+               if (currentPoint != null)
                {
                {
-                       DataPoint currentPoint = _trackInfo.getCurrentPoint();
-                       if (currentPoint != null)
+                       boolean deletePhoto = false;
+                       Photo currentPhoto = currentPoint.getPhoto();
+                       if (currentPhoto != null)
+                       {
+                               // Confirm deletion of photo or decoupling
+                               int response = JOptionPane.showConfirmDialog(_frame,
+                                       I18nManager.getText("dialog.deletepoint.deletephoto") + " " + currentPhoto.getFile().getName(),
+                                       I18nManager.getText("dialog.deletepoint.title"),
+                                       JOptionPane.YES_NO_CANCEL_OPTION);
+                               if (response == JOptionPane.CANCEL_OPTION || response == JOptionPane.CLOSED_OPTION)
+                               {
+                                       // cancel pressed- abort delete
+                                       return;
+                               }
+                               if (response == JOptionPane.YES_OPTION) {deletePhoto = true;}
+                       }
+                       // store necessary information to undo it later
+                       int pointIndex = _trackInfo.getSelection().getCurrentPointIndex();
+                       int photoIndex = _trackInfo.getPhotoList().getPhotoIndex(currentPhoto);
+                       DataPoint nextTrackPoint = _trackInfo.getTrack().getNextTrackPoint(pointIndex + 1);
+                       // Construct Undo object
+                       UndoOperation undo = new UndoDeletePoint(pointIndex, currentPoint, photoIndex,
+                               nextTrackPoint != null && nextTrackPoint.getSegmentStart());
+                       // call track to delete point
+                       if (_trackInfo.deletePoint())
                        {
                        {
-                               boolean deletePhoto = false;
-                               Photo currentPhoto = currentPoint.getPhoto();
+                               // Delete was successful so add undo info to stack
+                               _undoStack.push(undo);
                                if (currentPhoto != null)
                                {
                                if (currentPhoto != null)
                                {
-                                       // Confirm deletion of photo or decoupling
-                                       int response = JOptionPane.showConfirmDialog(_frame,
-                                               I18nManager.getText("dialog.deletepoint.deletephoto") + " " + currentPhoto.getFile().getName(),
-                                               I18nManager.getText("dialog.deletepoint.title"),
-                                               JOptionPane.YES_NO_CANCEL_OPTION);
-                                       if (response == JOptionPane.CANCEL_OPTION || response == JOptionPane.CLOSED_OPTION)
+                                       // delete photo if necessary
+                                       if (deletePhoto)
                                        {
                                        {
-                                               // cancel pressed- abort delete
-                                               return;
+                                               _trackInfo.getPhotoList().deletePhoto(photoIndex);
                                        }
                                        }
-                                       if (response == JOptionPane.YES_OPTION) {deletePhoto = true;}
-                               }
-                               // add information to undo stack
-                               int pointIndex = _trackInfo.getSelection().getCurrentPointIndex();
-                               int photoIndex = _trackInfo.getPhotoList().getPhotoIndex(currentPhoto);
-                               // Undo object needs to know index of photo in list (if any) to restore
-                               UndoOperation undo = new UndoDeletePoint(pointIndex, currentPoint, photoIndex);
-                               // call track to delete point
-                               if (_trackInfo.deletePoint())
-                               {
-                                       _undoStack.push(undo);
-                                       if (currentPhoto != null)
+                                       else
                                        {
                                        {
-                                               // delete photo if necessary
-                                               if (deletePhoto)
-                                               {
-                                                       _trackInfo.getPhotoList().deletePhoto(photoIndex);
-                                               }
-                                               else
-                                               {
-                                                       // decouple photo from point
-                                                       currentPhoto.setDataPoint(null);
-                                               }
+                                               // decouple photo from point
+                                               currentPhoto.setDataPoint(null);
                                        }
                                }
                                        }
                                }
+                               // Confirm
+                               UpdateMessageBroker.informSubscribers(I18nManager.getText("confirm.deletepoint.single"));
                        }
                }
        }
                        }
                }
        }
@@ -453,7 +460,7 @@ public class App
                                        }
                                }
                                // add information to undo stack
                                        }
                                }
                                // add information to undo stack
-                               UndoOperation undo = new UndoDeleteRange(_trackInfo);
+                               UndoDeleteRange undo = new UndoDeleteRange(_trackInfo);
                                // delete requested photos
                                for (int i=0; i<numToDelete; i++)
                                {
                                // delete requested photos
                                for (int i=0; i<numToDelete; i++)
                                {
@@ -476,6 +483,9 @@ public class App
                                if (_trackInfo.deleteRange())
                                {
                                        _undoStack.push(undo);
                                if (_trackInfo.deleteRange())
                                {
                                        _undoStack.push(undo);
+                                       // Confirm
+                                       UpdateMessageBroker.informSubscribers("" + numToDelete + " "
+                                               + I18nManager.getText("confirm.deletepoint.multi"));
                                }
                        }
                }
                                }
                        }
                }
@@ -499,17 +509,18 @@ public class App
                                String message = null;
                                if (numDeleted == 1)
                                {
                                String message = null;
                                if (numDeleted == 1)
                                {
-                                       message = "1 " + I18nManager.getText("dialog.deleteduplicates.single.text");
+                                       message = "1 " + I18nManager.getText("confirm.deleteduplicates.single");
                                }
                                else
                                {
                                }
                                else
                                {
-                                       message = "" + numDeleted + " " + I18nManager.getText("dialog.deleteduplicates.multi.text");
+                                       message = "" + numDeleted + " " + I18nManager.getText("confirm.deleteduplicates.multi");
                                }
                                }
-                               JOptionPane.showMessageDialog(_frame, message,
-                                       I18nManager.getText("dialog.deleteduplicates.title"), JOptionPane.INFORMATION_MESSAGE);
+                               // Pass message to broker
+                               UpdateMessageBroker.informSubscribers(message);
                        }
                        else
                        {
                        }
                        else
                        {
+                               // No duplicates found to delete
                                JOptionPane.showMessageDialog(_frame,
                                        I18nManager.getText("dialog.deleteduplicates.nonefound"),
                                        I18nManager.getText("dialog.deleteduplicates.title"), JOptionPane.INFORMATION_MESSAGE);
                                JOptionPane.showMessageDialog(_frame,
                                        I18nManager.getText("dialog.deleteduplicates.nonefound"),
                                        I18nManager.getText("dialog.deleteduplicates.title"), JOptionPane.INFORMATION_MESSAGE);
@@ -538,11 +549,8 @@ public class App
                {
                        undo.setNumPointsDeleted(numPointsDeleted);
                        _undoStack.add(undo);
                {
                        undo.setNumPointsDeleted(numPointsDeleted);
                        _undoStack.add(undo);
-                       JOptionPane.showMessageDialog(_frame,
-                               I18nManager.getText("dialog.compresstrack.text") + " - "
-                                + numPointsDeleted + " "
-                                + (numPointsDeleted==1?I18nManager.getText("dialog.compresstrack.single.text"):I18nManager.getText("dialog.compresstrack.multi.text")),
-                               I18nManager.getText("dialog.compresstrack.title"), JOptionPane.INFORMATION_MESSAGE);
+                       UpdateMessageBroker.informSubscribers("" + numPointsDeleted + " "
+                                + (numPointsDeleted==1?I18nManager.getText("confirm.deletepoint.single"):I18nManager.getText("confirm.deletepoint.multi")));
                }
                else
                {
                }
                else
                {
@@ -553,7 +561,7 @@ public class App
 
 
        /**
 
 
        /**
-        * Reverse a section of the track
+        * Reverse the currently selected section of the track
         */
        public void reverseRange()
        {
         */
        public void reverseRange()
        {
@@ -567,11 +575,35 @@ public class App
                                 I18nManager.getText("dialog.confirmreversetrack.title"),
                                 JOptionPane.YES_NO_OPTION) == JOptionPane.YES_OPTION && (_reversePointsConfirmed = true)))
                {
                                 I18nManager.getText("dialog.confirmreversetrack.title"),
                                 JOptionPane.YES_NO_OPTION) == JOptionPane.YES_OPTION && (_reversePointsConfirmed = true)))
                {
-                       UndoReverseSection undo = new UndoReverseSection(selStart, selEnd);
+                       UndoReverseSection undo = new UndoReverseSection(_track, selStart, selEnd);
                        // call track to reverse range
                        if (_track.reverseRange(selStart, selEnd))
                        {
                                _undoStack.add(undo);
                        // call track to reverse range
                        if (_track.reverseRange(selStart, selEnd))
                        {
                                _undoStack.add(undo);
+                               // Confirm
+                               UpdateMessageBroker.informSubscribers(I18nManager.getText("confirm.reverserange"));
+                       }
+               }
+       }
+
+       /**
+        * Merge the track segments within the current selection
+        */
+       public void mergeTrackSegments()
+       {
+               if (_trackInfo.getSelection().hasRangeSelected())
+               {
+                       // Maybe could check segment start flags to see if it's worth merging
+                       // If first track point is already start and no other seg starts then do nothing
+
+                       int selStart = _trackInfo.getSelection().getStart();
+                       int selEnd = _trackInfo.getSelection().getEnd();
+                       // Make undo object
+                       UndoMergeTrackSegments undo = new UndoMergeTrackSegments(_track, selStart, selEnd);
+                       // Call track to merge segments
+                       if (_track.mergeTrackSegments(selStart, selEnd)) {
+                               _undoStack.add(undo);
+                               UpdateMessageBroker.informSubscribers(I18nManager.getText("confirm.mergetracksegments"));
                        }
                }
        }
                        }
                }
        }
@@ -686,7 +718,7 @@ public class App
        public void informDataLoaded(Field[] inFieldArray, Object[][] inDataArray, int inAltFormat, String inFilename)
        {
                // Check whether loaded array can be properly parsed into a Track
        public void informDataLoaded(Field[] inFieldArray, Object[][] inDataArray, int inAltFormat, String inFilename)
        {
                // Check whether loaded array can be properly parsed into a Track
-               Track loadedTrack = new Track(_broker);
+               Track loadedTrack = new Track();
                loadedTrack.load(inFieldArray, inDataArray, inAltFormat);
                if (loadedTrack.getNumPoints() <= 0)
                {
                loadedTrack.load(inFieldArray, inDataArray, inAltFormat);
                if (loadedTrack.getNumPoints() <= 0)
                {
@@ -747,7 +779,9 @@ public class App
                        _trackInfo.loadTrack(inFieldArray, inDataArray, inAltFormat);
                        _trackInfo.getFileInfo().setFile(inFilename);
                }
                        _trackInfo.loadTrack(inFieldArray, inDataArray, inAltFormat);
                        _trackInfo.getFileInfo().setFile(inFilename);
                }
-               _broker.informSubscribers();
+               UpdateMessageBroker.informSubscribers();
+               // Update status bar
+               UpdateMessageBroker.informSubscribers(I18nManager.getText("confirm.loadfile") + " '" + inFilename + "'");
                // update menu
                _menuManager.informFileLoaded();
        }
                // update menu
                _menuManager.informFileLoaded();
        }
@@ -771,18 +805,14 @@ public class App
                        }
                        if (numPhotosAdded == 1)
                        {
                        }
                        if (numPhotosAdded == 1)
                        {
-                               JOptionPane.showMessageDialog(_frame,
-                                       "" + numPhotosAdded + " " + I18nManager.getText("dialog.jpegload.photoadded"),
-                                       I18nManager.getText("dialog.jpegload.title"), JOptionPane.INFORMATION_MESSAGE);
+                               UpdateMessageBroker.informSubscribers("" + numPhotosAdded + " " + I18nManager.getText("confirm.jpegload.single"));
                        }
                        else
                        {
                        }
                        else
                        {
-                               JOptionPane.showMessageDialog(_frame,
-                                       "" + numPhotosAdded + " " + I18nManager.getText("dialog.jpegload.photosadded"),
-                                       I18nManager.getText("dialog.jpegload.title"), JOptionPane.INFORMATION_MESSAGE);
+                               UpdateMessageBroker.informSubscribers("" + numPhotosAdded + " " + I18nManager.getText("confirm.jpegload.multi"));
                        }
                        // TODO: Improve message when photo(s) fail to load (eg already added)
                        }
                        // TODO: Improve message when photo(s) fail to load (eg already added)
-                       _broker.informSubscribers();
+                       UpdateMessageBroker.informSubscribers();
                        // update menu
                        _menuManager.informFileLoaded();
                }
                        // update menu
                        _menuManager.informFileLoaded();
                }
@@ -802,7 +832,8 @@ public class App
                        _undoStack.add(new UndoConnectPhoto(point, photo.getFile().getName()));
                        photo.setDataPoint(point);
                        point.setPhoto(photo);
                        _undoStack.add(new UndoConnectPhoto(point, photo.getFile().getName()));
                        photo.setDataPoint(point);
                        point.setPhoto(photo);
-                       _broker.informSubscribers(DataSubscriber.SELECTION_CHANGED);
+                       UpdateMessageBroker.informSubscribers(DataSubscriber.SELECTION_CHANGED);
+                       UpdateMessageBroker.informSubscribers(I18nManager.getText("confirm.photo.connect"));
                }
        }
 
                }
        }
 
@@ -820,7 +851,8 @@ public class App
                        // disconnect
                        photo.setDataPoint(null);
                        point.setPhoto(null);
                        // disconnect
                        photo.setDataPoint(null);
                        point.setPhoto(null);
-                       _broker.informSubscribers(DataSubscriber.SELECTION_CHANGED);
+                       UpdateMessageBroker.informSubscribers(DataSubscriber.SELECTION_CHANGED);
+                       UpdateMessageBroker.informSubscribers(I18nManager.getText("confirm.photo.disconnect"));
                }
        }
 
                }
        }
 
@@ -875,7 +907,7 @@ public class App
        public void beginCorrelatePhotos()
        {
                PhotoCorrelator correlator = new PhotoCorrelator(this, _frame);
        public void beginCorrelatePhotos()
        {
                PhotoCorrelator correlator = new PhotoCorrelator(this, _frame);
-               // TODO: Do we need to keep a reference to this object to reuse it later?
+               // TODO: Do we need to keep a reference to this Photo Correlator object to reuse it later?
                correlator.begin();
        }
 
                correlator.begin();
        }
 
@@ -971,10 +1003,8 @@ public class App
                        undo.setNumPhotosCorrelated(numPhotos);
                        _undoStack.add(undo);
                        // confirm correlation
                        undo.setNumPhotosCorrelated(numPhotos);
                        _undoStack.add(undo);
                        // confirm correlation
-                       JOptionPane.showMessageDialog(_frame, "" + numPhotos + " "
-                                + (numPhotos==1?I18nManager.getText("dialog.correlate.confirmsingle.text"):I18nManager.getText("dialog.correlate.confirmmultiple.text")),
-                               I18nManager.getText("dialog.correlate.title"),
-                               JOptionPane.INFORMATION_MESSAGE);
+                       UpdateMessageBroker.informSubscribers("" + numPhotos + " "
+                                + (numPhotos==1?I18nManager.getText("confirm.correlate.single"):I18nManager.getText("confirm.correlate.multi")));
                        // observers already informed by track update
                }
        }
                        // observers already informed by track update
                }
        }
@@ -1006,6 +1036,7 @@ public class App
        {
                if (_undoStack.isEmpty())
                {
        {
                if (_undoStack.isEmpty())
                {
+                       // Nothing to undo
                        JOptionPane.showMessageDialog(_frame, I18nManager.getText("dialog.undo.none.text"),
                                I18nManager.getText("dialog.undo.none.title"), JOptionPane.INFORMATION_MESSAGE);
                }
                        JOptionPane.showMessageDialog(_frame, I18nManager.getText("dialog.undo.none.text"),
                                I18nManager.getText("dialog.undo.none.title"), JOptionPane.INFORMATION_MESSAGE);
                }
@@ -1036,7 +1067,7 @@ public class App
                        _undoStack.clear();
                        _lastSavePosition = 0;
                        if (unsaved) _lastSavePosition = -1;
                        _undoStack.clear();
                        _lastSavePosition = 0;
                        if (unsaved) _lastSavePosition = -1;
-                       _broker.informSubscribers();
+                       UpdateMessageBroker.informSubscribers();
                }
        }
 
                }
        }
 
@@ -1053,10 +1084,9 @@ public class App
                        {
                                ((UndoOperation) _undoStack.pop()).performUndo(_trackInfo);
                        }
                        {
                                ((UndoOperation) _undoStack.pop()).performUndo(_trackInfo);
                        }
-                       JOptionPane.showMessageDialog(_frame, "" + inNumUndos + " "
-                                + (inNumUndos==1?I18nManager.getText("dialog.confirmundo.single.text"):I18nManager.getText("dialog.confirmundo.multiple.text")),
-                               I18nManager.getText("dialog.confirmundo.title"),
-                               JOptionPane.INFORMATION_MESSAGE);
+                       String message = "" + inNumUndos + " "
+                                + (inNumUndos==1?I18nManager.getText("confirm.undo.single"):I18nManager.getText("confirm.undo.multi"));
+                       UpdateMessageBroker.informSubscribers(message);
                }
                catch (UndoException ue)
                {
                }
                catch (UndoException ue)
                {
@@ -1065,7 +1095,7 @@ public class App
                                I18nManager.getText("error.undofailed.title"),
                                JOptionPane.ERROR_MESSAGE);
                        _undoStack.clear();
                                I18nManager.getText("error.undofailed.title"),
                                JOptionPane.ERROR_MESSAGE);
                        _undoStack.clear();
-                       _broker.informSubscribers();
+                       UpdateMessageBroker.informSubscribers();
                }
                catch (EmptyStackException empty) {}
        }
                }
                catch (EmptyStackException empty) {}
        }
@@ -1100,4 +1130,23 @@ public class App
                        I18nManager.getText("menu.help"),
                        JOptionPane.INFORMATION_MESSAGE);
        }
                        I18nManager.getText("menu.help"),
                        JOptionPane.INFORMATION_MESSAGE);
        }
+
+       /**
+        * Show an OSM map window
+        */
+       public void showOsmMap()
+       {
+               MapWindow map = new MapWindow(_track);
+               map.pack();
+               map.show();
+       }
+
+       /**
+        * Show a map url in an external browser
+        */
+       public void showExternalMap(int inSourceIndex)
+       {
+               if (_browserLauncher == null) {_browserLauncher = new BrowserLauncher();}
+               _browserLauncher.launchBrowser(UrlGenerator.generateUrl(inSourceIndex, _trackInfo));
+       }
 }
 }
index d3fc123174635183d0f9008f7c1d86be30ce8c5f..ceaed70a5a9903f333edb96573e7f7227f6e3066 100644 (file)
@@ -20,4 +20,9 @@ public interface DataSubscriber
         */
        public void dataUpdated(byte inUpdateType);
 
         */
        public void dataUpdated(byte inUpdateType);
 
+       /**
+        * Inform clients that an action has been completed
+        * @param inMessage message describing action
+        */
+       public void actionCompleted(String inMessage);
 }
 }
index cd65fffd519d68a95a21b0623dac2146d3e0048b..36c496a6e24229603769d5ff8405cc397ff645f8 100644 (file)
@@ -15,16 +15,7 @@ public abstract class ExternalTools
         */
        public static boolean isPovrayInstalled()
        {
         */
        public static boolean isPovrayInstalled()
        {
-               try
-               {
-                       Runtime.getRuntime().exec("povray");
-                       return true;
-               }
-               catch (IOException ioe)
-               {
-                       // exception thrown, povray not found
-                       return false;
-               }
+               return check("povray");
        }
 
 
        }
 
 
@@ -33,15 +24,33 @@ public abstract class ExternalTools
         * @return true if found, false otherwise
         */
        public static boolean isExiftoolInstalled()
         * @return true if found, false otherwise
         */
        public static boolean isExiftoolInstalled()
+       {
+               return check("exiftool -v");
+       }
+
+       /**
+        * Attempt to call gpsbabel to see if it's installed / available in path
+        * @return true if found, false otherwise
+        */
+       public static boolean isGpsbabelInstalled()
+       {
+               return check("gpsbabel -V");
+       }
+
+       /**
+        * Attempt to call the specified command
+        * @return true if found, false otherwise
+        */
+       private static boolean check(String inCommand)
        {
                try
                {
        {
                try
                {
-                       Runtime.getRuntime().exec("exiftool -v");
+                       Runtime.getRuntime().exec(inCommand);
                        return true;
                }
                catch (IOException ioe)
                {
                        return true;
                }
                catch (IOException ioe)
                {
-                       // exception thrown, exiftool not found
+                       // exception thrown, command not found
                        return false;
                }
        }
                        return false;
                }
        }
index e19cb2108b49161098484e856519011f64728a94..7208eb7e83815b2de02341954cb9df3cdfa5441d 100644 (file)
@@ -1,10 +1,11 @@
 package tim.prune;
 
 package tim.prune;
 
-import java.awt.BorderLayout;
 import java.awt.event.WindowAdapter;
 import java.awt.event.WindowAdapter;
+import java.awt.BorderLayout;
 import java.awt.event.WindowEvent;
 import java.util.Locale;
 
 import java.awt.event.WindowEvent;
 import java.util.Locale;
 
+import javax.swing.ImageIcon;
 import javax.swing.JFrame;
 import javax.swing.JSplitPane;
 import javax.swing.JToolBar;
 import javax.swing.JFrame;
 import javax.swing.JSplitPane;
 import javax.swing.JToolBar;
@@ -15,6 +16,7 @@ import tim.prune.gui.MapChart;
 import tim.prune.gui.MenuManager;
 import tim.prune.gui.ProfileChart;
 import tim.prune.gui.SelectorDisplay;
 import tim.prune.gui.MenuManager;
 import tim.prune.gui.ProfileChart;
 import tim.prune.gui.SelectorDisplay;
+import tim.prune.gui.StatusBar;
 
 /**
  * Tool to visualize, edit and prune GPS data
 
 /**
  * Tool to visualize, edit and prune GPS data
@@ -22,9 +24,9 @@ import tim.prune.gui.SelectorDisplay;
  */
 public class GpsPruner
 {
  */
 public class GpsPruner
 {
-       // Patch to version 4
-       public static final String VERSION_NUMBER = "4.1";
-       public static final String BUILD_NUMBER = "091";
+       // Final build of version 5
+       public static final String VERSION_NUMBER = "5";
+       public static final String BUILD_NUMBER = "100";
        private static App APP = null;
 
 
        private static App APP = null;
 
 
@@ -83,27 +85,30 @@ public class GpsPruner
        private static void launch()
        {
                JFrame frame = new JFrame("Prune");
        private static void launch()
        {
                JFrame frame = new JFrame("Prune");
-               UpdateMessageBroker broker = new UpdateMessageBroker();
-               APP = new App(frame, broker);
+               APP = new App(frame);
 
                // make menu
                MenuManager menuManager = new MenuManager(frame, APP, APP.getTrackInfo());
                frame.setJMenuBar(menuManager.createMenuBar());
                APP.setMenuManager(menuManager);
 
                // make menu
                MenuManager menuManager = new MenuManager(frame, APP, APP.getTrackInfo());
                frame.setJMenuBar(menuManager.createMenuBar());
                APP.setMenuManager(menuManager);
-               broker.addSubscriber(menuManager);
+               UpdateMessageBroker.addSubscriber(menuManager);
                // Make toolbar for buttons
                JToolBar toolbar = menuManager.createToolBar();
 
                // Make toolbar for buttons
                JToolBar toolbar = menuManager.createToolBar();
 
-               // Make three GUI components and add as listeners
+               // Make main GUI components and add as listeners
                SelectorDisplay leftPanel = new SelectorDisplay(APP.getTrackInfo());
                SelectorDisplay leftPanel = new SelectorDisplay(APP.getTrackInfo());
-               broker.addSubscriber(leftPanel);
+               UpdateMessageBroker.addSubscriber(leftPanel);
                DetailsDisplay rightPanel = new DetailsDisplay(APP.getTrackInfo());
                DetailsDisplay rightPanel = new DetailsDisplay(APP.getTrackInfo());
-               broker.addSubscriber(rightPanel);
+               UpdateMessageBroker.addSubscriber(rightPanel);
                MapChart mapDisp = new MapChart(APP, APP.getTrackInfo());
                MapChart mapDisp = new MapChart(APP, APP.getTrackInfo());
-               broker.addSubscriber(mapDisp);
+               UpdateMessageBroker.addSubscriber(mapDisp);
                ProfileChart profileDisp = new ProfileChart(APP.getTrackInfo());
                ProfileChart profileDisp = new ProfileChart(APP.getTrackInfo());
-               broker.addSubscriber(profileDisp);
+               UpdateMessageBroker.addSubscriber(profileDisp);
+               StatusBar statusBar = new StatusBar();
+               UpdateMessageBroker.addSubscriber(statusBar);
+               UpdateMessageBroker.informSubscribers("Prune v" + VERSION_NUMBER);
 
 
+               // Arrange in the frame using split panes
                JSplitPane midPane = new JSplitPane(JSplitPane.VERTICAL_SPLIT, mapDisp, profileDisp);
                midPane.setResizeWeight(1.0); // allocate as much space as poss to map
                JSplitPane triplePane = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, midPane, rightPanel);
                JSplitPane midPane = new JSplitPane(JSplitPane.VERTICAL_SPLIT, mapDisp, profileDisp);
                midPane.setResizeWeight(1.0); // allocate as much space as poss to map
                JSplitPane triplePane = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, midPane, rightPanel);
@@ -113,6 +118,8 @@ public class GpsPruner
                frame.getContentPane().add(toolbar, BorderLayout.NORTH);
                frame.getContentPane().add(new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, leftPanel,
                        triplePane), BorderLayout.CENTER);
                frame.getContentPane().add(toolbar, BorderLayout.NORTH);
                frame.getContentPane().add(new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, leftPanel,
                        triplePane), BorderLayout.CENTER);
+               frame.getContentPane().add(statusBar, BorderLayout.SOUTH);
+
                // add closing listener
                frame.addWindowListener(new WindowAdapter() {
                        public void windowClosing(WindowEvent e) {
                // add closing listener
                frame.addWindowListener(new WindowAdapter() {
                        public void windowClosing(WindowEvent e) {
@@ -122,9 +129,17 @@ public class GpsPruner
                // Avoid automatically shutting down if window closed
                frame.setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE);
 
                // Avoid automatically shutting down if window closed
                frame.setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE);
 
+               // set icon
+               try {
+                       frame.setIconImage(new ImageIcon(GpsPruner.class.getResource("gui/images/window_icon.png")).getImage());
+               }
+               catch (Exception e) {} // ignore
+
                // finish off and display frame
                frame.pack();
                frame.setSize(650, 450);
                frame.show();
                // finish off and display frame
                frame.pack();
                frame.setSize(650, 450);
                frame.show();
+               // Set position of map/profile splitter
+               midPane.setDividerLocation(0.75);
        }
 }
        }
 }
index cac2a79dddc08e5a5d68ccc6f3dcca934c73a930..0b21f52d0a381de1c6a293717393792fadc7ea62 100644 (file)
@@ -4,28 +4,18 @@ package tim.prune;
  * Class responsible for distributing update information
  * to all registered listeners
  */
  * Class responsible for distributing update information
  * to all registered listeners
  */
-public class UpdateMessageBroker
+public abstract class UpdateMessageBroker
 {
 {
-       private DataSubscriber[] _subscribers;
-       private int _subscriberNum = 0;
-       private static final int MAXIMUM_NUMBER_SUBSCRIBERS = 5;
-
-
-       /**
-        * Constructor
-        * @param inTrack Track object
-        */
-       public UpdateMessageBroker()
-       {
-               _subscribers = new DataSubscriber[MAXIMUM_NUMBER_SUBSCRIBERS];
-       }
+       private static final int MAXIMUM_NUMBER_SUBSCRIBERS = 6;
+       private static DataSubscriber[] _subscribers = new DataSubscriber[MAXIMUM_NUMBER_SUBSCRIBERS];
+       private static int _subscriberNum = 0;
 
 
        /**
         * Add a data subscriber to the list
         * @param inSub DataSubscriber to add
         */
 
 
        /**
         * Add a data subscriber to the list
         * @param inSub DataSubscriber to add
         */
-       public void addSubscriber(DataSubscriber inSub)
+       public static void addSubscriber(DataSubscriber inSub)
        {
                _subscribers[_subscriberNum] = inSub;
                _subscriberNum++;
        {
                _subscribers[_subscriberNum] = inSub;
                _subscriberNum++;
@@ -36,7 +26,7 @@ public class UpdateMessageBroker
         * Send a message to all subscribers that
         * the data has been updated
         */
         * Send a message to all subscribers that
         * the data has been updated
         */
-       public void informSubscribers()
+       public static void informSubscribers()
        {
                informSubscribers(DataSubscriber.ALL);
        }
        {
                informSubscribers(DataSubscriber.ALL);
        }
@@ -46,7 +36,7 @@ public class UpdateMessageBroker
         * Send message to all subscribers
         * @param inChange Change that occurred
         */
         * Send message to all subscribers
         * @param inChange Change that occurred
         */
-       public void informSubscribers(byte inChange)
+       public static void informSubscribers(byte inChange)
        {
                for (int i=0; i<_subscribers.length; i++)
                {
        {
                for (int i=0; i<_subscribers.length; i++)
                {
@@ -56,4 +46,19 @@ public class UpdateMessageBroker
                        }
                }
        }
                        }
                }
        }
+
+       /**
+        * Send message to all subscribers
+        * @param inMessage message to display informing of action completed
+        */
+       public static void informSubscribers(String inMessage)
+       {
+               for (int i=0; i<_subscribers.length; i++)
+               {
+                       if (_subscribers[i] != null)
+                       {
+                               _subscribers[i].actionCompleted(inMessage);
+                       }
+               }
+       }
 }
 }
diff --git a/tim/prune/browser/BrowserLauncher.java b/tim/prune/browser/BrowserLauncher.java
new file mode 100644 (file)
index 0000000..fe4c79a
--- /dev/null
@@ -0,0 +1,95 @@
+package tim.prune.browser;
+
+import javax.swing.JOptionPane;
+
+
+/**
+ * Class to launch a browser window to show an external map
+ */
+public class BrowserLauncher
+{
+       private String[] _browserCommand = null;
+       private boolean _urlNeedsQuotes = false;
+
+       /**
+        * Constructor to set up browser
+        */
+       public BrowserLauncher()
+       {
+               // First check if "which" command is available
+               if (commandExists("which"))
+               {
+                       // which exists, so try browsers in turn
+                       String[] browsersToTry = {"firefox", "iceweasel", "konqueror", "opera", "epiphany", "mozilla", "safari", "lynx"};
+                       String browserFound = null;
+                       for (int i=0; i<browsersToTry.length && browserFound == null; i++)
+                       {
+                               if (commandExists(browsersToTry[i]))
+                                       browserFound = browsersToTry[i];
+                       }
+                       if (browserFound != null) {
+                               _browserCommand = new String[] {browserFound, null};
+                       }
+               }
+               else
+               {
+                       // no which command, so check if os name looks like a mac
+                       boolean isMacOsx = System.getProperty("os.name").toLowerCase().indexOf("mac os") >= 0;
+                       if (isMacOsx) {
+                               // for Mac Osx just use "open" command
+                               _browserCommand = new String[] {"open", null};
+                       }
+                       else {
+                               // assume it's not linux or mac, so try windows method using "start" command
+                               _browserCommand = new String[] {"cmd.exe", "/C", "start", "\"\"", null};
+                               _urlNeedsQuotes = true;
+                       }
+               }
+       }
+
+       /**
+        * Check if the specified command exists on the system
+        * @param inCommand command to check
+        * @return true if the command exists
+        */
+       private static boolean commandExists(String inCommand)
+       {
+               try
+               {
+                       String[] commands = {"which", inCommand};
+                       if (Runtime.getRuntime().exec(commands).waitFor() == 0)
+                       {
+                               return true;
+                       }
+               }
+               catch (Exception e) {} // failed
+               return false;
+       }
+
+       /**
+        * Launch a browser window to show the given url
+        * @param inUrl url to show
+        */
+       public void launchBrowser(String inUrl)
+       {
+               if (_browserCommand == null) {
+                       JOptionPane.showMessageDialog(null, "Cannot show url: " + inUrl);
+               }
+               else
+               {
+                       try
+                       {
+                               // enclose url in quotes if necessary
+                               String url = inUrl;
+                               if (_urlNeedsQuotes) {url = "\"" + url + "\"";}
+                               // Fill in url in last element of coommand array
+                               _browserCommand[_browserCommand.length - 1] = url;
+                               // execute command to launch browser
+                               Runtime.getRuntime().exec(_browserCommand);
+                       }
+                       catch (Exception e) {
+                               JOptionPane.showMessageDialog(null, "Failed to show url: " + inUrl);
+                       }
+               }
+       }
+}
diff --git a/tim/prune/browser/UrlGenerator.java b/tim/prune/browser/UrlGenerator.java
new file mode 100644 (file)
index 0000000..07b8ff1
--- /dev/null
@@ -0,0 +1,118 @@
+package tim.prune.browser;
+
+import java.text.DecimalFormat;
+
+import tim.prune.I18nManager;
+import tim.prune.data.DataPoint;
+import tim.prune.data.DoubleRange;
+import tim.prune.data.TrackInfo;
+
+/**
+ * Class to manage the generation of map urls
+ * for display in an external browser
+ */
+public abstract class UrlGenerator
+{
+       /** Number formatter for five dp */
+       public static final DecimalFormat FIVE_DP = new DecimalFormat("0.00000");
+
+       /** Constant for Google Maps */
+       public static final int MAP_SOURCE_GOOGLE = 0;
+       /** Constant for Open Street Maps */
+       public static final int MAP_SOURCE_OSM    = 1;
+
+       // TODO: Add other map sources, eg Yahoo, MSN, search.ch ?
+
+       /**
+        * Generate a URL for the given source and track info
+        * @param inSource source to use, either google or openstreetmap
+        * @param inTrackInfo track info
+        * @return url for map
+        */
+       public static String generateUrl(int inSource, TrackInfo inTrackInfo)
+       {
+               if (inSource == MAP_SOURCE_GOOGLE) {
+                       return generateGoogleUrl(inTrackInfo);
+               }
+               return generateOpenStreetMapUrl(inTrackInfo);
+       }
+
+       /**
+        * Generate a url for Google maps
+        * @param inTrackInfo track information
+        * @return URL
+        */
+       private static String generateGoogleUrl(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());
+               double latSpan = getSpan(inTrackInfo.getTrack().getLatRange());
+               double lonSpan = getSpan(inTrackInfo.getTrack().getLonRange());
+               // Build basic url with centre position and span
+               String url = "http://" + I18nManager.getText("url.googlemaps")
+                       + "/?ll=" + FIVE_DP.format(medianLat) + "," + FIVE_DP.format(medianLon)
+                       + "&spn=" + FIVE_DP.format(latSpan) + "," + FIVE_DP.format(lonSpan);
+               DataPoint currPoint = inTrackInfo.getCurrentPoint();
+               // Add selected point, if any
+               if (currPoint != null) {
+                       url = url + "&q=" + FIVE_DP.format(currPoint.getLatitude().getDouble()) + ","
+                               + FIVE_DP.format(currPoint.getLongitude().getDouble());
+                       if (currPoint.getWaypointName() != null) {
+                               url = url + "(" + currPoint.getWaypointName() + ")";
+                       }
+               }
+               return url;
+       }
+
+       /**
+        * Generate a url for Open Street Map
+        * @param inTrackInfo track information
+        * @return URL
+        */
+       private static String generateOpenStreetMapUrl(TrackInfo inTrackInfo)
+       {
+               // Check if any data to display
+               if (inTrackInfo == null || inTrackInfo.getTrack() == null || inTrackInfo.getTrack().getNumPoints() < 1)
+               {
+                       return null;
+               }
+               DoubleRange latRange = inTrackInfo.getTrack().getLatRange();
+               DoubleRange lonRange = inTrackInfo.getTrack().getLonRange();
+               // Build basic url using min and max lat and long
+               String url = "http://openstreetmap.org/?minlat=" + FIVE_DP.format(latRange.getMinimum())
+                       + "&maxlat=" + FIVE_DP.format(latRange.getMaximum())
+                       + "&minlon=" + FIVE_DP.format(lonRange.getMinimum()) + "&maxlon=" + FIVE_DP.format(lonRange.getMaximum());
+               DataPoint currPoint = inTrackInfo.getCurrentPoint();
+               // Add selected point, if any (no way to add point name?)
+               if (currPoint != null) {
+                       url = url + "&mlat=" + FIVE_DP.format(currPoint.getLatitude().getDouble())
+                               + "&mlon=" + FIVE_DP.format(currPoint.getLongitude().getDouble());
+               }
+               return url;
+       }
+
+       /**
+        * Get the median value from the given lat/long range
+        * @param inRange range of values
+        * @return median value
+        */
+       private static double getMedianValue(DoubleRange inRange)
+       {
+               return (inRange.getMaximum() + inRange.getMinimum()) / 2.0;
+       }
+
+       /**
+        * Get the span of the given lat/long range
+        * @param inRange range of values
+        * @return span
+        */
+       private static double getSpan(DoubleRange inRange)
+       {
+               return inRange.getMaximum() - inRange.getMinimum();
+       }
+}
index 22237725c8daef673d99a7446f137054b65e559b..f2c1fc8961ecdc412a5a91495129911bd6f5ea4d 100644 (file)
@@ -427,10 +427,9 @@ public class PhotoCorrelator
                                long numSecs = pair.getMinSeconds();
                                correlatePhoto = (numSecs <= timeLimit.getTotalSeconds());
                        }
                                long numSecs = pair.getMinSeconds();
                                correlatePhoto = (numSecs <= timeLimit.getTotalSeconds());
                        }
-                       if (angDistLimit > 0.0 && correlatePhoto) {
+                       if (angDistLimit > 0.0 && correlatePhoto)
+                       {
                                final double angDistPair = DataPoint.calculateRadiansBetween(pair.getPointBefore(), pair.getPointAfter());
                                final double angDistPair = DataPoint.calculateRadiansBetween(pair.getPointBefore(), pair.getPointAfter());
-                               //System.out.println("(dist between pair is " + angDistPair + ") which means "
-                               //      + Distance.convertRadiansToDistance(angDistPair, Distance.UNITS_METRES) + "m");
                                double frac = pair.getFraction();
                                if (frac > 0.5) {frac = 1 - frac;}
                                final double angDistPhoto = angDistPair * frac;
                                double frac = pair.getFraction();
                                if (frac > 0.5) {frac = 1 - frac;}
                                final double angDistPhoto = angDistPair * frac;
@@ -613,7 +612,6 @@ public class PhotoCorrelator
                {
                        PhotoSelectionTableRow row = inModel.getRow(i);
                        set.add(new TimeIndexPair(row.getTimeDiff().getTotalSeconds(), i));
                {
                        PhotoSelectionTableRow row = inModel.getRow(i);
                        set.add(new TimeIndexPair(row.getTimeDiff().getTotalSeconds(), i));
-                       //System.out.println("pair " + i + " has time " + row.getTimeDiff().getTotalSeconds());
                }
                // pull out middle entry and return index
                TimeIndexPair pair = null;
                }
                // pull out middle entry and return index
                TimeIndexPair pair = null;
@@ -621,7 +619,6 @@ public class PhotoCorrelator
                for (i=0; i<(numRows+1)/2; i++)
                {
                        pair = (TimeIndexPair) iterator.next();
                for (i=0; i<(numRows+1)/2; i++)
                {
                        pair = (TimeIndexPair) iterator.next();
-                       //System.out.println("After sorting, pair " + i + " has index " + pair.getIndex());
                }
                return pair.getIndex();
        }
                }
                return pair.getIndex();
        }
@@ -632,8 +629,7 @@ public class PhotoCorrelator
         */
        public void disableOkButton()
        {
         */
        public void disableOkButton()
        {
-               if (_okButton != null)
-               {
+               if (_okButton != null) {
                        _okButton.setEnabled(false);
                }
        }
                        _okButton.setEnabled(false);
                }
        }
index 5e864ce10e821068310932621f24c011be9e3097..38ec19a4549e38dbe0d8aba6709d43546e8faf3a 100644 (file)
@@ -17,7 +17,7 @@ public class DataPoint
        private Timestamp _timestamp = null;
        private Photo _photo = null;
        private String _waypointName = null;
        private Timestamp _timestamp = null;
        private Photo _photo = null;
        private String _waypointName = null;
-       // private boolean _startOfSegment = false;
+       private boolean _startOfSegment = false;
 
 
        /**
 
 
        /**
@@ -48,7 +48,9 @@ public class DataPoint
                _altitude = new Altitude(getFieldValue(Field.ALTITUDE), inAltFormat);
                _timestamp = new Timestamp(getFieldValue(Field.TIMESTAMP));
                _waypointName = getFieldValue(Field.WAYPT_NAME);
                _altitude = new Altitude(getFieldValue(Field.ALTITUDE), inAltFormat);
                _timestamp = new Timestamp(getFieldValue(Field.TIMESTAMP));
                _waypointName = getFieldValue(Field.WAYPT_NAME);
-               // TODO: Parse segment start field (format?)
+               String segmentStr = getFieldValue(Field.NEW_SEGMENT);
+               if (segmentStr != null) {segmentStr = segmentStr.trim();}
+               _startOfSegment = (segmentStr != null && (segmentStr.equals("1") || segmentStr.toUpperCase().equals("Y")));
        }
 
 
        }
 
 
@@ -137,6 +139,11 @@ public class DataPoint
                }
        }
 
                }
        }
 
+       /** @param inFlag true for start of track segment */
+       public void setSegmentStart(boolean inFlag)
+       {
+               setFieldValue(Field.NEW_SEGMENT, inFlag?"1":null);
+       }
 
        /** @return latitude */
        public Coordinate getLatitude()
 
        /** @return latitude */
        public Coordinate getLatitude()
@@ -174,6 +181,12 @@ public class DataPoint
                return _waypointName;
        }
 
                return _waypointName;
        }
 
+       /** @return true if start of new track segment */
+       public boolean getSegmentStart()
+       {
+               return _startOfSegment;
+       }
+
        /**
         * @return true if point has a waypoint name
         */
        /**
         * @return true if point has a waypoint name
         */
index f241d4d13470eb1b5e1feb60cdab5d22b686d5b8..e103759fb7eb20d83eb9f7ca6d94cd2ba675d672 100644 (file)
@@ -10,6 +10,20 @@ public class DoubleRange
        private double _min = 0.0, _max = 0.0;
 
 
        private double _min = 0.0, _max = 0.0;
 
 
+       /** Empty constructor, cleared to zeroes */
+       public DoubleRange() {}
+
+       /**
+        * Constructor giving two initial values
+        * @param inValue1 first value
+        * @param inValue2 second value
+        */
+       public DoubleRange(double inValue1, double inValue2)
+       {
+               addValue(inValue1);
+               addValue(inValue2);
+       }
+
        /**
         * Clear for a new calculation
         */
        /**
         * Clear for a new calculation
         */
index b26c11ff7bbca551bbc4f6574dc4123259512fc0..cdbe58ecca33035a7a012d5ee5e3be402e422ccc 100644 (file)
@@ -10,7 +10,6 @@ import tim.prune.UpdateMessageBroker;
 public class Selection
 {
        private Track _track = null;
 public class Selection
 {
        private Track _track = null;
-       private UpdateMessageBroker _broker = null;
        private int _currentPoint = -1;
        private boolean _valid = false;
        private int _startIndex = -1, _endIndex = -1;
        private int _currentPoint = -1;
        private boolean _valid = false;
        private int _startIndex = -1, _endIndex = -1;
@@ -25,12 +24,10 @@ public class Selection
        /**
         * Constructor
         * @param inTrack track object
        /**
         * Constructor
         * @param inTrack track object
-        * @param inBroker broker object
         */
         */
-       public Selection(Track inTrack, UpdateMessageBroker inBroker)
+       public Selection(Track inTrack)
        {
                _track = inTrack;
        {
                _track = inTrack;
-               _broker = inBroker;
        }
 
 
        }
 
 
@@ -304,7 +301,7 @@ public class Selection
                        }
                }
                reset();
                        }
                }
                reset();
-               _broker.informSubscribers();
+               UpdateMessageBroker.informSubscribers();
        }
 
 
        }
 
 
@@ -337,7 +334,7 @@ public class Selection
                        }
                }
                reset();
                        }
                }
                reset();
-               _broker.informSubscribers();
+               UpdateMessageBroker.informSubscribers();
        }
 
 
        }
 
 
@@ -419,7 +416,6 @@ public class Selection
                return _currentPhotoIndex;
        }
 
                return _currentPhotoIndex;
        }
 
-
        /**
         * Check that the selection still makes sense
         * and fire update message to listeners
        /**
         * Check that the selection still makes sense
         * and fire update message to listeners
@@ -450,6 +446,6 @@ public class Selection
                                _currentPoint = _startIndex = _endIndex = -1;
                        }
                }
                                _currentPoint = _startIndex = _endIndex = -1;
                        }
                }
-               _broker.informSubscribers(DataSubscriber.SELECTION_CHANGED);
+               UpdateMessageBroker.informSubscribers(DataSubscriber.SELECTION_CHANGED);
        }
 }
        }
 }
index f6ad709b05e3bde338749607e3526426e85b3a9a..9c65437b60abc86df5bd803c3f045d946e89a2f5 100644 (file)
@@ -13,8 +13,6 @@ import tim.prune.edit.FieldEditList;
  */
 public class Track
 {
  */
 public class Track
 {
-       // Broker object
-       UpdateMessageBroker _broker = null;
        // Data points
        private DataPoint[] _dataPoints = null;
        // Scaled x, y values
        // Data points
        private DataPoint[] _dataPoints = null;
        // Scaled x, y values
@@ -33,11 +31,9 @@ public class Track
 
        /**
         * Constructor for empty track
 
        /**
         * Constructor for empty track
-        * @param inBroker message broker object
         */
         */
-       public Track(UpdateMessageBroker inBroker)
+       public Track()
        {
        {
-               _broker = inBroker;
                // create field list
                _masterFieldList = new FieldList(null);
                // make empty DataPoint array
                // create field list
                _masterFieldList = new FieldList(null);
                // make empty DataPoint array
@@ -79,6 +75,11 @@ public class Track
                        }
                }
                _numPoints = pointIndex;
                        }
                }
                _numPoints = pointIndex;
+               // Set first track point to be start of segment
+               DataPoint firstTrackPoint = getNextTrackPoint(0);
+               if (firstTrackPoint != null) {
+                       firstTrackPoint.setSegmentStart(true);
+               }
                // needs to be scaled
                _scaled = false;
        }
                // needs to be scaled
                _scaled = false;
        }
@@ -89,7 +90,7 @@ public class Track
 
        /**
         * Combine this Track with new data
 
        /**
         * Combine this Track with new data
-        * @param inOtherTrack
+        * @param inOtherTrack other track to combine
         */
        public void combine(Track inOtherTrack)
        {
         */
        public void combine(Track inOtherTrack)
        {
@@ -106,7 +107,7 @@ public class Track
                // needs to be scaled again
                _scaled = false;
                // inform listeners
                // needs to be scaled again
                _scaled = false;
                // inform listeners
-               _broker.informSubscribers();
+               UpdateMessageBroker.informSubscribers();
        }
 
 
        }
 
 
@@ -121,7 +122,7 @@ public class Track
                        _numPoints = inNewSize;
                        // needs to be scaled again
                        _scaled = false;
                        _numPoints = inNewSize;
                        // needs to be scaled again
                        _scaled = false;
-                       _broker.informSubscribers();
+                       UpdateMessageBroker.informSubscribers();
                }
        }
 
                }
        }
 
@@ -146,14 +147,17 @@ public class Track
                if (yscale > wholeScale) wholeScale = yscale;
                double minDist = wholeScale / inResolution;
 
                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++)
                {
                // 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
                        boolean keepPoint = true;
                        // Don't delete waypoints or photo points
-                       if (!_dataPoints[i].isWaypoint() && _dataPoints[i].getPhoto() == null)
+                       if (!point.isWaypoint() && point.getPhoto() == null)
                        {
                                // go through newPointArray to check for range
                                for (int j=0; j<numCopied && keepPoint; j++)
                        {
                                // go through newPointArray to check for range
                                for (int j=0; j<numCopied && keepPoint; j++)
@@ -167,9 +171,20 @@ public class Track
                        }
                        if (keepPoint)
                        {
                        }
                        if (keepPoint)
                        {
-                               newPointArray[numCopied] = _dataPoints[i];
+                               newPointArray[numCopied] = point;
                                pointIndices[numCopied] = i;
                                numCopied++;
                                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;}
                        }
                }
 
                        }
                }
 
@@ -203,7 +218,7 @@ public class Track
                _dataPoints = newPointArray;
                _numPoints = _dataPoints.length;
                _scaled = false;
                _dataPoints = newPointArray;
                _numPoints = _dataPoints.length;
                _scaled = false;
-               _broker.informSubscribers();
+               UpdateMessageBroker.informSubscribers();
                return numDeleted;
        }
 
                return numDeleted;
        }
 
@@ -233,6 +248,16 @@ public class Track
                        // no valid range selected so can't delete
                        return false;
                }
                        // no valid range selected so can't delete
                        return false;
                }
+               // check through range to be deleted, and see if any new segment flags present
+               boolean hasSegmentStart = false;
+               DataPoint nextTrackPoint = getNextTrackPoint(inEnd+1);
+               if (nextTrackPoint != null) {
+                       for (int i=inStart; i<=inEnd && !hasSegmentStart; i++) {
+                               hasSegmentStart |= _dataPoints[i].getSegmentStart();
+                       }
+                       // If segment break found, make sure next trackpoint also has break
+                       if (hasSegmentStart) {nextTrackPoint.setSegmentStart(true);}
+               }
                // valid range, let's delete it
                int numToDelete = inEnd - inStart + 1;
                DataPoint[] newPointArray = new DataPoint[_numPoints - numToDelete];
                // valid range, let's delete it
                int numToDelete = inEnd - inStart + 1;
                DataPoint[] newPointArray = new DataPoint[_numPoints - numToDelete];
@@ -324,13 +349,45 @@ public class Track
                        _dataPoints[inStart + i] = _dataPoints[inEnd - i];
                        _dataPoints[inEnd - i] = p;
                }
                        _dataPoints[inStart + i] = _dataPoints[inEnd - i];
                        _dataPoints[inEnd - i] = p;
                }
+               // adjust segment starts
+               shiftSegmentStarts(inStart, inEnd);
+               // Find first track point and following track point, and set segment starts to true
+               DataPoint firstTrackPoint = getNextTrackPoint(inStart);
+               if (firstTrackPoint != null) {firstTrackPoint.setSegmentStart(true);}
+               DataPoint nextTrackPoint = getNextTrackPoint(inEnd+1);
+               if (nextTrackPoint != null) {nextTrackPoint.setSegmentStart(true);}
                // needs to be scaled again
                _scaled = false;
                // needs to be scaled again
                _scaled = false;
-               _broker.informSubscribers();
+               UpdateMessageBroker.informSubscribers();
                return true;
        }
 
 
                return true;
        }
 
 
+       /**
+        * Merge the track segments within the given range
+        * @param inStart start index
+        * @param inEnd end index
+        * @return true if successful
+        */
+       public boolean mergeTrackSegments(int inStart, int inEnd)
+       {
+               boolean firstTrackPoint = true;
+               // Loop between start and end
+               for (int i=inStart; i<=inEnd; i++) {
+                       DataPoint point = getPoint(i);
+                       // Set all segments to false apart from first track point
+                       if (point != null && !point.isWaypoint()) {
+                               point.setSegmentStart(firstTrackPoint);
+                               firstTrackPoint = false;
+                       }
+               }
+               // Find following track point, if any
+               DataPoint nextPoint = getNextTrackPoint(inEnd+1);
+               if (nextPoint != null) {nextPoint.setSegmentStart(true);}
+               UpdateMessageBroker.informSubscribers();
+               return true;
+       }
+
        /**
         * Collect all waypoints to the start or end of the track
         * @param inAtStart true to collect at start, false for end
        /**
         * Collect all waypoints to the start or end of the track
         * @param inAtStart true to collect at start, false for end
@@ -381,7 +438,7 @@ public class Track
                }
                // needs to be scaled again
                _scaled = false;
                }
                // needs to be scaled again
                _scaled = false;
-               _broker.informSubscribers();
+               UpdateMessageBroker.informSubscribers();
                return true;
        }
 
                return true;
        }
 
@@ -439,7 +496,7 @@ public class Track
                _dataPoints = dataCopy;
                // needs to be scaled again to recalc x, y
                _scaled = false;
                _dataPoints = dataCopy;
                // needs to be scaled again to recalc x, y
                _scaled = false;
-               _broker.informSubscribers();
+               UpdateMessageBroker.informSubscribers();
                return true;
        }
 
                return true;
        }
 
@@ -481,7 +538,7 @@ public class Track
                }
                // needs to be scaled again to recalc x, y
                _scaled = false;
                }
                // needs to be scaled again to recalc x, y
                _scaled = false;
-               _broker.informSubscribers();
+               UpdateMessageBroker.informSubscribers();
        }
 
 
        }
 
 
@@ -760,6 +817,71 @@ public class Track
        }
 
 
        }
 
 
+       /**
+        * Get the next track point starting from the given index
+        * @param inStartIndex index to start looking from
+        * @return next track point, or null if end of data reached
+        */
+       public DataPoint getNextTrackPoint(int inStartIndex)
+       {
+               return getNextTrackPoint(inStartIndex, 1);
+       }
+
+       /**
+        * Get the previous track point starting from the given index
+        * @param inStartIndex index to start looking from
+        * @return next track point, or null if end of data reached
+        */
+       public DataPoint getPreviousTrackPoint(int inStartIndex)
+       {
+               return getNextTrackPoint(inStartIndex, -1);
+       }
+
+       /**
+        * Get the next track point starting from the given index
+        * @param inStartIndex index to start looking from
+        * @param inIncrement increment to add to point index, +1 for next, -1 for previous
+        * @return next track point, or null if end of data reached
+        */
+       private DataPoint getNextTrackPoint(int inStartIndex, int inIncrement)
+       {
+               // Loop forever over points
+               for (int i=inStartIndex; ; i+=inIncrement)
+               {
+                       DataPoint point = getPoint(i);
+                       // Exit if end of data reached - there wasn't a track point
+                       if (point == null) {return null;}
+                       if (point.isValid() && !point.isWaypoint()) {
+                               // next track point found
+                               return point;
+                       }
+               }
+       }
+
+       /**
+        * Shift all the segment start flags in the given range by 1
+        * Method used by reverse range and its undo
+        * @param inStartIndex start of range, inclusive
+        * @param inEndIndex end of range, inclusive
+        */
+       public void shiftSegmentStarts(int inStartIndex, int inEndIndex)
+       {
+               boolean prevFlag = true;
+               boolean currFlag = true;
+               for (int i=inStartIndex; i<= inEndIndex; i++)
+               {
+                       DataPoint point = getPoint(i);
+                       if (point != null && !point.isWaypoint())
+                       {
+                               // remember flag
+                               currFlag = point.getSegmentStart();
+                               // shift flag by 1
+                               point.setSegmentStart(prevFlag);
+                               prevFlag = currFlag;
+                       }
+               }
+       }
+
        ////////////////// Cloning and replacing ///////////////////
 
        /**
        ////////////////// Cloning and replacing ///////////////////
 
        /**
@@ -824,7 +946,7 @@ public class Track
                _numPoints++;
                // needs to be scaled again
                _scaled = false;
                _numPoints++;
                // needs to be scaled again
                _scaled = false;
-               _broker.informSubscribers();
+               UpdateMessageBroker.informSubscribers();
                return true;
        }
 
                return true;
        }
 
@@ -857,7 +979,7 @@ public class Track
                _numPoints += inPoints.length;
                // needs to be scaled again
                _scaled = false;
                _numPoints += inPoints.length;
                // needs to be scaled again
                _scaled = false;
-               _broker.informSubscribers();
+               UpdateMessageBroker.informSubscribers();
                return true;
        }
 
                return true;
        }
 
@@ -875,7 +997,7 @@ public class Track
                _dataPoints = inContents;
                _numPoints = _dataPoints.length;
                _scaled = false;
                _dataPoints = inContents;
                _numPoints = _dataPoints.length;
                _scaled = false;
-               _broker.informSubscribers();
+               UpdateMessageBroker.informSubscribers();
                return true;
        }
 
                return true;
        }
 
@@ -910,7 +1032,7 @@ public class Track
                        // point possibly needs to be scaled again
                        _scaled = false;
                        // trigger listeners
                        // point possibly needs to be scaled again
                        _scaled = false;
                        // trigger listeners
-                       _broker.informSubscribers();
+                       UpdateMessageBroker.informSubscribers();
                        return true;
                }
                return false;
                        return true;
                }
                return false;
index f8e3c844b8ac86bc46c7c45bf8b78c7bc976f88e..bbbdefb2336d210a35d2336824d271a058557a76 100644 (file)
@@ -10,7 +10,6 @@ import tim.prune.UpdateMessageBroker;
  */
 public class TrackInfo
 {
  */
 public class TrackInfo
 {
-       private UpdateMessageBroker _broker = null;
        private Track _track = null;
        private Selection _selection = null;
        private FileInfo _fileInfo = null;
        private Track _track = null;
        private Selection _selection = null;
        private FileInfo _fileInfo = null;
@@ -20,13 +19,11 @@ public class TrackInfo
        /**
         * Constructor
         * @param inTrack Track object
        /**
         * Constructor
         * @param inTrack Track object
-        * @param inBroker broker object
         */
         */
-       public TrackInfo(Track inTrack, UpdateMessageBroker inBroker)
+       public TrackInfo(Track inTrack)
        {
        {
-               _broker = inBroker;
                _track = inTrack;
                _track = inTrack;
-               _selection = new Selection(_track, inBroker);
+               _selection = new Selection(_track);
                _fileInfo = new FileInfo();
                _photoList = new PhotoList();
        }
                _fileInfo = new FileInfo();
                _photoList = new PhotoList();
        }
@@ -198,7 +195,7 @@ public class TrackInfo
                if (_track.deletePoint(_selection.getCurrentPointIndex()))
                {
                        _selection.modifyPointDeleted();
                if (_track.deletePoint(_selection.getCurrentPointIndex()))
                {
                        _selection.modifyPointDeleted();
-                       _broker.informSubscribers();
+                       UpdateMessageBroker.informSubscribers();
                        return true;
                }
                return false;
                        return true;
                }
                return false;
@@ -236,7 +233,7 @@ public class TrackInfo
                        }
                        // update subscribers
                        _selection.modifyPointDeleted();
                        }
                        // update subscribers
                        _selection.modifyPointDeleted();
-                       _broker.informSubscribers();
+                       UpdateMessageBroker.informSubscribers();
                }
                return true;
        }
                }
                return true;
        }
@@ -252,7 +249,7 @@ public class TrackInfo
                int numDeleted = _track.compress(inResolution);
                if (numDeleted > 0) {
                        _selection.clearAll();
                int numDeleted = _track.compress(inResolution);
                if (numDeleted > 0) {
                        _selection.clearAll();
-                       _broker.informSubscribers();
+                       UpdateMessageBroker.informSubscribers();
                }
                return numDeleted;
        }
                }
                return numDeleted;
        }
@@ -267,7 +264,7 @@ public class TrackInfo
                int numDeleted = _track.deleteDuplicates();
                if (numDeleted > 0) {
                        _selection.clearAll();
                int numDeleted = _track.deleteDuplicates();
                if (numDeleted > 0) {
                        _selection.clearAll();
-                       _broker.informSubscribers();
+                       UpdateMessageBroker.informSubscribers();
                }
                return numDeleted;
        }
                }
                return numDeleted;
        }
@@ -331,13 +328,4 @@ public class TrackInfo
                        _selection.selectPhotoAndPoint(-1, -1);
                }
        }
                        _selection.selectPhotoAndPoint(-1, -1);
                }
        }
-
-
-       /**
-        * Fire a trigger to all data subscribers
-        */
-       public void triggerUpdate()
-       {
-               _broker.informSubscribers();
-       }
 }
 }
index 605abf6dff2c3ea62eff1330adc262d31fdd54cc..02c37f7624d21d3726c109f32668beacad18868c 100644 (file)
@@ -2,6 +2,7 @@ package tim.prune.gui;
 
 import java.awt.BorderLayout;
 import java.awt.Component;
 
 import java.awt.BorderLayout;
 import java.awt.Component;
+import java.awt.Dimension;
 import java.awt.FlowLayout;
 import java.awt.Font;
 import java.awt.GridBagConstraints;
 import java.awt.FlowLayout;
 import java.awt.Font;
 import java.awt.GridBagConstraints;
@@ -10,6 +11,7 @@ import java.awt.event.ActionEvent;
 import java.awt.event.ActionListener;
 import java.awt.event.KeyEvent;
 import java.awt.event.KeyListener;
 import java.awt.event.ActionListener;
 import java.awt.event.KeyEvent;
 import java.awt.event.KeyListener;
+import java.io.InputStream;
 
 import javax.swing.BorderFactory;
 import javax.swing.BoxLayout;
 
 import javax.swing.BorderFactory;
 import javax.swing.BoxLayout;
@@ -19,7 +21,9 @@ import javax.swing.JEditorPane;
 import javax.swing.JFrame;
 import javax.swing.JLabel;
 import javax.swing.JPanel;
 import javax.swing.JFrame;
 import javax.swing.JLabel;
 import javax.swing.JPanel;
+import javax.swing.JScrollPane;
 import javax.swing.JTabbedPane;
 import javax.swing.JTabbedPane;
+import javax.swing.JTextArea;
 
 import tim.prune.ExternalTools;
 import tim.prune.GpsPruner;
 
 import tim.prune.ExternalTools;
 import tim.prune.GpsPruner;
@@ -120,6 +124,12 @@ public class AboutScreen extends JDialog
                addToGridBagPanel(sysInfoPanel, gridBag, constraints,
                        new JLabel(I18nManager.getText(ExternalTools.isExiftoolInstalled()?"dialog.about.yes":"dialog.about.no")),
                        1, 4);
                addToGridBagPanel(sysInfoPanel, gridBag, constraints,
                        new JLabel(I18nManager.getText(ExternalTools.isExiftoolInstalled()?"dialog.about.yes":"dialog.about.no")),
                        1, 4);
+               addToGridBagPanel(sysInfoPanel, gridBag, constraints,
+                       new JLabel(I18nManager.getText("dialog.about.systeminfo.gpsbabel") + " : "),
+                       0, 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);
 
                // Third pane for credits
                tabPane.add(I18nManager.getText("dialog.about.systeminfo"), sysInfoPanel);
 
                // Third pane for credits
@@ -151,7 +161,7 @@ public class AboutScreen extends JDialog
                        new JLabel(I18nManager.getText("dialog.about.credits.translators") + " : "),
                        0, 3);
                addToGridBagPanel(creditsPanel, gridBag, constraints,
                        new JLabel(I18nManager.getText("dialog.about.credits.translators") + " : "),
                        0, 3);
                addToGridBagPanel(creditsPanel, gridBag, constraints,
-                       new JLabel("Ramon, Miguel, Inés, Piotr"),
+                       new JLabel("Ramon, Miguel, Inés, Piotr, Petrovsk"),
                        1, 3);
                addToGridBagPanel(creditsPanel, gridBag, constraints,
                        new JLabel(I18nManager.getText("dialog.about.credits.translations") + " : "),
                        1, 3);
                addToGridBagPanel(creditsPanel, gridBag, constraints,
                        new JLabel(I18nManager.getText("dialog.about.credits.translations") + " : "),
@@ -179,6 +189,18 @@ public class AboutScreen extends JDialog
                        1, 7);
                tabPane.add(I18nManager.getText("dialog.about.credits"), creditsPanel);
 
                        1, 7);
                tabPane.add(I18nManager.getText("dialog.about.credits"), creditsPanel);
 
+               // Read me
+               JPanel readmePanel = new JPanel();
+               readmePanel.setLayout(new BorderLayout());
+               JTextArea textArea = new JTextArea(getReadmeText());
+               textArea.setEditable(false);
+               textArea.setLineWrap(true); textArea.setWrapStyleWord(true);
+               JScrollPane scrollPane = new JScrollPane(textArea);
+               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);
+
                // OK button at the bottom
                JPanel okPanel = new JPanel();
                okPanel.setLayout(new FlowLayout(FlowLayout.CENTER));
                // OK button at the bottom
                JPanel okPanel = new JPanel();
                okPanel.setLayout(new FlowLayout(FlowLayout.CENTER));
@@ -227,6 +249,26 @@ public class AboutScreen extends JDialog
                inPanel.add(inLabel);
        }
 
                inPanel.add(inLabel);
        }
 
+       /**
+        * @return text from the readme file
+        */
+       private String getReadmeText()
+       {
+               try
+               {
+                       // For some reason using ../readme.txt doesn't work, so need absolute path
+                       InputStream in = getClass().getResourceAsStream("/tim/prune/readme.txt");
+                       if (in != null) {
+                               byte[] buffer = new byte[in.available()];
+                               in.read(buffer);
+                               return new String(buffer);
+                       }
+               }
+               catch (java.io.IOException e) {
+                       System.err.println("Exception trying to get readme : " + e.getMessage());
+               }
+               return I18nManager.getText("error.readme.notfound");
+       }
 
        /**
         * Show window
 
        /**
         * Show window
index aab8362e4d47e5328ba39d224e404857d2387793..7773062cccc25f006e4620f8c9b82edbbcc7ec99 100644 (file)
@@ -37,12 +37,13 @@ public class DetailsDisplay extends GenericDisplay
        private JLabel _indexLabel = null;
        private JLabel _latLabel = null, _longLabel = null;
        private JLabel _altLabel = null, _nameLabel = null;
        private JLabel _indexLabel = null;
        private JLabel _latLabel = null, _longLabel = null;
        private JLabel _altLabel = null, _nameLabel = null;
-       private JLabel _timeLabel = null;
+       private JLabel _timeLabel = null, _speedLabel = null;
 
        // Range details
        private JLabel _rangeLabel = null;
        private JLabel _distanceLabel = null, _durationLabel = null;
        private JLabel _altRangeLabel = null, _updownLabel = null;
 
        // Range details
        private JLabel _rangeLabel = null;
        private JLabel _distanceLabel = null, _durationLabel = null;
        private JLabel _altRangeLabel = null, _updownLabel = null;
+       private JLabel _aveSpeedLabel = null;
 
        // Photo details
        private JLabel _photoLabel = null;
 
        // Photo details
        private JLabel _photoLabel = null;
@@ -106,6 +107,8 @@ public class DetailsDisplay extends GenericDisplay
                pointDetailsPanel.add(_altLabel);
                _timeLabel = new JLabel("");
                pointDetailsPanel.add(_timeLabel);
                pointDetailsPanel.add(_altLabel);
                _timeLabel = new JLabel("");
                pointDetailsPanel.add(_timeLabel);
+               _speedLabel = new JLabel("");
+               pointDetailsPanel.add(_speedLabel);
                _nameLabel = new JLabel("");
                pointDetailsPanel.add(_nameLabel);
                pointDetailsPanel.setAlignmentX(Component.LEFT_ALIGNMENT);
                _nameLabel = new JLabel("");
                pointDetailsPanel.add(_nameLabel);
                pointDetailsPanel.setAlignmentX(Component.LEFT_ALIGNMENT);
@@ -125,13 +128,15 @@ public class DetailsDisplay extends GenericDisplay
                rangeDetailsPanel.add(_distanceLabel);
                _durationLabel = new JLabel("");
                rangeDetailsPanel.add(_durationLabel);
                rangeDetailsPanel.add(_distanceLabel);
                _durationLabel = new JLabel("");
                rangeDetailsPanel.add(_durationLabel);
+               _aveSpeedLabel = new JLabel("");
+               rangeDetailsPanel.add(_aveSpeedLabel);
                _altRangeLabel = new JLabel("");
                rangeDetailsPanel.add(_altRangeLabel);
                _updownLabel = new JLabel("");
                rangeDetailsPanel.add(_updownLabel);
                rangeDetailsPanel.setAlignmentX(Component.LEFT_ALIGNMENT);
 
                _altRangeLabel = new JLabel("");
                rangeDetailsPanel.add(_altRangeLabel);
                _updownLabel = new JLabel("");
                rangeDetailsPanel.add(_updownLabel);
                rangeDetailsPanel.setAlignmentX(Component.LEFT_ALIGNMENT);
 
-               // range details panel
+               // photo details panel
                JPanel photoDetailsPanel = new JPanel();
                photoDetailsPanel.setLayout(new BoxLayout(photoDetailsPanel, BoxLayout.Y_AXIS));
                photoDetailsPanel.setBorder(BorderFactory.createCompoundBorder(
                JPanel photoDetailsPanel = new JPanel();
                photoDetailsPanel.setLayout(new BoxLayout(photoDetailsPanel, BoxLayout.Y_AXIS));
                photoDetailsPanel.setBorder(BorderFactory.createCompoundBorder(
@@ -203,6 +208,10 @@ public class DetailsDisplay extends GenericDisplay
                DataPoint currentPoint = _trackInfo.getCurrentPoint();
                Selection selection = _trackInfo.getSelection();
                int currentPointIndex = selection.getCurrentPointIndex();
                DataPoint currentPoint = _trackInfo.getCurrentPoint();
                Selection selection = _trackInfo.getSelection();
                int currentPointIndex = selection.getCurrentPointIndex();
+               _speedLabel.setText("");
+               int 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)
                {
                        _indexLabel.setText(I18nManager.getText("details.nopointselection"));
                if (_track == null || currentPoint == null)
                {
                        _indexLabel.setText(I18nManager.getText("details.nopointselection"));
@@ -224,9 +233,27 @@ public class DetailsDisplay extends GenericDisplay
                                        (currentPoint.getAltitude().getValue() + getAltitudeUnitsLabel(currentPoint.getAltitude().getFormat())):
                                ""));
                        if (currentPoint.getTimestamp().isValid())
                                        (currentPoint.getAltitude().getValue() + getAltitudeUnitsLabel(currentPoint.getAltitude().getFormat())):
                                ""));
                        if (currentPoint.getTimestamp().isValid())
+                       {
+                               if (currentPointIndex > 0 && currentPointIndex < (_trackInfo.getTrack().getNumPoints()-1)) {
+                                       DataPoint prevPoint = _trackInfo.getTrack().getPoint(currentPointIndex - 1);
+                                       DataPoint nextPoint = _trackInfo.getTrack().getPoint(currentPointIndex + 1);
+                                       if (prevPoint.getTimestamp().isValid() && nextPoint.getTimestamp().isValid()) {
+                                               // use total distance and total time between neighbouring points
+                                               long diff = nextPoint.getTimestamp().getSecondsSince(prevPoint.getTimestamp());
+                                               if (diff < 100) {
+                                                       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);
+                                               }
+                                       }
+                               }
                                _timeLabel.setText(LABEL_POINT_TIMESTAMP + currentPoint.getTimestamp().getText());
                                _timeLabel.setText(LABEL_POINT_TIMESTAMP + currentPoint.getTimestamp().getText());
-                       else
+                       }
+                       else {
                                _timeLabel.setText("");
                                _timeLabel.setText("");
+                       }
                        String name = currentPoint.getWaypointName();
                        if (name != null && !name.equals(""))
                        {
                        String name = currentPoint.getWaypointName();
                        if (name != null && !name.equals(""))
                        {
@@ -249,18 +276,16 @@ public class DetailsDisplay extends GenericDisplay
                        _rangeLabel.setText(LABEL_RANGE_SELECTED1
                                + (selection.getStart()+1) + " " + I18nManager.getText("details.range.to")
                                + " " + (selection.getEnd()+1));
                        _rangeLabel.setText(LABEL_RANGE_SELECTED1
                                + (selection.getStart()+1) + " " + I18nManager.getText("details.range.to")
                                + " " + (selection.getEnd()+1));
-                       if (_distUnitsDropdown.getSelectedIndex() == 0)
-                               _distanceLabel.setText(LABEL_RANGE_DISTANCE + buildDistanceString(
-                                       selection.getDistance(Distance.UNITS_KILOMETRES))
-                                       + " " + I18nManager.getText("units.kilometres.short"));
-                       else
-                               _distanceLabel.setText(LABEL_RANGE_DISTANCE + buildDistanceString(
-                                       selection.getDistance(Distance.UNITS_MILES))
-                                       + " " + I18nManager.getText("units.miles.short"));
-                       if (selection.getNumSeconds() > 0)
+                       _distanceLabel.setText(LABEL_RANGE_DISTANCE + roundedNumber(selection.getDistance(distUnits)) + " " + distUnitsStr);
+                       if (selection.getNumSeconds() > 0) {
                                _durationLabel.setText(LABEL_RANGE_DURATION + buildDurationString(selection.getNumSeconds()));
                                _durationLabel.setText(LABEL_RANGE_DURATION + buildDurationString(selection.getNumSeconds()));
-                       else
+                               _aveSpeedLabel.setText(I18nManager.getText("details.range.avespeed") + ": "
+                                       + roundedNumber(selection.getDistance(distUnits)/selection.getNumSeconds()*3600.0) + " " + speedUnitsStr);
+                       }
+                       else {
                                _durationLabel.setText("");
                                _durationLabel.setText("");
+                               _aveSpeedLabel.setText("");
+                       }
                        String altUnitsLabel = getAltitudeUnitsLabel(selection.getAltitudeFormat());
                        IntegerRange altRange = selection.getAltitudeRange();
                        if (altRange.getMinimum() >= 0 && altRange.getMaximum() >= 0)
                        String altUnitsLabel = getAltitudeUnitsLabel(selection.getAltitudeFormat());
                        IntegerRange altRange = selection.getAltitudeRange();
                        if (altRange.getMinimum() >= 0 && altRange.getMaximum() >= 0)
@@ -354,17 +379,19 @@ public class DetailsDisplay extends GenericDisplay
                        + " " + (inNumSecs % 60) + I18nManager.getText("display.range.time.secs");
                if (inNumSecs < 86400L) return "" + (inNumSecs / 60 / 60) + I18nManager.getText("display.range.time.hours")
                        + " " + ((inNumSecs / 60) % 60) + I18nManager.getText("display.range.time.mins");
                        + " " + (inNumSecs % 60) + I18nManager.getText("display.range.time.secs");
                if (inNumSecs < 86400L) return "" + (inNumSecs / 60 / 60) + I18nManager.getText("display.range.time.hours")
                        + " " + ((inNumSecs / 60) % 60) + I18nManager.getText("display.range.time.mins");
+               if (inNumSecs < 432000L) return "" + (inNumSecs / 86400L) + I18nManager.getText("display.range.time.days")
+                       + (inNumSecs / 60 / 60) + I18nManager.getText("display.range.time.hours");
                if (inNumSecs < 8640000L) return "" + (inNumSecs / 86400L) + I18nManager.getText("display.range.time.days");
                return "big";
        }
 
 
        /**
                if (inNumSecs < 8640000L) return "" + (inNumSecs / 86400L) + I18nManager.getText("display.range.time.days");
                return "big";
        }
 
 
        /**
-        * Build a String to describe a distance
+        * Format a number to a sensible precision
         * @param inDist distance
         * @return formatted String
         */
         * @param inDist distance
         * @return formatted String
         */
-       private String buildDistanceString(double inDist)
+       private String roundedNumber(double inDist)
        {
                // Set precision of formatter
                int numDigits = 0;
        {
                // Set precision of formatter
                int numDigits = 0;
index 67c4d921128d0f0264b44e4730a6b2d50de1a3d0..a6f9b8635fdff03c3d962b7f29d45bb79247c09f 100644 (file)
@@ -23,4 +23,11 @@ public abstract class GenericDisplay extends JPanel implements DataSubscriber
                _trackInfo = inTrackInfo;
                _track = _trackInfo.getTrack();
        }
                _trackInfo = inTrackInfo;
                _track = _trackInfo.getTrack();
        }
+
+       /**
+        * Ignore action completed signals
+        */
+       public void actionCompleted(String inMessage)
+       {
+       }
 }
 }
index a5e7819ba209ab14e6b565fc31e49cca1523e091..37f43663c8c40ab28c511a0adf957610a781d738 100644 (file)
@@ -23,7 +23,6 @@ import tim.prune.DataSubscriber;
 import tim.prune.I18nManager;
 import tim.prune.data.DataPoint;
 import tim.prune.data.TrackInfo;
 import tim.prune.I18nManager;
 import tim.prune.data.DataPoint;
 import tim.prune.data.TrackInfo;
-//import tim.prune.gui.map.MapWindow;
 
 
 /**
 
 
 /**
@@ -34,7 +33,7 @@ public class MapChart extends GenericChart implements MouseWheelListener, KeyLis
        // Constants
        private static final int POINT_RADIUS = 4;
        private static final int CLICK_SENSITIVITY = 10;
        // Constants
        private static final int POINT_RADIUS = 4;
        private static final int CLICK_SENSITIVITY = 10;
-       private static final double ZOOM_SCALE_FACTOR = 1.2;
+       private static final double ZOOM_SCALE_FACTOR = 1.4;
        private static final int PAN_DISTANCE = 10;
        private static final int LIMIT_WAYPOINT_NAMES = 40;
 
        private static final int PAN_DISTANCE = 10;
        private static final int LIMIT_WAYPOINT_NAMES = 40;
 
@@ -252,8 +251,10 @@ public class MapChart extends GenericChart implements MouseWheelListener, KeyLis
                                bufferedG.drawRect(x - 2, y - 2, 3, 3);
 
                                // See whether to connect the point with previous one or not
                                bufferedG.drawRect(x - 2, y - 2, 3, 3);
 
                                // See whether to connect the point with previous one or not
-                               currPointTrackpoint = !_track.getPoint(i).isWaypoint() && _track.getPoint(i).getPhoto() == null;
-                               if (_connectPointsMenuItem.isSelected() && currPointTrackpoint && lastPointTrackpoint)
+                               DataPoint point = _track.getPoint(i);
+                               currPointTrackpoint = !point.isWaypoint() && point.getPhoto() == null;
+                               if (_connectPointsMenuItem.isSelected() && currPointTrackpoint && lastPointTrackpoint
+                                       && !point.getSegmentStart())
                                {
                                        bufferedG.drawLine(lastX, lastY, x, y);
                                }
                                {
                                        bufferedG.drawLine(lastX, lastY, x, y);
                                }
@@ -388,21 +389,11 @@ public class MapChart extends GenericChart implements MouseWheelListener, KeyLis
                                dataUpdated(DataSubscriber.ALL);
                        }
                });
                                dataUpdated(DataSubscriber.ALL);
                        }
                });
-               _connectPointsMenuItem.setSelected(false);
+               _connectPointsMenuItem.setSelected(true);
                _popup.add(_connectPointsMenuItem);
                _autoPanMenuItem = new JCheckBoxMenuItem(I18nManager.getText("menu.map.autopan"));
                _autoPanMenuItem.setSelected(true);
                _popup.add(_autoPanMenuItem);
                _popup.add(_connectPointsMenuItem);
                _autoPanMenuItem = new JCheckBoxMenuItem(I18nManager.getText("menu.map.autopan"));
                _autoPanMenuItem.setSelected(true);
                _popup.add(_autoPanMenuItem);
-/*
-               JMenuItem mapItem = new JMenuItem("Show map");
-               mapItem.addActionListener(new ActionListener() {
-                       public void actionPerformed(ActionEvent e)
-                       {
-                               showMap();
-                       }
-               });
-               _popup.add(mapItem);
-*/
        }
 
 
        }
 
 
@@ -642,15 +633,4 @@ public class MapChart extends GenericChart implements MouseWheelListener, KeyLis
        {
                // ignore
        }
        {
                // ignore
        }
-
-       /**
-        * Show a map window - probably only temporarily here until it gets fixed
-        */
-/*
-       private void showMap()
-       {
-               MapWindow map = new MapWindow(_track);
-               map.show();
-       }
-*/
 }
 }
index b97bb76bf660b0f72bf43c6fef948624c898f8f6..4b752681244e03b80bd845f7a908c493a6357f57 100644 (file)
@@ -17,6 +17,7 @@ import javax.swing.KeyStroke;
 import tim.prune.App;
 import tim.prune.DataSubscriber;
 import tim.prune.I18nManager;
 import tim.prune.App;
 import tim.prune.DataSubscriber;
 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.PhotoList;
 import tim.prune.data.Selection;
 import tim.prune.data.Track;
@@ -53,11 +54,11 @@ public class MenuManager implements DataSubscriber
        private JMenuItem _selectStartItem = null;
        private JMenuItem _selectEndItem = null;
        private JMenuItem _reverseItem = null;
        private JMenuItem _selectStartItem = null;
        private JMenuItem _selectEndItem = null;
        private JMenuItem _reverseItem = null;
+       private JMenuItem _mergeSegmentsItem = null;
        private JMenu     _rearrangeMenu = null;
        private JMenu     _rearrangeMenu = null;
-       private JMenuItem _rearrangeStartItem = null;
-       private JMenuItem _rearrangeEndItem = null;
-       private JMenuItem _rearrangeNearestItem = null;
        private JMenuItem _show3dItem = null;
        private JMenuItem _show3dItem = null;
+       private JMenuItem _showOsmMapItem = null;
+       private JMenu     _browserMapMenu = null;
        private JMenuItem _saveExifItem = null;
        private JMenuItem _connectPhotoItem = null;
        private JMenuItem _deletePhotoItem = null;
        private JMenuItem _saveExifItem = null;
        private JMenuItem _connectPhotoItem = null;
        private JMenuItem _deletePhotoItem = null;
@@ -275,36 +276,45 @@ public class MenuManager implements DataSubscriber
                });
                _reverseItem.setEnabled(false);
                editMenu.add(_reverseItem);
                });
                _reverseItem.setEnabled(false);
                editMenu.add(_reverseItem);
+               _mergeSegmentsItem = new JMenuItem(I18nManager.getText("menu.edit.mergetracksegments"));
+               _mergeSegmentsItem.addActionListener(new ActionListener() {
+                       public void actionPerformed(ActionEvent e)
+                       {
+                               _app.mergeTrackSegments();
+                       }
+               });
+               _mergeSegmentsItem.setEnabled(false);
+               editMenu.add(_mergeSegmentsItem);
                // Rearrange waypoints
                _rearrangeMenu = new JMenu(I18nManager.getText("menu.edit.rearrange"));
                _rearrangeMenu.setEnabled(false);
                // Rearrange waypoints
                _rearrangeMenu = new JMenu(I18nManager.getText("menu.edit.rearrange"));
                _rearrangeMenu.setEnabled(false);
-               _rearrangeStartItem = new JMenuItem(I18nManager.getText("menu.edit.rearrange.start"));
-               _rearrangeStartItem.addActionListener(new ActionListener() {
+               JMenuItem  rearrangeStartItem = new JMenuItem(I18nManager.getText("menu.edit.rearrange.start"));
+               rearrangeStartItem.addActionListener(new ActionListener() {
                        public void actionPerformed(ActionEvent e)
                        {
                                _app.rearrangeWaypoints(App.REARRANGE_TO_START);
                        }
                });
                        public void actionPerformed(ActionEvent e)
                        {
                                _app.rearrangeWaypoints(App.REARRANGE_TO_START);
                        }
                });
-               _rearrangeStartItem.setEnabled(true);
-               _rearrangeMenu.add(_rearrangeStartItem);
-               _rearrangeEndItem = new JMenuItem(I18nManager.getText("menu.edit.rearrange.end"));
-               _rearrangeEndItem.addActionListener(new ActionListener() {
+               rearrangeStartItem.setEnabled(true);
+               _rearrangeMenu.add(rearrangeStartItem);
+               JMenuItem rearrangeEndItem = new JMenuItem(I18nManager.getText("menu.edit.rearrange.end"));
+               rearrangeEndItem.addActionListener(new ActionListener() {
                        public void actionPerformed(ActionEvent e)
                        {
                                _app.rearrangeWaypoints(App.REARRANGE_TO_END);
                        }
                });
                        public void actionPerformed(ActionEvent e)
                        {
                                _app.rearrangeWaypoints(App.REARRANGE_TO_END);
                        }
                });
-               _rearrangeEndItem.setEnabled(true);
-               _rearrangeMenu.add(_rearrangeEndItem);
-               _rearrangeNearestItem = new JMenuItem(I18nManager.getText("menu.edit.rearrange.nearest"));
-               _rearrangeNearestItem.addActionListener(new ActionListener() {
+               rearrangeEndItem.setEnabled(true);
+               _rearrangeMenu.add(rearrangeEndItem);
+               JMenuItem rearrangeNearestItem = new JMenuItem(I18nManager.getText("menu.edit.rearrange.nearest"));
+               rearrangeNearestItem.addActionListener(new ActionListener() {
                        public void actionPerformed(ActionEvent e)
                        {
                                _app.rearrangeWaypoints(App.REARRANGE_TO_NEAREST);
                        }
                });
                        public void actionPerformed(ActionEvent e)
                        {
                                _app.rearrangeWaypoints(App.REARRANGE_TO_NEAREST);
                        }
                });
-               _rearrangeNearestItem.setEnabled(true);
-               _rearrangeMenu.add(_rearrangeNearestItem);
+               rearrangeNearestItem.setEnabled(true);
+               _rearrangeMenu.add(rearrangeNearestItem);
                editMenu.add(_rearrangeMenu);
                menubar.add(editMenu);
 
                editMenu.add(_rearrangeMenu);
                menubar.add(editMenu);
 
@@ -351,6 +361,49 @@ public class MenuManager implements DataSubscriber
                selectMenu.add(_selectEndItem);
                menubar.add(selectMenu);
 
                selectMenu.add(_selectEndItem);
                menubar.add(selectMenu);
 
+               // Add view menu
+               JMenu viewMenu = new JMenu(I18nManager.getText("menu.view"));
+               _show3dItem = new JMenuItem(I18nManager.getText("menu.view.show3d"));
+               _show3dItem.addActionListener(new ActionListener() {
+                       public void actionPerformed(ActionEvent e)
+                       {
+                               _app.show3dWindow();
+                       }
+               });
+               _show3dItem.setEnabled(false);
+               viewMenu.add(_show3dItem);
+               // Show OSM map
+               _showOsmMapItem = new JMenuItem(I18nManager.getText("menu.view.showmap"));
+               _showOsmMapItem.addActionListener(new ActionListener() {
+                       public void actionPerformed(ActionEvent e)
+                       {
+                               _app.showOsmMap();
+                       }
+               });
+               _showOsmMapItem.setEnabled(false);
+               viewMenu.add(_showOsmMapItem);
+               // browser submenu
+               _browserMapMenu = new JMenu(I18nManager.getText("menu.view.browser"));
+               _browserMapMenu.setEnabled(false);
+               JMenuItem googleMapsItem = new JMenuItem(I18nManager.getText("menu.view.browser.google"));
+               googleMapsItem.addActionListener(new ActionListener() {
+                       public void actionPerformed(ActionEvent e)
+                       {
+                               _app.showExternalMap(UrlGenerator.MAP_SOURCE_GOOGLE);
+                       }
+               });
+               _browserMapMenu.add(googleMapsItem);
+               JMenuItem openMapsItem = new JMenuItem(I18nManager.getText("menu.view.browser.openstreetmap"));
+               openMapsItem.addActionListener(new ActionListener() {
+                       public void actionPerformed(ActionEvent e)
+                       {
+                               _app.showExternalMap(UrlGenerator.MAP_SOURCE_OSM);
+                       }
+               });
+               _browserMapMenu.add(openMapsItem);
+               viewMenu.add(_browserMapMenu);
+               menubar.add(viewMenu);
+
                // Add photo menu
                JMenu photoMenu = new JMenu(I18nManager.getText("menu.photo"));
                addPhotosMenuItem = new JMenuItem(I18nManager.getText("menu.file.addphotos"));
                // Add photo menu
                JMenu photoMenu = new JMenu(I18nManager.getText("menu.photo"));
                addPhotosMenuItem = new JMenuItem(I18nManager.getText("menu.file.addphotos"));
@@ -408,19 +461,6 @@ public class MenuManager implements DataSubscriber
                photoMenu.add(_correlatePhotosItem);
                menubar.add(photoMenu);
 
                photoMenu.add(_correlatePhotosItem);
                menubar.add(photoMenu);
 
-               // Add 3d menu (whether java3d available or not)
-               JMenu threeDMenu = new JMenu(I18nManager.getText("menu.3d"));
-               _show3dItem = new JMenuItem(I18nManager.getText("menu.3d.show3d"));
-               _show3dItem.addActionListener(new ActionListener() {
-                       public void actionPerformed(ActionEvent e)
-                       {
-                               _app.show3dWindow();
-                       }
-               });
-               _show3dItem.setEnabled(false);
-               threeDMenu.add(_show3dItem);
-               menubar.add(threeDMenu);
-
                // Help menu
                JMenu helpMenu = new JMenu(I18nManager.getText("menu.help"));
                JMenuItem helpItem = new JMenuItem(I18nManager.getText("menu.help"));
                // Help menu
                JMenu helpMenu = new JMenu(I18nManager.getText("menu.help"));
                JMenuItem helpItem = new JMenuItem(I18nManager.getText("menu.help"));
@@ -534,6 +574,8 @@ public class MenuManager implements DataSubscriber
                _selectNoneItem.setEnabled(hasData);
                if (_show3dItem != null)
                        _show3dItem.setEnabled(hasData);
                _selectNoneItem.setEnabled(hasData);
                if (_show3dItem != null)
                        _show3dItem.setEnabled(hasData);
+               _showOsmMapItem.setEnabled(hasData);
+               _browserMapMenu.setEnabled(hasData);
                // is undo available?
                boolean hasUndo = !_app.getUndoStack().isEmpty();
                _undoItem.setEnabled(hasUndo);
                // is undo available?
                boolean hasUndo = !_app.getUndoStack().isEmpty();
                _undoItem.setEnabled(hasUndo);
@@ -568,6 +610,15 @@ public class MenuManager implements DataSubscriber
                _deleteRangeItem.setEnabled(hasRange);
                _interpolateItem.setEnabled(hasRange
                        && (_selection.getEnd() - _selection.getStart()) == 1);
                _deleteRangeItem.setEnabled(hasRange);
                _interpolateItem.setEnabled(hasRange
                        && (_selection.getEnd() - _selection.getStart()) == 1);
+               _mergeSegmentsItem.setEnabled(hasRange);
                _reverseItem.setEnabled(hasRange);
        }
                _reverseItem.setEnabled(hasRange);
        }
+
+
+       /**
+        * Ignore action completed signals
+        * @see tim.prune.DataSubscriber#actionCompleted(java.lang.String)
+        */
+       public void actionCompleted(String inMessage)
+       {}
 }
 }
index b792a66f55b6b70ff820a8d539739fa51c096787..629389150c8170ed47c872d89d037728b7adfd7e 100644 (file)
@@ -105,10 +105,8 @@ public class PhotoThumbnail extends JPanel implements Runnable
                        if (picWidth > -1 && picHeight > -1)
                        {
                                int displayWidth = Math.min(getWidth(), getParent().getWidth());
                        if (picWidth > -1 && picHeight > -1)
                        {
                                int displayWidth = Math.min(getWidth(), getParent().getWidth());
-                               // System.out.println("width = " + getWidth() + ", " + getParent().getWidth() + " = " + displayWidth);
                                int displayHeight = Math.min(getHeight(), getParent().getHeight());
                                int displayHeight = Math.min(getHeight(), getParent().getHeight());
-                               // System.out.println("height = " + getHeight() + ", " + getParent().getHeight() + " = " + displayHeight);
-       
+
                                // calculate maximum thumbnail size
                                Dimension thumbSize = ImageUtils.getThumbnailSize(picWidth, picHeight, displayWidth, displayHeight);
                                // Work out if need to remake image
                                // calculate maximum thumbnail size
                                Dimension thumbSize = ImageUtils.getThumbnailSize(picWidth, picHeight, displayWidth, displayHeight);
                                // Work out if need to remake image
diff --git a/tim/prune/gui/StatusBar.java b/tim/prune/gui/StatusBar.java
new file mode 100644 (file)
index 0000000..75810db
--- /dev/null
@@ -0,0 +1,76 @@
+package tim.prune.gui;
+
+import java.awt.FlowLayout;
+
+import javax.swing.BorderFactory;
+import javax.swing.JLabel;
+import javax.swing.JPanel;
+import tim.prune.DataSubscriber;
+
+/**
+ * Class to act as a status bar for the application
+ */
+public class StatusBar extends JPanel implements Runnable, DataSubscriber
+{
+       /** Label for displaying the text */
+       private JLabel _label = null;
+       /** timer for clearing the status */
+       private long _timer = 0L;
+       /** thread for clearing the status */
+       private Thread _thread = null;
+
+       /** Number of milliseconds until status text cleared */
+       private static final long DEFAULT_CLEAR_INTERVAL = 1000L * 4;
+
+
+       /**
+        * Constructor
+        */
+       public StatusBar()
+       {
+               setLayout(new FlowLayout(FlowLayout.LEFT, 0, 0));
+               setBorder(BorderFactory.createLoweredBevelBorder());
+               _label = new JLabel(" ");
+               _label.setFont(_label.getFont().deriveFont(8));
+               add(_label);
+       }
+
+       /**
+        * Run method, to check if text should be deleted
+        * @see java.lang.Runnable#run()
+        */
+       public void run()
+       {
+               while (System.currentTimeMillis() < _timer) {
+                       try {
+                               Thread.sleep(500);
+                       }
+                       catch (InterruptedException ie) {} // ignore
+               }
+               _label.setText(" ");
+       }
+
+       /**
+        * Accept notification that an action has been completed
+        * @param inMessage message to display
+        */
+       public void actionCompleted(String inMessage)
+       {
+               _label.setText(" " + inMessage);
+               _timer = System.currentTimeMillis() + DEFAULT_CLEAR_INTERVAL;
+               // If necessary, start a new checker thread
+               if (_thread == null || !_thread.isAlive()) {
+                       _thread = new Thread(this);
+                       _thread.start();
+               }
+               // TODO: Emphasize status bar when text set, eg change colour, make bold or something
+       }
+
+       /**
+        * Ignore signals about updated data
+        * @param inUpdateType update type
+        */
+       public void dataUpdated(byte inUpdateType)
+       {
+       }
+}
diff --git a/tim/prune/gui/images/window_icon.png b/tim/prune/gui/images/window_icon.png
new file mode 100644 (file)
index 0000000..76bbe94
Binary files /dev/null and b/tim/prune/gui/images/window_icon.png differ
diff --git a/tim/prune/gui/map/MapCanvas.java b/tim/prune/gui/map/MapCanvas.java
new file mode 100644 (file)
index 0000000..d306a09
--- /dev/null
@@ -0,0 +1,223 @@
+package tim.prune.gui.map;
+
+import java.awt.Color;
+import java.awt.Dimension;
+import java.awt.Graphics;
+import java.awt.MediaTracker;
+import java.awt.image.BufferedImage;
+import java.net.MalformedURLException;
+import java.net.URL;
+
+import javax.swing.ImageIcon;
+import javax.swing.JOptionPane;
+import javax.swing.JPanel;
+
+import tim.prune.I18nManager;
+import tim.prune.data.DoubleRange;
+import tim.prune.data.Track;
+
+/**
+ * Class for the map canvas, to display a background map and draw on it
+ */
+public class MapCanvas extends JPanel
+{
+
+       private BufferedImage _mapImage = null;
+       private Track _track = null;
+       private DoubleRange _latRange = null, _lonRange = null;
+       private DoubleRange _xRange = null, _yRange = null;
+       private boolean _gettingTiles = false;
+       /** Current zoom level */
+       private int _currZoom = 0;
+       /** Maximum zoom level (to avoid panning) */
+       private int _maxZoom = 0;
+
+
+       /**
+        * Constructor
+        * @param inTrack track object
+        */
+       public MapCanvas(Track inTrack)
+       {
+               _track = inTrack;
+               _latRange = inTrack.getLatRange();
+               _lonRange = inTrack.getLonRange();
+               _xRange = new DoubleRange(transformX(_lonRange.getMinimum()), transformX(_lonRange.getMaximum()));
+               _yRange = new DoubleRange(transformY(_latRange.getMinimum()), transformY(_latRange.getMaximum()));
+       }
+
+       /**
+        * Paint method
+        * @see java.awt.Canvas#paint(java.awt.Graphics)
+        */
+       public void paint(Graphics g)
+       {
+               super.paint(g);
+               if (_mapImage == null && !_gettingTiles) {
+                       _gettingTiles = true;
+                       new Thread(new Runnable() {
+                               public void run()
+                               {
+                                       getMapTiles();
+                               }
+                       }).start();
+               }
+               if (_mapImage != null) {
+                       g.drawImage(_mapImage, 0, 0, 512, 512, null);
+               }
+       }
+
+       /**
+        * Get the map tiles for the specified track range
+        */
+       private void getMapTiles()
+       {
+               _mapImage = new BufferedImage(512, 512, BufferedImage.TYPE_INT_RGB);
+               // zoom out until mins and maxes all on same group of four tiles
+               for (int zoom=15; zoom>1; zoom--)
+               {
+                       int tx1 = (int) Math.floor(_xRange.getMinimum() * (1<<zoom));
+                       int tx2 = (int) Math.floor(_xRange.getMaximum() * (1<<zoom));
+                       int ty1 = (int) Math.floor(_yRange.getMinimum() * (1<<zoom));
+                       int ty2 = (int) Math.floor(_yRange.getMaximum() * (1<<zoom));
+
+                       // Stop if reached a block of four adjacent tiles
+                       if (tx2 <= (tx1+1) && ty1 >= (ty2-1))
+                       {
+                               _currZoom = zoom;
+                               _maxZoom = zoom;
+                               getMapTiles(tx1, ty1);
+                               break;
+                       }
+               }
+               _gettingTiles = false;
+               repaint();
+       }
+
+       /**
+        * Get the map tiles for the current zoom level and given tile parameters
+        * @param inTileX x index of leftmost tile
+        * @param inTileY y index of lower tile
+        */
+       private void getMapTiles(int inTileX, int inTileY)
+       {
+               // Check if tile parameters were given
+               if (inTileX == -1 || inTileY == -1) {
+                       double tileX = _xRange.getMinimum() * (1<<_currZoom);
+                       double tileY = _yRange.getMinimum() * (1<<_currZoom);
+                       inTileX = (int) Math.floor(tileX);
+                       inTileY = (int) Math.floor(tileY);
+                       // see if should be shifted by 1 to make more central
+                       if (_currZoom != _maxZoom) {
+                               if ((tileX - inTileX) < 0.5) inTileX--; // don't squash to left
+                               if ((tileY - inTileY) < 0.5) inTileY--; // don't squash too high
+                       }
+               }
+               try
+               {
+                       ImageIcon[] icons = new ImageIcon[4];
+                       boolean loadingFailed = false;
+                       // Clear map
+                       Graphics g = _mapImage.getGraphics();
+                       g.clearRect(0, 0, 512, 512);
+                       for (int i=0; i<4 && !loadingFailed; i++)
+                       {
+                               String url = "http://tile.openstreetmap.org/" + _currZoom + "/" + (inTileX + i%2) + "/" + (inTileY + i/2) + ".png";
+                               icons[i] = new ImageIcon(new URL(url));
+                               if (icons[i] == null || icons[i].getImage() == null || icons[i].getImageLoadStatus() == MediaTracker.ERRORED)
+                               {
+                                       loadingFailed = true;
+                               }
+                               g.drawImage(icons[i].getImage(), 256*(i%2), 256*(i/2), 256, 256, null);
+                       }
+                       // show message if loading failed
+                       if (loadingFailed) {
+                               JOptionPane.showMessageDialog(this,
+                                       I18nManager.getText("error.osmimage.failed"),
+                                       I18nManager.getText("error.osmimage.dialogtitle"),
+                                       JOptionPane.ERROR_MESSAGE);
+                       }
+                       // red rectangle
+                       int rectX1 = (int) (256 * ((_xRange.getMinimum() * (1<<_currZoom)) - inTileX));
+                       int rectX2 = (int) (256 * ((_xRange.getMaximum() * (1<<_currZoom)) - inTileX));
+                       int rectY1 = (int) (256 * ((_yRange.getMinimum() * (1<<_currZoom)) - inTileY));
+                       int rectY2 = (int) (256 * ((_yRange.getMaximum() * (1<<_currZoom)) - inTileY));
+                       g.setColor(Color.RED);
+                       g.drawRect(rectX1, rectY1, rectX2-rectX1, rectY2-rectY1);
+                       // draw points
+                       g.setColor(Color.BLUE);
+                       for (int i=0; i<_track.getNumPoints(); i++)
+                       {
+                               int px = (int) (256 * ((transformX(_track.getPoint(i).getLongitude().getDouble()) * (1<<_currZoom)) - inTileX));
+                               int py = (int) (256 * ((transformY(_track.getPoint(i).getLatitude().getDouble()) * (1<<_currZoom)) - inTileY));
+                               g.drawRect(px, py, 2, 2);
+                       }
+               }
+               catch (MalformedURLException urle) {
+                       _mapImage = null;
+               }
+       }
+
+       /**
+        * Zoom out, if not already at minimum zoom
+        */
+       public void zoomOut()
+       {
+               if (_currZoom >= 2)
+               {
+                       _currZoom--;
+                       getMapTiles(-1, -1);
+                       repaint();
+               }
+       }
+
+       /**
+        * Zoom in, if not already at maximum zoom
+        */
+       public void zoomIn()
+       {
+               if (_currZoom < _maxZoom)
+               {
+                       _currZoom++;
+                       getMapTiles(-1, -1);
+                       repaint();
+               }
+       }
+
+       /**
+        * Transform a longitude into an x coordinate
+        * @param inLon longitude in degrees
+        * @return scaled X value from 0 to 1
+        */
+       private static double transformX(double inLon)
+       {
+               return (inLon + 180.0) / 360.0;
+       }
+
+       /**
+        * Transform a latitude into a y coordinate
+        * @param inLat latitude in degrees
+        * @return scaled Y value from 0 to 1
+        */
+       private static double transformY(double inLat)
+       {
+               return (1 - Math.log(Math.tan(inLat * Math.PI / 180) + 1 / Math.cos(inLat * Math.PI / 180)) / Math.PI) / 2;
+       }
+
+       /**
+        * @see javax.swing.JComponent#getMinimumSize()
+        */
+       public Dimension getMinimumSize()
+       {
+               final Dimension minSize = new Dimension(512, 512);
+               return minSize;
+       }
+
+       /**
+        * @see javax.swing.JComponent#getPreferredSize()
+        */
+       public Dimension getPreferredSize()
+       {
+               return getMinimumSize();
+       }
+}
diff --git a/tim/prune/gui/map/MapWindow.java b/tim/prune/gui/map/MapWindow.java
new file mode 100644 (file)
index 0000000..f47414a
--- /dev/null
@@ -0,0 +1,64 @@
+package tim.prune.gui.map;
+
+import java.awt.BorderLayout;
+import java.awt.Component;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+
+import javax.swing.JButton;
+import javax.swing.JFrame;
+import javax.swing.JPanel;
+
+import tim.prune.I18nManager;
+import tim.prune.data.Track;
+
+/**
+ * Class to hold the gui functions of the map window
+ */
+public class MapWindow extends JFrame
+{
+       private MapCanvas _canvas = null;
+
+       /**
+        * Constructor
+        * @param inTrack track object
+        */
+       public MapWindow(Track inTrack)
+       {
+               super(I18nManager.getText("dialog.map.title"));
+               getContentPane().add(createComponents(inTrack));
+               setResizable(false);
+       }
+
+       /**
+        * @param inTrack track object
+        * @return gui components
+        */
+       private Component createComponents(Track inTrack)
+       {
+               JPanel panel = new JPanel();
+               panel.setLayout(new BorderLayout());
+               _canvas = new MapCanvas(inTrack);
+               panel.add(_canvas, BorderLayout.CENTER);
+               // Make panel for zoom buttons
+               JPanel buttonPanel = new JPanel();
+               JButton zoomInButton = new JButton(I18nManager.getText("menu.map.zoomin"));
+               zoomInButton.addActionListener(new ActionListener() {
+                       public void actionPerformed(ActionEvent e)
+                       {
+                               _canvas.zoomIn();
+                       }
+               });
+               buttonPanel.add(zoomInButton);
+               JButton zoomOutButton = new JButton(I18nManager.getText("menu.map.zoomout"));
+               zoomOutButton.addActionListener(new ActionListener() {
+                       public void actionPerformed(ActionEvent e)
+                       {
+                               _canvas.zoomOut();
+                       }
+               });
+               buttonPanel.add(zoomOutButton);
+               panel.add(buttonPanel, BorderLayout.SOUTH);
+               return panel;
+       }
+}
index b9d86eb21d8669f3979fa57830c48259baa61b29..d1861356e5e9e2e2f99a2ff6b733e4fc48f12ad0 100644 (file)
@@ -21,6 +21,7 @@ menu.edit.deleteduplicates=Delete duplicates
 menu.edit.compress=Compress track
 menu.edit.interpolate=Interpolate
 menu.edit.reverse=Reverse range
 menu.edit.compress=Compress track
 menu.edit.interpolate=Interpolate
 menu.edit.reverse=Reverse range
+menu.edit.mergetracksegments=Merge track segments
 menu.edit.rearrange=Rearrange waypoints
 menu.edit.rearrange.start=All to start of file
 menu.edit.rearrange.end=All to end of file
 menu.edit.rearrange=Rearrange waypoints
 menu.edit.rearrange.start=All to start of file
 menu.edit.rearrange.end=All to end of file
@@ -36,8 +37,12 @@ menu.photo.connect=Connect to point
 menu.photo.disconnect=Disconnect from point
 menu.photo.correlate=Correlate all photos
 menu.photo.delete=Remove photo
 menu.photo.disconnect=Disconnect from point
 menu.photo.correlate=Correlate all photos
 menu.photo.delete=Remove photo
-menu.3d=Three-D
-menu.3d.show3d=Show in Three-D
+menu.view=View
+menu.view.show3d=Show in three-D
+menu.view.showmap=Show map
+menu.view.browser=Map in browser
+menu.view.browser.google=Google maps
+menu.view.browser.openstreetmap=Openstreetmap
 menu.help=Help
 menu.help.about=About Prune
 # Popup menu for map
 menu.help=Help
 menu.help.about=About Prune
 # Popup menu for map
@@ -57,14 +62,9 @@ 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.deletephoto.title=Delete Photo
 dialog.deletephoto.deletepoint=Delete point attached to this photo?
 dialog.deleteduplicates.title=Delete Duplicates
-dialog.deleteduplicates.single.text=duplicate was deleted
-dialog.deleteduplicates.multi.text=duplicates were deleted
 dialog.deleteduplicates.nonefound=No duplicates found
 dialog.compresstrack.title=Compress Track
 dialog.compresstrack.parameter.text=Parameter for compression (lower number = more compression)
 dialog.deleteduplicates.nonefound=No duplicates found
 dialog.compresstrack.title=Compress Track
 dialog.compresstrack.parameter.text=Parameter for compression (lower number = more compression)
-dialog.compresstrack.text=Track compressed
-dialog.compresstrack.single.text=data point was removed
-dialog.compresstrack.multi.text=data points were removed
 dialog.compresstrack.nonefound=No data points could be removed
 dialog.openoptions.title=Open options
 dialog.openoptions.filesnippet=Extract of file
 dialog.compresstrack.nonefound=No data points could be removed
 dialog.openoptions.title=Open options
 dialog.openoptions.filesnippet=Extract of file
@@ -77,7 +77,7 @@ dialog.delimiter.tab=Tab
 dialog.delimiter.space=Space
 dialog.delimiter.semicolon=Semicolon ;
 dialog.delimiter.other=Other
 dialog.delimiter.space=Space
 dialog.delimiter.semicolon=Semicolon ;
 dialog.delimiter.other=Other
-dialog.openoptions.deliminfo.records=records, with 
+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.deliminfo.fields=fields
 dialog.openoptions.deliminfo.norecords=No records
 dialog.openoptions.tabledesc=Extract of file
@@ -86,9 +86,6 @@ dialog.jpegload.subdirectories=Include subdirectories
 dialog.jpegload.loadjpegswithoutcoords=Include photos without coordinates
 dialog.jpegload.progress.title=Loading photos
 dialog.jpegload.progress=Please wait while the photos are searched
 dialog.jpegload.loadjpegswithoutcoords=Include photos without coordinates
 dialog.jpegload.progress.title=Loading photos
 dialog.jpegload.progress=Please wait while the photos are searched
-dialog.jpegload.title=Loaded photos
-dialog.jpegload.photoadded=photo was added
-dialog.jpegload.photosadded=photos were added
 dialog.saveoptions.title=Save file
 dialog.save.fieldstosave=Fields to save
 dialog.save.table.field=Field
 dialog.saveoptions.title=Save file
 dialog.save.fieldstosave=Fields to save
 dialog.save.table.field=Field
@@ -98,9 +95,6 @@ dialog.save.headerrow=Output header row
 dialog.save.coordinateunits=Coordinate units
 dialog.save.altitudeunits=Altitude units
 dialog.save.timestampformat=Timestamp format
 dialog.save.coordinateunits=Coordinate units
 dialog.save.altitudeunits=Altitude units
 dialog.save.timestampformat=Timestamp format
-dialog.save.oktitle=File saved
-dialog.save.ok1=Successfully saved
-dialog.save.ok2=points to file
 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.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
@@ -127,9 +121,6 @@ dialog.interpolate.title=Interpolate points
 dialog.interpolate.parameter.text=Number of points to insert between selected points
 dialog.undo.title=Undo action(s)
 dialog.undo.pretext=Please select the action(s) to undo
 dialog.interpolate.parameter.text=Number of points to insert between selected points
 dialog.undo.title=Undo action(s)
 dialog.undo.pretext=Please select the action(s) to undo
-dialog.confirmundo.title=Operation(s) undone
-dialog.confirmundo.single.text=operation undone.
-dialog.confirmundo.multiple.text=operations undone.
 dialog.undo.none.title=Cannot undo
 dialog.undo.none.text=No operations to undo!
 dialog.clearundo.title=Clear undo list
 dialog.undo.none.title=Cannot undo
 dialog.undo.none.text=No operations to undo!
 dialog.clearundo.title=Clear undo list
@@ -157,8 +148,6 @@ dialog.saveexif.photostatus.connected=Connected
 dialog.saveexif.photostatus.disconnected=Disconnected
 dialog.saveexif.photostatus.modified=Modified
 dialog.saveexif.overwrite=Overwrite files
 dialog.saveexif.photostatus.disconnected=Disconnected
 dialog.saveexif.photostatus.modified=Modified
 dialog.saveexif.overwrite=Overwrite files
-dialog.saveexif.ok1=Saved
-dialog.saveexif.ok2=photo files
 dialog.correlate.title=Correlate photos
 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.title=Correlate photos
 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?
@@ -182,8 +171,7 @@ 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.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.correlate.confirmsingle.text=photo was correlated
-dialog.correlate.confirmmultiple.text=photos were correlated
+dialog.map.title=Prune map
 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.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
@@ -198,6 +186,7 @@ dialog.about.systeminfo.java=Java Runtime
 dialog.about.systeminfo.java3d=Java3d installed
 dialog.about.systeminfo.povray=Povray installed
 dialog.about.systeminfo.exiftool=Exiftool installed
 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.yes=Yes
 dialog.about.no=No
 dialog.about.credits=Credits
 dialog.about.yes=Yes
 dialog.about.no=No
 dialog.about.credits=Credits
@@ -209,6 +198,7 @@ dialog.about.credits.translations=Translations helped by
 dialog.about.credits.devtools=Development tools
 dialog.about.credits.othertools=Other tools
 dialog.about.credits.thanks=Thanks to
 dialog.about.credits.devtools=Development tools
 dialog.about.credits.othertools=Other tools
 dialog.about.credits.thanks=Thanks to
+dialog.about.readme=Readme
 
 # 3d window
 dialog.3d.title=Prune Three-d view
 
 # 3d window
 dialog.3d.title=Prune Three-d view
@@ -217,6 +207,28 @@ dialog.3dlines.title=Prune gridlines
 dialog.3dlines.empty=No gridlines to display!
 dialog.3dlines.intro=These are the gridlines for the three-d view
 
 dialog.3dlines.empty=No gridlines to display!
 dialog.3dlines.intro=These are the gridlines for the three-d view
 
+# Confirm messages || These are displayed as confirmation in the status bar
+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
+confirm.mergetracksegments=track segments merged
+confirm.reverserange=Range reversed
+confirm.saveexif.ok1=Saved
+confirm.saveexif.ok2=photo files
+confirm.undo.single=operation undone
+confirm.undo.multi=operations undone
+confirm.jpegload.single=photo was added
+confirm.jpegload.multi=photos were added
+confirm.photo.connect=photo connected
+confirm.photo.disconnect=photo disconnected
+confirm.correlate.single=photo was correlated
+confirm.correlate.multi=photos were correlated
+
 # Buttons
 button.ok=OK
 button.back=Back
 # Buttons
 button.ok=OK
 button.back=Back
@@ -252,6 +264,7 @@ details.pointdetails=Point details
 details.index.selected=Index
 details.index.of=of
 details.nopointselection=No point selected
 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
 details.photofile=Photo file
 details.norangeselection=No range selected
 details.rangedetails=Range details
@@ -266,6 +279,7 @@ display.range.time.secs=s
 display.range.time.mins=m
 display.range.time.hours=h
 display.range.time.days=d
 display.range.time.mins=m
 display.range.time.hours=h
 display.range.time.days=d
+details.range.avespeed=Ave speed
 details.waypointsphotos.waypoints=Waypoints
 details.waypointsphotos.photos=Photos
 details.photodetails=Photo details
 details.waypointsphotos.waypoints=Waypoints
 details.waypointsphotos.photos=Photos
 details.photodetails=Photo details
@@ -295,13 +309,18 @@ units.feet=Feet
 units.feet.short=ft
 units.kilometres=Kilometres
 units.kilometres.short=km
 units.feet.short=ft
 units.kilometres=Kilometres
 units.kilometres.short=km
+units.kmh=km/h
 units.miles=Miles
 units.miles.short=mi
 units.miles=Miles
 units.miles.short=mi
+units.mph=mph
 units.degminsec=Deg-min-sec
 units.degmin=Deg-min
 units.deg=Degrees
 units.iso8601=ISO 8601
 
 units.degminsec=Deg-min-sec
 units.degmin=Deg-min
 units.deg=Degrees
 units.iso8601=ISO 8601
 
+# External urls
+url.googlemaps=maps.google.co.uk
+
 # Cardinals for 3d plots
 cardinal.n=N
 cardinal.s=S
 # Cardinals for 3d plots
 cardinal.n=N
 cardinal.s=S
@@ -319,6 +338,7 @@ undo.compress=compress track
 undo.insert=insert points
 undo.deleteduplicates=delete duplicates
 undo.reverse=reverse range
 undo.insert=insert points
 undo.deleteduplicates=delete duplicates
 undo.reverse=reverse range
+undo.mergetracksegments=merge track segments
 undo.rearrangewaypoints=rearrange waypoints
 undo.connectphoto=connect photo
 undo.disconnectphoto=disconnect photo
 undo.rearrangewaypoints=rearrange waypoints
 undo.connectphoto=connect photo
 undo.disconnectphoto=disconnect photo
@@ -347,6 +367,9 @@ 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.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 or Blackdown.org.
+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.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
+error.osmimage.failed=Failed to load map images. Please check internet connection.
index 7c67508e83330e41483a27f48f1e42d6dbb576a2..1f8b0d155c3703cf145abd17f97bfe9b7b30bd7a 100644 (file)
@@ -21,13 +21,14 @@ menu.edit.deleteduplicates=Duplikate l
 menu.edit.compress=Track komprimieren
 menu.edit.interpolate=Interpolieren
 menu.edit.reverse=Spanne umkehren
 menu.edit.compress=Track komprimieren
 menu.edit.interpolate=Interpolieren
 menu.edit.reverse=Spanne umkehren
+menu.edit.mergetracksegments=Trackteilen verbinden
 menu.edit.rearrange=Waypoints reorganisieren
 menu.edit.rearrange.start=Alle zum Anfang
 menu.edit.rearrange.end=Alle zum Ende
 menu.edit.rearrange.nearest=Jeder zum nächsten Trackpunkt
 menu.edit.rearrange=Waypoints reorganisieren
 menu.edit.rearrange.start=Alle zum Anfang
 menu.edit.rearrange.end=Alle zum Ende
 menu.edit.rearrange.nearest=Jeder zum nächsten Trackpunkt
-menu.select=Selektieren
-menu.select.all=Alles selektieren
-menu.select.none=Nichts selektieren
+menu.select=Markieren
+menu.select.all=Alles markieren
+menu.select.none=Nichts markieren
 menu.select.start=Start setzen
 menu.select.end=Stopp setzen
 menu.photo=Foto
 menu.select.start=Start setzen
 menu.select.end=Stopp setzen
 menu.photo=Foto
@@ -36,8 +37,12 @@ menu.photo.connect=Mit Punkt verbinden
 menu.photo.disconnect=Vom Punkt trennen
 menu.photo.correlate=Alle Fotos korrelieren
 menu.photo.delete=Foto entfernen
 menu.photo.disconnect=Vom Punkt trennen
 menu.photo.correlate=Alle Fotos korrelieren
 menu.photo.delete=Foto entfernen
-menu.3d=Drei-D
-menu.3d.show3d=In drei-D zeigen
+menu.view=Ansicht
+menu.view.show3d=In drei-D zeigen
+menu.view.showmap=Karte zeigen
+menu.view.browser=Karte in Browser
+menu.view.browser.google=Google Maps
+menu.view.browser.openstreetmap=Openstreetmap
 menu.help=Hilfe
 menu.help.about=Ãœber Prune
 # Popup menu for map
 menu.help=Hilfe
 menu.help.about=Ãœber Prune
 # Popup menu for map
@@ -57,14 +62,9 @@ dialog.deletepoint.deletephoto=Foto von diesem Punkt auch l
 dialog.deletephoto.title=Photo entfernen
 dialog.deletephoto.deletepoint=Punkt von diesem Foto auch löschen?
 dialog.deleteduplicates.title=Duplikate löschen
 dialog.deletephoto.title=Photo entfernen
 dialog.deletephoto.deletepoint=Punkt von diesem Foto auch löschen?
 dialog.deleteduplicates.title=Duplikate löschen
-dialog.deleteduplicates.single.text=Duplikat wurde gelöscht
-dialog.deleteduplicates.multi.text=Duplikate wurden gelöscht
 dialog.deleteduplicates.nonefound=Keine Duplikate gefunden
 dialog.compresstrack.title=Track komprimieren
 dialog.compresstrack.parameter.text=Parameter für Komprimierung (niedriger Nummer = höher Komprimierung)
 dialog.deleteduplicates.nonefound=Keine Duplikate gefunden
 dialog.compresstrack.title=Track komprimieren
 dialog.compresstrack.parameter.text=Parameter für Komprimierung (niedriger Nummer = höher Komprimierung)
-dialog.compresstrack.text=Track komprimiert
-dialog.compresstrack.single.text=Punkt wurde entfernt
-dialog.compresstrack.multi.text=Punkte wurden entfernt
 dialog.compresstrack.nonefound=Keine Punkte konnten entfernt werden
 dialog.openoptions.title=Öffnen Optionen
 dialog.openoptions.filesnippet=Extrakt von der Datei
 dialog.compresstrack.nonefound=Keine Punkte konnten entfernt werden
 dialog.openoptions.title=Öffnen Optionen
 dialog.openoptions.filesnippet=Extrakt von der Datei
@@ -77,7 +77,7 @@ dialog.delimiter.tab=Tab
 dialog.delimiter.space=Abstand
 dialog.delimiter.semicolon=Strichpunkt ;
 dialog.delimiter.other=Andere
 dialog.delimiter.space=Abstand
 dialog.delimiter.semicolon=Strichpunkt ;
 dialog.delimiter.other=Andere
-dialog.openoptions.deliminfo.records=Rekords, mit 
+dialog.openoptions.deliminfo.records=Rekords, mit
 dialog.openoptions.deliminfo.fields=Feldern
 dialog.openoptions.deliminfo.norecords=Keine Rekords
 dialog.openoptions.tabledesc=Extrakt von der Datei
 dialog.openoptions.deliminfo.fields=Feldern
 dialog.openoptions.deliminfo.norecords=Keine Rekords
 dialog.openoptions.tabledesc=Extrakt von der Datei
@@ -86,9 +86,6 @@ dialog.jpegload.subdirectories=Subordnern auch durchsuchen
 dialog.jpegload.loadjpegswithoutcoords=Auch Fotos ohne Koordinaten laden
 dialog.jpegload.progress.title=Fotos werden geladen
 dialog.jpegload.progress=Bitte warten während die Fotos durchgesucht werden
 dialog.jpegload.loadjpegswithoutcoords=Auch Fotos ohne Koordinaten laden
 dialog.jpegload.progress.title=Fotos werden geladen
 dialog.jpegload.progress=Bitte warten während die Fotos durchgesucht werden
-dialog.jpegload.title=Fotos geladen
-dialog.jpegload.photoadded=Foto wurde geladen
-dialog.jpegload.photosadded=Fotos wurden geladen
 dialog.saveoptions.title=Datei speichern
 dialog.save.fieldstosave=Felder zu speichern
 dialog.save.table.field=Feld
 dialog.saveoptions.title=Datei speichern
 dialog.save.fieldstosave=Felder zu speichern
 dialog.save.table.field=Feld
@@ -98,9 +95,6 @@ dialog.save.headerrow=Titel Zeile speichern
 dialog.save.coordinateunits=Koordinaten Maßeinheiten
 dialog.save.altitudeunits=Höhe Maßeinheiten
 dialog.save.timestampformat=Zeitstempelformat
 dialog.save.coordinateunits=Koordinaten Maßeinheiten
 dialog.save.altitudeunits=Höhe Maßeinheiten
 dialog.save.timestampformat=Zeitstempelformat
-dialog.save.oktitle=Datei gespeichert
-dialog.save.ok1=Es wurden
-dialog.save.ok2=Punkte gespeichert nach
 dialog.save.overwrite.title=Datei existiert
 dialog.save.overwrite.text=Diese Datei existiert schon. Sind Sie sicher, Sie wollen die Datei Ã¼berschreiben?
 dialog.exportkml.title=KML exportieren
 dialog.save.overwrite.title=Datei existiert
 dialog.save.overwrite.text=Diese Datei existiert schon. Sind Sie sicher, Sie wollen die Datei Ã¼berschreiben?
 dialog.exportkml.title=KML exportieren
@@ -127,9 +121,6 @@ dialog.interpolate.title=Punkte interpolieren
 dialog.interpolate.parameter.text=Anzahl Punkte zuzufügen zwischen den selektierten Punkten
 dialog.undo.title=Undo Operation(en)
 dialog.undo.pretext=Selektieren die Operationen die rückgängig gemacht werden sollen.
 dialog.interpolate.parameter.text=Anzahl Punkte zuzufügen zwischen den selektierten Punkten
 dialog.undo.title=Undo Operation(en)
 dialog.undo.pretext=Selektieren die Operationen die rückgängig gemacht werden sollen.
-dialog.confirmundo.title=Operation(en) rückgängig gemacht
-dialog.confirmundo.single.text=Operation rückgängig gemacht.
-dialog.confirmundo.multiple.text=Operationen rückgängig gemacht.
 dialog.undo.none.title=Undo nicht möglich
 dialog.undo.none.text=Keine Operationen können rückgängig gemacht werden.
 dialog.clearundo.title=Undo-Liste löschen
 dialog.undo.none.title=Undo nicht möglich
 dialog.undo.none.text=Keine Operationen können rückgängig gemacht werden.
 dialog.clearundo.title=Undo-Liste löschen
@@ -157,8 +148,6 @@ dialog.saveexif.photostatus.connected=Verbunden
 dialog.saveexif.photostatus.disconnected=Getrennt
 dialog.saveexif.photostatus.modified=Modifiziert
 dialog.saveexif.overwrite=Dateien Ã¼berschreiben
 dialog.saveexif.photostatus.disconnected=Getrennt
 dialog.saveexif.photostatus.modified=Modifiziert
 dialog.saveexif.overwrite=Dateien Ã¼berschreiben
-dialog.saveexif.ok1=Es wurden
-dialog.saveexif.ok2=Foto Dateien geschrieben
 dialog.correlate.title=Fotos korrelieren
 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.title=Fotos korrelieren
 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?
@@ -182,8 +171,7 @@ 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.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.correlate.confirmsingle.text=Foto wurde korreliert
-dialog.correlate.confirmmultiple.text=Fotos wurden korreliert
+dialog.map.title=Prune Karte
 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.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
@@ -198,6 +186,7 @@ dialog.about.systeminfo.java=Java Runtime
 dialog.about.systeminfo.java3d=Java3d installiert
 dialog.about.systeminfo.povray=Povray installiert
 dialog.about.systeminfo.exiftool=Exiftool installiert
 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.yes=Ja
 dialog.about.no=Nein
 dialog.about.credits=Credits
 dialog.about.yes=Ja
 dialog.about.no=Nein
 dialog.about.credits=Credits
@@ -209,6 +198,7 @@ dialog.about.credits.translations=
 dialog.about.credits.devtools=Entwicklungsprogrammen
 dialog.about.credits.othertools=Andere Programmen
 dialog.about.credits.thanks=Danke an
 dialog.about.credits.devtools=Entwicklungsprogrammen
 dialog.about.credits.othertools=Andere Programmen
 dialog.about.credits.thanks=Danke an
+dialog.about.readme=Liesmich
 
 # 3d window
 dialog.3d.title=Prune Drei-D Ansicht
 
 # 3d window
 dialog.3d.title=Prune Drei-D Ansicht
@@ -217,6 +207,28 @@ dialog.3dlines.title=Prune Gitterlinien
 dialog.3dlines.empty=Keine Linien zum anzeigen!
 dialog.3dlines.intro=Hier sind die Linien für die drei-D Ansicht
 
 dialog.3dlines.empty=Keine Linien zum anzeigen!
 dialog.3dlines.intro=Hier sind die Linien für die drei-D Ansicht
 
+# Confirm messages || These are displayed as confirmation in the status bar
+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
+confirm.mergetracksegments=Trackteilen verbunden
+confirm.reverserange=Spanne umgekehrt
+confirm.saveexif.ok1=Es wurden
+confirm.saveexif.ok2=Foto Dateien geschrieben
+confirm.undo.single=Operation rückgängig gemacht
+confirm.undo.multi=Operationen rückgängig gemacht
+confirm.jpegload.single=Foto wurde geladen
+confirm.jpegload.multi=Fotos wurden geladen
+confirm.photo.connect=Foto verbunden
+confirm.photo.disconnect=Foto getrennt
+confirm.correlate.single=Foto wurde korreliert
+confirm.correlate.multi=Fotos wurden korreliert
+
 # Buttons
 button.ok=OK
 button.back=Zurück
 # Buttons
 button.ok=OK
 button.back=Zurück
@@ -252,6 +264,7 @@ details.pointdetails=Details vom Punkt
 details.index.selected=Index
 details.index.of=von
 details.nopointselection=Nichts selektiert
 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 von Spanne
 details.photofile=Foto Datei
 details.norangeselection=Nichts selektiert
 details.rangedetails=Details von Spanne
@@ -266,6 +279,7 @@ display.range.time.secs=S
 display.range.time.mins=M
 display.range.time.hours=Std
 display.range.time.days=T
 display.range.time.mins=M
 display.range.time.hours=Std
 display.range.time.days=T
+details.range.avespeed=Geschwindigkeit
 details.waypointsphotos.waypoints=Waypoints
 details.waypointsphotos.photos=Fotos
 details.photodetails=Details vom Foto
 details.waypointsphotos.waypoints=Waypoints
 details.waypointsphotos.photos=Fotos
 details.photodetails=Details vom Foto
@@ -295,13 +309,18 @@ units.feet=F
 units.feet.short=F
 units.kilometres=Kilometer
 units.kilometres.short=Km
 units.feet.short=F
 units.kilometres=Kilometer
 units.kilometres.short=Km
+units.kmh=Km/h
 units.miles=Meilen
 units.miles.short=Mei
 units.miles=Meilen
 units.miles.short=Mei
+units.mph=Mei/Std
 units.degminsec=Grad-Min-Sek
 units.degmin=Grad-Min
 units.deg=Grad
 units.iso8601=ISO 8601
 
 units.degminsec=Grad-Min-Sek
 units.degmin=Grad-Min
 units.deg=Grad
 units.iso8601=ISO 8601
 
+# External urls
+url.googlemaps=maps.google.de
+
 # Cardinals for 3d plots
 cardinal.n=N
 cardinal.s=S
 # Cardinals for 3d plots
 cardinal.n=N
 cardinal.s=S
@@ -319,6 +338,7 @@ undo.compress=Track komprimieren
 undo.insert=Punkte hinzufügen
 undo.deleteduplicates=Duplikaten löschen
 undo.reverse=Spanne umdrehen
 undo.insert=Punkte hinzufügen
 undo.deleteduplicates=Duplikaten löschen
 undo.reverse=Spanne umdrehen
+undo.mergetracksegments=Trackteilen verbinden
 undo.rearrangewaypoints=Waypoints reorganisieren
 undo.connectphoto=Foto verbinden
 undo.disconnectphoto=Foto trennen
 undo.rearrangewaypoints=Waypoints reorganisieren
 undo.connectphoto=Foto verbinden
 undo.disconnectphoto=Foto trennen
@@ -347,6 +367,9 @@ 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.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 oder Blackdown.org erhältlich.
+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.3d.title=Fehler mit 3d Darstellung
 error.3d=Ein Fehler ist mit der 3d Darstellung aufgetreten
+error.readme.notfound=Lies mich Datei nicht gefunden
+error.osmimage.dialogtitle=Laden von Karten-Bilder fehlgeschlagen
+error.osmimage.failed=Laden von Karten-Bilder fehlgeschlagen. Bitte prüfen Sie die Internet-Verbindung.
index 9ce937ae11e877167a910ac2aea0c2c85f00cc8e..5b0c378a63c918392acdedf1031608a4bb2a0006 100644 (file)
@@ -21,6 +21,7 @@ menu.edit.deleteduplicates=Doppeldate l
 menu.edit.compress=Date komprimiere
 menu.edit.interpolate=Interpoliere
 menu.edit.reverse=Spanne umdrähie
 menu.edit.compress=Date komprimiere
 menu.edit.interpolate=Interpoliere
 menu.edit.reverse=Spanne umdrähie
+menu.edit.mergetracksegments=Track Segmänte merge
 menu.edit.rearrange=Waypoints reorganisiere
 menu.edit.rearrange.start=Alli zum Aafang
 menu.edit.rearrange.end=Alli zum Ã„nde
 menu.edit.rearrange=Waypoints reorganisiere
 menu.edit.rearrange.start=Alli zum Aafang
 menu.edit.rearrange.end=Alli zum Ã„nde
@@ -36,8 +37,12 @@ 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.photo.disconnect=Vonem Punkt trännä
 menu.photo.correlate=Alli Fötelis korrelierä
 menu.photo.delete=Föteli entfernä
-menu.3d=Drüü-D
-menu.3d.show3d=In drüü-D zeigä
+menu.view=Aasicht
+menu.view.show3d=In drüü-D zeigä
+menu.view.showmap=Kate zeigä
+menu.view.browser=Karte inem Browser
+menu.view.browser.google=Google maps
+menu.view.browser.openstreetmap=Openstreetmap
 menu.help=Hilfe
 menu.help.about=Ãœber Prune
 # Popup menu for map
 menu.help=Hilfe
 menu.help.about=Ãœber Prune
 # Popup menu for map
@@ -57,14 +62,9 @@ dialog.deletepoint.deletephoto=s F
 dialog.deletephoto.title=Föteli entfernä
 dialog.deletephoto.deletepoint=Punkt vonem Föteli au löschä?
 dialog.deleteduplicates.title=Duplikaten lösche
 dialog.deletephoto.title=Föteli entfernä
 dialog.deletephoto.deletepoint=Punkt vonem Föteli au löschä?
 dialog.deleteduplicates.title=Duplikaten lösche
-dialog.deleteduplicates.single.text=Duplikat isch glöscht worde
-dialog.deleteduplicates.multi.text=Duplikaten sin glöscht worde
 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.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.text=Track komprimiert worde
-dialog.compresstrack.single.text=Punkt isch entfernt worde
-dialog.compresstrack.multi.text=Punkte sin entfernt worde
 dialog.compresstrack.nonefound=Kei Punkte hätte gelöscht werde könne
 dialog.openoptions.title=Öffne Optionen
 dialog.openoptions.filesnippet=Extrakt vom File
 dialog.compresstrack.nonefound=Kei Punkte hätte gelöscht werde könne
 dialog.openoptions.title=Öffne Optionen
 dialog.openoptions.filesnippet=Extrakt vom File
@@ -77,7 +77,7 @@ dialog.delimiter.tab=Tab
 dialog.delimiter.space=Abstand
 dialog.delimiter.semicolon=Strichpunkt ;
 dialog.delimiter.other=Andere
 dialog.delimiter.space=Abstand
 dialog.delimiter.semicolon=Strichpunkt ;
 dialog.delimiter.other=Andere
-dialog.openoptions.deliminfo.records=Rekords, mit 
+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.deliminfo.fields=Fäldere
 dialog.openoptions.deliminfo.norecords=Kei Rekords
 dialog.openoptions.tabledesc=Extrakt vom File
@@ -86,9 +86,6 @@ dialog.jpegload.subdirectories=Subordnern au
 dialog.jpegload.loadjpegswithoutcoords=Au Fötelis ohni Koordinate
 dialog.jpegload.progress.title=Fötelis lade
 dialog.jpegload.progress=Bitte warte während die Fötelis durägsucht werde
 dialog.jpegload.loadjpegswithoutcoords=Au Fötelis ohni Koordinate
 dialog.jpegload.progress.title=Fötelis lade
 dialog.jpegload.progress=Bitte warte während die Fötelis durägsucht werde
-dialog.jpegload.title=Fötelis glade worde
-dialog.jpegload.photoadded=Föteli isch glade worde
-dialog.jpegload.photosadded=Fötelis sin glade worde
 dialog.saveoptions.title=File speicherä
 dialog.save.fieldstosave=Fälder zu speicherä
 dialog.save.table.field=Fäld
 dialog.saveoptions.title=File speicherä
 dialog.save.fieldstosave=Fälder zu speicherä
 dialog.save.table.field=Fäld
@@ -98,9 +95,6 @@ dialog.save.headerrow=Titel Ziile speicher
 dialog.save.coordinateunits=Koordinate Massiiheite
 dialog.save.altitudeunits=Höchi Massiiheite
 dialog.save.timestampformat=Ziitstämpelformat
 dialog.save.coordinateunits=Koordinate Massiiheite
 dialog.save.altitudeunits=Höchi Massiiheite
 dialog.save.timestampformat=Ziitstämpelformat
-dialog.save.oktitle=File gspeicheret worde
-dialog.save.ok1=Es sin
-dialog.save.ok2=Punkte gspeicheret worde na
 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.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ä
@@ -127,9 +121,6 @@ dialog.interpolate.title=Punkte interpoliere
 dialog.interpolate.parameter.text=Aazahl Punkte zum innätue zwüschet den selektierten Punkten
 dialog.undo.title=Undo Operation(e)
 dialog.undo.pretext=Selektiere die Operatione die rückgängig gmacht söllti werde.
 dialog.interpolate.parameter.text=Aazahl Punkte zum innätue zwüschet den selektierten Punkten
 dialog.undo.title=Undo Operation(e)
 dialog.undo.pretext=Selektiere die Operatione die rückgängig gmacht söllti werde.
-dialog.confirmundo.title=Operation(e) rückgängig gmacht worde
-dialog.confirmundo.single.text=Operation rückgängig gmacht worde.
-dialog.confirmundo.multiple.text=Operatione rückgängig gmacht worde.
 dialog.undo.none.title=Undo nöd möglich
 dialog.undo.none.text=Keini Operatione könne rückgängig gmacht werde.
 dialog.clearundo.title=Undo-Liste löschä
 dialog.undo.none.title=Undo nöd möglich
 dialog.undo.none.text=Keini Operatione könne rückgängig gmacht werde.
 dialog.clearundo.title=Undo-Liste löschä
@@ -157,8 +148,6 @@ dialog.saveexif.photostatus.connected=Verbund
 dialog.saveexif.photostatus.disconnected=Gtrännt
 dialog.saveexif.photostatus.modified=Gänderet
 dialog.saveexif.overwrite=Files Ã¼berschriebä
 dialog.saveexif.photostatus.disconnected=Gtrännt
 dialog.saveexif.photostatus.modified=Gänderet
 dialog.saveexif.overwrite=Files Ã¼berschriebä
-dialog.saveexif.ok1=Es sin
-dialog.saveexif.ok2=Fötelis gschriebe worde
 dialog.correlate.title=Fötelis korrelierä
 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.title=Fötelis korrelierä
 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ä?
@@ -182,8 +171,7 @@ 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.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.correlate.confirmsingle.text=Föteli isch korreliert worde
-dialog.correlate.confirmmultiple.text=Fötelis sin korreliert worde
+dialog.map.title=Prune Karte
 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.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
@@ -198,6 +186,7 @@ dialog.about.systeminfo.java=Version vonem Java
 dialog.about.systeminfo.java3d=Java3d inschtalliert
 dialog.about.systeminfo.povray=Povray inschtalliert
 dialog.about.systeminfo.exiftool=Exiftool inschtalliert
 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.yes=Ja
 dialog.about.no=Nei
 dialog.about.credits=Credits
 dialog.about.yes=Ja
 dialog.about.no=Nei
 dialog.about.credits=Credits
@@ -209,6 +198,7 @@ dialog.about.credits.translations=
 dialog.about.credits.devtools=Entwicklungswärkzüüge
 dialog.about.credits.othertools=Anderi Wärkzüüge
 dialog.about.credits.thanks=Danke an
 dialog.about.credits.devtools=Entwicklungswärkzüüge
 dialog.about.credits.othertools=Anderi Wärkzüüge
 dialog.about.credits.thanks=Danke an
+dialog.about.readme=Läsmi
 
 # 3d window
 dialog.3d.title=Prune Drüü-d Aasicht
 
 # 3d window
 dialog.3d.title=Prune Drüü-d Aasicht
@@ -217,6 +207,28 @@ dialog.3dlines.title=Prune Gitterlinie
 dialog.3dlines.empty=Kei Linie zum aazeigä!
 dialog.3dlines.intro=Hier sin die Linie für die drüü-D Aasicht
 
 dialog.3dlines.empty=Kei Linie zum aazeigä!
 dialog.3dlines.intro=Hier sin die Linie für die drüü-D Aasicht
 
+# Confirm messages || These are displayed as confirmation in the status bar
+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
+confirm.mergetracksegments=Segmänte gmerged
+confirm.reverserange=Spanne umgdrähet
+confirm.saveexif.ok1=Es sin
+confirm.saveexif.ok2=Fötelis gschriebe worde
+confirm.undo.single=Operation rückgängig gmacht worde.
+confirm.undo.multi=Operatione rückgängig gmacht worde.
+confirm.jpegload.single=Föteli isch glade worde
+confirm.jpegload.multi=Fötelis sin glade worde
+confirm.photo.connect=Föteli verbundä
+confirm.photo.disconnect=Föteli gtrännt
+confirm.correlate.single=Föteli isch korreliert worde
+confirm.correlate.multi=Fötelis sin korreliert worde
+
 # Buttons
 button.ok=OK
 button.back=Zrugg
 # Buttons
 button.ok=OK
 button.back=Zrugg
@@ -252,6 +264,7 @@ details.pointdetails=Details vom Punkt
 details.index.selected=Index
 details.index.of=vo
 details.nopointselection=Nüüt selektiert
 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 vo dr Spanne
 details.photofile=Föteli Datei
 details.norangeselection=Nüüt selektiert
 details.rangedetails=Details vo dr Spanne
@@ -266,6 +279,7 @@ display.range.time.secs=S
 display.range.time.mins=M
 display.range.time.hours=Std
 display.range.time.days=T
 display.range.time.mins=M
 display.range.time.hours=Std
 display.range.time.days=T
+details.range.avespeed=Gschwindikeit
 details.waypointsphotos.waypoints=Waypoints
 details.waypointsphotos.photos=Fötelis
 details.photodetails=Details vom Föteli
 details.waypointsphotos.waypoints=Waypoints
 details.waypointsphotos.photos=Fötelis
 details.photodetails=Details vom Föteli
@@ -295,13 +309,18 @@ units.feet=Fuess
 units.feet.short=F
 units.kilometres=Kilometer
 units.kilometres.short=Km
 units.feet.short=F
 units.kilometres=Kilometer
 units.kilometres.short=Km
+units.kmh=Km/h
 units.miles=Meile
 units.miles.short=Mei
 units.miles=Meile
 units.miles.short=Mei
+units.mph=Mei/Std
 units.degminsec=Grad-Min-Sek
 units.degmin=Grad-Min
 units.deg=Grad
 units.iso8601=ISO 8601
 
 units.degminsec=Grad-Min-Sek
 units.degmin=Grad-Min
 units.deg=Grad
 units.iso8601=ISO 8601
 
+# External urls
+url.googlemaps=maps.google.ch
+
 # Cardinals for 3d plots
 cardinal.n=N
 cardinal.s=S
 # Cardinals for 3d plots
 cardinal.n=N
 cardinal.s=S
@@ -319,6 +338,7 @@ undo.compress=Track komprimier
 undo.insert=Punkte innätuä
 undo.deleteduplicates=Duplikaten löschä
 undo.reverse=Spanne umdrähie
 undo.insert=Punkte innätuä
 undo.deleteduplicates=Duplikaten löschä
 undo.reverse=Spanne umdrähie
+undo.mergetracksegments=track segmänte merge
 undo.rearrangewaypoints=Waypoints reorganisierä
 undo.connectphoto=Föteli verbindä
 undo.disconnectphoto=Föteli trännä
 undo.rearrangewaypoints=Waypoints reorganisierä
 undo.connectphoto=Föteli verbindä
 undo.disconnectphoto=Föteli trännä
@@ -347,6 +367,9 @@ error.function.noop.title=Funktion h
 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.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 odr Blackdown.org erhältlech.
+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.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
+error.osmimage.failed=Map Bildli könne nöd glade werde.  Gits ne Internet Verbindig?
index f6746c713f5eabd48d1b2f332461eb1ecb5ae452..191260380543916965c17ac61f15ab4cc255d018 100644 (file)
@@ -21,6 +21,7 @@ menu.edit.deleteduplicates=Eliminar duplicados
 menu.edit.compress=Comprimir track
 menu.edit.interpolate=Interpolar
 menu.edit.reverse=Invertir rango
 menu.edit.compress=Comprimir track
 menu.edit.interpolate=Interpolar
 menu.edit.reverse=Invertir rango
+menu.edit.mergetracksegments=Unir los segmentos de track
 menu.edit.rearrange=Reorganizar waypoints
 menu.edit.rearrange.start=Volver al comienzo
 menu.edit.rearrange.end=Ir al final
 menu.edit.rearrange=Reorganizar waypoints
 menu.edit.rearrange.start=Volver al comienzo
 menu.edit.rearrange.end=Ir al final
@@ -36,8 +37,12 @@ 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.photo.disconnect=Desconectar de punto
 menu.photo.correlate=Correlacionar todas las fotos
 menu.photo.delete=Eliminar foto
-menu.3d=3-D
-menu.3d.show3d=Mostrar en 3-D
+menu.view=Ver
+menu.view.show3d=Mostrar en 3-D
+menu.view.showmap=Mostrar el mapa
+menu.view.browser=Mapa en un navegador
+menu.view.browser.google=Google maps
+menu.view.browser.openstreetmap=Openstreetmap
 menu.help=Ayuda
 menu.help.about=Acerca de Prune
 # Popup menu for map
 menu.help=Ayuda
 menu.help.about=Acerca de Prune
 # Popup menu for map
@@ -57,14 +62,9 @@ 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.deletephoto.title=Borrar foto
 dialog.deletephoto.deletepoint=Borrar el punto tambien?
 dialog.deleteduplicates.title=Borrar duplicados
-dialog.deleteduplicates.single.text=duplicado eliminado
-dialog.deleteduplicates.multi.text=duplicados eliminados
 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.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.text=Track comprimido
-dialog.compresstrack.single.text=punto eliminado
-dialog.compresstrack.multi.text=puntos eliminados
 dialog.compresstrack.nonefound=Ningún punto eliminado
 dialog.openoptions.title=Opciones de abrir
 dialog.openoptions.filesnippet=Extraer archivo
 dialog.compresstrack.nonefound=Ningún punto eliminado
 dialog.openoptions.title=Opciones de abrir
 dialog.openoptions.filesnippet=Extraer archivo
@@ -86,9 +86,6 @@ dialog.jpegload.subdirectories=Incluir subdirectorios
 dialog.jpegload.loadjpegswithoutcoords=Fotos sin coordenadas tambien
 dialog.jpegload.progress.title=Cargando fotos
 dialog.jpegload.progress=Por favor espere mientras se buscan las fotos
 dialog.jpegload.loadjpegswithoutcoords=Fotos sin coordenadas tambien
 dialog.jpegload.progress.title=Cargando fotos
 dialog.jpegload.progress=Por favor espere mientras se buscan las fotos
-dialog.jpegload.title=Fotos cargadas
-dialog.jpegload.photoadded=Foto incluida
-dialog.jpegload.photosadded=Fotos incluidas
 dialog.saveoptions.title=Guardar archivo
 dialog.save.fieldstosave=Campos a guardar
 dialog.save.table.field=Campo
 dialog.saveoptions.title=Guardar archivo
 dialog.save.fieldstosave=Campos a guardar
 dialog.save.table.field=Campo
@@ -98,9 +95,6 @@ dialog.save.headerrow=T
 dialog.save.coordinateunits=Unidades de las coordenadas
 dialog.save.altitudeunits=Unidades de las altitudes
 dialog.save.timestampformat=Format del tiempo
 dialog.save.coordinateunits=Unidades de las coordenadas
 dialog.save.altitudeunits=Unidades de las altitudes
 dialog.save.timestampformat=Format del tiempo
-dialog.save.oktitle=Guardando archivo
-dialog.save.ok1=Guardando
-dialog.save.ok2=puntos al archivo
 dialog.save.overwrite.title=El archivo ya existe
 dialog.save.overwrite.text=El archivo ya existe, desea sobreescribirlo?
 dialog.exportkml.title=Exportar KML
 dialog.save.overwrite.title=El archivo ya existe
 dialog.save.overwrite.text=El archivo ya existe, desea sobreescribirlo?
 dialog.exportkml.title=Exportar KML
@@ -127,9 +121,6 @@ dialog.interpolate.title=Interpolar puntos
 dialog.interpolate.parameter.text=Número de los puntos a insertar entre los puntos elegidos
 dialog.undo.title=Deshacer
 dialog.undo.pretext=Por favor, seleccione la operación(es) a deshacer
 dialog.interpolate.parameter.text=Número de los puntos a insertar entre los puntos elegidos
 dialog.undo.title=Deshacer
 dialog.undo.pretext=Por favor, seleccione la operación(es) a deshacer
-dialog.confirmundo.title=Operación(es) no realizada(s)
-dialog.confirmundo.single.text=operación no realizada
-dialog.confirmundo.multiple.text=operación(es) no realizada(s)
 dialog.undo.none.title=No se puede deshacer
 dialog.undo.none.text=Ninguna operación a deshacer
 dialog.clearundo.title=Despejar la lista de deshacer
 dialog.undo.none.title=No se puede deshacer
 dialog.undo.none.text=Ninguna operación a deshacer
 dialog.clearundo.title=Despejar la lista de deshacer
@@ -157,8 +148,6 @@ dialog.saveexif.photostatus.connected=Conectada
 dialog.saveexif.photostatus.disconnected=Desconectada
 dialog.saveexif.photostatus.modified=Modificada
 dialog.saveexif.overwrite=Sobreescribirlar archivos?
 dialog.saveexif.photostatus.disconnected=Desconectada
 dialog.saveexif.photostatus.modified=Modificada
 dialog.saveexif.overwrite=Sobreescribirlar archivos?
-dialog.saveexif.ok1=Guardando
-dialog.saveexif.ok2=fotos
 dialog.correlate.title=Correlacionar fotos
 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.title=Correlacionar fotos
 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?
@@ -182,8 +171,7 @@ 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.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.correlate.confirmsingle.text=foto fue correlada
-dialog.correlate.confirmmultiple.text=fotos fueron correladas
+dialog.map.title=Mapa Prune
 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.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
@@ -198,6 +186,7 @@ dialog.about.systeminfo.java=Java Runtime
 dialog.about.systeminfo.java3d=Java3d instalado
 dialog.about.systeminfo.povray=Povray instalado
 dialog.about.systeminfo.exiftool=Exiftool instalado
 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.yes=Si
 dialog.about.no=No
 dialog.about.credits=Credits
 dialog.about.yes=Si
 dialog.about.no=No
 dialog.about.credits=Credits
@@ -209,6 +198,7 @@ dialog.about.credits.translations=Ayuda en la traducci
 dialog.about.credits.devtools=Herramientas de desarrollo
 dialog.about.credits.othertools=Otras herramientas
 dialog.about.credits.thanks=Gracias a
 dialog.about.credits.devtools=Herramientas de desarrollo
 dialog.about.credits.othertools=Otras herramientas
 dialog.about.credits.thanks=Gracias a
+dialog.about.readme=Readme
 
 # 3d window
 dialog.3d.title=Prune vista 3-D
 
 # 3d window
 dialog.3d.title=Prune vista 3-D
@@ -217,6 +207,28 @@ dialog.3dlines.title=Cuadr
 dialog.3dlines.empty=No hay ninguna cuadrícula!
 dialog.3dlines.intro=Información de la cuadrícula
 
 dialog.3dlines.empty=No hay ninguna cuadrícula!
 dialog.3dlines.intro=Información de la cuadrícula
 
+# Confirm messages || These are displayed as confirmation in the status bar
+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
+confirm.mergetracksegments=Segmentos unidos
+confirm.reverserange=Rango invertido
+confirm.saveexif.ok1=Guardando
+confirm.saveexif.ok2=fotos
+confirm.undo.single=operación no realizada
+confirm.undo.multi=operación(es) no realizada(s)
+confirm.jpegload.single=Foto incluida
+confirm.jpegload.multi=Fotos incluidas
+confirm.photo.connect=Foto conectado
+confirm.photo.disconnect=Foto desconectado
+confirm.correlate.single=foto fue correlada
+confirm.correlate.multi=fotos fueron correladas
+
 # Buttons
 button.ok=Aceptar
 button.back=Anterior
 # Buttons
 button.ok=Aceptar
 button.back=Anterior
@@ -252,6 +264,7 @@ details.pointdetails=Detalles del punto
 details.index.selected=Indice seleccionado
 details.index.of=de
 details.nopointselection=Ningún punto seleccionado
 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
 details.photofile=Archivo de fotos
 details.norangeselection=Ningún rango seleccionado
 details.rangedetails=Detalles del rango
@@ -266,6 +279,7 @@ display.range.time.secs=s
 display.range.time.mins=m
 display.range.time.hours=h
 display.range.time.days=d
 display.range.time.mins=m
 display.range.time.hours=h
 display.range.time.days=d
+details.range.avespeed=Velocidad media
 details.waypointsphotos.waypoints=Waypoints
 details.waypointsphotos.photos=Fotos
 details.photodetails=Detalles del Foto
 details.waypointsphotos.waypoints=Waypoints
 details.waypointsphotos.photos=Fotos
 details.photodetails=Detalles del Foto
@@ -295,13 +309,18 @@ units.feet=Pies
 units.feet.short=ft
 units.kilometres=Kilómetros
 units.kilometres.short=km
 units.feet.short=ft
 units.kilometres=Kilómetros
 units.kilometres.short=km
+units.kmh=km/h
 units.miles=Millas
 units.miles.short=mi
 units.miles=Millas
 units.miles.short=mi
+units.mph=mi/h
 units.degminsec=Gra-min-seg
 units.degmin=Gra-min
 units.deg=Grados
 units.iso8601=ISO 8601
 
 units.degminsec=Gra-min-seg
 units.degmin=Gra-min
 units.deg=Grados
 units.iso8601=ISO 8601
 
+# External urls
+url.googlemaps=maps.google.es
+
 # Cardinals for 3d plots
 cardinal.n=N
 cardinal.s=S
 # Cardinals for 3d plots
 cardinal.n=N
 cardinal.s=S
@@ -319,6 +338,7 @@ undo.compress=comprimir track
 undo.insert=insertar puntos
 undo.deleteduplicates=eliminar duplicados
 undo.reverse=invertir rango
 undo.insert=insertar puntos
 undo.deleteduplicates=eliminar duplicados
 undo.reverse=invertir rango
+undo.mergetracksegments=unir los segmentos de track
 undo.rearrangewaypoints=reordenar waypoints
 undo.connectphoto=conectar foto
 undo.disconnectphoto=desconectar foto
 undo.rearrangewaypoints=reordenar waypoints
 undo.connectphoto=conectar foto
 undo.disconnectphoto=desconectar foto
@@ -347,6 +367,9 @@ error.function.noop.title=La funci
 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.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 o Blackdown.org.
+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.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
+error.osmimage.failed=Imposible cargar el mapa. Por favor, compruebe la conexión a internet.
index adc2853940dcbc919de71be8e3e635a05aa6d505..1906ea7ae6b107df8a73938caebc1dcde3ec7425 100644 (file)
@@ -6,70 +6,70 @@ menu.file=Fichier
 menu.file.open=Ouvrir
 menu.file.addphotos=Ouvrir photos
 menu.file.save=Enregistrer
 menu.file.open=Ouvrir
 menu.file.addphotos=Ouvrir photos
 menu.file.save=Enregistrer
-menu.file.exportkml=Exporter au KML
-menu.file.exportgpx=Exporter au GPX
-menu.file.exportpov=Exporter au POV
+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
 menu.file.exit=Quitter
 menu.edit=Édition
 menu.edit.undo=Annuler
-menu.edit.clearundo=Purger undo liste
-menu.edit.editpoint=Editer point
-menu.edit.editwaypointname=Editer nom du waypoint
-menu.edit.deletepoint=Supprimer du point
-menu.edit.deleterange=Supprimer de range
-menu.edit.deleteduplicates=Supprimer des duplicates
-menu.edit.compress=Compacter track
-menu.edit.interpolate=Interpolate
-menu.edit.reverse=Reverse range
-menu.edit.rearrange=Rearrange waypoints
-menu.edit.rearrange.start=Tous Ã  tête de fichier
-menu.edit.rearrange.end=Tous Ã  pied de fichier
-menu.edit.rearrange.nearest=Chaque Ã  prochain point
+menu.edit.clearundo=Purger la liste d'annulation
+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.interpolate=Interpoler
+menu.edit.reverse=Inverser l'étendue
+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.select=Sélectionner
 menu.select=Sélectionner
-menu.select.all=Tous sélectionner
+menu.select.all=Tout sélectionner
 menu.select.none=Rien sélectionner
 menu.select.none=Rien sélectionner
-menu.select.start=Set range début
-menu.select.end=Set range fin
+menu.select.start=Définir le début de l'étendue
+menu.select.end=Définir la fin de l'étendue
 menu.photo=Photo
 menu.photo=Photo
-menu.photo.saveexif=Enregistrer Ã  Exif
+menu.photo.saveexif=Enregistrer dans les Exif
 menu.photo.connect=Relier au point
 menu.photo.connect=Relier au point
-menu.photo.disconnect=Disconnect from point
-menu.photo.correlate=Corréler tous les photos
-menu.photo.delete=Remove photo
-menu.3d=Trois-D
-menu.3d.show3d=Montrer en Trois-D
+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.showmap=Montrer la carte
+menu.view.browser=Ouvrir la carte dans le navigateur
+menu.view.browser.google=Google maps
+menu.view.browser.openstreetmap=Openstreetmap
 menu.help=Aide
 menu.help.about=À propos de Prune
 # Popup menu for map
 menu.map.zoomin=Zoom avant
 menu.map.zoomout=Zoom arrière
 menu.help=Aide
 menu.help.about=À propos de Prune
 # Popup menu for map
 menu.map.zoomin=Zoom avant
 menu.map.zoomout=Zoom arrière
-menu.map.zoomfull=Zoom to full scale
-menu.map.connect=Connect track points
-menu.map.autopan=Pan automatique
+menu.map.zoomfull=Adapter Ã  la vue
+menu.map.connect=Relier les points de trace
+menu.map.autopan=Déplacement automatique
 
 # Dialogs
 
 # Dialogs
-dialog.exit.confirm.title=Terminer Prune
-dialog.exit.confirm.text=Les données ont Ã©té modifié. Souhaitez-vous terminer Prune sans enregistrement?
-dialog.openappend.title=Append to existing données
-dialog.openappend.text=Append this to the données already loaded?
-dialog.deletepoint.title=Effacer point
-dialog.deletepoint.deletephoto=Effacer photo attached to this point?
-dialog.deletephoto.title=Effacer photo
-dialog.deletephoto.deletepoint=Effacer point attached to this photo?
-dialog.deleteduplicates.title=Effacer duplicates
-dialog.deleteduplicates.single.text=duplicate a Ã©té effacé
-dialog.deleteduplicates.multi.text=duplicates ont Ã©té effacés
-dialog.deleteduplicates.nonefound=No duplicates found
-dialog.compresstrack.title=Comprimer track
-dialog.compresstrack.parameter.text=Parameter for compression (lower number = more compression)
-dialog.compresstrack.text=Track compressed
-dialog.compresstrack.single.text=point a Ã©té effacé
-dialog.compresstrack.multi.text=points ont Ã©té effacés
-dialog.compresstrack.nonefound=Pas de données ont Ã©té effacés
+dialog.exit.confirm.title=Quitter Prune
+dialog.exit.confirm.text=Les données ont Ã©té modifiées. Souhaitez-vous quitter Prune sans 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.title=Ouvrir options
-dialog.openoptions.filesnippet=Extract of fichier
+dialog.openoptions.filesnippet=Extrait de fichier
 dialog.load.table.field=Champ
 dialog.load.table.field=Champ
-dialog.load.table.datatype=Typ des données
+dialog.load.table.datatype=Type de donnée
 dialog.load.table.description=Description
 dialog.delimiter.label=Séparateur de texte
 dialog.delimiter.comma=Virgule ,
 dialog.load.table.description=Description
 dialog.delimiter.label=Séparateur de texte
 dialog.delimiter.comma=Virgule ,
@@ -77,156 +77,168 @@ dialog.delimiter.tab=Tabulation
 dialog.delimiter.space=Espace
 dialog.delimiter.semicolon=Point-virgule ;
 dialog.delimiter.other=Autres
 dialog.delimiter.space=Espace
 dialog.delimiter.semicolon=Point-virgule ;
 dialog.delimiter.other=Autres
-dialog.openoptions.deliminfo.records=records, avec 
-dialog.openoptions.deliminfo.fields=fields
-dialog.openoptions.deliminfo.norecords=Pas de records
-dialog.openoptions.tabledesc=Extract of fichier
-dialog.openoptions.altitudeunits=Unités de altitude
-dialog.jpegload.subdirectories=Subdirectories aussi
-dialog.jpegload.loadjpegswithoutcoords=Photos sans coordonnées aussi
-dialog.jpegload.progress.title=Loading photos
-dialog.jpegload.progress=Please wait while the photos are searched
-dialog.jpegload.title=Loaded photos
-dialog.jpegload.photoadded=photo was added
-dialog.jpegload.photosadded=photos were added
-dialog.saveoptions.title=Save fichier
-dialog.save.fieldstosave=Fields to save
+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.progress.title=Chargement des photos
+dialog.jpegload.progress=Veuillez patienter pendant la recherche des photos
+dialog.saveoptions.title=Enregistrer le fichier
+dialog.save.fieldstosave=Champs Ã  enregistrer
 dialog.save.table.field=Champ
 dialog.save.table.field=Champ
-dialog.save.table.hasdata=A information
+dialog.save.table.hasdata=Possède une information
 dialog.save.table.save=Enregistrer
 dialog.save.table.save=Enregistrer
-dialog.save.headerrow=Output header row
+dialog.save.headerrow=Entêtes
 dialog.save.coordinateunits=Unités des coordonnées
 dialog.save.coordinateunits=Unités des coordonnées
-dialog.save.altitudeunits=Unités de altitude
-dialog.save.timestampformat=Format de timestamp
-dialog.save.oktitle=File saved
-dialog.save.ok1=Successfully saved
-dialog.save.ok2=points to fichier
-dialog.save.overwrite.title=File already exists
-dialog.save.overwrite.text=This fichier already exists. Are you sure you want to overwrite the fichier?
-dialog.exportkml.title=Exporter au KML
-dialog.exportkml.text=Titre pour le data
-dialog.exportkml.altitude=Include altitudes (pour aviation)
-dialog.exportkml.kmz=Comprimer Ã  kmz fichier
-dialog.exportkml.exportimages=Export image thumbnails Ã  kmz
-dialog.exportkml.filetype=Classeur KML, KMZ
-dialog.exportgpx.title=Exporter au GPX
+dialog.save.altitudeunits=Unités d'altitude
+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.exportkml.filetype=Fichiers KML, KMZ
+dialog.exportgpx.title=Exporter en GPX
 dialog.exportgpx.name=Nom
 dialog.exportgpx.name=Nom
-dialog.exportgpx.desc=Légende 
-dialog.exportgpx.filetype=Classeur GPX
-dialog.exportpov.title=Exporter au POV
-dialog.exportpov.text=Please enter the parameters for the POV export
+dialog.exportgpx.desc=Légende
+dialog.exportgpx.filetype=Fichiers GPX
+dialog.exportpov.title=Exporter en POV
+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.font=Police
 dialog.exportpov.camerax=Camera X
 dialog.exportpov.cameray=Camera Y
 dialog.exportpov.cameraz=Camera Z
-dialog.exportpov.filetype=Classeur POV
-dialog.exportpov.warningtracksize=This track has a large number of points, which Java3D might not be able to display.\nAre you sure you want to continue?
-dialog.confirmreversetrack.title=Confirm reversal
-dialog.confirmreversetrack.text=This track contains timestamp information, which will be out of sequence after a reversal.\nAre you sure you want to reverse this section?
-dialog.interpolate.title=Interpolate points
-dialog.interpolate.parameter.text=Number of points to insert between selected points
-dialog.undo.title=Undo action(s)
-dialog.undo.pretext=Please select the action(s) to undo
-dialog.confirmundo.title=Operation(s) undone
-dialog.confirmundo.single.text=operation undone.
-dialog.confirmundo.multiple.text=operations undone.
-dialog.undo.none.title=Cannot undo
-dialog.undo.none.text=No operations to undo!
-dialog.clearundo.title=Clear undo list
-dialog.clearundo.text=Are you sure you want to clear the undo list?\nAll undo information will be lost!
-dialog.pointedit.title=Edit point
-dialog.pointedit.text=Select each field to edit and use the 'Edit' button to change the value
-dialog.pointedit.table.field=Field
-dialog.pointedit.table.value=Value
-dialog.pointedit.table.changed=Changed
-dialog.pointedit.changevalue.text=Enter the new value for this field
-dialog.pointedit.changevalue.title=Edit field
-dialog.pointnameedit.title=Edit waypoint name
-dialog.pointnameedit.name=Waypoint name
+dialog.exportpov.filetype=Fichiers POV
+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.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.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
+dialog.undo.pretext=Sélectionnez les actions Ã  annuler
+dialog.undo.none.title=Annulation impossible
+dialog.undo.none.text=Pas d'opération Ã  annuler !
+dialog.clearundo.title=Purger la liste d'annulation
+dialog.clearundo.text=Etes-vous sûr de vouloir effacer la liste d'annulation ?\nToutes les informations d'annulation seront perdues !
+dialog.pointedit.title=Editer le point
+dialog.pointedit.text=Sélectionner chaque champ Ã  Ã©diter et utiliser le bouton 'Editer' pour changer la valeur
+dialog.pointedit.table.field=Champ
+dialog.pointedit.table.value=Valeur
+dialog.pointedit.table.changed=Changé
+dialog.pointedit.changevalue.text=Entrer la nouvelle valeur pour ce champ
+dialog.pointedit.changevalue.title=Editer le champ
+dialog.pointnameedit.title=Editer le nom de waypoint
+dialog.pointnameedit.name=Nom de waypoint
 dialog.pointnameedit.uppercase=CASSE MAJUSCULES
 dialog.pointnameedit.lowercase=casse minuscules
 dialog.pointnameedit.uppercase=CASSE MAJUSCULES
 dialog.pointnameedit.lowercase=casse minuscules
-dialog.pointnameedit.sentencecase=Casse Sentence
-dialog.saveexif.title=Save Exif
-dialog.saveexif.intro=Select the photos to save using the checkboxes
-dialog.saveexif.nothingtosave=Coordinate data is unchanged, nothing to save
-dialog.saveexif.noexiftool=No exiftool program could be found. Continue?
-dialog.saveexif.table.photoname=Nom de photo
-dialog.saveexif.table.status=Status
+dialog.pointnameedit.sentencecase=Casse Phrase
+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
+dialog.saveexif.noexiftool=Exiftool introuvable. Continuer ?
+dialog.saveexif.table.photoname=Nom de la photo
+dialog.saveexif.table.status=Statut
 dialog.saveexif.table.save=Enregistrer
 dialog.saveexif.table.save=Enregistrer
-dialog.saveexif.photostatus.connected=Connected
-dialog.saveexif.photostatus.disconnected=Disconnected
-dialog.saveexif.photostatus.modified=Modified
-dialog.saveexif.overwrite=Overwrite fichiers
-dialog.saveexif.ok1=Saved
-dialog.saveexif.ok2=photo fichiers
-dialog.correlate.title=Correlate photos
-dialog.correlate.notimestamps=Les points n'ont pas de timestamps, donc ce n'est pas possible de correler.
-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
-dialog.correlate.photoselect.photoname=Nom de photo
-dialog.correlate.photoselect.timediff=Difference de temps
-dialog.correlate.photoselect.photolater=Photo plus tard
-dialog.correlate.options.tip=Tip: By manually correlating at least one photo, the time offset can be calculated for you.
-dialog.correlate.options.intro=Select the options for automatic correlation
-dialog.correlate.options.offsetpanel=Offset de temps
-dialog.correlate.options.offset=Offset
+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.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
+dialog.correlate.photoselect.photoname=Nom de la photo
+dialog.correlate.photoselect.timediff=Différence de temps
+dialog.correlate.photoselect.photolater=Photo prise plus tard
+dialog.correlate.options.tip=Astuce : En corrélant manuellement au moins une photo, le décalage de temps peut Ãªtre calculé pour vous.
+dialog.correlate.options.intro=Sélectionner les options pour la corrélation automatique
+dialog.correlate.options.offsetpanel=Décalage de temps
+dialog.correlate.options.offset=Décalage
 dialog.correlate.options.offset.hours=heures,
 dialog.correlate.options.offset.minutes=minutes et
 dialog.correlate.options.offset.seconds=secondes
 dialog.correlate.options.offset.hours=heures,
 dialog.correlate.options.offset.minutes=minutes et
 dialog.correlate.options.offset.seconds=secondes
-dialog.correlate.options.photolater=Photo later than point
-dialog.correlate.options.pointlater=Point later than photo
-dialog.correlate.options.limitspanel=Correlation limits
-dialog.correlate.options.notimelimit=No time limit
-dialog.correlate.options.timelimit=Time limit
-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.correlate.confirmsingle.text=photo was correlated
-dialog.correlate.confirmmultiple.text=photos were correlated
-dialog.help.help=Consultez la page\n http://activityworkshop.net/software/prune/\npour de plus détails et user guides.
+dialog.correlate.options.photolater=Photo postérieure au point
+dialog.correlate.options.pointlater=Point postérieur Ã  la photo
+dialog.correlate.options.limitspanel=Limites de corrélation
+dialog.correlate.options.notimelimit=Pas de limite de temps
+dialog.correlate.options.timelimit=Limite de temps
+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.map.title=Prune carte
+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.title=À propos de Prune
 dialog.about.version=Version
 dialog.about.build=Build
-dialog.about.summarytext1=Prune est une programme for loading, displaying and editing data from GPS receivers.
-dialog.about.summarytext2=It is released under the Gnu GPL for free, open, worldwide use and enhancement.<br>Copying, redistribution and modification are permitted and encouraged<br>according to the conditions in the included <code>license.txt</code> file.
-dialog.about.summarytext3=Consultez la page <code style="font-weight:bold">http://activityworkshop.net/</code> pour de plus détails et user guides.
-dialog.about.translatedby=Texte en français de activityworkshop.
-dialog.about.systeminfo=Info de Systeme
-dialog.about.systeminfo.os=Operating Systeme
+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.translatedby=Texte en français par Petrovsk.
+dialog.about.systeminfo=Info Système
+dialog.about.systeminfo.os=Système d'exploitation
 dialog.about.systeminfo.java=Java Runtime
 dialog.about.systeminfo.java3d=Java3d installé
 dialog.about.systeminfo.povray=Povray installé
 dialog.about.systeminfo.exiftool=Exiftool installé
 dialog.about.systeminfo.java=Java Runtime
 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.yes=Oui
 dialog.about.no=Non
 dialog.about.credits=Crédits
 dialog.about.yes=Oui
 dialog.about.no=Non
 dialog.about.credits=Crédits
-dialog.about.credits.code=Prune code Ã©crit par
-dialog.about.credits.exifcode=Exif code par
-dialog.about.credits.icons=Some icons taken from
-dialog.about.credits.translators=Interprète
+dialog.about.credits.code=Code de Prune Ã©crit par
+dialog.about.credits.exifcode=Code Exif par
+dialog.about.credits.icons=Quelques icônes provenant de
+dialog.about.credits.translators=Interprètes
 dialog.about.credits.translations=Traduction avec l'aide de
 dialog.about.credits.devtools=Outils de développement
 dialog.about.credits.othertools=Autre outils
 dialog.about.credits.thanks=Merci Ã 
 dialog.about.credits.translations=Traduction avec l'aide de
 dialog.about.credits.devtools=Outils de développement
 dialog.about.credits.othertools=Autre outils
 dialog.about.credits.thanks=Merci Ã 
+dialog.about.readme=Lisez-moi
 
 # 3d window
 
 # 3d window
-dialog.3d.title=Vue Trois-d de Prune
-dialog.3d.altitudecap=Minimum altitude range
-dialog.3dlines.title=Prune gridlines
-dialog.3dlines.empty=No gridlines to display!
-dialog.3dlines.intro=These are the gridlines for the three-d view
+dialog.3d.title=Vue 3D de Prune
+dialog.3d.altitudecap=Etendue d'altitude minimale
+dialog.3dlines.title=Grille de Prune
+dialog.3dlines.empty=Pas de grille Ã  afficher !
+dialog.3dlines.intro=Ceci est la grille pour la vue 3D
+
+# Confirm messages - these are displayed as confirmation in the status bar
+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.saveexif.ok1=Enregistrement de
+confirm.saveexif.ok2=fichiers photo
+confirm.undo.single=opération annulée
+confirm.undo.multi=opérations annulées
+confirm.jpegload.single=la photo a Ã©té ajoutée
+confirm.jpegload.multi=les photos ont Ã©té ajoutées
+confirm.photo.connect=photo reliée
+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
 
 # Buttons
 button.ok=OK
 button.back=Retour
 button.next=Prochain
 
 # Buttons
 button.ok=OK
 button.back=Retour
 button.next=Prochain
-button.finish=Fini
+button.finish=Fin
 button.cancel=Annuler
 button.overwrite=Écraser
 button.cancel=Annuler
 button.overwrite=Écraser
-button.moveup=Move up
-button.movedown=Move down
-button.showlines=Montrer lignes
+button.moveup=Monter
+button.movedown=Descendre
+button.showlines=Montrer les lignes
 button.edit=Éditer
 button.exit=Terminer
 button.close=Fermer
 button.edit=Éditer
 button.exit=Terminer
 button.close=Fermer
@@ -235,73 +247,80 @@ button.yes=Oui
 button.no=Non
 button.yestoall=Oui pour tous
 button.notoall=Non pour tous
 button.no=Non
 button.yestoall=Oui pour tous
 button.notoall=Non pour tous
-button.selectall=Sélecter tous
-button.selectnone=Sélecter rien
-button.preview=Preview
-button.guessfields=Guess fields
+button.selectall=Tout sélectionner
+button.selectnone=Ne rien sélectionner
+button.preview=Aperçu
+button.guessfields=Deviner les champs
 
 # Display components
 
 # Display components
-display.nodata=Pas de data loaded
-display.noaltitudes=Track data does not include altitudes
-details.trackdetails=Détails de track
-details.notrack=Pas de track loaded
+display.nodata=Pas de données chargées
+display.noaltitudes=La trace ne comporte pas d'information d'altitude
+details.trackdetails=Détails de la trace
+details.notrack=Pas de trace chargée
 details.track.points=Points
 details.track.file=Fichier
 details.track.numfiles=Nombre de fichiers
 details.track.points=Points
 details.track.file=Fichier
 details.track.numfiles=Nombre de fichiers
-details.pointdetails=Détails de point
+details.pointdetails=Détails du point
 details.index.selected=Index
 details.index.selected=Index
-details.index.of=de
-details.nopointselection=Pas de point choisis
-details.photofile=Photo fichier
-details.norangeselection=No range choisis
-details.rangedetails=Range details
-details.range.selected=Choisis
+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
+details.range.selected=Sélection des points
 details.range.to=à
 details.altitude.to=à
 details.range.climb=Montée
 details.range.descent=Descente
 details.range.to=à
 details.altitude.to=à
 details.range.climb=Montée
 details.range.descent=Descente
-details.coordformat=Coordinate format
+details.coordformat=Format de coordonnées
 details.distanceunits=Unités de distance
 display.range.time.secs=s
 display.range.time.mins=m
 display.range.time.hours=h
 display.range.time.days=j
 details.distanceunits=Unités de distance
 display.range.time.secs=s
 display.range.time.mins=m
 display.range.time.hours=h
 display.range.time.days=j
+details.range.avespeed=Vitesse moyenne
 details.waypointsphotos.waypoints=Waypoints
 details.waypointsphotos.photos=Photos
 details.waypointsphotos.waypoints=Waypoints
 details.waypointsphotos.photos=Photos
-details.photodetails=Détails de photo
+details.photodetails=Détails de la photo
 details.nophoto=Pas de photo
 details.nophoto=Pas de photo
-details.photo.loading=Charger
-details.photo.connected=Connected
+details.photo.loading=Chargement
+details.photo.connected=Reliée
 
 # Field names
 fieldname.latitude=Latitude
 fieldname.longitude=Longitude
 fieldname.altitude=Altitude
 
 # Field names
 fieldname.latitude=Latitude
 fieldname.longitude=Longitude
 fieldname.altitude=Altitude
-fieldname.timestamp=Timestamp
+fieldname.timestamp=Date et heure
 fieldname.waypointname=Nom
 fieldname.waypointtype=Type
 fieldname.newsegment=Segment
 fieldname.waypointname=Nom
 fieldname.waypointtype=Type
 fieldname.newsegment=Segment
-fieldname.custom=Custom
+fieldname.custom=Personnalisé
 fieldname.prefix=Champ
 fieldname.distance=Distance
 fieldname.duration=Durée
 
 # Measurement units
 units.original=Original
 fieldname.prefix=Champ
 fieldname.distance=Distance
 fieldname.duration=Durée
 
 # Measurement units
 units.original=Original
-units.default=Default
+units.default=Défaut
 units.metres=mètres
 units.metres.short=m
 units.feet=pieds
 units.feet.short=p
 units.kilometres=Kilomètres
 units.kilometres.short=km
 units.metres=mètres
 units.metres.short=m
 units.feet=pieds
 units.feet.short=p
 units.kilometres=Kilomètres
 units.kilometres.short=km
-units.miles=lieues
-units.miles.short=li
+units.kmh=km/h
+units.miles=Miles
+units.miles.short=mi
+units.mph=mi/h
 units.degminsec=Deg-min-sec
 units.degmin=Deg-min
 units.deg=Degrés
 units.iso8601=ISO 8601
 
 units.degminsec=Deg-min-sec
 units.degmin=Deg-min
 units.deg=Degrés
 units.iso8601=ISO 8601
 
+# External urls
+url.googlemaps=maps.google.fr
+
 # Cardinals for 3d plots
 cardinal.n=N
 cardinal.s=S
 # Cardinals for 3d plots
 cardinal.n=N
 cardinal.s=S
@@ -309,44 +328,48 @@ cardinal.e=E
 cardinal.w=O
 
 # Undo operations
 cardinal.w=O
 
 # Undo operations
-undo.load=load data
-undo.loadphotos=load photos
-undo.editpoint=editer point
-undo.deletepoint=delete point
-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.rearrangewaypoints=rearrange waypoints
-undo.connectphoto=connect photo
-undo.disconnectphoto=disconnect photo
-undo.correlate=correlate photos
+undo.load=charger les données
+undo.loadphotos=charger les photos
+undo.editpoint=éditer le point
+undo.deletepoint=effacer le point
+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.rearrangewaypoints=réarranger les waypoints
+undo.connectphoto=relier la photo
+undo.disconnectphoto=détacher la photo
+undo.correlate=corréler les photos
 
 # Error messages
 
 # Error messages
-error.save.dialogtitle=Error saving data
-error.save.nodata=No data to save
-error.save.failed=Failed to save the data to fichier:
-error.saveexif.filenotfound=Failed to find photo fichier
-error.saveexif.cannotoverwrite1=Photo fichier
-error.saveexif.cannotoverwrite2=is read-only and can't be overwritten. Write to copy?
-error.load.dialogtitle=Error loading data
-error.load.noread=Cannot read fichier
-error.load.nopoints=No coordinate information found in the fichier
-error.load.unknownxml=Unrecognised xml format:
-error.load.othererror=Error reading fichier:
-error.jpegload.dialogtitle=Error loading photos
-error.jpegload.nofilesfound=No fichiers found
-error.jpegload.nojpegsfound=No jpeg fichiers found
-error.jpegload.noexiffound=No EXIF information found
-error.jpegload.nogpsfound=No GPS information found
-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=Desoler, 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 or Blackdown.org.
-error.3d.title=Error in 3d display
-error.3d=An error occurred with the 3d display
+error.save.dialogtitle=Erreur Ã  l'enregistrement des données
+error.save.nodata=Pas de données Ã  enregistrer
+error.save.failed=Echec de l'enregistrement des données dans le fichier:
+error.saveexif.filenotfound=Fichier photo introuvable
+error.saveexif.cannotoverwrite1=Le fichier photo
+error.saveexif.cannotoverwrite2=est en lecture seule et ne peut pas Ãªtre Ã©craser. Enregistrer sur une copie ?
+error.load.dialogtitle=Erreur au chargement des données
+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.othererror=Erreur Ã  la lecture du fichier :
+error.jpegload.dialogtitle=Erreur au chargement des photos
+error.jpegload.nofilesfound=Aucun fichier trouvé
+error.jpegload.nojpegsfound=Aucun fichier jpeg trouvé
+error.jpegload.noexiffound=Aucune information EXIF trouvée
+error.jpegload.nogpsfound=Aucune information GPS trouvée
+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
+error.osmimage.failed=Erreur du chargement des portions de cartes. Vérifiez votre connexion internet.
index 752436345851f186e21821748d1044a520535b18..f3d97c39bcf4986f3f78e2135fd69bcc038b7923 100644 (file)
@@ -21,6 +21,7 @@ menu.edit.deleteduplicates=Usu\u0144 duplikaty
 menu.edit.compress=Skompresuj scie\u017Ck\u0119
 menu.edit.interpolate=Interpoluj punkty
 menu.edit.reverse=Odwr\u00F3\u0107 zakres
 menu.edit.compress=Skompresuj scie\u017Ck\u0119
 menu.edit.interpolate=Interpoluj punkty
 menu.edit.reverse=Odwr\u00F3\u0107 zakres
+menu.edit.mergetracksegments=Merge track segments
 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=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
@@ -36,16 +37,20 @@ 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.photo.disconnect=Od\u0142\u0105cz od punktu
 menu.photo.correlate=Skoreluj wszystkie zdj\u0119cia
 menu.photo.delete=Usu\u0144 zdj\u0119cie
-menu.3d=Operacje 3D
-menu.3d.show3d=Poka\u017C model
+menu.view=Widok
+menu.view.show3d=Poka\u017C 3D model
+menu.view.showmap=Show map
+menu.view.browser=Map in browser
+menu.view.browser.google=Google maps
+menu.view.browser.openstreetmap=Openstreetmap
 menu.help=Pomoc
 menu.help.about=Prune - Informacje
 # Popup menu for map
 menu.map.zoomin=Powi\u0119ksz
 menu.map.zoomout=Zmniejsz
 menu.map.zoomfull=Dostosuj powi\u0119kszenie
 menu.help=Pomoc
 menu.help.about=Prune - Informacje
 # Popup menu for map
 menu.map.zoomin=Powi\u0119ksz
 menu.map.zoomout=Zmniejsz
 menu.map.zoomfull=Dostosuj powi\u0119kszenie
-menu.map.connect=Connect track punkty
-menu.map.autopan=Autopan
+menu.map.connect=Po\u0142\u0105czenie track punkty
+menu.map.autopan=Przesuwanie mapy
 
 # Dialogs
 dialog.exit.confirm.title=Zako\u0144cz Prune
 
 # Dialogs
 dialog.exit.confirm.title=Zako\u0144cz Prune
@@ -57,14 +62,9 @@ dialog.deletepoint.deletephoto=Usu\u0144 zdj\u0119cie attached to this punkt?
 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.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.single.text=duplicate was deleted
-dialog.deleteduplicates.multi.text=duplicates were deleted
 dialog.deleteduplicates.nonefound=Brak duplikaty found
 dialog.compresstrack.title=Skompresuj scie\u017Ck\u0119
 dialog.compresstrack.parameter.text=Parameter for compression (lower number = more compression)
 dialog.deleteduplicates.nonefound=Brak duplikaty found
 dialog.compresstrack.title=Skompresuj scie\u017Ck\u0119
 dialog.compresstrack.parameter.text=Parameter for compression (lower number = more compression)
-dialog.compresstrack.text=Track compressed
-dialog.compresstrack.single.text=data punkt was removed
-dialog.compresstrack.multi.text=data punkty were removed
 dialog.compresstrack.nonefound=No data punkty could be removed
 dialog.openoptions.title=Otw\u00F3rz opcje
 dialog.openoptions.filesnippet=Extract of plik
 dialog.compresstrack.nonefound=No data punkty could be removed
 dialog.openoptions.title=Otw\u00F3rz opcje
 dialog.openoptions.filesnippet=Extract of plik
@@ -77,30 +77,24 @@ dialog.delimiter.tab=Tabulator
 dialog.delimiter.space=Spacja
 dialog.delimiter.semicolon=\u015Arednik ;
 dialog.delimiter.other=Inne
 dialog.delimiter.space=Spacja
 dialog.delimiter.semicolon=\u015Arednik ;
 dialog.delimiter.other=Inne
-dialog.openoptions.deliminfo.records=records, with 
+dialog.openoptions.deliminfo.records=records, with
 dialog.openoptions.deliminfo.fields=pola
 dialog.openoptions.deliminfo.norecords=No records
 dialog.openoptions.tabledesc=Extract of plik
 dialog.openoptions.deliminfo.fields=pola
 dialog.openoptions.deliminfo.norecords=No records
 dialog.openoptions.tabledesc=Extract of plik
-dialog.openoptions.altitudeunits=Wysoko\u015B\u0107 units
+dialog.openoptions.altitudeunits=Wysoko\u015B\u0107 jednostki
 dialog.jpegload.subdirectories=Include subdirectories
 dialog.jpegload.subdirectories=Include subdirectories
-dialog.jpegload.loadjpegswithoutcoords=Include zdj\u0119cia without coordinates
+dialog.jpegload.loadjpegswithoutcoords=Include zdj\u0119cia without koordinaty
 dialog.jpegload.progress.title=Loading zdj\u0119cia
 dialog.jpegload.progress=Please wait while the zdj\u0119cia are searched
 dialog.jpegload.progress.title=Loading zdj\u0119cia
 dialog.jpegload.progress=Please wait while the zdj\u0119cia are searched
-dialog.jpegload.title=Loaded zdj\u0119cia
-dialog.jpegload.photoadded=zdj\u0119cie was added
-dialog.jpegload.photosadded=zdj\u0119cia were added
 dialog.saveoptions.title=Zapisz plik
 dialog.save.fieldstosave=Pola to save
 dialog.save.table.field=Pole
 dialog.save.table.hasdata=Has data
 dialog.save.table.save=Zapisz
 dialog.save.headerrow=Output header row
 dialog.saveoptions.title=Zapisz plik
 dialog.save.fieldstosave=Pola to save
 dialog.save.table.field=Pole
 dialog.save.table.hasdata=Has data
 dialog.save.table.save=Zapisz
 dialog.save.headerrow=Output header row
-dialog.save.coordinateunits=Wsp\u00f3\u0142rz\u0119dne units
-dialog.save.altitudeunits=Wysoko\u015B\u0107 units
+dialog.save.coordinateunits=Wsp\u00f3\u0142rz\u0119dne jednostki
+dialog.save.altitudeunits=Wysoko\u015B\u0107 jednostki
 dialog.save.timestampformat=Timestamp format
 dialog.save.timestampformat=Timestamp format
-dialog.save.oktitle=Plik saved
-dialog.save.ok1=Successfully saved
-dialog.save.ok2=punkty to plik
 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.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
@@ -108,18 +102,18 @@ dialog.exportkml.text=Tytu\u0142 for the data
 dialog.exportkml.altitude=Include altitudes (for aviation)
 dialog.exportkml.kmz=Compress to make kmz plik
 dialog.exportkml.exportimages=Eksportuj image thumbnails to kmz
 dialog.exportkml.altitude=Include altitudes (for aviation)
 dialog.exportkml.kmz=Compress to make kmz plik
 dialog.exportkml.exportimages=Eksportuj image thumbnails to kmz
-dialog.exportkml.filetype=KML, KMZ pliki
-dialog.exportgpx.title=Eksportuj GPX
+dialog.exportkml.filetype=Pliki KML, KMZ
+dialog.exportgpx.title=Eksportuj jako GPX
 dialog.exportgpx.name=Nazwa
 dialog.exportgpx.desc=Opis
 dialog.exportgpx.name=Nazwa
 dialog.exportgpx.desc=Opis
-dialog.exportgpx.filetype=GPX pliki
-dialog.exportpov.title=Eksportuj POV
+dialog.exportgpx.filetype=Pliki GPX
+dialog.exportpov.title=Eksportuj jako POV
 dialog.exportpov.text=Please enter the parameters for the POV export
 dialog.exportpov.font=Czcionka
 dialog.exportpov.camerax=Camera X
 dialog.exportpov.cameray=Camera Y
 dialog.exportpov.cameraz=Camera Z
 dialog.exportpov.text=Please enter the parameters for the POV export
 dialog.exportpov.font=Czcionka
 dialog.exportpov.camerax=Camera X
 dialog.exportpov.cameray=Camera Y
 dialog.exportpov.cameraz=Camera Z
-dialog.exportpov.filetype=POV pliki
+dialog.exportpov.filetype=Pliki POV
 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=Confirm reversal
 dialog.confirmreversetrack.text=This track contains timestamp information, which will be out of sequence after a reversal.\nAre you sure you want to reverse this section?
 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=Confirm reversal
 dialog.confirmreversetrack.text=This track contains timestamp information, which will be out of sequence after a reversal.\nAre you sure you want to reverse this section?
@@ -127,9 +121,6 @@ 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=Please select the action(s) to undo
 dialog.interpolate.parameter.text=Number of punkty to insert between selected punkty
 dialog.undo.title=Cofnij action(s)
 dialog.undo.pretext=Please select the action(s) to undo
-dialog.confirmundo.title=Operation(s) undone
-dialog.confirmundo.single.text=operation undone.
-dialog.confirmundo.multiple.text=operations undone.
 dialog.undo.none.title=Cannot undo
 dialog.undo.none.text=No operations to undo!
 dialog.clearundo.title=Wyczy\u015B\u0107 list\u0119 zmian
 dialog.undo.none.title=Cannot undo
 dialog.undo.none.text=No operations to undo!
 dialog.clearundo.title=Wyczy\u015B\u0107 list\u0119 zmian
@@ -155,10 +146,8 @@ dialog.saveexif.table.status=Status
 dialog.saveexif.table.save=Zapisz
 dialog.saveexif.photostatus.connected=Connected
 dialog.saveexif.photostatus.disconnected=Disconnected
 dialog.saveexif.table.save=Zapisz
 dialog.saveexif.photostatus.connected=Connected
 dialog.saveexif.photostatus.disconnected=Disconnected
-dialog.saveexif.photostatus.modified=Modified
+dialog.saveexif.photostatus.modified=Zmodyfikowany
 dialog.saveexif.overwrite=Overwrite pliki
 dialog.saveexif.overwrite=Overwrite pliki
-dialog.saveexif.ok1=Saved
-dialog.saveexif.ok2=zdj\u0119cia 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.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?
@@ -182,15 +171,14 @@ dialog.correlate.options.nodistancelimit=No distance limit
 dialog.correlate.options.distancelimit=Distance limit
 dialog.correlate.options.correlate=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.correlate.options.distancelimit=Distance limit
 dialog.correlate.options.correlate=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.correlate.confirmsingle.text=zdj\u0119cie was correlated
-dialog.correlate.confirmmultiple.text=zdj\u0119cia were correlated
-dialog.help.help=Please see\n http://activityworkshop.net/software/prune/\nfor more information and user guides.
+dialog.map.title=Prune map
+dialog.help.help=Please see\n http://activityworkshop.net/software/prune/\npo wi\u0119cej informacji and user guides.
 dialog.about.title=Prune Informacje
 dialog.about.version=Wersja
 dialog.about.build=Build
 dialog.about.summarytext1=Prune is a program for loading, displaying and editing data from GPS receivers.
 dialog.about.summarytext2=It is released under the Gnu GPL for free, open, worldwide use and enhancement.<br>Copying, redistribution and modification are permitted and encouraged<br>according to the conditions in the included <code>license.txt</code> file.
 dialog.about.title=Prune Informacje
 dialog.about.version=Wersja
 dialog.about.build=Build
 dialog.about.summarytext1=Prune is a program for loading, displaying and editing data from GPS receivers.
 dialog.about.summarytext2=It is released under the Gnu GPL for free, open, worldwide use and enhancement.<br>Copying, redistribution and modification are permitted and encouraged<br>according to the conditions in the included <code>license.txt</code> file.
-dialog.about.summarytext3=Please see <code style="font-weight:bold">http://activityworkshop.net/</code> for more information and user guides.
+dialog.about.summarytext3=Please see <code style="font-weight:bold">http://activityworkshop.net/</code> for more informacji and user guides.
 dialog.about.translatedby=Tekst po polsku by Piotr.
 dialog.about.systeminfo=System info
 dialog.about.systeminfo.os=Operating System
 dialog.about.translatedby=Tekst po polsku by Piotr.
 dialog.about.systeminfo=System info
 dialog.about.systeminfo.os=Operating System
@@ -198,6 +186,7 @@ dialog.about.systeminfo.java=Java Runtime
 dialog.about.systeminfo.java3d=Java3d zainstalowana
 dialog.about.systeminfo.povray=Povray zainstalowana
 dialog.about.systeminfo.exiftool=Exiftool zainstalowana
 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.yes=Tak
 dialog.about.no=Nie
 dialog.about.credits=Credits
 dialog.about.yes=Tak
 dialog.about.no=Nie
 dialog.about.credits=Credits
@@ -209,6 +198,7 @@ dialog.about.credits.translations=T\u0142umaczenie helped by
 dialog.about.credits.devtools=Development tools
 dialog.about.credits.othertools=Other tools
 dialog.about.credits.thanks=Dzi\u0119kuje to
 dialog.about.credits.devtools=Development tools
 dialog.about.credits.othertools=Other tools
 dialog.about.credits.thanks=Dzi\u0119kuje to
+dialog.about.readme=Readme
 
 # 3d window
 dialog.3d.title=Prune tr\u00f3jwymiarowa model
 
 # 3d window
 dialog.3d.title=Prune tr\u00f3jwymiarowa model
@@ -217,59 +207,83 @@ dialog.3dlines.title=Prune gridlines
 dialog.3dlines.empty=No gridlines to display!
 dialog.3dlines.intro=These are the gridlines for the three-d view
 
 dialog.3dlines.empty=No gridlines to display!
 dialog.3dlines.intro=These are the gridlines for the three-d view
 
+# Confirm messages || These are displayed as confirmation in the status bar
+confirm.loadfile=Data loaded from file
+confirm.save.ok1=Successfully saved
+confirm.save.ok2=punkty to plik
+confirm.deleteduplicates.single=duplicate was deleted
+confirm.deleteduplicates.multi=duplicates were deleted
+confirm.deletepoint.single=data punkt was removed
+confirm.deletepoint.multi=data punkty were removed
+confirm.undo.single=operation undone
+confirm.undo.multi=operations undone
+confirm.point.edit=punkt edited
+confirm.mergetracksegments=track segments merged
+confirm.reverserange=Range reversed
+confirm.saveexif.ok1=Saved
+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
+
 # Buttons
 button.ok=OK
 button.back=Poprzedni
 button.next=Nast\u0119pny
 # Buttons
 button.ok=OK
 button.back=Poprzedni
 button.next=Nast\u0119pny
-button.finish=Finish
+button.finish=Koniec
 button.cancel=Anuluj
 button.cancel=Anuluj
-button.overwrite=Overwrite
+button.overwrite=Zapisz Zmiany
 button.moveup=Do g\u00F3ry
 button.moveup=Do g\u00F3ry
-button.movedown=Move down
-button.showlines=Show lines
+button.movedown=Do d\u00F3\u0142
+button.showlines=Poka\u017C linie
 button.edit=Edycja
 button.exit=Zako\u0144cz
 button.close=Zamknij
 button.edit=Edycja
 button.exit=Zako\u0144cz
 button.close=Zamknij
-button.continue=Continue
+button.continue=Kontynuuj
 button.yes=Tak
 button.no=Nie
 button.yes=Tak
 button.no=Nie
-button.yestoall=Tak to all
-button.notoall=Nie to all
-button.selectall=Select all
-button.selectnone=Select none
-button.preview=Preview
+button.yestoall=To wszystko
+button.notoall=Nie wszystko
+button.selectall=Zaznacz wszystko
+button.selectnone=Odznacz
+button.preview=Podgl\u0105d
 button.guessfields=Guess fields
 
 # Display components
 button.guessfields=Guess fields
 
 # Display components
-display.nodata=No data loaded
+display.nodata=Brak za\u0142awadowanych danych
 display.noaltitudes=Track data does not include altitudes
 details.trackdetails=Track szczeg\u00F3\u0142y
 display.noaltitudes=Track data does not include altitudes
 details.trackdetails=Track szczeg\u00F3\u0142y
-details.notrack=No track loaded
+details.notrack=Brak za\u0142awadowanych track
 details.track.points=Punkty
 details.track.file=Plik
 details.track.numfiles=Number ze pliki
 details.pointdetails=Punkt szczeg\u00F3\u0142y
 details.track.points=Punkty
 details.track.file=Plik
 details.track.numfiles=Number ze pliki
 details.pointdetails=Punkt szczeg\u00F3\u0142y
-details.index.selected=Index
-details.index.of=of
-details.nopointselection=No punkt selected
+details.index.selected=Indeks
+details.index.of=z
+details.nopointselection=Brak punkt zaznaczenia
+details.speed=Speed
 details.photofile=Plik zdj\u0119cie
 details.photofile=Plik zdj\u0119cie
-details.norangeselection=No range selected
+details.norangeselection=Brak range zaznaczenia
 details.rangedetails=Range szczeg\u00F3\u0142y
 details.range.selected=Selected
 details.range.to=to
 details.altitude.to=to
 details.range.climb=Climb
 details.range.descent=Descent
 details.rangedetails=Range szczeg\u00F3\u0142y
 details.range.selected=Selected
 details.range.to=to
 details.altitude.to=to
 details.range.climb=Climb
 details.range.descent=Descent
-details.coordformat=Wsp\u00f3\u0142rz\u0119dne format
-details.distanceunits=Distance units
+details.coordformat=Format wsp\u00f3\u0142rz\u0119dne
+details.distanceunits=Jednostki dystansowy
 display.range.time.secs=s
 display.range.time.mins=m
 display.range.time.hours=h
 display.range.time.days=d
 display.range.time.secs=s
 display.range.time.mins=m
 display.range.time.hours=h
 display.range.time.days=d
+details.range.avespeed=Ave speed
 details.waypointsphotos.waypoints=Waypoints
 details.waypointsphotos.photos=Zdj\u0119cia
 details.photodetails=Zdj\u0119cie szczeg\u00F3\u0142y
 details.waypointsphotos.waypoints=Waypoints
 details.waypointsphotos.photos=Zdj\u0119cia
 details.photodetails=Zdj\u0119cie szczeg\u00F3\u0142y
-details.nophoto=No zdj\u0119cie selected
+details.nophoto=Brak zdj\u0119cie zaznaczenia
 details.photo.loading=Wczytywanie
 details.photo.connected=Connected
 
 details.photo.loading=Wczytywanie
 details.photo.connected=Connected
 
@@ -283,25 +297,30 @@ fieldname.waypointtype=Type
 fieldname.newsegment=Segment
 fieldname.custom=U\u017Cytkownika
 fieldname.prefix=Pole
 fieldname.newsegment=Segment
 fieldname.custom=U\u017Cytkownika
 fieldname.prefix=Pole
-fieldname.distance=Distance
+fieldname.distance=Dystansowy
 fieldname.duration=Duration
 
 # Measurement units
 units.original=Oryginalny
 fieldname.duration=Duration
 
 # Measurement units
 units.original=Oryginalny
-units.default=Default
+units.default=Domy\u015Blny
 units.metres=Metres
 units.metres.short=m
 units.feet=Feet
 units.feet.short=ft
 units.kilometres=Kilometres
 units.kilometres.short=km
 units.metres=Metres
 units.metres.short=m
 units.feet=Feet
 units.feet.short=ft
 units.kilometres=Kilometres
 units.kilometres.short=km
+units.kmh=km/h
 units.miles=Miles
 units.miles.short=mi
 units.miles=Miles
 units.miles.short=mi
+units.mph=mi/h
 units.degminsec=Deg-min-sek
 units.degmin=Deg-min
 units.deg=Degrees
 units.iso8601=ISO 8601
 
 units.degminsec=Deg-min-sek
 units.degmin=Deg-min
 units.deg=Degrees
 units.iso8601=ISO 8601
 
+# External urls
+url.googlemaps=maps.google.pl
+
 # Cardinals for 3d plots
 cardinal.n=N
 cardinal.s=S
 # Cardinals for 3d plots
 cardinal.n=N
 cardinal.s=S
@@ -319,6 +338,7 @@ undo.compress=compress track
 undo.insert=insert punkty
 undo.deleteduplicates=usu\u0144 duplicates
 undo.reverse=reverse range
 undo.insert=insert punkty
 undo.deleteduplicates=usu\u0144 duplicates
 undo.reverse=reverse range
+undo.mergetracksegments=merge track segments
 undo.rearrangewaypoints=rearrange waypoints
 undo.connectphoto=connect zdj\u0119cie
 undo.disconnectphoto=disconnect zdj\u0119cie
 undo.rearrangewaypoints=rearrange waypoints
 undo.connectphoto=connect zdj\u0119cie
 undo.disconnectphoto=disconnect zdj\u0119cie
@@ -333,7 +353,7 @@ 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.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 coordinate information found in the 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.load.unknownxml=Nieznany xml format:
 error.load.othererror=B\u0142\u0105d reading plik:
 error.jpegload.dialogtitle=B\u0142\u0105d loading zdj\u0119cia
@@ -341,12 +361,15 @@ 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.jpegload.nojpegsfound=No jpeg pliki found
 error.jpegload.noexiffound=No EXIF information found
 error.jpegload.nogpsfound=No GPS information found
-error.undofailed.title=Undo failed
-error.undofailed.text=Failed to undo operation
-error.function.noop.title=Function had no effect
+error.undofailed.title=Cofnij failed
+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.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 or Blackdown.org.
+error.function.notimplemented=Sorry, this funkcji has not yet been implemented.
+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.3d.title=B\u0142\u0105d in 3d display
 error.3d=A b\u0142\u0105d occurred with the 3d display
+error.readme.notfound=Readme file not found
+error.osmimage.dialogtitle=Error loading map images
+error.osmimage.failed=Failed to load map images. Please check internet connection.
index 032874af74da8ac9dafa5ad7e36f43dbfd71bbb2..7a670968e0e460247ee002c03ce6f48a0be53b4e 100644 (file)
@@ -80,6 +80,12 @@ public abstract class FieldGuesser
                                        fields[f] = Field.TIMESTAMP;
                                        continue;
                                }
                                        fields[f] = Field.TIMESTAMP;
                                        continue;
                                }
+                               // check for tracksegment
+                               if (!checkArrayHasField(fields, Field.NEW_SEGMENT) && fieldLooksLikeSegment(value, isHeader))
+                               {
+                                       fields[f] = Field.NEW_SEGMENT;
+                                       continue;
+                               }
                        }
                }
                // Fill in the rest of the fields using just custom fields
                        }
                }
                // Fill in the rest of the fields using just custom fields
@@ -270,4 +276,26 @@ public abstract class FieldGuesser
                        return stamp.isValid();
                }
        }
                        return stamp.isValid();
                }
        }
+
+       /**
+        * Check whether the given String looks like a track segment field
+        * @param inValue value from file
+        * @param inIsHeader true if this is a header line, false for data
+        * @return true if it could be a track segment
+        */
+       private static boolean fieldLooksLikeSegment(String inValue, boolean inIsHeader)
+       {
+               if (inValue == null || inValue.equals("")) {return false;}
+               if (inIsHeader)
+               {
+                       String upperValue = inValue.toUpperCase();
+                       // This is a header line so look for english or local text
+                       return upperValue.equals("SEGMENT");
+               }
+               else
+               {
+                       // can't reliably identify it just using the value
+                       return false;
+               }
+       }
 }
 }
index 39cd36c4fd6d382850642069a3b588a1e6088bbf..99464f705c44000054cc3b48b92b1cbcb7508c3d 100644 (file)
@@ -106,7 +106,7 @@ public class FileSplitter
         */
        public String[] getFirstFullRow()
        {
         */
        public String[] getFirstFullRow()
        {
-               return _firstFullRow; 
+               return _firstFullRow;
        }
 
 
        }
 
 
index a2453bec57a071d8e7abb4c85c1e4b623c31bf64..cab6c565524bc5a48bcab9b9e4b80b56b36660ed 100644 (file)
@@ -61,11 +61,11 @@ public class JpegLoader implements Runnable
 
 
        /**
 
 
        /**
-        * Select an input file and open the GUI frame
-        * to select load options
+        * Open the GUI to select options and start the load
         */
         */
-       public void openFile()
+       public void openDialog()
        {
        {
+               // TODO: Allow restriction of load area, either to current track or manually-entered range
                if (_fileChooser == null)
                {
                        _fileChooser = new JFileChooser();
                if (_fileChooser == null)
                {
                        _fileChooser = new JFileChooser();
index 977845ae597152002a58eeba164d25c4adf0dede..f0408da1c4eaab15363b1e1bde2c6c3ae184e994 100644 (file)
@@ -427,7 +427,7 @@ public class TextFileLoader
                                {
                                        fields = _delimiterInfos[i].getMaxFields();
                                        _statusLabel.setText("" + numRecords + " " + I18nManager.getText("dialog.openoptions.deliminfo.records")
                                {
                                        fields = _delimiterInfos[i].getMaxFields();
                                        _statusLabel.setText("" + numRecords + " " + I18nManager.getText("dialog.openoptions.deliminfo.records")
-                                               + fields + " " + I18nManager.getText("dialog.openoptions.deliminfo.fields"));
+                                               + " " + fields + " " + I18nManager.getText("dialog.openoptions.deliminfo.fields"));
                                }
                        }
                }
                                }
                        }
                }
index 771621b57f75b98ca1d5229704dda7b63e3a446b..b58ec3127cc63bab9541d465a339afcb448d9841 100644 (file)
@@ -17,6 +17,7 @@ public class GpxHandler extends XmlHandler
        private boolean _insideName = false;
        private boolean _insideElevation = false;
        private boolean _insideTime = false;
        private boolean _insideName = false;
        private boolean _insideElevation = false;
        private boolean _insideTime = false;
+       private boolean _startSegment = true;
        private String _name = null, _latitude = null, _longitude = null;
        private String _elevation = null;
        private String _time = null;
        private String _name = null, _latitude = null, _longitude = null;
        private String _elevation = null;
        private String _time = null;
@@ -57,6 +58,10 @@ public class GpxHandler extends XmlHandler
                {
                        _insideTime = true;
                }
                {
                        _insideTime = true;
                }
+               else if (qName.equalsIgnoreCase("trkseg"))
+               {
+                       _startSegment = true;
+               }
                super.startElement(uri, localName, qName, attributes);
        }
 
                super.startElement(uri, localName, qName, attributes);
        }
 
@@ -122,10 +127,14 @@ public class GpxHandler extends XmlHandler
        private void processPoint()
        {
                // Put the values into a String array matching the order in getFieldArray()
        private void processPoint()
        {
                // Put the values into a String array matching the order in getFieldArray()
-               String[] values = new String[5];
+               String[] values = new String[6];
                values[0] = _latitude; values[1] = _longitude;
                values[2] = _elevation; values[3] = _name;
                values[4] = _time;
                values[0] = _latitude; values[1] = _longitude;
                values[2] = _elevation; values[3] = _name;
                values[4] = _time;
+               if (_startSegment && !_insideWaypoint) {
+                       values[5] = "1";
+                       _startSegment = false;
+               }
                _pointList.add(values);
        }
 
                _pointList.add(values);
        }
 
@@ -136,7 +145,7 @@ public class GpxHandler extends XmlHandler
        public Field[] getFieldArray()
        {
                final Field[] fields = {Field.LATITUDE, Field.LONGITUDE, Field.ALTITUDE,
        public Field[] getFieldArray()
        {
                final Field[] fields = {Field.LATITUDE, Field.LONGITUDE, Field.ALTITUDE,
-                       Field.WAYPT_NAME, Field.TIMESTAMP};
+                       Field.WAYPT_NAME, Field.TIMESTAMP, Field.NEW_SEGMENT};
                return fields;
        }
 
                return fields;
        }
 
index 09706390c03b59506781f11da5570f3f8d051bd9..02c9be7cfe6b69b932f3e5acc3ea62d24e7943eb 100644 (file)
@@ -99,7 +99,9 @@ public class KmlHandler extends XmlHandler
                        // Add each of the unnamed track points to list
                        for (int p=0; p<numPoints; p++)
                        {
                        // Add each of the unnamed track points to list
                        for (int p=0; p<numPoints; p++)
                        {
-                               _pointList.add(makeStringArray(coordArray[p], null));
+                               String[] pointArray = makeStringArray(coordArray[p], null);
+                               if (p==0) {pointArray[4] = "1";}
+                               _pointList.add(pointArray);
                        }
                }
        }
                        }
                }
        }
@@ -113,7 +115,7 @@ public class KmlHandler extends XmlHandler
         */
        private static String[] makeStringArray(String inCoordinates, String inName)
        {
         */
        private static String[] makeStringArray(String inCoordinates, String inName)
        {
-               String[] result = new String[4];
+               String[] result = new String[5];
                String[] values = inCoordinates.split(",");
                if (values.length == 3) {System.arraycopy(values, 0, result, 0, 3);}
                result[3] = inName;
                String[] values = inCoordinates.split(",");
                if (values.length == 3) {System.arraycopy(values, 0, result, 0, 3);}
                result[3] = inName;
@@ -126,7 +128,7 @@ public class KmlHandler extends XmlHandler
         */
        public Field[] getFieldArray()
        {
         */
        public Field[] getFieldArray()
        {
-               final Field[] fields = {Field.LONGITUDE, Field.LATITUDE, Field.ALTITUDE, Field.WAYPT_NAME};
+               final Field[] fields = {Field.LONGITUDE, Field.LATITUDE, Field.ALTITUDE, Field.WAYPT_NAME, Field.NEW_SEGMENT};
                return fields;
        }
 
                return fields;
        }
 
index 94702c4d736b4ef469a4469b26a2c5c53b2375bc..44adc9fd4a6302b5e6c0b28b47d223961527d3b3 100644 (file)
@@ -1,5 +1,5 @@
-Prune version 4.1
-=================
+Prune version 5
+===============
 
 Prune is an application for viewing, editing and managing coordinate data from GPS systems,
 including format conversion and photo correlation.
 
 Prune is an application for viewing, editing and managing coordinate data from GPS systems,
 including format conversion and photo correlation.
@@ -16,7 +16,7 @@ Running
 =======
 
 To run Prune from the jar file, simply call it from a command prompt or shell:
 =======
 
 To run Prune from the jar file, simply call it from a command prompt or shell:
-   java -jar prune_04.1.jar
+   java -jar prune_05.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
 
 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 +24,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:
 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_04.1.jar --lang=DE
+   java -jar prune_05.jar --lang=DE
 
 
 
 
+New with version 5
+==================
+
+The following features were added since version 4.1:
+  - New map window in the View menu, showing points overlaid on OpenStreetMap images
+  - New function to launch a browser showing the area in either Google Maps or OpenStreetMap
+  - Handling of track segments, including loading, saving and exporting, and preservation during edits and undos
+  - New function to merge track segments for the current selection, to make one single segment
+  - Display of current and average speed on details panel
+  - Statusbar showing confirmation of actions
+  - Much improved French texts thanks to generous user input
+
 New with version 4.1
 ====================
 
 New with version 4.1
 ====================
 
index 42f9e4f80cf4c3dee51d6478eaa792ca604af6fa..a5ae40295054d5eace532c3a542c53d99d510f07 100644 (file)
@@ -21,6 +21,7 @@ import javax.swing.JTable;
 
 import tim.prune.ExternalTools;
 import tim.prune.I18nManager;
 
 import tim.prune.ExternalTools;
 import tim.prune.I18nManager;
+import tim.prune.UpdateMessageBroker;
 import tim.prune.data.Altitude;
 import tim.prune.data.Coordinate;
 import tim.prune.data.DataPoint;
 import tim.prune.data.Altitude;
 import tim.prune.data.Coordinate;
 import tim.prune.data.DataPoint;
@@ -244,10 +245,9 @@ public class ExifSaver implements Runnable
                        _progressBar.setValue(i + 1);
                }
                _progressBar.setVisible(false);
                        _progressBar.setValue(i + 1);
                }
                _progressBar.setVisible(false);
-               // Show confirmation dialog
-               JOptionPane.showMessageDialog(_dialog, I18nManager.getText("dialog.saveexif.ok1") + " "
-                       + numSaved + " " + I18nManager.getText("dialog.saveexif.ok2"),
-                       I18nManager.getText("dialog.saveexif.title"), JOptionPane.INFORMATION_MESSAGE);
+               // Show confirmation
+               UpdateMessageBroker.informSubscribers(I18nManager.getText("confirm.saveexif.ok1") + " "
+                       + numSaved + " " + I18nManager.getText("confirm.saveexif.ok2"));
                // close dialog, all finished
                _dialog.dispose();
        }
                // close dialog, all finished
                _dialog.dispose();
        }
index db41a34aee5f581a1cd064e9e873f62d9c6f3dfc..c42a644c4c7cf3562a7e85f78367f6bc25d79f4d 100644 (file)
@@ -33,6 +33,7 @@ import javax.swing.table.TableModel;
 
 import tim.prune.App;
 import tim.prune.I18nManager;
 
 import tim.prune.App;
 import tim.prune.I18nManager;
+import tim.prune.UpdateMessageBroker;
 import tim.prune.data.Altitude;
 import tim.prune.data.Coordinate;
 import tim.prune.data.DataPoint;
 import tim.prune.data.Altitude;
 import tim.prune.data.Coordinate;
 import tim.prune.data.DataPoint;
@@ -490,7 +491,7 @@ public class FileSaver
                                                                }
                                                                else if (field == Field.TIMESTAMP)
                                                                {
                                                                }
                                                                else if (field == Field.TIMESTAMP)
                                                                {
-                                                                       try
+                                                                       if (point.hasTimestamp())
                                                                        {
                                                                                if (timestampFormat == Timestamp.FORMAT_ORIGINAL) {
                                                                                        // output original string
                                                                        {
                                                                                if (timestampFormat == Timestamp.FORMAT_ORIGINAL) {
                                                                                        // output original string
@@ -501,7 +502,6 @@ public class FileSaver
                                                                                        buffer.append(point.getTimestamp().getText(timestampFormat));
                                                                                }
                                                                        }
                                                                                        buffer.append(point.getTimestamp().getText(timestampFormat));
                                                                                }
                                                                        }
-                                                                       catch (NullPointerException npe) {}
                                                                }
                                                                else
                                                                {
                                                                }
                                                                else
                                                                {
@@ -519,10 +519,9 @@ public class FileSaver
                                                writer.write(lineSeparator);
                                        }
                                        // Save successful
                                                writer.write(lineSeparator);
                                        }
                                        // Save successful
-                                       JOptionPane.showMessageDialog(_parentFrame, I18nManager.getText("dialog.save.ok1")
-                                                + " " + numPoints + " " + I18nManager.getText("dialog.save.ok2")
-                                                + " " + saveFile.getAbsolutePath(),
-                                               I18nManager.getText("dialog.save.oktitle"), JOptionPane.INFORMATION_MESSAGE);
+                                       UpdateMessageBroker.informSubscribers(I18nManager.getText("confirm.save.ok1")
+                                                + " " + numPoints + " " + I18nManager.getText("confirm.save.ok2")
+                                                + " " + saveFile.getAbsolutePath());
                                        _app.informDataSaved();
                                }
                                catch (IOException ioe)
                                        _app.informDataSaved();
                                }
                                catch (IOException ioe)
index 98619d1a81dddf0fdef65060a1969f6c582f0c25..0e028d18ddd9abff7bf41125ff8018f997c1afa4 100644 (file)
@@ -25,6 +25,7 @@ import javax.swing.filechooser.FileFilter;
 
 import tim.prune.GpsPruner;
 import tim.prune.I18nManager;
 
 import tim.prune.GpsPruner;
 import tim.prune.I18nManager;
+import tim.prune.UpdateMessageBroker;
 import tim.prune.data.Altitude;
 import tim.prune.data.Coordinate;
 import tim.prune.data.DataPoint;
 import tim.prune.data.Altitude;
 import tim.prune.data.Coordinate;
 import tim.prune.data.DataPoint;
@@ -201,10 +202,10 @@ public class GpxExporter implements Runnable
 
                        // close file
                        writer.close();
 
                        // close file
                        writer.close();
-                       JOptionPane.showMessageDialog(_parentFrame, I18nManager.getText("dialog.save.ok1")
-                                + " " + numPoints + " " + I18nManager.getText("dialog.save.ok2")
-                                + " " + _exportFile.getAbsolutePath(),
-                               I18nManager.getText("dialog.save.oktitle"), JOptionPane.INFORMATION_MESSAGE);
+                       // Show confirmation
+                       UpdateMessageBroker.informSubscribers(I18nManager.getText("confirm.save.ok1")
+                                + " " + numPoints + " " + I18nManager.getText("confirm.save.ok2")
+                                + " " + _exportFile.getAbsolutePath());
                        // export successful so need to close dialog and return
                        _dialog.dispose();
                        return;
                        // export successful so need to close dialog and return
                        _dialog.dispose();
                        return;
@@ -264,7 +265,7 @@ public class GpxExporter implements Runnable
                for (i=0; i<numPoints; i++)
                {
                        point = _track.getPoint(i);
                for (i=0; i<numPoints; i++)
                {
                        point = _track.getPoint(i);
-                       // Make a blob for each waypoint
+                       // Make a wpt element for each waypoint
                        if (point.isWaypoint())
                        {
                                exportWaypoint(point, inWriter);
                        if (point.isWaypoint())
                        {
                                exportWaypoint(point, inWriter);
@@ -274,18 +275,23 @@ public class GpxExporter implements Runnable
                                hasTrackpoints = true;
                        }
                }
                                hasTrackpoints = true;
                        }
                }
-               // Make a line for the track, if there is one
-               // TODO: Look at segments of track, and split into separate track segments in Gpx if necessary
+               // Output the track, if there is one
                if (hasTrackpoints)
                {
                if (hasTrackpoints)
                {
+                       boolean firstPoint = true;
                        inWriter.write("\t<trk><trkseg>\n");
                        // Loop over track points
                        for (i=0; i<numPoints; i++)
                        {
                                point = _track.getPoint(i);
                        inWriter.write("\t<trk><trkseg>\n");
                        // Loop over track points
                        for (i=0; i<numPoints; i++)
                        {
                                point = _track.getPoint(i);
-                               if (!point.isWaypoint())
-                               {
+                               if (point.getSegmentStart() && !firstPoint) {
+                                       inWriter.write("\t</trkseg>\n\t<trkseg>\n");
+                               }
+                               if (!point.isWaypoint()) {
+                                       // restart track segment if necessary
+                                       // export the track point
                                        exportTrackpoint(point, inWriter);
                                        exportTrackpoint(point, inWriter);
+                                       firstPoint = false;
                                }
                        }
                        inWriter.write("\t</trkseg></trk>\n");
                                }
                        }
                        inWriter.write("\t</trkseg></trk>\n");
index c091d0c74ac0f705be6acd1ebd977b6010a0af86..a6a3ee6e55df281c43aef3a8f6884d62655ea313 100644 (file)
@@ -35,6 +35,7 @@ import javax.swing.SwingConstants;
 import javax.swing.filechooser.FileFilter;
 
 import tim.prune.I18nManager;
 import javax.swing.filechooser.FileFilter;
 
 import tim.prune.I18nManager;
+import tim.prune.UpdateMessageBroker;
 import tim.prune.data.Altitude;
 import tim.prune.data.Coordinate;
 import tim.prune.data.DataPoint;
 import tim.prune.data.Altitude;
 import tim.prune.data.Coordinate;
 import tim.prune.data.DataPoint;
@@ -302,10 +303,10 @@ public class KmlExporter implements Runnable
 
                        // close file
                        writer.close();
 
                        // close file
                        writer.close();
-                       JOptionPane.showMessageDialog(_parentFrame, I18nManager.getText("dialog.save.ok1")
-                                + " " + numPoints + " " + I18nManager.getText("dialog.save.ok2")
-                                + " " + _exportFile.getAbsolutePath(),
-                               I18nManager.getText("dialog.save.oktitle"), JOptionPane.INFORMATION_MESSAGE);
+                       // show confirmation
+                       UpdateMessageBroker.informSubscribers(I18nManager.getText("confirm.save.ok1")
+                                + " " + numPoints + " " + I18nManager.getText("confirm.save.ok2")
+                                + " " + _exportFile.getAbsolutePath());
                        // export successful so need to close dialog and return
                        _dialog.dispose();
                        return;
                        // export successful so need to close dialog and return
                        _dialog.dispose();
                        return;
@@ -335,7 +336,6 @@ public class KmlExporter implements Runnable
        private int exportData(OutputStreamWriter inWriter, boolean inExportImages)
        throws IOException
        {
        private int exportData(OutputStreamWriter inWriter, boolean inExportImages)
        throws IOException
        {
-               // TODO: Look at segments of track, and split into separate lines in Kml if necessary
                inWriter.write("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<kml xmlns=\"http://earth.google.com/kml/2.1\">\n<Folder>\n");
                inWriter.write("\t<name>");
                if (_descriptionField != null && _descriptionField.getText() != null && !_descriptionField.getText().equals(""))
                inWriter.write("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<kml xmlns=\"http://earth.google.com/kml/2.1\">\n<Folder>\n");
                inWriter.write("\t<name>");
                if (_descriptionField != null && _descriptionField.getText() != null && !_descriptionField.getText().equals(""))
@@ -383,24 +383,37 @@ public class KmlExporter implements Runnable
                // Make a line for the track, if there is one
                if (hasTrackpoints)
                {
                // Make a line for the track, if there is one
                if (hasTrackpoints)
                {
-                       inWriter.write("\t<Placemark>\n\t\t<name>track</name>\n\t\t<Style>\n\t\t\t<LineStyle>\n"
+                       // Set up strings for start and end of track segment
+                       String trackStart = "\t<Placemark>\n\t\t<name>track</name>\n\t\t<Style>\n\t\t\t<LineStyle>\n"
                                + "\t\t\t\t<color>cc0000cc</color>\n\t\t\t\t<width>4</width>\n\t\t\t</LineStyle>\n"
                                + "\t\t\t<PolyStyle><color>33cc0000</color></PolyStyle>\n"
                                + "\t\t\t\t<color>cc0000cc</color>\n\t\t\t\t<width>4</width>\n\t\t\t</LineStyle>\n"
                                + "\t\t\t<PolyStyle><color>33cc0000</color></PolyStyle>\n"
-                               + "\t\t</Style>\n\t\t<LineString>\n");
+                               + "\t\t</Style>\n\t\t<LineString>\n";
                        if (exportAltitudes) {
                        if (exportAltitudes) {
-                               inWriter.write("\t\t\t<extrude>1</extrude>\n\t\t\t<altitudeMode>absolute</altitudeMode>\n");
+                               trackStart += "\t\t\t<extrude>1</extrude>\n\t\t\t<altitudeMode>absolute</altitudeMode>\n";
                        }
                        }
-                       inWriter.write("\t\t\t<coordinates>");
+                       trackStart += "\t\t\t<coordinates>";
+                       String trackEnd = "\t\t\t</coordinates>\n\t\t</LineString>\n\t</Placemark>";
+
+                       // Start segment
+                       inWriter.write(trackStart);
                        // Loop over track points
                        // Loop over track points
+                       boolean firstTrackpoint = true;
                        for (i=0; i<numPoints; i++)
                        {
                                point = _track.getPoint(i);
                        for (i=0; i<numPoints; i++)
                        {
                                point = _track.getPoint(i);
+                               // start new track segment if necessary
+                               if (point.getSegmentStart() && !firstTrackpoint) {
+                                       inWriter.write(trackEnd);
+                                       inWriter.write(trackStart);
+                               }
                                if (!point.isWaypoint() && point.getPhoto() == null)
                                {
                                        exportTrackpoint(point, inWriter, exportAltitudes);
                                if (!point.isWaypoint() && point.getPhoto() == null)
                                {
                                        exportTrackpoint(point, inWriter, exportAltitudes);
+                                       firstTrackpoint = false;
                                }
                        }
                                }
                        }
-                       inWriter.write("\t\t\t</coordinates>\n\t\t</LineString>\n\t</Placemark>");
+                       // end segment
+                       inWriter.write(trackEnd);
                }
                inWriter.write("</Folder>\n</kml>");
                return numPoints;
                }
                inWriter.write("</Folder>\n</kml>");
                return numPoints;
index aacee115adecd4c95fdaa3b0ef0bcc6d0f803a04..1afa255f1c7bd39852ed50764c0d167de2a033b4 100644 (file)
@@ -22,6 +22,7 @@ import javax.swing.SwingConstants;
 import javax.swing.filechooser.FileFilter;
 
 import tim.prune.I18nManager;
 import javax.swing.filechooser.FileFilter;
 
 import tim.prune.I18nManager;
+import tim.prune.UpdateMessageBroker;
 import tim.prune.data.Track;
 import tim.prune.threedee.LineDialog;
 import tim.prune.threedee.ThreeDModel;
 import tim.prune.data.Track;
 import tim.prune.threedee.LineDialog;
 import tim.prune.threedee.ThreeDModel;
@@ -308,10 +309,9 @@ public class PovExporter
                        writeDataPoints(writer, model, lineSeparator);
 
                        // everything worked
                        writeDataPoints(writer, model, lineSeparator);
 
                        // everything worked
-                       JOptionPane.showMessageDialog(_parentFrame, I18nManager.getText("dialog.save.ok1")
-                                + " " + _track.getNumPoints() + " " + I18nManager.getText("dialog.save.ok2")
-                                + " " + inFile.getAbsolutePath(),
-                               I18nManager.getText("dialog.save.oktitle"), JOptionPane.INFORMATION_MESSAGE);
+                       UpdateMessageBroker.informSubscribers(I18nManager.getText("confirm.save.ok1")
+                                + " " + _track.getNumPoints() + " " + I18nManager.getText("confirm.save.ok2")
+                                + " " + inFile.getAbsolutePath());
                        return true;
                }
                catch (IOException ioe)
                        return true;
                }
                catch (IOException ioe)
index 843054dc90fd3195b01a3733da099feb0a40c58e..50582215aaf82aeb265c52b3cddac6ca5cb7b7b7 100644 (file)
@@ -12,6 +12,7 @@ public class UndoCompress implements UndoOperation
 {\r
        private DataPoint[] _contents = null;\r
        protected int _numPointsDeleted = -1;\r
 {\r
        private DataPoint[] _contents = null;\r
        protected int _numPointsDeleted = -1;\r
+       private boolean[] _segmentStarts = null;\r
 \r
 \r
        /**\r
 \r
 \r
        /**\r
@@ -21,6 +22,11 @@ public class UndoCompress implements UndoOperation
        public UndoCompress(Track inTrack)\r
        {\r
                _contents = inTrack.cloneContents();\r
        public UndoCompress(Track inTrack)\r
        {\r
                _contents = inTrack.cloneContents();\r
+               // Copy boolean segment start flags\r
+               _segmentStarts = new boolean[inTrack.getNumPoints()];\r
+               for (int i=0; i<inTrack.getNumPoints(); i++) {\r
+                       _segmentStarts[i] = inTrack.getPoint(i).getSegmentStart();\r
+               }\r
        }\r
 \r
 \r
        }\r
 \r
 \r
@@ -55,6 +61,13 @@ public class UndoCompress implements UndoOperation
        {\r
                // restore track to previous values\r
                inTrackInfo.getTrack().replaceContents(_contents);\r
        {\r
                // restore track to previous values\r
                inTrackInfo.getTrack().replaceContents(_contents);\r
+               // Copy boolean segment start flags\r
+               Track track = inTrackInfo.getTrack();\r
+               if (_segmentStarts.length != track.getNumPoints())\r
+                       throw new UndoException("Cannot undo compress - track length no longer matches");\r
+               for (int i=0; i<_segmentStarts.length; i++) {\r
+                       track.getPoint(i).setSegmentStart(_segmentStarts[i]);\r
+               }\r
                // clear selection\r
                inTrackInfo.getSelection().clearAll();\r
        }\r
                // clear selection\r
                inTrackInfo.getSelection().clearAll();\r
        }\r
index c5fc2f4ad702d9d2c79dc166dc0d0f18301719cf..3e653ce54216708e906eab8a3373ded5284ffb5f 100644 (file)
@@ -1,6 +1,7 @@
 package tim.prune.undo;\r
 \r
 import tim.prune.I18nManager;\r
 package tim.prune.undo;\r
 \r
 import tim.prune.I18nManager;\r
+import tim.prune.UpdateMessageBroker;\r
 import tim.prune.data.DataPoint;\r
 import tim.prune.data.Photo;\r
 import tim.prune.data.TrackInfo;\r
 import tim.prune.data.DataPoint;\r
 import tim.prune.data.Photo;\r
 import tim.prune.data.TrackInfo;\r
@@ -49,7 +50,7 @@ public class UndoConnectPhoto implements UndoOperation
                        _point.setPhoto(null);\r
                        photo.setDataPoint(null);\r
                        // inform subscribers\r
                        _point.setPhoto(null);\r
                        photo.setDataPoint(null);\r
                        // inform subscribers\r
-                       inTrackInfo.triggerUpdate();\r
+                       UpdateMessageBroker.informSubscribers();\r
                }\r
                else\r
                {\r
                }\r
                else\r
                {\r
index cfc166271131eec1f41f6a79ba3bcfe8dd29a354..b2831f0301ab32c217ec81848074e2f1213facf7 100644 (file)
@@ -1,6 +1,7 @@
 package tim.prune.undo;\r
 \r
 import tim.prune.I18nManager;\r
 package tim.prune.undo;\r
 \r
 import tim.prune.I18nManager;\r
+import tim.prune.UpdateMessageBroker;\r
 import tim.prune.data.DataPoint;\r
 import tim.prune.data.Photo;\r
 import tim.prune.data.TrackInfo;\r
 import tim.prune.data.DataPoint;\r
 import tim.prune.data.Photo;\r
 import tim.prune.data.TrackInfo;\r
@@ -61,7 +62,7 @@ public class UndoDeletePhoto implements UndoOperation
                else\r
                {\r
                        // update needed if not already triggered by track update\r
                else\r
                {\r
                        // update needed if not already triggered by track update\r
-                       inTrackInfo.triggerUpdate();\r
+                       UpdateMessageBroker.informSubscribers();\r
                }\r
                // Ensure that photo is associated with point and vice versa\r
                _photo.setDataPoint(_point);\r
                }\r
                // Ensure that photo is associated with point and vice versa\r
                _photo.setDataPoint(_point);\r
index daab9fd574c89d177737f9adaf2a34636d09e6bf..57abc98814ebef54551fc529f3c49be934d2eca1 100644 (file)
@@ -12,6 +12,7 @@ public class UndoDeletePoint implements UndoOperation
        private int _pointIndex = -1;\r
        private DataPoint _point = null;\r
        private int _photoIndex = -1;\r
        private int _pointIndex = -1;\r
        private DataPoint _point = null;\r
        private int _photoIndex = -1;\r
+       private boolean _segmentStart = false;\r
 \r
 \r
        /**\r
 \r
 \r
        /**\r
@@ -19,12 +20,14 @@ public class UndoDeletePoint implements UndoOperation
         * @param inPointIndex index number of point within track\r
         * @param inPoint data point\r
         * @param inPhotoIndex index number of photo within photo list\r
         * @param inPointIndex index number of point within track\r
         * @param inPoint data point\r
         * @param inPhotoIndex index number of photo within photo list\r
+        * @param inSegmentStart true if following track point starts new segment\r
         */\r
         */\r
-       public UndoDeletePoint(int inPointIndex, DataPoint inPoint, int inPhotoIndex)\r
+       public UndoDeletePoint(int inPointIndex, DataPoint inPoint, int inPhotoIndex, boolean inSegmentStart)\r
        {\r
                _pointIndex = inPointIndex;\r
                _point = inPoint;\r
                _photoIndex = inPhotoIndex;\r
        {\r
                _pointIndex = inPointIndex;\r
                _point = inPoint;\r
                _photoIndex = inPhotoIndex;\r
+               _segmentStart = inSegmentStart;\r
        }\r
 \r
 \r
        }\r
 \r
 \r
@@ -64,5 +67,14 @@ public class UndoDeletePoint implements UndoOperation
                        // Ensure that photo is associated with point\r
                        _point.getPhoto().setDataPoint(_point);\r
                }\r
                        // Ensure that photo is associated with point\r
                        _point.getPhoto().setDataPoint(_point);\r
                }\r
+               // Restore previous status of following track point if necessary\r
+               if (!_segmentStart)\r
+               {\r
+                       // Deletion of point can only set following point to true, so only need to set it back to false\r
+                       DataPoint nextTrackPoint = inTrackInfo.getTrack().getNextTrackPoint(_pointIndex + 1);\r
+                       if (nextTrackPoint != null) {\r
+                               nextTrackPoint.setSegmentStart(false);\r
+                       }\r
+               }\r
        }\r
 }\r
        }\r
 }\r
index 04592aef43de183e7a2908eacf1ec17e9e2f552c..e2a76995ebb478ec868c9e4a8c68b8a9d4fcfed8 100644 (file)
@@ -13,6 +13,8 @@ public class UndoDeleteRange implements UndoOperation
        private int _startIndex = -1;\r
        private DataPoint[] _points = null;\r
        private PhotoList _photoList = null;\r
        private int _startIndex = -1;\r
        private DataPoint[] _points = null;\r
        private PhotoList _photoList = null;\r
+       private DataPoint _nextTrackPoint = null;\r
+       private boolean _segmentStart = false;\r
 \r
 \r
        /**\r
 \r
 \r
        /**\r
@@ -24,6 +26,11 @@ public class UndoDeleteRange implements UndoOperation
                _startIndex = inTrackInfo.getSelection().getStart();\r
                _points = inTrackInfo.cloneSelectedRange();\r
                _photoList = inTrackInfo.getPhotoList().cloneList();\r
                _startIndex = inTrackInfo.getSelection().getStart();\r
                _points = inTrackInfo.cloneSelectedRange();\r
                _photoList = inTrackInfo.getPhotoList().cloneList();\r
+               // Save segment flag of following track point\r
+               _nextTrackPoint = inTrackInfo.getTrack().getNextTrackPoint(_startIndex + _points.length);\r
+               if (_nextTrackPoint != null) {\r
+                       _segmentStart = _nextTrackPoint.getSegmentStart();\r
+               }\r
        }\r
 \r
 \r
        }\r
 \r
 \r
@@ -56,5 +63,9 @@ public class UndoDeleteRange implements UndoOperation
                }\r
                // restore point array into track\r
                inTrackInfo.getTrack().insertRange(_points, _startIndex);\r
                }\r
                // restore point array into track\r
                inTrackInfo.getTrack().insertRange(_points, _startIndex);\r
+               // Restore segment flag of following track point\r
+               if (_nextTrackPoint != null) {\r
+                       _nextTrackPoint.setSegmentStart(_segmentStart);\r
+               }\r
        }\r
 }
\ No newline at end of file
        }\r
 }
\ No newline at end of file
index 6cd27fd0c32c549237336ef5ce15d525dfc019ce..c12f74e20630d2041e862aea5ff2b23472991bab 100644 (file)
@@ -1,6 +1,7 @@
 package tim.prune.undo;\r
 \r
 import tim.prune.I18nManager;\r
 package tim.prune.undo;\r
 \r
 import tim.prune.I18nManager;\r
+import tim.prune.UpdateMessageBroker;\r
 import tim.prune.data.DataPoint;\r
 import tim.prune.data.Photo;\r
 import tim.prune.data.TrackInfo;\r
 import tim.prune.data.DataPoint;\r
 import tim.prune.data.Photo;\r
 import tim.prune.data.TrackInfo;\r
@@ -50,7 +51,7 @@ public class UndoDisconnectPhoto implements UndoOperation
                        _point.setPhoto(_photo);\r
                        _photo.setDataPoint(_point);\r
                        // inform subscribers\r
                        _point.setPhoto(_photo);\r
                        _photo.setDataPoint(_point);\r
                        // inform subscribers\r
-                       inTrackInfo.triggerUpdate();\r
+                       UpdateMessageBroker.informSubscribers();\r
                }\r
                else\r
                {\r
                }\r
                else\r
                {\r
diff --git a/tim/prune/undo/UndoMergeTrackSegments.java b/tim/prune/undo/UndoMergeTrackSegments.java
new file mode 100644 (file)
index 0000000..edd0aef
--- /dev/null
@@ -0,0 +1,75 @@
+package tim.prune.undo;
+
+import tim.prune.I18nManager;
+import tim.prune.UpdateMessageBroker;
+import tim.prune.data.DataPoint;
+import tim.prune.data.Track;
+import tim.prune.data.TrackInfo;
+
+/**
+ * Undo merging of track segments
+ */
+public class UndoMergeTrackSegments implements UndoOperation
+{
+       /** Start index */
+       private int _startIndex;
+       /** array of segment flags */
+       private boolean[] _segmentFlags = null;
+       /** Following point, if any */
+       private DataPoint _nextTrackPoint = null;
+       /** Segment flag of next point */
+       private boolean _nextSegmentFlag = false;
+
+
+       /**
+        * Constructor
+        * @param inTrack track object for copying segment flags
+        * @param inStart start index of section
+        * @param inEnd end index of section
+        */
+       public UndoMergeTrackSegments(Track inTrack, int inStart, int inEnd)
+       {
+               _startIndex = inStart;
+               // Store booleans for all points within selection
+               int numPoints = inEnd - inStart + 1;
+               _segmentFlags = new boolean[numPoints];
+               for (int i=inStart; i<=inEnd; i++) {
+                       _segmentFlags[i-inStart] = inTrack.getPoint(i).getSegmentStart();
+               }
+               // Look for following track point, store flag
+               _nextTrackPoint = inTrack.getNextTrackPoint(inEnd + 1);
+               if (_nextTrackPoint != null) {
+                       _nextSegmentFlag = _nextTrackPoint.getSegmentStart();
+               }
+       }
+
+
+       /**
+        * @return description of operation
+        */
+       public String getDescription()
+       {
+               return I18nManager.getText("undo.mergetracksegments");
+       }
+
+
+       /**
+        * Perform the undo operation on the given Track
+        * @param inTrackInfo TrackInfo object on which to perform the operation
+        */
+       public void performUndo(TrackInfo inTrackInfo) throws UndoException
+       {
+               // Loop through points replacing segment start flags
+               for (int i=0; i<_segmentFlags.length; i++) {
+                       DataPoint point = inTrackInfo.getTrack().getPoint(_startIndex + i);
+                       if (!point.isWaypoint()) {
+                               point.setSegmentStart(_segmentFlags[i]);
+                       }
+               }
+               // Restore segment start flag for following point
+               if (_nextTrackPoint != null) {
+                       _nextTrackPoint.setSegmentStart(_nextSegmentFlag);
+               }
+               UpdateMessageBroker.informSubscribers();
+       }
+}
index 73fe6923a2d834d96851f88c5748d28d52cc6d52..dd4a24e7b0d1f7e67d43d983b905df89906f91d4 100644 (file)
@@ -1,6 +1,8 @@
 package tim.prune.undo;
 
 import tim.prune.I18nManager;
 package tim.prune.undo;
 
 import tim.prune.I18nManager;
+import tim.prune.data.DataPoint;
+import tim.prune.data.Track;
 import tim.prune.data.TrackInfo;
 
 /**
 import tim.prune.data.TrackInfo;
 
 /**
@@ -8,18 +10,39 @@ import tim.prune.data.TrackInfo;
  */
 public class UndoReverseSection implements UndoOperation
 {
  */
 public class UndoReverseSection implements UndoOperation
 {
+       /** Start and end indices of section */
        private int _startIndex, _endIndex;
        private int _startIndex, _endIndex;
+       /** First and last track point in section and next track point after */
+       private DataPoint _firstTrackPoint, _lastTrackPoint, _nextTrackPoint;
+       /** Segment flags for these points */
+       private boolean _firstSegmentFlag, _lastSegmentFlag, _nextSegmentFlag;
 
 
        /**
         * Constructor
 
 
        /**
         * Constructor
+        * @param inTrack track object for copying segment flags
         * @param inStart start index of section
         * @param inEnd end index of section
         */
         * @param inStart start index of section
         * @param inEnd end index of section
         */
-       public UndoReverseSection(int inStart, int inEnd)
+       public UndoReverseSection(Track inTrack, int inStart, int inEnd)
        {
                _startIndex = inStart;
                _endIndex = inEnd;
        {
                _startIndex = inStart;
                _endIndex = inEnd;
+               // Look for first track point in section to be reversed, store flag
+               _firstTrackPoint = inTrack.getNextTrackPoint(inStart);
+               if (_firstTrackPoint != null) {
+                       _firstSegmentFlag = _firstTrackPoint.getSegmentStart();
+               }
+               // Look for last track point in section to be reversed, store flag
+               _lastTrackPoint = inTrack.getPreviousTrackPoint(inEnd);
+               if (_lastTrackPoint != null) {
+                       _lastSegmentFlag = _lastTrackPoint.getSegmentStart();
+               }
+               // Look for following track point, store flag
+               _nextTrackPoint = inTrack.getNextTrackPoint(inEnd + 1);
+               if (_nextTrackPoint != null) {
+                       _nextSegmentFlag = _nextTrackPoint.getSegmentStart();
+               }
        }
 
 
        }
 
 
@@ -42,5 +65,15 @@ public class UndoReverseSection implements UndoOperation
                {
                        throw new UndoException(getDescription());
                }
                {
                        throw new UndoException(getDescription());
                }
+               // Restore segment start flags
+               if (_firstTrackPoint != null) {
+                       _firstTrackPoint.setSegmentStart(_firstSegmentFlag);
+               }
+               if (_lastTrackPoint != null) {
+                       _lastTrackPoint.setSegmentStart(_lastSegmentFlag);
+               }
+               if (_nextTrackPoint != null) {
+                       _nextTrackPoint.setSegmentStart(_nextSegmentFlag);
+               }
        }
 }
        }
 }