Index: applications/editors/josm/plugins/ElevationProfile/src/org/openstreetmap/josm/plugins/elevation/ColorMap.java
===================================================================
--- applications/editors/josm/plugins/ElevationProfile/src/org/openstreetmap/josm/plugins/elevation/ColorMap.java	(revision 30736)
+++ applications/editors/josm/plugins/ElevationProfile/src/org/openstreetmap/josm/plugins/elevation/ColorMap.java	(revision 30737)
@@ -16,176 +16,176 @@
  */
 public class ColorMap {
-    private List<ColorMapEntry> colorList;
-    private String name;
-    private static HashMap<String, ColorMap> colorMaps;
+	private List<ColorMapEntry> colorList;
+	private String name;
+	private static HashMap<String, ColorMap> colorMaps;
 
-    static {
-        colorMaps = new HashMap<String, ColorMap>();
-    }
+	static {
+		colorMaps = new HashMap<>();
+	}
 
-    // Private ctor to enforce use of create
-    private ColorMap() {
-    }
+	// Private ctor to enforce use of create
+	private ColorMap() {
+	}
 
-    public String getName() {
-        return name;
-    }
+	public String getName() {
+		return name;
+	}
 
-    public void setName(String name) {
-        this.name = name;
-    }
+	public void setName(String name) {
+		this.name = name;
+	}
 
-    /**
-     * Gets the color according to the given elevation value.
-     *
-     * @param elevation the elevation
-     * @return the color
-     */
-    public Color getColor(int elevation) {
-        // empty color map?
-        if (colorList == null || colorList.size() == 0) {
-            return Color.white;
-        }
+	/**
+	 * Gets the color according to the given elevation value.
+	 *
+	 * @param elevation the elevation
+	 * @return the color
+	 */
+	public Color getColor(int elevation) {
+		// empty color map?
+		if (colorList == null || colorList.size() == 0) {
+			return Color.white;
+		}
 
-        // out of range?
-        if (elevation < colorList.get(0).ele) {
-            return colorList.get(0).getColor();
-        }
+		// out of range?
+		if (elevation < colorList.get(0).ele) {
+			return colorList.get(0).getColor();
+		}
 
-        int last = colorList.size() - 1;
-        if (elevation > colorList.get(last).ele) {
-            return colorList.get(last).getColor();
-        }
+		int last = colorList.size() - 1;
+		if (elevation > colorList.get(last).ele) {
+			return colorList.get(last).getColor();
+		}
 
-        // find elevation section
-        for (int i = 0; i < last; i++) {
-            ColorMapEntry e1 = colorList.get(i);
-            ColorMapEntry e2 = colorList.get(i + 1);
+		// find elevation section
+		for (int i = 0; i < last; i++) {
+			ColorMapEntry e1 = colorList.get(i);
+			ColorMapEntry e2 = colorList.get(i + 1);
 
-            // elevation within range?
-            if (e1.getEle() <= elevation && e2.getEle() >= elevation) {
+			// elevation within range?
+			if (e1.getEle() <= elevation && e2.getEle() >= elevation) {
 
-                // interpolate color between both
-                double val = (elevation - e1.getEle()) / (double)(e2.getEle() - e1.getEle());
-                return interpolate(e1.getColor(), e2.getColor(), val);
-            }
-        }
+				// interpolate color between both
+				double val = (elevation - e1.getEle()) / (double)(e2.getEle() - e1.getEle());
+				return interpolate(e1.getColor(), e2.getColor(), val);
+			}
+		}
 
-        // here we should never end!
-        throw new RuntimeException("Inconsistent color map - found no entry for elevation " + elevation);
-    }
+		// here we should never end!
+		throw new RuntimeException("Inconsistent color map - found no entry for elevation " + elevation);
+	}
 
 
-    /**
-     * Gets the color map with the given name.
-     *
-     * @param name the name
-     * @return the map or <code>null</code>, if no such map exists
-     */
-    public static ColorMap getMap(String name) {
-        if (colorMaps.containsKey(name)) {
-            return colorMaps.get(name);
-        }
-        return null;
-    }
+	/**
+	 * Gets the color map with the given name.
+	 *
+	 * @param name the name
+	 * @return the map or <code>null</code>, if no such map exists
+	 */
+	public static ColorMap getMap(String name) {
+		if (colorMaps.containsKey(name)) {
+			return colorMaps.get(name);
+		}
+		return null;
+	}
 
-    /**
-     * Gets the number of available color maps.
-     *
-     * @return the int
-     */
-    public static int size() {
-        return colorMaps != null ? colorMaps.size() : 0;
-    }
+	/**
+	 * Gets the number of available color maps.
+	 *
+	 * @return the int
+	 */
+	public static int size() {
+		return colorMaps != null ? colorMaps.size() : 0;
+	}
 
 
-    /**
-     * Gets the available color map names.
-     *
-     * @param name the name
-     * @return the map or <code>null</code>, if no such map exists
-     */
-    public static String[] getNames() {
-        return colorMaps.keySet().toArray(new String[size()]);
-    }
+	/**
+	 * Gets the available color map names.
+	 *
+	 * @param name the name
+	 * @return the map or <code>null</code>, if no such map exists
+	 */
+	public static String[] getNames() {
+		return colorMaps.keySet().toArray(new String[size()]);
+	}
 
-    private static void registerColorMap(ColorMap newMap) {
-        CheckParameterUtil.ensureParameterNotNull(newMap);
-        colorMaps.put(newMap.getName(), newMap);
-    }
+	private static void registerColorMap(ColorMap newMap) {
+		CheckParameterUtil.ensureParameterNotNull(newMap);
+		colorMaps.put(newMap.getName(), newMap);
+	}
 
-    public static void unregisterColorMap(String name) {
-        if (colorMaps.containsKey(name)) {
-            colorMaps.remove(name);
-        }
-    }
+	public static void unregisterColorMap(String name) {
+		if (colorMaps.containsKey(name)) {
+			colorMaps.remove(name);
+		}
+	}
 
-    public static Color interpolate(java.awt.Color c1, java.awt.Color c2, double ratio) {
-        double r1 = 1 -ratio;
-        // clip
-        if (r1 < 0) r1 = 0d;
-        if (r1 > 1) r1 = 1d;
-        double r2 = 1 - r1;
+	public static Color interpolate(java.awt.Color c1, java.awt.Color c2, double ratio) {
+		double r1 = 1 -ratio;
+		// clip
+		if (r1 < 0) r1 = 0d;
+		if (r1 > 1) r1 = 1d;
+		double r2 = 1 - r1;
 
-        int r = (int) Math.round((r1 * c1.getRed()) + (r2 * c2.getRed()));
-        int g = (int) Math.round((r1 * c1.getGreen()) + (r2 * c2.getGreen()));
-        int b = (int) Math.round((r1 * c1.getBlue()) + (r2 * c2.getBlue()));
-        return new Color(r, g, b);
-    }
+		int r = (int) Math.round((r1 * c1.getRed()) + (r2 * c2.getRed()));
+		int g = (int) Math.round((r1 * c1.getGreen()) + (r2 * c2.getGreen()));
+		int b = (int) Math.round((r1 * c1.getBlue()) + (r2 * c2.getBlue()));
+		return new Color(r, g, b);
+	}
 
-    /**
-     * Creates a color map using the given colors/elevation values.
-     * Both arrays must have same length.
-     *
-     * @param name the name of the color map
-     * @param colors the array containing the colors
-     * @param ele the elevation values
-     * @return the color map
-     */
-    public static ColorMap create(String name, Color[] colors, int[] ele) {
-        CheckParameterUtil.ensureParameterNotNull(colors);
-        CheckParameterUtil.ensureParameterNotNull(ele);
+	/**
+	 * Creates a color map using the given colors/elevation values.
+	 * Both arrays must have same length.
+	 *
+	 * @param name the name of the color map
+	 * @param colors the array containing the colors
+	 * @param ele the elevation values
+	 * @return the color map
+	 */
+	public static ColorMap create(String name, Color[] colors, int[] ele) {
+		CheckParameterUtil.ensureParameterNotNull(colors);
+		CheckParameterUtil.ensureParameterNotNull(ele);
 
-        if (colors.length != ele.length) {
-            throw new IllegalArgumentException("Arrays colors and ele must have same length: " + colors.length + " vs " + ele.length);
-        }
+		if (colors.length != ele.length) {
+			throw new IllegalArgumentException("Arrays colors and ele must have same length: " + colors.length + " vs " + ele.length);
+		}
 
-        ColorMap map = new ColorMap();
-        map.colorList = new ArrayList<ColorMap.ColorMapEntry>();
-        map.name = name;
-        for (int i = 0; i < ele.length; i++) {
-            map.colorList.add(map.new ColorMapEntry(colors[i], ele[i]));
-        }
+		ColorMap map = new ColorMap();
+		map.colorList = new ArrayList<>();
+		map.name = name;
+		for (int i = 0; i < ele.length; i++) {
+			map.colorList.add(map.new ColorMapEntry(colors[i], ele[i]));
+		}
 
-        // sort by elevation
-        Collections.sort(map.colorList);
+		// sort by elevation
+		Collections.sort(map.colorList);
 
-        registerColorMap(map);
-        return map;
-    }
+		registerColorMap(map);
+		return map;
+	}
 
 
-    class ColorMapEntry implements Comparable<ColorMapEntry> {
-        private final int ele; // limit
-        private final Color color;
+	class ColorMapEntry implements Comparable<ColorMapEntry> {
+		private final int ele; // limit
+		private final Color color;
 
-        public ColorMapEntry(Color color, int ele) {
-            super();
-            this.color = color;
-            this.ele = ele;
-        }
+		public ColorMapEntry(Color color, int ele) {
+			super();
+			this.color = color;
+			this.ele = ele;
+		}
 
-        public int getEle() {
-            return ele;
-        }
+		public int getEle() {
+			return ele;
+		}
 
-        public Color getColor() {
-            return color;
-        }
+		public Color getColor() {
+			return color;
+		}
 
-        @Override
-        public int compareTo(ColorMapEntry o) {
-            return this.ele - o.ele;
-        }
-    }
+		@Override
+		public int compareTo(ColorMapEntry o) {
+			return this.ele - o.ele;
+		}
+	}
 }
Index: applications/editors/josm/plugins/ElevationProfile/src/org/openstreetmap/josm/plugins/elevation/ElevationHelper.java
===================================================================
--- applications/editors/josm/plugins/ElevationProfile/src/org/openstreetmap/josm/plugins/elevation/ElevationHelper.java	(revision 30736)
+++ applications/editors/josm/plugins/ElevationProfile/src/org/openstreetmap/josm/plugins/elevation/ElevationHelper.java	(revision 30737)
@@ -19,282 +19,282 @@
  */
 public class ElevationHelper {
-    public static double METER_TO_FEET = 3.280948;
-
-    /* Countries which use the imperial system instead of the metric system. */
-    private static String IMPERIAL_SYSTEM_COUNTRIES[] = {
-        "en_US",     /* USA */
-        "en_CA",    /* Canada */
-        "en_AU",    /* Australia */
-        "en_NZ",    /* New Zealand */
-        //        "de_DE",    /* for testing only */
-        "en_ZA"    /* South Africa */
-    };
-
-    /** The 'no elevation' data magic. */
-    public static double NO_ELEVATION = Double.NaN;
-
-    /**
-     * The name of the elevation height of a way point.
-     */
-    public static final String HEIGHT_ATTRIBUTE = "ele";
-
-    private static UnitMode unitMode = UnitMode.NotSelected;
-
-    private static GeoidCorrectionKind geoidKind = GeoidCorrectionKind.None;
-
-    /** The HGT reader instance. */
-    private static HgtReader hgt = new HgtReader();
-
-    /**
-     * Gets the current mode of GEOID correction.
-     * @return
-     */
-    public static GeoidCorrectionKind getGeoidKind() {
-        return geoidKind;
-    }
-
-    public static void setGeoidKind(GeoidCorrectionKind geoidKind) {
-        ElevationHelper.geoidKind = geoidKind;
-    }
-
-    /**
-     * Gets the current unit mode (metric or imperial).
-     * @return
-     */
-    public static UnitMode getUnitMode() {
-        //TODO: Use this until /JOSM/src/org/openstreetmap/josm/gui/NavigatableComponent.java
-        // has a an appropriate method
-
-        // unit mode already determined?
-        if (unitMode != UnitMode.NotSelected) {
-            return unitMode;
-        }
-
-        // Set default
-        unitMode = UnitMode.Metric;
-
-        // Check if user could prefer imperial system
-        Locale l = Locale.getDefault();
-        for (int i = 0; i < IMPERIAL_SYSTEM_COUNTRIES.length; i++) {
-            String ctry = l.toString();
-            if (IMPERIAL_SYSTEM_COUNTRIES[i].equals(ctry)) {
-                unitMode = UnitMode.Imperial;
-            }
-        }
-
-        return unitMode;
-    }
-
-    /**
-     * Gets the unit string for elevation ("m" or "ft").
-     * @return
-     */
-    public static String getUnit() {
-        switch (getUnitMode()) {
-        case Metric:
-            return "m";
-        case Imperial:
-            return "ft";
-        default:
-            throw new RuntimeException("Invalid or unsupported unit mode: " + unitMode);
-        }
-    }
-
-    /**
-     * Checks if given value is a valid elevation value.
-     *
-     * @param ele the ele
-     * @return true, if is valid elevation
-     */
-    public static boolean isValidElevation(double ele) {
-        return !Double.isNaN(ele);
-    }
-
-    /**
-     * Gets the elevation (Z coordinate) of a GPX way point in meter or feet (for
-     * US, UK, ZA, AU, NZ and CA).
-     * 
-     * @param wpt
-     *            The way point instance.
-     * @return The x coordinate or <code>NO_ELEVATION</code>, if the given way point is null or contains
-     *         not height attribute.
-     */
-    public static double getElevation(WayPoint wpt) {
-        if (wpt == null) return NO_ELEVATION;
-
-        // try to get elevation from HGT file
-        double eleInt = getSrtmElevation(wpt.getCoor());
-        if (isValidElevation(eleInt)) {
-            return convert(eleInt);
-        }
-
-        // no HGT, check for elevation data in GPX
-        if (!wpt.attr.containsKey(HEIGHT_ATTRIBUTE)) {
-            // GPX has no elevation data :-(
-            return NO_ELEVATION;
-        }
-
-        // Parse elevation from GPX data
-        String height = wpt.getString(ElevationHelper.HEIGHT_ATTRIBUTE);
-        try {
-            double z = Double.parseDouble(height);
-
-            return convert(z);
-        } catch (NumberFormatException e) {
-            System.err.println(String.format(
-                    "Cannot parse double from '%s': %s", height, e
-                    .getMessage()));
-            return NO_ELEVATION;
-        }
-    }
-
-
-    private static double getElevation(LatLon ll) {
-        double ele = getSrtmElevation(ll);
-        //System.out.println("Get elevation " + ll + " => " + ele);
-        return convert(ele);
-    }
-
-    /**
-     * Converts the value to feet, if required.
-     *
-     * @param ele the elevation to convert
-     * @return the double
-     */
-    private static double convert(double ele) {
-        if (isValidElevation(ele)) {
-            if (getUnitMode() == UnitMode.Imperial) {
-                // translate to feet
-                return meter2Feet(ele);
-            } else {
-                // keep 'as is'
-                return ele;
-            }
-        }
-        return NO_ELEVATION;
-    }
-
-    /**
-     * Computes the slope <b>in percent</b> between two way points. E. g. an elevation gain of 12m
-     * within a distance of 100m is equal to a slope of 12%.
-     *
-     * @param w1 the first way point
-     * @param w2 the second way point
-     * @return the slope in percent
-     */
-    public static double computeSlope(LatLon w1, LatLon w2) {
-        // same coordinates? -> return 0, if yes
-        if (w1.equals(w2)) return 0;
-
-        // get distance in meters and divide it by 100 in advance
-        double distInMeter = convert(w1.greatCircleDistance(w2) / 100.0);
-
-        // get elevation (difference) - is converted automatically to feet
-        int ele1 = (int) ElevationHelper.getElevation(w1);
-        int ele2 = (int) ElevationHelper.getElevation(w2);
-        int dH = ele2 - ele1;
-
-        // Slope in percent is define as elevation gain/loss in meters related to a distance of 100m
-        return dH / distInMeter;
-    }
-
-    /**
-     * Converts meter into feet
-     *
-     * @param meter the meter
-     * @return the double
-     */
-    public static double meter2Feet(double meter) {
-        return meter * METER_TO_FEET;
-    }
-
-    /**
-     * Gets the elevation string for a given elevation, e. g "300m" or "800ft".
-     * @param elevation
-     * @return
-     */
-    public static String getElevationText(int elevation) {
-        return String.format("%d %s", elevation, getUnit());
-    }
-
-    /**
-     * Gets the elevation string for a given elevation, e. g "300m" or "800ft".
-     * @param elevation
-     * @return
-     */
-    public static String getElevationText(double elevation) {
-        return String.format("%d %s", (int)Math.round(elevation), getUnit());
-    }
-
-    /**
-     * Gets the elevation string for a given way point, e. g "300m" or "800ft".
-     *
-     * @param wpt the way point
-     * @return the elevation text
-     */
-    public static String getElevationText(WayPoint wpt) {
-        if (wpt == null) return "-";
-
-        int elevation = (int)Math.round(ElevationHelper.getElevation(wpt));
-        return String.format("%d %s", elevation, getUnit());
-    }
-
-    /**
-     * Get the time string for a given way point.
-     * @param wpt
-     * @return
-     */
-    public static String getTimeText(WayPoint wpt) {
-        if (wpt == null) return null;
-
-        int hour = ElevationHelper.getHourOfWayPoint(wpt);
-        int min = ElevationHelper.getMinuteOfWayPoint(wpt);
-        return String.format("%02d:%02d", hour, min);
-    }
-
-    /**
-     * Gets the SRTM elevation (Z coordinate) of the given coordinate.
-     * 
-     * @param ll
-     *            The coordinate.
-     * @return The z coordinate or {@link Double#NaN}, if elevation value could not be obtained
-     *         not height attribute.
-     */
-    public static double getSrtmElevation(LatLon ll) {
-        if (ll != null) {
-            // Try to read data from SRTM file
-            // TODO: Option to switch this off
-            double eleHgt = hgt.getElevationFromHgt(ll);
-
-            //System.out.println("Get elevation from HGT " + ll + " => " + eleHgt);
-            if (isValidElevation(eleHgt)) {
-                return eleHgt;
-            }
-        }
-        return NO_ELEVATION;
-    }
-
-    /**
-     * Checks given area for SRTM data.
-     *
-     * @param bounds the bounds/area to check
-     * @return true, if SRTM data are present; otherwise false
-     */
-    public static boolean hasSrtmData(Bounds bounds) {
-        if (bounds == null) return false;
-
-        LatLon tl = bounds.getMin();
-        LatLon br = bounds.getMax();
-
-        return     isValidElevation(getSrtmElevation(tl)) &&
-                isValidElevation(getSrtmElevation(br));
-    }
-
-    /*
-     * Gets the geoid height for the given way point. See also {@link
-     * GeoidData}.
-     */
-    public static byte getGeoidCorrection(WayPoint wpt) {
-        /*
+	public static double METER_TO_FEET = 3.280948;
+
+	/* Countries which use the imperial system instead of the metric system. */
+	private static String IMPERIAL_SYSTEM_COUNTRIES[] = {
+		"en_US",     /* USA */
+		"en_CA",    /* Canada */
+		"en_AU",    /* Australia */
+		"en_NZ",    /* New Zealand */
+		//        "de_DE",    /* for testing only */
+		"en_ZA"    /* South Africa */
+	};
+
+	/** The 'no elevation' data magic. */
+	public static double NO_ELEVATION = Double.NaN;
+
+	/**
+	 * The name of the elevation height of a way point.
+	 */
+	public static final String HEIGHT_ATTRIBUTE = "ele";
+
+	private static UnitMode unitMode = UnitMode.NotSelected;
+
+	private static GeoidCorrectionKind geoidKind = GeoidCorrectionKind.None;
+
+	/** The HGT reader instance. */
+	private static HgtReader hgt = new HgtReader();
+
+	/**
+	 * Gets the current mode of GEOID correction.
+	 * @return
+	 */
+	public static GeoidCorrectionKind getGeoidKind() {
+		return geoidKind;
+	}
+
+	public static void setGeoidKind(GeoidCorrectionKind geoidKind) {
+		ElevationHelper.geoidKind = geoidKind;
+	}
+
+	/**
+	 * Gets the current unit mode (metric or imperial).
+	 * @return
+	 */
+	public static UnitMode getUnitMode() {
+		//TODO: Use this until /JOSM/src/org/openstreetmap/josm/gui/NavigatableComponent.java
+		// has a an appropriate method
+
+		// unit mode already determined?
+		if (unitMode != UnitMode.NotSelected) {
+			return unitMode;
+		}
+
+		// Set default
+		unitMode = UnitMode.Metric;
+
+		// Check if user could prefer imperial system
+		Locale l = Locale.getDefault();
+		for (int i = 0; i < IMPERIAL_SYSTEM_COUNTRIES.length; i++) {
+			String ctry = l.toString();
+			if (IMPERIAL_SYSTEM_COUNTRIES[i].equals(ctry)) {
+				unitMode = UnitMode.Imperial;
+			}
+		}
+
+		return unitMode;
+	}
+
+	/**
+	 * Gets the unit string for elevation ("m" or "ft").
+	 * @return
+	 */
+	public static String getUnit() {
+		switch (getUnitMode()) {
+		case Metric:
+			return "m";
+		case Imperial:
+			return "ft";
+		default:
+			throw new RuntimeException("Invalid or unsupported unit mode: " + unitMode);
+		}
+	}
+
+	/**
+	 * Checks if given value is a valid elevation value.
+	 *
+	 * @param ele the ele
+	 * @return true, if is valid elevation
+	 */
+	public static boolean isValidElevation(double ele) {
+		return !Double.isNaN(ele);
+	}
+
+	/**
+	 * Gets the elevation (Z coordinate) of a GPX way point in meter or feet (for
+	 * US, UK, ZA, AU, NZ and CA).
+	 *
+	 * @param wpt
+	 *            The way point instance.
+	 * @return The x coordinate or <code>NO_ELEVATION</code>, if the given way point is null or contains
+	 *         not height attribute.
+	 */
+	public static double getElevation(WayPoint wpt) {
+		if (wpt == null) return NO_ELEVATION;
+
+		// try to get elevation from HGT file
+		double eleInt = getSrtmElevation(wpt.getCoor());
+		if (isValidElevation(eleInt)) {
+			return convert(eleInt);
+		}
+
+		// no HGT, check for elevation data in GPX
+		if (!wpt.attr.containsKey(HEIGHT_ATTRIBUTE)) {
+			// GPX has no elevation data :-(
+			return NO_ELEVATION;
+		}
+
+		// Parse elevation from GPX data
+		String height = wpt.getString(ElevationHelper.HEIGHT_ATTRIBUTE);
+		try {
+			double z = Double.parseDouble(height);
+
+			return convert(z);
+		} catch (NumberFormatException e) {
+			System.err.println(String.format(
+					"Cannot parse double from '%s': %s", height, e
+					.getMessage()));
+			return NO_ELEVATION;
+		}
+	}
+
+
+	private static double getElevation(LatLon ll) {
+		double ele = getSrtmElevation(ll);
+		//System.out.println("Get elevation " + ll + " => " + ele);
+		return convert(ele);
+	}
+
+	/**
+	 * Converts the value to feet, if required.
+	 *
+	 * @param ele the elevation to convert
+	 * @return the double
+	 */
+	private static double convert(double ele) {
+		if (isValidElevation(ele)) {
+			if (getUnitMode() == UnitMode.Imperial) {
+				// translate to feet
+				return meter2Feet(ele);
+			} else {
+				// keep 'as is'
+				return ele;
+			}
+		}
+		return NO_ELEVATION;
+	}
+
+	/**
+	 * Computes the slope <b>in percent</b> between two way points. E. g. an elevation gain of 12m
+	 * within a distance of 100m is equal to a slope of 12%.
+	 *
+	 * @param w1 the first way point
+	 * @param w2 the second way point
+	 * @return the slope in percent
+	 */
+	public static double computeSlope(LatLon w1, LatLon w2) {
+		// same coordinates? -> return 0, if yes
+		if (w1.equals(w2)) return 0;
+
+		// get distance in meters and divide it by 100 in advance
+		double distInMeter = convert(w1.greatCircleDistance(w2) / 100.0);
+
+		// get elevation (difference) - is converted automatically to feet
+		int ele1 = (int) ElevationHelper.getElevation(w1);
+		int ele2 = (int) ElevationHelper.getElevation(w2);
+		int dH = ele2 - ele1;
+
+		// Slope in percent is define as elevation gain/loss in meters related to a distance of 100m
+		return dH / distInMeter;
+	}
+
+	/**
+	 * Converts meter into feet
+	 *
+	 * @param meter the meter
+	 * @return the double
+	 */
+	public static double meter2Feet(double meter) {
+		return meter * METER_TO_FEET;
+	}
+
+	/**
+	 * Gets the elevation string for a given elevation, e. g "300m" or "800ft".
+	 * @param elevation
+	 * @return
+	 */
+	public static String getElevationText(int elevation) {
+		return String.format("%d %s", elevation, getUnit());
+	}
+
+	/**
+	 * Gets the elevation string for a given elevation, e. g "300m" or "800ft".
+	 * @param elevation
+	 * @return
+	 */
+	public static String getElevationText(double elevation) {
+		return String.format("%d %s", (int)Math.round(elevation), getUnit());
+	}
+
+	/**
+	 * Gets the elevation string for a given way point, e. g "300m" or "800ft".
+	 *
+	 * @param wpt the way point
+	 * @return the elevation text
+	 */
+	public static String getElevationText(WayPoint wpt) {
+		if (wpt == null) return "-";
+
+		int elevation = (int)Math.round(ElevationHelper.getElevation(wpt));
+		return String.format("%d %s", elevation, getUnit());
+	}
+
+	/**
+	 * Get the time string for a given way point.
+	 * @param wpt
+	 * @return
+	 */
+	public static String getTimeText(WayPoint wpt) {
+		if (wpt == null) return null;
+
+		int hour = ElevationHelper.getHourOfWayPoint(wpt);
+		int min = ElevationHelper.getMinuteOfWayPoint(wpt);
+		return String.format("%02d:%02d", hour, min);
+	}
+
+	/**
+	 * Gets the SRTM elevation (Z coordinate) of the given coordinate.
+	 *
+	 * @param ll
+	 *            The coordinate.
+	 * @return The z coordinate or {@link Double#NaN}, if elevation value could not be obtained
+	 *         not height attribute.
+	 */
+	public static double getSrtmElevation(LatLon ll) {
+		if (ll != null) {
+			// Try to read data from SRTM file
+			// TODO: Option to switch this off
+			double eleHgt = hgt.getElevationFromHgt(ll);
+
+			//System.out.println("Get elevation from HGT " + ll + " => " + eleHgt);
+			if (isValidElevation(eleHgt)) {
+				return eleHgt;
+			}
+		}
+		return NO_ELEVATION;
+	}
+
+	/**
+	 * Checks given area for SRTM data.
+	 *
+	 * @param bounds the bounds/area to check
+	 * @return true, if SRTM data are present; otherwise false
+	 */
+	public static boolean hasSrtmData(Bounds bounds) {
+		if (bounds == null) return false;
+
+		LatLon tl = bounds.getMin();
+		LatLon br = bounds.getMax();
+
+		return     isValidElevation(getSrtmElevation(tl)) &&
+				isValidElevation(getSrtmElevation(br));
+	}
+
+	/*
+	 * Gets the geoid height for the given way point. See also {@link
+	 * GeoidData}.
+	 */
+	public static byte getGeoidCorrection(WayPoint wpt) {
+		/*
         int lat = (int)Math.round(wpt.getCoor().lat());
         int lon = (int)Math.round(wpt.getCoor().lon());
@@ -303,66 +303,66 @@
         System.out.println(
                 String.format("Geoid(%d, %d) = %d", lat, lon, geoid));
-         */
-        return 0;
-    }
-
-    /**
-     * Reduces a given list of way points to the specified target size.
-     * 
-     * @param origList
-     *            The original list containing the way points.
-     * @param targetSize
-     *            The desired target size of the list. The resulting list may
-     *            contain fewer items, so targetSize should be considered as
-     *            maximum.
-     * @return A list containing the reduced list.
-     */
-    public static List<WayPoint> downsampleWayPoints(List<WayPoint> origList,
-            int targetSize) {
-        if (origList == null)
-            return null;
-        if (targetSize <= 0)
-            throw new IllegalArgumentException(
-                    "targetSize must be greater than zero");
-
-        int origSize = origList.size();
-        if (origSize <= targetSize) {
-            return origList;
-        }
-
-        int delta = (int) Math.max(Math.ceil(origSize / targetSize), 2);
-
-        List<WayPoint> res = new ArrayList<WayPoint>(targetSize);
-        for (int i = 0; i < origSize; i += delta) {
-            res.add(origList.get(i));
-        }
-
-        return res;
-    }
-
-    /**
-     * Gets the hour value of a way point in 24h format.
-     * @param wpt
-     * @return
-     */
-    public static int getHourOfWayPoint(WayPoint wpt) {
-        if (wpt == null) return -1;
-
-        Calendar calendar = GregorianCalendar.getInstance(); // creates a new calendar instance
-        calendar.setTime(wpt.getTime());   // assigns calendar to given date
-        return calendar.get(Calendar.HOUR_OF_DAY);
-    }
-
-    /**
-     * Gets the minute value of a way point in 24h format.
-     * @param wpt
-     * @return
-     */
-    public static int getMinuteOfWayPoint(WayPoint wpt) {
-        if (wpt == null) return -1;
-
-        Calendar calendar = GregorianCalendar.getInstance(); // creates a new calendar instance
-        calendar.setTime(wpt.getTime());   // assigns calendar to given date
-        return calendar.get(Calendar.MINUTE);
-    }
+		 */
+		return 0;
+	}
+
+	/**
+	 * Reduces a given list of way points to the specified target size.
+	 *
+	 * @param origList
+	 *            The original list containing the way points.
+	 * @param targetSize
+	 *            The desired target size of the list. The resulting list may
+	 *            contain fewer items, so targetSize should be considered as
+	 *            maximum.
+	 * @return A list containing the reduced list.
+	 */
+	public static List<WayPoint> downsampleWayPoints(List<WayPoint> origList,
+			int targetSize) {
+		if (origList == null)
+			return null;
+		if (targetSize <= 0)
+			throw new IllegalArgumentException(
+					"targetSize must be greater than zero");
+
+		int origSize = origList.size();
+		if (origSize <= targetSize) {
+			return origList;
+		}
+
+		int delta = (int) Math.max(Math.ceil(origSize / targetSize), 2);
+
+		List<WayPoint> res = new ArrayList<>(targetSize);
+		for (int i = 0; i < origSize; i += delta) {
+			res.add(origList.get(i));
+		}
+
+		return res;
+	}
+
+	/**
+	 * Gets the hour value of a way point in 24h format.
+	 * @param wpt
+	 * @return
+	 */
+	public static int getHourOfWayPoint(WayPoint wpt) {
+		if (wpt == null) return -1;
+
+		Calendar calendar = GregorianCalendar.getInstance(); // creates a new calendar instance
+		calendar.setTime(wpt.getTime());   // assigns calendar to given date
+		return calendar.get(Calendar.HOUR_OF_DAY);
+	}
+
+	/**
+	 * Gets the minute value of a way point in 24h format.
+	 * @param wpt
+	 * @return
+	 */
+	public static int getMinuteOfWayPoint(WayPoint wpt) {
+		if (wpt == null) return -1;
+
+		Calendar calendar = GregorianCalendar.getInstance(); // creates a new calendar instance
+		calendar.setTime(wpt.getTime());   // assigns calendar to given date
+		return calendar.get(Calendar.MINUTE);
+	}
 }
