]> 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 tim.prune.browser.BrowserLauncher;
+import tim.prune.browser.UrlGenerator;
 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.gui.map.MapWindow;
 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.UndoMergeTrackSegments;
 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 BrowserLauncher _browserLauncher = null;
        private Stack _undoStack = null;
-       private UpdateMessageBroker _broker = null;
        private boolean _reversePointsConfirmed = false;
 
        // Constants
@@ -78,15 +82,13 @@ public class App
        /**
         * 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();
-               _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);
-               _jpegLoader.openFile();
+               _jpegLoader.openDialog();
        }
 
 
@@ -322,6 +324,8 @@ public class App
                        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()
        {
-               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)
                                {
-                                       // 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
-                               UndoOperation undo = new UndoDeleteRange(_trackInfo);
+                               UndoDeleteRange undo = new UndoDeleteRange(_trackInfo);
                                // delete requested photos
                                for (int i=0; i<numToDelete; i++)
                                {
@@ -476,6 +483,9 @@ public class App
                                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)
                                {
-                                       message = "1 " + I18nManager.getText("dialog.deleteduplicates.single.text");
+                                       message = "1 " + I18nManager.getText("confirm.deleteduplicates.single");
                                }
                                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
                        {
+                               // No duplicates found to delete
                                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);
-                       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
                {
@@ -553,7 +561,7 @@ public class App
 
 
        /**
-        * Reverse a section of the track
+        * Reverse the currently selected section of the track
         */
        public void reverseRange()
        {
@@ -567,11 +575,35 @@ public class App
                                 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);
+                               // 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
-               Track loadedTrack = new Track(_broker);
+               Track loadedTrack = new Track();
                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);
                }
-               _broker.informSubscribers();
+               UpdateMessageBroker.informSubscribers();
+               // Update status bar
+               UpdateMessageBroker.informSubscribers(I18nManager.getText("confirm.loadfile") + " '" + inFilename + "'");
                // update menu
                _menuManager.informFileLoaded();
        }
@@ -771,18 +805,14 @@ public class App
                        }
                        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
                        {
-                               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)
-                       _broker.informSubscribers();
+                       UpdateMessageBroker.informSubscribers();
                        // 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);
-                       _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);
-                       _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);
-               // 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();
        }
 
@@ -971,10 +1003,8 @@ public class App
                        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
                }
        }
@@ -1006,6 +1036,7 @@ public class App
        {
                if (_undoStack.isEmpty())
                {
+                       // Nothing to undo
                        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;
-                       _broker.informSubscribers();
+                       UpdateMessageBroker.informSubscribers();
                }
        }
 
@@ -1053,10 +1084,9 @@ public class App
                        {
                                ((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)
                {
@@ -1065,7 +1095,7 @@ public class App
                                I18nManager.getText("error.undofailed.title"),
                                JOptionPane.ERROR_MESSAGE);
                        _undoStack.clear();
-                       _broker.informSubscribers();
+                       UpdateMessageBroker.informSubscribers();
                }
                catch (EmptyStackException empty) {}
        }
@@ -1100,4 +1130,23 @@ public class App
                        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);
 
+       /**
+        * 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()
        {
-               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 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
                {
-                       Runtime.getRuntime().exec("exiftool -v");
+                       Runtime.getRuntime().exec(inCommand);
                        return true;
                }
                catch (IOException ioe)
                {
-                       // exception thrown, exiftool not found
+                       // exception thrown, command not found
                        return false;
                }
        }
index e19cb2108b49161098484e856519011f64728a94..7208eb7e83815b2de02341954cb9df3cdfa5441d 100644 (file)
@@ -1,10 +1,11 @@
 package tim.prune;
 
-import java.awt.BorderLayout;
 import java.awt.event.WindowAdapter;
+import java.awt.BorderLayout;
 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;
@@ -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.StatusBar;
 
 /**
  * Tool to visualize, edit and prune GPS data
@@ -22,9 +24,9 @@ import tim.prune.gui.SelectorDisplay;
  */
 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;
 
 
@@ -83,27 +85,30 @@ public class GpsPruner
        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);
