private boolean _mangleTimestampsConfirmed = false;
private Viewport _viewport = null;
private ArrayList<File> _dataFiles = null;
- private boolean _firstDataFile = true;
+ private boolean _autoAppendNextFile = false;
private boolean _busyLoading = false;
+ private AppMode _appMode = AppMode.NORMAL;
+
+ /** Enum for the app mode - currently only two options but may expand later */
+ public enum AppMode {NORMAL, DRAWRECT};
/**
if (inDataFiles == null || inDataFiles.size() == 0) {
_dataFiles = null;
}
- else {
+ else
+ {
_dataFiles = inDataFiles;
File f = _dataFiles.get(0);
_dataFiles.remove(0);
// Start load of specified file
if (_fileLoader == null)
_fileLoader = new FileLoader(this, _frame);
- _firstDataFile = true;
+ _autoAppendNextFile = false; // prompt for append
_fileLoader.openFile(f);
}
}
{
_undoStack.add(inUndo);
UpdateMessageBroker.informSubscribers(inConfirmText);
+ setCurrentMode(AppMode.NORMAL);
}
/**
DataPoint currentPoint = _trackInfo.getCurrentPoint();
if (currentPoint != null)
{
+ // Check for photo
boolean deletePhoto = false;
Photo currentPhoto = currentPoint.getPhoto();
if (currentPhoto != null)
// store necessary information to undo it later
int pointIndex = _trackInfo.getSelection().getCurrentPointIndex();
int photoIndex = _trackInfo.getPhotoList().getPhotoIndex(currentPhoto);
+ int audioIndex = _trackInfo.getAudioList().getAudioIndex(currentPoint.getAudio());
DataPoint nextTrackPoint = _trackInfo.getTrack().getNextTrackPoint(pointIndex + 1);
// Construct Undo object
UndoOperation undo = new UndoDeletePoint(pointIndex, currentPoint, photoIndex,
- nextTrackPoint != null && nextTrackPoint.getSegmentStart());
+ audioIndex, nextTrackPoint != null && nextTrackPoint.getSegmentStart());
// call track to delete point
if (_trackInfo.deletePoint())
{
// decouple photo from point
currentPhoto.setDataPoint(null);
}
- UpdateMessageBroker.informSubscribers();
+ UpdateMessageBroker.informSubscribers(DataSubscriber.PHOTOS_MODIFIED);
}
- // Confirm
- UpdateMessageBroker.informSubscribers(I18nManager.getText("confirm.deletepoint.single"));
- }
- }
- }
-
-
- /**
- * Delete the currently selected range
- */
- public void deleteSelectedRange()
- {
- if (_track == null) return;
- // Find out if photos should be deleted or not
- int selStart = _trackInfo.getSelection().getStart();
- int selEnd = _trackInfo.getSelection().getEnd();
- if (selStart >= 0 && selEnd >= selStart)
- {
- int numToDelete = selEnd - selStart + 1;
- boolean[] deletePhotos = new boolean[numToDelete];
- Photo[] photosToDelete = new Photo[numToDelete];
- boolean deleteAll = false;
- boolean deleteNone = false;
- String[] questionOptions = {I18nManager.getText("button.yes"), I18nManager.getText("button.no"),
- I18nManager.getText("button.yestoall"), I18nManager.getText("button.notoall"),
- I18nManager.getText("button.cancel")};
- DataPoint point = null;
- for (int i=0; i<numToDelete; i++)
- {
- point = _trackInfo.getTrack().getPoint(i + selStart);
- if (point != null && point.getPhoto() != null)
- {
- if (deleteAll)
- {
- deletePhotos[i] = true;
- photosToDelete[i] = point.getPhoto();
- }
- else if (deleteNone) {deletePhotos[i] = false;}
- else
- {
- int response = JOptionPane.showOptionDialog(_frame,
- I18nManager.getText("dialog.deletepoint.deletephoto") + " " + point.getPhoto().getName(),
- I18nManager.getText("dialog.deletepoint.title"),
- JOptionPane.YES_NO_CANCEL_OPTION, JOptionPane.QUESTION_MESSAGE, null,
- questionOptions, questionOptions[1]);
- // check for cancel or close
- if (response == 4 || response == -1) {return;}
- // check for yes or yes to all
- if (response == 0 || response == 2)
- {
- deletePhotos[i] = true;
- photosToDelete[i] = point.getPhoto();
- if (response == 2) {deleteAll = true;}
- }
- // check for no to all
- if (response == 3) {deleteNone = true;}
- }
+ // Delete audio object (without bothering to ask)
+ if (audioIndex > -1) {
+ _trackInfo.getAudioList().deleteAudio(audioIndex);
}
- }
- // add information to undo stack
- UndoDeleteRange undo = new UndoDeleteRange(_trackInfo);
- // delete requested photos
- for (int i=0; i<numToDelete; i++)
- {
- point = _trackInfo.getTrack().getPoint(i + selStart);
- if (point != null && point.getPhoto() != null)
- {
- if (deletePhotos[i])
- {
- // delete photo from list
- _trackInfo.getPhotoList().deletePhoto(_trackInfo.getPhotoList().getPhotoIndex(point.getPhoto()));
- }
- else
- {
- // decouple from point
- point.getPhoto().setDataPoint(null);
- }
- }
- }
- // call track to delete range
- if (_trackInfo.deleteRange())
- {
- _undoStack.push(undo);
// Confirm
- UpdateMessageBroker.informSubscribers("" + numToDelete + " "
- + I18nManager.getText("confirm.deletepoint.multi"));
+ UpdateMessageBroker.informSubscribers(I18nManager.getText("confirm.deletepoint.single"));
+ UpdateMessageBroker.informSubscribers(DataSubscriber.DATA_ADDED_OR_REMOVED);
}
}
}
*/
public void finishCompressTrack()
{
- UndoCompress undo = new UndoCompress(_track);
+ UndoDeleteMarked undo = new UndoDeleteMarked(_track);
// call track to do compress
int numPointsDeleted = _trackInfo.deleteMarkedPoints();
// add to undo stack if successful
+ (numPointsDeleted==1?I18nManager.getText("confirm.deletepoint.single"):I18nManager.getText("confirm.deletepoint.multi")));
}
else {
- showErrorMessage("function.compress", "dialog.compress.nonefound");
+ showErrorMessage("function.compress", "dialog.deletemarked.nonefound");
}
}
}
- /**
- * Interpolate the two selected points
- */
- public void interpolateSelection()
- {
- // Get number of points to add
- Object numPointsStr = JOptionPane.showInputDialog(_frame,
- I18nManager.getText("dialog.interpolate.parameter.text"),
- I18nManager.getText("dialog.interpolate.title"),
- JOptionPane.QUESTION_MESSAGE, null, null, "");
- int numPoints = parseNumber(numPointsStr);
- if (numPoints <= 0) return;
-
- UndoInsert undo = new UndoInsert(_trackInfo.getSelection().getStart() + 1,
- numPoints);
- // call track to interpolate
- if (_trackInfo.interpolate(numPoints))
- {
- _undoStack.add(undo);
- }
- }
-
-
/**
* Average the selected points
*/
/**
- * Create a new point at the given position
+ * Create a new point at the end of the track
* @param inPoint point to add
*/
public void createPoint(DataPoint inPoint)
}
+ /**
+ * Create a new point before the given position
+ * @param inPoint point to add
+ * @param inIndex index of following point
+ */
+ public void createPoint(DataPoint inPoint, int inIndex)
+ {
+ // create undo object
+ UndoInsert undo = new UndoInsert(inIndex, 1);
+ _undoStack.add(undo);
+ // add point to track
+ _track.insertPoint(inPoint, inIndex);
+ // ensure track's field list contains point's fields
+ _track.extendFieldList(inPoint.getFieldList());
+ _trackInfo.selectPoint(inIndex);
+ // update listeners
+ UpdateMessageBroker.informSubscribers(I18nManager.getText("confirm.createpoint"));
+ }
+
+
/**
* Cut the current selection and move it to before the currently selected point
*/
_track.clearDeletionMarkers();
}
- /**
- * Receive loaded data and start load
- * @param inFieldArray array of fields
- * @param inDataArray array of data
- * @param inAltFormat altitude format
- * @param inSourceInfo information about the source of the data
- */
- public void informDataLoaded(Field[] inFieldArray, Object[][] inDataArray,
- Altitude.Format inAltFormat, SourceInfo inSourceInfo)
- {
- informDataLoaded(inFieldArray, inDataArray, inAltFormat, inSourceInfo, null, null);
- }
-
/**
* Receive loaded data and determine whether to filter on tracks or not
* @param inFieldArray array of fields
// go directly to load
informDataLoaded(loadedTrack, inSourceInfo);
}
+ setCurrentMode(AppMode.NORMAL);
}
{
// ask whether to replace or append
int answer = 0;
- if (_dataFiles == null || _firstDataFile) {
+ if (_autoAppendNextFile) {
+ // Automatically append the next file
+ answer = JOptionPane.YES_OPTION;
+ }
+ else {
+ // Ask whether to append or not
answer = JOptionPane.showConfirmDialog(_frame,
I18nManager.getText("dialog.openappend.text"),
I18nManager.getText("dialog.openappend.title"),
JOptionPane.YES_NO_CANCEL_OPTION);
}
- else {
- // Automatically append if there's a file load queue
- answer = JOptionPane.YES_OPTION;
- }
+ _autoAppendNextFile = false; // reset flag to cancel autoappend
+
if (answer == JOptionPane.YES_OPTION)
{
// append data to current Track
loadNextFile();
}
+ /**
+ * External trigger to automatically append the next loaded file
+ * instead of prompting to replace or append
+ */
+ public void autoAppendNextFile()
+ {
+ _autoAppendNextFile = true;
+ }
+
/**
* Load the next file in the waiting list, if any
*/
private void loadNextFile()
{
- _firstDataFile = false;
if (_dataFiles == null || _dataFiles.size() == 0) {
_dataFiles = null;
}
public void run() {
File f = _dataFiles.get(0);
_dataFiles.remove(0);
+ _autoAppendNextFile = true;
_fileLoader.openFile(f);
}
}).start();
showErrorMessageNoLookup("error.undofailed.title",
I18nManager.getText("error.undofailed.text") + " : " + ue.getMessage());
_undoStack.clear();
- UpdateMessageBroker.informSubscribers();
}
catch (EmptyStackException empty) {}
+ UpdateMessageBroker.informSubscribers();
}
- /**
- * Helper method to parse an Object into an integer
- * @param inObject object, eg from dialog
- * @return int value given
- */
- private static int parseNumber(Object inObject)
- {
- int num = 0;
- if (inObject != null)
- {
- try
- {
- num = Integer.parseInt(inObject.toString());
- }
- catch (NumberFormatException nfe)
- {}
- }
- return num;
- }
-
/**
* Show a map url in an external browser
* @param inSourceIndex index of map source to use
public boolean isBusyLoading() {
return _busyLoading;
}
+
+ /** @return current app mode */
+ public AppMode getCurrentMode() {
+ return _appMode;
+ }
+
+ /** @param inMode the current app mode */
+ public void setCurrentMode(AppMode inMode) {
+ _appMode = inMode;
+ }
}
public static RearrangeWaypointsFunction FUNCTION_REARRANGE_WAYPOINTS = null;
public static GenericFunction FUNCTION_REARRANGE_PHOTOS = null;
public static GenericFunction FUNCTION_COMPRESS = null;
+ public static GenericFunction FUNCTION_DELETE_RANGE = null;
+ public static GenericFunction FUNCTION_CROP_TRACK = null;
+ public static GenericFunction FUNCTION_INTERPOLATE = null;
public static GenericFunction FUNCTION_LOOKUP_SRTM = null;
public static GenericFunction FUNCTION_LOOKUP_WIKIPEDIA = null;
public static GenericFunction FUNCTION_SEARCH_WIKIPEDIA = null;
FUNCTION_REARRANGE_WAYPOINTS = new RearrangeWaypointsFunction(inApp);
FUNCTION_REARRANGE_PHOTOS = new RearrangePhotosFunction(inApp);
FUNCTION_COMPRESS = new CompressTrackFunction(inApp);
+ FUNCTION_DELETE_RANGE = new DeleteSelectedRangeFunction(inApp);
+ FUNCTION_CROP_TRACK = new CropToSelection(inApp);
+ FUNCTION_INTERPOLATE = new InterpolateFunction(inApp);
FUNCTION_LOOKUP_SRTM = new LookupSrtmFunction(inApp);
FUNCTION_LOOKUP_WIKIPEDIA = new GetWikipediaFunction(inApp);
FUNCTION_SEARCH_WIKIPEDIA = new SearchWikipediaNames(inApp);
/**
* GpsPrune is a tool to visualize, edit, convert and prune GPS data
* Please see the included readme.txt or http://activityworkshop.net
- * This software is copyright activityworkshop.net 2006-2011 and made available through the Gnu GPL version 2.
+ * This software is copyright activityworkshop.net 2006-2012 and made available through the Gnu GPL version 2.
* For license details please see the included license.txt.
* GpsPrune is the main entry point to the application, including initialisation and launch
*/
public class GpsPrune
{
/** Version number of application, used in about screen and for version check */
- public static final String VERSION_NUMBER = "13.4";
+ public static final String VERSION_NUMBER = "14";
/** Build number, just used for about screen */
- public static final String BUILD_NUMBER = "244c";
+ public static final String BUILD_NUMBER = "265a";
/** Static reference to App object */
private static App APP = null;
{
// Check if a data file has been given
File f = new File(arg);
- if (f.exists() && f.canRead()) {
+ if (f.exists() && f.isFile() && f.canRead()) {
dataFiles.add(f);
}
else
private static String makeUnknownParameterString(String inParam)
{
File file = new File(inParam);
- if (file.exists()) {
- return (file.canRead() ? "Something wrong with file" : "Cannot read file") + " '" + inParam + "'";
+ if (file.exists())
+ {
+ if (file.isDirectory()) return "'" + inParam + "' is a directory";
+ if (!file.canRead()) return "Cannot read file '" + inParam + "'";
+ return "Something wrong with file '" + inParam + "'";
}
do
{
import java.util.Properties;
import tim.prune.data.RecentFileList;
+import tim.prune.data.UnitSet;
+import tim.prune.data.UnitSetLibrary;
/**
private static ColourScheme _colourScheme = new ColourScheme();
/** Recently-used file list */
private static RecentFileList _recentFiles = new RecentFileList();
+ /** Current unit set */
+ private static UnitSet _unitSet = UnitSetLibrary.getUnitSet(null);
/** Default config file */
public static final File DEFAULT_CONFIG_FILE = new File(".pruneconfig");
public static final String KEY_GPS_FORMAT = "prune.gpsformat";
/** Key for Povray font */
public static final String KEY_POVRAY_FONT = "prune.povrayfont";
- /** Key for metric/imperial */
- public static final String KEY_METRIC_UNITS = "prune.metricunits";
+ /** Key for the selected unit set */
+ public static final String KEY_UNITSET_KEY = "prune.unitsetkey";
/** Key for index of map source */
public static final String KEY_MAPSOURCE_INDEX = "prune.mapsource";
/** Key for number of fixed map sources */
_configValues.putAll(props);
_colourScheme.loadFromHex(_configValues.getProperty(KEY_COLOUR_SCHEME));
_recentFiles = new RecentFileList(_configValues.getProperty(KEY_RECENT_FILES));
+ _unitSet = UnitSetLibrary.getUnitSet(_configValues.getProperty(KEY_UNITSET_KEY));
+
if (loadFailed) {
throw new ConfigException();
}
props.put(KEY_KMZ_IMAGE_WIDTH, "240");
props.put(KEY_KMZ_IMAGE_HEIGHT, "240");
props.put(KEY_AUTOSAVE_SETTINGS, "0"); // autosave false by default
+ props.put(KEY_UNITSET_KEY, "unitset.kilometres"); // metric by default
return props;
}
*/
public static boolean isKeyBoolean(String inKey)
{
- // Only two boolean keys so far
+ // Only one boolean key so far (after metric flag was removed)
return inKey != null && (
- inKey.equals(KEY_METRIC_UNITS) || inKey.equals(KEY_SHOW_MAP));
+ inKey.equals(KEY_SHOW_MAP));
}
/**
{
setConfigString(KEY_COLOUR_SCHEME, _colourScheme.toString());
}
+
+ /**
+ * @return the current unit set
+ */
+ public static UnitSet getUnitSet() {
+ return _unitSet;
+ }
+
+ public static void selectUnitSet(int inIndex)
+ {
+ _unitSet = UnitSetLibrary.getUnitSet(inIndex);
+ // Set name of set in config
+ setConfigString(KEY_UNITSET_KEY, _unitSet.getNameKey());
+ }
}
-The source code of GpsPrune is copyright 2006-2011 activityworkshop.net
+The source code of GpsPrune is copyright 2006-2012 activityworkshop.net
and is distributed under the terms of the Gnu GPL version 2.
Portions of the package jpeg.drew (if included in this package) were taken
import tim.prune.data.TimeDifference;
import tim.prune.data.Timestamp;
import tim.prune.data.Track;
+import tim.prune.data.Unit;
+import tim.prune.data.UnitSetLibrary;
/**
* Abstract superclass of the two correlator functions
{
JPanel card = new JPanel();
card.setLayout(new BorderLayout(10, 10));
- card.add(new JLabel(I18nManager.getText(
- "dialog.correlate." + getMediaTypeKey() + "select.intro")), BorderLayout.NORTH);
+ JLabel introLabel = new JLabel(I18nManager.getText(
+ "dialog.correlate." + getMediaTypeKey() + "select.intro"));
+ introLabel.setBorder(BorderFactory.createEmptyBorder(6, 6, 6, 6));
+ card.add(introLabel, BorderLayout.NORTH);
// table doesn't have model yet - that will be attached later
_selectionTable = new JTable();
JScrollPane photoScrollPane = new JScrollPane(_selectionTable);
offsetPanelBot.setLayout(new FlowLayout());
offsetPanelBot.setBorder(null);
_mediaLaterOption = new JRadioButton(I18nManager.getText("dialog.correlate.options." + getMediaTypeKey() + "later"));
- _pointLaterOption = new JRadioButton(I18nManager.getText("dialog.correlate.options.pointlaterphoto"));
+ _pointLaterOption = new JRadioButton(I18nManager.getText("dialog.correlate.options.pointlater" + getMediaTypeKey()));
_mediaLaterOption.addItemListener(optionsChangedListener);
_pointLaterOption.addItemListener(optionsChangedListener);
ButtonGroup laterGroup = new ButtonGroup();
offsetPanel.setAlignmentX(Component.LEFT_ALIGNMENT);
card2Top.add(offsetPanel);
+ // listener for radio buttons
+ ActionListener radioListener = new ActionListener() {
+ public void actionPerformed(ActionEvent e) {
+ enableEditBoxes();
+ }
+ };
// time limits section
JPanel limitsPanel = new JPanel();
limitsPanel.setBorder(BorderFactory.createTitledBorder(I18nManager.getText("dialog.correlate.options.limitspanel")));
timeLimitPanel.setLayout(new FlowLayout());
JRadioButton noTimeLimitRadio = new JRadioButton(I18nManager.getText("dialog.correlate.options.notimelimit"));
noTimeLimitRadio.addItemListener(optionsChangedListener);
+ noTimeLimitRadio.addActionListener(radioListener);
timeLimitPanel.add(noTimeLimitRadio);
_timeLimitRadio = new JRadioButton(I18nManager.getText("dialog.correlate.options.timelimit") + " : ");
_timeLimitRadio.addItemListener(optionsChangedListener);
+ _timeLimitRadio.addActionListener(radioListener);
timeLimitPanel.add(_timeLimitRadio);
groupRadioButtons(noTimeLimitRadio, _timeLimitRadio);
_limitMinBox = new JTextField(3);
distLimitPanel.setLayout(new FlowLayout());
JRadioButton noDistLimitRadio = new JRadioButton(I18nManager.getText("dialog.correlate.options.nodistancelimit"));
noDistLimitRadio.addItemListener(optionsChangedListener);
+ noDistLimitRadio.addActionListener(radioListener);
distLimitPanel.add(noDistLimitRadio);
_distLimitRadio = new JRadioButton(I18nManager.getText("dialog.correlate.options.distancelimit"));
_distLimitRadio.addItemListener(optionsChangedListener);
+ _distLimitRadio.addActionListener(radioListener);
distLimitPanel.add(_distLimitRadio);
groupRadioButtons(noDistLimitRadio, _distLimitRadio);
_limitDistBox = new JTextField(4);
_okButton.setEnabled(inCardNum == 2 && ((MediaPreviewTableModel) _previewTable.getModel()).hasAnySelected());
}
+ /**
+ * Enable or disable the edit boxes according to the radio button selections
+ */
+ private void enableEditBoxes()
+ {
+ // enable/disable text field for distance input
+ _limitDistBox.setEnabled(_distLimitRadio.isSelected());
+ // and for time limits
+ _limitMinBox.setEnabled(_timeLimitRadio.isSelected());
+ _limitSecBox.setEnabled(_timeLimitRadio.isSelected());
+ }
+
/**
* Parse the time limit values entered and validate them
* @return TimeDifference object describing limit
/**
* @return the selected distance units from the dropdown
*/
- protected Distance.Units getSelectedDistanceUnits()
+ protected Unit getSelectedDistanceUnits()
{
- final Distance.Units[] distUnits = {Distance.Units.KILOMETRES, Distance.Units.METRES, Distance.Units.MILES};
+ final Unit[] distUnits = {UnitSetLibrary.UNITS_KILOMETRES, UnitSetLibrary.UNITS_METRES, UnitSetLibrary.UNITS_MILES};
return distUnits[_distUnitsDropdown.getSelectedIndex()];
}
_mediaLaterOption.setSelected(timeDiff.getIsPositive());
_pointLaterOption.setSelected(!timeDiff.getIsPositive());
_previewEnabled = true;
+ enableEditBoxes();
createPreview(timeDiff, true);
}
protected PointMediaPair getPointPairForMedia(Track inTrack, MediaObject inMedia, TimeDifference inOffset)
{
PointMediaPair pair = new PointMediaPair(inMedia);
- // Add/subtract offset to media timestamp
- Timestamp mediaStamp = getMediaTimestamp(inMedia).createMinusOffset(inOffset);
- int numPoints = inTrack.getNumPoints();
- for (int i=0; i<numPoints; i++)
+ if (inMedia.hasTimestamp())
{
- DataPoint point = inTrack.getPoint(i);
- if (point.getPhoto() == null && point.getAudio() == null)
+ // Add/subtract offset to media timestamp
+ Timestamp mediaStamp = getMediaTimestamp(inMedia).createMinusOffset(inOffset);
+ int numPoints = inTrack.getNumPoints();
+ for (int i=0; i<numPoints; i++)
{
- Timestamp pointStamp = point.getTimestamp();
- if (pointStamp != null && pointStamp.isValid())
+ DataPoint point = inTrack.getPoint(i);
+ if (point.getPhoto() == null && point.getAudio() == null)
{
- long numSeconds = pointStamp.getSecondsSince(mediaStamp);
- pair.addPoint(point, numSeconds);
+ Timestamp pointStamp = point.getTimestamp();
+ if (pointStamp != null && pointStamp.isValid())
+ {
+ long numSeconds = pointStamp.getSecondsSince(mediaStamp);
+ pair.addPoint(point, numSeconds);
+ }
}
}
}
import java.util.ArrayList;
import javax.swing.table.AbstractTableModel;
import tim.prune.I18nManager;
-import tim.prune.data.Distance;
+import tim.prune.data.Unit;
+import tim.prune.data.UnitSetLibrary;
/**
* Class to act as the table model for the correlation preview table
/** ArrayList containing TableRow objects */
private ArrayList<MediaPreviewTableRow> _list = new ArrayList<MediaPreviewTableRow>();
/** Distance units */
- private Distance.Units _distanceUnits = Distance.Units.KILOMETRES;
+ private Unit _distanceUnits = UnitSetLibrary.UNITS_KILOMETRES;
/** Number formatter */
private static final NumberFormat FORMAT_ONE_DP = NumberFormat.getNumberInstance();
MediaPreviewTableRow row = _list.get(inRowIndex);
if (inColumnIndex == 0) return row.getMedia().getName();
else if (inColumnIndex == 1) {
- return row.getMedia().getTimestamp().getText();
+ if (row.getMedia().hasTimestamp()) {
+ return row.getMedia().getTimestamp().getText();
+ }
+ return ""; // media doesn't have a timestamp
}
else if (inColumnIndex == 2) {
if (row.getPointPair().isValid()) {
/**
* @param inUnits the distance units to use
*/
- public void setDistanceUnits(Distance.Units inUnits)
+ public void setDistanceUnits(Unit inUnits)
{
_distanceUnits = inUnits;
}
package tim.prune.correlate;
import tim.prune.data.Distance;
+import tim.prune.data.Unit;
/**
* Class to hold the contents of a single row in the correlation preview table
{
private PointMediaPair _pointPair = null;
private double _distance = 0.0;
- private int _status = 0;
private boolean _correlate = false;
super(inPointPair.getMedia(), inPointPair.getMinSeconds());
_pointPair = inPointPair;
_distance = inPointPair.getMinRadians();
- _status = 0;
_correlate = (inPointPair.getMedia().getDataPoint() == null);
}
* @param inUnits units to use
* @return distance in selected format
*/
- public double getDistance(Distance.Units inUnits)
+ public double getDistance(Unit inUnits)
{
return Distance.convertRadiansToDistance(_distance, inUnits);
}
- /**
- * @return point status
- */
- public int getStatus()
- {
- return _status;
- }
-
/**
* @return point pair object
*/
// MAYBE: only show time of photos (not date) if dates all identical
MediaSelectionTableRow row = _list.get(inRowIndex);
if (inColumnIndex == 0) return row.getMedia().getName();
- else if (inColumnIndex == 1) return row.getMedia().getTimestamp().getText();
+ else if (inColumnIndex == 1) {
+ return (row.getMedia().hasTimestamp() ? row.getMedia().getTimestamp().getText() : "");
+ }
else if (inColumnIndex == 2) return row.getTimeDiff().getDescription();
return (row.getTimeDiff().getIsPositive() ? I18nManager.getText("dialog.about.yes") :
I18nManager.getText("dialog.about.no"));
}
/** Constants for conversion */
- private static final double CONVERT_FEET_TO_METRES = 0.3048;
- private static final double CONVERT_METRES_TO_FEET = 3.28084;
+ private static final double CONVERT_METRES_TO_FEET = UnitSetLibrary.UNITS_FEET.getMultFactorFromStd();
+ private static final double CONVERT_FEET_TO_METRES = 1 / CONVERT_METRES_TO_FEET;
/** Constant for no altitude value */
public static final Altitude NONE = new Altitude(null, Format.NO_FORMAT);
*/
public void reset(Altitude inClone)
{
+ _stringValue = inClone._stringValue;
_value = inClone._value;
_format = inClone._format;
_valid = inClone._valid;
return _value;
}
+ /**
+ * @param inAltUnit altitude units to use
+ * @return rounded value in specified units
+ */
+ public int getValue(Unit inAltUnit)
+ {
+ return (int) (getMetricValue() * inAltUnit.getMultFactorFromStd());
+ }
/**
* @return format of number
return _value;
}
+ /**
+ * @return value of altitude in metres, used for calculations and charts
+ */
+ public double getMetricValue()
+ {
+ if (_format == Format.FEET) {
+ return _value / UnitSetLibrary.UNITS_FEET.getMultFactorFromStd();
+ }
+ return _value;
+ }
+
/**
* Get a string version of the value
* @param inFormat specified format
else
offset = inOffset * CONVERT_METRES_TO_FEET;
}
+ // FIXME: The following will fail if _stringValue is null - not sure how it can get in that state!
+ if (_stringValue == null) System.err.println("*** Altitude.addOffset - how did the string value get to be null?");
// Add the offset
double newValue = Double.parseDouble(_stringValue.trim()) + offset;
_value = (int) newValue;
*/
public class AltitudeRange
{
+ /** Range of altitudes in metres */
private IntegerRange _range = new IntegerRange();
- private Altitude.Format _format = Altitude.Format.NO_FORMAT;
+ /** Empty flag */
+ private boolean _empty;
+ /** Previous metric value */
+ private int _prevValue;
+ /** Total climb in metres */
+ private double _climb;
+ /** Total descent in metres */
+ private double _descent;
+ /**
+ * Constructor
+ */
+ public AltitudeRange() {
+ clear();
+ }
+
/**
* Clear the altitude range
*/
public void clear()
{
_range.clear();
- _format = Altitude.Format.NO_FORMAT;
+ _climb = 0.0;
+ _descent = 0.0;
+ _empty = true;
+ _prevValue = 0;
}
*/
public void addValue(Altitude inAltitude)
{
- if (inAltitude != null)
+ if (inAltitude != null && inAltitude.isValid())
{
- int altValue = inAltitude.getValue(_format);
+ int altValue = (int) inAltitude.getMetricValue();
_range.addValue(altValue);
- if (_format == Altitude.Format.NO_FORMAT)
+ // Compare with previous value if any
+ if (!_empty)
{
- _format = inAltitude.getFormat();
+ if (altValue > _prevValue)
+ _climb += (altValue - _prevValue);
+ else
+ _descent += (_prevValue - altValue);
}
+ _prevValue = altValue;
+ _empty = false;
}
}
+ /**
+ * Reset the climb/descent calculations starting from the given value
+ * @param inAltitude altitude value
+ */
+ public void ignoreValue(Altitude inAltitude)
+ {
+ // If we set the empty flag to true, that has the same effect as restarting a segment
+ _empty = true;
+ addValue(inAltitude);
+ }
/**
* @return true if altitude range found
/**
+ * @param inUnit altitude units to use
* @return minimum value, or -1 if none found
*/
- public int getMinimum()
+ public int getMinimum(Unit inUnit)
{
- return _range.getMinimum();
+ if (_range.getMinimum() <= 0) return _range.getMinimum();
+ return (int) (_range.getMinimum() * inUnit.getMultFactorFromStd());
}
-
/**
+ * @param inUnit altitude units to use
* @return maximum value, or -1 if none found
*/
- public int getMaximum()
+ public int getMaximum(Unit inUnit)
{
- return _range.getMaximum();
+ if (_range.getMaximum() <= 0) return _range.getMaximum();
+ return (int) (_range.getMaximum() * inUnit.getMultFactorFromStd());
}
+ /**
+ * @param inUnit altitude units to use
+ * @return total climb
+ */
+ public int getClimb(Unit inUnit)
+ {
+ return (int) (_climb * inUnit.getMultFactorFromStd());
+ }
/**
- * @return the altitude format used
+ * @param inUnit altitude units to use
+ * @return total descent
*/
- public Altitude.Format getFormat()
+ public int getDescent(Unit inUnit)
{
- return _format;
+ return (int) (_descent * inUnit.getMultFactorFromStd());
}
}
_fieldValues = inValueArray;
// save list of fields
_fieldList = inFieldList;
+ // Remove double quotes around values
+ removeQuotes(_fieldValues);
// parse fields into objects
parseFields(null, inAltFormat);
}
}
else {
// use default altitude format from config
- parseFields(inField, Config.getConfigBoolean(Config.KEY_METRIC_UNITS)?Altitude.Format.METRES:Altitude.Format.FEET);
+ parseFields(inField, Config.getUnitSet().getDefaultAltitudeFormat());
}
}
return _photo != null || _audio != null;
}
+ /**
+ * @return name of attached photo and/or audio
+ */
+ public String getMediaName()
+ {
+ String mediaName = null;
+ if (_photo != null) mediaName = _photo.getName();
+ if (_audio != null)
+ {
+ if (mediaName == null) {
+ mediaName = _audio.getName();
+ }
+ else {
+ mediaName = mediaName + ", " + _audio.getName();
+ }
+ }
+ return mediaName;
+ }
+
/**
* Interpolate a set of points between this one and the given one
* @param inEndPoint end point of interpolation
}
+ /**
+ * Remove all single and double quotes surrounding each value
+ * @param inValues array of values
+ */
+ private static void removeQuotes(String[] inValues)
+ {
+ if (inValues == null) {return;}
+ for (int i=0; i<inValues.length; i++)
+ {
+ inValues[i] = removeQuotes(inValues[i]);
+ }
+ }
+
+ /**
+ * Remove any single or double quotes surrounding a value
+ * @param inValue value to modify
+ * @return modified String
+ */
+ private static String removeQuotes(String inValue)
+ {
+ if (inValue == null) {return inValue;}
+ final int len = inValue.length();
+ if (len <= 1) {return inValue;}
+ // get the first and last characters
+ final char firstChar = inValue.charAt(0);
+ final char lastChar = inValue.charAt(len-1);
+ if (firstChar == lastChar)
+ {
+ if (firstChar == '\"' || firstChar == '\'') {
+ return inValue.substring(1, len-1);
+ }
+ }
+ return inValue;
+ }
+
/**
* Get string for debug
* @see java.lang.Object#toString()
package tim.prune.data;
+import tim.prune.config.Config;
+
/**
* Class to provide distance constants and functions
*/
public abstract class Distance
{
- /** distance units */
- public enum Units
- {
- /** Kilometres */
- KILOMETRES,
- /** Miles */
- MILES,
- /** Metres */
- METRES,
- /** Feet */
- FEET
- }
-
// Geographical constants
- private static final double EARTH_RADIUS_KM = 6372.795;
- // Conversion constants
- private static final double CONVERT_KM_TO_MILES = 0.621371192;
+ /** Earth radius in metres */
+ private static final double EARTH_RADIUS_M = 6372795.0;
/**
* Convert the given angle in radians into a distance
* @param inAngDist angular distance in radians
- * @param inUnits desired units, eg miles or km
- * @return distance in specified format
+ * @return distance in currently configured distance units
*/
- public static double convertRadiansToDistance(double inAngDist, Units inUnits)
+ public static double convertRadiansToDistance(double inAngDist)
+ {
+ return convertRadiansToDistance(inAngDist, Config.getUnitSet().getDistanceUnit());
+ }
+
+ /**
+ * Convert the given angle in radians into a distance
+ * @param inAngDist angular distance in radians
+ * @param inUnit distance units
+ * @return distance in specified distance units
+ */
+ public static double convertRadiansToDistance(double inAngDist, Unit inUnit)
{
// Multiply by appropriate factor
- if (inUnits == Units.MILES)
- return inAngDist * EARTH_RADIUS_KM * CONVERT_KM_TO_MILES;
- else if (inUnits == Units.METRES)
- return inAngDist * EARTH_RADIUS_KM * 1000;
- // default kilometres
- return inAngDist * EARTH_RADIUS_KM;
+ return inAngDist * EARTH_RADIUS_M * inUnit.getMultFactorFromStd();
}
/**
* Convert the given distance into an angle in radians
- * @param inDist distance to convert
- * @param inUnits units, eg miles or km
+ * @param inDist distance to convert in the current distance units
* @return angular distance in radians
*/
- public static double convertDistanceToRadians(double inDist, Units inUnits)
+ public static double convertDistanceToRadians(double inDist)
{
- // Divide by appropriate factor
- if (inUnits == Units.MILES)
- return inDist / EARTH_RADIUS_KM / CONVERT_KM_TO_MILES;
- else if (inUnits == Units.METRES)
- return inDist / EARTH_RADIUS_KM / 1000;
- // default kilometres
- return inDist / EARTH_RADIUS_KM;
+ return convertDistanceToRadians(inDist, Config.getUnitSet().getDistanceUnit());
}
/**
- * Convert the given distance from metres to miles
- * @param inMetres number of metres
- * @return number of miles
+ * Convert the given distance into an angle in radians
+ * @param inDist distance to convert in the current distance units
+ * @param inUnit distance unit
+ * @return angular distance in radians
*/
- public static double convertMetresToMiles(double inMetres)
+ public static double convertDistanceToRadians(double inDist, Unit inUnit)
{
- return inMetres / 1000.0 * CONVERT_KM_TO_MILES;
+ // Divide by appropriate factor
+ return inDist / EARTH_RADIUS_M / inUnit.getMultFactorFromStd();
}
}
public static final Field DESCRIPTION = new Field("fieldname.description", true);
public static final Field NEW_SEGMENT = new Field("fieldname.newsegment", true);
+ public static final Field SPEED = new Field("fieldname.speed", true);
+ public static final Field VERTICAL_SPEED = new Field("fieldname.verticalspeed", true);
+
// TODO: Field for photo filename, ability to load (from text) and save (to text)
+ /** List of all the available fields */
private static final Field[] ALL_AVAILABLE_FIELDS = {
LATITUDE, LONGITUDE, ALTITUDE, TIMESTAMP, WAYPT_NAME, WAYPT_TYPE, DESCRIPTION, NEW_SEGMENT,
+ SPEED, VERTICAL_SPEED,
new Field(I18nManager.getText("fieldname.custom"))
};
public boolean hasUncorrelatedMedia()
{
for (MediaObject m : _media) {
- if (m.getDataPoint() == null) {
+ if (m.getDataPoint() == null && m.hasTimestamp()) {
return true;
}
}
return _url;
}
+ /**
+ * @return the full path to the media, either filename or url
+ */
+ public String getFullPath()
+ {
+ if (_file != null) return _file.getAbsolutePath();
+ return getUrl();
+ }
+
/**
* @return true if details are valid (might not have timestamp)
*/
--- /dev/null
+package tim.prune.data;
+
+/**
+ * Class to hold information about the mid-points between
+ * adjacent track points. Used by the MapCanvas for creating
+ * points by dragging.
+ */
+public class MidpointData
+{
+ // track object
+ private Track _track = null;
+ // Scaled x, y values
+ private double[] _xValues = null;
+ private double[] _yValues = null;
+ // Validity flags
+ private boolean[] _valids = null;
+ // Flag to set data stale
+ private boolean _needRefresh = true;
+
+
+ /**
+ * Flag the data as needing to be updated
+ * @param inTrack track object from which to get the data
+ */
+ public void updateData(Track inTrack)
+ {
+ _track = inTrack;
+ _needRefresh = true;
+ }
+
+ /**
+ * Update the arrays of data from the track
+ */
+ private synchronized void updateData()
+ {
+ _needRefresh = false;
+ if (_track == null) return;
+ // Make arrays the right size
+ final int numPoints = _track.getNumPoints();
+ if (_xValues == null || _xValues.length != numPoints)
+ {
+ _xValues = new double[numPoints];
+ _yValues = new double[numPoints];
+ _valids = new boolean[numPoints];
+ }
+ if (numPoints <= 0) return;
+ _valids[0] = false;
+
+ // Loop over the points in the track
+ for (int i=1; i<numPoints; i++)
+ {
+ boolean pointValid = false;
+ DataPoint point = _track.getPoint(i);
+ if (point != null && !point.getSegmentStart() && !point.isWaypoint())
+ {
+ _xValues[i] = (_track.getX(i) + _track.getX(i-1)) / 2.0;
+ _yValues[i] = (_track.getY(i) + _track.getY(i-1)) / 2.0;
+ pointValid = true;
+ }
+ _valids[i] = pointValid;
+ }
+ }
+
+ /**
+ * Find the nearest point to the specified x and y coordinates
+ * or -1 if no point is within the specified max distance
+ * @param inX x coordinate
+ * @param inY y coordinate
+ * @param inMaxDist maximum distance from selected coordinates
+ * @return index of nearest point or -1 if not found
+ */
+ public int getNearestPointIndex(double inX, double inY, double inMaxDist)
+ {
+ if (_track == null) return -1;
+ if (_needRefresh) updateData();
+ final int numPoints = _track.getNumPoints();
+ int nearestPoint = 0;
+ double nearestDist = -1.0;
+ double currDist;
+ for (int i=1; i < numPoints; i++)
+ {
+ if (_valids[i])
+ {
+ currDist = Math.abs(_xValues[i] - inX) + Math.abs(_yValues[i] - inY);
+ if (currDist < nearestDist || nearestDist < 0.0)
+ {
+ nearestPoint = i;
+ nearestDist = currDist;
+ }
+ }
+ }
+ // Check whether it's within required distance
+ if (nearestDist > inMaxDist && inMaxDist > 0.0) {
+ return -1;
+ }
+ return nearestPoint;
+ }
+}
DataPoint p2 = new DataPoint(new Latitude(latRange.getMaximum(), Coordinate.FORMAT_DEG),
new Longitude(_lonMedian, Coordinate.FORMAT_DEG), null);
double horizDist = Distance.convertRadiansToDistance(
- DataPoint.calculateRadiansBetween(p1, p2), Distance.Units.METRES);
+ DataPoint.calculateRadiansBetween(p1, p2), UnitSetLibrary.UNITS_METRES); // both in m
_altFactor = 1.0 / horizDist;
// create new arrays for scaled values
public boolean isSameFile(RecentFile inOther)
{
return inOther != null && isValid() && inOther.isValid()
- && _file.equals(inOther._file);
+ && (_file.equals(inOther._file) || _file.getAbsolutePath().equals(inOther._file.getAbsolutePath()));
+ // Note that the file.equals should be sufficient but sometimes it returns false even if the absolute paths are identical
}
}
private int _startIndex = -1, _endIndex = -1;
private int _currentPhotoIndex = -1;
private int _currentAudioIndex = -1;
- private IntegerRange _altitudeRange = null;
- private int _climb = -1, _descent = -1;
- private Altitude.Format _altitudeFormat = Altitude.Format.NO_FORMAT;
+ private AltitudeRange _altitudeRange = null;
private long _totalSeconds = 0L, _movingSeconds = 0L;
private double _angDistance = -1.0, _angMovingDistance = -1.0;
private int _numSegments = 0;
*/
private void recalculate()
{
- _altitudeFormat = Altitude.Format.NO_FORMAT;
_numSegments = 0;
final int numPoints = _track.getNumPoints();
// Recheck if the number of points has changed
}
if (numPoints > 0 && hasRangeSelected())
{
- _altitudeRange = new IntegerRange();
- _climb = 0;
- _descent = 0;
+ _altitudeRange = new AltitudeRange();
Altitude altitude = null;
Timestamp time = null, startTime = null, endTime = null;
Timestamp previousTime = null;
DataPoint lastPoint = null, currPoint = null;
_angDistance = 0.0; _angMovingDistance = 0.0;
_totalSeconds = 0L; _movingSeconds = 0L;
- int altValue = 0;
- int lastAltValue = 0;
- boolean foundAlt = false;
+ // Loop over points in selection
for (int i=_startIndex; i<=_endIndex; i++)
{
currPoint = _track.getPoint(i);
// Ignore waypoints in altitude calculations
if (!currPoint.isWaypoint() && altitude.isValid())
{
- altValue = altitude.getValue(_altitudeFormat);
- if (_altitudeFormat == Altitude.Format.NO_FORMAT)
- _altitudeFormat = altitude.getFormat();
- _altitudeRange.addValue(altValue);
- if (foundAlt)
- {
- if (altValue > lastAltValue)
- _climb += (altValue - lastAltValue);
- else
- _descent += (lastAltValue - altValue);
- }
- lastAltValue = altValue;
- foundAlt = true;
+ _altitudeRange.addValue(altitude);
}
// Store the first and last timestamp in the range
time = currPoint.getTimestamp();
return _endIndex;
}
-
- /**
- * @return the altitude format, ie feet or metres
- */
- public Altitude.Format getAltitudeFormat()
- {
- return _altitudeFormat;
- }
-
/**
* @return altitude range
*/
- public IntegerRange getAltitudeRange()
+ public AltitudeRange getAltitudeRange()
{
if (!_valid) recalculate();
return _altitudeRange;
}
- /**
- * @return climb
- */
- public int getClimb()
- {
- if (!_valid) recalculate();
- return _climb;
- }
-
- /**
- * @return descent
- */
- public int getDescent()
- {
- if (!_valid) recalculate();
- return _descent;
- }
-
-
/**
* @return number of seconds spanned by selection
*/
}
/**
- * @param inUnits distance units to use, from class Distance
* @return distance of Selection in specified units
*/
- public double getDistance(Distance.Units inUnits)
+ public double getDistance()
{
- return Distance.convertRadiansToDistance(_angDistance, inUnits);
+ return Distance.convertRadiansToDistance(_angDistance);
}
/**
- * @param inUnits distance units to use, from class Distance
- * @return moving distance of Selection in specified units
+ * @return moving distance of Selection in current units
*/
- public double getMovingDistance(Distance.Units inUnits)
+ public double getMovingDistance()
{
- return Distance.convertRadiansToDistance(_angMovingDistance, inUnits);
+ return Distance.convertRadiansToDistance(_angMovingDistance);
}
/**
--- /dev/null
+package tim.prune.data;
+
+import tim.prune.config.Config;
+
+/**
+ * Abstract class to hold static calculation functions
+ * for speed (and vertical speed)
+ */
+public abstract class SpeedCalculator
+{
+ /**
+ * Calculate the speed value of the track at the specified index
+ * @param inTrack track object
+ * @param inIndex index of point to calculate speed for
+ * @param inValue object in which to place result of calculation
+ */
+ public static void calculateSpeed(Track inTrack, int inIndex, SpeedValue inValue)
+ {
+ if (inTrack == null || inIndex < 0 || inValue == null) {
+ System.err.println("Cannot calculate speed for index " + inIndex);
+ return;
+ }
+ inValue.setInvalid();
+
+ DataPoint point = inTrack.getPoint(inIndex);
+ if (point == null) {return;}
+ boolean pointHasSpeed = false;
+ double speedValue = 0.0;
+
+ // First, see if point has a speed value already
+ // FIXME: How do we know what units this speed is in? m/s or mph or km/h or what?
+ String speedStr = point.getFieldValue(Field.SPEED);
+ try {
+ speedValue = Double.parseDouble(speedStr);
+ pointHasSpeed = true;
+ }
+ catch (Exception e) {} // ignore, leave pointHasSpeed false
+
+ // otherwise, see if we can calculate it from the timestamps
+ if (!pointHasSpeed && point.hasTimestamp() && !point.isWaypoint())
+ {
+ double totalRadians = 0.0;
+ int index = inIndex-1;
+ DataPoint p = null;
+ DataPoint q = point;
+ Timestamp earlyStamp = point.getTimestamp();
+ boolean stop = false;
+
+ // Count backwards until timestamp earlier than now; total distances back to this point
+ if (!point.getSegmentStart())
+ {
+ do
+ {
+ p = inTrack.getPoint(index);
+ boolean timeOk = p != null && p.hasTimestamp() && !p.getTimestamp().isAfter(point.getTimestamp());
+ boolean pValid = timeOk && !p.isWaypoint();
+ if (pValid) {
+ totalRadians += DataPoint.calculateRadiansBetween(p, q);
+ earlyStamp = p.getTimestamp();
+ }
+ stop = (p == null) || (p.hasTimestamp() && !p.getTimestamp().isEqual(point.getTimestamp())
+ || p.getSegmentStart());
+ index--;
+ if (p != null && !p.isWaypoint()) {
+ q = p;
+ }
+ }
+ while (!stop);
+ }
+ // Count forwards until timestamp later than now; total distances forward to this point
+ Timestamp lateStamp = point.getTimestamp();
+ q = point;
+ index = inIndex+1;
+ do
+ {
+ p = inTrack.getPoint(index);
+ boolean timeOk = p != null && p.hasTimestamp() && !p.getTimestamp().isBefore(point.getTimestamp());
+ boolean pValid = timeOk && !p.isWaypoint() && !p.getSegmentStart();
+ if (pValid) {
+ totalRadians += DataPoint.calculateRadiansBetween(p, q);
+ lateStamp = p.getTimestamp();
+ }
+ stop = (p == null) || (p.hasTimestamp() && !p.getTimestamp().isEqual(point.getTimestamp())
+ || p.getSegmentStart());
+ index++;
+ if (p != null && !p.isWaypoint()) {
+ q = p;
+ }
+ }
+ while (!stop);
+
+ // See if we've managed to get a time range of at least a second
+ long milliseconds = lateStamp.getMillisecondsSince(earlyStamp);
+ if (milliseconds >= 1000L)
+ {
+ double dist = Distance.convertRadiansToDistance(totalRadians);
+ // Store the value and maintain max and min values
+ speedValue = dist / milliseconds * 1000.0 * 60.0 * 60.0; // convert from per millisec to per hour
+ pointHasSpeed = true;
+ }
+ }
+ // Did we get a value?
+ if (pointHasSpeed)
+ {
+ inValue.setValue(speedValue);
+ }
+ // otherwise, just leave value as invalid
+ }
+
+
+ /**
+ * Calculate the vertical speed value of the track at the specified index
+ * @param inTrack track object
+ * @param inIndex index of point to calculate speed for
+ * @param inValue object in which to place the result of calculation
+ */
+ public static void calculateVerticalSpeed(Track inTrack, int inIndex, SpeedValue inValue)
+ {
+ if (inTrack == null || inIndex < 0 || inValue == null) {
+ System.err.println("Cannot calculate vert speed for index " + inIndex);
+ return;
+ }
+ inValue.setInvalid();
+
+ DataPoint point = inTrack.getPoint(inIndex);
+ boolean pointHasSpeed = false;
+ double speedValue = 0.0;
+
+ // First, see if point has a speed value already
+ if (point != null)
+ {
+ // FIXME: Can we assume m/s or ft/s?
+ String speedStr = point.getFieldValue(Field.VERTICAL_SPEED);
+ try {
+ speedValue = Double.parseDouble(speedStr);
+ pointHasSpeed = true;
+ }
+ catch (Exception e) {} // ignore, leave pointHasSpeed false
+ }
+ // otherwise, see if we can calculate it from the heights and timestamps
+ if (!pointHasSpeed
+ && point != null && point.hasTimestamp() && point.hasAltitude() && !point.isWaypoint())
+ {
+ int index = inIndex-1;
+ DataPoint p = null;
+ Timestamp earlyStamp = point.getTimestamp();
+ Altitude firstAlt = point.getAltitude();
+ boolean stop = false;
+
+ // Count backwards until timestamp earlier than now
+ if (!point.getSegmentStart())
+ {
+ do
+ {
+ p = inTrack.getPoint(index);
+ boolean timeOk = p != null && p.hasTimestamp() && !p.getTimestamp().isAfter(point.getTimestamp());
+ boolean pValid = timeOk && !p.isWaypoint();
+ if (pValid) {
+ earlyStamp = p.getTimestamp();
+ if (p.hasAltitude()) firstAlt = p.getAltitude();
+ }
+ stop = (p == null) || (p.hasTimestamp() && !p.getTimestamp().isEqual(point.getTimestamp())
+ || p.getSegmentStart());
+ index--;
+ }
+ while (!stop);
+ }
+
+ // Count forwards until timestamp later than now
+ Timestamp lateStamp = point.getTimestamp();
+ Altitude lastAlt = point.getAltitude();
+ index = inIndex+1;
+ do
+ {
+ p = inTrack.getPoint(index);
+ boolean timeOk = p != null && p.hasTimestamp() && !p.getTimestamp().isBefore(point.getTimestamp());
+ boolean pValid = timeOk && !p.isWaypoint() && !p.getSegmentStart();
+ if (pValid) {
+ lateStamp = p.getTimestamp();
+ if (p.hasAltitude()) lastAlt = p.getAltitude();
+ }
+ stop = (p == null) || (p.hasTimestamp() && !p.getTimestamp().isEqual(point.getTimestamp())
+ || p.getSegmentStart());
+ index++;
+ }
+ while (!stop);
+
+ // See if we've managed to get a non-zero time range
+ long milliseconds = lateStamp.getMillisecondsSince(earlyStamp);
+ if (milliseconds >= 1000L)
+ {
+ double altDiff = (lastAlt.getMetricValue() - firstAlt.getMetricValue())
+ * Config.getUnitSet().getVerticalSpeedUnit().getMultFactorFromStd();
+ speedValue = altDiff / milliseconds * 1000.0; // units are feet/sec or metres/sec
+ pointHasSpeed = true;
+ }
+ }
+ // Check whether we got a value from either method
+ if (pointHasSpeed)
+ {
+ inValue.setValue(speedValue);
+ }
+ }
+}
--- /dev/null
+package tim.prune.data;
+
+/**
+ * Holder for a speed value, including a boolean valid flag
+ */
+public class SpeedValue
+{
+ /** Valid flag */
+ private boolean _valid = false;
+ /** Value as a double, using current units */
+ private double _value = 0.0;
+
+
+ /**
+ * Set the flag to invalid
+ */
+ public void setInvalid()
+ {
+ _valid = false;
+ _value = 0.0;
+ }
+
+ /**
+ * @param inValue speed value to set
+ */
+ public void setValue(double inValue)
+ {
+ _valid = true;
+ _value = inValue;
+ }
+
+ /**
+ * @return true if value is valid
+ */
+ public boolean isValid() {
+ return _valid;
+ }
+
+ /**
+ * @return numeric value
+ */
+ public double getValue() {
+ return _value;
+ }
+}
public class Timestamp
{
private boolean _valid = false;
- private long _seconds = 0L;
+ private long _milliseconds = 0L;
private String _text = null;
private String _timeText = null;
private static final DateFormat ISO_8601_FORMAT_NOZ = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss");
private static DateFormat[] ALL_DATE_FORMATS = null;
private static Calendar CALENDAR = null;
+ private static final Pattern ISO8601_FRACTIONAL_PATTERN
+ = Pattern.compile("(\\d{4})-(\\d{2})-(\\d{2})T(\\d{2}):(\\d{2}):(\\d{2})\\.(\\d{1,3})Z?");
private static final Pattern GENERAL_TIMESTAMP_PATTERN
= Pattern.compile("(\\d{4})\\D(\\d{2})\\D(\\d{2})\\D(\\d{2})\\D(\\d{2})\\D(\\d{2})");
private static long SECS_SINCE_1970 = 0L;
/** Specifies ISO 8601 timestamp format */
public static final int FORMAT_ISO_8601 = 2;
+ /** Identifier for the parsing strategy to use */
+ private enum ParseType
+ {
+ NONE,
+ ISO8601_FRACTIONAL,
+ LONG,
+ FIXED_FORMAT0,
+ FIXED_FORMAT1,
+ FIXED_FORMAT2,
+ FIXED_FORMAT3,
+ FIXED_FORMAT4,
+ FIXED_FORMAT5,
+ FIXED_FORMAT6,
+ GENERAL_STRING
+ }
+
+ /** Array of parse types to loop through (first one is changed to last successful type) */
+ private static ParseType[] ALL_PARSE_TYPES = {ParseType.NONE, ParseType.ISO8601_FRACTIONAL, ParseType.LONG,
+ ParseType.FIXED_FORMAT0, ParseType.FIXED_FORMAT1, ParseType.FIXED_FORMAT2, ParseType.FIXED_FORMAT3,
+ ParseType.FIXED_FORMAT4, ParseType.FIXED_FORMAT5, ParseType.FIXED_FORMAT6, ParseType.GENERAL_STRING};
+
// Static block to initialise offsets
static
{
*/
public Timestamp(String inString)
{
- // TODO: Does it really help to store timestamps in seconds rather than ms?
+ _valid = false;
if (inString != null && !inString.equals(""))
{
- // Try to parse into a long
- try
+ // Try each of the parse types in turn
+ for (ParseType type : ALL_PARSE_TYPES)
{
- long rawValue = Long.parseLong(inString.trim());
- _seconds = getSeconds(rawValue);
- _valid = true;
+ if (parseString(inString, type))
+ {
+ ALL_PARSE_TYPES[0] = type;
+ _valid = true;
+ return;
+ }
}
- catch (NumberFormatException nfe)
- {
- // String is not a long, so try a date/time string instead
- // try each of the date formatters in turn
- Date date = null;
- for (int i=0; i<ALL_DATE_FORMATS.length && !_valid; i++)
+ }
+ }
+
+ /**
+ * Try to parse the given string in the specified way
+ * @param inString String to parse
+ * @param inType parse type to use
+ * @return true if successful
+ */
+ private boolean parseString(String inString, ParseType inType)
+ {
+ if (inString == null || inString.equals("")) {
+ return false;
+ }
+ switch (inType)
+ {
+ case NONE: return false;
+ case LONG:
+ // Try to parse into a long
+ try
{
- try
- {
- date = ALL_DATE_FORMATS[i].parse(inString);
- CALENDAR.setTime(date);
- _seconds = CALENDAR.getTimeInMillis() / 1000L;
- _valid = true;
+ long rawValue = Long.parseLong(inString.trim());
+ _milliseconds = getMilliseconds(rawValue);
+ return true;
+ }
+ catch (NumberFormatException nfe)
+ {}
+ break;
+
+ case ISO8601_FRACTIONAL:
+ final Matcher fmatcher = ISO8601_FRACTIONAL_PATTERN.matcher(inString);
+ if (fmatcher.matches())
+ {
+ try {
+ _milliseconds = getMilliseconds(Integer.parseInt(fmatcher.group(1)), // year
+ Integer.parseInt(fmatcher.group(2)), // month
+ Integer.parseInt(fmatcher.group(3)), // day
+ Integer.parseInt(fmatcher.group(4)), // hour
+ Integer.parseInt(fmatcher.group(5)), // minute
+ Integer.parseInt(fmatcher.group(6)), // second
+ fmatcher.group(7)); // fractional seconds
+ return true;
}
- catch (ParseException e) {}
+ catch (NumberFormatException nfe) {}
}
- if (!_valid && inString.length() == 19)
+ break;
+
+ case FIXED_FORMAT0: return parseString(inString, ALL_DATE_FORMATS[0]);
+ case FIXED_FORMAT1: return parseString(inString, ALL_DATE_FORMATS[1]);
+ case FIXED_FORMAT2: return parseString(inString, ALL_DATE_FORMATS[2]);
+ case FIXED_FORMAT3: return parseString(inString, ALL_DATE_FORMATS[3]);
+ case FIXED_FORMAT4: return parseString(inString, ALL_DATE_FORMATS[4]);
+ case FIXED_FORMAT5: return parseString(inString, ALL_DATE_FORMATS[5]);
+ case FIXED_FORMAT6: return parseString(inString, ALL_DATE_FORMATS[6]);
+
+ case GENERAL_STRING:
+ if (inString.length() == 19)
{
final Matcher matcher = GENERAL_TIMESTAMP_PATTERN.matcher(inString);
if (matcher.matches())
{
try {
- _seconds = getSeconds(Integer.parseInt(matcher.group(1)),
+ _milliseconds = getMilliseconds(Integer.parseInt(matcher.group(1)),
Integer.parseInt(matcher.group(2)),
Integer.parseInt(matcher.group(3)),
Integer.parseInt(matcher.group(4)),
Integer.parseInt(matcher.group(5)),
- Integer.parseInt(matcher.group(6)));
- _valid = true;
+ Integer.parseInt(matcher.group(6)),
+ null); // no fractions of a second
+ return true;
}
catch (NumberFormatException nfe2) {} // parse shouldn't fail if matcher matched
}
}
- }
+ return false;
}
+ return false;
+ }
+
+
+ /**
+ * Try to parse the given string with the given date format
+ * @param inString String to parse
+ * @param inDateFormat Date format to use
+ * @return true if successful
+ */
+ private boolean parseString(String inString, DateFormat inDateFormat)
+ {
+ try
+ {
+ Date date = inDateFormat.parse(inString);
+ CALENDAR.setTime(date);
+ _milliseconds = CALENDAR.getTimeInMillis();
+ return true;
+ }
+ catch (ParseException e) {}
+ return false;
}
*/
public Timestamp(int inYear, int inMonth, int inDay, int inHour, int inMinute, int inSecond)
{
- _seconds = getSeconds(inYear, inMonth, inDay, inHour, inMinute, inSecond);
+ _milliseconds = getMilliseconds(inYear, inMonth, inDay, inHour, inMinute, inSecond, null);
_valid = true;
}
*/
public Timestamp(long inMillis)
{
- _seconds = inMillis / 1000;
+ _milliseconds = inMillis;
_valid = true;
}
/**
- * Convert the given timestamp parameters into a number of seconds
+ * Convert the given timestamp parameters into a number of milliseconds
* @param inYear year
* @param inMonth month, beginning with 1
* @param inDay day of month, beginning with 1
* @param inHour hour of day, 0-24
* @param inMinute minute
* @param inSecond seconds
- * @return number of seconds
+ * @param inFraction fractions of a second
+ * @return number of milliseconds
*/
- private static long getSeconds(int inYear, int inMonth, int inDay, int inHour, int inMinute, int inSecond)
+ private static long getMilliseconds(int inYear, int inMonth, int inDay,
+ int inHour, int inMinute, int inSecond, String inFraction)
{
Calendar cal = Calendar.getInstance();
cal.set(Calendar.YEAR, inYear);
cal.set(Calendar.HOUR_OF_DAY, inHour);
cal.set(Calendar.MINUTE, inMinute);
cal.set(Calendar.SECOND, inSecond);
- cal.set(Calendar.MILLISECOND, 0);
- return cal.getTimeInMillis() / 1000;
+ int millis = 0;
+ if (inFraction != null)
+ {
+ try {
+ int frac = Integer.parseInt(inFraction);
+ final int fracLen = inFraction.length();
+ switch (fracLen) {
+ case 1: millis = frac * 100; break;
+ case 2: millis = frac * 10; break;
+ case 3: millis = frac; break;
+ }
+ }
+ catch (NumberFormatException nfe) {} // ignore errors, millis stay at 0
+ }
+ cal.set(Calendar.MILLISECOND, millis);
+ return cal.getTimeInMillis();
}
/**
- * Convert the given long parameters into a number of seconds
+ * Convert the given long parameters into a number of millisseconds
* @param inRawValue long value representing seconds / milliseconds
- * @return number of seconds
+ * @return number of milliseconds
*/
- private static long getSeconds(long inRawValue)
+ private static long getMilliseconds(long inRawValue)
{
// check for each format possibility and pick nearest
long diff1 = Math.abs(SECS_SINCE_1970 - inRawValue);
// Start off with "seconds since 1970" format
long smallestDiff = diff1;
- long seconds = inRawValue;
+ long millis = inRawValue * 1000;
// Now check millis since 1970
if (diff2 < smallestDiff)
{
// milliseconds since 1970
- seconds = inRawValue / 1000L;
+ millis = inRawValue;
smallestDiff = diff2;
}
// Now millis since 1990
if (diff3 < smallestDiff)
{
// milliseconds since 1990
- seconds = inRawValue / 1000L + TWENTY_YEARS_IN_SECS;
+ millis = inRawValue + TWENTY_YEARS_IN_SECS * 1000L;
smallestDiff = diff3;
}
// Lastly, check gartrip offset
if (diff4 < smallestDiff)
{
// seconds since gartrip offset
- seconds = inRawValue + GARTRIP_OFFSET;
+ millis = (inRawValue + GARTRIP_OFFSET) * 1000L;
}
- return seconds;
+ return millis;
}
/**
/**
* @param inOther other Timestamp
- * @return true if this one is after the other
+ * @return true if this one is at least a second after the other
*/
public boolean isAfter(Timestamp inOther)
{
- return _seconds > inOther._seconds;
+ return getSecondsSince(inOther) > 0L;
}
/**
*/
public long getSecondsSince(Timestamp inOther)
{
- return _seconds - inOther._seconds;
+ return (_milliseconds - inOther._milliseconds) / 1000L;
+ }
+
+ /**
+ * Calculate the difference between two Timestamps in milliseconds
+ * @param inOther other, earlier Timestamp
+ * @return number of millisseconds since other timestamp
+ */
+ public long getMillisecondsSince(Timestamp inOther)
+ {
+ return _milliseconds - inOther._milliseconds;
+ }
+
+ /**
+ * @param inOther other timestamp to compare
+ * @return true if they're equal to the nearest second
+ */
+ public boolean isEqual(Timestamp inOther)
+ {
+ return getSecondsSince(inOther) == 0L;
+ }
+
+ /**
+ * @param inOther other Timestamp
+ * @return true if this one is before the other
+ */
+ public boolean isBefore(Timestamp inOther)
+ {
+ return getSecondsSince(inOther) < 0L;
}
/**
*/
public void addOffset(long inOffset)
{
- _seconds += inOffset;
+ _milliseconds += (inOffset * 1000L);
_text = null;
}
*/
public Timestamp createPlusOffset(long inSeconds)
{
- return new Timestamp((_seconds + inSeconds) * 1000L);
+ return new Timestamp(_milliseconds + (inSeconds * 1000L));
}
*/
public Timestamp createMinusOffset(TimeDifference inOffset)
{
- return new Timestamp((_seconds - inOffset.getTotalSeconds()) * 1000L);
+ return new Timestamp(_milliseconds - (inOffset.getTotalSeconds() * 1000L));
}
*/
private String format(DateFormat inFormat)
{
- CALENDAR.setTimeInMillis(_seconds * 1000L);
+ CALENDAR.setTimeInMillis(_milliseconds);
return inFormat.format(CALENDAR.getTime());
}
public Calendar getCalendar()
{
Calendar cal = Calendar.getInstance();
- cal.setTimeInMillis(_seconds * 1000L);
+ cal.setTimeInMillis(_milliseconds);
return cal;
}
}
import java.util.List;
import tim.prune.UpdateMessageBroker;
-import tim.prune.config.Config;
import tim.prune.function.edit.FieldEdit;
import tim.prune.function.edit.FieldEditList;
import tim.prune.gui.map.MapUtils;
// Master field list
private FieldList _masterFieldList = null;
// variable ranges
- private AltitudeRange _altitudeRange = null;
private DoubleRange _latRange = null, _longRange = null;
private DoubleRange _xRange = null, _yRange = null;
double latitudeDiff = 0.0, longitudeDiff = 0.0;
double totalAltitude = 0;
int numAltitudes = 0;
- Altitude.Format altFormat = Config.getConfigBoolean(Config.KEY_METRIC_UNITS)?Altitude.Format.METRES:Altitude.Format.FEET;
+ Altitude.Format altFormat = Altitude.Format.NO_FORMAT;
// loop between start and end points
for (int i=inStartIndex; i<= inEndIndex; i++)
{
longitudeDiff += (currPoint.getLongitude().getDouble() - firstLongitude);
if (currPoint.hasAltitude()) {
totalAltitude += currPoint.getAltitude().getValue(altFormat);
+ // Use altitude format of first valid altitude
+ if (altFormat == Altitude.Format.NO_FORMAT)
+ altFormat = currPoint.getAltitude().getFormat();
numAltitudes++;
}
}
return null;
}
-
- /**
- * @return altitude range of points as AltitudeRange object
- */
- public AltitudeRange getAltitudeRange()
- {
- if (!_scaled) scalePoints();
- return _altitudeRange;
- }
-
/**
* @return the number of (valid) points in the track
*/
*/
private void scalePoints()
{
- // Loop through all points in track, to see limits of lat, long and altitude
+ // Loop through all points in track, to see limits of lat, long
_longRange = new DoubleRange();
_latRange = new DoubleRange();
- _altitudeRange = new AltitudeRange();
int p;
_hasWaypoint = false; _hasTrackpoint = false;
for (p=0; p < getNumPoints(); p++)
{
_longRange.addValue(point.getLongitude().getDouble());
_latRange.addValue(point.getLatitude().getDouble());
- if (point.getAltitude().isValid())
- {
- _altitudeRange.addValue(point.getAltitude());
- }
if (point.isWaypoint())
_hasWaypoint = true;
else
{
int nearestPoint = 0;
double nearestDist = -1.0;
- double currDist;
+ double mDist, yDist;
for (int i=0; i < getNumPoints(); i++)
{
if (!inJustTrackPoints || !_dataPoints[i].isWaypoint())
{
- currDist = Math.abs(_xValues[i] - inX) + Math.abs(_yValues[i] - inY);
- if (currDist < nearestDist || nearestDist < 0.0)
+ yDist = Math.abs(_yValues[i] - inY);
+ if (yDist < nearestDist || nearestDist < 0.0)
{
- nearestPoint = i;
- nearestDist = currDist;
+ // y dist is within range, so check x too
+ mDist = yDist + getMinXDist(_xValues[i] - inX);
+ if (mDist < nearestDist || nearestDist < 0.0)
+ {
+ nearestPoint = i;
+ nearestDist = mDist;
+ }
}
}
}
return nearestPoint;
}
+ /**
+ * @param inX x value of point
+ * @return minimum wrapped value
+ */
+ private static final double getMinXDist(double inX)
+ {
+ // TODO: Can use some kind of floor here?
+ return Math.min(Math.min(Math.abs(inX), Math.abs(inX-1.0)), Math.abs(inX+1.0));
+ }
+
/**
* Get the next track point starting from the given index
* @param inStartIndex index to start looking from
return numAudiosAdded;
}
- /**
- * Delete the currently selected range of points
- * @return true if successful
- */
- public boolean deleteRange()
- {
- int startSel = _selection.getStart();
- int endSel = _selection.getEnd();
- boolean answer = _track.deleteRange(startSel, endSel);
- // clear range selection
- _selection.modifyRangeDeleted();
- return answer;
- }
-
-
/**
* Delete the currently selected point
* @return true if point deleted
return true;
}
- /**
- * Interpolate extra points between two selected ones
- * @param inNumPoints num points to insert
- * @return true if successful
- */
- public boolean interpolate(int inNumPoints)
- {
- boolean success = _track.interpolate(_selection.getStart(), inNumPoints);
- if (success) {
- _selection.selectRangeEnd(_selection.getEnd() + inNumPoints);
- }
- return success;
- }
-
/**
* Average selected points to create a new one
// Has the new point got an audio clip?
DataPoint selectedPoint = _track.getPoint(pointIndex);
int audioIndex = _selection.getCurrentAudioIndex();
- if (selectedPoint != null) {
- if (selectedPoint.getAudio() != null) audioIndex = _audioList.getAudioIndex(selectedPoint.getAudio());
+ if (selectedPoint != null && selectedPoint.getAudio() != null) {
+ // New point has an audio, so select it
+ audioIndex = _audioList.getAudioIndex(selectedPoint.getAudio());
}
- else {
- if (selectedPoint != currPoint && currPoint.getAudio() != null) {audioIndex = -1;}
+ else if (currPoint != null && selectedPoint != currPoint && currPoint.getAudio() != null) {
+ // Old point had an audio, so deselect it
+ audioIndex = -1;
}
// give to selection object
_selection.selectPointPhotoAudio(pointIndex, inPhotoIndex, audioIndex);
// Has the new point got a photo?
DataPoint selectedPoint = _track.getPoint(pointIndex);
int photoIndex = _selection.getCurrentPhotoIndex();
- if (selectedPoint != null) {
- if (selectedPoint.getPhoto() != null) photoIndex = _photoList.getPhotoIndex(selectedPoint.getPhoto());
+ if (selectedPoint != null && selectedPoint.getPhoto() != null) {
+ // New point has a photo, so select it
+ photoIndex = _photoList.getPhotoIndex(selectedPoint.getPhoto());
}
- else {
- if (selectedPoint != currPoint && currPoint.getPhoto() != null) {photoIndex = -1;}
+ else if (currPoint != null && selectedPoint != currPoint && currPoint.getPhoto() != null) {
+ // Old point had a photo, so deselect it
+ photoIndex = -1;
}
// give to selection object
_selection.selectPointPhotoAudio(pointIndex, photoIndex, inAudioIndex);
--- /dev/null
+package tim.prune.data;
+
+/**
+ * Class to represent a single distance or speed unit
+ * such as kilometres, mph, feet etc
+ */
+public class Unit
+{
+ private String _nameKey = null;
+ private double _multFactorFromStd = 1.0;
+ private boolean _isStandard = false;
+
+ /**
+ * Unit constructor
+ * @param inNameKey name key
+ * @param inMultFactor multiplication factor from standard units
+ */
+ public Unit(String inNameKey, double inMultFactor)
+ {
+ _nameKey = inNameKey;
+ _multFactorFromStd = inMultFactor;
+ _isStandard = false;
+ }
+
+ /**
+ * Unit constructor for standard unit
+ * @param inNameKey name key
+ */
+ public Unit(String inNameKey)
+ {
+ _nameKey = inNameKey;
+ _multFactorFromStd = 1.0;
+ _isStandard = true;
+ }
+
+ /**
+ * Unit constructor
+ * @param inParent parent unit
+ * @param inSuffix suffix to name key
+ */
+ public Unit(Unit inParent, String inSuffix)
+ {
+ _nameKey = inParent._nameKey + inSuffix;
+ _multFactorFromStd = inParent._multFactorFromStd;
+ _isStandard = inParent._isStandard;
+ }
+
+ /**
+ * @return name key
+ */
+ public String getNameKey() {
+ return "units." + _nameKey;
+ }
+
+ /**
+ * @return shortname key
+ */
+ public String getShortnameKey() {
+ return getNameKey() + ".short";
+ }
+
+ /**
+ * @return multiplication factor from standard units
+ */
+ public double getMultFactorFromStd() {
+ return _multFactorFromStd;
+ }
+
+ /**
+ * @return true if this is the standard unit (mult factor 1.0)
+ */
+ public boolean isStandard() {
+ return _isStandard;
+ }
+}
--- /dev/null
+package tim.prune.data;
+
+/**
+ * Class to hold a set of units for distance, altitude and speed
+ */
+public class UnitSet
+{
+ private String _nameKey = null;
+ private Unit _distanceUnit = null;
+ private Unit _speedUnit = null;
+ private Unit _altitudeUnit = null;
+ private Unit _vertSpeedUnit = null;
+ private Altitude.Format _defaultAltitudeFormat = Altitude.Format.METRES;
+
+ /**
+ * Constructor
+ * @param inNameKey name key
+ * @param inDistanceUnit distance unit
+ * @param inAltitudeUnit altitude unit
+ * @param inAltitudeFormat default altitude format
+ */
+ public UnitSet(String inNameKey, Unit inDistanceUnit,
+ Unit inAltitudeUnit, Altitude.Format inAltitudeFormat)
+ {
+ _nameKey = inNameKey;
+ _distanceUnit = inDistanceUnit;
+ _speedUnit = new Unit(_distanceUnit, "perhour");
+ _altitudeUnit = inAltitudeUnit;
+ _defaultAltitudeFormat = inAltitudeFormat;
+ _vertSpeedUnit = new Unit(_altitudeUnit, "persec");
+ }
+
+ /**
+ * @return name key
+ */
+ public String getNameKey() {
+ return _nameKey;
+ }
+
+ /**
+ * @return distance unit
+ */
+ public Unit getDistanceUnit() {
+ return _distanceUnit;
+ }
+
+ /**
+ * @return speed unit
+ */
+ public Unit getSpeedUnit() {
+ return _speedUnit;
+ }
+
+ /**
+ * @return altitude unit
+ */
+ public Unit getAltitudeUnit() {
+ return _altitudeUnit;
+ }
+
+ /**
+ * @return vertical speed unit
+ */
+ public Unit getVerticalSpeedUnit() {
+ return _vertSpeedUnit;
+ }
+
+ /**
+ * @return default altitude format
+ */
+ public Altitude.Format getDefaultAltitudeFormat() {
+ return _defaultAltitudeFormat;
+ }
+}
--- /dev/null
+package tim.prune.data;
+
+/**
+ * List of all possible unit sets, for example
+ * metric, imperial, nautical
+ */
+public abstract class UnitSetLibrary
+{
+ // Distance units - all conversion factors are from metres
+ /** Units for feet (used for loading and converting values) */
+ public static final Unit UNITS_FEET = new Unit("feet", 3.2808);
+ /** Units for metres */
+ public static final Unit UNITS_METRES = new Unit("metres");
+ /** Units for km */
+ public static final Unit UNITS_KILOMETRES = new Unit("kilometres", 1/1000.0);
+ /** Units for miles */
+ public static final Unit UNITS_MILES = new Unit("miles", 1/1609.3);
+ /** Units for nautical miles */
+ public static final Unit UNITS_NAUTICAL_MILES = new Unit("nauticalmiles", 1/1852.0);
+
+ /** Array of available unit sets */
+ private static UnitSet[] _sets = {
+ new UnitSet("unitset.kilometres", UNITS_KILOMETRES, UNITS_METRES, Altitude.Format.METRES),
+ new UnitSet("unitset.miles", UNITS_MILES, UNITS_FEET, Altitude.Format.FEET),
+ new UnitSet("unitset.nautical", UNITS_NAUTICAL_MILES, UNITS_FEET, Altitude.Format.FEET)
+ };
+
+ /**
+ * @return number of available unit sets
+ */
+ public static int getNumUnitSets() {
+ return _sets.length;
+ }
+
+ /**
+ * Get the specified unit set
+ * @param inIndex index of set starting from 0
+ * @return specified unit set or the default one if index out of range
+ */
+ public static UnitSet getUnitSet(int inIndex)
+ {
+ if (inIndex >= 0 && inIndex < getNumUnitSets()) {
+ return _sets[inIndex];
+ }
+ return _sets[0];
+ }
+
+ /**
+ * Get the unit set specified by the given key
+ * @param inKey key to look for
+ * @return unit set with given key, or default set if key not found
+ */
+ public static UnitSet getUnitSet(String inKey)
+ {
+ // Loop over all available unit sets
+ for (int i=0; i<getNumUnitSets(); i++)
+ {
+ UnitSet set = getUnitSet(i);
+ if (set.getNameKey().equals(inKey)) {
+ return set;
+ }
+ }
+ // Not found in list, so just return the first one
+ return getUnitSet(0);
+ }
+}
import tim.prune.App;
import tim.prune.GenericFunction;
import tim.prune.I18nManager;
+import tim.prune.config.Config;
import tim.prune.data.Altitude;
import tim.prune.data.Field;
_dialog.pack();
}
// Set label according to altitude units
- setLabelText(selStart, selEnd);
+ setLabelText();
// Select the contents of the edit field
_editField.selectAll();
_dialog.setVisible(true);
/**
* Set the label text according to the current units
- * @param inStart start index of selection
- * @param inEnd end index of selection
*/
- private void setLabelText(int inStart, int inEnd)
+ private void setLabelText()
{
- _altFormat = Altitude.Format.NO_FORMAT;
- for (int i=inStart; i<=inEnd && _altFormat==Altitude.Format.NO_FORMAT; i++)
- {
- Altitude alt = _app.getTrackInfo().getTrack().getPoint(i).getAltitude();
- if (alt != null) {
- _altFormat = alt.getFormat();
- }
- }
- if (_altFormat==Altitude.Format.NO_FORMAT) {
+ _altFormat = Altitude.Format.FEET;
+ if (Config.getUnitSet().getAltitudeUnit().isStandard()) {
_altFormat = Altitude.Format.METRES;
}
final String unitKey = (_altFormat==Altitude.Format.METRES?"units.metres.short":"units.feet.short");
--- /dev/null
+package tim.prune.function;
+
+import tim.prune.App;
+import tim.prune.data.Track;
+
+/**
+ * Class to provide the function to crop the track
+ * to the current selection
+ */
+public class CropToSelection extends DeleteBitOfTrackFunction
+{
+ /**
+ * Constructor
+ * @param inApp application object for callback
+ */
+ public CropToSelection(App inApp)
+ {
+ super(inApp);
+ }
+
+ /** Get the name key */
+ public String getNameKey() {
+ return "function.croptrack";
+ }
+
+ /**
+ * @return name key for undo operation
+ */
+ protected String getUndoNameKey() {
+ return "undo.croptrack";
+ }
+
+ /**
+ * Begin the function
+ */
+ public void begin()
+ {
+ // check track
+ Track track = _app.getTrackInfo().getTrack();
+ if (track == null || track.getNumPoints() <= 0) return;
+ // check selection
+ final int selStart = _app.getTrackInfo().getSelection().getStart();
+ final int selEnd = _app.getTrackInfo().getSelection().getEnd();
+ if (selStart < 0 || selEnd < 0 || selEnd <= selStart) return;
+ // check for all selected
+ if (selStart == 0 && selEnd == (track.getNumPoints() - 1)) return;
+
+ // Pass indexes to parent class
+ deleteTwoSections(0, selStart-1, selEnd+1, track.getNumPoints()-1);
+ }
+}
--- /dev/null
+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.data.DataPoint;
+import tim.prune.data.TrackInfo;
+import tim.prune.undo.UndoDeleteRange;
+
+
+/**
+ * Abstract class to hold general deletion routines to delete
+ * either one or two track sections. Forms parent class to
+ * the DeleteSelection and CropToSelection functions
+ */
+public abstract class DeleteBitOfTrackFunction extends GenericFunction
+{
+ /**
+ * Constructor
+ * @param inApp application object for callback
+ */
+ public DeleteBitOfTrackFunction(App inApp)
+ {
+ super(inApp);
+ }
+
+ /**
+ * @return key of undo text
+ */
+ protected abstract String getUndoNameKey();
+
+ /**
+ * Delete a single section
+ * @param inStart1 start index of section
+ * @param inEnd1 end index of section
+ */
+ protected void deleteSection(int inStart1, int inEnd1)
+ {
+ deleteTwoSections(inStart1, inEnd1, -1, -1);
+ }
+
+ /**
+ * Delete the two specified sections
+ * @param inStart1 start index of first section to delete
+ * @param inEnd1 end index of first section
+ * @param inStart2 start index of second section to delete
+ * @param inEnd2 end index of second section
+ */
+ protected void deleteTwoSections(int inStart1, int inEnd1, int inStart2, int inEnd2)
+ {
+ boolean[] deleteAllOrNone = {false, false};
+ // TODO: Check for range overlap? And test!
+ if (inStart1 < 0 || inEnd1 < 0 || inEnd1 < inStart1) {
+ inStart1 = inEnd1 = -1;
+ }
+ if (inStart2 < 0 || inEnd2 < 0 || inEnd2 < inStart2) {
+ inStart2 = inEnd2 = -1;
+ }
+ if ((inStart1 >= 0 && inEnd1 < inStart1)
+ || (inStart2 >= 0 && (inStart2 < inEnd1 || inEnd2 <= inStart2)))
+ {
+ System.err.println("Invalid ranges: (" + inStart1 + " - " + inEnd1 + "), (" + inStart2 + " - " + inEnd2 + ")");
+ return;
+ }
+ // First section (if any)
+ int numPoints = inEnd1 - inStart1 + 1;
+ boolean[] deleteMedia1 = new boolean[numPoints];
+ int numDeleted1 = prepareDeleteMedia(inStart1, inEnd1, deleteAllOrNone, deleteMedia1);
+ if (numDeleted1 < 0) return;
+
+ // Second section (if any)
+ numPoints = inEnd2 - inStart2 + 1;
+ boolean[] deleteMedia2 = new boolean[numPoints];
+ int numDeleted2 = prepareDeleteMedia(inStart2, inEnd2, deleteAllOrNone, deleteMedia2);
+ if (numDeleted2 < 0) return;
+ int numDeleted = numDeleted1 + numDeleted2;
+ if (numDeleted <= 0) return;
+
+ // create undo object
+ UndoDeleteRange undo = new UndoDeleteRange(_app.getTrackInfo(), getUndoNameKey(),
+ inStart1, deleteMedia1, inStart2, deleteMedia2);
+
+ // Loop through media to remove or disconnect
+ if (numDeleted1 > 0) {
+ resolveMedia(_app.getTrackInfo(), inStart1, deleteMedia1);
+ }
+ if (numDeleted2 > 0) {
+ resolveMedia(_app.getTrackInfo(), inStart2, deleteMedia2);
+ }
+
+ // Call track to delete ranges 1 and 2
+ if (numDeleted2 > 0) { // delete range2 first
+ _app.getTrackInfo().getTrack().deleteRange(inStart2, inEnd2);
+ }
+ if (numDeleted1 > 0) { // delete range1 first
+ _app.getTrackInfo().getTrack().deleteRange(inStart1, inEnd1);
+ }
+
+ // clear selection and notify
+ _app.getTrackInfo().getSelection().clearAll();
+ UpdateMessageBroker.informSubscribers(DataSubscriber.DATA_ADDED_OR_REMOVED);
+
+ // pass back to _app
+ _app.completeFunction(undo, "" + numDeleted + " "
+ + I18nManager.getText("confirm.deletepoint.multi"));
+ }
+
+ /**
+ * Prepare to delete the media in the given section, including prompting to delete or not
+ * @param inStart start index of the range to delete
+ * @param inEnd end index
+ * @param inDeleteAllOrNone boolean flags for delete all and delete none, held in an array
+ * @param inDeleteMedia boolean flag for each point, whether to delete media or not
+ * @return number of points to delete
+ */
+ private int prepareDeleteMedia(int inStart, int inEnd, boolean[] inDeleteAllOrNone, boolean[] inDeleteMedia)
+ {
+ // Check sanity of inputs
+ if (inStart < 0 || inEnd < 0 || inEnd < inStart) return 0;
+ final int numPoints = inEnd - inStart + 1;
+ if (inDeleteAllOrNone == null || inDeleteAllOrNone.length != 2
+ || inDeleteMedia == null || inDeleteMedia.length != numPoints) {
+ return 0;
+ }
+
+ // define buttons on prompt
+ String[] questionOptions = {I18nManager.getText("button.yes"), I18nManager.getText("button.no"),
+ I18nManager.getText("button.yestoall"), I18nManager.getText("button.notoall"),
+ I18nManager.getText("button.cancel")};
+
+ // Loop over points to check for media
+ for (int i=0; i<numPoints; i++)
+ {
+ DataPoint point = _app.getTrackInfo().getTrack().getPoint(inStart + i);
+ if (point.hasMedia())
+ {
+ // point has either photo or audio
+ if (inDeleteAllOrNone[0]) // delete all has already been selected
+ {
+ inDeleteMedia[i] = true;
+ }
+ else if (inDeleteAllOrNone[1]) // delete none has already been selected
+ {
+ inDeleteMedia[i] = false;
+ }
+ else
+ {
+ int response = JOptionPane.showOptionDialog(_app.getFrame(),
+ I18nManager.getText("dialog.deletepoint.deletephoto") + " " + point.getMediaName(),
+ I18nManager.getText("dialog.deletepoint.title"),
+ JOptionPane.YES_NO_CANCEL_OPTION, JOptionPane.QUESTION_MESSAGE, null,
+ questionOptions, questionOptions[1]);
+ // check for cancel or close
+ if (response == 4 || response == -1) {return -1;}
+ // check for yes or yes to all
+ if (response == 0 || response == 2)
+ {
+ inDeleteMedia[i] = true;
+ if (response == 2) {inDeleteAllOrNone[0] = true;}
+ }
+ // check for no to all
+ if (response == 3) {inDeleteAllOrNone[1] = true;}
+ }
+ }
+ }
+ return numPoints;
+ }
+
+ /**
+ * Resolve the media from the given points by either detaching or deleting
+ * @param inTrack track object
+ * @param inStart start index of range
+ * @param inDeleteFlags media deletion flags
+ */
+ private static void resolveMedia(TrackInfo inTrackInfo, int inStart, boolean[] inDeleteFlags)
+ {
+ for (int i=0; i<inDeleteFlags.length; i++)
+ {
+ DataPoint point = inTrackInfo.getTrack().getPoint(i + inStart);
+ if (point != null && point.hasMedia())
+ {
+ if (inDeleteFlags[i])
+ {
+ // delete photo and/or audio from lists
+ if (point.getPhoto() != null) {
+ inTrackInfo.getPhotoList().deletePhoto(inTrackInfo.getPhotoList().getPhotoIndex(point.getPhoto()));
+ }
+ if (point.getAudio() != null) {
+ inTrackInfo.getAudioList().deleteAudio(inTrackInfo.getAudioList().getAudioIndex(point.getAudio()));
+ }
+ }
+ else
+ {
+ // decouple photo and/or audio from point
+ if (point.getPhoto() != null) {
+ point.getPhoto().setDataPoint(null);
+ }
+ if (point.getAudio() != null) {
+ point.getAudio().setDataPoint(null);
+ }
+ }
+ }
+ }
+ }
+}
--- /dev/null
+package tim.prune.function;
+
+import tim.prune.App;
+
+/**
+ * Class to provide the function to delete the currently selected range
+ */
+public class DeleteSelectedRangeFunction extends DeleteBitOfTrackFunction
+{
+ /**
+ * Constructor
+ * @param inApp application object for callback
+ */
+ public DeleteSelectedRangeFunction(App inApp)
+ {
+ super(inApp);
+ }
+
+ /** Get the name key */
+ public String getNameKey() {
+ return "function.deleterange";
+ }
+
+ /**
+ * @return name key for undo operation
+ */
+ protected String getUndoNameKey() {
+ return "undo.deleterange";
+ }
+
+ /**
+ * Begin the function
+ */
+ public void begin()
+ {
+ // Get the currently selected range and pass indexes to parent class
+ final int startIndex = _app.getTrackInfo().getSelection().getStart();
+ final int endIndex = _app.getTrackInfo().getSelection().getEnd();
+ deleteSection(startIndex, endIndex);
+ }
+}
I18nManager.getText(getNameKey()), JOptionPane.WARNING_MESSAGE);
return;
}
- // TODO: Check path is writeable too, and give warning if not
+ // Check that the cache path is writable too, and give warning if not
+ if (cacheDir.exists() && cacheDir.isDirectory() && !cacheDir.canWrite())
+ {
+ JOptionPane.showMessageDialog(_dialog, I18nManager.getText("dialog.diskcache.cannotwrite"),
+ I18nManager.getText(getNameKey()), JOptionPane.WARNING_MESSAGE);
+ }
}
Config.setConfigString(Config.KEY_DISK_CACHE, cachePath);
// inform subscribers so that tiles are wiped from memory and refetched
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
+import java.awt.event.KeyAdapter;
+import java.awt.event.KeyEvent;
import java.text.NumberFormat;
import javax.swing.BorderFactory;
import tim.prune.I18nManager;
import tim.prune.config.Config;
import tim.prune.data.Altitude;
-import tim.prune.data.Distance;
+import tim.prune.data.AltitudeRange;
+import tim.prune.data.DataPoint;
import tim.prune.data.Selection;
+import tim.prune.data.Unit;
import tim.prune.gui.DisplayUtils;
import tim.prune.gui.profile.SpeedData;
{
/** Dialog */
private JDialog _dialog = null;
+ /** Label for number of points */
+ private JLabel _numPointsLabel = null;
/** Label for number of segments */
private JLabel _numSegsLabel = null;
- /** Label for pace */
- private JLabel _paceLabel = null;
- /** Label for gradient */
- private JLabel _gradientLabel = null;
- /** Moving distance, speed */
- private JLabel _movingDistanceLabel = null, _aveMovingSpeedLabel = null;
+ /** Label for the maximum speed */
private JLabel _maxSpeedLabel = null;
+
+ /** Label for heading of "total" column */
+ private JLabel _colTotalLabel = null;
+ /** Label for heading of "segments" column */
+ private JLabel _colSegmentsLabel = null;
+ /** Labels for distances */
+ private JLabel _totalDistanceLabel = null, _movingDistanceLabel = null;
+ /** Labels for durations */
+ private JLabel _totalDurationLabel = null, _movingDurationLabel = null;
+ /** Labels for climbs */
+ private JLabel _totalClimbLabel = null, _movingClimbLabel = null;
+ /** Labels for descents */
+ private JLabel _totalDescentLabel = null, _movingDescentLabel = null;
+ /** Labels for pace */
+ private JLabel _totalPaceLabel = null, _movingPaceLabel = null;
+ /** Labels for gradient */
+ private JLabel _totalGradientLabel = null, _movingGradientLabel = null;
+ /** Labels for speed */
+ private JLabel _totalSpeedLabel, _movingSpeedLabel = null;
+ /** Labels for vertical speed */
+ private JLabel _totalVertSpeedLabel, _movingVertSpeedLabel = null;
+
/** Number formatter for one decimal place */
private static final NumberFormat FORMAT_ONE_DP = NumberFormat.getNumberInstance();
/** Flexible number formatter for different decimal places */
JPanel dialogPanel = new JPanel();
dialogPanel.setLayout(new BorderLayout(5, 5));
// Label at top
- JLabel topLabel = new JLabel(I18nManager.getText("dialog.fullrangedetails.intro"));
+ JLabel topLabel = new JLabel(I18nManager.getText("dialog.fullrangedetails.intro") + ":");
topLabel.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
dialogPanel.add(topLabel, BorderLayout.NORTH);
// Details panel in middle
JPanel midPanel = new JPanel();
- midPanel.setLayout(new GridLayout(0, 2, 6, 2));
+ midPanel.setLayout(new GridLayout(0, 3, 6, 2));
midPanel.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 15));
+ // Number of points
+ JLabel pointsLabel = new JLabel(I18nManager.getText("details.track.points") + ": ");
+ pointsLabel.setHorizontalAlignment(JLabel.RIGHT);
+ midPanel.add(pointsLabel);
+ _numPointsLabel = new JLabel("100");
+ midPanel.add(_numPointsLabel);
+ midPanel.add(new JLabel(" "));
// Number of segments
JLabel segLabel = new JLabel(I18nManager.getText("details.range.numsegments") + ": ");
segLabel.setHorizontalAlignment(JLabel.RIGHT);
midPanel.add(segLabel);
_numSegsLabel = new JLabel("100");
midPanel.add(_numSegsLabel);
+ midPanel.add(new JLabel(" "));
+ // Maximum speed
+ JLabel maxSpeedLabel = new JLabel(I18nManager.getText("details.range.maxspeed") + ": ");
+ maxSpeedLabel.setHorizontalAlignment(JLabel.RIGHT);
+ midPanel.add(maxSpeedLabel);
+ _maxSpeedLabel = new JLabel("10 km/h");
+ midPanel.add(_maxSpeedLabel);
+ midPanel.add(new JLabel(" "));
+
+ // blank row
+ for (int i=0; i<3; i++) midPanel.add(new JLabel(" "));
+
+ // Row for column headings
+ midPanel.add(new JLabel(" "));
+ _colTotalLabel = new JLabel(I18nManager.getText("dialog.fullrangedetails.coltotal"));
+ midPanel.add(_colTotalLabel);
+ _colSegmentsLabel = new JLabel(I18nManager.getText("dialog.fullrangedetails.colsegments"));
+ midPanel.add(_colSegmentsLabel);
+
+ // Distance
+ JLabel distLabel = new JLabel(I18nManager.getText("fieldname.distance") + ": ");
+ distLabel.setHorizontalAlignment(JLabel.RIGHT);
+ midPanel.add(distLabel);
+ _totalDistanceLabel = new JLabel("5 km");
+ midPanel.add(_totalDistanceLabel);
+ _movingDistanceLabel = new JLabel("5 km");
+ midPanel.add(_movingDistanceLabel);
+
+ // Duration
+ JLabel durationLabel = new JLabel(I18nManager.getText("fieldname.duration") + ": ");
+ durationLabel.setHorizontalAlignment(JLabel.RIGHT);
+ midPanel.add(durationLabel);
+ _totalDurationLabel = new JLabel("15 min");
+ midPanel.add(_totalDurationLabel);
+ _movingDurationLabel = new JLabel("15 min");
+ midPanel.add(_movingDurationLabel);
+
+ // Speed
+ JLabel speedLabel = new JLabel(I18nManager.getText("details.range.avespeed") + ": ");
+ speedLabel.setHorizontalAlignment(JLabel.RIGHT);
+ midPanel.add(speedLabel);
+ _totalSpeedLabel = new JLabel("5.5 km/h");
+ midPanel.add(_totalSpeedLabel);
+ _movingSpeedLabel = new JLabel("5.5 km/h");
+ midPanel.add(_movingSpeedLabel);
+
// Pace
JLabel paceLabel = new JLabel(I18nManager.getText("details.range.pace") + ": ");
paceLabel.setHorizontalAlignment(JLabel.RIGHT);
midPanel.add(paceLabel);
- _paceLabel = new JLabel("8 min/km");
- midPanel.add(_paceLabel);
+ _totalPaceLabel = new JLabel("8 min/km");
+ midPanel.add(_totalPaceLabel);
+ _movingPaceLabel = new JLabel("8 min/km");
+ midPanel.add(_movingPaceLabel);
+
+ // Climb
+ JLabel climbLabel = new JLabel(I18nManager.getText("details.range.climb") + ": ");
+ climbLabel.setHorizontalAlignment(JLabel.RIGHT);
+ midPanel.add(climbLabel);
+ _totalClimbLabel = new JLabel("1000 m");
+ midPanel.add(_totalClimbLabel);
+ _movingClimbLabel = new JLabel("1000 m");
+ midPanel.add(_movingClimbLabel);
+ // Descent
+ JLabel descentLabel = new JLabel(I18nManager.getText("details.range.descent") + ": ");
+ descentLabel.setHorizontalAlignment(JLabel.RIGHT);
+ midPanel.add(descentLabel);
+ _totalDescentLabel = new JLabel("1000 m");
+ midPanel.add(_totalDescentLabel);
+ _movingDescentLabel = new JLabel("1000 m");
+ midPanel.add(_movingDescentLabel);
+
// Gradient
JLabel gradientLabel = new JLabel(I18nManager.getText("details.range.gradient") + ": ");
gradientLabel.setHorizontalAlignment(JLabel.RIGHT);
midPanel.add(gradientLabel);
- _gradientLabel = new JLabel("10 %");
- midPanel.add(_gradientLabel);
- // Moving distance
- JLabel movingDistLabel = new JLabel(I18nManager.getText("fieldname.movingdistance") + ": ");
- movingDistLabel.setHorizontalAlignment(JLabel.RIGHT);
- midPanel.add(movingDistLabel);
- _movingDistanceLabel = new JLabel("5 km");
- midPanel.add(_movingDistanceLabel);
- // Moving speed
- JLabel movingSpeedLabel = new JLabel(I18nManager.getText("details.range.avemovingspeed") + ": ");
- movingSpeedLabel.setHorizontalAlignment(JLabel.RIGHT);
- midPanel.add(movingSpeedLabel);
- _aveMovingSpeedLabel = new JLabel("5 km/h");
- midPanel.add(_aveMovingSpeedLabel);
- // Maximum speed
- JLabel maxSpeedLabel = new JLabel(I18nManager.getText("details.range.maxspeed") + ": ");
- maxSpeedLabel.setHorizontalAlignment(JLabel.RIGHT);
- midPanel.add(maxSpeedLabel);
- _maxSpeedLabel = new JLabel("10 km/h");
- midPanel.add(_maxSpeedLabel);
+ _totalGradientLabel = new JLabel("10 %");
+ midPanel.add(_totalGradientLabel);
+ _movingGradientLabel = new JLabel("10 %");
+ midPanel.add(_movingGradientLabel);
+
+ // Vertical speed
+ JLabel vSpeedLabel = new JLabel(I18nManager.getText("fieldname.verticalspeed") + ": ");
+ vSpeedLabel.setHorizontalAlignment(JLabel.RIGHT);
+ midPanel.add(vSpeedLabel);
+ _totalVertSpeedLabel = new JLabel("1 m/s");
+ midPanel.add(_totalVertSpeedLabel);
+ _movingVertSpeedLabel = new JLabel("1 m/s");
+ midPanel.add(_movingVertSpeedLabel);
dialogPanel.add(midPanel, BorderLayout.CENTER);
// button panel at bottom
_dialog.dispose();
}
});
+ closeButton.addKeyListener(new KeyAdapter() {
+ public void keyPressed(KeyEvent inE) {
+ if (inE.getKeyCode() == KeyEvent.VK_ESCAPE) {_dialog.dispose();}
+ super.keyPressed(inE);
+ }
+ });
buttonPanel.add(closeButton);
dialogPanel.add(buttonPanel, BorderLayout.SOUTH);
return dialogPanel;
private void updateDetails()
{
Selection selection = _app.getTrackInfo().getSelection();
+ // Number of points
+ _numPointsLabel.setText("" + (selection.getEnd()-selection.getStart()+1));
// Number of segments
_numSegsLabel.setText("" + selection.getNumSegments());
- // Pace value
- if (selection.getNumSeconds() > 0)
+ final boolean isMultiSegments = (selection.getNumSegments() > 1);
+ // Set visibility of third column accordingly
+ _movingDistanceLabel.setVisible(isMultiSegments);
+ _movingDurationLabel.setVisible(isMultiSegments);
+ _movingClimbLabel.setVisible(isMultiSegments);
+ _movingDescentLabel.setVisible(isMultiSegments);
+ _movingSpeedLabel.setVisible(isMultiSegments);
+ _movingPaceLabel.setVisible(isMultiSegments);
+ _movingGradientLabel.setVisible(isMultiSegments);
+ _movingVertSpeedLabel.setVisible(isMultiSegments);
+
+ // Distance in current units
+ final Unit distUnit = Config.getUnitSet().getDistanceUnit();
+ final String distUnitsStr = I18nManager.getText(distUnit.getShortnameKey());
+ final double selectionDistance = selection.getDistance();
+ _totalDistanceLabel.setText(roundedNumber(selectionDistance) + " " + distUnitsStr);
+
+ // Duration
+ long numSecs = selection.getNumSeconds();
+ _totalDurationLabel.setText(DisplayUtils.buildDurationString(numSecs));
+ // Climb and descent
+ final Unit altUnit = Config.getUnitSet().getAltitudeUnit();
+ final String altUnitsStr = " " + I18nManager.getText(altUnit.getShortnameKey());
+ if (selection.getAltitudeRange().hasRange()) {
+ _totalClimbLabel.setText(selection.getAltitudeRange().getClimb(altUnit) + altUnitsStr);
+ _totalDescentLabel.setText(selection.getAltitudeRange().getDescent(altUnit) + altUnitsStr);
+ }
+ else {
+ _totalClimbLabel.setText("");
+ _totalDescentLabel.setText("");
+ }
+
+ // Overall pace and speed
+ final String speedUnitsStr = I18nManager.getText(Config.getUnitSet().getSpeedUnit().getShortnameKey());
+ if (numSecs > 0 && selectionDistance > 0)
{
- boolean useMetric = Config.getConfigBoolean(Config.KEY_METRIC_UNITS);
- Distance.Units distUnits = useMetric?Distance.Units.KILOMETRES:Distance.Units.MILES;
- String distUnitsStr = I18nManager.getText(useMetric?"units.kilometres.short":"units.miles.short");
- _paceLabel.setText(DisplayUtils.buildDurationString(
- (long) (selection.getNumSeconds()/selection.getDistance(distUnits)))
+ _totalPaceLabel.setText(
+ DisplayUtils.buildDurationString((long) (numSecs/selectionDistance))
+ " / " + distUnitsStr);
+ _totalSpeedLabel.setText(roundedNumber(selectionDistance/numSecs*3600.0)
+ + " " + speedUnitsStr);
}
else {
- _paceLabel.setText("");
+ _totalPaceLabel.setText("");
+ _totalSpeedLabel.setText("");
}
- // Gradient
- Altitude firstAlt = _app.getTrackInfo().getTrack().getPoint(selection.getStart()).getAltitude();
- Altitude lastAlt = _app.getTrackInfo().getTrack().getPoint(selection.getEnd()).getAltitude();
- double metreDist = selection.getDistance(Distance.Units.METRES);
- if (firstAlt.isValid() && lastAlt.isValid() && metreDist > 0.0)
+
+ // Moving distance
+ double movingDist = selection.getMovingDistance();
+ _movingDistanceLabel.setText(roundedNumber(movingDist) + " " + distUnitsStr);
+ // Moving average speed
+ long numMovingSecs = selection.getMovingSeconds();
+ if (numMovingSecs > 0)
+ {
+ _movingDurationLabel.setText(DisplayUtils.buildDurationString(numMovingSecs));
+ _movingSpeedLabel.setText(roundedNumber(movingDist/numMovingSecs*3600.0)
+ + " " + speedUnitsStr);
+ _movingPaceLabel.setText(
+ DisplayUtils.buildDurationString((long) (numMovingSecs/movingDist))
+ + " / " + distUnitsStr);
+ }
+ else
+ {
+ _movingDurationLabel.setText("");
+ _movingSpeedLabel.setText("");
+ _movingPaceLabel.setText("");
+ }
+
+ // Moving gradient and moving climb/descent
+ Altitude firstAlt = null, lastAlt = null;
+ Altitude veryFirstAlt = null, veryLastAlt = null;
+ AltitudeRange altRange = new AltitudeRange();
+ double movingHeightDiff = 0.0;
+ if (movingDist > 0.0)
+ {
+ for (int pNum = selection.getStart(); pNum <= selection.getEnd(); pNum++)
+ {
+ DataPoint p = _app.getTrackInfo().getTrack().getPoint(pNum);
+ if (p != null && !p.isWaypoint())
+ {
+ // If we're starting a new segment, calculate the height diff of the previous one
+ if (p.getSegmentStart())
+ {
+ if (firstAlt != null && firstAlt.isValid() && lastAlt != null && lastAlt.isValid())
+ movingHeightDiff = movingHeightDiff + lastAlt.getMetricValue() - firstAlt.getMetricValue();
+ firstAlt = null; lastAlt = null;
+ }
+ Altitude alt = p.getAltitude();
+ if (alt != null && alt.isValid())
+ {
+ if (firstAlt == null) firstAlt = alt;
+ else lastAlt = alt;
+ if (veryFirstAlt == null) veryFirstAlt = alt;
+ else veryLastAlt = alt;
+ }
+ // Keep track of climb and descent too
+ if (p.getSegmentStart())
+ altRange.ignoreValue(alt);
+ else
+ altRange.addValue(alt);
+ }
+ }
+ // deal with last segment
+ if (firstAlt != null && firstAlt.isValid() && lastAlt != null && lastAlt.isValid())
+ movingHeightDiff = movingHeightDiff + lastAlt.getMetricValue() - firstAlt.getMetricValue();
+ final double metricMovingDist = movingDist / distUnit.getMultFactorFromStd(); // convert back to metres
+ final double gradient = movingHeightDiff * 100.0 / metricMovingDist;
+ _movingGradientLabel.setText(FORMAT_ONE_DP.format(gradient) + " %");
+ }
+ if (!altRange.hasRange()) {
+ _movingGradientLabel.setText("");
+ }
+ final boolean hasAltitudes = veryFirstAlt != null && veryFirstAlt.isValid() && veryLastAlt != null && veryLastAlt.isValid();
+
+ // Total gradient
+ final double metreDist = selection.getDistance() / distUnit.getMultFactorFromStd(); // convert back to metres
+ if (hasAltitudes && metreDist > 0.0)
{
// got an altitude and range
- int altDiffInMetres = lastAlt.getValue(Altitude.Format.METRES) - firstAlt.getValue(Altitude.Format.METRES);
+ int altDiffInMetres = veryLastAlt.getValue(Altitude.Format.METRES) - veryFirstAlt.getValue(Altitude.Format.METRES);
double gradient = altDiffInMetres * 100.0 / metreDist;
- _gradientLabel.setText(FORMAT_ONE_DP.format(gradient) + " %");
+ _totalGradientLabel.setText(FORMAT_ONE_DP.format(gradient) + " %");
}
else {
// no altitude given
- _gradientLabel.setText("");
+ _totalGradientLabel.setText("");
}
- // Show moving distance and average even when number of segments is 1
- final boolean isMetric = Config.getConfigBoolean(Config.KEY_METRIC_UNITS);
- final Distance.Units distUnits = isMetric?Distance.Units.KILOMETRES:Distance.Units.MILES;
- final String distUnitsStr = I18nManager.getText(isMetric?"units.kilometres.short":"units.miles.short");
- final String speedUnitsStr = I18nManager.getText(isMetric?"units.kmh":"units.mph");
- // Moving distance
- _movingDistanceLabel.setText(roundedNumber(selection.getMovingDistance(distUnits)) + " " + distUnitsStr);
- // Moving average speed
- long numSecs = selection.getMovingSeconds();
- if (numSecs > 0) {
- _aveMovingSpeedLabel.setText(roundedNumber(selection.getMovingDistance(distUnits)/numSecs*3600.0)
- + " " + speedUnitsStr);
+ // Moving climb/descent
+ if (altRange.hasRange()) {
+ _movingClimbLabel.setText(altRange.getClimb(altUnit) + altUnitsStr);
+ _movingDescentLabel.setText(altRange.getDescent(altUnit) + altUnitsStr);
}
else {
- _aveMovingSpeedLabel.setText("");
+ _movingClimbLabel.setText("");
+ _movingDescentLabel.setText("");
}
-
// Maximum speed
SpeedData speeds = new SpeedData(_app.getTrackInfo().getTrack());
- speeds.init();
+ speeds.init(Config.getUnitSet());
double maxSpeed = 0.0;
- for (int i=selection.getStart(); i<=selection.getEnd(); i++) {
+ for (int i=selection.getStart(); i<=selection.getEnd(); i++)
+ {
if (speeds.hasData(i) && (speeds.getData(i) > maxSpeed)) {
maxSpeed = speeds.getData(i);
}
else {
_maxSpeedLabel.setText("");
}
+
+ // vertical speed
+ final String vertSpeedUnitsStr = I18nManager.getText(Config.getUnitSet().getVerticalSpeedUnit().getShortnameKey());
+ if (hasAltitudes && metreDist > 0.0 && numSecs > 0)
+ {
+ // got an altitude and time - do total
+ final int altDiffInMetres = veryLastAlt.getValue(Altitude.Format.METRES) - veryFirstAlt.getValue(Altitude.Format.METRES);
+ final double altDiff = altDiffInMetres * altUnit.getMultFactorFromStd();
+ _totalVertSpeedLabel.setText(roundedNumber(altDiff/numSecs) + " " + vertSpeedUnitsStr);
+ // and moving
+ _movingVertSpeedLabel.setText(roundedNumber(movingHeightDiff * altUnit.getMultFactorFromStd() / numMovingSecs) + " " + vertSpeedUnitsStr);
+ }
+ else {
+ // no vertical speed available
+ _totalVertSpeedLabel.setText("");
+ _movingVertSpeedLabel.setText("");
+ }
}
/**
/**
- * Load the selected track or point
+ * Load the selected point(s)
*/
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())
+ // Find the rows selected in the table and get the corresponding coords
+ int numSelected = _trackTable.getSelectedRowCount();
+ if (numSelected < 1) return;
+ int[] rowNums = _trackTable.getSelectedRows();
+ for (int i=0; i<numSelected; i++)
{
- String coords = _trackListModel.getTrack(rowNum).getDownloadLink();
- String[] latlon = coords.split(",");
- if (latlon.length == 2)
+ int rowNum = rowNums[i];
+ if (rowNum >= 0 && rowNum < _trackListModel.getRowCount())
{
- 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);
+ 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
--- /dev/null
+package tim.prune.function;
+
+import javax.swing.JOptionPane;
+
+import tim.prune.App;
+import tim.prune.GenericFunction;
+import tim.prune.I18nManager;
+import tim.prune.data.DataPoint;
+import tim.prune.data.Track;
+import tim.prune.undo.UndoInterpolate;
+
+/**
+ * Function to interpolate between the points in a range
+ */
+public class InterpolateFunction extends GenericFunction
+{
+ /**
+ * Constructor
+ * @param inApp app object
+ */
+ public InterpolateFunction(App inApp) {
+ super(inApp);
+ }
+
+ /** @return name key */
+ public String getNameKey() {
+ return "function.interpolate";
+ }
+
+ /**
+ * Perform the operation
+ */
+ public void begin()
+ {
+ // Firstly, work out whether the selected range only contains waypoints or not
+ final int startIndex = _app.getTrackInfo().getSelection().getStart();
+ final int endIndex = _app.getTrackInfo().getSelection().getEnd();
+ boolean betweenWaypoints = false;
+ // if there are only waypoints, then ask whether to interpolate them
+ if (!selectedRangeHasTrackpoints(_app.getTrackInfo().getTrack(), startIndex, endIndex))
+ {
+ int answer = JOptionPane.showConfirmDialog(_parentFrame,
+ I18nManager.getText("dialog.interpolate.betweenwaypoints"),
+ I18nManager.getText(getNameKey()), JOptionPane.YES_NO_OPTION);
+ if (answer == JOptionPane.NO_OPTION) {
+ // user said no, so nothing to do
+ return;
+ }
+ betweenWaypoints = true;
+ }
+
+ // Get number of points to add
+ Object numPointsStr = JOptionPane.showInputDialog(_parentFrame,
+ I18nManager.getText("dialog.interpolate.parameter.text"),
+ I18nManager.getText(getNameKey()),
+ JOptionPane.QUESTION_MESSAGE, null, null, "");
+ if (numPointsStr == null) {return;}
+ int numToAdd = parseNumber(numPointsStr);
+ if (numToAdd <= 0 || numToAdd > 1000)
+ {
+ _app.showErrorMessage(getNameKey(), "error.interpolate.invalidparameter");
+ return;
+ }
+
+ if (startIndex < 0 || endIndex < 0 || endIndex <= startIndex) {
+ return;
+ }
+
+ // construct new point array with the interpolated points
+ final Track track = _app.getTrackInfo().getTrack();
+ final int maxToAdd = (endIndex-startIndex) * numToAdd;
+ final int extendedSize = track.getNumPoints() + maxToAdd;
+ DataPoint[] oldPoints = track.cloneContents();
+ DataPoint[] newPoints = new DataPoint[extendedSize];
+ // Copy points before
+ System.arraycopy(oldPoints, 0, newPoints, 0, startIndex);
+ // Loop, copying points and interpolating
+ int destIndex = startIndex;
+ DataPoint prevPoint = null;
+ for (int i=startIndex; i<= endIndex; i++)
+ {
+ DataPoint p = _app.getTrackInfo().getTrack().getPoint(i);
+ if (prevPoint != null && ((p.isWaypoint() && betweenWaypoints) || (!p.isWaypoint() && !p.getSegmentStart())))
+ {
+ // interpolate between the previous point and this one
+ DataPoint[] addition = prevPoint.interpolate(p, numToAdd);
+ System.arraycopy(addition, 0, newPoints, destIndex, numToAdd);
+ destIndex += numToAdd;
+ }
+ // copy point
+ newPoints[destIndex] = p;
+ destIndex++;
+ if (!p.isWaypoint() || betweenWaypoints)
+ {
+ prevPoint = p;
+ }
+ else if (!p.isWaypoint()) {
+ prevPoint = null;
+ }
+ // If it's a waypoint, then keep the old prevPoint
+ }
+ final int totalInserted = destIndex - endIndex - 1;
+ // Copy the points after the selected range
+ System.arraycopy(oldPoints, endIndex, newPoints, destIndex-1, track.getNumPoints()-endIndex);
+
+ // If necessary, make a new array of the correct size and do another arraycopy into it
+ final int newTotalPoints = track.getNumPoints() + totalInserted;
+ if (newTotalPoints != newPoints.length)
+ {
+ DataPoint[] croppedPoints = new DataPoint[newTotalPoints];
+ System.arraycopy(newPoints, 0, croppedPoints, 0, newTotalPoints);
+ newPoints = croppedPoints;
+ }
+
+ // Make undo object
+ UndoInterpolate undo = new UndoInterpolate(_app.getTrackInfo(), totalInserted);
+ // Replace track with new points array
+ if (track.replaceContents(newPoints))
+ {
+ _app.completeFunction(undo, I18nManager.getText("confirm.interpolate"));
+ // Alter selection
+ _app.getTrackInfo().getSelection().selectRange(startIndex, endIndex + totalInserted);
+ }
+ }
+
+ /**
+ * Check if the given Track has trackpoints in the specified range
+ * @param inTrack track object
+ * @param inStart start index
+ * @param inEnd end index
+ * @return true if there are any non-waypoints in the range
+ */
+ private static boolean selectedRangeHasTrackpoints(Track inTrack, int inStart, int inEnd)
+ {
+ for (int i=inStart; i<= inEnd; i++)
+ {
+ DataPoint p = inTrack.getPoint(i);
+ if (p != null && !p.isWaypoint()) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Helper method to parse an Object into an integer
+ * @param inObject object, eg from dialog
+ * @return int value given
+ */
+ private static int parseNumber(Object inObject)
+ {
+ int num = 0;
+ if (inObject != null)
+ {
+ try
+ {
+ num = Integer.parseInt(inObject.toString());
+ }
+ catch (NumberFormatException nfe)
+ {}
+ }
+ return num;
+ }
+}
// MAYBE: Paste clipboard into the edit field
_coordField.setText("");
_nameField.setText("");
- boolean metric = Config.getConfigBoolean(Config.KEY_METRIC_UNITS);
- _altUnitsDropDown.setSelectedIndex(metric?0:1);
+ boolean useMetres = (Config.getUnitSet().getDefaultAltitudeFormat() == Altitude.Format.METRES);
+ _altUnitsDropDown.setSelectedIndex(useMetres?0:1);
enableOK();
_dialog.setVisible(true);
}
--- /dev/null
+package tim.prune.function;
+
+import java.util.Comparator;
+
+import tim.prune.data.DataPoint;
+
+/**
+ * Class for comparing photos to sort them by name or timestamp
+ */
+public class PhotoComparer implements Comparator<DataPoint>
+{
+ public enum SortMode {
+ SORTBY_NAME, SORTBY_TIME
+ };
+
+ /** Sort mode */
+ private SortMode _sortMode = SortMode.SORTBY_NAME;
+
+ /**
+ * Constructor
+ * @param inMode sort mode
+ */
+ public PhotoComparer(SortMode inMode)
+ {
+ _sortMode = inMode;
+ }
+
+ /**
+ * Main compare method
+ */
+ public int compare(DataPoint inP1, DataPoint inP2)
+ {
+ if (inP2 == null || inP2.getPhoto() == null) return -1; // all nulls at end
+ if (inP1 == null || inP1.getPhoto() == null) return 1;
+ // Sort by name
+ int result = 0;
+ if (_sortMode == SortMode.SORTBY_NAME) {
+ result = compareNames(inP1, inP2);
+ }
+ if (result == 0) {
+ result = compareTimes(inP1, inP2);
+ }
+ // check names if times didn't work
+ if (result == 0 && _sortMode == SortMode.SORTBY_TIME) {
+ result = compareNames(inP1, inP2);
+ }
+ // names and times equal, try width and height
+ if (result == 0) {
+ result = compareSizes(inP1, inP2);
+ }
+ return 0;
+ }
+
+ /**
+ * Compare the names of the two photo points
+ * @param inP1 first point
+ * @param inP2 second point
+ * @return compare value (-1,0,1)
+ */
+ private int compareNames(DataPoint inP1, DataPoint inP2)
+ {
+ // If the files can't be compared, use the photo names
+ if (inP1.getPhoto().getFile() == null || inP2.getPhoto().getFile() == null) {
+ return inP1.getPhoto().getName().compareTo(inP2.getPhoto().getName());
+ }
+ // both photos have files, so just compare the files
+ return inP1.getPhoto().getFile().compareTo(inP2.getPhoto().getFile());
+ }
+
+ /**
+ * Compare the timestamps of the two photo points
+ * @param inP1 first point
+ * @param inP2 second point
+ * @return compare value (-1,0,1)
+ */
+ private int compareTimes(DataPoint inP1, DataPoint inP2)
+ {
+ // Photos might not have timestamps
+ if (!inP2.hasTimestamp()) return -1;
+ if (!inP1.hasTimestamp()) return 1;
+ // Compare the timestamps
+ long secDiff = inP1.getPhoto().getTimestamp().getSecondsSince(inP2.getPhoto().getTimestamp());
+ return (secDiff<0?-1:(secDiff==0?0:1));
+ }
+
+ /**
+ * Compare the sizes of the two photos
+ * @param inP1 first point
+ * @param inP2 second point
+ * @return compare value (-1,0,1)
+ */
+ private int compareSizes(DataPoint inP1, DataPoint inP2)
+ {
+ // Try the widths
+ int w1 = inP1.getPhoto().getWidth();
+ int w2 = inP2.getPhoto().getWidth();
+ if (w2 <= 0) return -1;
+ if (w1 <= 0) return 1;
+ if (w1 != w2) return (w2 > w1 ? 1 : -1);
+ // Try the heights
+ int h1 = inP1.getPhoto().getHeight();
+ int h2 = inP2.getPhoto().getHeight();
+ if (h2 <= 0) return -1;
+ if (h1 <= 0) return 1;
+ if (h1 != h2) return (h2 > h1 ? 1 : -1);
+ // sizes same
+ return 0;
+ }
+}
_frame.setLocationRelativeTo(_parentFrame);
}
initFrame();
- _frame.setVisible(true);
+ final Photo photo = _app.getTrackInfo().getCurrentPhoto();
+ if (photo.getWidth() <= 0 || photo.getHeight() <= 0) {
+ _app.showErrorMessageNoLookup(getNameKey(), I18nManager.getText("error.showphoto.failed")
+ + " : " + photo.getName());
+ }
+ else {
+ _frame.setVisible(true);
+ }
}
/**
package tim.prune.function;
+import java.io.BufferedOutputStream;
import java.io.ByteArrayInputStream;
import java.io.File;
+import java.io.FileOutputStream;
import java.io.IOException;
+import java.lang.reflect.InvocationTargetException;
+
import javax.sound.sampled.AudioInputStream;
import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.Clip;
{
// First choice is to play using java
played = playClip(audio);
- // Second choice is to try the Desktop library from java 6, if available
+ // If this didn't work, then try to play the file another way
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;
- }
+ played = playAudioFile(audioFile);
}
- // If the Desktop call failed, need to try backup methods
+ }
+ else if (audioFile == null && audio.getByteData() != null)
+ {
+ // Try to play audio clip using byte array
+ played = playClip(audio);
+ // If this didn't work, then need to copy the byte data to a file and play it from there
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) {}
+ try
+ {
+ String suffix = getSuffix(audio.getName());
+ File tempFile = File.createTempFile("gpsaudio", suffix);
+ tempFile.deleteOnExit();
+ // Copy byte data to this file
+ BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(tempFile));
+ bos.write(audio.getByteData(), 0, audio.getByteData().length);
+ bos.close();
+ played = playAudioFile(tempFile);
+ }
+ catch (IOException ignore) {
+ System.err.println("Error: " + ignore.getClass().getName() + " - " + ignore.getMessage());
}
}
}
- else if (audioFile == null && audio.getByteData() != null) {
- // Try to play audio clip using byte array (can't use Desktop or Runtime)
- played = playClip(audio);
- }
if (!played)
{
// If still not worked, show error message
return success;
}
+ /**
+ * Try to play the specified audio file
+ * @param inFile file to play
+ * @return true if play was successful
+ */
+ private boolean playAudioFile(File inFile)
+ {
+ boolean played = false;
+ // 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[] {inFile});
+ //above code mimics: Desktop.getDesktop().open(audioFile);
+ played = true;
+ }
+ catch (InvocationTargetException e) {
+ System.err.println("ITE: " + e.getCause().getClass().getName() + " - " + e.getCause().getMessage());
+ played = false;
+ }
+ catch (Exception ignore) {
+ System.err.println(ignore.getClass().getName() + " - " + ignore.getMessage());
+ played = false;
+ }
+ }
+
+ // If the Desktop call failed, need to try backup methods
+ if (!played)
+ {
+ // If system looks like a Mac, try the 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", inFile.getAbsolutePath()};
+ try {
+ Runtime.getRuntime().exec(command);
+ played = true;
+ }
+ catch (IOException ioe) {}
+ }
+ }
+ return played;
+ }
+
/**
* Try to stop a currently playing clip
*/
}
return percent;
}
+
+ /**
+ * @param inName name of audio file
+ * @return suffix (rest of name after the dot) - expect mp3, wav, ogg
+ */
+ private static final String getSuffix(String inName)
+ {
+ if (inName == null || inName.equals("")) {return ".tmp";}
+ final int dotPos = inName.lastIndexOf('.');
+ if (dotPos < 0) {return inName;} // no dot found
+ return inName.substring(dotPos);
+ }
}
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Arrays;
-import java.util.Comparator;
import javax.swing.BoxLayout;
import javax.swing.ButtonGroup;
*/
private static void sortPhotos(DataPoint[] inPhotos, boolean inSortByFile)
{
- Comparator<DataPoint> comparator = null;
- if (inSortByFile)
- {
- // sort by filename
- comparator = new Comparator<DataPoint>() {
- public int compare(DataPoint inP1, DataPoint inP2) {
- if (inP2 == null) return -1; // all nulls at end
- if (inP1 == null) return 1;
- if (inP1.getPhoto().getFile() == null || inP2.getPhoto().getFile() == null)
- return inP1.getPhoto().getName().compareTo(inP2.getPhoto().getName());
- return inP1.getPhoto().getFile().compareTo(inP2.getPhoto().getFile());
- }
- };
- }
- else
- {
- // sort by photo timestamp
- comparator = new Comparator<DataPoint>() {
- public int compare(DataPoint inP1, DataPoint inP2) {
- if (inP2 == null) return -1; // all nulls at end
- if (inP1 == null) return 1;
- long secDiff = inP1.getPhoto().getTimestamp().getSecondsSince(inP2.getPhoto().getTimestamp());
- return (secDiff<0?-1:(secDiff==0?0:1));
- }
- };
- }
- Arrays.sort(inPhotos, comparator);
+ PhotoComparer comparer = new PhotoComparer(inSortByFile ? PhotoComparer.SortMode.SORTBY_NAME : PhotoComparer.SortMode.SORTBY_TIME);
+ Arrays.sort(inPhotos, comparer);
}
}
_statusLabel.setText(descMessage);
}
+
/**
- * Load the selected track or point
+ * Load the selected point(s)
*/
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())
+ // Find the rows selected in the table and get the corresponding coords
+ int numSelected = _trackTable.getSelectedRowCount();
+ if (numSelected < 1) return;
+ int[] rowNums = _trackTable.getSelectedRows();
+ for (int i=0; i<numSelected; i++)
{
- String coords = _trackListModel.getTrack(rowNum).getDownloadLink();
- String[] latlon = coords.split(",");
- if (latlon.length == 2)
+ int rowNum = rowNums[i];
+ if (rowNum >= 0 && rowNum < _trackListModel.getRowCount())
{
- 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);
+ 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
if (subdir.isDirectory()) {
numDeleted += deleteFilesFrom(subdir, inMaxDays);
}
- else if (subdir.isFile() && subdir.exists())
+ else if (subdir.isFile() && subdir.exists() && _TILEFILTER.accept(subdir))
{
- boolean isTileFile = _TILEFILTER.accept(subdir);
- boolean isBadFile = !isTileFile && subdir.getName().toLowerCase().endsWith("png");
- if (isTileFile || isBadFile)
+ long fileAge = (now - subdir.lastModified()) / 1000 / 60 / 60 / 24;
+ if (inMaxDays < 0 || fileAge > inMaxDays)
{
- long fileAge = (now - subdir.lastModified()) / 1000 / 60 / 60 / 24;
- if (inMaxDays < 0 || fileAge > inMaxDays || isBadFile)
- {
- if (subdir.delete()) {
- numDeleted++;
- }
+ if (subdir.delete()) {
+ numDeleted++;
}
}
}
/**
* Mark that an unexpected file or directory was found
+ * TODO: Is this needed?
*/
public void foundUnexpected() {
_unexpected = true;
import tim.prune.GenericFunction;
import tim.prune.I18nManager;
import tim.prune.config.Config;
-import tim.prune.data.Altitude;
import tim.prune.data.DataPoint;
import tim.prune.data.Distance;
import tim.prune.data.Field;
import tim.prune.data.Timestamp;
import tim.prune.data.Track;
-import tim.prune.data.Distance.Units;
+import tim.prune.gui.profile.SpeedData;
+import tim.prune.gui.profile.VerticalSpeedData;
import tim.prune.load.GenericFileFilter;
/**
private boolean setupDialog(Track inTrack)
{
boolean hasTimes = inTrack.hasData(Field.TIMESTAMP);
- boolean hasAltitudes = inTrack.getAltitudeRange().hasRange();
+ boolean hasAltitudes = inTrack.hasAltitudeData();
_timeRadio.setEnabled(hasTimes);
// Add checks to prevent choosing unavailable combinations
catch (Exception e) {}
}
+ // Sort out units to use
+ final String distLabel = I18nManager.getText(Config.getUnitSet().getDistanceUnit().getShortnameKey());
+ final String altLabel = I18nManager.getText(Config.getUnitSet().getAltitudeUnit().getShortnameKey());
+ final String speedLabel = I18nManager.getText(Config.getUnitSet().getSpeedUnit().getShortnameKey());
+ final String vertSpeedLabel = I18nManager.getText(Config.getUnitSet().getVerticalSpeedUnit().getShortnameKey());
+
// Set x axis label
if (inDistance) {
- inWriter.write("set xlabel '" + I18nManager.getText("fieldname.distance") + " (" + getUnitsLabel("units.kilometres.short", "units.miles.short") + ")'\n");
+ inWriter.write("set xlabel '" + I18nManager.getText("fieldname.distance") + " (" + distLabel + ")'\n");
}
else {
inWriter.write("set xlabel '" + I18nManager.getText("fieldname.time") + " (" + I18nManager.getText("units.hours") + ")'\n");
switch (inYaxis)
{
case 0: // y axis is distance
- inWriter.write("set ylabel '" + I18nManager.getText("fieldname.distance") + " (" + getUnitsLabel("units.kilometres.short", "units.miles.short") + ")'\n");
+ inWriter.write("set ylabel '" + I18nManager.getText("fieldname.distance") + " (" + distLabel + ")'\n");
chartTitle = I18nManager.getText("fieldname.distance");
break;
case 1: // y axis is altitude
- inWriter.write("set ylabel '" + I18nManager.getText("fieldname.altitude") + " (" + getUnitsLabel("units.metres.short", "units.feet.short") + ")'\n");
+ inWriter.write("set ylabel '" + I18nManager.getText("fieldname.altitude") + " (" + altLabel + ")'\n");
chartTitle = I18nManager.getText("fieldname.altitude");
break;
case 2: // y axis is speed
- inWriter.write("set ylabel '" + I18nManager.getText("fieldname.speed") + " (" + getUnitsLabel("units.kmh", "units.mph") + ")'\n");
+ inWriter.write("set ylabel '" + I18nManager.getText("fieldname.speed") + " (" + speedLabel + ")'\n");
chartTitle = I18nManager.getText("fieldname.speed");
break;
case 3: // y axis is vertical speed
- inWriter.write("set ylabel '" + I18nManager.getText("fieldname.verticalspeed") + " (" + getUnitsLabel("units.metrespersec", "units.feetpersec") + ")'\n");
+ inWriter.write("set ylabel '" + I18nManager.getText("fieldname.verticalspeed") + " (" + vertSpeedLabel + ")'\n");
chartTitle = I18nManager.getText("fieldname.verticalspeed");
break;
}
inWriter.write("plot '" + tempFile.getAbsolutePath() + "' title '" + chartTitle + "' with filledcurve y1=0 lt rgb \"#009000\"\n");
}
- /**
- * Get the units label for the given keys
- * @param inMetric key if metric
- * @param inImperial key if imperial
- * @return display label with appropriate text
- */
- private static String getUnitsLabel(String inMetric, String inImperial)
- {
- String key = Config.getConfigBoolean(Config.KEY_METRIC_UNITS)?inMetric:inImperial;
- return I18nManager.getText(key);
- }
-
/**
* Calculate the distance values for each point in the given track
{
totalRads += DataPoint.calculateRadiansBetween(prevPoint, currPoint);
}
- if (Config.getConfigBoolean(Config.KEY_METRIC_UNITS)) {
- values.setData(i, Distance.convertRadiansToDistance(totalRads, Units.KILOMETRES));
- } else {
- values.setData(i, Distance.convertRadiansToDistance(totalRads, Units.MILES));
- }
+
+ // distance values use currently configured units
+ values.setData(i, Distance.convertRadiansToDistance(totalRads));
+
prevPoint = currPoint;
}
return values;
private static ChartSeries getAltitudeValues(Track inTrack)
{
ChartSeries values = new ChartSeries(inTrack.getNumPoints());
- Altitude.Format altFormat = Config.getConfigBoolean(Config.KEY_METRIC_UNITS)?Altitude.Format.METRES:Altitude.Format.FEET;
+ final double multFactor = Config.getUnitSet().getAltitudeUnit().getMultFactorFromStd();
for (int i=0; i<inTrack.getNumPoints(); i++) {
if (inTrack.getPoint(i).hasAltitude()) {
- values.setData(i, inTrack.getPoint(i).getAltitude().getValue(altFormat));
+ values.setData(i, inTrack.getPoint(i).getAltitude().getMetricValue() * multFactor);
}
}
return values;
*/
private static ChartSeries getSpeedValues(Track inTrack)
{
- // Calculate speeds and fill in in values array
- ChartSeries values = new ChartSeries(inTrack.getNumPoints());
- DataPoint prevPoint = null, currPoint = null, nextPoint = null;
- DataPoint[] points = getDataPoints(inTrack, false);
- final boolean useMetric = Config.getConfigBoolean(Config.KEY_METRIC_UNITS);
+ // Calculate speeds using the same formula as the profile chart
+ SpeedData speeds = new SpeedData(inTrack);
+
+ final int numPoints = inTrack.getNumPoints();
+ ChartSeries values = new ChartSeries(numPoints);
// Loop over collected points
- for (int i=1; i<(points.length-1); i++)
+ for (int i=0; i<numPoints; i++)
{
- prevPoint = points[i-1];
- currPoint = points[i];
- nextPoint = points[i+1];
- if (prevPoint != null && currPoint != null && nextPoint != null
- && nextPoint.getTimestamp().isAfter(currPoint.getTimestamp())
- && currPoint.getTimestamp().isAfter(prevPoint.getTimestamp()))
+ if (speeds.hasData(i))
{
- // Calculate average speed between prevPoint and nextPoint
- double rads = DataPoint.calculateRadiansBetween(prevPoint, currPoint)
- + DataPoint.calculateRadiansBetween(currPoint, nextPoint);
- double time = nextPoint.getTimestamp().getSecondsSince(prevPoint.getTimestamp()) / 60.0 / 60.0;
- // Convert to distance and pass to chartseries
- if (useMetric) {
- values.setData(i, Distance.convertRadiansToDistance(rads, Units.KILOMETRES) / time);
- } else {
- values.setData(i, Distance.convertRadiansToDistance(rads, Units.MILES) / time);
- }
+ values.setData(i, speeds.getData(i));
}
}
return values;
*/
private static ChartSeries getVertSpeedValues(Track inTrack)
{
- // Calculate speeds and fill in in values array
- ChartSeries values = new ChartSeries(inTrack.getNumPoints());
- Altitude.Format altFormat = Config.getConfigBoolean(Config.KEY_METRIC_UNITS)?Altitude.Format.METRES:Altitude.Format.FEET;
- DataPoint prevPoint = null, currPoint = null, nextPoint = null;
- DataPoint[] points = getDataPoints(inTrack, true); // require that points have altitudes too
+ // Calculate speeds using the same formula as the profile chart
+ VerticalSpeedData speeds = new VerticalSpeedData(inTrack);
+
+ final int numPoints = inTrack.getNumPoints();
+ ChartSeries values = new ChartSeries(numPoints);
// Loop over collected points
- for (int i=1; i<(points.length-1); i++)
+ for (int i=0; i<numPoints; i++)
{
- prevPoint = points[i-1];
- currPoint = points[i];
- nextPoint = points[i+1];
- if (prevPoint != null && currPoint != null && nextPoint != null
- && nextPoint.getTimestamp().isAfter(currPoint.getTimestamp())
- && currPoint.getTimestamp().isAfter(prevPoint.getTimestamp()))
+ if (speeds.hasData(i))
{
- // Calculate average vertical speed between prevPoint and nextPoint
- double vspeed = (nextPoint.getAltitude().getValue(altFormat) - prevPoint.getAltitude().getValue(altFormat))
- * 1.0 / nextPoint.getTimestamp().getSecondsSince(prevPoint.getTimestamp());
- values.setData(i, vspeed);
+ values.setData(i, speeds.getData(i));
}
}
return values;
}
- /**
- * Get an array of DataPoints with data for the charts
- * @param inTrack track object containing points
- * @param inRequireAltitudes true if only points with altitudes are considered
- * @return array of points with contiguous non-null elements (<= size) with timestamps
- */
- private static DataPoint[] getDataPoints(Track inTrack, boolean inRequireAltitudes)
- {
- DataPoint[] points = new DataPoint[inTrack.getNumPoints()];
- DataPoint currPoint = null;
- int pointNum = 0;
- // Loop over all points
- for (int i=0; i<inTrack.getNumPoints(); i++)
- {
- currPoint = inTrack.getPoint(i);
- if (currPoint != null && !currPoint.isWaypoint() && currPoint.hasTimestamp()
- && (!inRequireAltitudes || currPoint.hasAltitude()))
- {
- points[pointNum] = currPoint;
- pointNum++;
- }
- }
- // Any elements at the end of the array will stay null
- // Also note, chronological order is not checked
- return points;
- }
-
-
/**
* Select a file to write for the SVG output
* @return selected File object or null if cancelled
import javax.swing.BoxLayout;
import javax.swing.JButton;
import javax.swing.JDialog;
+import javax.swing.JOptionPane;
import javax.swing.JPanel;
import tim.prune.App;
{
boolean[] deleteFlags = preview();
// All flags are now combined in deleteFlags array
+ int numMarked = 0;
for (int i=0; i<deleteFlags.length; i++)
{
DataPoint point = _track.getPoint(i);
- point.setMarkedForDeletion(deleteFlags[i] && !point.hasMedia());
+ boolean deletePoint = deleteFlags[i] && !point.hasMedia();
+ point.setMarkedForDeletion(deletePoint);
+ if (deletePoint) numMarked++;
}
// Close dialog and inform listeners
UpdateMessageBroker.informSubscribers();
_dialog.dispose();
+ // Show confirmation dialog with OK button (not status bar message)
+ if (numMarked > 0) {
+ JOptionPane.showMessageDialog(_parentFrame, I18nManager.getText("dialog.compress.confirm1")
+ + " " + numMarked + " " + I18nManager.getText("dialog.compress.confirm2"),
+ I18nManager.getText(getNameKey()), JOptionPane.INFORMATION_MESSAGE);
+ }
+ else {
+ JOptionPane.showMessageDialog(_parentFrame, I18nManager.getText("dialog.compress.confirmnone"),
+ I18nManager.getText(getNameKey()), JOptionPane.INFORMATION_MESSAGE);
+ }
}
}
if (isActivated())
{
// Run the compression and set the deletion flags
+ _trackDetails.initialise();
numDeleted = compress(inFlags);
_summaryLabel.setValue(numDeleted);
}
--- /dev/null
+package tim.prune.function.compress;
+
+import javax.swing.JOptionPane;
+
+import tim.prune.App;
+import tim.prune.GenericFunction;
+import tim.prune.I18nManager;
+import tim.prune.UpdateMessageBroker;
+import tim.prune.data.DataPoint;
+
+/**
+ * Function to mark all the points in the selected rectangle
+ */
+public class MarkPointsInRectangleFunction extends GenericFunction
+{
+ /** Minimum and maximum latitude values of rectangle */
+ private double _minLat = 0.0, _maxLat = 0.0;
+ /** Minimum and maximum longitude values of rectangle */
+ private double _minLon = 0.0, _maxLon = 0.0;
+
+
+ /**
+ * Constructor
+ * @param inApp App object
+ */
+ public MarkPointsInRectangleFunction(App inApp)
+ {
+ super(inApp);
+ }
+
+ /**
+ * Set the coordinates of the rectangle
+ * @param inLon1 first longitude value
+ * @param inLat1 first latitude value
+ * @param inLon2 second longitude value
+ * @param inLat2 second latitude value
+ */
+ public void setRectCoords(double inLon1, double inLat1, double inLon2, double inLat2)
+ {
+ if (inLon1 == inLon2 || inLat1 == inLat2)
+ {
+ // Coordinates not valid
+ _minLat = _maxLat = _minLon = _maxLon = 0.0;
+ }
+ else
+ {
+ if (inLon2 > inLon1) {
+ _minLon = inLon1; _maxLon = inLon2;
+ }
+ else {
+ _minLon = inLon2; _maxLon = inLon1;
+ }
+ if (inLat2 > inLat1) {
+ _minLat = inLat1; _maxLat = inLat2;
+ }
+ else {
+ _minLat = inLat2; _maxLat = inLat1;
+ }
+ }
+ }
+
+ /**
+ * Begin the function using the set parameters
+ */
+ public void begin()
+ {
+ if (_maxLon == _minLon || _maxLat == _minLat) {
+ return;
+ }
+
+ // Loop over all points in track
+ final int numPoints = _app.getTrackInfo().getTrack().getNumPoints();
+ int numMarked = 0;
+ for (int i=0; i<numPoints; i++)
+ {
+ DataPoint point = _app.getTrackInfo().getTrack().getPoint(i);
+ // For each point, see if it's within the rectangle
+ final double pointLon = point.getLongitude().getDouble();
+ final double pointLat = point.getLatitude().getDouble();
+ final boolean insideRect = (pointLon >= _minLon && pointLon <= _maxLon
+ && pointLat >= _minLat && pointLat <= _maxLat);
+ // If so, then mark it
+ point.setMarkedForDeletion(insideRect);
+ if (insideRect) {
+ numMarked++;
+ }
+ }
+
+ // Inform subscribers to update display
+ UpdateMessageBroker.informSubscribers();
+ // Confirm message showing how many marked
+ if (numMarked > 0) {
+ JOptionPane.showMessageDialog(_parentFrame, I18nManager.getText("dialog.compress.confirm1")
+ + " " + numMarked + " " + I18nManager.getText("dialog.compress.confirm2"),
+ I18nManager.getText(getNameKey()), JOptionPane.INFORMATION_MESSAGE);
+ }
+ }
+
+ /** @return name key */
+ public String getNameKey() {
+ return "menu.track.markrectangle";
+ }
+}
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
+import java.awt.event.KeyAdapter;
+import java.awt.event.KeyEvent;
import java.util.ArrayList;
import javax.swing.BorderFactory;
mainPanel.add(scrollPane);
dialogPanel.add(mainPanel, BorderLayout.CENTER);
+ // close window if escape pressed
+ KeyAdapter escListener = new KeyAdapter() {
+ public void keyReleased(KeyEvent inE) {
+ if (inE.getKeyCode() == KeyEvent.VK_ESCAPE) {
+ _dialog.dispose();
+ }
+ }
+ };
+ _pointTable.addKeyListener(escListener);
+ distTable.addKeyListener(escListener);
+
// button panel at bottom
JPanel buttonPanel = new JPanel();
buttonPanel.setLayout(new FlowLayout(FlowLayout.RIGHT));
import tim.prune.config.Config;
import tim.prune.data.DataPoint;
import tim.prune.data.Distance;
+import tim.prune.data.Unit;
/**
* Class to hold the table model for the distances table
{
/** Distances */
private double[] _distances = null;
- /** Metric distances? */
- private boolean _useMetric = true;
- /** Previous value of metric flag (to spot changes) */
- private boolean _prevUseMetric = false;
/** Column heading */
private static final String _toColLabel = I18nManager.getText("dialog.distances.column.to");
/** Column heading (depends on metric/imperial settings) */
*/
public void recalculate(int inIndex)
{
- // Use metric or not?
- _useMetric = Config.getConfigBoolean(Config.KEY_METRIC_UNITS);
- _distanceLabel = getDistanceLabel(_useMetric);
+ // Which units to use?
+ Unit distUnit = Config.getUnitSet().getDistanceUnit();
+ _distanceLabel = I18nManager.getText("fieldname.distance") + " (" +
+ I18nManager.getText(distUnit.getShortnameKey()) + ")";
// Initialize array of distances
int numRows = getRowCount();
if (_distances == null || _distances.length != numRows) {
}
else {
double rads = DataPoint.calculateRadiansBetween(fromPoint, _pointList.get(i));
- _distances[i] = Distance.convertRadiansToDistance(rads, _useMetric?Distance.Units.KILOMETRES:Distance.Units.MILES);
+ _distances[i] = Distance.convertRadiansToDistance(rads);
}
}
- // Let table know that it has to refresh data (and maybe refresh column headings too)
- if (_useMetric == _prevUseMetric) {
- fireTableDataChanged();
- }
- else {
- fireTableStructureChanged();
- }
- _prevUseMetric = _useMetric;
- }
-
- /**
- * @param inMetric true to use metric distances
- * @return distance label for column heading
- */
- private static String getDistanceLabel(boolean inMetric)
- {
- return I18nManager.getText("fieldname.distance") + " (" +
- I18nManager.getText(inMetric?"units.kilometres.short" : "units.miles.short") + ")";
+ // Let table know that it has to refresh data (and might as well refresh column headings too)
+ fireTableStructureChanged();
}
}
}
});
rightPanel.add(lowerButton);
- JButton sentenceButton = new JButton(I18nManager.getText("dialog.pointnameedit.sentencecase"));
- sentenceButton.addActionListener(new ActionListener() {
+ JButton titleButton = new JButton(I18nManager.getText("dialog.pointnameedit.titlecase"));
+ titleButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e)
{
- _nameField.setText(sentenceCase(_nameField.getText()));
+ _nameField.setText(titleCase(_nameField.getText()));
_okButton.setEnabled(true);
_nameField.requestFocus();
}
});
- rightPanel.add(sentenceButton);
+ rightPanel.add(titleButton);
panel.add(rightPanel, BorderLayout.EAST);
// Bottom panel for OK, cancel buttons
JPanel lowerPanel = new JPanel();
}
/**
- * Turn a String into sentence case by capitalizing each word
+ * Turn a String into title case by capitalizing each word
* @param inString String to convert
* @return capitalized String
*/
- private static String sentenceCase(String inString)
+ private static String titleCase(String inString)
{
// Check first for empty strings
if (inString == null || inString.equals(""))
import javax.swing.JSplitPane;
import javax.swing.JTable;
import javax.swing.JTextArea;
-import javax.swing.ListSelectionModel;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
public void valueChanged(ListSelectionEvent e) {
if (!e.getValueIsAdjusting())
{
- if (_trackTable.getSelectedRow() >= 0
- && _trackTable.getSelectedRow() < _trackListModel.getRowCount())
+ final int numSelected = _trackTable.getSelectedRowCount();
+ if (numSelected > 0)
{
- _loadButton.setEnabled(true);
- _showButton.setEnabled(true);
setDescription(_trackListModel.getTrack(_trackTable.getSelectedRow()).getDescription());
_descriptionBox.setCaretPosition(0);
}
else {
_descriptionBox.setText("");
}
+ _loadButton.setEnabled(numSelected > 0);
+ _showButton.setEnabled(numSelected == 1);
}
}
});
- _trackTable.getSelectionModel().setSelectionMode(ListSelectionModel.SINGLE_SELECTION); // only allow one to be selected
_trackTable.getColumnModel().getColumn(0).setPreferredWidth(300);
if (_trackListModel.getColumnCount() > 1) {
_trackTable.getColumnModel().getColumn(1).setPreferredWidth(70);
_statusLabel.setText(I18nManager.getText("confirm.running"));
// Act on callback to update list and send another request if necessary
double[] coords = _app.getViewport().getBounds();
- // Example http://www.gpsies.com/api.do?BBOX=10,51,12,53&limit=20&trackTypes=jogging&filetype=kml&device=Run.GPS
int currPage = 1;
ArrayList<GpsiesTrack> trackList = null;
// Loop for each page of the results
do
{
+ // Example http://ws.gpsies.com/api.do?BBOX=10,51,12,53&limit=20&resultPage=1&key=oumgvvbckiwpvsnb
String urlString = "http://ws.gpsies.com/api.do?BBOX=" +
coords[1] + "," + coords[0] + "," + coords[3] + "," + coords[2] +
"&limit=" + RESULTS_PER_PAGE + "&resultPage=" + currPage +
}
/**
- * Load the selected track or point
+ * Load the selected track(s)
*/
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())
+ // Find the row(s) selected in the table and get the corresponding track
+ int numSelected = _trackTable.getSelectedRowCount();
+ if (numSelected < 1) return;
+ int[] rowNums = _trackTable.getSelectedRows();
+ for (int i=0; i<numSelected; i++)
{
- String url = _trackListModel.getTrack(rowNum).getDownloadLink();
- XmlFileLoader xmlLoader = new XmlFileLoader(_app);
- ZipFileLoader loader = new ZipFileLoader(_app, xmlLoader);
- try
+ int rowNum = rowNums[i];
+ if (rowNum >= 0 && rowNum < _trackListModel.getRowCount())
{
- loader.openStream(new URL(url).openStream());
- }
- catch (IOException ioe) {
- System.err.println("IO Exception : " + ioe.getMessage());
+ String url = _trackListModel.getTrack(rowNum).getDownloadLink();
+ XmlFileLoader xmlLoader = new XmlFileLoader(_app);
+ ZipFileLoader loader = new ZipFileLoader(_app, xmlLoader);
+ if (i>0) _app.autoAppendNextFile();
+ try
+ {
+ loader.openStream(new URL(url).openStream());
+ }
+ catch (IOException ioe) {
+ System.err.println("IO Exception : " + ioe.getMessage());
+ }
}
}
// Close the dialog
import tim.prune.I18nManager;
import tim.prune.config.Config;
-import tim.prune.data.Distance;
+import tim.prune.data.Unit;
/**
* Model for list of tracks from gpsies.com
GpsiesTrack track = _trackList.get(inRowNum);
if (inColNum == 0) {return track.getTrackName();}
double lengthM = track.getLength();
- if (Config.getConfigBoolean(Config.KEY_METRIC_UNITS)) {
- return _distanceFormatter.format(lengthM / 1000.0) + " " + I18nManager.getText("units.kilometres.short");
- }
- // must be imperial
- return _distanceFormatter.format(Distance.convertMetresToMiles(lengthM))
- + " " + I18nManager.getText("units.miles.short");
+ // convert to current distance units
+ Unit distUnit = Config.getUnitSet().getDistanceUnit();
+ double length = lengthM * distUnit.getMultFactorFromStd();
+ // Make text
+ return _distanceFormatter.format(length) + " " + I18nManager.getText(distUnit.getShortnameKey());
}
/**
public void addTracks(ArrayList<GpsiesTrack> inList)
{
if (_trackList == null) {_trackList = new ArrayList<GpsiesTrack>();}
+ final int prevCount = _trackList.size();
if (inList != null && inList.size() > 0) {
_trackList.addAll(inList);
}
- fireTableDataChanged();
+ final int updatedCount = _trackList.size();
+ if (prevCount <= 0)
+ fireTableDataChanged();
+ else
+ fireTableRowsInserted(prevCount, updatedCount-1);
}
/**
public void run() {
boolean[] saveFlags = {true, true, true, true, false, true}; // export everything
try {
- GpxExporter.exportData(_writer, _app.getTrackInfo(), _nameField.getText(), null, saveFlags, false);
+ GpxExporter.exportData(_writer, _app.getTrackInfo(), _nameField.getText(), null, saveFlags, null);
} catch (IOException e) {}
finally {
try {_writer.close();} catch (IOException e) {}
import tim.prune.I18nManager;
import tim.prune.UpdateMessageBroker;
import tim.prune.config.Config;
-import tim.prune.data.Altitude;
+import tim.prune.data.AltitudeRange;
import tim.prune.data.AudioClip;
import tim.prune.data.Coordinate;
import tim.prune.data.DataPoint;
-import tim.prune.data.Distance;
import tim.prune.data.Field;
-import tim.prune.data.IntegerRange;
import tim.prune.data.Photo;
import tim.prune.data.Selection;
+import tim.prune.data.SpeedCalculator;
+import tim.prune.data.SpeedValue;
import tim.prune.data.TrackInfo;
+import tim.prune.data.Unit;
+import tim.prune.data.UnitSet;
+import tim.prune.data.UnitSetLibrary;
/**
* Class to hold point details and selection details
private JLabel _indexLabel = null;
private JLabel _latLabel = null, _longLabel = null;
private JLabel _altLabel = null;
- private JLabel _timeLabel = null, _speedLabel = null;
+ private JLabel _timeLabel = null;
+ private JLabel _speedLabel = null, _vSpeedLabel = null;
private JLabel _nameLabel = null, _typeLabel = null;
// Range details
// Photo details
private JPanel _photoDetailsPanel = null;
private JLabel _photoLabel = null;
+ private JLabel _photoPathLabel = null;
private PhotoThumbnail _photoThumbnail = null;
private JLabel _photoTimestampLabel = null;
private JLabel _photoConnectedLabel = null;
// Audio details
private JPanel _audioDetailsPanel = null;
private JLabel _audioLabel = null;
+ private JLabel _audioPathLabel = null;
private JLabel _audioConnectedLabel = null;
private JLabel _audioTimestampLabel = null;
private JLabel _audioLengthLabel = null;
private static final String LABEL_POINT_TIMESTAMP = I18nManager.getText("fieldname.timestamp") + ": ";
private static final String LABEL_POINT_WAYPOINTNAME = I18nManager.getText("fieldname.waypointname") + ": ";
private static final String LABEL_POINT_WAYPOINTTYPE = I18nManager.getText("fieldname.waypointtype") + ": ";
+ private static final String LABEL_POINT_SPEED = I18nManager.getText("fieldname.speed") + ": ";
+ private static final String LABEL_POINT_VERTSPEED = I18nManager.getText("fieldname.verticalspeed") + ": ";
private static final String LABEL_RANGE_SELECTED = I18nManager.getText("details.range.selected") + ": ";
private static final String LABEL_RANGE_DURATION = I18nManager.getText("fieldname.duration") + ": ";
private static final String LABEL_RANGE_DISTANCE = I18nManager.getText("fieldname.distance") + ": ";
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;
+ private static final String LABEL_FULL_PATH = I18nManager.getText("details.media.fullpath") + ": ";
/**
pointDetailsPanel.add(_timeLabel);
_speedLabel = new JLabel("");
pointDetailsPanel.add(_speedLabel);
+ _vSpeedLabel = new JLabel("");
+ pointDetailsPanel.add(_vSpeedLabel);
_nameLabel = new JLabel("");
pointDetailsPanel.add(_nameLabel);
_typeLabel = new JLabel("");
_photoDetailsPanel = makeDetailsPanel("details.photodetails", biggerFont);
_photoLabel = new JLabel(I18nManager.getText("details.nophoto"));
_photoDetailsPanel.add(_photoLabel);
+ _photoPathLabel = new JLabel("");
+ _photoDetailsPanel.add(_photoPathLabel);
_photoTimestampLabel = new JLabel("");
_photoTimestampLabel.setMinimumSize(new Dimension(120, 10));
_photoDetailsPanel.add(_photoTimestampLabel);
_audioDetailsPanel = makeDetailsPanel("details.audiodetails", biggerFont);
_audioLabel = new JLabel(I18nManager.getText("details.noaudio"));
_audioDetailsPanel.add(_audioLabel);
+ _audioPathLabel = new JLabel("");
+ _audioDetailsPanel.add(_audioPathLabel);
_audioTimestampLabel = new JLabel("");
_audioTimestampLabel.setMinimumSize(new Dimension(120, 10));
_audioDetailsPanel.add(_audioTimestampLabel);
JLabel unitsLabel = new JLabel(I18nManager.getText("details.distanceunits") + ": ");
unitsLabel.setAlignmentX(Component.LEFT_ALIGNMENT);
lowerPanel.add(unitsLabel);
- String[] distUnits = {I18nManager.getText("units.kilometres"), I18nManager.getText("units.miles")};
- _distUnitsDropdown = new JComboBox(distUnits);
- if (!Config.getConfigBoolean(Config.KEY_METRIC_UNITS)) {_distUnitsDropdown.setSelectedIndex(1);}
+ // Make dropdown for distance units
+ _distUnitsDropdown = new JComboBox();
+ final UnitSet currUnits = Config.getUnitSet();
+ for (int i=0; i<UnitSetLibrary.getNumUnitSets(); i++) {
+ _distUnitsDropdown.addItem(I18nManager.getText(UnitSetLibrary.getUnitSet(i).getDistanceUnit().getNameKey()));
+ if (UnitSetLibrary.getUnitSet(i) == currUnits) {_distUnitsDropdown.setSelectedIndex(i);}
+ }
_distUnitsDropdown.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e)
{
- Config.setConfigBoolean(Config.KEY_METRIC_UNITS, _distUnitsDropdown.getSelectedIndex() == 0);
+ Config.selectUnitSet(_distUnitsDropdown.getSelectedIndex());
UpdateMessageBroker.informSubscribers(DataSubscriber.UNITS_CHANGED);
}
});
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;
- String distUnitsStr = I18nManager.getText(_distUnitsDropdown.getSelectedIndex()==0?"units.kilometres.short":"units.miles.short");
- String speedUnitsStr = I18nManager.getText(_distUnitsDropdown.getSelectedIndex()==0?"units.kmh":"units.mph");
+ UnitSet unitSet = UnitSetLibrary.getUnitSet(_distUnitsDropdown.getSelectedIndex());
+ String distUnitsStr = I18nManager.getText(unitSet.getDistanceUnit().getShortnameKey());
+ String speedUnitsStr = I18nManager.getText(unitSet.getSpeedUnit().getShortnameKey());
if (_track == null || currentPoint == null)
{
_indexLabel.setText(I18nManager.getText("details.nopointselection"));
_timeLabel.setText("");
_nameLabel.setText("");
_typeLabel.setText("");
+ _speedLabel.setText("");
+ _vSpeedLabel.setText("");
}
else
{
+ " " + _track.getNumPoints());
_latLabel.setText(makeCoordinateLabel(LABEL_POINT_LATITUDE, currentPoint.getLatitude(), _coordFormatDropdown.getSelectedIndex()));
_longLabel.setText(makeCoordinateLabel(LABEL_POINT_LONGITUDE, currentPoint.getLongitude(), _coordFormatDropdown.getSelectedIndex()));
+ Unit altUnit = Config.getUnitSet().getAltitudeUnit();
_altLabel.setText(currentPoint.hasAltitude()?
- (LABEL_POINT_ALTITUDE + currentPoint.getAltitude().getValue() + getAltitudeUnitsLabel(currentPoint.getAltitude().getFormat()))
- :"");
- if (currentPoint.getTimestamp().isValid())
- {
- if (currentPointIndex > 0 && currentPointIndex < (_trackInfo.getTrack().getNumPoints()-1))
- {
- DataPoint prevPoint = _trackInfo.getTrack().getPoint(currentPointIndex - 1);
- DataPoint nextPoint = _trackInfo.getTrack().getPoint(currentPointIndex + 1);
- if (prevPoint.getTimestamp().isValid() && nextPoint.getTimestamp().isValid())
- {
- // use total distance and total time between neighbouring points
- long diff = nextPoint.getTimestamp().getSecondsSince(prevPoint.getTimestamp());
- if (diff < 1000 && diff > 0)
- {
- double rads = DataPoint.calculateRadiansBetween(prevPoint, currentPoint) +
- DataPoint.calculateRadiansBetween(currentPoint, nextPoint);
- double dist = Distance.convertRadiansToDistance(rads, distUnits);
- String speed = roundedNumber(3600 * dist / diff) + " " + speedUnitsStr;
- _speedLabel.setText(I18nManager.getText("fieldname.speed") + ": " + speed);
- }
- }
- }
+ (LABEL_POINT_ALTITUDE + currentPoint.getAltitude().getValue(altUnit) + " " +
+ I18nManager.getText(altUnit.getShortnameKey()))
+ : "");
+ if (currentPoint.hasTimestamp()) {
_timeLabel.setText(LABEL_POINT_TIMESTAMP + currentPoint.getTimestamp().getText());
}
else {
_timeLabel.setText("");
}
+
+ // Speed can come from either timestamps and distances, or speed values in data
+ SpeedValue speedValue = new SpeedValue();
+ SpeedCalculator.calculateSpeed(_track, currentPointIndex, speedValue);
+ if (speedValue.isValid())
+ {
+ String speed = roundedNumber(speedValue.getValue()) + " " + speedUnitsStr;
+ _speedLabel.setText(LABEL_POINT_SPEED + speed);
+ }
+ else {
+ _speedLabel.setText("");
+ }
+
+ // Now do the vertical speed in the same way
+ SpeedCalculator.calculateVerticalSpeed(_track, currentPointIndex, speedValue);
+ if (speedValue.isValid())
+ {
+ String vSpeedUnitsStr = I18nManager.getText(unitSet.getVerticalSpeedUnit().getShortnameKey());
+ String speed = roundedNumber(speedValue.getValue()) + " " + vSpeedUnitsStr;
+ _vSpeedLabel.setText(LABEL_POINT_VERTSPEED + speed);
+ }
+ else {
+ _vSpeedLabel.setText("");
+ }
+
// Waypoint name
final String name = currentPoint.getWaypointName();
if (name != null && !name.equals(""))
_rangeLabel.setText(LABEL_RANGE_SELECTED
+ (selection.getStart()+1) + " " + I18nManager.getText("details.range.to")
+ " " + (selection.getEnd()+1));
- _distanceLabel.setText(LABEL_RANGE_DISTANCE + roundedNumber(selection.getDistance(distUnits)) + " " + distUnitsStr);
+ _distanceLabel.setText(LABEL_RANGE_DISTANCE + roundedNumber(selection.getDistance()) + " " + distUnitsStr);
if (selection.getNumSeconds() > 0)
{
_durationLabel.setText(LABEL_RANGE_DURATION + DisplayUtils.buildDurationString(selection.getNumSeconds()));
_aveSpeedLabel.setText(I18nManager.getText("details.range.avespeed") + ": "
- + roundedNumber(selection.getDistance(distUnits)/selection.getNumSeconds()*3600.0) + " " + speedUnitsStr);
+ + roundedNumber(selection.getDistance()/selection.getNumSeconds()*3600.0) + " " + speedUnitsStr);
}
else {
_durationLabel.setText("");
_aveSpeedLabel.setText("");
}
- String altUnitsLabel = getAltitudeUnitsLabel(selection.getAltitudeFormat());
- IntegerRange altRange = selection.getAltitudeRange();
- if (altRange.getMinimum() >= 0 && altRange.getMaximum() >= 0)
+ AltitudeRange altRange = selection.getAltitudeRange();
+ Unit altUnit = Config.getUnitSet().getAltitudeUnit();
+ String altUnitsLabel = I18nManager.getText(altUnit.getShortnameKey());
+ if (altRange.hasRange())
{
_altRangeLabel.setText(LABEL_RANGE_ALTITUDE
- + altRange.getMinimum() + altUnitsLabel + " "
+ + altRange.getMinimum(altUnit) + altUnitsLabel + " "
+ I18nManager.getText("details.altitude.to") + " "
- + altRange.getMaximum() + altUnitsLabel);
- _updownLabel.setText(LABEL_RANGE_CLIMB + selection.getClimb() + altUnitsLabel
- + LABEL_RANGE_DESCENT + selection.getDescent() + altUnitsLabel);
+ + altRange.getMaximum(altUnit) + altUnitsLabel);
+ _updownLabel.setText(LABEL_RANGE_CLIMB + altRange.getClimb(altUnit) + altUnitsLabel
+ + LABEL_RANGE_DESCENT + altRange.getDescent(altUnit) + altUnitsLabel);
}
else
{
{
// no photo, hide details
_photoLabel.setText(I18nManager.getText("details.nophoto"));
+ _photoPathLabel.setText("");
+ _photoPathLabel.setToolTipText("");
_photoTimestampLabel.setText("");
_photoConnectedLabel.setText("");
_photoBearingLabel.setText("");
{
if (currentPhoto == null) {currentPhoto = currentPoint.getPhoto();}
_photoLabel.setText(I18nManager.getText("details.photofile") + ": " + currentPhoto.getName());
+ String fullPath = currentPhoto.getFullPath();
+ String shortPath = shortenPath(fullPath);
+ _photoPathLabel.setText(fullPath == null ? "" : LABEL_FULL_PATH + shortPath);
+ _photoPathLabel.setToolTipText(currentPhoto.getFullPath());
_photoTimestampLabel.setText(currentPhoto.hasTimestamp()?(LABEL_POINT_TIMESTAMP + currentPhoto.getTimestamp().getText()):"");
_photoConnectedLabel.setText(I18nManager.getText("details.media.connected") + ": "
+ (currentPhoto.getCurrentStatus() == Photo.Status.NOT_CONNECTED ?
// audio details
_audioDetailsPanel.setVisible(_trackInfo.getAudioList().getNumAudios() > 0);
AudioClip currentAudio = _trackInfo.getAudioList().getAudio(_trackInfo.getSelection().getCurrentAudioIndex());
- if (currentAudio == null) {
+ if (currentAudio == null)
+ {
_audioLabel.setText(I18nManager.getText("details.noaudio"));
+ _audioPathLabel.setText("");
+ _audioPathLabel.setToolTipText("");
_audioTimestampLabel.setText("");
_audioLengthLabel.setText("");
_audioConnectedLabel.setText("");
else
{
_audioLabel.setText(LABEL_AUDIO_FILE + currentAudio.getName());
+ String fullPath = currentAudio.getFullPath();
+ String shortPath = shortenPath(fullPath);
+ _audioPathLabel.setText(fullPath == null ? "" : LABEL_FULL_PATH + shortPath);
+ _audioPathLabel.setToolTipText(fullPath == null ? "" : fullPath);
_audioTimestampLabel.setText(currentAudio.hasTimestamp()?(LABEL_POINT_TIMESTAMP + currentAudio.getTimestamp().getText()):"");
int audioLength = currentAudio.getLengthInSeconds();
_audioLengthLabel.setText(audioLength < 0?"":LABEL_RANGE_DURATION + DisplayUtils.buildDurationString(audioLength));
}
- /**
- * Choose the appropriate altitude units label for the specified format
- * @param inFormat altitude format
- * @return language-sensitive string
- */
- private static String getAltitudeUnitsLabel(Altitude.Format inFormat)
- {
- if (inFormat == LABEL_POINT_ALTITUDE_FORMAT && LABEL_POINT_ALTITUDE_UNITS != null)
- return LABEL_POINT_ALTITUDE_UNITS;
- LABEL_POINT_ALTITUDE_FORMAT = inFormat;
- if (inFormat == Altitude.Format.METRES)
- return " " + I18nManager.getText("units.metres.short");
- return " " + I18nManager.getText("units.feet.short");
- }
-
-
/**
* Construct an appropriate coordinate label using the selected format
* @param inPrefix prefix of label
button.addActionListener(new FunctionLauncher(inFunction));
return button;
}
+
+ /**
+ * @param inFullPath full file path or URL to be shortened
+ * @return shortened string from beginning of path
+ */
+ private static String shortenPath(String inFullPath)
+ {
+ // Chop off the home path if possible
+ final String homePath = System.getProperty("user.home").toLowerCase();
+ if (inFullPath != null && inFullPath.toLowerCase().startsWith(homePath)) {
+ inFullPath = inFullPath.substring(homePath.length()+1);
+ }
+ if (inFullPath == null || inFullPath.length() < 21) {
+ return inFullPath;
+ }
+ // path is too long
+ return inFullPath.substring(0, 20) + "...";
+ }
}
public static final String POINTS_CONNECTED_BUTTON = "points_connected.gif";
/** Icon for points disconnected icon on main map display */
public static final String POINTS_DISCONNECTED_BUTTON = "points_disconnected.gif";
+ /** Icon for edit mode button on main map display when not selected */
+ public static final String EDIT_MODE_BUTTON = "drag_points_icon.gif";
+ /** Icon for edit mode button on main map display when selected */
+ public static final String EDIT_MODE_BUTTON_ON = "drag_points_icon_on.gif";
/** Icon for zoom in button on main map display */
public static final String ZOOM_IN_BUTTON = "zoom_in.gif";
/** Icon for zoom out button on main map display */
*/
public static Dimension getThumbnailSize(int inOrigWidth, int inOrigHeight, int inMaxWidth, int inMaxHeight)
{
- assert(inMaxWidth > 0 && inMaxHeight > 0);
+ if (inMaxWidth <= 0 || inMaxHeight <= 0) {return new Dimension(1, 1);}
// work out maximum zoom ratio available so that thumbnail isn't too big
double xZoom = inMaxWidth * 1.0 / inOrigWidth;
double yZoom = inMaxHeight * 1.0 / inOrigHeight;
double zoom = (xZoom > yZoom?yZoom:xZoom);
// Don't make thumbnail bigger than picture
if (zoom > 1.0) {return new Dimension(inOrigWidth, inOrigHeight);}
+
// calculate new width and height
- return new Dimension ((int) (zoom * inOrigWidth), (int) (zoom * inOrigHeight));
+ final int xSize = (int) (zoom * inOrigWidth);
+ final int ySize = (int) (zoom * inOrigHeight);
+ if (xSize <= 0 || ySize <= 0) {return new Dimension(1, 1);}
+ return new Dimension (xSize, ySize);
}
private JMenuItem _editWaypointNameItem = null;
private JMenuItem _deletePointItem = null;
private JMenuItem _deleteRangeItem = null;
+ private JMenuItem _cropTrackItem = null;
private JMenuItem _compressItem = null;
+ private JMenuItem _markRectangleItem = null;
private JMenuItem _deleteMarkedPointsItem = null;
private JMenuItem _interpolateItem = null;
private JMenuItem _averageItem = null;
private ActionListener _undoAction = null;
private ActionListener _editPointAction = null;
private ActionListener _deletePointAction = null;
- private ActionListener _deleteRangeAction = null;
private ActionListener _selectStartAction = null;
private ActionListener _selectEndAction = null;
private JButton _editPointButton = null;
private JButton _deletePointButton = null;
private JButton _deleteRangeButton = null;
+ private JButton _cutAndMoveButton = null;
private JButton _selectStartButton = null;
private JButton _selectEndButton = null;
private JButton _connectButton = null;
_compressItem = makeMenuItem(FunctionLibrary.FUNCTION_COMPRESS, false);
setShortcut(_compressItem, "shortcut.menu.edit.compress");
trackMenu.add(_compressItem);
+ _markRectangleItem = new JMenuItem(I18nManager.getText("menu.track.markrectangle"));
+ _markRectangleItem.addActionListener(new ActionListener() {
+ public void actionPerformed(ActionEvent e) {
+ _app.setCurrentMode(App.AppMode.DRAWRECT);
+ UpdateMessageBroker.informSubscribers();
+ }
+ });
+ _markRectangleItem.setEnabled(false);
+ trackMenu.add(_markRectangleItem);
_deleteMarkedPointsItem = new JMenuItem(I18nManager.getText("menu.track.deletemarked"));
_deleteMarkedPointsItem.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
_selectEndItem.addActionListener(_selectEndAction);
rangeMenu.add(_selectEndItem);
rangeMenu.addSeparator();
- _deleteRangeItem = new JMenuItem(I18nManager.getText("menu.range.deleterange"));
- _deleteRangeAction = new ActionListener() {
- public void actionPerformed(ActionEvent e) {
- _app.deleteSelectedRange();
- }
- };
- _deleteRangeItem.addActionListener(_deleteRangeAction);
- _deleteRangeItem.setEnabled(false);
+ _deleteRangeItem = makeMenuItem(FunctionLibrary.FUNCTION_DELETE_RANGE, false);
rangeMenu.add(_deleteRangeItem);
+ _cropTrackItem = makeMenuItem(FunctionLibrary.FUNCTION_CROP_TRACK, false);
+ rangeMenu.add(_cropTrackItem);
_reverseItem = new JMenuItem(I18nManager.getText("menu.range.reverse"));
_reverseItem.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
_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) {
- _app.interpolateSelection();
- }
- });
- _interpolateItem.setEnabled(false);
+ _interpolateItem = makeMenuItem(FunctionLibrary.FUNCTION_INTERPOLATE, false);
rangeMenu.add(_interpolateItem);
_averageItem = new JMenuItem(I18nManager.getText("menu.range.average"));
_averageItem.addActionListener(new ActionListener() {
_mapCheckbox.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
Config.setConfigBoolean(Config.KEY_SHOW_MAP, _mapCheckbox.isSelected());
- UpdateMessageBroker.informSubscribers();
- }
+ UpdateMessageBroker.informSubscribers(MAPSERVER_CHANGED);
+ }
});
viewMenu.add(_mapCheckbox);
// Turn off the sidebars
toolbar.add(_deletePointButton);
// Delete range
_deleteRangeButton = new JButton(IconManager.getImageIcon(IconManager.DELETE_RANGE));
- _deleteRangeButton.setToolTipText(I18nManager.getText("menu.range.deleterange"));
- _deleteRangeButton.addActionListener(_deleteRangeAction);
+ _deleteRangeButton.setToolTipText(I18nManager.getText("function.deleterange"));
+ _deleteRangeButton.addActionListener(new ActionListener() {
+ public void actionPerformed(ActionEvent arg0) {
+ FunctionLibrary.FUNCTION_DELETE_RANGE.begin();
+ }
+ });
_deleteRangeButton.setEnabled(false);
toolbar.add(_deleteRangeButton);
+ // Cut and move
+ _cutAndMoveButton = new JButton(IconManager.getImageIcon(IconManager.CUT_AND_MOVE));
+ _cutAndMoveButton.setToolTipText(I18nManager.getText("menu.range.cutandmove"));
+ _cutAndMoveButton.addActionListener(new ActionListener() {
+ public void actionPerformed(ActionEvent arg0) {
+ _app.cutAndMoveSelection();
+ }
+ });
+ _cutAndMoveButton.setEnabled(false);
+ toolbar.add(_cutAndMoveButton);
// Select start, end
_selectStartButton = new JButton(IconManager.getImageIcon(IconManager.SET_RANGE_START));
_selectStartButton.setToolTipText(I18nManager.getText("menu.range.start"));
_exportPovItem.setEnabled(hasData);
_exportSvgItem.setEnabled(hasData);
_compressItem.setEnabled(hasData);
+ _markRectangleItem.setEnabled(hasData);
_deleteMarkedPointsItem.setEnabled(hasData && _track.hasMarkedPoints());
_rearrangeMenu.setEnabled(hasData && _track.hasTrackPoints() && _track.hasWaypoints());
_selectAllItem.setEnabled(hasData);
boolean hasRange = (hasData && _selection.hasRangeSelected());
_deleteRangeItem.setEnabled(hasRange);
_deleteRangeButton.setEnabled(hasRange);
- _interpolateItem.setEnabled(hasRange
- && (_selection.getEnd() - _selection.getStart()) == 1);
+ _cropTrackItem.setEnabled(hasRange);
+ _interpolateItem.setEnabled(hasRange);
_averageItem.setEnabled(hasRange);
_mergeSegmentsItem.setEnabled(hasRange);
_reverseItem.setEnabled(hasRange);
_deleteFieldValuesItem.setEnabled(hasRange);
_fullRangeDetailsItem.setEnabled(hasRange);
// Is the currently selected point outside the current range?
- _cutAndMoveItem.setEnabled(hasRange && hasPoint &&
+ boolean canCutAndMove = hasRange && hasPoint &&
(_selection.getCurrentPointIndex() < _selection.getStart()
- || _selection.getCurrentPointIndex() > (_selection.getEnd()+1)));
+ || _selection.getCurrentPointIndex() > (_selection.getEnd()+1));
+ _cutAndMoveItem.setEnabled(canCutAndMove);
+ _cutAndMoveButton.setEnabled(canCutAndMove);
// Has the map been switched on/off?
boolean mapsOn = Config.getConfigBoolean(Config.KEY_SHOW_MAP);
if (_mapCheckbox.isSelected() != mapsOn) {
{
_waypointListModel.fireChanged();
}
- if ((inUpdateType |
+ if ((inUpdateType &
(DataSubscriber.DATA_ADDED_OR_REMOVED | DataSubscriber.DATA_EDITED | DataSubscriber.PHOTOS_MODIFIED)) > 0)
{
_photoListModel.fireChanged();
/** Selected style number */
private String _style = null;
/** Server prefix including API-key unique to GpsPrune application */
- private static final String SERVER_PREFIX = "tile.cloudmade.com/03d86b66f51f4a3b8c236ac06f2a2e57/";
+ private static final String SERVER_PREFIX = "[abc].tile.cloudmade.com/03d86b66f51f4a3b8c236ac06f2a2e57/";
/**
* Constructor
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
+import java.net.URLConnection;
+import java.util.HashSet;
+
+import tim.prune.GpsPrune;
/**
* Class to control the reading and saving of map tiles
private ImageObserver _observer = null;
/** Time limit to cache images for */
private static final long CACHE_TIME_LIMIT = 20 * 24 * 60 * 60 * 1000; // 20 days in ms
+ /** Hashset of all blocked / 404 tiles to avoid requesting them again */
+ private static final HashSet<String> BLOCKED_URLS = new HashSet<String>();
/**
* Private constructor
if (inBasePath == null) {return null;}
File tileFile = new File(inBasePath, inTilePath);
Image image = null;
- if (tileFile.exists() && tileFile.canRead() && tileFile.length() > 0) {
+ if (tileFile.exists() && tileFile.canRead() && tileFile.length() > 0)
+ {
long fileStamp = tileFile.lastModified();
if (!inCheckAge || ((System.currentTimeMillis()-fileStamp) < CACHE_TIME_LIMIT))
{
*/
public static boolean saveTile(URL inUrl, String inBasePath, String inTilePath, ImageObserver inObserver)
{
- // TODO: Check that these are getting blocked properly
if (inBasePath == null || inTilePath == null) {return false;}
// save file if possible
File basePath = new File(inBasePath);
File tileFile = new File(basePath, inTilePath);
// Check if this file is already being loaded
if (isBeingLoaded(tileFile)) {return true;}
+ // Check if it has already failed
+ if (BLOCKED_URLS.contains(inUrl.toString())) {return true;}
File dir = tileFile.getParentFile();
// Start a new thread to load the image if necessary
FileOutputStream out = null;
File tempFile = new File(_file.getAbsolutePath() + ".temp");
// Use a synchronized block across all threads to make sure this url is only fetched once
- synchronized (DiskTileCacher.class) {
+ synchronized (DiskTileCacher.class)
+ {
if (tempFile.exists()) {return;}
try {
if (!tempFile.createNewFile()) {return;}
{
// Open streams from URL and to file
out = new FileOutputStream(tempFile);
- in = _url.openStream();
+ // Set http user agent on connection
+ URLConnection conn = _url.openConnection();
+ conn.setRequestProperty("User-Agent", "GpsPrune v" + GpsPrune.VERSION_NUMBER);
+ in = conn.getInputStream();
int d = 0;
// Loop over each byte in the stream (maybe buffering is more efficient?)
while ((d = in.read()) >= 0) {
out.write(d);
}
finished = true;
- } catch (IOException e) {}
+ } catch (IOException e) {
+ System.err.println("ioe: " + e.getClass().getName() + " - " + e.getMessage());
+ BLOCKED_URLS.add(_url.toString());
+ }
finally
{
// clean up files
import java.awt.BasicStroke;
import java.awt.BorderLayout;
import java.awt.Color;
+import java.awt.Cursor;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.FontMetrics;
import tim.prune.data.Coordinate;
import tim.prune.data.DataPoint;
import tim.prune.data.DoubleRange;
+import tim.prune.data.Field;
+import tim.prune.data.FieldList;
import tim.prune.data.Latitude;
import tim.prune.data.Longitude;
+import tim.prune.data.MidpointData;
import tim.prune.data.Selection;
import tim.prune.data.Track;
import tim.prune.data.TrackInfo;
+import tim.prune.function.compress.MarkPointsInRectangleFunction;
+import tim.prune.function.edit.FieldEdit;
+import tim.prune.function.edit.FieldEditList;
import tim.prune.gui.IconManager;
/**
private TrackInfo _trackInfo = null;
/** Selection object */
private Selection _selection = null;
+ /** Object to keep track of midpoints */
+ private MidpointData _midpoints = null;
+ /** Index of point clicked at mouseDown */
+ private int _clickedPoint = -1;
/** Previously selected point */
private int _prevSelectedPoint = -1;
/** Tile manager */
private JCheckBox _autopanCheckBox = null;
/** Checkbox for connecting track points */
private JCheckBox _connectCheckBox = null;
+ /** Checkbox for enable edit mode */
+ private JCheckBox _editmodeCheckBox = null;
/** Right-click popup menu */
private JPopupMenu _popup = null;
/** Top component panel */
private boolean _checkBounds = false;
/** Map position */
private MapPosition _mapPosition = null;
- /** x coordinate of drag from point */
- private int _dragFromX = -1;
- /** y coordinate of drag from point */
- private int _dragFromY = -1;
- /** x coordinate of drag to point */
- private int _dragToX = -1;
- /** y coordinate of drag to point */
- private int _dragToY = -1;
- /** x coordinate of popup menu */
- private int _popupMenuX = -1;
- /** y coordinate of popup menu */
- private int _popupMenuY = -1;
+ /** coordinates of drag from point */
+ private int _dragFromX = -1, _dragFromY = -1;
+ /** coordinates of drag to point */
+ private int _dragToX = -1, _dragToY = -1;
+ /** coordinates of popup menu */
+ private int _popupMenuX = -1, _popupMenuY = -1;
/** Flag to prevent showing too often the error message about loading maps */
private boolean _shownOsmErrorAlready = false;
/** Current drawing mode */
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;
+ private static final int MODE_DRAG_POINT = 4;
+ private static final int MODE_CREATE_MIDPOINT = 5;
+ private static final int MODE_MARK_RECTANGLE = 6;
+
+ private static final int INDEX_UNKNOWN = -2;
+
/**
* Constructor
_trackInfo = inTrackInfo;
_track = inTrackInfo.getTrack();
_selection = inTrackInfo.getSelection();
+ _midpoints = new MidpointData();
_mapPosition = new MapPosition();
addMouseListener(this);
addMouseMotionListener(this);
_recalculate = true;
Config.setConfigBoolean(Config.KEY_SHOW_MAP, e.getStateChange() == ItemEvent.SELECTED);
UpdateMessageBroker.informSubscribers(); // to let menu know
+ // If the track is only partially visible and you turn the map off, make the track fully visible again
+ if (e.getStateChange() == ItemEvent.DESELECTED && _transparencySlider.getValue() < 0) {
+ _transparencySlider.setValue(0);
+ }
}
};
_topPanel = new OverlayPanel();
_connectCheckBox.setFocusable(false); // stop button from stealing keyboard focus
_topPanel.add(_connectCheckBox);
+ // Add checkbox button for edit mode or not
+ _editmodeCheckBox = new JCheckBox(IconManager.getImageIcon(IconManager.EDIT_MODE_BUTTON), false);
+ _editmodeCheckBox.setSelectedIcon(IconManager.getImageIcon(IconManager.EDIT_MODE_BUTTON_ON));
+ _editmodeCheckBox.setOpaque(false);
+ _editmodeCheckBox.setToolTipText(I18nManager.getText("menu.map.editmode"));
+ _editmodeCheckBox.addItemListener(itemListener);
+ _editmodeCheckBox.setFocusable(false); // stop button from stealing keyboard focus
+ _topPanel.add(_editmodeCheckBox);
+
// Add zoom in, zoom out buttons
_sidePanel = new OverlayPanel();
_sidePanel.setLayout(new BoxLayout(_sidePanel, BoxLayout.Y_AXIS));
if (_mapImage != null) {
inG.drawImage(_mapImage, 0, 0, getWidth(), getHeight(), null);
}
- // Draw the zoom rectangle if necessary
- if (_drawMode == MODE_ZOOM_RECT)
- {
- inG.setColor(Color.RED);
- inG.drawLine(_dragFromX, _dragFromY, _dragFromX, _dragToY);
- inG.drawLine(_dragFromX, _dragFromY, _dragToX, _dragFromY);
- inG.drawLine(_dragToX, _dragFromY, _dragToX, _dragToY);
- inG.drawLine(_dragFromX, _dragToY, _dragToX, _dragToY);
- }
- else if (_drawMode == MODE_DRAW_POINTS_CONT)
+
+ switch (_drawMode)
{
- // 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);
+ case MODE_DRAG_POINT:
+ drawDragLines(inG, _selection.getCurrentPointIndex()-1, _selection.getCurrentPointIndex()+1);
+ break;
+
+ case MODE_CREATE_MIDPOINT:
+ drawDragLines(inG, _clickedPoint-1, _clickedPoint);
+ break;
+
+ case MODE_ZOOM_RECT:
+ case MODE_MARK_RECTANGLE:
+ if (_dragFromX != -1 && _dragFromY != -1)
+ {
+ // Draw the zoom rectangle if necessary
+ inG.setColor(Color.RED);
+ inG.drawLine(_dragFromX, _dragFromY, _dragFromX, _dragToY);
+ inG.drawLine(_dragFromX, _dragFromY, _dragToX, _dragFromY);
+ inG.drawLine(_dragToX, _dragFromY, _dragToX, _dragToY);
+ inG.drawLine(_dragFromX, _dragToY, _dragToX, _dragToY);
+ }
+ break;
+
+ case 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);
+ break;
}
}
else
final Color secondColour = makeTransparentColour(cs.getColour(ColourScheme.IDX_SECONDARY), opacity);
final Color textColour = makeTransparentColour(cs.getColour(ColourScheme.IDX_TEXT), opacity);
+ final int winWidth = getWidth();
+ final int winHeight = getHeight();
+ final int halfWinWidth = winWidth / 2;
+ final int halfWinHeight = winHeight / 2;
+
+ final int numPoints = _track.getNumPoints();
+ final int[] xPixels = new int[numPoints];
+ final int[] yPixels = new int[numPoints];
+
// try to set line width for painting
if (inG instanceof Graphics2D)
{
boolean prevPointVisible = false, currPointVisible = false;
boolean anyWaypoints = false;
boolean isWaypoint = false;
- for (int i=0; i<_track.getNumPoints(); i++)
+ for (int i=0; i<numPoints; i++)
{
- int px = getWidth() / 2 + _mapPosition.getXFromCentre(_track.getX(i));
- int py = getHeight() / 2 + _mapPosition.getYFromCentre(_track.getY(i));
- currPointVisible = px >= 0 && px < getWidth() && py >= 0 && py < getHeight();
+ // Calculate pixel position of point from its x, y coordinates
+ int px = halfWinWidth + _mapPosition.getXFromCentre(_track.getX(i));
+ int py = halfWinHeight + _mapPosition.getYFromCentre(_track.getY(i));
+ px = wrapLongitudeValue(px, winWidth, _mapPosition.getZoom());
+ // Remember these calculated pixel values so they don't have to be recalculated
+ xPixels[i] = px; yPixels[i] = py;
+
+ currPointVisible = px >= 0 && px < winWidth && py >= 0 && py < winHeight;
isWaypoint = _track.getPoint(i).isWaypoint();
anyWaypoints = anyWaypoints || isWaypoint;
if (currPointVisible)
inG.setColor(textColour);
FontMetrics fm = inG.getFontMetrics();
int nameHeight = fm.getHeight();
- int width = getWidth();
- int height = getHeight();
- if (anyWaypoints) {
+ if (anyWaypoints)
+ {
for (int i=0; i<_track.getNumPoints(); i++)
{
if (_track.getPoint(i).isWaypoint())
{
- int px = getWidth() / 2 + _mapPosition.getXFromCentre(_track.getX(i));
- int py = getHeight() / 2 + _mapPosition.getYFromCentre(_track.getY(i));
- if (px >= 0 && px < getWidth() && py >= 0 && py < getHeight())
+ int px = xPixels[i];
+ int py = yPixels[i];
+ if (px >= 0 && px < winWidth && py >= 0 && py < winHeight)
{
inG.fillRect(px-3, py-3, 6, 6);
pointsPainted++;
{
if (_track.getPoint(i).isWaypoint())
{
- int px = getWidth() / 2 + _mapPosition.getXFromCentre(_track.getX(i));
- int py = getHeight() / 2 + _mapPosition.getYFromCentre(_track.getY(i));
- if (px >= 0 && px < getWidth() && py >= 0 && py < getHeight())
+ int px = xPixels[i];
+ int py = yPixels[i];
+ if (px >= 0 && px < winWidth && py >= 0 && py < winHeight)
{
// Figure out where to draw waypoint name so it doesn't obscure track
String waypointName = _track.getPoint(i).getWaypointName();
// Check each direction in turn right left up down
for (int a=0; a<4; a++)
{
- if (nameXs[a] > 0 && (nameXs[a] + nameWidth) < width
- && nameYs[a] < height && (nameYs[a] - nameHeight) > 0
+ if (nameXs[a] > 0 && (nameXs[a] + nameWidth) < winWidth
+ && nameYs[a] < winHeight && (nameYs[a] - nameHeight) > 0
&& !overlapsPoints(nameXs[a], nameYs[a], nameWidth, nameHeight, textColour))
{
// Found a rectangle to fit - draw name here and quit
{
if (_track.getPoint(i).hasMedia())
{
- int px = getWidth() / 2 + _mapPosition.getXFromCentre(_track.getX(i));
- int py = getHeight() / 2 + _mapPosition.getYFromCentre(_track.getY(i));
- if (px >= 0 && px < getWidth() && py >= 0 && py < getHeight())
+ int px = xPixels[i];
+ int py = yPixels[i];
+ if (px >= 0 && px < winWidth && py >= 0 && py < winHeight)
{
inG.drawRect(px-1, py-1, 2, 2);
inG.drawRect(px-2, py-2, 4, 4);
inG.setColor(rangeColour);
for (int i=_selection.getStart(); i<=_selection.getEnd(); i++)
{
- int px = getWidth() / 2 + _mapPosition.getXFromCentre(_track.getX(i));
- int py = getHeight() / 2 + _mapPosition.getYFromCentre(_track.getY(i));
+ int px = xPixels[i];
+ int py = yPixels[i];
inG.drawRect(px-1, py-1, 2, 2);
}
}
- // Draw selected point, crosshairs
+ // Draw crosshairs at selected point
int selectedPoint = _selection.getCurrentPointIndex();
if (selectedPoint >= 0)
{
- int px = getWidth() / 2 + _mapPosition.getXFromCentre(_track.getX(selectedPoint));
- int py = getHeight() / 2 + _mapPosition.getYFromCentre(_track.getY(selectedPoint));
+ int px = xPixels[selectedPoint];
+ int py = yPixels[selectedPoint];
inG.setColor(currentColour);
// crosshairs
- inG.drawLine(px, 0, px, getHeight());
- inG.drawLine(0, py, getWidth(), py);
- // oval
- inG.drawOval(px - 2, py - 2, 4, 4);
- inG.drawOval(px - 3, py - 3, 6, 6);
+ inG.drawLine(px, 0, px, winHeight);
+ inG.drawLine(0, py, winWidth, py);
}
// Return the number of points painted
return pointsPainted;
}
+ /**
+ * Wrap the given pixel value if appropriate and possible
+ * @param inPx Pixel x coordinate
+ * @param inWinWidth window width in pixels
+ * @param inZoom zoom level
+ * @return modified pixel x coordinate
+ */
+ private static int wrapLongitudeValue(int inPx, int inWinWidth, int inZoom)
+ {
+ if (inPx > inWinWidth)
+ {
+ // Pixel is too far right, could we wrap it back onto the screen?
+ int px = inPx;
+ while (px > inWinWidth) {
+ px -= (256 << inZoom);
+ }
+ if (px >= 0) {
+ return px; // successfully wrapped back onto the screen
+ }
+ }
+ else if (inPx < 0)
+ {
+ // Pixel is too far left, could we wrap it back onto the screen?
+ int px = inPx;
+ while (px < 0) {
+ px += (256 << inZoom);
+ }
+ if (px < inWinWidth) {
+ return px; // successfully wrapped back onto the screen
+ }
+ }
+ // Either it's already on the screen or couldn't be wrapped
+ return inPx;
+ }
+
+ /**
+ * Draw the lines while dragging a point
+ * @param inG graphics object
+ * @param inPrevIndex index of point to draw from
+ * @param inNextIndex index of point to draw to
+ */
+ private void drawDragLines(Graphics inG, int inPrevIndex, int inNextIndex)
+ {
+ inG.setColor(Config.getColourScheme().getColour(ColourScheme.IDX_POINT));
+ // line from prev point to cursor
+ if (inPrevIndex > -1 && !_track.getPoint(inPrevIndex+1).getSegmentStart())
+ {
+ final int px = getWidth() / 2 + _mapPosition.getXFromCentre(_track.getX(inPrevIndex));
+ final int py = getHeight() / 2 + _mapPosition.getYFromCentre(_track.getY(inPrevIndex));
+ inG.drawLine(px, py, _dragToX, _dragToY);
+ }
+ if (inNextIndex < _track.getNumPoints() && !_track.getPoint(inNextIndex).getSegmentStart())
+ {
+ final int px = getWidth() / 2 + _mapPosition.getXFromCentre(_track.getX(inNextIndex));
+ final int py = getHeight() / 2 + _mapPosition.getYFromCentre(_track.getY(inNextIndex));
+ inG.drawLine(px, py, _dragToX, _dragToY);
+ }
+ }
/**
* Tests whether there are any dark pixels within the specified x,y rectangle
new Longitude(lon, Coordinate.FORMAT_NONE), null);
}
+ /**
+ * Move a DataPoint object to the given mouse coordinates
+ * @param startX start x coordinate of mouse
+ * @param startY start y coordinate of mouse
+ * @param endX end x coordinate of mouse
+ * @param endY end y coordinate of mouse
+ */
+ private void movePointToMouse(int startX, int startY, int endX, int endY )
+ {
+ double lat1 = MapUtils.getLatitudeFromY(_mapPosition.getYFromPixels(startY, getHeight()));
+ double lon1 = MapUtils.getLongitudeFromX(_mapPosition.getXFromPixels(startX, getWidth()));
+ double lat_delta = MapUtils.getLatitudeFromY(_mapPosition.getYFromPixels(endY, getHeight())) - lat1;
+ double lon_delta = MapUtils.getLongitudeFromX(_mapPosition.getXFromPixels(endX, getWidth())) - lon1;
+
+ DataPoint point = _trackInfo.getCurrentPoint();
+ if (point == null) {
+ return;
+ }
+
+ // Make lists for edit and undo, and add each changed field in turn
+ FieldEditList editList = new FieldEditList();
+ FieldEditList undoList = new FieldEditList();
+
+ // Check field list
+ FieldList fieldList = _track.getFieldList();
+ int numFields = fieldList.getNumFields();
+ for (int i=0; i<numFields; i++)
+ {
+ Field field = fieldList.getField(i);
+ if (field == Field.LATITUDE) {
+ editList.addEdit(new FieldEdit(field, Double.toString(point.getLatitude().getDouble() + lat_delta)));
+ undoList.addEdit(new FieldEdit(field, point.getFieldValue(Field.LATITUDE)));
+ }
+ else if (field == Field.LONGITUDE) {
+ editList.addEdit(new FieldEdit(field, Double.toString(point.getLongitude().getDouble() + lon_delta)));
+ undoList.addEdit(new FieldEdit(field, point.getFieldValue(Field.LONGITUDE)));
+ }
+ }
+ _app.completePointEdit(editList, undoList);
+ }
+
+
/**
* @see javax.swing.JComponent#getMinimumSize()
*/
// single click
if (_drawMode == MODE_DEFAULT)
{
- int pointIndex = _track.getNearestPointIndex(
+ int pointIndex = _clickedPoint;
+ if (pointIndex == INDEX_UNKNOWN)
+ {
+ // index hasn't been calculated yet
+ 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);
_popup.show(this, _popupMenuX, _popupMenuY);
}
}
+ // Reset app mode
+ _app.setCurrentMode(App.AppMode.NORMAL);
+ if (_drawMode == MODE_MARK_RECTANGLE) _drawMode = MODE_DEFAULT;
}
/**
}
/**
- * Ignore mouse pressed events
+ * React to mouse pressed events to initiate a point drag
* @see java.awt.event.MouseListener#mousePressed(java.awt.event.MouseEvent)
*/
public void mousePressed(MouseEvent inE)
{
- // ignore
+ _clickedPoint = INDEX_UNKNOWN;
+ if (_track == null || _track.getNumPoints() <= 0)
+ return;
+ if (!inE.isMetaDown())
+ {
+ // Left mouse drag - check if point is near; if so select it for dragging
+ if (_drawMode == MODE_DEFAULT)
+ {
+ /* Drag points if edit mode is enabled OR ALT is pressed */
+ if (_editmodeCheckBox.isSelected() || inE.isAltDown() || inE.isAltGraphDown())
+ {
+ final double clickX = _mapPosition.getXFromPixels(inE.getX(), getWidth());
+ final double clickY = _mapPosition.getYFromPixels(inE.getY(), getHeight());
+ final double clickSens = _mapPosition.getBoundsFromPixels(CLICK_SENSITIVITY);
+ _clickedPoint = _track.getNearestPointIndex(clickX, clickY, clickSens, false);
+
+ if (_clickedPoint >= 0)
+ {
+ // TODO: maybe use another color of the cross or remove the cross while dragging???
+
+ _trackInfo.selectPoint(_clickedPoint);
+ if (_trackInfo.getCurrentPoint() != null)
+ {
+ _drawMode = MODE_DRAG_POINT;
+ _dragFromX = _dragToX = inE.getX();
+ _dragFromY = _dragToY = inE.getY();
+ }
+ }
+ else
+ {
+ // Not a click on a point, so check half-way between two (connected) trackpoints
+ int midpointIndex = _midpoints.getNearestPointIndex(clickX, clickY, clickSens);
+ if (midpointIndex > 0)
+ {
+ _drawMode = MODE_CREATE_MIDPOINT;
+ _clickedPoint = midpointIndex;
+ _dragFromX = _dragToX = inE.getX();
+ _dragFromY = _dragToY = inE.getY();
+ }
+ }
+ }
+ }
+ }
+ // else right-press ignored
}
/**
public void mouseReleased(MouseEvent inE)
{
_recalculate = true;
- if (_drawMode == MODE_ZOOM_RECT && Math.abs(_dragToX - _dragFromX) > 20
- && Math.abs(_dragToY - _dragFromY) > 20)
+
+ if (_drawMode == MODE_DRAG_POINT)
+ {
+ if (Math.abs(_dragToX - _dragFromX) > 2
+ || Math.abs(_dragToY - _dragFromY) > 2)
+ {
+ movePointToMouse(_dragFromX, _dragFromY, _dragToX, _dragToY );
+ }
+ _drawMode = MODE_DEFAULT;
+ }
+ else if (_drawMode == MODE_CREATE_MIDPOINT)
+ {
+ _drawMode = MODE_DEFAULT;
+ _app.createPoint(createPointFromClick(_dragToX, _dragToY), _clickedPoint);
+ }
+ else if (_drawMode == MODE_ZOOM_RECT)
{
- _mapPosition.zoomToPixels(_dragFromX, _dragToX, _dragFromY, _dragToY, getWidth(), getHeight());
+ if (Math.abs(_dragToX - _dragFromX) > 20
+ && Math.abs(_dragToY - _dragFromY) > 20)
+ {
+ _mapPosition.zoomToPixels(_dragFromX, _dragToX, _dragFromY, _dragToY, getWidth(), getHeight());
+ }
+ _drawMode = MODE_DEFAULT;
}
- if (_drawMode == MODE_ZOOM_RECT) {
+ else if (_drawMode == MODE_MARK_RECTANGLE)
+ {
+ // Reset app mode
+ _app.setCurrentMode(App.AppMode.NORMAL);
_drawMode = MODE_DEFAULT;
+ // Call a function to mark the points
+ MarkPointsInRectangleFunction marker = new MarkPointsInRectangleFunction(_app);
+ double lon1 = MapUtils.getLongitudeFromX(_mapPosition.getXFromPixels(_dragFromX, getWidth()));
+ double lat1 = MapUtils.getLatitudeFromY(_mapPosition.getYFromPixels(_dragFromY, getHeight()));
+ double lon2 = MapUtils.getLongitudeFromX(_mapPosition.getXFromPixels(_dragToX, getWidth()));
+ double lat2 = MapUtils.getLatitudeFromY(_mapPosition.getYFromPixels(_dragToY, getHeight()));
+ // Invalidate rectangle if pixel coords are (-1,-1)
+ if (_dragFromX < 0 || _dragFromY < 0) {
+ lon1 = lon2;
+ lat1 = lat2;
+ }
+ marker.setRectCoords(lon1, lat1, lon2, lat2);
+ marker.begin();
}
_dragFromX = _dragFromY = -1;
repaint();
{
if (!inE.isMetaDown())
{
- // Left mouse drag - pan map by appropriate amount
- if (_dragFromX != -1)
+ // Left mouse drag - either drag the point or pan the map
+ if (_drawMode == MODE_DRAG_POINT || _drawMode == MODE_CREATE_MIDPOINT)
{
- panMap(_dragFromX - inE.getX(), _dragFromY - inE.getY());
+ // move point
+ _dragToX = inE.getX();
+ _dragToY = inE.getY();
_recalculate = true;
repaint();
}
- _dragFromX = _dragToX = inE.getX();
- _dragFromY = _dragToY = inE.getY();
+ else if (_drawMode == MODE_MARK_RECTANGLE)
+ {
+ // draw a rectangle for marking points
+ if (_dragFromX == -1) {
+ _dragFromX = inE.getX();
+ _dragFromY = inE.getY();
+ }
+ _dragToX = inE.getX();
+ _dragToY = inE.getY();
+ repaint();
+ }
+ else
+ {
+ // regular left-drag pans map by appropriate amount
+ if (_dragFromX != -1)
+ {
+ panMap(_dragFromX - inE.getX(), _dragFromY - inE.getY());
+ }
+ _dragFromX = _dragToX = inE.getX();
+ _dragFromY = _dragToY = inE.getY();
+ }
}
else
{
- // Right-click and drag - draw rectangle and control zoom
+ // Right-click and drag - update rectangle
_drawMode = MODE_ZOOM_RECT;
if (_dragFromX == -1) {
_dragFromX = inE.getX();
*/
public void mouseMoved(MouseEvent inEvent)
{
+ boolean useCrosshairs = false;
+ boolean useResize = false;
// Ignore unless we're drawing points
if (_drawMode == MODE_DRAW_POINTS_CONT)
{
_dragToY = inEvent.getY();
repaint();
}
+ else if (_drawMode == MODE_MARK_RECTANGLE) {
+ useResize = true;
+ }
+ else if (_editmodeCheckBox.isSelected() || inEvent.isAltDown() || inEvent.isAltGraphDown())
+ {
+ // Try to find a point or a midpoint at this location, and if there is one
+ // then change the cursor to crosshairs
+ final double clickX = _mapPosition.getXFromPixels(inEvent.getX(), getWidth());
+ final double clickY = _mapPosition.getYFromPixels(inEvent.getY(), getHeight());
+ final double clickSens = _mapPosition.getBoundsFromPixels(CLICK_SENSITIVITY);
+ useCrosshairs = (_track.getNearestPointIndex(clickX, clickY, clickSens, false) >= 0
+ || _midpoints.getNearestPointIndex(clickX, clickY, clickSens) >= 0
+ );
+ }
+ if (useCrosshairs && !isCursorSet()) {
+ setCursor(Cursor.getPredefinedCursor(Cursor.CROSSHAIR_CURSOR));
+ }
+ else if (useResize && !isCursorSet()) {
+ setCursor(Cursor.getPredefinedCursor(Cursor.SE_RESIZE_CURSOR));
+ }
+ else if (!useCrosshairs && !useResize && isCursorSet()) {
+ setCursor(null);
+ }
}
/**
if ((inUpdateType & DataSubscriber.MAPSERVER_CHANGED) > 0) {
_tileManager.resetConfig();
}
+ if ((inUpdateType & (DataSubscriber.DATA_ADDED_OR_REMOVED + DataSubscriber.DATA_EDITED)) > 0) {
+ _midpoints.updateData(_track);
+ }
+ // See if rect mode has been activated
+ if (_app.getCurrentMode() == App.AppMode.DRAWRECT)
+ {
+ _drawMode = MODE_MARK_RECTANGLE;
+ if (!isCursorSet()) {
+ setCursor(Cursor.getPredefinedCursor(Cursor.SE_RESIZE_CURSOR));
+ }
+ }
repaint();
// enable or disable components
boolean hasData = _track.getNumPoints() > 0;
private static final int MAP_TILE_SIZE = 256;
/** x position (scale depends on zoom) */
- private long _xPosition = 0L;
+ private int _xPosition = 0;
/** y position (scale depends on zoom) */
- private long _yPosition = 0L;
+ private int _yPosition = 0;
/** Zoom level, from 2 to max */
private int _zoom = 12;
}
if (requiredZoom < 2) requiredZoom = 2;
// Set position
- _zoom = requiredZoom;
- _zoomFactor = 1 << _zoom;
+ setZoom(requiredZoom);
_xPosition = transformToPixels((inMinX + inMaxX) / 2.0);
_yPosition = transformToPixels((inMinY + inMaxY) / 2.0);
}
+ /**
+ * Ensure that zoom and zoomFactor remain in sync
+ * @param inZoom zoom level to set
+ */
+ private void setZoom(int inZoom)
+ {
+ _zoom = inZoom;
+ _zoomFactor = 1 << _zoom;
+ }
+
/**
* Zoom and pan to show the selected area
* @param inMinX minimum pixels X
break;
}
}
- _zoom = requiredZoom;
- _zoomFactor = 1 << _zoom;
+ setZoom(requiredZoom);
// Set position
_xPosition = (_xPosition - inWidth/2 + (inMinX + inMaxX) / 2) * multFactor;
_yPosition = (_yPosition - inHeight/2 + (inMinY + inMaxY) / 2) * multFactor;
* @param inValue value to transform
* @return pixels
*/
- private long transformToPixels(double inValue)
+ private int transformToPixels(double inValue)
{
return transformToPixels(inValue, _zoom);
}
* @param inZoom zoom value to use
* @return pixels
*/
- private static long transformToPixels(double inValue, int inZoom)
+ private static int transformToPixels(double inValue, int inZoom)
{
- return (long) (inValue * MAP_TILE_SIZE * (1 << inZoom));
+ return (int) (inValue * MAP_TILE_SIZE * (1 << inZoom));
}
/**
*/
public int getXFromCentre(double inValue)
{
- return (int) (transformToPixels(inValue) - _xPosition);
+ return transformToPixels(inValue) - _xPosition;
}
/**
*/
public int getYFromCentre(double inValue)
{
- return (int) (transformToPixels(inValue) - _yPosition);
+ return transformToPixels(inValue) - _yPosition;
}
/**
* @param inPosition position of point
* @return tile index for that point
*/
- private int getTileIndex(long inPosition)
+ private int getTileIndex(int inPosition)
{
- return (int) (inPosition / MAP_TILE_SIZE);
+ return inPosition / MAP_TILE_SIZE;
}
/**
* @param inPosition position of point
* @return pixel offset for that point
*/
- private int getDisplayOffset(long inPosition)
+ private int getDisplayOffset(int inPosition)
{
- return (int) (inPosition % MAP_TILE_SIZE);
- // Maybe >> 8 would be slightly faster?
+ return inPosition % MAP_TILE_SIZE;
+ // I thought that &255 would be slightly faster, but it gives the wrong result
}
/**
{
if (_zoom < MAX_ZOOM)
{
- _zoom++;
- _zoomFactor = 1 << _zoom;
+ setZoom(_zoom + 1);
_xPosition *= 2;
_yPosition *= 2;
}
*/
public void zoomOut()
{
- if (_zoom >= 2)
+ if (_zoom >= 3)
{
- _zoom--;
- _zoomFactor = 1 << _zoom;
+ setZoom(_zoom - 1);
_xPosition /= 2;
_yPosition /= 2;
}
import java.net.MalformedURLException;
import java.net.URL;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
/**
* Class to represent any map source, whether an OsmMapSource
/** File extensions */
protected String[] _extensions = null;
+ /** Regular expression for catching server wildcards */
+ protected static final Pattern WILD_PATTERN = Pattern.compile("^(.*)\\[(.*)\\](.*)$");
+
/**
* @return the number of layers used in this source
String urlstr = inUrl;
// check prefix
try {
- new URL(urlstr);
+ new URL(urlstr.replace('[', 'w').replace(']', 'w'));
}
- catch (MalformedURLException e) {
+ catch (MalformedURLException e)
+ {
// fail if protocol specified
if (urlstr.indexOf("://") >= 0) {return null;}
// add the http protocol
}
// Validate current url, return null if not ok
try {
- URL url = new URL(urlstr);
+ URL url = new URL(urlstr.replace('[', 'w').replace(']', 'w'));
// url host must contain a dot
if (url.getHost().indexOf('.') < 0) {return null;}
}
int idx = url.indexOf("://");
if (idx >= 0) {url = url.substring(idx + 3);}
if (url.startsWith("www.")) {url = url.substring(4);}
+ // Strip out any "[.*]" as well
+ if (url.indexOf('[') >= 0)
+ {
+ Matcher matcher = WILD_PATTERN.matcher(url);
+ if (matcher.matches()) {
+ url = matcher.group(1) + matcher.group(3);
+ if (url.length() > 1 && url.charAt(0) == '.') {
+ url = url.substring(1);
+ }
+ }
+ }
return url;
}
*/
private static void addFixedSources()
{
- _sourceList.add(new OsmMapSource("Mapnik", "http://tile.openstreetmap.org/"));
- _sourceList.add(new OsmMapSource("Cyclemap", "http://tile.opencyclemap.org/cycle/"));
+ _sourceList.add(new OsmMapSource("Mapnik", "http://[abc].tile.openstreetmap.org/"));
+ _sourceList.add(new OsmMapSource("Cyclemap", "http://[abc].tile.opencyclemap.org/cycle/"));
_sourceList.add(new OsmMapSource("Reitkarte", "http://wanderreitkarte.de/hills/",
"http://topo2.wanderreitkarte.de/topo/", 18));
_sourceList.add(new MffMapSource("Mapsforfree", "http://maps-for-free.com/layer/relief/", "jpg",
package tim.prune.gui.map;
import java.awt.Image;
-import java.awt.Toolkit;
import java.awt.image.ImageObserver;
import java.net.MalformedURLException;
import java.net.URL;
private int _numLayers = -1;
/** Current zoom level */
private int _zoom = 0;
- /** Currently blocked zoom level, to prevent looping for non-existent images */
- private int _blockedZoom = 0;
/** Number of tiles in each direction for this zoom level */
private int _numTileIndices = 1;
*/
public Image getTile(int inLayer, int inX, int inY)
{
- // Check tile boundaries
- if (inX < 0 || inX >= _numTileIndices || inY < 0 || inY >= _numTileIndices) return null;
+ if (inY < 0 || inY >= _numTileIndices) return null;
+ // Wrap tile indices which are too big or too small
+ inX = ((inX % _numTileIndices) + _numTileIndices) % _numTileIndices;
// Check first in memory cache for tile
MemTileCacher tempCache = _tempCaches[inLayer]; // Should probably guard against nulls and array indexes here
if (tile != null)
{
// Pass tile to memory cache
- tempCache.setTile(tile, inX, inY);
+ tempCache.setTile(tile, inX, inY, _zoom);
if (tile.getWidth(this) > 0) {return tile;}
return null;
}
}
// Tile wasn't in memory or on disk, so if online let's get it
- if (onlineMode && _blockedZoom != _zoom)
+ if (onlineMode)
{
- _blockedZoom = 0; // reset to try again
try
{
URL tileUrl = new URL(_mapSource.makeURL(inLayer, _zoom, inX, inY));
else
{
// Load image asynchronously, using observer
- tile = Toolkit.getDefaultToolkit().createImage(tileUrl);
- // Pass to memory cache
- _tempCaches[inLayer].setTile(tile, inX, inY);
- if (tile.getWidth(this) > 0) {return tile;}
+ // tile = Toolkit.getDefaultToolkit().createImage(tileUrl);
+ // In order to set the http user agent, need to use a TileDownloader instead
+ TileDownloader.triggerLoad(this, tileUrl, inLayer, inX, inY, _zoom);
}
}
catch (MalformedURLException urle) {} // ignore
{
boolean loaded = (infoflags & ImageObserver.ALLBITS) > 0;
boolean error = (infoflags & ImageObserver.ERROR) > 0;
- if (error) {
- _blockedZoom = _zoom;
- }
if (loaded || error) {
_parent.tilesUpdated(loaded);
}
return !loaded;
}
+
+ /**
+ * Callback method from TileDownloader to let us know that an image has been loaded
+ * @param inTile Loaded Image object
+ * @param inLayer layer index from 0
+ * @param inX x coordinate of tile
+ * @param inY y coordinate of tile
+ * @param inZoom zoom level of loaded image
+ */
+ public void notifyImageLoaded(Image inTile, int inLayer, int inX, int inY, int inZoom)
+ {
+ if (inTile != null)
+ {
+ MemTileCacher tempCache = _tempCaches[inLayer]; // Should probably guard against nulls and array indexes here
+ if (tempCache.getTile(inX, inY) == null)
+ {
+ // Check with cache that the zoom level is still valid
+ tempCache.setTile(inTile, inX, inY, inZoom);
+ inTile.getWidth(this); // trigger imageUpdate when image is ready
+ }
+ }
+ }
}
/**
* Transform an x coordinate into a longitude
- * @param inX scaled X value from 0 to 1
+ * @param inX scaled X value from 0(-180deg) to 1(+180deg)
* @return longitude in degrees
*/
public static double getLongitudeFromX(double inX)
{
- return inX * 360.0 - 180.0;
+ // Ensure x is really between 0 and 1 (to wrap longitudes)
+ double x = ((inX % 1.0) + 1.0) % 1.0;
+ // Note: First %1.0 restricts range to (-1,1), then +1.0 shifts to (0,2)
+ // Finally, %1.0 to give (0,1)
+ return x * 360.0 - 180.0;
}
/**
// Mark boundaries as invalid
for (int i=0; i<GRID_SIZE; i++)
{
- _tiles[getArrayIndex(_tileX + GRID_SIZE/2 + 1, _tileY + i - GRID_SIZE/2)] = null;
- _tiles[getArrayIndex(_tileX + i - GRID_SIZE/2, _tileY + GRID_SIZE/2 + 1)] = null;
+ _tiles[getArrayIndexNoWrap(_tileX + GRID_SIZE/2 + 1, _tileY + i - GRID_SIZE/2)] = null;
+ _tiles[getArrayIndexNoWrap(_tileX + i - GRID_SIZE/2, _tileY + GRID_SIZE/2 + 1)] = null;
}
}
}
/**
- * Get the array index for the given coordinates
+ * Get the array index for the given coordinates, including regular lon wrapping
* @param inX x coord of tile
* @param inY y coord of tile
* @return array index
*/
private int getArrayIndex(int inX, int inY)
{
- //System.out.println("Getting array index for (" + inX + ", " + inY + ") where the centre is at (" + _tileX + ", " + _tileY
- // + ") and grid coords (" + _gridCentreX + ", " + _gridCentreY + ")");
+ final int tileSpan = 1 << _zoom;
+ int deltaX = (inX - _tileX);
+ while (deltaX > (tileSpan/2)) {deltaX -= tileSpan;}
+ while (deltaX < (-tileSpan/2)) {deltaX += tileSpan;}
+
+ int x = getCacheCoordinate(deltaX + _gridCentreX);
+ int y = getCacheCoordinate(inY - _tileY + _gridCentreY);
+ return (x + y * GRID_SIZE);
+ }
+
+ /**
+ * Get the array index for the given coordinates, without wrapping x coords
+ * (used for deletion to avoid deleting the wrong tile)
+ * @param inX x coord of tile
+ * @param inY y coord of tile
+ * @return array index
+ */
+ private int getArrayIndexNoWrap(int inX, int inY)
+ {
int x = getCacheCoordinate(inX - _tileX + _gridCentreX);
int y = getCacheCoordinate(inY - _tileY + _gridCentreY);
- //System.out.println("Transformed to (" + x + ", " + y + ")");
return (x + y * GRID_SIZE);
}
*/
public void clearAll()
{
- // Clear all images if zoom changed
for (int i=0; i<_tiles.length; i++) {
_tiles[i] = null;
}
* @param inTile image to save
* @param inX x coordinate of tile
* @param inY y coordinate of tile
+ * @param inZoom zoom level
*/
- public void setTile(Image inTile, int inX, int inY)
+ public void setTile(Image inTile, int inX, int inY, int inZoom)
{
- _tiles[getArrayIndex(inX, inY)] = inTile;
+ // Ignore images received for a different zoom level
+ if (inZoom == _zoom) {
+ _tiles[getArrayIndex(inX, inY)] = inTile;
+ }
}
}
package tim.prune.gui.map;
+import java.util.regex.Matcher;
import tim.prune.I18nManager;
/**
*/
public String makeURL(int inLayerNum, int inZoom, int inX, int inY)
{
- return _baseUrls[inLayerNum] + inZoom + "/" + inX + "/" + inY + "." + getFileExtension(inLayerNum);
+ // Check if the base url has a [1234], if so replace at random
+ return pickServerUrl(_baseUrls[inLayerNum])
+ + inZoom + "/" + inX + "/" + inY + "." + getFileExtension(inLayerNum);
}
/**
return _maxZoom;
}
+ /**
+ * If the base url contains something like [1234], then pick a server
+ * @param inBaseUrl base url
+ * @return modified base url
+ */
+ protected static final String pickServerUrl(String inBaseUrl)
+ {
+ if (inBaseUrl == null || inBaseUrl.indexOf('[') < 0) {
+ return inBaseUrl;
+ }
+ // Check for [.*] (once only)
+ // Only need to support one, make things a bit easier
+ final Matcher matcher = WILD_PATTERN.matcher(inBaseUrl);
+ // if not, return base url unchanged
+ if (!matcher.matches()) {
+ return inBaseUrl;
+ }
+ // if so, pick one at random and replace in the String
+ final String match = matcher.group(2);
+ final int numMatches = match.length();
+ String server = null;
+ if (numMatches > 0)
+ {
+ int matchNum = (int) Math.floor(Math.random() * numMatches);
+ server = "" + match.charAt(matchNum);
+ }
+ final String result = matcher.group(1) + (server==null?"":server) + matcher.group(3);
+ return result;
+ }
/**
* @return semicolon-separated list of all fields
import tim.prune.I18nManager;
import tim.prune.config.ColourScheme;
import tim.prune.config.Config;
+import tim.prune.data.Unit;
/**
* Class to show a scale bar on the main map of GpsPrune
if (_zoomLevel > -1)
{
try {
- boolean useMetric = Config.getConfigBoolean(Config.KEY_METRIC_UNITS);
- double drightSide = LEFT_OFFSET + _metricPixels[_zoomLevel] * (useMetric?1:1.609);
+ final double distScaleFactor = Config.getUnitSet().getDistanceUnit().getMultFactorFromStd();
+ double drightSide = LEFT_OFFSET + _metricPixels[_zoomLevel] / 1000.0 / distScaleFactor;
int scale = _scales[_zoomLevel];
// work out cos(latitude) from y position, and apply to scale
inG.drawLine(rightSide, Y_OFFSET+1, rightSide, Y_OFFSET-TICK_HEIGHT);
inG.drawLine(rightSide+1, Y_OFFSET+1, rightSide+1, Y_OFFSET-TICK_HEIGHT);
// text
- String text = getScaleText(scale, useMetric);
+ String text = getScaleText(scale, Config.getUnitSet().getDistanceUnit());
inG.setColor(blankColour);
inG.drawString(text, rightSide+MARGIN_WIDTH-1, Y_OFFSET);
inG.drawString(text, rightSide+MARGIN_WIDTH+1, Y_OFFSET);
/**
* Get the scale text for the given scale
* @param inScale scale number
- * @param inUseMetric true to use km/m, false for miles/ft
+ * @param inDistUnit distance unit
* @return scale text as string
*/
- private static String getScaleText(int inScale, boolean inUseMetric)
+ private static String getScaleText(int inScale, Unit inDistUnit)
{
if (inScale > 0) {
// Positive scale means km or miles
return "" + inScale + " " +
- I18nManager.getText(inUseMetric?"units.kilometres.short":"units.miles.short");
+ I18nManager.getText(inDistUnit.getShortnameKey());
}
- if (inUseMetric) {
- // negative scale means m
- return "" + (-1000 / inScale) + " " + I18nManager.getText("units.metres.short");
- }
- // fallen through to feet
- return "" + (-5280 / inScale) + " " + I18nManager.getText("units.feet.short");
+ // negative scale means a fraction
+ return "" + (-1.0 / inScale) + " " + I18nManager.getText(inDistUnit.getShortnameKey());
+ // might be nice to say 100m instead of 0.1km, 275ft instead of 0.2miles, etc - need to be done by Unit itself?
}
/**
--- /dev/null
+package tim.prune.gui.map;
+
+import java.awt.Image;
+import java.awt.Toolkit;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URL;
+import java.net.URLConnection;
+import java.util.HashSet;
+
+import tim.prune.GpsPrune;
+
+/**
+ * Class to asynchronously download a tile from a url
+ * and populate an Image object with the contents
+ */
+public class TileDownloader implements Runnable
+{
+ private MapTileManager _manager = null;
+ private URL _url = null;
+ private int _layer = 0;
+ private int _x = 0, _y = 0;
+ private int _zoom = 0;
+ /** Hashset of all blocked / 404 tiles to avoid requesting them again */
+ private static final HashSet<String> BLOCKED_URLS = new HashSet<String>();
+ /** Hashset of all currently loading tiles to avoid requesting them again */
+ private static final HashSet<String> LOADING_URLS = new HashSet<String>();
+
+
+ /**
+ * Constructor (private)
+ * @param inManager parent manager for callback
+ * @param inUrl URL to load
+ * @param inLayer layer index from 0
+ * @param inX x coordinate of tile
+ * @param inY y coordinate of tile
+ * @param inZoom zoom level
+ */
+ private TileDownloader(MapTileManager inManager, URL inUrl, int inLayer, int inX, int inY, int inZoom)
+ {
+ _manager = inManager;
+ _url = inUrl;
+ _layer = inLayer;
+ _x = inX; _y = inY;
+ _zoom = inZoom;
+ }
+
+ /**
+ * Trigger a download in a new thread
+ * @param inManager manager to callback when image is loaded
+ * @param inUrl URL to load
+ * @param inLayer layer index from 0
+ * @param inX x coordinate of tile
+ * @param inY y coordinate of tile
+ * @param inZoom current zoom level
+ */
+ public static synchronized void triggerLoad(MapTileManager inManager, URL inUrl, int inLayer,
+ int inX, int inY, int inZoom)
+ {
+ if (inManager != null && inUrl != null)
+ {
+ String url = inUrl.toString();
+ if (!BLOCKED_URLS.contains(url) && !LOADING_URLS.contains(url))
+ {
+ LOADING_URLS.add(url);
+ new Thread(new TileDownloader(inManager, inUrl, inLayer, inX, inY, inZoom)).start();
+ }
+ }
+ }
+
+ /**
+ * Run method, called in separate thread
+ */
+ public void run()
+ {
+ InputStream in = null;
+ try
+ {
+ // Set http user agent on connection
+ URLConnection conn = _url.openConnection();
+ conn.setRequestProperty("User-Agent", "GpsPrune v" + GpsPrune.VERSION_NUMBER);
+ in = conn.getInputStream();
+ int len = conn.getContentLength();
+ if (len > 0)
+ {
+ byte[] data = new byte[len];
+ int totalRead = 0;
+ while (totalRead < len)
+ {
+ int numRead = in.read(data, totalRead, len-totalRead);
+ totalRead += numRead;
+ }
+ Image tile = Toolkit.getDefaultToolkit().createImage(data);
+ in.close();
+
+ // Pass back to manager so it can be stored in its memory cache
+ _manager.notifyImageLoaded(tile, _layer, _x, _y, _zoom);
+ }
+ }
+ catch (IOException e)
+ {
+ System.err.println("IOE: " + e.getClass().getName() + " - " + e.getMessage());
+ synchronized(this.getClass())
+ {
+ BLOCKED_URLS.add(_url.toString());
+ }
+ try {in.close();} catch (Exception e2) {}
+ }
+ LOADING_URLS.remove(_url.toString());
+ }
+}
package tim.prune.gui.profile;
import tim.prune.I18nManager;
-import tim.prune.data.Altitude;
import tim.prune.data.DataPoint;
import tim.prune.data.Track;
+import tim.prune.data.UnitSet;
/**
* Class to provide a source of altitude data for the profile chart
*/
public class AltitudeData extends ProfileData
{
- /** Altitude format for values */
- private Altitude.Format _altitudeFormat = Altitude.Format.NO_FORMAT;
-
-
/**
* Constructor
* @param inTrack track object
/**
* Get the data and populate the instance arrays
*/
- public void init()
+ public void init(UnitSet inUnitSet)
{
+ setUnitSet(inUnitSet);
initArrays();
_hasData = false;
- _altitudeFormat = Altitude.Format.NO_FORMAT;
+ // multiplication factor for unit conversion
+ final double multFactor = _unitSet.getAltitudeUnit().getMultFactorFromStd();
if (_track != null)
{
for (int i=0; i<_track.getNumPoints(); i++)
DataPoint point = _track.getPoint(i);
if (point != null && point.hasAltitude())
{
- // Point has an altitude - if it's the first one, use its format
- if (_altitudeFormat == Altitude.Format.NO_FORMAT)
- {
- _altitudeFormat = point.getAltitude().getFormat();
- _minValue = _maxValue = point.getAltitude().getValue();
- }
- // Store the value and maintain max and min values
- double value = point.getAltitude().getValue(_altitudeFormat);
+ // Point has an altitude - store value and maintain max and min values
+ double value = point.getAltitude().getMetricValue() * multFactor;
_pointValues[i] = value;
- if (value < _minValue) {_minValue = value;}
- if (value > _maxValue) {_maxValue = value;}
+ if (value < _minValue || !_hasData) {_minValue = value;}
+ if (value > _maxValue || !_hasData) {_maxValue = value;}
_hasData = true;
_pointHasData[i] = true;
public String getLabel()
{
return I18nManager.getText("fieldname.altitude") + " ("
- + I18nManager.getText(_altitudeFormat==Altitude.Format.FEET?"units.feet.short":"units.metres.short")
+ + I18nManager.getText(_unitSet.getAltitudeUnit().getShortnameKey())
+ ")";
}
private JPopupMenu _popup = null;
/** Possible scales to use */
- private static final int[] LINE_SCALES = {10000, 5000, 2000, 1000, 500, 200, 100, 50, 10, 5};
+ private static final int[] LINE_SCALES = {10000, 5000, 2000, 1000, 500, 200, 100, 50, 10, 5, 2, 1};
/** Border width around black line */
private static final int BORDER_WIDTH = 6;
/** Minimum size for profile chart in pixels */
/** Colour to use for text if no data found */
private static final Color COLOR_NODATA_TEXT = Color.GRAY;
/** Chart type */
- private static enum ChartType {ALTITUDE, SPEED};
+ private static enum ChartType {ALTITUDE, SPEED, VERT_SPEED};
/**
_data = new AltitudeData(inTrackInfo.getTrack());
addMouseListener(this);
setLayout(new FlowLayout(FlowLayout.LEFT));
- _label = new JLabel("Altitude");
+ _label = new JLabel("Altitude"); // text will be replaced later
add(_label);
makePopup();
}
paintBackground(g, colourScheme);
if (_track != null && _track.getNumPoints() > 0)
{
- _data.init();
_label.setText(_data.getLabel());
int width = getWidth();
int height = getHeight();
// horizontal lines for scale - set to round numbers eg 500
int lineScale = getLineScale(minValue, maxValue);
int scaleValue = (int) (minValue/lineScale + 1) * lineScale;
+ if (minValue < 0.0) {scaleValue -= lineScale;}
int x = 0, y = 0;
+ final int zeroY = height - BORDER_WIDTH - (int) (yScaleFactor * (0.0 - minValue));
+
double value = 0.0;
- if (lineScale > 1)
+ g.setColor(lineColour);
+ if (lineScale >= 1)
{
- g.setColor(lineColour);
while (scaleValue < maxValue)
{
y = height - BORDER_WIDTH - (int) (yScaleFactor * (scaleValue - minValue));
scaleValue += lineScale;
}
}
+ else if (minValue < 0.0)
+ {
+ // just draw zero line
+ y = zeroY;
+ g.drawLine(BORDER_WIDTH + 1, y, width - BORDER_WIDTH - 1, y);
+ }
try
{
if (_data.hasData(p))
{
value = _data.getData(p);
- y = (int) (yScaleFactor * (value - minValue));
- g.fillRect(BORDER_WIDTH+x, height-BORDER_WIDTH - y, barWidth, y);
+ // Normal case is the minimum value greater than zero
+ if (minValue >= 0)
+ {
+ y = (int) (yScaleFactor * (value - minValue));
+ g.fillRect(BORDER_WIDTH+x, height-BORDER_WIDTH - y, barWidth, y);
+ }
+ else if (value >= 0.0) {
+ // Bar upwards from the zero line
+ y = height-BORDER_WIDTH - (int) (yScaleFactor * (value - minValue));
+ g.fillRect(BORDER_WIDTH+x, y, barWidth, zeroY - y);
+ }
+ else {
+ // Bar downwards from the zero line
+ int barHeight = (int) (yScaleFactor * value);
+ g.fillRect(BORDER_WIDTH+x, zeroY, barWidth, -barHeight);
+ }
}
}
// current point (make sure it's drawn last)
catch (NullPointerException npe) { // ignore, probably due to data being changed
}
// Draw numbers on top of the graph to mark scale
- if (lineScale > 1)
+ if (lineScale >= 1)
{
int textHeight = g.getFontMetrics().getHeight();
scaleValue = (int) (minValue / lineScale + 1) * lineScale;
+ if (minValue < 0.0) {scaleValue -= lineScale;}
y = 0;
g.setColor(currentColour);
while (scaleValue < maxValue)
changeView(ChartType.SPEED);
}});
_popup.add(speedItem);
+ JMenuItem vertSpeedItem = new JMenuItem(I18nManager.getText("fieldname.verticalspeed"));
+ vertSpeedItem.addActionListener(new ActionListener() {
+ public void actionPerformed(ActionEvent e)
+ {
+ changeView(ChartType.VERT_SPEED);
+ }});
+ _popup.add(vertSpeedItem);
}
/**
*/
private int getLineScale(double inMin, double inMax)
{
- if ((inMax - inMin) < 5 || inMax < 0) {
+ if ((inMax - inMin) < 2.0) {
return -1;
}
int numScales = LINE_SCALES.length;
*/
public void dataUpdated(byte inUpdateType)
{
- _data.init();
+ // Try not to recalculate all the values unless necessary
+ if (inUpdateType != SELECTION_CHANGED) {
+ _data.init(Config.getUnitSet());
+ }
repaint();
}
else if (inType == ChartType.SPEED && !(_data instanceof SpeedData)) {
_data = new SpeedData(_track);
}
- _data.init();
+ else if (inType == ChartType.VERT_SPEED && !(_data instanceof VerticalSpeedData)) {
+ _data = new VerticalSpeedData(_track);
+ }
+ _data.init(Config.getUnitSet());
repaint();
}
package tim.prune.gui.profile;
import tim.prune.data.Track;
+import tim.prune.data.UnitSet;
/**
* Abstract class for all sources of profile data,
{
/** Track object */
protected final Track _track;
+ /** Unit set to use */
+ protected UnitSet _unitSet = null;
/** Flag for availability of any data */
protected boolean _hasData = false;
/** Array of booleans for data per point */
/**
* Get the data from the track and populate the value arrays
*/
- public abstract void init();
+ public abstract void init(UnitSet inUnitSet);
+
+ /**
+ * Set the UnitSet to use for the calculations
+ * @param inUnitSet unit set
+ */
+ protected void setUnitSet(UnitSet inUnitSet) {
+ _unitSet = inUnitSet;
+ }
/**
* @return text for label including units
package tim.prune.gui.profile;
import tim.prune.I18nManager;
-import tim.prune.config.Config;
-import tim.prune.data.DataPoint;
-import tim.prune.data.Distance;
+import tim.prune.data.SpeedCalculator;
+import tim.prune.data.SpeedValue;
import tim.prune.data.Track;
-import tim.prune.data.Distance.Units;
+import tim.prune.data.UnitSet;
/**
* Class to provide a source of speed data for the profile chart
*/
public class SpeedData extends ProfileData
{
- /** Flag for metric units */
- private boolean _metric = true;
-
/**
* Constructor
* @param inTrack track object
/**
* Get the data and populate the instance arrays
*/
- public void init()
+ public void init(UnitSet inUnitSet)
{
+ setUnitSet(inUnitSet);
initArrays();
- _metric = Config.getConfigBoolean(Config.KEY_METRIC_UNITS);
_hasData = false;
_minValue = _maxValue = 0.0;
- if (_track != null) {
- DataPoint prevPrevPoint = null, prevPoint = null, point = null;
+ SpeedValue speed = new SpeedValue();
+ if (_track != null)
+ {
for (int i=0; i<_track.getNumPoints(); i++)
{
- point = _track.getPoint(i);
- if (prevPrevPoint != null && prevPrevPoint.hasTimestamp()
- && prevPoint != null && prevPoint.hasTimestamp()
- && point != null && point.hasTimestamp())
+ // Get the speed either from the speed value or from the distances and timestamps
+ SpeedCalculator.calculateSpeed(_track, i, speed);
+ if (speed.isValid())
{
- // All three points have timestamps
- double seconds = point.getTimestamp().getSecondsSince(prevPrevPoint.getTimestamp());
- if (seconds > 0)
- {
- double distInRads = DataPoint.calculateRadiansBetween(prevPrevPoint, prevPoint)
- + DataPoint.calculateRadiansBetween(prevPoint, point);
- double dist = Distance.convertRadiansToDistance(distInRads, _metric?Units.KILOMETRES:Units.MILES);
- // Store the value and maintain max and min values
- double value = dist / seconds * 60.0 * 60.0;
- _pointValues[i-1] = value;
- if (value < _minValue || _minValue == 0.0) {_minValue = value;}
- if (value > _maxValue) {_maxValue = value;}
-
- _hasData = true;
- _pointHasData[i-1] = true;
- }
+ double speedValue = speed.getValue();
+ _pointValues[i] = speedValue;
+ if (speedValue < _minValue || _minValue == 0.0) {_minValue = speedValue;}
+ if (speedValue > _maxValue) {_maxValue = speedValue;}
+ _hasData = true;
}
- // Exchange points
- prevPrevPoint = prevPoint;
- prevPoint = point;
+ _pointHasData[i] = speed.isValid();
}
}
}
public String getLabel()
{
return I18nManager.getText("fieldname.speed") + " ("
- + I18nManager.getText(_metric?"units.kmh":"units.mph") + ")";
+ + I18nManager.getText(_unitSet.getSpeedUnit().getShortnameKey()) + ")";
}
/**
--- /dev/null
+package tim.prune.gui.profile;
+
+import tim.prune.I18nManager;
+import tim.prune.data.SpeedCalculator;
+import tim.prune.data.SpeedValue;
+import tim.prune.data.Track;
+import tim.prune.data.UnitSet;
+
+/**
+ * Class to provide a source of vertical speed data for the profile chart
+ */
+public class VerticalSpeedData extends ProfileData
+{
+ /**
+ * Constructor
+ * @param inTrack track object
+ */
+ public VerticalSpeedData(Track inTrack) {
+ super(inTrack);
+ }
+
+ /**
+ * Get the data and populate the instance arrays
+ */
+ public void init(UnitSet inUnitSet)
+ {
+ setUnitSet(inUnitSet);
+ initArrays();
+ _hasData = false;
+ _minValue = _maxValue = 0.0;
+ SpeedValue speed = new SpeedValue();
+ if (_track != null)
+ {
+ for (int i=0; i<_track.getNumPoints(); i++)
+ {
+ SpeedCalculator.calculateVerticalSpeed(_track, i, speed);
+ // Check whether we got a value from either method
+ if (speed.isValid())
+ {
+ // Store the value and maintain max and min values
+ double speedValue = speed.getValue();
+ _pointValues[i] = speedValue;
+ if (speedValue < _minValue || _minValue == 0.0) {_minValue = speedValue;}
+ if (speedValue > _maxValue) {_maxValue = speedValue;}
+ _hasData = true;
+ }
+ _pointHasData[i] = speed.isValid();
+ }
+ }
+ }
+
+ /**
+ * @return text description including units
+ */
+ public String getLabel()
+ {
+ return I18nManager.getText("fieldname.verticalspeed") + " ("
+ + I18nManager.getText(_unitSet.getVerticalSpeedUnit().getShortnameKey()) + ")";
+ }
+
+ /**
+ * @return key for message when no speeds present
+ */
+ public String getNoDataKey()
+ {
+ if (!_track.hasAltitudeData()) {
+ return "display.noaltitudes";
+ }
+ return "display.notimestamps";
+ }
+}
# Text entries for the GpsPrune application
-# Afrikaans entries as extra
+# Afrikaans entries
# Menu entries
menu.file=L\u00eaer
menu.range.none=Selekteer Niks
menu.range.start=Stel Reeks Begin
menu.range.end=Stel Reeks Einde
-menu.range.deleterange=Reeks Uitvee
-menu.range.interpolate=Interpoleer
+function.deleterange=Reeks Uitvee
+function.interpolate=Interpoleer punte
menu.range.average=Gemiddelde Seleksie
menu.range.reverse=Reeks Omkeer
menu.range.mergetracksegments=Saamvoeg van spoor segmente
menu.point.deletepoint=Punt Uitvee
menu.photo=Foto
menu.photo.saveexif=Stoor na EXIF
+menu.audio=Audio
menu.view=Kyk
+menu.view.showsidebars=Wys kantstawe
menu.view.browser=Kaart in werf blaaier
menu.view.browser.google=Google Kaarte
menu.view.browser.openstreetmap=Openstreetmap
menu.view.browser.yahoo=Yahoo Kaarte
menu.view.browser.bing=Bing Kaarte
menu.settings=Stellings
+menu.settings.onlinemode=Laai kaarte vanaf internet
+menu.settings.autosave=Autostoor stellings op uitgaan
menu.help=Hulp
# Popup menu for map
menu.map.zoomin=Zoom in
menu.map.zoomout=Zoom uit
menu.map.zoomfull=Zoom na vol skaal
menu.map.newpoint=Skep nuwe punt
+menu.map.drawpoints=Skep reeks van punte
menu.map.connect=Connekteer baan punte
menu.map.autopan=Automatiese Skuif van Kyk Venster
menu.map.showmap=Wys Kaart
# Alt keys for menus
altkey.menu.file=L
+altkey.menu.track=B
altkey.menu.range=R
altkey.menu.point=P
altkey.menu.view=K
altkey.menu.photo=F
+altkey.menu.audio=A
altkey.menu.settings=S
altkey.menu.help=H
function.compress=Kompakteer spoor
function.addtimeoffset=Voeg tyd spruit by
function.addaltitudeoffset=Voeg hoogte spruit by
-function.convertnamestotimes=Omskakel baken name na tye
+function.convertnamestotimes=Skakel baken name na tye
+function.deletefieldvalues=Verwyder veld waardes
function.findwaypoint=Vind Baken
function.pastecoordinates=Enter nuwe koordinate
function.charts=Grafieke
-function.show3d=3D Kyk
+function.show3d=3D Vertoon
function.distances=Afstande
function.fullrangedetails=Vol reeks besonderhede
function.setmapbg=Stel Kaart agtergrond
+function.setkmzimagesize=Stel KMZ beeld groote
function.setpaths=Stel program paaie
function.getgpsies=Kry GPS spore
+function.lookupsrtm=Kry hoogtes vanaf SRTM
function.duplicatepoint=Dupliseer Punt
function.setcolours=Stel kleure
+function.setlinewidth=Stel lyn dikte
function.setlanguage=Stel tale
function.connecttopoint=Las foto by huidige punt
function.disconnectfrompoint=Ontkoppel vanaf huidige punt
function.ignoreexifthumb=Ignoreer EXIF thumbnail
function.help=Hulp
function.showkeys=Wys Kortpad sleutels
-function.about=Omtrent Prune
+function.about=Omtrent GpsPrune
function.checkversion=Kyk vir nuwe weergawe
function.saveconfig=Stoor Stellings
+function.diskcache=Stoor kaarte na skyf
# Dialogs
-dialog.exit.confirm.title=Uitgaan uit Prune
+dialog.exit.confirm.title=Uitgaan uit GpsPrune
dialog.exit.confirm.text=Jou data is nie gestoor nie. Is jy seker jy wil uitgaan?
dialog.openappend.title=Voegby tot bestaande data
dialog.openappend.text=Voeg hierdie data by die data wat alreeds gelaai is?
dialog.load.table.field=Veld
dialog.load.table.datatype=Data Tipe
dialog.load.table.description=Beskrywing
-dialog.delimiter.label=Veld Skeinding Karakter
+dialog.delimiter.label=Veld Skeiding Karakter
dialog.delimiter.comma=Komma ,
dialog.delimiter.tab=Tab
dialog.delimiter.space=Spasie
dialog.openoptions.deliminfo.records=Rekords, met
dialog.openoptions.deliminfo.fields=velde
dialog.openoptions.deliminfo.norecords=Geen rekords
-dialog.openoptions.altitudeunits=Hoogte Eenhede
+dialog.openoptions.altitudeunits=Hoogte eenhede
+dialog.open.contentsdoubled=Hierdie leer bevat twee kopie van elke punt,\n once eenkeer as baken en eenkeer as spoor punt
+dialog.selecttracks.intro=Selekteer die spoor of spore om te laai
+dialog.selecttracks.noname=on benaamd
dialog.jpegload.subdirectories=Sluit sub-gidse in
dialog.jpegload.loadjpegswithoutcoords=Sluit fotos sonder koordinate in
dialog.jpegload.loadjpegsoutsidearea=Sluit foto buitekant huidige area in
dialog.exportpov.ballsandsticks=Balle en stokkies
dialog.exportpov.tubesandwalls=Buise en mure
dialog.exportpov.warningtracksize=Hierdie spoor het 'n groot aantal punte, wat Java3D miskien nie kan vertoon.\nIs jy seker jy wil voortgaan?
+dialog.exportsvg.text=Selekteer die parameters vir die SVG uitvoer
+dialog.exportsvg.phi=Azimuth hoek \u03d5
+dialog.exportsvg.theta=Opstandings angle \u03b8
dialog.pointtype.desc=Stoor die volgende punt tipes
dialog.pointtype.track=Spoor punte
dialog.pointtype.waypoint=Bakens
dialog.pointtype.photo=Foto punte
+dialog.pointtype.selection=Net seleksie
dialog.confirmreversetrack.title=Bevestig omkering
dialog.confirmreversetrack.text=Hierdie spoor bevat tydstempel informasie, wat uit sekwensie/order sal wees na omkering.\nIs jy seker jy wil die spoor omruil vir die seksie?
dialog.confirmcutandmove.title=Bevestig sny en skuif
dialog.confirmcutandmove.text=Hierdie spoor het tydstempel informasie, wat uit sekwensie/orde sal wees na skuif.\nIs jy seker jy wil die seksie skuif?
-dialog.interpolate.title=Interpoleer punte
dialog.interpolate.parameter.text=Aantal punte om bytevoeg tussen geselekteerde punte.
dialog.undo.title=Herroep aksie(s)
dialog.undo.pretext=Selekteer asb die aksie(s) om te herroep
dialog.clearundo.title=Maak Herroep lys uit skoon
dialog.clearundo.text=Is jy seker jy wil die herroep lys skoon maak?\nAlle herroep informasie sal verlore gaan!
dialog.pointedit.title=Redigeer punt
+dialog.pointedit.text=Selekteer elke veld om te wysig en gebruik die 'Wysig' knoppie om die waarde te verander
dialog.pointedit.table.field=Veld
dialog.pointedit.table.value=Waarde
dialog.pointedit.table.changed=Verander
+dialog.pointedit.changevalue.text=Sleutel die nuwe waarde vir hierdie veld.
+dialog.pointedit.changevalue.title=Wysig veld
dialog.pointnameedit.name=Baken naam
dialog.pointnameedit.uppercase=Hoof letter
dialog.pointnameedit.lowercase=Klein letter
dialog.addtimeoffset.days=Dae
dialog.addtimeoffset.hours=Ure
dialog.addtimeoffset.minutes=Minute
+dialog.findwaypoint.intro=Sleutel gedeelte van baken naam
dialog.findwaypoint.search=Soek
dialog.saveexif.title=Stoor Exif
+dialog.saveexif.table.photoname=Foto naam
dialog.saveexif.table.status=Status
dialog.saveexif.table.save=Stoor
+dialog.saveexif.photostatus.connected=Verbind
+dialog.saveexif.photostatus.disconnected=Afgesluit
+dialog.saveexif.photostatus.modified=Verander
+dialog.saveexif.overwrite=Oorskruif leers
+dialog.saveexif.force=Vorseer ten spyte van klein foute
+dialog.charts.xaxis=X as
+dialog.charts.yaxis=Y as
+dialog.charts.output=Uitset
+dialog.charts.screen=Uitset na skerm
+dialog.charts.svg=Uitset na SVG leer
+dialog.charts.svgwidth=SVG wydte
+dialog.charts.svgheight=SVG hoogte
+dialog.charts.needaltitudeortimes=die spoor moet of hoogtes of tyd informasie bevat om grafiek teskep
+dialog.charts.gnuplotnotfound=Kon nie gnuplot find op gegewe pad
+dialog.distances.intro=Reguit lyn afstande tussen punte
+dialog.distances.column.from=Vanaf punt
+dialog.distances.column.to=Na punt
+dialog.distances.currentpoint=Huidige Punt
+dialog.distances.toofewpoints=Hierdie funksie benodig bakens om afstande tussen bakens uit tewerk
+dialog.fullrangedetails.intro=Hier is die besonderhede for die geselekteerde reeks
+dialog.setmapbg.intro=Selekteer een van die kaart bronne, of voeg nuwe een by
+dialog.addmapsource.title=Voeg nuwe kaart bron by
+dialog.addmapsource.sourcename=Naam van bron
+dialog.correlate.notimestamps=Daar is geen tyd stempels in die data punte, so daar is niks om te korreleer met die fotos
+dialog.correlate.nouncorrelatedphotos=Daar is geen ongekorreleerde fotos.\nIs jy seker jy wil voortgaan?
+dialog.correlate.photoselect.intro=Selekteer een van die gekorreleerde fotos om te gebruik as tyd afset
+dialog.correlate.select.photoname=Foto naam
+dialog.correlate.select.timediff=Tyd verskil
+dialog.correlate.select.photolater=Foto later
+dialog.correlate.options.tip=Wenk: Deur een item te verbind, kan die tyd afset bereken word vir jou.
+dialog.correlate.options.intro=Seleketeer die opsies vir automatiese korrelasie
+dialog.correlate.options.offsetpanel=Tyd afset
+dialog.correlate.options.offset=Afset
+dialog.correlate.options.offset.hours=ure,
+dialog.correlate.options.offset.minutes=minute en
+dialog.correlate.options.offset.seconds=sekondes
+dialog.correlate.options.photolater=Foto later as punt
+dialog.correlate.options.pointlaterphoto=Punt later as foto
+dialog.correlate.options.limitspanel=Korrelasie limiete
+dialog.correlate.options.notimelimit=Geen tyd limiet
+dialog.correlate.options.timelimit=Tyd limiet
+dialog.correlate.options.nodistancelimit=Geen afstand limiet
+dialog.correlate.options.distancelimit=Afstand limiet
+dialog.correlate.options.correlate=Korreleer
+dialog.correlate.alloutsiderange=Al die fotos is buitekant die tyd reeks van die spoor, so geen kon gekorreleer word.\nProbeer om afset te stel of omself ten minste een foto te korreleer.
+dialog.correlate.correltimes=Vir korrelasie gebruik:
+dialog.correlate.timestamp.beginning=Begin
+dialog.correlate.timestamp.middle=Middel
+dialog.correlate.timestamp.end=Einde
+dialog.rearrangephotos.tostart=Beweeg na begin
+dialog.rearrangephotos.toend=Beweeg na einde
+dialog.rearrangephotos.nosort=Nie sorteer
+dialog.rearrangephotos.sortbyfilename=Sorteer volgens leernaam
+dialog.rearrangephotos.sortbytime=Sorteer volgens tyd
+dialog.compress.closepoints.title=Naby punt verwydering
+dialog.compress.closepoints.paramdesc=Span faktor
+dialog.compress.wackypoints.title=Gekkige punt verwydering
+dialog.compress.wackypoints.paramdesc=Afstands faktor
+dialog.compress.singletons.paramdesc=Afstand faktor
+dialog.compress.duplicates.title=Duplikaat verwydering
+dialog.compress.douglaspeucker.title=Douglas-Peuker kompressie
+dialog.compress.summarylabel=Punte om te verwyder
+dialog.deletemarked.nonefound=Geen data punt kon verwyder word
+dialog.pastecoordinates.desc=Sleutel of plak die koordinate hier
+dialog.pastecoordinates.coords=Koordinate
+dialog.pastecoordinates.nothingfound=Gaan asseblief koordinate na en probeer weer
+dialog.help.help=Sien asseblief\n http://activityworkshop.net/software/gpsprune/\n vir meer inligting en gebruikers handleidings.
+dialog.about.version=Weergawe
+dialog.about.build=Bou
+dialog.about.summarytext1=GpsPrune is 'n program vir die laai, vertoon en wysiging van data vanaf GPS ontvangers.
+dialog.about.languages=Beskikbare tale
+dialog.about.translatedby=Engelse teks deur activityworkshop
+dialog.about.systeminfo=Stelsel informasie
+dialog.about.systeminfo.os=Beheer Stelsel
+dialog.about.systeminfo.java3d=Java3d geinstalleer
+dialog.about.systeminfo.povray=Povray geinstalleer
+dialog.about.systeminfo.exiftool=Exiftool geinstalleer
+dialog.about.systeminfo.gpsbabel=Gpsbabel geinstalleer
+dialog.about.systeminfo.gnuplot=Gnuplot geinstalleer
+dialog.about.systeminfo.exiflib=Exif biblioteek
+dialog.about.systeminfo.exiflib.internal=Intern
+dialog.about.systeminfo.exiflib.internal.failed=Interne (nie gevind)
+dialog.about.systeminfo.exiflib.external=Ektern
+dialog.about.systeminfo.exiflib.external.failed=Ekstern (nie gevind)
+dialog.about.yes=Ja
+dialog.about.no=Nee
+dialog.about.credits=Krediete
+dialog.about.credits.code=GpsPrune bron kode geskruif deur
+dialog.about.credits.exifcode=Exif bron kode deur
+dialog.about.credits.icons=Somigge ikone gevat vanaf
+dialog.about.credits.translators=Vertalers
+dialog.about.credits.translations=Vertalings gehelp deur
+dialog.about.credits.devtools=Onwikkelings gereedskap
+dialog.about.credits.othertools=Ander gereedskap
+dialog.about.credits.thanks=Dankie aan
+dialog.about.readme=Leesmy
+
+# Field names
+fieldname.latitude=breedtegraad
+fieldname.longitude=lengtegraad
+fieldname.altitude=Hoogte
+fieldname.timestamp=Tyd
+fieldname.time=Tyd
+fieldname.waypointname=Naam
+fieldname.waypointtype=Tipe
+fieldname.newsegment=Segment
+fieldname.custom=Persoonlike
+fieldname.prefix=Veld
+fieldname.distance=Afstand
+fieldname.movingdistance=Beweeg afstand
+fieldname.duration=Tydperk
+fieldname.speed=Spoed
+fieldname.verticalspeed=Vertikale spoed
+fieldname.description=Beskrywing
+
+# Measurement units
+units.original=Oorspronklik
+units.default=Bestek
+units.metres=Meters
+units.metres.short=m
+units.feet=Voet
+units.feet.short=ft
+units.kilometres=Kilo meters
+units.kilometres.short=km
+units.miles=Myl
+units.miles.short=mi
+units.hours=ure
+units.degminsec=Deg-min-sec
+units.degmin=Deg-min
+units.deg=Grade
+units.iso8601=ISO 8601
+
+# Cardinals for 3d plots
+cardinal.n=N
+cardinal.s=S
+cardinal.e=O
+cardinal.w=W
+
+# Undo operations
+undo.load=laai data
+undo.loadphotos=laai fotos
+undo.editpoint=eind punt
+undo.deletepoint=verwyder punt
+undo.removephoto=verwyder foto
+undo.deleterange=verwyder reeks
+undo.insert=voeg punte by
+undo.reverse=keer baan om
+undo.mergetracksegments=smelt baan segmente
+undo.addtimeoffset=voeg tyd afset
+undo.addaltitudeoffset=voeg hoogte afset
+undo.rearrangewaypoints=herrangskik
+undo.cutandmove=beweeg seksie
+undo.connect=verbind
+undo.disconnect=afsluit
+undo.correlatephotos=korreleer fotos
+undo.rearrangephotos=herrangskik fotos
+undo.createpoint=skep punt
+undo.rotatephoto=roteer foto
+undo.convertnamestotimes=skakel name na tye
+undo.lookupsrtm=soek hoogtes vanaf SRTM
+undo.deletefieldvalues=verwyder veld waardes
+
+# Error messages
+error.save.dialogtitle=Fout om data te stoor
+error.save.nodata=Geen data om te stoor
+error.save.failed=Stoor van data na l\u00eaer het misluk
+error.saveexif.filenotfound=Find van foto het misluk
+error.saveexif.cannotoverwrite1=Foto leer
+error.saveexif.cannotoverwrite2=is lees-alleen en kan nie oorskruif word nie. Skyf na kopie?
+error.saveexif.failed1=Stoor het misluk
+error.saveexif.failed2=van die beelde
+error.saveexif.forced2=van die beelde vereis vorsering
+error.load.dialogtitle=Fout met laai van data
+error.load.noread=Kan nie leer lees
+error.load.nopoints=Geen koordinaat informasie gevind in the leer
+error.load.unknownxml=Onherkenbare xml formaat:
+error.load.noxmlinzip=Geen xml leer gevind binne zip leer
+error.jpegload.dialogtitle=Fout met fotos laai
+error.jpegload.nofilesfound=Geen leers gevind
+error.jpegload.nojpegsfound=Geen jpeg leers gevind
+error.jpegload.nogpsfound=Geen GPS informasie gevind
+error.gpsload.unknown=Onbekende fout
+error.function.noop.title=Funksie het geen effek gehad
+error.rearrange.noop=Herrangskikking van punte het geen effek gehad
+error.function.notavailable.title=Funksie nie beskikbaar
+error.3d='n fout het gebeur met die 3d vertoon
+error.readme.notfound=Readme leer nie gevind
+error.osmimage.dialogtitle=Fout met laai van kaart beelde
+error.osmimage.failed=Milsukking met die laai van kaart beelde.Toets internet conneksie
+error.language.wrongfile=Die geselekteerde leer lyk nie soos 'n taal leer vir GpsPrune
+error.convertnamestotimes.nonames=Geen name kon in tye omgeskakel word
+error.lookupsrtm.nonefound=Geen hoogte waardes beskikbaar vir die punte
+error.lookupsrtm.nonerequired=Al die punte het klaar hoogtes, so daar is niks meer om te soek
+error.gpsies.uploadnotok=Die gpsies server het die boodskap terug gestuur
+error.gpsies.uploadfailed=Die oplaai het misluk met die volgende fout boodskap
menu.track=Trasa
menu.track.undo=Undo
menu.track.clearundo=Vypr\u00e1zdnit pam\u011b\u0165 undo
+menu.track.markrectangle=Ozna\u010dit body v obd\u00e9ln\u00edku
menu.track.deletemarked=Smazat ozna\u010den\u00e9 body
menu.track.rearrange=P\u0159euspo\u0159\u00e1dat z\u00e1jmov\u00e9 body
menu.track.rearrange.start=V\u0161e na po\u010d\u00e1tek
menu.range.none=Zru\u0161it v\u00fdb\u011br
menu.range.start=Nastavit za\u010d\u00e1tek rozmez\u00ed
menu.range.end=Nastavit konec rozmez\u00ed
-menu.range.deleterange=Smazat rozmez\u00ed
-menu.range.interpolate=Interpolovat
menu.range.average=St\u0159ed z v\u00fdb\u011bru
menu.range.reverse=Obr\u00e1tit rozmez\u00ed
menu.range.mergetracksegments=Slou\u010dit \u010d\u00e1sti trasy
menu.map.autopan=Automatika zorn\u00e9ho pole
menu.map.showmap=Zobrazit mapu
menu.map.showscalebar=Zobrazit m\u011b\u0159\u00edtko
+menu.map.editmode=Edita\u010dn\u00ed m\u00f3d
# Alt keys for menus
altkey.menu.file=S
function.exportsvg=Export SVG
function.editwaypointname=Nastavit n\u00e1zev v\u00fdzna\u010dn\u00e9ho bodu
function.compress=Komprimovat trasu
+function.deleterange=Smazat rozmez\u00ed
+function.croptrack=O\u0159\u00edznout trasu
+function.interpolate=Interpolovat body
function.addtimeoffset=P\u0159idat \u010dasov\u00fd posun
function.addaltitudeoffset=P\u0159idat v\u00fd\u0161kov\u00fd posun
function.convertnamestotimes=P\u0159ev\u00e9st n\u00e1zvy v\u00fdzna\u010dn\u00fdch bod\u016f na \u010dasy
dialog.deletepoint.deletephoto=Odebrat fotografii p\u0159ipojenou k tomuto bodu?
dialog.deletephoto.title=Odebrat fotografii
dialog.deletephoto.deletepoint=Smazat bod p\u0159ipojen\u00fd k t\u00e9to fotografii?
+dialog.deleteaudio.deletepoint=Smazat bod p\u0159ipojen\u00fd k t\u00e9to audionahr\u00e1vce?
dialog.openoptions.title=Volby p\u0159i na\u010dten\u00ed
dialog.openoptions.filesnippet=N\u00e1hled souboru
dialog.load.table.field=Pole
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?
dialog.confirmcutandmove.title=Potvr\u010fte p\u0159esun
dialog.confirmcutandmove.text=Tato trasa obsahuje \u010dasov\u00e9 zna\u010dky, jejich\u017e po\u0159ad\u00ed se p\u0159esunem zm\u011bn\u00ed.\nOpravdu chcete v\u00fdb\u011br p\u0159esunout?
-dialog.interpolate.title=Interpolovat body
dialog.interpolate.parameter.text=Po\u010det bod\u016f, kter\u00e9 se maj\u00ed p\u0159idat mezi vybran\u00e9 body
+dialog.interpolate.betweenwaypoints=Vlo\u017eit nov\u00e9 body trasy mezi v\u00fdzna\u010dn\u00fdmi body?
dialog.undo.title=Vr\u00e1tit akci (akce)
dialog.undo.pretext=Pros\u00edm vyberte akci (akce) k vr\u00e1cen\u00ed
dialog.undo.none.title=Nelze vr\u00e1tit
dialog.pointnameedit.name=N\u00e1zev v\u00fdzna\u010dn\u00e9ho bodu
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.pointnameedit.titlecase=Po\u010d\u00e1te\u010dn\u00ed P\u00edsmena Velk\u00e1
dialog.addtimeoffset.add=P\u0159idat \u010das
dialog.addtimeoffset.subtract=Odebrat \u010das
dialog.addtimeoffset.days=Dny
dialog.distances.currentpoint=Aktu\u00e1ln\u00ed bod
dialog.distances.toofewpoints=Je t\u0159eba zadat v\u00edce bod\u016f, aby bylo mo\u017en\u00e9 vypo\u010d\u00edst jejich vzd\u00e1lenost
dialog.fullrangedetails.intro=Zobrazuji detaily vybran\u00e9ho rozmez\u00ed
+dialog.fullrangedetails.coltotal=V\u010detn\u011b p\u0159eru\u0161en\u00ed
+dialog.fullrangedetails.colsegments=Bez p\u0159eru\u0161en\u00ed
dialog.setmapbg.intro=Vyberte jeden ze zdroj\u016f map nebo p\u0159idejte nov\u00fd
dialog.addmapsource.title=P\u0159idat nov\u00fd zdroj map
dialog.addmapsource.sourcename=N\u00e1zev zdroje
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.nouncorrelatedaudios=V\u0161echny audionahr\u00e1vky 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.select.photoname=N\u00e1zev fotografie
dialog.correlate.select.timediff=\u010casov\u00fd rozd\u00edl
dialog.rearrangephotos.nosort=Neuspo\u0159\u00e1d\u00e1vat
dialog.rearrangephotos.sortbyfilename=Uspo\u0159\u00e1dat dle n\u00e1zvu souboru
dialog.rearrangephotos.sortbytime=Uspo\u0159\u00e1dat dle \u010dasu
-dialog.compress.nonefound=Nemohou b\u00fdt odstran\u011bny \u017e\u00e1dn\u00e9 body trasy
dialog.compress.closepoints.title=Odstran\u011bn\u00ed bl\u00edzk\u00fdch bod\u016f
dialog.compress.closepoints.paramdesc=Koeficient bl\u00edzkosti
dialog.compress.wackypoints.title=Odstran\u011bn\u00ed ust\u0159elen\u00fdch bod\u016f
dialog.compress.douglaspeucker.title=Douglasova-Peuckerova komprese
dialog.compress.douglaspeucker.paramdesc=Povolen\u00e1 odchylka
dialog.compress.summarylabel=Bod\u016f ke smaz\u00e1n\u00ed
+dialog.compress.confirm1=Bylo ozna\u010deno celkem
+dialog.compress.confirm2=bod\u016f.\nBody je mo\u017en\u00e9 smazat volbou Trasa->Smazat ozna\u010den\u00e9 body
+dialog.compress.confirmnone=Nebyly vybr\u00e1ny \u017e\u00e1dn\u00e9 body.
+dialog.deletemarked.nonefound=Nemohou b\u00fdt odstran\u011bny \u017e\u00e1dn\u00e9 body trasy
dialog.pastecoordinates.desc=Zadejte sou\u0159adnice
dialog.pastecoordinates.coords=Sou\u0159adnice
dialog.pastecoordinates.nothingfound=Pros\u00edm ov\u011b\u0159te sou\u0159adnice a zkuste znovu
dialog.saveconfig.prune.gpsdevice=Za\u0159\u00edzen\u00ed GPS
dialog.saveconfig.prune.gpsformat=Form\u00e1t GPS
dialog.saveconfig.prune.povrayfont=Font Povray
-dialog.saveconfig.prune.metricunits=Pou\u017e\u00edvat metrick\u00e9 jednotky?
dialog.saveconfig.prune.gnuplotpath=Cesta k gnuplot
dialog.saveconfig.prune.gpsbabelpath=Cesta k gpsbabel
dialog.saveconfig.prune.exiftoolpath=Cesta k exiftool
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.diskcache.cannotwrite=Neda\u0159\u00ed se ulo\u017eit mapov\u00e9 podklady do zvolen\u00e9ho adres\u00e1\u0159e
dialog.diskcache.table.path=Cesta
dialog.diskcache.table.usedby=Pou\u017e\u00edv\u00e1
dialog.diskcache.table.zoom=Zv\u011bt\u0161en\u00ed
confirm.rearrangewaypoints=Body p\u0159euspo\u0159\u00e1d\u00e1ny
confirm.rearrangephotos=Fotografie p\u0159euspo\u0159\u00e1d\u00e1ny
confirm.cutandmove=V\u00fdb\u011br p\u0159esunut
+confirm.interpolate=Body p\u0159id\u00e1ny
confirm.convertnamestotimes=N\u00e1zvy bod\u016f p\u0159evedeny
confirm.saveexif.ok1=Ulo\u017eeno
confirm.saveexif.ok2=fotografi\u00ed
display.range.time.hours=h
display.range.time.days=d
details.range.avespeed=Pr\u016fm. rychlost
-details.range.avemovingspeed=Okam\u017e. rychlost
details.range.maxspeed=Max. rychlost
details.range.numsegments=Po\u010det segment\u016f
details.range.pace=Tempo
details.photo.loading=Na\u010d\u00edt\u00e1m
details.photo.bearing=Azimut
details.media.connected=P\u0159ipojeno
+details.media.fullpath=\u00dapln\u00e1 cesta
details.audiodetails=Detaily audionahr\u00e1vky
details.noaudio=Audionahr\u00e1vka nevybr\u00e1na
details.audio.file=Zvukov\u00fd soubor
units.feet.short=stop
units.kilometres=Kilometry
units.kilometres.short=km
-units.kmh=km/h
+units.kilometresperhour.short=km/h
units.miles=M\u00edle
units.miles.short=mil
-units.mph=mph
-units.metrespersec=m/s
-units.feetpersec=stop/s
+units.milesperhour.short=mph
+units.nauticalmiles=N\u00e1mo\u0159n\u00ed m\u00edle
+units.nauticalmiles.short=N.m.
+units.nauticalmilesperhour.short=uzly
+units.metrespersec.short=m/s
+units.feetpersec.short=stop/s
units.hours=hodin
units.degminsec=Deg-min-sec
units.degmin=Deg-min
undo.removephoto=odebrat fotografii
undo.removeaudio=odebrat audionahr\u00e1vku
undo.deleterange=smazat rozmez\u00ed
-undo.compress=zkomprimovat trasu
+undo.croptrack=o\u0159\u00edznout trasu
+undo.deletemarked=zkomprimovat trasu
undo.insert=vlo\u017eit body
undo.reverse=obr\u00e1tit rozmez\u00ed
undo.mergetracksegments=slou\u010dit \u010d\u00e1sti trasy
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.showphoto.failed=Nepoda\u0159ilo se na\u010d\u00edst fotografii
error.playaudiofailed=Nepoda\u0159ilo se p\u0159ehr\u00e1t zvukov\u00fd soubor.
error.cache.notthere=Nepoda\u0159ilo se nal\u00e9zt adres\u00e1\u0159 s cache map.
error.cache.empty=Adres\u00e1\u0159 s cache map je pr\u00e1zdn\u00fd.
error.cache.cannotdelete=Nelze smazat soubory map.
+error.interpolate.invalidparameter=Po\u010det bod\u016f mus\u00ed b\u00fdt mezi 1 a 1000
--- /dev/null
+# Text entries for the GpsPrune application
+# Danish translations
+
+# Menu entries
+menu.file=Fil
+menu.file.addphotos=Tilf\u00f8j billeder
+menu.file.recentfiles=Seneste filer
+menu.file.save=Gem som tekst
+menu.file.exit=Afslut
+menu.track.undo=Fortryd
+menu.track.clearundo=Nulstil fortrydelsesliste
+menu.track.deletemarked=Slet markerede punkter
+menu.track.rearrange=Omorganis\u00e9r waypoints
+menu.track.rearrange.nearest=Hvert waypoint til n\u00e6rmeste nabo
+menu.range=Omr\u00e5de
+menu.range.all=V\u00e6lg alle
+menu.range.none=Ingen valgt
+menu.range.start=V\u00e6lg omr\u00e5des startpunkt
+menu.range.end=V\u00e6lg omr\u00e5des slutpunkt
+menu.range.average=Dan gennemsnit af valgte omr\u00e5de
+menu.range.reverse=Dan omvendt r\u00e6kkef\u00f8lge
+menu.range.mergetracksegments=Sammensmelt sporsegmenter
+menu.range.cutandmove=Afsk\u00e6r og flyt valgte omr\u00e5de
+menu.point=Punkt
+menu.point.editpoint=Redig\u00e8r punkt
+menu.point.deletepoint=Fjern punkt
+menu.photo=Foto
+menu.photo.saveexif=Gem Exif-data
+menu.audio=Lyd
+menu.view=Udseende
+menu.view.showsidebars=Vis sidepanel
+menu.view.browser=Kort i browser
+menu.settings=Indstillinger
+menu.settings.onlinemode=Hent kort fra Internettet
+menu.settings.autosave=Gem indstillinger automatisk ved aflutning
+menu.help=Hj\u00e6lp
+# Popup menu for map
+menu.map.zoomin=Zoom ind
+menu.map.zoomout=Zoom ud
+menu.map.newpoint=Skab nyt punkt
+menu.map.drawpoints=Skab serie af punkter
+menu.map.connect=Saml punkter p\u00e5 linie
+menu.map.autopan=Autocentrering
+menu.map.showmap=Vis kort
+menu.map.showscalebar=Vis m\u00e5lestok
+
+# Alt keys for menus
+altkey.menu.file=F
+altkey.menu.track=S
+altkey.menu.range=O
+altkey.menu.point=P
+altkey.menu.view=U
+altkey.menu.photo=T
+altkey.menu.audio=L
+altkey.menu.settings=I
+altkey.menu.help=H
+
+# Functions
+function.open=\u00c5bn fil
+function.importwithgpsbabel=Import\u00e9r fil med GPSBabel
+function.loadfromgps=Hent data fra GPS
+function.sendtogps=Overf\u00f8r data til GPS
+function.exportkml=Eksport\u00e9r KML
+function.exportgpx=Eksport\u00e9r GPX
+function.exportpov=Eksport\u00e9r POV
+function.exportsvg=Eksport\u00e9r SVG
+function.editwaypointname=Ret waypoint-navn
+function.compress=Komprim\u00e9r spor
+function.deleterange=Fjern det valgte omr\u00e5de
+function.croptrack=Afgr\u00e6ns spor
+function.interpolate=Interpol\u00e9r
+function.addtimeoffset=Tilf\u00f8j offset p\u00e5 tiden
+function.addaltitudeoffset=Tilf\u00f8j offset p\u00e5 h\u00f8jde
+function.convertnamestotimes=Ret waypoint-navne til tidspunkter
+function.deletefieldvalues=Fjern feltv\u00e6rdier
+function.findwaypoint=Find waypoint
+function.pastecoordinates=Indf\u00f8j nye koordinater
+function.charts=Kort
+function.show3d=3-D view
+function.distances=Afstande
+function.fullrangedetails=Vis alle detaljer
+function.setmapbg=V\u00e6lg kort som baggrund
+function.setkmzimagesize=V\u00e6lg KMZ billedst\u00f8rrelse
+function.setpaths=V\u00e6lg sti til programmer
+function.getgpsies=Se liste af GPS-spor
# Text entries for the GpsPrune application
-# German entries as extra
+# German entries
# Menu entries
menu.file=Datei
menu.file.addphotos=Fotos laden
menu.file.recentfiles=Zuletzt verwendete Dateien
-menu.file.save=Als Text Speichern
+menu.file.save=Als Text speichern
menu.file.exit=Beenden
menu.track=Track
menu.track.undo=R\u00fcckg\u00e4ngig
menu.track.clearundo=Liste der letzten \u00c4nderungen l\u00f6schen
-menu.track.deletemarked=Komprimierte Punkte l\u00f6schen
-menu.track.rearrange=Wegpunkte reorganisieren
+menu.track.markrectangle=Punkte im Viereck markieren
+menu.track.deletemarked=Markierte Punkte l\u00f6schen
+menu.track.rearrange=Wegpunkte neu anordnen
menu.track.rearrange.start=Alle Wegpunkte zum Anfang
menu.track.rearrange.end=Alle Wegpunkte ans Ende
menu.track.rearrange.nearest=Jeden Wegpunkt zum n\u00e4chsten Trackpunkt verschieben
menu.range.none=Nichts markieren
menu.range.start=Startpunkt setzen
menu.range.end=Endpunkt setzen
-menu.range.deleterange=Bereich l\u00f6schen
-menu.range.interpolate=Interpolieren
menu.range.average=Durchschnitt berechnen
menu.range.reverse=Bereich umkehren
menu.range.mergetracksegments=Trackabschnitte verbinden
-menu.range.cutandmove=Schneiden und verschieben
+menu.range.cutandmove=Auswahl vor den markierten Punkt verschieben
menu.point=Punkt
menu.point.editpoint=Punkt bearbeiten
menu.point.deletepoint=Punkt l\u00f6schen
menu.photo=Foto
-menu.photo.saveexif=Exif Daten speichern
+menu.photo.saveexif=Exif-Daten speichern
menu.audio=Audio
menu.view=Ansicht
menu.view.showsidebars=Seitenleisten anzeigen
-menu.view.browser=Karte in Browser
+menu.view.browser=Karte in Browser anzeigen
+menu.view.browser.google=Google Maps
+menu.view.browser.openstreetmap=OpenStreetMap
+menu.view.browser.mapquest=Mapquest
+menu.view.browser.yahoo=Yahoo Maps
+menu.view.browser.bing=Bing Maps
menu.settings=Einstellungen
menu.settings.onlinemode=Karten aus dem Internet laden
menu.settings.autosave=Einstellungen automatisch speichern
menu.map.autopan=Autozentrierung
menu.map.showmap=Karte zeigen
menu.map.showscalebar=Ma\u00dfstab anzeigen
+menu.map.editmode=Punkte verschieben
# Alt keys for menus
altkey.menu.file=D
function.open=Datei \u00f6ffnen
function.importwithgpsbabel=Datei mit GPSBabel importieren
function.loadfromgps=Vom GPS laden
-function.sendtogps=zum GPS schicken
+function.sendtogps=Zum GPS schicken
function.exportkml=KML exportieren
function.exportgpx=GPX exportieren
function.exportpov=POV exportieren
function.exportsvg=SVG exportieren
-function.editwaypointname=Wegpunkt Name bearbeiten
+function.editwaypointname=Name des Punkts bearbeiten
function.compress=Track komprimieren
+function.deleterange=Bereich l\u00f6schen
+function.croptrack=Track zuschneiden
+function.interpolate=Punkte interpolieren
function.addtimeoffset=Zeitverschiebung aufrechnen
function.addaltitudeoffset=H\u00f6henverschiebung aufrechnen
-function.convertnamestotimes=Wegpunktenamen in Zeitstempel umwandeln
+function.convertnamestotimes=Namen der Wegpunkte in Zeitstempel umwandeln
function.deletefieldvalues=Werte eines Feldes l\u00f6schen
function.findwaypoint=Wegpunkt finden
-function.pastecoordinates=Neue Koordinaten eingeben
+function.pastecoordinates=Neuen Wegpunkt anlegen
function.charts=Diagramme
function.show3d=3D Ansicht
function.distances=Entfernungen
function.setmapbg=Karte Hintergrund setzen
function.setkmzimagesize=Bildgr\u00f6\u00dfe im KMZ setzen
function.setpaths=Programmpfade setzen
-function.getgpsies=Gpsies Tracks holen
-function.uploadgpsies=Daten zum Gpsies hochladen
-function.lookupsrtm=H\u00f6hendaten von SRTM holen
+function.getgpsies=Tracks bei GPSies.com herunterladen
+function.uploadgpsies=Track zu GPSies.com hochladen
+function.lookupsrtm=H\u00f6hendaten von SRTM herunterladen
function.getwikipedia=Wikipediaartikel in der N\u00e4he nachschlagen
function.searchwikipedianames=Wikipedia mit Name durchsuchen
-function.downloadosm=OSM Daten f\u00fcr dieses Gebiet herunterladen
+function.downloadosm=OSM-Daten f\u00fcr dieses Gebiet herunterladen
function.duplicatepoint=Punkt verdoppeln
function.setcolours=Farben einstellen
function.setlinewidth=Liniendicke einstellen
function.disconnectfrompoint=Vom Punkt trennen
function.removephoto=Foto entfernen
function.correlatephotos=Fotos korrelieren
-function.rearrangephotos=Fotos reorganisieren
-function.rotatephotoleft=Foto nach Links drehen
-function.rotatephotoright=Foto nach Rechts drehen
+function.rearrangephotos=Fotos neu anordnen
+function.rotatephotoleft=Foto nach links drehen
+function.rotatephotoright=Foto nach rechts drehen
function.photopopup=Fotofenster anzeigen
-function.ignoreexifthumb=Exif Vorschaubild ignorieren
+function.ignoreexifthumb=Exif-Vorschaubild ignorieren
function.loadaudio=Audiodateien laden
function.removeaudio=Audiodatei entfernen
-function.correlateaudios=Audios korrelieren
+function.correlateaudios=Audiodateien korrelieren
function.playaudio=Audiodatei abspielen
function.stopaudio=Abspielen abbrechen
function.help=Hilfe
dialog.deletepoint.deletephoto=Das zu diesem Punkt geh\u00f6rende Foto ebenfalls l\u00f6schen?
dialog.deletephoto.title=Foto entfernen
dialog.deletephoto.deletepoint=Den zu diesem Foto geh\u00f6renden Punkt auch l\u00f6schen?
+dialog.deleteaudio.deletepoint=Den zu dieser Audiodatei geh\u00f6renden Punkt auch l\u00f6schen?
dialog.openoptions.title=\u00d6ffnen
dialog.openoptions.filesnippet=Dateiausschnitt
dialog.load.table.field=Feld
dialog.load.table.datatype=Datentyp
dialog.load.table.description=Beschreibung
-dialog.delimiter.label=Feld Trennzeichen
+dialog.delimiter.label=Feld-Trennzeichen
dialog.delimiter.comma=Komma ,
-dialog.delimiter.tab=Tab
+dialog.delimiter.tab=Tabulator
dialog.delimiter.space=Leerzeichen
dialog.delimiter.semicolon=Strichpunkt ;
dialog.delimiter.other=Andere
dialog.openoptions.deliminfo.records=Datens\u00e4tze, mit
dialog.openoptions.deliminfo.fields=Feldern
dialog.openoptions.deliminfo.norecords=Keine Datens\u00e4tze
-dialog.openoptions.altitudeunits=H\u00f6he Ma\u00dfeinheiten
-dialog.open.contentsdoubled=Diese Datei enth\u00e4lt zwei Kopien von jedem Punkt,\neinmal als Waypoint und einmal als Trackpunkt.
+dialog.openoptions.altitudeunits=Ma\u00dfeinheiten f\u00fcr die H\u00f6he
+dialog.open.contentsdoubled=Diese Datei enth\u00e4lt zwei Kopien jedes Punkts,\neinmal als Waypoint und einmal als Trackpunkt.
dialog.selecttracks.intro=W\u00e4hlen Sie den Track oder die Tracks aus, die Sie laden m\u00f6chten
dialog.selecttracks.noname=Unbenannt
dialog.jpegload.subdirectories=Unterordner mit durchsuchen
dialog.jpegload.loadjpegswithoutcoords=Auch Fotos ohne Koordinaten laden
-dialog.jpegload.loadjpegsoutsidearea=Auch Fotos ausserhalb des Tracks laden
+dialog.jpegload.loadjpegsoutsidearea=Auch Fotos au\u00dferhalb des Tracks laden
dialog.jpegload.progress.title=Fotos werden geladen
-dialog.jpegload.progress=Bitte warten w\u00e4hrend die Fotos durchsucht werden
-dialog.gpsload.nogpsbabel=Programm gpsbabel wurde nicht gefunden. Weiter?
+dialog.jpegload.progress=Bitte warten, w\u00e4hrend die Fotos durchsucht werden
+dialog.gpsload.nogpsbabel=Programm GPSBabel wurde nicht gefunden. Weiter?
dialog.gpsload.device=Ger\u00e4tename
dialog.gpsload.format=Format
dialog.gpsload.getwaypoints=Wegpunkte laden
dialog.save.table.hasdata=Enth\u00e4lt Daten
dialog.save.table.save=Speichern
dialog.save.headerrow=Titelzeile speichern
-dialog.save.coordinateunits=Koordinaten Ma\u00dfeinheiten
-dialog.save.altitudeunits=H\u00f6he Ma\u00dfeinheiten
+dialog.save.coordinateunits=Format der Koordinaten
+dialog.save.altitudeunits=Ma\u00dfeinheiten f\u00fcr die H\u00f6he
dialog.save.timestampformat=Zeitstempelformat
dialog.save.overwrite.title=Datei schon vorhanden
dialog.save.overwrite.text=Diese Datei gibt es schon. Wollen Sie die vorhandene Datei \u00fcberschreiben?
dialog.save.notypesselected=Keine Punktetypen sind ausgew\u00e4hlt
dialog.exportkml.text=Titel f\u00fcr die Daten
dialog.exportkml.altitude=Absolute H\u00f6heninformation (f\u00fcr Luftfahrt)
-dialog.exportkml.kmz=Daten in kmz Datei komprimieren
-dialog.exportkml.exportimages=Vorschaubilder mit in kmz exportieren
+dialog.exportkml.kmz=Daten in KMZ-Datei komprimieren
+dialog.exportkml.exportimages=Vorschaubilder mit in KMZ-Datei exportieren
dialog.exportkml.trackcolour=Trackfarbe
dialog.exportgpx.name=Name
dialog.exportgpx.desc=Beschreibung
dialog.exportgpx.includetimestamps=Zeitstempel mit exportieren
-dialog.exportgpx.copysource=Xml von Quelle kopieren
+dialog.exportgpx.copysource=XML von Quelle kopieren
dialog.exportgpx.encoding=Enkodierung
dialog.exportgpx.encoding.system=System
dialog.exportgpx.encoding.utf8=UTF-8
-dialog.exportpov.text=Geben Sie die Parameter f\u00fcr den POV Export ein
+dialog.exportpov.text=Geben Sie die Parameter f\u00fcr den POV-Export ein
dialog.exportpov.font=Font
dialog.exportpov.camerax=Kamera X
dialog.exportpov.cameray=Kamera Y
dialog.exportpov.ballsandsticks=B\u00e4lle und Stangen
dialog.exportpov.tubesandwalls=R\u00f6hren und W\u00e4nde
dialog.exportpov.warningtracksize=Dieser Track hat sehr viele Punkte, die Java3D vielleicht nicht bearbeiten kann.\nM\u00f6chten Sie den Vorgang trotzdem fortsetzen?
-dialog.exportsvg.text=W\u00e4hlen Sie die Parameter f\u00fcr den SVG Export aus
+dialog.exportsvg.text=W\u00e4hlen Sie die Parameter f\u00fcr den SVG-Export aus
dialog.exportsvg.phi=Richtungswinkel \u03d5
dialog.exportsvg.theta=Neigungswinkel \u03b8
dialog.exportsvg.gradients=Farbverl\u00e4ufe verwenden
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?
dialog.confirmcutandmove.title=Verschieben best\u00e4tigen
dialog.confirmcutandmove.text=Diese Daten enthalten Zeitangaben, die nach dem Verschieben in falscher Reihenfolge erscheinen w\u00fcrden.\nSind Sie sicher, dass Sie diesen Bereich verschieben wollen?
-dialog.interpolate.title=Punkte interpolieren
dialog.interpolate.parameter.text=Anzahl Punkte, die zwischen den gew\u00e4hlten Punkten eingef\u00fcgt werden sollen
+dialog.interpolate.betweenwaypoints=Zwischen den Wegpunkten interpolieren?
dialog.undo.title=Aktionen R\u00fcckg\u00e4ngig
dialog.undo.pretext=Bitte die Operationen, die r\u00fcckg\u00e4ngig gemacht werden sollen, ausw\u00e4hlen.
dialog.undo.none.title=Undo nicht m\u00f6glich
dialog.clearundo.title=Undo-Liste l\u00f6schen
dialog.clearundo.text=Wollen Sie wirklich die Undo-Liste l\u00f6schen?\nAlle Undo- Informationen werden verloren gehen!
dialog.pointedit.title=Punkt bearbeiten
-dialog.pointedit.text=W\u00e4hlen Sie die Felder aus, die Sie bearbeiten m\u00f6chten, und verwenden Sie den 'Bearbeiten' Knopf, um den Wert zu \u00e4ndern
+dialog.pointedit.text=W\u00e4hlen Sie die Felder aus, die Sie bearbeiten m\u00f6chten, und verwenden Sie den 'Bearbeiten'-Button, um den Wert zu \u00e4ndern
dialog.pointedit.table.field=Feld
dialog.pointedit.table.value=Wert
dialog.pointedit.table.changed=Ge\u00e4ndert
dialog.pointedit.changevalue.text=Geben Sie den neuen Wert f\u00fcr dieses Feld ein
dialog.pointedit.changevalue.title=Feld bearbeiten
-dialog.pointnameedit.name=Wegpunkt Name
-dialog.pointnameedit.uppercase=GRO\u00df geschrieben
+dialog.pointnameedit.name=Name des Wegpunkts
+dialog.pointnameedit.uppercase=GROSS geschrieben
dialog.pointnameedit.lowercase=klein geschrieben
-dialog.pointnameedit.sentencecase=Gemischt geschrieben
+dialog.pointnameedit.titlecase=Gemischt geschrieben
dialog.addtimeoffset.add=Zeit addieren
dialog.addtimeoffset.subtract=Zeit subtrahieren
dialog.addtimeoffset.days=Tage
dialog.saveexif.title=Exif speichern
dialog.saveexif.intro=W\u00e4hlen Sie die Fotos zum Speichern aus
dialog.saveexif.nothingtosave=Koordinaten sind unver\u00e4ndert. Es gibt nichts zu speichern.
-dialog.saveexif.noexiftool=Kein exiftool Programm gefunden. Trotzdem fortfahren?
-dialog.saveexif.table.photoname=Foto Name
+dialog.saveexif.noexiftool=Kein ExifTool-Programm gefunden. Trotzdem fortfahren?
+dialog.saveexif.table.photoname=Name des Fotos
dialog.saveexif.table.status=Status
dialog.saveexif.table.save=Speichern
dialog.saveexif.photostatus.connected=Verbunden
dialog.saveexif.photostatus.modified=Modifiziert
dialog.saveexif.overwrite=Dateien \u00fcberschreiben
dialog.saveexif.force=Erzwingen trotz geringf\u00fcgiger Fehler
-dialog.charts.xaxis=X Achse
-dialog.charts.yaxis=Y Achse
+dialog.charts.xaxis=X-Achse
+dialog.charts.yaxis=Y-Achse
dialog.charts.output=Ausgabe
dialog.charts.screen=Ausgabe auf Bildschirm
-dialog.charts.svg=Ausgabe in SVG Datei
-dialog.charts.svgwidth=SVG Breite
-dialog.charts.svgheight=SVG H\u00f6he
-dialog.charts.needaltitudeortimes=Ohne Daten \u00fcber H\u00f6he und Zeit kann kein Diagramm erzeugt werden.
+dialog.charts.svg=Ausgabe in SVG-Datei
+dialog.charts.svgwidth=SVG-Breite
+dialog.charts.svgheight=SVG-H\u00f6he
+dialog.charts.needaltitudeortimes=Ohne Daten zu H\u00f6he und Zeit kann kein Diagramm erzeugt werden.
dialog.charts.gnuplotnotfound=Gnuplot konnte im angegebenen Pfad nicht gefunden werden
dialog.distances.intro=Luftlinienentfernung zwischen Punkten
dialog.distances.column.from=Vom Punkt
dialog.distances.column.to=Zum Punkt
dialog.distances.currentpoint=Aktueller Punkt
-dialog.distances.toofewpoints=Diese Funktion braucht Wegpunkte um die Distanzen zu berechnen
-dialog.fullrangedetails.intro=Hier sind die Details des markierten Bereichs
+dialog.distances.toofewpoints=Diese Funktion braucht Wegpunkte, um die Distanzen zu berechnen
+dialog.fullrangedetails.intro=Detaillierte Angaben zum markierten Bereich
+dialog.fullrangedetails.coltotal=Mit L\u00fccken
+dialog.fullrangedetails.colsegments=Ohne L\u00fccken
dialog.setmapbg.intro=Eine der Quellen ausw\u00e4hlen oder eine neue hinzuf\u00fcgen
dialog.addmapsource.title=Neue Kartenquelle hinzuf\u00fcgen
dialog.addmapsource.sourcename=Name der Quelle
dialog.addmapsource.maxzoom=Maximales Zoom
dialog.addmapsource.cloudstyle=Stilnummer
dialog.addmapsource.noname=Unbenannt
-dialog.gpsies.column.name=Track Name
+dialog.gpsies.column.name=Name des Tracks
dialog.gpsies.column.length=L\u00e4nge
dialog.gpsies.description=Beschreibung
dialog.gpsies.nodescription=Keine Beschreibung
dialog.gpsies.nonefound=Keine Tracks gefunden
-dialog.gpsies.username=Gpsies Username
-dialog.gpsies.password=Gpsies Passwort
+dialog.gpsies.username=Username bei GPSies.com
+dialog.gpsies.password=Passwort bei GPSies.com
dialog.gpsies.keepprivate=Track privat halten
dialog.gpsies.confirmopenpage=Webseite f\u00fcr den hochgeladenen Track \u00f6ffnen?
dialog.gpsies.activities=Aktivit\u00e4ten
dialog.gpsies.activity.trekking=Wandern
dialog.gpsies.activity.walking=Walking
dialog.gpsies.activity.jogging=Laufen
-dialog.gpsies.activity.biking=Fahrradtour
-dialog.gpsies.activity.motorbiking=Motorrad
-dialog.gpsies.activity.snowshoe=Schneeschuh
+dialog.gpsies.activity.biking=Fahrradfahren
+dialog.gpsies.activity.motorbiking=Motorradfahren
+dialog.gpsies.activity.snowshoe=Schneeschuhwandern
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.nouncorrelatedaudios=Alle Audiodateien 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.select.photoname=Bezeichnung des Fotos
dialog.correlate.select.timediff=Zeitdifferenz
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.limitspanel=Grenzen der Korrelation
dialog.correlate.options.notimelimit=Keine Zeitgrenzen
dialog.correlate.options.timelimit=Zeitgrenzen
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.alloutsiderange=Alle Elemente liegen au\u00dferhalb des Track-Zeitraums und k\u00f6nnen deshalb nicht korreliert werden.\nVersuchen Sie es mit einem anderen Offset oder binden Sie manuell mindestens ein Element ein.
dialog.correlate.filetimes=Die Datei Zeitstempel zeigen:
dialog.correlate.filetimes2=der Tonspuren
-dialog.correlate.correltimes=F\u00fcr das Korrelieren, folgendes verwenden:
+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.audioselect.intro=W\u00e4hlen Sie eines dieser Audiodateien 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.nosort=Nicht sortieren
dialog.rearrangephotos.sortbyfilename=per Dateiname sortieren
dialog.rearrangephotos.sortbytime=per Zeitstempel sortieren
-dialog.compress.nonefound=Es konnten keine Punkte entfernt werden
dialog.compress.closepoints.title=Nahegelegene Punkte entfernen
-dialog.compress.closepoints.paramdesc=Span Faktor
+dialog.compress.closepoints.paramdesc=Span-Faktor
dialog.compress.wackypoints.title=Ungew\u00f6hnliche Punkte entfernen
dialog.compress.wackypoints.paramdesc=Distanzfaktor
dialog.compress.singletons.title=Singletons (isolierte Punkte) entfernen
dialog.compress.singletons.paramdesc=Distanzfaktor
dialog.compress.duplicates.title=Duplikate entfernen
-dialog.compress.douglaspeucker.title=Douglas-Peucker Komprimierung
-dialog.compress.douglaspeucker.paramdesc=Span Faktor
-dialog.compress.summarylabel=Punkte zu entfernen
-dialog.pastecoordinates.desc=Geben Sie die Koordinaten ein
+dialog.compress.douglaspeucker.title=Douglas-Peucker-Komprimierung
+dialog.compress.douglaspeucker.paramdesc=Span-Faktor
+dialog.compress.summarylabel=Zu entfernende Punkte
+dialog.compress.confirm1=Es wurden
+dialog.compress.confirm2=Punkte markiert.\nMit Track->Markierte Punkte l\u00f6schen werden sie gel\u00f6scht
+dialog.compress.confirmnone=es wurden keine Punkte markiert
+dialog.deletemarked.nonefound=Es konnten keine Punkte entfernt werden
+dialog.pastecoordinates.desc=Koordinaten eingeben oder einf\u00fcgen
dialog.pastecoordinates.coords=Koordinaten
dialog.pastecoordinates.nothingfound=Bitte pr\u00fcfen Sie die Koordinaten und versuchen Sie es nochmals
dialog.help.help=Weitere Informationen und Benutzeranleitungen finden Sie unter\n http://activityworkshop.net/software/gpsprune/
dialog.about.version=Version
dialog.about.build=Build
-dialog.about.summarytext1=GpsPrune ist ein Programm zum Laden, Darstellen und Editieren von Daten von GPS Ger\u00e4ten.
-dialog.about.summarytext2=Es wird unter der Gnu GPL zur Verf\u00fcgung gestellt, zum freien, kostenlosen und offenen Gebrauch und zur Weiterentwicklung.<br>Kopieren, Weiterverbreitung und Ver\u00e4nderungen sind erlaubt und willkommen<br>unter den in der <code>license.txt</code> Datei enthaltenen Bedingungen.
+dialog.about.summarytext1=GpsPrune ist ein Programm zum Laden, Darstellen und Editieren der Daten von GPS- Ger\u00e4ten.
+dialog.about.summarytext2=Es wird unter der Gnu GPL zur Verf\u00fcgung gestellt zum freien, kostenlosen und offenen Gebrauch und zur Weiterentwicklung.<br>Das Kopieren, Weiterverbreiten und Ver\u00e4ndern ist erlaubt und willkommen<br>unter den in der Datei <code>license.txt</code> enthaltenen Bedingungen.
dialog.about.summarytext3=Auf der Seite <code style="font-weight:bold">http://activityworkshop.net/</code> finden Sie weitere Informationen und Bedienungsanleitungen.
dialog.about.languages=Verf\u00fcgbare Sprachen
dialog.about.translatedby=Deutsche \u00dcbersetzung von activityworkshop.
-dialog.about.systeminfo=System Informationen
+dialog.about.systeminfo=System-Informationen
dialog.about.systeminfo.os=Betriebssystem
dialog.about.systeminfo.java=Java Runtime
dialog.about.systeminfo.java3d=Java3d installiert
dialog.about.systeminfo.povray=Povray installiert
-dialog.about.systeminfo.exiftool=Exiftool installiert
-dialog.about.systeminfo.gpsbabel=Gpsbabel installiert
+dialog.about.systeminfo.exiftool=ExifTool installiert
+dialog.about.systeminfo.gpsbabel=GPSBabel installiert
dialog.about.systeminfo.gnuplot=Gnuplot installiert
-dialog.about.systeminfo.exiflib=Exif Bibliothek
+dialog.about.systeminfo.exiflib=Exif-Bibliothek
dialog.about.systeminfo.exiflib.internal=Intern
dialog.about.systeminfo.exiflib.internal.failed=Intern (nicht gefunden)
dialog.about.systeminfo.exiflib.external=Extern
dialog.about.systeminfo.exiflib.external.failed=Extern (nicht gefunden)
dialog.about.yes=Ja
dialog.about.no=Nein
-dialog.about.credits=Credits
-dialog.about.credits.code=GpsPrune Code geschrieben von
-dialog.about.credits.exifcode=Exif Code von
+dialog.about.credits=Danksagung
+dialog.about.credits.code=GpsPrune-Code geschrieben von
+dialog.about.credits.exifcode=Exif-Code von
dialog.about.credits.icons=Einige Bilder von
dialog.about.credits.translators=Dolmetscher
dialog.about.credits.translations=\u00dcbersetzungen mit Hilfe von
dialog.about.credits.devtools=Entwicklungsprogramme
dialog.about.credits.othertools=Andere Programme
dialog.about.credits.thanks=Dank an
-dialog.about.readme=Liesmich
-dialog.checkversion.error=Die Versionnummer konnte nicht ermittelt werden.\nBitte pr\u00fcfen Sie die Internet Verbindung.
+dialog.about.readme=Lies mich
+dialog.checkversion.error=Die Versionnummer konnte nicht ermittelt werden.\nBitte pr\u00fcfen Sie die Internet-Verbindung.
dialog.checkversion.uptodate=Sie haben schon die neueste Version von GpsPrune.
-dialog.checkversion.newversion1=Eine neue Version vom GpsPrune ist jetzt verf\u00fcgbar! Die neue Version ist Version
+dialog.checkversion.newversion1=Eine neue Version von GpsPrune ist jetzt verf\u00fcgbar! Die neue Version ist Version
dialog.checkversion.newversion2=.
dialog.checkversion.releasedate1=Diese neue Version ist am
dialog.checkversion.releasedate2=ver\u00f6ffentlicht worden.
dialog.checkversion.download=Um die neue Version herunterzuladen, gehen Sie zu http://activityworkshop.net/software/gpsprune/download.html.
dialog.keys.intro=Anstelle der Maus k\u00f6nnen Sie folgende Tastenkombinationen nutzen
-dialog.keys.keylist=<table><tr><td>Pfeil Tasten</td><td>Karte verschieben</td></tr><tr><td>Strg + links, rechts Pfeil</td><td>Vorherigen oder n\u00e4chsten Punkt markieren</td></tr><tr><td>Strg + auf, abw\u00e4rts Pfeil</td><td>Ein- oder Auszoomen</td></tr><tr><td>Strg + Bild auf, ab</td><td>Vorherigen oder n\u00e4chsten Segment markieren</td></tr><tr><td>Strg + Pos1, Ende</td><td>Ersten oder letzten Punkt markieren</td></tr><tr><td>Entf</td><td>Aktuellen Punkt entfernen</td></tr></table>
+dialog.keys.keylist=<table><tr><td>Pfeil Tasten</td><td>Karte verschieben</td></tr><tr><td>Strg + Links-, Rechts-Pfeil</td><td>Vorherigen oder n\u00e4chsten Punkt markieren</td></tr><tr><td>Strg + Auf-, Abw\u00e4rts-Pfeil</td><td>Ein- oder Auszoomen</td></tr><tr><td>Strg + Bild auf, ab</td><td>Vorheriges oder n\u00e4chstes Segment markieren</td></tr><tr><td>Strg + Pos1, Ende</td><td>Ersten oder letzten Punkt markieren</td></tr><tr><td>Entf</td><td>Aktuellen Punkt entfernen</td></tr></table>
dialog.keys.normalmodifier=Strg
dialog.keys.macmodifier=Kommando
dialog.saveconfig.desc=Die folgende Einstellungen k\u00f6nnen gespeichert werden:
dialog.saveconfig.prune.photodirectory=Fotoverzeichnis
dialog.saveconfig.prune.languagecode=Sprachcode (DE)
dialog.saveconfig.prune.languagefile=Sprachdatei
-dialog.saveconfig.prune.gpsdevice=GPS Ger\u00e4tename
-dialog.saveconfig.prune.gpsformat=GPS Format
-dialog.saveconfig.prune.povrayfont=Povray Font
-dialog.saveconfig.prune.metricunits=Metrische Einheiten verwenden?
-dialog.saveconfig.prune.gnuplotpath=Gnuplot Pfad
-dialog.saveconfig.prune.gpsbabelpath=Gpsbabel Pfad
-dialog.saveconfig.prune.exiftoolpath=Exiftool Pfad
-dialog.saveconfig.prune.mapsource=Kartenserver Index
+dialog.saveconfig.prune.gpsdevice=GPS-Ger\u00e4tename
+dialog.saveconfig.prune.gpsformat=GPS-Format
+dialog.saveconfig.prune.povrayfont=Povray-Font
+dialog.saveconfig.prune.gnuplotpath=Gnuplot-Pfad
+dialog.saveconfig.prune.gpsbabelpath=GPSBabel-Pfad
+dialog.saveconfig.prune.exiftoolpath=ExifTool-Pfad
+dialog.saveconfig.prune.mapsource=Kartenserver-Index
dialog.saveconfig.prune.mapsourcelist=Kartenserver
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.saveconfig.prune.kmltrackcolour=KML-Trackfarbe
dialog.saveconfig.prune.autosavesettings=Einstellungen speichern
-dialog.setpaths.intro=Sie k\u00f6nnen hier die Pfade f\u00fcr externe Applikationen setzen:
+dialog.setpaths.intro=Sie k\u00f6nnen hier die Pfade f\u00fcr externe Programme setzen:
dialog.setpaths.found=Pfad gefunden?
dialog.addaltitude.noaltitudes=Der markierte Bereich enth\u00e4lt keine H\u00f6henangaben
dialog.addaltitude.desc=Hinzuzurechnende H\u00f6henverschiebung
dialog.lookupsrtm.overwritezeros=H\u00f6henangaben von null \u00fcberschreiben?
-dialog.setcolours.intro=Klicken Sie auf eine Farbe um sie zu \u00e4ndern
+dialog.setcolours.intro=Klicken Sie auf eine Farbe, um sie zu \u00e4ndern
dialog.setcolours.background=Hintergrund
dialog.setcolours.borders=Umrandungen
dialog.setcolours.lines=Linien
dialog.setcolours.primary=Prim\u00e4r
-dialog.setcolours.secondary=Second\u00e4r
+dialog.setcolours.secondary=Sekund\u00e4r
dialog.setcolours.point=Punkte
dialog.setcolours.selection=Bereich
dialog.setcolours.text=Texte
dialog.colourchooser.green=Gr\u00fcn
dialog.colourchooser.blue=Blau
dialog.setlanguage.firstintro=Sie k\u00f6nnen entweder eine von den mitgelieferten Sprachen<p>oder eine Text-Datei ausw\u00e4hlen.
-dialog.setlanguage.secondintro=Sie m\u00fcssen Ihre Einstellungen speichern und dann<p>GpsPrune neu starten um die Sprache zu \u00e4ndern.
+dialog.setlanguage.secondintro=Sie m\u00fcssen Ihre Einstellungen speichern und dann<p>GpsPrune neu starten, um die Sprache zu \u00e4ndern.
dialog.setlanguage.language=Sprache
dialog.setlanguage.languagefile=Sprachdatei
-dialog.setlanguage.endmessage=Speichern Sie nun Ihre Einstellungen und starten Sie GpsPrune neu\num die neue Sprache zu verwenden.
-dialog.setlanguage.endmessagewithautosave=Starten Sie GpsPrune neu um die neue Sprache zu verwenden.
+dialog.setlanguage.endmessage=Speichern Sie nun Ihre Einstellungen und starten Sie GpsPrune neu,\num die neue Sprache zu verwenden.
+dialog.setlanguage.endmessagewithautosave=Starten Sie GpsPrune neu, um die neue Sprache zu verwenden.
dialog.diskcache.save=Karten auf Festplatte speichern
dialog.diskcache.dir=Kartenordner
dialog.diskcache.createdir=Ordner anlegen
dialog.diskcache.nocreate=Ordner wurde nicht angelegt
+dialog.diskcache.cannotwrite=Kacheln k\u00f6nnen nicht im Ordner gespeichert werden
dialog.diskcache.table.path=Pfad
dialog.diskcache.table.usedby=Anwender
dialog.diskcache.table.zoom=Zoom
dialog.diskcache.deleteall=Alle Kacheln l\u00f6schen
dialog.diskcache.deleted1=Es wurden
dialog.diskcache.deleted2=Dateien aus dem Ordner gel\u00f6scht
-dialog.deletefieldvalues.intro=W\u00e4hlen Sie das Feld aus, die Sie l\u00f6schen m\u00f6chten
+dialog.deletefieldvalues.intro=W\u00e4hlen Sie das Feld aus, das Sie l\u00f6schen m\u00f6chten
+dialog.deletefieldvalues.nofields=Es sind keine Felder zu l\u00f6schen f\u00fcr diesen Bereich
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.downloadosm.desc=Die OpenStreetMap-Daten f\u00fcr das folgende Gebiet werden heruntergeladen (.osm-Datei):
dialog.searchwikipedianames.search=Suche nach:
# 3d window
-dialog.3d.title=GpsPrune 3D Ansicht
+dialog.3d.title=GpsPrune-3D-Ansicht
dialog.3d.altitudefactor=Vervielfachungsfaktor f\u00fcr H\u00f6hen
-dialog.3dlines.title=GpsPrune Gitterlinien
+dialog.3dlines.title=GpsPrune-Gitterlinien
dialog.3dlines.empty=Keine Linien zum Anzeigen!
dialog.3dlines.intro=Hier sind die Linien f\u00fcr die 3D Ansicht
confirm.reverserange=Bereich umgekehrt
confirm.addtimeoffset=Zeitverschiebung aufgerechnet
confirm.addaltitudeoffset=H\u00f6henverschiebung aufgerechnet
-confirm.rearrangewaypoints=Wegpunkte reorganisiert
-confirm.rearrangephotos=Fotos reorganisiert
+confirm.rearrangewaypoints=Wegpunkte neu angeordnet
+confirm.rearrangephotos=Fotos neu angeordnet
confirm.cutandmove=Bereich verschoben
+confirm.interpolate=Punkte eingef\u00fcgt
confirm.convertnamestotimes=Wegpunktnamen umgewandelt
confirm.saveexif.ok1=Es wurden
confirm.saveexif.ok2=Fotodateien geschrieben
# Buttons
button.ok=OK
button.back=Zur\u00fcck
-button.next=Vorw\u00e4rts
+button.next=Weiter
button.finish=Fertig
button.cancel=Abbrechen
button.overwrite=\u00dcberschreiben
button.manage=Verwalten
# File types
-filetype.txt=TXT Dateien
-filetype.jpeg=JPG Dateien
-filetype.kmlkmz=KML, KMZ Dateien
-filetype.kml=KML Dateien
-filetype.kmz=KMZ Dateien
-filetype.gpx=GPX Dateien
-filetype.pov=POV Dateien
-filetype.svg=SVG Dateien
-filetype.audio=MP3, OGG, WAV Dateien
+filetype.txt=TXT-Dateien
+filetype.jpeg=JPG-Dateien
+filetype.kmlkmz=KML-, KMZ-Dateien
+filetype.kml=KML-Dateien
+filetype.kmz=KMZ-Dateien
+filetype.gpx=GPX-Dateien
+filetype.pov=POV-Dateien
+filetype.svg=SVG-Dateien
+filetype.audio=MP3-, OGG-, WAV-Dateien
# Display components
display.nodata=Keine Daten geladen
details.pointdetails=Details des Punkts
details.index.selected=Index
details.index.of=von
-details.nopointselection=Nichts selektiert
+details.nopointselection=Nichts ausgew\u00e4hlt
details.photofile=Fotodatei
details.norangeselection=Kein Bereich ausgew\u00e4hlt
details.rangedetails=Details der Auswahl
display.range.time.hours=h
display.range.time.days=T
details.range.avespeed=Durchschnittsgeschwindigkeit
-details.range.avemovingspeed=Durchschnittsgeschwindigkeit gleitend
details.range.maxspeed=H\u00f6chstgeschwindigkeit
details.range.numsegments=Anzahl Abschnitte
details.range.pace=Tempo
details.lists.waypoints=Wegpunkte
details.lists.photos=Fotos
details.lists.audio=Audio
-details.photodetails=Fotodetails
+details.photodetails=Details des Fotos
details.nophoto=Kein Foto ausgew\u00e4hlt
details.photo.loading=Laden
details.photo.bearing=Richtung
details.media.connected=Verbunden
+details.media.fullpath=Ganzer Pfad
details.audiodetails=Audiodetails
details.noaudio=Keine Audiodatei ausgew\u00e4hlt
details.audio.file=Audiodatei
units.original=Original
units.default=Standard
units.metres=Meter
+units.metres.short=m
units.kilometres=Kilometer
units.kilometres.short=km
-units.kmh=km/h
-units.metrespersec=m/s
-units.feetpersec=ft/s
+units.kilometresperhour.short=km/h
+units.nauticalmiles=Seemeilen
+units.nauticalmiles.short=sm
+units.nauticalmilesperhour.short=kn
+units.metrespersec.short=m/s
+units.feetpersec.short=ft/s
units.hours=Std
units.degminsec=Grad-Min-Sek
units.degmin=Grad-Min
undo.removephoto=Foto entfernen
undo.removeaudio=Audiodatei entfernen
undo.deleterange=Bereich l\u00f6schen
-undo.compress=Track komprimieren
+undo.croptrack=Track zuschneiden
+undo.deletemarked=Punkte l\u00f6schen
undo.insert=Punkte hinzuf\u00fcgen
undo.reverse=Bereich umdrehen
undo.mergetracksegments=Trackabschnitte verbinden
undo.addtimeoffset=Zeitverschiebung aufrechnen
undo.addaltitudeoffset=H\u00f6henverschiebung aufrechnen
-undo.rearrangewaypoints=Wegpunkte reorganisieren
+undo.rearrangewaypoints=Wegpunkte neu anordnen
undo.cutandmove=Bereich verschieben
undo.connect=verbinden
undo.disconnect=trennen
undo.correlatephotos=Fotos korrelieren
-undo.rearrangephotos=Fotos reorganisieren
+undo.rearrangephotos=Fotos neu anordnen
undo.createpoint=Punkt erzeugen
undo.rotatephoto=Foto umdrehen
undo.convertnamestotimes=Namen in Zeitstempel umwandeln
error.save.dialogtitle=Fehler beim Speichern
error.save.nodata=Keine Daten zum Speichern vorhanden
error.save.failed=Speichern von Daten in Datei fehlgeschlagen
-error.saveexif.filenotfound=Foto Datei nicht gefunden
-error.saveexif.cannotoverwrite1=Foto Datei
+error.saveexif.filenotfound=Bilddatei nicht gefunden
+error.saveexif.cannotoverwrite1=Bilddatei
error.saveexif.cannotoverwrite2=ist schreibgesch\u00fctzt. Als Kopie speichern?
error.saveexif.failed1=
error.saveexif.failed2=Bilder konnten nicht gespeichert werden
error.load.dialogtitle=Fehler beim Laden
error.load.noread=Datei konnte nicht gelesen werden
error.load.nopoints=Keine g\u00fcltigen Daten in Datei gefunden
-error.load.unknownxml=Unbekanntes xml Format:
-error.load.noxmlinzip=Keine xml Datei in Zip Datei gefunden
+error.load.unknownxml=Unbekanntes XML-Format:
+error.load.noxmlinzip=Keine XML-Datei in Zip-Datei gefunden
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.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.jpegload.nojpegsfound=Keine JPG-Dateien gefunden
+error.jpegload.nogpsfound=Keine GPS-Information gefunden
+error.jpegload.exifreadfailed=Exif-Aufruf fehlgeschlagen. Exif-Information k\u00f6nnen nicht gelesen werden\nwenn nicht eine interne oder externe Bibliothek vorhanden ist.
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
error.function.noop.title=Funktion hat nichts bewirkt
-error.rearrange.noop=Die Punkte zu reorganisieren hatte keinen Effekt
+error.rearrange.noop=Die Neuanordnung der Punkte hatte keinen Effekt
error.function.notavailable.title=Funktion nicht verf\u00fcgbar
-error.function.nojava3d=Diese Funktion ben\u00f6tigt die Java3d Library,\nvon Sun.com erh\u00e4ltlich.
+error.function.nojava3d=Diese Funktion ben\u00f6tigt die Java3d-Library,\ndie bei Sun.com erh\u00e4ltlich ist.
error.3d=Ein Fehler ist bei der 3D Darstellung aufgetreten
-error.readme.notfound=Liesmich Datei nicht gefunden
+error.readme.notfound=Liesmich-Datei nicht gefunden
error.osmimage.dialogtitle=Laden von Karten-Bildern fehlgeschlagen
error.osmimage.failed=Laden von Karten-Bildern fehlgeschlagen. Bitte pr\u00fcfen Sie die Internetverbindung.
error.language.wrongfile=Die ausgew\u00e4hlte Datei scheint keine Sprachdatei f\u00fcr GpsPrune zu sein
error.lookupsrtm.nonerequired=Alle Punkte haben schon H\u00f6hendaten
error.gpsies.uploadnotok=Der Gpsies Server hat geantwortet
error.gpsies.uploadfailed=Das Hochladen ist fehlgeschlagen
+error.showphoto.failed=Das Foto konnte nicht geladen werden
error.playaudiofailed=Das Abspielen der Audiodatei ist fehlgeschlagen
error.cache.notthere=Der Ordner wurde nicht gefunden
error.cache.empty=Der Ordner ist leer
error.cache.cannotdelete=Es konnte keine Kacheln gel\u00f6scht werden
+error.interpolate.invalidparameter=Die Anzahl der Punkte muss zwischen 1 und 1000 liegen
# Menu entries
menu.file=File
-menu.file.addphotos=Fötelis innätue
+menu.file.addphotos=F\u00f6telis inn\u00e4tue
menu.file.recentfiles=Letzschti aagluegte Files
menu.file.save=Als Text Speichere
-menu.file.exit=Beände
+menu.file.exit=Be\u00e4nde
menu.track=Track
menu.track.undo=Undo
-menu.track.clearundo=Undo-Liste lösche
-menu.track.deletemarked=Komprimierte Punkte lösche
+menu.track.clearundo=Undo-Liste l\u00f6sche
+menu.track.markrectangle=P\u00fcnkte inem Viereck markiere
+menu.track.deletemarked=Markierte P\u00fcnkte l\u00f6sche
menu.track.rearrange=Waypoints reorganisiere
menu.track.rearrange.start=Alli zum Aafang
menu.track.rearrange.end=Alli zum Ände
-menu.track.rearrange.nearest=Jede zum nöchsti Trackpunkt
+menu.track.rearrange.nearest=Jede zum n\u00f6chsti Trackpunkt
menu.range=Beriich
menu.range.all=Alles selektiere
-menu.range.none=Nüüt selektiere
-menu.range.start=Start setzä
-menu.range.end=Stopp setzä
-menu.range.deleterange=Beriich lösche
-menu.range.interpolate=Interpoliere
-menu.range.average=Durchschnitt uusrächne
-menu.range.reverse=Beriich umdrähie
-menu.range.mergetracksegments=Track Segmänte merge
+menu.range.none=N\u00fc\u00fct selektiere
+menu.range.start=Start setz\u00e4
+menu.range.end=Stopp setz\u00e4
+function.interpolate=P\u00fcnkte interpoliere
+menu.range.average=Durchschnitt uusr\u00e4chne
+menu.range.reverse=Beriich umdr\u00e4hie
+menu.range.mergetracksegments=Track Segm\u00e4nte merge
menu.range.cutandmove=Schniide und move
menu.point=Punkt
menu.point.editpoint=Punkt editiere
-menu.point.deletepoint=Punkt lösche
-menu.photo=Föteli
-menu.photo.saveexif=Exif Date speicherä
-function.connecttopoint=Mitem Punkt verbindä
-function.disconnectfrompoint=Vonem Punkt trännä
-function.removephoto=Föteli entfernä
+menu.point.deletepoint=Punkt l\u00f6sche
+menu.photo=F\u00f6teli
+menu.photo.saveexif=Exif Date speicher\u00e4
+function.connecttopoint=Mitem Punkt verbind\u00e4
+function.disconnectfrompoint=Vonem Punkt tr\u00e4nn\u00e4
+function.removephoto=F\u00f6teli entfern\u00e4
menu.audio=Audio
menu.view=Aasicht
menu.view.showsidebars=Seiteleischten aazeige
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.drawpoints=Noii P\u00fcnktli uufzeichn\u00e4
+menu.map.connect=Trackp\u00fcnktli verbind\u00e4
menu.map.autopan=Autopan
-menu.map.showmap=Karte zeigä
+menu.map.showmap=Karte zeig\u00e4
menu.map.showscalebar=Massstab aazeige
+menu.map.editmode=P\u00fcnkte verschiebe
# Alt keys for menus
altkey.menu.file=F
altkey.menu.range=B
altkey.menu.point=P
altkey.menu.view=A
-altkey.menu.photo=F
+altkey.menu.photo=L
altkey.menu.audio=U
altkey.menu.settings=I
altkey.menu.help=H
shortcut.menu.help.help=H
# Functions
-function.open=File öffne
+function.open=File \u00f6ffne
function.importwithgpsbabel=mit GPSBabel importiere
function.loadfromgps=uusem GPS lade
function.sendtogps=zum GPS schicke
-function.exportkml=KML exportierä
-function.exportgpx=GPX exportierä
-function.exportpov=POV exportierä
-function.exportsvg=SVG exportierä
+function.exportkml=KML exportier\u00e4
+function.exportgpx=GPX exportier\u00e4
+function.exportpov=POV exportier\u00e4
+function.exportsvg=SVG exportier\u00e4
function.editwaypointname=Waypoint Name editiere
-function.compress=Track komprimierä
+function.compress=Track komprimier\u00e4
+function.deleterange=Beriich l\u00f6sche
+function.croptrack=Track zuschniide
function.addtimeoffset=Ziitverschiebig zutue
-function.addaltitudeoffset=Höchiverschiebig zutue
-function.findwaypoint=Waypoint suechä
-function.convertnamestotimes=Waypointname ins Ziitstämple verwondle
-function.deletefieldvalues=Werte von nem Fäld lösche
+function.addaltitudeoffset=H\u00f6chiverschiebig zutue
+function.findwaypoint=Waypoint suech\u00e4
+function.convertnamestotimes=Waypointname ins Ziitst\u00e4mple verwondle
+function.deletefieldvalues=Werte von nem F\u00e4ld l\u00f6sche
function.pastecoordinates=Noii Koordinaten iigebe
function.charts=Diagramme
-function.show3d=Drüü-D Aasicht
-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.show3d=Dr\u00fc\u00fc-D Aasicht
+function.distances=Entf\u00e4rnige
+function.fullrangedetails=Zues\u00e4tzlichi Beriichinfos
+function.setmapbg=Karte Hintegrund setz\u00e4
+function.getgpsies=Gpsies Tracks hol\u00e4
+function.uploadgpsies=Date zum Gpsies uufalad\u00e4
+function.lookupsrtm=H\u00f6hendate vonem SRTM hole
+function.getwikipedia=Im Wikipedia in dr N\u00f6chi 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.downloadosm=OSM-Date f\u00fcr dere Gebiet abalad\u00e4
+function.duplicatepoint=Punkt verdoppl\u00e4
+function.correlatephotos=F\u00f6telis korrelier\u00e4
+function.rearrangephotos=F\u00f6telis reorganisier\u00e4
+function.rotatephotoleft=F\u00f6teli nach Links dr\u00e4y\u00e4
+function.rotatephotoright=F\u00f6teli nach R\u00e4chts dr\u00e4y\u00e4
+function.photopopup=F\u00f6telif\u00e4nschter aazeig\u00e4
+function.ignoreexifthumb=Exif Vorschaubildli ignorier\u00e4
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.removeaudio=Audiodatei entfern\u00e4
+function.correlateaudios=Audios korrelier\u00e4
+function.playaudio=Audiofile abspiel\u00e4
+function.stopaudio=Abspielen abbr\u00e4ch\u00e4
+function.setkmzimagesize=Bildligr\u00f6sse inem KMZ setz\u00e4
+function.setpaths=Programmepfade setz\u00e4
+function.setcolours=Farben setz\u00e4
+function.setlinewidth=Liniedicke setz\u00e4
+function.setlanguage=Sproch setz\u00e4
function.help=Hilfe
function.showkeys=Tastekombinatione aazeige
function.about=Ãœber GpsPrune
function.managetilecache=Kartebildli verwolte
# Dialogs
-dialog.exit.confirm.title=GpsPrune beände
-dialog.exit.confirm.text=Ihri Date sind nonig gspeicheret worde. Wend Sie trotzdem s Programm beände?
-dialog.openappend.title=Date aahänge oder ersätze
-dialog.openappend.text=Häng diese Date zur aktuelli Daten aa?
-dialog.deletepoint.title=Punkt löschä
-dialog.deletepoint.deletephoto=s Föteli vonem Punkt au löschä?
-dialog.deletephoto.title=Föteli entfernä
-dialog.deletephoto.deletepoint=Punkt vonem Föteli au löschä?
+dialog.exit.confirm.title=GpsPrune be\u00e4nde
+dialog.exit.confirm.text=Ihri Date sind nonig gspeicheret worde. Wend Sie trotzdem s Programm be\u00e4nde?
+dialog.openappend.title=Date aah\u00e4nge oder ers\u00e4tze
+dialog.openappend.text=H\u00e4ng diese Date zur aktuelli Daten aa?
+dialog.deletepoint.title=Punkt l\u00f6sch\u00e4
+dialog.deletepoint.deletephoto=s F\u00f6teli vonem Punkt au l\u00f6sch\u00e4?
+dialog.deletephoto.title=F\u00f6teli entfern\u00e4
+dialog.deletephoto.deletepoint=Punkt vonem F\u00f6teli au l\u00f6sch\u00e4?
+dialog.deleteaudio.deletepoint=Punkt vonem Audio au l\u00f6sch\u00e4?
dialog.openoptions.title=Öffne Optionen
dialog.openoptions.filesnippet=Extrakt vom File
-dialog.load.table.field=Fäld
+dialog.load.table.field=F\u00e4ld
dialog.load.table.datatype=Date Typ
dialog.load.table.description=Beschriibig
-dialog.delimiter.label=Fäld Trennzeiche
+dialog.delimiter.label=F\u00e4ld Trennzeiche
dialog.delimiter.comma=Komma ,
dialog.delimiter.tab=Tab
dialog.delimiter.space=Abstand
dialog.delimiter.semicolon=Strichpunkt ;
dialog.delimiter.other=Andere
dialog.openoptions.deliminfo.records=Rekords, mit
-dialog.openoptions.deliminfo.fields=Fäldere
+dialog.openoptions.deliminfo.fields=F\u00e4ldere
dialog.openoptions.deliminfo.norecords=Kei Rekords
-dialog.openoptions.altitudeunits=Höchi Masseiheite
-dialog.open.contentsdoubled=Dieses File hät zwei Kopien von jädem Punkt,\neimol als Waypoint und eimol als Trackpunkt.
-dialog.selecttracks.intro=Wählet Sie die Tracks uus zum ladä
+dialog.openoptions.altitudeunits=H\u00f6chi Masseiheite
+dialog.open.contentsdoubled=Dieses File h\u00e4t zwei Kopien von j\u00e4dem Punkt,\neimol als Waypoint und eimol als Trackpunkt.
+dialog.selecttracks.intro=W\u00e4hlet Sie die Tracks uus zum lad\u00e4
dialog.selecttracks.noname=Unbenannt
dialog.jpegload.subdirectories=Subordnern au
-dialog.jpegload.loadjpegswithoutcoords=Au Fötelis ohni Koordinate
-dialog.jpegload.loadjpegsoutsidearea=Au Fötelis uuserhalb vonem Track
-dialog.jpegload.progress.title=Fötelis lade
-dialog.jpegload.progress=Bitte warte während die Fötelis durägsucht werde
+dialog.jpegload.loadjpegswithoutcoords=Au F\u00f6telis ohni Koordinate
+dialog.jpegload.loadjpegsoutsidearea=Au F\u00f6telis uuserhalb vonem Track
+dialog.jpegload.progress.title=F\u00f6telis lade
+dialog.jpegload.progress=Bitte warte w\u00e4hrend die F\u00f6telis dur\u00e4gsucht werde
dialog.gpsload.nogpsbabel=Kei gpsbabel Programm gfunde. Wiiter?
dialog.gpsload.device=Device Name
dialog.gpsload.format=Format
dialog.gpsload.getwaypoints=Waypoints lade
dialog.gpsload.gettracks=Tracks lade
-dialog.gpsload.save=nach nem File speicherä
+dialog.gpsload.save=nach nem File speicher\u00e4
dialog.gpssend.sendwaypoints=Waypoints schicke
dialog.gpssend.sendtracks=Tracks schicke
dialog.gpssend.trackname=Track Name
-dialog.saveoptions.title=File speicherä
-dialog.save.fieldstosave=Fälder zu speicherä
-dialog.save.table.field=Fäld
+dialog.saveoptions.title=File speicher\u00e4
+dialog.save.fieldstosave=F\u00e4lder zu speicher\u00e4
+dialog.save.table.field=F\u00e4ld
dialog.save.table.hasdata=Het Date
-dialog.save.table.save=Speicherä
-dialog.save.headerrow=Titel Ziile speicherä
+dialog.save.table.save=Speicher\u00e4
+dialog.save.headerrow=Titel Ziile speicher\u00e4
dialog.save.coordinateunits=Koordinate Massiiheite
-dialog.save.altitudeunits=Höchi Massiiheite
-dialog.save.timestampformat=Ziitstämpelformat
+dialog.save.altitudeunits=H\u00f6chi Massiiheite
+dialog.save.timestampformat=Ziitst\u00e4mpelformat
dialog.save.overwrite.title=s'File existiert scho
-dialog.save.overwrite.text=s'File existiert scho. Sind Sie sicher, Sie wend s'File überschriibe?
-dialog.save.notypesselected=Kei Punktetype sin uusgewählt worde
-dialog.exportkml.text=Titel für die Date
-dialog.exportkml.altitude=Absolut Höchiinformation (fürs Fliege)
-dialog.exportkml.kmz=Date ins kmz File komprimierä
-dialog.exportkml.exportimages=Bildli ins Kmz exportierä
+dialog.save.overwrite.text=s'File existiert scho. Sind Sie sicher, Sie wend s'File \u00fcberschriibe?
+dialog.save.notypesselected=Kei Punktetype sin uusgew\u00e4hlt worde
+dialog.exportkml.text=Titel f\u00fcr die Date
+dialog.exportkml.altitude=Absolut H\u00f6chiinformation (f\u00fcrs Fliege)
+dialog.exportkml.kmz=Date ins kmz File komprimier\u00e4
+dialog.exportkml.exportimages=Bildli ins Kmz exportier\u00e4
dialog.exportkml.trackcolour=Trackfarb
dialog.exportgpx.name=Name
dialog.exportgpx.desc=Beschriibig
-dialog.exportgpx.includetimestamps=Au Ziitstämpel
-dialog.exportgpx.copysource=Xml-Quälle kopierä
+dialog.exportgpx.includetimestamps=Au Ziitst\u00e4mpel
+dialog.exportgpx.copysource=Xml-Qu\u00e4lle kopier\u00e4
dialog.exportgpx.encoding=Enkodierig
dialog.exportgpx.encoding.system=System
dialog.exportgpx.encoding.utf8=UTF-8
-dialog.exportpov.text=Gäbet Sie die Parameter ii fürs POV Export
+dialog.exportpov.text=G\u00e4bet Sie die Parameter ii f\u00fcrs POV Export
dialog.exportpov.font=Font
dialog.exportpov.camerax=Kamera X
dialog.exportpov.cameray=Kamera Y
dialog.exportpov.cameraz=Kamera Z
dialog.exportpov.modelstyle=Modellstil
-dialog.exportpov.ballsandsticks=Bälle und Schtange
-dialog.exportpov.tubesandwalls=Röhre und Wände
-dialog.exportpov.warningtracksize=Dieser Track hät mega viele Punkte, die Java3D villiicht nöd chann bearbeite.\nSind Sie sicher, Sie wend trotzdem fortsetze?
-dialog.exportsvg.text=Wählet Sie die Parameter fürs SVG Export uus
+dialog.exportpov.ballsandsticks=B\u00e4lle und Schtange
+dialog.exportpov.tubesandwalls=R\u00f6hre und W\u00e4nde
+dialog.exportpov.warningtracksize=Dieser Track h\u00e4t mega viele P\u00fcnkte, die Java3D villiicht n\u00f6d chann bearbeite.\nSind Sie sicher, Sie wend trotzdem fortsetze?
+dialog.exportsvg.text=W\u00e4hlet Sie die Parameter f\u00fcrs SVG Export uus
dialog.exportsvg.phi=Richtigswinkel \u03D5
dialog.exportsvg.theta=Neigigswinkel \u03B8
-dialog.exportsvg.gradients=Farbeverläufe verwände
+dialog.exportsvg.gradients=Farbeverl\u00e4ufe verw\u00e4nde
dialog.pointtype.desc=Folgende Punkttype speichere:
-dialog.pointtype.track=Trackpunkte
+dialog.pointtype.track=Trackp\u00fcnkte
dialog.pointtype.waypoint=Waypoints
-dialog.pointtype.photo=Fötelipunkte
-dialog.pointtype.audio=Audiopunkte
+dialog.pointtype.photo=F\u00f6telip\u00fcnkte
+dialog.pointtype.audio=Audiop\u00fcnkte
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?
-dialog.confirmcutandmove.title=Move bestätige
-dialog.confirmcutandmove.text=Diese Daten enthalte Ziitstämpel Informatione, die bei dr Move usser Reihefolge erschiene würdi.\nSind Sie sicher, Sie wend dn Beriich move?
-dialog.interpolate.title=Punkte interpoliere
-dialog.interpolate.parameter.text=Aazahl Punkte zum innätue zwüschet den selektierten Punkten
+dialog.confirmreversetrack.title=Umdrehig best\u00e4tige
+dialog.confirmreversetrack.text=Diese Daten enthalte Ziitst\u00e4mpel Informatione, die bei dr Umkehrig usser Reihefolge erschiene w\u00fcrdi.\nSind Sie sicher, Sie wend dn Beriich umkehre?
+dialog.confirmcutandmove.title=Move best\u00e4tige
+dialog.confirmcutandmove.text=Diese Daten enthalte Ziitst\u00e4mpel Informatione, die bei dr Move usser Reihefolge erschiene w\u00fcrdi.\nSind Sie sicher, Sie wend dn Beriich move?
+dialog.interpolate.parameter.text=Aazahl P\u00fcnkte zum inn\u00e4tue zw\u00fcschet den selektierten P\u00fcnkten
+dialog.interpolate.betweenwaypoints=Zw\u00fcschet d Waypoints interpoliere?
dialog.undo.title=Undo Operation(e)
-dialog.undo.pretext=Selektiere die Operatione die rückgängig gmacht söllti werde.
-dialog.undo.none.title=Undo nöd möglich
-dialog.undo.none.text=Keini Operatione könne rückgängig gmacht werde.
-dialog.clearundo.title=Undo-Liste löschä
-dialog.clearundo.text=Sind Sie sicher, Sie wend die Undo-Liste lösche?\nAlle Undo Infos werdet verlore gah!
-dialog.pointedit.title=Punkt editierä
-dialog.pointedit.text=Wählet Sie jäden Fäld uus zu editiere, und mitem 'Editierä' Chnopf den Wert ändere
-dialog.pointedit.table.field=Fäld
+dialog.undo.pretext=Selektiere die Operatione die r\u00fcckg\u00e4ngig gmacht s\u00f6llti werde.
+dialog.undo.none.title=Undo n\u00f6d m\u00f6glich
+dialog.undo.none.text=Keini Operatione k\u00f6nne r\u00fcckg\u00e4ngig gmacht werde.
+dialog.clearundo.title=Undo-Liste l\u00f6sch\u00e4
+dialog.clearundo.text=Sind Sie sicher, Sie wend die Undo-Liste l\u00f6sche?\nAlle Undo Infos werdet verlore gah!
+dialog.pointedit.title=Punkt editier\u00e4
+dialog.pointedit.text=W\u00e4hlet Sie j\u00e4den F\u00e4ld uus zu editiere, und mitem 'Editier\u00e4' Chnopf den Wert \u00e4ndere
+dialog.pointedit.table.field=F\u00e4ld
dialog.pointedit.table.value=Wert
-dialog.pointedit.table.changed=Geändert
-dialog.pointedit.changevalue.text=Gebet Sie den neuen Wert für diesen Fäld ina
-dialog.pointedit.changevalue.title=Fäld editiere
+dialog.pointedit.table.changed=Ge\u00e4ndert
+dialog.pointedit.changevalue.text=Gebet Sie den neuen Wert f\u00fcr diesen F\u00e4ld ina
+dialog.pointedit.changevalue.title=F\u00e4ld editiere
dialog.pointnameedit.name=Waypoint Name
dialog.pointnameedit.uppercase=GROSS gschriebe
dialog.pointnameedit.lowercase=chli gschriebe
-dialog.pointnameedit.sentencecase=Gmischt Gschriebe
+dialog.pointnameedit.titlecase=Gmischt Gschriebe
dialog.addtimeoffset.add=Ziit zutue
dialog.addtimeoffset.subtract=Ziit davo neh
dialog.addtimeoffset.days=Tage
dialog.addtimeoffset.hours=Schtunde
dialog.addtimeoffset.minutes=Minute
-dialog.addtimeoffset.notimestamps=Ziitverschiebig nöd möglech wil dr Beriich kei Ziitinfo hät
+dialog.addtimeoffset.notimestamps=Ziitverschiebig n\u00f6d m\u00f6glech wil dr Beriich kei Ziitinfo h\u00e4t
dialog.findwaypoint.intro=Gebet Sie en Teil vonem Namen ina
dialog.findwaypoint.search=Sueche
-dialog.saveexif.title=Exif go speicherä
-dialog.saveexif.intro=Wählet Sie die Fötelis uus zum speicherä
-dialog.saveexif.nothingtosave=Koordinaten sin nöd geänderet, nüüt zum speicherä
+dialog.saveexif.title=Exif go speicher\u00e4
+dialog.saveexif.intro=W\u00e4hlet Sie die F\u00f6telis uus zum speicher\u00e4
+dialog.saveexif.nothingtosave=Koordinaten sin n\u00f6d ge\u00e4nderet, n\u00fc\u00fct zum speicher\u00e4
dialog.saveexif.noexiftool=Kei exiftool Programm gfunde. Wiiter?
-dialog.saveexif.table.photoname=Föteli Name
+dialog.saveexif.table.photoname=F\u00f6teli Name
dialog.saveexif.table.status=Status
-dialog.saveexif.table.save=Speicherä
-dialog.saveexif.photostatus.connected=Verbundä
-dialog.saveexif.photostatus.disconnected=Gtrännt
-dialog.saveexif.photostatus.modified=Gänderet
-dialog.saveexif.overwrite=Files überschriebä
-dialog.saveexif.force=Forzierä trotz Warnige
+dialog.saveexif.table.save=Speicher\u00e4
+dialog.saveexif.photostatus.connected=Verbund\u00e4
+dialog.saveexif.photostatus.disconnected=Gtr\u00e4nnt
+dialog.saveexif.photostatus.modified=G\u00e4nderet
+dialog.saveexif.overwrite=Files \u00fcberschrieb\u00e4
+dialog.saveexif.force=Forzier\u00e4 trotz Warnige
dialog.charts.xaxis=X Achse
dialog.charts.yaxis=Y Achse
dialog.charts.output=Uusgabe
dialog.charts.screen=Bildschirm
dialog.charts.svg=SVG File
dialog.charts.svgwidth=SVG Breiti
-dialog.charts.svgheight=SVG Höhi
-dialog.charts.needaltitudeortimes=Ohni Höhi Date und au ohne Ziit, isch es nöd möglech, Diagramme z zeigä.
-dialog.charts.gnuplotnotfound=Gnuplot isch mit dem Pfad nöd gfunde worde
-dialog.distances.intro=Entfärnige per Luftlinie zwüschet Punkte
+dialog.charts.svgheight=SVG H\u00f6hi
+dialog.charts.needaltitudeortimes=Ohni H\u00f6hi Date und au ohne Ziit, isch es n\u00f6d m\u00f6glech, Diagramme z zeig\u00e4.
+dialog.charts.gnuplotnotfound=Gnuplot isch mit dem Pfad n\u00f6d gfunde worde
+dialog.distances.intro=Entf\u00e4rnige per Luftlinie zw\u00fcschet P\u00fcnkte
dialog.distances.column.from=Vom Punkt
dialog.distances.column.to=Zum Punkt
dialog.distances.currentpoint=Aktuelli Punkt
-dialog.distances.toofewpoints=d'Funktion bruucht Waypoints um die Dischtanze z berächne
+dialog.distances.toofewpoints=d'Funktion bruucht Waypoints um die Dischtanze z ber\u00e4chne
dialog.fullrangedetails.intro=Hier sind die Infos vonem aktuelli Beriich
-dialog.setmapbg.intro=Eini von den Quällen uuswähle, oder eini neui hinzuefüge
-dialog.addmapsource.title=Neui Kartequälle hinzuefüge
+dialog.fullrangedetails.coltotal=Inklusiv L\u00fccke
+dialog.fullrangedetails.colsegments=Ohni L\u00fccke
+dialog.setmapbg.intro=Eini von den Qu\u00e4llen uusw\u00e4hle, oder eini neui hinzuef\u00fcge
+dialog.addmapsource.title=Neui Kartequ\u00e4lle hinzuef\u00fcge
dialog.addmapsource.sourcename=Sourcename
-dialog.addmapsource.layer1url=URL für erschti Ebene
-dialog.addmapsource.layer2url=URL für oberi Ebene (falls nötig)
+dialog.addmapsource.layer1url=URL f\u00fcr erschti Ebene
+dialog.addmapsource.layer2url=URL f\u00fcr oberi Ebene (falls n\u00f6tig)
dialog.addmapsource.maxzoom=Maximali Zoom
dialog.addmapsource.cloudstyle=Stilnummere
dialog.addmapsource.noname=Unbenannt
dialog.gpsies.column.name=Track Name
-dialog.gpsies.column.length=Länge
+dialog.gpsies.column.length=L\u00e4nge
dialog.gpsies.description=Beschriebig
dialog.gpsies.nodescription=Kei Beschriebig
dialog.gpsies.nonefound=Kei Tracks gfunde
dialog.gpsies.username=Gpsies Username
dialog.gpsies.password=Gpsies Passwort
dialog.gpsies.keepprivate=Track privat halte
-dialog.gpsies.confirmopenpage=Websiite fürn uufageladenen Track öffne?
+dialog.gpsies.confirmopenpage=Websiite f\u00fcrn uufageladenen Track \u00f6ffne?
dialog.gpsies.activities=Aktivit\u00e4ten
dialog.gpsies.activity.trekking=Wandere
dialog.gpsies.activity.walking=Z'Fuess gah
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.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.wikipedia.column.distance=Entf\u00e4rnig
+dialog.correlate.notimestamps=Es h\u00e4t kei Ziitst\u00e4mpel inem Track inn\u00e4, so s'isch n\u00f6d m\u00f6glech die F\u00f6telis zu korrelier\u00e4.
+dialog.correlate.nouncorrelatedphotos=Alle F\u00f6telis sin scho korreliert.\nWend Sie trotzdem fortsetz\u00e4?
+dialog.correlate.nouncorrelatedaudios=Alle Audios sin scho korreliert.\nWend Sie trotzdem fortsetz\u00e4?
+dialog.correlate.photoselect.intro=W\u00e4hlet Sie eini vo deren F\u00f6teli uus, um die Ziitdiffer\u00e4nz zu ber\u00e4chn\u00e4
+dialog.correlate.select.photoname=F\u00f6teli Name
+dialog.correlate.select.timediff=Ziitdiffer\u00e4nz
+dialog.correlate.select.photolater=F\u00f6teli sp\u00f6ter
+dialog.correlate.options.tip=Tipp: Mit mindeschtens einem verbundenen Elem\u00e4nt kann die Ziitdiffer\u00e4nz automatisch ber\u00e4chnet werd\u00e4.
+dialog.correlate.options.intro=W\u00e4hlet Sie die Optione uus f\u00fcr die Korrelierig
dialog.correlate.options.offsetpanel=Ziitunterschied
dialog.correlate.options.offset=Unterschied
-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.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ä
-dialog.correlate.options.nodistancelimit=Kei Distanzgränzä
-dialog.correlate.options.distancelimit=Distanzgränzä
-dialog.correlate.options.correlate=Korrelierä
-dialog.correlate.alloutsiderange=Alli Fötelis sin uusserhalb vonem Track Ziitruum, so chönne nöd korreliert werdä.\nVersuechet Sie mitenem anderen Offset oder verbindet Sie manuell mindeschtens eis Föteli.
+dialog.correlate.options.offset.hours=Schtund\u00e4,
+dialog.correlate.options.offset.minutes=Minut\u00e4 und
+dialog.correlate.options.offset.seconds=Sekund\u00e4
+dialog.correlate.options.photolater=F\u00f6teli sp\u00f6ter alsem Punkt
+dialog.correlate.options.pointlaterphoto=Punkt sp\u00f6ter alsem F\u00f6teli
+dialog.correlate.options.audiolater=Audio sp\u00f6ter alsem Punkt
+dialog.correlate.options.pointlateraudio=Punkt sp\u00f6ter alsem Audio
+dialog.correlate.options.limitspanel=Korrelation Gr\u00e4nz\u00e4
+dialog.correlate.options.notimelimit=Kei Ziitgr\u00e4nz\u00e4
+dialog.correlate.options.timelimit=Ziitgr\u00e4nz\u00e4
+dialog.correlate.options.nodistancelimit=Kei Distanzgr\u00e4nz\u00e4
+dialog.correlate.options.distancelimit=Distanzgr\u00e4nz\u00e4
+dialog.correlate.options.correlate=Korrelier\u00e4
+dialog.correlate.alloutsiderange=Alli Elem\u00e4nte sin uusserhalb vonem Track Ziitruum, so ch\u00f6nne n\u00f6d korreliert werd\u00e4.\nVersuechet Sie mitenem anderen Offset oder verbindet Sie manuell mindeschtens eis Elem\u00e4nt.
dialog.correlate.filetimes=Die Datei Zeitstempel zeigen:
dialog.correlate.filetimes2=der Tonspuren
-dialog.correlate.correltimes=Fürs Korreliere, folgendes verwände:
+dialog.correlate.correltimes=F\u00fcrs Korreliere, folgendes verw\u00e4nde:
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.audioselect.intro=W\u00e4hlet Sie eini vo deren Audios uus, um die Ziitdiffer\u00e4nz zu ber\u00e4chn\u00e4
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.correlate.select.audiolater=Audio sp\u00f6ter
+dialog.rearrangephotos.desc=Bitte Ziel und Reihefolge von d P\u00fcnkte setze
dialog.rearrangephotos.tostart=zum Aafang
dialog.rearrangephotos.toend=zum Ände
-dialog.rearrangephotos.nosort=Nöd sortiere
+dialog.rearrangephotos.nosort=N\u00f6d sortiere
dialog.rearrangephotos.sortbyfilename=per Filename sortiere
dialog.rearrangephotos.sortbytime=per Ziit sortiere
-dialog.compress.nonefound=Kei Punkte hätte gelöscht werde könne
-dialog.compress.duplicates.title=Duplikate entfärnä
-dialog.compress.closepoints.title=Nöchiglägeni Punkte entfärnä
+dialog.compress.duplicates.title=Duplikate entf\u00e4rn\u00e4
+dialog.compress.closepoints.title=N\u00f6chigl\u00e4geni P\u00fcnkte entf\u00e4rn\u00e4
dialog.compress.closepoints.paramdesc=Span Faktor
-dialog.compress.wackypoints.title=Komischi Punkte entfärnä
+dialog.compress.wackypoints.title=Komischi P\u00fcnkte entf\u00e4rn\u00e4
dialog.compress.wackypoints.paramdesc=Distanz Faktor
-dialog.compress.singletons.title=Singletons entfärnä
+dialog.compress.singletons.title=Singletons entf\u00e4rn\u00e4
dialog.compress.singletons.paramdesc=Distanz faktor
dialog.compress.douglaspeucker.title=Douglas-Peucker Komprimierig
dialog.compress.douglaspeucker.paramdesc=Span Faktor
-dialog.compress.summarylabel=Punkte zu entfärnä
-dialog.pastecoordinates.desc=Gäbet Sie hier die Koordinaten innä
+dialog.compress.summarylabel=P\u00fcnkte zu entf\u00e4rn\u00e4
+dialog.compress.confirm1=Es sin
+dialog.compress.confirm2=P\u00fcnkt markiert.\nMit Track->Markierte P\u00fcnkte l\u00f6sche werdet sie gl\u00f6scht
+dialog.compress.confirmnone=es sin kei P\u00fcnkte markiert worde
+dialog.deletemarked.nonefound=Kei P\u00fcnkte h\u00e4tte gel\u00f6scht werde k\u00f6nne
+dialog.pastecoordinates.desc=G\u00e4bet Sie hier die Koordinaten inn\u00e4
dialog.pastecoordinates.coords=Koordinate
-dialog.pastecoordinates.nothingfound=Prüefet Sie die Koordinate und versuechet nomal
-dialog.help.help=Bitte lueg na\n http://activityworkshop.net/software/gpsprune/\nfür wiitere Information und Benutzeraaleitige.
+dialog.pastecoordinates.nothingfound=Pr\u00fcefet Sie die Koordinate und versuechet nomal
+dialog.help.help=Bitte lueg na\n http://activityworkshop.net/software/gpsprune/\nf\u00fcr wiitere Information und Benutzeraaleitige.
dialog.about.version=Version
dialog.about.build=Build
-dialog.about.summarytext1=GpsPrune isch s Programm fürs Lade, Darstelle und Editiere vo Date von GPS Geräte.
-dialog.about.summarytext2=Es isch unter den Gnu GPL zur Verfüegig gstellt,für frei, gratis und offen Gebruuch und Wiiterentwicklig.<br>Kopiere, Wiiterverbreitig und Veränderige sin erlaubt und willkomme<br>unter die Bedingige im enthaltene <code>license.txt</code> File.
-dialog.about.summarytext3=Bitte lueget Sie na <code style="font-weight:bold">http://activityworkshop.net/</code> für wiitere Informatione und Benutzeraaleitige.
-dialog.about.languages=Verfüegbare Sproche
-dialog.about.translatedby=Schwiizerdüütschi Übersetzig vo activityworkshop.
+dialog.about.summarytext1=GpsPrune isch s Programm f\u00fcrs Lade, Darstelle und Editiere vo Date von GPS Ger\u00e4te.
+dialog.about.summarytext2=Es isch unter den Gnu GPL zur Verf\u00fcegig gstellt,f\u00fcr frei, gratis und offen Gebruuch und Wiiterentwicklig.<br>Kopiere, Wiiterverbreitig und Ver\u00e4nderige sin erlaubt und willkomme<br>unter die Bedingige im enthaltene <code>license.txt</code> File.
+dialog.about.summarytext3=Bitte lueget Sie na <code style="font-weight:bold">http://activityworkshop.net/</code> f\u00fcr wiitere Informatione und Benutzeraaleitige.
+dialog.about.languages=Verf\u00fcegbare Sproche
+dialog.about.translatedby=Schwiizerd\u00fc\u00fctschi Ãœbersetzig vo activityworkshop.
dialog.about.systeminfo=Syschtem Info
dialog.about.systeminfo.os=Betriebsyschtem
dialog.about.systeminfo.java=Version vonem Java
dialog.about.systeminfo.gnuplot=Gnuplot inschtalliert
dialog.about.systeminfo.exiflib=Exif Bibliothek
dialog.about.systeminfo.exiflib.internal=Intern
-dialog.about.systeminfo.exiflib.internal.failed=Intern (nöd gfunde)
-dialog.about.systeminfo.exiflib.external=Extärn
-dialog.about.systeminfo.exiflib.external.failed=Extärn (nöd gfunde)
+dialog.about.systeminfo.exiflib.internal.failed=Intern (n\u00f6d gfunde)
+dialog.about.systeminfo.exiflib.external=Ext\u00e4rn
+dialog.about.systeminfo.exiflib.external.failed=Ext\u00e4rn (n\u00f6d gfunde)
dialog.about.yes=Ja
dialog.about.no=Nei
dialog.about.credits=Credits
-dialog.about.credits.code=GpsPrune Code gschriebä vo
+dialog.about.credits.code=GpsPrune Code gschrieb\u00e4 vo
dialog.about.credits.exifcode=Exif Code vo
dialog.about.credits.icons=Einigi Bilder vo
-dialog.about.credits.translators=Dolmätscher
+dialog.about.credits.translators=Dolm\u00e4tscher
dialog.about.credits.translations=Ãœbersetzige mit dr Hilfe vo
-dialog.about.credits.devtools=Entwicklungswärkzüüge
-dialog.about.credits.othertools=Anderi Wärkzüüge
+dialog.about.credits.devtools=Entwicklungsw\u00e4rkz\u00fc\u00fcge
+dialog.about.credits.othertools=Anderi W\u00e4rkz\u00fc\u00fcge
dialog.about.credits.thanks=Danke an
-dialog.about.readme=Läsmi
-dialog.checkversion.error=Die Versionnummer könne nöd gefprüft werdä.\nGits ne internet Verbindig?
+dialog.about.readme=L\u00e4smi
+dialog.checkversion.error=Die Versionnummer k\u00f6nne n\u00f6d gefpr\u00fcft werd\u00e4.\nGits ne internet Verbindig?
dialog.checkversion.uptodate=Sie han die noischti Version vonem GpsPrune scho.
dialog.checkversion.newversion1=Ne noii Version vonem GpsPrune isch jetzt usse! Die heisst jetzt Version
dialog.checkversion.newversion2=.
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/gpsprune/download.html.
-dialog.keys.intro=Aastatt d'Muus könnet Sie diese Tastekombinationen nutze
-dialog.keys.keylist=<table><tr><td>Pfiil Taste</td><td>Karte verschiebe</td></tr><tr><td>Strg + links, rächts Pfiil</td><td>Vorherigi oder nöchsti Punkt markiere</td></tr><tr><td>Strg + uuf, aba Pfiil</td><td>Ii- oder Uusezoome</td></tr><tr><td>Strg + Bild uuf, ab</td><td>Vorherigi oder nöchsti Segmänt markiere</td></tr><tr><td>Strg + Pos1, Ände</td><td>Erschti oder letschti Punkt markiere</td></tr><tr><td>Entf</td><td>Aktuelli Punkt lösche</td></tr></table>
+dialog.keys.intro=Aastatt d'Muus k\u00f6nnet Sie diese Tastekombinationen nutze
+dialog.keys.keylist=<table><tr><td>Pfiil Taste</td><td>Karte verschiebe</td></tr><tr><td>Strg + links, r\u00e4chts Pfiil</td><td>Vorherigi oder n\u00f6chsti Punkt markiere</td></tr><tr><td>Strg + uuf, aba Pfiil</td><td>Ii- oder Uusezoome</td></tr><tr><td>Strg + Bild uuf, ab</td><td>Vorherigi oder n\u00f6chsti Segm\u00e4nt markiere</td></tr><tr><td>Strg + Pos1, Ände</td><td>Erschti oder letschti Punkt markiere</td></tr><tr><td>Entf</td><td>Aktuelli Punkt l\u00f6sche</td></tr></table>
dialog.keys.normalmodifier=Strg
dialog.keys.macmodifier=Kommando
-dialog.saveconfig.desc=Die folgendi Iinstellige könne gspeicheret werde :
+dialog.saveconfig.desc=Die folgendi Iinstellige k\u00f6nne gspeicheret werde :
dialog.saveconfig.prune.trackdirectory=Trackverzeichnis
-dialog.saveconfig.prune.photodirectory=Föteliverzeichnis
+dialog.saveconfig.prune.photodirectory=F\u00f6teliverzeichnis
dialog.saveconfig.prune.languagecode=Sprochecode (DE_ch)
dialog.saveconfig.prune.languagefile=Sprochedatei
-dialog.saveconfig.prune.gpsdevice=GPS Gerätename
+dialog.saveconfig.prune.gpsdevice=GPS Ger\u00e4tename
dialog.saveconfig.prune.gpsformat=GPS Format
dialog.saveconfig.prune.povrayfont=Povray Font
-dialog.saveconfig.prune.metricunits=Metrischi Einheite verwende?
dialog.saveconfig.prune.gnuplotpath=Gnuplot Pfad
dialog.saveconfig.prune.gpsbabelpath=Gpsbabel Pfad
dialog.saveconfig.prune.exiftoolpath=Exiftool Pfad
dialog.saveconfig.prune.mapsourcelist=Kartenservers
dialog.saveconfig.prune.diskcache=Kartenordner
dialog.saveconfig.prune.kmzimagewidth=Bildbreiti im KMZ
-dialog.saveconfig.prune.kmzimageheight=Bildhöchi im KMZ
+dialog.saveconfig.prune.kmzimageheight=Bildh\u00f6chi im KMZ
dialog.saveconfig.prune.colourscheme=Farbeschema
dialog.saveconfig.prune.linewidth=Liniedicke
dialog.saveconfig.prune.kmltrackcolour=KML Trackfarb
dialog.saveconfig.prune.autosavesettings=Iistellige speichere
-dialog.setpaths.intro=Sie könnet dann die Pfade für dia Applikatione setzä:
+dialog.setpaths.intro=Sie k\u00f6nnet dann die Pfade f\u00fcr dia Applikatione setz\u00e4:
dialog.setpaths.found=Pfad gfunde?
-dialog.addaltitude.noaltitudes=Dr seläktierte Beriich hät keini Höchiinformation
-dialog.addaltitude.desc=Höchiverschiebig zuzutue
-dialog.lookupsrtm.overwritezeros=Höchiwärte von null überschriebä?
-dialog.setcolours.intro=Klicket Sie uuf ne Farb um sie z'verändere
+dialog.addaltitude.noaltitudes=Dr sel\u00e4ktierte Beriich h\u00e4t keini H\u00f6chiinformation
+dialog.addaltitude.desc=H\u00f6chiverschiebig zuzutue
+dialog.lookupsrtm.overwritezeros=H\u00f6chiw\u00e4rte von null \u00fcberschrieb\u00e4?
+dialog.setcolours.intro=Klicket Sie uuf ne Farb um sie z'ver\u00e4ndere
dialog.setcolours.background=Hintergrund
dialog.setcolours.borders=Rande
dialog.setcolours.lines=Linie
-dialog.setcolours.primary=Primär
-dialog.setcolours.secondary=Secondär
-dialog.setcolours.point=Punkte
+dialog.setcolours.primary=Prim\u00e4r
+dialog.setcolours.secondary=Second\u00e4r
+dialog.setcolours.point=P\u00fcnkte
dialog.setcolours.selection=Beriich
dialog.setcolours.text=Texte
-dialog.colourchooser.title=Farbe uuswähle
+dialog.colourchooser.title=Farbe uusw\u00e4hle
dialog.colourchooser.red=Rot
-dialog.colourchooser.green=Grüen
+dialog.colourchooser.green=Gr\u00fcen
dialog.colourchooser.blue=Blau
-dialog.setlanguage.firstintro=Sie könnet entweder eini vo den iigebouti Sproche<p>oder ne Text-Datei uuswähle.
-dialog.setlanguage.secondintro=Sie münt Ihri Iistellige speichere und dann<p>GpsPrune wieder neustarte um die Sproch z'ändere.
+dialog.setlanguage.firstintro=Sie k\u00f6nnet entweder eini vo den iigebouti Sproche<p>oder ne Text-Datei uusw\u00e4hle.
+dialog.setlanguage.secondintro=Sie m\u00fcnt Ihri Iistellige speichere und dann<p>GpsPrune wieder neustarte um die Sproch z'\u00e4ndere.
dialog.setlanguage.language=Sproch
dialog.setlanguage.languagefile=Sproch Datei
-dialog.setlanguage.endmessage=Jetze speicheret Sie Ihri Iistellige und startet Sie GpsPrune neu\num t noii Sproch z' verwände.
-dialog.setlanguage.endmessagewithautosave=Startet Sie GpsPrune neu um t noii Sproch z' verwände.
+dialog.setlanguage.endmessage=Jetze speicheret Sie Ihri Iistellige und startet Sie GpsPrune neu\num t noii Sproch z' verw\u00e4nde.
+dialog.setlanguage.endmessagewithautosave=Startet Sie GpsPrune neu um t noii Sproch z' verw\u00e4nde.
dialog.diskcache.save=Karten uufem Disk speichere
dialog.diskcache.dir=Kartenordner
dialog.diskcache.createdir=Ordner kreiere
-dialog.diskcache.nocreate=Ordner isch nöd kreiert worde
+dialog.diskcache.nocreate=Ordner isch n\u00f6d kreiert worde
+dialog.diskcache.cannotwrite=Kachle k\u00f6nned n\u00f6d im Ordner gspeicheret werde
dialog.diskcache.table.path=Pfad
-dialog.diskcache.table.usedby=Aawänder
+dialog.diskcache.table.usedby=Aaw\u00e4nder
dialog.diskcache.table.zoom=Zoom
dialog.diskcache.table.tiles=Kachle
dialog.diskcache.table.megabytes=Megabytes
dialog.diskcache.deleteall=Alli Kachle l\u00f6sche
dialog.diskcache.deleted1=Es sin
dialog.diskcache.deleted2=Files uusem Ordner gl\u00f6scht 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.deletefieldvalues.intro=W\u00e4hlet Sie s F\u00e4ld uus zum l\u00f6sche
+dialog.deletefieldvalues.nofields=Es sin kei F\u00e4lder z'l\u00f6sche f\u00fcr dere Beriich
+dialog.setlinewidth.text=G\u00e4bet Sie die Dicke vonen Linien ii (1-4)
+dialog.downloadosm.desc=Best\u00e4tige um rohi OSM Date f\u00fcrn Gebiet aba zlade:
dialog.searchwikipedianames.search=Sueche na:
# 3d window
-dialog.3d.title=GpsPrune Drüü-d Aasicht
-dialog.3d.altitudefactor=Höchivervilfachigsfaktor
+dialog.3d.title=GpsPrune Dr\u00fc\u00fc-d Aasicht
+dialog.3d.altitudefactor=H\u00f6chivervilfachigsfaktor
dialog.3dlines.title=GpsPrune Gitterlinie
-dialog.3dlines.empty=Kei Linie zum aazeigä!
-dialog.3dlines.intro=Hier sin die Linie für die drüü-D Aasicht
+dialog.3dlines.empty=Kei Linie zum aazeig\u00e4!
+dialog.3dlines.intro=Hier sin die Linie f\u00fcr die dr\u00fc\u00fc-D Aasicht
# Confirm messages
confirm.loadfile=Date glade vom
confirm.save.ok1=Es sin
-confirm.save.ok2=Punkte gspeicheret worde na
+confirm.save.ok2=P\u00fcnkte gspeicheret worde na
confirm.deletepoint.single=Punkt isch entfernt worde
-confirm.deletepoint.multi=Punkte sin entfernt worde
+confirm.deletepoint.multi=P\u00fcnkte sin entfernt worde
confirm.point.edit=Punkt editiert
-confirm.mergetracksegments=Segmänte gmerged
-confirm.reverserange=Beriich umgdrähet
+confirm.mergetracksegments=Segm\u00e4nte gmerged
+confirm.reverserange=Beriich umgdr\u00e4het
confirm.addtimeoffset=Ziitverschiebig zutue
-confirm.addaltitudeoffset=Höchiverschiebig zutue
+confirm.addaltitudeoffset=H\u00f6chiverschiebig zutue
confirm.rearrangewaypoints=Waypoints umorganisiert
confirm.rearrangephotos=Fotos umorganisiert
confirm.cutandmove=Beriich gmoved
+confirm.interpolate=P\u00fcnkte iigf\u00fcgt worde
confirm.convertnamestotimes=Waypointname verwondlet
confirm.saveexif.ok1=Es sin
-confirm.saveexif.ok2=Fötelis gschriebe worde
-confirm.undo.single=Operation rückgängig gmacht worde.
-confirm.undo.multi=Operatione rückgängig gmacht worde.
-confirm.jpegload.single=Föteli isch glade worde
-confirm.jpegload.multi=Fötelis sin glade worde
-confirm.media.connect=Media verbundä
-confirm.photo.disconnect=Föteli gtrännt
-confirm.audio.disconnect=Audio gtrännt
-confirm.correlatephotos.single=Föteli isch korreliert worde
-confirm.correlatephotos.multi=Fötelis sin korreliert worde
+confirm.saveexif.ok2=F\u00f6telis gschriebe worde
+confirm.undo.single=Operation r\u00fcckg\u00e4ngig gmacht worde.
+confirm.undo.multi=Operatione r\u00fcckg\u00e4ngig gmacht worde.
+confirm.jpegload.single=F\u00f6teli isch glade worde
+confirm.jpegload.multi=F\u00f6telis sin glade worde
+confirm.media.connect=Media verbund\u00e4
+details.media.fullpath=Ganzi Pfad
+confirm.photo.disconnect=F\u00f6teli gtr\u00e4nnt
+confirm.audio.disconnect=Audio gtr\u00e4nnt
+confirm.correlatephotos.single=F\u00f6teli isch korreliert worde
+confirm.correlatephotos.multi=F\u00f6telis sin korreliert worde
confirm.createpoint=Punkt kreiert worde
-confirm.rotatephoto=Föteli umgedräit worde
+confirm.rotatephoto=F\u00f6teli umgedr\u00e4it worde
confirm.running=Am Laufe ...
confirm.lookupsrtm1=Es sin
-confirm.lookupsrtm2=Höhenwerte gfunde
-confirm.deletefieldvalues=Feldwärte glöscht worde
+confirm.lookupsrtm2=H\u00f6henwerte gfunde
+confirm.deletefieldvalues=Feldw\u00e4rte gl\u00f6scht worde
confirm.audioload=Audiofiles glade worde
-confirm.media.removed=entfärnt
+confirm.media.removed=entf\u00e4rnt
confirm.correlateaudios.single=Audiofile isch korreliert worde
confirm.correlateaudios.multi=Audiofiles sin korreliert worde
# Buttons
button.ok=OK
button.back=Zrugg
-button.next=Nöchstä
+button.next=N\u00f6chst\u00e4
button.finish=Fertig
-button.cancel=Abbrächä
-button.overwrite=Überschriibä
-button.moveup=Uufä schiebä
-button.movedown=Aba schiebä
-button.showlines=Linie aazeigä
-button.edit=Editierä
-button.exit=Beändä
-button.close=Schliessä
-button.continue=Fortsetzä
+button.cancel=Abbr\u00e4ch\u00e4
+button.overwrite=Ãœberschriib\u00e4
+button.moveup=Uuf\u00e4 schieb\u00e4
+button.movedown=Aba schieb\u00e4
+button.showlines=Linie aazeig\u00e4
+button.edit=Editier\u00e4
+button.exit=Be\u00e4nd\u00e4
+button.close=Schliess\u00e4
+button.continue=Fortsetz\u00e4
button.yes=Ja
button.no=Nei
-button.yestoall=Ja für alli
-button.notoall=Nei für alli
-button.select=Uuswähle
-button.selectall=Alli uuswähle
-button.selectnone=Nüüt uuswähle
-button.preview=Vorschauä
-button.load=Ladä
-button.upload=Uufaladä
-button.guessfields=Fälde erratä
-button.showwebpage=Websiite aazeigä
-button.check=Prüefa
-button.resettodefaults=Zurücksetzä
-button.browse=Durasuechä...
-button.addnew=Hinzuefügä
-button.delete=Entfärnä
-button.manage=Verwoltä
+button.yestoall=Ja f\u00fcr alli
+button.notoall=Nei f\u00fcr alli
+button.select=Uusw\u00e4hle
+button.selectall=Alli uusw\u00e4hle
+button.selectnone=N\u00fc\u00fct uusw\u00e4hle
+button.preview=Vorschau\u00e4
+button.load=Lad\u00e4
+button.upload=Uufalad\u00e4
+button.guessfields=F\u00e4lde errat\u00e4
+button.showwebpage=Websiite aazeig\u00e4
+button.check=Pr\u00fcefa
+button.resettodefaults=Zur\u00fccksetz\u00e4
+button.browse=Durasuech\u00e4...
+button.addnew=Hinzuef\u00fcg\u00e4
+button.delete=Entf\u00e4rn\u00e4
+button.manage=Verwolt\u00e4
# File types
filetype.txt=TXT Dateie
# Display components
display.nodata=Kei Date glade worde
-display.noaltitudes=Track hät kei Höhi Date
-display.notimestamps=Track hät kei Ziitstämple
+display.noaltitudes=Track h\u00e4t kei H\u00f6hi Date
+display.notimestamps=Track h\u00e4t kei Ziitst\u00e4mple
details.trackdetails=Details vom Track
details.notrack=Kei Track glade worde
-details.track.points=Punkte
+details.track.points=P\u00fcnkte
details.track.file=Datei
details.track.numfiles=Anzahl Dateie
details.pointdetails=Details vonem Punkt
details.index.selected=Index
details.index.of=vo
-details.nopointselection=Nüüt selektiert
-details.photofile=Föteli Datei
-details.norangeselection=Nüüt selektiert
+details.nopointselection=N\u00fc\u00fct selektiert
+details.photofile=F\u00f6teli Datei
+details.norangeselection=N\u00fc\u00fct selektiert
details.rangedetails=Details vonem Beriich
details.range.selected=Selektiert
details.range.to=bis
display.range.time.hours=Std
display.range.time.days=T
details.range.avespeed=Gschwindikeit
-details.range.avemovingspeed=Gschwindikeit ufem Wäg
-details.range.maxspeed=Höchstgschwindikeit
-details.range.numsegments=Aazahl Segmänte
+details.range.maxspeed=H\u00f6chstgschwindikeit
+details.range.numsegments=Aazahl Segm\u00e4nte
details.range.pace=Tempo
-details.range.gradient=Gefälle
+details.range.gradient=Gef\u00e4lle
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.lists.photos=F\u00f6telis
+details.photodetails=Details vonem F\u00f6teli
+details.nophoto=Kei f\u00f6teli selektiert
+details.photo.loading=Lad\u00e4
details.photo.bearing=Richtig
-details.media.connected=Verbundä
+details.media.connected=Verbund\u00e4
details.lists.audio=Audio
details.audiodetails=Audiodetails
details.noaudio=Kei Audiofile selektiert
details.audio.file=Audiofile
-details.audio.playing=am abschpielä...
+details.audio.playing=am abschpiel\u00e4...
map.overzoom=Kei Karte mit diesem Zoom
# Field names
fieldname.latitude=Breitegrad
-fieldname.longitude=Längegrad
-fieldname.altitude=Höchi
-fieldname.timestamp=Ziitstämpel
+fieldname.longitude=L\u00e4ngegrad
+fieldname.altitude=H\u00f6chi
+fieldname.timestamp=Ziitst\u00e4mpel
fieldname.time=Ziit
fieldname.waypointname=Name
fieldname.waypointtype=Typ
-fieldname.newsegment=Segmänt
+fieldname.newsegment=Segm\u00e4nt
fieldname.custom=Custom
-fieldname.prefix=Fäld
-fieldname.distance=Längi
-fieldname.movingdistance=Weglängi
-fieldname.duration=Ziitlängi
+fieldname.prefix=F\u00e4ld
+fieldname.distance=L\u00e4ngi
+fieldname.movingdistance=Wegl\u00e4ngi
+fieldname.duration=Ziitl\u00e4ngi
fieldname.speed=Gschwindikeit
fieldname.verticalspeed=Uf/Ab Gschwindikeit
fieldname.description=Bschriibig
units.original=Original
units.default=Default
units.metres=Meter
+units.metres.short=m
units.kilometres=Kilometer
units.kilometres.short=km
-units.kmh=km/h
-units.metrespersec=m/s
-units.feetpersec=ft/s
+units.kilometresperhour.short=kmh
+units.nauticalmiles=Seemeile
+units.nauticalmiles.short=sm
+units.nauticalmilesperhour.short=kn
+units.metrespersec.short=m/s
+units.feetpersec.short=ft/s
units.hours=Std
units.degminsec=Grad-Min-Sek
units.degmin=Grad-Min
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.removephoto=Föteli entfärnä
-undo.removeaudio=Audiofile entfärnä
-undo.deleterange=Beriich löschä
-undo.compress=Track komprimierä
-undo.insert=Punkte innätuä
-undo.reverse=Beriich umdrähie
-undo.mergetracksegments=track segmänte merge
+undo.load=Date lad\u00e4
+undo.loadphotos=F\u00f6telis lad\u00e4
+undo.loadaudios=Audiofiles lad\u00e4
+undo.editpoint=Punkt editier\u00e4
+undo.deletepoint=Punkt l\u00f6sch\u00e4
+undo.removephoto=F\u00f6teli entf\u00e4rn\u00e4
+undo.removeaudio=Audiofile entf\u00e4rn\u00e4
+undo.deleterange=Beriich l\u00f6sch\u00e4
+undo.croptrack=Track zuschniid\u00e4
+undo.deletemarked=P\u00fcnkte l\u00f6sch\u00e4
+undo.insert=P\u00fcnkte inn\u00e4tu\u00e4
+undo.reverse=Beriich umdr\u00e4hie
+undo.mergetracksegments=track segm\u00e4nte merge
undo.addtimeoffset=ziitverschiebig zutue
-undo.addaltitudeoffset=höchiverschiebig zutue
-undo.rearrangewaypoints=Waypoints reorganisierä
-undo.cutandmove=Selektion movä
-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ä
+undo.addaltitudeoffset=h\u00f6chiverschiebig zutue
+undo.rearrangewaypoints=Waypoints reorganisier\u00e4
+undo.cutandmove=Selektion mov\u00e4
+undo.connect=verbind\u00e4
+undo.disconnect=tr\u00e4nn\u00e4
+undo.correlatephotos=F\u00f6telis korrelier\u00e4
+undo.rearrangephotos=F\u00f6telis reorganisier\u00e4
+undo.createpoint=Punkt kreier\u00e4
+undo.rotatephoto=F\u00f6teli umadr\u00e4ya
+undo.convertnamestotimes=Name ins Ziitst\u00e4mple verwondl\u00e4
+undo.lookupsrtm=H\u00f6hendate vonem SRTM hol\u00e4
+undo.deletefieldvalues=Feldw\u00e4rte l\u00f6sch\u00e4
+undo.correlateaudios=Audios korrelier\u00e4
# Error messages
-error.save.dialogtitle=Fähle bim Speichere
+error.save.dialogtitle=F\u00e4hle bim Speichere
error.save.nodata=Kei Date zum speichere
error.save.failed=Speichere vom File fehlgschlage
-error.saveexif.filenotfound=Föteli File nöd gfunde
-error.saveexif.cannotoverwrite1=Föteli File
-error.saveexif.cannotoverwrite2=isch nöd schriibbar. Speichere na einer Kopie?
+error.saveexif.filenotfound=F\u00f6teli File n\u00f6d gfunde
+error.saveexif.cannotoverwrite1=F\u00f6teli File
+error.saveexif.cannotoverwrite2=isch n\u00f6d schriibbar. Speichere na einer Kopie?
error.saveexif.failed1=
-error.saveexif.failed2=von d Bilder han i nöd speichere könne
+error.saveexif.failed2=von d Bilder han i n\u00f6d k\u00f6nne speichere
error.saveexif.forced1=
-error.saveexif.forced2=von d Bilder han i müsse forziere
-error.load.dialogtitle=Fähle bim Lade
-error.load.noread=File cha nöd glase werde
-error.load.nopoints=Kei gültigi Information inem File gfunde
+error.saveexif.forced2=von d Bilder han i m\u00fcsse forziere
+error.load.dialogtitle=F\u00e4hle bim Lade
+error.load.noread=File cha n\u00f6d glase werde
+error.load.nopoints=Kei g\u00fcltigi Information inem File gfunde
error.load.unknownxml=Unbekanntes xml Format:
error.load.noxmlinzip=Kei xml im Zip File gfunde
-error.load.othererror=Fähle bim Läse:
-error.jpegload.dialogtitle=Fähle bim Lade von Fötelis
+error.load.othererror=F\u00e4hle bim L\u00e4se:
+error.jpegload.dialogtitle=F\u00e4hle bim Lade von F\u00f6telis
error.jpegload.nofilesfound=Kei Files gfunde
error.jpegload.nojpegsfound=Kei Jpegs 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.jpegload.exifreadfailed=EXIF Uufruef isch fehlgschlage. Kei EXIF Infos k\u00f6nnet gl\u00e4se werde\nohni nen interni oder ext\u00e4rni Bibliothek.
error.audioload.nofilesfound=Kei Audiofiles gfunde
-error.gpsload.unknown=Unbekannts Fähler
+error.gpsload.unknown=Unbekannts F\u00e4hler
error.undofailed.title=Undo isch fehlgschlage worde
-error.undofailed.text=Operation kann nöd rückgängig gmacht werde
-error.function.noop.title=Funktion hät gar nüüt gmacht
-error.rearrange.noop=Punkte Reorganisierig hät kei Effäkt gha
-error.function.notavailable.title=Funktion nöd verfüegbar
-error.function.nojava3d=Sorry, d'Funktion brucht d Java3d Library,\nvo Sun.com erhältlech.
-error.3d=N Fähler isch mitere 3d Darstellig ufgträte
-error.readme.notfound=Läs mi File nöd gfunde
-error.osmimage.dialogtitle=Fähle bim Bildli-Lade
-error.osmimage.failed=Map Bildli könne nöd glade werde. Gits ne Internet Verbindig?
-error.language.wrongfile=Die uusgewählti Datei scheint kei Sproch-Datei für GpsPrune z'sii
-error.convertnamestotimes.nonames=Kei Namen han könnet verwondlet werde
-error.lookupsrtm.nonefound=Kei Höhendate verfüegbar für d'Punkte
-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.undofailed.text=Operation kann n\u00f6d r\u00fcckg\u00e4ngig gmacht werde
+error.function.noop.title=Funktion h\u00e4t gar n\u00fc\u00fct gmacht
+error.rearrange.noop=P\u00fcnkte Reorganisierig h\u00e4t kei Eff\u00e4kt gha
+error.function.notavailable.title=Funktion n\u00f6d verf\u00fcegbar
+error.function.nojava3d=Sorry, d'Funktion brucht d Java3d Library,\nvo Sun.com erh\u00e4ltlech.
+error.3d=N F\u00e4hler isch mitere 3d Darstellig ufgtr\u00e4te
+error.readme.notfound=L\u00e4s mi File n\u00f6d gfunde
+error.osmimage.dialogtitle=F\u00e4hle bim Bildli-Lade
+error.osmimage.failed=Map Bildli k\u00f6nne n\u00f6d glade werde. Gits ne Internet Verbindig?
+error.language.wrongfile=Die uusgew\u00e4hlti Datei scheint kei Sproch-Datei f\u00fcr GpsPrune z'sii
+error.convertnamestotimes.nonames=Kei Namen han k\u00f6nnet verwondlet werde
+error.lookupsrtm.nonefound=Kei H\u00f6hendate verf\u00fcegbar f\u00fcr d'P\u00fcnkte
+error.lookupsrtm.nonerequired=Alle P\u00fcnkte han die H\u00f6hendate scho. N\u00fc\u00fct z'tue.
+error.gpsies.uploadnotok=Der Gpsies Server h\u00e4t gseit gha
error.gpsies.uploadfailed=S Uufalade isch fehlgschlage
+error.showphoto.failed=S F\u00f6teli han i n\u00f6d k\u00f6nne lade
error.playaudiofailed=S Abschpiele vonem File isch fehlgschlage
-error.cache.notthere=D Ordner isch nöd gfunde worde
-error.cache.empty=D Ordner hät nüüt drinne
+error.cache.notthere=D Ordner isch n\u00f6d gfunde worde
+error.cache.empty=D Ordner h\u00e4t n\u00fc\u00fct drinne
error.cache.cannotdelete=Es sin kei Kachle gl\u00f6scht worde
+error.interpolate.invalidparameter=D'Aazahl P\u00fcnkt muess zw\u00fcschet 1 und 1000 sii
# Text entries for the GpsPrune application
-# English entries as default - others can be added
+# English entries as default
# Menu entries
menu.file=File
menu.track=Track
menu.track.undo=Undo
menu.track.clearundo=Clear undo list
+menu.track.markrectangle=Mark points in rectangle
menu.track.deletemarked=Delete marked points
menu.track.rearrange=Rearrange waypoints
menu.track.rearrange.start=All to start of file
menu.range.none=Select none
menu.range.start=Set range start
menu.range.end=Set range end
-menu.range.deleterange=Delete range
-menu.range.interpolate=Interpolate
menu.range.average=Average selection
menu.range.reverse=Reverse range
menu.range.mergetracksegments=Merge track segments
menu.map.autopan=Autopan
menu.map.showmap=Show map
menu.map.showscalebar=Show scalebar
+menu.map.editmode=Edit mode
# Alt keys for menus
altkey.menu.file=F
function.exportsvg=Export SVG
function.editwaypointname=Edit waypoint name
function.compress=Compress track
+function.deleterange=Delete range
+function.croptrack=Crop track
+function.interpolate=Interpolate points
function.addtimeoffset=Add time offset
function.addaltitudeoffset=Add altitude offset
function.findwaypoint=Find waypoint
dialog.deletepoint.deletephoto=Delete photo attached to this point?
dialog.deletephoto.title=Delete Photo
dialog.deletephoto.deletepoint=Delete point attached to this photo?
+dialog.deleteaudio.deletepoint=Delete point attached to this audio clip?
dialog.openoptions.title=Open options
dialog.openoptions.filesnippet=Extract of file
dialog.load.table.field=Field
dialog.confirmreversetrack.text=This track contains timestamp information, which will be out of sequence after a reversal.\nAre you sure you want to reverse this section?
dialog.confirmcutandmove.title=Confirm cut and move
dialog.confirmcutandmove.text=This track contains timestamp information, which will be out of sequence after a move.\nAre you sure you want to move this section?
-dialog.interpolate.title=Interpolate points
-dialog.interpolate.parameter.text=Number of points to insert between selected points
+dialog.interpolate.parameter.text=Number of points to insert between each pair of points
+dialog.interpolate.betweenwaypoints=Interpolate between waypoints?
dialog.undo.title=Undo action(s)
dialog.undo.pretext=Please select the action(s) to undo
dialog.undo.none.title=Cannot undo
dialog.pointnameedit.name=Waypoint name
dialog.pointnameedit.uppercase=UPPER case
dialog.pointnameedit.lowercase=lower case
-dialog.pointnameedit.sentencecase=Sentence Case
+dialog.pointnameedit.titlecase=Title Case
dialog.addtimeoffset.add=Add time
dialog.addtimeoffset.subtract=Subtract time
dialog.addtimeoffset.days=Days
dialog.distances.currentpoint=Current point
dialog.distances.toofewpoints=This function needs waypoints in order to calculate the distances between them
dialog.fullrangedetails.intro=Here are the details for the selected range
+dialog.fullrangedetails.coltotal=Including gaps
+dialog.fullrangedetails.colsegments=Without gaps
dialog.setmapbg.intro=Select one of the map sources, or add a new one
dialog.addmapsource.title=Add new map source
dialog.addmapsource.sourcename=Name of source
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.nouncorrelatedaudios=There are no uncorrelated audios.\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.select.photoname=Photo name
dialog.correlate.select.timediff=Time difference
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.alloutsiderange=All the items are outside the time range of the track, so none can be correlated.\nTry changing the offset or manually correlating at least one item.
dialog.correlate.filetimes=File timestamps denote:
dialog.correlate.filetimes2=of audio clip
dialog.correlate.correltimes=For correlation, use:
dialog.rearrangephotos.nosort=Don't sort
dialog.rearrangephotos.sortbyfilename=Sort by filename
dialog.rearrangephotos.sortbytime=Sort by time
-dialog.compress.nonefound=No data points could be removed
dialog.compress.duplicates.title=Duplicate removal
dialog.compress.closepoints.title=Nearby point removal
dialog.compress.closepoints.paramdesc=Span factor
dialog.compress.douglaspeucker.title=Douglas-Peucker compression
dialog.compress.douglaspeucker.paramdesc=Span factor
dialog.compress.summarylabel=Points to delete
+dialog.compress.confirm1=
+dialog.compress.confirm2=points have been marked.\nUse Track->Delete marked points to delete them
+dialog.compress.confirmnone=no points have been marked
+dialog.deletemarked.nonefound=No data points could be removed
dialog.pastecoordinates.desc=Enter or paste the coordinates here
dialog.pastecoordinates.coords=Coordinates
dialog.pastecoordinates.nothingfound=Please check the coordinates and try again
-dialog.help.help=Please see\n http://activityworkshop.net/software/gpsprune/\nfor more information and user guides.
+dialog.help.help=Please see\n http://gpsprune.activityworkshop.net/\nfor more information and tips,\nincluding a new PDF user guide you can buy.
dialog.about.version=Version
dialog.about.build=Build
dialog.about.summarytext1=GpsPrune is a program for loading, displaying and editing data from GPS receivers.
dialog.about.summarytext2=It is released under the Gnu GPL for free, open, worldwide use and enhancement.<br>Copying, redistribution and modification are permitted and encouraged<br>according to the conditions in the included <code>license.txt</code> file.
-dialog.about.summarytext3=Please see <code style="font-weight:bold">http://activityworkshop.net/</code> for more information and user guides.
+dialog.about.summarytext3=Please see <code style="font-weight:bold">http://activityworkshop.net/</code> for more information and tips, including<br>a new PDF user guide you can buy.
dialog.about.languages=Available languages
dialog.about.translatedby=English text by activityworkshop.
dialog.about.systeminfo=System info
dialog.saveconfig.prune.gpsdevice=GPS device
dialog.saveconfig.prune.gpsformat=GPS format
dialog.saveconfig.prune.povrayfont=Povray font
-dialog.saveconfig.prune.metricunits=Use metric units?
dialog.saveconfig.prune.gnuplotpath=Path to gnuplot
dialog.saveconfig.prune.gpsbabelpath=Path to gpsbabel
dialog.saveconfig.prune.exiftoolpath=Path to exiftool
dialog.diskcache.dir=Cache directory
dialog.diskcache.createdir=Create directory
dialog.diskcache.nocreate=Cache directory not created
+dialog.diskcache.cannotwrite=Map tiles cannot be saved in the selected directory
dialog.diskcache.table.path=Path
dialog.diskcache.table.usedby=Used by
dialog.diskcache.table.zoom=Zoom
dialog.diskcache.deleted1=Deleted
dialog.diskcache.deleted2=files from the cache
dialog.deletefieldvalues.intro=Select the field to delete for the current range
+dialog.deletefieldvalues.nofields=There are no fields to delete for this 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:
confirm.rearrangewaypoints=Waypoints rearranged
confirm.rearrangephotos=Photos rearranged
confirm.cutandmove=Selection moved
+confirm.interpolate=Points added
confirm.convertnamestotimes=Waypoint names converted
confirm.saveexif.ok1=Saved
confirm.saveexif.ok2=photo files
display.range.time.hours=h
display.range.time.days=d
details.range.avespeed=Ave speed
-details.range.avemovingspeed=Moving average
details.range.maxspeed=Maximum speed
details.range.numsegments=Number of segments
details.range.pace=Pace
details.photo.loading=Loading
details.photo.bearing=Bearing
details.media.connected=Connected
+details.media.fullpath=Full path
details.audiodetails=Audio details
details.noaudio=No audio clip selected
details.audio.file=Audio file
units.feet.short=ft
units.kilometres=Kilometres
units.kilometres.short=km
-units.kmh=km/h
+units.kilometresperhour.short=km/h
units.miles=Miles
units.miles.short=mi
-units.mph=mph
-units.metrespersec=m/s
-units.feetpersec=ft/s
+units.milesperhour.short=mph
+units.nauticalmiles=Nautical miles
+units.nauticalmiles.short=N.m.
+units.nauticalmilesperhour.short=kts
+units.metrespersec.short=m/s
+units.feetpersec.short=ft/s
units.hours=hours
units.degminsec=Deg-min-sec
units.degmin=Deg-min
undo.removephoto=remove photo
undo.removeaudio=remove audio clip
undo.deleterange=delete range
-undo.compress=compress track
+undo.croptrack=crop track
+undo.deletemarked=delete points
undo.insert=insert points
undo.reverse=reverse range
undo.mergetracksegments=merge track segments
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.showphoto.failed=Failed to load photo
error.playaudiofailed=Failed to play audio clip
error.cache.notthere=The tile cache directory was not found
error.cache.empty=The tile cache directory is empty
error.cache.cannotdelete=No tiles could be deleted
+error.interpolate.invalidparameter=The number of points must be between 1 and 1000
menu.range.none=No seleccionar nada
menu.range.start=Fijar comienzo
menu.range.end=Fijar final
-menu.range.deleterange=Eliminar rango
-menu.range.interpolate=Interpolar
+function.deleterange=Eliminar rango
+function.interpolate=Interpolar puntos
menu.range.average=Crear punto a la media del rango
menu.range.reverse=Invertir rango
menu.range.mergetracksegments=Unir los segmentos de track
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\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
dialog.undo.pretext=Por favor, seleccione la operaci\u00f3n(es) a deshacer
dialog.pointnameedit.name=Nombre de waypoint
dialog.pointnameedit.uppercase=May\u00fasculas
dialog.pointnameedit.lowercase=min\u00fasculas
-dialog.pointnameedit.sentencecase=Mezcla
+dialog.pointnameedit.titlecase=Mezcla
dialog.addtimeoffset.add=A\u00f1adir tiempo
dialog.addtimeoffset.subtract=Sustraer tiempo
dialog.addtimeoffset.days=Dias
dialog.rearrangephotos.nosort=No sortear
dialog.rearrangephotos.sortbyfilename=Sortear por nombre del archivo
dialog.rearrangephotos.sortbytime=Sortear por tiempo
-dialog.compress.nonefound=Ning\u00fan punto eliminado
+dialog.deletemarked.nonefound=Ning\u00fan punto eliminado
dialog.compress.closepoints.title=remover puntos cercanos
dialog.compress.closepoints.paramdesc=Factor de extensi\u00f3n
dialog.compress.wackypoints.title=Eliminar puntos an\u00f3malos
dialog.saveconfig.prune.gpsdevice=Dispositivo GPS
dialog.saveconfig.prune.gpsformat=Formato GPS
dialog.saveconfig.prune.povrayfont=Fuente povray
-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
display.range.time.hours=h
display.range.time.days=d
details.range.avespeed=Velocidad media
-details.range.avemovingspeed=Moviendo promedio
details.range.maxspeed=Velocidad m\u00e1xima
details.range.numsegments=N\u00famero de segmentos
details.range.pace=Ritmo
units.feet.short=ft
units.kilometres=Kil\u00f3metros
units.kilometres.short=km
-units.kmh=km/h
units.miles=Millas
units.miles.short=mi
-units.mph=mi/h
-units.metrespersec=m/s
-units.feetpersec=ft/s
+units.milesperhour.short=mi/h
+units.metrespersec.short=m/s
+units.feetpersec.short=ft/s
units.hours=horas
units.degminsec=Gra-min-seg
units.degmin=Gra-min
# Undo operations
undo.load=cargar datos
undo.loadphotos=cargar fotos
-undo.loadaudios=Cargar archivos de audio
+undo.loadaudios=cargar archivos de audio
undo.editpoint=editar punto
undo.deletepoint=eliminar punto
undo.removephoto=eliminar foto
-undo.removeaudio=Eliminar archivos de audio
+undo.removeaudio=eliminar archivos de audio
undo.deleterange=eliminar rango
-undo.compress=comprimir track
+undo.deletemarked=eliminar puntos
undo.insert=insertar puntos
undo.reverse=invertir rango
undo.mergetracksegments=unir los segmentos de track
undo.addaltitudeoffset=a\u00f1adir margen de altitud
undo.rearrangewaypoints=reordenar waypoints
undo.cutandmove=mover secci\u00f3n
-undo.connect=Conectar
-undo.disconnect=Desconectar
+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
+undo.deletefieldvalues=eliminar valores de campo
+undo.correlateaudios=correlacionar audios
# Error messages
error.save.dialogtitle=Fallo al guardar datos
menu.range.none=\u0627\u0646\u062a\u062e\u0627\u0628 \u0647\u064a\u0686 \u064a\u06a9 \u0627\u0632 \u0646\u0642\u0627\u0637
menu.range.start=\u062a\u0646\u0638\u064a\u0645 \u0634\u0631\u0648\u0639 \u0686\u064a\u0646\u0634
menu.range.end=\u062a\u0646\u0638\u064a\u0645 \u0627\u0646\u062a\u0647\u0627\u06cc \u0686\u064a\u0646\u0634
-menu.range.deleterange=\u067e\u0627\u06a9 \u06a9\u0631\u062f\u0646 \u0686\u064a\u0646\u0634
-menu.range.interpolate=\u062f\u0631\u0648\u0646\u064a\u0627\u0628\u06cc
+function.deleterange=\u067e\u0627\u06a9 \u06a9\u0631\u062f\u0646 \u0686\u064a\u0646\u0634
+function.interpolate=\u062f\u0631\u0648\u0646\u064a\u0627\u0628\u06cc
menu.range.average=\u0645\u06cc\u0627\u0646\u06af\u064a\u0646 \u0627\u0646\u062a\u062e\u0627\u0628 \u0634\u062f\u0647 \u0647\u0627
menu.range.reverse=\u0686\u064a\u0646\u0634 \u0645\u0639\u06a9\u0648\u0633
menu.range.mergetracksegments=\u0627\u062a\u0635\u0627\u0644 \u0642\u0633\u0645\u062a \u0647\u0627\u06cc \u0645\u0633\u064a\u0631
# Text entries for the GpsPrune application
-# French entries as extra
+# French entries
# Menu entries
menu.file=Fichier
menu.file.addphotos=Ajouter photos
-menu.file.recentfiles=Derniers Fichiers utilis\u00e9s
+menu.file.recentfiles=Fichiers r\u00e9cents
menu.file.save=Enregistrer
menu.file.exit=Quitter
menu.track=Trace
menu.range.none=Rien s\u00e9lectionner
menu.range.start=D\u00e9finir le d\u00e9but de l'\u00e9tendue
menu.range.end=D\u00e9finir la fin de l'\u00e9tendue
-menu.range.deleterange=Supprimer l'\u00e9tendue
-menu.range.interpolate=Interpoler
menu.range.average=Cr\u00e9er un point pour la s\u00e9lection
menu.range.reverse=Inverser l'\u00e9tendue
menu.range.mergetracksegments=Fusionner les segments de trace
# Functions
function.open=Ouvrir fichier
+function.importwithgpsbabel=Importer fichier avec GPSBabel
function.loadfromgps=T\u00e9l\u00e9charger donn\u00e9es du GPS
function.sendtogps=Envoyer donn\u00e9es au GPS
function.exportkml=Exporter en KML
function.exportsvg=Exporter en SVG
function.editwaypointname=\u00c9diter le nom du waypoint
function.compress=Compresser la trace
+function.deleterange=Supprimer l'\u00e9tendue
+function.interpolate=Interpoler les points
function.addtimeoffset=Ajouter un d\u00e9calage d'horaire
function.addaltitudeoffset=Ajouter un d\u00e9calage d'altitude
function.convertnamestotimes=Convertir les noms de waypoints en horodatages
function.checkversion=Chercher une mise \u00e0 jour
function.saveconfig=Enregistrer les pr\u00e9f\u00e9rences
function.diskcache=Enregistrer les cartes sur le disque
+function.managetilecache=Gestion du cache des tuiles de cartes
# Dialogs
dialog.exit.confirm.title=Quitter GpsPrune
dialog.exportgpx.desc=L\u00e9gende
dialog.exportgpx.includetimestamps=Inclure l'heure pour chaque point
dialog.exportgpx.copysource=Copier la source xml
-dialog.exportgpx.encoding.system=Syst\u00e8me
+dialog.exportgpx.encoding=Encodage
+dialog.exportgpx.encoding.system=Encodage syst\u00e8me
dialog.exportgpx.encoding.utf8=UTF-8
dialog.exportpov.text=Entrez les param\u00e8tres pour l'export POV
dialog.exportpov.font=Police
dialog.confirmreversetrack.text=Cette trace contient des informations temporelles qui seront d\u00e9sordonn\u00e9es apr\u00e8s une inversion.\n\u00cates-vous s\u00fbr de vouloir inverser cette section ?
dialog.confirmcutandmove.title=Confirmer le d\u00e9placement
dialog.confirmcutandmove.text=Cette trace contient des informations temporelles qui seront d\u00e9sordonn\u00e9es apr\u00e8s un d\u00e9placement.\n\u00cates-vous s\u00fbr de vouloir d\u00e9placer cette section ?
-dialog.interpolate.title=Interpoler les points
dialog.interpolate.parameter.text=Nombre de points \u00e0 ins\u00e9rer entre les points s\u00e9lectionn\u00e9s
dialog.undo.title=Annuler les actions
dialog.undo.pretext=S\u00e9lectionnez les actions \u00e0 annuler
dialog.pointnameedit.name=Nom de waypoint
dialog.pointnameedit.uppercase=CASSE MAJUSCULES
dialog.pointnameedit.lowercase=casse minuscules
-dialog.pointnameedit.sentencecase=Casse Phrase
+dialog.pointnameedit.titlecase=Casse Phrase
dialog.addtimeoffset.add=Retarder l'heure
dialog.addtimeoffset.subtract=Avancer l'heure
dialog.addtimeoffset.days=Jours
dialog.rearrangephotos.nosort=Ne pas trier
dialog.rearrangephotos.sortbyfilename=Trier par nom de fichier
dialog.rearrangephotos.sortbytime=Trier par horodatage
-dialog.compress.nonefound=Pas de donn\u00e9es \u00e0 effacer
dialog.compress.closepoints.title=Suppression des points voisins
dialog.compress.closepoints.paramdesc=Taille du voisinage
dialog.compress.wackypoints.title=Suppression des points anormaux
dialog.compress.douglaspeucker.title=Compression Douglas-Peucker
dialog.compress.douglaspeucker.paramdesc=Taille du voisinage
dialog.compress.summarylabel=Points \u00e0 supprimer
+dialog.deletemarked.nonefound=Pas de donn\u00e9es \u00e0 effacer
dialog.pastecoordinates.desc=Entrez ou collez les coordonn\u00e9es ici
dialog.pastecoordinates.coords=Coordonn\u00e9es
dialog.pastecoordinates.nothingfound=V\u00e9rifier les coordonn\u00e9es et essayez \u00e0 nouveau
dialog.saveconfig.prune.gpsdevice=Chemin du p\u00e9riph\u00e9rique GPS
dialog.saveconfig.prune.gpsformat=Format GPS
dialog.saveconfig.prune.povrayfont=Police povray
-dialog.saveconfig.prune.metricunits=Utiliser le syst\u00e8me m\u00e9trique ?
dialog.saveconfig.prune.gnuplotpath=Chemin gnuplot
dialog.saveconfig.prune.gpsbabelpath=Chemin gpsbabel
dialog.saveconfig.prune.exiftoolpath=Chemin exiftool
dialog.diskcache.dir=R\u00e9pertoire cache
dialog.diskcache.createdir=Cr\u00e9er r\u00e9pertoire
dialog.diskcache.nocreate=Le r\u00e9pertoire cache n'est pas cr\u00e9\u00e9
+dialog.diskcache.table.path=Chemin
+dialog.diskcache.table.usedby=Utilis\u00e9 par
+dialog.diskcache.table.zoom=Amplitude du zoom
+dialog.diskcache.table.tiles=Tuiles
+dialog.diskcache.table.megabytes=Megabytes
+dialog.diskcache.tileset.multiple=multiple
+dialog.diskcache.deleteold=Efface vieilles tuiles
+dialog.diskcache.deleteall=Efface toute les tuiles
+dialog.diskcache.deleted1=Effac\u00e9
+dialog.diskcache.deleted2=tuiles du cache
dialog.deletefieldvalues.intro=Choisir le champ \u00e0 effacer pour l'\u00e9tendue actuelle
dialog.setlinewidth.text=Entrer l'\u00e9paisseur des lignes des traces (1-4)
dialog.downloadosm.desc=Confirmer le t\u00e9l\u00e9chargement des donn\u00e9es OSM brutes pour la zone indiqu\u00e9e :
button.browse=Naviguer...
button.addnew=Ajouter nouveau...
button.delete=Supprimer
+button.manage=G\u00e9rer
# File types
filetype.txt=Fichiers TXT
display.range.time.hours=h
display.range.time.days=j
details.range.avespeed=Vitesse moyenne
-details.range.avemovingspeed=Moyenne continue
details.range.maxspeed=Vitesse maximum
details.range.numsegments=Nombre de segments
details.range.pace=Allure
details.photodetails=D\u00e9tails de la photo
details.nophoto=Pas de photo
details.photo.loading=Chargement
+details.photo.bearing=Direction
details.media.connected=Reli\u00e9e
details.audiodetails=D\u00e9tails de l'audio
details.noaudio=Pas de fichier audio s\u00e9lectionner
units.feet.short=p
units.kilometres=Kilom\u00e8tres
units.kilometres.short=km
-units.kmh=km/h
+units.kilometresperhour.short=km/h
units.miles=Miles
units.miles.short=mi
-units.mph=mi/h
-units.metrespersec=m/s
-units.feetpersec=ft/s
+units.milesperhour.short=mi/h
+units.metrespersec.short=m/s
+units.feetpersec.short=ft/s
units.hours=heures
units.degminsec=Deg-min-sec
units.degmin=Deg-min
undo.removephoto=retirer la photo
undo.removeaudio=retirer le fichier audio
undo.deleterange=effacer l'\u00e9tendue
-undo.compress=compresser la trace
+undo.deletemarked=effacer les points
undo.insert=ins\u00e9rer les points
undo.reverse=inverser l'\u00e9tendue
undo.mergetracksegments=fusionner les segments de trace
error.gpsies.uploadnotok=Le serveur de Gpsies \u00e0 renvoy\u00e9 le message
error.gpsies.uploadfailed=L'envoi a \u00e9chou\u00e9 avec l'erreur
error.playaudiofailed=\u00c9chec de la lecture du fichier audio
+error.cache.notthere=Le dossier du cache n'a pas \u00e9t\u00e9 trouv\u00e9
+error.cache.empty=Le dossier du cache est vide
+error.cache.cannotdelete=Ne peux pas effac\u00e9 les tuiles
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
+function.deleterange=Tartom\u00e1ny t\u00f6rl\u00e9se
+function.interpolate=Pontok interpol\u00e1l\u00e1sa
menu.range.average=Kijel\u00f6l\u00e9s \u00e1tlaga
menu.range.reverse=Tartom\u00e1ny megford\u00edt\u00e1sa
menu.range.mergetracksegments=Nyomvonalszakaszok egyes\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.pointnameedit.name=\u00datpont neve
dialog.pointnameedit.uppercase=NAGYBET\u0170S
dialog.pointnameedit.lowercase=kisbet\u0171s
-dialog.pointnameedit.sentencecase=Nagy Kezd\u0151bet\u0171s
+dialog.pointnameedit.titlecase=Nagy Kezd\u0151bet\u0171s
dialog.addtimeoffset.add=Id\u0151 hozz\u00e1ad\u00e1sa
dialog.addtimeoffset.subtract=Id\u0151 kivon\u00e1sa
dialog.addtimeoffset.days=Nap
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.deletemarked.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.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
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
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.milesperhour.short=mph
+units.metrespersec.short=m/s
+units.feetpersec.short=ft/s
units.hours=\u00f3ra
units.degminsec=Sz\u00f6g-sz\u00f6gperc-sz\u00f6gm\u00e1sodperc
units.degmin=Sz\u00f6g-sz\u00f6gperc
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.deletemarked=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
menu.track.undo=Batal
menu.point.editpoint=Perbaiki titik
menu.point.deletepoint=Hapus titik
-menu.range.deleterange=Hapus jarak
+function.deleterange=Hapus jarak
menu.range=Jangkauan
menu.point=Titik
menu.range.all=Pilih semua
# Text entries for the GpsPrune application
-# Italian entries thanks to josatoc and others
+# Italian entries thanks to josatoc, denisov
# Menu entries
menu.file=File
menu.track=Traccia
menu.track.undo=Annulla
menu.track.clearundo=Cancella lista annulla
+menu.track.markrectangle=Segnare i punti nel rettangolo
menu.track.deletemarked=Cancella punti marcati
menu.track.rearrange=Riorganizza waypoint
menu.track.rearrange.start=Tutti all'inizio del file
menu.range.none=Deseleziona tutto
menu.range.start=Imposta inizio serie
menu.range.end=Imposta fine serie
-menu.range.deleterange=Cancella la serie
-menu.range.interpolate=Interpola
menu.range.average=Crea punto medio della selezione
menu.range.reverse=Inverti la serie
menu.range.mergetracksegments=Unisci segmenti traccia
menu.map.autopan=Autopan
menu.map.showmap=Mostra sulla mappa
menu.map.showscalebar=Mostra scala
+menu.map.editmode=Modifica
# Alt keys for menus
altkey.menu.file=F
function.exportsvg=Esporta in SVG
function.editwaypointname=Modifica nome waypoint
function.compress=Comprimi la traccia
+function.deleterange=Cancella la serie
+function.croptrack=Cima la traccia
+function.interpolate=Interpola i punti
function.addtimeoffset=Aggiungi uno scarto temporale
function.addaltitudeoffset=Aggiungi uno scarto di altitudine
function.convertnamestotimes=Converti nomi dei waypoint in orari
dialog.deletepoint.deletephoto=Cancella la foto collegata a questo punto?
dialog.deletephoto.title=Cancella Foto
dialog.deletephoto.deletepoint=Cancella il punto collegato a questa foto?
+dialog.deleteaudio.deletepoint=Elimina il punto collegato a questo file audio?
dialog.openoptions.title=Apri opzioni
dialog.openoptions.filesnippet=Estrai dal file
dialog.load.table.field=Campo
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?
dialog.confirmcutandmove.title=Conferma il taglio e lo spostamento
dialog.confirmcutandmove.text=Questa traccia contiene informazioni sull'orario di scatto che possono essere messe fuori sequenza dopo lo spostamento\nSei sicuro di voler spostare questa sezione?
-dialog.interpolate.title=Interpola i punti
dialog.interpolate.parameter.text=Numero di punti da inserire tra i punti selezionati
+dialog.interpolate.betweenwaypoints=Interpolazione tra waypoint?
dialog.undo.title=Annulla l'azione(i)
dialog.undo.pretext=Per favore seleziona l'azione(i) da annullare
dialog.undo.none.title=Non \u00e8 possibile annullare
dialog.pointnameedit.name=Nome del waypoint
dialog.pointnameedit.uppercase=MAIUSCOLE
dialog.pointnameedit.lowercase=minuscole
-dialog.pointnameedit.sentencecase=Iniziali Maiuscole
+dialog.pointnameedit.titlecase=Iniziali Maiuscole
dialog.addtimeoffset.add=Scarto in aggiunta
dialog.addtimeoffset.subtract=Scarto in sottrazione
dialog.addtimeoffset.days=Giorni
dialog.distances.currentpoint=Punto attuale
dialog.distances.toofewpoints=Questa funzione necessita di waypoints per calcolare le distanze tra loro
dialog.fullrangedetails.intro=Qui i dettagli della selezione
+dialog.fullrangedetails.coltotal=Includere le lacune
+dialog.fullrangedetails.colsegments=Senza lacune
dialog.setmapbg.intro=Selezione una fonte delle mappe o aggiungine una nuova
dialog.addmapsource.title=Aggiungi nuova fonte delle mappa
dialog.addmapsource.sourcename=Nome della fonte
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.nouncorrelatedaudios=Non ci sono audio non correlati. \nSei sicuro di voler continuare?
dialog.correlate.photoselect.intro=Selezione una delle foto correlate da usare come scarto dell'orario
dialog.correlate.select.photoname=Nome della foto
dialog.correlate.select.timediff=Differenza di orario
dialog.rearrangephotos.nosort=Non mettere in ordine
dialog.rearrangephotos.sortbyfilename=Metti in ordine di nome del file
dialog.rearrangephotos.sortbytime=Metti in ordine di tempo
-dialog.compress.nonefound=Nessun punto rimosso
dialog.compress.closepoints.title=Cancella punti vicini
dialog.compress.closepoints.paramdesc=Fattore vicinanza
dialog.compress.wackypoints.title=Cancella punti strani
dialog.compress.singletons.paramdesc=Fattore distanza
dialog.compress.duplicates.title=Cancella duplicati
dialog.compress.douglaspeucker.title=Compressione con algoritmo Douglas-Peucker
+dialog.compress.douglaspeucker.paramdesc=Fattore di apertura
dialog.compress.summarylabel=Punti da cancellare
+dialog.compress.confirm1=
+dialog.compress.confirm2=punti sono stati contrassegnati.\nUsa traccia-> Elimina i punti segnati per eliminarle
+dialog.compress.confirmnone=I punti non sono stati marcati
+dialog.deletemarked.nonefound=Nessun punto rimosso
dialog.pastecoordinates.desc=Inserisci o incolla qui le coordinate
dialog.pastecoordinates.coords=Coordinate
dialog.pastecoordinates.nothingfound=Per favore, controlla le coordinate e riprova
dialog.saveconfig.prune.gpsdevice=Nome del Dispositivo GPS
dialog.saveconfig.prune.gpsformat=Formato GPS
dialog.saveconfig.prune.povrayfont=Font povray
-dialog.saveconfig.prune.metricunits=Utilizza unita' metrica?
dialog.saveconfig.prune.gnuplotpath=Path gnuplot
dialog.saveconfig.prune.gpsbabelpath=Path gpsbabel
dialog.saveconfig.prune.exiftoolpath=Path exiftool
dialog.diskcache.dir=Cartella della cache
dialog.diskcache.createdir=Crea cartella
dialog.diskcache.nocreate=Cartella della cache non creata
+dialog.diskcache.cannotwrite=Il titolo della mappa non pu\u00f2 essere salvato nella cartella selezionata
dialog.diskcache.table.path=Percorso (Path)
dialog.diskcache.table.usedby=Utilizzato da
dialog.diskcache.table.zoom=Zoom
confirm.rearrangewaypoints=Waypoint riorganizzati
confirm.rearrangephotos=Foto riorganizzate
confirm.cutandmove=Selezione spostata
+confirm.interpolate=Aggiungi punto
confirm.convertnamestotimes=Nome del waypoint convertito
confirm.saveexif.ok1=Salvato
confirm.saveexif.ok2=foto
display.range.time.hours=h
display.range.time.days=g
details.range.avespeed=Velocit\u00e0 media
-details.range.avemovingspeed=Velocit\u00e0 media in movimento
details.range.maxspeed=Velocit\u00e0 massima
details.range.numsegments=Numero di segmenti
details.range.pace=Passo
details.photo.loading=Caricamento
details.photo.bearing=Direzione
details.media.connected=Collegata
+details.media.fullpath=Percorso completo
details.audiodetails=Dettagli ripresa audio
details.noaudio=Nessuna ripresa audio selezionata
details.audio.file=Ripresa audio
units.feet.short=ft
units.kilometres=Kilometri
units.kilometres.short=km
-units.kmh=km/h
+units.kilometresperhour.short=km/h
units.miles=Miglia
units.miles.short=mi
-units.mph=mph
-units.metrespersec=m/s
-units.feetpersec=ft/s
+units.milesperhour.short=mph
+units.nauticalmiles=Miglia nautiche
+units.nauticalmiles.short=N.m
+units.nauticalmilesperhour.short=Miglia nautiche all'ora
+units.metrespersec.short=m/s
+units.feetpersec.short=ft/s
units.hours=Ore
units.degminsec=Deg-min-sec
units.degmin=Deg-min
undo.removephoto=rimuovi foto
undo.removeaudio=rimuovi riprese audio
undo.deleterange=cancella l'intervallo
-undo.compress=comprimi traccia
+undo.croptrack=taglia la traccia
+undo.deletemarked=
undo.insert=inserisci punti
undo.reverse=inverti l'intervallo
undo.mergetracksegments=unisci segmenti traccia
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.showphoto.failed=Caricamento foto fallito
error.playaudiofailed=Ripresa audio non riprodotta
error.cache.notthere=Directory del cache di tasselli non trovato
error.cache.empty=Directory del cache di tasselli \u00e8 vuoto
error.cache.cannotdelete=Impossibile cancellare tasselli
+error.interpolate.invalidparameter=Il numero di punti deve essere tra 1 e 1000
# Text entries for the GpsPrune application
-# Japanese entries as extra
+# Japanese entries
# Menu entries
-menu.file=\u30d5\u30a1\u30a4\u30eb
+menu.file=\u30d5\u30a1\u30a4\u30eb(F)
menu.file.addphotos=\u5199\u771f\u3092\u8ffd\u52a0
menu.file.save=\u4fdd\u5b58
menu.file.exit=\u7d42\u4e86
-menu.track=\u30c8\u30e9\u30c3\u30af
+menu.track=\u30c8\u30e9\u30c3\u30af(T)
menu.track.undo=\u30a2\u30f3\u30c9\u30a5
menu.track.clearundo=\u30a2\u30f3\u30c9\u30a5\u30ea\u30b9\u30c8\u3092\u7a7a\u306b\u3059\u308b
-menu.point.editpoint=\u70b9\u3092\u7de8\u96c6
-menu.point.deletepoint=\u70b9\u3092\u524a\u9664
-menu.range.deleterange=\u7bc4\u56f2\u3092\u524a\u9664
menu.track.deletemarked=\u5370\u306e\u4ed8\u3044\u305f\u70b9\u3092\u524a\u9664
-menu.range.interpolate=\u88dc\u5b8c
-menu.range.average=\u9078\u629e\u7bc4\u56f2\u3092\u5e73\u5747\u5316
-menu.range.reverse=\u7bc4\u56f2\u3092\u53cd\u8ee2
-menu.range.mergetracksegments=\u30c8\u30e9\u30c3\u30af\u30bb\u30b0\u30e1\u30f3\u30c8\u3092\u7d71\u5408
menu.track.rearrange=\u30a6\u30a7\u30a4\u30dd\u30a4\u30f3\u30c8\u3092\u4e26\u3079\u66ff\u3048
menu.track.rearrange.start=\u5168\u3066\u3092\u30d5\u30a1\u30a4\u30eb\u306e\u59cb\u70b9\u306b
menu.track.rearrange.end=\u5168\u3066\u3092\u30d5\u30a1\u30a4\u30eb\u306e\u7d42\u70b9\u306b
menu.track.rearrange.nearest=\u305d\u308c\u305e\u308c\u3092\u6700\u8fd1\u306e\u30c8\u30e9\u30c3\u30af\u30dd\u30a4\u30f3\u30c8\u306b
-menu.range.cutandmove=\u9078\u629e\u7bc4\u56f2\u3092\u79fb\u52d5
-menu.range=\u7bc4\u56f2
-menu.point=\u70b9
+menu.range=\u7bc4\u56f2(R)
menu.range.all=\u5168\u3066\u9078\u629e
menu.range.none=\u9078\u629e\u89e3\u9664
-menu.range.start=\u958b\u59cb\u70b9\u3092\u7f6e\u304f
-menu.range.end=\u7d42\u4e86\u70b9\u3092\u7f6e\u304f
+menu.range.start=\u958b\u59cb\u70b9\u3092\u8a2d\u5b9a
+menu.range.end=\u7d42\u4e86\u70b9\u3092\u8a2d\u5b9a
+menu.range.average=\u9078\u629e\u7bc4\u56f2\u3092\u5e73\u5747\u5316
+menu.range.reverse=\u7bc4\u56f2\u3092\u53cd\u8ee2
+menu.range.mergetracksegments=\u30c8\u30e9\u30c3\u30af\u30bb\u30b0\u30e1\u30f3\u30c8\u3092\u7d71\u5408
+menu.range.cutandmove=\u9078\u629e\u7bc4\u56f2\u3092\u79fb\u52d5
+menu.point=\u70b9(P)
+menu.point.editpoint=\u70b9\u3092\u7de8\u96c6
+menu.point.deletepoint=\u70b9\u3092\u524a\u9664
menu.photo=\u5199\u771f
menu.photo.saveexif=Exif\u306b\u4fdd\u5b58
-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.audio=\u30aa\u30fc\u30c7\u30a3\u30aa(A)
+menu.view=\u30d3\u30e5\u30fc(V)
+menu.view.showsidebars=\u30b5\u30a4\u30c9\u30d0\u30fc\u3092\u8868\u793a
menu.view.browser=\u5730\u56f3\u3092\u30d6\u30e9\u30a6\u30b6\u30fc\u3067\u898b\u308b
menu.view.browser.google=Google \u30de\u30c3\u30d7
menu.view.browser.openstreetmap=OpenStreetMap
menu.view.browser.mapquest=Mapquest
menu.view.browser.yahoo=Yahoo \u5730\u56f3
menu.view.browser.bing=Bing \u5730\u56f3
-menu.settings=\u8a2d\u5b9a
-menu.help=\u30d8\u30eb\u30d7
+menu.settings=\u8a2d\u5b9a(S)
+menu.settings.onlinemode=\u30a4\u30f3\u30bf\u30fc\u30cd\u30c3\u30c8\u304b\u3089\u5730\u56f3\u3092\u30ed\u30fc\u30c9
+menu.help=\u30d8\u30eb\u30d7(H)
# Popup menu for map
menu.map.zoomin=\u62e1\u5927
menu.map.zoomout=\u7e2e\u5c0f
menu.map.zoomfull=\u6700\u5927\u62e1\u5927
menu.map.newpoint=\u70b9\u3092\u4f5c\u308b
+menu.map.drawpoints=\u9023\u7d9a\u3057\u305f\u70b9\u3092\u4f5c\u308b
menu.map.connect=\u30c8\u30e9\u30c3\u30af\u30dd\u30a4\u30f3\u30c8\u306b\u63a5\u7d9a
menu.map.autopan=\u81ea\u52d5\u79fb\u52d5
menu.map.showmap=\u5730\u56f3\u3092\u8868\u793a
function.exportkml=KML\u306b\u30a8\u30af\u30b9\u30dd\u30fc\u30c8
function.exportgpx=GPX\u306b\u30a8\u30af\u30b9\u30dd\u30fc\u30c8
function.exportpov=POV\u306b\u30a8\u30af\u30b9\u30dd\u30fc\u30c8
+function.exportsvg=SVG\u306b\u30a8\u30af\u30b9\u30dd\u30fc\u30c8
function.editwaypointname=\u30a6\u30a7\u30a4\u30dd\u30a4\u30f3\u30c8\u306e\u540d\u524d\u3092\u7de8\u96c6
+function.deleterange=\u7bc4\u56f2\u3092\u524a\u9664
+function.interpolate=\u70b9\u3092\u88dc\u5b8c\u3059\u308b
function.compress=\u30c8\u30e9\u30c3\u30af\u3092\u5727\u7e2e
function.addtimeoffset=\u6642\u9593\u306e\u504f\u4f4d\u3092\u52a0\u3048\u308b
function.addaltitudeoffset=\u9ad8\u5ea6\u306b\u504f\u4f4d\u3092\u52a0\u3048\u308b
function.convertnamestotimes=\u30a6\u30a7\u30a4\u30dd\u30a4\u30f3\u30c8\u540d\u3092\u6642\u9593\u306b\u5909\u63db
+function.deletefieldvalues=\u30d5\u30a3\u30fc\u30eb\u30c9\u306e\u5024\u3092\u524a\u9664\u3059\u308b
function.findwaypoint=\u30a6\u30a7\u30a4\u30dd\u30a4\u30f3\u30c8\u3092\u63a2\u3059
function.pastecoordinates=\u65b0\u3057\u3044\u5ea7\u6a19\u3092\u5165\u529b
function.charts=\u9ad8\u5ea6\u901f\u5ea6\u30c1\u30e3\u30fc\u30c8
function.setkmzimagesize=KML \u30a4\u30e1\u30fc\u30b8\u30b5\u30a4\u30ba
function.setpaths=\u5916\u90e8\u30d7\u30ed\u30b0\u30e9\u30e0\u30d1\u30b9\u3092\u8a2d\u5b9a
function.getgpsies=Gpsies\u30c8\u30e9\u30c3\u30af\u3092\u5f97\u308b
+function.uploadgpsies=Gpsies\u306b\u30c8\u30e9\u30c3\u30af\u3092\u30a2\u30c3\u30d7\u30ed\u30fc\u30c9
+function.lookupsrtm=SRTM\u304b\u3089\u6a19\u9ad8\u3092\u53d6\u5f97\u3059\u308b
+function.getwikipedia=Wikipedia\u304b\u3089\u5468\u56f2\u306e\u8a18\u4e8b\u3092\u53d6\u5f97\u3059\u308b
+function.searchwikipedianames=\u540d\u524d\u3067Wikipedia\u3092\u691c\u7d22
+function.downloadosm=\u30a8\u30ea\u30a2\u306eOSM\u30c7\u30fc\u30bf\u3092\u30c0\u30a6\u30f3\u30ed\u30fc\u30c9
function.duplicatepoint=\u91cd\u8907\u70b9
function.setcolours=\u8272\u3092\u8a2d\u5b9a
+function.setlinewidth=\u884c\u306e\u5e45\u3092\u8a2d\u5b9a
function.setlanguage=\u8a00\u8a9e\u8a2d\u5b9a
+function.connecttopoint=\u70b9\u306b\u63a5\u7d9a
+function.disconnectfrompoint=\u70b9\u304b\u3089\u63a5\u7d9a\u89e3\u9664
+function.removephoto=\u5199\u771f\u3092\u53d6\u308a\u9664\u304f
function.correlatephotos=\u5199\u771f\u3068\u95a2\u9023\u3055\u305b\u308b
function.rearrangephotos=\u5199\u771f\u306e\u4e26\u3079\u76f4\u3057
function.rotatephotoleft=\u5199\u771f\u3092\u5de6\u306b\u56de\u3059
function.rotatephotoright=\u5199\u771f\u3092\u53f3\u306b\u56de\u3059
+function.photopopup=\u5199\u771f\u306e\u30dd\u30c3\u30d7\u30a2\u30c3\u30d7\u3092\u8868\u793a
function.ignoreexifthumb=EXIF\u30b5\u30e0\u30cd\u30a4\u30eb\u3092\u7121\u8996
+function.loadaudio=\u30aa\u30fc\u30c7\u30a3\u30aa\u30d5\u30a1\u30a4\u30eb\u3092\u8ffd\u52a0
+function.removeaudio=\u4e00\u89a7\u304b\u3089\u73fe\u5728\u306e\u30aa\u30fc\u30c7\u30a3\u30aa\u30d5\u30a1\u30a4\u30eb\u3092\u524a\u9664
+function.correlateaudios=\u30aa\u30fc\u30c7\u30a3\u30aa\u3092\u95a2\u9023\u4ed8\u3051\u308b
+function.playaudio=\u518d\u751f
+function.stopaudio=\u505c\u6b62
function.help=\u30d8\u30eb\u30d7
function.showkeys=\u30b7\u30e7\u30fc\u30c8\u30ab\u30c3\u30c8\u30ad\u30fc\u3092\u8868\u793a
function.about=GpsPrune \u306b\u3064\u3044\u3066
function.checkversion=\u65b0\u3057\u3044\u30d0\u30fc\u30b8\u30e7\u30f3\u3092\u8868\u793a
function.saveconfig=\u8a2d\u5b9a\u3092\u4fdd\u5b58
+function.diskcache=\u30c7\u30a3\u30b9\u30af\u306b\u30de\u30c3\u30d7\u3092\u4fdd\u5b58
# Dialogs
dialog.exit.confirm.title=GpsPrune \u3092\u7d42\u4e86
dialog.openoptions.deliminfo.fields=\u30d5\u30a3\u30fc\u30eb\u30c9
dialog.openoptions.deliminfo.norecords=\u8a18\u9332\u306a\u3057
dialog.openoptions.altitudeunits=\u9ad8\u5ea6\u5358\u4f4d
+dialog.selecttracks.noname=\u540d\u524d\u306a\u3057
dialog.jpegload.subdirectories=\u30b5\u30d6\u30c7\u30a3\u30ec\u30af\u30c8\u30ea\u30fc\u3092\u542b\u3081\u308b
dialog.jpegload.loadjpegswithoutcoords=\u5ea7\u6a19\u3092\u542b\u307e\u306a\u3044\u5199\u771f\u3092\u542b\u3081\u308b
dialog.jpegload.loadjpegsoutsidearea=\u73fe\u5728\u898b\u3066\u3044\u308b\u5730\u57df\u5916\u306e\u5199\u771f\u3092\u542b\u3081\u308b
dialog.pointtype.track=\u30c8\u30e9\u30c3\u30af\u30dd\u30a4\u30f3\u30c8
dialog.pointtype.waypoint=\u30a6\u30a7\u30a4\u30dd\u30a4\u30f3\u30c8
dialog.pointtype.photo=\u5199\u771f\u70b9
+dialog.pointtype.audio=\u30aa\u30fc\u30c7\u30a3\u30aa\u30dd\u30a4\u30f3\u30c8
dialog.pointtype.selection=\u9078\u629e\u7bc4\u56f2\u306e\u307f
dialog.confirmreversetrack.title=\u53cd\u8ee2\u306e\u78ba\u8a8d
dialog.confirmreversetrack.text=\u3053\u306e\u30c8\u30e9\u30c3\u30af\u306f\u30bf\u30a4\u30e0\u30b9\u30bf\u30f3\u30d7\u3092\u542b\u3093\u3067\u3044\u3066\u3001\u53cd\u8ee2\u3059\u308b\u3068\u306a\u304f\u306a\u308a\u307e\u3059\u3002\n\u672c\u5f53\u306b\u53cd\u8ee2\u3055\u305b\u307e\u3059\u304b\uff1f
dialog.confirmcutandmove.title=\u5207\u308a\u53d6\u308a\u3068\u79fb\u52d5\u306e\u78ba\u8a8d
dialog.confirmcutandmove.text=\u3053\u306e\u30c8\u30e9\u30c3\u30af\u306f\u30bf\u30a4\u30e0\u30b9\u30bf\u30f3\u30d7\u3092\u542b\u3093\u3067\u3044\u3066\u3001\u79fb\u52d5\u3059\u308b\u3068\u306a\u304f\u306a\u308a\u307e\u3059\u3002\n\u672c\u5f53\u306b\u53cd\u8ee2\u3055\u305b\u307e\u3059\u304b\uff1f
-dialog.interpolate.title=\u70b9\u3092\u88dc\u5b8c\u3059\u308b
dialog.interpolate.parameter.text=\u9078\u629e\u3057\u305f\u70b9\u306e\u9593\u306b\u633f\u5165\u3055\u308c\u308b\u70b9\u306e\u6570
dialog.undo.title=\u4f5c\u696d\u3092\u30a2\u30f3\u30c9\u30a5
dialog.undo.pretext=\u30a2\u30f3\u30c9\u30a5\u3059\u308b\u4f5c\u696d\u3092\u9078\u629e\u3057\u3066\u304f\u3060\u3055\u3044\u3002
dialog.pointnameedit.name=\u30a6\u30a7\u30a4\u30dd\u30a4\u30f3\u30c8\u540d
dialog.pointnameedit.uppercase=\u5927\u6587\u5b57
dialog.pointnameedit.lowercase=\u5c0f\u6587\u5b57
-dialog.pointnameedit.sentencecase=\u982d\u6587\u5b57\u306e\u307f\u5927\u6587\u5b57
+dialog.pointnameedit.titlecase=\u982d\u6587\u5b57\u306e\u307f\u5927\u6587\u5b57
dialog.addtimeoffset.add=\u6642\u9593\u3092\u8db3\u3059
dialog.addtimeoffset.subtract=\u6642\u9593\u3092\u5f15\u304f
dialog.addtimeoffset.days=\u65e5
dialog.distances.currentpoint=\u73fe\u5728\u306e\u70b9
dialog.distances.toofewpoints=\u3053\u306e\u6a5f\u80fd\u306f\u30a6\u30a7\u30a4\u30dd\u30a4\u30f3\u30c8\u9593\u306e\u8ddd\u96e2\u3092\u8a08\u7b97\u3059\u308b\u305f\u3081\u306b\u3001\u30a6\u30a7\u30a4\u30dd\u30a4\u30f3\u30c8\u304c\u5fc5\u8981\u3067\u3059\u3002
dialog.fullrangedetails.intro=\u9078\u629e\u7bc4\u56f2\u306b\u306f\u8a73\u7d30\u304c\u3042\u308a\u307e\u3059\u3002
-dialog.setmapbg.mapnik=Mapnik(\u521d\u671f\u5024)
-dialog.setmapbg.osma=Osma
-dialog.setmapbg.cyclemap=Cyclemap
-dialog.setmapbg.other=\u305d\u306e\u4ed6(URL\u306b\u5165\u529b)
-dialog.setmapbg.server=\u5730\u56f3\u30b5\u30fc\u30d0\u30fcURL
+dialog.addmapsource.title=\u65b0\u3057\u3044\u30de\u30c3\u30d7\u30fb\u30bd\u30fc\u30b9\u3092\u8ffd\u52a0
+dialog.addmapsource.sourcename=\u30bd\u30fc\u30b9\u306e\u540d\u524d
+dialog.addmapsource.maxzoom=\u6700\u5927\u30ba\u30fc\u30e0\u30ec\u30d9\u30eb
+dialog.addmapsource.cloudstyle=\u30b9\u30bf\u30a4\u30eb\u756a\u53f7
+dialog.addmapsource.noname=\u540d\u524d\u306a\u3057
dialog.gpsies.column.name=\u30c8\u30e9\u30c3\u30af\u540d
dialog.gpsies.column.length=\u9577\u3055
dialog.gpsies.description=\u8a18\u8ff0
dialog.gpsies.nodescription=\u8a18\u8ff0\u304c\u3042\u308a\u307e\u305b\u3093
dialog.gpsies.nonefound=\u30c8\u30e9\u30c3\u30af\u304c\u3042\u308a\u307e\u305b\u3093
+dialog.gpsies.username=Gpsies\u306e\u30e6\u30fc\u30b6\u30fc\u540d
+dialog.gpsies.password=Gpsies\u306e\u30d1\u30b9\u30ef\u30fc\u30c9
dialog.gpsies.activities=\u6d3b\u52d5\u306b\u9069\u3057\u3066
dialog.gpsies.activity.trekking=\u30cf\u30a4\u30ad\u30f3\u30b0
dialog.gpsies.activity.walking=\u30a6\u30a9\u30fc\u30ad\u30f3\u30b0
dialog.gpsies.activity.jogging=\u5b9f\u884c\u4e2d
dialog.gpsies.activity.biking=\u30b5\u30a4\u30af\u30ea\u30f3\u30b0
+dialog.gpsies.activity.motorbiking=\u30e2\u30fc\u30bf\u30fc\u30d0\u30a4\u30af
dialog.gpsies.activity.snowshoe=\u30b9\u30ce\u30fc\u30b7\u30e5\u30fc\u30a4\u30f3\u30b0
dialog.gpsies.activity.sailing=\u30bb\u30fc\u30ea\u30f3\u30b0
dialog.gpsies.activity.skating=\u30d5\u30a3\u30ae\u30e5\u30a2\u30b9\u30b1\u30fc\u30c8
+dialog.wikipedia.column.name=Wikipedia\u8a18\u4e8b\u540d
+dialog.wikipedia.column.distance=\u8ddd\u96e2
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.options.distancelimit=\u8ddd\u96e2\u5236\u9650
dialog.correlate.options.correlate=\u95a2\u9023\u4ed8\u3051
dialog.correlate.alloutsiderange=\u5168\u3066\u306e\u5199\u771f\u304c\u30c8\u30e9\u30c3\u30af\u306e\u7bc4\u56f2\u5916\u3067\u3059\u3002\u3060\u304b\u3089\u3001\u4f55\u3082\u95a2\u9023\u4ed8\u3051\u3089\u308c\u307e\u305b\u3093\u3067\u3057\u305f\u3002\n\u6642\u9593\u504f\u4f4d\u3092\u5909\u3048\u308b\u304b\u3001\u5c11\u306a\u304f\u3068\u3082\u4e00\u3064\u306e\u5199\u771f\u3092\u624b\u52d5\u95a2\u9023\u4ed8\u3051\u3092\u3059\u308b\u306a\u3069\u3057\u3066\u898b\u3066\u304f\u3060\u3055\u3044\u3002
+dialog.correlate.filetimes=\u30d5\u30a1\u30a4\u30eb\u306e\u30bf\u30a4\u30e0\u30b9\u30bf\u30f3\u30d7\u3092\u8868\u793a\uff1a
+dialog.correlate.filetimes2=\u30aa\u30fc\u30c7\u30a3\u30aa\u30af\u30ea\u30c3\u30d7\u306e
+dialog.correlate.timestamp.beginning=\u958b\u59cb
+dialog.correlate.timestamp.middle=\u4e2d\u9593\u70b9
+dialog.correlate.timestamp.end=\u7d42\u70b9
+dialog.correlate.select.audioname=\u30aa\u30fc\u30c7\u30a3\u30aa\u540d
dialog.rearrangephotos.desc=\u5411\u304b\u3046\u5148\u3092\u9078\u629e\u3057\u3066\u3001\u5199\u771f\u306e\u70b9\u3092\u4e26\u3079\u76f4\u3059\u3002
dialog.rearrangephotos.tostart=\u79fb\u52d5\u958b\u59cb
dialog.rearrangephotos.toend=\u79fb\u52d5\u7d42\u4e86
dialog.rearrangephotos.nosort=\u4e26\u3079\u66ff\u3048\u306a\u3044
dialog.rearrangephotos.sortbyfilename=\u30d5\u30a1\u30a4\u30eb\u540d\u3067\u4e26\u3079\u66ff\u3048
dialog.rearrangephotos.sortbytime=\u6642\u9593\u3067\u4e26\u3079\u66ff\u3048
-dialog.compress.nonefound=\u9664\u304f\u3053\u3068\u304c\u3067\u304d\u308b\u30c7\u30fc\u30bf\u30dd\u30a4\u30f3\u30c8\u304c\u3042\u308a\u307e\u305b\u3093\u3002
+dialog.deletemarked.nonefound=\u9664\u304f\u3053\u3068\u304c\u3067\u304d\u308b\u30c7\u30fc\u30bf\u30dd\u30a4\u30f3\u30c8\u304c\u3042\u308a\u307e\u305b\u3093\u3002
dialog.compress.closepoints.title=\u8fd1\u508d\u70b9\u3092\u524a\u9664
dialog.compress.closepoints.paramdesc=\u8fd1\u508d\u4fc2\u6570
dialog.compress.wackypoints.title=\u304a\u304b\u3057\u306a\u70b9\u306e\u524a\u9664
dialog.about.systeminfo.exiftool=Exiftool \u30a4\u30f3\u30b9\u30c8\u30fc\u30eb\u6e08
dialog.about.systeminfo.gpsbabel=Gpsbabel \u30a4\u30f3\u30b9\u30c8\u30fc\u30eb\u6e08
dialog.about.systeminfo.gnuplot=Gnuplot \u30a4\u30f3\u30b9\u30c8\u30fc\u30eb\u6e08
+dialog.about.systeminfo.exiflib=Exif\u30e9\u30a4\u30d6\u30e9\u30ea
dialog.about.yes=\u306f\u3044
dialog.about.no=\u3044\u3044\u3048
dialog.about.credits=\u30af\u30ec\u30b8\u30c3\u30c8
dialog.checkversion.download=\u65b0\u30d0\u30fc\u30b8\u30e7\u30f3\u3092\u30c0\u30a6\u30f3\u30ed\u30fc\u30c9\u3059\u308b\u306b\u306f\u3001 http://activityworkshop.net/software/gpsprune/download.html \u3078\u884c\u3063\u3066\u304f\u3060\u3055\u3044\u3002
dialog.keys.intro=\u30de\u30a6\u30b9\u306e\u4ee3\u308f\u308a\u306b\u6b21\u306e\u30b7\u30e7\u30fc\u30c8\u30ab\u30c3\u30c8\u30ad\u30fc\u3092\u4f7f\u3046\u4e8b\u304c\u3067\u304d\u307e\u3059\u3002
dialog.keys.keylist=<table><tr><td>\u77e2\u5370\u30ad\u30fc</td><td>\u5730\u56f3\u3092\u4e0a\u4e0b\u5de6\u53f3\u306b\u79fb\u52d5</td></tr><tr><td>Ctrl + \u5de6\u30fb\u53f3\u77e2\u5370</td><td>\u524d\u30fb\u6b21\u306e\u70b9\u3092\u9078\u629e</td></tr><tr><td>Ctrl + \u4e0a\u30fb\u4e0b\u77e2\u5370</td><td>\u62e1\u5927\u30fb\u7e2e\u5c0f</td></tr><tr><td>Del</td><td>\u73fe\u5728\u306e\u70b9\u3092\u524a\u9664</td></tr></table>
+dialog.keys.normalmodifier=Ctrl\u30ad\u30fc
+dialog.keys.macmodifier=Command\u30ad\u30fc
dialog.saveconfig.desc=\u4e0b\u8a18\u306e\u8a2d\u5b9a\u304c\u8a2d\u5b9a\u30d5\u30a1\u30a4\u30eb\u306b\u4fdd\u5b58\u3055\u308c\u307e\u3059
dialog.saveconfig.prune.trackdirectory=\u30c8\u30e9\u30c3\u30af\u30c7\u30a3\u30ec\u30af\u30c8\u30ea
dialog.saveconfig.prune.photodirectory=\u5199\u771f\u30c7\u30a3\u30ec\u30af\u30c8\u30ea
dialog.saveconfig.prune.gpsdevice=GPS\u30c7\u30d0\u30a4\u30b9
dialog.saveconfig.prune.gpsformat=GPS\u30d5\u30a9\u30fc\u30de\u30c3\u30c8
dialog.saveconfig.prune.povrayfont=Povray \u30d5\u30a9\u30f3\u30c8
-dialog.saveconfig.prune.metricunits=\u30e1\u30fc\u30c8\u30eb\u6cd5\u3092\u4f7f\u3046\uff1f
dialog.saveconfig.prune.gnuplotpath=gnuplot\u3078\u306e\u30d1\u30b9
dialog.saveconfig.prune.gpsbabelpath=gpsbabel\u3078\u306e\u30d1\u30b9
dialog.saveconfig.prune.exiftoolpath=exiftool\u3078\u306e\u30d1\u30b9
-dialog.saveconfig.prune.mapserverindex=\u80cc\u666f\u5730\u56f3\u30b5\u30fc\u30d0\u30fc\u306e\u7d22\u5f15(1-4)
-dialog.saveconfig.prune.mapserverurl=\u5730\u56f3\u30b5\u30fc\u30d0\u30fc\u306eURL
+dialog.saveconfig.prune.mapsource=\u30de\u30c3\u30d7\u30fb\u30bd\u30fc\u30b9\u3092\u9078\u629e
+dialog.saveconfig.prune.mapsourcelist=\u30de\u30c3\u30d7\u30fb\u30bd\u30fc\u30b9
+dialog.saveconfig.prune.diskcache=\u30de\u30c3\u30d7\u306e\u30ad\u30e3\u30c3\u30b7\u30e5
dialog.saveconfig.prune.kmzimagewidth=KML \u753b\u50cf\u5e45
dialog.saveconfig.prune.kmzimageheight=KML \u753b\u50cf\u9ad8
dialog.saveconfig.prune.colourscheme=\u8272\u306e\u30b9\u30ad\u30fc\u30e0
+dialog.saveconfig.prune.linewidth=\u7dda\u306e\u5e45
dialog.saveconfig.prune.kmltrackcolour=KML \u30c8\u30e9\u30c3\u30af\u306e\u8272
dialog.setpaths.intro=\u5fc5\u8981\u306a\u3089\u3001\u5916\u90e8\u30a2\u30d7\u30ea\u30b1\u30fc\u30b7\u30e7\u30f3\u306e\u30d1\u30b9\u3092\u9078\u3076\u4e8b\u304c\u3067\u304d\u307e\u3059
dialog.addaltitude.noaltitudes=\u9078\u629e\u7bc4\u56f2\u306f\u3001\u9ad8\u5ea6\u3092\u542b\u3093\u3067\u307e\u305b\u3093\u3002
dialog.setlanguage.languagefile=\u8a00\u8a9e\u30d5\u30a1\u30a4\u30eb
dialog.setlanguage.endmessage=\u8a2d\u5b9a\u3092\u4fdd\u5b58\u3057\u3001\u8a00\u8a9e\u306e\u5909\u66f4\u3092\u6709\u52b9\u306b\u3059\u308b\u305f\u3081\u306b\nGpsPrune \u3092\u518d\u8d77\u52d5\u3057\u3066\u304f\u3060\u3055\u3044\u3002
+dialog.diskcache.save=\u30c7\u30a3\u30b9\u30af\u306b\u30a4\u30e1\u30fc\u30b8\u3092\u4fdd\u5b58
+dialog.diskcache.dir=\u30ad\u30e3\u30c3\u30b7\u30e5\u30c7\u30a3\u30ec\u30af\u30c8\u30ea
+dialog.diskcache.createdir=\u30c7\u30a3\u30ec\u30af\u30c8\u30ea\u3092\u4f5c\u6210
+dialog.diskcache.nocreate=\u30ad\u30e3\u30c3\u30b7\u30e5\u30c7\u30a3\u30ec\u30af\u30c8\u30ea\u304c\u4f5c\u6210\u3055\u308c\u306a\u304b\u3063\u305f\u3002
+dialog.setlinewidth.text=\u30c8\u30e9\u30c3\u30af\u63cf\u753b\u306e\u7dda\u5e45\u30921-4\u306e\u7bc4\u56f2\u3067\u5165\u529b
+dialog.searchwikipedianames.search=\u53f3\u8a18\u3092\u691c\u7d22:
+
# 3d window
dialog.3d.title=GpsPrune 3D \u8868\u793a
dialog.3dlines.title=GpsPrune \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
-# Confirm messages || These are displayed as confirmation in the status bar
+# Confirm messages
confirm.loadfile=\u30d5\u30a1\u30a4\u30eb\u304b\u3089\u30c7\u30fc\u30bf\u3092\u8aad\u307f\u8fbc\u3080
confirm.save.ok1=\u4fdd\u5b58\u6210\u529f
confirm.save.ok2=\u30d5\u30a1\u30a4\u30eb\u304b\u3089\u70b9
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.disconnect=\u5199\u771f\u304c\u63a5\u7d9a\u3055\u308c\u305f
+confirm.media.connect=\u30e1\u30c7\u30a3\u30a2\u304c\u63a5\u7d9a\u3055\u308c\u305f
+confirm.photo.disconnect=\u5199\u771f\u304c\u5207\u65ad\u3055\u308c\u305f
+confirm.audio.disconnect=\u30aa\u30fc\u30c7\u30a3\u30aa\u304c\u5207\u65ad\u3055\u308c\u305f
+confirm.media.removed=\u524a\u9664\u3055\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...
+confirm.lookupsrtm1=
+confirm.lookupsrtm2=\u6a19\u9ad8\u5024
+confirm.deletefieldvalues=\u30d5\u30a3\u30fc\u30eb\u30c9\u306e\u5024\u304c\u524a\u9664\u3055\u308c\u305f
+confirm.audioload=\u30aa\u30fc\u30c7\u30a3\u30aa\u30d5\u30a1\u30a4\u30eb\u304c\u8ffd\u52a0\u3055\u308c\u305f
+confirm.correlateaudios.single=\u30aa\u30fc\u30c7\u30a3\u30aa\u304c\u95a2\u9023\u4ed8\u3051\u3089\u308c\u305f
+confirm.correlateaudios.multi=\u8907\u6570\u306e\u30aa\u30fc\u30c7\u30a3\u30aa\u304c\u95a2\u9023\u4ed8\u3051\u3089\u308c\u305f
-# Buttons || These are all the texts for buttons
+# Buttons
button.ok=\u6c7a\u5b9a
button.back=\u623b\u308b
button.next=\u6b21
button.selectnone=\u9078\u629e\u89e3\u9664
button.preview=\u30d7\u30ec\u30d3\u30e5\u30fc
button.load=\u8aad\u307f\u8fbc\u307f
+button.upload=\u30a2\u30c3\u30d7\u30ed\u30fc\u30c9
button.guessfields=\u30d5\u30a3\u30fc\u30eb\u30c9\u4e88\u6e2c
button.showwebpage=\u30a6\u30a7\u30d6\u30da\u30fc\u30b8\u3092\u8868\u793a
button.check=\u691c\u67fb
button.resettodefaults=\u521d\u671f\u5024\u306b\u623b\u3059
button.browse=\u95b2\u89a7...
+button.addnew=\u65b0\u3057\u304f\u8ffd\u52a0
+button.delete=\u524a\u9664
# File types
filetype.txt=TXT\u30d5\u30a1\u30a4\u30eb
filetype.gpx=GPX\u30d5\u30a1\u30a4\u30eb
filetype.pov=POV\u30d5\u30a1\u30a4\u30eb
filetype.svg=SVG\u30d5\u30a1\u30a4\u30eb
+filetype.audio=MP3,OGG,WAV\u30d5\u30a1\u30a4\u30eb
-# Display components || These are all for the side panels showing point/range details
+# Display components
display.nodata=\u8aad\u307f\u8fbc\u307e\u308c\u305f\u30c7\u30fc\u30bf\u306a\u3057
display.noaltitudes=\u30c8\u30e9\u30c3\u30af\u30c7\u30fc\u30bf\u306f\u9ad8\u5ea6\u3092\u542b\u307f\u307e\u305b\u3093
+display.notimestamps=\u30c8\u30e9\u30c3\u30af\u30c7\u30fc\u30bf\u306f\u30bf\u30a4\u30e0\u30b9\u30bf\u30f3\u30d7\u3092\u542b\u3093\u3067\u3044\u307e\u305b\u3093
details.trackdetails=\u30c8\u30e9\u30c3\u30af\u8a73\u7d30
details.notrack=\u8aad\u307f\u8fbc\u307e\u308c\u305f\u30c8\u30e9\u30c3\u30af\u306a\u3057
details.track.points=\u70b9
display.range.time.hours=\u6642
display.range.time.days=\u65e5
details.range.avespeed=\u5e73\u5747\u901f\u5ea6
-details.range.avemovingspeed=\u5e73\u5747\u79fb\u52d5
+details.range.maxspeed=\u6700\u9ad8\u901f\u5ea6
details.range.numsegments=\u30bb\u30b0\u30e1\u30f3\u30c8\u6570
details.range.pace=\u30da\u30fc\u30b9
details.range.gradient=\u52fe\u914d
details.lists.waypoints=\u30a6\u30a7\u30a4\u30dd\u30a4\u30f3\u30c8
details.lists.photos=\u5199\u771f
+details.lists.audio=\u30aa\u30fc\u30c7\u30a3\u30aa
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.media.connected=\u63a5\u7d9a\u6e08
+details.audiodetails=\u30aa\u30fc\u30c7\u30a3\u30aa\u306e\u8a73\u7d30
+details.noaudio=\u30aa\u30fc\u30c7\u30a3\u30aa\u30d5\u30a1\u30a4\u30eb\u304c\u672a\u9078\u629e
+details.audio.file=\u30aa\u30fc\u30c7\u30a3\u30aa\u30d5\u30a1\u30a4\u30eb
+details.audio.playing=\u518d\u751f...
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
units.feet.short=ft
units.kilometres=\u30ad\u30ed\u30e1\u30fc\u30c8\u30eb
units.kilometres.short=km
-units.kmh=km/h
+units.kilometresperhour.short=km/h
units.miles=\u30de\u30a4\u30eb
units.miles.short=mi
-units.mph=mph
-units.metrespersec=m/s
-units.feetpersec=ft/s
+units.milesperhour.short=mph
+units.metrespersec.short=m/s
+units.feetpersec.short=ft/s
units.hours=\u6642\u9593
units.degminsec=\u5ea6-\u5206-\u79d2
units.degmin=\u5ea6-\u5206
cardinal.e=E
cardinal.w=W
-# Undo operations || These will be displayed in the undo list after you've performed the operation, to tell you what you did
+# Undo operations
undo.load=\u30c7\u30fc\u30bf\u3092\u8aad\u307f\u8fbc\u307f
undo.loadphotos=\u5199\u771f\u306e\u8aad\u307f\u8fbc\u307f
+undo.loadaudios=\u30aa\u30fc\u30c7\u30a3\u30aa\u30d5\u30a1\u30a4\u30eb\u306e\u8aad\u307f\u8fbc\u307f
undo.editpoint=\u70b9\u306e\u7de8\u96c6
undo.deletepoint=\u70b9\u306e\u524a\u9664
-undo.removephoto=\u5199\u771f\u306e\u53d6\u308a\u9664\u304d
+undo.removephoto=\u5199\u771f\u306e\u524a\u9664
+undo.removeaudio=\u30aa\u30fc\u30c7\u30a3\u30aa\u306e\u524a\u9664
undo.deleterange=\u7bc4\u56f2\u306e\u524a\u9664
-undo.compress=\u30c8\u30e9\u30c3\u30af\u306e\u5727\u7e2e
+undo.deletemarked=\u30c8\u30e9\u30c3\u30af\u306e\u5727\u7e2e
undo.insert=\u70b9\u306e\u633f\u5165
undo.reverse=\u7bc4\u56f2\u306e\u53cd\u8ee2
undo.mergetracksegments=\u30c8\u30e9\u30c3\u30af\u30bb\u30b0\u30e1\u30f3\u30c8\u306e\u7d71\u5408
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.connect=\u5199\u771f\u306e\u63a5\u7d9a
-undo.disconnect=\u5199\u771f\u306e\u63a5\u7d9a\u89e3\u9664
+undo.connect=\u63a5\u7d9a
+undo.disconnect=\u5207\u65ad
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
undo.convertnamestotimes=\u540d\u524d\u3092\u6642\u9593\u306b\u5909\u63db\u3059\u308b
+undo.lookupsrtm=SRTM\u304b\u3089\u6a19\u9ad8\u3092\u691c\u7d22
+undo.deletefieldvalues=\u30d5\u30a3\u30fc\u30eb\u30c9\u306e\u5024\u3092\u524a\u9664
+undo.correlateaudios=\u30aa\u30fc\u30c7\u30a3\u30aa\u3092\u95a2\u9023\u4ed8\u3051
# Error messages
error.save.dialogtitle=\u30c7\u30fc\u30bf\u4fdd\u5b58\u306e\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.nogpsfound=GPS\u60c5\u5831\u304c\u898b\u3064\u304b\u308a\u307e\u305b\u3093
+error.audioload.nofilesfound=\u30aa\u30fc\u30c7\u30a3\u30aa\u30d5\u30a1\u30a4\u30eb\u304c\u672a\u9078\u629e
error.gpsload.unknown=\u4e0d\u660e\u306a\u30a8\u30e9\u30fc
error.undofailed.title=\u30a2\u30f3\u30c9\u30a5\u5931\u6557
error.undofailed.text=\u30a2\u30f3\u30c9\u30a5\u64cd\u4f5c\u306e\u5931\u6557
error.osmimage.failed=\u5730\u56f3\u753b\u50cf\u3092\u8aad\u307f\u8fbc\u307f\u306b\u5931\u6557\u3057\u307e\u3057\u305f\u3002\u30a4\u30f3\u30bf\u30fc\u30cd\u30c3\u30c8\u63a5\u7d9a\u3092\u78ba\u8a8d\u3057\u3066\u304f\u3060\u3055\u3044\u3002
error.language.wrongfile=\u9078\u629e\u3055\u308c\u305f\u30d5\u30a1\u30a4\u30eb\u306fGpsPrune \u7528\u306e\u8a00\u8a9e\u30d5\u30a1\u30a4\u30eb\u306b\u898b\u3048\u307e\u305b\u3093\u3002
error.convertnamestotimes.nonames=\u3069\u306e\u540d\u524d\u3082\u6642\u9593\u306b\u5909\u63db\u3067\u304d\u307e\u305b\u3093\u3067\u3057\u305f\u3002
+error.lookupsrtm.nonefound=\u3069\u306e\u6a19\u9ad8\u5024\u3082\u3053\u308c\u3089\u306e\u30dd\u30a4\u30f3\u30c8\u304b\u3089\u53d6\u5f97\u3055\u308c\u307e\u305b\u3093\u3067\u3057\u305f\u3002
+error.lookupsrtm.nonerequired=\u5168\u3066\u306e\u30dd\u30a4\u30f3\u30c8\u306f\u6a19\u9ad8\u5024\u3092\u6301\u3063\u3066\u3044\u308b\u305f\u3081\u3001\u691c\u7d22\u3055\u308c\u307e\u305b\u3093\u3067\u3057\u305f\u3002
+error.gpsies.uploadnotok=Gpsies\u30b5\u30fc\u30d0\u30fc\u304c\u30e1\u30c3\u30bb\u30fc\u30b8\u3092\u8fd4\u3057\u307e\u3057\u305f\u3002
+error.gpsies.uploadfailed=\u30a8\u30e9\u30fc\u306e\u305f\u3081\u30a2\u30c3\u30d7\u30ed\u30fc\u30c9\u306b\u5931\u6557\u3057\u307e\u3057\u305f
+error.playaudiofailed=\u30aa\u30fc\u30c7\u30a3\u30aa\u30d5\u30a1\u30a4\u30eb\u306e\u518d\u751f\u306b\u5931\u6557\u3057\u307e\u3057\u305f\u3002
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
+function.deleterange=\uc5f0\uacb0\uc120 \uc0ad\uc81c
+function.interpolate=\uc0bd\uc785\ud55c \uc9c0\uc810
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
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.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.pointnameedit.titlecase=\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.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.deletemarked.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.saveconfig.prune.gpsdevice=GPS\uc7a5\uce58
dialog.saveconfig.prune.gpsformat=GPS \ud615\uc2dd
dialog.saveconfig.prune.povrayfont=Povray \uae00\uaf34
-dialog.saveconfig.prune.metricunits=\ubbf8\ud130\ubc95 \ub2e8\uc704\ub97c \uc0ac\uc6a9\ud558\uc2dc\ub098\uc694?
dialog.saveconfig.prune.gnuplotpath=gnjuplot \uacbd\ub85c
dialog.saveconfig.prune.gpsbabelpath=gpsbabel \uacbd\ub85c
dialog.saveconfig.prune.exiftoolpath=exiftool \uacbd\ub85c
display.range.time.hours=\uc2dc\uac04
display.range.time.days=\uc77c
details.range.avespeed=\ud3c9\uade0 \uc18d\ub3c4
-details.range.avemovingspeed=\ud3c9\uade0 \uc774\ub3d9
details.range.maxspeed=\ucd5c\uace0 \uc18d\ub3c4
details.range.numsegments=\ubd80\ubd84\ub4e4\uc758 \uc218
details.range.pace=\ud398\uc774\uc2a4(1km\ub098 1mile\uc774\ub3d9 \uc2dc\uac04)
units.feet.short=\ud53c\ud2b8
units.kilometres=\ud0ac\ub85c\ubbf8\ud130
units.kilometres.short=\ud0ac\ub85c\ubbf8\ud130
-units.kmh=\ud0ac\ub85c\ubbf8\ud130-\uc2dc\uc18d
+units.kilometresperhour.short=\ud0ac\ub85c\ubbf8\ud130-\uc2dc\uc18d
units.miles=\ub9c8\uc77c
units.miles.short=\ub9c8\uc77c
-units.mph=\ub9c8\uc77c-\uc2dc\uc18d
-units.metrespersec=m/s
-units.feetpersec=ft/s
+units.milesperhour.short=\ub9c8\uc77c-\uc2dc\uc18d
+units.metrespersec.short=m/s
+units.feetpersec.short=ft/s
units.hours=\uc2dc\uac04
units.degminsec=\ub3c4-\ubd84-\ucd08
units.degmin=\ub3c4-\ubd84
undo.removephoto=\uc0ac\uc9c4 \uc81c\uac70
undo.removeaudio=\uc18c\ub9ac\ud30c\uc77c \uc81c\uac70
undo.deleterange=\ubc94\uc704 \uc0ad\uc81c
-undo.compress=\ud2b8\ub799 \uc555\ucd95
+undo.deletemarked=\ud2b8\ub799 \uc555\ucd95
undo.insert=\uc9c0\uc810\ub4e4 \uc0bd\uc785
undo.reverse=\ubc94\uc704 \ubc18\uc804
undo.mergetracksegments=\ud2b8\ub799 \ubd80\ubd84 \ubcd1\ud569
menu.track=Route
menu.track.undo=Ongedaan maken
menu.track.clearundo=Ongedaan-maken lijst wissen
+menu.track.markrectangle=Makeer alle punten in een vierkant
menu.track.deletemarked=Verwijderen gemarkeerde punten
menu.track.rearrange=Rangschikken waypoints
menu.track.rearrange.start=Alles naar begin route
menu.range.none=Selecteer geen
menu.range.start=Start van reeks
menu.range.end=Einde van reeks
-menu.range.deleterange=Verwijder reeks
-menu.range.interpolate=Interpoleren
menu.range.average=Cre\u00eber punt obv gemiddelde van reeks
menu.range.reverse=Reeks omkeren
menu.range.mergetracksegments=Samenvoegen route segmenten
menu.map.autopan=Autopan
menu.map.showmap=Toon kaart
menu.map.showscalebar=Toon schaal
+menu.map.editmode=Wijzigen
# Alt keys for menus
altkey.menu.file=F
function.exportsvg=Export SVG
function.editwaypointname=Hernoem waypoint
function.compress=Route comprimeren
+function.deleterange=Verwijder reeks
+function.croptrack=Route bijknippen
+function.interpolate=Interpoleer punten
function.addtimeoffset=Tijdsverschil toevoegen
function.addaltitudeoffset=Hoogteverschil toevoegen
function.convertnamestotimes=Converteer waypointnamen naar tijden
dialog.deletepoint.deletephoto=Wilt u de foto die aan dit punt is gekoppeld verwijderen?
dialog.deletephoto.title=Verwijder foto
dialog.deletephoto.deletepoint=Wilt u het punt dat aan deze foto is gekoppeld verwijderen?
+dialog.deleteaudio.deletepoint=Wilt u het punt dat aan dit geluidsbestand is gekoppeld verwijderen?
dialog.openoptions.title=Instellingen openen
dialog.openoptions.filesnippet=Samenvatting van bestand
dialog.load.table.field=Veld
dialog.confirmreversetrack.text=Deze route bevat tijd-informatie die niet meer klopt na een omkering.\nWeet u zeker dat u deze sectie wilt omkeren?
dialog.confirmcutandmove.title=Bevestig knip en verplaats
dialog.confirmcutandmove.text=Deze route bevat tijd-informatie die niet meer klopt na een verplaatsing.\nWeet u zeker dat u de sectie wilt verplaatsen?
-dialog.interpolate.title=Interpoleer punten
dialog.interpolate.parameter.text=Aantal punten om in te voegen tussen de geselecteerde punten
+dialog.interpolate.betweenwaypoints=Interpoleren tussen waypoints?
dialog.undo.title=Actie(s) ongedaan maken
dialog.undo.pretext=Selecteer de acties die u ongedaan wilt maken.
dialog.undo.none.title=Kan niet ongedaan gemaakt worden.
dialog.pointnameedit.name=Naam van het waypoint
dialog.pointnameedit.uppercase=HOOFDLETTERS
dialog.pointnameedit.lowercase=kleine letters
-dialog.pointnameedit.sentencecase=Ieder woord begint met hoofdletter
+dialog.pointnameedit.titlecase=Ieder woord begint met hoofdletter
dialog.addtimeoffset.add=Tijd toevoegen
dialog.addtimeoffset.subtract=Tijd aftrekken
dialog.addtimeoffset.days=Dagen
dialog.distances.currentpoint=Huidige punt
dialog.distances.toofewpoints=Deze functie heeft waypoints nodig om de afstand ertussen te berekenen
dialog.fullrangedetails.intro=Dit zijn de details van de geselecteerde reeks
+dialog.fullrangedetails.coltotal=Inclusief hiaten
+dialog.fullrangedetails.colsegments=Zonder hiaten
dialog.setmapbg.intro=Selecteer een kaart-bron, of voeg een nieuwe bron toe.
dialog.addmapsource.title=Nieuwe kaart-bron toevoegen
dialog.addmapsource.sourcename=Naam van de bron
dialog.wikipedia.column.distance=Afstand
dialog.correlate.notimestamps=Er zit geen tijdinformatie in de punten, dus kunnen ze niet aan foto's gekoppeld worden.
dialog.correlate.nouncorrelatedphotos=Er zijn geen ongekoppelde foto's.\nWeet u zeker dat u wilt doorgaan?
+dialog.correlate.nouncorrelatedaudios=Er zijn geen ongekoppelde geluidsbestanden.\nWeet u zeker dat u wilt doorgaan?
dialog.correlate.photoselect.intro=Selecteer \u00e9\u00e9n van deze gekoppelde foto's om het tijdsverschil te gebruiken
dialog.correlate.select.photoname=Fotonaam
dialog.correlate.select.timediff=Tijdsverschil
dialog.rearrangephotos.nosort=Niet sorteren
dialog.rearrangephotos.sortbyfilename=Sorteren op bestandsnaam
dialog.rearrangephotos.sortbytime=Sorteren op tijd
-dialog.compress.nonefound=Er konden geen punten verwijderd worden
dialog.compress.closepoints.title=Verwijder nabijliggende punten
dialog.compress.closepoints.paramdesc=Bereik
dialog.compress.wackypoints.title=Vreemde punten verwijderen
dialog.compress.douglaspeucker.title=Douglas-Peucker compressie
dialog.compress.douglaspeucker.paramdesc=Span factor
dialog.compress.summarylabel=Te verwijderen punten
+dialog.compress.confirm1=Er zijn
+dialog.compress.confirm2=punten zijn gemarkeerd.\nGebruik Track - Verwijder gemarkeerde punten om ze te verwijderen
+dialog.compress.confirmnone=er zijn geen punten gemarkeerd
+dialog.deletemarked.nonefound=Er konden geen punten verwijderd worden
dialog.pastecoordinates.desc=Geef co\u00f6rdinaten in
dialog.pastecoordinates.coords=Co\u00f6rdinaten
dialog.pastecoordinates.nothingfound=Controleer de co\u00f6rdinaten en probeer het nogmaals
dialog.saveconfig.prune.gpsdevice=GPS apparaat
dialog.saveconfig.prune.gpsformat=GPS formaat
dialog.saveconfig.prune.povrayfont=Povray lettertype
-dialog.saveconfig.prune.metricunits=Metrisch systeem gebruiken?
dialog.saveconfig.prune.gnuplotpath=Pad naar gnuplot
dialog.saveconfig.prune.gpsbabelpath=Pad naar gpsbabel
dialog.saveconfig.prune.exiftoolpath=Pad naar exiftool
dialog.diskcache.dir=Cache map
dialog.diskcache.createdir=Cre\u00eber map
dialog.diskcache.nocreate=Cache map niet aangemaakt
+dialog.diskcache.cannotwrite=Kaarttegels kunnen niet in de geselecteerde map worden opgeslagen
dialog.diskcache.table.path=Pad
dialog.diskcache.table.usedby=Gebruikt door
dialog.diskcache.table.zoom=Zoom
dialog.diskcache.deleted1=
dialog.diskcache.deleted2=bestanden uit de cache verwijderd
dialog.deletefieldvalues.intro=Selecteer het te verwijderen veld voor de huidige reeks
+dialog.deletefieldvalues.nofields=Er zijn geen velden in deze reeks om te verwijderen
dialog.setlinewidth.text=Geef lijndikte voor routes (1-4)
dialog.downloadosm.desc=Bevestig het downloaden van ruwe OSM data voor dit gebied:
dialog.searchwikipedianames.search=Zoeken naar:
confirm.rearrangewaypoints=Waypoints herschikt
confirm.rearrangephotos=Foto herschikt
confirm.cutandmove=Selectie verplaatst
+confirm.interpolate=Punten toegevoegd
confirm.convertnamestotimes=Namen waypoint geconverteerd
confirm.saveexif.ok1=Opgeslagen
confirm.saveexif.ok2=foto bestanden
display.range.time.hours=u
display.range.time.days=d
details.range.avespeed=Gem snelheid
-details.range.avemovingspeed=Gem snelheid in beweging
details.range.maxspeed=Max snelheid
details.range.numsegments=Aantal segmenten
details.range.pace=Tempo
details.photo.loading=Bezig met laden
details.photo.bearing=Richting
details.media.connected=Geconnecteerd
+details.media.fullpath=Volledig pad
details.audiodetails=Audio details
details.noaudio=Geen audiobestand geselecteerd
details.audio.file=Audiobestand
units.feet.short=ft
units.kilometres=Kilometers
units.kilometres.short=km
-units.kmh=km/u
+units.kilometresperhour.short=km/u
units.miles=Mijlen
units.miles.short=mi
-units.mph=mph
-units.metrespersec=m/s
-units.feetpersec=ft/s
+units.milesperhour.short=mph
+units.nauticalmiles=Nautische mijlen
+units.nauticalmiles.short=N.m.
+units.nauticalmilesperhour.short=Kn
+units.metrespersec.short=m/s
+units.feetpersec.short=ft/s
units.hours=uren
units.degminsec=Grd-min-sec
units.degmin=Grd-min
undo.removephoto=verwijderen foto
undo.removeaudio=verwijderen audiobestand
undo.deleterange=verwijderen reeks
-undo.compress=comprimeren route
+undo.croptrack=bijknippen track
+undo.deletemarked=verwijderen punten
undo.insert=punten invoegen
undo.reverse=reeks omkeren
undo.mergetracksegments=samenvoegen route segmenten
undo.addtimeoffset=tijdsverschil toevoegen
undo.addaltitudeoffset=hoogteverschil toevoegen
undo.rearrangewaypoints=herschikken waypoint
-undo.cutandmove=Verschuif sectie
+undo.cutandmove=verschuif sectie
undo.connect=koppel
undo.disconnect=loskoppelen
undo.correlatephotos=correleer foto
error.function.noop.title=Functie had geen effect
error.rearrange.noop=Herschikken van punten had geen effect
error.function.notavailable.title=Functie niet beschikbaar
-error.function.nojava3d=Deze functie heeft Java3d nodig,verkrijgbaar bij sun.com.
+error.function.nojava3d=Deze functie heeft Java3d nodig,\nverkrijgbaar bij sun.com.
error.3d=Er is een fout opgetreden bij de 3d afbeelding
error.readme.notfound=Leesmij bestand niet gevonden
error.osmimage.dialogtitle=Fout bij inlezen kaart afbeeldingen
error.lookupsrtm.nonerequired=Alle punten hebben reeds hoogte, er hoeft niets te worden opgezocht.
error.gpsies.uploadnotok=Gpsies server antwoordde met
error.gpsies.uploadfailed=De upload is mislukt. Fout
+error.showphoto.failed=Foto laden mislukt
error.playaudiofailed=Kon audiobestand niet afspelen
error.cache.notthere=De tegelcache map niet gevonden
error.cache.empty=De tegelcache map is leeg
error.cache.cannotdelete=Er konden geen tegels verwijderd worden
+error.interpolate.invalidparameter=Aantal punten moet tussen 1 en 1000 liggen
menu.track=\u015acie\u017cka
menu.track.undo=Cofnij
menu.track.clearundo=Wyczy\u015b\u0107 list\u0119 zmian
+menu.track.markrectangle=Zaznaczenie prostok\u0105tne
menu.track.deletemarked=Usu\u0144 zaznaczone punkty
menu.track.rearrange=Zmie\u0144 kolejno\u015b\u0107 punkt\u00f3w po\u015brednich
menu.track.rearrange.start=Wszystkie na pocz\u0105tek \u015bcie\u017cki
menu.range.none=Usu\u0144 zaznaczenie
menu.range.start=Zaznacz pocz\u0105tek zakresu
menu.range.end=Zaznacz koniec zakresu
-menu.range.deleterange=Usu\u0144 zakres
-menu.range.interpolate=Wstaw pomi\u0119dzy
menu.range.average=U\u015brednij zaznaczenie
menu.range.reverse=Odwr\u00f3\u0107 zakres
menu.range.mergetracksegments=Po\u0142\u0105cz fragmenty \u015bcie\u017cek
menu.map.autopan=Przesuwanie mapy
menu.map.showmap=Poka\u017c map\u0119
menu.map.showscalebar=Poka\u017c skal\u0119
+menu.map.editmode=Tryb edycji
# Alt keys for menus
altkey.menu.file=P
function.exportsvg=Eksportuj jako SVG
function.editwaypointname=Zmie\u0144 nazw\u0119 punktu po\u015bredniego
function.compress=Kompresuj \u015bcie\u017ck\u0119
+function.deleterange=Usu\u0144 zakres
+function.croptrack=Przytnij \u015bcie\u017ck\u0119
+function.interpolate=Wstaw pomi\u0119dzy punkty
function.addtimeoffset=Dodaj przesuni\u0119cie czasu
function.addaltitudeoffset=Dodaj przesuni\u0119cie wysoko\u015bci
function.convertnamestotimes=Zamie\u0144 nazwy punkt\u00f3w na czas
dialog.deletepoint.deletephoto=Usun\u0105\u0107 zdj\u0119cie do\u0142\u0105czone do tego punktu?
dialog.deletephoto.title=Usu\u0144 zdj\u0119cie
dialog.deletephoto.deletepoint=Usun\u0105\u0107 punkt do\u0142\u0105czony do tego zdj\u0119cia?
+dialog.deleteaudio.deletepoint=Usun\u0105\u0107 punkt do\u0142\u0105czony do tego pliku audio?
dialog.openoptions.title=Otw\u00f3rz opcje
dialog.openoptions.filesnippet=Fragment z pliku
dialog.load.table.field=Pole
dialog.confirmreversetrack.text=Ta \u015bcie\u017cka zawiera znaczniki czasu, kt\u00f3re po odwr\u00f3ceniu nie b\u0119d\u0105 ustawione w kolejno\u015bci.\nCzy na pewno chcesz odwr\u00f3ci\u0107 ten fragment?
dialog.confirmcutandmove.title=Potwierd\u017a wytnij i przesu\u0144
dialog.confirmcutandmove.text=Ta \u015bcie\u017cka zawiera znaczniki czasu, kt\u00f3re po przesuni\u0119ciu nie b\u0119d\u0105 ustawione w kolejno\u015bci.\nCzy na pewno chcesz przesun\u0105\u0107 ten fragment?
-dialog.interpolate.title=Interpoluj punkty
dialog.interpolate.parameter.text=Ilo\u015b\u0107 punkt\u00f3w do wstawienia pomi\u0119dzy wybrane punkty
+dialog.interpolate.betweenwaypoints=Wstawi\u0107 pomi\u0119dzy punkty po\u015brednie?
dialog.undo.title=Potwierd\u017a akcje
dialog.undo.pretext=Wybierz akcje kt\u00f3re chcesz cofn\u0105\u0107
dialog.undo.none.title=Nie mo\u017cna cofn\u0105\u0107
dialog.pointnameedit.name=Nazwa punktu po\u015bredniego
dialog.pointnameedit.uppercase=WIELKIE litery
dialog.pointnameedit.lowercase=ma\u0142e litery
-dialog.pointnameedit.sentencecase=Jak W Zdaniu
+dialog.pointnameedit.titlecase=Jak W Zdaniu
dialog.addtimeoffset.add=Dodaj czas
dialog.addtimeoffset.subtract=Odejmij czas
dialog.addtimeoffset.days=Dni
dialog.distances.currentpoint=Wybrany punkt
dialog.distances.toofewpoints=Ta funkcja wymaga przynajmniej dw\u00f3ch punkt\u00f3w po\u015brednich, aby mo\u017cna by\u0142o obliczy\u0107 odleg\u0142o\u015bci
dialog.fullrangedetails.intro=Szczeg\u00f3\u0142y wybranego zakresu
+dialog.fullrangedetails.coltotal=Z lukami
+dialog.fullrangedetails.colsegments=Bez luk
dialog.setmapbg.intro=Wybierz dostawc\u0119 map t\u0142a lub dodaj nowego
dialog.addmapsource.title=Dodaj dostawc\u0119 map
dialog.addmapsource.sourcename=Nazwa dostawcy
dialog.wikipedia.column.distance=Odleg\u0142o\u015b\u0107
dialog.correlate.notimestamps=Punkty nie maj\u0105 znacznik\u00f3w czasu, nie mo\u017cna ich powi\u0105za\u0107 ze zdj\u0119ciami.
dialog.correlate.nouncorrelatedphotos=Nie ma nie powi\u0105zanych zdj\u0119\u0107.\nCzy na pewno chcesz kontynuowa\u0107?
+dialog.correlate.nouncorrelatedaudios=Nie ma nie powi\u0105zanych plik\u00f3w audio.\nCzy na pewno chcesz kontynuowa\u0107?
dialog.correlate.photoselect.intro=Wybierz jedno z powi\u0105zanych zdj\u0119\u0107 i u\u017cyj go jako wzorca do przesuni\u0119cia czasu
dialog.correlate.select.photoname=Nazwa zdj\u0119cia
dialog.correlate.select.timediff=R\u00f3\u017cnica czasowa
dialog.rearrangephotos.nosort=Nie sortuj
dialog.rearrangephotos.sortbyfilename=Sortuj po nazwie pliku
dialog.rearrangephotos.sortbytime=Sortuj wed\u0142ug czasu
-dialog.compress.nonefound=Nie mo\u017cna usun\u0105\u0107 \u017cadnych punkt\u00f3w
dialog.compress.closepoints.title=Usuwanie bliskich sobie punkt\u00f3w
dialog.compress.closepoints.paramdesc=Wsp\u00f3\u0142czynnik rozpi\u0119to\u015bci
dialog.compress.wackypoints.title=Usuwanie dziwacznych punkt\u00f3w
dialog.compress.douglaspeucker.title=kompresja Douglasa-Peuckera
dialog.compress.douglaspeucker.paramdesc=wsp\u00f3\u0142czynnik rozpi\u0119to\u015bci (szeroko\u015bci korytarza)
dialog.compress.summarylabel=Punkty do usuni\u0119cia
+dialog.compress.confirm1=
+dialog.compress.confirm2=punkt\u00f3w zosta\u0142o zaznaczonych\nU\u017cyj \u015acie\u017cka->Usu\u0144 zaznaczone punkty, by je usun\u0105\u0107
+dialog.compress.confirmnone=\u017cadne punkty nie zosta\u0142y zaznaczone
+dialog.deletemarked.nonefound=Nie mo\u017cna usun\u0105\u0107 \u017cadnych punkt\u00f3w
dialog.pastecoordinates.desc=Wprowad\u017a lub wklej wsp\u00f3\u0142rz\u0119dne
dialog.pastecoordinates.coords=Wsp\u00f3\u0142rz\u0119dne
dialog.pastecoordinates.nothingfound=Sprawd\u017a wsp\u00f3\u0142rz\u0119dne i spr\u00f3buj jeszcze raz
dialog.saveconfig.prune.gpsdevice=Urz\u0105dzenie GPS
dialog.saveconfig.prune.gpsformat=Format pliku GPS
dialog.saveconfig.prune.povrayfont=czcionka dla Povray-a
-dialog.saveconfig.prune.metricunits=U\u017cywaj jednostek metrycznych?
dialog.saveconfig.prune.gnuplotpath=\u015bcie\u017cka do gnuplot
dialog.saveconfig.prune.gpsbabelpath=\u015bcie\u017cka do gpsbabel
dialog.saveconfig.prune.exiftoolpath=\u015bcie\u017cka do exiftool
dialog.diskcache.dir=katalog pami\u0119ci podr\u0119cznej
dialog.diskcache.createdir=stw\u00f3rz katalog
dialog.diskcache.nocreate=Nie utworzono katalogu pami\u0119ci podr\u0119cznej
+dialog.diskcache.cannotwrite=W wybranym katalogu nie mo\u017cna zapisa\u0107 map
dialog.diskcache.table.path=\u015acie\u017cka
dialog.diskcache.table.usedby=u\u017cywane przez
dialog.diskcache.table.zoom=Powi\u0119kszenie
confirm.rearrangewaypoints=Przestawiono punkty po\u015brednie
confirm.rearrangephotos=Zmieniono kolejno\u015b\u0107 zdj\u0119\u0107
confirm.cutandmove=Przesuni\u0119to zaznaczenie
+confirm.interpolate=Dodano punkty
confirm.convertnamestotimes=Zmieniono nazwy punkt\u00f3w po\u015brednich
confirm.saveexif.ok1=Zapisano
confirm.saveexif.ok2=plik(\u00f3w) zdj\u0119\u0107
confirm.lookupsrtm1=Znaleziono
confirm.lookupsrtm2=warto\u015bci wysoko\u015bci
confirm.deletefieldvalues=Warto\u015bci p\u00f3l usuni\u0119to
-confirm.audioload=dodano
+confirm.audioload=dodano pliki audio
confirm.correlateaudios.single=audio zosta\u0142o po\u0142\u0105czone
confirm.correlateaudios.multi=audio zosta\u0142y po\u0142\u0105czone
display.range.time.hours=h
display.range.time.days=d
details.range.avespeed=\u015arednia pr\u0119dko\u015b\u0107
-details.range.avemovingspeed=\u015arednie przesuni\u0119cie
details.range.maxspeed=Pr\u0119dko\u015b\u0107 maksymalna
details.range.numsegments=Liczba segment\u00f3w
details.range.pace=Tempo
details.photo.loading=Wczytywanie
details.photo.bearing=Kierunek
details.media.connected=Pod\u0142\u0105czony
+details.media.fullpath=Pe\u0142na \u015bcie\u017cka
details.audiodetails=Szczeg\u00f3\u0142y audio
details.noaudio=Brak zaznaczonego audio
details.audio.file=Plik audio
units.feet.short=ft
units.kilometres=Kilometry
units.kilometres.short=km
-units.kmh=km/h
+units.kilometresperhour.short=km/h
units.miles=Mile
units.miles.short=mi
-units.mph=mi/h
-units.metrespersec=m/s
-units.feetpersec=ft/s
+units.milesperhour.short=mi/h
+units.nauticalmiles=Mile morskie
+units.nauticalmiles.short=Mm
+units.nauticalmilesperhour.short=w.
+units.metrespersec.short=m/s
+units.feetpersec.short=ft/s
units.hours=Godziny
units.degminsec=Sto-min-sek
units.degmin=Sto-min
undo.removephoto=usu\u0144 zdj\u0119cie (nie z dysku)
undo.removeaudio=usu\u0144 audio
undo.deleterange=usu\u0144 zakres
-undo.compress=skompresuj \u015bcie\u017ck\u0119
+undo.croptrack=przytnij \u015bcie\u017ck\u0119
+undo.deletemarked=usu\u0144 punkty
undo.insert=wstaw punkty
undo.reverse=odwr\u00f3\u0107 zakres
undo.mergetracksegments=po\u0142\u0105cz fragmenty \u015bcie\u017cki
error.lookupsrtm.nonerequired=Wszystkie pola maj\u0105 informacj\u0119 o wysoko\u015bci, nie ma czego szuka\u0107
error.gpsies.uploadnotok=Serwer Gpsies zwr\u00f3ci\u0142 informacj\u0119
error.gpsies.uploadfailed=B\u0142\u0105d wysy\u0142ania
+error.showphoto.failed=Nie powiod\u0142o si\u0119 za\u0142adowanie zdj\u0119cia
error.playaudiofailed=Nie powiod\u0142o si\u0119 odtwarzanie pliku audio
error.cache.notthere=Nie znaleziono katalogu kesza
error.cache.empty=Katalog kesza jest pusty
error.cache.cannotdelete=\u017badne p\u0142ytki nie mog\u0142y zosta\u0107 usuni\u0119te
+error.interpolate.invalidparameter=Ilo\u015b\u0107 punkt\u00f3w musi zawiera\u0107 si\u0119 w zakresie od 1 do 1000
menu.range.none=N\u00e3o selecionar nenhuns
menu.range.start=Definir in\u00edcio do intervalo
menu.range.end=Definir fim do intervalo
-menu.range.deleterange=Remover intervalo
-menu.range.interpolate=Interpolar
+function.deleterange=Remover intervalo
+function.interpolate=Interpolar pontos
menu.range.average=Sele\u00e7\u00e3o m\u00e9dia
menu.range.reverse=Reverter intervalo
menu.range.mergetracksegments=Mesclar trechos da rota
dialog.confirmreversetrack.text=Esta rota possui informa\u00e7\u00f5es de data-hora, as quais estar\u00e3o fora de sequ\u00eancia ap\u00f3s a revers\u00e3o.\n Voc\u00ea tem certeza que deseja reverter esta se\u00e7\u00e3o?
dialog.confirmcutandmove.title=Confirmar cortar e mover
dialog.confirmcutandmove.text=A rota cont\u00e9m informa\u00e7\u00f5es de data-hora, as quais estar\u00e3o fora de sequ\u00eancia ap\u00f3s o movimento.\n Voc\u00ea tem certeza que deseja mover esta se\u00e7\u00e3o?
-dialog.interpolate.title=Interpolar pontos
dialog.interpolate.parameter.text=N\u00famero de pontos para inserir entre os pontos selecionados
dialog.undo.title=A\u00e7\u00e3o(\u00f5es) de desfazer
dialog.undo.pretext=Por favor, selecione a a\u00e7\u00e3o(\u00f5es) a desfazer
dialog.pointnameedit.name=Nome do ponto
dialog.pointnameedit.uppercase=MAI\u00daSCULAS
dialog.pointnameedit.lowercase=min\u00fasculas
-dialog.pointnameedit.sentencecase=Frase
+dialog.pointnameedit.titlecase=Frase
dialog.addtimeoffset.add=Adicionar tempo
dialog.addtimeoffset.subtract=Subtrair tempo
dialog.addtimeoffset.days=Dias
dialog.rearrangephotos.nosort=N\u00e3o ordenar
dialog.rearrangephotos.sortbyfilename=Ordenar pelo nome do arquivo
dialog.rearrangephotos.sortbytime=Ordenar pela hora
-dialog.compress.nonefound=Nenhum dado dos pontos pode ser removido
+dialog.deletemarked.nonefound=Nenhum dado dos pontos pode ser removido
dialog.compress.closepoints.title=Remo\u00e7\u00e3o de ponto pr\u00f3ximo
dialog.compress.closepoints.paramdesc=Fator de deslocamento
dialog.compress.wackypoints.title=Remo\u00e7\u00e3o de ponto exc\u00eantrica
dialog.saveconfig.prune.gpsdevice=Dispositivo de GPS
dialog.saveconfig.prune.gpsformat=Formato do GPS
dialog.saveconfig.prune.povrayfont=Fonte Povray
-dialog.saveconfig.prune.metricunits=Usar unidades m\u00e9tricas?
dialog.saveconfig.prune.gnuplotpath=Caminho para o gnuplot
dialog.saveconfig.prune.gpsbabelpath=Caminho para o gpsbabel
dialog.saveconfig.prune.exiftoolpath=Caminho para o exiftool
display.range.time.hours=h
display.range.time.days=d
details.range.avespeed=Velocidade m\u00e9dia
-details.range.avemovingspeed=Movimento m\u00e9dio
details.range.maxspeed=Velocidade m\u00e1xima
details.range.numsegments=N\u00famero de segmentos
details.range.pace=Passo
units.feet.short=ft
units.kilometres=Quil\u00f4metros
units.kilometres.short=km
-units.kmh=km/h
+units.kilometresperhour.short=km/h
units.miles=Milhas
units.miles.short=mi
-units.mph=mph
-units.metrespersec=m/s
-units.feetpersec=ft/s
+units.milesperhour.short=mph
+units.metrespersec.short=m/s
+units.feetpersec.short=ft/s
units.hours=horas
units.degminsec=Graus-min-seg
units.degmin=Graus-min
undo.removephoto=remover foto
undo.removeaudio=remover arquivo de \u00e1udio
undo.deleterange=remover intervalo
-undo.compress=comprimir rota
+undo.deletemarked=remover pontos
undo.insert=inserir pontos
undo.reverse=inverter intervalo
undo.mergetracksegments=mesclar segmentos de rota
# Text entries for the GpsPrune application
-# Romanian entries
+# Romanian entries as extra
# Menu entries
menu.file=Fi\u015fier
menu.track=Traseu
menu.track.undo=Anulare
menu.track.clearundo=\u015etergere lista de anulari
-menu.point.editpoint=Editare punct
-menu.point.deletepoint=\u015etergere punct
-menu.range.deleterange=\u015etergere gama
menu.track.deletemarked=\u015etergere puncte marcate
-menu.range.interpolate=Interpolare
-menu.range.average=Mediere selectie
-menu.range.reverse=Inversare selectie
-menu.range.mergetracksegments=Unire segmente traseu
menu.track.rearrange=Rearanjare waypoint
menu.track.rearrange.start=Toate la inceputul fisierului
menu.track.rearrange.end=Toate la sfarsitul fisierului
menu.track.rearrange.nearest=Fiecare la punctul cel mai apropiat al traseului
-menu.range.cutandmove=Taiere si mutare selectie
-menu.point=Punct
menu.range.all=Selectare toate
menu.range.none=Nu selecta niciun punct
menu.range.start=Seteaza inceputul selectiei
menu.range.end=Seteaza sfarsitul selectiei
+menu.range.average=Mediere selectie
+menu.range.reverse=Inversare selectie
+menu.range.mergetracksegments=Unire segmente traseu
+menu.range.cutandmove=Taiere si mutare selectie
+menu.point=Punct
+menu.point.editpoint=Editare punct
+menu.point.deletepoint=\u015etergere punct
menu.photo=Foto
menu.photo.saveexif=Salveaza la Exif
-function.connecttopoint=Conecteaza la punct
-function.disconnectfrompoint=Deconecteaza de la punct
-function.removephoto=Elimina foto
menu.view=Vizualizare
menu.view.browser=Harta in browser
menu.view.browser.google=Harti Google
menu.view.browser.openstreetmap=Openstreetmap
menu.view.browser.mapquest=Mapquest
menu.view.browser.yahoo=Harti Yahoo
-menu.view.browser.bing=Harti Bing
menu.help=Ajutor
# Popup menu for map
menu.map.zoomin=Apropie
function.exportsvg=Export\u0103 \u00eentr-un fi\u015fier SVG
function.editwaypointname=Editare nume waypoint
function.compress=Comprima traseu
+function.deleterange=\u015etergere gama
+function.interpolate=Interpolare
+function.findwaypoint=Gasire waypoint
function.charts=Grafice
function.show3d=Vizualizare arborescenta
function.distances=Distan\u0163e
function.correlatephotos=Corelare fotografii
function.setcolours=Selectare culorile
function.setlanguage=Selectare limba
+function.connecttopoint=Conecteaza la punct
+function.disconnectfrompoint=Deconecteaza de la punct
+function.removephoto=Elimina foto
function.help=Ajutor
function.showkeys=Arat\u0103 tastele scurt\u0103turi
function.about=Despre GpsPrune
menu.range.none=\u041e\u0442\u043c\u0435\u043d\u0438\u0442\u044c \u0432\u044b\u0431\u043e\u0440\u043a\u0443
menu.range.start=\u041d\u0430\u0447\u0430\u043b\u043e \u0438\u043d\u0442\u0435\u0440\u0432\u0430\u043b\u0430
menu.range.end=\u041a\u043e\u043d\u0435\u0446 \u0438\u043d\u0442\u0435\u0440\u0432\u0430\u043b\u0430
-menu.range.deleterange=\u0423\u0434\u0430\u043b\u0438\u0442\u044c \u0438\u043d\u0442\u0435\u0440\u0432\u0430\u043b
-menu.range.interpolate=\u0422\u043e\u0447\u043a\u0430 \u043f\u043e \u0438\u043d\u0442\u0435\u0440\u043f\u043e\u043b\u044f\u0446\u0438\u0438
+function.deleterange=\u0423\u0434\u0430\u043b\u0438\u0442\u044c \u0438\u043d\u0442\u0435\u0440\u0432\u0430\u043b
+function.interpolate=\u0418\u043d\u0442\u0435\u0440\u043f\u043e\u043b\u044f\u0446\u0438\u044f \u0442\u043e\u0447\u0435\u043a
menu.range.average=\u0422\u043e\u0447\u043a\u0430 \u043f\u043e \u0441\u0440\u0435\u0434\u043d\u0435\u043c\u0443
menu.range.reverse=\u041f\u0435\u0440\u0435\u0432\u0435\u0440\u043d\u0443\u0442\u044c \u0438\u043d\u0442\u0435\u0440\u0432\u0430\u043b
menu.range.mergetracksegments=\u0421\u043b\u0438\u0442\u044c \u0441\u0435\u0433\u043c\u0435\u043d\u0442\u044b \u0442\u0440\u0435\u043a\u0430
dialog.confirmreversetrack.text=\u042d\u0442\u043e\u0442 \u0442\u0440\u0435\u043a \u0441\u043e\u0434\u0435\u0440\u0436\u0438\u0442 \u043e\u0442\u043c\u0435\u0442\u043a\u0438 \u0432\u0440\u0435\u043c\u0435\u043d\u0438, \u043f\u043e\u0441\u043b\u0435\u0434\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u043d\u043e\u0441\u0442\u044c \u043a\u043e\u0442\u043e\u0440\u044b\u0445 \u0431\u0443\u0434\u0435\u0442 \u043d\u0430\u0440\u0443\u0448\u0435\u043d\u0430 \u043f\u043e\u0441\u043b\u0435 \u0440\u0430\u0437\u0432\u043e\u0440\u043e\u0442\u0430.\n\u0412\u044b \u0443\u0432\u0435\u0440\u0435\u043d\u044b, \u0447\u0442\u043e \u0445\u043e\u0442\u0438\u0442\u0435 \u0440\u0430\u0437\u0432\u0435\u0440\u043d\u0443\u0442\u044c \u0432\u044b\u0431\u0440\u0430\u043d\u043d\u043e\u0435?
dialog.confirmcutandmove.title=\u041f\u043e\u0434\u0442\u0432\u0435\u0440\u0434\u0438\u0442\u0435 "\u0432\u044b\u0440\u0435\u0437\u0430\u0442\u044c \u0438 \u043f\u0435\u0440\u0435\u043d\u0435\u0441\u0442\u0438"
dialog.confirmcutandmove.text=\u042d\u0442\u043e\u0442 \u0442\u0440\u0435\u043a \u0441\u043e\u0434\u0435\u0440\u0436\u0438\u0442 \u043e\u0442\u043c\u0435\u0442\u043a\u0438 \u0432\u0440\u0435\u043c\u0435\u043d\u0438, \u043f\u043e\u0441\u043b\u0435\u0434\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u043d\u043e\u0441\u0442\u044c \u043a\u043e\u0442\u043e\u0440\u044b\u0445 \u0431\u0443\u0434\u0435\u0442 \u043d\u0430\u0440\u0443\u0448\u0435\u043d\u0430 \u043f\u043e\u0441\u043b\u0435 \u043f\u0435\u0440\u0435\u043c\u0435\u0449\u0435\u043d\u0438\u044f.\n\u0412\u044b \u0443\u0432\u0435\u0440\u0435\u043d\u044b, \u0447\u0442\u043e \u0445\u043e\u0442\u0438\u0442\u0435 \u043f\u0435\u0440\u0435\u043c\u0435\u0449\u0430\u0442\u044c \u0432\u044b\u0431\u0440\u0430\u043d\u043d\u043e\u0435?
-dialog.interpolate.title=\u0418\u043d\u0442\u0435\u0440\u043f\u043e\u043b\u044f\u0446\u0438\u044f \u0442\u043e\u0447\u0435\u043a
dialog.interpolate.parameter.text=\u041a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u043e \u0442\u043e\u0447\u0435\u043a \u0434\u043b\u044f \u0432\u0441\u0442\u0430\u0432\u043a\u0438 \u043c\u0435\u0436\u0434\u0443 \u0432\u044b\u0431\u0440\u0430\u043d\u043d\u044b\u043c\u0438
dialog.undo.title=\u041e\u0442\u043c\u0435\u043d\u0438\u0442\u044c \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0435(\u044f)
dialog.undo.pretext=\u041f\u043e\u0436\u0430\u043b\u0443\u0439\u0441\u0442\u0430, \u0432\u044b\u0431\u0435\u0440\u0438\u0442\u0435 \u043e\u0442\u043c\u0435\u043d\u044f\u0435\u043c\u043e\u0435 \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0435(\u044f)
dialog.pointnameedit.name=\u0418\u043c\u044f \u043f\u0443\u0442\u0435\u0432\u043e\u0439 \u0442\u043e\u0447\u043a\u0438
dialog.pointnameedit.uppercase=\u0412\u0435\u0440\u0445\u043d\u0438\u0439 \u0440\u0435\u0433\u0438\u0441\u0442\u0440
dialog.pointnameedit.lowercase=\u043d\u0438\u0436\u043d\u0438\u0439 \u0440\u0435\u0433\u0438\u0441\u0442\u0440
-dialog.pointnameedit.sentencecase=\u041a\u0430\u0436\u0434\u043e\u0435 \u0421\u043b\u043e\u0432\u043e \u0441 \u0417\u0430\u0433\u043b\u0430\u0432\u043d\u043e\u0439
+dialog.pointnameedit.titlecase=\u041a\u0430\u0436\u0434\u043e\u0435 \u0421\u043b\u043e\u0432\u043e \u0441 \u0417\u0430\u0433\u043b\u0430\u0432\u043d\u043e\u0439
dialog.addtimeoffset.add=\u0414\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u0432\u0440\u0435\u043c\u044f \u043f\u043e\u0441\u043b\u0435
dialog.addtimeoffset.subtract=\u0414\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u0432\u0440\u0435\u043c\u044f \u0434\u043e
dialog.addtimeoffset.days=\u0414\u043d\u0438
dialog.rearrangephotos.nosort=\u041d\u0435 \u0441\u043e\u0440\u0442\u0438\u0440\u043e\u0432\u0430\u0442\u044c
dialog.rearrangephotos.sortbyfilename=\u0421\u043e\u0440\u0442\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u043f\u043e \u0438\u043c\u0435\u043d\u0438 \u0444\u0430\u0439\u043b\u0430
dialog.rearrangephotos.sortbytime=\u0421\u043e\u0440\u0442\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u043f\u043e \u0432\u0440\u0435\u043c\u0435\u043d\u0438
-dialog.compress.nonefound=\u041d\u0435\u0442 \u0442\u043e\u0447\u0435\u043a, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043c\u043e\u0433\u043b\u0438 \u0431\u044b \u0431\u044b\u0442\u044c \u0443\u0434\u0430\u043b\u0435\u043d\u044b
+dialog.deletemarked.nonefound=\u041d\u0435\u0442 \u0442\u043e\u0447\u0435\u043a, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043c\u043e\u0433\u043b\u0438 \u0431\u044b \u0431\u044b\u0442\u044c \u0443\u0434\u0430\u043b\u0435\u043d\u044b
dialog.compress.closepoints.title=\u0423\u0434\u0430\u043b\u0435\u043d\u0438\u0435 \u0441\u0431\u043b\u0438\u0436\u0435\u043d\u043d\u044b\u0445 \u0442\u043e\u0447\u0435\u043a
dialog.compress.closepoints.paramdesc=\u0420\u0430\u0437\u043c\u0430\u0445
dialog.compress.wackypoints.title=\u0423\u0434\u0430\u043b\u0435\u043d\u0438\u0435 "\u0448\u0430\u043b\u044c\u043d\u044b\u0445"(\u043d\u0435\u043e\u0431\u044b\u0447\u043d\u044b\u0445) \u0442\u043e\u0447\u0435\u043a
dialog.saveconfig.prune.gpsdevice=GPS \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u043e
dialog.saveconfig.prune.gpsformat=GPS \u0444\u043e\u0440\u043c\u0430\u0442
dialog.saveconfig.prune.povrayfont=Povray \u0448\u0440\u0438\u0444\u0442
-dialog.saveconfig.prune.metricunits=\u0418\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u043c\u0435\u0442\u0440\u0438\u0447\u0435\u0441\u043a\u0438\u0435 \u0435\u0434\u0438\u043d\u0438\u0446\u044b?
dialog.saveconfig.prune.gnuplotpath=\u041f\u0443\u0442\u044c \u043a GNUPLOT
dialog.saveconfig.prune.gpsbabelpath=\u041f\u0443\u0442\u044c \u043a GPSBabel
dialog.saveconfig.prune.exiftoolpath=\u041f\u0443\u0442\u044c \u043a ExifTool
dialog.colourchooser.green=\u0417\u0435\u043b\u0435\u043d\u044b\u0439
dialog.colourchooser.blue=\u0421\u0438\u043d\u0438\u0439
dialog.setlanguage.firstintro=\u0412\u044b \u043c\u043e\u0436\u0435\u0442\u0435 \u0432\u044b\u0431\u0440\u0430\u0442\u044c \u043e\u0434\u0438\u043d \u0438\u0437 \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u0435\u043c\u044b\u0445 \u044f\u0437\u044b\u043a\u043e\u0432, <p> \u0438\u043b\u0438 \u0443\u043a\u0430\u0437\u0430\u0442\u044c \u0438 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0432\u043d\u0435\u0448\u043d\u0438\u0439 \u044f\u0437\u044b\u043a\u043e\u0432\u043e\u0439 \u0444\u0430\u0439\u043b.
-dialog.setlanguage.secondintro=\u041d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u0441\u043e\u0445\u0440\u0430\u043d\u0438\u0442\u044c \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0438 \u0438 <p> \u043f\u0435\u0440\u0435\u0437\u0430\u043f\u0443\u0441\u0442\u0438\u0442\u044c \u0434\u043b\u044f \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u044f \u044f\u0437\u044b\u043a\u0430 \u0432 GpsPrune.
+dialog.setlanguage.secondintro=\u0414\u043b\u044f \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u044f \u044f\u0437\u044b\u043a\u0430 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u0441\u043e\u0445\u0440\u0430\u043d\u0438\u0442\u044c \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0438 <p>\u0438 \u043f\u0435\u0440\u0435\u0437\u0430\u043f\u0443\u0441\u0442\u0438\u0442\u044c GpsPrune .
dialog.setlanguage.language=\u042f\u0437\u044b\u043a
dialog.setlanguage.languagefile=\u042f\u0437\u044b\u043a\u043e\u0432\u043e\u0439 \u0444\u0430\u0439\u043b
dialog.setlanguage.endmessage=\u0422\u0435\u043f\u0435\u0440\u044c \u0441\u043e\u0445\u0440\u0430\u043d\u0438\u0442\u0435 \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0438 \u0438 \u043f\u0435\u0440\u0435\u0437\u0430\u043f\u0443\u0441\u0442\u0438\u0442\u0435 GpsPrune,\n\u0447\u0442\u043e\u0431\u044b \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u0435 \u044f\u0437\u044b\u043a\u0430 \u0432\u0441\u0442\u0443\u043f\u0438\u043b\u043e \u0432 \u0441\u0438\u043b\u0443.
# 3d window
dialog.3d.title=GpsPrune 3D-\u0432\u0438\u0434
-dialog.3d.altitudefactor=\u043a\u043e\u044d\u0444\u0444\u0438\u0446\u0438\u0435\u043d\u0442 \u043f\u043e \u0432\u044b\u0441\u043e\u0442\u0435
-dialog.3dlines.title=\u0441\u0435\u0442\u043a\u0430 GpsPrune
-dialog.3dlines.empty=\u043d\u0435\u0442 \u0441\u0435\u0442\u043a\u0438 \u0434\u043b\u044f \u043e\u0442\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u044f!
+dialog.3d.altitudefactor=\u041a\u043e\u044d\u0444\u0444\u0438\u0446\u0438\u0435\u043d\u0442 \u043f\u043e \u0432\u044b\u0441\u043e\u0442\u0435
+dialog.3dlines.title=\u0421\u0435\u0442\u043a\u0430 GpsPrune
+dialog.3dlines.empty=\u041d\u0435\u0442 \u0441\u0435\u0442\u043a\u0438 \u0434\u043b\u044f \u043e\u0442\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u044f!
dialog.3dlines.intro=\u041a\u043e\u043e\u0440\u0434\u0438\u043d\u0430\u0442\u044b \u0441\u0435\u0442\u043a\u0438 3D-\u0432\u0438\u0434\u0430
# Confirm messages
button.notoall=\u041d\u0435\u0442 \u0434\u043b\u044f \u0432\u0441\u0435\u0445
button.select=\u0412\u044b\u0431\u0440\u0430\u0442\u044c
button.selectall=\u0412\u044b\u0431\u0440\u0430\u0442\u044c \u0432\u0441\u0435
-button.selectnone=\u041d\u0438\u0447\u0435\u0433\u043e \u043d\u0435 \u043e\u0442\u0431\u0438\u0440\u0430\u0442\u044c
+button.selectnone=\u041e\u0442\u043c\u0435\u043d\u0442\u0438\u0442\u044c \u0432\u044b\u0431\u043e\u0440\u043a\u0443
button.preview=\u041f\u0440\u0435\u0434\u043f\u0440\u043e\u0441\u043c\u043e\u0442\u0440
button.load=\u0417\u0430\u0433\u0440\u0443\u0437\u0438\u0442\u044c
button.upload=\u0412\u044b\u0433\u0440\u0443\u0437\u0438\u0442\u044c
button.guessfields=\u041f\u0440\u0435\u0434\u043f\u043e\u043b\u0430\u0433\u0430\u0435\u043c\u044b\u0435 \u043f\u043e\u043b\u044f
-button.showwebpage=\u041f\u043e\u043a\u0430\u0437\u0430\u0442\u044c \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u0443
+button.showwebpage=\u041f\u043e\u043a\u0430\u0437\u0430\u0442\u044c \u0432\u0435\u0431\u0441\u0442\u0440\u0430\u043d\u0438\u0446\u0443
button.check=\u041f\u0440\u043e\u0432\u0435\u0440\u043a\u0430
button.resettodefaults=\u0421\u0431\u0440\u043e\u0441\u0438\u0442\u044c \u0432 \u0438\u0441\u0445\u043e\u0434\u043d\u043e\u0435
-button.browse=\u0423\u043a\u0430\u0437\u0430\u0442\u044c...
+button.browse=\u041e\u0431\u0437\u043e\u0440...
button.addnew=\u0414\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u043d\u043e\u0432\u043e\u0435
button.delete=\u0423\u0434\u0430\u043b\u0438\u0442\u044c
button.manage=\u0423\u043f\u0440\u0430\u0432\u043b\u044f\u0442\u044c
display.range.time.hours=h
display.range.time.days=d
details.range.avespeed=\u0421\u0440\u0435\u0434\u043d\u044f\u044f \u0441\u043a\u043e\u0440\u043e\u0441\u0442\u044c
-details.range.avemovingspeed=\u0421\u0440\u0435\u0434\u043d\u044f\u044f \u0441\u043a\u043e\u0440\u043e\u0441\u0442\u044c \u0441\u0435\u0433\u043c\u0435\u043d\u0442\u0430
details.range.maxspeed=\u041c\u0430\u043a\u0441\u0438\u043c\u0430\u043b\u044c\u043d\u0430\u044f \u0441\u043a\u043e\u0440\u043e\u0441\u0442\u044c
details.range.numsegments=\u041a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u043e \u0441\u0435\u0433\u043c\u0435\u043d\u0442\u043e\u0432
details.range.pace=\u0422\u0435\u043c\u043f
units.feet.short=ft
units.kilometres=\u041a\u0438\u043b\u043e\u043c\u0435\u0442\u0440\u044b
units.kilometres.short=km
-units.kmh=km/h
units.kilometresperhour.short=km/h
units.miles=\u041c\u0438\u043b\u0438
units.miles.short=mi
-units.mph=mph
units.milesperhour.short=mph
-units.metrespersec=m/s
-units.feetpersec=ft/s
units.hours=\u0427\u0430\u0441\u044b
units.degminsec=\u0413\u0440\u0430\u0434-\u043c\u0438\u043d-\u0441\u0435\u043a
units.degmin=\u0413\u0440\u0430\u0434-\u043c\u0438\u043d
wikipedia.lang=ru
# Cardinals for 3d plots
-cardinal.n=\u0421
-cardinal.s=\u042e
-cardinal.e=\u0412
-cardinal.w=\u0417
+cardinal.n=\u0421\u0435\u0432\u0435\u0440
+cardinal.s=\u042e\u0433
+cardinal.e=\u0412\u043e\u0441\u0442\u043e\u043a
+cardinal.w=\u0417\u0430\u043f\u0430\u0434
# Undo operations
undo.load=\u0437\u0430\u0433\u0440\u0443\u0437\u043a\u0430 \u0434\u0430\u043d\u043d\u044b\u0445
undo.removephoto=\u0443\u0434\u0430\u043b\u0438\u0442\u044c \u0444\u043e\u0442\u043e
undo.removeaudio=\u0443\u0434\u0430\u043b\u0438\u0442\u044c \u0437\u0432\u0443\u043a\u043e\u0437\u0430\u043f\u0438\u0441\u044c
undo.deleterange=\u0443\u0434\u0430\u043b\u0438\u0442\u044c \u0438\u043d\u0442\u0435\u0440\u0432\u0430\u043b
-undo.compress=\u0441\u0436\u0430\u0442\u044c \u0442\u0440\u0435\u043a
+undo.deletemarked=\u0441\u0436\u0430\u0442\u044c \u0442\u0440\u0435\u043a
undo.insert=\u0432\u0441\u0442\u0430\u0432\u0438\u0442\u044c \u0442\u043e\u0447\u043a\u0438
undo.reverse=\u043f\u0435\u0440\u0435\u0432\u0435\u0440\u043d\u0443\u0442\u044c \u0438\u043d\u0442\u0435\u0440\u0432\u0430\u043b
undo.mergetracksegments=\u0441\u043b\u0438\u044f\u043d\u0438\u0435 \u0441\u0435\u0433\u043c\u0435\u043d\u0442\u043e\u0432 \u0442\u0440\u0435\u043a\u0430
menu.track.clearundo=Geri alma listesi s\u0131f\u0131rla
menu.point.editpoint=Nokta d\u00fczenle
menu.point.deletepoint=Noktay\u0131 sil
-menu.range.deleterange=S\u0131ray\u0131 sil
+function.deleterange=S\u0131ray\u0131 sil
menu.track.deletemarked=Se\u00e7ili noktalar\u0131 sil
-menu.range.interpolate=\u0130nterpolasyon
+function.interpolate=\u0130nterpolasyon
menu.range.average=Se\u00e7me ortala
menu.range.reverse=S\u0131ra tersine \u00e7evir
menu.range.mergetracksegments=\u0130z par\u00e7alar\u0131 birle\u015ftir
dialog.pointnameedit.name=Nokta ad\u0131
dialog.pointnameedit.uppercase=B\u00dcY\u00dcK HARFLER
dialog.pointnameedit.lowercase=k\u00fc\u00e7\u00fck harfler
-dialog.pointnameedit.sentencecase=\u0130lk Harfi B\u00fcy\u00fck
+dialog.pointnameedit.titlecase=\u0130lk Harfi B\u00fcy\u00fck
dialog.addtimeoffset.add=Zaman ekle
dialog.addtimeoffset.subtract=Zaman \u00e7\u0131kart
dialog.addtimeoffset.days=G\u00fcn
dialog.saveconfig.prune.gpsdevice=GPS ayg\u0131t
dialog.saveconfig.prune.gpsformat=GPS bi\u00e7imi
dialog.saveconfig.prune.povrayfont=Povray yaz\u0131tipi
-dialog.saveconfig.prune.metricunits=Metrik sistemi
dialog.saveconfig.prune.gnuplotpath=gnuplot'un yeriyolu
dialog.saveconfig.prune.gpsbabelpath=gpsbabel'in yeriyolu
dialog.saveconfig.prune.exiftoolpath=exiftool'un yeriyolu
display.range.time.hours=saat
display.range.time.days=g\u011fn
details.range.avespeed=Ortalama h\u0131z\u0131
-details.range.avemovingspeed=Ortalama hareketi
details.lists.waypoints=Noktalar
details.lists.photos=Fotolar
details.photodetails=Foto ayr\u0131nt\u0131lar\u0131
units.feet.short=ft
units.kilometres=Kilometre
units.kilometres.short=km
-units.kmh=km/h
+units.kilometresperhour.short=km/h
units.miles=Mil
units.miles.short=mi
-units.mph=mph
-units.metrespersec=m/s
-units.feetpersec=ft/s
+units.milesperhour.short=mph
+units.metrespersec.short=m/s
+units.feetpersec.short=ft/s
units.hours=saat
units.degminsec=Derece/Dakika/Saniye
units.degmin=Derece/Dakika
undo.deletepoint=noktay\u0131 sil
undo.removephoto=foto kald\u0131r
undo.deleterange=s\u0131ra sil
-undo.compress=izi s\u0131k\u0131\u015ft\u0131r
+undo.deletemarked=izi s\u0131k\u0131\u015ft\u0131r
undo.insert=noktalar\u0131 ekle
undo.reverse=s\u0131ra tersine d\u00f6nd\u00fcr
undo.mergetracksegments=iz par\u00e7alar\u0131 birle\u015ftir
# Text entries for the GpsPrune application
-# Chinese entries as extra
+# Chinese entries
# Menu entries
menu.file=\u6587\u4ef6
-menu.file.addphotos=\u6dfb\u52a0\u76f8\u7247
+menu.file.addphotos=\u6dfb\u52a0\u7167\u7247
menu.file.recentfiles=\u6700\u8fd1\u6253\u5f00\u8fc7\u6587\u4ef6
menu.file.save=\u4fdd\u5b58
menu.file.exit=\u9000\u51fa
menu.track=\u8f68\u8ff9
menu.track.undo=\u64a4\u9500
menu.track.clearundo=\u6e05\u9664\u64a4\u9500\u6e05\u5355
-menu.track.deletemarked=\u5220\u9664\u5df2\u6807\u793a\u8f68\u8ff9\u70b9
+menu.track.markrectangle=\u6807\u8bb0\u9009\u53d6\u533a\u57df\u5185\u7684\u70b9
+menu.track.deletemarked=\u5220\u9664\u5df2\u6807\u8bb0\u8f68\u8ff9\u70b9
menu.track.rearrange=\u91cd\u65b0\u6392\u5217\u822a\u70b9
menu.track.rearrange.start=\u81f3\u8d77\u59cb\u4f4d\u7f6e
menu.track.rearrange.end=\u81f3\u672b\u4f4d\u7f6e
menu.range.none=\u64a4\u9500\u9009\u62e9
menu.range.start=\u8bbe\u7f6e\u8d77\u70b9
menu.range.end=\u8bbe\u7f6e\u7ec8\u70b9
-menu.range.deleterange=\u5220\u9664\u8f68\u8ff9\u70b9\u6bb5
-menu.range.interpolate=\u63d2\u5165\u8f68\u8ff9\u70b9
menu.range.average=\u8bbe\u7f6e\u5e73\u5747\u8f68\u8ff9\u70b9
-menu.range.reverse=\u8f68\u8ff9\u70b9\u53cd\u5411
+menu.range.reverse=\u8f68\u8ff9\u70b9\u53cd\u8f6c
menu.range.mergetracksegments=\u5408\u5e76\u8f68\u8ff9\u6bb5
menu.range.cutandmove=\u79fb\u52a8
menu.point=\u8f68\u8ff9\u70b9
menu.point.editpoint=\u7f16\u8f91\u8f68\u8ff9\u70b9
menu.point.deletepoint=\u5220\u9664\u8f68\u8ff9\u70b9
-menu.photo=\u76f8\u7247
+menu.photo=\u7167\u7247
menu.photo.saveexif=\u5750\u6807\u4fdd\u5b58\u81f3Exif
menu.audio=\u58f0\u97f3
menu.view=\u67e5\u770b
menu.view.browser.openstreetmap=Openstreet\u5730\u56fe
menu.view.browser.mapquest=Mapquest\u5730\u56fe
menu.view.browser.yahoo=Yahoo\u5730\u56fe
-menu.view.browser.bing=Bing(\u5fc5\u5e94\uff09\u5730\u56fe
+menu.view.browser.bing=Bing(\u5fc5\u5e94)\u5730\u56fe
menu.settings=\u8bbe\u7f6e
menu.settings.onlinemode=\u4ece\u7f51\u4e0a\u5bfc\u5165\u5730\u56fe
menu.settings.autosave=\u9000\u51fa\u65f6\u81ea\u52a8\u4fdd\u5b58\u8bbe\u7f6e
menu.map.autopan=\u81ea\u52a8\u7f29\u653e
menu.map.showmap=\u663e\u793a\u5730\u56fe
menu.map.showscalebar=\u663e\u793a\u6bd4\u4f8b\u5c3a
+menu.map.editmode=\u7f16\u8f91\u6a21\u5f0f
# Alt keys for menus
altkey.menu.file=F
function.exportpov=\u8f93\u51faPOV\u6587\u4ef6
function.exportsvg=\u8f93\u51faSVG\u6587\u4ef6
function.editwaypointname=\u7f16\u8f91\u822a\u70b9\u540d
-function.compress=\u538b\u7f29\u8f68\u8ff9(\u6807\u793a\u8981\u5220\u9664\u822a\u70b9\uff09
+function.compress=\u538b\u7f29\u8f68\u8ff9(\u6807\u8bb0\u8981\u5220\u9664\u822a\u70b9)
+function.deleterange=\u5220\u9664\u8f68\u8ff9\u70b9\u6bb5
+function.croptrack=\u4fee\u526a\u8f68\u8ff9
+function.interpolate=\u91cd\u53e0\u8f68\u8ff9\u70b9
function.addtimeoffset=\u52a0\u5165\u65f6\u95f4\u5dee
function.addaltitudeoffset=\u52a0\u5165\u9ad8\u5ea6\u504f\u79fb
function.convertnamestotimes=\u822a\u70b9\u540d\u79f0\u8f6c\u4e3a\u65f6\u95f4
function.deletefieldvalues=\u5220\u9664\u533a\u57df\u6570\u503c
function.findwaypoint=\u67e5\u627e\u822a\u70b9
function.pastecoordinates=\u8f93\u5165\u65b0\u5750\u6807
-function.charts=\u9ad8\u5ea6\u901f\u5ea6\u56fe\u8868
+function.charts=\u56fe\u8868
function.show3d=3D\u89c6\u56fe
function.distances=\u8ddd\u79bb
function.fullrangedetails=\u5168\u822a\u6bb5\u8be6\u7ec6\u4fe1\u606f
function.setmapbg=\u80cc\u666f\u5730\u56fe
function.setkmzimagesize=\u8bbe\u7f6eKMZ\u56fe\u50cf\u5c3a\u5bf8
function.setpaths=\u8bbe\u7f6e\u7a0b\u5e8f\u8def\u5f84
-function.getgpsies=Gpsies\u8f68\u8ff9
-function.uploadgpsies=\u8f68\u8ff9\u4e0a\u4f20\u5230 Gpsies
+function.getgpsies=\u83b7\u53d6Gpsies\u8f68\u8ff9
+function.uploadgpsies=\u4e0a\u4f20\u8f68\u8ff9\u5230Gpsies
function.lookupsrtm=\u4eceSRTM\u83b7\u5f97\u9ad8\u5ea6\u4fe1\u606f
function.getwikipedia=\u7ef4\u57fa\u767e\u79d1\u6709\u5173\u672c\u5730\u6587\u7ae0
function.searchwikipedianames=\u6309\u540d\u5b57\u4ece\u7ef4\u57fa\u767e\u79d1\u67e5\u627e
function.setcolours=\u8bbe\u7f6e\u989c\u8272
function.setlinewidth=\u8bbe\u7f6e\u7ebf\u4f53\u5bbd\u5ea6
function.setlanguage=\u8bbe\u7f6e\u8bed\u8a00
-function.connecttopoint=\u94fe\u63a5\u76f8\u7247
+function.connecttopoint=\u94fe\u63a5\u5230\u5f53\u524d\u70b9
function.disconnectfrompoint=\u64a4\u9500\u94fe\u63a5
function.removephoto=\u5220\u9664\u7167\u7247
-function.correlatephotos=\u94fe\u63a5\u76f8\u7247
-function.rearrangephotos=\u91cd\u6392\u76f8\u7247
+function.correlatephotos=\u94fe\u63a5\u7167\u7247\u7167
+function.rearrangephotos=\u91cd\u6392\u7167\u7247
function.rotatephotoleft=\u5de6\u65cb\u8f6c
function.rotatephotoright=\u53f3\u65cb\u8f6c
function.photopopup=\u663e\u793a\u5f39\u51fa\u7167\u7247
dialog.openappend.title=\u9644\u52a0\u81f3\u5df2\u5bfc\u5165\u6570\u636e
dialog.openappend.text=\u9644\u52a0\u73b0\u6709\u6570\u636e\u81f3\u5df2\u5bfc\u5165\u6570\u636e
dialog.deletepoint.title=\u5220\u9664\u8f68\u8ff9\u70b9
-dialog.deletepoint.deletephoto=\u5220\u9664\u8f68\u8ff9\u70b9\u94fe\u63a5\u7684\u76f8\u7247\uff1f
-dialog.deletephoto.title=\u5220\u9664\u76f8\u7247
-dialog.deletephoto.deletepoint=\u5220\u9664\u76f8\u7247\u94fe\u63a5\u7684\u8f68\u8ff9\u70b9\uff1f
+dialog.deletepoint.deletephoto=\u5220\u9664\u94fe\u63a5\u5230\u8f68\u8ff9\u70b9\u7684\u7167\u7247\uff1f
+dialog.deletephoto.title=\u5220\u9664\u7167\u7247
+dialog.deletephoto.deletepoint=\u5220\u9664\u94fe\u63a5\u5230\u7167\u7247\u7684\u8f68\u8ff9\u70b9\uff1f
+dialog.deleteaudio.deletepoint=\u5220\u9664\u94fe\u63a5\u5230\u97f3\u9891\u7684\u8f68\u8ff9\u70b9\uff1f
dialog.openoptions.title=\u6253\u5f00\u9009\u9879
dialog.openoptions.filesnippet=\u63d0\u53d6\u6587\u4ef6\u7247\u6bb5
dialog.load.table.field=\u6570\u636e\u6bb5
dialog.selecttracks.intro=\u9009\u62e9\u8981\u5bfc\u5165\u7684\u8f68\u8ff9
dialog.selecttracks.noname=\u672a\u547d\u540d
dialog.jpegload.subdirectories=\u542b\u6b21\u7ea7\u65b9\u4f4d
-dialog.jpegload.loadjpegswithoutcoords=\u542b\u65e0\u5750\u6807\u70b9\u76f8\u7247
-dialog.jpegload.loadjpegsoutsidearea=\u542b\u533a\u57df\u5916\u76f8\u7247
-dialog.jpegload.progress.title=\u5bfc\u5165\u76f8\u7247
-dialog.jpegload.progress=\u8bf7\u7b49\u5f85\uff0c\u6b63\u641c\u7d22\u76f8\u7247
+dialog.jpegload.loadjpegswithoutcoords=\u542b\u65e0\u5750\u6807\u70b9\u7167\u7247
+dialog.jpegload.loadjpegsoutsidearea=\u542b\u533a\u57df\u5916\u7167\u7247
+dialog.jpegload.progress.title=\u5bfc\u5165\u7167\u7247
+dialog.jpegload.progress=\u8bf7\u7b49\u5f85\uff0c\u6b63\u641c\u7d22\u7167\u7247
dialog.gpsload.nogpsbabel=\u627e\u4e0d\u5230Gpsbabel\uff0c\u7ee7\u7eed\uff1f
dialog.gpsload.device=GPS\u8bbe\u5907\u540d\u79f0
dialog.gpsload.format=GPS\u6587\u4ef6\u683c\u5f0f
dialog.save.overwrite.text=\u6587\u4ef6\u5df2\u5b58\u5728\uff0c\u662f\u5426\u8986\u76d6\uff1f
dialog.save.notypesselected=\u70b9\u7c7b\u578b\u672a\u9009\u5b9a
dialog.exportkml.text=\u6570\u636e\u540d\u79f0
-dialog.exportkml.altitude=\u7edd\u5bf9\u9ad8\u5ea6\uff08\u822a\u7a7a\u7528\uff09
+dialog.exportkml.altitude=\u7edd\u5bf9\u9ad8\u5ea6(\u822a\u7a7a\u7528)
dialog.exportkml.kmz=\u538b\u7f29\u6210KMZ\u6587\u4ef6
-dialog.exportkml.exportimages=\u8f93\u51fa\u76f8\u7247\u7f29\u7565\u56fe\u81f3KMZ
+dialog.exportkml.exportimages=\u8f93\u51fa\u7f29\u7565\u56fe\u81f3KMZ
dialog.exportkml.trackcolour=\u8f68\u8ff9\u989c\u8272
dialog.exportgpx.name=\u540d\u79f0
dialog.exportgpx.desc=\u63cf\u8ff0
dialog.pointtype.desc=\u4fdd\u5b58\u4e0b\u5217\u70b9\uff1a
dialog.pointtype.track=\u8f68\u8ff9\u70b9
dialog.pointtype.waypoint=\u822a\u70b9
-dialog.pointtype.photo=\u76f8\u7247\u70b9
+dialog.pointtype.photo=\u7167\u7247\u70b9
dialog.pointtype.audio=\u5e26\u58f0\u97f3\u7684\u822a\u70b9
dialog.pointtype.selection=\u4ec5\u5df2\u9009\u62e9\u822a\u6bb5
-dialog.confirmreversetrack.title=\u786e\u8ba4\u53cd\u5411
-dialog.confirmreversetrack.text=\u8f68\u8ff9\u5305\u542b\u65f6\u95f4\u4fe1\u606f\uff0c\u53cd\u5411\u540e\u53ef\u80fd\u4e22\u5931\u3002\n\u662f\u5426\u7ee7\u7eed\uff1f
+dialog.confirmreversetrack.title=\u786e\u8ba4\u53cd\u8f6c
+dialog.confirmreversetrack.text=\u8f68\u8ff9\u5305\u542b\u65f6\u95f4\u4fe1\u606f\uff0c\u53cd\u8f6c\u540e\u53ef\u80fd\u4e22\u5931\u3002\n\u662f\u5426\u7ee7\u7eed\uff1f
dialog.confirmcutandmove.title=\u786e\u8ba4\u526a\u5207\u548c\u79fb\u52a8
dialog.confirmcutandmove.text=\u8f68\u8ff9\u5305\u542b\u65f6\u95f4\u4fe1\u606f\uff0c\u79fb\u52a8\u540e\u53ef\u80fd\u4e22\u5931\u3002\n\u662f\u5426\u7ee7\u7eed\uff1f
-dialog.interpolate.title=\u91cd\u53e0\u8f68\u8ff9\u70b9
dialog.interpolate.parameter.text=\u6240\u9009\u4e24\u70b9\u4e2d\u63d2\u5165\u70b9\u7684\u4e2a\u6570
-dialog.undo.title=\u64a4\u9500\u52a8\u4f5c
-dialog.undo.pretext=\u8bf7\u9009\u62e9\u8981\u64a4\u9500\u7684\u52a8\u4f5c
+dialog.interpolate.betweenwaypoints=\u521b\u5efa\u4e2d\u7ee7\u822a\u70b9\uff1f
+dialog.undo.title=\u64a4\u9500\u64cd\u4f5c
+dialog.undo.pretext=\u8bf7\u9009\u62e9\u8981\u64a4\u9500\u7684\u64cd\u4f5c
dialog.undo.none.title=\u4e0d\u80fd\u64a4\u9500
-dialog.undo.none.text=\u65e0\u52a8\u4f5c\u53ef\u64a4\u9500
-dialog.clearundo.title=\u6e05\u9664\u64a4\u9500\u6e05\u5355
-dialog.clearundo.text=\u662f\u5426\u786e\u5b9e\u8981\u6e05\u9664\u64a4\u9500\u6e05\u5355\uff1f\n\u64a4\u9500\u4fe1\u606f\u4f1a\u4e22\u5931\uff01
+dialog.undo.none.text=\u65e0\u64cd\u4f5c\u53ef\u64a4\u9500
+dialog.clearundo.title=\u6e05\u9664\u64a4\u9500\u64cd\u4f5c\u6e05\u5355
+dialog.clearundo.text=\u662f\u5426\u786e\u5b9e\u8981\u6e05\u9664\u64a4\u9500\u64cd\u4f5c\u6e05\u5355\uff1f\n\u64a4\u9500\u64cd\u4f5c\u4fe1\u606f\u4f1a\u4e22\u5931\uff01
dialog.pointedit.title=\u7f16\u8f91\u8f68\u8ff9\u70b9
dialog.pointedit.text=\u9009\u62e9\u8981\u7f16\u8f91\u7684\u533a\u57df\u5e76\u7528\u201c\u7f16\u8f91\u201d\u952e\u6539\u53d8\u6570\u503c
dialog.pointedit.table.field=\u6570\u636e\u6bb5
dialog.pointedit.table.value=\u6570\u503c
-dialog.pointedit.table.changed=\u6539\u53d8
+dialog.pointedit.table.changed=\u5df2\u6539\u53d8
dialog.pointedit.changevalue.text=\u8f93\u5165\u65b0\u6570\u503c
dialog.pointedit.changevalue.title=\u7f16\u8f91\u6570\u636e\u6bb5
dialog.pointnameedit.name=\u822a\u70b9\u540d\u79f0
dialog.pointnameedit.uppercase=\u4e0a\u6863\u952e
dialog.pointnameedit.lowercase=\u4e0b\u6863\u952e
-dialog.pointnameedit.sentencecase=\u6807\u9898\u952e
+dialog.pointnameedit.titlecase=\u6807\u9898\u952e
dialog.addtimeoffset.add=\u5ef6\u540e\u65f6\u95f4
dialog.addtimeoffset.subtract=\u63d0\u524d\u65f6\u95f4
dialog.addtimeoffset.days=\u5929\u6570
dialog.findwaypoint.intro=\u8f93\u5165\u90e8\u5206\u822a\u70b9\u540d
dialog.findwaypoint.search=\u641c\u7d22
dialog.saveexif.title=\u4fdd\u5b58Exif
-dialog.saveexif.intro=\u9009\u62e9\u8981\u4fdd\u5b58\u7684\u76f8\u7247
+dialog.saveexif.intro=\u9009\u62e9\u8981\u4fdd\u5b58\u7684\u7167\u7247
dialog.saveexif.nothingtosave=\u5750\u6807\u672a\u6539\u53d8\uff0c\u65e0\u4fdd\u5b58\u5185\u5bb9
-dialog.saveexif.noexiftool=\u672a\u627e\u5230Exif \u5de5\u5177\uff0c\u7ee7\u7eed\uff1f
-dialog.saveexif.table.photoname=\u76f8\u7247\u540d
+dialog.saveexif.noexiftool=\u672a\u627e\u5230Exiftool\uff0c\u7ee7\u7eed\uff1f
+dialog.saveexif.table.photoname=\u7167\u7247\u540d
dialog.saveexif.table.status=\u72b6\u6001
dialog.saveexif.table.save=\u4fdd\u5b58
dialog.saveexif.photostatus.connected=\u5df2\u94fe\u63a5
dialog.distances.currentpoint=\u5f53\u524d\u70b9
dialog.distances.toofewpoints=\u9700\u8981\u822a\u70b9\u6765\u8ba1\u7b97\u8ddd\u79bb
dialog.fullrangedetails.intro=\u822a\u6bb5\u8be6\u60c5
+dialog.fullrangedetails.coltotal=\u5305\u542b\u95f4\u65ad
+dialog.fullrangedetails.colsegments=\u4e0d\u5305\u542b\u95f4\u65ad
dialog.setmapbg.intro=\u8bf7\u9009\u62e9\u5730\u56fe\uff0c\u6216\u6dfb\u52a0\u5730\u56fe
dialog.addmapsource.title=\u6dfb\u52a0\u5730\u56fe
dialog.addmapsource.sourcename=\u5730\u56fe\u6765\u6e90\u540d\u79f0
dialog.gpsies.nonefound=\u672a\u627e\u5230\u8f68\u8ff9
dialog.gpsies.username=Gpsies\u7f51\u7ad9\u7528\u6237\u540d
dialog.gpsies.password=Gpsies\u7f51\u7ad9\u5bc6\u7801
-dialog.gpsies.keepprivate=\u8f68\u8ff9\u4fdd\u5bc6\uff08\u4e0d\u516c\u5f00\uff09
+dialog.gpsies.keepprivate=\u4e0d\u516c\u5f00\u8f68\u8ff9
dialog.gpsies.confirmopenpage=\u6253\u5f00\u4e0a\u4f20\u8f68\u8ff9\u7684\u7f51\u7ad9\uff1f
dialog.gpsies.activities=\u6d3b\u52a8\u7c7b\u578b
dialog.gpsies.activity.trekking=\u5f92\u6b65
-dialog.gpsies.activity.walking=\u7ade\u8d70
+dialog.gpsies.activity.walking=\u6b65\u884c
dialog.gpsies.activity.jogging=\u8dd1\u6b65
-dialog.gpsies.activity.biking=\u9a91\u81ea\u884c\u8f66
+dialog.gpsies.activity.biking=\u81ea\u884c\u8f66
dialog.gpsies.activity.motorbiking=\u7535\u52a8\u81ea\u884c\u8f66
dialog.gpsies.activity.snowshoe=\u96ea\u978b\u5065\u884c
dialog.gpsies.activity.sailing=\u5e06\u8239
dialog.gpsies.activity.skating=\u6ed1\u51b0
dialog.wikipedia.column.name=\u6587\u7ae0\u9898\u76ee
dialog.wikipedia.column.distance=\u8ddd\u79bb
-dialog.correlate.notimestamps=\u6570\u636e\u70b9\u4e2d\u65e0\u65f6\u95f4\u4fe1\u606f\uff0c\u76f8\u7247\u65e0\u6cd5\u94fe\u63a5
-dialog.correlate.nouncorrelatedphotos=\u6240\u6709\u76f8\u7247\u5df2\u94fe\u63a5\u3002\u7ee7\u7eed\uff1f
-dialog.correlate.photoselect.intro=\u9009\u62e9\u5df2\u94fe\u63a5\u76f8\u7247\u4f5c\u4e3a\u65f6\u95f4\u504f\u79fb
-dialog.correlate.select.photoname=\u76f8\u7247\u540d
+dialog.correlate.notimestamps=\u6570\u636e\u70b9\u4e2d\u65e0\u65f6\u95f4\u4fe1\u606f\uff0c\u7167\u7247\u65e0\u6cd5\u94fe\u63a5
+dialog.correlate.nouncorrelatedphotos=\u6240\u6709\u7167\u7247\u5df2\u94fe\u63a5\u3002\u7ee7\u7eed\uff1f
+dialog.correlate.nouncorrelatedaudios=\u6240\u6709\u97f3\u9891\u5df2\u94fe\u63a5\u3002\u7ee7\u7eed\uff1f
+dialog.correlate.photoselect.intro=\u9009\u62e9\u5df2\u94fe\u63a5\u7167\u7247\u4f5c\u4e3a\u65f6\u95f4\u504f\u79fb
+dialog.correlate.select.photoname=\u7167\u7247\u540d
dialog.correlate.select.timediff=\u65f6\u95f4\u5dee
-dialog.correlate.select.photolater=\u76f8\u7247\u5ef6\u540e
-dialog.correlate.options.tip=\u63d0\u793a\uff1a\u624b\u52a8\u94fe\u63a5\u81f3\u5c11\u4e00\u5f20\u76f8\u7247\uff0c\u53ef\u81ea\u52a8\u8ba1\u7b97\u65f6\u95f4\u504f\u79fb
+dialog.correlate.select.photolater=\u7167\u7247\u5ef6\u540e
+dialog.correlate.options.tip=\u63d0\u793a\uff1a\u624b\u52a8\u94fe\u63a5\u81f3\u5c11\u4e00\u5f20\u7167\u7247\uff0c\u53ef\u81ea\u52a8\u8ba1\u7b97\u65f6\u95f4\u504f\u79fb
dialog.correlate.options.intro=\u9009\u62e9\u81ea\u52a8\u94fe\u63a5\u8bbe\u7f6e
dialog.correlate.options.offsetpanel=\u65f6\u95f4\u504f\u79fb
dialog.correlate.options.offset=\u504f\u79fb
dialog.correlate.options.offset.hours=\u5c0f\u65f6
-dialog.correlate.options.offset.minutes=\u5206\u949f
+dialog.correlate.options.offset.minutes=\u5206
dialog.correlate.options.offset.seconds=\u79d2
-dialog.correlate.options.photolater=\u76f8\u7247\u6ede\u540e\u4e8e\u8f68\u8ff9\u70b9
-dialog.correlate.options.pointlaterphoto=\u8f68\u8ff9\u70b9\u6ede\u540e\u4e8e\u76f8\u7247
-dialog.correlate.options.audiolater=\u58f0\u97f3\u6ede\u540e\u4e8e\u822a\u70b9
-dialog.correlate.options.pointlateraudio=\u822a\u70b9\u6ede\u540e\u4e8e\u58f0\u97f3
+dialog.correlate.options.photolater=\u7167\u7247\u6ede\u540e\u4e8e\u8f68\u8ff9\u70b9
+dialog.correlate.options.pointlaterphoto=\u8f68\u8ff9\u70b9\u6ede\u540e\u4e8e\u7167\u7247
+dialog.correlate.options.audiolater=\u97f3\u9891\u6ede\u540e\u4e8e\u822a\u70b9
+dialog.correlate.options.pointlateraudio=\u822a\u70b9\u6ede\u540e\u4e8e\u97f3\u9891
dialog.correlate.options.limitspanel=\u5173\u8054\u9650\u5236
dialog.correlate.options.notimelimit=\u65e0\u65f6\u95f4\u9650\u5236
dialog.correlate.options.timelimit=\u65f6\u95f4\u9650\u5236
dialog.correlate.options.nodistancelimit=\u65e0\u8ddd\u79bb\u9650\u5236
dialog.correlate.options.distancelimit=\u8ddd\u79bb\u9650\u5236
dialog.correlate.options.correlate=\u5173\u8054
-dialog.correlate.alloutsiderange=\u65e0\u6cd5\u94fe\u63a5\uff0c\u6240\u6709\u76f8\u7247\u8d85\u51fa\u8f68\u8ff9\u65f6\u95f4\u8303\u56f4\u3002\n\u8bf7\u6539\u53d8\u65f6\u95f4\u504f\u79fb\u6216\u624b\u52a8\u94fe\u63a5\u81f3\u5c11\u4e00\u5f20\u76f8\u7247\u3002
+dialog.correlate.alloutsiderange=\u65e0\u6cd5\u94fe\u63a5\uff0c\u6240\u6709\u7167\u7247\u8d85\u51fa\u8f68\u8ff9\u65f6\u95f4\u8303\u56f4\u3002\n\u8bf7\u6539\u53d8\u65f6\u95f4\u504f\u79fb\u6216\u624b\u52a8\u94fe\u63a5\u81f3\u5c11\u4e00\u5f20\u5728\u7167\u7247\u3002
dialog.correlate.filetimes=\u6587\u4ef6\u65f6\u95f4\u8868\u793a\u58f0\u97f3\u7684\uff1a
dialog.correlate.filetimes2=\u90e8\u5206
dialog.correlate.correltimes=\u5982\u8981\u5173\u8054\uff0c\u8bf7\u4f7f\u7528\uff1a
dialog.correlate.audioselect.intro=\u9009\u62e9\u4ee5\u4e0b\u58f0\u97f3\u6587\u4ef6\u4f5c\u4e3a\u65f6\u95f4\u504f\u5dee
dialog.correlate.select.audioname=\u58f0\u97f3\u6587\u4ef6\u540d\u5b57
dialog.correlate.select.audiolater=\u58f0\u97f3\u5ef6\u8fdf
-dialog.rearrangephotos.desc=\u9009\u62e9\u76ee\u7684\u5730\u53ca\u6392\u76f8\u7247\u70b9
+dialog.rearrangephotos.desc=\u9009\u62e9\u76ee\u7684\u5730\u53ca\u7167\u7247\u70b9\u6392\u5217\u987a\u5e8f
dialog.rearrangephotos.tostart=\u79fb\u5230\u5f00\u59cb
dialog.rearrangephotos.toend=\u79fb\u5230\u672b\u5c3e
dialog.rearrangephotos.nosort=\u4e0d\u6392\u5e8f
dialog.rearrangephotos.sortbyfilename=\u6309\u540d\u79f0\u6392\u5e8f
dialog.rearrangephotos.sortbytime=\u6309\u65f6\u95f4\u6392\u5e8f
-dialog.compress.nonefound=\u65e0\u6cd5\u5220\u9664\u6570\u636e\u70b9
dialog.compress.closepoints.title=\u90bb\u8fd1\u70b9\u5220\u9664
dialog.compress.closepoints.paramdesc=\u8303\u56f4\u7cfb\u6570
dialog.compress.wackypoints.title=\u5f02\u5e38\u70b9\u5220\u9664
dialog.compress.douglaspeucker.title=Douglas-Peucker \u538b\u7f29
dialog.compress.douglaspeucker.paramdesc=\u95f4\u8ddd\u7cfb\u6570
dialog.compress.summarylabel=\u8981\u5220\u9664\u7684\u70b9
+dialog.compress.confirm1=\u5df2\u6807\u8bb0
+dialog.compress.confirm2=\u70b9\u3002\n\u70b9\u51fb \u8f68\u8ff9->\u5220\u9664 \u5220\u9664\u8fd9\u4e9b\u70b9
+dialog.compress.confirmnone=\u672a\u6807\u8bb0\u4efb\u4f55\u70b9
+dialog.deletemarked.nonefound=\u65e0\u6cd5\u5220\u9664\u6570\u636e\u70b9
dialog.pastecoordinates.desc=\u5728\u6b64\u8f93\u5165\u6216\u7c98\u8d34\u5750\u6807\u70b9
dialog.pastecoordinates.coords=\u5750\u6807\u70b9
dialog.pastecoordinates.nothingfound=\u8bf7\u68c0\u67e5\u5750\u6807\u6570\u636e\u5e76\u91cd\u8bd5
dialog.about.systeminfo.gnuplot=Gnuplot \u662f\u5426\u5b89\u88c5
dialog.about.systeminfo.exiflib=Exif \u5e93
dialog.about.systeminfo.exiflib.internal=\u5185\u90e8
-dialog.about.systeminfo.exiflib.internal.failed=\u5185\u90e8\uff08\u672a\u627e\u5230\uff09
+dialog.about.systeminfo.exiflib.internal.failed=\u5185\u90e8(\u672a\u627e\u5230)
dialog.about.systeminfo.exiflib.external=\u5916\u90e8
-dialog.about.systeminfo.exiflib.external.failed=\u5916\u90e8\uff08\u672a\u627e\u5230\uff09
+dialog.about.systeminfo.exiflib.external.failed=\u5916\u90e8(\u672a\u627e\u5230)
dialog.about.yes=\u662f
dialog.about.no=\u5426
dialog.about.credits=\u81f4\u8c22
dialog.about.credits.code=GpsPrune \u539f\u7801\u7f16\u5199
dialog.about.credits.exifcode=Exif \u539f\u7801\u7f16\u5199
-dialog.about.credits.icons=\u56fe\u6807\u6765\u81ea\u4e8e
+dialog.about.credits.icons=\u90e8\u5206\u56fe\u6807\u6765\u81ea\u4e8e
dialog.about.credits.translators=\u8bd1\u8005
-dialog.about.credits.translations=\u7ffb\u8bd1\u52a9\u7406
+dialog.about.credits.translations=\u534f\u52a9\u7ffb\u8bd1
dialog.about.credits.devtools=\u5f00\u53d1\u5de5\u5177
dialog.about.credits.othertools=\u5176\u4ed6\u5de5\u5177
-dialog.about.credits.thanks=\u81f3\u8c22
+dialog.about.credits.thanks=\u81f4\u8c22
dialog.about.readme=\u7248\u672c\u4fe1\u606f
dialog.checkversion.error=\u65e0\u6cd5\u68c0\u6d4b\u7248\u672c\u66f4\u65b0\n\u8bf7\u68c0\u67e5\u7f51\u7edc\u8fde\u63a5
dialog.checkversion.uptodate=\u4f60\u4f7f\u7528\u7684\u5df2\u662f\u6700\u65b0\u7248\u672c
-dialog.checkversion.newversion1=\u65b0\u7248\u672c\u5b58\u5728\uff0c \u6700\u65b0\u7248\u672c\u53f7\u662f\uff1a
+dialog.checkversion.newversion1=\u53d1\u73b0\u65b0\u7248\u672c\uff01\u6700\u65b0\u7248\u672c\u662f\uff1a
dialog.checkversion.newversion2=
dialog.checkversion.releasedate1=\u65b0\u7248\u672c\u53d1\u884c\u4e8e
dialog.checkversion.releasedate2=
dialog.keys.macmodifier=Command
dialog.saveconfig.desc=\u4e0b\u5217\u8bbe\u7f6e\u5c06\u4fdd\u5b58\u5230\u8bbe\u7f6e\u6587\u4ef6
dialog.saveconfig.prune.trackdirectory=\u8f68\u8ff9\u6587\u4ef6\u5939
-dialog.saveconfig.prune.photodirectory=\u76f8\u7247\u6587\u4ef6\u5939
+dialog.saveconfig.prune.photodirectory=\u7167\u7247\u6587\u4ef6\u5939
dialog.saveconfig.prune.languagecode=\u8bed\u8a00\u9009\u62e9(ZH)
dialog.saveconfig.prune.languagefile=\u8bed\u8a00\u6587\u4ef6\u5305
dialog.saveconfig.prune.gpsdevice=GPS\u7aef\u53e3\u540d\u79f0
dialog.saveconfig.prune.gpsformat=GPS\u6587\u4ef6\u683c\u5f0f
dialog.saveconfig.prune.povrayfont=Povray \u5b57\u4f53
-dialog.saveconfig.prune.metricunits=\u4f7f\u7528\u516c\u5236\uff1f
dialog.saveconfig.prune.gnuplotpath=gnuplot\u8def\u5f84
dialog.saveconfig.prune.gpsbabelpath=gpsbabel\u8def\u5f84
dialog.saveconfig.prune.exiftoolpath=exiftool\u8def\u5f84
-dialog.saveconfig.prune.mapsource=\u5df2\u9009\u62e9\u7684\u5730\u56fe\u6e90
-dialog.saveconfig.prune.mapsourcelist=\u5730\u56fe\u6e90
+dialog.saveconfig.prune.mapsource=\u5df2\u9009\u62e9\u7684\u5730\u56fe\u6570\u636e\u6e90
+dialog.saveconfig.prune.mapsourcelist=\u5730\u56fe\u6570\u636e\u6e90
dialog.saveconfig.prune.diskcache=\u5b58\u50a8\u8def\u5f84
dialog.saveconfig.prune.kmzimagewidth=KMZ\u56fe\u50cf\u5bbd\u5ea6
dialog.saveconfig.prune.kmzimageheight=KMZ\u56fe\u50cf\u9ad8\u5ea6
dialog.saveconfig.prune.linewidth=\u7ebf\u4f53\u5bbd\u5ea6
dialog.saveconfig.prune.kmltrackcolour=KML\u8f68\u8ff9\u989c\u8272
dialog.saveconfig.prune.autosavesettings=\u81ea\u52a8\u4fdd\u5b58\u8bbe\u7f6e
-dialog.setpaths.intro=\u82e5\u9700\u8981\uff0c\u53ef\u8bbe\u5b9a\u5916\u6302\u7a0b\u5e8f\u8def\u5f84
+dialog.setpaths.intro=\u5982\u679c\u9700\u8981\uff0c\u53ef\u8bbe\u5b9a\u5916\u6302\u7a0b\u5e8f\u8def\u5f84
dialog.setpaths.found=\u627e\u5230\u8def\u5f84\uff1f
dialog.addaltitude.noaltitudes=\u8f68\u8ff9\u4e0d\u542b\u9ad8\u5ea6\u4fe1\u606f
dialog.addaltitude.desc=\u9ad8\u5ea6\u504f\u79fb
dialog.setlanguage.languagefile=\u8bed\u8a00\u5305
dialog.setlanguage.endmessage=\u73b0\u5728\u8bf7\u4fdd\u5b58\u8bbe\u7f6e\u5e76\u91cd\u542fGpsPrune\n\u4f7f\u8bbe\u7f6e\u751f\u6548
dialog.setlanguage.endmessagewithautosave=\u8981\u4f7f\u6240\u9009\u8bed\u8a00\u751f\u6548\uff0c\u8bf7\u91cd\u65b0\u542f\u52a8GosPrune
-dialog.diskcache.save=\u5730\u56fe\u56fe\u7247\u4fdd\u5b58\u5230\u7535\u8111
-dialog.diskcache.dir=\u4fdd\u5b58\u8def\u5f84
-dialog.diskcache.createdir=\u65b0\u5efa\u8def\u5f84
-dialog.diskcache.nocreate=\u672a\u65b0\u5efa\u8def\u5f84
+dialog.diskcache.save=\u4fdd\u5b58\u5730\u56fe\u56fe\u7247
+dialog.diskcache.dir=\u4e34\u65f6\u6587\u4ef6\u5939
+dialog.diskcache.createdir=\u65b0\u5efa\u6587\u4ef6\u5939
+dialog.diskcache.nocreate=\u6587\u4ef6\u5939\u672a\u521b\u5efa
+dialog.diskcache.cannotwrite=\u65e0\u6cd5\u5728\u6307\u5b9a\u6587\u4ef6\u5939\u4e0b\u4fdd\u5b58\u5730\u56fe\u5757
dialog.diskcache.table.path=\u8def\u5f84
dialog.diskcache.table.usedby=\u4f7f\u7528\u8005
-dialog.diskcache.table.zoom=\u653e\u5927\u7f29\u5c0f
-dialog.diskcache.table.tiles=\u627e\u5230\u7684\u5730\u56fe\u533a\u57df\u6570\u636e
+dialog.diskcache.table.zoom=\u7f29\u653e\u7ea7\u522b
+dialog.diskcache.table.tiles=\u5730\u56fe\u5757
dialog.diskcache.table.megabytes=MB
-dialog.diskcache.tileset=\u5730\u56fe\u533a\u57df\u6570\u5b58\u653e\u8def\u5f84
+dialog.diskcache.tileset=\u5730\u56fe\u5757\u5b58\u653e\u8def\u5f84
dialog.diskcache.tileset.multiple=\u6570\u76ee
-dialog.diskcache.deleteold=\u5220\u9664\u65e7\u533a\u57df\u6570\u636e
+dialog.diskcache.deleteold=\u5220\u9664\u65e7\u5730\u56fe\u5757
dialog.diskcache.maximumage=\u6700\u957f\u65f6\u95f4(\u5929)
-dialog.diskcache.deleteall=\u5220\u9664\u6240\u6709\u533a\u57df\u6570\u636e
+dialog.diskcache.deleteall=\u5220\u9664\u6240\u6709\u5730\u56fe\u5757
dialog.diskcache.deleted1=\u5df2\u5220\u9664
dialog.diskcache.deleted2=\u7f13\u5b58\u5185\u6587\u4ef6
dialog.deletefieldvalues.intro=\u9009\u62e9\u5f53\u524d\u8303\u56f4\u5185\u8981\u5220\u9664\u7684\u533a\u57df
-dialog.setlinewidth.text=\u8f93\u5165\u8f68\u8ff9\u7ebf\u5bbd\u50cf\u7d20\u503c\uff081-4\uff09
-dialog.downloadosm.desc=\u786e\u8ba4\u4eceOSM\u4e0b\u8f7d\u8be5\u5730\u533a\u539f\u59cb\u6570\u636e
-dialog.searchwikipedianames.search=\u67e5\u627e
+dialog.setlinewidth.text=\u8f93\u5165\u8f68\u8ff9\u7ebf\u5bbd\u50cf\u7d20\u503c(1-4)
+dialog.downloadosm.desc=\u786e\u8ba4\u4eceOSM\u4e0b\u8f7d\u8be5\u5730\u533a\u539f\u59cb\u6570\u636e:
+dialog.searchwikipedianames.search=\u67e5\u627e:
# 3d window
dialog.3d.title=GpsPrune 3D \u663e\u793a
confirm.deletepoint.multi=\u5df2\u5220\u9664\u7684\u8f68\u8ff9\u70b9
confirm.point.edit=\u5df2\u7f16\u8f91\u7684\u8f68\u8ff9\u70b9
confirm.mergetracksegments=\u5df2\u5408\u5e76\u7684\u8f68\u8ff9\u6bb5
-confirm.reverserange=\u53cd\u5411\u7684\u8303\u56f4
+confirm.reverserange=\u53cd\u8f6c\u7684\u8303\u56f4
confirm.addtimeoffset=\u5df2\u52a0\u4e0a\u65f6\u95f4\u504f\u5dee
confirm.addaltitudeoffset=\u5df2\u52a0\u4e0a\u9ad8\u5ea6\u504f\u5dee
confirm.rearrangewaypoints=\u91cd\u65b0\u914d\u7f6e\u7684\u822a\u70b9
-confirm.rearrangephotos=\u76f8\u7247\u5df2\u91cd\u6392
+confirm.rearrangephotos=\u7167\u7247\u5df2\u91cd\u6392
confirm.cutandmove=\u5df2\u79fb\u52a8\u7684\u8f68\u8ff9\u6bb5
+confirm.interpolate=\u8f68\u8ff9\u70b9\u5df2\u6dfb\u52a0
confirm.convertnamestotimes=\u822a\u70b9\u540d\u79f0\u5df2\u8f6c\u6362
confirm.saveexif.ok1=\u5df2\u4fdd\u5b58
-confirm.saveexif.ok2=\u76f8\u7247\u6587\u4ef6
+confirm.saveexif.ok2=\u7167\u7247\u6587\u4ef6
confirm.undo.single=\u5df2\u64a4\u9500\u7684\u64cd\u4f5c
confirm.undo.multi=\u5df2\u64a4\u9500\u7684\u64cd\u4f5c
-confirm.jpegload.single=\u5df2\u52a0\u5165\u76f8\u7247
-confirm.jpegload.multi=\u5df2\u52a0\u5165\u76f8\u7247
+confirm.jpegload.single=\u5df2\u52a0\u5165\u7167\u7247
+confirm.jpegload.multi=\u5df2\u52a0\u5165\u7167\u7247
confirm.media.connect=\u5a92\u4f53\u5df2\u5173\u8054
-confirm.photo.disconnect=\u76f8\u7247\u672a\u94fe\u63a5
+confirm.photo.disconnect=\u7167\u7247\u672a\u94fe\u63a5
confirm.audio.disconnect=\u58f0\u97f3\u672a\u94fe\u63a5
confirm.media.removed=\u5df2\u5220\u9664
-confirm.correlatephotos.single=\u76f8\u7247\u5df2\u94fe\u63a5
-confirm.correlatephotos.multi=\u76f8\u7247\u5df2\u94fe\u63a5
+confirm.correlatephotos.single=\u7167\u7247\u5df2\u94fe\u63a5
+confirm.correlatephotos.multi=\u7167\u7247\u5df2\u94fe\u63a5
confirm.createpoint=\u5df2\u521b\u5efa\u70b9
-confirm.rotatephoto=\u76f8\u7247\u5df2\u65cb\u8f6c
+confirm.rotatephoto=\u7167\u7247\u5df2\u65cb\u8f6c
confirm.running=\u8bf7\u7a0d\u7b49...
confirm.lookupsrtm1=\u627e\u5230
confirm.lookupsrtm2=\u9ad8\u5ea6\u503c
details.index.selected=\u7b2c
details.index.of=\u70b9\u53d6\u81ea
details.nopointselection=\u6ca1\u6709\u9009\u62e9\u70b9
-details.photofile=\u76f8\u7247\u6587\u4ef6
+details.photofile=\u7167\u7247\u6587\u4ef6
details.norangeselection=\u6ca1\u6709\u9009\u62e9\u8f68\u8ff9/\u822a\u70b9\u6bb5
details.rangedetails=\u8f68\u8ff9/\u822a\u70b9\u6bb5\u4fe1\u606f
details.range.selected=\u9009\u4e2d
display.range.time.hours=\u5c0f\u65f6
display.range.time.days=\u5929
details.range.avespeed=\u5e73\u5747\u901f\u5ea6
-details.range.avemovingspeed=\u5e73\u5747\u79fb\u52a8
details.range.maxspeed=\u6700\u5927\u901f\u5ea6
details.range.numsegments=\u6bb5\u6570
details.range.pace=\u6b65\u901f
details.range.gradient=\u5761\u5ea6
details.lists.waypoints=\u822a\u70b9
-details.lists.photos=\u76f8\u7247
+details.lists.photos=\u7167\u7247
details.lists.audio=\u58f0\u97f3
-details.photodetails=\u76f8\u7247\u4fe1\u606f
-details.nophoto=\u65e0\u76f8\u7247\u88ab\u9009\u4e2d
-details.photo.loading=\u6b63\u5bfc\u5165
+details.photodetails=\u7167\u7247\u4fe1\u606f
+details.nophoto=\u6ca1\u6709\u9009\u4e2d\u7167\u7247
+details.photo.loading=\u5bfc\u5165\u4e2d
details.photo.bearing=\u65b9\u5411
details.media.connected=\u5df2\u94fe\u63a5
+details.media.fullpath=\u5b8c\u6574\u8def\u5f84
details.audiodetails=\u8be6\u7ec6\u4fe1\u606f
details.noaudio=\u672a\u9009\u62e9\u58f0\u97f3\u6587\u4ef6
details.audio.file=\u58f0\u97f3\u6587\u4ef6
units.feet.short=\u82f1\u5c3a
units.kilometres=\u5343\u7c73
units.kilometres.short=\u5343\u7c73
-units.kmh=\u5343\u7c73/\u65f6
+units.kilometresperhour.short=\u5343\u7c73/\u65f6
units.miles=\u82f1\u91cc
units.miles.short=\u82f1\u91cc
-units.mph=\u82f1\u91cc/\u65f6
+units.milesperhour.short=\u82f1\u91cc/\u65f6
+units.nauticalmiles=\u6d77\u91cc
+units.nauticalmiles.short=\u6d77\u91cc
+units.nauticalmilesperhour.short=\u6d77\u91cc/\u65f6
+units.metrespersec.short=\u7c73/\u79d2
+units.feetpersec.short=\u82f1\u5c3a/\u79d2
units.hours=\u5c0f\u65f6
units.degminsec=\u5ea6-\u5206-\u79d2
units.degmin=\u5ea6-\u5206
# Undo operations
undo.load=\u5bfc\u5165\u6570\u636e
-undo.loadphotos=\u5bfc\u5165\u76f8\u7247
+undo.loadphotos=\u5bfc\u5165\u7167\u7247
undo.loadaudios=\u8f7d\u5165\u58f0\u97f3\u6587\u4ef6
undo.editpoint=\u7f16\u8f91\u8f68\u8ff9\u70b9
undo.deletepoint=\u5220\u9664\u8f68\u8ff9\u70b9
-undo.removephoto=\u5220\u9664\u76f8\u7247
+undo.removephoto=\u5220\u9664\u7167\u7247
undo.removeaudio=\u5220\u9664\u58f0\u97f3\u6587\u4ef6
undo.deleterange=\u5220\u9664\u6bb5
-undo.compress=\u538b\u7f29\u8f68\u8ff9
+undo.croptrack=\u4fee\u526a\u8f68\u8ff9
+undo.deletemarked=\u538b\u7f29\u8f68\u8ff9
undo.insert=\u63d2\u5165\u822a\u70b9
-undo.reverse=\u53cd\u5411\u6bb5
+undo.reverse=\u53cd\u8f6c\u6bb5
undo.mergetracksegments=\u5408\u5e76\u6bb5
undo.addtimeoffset=\u6dfb\u52a0\u65f6\u95f4\u504f\u79fb
undo.addaltitudeoffset=\u52a0\u5165\u9ad8\u5ea6\u504f\u79fb
undo.cutandmove=\u79fb\u52a8\u6bb5
undo.connect=\u94fe\u63a5
undo.disconnect=\u65ad\u5f00
-undo.correlatephotos=\u94fe\u63a5\u76f8\u7247
-undo.rearrangephotos=\u91cd\u62cd\u76f8\u7247
+undo.correlatephotos=\u94fe\u63a5\u7167\u7247
+undo.rearrangephotos=\u91cd\u6392\u7167\u7247
undo.createpoint=\u521b\u5efa\u8f68\u8ff9\u70b9
-undo.rotatephoto=\u65cb\u8f6c\u76f8\u7247
-undo.convertnamestotimes=\u540d\u79f0\u8f6c\u4e3a\u65f6\u95f4
+undo.rotatephoto=\u65cb\u8f6c\u7167\u7247
+undo.convertnamestotimes=\u5c06\u540d\u79f0\u8f6c\u4e3a\u65f6\u95f4
undo.lookupsrtm=\u4eceSRTM\u67e5\u627e\u9ad8\u5ea6
undo.deletefieldvalues=\u5220\u9664\u533a\u57df\u6570\u636e
-undo.correlateaudios=\u5173\u8054\u58f0\u97f3
+undo.correlateaudios=\u5173\u8054\u97f3\u9891
# Error messages
error.save.dialogtitle=\u4fdd\u5b58\u6570\u636e\u9519\u8bef
error.save.nodata=\u65e0\u6570\u636e\u4fdd\u5b58
error.save.failed=\u5411\u6587\u4ef6\u4fdd\u5b58\u6570\u636e\u5931\u8d25
-error.saveexif.filenotfound=\u627e\u4e0d\u5230\u76f8\u7247\u6587\u4ef6
-error.saveexif.cannotoverwrite1=\u76f8\u7247\u6587\u4ef6
-error.saveexif.cannotoverwrite2=\u53ea\u8bfb\u6587\u4ef6\u3002\u4fdd\u5b58\u526f\u672c\uff1f
-error.saveexif.failed1=\u56fe\u7247
-error.saveexif.failed2=\u4fdd\u5b58\u5931\u8d25
+error.saveexif.filenotfound=\u627e\u4e0d\u5230\u7167\u7247\u6587\u4ef6
+error.saveexif.cannotoverwrite1=\u7167\u7247
+error.saveexif.cannotoverwrite2=\u662f\u53ea\u8bfb\u6587\u4ef6\u3002\u4fdd\u5b58\u526f\u672c\uff1f
+error.saveexif.failed1=\u65e0\u6cd5\u4fdd\u5b58
+error.saveexif.failed2=\u5f20\u7167\u7247
error.saveexif.forced1=
-error.saveexif.forced2=\u4e2a\u56fe\u7247\u9700\u8981\u5f3a\u5236\u6267\u884c
+error.saveexif.forced2=\u5f20\u7167\u7247\u9700\u8981\u5f3a\u5236\u6267\u884c
error.load.dialogtitle=\u5bfc\u5165\u6570\u636e\u9519\u8bef
error.load.noread=\u65e0\u6cd5\u8bfb\u6587\u4ef6
error.load.nopoints=\u6587\u4ef6\u4e2d\u65e0\u5750\u6807\u4fe1\u606f
error.load.unknownxml=XML\u683c\u5f0f\u9519\u8bef
error.load.noxmlinzip=Zip\u6587\u4ef6\u4e2d\u65e0\u6cd5\u627e\u5230XML
error.load.othererror=\u8bfb\u6587\u4ef6\u9519\u8bef
-error.jpegload.dialogtitle=\u5bfc\u5165\u76f8\u7247\u9519\u8bef
+error.jpegload.dialogtitle=\u5bfc\u5165\u7167\u7247\u9519\u8bef
error.jpegload.nofilesfound=\u627e\u4e0d\u5230\u6587\u4ef6
error.jpegload.nojpegsfound=\u627e\u4e0d\u5230Jpeg\u6587\u4ef6
error.jpegload.nogpsfound=\u627e\u4e0d\u5230GPS\u4fe1\u606f
error.lookupsrtm.nonerequired=\u6240\u6709\u70b9\u5747\u542b\u9ad8\u5ea6\u4fe1\u606f
error.gpsies.uploadnotok=gpsies\u670d\u52a1\u5668\u8fd4\u56de\u4fe1\u606f\uff1a
error.gpsies.uploadfailed=\u4e0a\u4f20\u5931\u8d25
+error.showphoto.failed=\u52a0\u8f7d\u7167\u7247\u5931\u8d25
error.playaudiofailed=\u65e0\u6cd5\u64ad\u653e\u58f0\u97f3\u6587\u4ef6
error.cache.notthere=\u672a\u627e\u5230\u533a\u57df\u6570\u636e\u7f13\u5b58\u6587\u4ef6\u5939
error.cache.empty=\u533a\u57df\u6570\u636e\u6587\u4ef6\u5939\u7a7a
error.cache.cannotdelete=\u65e0\u53ef\u5220\u9664\u533a\u57df\u6570\u636e
+error.interpolate.invalidparameter=\u8f93\u5165\u70b9\u6570\u91cf\u5fc5\u987b\u57281\u52301000\u4e4b\u95f4
}
// If we haven't got a result by now, try to load plain file
- File file = (inSourceFile == null ? new File(inPath) : new File(inSourceFile.getParent(), inPath));
+ File file = new File(inPath);
+ if (inSourceFile != null && !file.isAbsolute()) {
+ file = new File(inSourceFile.getParent(), inPath);
+ }
+ // awkward construction because new File(startPath, absolutePath) doesn't work
return createMediaObject(file);
}
if (messages.size() > 0)
{
_app.informDataLoaded(getFieldArray(), makeDataArray(messages),
- Altitude.Format.METRES, new SourceInfo(inFile, SourceInfo.FILE_TYPE.NMEA));
+ Altitude.Format.METRES, new SourceInfo(inFile, SourceInfo.FILE_TYPE.NMEA),
+ null);
}
}
// give data to App
SourceInfo sourceInfo = new SourceInfo(_file, SourceInfo.FILE_TYPE.TEXT);
_app.informDataLoaded(_fieldTableModel.getFieldArray(),
- _fileExtractTableModel.getData(), altitudeFormat, sourceInfo);
+ _fileExtractTableModel.getData(), altitudeFormat, sourceInfo, null);
// clear up file cacher
_fileCacher.clear();
// dispose of dialog
-GpsPrune version 13.4
-=====================
+GpsPrune version 14
+===================
GpsPrune is an application for viewing, editing and managing coordinate data from GPS systems,
including format conversion, charting and photo correlation.
=======
To run GpsPrune from the jar file, simply call it from a command prompt or shell:
- java -jar gpsprune_13.4.jar
+ java -jar gpsprune_14.jar
If the jar file is saved in a different directory, you will need to include the path.
Depending on your system settings, you may be able to click or double-click on the jar file
or other link can of course be made should you wish.
To specify a language other than the default, use an additional parameter, eg:
- java -jar gpsprune_13.4.jar --lang=DE
-
+ java -jar gpsprune_14.jar --lang=DE
-New with version 13.4
-=====================
-The following features were added since version 13.3:
- - Fix for empty settings
- - Fix for file suffixes of cached tiles
- - Removed Osma source as tiles@home has been discontinued
-New with version 13.3
-=====================
-The following features were added since version 13.2:
- - Completion of Italian translations
- - Fix for exporting track names to version 1.1 gpx files
- - Changed OpenCycleMap url
- - Added diagnostics if unrecognised command-line parameter wasn't a valid file
- - Improve error handling when tile downloading fails
- - Fix for editing a cloudmade source
-
-New with version 13.2
-=====================
-The following features were added since version 13.1:
- - Russian translation
- - Fix for loading kml with placemarks with multiple coordinate lists
- - Fix for exporting descriptions to version 1.1 gpx files
-
-New with version 13.1
+New with version 14
=====================
The following features were added since version 13:
- - Allow loading of photos and audio using relative paths from the gpx/kml file
- - Cosmetic fixes to make the map controls more visible
- - Allow osm-style map sources to use gifs or jpgs as well as pngs
- - Allow edit of custom map sources
- - Addition of a few more built-in map sources, such as hikebikemap and openseamap
+ - Dragging of existing points
+ - Creation of new points by dragging the halfway point between two points
+ - Nautical miles option including knots
+ - Full range details dialog
+ - Extension of interpolation function
+ - Selecting points within a rectangle to delete
New with version 13
===================
- Importing of files through GPSBabel
- List of recently used files in the menu
- Display of bearing at which a photo was taken (display only)
+ - Allow edit of custom map sources
+ - Russian translation
New with version 12
===================
{
if (inTimestampFormat == Timestamp.FORMAT_ORIGINAL) {
// output original string
- inBuffer.append(inPoint.getFieldValue(Field.TIMESTAMP));
+ inBuffer.append(inPoint.getTimestamp().getText(Timestamp.FORMAT_ORIGINAL));
}
else {
// format value accordingly
// Generate the GPX file and send to the GPS
OutputStreamWriter writer = new OutputStreamWriter(process.getOutputStream());
boolean[] saveFlags = {true, true, true, true, false, true}; // export everything
- GpxExporter.exportData(writer, _app.getTrackInfo(), trackName, null, saveFlags, false);
+ GpxExporter.exportData(writer, _app.getTrackInfo(), trackName, null, saveFlags, null);
writer.close();
// Read the error stream to see if there's a better error message there
*/
public void run()
{
+ // Instantiate source file cachers in case we want to copy output
+ GpxCacherList gpxCachers = null;
+ if (_copySourceCheckbox.isSelected()) {
+ gpxCachers = new GpxCacherList(_trackInfo.getFileInfo());
+ }
OutputStreamWriter writer = null;
try
{
_pointTypeSelector.getJustSelection(), _timestampsCheckbox.isSelected()};
// write file
final int numPoints = exportData(writer, _trackInfo, _nameField.getText(),
- _descriptionField.getText(), saveFlags, _copySourceCheckbox.isSelected());
+ _descriptionField.getText(), saveFlags, gpxCachers);
// close file
writer.close();
* @param inName name of track (optional)
* @param inDesc description of track (optional)
* @param inSaveFlags array of booleans to export tracks, waypoints, photos, audios, selection, timestamps
- * @param inUseCopy true to copy source if available
+ * @param inGpxCachers list of Gpx cachers containing input data
* @return number of points written
* @throws IOException if io errors occur on write
*/
public static int exportData(OutputStreamWriter inWriter, TrackInfo inInfo, String inName,
- String inDesc, boolean[] inSaveFlags, boolean inUseCopy) throws IOException
+ String inDesc, boolean[] inSaveFlags, GpxCacherList inGpxCachers) throws IOException
{
- // Instantiate source file cachers in case we want to copy output
- GpxCacherList gpxCachers = null;
- if (inUseCopy) gpxCachers = new GpxCacherList(inInfo.getFileInfo());
// Write or copy headers
inWriter.write(getXmlHeaderString(inWriter));
- final String gpxHeader = getGpxHeaderString(gpxCachers);
+ final String gpxHeader = getGpxHeaderString(inGpxCachers);
final boolean isVersion1_1 = (gpxHeader.toUpperCase().indexOf("GPX/1/1") > 0);
inWriter.write(gpxHeader);
// Name field
// Make a wpt element for each waypoint
if (point.isWaypoint() && exportWaypoints)
{
- String pointSource = (inUseCopy?getPointSource(gpxCachers, point):null);
- if (pointSource != null) {
+ String pointSource = (inGpxCachers == null? null : getPointSource(inGpxCachers, point));
+ if (pointSource != null)
+ {
+ // If timestamp checkbox is off, strip time
+ if (!exportTimestamps) {
+ pointSource = stripTime(pointSource);
+ }
inWriter.write(pointSource);
inWriter.write('\n');
}
{
// Output all route points (if any)
numSaved += writeTrackPoints(inWriter, inInfo, exportSelection, exportTrackpoints, exportPhotos,
- exportAudios, exportTimestamps, true, gpxCachers, "<rtept", "\t<rte><number>1</number>\n",
+ exportAudios, exportTimestamps, true, inGpxCachers, "<rtept", "\t<rte><number>1</number>\n",
null, "\t</rte>\n");
// Output all track points, if any
String trackStart = "\t<trk><name>" + trackName + "</name><number>1</number><trkseg>\n";
numSaved += writeTrackPoints(inWriter, inInfo, exportSelection, exportTrackpoints, exportPhotos,
- exportAudios, exportTimestamps, false, gpxCachers, "<trkpt", trackStart,
+ exportAudios, exportTimestamps, false, inGpxCachers, "<trkpt", trackStart,
"\t</trkseg>\n\t<trkseg>\n", "\t</trkseg></trk>\n");
}
inWriter.write(inSegmentTag);
}
if (numSaved == 0) {inWriter.write(inStartTag);}
- if (pointSource != null) {
+ if (pointSource != null)
+ {
+ // If timestamps checkbox is off, strip the time
+ if (!exportTimestamps) {
+ pointSource = stripTime(pointSource);
+ }
inWriter.write(pointSource);
inWriter.write('\n');
}
encoding = Charset.forName(encoding).name();
}
catch (Exception e) {} // ignore failure to find encoding
- // Hack to fix bugs with Mac OSX (which reports MacRoman but is actually UTF-8)
- if (encoding == null || encoding.toLowerCase().startsWith("macroman")) {
- encoding = "UTF-8";
- }
return encoding;
}
// No link available, must have been loaded from zip file - no link possible
return "";
}
+
+
+ /**
+ * Strip the time from a GPX point source string
+ * @param inPointSource point source to copy
+ * @return point source with timestamp removed
+ */
+ private static String stripTime(String inPointSource)
+ {
+ return inPointSource.replaceAll("<time>.*?</time>", "");
+ }
}
{
FileWriter writer = null;
// find out the line separator for this system
- String lineSeparator = System.getProperty("line.separator");
+ final String lineSeparator = System.getProperty("line.separator");
try
{
// create and scale model
" sphere {",
" <0, 0, 0>, 0.3", // size should depend on model size
" texture {",
- " pigment {color rgb <0.2 1.0 0.2>}",
+ " pigment {color rgb <0.1 0.6 0.1>}", // dark green
" finish { phong 1 }",
" }",
" }",
" sphere {",
" <0, 0, 0>, 0.3", // size should depend on model size
" texture {",
- " pigment {color rgb <0.6 1.0 0.2>}",
+ " pigment {color rgb <0.4 0.9 0.2>}", // green
" finish { phong 1 }",
" }",
" }",
" sphere {",
" <0, 0, 0>, 0.3", // size should depend on model size
" texture {",
- " pigment {color rgb <1.0 1.0 0.1>}",
+ " pigment {color rgb <0.7 0.8 0.2>}", // yellow
" finish { phong 1 }",
" }",
" }",
" sphere {",
" <0, 0, 0>, 0.3", // size should depend on model size
" texture {",
- " pigment {color rgb <1.0 1.0 1.0>}",
+ " pigment {color rgb <0.5 0.8 0.6>}", // greeny
" finish { phong 1 }",
" }",
" }",
" sphere {",
" <0, 0, 0>, 0.3", // size should depend on model size
" texture {",
- " pigment {color rgb <0.1 1.0 1.0>}",
+ " pigment {color rgb <0.2 0.9 0.9>}", // cyan
+ " finish { phong 1 }",
+ " }",
+ " }",
+ "#declare track_sphere5 =",
+ " sphere {",
+ " <0, 0, 0>, 0.3", // size should depend on model size
+ " texture {",
+ " pigment {color rgb <1.0 1.0 1.0>}", // white
" finish { phong 1 }",
" }",
" }",
* @param inLineSeparator line separator to use
* @throws IOException on file writing error
*/
- private void writeLatLongLines(FileWriter inWriter, ThreeDModel inModel, String inLineSeparator)
+ private static void writeLatLongLines(FileWriter inWriter, ThreeDModel inModel, String inLineSeparator)
throws IOException
{
inWriter.write("// Latitude and longitude lines:");
* @param inLineSeparator line separator to use
* @throws IOException on file writing error
*/
- private void writeDataPointsBallsAndSticks(FileWriter inWriter, ThreeDModel inModel, String inLineSeparator)
+ private static void writeDataPointsBallsAndSticks(FileWriter inWriter, ThreeDModel inModel, String inLineSeparator)
throws IOException
{
inWriter.write("// Data points:");
* @param inLineSeparator line separator to use
* @throws IOException on file writing error
*/
- private void writeDataPointsTubesAndWalls(FileWriter inWriter, ThreeDModel inModel, String inLineSeparator)
+ private static void writeDataPointsTubesAndWalls(FileWriter inWriter, ThreeDModel inModel, String inLineSeparator)
throws IOException
{
inWriter.write("// Data points:");
*/
private static byte checkHeightCode(byte inCode)
{
- final byte maxHeightCode = 4;
+ final byte maxHeightCode = 5;
if (inCode < 0) return 0;
if (inCode > maxHeightCode) return maxHeightCode;
return inCode;
Object[] buttonTexts = {I18nManager.getText("button.continue"), I18nManager.getText("button.cancel")};
if (_track.getNumPoints() > MAX_TRACK_SIZE && !TRACK_SIZE_WARNING_GIVEN)
{
- if (JOptionPane.showOptionDialog(_frame,
+ // FIXME: Change text reference from exportpov to java3d
+ if (JOptionPane.showOptionDialog(_parentFrame,
I18nManager.getText("dialog.exportpov.warningtracksize"),
- I18nManager.getText("function.exportpov"), JOptionPane.OK_CANCEL_OPTION,
+ I18nManager.getText("function.show3d"), JOptionPane.OK_CANCEL_OPTION,
JOptionPane.WARNING_MESSAGE, null, buttonTexts, buttonTexts[1])
== JOptionPane.OK_OPTION)
{
{
private Track _track = null;
private PointScaler _scaler = null;
- private double _modelSize;
private double _scaleFactor = 1.0;
private double _altFactor = 1.0;
// MAYBE: How to store rods (lifts) in data?
private byte[] _pointTypes = null;
private byte[] _pointHeights = null;
- private static final double DEFAULT_MODEL_SIZE = 10.0;
+ private static final double MODEL_SIZE = 10.0;
// Constants for point types
public static final byte POINT_TYPE_WAYPOINT = 1;
* @param inTrack Track object
*/
public ThreeDModel(Track inTrack)
- {
- this(inTrack, DEFAULT_MODEL_SIZE);
- }
-
-
- /**
- * Constructor
- * @param inTrack Track object
- * @param inSize model size
- */
- public ThreeDModel(Track inTrack, double inSize)
{
_track = inTrack;
- _modelSize = inSize;
- if (_modelSize <= 0.0) _modelSize = DEFAULT_MODEL_SIZE;
}
if (_scaler.getMaximumHoriz() > _scaler.getMaximumVert())
{
// scale limited by longitude
- _scaleFactor = _modelSize / _scaler.getMaximumHoriz();
+ _scaleFactor = MODEL_SIZE / _scaler.getMaximumHoriz();
}
else
{
// scale limited by latitude
- _scaleFactor = _modelSize / _scaler.getMaximumVert();
+ _scaleFactor = MODEL_SIZE / _scaler.getMaximumVert();
}
}
// cap altitude scale factor if it's too big
double maxScaledAlt = _scaler.getMaxScaledAlt() * _altFactor;
- if (maxScaledAlt > _modelSize) {
+ if (maxScaledAlt > MODEL_SIZE) {
// capped
- _altFactor = _altFactor * _modelSize / maxScaledAlt;
+ _altFactor = _altFactor * MODEL_SIZE / maxScaledAlt;
}
// calculate lat/long lines
_scaler.calculateLatLongLines();
*/
public double getModelSize()
{
- return _modelSize;
+ return MODEL_SIZE;
}
}
{
// Perform the inverse operation
final int numPoints = _altitudes.length;
- for (int i=0; i<numPoints; i++) {
+ for (int i=0; i<numPoints; i++)
+ {
DataPoint point = inTrackInfo.getTrack().getPoint(i+_startIndex);
point.getAltitude().reset(_altitudes[i]);
point.setModified(true);
import tim.prune.data.TrackInfo;\r
\r
/**\r
- * Operation to undo a track compression\r
+ * Operation to undo the deletion of marked points\r
*/\r
-public class UndoCompress implements UndoOperation\r
+public class UndoDeleteMarked implements UndoOperation\r
{\r
private DataPoint[] _contents = null;\r
protected int _numPointsDeleted = -1;\r
* Constructor\r
* @param inTrack track contents to copy\r
*/\r
- public UndoCompress(Track inTrack)\r
+ public UndoDeleteMarked(Track inTrack)\r
{\r
_contents = inTrack.cloneContents();\r
// Copy boolean segment start flags\r
*/\r
public String getDescription()\r
{\r
- String desc = I18nManager.getText("undo.compress");\r
+ String desc = I18nManager.getText("undo.deletemarked");\r
if (_numPointsDeleted > 0)\r
desc = desc + " (" + _numPointsDeleted + ")";\r
return desc;\r
// Copy boolean segment start flags\r
Track track = inTrackInfo.getTrack();\r
if (_segmentStarts.length != track.getNumPoints())\r
- throw new UndoException("Cannot undo compress - track length no longer matches");\r
+ throw new UndoException("Cannot undo delete - track length no longer matches");\r
for (int i=0; i<_segmentStarts.length; i++) {\r
track.getPoint(i).setSegmentStart(_segmentStarts[i]);\r
}\r
private int _pointIndex = -1;\r
private DataPoint _point = null;\r
private int _photoIndex = -1;\r
+ private int _audioIndex = -1;\r
private boolean _segmentStart = false;\r
\r
\r
* @param inPointIndex index number of point within track\r
* @param inPoint data point\r
* @param inPhotoIndex index number of photo within photo list\r
+ * @param inAudioIndex index number of audio within audio list\r
* @param inSegmentStart true if following track point starts new segment\r
*/\r
- public UndoDeletePoint(int inPointIndex, DataPoint inPoint, int inPhotoIndex, boolean inSegmentStart)\r
+ public UndoDeletePoint(int inPointIndex, DataPoint inPoint, int inPhotoIndex, int inAudioIndex,\r
+ boolean inSegmentStart)\r
{\r
_pointIndex = inPointIndex;\r
_point = inPoint;\r
_photoIndex = inPhotoIndex;\r
+ _audioIndex = inAudioIndex;\r
_segmentStart = inSegmentStart;\r
}\r
\r
_point.getPhoto().setDataPoint(_point);\r
}\r
}\r
+ // Re-add audio as well if necessary\r
+ if (_point.getAudio() != null && _audioIndex > -1)\r
+ {\r
+ // add audio object to list\r
+ inTrackInfo.getAudioList().addAudio(_point.getAudio(), _audioIndex);\r
+ _point.getAudio().setDataPoint(_point);\r
+ }\r
// Restore previous status of following track point if necessary\r
if (!_segmentStart)\r
{\r
package tim.prune.undo;\r
\r
import tim.prune.I18nManager;\r
+import tim.prune.data.AudioList;\r
import tim.prune.data.DataPoint;\r
import tim.prune.data.PhotoList;\r
import tim.prune.data.TrackInfo;\r
*/\r
public class UndoDeleteRange implements UndoOperation\r
{\r
- private int _startIndex = -1;\r
- private DataPoint[] _points = null;\r
+ /**\r
+ * Inner class to hold a single range information set\r
+ */\r
+ class RangeInfo\r
+ {\r
+ public int _startIndex = -1;\r
+ public DataPoint[] _points = null;\r
+ public DataPoint _nextTrackPoint = null;\r
+ public boolean _segmentStart = false;\r
+\r
+ /**\r
+ * @param inPoint next track point after deleted section, or null\r
+ */\r
+ public void setNextTrackPoint(DataPoint inPoint)\r
+ {\r
+ _nextTrackPoint = inPoint;\r
+ if (inPoint != null) {\r
+ _segmentStart = inPoint.getSegmentStart();\r
+ }\r
+\r
+ }\r
+\r
+ /**\r
+ * @return true if the range is valid\r
+ */\r
+ public boolean isValid()\r
+ {\r
+ return _startIndex >= 0 && _points != null && _points.length > 0;\r
+ }\r
+ }\r
+\r
+\r
+ // Instance variables for UndoDeleteRange\r
+ private RangeInfo _rangeInfo1 = null;\r
+ private RangeInfo _rangeInfo2 = null;\r
private PhotoList _photoList = null;\r
- private DataPoint _nextTrackPoint = null;\r
- private boolean _segmentStart = false;\r
+ private AudioList _audioList = null;\r
+ private String _nameKey = null;\r
+ private int _totalDeleted = 0;\r
\r
\r
/**\r
* Constructor\r
* @param inTrackInfo track info object\r
+ * @param inNameKey key to use for undo text\r
+ * @param inStartIndex1 start index of first deleted segment\r
+ * @param inDeleteMedias1 flags to delete media for range1\r
+ * @param inStartIndex2 start index of second segment\r
+ * @param inDeleteMedias2 flags to delete media for range2\r
*/\r
- public UndoDeleteRange(TrackInfo inTrackInfo)\r
+ public UndoDeleteRange(TrackInfo inTrackInfo, String inNameKey,\r
+ int inStartIndex1, boolean[] inDeleteMedias1,\r
+ int inStartIndex2, boolean[] inDeleteMedias2)\r
{\r
- _startIndex = inTrackInfo.getSelection().getStart();\r
- _points = inTrackInfo.cloneSelectedRange();\r
- _photoList = inTrackInfo.getPhotoList().cloneList();\r
- // Save segment flag of following track point\r
- _nextTrackPoint = inTrackInfo.getTrack().getNextTrackPoint(_startIndex + _points.length);\r
- if (_nextTrackPoint != null) {\r
- _segmentStart = _nextTrackPoint.getSegmentStart();\r
+ _nameKey = inNameKey;\r
+ boolean mediaDeleted = false;\r
+ _totalDeleted = 0;\r
+ // Check if there's a valid first range\r
+ if (inStartIndex1 >= 0 && inDeleteMedias1 != null)\r
+ {\r
+ final int numPoints = inDeleteMedias1.length;\r
+ if (numPoints > 0)\r
+ {\r
+ _totalDeleted += numPoints;\r
+ _rangeInfo1 = new RangeInfo();\r
+ _rangeInfo1._startIndex = inStartIndex1;\r
+\r
+ for (int i=0; i<numPoints && !mediaDeleted; i++) {\r
+ if (inDeleteMedias1[i]) mediaDeleted = true;\r
+ }\r
+ // Clone points\r
+ _rangeInfo1._points = inTrackInfo.getTrack().cloneRange(inStartIndex1, inStartIndex1 + numPoints - 1);\r
+ // Save segment flag of following track point\r
+ _rangeInfo1.setNextTrackPoint(inTrackInfo.getTrack().getNextTrackPoint(inStartIndex1 + numPoints));\r
+ }\r
+ }\r
+ // And the same for the second range, if any\r
+ if (inStartIndex2 >= 0 && inDeleteMedias2 != null)\r
+ {\r
+ final int numPoints = inDeleteMedias2.length;\r
+ if (numPoints > 0)\r
+ {\r
+ _totalDeleted += numPoints;\r
+ _rangeInfo2 = new RangeInfo();\r
+ _rangeInfo2._startIndex = inStartIndex2;\r
+ for (int i=0; i<numPoints && !mediaDeleted; i++) {\r
+ if (inDeleteMedias2[i]) mediaDeleted = true;\r
+ }\r
+\r
+ // Clone points\r
+ _rangeInfo2._points = inTrackInfo.getTrack().cloneRange(inStartIndex2, inStartIndex2 + numPoints - 1);\r
+ // Save segment flag of following track point\r
+ _rangeInfo2.setNextTrackPoint(inTrackInfo.getTrack().getNextTrackPoint(inStartIndex2 + numPoints));\r
+ }\r
+ }\r
+ // If any media have been deleted, then the lists must be copied\r
+ if (mediaDeleted)\r
+ {\r
+ _photoList = inTrackInfo.getPhotoList().cloneList();\r
+ _audioList = inTrackInfo.getAudioList().cloneList();\r
}\r
}\r
\r
\r
/**\r
- * @return description of operation including range length\r
+ * @return description of operation including number of points deleted\r
*/\r
public String getDescription()\r
{\r
- return I18nManager.getText("undo.deleterange")\r
- + " (" + _points.length + ")";\r
+ return I18nManager.getText(_nameKey) + " (" + _totalDeleted + ")";\r
}\r
\r
\r
*/\r
public void performUndo(TrackInfo inTrackInfo)\r
{\r
- // restore photos to how they were before\r
- inTrackInfo.getPhotoList().restore(_photoList);\r
- // reconnect photos to points\r
- for (int i=0; i<_points.length; i++)\r
+ // restore photos and audios to how they were before\r
+ if (_photoList != null) {\r
+ inTrackInfo.getPhotoList().restore(_photoList);\r
+ }\r
+ if (_audioList != null) {\r
+ inTrackInfo.getAudioList().restore(_audioList);\r
+ }\r
+\r
+ // Undo both the ranges\r
+ performUndo(inTrackInfo, _rangeInfo1);\r
+ performUndo(inTrackInfo, _rangeInfo2);\r
+ }\r
+\r
+ /**\r
+ * Perform the undo on a single deleted range\r
+ * @param inTrackInfo track info object\r
+ * @param inRangeInfo info object describing deleted range\r
+ */\r
+ private void performUndo(TrackInfo inTrackInfo, RangeInfo inRangeInfo)\r
+ {\r
+ if (inRangeInfo == null || !inRangeInfo.isValid()) return;\r
+\r
+ // reconnect photos and audios to points\r
+ final int numPoints = inRangeInfo._points.length;\r
+ for (int i=0; i<numPoints; i++)\r
{\r
- DataPoint point = _points[i];\r
- if (point != null && point.getPhoto() != null)\r
+ DataPoint point = inRangeInfo._points[i];\r
+ if (point != null && point.hasMedia())\r
{\r
- point.getPhoto().setDataPoint(point);\r
+ if (point.getPhoto() != null) {\r
+ point.getPhoto().setDataPoint(point);\r
+ }\r
+ if (point.getAudio() != null) {\r
+ point.getAudio().setDataPoint(point);\r
+ }\r
}\r
}\r
// restore point array into track\r
- inTrackInfo.getTrack().insertRange(_points, _startIndex);\r
+ inTrackInfo.getTrack().insertRange(inRangeInfo._points, inRangeInfo._startIndex);\r
// Restore segment flag of following track point\r
- if (_nextTrackPoint != null) {\r
- _nextTrackPoint.setSegmentStart(_segmentStart);\r
+ if (inRangeInfo._nextTrackPoint != null) {\r
+ inRangeInfo._nextTrackPoint.setSegmentStart(inRangeInfo._segmentStart);\r
}\r
}\r
-}
\ No newline at end of file
+}\r
\r
import tim.prune.I18nManager;\r
import tim.prune.data.DataPoint;\r
+import tim.prune.data.Field;\r
import tim.prune.data.TrackInfo;\r
import tim.prune.function.edit.FieldEditList;\r
\r
public String getDescription()\r
{\r
String desc = I18nManager.getText("undo.editpoint");\r
- String newName = _undoFieldList.getEdit(0).getValue();\r
+ String newName = null;\r
+ if (_undoFieldList.getEdit(0).getField() == Field.WAYPT_NAME)\r
+ newName = _undoFieldList.getEdit(0).getValue();\r
String pointName = _originalPoint.getWaypointName();\r
if (newName != null && !newName.equals(""))\r
desc = desc + " " + newName;\r
import tim.prune.data.TrackInfo;\r
\r
/**\r
- * Operation to undo an insertion (eg interpolate, average)\r
+ * Operation to undo an insertion (eg average)\r
*/\r
public class UndoInsert implements UndoOperation\r
{\r
--- /dev/null
+package tim.prune.undo;\r
+\r
+import tim.prune.I18nManager;\r
+import tim.prune.data.DataPoint;\r
+import tim.prune.data.TrackInfo;\r
+\r
+/**\r
+ * Operation to undo an interpolation\r
+ */\r
+public class UndoInterpolate implements UndoOperation\r
+{\r
+ private int _startIndex = 0;\r
+ private int _totalInserted = 0;\r
+ private DataPoint[] _points = null;\r
+\r
+\r
+ /**\r
+ * Constructor\r
+ * @param inTrackInfo track info object\r
+ * @param inTotalInserted total number of points inserted\r
+ */\r
+ public UndoInterpolate(TrackInfo inTrackInfo, int inTotalInserted)\r
+ {\r
+ _startIndex = inTrackInfo.getSelection().getStart();\r
+ _points = inTrackInfo.cloneSelectedRange();\r
+ _totalInserted = inTotalInserted;\r
+ }\r
+\r
+\r
+ /**\r
+ * @return description of operation including parameters\r
+ */\r
+ public String getDescription()\r
+ {\r
+ return I18nManager.getText("undo.insert") + " (" + _totalInserted + ")";\r
+ }\r
+\r
+\r
+ /**\r
+ * Perform the undo operation on the given TrackInfo\r
+ * @param inTrackInfo TrackInfo object on which to perform the operation\r
+ */\r
+ public void performUndo(TrackInfo inTrackInfo) throws UndoException\r
+ {\r
+ // Work out how many points were in the track before the interpolation\r
+ final int newSize = inTrackInfo.getTrack().getNumPoints() - _totalInserted;\r
+ DataPoint[] oldPoints = inTrackInfo.getTrack().cloneContents();\r
+ DataPoint[] newPoints = new DataPoint[newSize];\r
+\r
+ // Restore track to previous values\r
+ System.arraycopy(oldPoints, 0, newPoints, 0, _startIndex);\r
+ System.arraycopy(_points, 0, newPoints, _startIndex, _points.length);\r
+ int endIndex = _startIndex + _points.length;\r
+ System.arraycopy(oldPoints, endIndex + _totalInserted, newPoints, endIndex, newSize - endIndex);\r
+\r
+ inTrackInfo.getTrack().replaceContents(newPoints);\r
+ // reset selection\r
+ inTrackInfo.getSelection().clearAll();\r
+ }\r
+}\r
package tim.prune.undo;\r
\r
import tim.prune.I18nManager;\r
+import tim.prune.data.DataPoint;\r
+import tim.prune.data.Photo;\r
import tim.prune.data.TrackInfo;\r
\r
/**\r
cropIndex = inTrackInfo.getTrack().getNumPoints() - _numPoints;\r
inTrackInfo.getTrack().cropTo(cropIndex);\r
}\r
+ else\r
+ {\r
+ // Loop through the points (if any) and detach them\r
+ for (int i=0; i<_numPhotos; i++)\r
+ {\r
+ Photo photo = inTrackInfo.getPhotoList().getPhoto(inTrackInfo.getPhotoList().getNumPhotos() - 1 - i);\r
+ if (photo.isConnected()) {\r
+ DataPoint point = photo.getDataPoint();\r
+ if (point != null) {point.setPhoto(null);}\r
+ }\r
+ }\r
+ }\r
// crop photo list to previous size\r
cropIndex = inTrackInfo.getPhotoList().getNumPhotos() - _numPhotos;\r
inTrackInfo.getPhotoList().cropTo(cropIndex);\r
// Make arrays of points and altitudes
_points = new DataPoint[numPoints];
_altitudes = new String[numPoints];
- for (int i=0; i<numPoints; i++) {
+ for (int i=0; i<numPoints; i++)
+ {
DataPoint point = track.getPoint(i);
- if (!point.hasAltitude() || point.getAltitude().getValue() == 0) {
+ if (!point.hasAltitude() || point.getAltitude().getValue() == 0)
+ {
_points[i] = point;
if (point.hasAltitude()) {
_altitudes[i] = point.getFieldValue(Field.ALTITUDE);