package tim.prune;
+import java.io.File;
import java.util.ArrayList;
import java.util.EmptyStackException;
import java.util.Set;
import java.util.Stack;
-import java.io.File;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import tim.prune.data.Altitude;
-import tim.prune.data.Coordinate;
import tim.prune.data.DataPoint;
import tim.prune.data.Field;
import tim.prune.data.LatLonRectangle;
-import tim.prune.data.Latitude;
-import tim.prune.data.Longitude;
import tim.prune.data.NumberUtils;
import tim.prune.data.Photo;
import tim.prune.data.PhotoList;
+import tim.prune.data.SourceInfo;
import tim.prune.data.Track;
import tim.prune.data.TrackInfo;
import tim.prune.function.browser.BrowserLauncher;
import tim.prune.load.JpegLoader;
import tim.prune.save.ExifSaver;
import tim.prune.save.FileSaver;
-import tim.prune.undo.*;
+import tim.prune.undo.UndoAddAltitudeOffset;
+import tim.prune.undo.UndoAddTimeOffset;
+import tim.prune.undo.UndoCompress;
+import tim.prune.undo.UndoConnectPhoto;
+import tim.prune.undo.UndoCreatePoint;
+import tim.prune.undo.UndoCutAndMove;
+import tim.prune.undo.UndoDeletePhoto;
+import tim.prune.undo.UndoDeletePoint;
+import tim.prune.undo.UndoDeleteRange;
+import tim.prune.undo.UndoDisconnectPhoto;
+import tim.prune.undo.UndoEditPoint;
+import tim.prune.undo.UndoException;
+import tim.prune.undo.UndoInsert;
+import tim.prune.undo.UndoLoad;
+import tim.prune.undo.UndoLoadPhotos;
+import tim.prune.undo.UndoMergeTrackSegments;
+import tim.prune.undo.UndoOperation;
+import tim.prune.undo.UndoReverseSection;
/**
else
{
if (_fileSaver == null) {
- _fileSaver = new FileSaver(this, _frame, _track);
+ _fileSaver = new FileSaver(this, _frame);
}
char delim = ',';
if (_fileLoader != null) {delim = _fileLoader.getLastUsedDelimiter();}
// add information to undo stack
UndoOperation undo = new UndoEditPoint(currentPoint, inUndoList);
// pass to track for completion
- if (_track.editPoint(currentPoint, inEditList))
+ if (_track.editPoint(currentPoint, inEditList, false))
{
_undoStack.push(undo);
// Confirm point edit
/**
- * Create a new point at the given lat/long coordinates
- * @param inLat latitude
- * @param inLong longitude
+ * Create a new point at the given position
+ * @param inPoint point to add
*/
- public void createPoint(double inLat, double inLong)
+ public void createPoint(DataPoint inPoint)
{
// create undo object
UndoCreatePoint undo = new UndoCreatePoint();
- // create point and add to track
- DataPoint point = new DataPoint(new Latitude(inLat, Coordinate.FORMAT_NONE), new Longitude(inLong, Coordinate.FORMAT_NONE), null);
- point.setSegmentStart(true);
- _track.appendPoints(new DataPoint[] {point});
+ // add point to track
+ inPoint.setSegmentStart(true);
+ _track.appendPoints(new DataPoint[] {inPoint});
+ // ensure track's field list contains point's fields
+ _track.extendFieldList(inPoint.getFieldList());
_trackInfo.selectPoint(_trackInfo.getTrack().getNumPoints()-1);
// add undo object to stack
_undoStack.add(undo);
* @param inFieldArray array of fields
* @param inDataArray array of data
* @param inAltFormat altitude format
- * @param inFilename filename used
+ * @param inSourceInfo information about the source of the data
*/
public void informDataLoaded(Field[] inFieldArray, Object[][] inDataArray, Altitude.Format inAltFormat,
- String inFilename)
+ SourceInfo inSourceInfo)
{
// Check whether loaded array can be properly parsed into a Track
Track loadedTrack = new Track();
// append data to current Track
_undoStack.add(new UndoLoad(_track.getNumPoints(), loadedTrack.getNumPoints()));
_track.combine(loadedTrack);
- // set filename if currently empty
- if (_trackInfo.getFileInfo().getNumFiles() == 0)
- {
- _trackInfo.getFileInfo().setFile(inFilename);
- }
- else
- {
- _trackInfo.getFileInfo().addFile();
- }
+ // set source information
+ inSourceInfo.populatePointObjects(_track, loadedTrack.getNumPoints());
+ _trackInfo.getFileInfo().addSource(inSourceInfo);
}
else if (answer == JOptionPane.NO_OPTION)
{
_lastSavePosition = _undoStack.size();
_trackInfo.getSelection().clearAll();
_track.load(loadedTrack);
- _trackInfo.getFileInfo().setFile(inFilename);
+ inSourceInfo.populatePointObjects(_track, _track.getNumPoints());
+ _trackInfo.getFileInfo().replaceSource(inSourceInfo);
if (photos != null)
{
_trackInfo.getPhotoList().removeCorrelatedPhotos();
_lastSavePosition = _undoStack.size();
_trackInfo.getSelection().clearAll();
_track.load(loadedTrack);
- _trackInfo.getFileInfo().setFile(inFilename);
+ inSourceInfo.populatePointObjects(_track, _track.getNumPoints());
+ _trackInfo.getFileInfo().addSource(inSourceInfo);
}
UpdateMessageBroker.informSubscribers();
// Update status bar
- UpdateMessageBroker.informSubscribers(I18nManager.getText("confirm.loadfile") + " '" + inFilename + "'");
+ UpdateMessageBroker.informSubscribers(I18nManager.getText("confirm.loadfile") + " '" + inSourceInfo.getName() + "'");
// update menu
_menuManager.informFileLoaded();
// load next file if there's a queue
DataPoint point = _trackInfo.getCurrentPoint();
if (photo != null && point != null)
{
- if (point.getPhoto() != null)
- {
- // point already has a photo, confirm cloning of new point
- if (JOptionPane.showConfirmDialog(_frame,
- I18nManager.getText("dialog.connectphoto.clonepoint"),
- I18nManager.getText("dialog.connect.title"),
- JOptionPane.OK_CANCEL_OPTION) == JOptionPane.OK_OPTION)
- {
- // Create undo, clone point and attach
- int pointIndex = _trackInfo.getSelection().getCurrentPointIndex() + 1;
- // insert new point after current one
- point = point.clonePoint();
- UndoConnectPhotoWithClone undo = new UndoConnectPhotoWithClone(
- point, photo.getFile().getName(), pointIndex);
- _track.insertPoint(point, pointIndex);
- photo.setDataPoint(point);
- point.setPhoto(photo);
- _undoStack.add(undo);
- UpdateMessageBroker.informSubscribers(DataSubscriber.SELECTION_CHANGED);
- UpdateMessageBroker.informSubscribers(I18nManager.getText("confirm.photo.connect"));
- }
- }
- else
+ if (point.getPhoto() == null)
{
// point doesn't currently have a photo, so just connect it
_undoStack.add(new UndoConnectPhoto(point, photo.getFile().getName()));
import java.io.IOException;
+import tim.prune.config.Config;
+
/**
* Class to manage interfaces to external tools, like exiftool
*/
private static boolean check(String inCommand)
{
- // System.out.println("Checking tool '" + inCommand + "'");
try
{
Runtime.getRuntime().exec(inCommand);
package tim.prune;
import tim.prune.correlate.PhotoCorrelator;
-import tim.prune.function.AboutScreen;
-import tim.prune.function.AddAltitudeOffset;
-import tim.prune.function.AddTimeOffset;
-import tim.prune.function.CheckVersionScreen;
-import tim.prune.function.FindWaypoint;
-import tim.prune.function.HelpScreen;
-import tim.prune.function.RearrangeWaypointsFunction;
-import tim.prune.function.SaveConfig;
-import tim.prune.function.SetKmzImageSize;
-import tim.prune.function.SetMapBgFunction;
-import tim.prune.function.ShowKeysScreen;
-import tim.prune.function.ShowThreeDFunction;
+import tim.prune.function.*;
import tim.prune.function.charts.Charter;
import tim.prune.function.compress.CompressTrackFunction;
import tim.prune.function.distance.DistanceFunction;
import tim.prune.function.edit.PointNameEditor;
import tim.prune.function.gpsies.GetGpsiesFunction;
-import tim.prune.function.SetPathsFunction;
import tim.prune.load.GpsLoader;
import tim.prune.save.GpsSaver;
import tim.prune.save.GpxExporter;
public static GenericFunction FUNCTION_SAVECONFIG = null;
public static GenericFunction FUNCTION_EDIT_WAYPOINT_NAME = null;
public static RearrangeWaypointsFunction FUNCTION_REARRANGE_WAYPOINTS = null;
+ public static GenericFunction FUNCTION_REARRANGE_PHOTOS = null;
public static GenericFunction FUNCTION_COMPRESS = null;
public static GenericFunction FUNCTION_ADD_TIME_OFFSET = null;
public static GenericFunction FUNCTION_ADD_ALTITUDE_OFFSET = null;
+ public static GenericFunction FUNCTION_CONVERT_NAMES_TO_TIMES = null;
+ public static GenericFunction FUNCTION_PASTE_COORDINATES = null;
public static GenericFunction FUNCTION_FIND_WAYPOINT = null;
+ public static GenericFunction FUNCTION_DUPLICATE_POINT = null;
public static GenericFunction FUNCTION_CORRELATE_PHOTOS = null;
+ public static GenericFunction FUNCTION_ROTATE_PHOTO_LEFT = null;
+ public static GenericFunction FUNCTION_ROTATE_PHOTO_RIGHT = null;
+ public static GenericFunction FUNCTION_IGNORE_EXIF_THUMB = null;
public static GenericFunction FUNCTION_CHARTS = null;
public static GenericFunction FUNCTION_3D = null;
public static GenericFunction FUNCTION_DISTANCES = null;
+ public static GenericFunction FUNCTION_FULL_RANGE_DETAILS = null;
public static GenericFunction FUNCTION_GET_GPSIES = null;
public static GenericFunction FUNCTION_SET_MAP_BG = null;
public static GenericFunction FUNCTION_SET_PATHS = null;
public static GenericFunction FUNCTION_SET_KMZ_IMAGE_SIZE = null;
+ public static GenericFunction FUNCTION_SET_COLOURS = null;
+ public static GenericFunction FUNCTION_SET_LANGUAGE = null;
public static GenericFunction FUNCTION_HELP = null;
public static GenericFunction FUNCTION_SHOW_KEYS = null;
public static GenericFunction FUNCTION_ABOUT = null;
FUNCTION_SAVECONFIG = new SaveConfig(inApp);
FUNCTION_EDIT_WAYPOINT_NAME = new PointNameEditor(inApp);
FUNCTION_REARRANGE_WAYPOINTS = new RearrangeWaypointsFunction(inApp);
+ FUNCTION_REARRANGE_PHOTOS = new RearrangePhotosFunction(inApp);
FUNCTION_COMPRESS = new CompressTrackFunction(inApp);
FUNCTION_ADD_TIME_OFFSET = new AddTimeOffset(inApp);
FUNCTION_ADD_ALTITUDE_OFFSET = new AddAltitudeOffset(inApp);
+ FUNCTION_CONVERT_NAMES_TO_TIMES = new ConvertNamesToTimes(inApp);
+ FUNCTION_PASTE_COORDINATES = new PasteCoordinates(inApp);
FUNCTION_FIND_WAYPOINT = new FindWaypoint(inApp);
+ FUNCTION_DUPLICATE_POINT = new DuplicatePoint(inApp);
FUNCTION_CORRELATE_PHOTOS = new PhotoCorrelator(inApp);
+ FUNCTION_ROTATE_PHOTO_LEFT = new RotatePhoto(inApp, false);
+ FUNCTION_ROTATE_PHOTO_RIGHT = new RotatePhoto(inApp, true);
+ FUNCTION_IGNORE_EXIF_THUMB = new IgnoreExifThumb(inApp);
FUNCTION_CHARTS = new Charter(inApp);
FUNCTION_3D = new ShowThreeDFunction(inApp);
FUNCTION_DISTANCES = new DistanceFunction(inApp);
+ FUNCTION_FULL_RANGE_DETAILS = new FullRangeDetails(inApp);
FUNCTION_GET_GPSIES = new GetGpsiesFunction(inApp);
FUNCTION_SET_MAP_BG = new SetMapBgFunction(inApp);
FUNCTION_SET_PATHS = new SetPathsFunction(inApp);
FUNCTION_SET_KMZ_IMAGE_SIZE = new SetKmzImageSize(inApp);
+ FUNCTION_SET_COLOURS = new SetColours(inApp);
+ FUNCTION_SET_LANGUAGE = new SetLanguage(inApp);
FUNCTION_HELP = new HelpScreen(inApp);
FUNCTION_SHOW_KEYS = new ShowKeysScreen(inApp);
FUNCTION_ABOUT = new AboutScreen(inApp);
import javax.swing.JToolBar;
import javax.swing.WindowConstants;
+import tim.prune.config.Config;
+import tim.prune.config.ConfigException;
import tim.prune.gui.DetailsDisplay;
import tim.prune.gui.IconManager;
import tim.prune.gui.MenuManager;
import tim.prune.gui.map.MapCanvas;
/**
- * Tool to visualize, edit, convert and prune GPS data
+ * Prune 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 and made available through the Gnu GPL
+ * This software is copyright activityworkshop.net 2006-2010 and made available through the Gnu GPL version 2.
+ * For license details please see the included license.txt.
+ * GpsPruner is the main entry point to the application, including initialisation and launch
*/
public class GpsPruner
{
/** Version number of application, used in about screen and for version check */
- public static final String VERSION_NUMBER = "8";
+ public static final String VERSION_NUMBER = "9";
/** Build number, just used for about screen */
- public static final String BUILD_NUMBER = "155";
+ public static final String BUILD_NUMBER = "176";
/** Static reference to App object */
private static App APP = null;
catch (ConfigException ce) {
System.err.println("Failed to load config file: " + configFilename);
}
- if (locale != null) {
+ boolean overrideLang = (locale != null);
+ if (overrideLang) {
// Make sure Config holds chosen language
Config.setConfigString(Config.KEY_LANGUAGE_CODE, localeCode);
}
}
}
I18nManager.init(locale);
- if (langFilename != null) {
+ // Load the external language file, either from config file or from command line params
+ if (langFilename == null && !overrideLang) {
+ // If langfilename is blank on command line parameters then don't use setting from config
+ langFilename = Config.getConfigString(Config.KEY_LANGUAGE_FILE);
+ }
+ if (langFilename != null && !langFilename.equals("")) {
try {
I18nManager.addLanguageFile(langFilename);
+ Config.setConfigString(Config.KEY_LANGUAGE_FILE, langFilename);
}
catch (FileNotFoundException fnfe) {
System.err.println("Failed to load language file: " + langFilename);
*/
public static String getText(String inKey)
{
- String value = null;
// look in external props file if available
- if (ExternalPropsFile != null)
+ if (ExternalPropsFile != null && ExternalPropsFile.containsKey(inKey))
{
- value = ExternalPropsFile.getProperty(inKey);
- if (value != null && !value.equals(""))
- return value;
+ return ExternalPropsFile.getProperty(inKey);
}
// look in extra texts if available
if (LocalTexts != null)
{
try
{
- value = LocalTexts.getString(inKey);
- if (value != null && !value.equals(""))
- return value;
+ if (LocalTexts.containsKey(inKey)) {
+ return LocalTexts.getString(inKey);
+ }
}
catch (MissingResourceException mre) {}
}
{
try
{
- value = EnglishTexts.getString(inKey);
- if (value != null && !value.equals(""))
- return value;
+ if (EnglishTexts.containsKey(inKey)) {
+ return EnglishTexts.getString(inKey);
+ }
}
catch (MissingResourceException mre) {}
}
--- /dev/null
+package tim.prune.config;
+
+import java.awt.Color;
+
+/**
+ * Class to hold a colour scheme for Prune, including
+ * colours for background, points, selections and texts
+ */
+public class ColourScheme
+{
+ // Current colours
+ private Color[] _colours = new Color[NUM_COLOURS];
+
+ // Default colours
+ private static final Color[] DEFAULT_COLOURS = {Color.WHITE, Color.BLUE, Color.GREEN,
+ Color.BLACK, Color.RED, Color.ORANGE, Color.BLACK, Color.GRAY};
+
+ // Colour indices
+ public static final int IDX_BACKGROUND = 0;
+ public static final int IDX_POINT = 1;
+ public static final int IDX_SELECTION = 2;
+ public static final int IDX_TEXT = 3;
+ public static final int IDX_PRIMARY = 4;
+ public static final int IDX_SECONDARY = 5;
+ public static final int IDX_BORDERS = 6;
+ public static final int IDX_LINES = 7;
+ // Number of colours
+ private static final int NUM_COLOURS = 8;
+
+
+ /**
+ * Load the colour scheme from the given String
+ * @param inCodes comma-separated hex codes describing colours
+ */
+ public void loadFromHex(String inCodes)
+ {
+ if (inCodes != null && inCodes.length() > 5)
+ {
+ String[] codes = inCodes.split(",");
+ final int numCodes = (codes.length > NUM_COLOURS ? NUM_COLOURS : codes.length);
+ for (int i=0; i<numCodes; i++) {
+ _colours[i] = ColourUtils.colourFromHex(codes[i]);
+ }
+ }
+ }
+
+ /**
+ * @return colour to use for given index
+ */
+ public Color getColour(int inIndex)
+ {
+ assert (inIndex >= 0 && inIndex < NUM_COLOURS);
+ Color currColour = _colours[inIndex];
+ return (currColour != null ? currColour : DEFAULT_COLOURS[inIndex]);
+ }
+
+ /**
+ * @return default colour for given index
+ */
+ public static Color getDefaultColour(int inIndex)
+ {
+ assert (inIndex >= 0 && inIndex < NUM_COLOURS);
+ return DEFAULT_COLOURS[inIndex];
+ }
+
+ /**
+ * Edit one of the colours to a new value
+ * @param inIndex index of colour
+ * @param inColour colour to set
+ */
+ public void setColour(int inIndex, Color inColour)
+ {
+ assert (inIndex >= 0 && inIndex < NUM_COLOURS);
+ _colours[inIndex] = inColour;
+ }
+
+ /**
+ * @return colour scheme as string of concatenated hex codes
+ */
+ public String toString()
+ {
+ StringBuffer buff = new StringBuffer();
+ for (int i=0; i<NUM_COLOURS; i++) {
+ buff.append(ColourUtils.makeHexCode(getColour(i)));
+ buff.append(',');
+ }
+ return buff.toString();
+ }
+}
--- /dev/null
+package tim.prune.config;
+
+import java.awt.Color;
+
+/**
+ * Class to hold static methods for handling colours
+ * including converting to and from hex code Strings
+ */
+public abstract class ColourUtils
+{
+ /**
+ * Convert a string into a Color object
+ * @param inValue 6-character hex code
+ * @return corresponding colour
+ */
+ public static Color colourFromHex(String inValue)
+ {
+ Color retVal = null;
+ if (inValue != null && inValue.length() == 6)
+ {
+ try
+ {
+ final int redness = convertToInt(inValue.substring(0, 2));
+ final int greenness = convertToInt(inValue.substring(2, 4));
+ final int blueness = convertToInt(inValue.substring(4, 6));
+ retVal = new Color(redness, greenness, blueness);
+ }
+ catch (NumberFormatException nfe) {} // colour stays null
+ }
+ return retVal;
+ }
+
+ /**
+ * @param inPair two-digit String representing hex code
+ * @return corresponding integer (0 to 255)
+ */
+ private static int convertToInt(String inPair)
+ {
+ int val = Integer.parseInt(inPair, 16);
+ if (val < 0) val = 0;
+ return val;
+ }
+
+ /**
+ * Make a hex code string for the given colour
+ * @param inColour colour
+ * @return 6-character hex code
+ */
+ public static String makeHexCode(Color inColour)
+ {
+ return convertToHex(inColour.getRed()) + convertToHex(inColour.getGreen()) + convertToHex(inColour.getBlue());
+ }
+
+ /**
+ * @param inValue integer value from 0 to 255
+ * @return two-character hex code
+ */
+ private static String convertToHex(int inValue)
+ {
+ // Uses lower case a-f
+ String code = Integer.toHexString(inValue);
+ // Pad with leading 0 if necessary
+ return (inValue < 16 ? "0" + code : code);
+ }
+}
-package tim.prune;
+package tim.prune.config;
import java.io.File;
import java.io.FileInputStream;
import java.util.Properties;
+
/**
* Abstract class to hold application-wide configuration
*/
/** Hashtable containing all config values */
private static Properties _configValues = new Properties();
+ /** Colour scheme object is also part of config */
+ private static ColourScheme _colourScheme = new ColourScheme();
/** Default config file */
private static final File DEFAULT_CONFIG_FILE = new File(".pruneconfig");
public static final String KEY_PHOTO_DIR = "prune.photodirectory";
/** Key for language code */
public static final String KEY_LANGUAGE_CODE = "prune.languagecode";
+ /** Key for language file */
+ public static final String KEY_LANGUAGE_FILE = "prune.languagefile";
/** Key for GPS device */
public static final String KEY_GPS_DEVICE = "prune.gpsdevice";
/** Key for GPS format */
public static final String KEY_MAPSERVERINDEX = "prune.mapserverindex";
/** Key for map server url */
public static final String KEY_MAPSERVERURL = "prune.mapserverurl";
- /** Key for show pace flag */
- public static final String KEY_SHOW_PACE = "prune.showpace";
+ /** Key for show map flag */
+ public static final String KEY_SHOW_MAP = "prune.showmap";
/** Key for width of thumbnails in kmz */
public static final String KEY_KMZ_IMAGE_WIDTH = "prune.kmzimagewidth";
/** Key for height of thumbnails in kmz */
public static final String KEY_GNUPLOT_PATH = "prune.gnuplotpath";
/** Key for exiftool path */
public static final String KEY_EXIFTOOL_PATH = "prune.exiftoolpath";
+ /** Key for colour scheme */
+ public static final String KEY_COLOUR_SCHEME = "prune.colourscheme";
+ /** Key for kml track colour */
+ public static final String KEY_KML_TRACK_COLOUR = "prune.kmltrackcolour";
/**
}
// Save all properties from file
_configValues.putAll(props);
+ _colourScheme.loadFromHex(_configValues.getProperty(KEY_COLOUR_SCHEME));
if (loadFailed) {
throw new ConfigException();
}
props.put(KEY_GPS_DEVICE, "usb:");
props.put(KEY_GPS_FORMAT, "garmin");
props.put(KEY_POVRAY_FONT, "crystal.ttf"); // alternative: DejaVuSans-Bold.ttf
- props.put(KEY_SHOW_PACE, "0"); // hide by default
+ props.put(KEY_SHOW_MAP, "0"); // hide by default
props.put(KEY_EXIFTOOL_PATH, "exiftool");
props.put(KEY_GNUPLOT_PATH, "gnuplot");
props.put(KEY_GPSBABEL_PATH, "gpsbabel");
props.put(KEY_KMZ_IMAGE_WIDTH, "240");
- props.put(KEY_KMZ_IMAGE_HEIGHT, "180");
+ props.put(KEY_KMZ_IMAGE_HEIGHT, "240");
return props;
}
return _configValues;
}
+ /**
+ * @return the current colour scheme
+ */
+ public static ColourScheme getColourScheme()
+ {
+ return _colourScheme;
+ }
+
/**
* Store the given configuration setting
* @param inKey key (from constants)
*/
public static void setConfigString(String inKey, String inValue)
{
- if (inKey != null && !inKey.equals(""))
- {
+ if (inValue == null || inValue.equals("")) {
+ _configValues.remove(inKey);
+ }
+ else {
_configValues.put(inKey, inValue);
}
}
public static boolean isKeyBoolean(String inKey)
{
// Only two boolean keys so far
- return inKey != null && (inKey.equals(KEY_METRIC_UNITS) || inKey.equals(KEY_SHOW_PACE));
+ return inKey != null && (
+ inKey.equals(KEY_METRIC_UNITS) || inKey.equals(KEY_SHOW_MAP));
+ }
+
+ /**
+ * Update the colour scheme property from the current settings
+ */
+ public static void updateColourScheme()
+ {
+ setConfigString(KEY_COLOUR_SCHEME, _colourScheme.toString());
}
}
-package tim.prune;
+package tim.prune.config;
/**
* Exception thrown when something went wrong with the config
--- /dev/null
+The source code of Prune is copyright 2006-2010 activityworkshop.net
+and distributed under the terms of the Gnu GPL version 2.
+
+The package drew.jpeg is taken from Drew Noakes' "Metadata extractor"
+which is copyright Drew Noakes 2002-2006 and was placed in the public domain.
+
+Translations are copyright various contributors, some of whom are named
+in the source code and some preferred to remain anonymous.
\ No newline at end of file
// Instance variables
private boolean _valid = false;
+ private boolean _cardinalGuessed = false;
protected int _cardinal = NORTH;
private int _degrees = 0;
private int _minutes = 0;
hasCardinal = false;
// use default from concrete subclass
_cardinal = getDefaultCardinal();
+ _cardinalGuessed = true;
+ }
+ else if (isJustNumber(inString)) {
+ // it's just a number
+ hasCardinal = false;
+ _cardinalGuessed = true;
}
// count numeric fields - 1=d, 2=dm, 3=dm.m/dms, 4=dms.s
return cardinal;
}
+ /**
+ * @return true if cardinal was guessed, false if parsed
+ */
+ public boolean getCardinalGuessed() {
+ return _cardinalGuessed;
+ }
/**
* Get the cardinal from the given character
case FORMAT_DECIMAL_FORCE_POINT:
{
// Forcing a decimal point instead of system-dependent commas etc
- answer = EIGHT_DP.format(_asDouble);
+ if (_originalFormat != FORMAT_DEG_WITHOUT_CARDINAL || answer.indexOf('.') < 0) {
+ answer = EIGHT_DP.format(_asDouble);
+ }
break;
}
case FORMAT_DEG_MIN_SEC_WITH_SPACES:
*/
protected abstract Coordinate makeNew(double inValue, int inFormat);
+ /**
+ * Try to parse the given string
+ * @param inString string to check
+ * @return true if it can be parsed as a number
+ */
+ private static boolean isJustNumber(String inString)
+ {
+ boolean justNum = false;
+ try {
+ double x = Double.parseDouble(inString);
+ justNum = (x >= -180.0 && x <= 360.0);
+ }
+ catch (NumberFormatException nfe) {} // flag remains false
+ return justNum;
+ }
/**
* Create a String representation for debug
package tim.prune.data;
-import tim.prune.Config;
+import tim.prune.config.Config;
/**
* Class to represent a single data point in the series
private String _waypointName = null;
private boolean _startOfSegment = false;
private boolean _markedForDeletion = false;
-
+ private int _modifyCount = 0;
/**
* Constructor
if (inField == null || inField == Field.WAYPT_NAME) {
_waypointName = getFieldValue(Field.WAYPT_NAME);
}
- if (inField == null || inField == Field.NEW_SEGMENT) {
+ if (inField == null || inField == Field.NEW_SEGMENT)
+ {
String segmentStr = getFieldValue(Field.NEW_SEGMENT);
if (segmentStr != null) {segmentStr = segmentStr.trim();}
_startOfSegment = (segmentStr != null && (segmentStr.equals("1") || segmentStr.toUpperCase().equals("Y")));
Field[] fields = {Field.LATITUDE, Field.LONGITUDE, Field.ALTITUDE};
_fieldList = new FieldList(fields);
_latitude = inLatitude;
- _fieldValues[0] = inLatitude.output(Coordinate.FORMAT_DEG_MIN_SEC);
+ _fieldValues[0] = inLatitude.output(Coordinate.FORMAT_NONE);
_longitude = inLongitude;
- _fieldValues[1] = inLongitude.output(Coordinate.FORMAT_DEG_MIN_SEC);
+ _fieldValues[1] = inLongitude.output(Coordinate.FORMAT_NONE);
if (inAltitude == null) {
_altitude = Altitude.NONE;
}
else {
_altitude = inAltitude;
- _fieldValues[2] = "" + inAltitude.getValue(Altitude.Format.METRES); // units are ignored
+ _fieldValues[2] = "" + inAltitude.getValue();
}
_timestamp = new Timestamp(null);
}
* Set (or edit) the specified field value
* @param inField Field to set
* @param inValue value to set
+ * @param inUndo true if undo operation, false otherwise
*/
- public void setFieldValue(Field inField, String inValue)
+ public void setFieldValue(Field inField, String inValue, boolean inUndo)
{
// See if this data point already has this field
int fieldIndex = _fieldList.getFieldIndex(inField);
}
// Set field value in array
_fieldValues[fieldIndex] = inValue;
+ // Increment edit count on all field edits except segment
+ if (inField != Field.NEW_SEGMENT) {
+ if (!inUndo) {
+ _modifyCount++;
+ }
+ else {
+ _modifyCount--;
+ }
+ }
// Change Coordinate, Altitude, Name or Timestamp fields after edit
if (_altitude != null && _altitude.getFormat() != Altitude.Format.NO_FORMAT) {
// Altitude already present so reuse format
}
}
+ /**
+ * @return field list for this point
+ */
+ public FieldList getFieldList()
+ {
+ return _fieldList;
+ }
+
/** @param inFlag true for start of track segment */
public void setSegmentStart(boolean inFlag)
{
- setFieldValue(Field.NEW_SEGMENT, inFlag?"1":null);
+ setFieldValue(Field.NEW_SEGMENT, inFlag?"1":null, false);
}
/**
return (_waypointName != null && !_waypointName.equals(""));
}
+ /**
+ * @return true if point has been modified since loading
+ */
+ public boolean isModified()
+ {
+ return _modifyCount > 0;
+ }
/**
* Compare two DataPoint objects to see if they are duplicates
return _latitude.isValid() && _longitude.isValid();
}
-
/**
* Interpolate a set of points between this one and the given one
* @param inEndPoint end point of interpolation
*/
public DataPoint clonePoint()
{
- // Copy all values
+ // Copy all values (note that photo not copied)
String[] valuesCopy = new String[_fieldValues.length];
System.arraycopy(_fieldValues, 0, valuesCopy, 0, _fieldValues.length);
// Make new object to hold cloned data
package tim.prune.data;
+import java.util.ArrayList;
+
/**
* Class to hold the information about the file(s)
* from which the data was loaded from / saved to
*/
public class FileInfo
{
- private String _filename = null;
- private int _numFiles = 0;
+ /** List of sources */
+ private ArrayList<SourceInfo> _sources = new ArrayList<SourceInfo>();
/**
- * Set the file information to the specified file
- * @param inFilename filename of file
+ * Empty constructor
*/
- public void setFile(String inFilename)
+ public FileInfo()
+ {}
+
+ /**
+ * Private constructor for creating clone
+ * @param inList list of sources
+ */
+ private FileInfo(ArrayList<SourceInfo> inList)
{
- _filename = inFilename;
- _numFiles = 1;
+ _sources = inList;
}
-
/**
- * Add a file to the data
+ * Add a data source to the list
+ * @param inInfo info object to add
*/
- public void addFile()
+ public void addSource(SourceInfo inInfo)
{
- _numFiles++;
+ _sources.add(inInfo);
}
-
/**
- * Undo a load file
+ * Replace the list of data sources with the given source
+ * @param inInfo new source
*/
- public void removeFile()
+ public void replaceSource(SourceInfo inInfo)
{
- _numFiles--;
+ _sources.clear();
+ addSource(inInfo);
}
+ /**
+ * remove the last source added
+ */
+ public void removeSource()
+ {
+ _sources.remove(_sources.size()-1);
+ }
/**
* @return the number of files loaded
*/
public int getNumFiles()
{
- return _numFiles;
+ return _sources.size();
}
/**
- * @return The filename, if a single file
+ * @return The source name, if a single file
*/
public String getFilename()
{
- if (_numFiles == 1 && _filename != null)
- return _filename;
+ if (getNumFiles() == 1)
+ return _sources.get(0).getName();
return "";
}
+
+ /**
+ * @param inIndex index number
+ * @return source info object
+ */
+ public SourceInfo getSource(int inIndex) {
+ return _sources.get(inIndex);
+ }
+
+ /**
+ * Clone contents of file info
+ */
+ @SuppressWarnings("unchecked")
+ public FileInfo clone()
+ {
+ // copy source list
+ ArrayList<SourceInfo> copy = (ArrayList<SourceInfo>) _sources.clone();
+ return new FileInfo(copy);
+ }
}
private Status _originalStatus = Status.NOT_CONNECTED;
/** Current photo status */
private Status _currentStatus = Status.NOT_CONNECTED;
+ /** rotation flag (clockwise from 0 to 3) */
+ private int _rotation = 0;
// TODO: Need to store caption for image?
// thumbnail for image (from exif)
private byte[] _exifThumbnail = null;
CONNECTED
};
-
/**
* Constructor
* @param inFile File object for photo
return (inOther != null && inOther.getFile() != null && getFile() != null
&& inOther.getFile().equals(getFile()));
}
+
+ /**
+ * @param inRotation initial rotation value (from exif)
+ */
+ public void setRotation(int inRotation)
+ {
+ if (inRotation >= 0 && inRotation <= 3) {
+ _rotation = inRotation;
+ }
+ }
+
+ /**
+ * Rotate the image by 90 degrees
+ * @param inRight true to rotate right, false for left
+ */
+ public void rotate(boolean inRight)
+ {
+ int dir = inRight?1:3;
+ _rotation = (_rotation + dir) % 4;
+ }
+
+ /**
+ * @return rotation status
+ */
+ public int getRotationDegrees()
+ {
+ return _rotation * 90;
+ }
}
private Altitude.Format _altitudeFormat = Altitude.Format.NO_FORMAT;
private long _totalSeconds = 0L, _movingSeconds = 0L;
private double _angDistance = -1.0, _angMovingDistance = -1.0;
- private boolean _multipleSegments = false;
+ private int _numSegments = 0;
/**
private void recalculate()
{
_altitudeFormat = Altitude.Format.NO_FORMAT;
- _multipleSegments = false;
+ _numSegments = 0;
if (_track.getNumPoints() > 0 && hasRangeSelected())
{
_altitudeRange = new IntegerRange();
double radians = DataPoint.calculateRadiansBetween(lastPoint, currPoint);
_angDistance += radians;
if (currPoint.getSegmentStart()) {
- _multipleSegments = true;
+ _numSegments++;
}
else {
_angMovingDistance += radians;
}
}
lastPoint = currPoint;
+ // If it's a track point then there must be at least one segment
+ if (_numSegments == 0) {_numSegments = 1;}
}
}
if (endTime != null) {
}
/**
- * @return true if track has multiple segments
+ * @return number of segments in selection
*/
- public boolean getHasMultipleSegments()
+ public int getNumSegments()
{
- return _multipleSegments;
+ return _numSegments;
}
/**
/**
- * Deselect range
+ * Select range from start to end
* @param inStartIndex index of start of range
* @param inEndIndex index of end of range
*/
--- /dev/null
+package tim.prune.data;
+
+import java.io.File;
+
+/**
+ * Class to hold the source of the point data,
+ * including original file and file type, and
+ * also file offsets for source copying
+ */
+public class SourceInfo
+{
+ /** File type of source file */
+ public enum FILE_TYPE {TEXT, GPX, KML, NMEA, GPSBABEL, GPSIES};
+
+ /** Source file */
+ private File _sourceFile = null;
+ /** Name of source */
+ private String _sourceName = null;
+ /** File type */
+ private FILE_TYPE _fileType = null;
+
+ /** Array of datapoints */
+ private DataPoint[] _points = null;
+
+
+ /**
+ * Constructor
+ * @param inFile source file
+ * @param inType type of file
+ */
+ public SourceInfo(File inFile, FILE_TYPE inType)
+ {
+ _sourceFile = inFile;
+ _sourceName = inFile.getName();
+ _fileType = inType;
+ }
+
+ /**
+ * Constructor
+ * @param inName name of source (without file)
+ * @param inType type of file
+ */
+ public SourceInfo(String inName, FILE_TYPE inType)
+ {
+ _sourceFile = null;
+ _sourceName = inName;
+ _fileType = inType;
+ }
+
+ /**
+ * @return source file
+ */
+ public File getFile()
+ {
+ return _sourceFile;
+ }
+
+ /**
+ * @return source name
+ */
+ public String getName()
+ {
+ return _sourceName;
+ }
+
+ /**
+ * @return file type of source
+ */
+ public FILE_TYPE getFileType()
+ {
+ return _fileType;
+ }
+
+ /**
+ * @return number of points from this source
+ */
+ public int getNumPoints()
+ {
+ return _points.length;
+ }
+
+ /**
+ * Take the points from the given track and store
+ * @param inTrack track object containing points
+ * @param inNumPoints number of points loaded
+ */
+ public void populatePointObjects(Track inTrack, int inNumPoints)
+ {
+ if (inNumPoints > 0)
+ {
+ _points = new DataPoint[inNumPoints];
+ int trackLen = inTrack.getNumPoints();
+ System.arraycopy(inTrack.cloneContents(), trackLen-inNumPoints, _points, 0, inNumPoints);
+ // Note data copied twice here but still more efficient than looping
+ }
+ }
+
+ /**
+ * Look for the given point in the array
+ * @param inPoint point to look for
+ * @return index, or -1 if not found
+ */
+ public int getIndex(DataPoint inPoint)
+ {
+ int idx = -1;
+ for (int i=0; i<_points.length && (idx < 0); i++) {
+ if (_points[i] == inPoint) {idx = i;}
+ }
+ return idx;
+ }
+}
import java.util.List;
-import tim.prune.Config;
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;
_scaled = false;
}
+ /**
+ * Request that a rescale be done to recalculate derived values
+ */
+ public void requestRescale()
+ {
+ _scaled = false;
+ }
+
+ /**
+ * Extend the track's field list with the given additional fields
+ * @param inFieldList list of fields to be added
+ */
+ public void extendFieldList(FieldList inFieldList)
+ {
+ _masterFieldList = _masterFieldList.merge(inFieldList);
+ }
+
////////////////// Modification methods //////////////////////
return foundAlt;
}
- // TODO: Function to collect and sort photo points by time or photo filename
- // TODO: Function to convert waypoint names into timestamps
/**
* Collect all waypoints to the start or end of the track
* Edit the specified point
* @param inPoint point to edit
* @param inEditList list of edits to make
+ * @param inUndo true if undo operation, false otherwise
* @return true if successful
*/
- public boolean editPoint(DataPoint inPoint, FieldEditList inEditList)
+ public boolean editPoint(DataPoint inPoint, FieldEditList inEditList, boolean inUndo)
{
if (inPoint != null && inEditList != null && inEditList.getNumEdits() > 0)
{
{
FieldEdit edit = inEditList.getEdit(i);
Field editField = edit.getField();
- inPoint.setFieldValue(editField, edit.getValue());
+ inPoint.setFieldValue(editField, edit.getValue(), inUndo);
// Check that master field list has this field already (maybe point name has been added)
if (!_masterFieldList.contains(editField)) {
_masterFieldList.extendList(editField);
return _fileInfo;
}
+ /**
+ * Replace the file info with a previously made clone
+ * @param inInfo cloned file info
+ */
+ public void setFileInfo(FileInfo inInfo) {
+ _fileInfo = inInfo;
+ }
+
/**
* @return the PhotoList object
*/
}
}
}
+
+ /**
+ * Extend the current selection to end at the given point, eg by shift-clicking
+ * @param inPointNum index of end point
+ */
+ public void extendSelection(int inPointNum)
+ {
+ // See whether to start selection from current range start or current point
+ int rangeStart = _selection.getStart();
+ if (rangeStart < 0) {rangeStart = _selection.getCurrentPointIndex();}
+ selectPoint(inPointNum);
+ if (rangeStart < inPointNum) {
+ _selection.selectRange(rangeStart, inPointNum);
+ }
+ }
}
private static final int TAG_THUMBNAIL_OFFSET = 0x0201;\r
/** Thumbnail length */\r
private static final int TAG_THUMBNAIL_LENGTH = 0x0202;\r
+ /** Orientation of image */\r
+ private static final int TAG_ORIENTATION = 0x0112;\r
\r
\r
/**\r
_thumbnailLength = get16Bits(inTagValueOffset);\r
extractThumbnail(inMetadata);\r
}\r
+ else if (inTagType == TAG_ORIENTATION) {\r
+ if (inMetadata.getOrientationCode() < 1) {\r
+ inMetadata.setOrientationCode(get16Bits(inTagValueOffset));\r
+ }\r
+ }\r
}\r
\r
/**\r
if (inByteCount > 4)\r
{\r
// If it's bigger than 4 bytes, the dir entry contains an offset.\r
- // dirEntryOffset must be passed, as some makernote implementations (e.g. FujiFilm) incorrectly use an\r
+ // dirEntryOffset must be passed, as some makers (e.g. FujiFilm) incorrectly use an\r
// offset relative to the start of the makernote itself, not the TIFF segment.\r
final int offsetVal = get32Bits(inDirEntryOffset + 8);\r
if (offsetVal + inByteCount > _data.length)\r
private int get16Bits(int offset)\r
{\r
if (offset<0 || offset+2>_data.length)\r
- throw new ArrayIndexOutOfBoundsException("attempt to read data outside of exif segment (index " + offset + " where max index is " + (_data.length - 1) + ")");\r
+ throw new ArrayIndexOutOfBoundsException("attempt to read data outside of exif segment (index "\r
+ + offset + " where max index is " + (_data.length - 1) + ")");\r
\r
if (_isMotorolaByteOrder) {\r
// Motorola - MSB first\r
/**
* Class to hold the GPS data extracted from a Jpeg including position and time
- * All contents are in Rational format
*/
public class JpegData
{
private Rational[] _gpsTimestamp = null;
private Rational[] _gpsDatestamp = null;
private String _originalTimestamp = null;
+ private int _orientationCode = -1;
private byte[] _thumbnail = null;
private ArrayList<String> _errors = null;
_originalTimestamp = inStamp;
}
+ /**
+ * Set the orientation code
+ * @param inCode code from exif (1 to 8)
+ */
+ public void setOrientationCode(int inCode)
+ {
+ if (inCode >= 1 && inCode <= 8) {
+ _orientationCode = inCode;
+ }
+ }
+
/** @return latitude ref as char */
public char getLatitudeRef() { return _latitudeRef; }
/** @return latitude as array of 3 Rationals */
public Rational[] getGpsTimestamp() { return _gpsTimestamp; }
/** @return Gps datestamp as array of 3 Rationals */
public Rational[] getGpsDatestamp() { return _gpsDatestamp; }
+ /** @return orientation code (1 to 8) */
+ public int getOrientationCode() { return _orientationCode; }
/** @return original timestamp as string */
public String getOriginalTimestamp() { return _originalTimestamp; }
return _thumbnail;
}
+ /**
+ * @return rotation required to display photo properly (0 to 3)
+ */
+ public int getRequiredRotation()
+ {
+ if (_orientationCode <= 2) { return 0; } // no rotation required
+ if (_orientationCode <= 4) { return 2; } // 180 degrees
+ if (_orientationCode <= 6) { return 1; } // 270 degrees, so need to rotate by 90
+ return 3; // 90 degrees, so need to rotate by 270
+ }
+
/**
* @return true if data looks valid, ie has at least lat and long
* (altitude and timestamp optional).
descBuffer.append("<p>").append(I18nManager.getText("dialog.about.summarytext3")).append("</p>");
descBuffer.append("<p>").append(I18nManager.getText("dialog.about.languages")).append(" : ")
.append("deutsch, english, espa\u00F1ol, fran\u00E7ais, italiano, polski, \u4e2d\u6587; (chinese)<br>" +
- "schwiizerd\u00FC\u00FCtsch, portugu\u00EAs, bahasa indonesia, rom\u00E2n\u0103").append("</p>");
+ "schwiizerd\u00FC\u00FCtsch, \u65E5\u672C\u8A9E (japanese), t\u00FCrk\u00E7e, portugu\u00EAs, " +
+ "bahasa indonesia, rom\u00E2n\u0103").append("</p>");
descBuffer.append("<p>").append(I18nManager.getText("dialog.about.translatedby")).append("</p>");
JEditorPane descPane = new JEditorPane("text/html", descBuffer.toString());
descPane.setBorder(BorderFactory.createEmptyBorder(3, 3, 3, 3));
new JLabel("Ramon, Miguel, In\u00E9s, Piotr, Petrovsk, Josatoc, Weehal,"),
1, 3);
addToGridBagPanel(creditsPanel, gridBag, constraints,
- new JLabel(" theYinYeti, Rothermographer, Sam, Rudolph"),
+ new JLabel(" theYinYeti, Rothermographer, Sam, Rudolph, nazotoko, katpatuka"),
1, 4);
addToGridBagPanel(creditsPanel, gridBag, constraints,
new JLabel(I18nManager.getText("dialog.about.credits.translations") + " : "),
new JLabel(I18nManager.getText("dialog.about.credits.devtools") + " : "),
0, 6);
addToGridBagPanel(creditsPanel, gridBag, constraints,
- new JLabel("Mandriva Linux, Sun Java, Eclipse, Svn, Gimp"),
+ new JLabel("Debian Linux, Sun Java, Eclipse, Svn, Gimp, Inkscape"),
1, 6);
addToGridBagPanel(creditsPanel, gridBag, constraints,
new JLabel(I18nManager.getText("dialog.about.credits.othertools") + " : "),
0, 7);
addToGridBagPanel(creditsPanel, gridBag, constraints,
- new JLabel("Kate, Povray, Exiftool, Inkscape, Google Earth, Gpsbabel, Gnuplot"),
+ new JLabel("Openstreetmap, Povray, Exiftool, Google Earth, Gpsbabel, Gnuplot"),
1, 7);
addToGridBagPanel(creditsPanel, gridBag, constraints,
new JLabel(I18nManager.getText("dialog.about.credits.thanks") + " : "),
}
/**
- * Helper function to reduce complexity of gui making code
+ * Helper function to reduce complexity of gui-making code
* when adding labels to a GridBagLayout
* @param inPanel panel to add to
* @param inLayout GridBagLayout object
* @param inX grid x
* @param inY grid y
*/
- private static void addToGridBagPanel(JPanel inPanel, GridBagLayout inLayout, GridBagConstraints inConstraints,
- JLabel inLabel, int inX, int inY)
+ private static void addToGridBagPanel(JPanel inPanel, GridBagLayout inLayout,
+ GridBagConstraints inConstraints, JLabel inLabel, int inX, int inY)
{
// set x and y in constraints
inConstraints.gridx = inX;
package tim.prune.function;
import java.awt.BorderLayout;
-import java.awt.Component;
import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
* Create dialog components
* @return Panel containing all gui elements in dialog
*/
- private Component makeDialogComponents()
+ private JPanel makeDialogComponents()
{
JPanel dialogPanel = new JPanel();
dialogPanel.setLayout(new BorderLayout());
--- /dev/null
+package tim.prune.function;
+
+import tim.prune.App;
+import tim.prune.DataSubscriber;
+import tim.prune.GenericFunction;
+import tim.prune.I18nManager;
+import tim.prune.UpdateMessageBroker;
+import tim.prune.data.DataPoint;
+import tim.prune.data.Field;
+import tim.prune.data.Timestamp;
+import tim.prune.data.Track;
+import tim.prune.undo.UndoConvertNamesToTimes;
+
+/**
+ * Class to provide the function to convert waypoint names to timestamps
+ */
+public class ConvertNamesToTimes extends GenericFunction
+{
+ /**
+ * Constructor
+ * @param inApp application object for callback
+ */
+ public ConvertNamesToTimes(App inApp)
+ {
+ super(inApp);
+ }
+
+ /** Get the name key */
+ public String getNameKey() {
+ return "function.convertnamestotimes";
+ }
+
+ /**
+ * Begin the function
+ */
+ public void begin()
+ {
+ int selStart = _app.getTrackInfo().getSelection().getStart();
+ int selEnd = _app.getTrackInfo().getSelection().getEnd();
+ final Track track = _app.getTrackInfo().getTrack();
+ if (!track.hasData(Field.WAYPT_NAME, selStart, selEnd))
+ {
+ _app.showErrorMessage(getNameKey(), "error.convertnamestotimes.nonames");
+ return;
+ }
+ UndoConvertNamesToTimes undo = new UndoConvertNamesToTimes(_app.getTrackInfo());
+ int numConverted = 0;
+ // Loop over all points in selection
+ for (int i=selStart; i<=selEnd; i++)
+ {
+ DataPoint point = track.getPoint(i);
+ if (point.isWaypoint())
+ {
+ Timestamp tstamp = new Timestamp(point.getWaypointName());
+ if (tstamp.isValid()) {
+ // timestamp could be parsed!
+ point.setFieldValue(Field.TIMESTAMP, point.getWaypointName(), false);
+ // set waypoint name to nothing (track point)
+ point.setFieldValue(Field.WAYPT_NAME, null, false);
+ // increment counter
+ numConverted++;
+ }
+ }
+ }
+ if (numConverted > 0)
+ {
+ _app.getTrackInfo().getTrack().requestRescale();
+ UpdateMessageBroker.informSubscribers(DataSubscriber.DATA_EDITED);
+ _app.completeFunction(undo, I18nManager.getText("confirm.convertnamestotimes"));
+ }
+ }
+
+}
--- /dev/null
+package tim.prune.function;
+
+import tim.prune.App;
+import tim.prune.GenericFunction;
+import tim.prune.data.DataPoint;
+
+/**
+ * Class to provide the function to duplicate
+ * the current point and add to the end of the track
+ */
+public class DuplicatePoint extends GenericFunction
+{
+ /**
+ * Constructor
+ * @param inApp application object for callback
+ */
+ public DuplicatePoint(App inApp)
+ {
+ super(inApp);
+ }
+
+ /** Get the name key */
+ public String getNameKey() {
+ return "function.duplicatepoint";
+ }
+
+ /**
+ * Begin the function
+ */
+ public void begin()
+ {
+ DataPoint point = _app.getTrackInfo().getCurrentPoint();
+ if (point != null) {
+ // Pass information back to App to complete function
+ _app.createPoint(point.clonePoint());
+ }
+ }
+}
--- /dev/null
+package tim.prune.function;
+
+import java.awt.BorderLayout;
+import java.awt.Component;
+import java.awt.FlowLayout;
+import java.awt.GridLayout;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.text.NumberFormat;
+
+import javax.swing.BorderFactory;
+import javax.swing.JButton;
+import javax.swing.JDialog;
+import javax.swing.JLabel;
+import javax.swing.JPanel;
+
+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.Distance;
+import tim.prune.data.Selection;
+import tim.prune.gui.DisplayUtils;
+
+/**
+ * Class to show the full range details in a separate popup
+ */
+public class FullRangeDetails extends GenericFunction
+{
+ /** Dialog */
+ private JDialog _dialog = 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;
+ /** Number formatter for one decimal place */
+ private static final NumberFormat FORMAT_ONE_DP = NumberFormat.getNumberInstance();
+ /** Flexible number formatter for different decimal places */
+ private NumberFormat _distanceFormatter = NumberFormat.getInstance();
+
+ /**
+ * Constructor
+ * @param inApp App object
+ */
+ public FullRangeDetails(App inApp)
+ {
+ super(inApp);
+ FORMAT_ONE_DP.setMaximumFractionDigits(1);
+ FORMAT_ONE_DP.setMinimumFractionDigits(1);
+ }
+
+ /** Get the name key */
+ public String getNameKey() {
+ return "function.fullrangedetails";
+ }
+
+ /**
+ * Begin the function
+ */
+ public void begin()
+ {
+ if (_dialog == null)
+ {
+ _dialog = new JDialog(_parentFrame, I18nManager.getText(getNameKey()), true);
+ _dialog.setLocationRelativeTo(_parentFrame);
+ _dialog.setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE);
+ _dialog.getContentPane().add(makeDialogComponents());
+ _dialog.pack();
+ }
+ updateDetails();
+ _dialog.setVisible(true);
+ }
+
+ /**
+ * Create dialog components
+ * @return Panel containing all gui elements in dialog
+ */
+ private Component makeDialogComponents()
+ {
+ JPanel dialogPanel = new JPanel();
+ dialogPanel.setLayout(new BorderLayout(5, 5));
+ // Label at top
+ 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.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 15));
+ // 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);
+ // 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);
+ // 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);
+
+ dialogPanel.add(midPanel, BorderLayout.CENTER);
+ // button panel at bottom
+ JPanel buttonPanel = new JPanel();
+ buttonPanel.setLayout(new FlowLayout(FlowLayout.RIGHT));
+ JButton closeButton = new JButton(I18nManager.getText("button.close"));
+ closeButton.addActionListener(new ActionListener() {
+ public void actionPerformed(ActionEvent e)
+ {
+ _dialog.dispose();
+ }
+ });
+ buttonPanel.add(closeButton);
+ dialogPanel.add(buttonPanel, BorderLayout.SOUTH);
+ return dialogPanel;
+ }
+
+
+ /**
+ * Update the labels with the current details
+ */
+ private void updateDetails()
+ {
+ Selection selection = _app.getTrackInfo().getSelection();
+ // Number of segments
+ _numSegsLabel.setText("" + selection.getNumSegments());
+ // Pace value
+ if (selection.getNumSeconds() > 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)))
+ + " / " + distUnitsStr);
+ }
+ else {
+ _paceLabel.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)
+ {
+ // got an altitude and range
+ int altDiffInMetres = lastAlt.getValue(Altitude.Format.METRES) - firstAlt.getValue(Altitude.Format.METRES);
+ double gradient = altDiffInMetres * 100.0 / metreDist;
+ _gradientLabel.setText(FORMAT_ONE_DP.format(gradient) + " %");
+ }
+ else {
+ // no altitude given
+ _gradientLabel.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);
+ }
+ else {
+ _aveMovingSpeedLabel.setText("");
+ }
+ }
+
+ /**
+ * Format a number to a sensible precision
+ * @param inDist distance
+ * @return formatted String
+ */
+ private String roundedNumber(double inDist)
+ {
+ // Set precision of formatter
+ int numDigits = 0;
+ if (inDist < 1.0)
+ numDigits = 3;
+ else if (inDist < 10.0)
+ numDigits = 2;
+ else if (inDist < 100.0)
+ numDigits = 1;
+ // set formatter
+ _distanceFormatter.setMaximumFractionDigits(numDigits);
+ _distanceFormatter.setMinimumFractionDigits(numDigits);
+ return _distanceFormatter.format(inDist);
+ }
+}
--- /dev/null
+package tim.prune.function;
+
+import tim.prune.App;
+import tim.prune.DataSubscriber;
+import tim.prune.GenericFunction;
+import tim.prune.UpdateMessageBroker;
+import tim.prune.data.Photo;
+
+/**
+ * Class to provide the function to disable the exif thumbnail
+ * for the current photo so that the full image must be loaded
+ */
+public class IgnoreExifThumb extends GenericFunction
+{
+ /**
+ * Constructor
+ * @param inApp application object for callback
+ */
+ public IgnoreExifThumb(App inApp)
+ {
+ super(inApp);
+ }
+
+ /** Get the name key */
+ public String getNameKey() {
+ return "function.ignoreexifthumb";
+ }
+
+ /**
+ * Begin the function
+ */
+ public void begin()
+ {
+ Photo photo = _app.getTrackInfo().getCurrentPhoto();
+ if (photo != null)
+ {
+ // no undo necessary, no data being edited
+ photo.setExifThumbnail(null);
+ UpdateMessageBroker.informSubscribers(DataSubscriber.PHOTOS_MODIFIED);
+ }
+ }
+}
--- /dev/null
+package tim.prune.function;
+
+import java.awt.BorderLayout;
+import java.awt.Component;
+import java.awt.FlowLayout;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.awt.event.KeyAdapter;
+import java.awt.event.KeyEvent;
+import java.awt.event.MouseAdapter;
+
+import javax.swing.BorderFactory;
+import javax.swing.JButton;
+import javax.swing.JComboBox;
+import javax.swing.JDialog;
+import javax.swing.JLabel;
+import javax.swing.JOptionPane;
+import javax.swing.JPanel;
+import javax.swing.JTextField;
+import javax.swing.SwingConstants;
+
+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.DataPoint;
+import tim.prune.data.Field;
+import tim.prune.data.Latitude;
+import tim.prune.data.Longitude;
+import tim.prune.gui.GuiGridLayout;
+
+/**
+ * Class to provide the function to paste coordinates
+ * - see wikipedia, opencaching.de, waymarking.com etc
+ */
+public class PasteCoordinates extends GenericFunction
+{
+ private JDialog _dialog = null;
+ private JTextField _nameField = null;
+ private JTextField _coordField = null;
+ private JButton _okButton = null;
+ private JComboBox _altUnitsDropDown;
+
+
+ /**
+ * Constructor
+ * @param inApp application object for callback
+ */
+ public PasteCoordinates(App inApp)
+ {
+ super(inApp);
+ }
+
+ /** Get the name key */
+ public String getNameKey() {
+ return "function.pastecoordinates";
+ }
+
+ /**
+ * Begin the function
+ */
+ public void begin()
+ {
+ // Make dialog window
+ if (_dialog == null)
+ {
+ _dialog = new JDialog(_parentFrame, I18nManager.getText(getNameKey()), true);
+ _dialog.setLocationRelativeTo(_parentFrame);
+ _dialog.setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE);
+ _dialog.getContentPane().add(makeDialogComponents());
+ _dialog.pack();
+ }
+ // MAYBE: Paste clipboard into the edit field
+ _coordField.setText("");
+ _nameField.setText("");
+ boolean metric = Config.getConfigBoolean(Config.KEY_METRIC_UNITS);
+ _altUnitsDropDown.setSelectedIndex(metric?0:1);
+ enableOK();
+ _dialog.setVisible(true);
+ }
+
+
+ /**
+ * Create dialog components
+ * @return Panel containing all gui elements in dialog
+ */
+ private Component makeDialogComponents()
+ {
+ JPanel dialogPanel = new JPanel();
+ dialogPanel.setLayout(new BorderLayout(0, 10));
+ dialogPanel.add(new JLabel(I18nManager.getText("dialog.pastecoordinates.desc")), BorderLayout.NORTH);
+ JPanel mainPanel = new JPanel();
+ GuiGridLayout grid = new GuiGridLayout(mainPanel);
+ _coordField = new JTextField("", 25);
+ // Listeners to enable/disable ok button
+ KeyAdapter keyListener = new KeyAdapter() {
+ /** Key released */
+ public void keyReleased(KeyEvent arg0) {
+ enableOK();
+ }
+ };
+ MouseAdapter mouseListener = new MouseAdapter() {
+ public void mouseReleased(java.awt.event.MouseEvent arg0) {
+ enableOK();
+ };
+ };
+ _coordField.addKeyListener(keyListener);
+ _coordField.addMouseListener(mouseListener);
+ JLabel coordLabel = new JLabel(I18nManager.getText("dialog.pastecoordinates.coords"));
+ coordLabel.setHorizontalAlignment(SwingConstants.RIGHT);
+ grid.add(coordLabel);
+ grid.add(_coordField);
+ // Altitude format (if any)
+ JLabel formatLabel = new JLabel(I18nManager.getText("dialog.openoptions.altitudeunits"));
+ formatLabel.setHorizontalAlignment(SwingConstants.RIGHT);
+ grid.add(formatLabel);
+ final String[] altunits = {I18nManager.getText("units.metres"), I18nManager.getText("units.feet")};
+ _altUnitsDropDown = new JComboBox(altunits);
+ grid.add(_altUnitsDropDown);
+ // Waypoint name
+ JLabel nameLabel = new JLabel(I18nManager.getText("dialog.pointnameedit.name"));
+ nameLabel.setHorizontalAlignment(SwingConstants.RIGHT);
+ grid.add(nameLabel);
+ _nameField = new JTextField("", 12);
+ grid.add(_nameField);
+ dialogPanel.add(mainPanel, BorderLayout.CENTER);
+ // button panel at bottom
+ JPanel buttonPanel = new JPanel();
+ buttonPanel.setLayout(new FlowLayout(FlowLayout.RIGHT));
+ _okButton = new JButton(I18nManager.getText("button.ok"));
+ ActionListener okListener = new ActionListener() {
+ public void actionPerformed(ActionEvent e)
+ {
+ finish();
+ }
+ };
+ _okButton.addActionListener(okListener);
+ _okButton.setEnabled(false);
+ _coordField.addActionListener(okListener);
+ _nameField.addActionListener(okListener);
+ buttonPanel.add(_okButton);
+ JButton cancelButton = new JButton(I18nManager.getText("button.cancel"));
+ cancelButton.addActionListener(new ActionListener() {
+ public void actionPerformed(ActionEvent e)
+ {
+ _dialog.dispose();
+ }
+ });
+ buttonPanel.add(cancelButton);
+ dialogPanel.add(buttonPanel, BorderLayout.SOUTH);
+ dialogPanel.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 15));
+ return dialogPanel;
+ }
+
+ /**
+ * Enable or disable the OK button based on the contents of the text field
+ */
+ private void enableOK()
+ {
+ String text = _coordField.getText();
+ _okButton.setEnabled(text != null && text.length() > 10
+ && (text.indexOf(' ') >= 0 || text.indexOf(',') >= 0));
+ }
+
+ /**
+ * Finish the dialog when OK pressed
+ */
+ private void finish()
+ {
+ DataPoint point = null;
+ // Try to split using commas
+ String[] items = _coordField.getText().split(",");
+ if (items.length == 2) {
+ point = parseValues(items[0].trim(), items[1].trim(), null);
+ }
+ else if (items.length == 3) {
+ point = parseValues(items[0].trim(), items[1].trim(), items[2].trim());
+ }
+ else {
+ // Splitting with commas didn't work, so try spaces
+ items = _coordField.getText().split(" ");
+ if (items.length == 2) {
+ point = parseValues(items[0], items[1], null);
+ }
+ else if (items.length == 3 && items[1].length() == 1) {
+ point = parseValues(items[0], items[2], null);
+ }
+ else if (items.length == 4) {
+ point = parseValues(items[0] + " " + items[1],
+ items[2] + " " + items[3], null);
+ }
+ else if (items.length == 6) {
+ point = parseValues(items[0] + " " + items[1] + " " + items[2],
+ items[3] + " " + items[4] + " " + items[5], null);
+ }
+ else if (items.length == 8) {
+ point = parseValues(items[0] + " " + items[1] + " " + items[2] + " " + items[3],
+ items[4] + " " + items[5] + " " + items[6] + " " + items[7], null);
+ }
+ }
+
+ if (point == null) {
+ JOptionPane.showMessageDialog(_parentFrame,
+ I18nManager.getText("dialog.pastecoordinates.nothingfound"),
+ I18nManager.getText(getNameKey()), JOptionPane.ERROR_MESSAGE);
+ }
+ else {
+ // See if name was entered
+ String name = _nameField.getText();
+ if (name != null && name.length() > 0) {
+ point.setFieldValue(Field.WAYPT_NAME, name, false);
+ }
+ // Pass information back to App to complete function
+ _app.createPoint(point);
+ _dialog.dispose();
+ }
+ }
+
+
+ /**
+ * Try to parse the three given Strings into lat, lon and alt
+ * @param inValue1 first value (either lat/lon)
+ * @param inValue2 second value (either lon/lat)
+ * @param inValue3 altitude value or null if absent
+ * @return DataPoint object or null if failed
+ */
+ private DataPoint parseValues(String inValue1, String inValue2, String inValue3)
+ {
+ // Check for parseable altitude
+ Altitude alt = null;
+ if (inValue3 != null)
+ {
+ // Look at altitude units dropdown
+ final Altitude.Format altFormat = (_altUnitsDropDown.getSelectedIndex()==0?
+ Altitude.Format.METRES:Altitude.Format.FEET);
+ alt = new Altitude(inValue3, altFormat);
+ if (!alt.isValid()) {alt = null;}
+ }
+ // See if value1 can be lat and value2 lon:
+ Latitude coord1 = new Latitude(inValue1);
+ Longitude coord2 = new Longitude(inValue2);
+ if (coord1.isValid() && !coord1.getCardinalGuessed()
+ && coord2.isValid() && !coord2.getCardinalGuessed())
+ {
+ return new DataPoint(coord1, coord2, alt);
+ }
+ // Now see if lat/lon are reversed
+ Longitude coord3 = new Longitude(inValue1);
+ Latitude coord4 = new Latitude(inValue2);
+ if (coord3.isValid() && !coord3.getCardinalGuessed()
+ && coord4.isValid() && !coord4.getCardinalGuessed())
+ {
+ // reversed order
+ return new DataPoint(coord4, coord3, alt);
+ }
+ // Didn't work without guessing cardinals, so accept latitude, longitude order (if valid)
+ if (coord1.isValid() && coord2.isValid()) {
+ return new DataPoint(coord1, coord2, alt);
+ }
+ // Or accept other order (if valid)
+ if (coord3.isValid() && coord4.isValid()) {
+ // reversed order
+ return new DataPoint(coord4, coord3, alt);
+ }
+ // Couldn't be parsed either way
+ return null;
+ }
+}
--- /dev/null
+package tim.prune.function;
+
+import java.awt.BorderLayout;
+import java.awt.FlowLayout;
+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;
+import javax.swing.JButton;
+import javax.swing.JDialog;
+import javax.swing.JLabel;
+import javax.swing.JOptionPane;
+import javax.swing.JPanel;
+import javax.swing.JRadioButton;
+
+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.UndoRearrangePhotos;
+
+/**
+ * Class to provide the function for rearranging photo points
+ */
+public class RearrangePhotosFunction extends GenericFunction
+{
+ /** Function dialog */
+ private JDialog _dialog = null;
+ /** Radio buttons for start/end */
+ private JRadioButton[] _positionRadios = null;
+ /** Radio buttons for sorting */
+ private JRadioButton[] _sortRadios = null;
+
+
+ /**
+ * Constructor
+ * @param inApp app object
+ */
+ public RearrangePhotosFunction(App inApp)
+ {
+ super(inApp);
+ }
+
+ /** Begin the rearrange */
+ public void begin()
+ {
+ // Make dialog window
+ if (_dialog == null)
+ {
+ _dialog = new JDialog(_parentFrame, I18nManager.getText(getNameKey()), true);
+ _dialog.setLocationRelativeTo(_parentFrame);
+ _dialog.setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE);
+ _dialog.getContentPane().add(makeDialogComponents());
+ _dialog.pack();
+ }
+ // Reset dialog and show
+ _dialog.setVisible(true);
+ }
+
+ /** Get the name key (not needed) */
+ public String getNameKey() {
+ return "function.rearrangephotos";
+ }
+
+
+ /**
+ * Create dialog components
+ * @return Panel containing all gui elements in dialog
+ */
+ private JPanel makeDialogComponents()
+ {
+ JPanel dialogPanel = new JPanel();
+ dialogPanel.setLayout(new BorderLayout());
+ dialogPanel.add(new JLabel(I18nManager.getText("dialog.rearrangephotos.desc")), BorderLayout.NORTH);
+ // Radios for position (start / end)
+ _positionRadios = new JRadioButton[2];
+ final String[] posNames = {"tostart", "toend"};
+ ButtonGroup posGroup = new ButtonGroup();
+ JPanel posPanel = new JPanel();
+ posPanel.setLayout(new FlowLayout(FlowLayout.CENTER));
+ for (int i=0; i<2; i++)
+ {
+ _positionRadios[i] = new JRadioButton(I18nManager.getText("dialog.rearrangephotos." + posNames[i]));
+ posGroup.add(_positionRadios[i]);
+ posPanel.add(_positionRadios[i]);
+ }
+ _positionRadios[0].setSelected(true);
+ // Radios for sort (none / filename / time)
+ _sortRadios = new JRadioButton[3];
+ final String[] sortNames = {"nosort", "sortbyfilename", "sortbytime"};
+ ButtonGroup sortGroup = new ButtonGroup();
+ JPanel sortPanel = new JPanel();
+ sortPanel.setLayout(new FlowLayout(FlowLayout.CENTER));
+ for (int i=0; i<3; i++)
+ {
+ _sortRadios[i] = new JRadioButton(I18nManager.getText("dialog.rearrangephotos." + sortNames[i]));
+ sortGroup.add(_sortRadios[i]);
+ sortPanel.add(_sortRadios[i]);
+ }
+ _sortRadios[0].setSelected(true);
+ // add to middle of dialog
+ JPanel centrePanel = new JPanel();
+ centrePanel.setLayout(new BoxLayout(centrePanel, BoxLayout.Y_AXIS));
+ centrePanel.add(posPanel);
+ centrePanel.add(sortPanel);
+ dialogPanel.add(centrePanel, BorderLayout.CENTER);
+ // button panel at bottom
+ JPanel buttonPanel = new JPanel();
+ buttonPanel.setLayout(new FlowLayout(FlowLayout.RIGHT));
+ JButton okButton = new JButton(I18nManager.getText("button.ok"));
+ okButton.addActionListener(new ActionListener() {
+ public void actionPerformed(ActionEvent e) {
+ finish();
+ _dialog.dispose();
+ }
+ });
+ buttonPanel.add(okButton);
+ JButton cancelButton = new JButton(I18nManager.getText("button.cancel"));
+ cancelButton.addActionListener(new ActionListener() {
+ public void actionPerformed(ActionEvent e) {
+ _dialog.dispose();
+ }
+ });
+ buttonPanel.add(cancelButton);
+ dialogPanel.add(buttonPanel, BorderLayout.SOUTH);
+ return dialogPanel;
+ }
+
+ /**
+ * Perform the rearrange
+ */
+ private void finish()
+ {
+ Track track = _app.getTrackInfo().getTrack();
+ UndoRearrangePhotos undo = new UndoRearrangePhotos(track);
+ // Loop through track collecting non-photo points and photo points
+ final int numPoints = track.getNumPoints();
+ DataPoint[] nonPhotos = new DataPoint[numPoints];
+ DataPoint[] photos = new DataPoint[numPoints];
+ int numNonPhotos = 0;
+ int numPhotos = 0;
+ for (int i=0; i<numPoints; i++)
+ {
+ DataPoint point = track.getPoint(i);
+ if (point.getPhoto() != null) {
+ photos[numPhotos] = point;
+ numPhotos++;
+ }
+ else {
+ nonPhotos[numNonPhotos] = point;
+ numNonPhotos++;
+ }
+ }
+ // Sort photos if necessary
+ if (!_sortRadios[0].isSelected() && numPhotos > 1) {
+ sortPhotos(photos, _sortRadios[1].isSelected());
+ }
+ // Put the non-photo points and photo points together
+ DataPoint[] neworder = new DataPoint[numPoints];
+ if (_positionRadios[0].isSelected()) {
+ // photos at front
+ System.arraycopy(photos, 0, neworder, 0, numPhotos);
+ System.arraycopy(nonPhotos, 0, neworder, numPhotos, numNonPhotos);
+ }
+ else {
+ // photos at end
+ System.arraycopy(nonPhotos, 0, neworder, 0, numNonPhotos);
+ System.arraycopy(photos, 0, neworder, numNonPhotos, numPhotos);
+ }
+ // Give track the new point order
+ if (track.replaceContents(neworder))
+ {
+ _app.getTrackInfo().getSelection().clearAll();
+ _app.completeFunction(undo, I18nManager.getText("confirm.rearrangephotos"));
+ // Note: subscribers are informed up to three times now
+ }
+ else
+ {
+ JOptionPane.showMessageDialog(_parentFrame, I18nManager.getText("error.rearrange.noop"),
+ I18nManager.getText("error.function.noop.title"), JOptionPane.WARNING_MESSAGE);
+ }
+ }
+
+ /**
+ * Sort the given photo list either by filename or by time
+ * @param inPhotos array of DataPoint objects to sort
+ * @param inSortByFile true to sort by filename, false to sort by timestamp
+ * @return sorted array
+ */
+ 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;
+ 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);
+ }
+}
--- /dev/null
+package tim.prune.function;
+
+import tim.prune.App;
+import tim.prune.DataSubscriber;
+import tim.prune.GenericFunction;
+import tim.prune.I18nManager;
+import tim.prune.UpdateMessageBroker;
+import tim.prune.data.Photo;
+import tim.prune.undo.UndoRotatePhoto;
+
+/**
+ * Class to provide the function to rotate a photo
+ * either clockwise or anticlockwise
+ */
+public class RotatePhoto extends GenericFunction
+{
+ /** Direction of rotation */
+ private boolean _direction = true;
+
+ /**
+ * Constructor
+ * @param inApp application object for callback
+ * @param inDir true for clockwise, false for anticlockwise
+ */
+ public RotatePhoto(App inApp, boolean inDir)
+ {
+ super(inApp);
+ _direction = inDir;
+ }
+
+ /** Get the name key */
+ public String getNameKey() {
+ return _direction?"function.rotatephotoright":"function.rotatephotoleft";
+ }
+
+ /**
+ * Begin the function
+ */
+ public void begin()
+ {
+ Photo photo = _app.getTrackInfo().getCurrentPhoto();
+ if (photo != null)
+ {
+ UndoRotatePhoto undo = new UndoRotatePhoto(photo, _direction);
+ photo.rotate(_direction);
+ UpdateMessageBroker.informSubscribers(DataSubscriber.PHOTOS_MODIFIED);
+ _app.completeFunction(undo, I18nManager.getText("confirm.rotatephoto"));
+ }
+ }
+}
import javax.swing.JPanel;
import tim.prune.App;
-import tim.prune.Config;
import tim.prune.GenericFunction;
import tim.prune.I18nManager;
+import tim.prune.config.Config;
/**
* Class to provide the function to save the config settings
--- /dev/null
+package tim.prune.function;
+
+import java.awt.BorderLayout;
+import java.awt.Color;
+import java.awt.Component;
+import java.awt.Dimension;
+import java.awt.GridLayout;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.awt.event.MouseAdapter;
+import java.awt.event.MouseEvent;
+
+import javax.swing.BorderFactory;
+import javax.swing.Box;
+import javax.swing.BoxLayout;
+import javax.swing.JButton;
+import javax.swing.JDialog;
+import javax.swing.JLabel;
+import javax.swing.JPanel;
+
+import tim.prune.App;
+import tim.prune.GenericFunction;
+import tim.prune.I18nManager;
+import tim.prune.UpdateMessageBroker;
+import tim.prune.config.ColourScheme;
+import tim.prune.config.Config;
+import tim.prune.gui.ColourChooser;
+import tim.prune.gui.ColourPatch;
+
+/**
+ * Class to show the popup window for setting the colours
+ */
+public class SetColours extends GenericFunction
+{
+ private JDialog _dialog = null;
+ private JButton _okButton = null;
+ /** Array of 8 colour patches */
+ private ColourPatch[] _patches = null;
+ /** Single colour chooser */
+ private ColourChooser _colourChooser = null;
+
+ /** Array of label keys for the 8 patches */
+ private static final String[] LABEL_KEYS = {"background", "primary", "point", "secondary",
+ "selection", "borders", "text", "lines"};
+ /** Array of indices for the 8 patches */
+ private static final int[] INDICES = {ColourScheme.IDX_BACKGROUND, ColourScheme.IDX_PRIMARY,
+ ColourScheme.IDX_POINT, ColourScheme.IDX_SECONDARY,
+ ColourScheme.IDX_SELECTION, ColourScheme.IDX_BORDERS,
+ ColourScheme.IDX_TEXT, ColourScheme.IDX_LINES
+ };
+
+ /**
+ * Inner class to react to patch clicks
+ */
+ class PatchListener extends MouseAdapter
+ {
+ /** Associated patch */
+ private ColourPatch _patch = null;
+ /** Constructor */
+ public PatchListener(ColourPatch inPatch) {
+ _patch = inPatch;
+ }
+ /** React to mouse clicks */
+ public void mouseClicked(MouseEvent e)
+ {
+ _colourChooser.showDialog(_patch.getBackground());
+ Color colour = _colourChooser.getChosenColour();
+ if (colour != null) _patch.setColour(colour);
+ }
+ }
+
+ /**
+ * Constructor
+ * @param inApp app object
+ */
+ public SetColours(App inApp)
+ {
+ super(inApp);
+ }
+
+ /**
+ * Return the name key for this function
+ */
+ public String getNameKey()
+ {
+ return "function.setcolours";
+ }
+
+ /**
+ * @return the contents of the window as a Component
+ */
+ private Component makeContents()
+ {
+ JPanel mainPanel = new JPanel();
+ mainPanel.setLayout(new BorderLayout(0, 10));
+
+ JLabel intro = new JLabel(I18nManager.getText("dialog.setcolours.intro"));
+ intro.setBorder(BorderFactory.createEmptyBorder(5, 5, 0, 0));
+ mainPanel.add(intro, BorderLayout.NORTH);
+ JPanel centralPanel = new JPanel();
+ centralPanel.setLayout(new GridLayout());
+ _patches = new ColourPatch[8];
+
+ ColourScheme scheme = Config.getColourScheme();
+ ColourPatch patch = null;
+ // Loop over four columns of patches
+ for (int i=0; i<4; i++)
+ {
+ JPanel colPanel = new JPanel();
+ colPanel.setLayout(new BoxLayout(colPanel, BoxLayout.Y_AXIS));
+ // Top label and patch
+ colPanel.add(new JLabel(I18nManager.getText("dialog.setcolours." + LABEL_KEYS[i*2])));
+ patch = new ColourPatch(scheme.getColour(INDICES[i*2]));
+ patch.addMouseListener(new PatchListener(patch));
+ colPanel.add(patch);
+ _patches[i*2] = patch;
+ // separator
+ colPanel.add(Box.createRigidArea(new Dimension(0, 5)));
+ // Bottom label and patch
+ colPanel.add(new JLabel(I18nManager.getText("dialog.setcolours." + LABEL_KEYS[i*2+1])));
+ patch = new ColourPatch(scheme.getColour(INDICES[i*2+1]));
+ patch.addMouseListener(new PatchListener(patch));
+ colPanel.add(patch);
+ _patches[i*2+1] = patch;
+
+ // Add column to panel
+ colPanel.setBorder(BorderFactory.createEmptyBorder(2, 2, 2, 2));
+ centralPanel.add(colPanel);
+ }
+ mainPanel.add(centralPanel, BorderLayout.CENTER);
+
+ // Buttons at the bottom
+ JPanel buttonPanel = new JPanel();
+ buttonPanel.setLayout(new BoxLayout(buttonPanel, BoxLayout.LINE_AXIS));
+ _okButton = new JButton(I18nManager.getText("button.ok"));
+ _okButton.addActionListener(new ActionListener()
+ {
+ public void actionPerformed(ActionEvent e)
+ {
+ updateConfigColours();
+ _dialog.dispose();
+ }
+ });
+ JButton cancelButton = new JButton(I18nManager.getText("button.cancel"));
+ cancelButton.addActionListener(new ActionListener() {
+ public void actionPerformed(ActionEvent e)
+ {
+ _dialog.dispose();
+ }
+ });
+ JButton resetButton = new JButton(I18nManager.getText("button.resettodefaults"));
+ resetButton.addActionListener(new ActionListener() {
+ public void actionPerformed(ActionEvent e) {
+ for (int i=0; i<8; i++) {
+ _patches[i].setColour(ColourScheme.getDefaultColour(INDICES[i]));
+ }
+ }
+ });
+ buttonPanel.add(resetButton);
+ buttonPanel.add(Box.createHorizontalGlue());
+ buttonPanel.add(_okButton);
+ buttonPanel.add(Box.createHorizontalStrut(5));
+ buttonPanel.add(cancelButton);
+ buttonPanel.setBorder(BorderFactory.createEmptyBorder(2, 2, 2, 2));
+ mainPanel.add(buttonPanel, BorderLayout.SOUTH);
+ return mainPanel;
+ }
+
+
+ /**
+ * Show window
+ */
+ public void begin()
+ {
+ if (_dialog == null)
+ {
+ _dialog = new JDialog(_parentFrame, I18nManager.getText(getNameKey()));
+ _dialog.setLocationRelativeTo(_parentFrame);
+ _dialog.getContentPane().add(makeContents());
+ _dialog.pack();
+ _colourChooser = new ColourChooser(_dialog);
+ }
+ // Reset colours to current ones
+ ColourScheme scheme = Config.getColourScheme();
+ for (int i=0; i<8; i++) {
+ _patches[i].setColour(scheme.getColour(INDICES[i]));
+ }
+ _dialog.setVisible(true);
+ _okButton.requestFocus();
+ }
+
+ /**
+ * Update the current colour scheme with the selected colours
+ */
+ private void updateConfigColours()
+ {
+ ColourScheme scheme = Config.getColourScheme();
+ for (int i=0; i<_patches.length; i++)
+ {
+ scheme.setColour(INDICES[i], _patches[i].getBackground());
+ }
+ Config.updateColourScheme();
+ UpdateMessageBroker.informSubscribers();
+ }
+}
import javax.swing.SwingConstants;
import tim.prune.App;
-import tim.prune.Config;
import tim.prune.GenericFunction;
import tim.prune.I18nManager;
+import tim.prune.config.Config;
import tim.prune.gui.WholeNumberField;
/**
--- /dev/null
+package tim.prune.function;
+
+import java.awt.BorderLayout;
+import java.awt.Component;
+import java.awt.FlowLayout;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileReader;
+import java.util.Locale;
+
+import javax.swing.BorderFactory;
+import javax.swing.Box;
+import javax.swing.BoxLayout;
+import javax.swing.JButton;
+import javax.swing.JComboBox;
+import javax.swing.JDialog;
+import javax.swing.JFileChooser;
+import javax.swing.JLabel;
+import javax.swing.JOptionPane;
+import javax.swing.JPanel;
+import javax.swing.JTextField;
+import javax.swing.SwingConstants;
+import javax.swing.border.EtchedBorder;
+
+import tim.prune.App;
+import tim.prune.GenericFunction;
+import tim.prune.I18nManager;
+import tim.prune.config.Config;
+import tim.prune.load.GenericFileFilter;
+
+/**
+ * Class to show the popup window for setting the language code / file
+ */
+public class SetLanguage extends GenericFunction
+{
+ private JDialog _dialog = null;
+ private JComboBox _languageDropDown = null;
+ private JTextField _langFileBox = null;
+ private int _startIndex = 0;
+
+ /** Names of languages for display in dropdown (not translated) */
+ private static final String[] LANGUAGE_NAMES = {"deutsch", "english", "espa\u00F1ol", "fran\u00E7ais",
+ "italiano", "polski", "\u4e2d\u6587 (chinese)", "\u65E5\u672C\u8A9E (japanese)",
+ "schwiizerd\u00FC\u00FCtsch", "t\u00FCrk\u00E7e", "portugu\u00EAs", "bahasa indonesia", "rom\u00E2n\u0103"
+ };
+ /** Associated language codes (must be in same order as names!) */
+ private static final String[] LANGUAGE_CODES = {"de", "en", "es", "fr", "it", "pl", "zh", "ja",
+ "de_ch", "tr", "pt", "in", "ro"
+ };
+
+
+ /**
+ * Constructor
+ * @param inApp app object
+ */
+ public SetLanguage(App inApp)
+ {
+ super(inApp);
+ }
+
+ /**
+ * Return the name key for this function
+ */
+ public String getNameKey()
+ {
+ return "function.setlanguage";
+ }
+
+ /**
+ * @return the contents of the window as a Component
+ */
+ private Component makeContents()
+ {
+ JPanel mainPanel = new JPanel();
+ mainPanel.setLayout(new BorderLayout(0, 5));
+ JPanel midPanel = new JPanel();
+ midPanel.setLayout(new BoxLayout(midPanel, BoxLayout.Y_AXIS));
+ midPanel.setBorder(BorderFactory.createEmptyBorder(3, 3, 3, 3));
+ // description labels
+ JLabel label1 = new JLabel("<html>" + I18nManager.getText("dialog.setlanguage.firstintro") + "</html>");
+ label1.setAlignmentX(Component.LEFT_ALIGNMENT);
+ label1.setHorizontalAlignment(SwingConstants.LEFT);
+ midPanel.add(label1);
+ JLabel label2 = new JLabel("<html>" + I18nManager.getText("dialog.setlanguage.secondintro") + "</html>");
+ label2.setAlignmentX(Component.LEFT_ALIGNMENT);
+ label2.setHorizontalAlignment(SwingConstants.LEFT);
+ midPanel.add(label2);
+ midPanel.add(Box.createVerticalStrut(10));
+
+ // built-in languages
+ JPanel builtinPanel = new JPanel();
+ builtinPanel.setBorder(BorderFactory.createCompoundBorder(
+ BorderFactory.createEtchedBorder(EtchedBorder.LOWERED), BorderFactory.createEmptyBorder(3, 3, 3, 3))
+ );
+ builtinPanel.setLayout(new BoxLayout(builtinPanel, BoxLayout.X_AXIS));
+ builtinPanel.add(new JLabel(I18nManager.getText("dialog.setlanguage.language") + " : "));
+ // Language dropdown
+ _languageDropDown = new JComboBox(LANGUAGE_NAMES);
+ builtinPanel.add(_languageDropDown);
+ builtinPanel.add(Box.createHorizontalGlue());
+ JButton selectLangButton = new JButton(I18nManager.getText("button.select"));
+ selectLangButton.addActionListener(new ActionListener() {
+ public void actionPerformed(ActionEvent e) {
+ selectLanguage();
+ }
+ });
+ builtinPanel.add(selectLangButton);
+ builtinPanel.setAlignmentX(Component.LEFT_ALIGNMENT);
+ midPanel.add(builtinPanel);
+ midPanel.add(Box.createVerticalStrut(4));
+
+ // external language file
+ JPanel extraPanel = new JPanel();
+ extraPanel.setBorder(BorderFactory.createCompoundBorder(
+ BorderFactory.createEtchedBorder(EtchedBorder.LOWERED), BorderFactory.createEmptyBorder(3, 3, 3, 3))
+ );
+ extraPanel.setLayout(new BoxLayout(extraPanel, BoxLayout.X_AXIS));
+ extraPanel.add(new JLabel(I18nManager.getText("dialog.setlanguage.languagefile") + " : "));
+ _langFileBox = new JTextField("some_long_example_file_path.txt");
+ extraPanel.add(_langFileBox);
+ // browse button
+ JButton browseButton = new JButton(I18nManager.getText("button.browse"));
+ extraPanel.add(browseButton);
+ browseButton.addActionListener(new ActionListener() {
+ public void actionPerformed(ActionEvent arg0) {
+ chooseFile();
+ }
+ });
+ extraPanel.add(Box.createHorizontalStrut(5));
+ JButton selectFileButton = new JButton(I18nManager.getText("button.select"));
+ selectFileButton.addActionListener(new ActionListener() {
+ public void actionPerformed(ActionEvent e) {
+ selectLanguageFile();
+ }
+ });
+ extraPanel.add(selectFileButton);
+ extraPanel.setAlignmentX(Component.LEFT_ALIGNMENT);
+ midPanel.add(Box.createVerticalStrut(5));
+ midPanel.add(extraPanel);
+ midPanel.add(Box.createVerticalGlue());
+ mainPanel.add(midPanel, BorderLayout.CENTER);
+
+ // Cancel button at the bottom
+ JPanel buttonPanel = new JPanel();
+ buttonPanel.setLayout(new FlowLayout(FlowLayout.RIGHT));
+ JButton cancelButton = new JButton(I18nManager.getText("button.cancel"));
+ cancelButton.addActionListener(new ActionListener() {
+ public void actionPerformed(ActionEvent e)
+ {
+ _dialog.dispose();
+ }
+ });
+ buttonPanel.add(cancelButton);
+ mainPanel.add(buttonPanel, BorderLayout.SOUTH);
+ return mainPanel;
+ }
+
+
+ /**
+ * Show window
+ */
+ public void begin()
+ {
+ if (_dialog == null)
+ {
+ _dialog = new JDialog(_parentFrame, I18nManager.getText(getNameKey()));
+ _dialog.setLocationRelativeTo(_parentFrame);
+ _dialog.getContentPane().add(makeContents());
+ _dialog.pack();
+ }
+ // Try to use code from config
+ String code = Config.getConfigString(Config.KEY_LANGUAGE_CODE);
+ int index = getLanguageIndex(code);
+ // If it's not present, then use system locale settings
+ if (index < 0) {
+ Locale locale = Locale.getDefault();
+ index = getLanguageIndex(locale.getLanguage() + "_" + locale.getCountry());
+ if (index < 0) {
+ index = getLanguageIndex(locale.getLanguage());
+ }
+ }
+ // Select appropriate language from dropdown
+ if (index >= 0) {
+ _languageDropDown.setSelectedIndex(index);
+ }
+ _startIndex = _languageDropDown.getSelectedIndex();
+ // Get language file from config
+ String langfile = Config.getConfigString(Config.KEY_LANGUAGE_FILE);
+ _langFileBox.setText(langfile==null?"":langfile);
+ _dialog.setVisible(true);
+ }
+
+ /**
+ * Find the index of the given language code
+ * @param inCode code to look for
+ * @return index if found or -1
+ */
+ private static int getLanguageIndex(String inCode)
+ {
+ int idx = -1;
+ if (inCode != null && !inCode.equals("")) {
+ for (int i=0; i<LANGUAGE_CODES.length; i++) {
+ if (LANGUAGE_CODES[i].equalsIgnoreCase(inCode)) {
+ idx = i;
+ }
+ }
+ }
+ return idx;
+ }
+
+ /**
+ * Set the currently selected language in the Config
+ */
+ private void selectLanguage()
+ {
+ int index = _languageDropDown.getSelectedIndex();
+ // If index hasn't changed then don't dismiss dialog
+ if (index >= 0 && index != _startIndex)
+ {
+ String code = LANGUAGE_CODES[index];
+ // Set code and langfile in config
+ Config.setConfigString(Config.KEY_LANGUAGE_CODE, code);
+ Config.setConfigString(Config.KEY_LANGUAGE_FILE, null);
+ _dialog.dispose();
+ showEndMessage();
+ }
+ }
+
+ /**
+ * Select the currently selected language file to use for texts
+ */
+ private void selectLanguageFile()
+ {
+ final String oldPath = Config.getConfigString(Config.KEY_LANGUAGE_FILE);
+ String filename = _langFileBox.getText();
+ // Check there is an entry in the box
+ if (filename != null && !filename.equals(""))
+ {
+ // Check the file exists and is readable
+ File textsFile = new File(filename);
+ if (!textsFile.exists() || !textsFile.canRead())
+ {
+ _app.showErrorMessage(getNameKey(), "error.load.noread");
+ }
+ else if (!languageFileLooksOk(textsFile))
+ {
+ _app.showErrorMessage(getNameKey(), "error.language.wrongfile");
+ }
+ else if (oldPath == null || !textsFile.getAbsolutePath().equalsIgnoreCase(oldPath))
+ {
+ // Set in Config
+ Config.setConfigString(Config.KEY_LANGUAGE_FILE, textsFile.getAbsolutePath());
+ _dialog.dispose();
+ showEndMessage();
+ }
+ }
+ else {
+ // if file was previously selected, and now it's blank, then reset Config
+ if (oldPath != null && oldPath.length() > 0)
+ {
+ Config.setConfigString(Config.KEY_LANGUAGE_FILE, null);
+ _dialog.dispose();
+ showEndMessage();
+ }
+ }
+ }
+
+ /**
+ * Check the given file to see if it looks like a language file
+ * @param inFile File object to load
+ * @return true if file looks ok
+ */
+ private static boolean languageFileLooksOk(File inFile)
+ {
+ boolean ok = false;
+ boolean wrong = false;
+ BufferedReader reader = null;
+ try
+ {
+ // Read through text file looking for lines with the right start
+ reader = new BufferedReader(new FileReader(inFile));
+ String currLine = reader.readLine();
+ while (currLine != null && !ok && !wrong)
+ {
+ if (currLine.trim().length() > 0 && currLine.matches("[a-z.]+=.+")) {
+ ok = true;
+ }
+ if (currLine.indexOf('\0', 0) >= 0) {
+ wrong = true;
+ }
+ currLine = reader.readLine();
+ }
+ }
+ catch (Exception e) {} // ignore exceptions, flag remains as set
+ finally {
+ try {reader.close();} catch (Exception e2) {}
+ }
+ return ok && !wrong;
+ }
+
+ /**
+ * Function activated by the "Browse..." button to select a file
+ */
+ private void chooseFile()
+ {
+ JFileChooser chooser = new JFileChooser();
+ chooser.addChoosableFileFilter(
+ new GenericFileFilter("filetype.txt", new String[] {"txt", "text"}));
+ chooser.setAcceptAllFileFilterUsed(true);
+ // Set start path from currently selected file
+ String currPath = _langFileBox.getText();
+ if (currPath != null && currPath.length() > 1) {
+ chooser.setSelectedFile(new File(currPath));
+ }
+ if (chooser.showOpenDialog(_parentFrame) == JFileChooser.APPROVE_OPTION)
+ {
+ _langFileBox.setText(chooser.getSelectedFile().getAbsolutePath());
+ }
+ }
+
+ /**
+ * Show message to remind about saving settings and restarting
+ */
+ private void showEndMessage()
+ {
+ JOptionPane.showMessageDialog(_parentFrame,
+ I18nManager.getText("dialog.setlanguage.endmessage"),
+ I18nManager.getText(getNameKey()), JOptionPane.INFORMATION_MESSAGE);
+ }
+}
import javax.swing.JTextField;
import tim.prune.App;
-import tim.prune.Config;
import tim.prune.DataSubscriber;
import tim.prune.GenericFunction;
import tim.prune.I18nManager;
import tim.prune.UpdateMessageBroker;
+import tim.prune.config.Config;
/**
* Function to set the tile server for the map backgrounds
import javax.swing.SwingConstants;
import tim.prune.App;
-import tim.prune.Config;
import tim.prune.ExternalTools;
import tim.prune.GenericFunction;
import tim.prune.I18nManager;
+import tim.prune.config.Config;
/**
* Function to set the paths for the external programs (eg gnuplot)
public static final int MAP_SOURCE_MAPQUEST = 2;
/** Constant for Yahoo */
public static final int MAP_SOURCE_YAHOO = 3;
-
- // TODO: Add other map sources, eg MSN, search.ch ?
+ /** Constant for Bing */
+ public static final int MAP_SOURCE_BING = 4;
/**
* Generate a URL for the given source and track info
else if (inSource == MAP_SOURCE_YAHOO) {
return generateYahooUrl(inTrackInfo);
}
+ else if (inSource == MAP_SOURCE_BING) {
+ return generateBingUrl(inTrackInfo);
+ }
return generateOpenStreetMapUrl(inTrackInfo);
}
url = url + "(" + currPoint.getWaypointName() + ")";
}
}
- //System.out.println(url);
return url;
}
return url;
}
-/**
+ /**
+ * Generate a url for Bing maps
+ * @param inTrackInfo track information
+ * @return URL
+ */
+ private static String generateBingUrl(TrackInfo inTrackInfo)
+ {
+ // Check if any data to display
+ if (inTrackInfo == null || inTrackInfo.getTrack() == null || inTrackInfo.getTrack().getNumPoints() < 1)
+ {
+ return null;
+ }
+ double medianLat = getMedianValue(inTrackInfo.getTrack().getLatRange());
+ double medianLon = getMedianValue(inTrackInfo.getTrack().getLonRange());
+ // Build basic url with centre position
+ String latStr = FIVE_DP.format(medianLat);
+ String lonStr = FIVE_DP.format(medianLon);
+ String url = "http://bing.com/maps/default.aspx?cp=" + latStr + "~" + lonStr
+ + "&where1=" + latStr + "%2C%20" + lonStr;
+ return url;
+ }
+
+
+ /**
* Get the median value from the given lat/long range
* @param inRange range of values
* @return median value
import javax.swing.SwingConstants;
import tim.prune.App;
-import tim.prune.Config;
import tim.prune.ExternalTools;
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;
*/
private boolean[] preview()
{
- // System.out.println("track dialog preview");
int numToDelete = 0;
boolean[] deleteFlags = new boolean[_track.getNumPoints()];
for (int i=0; i<_algorithms.length; i++)
package tim.prune.function.distance;
-import tim.prune.Config;
import tim.prune.I18nManager;
+import tim.prune.config.Config;
import tim.prune.data.DataPoint;
import tim.prune.data.Distance;
private Component makeDialogComponents()
{
JPanel panel = new JPanel();
- panel.setLayout(new BorderLayout());
+ panel.setLayout(new BorderLayout(1, 10));
// Create GUI layout for point editor
_table = new JTable(_model);
_table.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.io.IOException;
+import java.io.InputStream;
import java.net.URL;
import java.util.ArrayList;
ArrayList<GpsiesTrack> trackList = null;
URL url = null;
String descMessage = "";
+ InputStream inStream = null;
// Loop for each page of the results
do
{
{
url = new URL(urlString);
SAXParser saxParser = SAXParserFactory.newInstance().newSAXParser();
- saxParser.parse(url.openStream(), xmlHandler);
+ inStream = url.openStream();
+ saxParser.parse(inStream, xmlHandler);
}
catch (Exception e) {
descMessage = e.getClass().getName() + " - " + e.getMessage();
}
- // TODO: Close streams somehow? Haven't got a reference to the input stream to close it!
+ // Close stream and ignore errors
+ try {
+ inStream.close();
+ } catch (Exception e) {}
// Add track list to model
trackList = xmlHandler.getTrackList();
_trackListModel.addTracks(trackList);
import javax.swing.table.AbstractTableModel;
-import tim.prune.Config;
import tim.prune.I18nManager;
+import tim.prune.config.Config;
import tim.prune.data.Distance;
/**
--- /dev/null
+package tim.prune.gui;
+
+import java.awt.BorderLayout;
+import java.awt.Color;
+import java.awt.Dimension;
+import java.awt.FlowLayout;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+
+import javax.swing.BoxLayout;
+import javax.swing.JButton;
+import javax.swing.JDialog;
+import javax.swing.JLabel;
+import javax.swing.JPanel;
+import javax.swing.JSlider;
+import javax.swing.event.ChangeEvent;
+import javax.swing.event.ChangeListener;
+
+import tim.prune.I18nManager;
+
+/**
+ * Class to offer a dialog to choose a colour.
+ * Normally a JColorChooser would be used, but this is too buggy
+ * in Java 1.6 and extremely prone to thread-locking, meaning
+ * that the application has to be killed (and all data lost).
+ */
+public class ColourChooser
+{
+ /** main dialog object */
+ private JDialog _dialog = null;
+ /** array of three slider objects for rgb */
+ private JSlider[] _rgbSliders = null;
+ /** array of labels for rgb values */
+ private JLabel[] _rgbLabels = null;
+ /** colour patch */
+ private ColourPatch _patch = null;
+ /** chosen colour */
+ private Color _chosenColour = null;
+
+
+ /**
+ * Constructor
+ * @param inParent parent dialog
+ */
+ public ColourChooser(JDialog inParent)
+ {
+ _dialog = new JDialog(inParent, I18nManager.getText("dialog.colourchooser.title"), true);
+ _dialog.setLocationRelativeTo(inParent);
+ _dialog.getContentPane().add(makeContents());
+ _dialog.pack();
+ }
+
+ /**
+ * Make the dialog contents
+ * @return JPanel containing dialog elements
+ */
+ private JPanel makeContents()
+ {
+ JPanel mainPanel = new JPanel();
+ mainPanel.setLayout(new BorderLayout());
+ _rgbSliders = new JSlider[3];
+ _rgbLabels = new JLabel[3];
+ _patch = new ColourPatch(Color.WHITE);
+ JPanel centrePanel = new JPanel();
+ centrePanel.setLayout(new BorderLayout());
+ centrePanel.add(_patch, BorderLayout.CENTER);
+
+ JPanel sliderPanel = new JPanel();
+ sliderPanel.setLayout(new BoxLayout(sliderPanel, BoxLayout.Y_AXIS));
+ final String[] labelKeys = {"red", "green", "blue"};
+ for (int i=0; i<3; i++)
+ {
+ String key = I18nManager.getText("dialog.colourchooser." + labelKeys[i]);
+ sliderPanel.add(new JLabel(key));
+ _rgbSliders[i] = new JSlider(0, 255);
+ _rgbSliders[i].addChangeListener(new ChangeListener() {
+ public void stateChanged(ChangeEvent arg0) {
+ updatePatch();
+ }
+ });
+ _rgbSliders[i].setToolTipText(key);
+ JPanel sliderHolder = new JPanel();
+ sliderHolder.setLayout(new BorderLayout(5, 0));
+ sliderHolder.add(_rgbSliders[i], BorderLayout.CENTER);
+ _rgbLabels[i] = new JLabel("255");
+ _rgbLabels[i].setPreferredSize(new Dimension(40, 1));
+ sliderHolder.add(_rgbLabels[i], BorderLayout.EAST);
+ sliderPanel.add(sliderHolder);
+ }
+ centrePanel.add(sliderPanel, BorderLayout.SOUTH);
+ mainPanel.add(centrePanel, BorderLayout.CENTER);
+
+ // Button panel for ok, cancel
+ JPanel buttonPanel = new JPanel();
+ buttonPanel.setLayout(new FlowLayout(FlowLayout.RIGHT));
+ JButton okButton = new JButton(I18nManager.getText("button.ok"));
+ okButton.addActionListener(new ActionListener() {
+ public void actionPerformed(ActionEvent e) {
+ _chosenColour = _patch.getBackground();
+ _dialog.setVisible(false);
+ }
+ });
+ buttonPanel.add(okButton);
+ JButton cancelButton = new JButton(I18nManager.getText("button.cancel"));
+ cancelButton.addActionListener(new ActionListener() {
+ public void actionPerformed(ActionEvent e) {
+ _chosenColour = null;
+ _dialog.setVisible(false);
+ }
+ });
+ buttonPanel.add(cancelButton);
+ mainPanel.add(buttonPanel, BorderLayout.SOUTH);
+ return mainPanel;
+ }
+
+ /**
+ * Show the dialog to choose a colour
+ * @param inStartColour current colour
+ */
+ public void showDialog(Color inStartColour)
+ {
+ // Initialise sliders
+ _rgbSliders[0].setValue(inStartColour.getRed());
+ _rgbSliders[1].setValue(inStartColour.getGreen());
+ _rgbSliders[2].setValue(inStartColour.getBlue());
+ updatePatch();
+ _dialog.setLocationRelativeTo(_dialog.getParent());
+ _dialog.setVisible(true);
+ }
+
+ /**
+ * Update the patch colour from the slider values
+ */
+ private void updatePatch()
+ {
+ for (int i=0; i<3; i++) {
+ _rgbLabels[i].setText("" + _rgbSliders[i].getValue());
+ }
+ final Color colour = new Color(_rgbSliders[0].getValue(),
+ _rgbSliders[1].getValue(),_rgbSliders[2].getValue());
+ _patch.setColour(colour);
+ }
+
+ /**
+ * @return the selected colour, or null if cancel pressed
+ */
+ public Color getChosenColour()
+ {
+ return _chosenColour;
+ }
+}
--- /dev/null
+package tim.prune.gui;
+
+import java.awt.Color;
+import java.awt.Dimension;
+import javax.swing.JPanel;
+
+import tim.prune.config.ColourUtils;
+
+/**
+ * Class to act as a colour patch to illustrate a chosen colour
+ */
+public class ColourPatch extends JPanel
+{
+ /**
+ * Constructor
+ */
+ public ColourPatch(Color inColour)
+ {
+ Dimension size = new Dimension(80, 50);
+ setMinimumSize(size);
+ setPreferredSize(size);
+ setColour(inColour);
+ }
+
+ /**
+ * Set the colour of the patch
+ * @param inColour Color to use
+ */
+ public void setColour(Color inColour)
+ {
+ super.setBackground(inColour);
+ setToolTipText(ColourUtils.makeHexCode(inColour));
+ }
+}
import java.awt.Component;
import java.awt.Dimension;
import java.awt.Font;
+import java.awt.Insets;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.text.NumberFormat;
import javax.swing.BorderFactory;
import javax.swing.Box;
import javax.swing.BoxLayout;
+import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.border.EtchedBorder;
-import tim.prune.Config;
import tim.prune.DataSubscriber;
+import tim.prune.FunctionLibrary;
+import tim.prune.GenericFunction;
import tim.prune.I18nManager;
+import tim.prune.config.Config;
import tim.prune.data.Altitude;
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;
// Point details
private JLabel _indexLabel = null;
private JLabel _latLabel = null, _longLabel = null;
- private JLabel _altLabel = null, _nameLabel = null;
+ private JLabel _altLabel = null;
private JLabel _timeLabel = null, _speedLabel = null;
+ private JLabel _nameLabel = null, _typeLabel = null;
// Range details
private JLabel _rangeLabel = null;
- private JLabel _distanceLabel = null, _movingDistanceLabel = null;
+ private JLabel _distanceLabel = null;
private JLabel _durationLabel = null;
private JLabel _altRangeLabel = null, _updownLabel = null;
- private JLabel _aveSpeedLabel = null, _aveMovingSpeedLabel = null;
- private JLabel _paceLabel = null;
+ private JLabel _aveSpeedLabel = null;
// Photo details
private JLabel _photoLabel = null;
private PhotoThumbnail _photoThumbnail = null;
private JLabel _photoTimestampLabel = null;
private JLabel _photoConnectedLabel = null;
+ private JPanel _rotationButtons = null;
// Units
private JComboBox _coordFormatDropdown = null;
private static final String LABEL_POINT_ALTITUDE = I18nManager.getText("fieldname.altitude") + ": ";
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_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_MOVINGDISTANCE = I18nManager.getText("fieldname.movingdistance") + ": ";
private static final String LABEL_RANGE_ALTITUDE = I18nManager.getText("fieldname.altitude") + ": ";
private static final String LABEL_RANGE_CLIMB = I18nManager.getText("details.range.climb") + ": ";
private static final String LABEL_RANGE_DESCENT = ", " + I18nManager.getText("details.range.descent") + ": ";
pointDetailsPanel.add(_speedLabel);
_nameLabel = new JLabel("");
pointDetailsPanel.add(_nameLabel);
+ _typeLabel = new JLabel("");
+ pointDetailsPanel.add(_typeLabel);
pointDetailsPanel.setAlignmentX(Component.LEFT_ALIGNMENT);
// range details panel
rangeDetailsPanel.add(_rangeLabel);
_distanceLabel = new JLabel("");
rangeDetailsPanel.add(_distanceLabel);
- _movingDistanceLabel = new JLabel("");
- rangeDetailsPanel.add(_movingDistanceLabel);
_durationLabel = new JLabel("");
rangeDetailsPanel.add(_durationLabel);
_aveSpeedLabel = new JLabel("");
rangeDetailsPanel.add(_aveSpeedLabel);
- _aveMovingSpeedLabel = new JLabel("");
- rangeDetailsPanel.add(_aveMovingSpeedLabel);
- _paceLabel = new JLabel("");
- rangeDetailsPanel.add(_paceLabel);
_altRangeLabel = new JLabel("");
rangeDetailsPanel.add(_altRangeLabel);
_updownLabel = new JLabel("");
_photoThumbnail.setVisible(false);
_photoThumbnail.setPreferredSize(new Dimension(100, 100));
photoDetailsPanel.add(_photoThumbnail);
+ // Rotate buttons
+ JButton rotLeft = makeRotateButton(IconManager.ROTATE_LEFT, FunctionLibrary.FUNCTION_ROTATE_PHOTO_LEFT);
+ JButton rotRight = makeRotateButton(IconManager.ROTATE_RIGHT, FunctionLibrary.FUNCTION_ROTATE_PHOTO_RIGHT);
+ _rotationButtons = new JPanel();
+ _rotationButtons.add(rotLeft);
+ _rotationButtons.add(rotRight);
+ _rotationButtons.setAlignmentX(Component.LEFT_ALIGNMENT);
+ _rotationButtons.setVisible(false);
+ photoDetailsPanel.add(_rotationButtons);
// add the details panels to the main panel
mainPanel.add(pointDetailsPanel);
_altLabel.setText("");
_timeLabel.setText("");
_nameLabel.setText("");
+ _typeLabel.setText("");
}
else
{
else {
_timeLabel.setText("");
}
- String name = currentPoint.getWaypointName();
+ // Waypoint name
+ final String name = currentPoint.getWaypointName();
if (name != null && !name.equals(""))
{
_nameLabel.setText(LABEL_POINT_WAYPOINTNAME + name);
}
else _nameLabel.setText("");
+ // Waypoint type
+ final String type = currentPoint.getFieldValue(Field.WAYPT_TYPE);
+ if (type != null && !type.equals("")) {
+ _typeLabel.setText(LABEL_POINT_WAYPOINTTYPE + type);
+ }
+ else _typeLabel.setText("");
}
// Update range details
{
_rangeLabel.setText(I18nManager.getText("details.norangeselection"));
_distanceLabel.setText("");
- _movingDistanceLabel.setText("");
_durationLabel.setText("");
_altRangeLabel.setText("");
_updownLabel.setText("");
_aveSpeedLabel.setText("");
- _aveMovingSpeedLabel.setText("");
- _paceLabel.setText("");
}
else
{
+ (selection.getStart()+1) + " " + I18nManager.getText("details.range.to")
+ " " + (selection.getEnd()+1));
_distanceLabel.setText(LABEL_RANGE_DISTANCE + roundedNumber(selection.getDistance(distUnits)) + " " + distUnitsStr);
- if (selection.getHasMultipleSegments()) {
- _movingDistanceLabel.setText(LABEL_RANGE_MOVINGDISTANCE + roundedNumber(selection.getMovingDistance(distUnits)) + " " + distUnitsStr);
- }
- else {
- _movingDistanceLabel.setText(null);
- }
if (selection.getNumSeconds() > 0)
{
- _durationLabel.setText(LABEL_RANGE_DURATION + buildDurationString(selection.getNumSeconds()));
+ _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);
- if (selection.getHasMultipleSegments()) {
- _aveMovingSpeedLabel.setText(I18nManager.getText("details.range.avemovingspeed") + ": "
- + roundedNumber(selection.getMovingDistance(distUnits)/selection.getMovingSeconds()*3600.0) + " " + speedUnitsStr);
- }
- else {
- _aveMovingSpeedLabel.setText(null);
- }
- if (Config.getConfigBoolean(Config.KEY_SHOW_PACE)) {
- _paceLabel.setText(I18nManager.getText("details.range.pace") + ": "
- + buildDurationString((long) (selection.getNumSeconds()/selection.getDistance(distUnits)))
- + " / " + distUnitsStr);
- }
- else {
- _paceLabel.setText("");
- }
}
else {
_durationLabel.setText("");
_aveSpeedLabel.setText("");
- _aveMovingSpeedLabel.setText("");
- _paceLabel.setText("");
}
String altUnitsLabel = getAltitudeUnitsLabel(selection.getAltitudeFormat());
IntegerRange altRange = selection.getAltitudeRange();
_photoTimestampLabel.setText("");
_photoConnectedLabel.setText("");
_photoThumbnail.setVisible(false);
+ _rotationButtons.setVisible(false);
}
else
{
I18nManager.getText("dialog.about.no"):I18nManager.getText("dialog.about.yes")));
_photoThumbnail.setVisible(true);
_photoThumbnail.setPhoto(currentPhoto);
+ _rotationButtons.setVisible(true);
+ if ((inUpdateType & DataSubscriber.PHOTOS_MODIFIED) > 0) {_photoThumbnail.refresh();}
}
_photoThumbnail.repaint();
}
}
- /**
- * Build a String to describe a time duration
- * @param inNumSecs number of seconds
- * @return time as a string, days, hours, mins, secs as appropriate
- */
- private static String buildDurationString(long inNumSecs)
- {
- if (inNumSecs <= 0L) return "";
- if (inNumSecs < 60L) return "" + inNumSecs + I18nManager.getText("display.range.time.secs");
- if (inNumSecs < 3600L) return "" + (inNumSecs / 60) + I18nManager.getText("display.range.time.mins")
- + " " + (inNumSecs % 60) + I18nManager.getText("display.range.time.secs");
- if (inNumSecs < 86400L) return "" + (inNumSecs / 60 / 60) + I18nManager.getText("display.range.time.hours")
- + " " + ((inNumSecs / 60) % 60) + I18nManager.getText("display.range.time.mins");
- if (inNumSecs < 432000L) return "" + (inNumSecs / 86400L) + I18nManager.getText("display.range.time.days")
- + " " + (inNumSecs / 60 / 60) % 24 + I18nManager.getText("display.range.time.hours");
- if (inNumSecs < 8640000L) return "" + (inNumSecs / 86400L) + I18nManager.getText("display.range.time.days");
- return "big";
- }
-
-
/**
* Format a number to a sensible precision
* @param inDist distance
_distanceFormatter.setMinimumFractionDigits(numDigits);
return _distanceFormatter.format(inDist);
}
+
+ /**
+ * Create a little button for rotating the current photo
+ * @param inIcon icon to use (from IconManager)
+ * @param inFunction function to call (from FunctionLibrary)
+ * @return button object
+ */
+ private static JButton makeRotateButton(String inIcon, GenericFunction inFunction)
+ {
+ JButton button = new JButton(IconManager.getImageIcon(inIcon));
+ button.setToolTipText(I18nManager.getText(inFunction.getNameKey()));
+ button.setMargin(new Insets(0, 2, 0, 2));
+ button.addActionListener(new FunctionLauncher(inFunction));
+ return button;
+ }
}
--- /dev/null
+package tim.prune.gui;
+
+import tim.prune.I18nManager;
+
+/**
+ * Class to provide general display util methods
+ */
+public abstract class DisplayUtils
+{
+ /**
+ * Build a String to describe a time duration
+ * @param inNumSecs number of seconds
+ * @return time as a string, days, hours, mins, secs as appropriate
+ */
+ public static String buildDurationString(long inNumSecs)
+ {
+ if (inNumSecs <= 0L) return "";
+ if (inNumSecs < 60L) return "" + inNumSecs + I18nManager.getText("display.range.time.secs");
+ if (inNumSecs < 3600L) return "" + (inNumSecs / 60) + I18nManager.getText("display.range.time.mins")
+ + " " + (inNumSecs % 60) + I18nManager.getText("display.range.time.secs");
+ if (inNumSecs < 86400L) return "" + (inNumSecs / 60 / 60) + I18nManager.getText("display.range.time.hours")
+ + " " + ((inNumSecs / 60) % 60) + I18nManager.getText("display.range.time.mins");
+ if (inNumSecs < 432000L) return "" + (inNumSecs / 86400L) + I18nManager.getText("display.range.time.days")
+ + " " + (inNumSecs / 60 / 60) % 24 + I18nManager.getText("display.range.time.hours");
+ if (inNumSecs < 8640000L) return "" + (inNumSecs / 86400L) + I18nManager.getText("display.range.time.days");
+ return "big";
+ }
+}
import java.awt.event.MouseListener;
import tim.prune.I18nManager;
+import tim.prune.config.ColourScheme;
+import tim.prune.config.Config;
import tim.prune.data.TrackInfo;
protected static final int BORDER_WIDTH = 8;
// Colours
- private static final Color COLOR_BORDER_BG = Color.WHITE;
- private static final Color COLOR_CHART_BG = Color.WHITE;
- private static final Color COLOR_CHART_LINE = Color.BLACK;
private static final Color COLOR_NODATA_TEXT = Color.GRAY;
super.paint(inG);
int width = getWidth();
int height = getHeight();
+ // Get colours
+ ColourScheme colourScheme = Config.getColourScheme();
+ final Color borderColour = colourScheme.getColour(ColourScheme.IDX_BORDERS);
+ final Color backgroundColour = colourScheme.getColour(ColourScheme.IDX_BACKGROUND);
+ final Color insideColour = backgroundColour;
// border background
- inG.setColor(COLOR_BORDER_BG);
+ inG.setColor(backgroundColour);
inG.fillRect(0, 0, width, height);
if (width < 2*BORDER_WIDTH || height < 2*BORDER_WIDTH) return;
// blank graph area, with line border
- inG.setColor(COLOR_CHART_BG);
+ inG.setColor(insideColour);
inG.fillRect(BORDER_WIDTH, BORDER_WIDTH, width - 2*BORDER_WIDTH, height-2*BORDER_WIDTH);
// Display message if no data to be displayed
if (_track == null || _track.getNumPoints() <= 0)
inG.drawString(I18nManager.getText("display.nodata"), 50, height/2);
}
else {
- inG.setColor(COLOR_CHART_LINE);
+ inG.setColor(borderColour);
inG.drawRect(BORDER_WIDTH, BORDER_WIDTH, width - 2*BORDER_WIDTH, height-2*BORDER_WIDTH);
}
}
--- /dev/null
+package tim.prune.gui;
+
+import java.awt.GridBagConstraints;
+import java.awt.GridBagLayout;
+import java.awt.Insets;
+
+import javax.swing.JComponent;
+import javax.swing.JPanel;
+
+/**
+ * Class to make it easier to use GridBagLayout
+ * for a two-column, non-equal-width layout
+ */
+public class GuiGridLayout
+{
+ private GridBagLayout _layout = null;
+ private GridBagConstraints _constraints = null;
+ private JPanel _panel = null;
+ private int _x = 0;
+ private int _y = 0;
+
+ /**
+ * Constructor
+ * @param inPanel panel using layout
+ */
+ public GuiGridLayout(JPanel inPanel)
+ {
+ _panel = inPanel;
+ _layout = new GridBagLayout();
+ _constraints = new GridBagConstraints();
+ _constraints.weightx = 1.0;
+ _constraints.weighty = 0.0;
+ _constraints.ipadx = 10;
+ _constraints.ipady = 1;
+ _constraints.insets = new Insets(1, 5, 1, 5);
+ // Apply layout to panel
+ _panel.setLayout(_layout);
+ }
+
+ /**
+ * Add the given component to the grid
+ * @param inComponent component to add
+ */
+ public void add(JComponent inComponent)
+ {
+ _constraints.gridx = _x;
+ _constraints.gridy = _y;
+ _constraints.weightx = (_x==0?0.5:1.0);
+ // set anchor
+ _constraints.anchor = (_x == 0?GridBagConstraints.LINE_END:GridBagConstraints.LINE_START);
+ _layout.setConstraints(inComponent, _constraints);
+ // add to panel
+ _panel.add(inComponent);
+ // work out next position
+ _x++;
+ if (_x > 1) {
+ _x = 0;
+ _y++;
+ }
+ }
+}
/** Icon for cut range and move */
public static final String CUT_AND_MOVE = "cut_and_move.gif";
+ /** Icon for rotating photos leftwards */
+ public static final String ROTATE_LEFT = "rotate_left_icon.png";
+ /** Icon for rotating photos rightwards */
+ public static final String ROTATE_RIGHT = "rotate_right_icon.png";
/**
* Get the specified image
import java.awt.Dimension;
import java.awt.Graphics;
+import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.image.BufferedImage;
import java.awt.image.ConvolveOp;
*/
public static Dimension getThumbnailSize(int inOrigWidth, int inOrigHeight, int inMaxWidth, int inMaxHeight)
{
- if (inMaxWidth <= 0 || inMaxHeight <= 0)
- {
- //System.out.println("Can't do it - maxwidth=" + inMaxWidth + ", maxheight=" + inMaxHeight);
- return new Dimension(0,0);
- }
+ assert(inMaxWidth > 0 && inMaxHeight > 0);
// 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;
// calculate new width and height
return new Dimension ((int) (zoom * inOrigWidth), (int) (zoom * inOrigHeight));
}
+
+
+ /**
+ * Create a new image by rotating and scaling the given one
+ * @param inImage input image
+ * @param inMaxWidth maximum width of output image
+ * @param inMaxHeight maximum height of output image
+ * @param inRotationDegrees number of degrees to rotate clockwise (0, 90, 180 or 270)
+ * @return rotated, scaled image
+ */
+ public static BufferedImage rotateImage(Image inImage, int inMaxWidth, int inMaxHeight, int inRotationDegrees)
+ {
+ // Create scaled image of suitable size
+ boolean isRotated = (inRotationDegrees % 180 != 0);
+ int origWidth = inImage.getWidth(null);
+ int origHeight = inImage.getHeight(null);
+ int thumbWidth = isRotated?origHeight:origWidth;
+ int thumbHeight = isRotated?origWidth:origHeight;
+ Dimension scaledSize = getThumbnailSize(thumbWidth, thumbHeight, inMaxWidth, inMaxHeight);
+ BufferedImage result = new BufferedImage(scaledSize.width, scaledSize.height, BufferedImage.TYPE_INT_RGB);
+ // Do different things according to rotation angle (a bit messy, sorry!)
+ if (inRotationDegrees == 0)
+ {
+ // Not rotated, so just copy image directly
+ result.getGraphics().drawImage(inImage, 0, 0, scaledSize.width, scaledSize.height, null);
+ }
+ else
+ {
+ // Need to use Graphics2D for rotation, not Graphics
+ Graphics2D g2d = result.createGraphics();
+ switch (inRotationDegrees)
+ {
+ case 90:
+ g2d.rotate(Math.PI / 2, 0.0, 0.0);
+ g2d.drawImage(inImage, 0, -scaledSize.width, scaledSize.height, scaledSize.width, null);
+ break;
+ case 180:
+ g2d.rotate(Math.PI, scaledSize.width/2.0, scaledSize.height/2.0);
+ g2d.drawImage(inImage, 0, 0, scaledSize.width, scaledSize.height, null);
+ break;
+ case 270:
+ g2d.rotate(Math.PI * 3/2, 0.0, 0.0);
+ g2d.drawImage(inImage, -scaledSize.height, 0, scaledSize.height, scaledSize.width, null);
+ }
+ // Clear up memory
+ g2d.dispose();
+ }
+ return result;
+ }
}
import javax.swing.KeyStroke;
import tim.prune.App;
-import tim.prune.Config;
import tim.prune.DataSubscriber;
import tim.prune.FunctionLibrary;
import tim.prune.GenericFunction;
import tim.prune.I18nManager;
import tim.prune.UpdateMessageBroker;
+import tim.prune.config.Config;
+import tim.prune.data.Photo;
import tim.prune.data.PhotoList;
import tim.prune.data.Selection;
import tim.prune.data.Track;
private JMenuItem _selectStartItem = null;
private JMenuItem _selectEndItem = null;
private JMenuItem _findWaypointItem = null;
+ private JMenuItem _duplicatePointItem = null;
private JMenuItem _reverseItem = null;
private JMenuItem _addTimeOffsetItem = null;
private JMenuItem _addAltitudeOffsetItem = null;
private JMenuItem _mergeSegmentsItem = null;
private JMenu _rearrangeMenu = null;
private JMenuItem _cutAndMoveItem = null;
+ private JMenuItem _convertNamesToTimesItem = null;
+ private JCheckBoxMenuItem _mapCheckbox = null;
private JMenuItem _show3dItem = null;
private JMenu _browserMapMenu = null;
private JMenuItem _chartItem = null;
- private JCheckBoxMenuItem _paceCheckbox = null;
private JMenuItem _getGpsiesItem = null;
private JMenuItem _distanceItem = null;
+ private JMenuItem _fullRangeDetailsItem = null;
private JMenuItem _saveExifItem = null;
private JMenuItem _connectPhotoItem = null;
private JMenuItem _deletePhotoItem = null;
private JMenuItem _disconnectPhotoItem = null;
private JMenuItem _correlatePhotosItem = null;
+ private JMenuItem _rearrangePhotosItem = null;
+ private JMenuItem _rotatePhotoLeft = null;
+ private JMenuItem _rotatePhotoRight = null;
+ private JMenuItem _ignoreExifThumb = null;
// ActionListeners for reuse by menu and toolbar
private ActionListener _openFileAction = null;
});
fileMenu.add(exitMenuItem);
menubar.add(fileMenu);
- // Edit menu
- JMenu editMenu = new JMenu(I18nManager.getText("menu.edit"));
- setAltKey(editMenu, "altkey.menu.edit");
+ // Track menu
+ JMenu trackMenu = new JMenu(I18nManager.getText("menu.track"));
+ setAltKey(trackMenu, "altkey.menu.track");
_undoItem = new JMenuItem(I18nManager.getText("menu.edit.undo"));
setShortcut(_undoItem, "shortcut.menu.edit.undo");
_undoAction = new ActionListener() {
};
_undoItem.addActionListener(_undoAction);
_undoItem.setEnabled(false);
- editMenu.add(_undoItem);
+ trackMenu.add(_undoItem);
_clearUndoItem = new JMenuItem(I18nManager.getText("menu.edit.clearundo"));
_clearUndoItem.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e)
}
});
_clearUndoItem.setEnabled(false);
- editMenu.add(_clearUndoItem);
- editMenu.addSeparator();
- _editPointItem = new JMenuItem(I18nManager.getText("menu.edit.editpoint"));
- _editPointAction = new ActionListener() {
- public void actionPerformed(ActionEvent e)
- {
- _app.editCurrentPoint();
- }
- };
- _editPointItem.addActionListener(_editPointAction);
- _editPointItem.setEnabled(false);
- editMenu.add(_editPointItem);
- _editWaypointNameItem = makeMenuItem(FunctionLibrary.FUNCTION_EDIT_WAYPOINT_NAME);
- _editWaypointNameItem.setEnabled(false);
- editMenu.add(_editWaypointNameItem);
- _deletePointItem = new JMenuItem(I18nManager.getText("menu.edit.deletepoint"));
- _deletePointAction = new ActionListener() {
- public void actionPerformed(ActionEvent e)
- {
- _app.deleteCurrentPoint();
- }
- };
- _deletePointItem.addActionListener(_deletePointAction);
- _deletePointItem.setEnabled(false);
- editMenu.add(_deletePointItem);
- _deleteRangeItem = new JMenuItem(I18nManager.getText("menu.edit.deleterange"));
- _deleteRangeAction = new ActionListener() {
- public void actionPerformed(ActionEvent e)
- {
- _app.deleteSelectedRange();
- }
- };
- _deleteRangeItem.addActionListener(_deleteRangeAction);
- _deleteRangeItem.setEnabled(false);
- editMenu.add(_deleteRangeItem);
- editMenu.addSeparator();
+ trackMenu.add(_clearUndoItem);
+ trackMenu.addSeparator();
_compressItem = makeMenuItem(FunctionLibrary.FUNCTION_COMPRESS);
setShortcut(_compressItem, "shortcut.menu.edit.compress");
_compressItem.setEnabled(false);
- editMenu.add(_compressItem);
+ trackMenu.add(_compressItem);
_deleteMarkedPointsItem = new JMenuItem(I18nManager.getText("menu.edit.deletemarked"));
_deleteMarkedPointsItem.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e)
}
});
_deleteMarkedPointsItem.setEnabled(false);
- editMenu.add(_deleteMarkedPointsItem);
- editMenu.addSeparator();
- _interpolateItem = new JMenuItem(I18nManager.getText("menu.edit.interpolate"));
- _interpolateItem.addActionListener(new ActionListener() {
- public void actionPerformed(ActionEvent e)
- {
- _app.interpolateSelection();
- }
- });
- _interpolateItem.setEnabled(false);
- editMenu.add(_interpolateItem);
- _averageItem = new JMenuItem(I18nManager.getText("menu.edit.average"));
- _averageItem.addActionListener(new ActionListener() {
- public void actionPerformed(ActionEvent e)
- {
- _app.averageSelection();
- }
- });
- _averageItem.setEnabled(false);
- editMenu.add(_averageItem);
- _reverseItem = new JMenuItem(I18nManager.getText("menu.edit.reverse"));
- _reverseItem.addActionListener(new ActionListener() {
- public void actionPerformed(ActionEvent e)
- {
- _app.reverseRange();
- }
- });
- _reverseItem.setEnabled(false);
- editMenu.add(_reverseItem);
- _addTimeOffsetItem = makeMenuItem(FunctionLibrary.FUNCTION_ADD_TIME_OFFSET);
- _addTimeOffsetItem.setEnabled(false);
- editMenu.add(_addTimeOffsetItem);
- _addAltitudeOffsetItem = makeMenuItem(FunctionLibrary.FUNCTION_ADD_ALTITUDE_OFFSET);
- _addAltitudeOffsetItem.setEnabled(false);
- editMenu.add(_addAltitudeOffsetItem);
- _mergeSegmentsItem = new JMenuItem(I18nManager.getText("menu.edit.mergetracksegments"));
- _mergeSegmentsItem.addActionListener(new ActionListener() {
- public void actionPerformed(ActionEvent e)
- {
- _app.mergeTrackSegments();
- }
- });
- _mergeSegmentsItem.setEnabled(false);
- editMenu.add(_mergeSegmentsItem);
+ trackMenu.add(_deleteMarkedPointsItem);
+ trackMenu.addSeparator();
// Rearrange waypoints
_rearrangeMenu = new JMenu(I18nManager.getText("menu.edit.rearrange"));
_rearrangeMenu.setEnabled(false);
});
rearrangeNearestItem.setEnabled(true);
_rearrangeMenu.add(rearrangeNearestItem);
- editMenu.add(_rearrangeMenu);
- _cutAndMoveItem = new JMenuItem(I18nManager.getText("menu.edit.cutandmove"));
- _cutAndMoveItem.addActionListener(new ActionListener() {
- public void actionPerformed(ActionEvent e)
- {
- _app.cutAndMoveSelection();
- }
- });
- _cutAndMoveItem.setEnabled(false);
- editMenu.add(_cutAndMoveItem);
- menubar.add(editMenu);
+ trackMenu.add(_rearrangeMenu);
+ // Get gpsies tracks
+ _getGpsiesItem = makeMenuItem(FunctionLibrary.FUNCTION_GET_GPSIES);
+ _getGpsiesItem.setEnabled(false);
+ trackMenu.add(_getGpsiesItem);
+ menubar.add(trackMenu);
- // Select menu
- JMenu selectMenu = new JMenu(I18nManager.getText("menu.select"));
- setAltKey(selectMenu, "altkey.menu.select");
+ // Range menu
+ JMenu rangeMenu = new JMenu(I18nManager.getText("menu.range"));
+ setAltKey(rangeMenu, "altkey.menu.range");
_selectAllItem = new JMenuItem(I18nManager.getText("menu.select.all"));
setShortcut(_selectAllItem, "shortcut.menu.select.all");
_selectAllItem.setEnabled(false);
_selection.selectRange(0, _track.getNumPoints()-1);
}
});
- selectMenu.add(_selectAllItem);
+ rangeMenu.add(_selectAllItem);
_selectNoneItem = new JMenuItem(I18nManager.getText("menu.select.none"));
_selectNoneItem.setEnabled(false);
_selectNoneItem.addActionListener(new ActionListener() {
_app.selectNone();
}
});
- selectMenu.add(_selectNoneItem);
- selectMenu.addSeparator();
+ rangeMenu.add(_selectNoneItem);
+ rangeMenu.addSeparator();
_selectStartItem = new JMenuItem(I18nManager.getText("menu.select.start"));
_selectStartItem.setEnabled(false);
_selectStartAction = new ActionListener() {
}
};
_selectStartItem.addActionListener(_selectStartAction);
- selectMenu.add(_selectStartItem);
+ rangeMenu.add(_selectStartItem);
_selectEndItem = new JMenuItem(I18nManager.getText("menu.select.end"));
_selectEndItem.setEnabled(false);
_selectEndAction = new ActionListener() {
}
};
_selectEndItem.addActionListener(_selectEndAction);
- selectMenu.add(_selectEndItem);
- selectMenu.addSeparator();
+ rangeMenu.add(_selectEndItem);
+ rangeMenu.addSeparator();
+ _deleteRangeItem = new JMenuItem(I18nManager.getText("menu.edit.deleterange"));
+ _deleteRangeAction = new ActionListener() {
+ public void actionPerformed(ActionEvent e)
+ {
+ _app.deleteSelectedRange();
+ }
+ };
+ _deleteRangeItem.addActionListener(_deleteRangeAction);
+ _deleteRangeItem.setEnabled(false);
+ rangeMenu.add(_deleteRangeItem);
+ _reverseItem = new JMenuItem(I18nManager.getText("menu.edit.reverse"));
+ _reverseItem.addActionListener(new ActionListener() {
+ public void actionPerformed(ActionEvent e)
+ {
+ _app.reverseRange();
+ }
+ });
+ _reverseItem.setEnabled(false);
+ rangeMenu.add(_reverseItem);
+ _addTimeOffsetItem = makeMenuItem(FunctionLibrary.FUNCTION_ADD_TIME_OFFSET);
+ _addTimeOffsetItem.setEnabled(false);
+ rangeMenu.add(_addTimeOffsetItem);
+ _addAltitudeOffsetItem = makeMenuItem(FunctionLibrary.FUNCTION_ADD_ALTITUDE_OFFSET);
+ _addAltitudeOffsetItem.setEnabled(false);
+ rangeMenu.add(_addAltitudeOffsetItem);
+ _mergeSegmentsItem = new JMenuItem(I18nManager.getText("menu.edit.mergetracksegments"));
+ _mergeSegmentsItem.addActionListener(new ActionListener() {
+ public void actionPerformed(ActionEvent e)
+ {
+ _app.mergeTrackSegments();
+ }
+ });
+ _mergeSegmentsItem.setEnabled(false);
+ rangeMenu.add(_mergeSegmentsItem);
+ rangeMenu.addSeparator();
+ _interpolateItem = new JMenuItem(I18nManager.getText("menu.edit.interpolate"));
+ _interpolateItem.addActionListener(new ActionListener() {
+ public void actionPerformed(ActionEvent e)
+ {
+ _app.interpolateSelection();
+ }
+ });
+ _interpolateItem.setEnabled(false);
+ rangeMenu.add(_interpolateItem);
+ _averageItem = new JMenuItem(I18nManager.getText("menu.edit.average"));
+ _averageItem.addActionListener(new ActionListener() {
+ public void actionPerformed(ActionEvent e)
+ {
+ _app.averageSelection();
+ }
+ });
+ _averageItem.setEnabled(false);
+ rangeMenu.add(_averageItem);
+ _cutAndMoveItem = new JMenuItem(I18nManager.getText("menu.edit.cutandmove"));
+ _cutAndMoveItem.addActionListener(new ActionListener() {
+ public void actionPerformed(ActionEvent e)
+ {
+ _app.cutAndMoveSelection();
+ }
+ });
+ _cutAndMoveItem.setEnabled(false);
+ rangeMenu.add(_cutAndMoveItem);
+ _convertNamesToTimesItem = makeMenuItem(FunctionLibrary.FUNCTION_CONVERT_NAMES_TO_TIMES);
+ _convertNamesToTimesItem.setEnabled(false);
+ rangeMenu.add(_convertNamesToTimesItem);
+ menubar.add(rangeMenu);
+
+ // Point menu
+ JMenu pointMenu = new JMenu(I18nManager.getText("menu.point"));
+ setAltKey(pointMenu, "altkey.menu.point");
+ _editPointItem = new JMenuItem(I18nManager.getText("menu.edit.editpoint"));
+ _editPointAction = new ActionListener() {
+ public void actionPerformed(ActionEvent e)
+ {
+ _app.editCurrentPoint();
+ }
+ };
+ _editPointItem.addActionListener(_editPointAction);
+ _editPointItem.setEnabled(false);
+ pointMenu.add(_editPointItem);
+ _editWaypointNameItem = makeMenuItem(FunctionLibrary.FUNCTION_EDIT_WAYPOINT_NAME);
+ _editWaypointNameItem.setEnabled(false);
+ pointMenu.add(_editWaypointNameItem);
+ _deletePointItem = new JMenuItem(I18nManager.getText("menu.edit.deletepoint"));
+ _deletePointAction = new ActionListener() {
+ public void actionPerformed(ActionEvent e)
+ {
+ _app.deleteCurrentPoint();
+ }
+ };
+ _deletePointItem.addActionListener(_deletePointAction);
+ _deletePointItem.setEnabled(false);
+ pointMenu.add(_deletePointItem);
+ pointMenu.addSeparator();
+ // find a waypoint
_findWaypointItem = makeMenuItem(FunctionLibrary.FUNCTION_FIND_WAYPOINT);
_findWaypointItem.setEnabled(false);
- selectMenu.add(_findWaypointItem);
- menubar.add(selectMenu);
+ pointMenu.add(_findWaypointItem);
+ // duplicate current point
+ _duplicatePointItem = makeMenuItem(FunctionLibrary.FUNCTION_DUPLICATE_POINT);
+ _duplicatePointItem.setEnabled(false);
+ pointMenu.add(_duplicatePointItem);
+ // paste coordinates function
+ JMenuItem pasteCoordsItem = makeMenuItem(FunctionLibrary.FUNCTION_PASTE_COORDINATES);
+ pointMenu.add(pasteCoordsItem);
+ menubar.add(pointMenu);
// Add view menu
JMenu viewMenu = new JMenu(I18nManager.getText("menu.view"));
setAltKey(viewMenu, "altkey.menu.view");
+ // Turn map display on/off
+ _mapCheckbox = new JCheckBoxMenuItem(
+ I18nManager.getText("menu.map.showmap"), false);
+ _mapCheckbox.addActionListener(new ActionListener() {
+ public void actionPerformed(ActionEvent e) {
+ Config.setConfigBoolean(Config.KEY_SHOW_MAP, _mapCheckbox.isSelected());
+ UpdateMessageBroker.informSubscribers();
+ }
+ });
+ viewMenu.add(_mapCheckbox);
_show3dItem = makeMenuItem(FunctionLibrary.FUNCTION_3D);
_show3dItem.setEnabled(false);
viewMenu.add(_show3dItem);
}
});
_browserMapMenu.add(yahooMapsItem);
+ JMenuItem bingMapsItem = new JMenuItem(I18nManager.getText("menu.view.browser.bing"));
+ bingMapsItem.addActionListener(new ActionListener() {
+ public void actionPerformed(ActionEvent e)
+ {
+ _app.showExternalMap(UrlGenerator.MAP_SOURCE_BING);
+ }
+ });
+ _browserMapMenu.add(bingMapsItem);
viewMenu.add(_browserMapMenu);
// Charts
_chartItem = makeMenuItem(FunctionLibrary.FUNCTION_CHARTS);
_distanceItem = makeMenuItem(FunctionLibrary.FUNCTION_DISTANCES);
_distanceItem.setEnabled(false);
viewMenu.add(_distanceItem);
- // Get gpsies tracks
- _getGpsiesItem = makeMenuItem(FunctionLibrary.FUNCTION_GET_GPSIES);
- _getGpsiesItem.setEnabled(false);
- viewMenu.add(_getGpsiesItem);
+ // full range details
+ _fullRangeDetailsItem = makeMenuItem(FunctionLibrary.FUNCTION_FULL_RANGE_DETAILS);
+ _fullRangeDetailsItem.setEnabled(false);
+ viewMenu.add(_fullRangeDetailsItem);
menubar.add(viewMenu);
// Add photo menu
});
_deletePhotoItem.setEnabled(false);
photoMenu.add(_deletePhotoItem);
+ // Rotate current photo
+ _rotatePhotoLeft = makeMenuItem(FunctionLibrary.FUNCTION_ROTATE_PHOTO_LEFT);
+ _rotatePhotoLeft.setEnabled(false);
+ photoMenu.add(_rotatePhotoLeft);
+ _rotatePhotoRight = makeMenuItem(FunctionLibrary.FUNCTION_ROTATE_PHOTO_RIGHT);
+ _rotatePhotoRight.setEnabled(false);
+ photoMenu.add(_rotatePhotoRight);
+ _ignoreExifThumb = makeMenuItem(FunctionLibrary.FUNCTION_IGNORE_EXIF_THUMB);
+ _ignoreExifThumb.setEnabled(false);
+ photoMenu.add(_ignoreExifThumb);
photoMenu.addSeparator();
// correlate all photos
_correlatePhotosItem = makeMenuItem(FunctionLibrary.FUNCTION_CORRELATE_PHOTOS);
_correlatePhotosItem.setEnabled(false);
photoMenu.add(_correlatePhotosItem);
+ // rearrange photo points
+ _rearrangePhotosItem = makeMenuItem(FunctionLibrary.FUNCTION_REARRANGE_PHOTOS);
+ _rearrangePhotosItem.setEnabled(false);
+ photoMenu.add(_rearrangePhotosItem);
menubar.add(photoMenu);
// Settings menu
// Set the map background
JMenuItem mapBgItem = makeMenuItem(FunctionLibrary.FUNCTION_SET_MAP_BG);
settingsMenu.add(mapBgItem);
- // Turn pace display on/off
- _paceCheckbox = new JCheckBoxMenuItem(
- I18nManager.getText("menu.settings.showpace"), false);
- _paceCheckbox.addActionListener(new ActionListener() {
- public void actionPerformed(ActionEvent e) {
- Config.setConfigBoolean(Config.KEY_SHOW_PACE, _paceCheckbox.isSelected());
- UpdateMessageBroker.informSubscribers();
- }
- });
- settingsMenu.add(_paceCheckbox);
// Set kmz image size
JMenuItem setKmzImageSizeItem = makeMenuItem(FunctionLibrary.FUNCTION_SET_KMZ_IMAGE_SIZE);
settingsMenu.add(setKmzImageSizeItem);
// Set program paths
JMenuItem setPathsItem = makeMenuItem(FunctionLibrary.FUNCTION_SET_PATHS);
settingsMenu.add(setPathsItem);
+ // Set colours
+ JMenuItem setColoursItem = makeMenuItem(FunctionLibrary.FUNCTION_SET_COLOURS);
+ settingsMenu.add(setColoursItem);
+ // Set language
+ JMenuItem setLanguageItem = makeMenuItem(FunctionLibrary.FUNCTION_SET_LANGUAGE);
+ settingsMenu.add(setLanguageItem);
settingsMenu.addSeparator();
// Save configuration
JMenuItem saveConfigMenuItem = makeMenuItem(FunctionLibrary.FUNCTION_SAVECONFIG);
_selectStartButton.setEnabled(hasPoint);
_selectEndItem.setEnabled(hasPoint);
_selectEndButton.setEnabled(hasPoint);
+ _duplicatePointItem.setEnabled(hasPoint);
// are there any photos?
boolean anyPhotos = _photos != null && _photos.getNumPhotos() > 0;
_saveExifItem.setEnabled(anyPhotos);
// is there a current photo?
boolean hasPhoto = anyPhotos && _selection.getCurrentPhotoIndex() >= 0;
// connect is available if photo and point selected, and photo has no point
- boolean connectAvailable = hasPhoto && hasPoint && _photos.getPhoto(_selection.getCurrentPhotoIndex()) != null
- && _photos.getPhoto(_selection.getCurrentPhotoIndex()).getDataPoint() == null;
+ Photo currentPhoto = _photos.getPhoto(_selection.getCurrentPhotoIndex());
+ boolean connectAvailable = hasPhoto && hasPoint && currentPhoto != null
+ && currentPhoto.getDataPoint() == null;
_connectPhotoItem.setEnabled(connectAvailable);
_connectPhotoButton.setEnabled(connectAvailable);
- _disconnectPhotoItem.setEnabled(hasPhoto && _photos.getPhoto(_selection.getCurrentPhotoIndex()) != null
- && _photos.getPhoto(_selection.getCurrentPhotoIndex()).getDataPoint() != null);
+ _disconnectPhotoItem.setEnabled(hasPhoto && currentPhoto != null && currentPhoto.getDataPoint() != null);
_correlatePhotosItem.setEnabled(anyPhotos && hasData);
+ _rearrangePhotosItem.setEnabled(anyPhotos && hasData && _track.getNumPoints() > 1);
_deletePhotoItem.setEnabled(hasPhoto);
+ _rotatePhotoLeft.setEnabled(hasPhoto);
+ _rotatePhotoRight.setEnabled(hasPhoto);
+ _ignoreExifThumb.setEnabled(hasPhoto && currentPhoto != null && currentPhoto.getExifThumbnail() != null);
// is there a current range?
boolean hasRange = (hasData && _selection.hasRangeSelected());
_deleteRangeItem.setEnabled(hasRange);
_reverseItem.setEnabled(hasRange);
_addTimeOffsetItem.setEnabled(hasRange);
_addAltitudeOffsetItem.setEnabled(hasRange);
+ _convertNamesToTimesItem.setEnabled(hasRange && _track.hasWaypoints());
+ _fullRangeDetailsItem.setEnabled(hasRange);
// Is the currently selected point outside the current range?
_cutAndMoveItem.setEnabled(hasRange && hasPoint &&
(_selection.getCurrentPointIndex() < _selection.getStart()
|| _selection.getCurrentPointIndex() > (_selection.getEnd()+1)));
+ // Has the map been switched on/off?
+ boolean mapsOn = Config.getConfigBoolean(Config.KEY_SHOW_MAP);
+ if (_mapCheckbox.isSelected() != mapsOn) {
+ _mapCheckbox.setSelected(mapsOn);
+ }
}
{
private Photo _photo = null;
private BufferedImage _thumbnail = null;
- private int _lastWidth = -1;
- private int _lastHeight = -1;
private boolean _loadingImage = false;
/** String to show before photo is loaded */
- private static final String _loadingString = I18nManager.getText("details.photo.loading") + " ...";
+ private static final String LOADING_STRING = I18nManager.getText("details.photo.loading") + " ...";
/**
*/
public PhotoThumbnail()
{
- // TODO: Make size of thumbnail dynamic, as big as it can be
setOpaque(true);
}
public void setPhoto(Photo inPhoto)
{
// Check whether the photo has changed
- if (_photo == inPhoto) {return;}
- _photo = inPhoto;
- _thumbnail = null;
+ if (_photo != inPhoto) {
+ _photo = inPhoto;
+ _thumbnail = null;
+ }
+ repaint();
}
+ /**
+ * Force a refresh / reload
+ */
+ public void refresh() {
+ _thumbnail = null;
+ }
/**
* Override paint method
super.paint(inG);
if (_photo != null)
{
- // recalculate thumbnail if photo has changed
- if (_thumbnail == null || getWidth() != _lastWidth || getHeight() != _lastHeight)
+ // read thumbnail in separate thread
+ if (_thumbnail == null && !_loadingImage)
{
- // initiate load if not already started
- if (!_loadingImage)
- {
- _loadingImage = true;
- new Thread(this).start();
- }
+ _loadingImage = true;
+ new Thread(this).start();
}
- // Set width and height
- _lastWidth = getWidth();
- _lastHeight = getHeight();
- // if loading, display image
+ // if loading, display message
if (_loadingImage)
{
inG.setColor(Color.BLACK);
- inG.drawString(_loadingString, 10, 30);
+ inG.drawString(LOADING_STRING, 10, 30);
}
else
{
- // Copy scaled, smoothed image onto the screen
- inG.drawImage(_thumbnail, 0, 0, _thumbnail.getWidth(), _thumbnail.getHeight(), null);
+ // Copy scaled, smoothed (and rotated) image into scaled
+ int usableWidth = getParent().getWidth()-10;
+ Image scaled = ImageUtils.rotateImage(_thumbnail, usableWidth, usableWidth, _photo.getRotationDegrees());
+ int scaleWidth = scaled.getWidth(null);
+ int scaleHeight = scaled.getHeight(null);
+ // Draw scaled / rotated image to component
+ int horizOffset = (getWidth() - scaleWidth) / 2;
+ int vertOffset = (getHeight() - scaleHeight) / 2;
+ inG.drawImage(scaled, horizOffset, vertOffset, scaleWidth, scaleHeight, null);
+ if (getHeight() < getWidth())
+ {
+ setPreferredSize(new Dimension(usableWidth, usableWidth));
+ invalidate();
+ }
}
}
}
int picHeight = _photo.getHeight();
if (picWidth > -1 && picHeight > -1)
{
- int displayWidth = Math.min(getWidth(), getParent().getWidth());
- int displayHeight = Math.min(getHeight(), getParent().getHeight());
-
+ // Just set a "reasonable" thumbnail size for now
+ final int DEFAULT_THUMB_SIZE = 400;
// calculate maximum thumbnail size
- Dimension thumbSize = ImageUtils.getThumbnailSize(picWidth, picHeight, displayWidth, displayHeight);
- // Work out if need to remake image
- boolean needToRemake = (_thumbnail == null)
- || _thumbnail.getWidth() != thumbSize.width || _thumbnail.getHeight() != thumbSize.height;
- if (thumbSize.width > 0 && thumbSize.height > 0 && needToRemake)
- {
- // Make icon to load image into
- Image image = new ImageIcon(_photo.getFile().getAbsolutePath()).getImage();
- // save scaled, smoothed thumbnail for reuse
- _thumbnail = ImageUtils.createScaledImage(image, thumbSize.width, thumbSize.height);
- image = null;
- // TODO: Calculate and set size of thumbnail here
- // setPreferredSize(new Dimension(200, 200));
- }
+ Dimension thumbSize = ImageUtils.getThumbnailSize(picWidth, picHeight, DEFAULT_THUMB_SIZE, DEFAULT_THUMB_SIZE);
+ // Make icon to load image into
+ Image image = new ImageIcon(_photo.getFile().getAbsolutePath()).getImage();
+ // save scaled, smoothed thumbnail for reuse
+ _thumbnail = ImageUtils.createScaledImage(image, thumbSize.width, thumbSize.height);
+ image = null;
}
}
_loadingImage = false;
import java.awt.event.MouseEvent;
import tim.prune.I18nManager;
+import tim.prune.config.ColourScheme;
+import tim.prune.config.Config;
import tim.prune.data.Altitude;
import tim.prune.data.AltitudeRange;
import tim.prune.data.Track;
*/
public class ProfileChart extends GenericChart
{
+ /** Current scale factor in x direction*/
private double _xScaleFactor = 0.0;
+ /** Possible altitude scales to use */
private static final int[] ALTITUDE_SCALES = {10000, 5000, 2000, 1000, 500, 200, 100, 50};
- private static final Color COLOR_LINES = Color.GRAY;
- private static final Color COLOR_ALT_BARS = Color.BLUE;
- private static final Color COLOR_CURR_RANGE = Color.GREEN;
- private static final Color COLOR_SELECTED = Color.RED;
- private static final Color COLOR_SELECTED_BG = Color.ORANGE;
- private static final Color COLOR_ALT_SCALE = Color.RED;
/**
int width = getWidth();
int height = getHeight();
+ // Set up colours
+ final Color barColour = Config.getColourScheme().getColour(ColourScheme.IDX_POINT);
+ final Color rangeColour = Config.getColourScheme().getColour(ColourScheme.IDX_SELECTION);
+ final Color currentColour = Config.getColourScheme().getColour(ColourScheme.IDX_PRIMARY);
+ final Color secondColour = Config.getColourScheme().getColour(ColourScheme.IDX_SECONDARY);
+ final Color lineColour = Config.getColourScheme().getColour(ColourScheme.IDX_LINES);
+
// message if no altitudes in track
if (!_track.hasAltitudeData())
{
- g.setColor(COLOR_LINES);
+ g.setColor(lineColour);
g.drawString(I18nManager.getText("display.noaltitudes"), 50, height/2);
return;
}
int minAltitude = altitudeRange.getMinimum();
int maxAltitude = altitudeRange.getMaximum();
int numPoints = _track.getNumPoints();
- _xScaleFactor = 1.0 * (width - 2 * BORDER_WIDTH) / numPoints;
+ _xScaleFactor = 1.0 * (width - 2 * BORDER_WIDTH - 1) / numPoints;
double yScaleFactor = 1.0 * (height - 2 * BORDER_WIDTH) / (maxAltitude - minAltitude);
int barWidth = (int) (_xScaleFactor + 1.0);
int selectedPoint = _trackInfo.getSelection().getCurrentPointIndex();
// horizontal lines for scale - set to round numbers eg 500m
int lineScale = getLineScale(minAltitude, maxAltitude);
int altitude = 0;
- int y = 0;
+ int x = 0, y = 0;
if (lineScale > 1)
{
- g.setColor(COLOR_LINES);
+ g.setColor(lineColour);
while (altitude < maxAltitude)
{
if (altitude > minAltitude)
{
// loop through points
Altitude.Format chartFormat = altitudeRange.getFormat();
+ g.setColor(barColour);
for (int p = 0; p < numPoints; p++)
{
- int x = (int) (_xScaleFactor * p);
- if (p == selectedPoint)
- {
- g.setColor(COLOR_SELECTED_BG);
- g.fillRect(BORDER_WIDTH + x, BORDER_WIDTH+1, barWidth, height-2*BORDER_WIDTH-2);
- g.setColor(COLOR_SELECTED);
- }
- else
- {
- g.setColor(COLOR_ALT_BARS);
- if (p >= selectionStart && p <= selectionEnd) {
- g.setColor(COLOR_CURR_RANGE);
- }
- }
+ x = (int) (_xScaleFactor * p) + 1;
+ if (p == selectionStart)
+ g.setColor(rangeColour);
+ else if (p == (selectionEnd+1))
+ g.setColor(barColour);
if (_track.getPoint(p).getAltitude().isValid())
{
altitude = _track.getPoint(p).getAltitude().getValue(chartFormat);
g.fillRect(BORDER_WIDTH+x, height-BORDER_WIDTH - y, barWidth, y);
}
}
+ // current point (make sure it's drawn last)
+ if (selectedPoint > -1)
+ {
+ Altitude alt = _track.getPoint(selectedPoint).getAltitude();
+ if (alt.isValid())
+ {
+ x = (int) (_xScaleFactor * selectedPoint) + 1;
+ g.setColor(secondColour);
+ g.fillRect(BORDER_WIDTH + x, BORDER_WIDTH+1, barWidth, height-2*BORDER_WIDTH-2);
+ g.setColor(currentColour);
+ altitude = alt.getValue(chartFormat);
+ y = (int) (yScaleFactor * (altitude - minAltitude));
+ g.fillRect(BORDER_WIDTH + x, height-BORDER_WIDTH - y, barWidth, y);
+ }
+ }
}
catch (NullPointerException npe) { // ignore, probably due to data being changed
}
int textHeight = g.getFontMetrics().getHeight();
altitude = 0;
y = 0;
- g.setColor(COLOR_ALT_SCALE);
+ g.setColor(currentColour);
while (altitude < maxAltitude)
{
if (altitude > minAltitude)
{
// work out which data point is nearest and select it
int pointNum = (int) ((e.getX() - BORDER_WIDTH) / _xScaleFactor);
- _trackInfo.selectPoint(pointNum);
+ // If shift clicked, then extend selection
+ if (e.isShiftDown()) {
+ _trackInfo.extendSelection(pointNum);
+ }
+ else {
+ _trackInfo.selectPoint(pointNum);
+ }
}
}
}
*/
public Object getElementAt(int inIndex)
{
+ if (inIndex < 0 || inIndex >= getSize()) return "";
return _waypoints.get(inIndex).getWaypointName();
}
import tim.prune.DataSubscriber;
import tim.prune.FunctionLibrary;
import tim.prune.I18nManager;
+import tim.prune.UpdateMessageBroker;
+import tim.prune.config.ColourScheme;
+import tim.prune.config.Config;
+import tim.prune.data.Coordinate;
+import tim.prune.data.DataPoint;
import tim.prune.data.DoubleRange;
+import tim.prune.data.Latitude;
+import tim.prune.data.Longitude;
import tim.prune.data.Selection;
import tim.prune.data.Track;
import tim.prune.data.TrackInfo;
private static final int AUTOPAN_DISTANCE = 75;
// Colours
- private static final Color COLOR_BG = Color.WHITE;
private static final Color COLOR_MESSAGES = Color.GRAY;
- private static final Color COLOR_POINT = Color.BLUE;
- private static final Color COLOR_POINT_DELETED = Color.RED;
- private static final Color COLOR_CURR_RANGE = Color.GREEN;
- private static final Color COLOR_CROSSHAIRS = Color.RED;
- private static final Color COLOR_WAYPT_NAME = Color.BLACK;
- private static final Color COLOR_PHOTO_PT = Color.ORANGE;
/**
{
_tileCacher.clearAll();
_recalculate = true;
- repaint();
+ Config.setConfigBoolean(Config.KEY_SHOW_MAP, e.getStateChange() == ItemEvent.SELECTED);
+ UpdateMessageBroker.informSubscribers(); // to let menu know
}
};
_topPanel = new JPanel();
newPointItem.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e)
{
- _app.createPoint(MapUtils.getLatitudeFromY(_mapPosition.getYFromPixels(_popupMenuY, getHeight())),
- MapUtils.getLongitudeFromX(_mapPosition.getXFromPixels(_popupMenuX, getWidth())));
+ double lat = MapUtils.getLatitudeFromY(_mapPosition.getYFromPixels(_popupMenuY, getHeight()));
+ double lon = MapUtils.getLongitudeFromX(_mapPosition.getXFromPixels(_popupMenuX, getWidth()));
+ _app.createPoint(new DataPoint(new Latitude(lat, Coordinate.FORMAT_NONE),
+ new Longitude(lon, Coordinate.FORMAT_NONE), null));
}});
newPointItem.setEnabled(true);
_popup.add(newPointItem);
}
else
{
- inG.setColor(COLOR_BG);
+ inG.setColor(Config.getColourScheme().getColour(ColourScheme.IDX_BACKGROUND));
inG.fillRect(0, 0, getWidth(), getHeight());
inG.setColor(COLOR_MESSAGES);
inG.drawString(I18nManager.getText("display.nodata"), 50, getHeight()/2);
// Clear map
Graphics g = _mapImage.getGraphics();
- // Clear to white
- g.setColor(COLOR_BG);
+ // Clear to background
+ g.setColor(Config.getColourScheme().getColour(ColourScheme.IDX_BACKGROUND));
g.fillRect(0, 0, getWidth(), getHeight());
+ // Check whether maps are on or not
+ boolean showMap = Config.getConfigBoolean(Config.KEY_SHOW_MAP);
+ _mapCheckBox.setSelected(showMap);
+
// reset error message
- if (!_mapCheckBox.isSelected()) {_shownOsmErrorAlready = false;}
+ if (!showMap) {_shownOsmErrorAlready = false;}
// Only get map tiles if selected
- if (_mapCheckBox.isSelected())
+ if (showMap)
{
// init tile cacher
_tileCacher.centreMap(_mapPosition.getZoom(), _mapPosition.getCentreTileX(), _mapPosition.getCentreTileY());
}
_checkBounds = false;
// enable / disable transparency slider
- _transparencySlider.setEnabled(_mapCheckBox.isSelected());
+ _transparencySlider.setEnabled(showMap);
}
*/
private int paintPoints(Graphics inG)
{
+ // Set up colours
+ final Color pointColour = Config.getColourScheme().getColour(ColourScheme.IDX_POINT);
+ final Color rangeColour = Config.getColourScheme().getColour(ColourScheme.IDX_SELECTION);
+ final Color currentColour = Config.getColourScheme().getColour(ColourScheme.IDX_PRIMARY);
+ final Color secondColour = Config.getColourScheme().getColour(ColourScheme.IDX_SECONDARY);
+ final Color textColour = Config.getColourScheme().getColour(ColourScheme.IDX_TEXT);
+
int pointsPainted = 0;
// draw track points
- inG.setColor(COLOR_POINT);
+ inG.setColor(pointColour);
int prevX = -1, prevY = -1;
boolean connectPoints = _connectCheckBox.isSelected();
boolean prevPointVisible = false, currPointVisible = false;
+ boolean anyWaypoints = false;
+ boolean isWaypoint = false;
for (int i=0; i<_track.getNumPoints(); 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();
+ isWaypoint = _track.getPoint(i).isWaypoint();
+ anyWaypoints = anyWaypoints || isWaypoint;
if (currPointVisible)
{
- if (!_track.getPoint(i).isWaypoint())
+ if (!isWaypoint)
{
// Draw rectangle for track point
if (_track.getPoint(i).getDeleteFlag()) {
- inG.setColor(COLOR_POINT_DELETED);
+ inG.setColor(currentColour);
}
else {
- inG.setColor(COLOR_POINT);
+ inG.setColor(pointColour);
}
inG.drawRect(px-2, py-2, 3, 3);
pointsPainted++;
}
}
- if (!_track.getPoint(i).isWaypoint())
+ if (!isWaypoint)
{
// Connect track points if either of them are visible
if (connectPoints && (currPointVisible || prevPointVisible)
}
// Loop over points, just drawing blobs for waypoints
- inG.setColor(COLOR_WAYPT_NAME);
+ inG.setColor(textColour);
FontMetrics fm = inG.getFontMetrics();
int nameHeight = fm.getHeight();
int width = getWidth();
int height = getHeight();
- for (int i=0; i<_track.getNumPoints(); i++)
- {
- if (_track.getPoint(i).isWaypoint())
+ if (anyWaypoints) {
+ for (int i=0; i<_track.getNumPoints(); i++)
{
- 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())
+ if (_track.getPoint(i).isWaypoint())
{
- inG.fillRect(px-3, py-3, 6, 6);
- pointsPainted++;
+ 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())
+ {
+ inG.fillRect(px-3, py-3, 6, 6);
+ pointsPainted++;
+ }
}
}
- }
- // Loop over points again, now draw names for waypoints
- for (int i=0; i<_track.getNumPoints(); i++)
- {
- if (_track.getPoint(i).isWaypoint())
+ // Loop over points again, now draw names for waypoints
+ for (int i=0; i<_track.getNumPoints(); i++)
{
- 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())
+ if (_track.getPoint(i).isWaypoint())
{
- // Figure out where to draw waypoint name so it doesn't obscure track
- String waypointName = _track.getPoint(i).getWaypointName();
- int nameWidth = fm.stringWidth(waypointName);
- boolean drawnName = false;
- // Make arrays for coordinates right left up down
- int[] nameXs = {px + 2, px - nameWidth - 2, px - nameWidth/2, px - nameWidth/2};
- int[] nameYs = {py + (nameHeight/2), py + (nameHeight/2), py - 2, py + nameHeight + 2};
- for (int extraSpace = 4; extraSpace < 13 && !drawnName; extraSpace+=2)
+ 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())
{
- // Shift arrays for coordinates right left up down
- nameXs[0] += 2; nameXs[1] -= 2;
- nameYs[2] -= 2; nameYs[3] += 2;
- // Check each direction in turn right left up down
- for (int a=0; a<4; a++)
+ // Figure out where to draw waypoint name so it doesn't obscure track
+ String waypointName = _track.getPoint(i).getWaypointName();
+ int nameWidth = fm.stringWidth(waypointName);
+ boolean drawnName = false;
+ // Make arrays for coordinates right left up down
+ int[] nameXs = {px + 2, px - nameWidth - 2, px - nameWidth/2, px - nameWidth/2};
+ int[] nameYs = {py + (nameHeight/2), py + (nameHeight/2), py - 2, py + nameHeight + 2};
+ for (int extraSpace = 4; extraSpace < 13 && !drawnName; extraSpace+=2)
{
- if (nameXs[a] > 0 && (nameXs[a] + nameWidth) < width
- && nameYs[a] < height && (nameYs[a] - nameHeight) > 0
- && !overlapsPoints(nameXs[a], nameYs[a], nameWidth, nameHeight))
+ // Shift arrays for coordinates right left up down
+ nameXs[0] += 2; nameXs[1] -= 2;
+ nameYs[2] -= 2; nameYs[3] += 2;
+ // Check each direction in turn right left up down
+ for (int a=0; a<4; a++)
{
- // Found a rectangle to fit - draw name here and quit
- inG.drawString(waypointName, nameXs[a], nameYs[a]);
- drawnName = true;
- break;
+ if (nameXs[a] > 0 && (nameXs[a] + nameWidth) < width
+ && nameYs[a] < height && (nameYs[a] - nameHeight) > 0
+ && !overlapsPoints(nameXs[a], nameYs[a], nameWidth, nameHeight, textColour))
+ {
+ // Found a rectangle to fit - draw name here and quit
+ inG.drawString(waypointName, nameXs[a], nameYs[a]);
+ drawnName = true;
+ break;
+ }
}
}
}
}
}
// Loop over points, drawing blobs for photo points
- inG.setColor(COLOR_PHOTO_PT);
+ inG.setColor(secondColour);
for (int i=0; i<_track.getNumPoints(); i++)
{
if (_track.getPoint(i).getPhoto() != null)
// Draw selected range
if (_selection.hasRangeSelected())
{
- inG.setColor(COLOR_CURR_RANGE);
+ inG.setColor(rangeColour);
for (int i=_selection.getStart(); i<=_selection.getEnd(); i++)
{
int px = getWidth() / 2 + _mapPosition.getXFromCentre(_track.getX(i));
{
int px = getWidth() / 2 + _mapPosition.getXFromCentre(_track.getX(selectedPoint));
int py = getHeight() / 2 + _mapPosition.getYFromCentre(_track.getY(selectedPoint));
- inG.setColor(COLOR_CROSSHAIRS);
+ inG.setColor(currentColour);
// crosshairs
inG.drawLine(px, 0, px, getHeight());
inG.drawLine(0, py, getWidth(), py);
* @param inY bottom Y coordinate
* @param inWidth width of rectangle
* @param inHeight height of rectangle
- * @return true if there's at least one data point in the rectangle
+ * @param inTextColour colour of text
+ * @return true if the rectangle overlaps stuff too close to the given colour
*/
- private boolean overlapsPoints(int inX, int inY, int inWidth, int inHeight)
+ private boolean overlapsPoints(int inX, int inY, int inWidth, int inHeight, Color inTextColour)
{
- // each of the colour channels must be brighter than this to count as empty
- final int BRIGHTNESS_LIMIT = 210;
+ // each of the colour channels must be further away than this to count as empty
+ final int BRIGHTNESS_LIMIT = 80;
+ final int textRGB = inTextColour.getRGB();
+ final int textLow = textRGB & 255;
+ final int textMid = (textRGB >> 8) & 255;
+ final int textHigh = (textRGB >> 16) & 255;
try
{
// loop over x coordinate of rectangle
{
int pixelColor = _mapImage.getRGB(inX + x, inY - y);
// split into four components rgba
- int lowestBit = pixelColor & 255;
- int secondBit = (pixelColor >> 8) & 255;
- int thirdBit = (pixelColor >> 16) & 255;
+ int pixLow = pixelColor & 255;
+ int pixMid = (pixelColor >> 8) & 255;
+ int pixHigh = (pixelColor >> 16) & 255;
//int fourthBit = (pixelColor >> 24) & 255; // alpha ignored
- if (lowestBit < BRIGHTNESS_LIMIT || secondBit < BRIGHTNESS_LIMIT || thirdBit < BRIGHTNESS_LIMIT) return true;
+ // If colours are too close in any channel then it's an overlap
+ if (Math.abs(pixLow-textLow) < BRIGHTNESS_LIMIT ||
+ Math.abs(pixMid-textMid) < BRIGHTNESS_LIMIT ||
+ Math.abs(pixHigh-textHigh) < BRIGHTNESS_LIMIT) {return true;}
}
}
}
_mapPosition.getXFromPixels(inE.getX(), getWidth()),
_mapPosition.getYFromPixels(inE.getY(), getHeight()),
_mapPosition.getBoundsFromPixels(CLICK_SENSITIVITY), false);
- _trackInfo.selectPoint(pointIndex);
+ // Extend selection for shift-click
+ if (inE.isShiftDown()) {
+ _trackInfo.extendSelection(pointIndex);
+ }
+ else {
+ _trackInfo.selectPoint(pointIndex);
+ }
}
else
{
import java.net.MalformedURLException;
import java.net.URL;
-import tim.prune.Config;
+import tim.prune.config.Config;
/**
* Class to hold the config for the map tiles
import java.awt.Graphics;
import javax.swing.JPanel;
-import tim.prune.Config;
import tim.prune.I18nManager;
+import tim.prune.config.ColourScheme;
+import tim.prune.config.Config;
/**
* Class to show a scale bar on the main map of Prune
if (scale < 1) {return;}
}
+ // Determine colours to use
+ Color barColour = Config.getColourScheme().getColour(ColourScheme.IDX_TEXT);
+ Color blankColour = new Color(255-barColour.getRed(), 255-barColour.getGreen(), 255-barColour.getBlue());
+ // Should this blank colour be set to saturation zero?
+ // Draw blank bars behind
+ inG.setColor(blankColour);
+ inG.drawLine(LEFT_OFFSET, Y_OFFSET-1, rightSide+2, Y_OFFSET-1);
+ inG.drawLine(LEFT_OFFSET, Y_OFFSET+2, rightSide+2, Y_OFFSET+2);
+ inG.drawLine(LEFT_OFFSET-1, Y_OFFSET+2, LEFT_OFFSET-1, Y_OFFSET-TICK_HEIGHT);
+ inG.drawLine(LEFT_OFFSET+2, Y_OFFSET+2, LEFT_OFFSET+2, Y_OFFSET-TICK_HEIGHT);
+ inG.drawLine(rightSide-1, Y_OFFSET+2, rightSide-1, Y_OFFSET-TICK_HEIGHT);
+ inG.drawLine(rightSide+2, Y_OFFSET+2, rightSide+2, Y_OFFSET-TICK_HEIGHT);
// horizontal
- inG.setColor(Color.BLACK);
+ inG.setColor(barColour);
inG.drawLine(LEFT_OFFSET, Y_OFFSET, rightSide, Y_OFFSET);
inG.drawLine(LEFT_OFFSET, Y_OFFSET+1, rightSide, Y_OFFSET+1);
// 0 tick
inG.drawLine(LEFT_OFFSET, Y_OFFSET, LEFT_OFFSET, Y_OFFSET-TICK_HEIGHT);
inG.drawLine(LEFT_OFFSET+1, Y_OFFSET, LEFT_OFFSET+1, Y_OFFSET-TICK_HEIGHT);
// end tick
- inG.drawLine(rightSide, Y_OFFSET, rightSide, Y_OFFSET-TICK_HEIGHT);
- inG.drawLine(rightSide+1, Y_OFFSET, rightSide+1, Y_OFFSET-TICK_HEIGHT);
+ 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 = (scale>0?(""+scale):("1/"+(-scale))) + " " + I18nManager.getText(useMetric?"units.kilometres.short":"units.miles.short");
+ String text = (scale>0?(""+scale):("1/"+(-scale))) + " "
+ + I18nManager.getText(useMetric?"units.kilometres.short":"units.miles.short");
+ inG.setColor(blankColour);
+ inG.drawString(text, rightSide+MARGIN_WIDTH-1, Y_OFFSET);
+ inG.drawString(text, rightSide+MARGIN_WIDTH+1, Y_OFFSET);
+ inG.drawString(text, rightSide+MARGIN_WIDTH, Y_OFFSET-1);
+ inG.drawString(text, rightSide+MARGIN_WIDTH, Y_OFFSET+1);
+ inG.setColor(barColour);
inG.drawString(text, rightSide+MARGIN_WIDTH, Y_OFFSET);
}
catch (ArrayIndexOutOfBoundsException ai) {}
menu.view.browser.openstreetmap=Openstreetmap
menu.view.browser.mapquest=Mapquest
menu.view.browser.yahoo=Yahoo Kaarte
+menu.view.browser.bing=Bing Kaarte
menu.help=Hulp
# Popup menu for map
menu.map.zoomin=Zoom in
menu.file.addphotos=Fotos laden
menu.file.save=Speichern
menu.file.exit=Beenden
-menu.edit=Bearbeiten
+menu.track=Track
menu.edit.undo=Rückgängig
menu.edit.clearundo=Liste der letzten Änderungen löschen
menu.edit.editpoint=Punkt bearbeiten
menu.edit.rearrange.end=Alle Wegpunkte ans Ende
menu.edit.rearrange.nearest=Jeden Wegpunkt zum nächsten Trackpunkt verschieben
menu.edit.cutandmove=Schneiden und verschieben
-menu.select=Markieren
+menu.range=Bereich
+menu.point=Punkt
menu.select.all=Alles markieren
menu.select.none=Nichts markieren
menu.select.start=Startpunkt setzen
menu.select.end=Endpunkt setzen
menu.photo=Foto
menu.photo.saveexif=Exif Daten speichern
-menu.photo.connect=Mit Punkt verbinden
+menu.photo.connect=Mit Punkt verknüpfen
menu.photo.disconnect=Vom Punkt trennen
menu.photo.delete=Foto entfernen
menu.view=Ansicht
menu.view.browser=Karte in Browser
-menu.view.browser.google=Google Maps
-menu.view.browser.openstreetmap=Openstreetmap
-menu.view.browser.mapquest=
-menu.view.browser.yahoo=
menu.settings=Einstellungen
-menu.settings.showpace=Tempo anzeigen
menu.help=Hilfe
# Popup menu for map
menu.map.zoomin=Hineinzoomen
# Alt keys for menus
altkey.menu.file=D
-altkey.menu.edit=B
-altkey.menu.select=M
+altkey.menu.track=T
+altkey.menu.range=B
+altkey.menu.point=P
altkey.menu.view=A
altkey.menu.photo=F
altkey.menu.settings=E
function.addtimeoffset=Zeitverschiebung aufrechnen
function.addaltitudeoffset=Höhenverschiebung aufrechnen
function.findwaypoint=Wegpunkt finden
+function.convertnamestotimes=Wegpunktenamen in Zeitstempeln verwandeln
+function.pastecoordinates=Neue Koordinaten eingeben
function.charts=Diagramme
function.show3d=3D Ansicht
-function.distances=Distanzen
+function.distances=Entfernungen
+function.fullrangedetails=Zusätzliche Bereichdetails
function.setmapbg=Karte Hintergrund setzen
function.setkmzimagesize=Bildgröße im KMZ setzen
-function.setpaths=Programmenpfade setzen
+function.setpaths=Programmpfade setzen
+function.setcolours=Farben einstellen
+function.setlanguage=Sprache einstellen
function.getgpsies=Gpsies Tracks holen
+function.duplicatepoint=Punkt verdoppeln
function.correlatephotos=Fotos korrelieren
+function.rearrangephotos=Fotos reorganisieren
+function.rotatephotoleft=Foto nach Links drehen
+function.rotatephotoright=Foto nach Rechts drehen
+function.ignoreexifthumb=Exif Vorschaubild ignorieren
function.help=Hilfe
function.showkeys=Tastenkombinationen anzeigen
function.about=Ãœber Prune
dialog.openoptions.title=Öffnen
dialog.openoptions.filesnippet=Dateiausschnitt
dialog.load.table.field=Feld
-dialog.load.table.datatype=Daten Typ
+dialog.load.table.datatype=Datentyp
dialog.load.table.description=Beschreibung
dialog.delimiter.label=Feld Trennzeichen
dialog.delimiter.comma=Komma ,
dialog.delimiter.tab=Tab
-dialog.delimiter.space=Leerstelle
+dialog.delimiter.space=Leerzeichen
dialog.delimiter.semicolon=Strichpunkt ;
dialog.delimiter.other=Andere
dialog.openoptions.deliminfo.records=Aufnahmen, mit
dialog.openoptions.deliminfo.fields=Feldern
dialog.openoptions.deliminfo.norecords=Keine Rekords
dialog.openoptions.altitudeunits=Höhe Maßeinheiten
-dialog.jpegload.subdirectories=Unterordner auch durchsuchen
+dialog.jpegload.subdirectories=Unterordner mit durchsuchen
dialog.jpegload.loadjpegswithoutcoords=Auch Fotos ohne Koordinaten laden
dialog.jpegload.loadjpegsoutsidearea=Auch Fotos ausserhalb vom Track laden
dialog.jpegload.progress.title=Fotos werden geladen
dialog.gpsload.format=Format
dialog.gpsload.getwaypoints=Wegpunkte laden
dialog.gpsload.gettracks=Tracks laden
+dialog.gpsload.save=nach Datei speichern
dialog.gpssend.sendwaypoints=Wegpunkte senden
dialog.gpssend.sendtracks=Tracks senden
dialog.gpssend.trackname=Track Name
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 überschreiben?
+dialog.save.notypesselected=Keine Punktetypen sind ausgewählt
dialog.exportkml.text=Titel für die Daten
dialog.exportkml.altitude=Absolute Höheninformation (für Luftfahrt)
dialog.exportkml.kmz=Daten in kmz Datei komprimieren
dialog.exportkml.exportimages=Vorschaubilder mit in kmz 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.exportpov.text=Geben Sie die Parameter für den POV Export ein
dialog.exportpov.font=Font
dialog.exportpov.camerax=Kamera X
dialog.pointtype.track=Trackpunkte
dialog.pointtype.waypoint=Wegpunkte
dialog.pointtype.photo=Fotopunkte
+dialog.pointtype.selection=Nur aktuellen Bereich
dialog.confirmreversetrack.title=Umkehrung bestätigen
dialog.confirmreversetrack.text=Diese Daten enthalten Zeitangaben, die bei einer Umkehrung in falscher Reihenfolge erscheinen würden.\nSind Sie sicher, dass Sie diesen Bereich umkehren wollen?
dialog.confirmcutandmove.title=Verschieben bestätigen
dialog.undo.none.title=Undo nicht möglich
dialog.undo.none.text=Keine Operationen können rückgängig gemacht werden.
dialog.clearundo.title=Undo-Liste löschen
-dialog.clearundo.text=Sind Sie sicher, Sie wollen die Undo-Liste löschen?\nAlle Undo Information wird veloren gehen!
+dialog.clearundo.text=Wollen Sie wirklich die Undo-Liste löschen?\nAlle Undo- Informationen werden verloren gehen!
dialog.pointedit.title=Punkt bearbeiten
dialog.pointedit.text=Wählen Sie die Felder aus, die Sie bearbeiten möchten, und verwenden Sie den 'Bearbeiten' Knopf, um den Wert zu ändern
dialog.pointedit.table.field=Feld
dialog.addtimeoffset.days=Tage
dialog.addtimeoffset.hours=Stunde
dialog.addtimeoffset.minutes=Minute
-dialog.addtimeoffset.notimestamps=Zeitdifferenz kann nicht addiert werden weil dieser Bereich keine Zeitinformation hat
-dialog.findwaypoint.intro=Geben Sie einen Teil von dem Namen ein
+dialog.addtimeoffset.notimestamps=Zeitdifferenz kann nicht addiert werden, weil dieser Bereich keine Zeitinformation hat
+dialog.findwaypoint.intro=Geben Sie einen Teil des Namens ein
dialog.findwaypoint.search=Suche
-dialog.connect.title=Foto mit Punkt verbinden
-dialog.connectphoto.clonepoint=Diesem Punkt ist schon ein Foto zugeordnet.\nWollen Sie eine Kopie dieses Punktes machen?
dialog.saveexif.title=Exif speichern
dialog.saveexif.intro=Wählen Sie die Fotos zum Speichern aus
dialog.saveexif.nothingtosave=Koordinaten sind unverändert. Es gibt nichts zu speichern.
dialog.saveexif.photostatus.disconnected=Getrennt
dialog.saveexif.photostatus.modified=Modifiziert
dialog.saveexif.overwrite=Dateien überschreiben
+dialog.saveexif.force=Forzieren trotz Warnungen
dialog.charts.xaxis=X Achse
dialog.charts.yaxis=Y Achse
dialog.charts.output=Ausgabe
-dialog.charts.screen=zum Bildschirm
-dialog.charts.svg=zur SVG Datei
+dialog.charts.screen=Ausgabe zum Bildschirm
+dialog.charts.svg=Ausgabe in SVG Datei
dialog.charts.svgwidth=SVG Breite
dialog.charts.svgheight=SVG Höhe
dialog.charts.needaltitudeortimes=Ohne Daten über Höhe und Zeit kann kein Diagramm erzeugt werden.
-dialog.charts.gnuplotpath=Gnuplot Pfad
dialog.charts.gnuplotnotfound=Gnuplot konnte im angegebenen Pfad nicht gefunden werden
-dialog.distances.intro=Luftlinienentfernung zwischen Punkte
+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.setmapbg.mapnik=
-dialog.setmapbg.osma=
+dialog.fullrangedetails.intro=Hier sind die Details vom markierten Bereich
dialog.setmapbg.cyclemap=Fahrradkarte
dialog.setmapbg.other=Andere
dialog.setmapbg.server=Server URL
dialog.correlate.options.distancelimit=Distanzgrenzen
dialog.correlate.options.correlate=Korrelieren
dialog.correlate.alloutsiderange=Alle Fotos sind außerhalb vom Track Zeitraum. Sie können nicht korreliert werden.\nVersuchen Sie es mit einem anderen Offset oder binden Sie manuell mindestens ein Foto ein.
+dialog.rearrangephotos.desc=Setzen Sie das Ziel und die Reihenfolge der Fotopunkte
+dialog.rearrangephotos.tostart=Am Anfang
+dialog.rearrangephotos.toend=Am Ende
+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.duplicates.title=Duplikate entfernen
dialog.compress.closepoints.title=Nahegelegene Punkte entfernen
dialog.compress.singletons.title=Singletons (isolierte Punkte) entfernen
dialog.compress.singletons.paramdesc=Distanzfaktor
dialog.compress.summarylabel=Punkte zu entfernen
-dialog.help.help=Bitte sehen Sie\n http://activityworkshop.net/software/prune/\nfür weitere Information und Benutzeranleitungen.
+dialog.pastecoordinates.desc=Geben Sie die Koordinaten ein
+dialog.pastecoordinates.coords=Koordinaten
+dialog.pastecoordinates.nothingfound=Bitte prüfen Sie die Koordinaten und versuchen nochmals
+dialog.help.help=Weitere Informationen und Benutzeranleitungen finden Sie unter\n http://activityworkshop.net/software/prune/
dialog.about.version=Version
dialog.about.build=Build
dialog.about.summarytext1=Prune ist ein Programm zum Laden, Darstellen und Editieren von Daten von GPS Geräten.
dialog.saveconfig.prune.trackdirectory=Datenverzeichnis
dialog.saveconfig.prune.photodirectory=Fotoverzeichnis
dialog.saveconfig.prune.languagecode=Sprachecode (DE)
+dialog.saveconfig.prune.languagefile=Sprachedatei
dialog.saveconfig.prune.gpsdevice=GPS Gerätename
dialog.saveconfig.prune.gpsformat=GPS Format
dialog.saveconfig.prune.povrayfont=Povray Font
dialog.saveconfig.prune.exiftoolpath=Exiftool Pfad
dialog.saveconfig.prune.mapserverindex=Kartenserver Index
dialog.saveconfig.prune.mapserverurl=Kartenserver URL
-dialog.saveconfig.prune.showpace=Tempo anzeigen
dialog.saveconfig.prune.kmzimagewidth=Bildbreite in KMZ
dialog.saveconfig.prune.kmzimageheight=Bildhöhe in KMZ
+dialog.saveconfig.prune.colourscheme=Farbenschema
+dialog.saveconfig.prune.kmltrackcolour=KML Trackfarbe
dialog.setpaths.intro=Sie können hier die Pfade für externe Applikationen setzen:
dialog.addaltitude.noaltitudes=Der markierten Bereich enthält keine Höhenangaben
dialog.addaltitude.desc=Höhenverschiebung aufzurechnen
+dialog.setcolours.intro=Klicken Sie auf einer Farbe um sie zu ändern
+dialog.setcolours.background=Hintergrund
+dialog.setcolours.borders=Umrandungen
+dialog.setcolours.lines=Linien
+dialog.setcolours.primary=Primär
+dialog.setcolours.secondary=Secondär
+dialog.setcolours.point=Punkte
+dialog.setcolours.selection=Bereich
+dialog.setcolours.text=Texte
+dialog.colourchooser.title=Farbe auswählen
+dialog.colourchooser.red=Rot
+dialog.colourchooser.green=Grün
+dialog.colourchooser.blue=Blau
+dialog.setlanguage.firstintro=Sie können entweder eine von den eingebauten Sprachen<p>oder eine Text-Datei auswählen.
+dialog.setlanguage.secondintro=Sie müssen Ihre Einstellungen speichern und dann<p>Prune wieder neustarten um die Sprache zu ändern.
+dialog.setlanguage.language=Sprache
+dialog.setlanguage.languagefile=Sprache Datei
+dialog.setlanguage.endmessage=Nun speichern Sie Ihre Einstellungen und starten Sie Prune neu\num die neue Sprache zu verwenden.
# 3d window
dialog.3d.title=Prune 3D Ansicht
confirm.addtimeoffset=Zeitverschiebung aufgerechnet
confirm.addaltitudeoffset=Höhenverschiebung aufgerechnet
confirm.rearrangewaypoints=Wegpunkte reorganisiert
+confirm.rearrangephotos=Fotos reorganisiert
confirm.cutandmove=Bereich verschoben
+confirm.convertnamestotimes=Wegpunktnamen verwandelt
confirm.saveexif.ok1=Es wurden
confirm.saveexif.ok2=Fotodateien geschrieben
confirm.undo.single=Operation rückgängig gemacht
confirm.correlate.single=Foto wurde korreliert
confirm.correlate.multi=Fotos wurden korreliert
confirm.createpoint=Punkt kreiert
+confirm.rotatephoto=Foto umgedreht
confirm.running=In Bearbeitung ...
# Buttons
button.no=Nein
button.yestoall=Ja für alle
button.notoall=Nein für alle
-button.selectall=Alle selektieren
-button.selectnone=Nichts selektieren
+button.select=Auswählen
+button.selectall=Alle auswählen
+button.selectnone=Nichts auswählen
button.preview=Vorschau
button.load=Laden
button.guessfields=Felder erraten
button.showwebpage=Webseite anzeigen
button.check=Prüfen
+button.resettodefaults=Zurücksetzen
+button.browse=Durchsuchen...
# File types
filetype.txt=TXT Dateien
display.range.time.days=T
details.range.avespeed=Geschwindigkeit
details.range.avemovingspeed=Geschwindigkeit unterwegs
+details.range.numsegments=Anzahl Abschnitte
details.range.pace=Tempo
+details.range.gradient=Gefälle
details.waypointsphotos.waypoints=Wegpunkte
details.waypointsphotos.photos=Fotos
details.photodetails=Fotodetails
units.original=Original
units.default=Standard
units.metres=Meter
-units.metres.short=
-units.feet=
-units.feet.short=
units.kilometres=Kilometer
units.kilometres.short=km
units.kmh=km/h
-units.miles=
-units.miles.short=
-units.mph=
units.metrespersec=m/s
units.feetpersec=ft/s
units.hours=Std
undo.connectphoto=Foto verbinden
undo.disconnectphoto=Foto trennen
undo.correlate=Fotos korrelieren
-undo.createpoint=Punkt kreieren
+undo.rearrangephotos=Fotos reorganisieren
+undo.rotatephoto=Foto umdrehen
+undo.createpoint=Punkt erzeugen
+undo.convertnamestotimes=Namen in Zeitstempeln verwandeln
# Error messages
error.save.dialogtitle=Fehler beim Speichern
error.save.nodata=Keine Daten zum Sichern vorhanden
-error.save.failed=Speichern von der Datei fehlgeschlagen
+error.save.failed=Speichern von Daten in Datei fehlgeschlagen
error.saveexif.filenotfound=Foto Datei nicht gefunden
error.saveexif.cannotoverwrite1=Foto Datei
error.saveexif.cannotoverwrite2=ist schreib-geschützt. Als Kopie speichern?
+error.saveexif.failed1=
+error.saveexif.failed2=von den Bildern konnten nicht gespeichert werden
+error.saveexif.forced1=
+error.saveexif.forced2=von den Bildern mussten forziert werden
error.load.dialogtitle=Fehler beim Laden
error.load.noread=Datei konnte nicht gelesen werden
error.load.nopoints=Keine gültigen Daten in Datei gefunden
error.jpegload.nojpegsfound=Keine Jpeg Dateien gefunden
error.jpegload.noexiffound=Keine EXIF Information gefunden
error.jpegload.nogpsfound=Keine GPS Information gefunden
+error.gpsload.unknown=Unbekanntes Fehler
error.undofailed.title=Undo fehlgeschlagen
error.undofailed.text=Operation konnte nicht rückgängig gemacht werden
error.function.noop.title=Funktion hat nichts bewirkt
-error.rearrange.noop=Die Wegpunkte zu reorganisieren hatte keinen Effekt
+error.rearrange.noop=Die Punkte zu reorganisieren hatte keinen Effekt
error.function.notavailable.title=Funktion nicht verfügbar
error.function.nojava3d=Diese Funktion benötigt die Java3d Library,\nvon Sun.com erhältlich.
error.3d=Ein Fehler ist bei der 3D Darstellung aufgetreten
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üfen Sie die Internetverbindung.
+error.language.wrongfile=Die ausgewählte Datei scheint keine Sprache-Datei für Prune zu sein
+error.convertnamestotimes.nonames=Keine Namen konnten verwandelt werden
menu.file.addphotos=Fötelis innätue
menu.file.save=Speichere
menu.file.exit=Beände
-menu.edit=Editiere
+menu.track=Track
menu.edit.undo=Undo
menu.edit.clearundo=Undo-Liste lösche
menu.edit.editpoint=Punkt editiere
menu.edit.rearrange.end=Alli zum Ände
menu.edit.rearrange.nearest=Jede zum nöchsti Trackpunkt
menu.edit.cutandmove=Schniide und move
-menu.select=Selektiere
+menu.range=Beriich
+menu.point=Punkt
menu.select.all=Alles selektiere
menu.select.none=Nüüt selektiere
menu.select.start=Start setzä
menu.photo.delete=Föteli entfernä
menu.view=Aasicht
menu.view.browser=Karte inem Browser
-menu.view.browser.google=
-menu.view.browser.openstreetmap=
-menu.view.browser.mapquest=
-menu.view.browser.yahoo=
menu.settings=Iistellige
-menu.settings.showpace=Tempo aazeige
menu.help=Hilfe
# Popup menu for map
menu.map.zoomin=Innezoome
menu.map.newpoint=Noii Punkt
menu.map.connect=Trackpünktli verbindä
menu.map.autopan=Autopan
-menu.map.showmap=Kate zeigä
+menu.map.showmap=Karte zeigä
menu.map.showscalebar=Massstab aazeige
# Alt keys for menus
altkey.menu.file=F
-altkey.menu.edit=E
-altkey.menu.select=S
+altkey.menu.track=T
+altkey.menu.range=B
+altkey.menu.point=P
altkey.menu.view=A
altkey.menu.photo=F
altkey.menu.settings=I
function.compress=Track komprimierä
function.addtimeoffset=Ziitverschiebig zutue
function.addaltitudeoffset=Höchiverschiebig zutue
-function.findwaypoint=Waypoint findä
+function.findwaypoint=Waypoint suechä
+function.convertnamestotimes=Waypointname ins Ziitstämple verwondle
+function.pastecoordinates=Noii Koordinaten iigebe
function.charts=Diagramme
function.show3d=Drüü-D Aasicht
function.distances=Distanze
+function.fullrangedetails=Zuesätzlichi Beriichinfos
function.setmapbg=Karte Hintegrund setzä
function.getgpsies=Gpsies Tracks holä
+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.ignoreexifthumb=Exif Vorschaubildli ignorierä
function.setkmzimagesize=Bildligrösse inem KMZ setze
function.setpaths=Programmepfade setze
+function.setcolours=Farben setze
+function.setlanguage=Sproch setze
function.help=Hilfe
function.showkeys=Tastekombinatione aazeige
function.about=Ãœber Prune
dialog.gpsload.format=Format
dialog.gpsload.getwaypoints=Waypoints lade
dialog.gpsload.gettracks=Tracks lade
+dialog.gpsload.save=nach nem File speicherä
dialog.gpssend.sendwaypoints=Waypoints schicke
dialog.gpssend.sendtracks=Tracks schicke
dialog.gpssend.trackname=Track Name
dialog.save.timestampformat=Ziitstämpelformat
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.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.exportpov.text=Gäbet Sie die Parameter ii fürs POV Export
dialog.exportpov.font=Font
dialog.exportpov.camerax=Kamera X
dialog.pointtype.track=Trackpunkte
dialog.pointtype.waypoint=Waypoints
dialog.pointtype.photo=Fötelipunkte
+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.addtimeoffset.notimestamps=Ziitverschiebig nöd möglech wil dr Beriich kei Ziitinfo hät
dialog.findwaypoint.intro=Gebet Sie en Teil vonem Namen ina
dialog.findwaypoint.search=Sueche
-dialog.connect.title=Föteli verknüpfe
-dialog.connectphoto.clonepoint=Derer Punkt hät scho s Föteli.\nWend sie ne Kopie vonem Punkt machä?
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.photostatus.disconnected=Gtrännt
dialog.saveexif.photostatus.modified=Gänderet
dialog.saveexif.overwrite=Files überschriebä
+dialog.saveexif.force=Forzierä trotz Warnige
dialog.charts.xaxis=X Achse
dialog.charts.yaxis=Y Achse
dialog.charts.output=Uusgabe
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.gnuplotpath=Gnuplot Pfad
dialog.charts.gnuplotnotfound=Gnuplot isch mit dem Pfad nöd gfunde worde
dialog.distances.intro=Dischtanze per Luftlinie zwüschet Punkte
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.setmapbg.mapnik=
-dialog.setmapbg.osma=
+dialog.fullrangedetails.intro=Hier sind die Infos vonem aktuelli Beriich
dialog.setmapbg.cyclemap=Velokarte
dialog.setmapbg.other=Anderi
dialog.setmapbg.server=Server URL
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.rearrangephotos.desc=Bitte Ziel und Reihefolge von den Punkten setze
+dialog.rearrangephotos.tostart=zum Aafang
+dialog.rearrangephotos.toend=zum Ende
+dialog.rearrangephotos.nosort=Nöd 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.singletons.title=Singletons entfärnä
dialog.compress.singletons.paramdesc=Distanz faktor
dialog.compress.summarylabel=Punkte zu entfärnä
+dialog.pastecoordinates.desc=Gäbet Sie hier die Koordinaten innä
+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/prune/\nfür wiitere Information und Benutzeraaleitige.
dialog.about.version=Version
dialog.about.build=Build
dialog.saveconfig.prune.trackdirectory=Trackverzeichnis
dialog.saveconfig.prune.photodirectory=Föteliverzeichnis
dialog.saveconfig.prune.languagecode=Sprochecode (DE_ch)
+dialog.saveconfig.prune.languagefile=Sprochedatei
dialog.saveconfig.prune.gpsdevice=GPS Gerätename
dialog.saveconfig.prune.gpsformat=GPS Format
dialog.saveconfig.prune.povrayfont=Povray Font
dialog.saveconfig.prune.exiftoolpath=Exiftool Pfad
dialog.saveconfig.prune.mapserverindex=Kartenserver Index
dialog.saveconfig.prune.mapserverurl=Kartenserver URL
-dialog.saveconfig.prune.showpace=Tempo aazeige
dialog.saveconfig.prune.kmzimagewidth=Bildbreiti im KMZ
dialog.saveconfig.prune.kmzimageheight=Bildhöchi im KMZ
+dialog.saveconfig.prune.colourscheme=Farbeschema
+dialog.saveconfig.prune.kmltrackcolour=KML Trackfarb
dialog.setpaths.intro=Sie könnet dann die Pfade für dia Applikatione setzä:
dialog.addaltitude.noaltitudes=Dr seläktierte Beriich hät keini Höchiinformation
dialog.addaltitude.desc=Höchiverschiebig zuzutue
+dialog.setcolours.intro=Klicket Sie uuf ne Farb um sie z'verändere
+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.selection=Beriich
+dialog.setcolours.text=Texte
+dialog.colourchooser.title=Farbe uuswähle
+dialog.colourchooser.red=Rot
+dialog.colourchooser.green=Grüen
+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>Prune wieder neustarte um die Sproch z'ändere.
+dialog.setlanguage.language=Sproch
+dialog.setlanguage.languagefile=Sproch Datei
+dialog.setlanguage.endmessage=Jetze speicheret Sie Ihri Iistellige und startet Sie Prune neu\num t noii Sproch z' verwände.
# 3d window
dialog.3d.title=Prune Drüü-d Aasicht
confirm.addtimeoffset=Ziitverschiebig zutue
confirm.addaltitudeoffset=Höchiverschiebig zutue
confirm.rearrangewaypoints=Waypoints umorganisiert
+confirm.rearrangephotos=Fotos umorganisiert
confirm.cutandmove=Beriich gmoved
+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.correlate.single=Föteli isch korreliert worde
confirm.correlate.multi=Fötelis sin korreliert worde
confirm.createpoint=Punkt kreiert worde
+confirm.rotatephoto=Föteli umgedräit worde
confirm.running=Am Laufe ...
# Buttons
button.no=Nei
button.yestoall=Ja für alli
button.notoall=Nei für alli
-button.selectall=Alli selektierä
-button.selectnone=Nüüt selektierä
+button.select=Uuswähle
+button.selectall=Alli uuswähle
+button.selectnone=Nüüt uuswähle
button.preview=Vorschauä
button.load=Ladä
button.guessfields=Fälde erratä
button.showwebpage=Websiite aazeigä
button.check=Prüefa
-
+button.resettodefaults=Zurücksetzä
+button.browse=Durasuechä...
# File types
filetype.txt=TXT Dateie
display.range.time.days=T
details.range.avespeed=Gschwindikeit
details.range.avemovingspeed=Gschwindikeit ufem Wäg
+details.range.numsegments=Aazahl Segmänte
details.range.pace=Tempo
+details.range.gradient=Gefälle
details.waypointsphotos.waypoints=Waypoints
details.waypointsphotos.photos=Fötelis
details.photodetails=Details vonem Föteli
units.original=Original
units.default=Default
units.metres=Meter
-units.metres.short=
-units.feet=
-units.feet.short=
units.kilometres=Kilometer
units.kilometres.short=km
units.kmh=km/h
-units.miles=
-units.miles.short=
-units.mph=
units.metrespersec=m/s
units.feetpersec=ft/s
units.hours=Std
undo.connectphoto=Föteli verbindä
undo.disconnectphoto=Föteli trännä
undo.correlate=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ä
# Error messages
error.save.dialogtitle=Fähle bim Speichere
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.failed1=
+error.saveexif.failed2=von d Bilder han i nöd speichere könne
+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.jpegload.nojpegsfound=Kei Jpegs gfunde
error.jpegload.noexiffound=Kei EXIF Information gfunde
error.jpegload.nogpsfound=Kei GPS Information gfunde
+error.gpsload.unknown=Unbekannts Fähler
error.undofailed.title=Undo isch fehlgschlage worde
error.undofailed.text=Operation kann nöd rückgängig gmacht werde
error.function.noop.title=Funktion hät gar nüüt gmacht
-error.rearrange.noop=Waypoints Reorganisierig hät kei Effäkt gha
+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 ufgtrete
+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 Prune z'sii
+error.convertnamestotimes.nonames=Kei Namen han könnet verwondlet werde
menu.file.addphotos=Add photos
menu.file.save=Save
menu.file.exit=Exit
-menu.edit=Edit
+menu.track=Track
menu.edit.undo=Undo
menu.edit.clearundo=Clear undo list
menu.edit.editpoint=Edit point
menu.edit.rearrange.end=All to end of file
menu.edit.rearrange.nearest=Each to nearest track point
menu.edit.cutandmove=Cut and move selection
-menu.select=Select
+menu.range=Range
+menu.point=Point
menu.select.all=Select all
menu.select.none=Select none
menu.select.start=Set range start
menu.view.browser.openstreetmap=Openstreetmap
menu.view.browser.mapquest=Mapquest
menu.view.browser.yahoo=Yahoo maps
+menu.view.browser.bing=Bing maps
menu.settings=Settings
-menu.settings.showpace=Show pace in range display
menu.help=Help
# Popup menu for map
menu.map.zoomin=Zoom in
# Alt keys for menus
altkey.menu.file=F
-altkey.menu.edit=E
-altkey.menu.select=S
+altkey.menu.range=R
+altkey.menu.track=T
+altkey.menu.point=P
altkey.menu.view=V
-altkey.menu.photo=P
-altkey.menu.settings=T
+altkey.menu.photo=O
+altkey.menu.settings=S
altkey.menu.help=H
# Ctrl shortcuts for menu items
function.addtimeoffset=Add time offset
function.addaltitudeoffset=Add altitude offset
function.findwaypoint=Find waypoint
+function.convertnamestotimes=Convert waypoint names to times
+function.pastecoordinates=Enter new coordinates
function.charts=Charts
function.show3d=Three-D view
function.distances=Distances
+function.fullrangedetails=Full range details
function.getgpsies=Get Gpsies tracks
+function.duplicatepoint=Duplicate point
function.correlatephotos=Correlate photos
+function.rearrangephotos=Rearrange photos
+function.rotatephotoleft=Rotate photo left
+function.rotatephotoright=Rotate photo right
+function.ignoreexifthumb=Ignore exif thumbnail
function.setmapbg=Set map background
function.setkmzimagesize=Set KMZ image size
function.setpaths=Set program paths
+function.setcolours=Set colours
+function.setlanguage=Set language
function.help=Help
function.showkeys=Show shortcut keys
function.about=About Prune
dialog.gpsload.format=Format
dialog.gpsload.getwaypoints=Load waypoints
dialog.gpsload.gettracks=Load tracks
+dialog.gpsload.save=Save to file
dialog.gpssend.sendwaypoints=Send waypoints
dialog.gpssend.sendtracks=Send tracks
dialog.gpssend.trackname=Track name
dialog.save.timestampformat=Timestamp format
dialog.save.overwrite.title=File already exists
dialog.save.overwrite.text=This file already exists. Are you sure you want to overwrite the file?
+dialog.save.notypesselected=No point types have been selected
dialog.exportkml.text=Title for the data
dialog.exportkml.altitude=Absolute altitudes (for aviation)
dialog.exportkml.kmz=Compress to make kmz file
dialog.exportkml.exportimages=Export image thumbnails to kmz
+dialog.exportkml.trackcolour=Track colour
dialog.exportgpx.name=Name
dialog.exportgpx.desc=Description
dialog.exportgpx.includetimestamps=Include timestamps
+dialog.exportgpx.copysource=Copy source xml
dialog.exportpov.text=Please enter the parameters for the POV export
dialog.exportpov.font=Font
dialog.exportpov.camerax=Camera X
dialog.pointtype.track=Track points
dialog.pointtype.waypoint=Waypoints
dialog.pointtype.photo=Photo points
+dialog.pointtype.selection=Just selection
dialog.confirmreversetrack.title=Confirm reversal
dialog.confirmreversetrack.text=This track contains timestamp information, which will be out of sequence after a reversal.\nAre you sure you want to reverse this section?
dialog.confirmcutandmove.title=Confirm cut and move
dialog.addtimeoffset.notimestamps=Cannot add a time offset as this selection doesn't contain any timestamp information
dialog.findwaypoint.intro=Enter part of the waypoint name
dialog.findwaypoint.search=Search
-dialog.connect.title=Connect photo to point
-dialog.connectphoto.clonepoint=This point already has a photo.\nDo you want to make a copy of the point?
dialog.saveexif.title=Save Exif
dialog.saveexif.intro=Select the photos to save using the checkboxes
dialog.saveexif.nothingtosave=Coordinate data is unchanged, nothing to save
dialog.saveexif.photostatus.disconnected=Disconnected
dialog.saveexif.photostatus.modified=Modified
dialog.saveexif.overwrite=Overwrite files
+dialog.saveexif.force=Force despite minor errors
dialog.charts.xaxis=X axis
dialog.charts.yaxis=Y axes
dialog.charts.output=Output
dialog.charts.svgwidth=SVG width
dialog.charts.svgheight=SVG height
dialog.charts.needaltitudeortimes=The track must have either altitudes or time information in order to create charts
-dialog.charts.gnuplotpath=Path to gnuplot
dialog.charts.gnuplotnotfound=Could not find gnuplot with the given path
dialog.distances.intro=Straight line distances between points
dialog.distances.column.from=From point
dialog.distances.column.to=To point
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.setmapbg.mapnik=Mapnik (default)
dialog.setmapbg.osma=Osma
dialog.setmapbg.cyclemap=Cyclemap
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.rearrangephotos.desc=Select the destination and sort order of the photo points
+dialog.rearrangephotos.tostart=Move to start
+dialog.rearrangephotos.toend=Move to end
+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.singletons.title=Singleton removal
dialog.compress.singletons.paramdesc=Distance factor
dialog.compress.summarylabel=Points to delete
+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/prune/\nfor more information and user guides.
dialog.about.version=Version
dialog.about.build=Build
dialog.saveconfig.prune.trackdirectory=Track directory
dialog.saveconfig.prune.photodirectory=Photo directory
dialog.saveconfig.prune.languagecode=Language code (EN)
+dialog.saveconfig.prune.languagefile=Language file
dialog.saveconfig.prune.gpsdevice=GPS device
dialog.saveconfig.prune.gpsformat=GPS format
dialog.saveconfig.prune.povrayfont=Povray font
dialog.saveconfig.prune.exiftoolpath=Path to exiftool
dialog.saveconfig.prune.mapserverindex=Index of map server
dialog.saveconfig.prune.mapserverurl=URL of map server
-dialog.saveconfig.prune.showpace=Show pace
dialog.saveconfig.prune.kmzimagewidth=KMZ image width
dialog.saveconfig.prune.kmzimageheight=KMZ image height
+dialog.saveconfig.prune.colourscheme=Colour scheme
+dialog.saveconfig.prune.kmltrackcolour=KML track colour
dialog.setpaths.intro=If you need to, you can choose the paths to the external applications:
dialog.addaltitude.noaltitudes=The selected range does not contain altitudes
dialog.addaltitude.desc=Altitude offset to add
+dialog.setcolours.intro=Click on a colour patch to change the colour
+dialog.setcolours.background=Background
+dialog.setcolours.borders=Borders
+dialog.setcolours.lines=Lines
+dialog.setcolours.primary=Primary
+dialog.setcolours.secondary=Secondary
+dialog.setcolours.point=Points
+dialog.setcolours.selection=Selection
+dialog.setcolours.text=Text
+dialog.colourchooser.title=Choose colour
+dialog.colourchooser.red=Red
+dialog.colourchooser.green=Green
+dialog.colourchooser.blue=Blue
+dialog.setlanguage.firstintro=You can either select one of the included languages,<p>or select a text file to use instead.
+dialog.setlanguage.secondintro=You need to save your settings and then<p>restart Prune to change the language.
+dialog.setlanguage.language=Language
+dialog.setlanguage.languagefile=Language file
+dialog.setlanguage.endmessage=Now save your settings and restart Prune\nfor the language change to take effect.
# 3d window
dialog.3d.title=Prune Three-d view
confirm.addtimeoffset=Time offset added
confirm.addaltitudeoffset=Altitude offset added
confirm.rearrangewaypoints=Waypoints rearranged
+confirm.rearrangephotos=Photos rearranged
confirm.cutandmove=Selection moved
+confirm.convertnamestotimes=Waypoint names converted
confirm.saveexif.ok1=Saved
confirm.saveexif.ok2=photo files
confirm.undo.single=operation undone
confirm.photo.disconnect=photo disconnected
confirm.correlate.single=photo was correlated
confirm.correlate.multi=photos were correlated
+confirm.rotatephoto=photo rotated
confirm.createpoint=point created
confirm.running=Running ...
button.no=No
button.yestoall=Yes to all
button.notoall=No to all
+button.select=Select
button.selectall=Select all
button.selectnone=Select none
button.preview=Preview
button.guessfields=Guess fields
button.showwebpage=Show webpage
button.check=Check
+button.resettodefaults=Reset to defaults
+button.browse=Browse...
# File types
filetype.txt=TXT files
display.range.time.days=d
details.range.avespeed=Ave speed
details.range.avemovingspeed=Moving ave
+details.range.numsegments=Number of segments
details.range.pace=Pace
+details.range.gradient=Gradient
details.waypointsphotos.waypoints=Waypoints
details.waypointsphotos.photos=Photos
details.photodetails=Photo details
undo.connectphoto=connect photo
undo.disconnectphoto=disconnect photo
undo.correlate=correlate photos
+undo.rearrangephotos=rearrange photos
+undo.rotatephoto=rotate photo
undo.createpoint=create point
+undo.convertnamestotimes=convert names to times
# Error messages
error.save.dialogtitle=Error saving data
error.saveexif.filenotfound=Failed to find photo file
error.saveexif.cannotoverwrite1=Photo file
error.saveexif.cannotoverwrite2=is read-only and can't be overwritten. Write to copy?
+error.saveexif.failed1=Failed to save
+error.saveexif.failed2=of the images
+error.saveexif.forced1=
+error.saveexif.forced2=of the images required forcing
error.load.dialogtitle=Error loading data
error.load.noread=Cannot read file
error.load.nopoints=No coordinate information found in the file
error.jpegload.nojpegsfound=No jpeg files found
error.jpegload.noexiffound=No EXIF information found
error.jpegload.nogpsfound=No GPS information found
+error.gpsload.unknown=Unknown error
error.undofailed.title=Undo failed
error.undofailed.text=Failed to undo operation
error.function.noop.title=Function had no effect
-error.rearrange.noop=Rearranging waypoints had no effect
+error.rearrange.noop=Rearranging points had no effect
error.function.notavailable.title=Function not available
error.function.nojava3d=This function requires the Java3d library,\navailable from Sun.com.
error.3d=An error occurred with the 3d display
error.readme.notfound=Readme file not found
error.osmimage.dialogtitle=Error loading map images
error.osmimage.failed=Failed to load map images. Please check internet connection.
+error.language.wrongfile=The selected file doesn't appear to be a language file for Prune
+error.convertnamestotimes.nonames=No names could be converted into times
menu.file.save=Guardar
menu.file.exit=Salir
menu.edit=Editar
+menu.track=Track
menu.edit.undo=Deshacer
menu.edit.clearundo=Despejar la lista de deshacer
menu.edit.editpoint=Editar punto
menu.edit.rearrange.nearest=Ir al m\u00e1s pr\u00f3ximo
menu.edit.cutandmove=Cortar y mover selecci\u00f3n
menu.select=Seleccionar
+menu.range=Rango
+menu.point=Punto
menu.select.all=Seleccionar todo
menu.select.none=No seleccionar nada
menu.select.start=Fijar comienzo
menu.view.browser.google=Google maps
menu.view.browser.openstreetmap=Openstreetmap
menu.view.browser.mapquest=Mapquest
-menu.view.browser.yahoo=mapas Yahoo
+menu.view.browser.yahoo=Mapas Yahoo
+menu.view.browser.bing=Mapas Bing
menu.settings=Preferencias
-menu.settings.showpace=
menu.help=Ayuda
# Popup menu for map
menu.map.zoomin=Ampliar zoom
menu.map.connect=Conectar puntos de track
menu.map.autopan=Posicionar autom\u00e1ticamente
menu.map.showmap=Mostrar el mapa
-menu.map.showscalebar=
+menu.map.showscalebar=Mostrar barra de escala
# Alt keys for menus
altkey.menu.file=A
altkey.menu.edit=E
altkey.menu.select=S
+altkey.menu.track=T
+altkey.menu.range=R
+altkey.menu.point=U
altkey.menu.view=V
altkey.menu.photo=F
altkey.menu.settings=P
function.compress=Comprimir track
function.addtimeoffset=A\u00f1adir compensar tiempo
function.addaltitudeoffset=A\u00f1adir compensar altitud
+function.convertnamestotimes=Convertir los nombres de los "waypoints" a tiempo
function.findwaypoint=Buscar waypoint
+function.pastecoordinates=Insertar nuevas coordenadas
function.charts=Diagramas
function.show3d=Mostrar en 3-D
function.distances=Distancias
-function.getgpsies=Bajar ruta de Gpsies
-function.correlatephotos=Correlacionar fotos
+function.fullrangedetails=Detalles adicionales de rango
function.setmapbg=Configurar fondo de mapa
function.setkmzimagesize=Configurar tama\u00f1os de las im\u00e1genes KMZ
function.setpaths=Configurar rutas del programas
+function.getgpsies=Bajar ruta de Gpsies
+function.duplicatepoint=Duplicar punto
+function.setcolours=Establecer color
+function.setlanguage=Establecer lenguaje
+function.correlatephotos=Correlacionar fotos
+function.rearrangephotos=Reacomodar fotos
+function.rotatephotoleft=Girar a la izquierda
+function.rotatephotoright=Girar a la derecha
+function.ignoreexifthumb=Ignorar "thumbnail" de exif
function.help=Ayuda
-function.showkeys=
+function.showkeys=Mostrar teclas o combinaciones de atajo
function.about=Acerca de Prune
function.checkversion=Buscar una nueva versi\u00f3n
function.saveconfig=Guardar preferencias
dialog.jpegload.progress.title=Cargando fotos
dialog.jpegload.progress=Por favor espere mientras se buscan las fotos
dialog.gpsload.nogpsbabel=gpsbabel program no encontrado. Desea continuar?
-dialog.gpsload.device=
+dialog.gpsload.device=Dispositivo
dialog.gpsload.format=Formato
dialog.gpsload.getwaypoints=Cargar waypoints
dialog.gpsload.gettracks=Cargar tracks
-dialog.gpssend.sendwaypoints=
-dialog.gpssend.sendtracks=
+dialog.gpsload.save=Salvar al archivo
+dialog.gpssend.sendwaypoints=enviar "waypoints"
+dialog.gpssend.sendtracks=enviar tracks
dialog.gpssend.trackname=Nombre del track
dialog.saveoptions.title=Guardar archivo
dialog.save.fieldstosave=Campos a guardar
dialog.save.timestampformat=Format del tiempo
dialog.save.overwrite.title=El archivo ya existe
dialog.save.overwrite.text=El archivo ya existe, desea sobreescribirlo?
+dialog.save.notypesselected=No se han seleccionado tipos de puntos
dialog.exportkml.text=Descripci\u00f3n para los datos
dialog.exportkml.altitude=Absoluta altitudes (para aviaci\u00f3n)
dialog.exportkml.kmz=Comprimir al archivo kmz
dialog.exportkml.exportimages=Exportar fotos al kmz
+dialog.exportkml.trackcolour=Color del track
dialog.exportgpx.name=Nombre
dialog.exportgpx.desc=Descripci\u00f3n
dialog.exportgpx.includetimestamps=Tiempo tambien
+dialog.exportgpx.copysource=Copiar la fuente
dialog.exportpov.text=Introdzca los Parametros para exportar
dialog.exportpov.font=Fuente
dialog.exportpov.camerax=C\u00e1mara X
dialog.exportpov.ballsandsticks=Balas en palos
dialog.exportpov.tubesandwalls=Tubos y paredes
dialog.exportpov.warningtracksize=Este track contiene un gran numero de puntos. Puede ser que Java3D no los pueda visualizar. Est\u00e1 seguro de que desea continuar?
-dialog.pointtype.desc=
-dialog.pointtype.track=
-dialog.pointtype.waypoint=
-dialog.pointtype.photo=
+dialog.pointtype.desc=Salvar los siguientes tipos de puntos:
+dialog.pointtype.track=Puntos de track
+dialog.pointtype.photo=Puntos de foto
+dialog.pointtype.selection=Solo selecci\u00f3n
dialog.confirmreversetrack.title=Confirmar inversi\u00f3n
dialog.confirmreversetrack.text=Este track contiene informaci\u00f3n sobre la fecha, que estar\u00e1 fuera de secuencia despu\u00e9s de la inversi\u00f3n. Esta seguro que desea invertir esta secci\u00f3n?
-dialog.confirmcutandmove.title=Confirmar ...
+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 la .... Esta seguro que desea ... esta secci\u00f3n?
dialog.interpolate.title=Interpolar puntos
dialog.interpolate.parameter.text=N\u00famero de los puntos a insertar entre los puntos elegidos
dialog.pointnameedit.uppercase=May\u00fasculas
dialog.pointnameedit.lowercase=min\u00fasculas
dialog.pointnameedit.sentencecase=Mezcla
-dialog.addtimeoffset.add=
-dialog.addtimeoffset.subtract=
+dialog.addtimeoffset.add=a\u00f1adir tiempo
+dialog.addtimeoffset.subtract=sustraer tiempo
dialog.addtimeoffset.days=Dias
dialog.addtimeoffset.hours=Horas
dialog.addtimeoffset.minutes=Minutos
-dialog.addtimeoffset.notimestamps=
-dialog.findwaypoint.intro=
-dialog.findwaypoint.search=
+dialog.addtimeoffset.notimestamps=No se puede a\u00f1adir tiempo de puesta a esta selecci\u00f3n si \u00e9sta no contiene ninguna informaci\u00f3n de "timestamp"
+dialog.findwaypoint.intro=Ingresar parte del nombre de "waypoint"
+dialog.findwaypoint.search=Buscar
dialog.connect.title=Conectar foto
-dialog.connectphoto.clonepoint=
+dialog.connectphoto.clonepoint=Este punto ya tiene una foto.\n Quisiera usted hacer una copia de este?
dialog.saveexif.title=Guardar Exif
dialog.saveexif.intro=Seleccione fotos a guardar
dialog.saveexif.nothingtosave=Coordenadas no modificadas, nada que guardar
dialog.saveexif.photostatus.disconnected=Desconectada
dialog.saveexif.photostatus.modified=Modificada
dialog.saveexif.overwrite=Sobreescribirlar archivos?
+dialog.saveexif.force=Fuerza despreciar errores menores
dialog.charts.xaxis=Eje de abscisas
dialog.charts.yaxis=Eje vertical
dialog.charts.output=Resultado
-dialog.charts.screen=
-dialog.charts.svg=
-dialog.charts.svgwidth=
-dialog.charts.svgheight=
-dialog.charts.needaltitudeortimes=
-dialog.charts.gnuplotpath=
-dialog.charts.gnuplotnotfound=
-dialog.distances.intro=
+dialog.charts.screen=Salida a pantalla
+dialog.charts.svg=Salida a archivo SVG
+dialog.charts.svgwidth=Ancho de SVG
+dialog.charts.svgheight=Alto de SVG
+dialog.charts.needaltitudeortimes=La pista debe tener altitudes o informaci\u00f3n de tiempo en orden para crear las tablas
+dialog.charts.gnuplotnotfound=No pudo ser encontrado gnuplot con el camino o la direcci\u00f3n proporcionada
+dialog.distances.intro=L\u00edneas rectas entre puntos
dialog.distances.column.from=De punto
dialog.distances.column.to=Al punto
dialog.distances.currentpoint=Punto actual
-dialog.distances.toofewpoints=
-dialog.setmapbg.mapnik=Mapnik (por defecto)
-dialog.setmapbg.osma=
-dialog.setmapbg.cyclemap=
+dialog.distances.toofewpoints=Esta funcion necesita "waypoints" para poder calcular las distancias entre ellos
+dialog.fullrangedetails.intro=Aqui estan los detalles para la selecci\u00f3n de rangos
+dialog.setmapbg.mapnik=Mapnik (predeterminado)
dialog.setmapbg.other=Otro
-dialog.setmapbg.server=
-dialog.gpsies.column.name=Nombre
-dialog.gpsies.column.length=
+dialog.setmapbg.server=Direcci\u00f3n URL del servidor
+dialog.gpsies.column.name=Nombre del track
+dialog.gpsies.column.length=Distancia
dialog.gpsies.description=Descripci\u00f3n
-dialog.gpsies.nodescription=Ning\u00fan descripci\u00f3n
-dialog.gpsies.nonefound=
+dialog.gpsies.nodescription=Sin Descripci\u00f3n
+dialog.gpsies.nonefound=No se encontraron pistas
dialog.correlate.notimestamps=No hay informaci\u00f3n de tiempo para los puntos, as\u00ed que no hay nada que correlacionar con las fotos.
dialog.correlate.nouncorrelatedphotos=No hay fotos no correlacionadas.\nEst\u00e1 seguro de que desea continuar?
dialog.correlate.photoselect.intro=Seleccione una de estas fotos correlacionadas para usar como margen de tiempo
dialog.correlate.options.distancelimit=L\u00edmite de distancia
dialog.correlate.options.correlate=Correlacionar
dialog.correlate.alloutsiderange=Todas las fotos est\u00e1n fuera del margen horario del track, por lo que ninguna puede ser correlada.\nIntente cambiar el margen o correle manualmente al menos una foto.
+dialog.rearrangephotos.desc=Seleccionar el destino y sortear el orden de los puntos de las fotos
+dialog.rearrangephotos.tostart=Mover al comienzo
+dialog.rearrangephotos.toend=Mover al final
+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.compress.closepoints.title=remover puntos cercanos
+dialog.compress.wackypoints.paramdesc=Factor distancia
+dialog.compress.singletons.paramdesc=Factor distancia
dialog.compress.duplicates.title=Eliminar duplicados
-dialog.compress.closepoints.title=
-dialog.compress.closepoints.paramdesc=
-dialog.compress.wackypoints.title=
-dialog.compress.wackypoints.paramdesc=
-dialog.compress.singletons.title=
-dialog.compress.singletons.paramdesc=
-dialog.compress.summarylabel=
+dialog.compress.summarylabel=Puntos para eliminar
+dialog.pastecoordinates.desc=Ingresar o pegar las coordenadas aqu\u00ed
+dialog.pastecoordinates.coords=Coordenadas
+dialog.pastecoordinates.nothingfound=Por favor verificar las coordenadas e intentar nuevamente
dialog.help.help=Por favor, ver\n http://activityworkshop.net/software/prune/\npara m\u00e1s informaci\u00f3n y gu\u00edas del usuario.
dialog.about.version=Versi\u00f3n
-dialog.about.build=Construir
+dialog.about.build=Construcci\u00f3n
dialog.about.summarytext1=Prune es un programa para cargar, mostrar y editar datos de receptores GPS.
dialog.about.summarytext2=Distribuido bajo el GNU GPL para uso libre y gratuito.<br>Se permite (y se anima) la copia, redistribuci\u00f3n y modificaci\u00f3n de acuerdo<br>a las condiciones incluidas en el archivo <code>licence.txt</code>.
dialog.about.summarytext3=Por favor, ver <code style="font-weight:bold">http://activityworkshop.net/</code> para m\u00e1s informaci\u00f3n y gu\u00edas del usuario.
dialog.about.systeminfo.gnuplot=Gnuplot instalado
dialog.about.yes=Si
dialog.about.no=No
-dialog.about.credits=Credits
+dialog.about.credits=Creditos
dialog.about.credits.code=El c\u00f3digo de Prune fue escrito por
dialog.about.credits.exifcode=El c\u00f3digo Exif por
dialog.about.credits.icons=Algunos iconos se tomaron de
dialog.about.credits.othertools=Otras herramientas
dialog.about.credits.thanks=Gracias a
dialog.about.readme=Readme
-dialog.checkversion.error=
-dialog.checkversion.uptodate=
-dialog.checkversion.newversion1=
-dialog.checkversion.newversion2=
-dialog.checkversion.releasedate1=
-dialog.checkversion.releasedate2=
-dialog.checkversion.download=To download the new version, go to http://activityworkshop.net/software/prune/download.html.
-dialog.keys.intro=
-dialog.keys.keylist=
-dialog.saveconfig.desc=
-dialog.saveconfig.prune.trackdirectory=
-dialog.saveconfig.prune.photodirectory=
-dialog.saveconfig.prune.languagecode=
-dialog.saveconfig.prune.gpsdevice=
-dialog.saveconfig.prune.gpsformat=
+dialog.checkversion.error=El numero de versi\u00f3n no pudo ser verificada.\n Por favor verificar la conexi\u00f3n de internet
+dialog.checkversion.uptodate=Esta usted utilizando la \u00faltima versi\u00f3n de Prune
+dialog.checkversion.newversion1=Una nueva versi\u00f3n de Prune est\u00e1 disponible! La \u00daltima versi\u00f3n es ahora versi\u00f3n
+dialog.checkversion.newversion2=.
+dialog.checkversion.releasedate1=La nueva versi\u00f3n fue lanzada en
+dialog.checkversion.releasedate2=.
+dialog.keys.intro=Usted puede usar el siguiente atajo en lugar de usar el rat\u00f3n
+dialog.saveconfig.desc=La siguiente configuraci\u00f3n puede ser salvada en un archivo de configuraci\u00f3n
+dialog.saveconfig.prune.trackdirectory=Directorio de pista
+dialog.saveconfig.prune.photodirectory=Directorio de foto
+dialog.saveconfig.prune.languagecode=C\u00f3digo de lenguaje (ES)
+dialog.saveconfig.prune.languagefile=Archivo de lenguaje
+dialog.saveconfig.prune.gpsdevice=Dispositivo GPS
+dialog.saveconfig.prune.gpsformat=Formato GPS
dialog.saveconfig.prune.povrayfont=Fuente povray
-dialog.saveconfig.prune.metricunits=
-dialog.saveconfig.prune.gnuplotpath=
-dialog.saveconfig.prune.gpsbabelpath=
-dialog.saveconfig.prune.exiftoolpath=
-dialog.saveconfig.prune.mapserverindex=
-dialog.saveconfig.prune.mapserverurl=
-dialog.saveconfig.prune.showpace=
-dialog.saveconfig.prune.kmzimagewidth=
-dialog.saveconfig.prune.kmzimageheight=
-dialog.setpaths.intro=
-dialog.addaltitude.noaltitudes=
+dialog.saveconfig.prune.metricunits=Usar unidades m\u00e9tricas?
+dialog.saveconfig.prune.gnuplotpath=Camino a gnuplot
+dialog.saveconfig.prune.gpsbabelpath=Camino a gpsbabel
+dialog.saveconfig.prune.exiftoolpath=Camino a exiftool
+dialog.saveconfig.prune.mapserverindex=\u00cdndice de mapa del servidor
+dialog.saveconfig.prune.mapserverurl=Direcci\u00f3n URL de mapa del servidor
+dialog.saveconfig.prune.kmzimagewidth=Ancho de im\u00e1genes en kmz
+dialog.saveconfig.prune.kmzimageheight=Alto de im\u00e1genes en kmz
+dialog.saveconfig.prune.colourscheme=Color de esquema
+dialog.saveconfig.prune.kmltrackcolour=Color de pista de KML
+dialog.setpaths.intro=Si usted necesita, puede escoger las rutas a aplicaciones externas
+dialog.addaltitude.noaltitudes=Los rangos seleccionados no contienen altitudes
dialog.addaltitude.desc=
+dialog.setcolours.intro=Clickear sobre una placa de color para cambiar el color
+dialog.setcolours.background=Fondo
+dialog.setcolours.borders=Bordes
+dialog.setcolours.lines=L\u00edneas
+dialog.setcolours.primary=Primario
+dialog.setcolours.secondary=Secundario
+dialog.setcolours.point=Puntos
+dialog.setcolours.selection=Selecci\u00f3n
+dialog.setcolours.text=Texto
+dialog.colourchooser.title=Elegir color
+dialog.colourchooser.red=Rojo
+dialog.colourchooser.green=Verde
+dialog.colourchooser.blue=Azul
+dialog.setlanguage.firstintro=Puede usted seleccionar algunos de los lenguajes incluidos,<p>o puede en lugar de esto seleccionar un archivo de texto
+dialog.setlanguage.secondintro=Usted necesita salvar su configuraci\u00f3n y luego<p>reiniciar Prune para cambiar el lenguaje
+dialog.setlanguage.language=Lenguaje
+dialog.setlanguage.languagefile=Archivo de lenguaje
+dialog.setlanguage.endmessage=Ahora salve su configuraci\u00f3n y reinicie Prune\npara que los cambios tomen efecto.
# 3d window
dialog.3d.title=Prune vista 3-D
confirm.point.edit=Punto editado
confirm.mergetracksegments=Segmentos unidos
confirm.reverserange=Rango invertido
-confirm.addtimeoffset=
-confirm.addaltitudeoffset=
confirm.rearrangewaypoints=Waypoints reorganizados
-confirm.cutandmove=
+confirm.rearrangephotos=Fotos reacomodadas
+confirm.cutandmove=Mover Selecci\u00f3n
confirm.saveexif.ok1=Guardando
confirm.saveexif.ok2=fotos
confirm.undo.single=operaci\u00f3n no realizada
confirm.correlate.single=foto fue correlada
confirm.correlate.multi=fotos fueron correladas
confirm.createpoint=punto creado
+confirm.rotatephoto=Foto rotada
confirm.running=Trabajando ...
-# Buttons
+# Buttons || These are all the texts for buttons
button.ok=Aceptar
button.back=Anterior
button.next=Siguiente
button.no=No
button.yestoall=Si por todo
button.notoall=No por todo
+button.select=Seleccionar
button.selectall=Seleccionar todo
button.selectnone=Seleccionar nada
button.preview=Previsualizaci\u00f3n
button.guessfields=Adivinar campos
button.showwebpage=Mostrar p\u00e1gina web
button.check=Verificar
+button.resettodefaults=Restablecer valores a los predeterminados
# File types
filetype.txt=Archivos TXT
filetype.pov=Archivos POV
filetype.svg=Archivos SVG
-# Display components
+# Display components || These are all for the side panels showing point/range details
display.nodata=Ning\u00fan dato cargado
display.noaltitudes=Los datos del track no incluyen altitudes
details.trackdetails=Detalles del track
display.range.time.hours=h
display.range.time.days=d
details.range.avespeed=Velocidad media
-details.range.avemovingspeed=
-details.range.pace=
+details.range.avemovingspeed=Moviendo promedio
+details.range.numsegments=N\u00famero de segmentos
+details.range.gradient=Gradiente
details.waypointsphotos.waypoints=Waypoints
details.waypointsphotos.photos=Fotos
details.photodetails=Detalles del Foto
details.nophoto=Ninguna foto seleccionada
details.photo.loading=Cargando
details.photo.connected=Conectada
-map.overzoom=
+map.overzoom=No existen mapas disponibles con este nivel de enfoque
# Field names
fieldname.latitude=Latitud
fieldname.custom=Personalizado
fieldname.prefix=Campo
fieldname.distance=Distancia
-fieldname.movingdistance=
+fieldname.movingdistance=Distancia en movimiento
fieldname.duration=Duraci\u00f3n
fieldname.speed=Velocidad
fieldname.verticalspeed=Velocidad vertical
cardinal.e=E
cardinal.w=O
-# Undo operations
+# Undo operations || These will be displayed in the undo list after you've performed the operation, to tell you what you did
undo.load=cargar datos
undo.loadphotos=cargar fotos
undo.editpoint=editar punto
undo.insert=insertar puntos
undo.reverse=invertir rango
undo.mergetracksegments=unir los segmentos de track
-undo.addtimeoffset=
-undo.addaltitudeoffset=
undo.rearrangewaypoints=reordenar waypoints
-undo.cutandmove=
undo.connectphoto=conectar foto
undo.disconnectphoto=desconectar foto
undo.correlate=correlacionar fotos
+undo.rotatephoto=girar foto
undo.createpoint=crear punto
# Error messages
error.saveexif.filenotfound=Archivo no encontrado
error.saveexif.cannotoverwrite1=No se puede guardar
error.saveexif.cannotoverwrite2=. Guardar a una copia?
+error.saveexif.failed1=Fall\u00f3 al salvar
+error.saveexif.failed2=de las im\u00e1genes
error.load.dialogtitle=Fallo al cargar datos
error.load.noread=No se puede leer el fichero
error.load.nopoints=Ninguna informaci\u00f3n coordenadas encontrada
error.jpegload.nojpegsfound=Ning\u00fan archivo jpeg encontrado
error.jpegload.noexiffound=Ninguna informaci\u00f3n EXIF encontrada
error.jpegload.nogpsfound=Ninguna informaci\u00f3n GPS encontrada
+error.gpsload.unknown=Error desconocido
error.undofailed.title=Fallo al deshacer
error.undofailed.text=No ha sido posible deshacer la operaci\u00f3n
error.function.noop.title=La funci\u00f3n no se ha efectuado
-error.rearrange.noop=Reordenaci\u00f3n de waypoints no se ha efectuado
+error.rearrange.noop=Reordenaci\u00f3n de puntos no se ha efectuado
error.function.notavailable.title=Funci\u00f3n no disponible
error.function.nojava3d=Esta funci\u00f3n requiere la librer\u00eda Java3d, disponible en Sun.com.
error.3d=Ha ocurrido un error con la funci\u00f3n 3-D
error.readme.notfound=Archivo readme no encontrado
error.osmimage.dialogtitle=Error al cargar el mapa
error.osmimage.failed=Imposible cargar el mapa. Por favor, compruebe la conexi\u00f3n a internet.
+error.language.wrongfile=El archivo seleccionado no parece ser un archivo de lenguaje para Prune
+error.convertnamestotimes.nonames=Los nombres no pudieron ser convertidos en tiempos
menu.file.save=Enregistrer
menu.file.exit=Quitter
menu.edit=\u00c9dition
+menu.track=Trace
menu.edit.undo=Annuler
menu.edit.clearundo=Purger la liste d'annulation
menu.edit.editpoint=Editer le point
menu.edit.rearrange.nearest=Chacun au point de trace le plus proche
menu.edit.cutandmove=Couper et bouger la s\u00e9lection
menu.select=S\u00e9lectionner
+menu.range=\u00c9tendue
+menu.point=Point
menu.select.all=Tout s\u00e9lectionner
menu.select.none=Rien s\u00e9lectionner
menu.select.start=D\u00e9finir le d\u00e9but de l'\u00e9tendue
menu.view.browser.openstreetmap=Openstreetmap
menu.view.browser.mapquest=Mapquest
menu.view.browser.yahoo=Yahoo maps
+menu.view.browser.bing=Cartes dans Bing
menu.settings=Pr\u00e9f\u00e9rences
menu.settings.showpace=Montrer allure dans les d\u00e9tails
menu.help=Aide
altkey.menu.file=F
altkey.menu.edit=E
altkey.menu.select=S
+altkey.menu.track=T
+altkey.menu.range=E
+altkey.menu.point=P
altkey.menu.view=A
-altkey.menu.photo=P
+altkey.menu.photo=H
altkey.menu.settings=R
altkey.menu.help=I
function.compress=Compresser la trace
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.findwaypoint=Trouver un waypoint
+function.pastecoordinates=Coller les coordonn\u00e9es
function.charts=Graphiques
function.show3d=Montrer en 3D
function.distances=Distances
-function.getgpsies=R\u00e9cup\u00e9rer les traces Gpsies
-function.correlatephotos=Corr\u00e9ler les photos
+function.fullrangedetails=Montrer tous les d\u00e9tails
function.setmapbg=D\u00e9finir le fond de carte
function.setkmzimagesize=D\u00e9finir la taille de l'image KMZ
function.setpaths=D\u00e9finir les chemins des programmes
+function.getgpsies=R\u00e9cup\u00e9rer les traces Gpsies
+function.duplicatepoint=Duppliquer le point
+function.setcolours=R\u00e9gler les couleurs
+function.setlanguage=R\u00e9gler la langue
+function.correlatephotos=Corr\u00e9ler les photos
+function.rearrangephotos=R\u00e9arranger les photos
+function.rotatephotoleft=Tourner la photo vers la gauche
+function.rotatephotoright=Tourner la photo vers la droite
+function.ignoreexifthumb=Ignorer l\u2019aper\u00e7u Exif
function.help=Aide
function.showkeys=Montrer les raccourcis clavier
function.about=À propos de Prune
dialog.gpsload.format=Format
dialog.gpsload.getwaypoints=T\u00e9l\u00e9charger les waypoints
dialog.gpsload.gettracks=T\u00e9l\u00e9charger les traces
+dialog.gpsload.save=Enregistrer dans un fichier
dialog.gpssend.sendwaypoints=Envoyer les waypoints
dialog.gpssend.sendtracks=Envoyer les traces
dialog.gpssend.trackname=Nom de trace
dialog.save.timestampformat=Format de l'heure
dialog.save.overwrite.title=Le fichier existe d\u00e9j\u00e0
dialog.save.overwrite.text=Ce fichier existe d\u00e9j\u00e0. \u00cates-vous s\u00fbr de vouloir \u00e9craser ce fichier ?
+dialog.save.notypesselected=Aucun type de point n\u2019a \u00e9t\u00e9 s\u00e9lectionn\u00e9
dialog.exportkml.text=Titre pour les donn\u00e9es
dialog.exportkml.altitude=Absolues altitudes (pour aviation)
dialog.exportkml.kmz=Compresser au format kmz
dialog.exportkml.exportimages=Exporter les vignettes au format kmz
+dialog.exportkml.trackcolour=Couleur de la trace
dialog.exportgpx.name=Nom
dialog.exportgpx.desc=L\u00e9gende
dialog.exportgpx.includetimestamps=Inclure l'heure pour chaque point
+dialog.exportgpx.copysource=Copier le XML source
dialog.exportpov.text=Entrez les param\u00e8tres pour l'export POV
dialog.exportpov.font=Police
dialog.exportpov.camerax=Cam\u00e9ra X
dialog.pointtype.track=Points de la trace
dialog.pointtype.waypoint=Waypoints
dialog.pointtype.photo=Points de photos
+dialog.pointtype.selection=Uniquement la s\u00e9lection
dialog.confirmreversetrack.title=Confirmer l'inversion
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.saveexif.photostatus.disconnected=D\u00e9connect\u00e9
dialog.saveexif.photostatus.modified=Modifi\u00e9
dialog.saveexif.overwrite=Ecraser les fichiers
+dialog.saveexif.force=Ignorer les erreurs mineures
dialog.charts.xaxis=Axe des x
dialog.charts.yaxis=Axe des y
dialog.charts.output=Sortie
dialog.charts.svgwidth=Largeur de l'image SVG
dialog.charts.svgheight=Hauteur de l'image SVG
dialog.charts.needaltitudeortimes=La trace ne peut g\u00e9n\u00e9rer des graphiques sans disposer d'altitudes ou d'indications temporelles
-dialog.charts.gnuplotpath=Chemin gnuplot
dialog.charts.gnuplotnotfound=Gnuplot est introuvable dans le chemin indiqu\u00e9
dialog.distances.intro=Distances \u00e0 vol d'oiseau entre des points
dialog.distances.column.from=Du point
dialog.distances.column.to=Vers le point
dialog.distances.currentpoint=Point courant
dialog.distances.toofewpoints=Cette fonction a besoin de waypoints pour calculer les distances entre eux
+dialog.fullrangedetails.intro=Voici les d\u00e9tails pour l\u2019\u00e9tendue s\u00e9lectionn\u00e9e
dialog.setmapbg.mapnik=Mapnik (d\u00e9faut)
dialog.setmapbg.osma=Osma
dialog.setmapbg.cyclemap=Cyclemap
dialog.correlate.options.distancelimit=Limite de distance
dialog.correlate.options.correlate=Corr\u00e9ler
dialog.correlate.alloutsiderange=Les photos ne correspondent pas \u00e0 la plage de temps de la trace, aucune ne peut \u00eatre corr\u00e9l\u00e9e.\nEssayez de modifier le d\u00e9calage ou de corr\u00e9ler manuellement au moins une photo.
+dialog.rearrangephotos.desc=Choisissez la destination et l\u2019ordre des points des photos
+dialog.rearrangephotos.tostart=Aller au d\u00e9but
+dialog.rearrangephotos.toend=Aller \u00e0 la fin
+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.duplicates.title=Suppression des doublons
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.wackypoints.paramdesc=Distance
dialog.compress.singletons.title=Suppression des points isol\u00e9s
dialog.compress.singletons.paramdesc=Distance
+dialog.compress.duplicates.title=Suppression des doublons
dialog.compress.summarylabel=Points \u00e0 supprimer
+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.help.help=Consultez la page\n http://activityworkshop.net/software/prune/\npour plus de d\u00e9tails et des manuels utilisateur.
dialog.about.version=Version
dialog.about.build=Build
dialog.about.summarytext1=Prune est un programme pour charger, afficher et \u00e9diter des donn\u00e9es de r\u00e9cepteurs GPS.
dialog.about.summarytext2=Distribu\u00e9 sous license Gnu GPL pour un usage et une am\u00e9lioration libres, ouverts et mondiaux.<br>La copie, la redistribution et la modification sont autoris\u00e9es et encourag\u00e9es<br>selon les conditions d\u00e9taill\u00e9es dans le fichier <code>license.txt</code> inclus.
-dialog.about.summarytext3=Consultez la page <code style="font-weight:bold">http://activityworkshop.net/</code> pour plus de d\u00e9tails et des manuels utilisateur.
+dialog.about.summarytext3=Consultez la page <code style``=``"font-weight:bold">http://activityworkshop.net/</code> pour plus de d\u00e9tails et des manuels utilisateur.
dialog.about.languages=Langues disponibles
dialog.about.translatedby=Texte en fran\u00e7ais par Petrovsk et theYinYeti.
dialog.about.systeminfo=Info Syst\u00e8me
dialog.saveconfig.prune.trackdirectory=Dossier des traces
dialog.saveconfig.prune.photodirectory=Dossier des Photos
dialog.saveconfig.prune.languagecode=Code langue (FR)
+dialog.saveconfig.prune.languagefile=Fichier de langue
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.showpace=Montrer l'allure
dialog.saveconfig.prune.kmzimagewidth=Largeur de l'image KMZ
dialog.saveconfig.prune.kmzimageheight=Hauteur de l'image KMZ
+dialog.saveconfig.prune.colourscheme=Mod\u00e8le de couleurs
+dialog.saveconfig.prune.kmltrackcolour=Couleur de la trace KML
dialog.setpaths.intro=Si vous le souhaitez, vous pouvez d\u00e9finir les chemins des applications externes:
dialog.addaltitude.noaltitudes=L'\u00e9tendue s\u00e9lectionn\u00e9e de contient pas d'altitudes
dialog.addaltitude.desc=D\u00e9callage d'altitude \u00e0 ajouter
+dialog.setcolours.intro=Cliquez sur une couleur pour la changer
+dialog.setcolours.background=Arri\u00e8re-plan
+dialog.setcolours.borders=Bordures
+dialog.setcolours.lines=Lignes
+dialog.setcolours.primary=Primaires
+dialog.setcolours.secondary=Secondaires
+dialog.setcolours.point=Points
+dialog.setcolours.selection=S\u00e9lection
+dialog.setcolours.text=Texte
+dialog.colourchooser.title=Choisissez la couleur
+dialog.colourchooser.red=Rouge
+dialog.colourchooser.green=Vert
+dialog.colourchooser.blue=Bleu
+dialog.setlanguage.language=Langue
+dialog.setlanguage.languagefile=Fichier de langue
# 3d window
dialog.3d.title=Vue 3D de Prune
confirm.addtimeoffset=D\u00e9calage ajout\u00e9
confirm.addaltitudeoffset=D\u00e9calage d'altitude ajout\u00e9
confirm.rearrangewaypoints=Waypoints r\u00e9arrang\u00e9s
+confirm.rearrangephotos=Photos r\u00e9arrang\u00e9es
confirm.cutandmove=S\u00e9lection d\u00e9plac\u00e9e
+confirm.convertnamestotimes=Noms de waypoints convertis
confirm.saveexif.ok1=Enregistrement de
confirm.saveexif.ok2=fichiers photo
confirm.undo.single=op\u00e9ration annul\u00e9e
confirm.correlate.single=photo a \u00e9t\u00e9 corr\u00e9l\u00e9e
confirm.correlate.multi=photos ont \u00e9t\u00e9 corr\u00e9l\u00e9es
confirm.createpoint=Point cr\u00e9\u00e9
+confirm.rotatephoto=Photo tourn\u00e9e
confirm.running=En cours...
-# Buttons
+# Buttons || These are all the texts for buttons
button.ok=OK
button.back=Retour
button.next=Prochain
button.no=Non
button.yestoall=Oui pour tous
button.notoall=Non pour tous
+button.select=S\u00e9lectionner
button.selectall=Tout s\u00e9lectionner
button.selectnone=Ne rien s\u00e9lectionner
button.preview=Aper\u00e7u
button.guessfields=Deviner les champs
button.showwebpage=Montrer page web
button.check=V\u00e9rifier
+button.resettodefaults=Revenir aux valeurs par d\u00e9faut
# File types
filetype.txt=Fichiers TXT
filetype.pov=Fichiers POV
filetype.svg=Fichiers SVG
-# Display components
+# Display components || These are all for the side panels showing point/range details
display.nodata=Pas de donn\u00e9es charg\u00e9es
display.noaltitudes=La trace ne comporte pas d'information d'altitude
details.trackdetails=D\u00e9tails de la trace
display.range.time.days=j
details.range.avespeed=Vitesse moyenne
details.range.avemovingspeed=Moyenne continue
+details.range.numsegments=Nombre de segments
details.range.pace=Allure
+details.range.gradient=Pente
details.waypointsphotos.waypoints=Waypoints
details.waypointsphotos.photos=Photos
details.photodetails=D\u00e9tails de la photo
cardinal.e=E
cardinal.w=O
-# Undo operations
+# Undo operations || These will be displayed in the undo list after you've performed the operation, to tell you what you did
undo.load=charger les donn\u00e9es
undo.loadphotos=charger les photos
undo.editpoint=\u00e9diter le point
undo.connectphoto=relier la photo
undo.disconnectphoto=d\u00e9tacher la photo
undo.correlate=corr\u00e9ler les photos
+undo.rearrangephotos=R\u00e9arranger les photos
undo.createpoint=ajouter un point
+undo.rotatephoto=Tourner la photo
+undo.convertnamestotimes=Convertir les noms en points
# Error messages
error.save.dialogtitle=Erreur \u00e0 l'enregistrement des donn\u00e9es
error.saveexif.filenotfound=Fichier photo introuvable
error.saveexif.cannotoverwrite1=Le fichier photo
error.saveexif.cannotoverwrite2=est en lecture seule et ne peut pas \u00eatre \u00e9craser. Enregistrer sur une copie ?
+error.saveexif.failed1=\u00c9chec de la sauvegarde de
+error.saveexif.failed2=images
+error.saveexif.forced1=Enregistrement forc\u00e9 pour
+error.saveexif.forced2=images
error.load.dialogtitle=Erreur au chargement des donn\u00e9es
error.load.noread=Fichier illisible
error.load.nopoints=Aucune coordonn\u00e9e trouv\u00e9e dans le fichier
error.jpegload.nojpegsfound=Aucun fichier jpeg trouv\u00e9
error.jpegload.noexiffound=Aucune information EXIF trouv\u00e9e
error.jpegload.nogpsfound=Aucune information GPS trouv\u00e9e
+error.gpsload.unknown=Erreur inconnue
error.undofailed.title=Echec de l'annulation
error.undofailed.text=Echec de l'op\u00e9ration d'annulation
error.function.noop.title=Fonction sans effet
-error.rearrange.noop=R\u00e9arrangement des waypoints sans effet
+error.rearrange.noop=R\u00e9arrangement des points sans effet
error.function.notavailable.title=Function non-disponible
error.function.nojava3d=Cette fonction n\u00e9cessite la librairie Java3d,\ndisponible sur Sun.com.
error.3d=Un probl\u00e8me est survenu avec l'affichage 3D
menu.file.addphotos=Muat foto
menu.file.save=Simpan
menu.file.exit=Keluar
-menu.edit=Ubah
+#menu.edit=Ubah
+menu.track=Track
menu.edit.undo=Batal
menu.edit.editpoint=Perbaiki titik
menu.edit.deletepoint=Hapus titik
menu.edit.deleterange=Hapus jarak
-menu.select=Pilih
+#menu.select=Pilih
+menu.range=Jangkauan
+menu.point=Titik
menu.select.all=Pilih semua
menu.select.none=Tidak memilih
menu.photo=Foto
# Alt keys for menus
altkey.menu.file=B
-altkey.menu.edit=U
-altkey.menu.select=P
+#altkey.menu.edit=U
+#altkey.menu.select=P
+altkey.menu.track=T
+altkey.menu.range=J
+altkey.menu.point=K
altkey.menu.view=L
altkey.menu.photo=F
altkey.menu.settings=G
button.close=Tutup
button.yes=Ya
button.no=Tidak
+button.select=Pilih
button.guessfields=Deteksi otomatis
# File types
menu.file.save=Salva
menu.file.exit=Esci
menu.edit=Edita
+menu.track=Traccia
menu.edit.undo=Annulla
menu.edit.clearundo=Cancella lista ultime modifiche
menu.edit.editpoint=Edita punto
menu.edit.rearrange.nearest=Sul punto pi\u00f9 vicino
menu.edit.cutandmove=Taglia e muovi la selezione
menu.select=Seleziona
+menu.range=Serie
+menu.point=Punto
menu.select.all=Seleziona tutto
menu.select.none=Deseleziona tutto
menu.select.start=Imposta inizio serie
menu.view.browser.openstreetmap=Openstreetmap
menu.view.browser.mapquest=Mapquest
menu.view.browser.yahoo=mappe Yahoo
+menu.view.browser.bing=mappe Bing
menu.settings=Preferenze
-menu.settings.showpace=
+menu.settings.showpace=Mostra passo nel display serie
menu.help=Aiuto
# Popup menu for map
menu.map.zoomin=Zoom +
menu.map.connect=Aggancia ai punti
menu.map.autopan=Autopan
menu.map.showmap=Mostra sulla mappa
-menu.map.showscalebar=
+menu.map.showscalebar=Mostra scala
# Alt keys for menus
altkey.menu.file=F
altkey.menu.edit=E
altkey.menu.select=S
+altkey.menu.track=T
+altkey.menu.range=S
+altkey.menu.point=P
altkey.menu.view=V
altkey.menu.photo=O
-altkey.menu.settings=P
+altkey.menu.settings=R
altkey.menu.help=A
# Ctrl shortcuts for menu items
function.editwaypointname=Edita nome waypoint
function.compress=Comprimi la traccia
function.addtimeoffset=Aggiungi uno scarto temporale
-function.addaltitudeoffset=
-function.findwaypoint=
+function.addaltitudeoffset=Aggiungi uno scarto di altitudine
+function.findwaypoint=Trova waypoint
function.charts=Diagrammi
function.show3d=Mostra in 3D
function.distances=Mostra distanze
-function.getgpsies=
-function.correlatephotos=Correla le foto
function.setmapbg=Configura sfondo mappa
-function.setkmzimagesize=
-function.setpaths=
+function.setkmzimagesize=Configura dimensione immagine KMZ
+function.setpaths=Configura percorsi programmi
+function.getgpsies=Ottieni traccie da Gpsies
+function.correlatephotos=Correla le foto
function.help=Aiuto
-function.showkeys=
+function.showkeys=Visualizza tasti scelta rapida
function.about=Informazioni su Prune
function.checkversion=Controlla gli aggiornamenti
-function.saveconfig=
+function.saveconfig=Salva configurazione
# Dialogs
dialog.exit.confirm.title=Esci da Prune
dialog.exportpov.ballsandsticks=Palle e bacchette
dialog.exportpov.tubesandwalls=Tubi e pareti
dialog.exportpov.warningtracksize=Questa traccia ha un elevato numero di punti, e Java3D pu\u00f2 non essere in grado di visualizzarli.\nSei sicuro di voler continuare?
-dialog.pointtype.desc=
-dialog.pointtype.track=
-dialog.pointtype.waypoint=
-dialog.pointtype.photo=
+dialog.pointtype.desc=Salva i tipi di punti seguenti:
+dialog.pointtype.track=Punti traccia
+dialog.pointtype.waypoint=Waypoints
+dialog.pointtype.photo=Punti foto
dialog.confirmreversetrack.title=Conferma l'inversione
dialog.confirmreversetrack.text=Questa traccia contiene informazioni sull'orario di scatto che possono essere messe fuori sequenza dopo l'inversione.\nSei sicuro di voler invertire questa sezione?
dialog.confirmcutandmove.title=Conferma il taglio e lo spostamento
dialog.addtimeoffset.hours=Ore
dialog.addtimeoffset.minutes=Minuti
dialog.addtimeoffset.notimestamps=Non posso aggiungere uno scarto temporale a questa selezione perch\u00e9 non contiene informazioni temporali
-dialog.findwaypoint.intro=
-dialog.findwaypoint.search=
+dialog.findwaypoint.intro=Inserisci parte del nome del waypoint
+dialog.findwaypoint.search=Cerca
dialog.connect.title=Collega la foto al punto
dialog.connectphoto.clonepoint=Questo punto ha gi\u00e0 una foto collegata.\nVuoi fare una copia del punto?
dialog.saveexif.title=Salva Exif
dialog.charts.svgwidth=larghezza SVG
dialog.charts.svgheight=altezza SVG
dialog.charts.needaltitudeortimes=La traccia necessita di dati altitudine o tempo per creare diagrammi
-dialog.charts.gnuplotpath=Path gnuplot
dialog.charts.gnuplotnotfound=Gnuplot non trovato nel path indicato
dialog.distances.intro=Distanze dirette tra punti
dialog.distances.column.from=Dal punto
dialog.setmapbg.cyclemap=Mappa ciclistica
dialog.setmapbg.other=Altro
dialog.setmapbg.server=URL server
-dialog.gpsies.column.name=
-dialog.gpsies.column.length=
-dialog.gpsies.description=
-dialog.gpsies.nodescription=
-dialog.gpsies.nonefound=
+dialog.gpsies.column.name=Nome traccia
+dialog.gpsies.column.length=Lunghezza
+dialog.gpsies.description=Descrizione
+dialog.gpsies.nodescription=Senza descrizione
dialog.correlate.notimestamps=Non ci sono informazioni temporali tra i dati dei punti, non c'\u00e8 niente per collegarli con le foto.
dialog.correlate.nouncorrelatedphotos=Non ci sono foto non correlate.\nSei sicuro di voler continuare?
dialog.correlate.photoselect.intro=Selezione una delle foto correlate da usare come scarto dell'orario
dialog.correlate.options.correlate=Correlate
dialog.correlate.alloutsiderange=Tutte le foto sono fuori dall'orario della traccia, e nessuna pu\u00f2 essere correlata.\nProva a cambiare lo scarto o correla manualmente almeno una foto.
dialog.compress.nonefound=Nessun punto rimosso
-dialog.compress.duplicates.title=Cancella duplicati
dialog.compress.closepoints.title=Cancella punti vicini
dialog.compress.closepoints.paramdesc=Fattore vicinanza
dialog.compress.wackypoints.title=Cancella punti strani
dialog.compress.wackypoints.paramdesc=Fattore distanza
dialog.compress.singletons.title=Cancella solitari
dialog.compress.singletons.paramdesc=Fattore distanza
+dialog.compress.duplicates.title=Cancella duplicati
dialog.compress.summarylabel=Punti da cancellare
dialog.help.help=Per favore vedi\n http://activityworkshop.net/software/prune/\nper maggiori informazioni e per la guida utente.
dialog.about.version=Versione
dialog.checkversion.releasedate1=Questa nuova versione \u00e8 stata rilasciata il
dialog.checkversion.releasedate2=.
dialog.checkversion.download=Per scaricare la nuova versione vai a http://activityworkshop.net/software/prune/download.html.
-dialog.keys.intro=
-dialog.keys.keylist=
-dialog.saveconfig.desc=
-dialog.saveconfig.prune.trackdirectory=
-dialog.saveconfig.prune.photodirectory=
-dialog.saveconfig.prune.languagecode=
+dialog.keys.intro=Puoi utilizzare i seguenti tast di scelta rapida al posto del mouse
+dialog.keys.keylist=<table><tr><td>Tasti freccia</td><td>Muovi mappa destra, sinistra, su, giu'</td></tr><tr><td>Ctrl + freccia destra, sinistra</td><td>Selezione punto successivo o precedente</td></tr><tr><td>Ctrl + freccia su, giu'</td><td>Zoom in o out</td></tr><tr><td>Del</td><td>Cancella punto attuale</td></tr></table>
+dialog.saveconfig.desc=Le configurazioni seguenti possono essere salvati in un file di configurazione:
+dialog.saveconfig.prune.trackdirectory=Cartella traccie
+dialog.saveconfig.prune.photodirectory=Cartella foto
+dialog.saveconfig.prune.languagecode=Codice linguaggio (EN)
dialog.saveconfig.prune.gpsdevice=Nome del Dispositivo GPS
dialog.saveconfig.prune.gpsformat=Formato GPS
dialog.saveconfig.prune.povrayfont=Font povray
-dialog.saveconfig.prune.metricunits=
+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.saveconfig.prune.mapserverindex=
-dialog.saveconfig.prune.mapserverurl=
-dialog.saveconfig.prune.showpace=
-dialog.saveconfig.prune.kmzimagewidth=
-dialog.saveconfig.prune.kmzimageheight=
-dialog.setpaths.intro=
-dialog.addaltitude.noaltitudes=
-dialog.addaltitude.desc=
+dialog.saveconfig.prune.mapserverindex=Indice server mappe
+dialog.saveconfig.prune.mapserverurl=URL del server mappe
+dialog.saveconfig.prune.showpace=Mostra passo
+dialog.saveconfig.prune.kmzimagewidth=larghezza immagine KMZ
+dialog.saveconfig.prune.kmzimageheight=altezza immagine KMZ
+dialog.setpaths.intro=Se necessario, puoi indicare il percorso delle applicazioni esterne:
+dialog.addaltitude.noaltitudes=L'intervallo selezionato non contiene altitudini
+dialog.addaltitude.desc=Scarto altitudine da aggiungere
# 3d window
dialog.3d.title=Visione Prune in 3D
-dialog.3d.altitudecap=Minimo intervallo si altitudine
+dialog.3d.altitudecap=Intervallo altitudine minimo
dialog.3dlines.title=Griglia di Prune
dialog.3dlines.empty=Nessuna griglia mostrata!
dialog.3dlines.intro=Queste sono le linee della griglia per la visione 3D
confirm.mergetracksegments=segmeni di traccia uniti
confirm.reverserange=Intervallo invertito
confirm.addtimeoffset=Scarto temporale aggiunto
-confirm.addaltitudeoffset=
+confirm.addaltitudeoffset=Scarto altitudine aggiunto
confirm.rearrangewaypoints=Waypoint riorganizzati
confirm.cutandmove=Selezione spostata
confirm.saveexif.ok1=Salvato
confirm.correlate.single=foto era correlata
confirm.correlate.multi=foto erano correlate
confirm.createpoint=punto creato
-confirm.running=
+confirm.running=Operazione in corso...
-# Buttons
+# Buttons || These are all the texts for buttons
button.ok=OK
button.back=Precedente
button.next=Prossimo
button.no=No
button.yestoall=Si a tutto
button.notoall=No a tutto
+button.select=Seleziona
button.selectall=Seleziona tutto
button.selectnone=Deseleziona tutto
button.preview=Anteprima
button.load=Carica
button.guessfields=Campi soluzione
button.showwebpage=Mostra pagina
-button.check=
+button.check=Controlla
# File types
filetype.txt=File TXT
filetype.pov=File POV
filetype.svg=File SVG
-# Display components
+# Display components || These are all for the side panels showing point/range details
display.nodata=Nessun dato caricato
display.noaltitudes=I dati della traccia non includono l'altitudine
details.trackdetails=Dettagli della traccia
display.range.time.days=g
details.range.avespeed=Velocit\u00e0 media
details.range.avemovingspeed=Velocit\u00e0 media in movimento
-details.range.pace=
+details.range.pace=Passo
details.waypointsphotos.waypoints=Waypoint
details.waypointsphotos.photos=Foto
details.photodetails=Dettagli foto
cardinal.e=E
cardinal.w=O
-# Undo operations
+# Undo operations || These will be displayed in the undo list after you've performed the operation, to tell you what you did
undo.load=carica dati
undo.loadphotos=carica foto
undo.editpoint=edita punto
undo.reverse=inverti l'intervallo
undo.mergetracksegments=unisci segmenti traccia
undo.addtimeoffset=aggiungi scarto temporale
-undo.addaltitudeoffset=
+undo.addaltitudeoffset=aggiungi scarto altitudine
undo.rearrangewaypoints=riorganizza waypoint
undo.cutandmove=muovi selezione
undo.connectphoto=collega foto
error.3d=\u00c8 avvenuto un errore nella visualizzazione 3D
error.readme.notfound=Non ho trovato il file Leggimi
error.osmimage.dialogtitle=Errore nel caricamento nelle immagini della mappa
-error.osmimage.failed=Impossibile caricare le immagini della mappa. Per favore verifica la connessione a internet.
\ No newline at end of file
+error.osmimage.failed=Impossibile caricare le immagini della mappa. Per favore verifica la connessione a internet.
--- /dev/null
+# Text entries for the Prune application
+# Japanese entries as extra
+
+# Menu entries
+menu.file=\u30d5\u30a1\u30a4\u30eb
+menu.file.open=\u30d5\u30a1\u30a4\u30eb\u3092\u958b\u304f
+menu.file.addphotos=\u5199\u771f\u3092\u8ffd\u52a0
+menu.file.save=\u4fdd\u5b58
+menu.file.exit=\u7d42\u4e86
+menu.edit=\u7de8\u96c6
+menu.track=\u30c8\u30e9\u30c3\u30af
+menu.edit.undo=\u30a2\u30f3\u30c9\u30a5
+menu.edit.clearundo=\u30a2\u30f3\u30c9\u30a5\u30ea\u30b9\u30c8\u3092\u7a7a\u306b\u3059\u308b
+menu.edit.editpoint=\u70b9\u3092\u7de8\u96c6
+menu.edit.deletepoint=\u70b9\u3092\u524a\u9664
+menu.edit.deleterange=\u7bc4\u56f2\u3092\u524a\u9664
+menu.edit.deletemarked=\u5370\u306e\u4ed8\u3044\u305f\u70b9\u3092\u524a\u9664
+menu.edit.interpolate=\u88dc\u5b8c
+menu.edit.average=\u9078\u629e\u7bc4\u56f2\u3092\u5e73\u5747\u5316
+menu.edit.reverse=\u7bc4\u56f2\u3092\u53cd\u8ee2
+menu.edit.mergetracksegments=\u30c8\u30e9\u30c3\u30af\u30bb\u30b0\u30e1\u30f3\u30c8\u3092\u7d71\u5408
+menu.edit.rearrange=\u30a6\u30a7\u30a4\u30dd\u30a4\u30f3\u30c8\u3092\u4e26\u3079\u66ff\u3048
+menu.edit.rearrange.start=\u5168\u3066\u3092\u30d5\u30a1\u30a4\u30eb\u306e\u59cb\u70b9\u306b
+menu.edit.rearrange.end=\u5168\u3066\u3092\u30d5\u30a1\u30a4\u30eb\u306e\u7d42\u70b9\u306b
+menu.edit.rearrange.nearest=\u305d\u308c\u305e\u308c\u3092\u6700\u8fd1\u306e\u30c8\u30e9\u30c3\u30af\u30dd\u30a4\u30f3\u30c8\u306b
+menu.edit.cutandmove=\u9078\u629e\u7bc4\u56f2\u3092\u79fb\u52d5
+menu.select=\u9078\u629e
+menu.range=\u7bc4\u56f2
+menu.point=\u70b9
+menu.select.all=\u5168\u3066\u9078\u629e
+menu.select.none=\u9078\u629e\u89e3\u9664
+menu.select.start=\u958b\u59cb\u70b9\u3092\u7f6e\u304f
+menu.select.end=\u7d42\u4e86\u70b9\u3092\u7f6e\u304f
+menu.photo=\u5199\u771f
+menu.photo.saveexif=Exif\u306b\u4fdd\u5b58
+menu.photo.connect=\u70b9\u306b\u63a5\u7d9a
+menu.photo.disconnect=\u70b9\u304b\u3089\u63a5\u7d9a\u89e3\u9664
+menu.photo.delete=\u5199\u771f\u3092\u53d6\u308a\u9664\u304f
+menu.view=\u30d3\u30e5\u30fc
+menu.view.browser=\u5730\u56f3\u3092\u30d6\u30e9\u30a6\u30b6\u30fc\u3067\u898b\u308b
+menu.view.browser.google=Google \u30de\u30c3\u30d7
+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.settings.showpace=\u8868\u793a\u7bc4\u56f2\u306e\u901f\u5ea6\u3092\u8868\u793a
+menu.help=\u30d8\u30eb\u30d7
+# 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.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
+menu.map.showscalebar=\u7e2e\u5c3a\u8868\u793a
+
+# Functions
+function.loadfromgps=GPS\u304b\u3089\u30c7\u30fc\u30bf\u3092\u8aad\u3080
+function.sendtogps=GPS\u3078\u4fdd\u5b58
+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.editwaypointname=\u30a6\u30a7\u30a4\u30dd\u30a4\u30f3\u30c8\u306e\u540d\u524d\u3092\u7de8\u96c6
+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.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.show3d=3-D\u30d3\u30e5\u30fc
+function.distances=\u8ddd\u96e2
+function.fullrangedetails=\u5168\u7bc4\u56f2\u8a73\u7d30
+function.setmapbg=\u80cc\u666f\u5730\u56f3
+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.duplicatepoint=\u91cd\u8907\u70b9
+function.setcolours=\u8272\u3092\u8a2d\u5b9a
+function.setlanguage=\u8a00\u8a9e\u8a2d\u5b9a
+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.ignoreexifthumb=EXIF\u30b5\u30e0\u30cd\u30a4\u30eb\u3092\u7121\u8996
+function.help=\u30d8\u30eb\u30d7
+function.showkeys=\u30b7\u30e7\u30fc\u30c8\u30ab\u30c3\u30c8\u30ad\u30fc\u3092\u8868\u793a
+function.about=Prune \u306b\u3064\u3044\u3066
+function.checkversion=\u65b0\u3057\u3044\u30d0\u30fc\u30b8\u30e7\u30f3\u3092\u8868\u793a
+function.saveconfig=\u8a2d\u5b9a\u3092\u4fdd\u5b58
+
+# Dialogs
+dialog.exit.confirm.title=Prune \u3092\u7d42\u4e86
+dialog.exit.confirm.text=\u30c7\u30fc\u30bf\u306f\u4fdd\u5b58\u3055\u308c\u3066\u3044\u307e\u305b\u3093\u3002\u672c\u5f53\u306b\u7d42\u4e86\u3057\u307e\u3059\u304b\uff1f
+dialog.openappend.title=\u65e2\u5b58\u306e\u30c7\u30fc\u30bf\u3092\u52a0\u3048\u308b
+dialog.openappend.text=\u3053\u306e\u30c7\u30fc\u30bf\u306b\u65e2\u5b58\u306e\u30c7\u30fc\u30bf\u30fc\u3092\u8aad\u307f\u8fbc\u3080\u3002
+dialog.deletepoint.title=\u70b9\u3092\u524a\u9664
+dialog.deletepoint.deletephoto=\u3053\u306e\u70b9\u63a5\u7d9a\u3055\u308c\u3066\u3044\u308b\u5199\u771f\u3092\u53d6\u308a\u9664\u304d\u307e\u3059\u304b\uff1f
+dialog.deletephoto.title=\u5199\u771f\u3092\u524a\u9664
+dialog.deletephoto.deletepoint=\u3053\u306e\u5199\u771f\u306b\u63a5\u7d9a\u3055\u308c\u3066\u3044\u308b\u5199\u771f\u3092\u53d6\u308a\u9664\u304d\u307e\u3059\u304b\uff1f
+dialog.openoptions.title=\u30aa\u30d7\u30b7\u30e7\u30f3\u3092\u958b\u304f
+dialog.openoptions.filesnippet=\u30d5\u30a1\u30a4\u30eb\u3092\u5c55\u958b
+dialog.load.table.field=\u30d5\u30a3\u30fc\u30eb\u30c9
+dialog.load.table.datatype=\u30c7\u30fc\u30bf\u30bf\u30a4\u30d7
+dialog.load.table.description=\u8a18\u8ff0
+dialog.delimiter.label=\u30d5\u30a3\u30fc\u30eb\u30c9\u533a\u5207\u308a
+dialog.delimiter.comma=\u30b3\u30f3\u30de ,
+dialog.delimiter.tab=\u30bf\u30d6
+dialog.delimiter.space=\u30b9\u30da\u30fc\u30b9
+dialog.delimiter.semicolon=\u30bb\u30df\u30b3\u30ed\u30f3 ;
+dialog.delimiter.other=\u305d\u306e\u4ed6
+dialog.openoptions.deliminfo.records=\u8a18\u9332\uff0c
+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.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.jpegload.progress.title=\u5199\u771f\u3092\u8aad\u307f\u8fbc\u307f
+dialog.jpegload.progress=\u691c\u7d22\u4e2d\u3067\u3059\u3002\u3057\u3070\u3057\u304a\u5f85\u3061\u304f\u3060\u3055\u3044\u3002
+dialog.gpsload.nogpsbabel=Gpsbabel\u304c\u898b\u3064\u304b\u308a\u307e\u305b\u3093\u3002\u7d9a\u3051\u307e\u3059\u304b\uff1f
+dialog.gpsload.device=GPS\u3068\u7d99\u304c\u3063\u3066\u3044\u308b\u30c7\u30d0\u30a4\u30b9\u540d
+dialog.gpsload.format=GPS \u30c7\u30d0\u30a4\u30b9\u306e\u30d5\u30a9\u30fc\u30de\u30c3\u30c8
+dialog.gpsload.getwaypoints=\u30a6\u30a7\u30a4\u30dd\u30a4\u30f3\u30c8\u3092\u8aad\u307f\u8fbc\u3080
+dialog.gpsload.gettracks=\u30c8\u30e9\u30c3\u30af\u3092\u8aad\u307f\u8fbc\u3080
+dialog.gpsload.save=\u30d5\u30a1\u30a4\u30eb\u306b\u4fdd\u5b58
+dialog.gpssend.sendwaypoints=\u30a6\u30a7\u30a4\u30dd\u30a4\u30f3\u30c8\u3092\u9001\u308b
+dialog.gpssend.sendtracks=\u30c8\u30e9\u30c3\u30af\u3092\u9001\u308b
+dialog.gpssend.trackname=\u30c8\u30e9\u30c3\u30af\u540d
+dialog.saveoptions.title=\u4fdd\u5b58
+dialog.save.fieldstosave=\u30d5\u30a3\u30fc\u30eb\u30c9\u306b\u4fdd\u5b58
+dialog.save.table.field=\u30d5\u30a3\u30fc\u30eb\u30c9
+dialog.save.table.hasdata=\u30c7\u30fc\u30bf\u304c\u3042\u308b
+dialog.save.table.save=\u4fdd\u5b58
+dialog.save.headerrow=\u30d8\u30c3\u30c0\u30fc\u884c\u3092\u51fa\u529b
+dialog.save.coordinateunits=\u5ea7\u6a19\u5358\u4f4d
+dialog.save.altitudeunits=\u9ad8\u5ea6\u5358\u4f4d
+dialog.save.timestampformat=\u6642\u9593\u8a18\u9332\u30d5\u30a9\u30fc\u30de\u30c3\u30c8
+dialog.save.overwrite.title=\u30d5\u30a1\u30a4\u30eb\u304c\u65e2\u306b\u5b58\u5728\u3057\u307e\u3059\u3002
+dialog.save.overwrite.text=\u30d5\u30a1\u30a4\u30eb\u304c\u65e2\u306b\u5b58\u5728\u3057\u307e\u3059\u3002\u4e0a\u66f8\u304d\u3057\u307e\u3059\u304b\uff1f
+dialog.save.notypesselected=\u70b9\u306e\u7a2e\u985e\u304c\u9078\u629e\u3055\u308c\u3066\u3044\u307e\u305b\u3093\u3002
+dialog.exportkml.text=\u30c7\u30fc\u30bf\u306e\u30bf\u30a4\u30c8\u30eb
+dialog.exportkml.altitude=\u7d76\u5bfe\u9ad8\u5ea6\uff08\u822a\u7a7a\u7528\uff09
+dialog.exportkml.kmz=KMZ\u30d5\u30a1\u30a4\u30eb\u3092\u5727\u7e2e
+dialog.exportkml.exportimages=KMZ\u3078\u753b\u50cf\u306e\u7e2e\u5c0f\u7248\u3092\u4fdd\u5b58
+dialog.exportkml.trackcolour=\u30c8\u30e9\u30c3\u30af\u306e\u8272
+dialog.exportgpx.name=\u540d\u524d
+dialog.exportgpx.desc=\u8a18\u8ff0
+dialog.exportgpx.includetimestamps=\u6642\u9593\u8a18\u9332\u3092\u542b\u3080
+dialog.exportgpx.copysource=XML\u30bd\u30fc\u30b9\u3092\u30b3\u30d4\u30fc
+dialog.exportpov.text=POV\u7528\u30d1\u30e9\u30e1\u30fc\u30bf\u3092\u5165\u529b\u3057\u3066\u304f\u3060\u3055\u3044\u3002
+dialog.exportpov.font=\u30d5\u30a9\u30f3\u30c8
+dialog.exportpov.camerax=\u30ab\u30e1\u30e9 X
+dialog.exportpov.cameray=\u30ab\u30e1\u30e9 Y
+dialog.exportpov.cameraz=\u30ab\u30e1\u30e9 Z
+dialog.exportpov.modelstyle=\u30e2\u30c7\u30eb\u30b9\u30bf\u30a4\u30eb
+dialog.exportpov.ballsandsticks=\u7403\u3068\u68d2
+dialog.exportpov.tubesandwalls=\u7ba1\u3068\u58c1
+dialog.exportpov.warningtracksize=\u3053\u306e\u30c8\u30e9\u30c3\u30af\u306f\u975e\u5e38\u306b\u591a\u304f\u306e\u70b9\u304c\u3042\u308b\u306e\u3067\u3001Java3D \u3067\u306f\u8868\u793a\u3057\u5207\u308c\u306a\u3044\u3068\u601d\u308f\u308c\u307e\u3059\u3002\n\u7d9a\u3051\u307e\u3059\u304b\uff1f
+dialog.pointtype.desc=\u6b21\u306e\u70b9\u3092\u4fdd\u5b58\u3057\u307e\u3059\uff1a
+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.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.undo.none.title=\u30a2\u30f3\u30c9\u30a5\u3067\u304d\u307e\u305b\u3093
+dialog.undo.none.text=\u30a2\u30f3\u30c9\u30a5\u3067\u304d\u308b\u4f5c\u696d\u753b\u3042\u308a\u307e\u305b\u3093!
+dialog.clearundo.title=\u30a2\u30f3\u30c9\u30a5\u30ea\u30b9\u30c8\u3092\u7a7a\u306b\u3059\u308b
+dialog.clearundo.text=\u672c\u5f53\u306b\u30a2\u30f3\u30c9\u30a5\u30ea\u30b9\u30c8\u3092\u7a7a\u306b\u3057\u307e\u3059\u304b?\n\u5168\u3066\u306e\u30a2\u30f3\u30c9\u30a5\u60c5\u5831\u304c\u5931\u308f\u308c\u307e\u3059\u3002
+dialog.pointedit.title=\u70b9\u3092\u7de8\u96c6
+dialog.pointedit.text=\u7de8\u96c6\u3059\u308b\u30d5\u30a3\u30fc\u30eb\u30c9\u3092\u9078\u629e\u3057\u3001'\u7de8\u96c6' \u30dc\u30bf\u30f3\u3067\u5024\u3092\u7de8\u96c6\u3057\u3066\u304f\u3060\u3055\u3044\u3002
+dialog.pointedit.table.field=\u30d5\u30a3\u30fc\u30eb\u30c9
+dialog.pointedit.table.value=\u503c
+dialog.pointedit.table.changed=\u5909\u66f4\u6e08
+dialog.pointedit.changevalue.text=\u65b0\u3057\u3044\u5024\u3092\u30d5\u30a3\u30fc\u30eb\u30c9\u306b\u5165\u308c\u3066\u304f\u3060\u3055\u3044\u3002
+dialog.pointedit.changevalue.title=\u30d5\u30a3\u30fc\u30eb\u30c9\u306e\u7de8\u96c6
+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.addtimeoffset.add=\u6642\u9593\u3092\u8db3\u3059
+dialog.addtimeoffset.subtract=\u6642\u9593\u3092\u5f15\u304f
+dialog.addtimeoffset.days=\u65e5
+dialog.addtimeoffset.hours=\u6642\u9593
+dialog.addtimeoffset.minutes=\u5206
+dialog.addtimeoffset.notimestamps=\u3053\u306e\u9078\u629e\u7bc4\u56f2\u306f\u30bf\u30a4\u30e0\u30b9\u30bf\u30f3\u30d7\u3092\u6301\u3063\u3066\u306a\u3044\u306e\u3067\u3001\u504f\u4f4d\u3092\u8db3\u305b\u307e\u305b\u3093\u3002
+dialog.findwaypoint.intro=\u30a6\u30a7\u30a4\u30dd\u30a4\u30f3\u30c8\u540d\u306e\u4e00\u90e8\u3092\u5165\u529b
+dialog.findwaypoint.search=\u691c\u7d22
+dialog.connect.title=\u70b9\u306b\u5199\u771f\u3092\u63a5\u7d9a
+dialog.connectphoto.clonepoint=\u3053\u306e\u70b9\u306f\u65e2\u306b\u5199\u771f\u3092\u6301\u3063\u3066\u307e\u3059\u3002\n\u30a6\u30a7\u30a4\u30dd\u30a4\u30f3\u30c8\u3092\u30b3\u30d4\u30fc\u3057\u307e\u3059\u304b\uff1f
+dialog.saveexif.title=EXIF\u3092\u4fdd\u5b58
+dialog.saveexif.intro=\u30c1\u30a7\u30c3\u30af\u30dc\u30c3\u30af\u30b9\u3092\u4f7f\u3063\u3066\u3001\u4fdd\u5b58\u3059\u308b\u5199\u771f\u3092\u9078\u629e\u3057\u3066\u304f\u3060\u3055\u3044\u3002
+dialog.saveexif.nothingtosave=\u5ea7\u6a19\u60c5\u5831\u306f\u7121\u5909\u66f4\u3067\u3059\u3002\u4fdd\u5b58\u3059\u308b\u3082\u306e\u306f\u3042\u308a\u307e\u305b\u3093\u3002
+dialog.saveexif.noexiftool=exiftool \u30d7\u30ed\u30b0\u30e9\u30e0\u304c\u898b\u3064\u304b\u308a\u307e\u305b\u3093\u3002\u7d9a\u3051\u307e\u3059\u304b\uff1f
+dialog.saveexif.table.photoname=\u5199\u771f\u540d
+dialog.saveexif.table.status=\u72b6\u614b
+dialog.saveexif.table.save=\u4fdd\u5b58
+dialog.saveexif.photostatus.connected=\u63a5\u7d9a\u6e08
+dialog.saveexif.photostatus.disconnected=\u672a\u63a5\u7d9a
+dialog.saveexif.photostatus.modified=\u6539\u5909\u6e08
+dialog.saveexif.overwrite=\u30d5\u30a1\u30a4\u30eb\u306e\u4e0a\u66f8\u304d
+dialog.saveexif.force=\u5c0f\u3055\u306a\u8aa4\u5dee\u3092\u7121\u8996\u3057\u3066\u5f37\u884c
+dialog.charts.xaxis=X\u8ef8
+dialog.charts.yaxis=Y\u8ef8
+dialog.charts.output=\u51fa\u529b
+dialog.charts.screen=\u753b\u9762\u3078\u51fa\u529b
+dialog.charts.svg=SVG\u30d5\u30a1\u30a4\u30eb\u306b\u51fa\u529b
+dialog.charts.svgwidth=SVG\u5e45
+dialog.charts.svgheight=SVG\u9ad8
+dialog.charts.needaltitudeortimes=\u30c1\u30e3\u30fc\u30c8\u3092\u4f5c\u308b\u306b\u306f\u3001\u9ad8\u5ea6\u306e\u60c5\u5831\u304b\u3001\u6642\u9593\u306e\u60c5\u5831\u304c\u30c8\u30e9\u30c3\u30af\u306b\u306a\u3051\u308c\u3070\u3044\u3051\u307e\u305b\u3093\u3002
+dialog.charts.gnuplotnotfound=gnuplot\u304c\u6307\u5b9a\u3055\u308c\u305f\u30d1\u30b9\u306b\u3042\u308a\u307e\u305b\u3093\u3002
+dialog.distances.intro=\u70b9\u9593\u306e\u76f4\u7dda\u8ddd\u96e2
+dialog.distances.column.from=\u958b\u59cb\u70b9
+dialog.distances.column.to=\u7d42\u70b9
+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.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.correlate.notimestamps=\u30c7\u30fc\u30bf\u30dd\u30a4\u30f3\u30c8\u306b\u306f\u30bf\u30a4\u30e0\u30b9\u30bf\u30f3\u30d7\u304c\u306a\u3044\u306e\u3067\u3001\u5199\u771f\u3092\u95a2\u9023\u4ed8\u3051\u3089\u308c\u308b\u7269\u304c\u3042\u308a\u307e\u305b\u3093\u3002
+dialog.correlate.nouncorrelatedphotos=\u95a2\u9023\u4ed8\u3051\u3089\u308c\u306a\u304b\u3063\u305f\u5199\u771f\u306f\u3042\u308a\u307e\u305b\u3093\u3002\n\u7d9a\u3051\u307e\u3059\u304b\uff1f
+dialog.correlate.photoselect.intro=\u6642\u9593\u504f\u4f4d\u3092\u4f5c\u308b\u305f\u3081\u306e\u5199\u771f\u3092\u4e00\u3064\u9078\u3093\u3067\u304f\u3060\u3055\u3044\u3002
+dialog.correlate.photoselect.photoname=\u5199\u771f\u540d
+dialog.correlate.photoselect.timediff=\u6642\u9593\u5dee
+dialog.correlate.photoselect.photolater=\u5199\u771f\u304c\u5f8c
+dialog.correlate.options.tip=\u63d0\u793a\uff1a\u5c11\u306a\u304f\u3068\u3082\u4e00\u3064\u306e\u5199\u771f\u3092\u624b\u52d5\u3067\u95a2\u9023\u4ed8\u3051\u308b\u3068\u3001\u6642\u9593\u504f\u4f4d\u3092\u8a08\u7b97\u3059\u308b\u4e8b\u304c\u3067\u304d\u307e\u3059\u3002
+dialog.correlate.options.intro=\u81ea\u52d5\u95a2\u9023\u4ed8\u3051\u30aa\u30d7\u30b7\u30e7\u30f3\u3092\u9078\u629e\u3057\u3066\u304f\u3060\u3055\u3044\u3002
+dialog.correlate.options.offsetpanel=\u6642\u9593\u504f\u4f4d
+dialog.correlate.options.offset=\u504f\u4f4d
+dialog.correlate.options.offset.hours=\u6642\u9593
+dialog.correlate.options.offset.minutes=\u5206
+dialog.correlate.options.offset.seconds=\u79d2
+dialog.correlate.options.photolater=\u3053\u306e\u70b9\u3088\u308a\u5f8c\u308d\u306e\u5199\u771f
+dialog.correlate.options.pointlater=\u5199\u771f\u3088\u308a\u5f8c\u308d\u306e\u70b9
+dialog.correlate.options.limitspanel=\u95a2\u9023\u4ed8\u3051\u5236\u9650
+dialog.correlate.options.notimelimit=\u6642\u9593\u5236\u9650\u306a\u3057
+dialog.correlate.options.timelimit=\u6642\u9593\u5236\u9650
+dialog.correlate.options.nodistancelimit=\u8ddd\u96e2\u5236\u9650\u306a\u3057
+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.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.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.compress.wackypoints.paramdesc=\u8ddd\u96e2\u4fc2\u6570
+dialog.compress.singletons.title=\u96e2\u6563\u70b9\u306e\u524a\u9664
+dialog.compress.singletons.paramdesc=\u8ddd\u96e2\u4fc2\u6570
+dialog.compress.duplicates.title=\u91cd\u8907\u70b9\u3092\u524a\u9664
+dialog.compress.summarylabel=\u524a\u9664\u3059\u308b\u70b9
+dialog.pastecoordinates.desc=\u5ea7\u6a19\u3092\u3053\u3053\u306b\u5165\u529b\u3059\u308b\u304b\u30da\u30fc\u30b9\u30c8\u3057\u3066\u304f\u3060\u3055\u3044\u3002
+dialog.pastecoordinates.coords=\u5ea7\u6a19
+dialog.pastecoordinates.nothingfound=\u5ea7\u6a19\u306e\u78ba\u8a8d\u3092\u3057\u3066\u3001\u3082\u3046\u4e00\u5ea6\u8a66\u3057\u3066\u304f\u3060\u3055\u3044\u3002
+dialog.help.help=\u8a73\u3057\u3044\u60c5\u5831\u3084\u3001\u30e6\u30fc\u30b6\u30fc\u30ac\u30a4\u30c9\u306a\u3069\u306f\u3001\nhttp://activityworkshop.net/software/prune/ \u3092\u898b\u3066\u304f\u3060\u3055\u3044\u3002
+dialog.about.version=\u30d0\u30fc\u30b8\u30e7\u30f3
+dialog.about.build=Build
+dialog.about.summarytext1=Prune \u306f\u3001GPS\u53d7\u4fe1\u6a5f\u304b\u3089\u306e\u30c7\u30fc\u30bf\u3092\u8aad\u307f\u8fbc\u307f\u3001\u8868\u793a\u3057\u3001\u7de8\u96c6\u3059\u308b\u305f\u3081\u306e\u30d7\u30ed\u30b0\u30e9\u30e0\u3067\u3059\u3002
+dialog.about.summarytext2=\u3053\u308c\u306f\u3001Gnu GPL\u306e\u4e0b\u306b\u516c\u958b\u3055\u308c\u3001\u81ea\u7531\u3067\u3001\u30aa\u30fc\u30d7\u30f3\u3067\u3001\u4e16\u754c\u4e2d\u3067\u3064\u304b\u3048\u3001\u62e1\u5f35\u53ef\u80fd\u3067\u3059\u3002<br><code>"license.txt"</code>\u306b\u304b\u304b\u308c\u3066\u3044\u308b\u6761\u4ef6\u306b\u3088\u308b\u3068\u3001<br>\u8907\u88fd\u30fb\u518d\u914d\u5e03\u30fb\u6539\u5909\u306f\u3001\u8a31\u3055\u308c\u3066\u304a\u308a\u3001\u304b\u3064\u5968\u52b1\u3055\u308c\u3066\u3044\u307e\u3059\u3002
+dialog.about.summarytext3=\u3082\u3063\u3068\u8a73\u3057\u3044\u60c5\u5831\u3084\u30e6\u30fc\u30b6\u30fc\u30ac\u30a4\u30c9\u306a\u3069\u306f\u3001<code style="font-weight:bold">http://activityworkshop.net/</code>\u3092\u898b\u3066\u304f\u3060\u3055\u3044\u3002
+dialog.about.languages=\u5229\u7528\u53ef\u80fd\u306a\u8a00\u8a9e
+dialog.about.translatedby=\u65e5\u672c\u8a9e\u7ffb\u8a33\uff1aOpenStreetMap \u8ca2\u732e\u8005\u306enazotoko
+dialog.about.systeminfo=\u30b7\u30b9\u30c6\u30e0\u60c5\u5831
+dialog.about.systeminfo.os=\u30aa\u30da\u30ec\u30fc\u30c6\u30a3\u30f3\u30b0\u30b7\u30b9\u30c6\u30e0
+dialog.about.systeminfo.java=Java Runtime
+dialog.about.systeminfo.java3d=Java 3D \u30a4\u30f3\u30b9\u30c8\u30fc\u30eb\u6e08
+dialog.about.systeminfo.povray=Povray \u30a4\u30f3\u30b9\u30c8\u30fc\u30eb\u6e08
+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.yes=\u306f\u3044
+dialog.about.no=\u3044\u3044\u3048
+dialog.about.credits=\u30af\u30ec\u30b8\u30c3\u30c8
+dialog.about.credits.code=Prune \u306e\u30b3\u30fc\u30c9\u306e\u4f5c\u8005
+dialog.about.credits.exifcode=Exif \u306e\u30b3\u30fc\u30c9\u306e\u4f5c\u8005
+dialog.about.credits.icons=\u3044\u304f\u3064\u304b\u306e\u30a2\u30a4\u30b3\u30f3
+dialog.about.credits.translators=\u7ffb\u8a33\u8005
+dialog.about.credits.translations=\u7ffb\u8a33\u52a9\u8005
+dialog.about.credits.devtools=\u958b\u767a\u30c4\u30fc\u30eb
+dialog.about.credits.othertools=\u305d\u306e\u4ed6\u30c4\u30fc\u30eb
+dialog.about.credits.thanks=\u611f\u8b1d
+dialog.about.readme=\u521d\u3081\u306b\u8aad\u3093\u3067\u304f\u3060\u3055\u3044
+dialog.checkversion.error=\u30d0\u30fc\u30b8\u30e7\u30f3\u756a\u53f7\u304c\u30c1\u30a7\u30c3\u30af\u3067\u304d\u307e\u305b\u3093\u3002\n\u30a4\u30f3\u30bf\u30fc\u30cd\u30c3\u30c8\u63a5\u7d9a\u306e\u78ba\u8a8d\u3092\u3057\u3066\u304f\u3060\u3055\u3044\u3002
+dialog.checkversion.uptodate=\u3042\u306a\u305f\u306f\u6700\u65b0\u30d0\u30fc\u30b8\u30e7\u30f3\u306ePrune\u3092\u4f7f\u3063\u3066\u3044\u307e\u3059\u3002
+dialog.checkversion.newversion1=\u65b0\u30d0\u30fc\u30b8\u30e7\u30f3\u306e Prune \u304c\u5165\u624b\u53ef\u80fd\u3067\u3059\u3002\u6700\u65b0\u30d0\u30fc\u30b8\u30e7\u30f3\u306f\u73fe\u5728
+dialog.checkversion.newversion2=\u3067\u3059\u3002
+dialog.checkversion.releasedate1=\u65b0\u30d0\u30fc\u30b8\u30e7\u30f3\u306f\u3001
+dialog.checkversion.releasedate2=\u306b\u30ea\u30ea\u30fc\u30b9\u3057\u307e\u3057\u305f\u3002
+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/prune/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.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.languagecode=\u8a00\u8a9e\u30b3\u30fc\u30c9(JA)
+dialog.saveconfig.prune.languagefile=\u8a00\u8a9e\u30d5\u30a1\u30a4\u30eb
+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.showpace=\u30da\u30fc\u30b9\u3092\u8868\u793a
+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.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.addaltitude.desc=\u52a0\u3048\u305f\u9ad8\u5ea6\u504f\u4f4d
+dialog.setcolours.intro=\u8272\u3092\u5909\u3048\u308b\u305f\u3081\u306b\u3001\u8272\u306e\u7bb1\u3092\u30af\u30ea\u30c3\u30af\u3057\u3066\u304f\u3060\u3055\u3044\u3002
+dialog.setcolours.background=\u80cc\u666f
+dialog.setcolours.borders=\u5883\u754c
+dialog.setcolours.lines=\u7dda
+dialog.setcolours.primary=\u4e3b\u8981
+dialog.setcolours.secondary=\u526f\u6b21
+dialog.setcolours.point=\u70b9
+dialog.setcolours.selection=\u9078\u629e
+dialog.setcolours.text=\u30c6\u30ad\u30b9\u30c8
+dialog.colourchooser.title=\u8272\u3092\u9078\u3093\u3067\u304f\u3060\u3055\u3044
+dialog.colourchooser.red=\u8d64
+dialog.colourchooser.green=\u7dd1
+dialog.colourchooser.blue=\u9752
+dialog.setlanguage.firstintro=\u642d\u8f09\u3055\u308c\u3066\u3044\u308b\u8a00\u8a9e\u306e\u4e00\u3064\u3092\u9078\u3076\u304b\u3001<p>\u4ee3\u308f\u308a\u306b\u4f7f\u3046\u30c6\u30ad\u30b9\u30c8\u30d5\u30a1\u30a4\u30eb\u3092\u9078\u3073\u307e\u3059\u3002
+dialog.setlanguage.secondintro=\u8a00\u8a9e\u3092\u5207\u308a\u66ff\u3048\u308b\u306b\u306f\u3001\u8a2d\u5b9a\u3092\u4fdd\u5b58\u3057\u3066<p>Prune \u3092\u518d\u8d77\u52d5\u3057\u3066\u304f\u3060\u3055\u3044\u3002
+dialog.setlanguage.language=\u8a00\u8a9e
+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\nPrune \u3092\u518d\u8d77\u52d5\u3057\u3066\u304f\u3060\u3055\u3044\u3002
+
+# 3d window
+dialog.3d.title=Prune 3D \u8868\u793a
+dialog.3d.altitudecap=\u6700\u4f4e\u9ad8\u5ea6\u7bc4\u56f2
+dialog.3dlines.title=Prune \u683c\u5b50\u7dda
+dialog.3dlines.empty=\u683c\u5b50\u7dda\u304c\u8868\u793a\u3055\u308c\u307e\u305b\u3093
+dialog.3dlines.intro=\u3053\u308c\u3089\u304c 3D \u8868\u793a\u7528\u306e\u683c\u5b50\u7dda\u3067\u3059\u3002
+
+# Confirm messages || These are displayed as confirmation in the status bar
+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.deletepoint.single=\u30c7\u30fc\u30bf\u70b9\u306f\u524a\u9664\u3055\u308c\u305f
+confirm.deletepoint.multi=\u30c7\u30fc\u30bf\u70b9\u306f\u524a\u9664\u3055\u308c\u305f
+confirm.point.edit=\u7de8\u96c6\u3055\u308c\u305f\u70b9
+confirm.mergetracksegments=\u30c8\u30e9\u30c3\u30af\u30bb\u30b0\u30e1\u30f3\u30c8\u304c\u7d71\u5408\u6e08\u307f
+confirm.reverserange=\u7bc4\u56f2\u304c\u53cd\u8ee2\u3055\u308c\u305f
+confirm.addtimeoffset=\u6642\u9593\u504f\u4f4d\u304c\u52a0\u3048\u3089\u308c\u3066\u3044\u308b
+confirm.addaltitudeoffset=\u9ad8\u5ea6\u504f\u4f4d\u304c\u52a0\u3048\u3089\u308c\u3066\u3044\u308b
+confirm.rearrangewaypoints=\u30a6\u30a7\u30a4\u30dd\u30a4\u30f3\u30c8\u304c\u4e26\u3079\u66ff\u3048\u3089\u308c\u305f
+confirm.rearrangephotos=\u5199\u771f\u304c\u4e26\u3079\u66ff\u3048\u3089\u308c\u305f
+confirm.cutandmove=\u9078\u629e\u304c\u52d5\u304b\u3055\u308c\u305f
+confirm.convertnamestotimes=\u30a6\u30a7\u30a4\u30dd\u30a4\u30f3\u30c8\u306e\u540d\u524d\u304c\u5909\u63db\u3055\u308c\u305f
+confirm.saveexif.ok1=\u4fdd\u5b58\u3055\u308c\u305f
+confirm.saveexif.ok2=\u5199\u771f\u30d5\u30a1\u30a4\u30eb
+confirm.undo.single=\u64cd\u4f5c\u306f\u30a2\u30f3\u30c9\u30a5\u3055\u308c\u305f
+confirm.undo.multi=\u64cd\u4f5c\u306f\u30a2\u30f3\u30c9\u30a5\u3055\u308c\u305f
+confirm.jpegload.single=\u5199\u771f\u304c\u52a0\u3048\u3089\u308c\u305f
+confirm.jpegload.multi=\u5199\u771f\u304c\u52a0\u3048\u3089\u308c\u305f
+confirm.photo.connect=\u5199\u771f\u304c\u63a5\u7d9a\u3055\u308c\u305f
+confirm.photo.disconnect=\u5199\u771f\u304c\u63a5\u7d9a\u3055\u308c\u305f
+confirm.correlate.single=\u5199\u771f\u304c\u95a2\u9023\u4ed8\u3051\u3089\u308c\u305f
+confirm.correlate.multi=\u5199\u771f\u304c\u95a2\u9023\u4ed8\u3051\u3089\u308c\u305f
+confirm.createpoint=\u70b9\u304c\u4f5c\u3089\u308c\u305f
+confirm.rotatephoto=\u5199\u771f\u3092\u56de\u8ee2\u3057\u305f
+confirm.running=\u5b9f\u884c\u4e2d...
+
+# Buttons || These are all the texts for buttons
+button.ok=\u6c7a\u5b9a
+button.back=\u623b\u308b
+button.next=\u6b21
+button.finish=\u5b8c\u6210
+button.cancel=\u53d6\u6d88
+button.overwrite=\u4e0a\u66f8\u304d
+button.moveup=\u4e0a\u3078
+button.movedown=\u4e0b\u3078
+button.showlines=\u7dda\u3092\u8868\u793a
+button.edit=\u7de8\u96c6
+button.exit=\u7d42\u4e86
+button.close=\u9589\u3058\u308b
+button.continue=\u7d9a\u3051\u308b
+button.yes=\u306f\u3044
+button.no=\u3044\u3044\u3048
+button.yestoall=\u5168\u90e8\u306b\u306f\u3044
+button.notoall=\u5168\u90e8\u306b\u3044\u3044\u3048
+button.select=\u9078\u629e
+button.selectall=\u5168\u9078\u629e
+button.selectnone=\u9078\u629e\u89e3\u9664
+button.preview=\u30d7\u30ec\u30d3\u30e5\u30fc
+button.load=\u8aad\u307f\u8fbc\u307f
+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...
+
+# File types
+filetype.txt=TXT\u30d5\u30a1\u30a4\u30eb
+filetype.jpeg=JPG\u30d5\u30a1\u30a4\u30eb
+filetype.kmlkmz=KML,KMZ\u30d5\u30a1\u30a4\u30eb
+filetype.kml=KML\u30d5\u30a1\u30a4\u30eb
+filetype.kmz=KMZ\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
+
+# Display components || These are all for the side panels showing point/range details
+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
+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
+details.track.file=\u30d5\u30a1\u30a4\u30eb
+details.track.numfiles=\u30d5\u30a1\u30a4\u30eb\u6570
+details.pointdetails=\u70b9\u306e\u8a73\u7d30
+details.index.selected=\u7b2c
+details.index.of=\u756a \u5168:
+details.nopointselection=\u70b9\u304c\u9078\u629e\u3055\u308c\u3066\u3044\u307e\u305b\u3093
+details.photofile=\u5199\u771f\u30d5\u30a1\u30a4\u30eb
+details.norangeselection=\u7bc4\u56f2\u304c\u9078\u629e\u3055\u308c\u3066\u3044\u307e\u305b\u3093
+details.rangedetails=\u7bc4\u56f2\u8a73\u7d30
+details.range.selected=\u9078\u629e\u6e08
+details.range.to=\u304b\u3089
+details.altitude.to=\u304b\u3089
+details.range.climb=\u4e0a\u308a
+details.range.descent=\u4e0b\u308a
+details.coordformat=\u5ea7\u6a19\u30d5\u30a9\u30fc\u30de\u30c3\u30c8
+details.distanceunits=\u8ddd\u96e2\u5358\u4f4d
+display.range.time.secs=\u79d2
+display.range.time.mins=\u5206
+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.numsegments=\u30bb\u30b0\u30e1\u30f3\u30c8\u6570
+details.range.pace=\u30da\u30fc\u30b9
+details.range.gradient=\u52fe\u914d
+details.waypointsphotos.waypoints=\u30a6\u30a7\u30a4\u30dd\u30a4\u30f3\u30c8
+details.waypointsphotos.photos=\u5199\u771f
+details.photodetails=\u5199\u771f\u8a73\u7d30
+details.nophoto=\u5199\u771f\u304c\u9078\u629e\u3055\u308c\u3066\u3044\u307e\u305b\u3093
+details.photo.loading=\u8aad\u307f\u8fbc\u307f\u4e2d
+details.photo.connected=\u63a5\u7d9a\u6e08
+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
+fieldname.latitude=\u7def\u5ea6
+fieldname.longitude=\u7d4c\u5ea6
+fieldname.altitude=\u9ad8\u5ea6
+fieldname.timestamp=\u6642\u9593
+fieldname.time=\u6642\u9593
+fieldname.waypointname=\u540d\u524d
+fieldname.waypointtype=\u7a2e\u985e
+fieldname.newsegment=\u30bb\u30b0\u30e1\u30f3\u30c8
+fieldname.custom=\u30ab\u30b9\u30bf\u30e0
+fieldname.prefix=\u30d5\u30a3\u30fc\u30eb\u30c9
+fieldname.distance=\u8ddd\u96e2
+fieldname.movingdistance=\u79fb\u52d5\u8ddd\u96e2
+fieldname.duration=\u9593\u9694
+fieldname.speed=\u901f\u5ea6
+fieldname.verticalspeed=\u5782\u76f4\u901f\u5ea6
+
+# Measurement units
+units.original=\u30aa\u30ea\u30b8\u30ca\u30eb
+units.default=\u521d\u671f\u5024
+units.metres=\u30e1\u30fc\u30c8\u30eb
+units.metres.short=m
+units.feet=\u30d5\u30a3\u30fc\u30c8
+units.feet.short=ft
+units.kilometres=\u30ad\u30ed\u30e1\u30fc\u30c8\u30eb
+units.kilometres.short=km
+units.kmh=km/h
+units.miles=\u30de\u30a4\u30eb
+units.miles.short=mi
+units.mph=mph
+units.metrespersec=m/s
+units.feetpersec=ft/s
+units.hours=\u6642\u9593
+units.degminsec=\u5ea6-\u5206-\u79d2
+units.degmin=\u5ea6-\u5206
+units.deg=\u5ea6
+units.iso8601=ISO 8601
+
+# External urls
+url.googlemaps=maps.google.co.jp
+
+# Cardinals for 3d plots
+cardinal.n=N
+cardinal.s=S
+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.load=\u30c7\u30fc\u30bf\u3092\u8aad\u307f\u8fbc\u307f
+undo.loadphotos=\u5199\u771f\u306e\u8aad\u307f\u8fbc\u307f
+undo.editpoint=\u70b9\u306e\u7de8\u96c6
+undo.deletepoint=\u70b9\u306e\u524a\u9664
+undo.deletephoto=\u5199\u771f\u306e\u53d6\u308a\u9664\u304d
+undo.deleterange=\u7bc4\u56f2\u306e\u524a\u9664
+undo.compress=\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.addtimeoffset=\u6642\u9593\u504f\u4f4d\u3092\u52a0\u3048\u308b
+undo.addaltitudeoffset=\u9ad8\u5ea6\u504f\u4f4d\u3092\u52a0\u3048\u308b
+undo.rearrangewaypoints=\u30a6\u30a7\u30a4\u30dd\u30a4\u30f3\u30c8\u3092\u633f\u5165
+undo.cutandmove=\u30bb\u30af\u30b7\u30e7\u30f3\u306e\u79fb\u52d5
+undo.connectphoto=\u5199\u771f\u306e\u63a5\u7d9a
+undo.disconnectphoto=\u5199\u771f\u306e\u63a5\u7d9a\u89e3\u9664
+undo.correlate=\u5199\u771f\u306e\u95a2\u9023\u4ed8\u3051
+undo.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
+
+# Error messages
+error.save.dialogtitle=\u30c7\u30fc\u30bf\u4fdd\u5b58\u306e\u30a8\u30e9\u30fc
+error.save.nodata=\u4fdd\u5b58\u3059\u308b\u30c7\u30fc\u30bf\u304c\u3042\u308a\u307e\u305b\u3093
+error.save.failed=\u30c7\u30fc\u30bf\u3092\u30d5\u30a1\u30a4\u30eb\u306b\u4fdd\u5b58\u3059\u308b\u306e\u306b\u5931\u6557\u3057\u307e\u3057\u305f
+error.saveexif.filenotfound=\u5199\u771f\u30d5\u30a1\u30a4\u30eb\u304c\u898b\u3064\u304b\u308a\u307e\u305b\u3093\u3067\u3057\u305f
+error.saveexif.cannotoverwrite1=\u5199\u771f\u30d5\u30a1\u30a4\u30eb
+error.saveexif.cannotoverwrite2=\u8aad\u307f\u8fbc\u307f\u5c02\u7528\u3067\u4e0a\u66f8\u304d\u3067\u304d\u307e\u305b\u3093\u3002\u8907\u88fd\u3092\u4f5c\u308a\u307e\u3059\u304b\uff1f
+error.saveexif.failed1=
+error.saveexif.failed2=\u679a\u306e\u753b\u50cf\u306e\u4fdd\u5b58\u306b\u5931\u6557\u3057\u307e\u3057\u305f
+error.saveexif.forced1=
+error.saveexif.forced2=\u679a\u306e\u753b\u50cf\u304c\u5f37\u884c\u3059\u308b\u5fc5\u8981\u304c\u3042\u308a\u307e\u3059\u3002
+error.load.dialogtitle=\u30c7\u30fc\u30bf\u306e\u8aad\u307f\u8fbc\u307f\u30a8\u30e9\u30fc
+error.load.noread=\u30d5\u30a1\u30a4\u30eb\u304c\u8aad\u3081\u307e\u305b\u3093
+error.load.nopoints=\u30d5\u30a1\u30a4\u30eb\u306e\u4e2d\u306b\u5ea7\u6a19\u60c5\u5831\u304c\u898b\u3064\u304b\u308a\u307e\u305b\u3093
+error.load.unknownxml=XML\u30d5\u30a9\u30fc\u30de\u30c3\u30c8\u304c\u89e3\u91c8\u3067\u304d\u307e\u305b\u3093
+error.load.noxmlinzip=Zip\u30d5\u30a1\u30a4\u30eb\u4e2d\u306bXML\u30d5\u30a1\u30a4\u30eb\u304c\u898b\u3064\u304b\u308a\u307e\u305b\u3093
+error.load.othererror=\u30d5\u30a1\u30a4\u30eb\u3092\u8aad\u307f\u8fbc\u307f\u30a8\u30e9\u30fc:
+error.jpegload.dialogtitle=\u5199\u771f\u306e\u8aad\u307f\u8fbc\u307f\u30a8\u30e9\u30fc:
+error.jpegload.nofilesfound=\u30d5\u30a1\u30a4\u30eb\u304c\u898b\u3064\u304b\u308a\u307e\u305b\u3093
+error.jpegload.nojpegsfound=Jpeg\u30d5\u30a1\u30a4\u30eb\u304c\u898b\u3064\u304b\u308a\u307e\u305b\u3093
+error.jpegload.noexiffound=EXIF\u60c5\u5831\u304c\u898b\u3064\u304b\u308a\u307e\u305b\u3093
+error.jpegload.nogpsfound=GPS\u60c5\u5831\u304c\u898b\u3064\u304b\u308a\u307e\u305b\u3093
+error.gpsload.unknown=\u4e0d\u660e\u306a\u30a8\u30e9\u30fc
+error.undofailed.title=\u30a2\u30f3\u30c9\u30a5\u5931\u6557
+error.undofailed.text=\u30a2\u30f3\u30c9\u30a5\u64cd\u4f5c\u306e\u5931\u6557
+error.function.noop.title=\u305d\u306e\u6a5f\u80fd\u306f\u52b9\u679c\u3042\u308a\u307e\u305b\u3093
+error.rearrange.noop=\u70b9\u306e\u518d\u914d\u7f6e\u306f\u52b9\u679c\u3042\u308a\u307e\u305b\u3093
+error.function.notavailable.title=\u305d\u306e\u6a5f\u80fd\u306f\u4f7f\u3048\u307e\u305b\u3093
+error.function.nojava3d=\u3053\u306e\u6a5f\u80fd\u306f Java3d \u30e9\u30a4\u30d6\u30e9\u30ea\u3092\u5fc5\u8981\u3068\u3057\u307e\u3059\u3002\nSun.com \u3088\u308a\u5165\u624b\u3057\u3066\u304f\u3060\u3055\u3044
+error.3d=3D \u8868\u793a\u3067\u30a8\u30e9\u30fc\u304c\u8d77\u304d\u307e\u3057\u305f
+error.readme.notfound=Readme \u30d5\u30a1\u30a4\u30eb\u304c\u898b\u3064\u304b\u308a\u307e\u305b\u3093
+error.osmimage.dialogtitle=\u5730\u56f3\u753b\u50cf\u3092\u8aad\u307f\u8fbc\u307f\u6642\u306e\u30a8\u30e9\u30fc
+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\u306fPrune \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
menu.file.addphotos=Dodaj zdj\u0119cia
menu.file.save=Zapisz
menu.file.exit=Zako\u0144cz
-menu.edit=Edycja
+menu.track=\u015acie\u017cka
menu.edit.undo=Cofnij
menu.edit.clearundo=Wyczy\u015b\u0107 list\u0119 zmian
menu.edit.editpoint=Edytuj punkt
menu.edit.rearrange.end=Wszystkie na koniec \u015bcie\u017cki
menu.edit.rearrange.nearest=Do najbli\u017cszego punktu
menu.edit.cutandmove=Wytnij i przesu\u0144 zaznaczenie
-menu.select=Zaznacz
+menu.range=Zakres
+menu.point=Punkt
menu.select.all=Zaznacz wszystko
menu.select.none=Usu\u0144 zaznaczenie
menu.select.start=Zaznacz pocz\u0105tek zakresu
menu.view.browser.openstreetmap=Openstreetmap
menu.view.browser.mapquest=Mapquest
menu.view.browser.yahoo=Mapy Yahoo
+menu.view.browser.bing=Mapy Bing
menu.settings=Ustawienia
-menu.settings.showpace=Poka\u017c tempo przy wy\u015bwietlaniu zakresu
menu.help=Pomoc
# Popup menu for map
menu.map.zoomin=Powi\u0119ksz
# Alt keys for menus
altkey.menu.file=P
-altkey.menu.edit=E
-altkey.menu.select=A
+altkey.menu.track=C
+altkey.menu.range=Z
+altkey.menu.point=U
altkey.menu.view=W
altkey.menu.photo=Z
altkey.menu.settings=T
function.compress=Kompresuj \u015bcie\u017ck\u0119
function.addtimeoffset=Dodaj przesuni\u0119cie czasu
function.addaltitudeoffset=Dodaj przesuni\u0119cie wysoko\u015bci
+function.convertnamestotimes=Zamie\u0144 nazwy punkt\u00f3w na czas
function.findwaypoint=Znajd\u017a punkt po\u015bredni
+function.pastecoordinates=Wprowad\u017a nowe wsp\u00f3\u0142rz\u0119dne
function.charts=Wykres
function.show3d=Poka\u017c model 3D
function.distances=Odleg\u0142o\u015bci
-function.getgpsies=Pobierz \u015bcie\u017cki z Gpsies
-function.correlatephotos=Powi\u0105\u017c zdj\u0119cia
-function.setmapbg=Wybierz map\u0119
+function.fullrangedetails=Wszystkie detale
+function.setmapbg=Wybierz map\u0119 t\u0142a
function.setkmzimagesize=Ustaw rozmiar zdj\u0119\u0107 w KMZ
function.setpaths=Ustaw \u015bcie\u017cki do program\u00f3w
+function.getgpsies=Pobierz \u015bcie\u017cki z Gpsies
+function.duplicatepoint=Duplikuj plik
+function.setcolours=Ustaw kolory
+function.setlanguage=Zmie\u0144 j\u0119zyk
+function.correlatephotos=Powi\u0105\u017c zdj\u0119cia
+function.rearrangephotos=Zmie\u0144 kolejno\u015b\u0107 zdj\u0119\u0107
+function.rotatephotoleft=Obr\u00f3\u0107 zdj\u0119cie w lewo
+function.rotatephotoright=Obr\u00f3\u0107 zdj\u0119cie wprawo
+function.ignoreexifthumb=Ignoruj miniaturk\u0119 z exif
function.help=Pomoc
function.showkeys=Poka\u017c klawisze skr\u00f3tu
function.about=O Prune
dialog.gpsload.format=Format
dialog.gpsload.getwaypoints=\u0141aduj punkty po\u015brednie
dialog.gpsload.gettracks=\u0141aduj \u015bcie\u017cki
+dialog.gpsload.save=Zapisz do pliku
dialog.gpssend.sendwaypoints=Wy\u015blij punkty po\u015brednie
dialog.gpssend.sendtracks=Wy\u015blij \u015bcie\u017cki
dialog.gpssend.trackname=Nazwa \u015bcie\u017cki
dialog.save.timestampformat=Format znacznika czasu
dialog.save.overwrite.title=Plik ju\u017c istnieje
dialog.save.overwrite.text=Ten plik ju\u017c istnieje. Czy na pewno chcesz go nadpisa\u0107?
+dialog.save.notypesselected=Nie zosta\u0142 wybrany \u017caden typ punkt\u00f3w
dialog.exportkml.text=Tytu\u0142 dla danych
dialog.exportkml.altitude=Do\u0142\u0105cz wysoko\u015bci (dla cel\u00f3w lotniczych)
dialog.exportkml.kmz=Skompresuj do pliku KMZ
dialog.exportkml.exportimages=Eksportuj miniaturki zdj\u0119\u0107 do KMZ
+dialog.exportkml.trackcolour=Kolor \u015bcie\u017cki
dialog.exportgpx.name=Nazwa
dialog.exportgpx.desc=Opis
dialog.exportgpx.includetimestamps=Do\u0142\u0105cz znaczniki czasu
+dialog.exportgpx.copysource=Kopiuj \u017ar\u00f3d\u0142owy xml
dialog.exportpov.text=Wprowad\u017a dodatkowe parametry eksportu do formatu POV
dialog.exportpov.font=Czcionka
dialog.exportpov.camerax=Kamera X
dialog.pointtype.track=punkty \u015bcie\u017cki
dialog.pointtype.waypoint=punkty po\u015brednie
dialog.pointtype.photo=punkty zdj\u0119\u0107
+dialog.pointtype.selection=Tylko wybrane
dialog.confirmreversetrack.title=Potwierd\u017a odwr\u00f3cenie
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.addtimeoffset.hours=Godziny
dialog.addtimeoffset.minutes=Minuty
dialog.addtimeoffset.notimestamps=Nie mo\u017cna przesun\u0105\u0107 czasu, poniewa\u017c zaznaczenie nie zawiera znacznik\u00f3w czasu
-dialog.findwaypoint.intro=
-dialog.findwaypoint.search=
-dialog.connect.title=Po\u0142\u0105cz zdj\u0119cie do punktu
-dialog.connectphoto.clonepoint=Ten punkt po\u0142\u0105czono ju\u017c ze zdj\u0119ciem.\nCzy chcesz zrobi\u0107 kopi\u0119 tego punktu?
+dialog.findwaypoint.intro=Wprowad\u017a nazw\u0119 punktu po\u015bredniego
+dialog.findwaypoint.search=Szukaj
dialog.saveexif.title=Zapisz Exif
dialog.saveexif.intro=Zaznacz zdj\u0119cia do zapisu u\u017cywaj\u0105c znacznik\u00f3w
dialog.saveexif.nothingtosave=Wsp\u00f3\u0142rz\u0119dne nie zosta\u0142y zmienione, nie ma nic do zapisu
dialog.saveexif.photostatus.disconnected=Roz\u0142\u0105czony
dialog.saveexif.photostatus.modified=Zmodyfikowany
dialog.saveexif.overwrite=Nadpisz pliki
+dialog.saveexif.force=Wymu\u015b pomimo niewielkich b\u0142\u0119d\u00f3w
dialog.charts.xaxis=O\u015b X
dialog.charts.yaxis=O\u015b Y
dialog.charts.output=Wykres
dialog.charts.svgwidth=szeroko\u015b\u0107 SVG
dialog.charts.svgheight=wysoko\u015b\u0107 SVG
dialog.charts.needaltitudeortimes=\u015acie\u017cka musi posiada\u0107 zapisane wysoko\u015bci lub znaczniki czasu aby mo\u017cliwe by\u0142o utworzenie wykres\u00f3w
-dialog.charts.gnuplotpath=\u015acie\u017cka do programu gnuplot
dialog.charts.gnuplotnotfound=Nie znalaz\u0142em programu gnuplot
dialog.distances.intro=Odleg\u0142o\u015b\u0107 mi\u0119dzy punktami w linii prostej
dialog.distances.column.from=Z punktu
dialog.distances.column.to=Do punktu
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.setmapbg.mapnik=Mapnik (domy\u015blny)
dialog.setmapbg.osma=Osma
dialog.setmapbg.cyclemap=Cyclemap
dialog.gpsies.column.length=D\u0142ugo\u015b\u0107
dialog.gpsies.description=Opis
dialog.gpsies.nodescription=Brak opisu
-dialog.gpsies.nonefound=
+dialog.gpsies.nonefound=Nie znalaz\u0142em \u015bcie\u017cek
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.photoselect.intro=Wybierz jedno z powi\u0105zanych zdj\u0119\u0107 i u\u017cyj go jako wzorca do przesuni\u0119cia czasu
dialog.correlate.options.distancelimit=Limit odleg\u0142o\u015bci
dialog.correlate.options.correlate=Powi\u0105\u017c ze sob\u0105
dialog.correlate.alloutsiderange=Wszystkie zdj\u0119cia s\u0105 poza zakresem czasu \u015bcie\u017cki, tak \u017ce \u017cadne nie mo\u017ce zosta\u0107 z ni\u0105 skorelowane.\nSpr\u00f3buj zmieni\u0107 przesuni\u0119cie lub r\u0119cznie skoreluj przynajmniej jedno zdj\u0119cie.
+dialog.rearrangephotos.desc=Wybierz przeznaczenie i porz\u0105dek sortowania punkt\u00f3w ze zdj\u0119ciami
+dialog.rearrangephotos.tostart=Przesu\u0144 na pocz\u0105tek
+dialog.rearrangephotos.toend=Przesu\u0144 na koniec
+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.duplicates.title=Usuwanie duplikat\u00f3w
-dialog.compress.closepoints.title=Usuwanie punkt\u00f3w bliskich sobie
+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.wackypoints.paramdesc=Wsp\u00f3\u0142czynnik odleg\u0142o\u015bci
dialog.compress.singletons.title=Usuwanie odosobnionych punkt\u00f3w
dialog.compress.singletons.paramdesc=Wsp\u00f3\u0142czynnik odleg\u0142o\u015bci
+dialog.compress.duplicates.title=Usuwanie duplikat\u00f3w
dialog.compress.summarylabel=Punkty do usuni\u0119cia
+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.help.help=Na stronie\n http://activityworkshop.net/software/prune/ \nznajdziesz wi\u0119cej informacji oraz podr\u0119cznik u\u017cytkownika
dialog.about.version=Wersja
dialog.about.build=Build
dialog.saveconfig.prune.trackdirectory=Katalog ze \u015bcie\u017ckami
dialog.saveconfig.prune.photodirectory=Katalog ze zdj\u0119ciami
dialog.saveconfig.prune.languagecode=Kod j\u0119zyka (PL)
+dialog.saveconfig.prune.languagefile=Plik t\u0142umaczenia
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.exiftoolpath=\u015bcie\u017cka do exiftool
dialog.saveconfig.prune.mapserverindex=kolejny numer serwera map
dialog.saveconfig.prune.mapserverurl=URL serwera map
-dialog.saveconfig.prune.showpace=Pokazuj tempo
dialog.saveconfig.prune.kmzimagewidth=szeroko\u015b\u0107 obrazka w KMZ
dialog.saveconfig.prune.kmzimageheight=wysoko\u015b\u0107 obrazka w KMZ
+dialog.saveconfig.prune.colourscheme=Schemat kolor\u00f3w
+dialog.saveconfig.prune.kmltrackcolour=Kolor \u015bcie\u017cki w pliku KML
dialog.setpaths.intro=Je\u015bli zachodzi tak potrzeba, mo\u017cesz wybra\u0107 \u015bcie\u017cki do aplikacji zewn\u0119trznych
dialog.addaltitude.noaltitudes=Wybrany zakres nie zawiera danych o wysoko\u015bciach
dialog.addaltitude.desc=Warto\u015b\u0107 przesuni\u0119cia wysoko\u015bci
+dialog.setcolours.intro=Kliknij na kolor by go wybra\u0107
+dialog.setcolours.background=T\u0142o
+dialog.setcolours.borders=Ramki
+dialog.setcolours.lines=Linie
+dialog.setcolours.primary=G\u0142\u00f3wny
+dialog.setcolours.secondary=Drugorz\u0119dny
+dialog.setcolours.point=Punkty
+dialog.setcolours.selection=Wyb\u00f3r
+dialog.setcolours.text=Tekst
+dialog.colourchooser.title=Wybierz kolor
+dialog.colourchooser.red=Czerwony
+dialog.colourchooser.green=Zielony
+dialog.colourchooser.blue=Niebieski
+dialog.setlanguage.firstintro=Mo\u017cesz wybra\u0107 jeden z do\u0142\u0105czonych j\u0119zyk\u00f3w<p>Albo wybra\u0107 wybrany przez siebie plik tekstowy.
+dialog.setlanguage.secondintro=B\u0119dziesz musia\u0142 zapisa\u0107 ustawienia<p>i zrestartowa\u0107 Prune by zmieni\u0107 j\u0119zyk.
+dialog.setlanguage.language=J\u0119zyk
+dialog.setlanguage.languagefile=Plik t\u0142umaczenia
+dialog.setlanguage.endmessage=Zapisz ustawienia i zrestartuj Prune\n by zmiana j\u0119zyka odnios\u0142a skutek.
# 3d window
dialog.3d.title=Prune widok tr\u00f3jwymiarowy
confirm.addtimeoffset=Dodano przesuni\u0119cie czasowe
confirm.addaltitudeoffset=Dodano przesuni\u0119cie wysoko\u015bci
confirm.rearrangewaypoints=Przestawiono punkty po\u015brednie
+confirm.rearrangephotos=Zmieniono kolejno\u015b\u0107 zdj\u0119\u0107
confirm.cutandmove=Przesuni\u0119to zaznaczenie
+confirm.convertnamestotimes=Zmieniono nazwy punkt\u00f3w po\u015brednich
confirm.saveexif.ok1=Zapisano
confirm.saveexif.ok2=pliki zdj\u0119\u0107
confirm.undo.single=cofni\u0119to operacj\u0119
confirm.correlate.single=zdj\u0119cie zosta\u0142o po\u0142\u0105czone
confirm.correlate.multi=zdj\u0119cia zosta\u0142y po\u0142\u0105czone
confirm.createpoint=stworzono punkt
+confirm.rotatephoto=obr\u00f3cono zdj\u0119cie
confirm.running=Przetwarzam dane ...
-# Buttons
+# Buttons || These are all the texts for buttons
button.ok=OK
button.back=Poprzedni
button.next=Nast\u0119pny
button.no=Nie
button.yestoall=Tak na wszystko
button.notoall=Nie na wszystko
+button.select=Zaznacz
button.selectall=Zaznacz wszystko
button.selectnone=Odznacz
button.preview=Podgl\u0105d
button.guessfields=Zgadnij pola
button.showwebpage=Poka\u017c stron\u0119 web
button.check=Sprawd\u017a
+button.resettodefaults=Przywr\u00f3\u0107 domy\u015blne
+button.browse=Przegl\u0105daj...
# File types
filetype.txt=Pliki TXT
filetype.pov=Pliki POV
filetype.svg=Pliki SVG
-# Display components
+# Display components || These are all for the side panels showing point/range details
display.nodata=Nie za\u0142adowano danych
display.noaltitudes=\u015acie\u017cki nie zawieraj\u0105 informacji o wysoko\u015bci
details.trackdetails=Szczeg\u00f3\u0142y \u015bcie\u017cki
display.range.time.days=d
details.range.avespeed=\u015arednia pr\u0119dko\u015b\u0107
details.range.avemovingspeed=\u015arednie przesuni\u0119cie
+details.range.numsegments=Liczba segment\u00f3w
details.range.pace=Tempo
+details.range.gradient=Nachylenie
details.waypointsphotos.waypoints=Punkty po\u015brednie
details.waypointsphotos.photos=Zdj\u0119cia
details.photodetails=Szczeg\u00f3\u0142y zdj\u0119cia
cardinal.e=E
cardinal.w=W
-# Undo operations
+# Undo operations || These will be displayed in the undo list after you've performed the operation, to tell you what you did
undo.load=za\u0142aduj dane
undo.loadphotos=za\u0142aduj zdj\u0119cia
undo.editpoint=edycja punktu
undo.connectphoto=do\u0142\u0105cz zdj\u0119cie
undo.disconnectphoto=od\u0142\u0105cz zdj\u0119cie
undo.correlate=po\u0142\u0105cz ze zdj\u0119ciami
+undo.rearrangephotos=zmie\u0144 kolejno\u015b\u0107 zdj\u0119\u0107
undo.createpoint=stw\u00f3rz punkt
+undo.rotatephoto=obr\u00f3\u0107 zdj\u0119cie
+undo.convertnamestotimes=zamie\u0144 nazwy punkt\u00f3w
# Error messages
error.save.dialogtitle=B\u0142\u0105d zapisu danych
error.save.nodata=Brak danych do zapisu
-error.save.failed=Nie powi\u00f3d\u0142 si\u0119 zapis danych do pliku:
-error.saveexif.filenotfound=Nie znaleziono pliku zdj\u0119cia
+error.save.failed=Nie powi\u00f3d\u0142 si\u0119 zapis danych do pliku
+error.saveexif.filenotfound=Nie znaleziono pliku ze zdj\u0119ciem
error.saveexif.cannotoverwrite1=Plik ze zdj\u0119ciem
-error.saveexif.cannotoverwrite2=jest w trybie tylko do odczytu i nie mo\u017ce zosta\u0107 nadpisany. Zapisa\u0107 do kopii?
+error.saveexif.cannotoverwrite2=jest w trybie tylko do odczytu i nie mo\u017ce zosta\u0107 nadpisany. Zapisa\u0107 kopi\u0119?
+error.saveexif.failed1=B\u0142\u0105d zapisu
+error.saveexif.failed2=zdj\u0119\u0107
+error.saveexif.forced1=
+error.saveexif.forced2=zdj\u0119\u0107 z wymuszonym zapisem
error.load.dialogtitle=B\u0142\u0105d \u0142adowania danych
error.load.noread=Nie mo\u017cna przeczyta\u0107 pliku
error.load.nopoints=Nie znaleziono informacji o wsp\u00f3\u0142rz\u0119dnych w pliku
error.jpegload.nojpegsfound=Nie znaleziono plik\u00f3w jpeg
error.jpegload.noexiffound=Nie znaleziono informacji EXIF
error.jpegload.nogpsfound=Nie znaleziono informacji GPS
+error.gpsload.unknown=Nieznany b\u0142\u0105d
error.undofailed.title=Cofnij nie powiod\u0142o si\u0119
error.undofailed.text=Nie mo\u017cna cofn\u0105\u0107
error.function.noop.title=Funkcja nie ma skutku
-error.rearrange.noop=Przestawienie punkt\u00f3w po\u015brednich nie przyniesie skutku
+error.rearrange.noop=Przestawienie punkt\u00f3w nie przyniesie skutku
error.function.notavailable.title=Funkcja nie dost\u0119pna
error.function.nojava3d=Ta funkcja wymaga biblioteki Java3d,\ndost\u0119pnej na Sun.com.
error.3d=Nast\u0105pi\u0142 b\u0142\u0105d z wy\u015bwietlaniem 3D
error.readme.notfound=Nie znaleziono pliku Readme
error.osmimage.dialogtitle=B\u0142\u0105d przy \u0142adowaniu obraz\u00f3w map
-error.osmimage.failed=B\u0142\u0105d przy \u0142adowaniu obraz\u00f3w map. Sprawd\u017a po\u0142\u0105czenie z internetem.
\ No newline at end of file
+error.osmimage.failed=B\u0142\u0105d przy \u0142adowaniu obraz\u00f3w map. Sprawd\u017a po\u0142\u0105czenie z internetem.
+error.language.wrongfile=Wybrany plik nie jest plikiem z t\u0142umaczeniem dla Prune
+error.convertnamestotimes.nonames=\u017badne nazwy nie mog\u0142y zosta\u0107 zmienione na czas
# Text entries for the Prune application
-# Portuguese entries as extra
+# (Brazilian) Portuguese entries as extra
# Menu entries
menu.file=Arquivo
menu.file.open=Abrir
+menu.file.addphotos=Adicionar fotos
menu.file.save=Salvar
menu.file.exit=Sair
menu.edit=Editar
+menu.track=Track
menu.edit.undo=Desfazer
+menu.edit.clearundo=Limpar lista de desfazer
menu.edit.editpoint=Editar ponto
+menu.edit.deletepoint=Remover ponto
+menu.edit.deleterange=Remover intervalo
+menu.edit.deletemarked=Remover pontos marcados
+menu.edit.interpolate=Interpolar
+menu.edit.average=Sele\u00e7\u00e3o m\u00e9dia
+menu.edit.reverse=Reverter intervalo
+menu.edit.mergetracksegments=Mesclar trechos da rota
+menu.edit.rearrange=Rearrumar pontos
+menu.edit.rearrange.start=Tudo para o in\u00edcio do arquivo
+menu.edit.rearrange.end=Tudo para o fim do arquivo
+menu.edit.rearrange.nearest=Cada um para o ponto da rota mais pr\u00f3ximo
+menu.edit.cutandmove=Recortar e mover sele\u00e7\u00e3o
menu.select=Selecionar
+menu.range=Intervalo
+menu.point=Ponto
menu.select.all=Selectionar tudo
-menu.select.none=Não selecionar nenhuns
+menu.select.none=N\u00e3o selecionar nenhuns
+menu.select.start=Definir in\u00edcio do intervalo
+menu.select.end=Definir fim do intervalo
menu.photo=Foto
-menu.photo.saveexif=Salvar exif
-menu.photo.delete=Remover Foto
+menu.photo.saveexif=Salvar para Exif
+menu.photo.connect=Conectar ao ponto
+menu.photo.disconnect=Desconectar do ponto
+menu.photo.delete=Remover foto
menu.view=Exibir
+menu.view.browser=Mapear no navegador
+menu.view.browser.google=Mapas do Google
+menu.view.browser.openstreetmap=Mapas do Openstreetmap
+menu.view.browser.mapquest=Mapas do Mapquest
+menu.view.browser.yahoo=Mapas do Yahoo
+menu.view.browser.bing=Mapas do Bing
+menu.settings=Configura\u00e7\u00f5es
menu.help=Ajuda
# Popup menu for map
-menu.map.zoomin=Ampliar zoom
-menu.map.zoomout=Reduzir zoom
+menu.map.zoomin=Ampliar
+menu.map.zoomout=Reduzir
+menu.map.zoomfull=Ajustar para tela
+menu.map.newpoint=Criar novo ponto
+menu.map.connect=Conectar pontos da rota
+menu.map.autopan=Auto-ajustar
menu.map.showmap=Mostrar o mapa
+menu.map.showscalebar=Mostrar barra de escala
# Alt keys for menus
altkey.menu.file=A
altkey.menu.edit=E
altkey.menu.select=S
+altkey.menu.track=T
+altkey.menu.range=I
+altkey.menu.point=P
altkey.menu.view=X
altkey.menu.photo=F
-altkey.menu.help=A
+altkey.menu.settings=C
+altkey.menu.help=J
# Ctrl shortcuts for menu items
shortcut.menu.file.open=A
+shortcut.menu.file.load=C
shortcut.menu.file.save=S
shortcut.menu.edit.undo=Z
+shortcut.menu.edit.compress=C
shortcut.menu.select.all=T
-shortcut.menu.help.help=H
+shortcut.menu.help.help=J
# Functions
-function.exportkml=Exportar KML
-function.exportgpx=Exportar GPX
-function.exportpov=Exportar POV
-function.editwaypointname=Editar nome do waypoint
-function.charts=Diagramas
-function.show3d=Visualizar 3d
-function.distances=Distâncias
+function.loadfromgps=Carregar dados do GPS
+function.sendtogps=Enviar dados para o GPS
+function.exportkml=Exportar para KML
+function.exportgpx=Exportar para GPX
+function.exportpov=Exportar para POV
+function.editwaypointname=Editar nome do ponto
+function.compress=Comprimir rota
+function.addtimeoffset=Adicionar diferen\u00e7a de tempo
+function.addaltitudeoffset=Adicionar diferen\u00e7a de altitude
+function.convertnamestotimes=Converter nomes dos pontos para tempos
+function.findwaypoint=Encontrar ponto
+function.pastecoordinates=Inserir novas coordenadas
+function.charts=Gr\u00e1ficos
+function.show3d=Visualizar 3D
+function.distances=Dist\u00e2ncias
+function.fullrangedetails=Todos os detalhes
+function.setmapbg=Definir como fundo do mapa
+function.setkmzimagesize=Definir tamanho da imagem KMZ
+function.setpaths=Definir caminhos do programa
+function.getgpsies=Obter rotas Gpsies
+function.duplicatepoint=Duplicar ponto
+function.setcolours=Definir cores
+function.setlanguage=Definir idioma
+function.correlatephotos=Correlacionar fotos
+function.rearrangephotos=Rearrumar fotos
+function.rotatephotoleft=Roda foto \u00e0 esquerda
+function.rotatephotoright=Roda foto \u00e0 direita
+function.ignoreexifthumb=Ignorar miniatura do exif
function.help=Ajuda
+function.showkeys=Mostrar atalhos de teclado
function.about=Sobre o Prune
+function.checkversion=Verificar novas vers\u00f5es
+function.saveconfig=Salvar configura\u00e7\u00f5es
# Dialogs
+dialog.exit.confirm.title=Sair do Prune
+dialog.exit.confirm.text=Seus dados n\u00e3o foram salvos. Voc\u00ea tem certeza que deseja sair?
+dialog.openappend.title=Adicionar aos dados existentes
+dialog.openappend.text=Adicionar estes dados aos dados j\u00e1 carregados?
+dialog.deletepoint.title=Remover Ponto
+dialog.deletepoint.deletephoto=Remover foto anexada a este ponto?
+dialog.deletephoto.title=Remover Foto
+dialog.deletephoto.deletepoint=Remover ponto anexado a esta foto?
+dialog.openoptions.title=Op\u00e7\u00f5es de abertura
+dialog.openoptions.filesnippet=Extrair do arquivo
+dialog.load.table.field=Campo
+dialog.load.table.datatype=Tipo de Dado
+dialog.load.table.description=Descri\u00e7\u00e3o
+dialog.delimiter.label=Delimitador do campo
+dialog.delimiter.comma=V\u00edrgula ,
+dialog.delimiter.tab=Tabula\u00e7\u00e3o
+dialog.delimiter.space=Espa\u00e7o
+dialog.delimiter.semicolon=Ponto e v\u00edrgula ;
+dialog.delimiter.other=Outro
+dialog.openoptions.deliminfo.records=registros, com
+dialog.openoptions.deliminfo.fields=campos
+dialog.openoptions.deliminfo.norecords=Sem registros
+dialog.openoptions.altitudeunits=Unidades de altitude
+dialog.jpegload.subdirectories=Incluir subpastas
+dialog.jpegload.loadjpegswithoutcoords=Incluir fotos sem coordenadas
+dialog.jpegload.loadjpegsoutsidearea=Incluir fotos fora da \u00e1rea atual
+dialog.jpegload.progress.title=Carregando fotos
+dialog.jpegload.progress=Por favor, espere enquanto as fotos s\u00e3o procuradas
+dialog.gpsload.nogpsbabel=Nenhum programa gpsbabel pode ser encontrado. Continuar?
+dialog.gpsload.device=Nome do dispositivo
+dialog.gpsload.format=Formato
+dialog.gpsload.getwaypoints=Carregar pontos
+dialog.gpsload.gettracks=Carregar rotas
+dialog.gpsload.save=Salvar para arquivo
+dialog.gpssend.sendwaypoints=Enviar pontos
+dialog.gpssend.sendtracks=Enviar rotas
+dialog.gpssend.trackname=Nome da rota
+dialog.saveoptions.title=Salvar arquivo
+dialog.save.fieldstosave=Campos a salvar
+dialog.save.table.field=Campo
+dialog.save.table.hasdata=Possui dados
+dialog.save.table.save=Salvar
+dialog.save.headerrow=Sa\u00edda da linha de cabe\u00e7alho
+dialog.save.coordinateunits=Unidades das coordenadas
+dialog.save.altitudeunits=Unidades da altitude
+dialog.save.timestampformat=Formato da data-hora
+dialog.save.overwrite.title=Arquivo j\u00e1 existe
+dialog.save.overwrite.text=Este arquivo j\u00e1 existe. Voc\u00ea tem certeza que deseja sobrescrev\u00ea-lo?
+dialog.save.notypesselected=Nenhum tipo de ponto foi selecionado
+dialog.exportkml.text=T\u00edtulo para os dados
+dialog.exportkml.altitude=Incluir altitudes (para avia\u00e7\u00e3o)
+dialog.exportkml.kmz=Comprimir para criar arquivo kmz
+dialog.exportkml.exportimages=Exportar miniaturas de imagem para o kmz
+dialog.exportkml.trackcolour=Cor da rota
+dialog.exportgpx.name=Nome
+dialog.exportgpx.desc=Descri\u00e7\u00e3o
+dialog.exportgpx.includetimestamps=Incluir data-hora
+dialog.exportgpx.copysource=Copiar fonte xml
+dialog.exportpov.text=Por favor, insira os par\u00e2metros para a exporta\u00e7\u00e3o POV
+dialog.exportpov.font=Fonte
+dialog.exportpov.camerax=X da C\u00e2mera
+dialog.exportpov.cameray=Y da C\u00e2mera
+dialog.exportpov.cameraz=Z da C\u00e2mera
+dialog.exportpov.modelstyle=Estilo do modelo
+dialog.exportpov.ballsandsticks=Bolas e galhos
+dialog.exportpov.tubesandwalls=Tubos e muros
+dialog.exportpov.warningtracksize=Esta rota possui um grande n\u00famero de pontos, os quais o Java3D n\u00e3o ser\u00e1 capaz de exibir.\n Voc\u00ea tem certeza que deseja continuar?
+dialog.pointtype.desc=Salvar os seguintes tipos de ponto:
+dialog.pointtype.track=Pontos de rotas
+dialog.pointtype.waypoint=Pontos
+dialog.pointtype.photo=Pontos de foto
+dialog.pointtype.selection=Apenas sele\u00e7\u00e3o
+dialog.confirmreversetrack.title=Confirmar invers\u00e3o
+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.undo.none.title=N\u00e3o foi poss\u00edvel desfazer
+dialog.undo.none.text=Nenhuma opera\u00e7\u00e3o a desfazer!
+dialog.clearundo.title=Limpar lista de desfazer
+dialog.clearundo.text=Voc\u00ea tem certeza que deseja limpar a lista de desfazer?\n Todas as informa\u00e7\u00f5es para desfazer ser\u00e3o perdidas!
+dialog.pointedit.title=Editar ponto
+dialog.pointedit.text=Selecionar cada campo para editar e usar o bot\u00e3o 'Editar' para mudar o valor
+dialog.pointedit.table.field=Campo
+dialog.pointedit.table.value=Valor
+dialog.pointedit.table.changed=Alterado
+dialog.pointedit.changevalue.text=Insira o novo valor para este campo
+dialog.pointedit.changevalue.title=Editar campo
+dialog.pointnameedit.name=Nome do ponto
+dialog.pointnameedit.uppercase=MAI\u00daSCULAS
+dialog.pointnameedit.lowercase=min\u00fasculas
+dialog.pointnameedit.sentencecase=Frase
+dialog.addtimeoffset.add=Adicionar tempo
+dialog.addtimeoffset.subtract=Subtrair tempo
+dialog.addtimeoffset.days=Dias
+dialog.addtimeoffset.hours=Horas
+dialog.addtimeoffset.minutes=Minutos
+dialog.addtimeoffset.notimestamps=N\u00e3o foi poss\u00edvel adicionar uma diferen\u00e7a de tempo uma vez que esta sele\u00e7\u00e3o n\u00e3o possui nenhuma informa\u00e7\u00e3o de data-hora
+dialog.findwaypoint.intro=Insira parte do nome do ponto
+dialog.findwaypoint.search=Pesquisar
+dialog.connect.title=Conectar foto ao ponto
+dialog.connectphoto.clonepoint=Este ponto j\u00e1 possui uma foto.\n Voc\u00ea deseja fazer uma c\u00f3pia deste ponto?
+dialog.saveexif.title=Salvar Exif
+dialog.saveexif.intro=Selecionar as fotos para salvar usando as caixas de sele\u00e7\u00e3o
+dialog.saveexif.nothingtosave=Dados das coordenadas n\u00e3o foram alterados, nada para salvar
+dialog.saveexif.noexiftool=Nenhum programa exiftool pode ser encontrado. Continuar?
+dialog.saveexif.table.photoname=Nome da foto
+dialog.saveexif.table.status=Estado
+dialog.saveexif.table.save=Salvar
+dialog.saveexif.photostatus.connected=Conectada
+dialog.saveexif.photostatus.disconnected=Desconectada
+dialog.saveexif.photostatus.modified=Modificada
+dialog.saveexif.overwrite=Sobrescrever arquivos
+dialog.saveexif.force=For\u00e7ar ignorar erros menores
+dialog.charts.xaxis=Eixo X
+dialog.charts.yaxis=Eixo Y
+dialog.charts.output=Sa\u00edda
+dialog.charts.screen=Sa\u00edda para tela
+dialog.charts.svg=Sa\u00edda para arquivo SVG
+dialog.charts.svgwidth=Largura do SVG
+dialog.charts.svgheight=Altura do SVG
+dialog.charts.needaltitudeortimes=A rota deve possuir informa\u00e7\u00f5es de tempo ou altitude para criar gr\u00e1ficos
+dialog.charts.gnuplotnotfound=N\u00e3o foi poss\u00edvel encontrar o gnuplot com o caminho fornecido
+dialog.distances.intro=Dist\u00e2ncias em linha reta entre pontos
+dialog.distances.column.from=Do ponto
+dialog.distances.column.to=Para o ponto
+dialog.distances.currentpoint=Ponto atual
+dialog.distances.toofewpoints=Esta fun\u00e7\u00e3o precisa de pontos para calcular a dist\u00e3ncia entre eles
+dialog.fullrangedetails.intro=Aqui est\u00e3o os detalhes para o intervalo selecionado
+dialog.setmapbg.mapnik=Mapnik (padr\u00e3o)
+dialog.setmapbg.osma=Osma
+dialog.setmapbg.cyclemap=Cyclemap
+dialog.setmapbg.other=Outro
+dialog.setmapbg.server=URL do Servidor
+dialog.gpsies.column.name=Nome da rota
+dialog.gpsies.column.length=Extens\u00e3o
+dialog.gpsies.description=Descri\u00e7\u00e3o
+dialog.gpsies.nodescription=Sem descri\u00e7\u00e3o
+dialog.gpsies.nonefound=Nenhuma rota encontrada
+dialog.correlate.notimestamps=N\u00e3o existem data-hora nos dados dos pontos, assim n\u00e3o h\u00e1 nada para correlacionar com as fotos
+dialog.correlate.nouncorrelatedphotos=Existem fotos n\u00e3o correlacionadas.\nVoc\u00ea tem certeza que deseja continuar?
+dialog.correlate.photoselect.intro=Selecione uma destas fotos correlacionadas para usar como diferen\u00e7a de tempo
+dialog.correlate.photoselect.photoname=Nome da foto
+dialog.correlate.photoselect.timediff=Diferen\u00e7a de tempo
+dialog.correlate.photoselect.photolater=Foto \u00e9 mais recente
+dialog.correlate.options.tip=Dica: Correlacionando pelo menos uma foto manualmente, a diferen\u00e7a de tempo pode ser calculada para voc\u00ea.
+dialog.correlate.options.intro=Selecione as op\u00e7\u00f5es para correla\u00e7\u00e3o autom\u00e1tica
+dialog.correlate.options.offsetpanel=Diferen\u00e7a de tempo
+dialog.correlate.options.offset=Diferen\u00e7a
+dialog.correlate.options.offset.hours=horas.
+dialog.correlate.options.offset.minutes=minutos e
+dialog.correlate.options.offset.seconds=segundos
+dialog.correlate.options.photolater=Foto mais recente que o ponto
+dialog.correlate.options.pointlater=Ponto mais recente que a foto
+dialog.correlate.options.limitspanel=Limites de correla\u00e7\u00e3o
+dialog.correlate.options.notimelimit=Nenhum limite de tempo
+dialog.correlate.options.timelimit=Limite de tempo
+dialog.correlate.options.nodistancelimit=Nenhum limite de dist\u00e2ncia
+dialog.correlate.options.distancelimit=Limite de dist\u00e2ncia
+dialog.correlate.options.correlate=Correlacionar
+dialog.correlate.alloutsiderange=Todas as fotos est\u00e3o fora do intervalo de tempo da rota, assim nenhuma pode ser correlacionada.\n Tente mudar a diferen\u00e7a de tempo ou manualmente correlacionar pelo menos uma foto.
+dialog.rearrangephotos.desc=Selecione o destino e a ordena\u00e7\u00e3o dos pontos das fotos
+dialog.rearrangephotos.tostart=Mover para o in\u00edcio
+dialog.rearrangephotos.toend=Mover para o fim
+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.compress.closepoints.title=Remo\u00e7\u00e3o de ponto pr\u00f3ximo
+dialog.compress.closepoints.paramdesc=Fator de 'span'
+dialog.compress.wackypoints.title=Remo\u00e7\u00e3o de ponto exc\u00eantrica
+dialog.compress.wackypoints.paramdesc=Fator de dist\u00e3ncia
+dialog.compress.singletons.title=Remo\u00e7\u00e3o avulsa
+dialog.compress.singletons.paramdesc=Fator de dist\u00e2ncia
+dialog.compress.duplicates.title=Remo\u00e7\u00e3o de duplicado
+dialog.compress.summarylabel=Pontos para remover
+dialog.pastecoordinates.desc=Insira ou cole as coordenadas aqui
+dialog.pastecoordinates.coords=Coordenadas
+dialog.pastecoordinates.nothingfound=Por favor, verifique as coordenadas novamente
+dialog.help.help=Por favor, veja\n http://activityworkshop.net/software/prune/\npara mais informa\u00e7\u00f5es e guia do usu\u00e1rio.
+dialog.about.version=Vers\u00e3o
+dialog.about.build=Compila\u00e7\u00e3o
+dialog.about.summarytext1=Prune \u00e9 um programa para carregar, exibir e editar dados de receptores de GPS.
+dialog.about.summarytext2=Isto est\u00e1 lan\u00e7ado sob a Gnu GPL para uso e melhoria livre, aberto e em todo o mundo.<br>A c\u00f3pia, redistribui\u00e7\u00e3o e modifica\u00e7\u00e3o s\u00e3o permitidas e encorajadas<br>de acordo coma as condi\u00e7\u00f5es no arquivo <code>license.txt</code>inclu\u00eddo.
+dialog.about.summarytext3=Por favor, veja <code style="font-weight:bold">http://activityworkshop.net/</code> para mais informa\u00e7\u00f5es e guia do usu\u00e1rio.
+dialog.about.languages=Idiomas dispon\u00edveis
+dialog.about.translatedby=Texto em portugu\u00eas por amigo anónimo.
+dialog.about.systeminfo=Informa\u00e7\u00f5es do sistema
+dialog.about.systeminfo.os=Sistema Operacional
+dialog.about.systeminfo.java=M\u00f3dulo Java
+dialog.about.systeminfo.java3d=Java3d instalado
+dialog.about.systeminfo.povray=Povray instalado
+dialog.about.systeminfo.exiftool=Exittool instalado
+dialog.about.systeminfo.gpsbabel=Gpsbabel instalado
+dialog.about.systeminfo.gnuplot=Gnuplot instalado
dialog.about.yes=Sim
-dialog.about.no=Não
+dialog.about.no=N\u00e3o
+dialog.about.credits=Cr\u00e9ditos
+dialog.about.credits.code=C\u00f3digo do Prune escrito por
+dialog.about.credits.exifcode=C\u00f3digo do Exif por
+dialog.about.credits.icons=Alguns \u00edcones obtidos de
+dialog.about.credits.translators=Tradutores
+dialog.about.credits.translations=Tradu\u00e7\u00f5es auxiliadas por
+dialog.about.credits.devtools=Ferramentas de desenvolvimento
+dialog.about.credits.othertools=Outras ferramentas
+dialog.about.credits.thanks=Agradecimentos a
+dialog.about.readme=Leiame
+dialog.checkversion.error=O n\u00famero da vers\u00e3o n\u00e3o pode ser verificado.\n Por favor, verifique a conex\u00e3o \u00e0 Internet.
+dialog.checkversion.uptodate=Voc\u00ea est\u00e1 usando a \u00faltima vers\u00e3o do Prune.
+dialog.checkversion.newversion1=Uma nova vers\u00e3o do Prune est\u00e1 dispon\u00edvel! A \u00faltima vers\u00e3o \u00e9 agora a vers\u00e3o
+dialog.checkversion.newversion2=.
+dialog.checkversion.releasedate1=Esta nova vers\u00e3o foi lan\u00e7ada em
+dialog.checkversion.releasedate2=.
+dialog.checkversion.download=Para baixar a nova vers\u00e3o, v\u00e1 para http://activityworkshop.net/software/prune/download.html.
+dialog.keys.intro=Voc\u00ea pode usar os seguintes atalhos de teclado ao inv\u00e9s de usar o mouse
+dialog.keys.keylist=<table><tr><td>Cursores</td><td>Move o mapa para esquerda, direita, acima e abaixo</td></tr><tr><td>Ctrl + cursores esquerdo e direito</td><td>Seleciona o pr\u00f3ximo ponto ou o anterior</td></tr><tr><td>Ctrl + cursores acima e abaixo</td><td>Amplia ou reduz</td></tr><tr><td>Del</td><td>Remove o ponto atual</td></tr></table>
+dialog.saveconfig.desc=As seguintes configura\u00e7\u00f5es podem ser salvas para um arquivo de configura\u00e7\u00e3o.
+dialog.saveconfig.prune.trackdirectory=Pasta de rotas
+dialog.saveconfig.prune.photodirectory=Pasta de fotos
+dialog.saveconfig.prune.languagecode=C\u00f3digo do idioma (PT_BR)
+dialog.saveconfig.prune.languagefile=Arquivo de idioma
+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
+dialog.saveconfig.prune.mapserverindex=\u00cdndice do servidor de mapas
+dialog.saveconfig.prune.mapserverurl=URL do servidor de mapas
+dialog.saveconfig.prune.kmzimagewidth=Largura da imagem KMZ
+dialog.saveconfig.prune.kmzimageheight=Altura da imagem KMZ
+dialog.saveconfig.prune.colourscheme=Esquema de cores
+dialog.saveconfig.prune.kmltrackcolour=Cor da rota KML
+dialog.setpaths.intro=Se voc\u00ea precisar, voc\u00ea pode escolher os caminhos para as aplica\u00e7\u00f5es externas:
+dialog.addaltitude.noaltitudes=O intervalo selecionado n\u00e3o cont\u00e9m altitudes
+dialog.addaltitude.desc=Diferen\u00e7a de altitude a adicionar
+dialog.setcolours.intro=Clique em um trecho de cor para mudar a cor
+dialog.setcolours.background=Fundo
+dialog.setcolours.borders=Bordas
+dialog.setcolours.lines=Linhas
+dialog.setcolours.primary=Prim\u00e1rio
+dialog.setcolours.secondary=Secund\u00e1rio
+dialog.setcolours.point=Pontos
+dialog.setcolours.selection=Sele\u00e7\u00e3o
+dialog.setcolours.text=Texto
+dialog.colourchooser.title=Selecionar cor
+dialog.colourchooser.red=Vermelho
+dialog.colourchooser.green=Verde
+dialog.colourchooser.blue=Azul
+dialog.setlanguage.firstintro=Voc\u00ea pode selecionar um dos idiomas inclu\u00eddos,<p>ou selecionar um arquivo de texto para usar.
+dialog.setlanguage.secondintro=Voc\u00ea precisa salvar suas configura\u00e7\u00f5es e ent\u00e3o<p>reiniciar o Prune para mudar o idioma.
+dialog.setlanguage.language=Idioma
+dialog.setlanguage.languagefile=Arquivo de idioma
+dialog.setlanguage.endmessage=Agora salve suas configura\u00e7\u00f5es e reinicie o Prune\npara que a mudan\u00e7a de idioma ocorra.
-# Buttons
+# 3d window
+dialog.3d.title=Vista 3D do Prune
+dialog.3d.altitudecap=Intervalo de altitude m\u00ednimo
+dialog.3dlines.title=Linhas da grade do Prune
+dialog.3dlines.empty=Nenhuma linha de grade para exibir!
+dialog.3dlines.intro=Estas s\u00e3o as linhas da grade para a vista 3D.
+
+# Confirm messages || These are displayed as confirmation in the status bar
+confirm.loadfile=Dados carregados do arquivo
+confirm.save.ok1=Salvo com sucesso
+confirm.save.ok2=pontos para arquivo
+confirm.deletepoint.single=dados do ponto foram removidos
+confirm.deletepoint.multi=dados dos pontos foram removidos
+confirm.point.edit=ponto editado
+confirm.mergetracksegments=Segmento da rota mesclado
+confirm.reverserange=Intervalo invertido
+confirm.addtimeoffset=Diferen\u00e7a de tempo adicionada
+confirm.addaltitudeoffset=Diferen\u00e7a de altitude adicionadas
+confirm.rearrangewaypoints=Pontos rearrumados
+confirm.rearrangephotos=Fotos rearrumadas
+confirm.cutandmove=Sele\u00e7\u00e3o movida
+confirm.convertnamestotimes=Nomes dos pontos convertidos
+confirm.saveexif.ok1=Salvo
+confirm.saveexif.ok2=arquivos de foto
+confirm.undo.single=opera\u00e7\u00e3o desfeita
+confirm.undo.multi=opera\u00e7\u00f5es desfeitas
+confirm.jpegload.single=foto foi adicionada
+confirm.jpegload.multi=fotos foram adicionadas
+confirm.photo.connect=foto conectada
+confirm.photo.disconnect=foto desconectada
+confirm.correlate.single=foto foi correlacionada
+confirm.correlate.multi=fotos foram correlacionadas
+confirm.createpoint=ponto criado
+confirm.rotatephoto=foto rotacionada
+confirm.running=Rodando...
+
+# Buttons || These are all the texts for buttons
+button.ok=Ok
+button.back=Voltar
+button.next=P\u0155oximo
+button.finish=Terminar
button.cancel=Cancelar
+button.overwrite=Sobrescrever
+button.moveup=Mover acima
+button.movedown=Mover abaixo
+button.showlines=Mostrar linhas
button.edit=Editar
button.exit=Sair
button.close=Fechar
+button.continue=Continuar
button.yes=Sim
-button.no=Não
+button.no=N\u00e3o
+button.yestoall=Sim para todos
+button.notoall=N\u00e3o para todos
+button.select=Selecionar
+button.selectall=Selecionar todos
+button.selectnone=Selecionar nenhum
+button.preview=Previs\u00e3o
+button.load=Carregar
+button.guessfields=Campos adivinhados
+button.showwebpage=Mostrar p\u00e1gina Web
+button.check=Verificar
+button.resettodefaults=Restaurar para os padr\u00f5es
+button.browse=Navegar...
-# Display components
-display.nodata=Nenhum dados foi carregado
+# File types
+filetype.txt=Arquivos TXT
+filetype.jpeg=Arquivos JPG
+filetype.kmlkmz=Arquivos KML, KMZ
+filetype.kml=Arquivos KML
+filetype.kmz=Arquivos KMZ
+filetype.gpx=Arquivos GPX
+filetype.pov=Arquivos POV
+filetype.svg=Arquivos SVG
+
+# Display components || These are all for the side panels showing point/range details
+display.nodata=Nenhum dado carregado
+display.noaltitudes=Dados da rota n\u00e3o incluem altitudes
details.trackdetails=Detalhes da track
+details.notrack=Nenhuma rota carrgeada
details.track.points=Pontos
details.track.file=Arquivo
-details.track.numfiles=Número de arquivos
+details.track.numfiles=N\u00famero de arquivos
details.pointdetails=Detalhes da ponto
+details.index.selected=\u00cdndice
details.index.of=de
+details.nopointselection=Nenhum ponto selecionado
+details.photofile=Arquivo de foto
+details.norangeselection=Nenhum intervalo selecionado
details.rangedetails=Detalhes da range
details.range.selected=Selecionado
details.range.to=a
details.altitude.to=a
+details.range.climb=Subir
+details.range.descent=Descer
+details.coordformat=Formato das coordenadas
+details.distanceunits=Unidades de dist\u00e2ncia
+display.range.time.secs=s
+display.range.time.mins=m
+display.range.time.hours=h
+display.range.time.days=d
+details.range.avespeed=Velocidade m\u00e9dia
+details.range.avemovingspeed=Movimento m\u00e9dio
+details.range.numsegments=N\u00famero de segmentos
+details.range.pace=Passo
+details.range.gradient=Gradiente
+details.waypointsphotos.waypoints=Pontos
details.waypointsphotos.photos=Fotos
details.photodetails=Detalhes da foto
+details.nophoto=Nenhuma foto selecionada
details.photo.loading=Carregando
+details.photo.connected=Conectada
+map.overzoom=Nenhum mapa dispon\u00edvel neste n\u00edvel de amplia\u00e7\u00e3o
# Field names
fieldname.latitude=Latitude
fieldname.longitude=Longitude
fieldname.altitude=Altura
+fieldname.timestamp=Tempo
fieldname.time=Tempo
-fieldname.distance=Distância
+fieldname.waypointname=Nome
+fieldname.waypointtype=Tipo
+fieldname.newsegment=Segmento
+fieldname.custom=Personalizado
+fieldname.prefix=Campo
+fieldname.distance=Dist\u00e2ncia
+fieldname.movingdistance=Dist\u00e2ncia de movimento
+fieldname.duration=Dura\u00e7\u00e3o
fieldname.speed=Velocidade
+fieldname.verticalspeed=Velocidade vertical
+
+# Measurement units
+units.original=Original
+units.default=Padr\u00e3o
+units.metres=Metros
+units.metres.short=m
+units.feet=P\u00e9s
+units.feet.short=ft
+units.kilometres=Quil\u00f4metros
+units.kilometres.short=km
+units.kmh=km/h
+units.miles=Milhas
+units.miles.short=mi
+units.mph=mph
+units.metrespersec=m/s
+units.feetpersec=ft/s
+units.hours=horas
+units.degminsec=Graus-min-seg
+units.degmin=Graus-min
+units.deg=Graus
+units.iso8601=ISO 8601
# External urls
url.googlemaps=maps.google.pt
+
+# Cardinals for 3d plots
+cardinal.n=N
+cardinal.s=S
+cardinal.e=L
+cardinal.w=O
+
+# Undo operations || These will be displayed in the undo list after you've performed the operation, to tell you what you did
+undo.load=carregar dados
+undo.loadphotos=carregar fotos
+undo.editpoint=editar ponto
+undo.deletepoint=remover ponto
+undo.deletephoto=remover foto
+undo.deleterange=remover intervalo
+undo.compress=comprimir rota
+undo.insert=inserir pontos
+undo.reverse=inverter intervalo
+undo.mergetracksegments=mesclar segmentos de rota
+undo.addtimeoffset=adicionar diferen\u00e7a de tempo
+undo.addaltitudeoffset=adicionar diferen\u00e7a de altitude
+undo.rearrangewaypoints=rearrumar pontos
+undo.cutandmove=mover se\u00e7\u00e3o
+undo.connectphoto=conectar foto
+undo.disconnectphoto=desconectar foto
+undo.correlate=conectar fotos
+undo.rearrangephotos=rearrumar fotos
+undo.createpoint=criar ponto
+undo.rotatephoto=rotacionar foto
+undo.convertnamestotimes=converter nomes para tempos
+
+# Error messages
+error.save.dialogtitle=Erro ao salvar dados
+error.save.nodata=Nenhum dado para salvar
+error.save.failed=Falha ao salvar dados para arquivo
+error.saveexif.filenotfound=Falha ao procurar o arquivo de foto
+error.saveexif.cannotoverwrite1=Arquivo de foto
+error.saveexif.cannotoverwrite2=\u00e9 somente leitura e n\u00e3o pode ser sobrescrito. Gravar para c\u00f3pia?
+error.saveexif.failed1=Falha ao salvar
+error.saveexif.failed2=das imagens
+error.saveexif.forced1=
+error.saveexif.forced2=das imagens for\u00e7adas por solicita\u00e7\u00e3o
+error.load.dialogtitle=Erro ao carregar dados
+error.load.noread=N\u00e3o foi poss\u00edvel ler arquivo
+error.load.nopoints=Nenhuma informa\u00e7\u00e3o de coordenadas encontrada no arquivo
+error.load.unknownxml=Formato xml n\u00e3o reconhecido:
+error.load.noxmlinzip=Nenhum arquivo xml encontrado dentro do arquivo zip
+error.load.othererror=Erro ao ler arquivo:
+error.jpegload.dialogtitle=Erro ao carregar fotos
+error.jpegload.nofilesfound=Nenhum arquivo encontrado
+error.jpegload.nojpegsfound=Nenhum arquivo jpeg encontrado
+error.jpegload.noexiffound=Nenhuma informa\u00e7\u00e3o EXIF encontrada
+error.jpegload.nogpsfound=Nenhuma informa\u00e7\u00e3o de GPS encontrada
+error.gpsload.unknown=Erro desconhecido
+error.undofailed.title=Falha ao desfazer
+error.undofailed.text=Falha para desfazer opera\u00e7\u00e3o
+error.function.noop.title=Fun\u00e7\u00e3o sem nenhum efeito
+error.rearrange.noop=Rearruma\u00e7\u00e3o de pontos n\u00e3o teve efeito
+error.function.notavailable.title=Fun\u00e7\u00e3o n\u00e3o dispon\u00edvel
+error.function.nojava3d=Esta fun\u00e7\u00e3o precisa da biblioteca Java3d,\ndispon\u00edvel em Sun.com
+error.3d=Um erro ocorreu com a exibi\u00e7\u00e3o 3D
+error.readme.notfound=Arquivo Leiame n\u00e3o encontrado
+error.osmimage.dialogtitle=Erro ao carregar imagens do mapa
+error.osmimage.failed=Falha ao carregar imagens do mapa. Por favor, verifique a conex\u00e3o \u00e0 Internet.
+error.language.wrongfile=O arquivo selecionado n\u00e3o parece ser um arquivo de idioma do Prune
+error.convertnamestotimes.nonames=Nenhum nome pode ser convertido para tempo
# Romanian entries as extra
# Menu entries
-menu.file=Fi\u015Fier
-menu.file.open=Deschidere fi\u015Fier
+menu.file=Fi\u015fier
+menu.file.open=Deschidere fi\u015fier
menu.file.addphotos=Adaugare foto
menu.file.save=Salvare
menu.file.exit=Iesire
+menu.track=Traseu
menu.edit=Editare
menu.edit.undo=Anulare
-menu.edit.clearundo=\u015Etergere lista de anulari
+menu.edit.clearundo=\u015etergere lista de anulari
menu.edit.editpoint=Editare punct
-menu.edit.deletepoint=\u015Etergere punct
-menu.edit.deleterange=\u015Etergere gama
-menu.edit.deletemarked=\u015Etergere puncte marcate
+menu.edit.deletepoint=\u015etergere punct
+menu.edit.deleterange=\u015etergere gama
+menu.edit.deletemarked=\u015etergere puncte marcate
menu.edit.interpolate=Interpolare
menu.edit.average=Mediere selectie
menu.edit.reverse=Inversare selectie
menu.edit.rearrange.end=Toate la sfarsitul fisierului
menu.edit.rearrange.nearest=Fiecare la punctul cel mai apropiat al traseului
menu.edit.cutandmove=Taiere si mutare selectie
+menu.point=Punct
menu.select=Selectare
menu.select.all=Selectare toate
menu.select.none=Nu selecta niciun punct
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 in
-menu.map.zoomout=Apropie out
+menu.map.zoomin=Apropie
+menu.map.zoomout=Departeaza
+menu.map.zoomfull=Departeaza la maxim
menu.map.newpoint=Adaug\u0103 punct
-menu.map.connect=Traseaz\u0103 linii între puncte
+menu.map.connect=Traseaz\u0103 linii \u00eentre puncte
+menu.map.autopan=Autovizualizare punct ales
+menu.map.showmap=Arata harta
# Alt keys for menus
altkey.menu.file=F
shortcut.menu.select.all=T
# Functions
-function.exportkml=Export\u0103 într-un fi\u015Fier KML
-function.exportgpx=Export\u0103 într-un fi\u015Fier GPX
-function.exportpov=Export\u0103 într-un fi\u015Fier POV
+function.loadfromgps=\u00cencarc\u0103 date de la GPS
+function.sendtogps=Trimite date spre GPS
+function.exportkml=Export\u0103 \u00eentr-un fi\u015fier KML
+function.exportgpx=Export\u0103 \u00eentr-un fi\u015fier GPX
+function.exportpov=Export\u0103 \u00eentr-un fi\u015fier POV
function.editwaypointname=Editare nume waypoint
+function.compress=Comprima traseu
+function.charts=Grafice
+function.show3d=Vizualizare arborescenta
+function.distances=Distan\u0163e
+function.setmapbg=Fundal
+function.correlatephotos=Corela fotografii
+function.setcolours=Selectare culorile
+function.setlanguage=Selectare limba
function.help=Ajutor
+function.showkeys=Arat\u0103 tastele scurt\u0103turi
function.about=Despre Prune
+function.checkversion=Verific\u0103 pentru o versiune noua
# Dialogs
-dialog.save.overwrite.text=Fi\u015Fierul exist\u0103. ÃŽl suprascriu?
-dialog.pointedit.text=V\u0103 rog selecta\u0163i rândul care va fi editat
+dialog.exit.confirm.title=Ie\u015fire din programul Prune
+dialog.exit.confirm.text=Datele dumneavoastra nu sunt salvate.\nSunte\u0163i sigur ca\u0103 dori\u0163i s\u0103 ie\u015fiti?
+dialog.openappend.title=Adauga la datele existente
+dialog.openappend.text=Adauga la datele deja incarcate?
+dialog.deletepoint.title=Sterge Punct
+dialog.deletepoint.deletephoto=Sterg fotografiile atasate acestui punct?
+dialog.deletephoto.title=Sterge Foto
+dialog.deletephoto.deletepoint=Sterg punct atasat acestei fotografii?
+dialog.openoptions.title=Optiuni deschidere
+dialog.load.table.field=Cimp
+dialog.load.table.datatype=Tip data
+dialog.load.table.description=Descriere
+dialog.delimiter.label=Delimitator cimp
+dialog.delimiter.comma=Virgula ,
+dialog.delimiter.tab=Tab
+dialog.delimiter.space=Spatiu
+dialog.delimiter.semicolon=Punct si virgula :
+dialog.delimiter.other=Altul
+dialog.openoptions.deliminfo.fields=cimpuri
+dialog.openoptions.deliminfo.norecords=Nu sunt inregistrari
+dialog.save.overwrite.text=Fi\u015fierul exist\u0103. \u00cel suprascriu?
+dialog.pointedit.text=V\u0103 rog selecta\u0163i r\u00e2ndul care va fi editat
+dialog.pointedit.table.field=Cimp
dialog.pointedit.table.value=Valoare
+dialog.pointedit.table.changed=Schimbat
+dialog.pointedit.changevalue.text=Introdu noua valoare pentru acest cimp
+dialog.pointedit.changevalue.title=Modifica cimp
+dialog.pointnameedit.uppercase=Litere MARI
+dialog.pointnameedit.lowercase=Litere mici
+dialog.addtimeoffset.days=Zile
+dialog.addtimeoffset.hours=Ore
+dialog.addtimeoffset.minutes=Minute
dialog.findwaypoint.search=C\u0103utare
+dialog.saveexif.table.status=Stare
+dialog.saveexif.table.save=Salveaza
+dialog.saveexif.photostatus.connected=Conectat
+dialog.saveexif.photostatus.disconnected=Deconectat
+dialog.saveexif.photostatus.modified=Modificat
+dialog.saveexif.overwrite=Suprascrie fisiere
+dialog.charts.xaxis=Axa X
+dialog.charts.yaxis=Axa Y
+dialog.distances.currentpoint=Punct curent
dialog.setmapbg.mapnik=Mapnik (implicit)
dialog.setmapbg.server=Adres\u0103 server
+dialog.gpsies.column.length=Lungime
+dialog.gpsies.description=Descriere
+dialog.gpsies.nodescription=Fara descriere
dialog.correlate.options.tip=Indiciu: By manually correlating at least one photo, the time offset can be calculated for you.
dialog.about.version=Versiunea
-dialog.about.readme=Cite\u015Fte-m\u0103
+dialog.about.readme=Cite\u015fte-m\u0103
+dialog.checkversion.releasedate1=Aceasta versiune noua a fost lansapa pe
+dialog.checkversion.releasedate2=.
+
+# Confirm messages || These are displayed as confirmation in the status bar
+confirm.loadfile=Date incarcate din fisier
+confirm.save.ok1=Salvat cu succes
# Buttons
button.ok=OK
+button.back=Inapoi
+button.next=Urmator
+button.finish=Terminat
button.cancel=Renun\u0163\u0103
+button.overwrite=Suprascrie
+button.moveup=Muta in sus
+button.movedown=Muta in jos
button.edit=Editare
button.exit=Iesire
+button.close=Inchide
+button.continue=Continua
+button.yes=Da
+button.no=Nu
+button.yestoall=Da pentru tot
+button.notoall=Nu pentru tot
+button.select=Selectare
+button.selectall=Selecteaza tot
+button.selectnone=Deselecteaza tot
+button.load=Incarca
# File types
+filetype.txt=Fisier text
filetype.jpeg=Imagine JPEG (*.jpg)
# Display components
details.range.selected=Selectat
details.range.to=la
details.altitude.to=la
+details.coordformat=Format coordonate
+details.distanceunits=Unitati de distanta
+display.range.time.secs=s
+display.range.time.mins=m
+display.range.time.hours=h
+display.range.time.days=z
+details.range.avespeed=Viteza medie
# Field names
+fieldname.latitude=Latitudine
+fieldname.longitude=Longitudine
+fieldname.altitude=Altitudine
fieldname.waypointname=Nume
+fieldname.distance=Distanta
+fieldname.duration=Durata
+fieldname.speed=Viteza
# Measurement units
units.default=Implicit
+
+# Cardinals for 3d plots
+cardinal.n=N
+cardinal.s=S
+cardinal.e=E
+cardinal.w=V
--- /dev/null
+# Text entries for the Prune application
+# Turkish entries as extra
+
+# Menu entries
+menu.file=Dosya
+menu.file.open=Dosya a\u00e7
+menu.file.addphotos=Foto ekle
+menu.file.save=Kaydet
+menu.file.exit=Ç\u0131k\u0131\u015f
+menu.edit=D\u00fczenle
+menu.track=\u0130z
+menu.edit.undo=Geri al
+menu.edit.clearundo=Geri alma listesi s\u0131f\u0131rla
+menu.edit.editpoint=Nokta d\u00fczenle
+menu.edit.deletepoint=Noktay\u0131 sil
+menu.edit.deleterange=S\u0131ray\u0131 sil
+menu.edit.deletemarked=Se\u00e7ili noktalar\u0131 sil
+menu.edit.interpolate=\u0130nterpolasyon
+menu.edit.average=Se\u00e7me ortala
+menu.edit.reverse=S\u0131ra tersine \u00e7evir
+menu.edit.mergetracksegments=\u0130z par\u00e7alar\u0131 birle\u015ftir
+menu.edit.rearrange=Yol noktalar\u0131 yeniden diz
+menu.edit.rearrange.start=Hepsini dosyan\u0131n ba\u015f\u0131na
+menu.edit.rearrange.end=Hepsini dosyan\u0131n sonuna
+menu.edit.rearrange.nearest=En yak\u0131n iz noktaya
+menu.edit.cutandmove=Se\u00e7me kes ve ta\u015f\u0131
+menu.select=Se\u00e7
+menu.range=S\u0131ra
+menu.point=Nokta
+menu.select.all=Hepsini se\u00e7
+menu.select.none=Hi\u00e7 se\u00e7
+menu.select.start=S\u0131ran\u0131n ba\u015fkang\u0131c\u0131 se\u00e7
+menu.select.end=S\u0131ran\u0131n sonu se\u00e7
+menu.photo=Foto
+menu.photo.saveexif=Exif'te kaydet
+menu.photo.connect=Noktaya ba\u011flan
+menu.photo.disconnect=Noktadan kopart
+menu.photo.delete=Fotoyu kald\u0131r
+menu.view=G\u00f6r\u00fcn\u00fcm
+menu.view.browser=Taray\u0131c\u0131n\u0131n haritas\u0131
+menu.view.browser.google=Google haritalar\u0131
+menu.view.browser.openstreetmap=OpenStreetMap
+menu.view.browser.mapquest=Mapquest
+menu.view.browser.yahoo=Yahoo haritalar\u0131
+menu.view.browser.bing=Bing haritalar\u0131
+menu.settings=Ayarlar
+menu.settings.showpace=H\u0131z\u0131 g\u00f6r\u00fcnt\u00fcle
+menu.help=Yard\u0131m
+# Popup menu for map
+menu.map.zoomin=Yak\u0131nla\u015ft\u0131r
+menu.map.zoomout=Uzakla\u015f
+menu.map.newpoint=Yeni nokta olu\u015ftur
+menu.map.connect=\u0130z noktalar\u0131 ba\u011flan
+menu.map.showmap=Harita g\u00f6ster
+menu.map.showscalebar=\u00d6l\u00e7e\u011fi g\u00f6r\u00fcnt\u00fcle
+
+# Alt keys for menus
+altkey.menu.file=D
+altkey.menu.edit=Z
+altkey.menu.select=S
+altkey.menu.track=Z
+altkey.menu.range=S
+altkey.menu.point=N
+altkey.menu.view=G
+altkey.menu.photo=F
+altkey.menu.settings=A
+altkey.menu.help=Y
+
+# Ctrl shortcuts for menu items
+shortcut.menu.file.open=A
+shortcut.menu.file.load=L
+shortcut.menu.file.save=K
+shortcut.menu.edit.undo=Z
+shortcut.menu.edit.compress=C
+shortcut.menu.select.all=A
+shortcut.menu.help.help=Y
+
+# Functions
+function.loadfromgps=GPS'den veri al
+function.sendtogps=GPS'e veri g\u00f6nder
+function.exportkml=Ver KML olarak
+function.exportgpx=Ver GPX olarak
+function.exportpov=Ver POV olarak
+function.editwaypointname=Noktan\u0131n ad\u0131 d\u00fczenle
+function.compress=Yolunu s\u0131k\u0131\u015ft\u0131r
+function.addtimeoffset=Zaman ofseti ekle
+function.addaltitudeoffset=Y\u00fckseklik ofseti ekle
+function.findwaypoint=Noktay\u0131 bul
+function.pastecoordinates=Yeni korrdinatlar gir
+function.charts=Krokiler
+function.show3d=3B g\u00fcr\u00fcnt\u00fcs\u00fc
+function.distances=Uzakl\u0131klar
+function.fullrangedetails=S\u0131ran\u0131n b\u00fct\u00fcn ayr\u0131nt\u0131lar
+function.setmapbg=Arkafonun haritas\u0131 se\u00e7
+function.setkmzimagesize=KMZ resim boyutu ayarla
+function.setpaths=Uygulamalar\u0131n yollar\u0131 ayarla
+function.getgpsies=Gpsies.com'dan yolu al
+function.duplicatepoint=Noktay\u0131 kopyala
+function.setcolours=Renkleri ayarla
+function.setlanguage=Dil se\u00e7
+function.correlatephotos=Fotolar\u0131n ba\u011fl\u0131la\u015ft\u0131r
+function.rearrangephotos=Fotolar\u0131 yeniden diz
+function.rotatephotoleft=Fotoyu sola d\u00f6nd\u00fcr
+function.rotatephotoright=Fotoyu sa\u011fa d\u00f6nd\u00fcr
+function.ignoreexifthumb=Exif t\u0131rnak resmi bo\u015fver
+function.help=Yard\u0131m
+function.showkeys=K\u0131sayol tu\u015flar\u0131 g\u00f6ster
+function.about=Prune hakk\u0131nda
+function.checkversion=Yeni s\u00fcr\u00fcm\u00fc i\u00e7in denetle
+function.saveconfig=Ayarlar\u0131 kaydet
+
+# Dialogs
+dialog.exit.confirm.title=Prune'dan \u00e7\u0131k
+dialog.exit.confirm.text=Ver\u0131 kaydetmedin -Ger\u00e7ekten \u00e7\u0131kmak istiyor musun?
+dialog.openappend.title=Varolan verisine ekle
+dialog.openappend.text=Append this data to the data already loaded?
+dialog.deletepoint.title=Noktay\u0131 sil
+dialog.deletepoint.deletephoto=Noktaya ba\u011fl\u0131 olan foto silmek ister misin?
+dialog.deletephoto.title=Fotoyu sil
+dialog.deletephoto.deletepoint=Fotoya ba\u011fl\u0131 olan nokta silmek ister misin?
+dialog.openoptions.title=Se\u00e7enekleri a\u00e7
+dialog.openoptions.filesnippet=Dosyan\u0131n par\u00e7as\u0131
+dialog.load.table.field=Alan
+dialog.load.table.datatype=Veri t\u00fcr\u00fc
+dialog.load.table.description=A\u00e7\u0131klama
+dialog.delimiter.label=Alan s\u0131n\u0131rlay\u0131c\u0131
+dialog.delimiter.comma=Virg\u00fcl ,
+dialog.delimiter.tab=Sekme
+dialog.delimiter.space=Bo\u015fluk
+dialog.delimiter.semicolon=Noktal\u0131 virg\u00fcl ;
+dialog.delimiter.other=Di\u011fer
+dialog.openoptions.deliminfo.records=sat\u0131rlar, ve
+dialog.openoptions.deliminfo.fields=alanlar
+dialog.openoptions.deliminfo.norecords=Hi\u00e7 bir sat\u0131r bulunmad\u0131
+dialog.openoptions.altitudeunits=Y\u00fckseklik birimi
+dialog.jpegload.subdirectories=Alt dizileri dahil et
+dialog.jpegload.loadjpegswithoutcoords=Koordinats\u0131z fotolar\u0131 dahil et
+dialog.jpegload.loadjpegsoutsidearea=Se\u00e7ili alan\u0131n d\u0131\u015f\u0131ndaki fotolar\u0131 dahil et
+dialog.jpegload.progress.title=Fotolar y\u00fckleniyor
+dialog.jpegload.progress=Fotolar\u0131 taran\u0131yor - l\u00fctfen bekle
+dialog.gpsload.nogpsbabel=gpsbabel uygulamas\u0131 bulunmad\u0131. Devam?
+dialog.gpsload.device=Ayg\u0131t ad\u0131
+dialog.gpsload.format=Bi\u00e7im
+dialog.gpsload.getwaypoints=Noktalar y\u00fckle
+dialog.gpsload.gettracks=Yollar y\u00fckle
+dialog.gpsload.save=Dosyaya kaydet
+dialog.gpssend.sendwaypoints=Noktalar\u0131 g\u00f6nder
+dialog.gpssend.sendtracks=Yollar g\u00f6nder
+dialog.gpssend.trackname=\u0130z ad\u0131
+dialog.saveoptions.title=Dosya kaydet
+dialog.save.fieldstosave=Kaydedecek alanlar
+dialog.save.table.field=Alan
+dialog.save.table.hasdata=Veri var
+dialog.save.table.save=Kaydet
+dialog.save.headerrow=Ba\u015fl\u0131k sat\u0131r\u0131 dahil et
+dialog.save.coordinateunits=Koordinat birimleri
+dialog.save.altitudeunits=Y\u00fckseklik birimleri
+dialog.save.timestampformat=Tarih ve saat bi\u00e7imi
+dialog.save.overwrite.title=Dosya zaten var
+dialog.save.overwrite.text=Bu dosya zaten var. Ger\u00e7ekten \u00fczerinde yazmak ister misin?
+dialog.exportkml.text=Verinin ba\u015fl\u0131\u011f\u0131
+dialog.exportkml.altitude=Absolut y\u00fckseklikleri (u\u00e7u\u015f i\u00e7in)
+dialog.exportkml.kmz=kmz dosyas\u0131 olu\u015fturmak i\u00e7in s\u0131k\u0131\u015ft\u0131r
+dialog.exportkml.exportimages=Fotolar\u0131n t\u0131rnak resimleri kmz dosyada dahil et
+dialog.exportkml.trackcolour=\u0130z rengi
+dialog.exportgpx.name=Ad\u0131
+dialog.exportgpx.desc=A\u00e7\u0131klama
+dialog.exportgpx.includetimestamps=Tarih ve saat dahil et
+dialog.exportgpx.copysource=Kaynak xml'i kopyala
+dialog.exportpov.font=Yaz\u0131tipi
+dialog.exportpov.camerax=Kamera X
+dialog.exportpov.cameray=Kamera Y
+dialog.exportpov.cameraz=Kamera Z
+dialog.pointtype.track=\u0130z noktalar
+dialog.pointtype.waypoint=Noktalar (POI)
+dialog.undo.title=Geri al
+dialog.undo.pretext=Geri alacaklar\u0131 se\u00e7
+dialog.undo.none.title=Geri alacak bir \u015fey yok
+dialog.undo.none.text=Geri alacak bir \u015fey yok!
+dialog.clearundo.title=Geri alma listesi s\u0131f\u0131rla
+dialog.clearundo.text=Ger\u00e7ekten geri alma listesi s\u0131f\u0131rlamak ister misin?\nGeri alma bilgileri tamamen silinecektir!
+dialog.pointedit.title=Nokta d\u00fczenle
+dialog.pointedit.table.field=Alan
+dialog.pointedit.table.value=De\u011fer
+dialog.pointedit.table.changed=De\u011fi\u015fmi\u015f
+dialog.pointedit.changevalue.text=Yeni de\u011feri gir
+dialog.pointedit.changevalue.title=Alan d\u00fczenle
+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.addtimeoffset.add=Zaman ekle
+dialog.addtimeoffset.subtract=Zaman \u00e7\u0131kart
+dialog.addtimeoffset.days=G\u00fcn
+dialog.addtimeoffset.hours=Saat
+dialog.addtimeoffset.minutes=Dakika
+dialog.findwaypoint.search=Ara
+dialog.saveexif.title=Exif kaydet
+dialog.saveexif.table.photoname=Foto ad\u0131
+dialog.saveexif.table.status=Durum
+dialog.saveexif.table.save=Kaydet
+dialog.saveexif.photostatus.connected=Ba\u011fland\u0131
+dialog.saveexif.photostatus.disconnected=Ba\u011flant\u0131 kesildi
+dialog.saveexif.photostatus.modified=De\u011fi\u015ftirildi
+dialog.saveexif.overwrite=Dosyalar\u0131n \u00fczerinde yaz
+dialog.saveexif.force=Ufak hatalar\u0131 bo\u015fver
+dialog.charts.xaxis=X axis
+dialog.charts.yaxis=Y axis
+dialog.charts.output=Ç\u0131kt\u0131
+dialog.charts.screen=Ekranda g\u00f6ster
+dialog.charts.svg=SVG dosya olarak g\u00f6ster
+dialog.charts.svgwidth=SVG geni\u015fli\u011fi
+dialog.charts.svgheight=SVG y\u00fcksekli\u011fi
+dialog.setmapbg.mapnik=Mapnik (default)
+dialog.setmapbg.osma=Osma
+dialog.setmapbg.cyclemap=Cyclemap
+dialog.setmapbg.other=Di\u011fer
+dialog.setmapbg.server=Sunucu URL
+dialog.gpsies.column.name=Yol ad\u0131
+dialog.gpsies.column.length=Uzunlu\u011fu
+dialog.gpsies.description=A\u00e7\u0131klama
+dialog.gpsies.nodescription=A\u00e7\u0131klama yok
+dialog.gpsies.nonefound=Herhangi bir yol bulunmad\u0131
+dialog.correlate.photoselect.photoname=Foto ad\u0131
+dialog.correlate.photoselect.photolater=Foto sonra
+dialog.correlate.options.offset.hours=saat,
+dialog.correlate.options.offset.minutes=dakika ve
+dialog.correlate.options.offset.seconds=saniye
+dialog.correlate.options.photolater=Foto noktadan sonra
+dialog.correlate.options.pointlater=Nokta fotodan sonra
+dialog.pastecoordinates.coords=Koordinatlar
+dialog.help.help=Ayr\u0131nt\u0131l\u0131 bilgi ve kullanma k\u0131lavuzu i\u00e7in l\u00fctfen\n http://activityworkshop.net/software/prune/\n sitesinde bak.
+dialog.about.version=S\u00fcr\u00fcm
+dialog.about.build=Build
+dialog.about.summarytext1=Prune GPS ayg\u0131tlardan veri y\u00fckler, g\u00f6r\u00fcnt\u00fcler ver d\u00fczenler bir uygulamad\u0131r.
+dialog.about.summarytext3=Ayr\u0131nt\u0131l\u0131 bilgi ve kullanma k\u0131lavuzu i\u00e7in l\u00fctfen\n <code style="font-weight:bold">http://activityworkshop.net/</code> sitesinde bak.
+dialog.about.languages=Prune ile kullanabilir diller
+dialog.about.translatedby=Turkish text by katpatuka
+dialog.about.systeminfo=Sistem bilgisi
+dialog.about.systeminfo.os=\u0130\u015fletim Sistemi
+dialog.about.systeminfo.java=Java Runtime
+dialog.about.systeminfo.java3d=Java3d kuruldu
+dialog.about.systeminfo.povray=Povray kuruldu
+dialog.about.systeminfo.exiftool=Exiftool kuruldu
+dialog.about.systeminfo.gpsbabel=Gpsbabel kuruldu
+dialog.about.systeminfo.gnuplot=Gnuplot kuruldu
+dialog.about.yes=Evet
+dialog.about.no=Hay\u0131r
+dialog.about.credits.translators=Çevirmen
+dialog.about.credits.thanks=Te\u015fekk\u00fcrler
+dialog.about.readme=Beni oku
+dialog.checkversion.uptodate=Prune'nin so s\u00fcr\u00fcm\u00fc kullan\u0131yorsun.
+dialog.checkversion.newversion1=Prune'nin yeni bir s\u00fcr\u00fcm\u00fc \u00e7\u0131kt\u0131! Son s\u00fcr\u00fcm \u015fimdi
+dialog.checkversion.newversion2=.
+dialog.checkversion.releasedate1=Yeni s\u00fcr\u00fcm\u00fcn\u00fcn devir tarihi
+dialog.checkversion.releasedate2=.
+dialog.checkversion.download=Yeni s\u00fcr\u00fcm indirmek i\u00e7in http://activityworkshop.net/software/prune/download.html adresine git.
+dialog.keys.intro=Fare yerinde a\u015fa\u011f\u0131daki k\u0131sayol tu\u015flar\u0131 kullanabilirsin:
+dialog.keys.keylist=<table><tr><td>Ok tu\u015flar\u0131</td><td>Haritay\u0131 sola/sa\u011fa/a\u015fa\u011f\u0131/yukar\u0131 kayd\u0131r</td></tr><tr><td>Ctrl + sol, sa\u011f</td><td>\u00d6nceki/sonraki noktay\u0131 se\u00e7</td></tr><tr><td>Ctrl + yukar/a\u015fa\u011f\u0131</td><td>Yak\u0131nla\u015ft\u0131r/Uzakla\u015ft\u0131r</td></tr><tr><td>Del</td><td>Se\u00e7ili noltay\u0131 sil</td></tr></table>
+dialog.saveconfig.desc=A\u011fa\u015f\u0131daki ayarlar\u0131 bir dasyada kaydedilir:
+dialog.saveconfig.prune.trackdirectory=\u0130z klas\u00f6r\u00fc
+dialog.saveconfig.prune.photodirectory=Foto klas\u00f6r\u00fc
+dialog.saveconfig.prune.languagecode=Dil kodu (TR)
+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
+dialog.saveconfig.prune.mapserverindex=Harita sunucunun index
+dialog.saveconfig.prune.mapserverurl=Harita sunucunun adresi
+dialog.saveconfig.prune.showpace=H\u0131z\u0131 g\u00f6r\u00fcnt\u00fcle
+dialog.saveconfig.prune.kmzimagewidth=KMZ resim geni\u015fli\u011fi
+dialog.saveconfig.prune.kmzimageheight=KMZ resim y\u00fcksekli\u011fi
+dialog.setpaths.intro=\u0130ste\u011fe ba\u011fl\u0131 a\u015fa\u011f\u0131daki uygulamalar\u0131n veriyolu kaydedebilirsin:
+dialog.addaltitude.noaltitudes=Se\u00e7ili s\u0131rada y\u00fckseklik bilgisi bulunmad\u0131
+dialog.addaltitude.desc=Eklenecek y\u00fckseklik ofseti
+dialog.setcolours.background=Arkafonu
+dialog.setcolours.borders=Kenarlar
+dialog.setcolours.lines=Çizgiler
+dialog.setcolours.primary=Birincil
+dialog.setcolours.secondary=\u0130kincil
+dialog.setcolours.point=Noktalar
+dialog.setcolours.selection=Se\u00e7im
+dialog.setcolours.text=Metin
+dialog.colourchooser.title=Rengi se\u00e7
+dialog.colourchooser.red=K\u0131rm\u0131z\u0131
+dialog.colourchooser.green=Ye\u015fil
+dialog.colourchooser.blue=Mavi
+
+# Confirm messages || These are displayed as confirmation in the status bar
+confirm.save.ok1=Ba\u011far\u0131yla kaydedildi
+confirm.save.ok2=points to file
+confirm.mergetracksegments=\u0130z par\u00e7alar\u0131 birle\u015ftirildi
+
+# Buttons || These are all the texts for buttons
+button.ok=Tamam
+button.back=Geri
+button.next=\u0130leri
+button.finish=Son
+button.cancel=\u0130ptal
+button.overwrite=\u00dczerinde yaz
+button.moveup=Yukar\u0131
+button.movedown=A\u015fa\u011f\u0131
+button.showlines=Çizgiler g\u00f6r\u00fcnt\u00fcle
+button.edit=D\u00fczenle
+button.exit=Ç\u0131k\u0131\u015f
+button.close=Kapat
+button.continue=Devam
+button.yes=Evet
+button.no=Hay\u0131r
+button.yestoall=Hepsini evet
+button.notoall=Hepsini hay\u0131r
+button.select=Se\u00e7
+button.selectall=Hepsini se\u00e7
+button.selectnone=Hi\u00e7 se\u00e7me
+button.preview=\u00d6ng\u00f6r\u00fcn\u00fcm
+button.load=Y\u00fckle
+button.guessfields=Alanlar\u0131 tahmin et
+button.showwebpage=Websayfas\u0131 g\u00f6r\u00fcnt\u00fcle
+button.check=Denetle
+
+# File types
+filetype.txt=TXT dosyalar\u0131
+filetype.jpeg=JPG dosyalar\u0131
+filetype.kmlkmz=KML, KMZ dosyalar\u0131
+filetype.kml=KML dosyalar\u0131
+filetype.kmz=KMZ dosyalar\u0131
+filetype.gpx=GPX dosyalar\u0131
+filetype.pov=POV dosyalar\u0131
+filetype.svg=SVG dosyalar\u0131
+
+# Display components || These are all for the side panels showing point/range details
+display.nodata=Hergangi veri y\u00fcklenmedi
+display.noaltitudes=Track verisinde y\u00fckseklik bilgisi yok
+details.trackdetails=\u0130z ayr\u0131nt\u0131lar\u0131
+details.notrack=Herhangi track y\u00fcklenmedi
+details.track.points=Noktalar
+details.track.file=Dosya
+details.track.numfiles=Dosya say\u0131s\u0131
+details.pointdetails=Nokta ayr\u0131nt\u0131lar\u0131
+details.index.selected=Endeks
+details.index.of=toplam:
+details.nopointselection=Herhangi nokta se\u00e7ili de\u011fil
+details.photofile=Foto dosyas\u0131
+details.norangeselection=Herhangi s\u0131ra se\u00e7ili de\u011fil
+details.rangedetails=S\u0131ra ayr\u0131nt\u0131lar\u0131
+details.range.selected=Se\u00e7ili
+details.range.to=-
+details.altitude.to=-
+details.range.climb=T\u0131rman\u0131\u015f
+details.range.descent=\u0130ni\u015f
+details.coordformat=Koordinat bi\u00e7imi
+details.distanceunits=Uzakl\u0131k birimi
+display.range.time.secs=san
+display.range.time.mins=dak
+display.range.time.hours=saat
+display.range.time.days=g\u011fn
+details.range.avespeed=Ortalama h\u0131z\u0131
+details.range.avemovingspeed=Ortalama hareketi
+details.waypointsphotos.waypoints=Noktalar
+details.waypointsphotos.photos=Fotolar
+details.photodetails=Foto ayr\u0131nt\u0131lar\u0131
+details.nophoto=Herhangi foto se\u00e7ili de\u011fil
+details.photo.loading=Y\u00fckleniyor
+details.photo.connected=Ba\u011fland\u0131
+map.overzoom=Fazla yak\u0131nla\u015ft\u0131n salak - harita g\u00f6r\u00fcnt\u00fclenmiyor
+
+# Field names
+fieldname.latitude=Enlem (lat)
+fieldname.longitude=Boylam (lon)
+fieldname.altitude=Y\u00fckseklik
+fieldname.timestamp=Zaman
+fieldname.time=Zaman
+fieldname.waypointname=Ad\u0131
+fieldname.waypointtype=T\u00fcr
+fieldname.newsegment=Par\u00e7a
+fieldname.custom=Di\u011fer
+fieldname.prefix=Alan
+fieldname.distance=Uzakl\u0131k
+fieldname.duration=S\u00fcre
+fieldname.speed=H\u0131z
+fieldname.verticalspeed=Dikey h\u0131z\u0131
+
+# Measurement units
+units.original=Orijinal
+units.default=Varsay\u0131lan
+units.metres=Metre
+units.metres.short=m
+units.feet=Ayak
+units.feet.short=ft
+units.kilometres=Kilometre
+units.kilometres.short=km
+units.kmh=km/h
+units.miles=Mil
+units.miles.short=mi
+units.mph=mph
+units.metrespersec=m/s
+units.feetpersec=ft/s
+units.hours=saat
+units.degminsec=Derece/Dakika/Saniye
+units.degmin=Derece/Dakika
+units.deg=Derece
+units.iso8601=ISO 8601
+
+# External urls
+url.googlemaps=maps.google.com
+
+# Cardinals for 3d plots
+cardinal.n=K
+cardinal.s=G
+cardinal.e=D
+cardinal.w=B
+
+# Undo operations || These will be displayed in the undo list after you've performed the operation, to tell you what you did
+undo.load=veri y\u00fckle
+undo.loadphotos=fotolar y\u00fckle
+undo.editpoint=noktay\u0131 d\u00fczenle
+undo.deletepoint=noktay\u0131 sil
+undo.deletephoto=foto kald\u0131r
+undo.deleterange=s\u0131ra sil
+undo.compress=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
+undo.addtimeoffset=zaman de\u011fi\u015ftir
+undo.addaltitudeoffset=y\u00fckseklik de\u011fi\u015ftir
+undo.rearrangewaypoints=noktalar\u0131 yeniden diz
+undo.cutandmove=par\u00e7as\u0131 ta\u015f\u0131
+undo.connectphoto=fotoyu ba\u011flan
+undo.disconnectphoto=fotonun ba\u011flant\u0131s\u0131 kes
+undo.correlate=fotolar\u0131n ba\u011fl\u0131la\u015f\u0131m\u0131
+undo.rearrangephotos=fotolar\u0131 yeniden diz
+undo.createpoint=noktay\u0131 olu\u015ftur
+undo.rotatephoto=fotoyu d\u00f6nder
menu.map.showmap=\u663e\u793a\u5730\u56fe
menu.map.showscalebar=\u663e\u793a\u6bd4\u4f8b\u5c3a
-# Alt keys for menus
-altkey.menu.file=
-altkey.menu.edit=
-altkey.menu.select=
-altkey.menu.view=
-altkey.menu.photo=
-altkey.menu.settings=
-altkey.menu.help=
-
-# Ctrl shortcuts for menu items
-shortcut.menu.file.open=
-shortcut.menu.file.load=
-shortcut.menu.file.save=
-shortcut.menu.edit.undo=
-shortcut.menu.edit.compress=
-shortcut.menu.select.all=
-shortcut.menu.help.help=
-
# Functions
function.loadfromgps=\u4eceGPS\u5bfc\u5165
function.sendtogps=\u53d1\u9001\u81f3GPS
function.charts=\u9ad8\u5ea6\u901f\u5ea6\u56fe\u8868
function.show3d=3-D\u89c6\u56fe
function.distances=\u8ddd\u79bb
-function.getgpsies=Gpsies\u8f68\u8ff9
-function.correlatephotos=\u94fe\u63a5\u76f8\u7247
function.setmapbg=\u80cc\u666f\u5730\u56fe
-function.setkmzimagesize=
+function.setkmzimagesize=\u8bbe\u7f6eKMZ\u56fe\u50cf\u5c3a\u5bf8
function.setpaths=\u8bbe\u7f6e\u7a0b\u5e8f\u8def\u5f84
+function.getgpsies=Gpsies\u8f68\u8ff9
+function.correlatephotos=\u94fe\u63a5\u76f8\u7247
function.help=\u5e2e\u52a9
function.showkeys=\u663e\u793a\u5feb\u6377\u952e
function.about=\u5173\u4e8ePrune
dialog.charts.svgwidth=SVG\u5bbd\u5ea6
dialog.charts.svgheight=SVG\u9ad8\u5ea6
dialog.charts.needaltitudeortimes=\u8f68\u8ff9\u5fc5\u987b\u542b\u6709\u9ad8\u5ea6\u6216\u65f6\u95f4\u4fe1\u606f
-dialog.charts.gnuplotpath=gnuplot\u8def\u5f84
dialog.charts.gnuplotnotfound=\u8def\u5f84\u9519\u8bef\uff0c\u65e0\u6cd5\u627e\u5230gnuplot
dialog.distances.intro=\u822a\u70b9\u4e4b\u95f4\u76f4\u7ebf\u8ddd\u79bb
dialog.distances.column.from=\u4ece\u6b64\u70b9
dialog.gpsies.column.length=\u957f\u5ea6
dialog.gpsies.description=\u63cf\u8ff0
dialog.gpsies.nodescription=\u65e0\u63cf\u8ff0
-dialog.gpsies.nonefound=
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\n\u7ee7\u7eed\uff1f
dialog.correlate.photoselect.intro=\u9009\u62e9\u5df2\u94fe\u63a5\u76f8\u7247\u4f5c\u4e3a\u65f6\u95f4\u504f\u79fb
dialog.correlate.options.correlate=\u94fe\u63a5
dialog.correlate.alloutsiderange=\u65e0\u6cd5\u94fe\u63a5\uff0c\u6240\u6709\u76f8\u7247\u8d85\u51fa\u8f68\u8ff9\u65f6\u95f4\u8303\u56f4\n\u8bf7\u6539\u53d8\u65f6\u95f4\u504f\u79fb\u6216\u624b\u52a8\u94fe\u63a5\u81f3\u5c11\u4e00\u5f20\u76f8\u7247
dialog.compress.nonefound=\u65e0\u6cd5\u5220\u9664\u6570\u636e\u70b9
-dialog.compress.duplicates.title=\u91cd\u590d\u70b9\u5220\u9664
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.wackypoints.paramdesc=\u8ddd\u79bb\u7cfb\u6570
dialog.compress.singletons.title=\u79bb\u6563\u70b9\u5220\u9664
dialog.compress.singletons.paramdesc=\u8ddd\u79bb\u7cfb\u6570
+dialog.compress.duplicates.title=\u91cd\u590d\u70b9\u5220\u9664
dialog.compress.summarylabel=\u8981\u5220\u9664\u7684\u70b9
dialog.help.help=\u66f4\u591a\u4fe1\u606f\u548c\u7528\u6cd5\uff0c\u8bf7\u53c2\u8003\u7f51\u7ad9\nhttp://activityworkshop.net/software/prune///
dialog.about.version=\u7248\u672c
dialog.checkversion.releasedate2=
dialog.checkversion.download=\u4e0b\u8f7d\u6700\u65b0\u7248\u672c\uff0c\u8bf7\u767b\u9646\u7f51\u7ad9\uff1a\nhttp://activityworkshop.net/software/prune/download.html
dialog.keys.intro=\u53ef\u7528\u4e0b\u5217\u5feb\u6377\u952e\u66ff\u4ee3\u9f20\u6807
-dialog.keys.keylist=
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.mapserverindex=\u80cc\u666f\u5730\u56fe\u7801(1-4)
dialog.saveconfig.prune.mapserverurl=\u90094\u65f6\u5730\u56fe\u670d\u52a1\u5668URL
dialog.saveconfig.prune.showpace=\u663e\u793a\u6b65\u901f
-dialog.saveconfig.prune.kmzimagewidth=
-dialog.saveconfig.prune.kmzimageheight=
+dialog.saveconfig.prune.kmzimagewidth=KMZ\u56fe\u50cf\u5bbd\u5ea6
+dialog.saveconfig.prune.kmzimageheight=KMZ\u56fe\u50cf\u9ad8\u5ea6
dialog.setpaths.intro=\u82e5\u9700\u8981\uff0c\u53ef\u8bbe\u5b9a\u5916\u6302\u7a0b\u5e8f\u8def\u5f84
dialog.addaltitude.noaltitudes=\u8f68\u8ff9\u4e0d\u542b\u9ad8\u5ea6\u4fe1\u606f
dialog.addaltitude.desc=\u9ad8\u5ea6\u504f\u79fb
confirm.mergetracksegments=\u5df2\u5408\u5e76\u7684\u8f68\u8ff9\u6bb5
confirm.reverserange=\u53cd\u5411\u7684\u8303\u56f4
confirm.addtimeoffset=\u5df2\u52a0\u4e0a\u65f6\u95f4\u504f\u5dee
-confirm.addaltitudeoffset=
confirm.rearrangewaypoints=\u91cd\u65b0\u914d\u7f6e\u7684\u822a\u70b9
confirm.cutandmove=\u5df2\u79fb\u52a8\u7684\u8f68\u8ff9\u6bb5
confirm.saveexif.ok1=\u5df2\u4fdd\u5b58
confirm.createpoint=\u5df2\u521b\u5efa\u70b9
confirm.running=\u8bf7\u7a0d\u7b49...
-# Buttons
+# Buttons || These are all the texts for buttons
button.ok=\u786e\u5b9a
button.back=\u8fd4\u56de
button.next=\u4e0b\u4e00\u6b65
button.no=\u5426
button.yestoall=\u5168\u90e8\u662f
button.notoall=\u5168\u90e8\u5426
+button.select=\u9009\u62e9
button.selectall=\u5168\u9009
button.selectnone=\u5168\u4e0d\u9009
button.preview=\u9884\u89c8
filetype.pov=POV\u6587\u4ef6
filetype.svg=SVG\u6587\u4ef6
-# Display components
+# Display components || These are all for the side panels showing point/range details
display.nodata=\u65e0\u6570\u636e
display.noaltitudes=\u8f68\u8ff9\u6570\u636e\u4e0d\u542b\u9ad8\u5ea6\u4fe1\u606f
details.trackdetails=\u8f68\u8ff9\u4fe1\u606f
cardinal.e=E
cardinal.w=W
-# Undo operations
+# Undo operations || These will be displayed in the undo list after you've performed the operation, to tell you what you did
undo.load=\u5bfc\u5165\u6570\u636e
undo.loadphotos=\u5bfc\u5165\u76f8\u7247
undo.editpoint=\u7f16\u8f91\u8f68\u8ff9\u70b9
fields[f] = Field.NEW_SEGMENT;
continue;
}
+ // check for waypoint type
+ if (!checkArrayHasField(fields, Field.WAYPT_TYPE) && fieldLooksLikeWaypointType(value, isHeader))
+ {
+ fields[f] = Field.WAYPT_TYPE;
+ continue;
+ }
}
}
// Fill in the rest of the fields using just custom fields
else if (!checkArrayHasField(fields, Field.LONGITUDE)) {
fields[1] = Field.LONGITUDE;
}
+ // Longitude _could_ have overwritten latitude in position 1
+ if (!checkArrayHasField(fields, Field.LATITUDE)) {
+ fields[0] = Field.LATITUDE;
+ }
return fields;
}
return false;
}
}
+
+ /**
+ * Check whether the given String looks like a waypoint type
+ * @param inValue value from file
+ * @param inIsHeader true if this is a header line, false for data
+ * @return true if it could be a waypoint type
+ */
+ private static boolean fieldLooksLikeWaypointType(String inValue, boolean inIsHeader)
+ {
+ if (inValue == null || inValue.equals("")) {return false;}
+ if (inIsHeader)
+ {
+ String upperValue = inValue.toUpperCase();
+ // This is a header line so look for english or local text
+ return (upperValue.equals("TYPE")
+ || upperValue.equals(I18nManager.getText("fieldname.waypointtype").toUpperCase()));
+ }
+ else
+ {
+ // can't reliably identify it just using the value
+ return false;
+ }
+ }
}
import javax.swing.JFrame;
import tim.prune.App;
-import tim.prune.Config;
+import tim.prune.config.Config;
+import tim.prune.load.xml.GzipFileLoader;
import tim.prune.load.xml.XmlFileLoader;
import tim.prune.load.xml.ZipFileLoader;
private NmeaFileLoader _nmeaFileLoader = null;
private XmlFileLoader _xmlFileLoader = null;
private ZipFileLoader _zipFileLoader = null;
+ private GzipFileLoader _gzipFileLoader = null;
/**
_nmeaFileLoader = new NmeaFileLoader(inApp);
_xmlFileLoader = new XmlFileLoader(inApp);
_zipFileLoader = new ZipFileLoader(inApp, _xmlFileLoader);
+ _gzipFileLoader = new GzipFileLoader(inApp, _xmlFileLoader);
}
// Use zip loader for zipped kml (or zipped gpx)
_zipFileLoader.openFile(inFile);
}
+ else if (fileExtension.endsWith(".gz") || fileExtension.equals("gzip"))
+ {
+ // Use gzip loader for gzipped xml
+ _gzipFileLoader.openFile(inFile);
+ }
else if (fileExtension.equals("nmea"))
{
_nmeaFileLoader.openFile(inFile);
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.io.BufferedReader;
+import java.io.File;
import java.io.InputStreamReader;
+import java.util.ArrayList;
import javax.swing.BorderFactory;
import javax.swing.BoxLayout;
import javax.swing.JProgressBar;
import javax.swing.JTextField;
import javax.swing.SwingConstants;
+import javax.swing.SwingUtilities;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
import tim.prune.App;
-import tim.prune.Config;
import tim.prune.ExternalTools;
import tim.prune.GenericFunction;
import tim.prune.I18nManager;
+import tim.prune.config.Config;
import tim.prune.data.Altitude;
+import tim.prune.data.SourceInfo;
import tim.prune.load.xml.XmlFileLoader;
import tim.prune.load.xml.XmlHandler;
+import tim.prune.save.GpxExporter;
/**
* Class to manage the loading of GPS data using GpsBabel
private JDialog _dialog = null;
private JTextField _deviceField = null, _formatField = null;
private JCheckBox _waypointCheckbox = null, _trackCheckbox = null;
+ private JCheckBox _saveCheckbox = null;
private JButton _okButton = null;
private JProgressBar _progressBar = null;
+ private File _saveFile = null;
private boolean _cancelled = false;
_trackCheckbox.addChangeListener(checkboxListener);
_trackCheckbox.setAlignmentX(Component.CENTER_ALIGNMENT);
mainPanel.add(_trackCheckbox);
+ // Checkbox for immediately saving to file
+ _saveCheckbox = new JCheckBox(I18nManager.getText("dialog.gpsload.save"));
+ _saveCheckbox.setAlignmentX(Component.CENTER_ALIGNMENT);
+ mainPanel.add(_saveCheckbox);
+
// progress bar (initially invisible)
_progressBar = new JProgressBar(0, 10);
mainPanel.add(_progressBar);
if (_waypointCheckbox.isSelected() || _trackCheckbox.isSelected())
{
_progressBar.setIndeterminate(true);
+ _saveFile = null;
try
{
- callGpsBabel(_waypointCheckbox.isSelected(), _trackCheckbox.isSelected());
+ callGpsBabel();
}
catch (Exception e)
{
- // System.err.println("Error: " + e.getClass().getName());
- // System.err.println("Error: " + e.getMessage());
_app.showErrorMessageNoLookup(getNameKey(), e.getMessage());
_cancelled = true;
}
/**
* Execute the call to gpsbabel and pass the results back to the app
- * @param inWaypoints true to load waypoints
- * @param inTracks true to load track points
*/
- private void callGpsBabel(boolean inWaypoints, boolean inTracks) throws Exception
+ private void callGpsBabel() throws Exception
{
// Set up command to call gpsbabel
- String[] commands = null;
final String device = _deviceField.getText().trim();
final String format = _formatField.getText().trim();
- final String command = Config.getConfigString(Config.KEY_GPSBABEL_PATH);
- if (inWaypoints && inTracks) {
- // Both waypoints and track points selected
- commands = new String[] {command, "-w", "-t", "-i", format,
- "-f", device, "-o", "gpx", "-F", "-"};
- }
- else
- {
- // Only waypoints OR track points selected
- commands = new String[] {command, "-w", "-i", format,
- "-f", device, "-o", "gpx", "-F", "-"};
- if (inTracks) {
- commands[1] = "-t";
- }
- }
+ String[] commands = getCommandArray(device, format);
// Save GPS settings in config
Config.setConfigString(Config.KEY_GPS_DEVICE, device);
Config.setConfigString(Config.KEY_GPS_FORMAT, format);
- String errorMessage = "";
+ String errorMessage = "", errorMessage2 = "";
XmlHandler handler = null;
Process process = Runtime.getRuntime().exec(commands);
+ String line = null;
- // Pass input stream to try to parse the xml
- try
+ if (_saveFile != null)
{
- XmlFileLoader xmlLoader = new XmlFileLoader(_app);
- SAXParser saxParser = SAXParserFactory.newInstance().newSAXParser();
- saxParser.parse(process.getInputStream(), xmlLoader);
- handler = xmlLoader.getHandler();
- if (handler == null) {
- errorMessage = "Null handler";
+ // data is being saved to file, so need to wait for it to finish
+ process.waitFor();
+ // try to read error message, if any
+ try {
+ BufferedReader r = new BufferedReader(new InputStreamReader(process.getErrorStream()));
+ while ((line = r.readLine()) != null) {
+ errorMessage += line + "\n";
+ }
+ // Close error stream
+ try {
+ r.close();
+ } catch (Exception e) {}
}
+ catch (Exception e) {} // couldn't get error message
+
+ // Trigger it to be loaded by app
+ if (process.exitValue() == 0)
+ {
+ SwingUtilities.invokeLater(new Runnable() {
+ public void run() {
+ ArrayList<File> fileList = new ArrayList<File>();
+ fileList.add(_saveFile);
+ _app.loadDataFiles(fileList);
+ }
+ });
+ }
+ else if (errorMessage.length() > 0) {
+ throw new Exception(errorMessage);
+ }
+ else throw new Exception(I18nManager.getText("error.gpsload.unknown"));
}
- catch (Exception e) {
- errorMessage = e.getMessage();
- }
+ else
+ {
+ // Pass input stream to try to parse the xml
+ try
+ {
+ XmlFileLoader xmlLoader = new XmlFileLoader(_app);
+ SAXParser saxParser = SAXParserFactory.newInstance().newSAXParser();
+ saxParser.parse(process.getInputStream(), xmlLoader);
+ handler = xmlLoader.getHandler();
+ if (handler == null) {
+ errorMessage = "Null handler";
+ }
+ }
+ catch (Exception e) {
+ errorMessage = e.getMessage();
+ }
- // Read the error stream to see if there's a better error message there
- BufferedReader r = new BufferedReader(new InputStreamReader(process.getErrorStream()));
- String line = null;
- String errorMessage2 = "";
- while ((line = r.readLine()) != null) {
- errorMessage2 += line + "\n";
+ // Read the error stream to see if there's a better error message there
+ BufferedReader r = new BufferedReader(new InputStreamReader(process.getErrorStream()));
+ while ((line = r.readLine()) != null) {
+ errorMessage2 += line + "\n";
+ }
+ // Close error stream
+ try {
+ r.close();
+ } catch (Exception e) {}
+
+ if (errorMessage2.length() > 0) {errorMessage = errorMessage2;}
+ if (errorMessage.length() > 0) {throw new Exception(errorMessage);}
+
+ // Send data back to app
+ _app.informDataLoaded(handler.getFieldArray(), handler.getDataArray(), Altitude.Format.METRES,
+ new SourceInfo(_deviceField.getText(), SourceInfo.FILE_TYPE.GPSBABEL));
}
- // Close error stream
- try {
- r.close();
- } catch (Exception e) {}
+ }
- if (errorMessage2.length() > 0) {errorMessage = errorMessage2;}
- if (errorMessage.length() > 0) {throw new Exception(errorMessage);}
- // Send data back to app
- _app.informDataLoaded(handler.getFieldArray(), handler.getDataArray(),
- Altitude.Format.METRES, _deviceField.getText());
+ /**
+ * Get the commands to call
+ * @param inDevice device name to use
+ * @param inFormat format to use
+ * @return String array containing commands
+ */
+ private String[] getCommandArray(String inDevice, String inFormat)
+ {
+ String[] commands = null;
+ final String command = Config.getConfigString(Config.KEY_GPSBABEL_PATH);
+ final boolean loadWaypoints = _waypointCheckbox.isSelected();
+ final boolean loadTrack = _trackCheckbox.isSelected();
+ if (loadWaypoints && loadTrack) {
+ // Both waypoints and track points selected
+ commands = new String[] {command, "-w", "-t", "-i", inFormat,
+ "-f", inDevice, "-o", "gpx", "-F", "-"};
+ }
+ else
+ {
+ // Only waypoints OR track points selected
+ commands = new String[] {command, "-w", "-i", inFormat,
+ "-f", inDevice, "-o", "gpx", "-F", "-"};
+ if (loadTrack) {
+ commands[1] = "-t";
+ }
+ }
+ // Do we want to save the gpx straight to file?
+ if (_saveCheckbox.isSelected()) {
+ // Select file to save to
+ _saveFile = GpxExporter.chooseGpxFile(_parentFrame);
+ if (_saveFile != null) {
+ commands[commands.length-1] = _saveFile.getAbsolutePath();
+ }
+ }
+ return commands;
}
}
import javax.swing.JProgressBar;
import tim.prune.App;
-import tim.prune.Config;
import tim.prune.I18nManager;
+import tim.prune.config.Config;
import tim.prune.data.Altitude;
import tim.prune.data.DataPoint;
import tim.prune.data.LatLonRectangle;
if (_fileChooser.showOpenDialog(_parentFrame) == JFileChooser.APPROVE_OPTION)
{
// Bring up dialog before starting
- showDialog();
+ if (_progressDialog == null) {
+ createProgressDialog();
+ }
+ // reset dialog and show it
+ _progressBar.setValue(0);
+ _progressBar.setString("");
+ _progressDialog.setVisible(true);
+ // start thread for processing
new Thread(this).start();
}
}
/**
- * Show the main dialog
+ * Create the dialog to show the progress
*/
- private void showDialog()
+ private void createProgressDialog()
{
_progressDialog = new JDialog(_parentFrame, I18nManager.getText("dialog.jpegload.progress.title"));
_progressDialog.setLocationRelativeTo(_parentFrame);
panel.add(cancelButton);
_progressDialog.getContentPane().add(panel);
_progressDialog.pack();
- _progressDialog.setVisible(true);
}
// Process the files recursively and build lists of photos
processFileList(files, true, _subdirCheckbox.isSelected());
_progressDialog.setVisible(false);
+ _progressDialog.dispose(); // Sometimes dialog doesn't disappear without this dispose
if (_cancelled) {return;}
//System.out.println("Finished - counts are: " + _fileCounts[0] + ", " + _fileCounts[1]
if (inFiles != null)
{
// Loop over elements in array
- for (int i=0; i<inFiles.length; i++)
+ for (int i=0; i<inFiles.length && !_cancelled; i++)
{
File file = inFiles[i];
if (file.exists() && file.canRead())
processFileList(files, false, inDescend);
}
}
- else
- {
- // file doesn't exist or isn't readable - ignore error
- }
- // check for cancel button pressed
- if (_cancelled) break;
+ // if file doesn't exist or isn't readable - ignore
}
}
}
photo.setTimestamp(createTimestamp(jpegData.getOriginalTimestamp()));
}
photo.setExifThumbnail(jpegData.getThumbnailImage());
+ // Also extract orientation tag for setting rotation state of photo
+ photo.setRotation(jpegData.getRequiredRotation());
}
catch (JpegException jpe) { // don't list errors, just count them
}
*/
private static Timestamp createTimestamp(Rational[] inDate, Rational[] inTime)
{
- //System.out.println("Making timestamp for date (" + inDate[0].toString() + "," + inDate[1].toString() + "," + inDate[2].toString() + ") and time ("
- // + inTime[0].toString() + "," + inTime[1].toString() + "," + inTime[2].toString() + ")");
return new Timestamp(inDate[0].intValue(), inDate[1].intValue(), inDate[2].intValue(),
inTime[0].intValue(), inTime[1].intValue(), inTime[2].intValue());
}
import tim.prune.App;
import tim.prune.data.Altitude;
import tim.prune.data.Field;
+import tim.prune.data.SourceInfo;
/**
* Class to handle the loading of Nmea files
if (messages.size() > 0)
{
_app.informDataLoaded(getFieldArray(), makeDataArray(messages),
- Altitude.Format.METRES, inFile.getName());
+ Altitude.Format.METRES, new SourceInfo(inFile, SourceInfo.FILE_TYPE.NMEA));
}
}
import tim.prune.I18nManager;
import tim.prune.data.Altitude;
import tim.prune.data.Field;
+import tim.prune.data.SourceInfo;
/**
}
_lastAltitudeFormat = altitudeFormat;
// give data to App
+ SourceInfo sourceInfo = new SourceInfo(_file, SourceInfo.FILE_TYPE.TEXT);
_app.informDataLoaded(_fieldTableModel.getFieldArray(),
- _fileExtractTableModel.getData(), altitudeFormat,
- _file.getName());
+ _fileExtractTableModel.getData(), altitudeFormat, sourceInfo);
// clear up file cacher
_fileCacher.clear();
// dispose of dialog
private boolean _insideName = false;
private boolean _insideElevation = false;
private boolean _insideTime = false;
-// private boolean _insideType = false;
+ private boolean _insideType = false;
private boolean _startSegment = true;
private String _name = null, _latitude = null, _longitude = null;
private String _elevation = null;
private String _time = null;
-// private String _type = null;
+ private String _type = null;
private ArrayList<String[]> _pointList = new ArrayList<String[]>();
- // FIXME: Read waypoint type too
-
/**
* Receive the start of a tag
* @see org.xml.sax.ContentHandler#startElement(java.lang.String, java.lang.String, java.lang.String, org.xml.sax.Attributes)
Attributes attributes) throws SAXException
{
// Read the parameters for waypoints and track points
- if (qName.equalsIgnoreCase("wpt") || qName.equalsIgnoreCase("trkpt"))
+ if (qName.equalsIgnoreCase("wpt") || qName.equalsIgnoreCase("trkpt") || qName.equalsIgnoreCase("rtept"))
{
_insideWaypoint = qName.equalsIgnoreCase("wpt");
int numAttributes = attributes.getLength();
_elevation = null;
_name = null;
_time = null;
+ _type = null;
}
else if (qName.equalsIgnoreCase("ele"))
{
{
_insideTime = true;
}
-// else if (qName.equalsIgnoreCase("type"))
-// {
-// _insideType = true;
-// }
+ else if (qName.equalsIgnoreCase("type"))
+ {
+ _insideType = true;
+ }
else if (qName.equalsIgnoreCase("trkseg"))
{
_startSegment = true;
public void endElement(String uri, String localName, String qName)
throws SAXException
{
- if (qName.equalsIgnoreCase("wpt") || qName.equalsIgnoreCase("trkpt"))
+ if (qName.equalsIgnoreCase("wpt") || qName.equalsIgnoreCase("trkpt") || qName.equalsIgnoreCase("rtept"))
{
processPoint();
}
{
_insideTime = false;
}
+ else if (qName.equalsIgnoreCase("type"))
+ {
+ _insideType = false;
+ }
super.endElement(uri, localName, qName);
}
if (_insideName && _insideWaypoint) {_name = checkCharacters(_name, value);}
else if (_insideElevation) {_elevation = checkCharacters(_elevation, value);}
else if (_insideTime) {_time = checkCharacters(_time, value);}
+ else if (_insideType) {_type = checkCharacters(_type, value);}
super.characters(ch, start, length);
}
private void processPoint()
{
// Put the values into a String array matching the order in getFieldArray()
- String[] values = new String[6];
+ String[] values = new String[7];
values[0] = _latitude; values[1] = _longitude;
values[2] = _elevation; values[3] = _name;
values[4] = _time;
values[5] = "1";
_startSegment = false;
}
+ values[6] = _type;
_pointList.add(values);
}
public Field[] getFieldArray()
{
final Field[] fields = {Field.LATITUDE, Field.LONGITUDE, Field.ALTITUDE,
- Field.WAYPT_NAME, Field.TIMESTAMP, Field.NEW_SEGMENT};
+ Field.WAYPT_NAME, Field.TIMESTAMP, Field.NEW_SEGMENT, Field.WAYPT_TYPE};
return fields;
}
--- /dev/null
+package tim.prune.load.xml;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.util.zip.GZIPInputStream;
+import javax.xml.parsers.SAXParser;
+import javax.xml.parsers.SAXParserFactory;
+import tim.prune.App;
+import tim.prune.I18nManager;
+import tim.prune.data.Altitude;
+import tim.prune.data.SourceInfo;
+
+/**
+ * Class to handle the loading of gzipped xml files
+ */
+public class GzipFileLoader
+{
+ /** App for callback of file loading */
+ private App _app = null;
+ /** Object to do the handling of the xml */
+ XmlFileLoader _xmlLoader = null;
+
+ /**
+ * Constructor
+ * @param inApp App object
+ * @param inXmlLoader object to do the xml handling
+ */
+ public GzipFileLoader(App inApp, XmlFileLoader inXmlLoader)
+ {
+ _app = inApp;
+ _xmlLoader = inXmlLoader;
+ }
+
+ /**
+ * Open the selected file and select appropriate xml loader
+ * @param inFile File to open
+ */
+ public void openFile(File inFile)
+ {
+ GZIPInputStream istream = null;
+ try
+ {
+ istream = new GZIPInputStream(new FileInputStream(inFile));
+ _xmlLoader.reset();
+ SAXParser saxParser = SAXParserFactory.newInstance().newSAXParser();
+ saxParser.parse(istream, _xmlLoader);
+ XmlHandler handler = _xmlLoader.getHandler();
+ if (handler == null) {
+ _app.showErrorMessage("error.load.dialogtitle", "error.load.noread");
+ }
+ else {
+ // Send back to app
+ SourceInfo sourceInfo = new SourceInfo(inFile,
+ (handler instanceof GpxHandler?SourceInfo.FILE_TYPE.GPX:SourceInfo.FILE_TYPE.KML));
+ _app.informDataLoaded(handler.getFieldArray(), handler.getDataArray(),
+ Altitude.Format.METRES, sourceInfo);
+ }
+ }
+ catch (Exception e) {
+ // Error occurred, could be a non-xml file borking the parser
+ _app.showErrorMessageNoLookup("error.load.dialogtitle",
+ I18nManager.getText("error.load.othererror") + " " + e.getClass().getName());
+ // It would be nice to verify the filename of the file inside the gz,
+ // but the java classes don't give access to this information
+ }
+ finally {
+ try {
+ istream.close();
+ }
+ catch (Exception e2) {}
+ }
+ }
+}
import tim.prune.App;
import tim.prune.I18nManager;
import tim.prune.data.Altitude;
+import tim.prune.data.SourceInfo;
/**
* Class for handling loading of Xml files, and passing the
else
{
// Pass information back to app
+ SourceInfo sourceInfo = new SourceInfo(_file,
+ (_handler instanceof GpxHandler?SourceInfo.FILE_TYPE.GPX:SourceInfo.FILE_TYPE.KML));
_app.informDataLoaded(_handler.getFieldArray(), _handler.getDataArray(),
- Altitude.Format.METRES, _file.getName());
+ Altitude.Format.METRES, sourceInfo);
}
}
catch (Exception e)
import tim.prune.App;
import tim.prune.data.Altitude;
+import tim.prune.data.SourceInfo;
/**
* Class to handle the loading of zipped xml files
}
else {
// Send back to app
+ SourceInfo sourceInfo = new SourceInfo(inFile,
+ (handler instanceof GpxHandler?SourceInfo.FILE_TYPE.GPX:SourceInfo.FILE_TYPE.KML));
_app.informDataLoaded(handler.getFieldArray(), handler.getDataArray(),
- Altitude.Format.METRES, inFile.getName());
+ Altitude.Format.METRES, sourceInfo);
xmlFound = true;
}
}
else {
// Send back to app
_app.informDataLoaded(handler.getFieldArray(), handler.getDataArray(),
- Altitude.Format.METRES, "gpsies");
+ Altitude.Format.METRES, new SourceInfo("gpsies", SourceInfo.FILE_TYPE.GPSIES));
xmlFound = true;
}
}
-Prune version 8
+Prune version 9
===============
Prune is an application for viewing, editing and managing coordinate data from GPS systems,
including format conversion, charting and photo correlation.
Full details can be found at http://activityworkshop.net/software/prune/
-Prune is copyright activityworkshop.net and distributed under the terms of the Gnu GPL version 2.
+Prune is copyright 2006-2010 activityworkshop.net and distributed under the terms of the Gnu GPL version 2.
You may freely use the software, and may help others to freely use it too. For further information
on your rights and how they are protected, see the included license.txt file.
=======
To run Prune from the jar file, simply call it from a command prompt or shell:
- java -jar prune_08.jar
+ java -jar prune_09.jar
If the jar file is saved in a different directory, you will need to include the path.
Depending on your system settings, you may be able to click or double-click on the jar file
or other link can of course be made should you wish.
To specify a language other than the default, use an additional parameter, eg:
- java -jar prune_08.jar --lang=DE
+ java -jar prune_09.jar --lang=DE
+
+New with version 9
+==================
+
+The following features were added since version 8:
+ - Ability to paste coordinates (eg from wikipedia or geocaching sites) to create new points
+ - Configurable colour settings
+ - Function to convert waypoint names into timestamps
+ - Function to reorganise and sort photos either by filename or time
+ - Ability to load gzipped xml files
+ - New "full range details" dialog including pace and average gradient
+ - Preservation of unrecognised gpx tags by copying source xml
+ - Improved photo handling and ability to rotate photos
+ - Japanese, Portuguese and Turkish languages thanks to generous user input
New with version 8
==================
- Waypoint list
- Spanish language
+Features of version 1
+=====================
+
+The following features were included in version 1:
+ - Loading of text files, display in overhead and profile views
+ - Display of track details such as distances, speeds
+ - Deletion of points and ranges, and variable compression
+ - Export to KML format
+ - English, German and Swiss German languages
+
Further information and updates
===============================
import javax.swing.JScrollPane;
import javax.swing.JTable;
-import tim.prune.Config;
import tim.prune.ExternalTools;
import tim.prune.I18nManager;
import tim.prune.UpdateMessageBroker;
+import tim.prune.config.Config;
import tim.prune.data.Altitude;
import tim.prune.data.Coordinate;
import tim.prune.data.DataPoint;
private JDialog _dialog = null;
private JButton _okButton = null;
private JCheckBox _overwriteCheckbox = null;
+ private JCheckBox _forceCheckbox = null;
private JProgressBar _progressBar = null;
private PhotoTableModel _photoTableModel = null;
private boolean _saveCancelled = false;
JScrollPane scrollPane = new JScrollPane(photoTable);
scrollPane.setPreferredSize(new Dimension(300, 160));
tablePanel.add(scrollPane, BorderLayout.CENTER);
+ // Pair of checkboxes
+ JPanel checkPanel = new JPanel();
+ checkPanel.setLayout(new BoxLayout(checkPanel, BoxLayout.Y_AXIS));
_overwriteCheckbox = new JCheckBox(I18nManager.getText("dialog.saveexif.overwrite"));
_overwriteCheckbox.setSelected(false);
- tablePanel.add(_overwriteCheckbox, BorderLayout.SOUTH);
+ checkPanel.add(_overwriteCheckbox);
+ _forceCheckbox = new JCheckBox(I18nManager.getText("dialog.saveexif.force"));
+ _forceCheckbox.setSelected(false);
+ checkPanel.add(_forceCheckbox);
+ tablePanel.add(checkPanel, BorderLayout.SOUTH);
centrePanel.add(tablePanel, BorderLayout.CENTER);
// progress bar below main controls
_progressBar = new JProgressBar(0, 100);
_progressBar.setValue(0);
_progressBar.setVisible(true);
boolean overwriteFlag = _overwriteCheckbox.isSelected();
- int numSaved = 0;
+ int numSaved = 0, numFailed = 0, numForced = 0;
// Loop over all photos in list
for (int i=0; i<numPhotos; i++)
{
if (photo != null && photo.getOriginalStatus() != photo.getCurrentStatus())
{
// Increment counter if save successful
- if (savePhoto(photo, overwriteFlag))
- {
+ if (savePhoto(photo, overwriteFlag, false)) {
numSaved++;
}
+ else {
+ if (_forceCheckbox.isSelected() && savePhoto(photo, overwriteFlag, true))
+ {
+ numForced++;
+ }
+ else {
+ numFailed++;
+ }
+ }
}
}
// update progress bar
// Show confirmation
UpdateMessageBroker.informSubscribers(I18nManager.getText("confirm.saveexif.ok1") + " "
+ numSaved + " " + I18nManager.getText("confirm.saveexif.ok2"));
+ if (numFailed > 0)
+ {
+ JOptionPane.showMessageDialog(_parentFrame,
+ I18nManager.getText("error.saveexif.failed1") + " " + numFailed + " "
+ + I18nManager.getText("error.saveexif.failed2"),
+ I18nManager.getText("dialog.saveexif.title"), JOptionPane.ERROR_MESSAGE);
+ }
+ if (numForced > 0)
+ {
+ JOptionPane.showMessageDialog(_parentFrame,
+ I18nManager.getText("error.saveexif.forced1") + " " + numForced + " "
+ + I18nManager.getText("error.saveexif.forced2"),
+ I18nManager.getText("dialog.saveexif.title"), JOptionPane.WARNING_MESSAGE);
+ }
// close dialog, all finished
_dialog.dispose();
}
* Save the details for the given photo
* @param inPhoto Photo object
* @param inOverwriteFlag true to overwrite file, false otherwise
+ * @param inForceFlag true to force write, ignoring minor errors
* @return true if details saved ok
*/
- private boolean savePhoto(Photo inPhoto, boolean inOverwriteFlag)
+ private boolean savePhoto(Photo inPhoto, boolean inOverwriteFlag, boolean inForceFlag)
{
// Check whether photo file still exists
if (!inPhoto.getFile().exists())
else
{
// Photo is now connected, so write new gps tags
- command = getWriteGpsExifTagsCommand(inPhoto.getFile(), inPhoto.getDataPoint(), inOverwriteFlag);
+ command = getWriteGpsExifTagsCommand(inPhoto.getFile(), inPhoto.getDataPoint(), inOverwriteFlag, inForceFlag);
}
// Execute exif command
+ boolean saved = false;
try
{
Process process = Runtime.getRuntime().exec(command);
process.waitFor();
}
catch (InterruptedException ie) {}
+ saved = (process.exitValue() == 0);
}
catch (Exception e)
{
// show error message
JOptionPane.showMessageDialog(_parentFrame, "Exception: '" + e.getClass().getName() + "' : "
+ e.getMessage(), I18nManager.getText("dialog.saveexif.title"), JOptionPane.ERROR_MESSAGE);
- return false;
}
- return true;
+ return saved;
}
* @param inFile file to which to write the tags
* @param inPoint DataPoint object containing coordinate information
* @param inOverwrite true to overwrite file, false to create copy
+ * @param inForce true to force write, ignoring minor errors
* @return external command to write gps tags
*/
- private static String[] getWriteGpsExifTagsCommand(File inFile, DataPoint inPoint, boolean inOverwrite)
+ private static String[] getWriteGpsExifTagsCommand(File inFile, DataPoint inPoint,
+ boolean inOverwrite, boolean inForce)
{
// Make a string array to construct the command and its parameters
- String[] result = new String[inOverwrite?10:9];
+ String[] result = new String[(inOverwrite?10:9) + (inForce?1:0)];
result[0] = Config.getConfigString(Config.KEY_EXIFTOOL_PATH);
result[1] = "-P";
if (inOverwrite) {result[2] = "-overwrite_original_in_place";}
int paramOffset = inOverwrite?3:2;
+ if (inForce) {
+ result[paramOffset] = "-m";
+ paramOffset++;
+ }
// To set latitude : -GPSLatitude='12 34 56.78' -GPSLatitudeRef='N'
// (latitude as space-separated deg min sec, reference as either N or S)
result[paramOffset] = "-GPSLatitude='" + inPoint.getLatitude().output(Coordinate.FORMAT_DEG_MIN_SEC_WITH_SPACES)
import javax.swing.table.TableModel;
import tim.prune.App;
-import tim.prune.Config;
import tim.prune.I18nManager;
import tim.prune.UpdateMessageBroker;
+import tim.prune.config.Config;
import tim.prune.data.Altitude;
import tim.prune.data.Coordinate;
import tim.prune.data.DataPoint;
/**
* Class to manage the saving of track data
- * into a user-specified file
+ * as text into a user-specified file
*/
public class FileSaver
{
private App _app = null;
private JFrame _parentFrame = null;
- private Track _track = null;
private JDialog _dialog = null;
private JFileChooser _fileChooser = null;
private JPanel _cards = null;
* Constructor
* @param inApp application object to inform of success
* @param inParentFrame parent frame
- * @param inTrack track object to save
*/
- public FileSaver(App inApp, JFrame inParentFrame, Track inTrack)
+ public FileSaver(App inApp, JFrame inParentFrame)
{
_app = inApp;
_parentFrame = inParentFrame;
- _track = inTrack;
}
_dialog.pack();
}
// Check field list
- FieldList fieldList = _track.getFieldList();
+ Track track = _app.getTrackInfo().getTrack();
+ FieldList fieldList = track.getFieldList();
int numFields = fieldList.getNumFields();
_model = new FieldSelectionTableModel(numFields);
for (int i=0; i<numFields; i++)
{
Field field = fieldList.getField(i);
- FieldInfo info = new FieldInfo(field, _track.hasData(field));
+ FieldInfo info = new FieldInfo(field, track.hasData(field));
_model.addFieldInfo(info, i);
}
// Initialise dialog and show it
/**
- * Save the track to file with the chosen options
+ * Start the save process by choosing the file to save to
* @return true if successful or cancelled, false if failed
*/
private boolean saveToFile()
{
- // TODO: Shorten method
- if (!_pointTypeSelector.getAnythingSelected()) {return false;}
- boolean saveOK = true;
- FileWriter writer = null;
+ if (!_pointTypeSelector.getAnythingSelected()) {
+ JOptionPane.showMessageDialog(_parentFrame, I18nManager.getText("dialog.save.notypesselected"),
+ I18nManager.getText("dialog.saveoptions.title"), JOptionPane.WARNING_MESSAGE);
+ return false;
+ }
if (_fileChooser == null)
{
_fileChooser = new JFileChooser();
}
if (_fileChooser.showSaveDialog(_parentFrame) == JFileChooser.APPROVE_OPTION)
{
- File saveFile = _fileChooser.getSelectedFile();
- String lineSeparator = System.getProperty("line.separator");
- // Get coordinate format and altitude format
- int coordFormat = Coordinate.FORMAT_NONE;
- for (int i=0; i<_coordUnitsRadios.length; i++)
- if (_coordUnitsRadios[i].isSelected())
- coordFormat = FORMAT_COORDS[i];
- Altitude.Format altitudeFormat = Altitude.Format.NO_FORMAT;
- for (int i=0; i<_altitudeUnitsRadios.length; i++)
- {
- if (_altitudeUnitsRadios[i].isSelected())
- {
- altitudeFormat = FORMAT_ALTS[i];
- }
+ return saveToFile(_fileChooser.getSelectedFile());
+ }
+ return true; // cancelled
+ }
+
+
+ /**
+ * Save the track to the specified file using the chosen options
+ * @param inSaveFile file to save to
+ * @return true if save successful, false if failed
+ */
+ private boolean saveToFile(File inSaveFile)
+ {
+ // TODO: Shorten method
+ FileWriter writer = null;
+ final String lineSeparator = System.getProperty("line.separator");
+ boolean saveOK = true;
+ // Get coordinate format and altitude format
+ int coordFormat = Coordinate.FORMAT_NONE;
+ for (int i=0; i<_coordUnitsRadios.length; i++)
+ if (_coordUnitsRadios[i].isSelected())
+ coordFormat = FORMAT_COORDS[i];
+ Altitude.Format altitudeFormat = Altitude.Format.NO_FORMAT;
+ for (int i=0; i<_altitudeUnitsRadios.length; i++)
+ {
+ if (_altitudeUnitsRadios[i].isSelected()) {
+ altitudeFormat = FORMAT_ALTS[i];
}
- // Get timestamp formats
- int timestampFormat = Timestamp.FORMAT_ORIGINAL;
- for (int i=0; i<_timestampUnitsRadios.length; i++)
- {
- if (_timestampUnitsRadios[i].isSelected())
- {
- timestampFormat = FORMAT_TIMES[i];
- }
+ }
+ // Get timestamp format
+ int timestampFormat = Timestamp.FORMAT_ORIGINAL;
+ for (int i=0; i<_timestampUnitsRadios.length; i++)
+ {
+ if (_timestampUnitsRadios[i].isSelected()) {
+ timestampFormat = FORMAT_TIMES[i];
}
+ }
- // Check if file exists, and confirm overwrite if necessary
- Object[] buttonTexts = {I18nManager.getText("button.overwrite"), I18nManager.getText("button.cancel")};
- if (!saveFile.exists() || JOptionPane.showOptionDialog(_parentFrame,
- I18nManager.getText("dialog.save.overwrite.text"),
- I18nManager.getText("dialog.save.overwrite.title"), JOptionPane.YES_NO_OPTION,
- JOptionPane.WARNING_MESSAGE, null, buttonTexts, buttonTexts[1])
- == JOptionPane.YES_OPTION)
+ // Check if file exists, and confirm overwrite if necessary
+ Object[] buttonTexts = {I18nManager.getText("button.overwrite"), I18nManager.getText("button.cancel")};
+ if (!inSaveFile.exists() || JOptionPane.showOptionDialog(_parentFrame,
+ I18nManager.getText("dialog.save.overwrite.text"),
+ I18nManager.getText("dialog.save.overwrite.title"), JOptionPane.YES_NO_OPTION,
+ JOptionPane.WARNING_MESSAGE, null, buttonTexts, buttonTexts[1])
+ == JOptionPane.YES_OPTION)
+ {
+ try
{
- try
- {
- // Create output file
- writer = new FileWriter(saveFile);
- // Determine delimiter character to use
- char delimiter = getDelimiter();
- FieldInfo info = null;
- Field field = null;
+ // Create output file
+ writer = new FileWriter(inSaveFile);
+ // Determine delimiter character to use
+ final char delimiter = getDelimiter();
+ FieldInfo info = null;
- StringBuffer buffer = null;
- int numFields = _model.getRowCount();
- boolean firstField = true;
- // Write header row if required
- if (_headerRowCheckbox.isSelected())
+ StringBuffer buffer = null;
+ int numFields = _model.getRowCount();
+ boolean firstField = true;
+ // Write header row if required
+ if (_headerRowCheckbox.isSelected())
+ {
+ buffer = new StringBuffer();
+ for (int f=0; f<numFields; f++)
{
- buffer = new StringBuffer();
- for (int f=0; f<numFields; f++)
+ info = _model.getFieldInfo(f);
+ if (info.isSelected())
{
- info = _model.getFieldInfo(f);
- if (info.isSelected())
- {
- if (!firstField)
- {
- // output field separator
- buffer.append(delimiter);
- }
- field = info.getField();
- buffer.append(field.getName());
- firstField = false;
+ // output field separator
+ if (!firstField) {
+ buffer.append(delimiter);
}
+ buffer.append(info.getField().getName());
+ firstField = false;
}
- writer.write(buffer.toString());
- writer.write(lineSeparator);
}
+ writer.write(buffer.toString());
+ writer.write(lineSeparator);
+ }
- // Loop over points outputting each in turn to buffer
- final int numPoints = _track.getNumPoints();
- int numSaved = 0;
- for (int p=0; p<numPoints; p++)
+ // Examine selection
+ int selStart = -1, selEnd = -1;
+ if (_pointTypeSelector.getJustSelection()) {
+ selStart = _app.getTrackInfo().getSelection().getStart();
+ selEnd = _app.getTrackInfo().getSelection().getEnd();
+ }
+ // Loop over points outputting each in turn to buffer
+ Track track = _app.getTrackInfo().getTrack();
+ final int numPoints = track.getNumPoints();
+ int numSaved = 0;
+ for (int p=0; p<numPoints; p++)
+ {
+ DataPoint point = track.getPoint(p);
+ boolean savePoint = ((point.isWaypoint() && _pointTypeSelector.getWaypointsSelected())
+ || (!point.isWaypoint() && point.getPhoto()==null && _pointTypeSelector.getTrackpointsSelected())
+ || (!point.isWaypoint() && point.getPhoto()!=null && _pointTypeSelector.getPhotopointsSelected()))
+ && (!_pointTypeSelector.getJustSelection() || (p>=selStart && p<=selEnd));
+ if (!savePoint) {continue;}
+ numSaved++;
+ firstField = true;
+ buffer = new StringBuffer();
+ for (int f=0; f<numFields; f++)
{
- DataPoint point = _track.getPoint(p);
- boolean savePoint = ((point.isWaypoint() && _pointTypeSelector.getWaypointsSelected())
- || (!point.isWaypoint() && point.getPhoto()==null && _pointTypeSelector.getTrackpointsSelected())
- || (!point.isWaypoint() && point.getPhoto()!=null && _pointTypeSelector.getPhotopointsSelected()));
- if (!savePoint) {continue;}
- numSaved++;
- firstField = true;
- buffer = new StringBuffer();
- for (int f=0; f<numFields; f++)
+ info = _model.getFieldInfo(f);
+ if (info.isSelected())
{
- info = _model.getFieldInfo(f);
- if (info.isSelected())
+ if (!firstField)
{
- if (!firstField)
- {
- // output field separator
- buffer.append(delimiter);
- }
- field = info.getField();
- // Output field according to type
- if (field == Field.LATITUDE)
- {
- buffer.append(point.getLatitude().output(coordFormat));
- }
- else if (field == Field.LONGITUDE)
- {
- buffer.append(point.getLongitude().output(coordFormat));
- }
- else if (field == Field.ALTITUDE)
- {
- try
- {
- buffer.append(point.getAltitude().getStringValue(altitudeFormat));
- }
- catch (NullPointerException npe) {}
- }
- else if (field == Field.TIMESTAMP)
- {
- if (point.hasTimestamp())
- {
- if (timestampFormat == Timestamp.FORMAT_ORIGINAL) {
- // output original string
- buffer.append(point.getFieldValue(Field.TIMESTAMP));
- }
- else {
- // format value accordingly
- buffer.append(point.getTimestamp().getText(timestampFormat));
- }
- }
- }
- else
- {
- String value = point.getFieldValue(field);
- if (value != null)
- {
- buffer.append(value);
- }
- }
- firstField = false;
+ // output field separator
+ buffer.append(delimiter);
}
- }
- // Output to file
- writer.write(buffer.toString());
- writer.write(lineSeparator);
- }
- // Store directory in config for later
- Config.setConfigString(Config.KEY_TRACK_DIR, saveFile.getParentFile().getAbsolutePath());
- // Save successful
- UpdateMessageBroker.informSubscribers(I18nManager.getText("confirm.save.ok1")
- + " " + numSaved + " " + I18nManager.getText("confirm.save.ok2")
- + " " + saveFile.getAbsolutePath());
- _app.informDataSaved();
- }
- catch (IOException ioe)
- {
- saveOK = false;
- _app.showErrorMessageNoLookup("error.save.dialogtitle",
- I18nManager.getText("error.save.failed") + " : " + ioe.getMessage());
- }
- finally
- {
- // try to close file if it's open
- try {
- if (writer != null) {
- writer.close();
+ saveField(buffer, point, info.getField(), coordFormat, altitudeFormat, timestampFormat);
+ firstField = false;
}
}
- catch (Exception e) {}
+ // Output to file
+ writer.write(buffer.toString());
+ writer.write(lineSeparator);
}
+ // Store directory in config for later
+ Config.setConfigString(Config.KEY_TRACK_DIR, inSaveFile.getParentFile().getAbsolutePath());
+ // Save successful
+ UpdateMessageBroker.informSubscribers(I18nManager.getText("confirm.save.ok1")
+ + " " + numSaved + " " + I18nManager.getText("confirm.save.ok2")
+ + " " + inSaveFile.getAbsolutePath());
+ _app.informDataSaved();
}
- else
+ catch (IOException ioe)
{
- // Overwrite file confirm cancelled
saveOK = false;
+ _app.showErrorMessageNoLookup("error.save.dialogtitle",
+ I18nManager.getText("error.save.failed") + " : " + ioe.getMessage());
}
+ finally
+ {
+ // try to close file if it's open
+ try {
+ writer.close();
+ }
+ catch (Exception e) {}
+ }
+ }
+ else
+ {
+ // Overwrite file confirm cancelled
+ saveOK = false;
}
return saveOK;
}
+ /**
+ * Format the given field and append to the given buffer for saving
+ * @param inBuffer buffer to append to
+ * @param inPoint point object
+ * @param inField field object
+ * @param inCoordFormat coordinate format
+ * @param inAltitudeFormat altitude format
+ * @param inTimestampFormat timestamp format
+ */
+ private void saveField(StringBuffer inBuffer, DataPoint inPoint, Field inField,
+ int inCoordFormat, Altitude.Format inAltitudeFormat, int inTimestampFormat)
+ {
+ // Output field according to type
+ if (inField == Field.LATITUDE)
+ {
+ inBuffer.append(inPoint.getLatitude().output(inCoordFormat));
+ }
+ else if (inField == Field.LONGITUDE)
+ {
+ inBuffer.append(inPoint.getLongitude().output(inCoordFormat));
+ }
+ else if (inField == Field.ALTITUDE)
+ {
+ try
+ {
+ inBuffer.append(inPoint.getAltitude().getStringValue(inAltitudeFormat));
+ }
+ catch (NullPointerException npe) {}
+ }
+ else if (inField == Field.TIMESTAMP)
+ {
+ if (inPoint.hasTimestamp())
+ {
+ if (inTimestampFormat == Timestamp.FORMAT_ORIGINAL) {
+ // output original string
+ inBuffer.append(inPoint.getFieldValue(Field.TIMESTAMP));
+ }
+ else {
+ // format value accordingly
+ inBuffer.append(inPoint.getTimestamp().getText(inTimestampFormat));
+ }
+ }
+ }
+ else
+ {
+ String value = inPoint.getFieldValue(inField);
+ if (value != null)
+ {
+ inBuffer.append(value);
+ }
+ }
+ }
+
+
/**
* @return the selected delimiter character
*/
import javax.swing.event.ChangeListener;
import tim.prune.App;
-import tim.prune.Config;
import tim.prune.ExternalTools;
import tim.prune.GenericFunction;
import tim.prune.I18nManager;
+import tim.prune.config.Config;
/**
* Class to manage the loading of GPS data using GpsBabel
if (trackName == null || trackName.equals("")) {trackName = "prune";}
// Generate the GPX file and send to the GPS
OutputStreamWriter writer = new OutputStreamWriter(process.getOutputStream());
- boolean[] saveFlags = {true, true, true, true}; // export everything
- GpxExporter.exportData(writer, _app.getTrackInfo().getTrack(), trackName, null, saveFlags);
+ boolean[] saveFlags = {true, true, true, false, true}; // export everything
+ GpxExporter.exportData(writer, _app.getTrackInfo(), trackName, null, saveFlags, false);
writer.close();
// Read the error stream to see if there's a better error message there
--- /dev/null
+package tim.prune.save;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.InputStream;
+import java.util.zip.GZIPInputStream;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipInputStream;
+
+import javax.xml.parsers.SAXParser;
+import javax.xml.parsers.SAXParserFactory;
+
+import org.xml.sax.Attributes;
+import org.xml.sax.SAXException;
+import org.xml.sax.helpers.DefaultHandler;
+
+import tim.prune.data.DataPoint;
+import tim.prune.data.SourceInfo;
+
+/**
+ * Class to read in a GPX file and cache all the point strings
+ */
+public class GpxCacher extends DefaultHandler
+{
+ private SourceInfo _sourceInfo = null;
+ private String _headerString = null;
+ private String[] _strings = null;
+ private int _pointNum = 0;
+ private boolean _insidePoint = false;
+ private StringBuilder _builder = null;
+
+
+ /**
+ * Constructor
+ * @param inSourceInfo source information
+ */
+ public GpxCacher(SourceInfo inInfo)
+ {
+ _sourceInfo = inInfo;
+ _strings = new String[inInfo.getNumPoints()];
+ _pointNum = 0;
+ // Should be a gpx file, but might be raw, zipped or gzipped
+ File gpxFile = inInfo.getFile();
+ String fileName = gpxFile.getName().toLowerCase();
+ if (gpxFile.exists() && gpxFile.canRead())
+ {
+ try {
+ SAXParser saxParser = SAXParserFactory.newInstance().newSAXParser();
+ if (fileName.endsWith(".gpx") || fileName.endsWith(".xml")) {
+ saxParser.parse(inInfo.getFile(), this);
+ }
+ else if (fileName.endsWith(".zip")) {
+ saxParser.parse(getZipInputStream(inInfo.getFile()), this);
+ }
+ else if (fileName.endsWith(".gz")) {
+ saxParser.parse(new GZIPInputStream(new FileInputStream(inInfo.getFile())), this);
+ }
+ else {
+ System.out.println("Unrecognised file type: " + inInfo.getFile().getName());
+ }
+ } catch (Exception e) {
+ // TODO: Handle errors here with a list of warnings?
+ e.printStackTrace();
+ }
+ }
+ _builder = null;
+ }
+
+
+ /**
+ * Receive the start of a tag
+ */
+ public void startElement(String inUri, String inLocalName, String inTagName,
+ Attributes inAttributes) throws SAXException
+ {
+ if (inTagName.equalsIgnoreCase("gpx"))
+ {
+ // store initial gpx tag
+ _builder = new StringBuilder(60);
+ appendTag(_builder, inTagName, inAttributes);
+ _headerString = _builder.toString();
+ }
+ else
+ {
+ if (inTagName.equalsIgnoreCase("wpt") || inTagName.equalsIgnoreCase("trkpt")
+ || inTagName.equalsIgnoreCase("rtept"))
+ {
+ _insidePoint = true;
+ _builder = new StringBuilder(60);
+ }
+ if (_insidePoint) {
+ appendTag(_builder, inTagName, inAttributes);
+ }
+ }
+ super.startElement(inUri, inLocalName, inTagName, inAttributes);
+ }
+
+ /**
+ * Receive characters between tags (inside or outside)
+ */
+ public void characters(char[] inChars, int inStart, int inLength)
+ throws SAXException
+ {
+ if (_insidePoint) {
+ _builder.append(new String(inChars, inStart, inLength));
+ }
+ super.characters(inChars, inStart, inLength);
+ }
+
+ /**
+ * Receive end of xml tag
+ */
+ public void endElement(String inUri, String inLocalName, String inTagName)
+ throws SAXException
+ {
+ if (_insidePoint) {
+ _builder.append("</").append(inTagName).append('>');
+ }
+ if (inTagName.equalsIgnoreCase("wpt") || inTagName.equalsIgnoreCase("trkpt")
+ || inTagName.equalsIgnoreCase("rtept"))
+ {
+ _strings[_pointNum] = _builder.toString();
+ _pointNum++;
+ _insidePoint = false;
+ }
+ super.endElement(inUri, inLocalName, inTagName);
+ }
+
+
+ /**
+ * Append the current tag to the supplied StringBuilder
+ * @param inBuilder Stringbuilder object to append tag to
+ * @param inTagName name of tag
+ * @param inAttributes attributes of tag
+ */
+ private static void appendTag(StringBuilder inBuilder, String inTagName, Attributes inAttributes)
+ {
+ inBuilder.append('<').append(inTagName);
+ int numAtts = inAttributes.getLength();
+ for (int i=0; i<numAtts; i++) {
+ inBuilder.append(' ').append(inAttributes.getQName(i)).append("=\"")
+ .append(inAttributes.getValue(i)).append('"');
+ }
+ inBuilder.append('>');
+ }
+
+
+ /**
+ * @return the header string from the GPX tag
+ */
+ public String getHeaderString()
+ {
+ return _headerString;
+ }
+
+ /**
+ * Get the source string for the given point
+ * @param inPoint point to retrieve
+ * @return string if found, otherwise null
+ */
+ public String getSourceString(DataPoint inPoint)
+ {
+ int index = _sourceInfo.getIndex(inPoint);
+ if (index >= 0) {
+ return _strings[index];
+ }
+ return null;
+ }
+
+ /**
+ * Get an inputstream of a GPX file inside a zip
+ * @param inFile File object describing zip file
+ * @return input stream for Xml parser
+ */
+ private static InputStream getZipInputStream(File inFile)
+ {
+ try
+ {
+ ZipInputStream zis = new ZipInputStream(new FileInputStream(inFile));
+ while (zis.available() > 0)
+ {
+ ZipEntry entry = zis.getNextEntry();
+ String entryName = entry.toString();
+ if (entryName != null && entryName.length() > 4)
+ {
+ String suffix = entryName.substring(entryName.length()-4).toLowerCase();
+ if (suffix.equals(".gpx") || suffix.equals(".xml")) {
+ // First matching file so must be gpx
+ return zis;
+ }
+ }
+ }
+ }
+ catch (Exception e) {} // ignore errors
+ // not found - error!
+ return null;
+ }
+}
--- /dev/null
+package tim.prune.save;
+
+import tim.prune.data.DataPoint;
+import tim.prune.data.FileInfo;
+import tim.prune.data.SourceInfo;
+
+/**
+ * Class to hold a list of GpxCacher objects
+ * and get the original source xml for data points
+ */
+public class GpxCacherList
+{
+ /** Array of Gpx Cachers */
+ private GpxCacher[] _cacherList = null;
+
+ /**
+ * Constructor
+ * @param inInfo file info object
+ */
+ public GpxCacherList(FileInfo inInfo)
+ {
+ int numFiles = inInfo.getNumFiles();
+ _cacherList = new GpxCacher[numFiles];
+ for (int i=0; i<numFiles; i++) {
+ SourceInfo info = inInfo.getSource(i);
+ if (info.getFileType() == SourceInfo.FILE_TYPE.GPX) {
+ _cacherList[i] = new GpxCacher(info);
+ }
+ }
+ }
+
+ /**
+ * Get the source for the given data point
+ * @param inPoint point to look for
+ * @return source string or null if not found
+ */
+ public String getSourceString(DataPoint inPoint)
+ {
+ String str = null;
+ // Check if point has been modified, if so return null
+ if (inPoint.isModified()) {return null;}
+ // Loop over sources
+ for (int i=0; i<_cacherList.length && (str == null); i++) {
+ GpxCacher cacher = _cacherList[i];
+ if (cacher != null) {
+ str = cacher.getSourceString(inPoint);
+ }
+ }
+ return str;
+ }
+
+ /**
+ * @return the first non-empty header from the list
+ */
+ public String getFirstHeader()
+ {
+ String str = null;
+ // Loop over sources
+ for (int i=0; i<_cacherList.length && (str == null || str.equals("")); i++)
+ {
+ GpxCacher cacher = _cacherList[i];
+ if (cacher != null) {
+ str = cacher.getHeaderString();
+ }
+ }
+ return str;
+ }
+}
import java.io.Writer;
import javax.swing.BorderFactory;
+import javax.swing.Box;
import javax.swing.BoxLayout;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JDialog;
import javax.swing.JFileChooser;
+import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JTextField;
import tim.prune.App;
-import tim.prune.Config;
import tim.prune.GenericFunction;
import tim.prune.GpsPruner;
import tim.prune.I18nManager;
import tim.prune.UpdateMessageBroker;
+import tim.prune.config.Config;
import tim.prune.data.Altitude;
import tim.prune.data.Coordinate;
import tim.prune.data.DataPoint;
+import tim.prune.data.Field;
import tim.prune.data.Timestamp;
-import tim.prune.data.Track;
+import tim.prune.data.TrackInfo;
import tim.prune.load.GenericFileFilter;
/**
*/
public class GpxExporter extends GenericFunction implements Runnable
{
- private Track _track = null;
+ private TrackInfo _trackInfo = null;
private JDialog _dialog = null;
private JTextField _nameField = null;
private JTextField _descriptionField = null;
private PointTypeSelector _pointTypeSelector = null;
private JCheckBox _timestampsCheckbox = null;
- private JFileChooser _fileChooser = null;
+ private JCheckBox _copySourceCheckbox = null;
private File _exportFile = null;
- /** version number of Gpx */
- private static final String GPX_VERSION_NUMBER = "1.0";
/** this program name */
private static final String GPX_CREATOR = "Prune v" + GpsPruner.VERSION_NUMBER + " activityworkshop.net";
public GpxExporter(App inApp)
{
super(inApp);
- _track = inApp.getTrackInfo().getTrack();
+ _trackInfo = inApp.getTrackInfo();
}
/** Get name key */
_descriptionField = new JTextField(10);
descPanel.add(_descriptionField);
mainPanel.add(descPanel);
+ mainPanel.add(Box.createVerticalStrut(5));
// point type selection (track points, waypoints, photo points)
_pointTypeSelector = new PointTypeSelector();
mainPanel.add(_pointTypeSelector);
- // checkbox for timestamps
+ // checkboxes for timestamps and copying
+ JPanel checkPanel = new JPanel();
_timestampsCheckbox = new JCheckBox(I18nManager.getText("dialog.exportgpx.includetimestamps"));
_timestampsCheckbox.setSelected(true);
- mainPanel.add(_timestampsCheckbox);
+ checkPanel.add(_timestampsCheckbox);
+ _copySourceCheckbox = new JCheckBox(I18nManager.getText("dialog.exportgpx.copysource"));
+ _copySourceCheckbox.setSelected(true);
+ checkPanel.add(_copySourceCheckbox);
+ mainPanel.add(checkPanel);
dialogPanel.add(mainPanel, BorderLayout.CENTER);
// button panel at bottom
{
// OK pressed, so check selections
if (!_pointTypeSelector.getAnythingSelected()) {
+ JOptionPane.showMessageDialog(_parentFrame, I18nManager.getText("dialog.save.notypesselected"),
+ I18nManager.getText("dialog.saveoptions.title"), JOptionPane.WARNING_MESSAGE);
return;
}
// Choose output file
- if (_fileChooser == null)
+ File saveFile = chooseGpxFile(_parentFrame);
+ if (saveFile != null)
{
- _fileChooser = new JFileChooser();
- _fileChooser.setDialogType(JFileChooser.SAVE_DIALOG);
- _fileChooser.setFileFilter(new GenericFileFilter("filetype.gpx", new String[] {"gpx"}));
- _fileChooser.setAcceptAllFileFilterUsed(false);
- // start from directory in config which should be set
- String configDir = Config.getConfigString(Config.KEY_TRACK_DIR);
- if (configDir != null) {_fileChooser.setCurrentDirectory(new File(configDir));}
+ // New file or overwrite confirmed, so initiate export in separate thread
+ _exportFile = saveFile;
+ new Thread(this).start();
}
+ }
+
+ /**
+ * Select a GPX file to save to
+ * @param inParentFrame parent frame for file chooser dialog
+ * @return selected File, or null if selection cancelled
+ */
+ public static File chooseGpxFile(JFrame inParentFrame)
+ {
+ File saveFile = null;
+ JFileChooser fileChooser = new JFileChooser();
+ fileChooser.setDialogType(JFileChooser.SAVE_DIALOG);
+ fileChooser.setFileFilter(new GenericFileFilter("filetype.gpx", new String[] {"gpx"}));
+ fileChooser.setAcceptAllFileFilterUsed(false);
+ // start from directory in config which should be set
+ String configDir = Config.getConfigString(Config.KEY_TRACK_DIR);
+ if (configDir != null) {fileChooser.setCurrentDirectory(new File(configDir));}
+
// Allow choose again if an existing file is selected
boolean chooseAgain = false;
do
{
chooseAgain = false;
- if (_fileChooser.showSaveDialog(_parentFrame) == JFileChooser.APPROVE_OPTION)
+ if (fileChooser.showSaveDialog(inParentFrame) == JFileChooser.APPROVE_OPTION)
{
// OK pressed and file chosen
- File file = _fileChooser.getSelectedFile();
+ File file = fileChooser.getSelectedFile();
// Check file extension
if (!file.getName().toLowerCase().endsWith(".gpx"))
{
}
// Check if file exists and if necessary prompt for overwrite
Object[] buttonTexts = {I18nManager.getText("button.overwrite"), I18nManager.getText("button.cancel")};
- if (!file.exists() || JOptionPane.showOptionDialog(_parentFrame,
+ if (!file.exists() || JOptionPane.showOptionDialog(inParentFrame,
I18nManager.getText("dialog.save.overwrite.text"),
I18nManager.getText("dialog.save.overwrite.title"), JOptionPane.YES_NO_OPTION,
JOptionPane.WARNING_MESSAGE, null, buttonTexts, buttonTexts[1])
== JOptionPane.YES_OPTION)
{
- // New file or overwrite confirmed, so initiate export in separate thread
- _exportFile = file;
- new Thread(this).start();
+ // new file or overwrite confirmed
+ saveFile = file;
}
else
{
+ // file exists and overwrite cancelled - select again
chooseAgain = true;
}
}
} while (chooseAgain);
+ return saveFile;
}
-
/**
* Run method for controlling separate thread for exporting
*/
// normal writing to file
writer = new OutputStreamWriter(new FileOutputStream(_exportFile));
boolean[] saveFlags = {_pointTypeSelector.getTrackpointsSelected(), _pointTypeSelector.getWaypointsSelected(),
- _pointTypeSelector.getPhotopointsSelected(), _timestampsCheckbox.isSelected()};
+ _pointTypeSelector.getPhotopointsSelected(), _pointTypeSelector.getJustSelection(),
+ _timestampsCheckbox.isSelected()};
// write file
- final int numPoints = exportData(writer, _track, _nameField.getText(),
- _descriptionField.getText(), saveFlags);
+ final int numPoints = exportData(writer, _trackInfo, _nameField.getText(),
+ _descriptionField.getText(), saveFlags, _copySourceCheckbox.isSelected());
// close file
writer.close();
/**
* Export the information to the given writer
* @param inWriter writer object
- * @param inTrack track object containing data
+ * @param inInfo track info object
* @param inName name of track (optional)
* @param inDesc description of track (optional)
* @param inSaveFlags array of booleans to export tracks, waypoints, photos, timestamps
+ * @param inUseCopy true to copy source if available
* @return number of points written
* @throws IOException if io errors occur on write
*/
- public static int exportData(OutputStreamWriter inWriter, Track inTrack, String inName,
- String inDesc, boolean[] inSaveFlags) throws IOException
+ public static int exportData(OutputStreamWriter inWriter, TrackInfo inInfo, String inName,
+ String inDesc, boolean[] inSaveFlags, boolean inUseCopy) throws IOException
{
- inWriter.write("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<gpx version=\"");
- inWriter.write(GPX_VERSION_NUMBER);
- inWriter.write("\" creator=\"");
- inWriter.write(GPX_CREATOR);
- inWriter.write("\"\n xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n"
- + " xmlns=\"http://www.topografix.com/GPX/1/0\""
- + " xsi:schemaLocation=\"http://www.topografix.com/GPX/1/0 http://www.topografix.com/GPX/1/0/gpx.xsd\">\n");
+ // Instantiate source file cachers in case we want to copy output
+ GpxCacherList gpxCachers = null;
+ if (inUseCopy) gpxCachers = new GpxCacherList(inInfo.getFileInfo());
+ // Write or copy header
+ inWriter.write(getHeaderString(gpxCachers));
// Name field
String trackName = "PruneTrack";
if (inName != null && !inName.equals(""))
if (inDesc != null && !inDesc.equals("")) {
inWriter.write(inDesc);
}
- else
- {
+ else {
inWriter.write("Export from Prune");
}
inWriter.write("</desc>\n");
final boolean exportTrackpoints = inSaveFlags[0];
final boolean exportWaypoints = inSaveFlags[1];
final boolean exportPhotos = inSaveFlags[2];
- final boolean exportTimestamps = inSaveFlags[3];
+ final boolean exportSelection = inSaveFlags[3];
+ final boolean exportTimestamps = inSaveFlags[4];
+ // Examine selection
+ int selStart = -1, selEnd = -1;
+ if (exportSelection) {
+ selStart = inInfo.getSelection().getStart();
+ selEnd = inInfo.getSelection().getEnd();
+ }
// Loop over waypoints
- final int numPoints = inTrack.getNumPoints();
+ final int numPoints = inInfo.getTrack().getNumPoints();
int numSaved = 0;
for (i=0; i<numPoints; i++)
{
- point = inTrack.getPoint(i);
- // Make a wpt element for each waypoint
- if (point.isWaypoint())
- {
- if (exportWaypoints) {
- exportWaypoint(point, inWriter, exportTimestamps);
- numSaved++;
+ point = inInfo.getTrack().getPoint(i);
+ if (!exportSelection || (i>=selStart && i<=selEnd)) {
+ // Make a wpt element for each waypoint
+ if (point.isWaypoint()) {
+ if (exportWaypoints)
+ {
+ String pointSource = (inUseCopy?gpxCachers.getSourceString(point):null);
+ if (pointSource != null) {
+ inWriter.write(pointSource);
+ inWriter.write('\n');
+ }
+ else {
+ exportWaypoint(point, inWriter, exportTimestamps);
+ }
+ numSaved++;
+ }
+ }
+ else {
+ hasTrackpoints = true;
}
}
- else
- {
- hasTrackpoints = true;
- }
}
- // Output the track, if there is one
- if (hasTrackpoints)
+ // Export both route points and then track points
+ if (hasTrackpoints && (exportTrackpoints || exportPhotos))
+ {
+ // Output all route points (if any)
+ numSaved += writeTrackPoints(inWriter, inInfo, exportSelection, exportTrackpoints, exportPhotos,
+ exportTimestamps, true, gpxCachers, "<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,
+ exportTimestamps, false, gpxCachers, "<trkpt", trackStart, "\t</trkseg>\n\t<trkseg>\n",
+ "\t</trkseg></trk>\n");
+ }
+
+ inWriter.write("</gpx>\n");
+ return numSaved;
+ }
+
+ /**
+ * Loop through the track outputting the relevant track points
+ * @param inWriter writer object for output
+ * @param inInfo track info object containing track
+ * @param inExportSelection true to just output current selection
+ * @param inExportTrackpoints true to output track points
+ * @param inExportPhotos true to output photo points
+ * @param exportTimestamps true to include timestamps in export
+ * @param inOnlyCopies true to only export if source can be copied
+ * @param inCachers list of GpxCachers
+ * @param inPointTag tag to match for each point
+ * @param inStartTag start tag to output
+ * @param inSegmentTag tag to output between segments (or null)
+ * @param inEndTag end tag to output
+ */
+ private static int writeTrackPoints(OutputStreamWriter inWriter,
+ TrackInfo inInfo, boolean inExportSelection, boolean inExportTrackpoints,
+ boolean inExportPhotos, boolean exportTimestamps, boolean inOnlyCopies,
+ GpxCacherList inCachers, String inPointTag, String inStartTag,
+ String inSegmentTag, String inEndTag)
+ throws IOException
+ {
+ // Note: far too many input parameters to this method but avoids duplication
+ // of output functionality for writing track points and route points
+ int numPoints = inInfo.getTrack().getNumPoints();
+ int selStart = inInfo.getSelection().getStart();
+ int selEnd = inInfo.getSelection().getEnd();
+ int numSaved = 0;
+ // Loop over track points
+ for (int i=0; i<numPoints; i++)
{
- boolean firstPoint = true;
- inWriter.write("\t<trk><name>" + trackName + "</name><number>1</number><trkseg>\n");
- // Loop over track points
- for (i=0; i<numPoints; i++)
+ DataPoint point = inInfo.getTrack().getPoint(i);
+ if ((!inExportSelection || (i>=selStart && i<=selEnd)) && !point.isWaypoint())
{
- point = inTrack.getPoint(i);
- // restart track segment if necessary
- if (point.getSegmentStart() && !firstPoint) {
- inWriter.write("\t</trkseg>\n\t<trkseg>\n");
- }
- if (!point.isWaypoint())
+ if ((point.getPhoto()==null && inExportTrackpoints) || (point.getPhoto()!=null && inExportPhotos))
{
- if ((point.getPhoto()==null && exportTrackpoints) || (point.getPhoto()!=null && exportPhotos))
+ // get the source from the point (if any)
+ String pointSource = (inCachers!=null?inCachers.getSourceString(point):null);
+ boolean writePoint = (pointSource != null && pointSource.toLowerCase().startsWith(inPointTag))
+ || (pointSource == null && !inOnlyCopies);
+ if (writePoint)
{
- // export the point
- exportTrackpoint(point, inWriter, exportTimestamps);
+ // restart track segment if necessary
+ if ((numSaved > 0) && point.getSegmentStart() && (inSegmentTag != null)) {
+ inWriter.write(inSegmentTag);
+ }
+ if (numSaved == 0) {inWriter.write(inStartTag);}
+ if (pointSource != null) {
+ inWriter.write(pointSource);
+ inWriter.write('\n');
+ }
+ else {
+ if (!inOnlyCopies) {exportTrackpoint(point, inWriter, exportTimestamps);}
+ }
numSaved++;
- firstPoint = false;
}
}
}
- inWriter.write("\t</trkseg></trk>\n");
}
- inWriter.write("</gpx>\n");
+ if (numSaved > 0) {inWriter.write(inEndTag);}
return numSaved;
}
+ /**
+ * Get the header string for the gpx
+ * @param inCachers cacher list to ask for headers, if available
+ * @return header string from cachers or as default
+ */
+ private static String getHeaderString(GpxCacherList inCachers)
+ {
+ String gpxHeader = null;
+ if (inCachers != null) {gpxHeader = inCachers.getFirstHeader();}
+ if (gpxHeader == null || gpxHeader.length() < 5)
+ {
+ // Create default (1.0) header
+ gpxHeader = "<gpx version=\"1.0\" creator=\"" + GPX_CREATOR
+ + "\"\n xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n"
+ + " xmlns=\"http://www.topografix.com/GPX/1/0\""
+ + " xsi:schemaLocation=\"http://www.topografix.com/GPX/1/0 http://www.topografix.com/GPX/1/0/gpx.xsd\">\n";
+ }
+ return "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" + gpxHeader + "\n";
+ }
+
/**
* Export the specified waypoint into the file
* @param inPoint waypoint to export
inWriter.write("" + inPoint.getAltitude().getStringValue(Altitude.Format.METRES));
inWriter.write("</ele>\n");
}
- // write waypoint name after elevation
- inWriter.write("\t\t<name>");
- inWriter.write(inPoint.getWaypointName().trim());
- inWriter.write("</name>\n");
// timestamp if available (point might have timestamp and then be turned into a waypoint)
if (inPoint.hasTimestamp() && inTimestamps)
{
inWriter.write(inPoint.getTimestamp().getText(Timestamp.FORMAT_ISO_8601));
inWriter.write("</time>\n");
}
- // TODO: Include waypt type in Gpx
+ // write waypoint name after elevation and time
+ inWriter.write("\t\t<name>");
+ inWriter.write(inPoint.getWaypointName().trim());
+ inWriter.write("</name>\n");
+ // write waypoint type if any
+ String type = inPoint.getFieldValue(Field.WAYPT_TYPE);
+ if (type != null)
+ {
+ type = type.trim();
+ if (!type.equals(""))
+ {
+ inWriter.write("\t\t<type>");
+ inWriter.write(type);
+ inWriter.write("</type>\n");
+ }
+ }
inWriter.write("\t</wpt>\n");
}
package tim.prune.save;
import java.awt.BorderLayout;
+import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
+import java.awt.event.MouseAdapter;
+import java.awt.event.MouseEvent;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.FileOutputStream;
import javax.swing.SwingConstants;
import tim.prune.App;
-import tim.prune.Config;
import tim.prune.GenericFunction;
import tim.prune.I18nManager;
import tim.prune.UpdateMessageBroker;
+import tim.prune.config.ColourUtils;
+import tim.prune.config.Config;
import tim.prune.data.Altitude;
import tim.prune.data.Coordinate;
import tim.prune.data.DataPoint;
import tim.prune.data.Field;
import tim.prune.data.Track;
import tim.prune.data.TrackInfo;
+import tim.prune.gui.ColourChooser;
+import tim.prune.gui.ColourPatch;
import tim.prune.gui.ImageUtils;
import tim.prune.load.GenericFileFilter;
/**
* Class to export track information
- * into a specified Kml file
+ * into a specified Kml or Kmz file
*/
public class KmlExporter extends GenericFunction implements Runnable
{
private JCheckBox _altitudesCheckbox = null;
private JCheckBox _kmzCheckbox = null;
private JCheckBox _exportImagesCheckbox = null;
+ private ColourPatch _colourPatch = null;
private JLabel _progressLabel = null;
private JProgressBar _progressBar = null;
+ private Dimension[] _imageDimensions = null;
private JFileChooser _fileChooser = null;
private File _exportFile = null;
private JButton _okButton = null;
private boolean _cancelPressed = false;
+ private ColourChooser _colourChooser = null;
// Filename of Kml file within zip archive
private static final String KML_FILENAME_IN_KMZ = "doc.kml";
// Default width and height of thumbnail images in Kmz
private static final int DEFAULT_THUMBNAIL_WIDTH = 240;
- private static final int DEFAULT_THUMBNAIL_HEIGHT = 180;
+ private static final int DEFAULT_THUMBNAIL_HEIGHT = 240;
// Actual selected width and height of thumbnail images in Kmz
private static int THUMBNAIL_WIDTH = 0;
private static int THUMBNAIL_HEIGHT = 0;
+ // Default track colour
+ private static final Color DEFAULT_TRACK_COLOUR = new Color(204, 0, 0); // red
/**
_dialog.setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE);
_dialog.getContentPane().add(makeDialogComponents());
_dialog.pack();
+ _colourChooser = new ColourChooser(_dialog);
}
enableCheckboxes();
_descriptionField.setEnabled(true);
_pointTypeSelector = new PointTypeSelector();
_pointTypeSelector.setAlignmentX(Component.CENTER_ALIGNMENT);
mainPanel.add(_pointTypeSelector);
+ // Colour definition
+ Color trackColour = ColourUtils.colourFromHex(Config.getConfigString(Config.KEY_KML_TRACK_COLOUR));
+ if (trackColour == null) {
+ trackColour = DEFAULT_TRACK_COLOUR;
+ }
+ _colourPatch = new ColourPatch(trackColour);
+ _colourPatch.addMouseListener(new MouseAdapter() {
+ public void mouseClicked(MouseEvent e) {
+ _colourChooser.showDialog(_colourPatch.getBackground());
+ Color colour = _colourChooser.getChosenColour();
+ if (colour != null) _colourPatch.setColour(colour);
+ }
+ });
+ JPanel colourPanel = new JPanel();
+ colourPanel.add(new JLabel(I18nManager.getText("dialog.exportkml.trackcolour")));
+ colourPanel.add(_colourPatch);
+ mainPanel.add(colourPanel);
// Checkbox for altitude export
_altitudesCheckbox = new JCheckBox(I18nManager.getText("dialog.exportkml.altitude"));
_altitudesCheckbox.setHorizontalTextPosition(SwingConstants.LEFT);
{
// OK pressed, now validate selection checkboxes
if (!_pointTypeSelector.getAnythingSelected()) {
+ JOptionPane.showMessageDialog(_parentFrame, I18nManager.getText("dialog.save.notypesselected"),
+ I18nManager.getText("dialog.saveoptions.title"), JOptionPane.WARNING_MESSAGE);
return;
}
// Choose output file
if (configDir != null) {_fileChooser.setCurrentDirectory(new File(configDir));}
}
String requiredExtension = null, otherExtension = null;
- if (_kmzCheckbox.isSelected())
- {
+ if (_kmzCheckbox.isSelected()) {
requiredExtension = ".kmz"; otherExtension = ".kml";
}
- else
- {
+ else {
requiredExtension = ".kml"; otherExtension = ".kmz";
}
_fileChooser.setAcceptAllFileFilterUsed(false);
if (THUMBNAIL_WIDTH < DEFAULT_THUMBNAIL_WIDTH) {THUMBNAIL_WIDTH = DEFAULT_THUMBNAIL_WIDTH;}
THUMBNAIL_HEIGHT = Config.getConfigInt(Config.KEY_KMZ_IMAGE_HEIGHT);
if (THUMBNAIL_HEIGHT < DEFAULT_THUMBNAIL_HEIGHT) {THUMBNAIL_HEIGHT = DEFAULT_THUMBNAIL_HEIGHT;}
+ // Create array for image dimensions in case it's required
+ _imageDimensions = new Dimension[_track.getNumPoints()];
OutputStreamWriter writer = null;
ZipOutputStream zipOutputStream = null;
}
// write file
final int numPoints = exportData(writer, exportImages);
+ // update config with selected track colour
+ Config.setConfigString(Config.KEY_KML_TRACK_COLOUR, ColourUtils.makeHexCode(_colourPatch.getBackground()));
// update progress bar
_progressBar.setValue(1);
// close file
writer.close();
+ _imageDimensions = null;
// Store directory in config for later
Config.setConfigString(Config.KEY_TRACK_DIR, _exportFile.getParentFile().getAbsolutePath());
// show confirmation
}
catch (IOException ioe)
{
- // System.out.println("Exception: " + ioe.getClass().getName() + " - " + ioe.getMessage());
try {
if (writer != null) writer.close();
}
boolean writeTrack = _pointTypeSelector.getTrackpointsSelected();
boolean writeWaypoints = _pointTypeSelector.getWaypointsSelected();
boolean writePhotos = _pointTypeSelector.getPhotopointsSelected();
+ boolean justSelection = _pointTypeSelector.getJustSelection();
inWriter.write("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<kml xmlns=\"http://earth.google.com/kml/2.1\">\n<Folder>\n");
inWriter.write("\t<name>");
if (_descriptionField != null && _descriptionField.getText() != null && !_descriptionField.getText().equals(""))
}
inWriter.write("</name>\n");
+ // Examine selection if required
+ int selStart = -1, selEnd = -1;
+ if (justSelection) {
+ selStart = _trackInfo.getSelection().getStart();
+ selEnd = _trackInfo.getSelection().getEnd();
+ }
+
boolean absoluteAltitudes = _altitudesCheckbox.isSelected();
int i = 0;
DataPoint point = null;
boolean hasTrackpoints = false;
- // Loop over waypoints (if any)
boolean writtenPhotoHeader = false;
final int numPoints = _track.getNumPoints();
int numSaved = 0;
for (i=0; i<numPoints; i++)
{
point = _track.getPoint(i);
+ boolean writeCurrentPoint = !justSelection || (i>=selStart && i<=selEnd);
// Make a blob for each waypoint
if (point.isWaypoint())
{
- if (writeWaypoints) {
+ if (writeWaypoints && writeCurrentPoint)
+ {
exportWaypoint(point, inWriter, absoluteAltitudes);
numSaved++;
}
}
// Make a blob with description for each photo
// Photos have already been written so picture sizes already known
- if (point.getPhoto() != null && writePhotos)
+ if (point.getPhoto() != null && writePhotos && writeCurrentPoint)
{
if (!writtenPhotoHeader)
{
writtenPhotoHeader = true;
}
photoNum++;
- exportPhotoPoint(point, inWriter, inExportImages, photoNum, absoluteAltitudes);
+ exportPhotoPoint(point, inWriter, inExportImages, i, photoNum, absoluteAltitudes);
numSaved++;
}
}
{
// Set up strings for start and end of track segment
String trackStart = "\t<Placemark>\n\t\t<name>track</name>\n\t\t<Style>\n\t\t\t<LineStyle>\n"
- + "\t\t\t\t<color>cc0000cc</color>\n\t\t\t\t<width>4</width>\n\t\t\t</LineStyle>\n"
+ + "\t\t\t\t<color>cc" + reverse(ColourUtils.makeHexCode(_colourPatch.getBackground())) + "</color>\n"
+ + "\t\t\t\t<width>4</width>\n\t\t\t</LineStyle>\n"
+ "\t\t\t<PolyStyle><color>33cc0000</color></PolyStyle>\n"
+ "\t\t</Style>\n\t\t<LineString>\n";
if (absoluteAltitudes) {
for (i=0; i<numPoints; i++)
{
point = _track.getPoint(i);
- // start new track segment if necessary
- if (point.getSegmentStart() && !firstTrackpoint) {
- inWriter.write(trackEnd);
- inWriter.write(trackStart);
- }
- if (!point.isWaypoint() && point.getPhoto() == null)
+ boolean writeCurrentPoint = !justSelection || (i>=selStart && i<=selEnd);
+ if (!point.isWaypoint() && writeCurrentPoint)
{
- exportTrackpoint(point, inWriter);
- numSaved++;
- firstTrackpoint = false;
+ // start new track segment if necessary
+ if (point.getSegmentStart() && !firstTrackpoint) {
+ inWriter.write(trackEnd);
+ inWriter.write(trackStart);
+ }
+ if (point.getPhoto() == null)
+ {
+ exportTrackpoint(point, inWriter);
+ numSaved++;
+ firstTrackpoint = false;
+ }
}
}
// end segment
return numSaved;
}
+ /**
+ * Reverse the hex code for the colours for KML's stupid backwards format
+ * @param inCode colour code rrggbb
+ * @return kml code bbggrr
+ */
+ private static String reverse(String inCode)
+ {
+ return inCode.substring(4, 6) + inCode.substring(2, 4) + inCode.substring(0, 2);
+ }
/**
* Export the specified waypoint into the file
* @param inPoint data point including photo
* @param inWriter writer object
* @param inImageLink flag to set whether to export image links or not
+ * @param inPointNumber number of point for accessing dimensions
* @param inImageNumber number of image for filename
* @param inAbsoluteAltitude true for absolute altitudes
* @throws IOException on write failure
*/
private void exportPhotoPoint(DataPoint inPoint, Writer inWriter, boolean inImageLink,
- int inImageNumber, boolean inAbsoluteAltitude)
+ int inPointNumber, int inImageNumber, boolean inAbsoluteAltitude)
throws IOException
{
inWriter.write("\t<Placemark>\n\t\t<name>");
inWriter.write("</name>\n");
if (inImageLink)
{
- // Work out image dimensions of thumbnail
- Dimension picSize = inPoint.getPhoto().getSize();
- Dimension thumbSize = ImageUtils.getThumbnailSize(picSize.width, picSize.height, THUMBNAIL_WIDTH, THUMBNAIL_HEIGHT);
+ Dimension imageSize = _imageDimensions[inPointNumber];
// Write out some html for the thumbnail images
inWriter.write("<description><![CDATA[<br/><table border='0'><tr><td><center><img src='images/image"
- + inImageNumber + ".jpg' width='" + thumbSize.width + "' height='" + thumbSize.height + "'></center></td></tr>"
- + "<tr><td><center>Caption for the photo</center></td></tr></table>]]></description>");
+ + inImageNumber + ".jpg' width='" + imageSize.width + "' height='" + imageSize.height + "'></center></td></tr>"
+ + "<tr><td><center>" + inPoint.getPhoto().getFile().getName() + "</center></td></tr></table>]]></description>");
}
inWriter.write("<styleUrl>#camera_icon</styleUrl>\n");
inWriter.write("\t\t<Point>\n");
}
ImageWriter imageWriter = writers.next();
+ // Check selection checkbox
+ boolean justSelection = _pointTypeSelector.getJustSelection();
+ int selStart = -1, selEnd = -1;
+ if (justSelection) {
+ selStart = _trackInfo.getSelection().getStart();
+ selEnd = _trackInfo.getSelection().getEnd();
+ }
+
int numPoints = _track.getNumPoints();
DataPoint point = null;
int photoNum = 0;
for (int i=0; i<numPoints && !_cancelPressed; i++)
{
point = _track.getPoint(i);
- if (point.getPhoto() != null)
+ if (point.getPhoto() != null && (!justSelection || (i>=selStart && i<=selEnd)))
{
photoNum++;
// Make a new entry in zip file
ImageIcon icon = new ImageIcon(point.getPhoto().getFile().getAbsolutePath());
// Scale and smooth image to required size
- Dimension outputSize = ImageUtils.getThumbnailSize(
- point.getPhoto().getWidth(), point.getPhoto().getHeight(),
- THUMBNAIL_WIDTH, THUMBNAIL_HEIGHT);
- BufferedImage bufferedImage = ImageUtils.createScaledImage(icon.getImage(), outputSize.width, outputSize.height);
+ BufferedImage bufferedImage = ImageUtils.rotateImage(icon.getImage(),
+ THUMBNAIL_WIDTH, THUMBNAIL_HEIGHT, point.getPhoto().getRotationDegrees());
+ // Store image dimensions so that it doesn't have to be calculated again for the points
+ _imageDimensions[i] = new Dimension(bufferedImage.getWidth(), bufferedImage.getHeight());
imageWriter.setOutput(ImageIO.createImageOutputStream(inZipStream));
imageWriter.write(bufferedImage);
/**
* GUI element to allow the selection of point types for saving,
- * including three checkboxes for track points, waypoints, photo points
+ * including checkboxes for track points, waypoints, photo points
+ * and also a checkbox for the current selection
*/
public class PointTypeSelector extends JPanel
{
- /** Array of three checkboxes */
- private JCheckBox[] _checkboxes = new JCheckBox[3];
+ /** Array of checkboxes */
+ private JCheckBox[] _checkboxes = new JCheckBox[4];
/**
private void createComponents()
{
setLayout(new BorderLayout());
- // Need JLabel to explain what it is
+ // Need label to explain what it is
add(new JLabel(I18nManager.getText("dialog.pointtype.desc")), BorderLayout.NORTH);
// panel for the checkboxes
JPanel gridPanel = new JPanel();
- gridPanel.setLayout(new GridLayout(1, 3, 15, 3));
+ gridPanel.setLayout(new GridLayout(0, 3, 15, 3));
final String[] keys = {"track", "waypoint", "photo"};
for (int i=0; i<3; i++)
{
_checkboxes[i] = new JCheckBox(I18nManager.getText("dialog.pointtype." + keys[i]));
- _checkboxes[i].setEnabled(true);
_checkboxes[i].setSelected(true);
gridPanel.add(_checkboxes[i]);
}
add(gridPanel, BorderLayout.CENTER);
+ _checkboxes[3] = new JCheckBox(I18nManager.getText("dialog.pointtype.selection"));
+ add(_checkboxes[3], BorderLayout.SOUTH);
}
/**
_checkboxes[i].setEnabled(false);
}
}
+ _checkboxes[3].setEnabled(inTrackInfo.getSelection().hasRangeSelected());
+ _checkboxes[3].setSelected(false);
}
/**
return _checkboxes[2].isSelected();
}
+ /**
+ * @return true if only the current selection should be saved
+ */
+ public boolean getJustSelection()
+ {
+ return _checkboxes[3].isSelected();
+ }
+
/**
* @return true if at least one type selected
*/
import javax.swing.SwingConstants;
import tim.prune.App;
-import tim.prune.Config;
import tim.prune.GenericFunction;
import tim.prune.I18nManager;
import tim.prune.UpdateMessageBroker;
+import tim.prune.config.Config;
import tim.prune.data.Track;
import tim.prune.load.GenericFileFilter;
import tim.prune.threedee.LineDialog;
+++ /dev/null
-package tim.prune.undo;
-
-import tim.prune.data.DataPoint;
-import tim.prune.data.TrackInfo;
-
-/**
- * Operation to undo the connection of a photo to a point
- * where the point had to be cloned
- */
-public class UndoConnectPhotoWithClone extends UndoConnectPhoto
-{
- /** Additional undo object for removing inserted point */
- private UndoInsert _undoInsert = null;
-
-
- /**
- * Constructor
- * @param inPoint data point
- * @param inFilename filename of photo
- * @param inIndex index of cloned point
- */
- public UndoConnectPhotoWithClone(DataPoint inPoint, String inFilename, int inIndex)
- {
- super(inPoint, inFilename);
- // Make an undo object for the insert
- _undoInsert = new UndoInsert(inIndex, 1);
- }
-
- /**
- * Perform the undo operation on the given Track
- * @param inTrackInfo TrackInfo object on which to perform the operation
- */
- public void performUndo(TrackInfo inTrackInfo) throws UndoException
- {
- //System.out.println("Performing undo: (" + super.getDescription() + ", " + _undoInsert.getDescription() + ")");
- // Firstly, undo connect
- super.performUndo(inTrackInfo);
- // Next, undo insert to remove cloned point
- _undoInsert.performUndo(inTrackInfo);
- }
-}
--- /dev/null
+package tim.prune.undo;\r
+\r
+import tim.prune.I18nManager;\r
+import tim.prune.UpdateMessageBroker;\r
+import tim.prune.data.DataPoint;\r
+import tim.prune.data.Field;\r
+import tim.prune.data.Track;\r
+import tim.prune.data.TrackInfo;\r
+\r
+/**\r
+ * Operation to undo a conversion from names to times\r
+ */\r
+public class UndoConvertNamesToTimes implements UndoOperation\r
+{\r
+ /** Start and end indices of section */\r
+ private int _startIndex, _endIndex;\r
+ /** Waypoint names before operation */\r
+ private String[] _waypointNames = null;\r
+ /** Timestamp strings before operation */\r
+ private String[] _timestamps = null;\r
+\r
+ /**\r
+ * Constructor\r
+ * @param inTrackInfo track info object to copy values from\r
+ */\r
+ public UndoConvertNamesToTimes(TrackInfo inTrackInfo)\r
+ {\r
+ _startIndex = inTrackInfo.getSelection().getStart();\r
+ _endIndex = inTrackInfo.getSelection().getEnd();\r
+ final int numPoints = _endIndex - _startIndex + 1;\r
+ _waypointNames = new String[numPoints];\r
+ _timestamps = new String[numPoints];\r
+ // Loop over points in selection, and copy names and timestamps\r
+ for (int i=_startIndex; i<=_endIndex; i++)\r
+ {\r
+ DataPoint point = inTrackInfo.getTrack().getPoint(i);\r
+ if (point.isWaypoint())\r
+ {\r
+ _waypointNames[i-_startIndex] = point.getWaypointName();\r
+ _timestamps[i-_startIndex] = point.getFieldValue(Field.TIMESTAMP);\r
+ }\r
+ }\r
+ }\r
+\r
+\r
+ /**\r
+ * @return description of operation\r
+ */\r
+ public String getDescription()\r
+ {\r
+ return I18nManager.getText("undo.convertnamestotimes");\r
+ }\r
+\r
+\r
+ /**\r
+ * Perform the undo operation on the given Track\r
+ * @param inTrackInfo TrackInfo object on which to perform the operation\r
+ */\r
+ public void performUndo(TrackInfo inTrackInfo) throws UndoException\r
+ {\r
+ // Sanity check\r
+ Track track = inTrackInfo.getTrack();\r
+ if (track.getNumPoints() <= _endIndex || _endIndex <= _startIndex) {\r
+ throw new UndoException("Cannot undo conversion, track length doesn't match");\r
+ }\r
+ // Loop over points in selection and replace names and timestamps\r
+ for (int i=_startIndex; i<=_endIndex; i++)\r
+ {\r
+ String storedName = _waypointNames[i-_startIndex];\r
+ if (storedName != null)\r
+ {\r
+ // point had a name before the operation, so might have been converted\r
+ DataPoint point = track.getPoint(i);\r
+ point.setFieldValue(Field.WAYPT_NAME, storedName, true);\r
+ point.setFieldValue(Field.TIMESTAMP, _timestamps[i-_startIndex], true);\r
+ }\r
+ }\r
+ track.requestRescale();\r
+ UpdateMessageBroker.informSubscribers();\r
+ }\r
+}\r
*/
public UndoCutAndMove(Track inTrack, int inStart, int inEnd, int inMoveTo)
{
- // System.out.println("Construct undo with params " + inStart + ", "+ inEnd + ", " + inMoveTo);
_startIndex = inStart;
_endIndex = inEnd;
_moveToIndex = inMoveTo;
public void performUndo(TrackInfo inTrackInfo) throws UndoException\r
{\r
// Restore contents of point into track\r
- if (!inTrackInfo.getTrack().editPoint(_originalPoint, _undoFieldList))\r
+ if (!inTrackInfo.getTrack().editPoint(_originalPoint, _undoFieldList, true))\r
{\r
// throw exception if failed\r
throw new UndoException(getDescription());\r
\r
import tim.prune.I18nManager;\r
import tim.prune.data.DataPoint;\r
+import tim.prune.data.FileInfo;\r
import tim.prune.data.PhotoList;\r
import tim.prune.data.TrackInfo;\r
\r
private int _cropIndex = -1;\r
private int _numLoaded = -1;\r
private DataPoint[] _contents = null;\r
- private String _previousFilename = null;\r
private PhotoList _photoList = null;\r
+ private FileInfo _oldFileInfo = null;\r
\r
\r
/**\r
_cropIndex = inIndex;\r
_numLoaded = inNumLoaded;\r
_contents = null;\r
- _previousFilename = null;\r
}\r
\r
\r
_cropIndex = -1;\r
_numLoaded = inNumLoaded;\r
_contents = inOldTrackInfo.getTrack().cloneContents();\r
- if (inOldTrackInfo.getFileInfo().getNumFiles() == 1)\r
- _previousFilename = inOldTrackInfo.getFileInfo().getFilename();\r
+ _oldFileInfo = inOldTrackInfo.getFileInfo().clone();\r
_photoList = inPhotoList;\r
}\r
\r
*/\r
public void performUndo(TrackInfo inTrackInfo) throws UndoException\r
{\r
- // remove file from fileinfo\r
- inTrackInfo.getFileInfo().removeFile();\r
- if (_previousFilename != null)\r
- {\r
- inTrackInfo.getFileInfo().setFile(_previousFilename);\r
+ // remove source from fileinfo\r
+ if (_oldFileInfo == null) {\r
+ inTrackInfo.getFileInfo().removeSource();\r
+ }\r
+ else {\r
+ inTrackInfo.setFileInfo(_oldFileInfo);\r
}\r
// Crop / replace\r
if (_contents == null)\r
--- /dev/null
+package tim.prune.undo;\r
+\r
+import tim.prune.data.Track;\r
+\r
+/**\r
+ * Operation to undo a photo rearrangement\r
+ */\r
+public class UndoRearrangePhotos extends UndoReorder\r
+{\r
+ /**\r
+ * Constructor\r
+ * @param inTrack track contents to copy\r
+ */\r
+ public UndoRearrangePhotos(Track inTrack)\r
+ {\r
+ super(inTrack, "undo.rearrangephotos");\r
+ }\r
+\r
+}
\ No newline at end of file
package tim.prune.undo;\r
\r
-import tim.prune.I18nManager;\r
-import tim.prune.data.DataPoint;\r
import tim.prune.data.Track;\r
-import tim.prune.data.TrackInfo;\r
\r
/**\r
* Operation to undo a waypoint rearrangement\r
*/\r
-public class UndoRearrangeWaypoints implements UndoOperation\r
+public class UndoRearrangeWaypoints extends UndoReorder\r
{\r
- private DataPoint[] _contents = null;\r
-\r
-\r
/**\r
* Constructor\r
* @param inTrack track contents to copy\r
*/\r
public UndoRearrangeWaypoints(Track inTrack)\r
{\r
- _contents = inTrack.cloneContents();\r
+ super(inTrack, "undo.rearrangewaypoints");\r
}\r
\r
-\r
- /**\r
- * @return description of operation\r
- */\r
- public String getDescription()\r
- {\r
- return I18nManager.getText("undo.rearrangewaypoints");\r
- }\r
-\r
-\r
- /**\r
- * Perform the undo operation on the given Track\r
- * @param inTrackInfo TrackInfo object on which to perform the operation\r
- */\r
- public void performUndo(TrackInfo inTrackInfo) throws UndoException\r
- {\r
- // restore track to previous values\r
- inTrackInfo.getTrack().replaceContents(_contents);\r
- }\r
}
\ No newline at end of file
--- /dev/null
+package tim.prune.undo;\r
+\r
+import tim.prune.I18nManager;\r
+import tim.prune.data.DataPoint;\r
+import tim.prune.data.Track;\r
+import tim.prune.data.TrackInfo;\r
+\r
+/**\r
+ * Abstract operation to undo a reordering by replacing track contents with a shallow copy\r
+ */\r
+public abstract class UndoReorder implements UndoOperation\r
+{\r
+ /** Shallow copy of whole track contents */\r
+ private DataPoint[] _contents = null;\r
+ /** Description */\r
+ private String _description = null;\r
+\r
+ /**\r
+ * Constructor\r
+ * @param inTrack track contents to copy\r
+ * @param inDescKey description key\r
+ */\r
+ public UndoReorder(Track inTrack, String inDescKey)\r
+ {\r
+ _contents = inTrack.cloneContents();\r
+ _description = I18nManager.getText(inDescKey);\r
+ }\r
+\r
+ /**\r
+ * @return description\r
+ */\r
+ public String getDescription() {\r
+ return _description;\r
+ }\r
+\r
+\r
+ /**\r
+ * Perform the undo operation on the given Track\r
+ * @param inTrackInfo TrackInfo object on which to perform the operation\r
+ */\r
+ public void performUndo(TrackInfo inTrackInfo) throws UndoException\r
+ {\r
+ // restore track to previous values\r
+ inTrackInfo.getTrack().replaceContents(_contents);\r
+ }\r
+}
\ No newline at end of file
--- /dev/null
+package tim.prune.undo;\r
+\r
+import tim.prune.I18nManager;\r
+import tim.prune.UpdateMessageBroker;\r
+import tim.prune.data.Photo;\r
+import tim.prune.data.TrackInfo;\r
+\r
+/**\r
+ * Operation to undo the rotation of a photo\r
+ */\r
+public class UndoRotatePhoto implements UndoOperation\r
+{\r
+ private Photo _photo = null;\r
+ private boolean _rightwards = true;\r
+\r
+\r
+ /**\r
+ * Constructor\r
+ * @param inPhoto photo\r
+ * @param inDir true if original operation was rightwards (clockwise) rotation\r
+ */\r
+ public UndoRotatePhoto(Photo inPhoto, boolean inDir)\r
+ {\r
+ _photo = inPhoto;\r
+ _rightwards = inDir;\r
+ }\r
+\r
+\r
+ /**\r
+ * @return description of operation including photo name\r
+ */\r
+ public String getDescription()\r
+ {\r
+ return I18nManager.getText("undo.rotatephoto") + " " + _photo.getFile().getName();\r
+ }\r
+\r
+\r
+ /**\r
+ * Perform the undo operation on the given Track\r
+ * @param inTrackInfo TrackInfo object on which to perform the operation\r
+ */\r
+ public void performUndo(TrackInfo inTrackInfo) throws UndoException\r
+ {\r
+ _photo.rotate(!_rightwards);\r
+ // inform subscribers\r
+ UpdateMessageBroker.informSubscribers();\r
+ }\r
+}
\ No newline at end of file