-               broker.addSubscriber(menuManager);
+               UpdateMessageBroker.addSubscriber(menuManager);
                // 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());
-               broker.addSubscriber(leftPanel);
+               UpdateMessageBroker.addSubscriber(leftPanel);
                DetailsDisplay rightPanel = new DetailsDisplay(APP.getTrackInfo());
-               broker.addSubscriber(rightPanel);
+               UpdateMessageBroker.addSubscriber(rightPanel);
                MapChart mapDisp = new MapChart(APP, APP.getTrackInfo());
-               broker.addSubscriber(mapDisp);
+               UpdateMessageBroker.addSubscriber(mapDisp);
                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);
@@ -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(statusBar, BorderLayout.SOUTH);
+
                // 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);
 
+               // 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();
+               // 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
  */
-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
         */
-       public void addSubscriber(DataSubscriber inSub)
+       public static void addSubscriber(DataSubscriber inSub)
        {
                _subscribers[_subscriberNum] = inSub;
                _subscriberNum++;
@@ -36,7 +26,7 @@ public class UpdateMessageBroker
         * Send a message to all subscribers that
         * the data has been updated
         */
-       public void informSubscribers()
+       public static void informSubscribers()
        {
                informSubscribers(DataSubscriber.ALL);
        }
@@ -46,7 +36,7 @@ public class UpdateMessageBroker
         * 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++)
                {
@@ -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());
                        }
-                       if (angDistLimit > 0.0 && correlatePhoto) {
+                       if (angDistLimit > 0.0 && correlatePhoto)
+                       {
                                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;
@@ -613,7 +612,6 @@ public class PhotoCorrelator
                {
                        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;
@@ -621,7 +619,6 @@ public class PhotoCorrelator
                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();
        }
@@ -632,8 +629,7 @@ public class PhotoCorrelator
         */
        public void disableOkButton()
        {
-               if (_okButton != null)
-               {
+               if (_okButton != null) {
                        _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 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);
-               // 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()
@@ -174,6 +181,12 @@ public class DataPoint
                return _waypointName;
        }
 
+       /** @return true if start of new track segment */
+       public boolean getSegmentStart()
+       {
+               return _startOfSegment;
+       }
+
        /**
         * @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;
 
 
+       /** 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
         */
index b26c11ff7bbca551bbc4f6574dc4123259512fc0..cdbe58ecca33035a7a012d5ee5e3be402e422ccc 100644 (file)
@@ -10,7 +10,6 @@ import tim.prune.UpdateMessageBroker;
 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;
@@ -25,12 +24,10 @@ public class Selection
        /**
         * Constructor
         * @param inTrack track object
-        * @param inBroker broker object
         */
-       public Selection(Track inTrack, UpdateMessageBroker inBroker)
+       public Selection(Track inTrack)
        {
                _track = inTrack;
-               _broker = inBroker;
        }
 
 
@@ -304,7 +301,7 @@ public class Selection
                        }
                }
                reset();
-               _broker.informSubscribers();
+               UpdateMessageBroker.informSubscribers();
        }
 
 
@@ -337,7 +334,7 @@ public class Selection
                        }
                }
                reset();
-               _broker.informSubscribers();
+               UpdateMessageBroker.informSubscribers();
        }
 
 
@@ -419,7 +416,6 @@ public class Selection
                return _currentPhotoIndex;
        }
 
-
        /**
         * Check that the selection still makes sense
         * and fire update message to listeners
@@ -450,6 +446,6 @@ public class Selection
                                _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
 {
-       // Broker object
-       UpdateMessageBroker _broker = null;
        // Data points
        private DataPoint[] _dataPoints = null;
        // Scaled x, y values
@@ -33,11 +31,9 @@ public class 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
@@ -79,6 +75,11 @@ public class Track
                        }
                }
                _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;
        }
@@ -89,7 +90,7 @@ public class Track
 
        /**
         * Combine this Track with new data
-        * @param inOtherTrack
+        * @param inOtherTrack other track to combine
         */
        public void combine(Track inOtherTrack)
        {
@@ -106,7 +107,7 @@ public class Track
                // 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;
-                       _broker.informSubscribers();
+                       UpdateMessageBroker.informSubscribers();
                }
        }
 