Index: applications/editors/josm/plugins/ElevationProfile/src/org/openstreetmap/josm/plugins/elevation/HgtReader.java
===================================================================
--- applications/editors/josm/plugins/ElevationProfile/src/org/openstreetmap/josm/plugins/elevation/HgtReader.java	(revision 30736)
+++ applications/editors/josm/plugins/ElevationProfile/src/org/openstreetmap/josm/plugins/elevation/HgtReader.java	(revision 30737)
@@ -17,157 +17,157 @@
 /**
  *  Class HgtReader reads data from SRTM HGT files. Currently this class is restricted to a resolution of 3 arc seconds.
- * 
+ *
  *  SRTM data files are available at the <a href="http://dds.cr.usgs.gov/srtm/version2_1/SRTM3">NASA SRTM site</a>
  *  @author Oliver Wieland <oliver.wieland@online.de>
  */
 public class HgtReader {
-    private static final int SECONDS_PER_MINUTE = 60;
+	private static final int SECONDS_PER_MINUTE = 60;
 
-    public static final String HGT_EXT = ".hgt";
+	public static final String HGT_EXT = ".hgt";
 
-    // alter these values for different SRTM resolutions
-    public static final int HGT_RES = 3; // resolution in arc seconds
-    public static final int HGT_ROW_LENGTH = 1201; // number of elevation values per line
-    public static final int HGT_VOID = -32768; // magic number which indicates 'void data' in HGT file
+	// alter these values for different SRTM resolutions
+	public static final int HGT_RES = 3; // resolution in arc seconds
+	public static final int HGT_ROW_LENGTH = 1201; // number of elevation values per line
+	public static final int HGT_VOID = -32768; // magic number which indicates 'void data' in HGT file
 
-    private final HashMap<String, ShortBuffer> cache = new HashMap<String, ShortBuffer>();
+	private final HashMap<String, ShortBuffer> cache = new HashMap<>();
 
-    public double getElevationFromHgt(LatLon coor) {
-        try {
-            String file = getHgtFileName(coor);
-            // given area in cache?
-            if (!cache.containsKey(file)) {
+	public double getElevationFromHgt(LatLon coor) {
+		try {
+			String file = getHgtFileName(coor);
+			// given area in cache?
+			if (!cache.containsKey(file)) {
 
-                // fill initial cache value. If no file is found, then
-                // we use it as a marker to indicate 'file has been searched
-                // but is not there'
-                cache.put(file, null);
-                // Try all resource directories
-                for (String location : Main.pref.getAllPossiblePreferenceDirs()) {
-                    String fullPath = new File(location + File.separator + "elevation", file).getPath();
-                    File f = new File(fullPath);
-                    if (f.exists()) {
-                        // found something: read HGT file...
-                        ShortBuffer data = readHgtFile(fullPath);
-                        // ... and store result in cache
-                        cache.put(file, data);
-                        break;
-                    }
-                }
-            }
+				// fill initial cache value. If no file is found, then
+				// we use it as a marker to indicate 'file has been searched
+				// but is not there'
+				cache.put(file, null);
+				// Try all resource directories
+				for (String location : Main.pref.getAllPossiblePreferenceDirs()) {
+					String fullPath = new File(location + File.separator + "elevation", file).getPath();
+					File f = new File(fullPath);
+					if (f.exists()) {
+						// found something: read HGT file...
+						ShortBuffer data = readHgtFile(fullPath);
+						// ... and store result in cache
+						cache.put(file, data);
+						break;
+					}
+				}
+			}
 
-            // read elevation value
-            return readElevation(coor);
-        } catch (FileNotFoundException e) {
-            System.err.println("Get elevation from HGT " + coor + " failed: => " + e.getMessage());
-            // no problem... file not there
-            return ElevationHelper.NO_ELEVATION;
-        } catch (Exception ioe) {
-            // oops...
-            ioe.printStackTrace(System.err);
-            // fallback
-            return ElevationHelper.NO_ELEVATION;
-        }
-    }
+			// read elevation value
+			return readElevation(coor);
+		} catch (FileNotFoundException e) {
+			System.err.println("Get elevation from HGT " + coor + " failed: => " + e.getMessage());
+			// no problem... file not there
+			return ElevationHelper.NO_ELEVATION;
+		} catch (Exception ioe) {
+			// oops...
+			ioe.printStackTrace(System.err);
+			// fallback
+			return ElevationHelper.NO_ELEVATION;
+		}
+	}
 
-    @SuppressWarnings("resource")
-    private ShortBuffer readHgtFile(String file) throws Exception {
-        CheckParameterUtil.ensureParameterNotNull(file);
+	@SuppressWarnings("resource")
+	private ShortBuffer readHgtFile(String file) throws Exception {
+		CheckParameterUtil.ensureParameterNotNull(file);
 
-        FileChannel fc = null;
-        ShortBuffer sb = null;
-        try {
-            // Eclipse complains here about resource leak on 'fc' - even with 'finally' clause???
-            fc = new FileInputStream(file).getChannel();
-            // choose the right endianness
+		FileChannel fc = null;
+		ShortBuffer sb = null;
+		try {
+			// Eclipse complains here about resource leak on 'fc' - even with 'finally' clause???
+			fc = new FileInputStream(file).getChannel();
+			// choose the right endianness
 
-            ByteBuffer bb = ByteBuffer.allocateDirect((int) fc.size());
-            while (bb.remaining() > 0) fc.read(bb);
+			ByteBuffer bb = ByteBuffer.allocateDirect((int) fc.size());
+			while (bb.remaining() > 0) fc.read(bb);
 
-            bb.flip();
-            //sb = bb.order(ByteOrder.LITTLE_ENDIAN).asShortBuffer();
-            sb = bb.order(ByteOrder.BIG_ENDIAN).asShortBuffer();
-        } finally {
-            if (fc != null) fc.close();
-        }
+			bb.flip();
+			//sb = bb.order(ByteOrder.LITTLE_ENDIAN).asShortBuffer();
+			sb = bb.order(ByteOrder.BIG_ENDIAN).asShortBuffer();
+		} finally {
+			if (fc != null) fc.close();
+		}
 
-        return sb;
-    }
+		return sb;
+	}
 
-    /**
-     * Reads the elevation value for the given coordinate.
-     *
-     * See also <a href="http://gis.stackexchange.com/questions/43743/how-to-extract-elevation-from-hgt-file">stackexchange.com</a>
-     * @param coor the coordinate to get the elevation data for
-     * @return the elevation value or <code>Double.NaN</code>, if no value is present
-     */
-    public double readElevation(LatLon coor) {
-        String tag = getHgtFileName(coor);
+	/**
+	 * Reads the elevation value for the given coordinate.
+	 *
+	 * See also <a href="http://gis.stackexchange.com/questions/43743/how-to-extract-elevation-from-hgt-file">stackexchange.com</a>
+	 * @param coor the coordinate to get the elevation data for
+	 * @return the elevation value or <code>Double.NaN</code>, if no value is present
+	 */
+	public double readElevation(LatLon coor) {
+		String tag = getHgtFileName(coor);
 
-        ShortBuffer sb = cache.get(tag);
+		ShortBuffer sb = cache.get(tag);
 
-        if (sb == null) {
-            return ElevationHelper.NO_ELEVATION;
-        }
+		if (sb == null) {
+			return ElevationHelper.NO_ELEVATION;
+		}
 
-        // see http://gis.stackexchange.com/questions/43743/how-to-extract-elevation-from-hgt-file
-        double fLat = frac(coor.lat()) * SECONDS_PER_MINUTE;
-        double fLon = frac(coor.lon()) * SECONDS_PER_MINUTE;
+		// see http://gis.stackexchange.com/questions/43743/how-to-extract-elevation-from-hgt-file
+		double fLat = frac(coor.lat()) * SECONDS_PER_MINUTE;
+		double fLon = frac(coor.lon()) * SECONDS_PER_MINUTE;
 
-        // compute offset within HGT file
-        int row = (int)Math.round(fLat * SECONDS_PER_MINUTE / HGT_RES);
-        int col = (int)Math.round(fLon * SECONDS_PER_MINUTE / HGT_RES);
+		// compute offset within HGT file
+		int row = (int)Math.round(fLat * SECONDS_PER_MINUTE / HGT_RES);
+		int col = (int)Math.round(fLon * SECONDS_PER_MINUTE / HGT_RES);
 
-        row = HGT_ROW_LENGTH - row;
-        int cell = (HGT_ROW_LENGTH*  (row - 1)) + col;
+		row = HGT_ROW_LENGTH - row;
+		int cell = (HGT_ROW_LENGTH*  (row - 1)) + col;
 
-        //System.out.println("Read SRTM elevation data from row/col/cell " + row + "," + col + ", " + cell + ", " + sb.limit());
+		//System.out.println("Read SRTM elevation data from row/col/cell " + row + "," + col + ", " + cell + ", " + sb.limit());
 
-        // valid position in buffer?
-        if (cell < sb.limit()) {
-            short ele = sb.get(cell);
-            //System.out.println("==> Read SRTM elevation data from row/col/cell " + row + "," + col + ", " + cell + " = " + ele);
-            // check for data voids
-            if (ele == HGT_VOID) {
-                return ElevationHelper.NO_ELEVATION;
-            } else {
-                return ele;
-            }
-        } else {
-            return ElevationHelper.NO_ELEVATION;
-        }
-    }
+		// valid position in buffer?
+		if (cell < sb.limit()) {
+			short ele = sb.get(cell);
+			//System.out.println("==> Read SRTM elevation data from row/col/cell " + row + "," + col + ", " + cell + " = " + ele);
+			// check for data voids
+			if (ele == HGT_VOID) {
+				return ElevationHelper.NO_ELEVATION;
+			} else {
+				return ele;
+			}
+		} else {
+			return ElevationHelper.NO_ELEVATION;
+		}
+	}
 
-    /**
-     * Gets the associated HGT file name for the given way point. Usually the
-     * format is <tt>[N|S]nn[W|E]mmm.hgt</tt> where <i>nn</i> is the integral latitude
-     * without decimals and <i>mmm</i> is the longitude.
-     *
-     * @param latLon the coordinate to get the filename for
-     * @return the file name of the HGT file
-     */
-    public String getHgtFileName(LatLon latLon) {
-        int lat = (int) latLon.lat();
-        int lon = (int) latLon.lon();
+	/**
+	 * Gets the associated HGT file name for the given way point. Usually the
+	 * format is <tt>[N|S]nn[W|E]mmm.hgt</tt> where <i>nn</i> is the integral latitude
+	 * without decimals and <i>mmm</i> is the longitude.
+	 *
+	 * @param latLon the coordinate to get the filename for
+	 * @return the file name of the HGT file
+	 */
+	public String getHgtFileName(LatLon latLon) {
+		int lat = (int) latLon.lat();
+		int lon = (int) latLon.lon();
 
-        String latPref = "N";
-        if (lat < 0) latPref = "S";
+		String latPref = "N";
+		if (lat < 0) latPref = "S";
 
-        String lonPref = "E";
-        if (lon < 0) {
-            lonPref = "W";
-        }
+		String lonPref = "E";
+		if (lon < 0) {
+			lonPref = "W";
+		}
 
-        return String.format("%s%02d%s%03d%s", latPref, lat, lonPref, lon, HGT_EXT);
-    }
+		return String.format("%s%02d%s%03d%s", latPref, lat, lonPref, lon, HGT_EXT);
+	}
 
-    public static double frac(double d) {
-        long iPart;
-        double fPart;
+	public static double frac(double d) {
+		long iPart;
+		double fPart;
 
-        // Get user input
-        iPart = (long) d;
-        fPart = d - iPart;
-        return fPart;
-    }
+		// Get user input
+		iPart = (long) d;
+		fPart = d - iPart;
+		return fPart;
+	}
 }
Index: applications/editors/josm/plugins/ElevationProfile/src/org/openstreetmap/josm/plugins/elevation/gpx/ElevationModel.java
===================================================================
--- applications/editors/josm/plugins/ElevationProfile/src/org/openstreetmap/josm/plugins/elevation/gpx/ElevationModel.java	(revision 30736)
+++ applications/editors/josm/plugins/ElevationProfile/src/org/openstreetmap/josm/plugins/elevation/gpx/ElevationModel.java	(revision 30737)
@@ -19,227 +19,227 @@
  * Represents the top-level part of the elevation model. The elevation model
  * breaks done into the tracks/routes of a GPX file.
