import javax.swing.JFrame;
import javax.swing.JOptionPane;
+import tim.prune.browser.BrowserLauncher;
+import tim.prune.browser.UrlGenerator;
import tim.prune.correlate.PhotoCorrelator;
import tim.prune.correlate.PointPair;
import tim.prune.data.DataPoint;
import tim.prune.edit.PointNameEditor;
import tim.prune.gui.MenuManager;
import tim.prune.gui.UndoManager;
+import tim.prune.gui.map.MapWindow;
import tim.prune.load.FileLoader;
import tim.prune.load.JpegLoader;
import tim.prune.save.ExifSaver;
import tim.prune.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;
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
/**
* 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);
}
/**
- * 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();
}
if (_track.editPoint(currentPoint, inEditList))
{
_undoStack.push(undo);
+ // Confirm point edit
+ UpdateMessageBroker.informSubscribers(I18nManager.getText("confirm.point.edit"));
}
}
}
*/
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"));
}
}
}
}
}
// 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++)
{
if (_trackInfo.deleteRange())
{
_undoStack.push(undo);
+ // Confirm
+ UpdateMessageBroker.informSubscribers("" + numToDelete + " "
+ + I18nManager.getText("confirm.deletepoint.multi"));
}
}
}
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);
{
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
{
/**
- * Reverse a section of the track
+ * Reverse the currently selected section of the track
*/
public void reverseRange()
{
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"));
}
}
}
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)
{
_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();
}
}
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();
}
_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"));
}
}
// disconnect
photo.setDataPoint(null);
point.setPhoto(null);
- _broker.informSubscribers(DataSubscriber.SELECTION_CHANGED);
+ UpdateMessageBroker.informSubscribers(DataSubscriber.SELECTION_CHANGED);
+ UpdateMessageBroker.informSubscribers(I18nManager.getText("confirm.photo.disconnect"));
}
}
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();
}
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
}
}
{
if (_undoStack.isEmpty())
{
+ // Nothing to undo
JOptionPane.showMessageDialog(_frame, I18nManager.getText("dialog.undo.none.text"),
I18nManager.getText("dialog.undo.none.title"), JOptionPane.INFORMATION_MESSAGE);
}
_undoStack.clear();
_lastSavePosition = 0;
if (unsaved) _lastSavePosition = -1;
- _broker.informSubscribers();
+ UpdateMessageBroker.informSubscribers();
}
}
{
((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)
{
I18nManager.getText("error.undofailed.title"),
JOptionPane.ERROR_MESSAGE);
_undoStack.clear();
- _broker.informSubscribers();
+ UpdateMessageBroker.informSubscribers();
}
catch (EmptyStackException empty) {}
}
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));
+ }
}
*/
public void dataUpdated(byte inUpdateType);
+ /**
+ * Inform clients that an action has been completed
+ * @param inMessage message describing action
+ */
+ public void actionCompleted(String inMessage);
}
*/
public static boolean isPovrayInstalled()
{
- try
- {
- Runtime.getRuntime().exec("povray");
- return true;
- }
- catch (IOException ioe)
- {
- // exception thrown, povray not found
- return false;
- }
+ return check("povray");
}
* @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;
}
}
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;
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
*/
public class GpsPruner
{
- // Patch to version 4
- public static final String VERSION_NUMBER = "4.1";
- public static final String BUILD_NUMBER = "091";
+ // Final build of version 5
+ public static final String VERSION_NUMBER = "5";
+ public static final String BUILD_NUMBER = "100";
private static App APP = null;
private static 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);
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) {
// 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);
}
}
* 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++;
* Send a message to all subscribers that
* the data has been updated
*/
- public void informSubscribers()
+ public static void informSubscribers()
{
informSubscribers(DataSubscriber.ALL);
}
* 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++)
{
}
}
}
+
+ /**
+ * 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);
+ }
+ }
+ }
}
--- /dev/null
+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);
+ }
+ }
+ }
+}
--- /dev/null
+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();
+ }
+}
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;
{
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;
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();
}
*/
public void disableOkButton()
{
- if (_okButton != null)
- {
+ if (_okButton != null) {
_okButton.setEnabled(false);
}
}
private Timestamp _timestamp = null;
private Photo _photo = null;
private String _waypointName = null;
- // private boolean _startOfSegment = false;
+ private boolean _startOfSegment = false;
/**
_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")));
}
}
}
+ /** @param inFlag true for start of track segment */
+ public void setSegmentStart(boolean inFlag)
+ {
+ setFieldValue(Field.NEW_SEGMENT, inFlag?"1":null);
+ }
/** @return latitude */
public Coordinate getLatitude()
return _waypointName;
}
+ /** @return true if start of new track segment */
+ public boolean getSegmentStart()
+ {
+ return _startOfSegment;
+ }
+
/**
* @return true if point has a waypoint name
*/
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
*/
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;
/**
* Constructor
* @param inTrack track object
- * @param inBroker broker object
*/
- public Selection(Track inTrack, UpdateMessageBroker inBroker)
+ public Selection(Track inTrack)
{
_track = inTrack;
- _broker = inBroker;
}
}
}
reset();
- _broker.informSubscribers();
+ UpdateMessageBroker.informSubscribers();
}
}
}
reset();
- _broker.informSubscribers();
+ UpdateMessageBroker.informSubscribers();
}
return _currentPhotoIndex;
}
-
/**
* Check that the selection still makes sense
* and fire update message to listeners
_currentPoint = _startIndex = _endIndex = -1;
}
}
- _broker.informSubscribers(DataSubscriber.SELECTION_CHANGED);
+ UpdateMessageBroker.informSubscribers(DataSubscriber.SELECTION_CHANGED);
}
}
*/
public class Track
{
- // Broker object
- UpdateMessageBroker _broker = null;
// Data points
private DataPoint[] _dataPoints = null;
// Scaled x, y values
/**
* 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
}
}
_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;
}
/**
* Combine this Track with new data
- * @param inOtherTrack
+ * @param inOtherTrack other track to combine
*/
public void combine(Track inOtherTrack)
{
// needs to be scaled again
_scaled = false;
// inform listeners
- _broker.informSubscribers();
+ UpdateMessageBroker.informSubscribers();
}
_numPoints = inNewSize;
// needs to be scaled again
_scaled = false;
- _broker.informSubscribers();
+ UpdateMessageBroker.informSubscribers();
}
}
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++)
}
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;}
}
}
_dataPoints = newPointArray;
_numPoints = _dataPoints.length;
_scaled = false;
- _broker.informSubscribers();
+ UpdateMessageBroker.informSubscribers();
return numDeleted;
}
// 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];
_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
}
// needs to be scaled again
_scaled = false;
- _broker.informSubscribers();
+ UpdateMessageBroker.informSubscribers();
return true;
}
_dataPoints = dataCopy;
// needs to be scaled again to recalc x, y
_scaled = false;
- _broker.informSubscribers();
+ UpdateMessageBroker.informSubscribers();
return true;
}
}
// needs to be scaled again to recalc x, y
_scaled = false;
- _broker.informSubscribers();
+ UpdateMessageBroker.informSubscribers();
}
}
+ /**
+ * 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 ///////////////////
/**
_numPoints++;
// needs to be scaled again
_scaled = false;
- _broker.informSubscribers();
+ UpdateMessageBroker.informSubscribers();
return true;
}
_numPoints += inPoints.length;
// needs to be scaled again
_scaled = false;
- _broker.informSubscribers();
+ UpdateMessageBroker.informSubscribers();
return true;
}
_dataPoints = inContents;
_numPoints = _dataPoints.length;
_scaled = false;
- _broker.informSubscribers();
+ UpdateMessageBroker.informSubscribers();
return true;
}
// point possibly needs to be scaled again
_scaled = false;
// trigger listeners
- _broker.informSubscribers();
+ UpdateMessageBroker.informSubscribers();
return true;
}
return false;
*/
public class TrackInfo
{
- private UpdateMessageBroker _broker = null;
private Track _track = null;
private Selection _selection = null;
private FileInfo _fileInfo = null;
/**
* 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();
}
if (_track.deletePoint(_selection.getCurrentPointIndex()))
{
_selection.modifyPointDeleted();
- _broker.informSubscribers();
+ UpdateMessageBroker.informSubscribers();
return true;
}
return false;
}
// update subscribers
_selection.modifyPointDeleted();
- _broker.informSubscribers();
+ UpdateMessageBroker.informSubscribers();
}
return true;
}
int numDeleted = _track.compress(inResolution);
if (numDeleted > 0) {
_selection.clearAll();
- _broker.informSubscribers();
+ UpdateMessageBroker.informSubscribers();
}
return numDeleted;
}
int numDeleted = _track.deleteDuplicates();
if (numDeleted > 0) {
_selection.clearAll();
- _broker.informSubscribers();
+ UpdateMessageBroker.informSubscribers();
}
return numDeleted;
}
_selection.selectPhotoAndPoint(-1, -1);
}
}
-
-
- /**
- * Fire a trigger to all data subscribers
- */
- public void triggerUpdate()
- {
- _broker.informSubscribers();
- }
}
import java.awt.BorderLayout;
import java.awt.Component;
+import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.Font;
import java.awt.GridBagConstraints;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
+import java.io.InputStream;
import javax.swing.BorderFactory;
import javax.swing.BoxLayout;
import javax.swing.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;
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
new JLabel(I18nManager.getText("dialog.about.credits.translators") + " : "),
0, 3);
addToGridBagPanel(creditsPanel, gridBag, constraints,
- new JLabel("Ramon, Miguel, Inés, Piotr"),
+ new JLabel("Ramon, Miguel, Inés, Piotr, Petrovsk"),
1, 3);
addToGridBagPanel(creditsPanel, gridBag, constraints,
new JLabel(I18nManager.getText("dialog.about.credits.translations") + " : "),
1, 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));
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
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;
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);
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(
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"));
(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(""))
{
_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)
+ " " + (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;
_trackInfo = inTrackInfo;
_track = _trackInfo.getTrack();
}
+
+ /**
+ * Ignore action completed signals
+ */
+ public void actionCompleted(String inMessage)
+ {
+ }
}
import tim.prune.I18nManager;
import tim.prune.data.DataPoint;
import tim.prune.data.TrackInfo;
-//import tim.prune.gui.map.MapWindow;
/**
// 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;
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);
}
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);
-*/
}
{
// ignore
}
-
- /**
- * Show a map window - probably only temporarily here until it gets fixed
- */
-/*
- private void showMap()
- {
- MapWindow map = new MapWindow(_track);
- map.show();
- }
-*/
}
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;
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;
});
_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);
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"));
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"));
_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);
_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)
+ {}
}
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
--- /dev/null
+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)
+ {
+ }
+}
--- /dev/null
+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();
+ }
+}
--- /dev/null
+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;
+ }
+}
menu.edit.compress=Compress track
menu.edit.interpolate=Interpolate
menu.edit.reverse=Reverse range
+menu.edit.mergetracksegments=Merge track segments
menu.edit.rearrange=Rearrange waypoints
menu.edit.rearrange.start=All to start of file
menu.edit.rearrange.end=All to end of file
menu.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
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
dialog.delimiter.space=Space
dialog.delimiter.semicolon=Semicolon ;
dialog.delimiter.other=Other
-dialog.openoptions.deliminfo.records=records, with
+dialog.openoptions.deliminfo.records=records, with
dialog.openoptions.deliminfo.fields=fields
dialog.openoptions.deliminfo.norecords=No records
dialog.openoptions.tabledesc=Extract of file
dialog.jpegload.loadjpegswithoutcoords=Include photos without coordinates
dialog.jpegload.progress.title=Loading photos
dialog.jpegload.progress=Please wait while the photos are searched
-dialog.jpegload.title=Loaded photos
-dialog.jpegload.photoadded=photo was added
-dialog.jpegload.photosadded=photos were added
dialog.saveoptions.title=Save file
dialog.save.fieldstosave=Fields to save
dialog.save.table.field=Field
dialog.save.coordinateunits=Coordinate units
dialog.save.altitudeunits=Altitude units
dialog.save.timestampformat=Timestamp format
-dialog.save.oktitle=File saved
-dialog.save.ok1=Successfully saved
-dialog.save.ok2=points to file
dialog.save.overwrite.title=File already exists
dialog.save.overwrite.text=This file already exists. Are you sure you want to overwrite the file?
dialog.exportkml.title=Export KML
dialog.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.saveexif.photostatus.disconnected=Disconnected
dialog.saveexif.photostatus.modified=Modified
dialog.saveexif.overwrite=Overwrite files
-dialog.saveexif.ok1=Saved
-dialog.saveexif.ok2=photo files
dialog.correlate.title=Correlate photos
dialog.correlate.notimestamps=There are no timestamps in the data points, so there is nothing to correlate with the photos.
dialog.correlate.nouncorrelatedphotos=There are no uncorrelated photos.\nAre you sure you want to continue?
dialog.correlate.options.distancelimit=Distance limit
dialog.correlate.options.correlate=Correlate
dialog.correlate.alloutsiderange=All photos are outside the time range of the track, so none can be correlated.\nTry changing the offset or manually correlating at least one photo.
-dialog.correlate.confirmsingle.text=photo was correlated
-dialog.correlate.confirmmultiple.text=photos were correlated
+dialog.map.title=Prune map
dialog.help.help=Please see\n http://activityworkshop.net/software/prune/\nfor more information and user guides.
dialog.about.title=About Prune
dialog.about.version=Version
dialog.about.systeminfo.java3d=Java3d installed
dialog.about.systeminfo.povray=Povray installed
dialog.about.systeminfo.exiftool=Exiftool installed
+dialog.about.systeminfo.gpsbabel=Gpsbabel installed
dialog.about.yes=Yes
dialog.about.no=No
dialog.about.credits=Credits
dialog.about.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
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
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
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
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
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
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.
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
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
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
dialog.delimiter.space=Abstand
dialog.delimiter.semicolon=Strichpunkt ;
dialog.delimiter.other=Andere
-dialog.openoptions.deliminfo.records=Rekords, mit
+dialog.openoptions.deliminfo.records=Rekords, mit
dialog.openoptions.deliminfo.fields=Feldern
dialog.openoptions.deliminfo.norecords=Keine Rekords
dialog.openoptions.tabledesc=Extrakt von der Datei
dialog.jpegload.loadjpegswithoutcoords=Auch Fotos ohne Koordinaten laden
dialog.jpegload.progress.title=Fotos werden geladen
dialog.jpegload.progress=Bitte warten während die Fotos durchgesucht werden
-dialog.jpegload.title=Fotos geladen
-dialog.jpegload.photoadded=Foto wurde geladen
-dialog.jpegload.photosadded=Fotos wurden geladen
dialog.saveoptions.title=Datei speichern
dialog.save.fieldstosave=Felder zu speichern
dialog.save.table.field=Feld
dialog.save.coordinateunits=Koordinaten Maßeinheiten
dialog.save.altitudeunits=Höhe Maßeinheiten
dialog.save.timestampformat=Zeitstempelformat
-dialog.save.oktitle=Datei gespeichert
-dialog.save.ok1=Es wurden
-dialog.save.ok2=Punkte gespeichert nach
dialog.save.overwrite.title=Datei existiert
dialog.save.overwrite.text=Diese Datei existiert schon. Sind Sie sicher, Sie wollen die Datei überschreiben?
dialog.exportkml.title=KML exportieren
dialog.interpolate.parameter.text=Anzahl Punkte zuzufügen zwischen den selektierten Punkten
dialog.undo.title=Undo Operation(en)
dialog.undo.pretext=Selektieren die Operationen die rückgängig gemacht werden sollen.
-dialog.confirmundo.title=Operation(en) rückgängig gemacht
-dialog.confirmundo.single.text=Operation rückgängig gemacht.
-dialog.confirmundo.multiple.text=Operationen rückgängig gemacht.
dialog.undo.none.title=Undo nicht möglich
dialog.undo.none.text=Keine Operationen können rückgängig gemacht werden.
dialog.clearundo.title=Undo-Liste löschen
dialog.saveexif.photostatus.disconnected=Getrennt
dialog.saveexif.photostatus.modified=Modifiziert
dialog.saveexif.overwrite=Dateien überschreiben
-dialog.saveexif.ok1=Es wurden
-dialog.saveexif.ok2=Foto Dateien geschrieben
dialog.correlate.title=Fotos korrelieren
dialog.correlate.notimestamps=Die Punkte haben keine Zeitinformation, deswegen ist es nicht möglich die Fotos zu korrelieren.
dialog.correlate.nouncorrelatedphotos=Alle Photos sind schon korreliert.\nWollen Sie trotzdem fortsetzen?
dialog.correlate.options.distancelimit=Distanzgrenzen
dialog.correlate.options.correlate=Korrelieren
dialog.correlate.alloutsiderange=Alle Fotos sind ausserhalb vom Track Zeitraum, so können nicht korreliert werden.\nVersuchen Sie mit einem anderen Offset oder verbinden Sie manuell mindestens ein Foto.
-dialog.correlate.confirmsingle.text=Foto wurde korreliert
-dialog.correlate.confirmmultiple.text=Fotos wurden korreliert
+dialog.map.title=Prune Karte
dialog.help.help=Bitte sehen Sie\n http://activityworkshop.net/software/prune/\nfür weitere Information und Benutzeranleitungen.
dialog.about.title=Ãœber Prune
dialog.about.version=Version
dialog.about.systeminfo.java3d=Java3d installiert
dialog.about.systeminfo.povray=Povray installiert
dialog.about.systeminfo.exiftool=Exiftool installiert
+dialog.about.systeminfo.gpsbabel=Gpsbabel installiert
dialog.about.yes=Ja
dialog.about.no=Nein
dialog.about.credits=Credits
dialog.about.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
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
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
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
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
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
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.
menu.edit.compress=Date komprimiere
menu.edit.interpolate=Interpoliere
menu.edit.reverse=Spanne umdrähie
+menu.edit.mergetracksegments=Track Segmänte merge
menu.edit.rearrange=Waypoints reorganisiere
menu.edit.rearrange.start=Alli zum Aafang
menu.edit.rearrange.end=Alli zum Ände
menu.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
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
dialog.delimiter.space=Abstand
dialog.delimiter.semicolon=Strichpunkt ;
dialog.delimiter.other=Andere
-dialog.openoptions.deliminfo.records=Rekords, mit
+dialog.openoptions.deliminfo.records=Rekords, mit
dialog.openoptions.deliminfo.fields=Fäldere
dialog.openoptions.deliminfo.norecords=Kei Rekords
dialog.openoptions.tabledesc=Extrakt vom File
dialog.jpegload.loadjpegswithoutcoords=Au Fötelis ohni Koordinate
dialog.jpegload.progress.title=Fötelis lade
dialog.jpegload.progress=Bitte warte während die Fötelis durägsucht werde
-dialog.jpegload.title=Fötelis glade worde
-dialog.jpegload.photoadded=Föteli isch glade worde
-dialog.jpegload.photosadded=Fötelis sin glade worde
dialog.saveoptions.title=File speicherä
dialog.save.fieldstosave=Fälder zu speicherä
dialog.save.table.field=Fäld
dialog.save.coordinateunits=Koordinate Massiiheite
dialog.save.altitudeunits=Höchi Massiiheite
dialog.save.timestampformat=Ziitstämpelformat
-dialog.save.oktitle=File gspeicheret worde
-dialog.save.ok1=Es sin
-dialog.save.ok2=Punkte gspeicheret worde na
dialog.save.overwrite.title=s'File existiert scho
dialog.save.overwrite.text=s'File existiert scho. Sind Sie sicher, Sie wend s'File überschriibe?
dialog.exportkml.title=KML exportierä
dialog.interpolate.parameter.text=Aazahl Punkte zum innätue zwüschet den selektierten Punkten
dialog.undo.title=Undo Operation(e)
dialog.undo.pretext=Selektiere die Operatione die rückgängig gmacht söllti werde.
-dialog.confirmundo.title=Operation(e) rückgängig gmacht worde
-dialog.confirmundo.single.text=Operation rückgängig gmacht worde.
-dialog.confirmundo.multiple.text=Operatione rückgängig gmacht worde.
dialog.undo.none.title=Undo nöd möglich
dialog.undo.none.text=Keini Operatione könne rückgängig gmacht werde.
dialog.clearundo.title=Undo-Liste löschä
dialog.saveexif.photostatus.disconnected=Gtrännt
dialog.saveexif.photostatus.modified=Gänderet
dialog.saveexif.overwrite=Files überschriebä
-dialog.saveexif.ok1=Es sin
-dialog.saveexif.ok2=Fötelis gschriebe worde
dialog.correlate.title=Fötelis korrelierä
dialog.correlate.notimestamps=Es hät kei Ziitstämpel inem Track innä, so s'isch nöd möglech die Fötelis zu korrelierä.
dialog.correlate.nouncorrelatedphotos=Alle Fötelis sin scho korreliert.\nWend Sie trotzdem fortsetzä?
dialog.correlate.options.distancelimit=Distanzgränzä
dialog.correlate.options.correlate=Korrelierä
dialog.correlate.alloutsiderange=Alli Fötelis sin uusserhalb vonem Track Ziitruum, so chönne nöd korreliert werdä.\nVersuechet Sie mitenem anderen Offset oder verbindet Sie manuell mindeschtens eis Föteli.
-dialog.correlate.confirmsingle.text=Föteli isch korreliert worde
-dialog.correlate.confirmmultiple.text=Fötelis sin korreliert worde
+dialog.map.title=Prune Karte
dialog.help.help=Bitte lueg na\n http://activityworkshop.net/software/prune/\nfür wiitere Information und Benutzeraaleitige.
dialog.about.title=Ãœber Prune
dialog.about.version=Version
dialog.about.systeminfo.java3d=Java3d inschtalliert
dialog.about.systeminfo.povray=Povray inschtalliert
dialog.about.systeminfo.exiftool=Exiftool inschtalliert
+dialog.about.systeminfo.gpsbabel=Gpsbabel inschtalliert
dialog.about.yes=Ja
dialog.about.no=Nei
dialog.about.credits=Credits
dialog.about.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
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
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
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
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
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ä
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?
menu.edit.compress=Comprimir track
menu.edit.interpolate=Interpolar
menu.edit.reverse=Invertir rango
+menu.edit.mergetracksegments=Unir los segmentos de track
menu.edit.rearrange=Reorganizar waypoints
menu.edit.rearrange.start=Volver al comienzo
menu.edit.rearrange.end=Ir al final
menu.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
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
dialog.jpegload.loadjpegswithoutcoords=Fotos sin coordenadas tambien
dialog.jpegload.progress.title=Cargando fotos
dialog.jpegload.progress=Por favor espere mientras se buscan las fotos
-dialog.jpegload.title=Fotos cargadas
-dialog.jpegload.photoadded=Foto incluida
-dialog.jpegload.photosadded=Fotos incluidas
dialog.saveoptions.title=Guardar archivo
dialog.save.fieldstosave=Campos a guardar
dialog.save.table.field=Campo
dialog.save.coordinateunits=Unidades de las coordenadas
dialog.save.altitudeunits=Unidades de las altitudes
dialog.save.timestampformat=Format del tiempo
-dialog.save.oktitle=Guardando archivo
-dialog.save.ok1=Guardando
-dialog.save.ok2=puntos al archivo
dialog.save.overwrite.title=El archivo ya existe
dialog.save.overwrite.text=El archivo ya existe, desea sobreescribirlo?
dialog.exportkml.title=Exportar KML
dialog.interpolate.parameter.text=Número de los puntos a insertar entre los puntos elegidos
dialog.undo.title=Deshacer
dialog.undo.pretext=Por favor, seleccione la operación(es) a deshacer
-dialog.confirmundo.title=Operación(es) no realizada(s)
-dialog.confirmundo.single.text=operación no realizada
-dialog.confirmundo.multiple.text=operación(es) no realizada(s)
dialog.undo.none.title=No se puede deshacer
dialog.undo.none.text=Ninguna operación a deshacer
dialog.clearundo.title=Despejar la lista de deshacer
dialog.saveexif.photostatus.disconnected=Desconectada
dialog.saveexif.photostatus.modified=Modificada
dialog.saveexif.overwrite=Sobreescribirlar archivos?
-dialog.saveexif.ok1=Guardando
-dialog.saveexif.ok2=fotos
dialog.correlate.title=Correlacionar fotos
dialog.correlate.notimestamps=No hay información de tiempo para los puntos, asà que no hay nada que correlacionar con las fotos.
dialog.correlate.nouncorrelatedphotos=No hay fotos no correlacionadas.\nEstá seguro de que desea continuar?
dialog.correlate.options.distancelimit=LÃmite de distancia
dialog.correlate.options.correlate=Correlacionar
dialog.correlate.alloutsiderange=Todas las fotos están fuera del margen horario del track, por lo que ninguna puede ser correlada.\nIntente cambiar el margen o correle manualmente al menos una foto.
-dialog.correlate.confirmsingle.text=foto fue correlada
-dialog.correlate.confirmmultiple.text=fotos fueron correladas
+dialog.map.title=Mapa Prune
dialog.help.help=Por favor, ver\n http://activityworkshop.net/software/prune/\npara más información y guÃas del usuario.
dialog.about.title=Acerca de Prune
dialog.about.version=Versión
dialog.about.systeminfo.java3d=Java3d instalado
dialog.about.systeminfo.povray=Povray instalado
dialog.about.systeminfo.exiftool=Exiftool instalado
+dialog.about.systeminfo.gpsbabel=Gpsbabel instalado
dialog.about.yes=Si
dialog.about.no=No
dialog.about.credits=Credits
dialog.about.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
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
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
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
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
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
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.
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 ,
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
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
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.
menu.edit.compress=Skompresuj scie\u017Ck\u0119
menu.edit.interpolate=Interpoluj punkty
menu.edit.reverse=Odwr\u00F3\u0107 zakres
+menu.edit.mergetracksegments=Merge track segments
menu.edit.rearrange=Zmie\u0144 kolejno\u015B\u0107 punkt\u00F3w po\u015Brednich
menu.edit.rearrange.start=Wszystkie na pocz\u0105tek \u015Bcie\u017Cki
menu.edit.rearrange.end=Wszystkie na koniec \u015Bcie\u017Cki
menu.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
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
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
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?
dialog.interpolate.parameter.text=Number of punkty to insert between selected punkty
dialog.undo.title=Cofnij action(s)
dialog.undo.pretext=Please select the action(s) to undo
-dialog.confirmundo.title=Operation(s) undone
-dialog.confirmundo.single.text=operation undone.
-dialog.confirmundo.multiple.text=operations undone.
dialog.undo.none.title=Cannot undo
dialog.undo.none.text=No operations to undo!
dialog.clearundo.title=Wyczy\u015B\u0107 list\u0119 zmian
dialog.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?
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
dialog.about.systeminfo.java3d=Java3d zainstalowana
dialog.about.systeminfo.povray=Povray zainstalowana
dialog.about.systeminfo.exiftool=Exiftool zainstalowana
+dialog.about.systeminfo.gpsbabel=Gpsbabel zainstalowana
dialog.about.yes=Tak
dialog.about.no=Nie
dialog.about.credits=Credits
dialog.about.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
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
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
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
error.saveexif.cannotoverwrite2=is read-only and can't be overwritten. Write to copy?
error.load.dialogtitle=B\u0142\u0105d loading data
error.load.noread=Cannot read plik
-error.load.nopoints=No coordinate information found in the plik
+error.load.nopoints=No koordinaty information found in the plik
error.load.unknownxml=Nieznany xml format:
error.load.othererror=B\u0142\u0105d reading plik:
error.jpegload.dialogtitle=B\u0142\u0105d loading zdj\u0119cia
error.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.
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
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;
+ }
+ }
}
*/
public String[] getFirstFullRow()
{
- return _firstFullRow;
+ return _firstFullRow;
}
/**
- * 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();
{
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"));
}
}
}
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;
{
_insideTime = true;
}
+ else if (qName.equalsIgnoreCase("trkseg"))
+ {
+ _startSegment = true;
+ }
super.startElement(uri, localName, qName, attributes);
}
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);
}
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;
}
// 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);
}
}
}
*/
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;
*/
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;
}
-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.
=======
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
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
====================
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;
_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();
}
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;
}
else if (field == Field.TIMESTAMP)
{
- try
+ if (point.hasTimestamp())
{
if (timestampFormat == Timestamp.FORMAT_ORIGINAL) {
// output original string
buffer.append(point.getTimestamp().getText(timestampFormat));
}
}
- catch (NullPointerException npe) {}
}
else
{
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)
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;
// 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;
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);
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");
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;
// 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;
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(""))
// 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;
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;
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)
{\r
private DataPoint[] _contents = null;\r
protected int _numPointsDeleted = -1;\r
+ private boolean[] _segmentStarts = null;\r
\r
\r
/**\r
public UndoCompress(Track inTrack)\r
{\r
_contents = inTrack.cloneContents();\r
+ // Copy boolean segment start flags\r
+ _segmentStarts = new boolean[inTrack.getNumPoints()];\r
+ for (int i=0; i<inTrack.getNumPoints(); i++) {\r
+ _segmentStarts[i] = inTrack.getPoint(i).getSegmentStart();\r
+ }\r
}\r
\r
\r
{\r
// 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
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
_point.setPhoto(null);\r
photo.setDataPoint(null);\r
// inform subscribers\r
- inTrackInfo.triggerUpdate();\r
+ UpdateMessageBroker.informSubscribers();\r
}\r
else\r
{\r
package tim.prune.undo;\r
\r
import tim.prune.I18nManager;\r
+import tim.prune.UpdateMessageBroker;\r
import tim.prune.data.DataPoint;\r
import tim.prune.data.Photo;\r
import tim.prune.data.TrackInfo;\r
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
private int _pointIndex = -1;\r
private DataPoint _point = null;\r
private int _photoIndex = -1;\r
+ private boolean _segmentStart = false;\r
\r
\r
/**\r
* @param inPointIndex index number of point within track\r
* @param inPoint data point\r
* @param inPhotoIndex index number of photo within photo list\r
+ * @param inSegmentStart true if following track point starts new segment\r
*/\r
- 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
// 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
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
_startIndex = inTrackInfo.getSelection().getStart();\r
_points = inTrackInfo.cloneSelectedRange();\r
_photoList = inTrackInfo.getPhotoList().cloneList();\r
+ // Save segment flag of following track point\r
+ _nextTrackPoint = inTrackInfo.getTrack().getNextTrackPoint(_startIndex + _points.length);\r
+ if (_nextTrackPoint != null) {\r
+ _segmentStart = _nextTrackPoint.getSegmentStart();\r
+ }\r
}\r
\r
\r
}\r
// 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
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
_point.setPhoto(_photo);\r
_photo.setDataPoint(_point);\r
// inform subscribers\r
- inTrackInfo.triggerUpdate();\r
+ UpdateMessageBroker.informSubscribers();\r
}\r
else\r
{\r
--- /dev/null
+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();
+ }
+}
package tim.prune.undo;
import tim.prune.I18nManager;
+import tim.prune.data.DataPoint;
+import tim.prune.data.Track;
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();
+ }
}
{
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);
+ }
}
}