@@ -146,14 +147,17 @@ public class Track
                if (yscale > wholeScale) wholeScale = yscale;
                double minDist = wholeScale / inResolution;
 
+               // Keep track of segment start flags of the deleted points
+               boolean setSegment = false;
                // Copy selected points
                DataPoint[] newPointArray = new DataPoint[_numPoints];
                int[] pointIndices = new int[_numPoints];
                for (int i=0; i<_numPoints; i++)
                {
+                       DataPoint point = _dataPoints[i];
                        boolean keepPoint = true;
                        // Don't delete waypoints or photo points
-                       if (!_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++)
@@ -167,9 +171,20 @@ public class Track
                        }
                        if (keepPoint)
                        {
-                               newPointArray[numCopied] = _dataPoints[i];
+                               newPointArray[numCopied] = point;
                                pointIndices[numCopied] = i;
                                numCopied++;
+                               // set segment flag if it's the first track point
+                               if (setSegment && !point.isWaypoint())
+                               {
+                                       point.setSegmentStart(true);
+                                       setSegment = false;
+                               }
+                       }
+                       else
+                       {
+                               // point will be removed, so check segment flag
+                               if (point.getSegmentStart()) {setSegment = true;}
                        }
                }
 
@@ -203,7 +218,7 @@ public class Track
                _dataPoints = newPointArray;
                _numPoints = _dataPoints.length;
                _scaled = false;
-               _broker.informSubscribers();
+               UpdateMessageBroker.informSubscribers();
                return numDeleted;
        }
 
@@ -233,6 +248,16 @@ public class Track
                        // 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];
@@ -324,13 +349,45 @@ public class Track
                        _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;
-               _broker.informSubscribers();
+               UpdateMessageBroker.informSubscribers();
                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
@@ -381,7 +438,7 @@ public class Track
                }
                // needs to be scaled again
                _scaled = false;
-               _broker.informSubscribers();
+               UpdateMessageBroker.informSubscribers();
                return true;
        }
 
@@ -439,7 +496,7 @@ public class Track
                _dataPoints = dataCopy;
                // needs to be scaled again to recalc x, y
                _scaled = false;
-               _broker.informSubscribers();
+               UpdateMessageBroker.informSubscribers();
                return true;
        }
 
@@ -481,7 +538,7 @@ public class Track
                }
                // 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 ///////////////////
 
        /**
@@ -824,7 +946,7 @@ public class Track
                _numPoints++;
                // needs to be scaled again
                _scaled = false;
-               _broker.informSubscribers();
+               UpdateMessageBroker.informSubscribers();
                return true;
        }
 
@@ -857,7 +979,7 @@ public class Track
                _numPoints += inPoints.length;
                // needs to be scaled again
                _scaled = false;
-               _broker.informSubscribers();
+               UpdateMessageBroker.informSubscribers();
                return true;
        }
 
@@ -875,7 +997,7 @@ public class Track
                _dataPoints = inContents;
                _numPoints = _dataPoints.length;
                _scaled = false;
-               _broker.informSubscribers();
+               UpdateMessageBroker.informSubscribers();
                return true;
        }
 
@@ -910,7 +1032,7 @@ public class Track
                        // point possibly needs to be scaled again
                        _scaled = false;
                        // trigger listeners
-                       _broker.informSubscribers();
+                       UpdateMessageBroker.informSubscribers();
                        return true;
                }
                return false;
index f8e3c844b8ac86bc46c7c45bf8b78c7bc976f88e..bbbdefb2336d210a35d2336824d271a058557a76 100644 (file)
@@ -10,7 +10,6 @@ import tim.prune.UpdateMessageBroker;
  */
 public class TrackInfo
 {
-       private UpdateMessageBroker _broker = 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
-        * @param inBroker broker object
         */
-       public TrackInfo(Track inTrack, UpdateMessageBroker inBroker)
+       public TrackInfo(Track inTrack)
        {
-               _broker = inBroker;
                _track = inTrack;
-               _selection = new Selection(_track, inBroker);
+               _selection = new Selection(_track);
                _fileInfo = new FileInfo();
                _photoList = new PhotoList();
        }
@@ -198,7 +195,7 @@ public class TrackInfo
                if (_track.deletePoint(_selection.getCurrentPointIndex()))
                {
                        _selection.modifyPointDeleted();
-                       _broker.informSubscribers();
+                       UpdateMessageBroker.informSubscribers();
                        return true;
                }
                return false;
@@ -236,7 +233,7 @@ public class TrackInfo
                        }
                        // update subscribers
                        _selection.modifyPointDeleted();