- * 
+ *
  * @see IElevationModelTrackListener
  * @author Oliver Wieland <oliver.wieland@online.de>
  */
 public class ElevationModel implements IGpxVisitor, IElevationModel {
-    // private int sliceSize;
-    private int trackCounter;
-    private final GpxData gpxData;
-    private final String name;
-    private final WayPointMap profiles = new WayPointMap();
-    private final List<IElevationModelListener> listeners = new ArrayList<IElevationModelListener>();
-    private final List<WayPoint> buffer = new ArrayList<WayPoint>();
-    private int currentProfileIndex = 0;
-    private ElevationProfile curProfile = null;
-
-    /**
-     * Instantiates a new elevation model.
-     */
-    public ElevationModel() {
-        this("", null);
-    }
-
-    /**
-     * Instantiates a new elevation model.
-     *
-     * @param name the name of the model
-     * @param data the GPX data
-     */
-    public ElevationModel(String name, GpxData data) {
-        gpxData = data;
-        this.name = name;
-        GpxIterator.visit(data, this);
-    }
-
-    /**
-     * Gets the GPX data instance used by this model.
-     * 
-     * @return
-     */
-    public GpxData getGpxData() {
-        return gpxData;
-    }
-
-    /**
-     * @return the tracks
-     */
-    protected WayPointMap getTracks() {
-        return profiles;
-    }
-
-    /**
-     * Fires the 'model changed' event to all listeners.
-     */
-    protected void fireModelChanged() {
-        for (IElevationModelListener listener : listeners) {
-            if (profiles != null && profiles.size() > 0)
-                listener.elevationProfileChanged(getCurrentProfile());
-        }
-    }
-
-    @Override
-    public void addModelListener(IElevationModelListener listener) {
-        this.listeners.add(listener);
-    }
-
-    @Override
-    public void removeModelListener(IElevationModelListener listener) {
-        this.listeners.remove(listener);
-    }
-
-    @Override
-    public void removeAllListeners() {
-        this.listeners.clear();
-    }
-
-    @Override
-    public List<IElevationProfile> getProfiles() {
-        return profiles;
-    }
-
-    @Override
-    public IElevationProfile getCurrentProfile() {
-        if (currentProfileIndex < 0 || currentProfileIndex >= profileCount()) return null;
-
-        return profiles.get(currentProfileIndex);
-    }
-
-    @Override
-    public void setCurrentProfile(IElevationProfile newProfile) {
-        CheckParameterUtil.ensureParameterNotNull(newProfile);
-
-        if (!profiles.contains(newProfile)) {
-            profiles.add(newProfile);
-        }
-
-        setCurrentProfile(profiles.indexOf(newProfile));
-    }
-
-    @Override
-    public void setCurrentProfile(int index) {
-        if (index < 0 || index >= profileCount()) throw new RuntimeException("Invalid arg for setCurrentProfile: " + index + ", value must be 0.." + profileCount());
-
-        currentProfileIndex = index;
-        fireModelChanged();
-    }
-
-    @Override
-    public int profileCount() {
-        return profiles != null ? profiles.size() : 0;
-    }
-
-    // Visitor stuff starts here...
-
-    @Override
-    public void beginWayPoints() {
-        // we ignore single way points (elevation profile is quite meaningless...)
-    }
-
-    @Override
-    public void endWayPoints() {
-        // we ignore single way points (elevation profile is quite meaningless...)
-    }
-
-    @Override
-    public void visitWayPoint(WayPoint wp) {
-        // we ignore single way points (elevation profile is quite meaningless...)
-    }
-
-
-    @Override
-    public void beginTrack(GpxTrack track) {
-        createProfile(track);
-    }
-
-    @Override
-    public void endTrack(GpxTrack track) {
-        if (curProfile == null) throw new RuntimeException("Internal error: No elevation profile");
-
-        curProfile.setDistance(track.length());
-        commitProfile();
-    }
-
-    @Override
-    public void beginTrackSegment(GpxTrack track, GpxTrackSegment segment) {
-        // Nothing to do here for now
-    }
-
-    @Override
-    public void endTrackSegment(GpxTrack track, GpxTrackSegment segment) {
-        // Nothing to do here for now
-    }
-
-    @Override
-    public void visitTrackPoint(WayPoint wp, GpxTrack track,
-            GpxTrackSegment segment) {
-
-        processWayPoint(wp);
-    }
-
-    @Override
-    public void beginRoute(GpxRoute route) {
-        createProfile(route);
-    }
-
-    @Override
-    public void endRoute(GpxRoute route) {
-        if (curProfile == null) throw new RuntimeException("Internal error: No elevation profile");
-        // a GpxRoute has no 'length' property
-        curProfile.setDistance(0);
-        commitProfile();
-    }
-
-    @Override
-    public void visitRoutePoint(WayPoint wp, GpxRoute route) {
-        processWayPoint(wp);
-    }
-
-    /**
-     * Creates a new profile.
-     *
-     * @param trackOrRoute the track or route
-     */
-    private void createProfile(IWithAttributes trackOrRoute) {
-        // check GPX data
-        String trackName = (String) trackOrRoute.get("name");
-
-        if (trackName == null) {
-            trackName = (String) trackOrRoute.get(GpxData.META_NAME);
-            if (trackName == null) {
-                // no name given, build artificial one
-                trackName = name + "." + trackCounter;
-            }
-        }
-
-        curProfile = new ElevationProfile(trackName);
-    }
-
-    /**
-     * Adds a track or route to the internal track list.
-     *
-     * @param trackName the track name
-     */
-    private void commitProfile() {
-        if (buffer.size() > 0) {
-            // assign way points to profile...
-            curProfile.setWayPoints(buffer);
-            // ... and add to profile list
-            profiles.add(curProfile);
-            buffer.clear();
-        }
-    }
-
-    /**
-     * Adds the given way point to the current buffer.
-     *
-     * @param wp the wp
-     */
-    private void processWayPoint(WayPoint wp) {
-        if (wp == null) {
-            throw new RuntimeException("WPT must not be null!");
-        }
-
-        buffer.add(wp);
-    }
+	// private int sliceSize;
+	private int trackCounter;
+	private final GpxData gpxData;
+	private final String name;
+	private final WayPointMap profiles = new WayPointMap();
+	private final List<IElevationModelListener> listeners = new ArrayList<>();
+	private final List<WayPoint> buffer = new ArrayList<>();
+	private int currentProfileIndex = 0;
+	private ElevationProfile curProfile = null;
+
+	/**
+	 * Instantiates a new elevation model.
+	 */
+	public ElevationModel() {
+		this("", null);
+	}
+
+	/**
+	 * Instantiates a new elevation model.
+	 *
+	 * @param name the name of the model
+	 * @param data the GPX data
+	 */
+	public ElevationModel(String name, GpxData data) {
+		gpxData = data;
+		this.name = name;
+		GpxIterator.visit(data, this);
+	}
+
+	/**
+	 * Gets the GPX data instance used by this model.
+	 *
+	 * @return
+	 */
+	public GpxData getGpxData() {
+		return gpxData;
+	}
+
+	/**
+	 * @return the tracks
+	 */
+	protected WayPointMap getTracks() {
+		return profiles;
+	}
+
+	/**
+	 * Fires the 'model changed' event to all listeners.
+	 */
+	protected void fireModelChanged() {
+		for (IElevationModelListener listener : listeners) {
+			if (profiles != null && profiles.size() > 0)
+				listener.elevationProfileChanged(getCurrentProfile());
+		}
+	}
+
+	@Override
+	public void addModelListener(IElevationModelListener listener) {
+		this.listeners.add(listener);
+	}
+
+	@Override
+	public void removeModelListener(IElevationModelListener listener) {
+		this.listeners.remove(listener);
+	}
+
+	@Override
+	public void removeAllListeners() {
+		this.listeners.clear();
+	}
+
+	@Override
+	public List<IElevationProfile> getProfiles() {
+		return profiles;
+	}
+
+	@Override
+	public IElevationProfile getCurrentProfile() {
+		if (currentProfileIndex < 0 || currentProfileIndex >= profileCount()) return null;
+
+		return profiles.get(currentProfileIndex);
+	}
+
+	@Override
+	public void setCurrentProfile(IElevationProfile newProfile) {
+		CheckParameterUtil.ensureParameterNotNull(newProfile);
+
+		if (!profiles.contains(newProfile)) {
+			profiles.add(newProfile);
+		}
+
+		setCurrentProfile(profiles.indexOf(newProfile));
+	}
+
+	@Override
+	public void setCurrentProfile(int index) {
+		if (index < 0 || index >= profileCount()) throw new RuntimeException("Invalid arg for setCurrentProfile: " + index + ", value must be 0.." + profileCount());
+
+		currentProfileIndex = index;
+		fireModelChanged();
+	}
+
+	@Override
+	public int profileCount() {
+		return profiles != null ? profiles.size() : 0;
+	}
+
+	// Visitor stuff starts here...
+
+	@Override
+	public void beginWayPoints() {
+		// we ignore single way points (elevation profile is quite meaningless...)
+	}
+
+	@Override
+	public void endWayPoints() {
+		// we ignore single way points (elevation profile is quite meaningless...)
+	}
+
+	@Override
+	public void visitWayPoint(WayPoint wp) {
+		// we ignore single way points (elevation profile is quite meaningless...)
+	}
+
+
+	@Override
+	public void beginTrack(GpxTrack track) {
+		createProfile(track);
+	}
+
+	@Override
+	public void endTrack(GpxTrack track) {
+		if (curProfile == null) throw new RuntimeException("Internal error: No elevation profile");
+
+		curProfile.setDistance(track.length());
+		commitProfile();
+	}
+
+	@Override
+	public void beginTrackSegment(GpxTrack track, GpxTrackSegment segment) {
+		// Nothing to do here for now
+	}
+
+	@Override
+	public void endTrackSegment(GpxTrack track, GpxTrackSegment segment) {
+		// Nothing to do here for now
+	}
+
+	@Override
+	public void visitTrackPoint(WayPoint wp, GpxTrack track,
+			GpxTrackSegment segment) {
+
+		processWayPoint(wp);
+	}
+
+	@Override
+	public void beginRoute(GpxRoute route) {
+		createProfile(route);
+	}
+
+	@Override
+	public void endRoute(GpxRoute route) {
+		if (curProfile == null) throw new RuntimeException("Internal error: No elevation profile");
+		// a GpxRoute has no 'length' property
+		curProfile.setDistance(0);
+		commitProfile();
+	}
+
+	@Override
+	public void visitRoutePoint(WayPoint wp, GpxRoute route) {
+		processWayPoint(wp);
+	}
+
+	/**
+	 * Creates a new profile.
+	 *
+	 * @param trackOrRoute the track or route
+	 */
+	private void createProfile(IWithAttributes trackOrRoute) {
+		// check GPX data
+		String trackName = (String) trackOrRoute.get("name");
+
+		if (trackName == null) {
+			trackName = (String) trackOrRoute.get(GpxData.META_NAME);
+			if (trackName == null) {
+				// no name given, build artificial one
+				trackName = name + "." + trackCounter;
+			}
+		}
+
+		curProfile = new ElevationProfile(trackName);
+	}
+
+	/**
+	 * Adds a track or route to the internal track list.
+	 *
+	 * @param trackName the track name
+	 */
+	private void commitProfile() {
+		if (buffer.size() > 0) {
+			// assign way points to profile...
+			curProfile.setWayPoints(buffer);
+			// ... and add to profile list
+			profiles.add(curProfile);
+			buffer.clear();
+		}
+	}
+
+	/**
+	 * Adds the given way point to the current buffer.
+	 *
+	 * @param wp the wp
+	 */
+	private void processWayPoint(WayPoint wp) {
+		if (wp == null) {
+			throw new RuntimeException("WPT must not be null!");
+		}
+
+		buffer.add(wp);
+	}
 }
Index: applications/editors/josm/plugins/ElevationProfile/src/org/openstreetmap/josm/plugins/elevation/gpx/ElevationProfile.java
===================================================================
--- applications/editors/josm/plugins/ElevationProfile/src/org/openstreetmap/josm/plugins/elevation/gpx/ElevationProfile.java	(revision 30736)
+++ applications/editors/josm/plugins/ElevationProfile/src/org/openstreetmap/josm/plugins/elevation/gpx/ElevationProfile.java	(revision 30737)
@@ -17,420 +17,420 @@
  * full way point set and then reduces the number of way points to a given
  * amount, if necessary.
