");
JEditorPane descPane = new JEditorPane("text/html", descBuffer.toString());
descPane.setBorder(BorderFactory.createEmptyBorder(3, 3, 3, 3));
@@ -195,7 +195,7 @@ public class AboutScreen extends GenericFunction
new JLabel(" theYinYeti, Rothermographer, Sam, Rudolph, nazotoko,"),
1, 4);
addToGridBagPanel(creditsPanel, gridBag, constraints,
- new JLabel(" katpatuka, R\u00E9mi, Marcus, Ali, Javier, Jeroen, prot_d"),
+ new JLabel(" katpatuka, R\u00E9mi, Marcus, Ali, Javier, Jeroen, prot_d, Gy\u00F6rgy, HooAU"),
1, 5);
addToGridBagPanel(creditsPanel, gridBag, constraints,
new JLabel(I18nManager.getText("dialog.about.credits.translations") + " : "),
@@ -297,20 +297,27 @@ public class AboutScreen extends GenericFunction
// First, try locally-held readme.txt if available (as it normally should be)
// Readme file can either be in file system or packed in the same jar as code
String errorMessage = null;
+ String readme = null;
+ InputStream in = null;
try
{
// For some reason using ../readme.txt doesn't work, so need absolute path
- InputStream in = AboutScreen.class.getResourceAsStream("/tim/prune/readme.txt");
+ in = AboutScreen.class.getResourceAsStream("/tim/prune/readme.txt");
if (in != null) {
byte[] buffer = new byte[in.available()];
in.read(buffer);
in.close();
- return new String(buffer);
+ readme = new String(buffer);
}
}
catch (IOException e) {
errorMessage = e.getMessage();
}
+ finally {
+ try {in.close();} catch (Exception e) {}
+ }
+ if (readme != null) {return readme;}
+
// Locally-held file failed, so try to find gz file installed on system (eg Debian)
try
{
@@ -318,7 +325,7 @@ public class AboutScreen extends GenericFunction
if (gzFile.exists())
{
// Copy decompressed bytes from gz file into out
- InputStream in = new GZIPInputStream(new FileInputStream(gzFile));
+ in = new GZIPInputStream(new FileInputStream(gzFile));
ByteArrayOutputStream out = new ByteArrayOutputStream();
byte[] buffer = new byte[8 * 1024];
int count = 0;
@@ -328,12 +335,16 @@ public class AboutScreen extends GenericFunction
} while (count != -1);
out.close();
in.close();
- return out.toString();
+ readme = out.toString();
}
}
catch (IOException e) {
System.err.println("Exception trying to get readme.gz : " + e.getMessage());
}
+ finally {
+ try {in.close();} catch (Exception e) {}
+ }
+ if (readme != null) {return readme;}
// Only show first error message if couldn't get readme from gz either
if (errorMessage != null) {
System.err.println("Exception trying to get readme: " + errorMessage);
diff --git a/tim/prune/function/AddMapSourceDialog.java b/tim/prune/function/AddMapSourceDialog.java
index d7126ea..ec13bb1 100644
--- a/tim/prune/function/AddMapSourceDialog.java
+++ b/tim/prune/function/AddMapSourceDialog.java
@@ -9,8 +9,6 @@ import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
-import java.net.MalformedURLException;
-import java.net.URL;
import javax.swing.BorderFactory;
import javax.swing.ButtonGroup;
@@ -216,23 +214,15 @@ public class AddMapSourceDialog
private boolean isOsmPanelOk()
{
boolean ok = _oNameField.getText().trim().length() > 1;
- URL baseUrl = null, topUrl = null;
- try {
- // Try to parse base url if given
- String baseText = _baseUrlField.getText().trim();
- if (baseText.length() > 10) {
- baseUrl = new URL(baseText);
- }
- else if (baseText.length() > 0) {ok = false;}
- // Same again for top url if given
- String topText = _topUrlField.getText().trim();
- if (topText.length() > 10) {
- topUrl = new URL(topText);
- }
- else if (topText.length() > 0) {ok = false;}
- } catch (MalformedURLException e) {
- ok = false;
- }
+ String baseUrl = null, topUrl = null;
+ // Try to parse base url if given
+ String baseText = _baseUrlField.getText().trim();
+ baseUrl = MapSource.fixBaseUrl(baseText);
+ if (baseText.length() > 0 && baseUrl == null) {ok = false;}
+ // Same again for top url if given
+ String topText = _topUrlField.getText().trim();
+ topUrl = MapSource.fixBaseUrl(topText);
+ if (topText.length() > 0 && topUrl == null) {ok = false;}
// looks ok if at least one url given
return (ok && (baseUrl != null || topUrl != null));
}
diff --git a/tim/prune/function/ConnectToPointFunction.java b/tim/prune/function/ConnectToPointFunction.java
new file mode 100644
index 0000000..fa6f30b
--- /dev/null
+++ b/tim/prune/function/ConnectToPointFunction.java
@@ -0,0 +1,63 @@
+package tim.prune.function;
+
+import tim.prune.App;
+import tim.prune.DataSubscriber;
+import tim.prune.GenericFunction;
+import tim.prune.I18nManager;
+import tim.prune.UpdateMessageBroker;
+import tim.prune.data.AudioFile;
+import tim.prune.data.DataPoint;
+import tim.prune.data.Photo;
+import tim.prune.undo.UndoConnectMedia;
+import tim.prune.undo.UndoOperation;
+
+/**
+ * Function to connect either a photo or an audio file to the current point
+ */
+public class ConnectToPointFunction extends GenericFunction
+{
+ /**
+ * Constructor
+ * @param inApp app object
+ */
+ public ConnectToPointFunction(App inApp) {
+ super(inApp);
+ }
+
+ /**
+ * @return name key
+ */
+ public String getNameKey() {
+ return "function.connecttopoint";
+ }
+
+ /**
+ * Perform function
+ */
+ public void begin()
+ {
+ Photo photo = _app.getTrackInfo().getCurrentPhoto();
+ DataPoint point = _app.getTrackInfo().getCurrentPoint();
+ AudioFile audio = _app.getTrackInfo().getCurrentAudio();
+ boolean connectPhoto = (point != null && photo != null && point.getPhoto() == null);
+ boolean connectAudio = (point != null && audio != null && point.getAudio() == null);
+
+ if (connectPhoto && connectAudio) {
+ // TODO: Let user choose whether to connect photo/audio or both
+ }
+ // Make undo object
+ UndoOperation undo = new UndoConnectMedia(point, connectPhoto?photo.getFile().getName():null,
+ connectAudio?audio.getFile().getName():null);
+ // Connect the media
+ if (connectPhoto) {
+ photo.setDataPoint(point);
+ point.setPhoto(photo);
+ }
+ if (connectAudio) {
+ audio.setDataPoint(point);
+ point.setAudio(audio);
+ }
+ UpdateMessageBroker.informSubscribers(DataSubscriber.SELECTION_CHANGED);
+ _app.completeFunction(undo, I18nManager.getText("confirm.media.connect"));
+ }
+}
diff --git a/tim/prune/function/DisconnectAudioFunction.java b/tim/prune/function/DisconnectAudioFunction.java
new file mode 100644
index 0000000..abcd9c4
--- /dev/null
+++ b/tim/prune/function/DisconnectAudioFunction.java
@@ -0,0 +1,48 @@
+package tim.prune.function;
+
+import tim.prune.App;
+import tim.prune.DataSubscriber;
+import tim.prune.GenericFunction;
+import tim.prune.I18nManager;
+import tim.prune.UpdateMessageBroker;
+import tim.prune.data.AudioFile;
+import tim.prune.data.DataPoint;
+import tim.prune.undo.UndoDisconnectMedia;
+import tim.prune.undo.UndoOperation;
+
+/**
+ * Function to disconnect the current audio object from the current point (like DisconnectPhotoFunction)
+ */
+public class DisconnectAudioFunction extends GenericFunction
+{
+ /**
+ * Constructor
+ * @param inApp app object
+ */
+ public DisconnectAudioFunction(App inApp) {
+ super(inApp);
+ }
+
+ /** @return name key */
+ public String getNameKey() {
+ return "function.disconnectfrompoint";
+ }
+
+ /**
+ * Perform the operation
+ */
+ public void begin()
+ {
+ AudioFile audio = _app.getTrackInfo().getCurrentAudio();
+ if (audio != null && audio.getDataPoint() != null)
+ {
+ DataPoint point = audio.getDataPoint();
+ UndoOperation undo = new UndoDisconnectMedia(point, false, true, audio.getFile().getName());
+ // disconnect
+ audio.setDataPoint(null);
+ point.setAudio(null);
+ UpdateMessageBroker.informSubscribers(DataSubscriber.SELECTION_CHANGED);
+ _app.completeFunction(undo, I18nManager.getText("confirm.audio.disconnect"));
+ }
+ }
+}
diff --git a/tim/prune/function/DisconnectPhotoFunction.java b/tim/prune/function/DisconnectPhotoFunction.java
new file mode 100644
index 0000000..6223433
--- /dev/null
+++ b/tim/prune/function/DisconnectPhotoFunction.java
@@ -0,0 +1,47 @@
+package tim.prune.function;
+
+import tim.prune.App;
+import tim.prune.DataSubscriber;
+import tim.prune.GenericFunction;
+import tim.prune.I18nManager;
+import tim.prune.UpdateMessageBroker;
+import tim.prune.data.DataPoint;
+import tim.prune.data.Photo;
+import tim.prune.undo.UndoDisconnectMedia;
+
+/**
+ * Function to disconnect the current photo from the current point
+ */
+public class DisconnectPhotoFunction extends GenericFunction
+{
+ /**
+ * Constructor
+ * @param inApp app object
+ */
+ public DisconnectPhotoFunction(App inApp) {
+ super(inApp);
+ }
+
+ /** @return name key */
+ public String getNameKey() {
+ return "function.disconnectfrompoint";
+ }
+
+ /**
+ * Perform the operation
+ */
+ public void begin()
+ {
+ Photo photo = _app.getTrackInfo().getCurrentPhoto();
+ if (photo != null && photo.getDataPoint() != null)
+ {
+ DataPoint point = photo.getDataPoint();
+ UndoDisconnectMedia undo = new UndoDisconnectMedia(point, true, false, photo.getFile().getName());
+ // disconnect
+ photo.setDataPoint(null);
+ point.setPhoto(null);
+ UpdateMessageBroker.informSubscribers(DataSubscriber.SELECTION_CHANGED);
+ _app.completeFunction(undo, I18nManager.getText("confirm.photo.disconnect"));
+ }
+ }
+}
diff --git a/tim/prune/function/DownloadOsmFunction.java b/tim/prune/function/DownloadOsmFunction.java
new file mode 100644
index 0000000..bef09ad
--- /dev/null
+++ b/tim/prune/function/DownloadOsmFunction.java
@@ -0,0 +1,277 @@
+package tim.prune.function;
+
+import java.awt.BorderLayout;
+import java.awt.Component;
+import java.awt.FlowLayout;
+import java.awt.GridLayout;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.text.NumberFormat;
+
+import javax.swing.BorderFactory;
+import javax.swing.BoxLayout;
+import javax.swing.JButton;
+import javax.swing.JDialog;
+import javax.swing.JFileChooser;
+import javax.swing.JLabel;
+import javax.swing.JOptionPane;
+import javax.swing.JPanel;
+import javax.swing.JProgressBar;
+
+import tim.prune.App;
+import tim.prune.GenericFunction;
+import tim.prune.I18nManager;
+import tim.prune.data.DoubleRange;
+
+/**
+ * Class to allow the download of OSM data (using the XAPI)
+ * for the area covered by the data
+ */
+public class DownloadOsmFunction extends GenericFunction implements Runnable
+{
+ private JDialog _dialog = null;
+ private JLabel[] _latLonLabels = null;
+ private JProgressBar _progressBar = null;
+ private JButton _okButton = null;
+ private JFileChooser _fileChooser = null;
+ private File _selectedFile = null;
+ private boolean _cancelled = false;
+ /** Number formatter */
+ private final NumberFormat FORMAT_TWO_DP = NumberFormat.getNumberInstance();
+
+
+ /**
+ * Constructor
+ * @param inApp application object for callback
+ */
+ public DownloadOsmFunction(App inApp)
+ {
+ super(inApp);
+ FORMAT_TWO_DP.setMaximumFractionDigits(2);
+ FORMAT_TWO_DP.setMinimumFractionDigits(2);
+ }
+
+ /** Get the name key */
+ public String getNameKey() {
+ return "function.downloadosm";
+ }
+
+ /**
+ * Begin the function
+ */
+ public void begin()
+ {
+ // Make dialog window
+ if (_dialog == null)
+ {
+ _dialog = new JDialog(_parentFrame, I18nManager.getText(getNameKey()), true);
+ _dialog.setLocationRelativeTo(_parentFrame);
+ _dialog.setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE);
+ _dialog.getContentPane().add(makeDialogComponents());
+ _dialog.pack();
+ _fileChooser = new JFileChooser();
+ _fileChooser.setSelectedFile(new File("data.osm"));
+ }
+ initDialog();
+ _dialog.setVisible(true);
+ }
+
+
+ /**
+ * Create dialog components
+ * @return Panel containing all gui elements in dialog
+ */
+ private Component makeDialogComponents()
+ {
+ JPanel dialogPanel = new JPanel();
+ dialogPanel.setLayout(new BorderLayout(0, 10));
+ dialogPanel.add(new JLabel(I18nManager.getText("dialog.downloadosm.desc")), BorderLayout.NORTH);
+ // grid of labels to show lat/long extent
+ JPanel gridPanel = new JPanel();
+ gridPanel.setLayout(new GridLayout(3, 3));
+ _latLonLabels = new JLabel[4];
+ for (int i=0; i<4; i++) {
+ _latLonLabels[i] = new JLabel("0");
+ }
+ int lNum = 0;
+ for (int i=0; i<4; i++) {
+ gridPanel.add(new JLabel(" "));
+ gridPanel.add(_latLonLabels[lNum++]);
+ }
+ // layout main panel
+ JPanel mainPanel = new JPanel();
+ mainPanel.setLayout(new BoxLayout(mainPanel, BoxLayout.Y_AXIS));
+ mainPanel.add(gridPanel);
+ _progressBar = new JProgressBar();
+ _progressBar.setIndeterminate(true);
+ mainPanel.add(_progressBar);
+ dialogPanel.add(mainPanel, BorderLayout.CENTER);
+ // button panel at bottom
+ JPanel buttonPanel = new JPanel();
+ buttonPanel.setLayout(new FlowLayout(FlowLayout.RIGHT));
+ _okButton = new JButton(I18nManager.getText("button.ok"));
+ ActionListener okListener = new ActionListener() {
+ public void actionPerformed(ActionEvent e) {
+ finish();
+ }
+ };
+ _okButton.addActionListener(okListener);
+ buttonPanel.add(_okButton);
+ JButton cancelButton = new JButton(I18nManager.getText("button.cancel"));
+ cancelButton.addActionListener(new ActionListener() {
+ public void actionPerformed(ActionEvent e) {
+ _cancelled = true;
+ _dialog.dispose();
+ }
+ });
+ buttonPanel.add(cancelButton);
+ dialogPanel.add(buttonPanel, BorderLayout.SOUTH);
+ dialogPanel.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 15));
+ return dialogPanel;
+ }
+
+ /**
+ * Initialise the values of the labels in the dialog
+ */
+ private void initDialog()
+ {
+ // Get range of data
+ String[] lats = expandRange(_app.getTrackInfo().getTrack().getLatRange());
+ String[] lons = expandRange(_app.getTrackInfo().getTrack().getLonRange());
+ _latLonLabels[0].setText(lats[1]); // max lat
+ _latLonLabels[1].setText(lons[0]); // min lon
+ _latLonLabels[2].setText(lons[1]); // max lon
+ _latLonLabels[3].setText(lats[0]); // min lat
+ _okButton.setEnabled(true);
+ _progressBar.setVisible(false);
+ _cancelled = false;
+ }
+
+ /**
+ * Expand the given range to reasonable limits
+ * @param inRange range of lat/long values
+ * @return expanded range as pair of Strings
+ */
+ private String[] expandRange(DoubleRange inRange)
+ {
+ double mid = (inRange.getMaximum() + inRange.getMinimum()) / 2.0;
+ double range = inRange.getRange();
+ double max = 0.0, min = 0.0;
+ // Expand range to at least 0.02 degree
+ if (range < 0.02)
+ {
+ min = mid - 0.01;
+ max = mid + 0.01;
+ }
+ else {
+ // expand by 10% in both directions
+ min = mid - range * 0.55;
+ max = mid + range * 0.55;
+ }
+ // Round min down to 0.01 degree
+ int minCents = (int) (100 * min);
+ // Round max upwards likewise
+ int maxCents = (int) (100 * max + 1);
+ final String[] answer = new String[] {FORMAT_TWO_DP.format(minCents/100.0),
+ FORMAT_TWO_DP.format(maxCents/100.0)};
+ return answer;
+ }
+
+ /**
+ * Finish the dialog when OK pressed
+ */
+ private void finish()
+ {
+ if (!_okButton.isEnabled()) return;
+ _selectedFile = selectOsmFile();
+ if (_selectedFile != null)
+ {
+ // Show progress bar
+ _okButton.setEnabled(false);
+ _progressBar.setVisible(true);
+ new Thread(this).start();
+ }
+ else
+ _dialog.dispose();
+ }
+
+ /**
+ * Select a file to save the OSM data to
+ * @return selected file or null if cancelled
+ */
+ private File selectOsmFile()
+ {
+ File saveFile = null;
+ boolean chooseAgain = false;
+ do
+ {
+ chooseAgain = false;
+ if (_fileChooser.showSaveDialog(_dialog) == JFileChooser.APPROVE_OPTION)
+ {
+ // OK pressed and file chosen
+ File file = _fileChooser.getSelectedFile();
+ // Check if file exists and if necessary prompt for overwrite
+ Object[] buttonTexts = {I18nManager.getText("button.overwrite"), I18nManager.getText("button.cancel")};
+ if (!file.exists() || JOptionPane.showOptionDialog(_dialog,
+ I18nManager.getText("dialog.save.overwrite.text"),
+ I18nManager.getText("dialog.save.overwrite.title"), JOptionPane.YES_NO_OPTION,
+ JOptionPane.WARNING_MESSAGE, null, buttonTexts, buttonTexts[1])
+ == JOptionPane.YES_OPTION)
+ {
+ // new file or overwrite confirmed
+ saveFile = file;
+ }
+ else
+ {
+ // file exists and overwrite cancelled - select again
+ chooseAgain = true;
+ }
+ }
+ } while (chooseAgain);
+ return saveFile;
+ }
+
+
+ /**
+ * Do the actual download - launched to run in another thread
+ */
+ public void run()
+ {
+ final String url = "http://www.informationfreeway.org/api/0.6/map?bbox=" +
+ _latLonLabels[1].getText() + "," + _latLonLabels[3].getText() + "," +
+ _latLonLabels[2].getText() + "," + _latLonLabels[0].getText();
+
+ byte[] buffer = new byte[1024];
+ InputStream inStream = null;
+ FileOutputStream outStream = null;
+ int numBytesRead = 0;
+ try
+ {
+ inStream = new URL(url).openStream();
+ outStream = new FileOutputStream(_selectedFile);
+ // Loop and copy bytes to file
+ while ((numBytesRead = inStream.read(buffer)) > -1 && !_cancelled)
+ {
+ outStream.write(buffer, 0, numBytesRead);
+ }
+ }
+ catch (MalformedURLException mue) {}
+ catch (IOException ioe) {
+ // TODO: throw exception or show dialog
+ System.out.println("Exception: " + ioe.getClass().getName());
+ }
+ // clean up streams
+ finally {
+ try {inStream.close();} catch (Exception e) {}
+ try {outStream.close();} catch (Exception e) {}
+ }
+ // close dialog
+ _dialog.dispose();
+ }
+}
diff --git a/tim/prune/function/GetWikipediaFunction.java b/tim/prune/function/GetWikipediaFunction.java
new file mode 100644
index 0000000..acef09c
--- /dev/null
+++ b/tim/prune/function/GetWikipediaFunction.java
@@ -0,0 +1,133 @@
+package tim.prune.function;
+
+import java.io.InputStream;
+import java.net.URL;
+import java.util.ArrayList;
+
+import javax.xml.parsers.SAXParser;
+import javax.xml.parsers.SAXParserFactory;
+
+import tim.prune.App;
+import tim.prune.I18nManager;
+import tim.prune.data.DataPoint;
+import tim.prune.data.Field;
+import tim.prune.data.Latitude;
+import tim.prune.data.Longitude;
+import tim.prune.function.gpsies.GenericDownloaderFunction;
+import tim.prune.function.gpsies.GpsiesTrack;
+
+/**
+ * Function to load nearby point information from Wikipedia
+ * according to the currently viewed area
+ */
+public class GetWikipediaFunction extends GenericDownloaderFunction
+{
+ /** Maximum number of results to get */
+ private static final int MAX_RESULTS = 20;
+ /** Maximum distance from point in km */
+ private static final int MAX_DISTANCE = 15;
+
+
+ /**
+ * Constructor
+ * @param inApp App object
+ */
+ public GetWikipediaFunction(App inApp) {
+ super(inApp);
+ }
+
+ /**
+ * @return name key
+ */
+ public String getNameKey() {
+ return "function.getwikipedia";
+ }
+
+ /**
+ * @param inColNum index of column, 0 or 1
+ * @return key for this column
+ */
+ protected String getColumnKey(int inColNum)
+ {
+ if (inColNum == 0) return "dialog.wikipedia.column.name";
+ return "dialog.wikipedia.column.distance";
+ }
+
+
+ /**
+ * Run method to call geonames in separate thread
+ */
+ public void run()
+ {
+ _statusLabel.setText(I18nManager.getText("confirm.running"));
+ // Get coordinates from current point (if any) or from centre of screen
+ double lat = 0.0, lon = 0.0;
+ DataPoint point = _app.getTrackInfo().getCurrentPoint();
+ if (point == null)
+ {
+ double[] coords = _app.getViewport().getBounds();
+ lat = (coords[0] + coords[2]) / 2.0;
+ lon = (coords[1] + coords[3]) / 2.0;
+ }
+ else {
+ lat = point.getLatitude().getDouble();
+ lon = point.getLongitude().getDouble();
+ }
+
+ String descMessage = "";
+ InputStream inStream = null;
+
+ // Example http://ws.geonames.org/findNearbyWikipedia?lat=47&lng=9
+ String urlString = "http://ws.geonames.org/findNearbyWikipedia?lat=" +
+ lat + "&lng=" + lon + "&maxRows=" + MAX_RESULTS
+ + "&radius=" + MAX_DISTANCE + "&lang=" + I18nManager.getText("wikipedia.lang");
+ // Parse the returned XML with a special handler
+ GetWikipediaXmlHandler xmlHandler = new GetWikipediaXmlHandler();
+ try
+ {
+ URL url = new URL(urlString);
+ SAXParser saxParser = SAXParserFactory.newInstance().newSAXParser();
+ inStream = url.openStream();
+ saxParser.parse(inStream, xmlHandler);
+ }
+ catch (Exception e) {
+ descMessage = e.getClass().getName() + " - " + e.getMessage();
+ }
+ // Close stream and ignore errors
+ try {
+ inStream.close();
+ } catch (Exception e) {}
+ // Add track list to model
+ ArrayList trackList = xmlHandler.getTrackList();
+ _trackListModel.addTracks(trackList);
+
+ // Set status label according to error or "none found", leave blank if ok
+ if (descMessage.equals("") && (trackList == null || trackList.size() == 0)) {
+ descMessage = I18nManager.getText("dialog.gpsies.nonefound");
+ }
+ _statusLabel.setText(descMessage);
+ }
+
+ /**
+ * Load the selected track or point
+ */
+ protected void loadSelected()
+ {
+ // Find the row selected in the table and get the corresponding track
+ int rowNum = _trackTable.getSelectedRow();
+ if (rowNum >= 0 && rowNum < _trackListModel.getRowCount())
+ {
+ String coords = _trackListModel.getTrack(rowNum).getDownloadLink();
+ String[] latlon = coords.split(",");
+ if (latlon.length == 2)
+ {
+ DataPoint point = new DataPoint(new Latitude(latlon[0]), new Longitude(latlon[1]), null);
+ point.setFieldValue(Field.WAYPT_NAME, _trackListModel.getTrack(rowNum).getTrackName(), false);
+ _app.createPoint(point);
+ }
+ }
+ // Close the dialog
+ _cancelled = true;
+ _dialog.dispose();
+ }
+}
diff --git a/tim/prune/function/GetWikipediaXmlHandler.java b/tim/prune/function/GetWikipediaXmlHandler.java
new file mode 100644
index 0000000..3cca682
--- /dev/null
+++ b/tim/prune/function/GetWikipediaXmlHandler.java
@@ -0,0 +1,93 @@
+package tim.prune.function;
+
+import java.util.ArrayList;
+
+import org.xml.sax.Attributes;
+import org.xml.sax.SAXException;
+import org.xml.sax.helpers.DefaultHandler;
+
+import tim.prune.function.gpsies.GpsiesTrack;
+
+/**
+ * XML handler for dealing with XML returned from gpsies.com
+ */
+public class GetWikipediaXmlHandler extends DefaultHandler
+{
+ private String _value = null;
+ private ArrayList _trackList = null;
+ private GpsiesTrack _track = null;
+ private String _lat = null, _lon = null;
+
+
+ /**
+ * React to the start of an XML tag
+ */
+ public void startElement(String inUri, String inLocalName, String inTagName,
+ Attributes inAttributes) throws SAXException
+ {
+ if (inTagName.equals("geonames")) {
+ _trackList = new ArrayList();
+ }
+ else if (inTagName.equals("entry")) {
+ _track = new GpsiesTrack();
+ _lat = null;
+ _lon = null;
+ }
+ else _value = null;
+ super.startElement(inUri, inLocalName, inTagName, inAttributes);
+ }
+
+ /**
+ * React to the end of an XML tag
+ */
+ public void endElement(String inUri, String inLocalName, String inTagName)
+ throws SAXException
+ {
+ if (inTagName.equals("entry")) {
+ // end of the entry
+ _track.setDownloadLink(_lat + "," + _lon);
+ _trackList.add(_track);
+ }
+ else if (inTagName.equals("title")) {
+ _track.setTrackName(_value);
+ }
+ else if (inTagName.equals("summary")) {
+ _track.setDescription(_value);
+ }
+ else if (inTagName.equals("lat")) {
+ _lat = _value;
+ }
+ else if (inTagName.equals("lng")) {
+ _lon = _value;
+ }
+ else if (inTagName.equals("distance")) {
+ try {
+ _track.setLength(Double.parseDouble(_value) * 1000.0); // convert from km to m
+ }
+ catch (NumberFormatException nfe) {}
+ }
+ else if (inTagName.equals("wikipediaUrl")) {
+ _track.setWebUrl(_value);
+ }
+ super.endElement(inUri, inLocalName, inTagName);
+ }
+
+ /**
+ * React to characters received inside tags
+ */
+ public void characters(char[] inCh, int inStart, int inLength)
+ throws SAXException
+ {
+ String value = new String(inCh, inStart, inLength);
+ _value = (_value==null?value:_value+value);
+ super.characters(inCh, inStart, inLength);
+ }
+
+ /**
+ * @return the list of tracks
+ */
+ public ArrayList getTrackList()
+ {
+ return _trackList;
+ }
+}
diff --git a/tim/prune/function/PhotoPopupFunction.java b/tim/prune/function/PhotoPopupFunction.java
new file mode 100644
index 0000000..6b8b3e0
--- /dev/null
+++ b/tim/prune/function/PhotoPopupFunction.java
@@ -0,0 +1,113 @@
+package tim.prune.function;
+
+import java.awt.BorderLayout;
+import java.awt.Component;
+import java.awt.Dimension;
+import java.awt.FlowLayout;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.awt.event.KeyEvent;
+import java.awt.event.KeyListener;
+
+import javax.swing.JButton;
+import javax.swing.JFrame;
+import javax.swing.JLabel;
+import javax.swing.JPanel;
+import tim.prune.App;
+import tim.prune.GenericFunction;
+import tim.prune.I18nManager;
+import tim.prune.data.Photo;
+import tim.prune.gui.PhotoThumbnail;
+
+/**
+ * Class to show a popup window for a photo
+ */
+public class PhotoPopupFunction extends GenericFunction
+{
+ /** popup window */
+ private JFrame _frame = null; // would be a JDialog but that doesn't allow max button
+ /** label for filename */
+ private JLabel _label = null;
+ /** Photo thumbnail */
+ private PhotoThumbnail _photoThumb = null;
+
+ /**
+ * Constructor
+ * @param inApp app object
+ */
+ public PhotoPopupFunction(App inApp)
+ {
+ super(inApp);
+ }
+
+ /**
+ * Get the name key
+ */
+ public String getNameKey() {
+ return "function.photopopup";
+ }
+
+ /**
+ * Show the screen
+ */
+ public void begin()
+ {
+ if (_frame == null)
+ {
+ _frame = new JFrame(I18nManager.getText(getNameKey()));
+ _frame.setIconImage(_parentFrame.getIconImage());
+ _frame.getContentPane().add(makeContents());
+ _frame.pack();
+ _frame.setLocationRelativeTo(_parentFrame);
+ }
+ initFrame();
+ _frame.setVisible(true);
+ }
+
+ /**
+ * Initialise the frame to show the current photo
+ */
+ private void initFrame()
+ {
+ _frame.setVisible(false);
+ Photo photo = _app.getTrackInfo().getCurrentPhoto();
+ _frame.setTitle(photo.getFile().getName());
+ _label.setText("'" + photo.getFile().getName() + "' ("
+ + photo.getWidth() + " x " + photo.getHeight() + ")");
+ _photoThumb.setPhoto(photo);
+ }
+
+ /**
+ * @return the contents of the window as a Component
+ */
+ private Component makeContents()
+ {
+ JPanel mainPanel = new JPanel();
+ mainPanel.setLayout(new BorderLayout());
+ _label = new JLabel("Photo popup");
+ mainPanel.add(_label, BorderLayout.NORTH);
+ _photoThumb = new PhotoThumbnail(false); // specify not in details panel
+ _photoThumb.setPreferredSize(new Dimension(300, 300));
+ mainPanel.add(_photoThumb, BorderLayout.CENTER);
+ // Close button at bottom
+ JPanel okPanel = new JPanel();
+ okPanel.setLayout(new FlowLayout(FlowLayout.RIGHT));
+ JButton okButton = new JButton(I18nManager.getText("button.ok"));
+ okButton.addActionListener(new ActionListener()
+ {
+ public void actionPerformed(ActionEvent e) {
+ _frame.dispose();
+ }
+ });
+ okButton.addKeyListener(new KeyListener() {
+ public void keyPressed(KeyEvent e) {
+ if (e.getKeyCode() == KeyEvent.VK_ESCAPE) {_frame.dispose();}
+ }
+ public void keyTyped(KeyEvent e) {}
+ public void keyReleased(KeyEvent e) {}
+ });
+ okPanel.add(okButton);
+ mainPanel.add(okPanel, BorderLayout.SOUTH);
+ return mainPanel;
+ }
+}
diff --git a/tim/prune/function/PlayAudioFunction.java b/tim/prune/function/PlayAudioFunction.java
new file mode 100644
index 0000000..7e7a34a
--- /dev/null
+++ b/tim/prune/function/PlayAudioFunction.java
@@ -0,0 +1,153 @@
+package tim.prune.function;
+
+import java.io.File;
+import java.io.IOException;
+import javax.sound.sampled.AudioInputStream;
+import javax.sound.sampled.AudioSystem;
+import javax.sound.sampled.Clip;
+
+import tim.prune.App;
+import tim.prune.GenericFunction;
+
+/**
+ * Class to play the current audio file
+ */
+public class PlayAudioFunction extends GenericFunction implements Runnable
+{
+ /** Audio clip used for playing within java */
+ private Clip _clip = null;
+
+
+ /**
+ * Constructor
+ * @param inApp app object
+ */
+ public PlayAudioFunction(App inApp) {
+ super(inApp);
+ }
+
+ /**
+ * @return name key
+ */
+ public String getNameKey() {
+ return "function.playaudio";
+ }
+
+ /**
+ * Perform function
+ */
+ public void begin()
+ {
+ // Launch new thread if clip isn't currently playing
+ if (_clip == null) {
+ new Thread(this).start();
+ }
+ }
+
+ /**
+ * Play the audio in a new thread
+ */
+ public void run()
+ {
+ File audioFile = _app.getTrackInfo().getCurrentAudio().getFile();
+ boolean played = false;
+ if (audioFile.exists() && audioFile.isFile() && audioFile.canRead())
+ {
+ // First choice is to play using java
+ played = playClip(audioFile);
+ // Second choice is to try the Desktop library from java 6, if available
+ if (!played) {
+ try {
+ Class> d = Class.forName("java.awt.Desktop");
+ d.getDeclaredMethod("open", new Class[] {File.class}).invoke(
+ d.getDeclaredMethod("getDesktop").invoke(null), new Object[] {audioFile});
+ //above code mimics: Desktop.getDesktop().open(audioFile);
+ played = true;
+ }
+ catch (Exception ignore) {
+ played = false;
+ }
+ }
+ // If the Desktop call failed, need to try backup methods
+ if (!played)
+ {
+ // If system looks like a Mac, try open command
+ String osName = System.getProperty("os.name").toLowerCase();
+ boolean isMacOsx = osName.indexOf("mac os") >= 0 || osName.indexOf("darwin") >= 0;
+ if (isMacOsx) {
+ String[] command = new String[] {"open", audioFile.getAbsolutePath()};
+ try {
+ Runtime.getRuntime().exec(command);
+ played = true;
+ }
+ catch (IOException ioe) {}
+ }
+ }
+ }
+ if (!played)
+ {
+ // If still not worked, show error message
+ _app.showErrorMessage(getNameKey(), "error.playaudiofailed");
+ }
+ }
+
+ /**
+ * Try to play the sound file using built-in java libraries
+ * @return true if play was successful
+ */
+ private boolean playClip(File inFile)
+ {
+ boolean success = false;
+ AudioInputStream audioInputStream = null;
+ _clip = null;
+ try
+ {
+ audioInputStream = AudioSystem.getAudioInputStream(inFile);
+ _clip = AudioSystem.getClip();
+ _clip.open(audioInputStream);
+ // play the clip
+ _clip.start();
+ _clip.drain();
+ success = true;
+ } catch (Exception e) {
+ } finally {
+ // close the stream to clean up
+ try {
+ _clip.close();
+ audioInputStream.close();
+ } catch (Exception e) {}
+ _clip = null;
+ }
+ return success;
+ }
+
+ /**
+ * Try to stop a currently playing clip
+ */
+ public void stopClip()
+ {
+ if (_clip != null && _clip.isActive()) {
+ try {
+ _clip.stop();
+ _clip.flush();
+ }
+ catch (Exception e) {}
+ }
+ }
+
+ /**
+ * @return percentage of clip currently played, or -1 if not playing
+ */
+ public int getPercentage()
+ {
+ int percent = -1;
+ if (_clip != null && _clip.isActive())
+ {
+ long clipLen = _clip.getMicrosecondLength();
+ if (clipLen > 0) {
+ percent = (int) (_clip.getMicrosecondPosition() * 100.0 / clipLen);
+ }
+ }
+ return percent;
+ }
+}
diff --git a/tim/prune/function/RemoveAudioFunction.java b/tim/prune/function/RemoveAudioFunction.java
new file mode 100644
index 0000000..fa859be
--- /dev/null
+++ b/tim/prune/function/RemoveAudioFunction.java
@@ -0,0 +1,68 @@
+package tim.prune.function;
+
+import javax.swing.JOptionPane;
+
+import tim.prune.App;
+import tim.prune.GenericFunction;
+import tim.prune.I18nManager;
+import tim.prune.data.AudioFile;
+import tim.prune.undo.UndoDeleteAudio;
+
+/**
+ * Function to remove the currently selected audio file
+ */
+public class RemoveAudioFunction extends GenericFunction
+{
+ /**
+ * Constructor
+ * @param inApp App object
+ */
+ public RemoveAudioFunction(App inApp) {
+ super(inApp);
+ }
+
+ /** @return name key */
+ public String getNameKey() {
+ return "function.removeaudio";
+ }
+
+ /**
+ * Perform the function
+ */
+ public void begin()
+ {
+ // Delete the current audio, and optionally its point too, keeping undo information
+ AudioFile currentAudio = _app.getTrackInfo().getCurrentAudio();
+ if (currentAudio != null)
+ {
+ // Audio is selected, see if it has a point or not
+ boolean deleted = false;
+ UndoDeleteAudio undoAction = null;
+ if (currentAudio.getDataPoint() == null)
+ {
+ // no point attached, so just delete
+ undoAction = new UndoDeleteAudio(currentAudio, _app.getTrackInfo().getSelection().getCurrentAudioIndex(),
+ null, -1);
+ deleted = _app.getTrackInfo().deleteCurrentAudio(false);
+ }
+ else
+ {
+ // point is attached, so need to confirm point deletion
+ undoAction = new UndoDeleteAudio(currentAudio, _app.getTrackInfo().getSelection().getCurrentAudioIndex(),
+ currentAudio.getDataPoint(), _app.getTrackInfo().getTrack().getPointIndex(currentAudio.getDataPoint()));
+ int response = JOptionPane.showConfirmDialog(_app.getFrame(),
+ I18nManager.getText("dialog.deleteaudio.deletepoint"),
+ I18nManager.getText(getNameKey()), JOptionPane.YES_NO_CANCEL_OPTION);
+ boolean deletePointToo = (response == JOptionPane.YES_OPTION);
+ // Cancel delete if cancel pressed or dialog closed
+ if (response == JOptionPane.YES_OPTION || response == JOptionPane.NO_OPTION) {
+ deleted = _app.getTrackInfo().deleteCurrentAudio(deletePointToo);
+ }
+ }
+ // Add undo information to stack if necessary
+ if (deleted) {
+ _app.completeFunction(undoAction, currentAudio.getFile().getName() + " " + I18nManager.getText("confirm.media.removed"));
+ }
+ }
+ }
+}
diff --git a/tim/prune/function/RemovePhotoFunction.java b/tim/prune/function/RemovePhotoFunction.java
new file mode 100644
index 0000000..b09ae10
--- /dev/null
+++ b/tim/prune/function/RemovePhotoFunction.java
@@ -0,0 +1,69 @@
+package tim.prune.function;
+
+import javax.swing.JOptionPane;
+
+import tim.prune.App;
+import tim.prune.GenericFunction;
+import tim.prune.I18nManager;
+import tim.prune.data.Photo;
+import tim.prune.undo.UndoDeletePhoto;
+
+/**
+ * Function to remove the currently selected photo
+ */
+public class RemovePhotoFunction extends GenericFunction
+{
+ /**
+ * Constructor
+ * @param inApp App object
+ */
+ public RemovePhotoFunction(App inApp) {
+ super(inApp);
+ }
+
+ /** @return name key */
+ public String getNameKey() {
+ return "function.removephoto";
+ }
+
+ /**
+ * Perform the function
+ */
+ public void begin()
+ {
+ // Delete the current photo, and optionally its point too, keeping undo information
+ Photo currentPhoto = _app.getTrackInfo().getCurrentPhoto();
+ if (currentPhoto != null)
+ {
+ // Photo is selected, see if it has a point or not
+ boolean photoDeleted = false;
+ UndoDeletePhoto undoAction = null;
+ if (currentPhoto.getDataPoint() == null)
+ {
+ // no point attached, so just delete photo
+ undoAction = new UndoDeletePhoto(currentPhoto, _app.getTrackInfo().getSelection().getCurrentPhotoIndex(),
+ null, -1);
+ photoDeleted = _app.getTrackInfo().deleteCurrentPhoto(false);
+ }
+ else
+ {
+ // point is attached, so need to confirm point deletion
+ undoAction = new UndoDeletePhoto(currentPhoto, _app.getTrackInfo().getSelection().getCurrentPhotoIndex(),
+ currentPhoto.getDataPoint(), _app.getTrackInfo().getTrack().getPointIndex(currentPhoto.getDataPoint()));
+ int response = JOptionPane.showConfirmDialog(_app.getFrame(),
+ I18nManager.getText("dialog.deletephoto.deletepoint"),
+ I18nManager.getText("dialog.deletephoto.title"),
+ JOptionPane.YES_NO_CANCEL_OPTION);
+ boolean deletePointToo = (response == JOptionPane.YES_OPTION);
+ // Cancel delete if cancel pressed or dialog closed
+ if (response == JOptionPane.YES_OPTION || response == JOptionPane.NO_OPTION) {
+ photoDeleted = _app.getTrackInfo().deleteCurrentPhoto(deletePointToo);
+ }
+ }
+ // Add undo information to stack if necessary
+ if (photoDeleted) {
+ _app.completeFunction(undoAction, currentPhoto.getFile().getName() + " " + I18nManager.getText("confirm.media.removed"));
+ }
+ }
+ }
+}
diff --git a/tim/prune/function/SaveConfig.java b/tim/prune/function/SaveConfig.java
index 125b4b7..6c0e4d0 100644
--- a/tim/prune/function/SaveConfig.java
+++ b/tim/prune/function/SaveConfig.java
@@ -135,14 +135,19 @@ public class SaveConfig extends GenericFunction
if (response == JFileChooser.APPROVE_OPTION)
{
File saveFile = chooser.getSelectedFile();
+ FileOutputStream outStream = null;
try
{
- Config.getAllConfig().store(new FileOutputStream(saveFile), "Prune config file");
+ outStream = new FileOutputStream(saveFile);
+ Config.getAllConfig().store(outStream, "Prune config file");
}
catch (IOException ioe) {
_app.showErrorMessageNoLookup(getNameKey(),
I18nManager.getText("error.save.failed") + " : " + ioe.getMessage());
}
+ finally {
+ try {outStream.close();} catch (Exception e) {}
+ }
}
_dialog.dispose();
_dialog = null;
diff --git a/tim/prune/function/SearchWikipediaNames.java b/tim/prune/function/SearchWikipediaNames.java
new file mode 100644
index 0000000..4377df8
--- /dev/null
+++ b/tim/prune/function/SearchWikipediaNames.java
@@ -0,0 +1,144 @@
+package tim.prune.function;
+
+import java.io.InputStream;
+import java.net.URL;
+import java.util.ArrayList;
+
+import javax.swing.JOptionPane;
+import javax.xml.parsers.SAXParser;
+import javax.xml.parsers.SAXParserFactory;
+
+import tim.prune.App;
+import tim.prune.I18nManager;
+import tim.prune.data.DataPoint;
+import tim.prune.data.Field;
+import tim.prune.data.Latitude;
+import tim.prune.data.Longitude;
+import tim.prune.function.gpsies.GenericDownloaderFunction;
+import tim.prune.function.gpsies.GpsiesTrack;
+
+/**
+ * Function to search Wikipedia for place names
+ */
+public class SearchWikipediaNames extends GenericDownloaderFunction
+{
+ /** search term */
+ private String _searchTerm = null;
+ /** Maximum number of results to get */
+ private static final int MAX_RESULTS = 20;
+
+ /**
+ * Constructor
+ * @param inApp App object
+ */
+ public SearchWikipediaNames(App inApp) {
+ super(inApp);
+ }
+
+ /**
+ * @return name key
+ */
+ public String getNameKey() {
+ return "function.searchwikipedianames";
+ }
+
+ /**
+ * @param inColNum index of column, 0 or 1
+ * @return key for this column
+ */
+ protected String getColumnKey(int inColNum)
+ {
+ if (inColNum == 0) return "dialog.wikipedia.column.name";
+ return null;
+ }
+
+ /**
+ * Before dialog is shown, need to get search term
+ */
+ public void begin()
+ {
+ Object search = JOptionPane.showInputDialog(_app.getFrame(),
+ I18nManager.getText("dialog.searchwikipedianames.search"),
+ I18nManager.getText(getNameKey()),
+ JOptionPane.QUESTION_MESSAGE, null, null, "");
+ if (search != null)
+ {
+ _searchTerm = search.toString();
+ if (!_searchTerm.equals("")) {
+ super.begin();
+ }
+ }
+ }
+
+ /**
+ * Run method to call geonames in separate thread
+ */
+ public void run()
+ {
+ _statusLabel.setText(I18nManager.getText("confirm.running"));
+
+ String descMessage = "";
+ InputStream inStream = null;
+
+ // language (only de and en available)
+ String lang = I18nManager.getText("wikipedia.lang");
+ if (lang.equals("de") || lang.equals("als")) {
+ lang = "de";
+ }
+ else {
+ lang = "en";
+ }
+ // Example http://ws.geonames.org/wikipediaSearch?q=london&maxRows=10
+ String urlString = "http://ws.geonames.org/wikipediaSearch?title=" + _searchTerm + "&maxRows=" + MAX_RESULTS
+ + "&lang=" + lang;
+ // Parse the returned XML with a special handler
+ GetWikipediaXmlHandler xmlHandler = new GetWikipediaXmlHandler();
+ try
+ {
+ URL url = new URL(urlString);
+ SAXParser saxParser = SAXParserFactory.newInstance().newSAXParser();
+ inStream = url.openStream();
+ saxParser.parse(inStream, xmlHandler);
+ }
+ catch (Exception e) {
+ descMessage = e.getClass().getName() + " - " + e.getMessage();
+ }
+ // Close stream and ignore errors
+ try {
+ inStream.close();
+ } catch (Exception e) {}
+ // Add track list to model
+ ArrayList trackList = xmlHandler.getTrackList();
+ // TODO: Do a better job of sorting replies by relevance - use three different lists
+ _trackListModel.addTracks(trackList);
+
+ // Set status label according to error or "none found", leave blank if ok
+ if (descMessage.equals("") && (trackList == null || trackList.size() == 0)) {
+ descMessage = I18nManager.getText("dialog.gpsies.nonefound");
+ }
+ _statusLabel.setText(descMessage);
+ }
+
+ /**
+ * Load the selected track or point
+ */
+ protected void loadSelected()
+ {
+ // Find the row selected in the table and get the corresponding track
+ int rowNum = _trackTable.getSelectedRow();
+ if (rowNum >= 0 && rowNum < _trackListModel.getRowCount())
+ {
+ String coords = _trackListModel.getTrack(rowNum).getDownloadLink();
+ String[] latlon = coords.split(",");
+ if (latlon.length == 2)
+ {
+ DataPoint point = new DataPoint(new Latitude(latlon[0]), new Longitude(latlon[1]), null);
+ point.setFieldValue(Field.WAYPT_NAME, _trackListModel.getTrack(rowNum).getTrackName(), false);
+ _app.createPoint(point);
+ }
+ }
+ // Close the dialog
+ _cancelled = true;
+ _dialog.dispose();
+ }
+}
diff --git a/tim/prune/function/SetLanguage.java b/tim/prune/function/SetLanguage.java
index 90bbc8f..f2ef5d3 100644
--- a/tim/prune/function/SetLanguage.java
+++ b/tim/prune/function/SetLanguage.java
@@ -41,14 +41,15 @@ public class SetLanguage extends GenericFunction
private int _startIndex = 0;
/** Names of languages for display in dropdown (not translated) */
- private static final String[] LANGUAGE_NAMES = {"\u010de\u0161tina", "deutsch", "english", "espa\u00F1ol",
- "fran\u00E7ais", "italiano", "nederlands", "polski", "portugu\u00EAs", "\u4e2d\u6587 (chinese)",
- "\u65E5\u672C\u8A9E (japanese)", "schwiizerd\u00FC\u00FCtsch", "t\u00FCrk\u00E7e", "rom\u00E2n\u0103",
- "afrikaans", "bahasa indonesia", "farsi"
+ private static final String[] LANGUAGE_NAMES = {"\u010de\u0161tina", "deutsch", "english",
+ "espa\u00F1ol", "fran\u00E7ais", "italiano", "magyar", "nederlands", "polski",
+ "portugu\u00EAs", "\u4e2d\u6587 (chinese)", "\u65E5\u672C\u8A9E (japanese)",
+ "\uD55C\uAD6D\uC5B4/\uC870\uC120\uB9D0 (korean)", "schwiizerd\u00FC\u00FCtsch", "t\u00FCrk\u00E7e",
+ "rom\u00E2n\u0103", "afrikaans", "bahasa indonesia", "farsi"
};
/** Associated language codes (must be in same order as names!) */
- private static final String[] LANGUAGE_CODES = {"cz", "de", "en", "es", "fr", "it", "nl", "pl", "pt", "zh",
- "ja", "de_ch", "tr", "ro", "af", "in", "fa"
+ private static final String[] LANGUAGE_CODES = {"cz", "de", "en", "es", "fr", "it", "hu",
+ "nl", "pl", "pt", "zh", "ja", "ko", "de_ch", "tr", "ro", "af", "in", "fa"
};
diff --git a/tim/prune/function/SetLineWidth.java b/tim/prune/function/SetLineWidth.java
new file mode 100644
index 0000000..5ac64ae
--- /dev/null
+++ b/tim/prune/function/SetLineWidth.java
@@ -0,0 +1,56 @@
+package tim.prune.function;
+
+import javax.swing.JOptionPane;
+
+import tim.prune.App;
+import tim.prune.DataSubscriber;
+import tim.prune.GenericFunction;
+import tim.prune.I18nManager;
+import tim.prune.UpdateMessageBroker;
+import tim.prune.config.Config;
+
+public class SetLineWidth extends GenericFunction
+{
+
+ /**
+ * Constructor
+ * @param inApp App object
+ */
+ public SetLineWidth(App inApp) {
+ super(inApp);
+ }
+
+ /** @return name key */
+ public String getNameKey() {
+ return "function.setlinewidth";
+ }
+
+
+ /**
+ * Run function
+ */
+ public void begin()
+ {
+ int currLineWidth = Config.getConfigInt(Config.KEY_LINE_WIDTH);
+ if (currLineWidth < 1 || currLineWidth > 4) {
+ currLineWidth = 2;
+ }
+ Object lineWidthStr = JOptionPane.showInputDialog(_app.getFrame(),
+ I18nManager.getText("dialog.setlinewidth.text"),
+ I18nManager.getText(getNameKey()),
+ JOptionPane.QUESTION_MESSAGE, null, null, "" + currLineWidth);
+ if (lineWidthStr != null)
+ {
+ int lineWidth = 2;
+ try {
+ lineWidth = Integer.parseInt(lineWidthStr.toString());
+ if (lineWidth >= 1 && lineWidth <= 4 && lineWidth != currLineWidth)
+ {
+ Config.setConfigInt(Config.KEY_LINE_WIDTH, lineWidth);
+ UpdateMessageBroker.informSubscribers(DataSubscriber.SELECTION_CHANGED);
+ }
+ }
+ catch (NumberFormatException nfe) {};
+ }
+ }
+}
diff --git a/tim/prune/function/StopAudioFunction.java b/tim/prune/function/StopAudioFunction.java
new file mode 100644
index 0000000..1d58dda
--- /dev/null
+++ b/tim/prune/function/StopAudioFunction.java
@@ -0,0 +1,35 @@
+package tim.prune.function;
+
+import tim.prune.App;
+import tim.prune.FunctionLibrary;
+import tim.prune.GenericFunction;
+
+/**
+ * Class to stop playing the current audio file
+ */
+public class StopAudioFunction extends GenericFunction
+{
+ /**
+ * Constructor
+ * @param inApp app object
+ */
+ public StopAudioFunction(App inApp) {
+ super(inApp);
+ }
+
+ /**
+ * @return name key
+ */
+ public String getNameKey() {
+ return "function.stopaudio";
+ }
+
+ /**
+ * Perform function
+ */
+ public void begin()
+ {
+ PlayAudioFunction playFn = (PlayAudioFunction) FunctionLibrary.FUNCTION_PLAY_AUDIO;
+ playFn.stopClip();
+ }
+}
diff --git a/tim/prune/function/compress/ClosePointsAlgorithm.java b/tim/prune/function/compress/ClosePointsAlgorithm.java
index 69c3635..b488238 100644
--- a/tim/prune/function/compress/ClosePointsAlgorithm.java
+++ b/tim/prune/function/compress/ClosePointsAlgorithm.java
@@ -58,7 +58,7 @@ public class ClosePointsAlgorithm extends SingleParameterAlgorithm
if (!currPoint.isWaypoint())
{
// Don't delete any photo points or start/end of segments
- if (currPoint.getPhoto() == null
+ if (!currPoint.hasMedia()
&& !_trackDetails.isSegmentStart(i) && !_trackDetails.isSegmentEnd(i))
{
// Check current point against prevPoint
diff --git a/tim/prune/function/compress/CompressTrackFunction.java b/tim/prune/function/compress/CompressTrackFunction.java
index 35ff61d..b347305 100644
--- a/tim/prune/function/compress/CompressTrackFunction.java
+++ b/tim/prune/function/compress/CompressTrackFunction.java
@@ -171,7 +171,7 @@ public class CompressTrackFunction extends GenericFunction
for (int i=0; i d = Class.forName("javax.swing.JTable");
+ d.getDeclaredMethod("setAutoCreateRowSorter", new Class[]{Boolean.TYPE}).invoke(distTable, Boolean.TRUE);
+ }
+ catch (Exception e) {}
scrollPane = new JScrollPane(distTable);
scrollPane.setPreferredSize(new Dimension(200, 250));
mainPanel.add(scrollPane);
diff --git a/tim/prune/function/gpsies/GenericDownloaderFunction.java b/tim/prune/function/gpsies/GenericDownloaderFunction.java
new file mode 100644
index 0000000..743becf
--- /dev/null
+++ b/tim/prune/function/gpsies/GenericDownloaderFunction.java
@@ -0,0 +1,226 @@
+package tim.prune.function.gpsies;
+
+import java.awt.BorderLayout;
+import java.awt.Component;
+import java.awt.Dimension;
+import java.awt.FlowLayout;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.awt.event.WindowAdapter;
+import java.awt.event.WindowEvent;
+
+import javax.swing.BorderFactory;
+import javax.swing.JButton;
+import javax.swing.JDialog;
+import javax.swing.JLabel;
+import javax.swing.JPanel;
+import javax.swing.JScrollPane;
+import javax.swing.JSplitPane;
+import javax.swing.JTable;
+import javax.swing.JTextArea;
+import javax.swing.event.ListSelectionEvent;
+import javax.swing.event.ListSelectionListener;
+
+import tim.prune.App;
+import tim.prune.GenericFunction;
+import tim.prune.I18nManager;
+import tim.prune.function.browser.BrowserLauncher;
+
+/**
+ * Function to load track information from any source,
+ * subclassed for special cases gpsies or wikipedia
+ */
+public abstract class GenericDownloaderFunction extends GenericFunction implements Runnable
+{
+ /** Dialog object */
+ protected JDialog _dialog = null;
+ /** list model */
+ protected TrackListModel _trackListModel = null;
+ /** track table */
+ protected JTable _trackTable = null;
+ /** Cancelled flag */
+ protected boolean _cancelled = false;
+ /** Status label */
+ protected JLabel _statusLabel = null;
+ /** Description box */
+ private JTextArea _descriptionBox = null;
+ /** Load button */
+ private JButton _loadButton = null;
+ /** Show button */
+ private JButton _showButton = null;
+
+
+ /**
+ * Constructor
+ * @param inApp App object
+ */
+ public GenericDownloaderFunction(App inApp) {
+ super(inApp);
+ }
+
+ /**
+ * Begin the function
+ */
+ public void begin()
+ {
+ // Initialise dialog, show empty list
+ if (_dialog == null)
+ {
+ _dialog = new JDialog(_parentFrame, I18nManager.getText(getNameKey()), true);
+ _dialog.setLocationRelativeTo(_parentFrame);
+ _dialog.setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE);
+ // add closing listener
+ _dialog.addWindowListener(new WindowAdapter() {
+ public void windowClosing(WindowEvent e) {
+ _cancelled = true;
+ }
+ });
+ _dialog.getContentPane().add(makeDialogComponents());
+ _dialog.pack();
+ }
+ // Clear list
+ _trackListModel.clear();
+ _loadButton.setEnabled(false);
+ _showButton.setEnabled(false);
+ _cancelled = false;
+ _descriptionBox.setText("");
+ // Start new thread to load list asynchronously
+ new Thread(this).start();
+
+ // Show dialog
+ _dialog.setVisible(true);
+ }
+
+
+ /**
+ * Create dialog components
+ * @return Panel containing all gui elements in dialog
+ */
+ private Component makeDialogComponents()
+ {
+ JPanel dialogPanel = new JPanel();
+ dialogPanel.setLayout(new BorderLayout());
+
+ // Status label
+ _statusLabel = new JLabel(I18nManager.getText("confirm.running"));
+ dialogPanel.add(_statusLabel, BorderLayout.NORTH);
+ // Main panel with track list
+ _trackListModel = new TrackListModel(getColumnKey(0), getColumnKey(1));
+ _trackTable = new JTable(_trackListModel);
+ _trackTable.getSelectionModel().addListSelectionListener(new ListSelectionListener() {
+ public void valueChanged(ListSelectionEvent e) {
+ if (!e.getValueIsAdjusting())
+ {
+ if (_trackTable.getSelectedRow() >= 0
+ && _trackTable.getSelectedRow() < _trackListModel.getRowCount())
+ {
+ _loadButton.setEnabled(true);
+ _showButton.setEnabled(true);
+ setDescription(_trackListModel.getTrack(_trackTable.getSelectedRow()).getDescription());
+ _descriptionBox.setCaretPosition(0);
+ }
+ else {
+ _descriptionBox.setText("");
+ }
+ }
+ }
+ });
+ _trackTable.getColumnModel().getColumn(0).setPreferredWidth(300);
+ if (_trackListModel.getColumnCount() > 1) {
+ _trackTable.getColumnModel().getColumn(1).setPreferredWidth(70);
+ }
+ JScrollPane tablePane = new JScrollPane(_trackTable);
+ tablePane.setPreferredSize(new Dimension(450, 200));
+ // Panel to hold description label and box
+ JPanel descPanel = new JPanel();
+ descPanel.setLayout(new BorderLayout());
+ JLabel descLabel = new JLabel(I18nManager.getText("dialog.gpsies.description") + " :");
+ descPanel.add(descLabel, BorderLayout.NORTH);
+ _descriptionBox = new JTextArea(5, 20);
+ _descriptionBox.setEditable(false);
+ _descriptionBox.setLineWrap(true);
+ _descriptionBox.setWrapStyleWord(true);
+ JScrollPane descPane = new JScrollPane(_descriptionBox);
+ descPane.setPreferredSize(new Dimension(400, 80));
+ descPanel.add(descPane, BorderLayout.CENTER);
+ // Use split pane to split table from description
+ JSplitPane splitPane = new JSplitPane(JSplitPane.VERTICAL_SPLIT, tablePane, descPanel);
+ splitPane.setResizeWeight(1.0);
+ dialogPanel.add(splitPane, BorderLayout.CENTER);
+
+ // button panel at bottom
+ JPanel buttonPanel = new JPanel();
+ buttonPanel.setLayout(new FlowLayout(FlowLayout.RIGHT));
+ _loadButton = new JButton(I18nManager.getText("button.load"));
+ _loadButton.setEnabled(false);
+ _loadButton.addActionListener(new ActionListener() {
+ public void actionPerformed(ActionEvent e)
+ {
+ loadSelected();
+ }
+ });
+ buttonPanel.add(_loadButton);
+ _showButton = new JButton(I18nManager.getText("button.showwebpage"));
+ _showButton.setEnabled(false);
+ _showButton.addActionListener(new ActionListener() {
+ public void actionPerformed(ActionEvent e)
+ {
+ showSelectedWebpage();
+ }
+ });
+ buttonPanel.add(_showButton);
+ JButton cancelButton = new JButton(I18nManager.getText("button.cancel"));
+ cancelButton.addActionListener(new ActionListener() {
+ public void actionPerformed(ActionEvent e)
+ {
+ _cancelled = true;
+ _dialog.dispose();
+ }
+ });
+ buttonPanel.add(cancelButton);
+ dialogPanel.add(buttonPanel, BorderLayout.SOUTH);
+ dialogPanel.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 15));
+ return dialogPanel;
+ }
+
+ /**
+ * @param inColNum index of column, 0 or 1
+ * @return key for this column
+ */
+ protected abstract String getColumnKey(int inColNum);
+
+ /**
+ * Set the description in the box
+ * @param inDesc description to set, or null for no description
+ */
+ private void setDescription(String inDesc)
+ {
+ String text = inDesc;
+ if (inDesc == null || inDesc.length() < 2) {
+ text = I18nManager.getText("dialog.gpsies.nodescription");
+ }
+ _descriptionBox.setText(text);
+ }
+
+
+ /**
+ * Load the selected track or point
+ */
+ protected abstract void loadSelected();
+
+
+ /**
+ * Show the webpage for the selected item
+ */
+ private void showSelectedWebpage()
+ {
+ // Find the row selected in the table and show the corresponding url
+ int rowNum = _trackTable.getSelectedRow();
+ if (rowNum >= 0 && rowNum < _trackListModel.getRowCount())
+ {
+ String url = _trackListModel.getTrack(rowNum).getWebUrl();
+ BrowserLauncher.launchBrowser(url);
+ }
+ // Don't close the dialog
+ }
+}
diff --git a/tim/prune/function/gpsies/GetGpsiesFunction.java b/tim/prune/function/gpsies/GetGpsiesFunction.java
index d1d83f3..804c4ce 100644
--- a/tim/prune/function/gpsies/GetGpsiesFunction.java
+++ b/tim/prune/function/gpsies/GetGpsiesFunction.java
@@ -1,36 +1,15 @@
package tim.prune.function.gpsies;
-import java.awt.BorderLayout;
-import java.awt.Component;
-import java.awt.Dimension;
-import java.awt.FlowLayout;
-import java.awt.event.ActionEvent;
-import java.awt.event.ActionListener;
-import java.awt.event.WindowAdapter;
-import java.awt.event.WindowEvent;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.util.ArrayList;
-import javax.swing.BorderFactory;
-import javax.swing.JButton;
-import javax.swing.JDialog;
-import javax.swing.JLabel;
-import javax.swing.JPanel;
-import javax.swing.JScrollPane;
-import javax.swing.JSplitPane;
-import javax.swing.JTable;
-import javax.swing.JTextArea;
-import javax.swing.event.ListSelectionEvent;
-import javax.swing.event.ListSelectionListener;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
import tim.prune.App;
-import tim.prune.GenericFunction;
import tim.prune.I18nManager;
-import tim.prune.function.browser.BrowserLauncher;
import tim.prune.load.xml.XmlFileLoader;
import tim.prune.load.xml.ZipFileLoader;
@@ -38,24 +17,8 @@ import tim.prune.load.xml.ZipFileLoader;
* Function to load track information from Gpsies.com
* according to the currently viewed area
*/
-public class GetGpsiesFunction extends GenericFunction implements Runnable
+public class GetGpsiesFunction extends GenericDownloaderFunction
{
- /** Dialog object */
- private JDialog _dialog = null;
- /** list model */
- private TrackListModel _trackListModel = null;
- /** track table */
- private JTable _trackTable = null;
- /** Cancelled flag */
- private boolean _cancelled = false;
- /** Status label */
- private JLabel _statusLabel = null;
- /** Description box */
- private JTextArea _descriptionBox = null;
- /** Load button */
- private JButton _loadButton = null;
- /** Show button */
- private JButton _showButton = null;
/** Number of results per page */
private static final int RESULTS_PER_PAGE = 20;
/** Maximum number of results to get */
@@ -66,8 +29,7 @@ public class GetGpsiesFunction extends GenericFunction implements Runnable
* Constructor
* @param inApp App object
*/
- public GetGpsiesFunction(App inApp)
- {
+ public GetGpsiesFunction(App inApp) {
super(inApp);
}
@@ -79,140 +41,15 @@ public class GetGpsiesFunction extends GenericFunction implements Runnable
}
/**
- * Begin the function
- */
- public void begin()
- {
- // Initialise dialog, show empty list
- if (_dialog == null)
- {
- _dialog = new JDialog(_parentFrame, I18nManager.getText(getNameKey()), true);
- _dialog.setLocationRelativeTo(_parentFrame);
- _dialog.setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE);
- // add closing listener
- _dialog.addWindowListener(new WindowAdapter() {
- public void windowClosing(WindowEvent e) {
- _cancelled = true;
- }
- });
- _dialog.getContentPane().add(makeDialogComponents());
- _dialog.pack();
- }
- // Clear list
- _trackListModel.clear();
- _loadButton.setEnabled(false);
- _showButton.setEnabled(false);
- _cancelled = false;
- _descriptionBox.setText("");
- // Start new thread to load list asynchronously
- new Thread(this).start();
-
- // Show dialog
- _dialog.setVisible(true);
- }
-
-
- /**
- * Create dialog components
- * @return Panel containing all gui elements in dialog
+ * @param inColNum index of column, 0 or 1
+ * @return key for this column
*/
- private Component makeDialogComponents()
+ protected String getColumnKey(int inColNum)
{
- JPanel dialogPanel = new JPanel();
- dialogPanel.setLayout(new BorderLayout());
-
- // Status label
- _statusLabel = new JLabel(I18nManager.getText("confirm.running"));
- dialogPanel.add(_statusLabel, BorderLayout.NORTH);
- // Main panel with track list
- _trackListModel = new TrackListModel();
- _trackTable = new JTable(_trackListModel);
- _trackTable.getSelectionModel().addListSelectionListener(new ListSelectionListener() {
- public void valueChanged(ListSelectionEvent e) {
- if (!e.getValueIsAdjusting())
- {
- if (_trackTable.getSelectedRow() >= 0
- && _trackTable.getSelectedRow() < _trackListModel.getRowCount())
- {
- _loadButton.setEnabled(true);
- _showButton.setEnabled(true);
- setDescription(_trackListModel.getTrack(_trackTable.getSelectedRow()).getDescription());
- _descriptionBox.setCaretPosition(0);
- }
- else {
- _descriptionBox.setText("");
- }
- }
- }
- });
- _trackTable.getColumnModel().getColumn(0).setPreferredWidth(300);
- _trackTable.getColumnModel().getColumn(1).setPreferredWidth(70);
- JScrollPane tablePane = new JScrollPane(_trackTable);
- tablePane.setPreferredSize(new Dimension(450, 200));
- // Panel to hold description label and box
- JPanel descPanel = new JPanel();
- descPanel.setLayout(new BorderLayout());
- JLabel descLabel = new JLabel(I18nManager.getText("dialog.gpsies.description") + " :");
- descPanel.add(descLabel, BorderLayout.NORTH);
- _descriptionBox = new JTextArea(5, 20);
- _descriptionBox.setEditable(false);
- _descriptionBox.setLineWrap(true);
- _descriptionBox.setWrapStyleWord(true);
- JScrollPane descPane = new JScrollPane(_descriptionBox);
- descPane.setPreferredSize(new Dimension(400, 80));
- descPanel.add(descPane, BorderLayout.CENTER);
- // Use split pane to split table from description
- JSplitPane splitPane = new JSplitPane(JSplitPane.VERTICAL_SPLIT, tablePane, descPanel);
- splitPane.setResizeWeight(1.0);
- dialogPanel.add(splitPane, BorderLayout.CENTER);
-
- // button panel at bottom
- JPanel buttonPanel = new JPanel();
- buttonPanel.setLayout(new FlowLayout(FlowLayout.RIGHT));
- _loadButton = new JButton(I18nManager.getText("button.load"));
- _loadButton.setEnabled(false);
- _loadButton.addActionListener(new ActionListener() {
- public void actionPerformed(ActionEvent e)
- {
- loadSelectedTrack();
- }
- });
- buttonPanel.add(_loadButton);
- _showButton = new JButton(I18nManager.getText("button.showwebpage"));
- _showButton.setEnabled(false);
- _showButton.addActionListener(new ActionListener() {
- public void actionPerformed(ActionEvent e)
- {
- showSelectedTrack();
- }
- });
- buttonPanel.add(_showButton);
- JButton cancelButton = new JButton(I18nManager.getText("button.cancel"));
- cancelButton.addActionListener(new ActionListener() {
- public void actionPerformed(ActionEvent e)
- {
- _cancelled = true;
- _dialog.dispose();
- }
- });
- buttonPanel.add(cancelButton);
- dialogPanel.add(buttonPanel, BorderLayout.SOUTH);
- dialogPanel.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 15));
- return dialogPanel;
+ if (inColNum == 0) return "dialog.gpsies.column.name";
+ return "dialog.gpsies.column.length";
}
- /**
- * Set the description in the box
- * @param inDesc description to set, or null for no description
- */
- private void setDescription(String inDesc)
- {
- String text = inDesc;
- if (inDesc == null || inDesc.length() < 2) {
- text = I18nManager.getText("dialog.gpsies.nodescription");
- }
- _descriptionBox.setText(text);
- }
/**
* Run method to call gpsies.com in separate thread
@@ -235,7 +72,6 @@ public class GetGpsiesFunction extends GenericFunction implements Runnable
String urlString = "http://www.gpsies.com/api.do?BBOX=" +
coords[1] + "," + coords[0] + "," + coords[3] + "," + coords[2] +
"&limit=" + RESULTS_PER_PAGE + "&resultPage=" + currPage;
- // System.out.println(urlString);
// Parse the returned XML with a special handler
GpsiesXmlHandler xmlHandler = new GpsiesXmlHandler();
try
@@ -260,7 +96,7 @@ public class GetGpsiesFunction extends GenericFunction implements Runnable
currPage++;
}
while (trackList != null && trackList.size() == RESULTS_PER_PAGE
- && _trackListModel.getRowCount() < MAX_RESULTS && !_cancelled);
+ && _trackListModel.getRowCount() < MAX_RESULTS && !_cancelled);
// Set status label according to error or "none found", leave blank if ok
if (descMessage.equals("") && (trackList == null || trackList.size() == 0)) {
descMessage = I18nManager.getText("dialog.gpsies.nonefound");
@@ -268,11 +104,10 @@ public class GetGpsiesFunction extends GenericFunction implements Runnable
_statusLabel.setText(descMessage);
}
-
/**
- * Load the selected track
+ * Load the selected track or point
*/
- private void loadSelectedTrack()
+ protected void loadSelected()
{
// Find the row selected in the table and get the corresponding track
int rowNum = _trackTable.getSelectedRow();
@@ -293,22 +128,4 @@ public class GetGpsiesFunction extends GenericFunction implements Runnable
_cancelled = true;
_dialog.dispose();
}
-
-
- /**
- * Show the webpage for the selected track
- */
- private void showSelectedTrack()
- {
- // Find the row selected in the table and show the corresponding url
- int rowNum = _trackTable.getSelectedRow();
- if (rowNum >= 0 && rowNum < _trackListModel.getRowCount())
- {
- String id = _trackListModel.getTrack(rowNum).getFileId();
- BrowserLauncher.launchBrowser("http://gpsies.com/map.do?fileId=" + id);
- }
- // Close the dialog
- _cancelled = true;
- _dialog.dispose();
- }
}
diff --git a/tim/prune/function/gpsies/GpsiesTrack.java b/tim/prune/function/gpsies/GpsiesTrack.java
index 7441195..da1339e 100644
--- a/tim/prune/function/gpsies/GpsiesTrack.java
+++ b/tim/prune/function/gpsies/GpsiesTrack.java
@@ -9,8 +9,8 @@ public class GpsiesTrack
private String _trackName = null;
/** Description */
private String _description = null;
- /** File id for more details */
- private String _fileId = null;
+ /** Web page for more details */
+ private String _webUrl = null;
/** Track length in metres */
private double _trackLength = 0.0;
/** Download link */
@@ -50,19 +50,19 @@ public class GpsiesTrack
}
/**
- * @param inId id of track
+ * @param inUrl web page url
*/
- public void setFileId(String inId)
+ public void setWebUrl(String inUrl)
{
- _fileId = inId;
+ _webUrl = inUrl;
}
/**
- * @return file id
+ * @return web url
*/
- public String getFileId()
+ public String getWebUrl()
{
- return _fileId;
+ return _webUrl;
}
/**
diff --git a/tim/prune/function/gpsies/GpsiesXmlHandler.java b/tim/prune/function/gpsies/GpsiesXmlHandler.java
index e639160..3d801be 100644
--- a/tim/prune/function/gpsies/GpsiesXmlHandler.java
+++ b/tim/prune/function/gpsies/GpsiesXmlHandler.java
@@ -11,13 +11,6 @@ import org.xml.sax.helpers.DefaultHandler;
*/
public class GpsiesXmlHandler extends DefaultHandler
{
- private boolean _inTracks = false;
- private boolean _inTrack = false;
- private boolean _inTrackName = false;
- private boolean _inDescription = false;
- private boolean _inFileId = false;
- private boolean _inTrackLength = false;
- private boolean _inLink = false;
private String _value = null;
private ArrayList _trackList = null;
private GpsiesTrack _track = null;
@@ -30,18 +23,12 @@ public class GpsiesXmlHandler extends DefaultHandler
Attributes inAttributes) throws SAXException
{
if (inTagName.equals("tracks")) {
- _inTracks = true;
_trackList = new ArrayList();
}
- else if (_inTracks && inTagName.equals("track")) {
- _inTrack = true;
+ else if (inTagName.equals("track")) {
_track = new GpsiesTrack();
}
- else if (_inTrack && inTagName.equals("title")) {_inTrackName = true;}
- else if (_inTrack && inTagName.equals("description")) {_inDescription = true;}
- else if (_inTrack && inTagName.equals("fileId")) {_inFileId = true;}
- else if (_inTrack && inTagName.equals("trackLengthM")) {_inTrackLength = true;}
- else if (_inTrack && inTagName.equals("downloadLink")) {_inLink = true;}
+ _value = null;
super.startElement(inUri, inLocalName, inTagName, inAttributes);
}
@@ -51,33 +38,26 @@ public class GpsiesXmlHandler extends DefaultHandler
public void endElement(String inUri, String inLocalName, String inTagName)
throws SAXException
{
- if (inTagName.equals("tracks")) {_inTracks = false;}
- else if (_inTrack && inTagName.equals("track")) {
+ if (inTagName.equals("track")) {
_trackList.add(_track);
- _inTrack = false;
}
- else if (_inTrackName && inTagName.equals("title")) {
+ else if (inTagName.equals("title")) {
_track.setTrackName(_value);
- _inTrackName = false;
}
- else if (_inDescription && inTagName.equals("description")) {
+ else if (inTagName.equals("description")) {
_track.setDescription(_value);
- _inDescription = false;
}
- else if (_inFileId && inTagName.equals("fileId")) {
- _track.setFileId(_value);
- _inFileId = false;
+ else if (inTagName.equals("fileId")) {
+ _track.setWebUrl("http://gpsies.com/map.do?fileId=" + _value);
}
- else if (_inTrackLength && inTagName.equals("trackLengthM")) {
+ else if (inTagName.equals("trackLengthM")) {
try {
_track.setLength(Double.parseDouble(_value));
}
catch (NumberFormatException nfe) {}
- _inTrackLength = false;
}
- else if (_inLink && inTagName.equals("downloadLink")) {
+ else if (inTagName.equals("downloadLink")) {
_track.setDownloadLink(_value);
- _inLink = false;
}
super.endElement(inUri, inLocalName, inTagName);
}
@@ -88,9 +68,8 @@ public class GpsiesXmlHandler extends DefaultHandler
public void characters(char[] inCh, int inStart, int inLength)
throws SAXException
{
- _value = new String(inCh, inStart, inLength);
- // System.out.println("Value: '" + value + "'");
- // TODO: Note, this doesn't cope well with split characters for really long descriptions etc
+ String value = new String(inCh, inStart, inLength);
+ _value = (_value==null?value:_value+value);
super.characters(inCh, inStart, inLength);
}
diff --git a/tim/prune/function/gpsies/TrackListModel.java b/tim/prune/function/gpsies/TrackListModel.java
index 3bdeb16..3a7326f 100644
--- a/tim/prune/function/gpsies/TrackListModel.java
+++ b/tim/prune/function/gpsies/TrackListModel.java
@@ -17,17 +17,26 @@ public class TrackListModel extends AbstractTableModel
/** List of tracks */
private ArrayList _trackList = null;
/** Column heading for track name */
- private static final String _nameColLabel = I18nManager.getText("dialog.gpsies.column.name");
+ private String _nameColLabel = null;
/** Column heading for length */
- private static final String _lengthColLabel = I18nManager.getText("dialog.gpsies.column.length");
+ private String _lengthColLabel = null;
+ /** Number of columns */
+ private int _numColumns = 2;
/** Formatter for distances */
private NumberFormat _distanceFormatter = NumberFormat.getInstance();
/**
* Constructor
+ * @param inColumn1Key key for first column
+ * @param inColumn2Key key for second column
*/
- public TrackListModel()
+ public TrackListModel(String inColumn1Key, String inColumn2Key)
{
+ _nameColLabel = I18nManager.getText(inColumn1Key);
+ if (inColumn2Key != null) {
+ _lengthColLabel = I18nManager.getText(inColumn2Key);
+ }
+ _numColumns = (_lengthColLabel != null?2:1);
_distanceFormatter.setMaximumFractionDigits(1);
}
@@ -36,7 +45,7 @@ public class TrackListModel extends AbstractTableModel
*/
public int getColumnCount()
{
- return 2;
+ return _numColumns;
}
/**
diff --git a/tim/prune/function/gpsies/UploadGpsiesFunction.java b/tim/prune/function/gpsies/UploadGpsiesFunction.java
index 6bd762f..49bd000 100644
--- a/tim/prune/function/gpsies/UploadGpsiesFunction.java
+++ b/tim/prune/function/gpsies/UploadGpsiesFunction.java
@@ -250,6 +250,7 @@ public class UploadGpsiesFunction extends GenericFunction
*/
private void startUpload()
{
+ BufferedReader reader = null;
try
{
FormPoster poster = new FormPoster(new URL(GPSIES_URL));
@@ -277,12 +278,12 @@ public class UploadGpsiesFunction extends GenericFunction
_writer = new OutputStreamWriter(oStream);
new Thread(new Runnable() {
public void run() {
- boolean[] saveFlags = {true, true, true, false, true}; // export everything
+ boolean[] saveFlags = {true, true, true, true, false, true}; // export everything
try {
GpxExporter.exportData(_writer, _app.getTrackInfo(), _nameField.getText(), null, saveFlags, false);
- _writer.close();
- } catch (IOException e) {
- e.printStackTrace();
+ } catch (IOException e) {}
+ finally {
+ try {_writer.close();} catch (IOException e) {}
}
}
}).start();
@@ -290,7 +291,7 @@ public class UploadGpsiesFunction extends GenericFunction
BufferedInputStream answer = new BufferedInputStream(poster.post());
int response = poster.getResponseCode();
- BufferedReader reader = new BufferedReader(new InputStreamReader(answer));
+ reader = new BufferedReader(new InputStreamReader(answer));
String line = reader.readLine();
// Try to extract gpsies page url from the returned message
String pageUrl = null;
@@ -321,6 +322,9 @@ public class UploadGpsiesFunction extends GenericFunction
_app.showErrorMessageNoLookup(getNameKey(), I18nManager.getText("error.gpsies.uploadfailed") + ": "
+ ioe.getClass().getName() + " : " + ioe.getMessage());
}
+ finally {
+ try {if (reader != null) reader.close();} catch (IOException e) {}
+ }
_dialog.dispose();
}
}
diff --git a/tim/prune/gui/AudioListener.java b/tim/prune/gui/AudioListener.java
new file mode 100644
index 0000000..fe1e933
--- /dev/null
+++ b/tim/prune/gui/AudioListener.java
@@ -0,0 +1,52 @@
+package tim.prune.gui;
+
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+
+import javax.swing.JProgressBar;
+
+import tim.prune.FunctionLibrary;
+import tim.prune.function.PlayAudioFunction;
+
+/**
+ * Class to update the supplied progress bar on the basis of
+ * the currently playing audio file (if any)
+ */
+public class AudioListener implements Runnable, ActionListener
+{
+ /** progress bar */
+ private JProgressBar _progressBar = null;
+
+ /**
+ * Constructor
+ * @param inBar progress bar object to update
+ */
+ public AudioListener(JProgressBar inBar) {
+ _progressBar = inBar;
+ }
+
+ /**
+ * React to button press
+ */
+ public void actionPerformed(ActionEvent inEvent) {
+ new Thread(this).start();
+ }
+
+ /**
+ * Loop and update progress bar
+ */
+ public void run()
+ {
+ int progress = 0;
+ while (progress >= 0)
+ {
+ try {
+ Thread.sleep(400);
+ }
+ catch (InterruptedException e) {}
+ progress = ((PlayAudioFunction) FunctionLibrary.FUNCTION_PLAY_AUDIO).getPercentage();
+ _progressBar.setVisible(progress >= 0);
+ _progressBar.setValue(progress);
+ }
+ }
+}
diff --git a/tim/prune/gui/DetailsDisplay.java b/tim/prune/gui/DetailsDisplay.java
index 9cfd7ce..dee14a9 100644
--- a/tim/prune/gui/DetailsDisplay.java
+++ b/tim/prune/gui/DetailsDisplay.java
@@ -3,6 +3,7 @@ package tim.prune.gui;
import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.Dimension;
+import java.awt.FlowLayout;
import java.awt.Font;
import java.awt.Insets;
import java.awt.event.ActionEvent;
@@ -16,6 +17,7 @@ import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JLabel;
import javax.swing.JPanel;
+import javax.swing.JProgressBar;
import javax.swing.border.EtchedBorder;
import tim.prune.DataSubscriber;
@@ -25,6 +27,7 @@ import tim.prune.I18nManager;
import tim.prune.UpdateMessageBroker;
import tim.prune.config.Config;
import tim.prune.data.Altitude;
+import tim.prune.data.AudioFile;
import tim.prune.data.Coordinate;
import tim.prune.data.DataPoint;
import tim.prune.data.Distance;
@@ -55,12 +58,22 @@ public class DetailsDisplay extends GenericDisplay
private JLabel _aveSpeedLabel = null;
// Photo details
+ private JPanel _photoDetailsPanel = null;
private JLabel _photoLabel = null;
private PhotoThumbnail _photoThumbnail = null;
private JLabel _photoTimestampLabel = null;
private JLabel _photoConnectedLabel = null;
private JPanel _rotationButtons = null;
+ // Audio details
+ private JPanel _audioDetailsPanel = null;
+ private JLabel _audioLabel = null;
+ private JLabel _audioConnectedLabel = null;
+ private JLabel _audioTimestampLabel = null;
+ private JLabel _audioLengthLabel = null;
+ private JProgressBar _audioProgress = null;
+ private JPanel _playAudioPanel = null;
+
// Units
private JComboBox _coordFormatDropdown = null;
private JComboBox _distUnitsDropdown = null;
@@ -81,6 +94,7 @@ public class DetailsDisplay extends GenericDisplay
private static final String LABEL_RANGE_ALTITUDE = I18nManager.getText("fieldname.altitude") + ": ";
private static final String LABEL_RANGE_CLIMB = I18nManager.getText("details.range.climb") + ": ";
private static final String LABEL_RANGE_DESCENT = ", " + I18nManager.getText("details.range.descent") + ": ";
+ private static final String LABEL_AUDIO_FILE = I18nManager.getText("details.audio.file") + ": ";
private static String LABEL_POINT_ALTITUDE_UNITS = null;
private static Altitude.Format LABEL_POINT_ALTITUDE_FORMAT = Altitude.Format.NO_FORMAT;
@@ -97,18 +111,11 @@ public class DetailsDisplay extends GenericDisplay
JPanel mainPanel = new JPanel();
mainPanel.setLayout(new BoxLayout(mainPanel, BoxLayout.Y_AXIS));
mainPanel.setBorder(BorderFactory.createEmptyBorder(3, 3, 3, 3));
+ Font biggerFont = new JLabel().getFont();
+ biggerFont = biggerFont.deriveFont(Font.BOLD, biggerFont.getSize2D() + 2.0f);
// Point details panel
- JPanel pointDetailsPanel = new JPanel();
- pointDetailsPanel.setLayout(new BoxLayout(pointDetailsPanel, BoxLayout.Y_AXIS));
- pointDetailsPanel.setBorder(BorderFactory.createCompoundBorder(
- BorderFactory.createEtchedBorder(EtchedBorder.LOWERED), BorderFactory.createEmptyBorder(3, 3, 3, 3))
- );
- JLabel pointDetailsLabel = new JLabel(I18nManager.getText("details.pointdetails"));
- Font biggerFont = pointDetailsLabel.getFont();
- biggerFont = biggerFont.deriveFont(Font.BOLD, biggerFont.getSize2D() + 2.0f);
- pointDetailsLabel.setFont(biggerFont);
- pointDetailsPanel.add(pointDetailsLabel);
+ JPanel pointDetailsPanel = makeDetailsPanel("details.pointdetails", biggerFont);
_indexLabel = new JLabel(I18nManager.getText("details.nopointselection"));
pointDetailsPanel.add(_indexLabel);
_latLabel = new JLabel("");
@@ -118,6 +125,7 @@ public class DetailsDisplay extends GenericDisplay
_altLabel = new JLabel("");
pointDetailsPanel.add(_altLabel);
_timeLabel = new JLabel("");
+ _timeLabel.setMinimumSize(new Dimension(120, 10));
pointDetailsPanel.add(_timeLabel);
_speedLabel = new JLabel("");
pointDetailsPanel.add(_speedLabel);
@@ -128,14 +136,7 @@ public class DetailsDisplay extends GenericDisplay
pointDetailsPanel.setAlignmentX(Component.LEFT_ALIGNMENT);
// range details panel
- JPanel rangeDetailsPanel = new JPanel();
- rangeDetailsPanel.setLayout(new BoxLayout(rangeDetailsPanel, BoxLayout.Y_AXIS));
- rangeDetailsPanel.setBorder(BorderFactory.createCompoundBorder(
- BorderFactory.createEtchedBorder(EtchedBorder.LOWERED), BorderFactory.createEmptyBorder(3, 3, 3, 3))
- );
- JLabel rangeDetailsLabel = new JLabel(I18nManager.getText("details.rangedetails"));
- rangeDetailsLabel.setFont(biggerFont);
- rangeDetailsPanel.add(rangeDetailsLabel);
+ JPanel rangeDetailsPanel = makeDetailsPanel("details.rangedetails", biggerFont);
_rangeLabel = new JLabel(I18nManager.getText("details.norangeselection"));
rangeDetailsPanel.add(_rangeLabel);
_distanceLabel = new JLabel("");
@@ -151,40 +152,68 @@ public class DetailsDisplay extends GenericDisplay
rangeDetailsPanel.setAlignmentX(Component.LEFT_ALIGNMENT);
// photo details panel
- JPanel photoDetailsPanel = new JPanel();
- photoDetailsPanel.setLayout(new BoxLayout(photoDetailsPanel, BoxLayout.Y_AXIS));
- photoDetailsPanel.setBorder(BorderFactory.createCompoundBorder(
- BorderFactory.createEtchedBorder(EtchedBorder.LOWERED), BorderFactory.createEmptyBorder(3, 3, 3, 3))
- );
- JLabel photoDetailsLabel = new JLabel(I18nManager.getText("details.photodetails"));
- photoDetailsLabel.setFont(biggerFont);
- photoDetailsPanel.add(photoDetailsLabel);
+ _photoDetailsPanel = makeDetailsPanel("details.photodetails", biggerFont);
_photoLabel = new JLabel(I18nManager.getText("details.nophoto"));
- photoDetailsPanel.add(_photoLabel);
+ _photoDetailsPanel.add(_photoLabel);
_photoTimestampLabel = new JLabel("");
- photoDetailsPanel.add(_photoTimestampLabel);
+ _photoTimestampLabel.setMinimumSize(new Dimension(120, 10));
+ _photoDetailsPanel.add(_photoTimestampLabel);
_photoConnectedLabel = new JLabel("");
- photoDetailsPanel.add(_photoConnectedLabel);
+ _photoDetailsPanel.add(_photoConnectedLabel);
_photoThumbnail = new PhotoThumbnail();
_photoThumbnail.setVisible(false);
_photoThumbnail.setPreferredSize(new Dimension(100, 100));
- photoDetailsPanel.add(_photoThumbnail);
+ _photoDetailsPanel.add(_photoThumbnail);
// Rotate buttons
JButton rotLeft = makeRotateButton(IconManager.ROTATE_LEFT, FunctionLibrary.FUNCTION_ROTATE_PHOTO_LEFT);
JButton rotRight = makeRotateButton(IconManager.ROTATE_RIGHT, FunctionLibrary.FUNCTION_ROTATE_PHOTO_RIGHT);
+ JButton popup = makeRotateButton(IconManager.SHOW_DETAILS, FunctionLibrary.FUNCTION_PHOTO_POPUP);
_rotationButtons = new JPanel();
_rotationButtons.add(rotLeft);
_rotationButtons.add(rotRight);
+ _rotationButtons.add(Box.createHorizontalStrut(10));
+ _rotationButtons.add(popup);
_rotationButtons.setAlignmentX(Component.LEFT_ALIGNMENT);
_rotationButtons.setVisible(false);
- photoDetailsPanel.add(_rotationButtons);
+ _photoDetailsPanel.add(_rotationButtons);
+ _photoDetailsPanel.setVisible(false);
+
+ // audio details panel
+ _audioDetailsPanel = makeDetailsPanel("details.audiodetails", biggerFont);
+ _audioLabel = new JLabel(I18nManager.getText("details.noaudio"));
+ _audioDetailsPanel.add(_audioLabel);
+ _audioTimestampLabel = new JLabel("");
+ _audioTimestampLabel.setMinimumSize(new Dimension(120, 10));
+ _audioDetailsPanel.add(_audioTimestampLabel);
+ _audioLengthLabel = new JLabel("");
+ _audioDetailsPanel.add(_audioLengthLabel);
+ _audioConnectedLabel = new JLabel("");
+ _audioDetailsPanel.add(_audioConnectedLabel);
+ _audioProgress = new JProgressBar(0, 100);
+ _audioProgress.setString(I18nManager.getText("details.audio.playing"));
+ _audioProgress.setStringPainted(true);
+ _audioProgress.setVisible(false);
+ _audioDetailsPanel.add(_audioProgress);
+ _playAudioPanel = new JPanel();
+ _playAudioPanel.setLayout(new FlowLayout(FlowLayout.RIGHT));
+ JButton playAudio = makeRotateButton(IconManager.PLAY_AUDIO, FunctionLibrary.FUNCTION_PLAY_AUDIO);
+ playAudio.addActionListener(new AudioListener(_audioProgress));
+ _playAudioPanel.add(playAudio);
+ JButton stopAudio = makeRotateButton(IconManager.STOP_AUDIO, FunctionLibrary.FUNCTION_STOP_AUDIO);
+ _playAudioPanel.add(stopAudio);
+ _playAudioPanel.setAlignmentX(Component.LEFT_ALIGNMENT);
+ _playAudioPanel.setVisible(false);
+ _audioDetailsPanel.add(_playAudioPanel);
+ _audioDetailsPanel.setVisible(false);
// add the details panels to the main panel
mainPanel.add(pointDetailsPanel);
mainPanel.add(Box.createVerticalStrut(5));
mainPanel.add(rangeDetailsPanel);
mainPanel.add(Box.createVerticalStrut(5));
- mainPanel.add(photoDetailsPanel);
+ mainPanel.add(_photoDetailsPanel);
+ mainPanel.add(Box.createVerticalStrut(5));
+ mainPanel.add(_audioDetailsPanel);
mainPanel.add(Box.createVerticalStrut(5));
// add the main panel at the top
add(mainPanel, BorderLayout.NORTH);
@@ -234,6 +263,7 @@ public class DetailsDisplay extends GenericDisplay
// Update current point data, if any
DataPoint currentPoint = _trackInfo.getCurrentPoint();
Selection selection = _trackInfo.getSelection();
+ if ((inUpdateType | DATA_ADDED_OR_REMOVED) > 0) selection.markInvalid();
int currentPointIndex = selection.getCurrentPointIndex();
_speedLabel.setText("");
Distance.Units distUnits = _distUnitsDropdown.getSelectedIndex()==0?Distance.Units.KILOMETRES:Distance.Units.MILES;
@@ -343,6 +373,7 @@ public class DetailsDisplay extends GenericDisplay
}
}
// show photo details and thumbnail
+ _photoDetailsPanel.setVisible(_trackInfo.getPhotoList().getNumPhotos() > 0);
Photo currentPhoto = _trackInfo.getPhotoList().getPhoto(_trackInfo.getSelection().getCurrentPhotoIndex());
if ((currentPoint == null || currentPoint.getPhoto() == null) && currentPhoto == null)
{
@@ -358,7 +389,7 @@ public class DetailsDisplay extends GenericDisplay
if (currentPhoto == null) {currentPhoto = currentPoint.getPhoto();}
_photoLabel.setText(I18nManager.getText("details.photofile") + ": " + currentPhoto.getFile().getName());
_photoTimestampLabel.setText(LABEL_POINT_TIMESTAMP + currentPhoto.getTimestamp().getText());
- _photoConnectedLabel.setText(I18nManager.getText("details.photo.connected") + ": "
+ _photoConnectedLabel.setText(I18nManager.getText("details.media.connected") + ": "
+ (currentPhoto.getCurrentStatus() == Photo.Status.NOT_CONNECTED ?
I18nManager.getText("dialog.about.no"):I18nManager.getText("dialog.about.yes")));
_photoThumbnail.setVisible(true);
@@ -367,6 +398,27 @@ public class DetailsDisplay extends GenericDisplay
if ((inUpdateType & DataSubscriber.PHOTOS_MODIFIED) > 0) {_photoThumbnail.refresh();}
}
_photoThumbnail.repaint();
+
+ // audio details
+ _audioDetailsPanel.setVisible(_trackInfo.getAudioList().getNumAudios() > 0);
+ AudioFile currentAudio = _trackInfo.getAudioList().getAudio(_trackInfo.getSelection().getCurrentAudioIndex());
+ if (currentAudio == null) {
+ _audioLabel.setText(I18nManager.getText("details.noaudio"));
+ _audioTimestampLabel.setText("");
+ _audioLengthLabel.setText("");
+ _audioConnectedLabel.setText("");
+ }
+ else
+ {
+ _audioLabel.setText(LABEL_AUDIO_FILE + currentAudio.getFile().getName());
+ _audioTimestampLabel.setText(LABEL_POINT_TIMESTAMP + currentAudio.getTimestamp().getText());
+ int audioLength = currentAudio.getLengthInSeconds();
+ _audioLengthLabel.setText(audioLength < 0?"":LABEL_RANGE_DURATION + DisplayUtils.buildDurationString(audioLength));
+ _audioConnectedLabel.setText(I18nManager.getText("details.media.connected") + ": "
+ + (currentAudio.getCurrentStatus() == Photo.Status.NOT_CONNECTED ?
+ I18nManager.getText("dialog.about.no"):I18nManager.getText("dialog.about.yes")));
+ }
+ _playAudioPanel.setVisible(currentAudio != null);
}
@@ -455,6 +507,25 @@ public class DetailsDisplay extends GenericDisplay
return inCoord;
}
+ /**
+ * Make a details subpanel
+ * @param inNameKey key to use for top label
+ * @param inFont font for top label
+ * @return panel with correct layout, label
+ */
+ private static JPanel makeDetailsPanel(String inNameKey, Font inFont)
+ {
+ JPanel detailsPanel = new JPanel();
+ detailsPanel.setLayout(new BoxLayout(detailsPanel, BoxLayout.Y_AXIS));
+ detailsPanel.setBorder(BorderFactory.createCompoundBorder(
+ BorderFactory.createEtchedBorder(EtchedBorder.LOWERED), BorderFactory.createEmptyBorder(3, 3, 3, 3))
+ );
+ JLabel detailsLabel = new JLabel(I18nManager.getText(inNameKey));
+ detailsLabel.setFont(inFont);
+ detailsPanel.add(detailsLabel);
+ return detailsPanel;
+ }
+
/**
* Create a little button for rotating the current photo
* @param inIcon icon to use (from IconManager)
diff --git a/tim/prune/gui/DialogCloser.java b/tim/prune/gui/DialogCloser.java
new file mode 100644
index 0000000..1085545
--- /dev/null
+++ b/tim/prune/gui/DialogCloser.java
@@ -0,0 +1,33 @@
+package tim.prune.gui;
+
+import java.awt.event.KeyAdapter;
+import java.awt.event.KeyEvent;
+
+import javax.swing.JDialog;
+
+/**
+ * Convenience class to close a dialog when the escape key is pressed
+ */
+public class DialogCloser extends KeyAdapter
+{
+ /** dialog to close */
+ private JDialog _dialog = null;
+
+ /**
+ * Constructor
+ * @param inDialog dialog to close
+ */
+ public DialogCloser(JDialog inDialog) {
+ _dialog = inDialog;
+ }
+
+ /**
+ * React to the release of the escape key
+ */
+ public void keyReleased(KeyEvent e)
+ {
+ if (e.getKeyCode() == KeyEvent.VK_ESCAPE) {
+ _dialog.dispose();
+ }
+ }
+}
diff --git a/tim/prune/gui/IconManager.java b/tim/prune/gui/IconManager.java
index a42d759..858e97a 100644
--- a/tim/prune/gui/IconManager.java
+++ b/tim/prune/gui/IconManager.java
@@ -60,6 +60,12 @@ public abstract class IconManager
public static final String ROTATE_LEFT = "rotate_left_icon.png";
/** Icon for rotating photos rightwards */
public static final String ROTATE_RIGHT = "rotate_right_icon.png";
+ /** Icon for showing photo popup */
+ public static final String SHOW_DETAILS = "show_details_icon.gif";
+ /** Icon for playing audio file */
+ public static final String PLAY_AUDIO = "play_audio.gif";
+ /** Icon for stopping the current audio file */
+ public static final String STOP_AUDIO = "stop_audio.gif";
/**
* Get the specified image
diff --git a/tim/prune/gui/MediaListModel.java b/tim/prune/gui/MediaListModel.java
new file mode 100644
index 0000000..2d8eb6e
--- /dev/null
+++ b/tim/prune/gui/MediaListModel.java
@@ -0,0 +1,47 @@
+package tim.prune.gui;
+
+import javax.swing.AbstractListModel;
+
+import tim.prune.data.MediaFile;
+import tim.prune.data.MediaList;
+
+/**
+ * Class to act as list model for the photo list and audio list
+ */
+public class MediaListModel extends AbstractListModel
+{
+ /** media list */
+ MediaList _media = null;
+
+ /**
+ * Constructor giving MediaList object
+ * @param inList MediaList
+ */
+ public MediaListModel(MediaList inList) {
+ _media = inList;
+ }
+
+ /**
+ * @see javax.swing.ListModel#getSize()
+ */
+ public int getSize() {
+ return _media.getNumMedia();
+ }
+
+ /**
+ * @see javax.swing.ListModel#getElementAt(int)
+ */
+ public Object getElementAt(int inIndex)
+ {
+ MediaFile m = _media.getMedia(inIndex);
+ // * means modified since loading
+ return (m.getCurrentStatus() == m.getOriginalStatus()?"":"* ") + m.getFile().getName();
+ }
+
+ /**
+ * Fire event to notify that contents have changed
+ */
+ public void fireChanged() {
+ this.fireContentsChanged(this, 0, getSize()-1);
+ }
+}
diff --git a/tim/prune/gui/MenuManager.java b/tim/prune/gui/MenuManager.java
index 588b49e..47044f2 100644
--- a/tim/prune/gui/MenuManager.java
+++ b/tim/prune/gui/MenuManager.java
@@ -20,8 +20,8 @@ import tim.prune.GenericFunction;
import tim.prune.I18nManager;
import tim.prune.UpdateMessageBroker;
import tim.prune.config.Config;
+import tim.prune.data.AudioFile;
import tim.prune.data.Photo;
-import tim.prune.data.PhotoList;
import tim.prune.data.Selection;
import tim.prune.data.Track;
import tim.prune.data.TrackInfo;
@@ -37,7 +37,6 @@ public class MenuManager implements DataSubscriber
private App _app = null;
private Track _track = null;
private Selection _selection = null;
- private PhotoList _photos = null;
// Menu items which need enabling/disabling
private JMenuItem _sendGpsItem = null;
@@ -77,18 +76,26 @@ public class MenuManager implements DataSubscriber
private JMenuItem _getGpsiesItem = null;
private JMenuItem _uploadGpsiesItem = null;
private JMenuItem _lookupSrtmItem = null;
+ private JMenuItem _lookupWikipediaItem = null;
+ private JMenuItem _downloadOsmItem = null;
private JMenuItem _distanceItem = null;
private JMenuItem _fullRangeDetailsItem = null;
private JMenuItem _saveExifItem = null;
+ private JMenuItem _photoPopupItem = null;
private JMenuItem _selectNoPhotoItem = null;
private JMenuItem _connectPhotoItem = null;
- private JMenuItem _deletePhotoItem = null;
+ private JMenuItem _removePhotoItem = null;
private JMenuItem _disconnectPhotoItem = null;
private JMenuItem _correlatePhotosItem = null;
private JMenuItem _rearrangePhotosItem = null;
private JMenuItem _rotatePhotoLeft = null;
private JMenuItem _rotatePhotoRight = null;
private JMenuItem _ignoreExifThumb = null;
+ private JMenuItem _connectAudioItem = null;
+ private JMenuItem _disconnectAudioItem = null;
+ private JMenuItem _removeAudioItem = null;
+ private JMenuItem _correlateAudiosItem = null;
+ private JMenuItem _selectNoAudioItem = null;
private JCheckBoxMenuItem _onlineCheckbox = null;
// ActionListeners for reuse by menu and toolbar
@@ -101,7 +108,6 @@ public class MenuManager implements DataSubscriber
private ActionListener _deleteRangeAction = null;
private ActionListener _selectStartAction = null;
private ActionListener _selectEndAction = null;
- private ActionListener _connectPhotoAction = null;
// Toolbar buttons which need enabling/disabling
private JButton _saveButton = null;
@@ -111,7 +117,7 @@ public class MenuManager implements DataSubscriber
private JButton _deleteRangeButton = null;
private JButton _selectStartButton = null;
private JButton _selectEndButton = null;
- private JButton _connectPhotoButton = null;
+ private JButton _connectButton = null;
/** Array of key events */
private static final int[] KEY_EVENTS = {
@@ -132,7 +138,6 @@ public class MenuManager implements DataSubscriber
_app = inApp;
_track = inTrackInfo.getTrack();
_selection = inTrackInfo.getSelection();
- _photos = inTrackInfo.getPhotoList();
}
@@ -149,8 +154,7 @@ public class MenuManager implements DataSubscriber
JMenuItem openMenuItem = new JMenuItem(I18nManager.getText("function.open"));
setShortcut(openMenuItem, "shortcut.menu.file.open");
_openFileAction = new ActionListener() {
- public void actionPerformed(ActionEvent e)
- {
+ public void actionPerformed(ActionEvent e) {
_app.openFile();
}
};
@@ -159,29 +163,29 @@ public class MenuManager implements DataSubscriber
// Add photos
JMenuItem addPhotosMenuItem = new JMenuItem(I18nManager.getText("menu.file.addphotos"));
_addPhotoAction = new ActionListener() {
- public void actionPerformed(ActionEvent e)
- {
+ public void actionPerformed(ActionEvent e) {
_app.addPhotos();
}
};
addPhotosMenuItem.addActionListener(_addPhotoAction);
fileMenu.add(addPhotosMenuItem);
+ // Add audio files
+ JMenuItem addAudioMenuItem = makeMenuItem(FunctionLibrary.FUNCTION_LOAD_AUDIO);
+ fileMenu.add(addAudioMenuItem);
fileMenu.addSeparator();
// Load from GPS
JMenuItem loadFromGpsMenuItem = makeMenuItem(FunctionLibrary.FUNCTION_GPSLOAD);
setShortcut(loadFromGpsMenuItem, "shortcut.menu.file.load");
fileMenu.add(loadFromGpsMenuItem);
// Send to GPS
- _sendGpsItem = makeMenuItem(FunctionLibrary.FUNCTION_GPSSAVE);
- _sendGpsItem.setEnabled(false);
+ _sendGpsItem = makeMenuItem(FunctionLibrary.FUNCTION_GPSSAVE, false);
fileMenu.add(_sendGpsItem);
fileMenu.addSeparator();
// Save
_saveItem = new JMenuItem(I18nManager.getText("menu.file.save"), KeyEvent.VK_S);
setShortcut(_saveItem, "shortcut.menu.file.save");
_saveAction = new ActionListener() {
- public void actionPerformed(ActionEvent e)
- {
+ public void actionPerformed(ActionEvent e) {
_app.saveFile();
}
};
@@ -189,26 +193,21 @@ public class MenuManager implements DataSubscriber
_saveItem.setEnabled(false);
fileMenu.add(_saveItem);
// Export - Kml
- _exportKmlItem = makeMenuItem(FunctionLibrary.FUNCTION_KMLEXPORT);
- _exportKmlItem.setEnabled(false);
+ _exportKmlItem = makeMenuItem(FunctionLibrary.FUNCTION_KMLEXPORT, false);
fileMenu.add(_exportKmlItem);
// Gpx
- _exportGpxItem = makeMenuItem(FunctionLibrary.FUNCTION_GPXEXPORT);
- _exportGpxItem.setEnabled(false);
+ _exportGpxItem = makeMenuItem(FunctionLibrary.FUNCTION_GPXEXPORT, false);
fileMenu.add(_exportGpxItem);
// Pov
- _exportPovItem = makeMenuItem(FunctionLibrary.FUNCTION_POVEXPORT);
- _exportPovItem.setEnabled(false);
+ _exportPovItem = makeMenuItem(FunctionLibrary.FUNCTION_POVEXPORT, false);
fileMenu.add(_exportPovItem);
// Svg
- _exportSvgItem = makeMenuItem(FunctionLibrary.FUNCTION_SVGEXPORT);
- _exportSvgItem.setEnabled(false);
+ _exportSvgItem = makeMenuItem(FunctionLibrary.FUNCTION_SVGEXPORT, false);
fileMenu.add(_exportSvgItem);
fileMenu.addSeparator();
JMenuItem exitMenuItem = new JMenuItem(I18nManager.getText("menu.file.exit"));
exitMenuItem.addActionListener(new ActionListener() {
- public void actionPerformed(ActionEvent e)
- {
+ public void actionPerformed(ActionEvent e) {
_app.exit();
}
});
@@ -220,8 +219,7 @@ public class MenuManager implements DataSubscriber
_undoItem = new JMenuItem(I18nManager.getText("menu.track.undo"));
setShortcut(_undoItem, "shortcut.menu.track.undo");
_undoAction = new ActionListener() {
- public void actionPerformed(ActionEvent e)
- {
+ public void actionPerformed(ActionEvent e) {
_app.beginUndo();
}
};
@@ -230,22 +228,19 @@ public class MenuManager implements DataSubscriber
trackMenu.add(_undoItem);
_clearUndoItem = new JMenuItem(I18nManager.getText("menu.track.clearundo"));
_clearUndoItem.addActionListener(new ActionListener() {
- public void actionPerformed(ActionEvent e)
- {
+ public void actionPerformed(ActionEvent e) {
_app.clearUndo();
}
});
_clearUndoItem.setEnabled(false);
trackMenu.add(_clearUndoItem);
trackMenu.addSeparator();
- _compressItem = makeMenuItem(FunctionLibrary.FUNCTION_COMPRESS);
+ _compressItem = makeMenuItem(FunctionLibrary.FUNCTION_COMPRESS, false);
setShortcut(_compressItem, "shortcut.menu.edit.compress");
- _compressItem.setEnabled(false);
trackMenu.add(_compressItem);
_deleteMarkedPointsItem = new JMenuItem(I18nManager.getText("menu.track.deletemarked"));
_deleteMarkedPointsItem.addActionListener(new ActionListener() {
- public void actionPerformed(ActionEvent e)
- {
+ public void actionPerformed(ActionEvent e) {
_app.finishCompressTrack();
}
});
@@ -257,8 +252,7 @@ public class MenuManager implements DataSubscriber
_rearrangeMenu.setEnabled(false);
JMenuItem rearrangeStartItem = new JMenuItem(I18nManager.getText("menu.track.rearrange.start"));
rearrangeStartItem.addActionListener(new ActionListener() {
- public void actionPerformed(ActionEvent e)
- {
+ public void actionPerformed(ActionEvent e) {
FunctionLibrary.FUNCTION_REARRANGE_WAYPOINTS.rearrangeWaypoints(Rearrange.TO_START);
}
});
@@ -266,8 +260,7 @@ public class MenuManager implements DataSubscriber
_rearrangeMenu.add(rearrangeStartItem);
JMenuItem rearrangeEndItem = new JMenuItem(I18nManager.getText("menu.track.rearrange.end"));
rearrangeEndItem.addActionListener(new ActionListener() {
- public void actionPerformed(ActionEvent e)
- {
+ public void actionPerformed(ActionEvent e) {
FunctionLibrary.FUNCTION_REARRANGE_WAYPOINTS.rearrangeWaypoints(Rearrange.TO_END);
}
});
@@ -275,8 +268,7 @@ public class MenuManager implements DataSubscriber
_rearrangeMenu.add(rearrangeEndItem);
JMenuItem rearrangeNearestItem = new JMenuItem(I18nManager.getText("menu.track.rearrange.nearest"));
rearrangeNearestItem.addActionListener(new ActionListener() {
- public void actionPerformed(ActionEvent e)
- {
+ public void actionPerformed(ActionEvent e) {
FunctionLibrary.FUNCTION_REARRANGE_WAYPOINTS.rearrangeWaypoints(Rearrange.TO_NEAREST);
}
});
@@ -284,16 +276,19 @@ public class MenuManager implements DataSubscriber
_rearrangeMenu.add(rearrangeNearestItem);
trackMenu.add(_rearrangeMenu);
// Get gpsies tracks
- _getGpsiesItem = makeMenuItem(FunctionLibrary.FUNCTION_GET_GPSIES);
- _getGpsiesItem.setEnabled(false);
+ _getGpsiesItem = makeMenuItem(FunctionLibrary.FUNCTION_GET_GPSIES, false);
trackMenu.add(_getGpsiesItem);
// Upload to gpsies
- _uploadGpsiesItem = makeMenuItem(FunctionLibrary.FUNCTION_UPLOAD_GPSIES);
- _uploadGpsiesItem.setEnabled(false);
+ _uploadGpsiesItem = makeMenuItem(FunctionLibrary.FUNCTION_UPLOAD_GPSIES, false);
trackMenu.add(_uploadGpsiesItem);
- _lookupSrtmItem = makeMenuItem(FunctionLibrary.FUNCTION_LOOKUP_SRTM);
- _lookupSrtmItem.setEnabled(false);
+ _lookupSrtmItem = makeMenuItem(FunctionLibrary.FUNCTION_LOOKUP_SRTM, false);
trackMenu.add(_lookupSrtmItem);
+ _lookupWikipediaItem = makeMenuItem(FunctionLibrary.FUNCTION_LOOKUP_WIKIPEDIA, false);
+ trackMenu.add(_lookupWikipediaItem);
+ JMenuItem searchWikipediaNamesItem = makeMenuItem(FunctionLibrary.FUNCTION_SEARCH_WIKIPEDIA);
+ trackMenu.add(searchWikipediaNamesItem);
+ _downloadOsmItem = makeMenuItem(FunctionLibrary.FUNCTION_DOWNLOAD_OSM, false);
+ trackMenu.add(_downloadOsmItem);
menubar.add(trackMenu);
// Range menu
@@ -303,8 +298,7 @@ public class MenuManager implements DataSubscriber
setShortcut(_selectAllItem, "shortcut.menu.range.all");
_selectAllItem.setEnabled(false);
_selectAllItem.addActionListener(new ActionListener() {
- public void actionPerformed(ActionEvent e)
- {
+ public void actionPerformed(ActionEvent e) {
_selection.selectRange(0, _track.getNumPoints()-1);
}
});
@@ -312,8 +306,7 @@ public class MenuManager implements DataSubscriber
_selectNoneItem = new JMenuItem(I18nManager.getText("menu.range.none"));
_selectNoneItem.setEnabled(false);
_selectNoneItem.addActionListener(new ActionListener() {
- public void actionPerformed(ActionEvent e)
- {
+ public void actionPerformed(ActionEvent e) {
_app.selectNone();
}
});
@@ -322,8 +315,7 @@ public class MenuManager implements DataSubscriber
_selectStartItem = new JMenuItem(I18nManager.getText("menu.range.start"));
_selectStartItem.setEnabled(false);
_selectStartAction = new ActionListener() {
- public void actionPerformed(ActionEvent e)
- {
+ public void actionPerformed(ActionEvent e) {
_selection.selectRangeStart();
}
};
@@ -332,8 +324,7 @@ public class MenuManager implements DataSubscriber
_selectEndItem = new JMenuItem(I18nManager.getText("menu.range.end"));
_selectEndItem.setEnabled(false);
_selectEndAction = new ActionListener() {
- public void actionPerformed(ActionEvent e)
- {
+ public void actionPerformed(ActionEvent e) {
_selection.selectRangeEnd();
}
};
@@ -342,8 +333,7 @@ public class MenuManager implements DataSubscriber
rangeMenu.addSeparator();
_deleteRangeItem = new JMenuItem(I18nManager.getText("menu.range.deleterange"));
_deleteRangeAction = new ActionListener() {
- public void actionPerformed(ActionEvent e)
- {
+ public void actionPerformed(ActionEvent e) {
_app.deleteSelectedRange();
}
};
@@ -352,36 +342,30 @@ public class MenuManager implements DataSubscriber
rangeMenu.add(_deleteRangeItem);
_reverseItem = new JMenuItem(I18nManager.getText("menu.range.reverse"));
_reverseItem.addActionListener(new ActionListener() {
- public void actionPerformed(ActionEvent e)
- {
+ public void actionPerformed(ActionEvent e) {
_app.reverseRange();
}
});
_reverseItem.setEnabled(false);
rangeMenu.add(_reverseItem);
- _addTimeOffsetItem = makeMenuItem(FunctionLibrary.FUNCTION_ADD_TIME_OFFSET);
- _addTimeOffsetItem.setEnabled(false);
+ _addTimeOffsetItem = makeMenuItem(FunctionLibrary.FUNCTION_ADD_TIME_OFFSET, false);
rangeMenu.add(_addTimeOffsetItem);
- _addAltitudeOffsetItem = makeMenuItem(FunctionLibrary.FUNCTION_ADD_ALTITUDE_OFFSET);
- _addAltitudeOffsetItem.setEnabled(false);
+ _addAltitudeOffsetItem = makeMenuItem(FunctionLibrary.FUNCTION_ADD_ALTITUDE_OFFSET, false);
rangeMenu.add(_addAltitudeOffsetItem);
_mergeSegmentsItem = new JMenuItem(I18nManager.getText("menu.range.mergetracksegments"));
_mergeSegmentsItem.addActionListener(new ActionListener() {
- public void actionPerformed(ActionEvent e)
- {
+ public void actionPerformed(ActionEvent e) {
_app.mergeTrackSegments();
}
});
_mergeSegmentsItem.setEnabled(false);
rangeMenu.add(_mergeSegmentsItem);
- _deleteFieldValuesItem = makeMenuItem(FunctionLibrary.FUNCTION_DELETE_FIELD_VALUES);
- _deleteFieldValuesItem.setEnabled(false);
+ _deleteFieldValuesItem = makeMenuItem(FunctionLibrary.FUNCTION_DELETE_FIELD_VALUES, false);
rangeMenu.add(_deleteFieldValuesItem);
rangeMenu.addSeparator();
_interpolateItem = new JMenuItem(I18nManager.getText("menu.range.interpolate"));
_interpolateItem.addActionListener(new ActionListener() {
- public void actionPerformed(ActionEvent e)
- {
+ public void actionPerformed(ActionEvent e) {
_app.interpolateSelection();
}
});
@@ -389,8 +373,7 @@ public class MenuManager implements DataSubscriber
rangeMenu.add(_interpolateItem);
_averageItem = new JMenuItem(I18nManager.getText("menu.range.average"));
_averageItem.addActionListener(new ActionListener() {
- public void actionPerformed(ActionEvent e)
- {
+ public void actionPerformed(ActionEvent e) {
_app.averageSelection();
}
});
@@ -405,8 +388,7 @@ public class MenuManager implements DataSubscriber
});
_cutAndMoveItem.setEnabled(false);
rangeMenu.add(_cutAndMoveItem);
- _convertNamesToTimesItem = makeMenuItem(FunctionLibrary.FUNCTION_CONVERT_NAMES_TO_TIMES);
- _convertNamesToTimesItem.setEnabled(false);
+ _convertNamesToTimesItem = makeMenuItem(FunctionLibrary.FUNCTION_CONVERT_NAMES_TO_TIMES, false);
rangeMenu.add(_convertNamesToTimesItem);
menubar.add(rangeMenu);
@@ -415,21 +397,18 @@ public class MenuManager implements DataSubscriber
setAltKey(pointMenu, "altkey.menu.point");
_editPointItem = new JMenuItem(I18nManager.getText("menu.point.editpoint"));
_editPointAction = new ActionListener() {
- public void actionPerformed(ActionEvent e)
- {
+ public void actionPerformed(ActionEvent e) {
_app.editCurrentPoint();
}
};
_editPointItem.addActionListener(_editPointAction);
_editPointItem.setEnabled(false);
pointMenu.add(_editPointItem);
- _editWaypointNameItem = makeMenuItem(FunctionLibrary.FUNCTION_EDIT_WAYPOINT_NAME);
- _editWaypointNameItem.setEnabled(false);
+ _editWaypointNameItem = makeMenuItem(FunctionLibrary.FUNCTION_EDIT_WAYPOINT_NAME, false);
pointMenu.add(_editWaypointNameItem);
_deletePointItem = new JMenuItem(I18nManager.getText("menu.point.deletepoint"));
_deletePointAction = new ActionListener() {
- public void actionPerformed(ActionEvent e)
- {
+ public void actionPerformed(ActionEvent e) {
_app.deleteCurrentPoint();
}
};
@@ -439,12 +418,10 @@ public class MenuManager implements DataSubscriber
pointMenu.add(_deletePointItem);
pointMenu.addSeparator();
// find a waypoint
- _findWaypointItem = makeMenuItem(FunctionLibrary.FUNCTION_FIND_WAYPOINT);
- _findWaypointItem.setEnabled(false);
+ _findWaypointItem = makeMenuItem(FunctionLibrary.FUNCTION_FIND_WAYPOINT, false);
pointMenu.add(_findWaypointItem);
// duplicate current point
- _duplicatePointItem = makeMenuItem(FunctionLibrary.FUNCTION_DUPLICATE_POINT);
- _duplicatePointItem.setEnabled(false);
+ _duplicatePointItem = makeMenuItem(FunctionLibrary.FUNCTION_DUPLICATE_POINT, false);
pointMenu.add(_duplicatePointItem);
// paste coordinates function
JMenuItem pasteCoordsItem = makeMenuItem(FunctionLibrary.FUNCTION_PASTE_COORDINATES);
@@ -474,64 +451,55 @@ public class MenuManager implements DataSubscriber
});
viewMenu.add(sidebarsCheckbox);
// 3d
- _show3dItem = makeMenuItem(FunctionLibrary.FUNCTION_3D);
- _show3dItem.setEnabled(false);
+ _show3dItem = makeMenuItem(FunctionLibrary.FUNCTION_3D, false);
viewMenu.add(_show3dItem);
// browser submenu
_browserMapMenu = new JMenu(I18nManager.getText("menu.view.browser"));
_browserMapMenu.setEnabled(false);
JMenuItem googleMapsItem = new JMenuItem(I18nManager.getText("menu.view.browser.google"));
googleMapsItem.addActionListener(new ActionListener() {
- public void actionPerformed(ActionEvent e)
- {
+ 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)
- {
+ public void actionPerformed(ActionEvent e) {
_app.showExternalMap(UrlGenerator.MAP_SOURCE_OSM);
}
});
_browserMapMenu.add(openMapsItem);
JMenuItem mapquestMapsItem = new JMenuItem(I18nManager.getText("menu.view.browser.mapquest"));
mapquestMapsItem.addActionListener(new ActionListener() {
- public void actionPerformed(ActionEvent e)
- {
+ public void actionPerformed(ActionEvent e) {
_app.showExternalMap(UrlGenerator.MAP_SOURCE_MAPQUEST);
}
});
_browserMapMenu.add(mapquestMapsItem);
JMenuItem yahooMapsItem = new JMenuItem(I18nManager.getText("menu.view.browser.yahoo"));
yahooMapsItem.addActionListener(new ActionListener() {
- public void actionPerformed(ActionEvent e)
- {
+ public void actionPerformed(ActionEvent e) {
_app.showExternalMap(UrlGenerator.MAP_SOURCE_YAHOO);
}
});
_browserMapMenu.add(yahooMapsItem);
JMenuItem bingMapsItem = new JMenuItem(I18nManager.getText("menu.view.browser.bing"));
bingMapsItem.addActionListener(new ActionListener() {
- public void actionPerformed(ActionEvent e)
- {
+ public void actionPerformed(ActionEvent e) {
_app.showExternalMap(UrlGenerator.MAP_SOURCE_BING);
}
});
_browserMapMenu.add(bingMapsItem);
viewMenu.add(_browserMapMenu);
// Charts
- _chartItem = makeMenuItem(FunctionLibrary.FUNCTION_CHARTS);
- _chartItem.setEnabled(false);
+ _chartItem = makeMenuItem(FunctionLibrary.FUNCTION_CHARTS, false);
viewMenu.add(_chartItem);
// Distances
- _distanceItem = makeMenuItem(FunctionLibrary.FUNCTION_DISTANCES);
- _distanceItem.setEnabled(false);
+ _distanceItem = makeMenuItem(FunctionLibrary.FUNCTION_DISTANCES, false);
viewMenu.add(_distanceItem);
// full range details
- _fullRangeDetailsItem = makeMenuItem(FunctionLibrary.FUNCTION_FULL_RANGE_DETAILS);
- _fullRangeDetailsItem.setEnabled(false);
+ _fullRangeDetailsItem = makeMenuItem(FunctionLibrary.FUNCTION_FULL_RANGE_DETAILS, false);
viewMenu.add(_fullRangeDetailsItem);
menubar.add(viewMenu);
@@ -543,73 +511,77 @@ public class MenuManager implements DataSubscriber
photoMenu.add(addPhotosMenuItem);
_saveExifItem = new JMenuItem(I18nManager.getText("menu.photo.saveexif"));
_saveExifItem.addActionListener(new ActionListener() {
- public void actionPerformed(ActionEvent e)
- {
+ public void actionPerformed(ActionEvent e) {
_app.saveExif();
}
});
_saveExifItem.setEnabled(false);
photoMenu.add(_saveExifItem);
- _connectPhotoItem = new JMenuItem(I18nManager.getText("menu.photo.connect"));
- _connectPhotoAction = new ActionListener() {
- public void actionPerformed(ActionEvent e)
- {
- _app.connectPhotoToPoint();
+ // Deselect current photo
+ _selectNoPhotoItem = new JMenuItem(I18nManager.getText("menu.range.none"));
+ _selectNoPhotoItem.setEnabled(false);
+ _selectNoPhotoItem.addActionListener(new ActionListener() {
+ public void actionPerformed(ActionEvent e) {
+ _app.getTrackInfo().selectPhoto(-1);
}
- };
- _connectPhotoItem.addActionListener(_connectPhotoAction);
- _connectPhotoItem.setEnabled(false);
+ });
+ photoMenu.add(_selectNoPhotoItem);
photoMenu.addSeparator();
+ _connectPhotoItem = makeMenuItem(FunctionLibrary.FUNCTION_CONNECT_TO_POINT, false);
photoMenu.add(_connectPhotoItem);
// disconnect photo
- _disconnectPhotoItem = new JMenuItem(I18nManager.getText("menu.photo.disconnect"));
- _disconnectPhotoItem.addActionListener(new ActionListener() {
- public void actionPerformed(ActionEvent e)
- {
- _app.disconnectPhotoFromPoint();
- }
- });
- _disconnectPhotoItem.setEnabled(false);
+ _disconnectPhotoItem = makeMenuItem(FunctionLibrary.FUNCTION_DISCONNECT_PHOTO, false);
photoMenu.add(_disconnectPhotoItem);
- _deletePhotoItem = new JMenuItem(I18nManager.getText("menu.photo.delete"));
- _deletePhotoItem.addActionListener(new ActionListener() {
- public void actionPerformed(ActionEvent e)
- {
- _app.deleteCurrentPhoto();
- }
- });
- _deletePhotoItem.setEnabled(false);
- photoMenu.add(_deletePhotoItem);
+ _removePhotoItem = makeMenuItem(FunctionLibrary.FUNCTION_REMOVE_PHOTO, false);
+ photoMenu.add(_removePhotoItem);
// Rotate current photo
- _rotatePhotoLeft = makeMenuItem(FunctionLibrary.FUNCTION_ROTATE_PHOTO_LEFT);
- _rotatePhotoLeft.setEnabled(false);
+ _rotatePhotoLeft = makeMenuItem(FunctionLibrary.FUNCTION_ROTATE_PHOTO_LEFT, false);
photoMenu.add(_rotatePhotoLeft);
- _rotatePhotoRight = makeMenuItem(FunctionLibrary.FUNCTION_ROTATE_PHOTO_RIGHT);
- _rotatePhotoRight.setEnabled(false);
+ _rotatePhotoRight = makeMenuItem(FunctionLibrary.FUNCTION_ROTATE_PHOTO_RIGHT, false);
photoMenu.add(_rotatePhotoRight);
- _ignoreExifThumb = makeMenuItem(FunctionLibrary.FUNCTION_IGNORE_EXIF_THUMB);
- _ignoreExifThumb.setEnabled(false);
+ // Show photo popup
+ _photoPopupItem = makeMenuItem(FunctionLibrary.FUNCTION_PHOTO_POPUP, false);
+ photoMenu.add(_photoPopupItem);
+ _ignoreExifThumb = makeMenuItem(FunctionLibrary.FUNCTION_IGNORE_EXIF_THUMB, false);
photoMenu.add(_ignoreExifThumb);
- _selectNoPhotoItem = new JMenuItem(I18nManager.getText("menu.range.none"));
- _selectNoPhotoItem.setEnabled(false);
- _selectNoPhotoItem.addActionListener(new ActionListener() {
- public void actionPerformed(ActionEvent e)
- {
- _app.getTrackInfo().selectPhoto(-1);
- }
- });
- photoMenu.add(_selectNoPhotoItem);
photoMenu.addSeparator();
// correlate all photos
- _correlatePhotosItem = makeMenuItem(FunctionLibrary.FUNCTION_CORRELATE_PHOTOS);
- _correlatePhotosItem.setEnabled(false);
+ _correlatePhotosItem = makeMenuItem(FunctionLibrary.FUNCTION_CORRELATE_PHOTOS, false);
photoMenu.add(_correlatePhotosItem);
// rearrange photo points
- _rearrangePhotosItem = makeMenuItem(FunctionLibrary.FUNCTION_REARRANGE_PHOTOS);
- _rearrangePhotosItem.setEnabled(false);
+ _rearrangePhotosItem = makeMenuItem(FunctionLibrary.FUNCTION_REARRANGE_PHOTOS, false);
photoMenu.add(_rearrangePhotosItem);
menubar.add(photoMenu);
+ // Audio menu
+ JMenu audioMenu = new JMenu(I18nManager.getText("menu.audio"));
+ setAltKey(audioMenu, "altkey.menu.audio");
+ addAudioMenuItem = makeMenuItem(FunctionLibrary.FUNCTION_LOAD_AUDIO);
+ audioMenu.add(addAudioMenuItem);
+ _selectNoAudioItem = new JMenuItem(I18nManager.getText("menu.range.none"));
+ _selectNoAudioItem.setEnabled(false);
+ _selectNoAudioItem.addActionListener(new ActionListener() {
+ public void actionPerformed(ActionEvent e) {
+ _app.getTrackInfo().selectAudio(-1);
+ }
+ });
+ audioMenu.add(_selectNoAudioItem);
+ audioMenu.addSeparator();
+ // connect audio
+ _connectAudioItem = makeMenuItem(FunctionLibrary.FUNCTION_CONNECT_TO_POINT, false);
+ audioMenu.add(_connectAudioItem);
+ // Disconnect current audio file
+ _disconnectAudioItem = makeMenuItem(FunctionLibrary.FUNCTION_DISCONNECT_AUDIO, false);
+ audioMenu.add(_disconnectAudioItem);
+ // Remove current audio file
+ _removeAudioItem = makeMenuItem(FunctionLibrary.FUNCTION_REMOVE_AUDIO, false);
+ audioMenu.add(_removeAudioItem);
+ audioMenu.addSeparator();
+ // Correlate audio files
+ _correlateAudiosItem = makeMenuItem(FunctionLibrary.FUNCTION_CORRELATE_AUDIOS, false);
+ audioMenu.add(_correlateAudiosItem);
+ menubar.add(audioMenu);
+
// Settings menu
JMenu settingsMenu = new JMenu(I18nManager.getText("menu.settings"));
setAltKey(settingsMenu, "altkey.menu.settings");
@@ -634,6 +606,8 @@ public class MenuManager implements DataSubscriber
settingsMenu.add(makeMenuItem(FunctionLibrary.FUNCTION_SET_PATHS));
// Set colours
settingsMenu.add(makeMenuItem(FunctionLibrary.FUNCTION_SET_COLOURS));
+ // Set line width used for drawing
+ settingsMenu.add(makeMenuItem(FunctionLibrary.FUNCTION_SET_LINE_WIDTH));
// Set language
settingsMenu.add(makeMenuItem(FunctionLibrary.FUNCTION_SET_LANGUAGE));
settingsMenu.addSeparator();
@@ -655,6 +629,19 @@ public class MenuManager implements DataSubscriber
return menubar;
}
+ /**
+ * Convenience method for making a menu item using a function
+ * @param inFunction function
+ * @param inEnabled flag to specify initial enabled state
+ * @return menu item using localized name of function
+ */
+ private static JMenuItem makeMenuItem(GenericFunction inFunction, boolean inEnabled)
+ {
+ JMenuItem item = makeMenuItem(inFunction);
+ item.setEnabled(inEnabled);
+ return item;
+ }
+
/**
* Convenience method for making a menu item using a function
* @param inFunction function
@@ -767,11 +754,16 @@ public class MenuManager implements DataSubscriber
_selectEndButton.addActionListener(_selectEndAction);
_selectEndButton.setEnabled(false);
toolbar.add(_selectEndButton);
- _connectPhotoButton = new JButton(IconManager.getImageIcon(IconManager.CONNECT_PHOTO));
- _connectPhotoButton.setToolTipText(I18nManager.getText("menu.photo.connect"));
- _connectPhotoButton.addActionListener(_connectPhotoAction);
- _connectPhotoButton.setEnabled(false);
- toolbar.add(_connectPhotoButton);
+ // Connect to point
+ _connectButton = new JButton(IconManager.getImageIcon(IconManager.CONNECT_PHOTO));
+ _connectButton.setToolTipText(I18nManager.getText(FunctionLibrary.FUNCTION_CONNECT_TO_POINT.getNameKey()));
+ _connectButton.addActionListener(new ActionListener() {
+ public void actionPerformed(ActionEvent arg0) {
+ FunctionLibrary.FUNCTION_CONNECT_TO_POINT.begin();
+ }
+ });
+ _connectButton.setEnabled(false);
+ toolbar.add(_connectButton);
// finish off
toolbar.setFloatable(false);
return toolbar;
@@ -818,6 +810,8 @@ public class MenuManager implements DataSubscriber
_getGpsiesItem.setEnabled(hasData);
_uploadGpsiesItem.setEnabled(hasData && _track.hasTrackPoints());
_lookupSrtmItem.setEnabled(hasData);
+ _lookupWikipediaItem.setEnabled(hasData);
+ _downloadOsmItem.setEnabled(hasData);
_findWaypointItem.setEnabled(hasData && _track.hasWaypoints());
// is undo available?
boolean hasUndo = !_app.getUndoStack().isEmpty();
@@ -837,24 +831,33 @@ public class MenuManager implements DataSubscriber
_selectEndButton.setEnabled(hasPoint);
_duplicatePointItem.setEnabled(hasPoint);
// are there any photos?
- boolean anyPhotos = _photos != null && _photos.getNumPhotos() > 0;
+ boolean anyPhotos = _app.getTrackInfo().getPhotoList().getNumPhotos() > 0;
_saveExifItem.setEnabled(anyPhotos);
- // is there a current photo?
- boolean hasPhoto = anyPhotos && _selection.getCurrentPhotoIndex() >= 0;
- // connect is available if photo and point selected, and photo has no point
- Photo currentPhoto = _photos.getPhoto(_selection.getCurrentPhotoIndex());
- boolean connectAvailable = hasPhoto && hasPoint && currentPhoto != null
- && currentPhoto.getDataPoint() == null;
- _connectPhotoItem.setEnabled(connectAvailable);
- _connectPhotoButton.setEnabled(connectAvailable);
- _disconnectPhotoItem.setEnabled(hasPhoto && currentPhoto != null && currentPhoto.getDataPoint() != null);
+ // is there a current photo, audio?
+ Photo currentPhoto = _app.getTrackInfo().getCurrentPhoto();
+ boolean hasPhoto = currentPhoto != null;
+ AudioFile currentAudio = _app.getTrackInfo().getCurrentAudio();
+ boolean hasAudio = currentAudio != null;
+ // connect is available if (photo/audio) and point selected, and media has no point
+ boolean connectAvailable = (hasPhoto && hasPoint && currentPhoto.getDataPoint() == null)
+ || (hasAudio && hasPoint && currentAudio.getDataPoint() == null);
+ _connectPhotoItem.setEnabled(hasPhoto && hasPoint && currentPhoto.getDataPoint() == null);
+ _connectButton.setEnabled(connectAvailable);
+ _disconnectPhotoItem.setEnabled(hasPhoto && currentPhoto.getDataPoint() != null);
_correlatePhotosItem.setEnabled(anyPhotos && hasData);
_rearrangePhotosItem.setEnabled(anyPhotos && hasData && _track.getNumPoints() > 1);
- _deletePhotoItem.setEnabled(hasPhoto);
+ _removePhotoItem.setEnabled(hasPhoto);
_rotatePhotoLeft.setEnabled(hasPhoto);
_rotatePhotoRight.setEnabled(hasPhoto);
- _ignoreExifThumb.setEnabled(hasPhoto && currentPhoto != null && currentPhoto.getExifThumbnail() != null);
+ _photoPopupItem.setEnabled(hasPhoto);
+ _ignoreExifThumb.setEnabled(hasPhoto && currentPhoto.getExifThumbnail() != null);
_selectNoPhotoItem.setEnabled(hasPhoto);
+ boolean anyAudios = _app.getTrackInfo().getAudioList().getNumAudios() > 0;
+ _selectNoAudioItem.setEnabled(hasAudio);
+ _removeAudioItem.setEnabled(hasAudio);
+ _connectAudioItem.setEnabled(hasAudio && hasPoint && currentAudio.getDataPoint() == null);
+ _disconnectAudioItem.setEnabled(hasAudio && _app.getTrackInfo().getCurrentAudio().getDataPoint() != null);
+ _correlateAudiosItem.setEnabled(anyAudios && hasData);
// is there a current range?
boolean hasRange = (hasData && _selection.hasRangeSelected());
_deleteRangeItem.setEnabled(hasRange);
diff --git a/tim/prune/gui/PhotoListModel.java b/tim/prune/gui/PhotoListModel.java
deleted file mode 100644
index 27ed0e6..0000000
--- a/tim/prune/gui/PhotoListModel.java
+++ /dev/null
@@ -1,57 +0,0 @@
-package tim.prune.gui;
-
-import javax.swing.AbstractListModel;
-
-import tim.prune.data.Photo;
-import tim.prune.data.PhotoList;
-
-/**
- * Class to act as list model for the photo list
- */
-public class PhotoListModel extends AbstractListModel
-{
- PhotoList _photos = null;
-
- /**
- * Constructor giving PhotoList object
- * @param inList PhotoList
- */
- public PhotoListModel(PhotoList inList)
- {
- _photos = inList;
- }
-
- /**
- * @see javax.swing.ListModel#getSize()
- */
- public int getSize()
- {
- return _photos.getNumPhotos();
- }
-
- /**
- * @see javax.swing.ListModel#getElementAt(int)
- */
- public Object getElementAt(int inIndex)
- {
- return _photos.getPhoto(inIndex).getFile().getName();
- }
-
- /**
- * Get the Photo at the given index
- * @param inIndex index number, starting at 0
- * @return Photo object
- */
- public Photo getPhoto(int inIndex)
- {
- return _photos.getPhoto(inIndex);
- }
-
- /**
- * Fire event to notify that contents have changed
- */
- public void fireChanged()
- {
- this.fireContentsChanged(this, 0, getSize()-1);
- }
-}
diff --git a/tim/prune/gui/PhotoThumbnail.java b/tim/prune/gui/PhotoThumbnail.java
index cc7e776..686d90a 100644
--- a/tim/prune/gui/PhotoThumbnail.java
+++ b/tim/prune/gui/PhotoThumbnail.java
@@ -4,7 +4,6 @@ import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Image;
-import java.awt.image.BufferedImage;
import javax.swing.ImageIcon;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
@@ -18,9 +17,10 @@ import tim.prune.data.Photo;
public class PhotoThumbnail extends JPanel implements Runnable
{
private Photo _photo = null;
- private BufferedImage _thumbnail = null;
+ private Image _thumbnail = null;
private boolean _loadingImage = false;
private boolean _loadFailed = false;
+ private boolean _inPanel = false;
/** String to show before photo is loaded */
private static final String LOADING_STRING = I18nManager.getText("details.photo.loading") + " ...";
@@ -30,9 +30,18 @@ public class PhotoThumbnail extends JPanel implements Runnable
*/
public PhotoThumbnail()
{
- setOpaque(true);
+ this(true);
}
+ /**
+ * Constructor
+ * @param inPanel true if thumbnail is inside panel
+ */
+ public PhotoThumbnail(boolean inPanel)
+ {
+ setOpaque(true);
+ _inPanel = inPanel;
+ }
/**
* Set the Photo
@@ -41,7 +50,8 @@ public class PhotoThumbnail extends JPanel implements Runnable
public void setPhoto(Photo inPhoto)
{
// Check whether the photo has changed
- if (_photo != inPhoto) {
+ if (_photo != inPhoto)
+ {
_photo = inPhoto;
_thumbnail = null;
_loadFailed = false;
@@ -52,7 +62,8 @@ public class PhotoThumbnail extends JPanel implements Runnable
/**
* Force a refresh / reload
*/
- public void refresh() {
+ public void refresh()
+ {
_thumbnail = null;
_loadFailed = false;
}
@@ -82,14 +93,16 @@ public class PhotoThumbnail extends JPanel implements Runnable
{
// Copy scaled, smoothed (and rotated) image into scaled
int usableWidth = getParent().getWidth()-10;
- Image scaled = ImageUtils.rotateImage(_thumbnail, usableWidth, usableWidth, _photo.getRotationDegrees());
+ int usableHeight = (_inPanel?usableWidth:getHeight()-10);
+ Image scaled = ImageUtils.rotateImage(_thumbnail, usableWidth, usableHeight, _photo.getRotationDegrees());
int scaleWidth = scaled.getWidth(null);
int scaleHeight = scaled.getHeight(null);
// Draw scaled / rotated image to component
int horizOffset = (getWidth() - scaleWidth) / 2;
int vertOffset = (getHeight() - scaleHeight) / 2;
inG.drawImage(scaled, horizOffset, vertOffset, scaleWidth, scaleHeight, null);
- if (getHeight() < getWidth() || getHeight() > usableWidth)
+ // Special resize behaviour when locked inside details panel
+ if (_inPanel && (getHeight() < getWidth() || getHeight() > usableWidth))
{
Dimension newsize = new Dimension(usableWidth, usableWidth);
setPreferredSize(newsize);
@@ -114,30 +127,37 @@ public class PhotoThumbnail extends JPanel implements Runnable
*/
public void run()
{
- // Use exif thumbnail?
- if (_photo.getExifThumbnail() != null) {
- Image image = new ImageIcon(_photo.getExifThumbnail()).getImage();
- _thumbnail = ImageUtils.createScaledImage(image, image.getWidth(null), image.getHeight(null));
- image = null;
- }
- else
+ if (_inPanel)
{
- // no exif thumbnail available, going to have to read whole thing
- int picWidth = _photo.getWidth();
- int picHeight = _photo.getHeight();
- if (picWidth > -1 && picHeight > -1)
- {
- // Just set a "reasonable" thumbnail size for now
- final int DEFAULT_THUMB_SIZE = 400;
- // calculate maximum thumbnail size
- Dimension thumbSize = ImageUtils.getThumbnailSize(picWidth, picHeight, DEFAULT_THUMB_SIZE, DEFAULT_THUMB_SIZE);
- // Make icon to load image into
- Image image = new ImageIcon(_photo.getFile().getAbsolutePath()).getImage();
- // save scaled, smoothed thumbnail for reuse
- _thumbnail = ImageUtils.createScaledImage(image, thumbSize.width, thumbSize.height);
+ // use either exif thumbnail or photo scaled down to sensible size
+ if (_photo.getExifThumbnail() != null) {
+ // Use exif thumbnail
+ Image image = new ImageIcon(_photo.getExifThumbnail()).getImage();
+ _thumbnail = ImageUtils.createScaledImage(image, image.getWidth(null), image.getHeight(null));
image = null;
}
- else _loadFailed = true;
+ else
+ {
+ // no exif thumbnail available, going to have to read whole thing
+ int picWidth = _photo.getWidth();
+ int picHeight = _photo.getHeight();
+ if (picWidth > -1 && picHeight > -1)
+ {
+ // Just set a "reasonable" thumbnail size for now
+ final int DEFAULT_THUMB_SIZE = 400;
+ // calculate maximum thumbnail size
+ Dimension thumbSize = ImageUtils.getThumbnailSize(picWidth, picHeight, DEFAULT_THUMB_SIZE, DEFAULT_THUMB_SIZE);
+ // Make icon to load image into
+ Image image = new ImageIcon(_photo.getFile().getAbsolutePath()).getImage();
+ // save scaled, smoothed thumbnail for reuse
+ _thumbnail = ImageUtils.createScaledImage(image, thumbSize.width, thumbSize.height);
+ image = null;
+ }
+ else _loadFailed = true;
+ }
+ }
+ else {
+ _thumbnail = new ImageIcon(_photo.getFile().getAbsolutePath()).getImage();
}
_loadingImage = false;
repaint();
diff --git a/tim/prune/gui/SelectorDisplay.java b/tim/prune/gui/SelectorDisplay.java
index ed244d0..f0772bf 100644
--- a/tim/prune/gui/SelectorDisplay.java
+++ b/tim/prune/gui/SelectorDisplay.java
@@ -38,12 +38,21 @@ public class SelectorDisplay extends GenericDisplay
private JScrollBar _scroller = null;
private boolean _ignoreScrollEvents = false;
- // Photos
- private JList _photoList = null;
- private PhotoListModel _photoListModel = null;
+ // Panel containing lists
+ private JPanel _listsPanel = null;
+ private int _visiblePanels = 1;
// Waypoints
+ private JPanel _waypointListPanel = null;
private JList _waypointList = null;
private WaypointListModel _waypointListModel = null;
+ // Photos
+ private JPanel _photoListPanel = null;
+ private JList _photoList = null;
+ private MediaListModel _photoListModel = null;
+ // Audio files
+ private JPanel _audioListPanel = null;
+ private JList _audioList = null;
+ private MediaListModel _audioListModel = null;
// scrollbar interval
private static final int SCROLLBAR_INTERVAL = 50;
@@ -78,43 +87,39 @@ public class SelectorDisplay extends GenericDisplay
_trackpointsLabel = new JLabel(I18nManager.getText("details.notrack"));
trackDetailsPanel.add(_trackpointsLabel);
_filenameLabel = new JLabel("");
+ _filenameLabel.setMinimumSize(new Dimension(120, 10));
trackDetailsPanel.add(_filenameLabel);
// Scroll bar
_scroller = new JScrollBar(JScrollBar.HORIZONTAL, 0, SCROLLBAR_INTERVAL, 0, 100);
_scroller.addAdjustmentListener(new AdjustmentListener() {
- public void adjustmentValueChanged(AdjustmentEvent e)
- {
+ public void adjustmentValueChanged(AdjustmentEvent e) {
selectPoint(e.getValue());
}
});
_scroller.setEnabled(false);
// Add panel for waypoints / photos
- JPanel listsPanel = new JPanel();
- listsPanel.setLayout(new GridLayout(0, 1));
- listsPanel.setBorder(BorderFactory.createCompoundBorder(
+ _listsPanel = new JPanel();
+ _listsPanel.setLayout(new GridLayout(0, 1));
+ _listsPanel.setBorder(BorderFactory.createCompoundBorder(
BorderFactory.createEtchedBorder(EtchedBorder.LOWERED), BorderFactory.createEmptyBorder(3, 3, 3, 3))
);
_waypointListModel = new WaypointListModel(_trackInfo.getTrack());
_waypointList = new JList(_waypointListModel);
_waypointList.setVisibleRowCount(NUM_LIST_ENTRIES);
- _waypointList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
_waypointList.addListSelectionListener(new ListSelectionListener() {
public void valueChanged(ListSelectionEvent e)
{
if (!e.getValueIsAdjusting()) selectWaypoint(_waypointList.getSelectedIndex());
- }});
- JPanel waypointListPanel = new JPanel();
- waypointListPanel.setLayout(new BorderLayout());
- waypointListPanel.add(new JLabel(I18nManager.getText("details.waypointsphotos.waypoints")), BorderLayout.NORTH);
- waypointListPanel.add(new JScrollPane(_waypointList), BorderLayout.CENTER);
- listsPanel.add(waypointListPanel);
+ }
+ });
+ _waypointListPanel = makeListPanel("details.lists.waypoints", _waypointList);
+ _listsPanel.add(_waypointListPanel);
// photo list
- _photoListModel = new PhotoListModel(_trackInfo.getPhotoList());
+ _photoListModel = new MediaListModel(_trackInfo.getPhotoList());
_photoList = new JList(_photoListModel);
_photoList.setVisibleRowCount(NUM_LIST_ENTRIES);
- _photoList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
_photoList.addListSelectionListener(new ListSelectionListener() {
public void valueChanged(ListSelectionEvent e)
{
@@ -122,12 +127,22 @@ public class SelectorDisplay extends GenericDisplay
selectPhoto(_photoList.getSelectedIndex());
}
}});
- JPanel photoListPanel = new JPanel();
- photoListPanel.setLayout(new BorderLayout());
- photoListPanel.add(new JLabel(I18nManager.getText("details.waypointsphotos.photos")), BorderLayout.NORTH);
- photoListPanel.add(new JScrollPane(_photoList), BorderLayout.CENTER);
- listsPanel.add(photoListPanel);
- listsPanel.setAlignmentX(Component.LEFT_ALIGNMENT);
+ _photoListPanel = makeListPanel("details.lists.photos", _photoList);
+ // don't add photo list (because there aren't any photos yet)
+
+ // List for audio files
+ _audioListModel = new MediaListModel(_trackInfo.getAudioList());
+ _audioList = new JList(_audioListModel);
+ _audioList.addListSelectionListener(new ListSelectionListener() {
+ public void valueChanged(ListSelectionEvent e)
+ {
+ if (!e.getValueIsAdjusting()) {
+ selectAudio(_audioList.getSelectedIndex());
+ }
+ }});
+ _audioListPanel = makeListPanel("details.lists.audio", _audioList);
+ // don't add audio list either
+ _listsPanel.setAlignmentX(Component.LEFT_ALIGNMENT);
// add the controls to the main panel
mainPanel.add(trackDetailsPanel);
@@ -138,7 +153,7 @@ public class SelectorDisplay extends GenericDisplay
// add the main panel at the top
add(mainPanel, BorderLayout.NORTH);
// and lists in the centre
- add(listsPanel, BorderLayout.CENTER);
+ add(_listsPanel, BorderLayout.CENTER);
// set preferred width to be small
setPreferredSize(new Dimension(100, 100));
}
@@ -150,8 +165,7 @@ public class SelectorDisplay extends GenericDisplay
*/
private void selectPoint(int inValue)
{
- if (_track != null && !_ignoreScrollEvents)
- {
+ if (_track != null && !_ignoreScrollEvents) {
_trackInfo.selectPoint(inValue);
}
}
@@ -166,6 +180,14 @@ public class SelectorDisplay extends GenericDisplay
_trackInfo.selectPhoto(inPhotoIndex);
}
+ /**
+ * Select the specified audio file
+ * @param inIndex index of selected audio file
+ */
+ private void selectAudio(int inIndex)
+ {
+ _trackInfo.selectAudio(inIndex);
+ }
/**
* Select the specified waypoint
@@ -173,8 +195,7 @@ public class SelectorDisplay extends GenericDisplay
*/
private void selectWaypoint(int inWaypointIndex)
{
- if (inWaypointIndex >= 0)
- {
+ if (inWaypointIndex >= 0) {
_trackInfo.selectPoint(_waypointListModel.getWaypoint(inWaypointIndex));
}
}
@@ -203,8 +224,7 @@ public class SelectorDisplay extends GenericDisplay
}
else if (numFiles > 1)
{
- _filenameLabel.setText(I18nManager.getText("details.track.numfiles") + ": "
- + numFiles);
+ _filenameLabel.setText(I18nManager.getText("details.track.numfiles") + ": " + numFiles);
}
else _filenameLabel.setText("");
}
@@ -237,6 +257,7 @@ public class SelectorDisplay extends GenericDisplay
(DataSubscriber.DATA_ADDED_OR_REMOVED | DataSubscriber.DATA_EDITED | DataSubscriber.PHOTOS_MODIFIED)) > 0)
{
_photoListModel.fireChanged();
+ _audioListModel.fireChanged();
}
// Deselect selected waypoint if selected point has since changed
if (_waypointList.getSelectedIndex() >= 0)
@@ -249,6 +270,9 @@ public class SelectorDisplay extends GenericDisplay
_waypointList.clearSelection();
}
}
+ // Hide photo list if no photos loaded, same for audio
+ redrawLists(_photoListModel.getSize() > 0, _audioListModel.getSize() > 0);
+
// Make sure correct photo is selected
if (_photoListModel.getSize() > 0)
{
@@ -265,5 +289,62 @@ public class SelectorDisplay extends GenericDisplay
}
}
}
+ // Same for audio files
+ if (_audioListModel.getSize() > 0)
+ {
+ int audioIndex = _trackInfo.getSelection().getCurrentAudioIndex();
+ int listSelection = _audioList.getSelectedIndex();
+ // Change listbox selection if indexes not equal
+ if (listSelection != audioIndex)
+ {
+ if (audioIndex < 0) {
+ _audioList.clearSelection();
+ }
+ else {
+ _audioList.setSelectedIndex(audioIndex);
+ }
+ }
+ }
+ }
+
+ /**
+ * Make one of the three list panels
+ * @param inNameKey key for heading text
+ * @param inList list object
+ * @return panel object
+ */
+ private static JPanel makeListPanel(String inNameKey, JList inList)
+ {
+ JPanel panel = new JPanel();
+ panel.setLayout(new BorderLayout());
+ panel.add(new JLabel(I18nManager.getText(inNameKey)), BorderLayout.NORTH);
+ inList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
+ panel.add(new JScrollPane(inList), BorderLayout.CENTER);
+ return panel;
+ }
+
+ /**
+ * Redraw the list panels in the display according to which ones should be shown
+ * @param inShowPhotos true to show photo list
+ * @param inShowAudio true to show audio list
+ */
+ private void redrawLists(boolean inShowPhotos, boolean inShowAudio)
+ {
+ // exit if same as last time
+ int panels = 1 + (inShowPhotos?2:0) + (inShowAudio?4:0);
+ if (panels == _visiblePanels) return;
+ _visiblePanels = panels;
+ // remove all panels and re-add them
+ _listsPanel.removeAll();
+ _listsPanel.setLayout(new GridLayout(0, 1));
+ _listsPanel.add(_waypointListPanel);
+ if (inShowPhotos) {
+ _listsPanel.add(_photoListPanel);
+ }
+ if (inShowAudio) {
+ _listsPanel.add(_audioListPanel);
+ }
+ _listsPanel.invalidate();
+ _listsPanel.getParent().validate();
}
}
diff --git a/tim/prune/gui/images/play_audio.gif b/tim/prune/gui/images/play_audio.gif
new file mode 100644
index 0000000..8d4d6e5
Binary files /dev/null and b/tim/prune/gui/images/play_audio.gif differ
diff --git a/tim/prune/gui/images/show_details_icon.gif b/tim/prune/gui/images/show_details_icon.gif
new file mode 100644
index 0000000..97674f2
Binary files /dev/null and b/tim/prune/gui/images/show_details_icon.gif differ
diff --git a/tim/prune/gui/images/stop_audio.gif b/tim/prune/gui/images/stop_audio.gif
new file mode 100644
index 0000000..e0af8f5
Binary files /dev/null and b/tim/prune/gui/images/stop_audio.gif differ
diff --git a/tim/prune/gui/map/DiskTileCacher.java b/tim/prune/gui/map/DiskTileCacher.java
index dfc4f92..a250e23 100644
--- a/tim/prune/gui/map/DiskTileCacher.java
+++ b/tim/prune/gui/map/DiskTileCacher.java
@@ -120,7 +120,8 @@ public class DiskTileCacher implements Runnable
}
catch (Exception e) {return;}
}
- try {
+ try
+ {
// Open streams from URL and to file
out = new FileOutputStream(tempFile);
in = _url.openStream();
@@ -131,16 +132,18 @@ public class DiskTileCacher implements Runnable
}
finished = true;
} catch (IOException e) {}
- finally {
- try {
- in.close();
- out.close();
- if (!finished) {tempFile.delete();}
+ finally
+ {
+ // clean up files
+ try {in.close();} catch (Exception e) {} // ignore
+ try {out.close();} catch (Exception e) {} // ignore
+ if (!finished) {
+ tempFile.delete();
}
- catch (Exception e) {} // ignore
}
// Move temp file to desired file location
- if (!tempFile.renameTo(_file)) {
+ if (!tempFile.renameTo(_file))
+ {
// File couldn't be moved - delete both to be sure
tempFile.delete();
_file.delete();
diff --git a/tim/prune/gui/map/MapCanvas.java b/tim/prune/gui/map/MapCanvas.java
index 97be7b5..2308fac 100644
--- a/tim/prune/gui/map/MapCanvas.java
+++ b/tim/prune/gui/map/MapCanvas.java
@@ -103,8 +103,6 @@ public class MapCanvas extends JPanel implements MouseListener, MouseMotionListe
private int _dragFromX = -1;
/** y coordinate of drag from point */
private int _dragFromY = -1;
- /** Flag set to true for right-click dragging */
- private boolean _zoomDragging = false;
/** x coordinate of drag to point */
private int _dragToX = -1;
/** y coordinate of drag to point */
@@ -115,6 +113,8 @@ public class MapCanvas extends JPanel implements MouseListener, MouseMotionListe
private int _popupMenuY = -1;
/** Flag to prevent showing too often the error message about loading maps */
private boolean _shownOsmErrorAlready = false;
+ /** Current drawing mode */
+ private int _drawMode = MODE_DEFAULT;
/** Constant for click sensitivity when selecting nearest point */
private static final int CLICK_SENSITIVITY = 10;
@@ -126,6 +126,11 @@ public class MapCanvas extends JPanel implements MouseListener, MouseMotionListe
// Colours
private static final Color COLOR_MESSAGES = Color.GRAY;
+ // Drawing modes
+ private static final int MODE_DEFAULT = 0;
+ private static final int MODE_ZOOM_RECT = 1;
+ private static final int MODE_DRAW_POINTS_START = 2;
+ private static final int MODE_DRAW_POINTS_CONT = 3;
/**
* Constructor
@@ -273,7 +278,6 @@ public class MapCanvas extends JPanel implements MouseListener, MouseMotionListe
{
zoomIn();
}});
- zoomInItem.setEnabled(true);
_popup.add(zoomInItem);
JMenuItem zoomOutItem = new JMenuItem(I18nManager.getText("menu.map.zoomout"));
zoomOutItem.addActionListener(new ActionListener() {
@@ -281,7 +285,6 @@ public class MapCanvas extends JPanel implements MouseListener, MouseMotionListe
{
zoomOut();
}});
- zoomOutItem.setEnabled(true);
_popup.add(zoomOutItem);
JMenuItem zoomFullItem = new JMenuItem(I18nManager.getText("menu.map.zoomfull"));
zoomFullItem.addActionListener(new ActionListener() {
@@ -291,7 +294,6 @@ public class MapCanvas extends JPanel implements MouseListener, MouseMotionListe
_recalculate = true;
repaint();
}});
- zoomFullItem.setEnabled(true);
_popup.add(zoomFullItem);
_popup.addSeparator();
// Set background
@@ -308,13 +310,18 @@ public class MapCanvas extends JPanel implements MouseListener, MouseMotionListe
newPointItem.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e)
{
- double lat = MapUtils.getLatitudeFromY(_mapPosition.getYFromPixels(_popupMenuY, getHeight()));
- double lon = MapUtils.getLongitudeFromX(_mapPosition.getXFromPixels(_popupMenuX, getWidth()));
- _app.createPoint(new DataPoint(new Latitude(lat, Coordinate.FORMAT_NONE),
- new Longitude(lon, Coordinate.FORMAT_NONE), null));
+ _app.createPoint(createPointFromClick(_popupMenuX, _popupMenuY));
}});
- newPointItem.setEnabled(true);
_popup.add(newPointItem);
+ // draw point series
+ JMenuItem drawPointsItem = new JMenuItem(I18nManager.getText("menu.map.drawpoints"));
+ drawPointsItem.addActionListener(new ActionListener() {
+ public void actionPerformed(ActionEvent e)
+ {
+ _drawMode = MODE_DRAW_POINTS_START;
+ }
+ });
+ _popup.add(drawPointsItem);
}
@@ -386,7 +393,7 @@ public class MapCanvas extends JPanel implements MouseListener, MouseMotionListe
inG.drawImage(_mapImage, 0, 0, getWidth(), getHeight(), null);
}
// Draw the zoom rectangle if necessary
- if (_zoomDragging)
+ if (_drawMode == MODE_ZOOM_RECT)
{
inG.setColor(Color.RED);
inG.drawLine(_dragFromX, _dragFromY, _dragFromX, _dragToY);
@@ -394,6 +401,15 @@ public class MapCanvas extends JPanel implements MouseListener, MouseMotionListe
inG.drawLine(_dragToX, _dragFromY, _dragToX, _dragToY);
inG.drawLine(_dragFromX, _dragToY, _dragToX, _dragToY);
}
+ else if (_drawMode == MODE_DRAW_POINTS_CONT)
+ {
+ // draw line to mouse position to show drawing mode
+ inG.setColor(Config.getColourScheme().getColour(ColourScheme.IDX_POINT));
+ int prevIndex = _track.getNumPoints()-1;
+ int px = getWidth() / 2 + _mapPosition.getXFromCentre(_track.getX(prevIndex));
+ int py = getHeight() / 2 + _mapPosition.getYFromCentre(_track.getY(prevIndex));
+ inG.drawLine(px, py, _dragToX, _dragToY);
+ }
}
else
{
@@ -520,9 +536,12 @@ public class MapCanvas extends JPanel implements MouseListener, MouseMotionListe
final Color secondColour = Config.getColourScheme().getColour(ColourScheme.IDX_SECONDARY);
final Color textColour = Config.getColourScheme().getColour(ColourScheme.IDX_TEXT);
- // try to set double line width for painting
- if (inG instanceof Graphics2D) {
- ((Graphics2D) inG).setStroke(new BasicStroke(2.0f));
+ // try to set line width for painting
+ if (inG instanceof Graphics2D)
+ {
+ int lineWidth = Config.getConfigInt(Config.KEY_LINE_WIDTH);
+ if (lineWidth < 1 || lineWidth > 4) {lineWidth = 2;}
+ ((Graphics2D) inG).setStroke(new BasicStroke(lineWidth));
}
int pointsPainted = 0;
// draw track points
@@ -627,11 +646,11 @@ public class MapCanvas extends JPanel implements MouseListener, MouseMotionListe
}
}
}
- // Loop over points, drawing blobs for photo points
+ // Loop over points, drawing blobs for photo / audio points
inG.setColor(secondColour);
for (int i=0; i<_track.getNumPoints(); i++)
{
- if (_track.getPoint(i).getPhoto() != null)
+ if (_track.getPoint(i).hasMedia())
{
int px = getWidth() / 2 + _mapPosition.getXFromCentre(_track.getX(i));
int py = getHeight() / 2 + _mapPosition.getYFromCentre(_track.getY(i));
@@ -774,6 +793,20 @@ public class MapCanvas extends JPanel implements MouseListener, MouseMotionListe
repaint();
}
+ /**
+ * Create a DataPoint object from the given click coordinates
+ * @param inX x coordinate of click
+ * @param inY y coordinate of click
+ * @return DataPoint with given coordinates and no altitude
+ */
+ private DataPoint createPointFromClick(int inX, int inY)
+ {
+ double lat = MapUtils.getLatitudeFromY(_mapPosition.getYFromPixels(inY, getHeight()));
+ double lon = MapUtils.getLongitudeFromX(_mapPosition.getXFromPixels(inX, getWidth()));
+ return new DataPoint(new Latitude(lat, Coordinate.FORMAT_NONE),
+ new Longitude(lon, Coordinate.FORMAT_NONE), null);
+ }
+
/**
* @see javax.swing.JComponent#getMinimumSize()
*/
@@ -806,22 +839,43 @@ public class MapCanvas extends JPanel implements MouseListener, MouseMotionListe
if (inE.getClickCount() == 1)
{
// single click
- int pointIndex = _track.getNearestPointIndex(
- _mapPosition.getXFromPixels(inE.getX(), getWidth()),
- _mapPosition.getYFromPixels(inE.getY(), getHeight()),
- _mapPosition.getBoundsFromPixels(CLICK_SENSITIVITY), false);
- // Extend selection for shift-click
- if (inE.isShiftDown()) {
- _trackInfo.extendSelection(pointIndex);
+ if (_drawMode == MODE_DEFAULT)
+ {
+ int pointIndex = _track.getNearestPointIndex(
+ _mapPosition.getXFromPixels(inE.getX(), getWidth()),
+ _mapPosition.getYFromPixels(inE.getY(), getHeight()),
+ _mapPosition.getBoundsFromPixels(CLICK_SENSITIVITY), false);
+ // Extend selection for shift-click
+ if (inE.isShiftDown()) {
+ _trackInfo.extendSelection(pointIndex);
+ }
+ else {
+ _trackInfo.selectPoint(pointIndex);
+ }
}
- else {
- _trackInfo.selectPoint(pointIndex);
+ else if (_drawMode == MODE_DRAW_POINTS_START)
+ {
+ _app.createPoint(createPointFromClick(inE.getX(), inE.getY()));
+ _dragToX = inE.getX();
+ _dragToY = inE.getY();
+ _drawMode = MODE_DRAW_POINTS_CONT;
+ }
+ else if (_drawMode == MODE_DRAW_POINTS_CONT)
+ {
+ DataPoint point = createPointFromClick(inE.getX(), inE.getY());
+ _app.createPoint(point);
+ point.setSegmentStart(false);
}
}
else if (inE.getClickCount() == 2) {
// double click
- panMap(inE.getX() - getWidth()/2, inE.getY() - getHeight()/2);
- zoomIn();
+ if (_drawMode == MODE_DEFAULT) {
+ panMap(inE.getX() - getWidth()/2, inE.getY() - getHeight()/2);
+ zoomIn();
+ }
+ else if (_drawMode == MODE_DRAW_POINTS_START || _drawMode == MODE_DRAW_POINTS_CONT) {
+ _drawMode = MODE_DEFAULT;
+ }
}
}
else
@@ -868,13 +922,14 @@ public class MapCanvas extends JPanel implements MouseListener, MouseMotionListe
public void mouseReleased(MouseEvent inE)
{
_recalculate = true;
- if (_zoomDragging && Math.abs(_dragToX - _dragFromX) > 20 && Math.abs(_dragToY - _dragFromY) > 20)
+ if (_drawMode == MODE_ZOOM_RECT && Math.abs(_dragToX - _dragFromX) > 20
+ && Math.abs(_dragToY - _dragFromY) > 20)
{
//System.out.println("Finished zoom: " + _dragFromX + ", " + _dragFromY + " to " + _dragToX + ", " + _dragToY);
_mapPosition.zoomToPixels(_dragFromX, _dragToX, _dragFromY, _dragToY, getWidth(), getHeight());
+ _drawMode = MODE_DEFAULT;
}
_dragFromX = _dragFromY = -1;
- _zoomDragging = false;
repaint();
}
@@ -887,20 +942,19 @@ public class MapCanvas extends JPanel implements MouseListener, MouseMotionListe
if (!inE.isMetaDown())
{
// Left mouse drag - pan map by appropriate amount
- _zoomDragging = false;
if (_dragFromX != -1)
{
panMap(_dragFromX - inE.getX(), _dragFromY - inE.getY());
_recalculate = true;
repaint();
}
- _dragFromX = inE.getX();
- _dragFromY = inE.getY();
+ _dragFromX = _dragToX = inE.getX();
+ _dragFromY = _dragToY = inE.getY();
}
else
{
// Right-click and drag - draw rectangle and control zoom
- _zoomDragging = true;
+ _drawMode = MODE_ZOOM_RECT;
if (_dragFromX == -1) {
_dragFromX = inE.getX();
_dragFromY = inE.getY();
@@ -917,7 +971,13 @@ public class MapCanvas extends JPanel implements MouseListener, MouseMotionListe
*/
public void mouseMoved(MouseEvent inEvent)
{
- // ignore
+ // Ignore unless we're drawing points
+ if (_drawMode == MODE_DRAW_POINTS_CONT)
+ {
+ _dragToX = inEvent.getX();
+ _dragToY = inEvent.getY();
+ repaint();
+ }
}
/**
@@ -998,8 +1058,11 @@ public class MapCanvas extends JPanel implements MouseListener, MouseMotionListe
else if (code == KeyEvent.VK_LEFT)
rightwardsPan = -PAN_DISTANCE;
panMap(rightwardsPan, upwardsPan);
+ // Check for escape
+ if (code == KeyEvent.VK_ESCAPE)
+ _drawMode = MODE_DEFAULT;
// Check for backspace key to delete current point (delete key already handled by menu)
- if (code == KeyEvent.VK_BACK_SPACE && currPointIndex >= 0) {
+ else if (code == KeyEvent.VK_BACK_SPACE && currPointIndex >= 0) {
_app.deleteCurrentPoint();
}
}
diff --git a/tim/prune/gui/map/MapSource.java b/tim/prune/gui/map/MapSource.java
index c2311ae..35590a6 100644
--- a/tim/prune/gui/map/MapSource.java
+++ b/tim/prune/gui/map/MapSource.java
@@ -69,23 +69,34 @@ public abstract class MapSource
* @param inUrl url to check
* @return validated url with correct prefix and trailing slash, or null
*/
- protected static String fixBaseUrl(String inUrl)
+ public static String fixBaseUrl(String inUrl)
{
if (inUrl == null || inUrl.equals("")) {return null;}
- String url = inUrl;
+ String urlstr = inUrl;
// check prefix
try {
- new URL(url);
+ new URL(urlstr);
}
catch (MalformedURLException e) {
+ // fail if protocol specified
+ if (urlstr.indexOf("://") >= 0) {return null;}
// add the http protocol
- url = "http://" + url;
+ urlstr = "http://" + urlstr;
}
// check trailing /
- if (!url.endsWith("/")) {
- url = url + "/";
+ if (!urlstr.endsWith("/")) {
+ urlstr = urlstr + "/";
}
- return url;
+ // Validate current url, return null if not ok
+ try {
+ URL url = new URL(urlstr);
+ // url host must contain a dot
+ if (url.getHost().indexOf('.') < 0) {return null;}
+ }
+ catch (MalformedURLException e) {
+ urlstr = null;
+ }
+ return urlstr;
}
/**
@@ -114,11 +125,14 @@ public abstract class MapSource
*/
public String getSiteStrings()
{
- String s = "";
+ StringBuilder sb = new StringBuilder();
for (int i=0; idouble.
+ * Prevents interpretation of 32 bit numbers as negative, and forces a positive answer
+ */
+ public static final double convertToPositiveValue(int inNumerator, int inDenominator)
+ {
+ if (inDenominator == 0) return 0.0;
+ double numeratorDbl = inNumerator;
+ double denomDbl = inDenominator;
+ if (inNumerator >= 0)
+ return numeratorDbl / denomDbl;
+ final double correction = Math.pow(2.0, 32);
+ numeratorDbl += correction;
+ if (inDenominator < 0) denomDbl += correction;
+ return numeratorDbl / denomDbl;
+ }
}
diff --git a/tim/prune/jpeg/ExternalExifLibrary.java b/tim/prune/jpeg/ExternalExifLibrary.java
index 1c64b4e..cff2346 100644
--- a/tim/prune/jpeg/ExternalExifLibrary.java
+++ b/tim/prune/jpeg/ExternalExifLibrary.java
@@ -42,12 +42,14 @@ public class ExternalExifLibrary implements ExifLibrary
{
data.setLatitudeRef(gpsdir.getString(GpsDirectory.TAG_GPS_LATITUDE_REF));
Rational[] latRats = gpsdir.getRationalArray(GpsDirectory.TAG_GPS_LATITUDE);
+ double seconds = ExifGateway.convertToPositiveValue(latRats[2].getNumerator(), latRats[2].getDenominator());
data.setLatitude(new double[] {latRats[0].doubleValue(),
- latRats[1].doubleValue(), latRats[2].doubleValue()});
+ latRats[1].doubleValue(), seconds});
data.setLongitudeRef(gpsdir.getString(GpsDirectory.TAG_GPS_LONGITUDE_REF));
Rational[] lonRats = gpsdir.getRationalArray(GpsDirectory.TAG_GPS_LONGITUDE);
+ seconds = ExifGateway.convertToPositiveValue(lonRats[2].getNumerator(), lonRats[2].getDenominator());
data.setLongitude(new double[] {lonRats[0].doubleValue(),
- lonRats[1].doubleValue(), lonRats[2].doubleValue()});
+ lonRats[1].doubleValue(), seconds});
}
// Altitude (if present)
@@ -110,6 +112,7 @@ public class ExternalExifLibrary implements ExifLibrary
return data;
}
+
/**
* Check whether the exifreader class can be correctly resolved
* @return true if it looks ok
diff --git a/tim/prune/jpeg/drew/ExifReader.java b/tim/prune/jpeg/drew/ExifReader.java
index d4df892..384778d 100644
--- a/tim/prune/jpeg/drew/ExifReader.java
+++ b/tim/prune/jpeg/drew/ExifReader.java
@@ -3,6 +3,7 @@ package tim.prune.jpeg.drew;
import java.io.File;
import java.util.HashMap;
+import tim.prune.jpeg.ExifGateway;
import tim.prune.jpeg.JpegData;
/**
@@ -93,8 +94,7 @@ public class ExifReader
*/
public ExifReader(File inFile) throws JpegException
{
- JpegSegmentData segments = JpegSegmentReader.readSegments(inFile);
- _data = segments.getSegment(JpegSegmentReader.SEGMENT_APP1);
+ _data = JpegSegmentReader.readExifSegment(inFile);
}
/**
@@ -343,14 +343,16 @@ public class ExifReader
break;
case TAG_GPS_LATITUDE:
Rational[] latitudes = readRationalArray(inTagValueOffset, inFormatCode, inComponentCount);
- inMetadata.setLatitude(new double[] {latitudes[0].doubleValue(), latitudes[1].doubleValue(), latitudes[2].doubleValue()});
+ inMetadata.setLatitude(new double[] {latitudes[0].doubleValue(), latitudes[1].doubleValue(),
+ ExifGateway.convertToPositiveValue(latitudes[2].getNumerator(), latitudes[2].getDenominator())});
break;
case TAG_GPS_LONGITUDE_REF:
inMetadata.setLongitudeRef(readString(inTagValueOffset, inFormatCode, inComponentCount));
break;
case TAG_GPS_LONGITUDE:
Rational[] longitudes = readRationalArray(inTagValueOffset, inFormatCode, inComponentCount);
- inMetadata.setLongitude(new double[] {longitudes[0].doubleValue(), longitudes[1].doubleValue(), longitudes[2].doubleValue()});
+ inMetadata.setLongitude(new double[] {longitudes[0].doubleValue(), longitudes[1].doubleValue(),
+ ExifGateway.convertToPositiveValue(longitudes[2].getNumerator(), longitudes[2].getDenominator())});
break;
case TAG_GPS_ALTITUDE_REF:
inMetadata.setAltitudeRef(_data[inTagValueOffset]);
diff --git a/tim/prune/jpeg/drew/JpegSegmentReader.java b/tim/prune/jpeg/drew/JpegSegmentReader.java
index 382e9f5..65515a1 100644
--- a/tim/prune/jpeg/drew/JpegSegmentReader.java
+++ b/tim/prune/jpeg/drew/JpegSegmentReader.java
@@ -14,94 +14,64 @@ public class JpegSegmentReader
/** End of image marker */
private static final byte MARKER_EOI = (byte)0xD9;
- /** APP0 Jpeg segment identifier -- Jfif data. */
- public static final byte SEGMENT_APP0 = (byte)0xE0;
/** APP1 Jpeg segment identifier -- where Exif data is kept. */
- public static final byte SEGMENT_APP1 = (byte)0xE1;
- /** APP2 Jpeg segment identifier. */
- public static final byte SEGMENT_APP2 = (byte)0xE2;
- /** APP3 Jpeg segment identifier. */
- public static final byte SEGMENT_APP3 = (byte)0xE3;
- /** APP4 Jpeg segment identifier. */
- public static final byte SEGMENT_APP4 = (byte)0xE4;
- /** APP5 Jpeg segment identifier. */
- public static final byte SEGMENT_APP5 = (byte)0xE5;
- /** APP6 Jpeg segment identifier. */
- public static final byte SEGMENT_APP6 = (byte)0xE6;
- /** APP7 Jpeg segment identifier. */
- public static final byte SEGMENT_APP7 = (byte)0xE7;
- /** APP8 Jpeg segment identifier. */
- public static final byte SEGMENT_APP8 = (byte)0xE8;
- /** APP9 Jpeg segment identifier. */
- public static final byte SEGMENT_APP9 = (byte)0xE9;
- /** APPA Jpeg segment identifier -- can hold Unicode comments. */
- public static final byte SEGMENT_APPA = (byte)0xEA;
- /** APPB Jpeg segment identifier. */
- public static final byte SEGMENT_APPB = (byte)0xEB;
- /** APPC Jpeg segment identifier. */
- public static final byte SEGMENT_APPC = (byte)0xEC;
- /** APPD Jpeg segment identifier -- IPTC data in here. */
- public static final byte SEGMENT_APPD = (byte)0xED;
- /** APPE Jpeg segment identifier. */
- public static final byte SEGMENT_APPE = (byte)0xEE;
- /** APPF Jpeg segment identifier. */
- public static final byte SEGMENT_APPF = (byte)0xEF;
- /** Start Of Image segment identifier. */
- public static final byte SEGMENT_SOI = (byte)0xD8;
- /** Define Quantization Table segment identifier. */
- public static final byte SEGMENT_DQT = (byte)0xDB;
- /** Define Huffman Table segment identifier. */
- public static final byte SEGMENT_DHT = (byte)0xC4;
- /** Start-of-Frame Zero segment identifier. */
- public static final byte SEGMENT_SOF0 = (byte)0xC0;
- /** Jpeg comment segment identifier. */
- public static final byte SEGMENT_COM = (byte)0xFE;
+ private static final byte SEGMENT_APP1 = (byte)0xE1;
/** Magic numbers to mark the beginning of all Jpegs */
private static final int MAGIC_JPEG_BYTE_1 = 0xFF;
private static final int MAGIC_JPEG_BYTE_2 = 0xD8;
+ /**
+ * Get the Exif data segment for the specified file
+ * @param inFile File to read
+ * @return Exif data segment as byte array
+ * @throws JpegException on file read errors or exif data errors
+ */
+ public static byte[] readExifSegment(File inFile) throws JpegException
+ {
+ JpegSegmentData data = readSegments(inFile);
+ return data.getSegment(SEGMENT_APP1);
+ }
+
+
/**
* Obtain the Jpeg segment data from the specified file
* @param inFile File to read
* @return Jpeg segment data from file
* @throws JpegException on file read errors or exif data errors
*/
- public static JpegSegmentData readSegments(File inFile) throws JpegException
+ private static JpegSegmentData readSegments(File inFile) throws JpegException
{
JpegSegmentData segmentData = new JpegSegmentData();
-
BufferedInputStream bStream = null;
try
{
bStream = new BufferedInputStream(new FileInputStream(inFile));
- int offset = 0;
// first two bytes should be jpeg magic number
- int magic1 = bStream.read() & 0xFF;
- int magic2 = bStream.read() & 0xFF;
- checkMagicNumbers(magic1, magic2);
+ final int magic1 = bStream.read() & 0xFF;
+ final int magic2 = bStream.read() & 0xFF;
+ if (magic1 != MAGIC_JPEG_BYTE_1 || magic2 != MAGIC_JPEG_BYTE_2) {
+ throw new JpegException("not a jpeg file");
+ }
- offset += 2;
// Loop around segments found
+ boolean foundExif = false;
do
{
// next byte is 0xFF
byte segmentIdentifier = (byte) (bStream.read() & 0xFF);
if ((segmentIdentifier & 0xFF) != 0xFF)
{
- throw new JpegException("expected jpeg segment start identifier 0xFF at offset "
- + offset + ", not 0x" + Integer.toHexString(segmentIdentifier & 0xFF));
+ throw new JpegException("expected jpeg segment start 0xFF, not 0x"
+ + Integer.toHexString(segmentIdentifier & 0xFF));
}
- offset++;
// next byte is
byte thisSegmentMarker = (byte) (bStream.read() & 0xFF);
- offset++;
// next 2-bytes are : [high-byte] [low-byte]
byte[] segmentLengthBytes = new byte[2];
bStream.read(segmentLengthBytes, 0, 2);
- offset += 2;
int segmentLength = ((segmentLengthBytes[0] << 8) & 0xFF00) | (segmentLengthBytes[1] & 0xFF);
// segment length includes size bytes, so subtract two
segmentLength -= 2;
@@ -110,8 +80,11 @@ public class JpegSegmentReader
else if (segmentLength < 0)
throw new JpegException("segment size would be less than zero");
byte[] segmentBytes = new byte[segmentLength];
- bStream.read(segmentBytes, 0, segmentLength);
- offset += segmentLength;
+ int bytesRead = bStream.read(segmentBytes, 0, segmentLength);
+ // Bail if not all bytes read in one go - otherwise following sections will be out of step
+ if (bytesRead != segmentLength) {
+ throw new JpegException("Tried to read " + segmentLength + " bytes but only got " + bytesRead);
+ }
if ((thisSegmentMarker & 0xFF) == (SEGMENT_SOS & 0xFF))
{
// The 'Start-Of-Scan' segment comes last so break out of loop
@@ -126,9 +99,10 @@ public class JpegSegmentReader
{
segmentData.addSegment(thisSegmentMarker, segmentBytes);
}
- // loop through to the next segment
+ // loop through to the next segment if exif hasn't already been found
+ foundExif = (thisSegmentMarker == SEGMENT_APP1);
}
- while (true);
+ while (!foundExif);
}
catch (FileNotFoundException fnfe)
{
@@ -153,19 +127,4 @@ public class JpegSegmentReader
// Return the result
return segmentData;
}
-
-
- /**
- * Helper method that validates the Jpeg file's magic number.
- * @param inMagic1 first half of magic number
- * @param inMagic2 second half of magic number
- * @throws JpegException if numbers do not match magic numbers expected
- */
- private static void checkMagicNumbers(int inMagic1, int inMagic2) throws JpegException
- {
- if (inMagic1 != MAGIC_JPEG_BYTE_1 || inMagic2 != MAGIC_JPEG_BYTE_2)
- {
- throw new JpegException("not a jpeg file");
- }
- }
-}
\ No newline at end of file
+}
diff --git a/tim/prune/lang/prune-texts_af.properties b/tim/prune/lang/prune-texts_af.properties
index 109aeb8..2c0b6ce 100644
--- a/tim/prune/lang/prune-texts_af.properties
+++ b/tim/prune/lang/prune-texts_af.properties
@@ -29,9 +29,9 @@ menu.range.start=Stel Reeks Begin
menu.range.end=Stel Reeks Einde
menu.photo=Foto
menu.photo.saveexif=Stoor na EXIF
-menu.photo.connect=Las foto by huidige punt
-menu.photo.disconnect=Ontkoppel foto vanaf huidige punt
-menu.photo.delete=Verwyder foto
+function.connecttopoint=Las foto by huidige punt
+function.disconnectfrompoint=Ontkoppel vanaf huidige punt
+function.removephoto=Verwyder foto
menu.view=Kyk
menu.view.browser=Kaart in werf blaaier
menu.view.browser.google=Google Kaarte
diff --git a/tim/prune/lang/prune-texts_cz.properties b/tim/prune/lang/prune-texts_cz.properties
index 93f4494..37ab637 100644
--- a/tim/prune/lang/prune-texts_cz.properties
+++ b/tim/prune/lang/prune-texts_cz.properties
@@ -1,5 +1,5 @@
# Text entries for the Prune application
-# Czech entries as extra
+# Czech entries thanks to prot_d
# Menu entries
menu.file=Soubor
@@ -10,7 +10,7 @@ menu.track=Trasa
menu.track.undo=Undo
menu.track.clearundo=Vypr\u00e1zdnit pam\u011b\u0165 undo
menu.track.deletemarked=Smazat ozna\u010den\u00e9 body
-menu.track.rearrange=P\u0159euspo\u0159\u00e1dat body
+menu.track.rearrange=P\u0159euspo\u0159\u00e1dat z\u00e1jmov\u00e9 body
menu.track.rearrange.start=V\u0161e na po\u010d\u00e1tek
menu.track.rearrange.end=V\u0161e na konec
menu.track.rearrange.nearest=Zarovnat body na trasu
@@ -30,9 +30,7 @@ menu.point.editpoint=Upravit bod
menu.point.deletepoint=Smazat bod
menu.photo=Fotografie
menu.photo.saveexif=Ulo\u017eit do Exif
-menu.photo.connect=P\u0159ipojit do bodu
-menu.photo.disconnect=Odpojit od bodu
-menu.photo.delete=Odebrat fotografii
+menu.audio=Audionahr\u00e1vka
menu.view=Zobrazen\u00ed
menu.view.showsidebars=Zobrazit panely
menu.view.browser=Mapa v internetov\u00e9m prohl\u00ed\u017ee\u010di
@@ -49,7 +47,8 @@ menu.map.zoomin=P\u0159ibl\u00ed\u017eit
menu.map.zoomout=Odd\u00e1lit
menu.map.zoomfull=\u00dapln\u011b odd\u00e1lit
menu.map.newpoint=Vytvo\u0159it nov\u00fd bod
-menu.map.connect=Propojit body
+menu.map.drawpoints=Vytvo\u0159it n\u011bkolik bod\u016f
+menu.map.connect=Propojit body trasy
menu.map.autopan=Automatika zorn\u00e9ho pole
menu.map.showmap=Zobrazit mapu
menu.map.showscalebar=Zobrazit m\u011b\u0159\u00edtko
@@ -61,6 +60,7 @@ altkey.menu.range=R
altkey.menu.point=B
altkey.menu.view=Z
altkey.menu.photo=F
+altkey.menu.audio=A
altkey.menu.settings=N
altkey.menu.help=P
@@ -81,11 +81,11 @@ function.exportkml=Export KML
function.exportgpx=Export GPX
function.exportpov=Export POV
function.exportsvg=Export SVG
-function.editwaypointname=Nastavit n\u00e1zev bodu
+function.editwaypointname=Nastavit n\u00e1zev v\u00fdzna\u010dn\u00e9ho bodu
function.compress=Komprimovat trasu
function.addtimeoffset=P\u0159idat \u010dasov\u00fd posun
function.addaltitudeoffset=P\u0159idat v\u00fd\u0161kov\u00fd posun
-function.convertnamestotimes=P\u0159ev\u00e9st n\u00e1zvy bod\u016f na \u010dasov\u00e9 zna\u010dky
+function.convertnamestotimes=P\u0159ev\u00e9st n\u00e1zvy v\u00fdzna\u010dn\u00fdch bod\u016f na \u010dasy
function.deletefieldvalues=Smazat hodnoty pole
function.findwaypoint=Hledat bod
function.pastecoordinates=Zadat sou\u0159adnice
@@ -99,14 +99,27 @@ function.setpaths=Nastavit cestu k program\u016fm
function.getgpsies=St\u00e1hnout trasy z Gpsies
function.uploadgpsies=Nahr\u00e1t trasu na Gpsies
function.lookupsrtm=Na\u010d\u00edst nadm. v\u00fd\u0161ku ze SRTM
+function.getwikipedia=Hledat na Wikipedii podle vzd\u00e1lenosti
+function.searchwikipedianames=Hledat na Wikipedii podle jm\u00e9na
+function.downloadosm=St\u00e1hnout data OSM pro oblast
function.duplicatepoint=Zdvojit bod
function.setcolours=Nastavit barvy
+function.setlinewidth=Nastavit tlou\u0161\u0165ku \u010d\u00e1ry
function.setlanguage=Nastavit jazyk
+function.connecttopoint=P\u0159ipojit do bodu
+function.disconnectfrompoint=Odpojit od bodu
+function.removephoto=Odebrat fotografii
function.correlatephotos=Sladit fotografie podle \u010dasu
function.rearrangephotos=Uspo\u0159\u00e1dat fotografie
function.rotatephotoleft=Oto\u010dit fotografii doleva
function.rotatephotoright=Oto\u010dit fotografii doprava
+function.photopopup=Zobrazit celou fotografii
function.ignoreexifthumb=Ignorovat n\u00e1hled v Exif
+function.loadaudio=P\u0159idat audionahr\u00e1vky
+function.removeaudio=Odebrat audionahr\u00e1vku
+function.correlateaudios=Sladit audionahr\u00e1vky podle \u010dasu
+function.playaudio=P\u0159ehr\u00e1t audionahr\u00e1vku
+function.stopaudio=Zastavit p\u0159ehr\u00e1v\u00e1n\u00ed
function.help=Pomoc
function.showkeys=Zobrazit kl\u00e1vesov\u00e9 zkratky
function.about=O programu
@@ -149,7 +162,7 @@ dialog.jpegload.progress=Pros\u00edm chvilku strpen\u00ed p\u0159i vyhled\u00e1v
dialog.gpsload.nogpsbabel=Nenalezen program gpsbabel. Pokra\u010dovat?
dialog.gpsload.device=Ozna\u010den\u00ed za\u0159\u00edzen\u00ed
dialog.gpsload.format=Form\u00e1t
-dialog.gpsload.getwaypoints=Na\u010d\u00edst body
+dialog.gpsload.getwaypoints=Na\u010d\u00edst v\u00fdzna\u010dn\u00e9 body
dialog.gpsload.gettracks=Na\u010d\u00edst trasy
dialog.gpsload.save=Ulo\u017eit do souboru
dialog.gpssend.sendwaypoints=Poslat bod
@@ -168,7 +181,7 @@ dialog.save.overwrite.title=Soubor u\u017e existuje
dialog.save.overwrite.text=Tento soubor u\u017e existuje. Opravdu chcete soubor p\u0159epsat?
dialog.save.notypesselected=Nebyl vybr\u00e1n ani jeden typ bod\u016f
dialog.exportkml.text=Nadpis dat
-dialog.exportkml.altitude=V\u00fd\u0161ka nad hladinou mo\u0159e (pro l\u00e9t\u00e1n\u00ed)
+dialog.exportkml.altitude=V\u00fd\u0161ka nad hladinou mo\u0159e (pro letectv\u00ed)
dialog.exportkml.kmz=Komprimovat do souboru kmz
dialog.exportkml.exportimages=Vlo\u017eit n\u00e1hledy fotografi\u00ed
dialog.exportkml.trackcolour=Barva trasy
@@ -193,6 +206,7 @@ dialog.pointtype.desc=Ulo\u017eit body n\u00e1sleduj\u00edc\u00edch typ\u016f:
dialog.pointtype.track=Body trasy
dialog.pointtype.waypoint=V\u00fdzna\u010dn\u00e9 body
dialog.pointtype.photo=M\u00edsta s fotografiemi
+dialog.pointtype.audio=M\u00edsta s audionahr\u00e1vkami
dialog.pointtype.selection=Jen v\u00fdb\u011br
dialog.confirmreversetrack.title=Potvr\u010fte obr\u00e1cen\u00ed
dialog.confirmreversetrack.text=Tato trasa obsahuje \u010dasov\u00e9 zna\u010dky, jejich\u017e po\u0159ad\u00ed se obr\u00e1cen\u00edm zm\u011bn\u00ed.\nOpravdu chcete obr\u00e1tit v\u00fdb\u011br?
@@ -214,7 +228,7 @@ dialog.pointedit.table.changed=Zm\u011bn\u011bno
dialog.pointedit.changevalue.text=Zadejte novou hodnotu pole
dialog.pointedit.changevalue.title=Upravit pole
dialog.pointnameedit.name=N\u00e1zev v\u00fdzna\u010dn\u00e9ho bodu
-dialog.pointnameedit.uppercase=VELKÁ p\u00edsmena
+dialog.pointnameedit.uppercase=VELK\u00c1 p\u00edsmena
dialog.pointnameedit.lowercase=mal\u00e1 p\u00edsmena
dialog.pointnameedit.sentencecase=Po\u010d\u00e1te\u010dn\u00ed P\u00edsmena Velk\u00e1
dialog.addtimeoffset.add=P\u0159idat \u010das
@@ -278,12 +292,14 @@ dialog.gpsies.activity.motorbiking=Motorka
dialog.gpsies.activity.snowshoe=Sn\u011b\u017enice
dialog.gpsies.activity.sailing=Lo\u010f
dialog.gpsies.activity.skating=Bruslen\u00ed
+dialog.wikipedia.column.name=N\u00e1zev \u010dl\u00e1nku
+dialog.wikipedia.column.distance=Vzd\u00e1lenost
dialog.correlate.notimestamps=U bod\u016f nejsou \u010dasov\u00e9 zna\u010dky, tak\u017ee nen\u00ed s \u010d\u00edm fotografie sladit.
dialog.correlate.nouncorrelatedphotos=V\u0161echny fotografie jsou slad\u011bn\u00e9.\nOpravdu chcete pokra\u010dovat?
dialog.correlate.photoselect.intro=Vyberte jednu z t\u011bchto slad\u011bn\u00fdch fotografi\u00ed pro ur\u010den\u00ed \u010dasov\u00e9ho posunu
-dialog.correlate.photoselect.photoname=N\u00e1zev fotografie
-dialog.correlate.photoselect.timediff=\u010casov\u00fd rozd\u00edl
-dialog.correlate.photoselect.photolater=Vyfoceno pozd\u011bji
+dialog.correlate.select.photoname=N\u00e1zev fotografie
+dialog.correlate.select.timediff=\u010casov\u00fd rozd\u00edl
+dialog.correlate.select.photolater=Vyfoceno pozd\u011bji
dialog.correlate.options.tip=Tip: kdy\u017e ru\u010dn\u011b slad\u00edte aspo\u0148 jednu fotografii, \u010dasov\u00fd posun bude vypo\u010d\u00edtat za v\u00e1s.
dialog.correlate.options.intro=Upravte mo\u017enosti automatick\u00e9ho slad\u011bn\u00ed
dialog.correlate.options.offsetpanel=\u010casov\u00fd posun
@@ -292,7 +308,9 @@ dialog.correlate.options.offset.hours=hodin,
dialog.correlate.options.offset.minutes=minut a
dialog.correlate.options.offset.seconds=sekund
dialog.correlate.options.photolater=Fotografie pozd\u011bj\u0161\u00ed ne\u017e bod
-dialog.correlate.options.pointlater=Bod pozd\u011bj\u0161\u00ed ne\u017e fotografie
+dialog.correlate.options.pointlaterphoto=Bod pozd\u011bj\u0161\u00ed ne\u017e fotografie
+dialog.correlate.options.audiolater=Audio pozd\u011bj\u0161\u00ed ne\u017e bod
+dialog.correlate.options.pointlateraudio=Bod pozd\u011bj\u0161\u00ed ne\u017e audio
dialog.correlate.options.limitspanel=Limity slad\u011bn\u00ed
dialog.correlate.options.notimelimit=Bez \u010dasov\u00e9ho limitu
dialog.correlate.options.timelimit=\u010casov\u00fd limit
@@ -300,6 +318,15 @@ dialog.correlate.options.nodistancelimit=Bez d\u00e9lkov\u00e9ho limitu
dialog.correlate.options.distancelimit=D\u00e9lkov\u00fd limit
dialog.correlate.options.correlate=Sladit
dialog.correlate.alloutsiderange=V\u0161echny fotografie le\u017e\u00ed mimo \u010dasov\u00e9 rozmez\u00ed trasy, tak\u017ee nemohou b\u00fdt slad\u011bny.\nPokuste se zm\u011bnit \u010dasov\u00fd posun nebo ru\u010dn\u011b sla\u010fte aspo\u0148 jednu fotografii.
+dialog.correlate.filetimes=\u010cas z\u00e1znamu souboru znamen\u00e1:
+dialog.correlate.filetimes2=audionahr\u00e1vky
+dialog.correlate.correltimes=Sladit tento okam\u017eik nahr\u00e1vky:
+dialog.correlate.timestamp.beginning=Za\u010d\u00e1tek
+dialog.correlate.timestamp.middle=St\u0159ed
+dialog.correlate.timestamp.end=Konec
+dialog.correlate.audioselect.intro=Vyberte jednu z t\u011bchto slad\u011bn\u00fdch nahr\u00e1vek pro ur\u010den\u00ed \u010dasov\u00e9ho posunu
+dialog.correlate.select.audioname=N\u00e1zev audionahr\u00e1vky
+dialog.correlate.select.audiolater=Audio pozd\u011bj\u0161\u00ed
dialog.rearrangephotos.desc=Vyberte um\u00edst\u011bn\u00ed a uspo\u0159\u00e1d\u00e1n\u00ed bod\u016f fotografi\u00ed
dialog.rearrangephotos.tostart=P\u0159en\u00e9st na za\u010d\u00e1tek
dialog.rearrangephotos.toend=P\u0159en\u00e9st na konec
@@ -380,6 +407,7 @@ dialog.saveconfig.prune.diskcache=Cache s mapami
dialog.saveconfig.prune.kmzimagewidth=\u0160\u00ed\u0159ka bitmapy KMZ
dialog.saveconfig.prune.kmzimageheight=V\u00fd\u0161ka bitmapy KMZ
dialog.saveconfig.prune.colourscheme=Barevn\u00e9 sch\u00e9ma
+dialog.saveconfig.prune.linewidth=Tlou\u0161\u0165ka \u010d\u00e1ry
dialog.saveconfig.prune.kmltrackcolour=Barva trasy v KML
dialog.setpaths.intro=Je-li to t\u0159eba, m\u016f\u017eete nastavit cesty k extern\u00edm aplikac\u00edm:
dialog.setpaths.found=Cesta nalezena?
@@ -409,6 +437,9 @@ dialog.diskcache.dir=Adres\u00e1\u0159 s cache
dialog.diskcache.createdir=Vytvo\u0159it adres\u00e1\u0159
dialog.diskcache.nocreate=Adres\u00e1\u0159 nebyl vytvo\u0159en
dialog.deletefieldvalues.intro=Vyberte pole, kter\u00e9 se m\u00e1 z aktu\u00e1ln\u00edho rozmez\u00ed odstranit
+dialog.setlinewidth.text=Zvolte tlou\u0161\u0165ku \u010d\u00e1ry, kterou se nakresl\u00ed trasa (1-4)
+dialog.downloadosm.desc=Potvr\u010fte, \u017ee se maj\u00ed k dan\u00e9 oblasti st\u00e1hnout data OSM:
+dialog.searchwikipedianames.search=Vyhledat:
# 3d window
dialog.3d.title=Trojrozm\u011brn\u00e9 zobrazen\u00ed Prune
@@ -438,16 +469,21 @@ confirm.undo.single=operace vr\u00e1cena
confirm.undo.multi=operac\u00ed vr\u00e1ceno
confirm.jpegload.single=fotografie p\u0159id\u00e1na
confirm.jpegload.multi=fotografie p\u0159id\u00e1ny
-confirm.photo.connect=fotografie propojena
+confirm.media.connect=soubor p\u0159ipojen
confirm.photo.disconnect=fotografie odpojena
-confirm.correlate.single=fotografie slad\u011bna
-confirm.correlate.multi=fotografie slad\u011bny
+confirm.audio.disconnect=audionahr\u00e1vka odpojena
+confirm.media.removed=odstran\u011bno
+confirm.correlatephotos.single=fotografie slad\u011bna
+confirm.correlatephotos.multi=fotografie slad\u011bny
confirm.createpoint=bod vytvo\u0159en
confirm.rotatephoto=fotografie oto\u010dena
confirm.running=Prob\u00edh\u00e1 ...
confirm.lookupsrtm1=Nalezeno
confirm.lookupsrtm2=v\u00fd\u0161kov\u00fdch hodnot
confirm.deletefieldvalues=Hodnoty pole smaz\u00e1ny
+confirm.audioload=Audionahr\u00e1vky p\u0159id\u00e1ny
+confirm.correlateaudios.single=Audionahr\u00e1vka slad\u011bna
+confirm.correlateaudios.multi=Audionahr\u00e1vky slad\u011bny
# Buttons
button.ok=OK
@@ -490,6 +526,7 @@ filetype.kmz=soubory KMZ
filetype.gpx=soubory GPX
filetype.pov=soubory POV
filetype.svg=soubory SVG
+filetype.audio=soubory MP3, OGG, WAV
# Display components
display.nodata=\u017d\u00e1dn\u00e1 data
@@ -524,12 +561,17 @@ details.range.maxspeed=Max. rychlost
details.range.numsegments=Po\u010det segment\u016f
details.range.pace=Tempo
details.range.gradient=Sp\u00e1d
-details.waypointsphotos.waypoints=V\u00fdzna\u010dn\u00e9 body
-details.waypointsphotos.photos=Fotografie
+details.lists.waypoints=V\u00fdzna\u010dn\u00e9 body
+details.lists.photos=Fotografie
+details.lists.audio=Audionahr\u00e1vky
details.photodetails=Detaily fotografie
details.nophoto=Fotografie nevybr\u00e1na
details.photo.loading=Na\u010d\u00edt\u00e1m
-details.photo.connected=P\u0159ipojeno
+details.media.connected=P\u0159ipojeno
+details.audiodetails=Detaily audionahr\u00e1vky
+details.noaudio=Audionahr\u00e1vka nevybr\u00e1na
+details.audio.file=Zvukov\u00fd soubor
+details.audio.playing=p\u0159ehr\u00e1v\u00e1n...
map.overzoom=P\u0159i tomto p\u0159ibl\u00ed\u017een\u00ed mapa nen\u00ed k dispozici
# Field names
@@ -572,6 +614,7 @@ units.iso8601=ISO 8601
# External urls
url.googlemaps=maps.google.cz
+wikipedia.lang=cs
# Cardinals for 3d plots
cardinal.n=N
@@ -582,9 +625,11 @@ cardinal.w=W
# Undo operations
undo.load=na\u010d\u00edst data
undo.loadphotos=na\u010d\u00edst fotografie
+undo.loadaudios=na\u010d\u00edst audionahr\u00e1vky
undo.editpoint=upravit bod
undo.deletepoint=smazat bod
-undo.deletephoto=odebrat fotografii
+undo.removephoto=odebrat fotografii
+undo.removeaudio=odebrat audionahr\u00e1vku
undo.deleterange=smazat rozmez\u00ed
undo.compress=zkomprimovat trasu
undo.insert=vlo\u017eit body
@@ -594,15 +639,16 @@ undo.addtimeoffset=p\u0159idat \u010dasov\u00fd posun
undo.addaltitudeoffset=p\u0159idat v\u00fd\u0161kov\u00fd posun
undo.rearrangewaypoints=p\u0159euspo\u0159\u00e1dat body
undo.cutandmove=p\u0159esunout v\u00fdb\u011br
-undo.connectphoto=p\u0159ipojit fotografii
-undo.disconnectphoto=odpojit fotografii
-undo.correlate=sladit fotografie
+undo.connect=p\u0159ipojit
+undo.disconnect=odpojit
+undo.correlatephotos=sladit fotografie
undo.rearrangephotos=uspo\u0159\u00e1dat fotografie
undo.createpoint=vytvo\u0159it bod
undo.rotatephoto=oto\u010dit fotografii
undo.convertnamestotimes=p\u0159ev\u00e9st n\u00e1zvy na \u010dasy
undo.lookupsrtm=na\u010d\u00edst nadm. v\u00fd\u0161ky ze SRTM
undo.deletefieldvalues=smazat hodnoty pol\u00ed
+undo.correlateaudios=sladit audionahr\u00e1vky
# Error messages
error.save.dialogtitle=Chyba p\u0159i ukl\u00e1d\u00e1n\u00ed
@@ -624,9 +670,9 @@ error.load.othererror=Chyba p\u0159i \u010dten\u00ed souboru:
error.jpegload.dialogtitle=Chyba p\u0159i na\u010d\u00edt\u00e1n\u00ed fotografi\u00ed
error.jpegload.nofilesfound=Nenalezeny \u017e\u00e1dn\u00e9 soubory
error.jpegload.nojpegsfound=Nenalezeny \u017e\u00e1dn\u00e9 soubory jpeg
-error.jpegload.noexiffound=Nenalezena informace EXIF
error.jpegload.nogpsfound=Nenalezena informace GPS
error.jpegload.exifreadfailed=Nepoda\u0159ilo se na\u010d\u00edst informaci EXIF. Tu nelze na\u010d\u00edst\nbez intern\u00ed nebo extern\u00ed knihovny.
+error.audioload.nofilesfound=Nebyly nalezeny \u017e\u00e1dn\u00e9 zvukov\u00e9 soubory.
error.gpsload.unknown=Nezn\u00e1m\u00e1 chyba
error.undofailed.title=Selhalo undo
error.undofailed.text=Nepoda\u0159ilo se vr\u00e1tit operaci
@@ -644,3 +690,4 @@ error.lookupsrtm.nonefound=Pro tyto body nen\u00ed k dispozici informace o nadmo
error.lookupsrtm.nonerequired=U v\u0161ech bod\u016f u\u017e je informaci o v\u00fd\u0161ce, tak\u017ee nen\u00ed co dohled\u00e1vat
error.gpsies.uploadnotok=Server gpsies vr\u00e1til hl\u00e1\u0161en\u00ed
error.gpsies.uploadfailed=Chyba - nepoda\u0159ilo se nahr\u00e1t data.
+error.playaudiofailed=Nepoda\u0159ilo se p\u0159ehr\u00e1t zvukov\u00fd soubor.
diff --git a/tim/prune/lang/prune-texts_de.properties b/tim/prune/lang/prune-texts_de.properties
index cc95059..a2a45ba 100644
--- a/tim/prune/lang/prune-texts_de.properties
+++ b/tim/prune/lang/prune-texts_de.properties
@@ -30,9 +30,10 @@ menu.point.editpoint=Punkt bearbeiten
menu.point.deletepoint=Punkt l\u00f6schen
menu.photo=Foto
menu.photo.saveexif=Exif Daten speichern
-menu.photo.connect=Mit Punkt verkn\u00fcpfen
-menu.photo.disconnect=Vom Punkt trennen
-menu.photo.delete=Foto entfernen
+function.connecttopoint=Mit Punkt verkn\u00fcpfen
+function.disconnectfrompoint=Vom Punkt trennen
+function.removephoto=Foto entfernen
+menu.audio=Audio
menu.view=Ansicht
menu.view.showsidebars=Seitenleisten anzeigen
menu.view.browser=Karte in Browser
@@ -44,6 +45,7 @@ menu.map.zoomin=Hineinzoomen
menu.map.zoomout=Herauszoomen
menu.map.zoomfull=Auf Bildschirmgr\u00f6\u00dfe zoomen
menu.map.newpoint=Neuen Punkt erzeugen
+menu.map.drawpoints=Punktereihe aufzeichnen
menu.map.connect=Trackpunkte mit Linie anzeigen
menu.map.autopan=Autozentrierung
menu.map.showmap=Karte zeigen
@@ -56,6 +58,7 @@ altkey.menu.range=B
altkey.menu.point=P
altkey.menu.view=A
altkey.menu.photo=F
+altkey.menu.audio=U
altkey.menu.settings=E
altkey.menu.help=H
@@ -94,14 +97,24 @@ function.setpaths=Programmpfade setzen
function.getgpsies=Gpsies Tracks holen
function.uploadgpsies=Daten zum Gpsies hochladen
function.lookupsrtm=H\u00f6hendaten von SRTM holen
+function.getwikipedia=Wikipediaartikeln in der N\u00e4he nachschlagen
+function.searchwikipedianames=Wikipedia mit Name durchsuchen
+function.downloadosm=OSM Daten f\u00fcr dieses Gebiet herunterladen
function.duplicatepoint=Punkt verdoppeln
function.setcolours=Farben einstellen
+function.setlinewidth=Liniedicke einstellen
function.setlanguage=Sprache einstellen
function.correlatephotos=Fotos korrelieren
function.rearrangephotos=Fotos reorganisieren
function.rotatephotoleft=Foto nach Links drehen
function.rotatephotoright=Foto nach Rechts drehen
+function.photopopup=Fotofenster anzeigen
function.ignoreexifthumb=Exif Vorschaubild ignorieren
+function.loadaudio=Audiodateien laden
+function.removeaudio=Audiodatei entfernen
+function.correlateaudios=Audios korrelieren
+function.playaudio=Audiodatei abspielen
+function.stopaudio=Abspielen abbrechen
function.help=Hilfe
function.showkeys=Tastenkombinationen anzeigen
function.about=\u00dcber Prune
@@ -188,6 +201,7 @@ dialog.pointtype.desc=Folgende Punkttypen speichern:
dialog.pointtype.track=Trackpunkte
dialog.pointtype.waypoint=Wegpunkte
dialog.pointtype.photo=Fotopunkte
+dialog.pointtype.audio=Audiopunkte
dialog.pointtype.selection=Nur aktuellen Bereich
dialog.confirmreversetrack.title=Umkehrung best\u00e4tigen
dialog.confirmreversetrack.text=Diese Daten enthalten Zeitangaben, die bei einer Umkehrung in falscher Reihenfolge erscheinen w\u00fcrden.\nSind Sie sicher, dass Sie diesen Bereich umkehren wollen?
@@ -273,13 +287,15 @@ dialog.gpsies.activity.motorbiking=Motorrad
dialog.gpsies.activity.snowshoe=Schneeschuh
dialog.gpsies.activity.sailing=Segeln
dialog.gpsies.activity.skating=Inline-Skating
+dialog.wikipedia.column.name=Artikelname
+dialog.wikipedia.column.distance=Entfernung
dialog.correlate.notimestamps=Die Punkte enthalten keine Zeitangaben, deshalb k\u00f6nnen die Fotos nicht zugeordnet werden.
dialog.correlate.nouncorrelatedphotos=Alle Fotos sind schon zugeordnet.\nWollen Sie trotzdem fortfahren?
dialog.correlate.photoselect.intro=W\u00e4hlen Sie eines dieser Fotos aus, um die Zeitdifferenz zu berechnen
-dialog.correlate.photoselect.photoname=Bezeichnung des Fotos
-dialog.correlate.photoselect.timediff=Zeitdifferenz
-dialog.correlate.photoselect.photolater=Foto sp\u00e4ter
-dialog.correlate.options.tip=Tipp: Mit mindestens einem manuell korrelierten Foto kann die Zeitdifferenz automatisch berechnet werden.
+dialog.correlate.select.photoname=Bezeichnung des Fotos
+dialog.correlate.select.timediff=Zeitdifferenz
+dialog.correlate.select.photolater=Foto sp\u00e4ter
+dialog.correlate.options.tip=Tipp: Mit mindestens einem manuell verbundenen Element kann die Zeitdifferenz automatisch berechnet werden.
dialog.correlate.options.intro=W\u00e4hlen Sie die Optionen f\u00fcr die Korrelation aus
dialog.correlate.options.offsetpanel=Zeitunterschied
dialog.correlate.options.offset=Unterschied
@@ -287,7 +303,9 @@ dialog.correlate.options.offset.hours=Stunden,
dialog.correlate.options.offset.minutes=Minuten und
dialog.correlate.options.offset.seconds=Sekunden
dialog.correlate.options.photolater=Foto sp\u00e4ter als Punkt
-dialog.correlate.options.pointlater=Punkt sp\u00e4ter als Foto
+dialog.correlate.options.pointlaterphoto=Punkt sp\u00e4ter als Foto
+dialog.correlate.options.audiolater=Audio sp\u00e4ter als Punkt
+dialog.correlate.options.pointlateraudio=Punkt sp\u00e4ter als Audio
dialog.correlate.options.limitspanel=Korrelation Grenzen
dialog.correlate.options.notimelimit=Keine Zeitgrenzen
dialog.correlate.options.timelimit=Zeitgrenzen
@@ -295,6 +313,15 @@ dialog.correlate.options.nodistancelimit=Keine Distanzgrenzen
dialog.correlate.options.distancelimit=Distanzgrenzen
dialog.correlate.options.correlate=Korrelieren
dialog.correlate.alloutsiderange=Alle Fotos sind au\u00dferhalb des Track Zeitraums. Sie k\u00f6nnen nicht korreliert werden.\nVersuchen Sie es mit einem anderen Offset oder binden Sie manuell mindestens ein Foto ein.
+dialog.correlate.filetimes=Die Datei Zeitstempel zeigen:
+dialog.correlate.filetimes2=der Tonspuren
+dialog.correlate.correltimes=F\u00fcr das Korrelieren, folgendes verwenden:
+dialog.correlate.timestamp.beginning=Anfang
+dialog.correlate.timestamp.middle=Mitte
+dialog.correlate.timestamp.end=Ende
+dialog.correlate.audioselect.intro=W\u00e4hlen Sie eines dieser Audios aus, um die Zeitdifferenz zu berechnen
+dialog.correlate.select.audioname=Audio Name
+dialog.correlate.select.audiolater=Audio sp\u00e4ter
dialog.rearrangephotos.desc=Setzen Sie das Ziel und die Reihenfolge der Fotopunkte
dialog.rearrangephotos.tostart=Am Anfang
dialog.rearrangephotos.toend=Am Ende
@@ -375,6 +402,7 @@ dialog.saveconfig.prune.diskcache=Kartenordner
dialog.saveconfig.prune.kmzimagewidth=Bildbreite in KMZ
dialog.saveconfig.prune.kmzimageheight=Bildh\u00f6he in KMZ
dialog.saveconfig.prune.colourscheme=Farbschema
+dialog.saveconfig.prune.linewidth=Liniedicke
dialog.saveconfig.prune.kmltrackcolour=KML Trackfarbe
dialog.setpaths.intro=Sie k\u00f6nnen hier die Pfade f\u00fcr externe Applikationen setzen:
dialog.setpaths.found=Pfad gefunden?
@@ -404,16 +432,18 @@ dialog.diskcache.dir=Kartenordner
dialog.diskcache.createdir=Ordner anlegen
dialog.diskcache.nocreate=Ordner wurde nicht angelegt
dialog.deletefieldvalues.intro=W\u00e4hlen Sie das Feld aus, die Sie l\u00f6schen m\u00f6chten
+dialog.setlinewidth.text=Geben Sie die Dicke der Linien ein (1-4)
+dialog.downloadosm.desc=Best\u00e4tigen um rohe OSM Daten f\u00fcr den Gebiet herunterzuladen:
+dialog.searchwikipedianames.search=Suche nach:
# 3d window
dialog.3d.title=Prune 3D Ansicht
-dialog.3d.altitudecap=Minimum H\u00f6henskala
dialog.3d.altitudefactor=Vervielfachungsfaktor für Höhen
dialog.3dlines.title=Prune Gitterlinien
dialog.3dlines.empty=Keine Linien zum Anzeigen!
dialog.3dlines.intro=Hier sind die Linien f\u00fcr die 3D Ansicht
-# Confirm messages || These are displayed as confirmation in the status bar
+# Confirm messages
confirm.loadfile=Daten aus Datei geladen
confirm.save.ok1=Es wurden
confirm.save.ok2=Punkte gespeichert nach
@@ -434,18 +464,23 @@ confirm.undo.single=Operation r\u00fcckg\u00e4ngig gemacht
confirm.undo.multi=Operationen r\u00fcckg\u00e4ngig gemacht
confirm.jpegload.single=Foto wurde geladen
confirm.jpegload.multi=Fotos wurden geladen
-confirm.photo.connect=Foto verbunden
+confirm.media.connect=Media verbunden
confirm.photo.disconnect=Foto getrennt
-confirm.correlate.single=Foto wurde korreliert
-confirm.correlate.multi=Fotos wurden korreliert
+confirm.audio.disconnect=Audio getrennt
+confirm.correlatephotos.single=Foto wurde korreliert
+confirm.correlatephotos.multi=Fotos wurden korreliert
confirm.createpoint=Punkt erzeugt
confirm.rotatephoto=Foto gedreht
confirm.running=In Bearbeitung ...
confirm.lookupsrtm1=Es wurden
confirm.lookupsrtm2=H\u00f6henwerte gefunden
confirm.deletefieldvalues=Feldwerte gelöscht
+confirm.audioload=Audiodateien geladen
+confirm.media.removed=entfernt
+confirm.correlateaudios.single=Audio wurde korreliert
+confirm.correlateaudios.multi=Audios wurden korreliert
-# Buttons || These are all the texts for buttons
+# Buttons
button.ok=OK
button.back=Zur\u00fcck
button.next=Vorw\u00e4rts
@@ -486,6 +521,7 @@ filetype.kmz=KMZ Dateien
filetype.gpx=GPX Dateien
filetype.pov=POV Dateien
filetype.svg=SVG Dateien
+filetype.audio=MP3, OGG, WAV Dateien
# Display components
display.nodata=Keine Daten geladen
@@ -520,12 +556,17 @@ details.range.maxspeed=H\u00f6chstgeschwindigkeit
details.range.numsegments=Anzahl Abschnitte
details.range.pace=Tempo
details.range.gradient=Gef\u00e4lle
-details.waypointsphotos.waypoints=Wegpunkte
-details.waypointsphotos.photos=Fotos
+details.lists.waypoints=Wegpunkte
+details.lists.photos=Fotos
details.photodetails=Fotodetails
details.nophoto=Kein Foto ausgew\u00e4hlt
details.photo.loading=Laden
-details.photo.connected=Verbunden
+details.media.connected=Verbunden
+details.lists.audio=Audio
+details.audiodetails=Audiodetails
+details.noaudio=Keine Audiodatei ausgew\u00e4hlt
+details.audio.file=Audiodatei
+details.audio.playing=wird abgespielt...
map.overzoom=Keine Karten f\u00fcr diesen Zoomfaktor verf\u00fcgbar
# Field names
@@ -562,6 +603,7 @@ units.iso8601=ISO 8601
# External urls
url.googlemaps=maps.google.de
+wikipedia.lang=de
# Cardinals for 3d plots
cardinal.n=N
@@ -572,9 +614,11 @@ cardinal.w=W
# Undo operations
undo.load=Daten laden
undo.loadphotos=Fotos laden
+undo.loadaudios=Audiodateien laden
undo.editpoint=Punkt bearbeiten
undo.deletepoint=Punkt l\u00f6schen
-undo.deletephoto=Foto entfernen
+undo.removephoto=Foto entfernen
+undo.removeaudio=Audiodatei entfernen
undo.deleterange=Bereich l\u00f6schen
undo.compress=Track komprimieren
undo.insert=Punkte hinzuf\u00fcgen
@@ -584,15 +628,16 @@ undo.addtimeoffset=Zeitverschiebung aufrechnen
undo.addaltitudeoffset=H\u00f6henverschiebung aufrechnen
undo.rearrangewaypoints=Wegpunkte reorganisieren
undo.cutandmove=Bereich verschieben
-undo.connectphoto=Foto verbinden
-undo.disconnectphoto=Foto trennen
-undo.correlate=Fotos korrelieren
+undo.connect=verbinden
+undo.disconnect=trennen
+undo.correlatephotos=Fotos korrelieren
undo.rearrangephotos=Fotos reorganisieren
undo.createpoint=Punkt erzeugen
undo.rotatephoto=Foto umdrehen
undo.convertnamestotimes=Namen in Zeitstempel umwandeln
undo.lookupsrtm=H\u00f6hendaten von SRTM holen
undo.deletefieldvalues=Feldwerte löschen
+undo.correlateaudios=Audios korrelieren
# Error messages
error.save.dialogtitle=Fehler beim Speichern
@@ -614,9 +659,9 @@ error.load.othererror=Fehler beim Lesen der Datei:
error.jpegload.dialogtitle=Fehler beim Laden von Fotos
error.jpegload.nofilesfound=Keine Dateien gefunden
error.jpegload.nojpegsfound=Keine Jpeg Dateien gefunden
-error.jpegload.noexiffound=Keine EXIF Information gefunden
error.jpegload.nogpsfound=Keine GPS Information gefunden
error.jpegload.exifreadfailed=EXIF Aufruf fehlgeschlagen. Keine EXIF Information k\u00f6nnen gelesen werden\nohne einen internen oder externen Bibliothek.
+error.audioload.nofilesfound=Keine Audiodateien gefunden
error.gpsload.unknown=Unbekannter Fehler
error.undofailed.title=Undo fehlgeschlagen
error.undofailed.text=Operation konnte nicht r\u00fcckg\u00e4ngig gemacht werden
@@ -634,3 +679,4 @@ error.lookupsrtm.nonefound=Keine H\u00f6hendaten verf
error.lookupsrtm.nonerequired=Alle Punkte haben schon Höhendaten
error.gpsies.uploadnotok=Der Gpsies Server hat geantwortet
error.gpsies.uploadfailed=Das Hochladen ist fehlgeschlagen
+error.playaudiofailed=Das Abspielen der Audiodatei ist fehlgeschlagen
diff --git a/tim/prune/lang/prune-texts_de_CH.properties b/tim/prune/lang/prune-texts_de_CH.properties
index 21a47c4..b4a3cb0 100644
--- a/tim/prune/lang/prune-texts_de_CH.properties
+++ b/tim/prune/lang/prune-texts_de_CH.properties
@@ -30,9 +30,10 @@ menu.point.editpoint=Punkt editiere
menu.point.deletepoint=Punkt lösche
menu.photo=Föteli
menu.photo.saveexif=Exif Date speicherä
-menu.photo.connect=Mitem Punkt verbindä
-menu.photo.disconnect=Vonem Punkt trännä
-menu.photo.delete=Föteli entfernä
+function.connecttopoint=Mitem Punkt verbindä
+function.disconnectfrompoint=Vonem Punkt trännä
+function.removephoto=Föteli entfernä
+menu.audio=Audio
menu.view=Aasicht
menu.view.showsidebars=Seiteleischten aazeige
menu.view.browser=Karte inem Browser
@@ -44,6 +45,7 @@ menu.map.zoomin=Innezoome
menu.map.zoomout=Uusezoome
menu.map.zoomfull=Zoome zum ganzes Bild
menu.map.newpoint=Noii Punkt
+menu.map.drawpoints=Noii Punkte uufzeichnä
menu.map.connect=Trackpünktli verbindä
menu.map.autopan=Autopan
menu.map.showmap=Karte zeigä
@@ -56,6 +58,7 @@ altkey.menu.range=B
altkey.menu.point=P
altkey.menu.view=A
altkey.menu.photo=F
+altkey.menu.audio=U
altkey.menu.settings=I
altkey.menu.help=H
@@ -86,22 +89,32 @@ function.deletefieldvalues=Werte von nem F
function.pastecoordinates=Noii Koordinaten iigebe
function.charts=Diagramme
function.show3d=Drüü-D Aasicht
-function.distances=Distanze
+function.distances=Entfärnige
function.fullrangedetails=Zuesätzlichi Beriichinfos
function.setmapbg=Karte Hintegrund setzä
function.getgpsies=Gpsies Tracks holä
function.uploadgpsies=Date zum Gpsies uufaladä
function.lookupsrtm=Höhendate vonem SRTM hole
+function.getwikipedia=Im Wikipedia in dr Nöchi naaluege
+function.searchwikipedianames=Wikipedia mit Name durasueche
+function.downloadosm=OSM-Date für dere Gebiet abaladä
function.duplicatepoint=Punkt verdopplä
function.correlatephotos=Fötelis korrelierä
function.rearrangephotos=Fötelis reorganisierä
function.rotatephotoleft=Föteli nach Links dräyä
function.rotatephotoright=Föteli nach Rächts dräyä
+function.photopopup=Fötelifänschter aazeigä
function.ignoreexifthumb=Exif Vorschaubildli ignorierä
-function.setkmzimagesize=Bildligrösse inem KMZ setze
-function.setpaths=Programmepfade setze
-function.setcolours=Farben setze
-function.setlanguage=Sproch setze
+function.loadaudio=Audiofiles lade
+function.removeaudio=Audiodatei entfernä
+function.correlateaudios=Audios korrelierä
+function.playaudio=Audiofile abspielä
+function.stopaudio=Abspielen abbrächä
+function.setkmzimagesize=Bildligrösse inem KMZ setzä
+function.setpaths=Programmepfade setzä
+function.setcolours=Farben setzä
+function.setlinewidth=Liniedicke setzä
+function.setlanguage=Sproch setzä
function.help=Hilfe
function.showkeys=Tastekombinatione aazeige
function.about=Über Prune
@@ -188,6 +201,7 @@ dialog.pointtype.desc=Folgende Punkttype speichere:
dialog.pointtype.track=Trackpunkte
dialog.pointtype.waypoint=Waypoints
dialog.pointtype.photo=Fötelipunkte
+dialog.pointtype.audio=Audiopunkte
dialog.pointtype.selection=Nur aktuelli Beriich
dialog.confirmreversetrack.title=Umdrehig bestätige
dialog.confirmreversetrack.text=Diese Daten enthalte Ziitstämpel Informatione, die bei dr Umkehrig usser Reihefolge erschiene würdi.\nSind Sie sicher, Sie wend dn Beriich umkehre?
@@ -241,7 +255,7 @@ dialog.charts.svgwidth=SVG Breiti
dialog.charts.svgheight=SVG Höhi
dialog.charts.needaltitudeortimes=Ohni Höhi Date und au ohne Ziit, isch es nöd möglech, Diagramme z zeigä.
dialog.charts.gnuplotnotfound=Gnuplot isch mit dem Pfad nöd gfunde worde
-dialog.distances.intro=Dischtanze per Luftlinie zwüschet Punkte
+dialog.distances.intro=Entfärnige per Luftlinie zwüschet Punkte
dialog.distances.column.from=Vom Punkt
dialog.distances.column.to=Zum Punkt
dialog.distances.currentpoint=Aktuelli Punkt
@@ -273,13 +287,15 @@ dialog.gpsies.activity.motorbiking=Motorrad
dialog.gpsies.activity.snowshoe=Schneeschuh
dialog.gpsies.activity.sailing=Segle
dialog.gpsies.activity.skating=Inline-Skate
+dialog.wikipedia.column.name=Artikelname
+dialog.wikipedia.column.distance=Entfärnig
dialog.correlate.notimestamps=Es hät kei Ziitstämpel inem Track innä, so s'isch nöd möglech die Fötelis zu korrelierä.
dialog.correlate.nouncorrelatedphotos=Alle Fötelis sin scho korreliert.\nWend Sie trotzdem fortsetzä?
dialog.correlate.photoselect.intro=Wählet Sie eini vo deren Föteli uus, um die Ziitdifferänz zu berächnä
-dialog.correlate.photoselect.photoname=Föteli Name
-dialog.correlate.photoselect.timediff=Ziitdifferänz
-dialog.correlate.photoselect.photolater=Föteli spöter
-dialog.correlate.options.tip=Tipp: Mit mindeschtens einem korrelierten Föteli, die Ziitdifferänz kann automatisch berächnet werdä.
+dialog.correlate.select.photoname=Föteli Name
+dialog.correlate.select.timediff=Ziitdifferänz
+dialog.correlate.select.photolater=Föteli spöter
+dialog.correlate.options.tip=Tipp: Mit mindeschtens einem verbundenen Elemänt kann die Ziitdifferänz automatisch berächnet werdä.
dialog.correlate.options.intro=Wählet Sie die Optione uus für die Korrelierig
dialog.correlate.options.offsetpanel=Ziitunterschied
dialog.correlate.options.offset=Unterschied
@@ -287,7 +303,9 @@ dialog.correlate.options.offset.hours=Schtund
dialog.correlate.options.offset.minutes=Minutä und
dialog.correlate.options.offset.seconds=Sekundä
dialog.correlate.options.photolater=Föteli spöter alsem Punkt
-dialog.correlate.options.pointlater=Punkt spöter alsem Föteli
+dialog.correlate.options.pointlaterphoto=Punkt spöter alsem Föteli
+dialog.correlate.options.audiolater=Audio spöter alsem Punkt
+dialog.correlate.options.pointlateraudio=Punkt spöter alsem Audio
dialog.correlate.options.limitspanel=Korrelation Gränzä
dialog.correlate.options.notimelimit=Kei Ziitgränzä
dialog.correlate.options.timelimit=Ziitgränzä
@@ -295,9 +313,18 @@ dialog.correlate.options.nodistancelimit=Kei Distanzgr
dialog.correlate.options.distancelimit=Distanzgränzä
dialog.correlate.options.correlate=Korrelierä
dialog.correlate.alloutsiderange=Alli Fötelis sin uusserhalb vonem Track Ziitruum, so chönne nöd korreliert werdä.\nVersuechet Sie mitenem anderen Offset oder verbindet Sie manuell mindeschtens eis Föteli.
+dialog.correlate.filetimes=Die Datei Zeitstempel zeigen:
+dialog.correlate.filetimes2=der Tonspuren
+dialog.correlate.correltimes=Fürs Korreliere, folgendes verwände:
+dialog.correlate.timestamp.beginning=Aafang
+dialog.correlate.timestamp.middle=Mitti
+dialog.correlate.timestamp.end=Ände
+dialog.correlate.audioselect.intro=Wählet Sie eini vo deren Audios uus, um die Ziitdifferänz zu berächnä
+dialog.correlate.select.audioname=Audio Name
+dialog.correlate.select.audiolater=Audio spöter
dialog.rearrangephotos.desc=Bitte Ziel und Reihefolge von den Punkten setze
dialog.rearrangephotos.tostart=zum Aafang
-dialog.rearrangephotos.toend=zum Ende
+dialog.rearrangephotos.toend=zum Ände
dialog.rearrangephotos.nosort=Nöd sortiere
dialog.rearrangephotos.sortbyfilename=per Filename sortiere
dialog.rearrangephotos.sortbytime=per Ziit sortiere
@@ -354,7 +381,7 @@ dialog.checkversion.releasedate1=Die noii Version isch am
dialog.checkversion.releasedate2=ussecho.
dialog.checkversion.download=Um die noii Version runterzlade, schauet Sie na http://activityworkshop.net/software/prune/download.html.
dialog.keys.intro=Aastatt d'Muus könnet Sie diese Tastekombinationen nutze
-dialog.keys.keylist=
Pfiil Taste
Karte verschiebe
Strg + links, rächts Pfiil
Vorherigi oder nöchsti Punkt markiere
Strg + uuf, aba Pfiil
Ii- oder Uusezoome
Strg + Bild uuf, ab
Vorherigi oder nöchsti Segmänt markiere
Strg + Pos1, Ende
Erschti oder letschti Punkt markiere
Entf
Aktuelli Punkt lösche
+dialog.keys.keylist=
Pfiil Taste
Karte verschiebe
Strg + links, rächts Pfiil
Vorherigi oder nöchsti Punkt markiere
Strg + uuf, aba Pfiil
Ii- oder Uusezoome
Strg + Bild uuf, ab
Vorherigi oder nöchsti Segmänt markiere
Strg + Pos1, Ände
Erschti oder letschti Punkt markiere
Entf
Aktuelli Punkt lösche
dialog.keys.normalmodifier=Strg
dialog.keys.macmodifier=Kommando
dialog.saveconfig.desc=Die folgendi Iinstellige könne gspeicheret werde :
@@ -375,6 +402,7 @@ dialog.saveconfig.prune.diskcache=Kartenordner
dialog.saveconfig.prune.kmzimagewidth=Bildbreiti im KMZ
dialog.saveconfig.prune.kmzimageheight=Bildhöchi im KMZ
dialog.saveconfig.prune.colourscheme=Farbeschema
+dialog.saveconfig.prune.linewidth=Liniedicke
dialog.saveconfig.prune.kmltrackcolour=KML Trackfarb
dialog.setpaths.intro=Sie könnet dann die Pfade für dia Applikatione setzä:
dialog.setpaths.found=Pfad gfunde?
@@ -404,10 +432,12 @@ dialog.diskcache.dir=Kartenordner
dialog.diskcache.createdir=Ordner kreiere
dialog.diskcache.nocreate=Ordner isch nöd kreiert worde
dialog.deletefieldvalues.intro=Wählet Sie s Fäld uus zum lösche
+dialog.setlinewidth.text=Gäbet Sie die Dicke vonen Linien ii (1-4)
+dialog.downloadosm.desc=Best\ätige um rohi OSM Date fürn Gebiet aba zlade:
+dialog.searchwikipedianames.search=Sueche na:
# 3d window
dialog.3d.title=Prune Drüü-d Aasicht
-dialog.3d.altitudecap=Minimum Höhenskala
dialog.3d.altitudefactor=Höchivervilfachigsfaktor
dialog.3dlines.title=Prune Gitterlinie
dialog.3dlines.empty=Kei Linie zum aazeigä!
@@ -434,16 +464,21 @@ confirm.undo.single=Operation r
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.media.connect=Media verbundä
confirm.photo.disconnect=Föteli gtrännt
-confirm.correlate.single=Föteli isch korreliert worde
-confirm.correlate.multi=Fötelis sin korreliert worde
+confirm.audio.disconnect=Audio gtrännt
+confirm.correlatephotos.single=Föteli isch korreliert worde
+confirm.correlatephotos.multi=Fötelis sin korreliert worde
confirm.createpoint=Punkt kreiert worde
confirm.rotatephoto=Föteli umgedräit worde
confirm.running=Am Laufe ...
confirm.lookupsrtm1=Es sin
confirm.lookupsrtm2=Höhenwerte gfunde
-confirm.deletefieldvalues=Feldwärte glöscht
+confirm.deletefieldvalues=Feldwärte glöscht worde
+confirm.audioload=Audiofiles glade worde
+confirm.media.removed=entfärnt
+confirm.correlateaudios.single=Audiofile isch korreliert worde
+confirm.correlateaudios.multi=Audiofiles sin korreliert worde
# Buttons
button.ok=OK
@@ -486,6 +521,7 @@ filetype.kmz=KMZ Dateie
filetype.gpx=GPX Dateie
filetype.pov=POV Dateie
filetype.svg=SVG Dateie
+filetype.audio=MP3, OGG, WAV Dateie
# Display components
display.nodata=Kei Date glade worde
@@ -520,12 +556,17 @@ details.range.maxspeed=H
details.range.numsegments=Aazahl Segmänte
details.range.pace=Tempo
details.range.gradient=Gefälle
-details.waypointsphotos.waypoints=Waypoints
-details.waypointsphotos.photos=Fötelis
+details.lists.waypoints=Waypoints
+details.lists.photos=Fötelis
details.photodetails=Details vonem Föteli
details.nophoto=Kei föteli selektiert
details.photo.loading=Ladä
-details.photo.connected=Verbundä
+details.media.connected=Verbundä
+details.lists.audio=Audio
+details.audiodetails=Audiodetails
+details.noaudio=Kei Audiofile selektiert
+details.audio.file=Audiofile
+details.audio.playing=am abschpielä...
map.overzoom=Kei Karte mit diesem Zoom
# Field names
@@ -562,6 +603,7 @@ units.iso8601=ISO 8601
# External urls
url.googlemaps=maps.google.ch
+wikipedia.lang=als
# Cardinals for 3d plots
cardinal.n=N
@@ -572,9 +614,11 @@ cardinal.w=W
# Undo operations
undo.load=Date ladä
undo.loadphotos=Fötelis ladä
+undo.loadaudios=Audiofiles ladä
undo.editpoint=Punkt editierä
undo.deletepoint=Punkt löschä
-undo.deletephoto=Föteli entfärnä
+undo.removephoto=Föteli entfärnä
+undo.removeaudio=Audiofile entfärnä
undo.deleterange=Beriich löschä
undo.compress=Track komprimierä
undo.insert=Punkte innätuä
@@ -584,15 +628,16 @@ undo.addtimeoffset=ziitverschiebig zutue
undo.addaltitudeoffset=höchiverschiebig zutue
undo.rearrangewaypoints=Waypoints reorganisierä
undo.cutandmove=Selektion movä
-undo.connectphoto=Föteli verbindä
-undo.disconnectphoto=Föteli trännä
-undo.correlate=Fötelis korrelierä
+undo.connect=verbindä
+undo.disconnect=trännä
+undo.correlatephotos=Fötelis korrelierä
undo.rearrangephotos=Fötelis reorganisierä
undo.createpoint=Punkt kreierä
undo.rotatephoto=Föteli umadräya
undo.convertnamestotimes=Name ins Ziitstämple verwondlä
undo.lookupsrtm=Höhendate vonem SRTM holä
undo.deletefieldvalues=Feldwärte löschä
+undo.correlateaudios=Audios korrelierä
# Error messages
error.save.dialogtitle=Fähle bim Speichere
@@ -612,11 +657,11 @@ error.load.unknownxml=Unbekanntes xml Format:
error.load.noxmlinzip=Kei xml im Zip File gfunde
error.load.othererror=Fähle bim Läse:
error.jpegload.dialogtitle=Fähle bim Lade von Fötelis
-error.jpegload.nofilesfound=Kei Dateie gfunde
+error.jpegload.nofilesfound=Kei Files gfunde
error.jpegload.nojpegsfound=Kei Jpegs gfunde
-error.jpegload.noexiffound=Kei EXIF Information gfunde
error.jpegload.nogpsfound=Kei GPS Information gfunde
error.jpegload.exifreadfailed=EXIF Uufruef isch fehlgschlage. Kei EXIF Infos könnet gläse werde\nohni nen interni oder extärni Bibliothek.
+error.audioload.nofilesfound=Kei Audiofiles gfunde
error.gpsload.unknown=Unbekannts Fähler
error.undofailed.title=Undo isch fehlgschlage worde
error.undofailed.text=Operation kann nöd rückgängig gmacht werde
@@ -634,3 +679,4 @@ error.lookupsrtm.nonefound=Kei H
error.lookupsrtm.nonerequired=Alle Punkte han die Höhendate scho. Nüüt z'tue.
error.gpsies.uploadnotok=Der Gpsies Server hät gseit gha
error.gpsies.uploadfailed=S Uufalade isch fehlgschlage
+error.playaudiofailed=S Abschpiele vonem File isch fehlgschlage
diff --git a/tim/prune/lang/prune-texts_en.properties b/tim/prune/lang/prune-texts_en.properties
index 42b1d5e..869af6d 100644
--- a/tim/prune/lang/prune-texts_en.properties
+++ b/tim/prune/lang/prune-texts_en.properties
@@ -30,9 +30,7 @@ menu.point.editpoint=Edit point
menu.point.deletepoint=Delete point
menu.photo=Photo
menu.photo.saveexif=Save to Exif
-menu.photo.connect=Connect to point
-menu.photo.disconnect=Disconnect from point
-menu.photo.delete=Remove photo
+menu.audio=Audio
menu.view=View
menu.view.showsidebars=Show sidebars
menu.view.browser=Map in a browser window
@@ -49,6 +47,7 @@ menu.map.zoomin=Zoom in
menu.map.zoomout=Zoom out
menu.map.zoomfull=Zoom to full scale
menu.map.newpoint=Create new point
+menu.map.drawpoints=Create series of points
menu.map.connect=Connect track points
menu.map.autopan=Autopan
menu.map.showmap=Show map
@@ -61,6 +60,7 @@ altkey.menu.track=T
altkey.menu.point=P
altkey.menu.view=V
altkey.menu.photo=O
+altkey.menu.audio=A
altkey.menu.settings=S
altkey.menu.help=H
@@ -96,16 +96,29 @@ function.fullrangedetails=Full range details
function.getgpsies=Get Gpsies tracks
function.uploadgpsies=Upload track to Gpsies
function.lookupsrtm=Get altitudes from SRTM
+function.getwikipedia=Get nearby Wikipedia articles
+function.searchwikipedianames=Search Wikipedia by name
+function.downloadosm=Download OSM data for area
function.duplicatepoint=Duplicate point
+function.connecttopoint=Connect to point
+function.disconnectfrompoint=Disconnect from point
+function.removephoto=Remove photo
function.correlatephotos=Correlate photos
function.rearrangephotos=Rearrange photos
function.rotatephotoleft=Rotate photo left
function.rotatephotoright=Rotate photo right
+function.photopopup=Show photo popup
function.ignoreexifthumb=Ignore exif thumbnail
+function.loadaudio=Add audio files
+function.removeaudio=Remove audio file
+function.correlateaudios=Correlate audios
+function.playaudio=Play audio file
+function.stopaudio=Stop audio file
function.setmapbg=Set map background
function.setkmzimagesize=Set KMZ image size
function.setpaths=Set program paths
function.setcolours=Set colours
+function.setlinewidth=Set line width
function.setlanguage=Set language
function.help=Help
function.showkeys=Show shortcut keys
@@ -193,6 +206,7 @@ dialog.pointtype.desc=Save the following point types:
dialog.pointtype.track=Track points
dialog.pointtype.waypoint=Waypoints
dialog.pointtype.photo=Photo points
+dialog.pointtype.audio=Audio points
dialog.pointtype.selection=Just selection
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?
@@ -278,13 +292,15 @@ dialog.gpsies.activity.motorbiking=Motorbiking
dialog.gpsies.activity.snowshoe=Snowshoeing
dialog.gpsies.activity.sailing=Sailing
dialog.gpsies.activity.skating=Skating
+dialog.wikipedia.column.name=Article name
+dialog.wikipedia.column.distance=Distance
dialog.correlate.notimestamps=There are no timestamps in the data points, so there is nothing to correlate with the photos.
dialog.correlate.nouncorrelatedphotos=There are no uncorrelated photos.\nAre you sure you want to continue?
dialog.correlate.photoselect.intro=Select one of these correlated photos to use as the time offset
-dialog.correlate.photoselect.photoname=Photo name
-dialog.correlate.photoselect.timediff=Time difference
-dialog.correlate.photoselect.photolater=Photo later
-dialog.correlate.options.tip=Tip: By manually correlating at least one photo, the time offset can be calculated for you.
+dialog.correlate.select.photoname=Photo name
+dialog.correlate.select.timediff=Time difference
+dialog.correlate.select.photolater=Photo later
+dialog.correlate.options.tip=Tip: By manually connecting at least one item, the time offset can be calculated for you.
dialog.correlate.options.intro=Select the options for automatic correlation
dialog.correlate.options.offsetpanel=Time offset
dialog.correlate.options.offset=Offset
@@ -292,7 +308,9 @@ dialog.correlate.options.offset.hours=hours,
dialog.correlate.options.offset.minutes=minutes and
dialog.correlate.options.offset.seconds=seconds
dialog.correlate.options.photolater=Photo later than point
-dialog.correlate.options.pointlater=Point later than photo
+dialog.correlate.options.pointlaterphoto=Point later than photo
+dialog.correlate.options.audiolater=Audio later than point
+dialog.correlate.options.pointlateraudio=Point later than audio
dialog.correlate.options.limitspanel=Correlation limits
dialog.correlate.options.notimelimit=No time limit
dialog.correlate.options.timelimit=Time limit
@@ -300,6 +318,15 @@ 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.filetimes=File timestamps denote:
+dialog.correlate.filetimes2=of audio clip
+dialog.correlate.correltimes=For correlation, use:
+dialog.correlate.timestamp.beginning=Beginning
+dialog.correlate.timestamp.middle=Middle
+dialog.correlate.timestamp.end=End
+dialog.correlate.audioselect.intro=Select one of these correlated audios to use as the time offset
+dialog.correlate.select.audioname=Audio name
+dialog.correlate.select.audiolater=Audio later
dialog.rearrangephotos.desc=Select the destination and sort order of the photo points
dialog.rearrangephotos.tostart=Move to start
dialog.rearrangephotos.toend=Move to end
@@ -380,6 +407,7 @@ dialog.saveconfig.prune.diskcache=Map cache
dialog.saveconfig.prune.kmzimagewidth=KMZ image width
dialog.saveconfig.prune.kmzimageheight=KMZ image height
dialog.saveconfig.prune.colourscheme=Colour scheme
+dialog.saveconfig.prune.linewidth=Line width
dialog.saveconfig.prune.kmltrackcolour=KML track colour
dialog.setpaths.intro=If you need to, you can choose the paths to the external applications:
dialog.setpaths.found=Path found?
@@ -409,16 +437,18 @@ dialog.diskcache.dir=Cache directory
dialog.diskcache.createdir=Create directory
dialog.diskcache.nocreate=Cache directory not created
dialog.deletefieldvalues.intro=Select the field to delete for the current range
+dialog.setlinewidth.text=Enter the thickness of lines to draw for the tracks (1-4)
+dialog.downloadosm.desc=Confirm to download the raw OSM data for the specified area:
+dialog.searchwikipedianames.search=Search for:
# 3d window
dialog.3d.title=Prune Three-d view
-dialog.3d.altitudecap=
dialog.3d.altitudefactor=Altitude exaggeration factor
dialog.3dlines.title=Prune gridlines
dialog.3dlines.empty=No gridlines to display!
dialog.3dlines.intro=These are the gridlines for the three-d view
-# Confirm messages || These are displayed as confirmation in the status bar
+# Confirm messages
confirm.loadfile=Data loaded from file
confirm.save.ok1=Successfully saved
confirm.save.ok2=points to file
@@ -439,16 +469,21 @@ 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.media.connect=media connected
confirm.photo.disconnect=photo disconnected
-confirm.correlate.single=photo was correlated
-confirm.correlate.multi=photos were correlated
+confirm.audio.disconnect=audio disconnected
+confirm.media.removed=removed
+confirm.correlatephotos.single=photo was correlated
+confirm.correlatephotos.multi=photos were correlated
confirm.rotatephoto=photo rotated
confirm.createpoint=point created
confirm.running=Running ...
confirm.lookupsrtm1=Found
confirm.lookupsrtm2=altitude values
confirm.deletefieldvalues=Field values deleted
+confirm.audioload=Audio files added
+confirm.correlateaudios.single=audio was correlated
+confirm.correlateaudios.multi=audios were correlated
# Buttons
button.ok=OK
@@ -491,6 +526,7 @@ filetype.kmz=KMZ files
filetype.gpx=GPX files
filetype.pov=POV files
filetype.svg=SVG files
+filetype.audio=MP3, OGG, WAV files
# Display components
display.nodata=No data loaded
@@ -525,12 +561,17 @@ details.range.maxspeed=Maximum speed
details.range.numsegments=Number of segments
details.range.pace=Pace
details.range.gradient=Gradient
-details.waypointsphotos.waypoints=Waypoints
-details.waypointsphotos.photos=Photos
+details.lists.waypoints=Waypoints
+details.lists.photos=Photos
+details.lists.audio=Audio
details.photodetails=Photo details
details.nophoto=No photo selected
details.photo.loading=Loading
-details.photo.connected=Connected
+details.media.connected=Connected
+details.audiodetails=Audio details
+details.noaudio=No audio file selected
+details.audio.file=Audio file
+details.audio.playing=playing...
map.overzoom=No maps available at this zoom level
# Field names
@@ -573,6 +614,7 @@ units.iso8601=ISO 8601
# External urls
url.googlemaps=maps.google.co.uk
+wikipedia.lang=en
# Cardinals for 3d plots
cardinal.n=N
@@ -583,9 +625,11 @@ cardinal.w=W
# Undo operations
undo.load=load data
undo.loadphotos=load photos
+undo.loadaudios=load audio files
undo.editpoint=edit point
undo.deletepoint=delete point
-undo.deletephoto=remove photo
+undo.removephoto=remove photo
+undo.removeaudio=remove audio file
undo.deleterange=delete range
undo.compress=compress track
undo.insert=insert points
@@ -595,15 +639,16 @@ undo.addtimeoffset=add time offset
undo.addaltitudeoffset=add altitude offset
undo.rearrangewaypoints=rearrange waypoints
undo.cutandmove=move section
-undo.connectphoto=connect photo
-undo.disconnectphoto=disconnect photo
-undo.correlate=correlate photos
+undo.connect=connect
+undo.disconnect=disconnect
+undo.correlatephotos=correlate photos
undo.rearrangephotos=rearrange photos
undo.rotatephoto=rotate photo
undo.createpoint=create point
undo.convertnamestotimes=convert names to times
undo.lookupsrtm=lookup altitudes from SRTM
undo.deletefieldvalues=delete field values
+undo.correlateaudios=correlate audios
# Error messages
error.save.dialogtitle=Error saving data
@@ -625,9 +670,9 @@ error.load.othererror=Error reading file:
error.jpegload.dialogtitle=Error loading photos
error.jpegload.nofilesfound=No files found
error.jpegload.nojpegsfound=No jpeg files found
-error.jpegload.noexiffound=No EXIF information found
error.jpegload.nogpsfound=No GPS information found
error.jpegload.exifreadfailed=Failed to read EXIF information. No EXIF information can be read\nwithout either an internal or external library.
+error.audioload.nofilesfound=No audio files found
error.gpsload.unknown=Unknown error
error.undofailed.title=Undo failed
error.undofailed.text=Failed to undo operation
@@ -645,3 +690,4 @@ error.lookupsrtm.nonefound=No altitude values available for these points
error.lookupsrtm.nonerequired=All points already have altitudes, so there's nothing to lookup
error.gpsies.uploadnotok=The gpsies server returned the message
error.gpsies.uploadfailed=The upload failed with the error
+error.playaudiofailed=Failed to play audio file
diff --git a/tim/prune/lang/prune-texts_es.properties b/tim/prune/lang/prune-texts_es.properties
index aa76d8f..c554ab3 100644
--- a/tim/prune/lang/prune-texts_es.properties
+++ b/tim/prune/lang/prune-texts_es.properties
@@ -30,9 +30,7 @@ menu.point.editpoint=Editar punto
menu.point.deletepoint=Eliminar punto
menu.photo=Foto
menu.photo.saveexif=Guardar Exif
-menu.photo.connect=Conectar con punto
-menu.photo.disconnect=Desconectar de punto
-menu.photo.delete=Eliminar foto
+menu.audio=Audio
menu.view=Ver
menu.view.showsidebars=Mostrar barras laterales
menu.view.browser=Mapa en una ventana del navegador
@@ -49,6 +47,7 @@ menu.map.zoomin=Ampliar zoom
menu.map.zoomout=Reducir zoom
menu.map.zoomfull=Mostrar todo
menu.map.newpoint=Crear un punto nuevo
+menu.map.drawpoints=Crear series de puntos
menu.map.connect=Conectar puntos de track
menu.map.autopan=Posicionar autom\u00e1ticamente
menu.map.showmap=Mostrar el mapa
@@ -61,6 +60,7 @@ altkey.menu.range=R
altkey.menu.point=U
altkey.menu.view=V
altkey.menu.photo=F
+altkey.menu.audio=D
altkey.menu.settings=P
altkey.menu.help=Y
@@ -99,14 +99,27 @@ function.setpaths=Configurar rutas del programas
function.getgpsies=Bajar ruta de Gpsies
function.uploadgpsies=Subir recorrido a Gpsies
function.lookupsrtm=Obtener altitudes de SRTM
+function.getwikipedia=Obtener art\u00edculos de Wikipedia cercanos
+function.searchwikipedianames=Buscar en Wikipedia por nombre
+function.downloadosm=Descargar datos OSM del \u00e1rea
function.duplicatepoint=Duplicar punto
function.setcolours=Establecer color
+function.setlinewidth=Establecer ancho de l\u00ednea
function.setlanguage=Establecer lenguaje
+function.connecttopoint=Conectar con punto
+function.disconnectfrompoint=Desconectar de punto
+function.removephoto=Eliminar foto
function.correlatephotos=Correlacionar fotos
function.rearrangephotos=Reacomodar fotos
function.rotatephotoleft=Girar a la izquierda
function.rotatephotoright=Girar a la derecha
+function.photopopup=Mostrar foto en ventana emergente
function.ignoreexifthumb=Ignorar miniatura exif
+function.loadaudio=A\u00f1adir archivos de audio
+function.removeaudio=Eliminar archivo de audio
+function.correlateaudios=Correlacionar audios
+function.playaudio=Reproducir archivo de audio
+function.stopaudio=Detener reproducci\u00f3n de audio
function.help=Ayuda
function.showkeys=Mostrar teclas o combinaciones de atajo
function.about=Acerca de Prune
@@ -116,13 +129,13 @@ function.diskcache=Guardar mapas en disco
# Dialogs
dialog.exit.confirm.title=Salir de Prune
-dialog.exit.confirm.text=¿Los datos han sido modificados. Desea salir de Prune?
-dialog.openappend.title=¿Agregar a datos existentes
-dialog.openappend.text=¿Agregar estos datos a los datos ya guardados?
+dialog.exit.confirm.text=\u00bfLos datos han sido modificados. Desea salir de Prune?
+dialog.openappend.title=\u00bfAgregar a datos existentes
+dialog.openappend.text=\u00bfAgregar estos datos a los datos ya guardados?
dialog.deletepoint.title=Borrar punto
-dialog.deletepoint.deletephoto=¿Borrar la foto tambien?
+dialog.deletepoint.deletephoto=\u00bfBorrar la foto tambien?
dialog.deletephoto.title=Borrar foto
-dialog.deletephoto.deletepoint=¿Borrar el punto tambien?
+dialog.deletephoto.deletepoint=\u00bfBorrar el punto tambien?
dialog.openoptions.title=Opciones de abrir
dialog.openoptions.filesnippet=Extraer archivo
dialog.load.table.field=Campo
@@ -146,7 +159,7 @@ dialog.jpegload.loadjpegswithoutcoords=Fotos sin coordenadas tambien
dialog.jpegload.loadjpegsoutsidearea=Incluir fotos fuera del \u00e1rea
dialog.jpegload.progress.title=Cargando fotos
dialog.jpegload.progress=Por favor espere mientras se buscan las fotos
-dialog.gpsload.nogpsbabel=No se ha encontrado el programa gpsbabel. ¿Desea continuar?
+dialog.gpsload.nogpsbabel=No se ha encontrado el programa gpsbabel. \u00bfDesea continuar?
dialog.gpsload.device=Dispositivo
dialog.gpsload.format=Formato
dialog.gpsload.getwaypoints=Cargar waypoints
@@ -165,7 +178,7 @@ dialog.save.coordinateunits=Unidades de las coordenadas
dialog.save.altitudeunits=Unidades de las altitudes
dialog.save.timestampformat=Formato del tiempo
dialog.save.overwrite.title=El archivo ya existe
-dialog.save.overwrite.text=El archivo ya existe, ¿desea sobreescribirlo?
+dialog.save.overwrite.text=El archivo ya existe, \u00bfdesea sobreescribirlo?
dialog.save.notypesselected=No se han seleccionado tipos de puntos
dialog.exportkml.text=Descripci\u00f3n para los datos
dialog.exportkml.altitude=Absoluta altitudes (para aviaci\u00f3n)
@@ -186,17 +199,19 @@ dialog.exportpov.ballsandsticks=Balas en palos
dialog.exportpov.tubesandwalls=Tubos y paredes
dialog.exportpov.warningtracksize=Este track contiene un gran numero de puntos. Puede ser que Java3D no los pueda visualizar. Est\u00e1 seguro de que desea continuar?
dialog.exportsvg.text=Seleccione los par\u00e1metros para exportar a SVG
-dialog.exportsvg.phi=Ángulo de azimuth \u03d5
-dialog.exportsvg.theta=Ángulo de elevaci\u00f3n
+dialog.exportsvg.phi=\u00c1ngulo de azimuth \u03d5
+dialog.exportsvg.theta=\u00c1ngulo de elevaci\u00f3n
dialog.exportsvg.gradients=Usar degradado para sombras
dialog.pointtype.desc=Salvar los siguientes tipos de puntos:
dialog.pointtype.track=Puntos de track
+dialog.pointtype.waypoint=Waypoints
dialog.pointtype.photo=Puntos de foto
+dialog.pointtype.audio=Puntos de audio
dialog.pointtype.selection=Solo selecci\u00f3n
dialog.confirmreversetrack.title=Confirmar inversi\u00f3n
-dialog.confirmreversetrack.text=Este track contiene informaci\u00f3n sobre la fecha, que estar\u00e1 fuera de secuencia despu\u00e9s de la inversi\u00f3n. ¿Est\u00e1 seguro que desea invertir esta secci\u00f3n?
+dialog.confirmreversetrack.text=Este track contiene informaci\u00f3n sobre la fecha, que estar\u00e1 fuera de secuencia despu\u00e9s de la inversi\u00f3n. \u00bfEst\u00e1 seguro que desea invertir esta secci\u00f3n?
dialog.confirmcutandmove.title=Confirmar accion cortar/pegar
-dialog.confirmcutandmove.text=Este track contiene informaci\u00f3n sobre la fecha, que estar\u00e1 fuera de secuencia despu\u00e9s de mover.\n¿Esta seguro que desea mover esta secci\u00f3n?
+dialog.confirmcutandmove.text=Este track contiene informaci\u00f3n sobre la fecha, que estar\u00e1 fuera de secuencia despu\u00e9s de mover.\n\u00bfEsta seguro que desea mover esta secci\u00f3n?
dialog.interpolate.title=Interpolar puntos
dialog.interpolate.parameter.text=N\u00famero de los puntos a insertar entre los puntos elegidos
dialog.undo.title=Deshacer
@@ -204,7 +219,7 @@ dialog.undo.pretext=Por favor, seleccione la operaci\u00f3n(es) a deshacer
dialog.undo.none.title=No se puede deshacer
dialog.undo.none.text=Ninguna operaci\u00f3n a deshacer
dialog.clearundo.title=Despejar la lista de deshacer
-dialog.clearundo.text=¿Esta seguro que desea despejar la lista de deshacer?, ¡se perder\u00e1 toda la informaci\u00f3n!
+dialog.clearundo.text=\u00bfEsta seguro que desea despejar la lista de deshacer?, ¡se perder\u00e1 toda la informaci\u00f3n!
dialog.pointedit.title=Editar punto
dialog.pointedit.text=Seleccione cada campo a editar y use el bot\u00f3n 'Editar' para modificar el valor
dialog.pointedit.table.field=Campo
@@ -227,7 +242,7 @@ dialog.findwaypoint.search=Buscar
dialog.saveexif.title=Guardar Exif
dialog.saveexif.intro=Seleccione fotos a guardar
dialog.saveexif.nothingtosave=Coordenadas no modificadas, nada que guardar
-dialog.saveexif.noexiftool=No se encuentra el programa exiftool. ¿Desea continuar?
+dialog.saveexif.noexiftool=No se encuentra el programa exiftool. \u00bfDesea continuar?
dialog.saveexif.table.photoname=Nombre de la foto
dialog.saveexif.table.status=Estado
dialog.saveexif.table.save=Guardar
@@ -277,12 +292,14 @@ dialog.gpsies.activity.motorbiking=En moto
dialog.gpsies.activity.snowshoe=Raquetas de nieve
dialog.gpsies.activity.sailing=Vela
dialog.gpsies.activity.skating=Patinaje
+dialog.wikipedia.column.name=Nombre del art\u00edculo
+dialog.wikipedia.column.distance=Distancia
dialog.correlate.notimestamps=No hay informaci\u00f3n de tiempo para los puntos, as\u00ed que no hay nada que correlacionar con las fotos.
-dialog.correlate.nouncorrelatedphotos=No hay fotos no correlacionadas.\n¿Est\u00e1 seguro de que desea continuar?
+dialog.correlate.nouncorrelatedphotos=No hay fotos no correlacionadas.\n\u00bfEst\u00e1 seguro de que desea continuar?
dialog.correlate.photoselect.intro=Seleccione una de estas fotos correlacionadas para usar como margen de tiempo
-dialog.correlate.photoselect.photoname=Nombre de la foto
-dialog.correlate.photoselect.timediff=Diferencia de tiempo
-dialog.correlate.photoselect.photolater=Foto m\u00e1s adelante
+dialog.correlate.select.photoname=Nombre de la foto
+dialog.correlate.select.timediff=Diferencia de tiempo
+dialog.correlate.select.photolater=Foto m\u00e1s adelante
dialog.correlate.options.tip=Sugerencia: Correlacionando al menos una foto manualmente, el margen de tiempo se calcula autom\u00e1ticamente.
dialog.correlate.options.intro=Seleccionar las opciones para correlaci\u00f3n autom\u00e1tica
dialog.correlate.options.offsetpanel=Margen de tiempo
@@ -291,7 +308,9 @@ dialog.correlate.options.offset.hours=horas,
dialog.correlate.options.offset.minutes=minutos y
dialog.correlate.options.offset.seconds=segundos
dialog.correlate.options.photolater=Foto despu\u00e9s de punto
-dialog.correlate.options.pointlater=Punto despu\u00e9s de foto
+dialog.correlate.options.pointlaterphoto=Punto despu\u00e9s de foto
+dialog.correlate.options.audiolater=Audio despu\u00e9s de punto
+dialog.correlate.options.pointlateraudio=Punto despu\u00e9s de audio
dialog.correlate.options.limitspanel=L\u00edmites de correlaci\u00f3n
dialog.correlate.options.notimelimit=Sin l\u00edmite de tiempo
dialog.correlate.options.timelimit=L\u00edmite de tiempo
@@ -299,6 +318,15 @@ dialog.correlate.options.nodistancelimit=Sin l\u00edmite de distancia
dialog.correlate.options.distancelimit=L\u00edmite de distancia
dialog.correlate.options.correlate=Correlacionar
dialog.correlate.alloutsiderange=Todas las fotos est\u00e1n 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.filetimes=Las marcas del archivo denotan:
+dialog.correlate.filetimes2=de sonido
+dialog.correlate.correltimes=Para correlacionar use:
+dialog.correlate.timestamp.beginning=Comienzo
+dialog.correlate.timestamp.middle=Mitad
+dialog.correlate.timestamp.end=Final
+dialog.correlate.audioselect.intro=Seleccione uno de estos audios correlacionados para usarlo como margen temporal.
+dialog.correlate.select.audioname=Nombre del audio
+dialog.correlate.select.audiolater=Audio m\u00e1s adelante
dialog.rearrangephotos.desc=Seleccionar el destino y sortear el orden de los puntos de las fotos
dialog.rearrangephotos.tostart=Mover al comienzo
dialog.rearrangephotos.toend=Mover al final
@@ -367,7 +395,7 @@ dialog.saveconfig.prune.languagefile=Archivo de lenguaje
dialog.saveconfig.prune.gpsdevice=Dispositivo GPS
dialog.saveconfig.prune.gpsformat=Formato GPS
dialog.saveconfig.prune.povrayfont=Fuente povray
-dialog.saveconfig.prune.metricunits=¿Usar unidades m\u00e9tricas?
+dialog.saveconfig.prune.metricunits=\u00bfUsar unidades m\u00e9tricas?
dialog.saveconfig.prune.gnuplotpath=Ruta a gnuplot
dialog.saveconfig.prune.gpsbabelpath=Ruta a gpsbabel
dialog.saveconfig.prune.exiftoolpath=Ruta a exiftool
@@ -377,12 +405,13 @@ dialog.saveconfig.prune.diskcache=Memoria intermedia de mapas
dialog.saveconfig.prune.kmzimagewidth=Ancho de im\u00e1genes en KMZ
dialog.saveconfig.prune.kmzimageheight=Alto de im\u00e1genes en KMZ
dialog.saveconfig.prune.colourscheme=Color de esquema
+dialog.saveconfig.prune.linewidth=Ancho de l\u00ednea
dialog.saveconfig.prune.kmltrackcolour=Color de pista de KML
dialog.setpaths.intro=Si usted necesita, puede escoger las rutas a aplicaciones externas
-dialog.setpaths.found=¿Ruta encontrada?
+dialog.setpaths.found=\u00bfRuta encontrada?
dialog.addaltitude.noaltitudes=Los rangos seleccionados no contienen altitudes
dialog.addaltitude.desc=Desplazamiento de altitud a a\u00f1adir
-dialog.lookupsrtm.overwritezeros=¿Sobrescribir valores de altitud nulos?
+dialog.lookupsrtm.overwritezeros=\u00bfSobrescribir valores de altitud nulos?
dialog.setcolours.intro=Haga clic sobre una placa de color para cambiar el color
dialog.setcolours.background=Fondo
dialog.setcolours.borders=Bordes
@@ -406,10 +435,12 @@ dialog.diskcache.dir=Directorio de mapas
dialog.diskcache.createdir=Crear directorio
dialog.diskcache.nocreate=No se ha creado el directorio de mapas
dialog.deletefieldvalues.intro=Seleccionar el campo a eliminar para el rango actual
+dialog.setlinewidth.text=Introduzca la anchura de las l\u00edneas a dibujar para los recorridos (1-4)
+dialog.downloadosm.desc=Confirmar la descarga de datos en bruto de OSM para el \u00e1rea especificada.
+dialog.searchwikipedianames.search=Buscar:
# 3d window
dialog.3d.title=Prune vista 3-D
-dialog.3d.altitudecap=Escala de las altitudes
dialog.3d.altitudefactor=Factor de exageraci\u00f3n de altura
dialog.3dlines.title=Cuadr\u00edcula Prune
dialog.3dlines.empty=¡No hay ninguna cuadr\u00edcula!
@@ -436,16 +467,21 @@ confirm.undo.single=operaci\u00f3n deshecha
confirm.undo.multi=operaci\u00f3n(es) deshechas(s)
confirm.jpegload.single=Foto incluida
confirm.jpegload.multi=Fotos incluidas
-confirm.photo.connect=Foto conectada
+confirm.media.connect=Medio conectada
confirm.photo.disconnect=Foto desconectada
-confirm.correlate.single=foto fue correlacionada
-confirm.correlate.multi=fotos fueron correlacionadas
+confirm.audio.disconnect=Audio desconectado
+confirm.media.removed=Eliminado
+confirm.correlatephotos.single=foto fue correlacionada
+confirm.correlatephotos.multi=fotos fueron correlacionadas
confirm.createpoint=punto creado
confirm.rotatephoto=foto rotada
confirm.running=Trabajando ...
confirm.lookupsrtm1=Encontrados
confirm.lookupsrtm2=valor de altitud para la funci\u00f3n de b\u00fasqueda SRTM
confirm.deletefieldvalues=Valores del campo eliminados
+confirm.audioload=A\u00f1adidos archivos de audio
+confirm.correlateaudios.single=El audio fue correlacionado
+confirm.correlateaudios.multi=Los audios fueron correlacionados
# Buttons
button.ok=Aceptar
@@ -488,6 +524,7 @@ filetype.kmz=Archivos KMZ
filetype.gpx=Archivos GPX
filetype.pov=Archivos POV
filetype.svg=Archivos SVG
+filetype.audio=Archivos MP3, OGG, WAV
# Display components
display.nodata=Ning\u00fan dato cargado
@@ -522,12 +559,17 @@ details.range.maxspeed=Velocidad m\u00e1xima
details.range.numsegments=N\u00famero de segmentos
details.range.pace=Ritmo
details.range.gradient=Gradiente
-details.waypointsphotos.waypoints=Waypoints
-details.waypointsphotos.photos=Fotos
+details.lists.waypoints=Waypoints
+details.lists.photos=Fotos
+details.lists.audio=Audio
details.photodetails=Detalles de la foto
details.nophoto=Ninguna foto seleccionada
details.photo.loading=Cargando
-details.photo.connected=Conectada
+details.media.connected=Conectada
+details.audiodetails=Detalles de audio
+details.noaudio=No se ha seleccionado ning\u00fan archivo de audio
+details.audio.file=Archivo de audio
+details.audio.playing=Reproduciendo...
map.overzoom=No existen mapas disponibles con este nivel de enfoque
# Field names
@@ -570,6 +612,7 @@ units.iso8601=ISO 8601
# External urls
url.googlemaps=maps.google.es
+wikipedia.lang=es
# Cardinals for 3d plots
cardinal.n=N
@@ -580,9 +623,11 @@ cardinal.w=O
# Undo operations
undo.load=cargar datos
undo.loadphotos=cargar fotos
+undo.loadaudios=Cargar archivos de audio
undo.editpoint=editar punto
undo.deletepoint=eliminar punto
-undo.deletephoto=eliminar foto
+undo.removephoto=eliminar foto
+undo.removeaudio=Eliminar archivos de audio
undo.deleterange=eliminar rango
undo.compress=comprimir track
undo.insert=insertar puntos
@@ -592,15 +637,16 @@ undo.addtimeoffset=a\u00f1adir margen de tiempo
undo.addaltitudeoffset=a\u00f1adir margen de altitud
undo.rearrangewaypoints=reordenar waypoints
undo.cutandmove=mover secci\u00f3n
-undo.connectphoto=conectar foto
-undo.disconnectphoto=desconectar foto
-undo.correlate=correlacionar fotos
+undo.connect=Conectar
+undo.disconnect=Desconectar
+undo.correlatephotos=correlacionar fotos
undo.rearrangephotos=reordenar fotos
undo.createpoint=crear punto
undo.rotatephoto=girar foto
undo.convertnamestotimes=convertir nombres a tiempo
undo.lookupsrtm=obtener altitudes de SRTM
undo.deletefieldvalues=Eliminar valores de campo
+undo.correlateaudios=Correlacionar audios
# Error messages
error.save.dialogtitle=Fallo al guardar datos
@@ -622,9 +668,9 @@ error.load.othererror=Fallo al cargar datos:
error.jpegload.dialogtitle=Error cargando fotos
error.jpegload.nofilesfound=No se encuentra ning\u00fan archivo
error.jpegload.nojpegsfound=No se encuentra ning\u00fan archivo jpeg
-error.jpegload.noexiffound=No se encuentra informaci\u00f3n EXIF
error.jpegload.nogpsfound=No se encuentra informaci\u00f3n GPS
error.jpegload.exifreadfailed=Fallo al leer la informaci\u00f3n EXIF. No se puede leer ninguna informaci\u00f3n EXIF\ncon las librer\u00edas internas ni externas.
+error.audioload.nofilesfound=No se encontraron archivos de audio
error.gpsload.unknown=Error desconocido
error.undofailed.title=Fallo al deshacer
error.undofailed.text=No ha sido posible deshacer la operaci\u00f3n
@@ -642,3 +688,4 @@ error.lookupsrtm.nonefound=No se encontraron valores de altitud
error.lookupsrtm.nonerequired=Todos los puntos tienen altitudes, as\u00ed que no hay nada que buscar.
error.gpsies.uploadnotok=El servidor de gpsies ha devuelto el mensaje
error.gpsies.uploadfailed=La carga ha fallado con el error
+error.playaudiofailed=Fallo reproduciendo archivo de audio
diff --git a/tim/prune/lang/prune-texts_fa.properties b/tim/prune/lang/prune-texts_fa.properties
index b2aaefe..2e9d558 100644
--- a/tim/prune/lang/prune-texts_fa.properties
+++ b/tim/prune/lang/prune-texts_fa.properties
@@ -30,9 +30,9 @@ menu.point.editpoint=\u062a\u0646\u0638\u064a\u0645\u0627\u062a \u0646\u0642\u06
menu.point.deletepoint=\u067e\u0627\u06a9 \u06a9\u0631\u062f\u0646 \u0646\u0642\u0637\u0647
menu.photo=\u0639\u06a9\u0633
menu.photo.saveexif=\u0630\u062e\u064a\u0631\u0647 \u062f\u0631 \u0641\u0627\u064a\u0644 \u0636\u0645\u064a\u0645\u0647 \u0639\u06a9\u0633
-menu.photo.connect=\u0627\u062a\u0635\u0627\u0644 \u0628\u0647 \u0646\u0642\u0637\u0647
-menu.photo.disconnect=\u0642\u0637\u0639 \u0627\u062a\u0635\u0627\u0644 \u0627\u0632 \u0646\u0642\u0637\u0647
-menu.photo.delete=\u0628\u0631\u062f\u0627\u0634\u062a\u0646 \u0639\u06a9\u0633
+function.connecttopoint=\u0627\u062a\u0635\u0627\u0644 \u0628\u0647 \u0646\u0642\u0637\u0647
+function.disconnectfrompoint=\u0642\u0637\u0639 \u0627\u062a\u0635\u0627\u0644 \u0627\u0632 \u0646\u0642\u0637\u0647
+function.removephoto=\u0628\u0631\u062f\u0627\u0634\u062a\u0646 \u0639\u06a9\u0633
menu.view=\u062f\u064a\u062f
menu.view.browser=\u0646\u0642\u0634\u0647 \u062f\u0631\u062c\u0633\u062a\u062c\u0648\u06af\u0631
menu.view.browser.google=Google Maps
diff --git a/tim/prune/lang/prune-texts_fr.properties b/tim/prune/lang/prune-texts_fr.properties
index e608c9d..8c7f1b3 100644
--- a/tim/prune/lang/prune-texts_fr.properties
+++ b/tim/prune/lang/prune-texts_fr.properties
@@ -30,9 +30,9 @@ menu.point.editpoint=Editer le point
menu.point.deletepoint=Supprimer le point
menu.photo=Photo
menu.photo.saveexif=Enregistrer dans les Exif
-menu.photo.connect=Relier au point
-menu.photo.disconnect=D\u00e9tacher du point
-menu.photo.delete=Retirer la photo
+function.connecttopoint=Relier au point
+function.disconnectfrompoint=D\u00e9tacher du point
+function.removephoto=Retirer la photo
menu.view=Affichage
menu.view.browser=Ouvrir la carte dans le navigateur
menu.view.browser.google=Google maps
@@ -102,6 +102,7 @@ function.correlatephotos=Corr\u00e9ler les photos
function.rearrangephotos=R\u00e9arranger les photos
function.rotatephotoleft=Tourner la photo vers la gauche
function.rotatephotoright=Tourner la photo vers la droite
+function.photopopup=Montrer la photo
function.ignoreexifthumb=Ignorer l\u2019aper\u00e7u Exif
function.help=Aide
function.showkeys=Montrer les raccourcis clavier
@@ -266,9 +267,9 @@ dialog.gpsies.activity.skating=Skating
dialog.correlate.notimestamps=Les points n'ont pas d'indication de temps, il n'est pas possible de les corr\u00e9ler.
dialog.correlate.nouncorrelatedphotos=Il n'y a pas de photos non-corr\u00e9l\u00e9es.\nVoulez-vous continuer ?
dialog.correlate.photoselect.intro=S\u00e9lectionner une de ces photos corr\u00e9l\u00e9es pour d\u00e9finir le d\u00e9calage de temps
-dialog.correlate.photoselect.photoname=Nom de la photo
-dialog.correlate.photoselect.timediff=Diff\u00e9rence de temps
-dialog.correlate.photoselect.photolater=Photo prise plus tard
+dialog.correlate.select.photoname=Nom de la photo
+dialog.correlate.select.timediff=Diff\u00e9rence de temps
+dialog.correlate.select.photolater=Photo prise plus tard
dialog.correlate.options.tip=Astuce : En corr\u00e9lant manuellement au moins une photo, le d\u00e9calage de temps peut \u00eatre calcul\u00e9 pour vous.
dialog.correlate.options.intro=S\u00e9lectionner les options pour la corr\u00e9lation automatique
dialog.correlate.options.offsetpanel=D\u00e9calage de temps
@@ -277,7 +278,7 @@ dialog.correlate.options.offset.hours=heures,
dialog.correlate.options.offset.minutes=minutes et
dialog.correlate.options.offset.seconds=secondes
dialog.correlate.options.photolater=Photo post\u00e9rieure au point
-dialog.correlate.options.pointlater=Point post\u00e9rieur \u00e0 la photo
+dialog.correlate.options.pointlaterphoto=Point post\u00e9rieur \u00e0 la photo
dialog.correlate.options.limitspanel=Limites de corr\u00e9lation
dialog.correlate.options.notimelimit=Pas de limite de temps
dialog.correlate.options.timelimit=Limite de temps
@@ -395,7 +396,6 @@ dialog.diskcache.nocreate=Le r\u00e9pertoire cache n'est pas cr\u00e9\u00e9
# 3d window
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 \u00e0 afficher !
dialog.3dlines.intro=Ceci est la grille pour la vue 3D
@@ -421,17 +421,17 @@ confirm.undo.single=op\u00e9ration annul\u00e9e
confirm.undo.multi=op\u00e9rations annul\u00e9es
confirm.jpegload.single=la photo a \u00e9t\u00e9 ajout\u00e9e
confirm.jpegload.multi=les photos ont \u00e9t\u00e9 ajout\u00e9es
-confirm.photo.connect=photo reli\u00e9e
+confirm.media.connect=m\u00e9dia reli\u00e9e
confirm.photo.disconnect=photo d\u00e9tach\u00e9e
-confirm.correlate.single=photo a \u00e9t\u00e9 corr\u00e9l\u00e9e
-confirm.correlate.multi=photos ont \u00e9t\u00e9 corr\u00e9l\u00e9es
+confirm.correlatephotos.single=photo a \u00e9t\u00e9 corr\u00e9l\u00e9e
+confirm.correlatephotos.multi=photos ont \u00e9t\u00e9 corr\u00e9l\u00e9es
confirm.createpoint=Point cr\u00e9\u00e9
confirm.rotatephoto=Photo tourn\u00e9e
confirm.running=En cours...
confirm.lookupsrtm1=Trouv\u00e9
confirm.lookupsrtm2=valeurs d'altitude
-# Buttons || These are all the texts for buttons
+# Buttons
button.ok=OK
button.back=Retour
button.next=Prochain
@@ -505,12 +505,12 @@ details.range.maxspeed=Vitesse maximum
details.range.numsegments=Nombre de segments
details.range.pace=Allure
details.range.gradient=Pente
-details.waypointsphotos.waypoints=Waypoints
-details.waypointsphotos.photos=Photos
+details.lists.waypoints=Waypoints
+details.lists.photos=Photos
details.photodetails=D\u00e9tails de la photo
details.nophoto=Pas de photo
details.photo.loading=Chargement
-details.photo.connected=Reli\u00e9e
+details.media.connected=Reli\u00e9e
map.overzoom=Aucune carte disponible \u00e0 ce niveau de zoom
# Field names
@@ -553,6 +553,7 @@ units.iso8601=ISO 8601
# External urls
url.googlemaps=maps.google.fr
+wikipedia.lang=fr
# Cardinals for 3d plots
cardinal.n=N
@@ -565,7 +566,7 @@ undo.load=charger les donn\u00e9es
undo.loadphotos=charger les photos
undo.editpoint=\u00e9diter le point
undo.deletepoint=effacer le point
-undo.deletephoto=retirer la photo
+undo.removephoto=retirer la photo
undo.deleterange=effacer l'\u00e9tendue
undo.compress=compresser la trace
undo.insert=ins\u00e9rer les points
@@ -575,9 +576,9 @@ undo.addtimeoffset=ajouter d\u00e9calage d'heure
undo.addaltitudeoffset=ajouter d\u00e9calage d'altitude
undo.rearrangewaypoints=r\u00e9arranger les waypoints
undo.cutandmove=d\u00e9placer la s\u00e9lection
-undo.connectphoto=relier la photo
-undo.disconnectphoto=d\u00e9tacher la photo
-undo.correlate=corr\u00e9ler les photos
+undo.connect=relier
+undo.disconnect=d\u00e9tacher
+undo.correlatephotos=corr\u00e9ler les photos
undo.rearrangephotos=R\u00e9arranger les photos
undo.createpoint=ajouter un point
undo.rotatephoto=Tourner la photo
@@ -604,7 +605,6 @@ error.load.othererror=Erreur \u00e0 la lecture du fichier :
error.jpegload.dialogtitle=Erreur au chargement des photos
error.jpegload.nofilesfound=Aucun fichier trouv\u00e9
error.jpegload.nojpegsfound=Aucun fichier jpeg trouv\u00e9
-error.jpegload.noexiffound=Aucune information EXIF trouv\u00e9e
error.jpegload.nogpsfound=Aucune information GPS trouv\u00e9e
error.jpegload.exifreadfailed=Information EXIF illisible. Aucune information EXIF ne peut \u00eatre lue\nsans une librairie interne ou externe.
error.gpsload.unknown=Erreur inconnue
diff --git a/tim/prune/lang/prune-texts_hu.properties b/tim/prune/lang/prune-texts_hu.properties
new file mode 100644
index 0000000..29840dd
--- /dev/null
+++ b/tim/prune/lang/prune-texts_hu.properties
@@ -0,0 +1,693 @@
+# Text entries for the Prune application
+# Hungarian entries thanks to Gy\u00f6rgy Ball\u00f3
+
+# Menu entries
+menu.file=F\u00e1jl
+menu.file.addphotos=F\u00e9nyk\u00e9pek hozz\u00e1ad\u00e1sa
+menu.file.save=Ment\u00e9s sz\u00f6vegk\u00e9nt
+menu.file.exit=Kil\u00e9p\u00e9s
+menu.track=Nyomvonal
+menu.track.undo=Visszavon\u00e1s
+menu.track.clearundo=Visszavon\u00e1si lista t\u00f6rl\u00e9se
+menu.track.deletemarked=Jel\u00f6lt pontok t\u00f6rl\u00e9se
+menu.track.rearrange=\u00datpontok \u00fajrarendez\u00e9se
+menu.track.rearrange.start=\u00d6sszes a f\u00e1jl elej\u00e9re
+menu.track.rearrange.end=\u00d6sszes a f\u00e1jl v\u00e9g\u00e9re
+menu.track.rearrange.nearest=Egyenk\u00e9nt a legk\u00f6zelebbi nyomponthoz
+menu.range=Tartom\u00e1ny
+menu.range.all=Mindet kijel\u00f6l
+menu.range.none=Kijel\u00f6l\u00e9s megsz\u00fcntet\u00e9se
+menu.range.start=Tartom\u00e1ny kezdet\u00e9nek be\u00e1ll\u00edt\u00e1sa
+menu.range.end=Tartom\u00e1ny v\u00e9g\u00e9nek be\u00e1ll\u00edt\u00e1sa
+menu.range.deleterange=Tartom\u00e1ny t\u00f6rl\u00e9se
+menu.range.interpolate=Interpol\u00e1ci\u00f3
+menu.range.average=Kijel\u00f6l\u00e9s \u00e1tlaga
+menu.range.reverse=Tartom\u00e1ny megford\u00edt\u00e1sa
+menu.range.mergetracksegments=Nyomvonalszakaszok egyes\u00edt\u00e9se
+menu.range.cutandmove=Kijel\u00f6l\u00e9s kiv\u00e1g\u00e1sa \u00e9s mozgat\u00e1sa
+menu.point=Pont
+menu.point.editpoint=Pont szerkeszt\u00e9se
+menu.point.deletepoint=Pont t\u00f6rl\u00e9se
+menu.photo=F\u00e9nyk\u00e9p
+menu.photo.saveexif=Ment\u00e9s Exifbe
+menu.audio=Hang
+menu.view=N\u00e9zet
+menu.view.showsidebars=Oldals\u00e1vok megjelen\u00edt\u00e9se
+menu.view.browser=T\u00e9rk\u00e9p b\u00f6ng\u00e9sz\u0151ablakban
+menu.view.browser.google=Google T\u00e9rk\u00e9p
+menu.view.browser.openstreetmap=OpenStreetMap
+menu.view.browser.mapquest=Mapquest
+menu.view.browser.yahoo=Yahoo! Maps
+menu.view.browser.bing=Bing Maps
+menu.settings=Be\u00e1ll\u00edt\u00e1sok
+menu.settings.onlinemode=T\u00e9rk\u00e9pek bet\u00f6lt\u00e9se az internetr\u0151l
+menu.help=S\u00fag\u00f3
+# Popup menu for map
+menu.map.zoomin=Nagy\u00edt\u00e1s
+menu.map.zoomout=Kicsiny\u00edt\u00e9s
+menu.map.zoomfull=Nagy\u00edt\u00e1s a teljes m\u00e9retre
+menu.map.newpoint=\u00daj pont l\u00e9trehoz\u00e1sa
+menu.map.drawpoints=Pontsorozat l\u00e9trehoz\u00e1sa
+menu.map.connect=Nyompontok \u00f6sszek\u00f6t\u00e9se
+menu.map.autopan=Automatikus mozgat\u00e1s
+menu.map.showmap=T\u00e9rk\u00e9p megjelen\u00edt\u00e9se
+menu.map.showscalebar=M\u00e9retar\u00e1ny megjelen\u00edt\u00e9se
+
+# Alt keys for menus
+altkey.menu.file=F
+altkey.menu.track=V
+altkey.menu.range=T
+altkey.menu.point=P
+altkey.menu.view=N
+altkey.menu.photo=K
+altkey.menu.audio=H
+altkey.menu.settings=B
+altkey.menu.help=S
+
+# Ctrl shortcuts for menu items
+shortcut.menu.file.open=O
+shortcut.menu.file.load=L
+shortcut.menu.file.save=S
+shortcut.menu.track.undo=Z
+shortcut.menu.edit.compress=C
+shortcut.menu.range.all=A
+shortcut.menu.help.help=H
+
+# Functions
+function.open=F\u00e1jl megnyit\u00e1sa
+function.loadfromgps=Adatok let\u00f6lt\u00e9se GPS-r\u0151l
+function.sendtogps=Adatok felt\u00f6lt\u00e9se GPS-re
+function.exportkml=Export\u00e1l\u00e1s KML-be
+function.exportgpx=Export\u00e1l\u00e1s GPX-be
+function.exportpov=Export\u00e1l\u00e1s POV-ba
+function.exportsvg=Export\u00e1l\u00e1s SVG-be
+function.editwaypointname=\u00datpont nev\u00e9nek szerkeszt\u00e9se
+function.compress=Nyomvonal t\u00f6m\u00f6r\u00edt\u00e9se
+function.addtimeoffset=Id\u0151eltol\u00e1s hozz\u00e1ad\u00e1sa
+function.addaltitudeoffset=Magass\u00e1geltol\u00e1s hozz\u00e1ad\u00e1sa
+function.convertnamestotimes=\u00datpontok neveinek konvert\u00e1l\u00e1sa id\u0151pontokk\u00e1
+function.deletefieldvalues=Mez\u0151 \u00e9rt\u00e9keinek t\u00f6rl\u00e9se
+function.findwaypoint=\u00datpont keres\u00e9se
+function.pastecoordinates=\u00daj koordin\u00e1t\u00e1k megad\u00e1sa
+function.charts=Diagramok
+function.show3d=3D n\u00e9zet
+function.distances=T\u00e1vols\u00e1gok
+function.fullrangedetails=Teljes tartom\u00e1ny r\u00e9szletei
+function.setmapbg=H\u00e1tt\u00e9rk\u00e9p be\u00e1ll\u00edt\u00e1sa
+function.setkmzimagesize=KMZ k\u00e9pm\u00e9ret be\u00e1ll\u00edt\u00e1sa
+function.setpaths=Program\u00fatvonalak be\u00e1ll\u00edt\u00e1sa
+function.getgpsies=Gpsies nyomvonalak let\u00f6lt\u00e9se
+function.uploadgpsies=Nyomvonal felt\u00f6lt\u00e9se Gpsiesra
+function.lookupsrtm=Magass\u00e1gok let\u00f6lt\u00e9se SRTM-r\u0151l
+function.getwikipedia=K\u00f6zeli Wikip\u00e9dia sz\u00f3cikkek let\u00f6lt\u00e9se
+function.searchwikipedianames=Keres\u00e9s a Wikip\u00e9di\u00e1ban n\u00e9v szerint
+function.downloadosm=OSM adatok let\u00f6lt\u00e9se a ter\u00fcletr\u0151l
+function.duplicatepoint=Pont kett\u0151z\u00e9se
+function.setcolours=Sz\u00ednek be\u00e1ll\u00edt\u00e1sa
+function.setlinewidth=Vonalsz\u00e9less\u00e9g be\u00e1ll\u00edt\u00e1sa
+function.setlanguage=Nyelv be\u00e1ll\u00edt\u00e1sa
+function.connecttopoint=Kapcsol\u00e1s ponthoz
+function.disconnectfrompoint=Lev\u00e1laszt\u00e1s pontr\u00f3l
+function.removephoto=F\u00e9nyk\u00e9p elt\u00e1vol\u00edt\u00e1sa
+function.correlatephotos=F\u00e9nyk\u00e9pek megfeleltet\u00e9se
+function.rearrangephotos=F\u00e9nyk\u00e9pek \u00fajrarendez\u00e9se
+function.rotatephotoleft=F\u00e9nyk\u00e9p forgat\u00e1sa balra
+function.rotatephotoright=F\u00e9nyk\u00e9p forgat\u00e1sa jobbra
+function.photopopup=F\u00e9nyk\u00e9p felugr\u00f3 ablak megjelen\u00edt\u00e9se
+function.ignoreexifthumb=Exif miniat\u0171r figyelmen k\u00edv\u00fcl hagy\u00e1sa
+function.loadaudio=Hangf\u00e1jlok hozz\u00e1ad\u00e1sa
+function.removeaudio=Hangf\u00e1jl elt\u00e1vol\u00edt\u00e1sa
+function.correlateaudios=Hangok megfeleltet\u00e9se
+function.playaudio=Hangf\u00e1jl lej\u00e1tsz\u00e1sa
+function.stopaudio=Hangf\u00e1jl meg\u00e1ll\u00edt\u00e1sa
+function.help=S\u00fag\u00f3
+function.showkeys=Gyorsbillenty\u0171k megjelen\u00edt\u00e9se
+function.about=A Prune n\u00e9vjegye
+function.checkversion=\u00daj verzi\u00f3 keres\u00e9se
+function.saveconfig=Be\u00e1ll\u00edt\u00e1sok ment\u00e9se
+function.diskcache=T\u00e9rk\u00e9pek ment\u00e9se lemezre
+
+# Dialogs
+dialog.exit.confirm.title=Kil\u00e9p\u00e9s a Prune-b\u00f3l
+dialog.exit.confirm.text=Az adatok nincsenek elmentve. Biztos benne, hogy kil\u00e9p?
+dialog.openappend.title=Hozz\u00e1f\u0171z\u00e9s a megl\u00e9v\u0151 adatokhoz
+dialog.openappend.text=Hozz\u00e1f\u0171zi ezeket az adatokat a m\u00e1r bet\u00f6lt\u00f6tt adatokhoz?
+dialog.deletepoint.title=Pont t\u00f6rl\u00e9se
+dialog.deletepoint.deletephoto=T\u00f6rli a f\u00e9nyk\u00e9pet, amely ehhez a ponthoz tartozik?
+dialog.deletephoto.title=F\u00e9nyk\u00e9p t\u00f6rl\u00e9se
+dialog.deletephoto.deletepoint=T\u00f6rli a pontot, amely ehhez a f\u00e9nyk\u00e9phez tartozik?
+dialog.openoptions.title=Be\u00e1ll\u00edt\u00e1sok megnyit\u00e1sa
+dialog.openoptions.filesnippet=F\u00e1jl kivonata
+dialog.load.table.field=Mez\u0151
+dialog.load.table.datatype=Adatt\u00edpus
+dialog.load.table.description=Le\u00edr\u00e1s
+dialog.delimiter.label=Mez\u0151elv\u00e1laszt\u00f3
+dialog.delimiter.comma=Vessz\u0151 ,
+dialog.delimiter.tab=Tabul\u00e1tor
+dialog.delimiter.space=Sz\u00f3k\u00f6z
+dialog.delimiter.semicolon=Pontosvessz\u0151 ;
+dialog.delimiter.other=Egy\u00e9b
+dialog.openoptions.deliminfo.records=rekord
+dialog.openoptions.deliminfo.fields=mez\u0151vel
+dialog.openoptions.deliminfo.norecords=Nincsenek rekordok
+dialog.openoptions.altitudeunits=Magass\u00e1g egys\u00e9ge
+dialog.open.contentsdoubled=Ez a f\u00e1jl minden egyes pont k\u00e9t p\u00e9ld\u00e1ny\u00e1t tartalmazza,\negyszer mint \u00fatpont, m\u00e1sodszor mint nyompont.
+dialog.selecttracks.intro=Nyomvonal vagy nyomvonalak kiv\u00e1laszt\u00e1sa bet\u00f6lt\u00e9shez
+dialog.selecttracks.noname=N\u00e9vtelen
+dialog.jpegload.subdirectories=Alk\u00f6nyvt\u00e1rakban is
+dialog.jpegload.loadjpegswithoutcoords=Koordin\u00e1t\u00e1k n\u00e9lk\u00fcli k\u00e9peket is
+dialog.jpegload.loadjpegsoutsidearea=A jelenlegi ter\u00fcleten k\u00edv\u00fcli k\u00e9peket is
+dialog.jpegload.progress.title=F\u00e9nyk\u00e9pek bet\u00f6lt\u00e9se
+dialog.jpegload.progress=K\u00e9rem, v\u00e1rjon, am\u00edg a f\u00e9nyk\u00e9pek keres\u00e9se tart
+dialog.gpsload.nogpsbabel=A gpsbabel program nem tal\u00e1lhat\u00f3. Folytatja?
+dialog.gpsload.device=Eszk\u00f6z neve
+dialog.gpsload.format=Form\u00e1tum
+dialog.gpsload.getwaypoints=\u00datpontok bet\u00f6lt\u00e9se
+dialog.gpsload.gettracks=Nyomvonalak bet\u00f6lt\u00e9se
+dialog.gpsload.save=Ment\u00e9s f\u00e1jlba
+dialog.gpssend.sendwaypoints=\u00datpontok k\u00fcld\u00e9se
+dialog.gpssend.sendtracks=Nyomvonalak k\u00fcld\u00e9se
+dialog.gpssend.trackname=Nyomvonal neve
+dialog.saveoptions.title=F\u00e1jl ment\u00e9se
+dialog.save.fieldstosave=Mentend\u0151 mez\u0151k
+dialog.save.table.field=Mez\u0151
+dialog.save.table.hasdata=Tartalmaz adatot
+dialog.save.table.save=Ment\u00e9s
+dialog.save.headerrow=Fejl\u00e9csor a kimenetbe
+dialog.save.coordinateunits=Koordin\u00e1ta egys\u00e9ge
+dialog.save.altitudeunits=Magass\u00e1g egys\u00e9ge
+dialog.save.timestampformat=Id\u0151b\u00e9lyeg form\u00e1tuma
+dialog.save.overwrite.title=A f\u00e1jl m\u00e1r l\u00e9tezik
+dialog.save.overwrite.text=Ez a f\u00e1jl m\u00e1r l\u00e9tezik. Biztos benne, hogy fel\u00fcl\u00edrja a f\u00e1jlt?
+dialog.save.notypesselected=Nincs pontt\u00edpus kiv\u00e1lasztva
+dialog.exportkml.text=C\u00edm az adatokhoz
+dialog.exportkml.altitude=Abszol\u00fat magass\u00e1gok (rep\u00fcl\u00e9shez)
+dialog.exportkml.kmz=T\u00f6m\u00f6r\u00edt\u00e9s kmz f\u00e1jl k\u00e9sz\u00edt\u00e9s\u00e9hez
+dialog.exportkml.exportimages=K\u00e9pminiat\u0171r\u00f6k export\u00e1l\u00e1sa kmz-be
+dialog.exportkml.trackcolour=Nyomvonal sz\u00edne
+dialog.exportgpx.name=N\u00e9v
+dialog.exportgpx.desc=Le\u00edr\u00e1s
+dialog.exportgpx.includetimestamps=Id\u0151b\u00e9lyegek is
+dialog.exportgpx.copysource=Forr\u00e1s xml m\u00e1sol\u00e1sa
+dialog.exportpov.text=Adja meg a param\u00e9tereket a POV exporthoz
+dialog.exportpov.font=Bet\u0171t\u00edpus
+dialog.exportpov.camerax=X kamera
+dialog.exportpov.cameray=Y kamera
+dialog.exportpov.cameraz=Z kamera
+dialog.exportpov.modelstyle=Modell st\u00edlusa
+dialog.exportpov.ballsandsticks=Goly\u00f3k \u00e9s botok
+dialog.exportpov.tubesandwalls=Cs\u00f6vek \u00e9s falak
+dialog.exportpov.warningtracksize=Ez a nyomvonal nagy sz\u00e1m\u00fa pontot tartalmaz, amelyet a Java3D nem biztos, hogy meg tud jelen\u00edteni.\nBiztos benne, hogy folytatni szeretn\u00e9?
+dialog.exportsvg.text=Param\u00e9terek kiv\u00e1laszt\u00e1sa az SVG exporthoz
+dialog.exportsvg.phi=Ir\u00e1nysz\u00f6g \u03d5
+dialog.exportsvg.theta=Emel\u00e9s sz\u00f6ge \u03b8
+dialog.exportsvg.gradients=\u00c1tmenetek haszn\u00e1lata az \u00e1rny\u00e9kol\u00e1shoz
+dialog.pointtype.desc=A k\u00f6vetkez\u0151 pontt\u00edpusok ment\u00e9se:
+dialog.pointtype.track=Nyompontok
+dialog.pointtype.waypoint=\u00datpontok
+dialog.pointtype.photo=F\u00e9nyk\u00e9ppontok
+dialog.pointtype.audio=Hangpontok
+dialog.pointtype.selection=Csak a kijel\u00f6lt
+dialog.confirmreversetrack.title=Megford\u00edt\u00e1s meger\u0151s\u00edt\u00e9se
+dialog.confirmreversetrack.text=Ez a nyomvonal id\u0151b\u00e9lyeg-inform\u00e1ci\u00f3t tartalmaz, amely sorrendje megford\u00edt\u00e1s ut\u00e1n megv\u00e1ltozik.\n Biztos benne, hogy megford\u00edtja a kijel\u00f6l\u00e9st?
+dialog.confirmcutandmove.title=Kiv\u00e1g\u00e1s \u00e9s mozgat\u00e1s meger\u0151s\u00edt\u00e9se
+dialog.confirmcutandmove.text=Ez a nyomvonal id\u0151b\u00e9lyeg-inform\u00e1ci\u00f3t tartalmaz, amely sorrendje mozgat\u00e1s ut\u00e1n megv\u00e1ltozik.\n Biztos benne, hogy mozgatja a kijel\u00f6l\u00e9st?
+dialog.interpolate.title=Pontok interpol\u00e1l\u00e1sa
+dialog.interpolate.parameter.text=Pontok sz\u00e1ma, amely a k\u00e9t kiv\u00e1lasztott pont k\u00f6z\u00e9 besz\u00farand\u00f3
+dialog.undo.title=M\u0171velet(ek) visszavon\u00e1sa
+dialog.undo.pretext=V\u00e1lassza ki a visszavonand\u00f3 m\u0171velet(ek)et
+dialog.undo.none.title=Nem vonhat\u00f3 vissza
+dialog.undo.none.text=Nincs visszavonhat\u00f3 m\u0171velet!
+dialog.clearundo.title=Visszavon\u00e1si lista t\u00f6rl\u00e9se
+dialog.clearundo.text=Biztos benne, hogy t\u00f6r\u00f6lni szeretn\u00e9 a visszavon\u00e1si list\u00e1t?\nMinden visszavon\u00e1si inform\u00e1ci\u00f3 el fog veszni!
+dialog.pointedit.title=Pont szerkeszt\u00e9se
+dialog.pointedit.text=V\u00e1lassza ki egyenk\u00e9nt a mez\u0151ket, amelyeket szerkeszteni szeretne, majd az \u00e9rt\u00e9k m\u00f3dos\u00edt\u00e1s\u00e1hoz haszn\u00e1lja a "Szerkeszt\u00e9s" gombot
+dialog.pointedit.table.field=Mez\u0151
+dialog.pointedit.table.value=\u00c9rt\u00e9k
+dialog.pointedit.table.changed=M\u00f3dosult
+dialog.pointedit.changevalue.text=Adjon meg egy \u00faj \u00e9rt\u00e9ket a mez\u0151h\u00f6z
+dialog.pointedit.changevalue.title=Mez\u0151 szerkeszt\u00e9se
+dialog.pointnameedit.name=\u00datpont neve
+dialog.pointnameedit.uppercase=NAGYBET\u0170S
+dialog.pointnameedit.lowercase=kisbet\u0171s
+dialog.pointnameedit.sentencecase=Nagy Kezd\u0151bet\u0171s
+dialog.addtimeoffset.add=Id\u0151 hozz\u00e1ad\u00e1sa
+dialog.addtimeoffset.subtract=Id\u0151 kivon\u00e1sa
+dialog.addtimeoffset.days=Nap
+dialog.addtimeoffset.hours=\u00d3ra
+dialog.addtimeoffset.minutes=Perc
+dialog.addtimeoffset.notimestamps=Nem adhat\u00f3 hozz\u00e1 id\u0151eltol\u00e1s, mivel a kijel\u00f6l\u00e9s nem tartalmaz id\u0151b\u00e9lyeg-inform\u00e1ci\u00f3t
+dialog.findwaypoint.intro=Adja meg az \u00fatpont nev\u00e9nek egy r\u00e9sz\u00e9t
+dialog.findwaypoint.search=Keres\u00e9s
+dialog.saveexif.title=Exif ment\u00e9se
+dialog.saveexif.intro=V\u00e1lassza ki a mentend\u0151 f\u00e9nyk\u00e9peket a jel\u00f6l\u0151n\u00e9gyzetek haszn\u00e1lat\u00e1val
+dialog.saveexif.nothingtosave=A koordin\u00e1taadatok nem m\u00f3dosultak, nincs mit menteni
+dialog.saveexif.noexiftool=Az exiftool program nem tal\u00e1lhat\u00f3. Folytatja?
+dialog.saveexif.table.photoname=F\u00e9nyk\u00e9p neve
+dialog.saveexif.table.status=\u00c1llapot
+dialog.saveexif.table.save=Ment\u00e9s
+dialog.saveexif.photostatus.connected=\u00d6sszekapcsolva
+dialog.saveexif.photostatus.disconnected=Lev\u00e1lasztva
+dialog.saveexif.photostatus.modified=M\u00f3dos\u00edtva
+dialog.saveexif.overwrite=F\u00e1jlok fel\u00fcl\u00edr\u00e1sa
+dialog.saveexif.force=K\u00e9nyszer\u00edt\u00e9s kisebb hib\u00e1k ellen\u00e9re
+dialog.charts.xaxis=X tengely
+dialog.charts.yaxis=Y tengely
+dialog.charts.output=Kimenet
+dialog.charts.screen=Kimenet k\u00e9perny\u0151re
+dialog.charts.svg=Kimenet SVG f\u00e1jlba
+dialog.charts.svgwidth=SVG sz\u00e9less\u00e9ge
+dialog.charts.svgheight=SVG magass\u00e1ga
+dialog.charts.needaltitudeortimes=Diagramok k\u00e9sz\u00edt\u00e9s\u00e9hez a nyomvonalnak tartalmaznia kell magass\u00e1gi vagy id\u0151inform\u00e1ci\u00f3kat
+dialog.charts.gnuplotnotfound=A gnuplot a megadott \u00fatvonalon nem tal\u00e1lhat\u00f3
+dialog.distances.intro=T\u00e1vols\u00e1gok l\u00e9gvonalban a pontok k\u00f6z\u00f6tt
+dialog.distances.column.from=Indul\u00f3 pont
+dialog.distances.column.to=V\u00e9gpont
+dialog.distances.currentpoint=Jelenlegi pont
+dialog.distances.toofewpoints=Ehhez a funkci\u00f3hoz \u00fatpontok kellenek, amelyek k\u00f6z\u00f6tt a t\u00e1vols\u00e1g sz\u00e1m\u00edt\u00e1sra ker\u00fcl
+dialog.fullrangedetails.intro=Itt vannak a r\u00e9szletei a kiv\u00e1lasztott tartom\u00e1nynak
+dialog.setmapbg.intro=V\u00e1lassza ki az egyik t\u00e9rk\u00e9pforr\u00e1st, vagy adjon hozz\u00e1 egy \u00fajat
+dialog.addmapsource.title=\u00daj t\u00e9rk\u00e9pforr\u00e1s hozz\u00e1ad\u00e1sa
+dialog.addmapsource.sourcename=Forr\u00e1s neve
+dialog.addmapsource.layer1url=Els\u0151 r\u00e9teg URL-je
+dialog.addmapsource.layer2url=Opcion\u00e1lis m\u00e1sodik r\u00e9teg URL-je
+dialog.addmapsource.maxzoom=Maxim\u00e1lis nagy\u00edt\u00e1si szint
+dialog.addmapsource.cloudstyle=St\u00edlus sz\u00e1ma
+dialog.addmapsource.noname=N\u00e9vtelen
+dialog.gpsies.column.name=Nyomvonal neve
+dialog.gpsies.column.length=Hossz
+dialog.gpsies.description=Le\u00edr\u00e1s
+dialog.gpsies.nodescription=Nincs le\u00edr\u00e1s
+dialog.gpsies.nonefound=Nem tal\u00e1lhat\u00f3 nyomvonal
+dialog.gpsies.username=Gpsies felhaszn\u00e1l\u00f3n\u00e9v
+dialog.gpsies.password=Gpsies jelsz\u00f3
+dialog.gpsies.keepprivate=A nyomvonal maradjon priv\u00e1t
+dialog.gpsies.confirmopenpage=Megnyitja a weboldalt a felt\u00f6lt\u00f6tt nyomvonal sz\u00e1m\u00e1ra?
+dialog.gpsies.activities=Tev\u00e9kenys\u00e9gt\u00edpusok
+dialog.gpsies.activity.trekking=T\u00far\u00e1z\u00e1s
+dialog.gpsies.activity.walking=S\u00e9ta
+dialog.gpsies.activity.jogging=Fut\u00e1s
+dialog.gpsies.activity.biking=Ker\u00e9kp\u00e1roz\u00e1s
+dialog.gpsies.activity.motorbiking=Motorker\u00e9kp\u00e1roz\u00e1s
+dialog.gpsies.activity.snowshoe=H\u00f3talpas s\u00e9ta
+dialog.gpsies.activity.sailing=Vitorl\u00e1z\u00e1s
+dialog.gpsies.activity.skating=Korcsoly\u00e1z\u00e1s
+dialog.wikipedia.column.name=Sz\u00f3cikk neve
+dialog.wikipedia.column.distance=T\u00e1vols\u00e1g
+dialog.correlate.notimestamps=Nincsenek id\u0151b\u00e9lyegek az adatpontokon, \u00edgy nem feleltethet\u0151 meg semmi a f\u00e9nyk\u00e9pekkel.
+dialog.correlate.nouncorrelatedphotos=Nincsenek megfeleltetlen f\u00e9nyk\u00e9pek.\nBiztos benne, hogy folytatja?
+dialog.correlate.photoselect.intro=V\u00e1lasszon egyet ezek k\u00f6z\u00fcl a megfeleltetett f\u00e9nyk\u00e9pek k\u00f6z\u00fcl az id\u0151eltol\u00e1s haszn\u00e1lat\u00e1hoz
+dialog.correlate.select.photoname=F\u00e9nyk\u00e9p neve
+dialog.correlate.select.timediff=Id\u0151k\u00fcl\u00f6nbs\u00e9g
+dialog.correlate.select.photolater=K\u00e9s\u0151bbi f\u00e9nyk\u00e9p
+dialog.correlate.options.tip=Tipp: legal\u00e1bb egy elem k\u00e9zzel t\u00f6rt\u00e9n\u0151 \u00f6sszekapcsol\u00e1s\u00e1val az id\u0151eltol\u00e1s kisz\u00e1m\u00edthat\u00f3.
+dialog.correlate.options.intro=V\u00e1lassza ki az opci\u00f3kat az automatikus megfeleltet\u00e9shez
+dialog.correlate.options.offsetpanel=Id\u0151eltol\u00e1s
+dialog.correlate.options.offset=Eltol\u00e1s
+dialog.correlate.options.offset.hours=\u00f3ra,
+dialog.correlate.options.offset.minutes=perc \u00e9s
+dialog.correlate.options.offset.seconds=m\u00e1sodperc
+dialog.correlate.options.photolater=A f\u00e9nyk\u00e9p k\u00e9s\u0151bbi, mint a pont
+dialog.correlate.options.pointlaterphoto=A pont k\u00e9s\u0151bbi, mint a f\u00e9nyk\u00e9p
+dialog.correlate.options.audiolater=A hang k\u00e9s\u0151bbi, mint a pont
+dialog.correlate.options.pointlateraudio=A pont k\u00e9s\u0151bbi, mint a hang
+dialog.correlate.options.limitspanel=Megfeleltet\u00e9s korl\u00e1tai
+dialog.correlate.options.notimelimit=Nincs id\u0151korl\u00e1t
+dialog.correlate.options.timelimit=Id\u0151korl\u00e1t
+dialog.correlate.options.nodistancelimit=Nincs t\u00e1vols\u00e1gkorl\u00e1t
+dialog.correlate.options.distancelimit=T\u00e1vols\u00e1gkorl\u00e1t
+dialog.correlate.options.correlate=Megfeleltet\u00e9s
+dialog.correlate.alloutsiderange=Az \u00f6sszes f\u00e9nyk\u00e9p a nyomvonal id\u0151tartom\u00e1ny\u00e1n k\u00edv\u00fcl esik, \u00edgy egyik sem feleltethet\u0151 meg.\nPr\u00f3b\u00e1lja m\u00f3dos\u00edtani az eltol\u00e1st, vagy k\u00e9zzel megfeleltetni legal\u00e1bb egy f\u00e9nyk\u00e9pet.
+dialog.correlate.filetimes=F\u00e1jl-id\u0151b\u00e9lyegek jelzik:
+dialog.correlate.filetimes2=a hangf\u00e1jlnak
+dialog.correlate.correltimes=A megfeleltet\u00e9shez haszn\u00e1lja:
+dialog.correlate.timestamp.beginning=Elej\u00e9t
+dialog.correlate.timestamp.middle=K\u00f6zep\u00e9t
+dialog.correlate.timestamp.end=V\u00e9g\u00e9t
+dialog.correlate.audioselect.intro=V\u00e1lasszon egyet ezek k\u00f6z\u00fcl a megfeleltetett f\u00e9nyk\u00e9pek k\u00f6z\u00fcl az id\u0151eltol\u00e1s haszn\u00e1lat\u00e1hoz
+dialog.correlate.select.audioname=Hang neve
+dialog.correlate.select.audiolater=Hang k\u00e9s\u0151bb
+dialog.rearrangephotos.desc=V\u00e1lassza ki a f\u00e9nyk\u00e9ppontok c\u00e9lj\u00e1t \u00e9s rendez\u00e9si sorrendj\u00e9t
+dialog.rearrangephotos.tostart=Mozgat\u00e1s a kezdet\u00e9hez
+dialog.rearrangephotos.toend=Mozgat\u00e1s a v\u00e9g\u00e9hez
+dialog.rearrangephotos.nosort=Ne rendezze
+dialog.rearrangephotos.sortbyfilename=Rendez\u00e9s f\u00e1jln\u00e9v szerint
+dialog.rearrangephotos.sortbytime=Rendez\u00e9s id\u0151 szerint
+dialog.compress.nonefound=Nem t\u00e1vol\u00edthat\u00f3 el adatpont
+dialog.compress.closepoints.title=K\u00f6zeli pontok elt\u00e1vol\u00edt\u00e1sa
+dialog.compress.closepoints.paramdesc=Hat\u00f3t\u00e1vols\u00e1g
+dialog.compress.wackypoints.title=Kisz\u00e1m\u00edthatatlan pontok elt\u00e1vol\u00edt\u00e1sa
+dialog.compress.wackypoints.paramdesc=T\u00e1vols\u00e1gt\u00e9nyez\u0151
+dialog.compress.singletons.title=Egyke pontok elt\u00e1vol\u00edt\u00e1sa
+dialog.compress.singletons.paramdesc=T\u00e1vols\u00e1gt\u00e9nyez\u0151
+dialog.compress.duplicates.title=Kett\u0151z\u00f6tt pontok elt\u00e1vol\u00edt\u00e1sa
+dialog.compress.summarylabel=T\u00f6rlend\u0151 pontok
+dialog.pastecoordinates.desc=Adja meg vagy illessze be a koordin\u00e1t\u00e1kat ide
+dialog.pastecoordinates.coords=Koordin\u00e1t\u00e1k
+dialog.pastecoordinates.nothingfound=Ellen\u0151rizze a koordin\u00e1t\u00e1kat, \u00e9s pr\u00f3b\u00e1lja \u00f3jra
+dialog.help.help=Tov\u00e1bbi inform\u00e1ci\u00f3k\u00e9rt \u00e9s kezel\u00e9si \u00fatmutat\u00f3\u00e9rt l\u00e1sd a \n http://activityworkshop.net/software/prune/\nwebhelyet.
+dialog.about.version=Verzi\u00f3
+dialog.about.build=Build
+dialog.about.summarytext1=A Prune egy program GPS vev\u0151kr\u0151l sz\u00e1rmaz\u00f3 adatok bet\u00f6lt\u00e9s\u00e9re, megjelen\u00edt\u00e9s\u00e9re \u00e9s szerkeszt\u00e9s\u00e9re.
+dialog.about.summarytext2=Gnu GPL licenc alatt ker\u00fclt kiad\u00e1sra a szabad, ny\u00edlt, vil\u00e1gm\u00e9ret\u0171 haszn\u00e1lathoz \u00e9s fejleszt\u00e9shez. M\u00e1sol\u00e1sa, terjeszt\u00e9se \u00e9s m\u00f3dos\u00edt\u00e1sa megengedett \u00e9s \u00f6szt\u00f6nz\u00f6tt a mell\u00e9kelt license.txt f\u00e1jlban r\u00f6gz\u00edtett felt\u00e9telek szerint
+dialog.about.summarytext3=Tov\u00e1bbi inform\u00e1ci\u00f3k\u00e9rt \u00e9s kezel\u00e9si \u00fatmutat\u00f3\u00e9rt l\u00e1sd a http://activityworkshop.net/ webhelyet.
+dialog.about.languages=El\u00e9rhet\u0151 nyelvek
+dialog.about.translatedby=Magyar sz\u00f6veg: Ball\u00f3 Gy\u00f6rgy
+dialog.about.systeminfo=Rendszerinform\u00e1ci\u00f3
+dialog.about.systeminfo.os=Oper\u00e1ci\u00f3s rendszer
+dialog.about.systeminfo.java=Java futtat\u00f3k\u00f6rnyezet
+dialog.about.systeminfo.java3d=Java3d telep\u00edtve
+dialog.about.systeminfo.povray=Povray telep\u00edtve
+dialog.about.systeminfo.exiftool=Exiftool telep\u00edtve
+dialog.about.systeminfo.gpsbabel=Gpsbabel telep\u00edtve
+dialog.about.systeminfo.gnuplot=Gnuplot telep\u00edtve
+dialog.about.systeminfo.exiflib=Exif f\u00fcggv\u00e9nyk\u00f6nyvt\u00e1r
+dialog.about.systeminfo.exiflib.internal=Be\u00e9p\u00edtett
+dialog.about.systeminfo.exiflib.internal.failed=Be\u00e9p\u00edtett (nem tal\u00e1lhat\u00f3)
+dialog.about.systeminfo.exiflib.external=K\u00fcls\u0151
+dialog.about.systeminfo.exiflib.external.failed=K\u00fcls\u0151 (nem tal\u00e1lhat\u00f3)
+dialog.about.yes=Igen
+dialog.about.no=Nem
+dialog.about.credits=K\u00e9sz\u00edt\u0151k
+dialog.about.credits.code=Prune k\u00f3dj\u00e1t \u00edrta:
+dialog.about.credits.exifcode=Exif k\u00f3d:
+dialog.about.credits.icons=N\u00e9h\u00e1ny ikon sz\u00e1rmazik:
+dialog.about.credits.translators=Ford\u00edt\u00f3k
+dialog.about.credits.translations=Ford\u00edt\u00e1st seg\u00edtette
+dialog.about.credits.devtools=Fejleszt\u0151eszk\u00f6z\u00f6k
+dialog.about.credits.othertools=Egy\u00e9b eszk\u00f6z\u00f6k
+dialog.about.credits.thanks=K\u00f6sz\u00f6net:
+dialog.about.readme=Olvassel
+dialog.checkversion.error=A verzi\u00f3sz\u00e1m nem ellen\u0151rizhet\u0151.\nEllen\u0151rizze az internetkapcsolatot.
+dialog.checkversion.uptodate=A Prune leg\u00fajabb verzi\u00f3j\u00e1t haszn\u00e1lja.
+dialog.checkversion.newversion1=El\u00e9rhet\u0151 a Prune \u00faj verzi\u00f3ja! A leg\u00fajabb veri\u00f3 most:
+dialog.checkversion.newversion2=.
+dialog.checkversion.releasedate1=Ez az \u00faj verzi\u00f3 kiad\u00e1sra ker\u00fclt:
+dialog.checkversion.releasedate2=.
+dialog.checkversion.download=Az \u00faj verzi\u00f3 let\u00f6lt\u00e9s\u00e9hez keresse fel a http://activityworkshop.net/software/prune/download.html webhelyet.
+dialog.keys.intro=A k\u00f6vetkez\u0151 gyorsbillenty\u0171k haszn\u00e1lhat\u00f3k az eg\u00e9r haszn\u00e1lata helyett
+dialog.keys.keylist=
Ny\u00edlbillenty\u0171k
T\u00e9rk\u00e9p mozgat\u00e1sa balra, jobbra, fel, le
Ctrl + bal, jobb ny\u00edl
El\u0151z\u0151 vagy k\u00f6vetkez\u0151 pont kiv\u00e1laszt\u00e1sa
Ctrl + fel, le ny\u00edl
Nagy\u00edt\u00e1s vagy kicsiny\u00edt\u00e9s
Ctrl + PgUp, PgDown
El\u0151z\u0151, k\u00f6vetkez\u0151 szakasz kiv\u00e1laszt\u00e1sa
Ctrl + Home, End
Els\u0151, utols\u00f3 pont kiv\u00e1laszt\u00e1sa
Del
Jelenlegi pont t\u00f6rl\u00e9se
+dialog.keys.normalmodifier=Ctrl
+dialog.keys.macmodifier=Command
+dialog.saveconfig.desc=A k\u00f6vetkez\u0151 be\u00e1ll\u00edt\u00e1sok menthet\u0151k egy konfigur\u00e1ci\u00f3s f\u00e1jlba
+dialog.saveconfig.prune.trackdirectory=Nyomvonalak k\u00f6nyvt\u00e1ra
+dialog.saveconfig.prune.photodirectory=F\u00e9nyk\u00e9pek k\u00f6nyvt\u00e1ra
+dialog.saveconfig.prune.languagecode=Nyelv k\u00f3dja (HU)
+dialog.saveconfig.prune.languagefile=Nyelvi f\u00e1jl
+dialog.saveconfig.prune.gpsdevice=GPS eszk\u00f6z
+dialog.saveconfig.prune.gpsformat=GPS form\u00e1tum
+dialog.saveconfig.prune.povrayfont=Povray bet\u0171t\u00edpus
+dialog.saveconfig.prune.metricunits=Metrikus m\u00e9rt\u00e9krendszer haszn\u00e1lata?
+dialog.saveconfig.prune.gnuplotpath=\u00datvonal a gnuplothoz
+dialog.saveconfig.prune.gpsbabelpath=\u00datvonal a gpsbabelhez
+dialog.saveconfig.prune.exiftoolpath=\u00datvonal az exiftoolhoz
+dialog.saveconfig.prune.mapsource=Kiv\u00e1lasztott t\u00e9rk\u00e9pforr\u00e1s
+dialog.saveconfig.prune.mapsourcelist=T\u00e9rk\u00e9pforr\u00e1sok
+dialog.saveconfig.prune.diskcache=T\u00e9rk\u00e9p-gyors\u00edt\u00f3t\u00e1r
+dialog.saveconfig.prune.kmzimagewidth=KMZ k\u00e9psz\u00e9less\u00e9g
+dialog.saveconfig.prune.kmzimageheight=KMZ k\u00e9pmagass\u00e1g
+dialog.saveconfig.prune.colourscheme=Sz\u00edns\u00e9ma
+dialog.saveconfig.prune.linewidth=Vonalsz\u00e9less\u00e9g
+dialog.saveconfig.prune.kmltrackcolour=KML nyomvonal sz\u00edne
+dialog.setpaths.intro=Ha sz\u00fcks\u00e9ges, kiv\u00e1laszthatja a k\u00fcls\u0151 alkalmaz\u00e1sok \u00fatvonalait:
+dialog.setpaths.found=\u00datvonal megtal\u00e1lhat\u00f3?
+dialog.addaltitude.noaltitudes=A kiv\u00e1lasztott tartom\u00e1ny nem tartalmaz magass\u00e1gi \u00e9rt\u00e9keket
+dialog.addaltitude.desc=Magass\u00e1ki eltol\u00e1s, amely hozz\u00e1adand\u00f3
+dialog.lookupsrtm.overwritezeros=Fel\u00fcl\u00edrja a nulla magass\u00e1g \u00e9rt\u00e9ket?
+dialog.setcolours.intro=A sz\u00edn m\u00f3dos\u00edt\u00e1s\u00e1hoz kattintson egy sz\u00ednfoltra
+dialog.setcolours.background=H\u00e1tt\u00e9r
+dialog.setcolours.borders=Szeg\u00e9lyek
+dialog.setcolours.lines=Vonalak
+dialog.setcolours.primary=Els\u0151dleges
+dialog.setcolours.secondary=M\u00e1sodlagos
+dialog.setcolours.point=Pontok
+dialog.setcolours.selection=Kijel\u00f6l\u00e9s
+dialog.setcolours.text=Sz\u00f6veg
+dialog.colourchooser.title=Sz\u00edn kiv\u00e1laszt\u00e1sa
+dialog.colourchooser.red=Piros
+dialog.colourchooser.green=Z\u00f6ld
+dialog.colourchooser.blue=K\u00e9k
+dialog.setlanguage.firstintro=Kiv\u00e1laszthat egy be\u00e9p\u00edtett nyelvet,
vagy v\u00e1lasszon egy sz\u00f6vegf\u00e1jlt helyette.
+dialog.setlanguage.secondintro=Mentenie kell a be\u00e1ll\u00edt\u00e1sokat, majd
a nyelv v\u00e1lt\u00e1s\u00e1hoz ind\u00edtsa \u00fajra a Prune-t.
+dialog.setlanguage.language=Nyelv
+dialog.setlanguage.languagefile=Nyelvi f\u00e1jl
+dialog.setlanguage.endmessage=Most mentse a be\u00e1ll\u00edt\u00e1sokat, \u00e9s ind\u00edtsa \u00fajra a Prune-t,\nhogy a nyelv v\u00e1lt\u00e1sa \u00e9rv\u00e9nybe l\u00e9pjen
+dialog.diskcache.save=T\u00e9rk\u00e9pek ment\u00e9se a lemezre
+dialog.diskcache.dir=Gyors\u00edt\u00f3t\u00e1r k\u00f6nyvt\u00e1ra
+dialog.diskcache.createdir=K\u00f6nyvt\u00e1r l\u00e9trehoz\u00e1sa
+dialog.diskcache.nocreate=A gyors\u00edt\u00f3t\u00e1r k\u00f6nyvt\u00e1ra nem ker\u00fclt l\u00e9trehoz\u00e1sra
+dialog.deletefieldvalues.intro=V\u00e1lassza ki a t\u00f6rlend\u0151 mez\u0151t a jelenlegi tartom\u00e1nyban
+dialog.setlinewidth.text=Adja meg a rajzoland\u00f3 vonalak vastags\u00e1g\u00e1t a nyomvonalak sz\u00e1m\u00e1ra (1-4)
+dialog.downloadosm.desc=Nyers OSM adatok let\u00f6lt\u00e9s\u00e9nek meger\u0151s\u00edt\u00e9se a megadott ter\u00fcletre:
+dialog.searchwikipedianames.search=Keres\u00e9s erre:
+
+# 3d window
+dialog.3d.title=Prune 3D n\u00e9zet
+dialog.3d.altitudefactor=Magass\u00e1gi ny\u00fajt\u00e1si t\u00e9nyez\u0151
+dialog.3dlines.title=Prune r\u00e1csvonalak
+dialog.3dlines.empty=Nincsenek megjelen\u00edthet\u0151 r\u00e1csvonalak!
+dialog.3dlines.intro=Ezek a r\u00e1csvonalak a 3D n\u00e9zethez
+
+# Confirm messages
+confirm.loadfile=Adatok f\u00e1jlb\u00f3l bet\u00f6ltve
+confirm.save.ok1=
+confirm.save.ok2=pont f\u00e1jlba ment\u00e9se sikeres
+confirm.deletepoint.single=adatpont t\u00f6r\u00f6lve
+confirm.deletepoint.multi=adatpont t\u00f6r\u00f6lve
+confirm.point.edit=pont szerkesztve
+confirm.mergetracksegments=Nyomvonalszakaszok egyes\u00edtve
+confirm.reverserange=Tartom\u00e1ny megford\u00edtva
+confirm.addtimeoffset=Id\u0151eltol\u00e1s hozz\u00e1adva
+confirm.addaltitudeoffset=Magass\u00e1geltol\u00e1s hozz\u00e1adva
+confirm.rearrangewaypoints=\u00datpontok \u00fajrarendezve
+confirm.rearrangephotos=F\u00e9nyk\u00e9pek \u00fajrarendezve
+confirm.cutandmove=Kijel\u00f6l\u00e9s \u00e1thelyezve
+confirm.convertnamestotimes=\u00datpont nevei konvert\u00e1lva
+confirm.saveexif.ok1=Mentve
+confirm.saveexif.ok2=k\u00e9pf\u00e1jl
+confirm.undo.single=m\u0171velet visszavonva
+confirm.undo.multi=m\u0171velet visszavonva
+confirm.jpegload.single=f\u00e9nyk\u00e9p hozz\u00e1adva
+confirm.jpegload.multi=f\u00e9nyk\u00e9p hozz\u00e1adva
+confirm.media.connect=m\u00e9dium \u00f6sszekapcsolva
+confirm.photo.disconnect=f\u00e9nyk\u00e9p lev\u00e1lasztva
+confirm.audio.disconnect=hang lev\u00e1lasztva
+confirm.media.removed=elt\u00e1vol\u00edtva
+confirm.correlatephotos.single=f\u00e9nyk\u00e9p megfeleltetve
+confirm.correlatephotos.multi=f\u00e9nyk\u00e9p megfeleltetve
+confirm.createpoint=pont l\u00e9trehozva
+confirm.rotatephoto=f\u00e9nyk\u00e9p elforgatva
+confirm.running=Futtat\u00e1s...
+confirm.lookupsrtm1=
+confirm.lookupsrtm2=magass\u00e1gi \u00e9rt\u00e9k tal\u00e1lhat\u00f3
+confirm.deletefieldvalues=Mez\u0151 \u00e9rt\u00e9kei t\u00f6r\u00f6lve
+confirm.audioload=Hangf\u00e1jl hozz\u00e1adva
+confirm.correlateaudios.single=hangf\u00e1jl megfeleltetve
+confirm.correlateaudios.multi=hangf\u00e1jl megfeleltetve
+
+# Buttons
+button.ok=OK
+button.back=El\u0151z\u0151
+button.next=K\u00f6vetkez\u0151
+button.finish=K\u00e9sz
+button.cancel=M\u00e9gse
+button.overwrite=Fel\u00fcl\u00edr\u00e1s
+button.moveup=Mozgat\u00e1s feljebb
+button.movedown=Mozgat\u00e1s lejjebb
+button.showlines=Sorok megjelen\u00edt\u00e9se
+button.edit=Szerkeszt\u00e9s
+button.exit=Kil\u00e9p\u00e9s
+button.close=Bez\u00e1r\u00e1s
+button.continue=Folytat\u00e1s
+button.yes=Igen
+button.no=Nem
+button.yestoall=Igen, mindet
+button.notoall=Nem, egyiket se
+button.select=Kijel\u00f6l\u00e9s
+button.selectall=Mindent kijel\u00f6l
+button.selectnone=Kijel\u00f6l\u00e9s megsz\u00fcntet\u00e9se
+button.preview=El\u0151n\u00e9zet
+button.load=Bet\u00f6lt\u00e9s
+button.upload=Felt\u00f6lt\u00e9s
+button.guessfields=Mez\u0151k kital\u00e1l\u00e1sa
+button.showwebpage=Weboldal megjelen\u00edt\u00e9se
+button.check=Ellen\u0151rz\u00e9s
+button.resettodefaults=Vissza\u00e1ll\u00edt\u00e1s az alap\u00e9rtelmezettre
+button.browse=B\u00f6ng\u00e9sz\u00e9s...
+button.addnew=\u00daj hozz\u00e1ad\u00e1sa
+button.delete=T\u00f6rl\u00e9s
+
+# File types
+filetype.txt=TXT f\u00e1jlok
+filetype.jpeg=JPG f\u00e1jlok
+filetype.kmlkmz=KML, KMZ f\u00e1jlok
+filetype.kml=KML f\u00e1jlok
+filetype.kmz=KMZ f\u00e1jlok
+filetype.gpx=GPX f\u00e1jlok
+filetype.pov=POV f\u00e1jlok
+filetype.svg=SVG f\u00e1jlok
+filetype.audio=MP3, OGG, WAV f\u00e1jlok
+
+# Display components
+display.nodata=Nincs adat bet\u00f6ltve
+display.noaltitudes=A nyomvonal nem tartalmaz magass\u00e1gi adatot
+display.notimestamps=A nyomvonal nem tartalmaz id\u0151b\u00e9lyegeket
+details.trackdetails=Nyomvonal r\u00e9szletei
+details.notrack=Nincs adat bet\u00f6ltve
+details.track.points=Pontok
+details.track.file=F\u00e1jl
+details.track.numfiles=F\u00e1jlok sz\u00e1ma
+details.pointdetails=Pont r\u00e9szletei
+details.index.selected=Jelenlegi:
+details.index.of=\u00f6sszesen:
+details.nopointselection=Nincs pont kijel\u00f6lve
+details.photofile=F\u00e9nyk\u00e9pf\u00e1jl
+details.norangeselection=Nincs tartom\u00e1ny kijel\u00f6lve
+details.rangedetails=Tartom\u00e1ny r\u00e9szletei
+details.range.selected=Kiv\u00e1lasztva:
+details.range.to=\u00f6sszesen:
+details.altitude.to=\u00f6sszesen:
+details.range.climb=Emelked\u00e9s
+details.range.descent=Lejt\u00e9s
+details.coordformat=Koordin\u00e1ta form\u00e1tuma
+details.distanceunits=T\u00e1vols\u00e1g egys\u00e9ge
+display.range.time.secs=mp
+display.range.time.mins=p
+display.range.time.hours=\u00f3
+display.range.time.days=n
+details.range.avespeed=\u00c1tlagsebess\u00e9g
+details.range.avemovingspeed=Mozg\u00e1si \u00e1tlag
+details.range.maxspeed=Maxim\u00e1lis sebess\u00e9g
+details.range.numsegments=Szakaszok sz\u00e1ma
+details.range.pace=Iram
+details.range.gradient=Szintk\u00fcl\u00f6nbs\u00e9g
+details.lists.waypoints=\u00datpontok
+details.lists.photos=F\u00e9nyk\u00e9pek
+details.lists.audio=Hang
+details.photodetails=F\u00e9nyk\u00e9p r\u00e9szletei
+details.nophoto=Nincs f\u00e9nyk\u00e9p kiv\u00e1lasztva
+details.photo.loading=Bet\u00f6lt\u00e9s
+details.media.connected=\u00d6sszekapcsolva
+details.audiodetails=Hang r\u00e9szletei
+details.noaudio=Nincs hang kiv\u00e1lasztva
+details.audio.file=Hangf\u00e1jl
+details.audio.playing=lej\u00e1tsz\u00e1s...
+map.overzoom=Nem \u00e9rhet\u0151 el t\u00e9rk\u00e9p ezen a nagy\u00edt\u00e1si szinten
+
+# Field names
+fieldname.latitude=Sz\u00e9less\u00e9g
+fieldname.longitude=Hossz\u00fas\u00e1g
+fieldname.altitude=Magass\u00e1g
+fieldname.timestamp=Id\u00f5
+fieldname.time=Id\u0151
+fieldname.waypointname=N\u00e9v
+fieldname.waypointtype=T\u00edpus
+fieldname.newsegment=Szakasz
+fieldname.custom=Egy\u00e9ni
+fieldname.prefix=Mez\u0151
+fieldname.distance=T\u00e1vols\u00e1g
+fieldname.movingdistance=Mozg\u00e1si t\u00e1vols\u00e1g
+fieldname.duration=Id\u0151tartam
+fieldname.speed=Sebess\u00e9g
+fieldname.verticalspeed=F\u00fcgg\u0151leges sebess\u00e9g
+
+# Measurement units
+units.original=Eredeti
+units.default=Alap\u00e9rtelmezett
+units.metres=m\u00e9ter
+units.metres.short=m
+units.feet=l\u00e1b
+units.feet.short=ft
+units.kilometres=kilom\u00e9ter
+units.kilometres.short=km
+units.kmh=km/h
+units.miles=m\u00e9rf\u00f6ld
+units.miles.short=mi
+units.mph=mph
+units.metrespersec=m/s
+units.feetpersec=ft/s
+units.hours=\u00f3ra
+units.degminsec=Sz\u00f6g-sz\u00f6gperc-sz\u00f6gm\u00e1sodperc
+units.degmin=Sz\u00f6g-sz\u00f6gperc
+units.deg=Sz\u00f6g
+units.iso8601=ISO 8601
+
+# External urls
+url.googlemaps=maps.google.hu
+wikipedia.lang=hu
+
+# Cardinals for 3d plots
+cardinal.n=\u00c9
+cardinal.s=D
+cardinal.e=K
+cardinal.w=Ny
+
+# Undo operations
+undo.load=adatok bet\u00f6lt\u00e9se
+undo.loadphotos=f\u00e9nyk\u00e9pek bet\u00f6lt\u00e9se
+undo.loadaudios=hangf\u00e1jlok bet\u00f6lt\u00e9se
+undo.editpoint=pont szerkeszt\u00e9se
+undo.deletepoint=pont t\u00f6rl\u00e9se
+undo.removephoto=f\u00e9nyk\u00e9p elt\u00e1vol\u00edt\u00e1sa
+undo.removeaudio=hangf\u00e1jl elt\u00e1vol\u00edt\u00e1sa
+undo.deleterange=tartom\u00e1ny t\u00f6rl\u00e9se
+undo.compress=nyomvonal t\u00f6m\u00f6r\u00edt\u00e9se
+undo.insert=pontok besz\u00far\u00e1sa
+undo.reverse=tartom\u00e1ny megford\u00edt\u00e1sa
+undo.mergetracksegments=nyomvonalszakaszok egyes\u00edt\u00e9se
+undo.addtimeoffset=id\u0151eltol\u00e1s hozz\u00e1ad\u00e1sa
+undo.addaltitudeoffset=magass\u00e1geltol\u00e1s hozz\u00e1ad\u00e1sa
+undo.rearrangewaypoints=\u00fatpontok \u00fajrarendez\u00e9se
+undo.cutandmove=kijel\u00f6l\u00e9s mozgat\u00e1sa
+undo.connect=\u00f6sszekapcsol\u00e1s
+undo.disconnect=lev\u00e1laszt\u00e1s
+undo.correlatephotos=f\u00e9nyk\u00e9pek megfeleltet\u00e9se
+undo.rearrangephotos=f\u00e9nyk\u00e9pek \u00fajrarendez\u00e9se
+undo.createpoint=pont l\u00e9trehoz\u00e1sa
+undo.rotatephoto=f\u00e9nyk\u00e9p forgat\u00e1sa
+undo.convertnamestotimes=nevek konvert\u00e1l\u00e1sa id\u0151v\u00e9
+undo.lookupsrtm=magass\u00e1gi adatok let\u00f6lt\u00e9se SRTM-r\u0151l
+undo.deletefieldvalues=mez\u0151 \u00e9rt\u00e9keinek t\u00f6rl\u00e9se
+undo.correlateaudios=hang megfeleltet\u00e9se
+
+# Error messages
+error.save.dialogtitle=Hiba az adatok ment\u00e9sekor
+error.save.nodata=Nincs mentend\u0151 adat
+error.save.failed=Az adatok f\u00e1jlba ment\u00e9se nem siker\u00fclt
+error.saveexif.filenotfound=F\u00e9nyk\u00e9pf\u00e1jl keres\u00e9se nem siker\u00fclt
+error.saveexif.cannotoverwrite1=A(z)
+error.saveexif.cannotoverwrite2=f\u00e9nyk\u00e9pf\u00e1jl csak olvashat\u00f3, \u00e9s nem \u00edrhat\u00f3 fel\u00fcl. \u00cdrjuk m\u00e1solatba?
+error.saveexif.failed1=
+error.saveexif.failed2=k\u00e9p ment\u00e9se nem siker\u00fclt
+error.saveexif.forced1=
+error.saveexif.forced2=k\u00e9p er\u00f6ltet\u00e9st ig\u00e9nyelt
+error.load.dialogtitle=Hiba az adatok bet\u00f6lt\u00e9sekor
+error.load.noread=A f\u00e1jl nem olvashat\u00f3
+error.load.nopoints=Nem tal\u00e1lhat\u00f3 koordin\u00e1tainform\u00e1ci\u00f3 a f\u00e1jlban
+error.load.unknownxml=Ismeretlen xml form\u00e1tum:
+error.load.noxmlinzip=Nem tal\u00e1lhat\u00f3 xml f\u00e1jl a zip f\u00e1jlon bel\u00fcl
+error.load.othererror=Hiba a f\u00e1jl olvas\u00e1sa sor\u00e1n:
+error.jpegload.dialogtitle=Hiba a k\u00e9pek bet\u00f6lt\u00e9sekor
+error.jpegload.nofilesfound=Nem tal\u00e1lhat\u00f3 f\u00e1jl
+error.jpegload.nojpegsfound=Nem tal\u00e1lhat\u00f3 jpeg f\u00e1jl
+error.jpegload.nogpsfound=Nem tal\u00e1lhat\u00f3 GPS inform\u00e1ci\u00f3
+error.jpegload.exifreadfailed=Az EXIF inform\u00e1ci\u00f3 olvas\u00e1sa nem siker\u00fclt. Nem olvasat\u00f3 EXIF inform\u00e1ci\u00f3\nbe\u00e9p\u00edtett vagy k\u00fcls\u0151 f\u00fcggv\u00e9nyk\u00f6nyvt\u00e1r n\u00e9lk\u00fcl.
+error.audioload.nofilesfound=Nem tal\u00e1lhat\u00f3 hangf\u00e1jl
+error.gpsload.unknown=Ismeretlen hiba
+error.undofailed.title=A visszavon\u00e1s nem siker\u00fclt
+error.undofailed.text=A m\u0171velet visszavon\u00e1sa nem siker\u00fclt
+error.function.noop.title=A funkci\u00f3 nem eredm\u00e9nyezett v\u00e1ltoz\u00e1st
+error.rearrange.noop=A pontok \u00fajrarendez\u00e9se nem eredm\u00e9nyezett v\u00e1ltoz\u00e1st
+error.function.notavailable.title=A funkci\u00f3 nem \u00e9rhet\u0151 el
+error.function.nojava3d=Ehhez a funkci\u00f3hoz a Java3d f\u00fcggv\u00e9nyk\u00f6nyvt\u00e1r sz\u00fcks\u00e9ges,\n amely a Sun.com webhelyr\u0151l \u00e9rhet\u0151 el.
+error.3d=Hiba t\u00f6rt\u00e9nt a 3d megjelen\u00edt\u00e9ssel
+error.readme.notfound=Az olvassel f\u00e1jl nem tal\u00e1lhat\u00f3
+error.osmimage.dialogtitle=Hiba a t\u00e9rk\u00e9p bet\u00f6lt\u00e9sekor
+error.osmimage.failed=A t\u00e9rk\u00e9p bet\u00f6lt\u00e9se nem siker\u00fclt. Ellen\u0151rizze az internetkapcsolatot.
+error.language.wrongfile=\u00dagy t\u0171nik, hogy a kiv\u00e1lasztott f\u00e1jl nem egy nyelvi f\u00e1jl a Prune-hoz
+error.convertnamestotimes.nonames=A nevek nem konvert\u00e1lhat\u00f3k id\u0151adatokk\u00e1
+error.lookupsrtm.nonefound=Nem \u00e9rhet\u0151 el magass\u00e1gi \u00e9rt\u00e9k ezekhez a pontokhoz
+error.lookupsrtm.nonerequired=Az \u00f6sszes pont m\u00e1r rendelkezik magass\u00e1gadatokkal, \u00edgy nincs mit keresni
+error.gpsies.uploadnotok=A gpsies szerver a k\u00f6vetkez\u0151 \u00fczenetet adta vissza
+error.gpsies.uploadfailed=A felt\u00f6lt\u00e9s nem siker\u00fclt a k\u00f6vetkez\u0151 hib\u00e1val
+error.playaudiofailed=A hangf\u00e1jl lej\u00e1tsz\u00e1sa nem siker\u00fclt
diff --git a/tim/prune/lang/prune-texts_in.properties b/tim/prune/lang/prune-texts_in.properties
index 42e2b37..ec4bc25 100644
--- a/tim/prune/lang/prune-texts_in.properties
+++ b/tim/prune/lang/prune-texts_in.properties
@@ -17,9 +17,9 @@ menu.range.all=Pilih semua
menu.range.none=Tidak memilih
menu.photo=Foto
menu.photo.saveexif=Simpan ke Exif
-menu.photo.connect=Hubungkan ke titik
-menu.photo.disconnect=Putuskan dari titik
-menu.photo.delete=Menghapus foto
+function.connecttopoint=Hubungkan ke titik
+function.disconnectfrompoint=Putuskan dari titik
+function.removephoto=Menghapus foto
menu.view=Lihat
menu.settings=Pengaturan
menu.view.browser=Peta di browser
@@ -105,7 +105,7 @@ details.pointdetails=Rincian titik
details.nopointselection=Tidak ada titik
details.norangeselection=Tidak ada jangkauan
details.rangedetails=Rincian jangkauan
-details.waypointsphotos.photos=Foto
+details.lists.photos=Foto
details.photodetails=Rincian foto
details.nophoto=Tidak ada foto
details.photo.loading=Membuka
diff --git a/tim/prune/lang/prune-texts_it.properties b/tim/prune/lang/prune-texts_it.properties
index 6c07c73..bf19b95 100644
--- a/tim/prune/lang/prune-texts_it.properties
+++ b/tim/prune/lang/prune-texts_it.properties
@@ -1,5 +1,5 @@
# Text entries for the Prune application
-# Italian entries as extra
+# Italian entries thanks to josatoc
# Menu entries
menu.file=File
@@ -30,10 +30,8 @@ menu.point.editpoint=Edita Punto
menu.point.deletepoint=Cancella Punto
menu.photo=Foto
menu.photo.saveexif=Salva su Exif
-menu.photo.connect=Collega al punto
-menu.photo.disconnect=Scollega dal punto
-menu.photo.delete=Rimuovi foto
-menu.view=Visualizza
+menu.audio=Audio
+menu.view=Vista
menu.view.showsidebars=Mostra barre laterali
menu.view.browser=Mappa sul browser
menu.view.browser.google=Google maps
@@ -49,6 +47,7 @@ menu.map.zoomin=Zoom +
menu.map.zoomout=Zoom -
menu.map.zoomfull=Zoom tutto
menu.map.newpoint=Crea nuovo punto
+menu.map.drawpoints=Crea serie di punti
menu.map.connect=Aggancia ai punti
menu.map.autopan=Autopan
menu.map.showmap=Mostra sulla mappa
@@ -61,6 +60,7 @@ altkey.menu.range=S
altkey.menu.point=P
altkey.menu.view=V
altkey.menu.photo=O
+altkey.menu.audio=U
altkey.menu.settings=R
altkey.menu.help=A
@@ -99,14 +99,27 @@ function.setpaths=Configura percorsi programmi
function.getgpsies=Ottieni traccie da Gpsies
function.uploadgpsies=Carica traccia su Gpsies
function.lookupsrtm=Ottieni quote da SRTM
+function.getwikipedia=Ottieni informazioni da Wikipedia
+function.searchwikipedianames=Cerca il nome in Wikipedia
+function.downloadosm=Scarica dati OSM dell'area
function.duplicatepoint=Duplica punto corrente in coda
function.setcolours=Scegli colori
+function.setlinewidth=Scegli la lo spessore
function.setlanguage=Scegli la lingua
+function.connecttopoint=Collega al punto
+function.disconnectfrompoint=Scollega dal punto
+function.removephoto=Rimuovi foto
function.correlatephotos=Correla le foto
function.rearrangephotos=Riordina foto
function.rotatephotoleft=Ruota foto a sinistra
function.rotatephotoright=Ruota foto a destra
+function.photopopup=Mostra la foto in un riquadro
function.ignoreexifthumb=Ignora anteprima foto exif
+function.loadaudio=Aggiungi ripresa audio
+function.removeaudio=Rimuovi ripresa audio
+function.correlateaudios=Correla ripresa audio
+function.playaudio=Riproduci ripresa audio
+function.stopaudio=Ferma ripresa audio
function.help=Aiuto
function.showkeys=Visualizza tasti scelta rapida
function.about=Informazioni su Prune
@@ -193,6 +206,7 @@ dialog.pointtype.desc=Salva i tipi di punti seguenti:
dialog.pointtype.track=Punti traccia
dialog.pointtype.waypoint=Waypoints
dialog.pointtype.photo=Punti foto
+dialog.pointtype.audio=Punti audio
dialog.pointtype.selection=Solo la selezione
dialog.confirmreversetrack.title=Conferma l'inversione
dialog.confirmreversetrack.text=Questa traccia contiene informazioni sull'orario di scatto che possono essere messe fuori sequenza dopo l'inversione.\nSei sicuro di voler invertire questa sezione?
@@ -278,12 +292,14 @@ dialog.gpsies.activity.motorbiking=Motocicletta
dialog.gpsies.activity.snowshoe=Trekking sulla neve
dialog.gpsies.activity.sailing=Navigazione
dialog.gpsies.activity.skating=Pattinaggio
+dialog.wikipedia.column.name=Titolo articolo
+dialog.wikipedia.column.distance=Distanza
dialog.correlate.notimestamps=Non ci sono informazioni temporali tra i dati dei punti, non c'\u00e8 niente per collegarli con le foto.
dialog.correlate.nouncorrelatedphotos=Non ci sono foto non correlate.\nSei sicuro di voler continuare?
dialog.correlate.photoselect.intro=Selezione una delle foto correlate da usare come scarto dell'orario
-dialog.correlate.photoselect.photoname=Nome della foto
-dialog.correlate.photoselect.timediff=Differenza di orario
-dialog.correlate.photoselect.photolater=Foto scattata dopo il punto
+dialog.correlate.select.photoname=Nome della foto
+dialog.correlate.select.timediff=Differenza di orario
+dialog.correlate.select.photolater=Foto scattata dopo il punto
dialog.correlate.options.tip=Consiglio: Con il collegamento manuale di almeno una foto, lo scarto di orario viene calcolato per te
dialog.correlate.options.intro=Selezione le opzioni per la correlazione automatica
dialog.correlate.options.offsetpanel=Scarto di orario
@@ -292,7 +308,9 @@ dialog.correlate.options.offset.hours=ore,
dialog.correlate.options.offset.minutes=minuti e
dialog.correlate.options.offset.seconds=secondi
dialog.correlate.options.photolater=Foto scattata dopo il punto
-dialog.correlate.options.pointlater=Punto successivo allo scatto della foto
+dialog.correlate.options.pointlaterphoto=Punto successivo allo scatto della foto
+dialog.correlate.options.audiolater=Ripresa audio dopo il punto
+dialog.correlate.options.pointlateraudio=Punto successivo alla ripresa audio
dialog.correlate.options.limitspanel=Limiti di correlamento
dialog.correlate.options.notimelimit=Nessun limite di tempo
dialog.correlate.options.timelimit=Limite di tempo
@@ -300,6 +318,15 @@ dialog.correlate.options.nodistancelimit=Nessun limite di distanza
dialog.correlate.options.distancelimit=Distanza limite
dialog.correlate.options.correlate=Correlate
dialog.correlate.alloutsiderange=Tutte le foto sono fuori dall'orario della traccia, e nessuna pu\u00f2 essere correlata.\nProva a cambiare lo scarto o correla manualmente almeno una foto.
+dialog.correlate.filetimes=I dati temporali mostrano:
+dialog.correlate.filetimes2=della ripresa audio
+dialog.correlate.correltimes=Per la correlazione usa:
+dialog.correlate.timestamp.beginning=Inizio
+dialog.correlate.timestamp.middle=Met\u00e0
+dialog.correlate.timestamp.end=Fine
+dialog.correlate.audioselect.intro=Seleziona una di queste riprese audio correlate come scarto temporale
+dialog.correlate.select.audioname=Nome ripresa audio
+dialog.correlate.select.audiolater=Ripresa audio successiva
dialog.rearrangephotos.desc=Seleziona la destinazione e l'ordine dei punti foto
dialog.rearrangephotos.tostart=Sposta all'inizio
dialog.rearrangephotos.toend=Sposta alla fine
@@ -380,6 +407,7 @@ dialog.saveconfig.prune.diskcache=Cache delle mappe
dialog.saveconfig.prune.kmzimagewidth=larghezza immagine KMZ
dialog.saveconfig.prune.kmzimageheight=altezza immagine KMZ
dialog.saveconfig.prune.colourscheme=Schema colori
+dialog.saveconfig.prune.linewidth=Spessore linea
dialog.saveconfig.prune.kmltrackcolour=Colore della traccia KML
dialog.setpaths.intro=Se necessario, puoi indicare il percorso delle applicazioni esterne:
dialog.setpaths.found=trovato?
@@ -409,10 +437,12 @@ dialog.diskcache.dir=Cartella della cache
dialog.diskcache.createdir=Crea cartella
dialog.diskcache.nocreate=Cartella della cache non creata
dialog.deletefieldvalues.intro=Selezione il campo da cancellare dall'intervallo corrente
+dialog.setlinewidth.text=Specifica il tratteggio delle linee per disegnare la traccia (1-4)
+dialog.downloadosm.desc=Conferma lo scarico dei dati raw OSM per l'area specificata:
+dialog.searchwikipedianames.search=Cerca per:
# 3d window
dialog.3d.title=Visione Prune in 3D
-dialog.3d.altitudecap=Intervallo altitudine minimo
dialog.3d.altitudefactor=Fattore di moltiplicazione della quota
dialog.3dlines.title=Griglia di Prune
dialog.3dlines.empty=Nessuna griglia mostrata!
@@ -439,16 +469,21 @@ confirm.undo.single=operazione annullate
confirm.undo.multi=operazioni annullate
confirm.jpegload.single=foto \u00e8 stata aggiunta
confirm.jpegload.multi=foto sono state aggiunte
-confirm.photo.connect=foto collegata
+confirm.media.connect=media collegata
confirm.photo.disconnect=foto scollegata
-confirm.correlate.single=foto era correlata
-confirm.correlate.multi=foto erano correlate
+confirm.audio.disconnect=ripresa audio scollegata
+confirm.media.removed=rimosso
+confirm.correlatephotos.single=foto era correlata
+confirm.correlatephotos.multi=foto erano correlate
confirm.createpoint=punto creato
confirm.rotatephoto=foto ruotata
confirm.running=Operazione in corso...
confirm.lookupsrtm1=Trovato
confirm.lookupsrtm2=valori di quota
confirm.deletefieldvalues=Valori del campo cancellati
+confirm.audioload=Ripresa audio aggiunta
+confirm.correlateaudios.single=la ripresa audio era correlata
+confirm.correlateaudios.multi=le riprese audio erano correlate
# Buttons
button.ok=OK
@@ -491,6 +526,7 @@ filetype.kmz=File KMZ
filetype.gpx=File GPX
filetype.pov=File POV
filetype.svg=File SVG
+filetype.audio=File MP3, OGG, WAV
# Display components
display.nodata=Nessun dato caricato
@@ -525,12 +561,17 @@ details.range.maxspeed=Velocit\u00e0 massima
details.range.numsegments=Numero di segmenti
details.range.pace=Passo
details.range.gradient=Gradiente
-details.waypointsphotos.waypoints=Waypoint
-details.waypointsphotos.photos=Foto
+details.lists.waypoints=Waypoint
+details.lists.photos=Foto
+details.lists.audio=Ripresa audio
details.photodetails=Dettagli foto
details.nophoto=Nessuna foto selezionata
details.photo.loading=Caricamento
-details.photo.connected=Collegata
+details.media.connected=Collegata
+details.audiodetails=Dettagli ripresa audio
+details.noaudio=Nessuna ripresa audio selezionata
+details.audio.file=Ripresa audio
+details.audio.playing=Riproduzione...
map.overzoom=Mappa non disponibile a questo livello di zoom
# Field names
@@ -573,6 +614,7 @@ units.iso8601=ISO 8601
# External urls
url.googlemaps=maps.google.it
+wikipedia.lang=it
# Cardinals for 3d plots
cardinal.n=N
@@ -583,9 +625,11 @@ cardinal.w=O
# Undo operations
undo.load=carica dati
undo.loadphotos=carica foto
+undo.loadaudios=carica riprese audio
undo.editpoint=edita punto
undo.deletepoint=cancella punto
-undo.deletephoto=rimuovi foto
+undo.removephoto=rimuovi foto
+undo.removeaudio=rimuovi riprese audio
undo.deleterange=cancella l'intervallo
undo.compress=comprimi traccia
undo.insert=inserisci punti
@@ -595,15 +639,16 @@ undo.addtimeoffset=aggiungi scarto temporale
undo.addaltitudeoffset=aggiungi scarto altitudine
undo.rearrangewaypoints=riorganizza waypoint
undo.cutandmove=muovi selezione
-undo.connectphoto=collega foto
-undo.disconnectphoto=scollega foto
-undo.correlate=correla foto
+undo.connect=collega
+undo.disconnect=scollega
+undo.correlatephotos=correla foto
undo.rearrangephotos=riorganizza foto
undo.createpoint=crea punto
undo.rotatephoto=ruota foto
undo.convertnamestotimes=converti nomi in orari
undo.lookupsrtm=cerca quote in SRTM
undo.deletefieldvalues=cancellare i valori del campo
+undo.correlateaudios=correla riprese audio
# Error messages
error.save.dialogtitle=Errore nel salvataggio dati
@@ -625,9 +670,9 @@ error.load.othererror=Errore nella lettura del file:
error.jpegload.dialogtitle=Errore nel caricamento delle foto
error.jpegload.nofilesfound=File non trovato
error.jpegload.nojpegsfound=File jpeg non trovato
-error.jpegload.noexiffound=Informazioni EXIF non trovate
error.jpegload.nogpsfound=Informazioni GPS non trovate
error.jpegload.exifreadfailed=Lettera dei dati EXIF fallita. I dati EXIF non possono\n essere letti senza una libreria interna o esterna.
+error.audioload.nofilesfound=Riprese audio non trovate
error.gpsload.unknown=Errore sconosciuto
error.undofailed.title=Impossibile annullare
error.undofailed.text=Impossibile annullare l'operazione
@@ -645,3 +690,4 @@ error.lookupsrtm.nonefound=Valori di quota non trovati
error.lookupsrtm.nonerequired=Tutti i punti hanno gi\u00e0 una quota, non c'\u00e8 niente da cercare
error.gpsies.uploadnotok=Il server Gpsies ha riportato il messaggio
error.gpsies.uploadfailed=Il caricamento \u00e8 fallito con l'errore
+error.playaudiofailed=Ripresa audio non riprodotta
diff --git a/tim/prune/lang/prune-texts_ja.properties b/tim/prune/lang/prune-texts_ja.properties
index 0c0d5eb..c6b1653 100644
--- a/tim/prune/lang/prune-texts_ja.properties
+++ b/tim/prune/lang/prune-texts_ja.properties
@@ -30,9 +30,9 @@ menu.range.start=\u958b\u59cb\u70b9\u3092\u7f6e\u304f
menu.range.end=\u7d42\u4e86\u70b9\u3092\u7f6e\u304f
menu.photo=\u5199\u771f
menu.photo.saveexif=Exif\u306b\u4fdd\u5b58
-menu.photo.connect=\u70b9\u306b\u63a5\u7d9a
-menu.photo.disconnect=\u70b9\u304b\u3089\u63a5\u7d9a\u89e3\u9664
-menu.photo.delete=\u5199\u771f\u3092\u53d6\u308a\u9664\u304f
+function.connecttopoint=\u70b9\u306b\u63a5\u7d9a
+function.disconnectfrompoint=\u70b9\u304b\u3089\u63a5\u7d9a\u89e3\u9664
+function.removephoto=\u5199\u771f\u3092\u53d6\u308a\u9664\u304f
menu.view=\u30d3\u30e5\u30fc
menu.view.browser=\u5730\u56f3\u3092\u30d6\u30e9\u30a6\u30b6\u30fc\u3067\u898b\u308b
menu.view.browser.google=Google \u30de\u30c3\u30d7
@@ -240,9 +240,9 @@ dialog.gpsies.activity.skating=\u30d5\u30a3\u30ae\u30e5\u30a2\u30b9\u30b1\u30fc\
dialog.correlate.notimestamps=\u30c7\u30fc\u30bf\u30dd\u30a4\u30f3\u30c8\u306b\u306f\u30bf\u30a4\u30e0\u30b9\u30bf\u30f3\u30d7\u304c\u306a\u3044\u306e\u3067\u3001\u5199\u771f\u3092\u95a2\u9023\u4ed8\u3051\u3089\u308c\u308b\u7269\u304c\u3042\u308a\u307e\u305b\u3093\u3002
dialog.correlate.nouncorrelatedphotos=\u95a2\u9023\u4ed8\u3051\u3089\u308c\u306a\u304b\u3063\u305f\u5199\u771f\u306f\u3042\u308a\u307e\u305b\u3093\u3002\n\u7d9a\u3051\u307e\u3059\u304b\uff1f
dialog.correlate.photoselect.intro=\u6642\u9593\u504f\u4f4d\u3092\u4f5c\u308b\u305f\u3081\u306e\u5199\u771f\u3092\u4e00\u3064\u9078\u3093\u3067\u304f\u3060\u3055\u3044\u3002
-dialog.correlate.photoselect.photoname=\u5199\u771f\u540d
-dialog.correlate.photoselect.timediff=\u6642\u9593\u5dee
-dialog.correlate.photoselect.photolater=\u5199\u771f\u304c\u5f8c
+dialog.correlate.select.photoname=\u5199\u771f\u540d
+dialog.correlate.select.timediff=\u6642\u9593\u5dee
+dialog.correlate.select.photolater=\u5199\u771f\u304c\u5f8c
dialog.correlate.options.tip=\u63d0\u793a\uff1a\u5c11\u306a\u304f\u3068\u3082\u4e00\u3064\u306e\u5199\u771f\u3092\u624b\u52d5\u3067\u95a2\u9023\u4ed8\u3051\u308b\u3068\u3001\u6642\u9593\u504f\u4f4d\u3092\u8a08\u7b97\u3059\u308b\u4e8b\u304c\u3067\u304d\u307e\u3059\u3002
dialog.correlate.options.intro=\u81ea\u52d5\u95a2\u9023\u4ed8\u3051\u30aa\u30d7\u30b7\u30e7\u30f3\u3092\u9078\u629e\u3057\u3066\u304f\u3060\u3055\u3044\u3002
dialog.correlate.options.offsetpanel=\u6642\u9593\u504f\u4f4d
@@ -251,7 +251,7 @@ dialog.correlate.options.offset.hours=\u6642\u9593
dialog.correlate.options.offset.minutes=\u5206
dialog.correlate.options.offset.seconds=\u79d2
dialog.correlate.options.photolater=\u3053\u306e\u70b9\u3088\u308a\u5f8c\u308d\u306e\u5199\u771f
-dialog.correlate.options.pointlater=\u5199\u771f\u3088\u308a\u5f8c\u308d\u306e\u70b9
+dialog.correlate.options.pointlaterphoto=\u5199\u771f\u3088\u308a\u5f8c\u308d\u306e\u70b9
dialog.correlate.options.limitspanel=\u95a2\u9023\u4ed8\u3051\u5236\u9650
dialog.correlate.options.notimelimit=\u6642\u9593\u5236\u9650\u306a\u3057
dialog.correlate.options.timelimit=\u6642\u9593\u5236\u9650
@@ -356,7 +356,6 @@ dialog.setlanguage.endmessage=\u8a2d\u5b9a\u3092\u4fdd\u5b58\u3057\u3001\u8a00\u
# 3d window
dialog.3d.title=Prune 3D \u8868\u793a
-dialog.3d.altitudecap=\u6700\u4f4e\u9ad8\u5ea6\u7bc4\u56f2
dialog.3dlines.title=Prune \u683c\u5b50\u7dda
dialog.3dlines.empty=\u683c\u5b50\u7dda\u304c\u8868\u793a\u3055\u308c\u307e\u305b\u3093
dialog.3dlines.intro=\u3053\u308c\u3089\u304c 3D \u8868\u793a\u7528\u306e\u683c\u5b50\u7dda\u3067\u3059\u3002
@@ -382,10 +381,9 @@ confirm.undo.single=\u64cd\u4f5c\u306f\u30a2\u30f3\u30c9\u30a5\u3055\u308c\u305f
confirm.undo.multi=\u64cd\u4f5c\u306f\u30a2\u30f3\u30c9\u30a5\u3055\u308c\u305f
confirm.jpegload.single=\u5199\u771f\u304c\u52a0\u3048\u3089\u308c\u305f
confirm.jpegload.multi=\u5199\u771f\u304c\u52a0\u3048\u3089\u308c\u305f
-confirm.photo.connect=\u5199\u771f\u304c\u63a5\u7d9a\u3055\u308c\u305f
confirm.photo.disconnect=\u5199\u771f\u304c\u63a5\u7d9a\u3055\u308c\u305f
-confirm.correlate.single=\u5199\u771f\u304c\u95a2\u9023\u4ed8\u3051\u3089\u308c\u305f
-confirm.correlate.multi=\u5199\u771f\u304c\u95a2\u9023\u4ed8\u3051\u3089\u308c\u305f
+confirm.correlatephotos.single=\u5199\u771f\u304c\u95a2\u9023\u4ed8\u3051\u3089\u308c\u305f
+confirm.correlatephotos.multi=\u5199\u771f\u304c\u95a2\u9023\u4ed8\u3051\u3089\u308c\u305f
confirm.createpoint=\u70b9\u304c\u4f5c\u3089\u308c\u305f
confirm.rotatephoto=\u5199\u771f\u3092\u56de\u8ee2\u3057\u305f
confirm.running=\u5b9f\u884c\u4e2d...
@@ -460,12 +458,12 @@ details.range.avemovingspeed=\u5e73\u5747\u79fb\u52d5
details.range.numsegments=\u30bb\u30b0\u30e1\u30f3\u30c8\u6570
details.range.pace=\u30da\u30fc\u30b9
details.range.gradient=\u52fe\u914d
-details.waypointsphotos.waypoints=\u30a6\u30a7\u30a4\u30dd\u30a4\u30f3\u30c8
-details.waypointsphotos.photos=\u5199\u771f
+details.lists.waypoints=\u30a6\u30a7\u30a4\u30dd\u30a4\u30f3\u30c8
+details.lists.photos=\u5199\u771f
details.photodetails=\u5199\u771f\u8a73\u7d30
details.nophoto=\u5199\u771f\u304c\u9078\u629e\u3055\u308c\u3066\u3044\u307e\u305b\u3093
details.photo.loading=\u8aad\u307f\u8fbc\u307f\u4e2d
-details.photo.connected=\u63a5\u7d9a\u6e08
+details.media.connected=\u63a5\u7d9a\u6e08
map.overzoom=\u3053\u306e\u30ba\u30fc\u30e0\u30ec\u30d9\u30eb\u3067\u306f\u5730\u56f3\u304c\u5165\u624b\u3067\u304d\u307e\u305b\u3093\u3002
# Field names
@@ -508,6 +506,7 @@ units.iso8601=ISO 8601
# External urls
url.googlemaps=maps.google.co.jp
+wikipedia.lang=ja
# Cardinals for 3d plots
cardinal.n=N
@@ -520,7 +519,7 @@ undo.load=\u30c7\u30fc\u30bf\u3092\u8aad\u307f\u8fbc\u307f
undo.loadphotos=\u5199\u771f\u306e\u8aad\u307f\u8fbc\u307f
undo.editpoint=\u70b9\u306e\u7de8\u96c6
undo.deletepoint=\u70b9\u306e\u524a\u9664
-undo.deletephoto=\u5199\u771f\u306e\u53d6\u308a\u9664\u304d
+undo.removephoto=\u5199\u771f\u306e\u53d6\u308a\u9664\u304d
undo.deleterange=\u7bc4\u56f2\u306e\u524a\u9664
undo.compress=\u30c8\u30e9\u30c3\u30af\u306e\u5727\u7e2e
undo.insert=\u70b9\u306e\u633f\u5165
@@ -530,9 +529,9 @@ undo.addtimeoffset=\u6642\u9593\u504f\u4f4d\u3092\u52a0\u3048\u308b
undo.addaltitudeoffset=\u9ad8\u5ea6\u504f\u4f4d\u3092\u52a0\u3048\u308b
undo.rearrangewaypoints=\u30a6\u30a7\u30a4\u30dd\u30a4\u30f3\u30c8\u3092\u633f\u5165
undo.cutandmove=\u30bb\u30af\u30b7\u30e7\u30f3\u306e\u79fb\u52d5
-undo.connectphoto=\u5199\u771f\u306e\u63a5\u7d9a
-undo.disconnectphoto=\u5199\u771f\u306e\u63a5\u7d9a\u89e3\u9664
-undo.correlate=\u5199\u771f\u306e\u95a2\u9023\u4ed8\u3051
+undo.connect=\u5199\u771f\u306e\u63a5\u7d9a
+undo.disconnect=\u5199\u771f\u306e\u63a5\u7d9a\u89e3\u9664
+undo.correlatephotos=\u5199\u771f\u306e\u95a2\u9023\u4ed8\u3051
undo.rearrangephotos=\u5199\u771f\u306e\u4e26\u3079\u66ff\u3048
undo.createpoint=\u70b9\u306e\u4f5c\u6210
undo.rotatephoto=\u5199\u771f\u306e\u56de\u8ee2
@@ -558,7 +557,6 @@ error.load.othererror=\u30d5\u30a1\u30a4\u30eb\u3092\u8aad\u307f\u8fbc\u307f\u30
error.jpegload.dialogtitle=\u5199\u771f\u306e\u8aad\u307f\u8fbc\u307f\u30a8\u30e9\u30fc:
error.jpegload.nofilesfound=\u30d5\u30a1\u30a4\u30eb\u304c\u898b\u3064\u304b\u308a\u307e\u305b\u3093
error.jpegload.nojpegsfound=Jpeg\u30d5\u30a1\u30a4\u30eb\u304c\u898b\u3064\u304b\u308a\u307e\u305b\u3093
-error.jpegload.noexiffound=EXIF\u60c5\u5831\u304c\u898b\u3064\u304b\u308a\u307e\u305b\u3093
error.jpegload.nogpsfound=GPS\u60c5\u5831\u304c\u898b\u3064\u304b\u308a\u307e\u305b\u3093
error.gpsload.unknown=\u4e0d\u660e\u306a\u30a8\u30e9\u30fc
error.undofailed.title=\u30a2\u30f3\u30c9\u30a5\u5931\u6557
diff --git a/tim/prune/lang/prune-texts_ko.properties b/tim/prune/lang/prune-texts_ko.properties
new file mode 100644
index 0000000..eb4ef92
--- /dev/null
+++ b/tim/prune/lang/prune-texts_ko.properties
@@ -0,0 +1,693 @@
+# Text entries for the Prune application
+# Korean entries thanks to HooAU
+
+# Menu entries
+menu.file=\ud30c\uc77c
+menu.file.addphotos=\uc0ac\uc9c4 \ucd94\uac00\ud558\uae30
+menu.file.save=\ud0dd\uc2a4\ud2b8\ub85c \uc800\uc7a5\ud558\uae30
+menu.file.exit=\uc885\ub8cc
+menu.track=\ud2b8\ub799
+menu.track.undo=\uc2e4\ud589\ucde8\uc18c
+menu.track.clearundo=\uc2e4\ud589\ucde8\uc18c \ubaa9\ub85d \uc0ad\uc81c
+menu.track.deletemarked=\ud45c\uc2dc\ub41c \uc9c0\uc810 \uc9c0\uc6b0\uae30
+menu.track.rearrange=\uacbd\uc720\uc9c0 \uc7ac\uc815\ub82c
+menu.track.rearrange.start=\uc2dc\uc791 \uc9c0\uc810\uc73c\ub85c \uc774\ub3d9
+menu.track.rearrange.end=\ub05d \uc9c0\uc810\uc73c\ub85c \uc774\ub3d9
+menu.track.rearrange.nearest=\uac00\uae4c\uc6b4 \ud2b8\ub799\uc9c0\uc810\uc73c\ub85c \uc774\ub3d9
+menu.range=\uc5f0\uacb0\uc120
+menu.range.all=\ubaa8\ub450 \uc120\ud0dd
+menu.range.none=\uc120\ud0dd\ud558\uc9c0 \uc54a\uae30
+menu.range.start=\uc2dc\uc791 \uc9c0\uc810\uc73c\ub85c \uc9c0\uc815
+menu.range.end=\ub05d\uc9c0\uc810\uc73c\ub85c \uc9c0\uc815
+menu.range.deleterange=\uc5f0\uacb0\uc120 \uc0ad\uc81c
+menu.range.interpolate=\uc911\uac04\uc5d0 \ub123\uae30
+menu.range.average=\ud3c9\uade0\uc9c0\uc810\uc120\ud0dd
+menu.range.reverse=\ucc98\uc74c\uacfc \ub05d \ubc14\uafb8\uae30
+menu.range.mergetracksegments=\ud2b8\ub799 \ubd80\ubd84 \ubcd1\ud569
+menu.range.cutandmove=\uc790\ub974\uace0 \uc62e\uae30\uae30
+menu.point=\uc9c0\uc810
+menu.point.editpoint=\uc9c0\uc810 \uc218\uc815
+menu.point.deletepoint=\uc9c0\uc810 \uc0ad\uc81c
+menu.photo=\uc0ac\uc9c4
+menu.photo.saveexif=Exif\ub85c \uc800\uc7a5
+menu.audio=\uc18c\ub9ac
+menu.view=\ubcf4\uae30
+menu.view.showsidebars=\uc0ac\uc774\ub4dc\ubc14 \ubcf4\uae30
+menu.view.browser=\uc6f9\ube0c\ub77c\uc6b0\uc800\ub85c \uc9c0\ub3c4\ubcf4\uae30
+menu.view.browser.google=\uad6c\uae00 \uc9c0\ub3c4
+menu.view.browser.openstreetmap=\uc624\ud508\uc2a4\ud2b8\ub9ac\ud2b8\ub9f5
+menu.view.browser.mapquest=\ub9f5\ud018\uc2a4\ud2b8
+menu.view.browser.yahoo=\uc57c\ud6c4 \uc9c0\ub3c4
+menu.view.browser.bing=\ube59 \uc9c0\ub3c4
+menu.settings=\uc124\uc815
+menu.settings.onlinemode=\uc778\ud130\ub137\uc5d0\uc11c \uc9c0\ub3c4 \ubd88\ub7ec\uc624\uae30
+menu.help=\ub3c4\uc6c0\ub9d0
+# Popup menu for map
+menu.map.zoomin=\ud655\ub300
+menu.map.zoomout=\ucd95\uc18c
+menu.map.zoomfull=\uc804\uccb4\ud06c\uae30 \ubcf4\uae30
+menu.map.newpoint=\uc0c8 \uc9c0\uc810 \uc0dd\uc131
+menu.map.drawpoints=\uc0c8 \uc9c0\uc810\ub4e4 \uc0dd\uc131
+menu.map.connect=\ud2b8\ub809 \uc9c0\uc810 \uc5f0\uacb0\ud558\uae30
+menu.map.autopan=\uc790\ub3d9 \uc2dc\uc810 \ucd94\uc801
+menu.map.showmap=\uc9c0\ub3c4\ubcf4\uae30
+menu.map.showscalebar=\ucd95\uc801 \uc870\uc808\ubc14 \ubcf4\uae30
+
+# Alt keys for menus
+altkey.menu.file=F
+altkey.menu.track=F
+altkey.menu.range=R
+altkey.menu.point=P
+altkey.menu.view=V
+altkey.menu.photo=O
+altkey.menu.audio=A
+altkey.menu.settings=S
+altkey.menu.help=H
+
+# Ctrl shortcuts for menu items
+shortcut.menu.file.open=O
+shortcut.menu.file.load=L
+shortcut.menu.file.save=S
+shortcut.menu.track.undo=Z
+shortcut.menu.edit.compress=C
+shortcut.menu.range.all=A
+shortcut.menu.help.help=H
+
+# Functions
+function.open=\ud30c\uc77c \uc5f4\uae30
+function.loadfromgps=GPS\uc5d0\uc11c \uc790\ub8cc \uac00\uc838\uc624\uae30
+function.sendtogps=GPS\ub85c \uc790\ub8cc \ubcf4\ub0b4\uae30
+function.exportkml=KML \ub0b4\ubcf4\ub0b4\uae30
+function.exportgpx=GPX \ub0b4\ubcf4\ub0b4\uae30
+function.exportpov=POV \ub0b4\ubcf4\ub0b4\uae30
+function.exportsvg=SVG \ub0b4\ubcf4\ub0b4\uae30
+function.editwaypointname=\uacbd\uc720\uc9c0 \uc774\ub984 \uc218\uc815
+function.compress=\uacbd\ub85c \uc555\ucd95\ud558\uae30
+function.addtimeoffset=\uc624\ud504\uc14b \uc2dc\uac04 \ucd94\uac00
+function.addaltitudeoffset=\uc624\ud504\uc14b \uace0\ub3c4 \ucd94\uac00
+function.convertnamestotimes=\uacbd\uc720\uc9c0 \uc774\ub984\uc744 \uc2dc\uac04\uc73c\ub85c \ubcc0\ud658
+function.deletefieldvalues=\ud544\ub4dc\uac12 \uc0ad\uc81c
+function.findwaypoint=\uacbd\uc720\uc9c0 \ucc3e\uae30
+function.pastecoordinates=\uc0c8 \uc88c\ud45c \ub123\uae30
+function.charts=\ucc28\ud2b8
+function.show3d=3\ucc28\uc6d0 \ubcf4\uae30
+function.distances=\uac70\ub9ac
+function.fullrangedetails=\uc5f0\uacb0\uc120 \uc0c1\uc138 \uc815\ubcf4 \ubcf4\uae30
+function.setmapbg=\ubc30\uacbd \uc9c0\ub3c4 \uc9c0\uc815
+function.setkmzimagesize=KMZ \uadf8\ub9bc \ud06c\uae30 \uc9c0\uc815
+function.setpaths=\uc678\ubd80\ud504\ub85c\uadf8\ub7a8 \uc9c0\uc815
+function.getgpsies=gpsies\uc5d0\uc11c \ud2b8\ub799\ubaa9\ub85d \uc5bb\uae30
+function.uploadgpsies=gpsies\ub85c \ud2b8\ub799 \uc62c\ub9ac\uae30
+function.lookupsrtm=SRTM\uc5d0\uc11c \uace0\ub3c4 \ucc3e\uae30
+function.getwikipedia=\uc704\ud0a4\ud53c\ub514\uc544\uc5d0\uc11c \uadfc\ucc98 \uc815\ubcf4 \ucc3e\uae30
+function.searchwikipedianames=\uc774\ub984\uc73c\ub85c \uc704\ud0a4\ud53c\ub514\uc544 \uac80\uc0c9
+function.downloadosm=OSM \ub370\uc774\ud0c0 \ub2e4\uc6b4\ub85c\ub4dc\ud558\uae30
+function.duplicatepoint=\uc9c0\uc810 \ubcf5\uc0ac\ud558\uae30
+function.setcolours=\uc0c9\uc0c1 \uc9c0\uc815
+function.setlinewidth=\uc120 \ub113\uc774 \uc9c0\uc815
+function.setlanguage=\uc5b8\uc5b4 \uc9c0\uc815
+function.connecttopoint=\uc9c0\uc810\uc73c\ub85c \uc5f0\uacb0
+function.disconnectfrompoint=\uc9c0\uc810\uc5d0\uc11c \uc5f0\uacb0 \ub04a\uae30
+function.removephoto=\ub9ac\uc2a4\ud2b8\uc5d0\uc11c \uc0ac\uc9c4 \uc9c0\uc6b0\uae30
+function.correlatephotos=\uc2dc\uac04\uc815\ubcf4\ub85c \uc0ac\uc9c4 \uc5f0\uacb0\ud558\uae30
+function.rearrangephotos=\uc0ac\uc9c4 \uc7ac\ubc30\uc5f4\ud558\uae30
+function.rotatephotoleft=\uc67c\ucabd\uc73c\ub85c \uc0ac\uc9c4 \ud68c\uc804
+function.rotatephotoright=\uc624\ub978\ucabd\uc73c\ub85c \uc0ac\uc9c4 \ud68c\uc804
+function.photopopup=\ud31d\uc5c5 \uc0ac\uc9c4 \ubcf4\uae30
+function.ignoreexifthumb=exif \uc378\ub124\uc77c \ubb34\uc2dc\ud558\uae30
+function.loadaudio=\uc18c\ub9ac\ud30c\uc77c \ucd94\uac00\ud558\uae30
+function.removeaudio=\ub9ac\uc2a4\ud2b8\uc5d0\uc11c \uc18c\ub9ac\ud30c\uc77c \uc9c0\uc6b0\uae30
+function.correlateaudios=\uc2dc\uac04\uc815\ubcf4\ub85c \uc18c\ub9ac\ud30c\uc77c \uc5f0\uacb0\ud558\uae30
+function.playaudio=\uc18c\ub9ac\ud30c\uc77c \uc7ac\uc0dd
+function.stopaudio=\uc18c\ub9ac\ud30c\uc77c \uba48\ucda4
+function.help=\ub3c4\uc6c0\ub9d0
+function.showkeys=\ub2e8\ucd95\ud0a4 \ubcf4\uae30
+function.about=Prune \uc815\ubcf4
+function.checkversion=\uc0c8\ubc84\uc804\uc774 \uc788\ub294\uc9c0 \uac80\uc0ac
+function.saveconfig=\uc124\uc815 \uc800\uc7a5\ud558\uae30
+function.diskcache=\ub514\uc2a4\ud06c\uc5d0 \ub9f5 \uc800\uc7a5
+
+# Dialogs
+dialog.exit.confirm.title=Prune \uc885\ub8cc
+dialog.exit.confirm.text=\ub370\uc774\ud0c0\uac00 \uc800\uc7a5\ub418\uc9c0 \uc54a\uc558\uc2b5\ub2c8\ub2e4. \uadf8\ub798\ub3c4 \ub098\uac00\uc2dc\uac8c\uc2b5\ub2c8\uae4c?
+dialog.openappend.title=\ub370\uc774\ud130 \ucd94\uac00\ud558\uae30
+dialog.openappend.text=\uc774\uc804\uc5d0 \ubd88\ub7ec\uc628 \ub370\uc774\ud0c0\ub85c \ucd94\uac00\ud558\uae30\uaca0\uc2b5\ub2c8\uae4c?
+dialog.deletepoint.title=\uc9c0\uc810 \uc0ad\uc81c
+dialog.deletepoint.deletephoto=\uc9c0\uc810\uc73c\ub85c \ucca8\ubd80\ub41c \uc0ac\uc9c4\uc744 \uc9c0\uc6b0\uae30\uaca0\uc2b5\ub2c8\uae4c?
+dialog.deletephoto.title=\uc0ac\uc9c4 \uc0ad\uc81c
+dialog.deletephoto.deletepoint=\uc0ac\uc9c4\uc5d0 \ucca8\ubd80\ub41c \uc9c0\uc810\uc744 \uc9c0\uc6b0\uc2dc\uaca0\uc2b5\ub2c8\uae4c?
+dialog.openoptions.title=\uc124\uc815
+dialog.openoptions.filesnippet=\ud30c\uc77c\uc5d0\uc11c \ucd94\ucd9c\ud558\uae30
+dialog.load.table.field=\ud544\ub4dc
+dialog.load.table.datatype=\ub370\uc774\ud0c0 \ud0c0\uc785
+dialog.load.table.description=\uc124\uba85
+dialog.delimiter.label=\ud544\ub4dc \uad6c\ubd84 \uae30\ud638
+dialog.delimiter.comma=\ucf64\ub9c8 ,
+dialog.delimiter.tab=\ud0ed
+dialog.delimiter.space=\ube48\uce78
+dialog.delimiter.semicolon=\uc138\ubbf8\ucf5c\ub860 ;
+dialog.delimiter.other=\uae30\ud0c0
+dialog.openoptions.deliminfo.records=\uac1c\uc758 \ub808\ucf54\ub4dc
+dialog.openoptions.deliminfo.fields=\uac1c\uc758 \ud544\ub4dc\uac00 \uc788\ub294
+dialog.openoptions.deliminfo.norecords=\ub808\ucf54\ub4dc\uac00 \uc5c6\uc74c
+dialog.openoptions.altitudeunits=\uace0\ub3c4 \ub2e8\uc704
+dialog.open.contentsdoubled=\uc774 \ud30c\uc77c\uc740 \uac01 \uc9c0\uc810\uc774 2\ubc88\uc529 \uae30\ub85d\ub418\uc5b4 \uc788\uc2b5\ub2c8\ub2e4. /n\uac01 \uc9c0\uc810\uacfc \uac01 \uacbd\uc720\uc9c0\ub294 \ud55c\ubc88\uc529\ub9cc \uae30\ub85d\ub418\uc5b4\uc57c \ud569\ub2c8\ub2e4.
+dialog.selecttracks.intro=\ubd88\ub7ec\uc62c \uc9c0\uc810\uc774\ub098 \uc9c0\uc810\ub4e4\uc744 \uc120\ud0dd\ud558\uc138\uc694
+dialog.selecttracks.noname=\uc774\ub984 \uc5c6\uc74c
+dialog.jpegload.subdirectories=\ud558\uc704 \ud3f4\ub354\ub3c4 \ud3ec\ud568
+dialog.jpegload.loadjpegswithoutcoords=\uc88c\ud45c \uc815\ubcf4\uc5c6\ub294 \uc0ac\uc9c4\ub4e4\ub3c4 \ud3ec\ud568
+dialog.jpegload.loadjpegsoutsidearea=\uc9c0\uae08 \uc9c0\uc5ed\uc678\ubd80 \uc0ac\uc9c4\ub4e4\ub3c4 \ud3ec\ud568
+dialog.jpegload.progress.title=\uc0ac\uc9c4\uc744 \ubd88\ub7ec\uc624\uace0 \uc788\uc2b5\ub2c8\ub2e4.
+dialog.jpegload.progress=\uc0ac\uc9c4\uc774 \uac80\uc0c9\ub418\ub294 \ub3d9\uc548 \uae30\ub2e4\ub824 \uc8fc\uc138\uc694.
+dialog.gpsload.nogpsbabel=gpsbabel \ud504\ub85c\uadf8\ub7a8\uc744 \ucc3e\uc9c0 \ubabb\ud558\uc600\uc2b5\ub2c8\ub2e4. \uacc4\uc18d \ud558\uc2dc\uaca0\uc2b5\ub2c8\uae4c?
+dialog.gpsload.device=\uc7a5\uce58 \uc774\ub984
+dialog.gpsload.format=\ud615\ud0dc
+dialog.gpsload.getwaypoints=\uacbd\uc720\uc9c0 \ubd88\ub7ec\uc624\uae30
+dialog.gpsload.gettracks=\ud2b8\ub809 \ubd88\ub7ec\uc624\uae30
+dialog.gpsload.save=\ud30c\uc77c\ub85c \uc800\uc7a5
+dialog.gpssend.sendwaypoints=\uacbd\uc720\uc9c0 \ubcf4\ub0b4\uae30
+dialog.gpssend.sendtracks=\ud2b8\ub809 \ubcf4\ub0b4\uae30
+dialog.gpssend.trackname=\ud2b8\ub809 \uc774\ub984
+dialog.saveoptions.title=\ud30c\uc77c \uc800\uc7a5
+dialog.save.fieldstosave=\ud544\ub4dc\uba85\uc73c\ub85c \uc800\uc7a5
+dialog.save.table.field=\ud544\ub4dc
+dialog.save.table.hasdata=\uc790\ub8cc\uac00 \uc788\uc74c
+dialog.save.table.save=\uc800\uc7a5
+dialog.save.headerrow=\uccab\ubc88\uc9f8 \uc904\ub3c4 \uc800\uc7a5
+dialog.save.coordinateunits=\uc88c\ud45c \ub2e8\uc704
+dialog.save.altitudeunits=\uace0\ub3c4 \ub2e8\uc704
+dialog.save.timestampformat=\uc2dc\uac04 \ud45c\ud604\ud615\uc2dd
+dialog.save.overwrite.title=\ud30c\uc77c\uc774 \uc774\ubbf8 \uc874\uc7ac\ud569\ub2c8\ub2e4.
+dialog.save.overwrite.text=\ud30c\uc77c\uc774 \uc774\ubbf8 \uc788\uc2b5\ub2c8\ub2e4. \uadf8\ub798\ub3c4 \uc774 \ud30c\uc77c\uc5d0 \ub36e\uc5b4\uc50c\uc6b0\uc2dc\uaca0\uc2b5\ub2c8\uae4c?
+dialog.save.notypesselected=\uc9c0\uc810\uc758 \ud615\uc2dd\uc774 \uc9c0\uc815\ub418\uc9c0 \uc54a\uc558\uc2b5\ub2c8\ub2e4.
+dialog.exportkml.text=\uc81c\ubaa9\uc73c\ub85c \uc800\uc7a5
+dialog.exportkml.altitude=\uace0\ub3c4 \uace0\uc815(\ube44\ud589)
+dialog.exportkml.kmz=kmz \ud30c\uc77c \uc0dd\uc131\uc2dc \uc555\ucd95\ud558\uae30
+dialog.exportkml.exportimages=kmz\ub85c \uc791\uc740 \uc0ac\uc9c4 \ub0b4\ubcf4\ub0b4\uae30
+dialog.exportkml.trackcolour=\ud2b8\ub809 \uc0c9
+dialog.exportgpx.name=\uc774\ub984
+dialog.exportgpx.desc=\uc124\uba85
+dialog.exportgpx.includetimestamps=\uc2dc\uac04 \ud3ec\ud568\ud558\uae30
+dialog.exportgpx.copysource=xml \ud30c\uc77c \ubcf5\uc0ac\ud558\uae30
+dialog.exportpov.text=POV\ub85c \ub0b4\ubcf4\ub0bc \ubcc0\uc218\ub97c \uc801\uc5b4\uc8fc\uc138\uc694.
+dialog.exportpov.font=\uae00\uaf34
+dialog.exportpov.camerax=\uce74\uba54\ub77c\uc758 X \uc88c\ud45c
+dialog.exportpov.cameray=\uce74\uba54\ub77c\uc758 Y \uc88c\ud45c
+dialog.exportpov.cameraz=\uce74\uba54\ub77c\uc758 Z \uc88c\ud45c
+dialog.exportpov.modelstyle=\ubaa8\ub378 \uc2a4\ud0c0\uc77c
+dialog.exportpov.ballsandsticks=\ub9c9\ub300\uae30\uc640 \uacf5
+dialog.exportpov.tubesandwalls=\ubcbd\uacfc \ud29c\ube0c
+dialog.exportpov.warningtracksize=\uc774 \ud2b8\ub799\uc740 \uc9c0\uc810\uc774 \ub108\ubb34 \ub9ce\uc544 Java3D\uac00 \ud45c\ud604 \ubabb\ud560 \uc218\ub3c4 \uc788\uc2b5\ub2c8\ub2e4. /n \uadf8\ub798\ub3c4 \uacc4\uc18d \ud558\uc2dc\uaca0\uc2b5\ub2c8\uae4c?
+dialog.exportsvg.text=SVG\ub85c \ub0b4\ubcf4\ub0bc \ud30c\ub77c\ubbf8\ud130\ub97c \uc120\ud0dd\ud558\uc138\uc694
+dialog.exportsvg.phi=\ubc29\uc704\uac01(\u03d5)
+dialog.exportsvg.theta=\uace0\ub3c4(\u03b8)
+dialog.exportsvg.gradients=\uc250\uc774\ub529\uc5d0 \uadf8\ub798\ub514\uc5b8\ud2b8 \uc0ac\uc6a9\ud558\uae30
+dialog.pointtype.desc=\uc9c0\uc810 \ud615\uc2dd \uc800\uc7a5\ud558\uae30
+dialog.pointtype.track=\ud2b8\ub799 \uc9c0\uc810
+dialog.pointtype.waypoint=\uacbd\uc720 \uc9c0\uc810
+dialog.pointtype.photo=\uc0ac\uc9c4 \uc9c0\uc810
+dialog.pointtype.audio=\uc18c\ub9ac \uc9c0\uc810
+dialog.pointtype.selection=\uc120\ud0dd \uc601\uc5ed\ub9cc
+dialog.confirmreversetrack.title=\ubc18\uc804\uc778\uc9c0 \ud655\uc778
+dialog.confirmreversetrack.text=\uc774 \ud2b8\ub799\uc740 \ubc18\uc804\ud6c4 \uc21c\uc11c\uac00 \ubc14\uafe8\uc744 \uc218\ub3c4 \uc788\ub294\uc2dc\uac04\uc815\ubcf4\ub97c \ud3ec\ud568\ud558\uace0 \uc788\uc2b5\ub2c8\ub2e4. /n \uadf8\ub798\ub3c4 \uc774\uc601\uc5ed\uc744 \ubc18\uc804\uc2dc\ud0a4\uc2dc\ub824\ub098\uc694?
+dialog.confirmcutandmove.title=\uc790\ub974\uace0 \uc62e\uae30\uae30 \ud655\uc778
+dialog.confirmcutandmove.text=\uc774 \ud2b8\ub799\uc740 \uc774\ub3d9\ud6c4 \uc21c\uc11c\uac00 \ubc14\uafe7\uc744 \uc218\ub3c4 \uc788\ub294 \uc2dc\uac04\uc815\ubcf4\ub97c \ud3ec\ud568\ud558\uace0 \uc788\uc2b5\ub2c8\ub2e4. /n \uadf8\ub798\ub3c4 \uc774 \uc601\uc5ed\uc744 \uc62e\uae30\uc2dc\ub824\ub098\uc694?
+dialog.interpolate.title=\uc0bd\uc785\ud55c \uc9c0\uc810
+dialog.interpolate.parameter.text=\uc120\ud0dd\ud55c \uc9c0\uc810 \uc0ac\uc774\uc5d0 \ub123\uc744 \uc9c0\uc810\uc758 \uc218
+dialog.undo.title=\uc791\uc5c5 \ub418\ub3cc\ub9ac\uae30
+dialog.undo.pretext=\ub418\ub3cc\ub9b4 \uc791\uc5c5\uc744 \uc120\ud0dd\ud574\uc8fc\uc138\uc694
+dialog.undo.none.title=\ub418\ub3cc\ub9b4 \uc218 \uc5c6\uc5b4\uc694
+dialog.undo.none.text=\ub418\ub3cc\ub9b4 \uc791\uc5c5\uc774 \uc5c6\uc5b4\uc694!
+dialog.clearundo.title=\ub418\ub3cc\ub9ac\uae30 \ubaa9\ub85d \uc9c0\uc6b0\uae30
+dialog.clearundo.text=\uc815\ub9d0\ub85c \ub418\ub3cc\ub9ac\uae30 \ubaa9\ub85d \uc9c0\uc6b0\uc2e4\uac74\uac00\uc694? /n \ubaa8\ub4e0 \ub418\ub3cc\ub9ac\uae30 \uc815\ubcf4\uac00 \uc5c6\uc5b4\uc9c4\ub2e4\uad6c\uc694!
+dialog.pointedit.title=\uc9c0\uc810 \uc218\uc815\ud558\uae30
+dialog.pointedit.text=\uc218\uc815\ud560 \ud544\ub4dc\ub97c \uc120\ud0dd\ud558\uc2dc\uace0, \uc218\uc815\ud558\uae30 \ubc84\ud2bc\uc744 \uc0ac\uc6a9\ud558\uc138\uc694.
+dialog.pointedit.table.field=\ud544\ub4dc
+dialog.pointedit.table.value=\uac12
+dialog.pointedit.table.changed=\uc218\uc815\ub428
+dialog.pointedit.changevalue.text=\uc774 \ud544\ub4dc\uc5d0 \uc0c8 \uac12\uc744 \uc785\ub825\ud574\uc8fc\uc138\uc694
+dialog.pointedit.changevalue.title=\ud544\ub4dc \uc218\uc815
+dialog.pointnameedit.name=\uacbd\uc720\uc9c0 \uc774\ub984
+dialog.pointnameedit.uppercase=\ub300\ubb38\uc790\ub85c
+dialog.pointnameedit.lowercase=\uc18c\ubb38\uc790\ub85c
+dialog.pointnameedit.sentencecase=\uccab\uae00\uc790\ub9cc \ub300\ubb38\uc790\ub85c
+dialog.addtimeoffset.add=\uc2dc\uac04 \ucd94\uac00
+dialog.addtimeoffset.subtract=\uc2dc\uac04 \ube7c\uae30
+dialog.addtimeoffset.days=\uc77c
+dialog.addtimeoffset.hours=\uc2dc
+dialog.addtimeoffset.minutes=\ubd84
+dialog.addtimeoffset.notimestamps=\uc2dc\uac04 \uc815\ubcf4\ub97c \ud3ec\ud568\ud558\uace0 \uc788\uc9c0\uc54a\uc544\uc11c \uc2dc\uac04\uc624\ud504\uc14b\uc744 \ucd94\uac00\ud560 \uc218 \uc5c6\ub124\uc694.
+dialog.findwaypoint.intro=\uacbd\uc720\uc9c0 \uc774\ub984\uc744 \uc801\uc73c\uc138\uc694.
+dialog.findwaypoint.search=\ucc3e\uae30
+dialog.saveexif.title=Exif \uc800\uc7a5
+dialog.saveexif.intro=\uccb4\ud06c\ubc15\uc2a4\ub97c \uc774\uc6a9\ud574\uc11c \uc800\uc7a5\ud560 \uc0ac\uc9c4\uc744 \uc120\ud0dd\ud558\uc138\uc694.
+dialog.saveexif.nothingtosave=\uc88c\ud45c \ub370\uc774\ud0c0\uac00 \ubc14\ub00c\uc9c0 \uc54a\uc558\uc5b4\uc694. \uc800\uc7a5\ud560 \uac83\uc774 \uc544\ubb34\uac83\ub3c4 \uc5c6\ub124\uc694.
+dialog.saveexif.noexiftool=exiftool \ud504\ub85c\uadf8\ub7a8\uc744 \ucc3e\uc9c0 \ubabb\ud588\uc5b4\uc694. \uacc4\uc18d \ud558\uc2dc\uaca0\uc5b4\uc694?
+dialog.saveexif.table.photoname=\uc0ac\uc9c4 \uc774\ub984
+dialog.saveexif.table.status=\uc0c1\ud0dc
+dialog.saveexif.table.save=\uc800\uc7a5
+dialog.saveexif.photostatus.connected=\uc9c0\uc810\uacfc \uc5f0\uacb0\ub428
+dialog.saveexif.photostatus.disconnected=\uc9c0\uac80\uacfc\uc758 \uc5f0\uacb0 \ub04a\uae40
+dialog.saveexif.photostatus.modified=\uc218\uc815\ub428
+dialog.saveexif.overwrite=\ud30c\uc77c \ub36e\uc5b4\uc4f0\uae30
+dialog.saveexif.force=\uc624\ub958\ubb34\uc2dc\ud558\uae30
+dialog.charts.xaxis=x \ucd95
+dialog.charts.yaxis=y \ucd95
+dialog.charts.output=\ucd9c\ub825
+dialog.charts.screen=\ud654\uba74\uc73c\ub85c \ucd9c\ub825
+dialog.charts.svg=SVG\ud30c\uc77c\ub85c \ucd9c\ub825
+dialog.charts.svgwidth=SVG \ud3ed
+dialog.charts.svgheight=SVG \ub192\uc774
+dialog.charts.needaltitudeortimes=\ucc28\ud2b8\ub9cc\ub4e4\ub54c \ud2b8\ub809\uc5d0\ub294 \uace0\ub3c4\uc640 \uc2dc\uac04 \uc815\ubcf4\uac00 \ud544\uc694\ud574\uc694.
+dialog.charts.gnuplotnotfound=\uc54c\ub824\uc900\uacbd\ub85c\uc5d0\uc11c gnuplot\uc744 \ucc3e\uc744 \uc218 \uc5c6\uc5b4\uc694.
+dialog.distances.intro=\uc9c0\uc810\uc0ac\uc774\uc758 \uc9c1\uc120 \uac70\ub9ac
+dialog.distances.column.from=\uc9c0\uac80\uc5d0\uc11c
+dialog.distances.column.to=\uc9c0\uc810\uae4c\uc9c0
+dialog.distances.currentpoint=\uc9c0\uae08 \uc9c0\uc810
+dialog.distances.toofewpoints=\uacbd\uc720\uc9c0 \uc0ac\uc774\uc758 \uac70\ub9ac\ub97c \uc54c\ub824\uba74 \uacbd\uc720\uc9c0\uac00 2\uac1c\uc774\uc0c1 \ud544\uc694\ud574\uc694.
+dialog.fullrangedetails.intro=\uc120\ud0dd\ub41c \ubc94\uc704\uc758 \uc790\uc138\ud55c \uc815\ubcf4
+dialog.setmapbg.intro=\ub9f5 \uc18c\uc2a4 \ud558\ub098\ub97c \uace0\ub974\uac70\ub098 \uc0c8\ub85c \ucd94\uac00\ud558\uc138\uc694.
+dialog.addmapsource.title=\uc0c8 \ub9f5 \uc18c\uc2a4 \ucd94\uac00\ud558\uae30
+dialog.addmapsource.sourcename=\uc18c\uc2a4 \uc774\ub984
+dialog.addmapsource.layer1url=\uccab \ub808\uc774\uc5b4\uc758 URL
+dialog.addmapsource.layer2url=\ub450\ubc88\uc9f8 \ub808\uc774\uc5b4\uc758 URL
+dialog.addmapsource.maxzoom=\ucd5c\uace0 \ud655\ub300
+dialog.addmapsource.cloudstyle=\uc2a4\ud0c0\uc77c \uc218
+dialog.addmapsource.noname=\uc774\ub984 \uc5c6\uc74c
+dialog.gpsies.column.name=\ud2b8\ub809 \uc774\ub984
+dialog.gpsies.column.length=\uae38\uc774
+dialog.gpsies.description=\uc124\uba85
+dialog.gpsies.nodescription=\uc124\uba85 \uc5c6\uc74c
+dialog.gpsies.nonefound=\ud2b8\ub799\uc744 \ucc3e\uc744 \uc218 \uc5c6\uc74c
+dialog.gpsies.username=Gpsies username
+dialog.gpsies.password=Gpsies \ube44\ubc00\ubc88\ud638
+dialog.gpsies.keepprivate=\ud2b8\ub799 \uac1c\uc778\uc815\ubcf4\ubcf4\ud638
+dialog.gpsies.confirmopenpage=\uc5c5\ub85c\ub4dc\ud55c \ud2b8\ub799\uc744 \uc6f9\ud398\uc774\uc9c0\uc5d0\uc11c \ubcf4\uc2dc\uaca0\uc5b4\uc694?
+dialog.gpsies.activities=\ud65c\ub3d9 \ud615\ud0dc
+dialog.gpsies.activity.trekking=\ub3c4\ubcf4\uc5ec\ud589
+dialog.gpsies.activity.walking=\uac77\uae30
+dialog.gpsies.activity.jogging=\ub2ec\ub9ac\uae30
+dialog.gpsies.activity.biking=\uc790\uc804\uac70\ud0c0\uae30
+dialog.gpsies.activity.motorbiking=\uc624\ud1a0\ubc14\uc774\ud0c0\uae30
+dialog.gpsies.activity.snowshoe=\ub208\uae38\uac77\uae30
+dialog.gpsies.activity.sailing=\ubc30\ud0c0\uae30
+dialog.gpsies.activity.skating=\uc2a4\ucf00\uc774\ud2b8\ud0c0\uae30
+dialog.wikipedia.column.name=\uac8c\uc2dc\ubb3c \uc774\ub984
+dialog.wikipedia.column.distance=\uac70\ub9ac
+dialog.correlate.notimestamps=\uc9c0\uc810 \ub370\uc774\ud130\uc5d0 \uc2dc\uac04\uc815\ubcf4\uac00 \uc5c6\uc5b4\uc11c \uc0ac\uc9c4\uc744 \uc5f0\uacb0 \ud560 \uc218 \uc5c6\uc5b4\uc694.
+dialog.correlate.nouncorrelatedphotos=\uc5f0\uacb0\uc774 \uc548\ub41c \uc0ac\uc9c4\uc774 \uc5c6\ub124\uc694. /n \uacc4\uc18d \ud558\uc2e4\uac70\uc8e0?
+dialog.correlate.photoselect.intro=\ub300\ud45c\uc0ac\uc9c4\uc73c\ub85c \uc0ac\uc6a9\ud560 \uc0ac\uc9c4\uc744 \ud558\ub098 \uc120\ud0dd\ud558\uc138\uc694.
+dialog.correlate.select.photoname=\uc0ac\uc9c4\uc774\ub984
+dialog.correlate.select.timediff=\uc0ac\uae34 \ucc28\uc774
+dialog.correlate.select.photolater=\uc0ac\uc9c4 \uc2dc\uac04\uc774 \uc9c0\uc810\uc2dc\uac04\ubcf4\ub2e4 \ub290\ub9bc
+dialog.correlate.options.tip=\ub3c4\uc6c0: \ucd5c\uc18c\ud55c \ud55c\uac1c\uc758 \uc544\uc774\ud0ec(\uc0ac\uc9c4,\uc18c\ub9ac)\uc744 \uc9c1\uc811 \uc5f0\uacb0\ud558\uba74, \ud0c0\uc784 \uc624\ud504\uc14b\uc744 \uacc4\uc0b0\ud560 \uc218 \uc788\uc5b4\uc694.
+dialog.correlate.options.intro=\uc790\ub3d9 \uc5f0\uacb0\uc744 \uc704\ud574 \uc635\uc158\uc744 \uc120\ud0dd\ud574\uc8fc\uc138\uc694.
+dialog.correlate.options.offsetpanel=\uc2dc\uac04 \uc624\ud504\uc14b
+dialog.correlate.options.offset=\uc624\ud504\uc14b
+dialog.correlate.options.offset.hours=\uc2dc\uac04
+dialog.correlate.options.offset.minutes=\ubd84
+dialog.correlate.options.offset.seconds=\ucd08
+dialog.correlate.options.photolater=\uc9c0\uc810\uc2dc\uac04\ubcf4\ub2e4 \uc0ac\uc9c4\uc2dc\uac04\uc774 \ub4a4\uc784
+dialog.correlate.options.pointlaterphoto=\uc0ac\uc9c4\uc2dc\uac04\ubcf4\ub2e4 \uc9c0\uc810\uc2dc\uac04\uc774 \ub4a4\uc784
+dialog.correlate.options.audiolater=\uc9c0\uc810\uc2dc\uac04\ubcf4\ub2e4 \uc18c\ub9ac\uc2dc\uac04\uc774 \ub4a4\uc784
+dialog.correlate.options.pointlateraudio=\uc18c\ub9ac\uc2dc\uac04\ubcf4\ub2e4 \uc9c0\uc810\uc2dc\uac04\uc774 \ub4a4\uc784
+dialog.correlate.options.limitspanel=\uc5f0\uacb0 \uc81c\ud55c
+dialog.correlate.options.notimelimit=\uc2dc\uac04 \uc81c\ud55c \uc5c6\uc74c
+dialog.correlate.options.timelimit=\uc2dc\uac04 \uc81c\ud55c
+dialog.correlate.options.nodistancelimit=\uac70\ub9ac\uc81c\ud55c \uc5c6\uc74c
+dialog.correlate.options.distancelimit=\uac70\ub9ac\uc81c\ud55c
+dialog.correlate.options.correlate=\uc5f0\uacb0
+dialog.correlate.alloutsiderange=\ubaa8\ub4e0 \uc0ac\uc9c4\ub4e4\uc774 \ud2b8\ub809\uc758 \uc2dc\uac04 \ubc94\uc704\uc548\uc5d0 \uc788\uc9c0 \uc54a\uc2b5\ub2c8\ub2e4./n\uc624\ud504\uc14b\uc744 \uc218\uc815\ud574\ubcf4\uc2dc\uac70\ub098 \ucd5c\uc18c\ud55c \ud55c \uc7a5\uc758 \uc0ac\uc9c4\uc744 \uc9c1\uc811 \uc5f0\uacb0\ud574\ubcf4\uc138\uc694.
+dialog.correlate.filetimes=\ud30c\uc77c\uc758 \uc2dc\uac04\uc774 \ub098\ud0c0\ub0b4\ub294 :
+dialog.correlate.filetimes2=\uc18c\ub9ac\ud30c\uc77c\uc758
+dialog.correlate.correltimes=\uc5f0\uacb0\uc744 \uc0ac\uc6a9\ud558\uc138\uc694
+dialog.correlate.timestamp.beginning=\uc2dc\uc791
+dialog.correlate.timestamp.middle=\uc911\uac04
+dialog.correlate.timestamp.end=\ub05d
+dialog.correlate.audioselect.intro=\ud0c0\uc784\uc624\ud504\uc14b\uc73c\ub85c \uc0ac\uc6a9\ud560 \uc5f0\uacb0\ub41c \uc18c\ub9ac\ub4e4\uc911 \ud558\ub098\ub97c \uc120\ud0dd\ud558\uc138\uc694
+dialog.correlate.select.audioname=\uc18c\ub9ac \uc774\ub984
+dialog.correlate.select.audiolater=\uc18c\ub9ac \ud6c4\uc5d0
+dialog.rearrangephotos.desc=\uc0ac\uc9c4 \uc9c0\uc810\ub4e4\uc744 \uc5b4\ub5bb\uac8c \uc815\ub82c\ud560 \uac74\uc9c0 \uc120\ud0dd\ud574\uc8fc\uc138\uc694.
+dialog.rearrangephotos.tostart=\uc2dc\uc791\uc73c\ub85c
+dialog.rearrangephotos.toend=\ub05d\uc73c\ub85c
+dialog.rearrangephotos.nosort=\uc815\ub82c\ud558\uc9c0 \uc54a\uae30
+dialog.rearrangephotos.sortbyfilename=\ud30c\uc77c \uc774\ub984\uc73c\ub85c \uc815\ub82c
+dialog.rearrangephotos.sortbytime=\uc2dc\uac04\uc73c\ub85c \uc815\ub82c
+dialog.compress.nonefound=\uc9c0\uc810 \ub370\uc774\ud130\uac00 \uc81c\uac70\ub420 \uc218 \uc5c6\uc2b5\ub2c8\ub2e4.
+dialog.compress.closepoints.title=\uc8fc\ubcc0 \ud3ec\uc778\ud2b8 \uc81c\uac70
+dialog.compress.closepoints.paramdesc=\ud655\uc7a5 \uacc4\uc218
+dialog.compress.wackypoints.title=\uc5c9\ub6b1\ud558\uac70\ub098 \uc0ac\uc6a9\ud558\uc9c0 \uc54a\ub294 \uc9c0\uc810 \uc81c\uac70
+dialog.compress.wackypoints.paramdesc=\uac70\ub9ac \uacc4\uc218
+dialog.compress.singletons.title=\ud558\ub098\uc529 \uc81c\uac70
+dialog.compress.singletons.paramdesc=\uac70\ub9ac \uacc4\uc218
+dialog.compress.duplicates.title=\ubcf5\uc0ac\ub41c\uac70 \uc81c\uac70
+dialog.compress.summarylabel=\uc0ad\uc81c\ud560 \uc9c0\uc810
+dialog.pastecoordinates.desc=\uc790\ud45c\ub97c \ub123\uc73c\uc138\uc694
+dialog.pastecoordinates.coords=\uc88c\ud45c
+dialog.pastecoordinates.nothingfound=\uc88c\ud45c\ub97c \ud655\uc778\ud558\uc2dc\uace0 \ub2e4\uc2dc \uc2dc\ub3c4\ud574 \ubcf4\uc138\uc694.
+dialog.help.help=http://activityworkshop.net/software/prun
+dialog.about.version=\ubc84\uc804
+dialog.about.build=\ube4c\ub4dc
+dialog.about.summarytext1=Prune\uc740 GPS\uc218\uc2e0\uae30\uc5d0\uc11c \uc704\uce58 \uc815\ubcf4\ub97c \ubc1b\uace0, \ud654\uba74\uc5d0 \ubcf4\uc5ec\uc8fc\uace0, \uc218\uc815\ud558\uac8c \ud574\uc8fc\ub294 \ud504\ub85c\uadf8\ub7a8\uc785\ub2c8\ub2e4.
+dialog.about.summarytext2=\uc774 \ud504\ub85c\uadf8\ub7a8\uc740 \uc790\uc720\ub86d\uac8c, \uac1c\ubc29\uc801\uc73c\ub85c, \uadf8\ub9ac\uace0 \uc804\uc138\uacc4\uc801\uc73c\ub85c \uc0ac\uc6a9\ud558\uace0 \uac1c\uc120\ud558\uae30 \uc704\ud574 Gnu GPL \uc5d0 \ub530\ub77c\uc11c \ubc30\ud3ec\ub429\ub2c8\ub2e4. \uc774 \ud504\ub85c\uadf8\ub7a8\uc5d0 \ud3ec\ud568\ub41c license.txt \ud30c\uc77c\uc758 \uc870\uac74\uc5d0 \ub530\ub77c \ubcf5\uc81c, \uc7ac\ubc30\ud3ec, \uc218\uc815\uc774 \ud5c8\uac00\ub418\uace0, \uc7a5\ub824\ub429\ub2c8\ub2e4.
+dialog.about.summarytext3=\ub354 \uc790\uc138\ud55c \uc815\ubcf4\ub098 \uc0ac\uc6a9\uc790\uc124\uba85\uc740 \uc774\uacf3\uc744 \ucc38\uace0\ud574\uc8fc\uc138\uc694.http://activityworkshop.net/
+dialog.about.languages=\uc0ac\uc6a9 \uac00\ub2a5\ud55c \uc5b8\uc5b4\ub4e4
+dialog.about.translatedby=\ud55c\uad6d\uc5b4 Hooau
+dialog.about.systeminfo=\uc2dc\uc2a4\ud15c \uc815\ubcf4
+dialog.about.systeminfo.os=\uc6b4\uc601\uccb4\uc81c
+dialog.about.systeminfo.java=\uc790\ubc14 \ub7f0\ud0c0\uc784
+dialog.about.systeminfo.java3d=Java3D\uac00 \uc124\uce58\ub418\uc5c8\uc74c
+dialog.about.systeminfo.povray=Povray\uac00 \uc124\uce58\ub418\uc5c8\uc74c
+dialog.about.systeminfo.exiftool=Exiftool\uc774 \uc124\uce58\ub418\uc5c8\uc74c
+dialog.about.systeminfo.gpsbabel=Gpsbabel\uc774 \uc124\uce58\ub418\uc5c8\uc74c
+dialog.about.systeminfo.gnuplot=Gnuplot\uc774 \uc124\uce58\ub418\uc5c8\uc74c
+dialog.about.systeminfo.exiflib=Exif \ub77c\uc774\ube0c\ub7ec\ub9ac
+dialog.about.systeminfo.exiflib.internal=\ub0b4\uc7a5
+dialog.about.systeminfo.exiflib.internal.failed=\ub0b4\uc7a5(\ucc3e\uc9c0\ubabb\ud568)
+dialog.about.systeminfo.exiflib.external=\uc678\uc7a5
+dialog.about.systeminfo.exiflib.external.failed=\uc678\uc7a5(\ucc3e\uc9c0\ubabb\ud568)
+dialog.about.yes=\uc608
+dialog.about.no=\uc544\ub2c8\uc624
+dialog.about.credits=\uc5d0\uac8c \uac10\uc0ac\ub97c
+dialog.about.credits.code=Prune \ucf54\ub4dc\ub97c \uc791\uc131\ud574\uc900
+dialog.about.credits.exifcode=Exif \ucf54\ub4dc\ub97c \uc791\uc131\ud574\uc900
+dialog.about.credits.icons=\uc77c\ubd80 \uc544\uc774\ucf58\uc744 \uac00\uc838\uc628
+dialog.about.credits.translators=\ubc88\uc5ed\uc790\ub4e4
+dialog.about.credits.translations=\ubc88\uc5ed\uc5d0 \ub3c4\uc6c0\uc744 \uc900
+dialog.about.credits.devtools=\uac1c\ubc1c \ub3c4\uad6c\ub4e4
+dialog.about.credits.othertools=\ub2e4\ub978 \ub3c4\uad6c\ub4e4
+dialog.about.credits.thanks=\uac10\uc0ac\ud569\ub2c8\ub2e4.
+dialog.about.readme=\uc77d\uc5b4\uc8fc\uc138\uc694
+dialog.checkversion.error=\ubc84\uc804\uc774 \ud655\uc778\ub418\uc9c0 \uc54a\uc558\uc5b4\uc694./n \uc778\ud130\ub137 \uc5f0\uacb0\uc744 \ud655\uc778\ud574\uc8fc\uc138\uc694.
+dialog.checkversion.uptodate=\ub2f9\uc2e0\uc740 Prune\uc758 \ucd5c\uc2e0 \ubc84\uc804\uc744 \uc0ac\uc6a9\ud558\uace0 \uacc4\uc2ed\ub2c8\ub2e4.
+dialog.checkversion.newversion1=Prune\uc758 \uc0c8 \ubc84\uc804\uc744 \uc9c0\uae08 \uc0ac\uc6a9\ud560 \uc218 \uc788\uaca0\ub124\uc694. \ucd5c\uc2e0\ubc84\uc804\uc740
+dialog.checkversion.newversion2=\ubc84\uc804\uc785\ub2c8\ub2e4.
+dialog.checkversion.releasedate1=\uc0c8 \ubc84\uc804\uc740
+dialog.checkversion.releasedate2=\uc5d0 \ubc30\ud3ec\ub418\uc5c8\uc2b5\ub2c8\ub2e4.
+dialog.checkversion.download=\uc0c8 \ubc84\uc804\uc744 \ub2e4\uc6b4\ubc1b\uace0 \uc2f6\uc73c\uc138\uc694? \uadf8\ub7fc \uc544\ub798 URL\ub85c \uc640\uc8fc\uc138\uc694. /n http://activityworkshop.net/software/prune/download.html.
+dialog.keys.intro=\ub9c8\uc6b0\uc2a4\ub97c \uc0ac\uc6a9\ud558\uc9c0 \ub9c8\uc2dc\uace0 \uc544\ub798 \ub2e8\ucd95\ud0a4\ub97c \uc0ac\uc6a9\ud574\ubcf4\uc138\uc694.
+dialog.keys.keylist=