-                       _broker.informSubscribers();
+                       UpdateMessageBroker.informSubscribers();
                }
                return true;
        }
@@ -252,7 +249,7 @@ public class TrackInfo
                int numDeleted = _track.compress(inResolution);
                if (numDeleted > 0) {
                        _selection.clearAll();
-                       _broker.informSubscribers();
+                       UpdateMessageBroker.informSubscribers();
                }
                return numDeleted;
        }
@@ -267,7 +264,7 @@ public class TrackInfo
                int numDeleted = _track.deleteDuplicates();
                if (numDeleted > 0) {
                        _selection.clearAll();
-                       _broker.informSubscribers();
+                       UpdateMessageBroker.informSubscribers();
                }
                return numDeleted;
        }
@@ -331,13 +328,4 @@ public class TrackInfo
                        _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.Dimension;
 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.io.InputStream;
 
 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.JScrollPane;
 import javax.swing.JTabbedPane;
+import javax.swing.JTextArea;
 
 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("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
@@ -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("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") + " : "),
@@ -179,6 +189,18 @@ public class AboutScreen extends JDialog
                        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));
@@ -227,6 +249,26 @@ public class AboutScreen extends JDialog
                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
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 _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;
+       private JLabel _aveSpeedLabel = 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);
+               _speedLabel = new JLabel("");
+               pointDetailsPanel.add(_speedLabel);
                _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);
+               _aveSpeedLabel = new JLabel("");
+               rangeDetailsPanel.add(_aveSpeedLabel);
                _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(
@@ -203,6 +208,10 @@ public class DetailsDisplay extends GenericDisplay
                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"));
@@ -224,9 +233,27 @@ public class DetailsDisplay extends GenericDisplay
                                        (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());
-                       else
+                       }
+                       else {
                                _timeLabel.setText("");
+                       }
                        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));
-                       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()));
-                       else
+                               _aveSpeedLabel.setText(I18nManager.getText("details.range.avespeed") + ": "
+                                       + roundedNumber(selection.getDistance(distUnits)/selection.getNumSeconds()*3600.0) + " " + speedUnitsStr);
+                       }
+                       else {
                                _durationLabel.setText("");
+                               _aveSpeedLabel.setText("");
+                       }
                        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");
+               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";
        }
 
 
        /**
-        * Build a String to describe a distance
+        * Format a number to a sensible precision
         * @param inDist distance
         * @return formatted String
         */
-       private String buildDistanceString(double inDist)
+       private String roundedNumber(double inDist)
        {
                // 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();
        }