- * 
+ *
  * The computation is done via implementing {@link IGpxWaypointVisitor},
  * subclasses may override the {@link ElevationProfile#visitWayPoint(WayPoint)}
  * method to compute own values or run specific actions. The computation is
  * triggered by calling {@link ElevationProfile#updateValues()}.
- * 
+ *
  * Elevation profiles can break down into further child profiles. This is
  * intended to show different levels of details, if the number of way points
  * exceed the display space (which is usually the case).
- * 
+ *
  * {@link IElevationProfile} {@link IGpxWaypointVisitor} {@link GpxIterator}
- * 
+ *
  * @author Oliver Wieland <oliver.wieland@online.de>
- * 
+ *
  */
 public class ElevationProfile implements IElevationProfile,
 IGpxWaypointVisitor {
-    public static final int WAYPOINT_START = 0;
-    public static final int WAYPOINT_END = 1;
-    public static final int WAYPOINT_MIN = 2;
-    public static final int WAYPOINT_MAX = 3;
-
-    private String name;
-    private int minHeight;
-    private int maxHeight;
-    private int avrgHeight;
-    private double dist;
-    private Date start = new Date();
-    private Date end = new Date();
-    private final WayPoint[] importantWayPoints = new WayPoint[4];
-    private IElevationProfile parent;
-    private int sumEle; // temp var for average height
-    private List<WayPoint> wayPoints;
-    private int numWayPoints; // cached value
-    private int gain;
-    private int lastEle;
-    private Bounds bounds;
-
-    private static boolean ignoreZeroHeight = true;
-
-    /**
-     * Creates a name elevation profile without any way points.
-     * 
-     * @param name
-     */
-    public ElevationProfile(String name) {
-        this(name, null, null, 0);
-    }
-
-    /**
-     * Creates a name elevation profile with a given set of way points.
-     * 
-     * @param name
-     *            The name of the profile.
-     * @param parent
-     *            The (optional) parent profile.
-     * @param wayPoints
-     *            The list containing the way points of the profile.
-     * @param sliceSize
-     *            The requested target size of the profile.
-     */
-    public ElevationProfile(String name, IElevationProfile parent,
-            List<WayPoint> wayPoints, int sliceSize) {
-        super();
-        this.name = name;
-        this.parent = parent;
-
-        setWayPoints(wayPoints);
-    }
-
-    /**
-     * Checks if zero elevation should be ignored or not.
-     *
-     * @return true, if is ignore zero height
-     */
-    public static boolean isIgnoreZeroHeight() {
-        return ignoreZeroHeight;
-    }
-
-    /**
-     * Sets the ignore zero height.
-     *
-     * @param ignoreZeroHeight the new ignore zero height
-     */
-    public static void setIgnoreZeroHeight(boolean ignoreZeroHeight) {
-        ElevationProfile.ignoreZeroHeight = ignoreZeroHeight;
-    }
-
-    @Override
-    public void updateElevationData() {
-        updateValues();
-    }
-
-    /**
-     * Revisits all way points and recomputes the characteristic values like
-     * min/max elevation.
-     */
-    protected void updateValues() {
-        if (wayPoints == null)
-            return;
-
-        int n = this.wayPoints.size();
-        if (n == 0)
-            return;
-
-        start = new Date();
-        end = new Date(0L);
-        this.minHeight = Integer.MAX_VALUE;
-        this.maxHeight = Integer.MIN_VALUE;
-        sumEle = 0;
-        gain = 0;
-        lastEle = 0;
-
-        for (WayPoint wayPoint : this.wayPoints) {
-            visitWayPoint(wayPoint);
-        }
-
-        if (this.minHeight == Integer.MAX_VALUE && this.maxHeight == Integer.MIN_VALUE) {
-            // file does not contain elevation data    at all
-            minHeight = 0;
-            maxHeight = 0;
-            setMinWayPoint(wayPoints.get(0));
-            setMaxWayPoint(wayPoints.get(n-1));
-        }
-
-        //if (start.after(end) || start.equals(end)) {
-        // GPX does not contain time stamps -> use sequential order
-        setStart(wayPoints.get(0));
-        setEnd(wayPoints.get(n-1));
-        //}
-
-        avrgHeight = sumEle / n;
-    }
-
-    /**
-     * Gets the name of the profile.
-     */
-    @Override
-    public String getName() {
-        return name;
-    }
-
-    /**
-     * Sets the name of the profile.
-     * @param name The new name of the profile.
-     */
-    public void setName(String name) {
-        this.name = name;
-    }
-
-    /**
-     * Sets the way point with the lowest elevation.
-     * @param wp The way point instance having the lowest elevation.
-     */
-    protected void setMinWayPoint(WayPoint wp) {
-        importantWayPoints[WAYPOINT_MIN] = wp;
-        this.minHeight = (int) ElevationHelper.getElevation(wp);
-    }
-
-    /**
-     * Sets the way point with the highest elevation.
-     * @param wp The way point instance having the highest elevation.
-     */
-    protected void setMaxWayPoint(WayPoint wp) {
-        importantWayPoints[WAYPOINT_MAX] = wp;
-        this.maxHeight = (int) ElevationHelper.getElevation(wp);
-    }
-
-    /**
-     * Sets the average height.
-     * @param avrgHeight
-     */
-    protected void setAvrgHeight(int avrgHeight) {
-        this.avrgHeight = avrgHeight;
-    }
-
-    /**
-     * Sets the very first way point.
-     * @param wp
-     */
-    protected void setStart(WayPoint wp) {
-        importantWayPoints[WAYPOINT_START] = wp;
-        this.start = wp.getTime();
-    }
-
-    /**
-     * Sets the very last way point.
-     * @param wp
-     */
-    protected void setEnd(WayPoint wp) {
-        importantWayPoints[WAYPOINT_END] = wp;
-        this.end = wp.getTime();
-    }
-
-    public void setParent(IElevationProfile parent) {
-        this.parent = parent;
-    }
-
-    /**
-     * Sets the way points of this profile.
-     * 
-     * @param wayPoints
-     */
-    public void setWayPoints(List<WayPoint> wayPoints) {
-        if (this.wayPoints != wayPoints) {
-            this.wayPoints = new ArrayList<WayPoint>(wayPoints);
-            numWayPoints = wayPoints != null ? wayPoints.size() : 0;
-            updateValues();
-
-        }
-    }
-
-    /**
-     * Checks if the given index is valid or not.
-     * 
-     * @param index
-     *            The index to check.
-     * @return true, if the given index is valid; otherwise false.
-     */
-    protected boolean checkIndex(int index) {
-        return index >= 0 && index < getNumberOfWayPoints();
-    }
-
-    @Override
-    public int elevationValueAt(int i) {
-        if (checkIndex(i)) {
-            return (int) ElevationHelper.getElevation(wayPoints.get(i));
-        } else {
-            throw new IndexOutOfBoundsException(String.format(
-                    "Invalid index: %d, expected 0..%d", i,
-                    getNumberOfWayPoints()));
-        }
-    }
-
-    @Override
-    public int getAverageHeight() {
-        return avrgHeight;
-    }
-
-    @Override
-    public List<IElevationProfile> getChildren() {
-        return null;
-    }
-
-    @Override
-    public Date getEnd() {
-        return end;
-    }
-
-    @Override
-    public int getMaxHeight() {
-        return maxHeight;
-    }
-
-    @Override
-    public int getMinHeight() {
-        return minHeight;
-    }
-
-    /**
-     * Gets the difference between min and max elevation.
-     * 
-     * @return
-     */
-    @Override
-    public int getHeightDifference() {
-        return maxHeight - minHeight;
-    }
-
-    /**
-     * Gets the elevation gain.
-     * 
-     * @return
-     */
-    @Override
-    public int getGain() {
-        return gain;
-    }
-
-    @Override
-    public double getDistance() {
-        return dist; // dist is in meters
-    }
-
-    /**
-     * Sets the distance of the elevation profile.
-     * @param dist
-     */
-    protected void setDistance(double dist) {
-        this.dist = dist;
-    }
-
-    /**
-     * Returns the time between start and end of the track.
-     * @return
-     */
-    @Override
-    public long getTimeDifference() {
-        WayPoint wp1 = getStartWayPoint();
-        WayPoint wp2 = getEndWayPoint();
-
-        if (wp1 != null && wp2 != null) {
-            long diff = wp2.getTime().getTime() - wp1.getTime().getTime();
-            return diff;
-        }
-
-        return 0L;
-    }
-
-    @Override
-    public IElevationProfile getParent() {
-        return parent;
-    }
-
-    @Override
-    public Date getStart() {
-        return start;
-    }
-
-    @Override
-    public WayPoint getEndWayPoint() {
-        return importantWayPoints[WAYPOINT_END];
-    }
-
-    @Override
-    public WayPoint getMaxWayPoint() {
-        return importantWayPoints[WAYPOINT_MAX];
-    }
-
-    @Override
-    public WayPoint getMinWayPoint() {
-        return importantWayPoints[WAYPOINT_MIN];
-    }
-
-    @Override
-    public WayPoint getStartWayPoint() {
-        return importantWayPoints[WAYPOINT_START];
-    }
-
-    @Override
-    public List<WayPoint> getWayPoints() {
-        return wayPoints;
-    }
-
-    @Override
-    public int getNumberOfWayPoints() {
-        return numWayPoints;// wayPoints != null ? wayPoints.size() : 0;
-    }
-
-    /**
-     * Gets the coordinate bounds of this profile. See {@link Bounds} for details.
-     *
-     * @return the bounds of this elevation profile
-     */
-    @Override
-    public Bounds getBounds() {
-        return bounds;
-    }
-
-    /**
-     * Gets a flag indicating whether the associated way points contained
-     * elevation data or not. This is the case if min and max height or both
-     * zero.
-     * 
-     * @return
-     */
-    @Override
-    public boolean hasElevationData() {
-        return minHeight != maxHeight;
-    }
-
-    /**
-     * Visits a way point in order to update statistical values about the given
-     * way point list.
-     */
-    @Override
-    public void visitWayPoint(WayPoint wp) {
-        if (wp.getTime().after(end)) {
-            setEnd(wp);
-        }
-
-        if (wp.getTime().before(start)) {
-            setStart(wp);
-        }
-
-        // update boundaries
-        if (bounds == null) {
-            bounds = new Bounds(wp.getCoor());
-        } else {
-            bounds.extend(wp.getCoor());
-        }
-
-        int ele = (int) ElevationHelper.getElevation(wp);
-
-        if (!isIgnoreZeroHeight() || ele > 0) {
-            if (ele > maxHeight) {
-                setMaxWayPoint(wp);
-            }
-            if (ele < minHeight) {
-                setMinWayPoint(wp);
-            }
-
-            if (ele > lastEle) {
-                gain += ele - lastEle;
-            }
-
-            sumEle += ele;
-            lastEle = ele;
-        }
-    }
-
-    @Override
-    public String toString() {
-        return name; /*"ElevationProfileBase [start=" + getStart() + ", end=" + getEnd()
+	public static final int WAYPOINT_START = 0;
+	public static final int WAYPOINT_END = 1;
+	public static final int WAYPOINT_MIN = 2;
+	public static final int WAYPOINT_MAX = 3;
+
+	private String name;
+	private int minHeight;
+	private int maxHeight;
+	private int avrgHeight;
+	private double dist;
+	private Date start = new Date();
+	private Date end = new Date();
+	private final WayPoint[] importantWayPoints = new WayPoint[4];
+	private IElevationProfile parent;
+	private int sumEle; // temp var for average height
+	private List<WayPoint> wayPoints;
+	private int numWayPoints; // cached value
+	private int gain;
+	private int lastEle;
+	private Bounds bounds;
+
+	private static boolean ignoreZeroHeight = true;
+
+	/**
+	 * Creates a name elevation profile without any way points.
+	 *
+	 * @param name
+	 */
+	public ElevationProfile(String name) {
+		this(name, null, null, 0);
+	}
+
+	/**
+	 * Creates a name elevation profile with a given set of way points.
+	 *
+	 * @param name
+	 *            The name of the profile.
+	 * @param parent
+	 *            The (optional) parent profile.
+	 * @param wayPoints
+	 *            The list containing the way points of the profile.
+	 * @param sliceSize
+	 *            The requested target size of the profile.
+	 */
+	public ElevationProfile(String name, IElevationProfile parent,
+			List<WayPoint> wayPoints, int sliceSize) {
+		super();
+		this.name = name;
+		this.parent = parent;
+
+		setWayPoints(wayPoints);
+	}
+
+	/**
+	 * Checks if zero elevation should be ignored or not.
+	 *
+	 * @return true, if is ignore zero height
+	 */
+	public static boolean isIgnoreZeroHeight() {
+		return ignoreZeroHeight;
+	}
+
+	/**
+	 * Sets the ignore zero height.
+	 *
+	 * @param ignoreZeroHeight the new ignore zero height
+	 */
+	public static void setIgnoreZeroHeight(boolean ignoreZeroHeight) {
+		ElevationProfile.ignoreZeroHeight = ignoreZeroHeight;
+	}
+
+	@Override
+	public void updateElevationData() {
+		updateValues();
+	}
+
+	/**
+	 * Revisits all way points and recomputes the characteristic values like
+	 * min/max elevation.
+	 */
+	protected void updateValues() {
+		if (wayPoints == null)
+			return;
+
+		int n = this.wayPoints.size();
+		if (n == 0)
+			return;
+
+		start = new Date();
+		end = new Date(0L);
+		this.minHeight = Integer.MAX_VALUE;
+		this.maxHeight = Integer.MIN_VALUE;
+		sumEle = 0;
+		gain = 0;
+		lastEle = 0;
+
+		for (WayPoint wayPoint : this.wayPoints) {
+			visitWayPoint(wayPoint);
+		}
+
+		if (this.minHeight == Integer.MAX_VALUE && this.maxHeight == Integer.MIN_VALUE) {
+			// file does not contain elevation data    at all
+			minHeight = 0;
+			maxHeight = 0;
+			setMinWayPoint(wayPoints.get(0));
+			setMaxWayPoint(wayPoints.get(n-1));
+		}
+
+		//if (start.after(end) || start.equals(end)) {
+		// GPX does not contain time stamps -> use sequential order
+		setStart(wayPoints.get(0));
+		setEnd(wayPoints.get(n-1));
+		//}
+
+		avrgHeight = sumEle / n;
+	}
+
+	/**
+	 * Gets the name of the profile.
+	 */
+	@Override
+	public String getName() {
+		return name;
+	}
+
+	/**
+	 * Sets the name of the profile.
+	 * @param name The new name of the profile.
+	 */
+	public void setName(String name) {
+		this.name = name;
+	}
+
+	/**
+	 * Sets the way point with the lowest elevation.
+	 * @param wp The way point instance having the lowest elevation.
+	 */
+	protected void setMinWayPoint(WayPoint wp) {
+		importantWayPoints[WAYPOINT_MIN] = wp;
+		this.minHeight = (int) ElevationHelper.getElevation(wp);
+	}
+
+	/**
+	 * Sets the way point with the highest elevation.
+	 * @param wp The way point instance having the highest elevation.
+	 */
+	protected void setMaxWayPoint(WayPoint wp) {
+		importantWayPoints[WAYPOINT_MAX] = wp;
+		this.maxHeight = (int) ElevationHelper.getElevation(wp);
+	}
+
+	/**
+	 * Sets the average height.
+	 * @param avrgHeight
+	 */
+	protected void setAvrgHeight(int avrgHeight) {
+		this.avrgHeight = avrgHeight;
+	}
+
+	/**
+	 * Sets the very first way point.
+	 * @param wp
+	 */
+	protected void setStart(WayPoint wp) {
+		importantWayPoints[WAYPOINT_START] = wp;
+		this.start = wp.getTime();
+	}
+
+	/**
+	 * Sets the very last way point.
+	 * @param wp
+	 */
+	protected void setEnd(WayPoint wp) {
+		importantWayPoints[WAYPOINT_END] = wp;
+		this.end = wp.getTime();
+	}
+
+	public void setParent(IElevationProfile parent) {
+		this.parent = parent;
+	}
+
+	/**
+	 * Sets the way points of this profile.
+	 *
+	 * @param wayPoints
+	 */
+	public void setWayPoints(List<WayPoint> wayPoints) {
+		if (this.wayPoints != wayPoints) {
+			this.wayPoints = new ArrayList<>(wayPoints);
+			numWayPoints = wayPoints != null ? wayPoints.size() : 0;
+			updateValues();
+
+		}
+	}
+
+	/**
+	 * Checks if the given index is valid or not.
+	 *
+	 * @param index
+	 *            The index to check.
+	 * @return true, if the given index is valid; otherwise false.
+	 */
+	protected boolean checkIndex(int index) {
+		return index >= 0 && index < getNumberOfWayPoints();
+	}
+
+	@Override
+	public int elevationValueAt(int i) {
+		if (checkIndex(i)) {
+			return (int) ElevationHelper.getElevation(wayPoints.get(i));
+		} else {
+			throw new IndexOutOfBoundsException(String.format(
+					"Invalid index: %d, expected 0..%d", i,
+					getNumberOfWayPoints()));
+		}
+	}
+
+	@Override
+	public int getAverageHeight() {
+		return avrgHeight;
+	}
+
+	@Override
+	public List<IElevationProfile> getChildren() {
+		return null;
+	}
+
+	@Override
+	public Date getEnd() {
+		return end;
+	}
+
+	@Override
+	public int getMaxHeight() {
+		return maxHeight;
+	}
+
+	@Override
+	public int getMinHeight() {
+		return minHeight;
+	}
+
+	/**
+	 * Gets the difference between min and max elevation.
+	 *
+	 * @return
+	 */
+	@Override
+	public int getHeightDifference() {
+		return maxHeight - minHeight;
+	}
+
+	/**
+	 * Gets the elevation gain.
+	 *
+	 * @return
+	 */
+	@Override
+	public int getGain() {
+		return gain;
+	}
+
+	@Override
+	public double getDistance() {
+		return dist; // dist is in meters
+	}
+
+	/**
+	 * Sets the distance of the elevation profile.
+	 * @param dist
+	 */
+	protected void setDistance(double dist) {
+		this.dist = dist;
+	}
+
+	/**
+	 * Returns the time between start and end of the track.
+	 * @return
+	 */
+	@Override
+	public long getTimeDifference() {
+		WayPoint wp1 = getStartWayPoint();
+		WayPoint wp2 = getEndWayPoint();
+
+		if (wp1 != null && wp2 != null) {
+			long diff = wp2.getTime().getTime() - wp1.getTime().getTime();
+			return diff;
+		}
+
+		return 0L;
+	}
+
+	@Override
+	public IElevationProfile getParent() {
+		return parent;
+	}
+
+	@Override
+	public Date getStart() {
+		return start;
+	}
+
+	@Override
+	public WayPoint getEndWayPoint() {
+		return importantWayPoints[WAYPOINT_END];
+	}
+
+	@Override
+	public WayPoint getMaxWayPoint() {
+		return importantWayPoints[WAYPOINT_MAX];
+	}
+
+	@Override
+	public WayPoint getMinWayPoint() {
+		return importantWayPoints[WAYPOINT_MIN];
+	}
+
+	@Override
+	public WayPoint getStartWayPoint() {
+		return importantWayPoints[WAYPOINT_START];
+	}
+
+	@Override
+	public List<WayPoint> getWayPoints() {
+		return wayPoints;
+	}
+
+	@Override
+	public int getNumberOfWayPoints() {
+		return numWayPoints;// wayPoints != null ? wayPoints.size() : 0;
+	}
+
+	/**
+	 * Gets the coordinate bounds of this profile. See {@link Bounds} for details.
+	 *
+	 * @return the bounds of this elevation profile
+	 */
+	@Override
+	public Bounds getBounds() {
+		return bounds;
+	}
+
+	/**
+	 * Gets a flag indicating whether the associated way points contained
+	 * elevation data or not. This is the case if min and max height or both
+	 * zero.
+	 *
+	 * @return
+	 */
+	@Override
+	public boolean hasElevationData() {
+		return minHeight != maxHeight;
+	}
+
+	/**
+	 * Visits a way point in order to update statistical values about the given
+	 * way point list.
+	 */
+	@Override
+	public void visitWayPoint(WayPoint wp) {
+		if (wp.getTime().after(end)) {
+			setEnd(wp);
+		}
+
+		if (wp.getTime().before(start)) {
+			setStart(wp);
+		}
+
+		// update boundaries
+		if (bounds == null) {
+			bounds = new Bounds(wp.getCoor());
+		} else {
+			bounds.extend(wp.getCoor());
+		}
+
+		int ele = (int) ElevationHelper.getElevation(wp);
+
+		if (!isIgnoreZeroHeight() || ele > 0) {
+			if (ele > maxHeight) {
+				setMaxWayPoint(wp);
+			}
+			if (ele < minHeight) {
+				setMinWayPoint(wp);
+			}
+
+			if (ele > lastEle) {
+				gain += ele - lastEle;
+			}
+
+			sumEle += ele;
+			lastEle = ele;
+		}
+	}
+
+	@Override
+	public String toString() {
+		return name; /*"ElevationProfileBase [start=" + getStart() + ", end=" + getEnd()
                 + ", minHeight=" + getMinHeight() + ", maxHeight="
                 + getMaxHeight() + "]";*/
-    }
+	}
 }
Index: applications/editors/josm/plugins/ElevationProfile/src/org/openstreetmap/josm/plugins/elevation/grid/EleVertex.java
===================================================================
--- applications/editors/josm/plugins/ElevationProfile/src/org/openstreetmap/josm/plugins/elevation/grid/EleVertex.java	(revision 30736)
+++ applications/editors/josm/plugins/ElevationProfile/src/org/openstreetmap/josm/plugins/elevation/grid/EleVertex.java	(revision 30737)
@@ -87,5 +87,5 @@
     System.out.println(newP);
 		 */
-		List<EleVertex> res = new ArrayList<EleVertex>();
+		List<EleVertex> res = new ArrayList<>();
 		res.add(new EleVertex(pI, pK, newP));
 		res.add(new EleVertex(pJ, pK, newP));
Index: applications/editors/josm/plugins/ElevationProfile/src/org/openstreetmap/josm/plugins/elevation/grid/ElevationGridTile.java
===================================================================
--- applications/editors/josm/plugins/ElevationProfile/src/org/openstreetmap/josm/plugins/elevation/grid/ElevationGridTile.java	(revision 30736)
+++ applications/editors/josm/plugins/ElevationProfile/src/org/openstreetmap/josm/plugins/elevation/grid/ElevationGridTile.java	(revision 30737)
@@ -25,151 +25,151 @@
 
 public class ElevationGridTile extends Tile {
-    private final BlockingDeque<EleVertex> toDo = new LinkedBlockingDeque<EleVertex>();
-    private final BlockingDeque<EleVertex> vertices = new LinkedBlockingDeque<EleVertex>();
+	private final BlockingDeque<EleVertex> toDo = new LinkedBlockingDeque<>();
+	private final BlockingDeque<EleVertex> vertices = new LinkedBlockingDeque<>();
 
-    private Bounds box;
+	private Bounds box;
 
-    public ElevationGridTile(TileSource source, int xtile, int ytile, int zoom) {
-        super(source, xtile, ytile, zoom);
+	public ElevationGridTile(TileSource source, int xtile, int ytile, int zoom) {
+		super(source, xtile, ytile, zoom);
 
-        box = tile2Bounds(xtile, ytile, zoom);
-        initQueue();
-    }
+		box = tile2Bounds(xtile, ytile, zoom);
+		initQueue();
+	}
 
-    public ElevationGridTile(TileSource source, int xtile, int ytile, int zoom,
-            BufferedImage image) {
-        super(source, xtile, ytile, zoom, image);
+	public ElevationGridTile(TileSource source, int xtile, int ytile, int zoom,
+			BufferedImage image) {
+		super(source, xtile, ytile, zoom, image);
 
 
-    }
+	}
 
-    @Override
-    public void loadPlaceholderFromCache(TileCache cache) {
-        // TODO Auto-generated method stub
-        super.loadPlaceholderFromCache(cache);
+	@Override
+	public void loadPlaceholderFromCache(TileCache cache) {
+		// TODO Auto-generated method stub
+		super.loadPlaceholderFromCache(cache);
 
-        //System.out.println("loadPlaceholderFromCache");
-    }
+		//System.out.println("loadPlaceholderFromCache");
+	}
 
-    @Override
-    public String getUrl() throws IOException {
-        // TODO Auto-generated method stub
-        return super.getUrl();
-    }
+	@Override
+	public String getUrl() throws IOException {
+		// TODO Auto-generated method stub
+		return super.getUrl();
+	}
 
-    /**
-     * Use {@link ElevationGridTile#paintTile(Graphics2D, MapView, IVertexRenderer)} to render the tile as grid. This method just issues a debug text.
-     */
-    @Override
-    public void paint(Graphics g, int x, int y) {
-        super.paint(g, x, y);
+	/**
+	 * Use {@link ElevationGridTile#paintTile(Graphics2D, MapView, IVertexRenderer)} to render the tile as grid. This method just issues a debug text.
+	 */
+	@Override
+	public void paint(Graphics g, int x, int y) {
+		super.paint(g, x, y);
 
-        //g.drawString(String.format("EGT %d/%d ", getXtile(), getYtile()), x, y);
-        g.drawString(getStatus(), x, y);
-    }
+		//g.drawString(String.format("EGT %d/%d ", getXtile(), getYtile()), x, y);
+		g.drawString(getStatus(), x, y);
+	}
 
-    /**
-     * Paints the vertices of this tile.
-     *
-     * @param g the graphics context
-     * @param mv the map view
-     * @param vertexRenderer the vertex renderer
-     */
-    public void paintTile(Graphics2D g, MapView mv, IVertexRenderer vertexRenderer) {
-        BlockingDeque<EleVertex> list = getVertices();
-        for (EleVertex eleVertex : list) {
-            Point p0 = mv.getPoint(eleVertex.get(0));
-            Point p1 = mv.getPoint(eleVertex.get(1));
-            Point p2 = mv.getPoint(eleVertex.get(2));
-            Triangle shape = new Triangle(p0, p1, p2);
+	/**
+	 * Paints the vertices of this tile.
+	 *
+	 * @param g the graphics context
+	 * @param mv the map view
+	 * @param vertexRenderer the vertex renderer
+	 */
+	public void paintTile(Graphics2D g, MapView mv, IVertexRenderer vertexRenderer) {
+		BlockingDeque<EleVertex> list = getVertices();
+		for (EleVertex eleVertex : list) {
+			Point p0 = mv.getPoint(eleVertex.get(0));
+			Point p1 = mv.getPoint(eleVertex.get(1));
+			Point p2 = mv.getPoint(eleVertex.get(2));
+			Triangle shape = new Triangle(p0, p1, p2);
 
-            // obtain vertex color
-            g.setColor(vertexRenderer.getElevationColor(eleVertex));
-            // TODO: Move to renderer
-            g.fill(shape);
-        }
-    }
+			// obtain vertex color
+			g.setColor(vertexRenderer.getElevationColor(eleVertex));
+			// TODO: Move to renderer
+			g.fill(shape);
+		}
+	}
 
-    @Override
-    public void loadImage(InputStream input) throws IOException {
-        if (isLoaded()) return;
+	@Override
+	public void loadImage(InputStream input) throws IOException {
+		if (isLoaded()) return;
 
-        // TODO: Save
+		// TODO: Save
 
-        // We abuse the loadImage method to render the vertices...
-        //
-        while (toDo.size() > 0) {
-            EleVertex vertex = toDo.poll();
+		// We abuse the loadImage method to render the vertices...
+		//
+		while (toDo.size() > 0) {
+			EleVertex vertex = toDo.poll();
 
-            if (vertex.isFinished()) {
-                vertices.add(vertex);
-            } else {
-                List<EleVertex> newV = vertex.divide();
-                for (EleVertex eleVertex : newV) {
-                    toDo.add(eleVertex);
-                }
-            }
-        }
-        setLoaded(true);
-    }
+			if (vertex.isFinished()) {
+				vertices.add(vertex);
+			} else {
+				List<EleVertex> newV = vertex.divide();
+				for (EleVertex eleVertex : newV) {
+					toDo.add(eleVertex);
+				}
+			}
+		}
+		setLoaded(true);
+	}
 
-    public BlockingDeque<EleVertex> getVertices() {
-        return vertices;
-    }
+	public BlockingDeque<EleVertex> getVertices() {
+		return vertices;
+	}
 
-    /**
-     * See also <a href="http://wiki.openstreetmap.org/wiki/Slippy_map_tilenames#Tile_bounding_box">OSM Wiki</a>
-     * @param x the x
-     * @param y the y
-     * @param zoom the zoom
-     * @return the bounds
-     */
-    private Bounds tile2Bounds(final int x, final int y, final int zoom) {
-        Bounds bb = new Bounds(
-                new LatLon(source.tileYToLat(y, zoom), source.tileXToLon(x, zoom)),
-                new LatLon(source.tileYToLat(y + 1, zoom), source.tileXToLon(x + 1, zoom)));
+	/**
+	 * See also <a href="http://wiki.openstreetmap.org/wiki/Slippy_map_tilenames#Tile_bounding_box">OSM Wiki</a>
+	 * @param x the x
+	 * @param y the y
+	 * @param zoom the zoom
+	 * @return the bounds
+	 */
+	private Bounds tile2Bounds(final int x, final int y, final int zoom) {
+		Bounds bb = new Bounds(
+				new LatLon(source.tileYToLat(y, zoom), source.tileXToLon(x, zoom)),
+				new LatLon(source.tileYToLat(y + 1, zoom), source.tileXToLon(x + 1, zoom)));
 
-        return bb;
-    }
+		return bb;
+	}
 
-    /**
-     * Inits the 'todo' queue with the initial vertices.
-     */
-    private void initQueue() {
-        LatLon min = box.getMin();
-        LatLon max = box.getMax();
+	/**
+	 * Inits the 'todo' queue with the initial vertices.
+	 */
+	private void initQueue() {
+		LatLon min = box.getMin();
+		LatLon max = box.getMax();
 
-        // compute missing coordinates
-        LatLon h1 = new LatLon(min.lat(), max.lon());
-        LatLon h2 = new LatLon(max.lat(), min.lon());
+		// compute missing coordinates
+		LatLon h1 = new LatLon(min.lat(), max.lon());
+		LatLon h2 = new LatLon(max.lat(), min.lon());
 
-        double eleMin = ElevationHelper.getSrtmElevation(min);
-        double eleMax = ElevationHelper.getSrtmElevation(max);
+		double eleMin = ElevationHelper.getSrtmElevation(min);
+		double eleMax = ElevationHelper.getSrtmElevation(max);
 
-        // SRTM files present?
-        if (!ElevationHelper.isValidElevation(eleMax) || !ElevationHelper.isValidElevation(eleMin)) {
-            setError(tr("No SRTM data"));
-            return;
-        }
+		// SRTM files present?
+		if (!ElevationHelper.isValidElevation(eleMax) || !ElevationHelper.isValidElevation(eleMin)) {
+			setError(tr("No SRTM data"));
+			return;
+		}
 
-        // compute elevation coords
-        EleCoordinate p0 = new EleCoordinate(min, eleMin);
-        EleCoordinate p1 = new EleCoordinate(h1, ElevationHelper.getSrtmElevation(h1));
-        EleCoordinate p2 = new EleCoordinate(max, eleMax);
-        EleCoordinate p3 = new EleCoordinate(h2, ElevationHelper.getSrtmElevation(h2));
+		// compute elevation coords
+		EleCoordinate p0 = new EleCoordinate(min, eleMin);
+		EleCoordinate p1 = new EleCoordinate(h1, ElevationHelper.getSrtmElevation(h1));
+		EleCoordinate p2 = new EleCoordinate(max, eleMax);
+		EleCoordinate p3 = new EleCoordinate(h2, ElevationHelper.getSrtmElevation(h2));
 
-        // compute initial vertices
-        EleVertex v1 = new EleVertex(p0, p1, p2);
-        EleVertex v2 = new EleVertex(p2, p3, p0);
-        // enqueue vertices
-        toDo.add(v1);
-        toDo.add(v2);
-    }
+		// compute initial vertices
+		EleVertex v1 = new EleVertex(p0, p1, p2);
+		EleVertex v2 = new EleVertex(p2, p3, p0);
+		// enqueue vertices
+		toDo.add(v1);
+		toDo.add(v2);
+	}
 
-    @Override
-    public String toString() {
-        return "ElevationGridTile [box=" + box + ", xtile=" + xtile
-                + ", ytile=" + ytile + "]";
-    }
+	@Override
+	public String toString() {
+		return "ElevationGridTile [box=" + box + ", xtile=" + xtile
+				+ ", ytile=" + ytile + "]";
+	}
 
 
Index: applications/editors/josm/plugins/ElevationProfile/src/org/openstreetmap/josm/plugins/elevation/gui/DefaultElevationProfileRenderer.java
===================================================================
--- applications/editors/josm/plugins/ElevationProfile/src/org/openstreetmap/josm/plugins/elevation/gui/DefaultElevationProfileRenderer.java	(revision 30736)
+++ applications/editors/josm/plugins/ElevationProfile/src/org/openstreetmap/josm/plugins/elevation/gui/DefaultElevationProfileRenderer.java	(revision 30737)
@@ -33,510 +33,510 @@
 IElevationProfileRenderer {
 
-    private static final int ROUND_RECT_RADIUS = 6;
-    /**
-     * 
-     */
-    private static final int TRIANGLE_BASESIZE = 24;
-    /**
-     * 
-     */
-    private static final int BASIC_WPT_RADIUS = 1;
-    private static final int BIG_WPT_RADIUS = BASIC_WPT_RADIUS * 16;
-
-    // predefined colors
-    private static final Color HIGH_COLOR = ElevationColors.EPMidBlue;
-    private static final Color LOW_COLOR = ElevationColors.EPMidBlue;
-    private static final Color START_COLOR = Color.GREEN;
-    private static final Color END_POINT = Color.RED;
-    private static final Color LEVEL_GAIN_COLOR = Color.GREEN;
-    private static final Color LEVEL_LOSS_COLOR = Color.RED;
-    private static final Color MARKER_POINT = Color.YELLOW;
-    // Predefined radians
-    private static final double RAD_180 = Math.PI;
-    // private static final double RAD_270 = Math.PI * 1.5;
-    private static final double RAD_90 = Math.PI * 0.5;
-
-    private final List<Rectangle> forbiddenRects = new ArrayList<Rectangle>();
-
-    @Override
-    public Color getColorForWaypoint(IElevationProfile profile, WayPoint wpt,
-            ElevationWayPointKind kind) {
-
-        if (wpt == null || profile == null) {
-            System.err.println(String.format(
-                    "Cannot determine color: prof=%s, wpt=%s", profile, wpt));
-            return null;
-        }
-
-        switch (kind) {
-        case Plain:
-            return Color.LIGHT_GRAY;
-        case ElevationLevelLoss:
-            return LEVEL_LOSS_COLOR;
-        case ElevationLevelGain:
-            return LEVEL_GAIN_COLOR;
-        case Highlighted:
-            return Color.ORANGE;
-        case ElevationGainHigh:
-            return Color.getHSBColor(0.3f, 1.0f, 1.0f); // green
-        case ElevationLossHigh:
-            return Color.getHSBColor(0, 1.0f, 1.0f); // red
-        case ElevationGainLow:
-            return Color.getHSBColor(0.3f, 0.5f, 1.0f); // green with low sat
-        case ElevationLossLow:
-            return Color.getHSBColor(0, 0.5f, 1.0f); // red with low sat
-        case FullHour:
-            return MARKER_POINT;
-        case MaxElevation:
-            return HIGH_COLOR;
-        case MinElevation:
-            return LOW_COLOR;
-        case StartPoint:
-            return START_COLOR;
-        case EndPoint:
-            return END_POINT;
-        default:
-            break;
-        }
-
-        throw new RuntimeException("Unknown way point kind: " + kind);
-    }
-
-    @Override
-    public void renderWayPoint(Graphics g, IElevationProfile profile,
-            MapView mv, WayPoint wpt, ElevationWayPointKind kind) {
-
-        CheckParameterUtil.ensureParameterNotNull(g, "graphics");
-        CheckParameterUtil.ensureParameterNotNull(profile, "profile");
-        CheckParameterUtil.ensureParameterNotNull(mv, "map view");
-
-        if (wpt == null) {
-            System.err.println(String.format(
-                    "Cannot paint: mv=%s, prof=%s, wpt=%s", mv, profile, wpt));
-            return;
-        }
-
-        switch (kind) {
-        case MinElevation:
-        case MaxElevation:
-            renderMinMaxPoint(g, profile, mv, wpt, kind);
-            break;
-        case EndPoint:
-        case StartPoint:
-            renderStartEndPoint(g, profile, mv, wpt, kind);
-            break;
-        default:
-            renderRegularWayPoint(g, profile, mv, wpt, kind);
-            break;
-        }
-    }
-
-    @Override
-    public void renderLine(Graphics g, IElevationProfile profile,
-            MapView mv, WayPoint wpt1, WayPoint wpt2, ElevationWayPointKind kind) {
-
-        CheckParameterUtil.ensureParameterNotNull(g, "graphics");
-        CheckParameterUtil.ensureParameterNotNull(profile, "profile");
-        CheckParameterUtil.ensureParameterNotNull(mv, "map view");
-
-        if (wpt1 == null || wpt2 == null) {
-            System.err.println(String.format(
-                    "Cannot paint line: mv=%s, prof=%s, kind = %s", mv, profile, kind));
-            return;
-        }
-
-        // obtain and set color
-        g.setColor(getColorForWaypoint(profile, wpt2, kind));
-
-        // transform to view
-        Point pnt1 = mv.getPoint(wpt1.getEastNorth());
-        Point pnt2 = mv.getPoint(wpt2.getEastNorth());
-
-        // use thick line, if possible
-        if (g instanceof Graphics2D) {
-            Graphics2D g2 = (Graphics2D) g;
-            Stroke oldS = g2.getStroke();
-            try {
-                g2.setStroke(new BasicStroke(3, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND));
-                g2.drawLine(pnt1.x, pnt1.y, pnt2.x, pnt2.y);
-            } finally {
-                // must be restored; otherwise other layers may using this style, too
-                g2.setStroke(oldS);
-            }
-        } else {
-            // only poor man's graphics
-            g.drawLine(pnt1.x, pnt1.y, pnt2.x, pnt2.y);
-        }
-    }
-
-    /**
-     * Renders a regular way point.
-     * 
-     * @param g
-     *            The graphics context.
-     * @param profile
-     *            The elevation profile.
-     * @param mv
-     *            The map view instance.
-     * @param wpt
-     *            The way point to render.
-     * @param kind
-     *            The way point kind (start, end, max,...).
-     */
-    private void renderRegularWayPoint(Graphics g, IElevationProfile profile,
-            MapView mv, WayPoint wpt, ElevationWayPointKind kind) {
-
-        Color c = getColorForWaypoint(profile, wpt, kind);
-        Point pnt = mv.getPoint(wpt.getEastNorth());
-
-        /* Paint full hour label */
-        if (kind == ElevationWayPointKind.FullHour) {
-            int hour = ElevationHelper.getHourOfWayPoint(wpt);
-            drawLabel(String.format("%02d:00", hour), pnt.x, pnt.y
-                    + g.getFontMetrics().getHeight(), g);
-        }
-
-        /* Paint label for elevation levels */
-        if (kind == ElevationWayPointKind.ElevationLevelGain || kind == ElevationWayPointKind.ElevationLevelLoss) {
-            int ele = ((int) Math.rint(ElevationHelper.getElevation(wpt) / 100.0)) * 100;
-            drawLabelWithTriangle(ElevationHelper.getElevationText(ele), pnt.x, pnt.y
-                    + g.getFontMetrics().getHeight(), g, Color.darkGray, 8,
-                    getColorForWaypoint(profile, wpt, kind),
-                    kind == ElevationWayPointKind.ElevationLevelGain ? TriangleDir.Up : TriangleDir.Down);
-        }
-
-        /* Paint cursor labels */
-        if (kind == ElevationWayPointKind.Highlighted) {
-            drawSphere(g, Color.WHITE, c, pnt.x, pnt.y, BIG_WPT_RADIUS);
-            drawLabel(ElevationHelper.getTimeText(wpt), pnt.x, pnt.y
-                    - g.getFontMetrics().getHeight() - 5, g);
-            drawLabel(ElevationHelper.getElevationText(wpt), pnt.x, pnt.y
-                    + g.getFontMetrics().getHeight() + 5, g);
-        }
-    }
-
-    /**
-     * Renders a min/max point
-     * 
-     * @param g
-     *            The graphics context.
-     * @param profile
-     *            The elevation profile.
-     * @param mv
-     *            The map view instance.
-     * @param wpt
-     *            The way point to render.
-     * @param kind
-     *            The way point kind (start, end, max,...).
-     */
-    private void renderMinMaxPoint(Graphics g, IElevationProfile profile,
-            MapView mv, WayPoint wpt, ElevationWayPointKind kind) {
-
-        Color c = getColorForWaypoint(profile, wpt, kind);
-        int eleH = (int) ElevationHelper.getElevation(wpt);
-        Point pnt = mv.getPoint(wpt.getEastNorth());
-
-        TriangleDir td = TriangleDir.Up;
-
-        switch (kind) {
-        case MaxElevation:
-            td = TriangleDir.Up;
-            break;
-        case MinElevation:
-            td = TriangleDir.Down;
-            break;
-        case EndPoint:
-            td = TriangleDir.Left;
-            break;
-        case StartPoint:
-            td = TriangleDir.Right;
-            break;
-        default:
-            return; // nothing to do
-        }
-
-        drawRegularTriangle(g, c, td, pnt.x, pnt.y,
-                DefaultElevationProfileRenderer.TRIANGLE_BASESIZE);
-
-        drawLabel(ElevationHelper.getElevationText(eleH), pnt.x, pnt.y
-                + g.getFontMetrics().getHeight(), g, c);
-    }
-
-    /**
-     * Draws a regular triangle.
-     * 
-     * @param g
-     *            The graphics context.
-     * @param c
-     *            The fill color of the triangle.
-     * @param dir
-     *            The direction of the triangle
-     * @param x
-     *            The x coordinate in the graphics context.
-     * @param y
-     *            The y coordinate in the graphics context.
-     * @param baseLength
-     *            The side length in pixel of the triangle.
-     */
-    private void drawRegularTriangle(Graphics g, Color c, TriangleDir dir,
-            int x, int y, int baseLength) {
-        if (baseLength < 2)
-            return; // cannot render triangle
-
-        int b2 = baseLength >> 1;
-
-        // coordinates for upwards directed triangle
-        Point p[] = new Point[3];
-
-        for (int i = 0; i < p.length; i++) {
-            p[i] = new Point();
-        }
-
-        p[0].x = -b2;
-        p[0].y = b2;
-
-        p[1].x = b2;
-        p[1].y = b2;
-
-        p[2].x = 0;
-        p[2].y = -b2;
-
-        Triangle t = new Triangle(p[0], p[1], p[2]);
-
-        // rotation angle in rad
-        double theta = 0.0;
-
-        switch (dir) {
-        case Up:
-            theta = 0.0;
-            break;
-        case Down:
-            theta = RAD_180;
-            break;
-        case Left:
-            theta = -RAD_90;
-            break;
-        case Right:
-            theta = RAD_90;
-            break;
-        }
-
-        // rotate shape
-        AffineTransform at = AffineTransform.getRotateInstance(theta);
-        Shape tRot = at.createTransformedShape(t);
-        // translate shape
-        AffineTransform at2 = AffineTransform.getTranslateInstance(x, y);
-        Shape ts = at2.createTransformedShape(tRot);
-
-        // draw the shape
-        Graphics2D g2 = (Graphics2D) g;
-        if (g2 != null) {
-            Color oldC = g2.getColor();
-            g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
-                    RenderingHints.VALUE_ANTIALIAS_ON);
-            g2.setColor(c);
-            g2.fill(ts);
-            g2.setColor(oldC);
-        }
-    }
-
-    /**
-     * Renders a start/end point.
-     * 
-     * @param g
-     *            The graphics context.
-     * @param profile
-     *            The elevation profile.
-     * @param mv
-     *            The map view instance.
-     * @param wpt
-     *            The way point to render.
-     * @param kind
-     *            The way point kind (start, end, max,...).
-     */
-    private void renderStartEndPoint(Graphics g, IElevationProfile profile,
-            MapView mv, WayPoint wpt, ElevationWayPointKind kind) {
-
-        Color c = getColorForWaypoint(profile, wpt, kind);
-        Point pnt = mv.getPoint(wpt.getEastNorth());
-        drawSphere(g, Color.WHITE, c, pnt.x, pnt.y, BIG_WPT_RADIUS);
-    }
-
-    /**
-     * Draws a shaded sphere.
-     * 
-     * @param g
-     *            The graphics context.
-     * @param firstCol
-     *            The focus color (usually white).
-     * @param secondCol
-     *            The sphere color.
-     * @param x
-     *            The x coordinate of the sphere center.
-     * @param y
-     *            The y coordinate of the sphere center.
-     * @param radius
-     *            The radius of the sphere.
-     */
-    private void drawSphere(Graphics g, Color firstCol, Color secondCol, int x,
-            int y, int radius) {
-        Point2D center = new Point2D.Float(x, y);
-        Point2D focus = new Point2D.Float(x - (radius * 0.6f), y
-                - (radius * 0.6f));
-        float[] dist = { 0.1f, 0.2f, 1.0f };
-        Color[] colors = { firstCol, secondCol, Color.DARK_GRAY };
-        RadialGradientPaint p = new RadialGradientPaint(center, radius, focus,
-                dist, colors, CycleMethod.NO_CYCLE);
-
-        Graphics2D g2 = (Graphics2D) g;
-        if (g2 != null) {
-            g2.setPaint(p);
-            int r2 = radius / 2;
-            g2.fillOval(x - r2, y - r2, radius, radius);
-        }
-    }
-
-    /**
-     * Draws a label within a filled rounded rectangle with standard gradient colors.
-     * 
-     * @param s
-     *            The text to draw.
-     * @param x
-     *            The x coordinate of the label.
-     * @param y
-     *            The y coordinate of the label.
-     * @param g
-     *            The graphics context.
-     */
-    private void drawLabel(String s, int x, int y, Graphics g) {
-        drawLabel(s, x, y, g, Color.GRAY);
-    }
-
-    /**
-     * Draws a label within a filled rounded rectangle with the specified second gradient color (first color is <tt>Color.WHITE<tt>).
-     * 
-     * @param s
-     *            The text to draw.
-     * @param x
-     *            The x coordinate of the label.
-     * @param y
-     *            The y coordinate of the label.
-     * @param g
-     *            The graphics context.
-     * @param secondGradColor
-     *            The second color of the gradient.
-     */
-    private void drawLabel(String s, int x, int y, Graphics g,
-            Color secondGradColor) {
-        Graphics2D g2d = (Graphics2D) g;
-
-        int width = g.getFontMetrics(g.getFont()).stringWidth(s) + 10;
-        int height = g.getFont().getSize() + g.getFontMetrics().getLeading()
-                + 5;
-
-        Rectangle r = new Rectangle(x - (width / 2), y - (height / 2), width,
-                height);
-
-        if (isForbiddenArea(r)) {
-            return; // no space left, skip this label
-        }
-
-        g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
-                RenderingHints.VALUE_ANTIALIAS_ON);
-        GradientPaint gradient = new GradientPaint(x, y, Color.WHITE, x, y
-                + (height / 2), secondGradColor, false);
-        g2d.setPaint(gradient);
-
-        g2d.fillRoundRect(r.x, r.y, r.width, r.height, ROUND_RECT_RADIUS,
-                ROUND_RECT_RADIUS);
-
-        g2d.setColor(Color.BLACK);
-
-        g2d.drawRoundRect(r.x, r.y, r.width, r.height, ROUND_RECT_RADIUS,
-                ROUND_RECT_RADIUS);
-        g2d.drawString(s, x - (width / 2) + 5, y + (height / 2) - 3);
-
-        forbiddenRects.add(r);
-    }
-
-    /**
-     * Draws a label with an additional triangle on the left side.
-     * 
-     * @param s
-     *            The text to draw.
-     * @param x
-     *            The x coordinate of the label.
-     * @param y
-     *            The y coordinate of the label.
-     * @param g
-     *            The graphics context.
-     * @param secondGradColor
-     *            The second color of the gradient.
-     * @param baseLength
-     *            The base length of the triangle in pixels.
-     * @param triangleColor
-     *            The color of the triangle.
-     * @param triangleDir
-     *            The direction of the triangle.
-     */
-    private void drawLabelWithTriangle(String s, int x, int y, Graphics g,
-            Color secondGradColor, int baseLength, Color triangleColor,
-            TriangleDir triangleDir) {
-        Graphics2D g2d = (Graphics2D) g;
-
-        int width = g.getFontMetrics(g.getFont()).stringWidth(s) + 10 + baseLength + 5;
-        int height = g.getFont().getSize() + g.getFontMetrics().getLeading() + 5;
-
-        Rectangle r = new Rectangle(x - (width / 2), y - (height / 2), width, height);
-
-        if (isForbiddenArea(r)) {
-            return; // no space left, skip this label
-        }
-
-        g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
-                RenderingHints.VALUE_ANTIALIAS_ON);
-        GradientPaint gradient = new GradientPaint(x, y, Color.WHITE, x, y
-                + (height / 2), secondGradColor, false);
-        g2d.setPaint(gradient);
-
-        g2d.fillRoundRect(r.x, r.y, r.width, r.height, ROUND_RECT_RADIUS,
-                ROUND_RECT_RADIUS);
-
-        g2d.setColor(Color.BLACK);
-
-        g2d.drawRoundRect(r.x, r.y, r.width, r.height, ROUND_RECT_RADIUS,
-                ROUND_RECT_RADIUS);
-        g2d.drawString(s, x - (width / 2) + 8 + baseLength, y + (height / 2) - 3);
-        drawRegularTriangle(g2d, triangleColor, triangleDir, r.x + baseLength,
-                r.y + baseLength, baseLength);
-
-        forbiddenRects.add(r);
-    }
-
-    /**
-     * Checks, if the rectangle has been 'reserved' by an previous draw action.
-     * 
-     * @param r
-     *            The area to check for.
-     * @return true, if area is already occupied by another rectangle.
-     */
-    private boolean isForbiddenArea(Rectangle r) {
-
-        for (Rectangle rTest : forbiddenRects) {
-            if (r.intersects(rTest))
-                return true;
-        }
-        return false;
-    }
-
-    @Override
-    public void beginRendering() {
-        forbiddenRects.clear();
-    }
-
-    @Override
-    public void finishRendering() {
-        // nothing to do currently
-    }
+	private static final int ROUND_RECT_RADIUS = 6;
+	/**
+	 *
+	 */
+	private static final int TRIANGLE_BASESIZE = 24;
+	/**
+	 *
+	 */
+	private static final int BASIC_WPT_RADIUS = 1;
+	private static final int BIG_WPT_RADIUS = BASIC_WPT_RADIUS * 16;
+
+	// predefined colors
+	private static final Color HIGH_COLOR = ElevationColors.EPMidBlue;
+	private static final Color LOW_COLOR = ElevationColors.EPMidBlue;
+	private static final Color START_COLOR = Color.GREEN;
+	private static final Color END_POINT = Color.RED;
+	private static final Color LEVEL_GAIN_COLOR = Color.GREEN;
+	private static final Color LEVEL_LOSS_COLOR = Color.RED;
+	private static final Color MARKER_POINT = Color.YELLOW;
+	// Predefined radians
+	private static final double RAD_180 = Math.PI;
+	// private static final double RAD_270 = Math.PI * 1.5;
+	private static final double RAD_90 = Math.PI * 0.5;
+
+	private final List<Rectangle> forbiddenRects = new ArrayList<>();
+
+	@Override
+	public Color getColorForWaypoint(IElevationProfile profile, WayPoint wpt,
+			ElevationWayPointKind kind) {
+
+		if (wpt == null || profile == null) {
+			System.err.println(String.format(
+					"Cannot determine color: prof=%s, wpt=%s", profile, wpt));
+			return null;
+		}
+
+		switch (kind) {
+		case Plain:
+			return Color.LIGHT_GRAY;
+		case ElevationLevelLoss:
+			return LEVEL_LOSS_COLOR;
+		case ElevationLevelGain:
+			return LEVEL_GAIN_COLOR;
+		case Highlighted:
+			return Color.ORANGE;
+		case ElevationGainHigh:
+			return Color.getHSBColor(0.3f, 1.0f, 1.0f); // green
+		case ElevationLossHigh:
+			return Color.getHSBColor(0, 1.0f, 1.0f); // red
+		case ElevationGainLow:
+			return Color.getHSBColor(0.3f, 0.5f, 1.0f); // green with low sat
+		case ElevationLossLow:
+			return Color.getHSBColor(0, 0.5f, 1.0f); // red with low sat
+		case FullHour:
+			return MARKER_POINT;
+		case MaxElevation:
+			return HIGH_COLOR;
+		case MinElevation:
+			return LOW_COLOR;
+		case StartPoint:
+			return START_COLOR;
+		case EndPoint:
+			return END_POINT;
+		default:
+			break;
+		}
+
+		throw new RuntimeException("Unknown way point kind: " + kind);
+	}
+
+	@Override
+	public void renderWayPoint(Graphics g, IElevationProfile profile,
+			MapView mv, WayPoint wpt, ElevationWayPointKind kind) {
+
+		CheckParameterUtil.ensureParameterNotNull(g, "graphics");
+		CheckParameterUtil.ensureParameterNotNull(profile, "profile");
+		CheckParameterUtil.ensureParameterNotNull(mv, "map view");
+
+		if (wpt == null) {
+			System.err.println(String.format(
+					"Cannot paint: mv=%s, prof=%s, wpt=%s", mv, profile, wpt));
+			return;
+		}
+
+		switch (kind) {
+		case MinElevation:
+		case MaxElevation:
+			renderMinMaxPoint(g, profile, mv, wpt, kind);
+			break;
+		case EndPoint:
+		case StartPoint:
+			renderStartEndPoint(g, profile, mv, wpt, kind);
+			break;
+		default:
+			renderRegularWayPoint(g, profile, mv, wpt, kind);
+			break;
+		}
+	}
+
+	@Override
+	public void renderLine(Graphics g, IElevationProfile profile,
+			MapView mv, WayPoint wpt1, WayPoint wpt2, ElevationWayPointKind kind) {
+
+		CheckParameterUtil.ensureParameterNotNull(g, "graphics");
+		CheckParameterUtil.ensureParameterNotNull(profile, "profile");
+		CheckParameterUtil.ensureParameterNotNull(mv, "map view");
+
+		if (wpt1 == null || wpt2 == null) {
+			System.err.println(String.format(
+					"Cannot paint line: mv=%s, prof=%s, kind = %s", mv, profile, kind));
+			return;
+		}
+
+		// obtain and set color
+		g.setColor(getColorForWaypoint(profile, wpt2, kind));
+
+		// transform to view
+		Point pnt1 = mv.getPoint(wpt1.getEastNorth());
+		Point pnt2 = mv.getPoint(wpt2.getEastNorth());
+
+		// use thick line, if possible
+		if (g instanceof Graphics2D) {
+			Graphics2D g2 = (Graphics2D) g;
+			Stroke oldS = g2.getStroke();
+			try {
+				g2.setStroke(new BasicStroke(3, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND));
+				g2.drawLine(pnt1.x, pnt1.y, pnt2.x, pnt2.y);
+			} finally {
+				// must be restored; otherwise other layers may using this style, too
+				g2.setStroke(oldS);
+			}
+		} else {
+			// only poor man's graphics
+			g.drawLine(pnt1.x, pnt1.y, pnt2.x, pnt2.y);
+		}
+	}
+
+	/**
+	 * Renders a regular way point.
+	 *
+	 * @param g
+	 *            The graphics context.
+	 * @param profile
+	 *            The elevation profile.
+	 * @param mv
+	 *            The map view instance.
+	 * @param wpt
+	 *            The way point to render.
+	 * @param kind
+	 *            The way point kind (start, end, max,...).
+	 */
+	private void renderRegularWayPoint(Graphics g, IElevationProfile profile,
+			MapView mv, WayPoint wpt, ElevationWayPointKind kind) {
+
+		Color c = getColorForWaypoint(profile, wpt, kind);
+		Point pnt = mv.getPoint(wpt.getEastNorth());
+
+		/* Paint full hour label */
+		if (kind == ElevationWayPointKind.FullHour) {
+			int hour = ElevationHelper.getHourOfWayPoint(wpt);
+			drawLabel(String.format("%02d:00", hour), pnt.x, pnt.y
+					+ g.getFontMetrics().getHeight(), g);
+		}
+
+		/* Paint label for elevation levels */
+		if (kind == ElevationWayPointKind.ElevationLevelGain || kind == ElevationWayPointKind.ElevationLevelLoss) {
+			int ele = ((int) Math.rint(ElevationHelper.getElevation(wpt) / 100.0)) * 100;
+			drawLabelWithTriangle(ElevationHelper.getElevationText(ele), pnt.x, pnt.y
+					+ g.getFontMetrics().getHeight(), g, Color.darkGray, 8,
+					getColorForWaypoint(profile, wpt, kind),
+					kind == ElevationWayPointKind.ElevationLevelGain ? TriangleDir.Up : TriangleDir.Down);
+		}
+
+		/* Paint cursor labels */
+		if (kind == ElevationWayPointKind.Highlighted) {
+			drawSphere(g, Color.WHITE, c, pnt.x, pnt.y, BIG_WPT_RADIUS);
+			drawLabel(ElevationHelper.getTimeText(wpt), pnt.x, pnt.y
+					- g.getFontMetrics().getHeight() - 5, g);
+			drawLabel(ElevationHelper.getElevationText(wpt), pnt.x, pnt.y
+					+ g.getFontMetrics().getHeight() + 5, g);
+		}
+	}
+
+	/**
+	 * Renders a min/max point
+	 *
+	 * @param g
+	 *            The graphics context.
+	 * @param profile
+	 *            The elevation profile.
+	 * @param mv
+	 *            The map view instance.
+	 * @param wpt
+	 *            The way point to render.
+	 * @param kind
+	 *            The way point kind (start, end, max,...).
+	 */
+	private void renderMinMaxPoint(Graphics g, IElevationProfile profile,
+			MapView mv, WayPoint wpt, ElevationWayPointKind kind) {
+
+		Color c = getColorForWaypoint(profile, wpt, kind);
+		int eleH = (int) ElevationHelper.getElevation(wpt);
+		Point pnt = mv.getPoint(wpt.getEastNorth());
+
+		TriangleDir td = TriangleDir.Up;
+
+		switch (kind) {
+		case MaxElevation:
+			td = TriangleDir.Up;
+			break;
+		case MinElevation:
+			td = TriangleDir.Down;
+			break;
+		case EndPoint:
+			td = TriangleDir.Left;
+			break;
+		case StartPoint:
+			td = TriangleDir.Right;
+			break;
+		default:
+			return; // nothing to do
+		}
+
+		drawRegularTriangle(g, c, td, pnt.x, pnt.y,
+				DefaultElevationProfileRenderer.TRIANGLE_BASESIZE);
+
+		drawLabel(ElevationHelper.getElevationText(eleH), pnt.x, pnt.y
+				+ g.getFontMetrics().getHeight(), g, c);
+	}
+
+	/**
+	 * Draws a regular triangle.
+	 *
+	 * @param g
+	 *            The graphics context.
+	 * @param c
+	 *            The fill color of the triangle.
+	 * @param dir
+	 *            The direction of the triangle
+	 * @param x
+	 *            The x coordinate in the graphics context.
+	 * @param y
+	 *            The y coordinate in the graphics context.
+	 * @param baseLength
+	 *            The side length in pixel of the triangle.
+	 */
+	private void drawRegularTriangle(Graphics g, Color c, TriangleDir dir,
+			int x, int y, int baseLength) {
+		if (baseLength < 2)
+			return; // cannot render triangle
+
+		int b2 = baseLength >> 1;
+
+		// coordinates for upwards directed triangle
+		Point p[] = new Point[3];
+
+		for (int i = 0; i < p.length; i++) {
+			p[i] = new Point();
+		}
+
+		p[0].x = -b2;
+		p[0].y = b2;
+
+		p[1].x = b2;
+		p[1].y = b2;
+
+		p[2].x = 0;
+		p[2].y = -b2;
+
+		Triangle t = new Triangle(p[0], p[1], p[2]);
+
+		// rotation angle in rad
+		double theta = 0.0;
+
+		switch (dir) {
+		case Up:
+			theta = 0.0;
+			break;
+		case Down:
+			theta = RAD_180;
+			break;
+		case Left:
+			theta = -RAD_90;
+			break;
+		case Right:
+			theta = RAD_90;
+			break;
+		}
+
+		// rotate shape
+		AffineTransform at = AffineTransform.getRotateInstance(theta);
+		Shape tRot = at.createTransformedShape(t);
+		// translate shape
+		AffineTransform at2 = AffineTransform.getTranslateInstance(x, y);
+		Shape ts = at2.createTransformedShape(tRot);
+
+		// draw the shape
+		Graphics2D g2 = (Graphics2D) g;
+		if (g2 != null) {
+			Color oldC = g2.getColor();
+			g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
+					RenderingHints.VALUE_ANTIALIAS_ON);
+			g2.setColor(c);
+			g2.fill(ts);
+			g2.setColor(oldC);
+		}
+	}
+
+	/**
+	 * Renders a start/end point.
+	 *
+	 * @param g
+	 *            The graphics context.
+	 * @param profile
+	 *            The elevation profile.
+	 * @param mv
+	 *            The map view instance.
+	 * @param wpt
+	 *            The way point to render.
+	 * @param kind
+	 *            The way point kind (start, end, max,...).
+	 */
+	private void renderStartEndPoint(Graphics g, IElevationProfile profile,
+			MapView mv, WayPoint wpt, ElevationWayPointKind kind) {
+
+		Color c = getColorForWaypoint(profile, wpt, kind);
+		Point pnt = mv.getPoint(wpt.getEastNorth());
+		drawSphere(g, Color.WHITE, c, pnt.x, pnt.y, BIG_WPT_RADIUS);
+	}
+
+	/**
+	 * Draws a shaded sphere.
+	 *
+	 * @param g
+	 *            The graphics context.
+	 * @param firstCol
+	 *            The focus color (usually white).
+	 * @param secondCol
+	 *            The sphere color.
+	 * @param x
+	 *            The x coordinate of the sphere center.
+	 * @param y
+	 *            The y coordinate of the sphere center.
+	 * @param radius
+	 *            The radius of the sphere.
+	 */
+	private void drawSphere(Graphics g, Color firstCol, Color secondCol, int x,
+			int y, int radius) {
+		Point2D center = new Point2D.Float(x, y);
+		Point2D focus = new Point2D.Float(x - (radius * 0.6f), y
+				- (radius * 0.6f));
+		float[] dist = { 0.1f, 0.2f, 1.0f };
+		Color[] colors = { firstCol, secondCol, Color.DARK_GRAY };
+		RadialGradientPaint p = new RadialGradientPaint(center, radius, focus,
+				dist, colors, CycleMethod.NO_CYCLE);
+
+		Graphics2D g2 = (Graphics2D) g;
+		if (g2 != null) {
+			g2.setPaint(p);
+			int r2 = radius / 2;
+			g2.fillOval(x - r2, y - r2, radius, radius);
+		}
+	}
+
+	/**
+	 * Draws a label within a filled rounded rectangle with standard gradient colors.
+	 *
+	 * @param s
+	 *            The text to draw.
+	 * @param x
+	 *            The x coordinate of the label.
+	 * @param y
+	 *            The y coordinate of the label.
+	 * @param g
+	 *            The graphics context.
+	 */
+	private void drawLabel(String s, int x, int y, Graphics g) {
+		drawLabel(s, x, y, g, Color.GRAY);
+	}
+
+	/**
+	 * Draws a label within a filled rounded rectangle with the specified second gradient color (first color is <tt>Color.WHITE<tt>).
+	 *
+	 * @param s
+	 *            The text to draw.
+	 * @param x
+	 *            The x coordinate of the label.
+	 * @param y
+	 *            The y coordinate of the label.
+	 * @param g
+	 *            The graphics context.
+	 * @param secondGradColor
+	 *            The second color of the gradient.
+	 */
+	private void drawLabel(String s, int x, int y, Graphics g,
+			Color secondGradColor) {
+		Graphics2D g2d = (Graphics2D) g;
+
+		int width = g.getFontMetrics(g.getFont()).stringWidth(s) + 10;
+		int height = g.getFont().getSize() + g.getFontMetrics().getLeading()
+				+ 5;
+
+		Rectangle r = new Rectangle(x - (width / 2), y - (height / 2), width,
+				height);
+
+		if (isForbiddenArea(r)) {
+			return; // no space left, skip this label
+		}
+
+		g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
+				RenderingHints.VALUE_ANTIALIAS_ON);
+		GradientPaint gradient = new GradientPaint(x, y, Color.WHITE, x, y
+				+ (height / 2), secondGradColor, false);
+		g2d.setPaint(gradient);
+
+		g2d.fillRoundRect(r.x, r.y, r.width, r.height, ROUND_RECT_RADIUS,
+				ROUND_RECT_RADIUS);
+
+		g2d.setColor(Color.BLACK);
+
+		g2d.drawRoundRect(r.x, r.y, r.width, r.height, ROUND_RECT_RADIUS,
+				ROUND_RECT_RADIUS);
+		g2d.drawString(s, x - (width / 2) + 5, y + (height / 2) - 3);
+
+		forbiddenRects.add(r);
+	}
+
+	/**
+	 * Draws a label with an additional triangle on the left side.
+	 *
+	 * @param s
+	 *            The text to draw.
+	 * @param x
+	 *            The x coordinate of the label.
+	 * @param y
+	 *            The y coordinate of the label.
+	 * @param g
+	 *            The graphics context.
+	 * @param secondGradColor
+	 *            The second color of the gradient.
+	 * @param baseLength
+	 *            The base length of the triangle in pixels.
+	 * @param triangleColor
+	 *            The color of the triangle.
+	 * @param triangleDir
+	 *            The direction of the triangle.
+	 */
+	private void drawLabelWithTriangle(String s, int x, int y, Graphics g,
+			Color secondGradColor, int baseLength, Color triangleColor,
+			TriangleDir triangleDir) {
+		Graphics2D g2d = (Graphics2D) g;
+
+		int width = g.getFontMetrics(g.getFont()).stringWidth(s) + 10 + baseLength + 5;
+		int height = g.getFont().getSize() + g.getFontMetrics().getLeading() + 5;
+
+		Rectangle r = new Rectangle(x - (width / 2), y - (height / 2), width, height);
+
+		if (isForbiddenArea(r)) {
+			return; // no space left, skip this label
+		}
+
+		g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
+				RenderingHints.VALUE_ANTIALIAS_ON);
+		GradientPaint gradient = new GradientPaint(x, y, Color.WHITE, x, y
+				+ (height / 2), secondGradColor, false);
+		g2d.setPaint(gradient);
+
+		g2d.fillRoundRect(r.x, r.y, r.width, r.height, ROUND_RECT_RADIUS,
+				ROUND_RECT_RADIUS);
+
+		g2d.setColor(Color.BLACK);
+
+		g2d.drawRoundRect(r.x, r.y, r.width, r.height, ROUND_RECT_RADIUS,
+				ROUND_RECT_RADIUS);
+		g2d.drawString(s, x - (width / 2) + 8 + baseLength, y + (height / 2) - 3);
+		drawRegularTriangle(g2d, triangleColor, triangleDir, r.x + baseLength,
+				r.y + baseLength, baseLength);
+
+		forbiddenRects.add(r);
+	}
+
+	/**
+	 * Checks, if the rectangle has been 'reserved' by an previous draw action.
+	 *
+	 * @param r
+	 *            The area to check for.
+	 * @return true, if area is already occupied by another rectangle.
+	 */
+	private boolean isForbiddenArea(Rectangle r) {
+
+		for (Rectangle rTest : forbiddenRects) {
+			if (r.intersects(rTest))
+				return true;
+		}
+		return false;
+	}
+
+	@Override
+	public void beginRendering() {
+		forbiddenRects.clear();
+	}
+
+	@Override
+	public void finishRendering() {
+		// nothing to do currently
+	}
 
 
Index: applications/editors/josm/plugins/ElevationProfile/src/org/openstreetmap/josm/plugins/elevation/gui/ElevationProfileDialog.java
===================================================================
--- applications/editors/josm/plugins/ElevationProfile/src/org/openstreetmap/josm/plugins/elevation/gui/ElevationProfileDialog.java	(revision 30736)
+++ applications/editors/josm/plugins/ElevationProfile/src/org/openstreetmap/josm/plugins/elevation/gui/ElevationProfileDialog.java	(revision 30737)
@@ -47,415 +47,415 @@
 public class ElevationProfileDialog extends ToggleDialog implements LayerChangeListener, ComponentListener {
 
-    private static final String EMPTY_DATA_STRING = "-";
-    private static final long serialVersionUID = -868463893732535577L;
-    /* Elevation profile instance */
-    private IElevationModel model;
-    /* GPX data */
-    private GpxLayer activeLayer = null;
-    private final HashMap<GpxLayer, ElevationModel> layerMap = new HashMap<GpxLayer, ElevationModel>();
-
-    /* UI elements */
-    private final ElevationProfilePanel profPanel;
-    private final JLabel minHeightLabel;
-    private final JLabel maxHeightLabel;
-    private final JLabel avrgHeightLabel;
-    private final JLabel elevationGainLabel;
-    private final JLabel totalTimeLabel;
-    private final JLabel distLabel;
-    private final JComboBox<IElevationProfile> trackCombo;
-    private final JButton zoomButton;
-
-    /* Listener to the elevation model */
-    private final List<IElevationModelListener> listeners = new ArrayList<IElevationModelListener>();
-
-    /**
-     * Corresponding layer instance within map view.
-     */
-    private ElevationProfileLayer profileLayer;
-
-    /**
-     * Default constructor
-     */
-    public ElevationProfileDialog() {
-        this(tr("Elevation Profile"), "elevation",
-                tr("Open the elevation profile window."), null, 200, true);
-    }
-
-    /**
-     * Constructor (see below)
-     */
-    public ElevationProfileDialog(String name, String iconName, String tooltip,
-            Shortcut shortcut, int preferredHeight) {
-        this(name, iconName, tooltip, shortcut, preferredHeight, false);
-    }
-
-    /**
-     * Constructor
-     * 
-     * @param name
-     *            the name of the dialog
-     * @param iconName
-     *            the name of the icon to be displayed
-     * @param tooltip
-     *            the tool tip
-     * @param shortcut
-     *            the shortcut
-     * @param preferredHeight
-     *            the preferred height for the dialog
-     * @param defShow
-     *            if the dialog should be shown by default, if there is no
-     *            preference
-     */
-    public ElevationProfileDialog(String name, String iconName, String tooltip,
-            Shortcut shortcut, int preferredHeight, boolean defShow) {
-        super(name, iconName, tooltip, shortcut, preferredHeight, defShow);
-
-        // create model
-        model = new ElevationModel();
-
-        // top panel
-        JPanel rootPanel = new JPanel();
-        GridLayout gridLayout1 = new GridLayout(2, 1);
-        rootPanel.setLayout(gridLayout1);
-
-        // statistics panel
-        JPanel statPanel = new JPanel();
-        GridLayout gridLayoutStat = new GridLayout(2, 6);
-        statPanel.setLayout(gridLayoutStat);
-
-        // first row: Headlines with bold font
-        String[] labels = new String[]{tr("Min"), tr("Avrg"), tr("Max"), tr("Dist"), tr("Gain"), tr("Time")};
-        for (int i = 0; i < labels.length; i++) {
-            JLabel lbl = new JLabel(labels[i]);
-            lbl.setFont(getFont().deriveFont(Font.BOLD));
-            statPanel.add(lbl);
-        }
-
-        // second row
-        minHeightLabel = new JLabel("0 m");
-        statPanel.add(minHeightLabel);
-        avrgHeightLabel = new JLabel("0 m");
-        statPanel.add(avrgHeightLabel);
-        maxHeightLabel = new JLabel("0 m");
-        statPanel.add(maxHeightLabel);
-        distLabel = new JLabel("0 km");
-        statPanel.add(distLabel);
-        elevationGainLabel = new JLabel("0 m");
-        statPanel.add(elevationGainLabel);
-        totalTimeLabel = new JLabel("0");
-        statPanel.add(totalTimeLabel);
-
-        // track selection panel
-        JPanel trackPanel = new JPanel();
-        FlowLayout fl = new FlowLayout(FlowLayout.LEFT);
-        trackPanel.setLayout(fl);
-
-        JLabel lbTrack = new JLabel(tr("Tracks"));
-        lbTrack.setFont(getFont().deriveFont(Font.BOLD));
-        trackPanel.add(lbTrack);
-
-        zoomButton = new JButton(tr("Zoom"));
-        zoomButton.addActionListener(new ActionListener() {
-            @Override
-            public void actionPerformed(ActionEvent arg0) {
-                if (model != null) {
-                    IElevationProfile profile = model.getCurrentProfile();
-                    if (profile != null) {
-                        Main.map.mapView.zoomTo(profile.getBounds());
-                    }
-                }
-
-            }
-        });
-        zoomButton.setEnabled(false);
-
-        trackCombo = new JComboBox<>(new TrackModel());
-        trackCombo.setPreferredSize(new Dimension(200, 24)); // HACK!
-        trackCombo.setEnabled(false); // we have no model on startup
-
-        trackPanel.add(trackCombo);
-        trackPanel.add(zoomButton);
-
-        // assemble root panel
-        rootPanel.add(statPanel);
-        rootPanel.add(trackPanel);
-
-        JPanel mainPanel = new JPanel(new BorderLayout());
-        mainPanel.add(rootPanel, BorderLayout.PAGE_END);
-
-        // add chart component
-        profPanel = new ElevationProfilePanel(null);
-        mainPanel.add(profPanel, BorderLayout.CENTER);
-        profPanel.addComponentListener(this);
-
-        createLayout(mainPanel, true, null);
-    }
-
-    @Override
-    public void showNotify() {
-        MapView.addLayerChangeListener(this);
-        if (Main.isDisplayingMapView()) {
-            Layer layer = Main.map.mapView.getActiveLayer();
-            if (layer instanceof GpxLayer) {
-                setActiveLayer((GpxLayer) layer);
-            }
-        }
-    }
-
-    @Override
-    public void hideNotify() {
-        MapView.removeLayerChangeListener(this);
-    }
-
-    /**
-     * Gets the elevation model instance.
-     * @return
-     */
-    public IElevationModel getModel() {
-        return model;
-    }
-
-    /**
-     * Sets the elevation model instance.
-     * @param model The new model.
-     */
-    public void setModel(IElevationModel model) {
-        if (this.model != model) {
-            this.model = model;
-            profPanel.setElevationModel(model);
-            updateView();
-        }
-    }
-
-    /**
-     * Gets the associated layer instance of the elevation profile.
-     * @return
-     */
-    public ElevationProfileLayer getProfileLayer() {
-        return profileLayer;
-    }
-
-    /**
-     * Sets the associated layer instance of the elevation profile.
-     * @param profileLayer The elevation profile layer.
-     */
-    public void setProfileLayer(ElevationProfileLayer profileLayer) {
-        if (this.profileLayer != profileLayer) {
-            if (this.profileLayer != null) {
-                profPanel.removeSelectionListener(this.profileLayer);
-            }
-            this.profileLayer = profileLayer;
-            profPanel.addSelectionListener(this.profileLayer);
-        }
-    }
-
-    /**
-     * Refreshes the dialog when model data have changed and notifies clients
-     * that the model has changed.
-     */
-    private void updateView() {
-        if (model == null) {
-            disableView();
-            return;
-        }
-
-        IElevationProfile profile = model.getCurrentProfile();
-        if (profile != null) {
-            // Show name of profile in title
-            setTitle(String.format("%s: %s", tr("Elevation Profile"), profile.getName()));
-
-            if (profile.hasElevationData()) {
-                // Show elevation data
-                minHeightLabel.setText(
-                        ElevationHelper.getElevationText(profile.getMinHeight()));
-                maxHeightLabel.setText(
-                        ElevationHelper.getElevationText(profile.getMaxHeight()));
-                avrgHeightLabel.setText(
-                        ElevationHelper.getElevationText(profile.getAverageHeight()));
-                elevationGainLabel.setText(
-                        ElevationHelper.getElevationText(profile.getGain()));
-            }
-
-            // compute values for time and distance
-            long diff = profile.getTimeDifference();
-            long minutes = diff / (1000 * 60);
-            long hours = minutes / 60;
-            minutes = minutes % 60;
-
-            double dist = profile.getDistance();
-
-            totalTimeLabel.setText(String.format("%d:%02d h", hours, minutes));
-            distLabel.setText(NavigatableComponent.getSystemOfMeasurement().getDistText(dist));
-            trackCombo.setEnabled(model.profileCount() > 1);
-            trackCombo.setModel(new TrackModel());
-            zoomButton.setEnabled(true);
-        } else { // no elevation data, -> switch back to empty view
-            disableView();
-        }
-
-        fireModelChanged();
-        repaint();
-    }
-
-    private void disableView() {
-        setTitle(String.format("%s: (No data)", tr("Elevation Profile")));
-
-        minHeightLabel.setText(EMPTY_DATA_STRING);
-        maxHeightLabel.setText(EMPTY_DATA_STRING);
-        avrgHeightLabel.setText(EMPTY_DATA_STRING);
-        elevationGainLabel.setText(EMPTY_DATA_STRING);
-        totalTimeLabel.setText(EMPTY_DATA_STRING);
-        distLabel.setText(EMPTY_DATA_STRING);
-        trackCombo.setEnabled(false);
-        zoomButton.setEnabled(false);
-    }
-
-    /**
-     * Fires the 'model changed' event to all listeners.
-     */
-    protected void fireModelChanged() {
-        for (IElevationModelListener listener : listeners) {
-            listener.elevationProfileChanged(getModel().getCurrentProfile());
-        }
-    }
-
-    /**
-     * Adds a model listener to this instance.
-     * 
-     * @param listener
-     *            The listener to add.
-     */
-    public void addModelListener(IElevationModelListener listener) {
-        this.listeners.add(listener);
-    }
-
-    /**
-     * Removes a model listener from this instance.
-     * 
-     * @param listener
-     *            The listener to remove.
-     */
-    public void removeModelListener(IElevationModelListener listener) {
-        this.listeners.remove(listener);
-    }
-
-    /**
-     * Removes all listeners from this instance.
-     */
-    public void removeAllListeners() {
-        this.listeners.clear();
-    }
-
-    @Override
-    public void activeLayerChange(Layer oldLayer, Layer newLayer) {
-        if (newLayer instanceof GpxLayer) {
-            setActiveLayer((GpxLayer) newLayer);
-        }
-    }
-
-    private void setActiveLayer(GpxLayer newLayer) {
-        if (activeLayer != newLayer) {
-            activeLayer = newLayer;
-
-            // layer does not exist -> create
-            if (!layerMap.containsKey(newLayer)) {
-                GpxData gpxData = newLayer.data;
-                ElevationModel newEM = new ElevationModel(newLayer.getName(),
-                        gpxData);
-                layerMap.put(newLayer, newEM);
-            }
-
-            ElevationModel em = layerMap.get(newLayer);
-            setModel(em);
-        }
-    }
-
-    @Override
-    public void layerAdded(Layer newLayer) {
-        if (newLayer instanceof GpxLayer) {
-            GpxLayer gpxLayer = (GpxLayer) newLayer;
-            setActiveLayer(gpxLayer);
-        }
-    }
-
-    @Override
-    public void layerRemoved(Layer oldLayer) {
-        if (layerMap.containsKey(oldLayer)) {
-            layerMap.remove(oldLayer);
-        }
-
-        if (layerMap.size() == 0) {
-            setModel(null);
-            if (profileLayer != null) {
-                profileLayer.setProfile(null);
-            }
-        }
-    }
-
-    @Override
-    public void componentHidden(ComponentEvent e) {
-    }
-
-    @Override
-    public void componentMoved(ComponentEvent e) {
-    }
-
-    @Override
-    public void componentResized(ComponentEvent e) {
-    }
-
-    @Override
-    public void componentShown(ComponentEvent e) {
-    }
-
-    class TrackModel implements ComboBoxModel<IElevationProfile> {
-        private Collection<ListDataListener> listeners;
-
-        @Override
-        public void addListDataListener(ListDataListener arg0) {
-            if (listeners == null) {
-                listeners = new ArrayList<ListDataListener>();
-            }
-            listeners.add(arg0);
-        }
-
-        @Override
-        public IElevationProfile getElementAt(int index) {
-            if (model == null) return null;
-
-            IElevationProfile ep = model.getProfiles().get(index);
-            return ep;
-        }
-
-        @Override
-        public int getSize() {
-            if (model == null) return 0;
-
-            return model.profileCount();
-        }
-
-        @Override
-        public void removeListDataListener(ListDataListener listener) {
-            if (listeners == null) return;
-
-            listeners.remove(listener);
-        }
-
-        @Override
-        public IElevationProfile getSelectedItem() {
-            if (model == null) return null;
-
-            return model.getCurrentProfile();
-        }
-
-        @Override
-        public void setSelectedItem(Object selectedObject) {
-            if (model != null && selectedObject instanceof IElevationProfile) {
-                model.setCurrentProfile((IElevationProfile) selectedObject);
-                profileLayer.setProfile(model.getCurrentProfile());
-
-                repaint();
-            }
-        }
-    }
+	private static final String EMPTY_DATA_STRING = "-";
+	private static final long serialVersionUID = -868463893732535577L;
+	/* Elevation profile instance */
+	private IElevationModel model;
+	/* GPX data */
+	private GpxLayer activeLayer = null;
+	private final HashMap<GpxLayer, ElevationModel> layerMap = new HashMap<>();
+
+	/* UI elements */
+	private final ElevationProfilePanel profPanel;
+	private final JLabel minHeightLabel;
+	private final JLabel maxHeightLabel;
+	private final JLabel avrgHeightLabel;
+	private final JLabel elevationGainLabel;
+	private final JLabel totalTimeLabel;
+	private final JLabel distLabel;
+	private final JComboBox<IElevationProfile> trackCombo;
+	private final JButton zoomButton;
+
+	/* Listener to the elevation model */
+	private final List<IElevationModelListener> listeners = new ArrayList<>();
+
+	/**
+	 * Corresponding layer instance within map view.
+	 */
+	private ElevationProfileLayer profileLayer;
+
+	/**
+	 * Default constructor
+	 */
+	public ElevationProfileDialog() {
+		this(tr("Elevation Profile"), "elevation",
+				tr("Open the elevation profile window."), null, 200, true);
+	}
+
+	/**
+	 * Constructor (see below)
+	 */
+	public ElevationProfileDialog(String name, String iconName, String tooltip,
+			Shortcut shortcut, int preferredHeight) {
+		this(name, iconName, tooltip, shortcut, preferredHeight, false);
+	}
+
+	/**
+	 * Constructor
+	 *
+	 * @param name
+	 *            the name of the dialog
+	 * @param iconName
+	 *            the name of the icon to be displayed
+	 * @param tooltip
+	 *            the tool tip
+	 * @param shortcut
+	 *            the shortcut
+	 * @param preferredHeight
+	 *            the preferred height for the dialog
+	 * @param defShow
+	 *            if the dialog should be shown by default, if there is no
+	 *            preference
+	 */
+	public ElevationProfileDialog(String name, String iconName, String tooltip,
+			Shortcut shortcut, int preferredHeight, boolean defShow) {
+		super(name, iconName, tooltip, shortcut, preferredHeight, defShow);
+
+		// create model
+		model = new ElevationModel();
+
+		// top panel
+		JPanel rootPanel = new JPanel();
+		GridLayout gridLayout1 = new GridLayout(2, 1);
+		rootPanel.setLayout(gridLayout1);
+
+		// statistics panel
+		JPanel statPanel = new JPanel();
+		GridLayout gridLayoutStat = new GridLayout(2, 6);
+		statPanel.setLayout(gridLayoutStat);
+
+		// first row: Headlines with bold font
+		String[] labels = new String[]{tr("Min"), tr("Avrg"), tr("Max"), tr("Dist"), tr("Gain"), tr("Time")};
+		for (int i = 0; i < labels.length; i++) {
+			JLabel lbl = new JLabel(labels[i]);
+			lbl.setFont(getFont().deriveFont(Font.BOLD));
+			statPanel.add(lbl);
+		}
+
+		// second row
+		minHeightLabel = new JLabel("0 m");
+		statPanel.add(minHeightLabel);
+		avrgHeightLabel = new JLabel("0 m");
+		statPanel.add(avrgHeightLabel);
+		maxHeightLabel = new JLabel("0 m");
+		statPanel.add(maxHeightLabel);
+		distLabel = new JLabel("0 km");
+		statPanel.add(distLabel);
+		elevationGainLabel = new JLabel("0 m");
+		statPanel.add(elevationGainLabel);
+		totalTimeLabel = new JLabel("0");
+		statPanel.add(totalTimeLabel);
+
+		// track selection panel
+		JPanel trackPanel = new JPanel();
+		FlowLayout fl = new FlowLayout(FlowLayout.LEFT);
+		trackPanel.setLayout(fl);
+
+		JLabel lbTrack = new JLabel(tr("Tracks"));
+		lbTrack.setFont(getFont().deriveFont(Font.BOLD));
+		trackPanel.add(lbTrack);
+
+		zoomButton = new JButton(tr("Zoom"));
+		zoomButton.addActionListener(new ActionListener() {
+			@Override
+			public void actionPerformed(ActionEvent arg0) {
+				if (model != null) {
+					IElevationProfile profile = model.getCurrentProfile();
+					if (profile != null) {
+						Main.map.mapView.zoomTo(profile.getBounds());
+					}
+				}
+
+			}
+		});
+		zoomButton.setEnabled(false);
+
+		trackCombo = new JComboBox<>(new TrackModel());
+		trackCombo.setPreferredSize(new Dimension(200, 24)); // HACK!
+		trackCombo.setEnabled(false); // we have no model on startup
+
+		trackPanel.add(trackCombo);
+		trackPanel.add(zoomButton);
+
+		// assemble root panel
+		rootPanel.add(statPanel);
+		rootPanel.add(trackPanel);
+
+		JPanel mainPanel = new JPanel(new BorderLayout());
+		mainPanel.add(rootPanel, BorderLayout.PAGE_END);
+
+		// add chart component
+		profPanel = new ElevationProfilePanel(null);
+		mainPanel.add(profPanel, BorderLayout.CENTER);
+		profPanel.addComponentListener(this);
+
+		createLayout(mainPanel, true, null);
+	}
+
+	@Override
+	public void showNotify() {
+		MapView.addLayerChangeListener(this);
+		if (Main.isDisplayingMapView()) {
+			Layer layer = Main.map.mapView.getActiveLayer();
+			if (layer instanceof GpxLayer) {
+				setActiveLayer((GpxLayer) layer);
+			}
+		}
+	}
+
+	@Override
+	public void hideNotify() {
+		MapView.removeLayerChangeListener(this);
+	}
+
+	/**
+	 * Gets the elevation model instance.
+	 * @return
+	 */
+	public IElevationModel getModel() {
+		return model;
+	}
+
+	/**
+	 * Sets the elevation model instance.
+	 * @param model The new model.
+	 */
+	public void setModel(IElevationModel model) {
+		if (this.model != model) {
+			this.model = model;
+			profPanel.setElevationModel(model);
+			updateView();
+		}
+	}
+
+	/**
+	 * Gets the associated layer instance of the elevation profile.
+	 * @return
+	 */
+	public ElevationProfileLayer getProfileLayer() {
+		return profileLayer;
+	}
+
+	/**
+	 * Sets the associated layer instance of the elevation profile.
+	 * @param profileLayer The elevation profile layer.
+	 */
+	public void setProfileLayer(ElevationProfileLayer profileLayer) {
+		if (this.profileLayer != profileLayer) {
+			if (this.profileLayer != null) {
+				profPanel.removeSelectionListener(this.profileLayer);
+			}
+			this.profileLayer = profileLayer;
+			profPanel.addSelectionListener(this.profileLayer);
+		}
+	}
+
+	/**
+	 * Refreshes the dialog when model data have changed and notifies clients
+	 * that the model has changed.
+	 */
+	private void updateView() {
+		if (model == null) {
+			disableView();
+			return;
+		}
+
+		IElevationProfile profile = model.getCurrentProfile();
+		if (profile != null) {
+			// Show name of profile in title
+			setTitle(String.format("%s: %s", tr("Elevation Profile"), profile.getName()));
+
+			if (profile.hasElevationData()) {
+				// Show elevation data
+				minHeightLabel.setText(
+						ElevationHelper.getElevationText(profile.getMinHeight()));
+				maxHeightLabel.setText(
+						ElevationHelper.getElevationText(profile.getMaxHeight()));
+				avrgHeightLabel.setText(
+						ElevationHelper.getElevationText(profile.getAverageHeight()));
+				elevationGainLabel.setText(
+						ElevationHelper.getElevationText(profile.getGain()));
+			}
+
+			// compute values for time and distance
+			long diff = profile.getTimeDifference();
+			long minutes = diff / (1000 * 60);
+			long hours = minutes / 60;
+			minutes = minutes % 60;
+
+			double dist = profile.getDistance();
+
+			totalTimeLabel.setText(String.format("%d:%02d h", hours, minutes));
+			distLabel.setText(NavigatableComponent.getSystemOfMeasurement().getDistText(dist));
+			trackCombo.setEnabled(model.profileCount() > 1);
+			trackCombo.setModel(new TrackModel());
+			zoomButton.setEnabled(true);
+		} else { // no elevation data, -> switch back to empty view
+			disableView();
+		}
+
+		fireModelChanged();
+		repaint();
+	}
+
+	private void disableView() {
+		setTitle(String.format("%s: (No data)", tr("Elevation Profile")));
+
+		minHeightLabel.setText(EMPTY_DATA_STRING);
+		maxHeightLabel.setText(EMPTY_DATA_STRING);
+		avrgHeightLabel.setText(EMPTY_DATA_STRING);
+		elevationGainLabel.setText(EMPTY_DATA_STRING);
+		totalTimeLabel.setText(EMPTY_DATA_STRING);
+		distLabel.setText(EMPTY_DATA_STRING);
+		trackCombo.setEnabled(false);
+		zoomButton.setEnabled(false);
+	}
+
+	/**
+	 * Fires the 'model changed' event to all listeners.
+	 */
+	protected void fireModelChanged() {
+		for (IElevationModelListener listener : listeners) {
+			listener.elevationProfileChanged(getModel().getCurrentProfile());
+		}
+	}
+
+	/**
+	 * Adds a model listener to this instance.
+	 *
+	 * @param listener
+	 *            The listener to add.
+	 */
+	public void addModelListener(IElevationModelListener listener) {
+		this.listeners.add(listener);
+	}
+
+	/**
+	 * Removes a model listener from this instance.
+	 *
+	 * @param listener
+	 *            The listener to remove.
+	 */
+	public void removeModelListener(IElevationModelListener listener) {
+		this.listeners.remove(listener);
+	}
+
+	/**
+	 * Removes all listeners from this instance.
+	 */
+	public void removeAllListeners() {
+		this.listeners.clear();
+	}
+
+	@Override
+	public void activeLayerChange(Layer oldLayer, Layer newLayer) {
+		if (newLayer instanceof GpxLayer) {
+			setActiveLayer((GpxLayer) newLayer);
+		}
+	}
+
+	private void setActiveLayer(GpxLayer newLayer) {
+		if (activeLayer != newLayer) {
+			activeLayer = newLayer;
+
+			// layer does not exist -> create
+			if (!layerMap.containsKey(newLayer)) {
+				GpxData gpxData = newLayer.data;
+				ElevationModel newEM = new ElevationModel(newLayer.getName(),
+						gpxData);
+				layerMap.put(newLayer, newEM);
+			}
+
+			ElevationModel em = layerMap.get(newLayer);
+			setModel(em);
+		}
+	}
+
+	@Override
+	public void layerAdded(Layer newLayer) {
+		if (newLayer instanceof GpxLayer) {
+			GpxLayer gpxLayer = (GpxLayer) newLayer;
+			setActiveLayer(gpxLayer);
+		}
+	}
+
+	@Override
+	public void layerRemoved(Layer oldLayer) {
+		if (layerMap.containsKey(oldLayer)) {
+			layerMap.remove(oldLayer);
+		}
+
+		if (layerMap.size() == 0) {
+			setModel(null);
+			if (profileLayer != null) {
+				profileLayer.setProfile(null);
+			}
+		}
+	}
+
+	@Override
+	public void componentHidden(ComponentEvent e) {
+	}
+
+	@Override
+	public void componentMoved(ComponentEvent e) {
+	}
+
+	@Override
+	public void componentResized(ComponentEvent e) {
+	}
+
+	@Override
+	public void componentShown(ComponentEvent e) {
+	}
+
+	class TrackModel implements ComboBoxModel<IElevationProfile> {
+		private Collection<ListDataListener> listeners;
+
+		@Override
+		public void addListDataListener(ListDataListener arg0) {
+			if (listeners == null) {
+				listeners = new ArrayList<>();
+			}
+			listeners.add(arg0);
+		}
+
+		@Override
+		public IElevationProfile getElementAt(int index) {
+			if (model == null) return null;
+
+			IElevationProfile ep = model.getProfiles().get(index);
+			return ep;
+		}
+
+		@Override
+		public int getSize() {
+			if (model == null) return 0;
+
+			return model.profileCount();
+		}
+
+		@Override
+		public void removeListDataListener(ListDataListener listener) {
+			if (listeners == null) return;
+
+			listeners.remove(listener);
+		}
+
+		@Override
+		public IElevationProfile getSelectedItem() {
+			if (model == null) return null;
+
+			return model.getCurrentProfile();
+		}
+
+		@Override
+		public void setSelectedItem(Object selectedObject) {
+			if (model != null && selectedObject instanceof IElevationProfile) {
+				model.setCurrentProfile((IElevationProfile) selectedObject);
+				profileLayer.setProfile(model.getCurrentProfile());
+
+				repaint();
+			}
+		}
+	}
 }
