[gpsprune] 01/05: Imported Upstream version 18

Sebastiaan Couwenberg sebastic at moszumanska.debian.org
Wed Jul 22 07:41:36 UTC 2015


This is an automated email from the git hooks/post-receive script.

sebastic pushed a commit to branch master
in repository gpsprune.

commit 7a1141aabcd0a5c9f57235b565fdb9deefcff9db
Author: Bas Couwenberg <sebastic at xs4all.nl>
Date:   Wed Jul 22 09:12:16 2015 +0200

    Imported Upstream version 18
---
 build.sh                                           |   2 +-
 tim/prune/App.java                                 |  47 +-
 tim/prune/DataStatus.java                          |  10 +-
 tim/prune/FunctionLibrary.java                     |  13 +-
 tim/prune/GpsPrune.java                            |   4 +-
 tim/prune/I18nManager.java                         |  46 +-
 tim/prune/config/Config.java                       |   7 +-
 tim/prune/copyright.txt                            |   2 +-
 tim/prune/data/Field.java                          |   3 +-
 tim/prune/data/SourceInfo.java                     |   2 +-
 tim/prune/data/Timestamp.java                      |   5 +-
 tim/prune/data/Track.java                          |  15 +-
 tim/prune/data/TrackInfo.java                      |   8 +-
 tim/prune/function/AboutScreen.java                |   6 +-
 tim/prune/function/GetWikipediaFunction.java       |  14 +-
 tim/prune/function/GetWikipediaXmlHandler.java     |  23 +-
 ...mlHandler.java => OpenCachingDeXmlHandler.java} |  48 +-
 tim/prune/function/RearrangePhotosFunction.java    |   2 +-
 ...ction.java => SearchOpenCachingDeFunction.java} |  74 +--
 tim/prune/function/SearchWikipediaNames.java       |  14 +-
 tim/prune/function/SetLanguage.java                |  14 +-
 tim/prune/function/autoplay/AutoplayFunction.java  | 334 ++++++++++
 tim/prune/function/autoplay/PointInfo.java         |  98 +++
 tim/prune/function/autoplay/PointList.java         | 115 ++++
 tim/prune/function/browser/BrowserLauncher.java    |   1 +
 tim/prune/function/browser/UrlGenerator.java       | 194 ++++--
 tim/prune/function/browser/WebMapFunction.java     |  46 ++
 tim/prune/function/cache/ManageCacheFunction.java  |   1 +
 tim/prune/function/cache/RowInfo.java              |  16 -
 tim/prune/function/cache/TileSet.java              |  33 +-
 .../compress/DeleteMarkedPointsFunction.java       |  56 ++
 .../function/compress/MarkAndDeleteFunction.java   |  15 +-
 tim/prune/function/compress/MarkLiftsFunction.java | 143 ++++
 tim/prune/function/gpsies/GetGpsiesFunction.java   |   4 +-
 tim/prune/function/gpsies/GpsiesXmlHandler.java    |  12 +-
 tim/prune/function/gpsies/TrackListModel.java      |  11 +-
 .../GenericDownloaderFunction.java                 |   3 +-
 .../function/search/SearchMapillaryFunction.java   | 231 +++++++
 .../GpsiesTrack.java => search/SearchResult.java}  |  36 +-
 tim/prune/function/srtm/LookupSrtmFunction.java    |   7 +-
 .../function/srtm/gen/GenerateTileLookup.java      |  11 +-
 tim/prune/gui/IconManager.java                     |  12 +-
 tim/prune/gui/MenuManager.java                     | 122 ++--
 tim/prune/gui/TripleStateCheckBox.java             |  78 +++
 tim/prune/gui/UndoManager.java                     |  26 +-
 tim/prune/gui/images/add_photo_icon.png            | Bin
 tim/prune/gui/images/add_textfile_icon.png         | Bin
 tim/prune/gui/images/pause.png                     | Bin 0 -> 424 bytes
 tim/prune/gui/images/play.png                      | Bin 0 -> 523 bytes
 tim/prune/gui/images/points_connected.gif          | Bin 922 -> 0 bytes
 tim/prune/gui/images/points_connected.png          | Bin 0 -> 586 bytes
 tim/prune/gui/images/points_disconnected.gif       | Bin 897 -> 0 bytes
 tim/prune/gui/images/points_disconnected.png       | Bin 0 -> 513 bytes
 tim/prune/gui/images/points_hidden.png             | Bin 0 -> 403 bytes
 tim/prune/gui/images/rewind.png                    | Bin 0 -> 549 bytes
 tim/prune/gui/map/DiskTileCacher.java              |   3 +-
 tim/prune/gui/map/MapCanvas.java                   |  23 +-
 tim/prune/gui/map/MapSource.java                   |  17 +-
 tim/prune/gui/map/MapSourceLibrary.java            |   4 +-
 tim/prune/gui/profile/ProfileChart.java            |   6 +
 tim/prune/jpeg/ExternalExifLibrary.java            |  34 +-
 tim/prune/lang/prune-texts_af.properties           |   2 +-
 tim/prune/lang/prune-texts_cz.properties           |   2 +-
 tim/prune/lang/prune-texts_da.properties           |  84 +++
 tim/prune/lang/prune-texts_de.properties           |  22 +-
 tim/prune/lang/prune-texts_de_CH.properties        |  38 +-
 tim/prune/lang/prune-texts_en.properties           |  24 +-
 tim/prune/lang/prune-texts_es.properties           |  16 +-
 tim/prune/lang/prune-texts_fa.properties           |  73 +++
 tim/prune/lang/prune-texts_fr.properties           |  23 +-
 tim/prune/lang/prune-texts_hu.properties           |  15 +-
 tim/prune/lang/prune-texts_in.properties           | 111 ++++
 tim/prune/lang/prune-texts_it.properties           |  13 +-
 tim/prune/lang/prune-texts_ja.properties           |   2 +-
 tim/prune/lang/prune-texts_ko.properties           |   2 +-
 tim/prune/lang/prune-texts_nl.properties           |  12 +-
 tim/prune/lang/prune-texts_no.properties           | 142 ++++
 tim/prune/lang/prune-texts_pl.properties           |   4 +-
 tim/prune/lang/prune-texts_pt.properties           |  20 +-
 tim/prune/lang/prune-texts_ro.properties           | 724 ++++++++++++++++-----
 tim/prune/lang/prune-texts_ru.properties           |   6 +-
 tim/prune/lang/prune-texts_sv.properties           | 102 +++
 tim/prune/lang/prune-texts_tr.properties           |   2 +-
 tim/prune/lang/prune-texts_uk.properties           |   2 +-
 tim/prune/lang/prune-texts_zh.properties           |   2 +-
 tim/prune/load/FileLoader.java                     |   1 +
 tim/prune/load/xml/GpxHandler.java                 |   2 +-
 tim/prune/load/xml/KmlHandler.java                 |  66 +-
 tim/prune/load/xml/XmlHandler.java                 |   4 +-
 tim/prune/readme.txt                               |  35 +-
 tim/prune/save/BaseImageConfigDialog.java          |   3 +-
 tim/prune/save/FileSaver.java                      |  17 +-
 tim/prune/save/GpxExporter.java                    |  10 +-
 tim/prune/threedee/TerrainHelper.java              |  44 +-
 tim/prune/threedee/TerrainPatch.java               | 116 ++++
 tim/prune/undo/UndoStack.java                      |  56 +-
 96 files changed, 3191 insertions(+), 657 deletions(-)

diff --git a/build.sh b/build.sh
index e3b5c1a..2c5b85d 100644
--- a/build.sh
+++ b/build.sh
@@ -1,6 +1,6 @@
 # Build script using external exif library
 # Version number
-PRUNENAME=gpsprune_17.2
+PRUNENAME=gpsprune_18
 # remove compile directory
 rm -rf compile
 # remove dist directory
diff --git a/tim/prune/App.java b/tim/prune/App.java
index 7be8242..81e59cc 100644
--- a/tim/prune/App.java
+++ b/tim/prune/App.java
@@ -4,7 +4,6 @@ import java.io.File;
 import java.util.ArrayList;
 import java.util.EmptyStackException;
 import java.util.Set;
-import java.util.Stack;
 
 import javax.swing.JFrame;
 import javax.swing.JOptionPane;
@@ -27,8 +26,6 @@ import tim.prune.data.Unit;
 import tim.prune.function.AsyncMediaLoader;
 import tim.prune.function.SaveConfig;
 import tim.prune.function.SelectTracksFunction;
-import tim.prune.function.browser.BrowserLauncher;
-import tim.prune.function.browser.UrlGenerator;
 import tim.prune.function.edit.FieldEditList;
 import tim.prune.function.edit.PointEditor;
 import tim.prune.gui.MenuManager;
@@ -121,7 +118,7 @@ public class App
 	/**
 	 * @return the undo stack
 	 */
-	public Stack<UndoOperation> getUndoStack()
+	public UndoStack getUndoStack()
 	{
 		return _undoStack;
 	}
@@ -303,7 +300,7 @@ public class App
 			// pass to track for completion
 			if (_track.editPoint(currentPoint, inEditList, false))
 			{
-				_undoStack.push(undo);
+				_undoStack.add(undo);
 				// Confirm point edit
 				UpdateMessageBroker.informSubscribers(I18nManager.getText("confirm.point.edit"));
 			}
@@ -351,7 +348,7 @@ public class App
 			if (_trackInfo.deletePoint())
 			{
 				// Delete was successful so add undo info to stack
-				_undoStack.push(undo);
+				_undoStack.add(undo);
 				if (currentPhoto != null)
 				{
 					// delete photo if necessary
@@ -379,27 +376,6 @@ public class App
 
 
 	/**
-	 * Finish the compression by deleting the marked points
-	 */
-	public void finishCompressTrack()
-	{
-		UndoDeleteMarked undo = new UndoDeleteMarked(_track);
-		// call track to do compress
-		int numPointsDeleted = _trackInfo.deleteMarkedPoints();
-		// add to undo stack if successful
-		if (numPointsDeleted > 0)
-		{
-			undo.setNumPointsDeleted(numPointsDeleted);
-			_undoStack.add(undo);
-			UpdateMessageBroker.informSubscribers("" + numPointsDeleted + " "
-				 + (numPointsDeleted==1?I18nManager.getText("confirm.deletepoint.single"):I18nManager.getText("confirm.deletepoint.multi")));
-		}
-		else {
-			showErrorMessage("function.compress", "dialog.deletemarked.nonefound");
-		}
-	}
-
-	/**
 	 * Reverse the currently selected section of the track
 	 */
 	public void reverseRange()
@@ -891,7 +867,7 @@ public class App
 		}
 		else
 		{
-			new UndoManager(this, _frame);
+			new UndoManager(this, _frame).show();
 		}
 	}
 
@@ -931,7 +907,7 @@ public class App
 		{
 			for (int i=0; i<inNumUndos; i++)
 			{
-				_undoStack.pop().performUndo(_trackInfo);
+				_undoStack.popOperation().performUndo(_trackInfo);
 			}
 			String message = "" + inNumUndos + " "
 				 + (inNumUndos==1?I18nManager.getText("confirm.undo.single"):I18nManager.getText("confirm.undo.multi"));
@@ -950,19 +926,12 @@ public class App
 	/**
 	 * @return the current data status, used for later comparison
 	 */
-	public DataStatus getCurrentDataStatus() {
-		return new DataStatus(_undoStack.size(), _undoStack.getNumTimesDeleted());
-	}
-
-	/**
-	 * Show a map url in an external browser
-	 * @param inSourceIndex index of map source to use
-	 */
-	public void showExternalMap(int inSourceIndex)
+	public DataStatus getCurrentDataStatus()
 	{
-		BrowserLauncher.launchBrowser(UrlGenerator.generateUrl(inSourceIndex, _trackInfo));
+		return new DataStatus(_undoStack.size(), _undoStack.getNumUndos());
 	}
 
+
 	/**
 	 * Display a standard error message
 	 * @param inTitleKey key to lookup for window title
diff --git a/tim/prune/DataStatus.java b/tim/prune/DataStatus.java
index cacb288..80ad838 100644
--- a/tim/prune/DataStatus.java
+++ b/tim/prune/DataStatus.java
@@ -8,17 +8,17 @@ package tim.prune;
 public class DataStatus
 {
 	private int _undoSize = 0;
-	private int _deleteCount = 0;
+	private int _numUndos = 0;
 
 	/**
 	 * Constructor
 	 * @param inUndoSize current size of undo stack
-	 * @param inDeleteCount number of times undo stack has been deleted
+	 * @param inNumUndos number of operations undone
 	 */
-	public DataStatus(int inUndoSize, int inDeleteCount)
+	public DataStatus(int inUndoSize, int inNumUndos)
 	{
 		_undoSize = inUndoSize;
-		_deleteCount = inDeleteCount;
+		_numUndos = inNumUndos;
 	}
 
 	/**
@@ -29,6 +29,6 @@ public class DataStatus
 	public boolean hasDataChanged(DataStatus inPreviousStatus)
 	{
 		return _undoSize != inPreviousStatus._undoSize
-			|| _deleteCount != inPreviousStatus._deleteCount;
+			|| _numUndos != inPreviousStatus._numUndos;
 	}
 }
diff --git a/tim/prune/FunctionLibrary.java b/tim/prune/FunctionLibrary.java
index a8d7e0e..81e5e0f 100644
--- a/tim/prune/FunctionLibrary.java
+++ b/tim/prune/FunctionLibrary.java
@@ -3,8 +3,11 @@ package tim.prune;
 import tim.prune.correlate.AudioCorrelator;
 import tim.prune.correlate.PhotoCorrelator;
 import tim.prune.function.*;
+import tim.prune.function.autoplay.AutoplayFunction;
 import tim.prune.function.charts.Charter;
 import tim.prune.function.compress.CompressTrackFunction;
+import tim.prune.function.compress.DeleteMarkedPointsFunction;
+import tim.prune.function.compress.MarkLiftsFunction;
 import tim.prune.function.compress.MarkPointsInRectangleFunction;
 import tim.prune.function.deletebydate.DeleteByDateFunction;
 import tim.prune.function.distance.DistanceFunction;
@@ -49,6 +52,8 @@ public abstract class FunctionLibrary
 	public static GenericFunction FUNCTION_SEW_SEGMENTS = null;
 	public static GenericFunction FUNCTION_REARRANGE_PHOTOS = null;
 	public static GenericFunction FUNCTION_COMPRESS = null;
+	public static GenericFunction FUNCTION_MARK_LIFTS = null;
+	public static DeleteMarkedPointsFunction FUNCTION_DELETE_MARKED_POINTS = null;
 	public static GenericFunction FUNCTION_DELETE_RANGE = null;
 	public static GenericFunction FUNCTION_CROP_TRACK = null;
 	public static GenericFunction FUNCTION_MARK_IN_RECTANGLE = null;
@@ -56,7 +61,7 @@ public abstract class FunctionLibrary
 	public static SingleNumericParameterFunction FUNCTION_INTERPOLATE = null;
 	public static GenericFunction FUNCTION_LOOKUP_SRTM = null;
 	public static GenericFunction FUNCTION_DOWNLOAD_SRTM = null;
-	public static GenericFunction FUNCTION_LOOKUP_WIKIPEDIA = null;
+	public static GenericFunction FUNCTION_NEARBY_WIKIPEDIA = null;
 	public static GenericFunction FUNCTION_SEARCH_WIKIPEDIA = null;
 	public static GenericFunction FUNCTION_DOWNLOAD_OSM = null;
 	public static GenericFunction FUNCTION_ADD_TIME_OFFSET  = null;
@@ -79,6 +84,7 @@ public abstract class FunctionLibrary
 	public static GenericFunction FUNCTION_3D     = null;
 	public static GenericFunction FUNCTION_DISTANCES  = null;
 	public static GenericFunction FUNCTION_FULL_RANGE_DETAILS = null;
+	public static GenericFunction FUNCTION_AUTOPLAY_TRACK = null;
 	public static GenericFunction FUNCTION_ESTIMATE_TIME = null;
 	public static GenericFunction FUNCTION_LEARN_ESTIMATION_PARAMS = null;
 	public static GenericFunction FUNCTION_GET_GPSIES = null;
@@ -124,6 +130,8 @@ public abstract class FunctionLibrary
 		FUNCTION_SEW_SEGMENTS = new SewTrackSegmentsFunction(inApp);
 		FUNCTION_REARRANGE_PHOTOS = new RearrangePhotosFunction(inApp);
 		FUNCTION_COMPRESS = new CompressTrackFunction(inApp);
+		FUNCTION_MARK_LIFTS = new MarkLiftsFunction(inApp);
+		FUNCTION_DELETE_MARKED_POINTS = new DeleteMarkedPointsFunction(inApp);
 		FUNCTION_DELETE_RANGE = new DeleteSelectedRangeFunction(inApp);
 		FUNCTION_CROP_TRACK = new CropToSelection(inApp);
 		FUNCTION_MARK_IN_RECTANGLE = new MarkPointsInRectangleFunction(inApp);
@@ -131,7 +139,7 @@ public abstract class FunctionLibrary
 		FUNCTION_INTERPOLATE = new InterpolateFunction(inApp);
 		FUNCTION_LOOKUP_SRTM = new LookupSrtmFunction(inApp);
 		FUNCTION_DOWNLOAD_SRTM = new DownloadSrtmFunction(inApp);
-		FUNCTION_LOOKUP_WIKIPEDIA = new GetWikipediaFunction(inApp);
+		FUNCTION_NEARBY_WIKIPEDIA = new GetWikipediaFunction(inApp);
 		FUNCTION_SEARCH_WIKIPEDIA = new SearchWikipediaNames(inApp);
 		FUNCTION_DOWNLOAD_OSM = new DownloadOsmFunction(inApp);
 		FUNCTION_ADD_TIME_OFFSET = new AddTimeOffset(inApp);
@@ -153,6 +161,7 @@ public abstract class FunctionLibrary
 		FUNCTION_3D     = new ShowThreeDFunction(inApp);
 		FUNCTION_DISTANCES = new DistanceFunction(inApp);
 		FUNCTION_FULL_RANGE_DETAILS = new FullRangeDetails(inApp);
+		FUNCTION_AUTOPLAY_TRACK = new AutoplayFunction(inApp);
 		FUNCTION_ESTIMATE_TIME = new EstimateTime(inApp);
 		FUNCTION_LEARN_ESTIMATION_PARAMS = new LearnParameters(inApp);
 		FUNCTION_GET_GPSIES = new GetGpsiesFunction(inApp);
diff --git a/tim/prune/GpsPrune.java b/tim/prune/GpsPrune.java
index e8cfad5..1f76d16 100644
--- a/tim/prune/GpsPrune.java
+++ b/tim/prune/GpsPrune.java
@@ -36,9 +36,9 @@ import tim.prune.gui.profile.ProfileChart;
 public class GpsPrune
 {
 	/** Version number of application, used in about screen and for version check */
-	public static final String VERSION_NUMBER = "17.2";
+	public static final String VERSION_NUMBER = "18";
 	/** Build number, just used for about screen */
-	public static final String BUILD_NUMBER = "320b";
+	public static final String BUILD_NUMBER = "334";
 	/** Static reference to App object */
 	private static App APP = null;
 
diff --git a/tim/prune/I18nManager.java b/tim/prune/I18nManager.java
index 24a4fde..fbf781e 100644
--- a/tim/prune/I18nManager.java
+++ b/tim/prune/I18nManager.java
@@ -4,6 +4,7 @@ import java.io.File;
 import java.io.FileInputStream;
 import java.io.FileNotFoundException;
 import java.io.IOException;
+import java.util.Enumeration;
 import java.util.Locale;
 import java.util.MissingResourceException;
 import java.util.Properties;
@@ -16,11 +17,8 @@ import java.util.ResourceBundle;
  */
 public abstract class I18nManager
 {
-	private static final String BUNDLE_NAME = "tim.prune.lang.prune-texts";
-	private static final Locale BACKUP_LOCALE = new Locale("en", "GB");
-
-	private static ResourceBundle EnglishTexts = null;
-	private static ResourceBundle LocalTexts = null;
+	/** Properties object into which all the texts are copied */
+	private static Properties LocalTexts = null;
 
 	/** External properties file for developer testing */
 	private static Properties ExternalPropsFile = null;
@@ -32,26 +30,44 @@ public abstract class I18nManager
 	 */
 	public static void init(Locale inLocale)
 	{
+		final String BUNDLE_NAME = "tim.prune.lang.prune-texts";
+		final Locale BACKUP_LOCALE = new Locale("en", "GB");
+
+		LocalTexts = new Properties();
 		// Load English texts first to use as defaults
-		EnglishTexts = ResourceBundle.getBundle(BUNDLE_NAME, BACKUP_LOCALE);
+		loadFromBundle(ResourceBundle.getBundle(BUNDLE_NAME, BACKUP_LOCALE));
 
 		// Get bundle for selected locale, if any
 		try
 		{
 			if (inLocale != null)
 			{
-				LocalTexts = ResourceBundle.getBundle(BUNDLE_NAME, inLocale);
+				loadFromBundle(ResourceBundle.getBundle(BUNDLE_NAME, inLocale));
 			}
 			else
 			{
 				// locale is null so just use the system default
-				LocalTexts = ResourceBundle.getBundle(BUNDLE_NAME, Locale.getDefault());
+				loadFromBundle(ResourceBundle.getBundle(BUNDLE_NAME, Locale.getDefault()));
 			}
 		}
 		catch (MissingResourceException mre) { // ignore error, default to english
 		}
 	}
 
+	/**
+	 * Copy all the translations from the given bundle and store in the Properties object
+	 * overwriting the existing translations if necessary
+	 * @param inBundle bundle object loaded from file
+	 */
+	private static void loadFromBundle(ResourceBundle inBundle)
+	{
+		Enumeration<String> e = inBundle.getKeys();
+		while (e.hasMoreElements())
+		{
+			String key = e.nextElement();
+			LocalTexts.setProperty(key, inBundle.getString(key));
+		}
+	}
 
 	/**
 	 * Add a language file
@@ -92,26 +108,16 @@ public abstract class I18nManager
 			String extText = ExternalPropsFile.getProperty(inKey);
 			if (extText != null) return extText;
 		}
-		// look in extra texts if available
+		// look in texts if available
 		if (LocalTexts != null)
 		{
 			try
 			{
-				String localText = LocalTexts.getString(inKey);
+				String localText = LocalTexts.getProperty(inKey);
 				if (localText != null) return localText;
 			}
 			catch (MissingResourceException mre) {}
 		}
-		// look in english texts
-		if (EnglishTexts != null)
-		{
-			try
-			{
-				String engText = EnglishTexts.getString(inKey);
-				if (engText != null) return engText;
-			}
-			catch (MissingResourceException mre) {}
-		}
 		// return the key itself
 		return inKey;
 	}
diff --git a/tim/prune/config/Config.java b/tim/prune/config/Config.java
index ad3cc9c..8921332 100644
--- a/tim/prune/config/Config.java
+++ b/tim/prune/config/Config.java
@@ -81,6 +81,8 @@ public abstract class Config
 	public static final String KEY_POINT_COLOURER = "prune.pointcolourer";
 	/** Key for line width used for drawing */
 	public static final String KEY_LINE_WIDTH = "prune.linewidth";
+	/** Key for whether to use antialiasing or not */
+	public static final String KEY_ANTIALIAS = "prune.antialias";
 	/** Key for kml track colour */
 	public static final String KEY_KML_TRACK_COLOUR = "prune.kmltrackcolour";
 	/** Key for autosaving settings */
@@ -184,6 +186,7 @@ public abstract class Config
 		props.put(KEY_GPSBABEL_PATH, "gpsbabel");
 		props.put(KEY_IMPORT_FILE_FORMAT, "-1"); // no file format selected
 		props.put(KEY_KMZ_IMAGE_SIZE, "240");
+		props.put(KEY_ANTIALIAS, "1"); // antialias on by default
 		props.put(KEY_AUTOSAVE_SETTINGS, "0"); // autosave false by default
 		props.put(KEY_UNITSET_KEY, "unitset.kilometres"); // metric by default
 		props.put(KEY_HEIGHT_EXAGGERATION, "100"); // 100%, no exaggeration
@@ -345,9 +348,9 @@ public abstract class Config
 	 */
 	public static boolean isKeyBoolean(String inKey)
 	{
-		// Only one boolean key so far (after metric flag was removed)
 		return inKey != null && (
-			inKey.equals(KEY_SHOW_MAP));
+			inKey.equals(KEY_SHOW_MAP) || inKey.equals(KEY_AUTOSAVE_SETTINGS) || inKey.equals(KEY_ONLINE_MODE)
+			|| inKey.equals(KEY_ANTIALIAS));
 	}
 
 	/**
diff --git a/tim/prune/copyright.txt b/tim/prune/copyright.txt
index 7990765..f5bd232 100644
--- a/tim/prune/copyright.txt
+++ b/tim/prune/copyright.txt
@@ -1,4 +1,4 @@
-The source code of GpsPrune is copyright 2006-2014 activityworkshop.net
+The source code of GpsPrune is copyright 2006-2015 activityworkshop.net
 and is distributed under the terms of the Gnu GPL version 2.
 
 Portions of the package jpeg.drew (if included in this package) were taken
diff --git a/tim/prune/data/Field.java b/tim/prune/data/Field.java
index d020a7e..7b9d779 100644
--- a/tim/prune/data/Field.java
+++ b/tim/prune/data/Field.java
@@ -22,8 +22,9 @@ public class Field
 
 	public static final Field SPEED          = new Field("fieldname.speed", true);
 	public static final Field VERTICAL_SPEED = new Field("fieldname.verticalspeed", true);
+	public static final Field MEDIA_FILENAME = new Field("fieldname.mediafilename", true);
 
-	// TODO: Field for photo filename, ability to load (from text) and save (to text)
+	// TODO: Ability to load media (from text) and save (to text)
 
 	/** List of all the available fields */
 	private static final Field[] ALL_AVAILABLE_FIELDS = {
diff --git a/tim/prune/data/SourceInfo.java b/tim/prune/data/SourceInfo.java
index b9609f1..5e40eee 100644
--- a/tim/prune/data/SourceInfo.java
+++ b/tim/prune/data/SourceInfo.java
@@ -9,7 +9,7 @@ import java.io.File;
 public class SourceInfo
 {
 	/** File type of source file */
-	public enum FILE_TYPE {TEXT, GPX, KML, NMEA, GPSBABEL, GPSIES};
+	public enum FILE_TYPE {TEXT, GPX, KML, NMEA, GPSBABEL, GPSIES, JSON};
 
 	/** Source file */
 	private File _sourceFile = null;
diff --git a/tim/prune/data/Timestamp.java b/tim/prune/data/Timestamp.java
index d175c64..cfddffe 100644
--- a/tim/prune/data/Timestamp.java
+++ b/tim/prune/data/Timestamp.java
@@ -62,6 +62,7 @@ public class Timestamp
 		FIXED_FORMAT5,
 		FIXED_FORMAT6,
 		FIXED_FORMAT7,
+		FIXED_FORMAT8,
 		GENERAL_STRING
 	}
 
@@ -69,7 +70,7 @@ public class Timestamp
 	private static ParseType[] ALL_PARSE_TYPES = {ParseType.NONE, ParseType.ISO8601_FRACTIONAL, ParseType.LONG,
 		ParseType.FIXED_FORMAT0, ParseType.FIXED_FORMAT1, ParseType.FIXED_FORMAT2, ParseType.FIXED_FORMAT3,
 		ParseType.FIXED_FORMAT4, ParseType.FIXED_FORMAT5, ParseType.FIXED_FORMAT6, ParseType.FIXED_FORMAT7,
-		ParseType.GENERAL_STRING};
+		ParseType.FIXED_FORMAT8, ParseType.GENERAL_STRING};
 
 	// Static block to initialise offsets
 	static
@@ -95,6 +96,7 @@ public class Timestamp
 			new SimpleDateFormat("dd MMM yyyy HH:mm:ss"),
 			new SimpleDateFormat("dd-MMM-yyyy HH:mm:ss"),
 			new SimpleDateFormat("yyyy MMM dd HH:mm:ss"),
+			new SimpleDateFormat("MMM dd, yyyy hh:mm:ss aa"),
 			ISO_8601_FORMAT, ISO_8601_FORMAT_NOZ
 		};
 		for (DateFormat df : ALL_DATE_FORMATS) {
@@ -180,6 +182,7 @@ public class Timestamp
 			case FIXED_FORMAT5: return parseString(inString, ALL_DATE_FORMATS[5]);
 			case FIXED_FORMAT6: return parseString(inString, ALL_DATE_FORMATS[6]);
 			case FIXED_FORMAT7: return parseString(inString, ALL_DATE_FORMATS[7]);
+			case FIXED_FORMAT8: return parseString(inString, ALL_DATE_FORMATS[8]);
 
 			case GENERAL_STRING:
 				if (inString.length() == 19)
diff --git a/tim/prune/data/Track.java b/tim/prune/data/Track.java
index 31c9b4e..4ae47ff 100644
--- a/tim/prune/data/Track.java
+++ b/tim/prune/data/Track.java
@@ -178,21 +178,30 @@ public class Track
 
 	/**
 	 * Delete the points marked for deletion
+	 * @param inSplitSegments true to split segments at deleted points
 	 * @return number of points deleted
 	 */
-	public int deleteMarkedPoints()
+	public int deleteMarkedPoints(boolean inSplitSegments)
 	{
 		int numCopied = 0;
-		// Copy selected points
+		// Copy selected points into a new point array
 		DataPoint[] newPointArray = new DataPoint[_numPoints];
+		boolean prevPointDeleted = false;
 		for (int i=0; i<_numPoints; i++)
 		{
 			DataPoint point = _dataPoints[i];
 			// Don't delete photo points
 			if (point.hasMedia() || !point.getDeleteFlag())
 			{
+				if (prevPointDeleted && inSplitSegments) {
+					point.setSegmentStart(true);
+				}
 				newPointArray[numCopied] = point;
 				numCopied++;
+				prevPointDeleted = false;
+			}
+			else {
+				prevPointDeleted = true;
 			}
 		}
 
@@ -901,7 +910,7 @@ public class Track
 	 */
 	private static final double getMinXDist(double inX)
 	{
-		// TODO: Can use some kind of floor here?
+		// TODO: Should be abs(mod(inX-0.5,1)-0.5) - means two adds, one mod, one abs instead of two adds, 3 abss and two compares
 		return Math.min(Math.min(Math.abs(inX), Math.abs(inX-1.0)), Math.abs(inX+1.0));
 	}
 
diff --git a/tim/prune/data/TrackInfo.java b/tim/prune/data/TrackInfo.java
index 7bcbc64..00d6588 100644
--- a/tim/prune/data/TrackInfo.java
+++ b/tim/prune/data/TrackInfo.java
@@ -272,12 +272,14 @@ public class TrackInfo
 
 	/**
 	 * Delete all the points which have been marked for deletion
+	 * @param inSplitSegments true to split segments at deleted points
 	 * @return number of points deleted
 	 */
-	public int deleteMarkedPoints()
+	public int deleteMarkedPoints(boolean inSplitSegments)
 	{
-		int numDeleted = _track.deleteMarkedPoints();
-		if (numDeleted > 0) {
+		int numDeleted = _track.deleteMarkedPoints(inSplitSegments);
+		if (numDeleted > 0)
+		{
 			_selection.clearAll();
 			UpdateMessageBroker.informSubscribers();
 		}
diff --git a/tim/prune/function/AboutScreen.java b/tim/prune/function/AboutScreen.java
index 109d07e..c3a9f5b 100644
--- a/tim/prune/function/AboutScreen.java
+++ b/tim/prune/function/AboutScreen.java
@@ -98,8 +98,8 @@ public class AboutScreen extends GenericFunction
 		descBuffer.append("<p>").append(I18nManager.getText("dialog.about.summarytext3")).append("</p>");
 		descBuffer.append("<p>").append(I18nManager.getText("dialog.about.languages")).append(" : ")
 			.append("\u010de\u0161tina, deutsch, english, espa\u00F1ol, fran\u00E7ais, italiano, magyar,<br>" +
-				" nederlands, polski, portugu\u00EAs, \u0440\u0443\u0441\u0441\u043a\u0438\u0439 (russian), \u4e2d\u6587 (chinese), \u65E5\u672C\u8A9E (japanese),<br>" +
-				" \uD55C\uAD6D\uC5B4/\uC870\uC120\uB9D0 (korean), schwiizerd\u00FC\u00FCtsch, t\u00FCrk\u00E7e, afrikaans, rom\u00E2n\u0103, ukrainian</p>");
+				" nederlands, polski, portugu\u00EAs, rom\u00E2n\u0103, \u0440\u0443\u0441\u0441\u043a\u0438\u0439 (russian), \u4e2d\u6587 (chinese),<br>" +
+				" \u65E5\u672C\u8A9E (japanese), \uD55C\uAD6D\uC5B4/\uC870\uC120\uB9D0 (korean), schwiizerd\u00FC\u00FCtsch, t\u00FCrk\u00E7e, afrikaans, ukrainian</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));
@@ -200,7 +200,7 @@ public class AboutScreen extends GenericFunction
 			new JLabel(" katpatuka, R\u00E9mi, Marcus, Ali, Javier, Jeroen, prot_d, Gy\u00F6rgy,"),
 			1, 5);
 		addToGridBagPanel(creditsPanel, gridBag, constraints,
-			new JLabel(" HooAU, Sergey, P\u00E9ter, serhijdubyk, Peter"),
+			new JLabel(" HooAU, Sergey, P\u00E9ter, serhijdubyk, Peter, Cristian"),
 			1, 6);
 		addToGridBagPanel(creditsPanel, gridBag, constraints,
 			new JLabel(I18nManager.getText("dialog.about.credits.translations") + " : "),
diff --git a/tim/prune/function/GetWikipediaFunction.java b/tim/prune/function/GetWikipediaFunction.java
index 3ffdd06..be33a95 100644
--- a/tim/prune/function/GetWikipediaFunction.java
+++ b/tim/prune/function/GetWikipediaFunction.java
@@ -13,8 +13,8 @@ import tim.prune.data.DataPoint;
 import tim.prune.data.Field;
 import tim.prune.data.Latitude;
 import tim.prune.data.Longitude;
-import tim.prune.function.gpsies.GenericDownloaderFunction;
-import tim.prune.function.gpsies.GpsiesTrack;
+import tim.prune.function.search.GenericDownloaderFunction;
+import tim.prune.function.search.SearchResult;
 
 /**
  * Function to load nearby point information from Wikipedia
@@ -128,7 +128,7 @@ public class GetWikipediaFunction extends GenericDownloaderFunction
 			inStream.close();
 		} catch (Exception e) {}
 		// Add track list to model
-		ArrayList<GpsiesTrack> trackList = xmlHandler.getTrackList();
+		ArrayList<SearchResult> trackList = xmlHandler.getTrackList();
 		_trackListModel.addTracks(trackList);
 
 		// Show error message if any
@@ -157,11 +157,11 @@ public class GetWikipediaFunction extends GenericDownloaderFunction
 			int rowNum = rowNums[i];
 			if (rowNum >= 0 && rowNum < _trackListModel.getRowCount())
 			{
-				String coords = _trackListModel.getTrack(rowNum).getDownloadLink();
-				String[] latlon = coords.split(",");
-				if (latlon.length == 2)
+				String lat = _trackListModel.getTrack(rowNum).getLatitude();
+				String lon = _trackListModel.getTrack(rowNum).getLongitude();
+				if (lat != null && lon != null)
 				{
-					DataPoint point = new DataPoint(new Latitude(latlon[0]), new Longitude(latlon[1]), null);
+					DataPoint point = new DataPoint(new Latitude(lat), new Longitude(lon), null);
 					point.setFieldValue(Field.WAYPT_NAME, _trackListModel.getTrack(rowNum).getTrackName(), false);
 					_app.createPoint(point);
 				}
diff --git a/tim/prune/function/GetWikipediaXmlHandler.java b/tim/prune/function/GetWikipediaXmlHandler.java
index f70e5f7..b5cb3f9 100644
--- a/tim/prune/function/GetWikipediaXmlHandler.java
+++ b/tim/prune/function/GetWikipediaXmlHandler.java
@@ -6,17 +6,17 @@ import org.xml.sax.Attributes;
 import org.xml.sax.SAXException;
 import org.xml.sax.helpers.DefaultHandler;
 
-import tim.prune.function.gpsies.GpsiesTrack;
+import tim.prune.function.search.SearchResult;
 
 /**
- * XML handler for dealing with XML returned from the geonames api
+ * XML handler for dealing with XML returned from the geonames api,
+ * both from the search by name and search by location
  */
 public class GetWikipediaXmlHandler extends DefaultHandler
 {
 	private String _value = null;
-	private ArrayList<GpsiesTrack> _trackList = null;
-	private GpsiesTrack _track = null;
-	private String _lat = null, _lon = null;
+	private ArrayList<SearchResult> _trackList = null;
+	private SearchResult _track = null;
 	private String _errorMessage = null;
 
 
@@ -27,12 +27,10 @@ public class GetWikipediaXmlHandler extends DefaultHandler
 		Attributes inAttributes) throws SAXException
 	{
 		if (inTagName.equals("geonames")) {
-			_trackList = new ArrayList<GpsiesTrack>();
+			_trackList = new ArrayList<SearchResult>();
 		}
 		else if (inTagName.equals("entry")) {
-			_track = new GpsiesTrack();
-			_lat = null;
-			_lon = null;
+			_track = new SearchResult();
 		}
 		else if (inTagName.equals("status")) {
 			_errorMessage = inAttributes.getValue("message");
@@ -49,7 +47,6 @@ public class GetWikipediaXmlHandler extends DefaultHandler
 	{
 		if (inTagName.equals("entry")) {
 			// end of the entry
-			_track.setDownloadLink(_lat + "," + _lon);
 			_trackList.add(_track);
 		}
 		else if (inTagName.equals("title")) {
@@ -59,10 +56,10 @@ public class GetWikipediaXmlHandler extends DefaultHandler
 			_track.setDescription(_value);
 		}
 		else if (inTagName.equals("lat")) {
-			_lat = _value;
+			_track.setLatitude(_value);
 		}
 		else if (inTagName.equals("lng")) {
-			_lon = _value;
+			_track.setLongitude(_value);
 		}
 		else if (inTagName.equals("distance")) {
 			try {
@@ -90,7 +87,7 @@ public class GetWikipediaXmlHandler extends DefaultHandler
 	/**
 	 * @return the list of tracks
 	 */
-	public ArrayList<GpsiesTrack> getTrackList()
+	public ArrayList<SearchResult> getTrackList()
 	{
 		return _trackList;
 	}
diff --git a/tim/prune/function/GetWikipediaXmlHandler.java b/tim/prune/function/OpenCachingDeXmlHandler.java
similarity index 61%
copy from tim/prune/function/GetWikipediaXmlHandler.java
copy to tim/prune/function/OpenCachingDeXmlHandler.java
index f70e5f7..b4b28d5 100644
--- a/tim/prune/function/GetWikipediaXmlHandler.java
+++ b/tim/prune/function/OpenCachingDeXmlHandler.java
@@ -6,17 +6,16 @@ import org.xml.sax.Attributes;
 import org.xml.sax.SAXException;
 import org.xml.sax.helpers.DefaultHandler;
 
-import tim.prune.function.gpsies.GpsiesTrack;
+import tim.prune.function.search.SearchResult;
 
 /**
- * XML handler for dealing with XML returned from the geonames api
+ * XML handler for dealing with XML returned from the opencaching.de api
  */
-public class GetWikipediaXmlHandler extends DefaultHandler
+public class OpenCachingDeXmlHandler extends DefaultHandler
 {
 	private String _value = null;
-	private ArrayList<GpsiesTrack> _trackList = null;
-	private GpsiesTrack _track = null;
-	private String _lat = null, _lon = null;
+	private ArrayList<SearchResult> _trackList = null;
+	private SearchResult _track = null;
 	private String _errorMessage = null;
 
 
@@ -26,17 +25,16 @@ public class GetWikipediaXmlHandler extends DefaultHandler
 	public void startElement(String inUri, String inLocalName, String inTagName,
 		Attributes inAttributes) throws SAXException
 	{
-		if (inTagName.equals("geonames")) {
-			_trackList = new ArrayList<GpsiesTrack>();
+		if (inTagName.equals("result")) {
+			_trackList = new ArrayList<SearchResult>();
 		}
-		else if (inTagName.equals("entry")) {
-			_track = new GpsiesTrack();
-			_lat = null;
-			_lon = null;
-		}
-		else if (inTagName.equals("status")) {
-			_errorMessage = inAttributes.getValue("message");
+		else if (inTagName.equals("cache"))
+		{
+			_track = new SearchResult();
 		}
+//		else if (inTagName.equals("status")) {
+//			_errorMessage = inAttributes.getValue("message");
+//		}
 		else _value = null;
 		super.startElement(inUri, inLocalName, inTagName, inAttributes);
 	}
@@ -47,22 +45,22 @@ public class GetWikipediaXmlHandler extends DefaultHandler
 	public void endElement(String inUri, String inLocalName, String inTagName)
 	throws SAXException
 	{
-		if (inTagName.equals("entry")) {
+		if (inTagName.equals("cache"))
+		{
 			// end of the entry
-			_track.setDownloadLink(_lat + "," + _lon);
 			_trackList.add(_track);
 		}
-		else if (inTagName.equals("title")) {
+		else if (inTagName.equals("name")) {
 			_track.setTrackName(_value);
 		}
-		else if (inTagName.equals("summary")) {
+		else if (inTagName.equals("desc")) {
 			_track.setDescription(_value);
 		}
 		else if (inTagName.equals("lat")) {
-			_lat = _value;
+			_track.setLatitude(_value);
 		}
-		else if (inTagName.equals("lng")) {
-			_lon = _value;
+		else if (inTagName.equals("lon")) {
+			_track.setLongitude(_value);
 		}
 		else if (inTagName.equals("distance")) {
 			try {
@@ -70,8 +68,8 @@ public class GetWikipediaXmlHandler extends DefaultHandler
 			}
 			catch (NumberFormatException nfe) {}
 		}
-		else if (inTagName.equals("wikipediaUrl")) {
-			_track.setWebUrl(_value.replaceFirst("http://", "https://"));
+		else if (inTagName.equals("link")) {
+			_track.setWebUrl(_value);
 		}
 		super.endElement(inUri, inLocalName, inTagName);
 	}
@@ -90,7 +88,7 @@ public class GetWikipediaXmlHandler extends DefaultHandler
 	/**
 	 * @return the list of tracks
 	 */
-	public ArrayList<GpsiesTrack> getTrackList()
+	public ArrayList<SearchResult> getTrackList()
 	{
 		return _trackList;
 	}
diff --git a/tim/prune/function/RearrangePhotosFunction.java b/tim/prune/function/RearrangePhotosFunction.java
index 466cd66..e278dbe 100644
--- a/tim/prune/function/RearrangePhotosFunction.java
+++ b/tim/prune/function/RearrangePhotosFunction.java
@@ -89,7 +89,7 @@ public class RearrangePhotosFunction extends RearrangeFunction
 				System.arraycopy(nonPhotos, 0, neworder, 0, numNonPhotos);
 				System.arraycopy(photos, 0, neworder, numNonPhotos, numPhotos);
 			}
-			
+
 			// Give track the new point order
 			pointsChanged = track.replaceContents(neworder);
 		}
diff --git a/tim/prune/function/GetWikipediaFunction.java b/tim/prune/function/SearchOpenCachingDeFunction.java
similarity index 54%
copy from tim/prune/function/GetWikipediaFunction.java
copy to tim/prune/function/SearchOpenCachingDeFunction.java
index 3ffdd06..20e2fc8 100644
--- a/tim/prune/function/GetWikipediaFunction.java
+++ b/tim/prune/function/SearchOpenCachingDeFunction.java
@@ -13,28 +13,24 @@ import tim.prune.data.DataPoint;
 import tim.prune.data.Field;
 import tim.prune.data.Latitude;
 import tim.prune.data.Longitude;
-import tim.prune.function.gpsies.GenericDownloaderFunction;
-import tim.prune.function.gpsies.GpsiesTrack;
+import tim.prune.function.search.GenericDownloaderFunction;
+import tim.prune.function.search.SearchResult;
 
 /**
- * Function to load nearby point information from Wikipedia
- * according to the currently viewed area
+ * Function to load information about geocaches nearby to the current point
+ * using the service at opencaching.de
  */
-public class GetWikipediaFunction extends GenericDownloaderFunction
+public class SearchOpenCachingDeFunction extends GenericDownloaderFunction
 {
-	/** Maximum number of results to get */
-	private static final int MAX_RESULTS = 20;
 	/** Maximum distance from point in km */
-	private static final int MAX_DISTANCE = 15;
-	/** Username to use for geonames queries */
-	private static final String GEONAMES_USERNAME = "gpsprune";
+	private static final int MAX_DISTANCE = 50;
 
 
 	/**
 	 * Constructor
 	 * @param inApp App object
 	 */
-	public GetWikipediaFunction(App inApp) {
+	public SearchOpenCachingDeFunction(App inApp) {
 		super(inApp);
 	}
 
@@ -42,7 +38,7 @@ public class GetWikipediaFunction extends GenericDownloaderFunction
 	 * @return name key
 	 */
 	public String getNameKey() {
-		return "function.getwikipedia";
+		return "function.searchopencachingde";
 	}
 
 	/**
@@ -57,41 +53,25 @@ public class GetWikipediaFunction extends GenericDownloaderFunction
 
 
 	/**
-	 * Run method to call geonames in separate thread
+	 * Run method to call service in a separate thread
 	 */
 	public void run()
 	{
 		_statusLabel.setText(I18nManager.getText("confirm.running"));
-		// Get coordinates from current point (if any) or from centre of screen
-		double lat = 0.0, lon = 0.0;
+		// Get coordinates from current point
 		DataPoint point = _app.getTrackInfo().getCurrentPoint();
 		if (point == null)
 		{
-			double[] coords = _app.getViewport().getBounds();
-			lat = (coords[0] + coords[2]) / 2.0;
-			lon = (coords[1] + coords[3]) / 2.0;
-		}
-		else
-		{
-			lat = point.getLatitude().getDouble();
-			lon = point.getLongitude().getDouble();
+			return;
 		}
 
-		// Firstly try the local language
-		String lang = I18nManager.getText("wikipedia.lang");
-		submitSearch(lat, lon, lang);
-		// If we didn't get anything, try a secondary language
-		if (_trackListModel.isEmpty() && _errorMessage == null && lang.equals("als")) {
-			submitSearch(lat, lon, "de");
-		}
-		// If still nothing then try english
-		if (_trackListModel.isEmpty() && _errorMessage == null && !lang.equals("en")) {
-			submitSearch(lat, lon, "en");
-		}
+		final double lat = point.getLatitude().getDouble();
+		final double lon = point.getLongitude().getDouble();
+		submitSearch(lat, lon);
 
 		// Set status label according to error or "none found", leave blank if ok
 		if (_errorMessage == null && _trackListModel.isEmpty()) {
-			_errorMessage = I18nManager.getText("dialog.wikipedia.nonefound");
+			_errorMessage = I18nManager.getText("dialog.geocaching.nonefound");
 		}
 		_statusLabel.setText(_errorMessage == null ? "" : _errorMessage);
 	}
@@ -100,17 +80,15 @@ public class GetWikipediaFunction extends GenericDownloaderFunction
 	 * Submit the search for the given parameters
 	 * @param inLat latitude
 	 * @param inLon longitude
-	 * @param inLang language code to use, such as en or de
 	 */
-	private void submitSearch(double inLat, double inLon, String inLang)
+	private void submitSearch(double inLat, double inLon)
 	{
-		// Example http://api.geonames.org/findNearbyWikipedia?lat=47&lng=9
-		String urlString = "http://api.geonames.org/findNearbyWikipedia?lat=" +
-			inLat + "&lng=" + inLon + "&maxRows=" + MAX_RESULTS
-			+ "&radius=" + MAX_DISTANCE + "&lang=" + inLang
-			+ "&username=" + GEONAMES_USERNAME;
+		// The only parameters are lat and long from the current point
+		String urlString = "http://opencaching.de/search.php?searchto=searchbydistance&showresult=1"
+			+ "&output=XML&sort=bydistance&lat=" + inLat
+			+ "&lon=" + inLon + "&distance=" + MAX_DISTANCE + "&unit=km";
 		// Parse the returned XML with a special handler
-		GetWikipediaXmlHandler xmlHandler = new GetWikipediaXmlHandler();
+		OpenCachingDeXmlHandler xmlHandler = new OpenCachingDeXmlHandler();
 		InputStream inStream = null;
 
 		try
@@ -128,7 +106,7 @@ public class GetWikipediaFunction extends GenericDownloaderFunction
 			inStream.close();
 		} catch (Exception e) {}
 		// Add track list to model
-		ArrayList<GpsiesTrack> trackList = xmlHandler.getTrackList();
+		ArrayList<SearchResult> trackList = xmlHandler.getTrackList();
 		_trackListModel.addTracks(trackList);
 
 		// Show error message if any
@@ -157,11 +135,11 @@ public class GetWikipediaFunction extends GenericDownloaderFunction
 			int rowNum = rowNums[i];
 			if (rowNum >= 0 && rowNum < _trackListModel.getRowCount())
 			{
-				String coords = _trackListModel.getTrack(rowNum).getDownloadLink();
-				String[] latlon = coords.split(",");
-				if (latlon.length == 2)
+				String lat = _trackListModel.getTrack(rowNum).getLatitude();
+				String lon = _trackListModel.getTrack(rowNum).getLongitude();
+				if (lat != null && lon != null)
 				{
-					DataPoint point = new DataPoint(new Latitude(latlon[0]), new Longitude(latlon[1]), null);
+					DataPoint point = new DataPoint(new Latitude(lat), new Longitude(lon), null);
 					point.setFieldValue(Field.WAYPT_NAME, _trackListModel.getTrack(rowNum).getTrackName(), false);
 					_app.createPoint(point);
 				}
diff --git a/tim/prune/function/SearchWikipediaNames.java b/tim/prune/function/SearchWikipediaNames.java
index 5ab3950..20b23de 100644
--- a/tim/prune/function/SearchWikipediaNames.java
+++ b/tim/prune/function/SearchWikipediaNames.java
@@ -16,8 +16,8 @@ import tim.prune.data.DataPoint;
 import tim.prune.data.Field;
 import tim.prune.data.Latitude;
 import tim.prune.data.Longitude;
-import tim.prune.function.gpsies.GenericDownloaderFunction;
-import tim.prune.function.gpsies.GpsiesTrack;
+import tim.prune.function.search.GenericDownloaderFunction;
+import tim.prune.function.search.SearchResult;
 
 /**
  * Function to search Wikipedia for place names
@@ -133,7 +133,7 @@ public class SearchWikipediaNames extends GenericDownloaderFunction
 			inStream.close();
 		} catch (Exception e) {}
 		// Add track list to model
-		ArrayList<GpsiesTrack> trackList = xmlHandler.getTrackList();
+		ArrayList<SearchResult> trackList = xmlHandler.getTrackList();
 		// TODO: Do a better job of sorting replies by relevance - use three different lists
 		_trackListModel.addTracks(trackList);
 	}
@@ -203,11 +203,11 @@ public class SearchWikipediaNames extends GenericDownloaderFunction
 			int rowNum = rowNums[i];
 			if (rowNum >= 0 && rowNum < _trackListModel.getRowCount())
 			{
-				String coords = _trackListModel.getTrack(rowNum).getDownloadLink();
-				String[] latlon = coords.split(",");
-				if (latlon.length == 2)
+				String lat = _trackListModel.getTrack(rowNum).getLatitude();
+				String lon = _trackListModel.getTrack(rowNum).getLongitude();
+				if (lat != null && lon != null)
 				{
-					DataPoint point = new DataPoint(new Latitude(latlon[0]), new Longitude(latlon[1]), null);
+					DataPoint point = new DataPoint(new Latitude(lat), new Longitude(lon), null);
 					point.setFieldValue(Field.WAYPT_NAME, _trackListModel.getTrack(rowNum).getTrackName(), false);
 					_app.createPoint(point);
 				}
diff --git a/tim/prune/function/SetLanguage.java b/tim/prune/function/SetLanguage.java
index 27ec94e..832b521 100644
--- a/tim/prune/function/SetLanguage.java
+++ b/tim/prune/function/SetLanguage.java
@@ -41,15 +41,15 @@ public class SetLanguage extends GenericFunction
 	private int _startIndex = 0;
 
 	/** Names of languages for display in dropdown (not translated) */
-	private static final String[] LANGUAGE_NAMES = {"\u010de\u0161tina", "deutsch", "english", "american english",
-		"espa\u00F1ol", "fran\u00E7ais", "italiano", "magyar", "nederlands", "polski",
-		"portugu\u00EAs", "\u0440\u0443\u0441\u0441\u043a\u0438\u0439 (russian)", "\u4e2d\u6587 (chinese)", "\u65E5\u672C\u8A9E (japanese)",
-		"\uD55C\uAD6D\uC5B4/\uC870\uC120\uB9D0 (korean)", "schwiizerd\u00FC\u00FCtsch", "t\u00FCrk\u00E7e",
-		"afrikaans", "rom\u00E2n\u0103", "\u0443\u043a\u0440\u0430\u0457\u043d\u0441\u044c\u043a\u0430 \u043c\u043e\u0432\u0430 (ukrainian)"
+	private static final String[] LANGUAGE_NAMES = {"afrikaans", "\u010de\u0161tina", "deutsch", "english", "american english",
+		"espa\u00F1ol", "fran\u00E7ais", "italiano", "magyar", "nederlands", "polski", "portugu\u00EAs", "rom\u00E2n\u0103",
+		"\u0440\u0443\u0441\u0441\u043a\u0438\u0439 (russian)", "\u4e2d\u6587 (chinese)",
+		"\u65E5\u672C\u8A9E (japanese)", "\uD55C\uAD6D\uC5B4/\uC870\uC120\uB9D0 (korean)", "schwiizerd\u00FC\u00FCtsch",
+		"t\u00FCrk\u00E7e", "\u0443\u043a\u0440\u0430\u0457\u043d\u0441\u044c\u043a\u0430 \u043c\u043e\u0432\u0430 (ukrainian)"
 	};
 	/** Associated language codes (must be in same order as names!) */
-	private static final String[] LANGUAGE_CODES = {"cz", "de", "en", "en_us", "es", "fr", "it", "hu",
-		"nl", "pl", "pt", "ru", "zh", "ja", "ko", "de_ch", "tr", "af", "ro", "uk"
+	private static final String[] LANGUAGE_CODES = {"af", "cz", "de", "en", "en_us", "es", "fr", "it", "hu",
+		"nl", "pl", "pt", "ro", "ru", "zh", "ja", "ko", "de_ch", "tr", "uk"
 	};
 
 
diff --git a/tim/prune/function/autoplay/AutoplayFunction.java b/tim/prune/function/autoplay/AutoplayFunction.java
new file mode 100644
index 0000000..acb71ee
--- /dev/null
+++ b/tim/prune/function/autoplay/AutoplayFunction.java
@@ -0,0 +1,334 @@
+package tim.prune.function.autoplay;
+
+import java.awt.Component;
+import java.awt.FlowLayout;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.awt.event.WindowAdapter;
+import java.awt.event.WindowEvent;
+import java.util.Iterator;
+import java.util.TreeSet;
+
+import javax.swing.BoxLayout;
+import javax.swing.JButton;
+import javax.swing.JCheckBox;
+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.data.Field;
+import tim.prune.data.Timestamp;
+import tim.prune.data.Track;
+import tim.prune.gui.GuiGridLayout;
+import tim.prune.gui.IconManager;
+import tim.prune.gui.WholeNumberField;
+
+/**
+ * Function to handle the autoplay of a track
+ */
+public class AutoplayFunction extends GenericFunction implements Runnable
+{
+	/** Dialog */
+	private JDialog _dialog = null;
+	/** Entry field for number of seconds to autoplay for */
+	private WholeNumberField _durationField = null;
+	/** Checkbox for using point timestamps */
+	private JCheckBox _useTimestampsCheckbox = null;
+	/** Buttons for controlling autoplay */
+	private JButton _rewindButton = null, _pauseButton = null, _playButton = null;
+	/** Flag for recalculating all the times */
+	private boolean _needToRecalculate = true;
+	/** Point list */
+	private PointList _pointList = null;
+	/** Flag to see if we're still running or not */
+	private boolean _running = false;
+	/** Remember the time we started playing */
+	private long _startTime = 0L;
+
+
+	/**
+	 * Constructor
+	 * @param inApp App object
+	 */
+	public AutoplayFunction(App inApp) {
+		super(inApp);
+	}
+
+	@Override
+	public String getNameKey() {
+		return "function.autoplay";
+	}
+
+	/**
+	 * 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();
+			_dialog.setResizable(false);
+			_dialog.addWindowListener(new WindowAdapter() {
+				public void windowClosing(WindowEvent e) {
+					_running = false;
+					super.windowClosing(e);
+				}
+			});
+		}
+		// Don't select any point
+		_app.getTrackInfo().selectPoint(-1);
+		// enable buttons
+		enableButtons(false, true); // can't pause, can play
+		// MAYBE: reset duration if it's too long
+		// Disable point checkbox if there aren't any times
+		final boolean hasTimes = _app.getTrackInfo().getTrack().hasData(Field.TIMESTAMP);
+		_useTimestampsCheckbox.setEnabled(hasTimes);
+		if (!hasTimes)
+		{
+			_useTimestampsCheckbox.setSelected(false);
+		}
+
+		_needToRecalculate = true;
+		_dialog.setVisible(true);
+	}
+
+
+	/**
+	 * Create dialog components
+	 * @return Panel containing all gui elements in dialog
+	 */
+	private Component makeDialogComponents()
+	{
+		JPanel dialogPanel = new JPanel();
+		dialogPanel.setLayout(new BoxLayout(dialogPanel, BoxLayout.Y_AXIS));
+		// Duration panel
+		JPanel durationPanel = new JPanel();
+		GuiGridLayout grid = new GuiGridLayout(durationPanel);
+		grid.add(new JLabel(I18nManager.getText("dialog.autoplay.duration") + " :"));
+		_durationField = new WholeNumberField(3);
+		_durationField.setValue(60); // default is one minute
+		_durationField.addActionListener(new ActionListener() {
+			public void actionPerformed(ActionEvent e) {
+				onParamsChanged();
+			}
+		});
+		grid.add(_durationField);
+		durationPanel.setAlignmentX(Component.CENTER_ALIGNMENT);
+		dialogPanel.add(durationPanel);
+		// Checkbox
+		_useTimestampsCheckbox = new JCheckBox(I18nManager.getText("dialog.autoplay.usetimestamps"));
+		_useTimestampsCheckbox.setAlignmentX(Component.CENTER_ALIGNMENT);
+		dialogPanel.add(_useTimestampsCheckbox);
+		_useTimestampsCheckbox.addActionListener(new ActionListener() {
+			public void actionPerformed(ActionEvent e) {
+				onParamsChanged();
+			}
+		});
+		// Button panel
+		JPanel buttonPanel = new JPanel();
+		buttonPanel.setLayout(new FlowLayout(FlowLayout.CENTER));
+		buttonPanel.add(_rewindButton = new JButton(IconManager.getImageIcon(IconManager.AUTOPLAY_REWIND)));
+		_rewindButton.setToolTipText(I18nManager.getText("dialog.autoplay.rewind"));
+		_rewindButton.addActionListener(new ActionListener() {
+			public void actionPerformed(ActionEvent arg0) {
+				onRewindPressed();
+			}
+		});
+		buttonPanel.add(_pauseButton = new JButton(IconManager.getImageIcon(IconManager.AUTOPLAY_PAUSE)));
+		_pauseButton.setToolTipText(I18nManager.getText("dialog.autoplay.pause"));
+		_pauseButton.addActionListener(new ActionListener() {
+			public void actionPerformed(ActionEvent arg0) {
+				onPausePressed();
+			}
+		});
+		buttonPanel.add(_playButton = new JButton(IconManager.getImageIcon(IconManager.AUTOPLAY_PLAY)));
+		_playButton.setToolTipText(I18nManager.getText("dialog.autoplay.play"));
+		_playButton.addActionListener(new ActionListener() {
+			public void actionPerformed(ActionEvent arg0) {
+				onPlayPressed();
+			}
+		});
+		buttonPanel.setAlignmentX(Component.CENTER_ALIGNMENT);
+		dialogPanel.add(buttonPanel);
+		return dialogPanel;
+	}
+
+	/**
+	 * React to a change to either the duration or the checkbox
+	 */
+	private void onParamsChanged()
+	{
+		onRewindPressed();
+		enableButtons(false, _durationField.getValue() > 0);
+		_needToRecalculate = true;
+	}
+
+	/**
+	 * React to rewind button pressed - stop and go back to the first point
+	 */
+	private void onRewindPressed()
+	{
+		//System.out.println("Rewind!  Stop thread if playing");
+		_running = false;
+		if (_pointList != null)
+		{
+			_pointList.set(0);
+			_app.getTrackInfo().selectPoint(_pointList.getCurrentPointIndex());
+		}
+	}
+
+	/**
+	 * React to pause button pressed - stop scrolling but maintain position
+	 */
+	private void onPausePressed()
+	{
+		//System.out.println("Pause!  Stop thread if playing");
+		_running = false;
+		enableButtons(false, true);
+	}
+
+	/**
+	 * React to play button being pressed - either start or resume
+	 */
+	private void onPlayPressed()
+	{
+		//System.out.println("Play!");
+		if (_needToRecalculate) {
+			recalculateTimes();
+		}
+		enableButtons(true, false);
+		if (_pointList.isAtStart() || _pointList.isFinished())
+		{
+			_pointList.set(0);
+			_startTime = System.currentTimeMillis();
+		}
+		else
+		{
+			// Get current millis from pointList, reset _startTime
+			_startTime = System.currentTimeMillis() - _pointList.getCurrentMilliseconds();
+		}
+		new Thread(this).start();
+	}
+
+	/**
+	 * Recalculate the times using the dialog settings
+	 */
+	private void recalculateTimes()
+	{
+		//System.out.println("Recalculate using params " + _durationField.getValue()
+		//	+ " and " + (_useTimestampsCheckbox.isSelected() ? "times" : "indexes"));
+		if (_useTimestampsCheckbox.isSelected()) {
+			_pointList = generatePointListUsingTimes(_app.getTrackInfo().getTrack(), _durationField.getValue());
+		}
+		else {
+			_pointList = generatePointListUsingIndexes(_app.getTrackInfo().getTrack().getNumPoints(), _durationField.getValue());
+		}
+		_needToRecalculate = false;
+	}
+
+	/**
+	 * Enable and disable the pause and play buttons
+	 * @param inCanPause true to enable pause button
+	 * @param inCanPlay  true to enable play button
+	 */
+	private void enableButtons(boolean inCanPause, boolean inCanPlay)
+	{
+		_pauseButton.setEnabled(inCanPause);
+		_playButton.setEnabled(inCanPlay);
+	}
+
+	/**
+	 * Generate a points list based just on the point timestamps
+	 * (points without timestamps will be ignored)
+	 * @param inTrack track object
+	 * @param inDuration number of seconds to play
+	 * @return PointList object
+	 */
+	private static PointList generatePointListUsingTimes(Track inTrack, int inDuration)
+	{
+		// Make a Set of all the points with timestamps and sort them
+		TreeSet<PointInfo> set = new TreeSet<PointInfo>();
+		int numPoints = inTrack.getNumPoints();
+		for (int i=0; i<numPoints; i++)
+		{
+			PointInfo info = new PointInfo(inTrack.getPoint(i), i);
+			if (info.getTimestamp() != null) {
+				set.add(info);
+			}
+		}
+		// For each point, keep track of the time since the previous time
+		Timestamp previousTime = null;
+		long trackMillis = 0L;
+		// Copy info to point list
+		numPoints = set.size();
+		PointList list = new PointList(numPoints);
+		Iterator<PointInfo> it = set.iterator();
+		while (it.hasNext())
+		{
+			PointInfo info = it.next();
+			if (previousTime != null)
+			{
+				if (info.getSegmentFlag()) {
+					trackMillis += 1000; // just add a second if it's a new segment
+				}
+				else {
+					trackMillis += (info.getTimestamp().getMillisecondsSince(previousTime));
+				}
+			}
+			previousTime = info.getTimestamp();
+			list.setPoint(trackMillis, info.getIndex());
+		}
+		// Now normalize the list to the requested length
+		list.normalize(inDuration);
+		return list;
+	}
+
+
+	/**
+	 * Generate a points list based just on indexes, ignoring timestamps
+	 * @param inNumPoints number of points in track
+	 * @param inDuration number of seconds to play
+	 * @return PointList object
+	 */
+	private static PointList generatePointListUsingIndexes(int inNumPoints, int inDuration)
+	{
+		// simple case, just take all the points in the track
+		PointList list = new PointList(inNumPoints);
+		// Add each of the points in turn
+		for (int i=0; i<inNumPoints; i++)
+		{
+			list.setPoint(i, i);
+		}
+		list.normalize(inDuration);
+		return list;
+	}
+
+	/**
+	 * Run method, for scrolling in separate thread
+	 */
+	public void run()
+	{
+		_running = true;
+		_app.getTrackInfo().selectPoint(_pointList.getCurrentPointIndex());
+		while (_running && !_pointList.isFinished())
+		{
+			_pointList.set(System.currentTimeMillis() - _startTime);
+			final int pointIndex = _pointList.getCurrentPointIndex();
+			//System.out.println("Set point index to " + pointIndex);
+			_app.getTrackInfo().selectPoint(pointIndex);
+			long waitInterval = _pointList.getMillisUntilNextPoint(System.currentTimeMillis() - _startTime);
+			if (waitInterval < 20) {waitInterval = 20;}
+			try {Thread.sleep(waitInterval);}
+			catch (InterruptedException ie) {}
+		}
+		_running = false;
+		enableButtons(false, true);
+	}
+}
diff --git a/tim/prune/function/autoplay/PointInfo.java b/tim/prune/function/autoplay/PointInfo.java
new file mode 100644
index 0000000..1b04995
--- /dev/null
+++ b/tim/prune/function/autoplay/PointInfo.java
@@ -0,0 +1,98 @@
+package tim.prune.function.autoplay;
+
+import tim.prune.data.DataPoint;
+import tim.prune.data.Timestamp;
+
+/**
+ * Holds the information about a single point required for the sorting
+ */
+public class PointInfo implements Comparable<PointInfo>
+{
+	/** Timestamp of the point, if any */
+	private Timestamp _timestamp  = null;
+	/** Point index in the track */
+	private int       _pointIndex = 0;
+	/** Segment flag of point */
+	private boolean   _segmentFlag = false;
+
+
+	/**
+	 * Constructor
+	 * @param inPoint point from track
+	 * @param inIndex index of point in track
+	 */
+	public PointInfo(DataPoint inPoint, int inIndex)
+	{
+		if (inPoint.hasTimestamp())
+		{
+			_timestamp = inPoint.getTimestamp();
+		}
+		else if (inPoint.getPhoto() != null && inPoint.getPhoto().hasTimestamp())
+		{
+			_timestamp = inPoint.getPhoto().getTimestamp();
+		}
+		_pointIndex = inIndex;
+		_segmentFlag = inPoint.getSegmentStart();
+	}
+
+	/** @return timestamp */
+	public Timestamp getTimestamp() {
+		return _timestamp;
+	}
+
+	/** @return point index */
+	public int getIndex() {
+		return _pointIndex;
+	}
+
+	/** @return segment flag */
+	public boolean getSegmentFlag() {
+		return _segmentFlag;
+	}
+
+	/**
+	 * Sort two objects by timestamp and if times equal then by point index
+	 */
+	public int compareTo(PointInfo inOther)
+	{
+		long timeDiff = 0;
+		final boolean thisHasTime = (_timestamp != null);
+		final boolean otherHasTime = (inOther._timestamp != null);
+		if (thisHasTime && otherHasTime)
+		{
+			timeDiff = _timestamp.getMillisecondsSince(inOther._timestamp);
+		}
+		else if (thisHasTime)
+		{
+			timeDiff = -1; // points without time to the end
+		}
+		else if (otherHasTime)
+		{
+			timeDiff = 1;
+		}
+		// If the times are equal (or both missing) then use the point index
+		if (timeDiff == 0) {
+			return _pointIndex - inOther._pointIndex;
+		}
+		// Otherwise, compare by time
+		return (timeDiff < 0 ? -1 : 1);
+	}
+
+	@Override
+	public boolean equals(Object inOther)
+	{
+		if (inOther == null) return false;
+		try
+		{
+			PointInfo other = (PointInfo) inOther;
+			if (_pointIndex != other._pointIndex) return false;
+			final boolean thisHasTime = (_timestamp != null);
+			final boolean otherHasTime = (other._timestamp != null);
+			if (thisHasTime != otherHasTime) {return false;}
+			if (!thisHasTime && !otherHasTime) {return true;}
+			return _timestamp.isEqual(other._timestamp);
+		}
+		catch (ClassCastException cce) {}
+		return false;
+	}
+}
diff --git a/tim/prune/function/autoplay/PointList.java b/tim/prune/function/autoplay/PointList.java
new file mode 100644
index 0000000..13ccf61
--- /dev/null
+++ b/tim/prune/function/autoplay/PointList.java
@@ -0,0 +1,115 @@
+package tim.prune.function.autoplay;
+
+/**
+ * Class to hold a list of points and hold a running position
+ */
+public class PointList
+{
+	/** Array of milliseconds for each point */
+	private long[] _millis = null;
+	/** Array of indexes of corresponding points */
+	private int[]  _indexes = null;
+	/** Array index of current position */
+	private int    _currentItem = 0;
+	/** Max array index */
+	private int    _maxItem = 0;
+
+	/**
+	 * Constructor
+	 * @param inNumPoints number of points
+	 */
+	public PointList(int inNumPoints)
+	{
+		_millis = new long[inNumPoints];
+		_indexes = new int[inNumPoints];
+		_currentItem = 0;
+		_maxItem = inNumPoints - 1;
+	}
+
+	/**
+	 * Add a point to the array
+	 * @param inMillis milliseconds since start
+	 * @param inIndex point index
+	 */
+	public void setPoint(long inMillis, int inIndex)
+	{
+		_millis[_currentItem] = inMillis;
+		_indexes[_currentItem] = inIndex;
+		_currentItem++;
+	}
+
+	/**
+	 * Set the position using the current milliseconds
+	 * @param inMillis milliseconds since start
+	 */
+	public void set(long inMillis)
+	{
+		if (isFinished() || inMillis < _millis[_currentItem])
+		{
+			// must be reset
+			_currentItem = 0;
+		}
+		while (_currentItem < _maxItem && _millis[_currentItem + 1] < inMillis)
+		{
+			_currentItem++;
+		}
+	}
+
+	/**
+	 * Normalize the list to cover the requested number of seconds duration
+	 * @param inSeconds length of autoplay sequence in seconds
+	 */
+	public void normalize(int inSeconds)
+	{
+		if (_maxItem <= 0)
+		{
+			return; // nothing to normalize
+		}
+		long currentDuration = _millis[_maxItem] - _millis[0];
+		if (currentDuration > 0L)
+		{
+			double multFactor = inSeconds * 1000.0 / currentDuration;
+			for (int i=0; i<=_maxItem; i++)
+			{
+				_millis[i] = (long) (_millis[i] * multFactor);
+			}
+		}
+	}
+
+	/** @return the milliseconds of the current point */
+	public long getCurrentMilliseconds()
+	{
+		if (isAtStart() || isFinished()) {
+			return 0L;
+		}
+		return _millis[_currentItem];
+	}
+
+	/** @return the index of the current point */
+	public int getCurrentPointIndex()
+	{
+		return _indexes[_currentItem];
+	}
+
+	/** @return true if we're on the first point */
+	public boolean isAtStart() {
+		return _currentItem == 0;
+	}
+
+	/** @return true if we're on the last point */
+	public boolean isFinished() {
+		return _currentItem >= _maxItem;
+	}
+
+	/**
+	 * @param inCurrentMillis current time in milliseconds since start
+	 * @return number of milliseconds to wait until next point is due
+	 */
+	public long getMillisUntilNextPoint(long inCurrentMillis)
+	{
+		if (isFinished() || _millis[_currentItem+1] < _millis[_currentItem]) {
+			return 0; // no next point
+		}
+		return _millis[_currentItem+1] - inCurrentMillis;
+	}
+}
diff --git a/tim/prune/function/browser/BrowserLauncher.java b/tim/prune/function/browser/BrowserLauncher.java
index 4ba4b8d..7c6fa58 100644
--- a/tim/prune/function/browser/BrowserLauncher.java
+++ b/tim/prune/function/browser/BrowserLauncher.java
@@ -86,6 +86,7 @@ public abstract class BrowserLauncher
 	 */
 	public static void launchBrowser(String inUrl)
 	{
+		if (inUrl == null) {return;}
 		// First choice is to try the Desktop library from java 6, if available
 		try {
 			Class<?> d = Class.forName("java.awt.Desktop");
diff --git a/tim/prune/function/browser/UrlGenerator.java b/tim/prune/function/browser/UrlGenerator.java
index 8d264be..a0100b1 100644
--- a/tim/prune/function/browser/UrlGenerator.java
+++ b/tim/prune/function/browser/UrlGenerator.java
@@ -22,38 +22,46 @@ public abstract class UrlGenerator
 		if (FIVE_DP instanceof DecimalFormat) ((DecimalFormat) FIVE_DP).applyPattern("0.00000");
 	}
 
-	/** Constant for Google Maps */
-	public static final int MAP_SOURCE_GOOGLE = 0;
-	/** Constant for Open Street Maps */
-	public static final int MAP_SOURCE_OSM    = 1;
-	/** Constant for Mapquest */
-	public static final int MAP_SOURCE_MAPQUEST = 2;
-	/** Constant for Yahoo */
-	public static final int MAP_SOURCE_YAHOO  = 3;
-	/** Constant for Bing */
-	public static final int MAP_SOURCE_BING = 4;
+	public enum WebService
+	{
+		MAP_SOURCE_GOOGLE,     /* Google maps */
+		MAP_SOURCE_OSM,        /* OpenStreetMap */
+		MAP_SOURCE_MAPQUEST,   /* Mapquest */
+		MAP_SOURCE_YAHOO,      /* Yahoo */
+		MAP_SOURCE_BING,       /* Bing */
+		MAP_SOURCE_PEAKFINDER, /* PeakFinder */
+		MAP_SOURCE_GEOHACK,    /* Geohack */
+		MAP_SOURCE_PANORAMIO,  /* Panoramio */
+		MAP_SOURCE_OPENCACHINGCOM, /* Opencaching.com */
+	}
 
 	/**
 	 * Generate a URL for the given source and track info
-	 * @param inSource source to use, either google or openstreetmap
+	 * @param inSource source to use, from the enum in UrlGenerator
 	 * @param inTrackInfo track info
 	 * @return url for map
 	 */
-	public static String generateUrl(int inSource, TrackInfo inTrackInfo)
+	public static String generateUrl(WebService inSource, TrackInfo inTrackInfo)
 	{
-		if (inSource == MAP_SOURCE_GOOGLE) {
-			return generateGoogleUrl(inTrackInfo);
-		}
-		else if (inSource == MAP_SOURCE_MAPQUEST) {
-			return generateMapquestUrl(inTrackInfo);
-		}
-		else if (inSource == MAP_SOURCE_YAHOO) {
-			return generateYahooUrl(inTrackInfo);
-		}
-		else if (inSource == MAP_SOURCE_BING) {
-			return generateBingUrl(inTrackInfo);
+		switch (inSource)
+		{
+			case MAP_SOURCE_GOOGLE:
+				return generateGoogleUrl(inTrackInfo);
+			case MAP_SOURCE_MAPQUEST:
+				return generateMapquestUrl(inTrackInfo);
+			case MAP_SOURCE_YAHOO:
+				return generateYahooUrl(inTrackInfo);
+			case MAP_SOURCE_BING:
+				return generateBingUrl(inTrackInfo);
+			case MAP_SOURCE_PEAKFINDER:
+			case MAP_SOURCE_GEOHACK:
+			case MAP_SOURCE_PANORAMIO:
+			case MAP_SOURCE_OPENCACHINGCOM:
+				return generateUrlForPoint(inSource, inTrackInfo);
+			case MAP_SOURCE_OSM:
+			default:
+				return generateOpenStreetMapUrl(inTrackInfo);
 		}
-		return generateOpenStreetMapUrl(inTrackInfo);
 	}
 
 	/**
@@ -89,33 +97,6 @@ public abstract class UrlGenerator
 	}
 
 	/**
-	 * Generate a url for Open Street Map
-	 * @param inTrackInfo track information
-	 * @return URL
-	 */
-	private static String generateOpenStreetMapUrl(TrackInfo inTrackInfo)
-	{
-		// Check if any data to display
-		if (inTrackInfo == null || inTrackInfo.getTrack() == null || inTrackInfo.getTrack().getNumPoints() < 1)
-		{
-			return null;
-		}
-		DoubleRange latRange = inTrackInfo.getTrack().getLatRange();
-		DoubleRange lonRange = inTrackInfo.getTrack().getLonRange();
-		// Build basic url using min and max lat and long
-		String url = "http://openstreetmap.org/?minlat=" + FIVE_DP.format(latRange.getMinimum())
-			+ "&maxlat=" + FIVE_DP.format(latRange.getMaximum())
-			+ "&minlon=" + FIVE_DP.format(lonRange.getMinimum()) + "&maxlon=" + FIVE_DP.format(lonRange.getMaximum());
-		DataPoint currPoint = inTrackInfo.getCurrentPoint();
-		// Add selected point, if any (no way to add point name?)
-		if (currPoint != null) {
-			url = url + "&mlat=" + FIVE_DP.format(currPoint.getLatitude().getDouble())
-				+ "&mlon=" + FIVE_DP.format(currPoint.getLongitude().getDouble());
-		}
-		return url;
-	}
-
-	/**
 	 * Generate a url for Mapquest maps
 	 * @param inTrackInfo track information
 	 * @return URL
@@ -178,6 +159,117 @@ public abstract class UrlGenerator
 		return url;
 	}
 
+	/**
+	 * Generate a url for Open Street Map
+	 * @param inTrackInfo track information
+	 * @return URL
+	 */
+	private static String generateOpenStreetMapUrl(TrackInfo inTrackInfo)
+	{
+		// Check if any data to display
+		if (inTrackInfo == null || inTrackInfo.getTrack() == null || inTrackInfo.getTrack().getNumPoints() < 1)
+		{
+			return null;
+		}
+		DoubleRange latRange = inTrackInfo.getTrack().getLatRange();
+		DoubleRange lonRange = inTrackInfo.getTrack().getLonRange();
+		// Build basic url using min and max lat and long
+		String url = "http://openstreetmap.org/?minlat=" + FIVE_DP.format(latRange.getMinimum())
+			+ "&maxlat=" + FIVE_DP.format(latRange.getMaximum())
+			+ "&minlon=" + FIVE_DP.format(lonRange.getMinimum()) + "&maxlon=" + FIVE_DP.format(lonRange.getMaximum());
+		DataPoint currPoint = inTrackInfo.getCurrentPoint();
+		// Add selected point, if any (no way to add point name?)
+		if (currPoint != null) {
+			url = url + "&mlat=" + FIVE_DP.format(currPoint.getLatitude().getDouble())
+				+ "&mlon=" + FIVE_DP.format(currPoint.getLongitude().getDouble());
+		}
+		return url;
+	}
+
+	/**
+	 * Generate a URL which only needs the current point
+	 * This is just a helper method to simplify the calls to the service-specific methods
+	 * @param inSource service to call
+	 * @param inTrackInfo track info
+	 * @return URL if available, or null
+	 */
+	private static String generateUrlForPoint(WebService inService, TrackInfo inTrackInfo)
+	{
+		if (inTrackInfo == null || inTrackInfo.getTrack() == null || inTrackInfo.getTrack().getNumPoints() < 1)
+		{
+			return null;
+		}
+		// Need a current point
+		DataPoint currPoint = inTrackInfo.getCurrentPoint();
+		if (currPoint == null)
+		{
+			return null;
+		}
+		switch (inService)
+		{
+			case MAP_SOURCE_PEAKFINDER:
+				return generatePeakfinderUrl(currPoint);
+			case MAP_SOURCE_GEOHACK:
+				return generateGeohackUrl(currPoint);
+			case MAP_SOURCE_PANORAMIO:
+				return generatePanoramioUrl(currPoint);
+			case MAP_SOURCE_OPENCACHINGCOM:
+				return generateOpencachingComUrl(currPoint);
+			default:
+				return null;
+		}
+	}
+
+
+	/**
+	 * Generate a url for PeakFinder
+	 * @param inPoint current point, not null
+	 * @return URL
+	 */
+	private static String generatePeakfinderUrl(DataPoint inPoint)
+	{
+		return "http://peakfinder.org/?lat=" + FIVE_DP.format(inPoint.getLatitude().getDouble())
+			+ "&lng=" + FIVE_DP.format(inPoint.getLongitude().getDouble());
+	}
+
+	/**
+	 * Generate a url for Geohack
+	 * @param inPoint current point, not null
+	 * @return URL
+	 */
+	private static String generateGeohackUrl(DataPoint inPoint)
+	{
+		return "https://tools.wmflabs.org/geohack/geohack.php?params=" + FIVE_DP.format(inPoint.getLatitude().getDouble())
+			+ "_N_" + FIVE_DP.format(inPoint.getLongitude().getDouble()) + "_E";
+		// TODO: Could use absolute values and S, W but this seems to work
+	}
+
+	/**
+	 * Generate a url for Panoramio.com
+	 * @param inPoint current point, not null
+	 * @return URL
+	 */
+	private static String generatePanoramioUrl(DataPoint inPoint)
+	{
+		return "http://panoramio.com/map/#lt=" + FIVE_DP.format(inPoint.getLatitude().getDouble())
+			+ "&ln=" + FIVE_DP.format(inPoint.getLongitude().getDouble()) + "&z=1&k=0";
+	}
+
+
+	/**
+	 * Generate a url for OpenCaching.com
+	 * @param inPoint current point, not null
+	 * @return URL
+	 */
+	private static String generateOpencachingComUrl(DataPoint inPoint)
+	{
+		final String occLang = I18nManager.getText("webservice.opencachingcom.lang");
+		final String url = "http://www.opencaching.com/" + occLang
+			+ "/#find?&loc=" + FIVE_DP.format(inPoint.getLatitude().getDouble())
+			+ "," + FIVE_DP.format(inPoint.getLongitude().getDouble());
+		return url;
+	}
+
 
 	/**
 	 * Get the median value from the given lat/long range
diff --git a/tim/prune/function/browser/WebMapFunction.java b/tim/prune/function/browser/WebMapFunction.java
new file mode 100644
index 0000000..1639c45
--- /dev/null
+++ b/tim/prune/function/browser/WebMapFunction.java
@@ -0,0 +1,46 @@
+package tim.prune.function.browser;
+
+import tim.prune.App;
+import tim.prune.GenericFunction;
+
+/**
+ * Function to show a webservice for the current area or point
+ */
+public class WebMapFunction extends GenericFunction
+{
+	/** Service to call */
+	private UrlGenerator.WebService _service;
+	/** Key for appearance in menu */
+	private String _nameKey = null;
+
+	/**
+	 * Constructor
+	 * @param inApp app object
+	 * @param inService web service to call
+	 * @param inNameKey name key for function
+	 */
+	public WebMapFunction(App inApp, UrlGenerator.WebService inService,
+		String inNameKey)
+	{
+		super(inApp);
+		_service = inService;
+		_nameKey = inNameKey;
+	}
+
+	@Override
+	public String getNameKey() {
+		return _nameKey;
+	}
+
+	@Override
+	/**
+	 * Do the function call
+	 */
+	public void begin()
+	{
+		String url = UrlGenerator.generateUrl(_service, _app.getTrackInfo());
+		if (url != null) {
+			BrowserLauncher.launchBrowser(url);
+		}
+	}
+}
diff --git a/tim/prune/function/cache/ManageCacheFunction.java b/tim/prune/function/cache/ManageCacheFunction.java
index 59ef13a..5431e9e 100644
--- a/tim/prune/function/cache/ManageCacheFunction.java
+++ b/tim/prune/function/cache/ManageCacheFunction.java
@@ -273,6 +273,7 @@ public class ManageCacheFunction extends GenericFunction implements Runnable
 	 */
 	public void run()
 	{
+		// TODO: Maybe this can be speeded up so that it just finds the tilesets first and then gets the details later
 		// Check if directory has anything in it
 		_model = new TileCacheModel(_cacheDir);
 		_model.buildTileSets();
diff --git a/tim/prune/function/cache/RowInfo.java b/tim/prune/function/cache/RowInfo.java
index 8c7ee23..809c572 100644
--- a/tim/prune/function/cache/RowInfo.java
+++ b/tim/prune/function/cache/RowInfo.java
@@ -10,7 +10,6 @@ public class RowInfo
 	private int _minZoom = -1, _maxZoom = -1;
 	private int _numTiles = 0;
 	private long _totalSize = 0L;
-	private boolean _unexpected = false;
 
 
 	/**
@@ -84,20 +83,6 @@ public class RowInfo
 		return _totalSize;
 	}
 
-	/**
-	 * Mark that an unexpected file or directory was found
-	 * TODO: Is this needed?
-	 */
-	public void foundUnexpected() {
-		_unexpected = true;
-	}
-
-	/**
-	 * @return true if any unexpected files or directories were found
-	 */
-	public boolean wasUnexpected() {
-		return _unexpected;
-	}
 
 	/**
 	 * Add the given RowInfo object to this one
@@ -117,6 +102,5 @@ public class RowInfo
 			addZoom(inOther._maxZoom);
 		if (inOther._zoom > 0)
 			addZoom(inOther._zoom);
-		_unexpected = _unexpected || inOther._unexpected;
 	}
 }
diff --git a/tim/prune/function/cache/TileSet.java b/tim/prune/function/cache/TileSet.java
index ca2b81a..525696e 100644
--- a/tim/prune/function/cache/TileSet.java
+++ b/tim/prune/function/cache/TileSet.java
@@ -60,6 +60,35 @@ public class TileSet
 	}
 
 	/**
+	 * Check if a filename is numeric up until the first dot
+	 * This appears to be much faster than scanning for a . with indexOf, then
+	 * chopping to make a new String, and then calling isNumeric to scan through again
+	 * @param inName name of file
+	 * @return true if it only contains characters 0-9 before the first dot
+	 */
+	public static boolean isNumericUntilDot(String inName)
+	{
+		if (inName == null || inName.equals("") || inName.charAt(0) == '.') {
+			return false;
+		}
+		try
+		{
+			char c = '.';
+			int i = 0;
+			do
+			{
+				c = inName.charAt(i);
+				if (c == '.') return true; // found the dot, so stop
+				if (c < '0' || c > '9') return false; // not numeric
+				i++;
+			} while (c != '\0');
+		}
+		catch (IndexOutOfBoundsException iobe) {}
+		// Didn't find a dot, so can't be a valid name
+		return false;
+	}
+
+	/**
 	 * Make a RowInfo object from the given directory
 	 * @param inDir directory for a single zoom level
 	 * @return RowInfo object describing files and size
@@ -78,9 +107,7 @@ public class TileSet
 				{
 					if (f != null && f.exists() && f.isFile() && f.canRead())
 					{
-						final String filename = f.getName();
-						int dotpos = filename.lastIndexOf('.');
-						if (dotpos > 0 && isNumeric(filename.substring(0, dotpos))) {
+						if (isNumericUntilDot(f.getName())) {
 							row.addTile(f.length());
 						}
 					}
diff --git a/tim/prune/function/compress/DeleteMarkedPointsFunction.java b/tim/prune/function/compress/DeleteMarkedPointsFunction.java
new file mode 100644
index 0000000..a604907
--- /dev/null
+++ b/tim/prune/function/compress/DeleteMarkedPointsFunction.java
@@ -0,0 +1,56 @@
+package tim.prune.function.compress;
+
+import tim.prune.App;
+import tim.prune.GenericFunction;
+import tim.prune.I18nManager;
+import tim.prune.undo.UndoDeleteMarked;
+
+/**
+ * Function to delete the marked points in the track
+ */
+public class DeleteMarkedPointsFunction extends GenericFunction
+{
+	private boolean _splitSegments = false;
+	private String  _parentFunctionKey = null;
+
+	/** Constructor */
+	public DeleteMarkedPointsFunction(App inApp) {
+		super(inApp);
+	}
+
+	@Override
+	public String getNameKey() {
+		return "function.deletemarked";
+	}
+
+	/**
+	 * Get notification about parent function
+	 * @param inKey parent function name key
+	 * @param inSplitSegments true to split segment, false to not
+	 */
+	public void setParentFunction(String inKey, boolean inSplitSegments)
+	{
+		_parentFunctionKey = inKey;
+		_splitSegments = inSplitSegments;
+	}
+
+	@Override
+	public void begin()
+	{
+		UndoDeleteMarked undo = new UndoDeleteMarked(_app.getTrackInfo().getTrack());
+		// call track to do the actual delete//
+		int numPointsDeleted = _app.getTrackInfo().deleteMarkedPoints(_splitSegments);
+		// add to undo stack if successful
+		if (numPointsDeleted > 0)
+		{
+			undo.setNumPointsDeleted(numPointsDeleted);
+			_app.completeFunction(undo, "" + numPointsDeleted + " "
+				 + (numPointsDeleted==1?I18nManager.getText("confirm.deletepoint.single"):I18nManager.getText("confirm.deletepoint.multi")));
+		}
+		else
+		{
+			final String titleKey = (_parentFunctionKey == null ? getNameKey() : _parentFunctionKey);
+			_app.showErrorMessage(titleKey, "dialog.deletemarked.nonefound");
+		}
+	}
+}
diff --git a/tim/prune/function/compress/MarkAndDeleteFunction.java b/tim/prune/function/compress/MarkAndDeleteFunction.java
index 2189ecb..dddc897 100644
--- a/tim/prune/function/compress/MarkAndDeleteFunction.java
+++ b/tim/prune/function/compress/MarkAndDeleteFunction.java
@@ -3,6 +3,7 @@ package tim.prune.function.compress;
 import javax.swing.JOptionPane;
 
 import tim.prune.App;
+import tim.prune.FunctionLibrary;
 import tim.prune.GenericFunction;
 import tim.prune.I18nManager;
 
@@ -39,13 +40,23 @@ public abstract class MarkAndDeleteFunction extends GenericFunction
 			I18nManager.getText(getNameKey()), JOptionPane.YES_NO_CANCEL_OPTION,
 			JOptionPane.WARNING_MESSAGE, null, buttonTexts, buttonTexts[1]);
 		if (answer == JOptionPane.CANCEL_OPTION) {_automaticallyDelete = true;} // "always" is third option
+
+		// Make sure function knows what to do, whether we'll call it now or later
+		FunctionLibrary.FUNCTION_DELETE_MARKED_POINTS.setParentFunction(
+				getNameKey(), getShouldSplitSegments());
 		if (_automaticallyDelete || answer == JOptionPane.YES_OPTION)
 		{
 			new Thread(new Runnable() {
-				public void run() {
-					_app.finishCompressTrack();
+				public void run()
+				{
+					FunctionLibrary.FUNCTION_DELETE_MARKED_POINTS.begin();
 				}
 			}).start();
 		}
 	}
+
+	/** by default, segments are not split at deleted points */
+	protected boolean getShouldSplitSegments() {
+		return false;
+	}
 }
diff --git a/tim/prune/function/compress/MarkLiftsFunction.java b/tim/prune/function/compress/MarkLiftsFunction.java
new file mode 100644
index 0000000..5e39866
--- /dev/null
+++ b/tim/prune/function/compress/MarkLiftsFunction.java
@@ -0,0 +1,143 @@
+package tim.prune.function.compress;
+
+import tim.prune.App;
+import tim.prune.UpdateMessageBroker;
+import tim.prune.data.DataPoint;
+import tim.prune.data.Distance;
+import tim.prune.data.RangeStats;
+import tim.prune.data.Track;
+import tim.prune.data.UnitSetLibrary;
+
+/**
+ * Function to mark all the points going uphill on ski lifts
+ */
+public class MarkLiftsFunction extends MarkAndDeleteFunction
+{
+	/**
+	 * Constructor
+	 * @param inApp App object
+	 */
+	public MarkLiftsFunction(App inApp)
+	{
+		super(inApp);
+	}
+
+	/** @return name key */
+	public String getNameKey() {
+		return "function.marklifts";
+	}
+
+	/** this function _does_ require split at deleted points */
+	protected boolean getShouldSplitSegments() {
+		return true;
+	}
+
+	/**
+	 * Begin the function using the set parameters
+	 */
+	public void begin()
+	{
+		// TODO: Might need to do this in a separate thread, it might take a while if the track is big
+		// Loop over all points in track
+		int numMarked = 0;
+		final Track track = _app.getTrackInfo().getTrack();
+		final int numPoints = track.getNumPoints();
+		boolean[] markFlags = new boolean[numPoints];
+		int previousStartIndex = -1;
+		for (int i=0; i<numPoints; i++)
+		{
+			DataPoint currPoint = track.getPoint(i);
+			if (currPoint != null && !currPoint.isWaypoint() && currPoint.hasAltitude() && currPoint.hasTimestamp())
+			{
+				int n = i+1;
+				DataPoint endPoint = track.getPoint(n);
+				while (endPoint != null && endPoint.hasAltitude() && endPoint.hasTimestamp() &&
+					!endPoint.isWaypoint() && endPoint.getTimestamp().getSecondsSince(currPoint.getTimestamp()) < 120)
+				{
+					n++;
+					endPoint = track.getPoint(n);
+				}
+				if (endPoint != null && endPoint.hasAltitude() && endPoint.hasTimestamp() && !endPoint.isWaypoint()
+					&& n > (i+10))
+				{
+					// Found a 2 minute range to test with at least 12 points
+					if (looksLikeLiftRange(track, i, n))
+					{
+						// Passes tests, so we want to mark all points between i and n
+						int startIndex = i;
+						// First check if we can merge with the previous marked range
+						if (previousStartIndex >= 0
+							&& (looksLikeLiftRange(track, previousStartIndex, i)
+							 || looksLikeLiftRange(track, previousStartIndex, n)))
+						{
+							startIndex = previousStartIndex; // merge
+						}
+						for (int j=startIndex; j<=n; j++)
+						{
+							markFlags[j] = true;
+						}
+						// Remember start point for next one
+						previousStartIndex = startIndex;
+						// skip forward half the range, don't need to test the same points again
+						i = (i+n)/2;
+					}
+				}
+			}
+		}
+
+		// Copy mark flags to points
+		for (int i=0; i<numPoints; i++)
+		{
+			DataPoint point = track.getPoint(i);
+			if (!point.isWaypoint()) point.setMarkedForDeletion(markFlags[i]);
+			if (markFlags[i]) numMarked++;
+		}
+		// Inform subscribers to update display
+		UpdateMessageBroker.informSubscribers();
+		// Confirm message showing how many marked
+		if (numMarked > 0)
+		{
+			optionallyDeleteMarkedPoints(numMarked);
+		}
+		else
+		{
+			// TODO: Show message that no lifts were found
+		}
+	}
+
+
+	/**
+	 * Check whether the specified range looks like an uphill lift section or not
+	 * Must go at most a little bit downhill, much more uphill than down, and straight
+	 * (speed isn't checked yet, but maybe could be?)
+	 * @param inTrack track
+	 * @param inStartIndex start index of range
+	 * @param inEndIndex end index of range
+	 * @return true if it looks like a lift
+	 */
+	private boolean looksLikeLiftRange(Track inTrack, int inStartIndex, int inEndIndex)
+	{
+		RangeStats stats = new RangeStats(inTrack, inStartIndex, inEndIndex);
+		int descent = stats.getTotalAltitudeRange().getDescent(UnitSetLibrary.UNITS_METRES);
+		if (descent < 20)
+		{
+			int ascent = stats.getTotalAltitudeRange().getClimb(UnitSetLibrary.UNITS_METRES);
+			if (ascent > (descent * 10))
+			{
+				// Now check distance and compare to distance between start and end
+				final DataPoint startPoint = inTrack.getPoint(inStartIndex);
+				final DataPoint endPoint   = inTrack.getPoint(inEndIndex);
+
+				final double trackDist = stats.getTotalDistance();
+				final double endToEndDist = Distance.convertRadiansToDistance(
+					DataPoint.calculateRadiansBetween(startPoint, endPoint));
+				if ((trackDist / endToEndDist) < 1.02)  // Straight(ish) line
+				{
+					return true;
+				}
+				//else System.out.println("Not straight enough: " + (trackDist / endToEndDist));
+			}
+		}
+		return false;
+	}
+}
diff --git a/tim/prune/function/gpsies/GetGpsiesFunction.java b/tim/prune/function/gpsies/GetGpsiesFunction.java
index e60ed74..cdcc9a9 100644
--- a/tim/prune/function/gpsies/GetGpsiesFunction.java
+++ b/tim/prune/function/gpsies/GetGpsiesFunction.java
@@ -12,6 +12,8 @@ import javax.xml.parsers.SAXParserFactory;
 import tim.prune.App;
 import tim.prune.GpsPrune;
 import tim.prune.I18nManager;
+import tim.prune.function.search.GenericDownloaderFunction;
+import tim.prune.function.search.SearchResult;
 import tim.prune.load.xml.XmlFileLoader;
 import tim.prune.load.xml.ZipFileLoader;
 
@@ -65,7 +67,7 @@ public class GetGpsiesFunction extends GenericDownloaderFunction
 		double[] coords = _app.getViewport().getBounds();
 		int currPage = 1;
 
-		ArrayList<GpsiesTrack> trackList = null;
+		ArrayList<SearchResult> trackList = null;
 		URL url = null;
 		String descMessage = "";
 		InputStream inStream = null;
diff --git a/tim/prune/function/gpsies/GpsiesXmlHandler.java b/tim/prune/function/gpsies/GpsiesXmlHandler.java
index 3d801be..f90bb03 100644
--- a/tim/prune/function/gpsies/GpsiesXmlHandler.java
+++ b/tim/prune/function/gpsies/GpsiesXmlHandler.java
@@ -6,14 +6,16 @@ import org.xml.sax.Attributes;
 import org.xml.sax.SAXException;
 import org.xml.sax.helpers.DefaultHandler;
 
+import tim.prune.function.search.SearchResult;
+
 /**
  * XML handler for dealing with XML returned from gpsies.com
  */
 public class GpsiesXmlHandler extends DefaultHandler
 {
 	private String _value = null;
-	private ArrayList<GpsiesTrack> _trackList = null;
-	private GpsiesTrack _track = null;
+	private ArrayList<SearchResult> _trackList = null;
+	private SearchResult _track = null;
 
 
 	/**
@@ -23,10 +25,10 @@ public class GpsiesXmlHandler extends DefaultHandler
 		Attributes inAttributes) throws SAXException
 	{
 		if (inTagName.equals("tracks")) {
-			_trackList = new ArrayList<GpsiesTrack>();
+			_trackList = new ArrayList<SearchResult>();
 		}
 		else if (inTagName.equals("track")) {
-			_track = new GpsiesTrack();
+			_track = new SearchResult();
 		}
 		_value = null;
 		super.startElement(inUri, inLocalName, inTagName, inAttributes);
@@ -76,7 +78,7 @@ public class GpsiesXmlHandler extends DefaultHandler
 	/**
 	 * @return the list of tracks
 	 */
-	public ArrayList<GpsiesTrack> getTrackList()
+	public ArrayList<SearchResult> getTrackList()
 	{
 		return _trackList;
 	}
diff --git a/tim/prune/function/gpsies/TrackListModel.java b/tim/prune/function/gpsies/TrackListModel.java
index 274c0b8..298578c 100644
--- a/tim/prune/function/gpsies/TrackListModel.java
+++ b/tim/prune/function/gpsies/TrackListModel.java
@@ -8,6 +8,7 @@ import javax.swing.table.AbstractTableModel;
 import tim.prune.I18nManager;
 import tim.prune.config.Config;
 import tim.prune.data.Unit;
+import tim.prune.function.search.SearchResult;
 
 /**
  * Model for list of tracks from gpsies.com
@@ -15,7 +16,7 @@ import tim.prune.data.Unit;
 public class TrackListModel extends AbstractTableModel
 {
 	/** List of tracks */
-	private ArrayList<GpsiesTrack> _trackList = null;
+	private ArrayList<SearchResult> _trackList = null;
 	/** Column heading for track name */
 	private String _nameColLabel = null;
 	/** Column heading for length */
@@ -80,7 +81,7 @@ public class TrackListModel extends AbstractTableModel
 	 */
 	public Object getValueAt(int inRowNum, int inColNum)
 	{
-		GpsiesTrack track = _trackList.get(inRowNum);
+		SearchResult track = _trackList.get(inRowNum);
 		if (inColNum == 0) {return track.getTrackName();}
 		double lengthM = track.getLength();
 		// convert to current distance units
@@ -94,9 +95,9 @@ public class TrackListModel extends AbstractTableModel
 	 * Add a list of tracks to this model
 	 * @param inList list of tracks to add
 	 */
-	public void addTracks(ArrayList<GpsiesTrack> inList)
+	public void addTracks(ArrayList<SearchResult> inList)
 	{
-		if (_trackList == null) {_trackList = new ArrayList<GpsiesTrack>();}
+		if (_trackList == null) {_trackList = new ArrayList<SearchResult>();}
 		final int prevCount = _trackList.size();
 		if (inList != null && inList.size() > 0) {
 			_trackList.addAll(inList);
@@ -112,7 +113,7 @@ public class TrackListModel extends AbstractTableModel
 	 * @param inRowNum row number from 0
 	 * @return track object for this row
 	 */
-	public GpsiesTrack getTrack(int inRowNum)
+	public SearchResult getTrack(int inRowNum)
 	{
 		return _trackList.get(inRowNum);
 	}
diff --git a/tim/prune/function/gpsies/GenericDownloaderFunction.java b/tim/prune/function/search/GenericDownloaderFunction.java
similarity index 98%
rename from tim/prune/function/gpsies/GenericDownloaderFunction.java
rename to tim/prune/function/search/GenericDownloaderFunction.java
index 286ba1a..403a0ef 100644
--- a/tim/prune/function/gpsies/GenericDownloaderFunction.java
+++ b/tim/prune/function/search/GenericDownloaderFunction.java
@@ -1,4 +1,4 @@
-package tim.prune.function.gpsies;
+package tim.prune.function.search;
 
 import java.awt.BorderLayout;
 import java.awt.Component;
@@ -25,6 +25,7 @@ import tim.prune.App;
 import tim.prune.GenericFunction;
 import tim.prune.I18nManager;
 import tim.prune.function.browser.BrowserLauncher;
+import tim.prune.function.gpsies.TrackListModel;
 
 /**
  * Function to load track information from any source,
diff --git a/tim/prune/function/search/SearchMapillaryFunction.java b/tim/prune/function/search/SearchMapillaryFunction.java
new file mode 100644
index 0000000..32c58bd
--- /dev/null
+++ b/tim/prune/function/search/SearchMapillaryFunction.java
@@ -0,0 +1,231 @@
+package tim.prune.function.search;
+
+import java.io.InputStream;
+import java.net.URL;
+import java.util.ArrayList;
+
+import tim.prune.App;
+import tim.prune.I18nManager;
+import tim.prune.data.DataPoint;
+import tim.prune.data.Distance;
+import tim.prune.data.Field;
+import tim.prune.data.Latitude;
+import tim.prune.data.Longitude;
+import tim.prune.data.SourceInfo;
+import tim.prune.data.UnitSetLibrary;
+import tim.prune.load.MediaLinkInfo;
+
+/**
+ * Function to search mapillary for photos
+ */
+public class SearchMapillaryFunction extends GenericDownloaderFunction
+{
+	/** Maximum number of results to get */
+	private static final int MAX_RESULTS = 20;
+
+
+	/**
+	 * Constructor
+	 * @param inApp app object
+	 */
+	public SearchMapillaryFunction(App inApp)
+	{
+		super(inApp);
+	}
+
+	@Override
+	public String getNameKey() {
+		return "function.mapillary";
+	}
+
+	@Override
+	protected String getColumnKey(int inColNum)
+	{
+		if (inColNum == 0) return "dialog.wikipedia.column.name";
+		return "dialog.wikipedia.column.distance";
+	}
+
+	/**
+	 * Run method, for searching in a separate thread
+	 */
+	public void run()
+	{
+		_statusLabel.setText(I18nManager.getText("confirm.running"));
+		// Get coordinates from current point (if any) or from centre of screen
+		double lat = 0.0, lon = 0.0;
+		DataPoint currentPoint = _app.getTrackInfo().getCurrentPoint();
+		if (currentPoint == null)
+		{
+			double[] coords = _app.getViewport().getBounds();
+			lat = (coords[0] + coords[2]) / 2.0;
+			lon = (coords[1] + coords[3]) / 2.0;
+		}
+		else
+		{
+			lat = currentPoint.getLatitude().getDouble();
+			lon = currentPoint.getLongitude().getDouble();
+		}
+
+		// Construct URL
+		final String urlString = "http://api.mapillary.com/v1/im/close?lat="
+			+ lat + "&lon=" + lon + "&distance=1000&limit=" + MAX_RESULTS;
+		//System.out.println(urlString);
+		InputStream inStream = null;
+		try
+		{
+			inStream = new URL(urlString).openStream();
+			StringBuilder sb = new StringBuilder();
+			int ch = 0;
+			while ((ch = inStream.read()) >= 0)
+			{
+				sb.append((char) ch);
+			}
+			//System.out.println("Got answer: '" + sb.toString() + "'");
+
+			ArrayList<SearchResult> resultList = new ArrayList<SearchResult>();
+			for (String result : sb.toString().split("\\},\\{"))
+			{
+				//System.out.println("Result: '" + result + "'");
+				SearchResult sr = new SearchResult();
+				for (String prop : result.split(","))
+				{
+					String key = getKey(prop);
+					if (key == null) {continue;}
+					if (key.equals("key"))
+					{
+						final String value = getValue(prop);
+						sr.setDownloadLink("http://images.mapillary.com/" + value + "/thumb-1024.jpg");
+						sr.setWebUrl("http://www.mapillary.com/map/im/" + value);
+						sr.setTrackName(value);
+					}
+					else if (key.equals("lat")) {
+						sr.setLatitude(getValue(prop));
+					}
+					else if (key.equals("lon")) {
+						sr.setLongitude(getValue(prop));
+					}
+				}
+
+				if (sr.getLatitude() != null && sr.getLongitude() != null && sr.getTrackName() != null)
+				{
+					// Calculate distance away from current point and set this in sr.setLength
+					DataPoint resultPoint = new DataPoint(new Latitude(sr.getLatitude()), new Longitude(sr.getLongitude()), null);
+					if (resultPoint.isValid() && currentPoint != null && currentPoint.isValid())
+					{
+						double radianDist = DataPoint.calculateRadiansBetween(currentPoint, resultPoint);
+						double metresAway = Distance.convertRadiansToDistance(radianDist, UnitSetLibrary.UNITS_METRES);
+						sr.setLength(metresAway);
+					}
+
+					// If there's a valid result, add it to the temporary list
+					if (sr.getTrackName() != null) {
+						resultList.add(sr);
+					}
+				}
+			}
+			// Add all the results to the table model in one go
+			if (!resultList.isEmpty()) {
+				_trackListModel.addTracks(resultList);
+			}
+		}
+		catch (Exception e) {
+			_errorMessage = e.getClass().getName() + " - " + e.getMessage();
+		}
+		// Close stream and ignore errors
+		try {
+			inStream.close();
+		} catch (Exception e) {}
+
+		// Set status label according to error or "none found", leave blank if ok
+		if (_errorMessage == null && _trackListModel.isEmpty()) {
+			_errorMessage = I18nManager.getText("dialog.mapillary.nonefound");
+		}
+		_statusLabel.setText(_errorMessage == null ? "" : _errorMessage);
+	}
+
+	/**
+	 * From a JSON key:value string, return just the key
+	 * @param inString string to parse
+	 * @return just the key without the surrounding quotes, or null if not found
+	 */
+	private static String getKey(String inString)
+	{
+		if (inString == null || inString.equals("")) {return null;}
+		final int colonPos = inString.indexOf(':');
+		if (colonPos <= 0) {return null;}
+		int startPos = 0;
+		char c;
+		while ((c = inString.charAt(startPos)) == '['
+			|| c == '{' || c == '\"')
+		{
+			startPos++;
+		}
+		int endPos = colonPos;
+		while ((c = inString.charAt(endPos-1)) == '\"')
+		{
+			endPos--;
+		}
+		return inString.substring(startPos, endPos);
+	}
+
+	/**
+	 * From a JSON key:value string, return just the value
+	 * @param inString string to parse
+	 * @return just the value without the surrounding quotes
+	 */
+	private static String getValue(String inString)
+	{
+		final int colonPos = inString.indexOf(':');
+		if (colonPos <= 0 || colonPos >= inString.length()) {return null;}
+		int startPos = colonPos+1;
+		char c;
+		while ((c = inString.charAt(startPos)) == '\"')
+		{
+			startPos++;
+		}
+		int endPos = inString.length()-1;
+		while ((c = inString.charAt(endPos-1)) == '\"'
+			|| c == '}' || c == ']')
+		{
+			endPos--;
+		}
+		return inString.substring(startPos, endPos);
+	}
+
+	@Override
+	protected void loadSelected()
+	{
+		// Find the row(s) selected in the table and get the corresponding track
+		int numSelected = _trackTable.getSelectedRowCount();
+		if (numSelected < 1) return;
+		int[] rowNums = _trackTable.getSelectedRows();
+
+		String[][] pointData = new String[numSelected][];
+		String[]   linkArray = new String[numSelected];
+
+		// Loop over each of the selected points
+		for (int i=0; i<numSelected; i++)
+		{
+			pointData[i] = new String[3]; // lat, long, segment
+			int rowNum = rowNums[i];
+			if (rowNum >= 0 && rowNum < _trackListModel.getRowCount())
+			{
+				SearchResult result = _trackListModel.getTrack(rowNum);
+				//String url = result.getDownloadLink();
+				pointData[i][0] = result.getLatitude();
+				pointData[i][1] = result.getLongitude();
+				pointData[i][2] = "1"; // all points have a new segment
+				linkArray[i]    = result.getDownloadLink();
+			}
+		}
+		// Prepare the data for the app
+		final Field[] fields = {Field.LATITUDE, Field.LONGITUDE, Field.NEW_SEGMENT};
+		_app.autoAppendNextFile();
+		_app.informDataLoaded(fields, pointData, null, new SourceInfo("mapillary", SourceInfo.FILE_TYPE.JSON),
+			null, new MediaLinkInfo(linkArray));
+
+		// Close the dialog
+		_cancelled = true;
+		_dialog.dispose();
+	}
+}
diff --git a/tim/prune/function/gpsies/GpsiesTrack.java b/tim/prune/function/search/SearchResult.java
similarity index 68%
rename from tim/prune/function/gpsies/GpsiesTrack.java
rename to tim/prune/function/search/SearchResult.java
index da1339e..2a05a8c 100644
--- a/tim/prune/function/gpsies/GpsiesTrack.java
+++ b/tim/prune/function/search/SearchResult.java
@@ -1,9 +1,9 @@
-package tim.prune.function.gpsies;
+package tim.prune.function.search;
 
 /**
- * Class to hold a single track from Gpsies.com
+ * Class to hold a search result from wikipedia / gpsies / panoramio etc
  */
-public class GpsiesTrack
+public class SearchResult
 {
 	/** Track name or title */
 	private String _trackName = null;
@@ -15,6 +15,8 @@ public class GpsiesTrack
 	private double _trackLength = 0.0;
 	/** Download link */
 	private String _downloadLink = null;
+	/** Coordinates of point */
+	private String _latitude = null, _longitude = null;
 
 
 	/**
@@ -96,4 +98,32 @@ public class GpsiesTrack
 	{
 		return _downloadLink;
 	}
+
+	/**
+	 * @param inLatitude latitude
+	 */
+	public void setLatitude(String inLatitude) {
+		_latitude = inLatitude;
+	}
+
+	/**
+	 * @return latitude
+	 */
+	public String getLatitude() {
+		return _latitude;
+	}
+
+	/**
+	 * @param inLongitude longitude
+	 */
+	public void setLongitude(String inLongitude) {
+		_longitude = inLongitude;
+	}
+
+	/**
+	 * @return longitude
+	 */
+	public String getLongitude() {
+		return _longitude;
+	}
 }
diff --git a/tim/prune/function/srtm/LookupSrtmFunction.java b/tim/prune/function/srtm/LookupSrtmFunction.java
index 2ed1454..011dff6 100644
--- a/tim/prune/function/srtm/LookupSrtmFunction.java
+++ b/tim/prune/function/srtm/LookupSrtmFunction.java
@@ -228,13 +228,18 @@ public class LookupSrtmFunction extends GenericFunction implements Runnable
 											+ (fouralts[2]==VOID_VAL?1:0) + (fouralts[3]==VOID_VAL?1:0);
 										// if (numVoids > 0) System.out.println(numVoids + " voids found");
 										double altitude = 0.0;
-										switch (numVoids) {
+										switch (numVoids)
+										{
 											case 0:	altitude = bilinearInterpolate(fouralts, x, y); break;
 											case 1: altitude = bilinearInterpolate(fixVoid(fouralts), x, y); break;
 											case 2:
 											case 3: altitude = averageNonVoid(fouralts); break;
 											default: altitude = VOID_VAL;
 										}
+										// Special case for terrain tracks, don't interpolate voids yet
+										if (!_normalTrack && numVoids > 0) {
+											altitude = VOID_VAL;
+										}
 										if (altitude != VOID_VAL)
 										{
 											point.setFieldValue(Field.ALTITUDE, ""+altitude, false);
diff --git a/tim/prune/function/srtm/gen/GenerateTileLookup.java b/tim/prune/function/srtm/gen/GenerateTileLookup.java
index d797b13..11bc493 100644
--- a/tim/prune/function/srtm/gen/GenerateTileLookup.java
+++ b/tim/prune/function/srtm/gen/GenerateTileLookup.java
@@ -25,9 +25,10 @@ public class GenerateTileLookup
 		byte[] lookup = new byte[360 * 120]; // +/- 180 degrees longitude, +/- 60 degrees latitude
 		for (int f=1; f<= 6; f++)
 		{
+			BufferedReader r = null;
 			try
 			{
-				BufferedReader r = new BufferedReader(new FileReader(new File("tim/prune/function/srtm/gen/tiles" + f + ".txt")));
+				r = new BufferedReader(new FileReader(new File("tim/prune/function/srtm/gen/tiles" + f + ".txt")));
 				String line = r.readLine();
 				System.out.println("Read continent: '" + line + "'");
 				while ((line = r.readLine()) != null) {
@@ -48,6 +49,14 @@ public class GenerateTileLookup
 			catch (Exception e) {
 				e.printStackTrace();
 			}
+			finally {
+				if (r != null)
+				{
+					try {
+						r.close();
+					} catch (Exception e) {}
+				}
+			}
 		}
 		// Now f should be populated
 		StringBuilder b = new StringBuilder();
diff --git a/tim/prune/gui/IconManager.java b/tim/prune/gui/IconManager.java
index eff4714..fd0a888 100644
--- a/tim/prune/gui/IconManager.java
+++ b/tim/prune/gui/IconManager.java
@@ -25,9 +25,11 @@ public abstract class IconManager
 	/** Icon for autopan button on main map display when selected */
 	public static final String AUTOPAN_BUTTON_ON = "autopan_on.gif";
 	/** Icon for points connected icon on main map display */
-	public static final String POINTS_CONNECTED_BUTTON = "points_connected.gif";
+	public static final String POINTS_CONNECTED_BUTTON = "points_connected.png";
 	/** Icon for points disconnected icon on main map display */
-	public static final String POINTS_DISCONNECTED_BUTTON = "points_disconnected.gif";
+	public static final String POINTS_DISCONNECTED_BUTTON = "points_disconnected.png";
+	/** Icon for points hidden, just lines icon on main map display */
+	public static final String POINTS_HIDDEN_BUTTON = "points_hidden.png";
 	 /** Icon for edit mode button on main map display when not selected */
 	public static final String EDIT_MODE_BUTTON = "drag_points_icon.gif";
 	 /** Icon for edit mode button on main map display when selected */
@@ -70,6 +72,12 @@ public abstract class IconManager
 	public static final String PLAY_AUDIO = "play_audio.gif";
 	/** Icon for stopping the current audio clip */
 	public static final String STOP_AUDIO = "stop_audio.gif";
+	/** Icon for autoplaying a track */
+	public static final String AUTOPLAY_PLAY = "play.png";
+	/** Icon for pausing autoplay of a track */
+	public static final String AUTOPLAY_PAUSE = "pause.png";
+	/** Icon for rewinding the autoplay of a track */
+	public static final String AUTOPLAY_REWIND = "rewind.png";
 
 	/** Icon for a given entry being valid (green tick) */
 	public static final String ENTRY_VALID = "entry_valid.gif";
diff --git a/tim/prune/gui/MenuManager.java b/tim/prune/gui/MenuManager.java
index 741425d..f664f4b 100644
--- a/tim/prune/gui/MenuManager.java
+++ b/tim/prune/gui/MenuManager.java
@@ -30,7 +30,10 @@ import tim.prune.data.Selection;
 import tim.prune.data.Track;
 import tim.prune.data.TrackInfo;
 import tim.prune.function.ChooseSingleParameter;
+import tim.prune.function.SearchOpenCachingDeFunction;
 import tim.prune.function.browser.UrlGenerator;
+import tim.prune.function.browser.WebMapFunction;
+import tim.prune.function.search.SearchMapillaryFunction;
 
 /**
  * Class to manage the menu bar and tool bar,
@@ -60,6 +63,7 @@ public class MenuManager implements DataSubscriber
 	private JMenuItem _cropTrackItem = null;
 	private JMenuItem _compressItem = null;
 	private JMenuItem _markRectangleItem = null;
+	private JMenuItem _markUphillLiftsItem = null;
 	private JMenuItem _deleteMarkedPointsItem = null;
 	private JMenuItem _deleteByDateItem = null;
 	private JMenuItem _interpolateItem = null;
@@ -89,13 +93,20 @@ public class MenuManager implements DataSubscriber
 	private JMenuItem _uploadGpsiesItem = null;
 	private JMenuItem _lookupSrtmItem = null;
 	private JMenuItem _downloadSrtmItem = null;
-	private JMenuItem _lookupWikipediaItem = null;
+	private JMenuItem _nearbyWikipediaItem = null;
+	private JMenuItem _showPeakfinderItem = null;
+	private JMenuItem _showGeohackItem = null;
+	private JMenuItem _showPanoramioItem = null;
+	private JMenuItem _showOpencachingComItem = null;
+	private JMenuItem _searchOpencachingDeItem = null;
+	private JMenuItem _searchMapillaryItem = null;
 	private JMenuItem _downloadOsmItem = null;
 	private JMenuItem _getWeatherItem = null;
 	private JMenuItem _distanceItem = null;
 	private JMenuItem _fullRangeDetailsItem = null;
 	private JMenuItem _estimateTimeItem = null;
 	private JMenuItem _learnEstimationParams = null;
+	private JMenuItem _autoplayTrack = null;
 	private JMenuItem _saveExifItem = null;
 	private JMenuItem _photoPopupItem = null;
 	private JMenuItem _selectNoPhotoItem = null;
@@ -113,6 +124,7 @@ public class MenuManager implements DataSubscriber
 	private JMenuItem _correlateAudiosItem = null;
 	private JMenuItem _selectNoAudioItem = null;
 	private JCheckBoxMenuItem _onlineCheckbox = null;
+	private JCheckBoxMenuItem _antialiasCheckbox = null;
 	private JCheckBoxMenuItem _autosaveSettingsCheckbox = null;
 
 	// ActionListeners for reuse by menu and toolbar
@@ -257,14 +269,43 @@ public class MenuManager implements DataSubscriber
 		// Upload to gpsies
 		_uploadGpsiesItem = makeMenuItem(FunctionLibrary.FUNCTION_UPLOAD_GPSIES, false);
 		onlineMenu.add(_uploadGpsiesItem);
+
 		onlineMenu.addSeparator();
-		_lookupWikipediaItem = makeMenuItem(FunctionLibrary.FUNCTION_LOOKUP_WIKIPEDIA, false);
-		onlineMenu.add(_lookupWikipediaItem);
+		// browser submenu
+		_browserMapMenu = new JMenu(I18nManager.getText("menu.view.browser"));
+		_browserMapMenu.setEnabled(false);
+		JMenuItem googleMapsItem = makeMenuItem(new WebMapFunction(_app, UrlGenerator.WebService.MAP_SOURCE_GOOGLE, "menu.view.browser.google"));
+		_browserMapMenu.add(googleMapsItem);
+		JMenuItem openMapsItem = makeMenuItem(new WebMapFunction(_app, UrlGenerator.WebService.MAP_SOURCE_OSM, "menu.view.browser.openstreetmap"));
+		_browserMapMenu.add(openMapsItem);
+		JMenuItem mapquestMapsItem = makeMenuItem(new WebMapFunction(_app, UrlGenerator.WebService.MAP_SOURCE_MAPQUEST, "menu.view.browser.mapquest"));
+		_browserMapMenu.add(mapquestMapsItem);
+		JMenuItem yahooMapsItem = makeMenuItem(new WebMapFunction(_app, UrlGenerator.WebService.MAP_SOURCE_YAHOO, "menu.view.browser.yahoo"));
+		_browserMapMenu.add(yahooMapsItem);
+		JMenuItem bingMapsItem = makeMenuItem(new WebMapFunction(_app, UrlGenerator.WebService.MAP_SOURCE_BING, "menu.view.browser.bing"));
+		_browserMapMenu.add(bingMapsItem);
+		onlineMenu.add(_browserMapMenu);
+		// wikipedia
+		_nearbyWikipediaItem = makeMenuItem(FunctionLibrary.FUNCTION_NEARBY_WIKIPEDIA, false);
+		onlineMenu.add(_nearbyWikipediaItem);
 		JMenuItem searchWikipediaNamesItem = makeMenuItem(FunctionLibrary.FUNCTION_SEARCH_WIKIPEDIA);
 		onlineMenu.add(searchWikipediaNamesItem);
+		_showPeakfinderItem = makeMenuItem(new WebMapFunction(_app, UrlGenerator.WebService.MAP_SOURCE_PEAKFINDER, "webservice.peakfinder"), false);
+		onlineMenu.add(_showPeakfinderItem);
+		_showGeohackItem = makeMenuItem(new WebMapFunction(_app, UrlGenerator.WebService.MAP_SOURCE_GEOHACK, "webservice.geohack"), false);
+		onlineMenu.add(_showGeohackItem);
+		_showPanoramioItem = makeMenuItem(new WebMapFunction(_app, UrlGenerator.WebService.MAP_SOURCE_PANORAMIO, "webservice.panoramio"), false);
+		onlineMenu.add(_showPanoramioItem);
+		_showOpencachingComItem = makeMenuItem(new WebMapFunction(_app, UrlGenerator.WebService.MAP_SOURCE_OPENCACHINGCOM, "webservice.opencachingcom"), false);
+		onlineMenu.add(_showOpencachingComItem);
+
+		onlineMenu.addSeparator();
+		_searchOpencachingDeItem = makeMenuItem(new SearchOpenCachingDeFunction(_app), false);
+		onlineMenu.add(_searchOpencachingDeItem);
+		_searchMapillaryItem = makeMenuItem(new SearchMapillaryFunction(_app), false);
+		onlineMenu.add(_searchMapillaryItem);
 		_downloadOsmItem = makeMenuItem(FunctionLibrary.FUNCTION_DOWNLOAD_OSM, false);
 		onlineMenu.add(_downloadOsmItem);
-		onlineMenu.addSeparator();
 		_getWeatherItem = makeMenuItem(FunctionLibrary.FUNCTION_GET_WEATHER_FORECAST, false);
 		onlineMenu.add(_getWeatherItem);
 		menubar.add(onlineMenu);
@@ -304,13 +345,9 @@ public class MenuManager implements DataSubscriber
 		});
 		_markRectangleItem.setEnabled(false);
 		trackMenu.add(_markRectangleItem);
-		_deleteMarkedPointsItem = new JMenuItem(I18nManager.getText("menu.track.deletemarked"));
-		_deleteMarkedPointsItem.addActionListener(new ActionListener() {
-			public void actionPerformed(ActionEvent e) {
-				_app.finishCompressTrack();
-			}
-		});
-		_deleteMarkedPointsItem.setEnabled(false);
+		_markUphillLiftsItem = makeMenuItem(FunctionLibrary.FUNCTION_MARK_LIFTS, false);
+		trackMenu.add(_markUphillLiftsItem);
+		_deleteMarkedPointsItem = makeMenuItem(FunctionLibrary.FUNCTION_DELETE_MARKED_POINTS, false);
 		trackMenu.add(_deleteMarkedPointsItem);
 		_deleteByDateItem = makeMenuItem(FunctionLibrary.FUNCTION_DELETE_BY_DATE, false);
 		trackMenu.add(_deleteByDateItem);
@@ -483,45 +520,6 @@ public class MenuManager implements DataSubscriber
 		// 3d
 		_show3dItem = makeMenuItem(FunctionLibrary.FUNCTION_3D, false);
 		viewMenu.add(_show3dItem);
-		// browser submenu
-		_browserMapMenu = new JMenu(I18nManager.getText("menu.view.browser"));
-		_browserMapMenu.setEnabled(false);
-		JMenuItem googleMapsItem = new JMenuItem(I18nManager.getText("menu.view.browser.google"));
-		googleMapsItem.addActionListener(new ActionListener() {
-			public void actionPerformed(ActionEvent e) {
-				_app.showExternalMap(UrlGenerator.MAP_SOURCE_GOOGLE);
-			}
-		});
-		_browserMapMenu.add(googleMapsItem);
-		JMenuItem openMapsItem = new JMenuItem(I18nManager.getText("menu.view.browser.openstreetmap"));
-		openMapsItem.addActionListener(new ActionListener() {
-			public void actionPerformed(ActionEvent e) {
-				_app.showExternalMap(UrlGenerator.MAP_SOURCE_OSM);
-			}
-		});
-		_browserMapMenu.add(openMapsItem);
-		JMenuItem mapquestMapsItem = new JMenuItem(I18nManager.getText("menu.view.browser.mapquest"));
-		mapquestMapsItem.addActionListener(new ActionListener() {
-			public void actionPerformed(ActionEvent e) {
-				_app.showExternalMap(UrlGenerator.MAP_SOURCE_MAPQUEST);
-			}
-		});
-		_browserMapMenu.add(mapquestMapsItem);
-		JMenuItem yahooMapsItem = new JMenuItem(I18nManager.getText("menu.view.browser.yahoo"));
-		yahooMapsItem.addActionListener(new ActionListener() {
-			public void actionPerformed(ActionEvent e) {
-				_app.showExternalMap(UrlGenerator.MAP_SOURCE_YAHOO);
-			}
-		});
-		_browserMapMenu.add(yahooMapsItem);
-		JMenuItem bingMapsItem = new JMenuItem(I18nManager.getText("menu.view.browser.bing"));
-		bingMapsItem.addActionListener(new ActionListener() {
-			public void actionPerformed(ActionEvent e) {
-				_app.showExternalMap(UrlGenerator.MAP_SOURCE_BING);
-			}
-		});
-		_browserMapMenu.add(bingMapsItem);
-		viewMenu.add(_browserMapMenu);
 		// Charts
 		_chartItem = makeMenuItem(FunctionLibrary.FUNCTION_CHARTS, false);
 		viewMenu.add(_chartItem);
@@ -535,6 +533,10 @@ public class MenuManager implements DataSubscriber
 		// estimate time
 		_estimateTimeItem = makeMenuItem(FunctionLibrary.FUNCTION_ESTIMATE_TIME, false);
 		viewMenu.add(_estimateTimeItem);
+		viewMenu.addSeparator();
+		// autoplay
+		_autoplayTrack = makeMenuItem(FunctionLibrary.FUNCTION_AUTOPLAY_TRACK, false);
+		viewMenu.add(_autoplayTrack);
 		menubar.add(viewMenu);
 
 		// Add photo menu
@@ -640,6 +642,16 @@ public class MenuManager implements DataSubscriber
 		settingsMenu.add(makeMenuItem(FunctionLibrary.FUNCTION_SET_COLOURS));
 		// Set line width used for drawing
 		settingsMenu.add(makeMenuItem(new ChooseSingleParameter(_app, FunctionLibrary.FUNCTION_SET_LINE_WIDTH)));
+		// Use antialias or not
+		_antialiasCheckbox = new JCheckBoxMenuItem(I18nManager.getText("menu.settings.antialias"), false);
+		_antialiasCheckbox.setSelected(Config.getConfigBoolean(Config.KEY_ANTIALIAS));
+		_antialiasCheckbox.addActionListener(new ActionListener() {
+			public void actionPerformed(ActionEvent e) {
+				Config.setConfigBoolean(Config.KEY_ANTIALIAS, _antialiasCheckbox.isSelected());
+				UpdateMessageBroker.informSubscribers(MAPSERVER_CHANGED);
+			}
+		});
+			settingsMenu.add(_antialiasCheckbox);
 		// Set language
 		settingsMenu.add(makeMenuItem(FunctionLibrary.FUNCTION_SET_LANGUAGE));
 		// Set altitude tolerance
@@ -860,6 +872,7 @@ public class MenuManager implements DataSubscriber
 		_exportImageItem.setEnabled(hasMultiplePoints);
 		_compressItem.setEnabled(hasData);
 		_markRectangleItem.setEnabled(hasData);
+		_markUphillLiftsItem.setEnabled(hasData && _track.hasAltitudeData());
 		_deleteMarkedPointsItem.setEnabled(hasData && _track.hasMarkedPoints());
 		_rearrangeWaypointsItem.setEnabled(hasData && _track.hasTrackPoints() && _track.hasWaypoints());
 		_splitSegmentsItem.setEnabled(hasData && _track.hasTrackPoints() && _track.getNumPoints() > 3);
@@ -870,10 +883,11 @@ public class MenuManager implements DataSubscriber
 		_chartItem.setEnabled(hasData);
 		_browserMapMenu.setEnabled(hasData);
 		_distanceItem.setEnabled(hasData);
+		_autoplayTrack.setEnabled(hasData && _track.getNumPoints() > 3);
 		_getGpsiesItem.setEnabled(hasData);
 		_uploadGpsiesItem.setEnabled(hasData && _track.hasTrackPoints());
 		_lookupSrtmItem.setEnabled(hasData);
-		_lookupWikipediaItem.setEnabled(hasData);
+		_nearbyWikipediaItem.setEnabled(hasData);
 		_downloadOsmItem.setEnabled(hasData);
 		_getWeatherItem.setEnabled(hasData);
 		_findWaypointItem.setEnabled(hasData && _track.hasWaypoints());
@@ -900,6 +914,12 @@ public class MenuManager implements DataSubscriber
 		_selectEndItem.setEnabled(hasPoint);
 		_selectEndButton.setEnabled(hasPoint);
 		_duplicatePointItem.setEnabled(hasPoint);
+		_showPeakfinderItem.setEnabled(hasPoint);
+		_showGeohackItem.setEnabled(hasPoint);
+		_showPanoramioItem.setEnabled(hasPoint);
+		_showOpencachingComItem.setEnabled(hasPoint);
+		_searchOpencachingDeItem.setEnabled(hasPoint);
+		_searchMapillaryItem.setEnabled(hasPoint);
 		// is it a waypoint?
 		_selectSegmentItem.setEnabled(hasPoint && !currPoint.isWaypoint());
 		// are there any photos?
diff --git a/tim/prune/gui/TripleStateCheckBox.java b/tim/prune/gui/TripleStateCheckBox.java
new file mode 100644
index 0000000..6bd6001
--- /dev/null
+++ b/tim/prune/gui/TripleStateCheckBox.java
@@ -0,0 +1,78 @@
+package tim.prune.gui;
+
+import java.awt.event.ItemEvent;
+import java.awt.event.ItemListener;
+
+import javax.swing.ImageIcon;
+import javax.swing.JCheckBox;
+
+/**
+ * Class to represent a checkbox with three states, through which it cycles
+ * Instead of calling isChecked, need to use getCurrentState which will
+ * return 0, 1 or 2
+ */
+public class TripleStateCheckBox extends JCheckBox implements ItemListener
+{
+	/** Array of icons to be used */
+	private ImageIcon[] _icons = new ImageIcon[3];
+	/** Current state 0, 1 or 2 */
+	private int _currState = 0;
+
+	/** Inner class to proxy the listening events */
+	private class ProxyListener implements ItemListener
+	{
+		/** Listener onto which some of the events will be passed */
+		private ItemListener _listener = null;
+		/** Constructor */
+		ProxyListener(ItemListener inListener) {_listener = inListener;}
+		/** React to events, and only pass on the selected ones */
+		public void itemStateChanged(ItemEvent arg0) {
+			if (arg0.getStateChange() == ItemEvent.SELECTED) {
+				_listener.itemStateChanged(arg0);
+			}
+		}
+	}
+
+	/** Constructor */
+	public TripleStateCheckBox()
+	{
+		addItemListener(this);
+	}
+
+	/** Set the current state */
+	public void setCurrentState(int inState)
+	{
+		_currState = inState % 3;
+		setIcon(_icons[_currState]);
+		setSelected(false);
+		setSelectedIcon(_icons[(_currState+1)%3]);
+	}
+
+	/** @return current state 0, 1 or 2 */
+	public int getCurrentState()
+	{
+		return _currState;
+	}
+
+	/**
+	 * Set the icon to use for the given index
+	 * @param inIndex index 0, 1 or 2
+	 * @param inIcon icon to use for that state
+	 */
+	public void setIcon(int inIndex, ImageIcon inIcon)
+	{
+		_icons[inIndex % 3] = inIcon;
+	}
+
+	@Override
+	/** Intercept listener adding by putting a proxy inbetween */
+	public void addItemListener(ItemListener inListener) {
+		super.addItemListener(new ProxyListener(inListener));
+	}
+
+	/** React to a selection event by advancing the state */
+	public void itemStateChanged(ItemEvent inEvent)
+	{
+		setCurrentState(_currState + 1);
+	}
+}
diff --git a/tim/prune/gui/UndoManager.java b/tim/prune/gui/UndoManager.java
index 48307c1..b9d9f32 100644
--- a/tim/prune/gui/UndoManager.java
+++ b/tim/prune/gui/UndoManager.java
@@ -4,7 +4,6 @@ import java.awt.FlowLayout;
 import java.awt.BorderLayout;
 import java.awt.event.ActionEvent;
 import java.awt.event.ActionListener;
-import java.util.Stack;
 import javax.swing.BorderFactory;
 import javax.swing.JButton;
 import javax.swing.JDialog;
@@ -19,16 +18,17 @@ import javax.swing.event.ListSelectionListener;
 
 import tim.prune.App;
 import tim.prune.I18nManager;
-import tim.prune.undo.UndoOperation;
+import tim.prune.undo.UndoStack;
 
 /**
  * Class to manage the selection of actions to undo
  */
 public class UndoManager
 {
-	private App _app;
-	private JDialog _dialog;
-	private JList<String> _actionList;
+	private App _app = null;
+	private JFrame _parentFrame = null;
+	private JDialog _dialog = null;
+	private JList<String> _actionList = null;
 
 
 	/**
@@ -39,18 +39,26 @@ public class UndoManager
 	public UndoManager(App inApp, JFrame inFrame)
 	{
 		_app = inApp;
-		_dialog = new JDialog(inFrame, I18nManager.getText("dialog.undo.title"), true);
-		_dialog.setLocationRelativeTo(inFrame);
+		_parentFrame = inFrame;
+	}
+
+	/**
+	 * Show the dialog to select which actions to undo
+	 */
+	public void show()
+	{
+		_dialog = new JDialog(_parentFrame, I18nManager.getText("dialog.undo.title"), true);
+		_dialog.setLocationRelativeTo(_parentFrame);
 		JPanel mainPanel = new JPanel();
 		mainPanel.setLayout(new BorderLayout(3, 3));
 		mainPanel.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
-		Stack<UndoOperation> undoStack = inApp.getUndoStack();
+		UndoStack undoStack = _app.getUndoStack();
 		mainPanel.add(new JLabel(I18nManager.getText("dialog.undo.pretext")), BorderLayout.NORTH);
 
 		String[] undoActions = new String[undoStack.size()];
 		for (int i=0; i<undoStack.size(); i++)
 		{
-			undoActions[i] = undoStack.elementAt(undoStack.size()-1-i).getDescription();
+			undoActions[i] = undoStack.getOperationAt(undoStack.size()-1-i).getDescription();
 		}
 		_actionList = new JList<String>(undoActions);
 		_actionList.setSelectionMode(ListSelectionModel.SINGLE_INTERVAL_SELECTION);
diff --git a/tim/prune/gui/images/add_photo_icon.png b/tim/prune/gui/images/add_photo_icon.png
old mode 100755
new mode 100644
diff --git a/tim/prune/gui/images/add_textfile_icon.png b/tim/prune/gui/images/add_textfile_icon.png
old mode 100755
new mode 100644
diff --git a/tim/prune/gui/images/pause.png b/tim/prune/gui/images/pause.png
new file mode 100644
index 0000000..b9f48da
Binary files /dev/null and b/tim/prune/gui/images/pause.png differ
diff --git a/tim/prune/gui/images/play.png b/tim/prune/gui/images/play.png
new file mode 100644
index 0000000..38abef7
Binary files /dev/null and b/tim/prune/gui/images/play.png differ
diff --git a/tim/prune/gui/images/points_connected.gif b/tim/prune/gui/images/points_connected.gif
deleted file mode 100644
index e6091c1..0000000
Binary files a/tim/prune/gui/images/points_connected.gif and /dev/null differ
diff --git a/tim/prune/gui/images/points_connected.png b/tim/prune/gui/images/points_connected.png
new file mode 100644
index 0000000..1891af0
Binary files /dev/null and b/tim/prune/gui/images/points_connected.png differ
diff --git a/tim/prune/gui/images/points_disconnected.gif b/tim/prune/gui/images/points_disconnected.gif
deleted file mode 100644
index 1015169..0000000
Binary files a/tim/prune/gui/images/points_disconnected.gif and /dev/null differ
diff --git a/tim/prune/gui/images/points_disconnected.png b/tim/prune/gui/images/points_disconnected.png
new file mode 100644
index 0000000..37f2c0f
Binary files /dev/null and b/tim/prune/gui/images/points_disconnected.png differ
diff --git a/tim/prune/gui/images/points_hidden.png b/tim/prune/gui/images/points_hidden.png
new file mode 100644
index 0000000..452015c
Binary files /dev/null and b/tim/prune/gui/images/points_hidden.png differ
diff --git a/tim/prune/gui/images/rewind.png b/tim/prune/gui/images/rewind.png
new file mode 100644
index 0000000..bc0fdbd
Binary files /dev/null and b/tim/prune/gui/images/rewind.png differ
diff --git a/tim/prune/gui/map/DiskTileCacher.java b/tim/prune/gui/map/DiskTileCacher.java
index 459b140..63dc684 100644
--- a/tim/prune/gui/map/DiskTileCacher.java
+++ b/tim/prune/gui/map/DiskTileCacher.java
@@ -40,7 +40,6 @@ public class DiskTileCacher implements Runnable
 		_url = inUrl;
 		_file = inFile;
 		_observer = inObserver;
-		new Thread(this).start();
 	}
 
 	/**
@@ -98,7 +97,7 @@ public class DiskTileCacher implements Runnable
 		// Start a new thread to load the image if necessary
 		if ((dir.exists() || dir.mkdirs()) && dir.canWrite())
 		{
-			new DiskTileCacher(inUrl, tileFile, inObserver);
+			new Thread(new DiskTileCacher(inUrl, tileFile, inObserver)).start();
 			return true;
 		}
 		return false; // couldn't write the file
diff --git a/tim/prune/gui/map/MapCanvas.java b/tim/prune/gui/map/MapCanvas.java
index 7a6bce8..4221520 100644
--- a/tim/prune/gui/map/MapCanvas.java
+++ b/tim/prune/gui/map/MapCanvas.java
@@ -11,6 +11,7 @@ import java.awt.FontMetrics;
 import java.awt.Graphics;
 import java.awt.Graphics2D;
 import java.awt.Image;
+import java.awt.RenderingHints;
 import java.awt.event.ActionEvent;
 import java.awt.event.ActionListener;
 import java.awt.event.ItemEvent;
@@ -59,6 +60,7 @@ import tim.prune.function.compress.MarkPointsInRectangleFunction;
 import tim.prune.function.edit.FieldEdit;
 import tim.prune.function.edit.FieldEditList;
 import tim.prune.gui.IconManager;
+import tim.prune.gui.TripleStateCheckBox;
 import tim.prune.gui.colour.PointColourer;
 import tim.prune.tips.TipManager;
 
@@ -97,7 +99,7 @@ public class MapCanvas extends JPanel implements MouseListener, MouseMotionListe
 	/** Checkbox for autopan */
 	private JCheckBox _autopanCheckBox = null;
 	/** Checkbox for connecting track points */
-	private JCheckBox _connectCheckBox = null;
+	private TripleStateCheckBox _connectCheckBox = null;
 	/** Checkbox for enable edit mode */
 	private JCheckBox _editmodeCheckBox = null;
 	/** Right-click popup menu */
@@ -241,8 +243,11 @@ public class MapCanvas extends JPanel implements MouseListener, MouseMotionListe
 		_autopanCheckBox.setFocusable(false); // stop button from stealing keyboard focus
 		_topPanel.add(_autopanCheckBox);
 		// Add checkbox button for connecting points or not
-		_connectCheckBox = new JCheckBox(IconManager.getImageIcon(IconManager.POINTS_DISCONNECTED_BUTTON), true);
-		_connectCheckBox.setSelectedIcon(IconManager.getImageIcon(IconManager.POINTS_CONNECTED_BUTTON));
+		_connectCheckBox = new TripleStateCheckBox();
+		_connectCheckBox.setIcon(0, IconManager.getImageIcon(IconManager.POINTS_CONNECTED_BUTTON));
+		_connectCheckBox.setIcon(1, IconManager.getImageIcon(IconManager.POINTS_DISCONNECTED_BUTTON));
+		_connectCheckBox.setIcon(2, IconManager.getImageIcon(IconManager.POINTS_HIDDEN_BUTTON));
+		_connectCheckBox.setCurrentState(0);
 		_connectCheckBox.setOpaque(false);
 		_connectCheckBox.setToolTipText(I18nManager.getText("menu.map.connect"));
 		_connectCheckBox.addItemListener(itemListener);
@@ -509,8 +514,10 @@ public class MapCanvas extends JPanel implements MouseListener, MouseMotionListe
 			_mapImage = new BufferedImage(getWidth(), getHeight(), BufferedImage.TYPE_INT_RGB);
 		}
 
-		// Clear map
 		Graphics g = _mapImage.getGraphics();
+		// Set antialiasing according to config
+		((Graphics2D) g).setRenderingHint(RenderingHints.KEY_ANTIALIASING,
+			Config.getConfigBoolean(Config.KEY_ANTIALIAS) ? RenderingHints.VALUE_ANTIALIAS_ON : RenderingHints.VALUE_ANTIALIAS_OFF);
 		// Clear to background
 		g.setColor(Config.getColourScheme().getColour(ColourScheme.IDX_BACKGROUND));
 		g.fillRect(0, 0, getWidth(), getHeight());
@@ -678,7 +685,9 @@ public class MapCanvas extends JPanel implements MouseListener, MouseMotionListe
 		// draw track points
 		inG.setColor(pointColour);
 		int prevX = -1, prevY = -1;
-		boolean connectPoints = _connectCheckBox.isSelected();
+		final int connectState = _connectCheckBox.getCurrentState();
+		final boolean drawLines = (connectState % 2) == 0; // 0 or 2
+		final boolean drawPoints = (connectState <= 1);    // 0 or 1
 		boolean prevPointVisible = false, currPointVisible = false;
 		boolean anyWaypoints = false;
 		boolean isWaypoint = false;
@@ -696,7 +705,7 @@ public class MapCanvas extends JPanel implements MouseListener, MouseMotionListe
 			anyWaypoints = anyWaypoints || isWaypoint;
 			if (!isWaypoint)
 			{
-				if (currPointVisible || prevPointVisible)
+				if ((currPointVisible || prevPointVisible) && drawPoints)
 				{
 					// For track points, work out which colour to use
 					if (_track.getPoint(i).getDeleteFlag()) {
@@ -721,7 +730,7 @@ public class MapCanvas extends JPanel implements MouseListener, MouseMotionListe
 				}
 
 				// Connect track points if either of them are visible
-				if (connectPoints && !(prevX == -1 && prevY == -1)
+				if (drawLines && !(prevX == -1 && prevY == -1)
 				 && !_track.getPoint(i).getSegmentStart())
 				{
 					inG.drawLine(prevX, prevY, px, py);
diff --git a/tim/prune/gui/map/MapSource.java b/tim/prune/gui/map/MapSource.java
index 88ab85a..b7a08fc 100644
--- a/tim/prune/gui/map/MapSource.java
+++ b/tim/prune/gui/map/MapSource.java
@@ -84,14 +84,20 @@ public abstract class MapSource
 	{
 		if (inUrl == null || inUrl.equals("")) {return null;}
 		String urlstr = inUrl;
+		boolean urlOk = false;
+
 		// check prefix
-		try {
-			new URL(urlstr.replace('[', 'w').replace(']', 'w'));
-			// There's a warning that this URL object isn't used, but it's enough to know the parse
-			// was successful without an exception being thrown.
+		try
+		{
+			urlOk = new URL(urlstr.replace('[', 'w').replace(']', 'w')) != null;
 		}
 		catch (MalformedURLException e)
 		{
+			urlOk = false;
+		}
+
+		if (!urlOk)
+		{
 			// fail if protocol specified
 			if (urlstr.indexOf("://") >= 0) {return null;}
 			// add the http protocol
@@ -102,7 +108,8 @@ public abstract class MapSource
 			urlstr = urlstr + "/";
 		}
 		// Validate current url, return null if not ok
-		try {
+		try
+		{
 			URL url = new URL(urlstr.replace('[', 'w').replace(']', 'w'));
 			// url host must contain a dot
 			if (url.getHost().indexOf('.') < 0) {return null;}
diff --git a/tim/prune/gui/map/MapSourceLibrary.java b/tim/prune/gui/map/MapSourceLibrary.java
index b82fd4e..e324af1 100644
--- a/tim/prune/gui/map/MapSourceLibrary.java
+++ b/tim/prune/gui/map/MapSourceLibrary.java
@@ -43,8 +43,8 @@ public abstract class MapSourceLibrary
 		_sourceList.add(new OsmMapSource("Reitkarte", "http://topo[234].wanderreitkarte.de/topo/"));
 		_sourceList.add(new MffMapSource("Mapsforfree", "http://maps-for-free.com/layer/relief/", "jpg",
 			"http://maps-for-free.com/layer/water/", "gif", 11));
-		_sourceList.add(new OsmMapSource("Hikebikemap", "http://toolserver.org/tiles/hikebike/",
-			"http://toolserver.org/~cmarqu/hill/", 18));
+		_sourceList.add(new OsmMapSource("Hikebikemap", "http://[abc].tiles.wmflabs.org/hikebike/",
+			"http://[abc].tiles.wmflabs.org/hillshading/", 18));
 		_sourceList.add(new OsmMapSource("Openseamap", "http://tile.openstreetmap.org/",
 			"http://tiles.openseamap.org/seamark/", 18));
 	}
diff --git a/tim/prune/gui/profile/ProfileChart.java b/tim/prune/gui/profile/ProfileChart.java
index 0dcabcb..b2d0d0d 100644
--- a/tim/prune/gui/profile/ProfileChart.java
+++ b/tim/prune/gui/profile/ProfileChart.java
@@ -4,10 +4,13 @@ import java.awt.Color;
 import java.awt.Dimension;
 import java.awt.FlowLayout;
 import java.awt.Graphics;
+import java.awt.Graphics2D;
+import java.awt.RenderingHints;
 import java.awt.event.ActionEvent;
 import java.awt.event.ActionListener;
 import java.awt.event.MouseEvent;
 import java.awt.event.MouseListener;
+
 import javax.swing.JLabel;
 import javax.swing.JMenuItem;
 import javax.swing.JPopupMenu;
@@ -86,6 +89,9 @@ public class ProfileChart extends GenericDisplay implements MouseListener
 	public void paint(Graphics g)
 	{
 		super.paint(g);
+		// Set antialiasing depending on Config
+		((Graphics2D) g).setRenderingHint(RenderingHints.KEY_ANTIALIASING,
+			Config.getConfigBoolean(Config.KEY_ANTIALIAS) ? RenderingHints.VALUE_ANTIALIAS_ON : RenderingHints.VALUE_ANTIALIAS_OFF);
 		ColourScheme colourScheme = Config.getColourScheme();
 		paintBackground(g, colourScheme);
 		if (_track != null && _track.getNumPoints() > 0)
diff --git a/tim/prune/jpeg/ExternalExifLibrary.java b/tim/prune/jpeg/ExternalExifLibrary.java
index 496646e..4d06a27 100644
--- a/tim/prune/jpeg/ExternalExifLibrary.java
+++ b/tim/prune/jpeg/ExternalExifLibrary.java
@@ -37,48 +37,48 @@ public class ExternalExifLibrary implements ExifLibrary
 			if (metadata.containsDirectory(GpsDirectory.class))
 			{
 				Directory gpsdir = metadata.getDirectory(GpsDirectory.class);
-				if (gpsdir.containsTag(GpsDirectory.TAG_GPS_LATITUDE)
-					&& gpsdir.containsTag(GpsDirectory.TAG_GPS_LONGITUDE)
-					&& gpsdir.containsTag(GpsDirectory.TAG_GPS_LATITUDE_REF)
-					&& gpsdir.containsTag(GpsDirectory.TAG_GPS_LONGITUDE_REF))
+				if (gpsdir.containsTag(GpsDirectory.TAG_LATITUDE)
+					&& gpsdir.containsTag(GpsDirectory.TAG_LONGITUDE)
+					&& gpsdir.containsTag(GpsDirectory.TAG_LATITUDE_REF)
+					&& gpsdir.containsTag(GpsDirectory.TAG_LONGITUDE_REF))
 				{
-					data.setLatitudeRef(gpsdir.getString(GpsDirectory.TAG_GPS_LATITUDE_REF));
-					Rational[] latRats = gpsdir.getRationalArray(GpsDirectory.TAG_GPS_LATITUDE);
+					data.setLatitudeRef(gpsdir.getString(GpsDirectory.TAG_LATITUDE_REF));
+					Rational[] latRats = gpsdir.getRationalArray(GpsDirectory.TAG_LATITUDE);
 					double seconds = ExifGateway.convertToPositiveValue(latRats[2].getNumerator(), latRats[2].getDenominator());
 					data.setLatitude(new double[] {latRats[0].doubleValue(),
 						latRats[1].doubleValue(), seconds});
-					data.setLongitudeRef(gpsdir.getString(GpsDirectory.TAG_GPS_LONGITUDE_REF));
-					Rational[] lonRats = gpsdir.getRationalArray(GpsDirectory.TAG_GPS_LONGITUDE);
+					data.setLongitudeRef(gpsdir.getString(GpsDirectory.TAG_LONGITUDE_REF));
+					Rational[] lonRats = gpsdir.getRationalArray(GpsDirectory.TAG_LONGITUDE);
 					seconds = ExifGateway.convertToPositiveValue(lonRats[2].getNumerator(), lonRats[2].getDenominator());
 					data.setLongitude(new double[] {lonRats[0].doubleValue(),
 						lonRats[1].doubleValue(), seconds});
 				}
 
 				// Altitude (if present)
-				if (gpsdir.containsTag(GpsDirectory.TAG_GPS_ALTITUDE) && gpsdir.containsTag(GpsDirectory.TAG_GPS_ALTITUDE_REF))
+				if (gpsdir.containsTag(GpsDirectory.TAG_ALTITUDE) && gpsdir.containsTag(GpsDirectory.TAG_ALTITUDE_REF))
 				{
-					data.setAltitude(gpsdir.getRational(GpsDirectory.TAG_GPS_ALTITUDE).intValue());
-					byte altRef = (byte) gpsdir.getInt(GpsDirectory.TAG_GPS_ALTITUDE_REF);
+					data.setAltitude(gpsdir.getRational(GpsDirectory.TAG_ALTITUDE).intValue());
+					byte altRef = (byte) gpsdir.getInt(GpsDirectory.TAG_ALTITUDE_REF);
 					data.setAltitudeRef(altRef);
 				}
 
 				// Timestamp and datestamp (if present)
-				final int TAG_GPS_DATESTAMP = 0x001d;
-				if (gpsdir.containsTag(GpsDirectory.TAG_GPS_TIME_STAMP) && gpsdir.containsTag(TAG_GPS_DATESTAMP))
+				final int TAG_DATESTAMP = 0x001d;
+				if (gpsdir.containsTag(GpsDirectory.TAG_TIME_STAMP) && gpsdir.containsTag(TAG_DATESTAMP))
 				{
-					Rational[] times = gpsdir.getRationalArray(GpsDirectory.TAG_GPS_TIME_STAMP);
+					Rational[] times = gpsdir.getRationalArray(GpsDirectory.TAG_TIME_STAMP);
 					data.setGpsTimestamp(new int[] {times[0].intValue(), times[1].intValue(),
 						times[2].intValue()});
-					Rational[] dates = gpsdir.getRationalArray(TAG_GPS_DATESTAMP);
+					Rational[] dates = gpsdir.getRationalArray(TAG_DATESTAMP);
 					if (dates != null) {
 						data.setGpsDatestamp(new int[] {dates[0].intValue(), dates[1].intValue(), dates[2].intValue()});
 					}
 				}
 
 				// Image bearing (if present)
-				if (gpsdir.containsTag(GpsDirectory.TAG_GPS_IMG_DIRECTION) && gpsdir.containsTag(GpsDirectory.TAG_GPS_IMG_DIRECTION_REF))
+				if (gpsdir.containsTag(GpsDirectory.TAG_IMG_DIRECTION) && gpsdir.containsTag(GpsDirectory.TAG_IMG_DIRECTION_REF))
 				{
-					Rational bearing = gpsdir.getRational(GpsDirectory.TAG_GPS_IMG_DIRECTION);
+					Rational bearing = gpsdir.getRational(GpsDirectory.TAG_IMG_DIRECTION);
 					if (bearing != null) {
 						data.setBearing(bearing.doubleValue());
 					}
diff --git a/tim/prune/lang/prune-texts_af.properties b/tim/prune/lang/prune-texts_af.properties
index 35ef53f..ef735f7 100644
--- a/tim/prune/lang/prune-texts_af.properties
+++ b/tim/prune/lang/prune-texts_af.properties
@@ -12,7 +12,7 @@ menu.track=Baan
 menu.track.undo=Herroep
 menu.track.clearundo=Maak herroep lys skoon
 menu.track.markrectangle=Merk punte
-menu.track.deletemarked=Vee gemerkde punte uit
+function.deletemarked=Vee gemerkde punte uit
 menu.range=Reeks
 menu.range.all=Selekteer alles
 menu.range.none=Selekteer niks
diff --git a/tim/prune/lang/prune-texts_cz.properties b/tim/prune/lang/prune-texts_cz.properties
index 2ac7ca6..54093a8 100644
--- a/tim/prune/lang/prune-texts_cz.properties
+++ b/tim/prune/lang/prune-texts_cz.properties
@@ -12,7 +12,7 @@ menu.track=Stopa
 menu.track.undo=Undo
 menu.track.clearundo=Vypr\u00e1zdnit pam\u011b\u0165 undo
 menu.track.markrectangle=Ozna\u010dit body v obd\u00e9ln\u00edku
-menu.track.deletemarked=Smazat ozna\u010den\u00e9 body
+function.deletemarked=Smazat ozna\u010den\u00e9 body
 function.rearrangewaypoints=P\u0159euspo\u0159\u00e1dat z\u00e1jmov\u00e9 body
 menu.range=Rozmez\u00ed
 menu.range.all=Vybrat v\u0161e
diff --git a/tim/prune/lang/prune-texts_da.properties b/tim/prune/lang/prune-texts_da.properties
new file mode 100644
index 0000000..e1d29ae
--- /dev/null
+++ b/tim/prune/lang/prune-texts_da.properties
@@ -0,0 +1,84 @@
+# Text entries for the GpsPrune application
+# Danish translations
+
+# Menu entries
+menu.file=Fil
+menu.file.addphotos=Tilf\u00f8j billeder
+menu.file.recentfiles=Seneste filer
+menu.file.save=Gem som tekst
+menu.file.exit=Afslut
+menu.track.undo=Fortryd
+menu.track.clearundo=Nulstil fortrydelsesliste
+function.deletemarked=Slet markerede punkter
+function.rearrangewaypoints=Omorganis\u00e9r waypoints
+dialog.rearrange.tonearest=Hvert waypoint til n\u00e6rmeste nabo
+menu.range=Omr\u00e5de
+menu.range.all=V\u00e6lg alle
+menu.range.none=Ingen valgt
+menu.range.start=V\u00e6lg omr\u00e5des startpunkt
+menu.range.end=V\u00e6lg omr\u00e5des slutpunkt
+menu.range.average=Dan gennemsnit af valgte omr\u00e5de
+menu.range.reverse=Dan omvendt r\u00e6kkef\u00f8lge
+menu.range.mergetracksegments=Sammensmelt sporsegmenter
+menu.range.cutandmove=Afsk\u00e6r og flyt valgte omr\u00e5de
+menu.point=Punkt
+menu.point.editpoint=Redig\u00e8r punkt
+menu.point.deletepoint=Fjern punkt
+menu.photo=Foto
+menu.photo.saveexif=Gem Exif-data
+menu.audio=Lyd
+menu.view=Udseende
+menu.view.showsidebars=Vis sidepanel
+menu.view.browser=Kort i browser
+menu.settings=Indstillinger
+menu.settings.onlinemode=Hent kort fra Internettet
+menu.settings.autosave=Gem indstillinger automatisk ved aflutning
+menu.help=Hj\u00e6lp
+# Popup menu for map
+menu.map.zoomin=Zoom ind
+menu.map.zoomout=Zoom ud
+menu.map.newpoint=Skab nyt punkt
+menu.map.drawpoints=Skab serie af punkter
+menu.map.connect=Saml punkter p\u00e5 linie
+menu.map.autopan=Autocentrering
+menu.map.showmap=Vis kort
+menu.map.showscalebar=Vis m\u00e5lestok
+
+# Alt keys for menus
+altkey.menu.file=F
+altkey.menu.track=S
+altkey.menu.range=O
+altkey.menu.point=P
+altkey.menu.view=U
+altkey.menu.photo=T
+altkey.menu.audio=L
+altkey.menu.settings=I
+altkey.menu.help=H
+
+# Functions
+function.open=\u00c5bn fil
+function.importwithgpsbabel=Import\u00e9r fil med GPSBabel
+function.loadfromgps=Hent data fra GPS
+function.sendtogps=Overf\u00f8r data til GPS
+function.exportkml=Eksport\u00e9r KML
+function.exportgpx=Eksport\u00e9r GPX
+function.exportpov=Eksport\u00e9r POV
+function.exportsvg=Eksport\u00e9r SVG
+function.editwaypointname=Ret waypoint-navn
+function.compress=Komprim\u00e9r spor
+function.deleterange=Fjern det valgte omr\u00e5de
+function.croptrack=Afgr\u00e6ns spor
+function.interpolate=Interpol\u00e9r
+function.addtimeoffset=Tilf\u00f8j offset p\u00e5 tiden
+function.addaltitudeoffset=Tilf\u00f8j offset p\u00e5 h\u00f8jde
+function.convertnamestotimes=Ret waypoint-navne til tidspunkter
+function.deletefieldvalues=Fjern feltv\u00e6rdier
+function.findwaypoint=Find waypoint
+function.pastecoordinates=Indf\u00f8j nye koordinater
+function.charts=Kort
+function.show3d=3-D view
+function.distances=Afstande
+function.fullrangedetails=Vis alle detaljer
+function.setmapbg=V\u00e6lg kort som baggrund
+function.setpaths=V\u00e6lg sti til programmer
+function.getgpsies=Se liste af GPS-spor
diff --git a/tim/prune/lang/prune-texts_de.properties b/tim/prune/lang/prune-texts_de.properties
index a85515e..4169c91 100644
--- a/tim/prune/lang/prune-texts_de.properties
+++ b/tim/prune/lang/prune-texts_de.properties
@@ -12,7 +12,7 @@ menu.track=Track
 menu.track.undo=R\u00fcckg\u00e4ngig
 menu.track.clearundo=Liste der letzten \u00c4nderungen l\u00f6schen
 menu.track.markrectangle=Punkte im Viereck markieren
-menu.track.deletemarked=Markierte Punkte l\u00f6schen
+function.deletemarked=Markierte Punkte l\u00f6schen
 function.rearrangewaypoints=Wegpunkte neu anordnen
 menu.range=Bereich
 menu.range.all=Alles markieren
@@ -39,6 +39,7 @@ menu.view.browser.yahoo=Yahoo Maps
 menu.view.browser.bing=Bing Maps
 menu.settings=Einstellungen
 menu.settings.onlinemode=Karten aus dem Internet laden
+menu.settings.antialias=Kantengl\u00e4ttung an
 menu.settings.autosave=Einstellungen automatisch speichern
 menu.help=Hilfe
 # Popup menu for map
@@ -86,6 +87,7 @@ function.exportsvg=SVG exportieren
 function.exportimage=Bild exportieren
 function.editwaypointname=Namen des Punkts bearbeiten
 function.compress=Track komprimieren
+function.marklifts=Bergbahnen markieren
 function.deleterange=Bereich l\u00f6schen
 function.croptrack=Track zuschneiden
 function.interpolate=Punkte interpolieren
@@ -102,6 +104,7 @@ function.distances=Entfernungen
 function.fullrangedetails=Zus\u00e4tzliche Bereichdetails
 function.estimatetime=Zeit absch\u00e4tzen
 function.learnestimationparams=Zeitparameter erlernen
+function.autoplay=Track abspielen
 function.setmapbg=Karte Hintergrund setzen
 function.setpaths=Programmpfade setzen
 function.selectsegment=Aktuellen Abschnitt markieren
@@ -112,7 +115,9 @@ function.uploadgpsies=Track zu GPSies.com hochladen
 function.lookupsrtm=H\u00f6hendaten von SRTM nachschlagen
 function.downloadsrtm=SRTM Dateien herunterladen
 function.getwikipedia=Wikipediaartikel in der N\u00e4he nachschlagen
-function.searchwikipedianames=Wikipedia mit Name durchsuchen
+function.searchwikipedianames=Wikipedia nach Namen durchsuchen
+function.searchopencachingde=OpenCaching.de durchsuchen
+function.mapillary=Mapillary nach Fotos durchsuchen
 function.downloadosm=OSM-Daten f\u00fcr dieses Gebiet herunterladen
 function.duplicatepoint=Punkt verdoppeln
 function.setcolours=Farben einstellen
@@ -377,9 +382,11 @@ dialog.gpsies.activity.motorbiking=Motorradfahren
 dialog.gpsies.activity.snowshoe=Schneeschuhwandern
 dialog.gpsies.activity.sailing=Segeln
 dialog.gpsies.activity.skating=Inline-Skating
+dialog.mapillary.nonefound=Keine Fotos gefunden
 dialog.wikipedia.column.name=Artikelname
 dialog.wikipedia.column.distance=Entfernung
 dialog.wikipedia.nonefound=Keine Punkte gefunden
+dialog.geocaching.nonefound=Keine Punkte gefunden
 dialog.correlate.notimestamps=Die Punkte enthalten keine Zeitangaben, deshalb k\u00f6nnen die Fotos nicht zugeordnet werden.
 dialog.correlate.nouncorrelatedphotos=Alle Fotos sind schon zugeordnet.\nWollen Sie trotzdem fortfahren?
 dialog.correlate.nouncorrelatedaudios=Alle Audiodateien sind schon zugeordnet.\nWollen Sie trotzdem fortfahren?
@@ -588,6 +595,11 @@ dialog.deletebydate.column.keep=Behalten
 dialog.deletebydate.column.delete=L\u00f6schen
 dialog.setaltitudetolerance.text.metres=Mindestabweichung (Meter) f\u00fcr H\u00f6henunterschiede
 dialog.setaltitudetolerance.text.feet=Mindestabweichung (Feet) f\u00fcr H\u00f6henunterschiede
+dialog.autoplay.duration=Abspieldauer (Sek)
+dialog.autoplay.usetimestamps=Zeitstempeln verwenden
+dialog.autoplay.rewind=Zum Anfang
+dialog.autoplay.pause=Pause
+dialog.autoplay.play=Abspielen
 
 # 3d window
 dialog.3d.title=GpsPrune-3D-Ansicht
@@ -753,6 +765,7 @@ fieldname.duration=Zeitdauer
 fieldname.speed=Geschwindigkeit
 fieldname.verticalspeed=Vertikale Geschwindigkeit
 fieldname.description=Beschreibung
+fieldname.mediafilename=Foto- / Audioname
 
 # Measurement units
 units.original=Original
@@ -790,6 +803,11 @@ logic.or=oder
 url.googlemaps=maps.google.de
 wikipedia.lang=de
 openweathermap.lang=de
+webservice.peakfinder=Peakfinder.org \u00f6ffnen
+webservice.geohack=Geohack-Seite \u00f6ffnen
+webservice.panoramio=Panoramio Karte \u00f6ffnen
+webservice.opencachingcom=Opencaching.com \u00f6ffnen
+webservice.opencachingcom.lang=de
 
 # Cardinals for 3d plots
 cardinal.n=N
diff --git a/tim/prune/lang/prune-texts_de_CH.properties b/tim/prune/lang/prune-texts_de_CH.properties
index a0bad3e..d4e0e1e 100644
--- a/tim/prune/lang/prune-texts_de_CH.properties
+++ b/tim/prune/lang/prune-texts_de_CH.properties
@@ -12,7 +12,7 @@ menu.track=Track
 menu.track.undo=Undo
 menu.track.clearundo=Undo-Liste l\u00f6sche
 menu.track.markrectangle=P\u00fcnkte inem Viereck markiere
-menu.track.deletemarked=Markierte P\u00fcnkte l\u00f6sche
+function.deletemarked=Markierte P\u00fcnkte l\u00f6sche
 function.rearrangewaypoints=Waypoints reorganisiere
 menu.range=Beriich
 menu.range.all=Alles selektiere
@@ -38,6 +38,7 @@ menu.view.showsidebars=Seiteleischten aazeige
 menu.view.browser=Karte inem Browser
 menu.settings=Iistellige
 menu.settings.onlinemode=Karten uusem Internet lade
+menu.settings.antialias=Kantegl\u00e4ttig aa
 menu.settings.autosave=Iistellige automatisch speichere
 menu.help=Hilfe
 # Popup menu for map
@@ -85,6 +86,7 @@ function.exportsvg=SVG exportier\u00e4
 function.exportimage=Bild exportier\u00e4
 function.editwaypointname=Waypoint Namen editiere
 function.compress=Track komprimier\u00e4
+function.marklifts=Bergb\u00e4hnli markiere
 function.deleterange=Beriich l\u00f6sche
 function.croptrack=Track zuschniide
 function.deletebydate=P\u00fcnkte na Datum l\u00f6sche
@@ -100,6 +102,7 @@ function.distances=Entf\u00e4rnige
 function.fullrangedetails=Zues\u00e4tzlichi Beriichinfos
 function.estimatetime=Ziit absch\u00e4tze
 function.learnestimationparams=Ziitparameter erlerne
+function.autoplay=Track abschpiel\u00e4
 function.setmapbg=Karte Hintegrund setz\u00e4
 function.selectsegment=Aktuelli Segm\u00e4nt selektiere
 function.splitsegments=In Tracksegm\u00e4nte schniide
@@ -109,7 +112,9 @@ function.uploadgpsies=Date zum Gpsies uufalad\u00e4
 function.lookupsrtm=H\u00f6hendate vonem SRTM hole
 function.downloadsrtm=SRTM Files abalade
 function.getwikipedia=Im Wikipedia in dr N\u00f6chi naaluege
-function.searchwikipedianames=Wikipedia mit Name durasueche
+function.searchwikipedianames=Wikipedia nachem Namen durasueche
+function.searchopencachingde=OpenCaching.de durasueche
+function.mapillary=Mapillary nach F\u00f6telis durasueche
 function.downloadosm=OSM-Date f\u00fcr dere Gebiet abalad\u00e4
 function.duplicatepoint=Punkt verdoppl\u00e4
 function.correlatephotos=F\u00f6telis korrelier\u00e4
@@ -275,13 +280,13 @@ dialog.confirmcutandmove.text=Diese Daten enthalte Ziitst\u00e4mpel Informatione
 dialog.interpolate.parameter.text=Aazahl P\u00fcnkte zum inn\u00e4tue zw\u00fcschet den selektierten P\u00fcnkten
 dialog.interpolate.betweenwaypoints=Zw\u00fcschet d Waypoints interpoliere?
 dialog.undo.title=Undo Operation(e)
-dialog.undo.pretext=Selektiere die Operatione die r\u00fcckg\u00e4ngig gmacht s\u00f6llti werde.
+dialog.undo.pretext=Welli Operatione s\u00f6llet r\u00fcckg\u00e4ngig gmacht werde?
 dialog.undo.none.title=Undo n\u00f6d m\u00f6glich
 dialog.undo.none.text=Keini Operatione k\u00f6nne r\u00fcckg\u00e4ngig gmacht werde.
 dialog.clearundo.title=Undo-Liste l\u00f6sch\u00e4
 dialog.clearundo.text=Sind Sie sicher, Sie wend die Undo-Liste l\u00f6sche?\nAlle Undo Infos werdet verlore gah!
 dialog.pointedit.title=Punkt editier\u00e4
-dialog.pointedit.intro=W\u00e4hlet Sie j\u00e4den F\u00e4ld uus, um den Wert z'seh und z'\u00e4ndere
+dialog.pointedit.intro=W\u00e4hlet Sie j\u00e4des F\u00e4ld uus, um den Wert z'seh und z'\u00e4ndere
 dialog.pointedit.table.field=F\u00e4ld
 dialog.pointedit.nofield=Kei F\u00e4ld uusgew\u00e4hlt
 dialog.pointedit.table.value=Wert
@@ -362,7 +367,7 @@ dialog.gpsies.nonefound=Kei Tracks gfunde
 dialog.gpsies.username=Gpsies Username
 dialog.gpsies.password=Gpsies Passwort
 dialog.gpsies.keepprivate=Track privat halte
-dialog.gpsies.confirmopenpage=Websiite f\u00fcrn uufageladenen Track \u00f6ffne?
+dialog.gpsies.confirmopenpage=Websiite f\u00fcrn uufagladenen Track \u00f6ffne?
 dialog.gpsies.activities=Aktivit\u00e4ten
 dialog.gpsies.activity.trekking=Wandere
 dialog.gpsies.activity.walking=Z'Fuess gah
@@ -372,9 +377,11 @@ dialog.gpsies.activity.motorbiking=Motorrad
 dialog.gpsies.activity.snowshoe=Schneeschuh
 dialog.gpsies.activity.sailing=Segle
 dialog.gpsies.activity.skating=Inline-Skate
+dialog.mapillary.nonefound=Kei F\u00f6telis gfunde
 dialog.wikipedia.column.name=Artikelname
 dialog.wikipedia.column.distance=Entf\u00e4rnig
 dialog.wikipedia.nonefound=Kei Wiki-Iitr\u00e4ge gfunde
+dialog.geocaching.nonefound=Kei C�ches gfunde
 dialog.correlate.notimestamps=Es h\u00e4t kei Ziitst\u00e4mpel inem Track inn\u00e4, so s'isch n\u00f6d m\u00f6glech die F\u00f6telis zu korrelier\u00e4.
 dialog.correlate.nouncorrelatedphotos=Alle F\u00f6telis sin scho korreliert.\nWend Sie trotzdem fortsetz\u00e4?
 dialog.correlate.nouncorrelatedaudios=Alle Audios sin scho korreliert.\nWend Sie trotzdem fortsetz\u00e4?
@@ -433,7 +440,7 @@ dialog.deletemarked.nonefound=Kei P\u00fcnkte h\u00e4tte gel\u00f6scht werde k\u
 dialog.pastecoordinates.desc=G\u00e4bet Sie hier die Koordinaten inn\u00e4
 dialog.pastecoordinates.coords=Koordinate
 dialog.pastecoordinates.nothingfound=Pr\u00fcefet Sie die Koordinate und versuechet nomal
-dialog.help.help=Bitte lueg na\n http://gpsprune.activityworkshop.net/\nf\u00fcr wiitere Information und Benutzeraaleitige.
+dialog.help.help=Lueget Sie na\n http://gpsprune.activityworkshop.net/\nf\u00fcr wiitere Information und Benutzeraaleitige.
 dialog.about.version=Version
 dialog.about.build=Build
 dialog.about.summarytext1=GpsPrune isch s Programm f\u00fcrs Lade, Darstelle und Editiere vo Date von GPS Ger\u00e4te.
@@ -477,7 +484,7 @@ dialog.keys.intro=Aastatt d'Muus k\u00f6nnet Sie diese Tastekombinationen nutze
 dialog.keys.keylist=<table><tr><td>Pfiil Taste</td><td>Karte verschiebe</td></tr><tr><td>Strg + links, r\u00e4chts Pfiil</td><td>Vorherigi oder n\u00f6chsti Punkt markiere</td></tr><tr><td>Strg + uuf, aba Pfiil</td><td>Ii- oder Uusezoome</td></tr><tr><td>Strg + Bild uuf, ab</td><td>Vorherigi oder n\u00f6chsti Segm\u00e4nt markiere</td></tr><tr><td>Strg + Pos1, \u00c4nde</td><td>Erschti oder letschti Punkt markiere</td></tr><tr><td>Entf</td><td>Aktuelli Punkt l\u00f6sche</td></tr></table>
 dialog.keys.normalmodifier=Strg
 dialog.keys.macmodifier=Kommando
-dialog.saveconfig.desc=Die folgendi Iinstellige k\u00f6nne gspeicheret werde :
+dialog.saveconfig.desc=Die folgendi Iistellige k\u00f6nne gspeicheret werde :
 dialog.saveconfig.prune.trackdirectory=Trackverzeichnis
 dialog.saveconfig.prune.photodirectory=F\u00f6teliverzeichnis
 dialog.saveconfig.prune.languagecode=Sprochecode (DE_ch)
@@ -526,7 +533,7 @@ dialog.colourer.type.bygradient=Nach Gef\u00e4lle
 dialog.colourer.type.bydate=Nach Datum
 dialog.colourer.start=Aafangsfarb
 dialog.colourer.end=Zielfarb
-dialog.colourer.maxcolours=Maximal Anzahl Farbe
+dialog.colourer.maxcolours=Maximal Aazahl Farbe
 dialog.setlanguage.firstintro=Sie k\u00f6nnet entweder eini vo den iigebouti Sproche<p>oder ne Text-Datei uusw\u00e4hle.
 dialog.setlanguage.secondintro=Sie m\u00fcnt Ihri Iistellige speichere und dann<p>GpsPrune wieder neustarte um die Sproch z'\u00e4ndere.
 dialog.setlanguage.language=Sproch
@@ -582,7 +589,12 @@ dialog.deletebydate.nodate=Ohni Ziitaagab
 dialog.deletebydate.column.keep=Behalte
 dialog.deletebydate.column.delete=L\u00f6sche
 dialog.setaltitudetolerance.text.metres=Mindeschtabweichig (Meter) f\u00fcr H\u00f6chiunterschied
-dialog.setaltitudetolerance.text.feet=Mindeschtabweichig (Feet) f\u00fcr H\u00f6chinunterschied
+dialog.setaltitudetolerance.text.feet=Mindeschtabweichig (Feet) f\u00fcr H\u00f6chiunterschied
+dialog.autoplay.duration=Abspieldauer (Sek)
+dialog.autoplay.usetimestamps=Ziitst\u00e4mple verw\u00e4nde
+dialog.autoplay.rewind=Zum Aafang
+dialog.autoplay.pause=Pause
+dialog.autoplay.play=Abschpiele
 
 # 3d window
 dialog.3d.title=GpsPrune Dr\u00fc\u00fc-d Aasicht
@@ -693,7 +705,7 @@ details.trackdetails=Details vom Track
 details.notrack=Kei Track glade worde
 details.track.points=P\u00fcnkte
 details.track.file=Datei
-details.track.numfiles=Anzahl Dateie
+details.track.numfiles=Aazahl Dateie
 details.pointdetails=Details vonem Punkt
 details.index.selected=Index
 details.index.of=vo
@@ -748,6 +760,7 @@ fieldname.duration=Ziitl\u00e4ngi
 fieldname.speed=Gschwindikeit
 fieldname.verticalspeed=Uf/Ab Gschwindikeit
 fieldname.description=Bschriibig
+fieldname.mediafilename=F\u00f6teli- / Audioname
 
 # Measurement units
 units.original=Original
@@ -785,6 +798,11 @@ logic.or=oder
 url.googlemaps=maps.google.ch
 wikipedia.lang=als
 openweathermap.lang=de
+webservice.peakfinder=Peakfinder.org \u00f6ffne
+webservice.geohack=Geohack-Siite \u00f6ffne
+webservice.panoramio=Panoramio Karte \u00f6ffne
+webservice.opencachingcom=Opencaching.com \u00f6ffne
+webservice.opencachingcom.lang=de
 
 # Cardinals for 3d plots
 cardinal.n=N
diff --git a/tim/prune/lang/prune-texts_en.properties b/tim/prune/lang/prune-texts_en.properties
index 447ce4d..785a62e 100644
--- a/tim/prune/lang/prune-texts_en.properties
+++ b/tim/prune/lang/prune-texts_en.properties
@@ -12,7 +12,7 @@ menu.track=Track
 menu.track.undo=Undo
 menu.track.clearundo=Clear undo list
 menu.track.markrectangle=Mark points in rectangle
-menu.track.deletemarked=Delete marked points
+function.deletemarked=Delete marked points
 menu.range=Range
 menu.range.all=Select all
 menu.range.none=Select none
@@ -38,6 +38,7 @@ menu.view.browser.yahoo=Yahoo maps
 menu.view.browser.bing=Bing maps
 menu.settings=Settings
 menu.settings.onlinemode=Load maps from internet
+menu.settings.antialias=Use antialiasing
 menu.settings.autosave=Autosave settings on exit
 menu.help=Help
 # Popup menu for map
@@ -85,6 +86,7 @@ function.exportsvg=Export SVG
 function.exportimage=Export image
 function.editwaypointname=Edit waypoint name
 function.compress=Compress track
+function.marklifts=Mark uphill lifts
 function.deleterange=Delete range
 function.croptrack=Crop track
 function.interpolate=Interpolate points
@@ -102,6 +104,7 @@ function.distances=Distances
 function.fullrangedetails=Full range details
 function.estimatetime=Estimate time
 function.learnestimationparams=Learn time estimation parameters
+function.autoplay=Autoplay track
 function.selectsegment=Select current segment
 function.splitsegments=Split track into segments
 function.sewsegments=Sew track segments together
@@ -111,6 +114,8 @@ function.lookupsrtm=Get altitudes from SRTM
 function.downloadsrtm=Download SRTM tiles
 function.getwikipedia=Get nearby Wikipedia articles
 function.searchwikipedianames=Search Wikipedia by name
+function.searchopencachingde=Search OpenCaching.de
+function.mapillary=Search for photos in Mapillary
 function.downloadosm=Download OSM data for area
 function.duplicatepoint=Duplicate point
 function.connecttopoint=Connect to point
@@ -377,9 +382,11 @@ dialog.gpsies.activity.motorbiking=Motorbiking
 dialog.gpsies.activity.snowshoe=Snowshoeing
 dialog.gpsies.activity.sailing=Sailing
 dialog.gpsies.activity.skating=Skating
+dialog.mapillary.nonefound=No photos found
 dialog.wikipedia.column.name=Article name
 dialog.wikipedia.column.distance=Distance
 dialog.wikipedia.nonefound=No wikipedia entries found
+dialog.geocaching.nonefound=No geocaches found
 dialog.correlate.notimestamps=There are no timestamps in the data points, so there is nothing to correlate with the photos.
 dialog.correlate.nouncorrelatedphotos=There are no uncorrelated photos.\nAre you sure you want to continue?
 dialog.correlate.nouncorrelatedaudios=There are no uncorrelated audios.\nAre you sure you want to continue?
@@ -438,12 +445,12 @@ dialog.deletemarked.nonefound=No data points could be removed
 dialog.pastecoordinates.desc=Enter or paste the coordinates here
 dialog.pastecoordinates.coords=Coordinates
 dialog.pastecoordinates.nothingfound=Please check the coordinates and try again
-dialog.help.help=Please see\n http://gpsprune.activityworkshop.net/\nfor more information and tips,\nincluding a new PDF user guide you can buy.
+dialog.help.help=Please see\n http://gpsprune.activityworkshop.net/\nfor more information and tips,\nincluding a PDF user guide you can buy.
 dialog.about.version=Version
 dialog.about.build=Build
 dialog.about.summarytext1=GpsPrune is a program for loading, displaying and editing data from GPS receivers.
 dialog.about.summarytext2=It is released under the Gnu GPL for free, open, worldwide use and enhancement.<br>Copying, redistribution and modification are permitted and encouraged<br>according to the conditions in the included <code>license.txt</code> file.
-dialog.about.summarytext3=Please see <code style="font-weight:bold">http://activityworkshop.net/</code> for more information and tips, including<br>a new PDF user guide you can buy.
+dialog.about.summarytext3=Please see <code style="font-weight:bold">http://activityworkshop.net/</code> for more information and tips, including<br>a PDF user guide you can buy.
 dialog.about.languages=Available languages
 dialog.about.translatedby=English text by activityworkshop.
 dialog.about.systeminfo=System info
@@ -588,6 +595,11 @@ dialog.deletebydate.column.keep=Keep
 dialog.deletebydate.column.delete=Delete
 dialog.setaltitudetolerance.text.metres=Limit (in metres) below which small climbs and descents will be ignored
 dialog.setaltitudetolerance.text.feet=Limit (in feet) below which small climbs and descents will be ignored
+dialog.autoplay.duration=Duration (secs)
+dialog.autoplay.usetimestamps=Use point timestamps
+dialog.autoplay.rewind=Back to beginning
+dialog.autoplay.pause=Pause
+dialog.autoplay.play=Play
 
 # 3d window
 dialog.3d.title=GpsPrune Three-d view
@@ -753,6 +765,7 @@ fieldname.duration=Duration
 fieldname.speed=Speed
 fieldname.verticalspeed=Vertical speed
 fieldname.description=Description
+fieldname.mediafilename=Filename
 
 # Measurement units
 units.original=Original
@@ -796,6 +809,11 @@ logic.or=or
 url.googlemaps=maps.google.co.uk
 wikipedia.lang=en
 openweathermap.lang=en
+webservice.peakfinder=Open Peakfinder.org
+webservice.geohack=Open Geohack page
+webservice.panoramio=Open Panoramio map
+webservice.opencachingcom=Open Opencaching.com
+webservice.opencachingcom.lang=en
 
 # Cardinals for 3d plots
 cardinal.n=N
diff --git a/tim/prune/lang/prune-texts_es.properties b/tim/prune/lang/prune-texts_es.properties
index 5b920b8..a8be199 100644
--- a/tim/prune/lang/prune-texts_es.properties
+++ b/tim/prune/lang/prune-texts_es.properties
@@ -12,7 +12,7 @@ menu.track=Track
 menu.track.undo=Deshacer
 menu.track.clearundo=Despejar la lista de deshacer
 menu.track.markrectangle=Marcar puntos dentro de un rect\u00e1ngulo
-menu.track.deletemarked=Eliminar puntos marcados
+function.deletemarked=Eliminar puntos marcados
 menu.range=Rango
 menu.range.all=Seleccionar todo
 menu.range.none=No seleccionar nada
@@ -38,6 +38,7 @@ menu.view.browser.yahoo=Mapas Yahoo
 menu.view.browser.bing=Mapas Bing
 menu.settings=Preferencias
 menu.settings.onlinemode=Cargar mapas de Internet
+menu.settings.antialias=Usar antialiasing
 menu.settings.autosave=Auto Guardar
 menu.help=Ayuda
 
@@ -114,7 +115,8 @@ function.lookupsrtm=Obtener altitudes de SRTM
 function.downloadsrtm=Descargar datos de SRTM
 function.getwikipedia=Obtener art\u00edculos de Wikipedia cercanos
 function.searchwikipedianames=Buscar en Wikipedia por nombre
-function.searchopencachingde=Buscar OpenCaching.de
+function.searchopencachingde=Buscar en OpenCaching.de
+function.mapillary=Buscar en Mapillary
 function.downloadosm=Descargar datos OSM del \u00e1rea
 function.duplicatepoint=Duplicar punto
 function.setcolours=Establecer color
@@ -377,6 +379,7 @@ dialog.gpsies.activity.motorbiking=En moto
 dialog.gpsies.activity.snowshoe=Raquetas de nieve
 dialog.gpsies.activity.sailing=Vela
 dialog.gpsies.activity.skating=Patinaje
+dialog.mapillary.nonefound=No se encontraron fotos
 dialog.wikipedia.column.name=Nombre del art\u00edculo
 dialog.wikipedia.column.distance=Distancia
 dialog.wikipedia.nonefound=No se encontraron puntos
@@ -583,13 +586,13 @@ dialog.weather.humidity=Humedad
 dialog.deletebydate.nodate=Sin marcas de tiempo
 dialog.deletebydate.column.keep=Mantener
 dialog.deletebydate.column.delete=Eliminar
+dialog.autoplay.duration=Duraci\u00f3n (seg)
 
 ## 3d window
 dialog.3d.title=GpsPrune vista 3-D
 dialog.3d.altitudefactor=Factor de exageraci\u00f3n de altura
 
 ## Confirm messages
-# These are displayed as confirmation in the status bar
 confirm.loadfile=Dato cargado de
 confirm.save.ok1=Guardado correctamente
 confirm.save.ok2=puntos al archivo
@@ -678,7 +681,6 @@ filetype.png=Archivos PNG
 filetype.audio=Archivos MP3, OGG, WAV
 
 ## 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
 display.notimestamps=Los datos de recorrido no incluyen marcas de tiempo
@@ -743,6 +745,7 @@ fieldname.duration=Duraci\u00f3n
 fieldname.speed=Velocidad
 fieldname.verticalspeed=Velocidad vertical
 fieldname.description=Descripci\u00f3n
+fieldname.mediafilename=Archivo
 
 ## Measurement units
 units.original=Original
@@ -786,6 +789,10 @@ logic.or=o
 url.googlemaps=maps.google.es
 wikipedia.lang=es
 openweathermap.lang=sp
+webservice.peakfinder=Abrir Peakfinder.org
+webservice.geohack=Abrir Geohack
+webservice.panoramio=Abrir mapa Panoramio
+webservice.opencachingcom=Abrir Opencaching.com
 webservice.opencachingcom.lang=es
 
 ## Cardinals for 3d plots
@@ -795,7 +802,6 @@ cardinal.e=E
 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=cargar datos
 undo.loadphotos=cargar fotos
 undo.loadaudios=cargar archivos de audio
diff --git a/tim/prune/lang/prune-texts_fa.properties b/tim/prune/lang/prune-texts_fa.properties
new file mode 100644
index 0000000..a7637b2
--- /dev/null
+++ b/tim/prune/lang/prune-texts_fa.properties
@@ -0,0 +1,73 @@
+# Text entries for the Prune application
+# Persian (Farsi) entries as extra
+
+# Menu entries
+menu.file=\u067e\u0648\u0634\u0647
+menu.file.addphotos=\u0627\u0636\u0627\u0641\u0647 \u06a9\u0631\u062f\u0646 \u0639\u06a9\u0633
+menu.file.save=\u0630\u062e\u064a\u0631\u0647
+menu.file.exit=\u062e\u0631\u0648\u062c
+menu.track=\u0645\u0633\u064a\u0631
+menu.track.undo=\u0628\u0627\u0637\u0644 \u06a9\u0631\u062f\u0646 \u06a9\u0627\u0631 \u0642\u0628\u0644\u064a
+menu.track.clearundo=\u067e\u0627\u06a9 \u06a9\u0631\u062f\u0646 \u0644\u064a\u0633\u062a \u06a9\u0627\u0631\u0647\u0627\u06cc \u0627\u0646\u062c\u0627\u0645 \u0634\u062f\u0647
+function.deletemarked=\u067e\u0627\u06a9 \u06a9\u0631\u062f\u0646 \u0646\u0642\u0627\u0637 \u0627\u0646\u062a\u062e\u0627\u0628 \u0634\u062f\u0647
+function.rearrangewaypoints=\u0628\u0627\u0632 \u0686\u064a\u0646\u06cc \u0646\u0642\u0627\u0637 \u0645\u0633\u064a\u0631
+dialog.rearrange.tostart=\u0647\u0645\u0647 \u0646\u0642\u0627\u0637 \u0628\u0647 \u0627\u0628\u062a\u062f\u0627\u06cc \u0645\u0633\u064a\u0631
+dialog.rearrange.toend=\u0647\u0645\u0647 \u0646\u0642\u0627\u0637 \u0628\u0647 \u0627\u0646\u062a\u0647\u0627\u06cc \u0645\u0633\u064a\u0631
+dialog.rearrange.tonearest=\u0647\u0631 \u064a\u06a9 \u0628\u0647 \u0646\u0632\u062f\u064a\u06a9 \u0646\u0642\u0637\u0647 \u0645\u0633\u064a\u0631
+menu.range=\u0686\u064a\u0646\u0634
+menu.range.all=\u0627\u0646\u062a\u062e\u0627\u0628 \u0647\u0645\u0647 \u0646\u0642\u0627\u0637
+menu.range.none=\u0627\u0646\u062a\u062e\u0627\u0628 \u0647\u064a\u0686 \u064a\u06a9 \u0627\u0632 \u0646\u0642\u0627\u0637
+menu.range.start=\u062a\u0646\u0638\u064a\u0645 \u0634\u0631\u0648\u0639 \u0686\u064a\u0646\u0634
+menu.range.end=\u062a\u0646\u0638\u064a\u0645 \u0627\u0646\u062a\u0647\u0627\u06cc \u0686\u064a\u0646\u0634
+function.deleterange=\u067e\u0627\u06a9 \u06a9\u0631\u062f\u0646 \u0686\u064a\u0646\u0634
+function.interpolate=\u062f\u0631\u0648\u0646\u064a\u0627\u0628\u06cc
+menu.range.average=\u0645\u06cc\u0627\u0646\u06af\u064a\u0646 \u0627\u0646\u062a\u062e\u0627\u0628 \u0634\u062f\u0647 \u0647\u0627
+menu.range.reverse=\u0686\u064a\u0646\u0634 \u0645\u0639\u06a9\u0648\u0633
+menu.range.mergetracksegments=\u0627\u062a\u0635\u0627\u0644 \u0642\u0633\u0645\u062a \u0647\u0627\u06cc \u0645\u0633\u064a\u0631
+menu.range.cutandmove=\u062c\u062f\u0627 \u06a9\u0631\u062f\u0646 \u0642\u0633\u0645\u062a \u0627\u0646\u062a\u062e\u0627\u0628 \u0634\u062f\u0647
+menu.point=\u0646\u0642\u0637\u0647
+menu.point.editpoint=\u062a\u0646\u0638\u064a\u0645\u0627\u062a \u0646\u0642\u0637\u0647
+menu.point.deletepoint=\u067e\u0627\u06a9 \u06a9\u0631\u062f\u0646 \u0646\u0642\u0637\u0647
+menu.photo=\u0639\u06a9\u0633
+menu.photo.saveexif=\u0630\u062e\u064a\u0631\u0647 \u062f\u0631 \u0641\u0627\u064a\u0644 \u0636\u0645\u064a\u0645\u0647 \u0639\u06a9\u0633
+function.connecttopoint=\u0627\u062a\u0635\u0627\u0644 \u0628\u0647 \u0646\u0642\u0637\u0647
+function.disconnectfrompoint=\u0642\u0637\u0639 \u0627\u062a\u0635\u0627\u0644 \u0627\u0632 \u0646\u0642\u0637\u0647
+function.removephoto=\u0628\u0631\u062f\u0627\u0634\u062a\u0646 \u0639\u06a9\u0633
+menu.view=\u062f\u064a\u062f
+menu.view.browser=\u0646\u0642\u0634\u0647 \u062f\u0631\u062c\u0633\u062a\u062c\u0648\u06af\u0631
+menu.view.browser.google=Google Maps
+menu.view.browser.openstreetmap=OpenStreetMap
+menu.view.browser.mapquest=MapQuest
+menu.view.browser.yahoo=Yahoo Maps
+menu.view.browser.bing=Bing Maps
+menu.settings=\u062a\u0646\u0638\u06cc\u0645\u0627\u062a
+menu.settings.onlinemode=\u062f\u0627\u0646\u0644\u0648\u062f \u0646\u0642\u0634\u0647 \u0627\u0632 \u0627\u064a\u0646\u062a\u0631\u0646\u062a
+menu.help=\u0631\u0627\u0647\u0646\u0645\u0627
+# Popup menu for map
+menu.map.zoomin=\u0628\u0632\u0631\u06af \u0646\u0645\u0627\u064a\u06cc
+menu.map.zoomout=\u06a9\u0648\u0686\u06a9 \u0646\u0645\u0627\u064a\u06cc
+menu.map.zoomfull=\u0646\u0645\u0627\u064a\u0634 \u062f\u0631 \u0627\u0646\u062f\u0627\u0632\u0647 \u06a9\u0627\u0645\u0644
+menu.map.newpoint=\u0627\u064a\u062c\u0627\u062f \u0646\u0642\u0637\u0647 \u062c\u062f\u064a\u062f
+menu.map.connect=\u0627\u062a\u0635\u0627\u0644 \u0646\u0642\u0627\u0637 \u0645\u0633\u064a\u0631
+menu.map.autopan=\u0646\u0645\u0627\u064a\u0634 \u062f\u0627\u0626\u0645 \u0646\u0642\u0637\u0647
+menu.map.showmap=\u0646\u0645\u0627\u064a\u0634 \u0646\u0642\u0637\u0647
+menu.map.showscalebar=\u0646\u0645\u0627\u064a\u0634 \u062a\u0646\u0638\u064a\u0645\u0627\u062a \u0645\u0642\u064a\u0627\u0633
+
+# Alt keys for menus
+altkey.menu.file=\u067e
+altkey.menu.track=\u0645
+altkey.menu.range=\u0686
+altkey.menu.point=\u0646
+altkey.menu.view=\u062f
+altkey.menu.photo=\u0639
+altkey.menu.settings=\u062a
+altkey.menu.help=\u0631
+
+# Ctrl shortcuts for menu items
+shortcut.menu.file.open=\u0628
+shortcut.menu.file.load=\u062f
+shortcut.menu.file.save=\u0630
+shortcut.menu.track.undo=\u0638
+shortcut.menu.edit.compress=\u062a
+shortcut.menu.range.all=\u0686
+shortcut.menu.help.help=\u0631
diff --git a/tim/prune/lang/prune-texts_fr.properties b/tim/prune/lang/prune-texts_fr.properties
index ad05294..5714803 100644
--- a/tim/prune/lang/prune-texts_fr.properties
+++ b/tim/prune/lang/prune-texts_fr.properties
@@ -12,7 +12,7 @@ menu.track=Trace
 menu.track.undo=Annuler
 menu.track.clearundo=Purger la liste d'annulation
 menu.track.markrectangle=S\u00e9lectionner les points dans un rectangle
-menu.track.deletemarked=Supprimer les points marqu\u00e9s
+function.deletemarked=Supprimer les points marqu\u00e9s
 function.rearrangewaypoints=R\u00e9arranger les points du navigation
 menu.range=\u00c9tendue
 menu.range.all=Tout s\u00e9lectionner
@@ -39,6 +39,7 @@ menu.view.browser.yahoo=Cartes Yahoo
 menu.view.browser.bing=Cartes Bing
 menu.settings=Pr\u00e9f\u00e9rences
 menu.settings.onlinemode=Charger cartes depuis internet
+menu.settings.antialias=Anticr\u00e9nelage
 menu.settings.autosave=Sauver automatiquement en quittant
 menu.help=Aide
 # Popup menu for map
@@ -114,6 +115,8 @@ function.lookupsrtm=R\u00e9cup\u00e9rer les altitudes depuis SRTM
 function.downloadsrtm=T\u00e9l\u00e9charger les donn\u00e9es SRTM
 function.getwikipedia=Obtenir les articles de Wikip\u00e9dia \u00e0 proximit\u00e9
 function.searchwikipedianames=Rechercher dans Wikip\u00e9dia par nom
+function.searchopencachingde=Rechercher dans OpenCaching.de
+function.mapillary=Rechercher dans Mapillary
 function.downloadosm=T\u00e9l\u00e9charger les donn\u00e9es OSM de la zone
 function.duplicatepoint=Dupliquer le point
 function.setcolours=Choisir les couleurs
@@ -338,6 +341,8 @@ dialog.estimatetime.results.actualtime=Dur\u00e9e en fait
 dialog.estimatetime.error.noaltitudes=L'\u00e9tendue s\u00e9lectionn\u00e9e de contient pas d'altitudes
 dialog.learnestimationparams.averageerror=Erreur en moyenne
 dialog.learnestimationparams.combinedresults=R\u00e9sultats combin\u00e9es
+dialog.learnestimationparams.weight.current=actuel
+dialog.learnestimationparams.weight.calculated=calcul\u00e9
 dialog.setmapbg.intro=S\u00e9lectionnez une source de cartes, ou ajoutez-en une nouvelle
 dialog.addmapsource.title=Ajouter une nouvelle source de cartes
 dialog.addmapsource.sourcename=Nom de la source
@@ -507,6 +512,14 @@ dialog.colourchooser.green=Vert
 dialog.colourchooser.blue=Bleu
 dialog.colourer.type=Crit\u00e8re de coloriste
 dialog.colourer.type.none=Aucun
+dialog.colourer.type.byfile=Selon fichier
+dialog.colourer.type.bysegment=Selon segment
+dialog.colourer.type.byaltitude=Selon altitude
+dialog.colourer.type.byspeed=Selon vitesse
+dialog.colourer.type.byvertspeed=Selon vitesse verticale
+dialog.colourer.type.bygradient=Selon la pente
+dialog.colourer.type.bydate=Selon la date
+dialog.colourer.maxcolours=Nombre de couleurs maximum
 dialog.setlanguage.firstintro=Vous pouvez s\u00e9lectionner l'une des langues disponibles,<p> ou bien un fichier de langue \u00e0 utiliser.
 dialog.setlanguage.secondintro=Vous devez sauvegarder vos param\u00e8tres puis<p>red\u00e9marrer GpsPrune pour changer de langue.
 dialog.setlanguage.language=Langue
@@ -559,6 +572,9 @@ dialog.weather.creditnotice=Ces donn\u00e9es sont fournies par openweathermap.or
 dialog.deletebydate.nodate=Sans horodatage
 dialog.deletebydate.column.keep=Garder
 dialog.deletebydate.column.delete=Supprimer
+dialog.autoplay.duration=Dur\u00e9e (sec)
+dialog.autoplay.pause=Pause
+dialog.autoplay.play=Jouer
 
 # 3d window
 dialog.3d.title=Vue 3D de GpsPrune
@@ -722,6 +738,7 @@ fieldname.duration=Dur\u00e9e
 fieldname.speed=Vitesse
 fieldname.verticalspeed=Vitesse verticale
 fieldname.description=Description
+fieldname.mediafilename=Nom de fichier
 
 # Measurement units
 units.original=Original
@@ -765,6 +782,10 @@ logic.or=ou
 url.googlemaps=maps.google.fr
 wikipedia.lang=fr
 openweathermap.lang=fr
+webservice.peakfinder=Ouvrir Peakfinder.org
+webservice.geohack=Ouvrir la page Geohack
+webservice.panoramio=Ouvrir la carte Panoramio
+webservice.opencachingcom=Ouvrir Opencaching.com
 webservice.opencachingcom.lang=fr
 
 # Cardinals for 3d plots
diff --git a/tim/prune/lang/prune-texts_hu.properties b/tim/prune/lang/prune-texts_hu.properties
index 74ba9e4..c083f63 100644
--- a/tim/prune/lang/prune-texts_hu.properties
+++ b/tim/prune/lang/prune-texts_hu.properties
@@ -12,7 +12,7 @@ menu.track=Nyomvonal
 menu.track.undo=Visszavon\u00e1s
 menu.track.clearundo=Visszavon\u00e1si lista t\u00f6rl\u00e9se
 menu.track.markrectangle=N\u00e9gyzeten bel\u00fcli pontok megjel\u00f6l\u00e9se
-menu.track.deletemarked=Jel\u00f6lt pontok t\u00f6rl\u00e9se
+function.deletemarked=Jel\u00f6lt pontok t\u00f6rl\u00e9se
 menu.range=Tartom\u00e1ny
 menu.range.all=Mindet kijel\u00f6l
 menu.range.none=Kijel\u00f6l\u00e9s megsz\u00fcntet\u00e9se
@@ -38,6 +38,7 @@ menu.view.browser.yahoo=Yahoo! Maps
 menu.view.browser.bing=Bing Maps
 menu.settings=Be\u00e1ll\u00edt\u00e1sok
 menu.settings.onlinemode=T\u00e9rk\u00e9pek bet\u00f6lt\u00e9se internetr\u0151l
+menu.settings.antialias=\u00c9lsim\u00edt\u00e1s haszn\u00e1lata
 menu.settings.autosave=Be\u00e1ll\u00edt\u00e1sok automatikus ment\u00e9se kil\u00e9p\u00e9skor
 menu.help=S\u00fag\u00f3
 
@@ -86,6 +87,7 @@ function.exportsvg=Export\u00e1l\u00e1s SVG-be
 function.exportimage=Export\u00e1l\u00e1s k\u00e9pbe
 function.editwaypointname=\u00datpont nev\u00e9nek szerkeszt\u00e9se
 function.compress=Nyomvonal t\u00f6m\u00f6r\u00edt\u00e9se
+function.marklifts=S\u00edliftek megjel\u00f6l\u00e9se
 function.deleterange=Tartom\u00e1ny t\u00f6rl\u00e9se
 function.croptrack=Nyomvonal k\u00f6rbev\u00e1g\u00e1sa
 function.interpolate=Pontok interpol\u00e1l\u00e1sa
@@ -103,6 +105,7 @@ function.distances=T\u00e1vols\u00e1gok
 function.fullrangedetails=Teljes tartom\u00e1ny r\u00e9szletei
 function.estimatetime=Becs\u00fclt id\u0151
 function.learnestimationparams=Id\u0151becsl\u00e9s tanul\u00e1s\u00e1nak param\u00e9terei
+function.autoplay=Nyomvonal lej\u00e1tsz\u00e1sa
 function.setmapbg=H\u00e1tt\u00e9rk\u00e9p be\u00e1ll\u00edt\u00e1sa
 function.setpaths=Program\u00fatvonalak be\u00e1ll\u00edt\u00e1sa
 function.selectsegment=Aktu\u00e1lis szakasz kiv\u00e1laszt\u00e1sa
@@ -115,6 +118,7 @@ function.downloadsrtm=SRTM csemp\u00e9k let\u00f6lt\u00e9se
 function.getwikipedia=K\u00f6zeli Wikip\u00e9dia sz\u00f3cikkek let\u00f6lt\u00e9se
 function.searchwikipedianames=Keres\u00e9s a Wikip\u00e9di\u00e1ban n\u00e9v szerint
 function.searchopencachingde=Keres\u00e9s az OpenCaching.de-n
+function.mapillary=F\u00e9nyk\u00e9pek keres\u00e9se Mapillary-n
 function.downloadosm=OSM adatok let\u00f6lt\u00e9se a ter\u00fcletr\u0151l
 function.duplicatepoint=Pont kett\u0151z\u00e9se
 function.setcolours=Sz\u00ednek be\u00e1ll\u00edt\u00e1sa
@@ -379,6 +383,7 @@ dialog.gpsies.activity.motorbiking=Motorker\u00e9kp\u00e1roz\u00e1s
 dialog.gpsies.activity.snowshoe=H\u00f3talpas s\u00e9ta
 dialog.gpsies.activity.sailing=Vitorl\u00e1z\u00e1s
 dialog.gpsies.activity.skating=Korcsoly\u00e1z\u00e1s
+dialog.mapillary.nonefound=Nem tal\u00e1lhat\u00f3k f\u00e9nyk\u00e9pek
 dialog.wikipedia.column.name=Sz\u00f3cikk neve
 dialog.wikipedia.column.distance=T\u00e1vols\u00e1g
 dialog.wikipedia.nonefound=Nem tal\u00e1lhat\u00f3 Wikip\u00e9dia sz\u00f3cikk
@@ -447,7 +452,7 @@ dialog.about.summarytext1=A GpsPrune egy program GPS vev\u0151kr\u0151l sz\u00e1
 dialog.about.summarytext2=Gnu GPL licenc alatt ker\u00fclt kiad\u00e1sra a szabad, ny\u00edlt, vil\u00e1gm\u00e9ret\u0171 haszn\u00e1lathoz \u00e9s fejleszt\u00e9shez.<br>M\u00e1sol\u00e1sa, terjeszt\u00e9se \u00e9s m\u00f3dos\u00edt\u00e1sa megengedett \u00e9s \u00f6szt\u00f6nz\u00f6tt<br>a mell\u00e9kelt <code>license.txt</code> f\u00e1jlban r\u00f6gz\u00edtett felt\u00e9telek szerint
 dialog.about.summarytext3=Tov\u00e1bbi inform\u00e1ci\u00f3k\u00e9rt \u00e9s kezel\u00e9si \u00fatmutat\u00f3\u00e9rt l\u00e1sd a <code style="font-weight:bold">http://activityworkshop.net/</code> webhelyet.
 dialog.about.languages=El\u00e9rhet\u0151 nyelvek
-dialog.about.translatedby=Magyar sz\u00f6veg: Ball\u00f3 Gy\u00f6rgy, B\u00e1thory P\u00e9ter, Peter Gervai
+dialog.about.translatedby=Magyar sz\u00f6veg: Ball\u00f3 Gy\u00f6rgy \u00e9s B\u00e1thory P\u00e9ter
 dialog.about.systeminfo=Rendszerinform\u00e1ci\u00f3
 dialog.about.systeminfo.os=Oper\u00e1ci\u00f3s rendszer
 dialog.about.systeminfo.java=Java futtat\u00f3k\u00f6rnyezet
@@ -590,6 +595,11 @@ dialog.deletebydate.column.keep=Megtart
 dialog.deletebydate.column.delete=T\u00f6r\u00f6l
 dialog.setaltitudetolerance.text.metres=Az a hat\u00e1r (m\u00e9terben) ami alatt a kis s\u00fcllyed\u00e9seket \u00e9s emelked\u00e9seket figyelmen k\u00edv\u00fcl hagyjuk
 dialog.setaltitudetolerance.text.feet=Az a hat\u00e1r (l\u00e1bban) ami alatt a kis s\u00fcllyed\u00e9seket \u00e9s emelked\u00e9seket figyelmen k\u00edv\u00fcl hagyjuk
+dialog.autoplay.duration=Id\u0151tartam (mp)
+dialog.autoplay.usetimestamps=Nyompontok id\u0151b\u00e9lyege alapj\u00e1n
+dialog.autoplay.rewind=Vissza az elej\u00e9re
+dialog.autoplay.pause=Sz\u00fcnet
+dialog.autoplay.play=Lej\u00e1tsz\u00e1s
 
 # 3d window
 dialog.3d.title=GpsPrune 3D n\u00e9zet
@@ -755,6 +765,7 @@ fieldname.duration=Id\u0151tartam
 fieldname.speed=Sebess\u00e9g
 fieldname.verticalspeed=F\u00fcgg\u0151leges sebess\u00e9g
 fieldname.description=Le\u00edr\u00e1s
+fieldname.mediafilename=F\u00e1jln\u00e9v
 
 # Measurement units
 units.original=Eredeti
diff --git a/tim/prune/lang/prune-texts_in.properties b/tim/prune/lang/prune-texts_in.properties
new file mode 100644
index 0000000..c0b4246
--- /dev/null
+++ b/tim/prune/lang/prune-texts_in.properties
@@ -0,0 +1,111 @@
+# Text entries for the Prune application
+# Indonesian entries as extra
+
+# Menu entries
+menu.file=Berkas
+menu.file.addphotos=Muat foto
+menu.file.save=Simpan
+menu.file.exit=Keluar
+menu.track=Track
+menu.track.undo=Batal
+menu.point.editpoint=Perbaiki titik
+menu.point.deletepoint=Hapus titik
+function.deleterange=Hapus jarak
+menu.range=Jangkauan
+menu.point=Titik
+menu.range.all=Pilih semua
+menu.range.none=Tidak memilih
+menu.photo=Foto
+menu.photo.saveexif=Simpan ke Exif
+function.connecttopoint=Hubungkan ke titik
+function.disconnectfrompoint=Putuskan dari titik
+function.removephoto=Menghapus foto
+menu.view=Lihat
+menu.settings=Pengaturan
+menu.view.browser=Peta di browser
+menu.help=Bantuan
+# Popup menu for map
+menu.map.zoomin=Perbesar
+menu.map.zoomout=Perkecil
+menu.map.newpoint=Buat titik baru
+menu.map.connect=Hubungkan titik jalur
+menu.map.showmap=Tampilkan peta
+
+# Alt keys for menus
+altkey.menu.file=B
+altkey.menu.track=T
+altkey.menu.range=J
+altkey.menu.point=K
+altkey.menu.view=L
+altkey.menu.photo=F
+altkey.menu.settings=G
+altkey.menu.help=N
+
+# Ctrl shortcuts for menu items
+shortcut.menu.file.open=B
+shortcut.menu.file.load=M
+shortcut.menu.file.save=S
+shortcut.menu.track.undo=Z
+shortcut.menu.edit.compress=P
+shortcut.menu.range.all=-
+shortcut.menu.help.help=-
+
+# Functions
+function.open=Buka
+function.loadfromgps=Muat data dari GPS
+function.sendtogps=Kirim data ke GPS
+function.exportkml=Ekspor KML
+function.exportgpx=Ekspor GPX
+function.exportpov=Ekspor POV
+function.editwaypointname=Perbaiki Nama waypoint
+function.compress=Padatkan jalur
+function.findwaypoint=Menemukan waypoint
+function.charts=Grafik
+function.show3d=Lihat tiga-D
+function.distances=Jarak
+function.correlatephotos=Korelasikan foto
+function.help=Bantuan
+function.about=Tentang Prune
+function.saveconfig=Simpan pengaturan
+
+# Dialogs
+dialog.load.table.datatype=Jenis
+dialog.load.table.description=Keterangan
+dialog.pointnameedit.name=Nama
+dialog.distances.column.from=Awal
+dialog.distances.column.to=Akhir
+dialog.about.languages=Bahasa
+dialog.about.yes=Ya
+dialog.about.no=Tidak
+
+# Buttons
+button.back=Sebelumnya
+button.next=Lanjut
+button.close=Tutup
+button.yes=Ya
+button.no=Tidak
+button.select=Pilih
+button.guessfields=Deteksi otomatis
+
+# File types
+filetype.txt=Berkas teks
+filetype.jpeg=Berkas JPG
+filetype.kmlkmz=Berkas KML, KMZ
+filetype.kml=Berkas KML
+filetype.kmz=Berkas KMZ
+filetype.gpx=Berkas GPX
+filetype.pov=Berkas POV
+filetype.svg=Berkas SVG
+
+# Display components
+display.nodata=Tidak ada data
+details.trackdetails=Rincian track
+details.notrack=Tidak ada track
+details.pointdetails=Rincian titik
+details.nopointselection=Tidak ada titik
+details.norangeselection=Tidak ada jangkauan
+details.rangedetails=Rincian jangkauan
+details.lists.photos=Foto
+details.photodetails=Rincian foto
+details.nophoto=Tidak ada foto
+details.photo.loading=Membuka
diff --git a/tim/prune/lang/prune-texts_it.properties b/tim/prune/lang/prune-texts_it.properties
index 06eb029..69a9c83 100644
--- a/tim/prune/lang/prune-texts_it.properties
+++ b/tim/prune/lang/prune-texts_it.properties
@@ -12,7 +12,7 @@ menu.track=Traccia
 menu.track.undo=Annulla
 menu.track.clearundo=Cancella lista annulla
 menu.track.markrectangle=Segnare i punti nel rettangolo
-menu.track.deletemarked=Cancella punti marcati
+function.deletemarked=Cancella punti marcati
 function.rearrangewaypoints=Riorganizza waypoint
 menu.range=Serie
 menu.range.all=Seleziona tutto
@@ -35,10 +35,11 @@ menu.view.browser=Mappa sul browser
 menu.view.browser.google=Google maps
 menu.view.browser.openstreetmap=Openstreetmap
 menu.view.browser.mapquest=Mapquest
-menu.view.browser.yahoo=mappe Yahoo
-menu.view.browser.bing=mappe Bing
+menu.view.browser.yahoo=Mappe Yahoo
+menu.view.browser.bing=Mappe Bing
 menu.settings=Preferenze
 menu.settings.onlinemode=Carica mappa da internet
+menu.settings.antialias=Usa antialiasing
 menu.settings.autosave=Salva settaggi con chiusura del programma
 menu.help=Aiuto
 # Popup menu for map
@@ -114,6 +115,7 @@ function.downloadsrtm=Scarica file da SRTM
 function.getwikipedia=Ottieni informazioni da Wikipedia
 function.searchwikipedianames=Cerca il nome in Wikipedia
 function.searchopencachingde=Cerca OpenCaching.de
+function.mapillary=Cerca Mapillary.com
 function.downloadosm=Scarica dati OSM dell'area
 function.duplicatepoint=Duplica punto corrente in coda
 function.setcolours=Scegli colori
@@ -754,6 +756,7 @@ fieldname.duration=Durata
 fieldname.speed=Velocit\u00e0
 fieldname.verticalspeed=Velocit\u00e0 verticale
 fieldname.description=Descrizione
+fieldname.mediafilename=File
 
 # Measurement units
 units.original=Originale
@@ -797,6 +800,10 @@ logic.or=o
 url.googlemaps=maps.google.it
 wikipedia.lang=it
 openweathermap.lang=it
+webservice.peakfinder=Apri Peakfinder.org
+webservice.geohack=Apri la pagina Geohack
+webservice.panoramio=Apri la mappa Panoramio
+webservice.opencachingcom=Apri Opencaching.com
 webservice.opencachingcom.lang=it
 
 # Cardinals for 3d plots
diff --git a/tim/prune/lang/prune-texts_ja.properties b/tim/prune/lang/prune-texts_ja.properties
index 371eec5..087e8f7 100644
--- a/tim/prune/lang/prune-texts_ja.properties
+++ b/tim/prune/lang/prune-texts_ja.properties
@@ -11,7 +11,7 @@ menu.track=\u30c8\u30e9\u30c3\u30af(T)
 menu.track.undo=\u30a2\u30f3\u30c9\u30a5
 menu.track.clearundo=\u30a2\u30f3\u30c9\u30a5\u30ea\u30b9\u30c8\u3092\u7a7a\u306b\u3059\u308b
 menu.track.markrectangle=\u56db\u89d2\u306e\u4e2d\u306b\u5370\u3092\u3064\u3051\u308b
-menu.track.deletemarked=\u5370\u306e\u4ed8\u3044\u305f\u70b9\u3092\u524a\u9664
+function.deletemarked=\u5370\u306e\u4ed8\u3044\u305f\u70b9\u3092\u524a\u9664
 function.rearrangewaypoints=\u30a6\u30a7\u30a4\u30dd\u30a4\u30f3\u30c8\u3092\u4e26\u3079\u66ff\u3048
 menu.range=\u7bc4\u56f2(R)
 menu.range.all=\u5168\u3066\u9078\u629e
diff --git a/tim/prune/lang/prune-texts_ko.properties b/tim/prune/lang/prune-texts_ko.properties
index 69722c9..e1f1945 100644
--- a/tim/prune/lang/prune-texts_ko.properties
+++ b/tim/prune/lang/prune-texts_ko.properties
@@ -9,7 +9,7 @@ menu.file.exit=\uc885\ub8cc
 menu.track=\ud2b8\ub799
 menu.track.undo=\uc2e4\ud589\ucde8\uc18c
 menu.track.clearundo=\uc2e4\ud589\ucde8\uc18c \ubaa9\ub85d \uc0ad\uc81c
-menu.track.deletemarked=\ud45c\uc2dc\ub41c \uc9c0\uc810 \uc9c0\uc6b0\uae30
+function.deletemarked=\ud45c\uc2dc\ub41c \uc9c0\uc810 \uc9c0\uc6b0\uae30
 function.rearrangewaypoints=\uacbd\uc720\uc9c0 \uc7ac\uc815\ub82c
 menu.range=\uc5f0\uacb0\uc120
 menu.range.all=\ubaa8\ub450 \uc120\ud0dd
diff --git a/tim/prune/lang/prune-texts_nl.properties b/tim/prune/lang/prune-texts_nl.properties
index a9431c6..548f9b6 100644
--- a/tim/prune/lang/prune-texts_nl.properties
+++ b/tim/prune/lang/prune-texts_nl.properties
@@ -12,7 +12,7 @@ menu.track=Route
 menu.track.undo=Ongedaan maken
 menu.track.clearundo=Ongedaan-maken lijst wissen
 menu.track.markrectangle=Makeer alle punten in een vierkant
-menu.track.deletemarked=Verwijderen gemarkeerde punten
+function.deletemarked=Verwijderen gemarkeerde punten
 menu.range=Reeks
 menu.range.all=Selecteer alles
 menu.range.none=Selecteer geen
@@ -38,6 +38,7 @@ menu.view.browser.yahoo=Yahoo maps
 menu.view.browser.bing=Bing maps
 menu.settings=Instellingen
 menu.settings.onlinemode=Kaarten van internet ophalen
+menu.settings.antialias=Anti-kartelvorming
 menu.settings.autosave=Automatisch opslaan bij afsluiten
 menu.help=Help
 # Popup menu for map
@@ -113,6 +114,7 @@ function.lookupsrtm=Hoogtes van SRTM ophalen
 function.downloadsrtm=Downloaden SRTM tegels
 function.getwikipedia=Wikipedia artikelen uit de buurt ophalen
 function.searchwikipedianames=Wikipedia zoeken op naam
+function.searchopencachingde=OpenCaching.de zoeken
 function.downloadosm=Downloaden OSM data voor gebied
 function.duplicatepoint=Dupliceer punt
 function.setcolours=Instellen kleuren
@@ -377,9 +379,11 @@ dialog.gpsies.activity.motorbiking=Motorrijden
 dialog.gpsies.activity.snowshoe=Sneeuwschoen-lopen
 dialog.gpsies.activity.sailing=Zeilen
 dialog.gpsies.activity.skating=Skating
+dialog.mapillary.nonefound=Geen foto's gevonden
 dialog.wikipedia.column.name=Artikelnaam
 dialog.wikipedia.column.distance=Afstand
 dialog.wikipedia.nonefound=Geen punten gevonden
+dialog.geocaching.nonefound=Geen punten gevonden
 dialog.correlate.notimestamps=Er zit geen tijdinformatie in de punten, dus kunnen ze niet aan foto's gekoppeld worden.
 dialog.correlate.nouncorrelatedphotos=Er zijn geen ongekoppelde foto's.\nWeet u zeker dat u wilt doorgaan?
 dialog.correlate.nouncorrelatedaudios=Er zijn geen ongekoppelde geluidsbestanden.\nWeet u zeker dat u wilt doorgaan?
@@ -588,6 +592,7 @@ dialog.deletebydate.column.keep=Behouden
 dialog.deletebydate.column.delete=Verwijderen
 dialog.setaltitudetolerance.text.metres=Grens (in meters) waaronder kleine klimmen en afdalingen worden genegeerd
 dialog.setaltitudetolerance.text.feet=Grens (in feet) waaronder kleine klimmen en afdalingen worden genegeerd
+dialog.autoplay.duration=Duur (sec)
 
 # 3d window
 dialog.3d.title=GpsPrune in 3D
@@ -753,6 +758,7 @@ fieldname.duration=Duur
 fieldname.speed=Snelheid
 fieldname.verticalspeed=Verticale snelheid
 fieldname.description=Omschrijving
+fieldname.mediafilename=Bestandsnaam
 
 # Measurement units
 units.original=Oorspronkelijke
@@ -796,6 +802,10 @@ logic.or=of
 url.googlemaps=maps.google.nl
 wikipedia.lang=nl
 openweathermap.lang=nl
+webservice.peakfinder=Open Peakfinder.org
+webservice.geohack=Open Geohack webpagina
+webservice.panoramio=Open Panoramio map
+webservice.opencachingcom=Open Opencaching.com
 webservice.opencachingcom.lang=nl
 
 # Cardinals for 3d plots
diff --git a/tim/prune/lang/prune-texts_no.properties b/tim/prune/lang/prune-texts_no.properties
new file mode 100644
index 0000000..2ad0780
--- /dev/null
+++ b/tim/prune/lang/prune-texts_no.properties
@@ -0,0 +1,142 @@
+# Text entries for the GpsPrune application
+# Norwegian entries
+
+# Menu entries
+menu.file=Fil
+menu.file.addphotos=Legg til bilder
+menu.file.recentfiles=Nyeste filer
+menu.file.save=Lagre som tekst
+menu.file.exit=Avslutt
+menu.online=
+menu.track=
+menu.track.undo=Angre
+menu.track.clearundo=Nullstill angreliste
+menu.track.markrectangle=Marker punkter i rektangel
+function.deletemarked=Slett markerte punkter
+menu.range=Intervall
+menu.range.all=Velg alle
+menu.range.none=Velg ingen
+menu.range.start=Velg intervallets startpunkt
+menu.range.end=Velg intervallets slutpunkt
+menu.range.average=Nytt punkt midt i intervallet
+menu.range.reverse=Reverser intervallet
+menu.range.mergetracksegments=Sl\u00e5 sammen delintervaller
+menu.range.cutandmove=Kutt av og flytt valgt intervall
+menu.point=Punkt
+menu.point.editpoint=Rediger punkt
+menu.point.deletepoint=Slett punkt
+menu.photo=Bilde
+menu.photo.saveexif=Lagre Exif-data
+menu.audio=Lyd
+menu.view=Visning
+menu.view.showsidebars=Vis sidefelter
+menu.view.browser=Vis kart i nettleser
+menu.view.browser.google=Google kart
+menu.view.browser.openstreetmap=Openstreetmap
+menu.view.browser.mapquest=Mapquest
+menu.view.browser.yahoo=Yahoo maps
+menu.view.browser.bing=Bing maps
+menu.settings=Innstillinger
+menu.settings.onlinemode=Last kart fra Internet
+menu.settings.autosave=Lagre innstillinger automatisk ved avslutning
+menu.help=Hjelp
+# Popup menu for map
+menu.map.zoomin=Zoom inn
+menu.map.zoomout=Zoom ut
+menu.map.zoomfull=Zoom til hele sporet
+menu.map.newpoint=Lag nytt punkt
+menu.map.drawpoints=Lag en serie punkter
+menu.map.connect=Knyt sporpunkter til linje
+menu.map.autopan=Autosentrering
+menu.map.showmap=Vis kart
+menu.map.showscalebar=Vis m\u00e5lestokk
+menu.map.editmode=Redigeringsmodus
+
+# Alt keys for menus
+altkey.menu.file=F
+altkey.menu.online=
+altkey.menu.track=S
+altkey.menu.range=I
+altkey.menu.point=P
+altkey.menu.view=V
+altkey.menu.photo=B
+altkey.menu.audio=L
+altkey.menu.settings=n
+altkey.menu.help=H
+
+# Ctrl shortcuts for menu items
+shortcut.menu.file.open=\u00c5
+shortcut.menu.file.load=
+shortcut.menu.file.save=L
+shortcut.menu.track.undo=g
+shortcut.menu.edit.compress=K
+shortcut.menu.range.all=A
+shortcut.menu.help.help=H
+
+# Functions
+function.open=\u00c5pne fil
+function.importwithgpsbabel=Importer fil med GPSBabel
+function.loadfromgps=Hent data fra GPS
+function.sendtogps=Overf\u00f8r data til GPS
+function.exportkml=Eksporter KML
+function.exportgpx=Eksporter GPX
+function.exportpov=Eksporter POV
+function.exportsvg=Eksporter SVG
+function.exportimage=
+function.editwaypointname=Endre waypoint-navn
+function.compress=Komprimer spor
+function.deleterange=Fjern valgt intervall
+function.croptrack=Beskj\u00e6r sporet
+function.interpolate=Interpoler punkter
+function.deletebydate=
+function.addtimeoffset=Legg til tidsinkrement
+function.addaltitudeoffset=Legg til h\u00f8ideinkrement
+function.rearrangewaypoints=
+function.convertnamestotimes=Les waypoint-navn som tidspunkter
+function.deletefieldvalues=Slett feltets verdier
+function.findwaypoint=Finn waypoint
+function.pastecoordinates=Legg til nye koordinater
+function.charts=Grafer
+function.show3d=3-D visning
+function.distances=Avstander
+function.fullrangedetails=Vis alle detaljer
+function.estimatetime=
+function.learnestimationparams=
+function.setmapbg=Velg grunnlagskart
+function.setpaths=Angi plassering av programmer
+function.selectsegment=
+function.splitsegments=
+function.sewsegments=
+function.getgpsies=Vis spor fra gpsies.com
+function.uploadgpsies=Last opp spor til gpsies.com
+function.lookupsrtm=Hent h\u00f8yde fra SRTM
+function.downloadsrtm=
+function.getwikipedia=Vis Wikipedia info for omegn
+function.searchwikipedianames=S\u00f8k Wikipedia
+function.searchopencachingde=
+function.downloadosm=Last ned OSM data for omr\u00e5det
+function.duplicatepoint=Dupliser punkt
+function.setcolours=Velg farger
+function.setlinewidth=Velg linjebredde
+function.setlanguage=Velg spr\u00e5k
+function.connecttopoint=Knytt til punkt
+function.disconnectfrompoint=Koble fra punkt
+function.removephoto=Fjern foto
+function.correlatephotos=Relater alle bilder
+function.rearrangephotos=Omarranger bilder
+function.rotatephotoleft=Roter bilde mot venstre
+function.rotatephotoright=Roter bilde mot h\u00f8yre
+function.photopopup=Vis bilde popup
+function.ignoreexifthumb=Ignorer exif miniatyrbilder
+function.loadaudio=Legg til lydklipp
+function.removeaudio=Fjern lydklipp
+function.correlateaudios=Relater alle lydklipp
+function.playaudio=Spill lydklipp
+function.stopaudio=Avbryt lydklipp
+function.help=Hjelp
+function.showkeys=Vis hurtigtaster
+function.about=Om GpsPrune
+function.checkversion=Sjekk etter nye versjoner
+function.saveconfig=Lagre innstillinger
+function.diskcache=Om lagring av kart
+function.managetilecache=H\u00e5ndter kart-flis-lager
diff --git a/tim/prune/lang/prune-texts_pl.properties b/tim/prune/lang/prune-texts_pl.properties
index acf3fe0..a2302fe 100644
--- a/tim/prune/lang/prune-texts_pl.properties
+++ b/tim/prune/lang/prune-texts_pl.properties
@@ -12,7 +12,7 @@ menu.track=\u015acie\u017cka
 menu.track.undo=Cofnij
 menu.track.clearundo=Wyczy\u015b\u0107 list\u0119 zmian
 menu.track.markrectangle=Zaznaczenie prostok\u0105tne
-menu.track.deletemarked=Usu\u0144 zaznaczone punkty
+function.deletemarked=Usu\u0144 zaznaczone punkty
 menu.range=Zakres
 menu.range.all=Zaznacz wszystko
 menu.range.none=Usu\u0144 zaznaczenie
@@ -588,6 +588,7 @@ dialog.deletebydate.column.keep=Zostaw
 dialog.deletebydate.column.delete=Usu\u0144
 dialog.setaltitudetolerance.text.metres=Limit (w metrach) poni\u017cej kt\u00f3rego, ma\u0142e spadki wzniosy b\u0119d\u0105 ignorowane
 dialog.setaltitudetolerance.text.feet=Limit (w stopach) poni\u017cej kt\u00f3rego, ma\u0142e spadki wzniosy b\u0119d\u0105 ignorowane
+dialog.autoplay.duration=Czas trwania (sek)
 
 # 3d window
 dialog.3d.title=GpsPrune widok tr\u00f3jwymiarowy
@@ -753,6 +754,7 @@ fieldname.duration=Czas trwania
 fieldname.speed=Pr\u0119dko\u015b\u0107
 fieldname.verticalspeed=Pr\u0119dko\u015b\u0107 pionowa
 fieldname.description=Opis
+fieldname.mediafilename=Nazwa pliku
 
 # Measurement units
 units.original=Oryginalny
diff --git a/tim/prune/lang/prune-texts_pt.properties b/tim/prune/lang/prune-texts_pt.properties
index 6319688..8737cd3 100644
--- a/tim/prune/lang/prune-texts_pt.properties
+++ b/tim/prune/lang/prune-texts_pt.properties
@@ -12,7 +12,7 @@ menu.track=Rota
 menu.track.undo=Desfazer
 menu.track.clearundo=Limpar lista de desfazer
 menu.track.markrectangle=Marcar pontos no ret\u00e2ngulo
-menu.track.deletemarked=Remover pontos marcados
+function.deletemarked=Remover pontos marcados
 function.rearrangewaypoints=Rearrumar pontos
 menu.range=Intervalo
 menu.range.all=Selecionar tudo
@@ -113,6 +113,8 @@ function.lookupsrtm=Obter altitudes a partir do SRTM
 function.downloadsrtm=Baixar arquivos SRTM
 function.getwikipedia=Obter artigos da Wikip\u00e9dia das redondezas
 function.searchwikipedianames=Procurar na Wikip\u00e9dia por nome
+function.searchopencachingde=Procurar na OpenCaching.de
+function.mapillary=Procurar na Mapillary.com
 function.downloadosm=Baixar dados OSM para a \u00e1rea
 function.duplicatepoint=Duplicar ponto
 function.setcolours=Definir cores
@@ -393,7 +395,7 @@ 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.pointlaterphoto=Ponto mais recente que a foto
-dialog.correlate.options.audiolater=\u00e1udio mais recente que o ponto
+dialog.correlate.options.audiolater=\u00c1udio mais recente que o ponto
 dialog.correlate.options.pointlateraudio=Ponto mais recente que a \u00e1udio
 dialog.correlate.options.limitspanel=Limites de correla\u00e7\u00e3o
 dialog.correlate.options.notimelimit=Nenhum limite de tempo
@@ -565,6 +567,13 @@ dialog.weather.wind=Vento
 dialog.weather.temp=Temp
 dialog.weather.humidity=Umidade
 dialog.weather.creditnotice=Estes dados foram disponibilizados por openweathermap.org. A p\u00e1gina Web possui mais detalhes.
+dialog.deletebydate.column.keep=Guardar
+dialog.deletebydate.column.delete=Remover
+dialog.autoplay.duration=Dura\u00e7\u00e3o (seg)
+dialog.autoplay.usetimestamps=Usar data-hora
+dialog.autoplay.rewind=Rebobinar
+dialog.autoplay.pause=Suspender
+dialog.autoplay.play=Tocar
 
 # 3d window
 dialog.3d.title=Vista 3D do GpsPrune
@@ -719,6 +728,7 @@ fieldname.longitude=Longitude
 fieldname.altitude=Altura
 fieldname.timestamp=Tempo
 fieldname.time=Tempo
+fieldname.date=Data
 fieldname.waypointname=Nome
 fieldname.waypointtype=Tipo
 fieldname.newsegment=Segmento
@@ -729,6 +739,7 @@ fieldname.duration=Dura\u00e7\u00e3o
 fieldname.speed=Velocidade
 fieldname.verticalspeed=Velocidade vertical
 fieldname.description=Descri\u00e7\u00e3o
+fieldname.mediafilename=Arquivo
 
 # Measurement units
 units.original=Original
@@ -772,6 +783,11 @@ logic.or=ou
 url.googlemaps=maps.google.com.br
 wikipedia.lang=pt
 openweathermap.lang=pt
+webservice.peakfinder=Abrir Peakfinder.org
+webservice.geohack=Abrir p\u00e1gina Geohack
+webservice.panoramio=Abrir mapa do Panoramio
+webservice.opencachingcom=Abrir Opencaching.com
+webservice.opencachingcom.lang=pt
 
 # Cardinals for 3d plots
 cardinal.n=N
diff --git a/tim/prune/lang/prune-texts_ro.properties b/tim/prune/lang/prune-texts_ro.properties
index e311430..0a1f020 100644
--- a/tim/prune/lang/prune-texts_ro.properties
+++ b/tim/prune/lang/prune-texts_ro.properties
@@ -1,46 +1,51 @@
 # Text entries for the GpsPrune application
-# Romanian entries as extra
+# Romanian entries thanks to Rothermographer, Oana and Cristian
 
 # Menu entries
 menu.file=Fi\u015fier
 menu.file.addphotos=Adaug\u0103 foto
 menu.file.recentfiles=Fi\u015fiere recente
-menu.file.save=Salvare
+menu.file.save=Salveaz\u0103 ca fi\u0219ier text
 menu.file.exit=Ie\u015fire
 menu.online=Internet
 menu.track=Traseu
 menu.track.undo=Anulare
-menu.track.clearundo=\u015etergere lista de anulari
-menu.track.deletemarked=\u015etergere puncte marcate
+menu.track.clearundo=\u015eterge lista de anul\u0103ri
+menu.track.markrectangle=Selecteaz\u0103 puncte din p\u0103trat
+function.deletemarked=\u015eterge punctele marcate
 menu.range=Interval
-menu.range.all=Selectare toate
+menu.range.all=Selecteaz\u0103 toate punctele
 menu.range.none=Nu selecta niciun punct
-menu.range.start=Seteaza inceputul selectiei
-menu.range.end=Seteaza sfarsitul selectiei
-menu.range.average=Mediere selec\u0163ie
-menu.range.reverse=Inversare selec\u0163ie
-menu.range.mergetracksegments=Unire segmente traseu
-menu.range.cutandmove=Taiere si mutare selec\u0163ie
+menu.range.start=Seteaz\u0103 inceputul intervalului
+menu.range.end=Seteaz\u0103 sfarsitul intervalului
+menu.range.average=Mediaz\u0103 selec\u0163ia
+menu.range.reverse=Inverseaz\u0103 intervalul
+menu.range.mergetracksegments=Une\u0219te segmentele traseului
+menu.range.cutandmove=Taie \u0219i mut\u0103 intervalul
 menu.point=Punct
-menu.point.editpoint=Editare punct
-menu.point.deletepoint=\u015etergere punct
+menu.point.editpoint=Editeaz\u0103 punct
+menu.point.deletepoint=\u015eterge punct
 menu.photo=Foto
-menu.photo.saveexif=Salveaza la Exif
+menu.photo.saveexif=Salveaz\u0103 \u00een Exif
 menu.audio=Audio
 menu.view=Vizualizare
-menu.view.browser=Harta in browser
-menu.view.browser.google=Harti Google
+menu.view.showsidebars=Afi\u0219eaz\u0103 panourile laterale
+menu.view.browser=Harta \u00een browser
+menu.view.browser.google=Harta Google
 menu.view.browser.openstreetmap=Openstreetmap
 menu.view.browser.mapquest=Mapquest
-menu.view.browser.yahoo=Harti Yahoo
-menu.view.browser.bing=Harti Bing
+menu.view.browser.yahoo=Harta Yahoo
+menu.view.browser.bing=Harta Bing
 menu.settings=Set\u0103ri
 menu.settings.onlinemode=\u00cencarc\u0103 h\u0103r\u021bi
+menu.settings.antialias=Folose\u0219te antialiasing
+menu.settings.autosave=Salveaz\u0103 set\u0103rile automat la ie\u0219ire
 menu.help=Ajutor
+
 # Popup menu for map
 menu.map.zoomin=Apropie
-menu.map.zoomout=Departeaza
-menu.map.zoomfull=Departeaza la maxim
+menu.map.zoomout=Dep\u0103rteaz\u0103
+menu.map.zoomfull=Dep\u0103rteaz\u0103 la maxim
 menu.map.newpoint=Creaz\u0103 punct
 menu.map.drawpoints=Creaz\u0103 serie de puncte
 menu.map.connect=Traseaz\u0103 linii \u00eentre puncte
@@ -71,87 +76,116 @@ shortcut.menu.range.all=T
 shortcut.menu.help.help=A
 
 # Functions
-function.open=Deschidere fi\u015fier
-function.importwithgpsbabel=Importare fi\u015fier cu GPSBabel
+function.open=Deschide fi\u015fier
+function.importwithgpsbabel=Import\u0103 fi\u015fier cu GPSBabel
 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.exportsvg=Export\u0103 \u00eentr-un fi\u015fier SVG
+function.exportkml=Export\u0103 \u00een fi\u015fier KML
+function.exportgpx=Export\u0103 \u00een fi\u015fier GPX
+function.exportpov=Export\u0103 \u00een fi\u015fier POV
+function.exportsvg=Export\u0103 \u00een fi\u015fier SVG
 function.exportimage=Export\u0103 imagine
-function.editwaypointname=Editare nume waypoint
-function.compress=Comprima traseu
-function.deleterange=\u015etergere gama
-function.interpolate=Interpolare
+function.editwaypointname=Editeaz\u0103 nume waypoint
+function.compress=Comprim\u0103 traseu
+function.marklifts=Marcheaz\u0103 urc\u0103rile pe instala\u021bii
+function.deleterange=\u015eterge intervalul
+function.croptrack=Decupeaz\u0103 traseul
+function.interpolate=Interpoleaz\u0103
+function.deletebydate=\u0218terge puncte pe criterii de timp
 function.addtimeoffset=Adaug\u0103 decalaj timp
 function.addaltitudeoffset=Adaug\u0103 decalaj altitudine
-function.rearrangewaypoints=Rearanjare waypoint
-function.findwaypoint=Gasire waypoint
+function.rearrangewaypoints=Rearanjeaz\u0103 waypoint
+function.convertnamestotimes=Converte\u0219te numele waypoint-urilor \u00een timpi
+function.deletefieldvalues=\u0218terge valorile c\u00e2mpurilor
+function.findwaypoint=G\u0103se\u0219te waypoint
+function.pastecoordinates=Introdu coordonate noi
 function.charts=Grafice
-function.show3d=Vizualizare arborescenta
+function.show3d=Vizualizare 3D
 function.distances=Distan\u0163e
-function.fullrangedetails=Informa\u0163ie complet
-function.getgpsies=\u00cencarc\u0103 trassee Gpsies
-function.uploadgpsies=Trimite date spre Gpsies
-function.downloadsrtm=\u00cencarc\u0103 date SRTM
+function.fullrangedetails=Informa\u0163ie complet\u0103
 function.estimatetime=Estimare durat\u0103
-function.setmapbg=Seteaza harta
-function.selectsegment=Selectare segment curent
-function.setcolours=Selectare culorile
-function.setlanguage=Selectare limba
-function.connecttopoint=Conecteaza la punct
-function.disconnectfrompoint=Deconecteaza de la punct
-function.removephoto=Elimina foto
-function.correlatephotos=Corelare fotografii
-function.rearrangephotos=Rearanjare fotografii
-function.rotatephotoleft=Roti foto la st\u00e2nga
-function.rotatephotoright=Roti foto la dreapta
+function.learnestimationparams=\u00cenva\u021b\u0103 parametri de estimare timpi
+function.autoplay=Parcurge traseu
+function.setmapbg=Seteaz\u0103 fundalul h\u0103r\u021bii
+function.setpaths=Seteaz\u0103 calea c\u0103tre aplica\u021bii
+function.selectsegment=Selecteaz\u0103 segment curent
+function.splitsegments=Divizeaz\u0103 traseul \u00een segmente
+function.sewsegments=Combin\u0103 segmentele traseului
+function.getgpsies=\u00cencarc\u0103 trasee Gpsies
+function.uploadgpsies=Trimite date spre Gpsies
+function.lookupsrtm=Descarc\u0103 date SRTM \u00een cache
+function.downloadsrtm=Descarc\u0103 date SRTM
+function.getwikipedia=Caut\u0103 articole Wikipedia din proximitate
+function.searchwikipedianames=Caut\u0103 Wikipedia dup\u0103 nume
+function.searchopencachingde=Caut\u0103 OpenCaching.de
+function.mapillary=Caut\u0103 fotografii \u00een Mapillary
+function.downloadosm=Descarc\u0103 date OSM pentru zona traseului
+function.duplicatepoint=Duplic\u0103 punctul
+function.setcolours=Seteaz\u0103 culori
+function.setlinewidth=Seteaz\u0103 grosime linie
+function.setlanguage=Seteaz\u0103 limb\u0103
+function.connecttopoint=Conecteaz\u0103 la punct
+function.disconnectfrompoint=Deconecteaz\u0103 de la punct
+function.removephoto=Elimin\u0103 foto
+function.correlatephotos=Coreleaz\u0103 fotografii
+function.rearrangephotos=Rearanjeaz\u0103 fotografii
+function.rotatephotoleft=Rote\u0219te foto la st\u00e2nga
+function.rotatephotoright=Rote\u0219te foto la dreapta
 function.photopopup=Arat\u0103 foto
+function.ignoreexifthumb=Ignor\u0103 icoana EXIF
 function.loadaudio=Adaug\u0103 audio
-function.removeaudio=Elimina audio
-function.playaudio=Redare audio
+function.removeaudio=Elimin\u0103 audio
+function.correlateaudios=Coreleaz\u0103 clipuri audio
+function.playaudio=Red\u0103 clip audio
+function.stopaudio=Opre\u0219te clip audio
 function.help=Ajutor
-function.showkeys=Arat\u0103 tastele scurt\u0103turi
+function.showkeys=Arat\u0103 scurt\u0103turi
 function.about=Despre GpsPrune
-function.checkversion=Verific\u0103 pentru o versiune noua
+function.checkversion=Verific\u0103 versiune noua
 function.saveconfig=Salvare set\u0103ri
 function.diskcache=Salvare harti
+function.managetilecache=Administreaz\u0103 imaginile salvate
 function.getweatherforecast=Prognoz\u0103 meteo
+function.setaltitudetolerance=Alege toleran\u021ba varia\u021biei altitudinii
 
 # Dialogs
 dialog.exit.confirm.title=Ie\u015fire din programul GpsPrune
-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.exit.confirm.text=Datele dumneavoastra nu sunt salvate.\nSunte\u0163i sigur c\u0103 dori\u0163i s\u0103 ie\u015fiti?
+dialog.openappend.title=Adaug\u0103 la datele existente
+dialog.openappend.text=Adaug\u0103 la datele deja incarcate?
 dialog.deletepoint.title=\u015eterge Punct
 dialog.deletepoint.deletephoto=\u015eterg fotografiile atasate acestui punct?
 dialog.deletephoto.title=\u015eterge foto
 dialog.deletephoto.deletepoint=\u015eterg punct atasat acestei fotografii?
 dialog.deleteaudio.deletepoint=\u015eterg punct atasat acestei audio?
-dialog.openoptions.title=Optiuni deschidere
-dialog.load.table.field=Cimp
+dialog.openoptions.title=Op\u021biuni deschidere
+dialog.openoptions.filesnippet=Extras din fi\u0219ier
+dialog.load.table.field=C\u00e2mp
 dialog.load.table.datatype=Tip data
 dialog.load.table.description=Descriere
-dialog.delimiter.label=Delimitator cimp
-dialog.delimiter.comma=Virgula ,
+dialog.delimiter.label=Delimitator c\u00e2mp
+dialog.delimiter.comma=Virgul\u0103 ,
 dialog.delimiter.tab=Tab
-dialog.delimiter.space=Spatiu
-dialog.delimiter.semicolon=Punct si virgula :
-dialog.delimiter.other=Alte
-dialog.openoptions.deliminfo.records=inregistrari, cu
-dialog.openoptions.deliminfo.fields=cimpuri
-dialog.openoptions.deliminfo.norecords=Nu sunt inregistrari
-dialog.openoptions.altitudeunits=Unit\u0103\u0163i de altitudini
-dialog.openoptions.speedunits=Unit\u0103\u0163i de viteza
-dialog.openoptions.vertspeedunits=Unit\u0103\u0163i de viteza vertical\u0103
+dialog.delimiter.space=Spa\u021biu
+dialog.delimiter.semicolon=Punct \u0219i virgul\u0103 ;
+dialog.delimiter.other=Altele
+dialog.openoptions.deliminfo.records=\u00eenregistr\u0103ri, cu
+dialog.openoptions.deliminfo.fields=c\u00e2mpuri
+dialog.openoptions.deliminfo.norecords=Nu sunt \u00eenregistr\u0103ri
+dialog.openoptions.altitudeunits=Unit\u0103\u0163i de altitudine
+dialog.openoptions.speedunits=Unit\u0103\u0163i de vitez\u0103
+dialog.openoptions.vertspeedunits=Unit\u0103\u0163i de vitez\u0103 vertical\u0103
+dialog.openoptions.vspeed.positiveup=Vitezele pozitive \u00een sus
+dialog.openoptions.vspeed.positivedown=Vitezele pozitive \u00een jos
+dialog.open.contentsdoubled=Acest fi\u0219ier con\u021bine dou\u0103 copii ale aceluia\u0219i punct,\nonce ca waypoint-uri \u0219i ca puncte de traseu.
+dialog.selecttracks.intro=Alege\u021bi traseul(traseele) pentru \u00eenc\u0103rcare.
 dialog.selecttracks.noname=F\u0103r\u0103 nume
-dialog.jpegload.subdirectories=Include subdirectori
-dialog.jpegload.loadjpegswithoutcoords=Include fotografii fara coordonate
+dialog.jpegload.subdirectories=Include subdirectoarele
+dialog.jpegload.loadjpegswithoutcoords=Include fotografii f\u0103r\u0103 coordonate
 dialog.jpegload.loadjpegsoutsidearea=Include fotografii din afara zonei curente
 dialog.jpegload.progress.title=\u00cenc\u0103rcare fotografii
-dialog.jpegload.progress=Va rog sa asteptati, caut fotografiile
-dialog.gpsload.nogpsbabel=Nu gasesc programul gpsbabel. Continui ?
+dialog.jpegload.progress=Va rog s\u0103 a\u0219tepta\u021bi, caut fotografiile
+dialog.gpsload.nogpsbabel=Nu g\u0103sesc programul gpsbabel. Continui?
 dialog.gpsload.device=Nume dispozitiv
 dialog.gpsload.format=Format
 dialog.gpsload.getwaypoints=\u00cencarc\u0103 waypoints
@@ -165,128 +199,264 @@ dialog.addfilter.title=Adaug\u0103 filtru
 dialog.gpsbabel.filter.discard=Arunc\u0103
 dialog.gpsbabel.filter.simplify=Simplific\u0103
 dialog.gpsbabel.filter.distance=Distan\u0163\u0103
-dialog.gpsbabel.filter.interpolate=Interpolare
+dialog.gpsbabel.filter.interpolate=Interpoleaz\u0103
 dialog.gpsbabel.filter.discard.intro=Arunc\u0103 puncte dac\u0103
 dialog.gpsbabel.filter.discard.hdop=Hdop >
 dialog.gpsbabel.filter.discard.vdop=Vdop >
 dialog.gpsbabel.filter.discard.numsats=Num\u0103r de sateli\u0163i <
+dialog.gpsbabel.filter.discard.nofix=Punctul nu are fix GPS
+dialog.gpsbabel.filter.discard.unknownfix=Punctul are fix GPS necunoscut
+dialog.gpsbabel.filter.simplify.intro=\u0218terge punctele dac\u0103
 dialog.gpsbabel.filter.simplify.maxpoints=Num\u0103r de puncte <
+dialog.gpsbabel.filter.simplify.maxerror=sau erori de distan\u021b\u0103 <
+dialog.gpsbabel.filter.simplify.crosstrack=\u00een lungul traseului
 dialog.gpsbabel.filter.simplify.length=diferen\u0163\u0103 de lungime
+dialog.gpsbabel.filter.simplify.relative=relativ la HDOP
+dialog.gpsbabel.filter.distance.intro=\u0218terge punctele dac\u0103 sunt aproape de puncte anterioare
 dialog.gpsbabel.filter.distance.distance=Dac\u0103 distan\u0163\u0103 <
 dialog.gpsbabel.filter.distance.time=\u0219i diferen\u0163\u0103 de timp <
-dialog.gpsbabel.filter.interpolate.distance=Dac\u0103 distan\u0163\u0103 >
-dialog.gpsbabel.filter.interpolate.time=sau diferen\u0163\u0103 de timp >
+dialog.gpsbabel.filter.interpolate.intro=Adaug\u0103 puncte \u00eentre punctele existente
+dialog.gpsbabel.filter.interpolate.distance=Dac\u0103 distan\u0163a >
+dialog.gpsbabel.filter.interpolate.time=sau diferen\u0163a de timp >
 dialog.saveoptions.title=Salvare fi\u015fier
-dialog.save.table.field=Cimp
-dialog.save.table.hasdata=Date
+dialog.save.fieldstosave=C\u00e2mpuri ce urmeaz\u0103 a fi salvate
+dialog.save.table.field=C\u00e2mp
+dialog.save.table.hasdata=Con\u021bine date
 dialog.save.table.save=Salvare
+dialog.save.headerrow=Salveaza cap tabel
 dialog.save.coordinateunits=Format coordonate
-dialog.save.altitudeunits=Unit\u0103\u0163i de altitudini
+dialog.save.altitudeunits=Unit\u0103\u0163i de altitudine
 dialog.save.timestampformat=Format de timp
 dialog.save.overwrite.title=Fi\u015fierul exist\u0103
 dialog.save.overwrite.text=Fi\u015fierul exist\u0103. \u00cel suprascriu?
+dialog.save.notypesselected=Niciun tip de punct nu a fost selectat
 dialog.exportkml.text=Titlu
-dialog.exportkml.imagesize=Dimensiune imaginii
+dialog.exportkml.altitude=Altitudini absolute (pentru avia\u021bie)
+dialog.exportkml.kmz=Comprim\u0103 pentru a produce fi\u0219ier KMZ
+dialog.exportkml.exportimages=Export\u0103 icoane pentru imagini \u00een KMZ
+dialog.exportkml.imagesize=Dimensiune icoane imagini \u00een KMZ
 dialog.exportkml.trackcolour=Culoarea liniei
+dialog.exportkml.standardkml=KML standard
+dialog.exportkml.extendedkml=KML extins cu date cronologice
 dialog.exportgpx.name=Nume
 dialog.exportgpx.desc=Descriere
+dialog.exportgpx.includetimestamps=Include date cronologice
+dialog.exportgpx.copysource=Copiaz\u0103 sursa xml
 dialog.exportgpx.encoding=Codare
 dialog.exportgpx.encoding.system=Sistem
 dialog.exportgpx.encoding.utf8=UTF-8
+dialog.exportpov.text=Introduce\u021bi parametrii pentru export POV
 dialog.exportpov.font=Fontul
 dialog.exportpov.camerax=Vedere X
 dialog.exportpov.cameray=Vedere Y
 dialog.exportpov.cameraz=Vedere Z
 dialog.exportpov.modelstyle=Stilul
+dialog.exportpov.ballsandsticks=Bile \u0219i be\u021be
+dialog.exportpov.tubesandwalls=Tuburi \u0219i pere\u021bi
+dialog.3d.warningtracksize=Acest traseu are un num\u0103r mare de puncte pe care Java3D ar putea s\u0103 nu fie capabil s\u0103-l afi\u0219eze. Sigur dori\u021bi s\u0103 continua\u021bi?
 dialog.3d.useterrain=Arat\u0103 teren
-dialog.3d.terraingridsize=Dimensiune a grilei
-dialog.exportpov.baseimage=Imagine cartografice
-dialog.baseimage.title=Imagine cartografice
+dialog.3d.terraingridsize=Dimensiunea grilei
+dialog.exportpov.baseimage=Imagine cartografic\u0103
+dialog.exportpov.cannotmakebaseimage=Imaginea cartografic\u0103 nu poate fi scris\u0103
+dialog.baseimage.title=Imagine cartografic\u0103
+dialog.baseimage.useimage=Folose\u0219te imaginea
+dialog.baseimage.mapsource=Sursa h\u0103r\u021bii
 dialog.baseimage.zoom=Nivel de zoom
 dialog.baseimage.incomplete=Imagine incomplet\u0103
-dialog.baseimage.tiles=Tigla
+dialog.baseimage.tiles=\u021aigle
+dialog.baseimage.size=Dimensiunea imaginii
+dialog.exportsvg.text=Alege\u021bi parametrii pentru export SVG
 dialog.exportsvg.phi=Azimut \u03d5
 dialog.exportsvg.theta=\u00cenclina\u0163ie \u03b8
+dialog.exportsvg.gradients=Folose\u0219te gradien\u021bi pentru umbrire
+dialog.exportimage.noimagepossible=Imaginile hart\u0103 trebuie sa fie salvate \u00een cache pe disc pentru a putea fi folosite la export.
+dialog.exportimage.drawtrack=Deseneaz\u0103 traseu pe hart\u0103
+dialog.exportimage.drawtrackpoints=Deseneaz\u0103 punctele traseului
+dialog.exportimage.textscalepercent=Factor de scalare a textului (%)
+dialog.pointtype.desc=Salveaz\u0103 urm\u0103toarele tipuri de puncte:
 dialog.pointtype.track=Puncte de traseu
-dialog.pointtype.waypoint=Waypoints
+dialog.pointtype.waypoint=Waypoint-uri
 dialog.pointtype.photo=Puncte foto
 dialog.pointtype.audio=Puncte audio
-dialog.pointtype.selection=Doar interval
-dialog.undo.title=Anulare
-dialog.pointedit.title=Editare punct
-dialog.pointedit.intro=V\u0103 rog selecta\u0163i r\u00e2ndul care va fi editat
-dialog.pointedit.table.field=Cimp
+dialog.pointtype.selection=Doar intervalul selectat
+dialog.confirmreversetrack.title=Confirm\u0103 inversarea
+dialog.confirmreversetrack.text=Acest traseu con\u021bine informa\u021bii cronologice a c\u0103ror ordine va fi incorect\u0103 dup\u0103 inversare.\nSigur dori\u021bi s\u0103 inversa\u021bi selec\u021bia?
+dialog.confirmcutandmove.title=Confirm\u0103 t\u0103irea \u0219i mutarea
+dialog.confirmcutandmove.text=Acest traseu con\u021bine informa\u021bii cronologice a c\u0103ror ordine va fi incorect\u0103 dup\u0103 mutare.\n Sigur dori\u021bi mutarea sec\u021biunii?
+dialog.interpolate.parameter.text=Num\u0103rul de puncte de inserat \u00eentre fiecare pereche de puncte
+dialog.interpolate.betweenwaypoints=Interpolez \u00eentre waypoint-uri?
+dialog.undo.title=Anuleaz\u0103
+dialog.undo.pretext=Selecta\u021bi opera\u021biile ce vor fi anulate
+dialog.undo.none.title=Nu se poate anula
+dialog.undo.none.text=Nu exist\u0103 opera\u021bii pentru anulare!
+dialog.clearundo.title=\u0218terge lista de anul\u0103ri
+dialog.clearundo.text=Sigur vre\u021bi s\u0103 \u0219terge\u021bi lista de anul\u0103ri?\nToat\u0103 \u00eenforma\u021bia de anulare va fi pierdut\u0103!
+dialog.pointedit.title=Editeaz\u0103 punct
+dialog.pointedit.intro=Selecta\u0163i r\u00e2ndul care va fi editat
+dialog.pointedit.table.field=C\u00e2mp
+dialog.pointedit.nofield=Niciun c\u00e2mp selectat
 dialog.pointedit.table.value=Valoare
 dialog.pointnameedit.name=Nume de waypoint
 dialog.pointnameedit.uppercase=Litere MARI
 dialog.pointnameedit.lowercase=Litere mici
+dialog.pointnameedit.titlecase=Prima Liter\u0103 Mare
+dialog.addtimeoffset.add=Adaug\u0103 timp
+dialog.addtimeoffset.subtract=Scade timp
 dialog.addtimeoffset.days=Zile
 dialog.addtimeoffset.hours=Ore
 dialog.addtimeoffset.minutes=Minute
+dialog.addtimeoffset.notimestamps=Nu poate fi ad\u0103ugat un decalaj de timp pentru c\u0103 selec\u021bia nu con\u021bine date cronologice
+dialog.findwaypoint.intro=Introduce\u021bi o parte a numelui waypoint-ului
 dialog.findwaypoint.search=C\u0103utare
+dialog.saveexif.title=Salveaz\u0103 Exif
+dialog.saveexif.intro=Selecteaz\u0103 fotografiile ce  urmeaz\u0103 a fi salvate folosind bifele
+dialog.saveexif.nothingtosave=Coordonatele sunte neschimbate, nu e nimic de salvat
+dialog.saveexif.noexiftool=Aplica\u021bia exiftool nu a fost g\u0103sit\u0103. Continui?
 dialog.saveexif.table.photoname=Nume
-dialog.saveexif.title=Salvare Exif
 dialog.saveexif.table.status=Stare
-dialog.saveexif.table.save=Salveaza
+dialog.saveexif.table.save=Salveaz\u0103
 dialog.saveexif.photostatus.connected=Conectat
 dialog.saveexif.photostatus.disconnected=Deconectat
 dialog.saveexif.photostatus.modified=Modificat
 dialog.saveexif.overwrite=Suprascrie fi\u015fiere
+dialog.saveexif.force=Ignor\u0103 erorile minore
 dialog.charts.xaxis=Axa X
 dialog.charts.yaxis=Axa Y
 dialog.charts.output=Rezultat
+dialog.charts.screen=Rezultatul pe ecran
+dialog.charts.svg=Rezultatul \u00een fi\u0219ier SVG
 dialog.charts.svgwidth=L\u0103\u021bime SVG
 dialog.charts.svgheight=\u00cen\u0103l\u021bime SVG
-dialog.distances.column.from=De punct
+dialog.charts.needaltitudeortimes=Traseul trebuie s\u0103 con\u021bina altitudini sau date cronologice pentru a crea grafice
+dialog.charts.gnuplotnotfound=Aplica\u021bia gnuplot nu a fost g\u0103sit\u0103 la calea dat\u0103
+dialog.distances.intro=Distan\u021be \u00een linie dreapt\u0103 \u00eentre puncte
+dialog.distances.column.from=De la punct
 dialog.distances.column.to=Spre punct
 dialog.distances.currentpoint=Punct curent
+dialog.distances.toofewpoints=Aceast\u0103 func\u021bie are nevoie de waypoint-uri pentru a calcula distan\u021ba dintre ele
+dialog.fullrangedetails.intro=Detalii pentru invervalul selectat
+dialog.fullrangedetails.coltotal=Cu tot cu pauze
+dialog.fullrangedetails.colsegments=F\u0103r\u0103 pauze
 dialog.estimatetime.details=Detalii
-dialog.estimatetime.parameters=Parametrii
+dialog.estimatetime.gentle=Domol
+dialog.estimatetime.steep=Abrupt
+dialog.estimatetime.climb=Urcare
+dialog.estimatetime.descent=Cobor\u00e2re
+dialog.estimatetime.parameters=Parametri
 dialog.estimatetime.parameters.timefor=Durata pentru
 dialog.estimatetime.results=Rezultate
 dialog.estimatetime.results.estimatedtime=Durata estimat\u0103
 dialog.estimatetime.results.actualtime=Durata (measured)
-dialog.learnestimationparams.averageerror=Eroare estimat
-dialog.learnestimationparams.combinedresults=Rezultate combinat
+dialog.estimatetime.error.nodistance=Estim\u0103rile de timp necesit\u0103 puncte de traseu conectate, pentru a putea fi calculat\u0103 distan\u021ba
+dialog.estimatetime.error.noaltitudes=Selec\u021bia nu include informa\u021bii de altitudine
+dialog.learnestimationparams.intro=Ace\u0219tia sunt parametrii calcula\u021bi pentru acest traseu
+dialog.learnestimationparams.combine=Ace\u0219ti parametri pot fi combina\u021bi cu valorile curente
+dialog.learnestimationparams.averageerror=Eroare estimat\u0103
+dialog.learnestimationparams.combinedresults=Rezultate combinate
+dialog.learnestimationparams.weight.100pccurrent=P\u0103streaz\u0103 valorile curente
 dialog.learnestimationparams.weight.current=curente
 dialog.learnestimationparams.weight.calculated=calculate
+dialog.learnestimationparams.weight.50pc=Media dintre valorile curente \u0219i cele calculate
+dialog.learnestimationparams.weight.100pccalculated=Folose\u0219te valorile calculate
+dialog.setmapbg.intro=Alege\u021bi una din sursele h\u0103r\u021bii sau ad\u0103uga\u021bi una nou\u0103
+dialog.addmapsource.title=Adaug\u0103 surs\u0103 noua de hart\u0103
 dialog.addmapsource.sourcename=Nume
+dialog.addmapsource.layer1url=URL pentru primul strat
+dialog.addmapsource.layer2url=URL pentru cel de-al doilea strat (op\u021bional)
+dialog.addmapsource.maxzoom=Nivelul de apropiere maxim
 dialog.addmapsource.noname=F\u0103r\u0103 nume
 dialog.gpsies.column.name=Nume
 dialog.gpsies.column.length=Lungime
 dialog.gpsies.description=Descriere
 dialog.gpsies.nodescription=F\u0103r\u0103 descriere
-dialog.gpsies.nonefound=Nu a fost g\u0103sit
+dialog.gpsies.nonefound=Nu a fost g\u0103sit niciun traseu
 dialog.gpsies.username=Gpsies username
 dialog.gpsies.password=Gpsies parol\u0103
 dialog.gpsies.keepprivate=Traseu privat
+dialog.gpsies.confirmopenpage=Deschid pagin\u0103 web pentru traseul \u00eenc\u0103rcat?
 dialog.gpsies.activities=Activit\u0103\u0163i
+dialog.gpsies.activity.trekking=Mers pe munte
+dialog.gpsies.activity.walking=Mers pe jos
+dialog.gpsies.activity.jogging=Alergare
+dialog.gpsies.activity.biking=Biciclet\u0103
+dialog.gpsies.activity.motorbiking=Motociclet\u0103
+dialog.gpsies.activity.snowshoe=Mers cu rachete de z\u0103pad\u0103
+dialog.gpsies.activity.sailing=Navigare
+dialog.gpsies.activity.skating=Role
+dialog.mapillary.nonefound=Nicio fotografie nu a fost g\u0103sit\u0103
 dialog.wikipedia.column.name=Nume
 dialog.wikipedia.column.distance=Distan\u0163\u0103
 dialog.wikipedia.nonefound=Nu a fost g\u0103sit
-dialog.correlate.select.photoname=Nume
-dialog.correlate.select.timediff=Diferenta de timp
+dialog.geocaching.nonefound=Nu a fost g\u0103sit
+dialog.correlate.notimestamps=Corelarea cu fotografiile nu se poate realiza pentru c\u0103 \u00een puncte nu exist\u0103 informa\u021bie cronologic\u0103
+dialog.correlate.nouncorrelatedphotos=Nu exist\u0103 fotografii necorelate. Continui?
+dialog.correlate.nouncorrelatedaudios=Nu exist\u0103 clipuri audio necorelate. Continui?
+dialog.correlate.photoselect.intro=Alege\u021bi una din fotografiile corelate ca referin\u021b\u0103 pentru decalajul de timp
+dialog.correlate.select.photoname=Nume foto
+dialog.correlate.select.timediff=Diferen\u021ba de timp
+dialog.correlate.select.photolater=Foto mai t\u00e2rziu
+dialog.correlate.options.intro=Alege\u021bi op\u021biunile pentru corelare automat\u0103
+dialog.correlate.options.offsetpanel=Decalaj de timp
+dialog.correlate.options.offset=Decalaj
 dialog.correlate.options.offset.hours=ore,
-dialog.correlate.options.offset.minutes=minute,
+dialog.correlate.options.offset.minutes=minute \u0219i
 dialog.correlate.options.offset.seconds=secunde
+dialog.correlate.options.photolater=Foto dup\u0103 punct
+dialog.correlate.options.pointlaterphoto=Punct dup\u0103 foto
+dialog.correlate.options.audiolater=Audio dup\u0103 punct
+dialog.correlate.options.pointlateraudio=Punct dup\u0103 audio
+dialog.correlate.options.limitspanel=Limite corelare
+dialog.correlate.options.notimelimit=F\u0103r\u0103 limit\u0103 de timp
+dialog.correlate.options.timelimit=Limit\u0103 de timp
+dialog.correlate.options.nodistancelimit=F\u0103r\u0103 limit\u0103 de distan\u021b\u0103
+dialog.correlate.options.distancelimit=Limit\u0103 de distan\u021b\u0103
 dialog.correlate.options.correlate=Corelare
-dialog.correlate.timestamp.beginning=\u00cenceptutul
+dialog.correlate.alloutsiderange=Toate elementele sunt \u00een afara intervalului de timp din traseu, deci nu pot fi corelate.\n \u00cencerca\u021bi schimbarea decalajului de timp sau corela\u021bi manual cel pu\u021bin un element.
+dialog.correlate.filetimes=Informa\u021bia cronologic\u0103 din fi\u0219ier arat\u0103:
+dialog.correlate.filetimes2=a clipului audio
+dialog.correlate.correltimes=Pentru corelare folose\u0219te:
+dialog.correlate.timestamp.beginning=\u00cenceputul
 dialog.correlate.timestamp.middle=Mijlocul
 dialog.correlate.timestamp.end=Sf\u00e2r\u015fitul
-dialog.correlate.select.audioname=Nume
+dialog.correlate.audioselect.intro=Alege\u021bi unul din clipurile audio corelate ca referin\u021b\u0103 pentru decalajul de timp
+dialog.correlate.select.audioname=Nume clip
+dialog.correlate.select.audiolater=Audio mai t\u00e2rziu
+dialog.rearrangewaypoints.desc=Alege\u021bi destina\u021bia \u0219i ordinea de sortare a waypoint-urilor
+dialog.rearrangephotos.desc=Alege\u021bi destina\u021bia \u0219i ordinea de sortare a punctelor foto
 dialog.rearrange.tostart=Toate la inceputul fi\u015fierului
-dialog.rearrange.toend=Toate la sfarsitul fi\u015fierului
+dialog.rearrange.toend=Toate la sf\u00e2r\u0219itul fi\u015fierului
 dialog.rearrange.tonearest=Fiecare la punctul cel mai apropiat al traseului
 dialog.rearrange.nosort=Nu sunt sortate
-dialog.rearrange.sortbyfilename=Sorta dup\u0103 nume de fi\u015fier
-dialog.rearrange.sortbyname=Sorta dup\u0103 nume
-dialog.rearrange.sortbytime=Sorta dup\u0103 timp
+dialog.rearrange.sortbyfilename=Sortez\u0103 dup\u0103 nume de fi\u015fier
+dialog.rearrange.sortbyname=Sorteaz\u0103 dup\u0103 nume
+dialog.rearrange.sortbytime=Sorteaz\u0103 dup\u0103 timp
+dialog.compress.closepoints.title=\u0218tergere puncte apropiate
+dialog.compress.closepoints.paramdesc=Anvergur\u0103
+dialog.compress.wackypoints.title=\u0218tergere puncte aberante
+dialog.compress.wackypoints.paramdesc=Factor de distan\u021b\u0103
+dialog.compress.singletons.title=\u0218tergere puncte singulare
+dialog.compress.singletons.paramdesc=Factor de distan\u021b\u0103
+dialog.compress.duplicates.title=\u0218tergerea duplicatelor
+dialog.compress.douglaspeucker.title=Compresie Douglas-Peucker
+dialog.compress.douglaspeucker.paramdesc=Anvergur\u0103
+dialog.compress.summarylabel=Puncte ce vor fi \u0219terse
+dialog.compress.confirm=Au fost marcate %d puncte. \u0218terg aceste puncte?
+dialog.compress.confirmnone=niciun punct nu a fost marcat
+dialog.deletemarked.nonefound=Niciun punct nu a putut fi \u0219ters
+dialog.pastecoordinates.desc=Scrie\u021bi sau copia\u021bi aici coordonatele
 dialog.pastecoordinates.coords=Coordonate
+dialog.pastecoordinates.nothingfound=V\u0103 rug\u0103m verifica\u021bi coordonatele \u0219i \u00eencerca\u021bi din nou.
+dialog.help.help=V\u0103 rug\u0103m vizita\u021bi \n http://gpsprune.activityworkshop.net/\npentru mai multe informa\u021bii, inclusiv un nou manual PDF care poate fi cump\u0103rat.
 dialog.about.version=Versiunea
-dialog.about.build=Construi
-dialog.about.languages=Limbi
-dialog.about.systeminfo=Informa\u0163ii a sistemului
+dialog.about.build=Versiunea minor\u0103
+dialog.about.summarytext1=GpsPrune e o aplica\u021bie pentru \u00eenc\u0103rcarea, afi\u0219area \u0219i editarea datelor salvate de receptoarele GPS.
+dialog.about.summarytext2=Este distribuit\u0103 sub licen\u021b\u0103 Gnu GPL pentru a permite utilizarea gratuit\u0103 \u00een lumea \u00eentreag\u0103<br>\u0219i pentru a permite oricui dore\u0219te \u00eembun\u0103t\u0103\u021biea aplica\u021biei.<br>Copierea, redistribuirea \u0219i modificarea sunt permise \u0219i \u00eencurajate<br>\u00een conformitate cu condi\u021biile descrise \u00een fi\u0219ierul <code>license.txt</code> care este inclus \u00een aplica\u021bie.
+dialog.about.summarytext3=V\u0103 rug\u0103m vizita\u021bi <code style="font-weight:bold">http://activityworkshop.net/</code> pentru mai multe informa\u021bii \u0219i indicii, inclusiv<br>un nou manual \u00een format PDF care poate fi cump\u0103rat.
+dialog.about.languages=Traduceri
+dialog.about.translatedby=Textele romanesti sunt de Rothermographer, Oana \u0219i Cristian
+dialog.about.systeminfo=Informa\u0163ii sistem
 dialog.about.systeminfo.os=Sistem de operare
+dialog.about.systeminfo.java=Java Runtime
 dialog.about.systeminfo.java3d=Java3d instalat
 dialog.about.systeminfo.povray=Povray instalat
 dialog.about.systeminfo.exiftool=Exiftool instalat
@@ -299,33 +469,112 @@ dialog.about.systeminfo.exiflib.external=Extern
 dialog.about.systeminfo.exiflib.external.failed=Extern (absent)
 dialog.about.yes=Da
 dialog.about.no=Nu
+dialog.about.credits=Mul\u021bumiri
+dialog.about.credits.code=Codul GpsPune a fost scris de
+dialog.about.credits.exifcode=Codul Exif de
+dialog.about.credits.icons=Unele icoane au fost luate de la
+dialog.about.credits.translators=Traduc\u0103tori
+dialog.about.credits.translations=La traduceri au ajutat
+dialog.about.credits.devtools=Unelte de dezvoltare
+dialog.about.credits.othertools=Alte unelte
+dialog.about.credits.thanks=Mul\u021bumiri
 dialog.about.readme=Cite\u015fte-m\u0103
-dialog.checkversion.releasedate1=Aceasta versiune noua a fost lansapa pe
+dialog.checkversion.error=Num\u0103rul versiunii nu a putut fi verificat.\nVerifica\u021bi conexiunea Internet.
+dialog.checkversion.uptodate=Folosi\u021bi cea mai recent\u0103 versiune a GpsPrune.
+dialog.checkversion.newversion1=A ap\u0103rut o nou\u0103 versiune GpsPrune. Cea mai nou\u0103 versiune este
+dialog.checkversion.newversion2=.
+dialog.checkversion.releasedate1=Aceast\u0103 versiune nou\u0103 a fost lansat\u0103 la
 dialog.checkversion.releasedate2=.
+dialog.checkversion.download=Pentru a desc\u0103rca noua versiune merge\u021bi la http://gpsprune.activityworkshop.net/download.html.
+dialog.keys.intro=Pute\u021bi folosi urm\u0103toarele scurt\u0103turi \u00een locul mouse-ului
+dialog.keys.keylist=<table><tr><td>Taste s\u0103ge\u021bi</td><td>Mut\u0103 harta st\u00e2nga, dreapta, sus, jos</td></tr><tr><td>Ctrl + s\u0103geat\u0103 st\u00e2nga, dreapta</td><td>Selecteaz\u0103 punctul anterior sau urm\u0103tor</td></tr><tr><td>Ctrl + s\u0103geat\u0103 sus, jos</td><td>Aproprie sau \u00eendep\u0103rteaz\u0103</td></tr><tr><td>Ctrl + PgUp, PgDown</td><td>Selecteaz\u0103 segmentul anterior sau urm\u0103tor</td></tr><tr><td>Ctrl + Home, End</td><td>Selecteaz\u0103 pri [...]
+dialog.keys.normalmodifier=Ctrl
+dialog.keys.macmodifier=Command
+dialog.saveconfig.desc=Urm\u0103toarele set\u0103ri pot fi salvate \u00eentr-un fi\u0219ier de configur\u0103ri :
+dialog.saveconfig.prune.trackdirectory=Director trasee
+dialog.saveconfig.prune.photodirectory=Director foto
 dialog.saveconfig.prune.languagecode=Limb\u0103 (RO)
 dialog.saveconfig.prune.languagefile=Fi\u015fier de limba
 dialog.saveconfig.prune.gpsdevice=Dispozitiv GPS
 dialog.saveconfig.prune.gpsformat=Format GPS
-dialog.setcolours.background=Fund
+dialog.saveconfig.prune.povrayfont=Font Povray
+dialog.saveconfig.prune.gnuplotpath=Calea c\u0103tre gnuplot
+dialog.saveconfig.prune.gpsbabelpath=Calea c\u0103tre gpsbabel
+dialog.saveconfig.prune.exiftoolpath=Calea c\u0103tre exiftool
+dialog.saveconfig.prune.mapsource=Surs\u0103 hart\u0103 selectat\u0103
+dialog.saveconfig.prune.mapsourcelist=Surse hart\u0103
+dialog.saveconfig.prune.diskcache=Cache hart\u0103
+dialog.saveconfig.prune.kmzimagewidth=Dimensiuni imagini \u00een KMZ
+dialog.saveconfig.prune.colourscheme=Schem\u0103 de culoare
+dialog.saveconfig.prune.linewidth=Grosime linie
+dialog.saveconfig.prune.kmltrackcolour=Culoar track KML
+dialog.saveconfig.prune.autosavesettings=Set\u0103ri salv\u0103ri automate
+dialog.setpaths.intro=Dac\u0103 dori\u021bi pute\u021bi alege calea c\u0103tre aplica\u021bii externe
+dialog.setpaths.found=Cale g\u0103sit\u0103?
+dialog.addaltitude.noaltitudes=Intervalul nu con\u021bine altitudini
+dialog.addaltitude.desc=Decalaj altitudine
+dialog.lookupsrtm.overwritezeros=Suprascriu altitudinile cu valoare zero?
+dialog.setcolours.intro=Face\u021bi click pe un petec de culoare pentru a schimba culoarea
+dialog.setcolours.background=Fundal
+dialog.setcolours.borders=Margini
 dialog.setcolours.lines=Linii
 dialog.setcolours.primary=Primar
 dialog.setcolours.secondary=Secundar
 dialog.setcolours.point=Puncte
 dialog.setcolours.selection=Selec\u0163ie
 dialog.setcolours.text=Text
-dialog.colourchooser.title=Selectare culoare
+dialog.colourchooser.title=Alege\u021bi culoare
 dialog.colourchooser.red=Ro\u0219u
 dialog.colourchooser.green=Verde
 dialog.colourchooser.blue=Albastru
+dialog.colourer.intro=Un algoritm de colorare poate da punctelor culori diferite
+dialog.colourer.type=Tip algoritm colorare
 dialog.colourer.type.none=Nimic
+dialog.colourer.type.byfile=Dup\u0103 fi\u0219ier
+dialog.colourer.type.bysegment=Dup\u0103 segment
+dialog.colourer.type.byaltitude=Dup\u0103 altitudine
+dialog.colourer.type.byspeed=Dup\u0103 vitez\u0103
+dialog.colourer.type.byvertspeed=Dup\u0103 viteza vertical\u0103
+dialog.colourer.type.bygradient=Dup\u0103 gradient
+dialog.colourer.type.bydate=Dup\u0103 dat\u0103
+dialog.colourer.start=Culoare de \u00eenceput
+dialog.colourer.end=Culoare de sf\u00e2r\u0219it
+dialog.colourer.maxcolours=Num\u0103rul maxim de culori
+dialog.setlanguage.firstintro=Pute\u021bi folosi una din limbile incluse,<p>sau pute\u021bi alege un fi\u0219ier text pe care s\u0103-l folosi\u021bi.
+dialog.setlanguage.secondintro=Trebuie s\u0103 salva\u021bi set\u0103rile \u0219i s\u0103<p>restarta\u021bi GpsPrune pentru a schimba limba
 dialog.setlanguage.language=Limb\u0103
 dialog.setlanguage.languagefile=Fi\u015fier de limba
-dialog.diskcache.table.tiles=Tigla
-dialog.searchwikipedianames.search=C\u0103utare :
+dialog.setlanguage.endmessage=Salva\u021bi set\u0103rile \u0219i restarta\u021bi GpsPrune\npentru ca schimbarea de limb\u0103 s\u0103 aib\u0103 efect.
+dialog.setlanguage.endmessagewithautosave=Restarta\u021bi GpsPrune pentru ca schimbare limbii s\u0103 aib\u0103 efect.
+dialog.diskcache.save=Salveaz\u0103 imaginile h\u0103r\u021bii pe disc
+dialog.diskcache.dir=Director cache
+dialog.diskcache.createdir=Creaz\u0103 director
+dialog.diskcache.nocreate=Directorul cache nu a putut fi creat
+dialog.diskcache.cannotwrite=\u021aiglele h\u0103r\u021bii nu pot fi salvate \u00een directorul selectat
+dialog.diskcache.table.path=Cale
+dialog.diskcache.table.usedby=Folosit de
+dialog.diskcache.table.zoom=Nivel apropiere
+dialog.diskcache.table.tiles=\u021aigle
+dialog.diskcache.table.megabytes=Megabytes
+dialog.diskcache.tileset=Set \u021bigle (tile-uri)
+dialog.diskcache.tileset.multiple=multiple
+dialog.diskcache.deleteold=\u015eterge imaginile vechi
+dialog.diskcache.maximumage=V\u00e2rsta maxim\u0103 (zile)
+dialog.diskcache.deleteall=\u015eterge toate imaginile
+dialog.diskcache.deleted=Au fost \u0219terse %d fi\u0219iere din cache
+dialog.deletefieldvalues.intro=Alege\u021bi c\u00e2mpurile ce urmeaz\u0103 a fi \u0219terse din intervalul curent
+dialog.deletefieldvalues.nofields=Nu poate fi \u0219ters nici un c\u00e2mp pentru intervalul dat
+dialog.setlinewidth.text=Introduce\u021bi grosimea liniilor ce vor fi desenate pentru trasee (1-3)
+dialog.downloadosm.desc=Confirma\u021bi desc\u0103rcarea datelor brute OSM pentru zona specificat\u0103:
+dialog.searchwikipedianames.search=Caut\u0103:
 dialog.weather.location=Loca\u0163ie
+dialog.weather.update=Prognoz\u0103 actualizat\u0103
 dialog.weather.sunrise=R\u0103s\u0103rit
 dialog.weather.sunset=Apus de soare
+dialog.weather.temperatureunits=Temperaturi
 dialog.weather.currentforecast=Vremea curent\u0103
+dialog.weather.dailyforecast=Prognoz\u0103 zilnic\u0103
+dialog.weather.3hourlyforecast=Prognoz\u0103 la fiecare 3 ore
 dialog.weather.day.now=Vremea curent\u0103
 dialog.weather.day.today=Ast\u0103zi
 dialog.weather.day.tomorrow=M\u00e2ine
@@ -336,49 +585,109 @@ dialog.weather.day.thursday=Joi
 dialog.weather.day.friday=Vineri
 dialog.weather.day.saturday=S\u00e2mb\u0103t\u0103
 dialog.weather.day.sunday=Duminic\u0103
+dialog.weather.wind=V\u00e2nt
+dialog.weather.temp=Temp
+dialog.weather.humidity=Umiditate
+dialog.weather.creditnotice=Acest set de date este oferit de openweathermap.org. Site-ul lor de web are mai multe detalii.
+dialog.deletebydate.onlyonedate=Toate punctele au fost \u00eenregistrate la aceea\u0219i dat\u0103.
+dialog.deletebydate.intro=Pentru fiecare dat\u0103 din traseu pute\u021bi alege s\u0103 \u0219terge\u021bi sau s\u0103 p\u0103stra\u021bi punctele
+dialog.deletebydate.nodate=F\u0103r\u0103 info cronologic
+dialog.deletebydate.column.keep=P\u0103streaz\u0103
+dialog.deletebydate.column.delete=\u015eterge
+dialog.setaltitudetolerance.text.metres=Limita (\u00een metri) sub care micile urc\u0103ri \u0219i cobor\u00e2ri vor fi ignorate
+dialog.setaltitudetolerance.text.feet=Limita (\u00een picioare) sub care micile urc\u0103ri \u0219i cobor\u00e2ri vor fi ignorate
+dialog.autoplay.duration=Durat\u0103 (sec)
+dialog.autoplay.usetimestamps=Folose\u0219te puncte cronologice
+dialog.autoplay.rewind=\u00cenapoi la \u00eenceput
+dialog.autoplay.pause=Pauz\u0103
+dialog.autoplay.play=Redare
+
+# 3d window
+dialog.3d.title=Vedere GpsPrune Three-d
+dialog.3d.altitudefactor=Factorul de exagerare a altitudinii
 
 # Confirm messages
-confirm.loadfile=Date incarcate din fi\u015fier
+confirm.loadfile=Date \u00eenc\u0103rcate din fi\u015fier
 confirm.save.ok1=Salvat cu succes
 confirm.save.ok2=puncte \u00een
+confirm.deletepoint.single=punct a fost \u0219ters
+confirm.deletepoint.multi=puncte au fost \u0219terse
+confirm.point.edit=puncte editate
+confirm.mergetracksegments=Segmente traseului au fost unite
+confirm.reverserange=Intervalul a fost inversat
+confirm.addtimeoffset=Decalajele de timp au fost ad\u0103ugate
+confirm.addaltitudeoffset=Decalajele de altitudine au fost ad\u0103ugate
+confirm.rearrangewaypoints=Waypoint-urile au fost rearanjate
+confirm.rearrangephotos=Fotografiile au fost rearanjate
+confirm.splitsegments=Au fost f\u0103cute %d diviz\u0103ri de segmente
+confirm.sewsegments=Au fost combinate %d segmente
+confirm.cutandmove=Selec\u021bia a fost mutat\u0103
+confirm.interpolate=Punctele au fost ad\u0103ugate
+confirm.convertnamestotimes=Numele waypoint-urile au fost convertite
+confirm.saveexif.ok=Au fost salvate %d fi\u0219iere foto
+confirm.undo.single=opera\u021bia a fost anulat\u0103
+confirm.undo.multi=opera\u021biile au fost anulate
+confirm.jpegload.single=foto a fost ad\u0103ugat\u0103
+confirm.jpegload.multi=fotografiile au fost ad\u0103ugate
 confirm.media.connect=foto/audio conectat
 confirm.photo.disconnect=foto deconectat
 confirm.audio.disconnect=audio deconectat
 confirm.media.removed=\u0219ters
+confirm.correlatephotos.single=foto a fost corelat\u0103
+confirm.correlatephotos.multi=fotografiile au fost corelate
+confirm.createpoint=punct creat
+confirm.rotatephoto=foto rotit\u0103
 confirm.running=Executare ...
+confirm.lookupsrtm=Au fost g\u0103site %d valori de altitudine
 confirm.downloadsrtm=S-au desc\u0103rcat %d fi\u015fiere
 confirm.downloadsrtm.1=S-au desc\u0103rcat %d fi\u015fier
+confirm.downloadsrtm.none=Niciun fi\u0219ier nu a fost desc\u0103rcat, ele erau deja prezente \u00een cache
+confirm.deletefieldvalues=Valorile c\u00e2mpurilor au fost \u0219terse
+confirm.audioload=Fi\u0219iere audio au fost ad\u0103ugate
+confirm.correlateaudios.single=clipul audio a fost corelat
+confirm.correlateaudios.multi=clipurile audio au fost corelate
 
-# Tips
+# Tips, shown just once when appropriate
 tip.title=Indiciu
+tip.useamapcache=Prin configurarea unui cache pe disc (Set\u0103ri -> Salvare h\u0103r\u021bi)\npute\u021bi \u00eembun\u0103t\u0103\u021bi viteza de afi\u0219are \u0219i reduce traficul de re\u021bea
+tip.learntimeparams=Rezultatele vor fi mai corecte dac\u0103 folosi\u021bi\nTraseu -> \u00cenva\u021b\u0103 parametri pentru estim\u0103ri de timp\npe traseele deja \u00eenregistrate.
+tip.downloadsrtm=Pute\u021bi \u00eembun\u0103t\u0103\u021bi viteza prin folosirea\nInternet -> Descarc\u0103 date SRTM
+tip.usesrtmfor3d=Acest traseu nu are valori de altitudine.\nPute\u021bi folosi func\u021biile SRTM pentru a aproxima altitudinile \u00een vederea 3D.
+tip.manuallycorrelateone=Decalajul de timp poate fi calculat dac\u0103 cel pu\u021bin un element e conectat.
 
 # Buttons
 button.ok=OK
-button.back=Inapoi
+button.back=\u00cenapoi
 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.moveup=Mut\u0103 \u00een sus
+button.movedown=Mut\u0103 \u00een jos
+button.edit=Editeaz\u0103
+button.exit=Ie\u0219ire
+button.close=\u00cenchide
+button.continue=Continu\u0103
 button.yes=Da
 button.no=Nu
 button.yestoall=Da pentru tot
 button.notoall=Nu pentru tot
+button.always=\u00centotdeauna
 button.select=Selectare
-button.selectall=Selecteaza tot
-button.selectnone=Deselecteaza tot
-button.load=Descarca
+button.selectall=Selecteaz\u0103 tot
+button.selectnone=Deselecteaz\u0103 tot
+button.preview=Previzualizare
+button.load=Descarc\u0103
 button.upload=Trimite
-button.guessfields=Ghici cimpuri
-button.check=Verifica
-button.delete=\u015etergere
-button.manage=Administra
-button.combine=Combina
+button.guessfields=Ghice\u0219te c\u00e2mpuri
+button.showwebpage=Deschide pagina web
+button.check=Verific\u0103
+button.resettodefaults=Revino la valorile standard
+button.browse=Browse...
+button.addnew=Adaug\u0103
+button.delete=\u015eterge
+button.manage=Administreaz\u0103
+button.combine=Combin\u0103
 
 # File types
 filetype.txt=Fi\u015fiere text
@@ -393,23 +702,32 @@ filetype.png=Fi\u015fiere PNG
 filetype.audio=Fi\u015fiere MP3, OGG, WAV
 
 # Display components
+display.nodata=Nu exist\u0103 date \u00eenc\u0103rcate
+display.noaltitudes=Traseul nu include altitudini
+display.notimestamps=Datele traseului nu includ date cronologice
+display.novalues=Datele traseului nu includ valori pentru acest c\u00e2mp
 details.trackdetails=Detalii traseul
+details.notrack=Niciun traseu \u00eenc\u0103rcat
 details.track.points=Puncte
-details.pointdetails=Detalii punctul
+details.track.file=Fi\u0219ier
+details.track.numfiles=Num\u0103rul de fi\u015fiere
+details.pointdetails=Detalii punct
 details.index.selected=Punct
-details.index.of=de
-details.photofile=Fi\u015fier
-details.rangedetails=Detalii intervalul
-details.range.selected=Selectat
+details.index.of=din
+details.nopointselection=Niciun punct selectat
+details.photofile=Fi\u015fier foto
+details.norangeselection=Niciun interval selectat
+details.rangedetails=Detalii interval
+details.range.selected=Selectat de la
 details.range.to=la
-details.altitude.to=la
+details.altitude.to=p\u00e2n\u0103 la
 details.range.climb=Urcare
 details.range.descent=Cobor\u00e2re
 details.coordformat=Format coordonate
-details.distanceunits=Unit\u0103\u0163i de distan\u0163e
+details.distanceunits=Unitate de distan\u021b\u0103
 display.range.time.secs=s
 display.range.time.mins=m
-display.range.time.hours=o
+display.range.time.hours=h
 display.range.time.days=z
 details.range.avespeed=Viteza medie
 details.range.maxspeed=Viteza maxim\u0103
@@ -417,14 +735,19 @@ details.range.numsegments=Num\u0103r de segmente
 details.range.pace=Ritm
 details.range.gradient=Gradient
 details.lists.waypoints=Waypoints
-details.lists.photos=Foto-uri
+details.lists.photos=Fotografii
 details.lists.audio=Audio
 details.photodetails=Detalii foto
+details.nophoto=Nicio foto selectat\u0103
 details.photo.loading=\u00cenc\u0103rcare
 details.photo.bearing=Direc\u0163ie
 details.media.connected=Conectat
+details.media.fullpath=Cale complet\u0103
 details.audiodetails=Detalii audio
+details.noaudio=Niciun clip audio selectat
 details.audio.file=Fi\u015fier
+details.audio.playing=Redare audio...
+map.overzoom=Nu exist\u0103 h\u0103r\u021bi la acest nivel de apropiere
 
 # Field names
 fieldname.latitude=Latitudine
@@ -436,30 +759,37 @@ fieldname.date=Data
 fieldname.waypointname=Nume
 fieldname.waypointtype=Tip
 fieldname.newsegment=Segment
-fieldname.prefix=Cimp
+fieldname.custom=Personalizat
+fieldname.prefix=C\u00e2mp
 fieldname.distance=Distan\u0163\u0103
 fieldname.duration=Durat\u0103
 fieldname.speed=Vitez\u0103
 fieldname.verticalspeed=Vitez\u0103 vertical\u0103
 fieldname.description=Descriere
+fieldname.mediafilename=Fi\u0219ier
 
 # Measurement units
+units.original=Ini\u021bial
 units.default=Implicit
 units.metres=Metri
 units.metres.short=m
+units.feet=Picioare
+units.feet.short=ft
 units.kilometres=Kilometri
 units.kilometres.short=km
 units.kilometresperhour=km pe or\u0103
-units.kilometresperhour.short=km/o
-units.miles=Mil\u0103
+units.kilometresperhour.short=km/h
+units.miles=Mile
 units.miles.short=mi
-units.milesperhour=mil\u0103 pe or\u0103
-units.milesperhour.short=mpo
-units.nauticalmiles=Mil\u0103 marin\u0103
-units.nauticalmiles.short=mm
+units.milesperhour=mile pe or\u0103
+units.milesperhour.short=mph
+units.nauticalmiles=Mile marine
+units.nauticalmiles.short=N.m.
 units.nauticalmilesperhour.short=kn
-units.metrespersec=metri pe secund
+units.metrespersec=metri pe secund\u0103
 units.metrespersec.short=m/s
+units.feetpersec=picioare pe secund\u0103
+units.feetpersec.short=ft/s
 units.hours=ore
 units.minutes=minute
 units.seconds=secunde
@@ -476,9 +806,15 @@ units.degreesfahrenheit.short=\u00b0F
 logic.and=\u0219i
 logic.or=sau
 
-# External urls
+# External urls and services
+url.googlemaps=maps.google.com
 wikipedia.lang=ro
 openweathermap.lang=ro
+webservice.peakfinder=Deschide Peakfinder.org
+webservice.geohack=Deschide pagina Geohack
+webservice.panoramio=Deschide harta Panoramio
+webservice.opencachingcom=Deschide Opencaching.com
+webservice.opencachingcom.lang=en
 
 # Cardinals for 3d plots
 cardinal.n=N
@@ -487,24 +823,80 @@ cardinal.e=E
 cardinal.w=V
 
 # Undo operations
-undo.load=\u00cencarc\u0103 date
-undo.loadphotos=\u00cencarc\u0103 fotografii
-undo.loadaudios=\u00cencarc\u0103 audio
-undo.editpoint=Editare punct
-undo.deletepoint=\u015eterge punct
-undo.removephoto=Elimina foto
-undo.removeaudio=Elimina audio
-undo.deleterange=\u015eterge interval
-undo.deletemarked=\u015eterge puncte
-undo.connect=conecteaza
-undo.disconnect=deconecteaza
-undo.rotatephoto=roti foto
+undo.load=\u00eencarc\u0103 date
+undo.loadphotos=\u00eencarc\u0103 fotografii
+undo.loadaudios=\u00eencarc\u0103 audio
+undo.editpoint=editare punct
+undo.deletepoint=\u0219terge punct
+undo.removephoto=elimina foto
+undo.removeaudio=elimin\u0103 audio
+undo.deleterange=\u0219tergere interval
+undo.croptrack=decupare traseu
+undo.deletemarked=\u0219tergere puncte
+undo.insert=adaugare puncte
+undo.reverse=inversarea selec\u021biei
+undo.mergetracksegments=unirea segmentelor traseului
+undo.splitsegments=desp\u0103r\u021birea segmentelor traseului
+undo.sewsegments=combinarea segmentelor traseului
+undo.addtimeoffset=ad\u0103ugarea decalajului de timp
+undo.addaltitudeoffset=ad\u0103ugarea decalajului de altitudine
+undo.rearrangewaypoints=rearanjarea waypoint-urilor
+undo.cutandmove=mutarea sec\u021biunii
+undo.connect=conectarea
+undo.disconnect=deconectarea
+undo.correlatephotos=corelarea fotografiilor
+undo.rearrangephotos=rearanjarea fotografiilor
+undo.createpoint=ad\u0103ugarea punctului
+undo.rotatephoto=rotirea fotografiei
+undo.convertnamestotimes=conversia numelor \u00een timpi
+undo.lookupsrtm=calcularea altitudinilor din SRTM
+undo.deletefieldvalues=\u0219tergerea valorilor c\u00e2mpurilor
+undo.correlateaudios=corelarea clipurilor audio
 
 # Error messages
-error.saveexif.cannotoverwrite1=Fi\u0219ier
-error.jpegload.nofilesfound=Nu au fost g\u0103site fi\u0219iere
-error.jpegload.nojpegsfound=Nu au fost g\u0103site fi\u0219iere jpeg
-error.jpegload.nogpsfound=Nu a fost g\u0103sit informa\u021Bii GPS
-error.audioload.nofilesfound=Nu au fost g\u0103site fi\u0219iere audio
+error.save.dialogtitle=Eroare la salvarea datelor
+error.save.nodata=Nu exist\u0103 nimic de salvat
+error.save.failed=Salvarea datelor \u00een fi\u0219ier a e\u0219uat
+error.saveexif.filenotfound=Cautarea foto a e\u0219uat
+error.saveexif.cannotoverwrite1=Fi\u0219ierul foto
+error.saveexif.cannotoverwrite2=este read only \u0219i nu poate fi suprascris. Salvez o copie?
+error.saveexif.failed=Salvarea a %d imagini a e\u0219uat
+error.saveexif.forced=%d imagini au necesitat salvare for\u021bat\u0103
+error.load.dialogtitle=Eroare la \u00eencarcarea datelor
+error.load.noread=Fi\u0219ierul nu poate fi citit
+error.load.nopoints=\u00cen fi\u0219ier nu au fost g\u0103site coordonate geografice
+error.load.unknownxml=Formatul XML nu poate fi recunoscut
+error.load.noxmlinzip=\u00cen interiorul fi\u0219ierului ZIP sau KMZ nu a fost g\u0103sit con\u021binut XML
+error.load.othererror=Eroare la citirea fi\u0219ierului:
+error.jpegload.dialogtitle=Eroare la \u00eenc\u0103rcarea fotografiilor
+error.jpegload.nofilesfound=Nu a fost g\u0103sit niciun fi\u0219ier
+error.jpegload.nojpegsfound=Nu a fost g\u0103sit niciun fi\u0219ier jpeg
+error.jpegload.nogpsfound=\u00cen EXIF-ul fi\u0219ierelor JPEG nu a fost g\u0103sit\u0103 informa\u021bie GPS
+error.jpegload.exifreadfailed=Citirea informa\u021biei EXIF a e\u0219uat. Informa\u021bia EXIF nu poate fi citit\u0103 far\u0103 o bibliotec\u0103 extern\u0103 sau intern\u0103.
+error.audioload.nofilesfound=Nu a fost g\u0103sit niciun clip audio.
+error.gpsload.unknown=Eroare cu cauz\u0103 necunoscut\u0103
+error.undofailed.title=Anularea a e\u0219uat
+error.undofailed.text=\u00cencercarea de anulare a e\u0219uat
+error.function.noop.title=Func\u021bia nu a avut niciun efect
+error.rearrange.noop=Rearanjarea punctelor nu a avut niciun efect
 error.function.notavailable.title=Func\u021bie indisponibil\u0103
-error.readme.notfound=Fi\u015Fierul "cite\u015Fte-m\u0103" nu a fost g\u0103sit
+error.function.nojava3d=Aceast\u0103 func\u021bie necesit\u0103 biblioteca Java3d
+error.3d=Eroare la afi\u0219area 3d
+error.readme.notfound=Fi\u0219erul "Cite\u015fte-m\u0103" nu a fost g\u0103sit
+error.osmimage.dialogtitle=Eroarea la \u00eenc\u0103rcarea imaginilor h\u0103r\u021bii
+error.osmimage.failed=\u00cenc\u0103rcarea imaginilor h\u0103r\u021bii a e\u0219uat. Verifica\u021bi conexiunea la internet.
+error.language.wrongfile=Fi\u0219ierul selectat nu pare a fi un fi\u0219ier de limb\u0103 pentru GpsPrune
+error.convertnamestotimes.nonames=Niciun nume de waypoint nu a fost g\u0103sit sau nu au putut fi convertite
+error.lookupsrtm.nonefound=Pentru aceste puncte nu exist\u0103 valori de altitudine
+error.lookupsrtm.nonerequired=Toate punctele au deja altitudine, nu e nimic de calculat
+error.gpsies.uploadnotok=Server-ul gpsies a \u00eentors mesajul
+error.gpsies.uploadfailed=Upload-ul a e\u0219uat cu eroarea
+error.showphoto.failed=\u00cenc\u0103rcarea foto a e\u0219uat
+error.playaudiofailed=\u00cencercarea de a reda clipul audio a e\u0219uat
+error.cache.notthere=Directorul tile cache nu a fost g\u0103sit
+error.cache.empty=Directorul tile cache e gol
+error.cache.cannotdelete=Tile-urile (imaginile hart\u0103) nu au putut fi \u0219terse
+error.learnestimationparams.failed=Nu pot fi \u00eenv\u0103\u021ba\u021bi parametrii din acest traseu.\n\u00cencerca\u021bi s\u0103 \u00eenc\u0103rca\u021bi mai multe trasee.
+error.tracksplit.nosplit=Traseul nu a putut fi spart
+error.downloadsrtm.nocache=Fi\u0219ierele nu au putut fi salvate.\nV\u0103 rug\u0103m verifica\u021bi setarea cache-ului.
+error.sewsegments.nothingdone=Segmentele nu au putut fi combinate.\n\u00cen traseu sunt acum %d segmente.
diff --git a/tim/prune/lang/prune-texts_ru.properties b/tim/prune/lang/prune-texts_ru.properties
index ec30638..ea96aa8 100644
--- a/tim/prune/lang/prune-texts_ru.properties
+++ b/tim/prune/lang/prune-texts_ru.properties
@@ -12,7 +12,7 @@ menu.track=\u0422\u0440\u0435\u043a
 menu.track.undo=\u041e\u0442\u043c\u0435\u043d\u0438\u0442\u044c
 menu.track.clearundo=\u041e\u0447\u0438\u0441\u0442\u0438\u0442\u044c \u0441\u043f\u0438\u0441\u043e\u043a \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u0439
 menu.track.markrectangle=\u041e\u0442\u043c\u0435\u0442\u0438\u0442\u044c \u0442\u043e\u0447\u043a\u0438 \u0432 \u043a\u0432\u0430\u0434\u0440\u0430\u0442\u0435
-menu.track.deletemarked=\u0423\u0434\u0430\u043b\u0438\u0442\u044c \u043e\u0442\u043c\u0435\u0447\u0435\u043d\u043d\u044b\u0435 \u0442\u043e\u0447\u043a\u0438
+function.deletemarked=\u0423\u0434\u0430\u043b\u0438\u0442\u044c \u043e\u0442\u043c\u0435\u0447\u0435\u043d\u043d\u044b\u0435 \u0442\u043e\u0447\u043a\u0438
 function.rearrangewaypoints=\u041f\u0435\u0440\u0435\u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0438\u0442\u044c \u0438\u043d\u0442\u0435\u0440\u0432\u0430\u043b\u044b
 menu.range=\u0418\u043d\u0442\u0435\u0440\u0432\u0430\u043b
 menu.range.all=\u0412\u044b\u0431\u0440\u0430\u0442\u044c \u0432\u0441\u0435
@@ -108,7 +108,7 @@ function.sewsegments=\u0421\u043a\u043b\u0435\u0438\u0442\u044c \u0441\u0435\u04
 function.getgpsies=\u0417\u0430\u0433\u0440\u0443\u0437\u0438\u0442\u044c \u0442\u0440\u0435\u043a\u0438
 function.uploadgpsies=\u0412\u044b\u0433\u0440\u0443\u0437\u0438\u0442\u044c \u0442\u0440\u0435\u043a \u043d\u0430 gpsies.com
 function.lookupsrtm=\u0412\u044b\u0441\u043e\u0442\u044b \u0432 SRTM
-function.downloadsrtm=\u0417\u0430\u0433\u0440\u0443\u0437\u0438\u0442\u044c STRM 
+function.downloadsrtm=\u0417\u0430\u0433\u0440\u0443\u0437\u0438\u0442\u044c STRM
 function.getwikipedia=\u0421\u0442\u0430\u0442\u044c\u044f \u043e \u0431\u043b\u0438\u0436\u0430\u0439\u0448\u0435\u0439 \u043e\u0431\u043b\u0430\u0441\u0442\u0438 \u0432 \u0412\u0438\u043a\u0438
 function.searchwikipedianames=\u041f\u043e\u0438\u0441\u043a \u0441\u0442\u0430\u0442\u0435\u0439 \u0432 \u0412\u0438\u043a\u0438 \u043f\u043e \u0438\u043c\u0435\u043d\u0438
 function.downloadosm=\u0417\u0430\u0433\u0440\u0443\u0437\u0438\u0442\u044c OSM \u0434\u0430\u043d\u043d\u044b\u0435 \u043d\u0430 \u0442\u0435\u0440\u0440\u0438\u0442\u043e\u0440\u0438\u044e
@@ -694,6 +694,7 @@ fieldname.duration=\u041f\u0440\u043e\u0434\u043e\u043b\u0436\u0438\u0442\u0435\
 fieldname.speed=\u0421\u043a\u043e\u0440\u043e\u0441\u0442\u044c
 fieldname.verticalspeed=\u0412\u0435\u0440\u0442\u0438\u043a\u0430\u043b\u044c\u043d\u0430\u044f \u0441\u043a\u043e\u0440\u043e\u0441\u0442\u044c
 fieldname.description=\u041e\u043f\u0438\u0441\u0430\u043d\u0438\u0435
+fieldname.mediafilename=\u0424\u0430\u0439\u043b
 
 # Measurement units
 units.original=\u041e\u0440\u0438\u0433\u0438\u043d\u0430\u043b\u044c\u043d\u044b\u0439
@@ -737,6 +738,7 @@ logic.or=\u0438\u043b\u0438
 url.googlemaps=maps.google.ru
 wikipedia.lang=ru
 openweathermap.lang=ru
+webservice.opencachingcom.lang=ru
 
 # Cardinals for 3d plots
 cardinal.n=\u0421\u0435\u0432\u0435\u0440
diff --git a/tim/prune/lang/prune-texts_sv.properties b/tim/prune/lang/prune-texts_sv.properties
new file mode 100644
index 0000000..59a84af
--- /dev/null
+++ b/tim/prune/lang/prune-texts_sv.properties
@@ -0,0 +1,102 @@
+# Text entries for the GpsPrune application
+# Swedish entries
+
+# Menu entries
+menu.file=Arkiv
+menu.file.addphotos=L\u00e4gg till foto
+menu.file.recentfiles=Senaste filer
+menu.file.save=Spara som text
+menu.file.exit=Avsluta
+menu.track=Sp\u00e5r
+menu.track.undo=\u00c5ngra
+menu.track.clearundo=Rensa \u00e5ngra-historik
+menu.track.markrectangle=Markera punkter i rektangel
+function.deletemarked=Radera markerade punkter
+function.rearrangewaypoints=Ordna waypoints
+dialog.rearrange.tostart=Alla till b\u00f6rjan av fil
+dialog.rearrange.toend=Alla till slut av fil
+dialog.rearrange.tonearest=Varje till n\u00e4rmaste sp\u00e5rpunkt
+menu.range=Intervall
+menu.range.all=V\u00e4lj alla
+menu.range.none=V\u00e4lj ingen
+menu.range.start=S\u00e4tt till b\u00f6rjan av intervall
+menu.range.end=S\u00e4tt till slutet av intervall
+menu.range.average=Medelv\u00e4rdesval
+menu.range.reverse=V\u00e4nd intervall
+menu.range.mergetracksegments=Sl\u00e5 ihop sp\u00e5rsegment
+menu.range.cutandmove=Klipp och flytta urval
+menu.point=Punkt
+menu.point.editpoint=Redigera punkt
+menu.point.deletepoint=Radera punkt
+menu.photo=Foto
+menu.photo.saveexif=Spara till Exif
+menu.audio=Ljud
+menu.view=Visa
+menu.view.showsidebars=Visa sidopaneler
+menu.view.browser=Karta i webbl\u00e4sare
+menu.view.browser.google=Google Maps
+menu.view.browser.openstreetmap=Openstreetmap
+menu.view.browser.mapquest=Mapquest
+menu.view.browser.yahoo=Yahoo maps
+menu.view.browser.bing=Bing maps
+menu.settings=Inst\u00e4llningar
+menu.settings.onlinemode=H\u00e4mta kartor fr\u00e5n Internet
+menu.settings.autosave=Autospara inst\u00e4llningar vid avslut
+menu.help=Hj\u00e4lp
+# Popup menu for map
+menu.map.zoomin=Zooma ut
+menu.map.zoomout=Zooma in
+menu.map.zoomfull=Zooma till passning
+menu.map.newpoint=Skapa ny punkt
+menu.map.drawpoints=Skapa en serie punkter
+menu.map.connect=F\u00f6rbind sp\u00e5rpunkter
+menu.map.autopan=Panorera automatiskt
+menu.map.showmap=Visa karta
+menu.map.showscalebar=Visa skala
+menu.map.editmode=Redigeringsl\u00e4ge
+
+# Alt keys for menus
+altkey.menu.file=A
+altkey.menu.track=S
+altkey.menu.range=I
+altkey.menu.point=P
+altkey.menu.view=V
+altkey.menu.photo=F
+altkey.menu.audio=L
+altkey.menu.settings=I
+altkey.menu.help=H
+
+# Ctrl shortcuts for menu items
+shortcut.menu.file.open=O
+shortcut.menu.file.load=L
+shortcut.menu.file.save=S
+shortcut.menu.track.undo=Z
+shortcut.menu.range.all=A
+shortcut.menu.help.help=H
+
+# Functions
+function.open=\u00d6ppna fil
+function.importwithgpsbabel=Importera fil med GPSBabel
+function.loadfromgps=Ladda fr\u00e5n GPS
+function.sendtogps=Skicka till GPS
+function.exportkml=Exportera KML
+function.exportgpx=Exportera GPX
+function.exportpov=Exportera POV
+function.exportsvg=Exportera SVG
+function.exportimage=Exportera bildfil
+function.editwaypointname=Redigera namn p\u00e5 waypoint
+function.compress=Komprimera sp\u00e5r
+function.deleterange=Radera intervall
+function.croptrack=Besk\u00e4r sp\u00e5r till intervall
+function.interpolate=Interpolera punkter
+function.addtimeoffset=Infoga tidsoffset
+function.addaltitudeoffset=Infoga h\u00f6jdoffset
+function.convertnamestotimes=Omvandla waypointnamn till tidpunkter
+function.findwaypoint=S\u00f6k waypoint
+function.pastecoordinates=Infoga koordinater
+function.charts=Diagram
+function.show3d=3D-vy
+function.distances=Avst\u00e5nd
+function.estimatetime=Uppskatta tid
+
+openweathermap.lang=se
diff --git a/tim/prune/lang/prune-texts_tr.properties b/tim/prune/lang/prune-texts_tr.properties
index d236ff3..68eca80 100644
--- a/tim/prune/lang/prune-texts_tr.properties
+++ b/tim/prune/lang/prune-texts_tr.properties
@@ -12,7 +12,7 @@ menu.track.clearundo=Geri alma listesi s\u0131f\u0131rla
 menu.point.editpoint=Nokta d\u00fczenle
 menu.point.deletepoint=Noktay\u0131 sil
 function.deleterange=S\u0131ray\u0131 sil
-menu.track.deletemarked=Se\u00e7ili noktalar\u0131 sil
+function.deletemarked=Se\u00e7ili noktalar\u0131 sil
 function.interpolate=\u0130nterpolasyon
 menu.range.average=Se\u00e7me ortala
 menu.range.reverse=S\u0131ra tersine \u00e7evir
diff --git a/tim/prune/lang/prune-texts_uk.properties b/tim/prune/lang/prune-texts_uk.properties
index 3b47eea..380e564 100644
--- a/tim/prune/lang/prune-texts_uk.properties
+++ b/tim/prune/lang/prune-texts_uk.properties
@@ -11,7 +11,7 @@ menu.track=\u0422\u0440\u0435\u043a
 menu.track.undo=\u0421\u043a\u0430\u0441\u0443\u0432\u0430\u0442\u0438
 menu.track.clearundo=\u041e\u0447\u0438\u0441\u0442\u0438\u0442\u0438 \u0441\u043f\u0438\u0441\u043e\u043a \u0437\u043c\u0456\u043d
 menu.track.markrectangle=\u041f\u043e\u0437\u043d\u0430\u0447\u0438\u0442\u0438 \u0442\u043e\u0447\u043a\u0438 \u0443 \u043f\u0440\u044f\u043c\u043e\u043a\u0443\u0442\u043d\u0438\u043a\u0443
-menu.track.deletemarked=\u0412\u0438\u043b\u0443\u0447\u0438\u0442\u0438 \u043f\u043e\u0437\u043d\u0430\u0447\u0435\u043d\u0456 \u0442\u043e\u0447\u043a\u0438
+function.deletemarked=\u0412\u0438\u043b\u0443\u0447\u0438\u0442\u0438 \u043f\u043e\u0437\u043d\u0430\u0447\u0435\u043d\u0456 \u0442\u043e\u0447\u043a\u0438
 function.rearrangewaypoints=\u041f\u0435\u0440\u0435\u0432\u0438\u0437\u043d\u0430\u0447\u0438\u0442\u0438 \u0456\u043d\u0442\u0435\u0440\u0432\u0430\u043b\u0438
 dialog.rearrange.tostart=\u0423\u0441\u0435 \u043d\u0430 \u043f\u043e\u0447\u0430\u0442\u043e\u043a \u0444\u0430\u0439\u043b\u0443
 dialog.rearrange.toend=\u0423\u0441\u0435 \u043d\u0430 \u043a\u0456\u043d\u0435\u0446\u044c \u0444\u0430\u0439\u043b\u0443
diff --git a/tim/prune/lang/prune-texts_zh.properties b/tim/prune/lang/prune-texts_zh.properties
index 40319fa..a2344e4 100644
--- a/tim/prune/lang/prune-texts_zh.properties
+++ b/tim/prune/lang/prune-texts_zh.properties
@@ -12,7 +12,7 @@ menu.track=\u8f68\u8ff9
 menu.track.undo=\u64a4\u9500
 menu.track.clearundo=\u6e05\u9664\u64a4\u9500\u6e05\u5355
 menu.track.markrectangle=\u6807\u8bb0\u9009\u53d6\u533a\u57df\u5185\u7684\u70b9
-menu.track.deletemarked=\u5220\u9664\u5df2\u6807\u8bb0\u8f68\u8ff9\u70b9
+function.deletemarked=\u5220\u9664\u5df2\u6807\u8bb0\u8f68\u8ff9\u70b9
 menu.range=\u822a\u6bb5
 menu.range.all=\u5168\u9009
 menu.range.none=\u64a4\u9500\u9009\u62e9
diff --git a/tim/prune/load/FileLoader.java b/tim/prune/load/FileLoader.java
index 8669e18..cf60f9e 100644
--- a/tim/prune/load/FileLoader.java
+++ b/tim/prune/load/FileLoader.java
@@ -63,6 +63,7 @@ public class FileLoader
 			_fileChooser.addChoosableFileFilter(new GenericFileFilter("filetype.kml", new String[] {"kml"}));
 			_fileChooser.addChoosableFileFilter(new GenericFileFilter("filetype.kmz", new String[] {"kmz"}));
 			_fileChooser.setAcceptAllFileFilterUsed(true);
+			_fileChooser.setFileFilter(_fileChooser.getAcceptAllFileFilter()); // For some reason seems necessary
 			// start from directory in config if already set (by load jpegs)
 			String configDir = Config.getConfigString(Config.KEY_TRACK_DIR);
 			if (configDir == null) {configDir = Config.getConfigString(Config.KEY_PHOTO_DIR);}
diff --git a/tim/prune/load/xml/GpxHandler.java b/tim/prune/load/xml/GpxHandler.java
index 4208014..225a667 100644
--- a/tim/prune/load/xml/GpxHandler.java
+++ b/tim/prune/load/xml/GpxHandler.java
@@ -70,7 +70,7 @@ public class GpxHandler extends XmlHandler
 		else if (tag.equals("type")) {
 			_currentTag = _type;
 		}
-		else if (tag.equals("description")) {
+		else if (tag.equals("description") || tag.equals("desc")) {
 			_currentTag = _description;
 		}
 		else if (tag.equals("link")) {
diff --git a/tim/prune/load/xml/KmlHandler.java b/tim/prune/load/xml/KmlHandler.java
index 2ddd1cd..e8f2c6a 100644
--- a/tim/prune/load/xml/KmlHandler.java
+++ b/tim/prune/load/xml/KmlHandler.java
@@ -13,9 +13,10 @@ import tim.prune.data.Field;
 public class KmlHandler extends XmlHandler
 {
 	private boolean _insideCoordinates = false;
+	private boolean _insideGxTrack = false;
 	private String _value = null;
 	private String _name = null, _desc = null;
-	private String _imgLink = null;
+	private String _timestamp = null, _imgLink = null;
 	private StringBuffer _coordinates = null;
 	private ArrayList<String> _coordinateList = null;
 	private ArrayList<String[]> _pointList = new ArrayList<String[]>();
@@ -34,13 +35,21 @@ public class KmlHandler extends XmlHandler
 	{
 		String tagName = localName;
 		if (tagName == null || tagName.equals("")) {tagName = qName;}
-		if (tagName.equalsIgnoreCase("Placemark")) {
+		tagName = tagName.toLowerCase();
+
+		if (tagName.equals("placemark"))
+		{
 			_coordinateList = new ArrayList<String>();
 		}
-		else if (tagName.equalsIgnoreCase("coordinates")) {
+		else if (tagName.equals("coordinates"))
+		{
 			_insideCoordinates = true;
 			_coordinates = null;
 		}
+		else if (tagName.equals("gx:track"))
+		{
+			_insideGxTrack = true;
+		}
 		_value = null;
 		super.startElement(uri, localName, qName, attributes);
 	}
@@ -55,28 +64,44 @@ public class KmlHandler extends XmlHandler
 	{
 		String tagName = localName;
 		if (tagName == null || tagName.equals("")) {tagName = qName;}
-		if (tagName.equalsIgnoreCase("Placemark"))
+		tagName = tagName.toLowerCase();
+
+		if (tagName.equals("placemark"))
 		{
 			processPlacemark();
-			_name = _desc = _imgLink = null;
+			_name = _desc = _imgLink = _timestamp = null;
 		}
-		else if (tagName.equalsIgnoreCase("coordinates")) {
+		else if (tagName.equals("coordinates"))
+		{
 			_insideCoordinates = false;
 			if (_coordinates != null) _coordinateList.add(_coordinates.toString().trim());
 		}
-		else if (tagName.equalsIgnoreCase("name")) _name = _value;
-		else if (tagName.equalsIgnoreCase("description")) {
+		else if (tagName.equals("name"))
+		{
+			_name = _value;
+		}
+		else if (tagName.equals("description"))
+		{
 			_desc = _value;
 			_imgLink = getImgLink(_desc);
 		}
-		else if (tagName.equalsIgnoreCase("when")) {
-			_whenList.add(_value);
+		else if (tagName.equals("when"))
+		{
+			if (!_insideGxTrack)
+				_timestamp = _value;
+			else
+				_whenList.add(_value);
 		}
-		else if (tagName.equalsIgnoreCase("gx:coord")) {
-			_whereList.add(_value);
+		else if (tagName.equals("gx:coord"))
+		{
+			if (_insideGxTrack) {
+				_whereList.add(_value);
+			}
 		}
-		else if (tagName.equalsIgnoreCase("gx:Track")) {
+		else if (tagName.equals("gx:track"))
+		{
 			processGxTrack();
+			_insideGxTrack = false;
 		}
 		super.endElement(uri, localName, qName);
 	}
@@ -123,7 +148,7 @@ public class KmlHandler extends XmlHandler
 			{
 				// Add single point to list
 				final String name = (isSingleSelection ? _name : null);
-				_pointList.add(makeStringArray(coords, name, _desc));
+				_pointList.add(makeStringArray(coords, name, _desc, _timestamp));
 				_linkList.add(_imgLink);
 			}
 			else if (numPoints > 1)
@@ -134,7 +159,7 @@ public class KmlHandler extends XmlHandler
 				{
 					if (coordArray[p] != null && coordArray[p].trim().length()>3)
 					{
-						String[] pointArray = makeStringArray(coordArray[p], null, null);
+						String[] pointArray = makeStringArray(coordArray[p], null, null, null);
 						if (firstPoint) {pointArray[5] = "1";} // start of segment flag
 						firstPoint = false;
 						_pointList.add(pointArray);
@@ -150,14 +175,17 @@ public class KmlHandler extends XmlHandler
 	 */
 	private void processGxTrack()
 	{
-		if (_whenList.size() > 0 && _whenList.size() == _whereList.size())
+		if (!_whereList.isEmpty())
 		{
+			// If the whens don't match, then throw them all away
+			if (_whenList.size() != _whereList.size()) {System.out.println("clearing!"); _whenList.clear();}
+
 			// Add each of the unnamed track points to list
 			boolean firstPoint = true;
 			final int numPoints = _whenList.size();
 			for (int p=0; p < numPoints; p++)
 			{
-				String when  = _whenList.get(p);
+				String when  = (_whenList.isEmpty() ? null : _whenList.get(p));
 				String where = _whereList.get(p);
 				if (where != null)
 				{
@@ -210,10 +238,11 @@ public class KmlHandler extends XmlHandler
 	 * @param inCoordinates coordinate string in Kml format
 	 * @param inName name of waypoint, or null if track point
 	 * @param inDesc description of waypoint, if any
+	 * @param inDesc timestamp of waypoint, if any
 	 * @return String array for point
 	 */
 	private static String[] makeStringArray(String inCoordinates,
-		String inName, String inDesc)
+		String inName, String inDesc, String inTimestamp)
 	{
 		String[] result = new String[7];
 		String[] values = inCoordinates.split(",");
@@ -223,6 +252,7 @@ public class KmlHandler extends XmlHandler
 		}
 		result[3] = inName;
 		result[4] = inDesc;
+		result[6] = inTimestamp;
 		return result;
 	}
 
diff --git a/tim/prune/load/xml/XmlHandler.java b/tim/prune/load/xml/XmlHandler.java
index b604fde..fa51ebf 100644
--- a/tim/prune/load/xml/XmlHandler.java
+++ b/tim/prune/load/xml/XmlHandler.java
@@ -22,7 +22,7 @@ public abstract class XmlHandler extends DefaultHandler
 	public abstract Field[] getFieldArray();
 
 	/**
-	 * Can be overriden (eg by gpx handler) to provide a track name list
+	 * Can be overridden (eg by gpx handler) to provide a track name list
 	 * @return track name list object if any, or null
 	 */
 	public TrackNameList getTrackNameList() {
@@ -30,7 +30,7 @@ public abstract class XmlHandler extends DefaultHandler
 	}
 
 	/**
-	 * Can be overriden (eg by gpx handler) to provide an array of links to media
+	 * Can be overridden (eg by gpx handler) to provide an array of links to media
 	 * @return array of Strings if any, or null
 	 */
 	public String[] getLinkArray() {
diff --git a/tim/prune/readme.txt b/tim/prune/readme.txt
index eae9fe3..8c92694 100644
--- a/tim/prune/readme.txt
+++ b/tim/prune/readme.txt
@@ -1,8 +1,8 @@
-GpsPrune version 17.2
-=====================
+GpsPrune version 18
+===================
 
 GpsPrune is an application for viewing, editing and managing coordinate data from GPS systems,
-including format conversion, charting and photo correlation.
+including format conversion, charting, 3d visualisation, audio and photo correlation, and online resource lookup.
 Full details can be found at http://gpsprune.activityworkshop.net/
 
 GpsPrune is copyright 2006-2015 activityworkshop.net and distributed under the terms of the Gnu GPL version 2.
@@ -17,7 +17,7 @@ Running
 =======
 
 To run GpsPrune from the jar file, simply call it from a command prompt or shell:
-   java -jar gpsprune_17.2.jar
+   java -jar gpsprune_18.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
@@ -25,21 +25,18 @@ in a file manager window to execute it.  A shortcut, menu item, alias, desktop i
 or other link can of course be made should you wish.
 
 To specify a language other than the default, use an additional parameter, eg:
-   java -jar gpsprune_17.2.jar --lang=DE
+   java -jar gpsprune_18.jar --lang=DE
 
 
-New with version 17.2
-=====================
-The following fixes were added since version 17.1:
-  - Speed up the cache management dialog
-  - Translation improvements
-
-New with version 17.1
-=====================
-The following fixes were added since version 17:
-  - Fix the decimal precision of coordinates calculated by interpolation and averaging
-  - Fix the selection adjustment when midpoints within the selection are dragged
-  - Minor translation improvements
+New with version 18
+===================
+The following features were added since version 17:
+  - New search options using opencaching.de and mapillary
+  - New web options using peakfinder, geohack and panoramio
+  - Autoplay function for automatically scrolling through the track
+  - Marking uphill lift sections of skiing / snowboarding tracks
+  - Configurable anti-aliasing for map view and profile view
+  - Allow showing just the lines between track points but not the track points
 
 New with version 17
 ===================
@@ -50,7 +47,7 @@ The following features were added since version 16:
   - Select the current segment
   - Adding an altitude tolerance to the climb and descent calculations
   - Sorting waypoints by name or by timestamp
-  
+
 New with version 16
 ===================
 The following features were added since version 15:
@@ -244,7 +241,7 @@ Further information and updates
 ===============================
 
 To obtain the source code (if it wasn't included in your jar file), or for further information,
-please visit the website:  http://activityworkshop.net/
+please visit the website:  http://gpsprune.activityworkshop.net/
 
 You will find there user guides, screenshots and demo videos illustrating the major features.
 As GpsPrune is further developed, subsequent versions of the program will also be made freely
diff --git a/tim/prune/save/BaseImageConfigDialog.java b/tim/prune/save/BaseImageConfigDialog.java
index 0265569..8e7e9ae 100644
--- a/tim/prune/save/BaseImageConfigDialog.java
+++ b/tim/prune/save/BaseImageConfigDialog.java
@@ -471,7 +471,7 @@ public class BaseImageConfigDialog implements Runnable
 		{
 			_previewPanel.setImage(groutedImage);
 			final int numTilesRemaining = groutedImage.getNumTilesTotal() - groutedImage.getNumTilesUsed();
-			final boolean offerDownload = numTilesRemaining > 0 && numTilesRemaining < 50;
+			final boolean offerDownload = numTilesRemaining > 0 && numTilesRemaining < 50 && Config.getConfigBoolean(Config.KEY_ONLINE_MODE);
 			// Set values of labels
 			_downloadTilesButton.setVisible(offerDownload);
 			_downloadTilesButton.setEnabled(offerDownload);
@@ -502,6 +502,7 @@ public class BaseImageConfigDialog implements Runnable
 		try {
 			zoomLevel = Integer.parseInt(_zoomDropdown.getSelectedItem().toString());
 		}
+		catch (NullPointerException npe) {}
 		catch (Exception e) {
 			System.err.println("Exception: " + e.getClass().getName() + " : " + e.getMessage());
 		}
diff --git a/tim/prune/save/FileSaver.java b/tim/prune/save/FileSaver.java
index ecf61d3..1e199d9 100644
--- a/tim/prune/save/FileSaver.java
+++ b/tim/prune/save/FileSaver.java
@@ -102,17 +102,25 @@ public class FileSaver
 			_dialog.getContentPane().add(makeDialogComponents());
 			_dialog.pack();
 		}
+		// Has the track got media?
+		final boolean hasMedia = _app.getTrackInfo().getPhotoList().hasCorrelatedPhotos()
+			|| _app.getTrackInfo().getAudioList().hasCorrelatedAudios();
 		// Check field list
 		Track track = _app.getTrackInfo().getTrack();
 		FieldList fieldList = track.getFieldList();
 		int numFields = fieldList.getNumFields();
-		_model = new FieldSelectionTableModel(numFields);
+		_model = new FieldSelectionTableModel(numFields + (hasMedia ? 1 : 0));
 		for (int i=0; i<numFields; i++)
 		{
 			Field field = fieldList.getField(i);
 			FieldInfo info = new FieldInfo(field, track.hasData(field));
 			_model.addFieldInfo(info, i);
 		}
+		// Add a field for photos / audio if any present
+		if (hasMedia)
+		{
+			_model.addFieldInfo(new FieldInfo(Field.MEDIA_FILENAME, true), numFields);
+		}
 		// Initialise dialog and show it
 		initDialog(_model, inDefaultDelimiter);
 		_dialog.setVisible(true);
@@ -599,6 +607,13 @@ public class FileSaver
 				inBuffer.append(inPoint.getTimestamp().getText(inTimestampFormat));
 			}
 		}
+		else if (inField == Field.MEDIA_FILENAME)
+		{
+			if (inPoint.hasMedia())
+			{
+				inBuffer.append(inPoint.getMediaName());
+			}
+		}
 		else
 		{
 			String value = inPoint.getFieldValue(inField);
diff --git a/tim/prune/save/GpxExporter.java b/tim/prune/save/GpxExporter.java
index 0f038b7..584d9ba 100644
--- a/tim/prune/save/GpxExporter.java
+++ b/tim/prune/save/GpxExporter.java
@@ -539,7 +539,11 @@ public class GpxExporter extends GenericFunction implements Runnable
 		if (inPoint.isWaypoint())
 		{
 			source = replaceGpxTags(source, "<name>", "</name>", inPoint.getWaypointName());
-			source = replaceGpxTags(source, "<description>", "</description>",
+			if (source != null)
+			{
+				source = source.replaceAll("<description>", "<desc>").replaceAll("</description>", "</desc>");
+			}
+			source = replaceGpxTags(source, "<desc>", "</desc>",
 				XmlUtils.fixCdata(inPoint.getFieldValue(Field.DESCRIPTION)));
 		}
 		// photo / audio links
@@ -696,9 +700,9 @@ public class GpxExporter extends GenericFunction implements Runnable
 		String desc = XmlUtils.fixCdata(inPoint.getFieldValue(Field.DESCRIPTION));
 		if (desc != null && !desc.equals(""))
 		{
-			inWriter.write("\t\t<description>");
+			inWriter.write("\t\t<desc>");
 			inWriter.write(desc);
-			inWriter.write("</description>\n");
+			inWriter.write("</desc>\n");
 		}
 		// Media links, if any
 		if (inPhoto && inPoint.getPhoto() != null)
diff --git a/tim/prune/threedee/TerrainHelper.java b/tim/prune/threedee/TerrainHelper.java
index 16e63ed..ffe9db8 100644
--- a/tim/prune/threedee/TerrainHelper.java
+++ b/tim/prune/threedee/TerrainHelper.java
@@ -371,6 +371,7 @@ public class TerrainHelper
 				// System.out.println("Averaging values " + alt1.getMetricValue() + " and " + alt2.getMetricValue());
 				int newAltitude = (int) ((alt1.getMetricValue() + alt2.getMetricValue()) / 2.0);
 				corner.setFieldValue(Field.ALTITUDE, "" + newAltitude, false);
+				// TODO: Check forcing metres?  Is there a nicer way?
 			}
 		}
 	}
@@ -394,14 +395,19 @@ public class TerrainHelper
 				if (prevIndexWithAlt >= 0 && prevIndexWithAlt < (i-1))
 				{
 					final int gapLen = i - prevIndexWithAlt;
-					final double alt1 = inTerrainTrack.getPoint(prevIndexWithAlt).getAltitude().getMetricValue();
-					final double alt2 = inTerrainTrack.getPoint(i).getAltitude().getMetricValue();
+					final int cellIndex1 = inCornerIndex + prevIndexWithAlt * inInc;
+					final double alt1 = inTerrainTrack.getPoint(cellIndex1).getAltitude().getMetricValue();
+					final int cellIndex2 = inCornerIndex + i * inInc;
+					final double alt2 = inTerrainTrack.getPoint(cellIndex2).getAltitude().getMetricValue();
+					//System.out.println("Altitude along edge goes from " + alt1 + " (at " + prevIndexWithAlt + ") to " +
+					//		alt2 + " (at " + i + ")");
 					for (int j = 1; j < gapLen; j++)
 					{
-						// System.out.println("Fill in " + (prevIndexWithAlt + j) + " using " + prevIndexWithAlt + " and " + i);
 						final double alt = alt1 + (alt2-alt1) * j / gapLen;
+						//System.out.println("Fill in " + (prevIndexWithAlt + j) + "(" + (inCornerIndex + (prevIndexWithAlt + j) * inInc) + ")  with alt " + (int) alt);
 						final DataPoint p = inTerrainTrack.getPoint(inCornerIndex + (prevIndexWithAlt + j) * inInc);
 						p.setFieldValue(Field.ALTITUDE, "" + (int) alt, false);
+						// TODO: Check forcing metres?
 					}
 				}
 				prevIndexWithAlt = i;
@@ -415,7 +421,7 @@ public class TerrainHelper
 	 */
 	private void fixBiggerHoles(Track inTerrainTrack)
 	{
-		double[] altitudes = new double[inTerrainTrack.getNumPoints()];
+		TerrainPatch patch = new TerrainPatch(_gridSize);
 		for (int i=0; i<_gridSize; i++)
 		{
 			int prevHoriz = -1, prevVert = -1;
@@ -425,18 +431,13 @@ public class TerrainHelper
 				{
 					if (prevHoriz > -1 && prevHoriz != (j-1))
 					{
-//						System.out.println("Found a gap for y=" + i +" between x=" + prevHoriz + " and " + j + " (" + (j-prevHoriz-1) + ")");
+						//System.out.println("Found a gap for y=" + i +" between x=" + prevHoriz + " and " + j + " (" + (j-prevHoriz-1) + ")");
 						double startVal = inTerrainTrack.getPoint(i * _gridSize + prevHoriz).getAltitude().getMetricValue();
 						double endVal   = inTerrainTrack.getPoint(i * _gridSize + j).getAltitude().getMetricValue();
 						for (int k=prevHoriz + 1; k< j; k++)
 						{
 							double val = startVal + (k-prevHoriz) * (endVal-startVal) / (j-prevHoriz);
-							if (altitudes[i * _gridSize + k] > 0.0) {
-								altitudes[i * _gridSize + k] = (altitudes[i * _gridSize + k] + val) / 2.0;
-							}
-							else {
-								altitudes[i * _gridSize + k] = val;
-							}
+							patch.addAltitude(i * _gridSize + k, val, k-prevHoriz, j-prevHoriz);
 						}
 					}
 					prevHoriz = j;
@@ -445,32 +446,31 @@ public class TerrainHelper
 				{
 					if (prevVert > -1 && prevVert != (j-1))
 					{
-//						System.out.println("Found a gap for x=" + i +" between y=" + prevVert + " and " + j + " (" + (j-prevVert-1) + ")");
+						//System.out.println("Found a gap for x=" + i +" between y=" + prevVert + " and " + j + " (" + (j-prevVert-1) + ")");
 						double startVal = inTerrainTrack.getPoint(prevVert * _gridSize + i).getAltitude().getMetricValue();
 						double endVal   = inTerrainTrack.getPoint(j * _gridSize + i).getAltitude().getMetricValue();
 						for (int k=prevVert + 1; k< j; k++)
 						{
 							double val = startVal + (k-prevVert) * (endVal-startVal) / (j-prevVert);
-							if (altitudes[k * _gridSize + i] > 0.0) {
-								altitudes[k * _gridSize + i] = (altitudes[k * _gridSize + i] + val) / 2.0;
-							}
-							else {
-								altitudes[k * _gridSize + i] = val;
-							}
+							patch.addAltitude(k * _gridSize + i, val, k-prevVert, j-prevVert);
 						}
 					}
 					prevVert = j;
 				}
 			}
 		}
-		// Now the doubles have been set and/or averaged, we can set the values in the points
+		// Smooth the patch to reduce the blocky effect from the voids
+		patch.smooth();
+
+		// Now the doubles have been set and averaged, we can set the values in the points
 		for (int i=0; i<inTerrainTrack.getNumPoints(); i++)
 		{
 			DataPoint p = inTerrainTrack.getPoint(i);
-			if (!p.hasAltitude() && altitudes[i] > 0.0)
+			if (!p.hasAltitude())
 			{
-				p.setFieldValue(Field.ALTITUDE, "" + altitudes[i], false);
-				p.getAltitude().reset(new Altitude((int) altitudes[i], UnitSetLibrary.UNITS_METRES));
+				final double altitude = patch.getAltitude(i);
+				p.setFieldValue(Field.ALTITUDE, "" + altitude, false);
+				p.getAltitude().reset(new Altitude((int) altitude, UnitSetLibrary.UNITS_METRES));
 			}
 		}
 	}
diff --git a/tim/prune/threedee/TerrainPatch.java b/tim/prune/threedee/TerrainPatch.java
new file mode 100644
index 0000000..10f0b6e
--- /dev/null
+++ b/tim/prune/threedee/TerrainPatch.java
@@ -0,0 +1,116 @@
+package tim.prune.threedee;
+
+public class TerrainPatch
+{
+	private int      _gridSize = 0;
+	private double[] _altitudes = null;
+	private int[]    _tempDists = null;
+
+	/**
+	 * Constructor
+	 * @param inGridSize size of grid edge
+	 */
+	public TerrainPatch(int inGridSize)
+	{
+		_gridSize = inGridSize;
+		int numNodes = inGridSize * inGridSize;
+		_altitudes = new double[numNodes];
+		_tempDists = new int[numNodes];
+	}
+
+	/**
+	 * Add an altitude interpolation to the mix
+	 * @param inPointIndex point index to array
+	 * @param inValue altitude value in metres
+	 * @param inGapIndex index of point within gap, from 1 to gapLength-1
+	 * @param inGapLength length of gap, minimum 2
+	 */
+	public void addAltitude(int inPointIndex, double inValue, int inGapIndex, int inGapLength)
+	{
+		final int dist = Math.min(inGapIndex, inGapLength-inGapIndex);
+		if (_tempDists[inPointIndex] == 0)
+		{
+			if (_altitudes[inPointIndex] > 0.0) System.err.println("Altitude shouldn't be 0 if dist is 0!");
+			// first point
+			_altitudes[inPointIndex] = inValue;
+			_tempDists[inPointIndex] = dist;
+		}
+		else
+		{
+			// second point
+			final double firstValue = _altitudes[inPointIndex];
+			final int firstDist     = _tempDists[inPointIndex];
+			final double firstWeight = dist * 1.0 / (dist + firstDist);
+			final double secondWeight= firstDist * 1.0 / (dist + firstDist);
+			_altitudes[inPointIndex] = firstWeight * firstValue + secondWeight * inValue;
+			_tempDists[inPointIndex] = 0;
+		}
+	}
+
+	/**
+	 * Smooth the patch to reduce blockiness
+	 */
+	public void smooth()
+	{
+		double[] altCopy = new double[_altitudes.length];
+		for (int i=0; i<_gridSize; i++)
+		{
+			for (int j=0; j<_gridSize; j++)
+			{
+				if (hasAltitude(i, j) && hasAltitude(i-1, j) && hasAltitude(i+1, j)
+					&& hasAltitude(i, j+1) && hasAltitude(i-1, j+1) && hasAltitude(i+1, j+1)
+					&& hasAltitude(i, j-1) && hasAltitude(i-1, j-1) && hasAltitude(i+1, j-1))
+				{
+					// got a 3x3 square, can do a blur
+					double alt = (getAltitude(i, j) + getAltitude(i-1, j) + getAltitude(i+1, j)
+						+ getAltitude(i, j+1) + getAltitude(i-1, j+1) + getAltitude(i+1, j+1)
+						+ getAltitude(i, j-1) + getAltitude(i-1, j-1) + getAltitude(i+1, j-1)) / 9.0;
+					altCopy[i * _gridSize + j] = alt;
+				}
+			}
+		}
+		// Copy results back
+		for (int k=0; k<altCopy.length; k++)
+		{
+			if (altCopy[k] > 0.0)
+			{
+				_altitudes[k] = altCopy[k];
+			}
+		}
+	}
+
+	/**
+	 * @param inI first index
+	 * @param inJ second index
+	 * @return true if there is an altitude in the patch in this position
+	 */
+	private boolean hasAltitude(int inI, int inJ)
+	{
+		return inI >= 0 && inI < _gridSize && inJ >= 0 && inJ < _gridSize
+			&& _altitudes[inI * _gridSize + inJ] > 0.0;
+	}
+
+	/**
+	 * @param inI first index
+	 * @param inJ second index
+	 * @return true if there is an altitude in the patch in this position
+	 */
+	private double getAltitude(int inI, int inJ)
+	{
+		if (inI >= 0 && inI < _gridSize && inJ >= 0 && inJ < _gridSize)
+		{
+			return _altitudes[inI * _gridSize + inJ];
+		}
+		return 0.0;
+	}
+
+	/**
+	 * @param inPointIndex point index
+	 * @return altitude value
+	 */
+	public double getAltitude(int inPointIndex)
+	{
+		if (_tempDists[inPointIndex] != 0) System.err.println("Dists should be 0 if we're retrieving!");
+		return _altitudes[inPointIndex];
+	}
+}
diff --git a/tim/prune/undo/UndoStack.java b/tim/prune/undo/UndoStack.java
index bca92b1..d3e85e0 100644
--- a/tim/prune/undo/UndoStack.java
+++ b/tim/prune/undo/UndoStack.java
@@ -3,22 +3,60 @@ package tim.prune.undo;
 import java.util.Stack;
 
 /**
- * Stack of undo operations
- * which also remembers how many times it's been cleared
+ * Class to hold an undo operation together with a counter
  */
-public class UndoStack extends Stack<UndoOperation>
+class UndoOpWithState
 {
-	private int _numTimesDeleted = 0;
-
-	/** @return number of times this stack has been deleted */
-	public int getNumTimesDeleted() {
-		return _numTimesDeleted;
+	public UndoOperation _undoOperation = null;
+	public int           _undoCounter = 0;
+	/** Constructor */
+	public UndoOpWithState(UndoOperation inOp, int inCounter)
+	{
+		_undoOperation = inOp;
+		_undoCounter   = inCounter;
 	}
+}
+
+/**
+ * Stack of undo operations
+ * which also remembers how many undos have been performed
+ */
+public class UndoStack extends Stack<UndoOpWithState>
+{
+	/** Number of undos (and clears) already performed */
+	private int _numUndos = 0;
 
 	@Override
 	public void clear()
 	{
-		_numTimesDeleted++;
+		_numUndos++;
 		super.clear();
 	}
+
+	/** Add an undo operation to the stack */
+	public synchronized boolean add(UndoOperation inOp)
+	{
+		return super.add(new UndoOpWithState(inOp, _numUndos));
+	}
+
+	/** Pop the latest operation from the stack */
+	public synchronized UndoOperation popOperation()
+	{
+		_numUndos++;
+		return super.pop()._undoOperation;
+	}
+
+	/** Get the operation at the given index */
+	public UndoOperation getOperationAt(int inIndex)
+	{
+		return super.elementAt(inIndex)._undoOperation;
+	}
+
+	/** @return number of undos */
+	public int getNumUndos()
+	{
+		if (isEmpty()) {return 0;}
+		// Get the number of undos stored by the last operation on the stack
+		return peek()._undoCounter;
+	}
 }

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-grass/gpsprune.git



More information about the Pkg-grass-devel mailing list