+
+       /**
+        * 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.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;
-       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;
 
@@ -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
-                               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);
                                }
@@ -388,21 +389,11 @@ public class MapChart extends GenericChart implements MouseWheelListener, KeyLis
                                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);
-/*
-               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
        }
-
-       /**
-        * 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.browser.UrlGenerator;
 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 _mergeSegmentsItem = null;
        private JMenu     _rearrangeMenu = null;
-       private JMenuItem _rearrangeStartItem = null;
-       private JMenuItem _rearrangeEndItem = null;
-       private JMenuItem _rearrangeNearestItem = 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;
@@ -275,36 +276,45 @@ public class MenuManager implements DataSubscriber
                });
                _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);
-               _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);
                        }
                });
-               _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);
                        }
                });
-               _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);
                        }
                });
-               _rearrangeNearestItem.setEnabled(true);
-               _rearrangeMenu.add(_rearrangeNearestItem);
+               rearrangeNearestItem.setEnabled(true);
+               _rearrangeMenu.add(rearrangeNearestItem);
                editMenu.add(_rearrangeMenu);
                menubar.add(editMenu);
 
@@ -351,6 +361,49 @@ public class MenuManager implements DataSubscriber
                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"));
@@ -408,19 +461,6 @@ public class MenuManager implements DataSubscriber
                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"));
@@ -534,6 +574,8 @@ public class MenuManager implements DataSubscriber
                _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);
@@ -568,6 +610,15 @@ public class MenuManager implements DataSubscriber
                _deleteRangeItem.setEnabled(hasRange);
                _interpolateItem.setEnabled(hasRange
                        && (_selection.getEnd() - _selection.getStart()) == 1);
+               _mergeSegmentsItem.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());
-                               // System.out.println("width = " + getWidth() + ", " + getParent().getWidth() + " = " + displayWidth);
                                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
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.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
@@ -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.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
@@ -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.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.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
@@ -77,7 +77,7 @@ dialog.delimiter.tab=Tab
 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
@@ -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.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
@@ -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.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
@@ -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.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
@@ -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.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?
@@ -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.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
@@ -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.gpsbabel=Gpsbabel installed
 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.readme=Readme
 
 # 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
 
+# 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
@@ -252,6 +264,7 @@ details.pointdetails=Point details
 details.index.selected=Index
 details.index.of=of
 details.nopointselection=No point selected
+details.speed=Speed
 details.photofile=Photo file
 details.norangeselection=No range selected
 details.rangedetails=Range details
@@ -266,6 +279,7 @@ 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=Photos
 details.photodetails=Photo details
@@ -295,13 +309,18 @@ 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.mph=mph
 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
@@ -319,6 +338,7 @@ undo.compress=compress track
 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
@@ -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.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.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.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.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
@@ -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.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
@@ -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.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.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
@@ -77,7 +77,7 @@ dialog.delimiter.tab=Tab
 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
@@ -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.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
@@ -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.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
@@ -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.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
@@ -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.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?
@@ -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.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
@@ -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.gpsbabel=Gpsbabel installiert
 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.readme=Liesmich
 
 # 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
 
+# 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
@@ -252,6 +264,7 @@ details.pointdetails=Details vom Punkt
 details.index.selected=Index
 details.index.of=von
 details.nopointselection=Nichts selektiert
+details.speed=Geschwindigkeit
 details.photofile=Foto Datei
 details.norangeselection=Nichts selektiert
 details.rangedetails=Details 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
+details.range.avespeed=Geschwindigkeit
 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.kmh=Km/h
 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
 
+# External urls
+url.googlemaps=maps.google.de
+
 # 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.mergetracksegments=Trackteilen verbinden
 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.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.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.mergetracksegments=Track Segmänte merge
 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.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
@@ -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.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.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
@@ -77,7 +77,7 @@ dialog.delimiter.tab=Tab
 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
@@ -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.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
@@ -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.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ä
@@ -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.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ä
@@ -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.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ä?
@@ -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.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
@@ -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.gpsbabel=Gpsbabel inschtalliert
 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.readme=Läsmi
 
 # 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
 
+# 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
@@ -252,6 +264,7 @@ details.pointdetails=Details vom Punkt
 details.index.selected=Index
 details.index.of=vo
 details.nopointselection=Nüüt selektiert
+details.speed=Gschwindikeit
 details.photofile=Föteli Datei
 details.norangeselection=Nüüt selektiert
 details.rangedetails=Details 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
+details.range.avespeed=Gschwindikeit
 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.kmh=Km/h
 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
 
+# External urls
+url.googlemaps=maps.google.ch
+
 # 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.mergetracksegments=track segmänte merge
 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.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.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.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
@@ -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.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
@@ -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.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.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
@@ -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.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
@@ -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.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
@@ -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.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
@@ -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.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?
@@ -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.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
@@ -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.gpsbabel=Gpsbabel instalado
 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.readme=Readme
 
 # 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
 
+# 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
@@ -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.speed=Velocidad
 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
+details.range.avespeed=Velocidad media
 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.kmh=km/h
 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
 
+# External urls
+url.googlemaps=maps.google.es
+
 # 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.mergetracksegments=unir los segmentos de track
 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.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.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.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.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.all=Tous sélectionner
+menu.select.all=Tout 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.saveexif=Enregistrer Ã  Exif
+menu.photo.saveexif=Enregistrer dans les Exif
 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.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
-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.filesnippet=Extract of fichier
+dialog.openoptions.filesnippet=Extrait de fichier
 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 ,
@@ -77,156 +77,168 @@ dialog.delimiter.tab=Tabulation
 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.hasdata=A information
+dialog.save.table.hasdata=Possède une information
 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.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.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.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.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.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.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.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.gpsbabel=Gpsbabel installé
 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.readme=Lisez-moi
 
 # 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
-button.finish=Fini
+button.finish=Fin
 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
@@ -235,73 +247,80 @@ button.yes=Oui
 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.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.pointdetails=Détails de point
+details.pointdetails=Détails du point
 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.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.range.avespeed=Vitesse moyenne
 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.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
-fieldname.timestamp=Timestamp
+fieldname.timestamp=Date et heure
 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
-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.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
 
+# External urls
+url.googlemaps=maps.google.fr
+
 # Cardinals for 3d plots
 cardinal.n=N
 cardinal.s=S
@@ -309,44 +328,48 @@ cardinal.e=E
 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.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.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
@@ -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.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.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
@@ -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.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.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
@@ -77,30 +77,24 @@ dialog.delimiter.tab=Tabulator
 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.altitudeunits=Wysoko\u015B\u0107 units
+dialog.openoptions.altitudeunits=Wysoko\u015B\u0107 jednostki
 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.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.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.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
@@ -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.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.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.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?
@@ -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.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
@@ -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.photostatus.modified=Modified
+dialog.saveexif.photostatus.modified=Zmodyfikowany
 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?
@@ -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.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.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
@@ -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.gpsbabel=Gpsbabel zainstalowana
 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.readme=Readme
 
 # 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
 
+# 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
-button.finish=Finish
+button.finish=Koniec
 button.cancel=Anuluj
-button.overwrite=Overwrite
+button.overwrite=Zapisz Zmiany
 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.continue=Continue
+button.continue=Kontynuuj
 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
-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
-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.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.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.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
+details.range.avespeed=Ave speed
 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
 
@@ -283,25 +297,30 @@ fieldname.waypointtype=Type
 fieldname.newsegment=Segment
 fieldname.custom=U\u017Cytkownika
 fieldname.prefix=Pole
-fieldname.distance=Distance
+fieldname.distance=Dystansowy
 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.kmh=km/h
 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
 
+# External urls
+url.googlemaps=maps.google.pl
+
 # 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.mergetracksegments=merge track segments
 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.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
@@ -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.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.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.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;
                                }
+                               // 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
@@ -270,4 +276,26 @@ public abstract class FieldGuesser
                        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()
        {
-               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();
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 + " " + 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 _startSegment = true;
        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;
                }
+               else if (qName.equalsIgnoreCase("trkseg"))
+               {
+                       _startSegment = true;
+               }
                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()
-               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;
+               if (_startSegment && !_insideWaypoint) {
+                       values[5] = "1";
+                       _startSegment = false;
+               }
                _pointList.add(values);
        }
 
@@ -136,7 +145,7 @@ public class GpxHandler extends XmlHandler
        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;
        }
 
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++)
                        {
-                               _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)
        {
-               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;
@@ -126,7 +128,7 @@ public class KmlHandler extends XmlHandler
         */
        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;
        }
 
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.
@@ -16,7 +16,7 @@ Running
 =======
 
 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