Index: applications/editors/josm/plugins/ElevationProfile/src/org/openstreetmap/josm/plugins/elevation/gui/ElevationProfilePanel.java
===================================================================
--- applications/editors/josm/plugins/ElevationProfile/src/org/openstreetmap/josm/plugins/elevation/gui/ElevationProfilePanel.java	(revision 30736)
+++ applications/editors/josm/plugins/ElevationProfile/src/org/openstreetmap/josm/plugins/elevation/gui/ElevationProfilePanel.java	(revision 30737)
@@ -36,220 +36,220 @@
  */
 public class ElevationProfilePanel extends JPanel implements ComponentListener, MouseMotionListener {
-    /**
-     * Serial version UID
-     */
-    private static final long serialVersionUID = -7343429725259575319L;
-    private static final int BOTTOM_TEXT_Y_OFFSET = 7;
-
-    private IElevationModel model;
-    private Rectangle plotArea;
-    private final IElevationProfileRenderer renderer = new DefaultElevationProfileRenderer();
-    private int selectedIndex = -1;
-    private final List<IElevationProfileSelectionListener> selectionChangedListeners = new ArrayList<IElevationProfileSelectionListener>();
-    private boolean isPainting;
-    private int step = 0;
-
-    /**
-     * Constructs a new ElevationProfilePanel with the given elevation profile.
-     * @param profile The elevation profile to show in the panel.
-     */
-    public ElevationProfilePanel(IElevationModel profile) {
-        super();
-        this.model = profile;
-        setDoubleBuffered(true);
-        setBackground(Color.WHITE);
-        createOrUpdatePlotArea();
-        addComponentListener(this);
-        addMouseMotionListener(this);
-
-        Font lFont = getFont().deriveFont(9.0f);
-        setFont(lFont);
-    }
-
-    /**
-     * Gets the elevation profile instance.
-     * @return
-     */
-    public IElevationModel getProfile() {
-        return model;
-    }
-
-    /**
-     * Sets the new elevation profile instance.
-     * @param model
-     */
-    public void setElevationModel(IElevationModel model) {
-        if (this.model != model) {
-            this.model = model;
-            invalidate();
-        }
-    }
-
-    /**
-     * Gets the plot area coordinates.
-     * @return
-     */
-    public Rectangle getPlotArea() {
-        return plotArea;
-    }
-
-    /**
-     * Sets the plot area coordinates.
-     * @param plotArea
-     */
-    public void setPlotArea(Rectangle plotArea) {
-        this.plotArea = plotArea;
-    }
-
-    /**
-     * Gets the selected index of the bar.
-     * @return
-     */
-    public int getSelectedIndex() {
-        return selectedIndex;
-    }
-
-    /**
-     * Sets the selected index of the bar.
-     * @param selectedIndex
-     */
-    public void setSelectedIndex(int selectedIndex) {
-        this.selectedIndex = selectedIndex;
-
-        if (model != null) {
-            model.setCurrentProfile(selectedIndex);
-        }
-    }
-
-    /**
-     * Gets the selected (highlighted) way point.
-     * @return The selected way point or null, if no way point is selected.
-     */
-    public WayPoint getSelectedWayPoint() {
-        if (model == null) return null;
-
-        IElevationProfile profile = model.getCurrentProfile();
-
-        int selWp = this.selectedIndex * step;
-        if (profile != null && profile.getWayPoints() != null && selWp > 0 && profile.getWayPoints().size() > selWp) {
-            return profile.getWayPoints().get(selWp);
-        } else {
-            return null;
-        }
-    }
-
-    /**
-     * Adds a selection listener.
-     * @param listener The listener instance to add.
-     */
-    public void addSelectionListener(IElevationProfileSelectionListener listener) {
-        if (listener == null) return;
-
-        selectionChangedListeners.add(listener);
-    }
-
-    /**
-     * Removes a selection listener from the list.
-     * @param listener The listener instance to remove.
-     */
-    public void removeSelectionListener(IElevationProfileSelectionListener listener) {
-        if (listener == null) return;
-
-        selectionChangedListeners.remove(listener);
-    }
-
-    /**
-     * Removes all selection listeners.
-     */
-    public void removeAllSelectionListeners() {
-        selectionChangedListeners.clear();
-    }
-
-    protected void fireSelectionChanged(WayPoint selWayPoint) {
-        for (IElevationProfileSelectionListener listener : selectionChangedListeners) {
-            listener.selectedWayPointChanged(selWayPoint);
-        }
-    }
-
-    @Override
-    public void paint(Graphics g) {
-        isPainting = true;
-
-        try {
-            super.paint(g);
-            createOrUpdatePlotArea();
-            int y1 = getPlotBottom();
-
-            g.setColor(Color.DARK_GRAY);
-            g.drawLine(plotArea.x, plotArea.y, plotArea.x, plotArea.y
-                    + plotArea.height);
-            g.drawLine(plotArea.x, plotArea.y + plotArea.height, plotArea.x
-                    + plotArea.width, plotArea.y + plotArea.height);
-
-
-            if (model != null) {
-                IElevationProfile profile = model.getCurrentProfile();
-                if (profile != null && profile.hasElevationData()) {
-                    // Draw start and end date
-                    drawAlignedString(formatDate(profile.getStart()), 5, y1 + BOTTOM_TEXT_Y_OFFSET,
-                            TextAlignment.Left, g);
-                    drawAlignedString(formatDate(profile.getEnd()),
-                            getPlotRight(), y1 + BOTTOM_TEXT_Y_OFFSET, TextAlignment.Right, g);
-
-                    // Show SRTM indicator
-                    if (ElevationHelper.hasSrtmData(profile.getBounds())) {
-                        String txt = "SRTM";
-                        drawAlignedString(txt, getPlotHCenter(), y1 + BOTTOM_TEXT_Y_OFFSET, TextAlignment.Centered, g);
-                    }
-                    drawProfile(g);
-                    drawElevationLines(g);
-                } else {
-                    // No profile or profile supports no elevation data
-                    drawAlignedString(tr("(No elevation data)"), getPlotHCenter(),
-                            getPlotVCenter(), TextAlignment.Centered, g);
-                }
-            }
-        } finally {
-            isPainting = false;
-        }
-    }
-
-    /**
-     * Draw a string with a specified alignment.
-     * @param s The text to display.
-     * @param x The x coordinate.
-     * @param y The y coordinate.
-     * @param align The text alignment.
-     * @param g The graphics context.
-     * @return The resulting rectangle of the drawn string.
-     */
-    private Rectangle drawAlignedString(String s, int x, int y,
-            TextAlignment align, Graphics g) {
-        FontMetrics fm = g.getFontMetrics();
-        int w = fm.stringWidth(s);
-        int h = fm.getHeight();
-
-        int xoff = w / 2;
-        int yoff = h / 2;
-
-        if (align == TextAlignment.Left) {
-            xoff = 0;
-        }
-        if (align == TextAlignment.Right) {
-            xoff = w;
-        }
-
-        g.drawString(s, x - xoff, y + yoff);
-
-        return new Rectangle(x - xoff, y - yoff, w, h);
-    }
-
-    /**
-     * Draw a string which is horizontally centered around (x,y).
-     * @param s The text to display.
-     * @param x The x coordinate.
-     * @param y The y coordinate.
-     * @param g The graphics context.
-     * @return The resulting rectangle of the drawn string.
+	/**
+	 * Serial version UID
+	 */
+	private static final long serialVersionUID = -7343429725259575319L;
+	private static final int BOTTOM_TEXT_Y_OFFSET = 7;
+
+	private IElevationModel model;
+	private Rectangle plotArea;
+	private final IElevationProfileRenderer renderer = new DefaultElevationProfileRenderer();
+	private int selectedIndex = -1;
+	private final List<IElevationProfileSelectionListener> selectionChangedListeners = new ArrayList<>();
+	private boolean isPainting;
+	private int step = 0;
+
+	/**
+	 * Constructs a new ElevationProfilePanel with the given elevation profile.
+	 * @param profile The elevation profile to show in the panel.
+	 */
+	public ElevationProfilePanel(IElevationModel profile) {
+		super();
+		this.model = profile;
+		setDoubleBuffered(true);
+		setBackground(Color.WHITE);
+		createOrUpdatePlotArea();
+		addComponentListener(this);
+		addMouseMotionListener(this);
+
+		Font lFont = getFont().deriveFont(9.0f);
+		setFont(lFont);
+	}
+
+	/**
+	 * Gets the elevation profile instance.
+	 * @return
+	 */
+	public IElevationModel getProfile() {
+		return model;
+	}
+
+	/**
+	 * Sets the new elevation profile instance.
+	 * @param model
+	 */
+	public void setElevationModel(IElevationModel model) {
+		if (this.model != model) {
+			this.model = model;
+			invalidate();
+		}
+	}
+
+	/**
+	 * Gets the plot area coordinates.
+	 * @return
+	 */
+	public Rectangle getPlotArea() {
+		return plotArea;
+	}
+
+	/**
+	 * Sets the plot area coordinates.
+	 * @param plotArea
+	 */
+	public void setPlotArea(Rectangle plotArea) {
+		this.plotArea = plotArea;
+	}
+
+	/**
+	 * Gets the selected index of the bar.
+	 * @return
+	 */
+	public int getSelectedIndex() {
+		return selectedIndex;
+	}
+
+	/**
+	 * Sets the selected index of the bar.
+	 * @param selectedIndex
+	 */
+	public void setSelectedIndex(int selectedIndex) {
+		this.selectedIndex = selectedIndex;
+
+		if (model != null) {
+			model.setCurrentProfile(selectedIndex);
+		}
+	}
+
+	/**
+	 * Gets the selected (highlighted) way point.
+	 * @return The selected way point or null, if no way point is selected.
+	 */
+	public WayPoint getSelectedWayPoint() {
+		if (model == null) return null;
+
+		IElevationProfile profile = model.getCurrentProfile();
+
+		int selWp = this.selectedIndex * step;
+		if (profile != null && profile.getWayPoints() != null && selWp > 0 && profile.getWayPoints().size() > selWp) {
+			return profile.getWayPoints().get(selWp);
+		} else {
+			return null;
+		}
+	}
+
+	/**
+	 * Adds a selection listener.
+	 * @param listener The listener instance to add.
+	 */
+	public void addSelectionListener(IElevationProfileSelectionListener listener) {
+		if (listener == null) return;
+
+		selectionChangedListeners.add(listener);
+	}
+
+	/**
+	 * Removes a selection listener from the list.
+	 * @param listener The listener instance to remove.
+	 */
+	public void removeSelectionListener(IElevationProfileSelectionListener listener) {
+		if (listener == null) return;
+
+		selectionChangedListeners.remove(listener);
+	}
+
+	/**
+	 * Removes all selection listeners.
+	 */
+	public void removeAllSelectionListeners() {
+		selectionChangedListeners.clear();
+	}
+
+	protected void fireSelectionChanged(WayPoint selWayPoint) {
+		for (IElevationProfileSelectionListener listener : selectionChangedListeners) {
+			listener.selectedWayPointChanged(selWayPoint);
+		}
+	}
+
+	@Override
+	public void paint(Graphics g) {
+		isPainting = true;
+
+		try {
+			super.paint(g);
+			createOrUpdatePlotArea();
+			int y1 = getPlotBottom();
+
+			g.setColor(Color.DARK_GRAY);
+			g.drawLine(plotArea.x, plotArea.y, plotArea.x, plotArea.y
+					+ plotArea.height);
+			g.drawLine(plotArea.x, plotArea.y + plotArea.height, plotArea.x
+					+ plotArea.width, plotArea.y + plotArea.height);
+
+
+			if (model != null) {
+				IElevationProfile profile = model.getCurrentProfile();
+				if (profile != null && profile.hasElevationData()) {
+					// Draw start and end date
+					drawAlignedString(formatDate(profile.getStart()), 5, y1 + BOTTOM_TEXT_Y_OFFSET,
+							TextAlignment.Left, g);
+					drawAlignedString(formatDate(profile.getEnd()),
+							getPlotRight(), y1 + BOTTOM_TEXT_Y_OFFSET, TextAlignment.Right, g);
+
+					// Show SRTM indicator
+					if (ElevationHelper.hasSrtmData(profile.getBounds())) {
+						String txt = "SRTM";
+						drawAlignedString(txt, getPlotHCenter(), y1 + BOTTOM_TEXT_Y_OFFSET, TextAlignment.Centered, g);
+					}
+					drawProfile(g);
+					drawElevationLines(g);
+				} else {
+					// No profile or profile supports no elevation data
+					drawAlignedString(tr("(No elevation data)"), getPlotHCenter(),
+							getPlotVCenter(), TextAlignment.Centered, g);
+				}
+			}
+		} finally {
+			isPainting = false;
+		}
+	}
+
+	/**
+	 * Draw a string with a specified alignment.
+	 * @param s The text to display.
+	 * @param x The x coordinate.
+	 * @param y The y coordinate.
+	 * @param align The text alignment.
+	 * @param g The graphics context.
+	 * @return The resulting rectangle of the drawn string.
+	 */
+	private Rectangle drawAlignedString(String s, int x, int y,
+			TextAlignment align, Graphics g) {
+		FontMetrics fm = g.getFontMetrics();
+		int w = fm.stringWidth(s);
+		int h = fm.getHeight();
+
+		int xoff = w / 2;
+		int yoff = h / 2;
+
+		if (align == TextAlignment.Left) {
+			xoff = 0;
+		}
+		if (align == TextAlignment.Right) {
+			xoff = w;
+		}
+
+		g.drawString(s, x - xoff, y + yoff);
+
+		return new Rectangle(x - xoff, y - yoff, w, h);
+	}
+
+	/**
+	 * Draw a string which is horizontally centered around (x,y).
+	 * @param s The text to display.
+	 * @param x The x coordinate.
+	 * @param y The y coordinate.
+	 * @param g The graphics context.
+	 * @return The resulting rectangle of the drawn string.
 
     private void drawHCenteredString(String s, int x, int y, Graphics g) {
@@ -257,262 +257,262 @@
     }*/
 
-    /**
-     * Formats the date in a predefined manner: "21. Oct 2010, 12:10".
-     * @param date
-     * @return
-     */
-    private String formatDate(Date date) {
-        Format formatter = new SimpleDateFormat("d MMM yy, HH:mm");
-
-        return formatter.format(date);
-    }
-
-    /**
-     * Helper function to draw elevation axes.
-     * @param g
-     */
-    private void drawElevationLines(Graphics g) {
-        IElevationProfile profile = model.getCurrentProfile();
-
-        double diff = profile.getHeightDifference();
-
-        if (diff == 0.0) {
-            return;
-        }
-
-        double z10 = Math.floor(Math.log10(diff));
-        double scaleUnit = Math.pow(10, z10); // scale unit, e. g. 100 for
-        // values below 1000
-
-        int upperLimit = (int) (Math.round(Math.ceil(profile.getMaxHeight()
-                / scaleUnit)) * scaleUnit);
-        int lowerLimit = (int) (Math.round(Math.floor(profile.getMinHeight()
-                / scaleUnit)) * scaleUnit);
-        int su = (int) scaleUnit;
-
-        for (int i = lowerLimit; i <= upperLimit; i += su) {
-            int yLine = getYForEelevation(i);
-
-            // check bounds
-            if (yLine <= getPlotBottom() && yLine >= getPlotTop()) {
-                String txt = ElevationHelper.getElevationText(i);
-
-                Rectangle r = drawAlignedString(txt, getPlotHCenter(), yLine - 2,
-                        TextAlignment.Right, g);
-                r.grow(2, 2);
-
-                // Draw left and right line segment
-                g.drawLine(getPlotLeftAxis(), yLine, r.x,
-                        yLine);
-                g.drawLine(r.x + r.width, yLine, getPlotRight(),
-                        yLine);
-                // Draw label with shadow
-                g.setColor(Color.WHITE);
-                drawAlignedString(txt, getPlotHCenter() + 1, yLine - 1,
-                        TextAlignment.Right, g);
-                g.setColor(Color.BLACK);
-                drawAlignedString(txt, getPlotHCenter(), yLine - 2,
-                        TextAlignment.Right, g);
-            }
-        }
-    }
-
-    /**
-     * Gets the x value of the left border for axes (slightly smaller than the
-     * left x).
-     * 
-     * @return
-     */
-    private int getPlotLeftAxis() {
-        return plotArea.x - 3;
-    }
-
-    /**
-     * Gets the x value of the left border.
-     * 
-     * @return
-     */
-    private int getPlotLeft() {
-        return plotArea.x + 1;
-    }
-
-    /**
-     * Gets the horizontal center coordinate (mid between left and right x).
-     * 
-     * @return
-     */
-    private int getPlotHCenter() {
-        return (getPlotLeft() + getPlotRight()) / 2;
-    }
-
-    /**
-     * Gets the vertical center coordinate (mid between top and bottom y).
-     * 
-     * @return
-     */
-    private int getPlotVCenter() {
-        return (getPlotTop() + getPlotBottom()) / 2;
-    }
-
-    /**
-     * Gets the x value of the right border.
-     * 
-     * @return
-     */
-    private int getPlotRight() {
-        return plotArea.x + plotArea.width - 1;
-    }
-
-    private int getPlotBottom() {
-        return plotArea.y + plotArea.height - 1;
-    }
-
-    private int getPlotTop() {
-        return plotArea.y + 1;
-    }
-
-    /**
-     * Gets for an elevation value the according y coordinate in the plot area.
-     * 
-     * @param elevation
-     * @return The y coordinate in the plot area.
-     */
-    private int getYForEelevation(int elevation) {
-        int y1 = getPlotBottom();
-
-        IElevationProfile profile = model.getCurrentProfile();
-
-        if (!profile.hasElevationData()) {
-            return y1;
-        }
-
-        double diff = profile.getHeightDifference();
-
-        return y1 - (int) Math.round(((elevation - profile.getMinHeight()) / diff * plotArea.height));
-    }
-
-    /**
-     * Draws the elevation profile
-     * 
-     * @param g
-     */
-    private void drawProfile(Graphics g) {
-        IElevationProfile profile = model.getCurrentProfile();
-
-        int nwp = profile.getNumberOfWayPoints();
-        int n = Math.min(plotArea.width, nwp);
-
-        if (n == 0) return; // nothing to draw
-        // compute step size in panel (add 1 to make sure that
-        // the complete range fits into panel
-        step = (nwp / n) + 1;
-
-        int yBottom = getPlotBottom();
-        Color oldC = g.getColor();
-
-        for (int i = 0, ip = 0; i < n && ip < nwp; i++, ip += step) {
-            WayPoint wpt = profile.getWayPoints().get(ip);
-            int eleVal = (int) ElevationHelper.getElevation(wpt);
-            Color c = renderer.getColorForWaypoint(profile, wpt,
-                    ElevationWayPointKind.Plain);
-
-            // draw cursor
-            if (i == this.selectedIndex) {
-                g.setColor(Color.BLACK);
-                drawAlignedString(ElevationHelper.getElevationText(eleVal),
-                        (getPlotRight() + getPlotLeft()) / 2,
-                        getPlotBottom() + 6,
-                        TextAlignment.Centered,
-                        g);
-
-                c = renderer.getColorForWaypoint(profile, wpt, ElevationWayPointKind.Highlighted);
-            }
-
-            int yEle = getYForEelevation(eleVal);
-            int x = getPlotLeft() + i;
-
-            g.setColor(c);
-            g.drawLine(x, yBottom, x, yEle);
-            g.setColor(ElevationColors.EPLightBlue);
-        }
-
-        g.setColor(oldC);
-    }
-
-    @Override
-    protected void paintBorder(Graphics g) {
-        super.paintBorder(g);
-
-        Border loweredbevel = BorderFactory.createLoweredBevelBorder();
-        this.setBorder(loweredbevel);
-    }
-
-    /**
-     * Determines the size of the plot area depending on the panel size.
-     */
-    private void createOrUpdatePlotArea() {
-        Dimension caSize = getSize();
-
-        if (plotArea == null) {
-            plotArea = new Rectangle(0, 0, caSize.width, caSize.height);
-        } else {
-            plotArea.width = caSize.width;
-            plotArea.height = caSize.height;
-        }
-
-        plotArea.setLocation(0, 0);
-        plotArea.grow(-10, -15);
-    }
-
-    @Override
-    public void componentHidden(ComponentEvent arg0) {
-        // TODO Auto-generated method stub
-    }
-
-    @Override
-    public void componentMoved(ComponentEvent arg0) {
-        // TODO Auto-generated method stub
-    }
-
-    @Override
-    public void componentResized(ComponentEvent arg0) {
-        createOrUpdatePlotArea();
-    }
-
-    @Override
-    public void componentShown(ComponentEvent arg0) {
-        // TODO Auto-generated method stub
-    }
-
-    @Override
-    public void mouseDragged(MouseEvent arg0) {
-        // TODO Auto-generated method stub
-
-    }
-
-    @Override
-    public void mouseMoved(MouseEvent arg0) {
-        if (isPainting || arg0.isControlDown() || arg0.isAltDown() || arg0.isShiftDown()) arg0.consume();
-
-        int x = arg0.getX();
-        int l = this.getX();
-        int pl = this.getPlotLeft();
-        int newIdx = x - l - pl;
-
-        if (newIdx != this.selectedIndex && newIdx >= 0) {
-            this.selectedIndex = newIdx;
-            this.repaint();
-            fireSelectionChanged(getSelectedWayPoint());
-        }
-    }
-
-    @Override
-    public String getToolTipText() {
-        WayPoint wpt = getSelectedWayPoint();
-        if (wpt != null) {
-            return  String.format("%s: %s", ElevationHelper.getTimeText(wpt), ElevationHelper.getElevationText(wpt));
-        }
-
-        return super.getToolTipText();
-    }
+	/**
+	 * Formats the date in a predefined manner: "21. Oct 2010, 12:10".
+	 * @param date
+	 * @return
+	 */
+	private String formatDate(Date date) {
+		Format formatter = new SimpleDateFormat("d MMM yy, HH:mm");
+
+		return formatter.format(date);
+	}
+
+	/**
+	 * Helper function to draw elevation axes.
+	 * @param g
+	 */
+	private void drawElevationLines(Graphics g) {
+		IElevationProfile profile = model.getCurrentProfile();
+
+		double diff = profile.getHeightDifference();
+
+		if (diff == 0.0) {
+			return;
+		}
+
+		double z10 = Math.floor(Math.log10(diff));
+		double scaleUnit = Math.pow(10, z10); // scale unit, e. g. 100 for
+		// values below 1000
+
+		int upperLimit = (int) (Math.round(Math.ceil(profile.getMaxHeight()
+				/ scaleUnit)) * scaleUnit);
+		int lowerLimit = (int) (Math.round(Math.floor(profile.getMinHeight()
+				/ scaleUnit)) * scaleUnit);
+		int su = (int) scaleUnit;
+
+		for (int i = lowerLimit; i <= upperLimit; i += su) {
+			int yLine = getYForEelevation(i);
+
+			// check bounds
+			if (yLine <= getPlotBottom() && yLine >= getPlotTop()) {
+				String txt = ElevationHelper.getElevationText(i);
+
+				Rectangle r = drawAlignedString(txt, getPlotHCenter(), yLine - 2,
+						TextAlignment.Right, g);
+				r.grow(2, 2);
+
+				// Draw left and right line segment
+				g.drawLine(getPlotLeftAxis(), yLine, r.x,
+						yLine);
+				g.drawLine(r.x + r.width, yLine, getPlotRight(),
+						yLine);
+				// Draw label with shadow
+				g.setColor(Color.WHITE);
+				drawAlignedString(txt, getPlotHCenter() + 1, yLine - 1,
+						TextAlignment.Right, g);
+				g.setColor(Color.BLACK);
+				drawAlignedString(txt, getPlotHCenter(), yLine - 2,
+						TextAlignment.Right, g);
+			}
+		}
+	}
+
+	/**
+	 * Gets the x value of the left border for axes (slightly smaller than the
+	 * left x).
+	 *
+	 * @return
+	 */
+	private int getPlotLeftAxis() {
+		return plotArea.x - 3;
+	}
+
+	/**
+	 * Gets the x value of the left border.
+	 *
+	 * @return
+	 */
+	private int getPlotLeft() {
+		return plotArea.x + 1;
+	}
+
+	/**
+	 * Gets the horizontal center coordinate (mid between left and right x).
+	 *
+	 * @return
+	 */
+	private int getPlotHCenter() {
+		return (getPlotLeft() + getPlotRight()) / 2;
+	}
+
+	/**
+	 * Gets the vertical center coordinate (mid between top and bottom y).
+	 *
+	 * @return
+	 */
+	private int getPlotVCenter() {
+		return (getPlotTop() + getPlotBottom()) / 2;
+	}
+
+	/**
+	 * Gets the x value of the right border.
+	 *
+	 * @return
+	 */
+	private int getPlotRight() {
+		return plotArea.x + plotArea.width - 1;
+	}
+
+	private int getPlotBottom() {
+		return plotArea.y + plotArea.height - 1;
+	}
+
+	private int getPlotTop() {
+		return plotArea.y + 1;
+	}
+
+	/**
+	 * Gets for an elevation value the according y coordinate in the plot area.
+	 *
+	 * @param elevation
+	 * @return The y coordinate in the plot area.
+	 */
+	private int getYForEelevation(int elevation) {
+		int y1 = getPlotBottom();
+
+		IElevationProfile profile = model.getCurrentProfile();
+
+		if (!profile.hasElevationData()) {
+			return y1;
+		}
+
+		double diff = profile.getHeightDifference();
+
+		return y1 - (int) Math.round(((elevation - profile.getMinHeight()) / diff * plotArea.height));
+	}
+
+	/**
+	 * Draws the elevation profile
+	 *
+	 * @param g
+	 */
+	private void drawProfile(Graphics g) {
+		IElevationProfile profile = model.getCurrentProfile();
+
+		int nwp = profile.getNumberOfWayPoints();
+		int n = Math.min(plotArea.width, nwp);
+
+		if (n == 0) return; // nothing to draw
+		// compute step size in panel (add 1 to make sure that
+		// the complete range fits into panel
+		step = (nwp / n) + 1;
+
+		int yBottom = getPlotBottom();
+		Color oldC = g.getColor();
+
+		for (int i = 0, ip = 0; i < n && ip < nwp; i++, ip += step) {
+			WayPoint wpt = profile.getWayPoints().get(ip);
+			int eleVal = (int) ElevationHelper.getElevation(wpt);
+			Color c = renderer.getColorForWaypoint(profile, wpt,
+					ElevationWayPointKind.Plain);
+
+			// draw cursor
+			if (i == this.selectedIndex) {
+				g.setColor(Color.BLACK);
+				drawAlignedString(ElevationHelper.getElevationText(eleVal),
+						(getPlotRight() + getPlotLeft()) / 2,
+						getPlotBottom() + 6,
+						TextAlignment.Centered,
+						g);
+
+				c = renderer.getColorForWaypoint(profile, wpt, ElevationWayPointKind.Highlighted);
+			}
+
+			int yEle = getYForEelevation(eleVal);
+			int x = getPlotLeft() + i;
+
+			g.setColor(c);
+			g.drawLine(x, yBottom, x, yEle);
+			g.setColor(ElevationColors.EPLightBlue);
+		}
+
+		g.setColor(oldC);
+	}
+
+	@Override
+	protected void paintBorder(Graphics g) {
+		super.paintBorder(g);
+
+		Border loweredbevel = BorderFactory.createLoweredBevelBorder();
+		this.setBorder(loweredbevel);
+	}
+
+	/**
+	 * Determines the size of the plot area depending on the panel size.
+	 */
+	private void createOrUpdatePlotArea() {
+		Dimension caSize = getSize();
+
+		if (plotArea == null) {
+			plotArea = new Rectangle(0, 0, caSize.width, caSize.height);
+		} else {
+			plotArea.width = caSize.width;
+			plotArea.height = caSize.height;
+		}
+
+		plotArea.setLocation(0, 0);
+		plotArea.grow(-10, -15);
+	}
+
+	@Override
+	public void componentHidden(ComponentEvent arg0) {
+		// TODO Auto-generated method stub
+	}
+
+	@Override
+	public void componentMoved(ComponentEvent arg0) {
+		// TODO Auto-generated method stub
+	}
+
+	@Override
+	public void componentResized(ComponentEvent arg0) {
+		createOrUpdatePlotArea();
+	}
+
+	@Override
+	public void componentShown(ComponentEvent arg0) {
+		// TODO Auto-generated method stub
+	}
+
+	@Override
+	public void mouseDragged(MouseEvent arg0) {
+		// TODO Auto-generated method stub
+
+	}
+
+	@Override
+	public void mouseMoved(MouseEvent arg0) {
+		if (isPainting || arg0.isControlDown() || arg0.isAltDown() || arg0.isShiftDown()) arg0.consume();
+
+		int x = arg0.getX();
+		int l = this.getX();
+		int pl = this.getPlotLeft();
+		int newIdx = x - l - pl;
+
+		if (newIdx != this.selectedIndex && newIdx >= 0) {
+			this.selectedIndex = newIdx;
+			this.repaint();
+			fireSelectionChanged(getSelectedWayPoint());
+		}
+	}
+
+	@Override
+	public String getToolTipText() {
+		WayPoint wpt = getSelectedWayPoint();
+		if (wpt != null) {
+			return  String.format("%s: %s", ElevationHelper.getTimeText(wpt), ElevationHelper.getElevationText(wpt));
+		}
+
+		return super.getToolTipText();
+	}
 }