@@ -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:
-   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
 ====================
 
index 42f9e4f80cf4c3dee51d6478eaa792ca604af6fa..a5ae40295054d5eace532c3a542c53d99d510f07 100644 (file)
@@ -21,6 +21,7 @@ import javax.swing.JTable;
 
 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;
@@ -244,10 +245,9 @@ public class ExifSaver implements Runnable
                        _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();
        }
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.UpdateMessageBroker;
 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)
                                                                {
-                                                                       try
+                                                                       if (point.hasTimestamp())
                                                                        {
                                                                                if (timestampFormat == Timestamp.FORMAT_ORIGINAL) {
                                                                                        // output original string
@@ -501,7 +502,6 @@ public class FileSaver
                                                                                        buffer.append(point.getTimestamp().getText(timestampFormat));
                                                                                }
                                                                        }
-                                                                       catch (NullPointerException npe) {}
                                                                }
                                                                else
                                                                {
@@ -519,10 +519,9 @@ public class FileSaver
                                                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)
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.UpdateMessageBroker;
 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();
-                       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;
@@ -264,7 +265,7 @@ public class GpxExporter implements Runnable
                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);
@@ -274,18 +275,23 @@ public class GpxExporter implements Runnable
                                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)
                {
+                       boolean firstPoint = true;
                        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);
+                                       firstPoint = false;
                                }
                        }
                        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 tim.prune.UpdateMessageBroker;
 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();
-                       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;
@@ -335,7 +336,6 @@ public class KmlExporter implements Runnable
        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(""))
@@ -383,24 +383,37 @@ public class KmlExporter implements Runnable
                // 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</Style>\n\t\t<LineString>\n");
+                               + "\t\t</Style>\n\t\t<LineString>\n";
                        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
+                       boolean firstTrackpoint = true;
                        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);
+                                       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;
index aacee115adecd4c95fdaa3b0ef0bcc6d0f803a04..1afa255f1c7bd39852ed50764c0d167de2a033b4 100644 (file)
@@ -22,6 +22,7 @@ import javax.swing.SwingConstants;
 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;
@@ -308,10 +309,9 @@ public class PovExporter
                        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)
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
+       private boolean[] _segmentStarts = null;\r
 \r
 \r
        /**\r
@@ -21,6 +22,11 @@ public class UndoCompress implements UndoOperation
        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
@@ -55,6 +61,13 @@ public class UndoCompress implements UndoOperation
        {\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
index c5fc2f4ad702d9d2c79dc166dc0d0f18301719cf..3e653ce54216708e906eab8a3373ded5284ffb5f 100644 (file)
@@ -1,6 +1,7 @@
 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
@@ -49,7 +50,7 @@ public class UndoConnectPhoto implements UndoOperation
                        _point.setPhoto(null);\r
                        photo.setDataPoint(null);\r
                        // inform subscribers\r
-                       inTrackInfo.triggerUpdate();\r
+                       UpdateMessageBroker.informSubscribers();\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
+import tim.prune.UpdateMessageBroker;\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
-                       inTrackInfo.triggerUpdate();\r
+                       UpdateMessageBroker.informSubscribers();\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 boolean _segmentStart = false;\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 inSegmentStart true if following track point starts new segment\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
+               _segmentStart = inSegmentStart;\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
+               // 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
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 DataPoint _nextTrackPoint = null;\r
+       private boolean _segmentStart = false;\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
+               // 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
@@ -56,5 +63,9 @@ public class UndoDeleteRange implements UndoOperation
                }\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
index 6cd27fd0c32c549237336ef5ce15d525dfc019ce..c12f74e20630d2041e862aea5ff2b23472991bab 100644 (file)
@@ -1,6 +1,7 @@
 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
@@ -50,7 +51,7 @@ public class UndoDisconnectPhoto implements UndoOperation
                        _point.setPhoto(_photo);\r
                        _photo.setDataPoint(_point);\r
                        // inform subscribers\r
-                       inTrackInfo.triggerUpdate();\r
+                       UpdateMessageBroker.informSubscribers();\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;
+import tim.prune.data.DataPoint;
+import tim.prune.data.Track;
 import tim.prune.data.TrackInfo;
 
 /**
@@ -8,18 +10,39 @@ import tim.prune.data.TrackInfo;
  */
 public class UndoReverseSection implements UndoOperation
 {
+       /** Start and end indices of section */
        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
+        * @param inTrack track object for copying segment flags
         * @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;
+               // 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());
                }
+               // Restore segment start flags
+               if (_firstTrackPoint != null) {
+                       _firstTrackPoint.setSegmentStart(_firstSegmentFlag);
+               }
+               if (_lastTrackPoint != null) {
+                       _lastTrackPoint.setSegmentStart(_lastSegmentFlag);
+               }
+               if (_nextTrackPoint != null) {
+                       _nextTrackPoint.setSegmentStart(_nextSegmentFlag);
+               }
        }
 }