[josm-plugins] 174/369: Imported Upstream version 0.0.svn23479

Bas Couwenberg sebastic at xs4all.nl
Sat Oct 18 12:03:39 UTC 2014


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

sebastic-guest pushed a commit to branch master
in repository josm-plugins.

commit ee699c40843ca5d03141758497861f3c9a4e8186
Author: David Paleino <dapal at debian.org>
Date:   Sun Oct 10 22:00:16 2010 +0200

    Imported Upstream version 0.0.svn23479
---
 .../josm/plugins/DirectUpload/UploadDataGui.java   |  104 +-
 .../plugins/DirectUpload/UploadDataGuiPlugin.java  |   14 +-
 cadastre-fr/src/cadastre_fr/CacheControl.java      |   10 +-
 cadastre-fr/src/cadastre_fr/CadastreGrabber.java   |   10 +-
 cadastre-fr/src/cadastre_fr/CadastreInterface.java |   20 +-
 cadastre-fr/src/cadastre_fr/CadastrePlugin.java    |   28 +-
 .../src/cadastre_fr/CadastrePreferenceSetting.java |   34 +-
 .../src/cadastre_fr/CheckSourceUploadHook.java     |    2 +-
 .../src/cadastre_fr/DownloadSVGBuilding.java       |    2 +-
 cadastre-fr/src/cadastre_fr/DownloadSVGTask.java   |    2 +-
 .../src/cadastre_fr/DownloadWMSVectorImage.java    |    4 +-
 cadastre-fr/src/cadastre_fr/EastNorthBound.java    |    2 +-
 cadastre-fr/src/cadastre_fr/GeorefImage.java       |   20 +-
 cadastre-fr/src/cadastre_fr/ImageModifier.java     |   24 +-
 .../src/cadastre_fr/MenuActionGrabPlanImage.java   |  116 +-
 .../src/cadastre_fr/MenuActionLoadFromCache.java   |    2 +-
 .../src/cadastre_fr/MenuActionNewLocation.java     |   26 +-
 cadastre-fr/src/cadastre_fr/WMSLayer.java          |    4 +-
 .../josm/plugin/colorscheme/ColorSchemePlugin.java |    2 +-
 .../josm/plugins/editgpx/EditGpxLayer.java         |  260 ++--
 .../josm/plugins/editgpx/EditGpxMode.java          |  296 ++--
 .../josm/plugins/editgpx/EditGpxPlugin.java        |   56 +-
 .../josm/plugins/editgpx/GPXLayerImportAction.java |  170 +--
 .../josm/plugins/editgpx/data/EditGpxData.java     |   96 +-
 .../josm/plugins/editgpx/data/EditGpxTrack.java    |   82 +-
 .../plugins/editgpx/data/EditGpxTrackSegment.java  |   64 +-
 .../josm/plugins/editgpx/data/EditGpxWayPoint.java |   58 +-
 .../josm/plugins/lakewalker/BooleanConfigurer.java |  110 +-
 .../josm/plugins/lakewalker/Configurer.java        |    4 +-
 .../josm/plugins/lakewalker/DoubleConfigurer.java  |    6 +-
 .../josm/plugins/lakewalker/IntConfigurer.java     |   88 +-
 .../josm/plugins/lakewalker/Lakewalker.java        |  186 +--
 .../josm/plugins/lakewalker/LakewalkerAction.java  |    8 +-
 .../plugins/lakewalker/LakewalkerException.java    |    2 +-
 .../josm/plugins/lakewalker/LakewalkerPlugin.java  |   18 +-
 .../josm/plugins/lakewalker/LakewalkerWMS.java     |  220 +--
 .../josm/plugins/lakewalker/StringConfigurer.java  |    2 +-
 .../plugins/lakewalker/StringEnumConfigurer.java   |    8 +-
 livegps/src/livegps/AppendableGpxTrackSegment.java |   90 +-
 livegps/src/livegps/ILiveGpsSuppressor.java        |   20 +-
 livegps/src/livegps/LiveGpsAcquirer.java           |  618 ++++----
 livegps/src/livegps/LiveGpsLayer.java              |  316 ++---
 livegps/src/livegps/LiveGpsPlugin.java             |  468 +++---
 livegps/src/livegps/LiveGpsSuppressor.java         |  230 +--
 livegps/src/livegps/SingleSegmentGpxTrack.java     |   44 +-
 livegps/src/org/json/JSONArray.java                |   28 +-
 livegps/src/org/json/JSONException.java            |    8 +-
 livegps/src/org/json/JSONObject.java               |  102 +-
 livegps/src/org/json/JSONString.java               |   14 +-
 livegps/src/org/json/JSONTokener.java              |   74 +-
 measurement/.classpath                             |    1 +
 measurement/josm-measurement.launch                |   12 +
 .../plugins/measurement/MeasurementPlugin.java     |    6 +-
 .../josm/plugin/openvisible/OpenVisibleAction.java |    4 +-
 .../josm/plugins/remotecontrol/PermissionPref.java |   22 +-
 .../remotecontrol/PermissionPrefWithDefault.java   |   20 +-
 .../plugins/remotecontrol/RemoteControlPlugin.java |   62 +-
 .../josm/plugins/remotecontrol/RequestHandler.java |  184 +--
 .../RequestHandlerForbiddenException.java          |    2 +-
 .../plugins/remotecontrol/RequestProcessor.java    |  528 +++----
 .../remotecontrol/handler/AddNodeHandler.java      |   46 +-
 .../remotecontrol/handler/ImportHandler.java       |   48 +-
 .../remotecontrol/handler/LoadAndZoomHandler.java  |  254 ++--
 .../remotecontrol/handler/VersionHandler.java      |   44 +-
 .../com/innovant/josm/jrt/core/EdgeIterator.java   |    2 +-
 .../com/innovant/josm/jrt/core/RoutingEdge.java    |   10 +-
 .../josm/jrt/core/RoutingGraphDelegator.java       |   12 +-
 routing/src/com/innovant/josm/jrt/osm/OsmEdge.java |    2 +-
 .../josm/plugins/slippymap/SlippyMapKey.java       |  126 +-
 .../josm/plugins/slippymap/SlippyMapLayer.java     |    8 +-
 .../josm/plugins/slippymap/SlippyMapPlugin.java    |   36 +-
 .../slippymap/SlippyMapPreferenceSetting.java      |   10 +-
 .../plugins/slippymap/SlippyMapPreferences.java    |  108 +-
 svn-info.xml                                       |    8 +-
 wmsplugin/build.xml                                |    3 +-
 wmsplugin/sources.cfg                              |    3 +
 wmsplugin/src/wmsplugin/AddWMSLayerPanel.java      |  909 ++++++------
 wmsplugin/src/wmsplugin/GeorefImage.java           |  400 +++---
 wmsplugin/src/wmsplugin/Grabber.java               |  204 +--
 wmsplugin/src/wmsplugin/HTMLGrabber.java           |   59 +-
 .../src/wmsplugin/Map_Rectifier_WMSmenuAction.java |  421 +++---
 wmsplugin/src/wmsplugin/WMSAdjustAction.java       |  366 ++---
 wmsplugin/src/wmsplugin/WMSDownloadAction.java     |   33 +-
 wmsplugin/src/wmsplugin/WMSGrabber.java            |  332 ++---
 wmsplugin/src/wmsplugin/WMSInfo.java               |  113 +-
 wmsplugin/src/wmsplugin/WMSLayer.java              | 1497 ++++++++++----------
 wmsplugin/src/wmsplugin/WMSLayerInfo.java          |  156 ++
 wmsplugin/src/wmsplugin/WMSPlugin.java             |  618 ++++----
 wmsplugin/src/wmsplugin/WMSPreferenceEditor.java   |  319 +++--
 wmsplugin/src/wmsplugin/WMSRemoteHandler.java      |  168 ++-
 wmsplugin/src/wmsplugin/WMSRequest.java            |  186 +--
 wmsplugin/src/wmsplugin/io/WMSLayerExporter.java   |    8 +-
 wmsplugin/src/wmsplugin/io/WMSLayerImporter.java   |    8 +-
 93 files changed, 5874 insertions(+), 5656 deletions(-)

diff --git a/DirectUpload/src/org/openstreetmap/josm/plugins/DirectUpload/UploadDataGui.java b/DirectUpload/src/org/openstreetmap/josm/plugins/DirectUpload/UploadDataGui.java
index 2e48017..29775e6 100644
--- a/DirectUpload/src/org/openstreetmap/josm/plugins/DirectUpload/UploadDataGui.java
+++ b/DirectUpload/src/org/openstreetmap/josm/plugins/DirectUpload/UploadDataGui.java
@@ -81,7 +81,7 @@ public class UploadDataGui extends ExtendedDialog {
         }
 
         @Override
-		public String toString() {
+        public String toString() {
             return this.name().toLowerCase();
         }
     }
@@ -133,10 +133,10 @@ public class UploadDataGui extends ExtendedDialog {
      * @return JPanel with components
      */
     private JPanel initComponents() {
-    	JLabel visibilityLabel = new JLabel(tr("Visibility"));
+        JLabel visibilityLabel = new JLabel(tr("Visibility"));
         visibilityLabel.setToolTipText(tr("Defines the visibility of your trace for other OSM users."));
         for(visibility v : visibility.values()) {
-        	visibilityCombo.addItem(v.description);
+            visibilityCombo.addItem(v.description);
         }
         UrlLabel visiUrl = new UrlLabel(tr("http://wiki.openstreetmap.org/wiki/Visibility_of_GPS_traces"), tr("(What does that mean?)"));
 
@@ -204,55 +204,55 @@ public class UploadDataGui extends ExtendedDialog {
      * @param GpxData The GPX Data to upload
      */
     private void upload(String description, String tags, String visi, GpxData gpxData, ProgressMonitor progressMonitor) throws IOException {
-    	progressMonitor.beginTask(null);
-    	try {
-    		if(checkForErrors(username, password, description, gpxData))
-    			return;
-
-    		// Clean description/tags from disallowed chars
-    		description = description.replaceAll("[&?/\\\\]"," ");
-    		tags = tags.replaceAll("[&?/\\\\.;]"," ");
-
-    		// Set progress dialog to indeterminate while connecting
-    		progressMonitor.indeterminateSubTask(tr("Connecting..."));
-
-    		try {
-    			// Generate data for upload
-    			ByteArrayOutputStream baos  = new ByteArrayOutputStream();
-    			writeGpxFile(baos, "file", gpxData);
-    			writeField(baos, "description", description);
-    			writeField(baos, "tags", (tags != null && tags.length() > 0) ? tags : "");
-    			writeField(baos, "visibility", visi);
-    			writeString(baos, "--" + BOUNDARY + "--" + LINE_END);
-
-    			ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
-    			HttpURLConnection conn = setupConnection(baos.size());
-
-    			progressMonitor.setTicksCount(baos.size());
-    			progressMonitor.subTask(null);
-
-    			try {
-    				flushToServer(bais, conn.getOutputStream(), progressMonitor);
-    			} catch(Exception e) {}
-
-    			if(cancelled) {
-    				conn.disconnect();
-    				OutputDisplay.setText(tr("Upload cancelled"));
-    				buttons.get(0).setEnabled(true);
-    				cancelled = false;
-    			} else {
-    				boolean success = finishUpConnection(conn);
-    				buttons.get(0).setEnabled(!success);
-    				if(success)
-    					buttons.get(1).setText(tr("Close"));
-    			}
-    		} catch(Exception e) {
-    			OutputDisplay.setText(tr("Error while uploading"));
-    			e.printStackTrace();
-    		}
-    	} finally {
-    		progressMonitor.finishTask();
-    	}
+        progressMonitor.beginTask(null);
+        try {
+            if(checkForErrors(username, password, description, gpxData))
+                return;
+
+            // Clean description/tags from disallowed chars
+            description = description.replaceAll("[&?/\\\\]"," ");
+            tags = tags.replaceAll("[&?/\\\\.;]"," ");
+
+            // Set progress dialog to indeterminate while connecting
+            progressMonitor.indeterminateSubTask(tr("Connecting..."));
+
+            try {
+                // Generate data for upload
+                ByteArrayOutputStream baos  = new ByteArrayOutputStream();
+                writeGpxFile(baos, "file", gpxData);
+                writeField(baos, "description", description);
+                writeField(baos, "tags", (tags != null && tags.length() > 0) ? tags : "");
+                writeField(baos, "visibility", visi);
+                writeString(baos, "--" + BOUNDARY + "--" + LINE_END);
+
+                ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
+                HttpURLConnection conn = setupConnection(baos.size());
+
+                progressMonitor.setTicksCount(baos.size());
+                progressMonitor.subTask(null);
+
+                try {
+                    flushToServer(bais, conn.getOutputStream(), progressMonitor);
+                } catch(Exception e) {}
+
+                if(cancelled) {
+                    conn.disconnect();
+                    OutputDisplay.setText(tr("Upload cancelled"));
+                    buttons.get(0).setEnabled(true);
+                    cancelled = false;
+                } else {
+                    boolean success = finishUpConnection(conn);
+                    buttons.get(0).setEnabled(!success);
+                    if(success)
+                        buttons.get(1).setText(tr("Close"));
+                }
+            } catch(Exception e) {
+                OutputDisplay.setText(tr("Error while uploading"));
+                e.printStackTrace();
+            }
+        } finally {
+            progressMonitor.finishTask();
+        }
     }
 
     /**
diff --git a/DirectUpload/src/org/openstreetmap/josm/plugins/DirectUpload/UploadDataGuiPlugin.java b/DirectUpload/src/org/openstreetmap/josm/plugins/DirectUpload/UploadDataGuiPlugin.java
index 2473982..0fb7e68 100644
--- a/DirectUpload/src/org/openstreetmap/josm/plugins/DirectUpload/UploadDataGuiPlugin.java
+++ b/DirectUpload/src/org/openstreetmap/josm/plugins/DirectUpload/UploadDataGuiPlugin.java
@@ -26,7 +26,7 @@ public class UploadDataGuiPlugin extends Plugin{
     UploadAction openaction;
 
     public UploadDataGuiPlugin(PluginInformation info) {
-    	super(info);
+        super(info);
         openaction = new UploadAction();
         Main.main.menu.toolsMenu.add(openaction);
     }
@@ -43,15 +43,15 @@ public class UploadDataGuiPlugin extends Plugin{
         }
 
         @Override
-		protected void updateEnabledState() {
-           	// enable button if there is "one active GpxLayer" or "exactly one GpxLayer in the list of all layers available"
-           	if(Main.map == null
+        protected void updateEnabledState() {
+            // enable button if there is "one active GpxLayer" or "exactly one GpxLayer in the list of all layers available"
+            if(Main.map == null
                     || Main.map.mapView == null
                     || Main.map.mapView.getActiveLayer() == null
-                    || !(Main.map.mapView.getActiveLayer() instanceof GpxLayer)) {                
+                    || !(Main.map.mapView.getActiveLayer() instanceof GpxLayer)) {
                 setEnabled(false);
             } else {
-            	setEnabled(true);
+                setEnabled(true);
             }
 
             if(Main.map != null && Main.map.mapView.getNumLayers() > 1) {
@@ -60,6 +60,6 @@ public class UploadDataGuiPlugin extends Plugin{
                     setEnabled(true);
             }
 
-        }		
+        }
     }
 }
\ No newline at end of file
diff --git a/cadastre-fr/src/cadastre_fr/CacheControl.java b/cadastre-fr/src/cadastre_fr/CacheControl.java
index 84ca7f9..df00235 100644
--- a/cadastre-fr/src/cadastre_fr/CacheControl.java
+++ b/cadastre-fr/src/cadastre_fr/CacheControl.java
@@ -24,7 +24,7 @@ import org.openstreetmap.josm.data.projection.LambertCC9Zones;
 import org.openstreetmap.josm.data.projection.UTM_France_DOM;
 
 public class CacheControl implements Runnable {
-    
+
     public static final String cLambertCC9Z = "CC";
 
     public static final String cUTM20N = "UTM";
@@ -54,7 +54,7 @@ public class CacheControl implements Runnable {
         imagesLock.unlock();
         return ret;
     }
-    
+
     public CacheControl(WMSLayer wmsLayer) {
         cacheEnabled = Main.pref.getBoolean("cadastrewms.enableCaching", true);
         this.wmsLayer = wmsLayer;
@@ -109,7 +109,7 @@ public class CacheControl implements Runnable {
                     dialog.setVisible(true);
                     int reply = (Integer)pane.getValue();
                     // till here
-    
+
                     if (reply == JOptionPane.OK_OPTION && loadCache(file, wmsLayer.getLambertZone())) {
                         return true;
                     } else {
@@ -135,7 +135,7 @@ public class CacheControl implements Runnable {
             e.printStackTrace(System.out);
         }
     }
-    
+
     private void delete(File file) {
         System.out.println("Delete file "+file);
         if (file.exists())
@@ -214,7 +214,7 @@ public class CacheControl implements Runnable {
             }
         }
     }
-    
+
     private String WMSFileExtension() {
         String ext = String.valueOf((wmsLayer.getLambertZone() + 1));
         if (Main.proj instanceof LambertCC9Zones)
diff --git a/cadastre-fr/src/cadastre_fr/CadastreGrabber.java b/cadastre-fr/src/cadastre_fr/CadastreGrabber.java
index ccaea02..00528d2 100644
--- a/cadastre-fr/src/cadastre_fr/CadastreGrabber.java
+++ b/cadastre-fr/src/cadastre_fr/CadastreGrabber.java
@@ -51,7 +51,7 @@ public class CadastreGrabber {
             throw (IOException) new IOException(tr("CadastreGrabber: Illegal url.")).initCause(e);
         }
     }
-    
+
     public GeorefImage grabParcels(WMSLayer wmsLayer, EastNorth lambertMin, EastNorth lambertMax) throws IOException, OsmTransferException {
         try {
             URL url = getURLVectorParcels(lambertMin, lambertMax);
@@ -62,7 +62,7 @@ public class CadastreGrabber {
             throw (IOException) new IOException(tr("CadastreGrabber: Illegal url.")).initCause(e);
         }
     }
-    
+
     private URL getURLRaster(WMSLayer wmsLayer, EastNorth lambertMin, EastNorth lambertMax) throws MalformedURLException {
         // GET /scpc/wms?version=1.1&request=GetMap&layers=CDIF:PMC at QH4480001701&format=image/png&bbox=-1186,0,13555,8830&width=576&height=345&exception=application/vnd.ogc.se_inimage&styles= HTTP/1.1
         final int cRasterX = CadastrePlugin.imageWidth; // keep width constant and adjust width to original image proportions
@@ -84,7 +84,7 @@ public class CadastreGrabber {
             int width, int height,
             EastNorth lambertMin, EastNorth lambertMax) throws MalformedURLException {
         String str = new String(wmsInterface.baseURL+"/scpc/wms?version=1.1&request=GetMap");
-        str += "&layers="+ layers;  
+        str += "&layers="+ layers;
         str += "&format=image/png";
         //str += "&format=image/jpeg";
         str += "&bbox="+lambertMin.east()+",";
@@ -99,8 +99,8 @@ public class CadastreGrabber {
     }
 
     private URL getURLVector(EastNorth lambertMin, EastNorth lambertMax) throws MalformedURLException {
-        return buildURLVector(CadastrePlugin.grabLayers, CadastrePlugin.grabStyles, 
-                CadastrePlugin.imageWidth, CadastrePlugin.imageHeight, 
+        return buildURLVector(CadastrePlugin.grabLayers, CadastrePlugin.grabStyles,
+                CadastrePlugin.imageWidth, CadastrePlugin.imageHeight,
                 lambertMin, lambertMax);
     }
 
diff --git a/cadastre-fr/src/cadastre_fr/CadastreInterface.java b/cadastre-fr/src/cadastre_fr/CadastreInterface.java
index be0d168..dafa977 100644
--- a/cadastre-fr/src/cadastre_fr/CadastreInterface.java
+++ b/cadastre-fr/src/cadastre_fr/CadastreInterface.java
@@ -52,7 +52,7 @@ public class CadastreInterface {
     final String c0ptionListStart = "<option value=\"";
     final String cOptionListEnd = "</option>";
     final String cBBoxCommunStart = "new GeoBox(";
-    final String cBBoxCommunEnd = ")";    
+    final String cBBoxCommunEnd = ")";
 
     final String cInterfaceVector = "afficherCarteCommune.do";
     final String cInterfaceRasterTA = "afficherCarteTa.do";
@@ -61,7 +61,7 @@ public class CadastreInterface {
     final String cTAImageLinkStart = "title=\"image\"><a href=\"#\" onClick=\"popup('afficherCarteTa.do?f=";
     final String cImageNameStart = ">Feuille ";
     final String cTAImageNameStart = "Tableau d'assemblage <strong>";
-    
+
     final static long cCookieExpiration = 30 * 60 * 1000; // 30 minutes expressed in milliseconds
 
     final  int cRetriesGetCookie = 10; // 10 times every 3 seconds means 30 seconds trying to get a cookie
@@ -96,7 +96,7 @@ public class CadastreInterface {
     }
 
     /**
-     * 
+     *
      * @return true if a cookie is delivered by WMS and false is WMS is not opening a client session
      *         (too many clients or in maintenance)
      * @throws IOException
@@ -140,7 +140,7 @@ public class CadastreInterface {
         lastWMSLayerName = null;
         cookie = null;
     }
-    
+
     public boolean isCookieExpired() {
         long now = new Date().getTime();
         if ((now - cookieTimestamp) > cCookieExpiration) {
@@ -164,7 +164,7 @@ public class CadastreInterface {
     public void setCookie(HttpURLConnection urlConn) {
         urlConn.setRequestProperty("Cookie", this.cookie);
     }
-    
+
     private void getInterface(WMSLayer wmsLayer) throws IOException, DuplicateLayerException {
         // first attempt : search for given name without codeCommune
         interfaceRef = postForm(wmsLayer, "");
@@ -378,7 +378,7 @@ public class CadastreInterface {
         }
         return lines;
     }
-    
+
     private void parseFeuillesList(String input) {
         listOfFeuilles.clear();
         // get "Tableau d'assemblage"
@@ -401,7 +401,7 @@ public class CadastreInterface {
             listOfFeuilles.add(new PlanImage(nameFeuille, refFeuille));
         }
     }
-    
+
     private String selectMunicipalityDialog(WMSLayer wmsLayer) {
         JPanel p = new JPanel(new GridBagLayout());
         String[] communeList = new String[listOfCommunes.size() + 1];
@@ -454,7 +454,7 @@ public class CadastreInterface {
      * Retrieve the bounding box size in pixels of the whole commune (point 0,0 at top, left corner)
      * and store it in given wmsLayer
      * In case of raster image, we also check in the same http request if the image is already georeferenced
-     * and store the result in the wmsLayer as well. 
+     * and store the result in the wmsLayer as well.
      * @param wmsLayer the WMSLayer where the commune data and images are stored
      * @throws IOException
      */
@@ -501,7 +501,7 @@ public class CadastreInterface {
             wmsLayer.setCommuneBBox( new EastNorthBound(new EastNorth(minx,miny), new EastNorth(maxx,maxy)));
         }
     }
-    
+
     private void parseGeoreferences(WMSLayer wmsLayer, String input) {
         if (input.lastIndexOf(cBBoxCommunStart) != -1) {
             input = input.substring(input.lastIndexOf(cBBoxCommunStart));
@@ -536,7 +536,7 @@ public class CadastreInterface {
                     fY+","+X0+","+Y0);
         }
     }
-    
+
     private double tryParseDouble(String str) {
         try {
             return Double.parseDouble(str);
diff --git a/cadastre-fr/src/cadastre_fr/CadastrePlugin.java b/cadastre-fr/src/cadastre_fr/CadastrePlugin.java
index 7f993e0..e8cbd76 100644
--- a/cadastre-fr/src/cadastre_fr/CadastrePlugin.java
+++ b/cadastre-fr/src/cadastre_fr/CadastrePlugin.java
@@ -95,7 +95,7 @@ import org.openstreetmap.josm.data.projection.*;
  *                 - cookie expiration automatically detected and renewed (after 30 minutes)
  *                 - proper WMS layer cleanup at destruction (workaround for memory leak)
  *                 - new cache format (v3) storing original image and cropped image bbox + angle
- *                 - new cache format (v4) storing original image size for later rotation 
+ *                 - new cache format (v4) storing original image size for later rotation
  *                 - cache files read compatible with previous formats
  *                 - raster image rotation issues fixed, now using shift+ctrl key instead of ctrl
  *                 - raster image adjustment using default system menu modifier (ctrl for windows) for Mac support
@@ -103,7 +103,7 @@ import org.openstreetmap.josm.data.projection.*;
  *                 - layer selection configurable for vectorized images
  *                 - improved download cancellation
  *                 - from Erik Amzallag:
- *                 -     possibility to modify the auto-sourcing text just before upload 
+ *                 -     possibility to modify the auto-sourcing text just before upload
  *                 - from Clément Ménier:
  *                 -     new option allowing an auto-selection of the first cadastre layer for grab
  *                 -     non-modal JDialog in MenuActionGrabPlanImage
@@ -111,7 +111,7 @@ import org.openstreetmap.josm.data.projection.*;
  * 1.9 05-Apr-2010 - added a scroll bar in preferences
  *                 - download cancellation improved
  *                 - last deployment for Java1.5 compatibility
- * 2.0 xx-xxx-xxxx - update projection for "La Reunion" departement to RGR92, UTM40S. 
+ * 2.0 xx-xxx-xxxx - update projection for "La Reunion" departement to RGR92, UTM40S.
  *                 - add 'departement' as option in the municipality selection
  *                 - fixed bug in cache directory size control (and disabled by default)
  *                 - add map mode for addressing
@@ -144,7 +144,7 @@ public class CadastrePlugin extends Plugin {
     public static boolean drawBoundaries = false;
 
     public static int imageWidth, imageHeight;
-    
+
     public static String grabLayers, grabStyles = null;
 
     static private boolean menuEnabled = false;
@@ -155,7 +155,7 @@ public class CadastrePlugin extends Plugin {
      * @throws Exception
      */
     public CadastrePlugin(PluginInformation info) throws Exception {
-    	super(info);
+        super(info);
         System.out.println("Pluging cadastre-fr v"+VERSION+" started...");
         if (Main.pref.get("cadastrewms.cacheDir").equals(""))
             cacheDir = Main.pref.getPreferencesDir()+"plugins"+File.separatorChar+"cadastrewms"+File.separatorChar;
@@ -217,7 +217,7 @@ public class CadastrePlugin extends Plugin {
     }
 
     public static void refreshConfiguration() {
-        source = checkSourceMillesime(); 
+        source = checkSourceMillesime();
         autoSourcing = Main.pref.getBoolean("cadastrewms.autosourcing", true);
         alterColors = Main.pref.getBoolean("cadastrewms.alterColors");
         drawBoundaries = Main.pref.getBoolean("cadastrewms.drawBoundaries", false);
@@ -233,11 +233,11 @@ public class CadastrePlugin extends Plugin {
             imageWidth = 1000; imageHeight = 800;
         } else if (currentResolution.equals("medium")){
             imageWidth = 800; imageHeight = 600;
-        } else { 
+        } else {
             imageWidth = 600; imageHeight = 400;
         }
         refreshLayersURL();
-        
+
         // overwrite F11 shortcut used from the beginning by this plugin and recently used
         // for full-screen switch in JOSM core
         int i = 0;
@@ -267,7 +267,7 @@ public class CadastrePlugin extends Plugin {
 
         refreshMenu();
     }
-    
+
     private static void refreshLayersURL() {
         grabLayers = "";
         grabStyles = "";
@@ -345,7 +345,7 @@ public class CadastrePlugin extends Plugin {
             }
         }
     }
-    
+
     public static boolean isCadastreProjection() {
         return Main.proj.toString().equals(new Lambert().toString())
             || Main.proj.toString().equals(new UTM_France_DOM().toString())
@@ -359,7 +359,7 @@ public class CadastrePlugin extends Plugin {
     }
 
     // See OptionPaneUtil
-    // FIXME: this is a temporary solution. 
+    // FIXME: this is a temporary solution.
     public static void prepareDialog(JDialog dialog) {
         if (Main.pref.getBoolean("window-handling.option-pane-always-on-top", true)) {
             try {
@@ -372,7 +372,7 @@ public class CadastrePlugin extends Plugin {
         dialog.toFront();
         dialog.setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE);
     }
-    
+
     /**
      * Adds the WMSLayer following this rule:<br/>
      * - if a WMSLayer exists place this new layer just before this layer<br/>
@@ -392,7 +392,7 @@ public class CadastrePlugin extends Plugin {
         } else
             Main.main.addLayer(wmsLayer);
     }
-    
+
     private static String checkSourceMillesime() {
         java.util.Calendar calendar = java.util.Calendar.getInstance();
         int currentYear = calendar.get(java.util.Calendar.YEAR);
@@ -410,5 +410,5 @@ public class CadastrePlugin extends Plugin {
         }
         return src;
     }
-    
+
 }
diff --git a/cadastre-fr/src/cadastre_fr/CadastrePreferenceSetting.java b/cadastre-fr/src/cadastre_fr/CadastrePreferenceSetting.java
index d641c79..189274b 100644
--- a/cadastre-fr/src/cadastre_fr/CadastrePreferenceSetting.java
+++ b/cadastre-fr/src/cadastre_fr/CadastrePreferenceSetting.java
@@ -39,13 +39,13 @@ public class CadastrePreferenceSetting implements PreferenceSetting {
     private JComboBox imageInterpolationMethod = new JComboBox();
 
     private JCheckBox disableImageCropping = new JCheckBox(tr("Disable image cropping during georeferencing."));
-    
+
     private JCheckBox enableTableauAssemblage = new JCheckBox(tr("Use \"Tableau d''assemblage\""));
-    
+
     private JCheckBox autoFirstLayer = new JCheckBox(tr("Select first WMS layer in list."));
-    
+
     private JCheckBox dontUseRelation = new JCheckBox(tr("Don't use relation for addresses (but \"addr:street\" on elements)."));
-    
+
     private JRadioButton grabMultiplier1 = new JRadioButton("", true);
 
     private JRadioButton grabMultiplier2 = new JRadioButton("", true);
@@ -53,9 +53,9 @@ public class CadastrePreferenceSetting implements PreferenceSetting {
     private JRadioButton grabMultiplier3 = new JRadioButton("", true);
 
     private JRadioButton grabMultiplier4 = new JRadioButton("", true);
-    
+
     private JRadioButton crosspiece1 = new JRadioButton("off");
-    
+
     private JRadioButton crosspiece2 = new JRadioButton("25m");
 
     private JRadioButton crosspiece3 = new JRadioButton("50m");
@@ -86,12 +86,12 @@ public class CadastrePreferenceSetting implements PreferenceSetting {
     static final int DEFAULT_CACHE_SIZE = 0; // disabled by default
     JLabel jLabelCacheSize = new JLabel(tr("Max. cache size (in MB)"));
     private JTextField cacheSize = new JTextField(20);
-    
+
     static final String DEFAULT_RASTER_DIVIDER = "5";
     private JTextField rasterDivider = new JTextField(10);
 
     static final int DEFAULT_CROSSPIECES = 0;
-    
+
     public void addGui(final PreferenceTabbedPane gui) {
 
         String description = tr("A special handler of the French cadastre wms at www.cadastre.gouv.fr" + "<BR><BR>"
@@ -100,7 +100,7 @@ public class CadastrePreferenceSetting implements PreferenceSetting {
                 + "http://www.cadastre.gouv.fr/scpc/html/CU_01_ConditionsGenerales_fr.html</a> <BR>"
                 + "before any upload of data created by this plugin.");
         JPanel cadastrewmsMast = gui.createPreferenceTab("cadastrewms.gif", I18n.tr("French cadastre WMS"), description);
-        
+
         JPanel cadastrewms = new JPanel(new GridBagLayout());
         cadastrewms.setBorder(BorderFactory.createEmptyBorder(0,0,0,0));
 
@@ -176,7 +176,7 @@ public class CadastrePreferenceSetting implements PreferenceSetting {
         cadastrewms.add(grabRes1, GBC.std().insets(5, 0, 5, 0));
         cadastrewms.add(grabRes2, GBC.std().insets(5, 0, 5, 0));
         cadastrewms.add(grabRes3, GBC.eol().fill(GBC.HORIZONTAL).insets(5, 5, 0, 5));
-        
+
         // option to select image zooming interpolation method
         JLabel jLabelImageZoomInterpolation = new JLabel(tr("Image filter interpolation:"));
         cadastrewms.add(jLabelImageZoomInterpolation, GBC.std().insets(0, 0, 10, 0));
@@ -184,9 +184,9 @@ public class CadastrePreferenceSetting implements PreferenceSetting {
         imageInterpolationMethod.addItem(tr("Bilinear (fast)"));
         imageInterpolationMethod.addItem(tr("Bicubic (slow)"));
         String savedImageInterpolationMethod = Main.pref.get("cadastrewms.imageInterpolation", "standard");
-        if (savedImageInterpolationMethod.equals("bilinear")) 
+        if (savedImageInterpolationMethod.equals("bilinear"))
             imageInterpolationMethod.setSelectedIndex(1);
-        else if (savedImageInterpolationMethod.equals("bicubic")) 
+        else if (savedImageInterpolationMethod.equals("bicubic"))
             imageInterpolationMethod.setSelectedIndex(2);
         else
             imageInterpolationMethod.setSelectedIndex(0);
@@ -194,7 +194,7 @@ public class CadastrePreferenceSetting implements PreferenceSetting {
 
         // separator
         cadastrewms.add(new JSeparator(SwingConstants.HORIZONTAL), GBC.eol().fill(GBC.HORIZONTAL));
-        
+
         // the vectorized images multiplier
         JLabel jLabelScale = new JLabel(tr("Vector images grab multiplier:"));
         cadastrewms.add(jLabelScale, GBC.std().insets(0, 5, 10, 0));
@@ -274,7 +274,7 @@ public class CadastrePreferenceSetting implements PreferenceSetting {
         layerCommune.setSelected(Main.pref.getBoolean("cadastrewms.layerCommune", true));
         layerCommune.setToolTipText(tr("Municipality administrative borders."));
         cadastrewms.add(layerCommune, GBC.eop().insets(5, 0, 5, 0));
-        
+
         // separator
         cadastrewms.add(new JSeparator(SwingConstants.HORIZONTAL), GBC.eol().fill(GBC.HORIZONTAL));
 
@@ -334,7 +334,7 @@ public class CadastrePreferenceSetting implements PreferenceSetting {
 
         // separator
         cadastrewms.add(new JSeparator(SwingConstants.HORIZONTAL), GBC.eol().fill(GBC.HORIZONTAL));
-        
+
         // option to select the first WMS layer
         autoFirstLayer.setSelected(Main.pref.getBoolean("cadastrewms.autoFirstLayer", false));
         autoFirstLayer.setToolTipText(tr("Automatically selects the first WMS layer if multiple layers exist when grabbing."));
@@ -347,7 +347,7 @@ public class CadastrePreferenceSetting implements PreferenceSetting {
         dontUseRelation.setSelected(Main.pref.getBoolean("cadastrewms.addr.dontUseRelation", false));
         dontUseRelation.setToolTipText(tr("Enable this to use the tag \"add:street\" on nodes."));
         cadastrewms.add(dontUseRelation, GBC.eop().insets(0, 0, 0, 0));
-        
+
         // end of dialog, scroll bar
         cadastrewms.add(Box.createVerticalGlue(), GBC.eol().fill(GBC.VERTICAL));
         JScrollPane scrollpane = new JScrollPane(cadastrewms);
@@ -373,7 +373,7 @@ public class CadastrePreferenceSetting implements PreferenceSetting {
             Main.pref.put("cadastrewms.imageInterpolation", "bicubic");
         else if (imageInterpolationMethod.getSelectedIndex() == 1)
             Main.pref.put("cadastrewms.imageInterpolation", "bilinear");
-        else 
+        else
             Main.pref.put("cadastrewms.imageInterpolation", "standard");
         if (grabMultiplier1.isSelected())
             Main.pref.put("cadastrewms.scale", Scale.X1.toString());
diff --git a/cadastre-fr/src/cadastre_fr/CheckSourceUploadHook.java b/cadastre-fr/src/cadastre_fr/CheckSourceUploadHook.java
index c2a125c..a33266a 100644
--- a/cadastre-fr/src/cadastre_fr/CheckSourceUploadHook.java
+++ b/cadastre-fr/src/cadastre_fr/CheckSourceUploadHook.java
@@ -37,7 +37,7 @@ public class CheckSourceUploadHook implements UploadHook
     /**
      * Add the tag "source" if it doesn't exist for all new Nodes and Ways before uploading
      */
-    public boolean checkUpload(APIDataSet apiDataSet) 
+    public boolean checkUpload(APIDataSet apiDataSet)
     {
         if (CadastrePlugin.autoSourcing && CadastrePlugin.pluginUsed && !apiDataSet.getPrimitivesToAdd().isEmpty()) {
             Collection<OsmPrimitive> sel = new HashSet<OsmPrimitive>();
diff --git a/cadastre-fr/src/cadastre_fr/DownloadSVGBuilding.java b/cadastre-fr/src/cadastre_fr/DownloadSVGBuilding.java
index 7c035ba..7ac3339 100644
--- a/cadastre-fr/src/cadastre_fr/DownloadSVGBuilding.java
+++ b/cadastre-fr/src/cadastre_fr/DownloadSVGBuilding.java
@@ -53,7 +53,7 @@ public class DownloadSVGBuilding extends PleaseWaitRunnable {
 
     @Override
     public void realRun() throws IOException, OsmTransferException {
-    	progressMonitor.indeterminateSubTask(tr("Contacting WMS Server..."));
+        progressMonitor.indeterminateSubTask(tr("Contacting WMS Server..."));
         errorMessage = null;
         try {
             if (wmsInterface.retrieveInterface(wmsLayer)) {
diff --git a/cadastre-fr/src/cadastre_fr/DownloadSVGTask.java b/cadastre-fr/src/cadastre_fr/DownloadSVGTask.java
index eb36b3b..925d4e7 100644
--- a/cadastre-fr/src/cadastre_fr/DownloadSVGTask.java
+++ b/cadastre-fr/src/cadastre_fr/DownloadSVGTask.java
@@ -56,7 +56,7 @@ public class DownloadSVGTask extends PleaseWaitRunnable {
 
     @Override
     public void realRun() throws IOException, OsmTransferException {
-    	progressMonitor.indeterminateSubTask(tr("Contacting WMS Server..."));
+        progressMonitor.indeterminateSubTask(tr("Contacting WMS Server..."));
         errorMessage = null;
         try {
             if (wmsInterface.retrieveInterface(wmsLayer)) {
diff --git a/cadastre-fr/src/cadastre_fr/DownloadWMSVectorImage.java b/cadastre-fr/src/cadastre_fr/DownloadWMSVectorImage.java
index 0f2756c..44f316d 100644
--- a/cadastre-fr/src/cadastre_fr/DownloadWMSVectorImage.java
+++ b/cadastre-fr/src/cadastre_fr/DownloadWMSVectorImage.java
@@ -15,8 +15,8 @@ import org.openstreetmap.josm.gui.PleaseWaitRunnable;
 public class DownloadWMSVectorImage extends PleaseWaitRunnable {
 
     private WMSLayer wmsLayer;
-    private Bounds bounds;    
-    private CadastreGrabber grabber = CadastrePlugin.cadastreGrabber;    
+    private Bounds bounds;
+    private CadastreGrabber grabber = CadastrePlugin.cadastreGrabber;
     private static String errorMessage;
 
     public DownloadWMSVectorImage(WMSLayer wmsLayer, Bounds bounds, boolean buildingsOnly) {
diff --git a/cadastre-fr/src/cadastre_fr/EastNorthBound.java b/cadastre-fr/src/cadastre_fr/EastNorthBound.java
index d0e051c..178496f 100644
--- a/cadastre-fr/src/cadastre_fr/EastNorthBound.java
+++ b/cadastre-fr/src/cadastre_fr/EastNorthBound.java
@@ -30,7 +30,7 @@ public class EastNorthBound implements Serializable {
                 this.max.interpolate(en2.max, proportion));
         return enb;
     }
-    
+
     public Bounds toBounds() {
         return new Bounds(Main.proj.eastNorth2latlon(min), Main.proj.eastNorth2latlon(max));
     }
diff --git a/cadastre-fr/src/cadastre_fr/GeorefImage.java b/cadastre-fr/src/cadastre_fr/GeorefImage.java
index 735c86a..5560880 100644
--- a/cadastre-fr/src/cadastre_fr/GeorefImage.java
+++ b/cadastre-fr/src/cadastre_fr/GeorefImage.java
@@ -29,9 +29,9 @@ public class GeorefImage implements Serializable, ImageObserver {
     public EastNorth min;
     public EastNorth max;
     // bbox of the georeferenced original image (raster only) (inclined if rotated and before cropping)
-    // P[0] is bottom,left then next are clockwise. 
+    // P[0] is bottom,left then next are clockwise.
     public EastNorth[] orgRaster = new EastNorth[4];
-    // bbox of the georeferenced original image (raster only) after cropping 
+    // bbox of the georeferenced original image (raster only) after cropping
     public EastNorth[] orgCroppedRaster = new EastNorth[4];
     // angle with georeferenced original image after rotation (raster images only)(in radian)
     public double angle = 0;
@@ -45,7 +45,7 @@ public class GeorefImage implements Serializable, ImageObserver {
 
     public GeorefImage(BufferedImage img, EastNorth min, EastNorth max) {
         image = img;
-        
+
         this.min = min;
         this.max = max;
         this.orgRaster[0] = min;
@@ -69,8 +69,8 @@ public class GeorefImage implements Serializable, ImageObserver {
     }
 
     /**
-     * Recalculate the new bounding box of the image based on the four points provided as parameters. 
-     * The new bbox defined in [min.max] will retain the extreme values of both boxes. 
+     * Recalculate the new bounding box of the image based on the four points provided as parameters.
+     * The new bbox defined in [min.max] will retain the extreme values of both boxes.
      * @param p1 one of the bounding box corner
      * @param p2 one of the bounding box corner
      * @param p3 one of the bounding box corner
@@ -127,7 +127,7 @@ public class GeorefImage implements Serializable, ImageObserver {
                     g.setColor(Color.green);
                     g.drawLine(croppedPoint[i].x, croppedPoint[i].y, croppedPoint[i+1].x, croppedPoint[i+1].y);
                 }
-                /* 
+                /*
                 //Uncomment this section to display the original image size (before cropping)
                 Point[] orgPoint = new Point[5];
                 for (int i=0; i<4; i++)
@@ -211,7 +211,7 @@ public class GeorefImage implements Serializable, ImageObserver {
         if (WMSLayer.currentFormat >= 4) {
             imageOriginalHeight = in.readInt();
             imageOriginalWidth =  in.readInt();
-        }        
+        }
         image = (BufferedImage) ImageIO.read(ImageIO.createImageInputStream(in));
         updatePixelPer();
     }
@@ -275,10 +275,10 @@ public class GeorefImage implements Serializable, ImageObserver {
             orgCroppedRaster[i] = new EastNorth(orgCroppedRaster[i].east() + dx, orgCroppedRaster[i].north() + dy);
         }
     }
-    
+
     /**
      * Change this image scale by moving the min,max coordinates around an anchor
-     * @param anchor 
+     * @param anchor
      * @param proportion
      */
     public void scale(EastNorth anchor, double proportion) {
@@ -323,7 +323,7 @@ public class GeorefImage implements Serializable, ImageObserver {
         max = enb.max;
         angle+=delta_ang;
     }
-    
+
     /**
      * Crop the image based on new bbox coordinates adj1 and adj2 (for raster images only).
      * @param adj1 is the new corner bottom, left
diff --git a/cadastre-fr/src/cadastre_fr/ImageModifier.java b/cadastre-fr/src/cadastre_fr/ImageModifier.java
index 2c46401..1bbeaba 100644
--- a/cadastre-fr/src/cadastre_fr/ImageModifier.java
+++ b/cadastre-fr/src/cadastre_fr/ImageModifier.java
@@ -18,7 +18,7 @@ public abstract class ImageModifier {
     private static final long serialVersionUID = 1L;
 
     protected int parcelColor = Color.RED.getRGB();
-    
+
     public BufferedImage bufferedImage;
 
     public static int[] cRoofColors = new int[] {-197380, -592138};
@@ -30,21 +30,21 @@ public abstract class ImageModifier {
             new byte[] { (byte) 0, (byte) 0xFF },
             new byte[] { (byte) 0, (byte) 0xFF }
         );
-        
+
         BufferedImage dest = new BufferedImage(
             src.getWidth(), src.getHeight(),
             BufferedImage.TYPE_BYTE_BINARY,
             icm
             );
-        
+
         ColorConvertOp cco = new ColorConvertOp(
             src.getColorModel().getColorSpace(),
             dest.getColorModel().getColorSpace(),
             null
             );
-        
+
         cco.filter(src, dest);
-        
+
         return dest;
       }
 
@@ -71,7 +71,7 @@ public abstract class ImageModifier {
         };
         return convert4(src, cmap);
       }
-        
+
       /**
        * Converts the source image to 4-bit colour
        * using the given colour map.  No transparency.
@@ -95,10 +95,10 @@ public abstract class ImageModifier {
             null
             );
         cco.filter(src, dest);
-        
+
         return dest;
       }
-      
+
     protected BufferedImage convert8(BufferedImage src) {
         BufferedImage dest = new BufferedImage(
             src.getWidth(), src.getHeight(),
@@ -114,7 +114,7 @@ public abstract class ImageModifier {
       }
 
     public boolean isBuildingColor(int rgb, boolean ignoreParcelColor) {
-        for (int i = 0; i < cBuilingFootColors.length; i++) 
+        for (int i = 0; i < cBuilingFootColors.length; i++)
             if (rgb == cBuilingFootColors[i])
                     return true;
         if (ignoreParcelColor && (rgb == parcelColor))
@@ -123,7 +123,7 @@ public abstract class ImageModifier {
     }
 
     public boolean isRoofColor(int rgb, boolean ignoreParcelColor) {
-        for (int i = 0; i < cRoofColors.length; i++) 
+        for (int i = 0; i < cRoofColors.length; i++)
             if (rgb == cRoofColors[i])
                     return true;
         if (ignoreParcelColor && (rgb == parcelColor))
@@ -151,10 +151,10 @@ public abstract class ImageModifier {
             ret = isRoofColor(rgb, ignoreParcelColor);
         return ret;
     }
-    
+
     /**
      * Checks if the rgb value is the black background color
-     * @param  
+     * @param
      * @return
      */
     public boolean isBackgroundColor(BufferedImage img, int x, int y) {
diff --git a/cadastre-fr/src/cadastre_fr/MenuActionGrabPlanImage.java b/cadastre-fr/src/cadastre_fr/MenuActionGrabPlanImage.java
index 96b79a1..b406e1b 100644
--- a/cadastre-fr/src/cadastre_fr/MenuActionGrabPlanImage.java
+++ b/cadastre-fr/src/cadastre_fr/MenuActionGrabPlanImage.java
@@ -179,20 +179,20 @@ public class MenuActionGrabPlanImage extends JosmAction implements Runnable, Mou
      * @return false if all operations are canceled
      */
     private boolean startCropping() {
-	    mode = cGetCorners;
-	    countMouseClicked = 0;
-		Object[] options = { "OK", "Cancel" };
-		int ret = JOptionPane.showOptionDialog( null,
-				tr("Click first corner for image cropping\n(two points required)"),
-				tr("Image cropping"),
-	    		JOptionPane.DEFAULT_OPTION, JOptionPane.INFORMATION_MESSAGE,
-	    		null, options, options[0]);
-	    if (ret == JOptionPane.OK_OPTION) {
-	        mouseClickedTime = System.currentTimeMillis();
-	    } else
-	    	if (canceledOrRestartCurrAction("image cropping"))
-	    		return startCropping();
-	    return true;
+        mode = cGetCorners;
+        countMouseClicked = 0;
+        Object[] options = { "OK", "Cancel" };
+        int ret = JOptionPane.showOptionDialog( null,
+                tr("Click first corner for image cropping\n(two points required)"),
+                tr("Image cropping"),
+                JOptionPane.DEFAULT_OPTION, JOptionPane.INFORMATION_MESSAGE,
+                null, options, options[0]);
+        if (ret == JOptionPane.OK_OPTION) {
+            mouseClickedTime = System.currentTimeMillis();
+        } else
+            if (canceledOrRestartCurrAction("image cropping"))
+                return startCropping();
+        return true;
     }
 
     /**
@@ -200,17 +200,17 @@ public class MenuActionGrabPlanImage extends JosmAction implements Runnable, Mou
      * @return false if all operations are canceled
      */
     private boolean continueCropping() {
-		Object[] options = { "OK", "Cancel" };
-		int ret = JOptionPane.showOptionDialog( null,
-				tr("Click second corner for image cropping"),
-				tr("Image cropping"),
-	    		JOptionPane.DEFAULT_OPTION, JOptionPane.INFORMATION_MESSAGE,
-	    		null, options, options[0]);
-	    if (ret != JOptionPane.OK_OPTION) {
-	    	if (canceledOrRestartCurrAction("image cropping"))
-	    		return startCropping();
-	    }
-	    return true;
+        Object[] options = { "OK", "Cancel" };
+        int ret = JOptionPane.showOptionDialog( null,
+                tr("Click second corner for image cropping"),
+                tr("Image cropping"),
+                JOptionPane.DEFAULT_OPTION, JOptionPane.INFORMATION_MESSAGE,
+                null, options, options[0]);
+        if (ret != JOptionPane.OK_OPTION) {
+            if (canceledOrRestartCurrAction("image cropping"))
+                return startCropping();
+        }
+        return true;
     }
 
     /**
@@ -218,20 +218,20 @@ public class MenuActionGrabPlanImage extends JosmAction implements Runnable, Mou
      * @return false if all operations are canceled
      */
     private boolean startGeoreferencing() {
-	    countMouseClicked = 0;
-	    mode = cGetLambertCrosspieces;
-		Object[] options = { "OK", "Cancel" };
-		int ret = JOptionPane.showOptionDialog( null,
-				tr("Click first Lambert crosspiece for georeferencing\n(two points required)"),
-				tr("Image georeferencing"),
-	    		JOptionPane.DEFAULT_OPTION, JOptionPane.INFORMATION_MESSAGE,
-	    		null, options, options[0]);
-	    if (ret == JOptionPane.OK_OPTION) {
-	        mouseClickedTime = System.currentTimeMillis();
-	    } else
-	    	if (canceledOrRestartCurrAction("georeferencing"))
-	    		return startGeoreferencing();
-	    return true;
+        countMouseClicked = 0;
+        mode = cGetLambertCrosspieces;
+        Object[] options = { "OK", "Cancel" };
+        int ret = JOptionPane.showOptionDialog( null,
+                tr("Click first Lambert crosspiece for georeferencing\n(two points required)"),
+                tr("Image georeferencing"),
+                JOptionPane.DEFAULT_OPTION, JOptionPane.INFORMATION_MESSAGE,
+                null, options, options[0]);
+        if (ret == JOptionPane.OK_OPTION) {
+            mouseClickedTime = System.currentTimeMillis();
+        } else
+            if (canceledOrRestartCurrAction("georeferencing"))
+                return startGeoreferencing();
+        return true;
     }
 
     /**
@@ -239,17 +239,17 @@ public class MenuActionGrabPlanImage extends JosmAction implements Runnable, Mou
      * @return false if all operations are canceled
      */
     private boolean continueGeoreferencing() {
-		Object[] options = { "OK", "Cancel" };
-		int ret = JOptionPane.showOptionDialog( null,
-				tr("Click second Lambert crosspiece for georeferencing"),
-				tr("Image georeferencing"),
-	    		JOptionPane.DEFAULT_OPTION, JOptionPane.INFORMATION_MESSAGE,
-	    		null, options, options[0]);
-	    if (ret != JOptionPane.OK_OPTION) {
-	    	if (canceledOrRestartCurrAction("georeferencing"))
-	    		return startGeoreferencing();
-	    }
-	    return true;
+        Object[] options = { "OK", "Cancel" };
+        int ret = JOptionPane.showOptionDialog( null,
+                tr("Click second Lambert crosspiece for georeferencing"),
+                tr("Image georeferencing"),
+                JOptionPane.DEFAULT_OPTION, JOptionPane.INFORMATION_MESSAGE,
+                null, options, options[0]);
+        if (ret != JOptionPane.OK_OPTION) {
+            if (canceledOrRestartCurrAction("georeferencing"))
+                return startGeoreferencing();
+        }
+        return true;
     }
     
     /**
@@ -270,16 +270,16 @@ public class MenuActionGrabPlanImage extends JosmAction implements Runnable, Mou
      * @return false if all operations are canceled
      */
     private boolean canceledOrRestartCurrAction(String action) {
-    	Object[] options = { "Cancel", "Retry" };
-    	int selectedValue = JOptionPane.showOptionDialog( null,
-        		tr("Do you want to cancel completely\n"+
-        				"or just retry "+action+" ?"), "",
-        		JOptionPane.DEFAULT_OPTION, JOptionPane.WARNING_MESSAGE,
-        		null, options, options[0]);
+        Object[] options = { "Cancel", "Retry" };
+        int selectedValue = JOptionPane.showOptionDialog( null,
+                tr("Do you want to cancel completely\n"+
+                        "or just retry "+action+" ?"), "",
+                JOptionPane.DEFAULT_OPTION, JOptionPane.WARNING_MESSAGE,
+                null, options, options[0]);
         countMouseClicked = 0;
         if (selectedValue == 0) { // "Cancel"
-        	// remove layer
-        	Main.map.mapView.removeLayer(wmsLayer);
+            // remove layer
+            Main.map.mapView.removeLayer(wmsLayer);
             wmsLayer = null;
             Main.map.mapView.removeMouseListener(this);
             return false;
diff --git a/cadastre-fr/src/cadastre_fr/MenuActionLoadFromCache.java b/cadastre-fr/src/cadastre_fr/MenuActionLoadFromCache.java
index 37baa94..f280908 100644
--- a/cadastre-fr/src/cadastre_fr/MenuActionLoadFromCache.java
+++ b/cadastre-fr/src/cadastre_fr/MenuActionLoadFromCache.java
@@ -76,7 +76,7 @@ public class MenuActionLoadFromCache extends JosmAction {
                     WMSLayer wmsLayer = new WMSLayer("", "", Integer.parseInt(ext)-1);
                     if (wmsLayer.getCacheControl().loadCache(file, layoutZone)) {
                         CadastrePlugin.addWMSLayer(wmsLayer);
-                    }                    
+                    }
                 }
             }
         }
diff --git a/cadastre-fr/src/cadastre_fr/MenuActionNewLocation.java b/cadastre-fr/src/cadastre_fr/MenuActionNewLocation.java
index f740da3..2300b03 100644
--- a/cadastre-fr/src/cadastre_fr/MenuActionNewLocation.java
+++ b/cadastre-fr/src/cadastre_fr/MenuActionNewLocation.java
@@ -24,29 +24,29 @@ import org.openstreetmap.josm.tools.GBC;
 public class MenuActionNewLocation extends JosmAction {
 
     private static final long serialVersionUID = 1L;
-    
+
     private static final String departements[] = {
         "", tr("(optional)"),
         "001", "01 - Ain",                 "002", "02 - Aisne",              "003", "03 - Allier",                "004", "04 - Alpes de Haute-Provence", "005", "05 - Hautes-Alpes",
         "006", "06 - Alpes-Maritimes",     "007", "07 - Ard\u00eache",       "008", "08 - Ardennes",              "009", "09 - Ari\u00e8ge",             "010", "10 - Aube",
-        "011", "11 - Aude",                "012", "12 - Aveyron",            "013", "13 - Bouches-du-Rh\u00f4ne", "014", "14 - Calvados",                "015", "15 - Cantal", 
-        "016", "16 - Charente",            "017", "17 - Charente-Maritime",  "018", "18 - Cher",                  "019", "19 - Corr\u00e8ze", 
-        "02A", "2A - Corse-du-Sud",        "02B", "2B - Haute-Corse", 
-        "021", "21 - C\u00f4te-d'Or",      "022", "22 - C\u00f4tes d'Armor", "023", "23 - Creuse",                "024", "24 - Dordogne",                "025", "25 - Doubs", 
+        "011", "11 - Aude",                "012", "12 - Aveyron",            "013", "13 - Bouches-du-Rh\u00f4ne", "014", "14 - Calvados",                "015", "15 - Cantal",
+        "016", "16 - Charente",            "017", "17 - Charente-Maritime",  "018", "18 - Cher",                  "019", "19 - Corr\u00e8ze",
+        "02A", "2A - Corse-du-Sud",        "02B", "2B - Haute-Corse",
+        "021", "21 - C\u00f4te-d'Or",      "022", "22 - C\u00f4tes d'Armor", "023", "23 - Creuse",                "024", "24 - Dordogne",                "025", "25 - Doubs",
         "026", "26 - Dr\u00f4me",          "027", "27 - Eure",               "028", "28 - Eure-et-Loir",          "029", "29 - Finist\u00e8re",          "030", "30 - Gard",
-        "031", "31 - Haute-Garonne",       "032", "32 - Gers",               "033", "33 - Gironde",               "034", "34 - H\u00e9rault",            "035", "35 - Ille-et-Vilaine", 
+        "031", "31 - Haute-Garonne",       "032", "32 - Gers",               "033", "33 - Gironde",               "034", "34 - H\u00e9rault",            "035", "35 - Ille-et-Vilaine",
         "036", "36 - Indre",               "037", "37 - Indre-et-Loire",     "038", "38 - Is\u00e8re",            "039", "39 - Jura",                    "040", "40 - Landes",
-        "041", "41 - Loir-et-Cher",        "042", "42 - Loire",              "043", "43 - Haute-Loire",           "044", "44 - Loire-Atlantique",        "045", "45 - Loiret", 
+        "041", "41 - Loir-et-Cher",        "042", "42 - Loire",              "043", "43 - Haute-Loire",           "044", "44 - Loire-Atlantique",        "045", "45 - Loiret",
         "046", "46 - Lot",                 "047", "47 - Lot-et-Garonne",     "048", "48 - Loz\u00e8re",           "049", "49 - Maine-et-Loire",          "050", "50 - Manche",
-        "051", "51 - Marne",               "052", "52 - Haute-Marne",        "053", "53 - Mayenne",               "054", "54 - Meurthe-et-Moselle",      "055", "55 - Meuse", 
+        "051", "51 - Marne",               "052", "52 - Haute-Marne",        "053", "53 - Mayenne",               "054", "54 - Meurthe-et-Moselle",      "055", "55 - Meuse",
         "056", "56 - Morbihan",            "057", "57 - Moselle",            "058", "58 - Ni\u00e8vre",           "059", "59 - Nord",                    "060", "60 - Oise",
-        "061", "61 - Orne",                "062", "62 - Pas-de-Calais",      "063", "63 - Puy-de-D\u00f4me",      "064", "64 - Pyr\u00e9n\u00e9es-Atlantiques", "065", "65 - Hautes-Pyr\u00e9n\u00e9es", 
+        "061", "61 - Orne",                "062", "62 - Pas-de-Calais",      "063", "63 - Puy-de-D\u00f4me",      "064", "64 - Pyr\u00e9n\u00e9es-Atlantiques", "065", "65 - Hautes-Pyr\u00e9n\u00e9es",
         "066", "66 - Pyr\u00e9n\u00e9es-Orientales", "067", "67 - Bas-Rhin", "068", "68 - Haut-Rhin",             "069", "69 - Rh\u00f4ne",              "070", "70 - Haute-Sa\u00f4ne",
-        "071", "71 - Sa\u00f4ne-et-Loire", "072", "72 - Sarthe",             "073", "73 - Savoie",                "074", "74 - Haute-Savoie",            "075", "75 - Paris", 
+        "071", "71 - Sa\u00f4ne-et-Loire", "072", "72 - Sarthe",             "073", "73 - Savoie",                "074", "74 - Haute-Savoie",            "075", "75 - Paris",
         "076", "76 - Seine-Maritime",      "077", "77 - Seine-et-Marne",     "078", "78 - Yvelines",              "079", "79 - Deux-S\u00e8vres",        "080", "80 - Somme",
-        "081", "81 - Tarn",                "082", "82 - Tarn-et-Garonne",    "083", "83 - Var",                   "084", "84 - Vaucluse",                "085", "85 - Vend\u00e9e", 
+        "081", "81 - Tarn",                "082", "82 - Tarn-et-Garonne",    "083", "83 - Var",                   "084", "84 - Vaucluse",                "085", "85 - Vend\u00e9e",
         "086", "86 - Vienne",              "087", "87 - Haute-Vienne",       "088", "88 - Vosges",                "089", "89 - Yonne",                   "090", "90 - Territoire de Belfort",
-        "091", "91 - Essonne",             "092", "92 - Hauts-de-Seine",     "093", "93 - Seine-Saint-Denis",     "094", "94 - Val-de-Marne",            "095", "95 - Val-d'Oise", 
+        "091", "91 - Essonne",             "092", "92 - Hauts-de-Seine",     "093", "93 - Seine-Saint-Denis",     "094", "94 - Val-de-Marne",            "095", "95 - Val-d'Oise",
         "971", "971 - Guadeloupe",         "972", "972 - Martinique",        "973", "973 - Guyane",               "974", "974 - R\u00e9union"
     };
 
@@ -80,7 +80,7 @@ public class MenuActionNewLocation extends JosmAction {
         if (!Main.pref.get("cadastrewms.codeDepartement").equals("")) {
             for (int i=0; i < departements.length; i=i+2)
                 if (departements[i].equals(Main.pref.get("cadastrewms.codeDepartement")))
-                    inputDepartement.setSelectedIndex(i/2);        
+                    inputDepartement.setSelectedIndex(i/2);
         }
         p.add(labelSectionNewLocation, GBC.eol());
         p.add(labelLocation, GBC.std().insets(10, 0, 0, 0));
diff --git a/cadastre-fr/src/cadastre_fr/WMSLayer.java b/cadastre-fr/src/cadastre_fr/WMSLayer.java
index bfc4650..79b66da 100644
--- a/cadastre-fr/src/cadastre_fr/WMSLayer.java
+++ b/cadastre-fr/src/cadastre_fr/WMSLayer.java
@@ -103,7 +103,7 @@ public class WMSLayer extends Layer implements ImageObserver {
     }
 
     @Override
-	public void destroy() {
+    public void destroy() {
         // if the layer is currently saving the images in the cache, wait until it's finished
         if (cacheControl != null) {
             while (!cacheControl.isCachePipeEmpty()) {
@@ -304,7 +304,7 @@ public class WMSLayer extends Layer implements ImageObserver {
         saveAsPng = new MenuActionSaveRasterAs(this);
         saveAsPng.setEnabled(isRaster);
         return new Action[] {
-        		LayerListDialog.getInstance().createShowHideLayerAction(),
+                LayerListDialog.getInstance().createShowHideLayerAction(),
                 LayerListDialog.getInstance().createDeleteLayerAction(),
                 new MenuActionLoadFromCache(),
                 saveAsPng,
diff --git a/colorscheme/src/at/dallermassl/josm/plugin/colorscheme/ColorSchemePlugin.java b/colorscheme/src/at/dallermassl/josm/plugin/colorscheme/ColorSchemePlugin.java
index 106cb48..a48e15f 100644
--- a/colorscheme/src/at/dallermassl/josm/plugin/colorscheme/ColorSchemePlugin.java
+++ b/colorscheme/src/at/dallermassl/josm/plugin/colorscheme/ColorSchemePlugin.java
@@ -19,7 +19,7 @@ public class ColorSchemePlugin extends Plugin {
      * Default Constructor
      */
     public ColorSchemePlugin(PluginInformation info) {
-    	super(info);
+        super(info);
     }
 
     @Override
diff --git a/editgpx/src/org/openstreetmap/josm/plugins/editgpx/EditGpxLayer.java b/editgpx/src/org/openstreetmap/josm/plugins/editgpx/EditGpxLayer.java
index 12d1fd3..0b471a9 100644
--- a/editgpx/src/org/openstreetmap/josm/plugins/editgpx/EditGpxLayer.java
+++ b/editgpx/src/org/openstreetmap/josm/plugins/editgpx/EditGpxLayer.java
@@ -34,134 +34,134 @@ import org.openstreetmap.josm.tools.ImageProvider;
 
 public class EditGpxLayer extends Layer {
 
-	private static Icon icon = new ImageIcon(Toolkit.getDefaultToolkit().createImage(EditGpxPlugin.class.getResource("/images/editgpx_layer.png")));
-	public final EditGpxData data;
-	private GPXLayerImportAction layerImport;
-
-	public EditGpxLayer(String str, EditGpxData gpxData) {
-		super(str);
-		data = gpxData;
-		layerImport = new GPXLayerImportAction(data);
-	}
-
-	/**
-	 * check if dataSet is empty
-	 * if so show import dialog to user
-	 */
-	public void initializeImport() {
-		try {
-			if(data.isEmpty()) {
-				layerImport.activateImport();
-			}
-		} catch (Exception e) {
-			System.out.println(e.getMessage());
-			e.printStackTrace();
-		}
-	}
-
-	@Override
-	public Icon getIcon() {
-		return icon;
-	}
-
-	@Override
-	public Object getInfoComponent() {
-		return getToolTipText();
-	}
-
-	@Override
-	public Action[] getMenuEntries() {
-		return new Action[] {
-				LayerListDialog.getInstance().createShowHideLayerAction(),
-				LayerListDialog.getInstance().createDeleteLayerAction(),
-				SeparatorLayerAction.INSTANCE,
-				layerImport,
-				new ConvertToGpxLayerAction(),
-				new ConvertToAnonTimeGpxLayerAction(),
-				SeparatorLayerAction.INSTANCE,
-				new LayerListPopup.InfoAction(this)};
-	}
-
-	@Override
-	public String getToolTipText() {
-		return tr("Layer for editing GPX tracks");
-	}
-
-	@Override
-	public boolean isMergable(Layer other) {
-		// TODO
-		return false;
-	}
-
-	@Override
-	public void mergeFrom(Layer from) {
-		// TODO
-	}
-
-	@Override
-	public void paint(Graphics2D g, MapView mv, Bounds bounds) {
-		g.setColor(Color.yellow);
-
-		//don't iterate through dataSet whiling making changes
-		synchronized(layerImport.importing) {
-			for (EditGpxTrack track: data.getTracks()) {
-				for (EditGpxTrackSegment segment: track.getSegments()) {
-					for (EditGpxWayPoint wayPoint: segment.getWayPoints()) {
-						if (!wayPoint.isDeleted()) {
-							Point pnt = Main.map.mapView.getPoint(wayPoint.getCoor().getEastNorth());
-							g.drawOval(pnt.x - 2, pnt.y - 2, 4, 4);
-						}
-					}
-				}
-			}
-		}
-	}
-
-
-	public void reset(){
-		//TODO implement a reset
-	}
-
-
-	@Override
-	public void visitBoundingBox(BoundingXYVisitor v) {
-		// TODO Auto-generated method stub
-	}
-
-
-	/**
-	 * convert a DataSet to GPX
-	 *
-	 * @param boolean anonTime If true set all time and date in GPX to 01/01/1970 00:00 ?
-	 * @return GPXData
-	 */
-	private GpxData toGpxData(boolean anonTime) {
-		return data.createGpxData();
-	}
-
-	//context item "Convert to GPX layer"
-	public class ConvertToGpxLayerAction extends AbstractAction {
-		public ConvertToGpxLayerAction() {
-			super(tr("Convert to GPX layer"), ImageProvider.get("converttogpx"));
-		}
-		public void actionPerformed(ActionEvent e) {
-			Main.main.addLayer(new GpxLayer(toGpxData(false), tr("Converted from: {0}", getName())));
-			Main.main.removeLayer(EditGpxLayer.this);
-			if(Main.map.mapMode instanceof EditGpxMode)
-				Main.map.selectSelectTool(false);
-		}
-	}
-
-	//context item "Convert to GPX layer with anonymised time"
-	public class ConvertToAnonTimeGpxLayerAction extends AbstractAction {
-		public ConvertToAnonTimeGpxLayerAction() {
-			super(tr("Convert to GPX layer with anonymised time"), ImageProvider.get("converttogpx"));
-		}
-		public void actionPerformed(ActionEvent e) {
-			Main.main.addLayer(new GpxLayer(toGpxData(true), tr("Converted from: {0}", getName())));
-			Main.main.removeLayer(EditGpxLayer.this);
-			if(Main.map.mapMode instanceof EditGpxMode)
-				Main.map.selectSelectTool(false);
-		}
-	}
+    private static Icon icon = new ImageIcon(Toolkit.getDefaultToolkit().createImage(EditGpxPlugin.class.getResource("/images/editgpx_layer.png")));
+    public final EditGpxData data;
+    private GPXLayerImportAction layerImport;
+
+    public EditGpxLayer(String str, EditGpxData gpxData) {
+        super(str);
+        data = gpxData;
+        layerImport = new GPXLayerImportAction(data);
+    }
+
+    /**
+     * check if dataSet is empty
+     * if so show import dialog to user
+     */
+    public void initializeImport() {
+        try {
+            if(data.isEmpty()) {
+                layerImport.activateImport();
+            }
+        } catch (Exception e) {
+            System.out.println(e.getMessage());
+            e.printStackTrace();
+        }
+    }
+
+    @Override
+    public Icon getIcon() {
+        return icon;
+    }
+
+    @Override
+    public Object getInfoComponent() {
+        return getToolTipText();
+    }
+
+    @Override
+    public Action[] getMenuEntries() {
+        return new Action[] {
+                LayerListDialog.getInstance().createShowHideLayerAction(),
+                LayerListDialog.getInstance().createDeleteLayerAction(),
+                SeparatorLayerAction.INSTANCE,
+                layerImport,
+                new ConvertToGpxLayerAction(),
+                new ConvertToAnonTimeGpxLayerAction(),
+                SeparatorLayerAction.INSTANCE,
+                new LayerListPopup.InfoAction(this)};
+    }
+
+    @Override
+    public String getToolTipText() {
+        return tr("Layer for editing GPX tracks");
+    }
+
+    @Override
+    public boolean isMergable(Layer other) {
+        // TODO
+        return false;
+    }
+
+    @Override
+    public void mergeFrom(Layer from) {
+        // TODO
+    }
+
+    @Override
+    public void paint(Graphics2D g, MapView mv, Bounds bounds) {
+        g.setColor(Color.yellow);
+
+        //don't iterate through dataSet whiling making changes
+        synchronized(layerImport.importing) {
+            for (EditGpxTrack track: data.getTracks()) {
+                for (EditGpxTrackSegment segment: track.getSegments()) {
+                    for (EditGpxWayPoint wayPoint: segment.getWayPoints()) {
+                        if (!wayPoint.isDeleted()) {
+                            Point pnt = Main.map.mapView.getPoint(wayPoint.getCoor().getEastNorth());
+                            g.drawOval(pnt.x - 2, pnt.y - 2, 4, 4);
+                        }
+                    }
+                }
+            }
+        }
+    }
+
+
+    public void reset(){
+        //TODO implement a reset
+    }
+
+
+    @Override
+    public void visitBoundingBox(BoundingXYVisitor v) {
+        // TODO Auto-generated method stub
+    }
+
+
+    /**
+     * convert a DataSet to GPX
+     *
+     * @param boolean anonTime If true set all time and date in GPX to 01/01/1970 00:00 ?
+     * @return GPXData
+     */
+    private GpxData toGpxData(boolean anonTime) {
+        return data.createGpxData();
+    }
+
+    //context item "Convert to GPX layer"
+    public class ConvertToGpxLayerAction extends AbstractAction {
+        public ConvertToGpxLayerAction() {
+            super(tr("Convert to GPX layer"), ImageProvider.get("converttogpx"));
+        }
+        public void actionPerformed(ActionEvent e) {
+            Main.main.addLayer(new GpxLayer(toGpxData(false), tr("Converted from: {0}", getName())));
+            Main.main.removeLayer(EditGpxLayer.this);
+            if(Main.map.mapMode instanceof EditGpxMode)
+                Main.map.selectSelectTool(false);
+        }
+    }
+
+    //context item "Convert to GPX layer with anonymised time"
+    public class ConvertToAnonTimeGpxLayerAction extends AbstractAction {
+        public ConvertToAnonTimeGpxLayerAction() {
+            super(tr("Convert to GPX layer with anonymised time"), ImageProvider.get("converttogpx"));
+        }
+        public void actionPerformed(ActionEvent e) {
+            Main.main.addLayer(new GpxLayer(toGpxData(true), tr("Converted from: {0}", getName())));
+            Main.main.removeLayer(EditGpxLayer.this);
+            if(Main.map.mapMode instanceof EditGpxMode)
+                Main.map.selectSelectTool(false);
+        }
+    }
 }
diff --git a/editgpx/src/org/openstreetmap/josm/plugins/editgpx/EditGpxMode.java b/editgpx/src/org/openstreetmap/josm/plugins/editgpx/EditGpxMode.java
index 42a8058..efd7183 100644
--- a/editgpx/src/org/openstreetmap/josm/plugins/editgpx/EditGpxMode.java
+++ b/editgpx/src/org/openstreetmap/josm/plugins/editgpx/EditGpxMode.java
@@ -28,153 +28,153 @@ import org.openstreetmap.josm.plugins.editgpx.data.EditGpxWayPoint;
 
 public class EditGpxMode extends MapMode implements LayerChangeListener {
 
-	private static final long serialVersionUID = 7940589057093872411L;
-	Point pointPressed;
-	MapFrame mapFrame;
-	Rectangle oldRect;
-	MapFrame frame;
-	EditGpxLayer currentEditLayer;
-
-	public EditGpxMode(MapFrame mapFrame, String name, String desc) {
-		super(name, "editgpx_mode.png", desc, mapFrame, Cursor.getPredefinedCursor(Cursor.CROSSHAIR_CURSOR));
-	}
-
-	@Override public void enterMode() {
-		super.enterMode();
-		Main.map.mapView.addMouseListener(this);
-		Main.map.mapView.addMouseMotionListener(this);
-		MapView.addLayerChangeListener(this);
-		updateLayer();
-	}
-
-	@Override public void exitMode() {
-		super.exitMode();
-		Main.map.mapView.removeMouseListener(this);
-		Main.map.mapView.removeMouseMotionListener(this);
-	}
-
-
-	@Override public void mousePressed(MouseEvent e) {
-		pointPressed = new Point(e.getPoint());
-	}
-
-
-	@Override public void mouseDragged(MouseEvent e) {
-		if ( (e.getModifiersEx() & InputEvent.BUTTON1_DOWN_MASK) ==  InputEvent.BUTTON1_DOWN_MASK) {
-			//if button1 is hold, draw the rectangle.
-			paintRect(pointPressed, e.getPoint());
-		}
-	}
-
-	@Override public void mouseReleased(MouseEvent e) {
-		if (e.getButton() != MouseEvent.BUTTON1) {
-			return;
-		}
-
-		Point pointReleased = e.getPoint();
-
-		Rectangle r = createRect(pointReleased, pointPressed);
-
-		//go through nodes and mark the ones in the selection rect as deleted
-		if (currentEditLayer != null) {
-			for (EditGpxTrack track: currentEditLayer.data.getTracks()) {
-				for (EditGpxTrackSegment segment: track.getSegments()) {
-					for (EditGpxWayPoint wayPoint: segment.getWayPoints()) {
-						Point p = Main.map.mapView.getPoint(wayPoint.getCoor().getEastNorth());
-						if (r.contains(p)) {
-							wayPoint.setDeleted(true);
-						}
-					}
-				}
-			}
-		}
-		oldRect = null;
-		Main.map.mapView.repaint();
-
-	}
-
-	/**
-	 * create rectangle out of two given corners
-	 */
-	public Rectangle createRect(Point p1, Point p2) {
-		int x,y,w,h;
-		if (p1.x == p2.x && p1.y == p2.y) {
-			//if p1 and p2 same points draw a small rectangle around them
-			x = p1.x -1;
-			y = p1.y -1;
-			w = 3;
-			h = 3;
-		} else {
-			if (p1.x < p2.x){
-				x = p1.x;
-				w = p2.x-p1.x;
-			} else {
-				x = p2.x;
-				w = p1.x-p2.x;
-			}
-			if (p1.y < p2.y) {
-				y = p1.y;
-				h = p2.y-p1.y;
-			} else {
-				y = p2.y;
-				h = p1.y-p2.y;
-			}
-		}
-		return new Rectangle(x,y,w,h);
-	}
-
-	/**
-	 * Draw a selection rectangle on screen.
-	 */
-	private void paintRect(Point p1, Point p2) {
-		Graphics g = frame.getGraphics();//Main.map.mapView.getGraphics();
-
-		Rectangle r = oldRect;
-		if (r != null) {
-			//overwrite old rct
-			g.setXORMode(Color.BLACK);
-			g.setColor(Color.WHITE);
-			g.drawRect(r.x,r.y,r.width,r.height);
-		}
-
-		g.setXORMode(Color.BLACK);
-		g.setColor(Color.WHITE);
-		r = createRect(p1,p2);
-		g.drawRect(r.x,r.y,r.width,r.height);
-		oldRect = r;
-	}
-
-
-	public void setFrame(MapFrame mapFrame) {
-		frame = mapFrame;
-	}
-
-	/**
-	 * create new layer, add listeners and try importing gpx data.
-	 */
-	private void updateLayer() {
-
-		List<EditGpxLayer> layers = Main.map.mapView.getLayersOfType(EditGpxLayer.class);
-		currentEditLayer = layers.isEmpty()?null:layers.get(0);
-
-		if(currentEditLayer == null) {
-			currentEditLayer = new EditGpxLayer(tr("EditGpx"), new EditGpxData());
-			Main.main.addLayer(currentEditLayer);
-			currentEditLayer.initializeImport();
-		}
-		Main.map.mapView.repaint();
-	}
-
-	public void activeLayerChange(Layer oldLayer, Layer newLayer) { }
-
-	public void layerAdded(Layer newLayer) { }
-
-	public void layerRemoved(Layer oldLayer) {
-		if (oldLayer instanceof EditGpxLayer) {
-			currentEditLayer = null;
-			if(Main.map.mapMode instanceof EditGpxMode)
-				Main.map.selectSelectTool(false);
-		}
-	}
+    private static final long serialVersionUID = 7940589057093872411L;
+    Point pointPressed;
+    MapFrame mapFrame;
+    Rectangle oldRect;
+    MapFrame frame;
+    EditGpxLayer currentEditLayer;
+
+    public EditGpxMode(MapFrame mapFrame, String name, String desc) {
+        super(name, "editgpx_mode.png", desc, mapFrame, Cursor.getPredefinedCursor(Cursor.CROSSHAIR_CURSOR));
+    }
+
+    @Override public void enterMode() {
+        super.enterMode();
+        Main.map.mapView.addMouseListener(this);
+        Main.map.mapView.addMouseMotionListener(this);
+        MapView.addLayerChangeListener(this);
+        updateLayer();
+    }
+
+    @Override public void exitMode() {
+        super.exitMode();
+        Main.map.mapView.removeMouseListener(this);
+        Main.map.mapView.removeMouseMotionListener(this);
+    }
+
+
+    @Override public void mousePressed(MouseEvent e) {
+        pointPressed = new Point(e.getPoint());
+    }
+
+
+    @Override public void mouseDragged(MouseEvent e) {
+        if ( (e.getModifiersEx() & InputEvent.BUTTON1_DOWN_MASK) ==  InputEvent.BUTTON1_DOWN_MASK) {
+            //if button1 is hold, draw the rectangle.
+            paintRect(pointPressed, e.getPoint());
+        }
+    }
+
+    @Override public void mouseReleased(MouseEvent e) {
+        if (e.getButton() != MouseEvent.BUTTON1) {
+            return;
+        }
+
+        Point pointReleased = e.getPoint();
+
+        Rectangle r = createRect(pointReleased, pointPressed);
+
+        //go through nodes and mark the ones in the selection rect as deleted
+        if (currentEditLayer != null) {
+            for (EditGpxTrack track: currentEditLayer.data.getTracks()) {
+                for (EditGpxTrackSegment segment: track.getSegments()) {
+                    for (EditGpxWayPoint wayPoint: segment.getWayPoints()) {
+                        Point p = Main.map.mapView.getPoint(wayPoint.getCoor().getEastNorth());
+                        if (r.contains(p)) {
+                            wayPoint.setDeleted(true);
+                        }
+                    }
+                }
+            }
+        }
+        oldRect = null;
+        Main.map.mapView.repaint();
+
+    }
+
+    /**
+     * create rectangle out of two given corners
+     */
+    public Rectangle createRect(Point p1, Point p2) {
+        int x,y,w,h;
+        if (p1.x == p2.x && p1.y == p2.y) {
+            //if p1 and p2 same points draw a small rectangle around them
+            x = p1.x -1;
+            y = p1.y -1;
+            w = 3;
+            h = 3;
+        } else {
+            if (p1.x < p2.x){
+                x = p1.x;
+                w = p2.x-p1.x;
+            } else {
+                x = p2.x;
+                w = p1.x-p2.x;
+            }
+            if (p1.y < p2.y) {
+                y = p1.y;
+                h = p2.y-p1.y;
+            } else {
+                y = p2.y;
+                h = p1.y-p2.y;
+            }
+        }
+        return new Rectangle(x,y,w,h);
+    }
+
+    /**
+     * Draw a selection rectangle on screen.
+     */
+    private void paintRect(Point p1, Point p2) {
+        Graphics g = frame.getGraphics();//Main.map.mapView.getGraphics();
+
+        Rectangle r = oldRect;
+        if (r != null) {
+            //overwrite old rct
+            g.setXORMode(Color.BLACK);
+            g.setColor(Color.WHITE);
+            g.drawRect(r.x,r.y,r.width,r.height);
+        }
+
+        g.setXORMode(Color.BLACK);
+        g.setColor(Color.WHITE);
+        r = createRect(p1,p2);
+        g.drawRect(r.x,r.y,r.width,r.height);
+        oldRect = r;
+    }
+
+
+    public void setFrame(MapFrame mapFrame) {
+        frame = mapFrame;
+    }
+
+    /**
+     * create new layer, add listeners and try importing gpx data.
+     */
+    private void updateLayer() {
+
+        List<EditGpxLayer> layers = Main.map.mapView.getLayersOfType(EditGpxLayer.class);
+        currentEditLayer = layers.isEmpty()?null:layers.get(0);
+
+        if(currentEditLayer == null) {
+            currentEditLayer = new EditGpxLayer(tr("EditGpx"), new EditGpxData());
+            Main.main.addLayer(currentEditLayer);
+            currentEditLayer.initializeImport();
+        }
+        Main.map.mapView.repaint();
+    }
+
+    public void activeLayerChange(Layer oldLayer, Layer newLayer) { }
+
+    public void layerAdded(Layer newLayer) { }
+
+    public void layerRemoved(Layer oldLayer) {
+        if (oldLayer instanceof EditGpxLayer) {
+            currentEditLayer = null;
+            if(Main.map.mapMode instanceof EditGpxMode)
+                Main.map.selectSelectTool(false);
+        }
+    }
 
 }
diff --git a/editgpx/src/org/openstreetmap/josm/plugins/editgpx/EditGpxPlugin.java b/editgpx/src/org/openstreetmap/josm/plugins/editgpx/EditGpxPlugin.java
index b33f5f5..3ab9e01 100644
--- a/editgpx/src/org/openstreetmap/josm/plugins/editgpx/EditGpxPlugin.java
+++ b/editgpx/src/org/openstreetmap/josm/plugins/editgpx/EditGpxPlugin.java
@@ -30,32 +30,32 @@ import org.openstreetmap.josm.plugins.PluginInformation;
  */
 public class EditGpxPlugin extends Plugin {
 
-	private IconToggleButton btn;
-	private EditGpxMode mode;
-
-	public EditGpxPlugin(PluginInformation info) {
-		super(info);
-		mode = new EditGpxMode(Main.map, "editgpx", tr("edit gpx tracks"));
-
-		btn = new IconToggleButton(mode);
-		btn.setVisible(true);
-	}
-
-	/**
-	 * initialize button. if button is pressed create new layer.
-	 */
-	@Override
-	public void mapFrameInitialized(MapFrame oldFrame, MapFrame newFrame) {
-		if(oldFrame == null && newFrame != null) {
-			mode.setFrame(newFrame);
-
-			if(Main.map != null)
-				Main.map.addMapMode(btn);
-		}
-	}
-
-	public static ImageIcon loadIcon(String name) {
-		URL url = EditGpxPlugin.class.getResource("/images/editgpx.png");
-		return new ImageIcon(url);
-	}
+    private IconToggleButton btn;
+    private EditGpxMode mode;
+
+    public EditGpxPlugin(PluginInformation info) {
+        super(info);
+        mode = new EditGpxMode(Main.map, "editgpx", tr("edit gpx tracks"));
+
+        btn = new IconToggleButton(mode);
+        btn.setVisible(true);
+    }
+
+    /**
+     * initialize button. if button is pressed create new layer.
+     */
+    @Override
+    public void mapFrameInitialized(MapFrame oldFrame, MapFrame newFrame) {
+        if(oldFrame == null && newFrame != null) {
+            mode.setFrame(newFrame);
+
+            if(Main.map != null)
+                Main.map.addMapMode(btn);
+        }
+    }
+
+    public static ImageIcon loadIcon(String name) {
+        URL url = EditGpxPlugin.class.getResource("/images/editgpx.png");
+        return new ImageIcon(url);
+    }
 }
diff --git a/editgpx/src/org/openstreetmap/josm/plugins/editgpx/GPXLayerImportAction.java b/editgpx/src/org/openstreetmap/josm/plugins/editgpx/GPXLayerImportAction.java
index 65d23d5..337d0e4 100644
--- a/editgpx/src/org/openstreetmap/josm/plugins/editgpx/GPXLayerImportAction.java
+++ b/editgpx/src/org/openstreetmap/josm/plugins/editgpx/GPXLayerImportAction.java
@@ -37,89 +37,89 @@ import org.openstreetmap.josm.tools.ImageProvider;
 class GPXLayerImportAction extends AbstractAction {
 
 
-	private static final long serialVersionUID = 5794897888911798168L;
-	private EditGpxData data;
-	public Object importing = new Object(); //used for synchronization
-
-	public GPXLayerImportAction(EditGpxData data) {
-		//TODO what is icon at the end?
-		super(tr("Import path from GPX layer"), ImageProvider.get("dialogs", "edit"));
-		this.data = data;
-	}
-
-	/**
-	 * shows a list of GPX layers. if user selects one the data from this layer is
-	 * imported.
-	 */
-	public void activateImport() {
-		Box panel = Box.createVerticalBox();
-		DefaultListModel dModel= new DefaultListModel();
-
-		final JList layerList = new JList(dModel);
-		Collection<Layer> data = Main.map.mapView.getAllLayers();
-		Layer lastLayer = null;
-		int layerCnt = 0;
-
-		for (Layer l : data){
-			if(l instanceof GpxLayer){
-				dModel.addElement(l);
-				lastLayer = l;
-				layerCnt++;
-			}
-		}
-		if(layerCnt == 1){
-			layerList.setSelectedValue(lastLayer, true);
-		}
-		if(layerCnt > 0){
-			layerList.setCellRenderer(new DefaultListCellRenderer(){
-				@Override public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) {
-					Layer layer = (Layer)value;
-					JLabel label = (JLabel)super.getListCellRendererComponent(list,
-							layer.getName(), index, isSelected, cellHasFocus);
-					Icon icon = layer.getIcon();
-					label.setIcon(icon);
-					label.setToolTipText(layer.getToolTipText());
-					return label;
-				}
-			});
-
-			JCheckBox dropFirst = new JCheckBox(tr("Drop existing path"));
-
-			panel.add(layerList);
-			panel.add(dropFirst);
-
-			final JOptionPane optionPane = new JOptionPane(panel, JOptionPane.QUESTION_MESSAGE, JOptionPane.OK_CANCEL_OPTION){
-				@Override public void selectInitialValue() {
-					layerList.requestFocusInWindow();
-				}
-			};
-			final JDialog dlg = optionPane.createDialog(Main.parent, tr("Import path from GPX layer"));
-			dlg.setVisible(true);
-
-			Object answer = optionPane.getValue();
-			if (answer == null || answer == JOptionPane.UNINITIALIZED_VALUE ||
-					(answer instanceof Integer && (Integer)answer != JOptionPane.OK_OPTION)) {
-				return;
-			}
-
-			GpxLayer gpx = (GpxLayer)layerList.getSelectedValue();
-
-			synchronized(importing) {
-				this.data.load(gpx.data, dropFirst.isSelected());
-			}
-			Main.map.mapView.repaint();
-
-		} else {
-			// no gps layer
-			JOptionPane.showMessageDialog(Main.parent,tr("No GPX data layer found."));
-		}
-	}
-
-	/**
-	 * called when pressing "Import.." from context menu of EditGpx layer
-	 *
-	 */
-	public void actionPerformed(ActionEvent arg0) {
-		activateImport();
-	}
+    private static final long serialVersionUID = 5794897888911798168L;
+    private EditGpxData data;
+    public Object importing = new Object(); //used for synchronization
+
+    public GPXLayerImportAction(EditGpxData data) {
+        //TODO what is icon at the end?
+        super(tr("Import path from GPX layer"), ImageProvider.get("dialogs", "edit"));
+        this.data = data;
+    }
+
+    /**
+     * shows a list of GPX layers. if user selects one the data from this layer is
+     * imported.
+     */
+    public void activateImport() {
+        Box panel = Box.createVerticalBox();
+        DefaultListModel dModel= new DefaultListModel();
+
+        final JList layerList = new JList(dModel);
+        Collection<Layer> data = Main.map.mapView.getAllLayers();
+        Layer lastLayer = null;
+        int layerCnt = 0;
+
+        for (Layer l : data){
+            if(l instanceof GpxLayer){
+                dModel.addElement(l);
+                lastLayer = l;
+                layerCnt++;
+            }
+        }
+        if(layerCnt == 1){
+            layerList.setSelectedValue(lastLayer, true);
+        }
+        if(layerCnt > 0){
+            layerList.setCellRenderer(new DefaultListCellRenderer(){
+                @Override public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) {
+                    Layer layer = (Layer)value;
+                    JLabel label = (JLabel)super.getListCellRendererComponent(list,
+                            layer.getName(), index, isSelected, cellHasFocus);
+                    Icon icon = layer.getIcon();
+                    label.setIcon(icon);
+                    label.setToolTipText(layer.getToolTipText());
+                    return label;
+                }
+            });
+
+            JCheckBox dropFirst = new JCheckBox(tr("Drop existing path"));
+
+            panel.add(layerList);
+            panel.add(dropFirst);
+
+            final JOptionPane optionPane = new JOptionPane(panel, JOptionPane.QUESTION_MESSAGE, JOptionPane.OK_CANCEL_OPTION){
+                @Override public void selectInitialValue() {
+                    layerList.requestFocusInWindow();
+                }
+            };
+            final JDialog dlg = optionPane.createDialog(Main.parent, tr("Import path from GPX layer"));
+            dlg.setVisible(true);
+
+            Object answer = optionPane.getValue();
+            if (answer == null || answer == JOptionPane.UNINITIALIZED_VALUE ||
+                    (answer instanceof Integer && (Integer)answer != JOptionPane.OK_OPTION)) {
+                return;
+            }
+
+            GpxLayer gpx = (GpxLayer)layerList.getSelectedValue();
+
+            synchronized(importing) {
+                this.data.load(gpx.data, dropFirst.isSelected());
+            }
+            Main.map.mapView.repaint();
+
+        } else {
+            // no gps layer
+            JOptionPane.showMessageDialog(Main.parent,tr("No GPX data layer found."));
+        }
+    }
+
+    /**
+     * called when pressing "Import.." from context menu of EditGpx layer
+     *
+     */
+    public void actionPerformed(ActionEvent arg0) {
+        activateImport();
+    }
 }
diff --git a/editgpx/src/org/openstreetmap/josm/plugins/editgpx/data/EditGpxData.java b/editgpx/src/org/openstreetmap/josm/plugins/editgpx/data/EditGpxData.java
index 2e4a394..3c89c5e 100644
--- a/editgpx/src/org/openstreetmap/josm/plugins/editgpx/data/EditGpxData.java
+++ b/editgpx/src/org/openstreetmap/josm/plugins/editgpx/data/EditGpxData.java
@@ -10,53 +10,53 @@ import org.openstreetmap.josm.data.gpx.WayPoint;
 
 public class EditGpxData {
 
-	private final List<EditGpxTrack> tracks = new ArrayList<EditGpxTrack>();
-	// Only copy of routes and waypoints to preserve all info when converting back to gpx track
-	private final List<GpxRoute> routes = new ArrayList<GpxRoute>();
-	private final List<WayPoint> waypoints = new ArrayList<WayPoint>();
-
-	public void load(GpxData data, boolean drop) {
-		if(drop)
-			tracks.clear();
-		for (GpxTrack track: data.tracks) {
-			tracks.add(new EditGpxTrack(track));
-		}
-		routes.clear();
-		routes.addAll(data.routes);
-		waypoints.clear();
-		waypoints.addAll(data.waypoints);
-	}
-
-	public boolean isEmpty() {
-		for (EditGpxTrack track: tracks) {
-			for (EditGpxTrackSegment segment: track.getSegments()) {
-				if (!segment.getWayPoints().isEmpty()) {
-					return false;
-				}
-			}
-		}
-		return true;
-	}
-
-	public List<EditGpxTrack> getTracks() {
-		return tracks;
-	}
-
-	public GpxData createGpxData() {
-		GpxData result = new GpxData();
-
-		for (EditGpxTrack track: tracks) {
-			if (!track.isDeleted()) {
-				GpxTrack newTrack = track.createGpxTrack();
-				if (!newTrack.getSegments().isEmpty()) {
-					result.tracks.add(newTrack);
-				}
-			}
-		}
-
-		result.routes.addAll(routes);
-		result.waypoints.addAll(waypoints);
-		return result;
-	}
+    private final List<EditGpxTrack> tracks = new ArrayList<EditGpxTrack>();
+    // Only copy of routes and waypoints to preserve all info when converting back to gpx track
+    private final List<GpxRoute> routes = new ArrayList<GpxRoute>();
+    private final List<WayPoint> waypoints = new ArrayList<WayPoint>();
+
+    public void load(GpxData data, boolean drop) {
+        if(drop)
+            tracks.clear();
+        for (GpxTrack track: data.tracks) {
+            tracks.add(new EditGpxTrack(track));
+        }
+        routes.clear();
+        routes.addAll(data.routes);
+        waypoints.clear();
+        waypoints.addAll(data.waypoints);
+    }
+
+    public boolean isEmpty() {
+        for (EditGpxTrack track: tracks) {
+            for (EditGpxTrackSegment segment: track.getSegments()) {
+                if (!segment.getWayPoints().isEmpty()) {
+                    return false;
+                }
+            }
+        }
+        return true;
+    }
+
+    public List<EditGpxTrack> getTracks() {
+        return tracks;
+    }
+
+    public GpxData createGpxData() {
+        GpxData result = new GpxData();
+
+        for (EditGpxTrack track: tracks) {
+            if (!track.isDeleted()) {
+                GpxTrack newTrack = track.createGpxTrack();
+                if (!newTrack.getSegments().isEmpty()) {
+                    result.tracks.add(newTrack);
+                }
+            }
+        }
+
+        result.routes.addAll(routes);
+        result.waypoints.addAll(waypoints);
+        return result;
+    }
 
 }
diff --git a/editgpx/src/org/openstreetmap/josm/plugins/editgpx/data/EditGpxTrack.java b/editgpx/src/org/openstreetmap/josm/plugins/editgpx/data/EditGpxTrack.java
index 9cf5a91..a539863 100644
--- a/editgpx/src/org/openstreetmap/josm/plugins/editgpx/data/EditGpxTrack.java
+++ b/editgpx/src/org/openstreetmap/josm/plugins/editgpx/data/EditGpxTrack.java
@@ -13,45 +13,45 @@ import org.openstreetmap.josm.data.gpx.WayPoint;
 
 public class EditGpxTrack {
 
-	private final List<EditGpxTrackSegment> segments = new ArrayList<EditGpxTrackSegment>();
-	private final Map<String, Object> attributes = new HashMap<String, Object>();
-	private boolean isDeleted;
-
-	public EditGpxTrack(GpxTrack track) {
-		attributes.putAll(track.getAttributes());
-		for (GpxTrackSegment segment: track.getSegments()) {
-			segments.add(new EditGpxTrackSegment(segment));
-		}
-	}
-
-	public List<EditGpxTrackSegment> getSegments() {
-		return segments;
-	}
-	public Map<String, Object> getAttributes() {
-		return attributes;
-	}
-
-	public GpxTrack createGpxTrack() {
-
-		Collection<Collection<WayPoint>> wayPoints = new ArrayList<Collection<WayPoint>>();
-
-		for (EditGpxTrackSegment segment: segments) {
-			if (!segment.isDeleted()) {
-				List<WayPoint> points = segment.getNonDeletedWaypoints();
-				if (!points.isEmpty()) {
-					wayPoints.add(points);
-				}
-			}
-		}
-
-		return new ImmutableGpxTrack(wayPoints, attributes);
-	}
-
-	public void setDeleted(boolean isDeleted) {
-		this.isDeleted = isDeleted;
-	}
-
-	public boolean isDeleted() {
-		return isDeleted;
-	}
+    private final List<EditGpxTrackSegment> segments = new ArrayList<EditGpxTrackSegment>();
+    private final Map<String, Object> attributes = new HashMap<String, Object>();
+    private boolean isDeleted;
+
+    public EditGpxTrack(GpxTrack track) {
+        attributes.putAll(track.getAttributes());
+        for (GpxTrackSegment segment: track.getSegments()) {
+            segments.add(new EditGpxTrackSegment(segment));
+        }
+    }
+
+    public List<EditGpxTrackSegment> getSegments() {
+        return segments;
+    }
+    public Map<String, Object> getAttributes() {
+        return attributes;
+    }
+
+    public GpxTrack createGpxTrack() {
+
+        Collection<Collection<WayPoint>> wayPoints = new ArrayList<Collection<WayPoint>>();
+
+        for (EditGpxTrackSegment segment: segments) {
+            if (!segment.isDeleted()) {
+                List<WayPoint> points = segment.getNonDeletedWaypoints();
+                if (!points.isEmpty()) {
+                    wayPoints.add(points);
+                }
+            }
+        }
+
+        return new ImmutableGpxTrack(wayPoints, attributes);
+    }
+
+    public void setDeleted(boolean isDeleted) {
+        this.isDeleted = isDeleted;
+    }
+
+    public boolean isDeleted() {
+        return isDeleted;
+    }
 }
diff --git a/editgpx/src/org/openstreetmap/josm/plugins/editgpx/data/EditGpxTrackSegment.java b/editgpx/src/org/openstreetmap/josm/plugins/editgpx/data/EditGpxTrackSegment.java
index f11f8b4..95c1e27 100644
--- a/editgpx/src/org/openstreetmap/josm/plugins/editgpx/data/EditGpxTrackSegment.java
+++ b/editgpx/src/org/openstreetmap/josm/plugins/editgpx/data/EditGpxTrackSegment.java
@@ -8,37 +8,37 @@ import org.openstreetmap.josm.data.gpx.WayPoint;
 
 public class EditGpxTrackSegment {
 
-	private final List<EditGpxWayPoint> wayPoints = new ArrayList<EditGpxWayPoint>();
-	private boolean deleted;
-
-	public EditGpxTrackSegment(GpxTrackSegment segment) {
-		for (WayPoint wayPoint: segment.getWayPoints()) {
-			wayPoints.add(new EditGpxWayPoint(wayPoint));
-		}
-	}
-
-	public List<EditGpxWayPoint> getWayPoints() {
-		return wayPoints;
-	}
-
-	public List<WayPoint> getNonDeletedWaypoints() {
-		List<WayPoint> result = new ArrayList<WayPoint>();
-
-		for (EditGpxWayPoint wp: wayPoints) {
-			if (!wp.isDeleted()) {
-				result.add(wp.createWayPoint());
-			}
-		}
-
-		return result;
-	}
-
-	public void setDeleted(boolean deleted) {
-		this.deleted = deleted;
-	}
-
-	public boolean isDeleted() {
-		return deleted;
-	}
+    private final List<EditGpxWayPoint> wayPoints = new ArrayList<EditGpxWayPoint>();
+    private boolean deleted;
+
+    public EditGpxTrackSegment(GpxTrackSegment segment) {
+        for (WayPoint wayPoint: segment.getWayPoints()) {
+            wayPoints.add(new EditGpxWayPoint(wayPoint));
+        }
+    }
+
+    public List<EditGpxWayPoint> getWayPoints() {
+        return wayPoints;
+    }
+
+    public List<WayPoint> getNonDeletedWaypoints() {
+        List<WayPoint> result = new ArrayList<WayPoint>();
+
+        for (EditGpxWayPoint wp: wayPoints) {
+            if (!wp.isDeleted()) {
+                result.add(wp.createWayPoint());
+            }
+        }
+
+        return result;
+    }
+
+    public void setDeleted(boolean deleted) {
+        this.deleted = deleted;
+    }
+
+    public boolean isDeleted() {
+        return deleted;
+    }
 
 }
diff --git a/editgpx/src/org/openstreetmap/josm/plugins/editgpx/data/EditGpxWayPoint.java b/editgpx/src/org/openstreetmap/josm/plugins/editgpx/data/EditGpxWayPoint.java
index f0a5a42..255a48b 100644
--- a/editgpx/src/org/openstreetmap/josm/plugins/editgpx/data/EditGpxWayPoint.java
+++ b/editgpx/src/org/openstreetmap/josm/plugins/editgpx/data/EditGpxWayPoint.java
@@ -7,33 +7,33 @@ import org.openstreetmap.josm.data.coor.CachedLatLon;
 import org.openstreetmap.josm.data.gpx.WayPoint;
 
 public class EditGpxWayPoint {
-	private final double time;
-	private final CachedLatLon coor;
-	private boolean deleted;
-	private Map<String, Object> attributes;
-
-	public EditGpxWayPoint(WayPoint wayPoint) {
-		this.time = wayPoint.time;
-		this.coor = new CachedLatLon(wayPoint.getCoor());
-		this.attributes = new HashMap<String, Object>(wayPoint.attr);
-	}
-
-	public WayPoint createWayPoint() {
-		WayPoint result = new WayPoint(getCoor());
-		result.time = time;
-		result.attr = attributes;
-		return result;
-	}
-
-	public void setDeleted(boolean deleted) {
-		this.deleted = deleted;
-	}
-
-	public boolean isDeleted() {
-		return deleted;
-	}
-
-	public CachedLatLon getCoor() {
-		return coor;
-	}
+    private final double time;
+    private final CachedLatLon coor;
+    private boolean deleted;
+    private Map<String, Object> attributes;
+
+    public EditGpxWayPoint(WayPoint wayPoint) {
+        this.time = wayPoint.time;
+        this.coor = new CachedLatLon(wayPoint.getCoor());
+        this.attributes = new HashMap<String, Object>(wayPoint.attr);
+    }
+
+    public WayPoint createWayPoint() {
+        WayPoint result = new WayPoint(getCoor());
+        result.time = time;
+        result.attr = attributes;
+        return result;
+    }
+
+    public void setDeleted(boolean deleted) {
+        this.deleted = deleted;
+    }
+
+    public boolean isDeleted() {
+        return deleted;
+    }
+
+    public CachedLatLon getCoor() {
+        return coor;
+    }
 }
diff --git a/lakewalker/src/org/openstreetmap/josm/plugins/lakewalker/BooleanConfigurer.java b/lakewalker/src/org/openstreetmap/josm/plugins/lakewalker/BooleanConfigurer.java
index cdf5b28..cde5e24 100644
--- a/lakewalker/src/org/openstreetmap/josm/plugins/lakewalker/BooleanConfigurer.java
+++ b/lakewalker/src/org/openstreetmap/josm/plugins/lakewalker/BooleanConfigurer.java
@@ -22,70 +22,70 @@ package org.openstreetmap.josm.plugins.lakewalker;
  * Configurer for Boolean values
  */
 public class BooleanConfigurer extends Configurer {
-	private javax.swing.JCheckBox box;
+    private javax.swing.JCheckBox box;
 
-	public BooleanConfigurer() {
-		this(false);
-	}
+    public BooleanConfigurer() {
+        this(false);
+    }
 
-	public BooleanConfigurer(boolean val) {
-		this(null, "", val);
-	}
+    public BooleanConfigurer(boolean val) {
+        this(null, "", val);
+    }
 
-	public BooleanConfigurer(String key, String name, Boolean val) {
-		super(key, name, val);
-	}
+    public BooleanConfigurer(String key, String name, Boolean val) {
+        super(key, name, val);
+    }
 
-	public BooleanConfigurer(String key, String name, boolean val) {
-		super(key, name, val ? Boolean.TRUE : Boolean.FALSE);
-	}
+    public BooleanConfigurer(String key, String name, boolean val) {
+        super(key, name, val ? Boolean.TRUE : Boolean.FALSE);
+    }
 
-	public BooleanConfigurer(String key, String name) {
-		this(key, name, Boolean.FALSE);
-	}
+    public BooleanConfigurer(String key, String name) {
+        this(key, name, Boolean.FALSE);
+    }
 
-	@Override
-	public String getValueString() {
-		return booleanValue().toString();
-	}
+    @Override
+    public String getValueString() {
+        return booleanValue().toString();
+    }
 
-	@Override
-	public void setValue(Object o) {
-		super.setValue(o);
-		if (box != null
-				&& !o.equals(box.isSelected())) {
-			box.setSelected(booleanValue().booleanValue());
-		}
-	}
+    @Override
+    public void setValue(Object o) {
+        super.setValue(o);
+        if (box != null
+                && !o.equals(box.isSelected())) {
+            box.setSelected(booleanValue().booleanValue());
+        }
+    }
 
-	@Override
-	public void setValue(String s) {
-		setValue(Boolean.valueOf(s));
-	}
+    @Override
+    public void setValue(String s) {
+        setValue(Boolean.valueOf(s));
+    }
 
-	@Override
-	public void setName(String s) {
-		super.setName(s);
-		if (box != null) {
-			box.setText(s);
-		}
-	}
+    @Override
+    public void setName(String s) {
+        super.setName(s);
+        if (box != null) {
+            box.setText(s);
+        }
+    }
 
-	@Override
-	public java.awt.Component getControls() {
-		if (box == null) {
-			box = new javax.swing.JCheckBox(getName());
-			box.setSelected(booleanValue().booleanValue());
-			box.addItemListener(new java.awt.event.ItemListener() {
-				public void itemStateChanged(java.awt.event.ItemEvent e) {
-					setValue(box.isSelected());
-				}
-			});
-		}
-		return box;
-	}
+    @Override
+    public java.awt.Component getControls() {
+        if (box == null) {
+            box = new javax.swing.JCheckBox(getName());
+            box.setSelected(booleanValue().booleanValue());
+            box.addItemListener(new java.awt.event.ItemListener() {
+                public void itemStateChanged(java.awt.event.ItemEvent e) {
+                    setValue(box.isSelected());
+                }
+            });
+        }
+        return box;
+    }
 
-	public Boolean booleanValue() {
-		return (Boolean) value;
-	}
+    public Boolean booleanValue() {
+        return (Boolean) value;
+    }
 }
diff --git a/lakewalker/src/org/openstreetmap/josm/plugins/lakewalker/Configurer.java b/lakewalker/src/org/openstreetmap/josm/plugins/lakewalker/Configurer.java
index 8cdd72e..6e5f3da 100644
--- a/lakewalker/src/org/openstreetmap/josm/plugins/lakewalker/Configurer.java
+++ b/lakewalker/src/org/openstreetmap/josm/plugins/lakewalker/Configurer.java
@@ -13,7 +13,7 @@
  * Library General Public License for more details.
  *
  * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, copies are available 
+ * License along with this library; if not, copies are available
  * at http://www.opensource.org.
  */
 package org.openstreetmap.josm.plugins.lakewalker;
@@ -138,7 +138,7 @@ public abstract class Configurer {
   public void addPropertyChangeListener(java.beans.PropertyChangeListener l) {
     changeSupport.addPropertyChangeListener(l);
   }
-  
+
   public void removePropertyChangeListener(PropertyChangeListener l) {
     changeSupport.removePropertyChangeListener(l);
   }
diff --git a/lakewalker/src/org/openstreetmap/josm/plugins/lakewalker/DoubleConfigurer.java b/lakewalker/src/org/openstreetmap/josm/plugins/lakewalker/DoubleConfigurer.java
index 1fbbac7..329cfed 100644
--- a/lakewalker/src/org/openstreetmap/josm/plugins/lakewalker/DoubleConfigurer.java
+++ b/lakewalker/src/org/openstreetmap/josm/plugins/lakewalker/DoubleConfigurer.java
@@ -36,7 +36,7 @@ public class DoubleConfigurer extends StringConfigurer {
     }
 
     @Override
-	public void setValue(String s) {
+    public void setValue(String s) {
         Double d = null;
         try {
             d = Double.valueOf(s);
@@ -49,7 +49,7 @@ public class DoubleConfigurer extends StringConfigurer {
     }
 
     @Override
-	public void setValue(Object o) {
+    public void setValue(Object o) {
         if (!noUpdate && nameField != null && o != null) {
             nameField.setText(o.toString());
         }
@@ -57,7 +57,7 @@ public class DoubleConfigurer extends StringConfigurer {
     }
 
     @Override
-	public String getValueString() {
+    public String getValueString() {
         if (value == null || value.equals("")) {
             return null;
         }
diff --git a/lakewalker/src/org/openstreetmap/josm/plugins/lakewalker/IntConfigurer.java b/lakewalker/src/org/openstreetmap/josm/plugins/lakewalker/IntConfigurer.java
index ea87299..4ff1cbd 100644
--- a/lakewalker/src/org/openstreetmap/josm/plugins/lakewalker/IntConfigurer.java
+++ b/lakewalker/src/org/openstreetmap/josm/plugins/lakewalker/IntConfigurer.java
@@ -23,54 +23,54 @@ package org.openstreetmap.josm.plugins.lakewalker;
  */
 public class IntConfigurer extends StringConfigurer {
 
-	public IntConfigurer() {
-		super();
-	}
+    public IntConfigurer() {
+        super();
+    }
 
-	public IntConfigurer(String key, String name) {
-		this(key, name, 0);
-	}
+    public IntConfigurer(String key, String name) {
+        this(key, name, 0);
+    }
 
-	public IntConfigurer(String key, String name, Integer val) {
-		super(key, name);
-		if (val != null) {
-			setValue(val);
-		}
-	}
+    public IntConfigurer(String key, String name, Integer val) {
+        super(key, name);
+        if (val != null) {
+            setValue(val);
+        }
+    }
 
-	@Override
-	public void setValue(String s) {
-		Integer i = null;
-		try {
-			i = Integer.valueOf(s);
-		}
-		catch (NumberFormatException e) {
-			i = null;
-		}
-		if (i != null) {
-			setValue(i);
-		}
-	}
+    @Override
+    public void setValue(String s) {
+        Integer i = null;
+        try {
+            i = Integer.valueOf(s);
+        }
+        catch (NumberFormatException e) {
+            i = null;
+        }
+        if (i != null) {
+            setValue(i);
+        }
+    }
 
-	public int getIntValue(int defaultValue) {
-		if (getValue() instanceof Integer) {
-			return ((Integer)getValue()).intValue();
-		}
-		else {
-			return defaultValue;
-		}
-	}
+    public int getIntValue(int defaultValue) {
+        if (getValue() instanceof Integer) {
+            return ((Integer)getValue()).intValue();
+        }
+        else {
+            return defaultValue;
+        }
+    }
 
-	@Override
-	public void setValue(Object o) {
-		if (!noUpdate && nameField != null && o != null) {
-			nameField.setText(o.toString());
-		}
-		super.setValue(o);
-	}
+    @Override
+    public void setValue(Object o) {
+        if (!noUpdate && nameField != null && o != null) {
+            nameField.setText(o.toString());
+        }
+        super.setValue(o);
+    }
 
-	@Override
-	public String getValueString() {
-		return value == null ? null : value.toString();
-	}
+    @Override
+    public String getValueString() {
+        return value == null ? null : value.toString();
+    }
 }
diff --git a/lakewalker/src/org/openstreetmap/josm/plugins/lakewalker/Lakewalker.java b/lakewalker/src/org/openstreetmap/josm/plugins/lakewalker/Lakewalker.java
index 756521b..6937a13 100644
--- a/lakewalker/src/org/openstreetmap/josm/plugins/lakewalker/Lakewalker.java
+++ b/lakewalker/src/org/openstreetmap/josm/plugins/lakewalker/Lakewalker.java
@@ -83,130 +83,130 @@ public class Lakewalker {
      */
     public ArrayList<double[]> trace(double lat, double lon, double tl_lon, double br_lon, double tl_lat, double br_lat, ProgressMonitor progressMonitor) throws LakewalkerException {
 
-    	progressMonitor.beginTask(null);
+        progressMonitor.beginTask(null);
 
-    	try {
+        try {
 
-    		LakewalkerWMS wms = new LakewalkerWMS(this.resolution, this.tilesize, this.wmslayer, this.workingdir);
-    		LakewalkerBBox bbox = new LakewalkerBBox(tl_lat,tl_lon,br_lat,br_lon);
+            LakewalkerWMS wms = new LakewalkerWMS(this.resolution, this.tilesize, this.wmslayer, this.workingdir);
+            LakewalkerBBox bbox = new LakewalkerBBox(tl_lat,tl_lon,br_lat,br_lon);
 
-    		Boolean detect_loop = false;
+            Boolean detect_loop = false;
 
-    		ArrayList<double[]> nodelist = new ArrayList<double[]>();
+            ArrayList<double[]> nodelist = new ArrayList<double[]>();
 
-    		int[] xy = geo_to_xy(lat,lon,this.resolution);
+            int[] xy = geo_to_xy(lat,lon,this.resolution);
 
-    		if(!bbox.contains(lat, lon)){
-    			throw new LakewalkerException(tr("The starting location was not within the bbox"));
-    		}
-
-    		int v;
+            if(!bbox.contains(lat, lon)){
+                throw new LakewalkerException(tr("The starting location was not within the bbox"));
+            }
 
-    		progressMonitor.indeterminateSubTask(tr("Looking for shoreline..."));
+            int v;
 
-    		while(true){
-    			double[] geo = xy_to_geo(xy[0],xy[1],this.resolution);
-    			if(bbox.contains(geo[0],geo[1])==false){
-    				break;
-    			}
+            progressMonitor.indeterminateSubTask(tr("Looking for shoreline..."));
 
-    			v = wms.getPixel(xy[0], xy[1], progressMonitor.createSubTaskMonitor(0, false));
-    			if(v > this.threshold){
-    				break;
-    			}
+            while(true){
+                double[] geo = xy_to_geo(xy[0],xy[1],this.resolution);
+                if(bbox.contains(geo[0],geo[1])==false){
+                    break;
+                }
 
-    			int delta_lat = this.dirslat[getDirectionIndex(this.startdir)];
-    			int delta_lon = this.dirslon[getDirectionIndex(this.startdir)];
+                v = wms.getPixel(xy[0], xy[1], progressMonitor.createSubTaskMonitor(0, false));
+                if(v > this.threshold){
+                    break;
+                }
 
-    			xy[0] = xy[0]+delta_lon;
-    			xy[1] = xy[1]+delta_lat;
+                int delta_lat = this.dirslat[getDirectionIndex(this.startdir)];
+                int delta_lon = this.dirslon[getDirectionIndex(this.startdir)];
 
-    		}
+                xy[0] = xy[0]+delta_lon;
+                xy[1] = xy[1]+delta_lat;
 
-    		int[] startxy = new int[] {xy[0], xy[1]};
-    		double[] startgeo = xy_to_geo(xy[0],xy[1],this.resolution);
+            }
 
-    		//System.out.printf("Found shore at lat %.4f lon %.4f\n",lat,lon);
+            int[] startxy = new int[] {xy[0], xy[1]};
+            double[] startgeo = xy_to_geo(xy[0],xy[1],this.resolution);
 
-    		int last_dir = this.getDirectionIndex(this.startdir);
+            //System.out.printf("Found shore at lat %.4f lon %.4f\n",lat,lon);
 
-    		for(int i = 0; i < this.maxnode; i++){
+            int last_dir = this.getDirectionIndex(this.startdir);
 
-    			// Print a counter
-    			if(i % 250 == 0){
-    				progressMonitor.indeterminateSubTask(tr("{0} nodes so far...",i));
-    				//System.out.println(i+" nodes so far...");
-    			}
+            for(int i = 0; i < this.maxnode; i++){
 
-    			// Some variables we need
-    			int d;
-    			int test_x=0;
-    			int test_y=0;
-    			int new_dir = 0;
+                // Print a counter
+                if(i % 250 == 0){
+                    progressMonitor.indeterminateSubTask(tr("{0} nodes so far...",i));
+                    //System.out.println(i+" nodes so far...");
+                }
 
-    			// Loop through all the directions we can go
-    			for(d = 1; d <= this.dirslat.length; d++){
+                // Some variables we need
+                int d;
+                int test_x=0;
+                int test_y=0;
+                int new_dir = 0;
 
-    				// Decide which direction we want to look at from this pixel
-    				new_dir = (last_dir + d + 4) % 8;
+                // Loop through all the directions we can go
+                for(d = 1; d <= this.dirslat.length; d++){
 
-    				test_x = xy[0] + this.dirslon[new_dir];
-    				test_y = xy[1] + this.dirslat[new_dir];
+                    // Decide which direction we want to look at from this pixel
+                    new_dir = (last_dir + d + 4) % 8;
 
-    				double[] geo = xy_to_geo(test_x,test_y,this.resolution);
+                    test_x = xy[0] + this.dirslon[new_dir];
+                    test_y = xy[1] + this.dirslat[new_dir];
 
-    				if(!bbox.contains(geo[0], geo[1])){
-    					System.out.println("Outside bbox");
-    					break;
-    				}
+                    double[] geo = xy_to_geo(test_x,test_y,this.resolution);
 
-    				v = wms.getPixel(test_x, test_y, progressMonitor.createSubTaskMonitor(0, false));
-    				if(v > this.threshold){
-    					break;
-    				}
+                    if(!bbox.contains(geo[0], geo[1])){
+                        System.out.println("Outside bbox");
+                        break;
+                    }
 
-    				if(d == this.dirslat.length-1){
-    					System.out.println("Got stuck");
-    					break;
-    				}
-    			}
+                    v = wms.getPixel(test_x, test_y, progressMonitor.createSubTaskMonitor(0, false));
+                    if(v > this.threshold){
+                        break;
+                    }
 
-    			// Remember this direction
-    			last_dir = new_dir;
+                    if(d == this.dirslat.length-1){
+                        System.out.println("Got stuck");
+                        break;
+                    }
+                }
 
-    			// Set the pixel we found as current
-    			xy[0] = test_x;
-    			xy[1] = test_y;
+                // Remember this direction
+                last_dir = new_dir;
 
-    			// Break the loop if we managed to get back to our starting point
-    			if(xy[0] == startxy[0] && xy[1] == startxy[1]){
-    				break;
-    			}
+                // Set the pixel we found as current
+                xy[0] = test_x;
+                xy[1] = test_y;
 
-    			// Store this node
-    			double[] geo = xy_to_geo(xy[0],xy[1],this.resolution);
-    			nodelist.add(geo);
-    			//System.out.println("Adding node at "+xy[0]+","+xy[1]+" ("+geo[1]+","+geo[0]+")");
+                // Break the loop if we managed to get back to our starting point
+                if(xy[0] == startxy[0] && xy[1] == startxy[1]){
+                    break;
+                }
 
-    			// Check if we got stuck in a loop
-    			double start_proximity = Math.pow((geo[0] - startgeo[0]),2) + Math.pow((geo[1] - startgeo[1]),2);
+                // Store this node
+                double[] geo = xy_to_geo(xy[0],xy[1],this.resolution);
+                nodelist.add(geo);
+                //System.out.println("Adding node at "+xy[0]+","+xy[1]+" ("+geo[1]+","+geo[0]+")");
+
+                // Check if we got stuck in a loop
+                double start_proximity = Math.pow((geo[0] - startgeo[0]),2) + Math.pow((geo[1] - startgeo[1]),2);
+
+                if(detect_loop){
+                    if(start_proximity < Math.pow(start_radius_small,2)){
+                        System.out.println("Detected loop");
+                        break;
+                    }
+                }else{
+                    if(start_proximity > Math.pow(start_radius_big,2)){
+                        detect_loop = true;
+                    }
+                }
+            }
 
-    			if(detect_loop){
-    				if(start_proximity < Math.pow(start_radius_small,2)){
-    					System.out.println("Detected loop");
-    					break;
-    				}
-    			}else{
-    				if(start_proximity > Math.pow(start_radius_big,2)){
-    					detect_loop = true;
-    				}
-    			}
-    		}
-
-    		return nodelist;
-    	} finally {
-    		progressMonitor.finishTask();
-    	}
+            return nodelist;
+        } finally {
+            progressMonitor.finishTask();
+        }
     }
 
     /**
diff --git a/lakewalker/src/org/openstreetmap/josm/plugins/lakewalker/LakewalkerAction.java b/lakewalker/src/org/openstreetmap/josm/plugins/lakewalker/LakewalkerAction.java
index d2eb2e9..52a1d75 100644
--- a/lakewalker/src/org/openstreetmap/josm/plugins/lakewalker/LakewalkerAction.java
+++ b/lakewalker/src/org/openstreetmap/josm/plugins/lakewalker/LakewalkerAction.java
@@ -154,9 +154,9 @@ class LakewalkerAction extends JosmAction implements MouseListener {
                 @Override protected void finish() {
                 }
 
-				@Override protected void cancel() {
-					LakewalkerAction.this.cancel();
-				}
+                @Override protected void cancel() {
+                    LakewalkerAction.this.cancel();
+                }
             };
             Thread executeThread = new Thread(lakewalkerTask);
             executeThread.start();
@@ -246,7 +246,7 @@ class LakewalkerAction extends JosmAction implements MouseListener {
                     commands.add(new AddCommand(n));
 
                 } catch (Exception ex) {
-                	ex.printStackTrace();
+                    ex.printStackTrace();
                 }
 
                 way.addNode(n);
diff --git a/lakewalker/src/org/openstreetmap/josm/plugins/lakewalker/LakewalkerException.java b/lakewalker/src/org/openstreetmap/josm/plugins/lakewalker/LakewalkerException.java
index 5c6789e..6f4bb08 100644
--- a/lakewalker/src/org/openstreetmap/josm/plugins/lakewalker/LakewalkerException.java
+++ b/lakewalker/src/org/openstreetmap/josm/plugins/lakewalker/LakewalkerException.java
@@ -4,7 +4,7 @@ import static org.openstreetmap.josm.tools.I18n.tr;
 
 class LakewalkerException extends Exception {
     public LakewalkerException(){
-    	super(tr("An unknown error has occurred"));
+        super(tr("An unknown error has occurred"));
     }
 
     public LakewalkerException(String err){
diff --git a/lakewalker/src/org/openstreetmap/josm/plugins/lakewalker/LakewalkerPlugin.java b/lakewalker/src/org/openstreetmap/josm/plugins/lakewalker/LakewalkerPlugin.java
index 590f596..4983ae8 100644
--- a/lakewalker/src/org/openstreetmap/josm/plugins/lakewalker/LakewalkerPlugin.java
+++ b/lakewalker/src/org/openstreetmap/josm/plugins/lakewalker/LakewalkerPlugin.java
@@ -14,15 +14,15 @@ import org.openstreetmap.josm.plugins.PluginInformation;
  * @author Brent Easton
  */
 public class LakewalkerPlugin extends Plugin {
-	public LakewalkerPlugin(PluginInformation info) {
-		super(info);
-		MainMenu.add(Main.main.menu.toolsMenu, new LakewalkerAction(tr("Lake Walker")));
-	}
+    public LakewalkerPlugin(PluginInformation info) {
+        super(info);
+        MainMenu.add(Main.main.menu.toolsMenu, new LakewalkerAction(tr("Lake Walker")));
+    }
 
-	@Override
-	public PreferenceSetting getPreferenceSetting()
-	{
-		return new LakewalkerPreferences();
-	}
+    @Override
+    public PreferenceSetting getPreferenceSetting()
+    {
+        return new LakewalkerPreferences();
+    }
 
 }
diff --git a/lakewalker/src/org/openstreetmap/josm/plugins/lakewalker/LakewalkerWMS.java b/lakewalker/src/org/openstreetmap/josm/plugins/lakewalker/LakewalkerWMS.java
index 60a5dd5..2f97a2e 100644
--- a/lakewalker/src/org/openstreetmap/josm/plugins/lakewalker/LakewalkerWMS.java
+++ b/lakewalker/src/org/openstreetmap/josm/plugins/lakewalker/LakewalkerWMS.java
@@ -47,116 +47,116 @@ public class LakewalkerWMS {
     }
 
     public BufferedImage getTile(int x, int y, ProgressMonitor progressMonitor) throws LakewalkerException {
-    	progressMonitor.beginTask(tr("Downloading image tile..."));
-    	try {
-    		String layer = "global_mosaic_base";
-
-    		int[] bottom_left_xy = new int[2];
-    		bottom_left_xy[0] = floor(x,this.tilesize);
-    		bottom_left_xy[1] = floor(y,this.tilesize);
-
-    		int[] top_right_xy = new int[2];
-    		top_right_xy[0] = bottom_left_xy[0] + this.tilesize;
-    		top_right_xy[1] = bottom_left_xy[1] + this.tilesize;
-
-    		double[] topright_geo = xy_to_geo(top_right_xy[0],top_right_xy[1],this.resolution);
-    		double[] bottomleft_geo = xy_to_geo(bottom_left_xy[0],bottom_left_xy[1],this.resolution);
-
-    		String filename = this.wmslayer+"/landsat_"+this.resolution+"_"+this.tilesize+
-    		"_xy_"+bottom_left_xy[0]+"_"+bottom_left_xy[1]+".png";
-
-    		// The WMS server only understands decimal points using periods, so we need
-    		// to convert to a locale that uses that to build the proper URL
-    		NumberFormat nf = NumberFormat.getInstance(Locale.ENGLISH);
-    		DecimalFormat df = (DecimalFormat)nf;
-    		df.applyLocalizedPattern("0.000000");
-
-    		String urlloc = "http://onearth.jpl.nasa.gov/wms.cgi?request=GetMap&layers="+layer+
-    		"&styles="+wmslayer+"&srs=EPSG:4326&format=image/png"+
-    		"&bbox="+df.format(bottomleft_geo[1])+","+df.format(bottomleft_geo[0])+
-    		","+df.format(topright_geo[1])+","+df.format(topright_geo[0])+
-    		"&width="+this.tilesize+"&height="+this.tilesize;
-
-    		File file = new File(this.working_dir,filename);
-
-    		// Calculate the hashmap key
-    		String hashkey = Integer.toString(bottom_left_xy[0])+":"+Integer.toString(bottom_left_xy[1]);
-
-    		// See if this image is already loaded
-    		if(this.image != null){
-    			if(this.imagex != bottom_left_xy[0] || this.imagey != bottom_left_xy[1]){
-
-    				// Check if this image exists in the hashmap
-    				if(this.imageindex.containsKey(hashkey)){
-    					// Store which image we have
-    					this.imagex = bottom_left_xy[0];
-    					this.imagey = bottom_left_xy[1];
-
-    					// Retrieve from cache
-    					this.image = this.images.get(this.imageindex.get(hashkey));
-    					return this.image;
-    				} else {
-    					this.image = null;
-    				}
-    			} else {
-    				return this.image;
-    			}
-    		}
-
-    		try {
-    			System.out.println("Looking for image in disk cache: "+filename);
-
-    			// Read from a file
-    			this.image = ImageIO.read(file);
-
-    			this.images.add(this.image);
-    			this.imageindex.put(hashkey,this.images.size()-1);
-
-    		} catch(FileNotFoundException e){
-    			System.out.println("Could not find cached image, downloading.");
-    		} catch(IOException e){
-    			System.out.println(e.getMessage());
-    		} catch(Exception e){
-    			System.out.println(e.getMessage());
-    		}
-
-    		if(this.image == null){
-    			/**
-    			 * Try downloading the image
-    			 */
-    			try {
-    				System.out.println("Downloading from "+urlloc);
-
-    				// Read from a URL
-    				URL url = new URL(urlloc);
-    				this.image = ImageIO.read(url); // this can return null!
-    			} catch(MalformedURLException e){
-    				System.out.println(e.getMessage());
-    			} catch(IOException e){
-    				System.out.println(e.getMessage());
-    			} catch(Exception e){
-    				System.out.println(e.getMessage());
-    			}
-
-    			if (this.image != null) {
-    				this.images.add(this.image);
-    				this.imageindex.put(hashkey,this.images.size()-1);
-
-    				this.saveimage(file,this.image);
-    			}
-    		}
-
-    		this.imagex = bottom_left_xy[0];
-    		this.imagey = bottom_left_xy[1];
-
-    		if(this.image == null){
-    			throw new LakewalkerException(tr("Could not acquire image"));
-    		}
-
-    		return this.image;
-    	} finally {
-    		progressMonitor.finishTask();
-    	}
+        progressMonitor.beginTask(tr("Downloading image tile..."));
+        try {
+            String layer = "global_mosaic_base";
+
+            int[] bottom_left_xy = new int[2];
+            bottom_left_xy[0] = floor(x,this.tilesize);
+            bottom_left_xy[1] = floor(y,this.tilesize);
+
+            int[] top_right_xy = new int[2];
+            top_right_xy[0] = bottom_left_xy[0] + this.tilesize;
+            top_right_xy[1] = bottom_left_xy[1] + this.tilesize;
+
+            double[] topright_geo = xy_to_geo(top_right_xy[0],top_right_xy[1],this.resolution);
+            double[] bottomleft_geo = xy_to_geo(bottom_left_xy[0],bottom_left_xy[1],this.resolution);
+
+            String filename = this.wmslayer+"/landsat_"+this.resolution+"_"+this.tilesize+
+            "_xy_"+bottom_left_xy[0]+"_"+bottom_left_xy[1]+".png";
+
+            // The WMS server only understands decimal points using periods, so we need
+            // to convert to a locale that uses that to build the proper URL
+            NumberFormat nf = NumberFormat.getInstance(Locale.ENGLISH);
+            DecimalFormat df = (DecimalFormat)nf;
+            df.applyLocalizedPattern("0.000000");
+
+            String urlloc = "http://onearth.jpl.nasa.gov/wms.cgi?request=GetMap&layers="+layer+
+            "&styles="+wmslayer+"&srs=EPSG:4326&format=image/png"+
+            "&bbox="+df.format(bottomleft_geo[1])+","+df.format(bottomleft_geo[0])+
+            ","+df.format(topright_geo[1])+","+df.format(topright_geo[0])+
+            "&width="+this.tilesize+"&height="+this.tilesize;
+
+            File file = new File(this.working_dir,filename);
+
+            // Calculate the hashmap key
+            String hashkey = Integer.toString(bottom_left_xy[0])+":"+Integer.toString(bottom_left_xy[1]);
+
+            // See if this image is already loaded
+            if(this.image != null){
+                if(this.imagex != bottom_left_xy[0] || this.imagey != bottom_left_xy[1]){
+
+                    // Check if this image exists in the hashmap
+                    if(this.imageindex.containsKey(hashkey)){
+                        // Store which image we have
+                        this.imagex = bottom_left_xy[0];
+                        this.imagey = bottom_left_xy[1];
+
+                        // Retrieve from cache
+                        this.image = this.images.get(this.imageindex.get(hashkey));
+                        return this.image;
+                    } else {
+                        this.image = null;
+                    }
+                } else {
+                    return this.image;
+                }
+            }
+
+            try {
+                System.out.println("Looking for image in disk cache: "+filename);
+
+                // Read from a file
+                this.image = ImageIO.read(file);
+
+                this.images.add(this.image);
+                this.imageindex.put(hashkey,this.images.size()-1);
+
+            } catch(FileNotFoundException e){
+                System.out.println("Could not find cached image, downloading.");
+            } catch(IOException e){
+                System.out.println(e.getMessage());
+            } catch(Exception e){
+                System.out.println(e.getMessage());
+            }
+
+            if(this.image == null){
+                /**
+                 * Try downloading the image
+                 */
+                try {
+                    System.out.println("Downloading from "+urlloc);
+
+                    // Read from a URL
+                    URL url = new URL(urlloc);
+                    this.image = ImageIO.read(url); // this can return null!
+                } catch(MalformedURLException e){
+                    System.out.println(e.getMessage());
+                } catch(IOException e){
+                    System.out.println(e.getMessage());
+                } catch(Exception e){
+                    System.out.println(e.getMessage());
+                }
+
+                if (this.image != null) {
+                    this.images.add(this.image);
+                    this.imageindex.put(hashkey,this.images.size()-1);
+
+                    this.saveimage(file,this.image);
+                }
+            }
+
+            this.imagex = bottom_left_xy[0];
+            this.imagey = bottom_left_xy[1];
+
+            if(this.image == null){
+                throw new LakewalkerException(tr("Could not acquire image"));
+            }
+
+            return this.image;
+        } finally {
+            progressMonitor.finishTask();
+        }
     }
 
     public void saveimage(File file, BufferedImage image){
diff --git a/lakewalker/src/org/openstreetmap/josm/plugins/lakewalker/StringConfigurer.java b/lakewalker/src/org/openstreetmap/josm/plugins/lakewalker/StringConfigurer.java
index c5526ad..0b24e7a 100644
--- a/lakewalker/src/org/openstreetmap/josm/plugins/lakewalker/StringConfigurer.java
+++ b/lakewalker/src/org/openstreetmap/josm/plugins/lakewalker/StringConfigurer.java
@@ -72,7 +72,7 @@ public java.awt.Component getControls() {
       p.add(nameField);
       nameField.addKeyListener(new java.awt.event.KeyAdapter() {
         @Override
-		public void keyReleased(java.awt.event.KeyEvent evt) {
+        public void keyReleased(java.awt.event.KeyEvent evt) {
           noUpdate = true;
           setValue(nameField.getText());
           noUpdate = false;
diff --git a/lakewalker/src/org/openstreetmap/josm/plugins/lakewalker/StringEnumConfigurer.java b/lakewalker/src/org/openstreetmap/josm/plugins/lakewalker/StringEnumConfigurer.java
index 7ea8deb..093dbbb 100644
--- a/lakewalker/src/org/openstreetmap/josm/plugins/lakewalker/StringEnumConfigurer.java
+++ b/lakewalker/src/org/openstreetmap/josm/plugins/lakewalker/StringEnumConfigurer.java
@@ -63,7 +63,7 @@ public class StringEnumConfigurer extends Configurer {
         tooltipText = s;
     }
     @Override
-	public Component getControls() {
+    public Component getControls() {
         if (panel == null) {
             panel = Box.createHorizontalBox();
             panel.add(new JLabel(name));
@@ -84,7 +84,7 @@ public class StringEnumConfigurer extends Configurer {
     }
 
     @Override
-	public void setValue(Object o) {
+    public void setValue(Object o) {
         if(o == null)
             o = 0;
         super.setValue(o);
@@ -93,7 +93,7 @@ public class StringEnumConfigurer extends Configurer {
     }
 
     @Override
-	public void setValue(String s) {
+    public void setValue(String s) {
         Integer n = 0;
         for (int i = 0; i < transValues.length; ++i)
         {
@@ -106,7 +106,7 @@ public class StringEnumConfigurer extends Configurer {
     }
 
     @Override
-	public String getValueString() {
+    public String getValueString() {
         return validValues[(Integer)value];
     }
 }
diff --git a/livegps/src/livegps/AppendableGpxTrackSegment.java b/livegps/src/livegps/AppendableGpxTrackSegment.java
index dd786d6..1631cd3 100644
--- a/livegps/src/livegps/AppendableGpxTrackSegment.java
+++ b/livegps/src/livegps/AppendableGpxTrackSegment.java
@@ -13,50 +13,50 @@ import org.openstreetmap.josm.tools.CopyList;
  */
 public class AppendableGpxTrackSegment implements GpxTrackSegment {
 
-	private WayPoint[] wayPoints = new WayPoint[16];
-	private int size;
-	private Bounds bounds;
-	private double length;
-
-	public Bounds getBounds() {
-		return bounds;
-	}
-
-	public Collection<WayPoint> getWayPoints() {
-		return new CopyList<WayPoint>(wayPoints, size);
-	}
-
-	public void addWaypoint(WayPoint p) {
-		if (wayPoints.length == size) {
-			WayPoint[] newWaypoints = new WayPoint[wayPoints.length * 2];
-			System.arraycopy(wayPoints, 0, newWaypoints, 0, wayPoints.length);
-			wayPoints = newWaypoints;
-		}
-
-		if (size > 0) {
-			Double distance = wayPoints[size - 1].getCoor().greatCircleDistance(p.getCoor());
-			if (!distance.isNaN() && !distance.isInfinite()) {
-				length += distance;
-			}
-		}
-
-		if (bounds == null) {
-			bounds = new Bounds(p.getCoor());
-		} else {
-			bounds.extend(p.getCoor());
-		}
-
-		wayPoints[size] = p;
-		size++;
-	}
-
-	public double length() {
-		return length;
-	}
-
-	@Override
-	public int getUpdateCount() {
-		return size;
-	}
+    private WayPoint[] wayPoints = new WayPoint[16];
+    private int size;
+    private Bounds bounds;
+    private double length;
+
+    public Bounds getBounds() {
+        return bounds;
+    }
+
+    public Collection<WayPoint> getWayPoints() {
+        return new CopyList<WayPoint>(wayPoints, size);
+    }
+
+    public void addWaypoint(WayPoint p) {
+        if (wayPoints.length == size) {
+            WayPoint[] newWaypoints = new WayPoint[wayPoints.length * 2];
+            System.arraycopy(wayPoints, 0, newWaypoints, 0, wayPoints.length);
+            wayPoints = newWaypoints;
+        }
+
+        if (size > 0) {
+            Double distance = wayPoints[size - 1].getCoor().greatCircleDistance(p.getCoor());
+            if (!distance.isNaN() && !distance.isInfinite()) {
+                length += distance;
+            }
+        }
+
+        if (bounds == null) {
+            bounds = new Bounds(p.getCoor());
+        } else {
+            bounds.extend(p.getCoor());
+        }
+
+        wayPoints[size] = p;
+        size++;
+    }
+
+    public double length() {
+        return length;
+    }
+
+    @Override
+    public int getUpdateCount() {
+        return size;
+    }
 
 }
diff --git a/livegps/src/livegps/ILiveGpsSuppressor.java b/livegps/src/livegps/ILiveGpsSuppressor.java
index 50ef2c2..04aeb96 100644
--- a/livegps/src/livegps/ILiveGpsSuppressor.java
+++ b/livegps/src/livegps/ILiveGpsSuppressor.java
@@ -2,19 +2,19 @@ package livegps;
 
 /**
  * Interface for class LiveGpsSuppressor, only has a query if currently an update is allowed.
- * 
- * @author casualwalker 
+ *
+ * @author casualwalker
  *
  */
 public interface ILiveGpsSuppressor {
 
-	/**
-	 * Query, if an update is currently allowed.
-	 * When it is allowed, it will disable the allowUpdate flag as a side effect.
-	 * (this means, one thread got to issue an update event)
-	 *
-	 * @return true, if an update is currently allowed; false, if the update shall be suppressed.
-	 */
-	boolean isAllowUpdate();
+    /**
+     * Query, if an update is currently allowed.
+     * When it is allowed, it will disable the allowUpdate flag as a side effect.
+     * (this means, one thread got to issue an update event)
+     *
+     * @return true, if an update is currently allowed; false, if the update shall be suppressed.
+     */
+    boolean isAllowUpdate();
 
 }
diff --git a/livegps/src/livegps/LiveGpsAcquirer.java b/livegps/src/livegps/LiveGpsAcquirer.java
index c4542aa..10684c7 100644
--- a/livegps/src/livegps/LiveGpsAcquirer.java
+++ b/livegps/src/livegps/LiveGpsAcquirer.java
@@ -21,313 +21,313 @@ import org.json.JSONObject;
 import org.json.JSONException;
 
 public class LiveGpsAcquirer implements Runnable {
-	private String gpsdHost;
-	private int gpsdPort;
-
-	private Socket gpsdSocket;
-	private BufferedReader gpsdReader;
-	private boolean connected = false;
-	private boolean shutdownFlag = false;
-	private boolean JSONProtocol = true;
-
-	private final List<PropertyChangeListener> propertyChangeListener = new ArrayList<PropertyChangeListener>();
-	private PropertyChangeEvent lastStatusEvent;
-	private PropertyChangeEvent lastDataEvent;
-
-	/**
-	 * Constructor, initializes the configurable settings.
-	 */
-	public LiveGpsAcquirer() {
-		super();
-
-		gpsdHost = Main.pref.get("livegps.gpsd.host", "localhost");
-		gpsdPort = Main.pref.getInteger("livegps.gpsd.port", 2947);
-		// put the settings back in to the preferences, makes keys appear.
-		Main.pref.put("livegps.gpsd.host", gpsdHost);
-		Main.pref.putInteger("livegps.gpsd.port", gpsdPort);
-	}
-
-	/**
-	 * Adds a property change listener to the acquirer.
-	 * @param listener the new listener
-	 */
-	public void addPropertyChangeListener(PropertyChangeListener listener) {
-		if (!propertyChangeListener.contains(listener)) {
-			propertyChangeListener.add(listener);
-		}
-	}
-
-	/**
-	 * Remove a property change listener from the acquirer.
-	 * @param listener the new listener
-	 */
-	public void removePropertyChangeListener(PropertyChangeListener listener) {
-		if (propertyChangeListener.contains(listener)) {
-			propertyChangeListener.remove(listener);
-		}
-	}
-
-	/**
-	 * Fire a gps status change event. Fires events with key "gpsstatus" and a {@link LiveGpsStatus}
-	 * object as value.
-	 * The status event may be sent any time.
-	 * @param status the status.
-	 * @param statusMessage the status message.
-	 */
-	public void fireGpsStatusChangeEvent(LiveGpsStatus.GpsStatus status,
-			String statusMessage) {
-		PropertyChangeEvent event = new PropertyChangeEvent(this, "gpsstatus",
-				null, new LiveGpsStatus(status, statusMessage));
-
-		if (!event.equals(lastStatusEvent)) {
-			firePropertyChangeEvent(event);
-			lastStatusEvent = event;
-		}
-	}
-
-	/**
-	 * Fire a gps data change event to all listeners. Fires events with key "gpsdata" and a
-	 * {@link LiveGpsData} object as values.
-	 * This event is only sent, when the suppressor permits it. This
-	 * event will cause the UI to re-draw itself, which has some performance penalty,
-	 * @param oldData the old gps data.
-	 * @param newData the new gps data.
-	 */
-	public void fireGpsDataChangeEvent(LiveGpsData oldData, LiveGpsData newData) {
-		PropertyChangeEvent event = new PropertyChangeEvent(this, "gpsdata",
-				oldData, newData);
-
-		if (!event.equals(lastDataEvent)) {
-			firePropertyChangeEvent(event);
-			lastDataEvent = event;
-		}
-	}
-
-	/**
-	 * Fires the given event to all listeners.
-	 * @param event the event to fire.
-	 */
-	protected void firePropertyChangeEvent(PropertyChangeEvent event) {
-		for (PropertyChangeListener listener : propertyChangeListener) {
-			listener.propertyChange(event);
-		}
-	}
-
-	public void run() {
-		LiveGpsData oldGpsData = null;
-		LiveGpsData gpsData = null;
-
-		shutdownFlag = false;
-		while (!shutdownFlag) {
-
-			try {
-				if (!connected)
-					connect();
-
-				if (connected) {
-					String line;
-
-					// <FIXXME date="23.06.2007" author="cdaller">
-					// TODO this read is blocking if gps is connected but has no
-					// fix, so gpsd does not send positions
-					line = gpsdReader.readLine();
-					// </FIXXME>
-					if (line == null)
-						break;
-
-					if (JSONProtocol == true)
-						gpsData = ParseJSON(line);
-					else
-						gpsData = ParseOld(line);
-
-					if (gpsData == null)
-						continue;
-
-					fireGpsDataChangeEvent(oldGpsData, gpsData);
-					oldGpsData = gpsData;
-				} else {
-					fireGpsStatusChangeEvent(LiveGpsStatus.GpsStatus.DISCONNECTED, tr("Not connected"));
-					try {
-						Thread.sleep(1000);
-					} catch (InterruptedException ignore) {}
-				}
-			} catch (IOException iox) {
-				connected = false;
-				if (gpsData != null) {
-					gpsData.setFix(false);
-					fireGpsDataChangeEvent(oldGpsData, gpsData);
-				}
-				fireGpsStatusChangeEvent(
-						LiveGpsStatus.GpsStatus.CONNECTION_FAILED,
-						tr("Connection Failed"));
-				try {
-					Thread.sleep(1000);
-				} catch (InterruptedException ignore) {} ;
-				// send warning to layer
-			}
-		}
-
-		fireGpsStatusChangeEvent(LiveGpsStatus.GpsStatus.DISCONNECTED,
-				tr("Not connected"));
-		if (gpsdSocket != null) {
-			try {
-				gpsdSocket.close();
-				gpsdSocket = null;
-				System.out.println("LiveGps: Disconnected from gpsd");
-			} catch (Exception e) {
-				System.out.println("LiveGps: Unable to close socket; reconnection may not be possible");
-			}
-		}
-	}
-
-	public void shutdown() {
-		shutdownFlag = true;
-	}
-
-	private void connect() throws IOException {
-		JSONObject greeting;
-		String line, type, release;
-
-		System.out.println("LiveGps: trying to connect to gpsd at " + gpsdHost + ":" + gpsdPort);
-		fireGpsStatusChangeEvent( LiveGpsStatus.GpsStatus.CONNECTING, tr("Connecting"));
-
-		InetAddress[] addrs = InetAddress.getAllByName(gpsdHost);
-		for (int i = 0; i < addrs.length && gpsdSocket == null; i++) {
-			try {
-				gpsdSocket = new Socket(addrs[i], gpsdPort);
-				break;
-			} catch (Exception e) {
-				System.out.println("LiveGps: Could not open connection to gpsd: " + e);
-				gpsdSocket = null;
-			}
-		}
-
-		if (gpsdSocket == null)
-			return;
-
-		fireGpsStatusChangeEvent(LiveGpsStatus.GpsStatus.CONNECTING, tr("Connecting"));
-
-		/*
-		 * First emit the "w" symbol. The older version will activate, the newer one will ignore it.
-		 */
-		gpsdSocket.getOutputStream().write(new byte[] { 'w', 13, 10 });
-
-		gpsdReader = new BufferedReader(new InputStreamReader(gpsdSocket.getInputStream()));
-		line = gpsdReader.readLine();
-		if (line == null)
-			return;
-
-		try {
-			greeting = new JSONObject(line);
-			type = greeting.getString("class");
-			if (type.equals("VERSION")) {
-				release = greeting.getString("release");
-				System.out.println("LiveGps: Connected to gpsd " + release);
-			} else
-				System.out.println("LiveGps: Unexpected JSON in gpsd greeting: " + line);
-		} catch (JSONException jex) {
-			if (line.startsWith("GPSD,")) {
-				connected = true;
-				JSONProtocol = false;
-				System.out.println("LiveGps: Connected to old gpsd protocol version.");
-				fireGpsStatusChangeEvent(LiveGpsStatus.GpsStatus.CONNECTED, tr("Connected"));
-			}
-		}
-
-		if (JSONProtocol == true) {
-			JSONObject Watch = new JSONObject();
-			try { 
-				Watch.put("enable", true);
-				Watch.put("json", true);
-			} catch (JSONException je) {};
-
-			String Request = "?WATCH=" + Watch.toString() + ";\n";
-			gpsdSocket.getOutputStream().write(Request.getBytes());
-
-			connected = true;
-			fireGpsStatusChangeEvent(LiveGpsStatus.GpsStatus.CONNECTED, tr("Connected"));
-		}
-	}
-
-	private LiveGpsData ParseJSON(String line) {
-		JSONObject report;
-		String type;
-		double lat = 0;
-		double lon = 0;
-		float speed = 0;
-		float course = 0;
-
-		try {
-			report = new JSONObject(line);
-			type = report.getString("class");
-		} catch (JSONException jex) {
-			System.out.println("LiveGps: line read from gpsd is not a JSON object:" + line);
-			return null;
-		}
-		if (!type.equals("TPV"))
-			return null;
-
-		try {
-			lat = report.getDouble("lat");
-			lon = report.getDouble("lon");
-			speed = (new Float(report.getDouble("speed"))).floatValue();
-			course = (new Float(report.getDouble("track"))).floatValue();
-
-			return new LiveGpsData(lat, lon, course, speed, true);
-		} catch (JSONException je) {}
-
-		return null;
-	}
-
-	private LiveGpsData ParseOld(String line) {
-		String words[];
-		double lat = 0;
-		double lon = 0;
-		float speed = 0;
-		float course = 0;
-
-		words = line.split(",");
-		if ((words.length == 0) || (!words[0].equals("GPSD")))
-			return null;
-
-		for (int i = 1; i < words.length; i++) {
-			if ((words[i].length() < 2) || (words[i].charAt(1) != '=')) {
-				// unexpected response.
-				continue;
-			}
-
-			char what = words[i].charAt(0);
-			String value = words[i].substring(2);
-			switch (what) {
-			case 'O':
-				// full report, tab delimited.
-				String[] status = value.split("\\s+");
-				if (status.length >= 5) {
-					lat = Double.parseDouble(status[3]);
-					lon = Double.parseDouble(status[4]);
-					try {
-						speed = Float.parseFloat(status[9]);
-						course = Float.parseFloat(status[8]);
-					} catch (NumberFormatException nex) {}
-					return new LiveGpsData(lat, lon, course, speed, true);
-				}
-				break;
-			case 'P':
-				// position report, tab delimited.
-				String[] pos = value.split("\\s+");
-				if (pos.length >= 2) {
-					lat = Double.parseDouble(pos[0]);
-					lon = Double.parseDouble(pos[1]);
-					speed = Float.NaN;
-					course = Float.NaN;
-					return new LiveGpsData(lat, lon, course, speed, true);
-				}
-				break;
-			default:
-				// not interested
-			}
-		}
-
-		return null;
-	}
+    private String gpsdHost;
+    private int gpsdPort;
+
+    private Socket gpsdSocket;
+    private BufferedReader gpsdReader;
+    private boolean connected = false;
+    private boolean shutdownFlag = false;
+    private boolean JSONProtocol = true;
+
+    private final List<PropertyChangeListener> propertyChangeListener = new ArrayList<PropertyChangeListener>();
+    private PropertyChangeEvent lastStatusEvent;
+    private PropertyChangeEvent lastDataEvent;
+
+    /**
+     * Constructor, initializes the configurable settings.
+     */
+    public LiveGpsAcquirer() {
+        super();
+
+        gpsdHost = Main.pref.get("livegps.gpsd.host", "localhost");
+        gpsdPort = Main.pref.getInteger("livegps.gpsd.port", 2947);
+        // put the settings back in to the preferences, makes keys appear.
+        Main.pref.put("livegps.gpsd.host", gpsdHost);
+        Main.pref.putInteger("livegps.gpsd.port", gpsdPort);
+    }
+
+    /**
+     * Adds a property change listener to the acquirer.
+     * @param listener the new listener
+     */
+    public void addPropertyChangeListener(PropertyChangeListener listener) {
+        if (!propertyChangeListener.contains(listener)) {
+            propertyChangeListener.add(listener);
+        }
+    }
+
+    /**
+     * Remove a property change listener from the acquirer.
+     * @param listener the new listener
+     */
+    public void removePropertyChangeListener(PropertyChangeListener listener) {
+        if (propertyChangeListener.contains(listener)) {
+            propertyChangeListener.remove(listener);
+        }
+    }
+
+    /**
+     * Fire a gps status change event. Fires events with key "gpsstatus" and a {@link LiveGpsStatus}
+     * object as value.
+     * The status event may be sent any time.
+     * @param status the status.
+     * @param statusMessage the status message.
+     */
+    public void fireGpsStatusChangeEvent(LiveGpsStatus.GpsStatus status,
+            String statusMessage) {
+        PropertyChangeEvent event = new PropertyChangeEvent(this, "gpsstatus",
+                null, new LiveGpsStatus(status, statusMessage));
+
+        if (!event.equals(lastStatusEvent)) {
+            firePropertyChangeEvent(event);
+            lastStatusEvent = event;
+        }
+    }
+
+    /**
+     * Fire a gps data change event to all listeners. Fires events with key "gpsdata" and a
+     * {@link LiveGpsData} object as values.
+     * This event is only sent, when the suppressor permits it. This
+     * event will cause the UI to re-draw itself, which has some performance penalty,
+     * @param oldData the old gps data.
+     * @param newData the new gps data.
+     */
+    public void fireGpsDataChangeEvent(LiveGpsData oldData, LiveGpsData newData) {
+        PropertyChangeEvent event = new PropertyChangeEvent(this, "gpsdata",
+                oldData, newData);
+
+        if (!event.equals(lastDataEvent)) {
+            firePropertyChangeEvent(event);
+            lastDataEvent = event;
+        }
+    }
+
+    /**
+     * Fires the given event to all listeners.
+     * @param event the event to fire.
+     */
+    protected void firePropertyChangeEvent(PropertyChangeEvent event) {
+        for (PropertyChangeListener listener : propertyChangeListener) {
+            listener.propertyChange(event);
+        }
+    }
+
+    public void run() {
+        LiveGpsData oldGpsData = null;
+        LiveGpsData gpsData = null;
+
+        shutdownFlag = false;
+        while (!shutdownFlag) {
+
+            try {
+                if (!connected)
+                    connect();
+
+                if (connected) {
+                    String line;
+
+                    // <FIXXME date="23.06.2007" author="cdaller">
+                    // TODO this read is blocking if gps is connected but has no
+                    // fix, so gpsd does not send positions
+                    line = gpsdReader.readLine();
+                    // </FIXXME>
+                    if (line == null)
+                        break;
+
+                    if (JSONProtocol == true)
+                        gpsData = ParseJSON(line);
+                    else
+                        gpsData = ParseOld(line);
+
+                    if (gpsData == null)
+                        continue;
+
+                    fireGpsDataChangeEvent(oldGpsData, gpsData);
+                    oldGpsData = gpsData;
+                } else {
+                    fireGpsStatusChangeEvent(LiveGpsStatus.GpsStatus.DISCONNECTED, tr("Not connected"));
+                    try {
+                        Thread.sleep(1000);
+                    } catch (InterruptedException ignore) {}
+                }
+            } catch (IOException iox) {
+                connected = false;
+                if (gpsData != null) {
+                    gpsData.setFix(false);
+                    fireGpsDataChangeEvent(oldGpsData, gpsData);
+                }
+                fireGpsStatusChangeEvent(
+                        LiveGpsStatus.GpsStatus.CONNECTION_FAILED,
+                        tr("Connection Failed"));
+                try {
+                    Thread.sleep(1000);
+                } catch (InterruptedException ignore) {} ;
+                // send warning to layer
+            }
+        }
+
+        fireGpsStatusChangeEvent(LiveGpsStatus.GpsStatus.DISCONNECTED,
+                tr("Not connected"));
+        if (gpsdSocket != null) {
+            try {
+                gpsdSocket.close();
+                gpsdSocket = null;
+                System.out.println("LiveGps: Disconnected from gpsd");
+            } catch (Exception e) {
+                System.out.println("LiveGps: Unable to close socket; reconnection may not be possible");
+            }
+        }
+    }
+
+    public void shutdown() {
+        shutdownFlag = true;
+    }
+
+    private void connect() throws IOException {
+        JSONObject greeting;
+        String line, type, release;
+
+        System.out.println("LiveGps: trying to connect to gpsd at " + gpsdHost + ":" + gpsdPort);
+        fireGpsStatusChangeEvent( LiveGpsStatus.GpsStatus.CONNECTING, tr("Connecting"));
+
+        InetAddress[] addrs = InetAddress.getAllByName(gpsdHost);
+        for (int i = 0; i < addrs.length && gpsdSocket == null; i++) {
+            try {
+                gpsdSocket = new Socket(addrs[i], gpsdPort);
+                break;
+            } catch (Exception e) {
+                System.out.println("LiveGps: Could not open connection to gpsd: " + e);
+                gpsdSocket = null;
+            }
+        }
+
+        if (gpsdSocket == null)
+            return;
+
+        fireGpsStatusChangeEvent(LiveGpsStatus.GpsStatus.CONNECTING, tr("Connecting"));
+
+        /*
+         * First emit the "w" symbol. The older version will activate, the newer one will ignore it.
+         */
+        gpsdSocket.getOutputStream().write(new byte[] { 'w', 13, 10 });
+
+        gpsdReader = new BufferedReader(new InputStreamReader(gpsdSocket.getInputStream()));
+        line = gpsdReader.readLine();
+        if (line == null)
+            return;
+
+        try {
+            greeting = new JSONObject(line);
+            type = greeting.getString("class");
+            if (type.equals("VERSION")) {
+                release = greeting.getString("release");
+                System.out.println("LiveGps: Connected to gpsd " + release);
+            } else
+                System.out.println("LiveGps: Unexpected JSON in gpsd greeting: " + line);
+        } catch (JSONException jex) {
+            if (line.startsWith("GPSD,")) {
+                connected = true;
+                JSONProtocol = false;
+                System.out.println("LiveGps: Connected to old gpsd protocol version.");
+                fireGpsStatusChangeEvent(LiveGpsStatus.GpsStatus.CONNECTED, tr("Connected"));
+            }
+        }
+
+        if (JSONProtocol == true) {
+            JSONObject Watch = new JSONObject();
+            try {
+                Watch.put("enable", true);
+                Watch.put("json", true);
+            } catch (JSONException je) {};
+
+            String Request = "?WATCH=" + Watch.toString() + ";\n";
+            gpsdSocket.getOutputStream().write(Request.getBytes());
+
+            connected = true;
+            fireGpsStatusChangeEvent(LiveGpsStatus.GpsStatus.CONNECTED, tr("Connected"));
+        }
+    }
+
+    private LiveGpsData ParseJSON(String line) {
+        JSONObject report;
+        String type;
+        double lat = 0;
+        double lon = 0;
+        float speed = 0;
+        float course = 0;
+
+        try {
+            report = new JSONObject(line);
+            type = report.getString("class");
+        } catch (JSONException jex) {
+            System.out.println("LiveGps: line read from gpsd is not a JSON object:" + line);
+            return null;
+        }
+        if (!type.equals("TPV"))
+            return null;
+
+        try {
+            lat = report.getDouble("lat");
+            lon = report.getDouble("lon");
+            speed = (new Float(report.getDouble("speed"))).floatValue();
+            course = (new Float(report.getDouble("track"))).floatValue();
+
+            return new LiveGpsData(lat, lon, course, speed, true);
+        } catch (JSONException je) {}
+
+        return null;
+    }
+
+    private LiveGpsData ParseOld(String line) {
+        String words[];
+        double lat = 0;
+        double lon = 0;
+        float speed = 0;
+        float course = 0;
+
+        words = line.split(",");
+        if ((words.length == 0) || (!words[0].equals("GPSD")))
+            return null;
+
+        for (int i = 1; i < words.length; i++) {
+            if ((words[i].length() < 2) || (words[i].charAt(1) != '=')) {
+                // unexpected response.
+                continue;
+            }
+
+            char what = words[i].charAt(0);
+            String value = words[i].substring(2);
+            switch (what) {
+            case 'O':
+                // full report, tab delimited.
+                String[] status = value.split("\\s+");
+                if (status.length >= 5) {
+                    lat = Double.parseDouble(status[3]);
+                    lon = Double.parseDouble(status[4]);
+                    try {
+                        speed = Float.parseFloat(status[9]);
+                        course = Float.parseFloat(status[8]);
+                    } catch (NumberFormatException nex) {}
+                    return new LiveGpsData(lat, lon, course, speed, true);
+                }
+                break;
+            case 'P':
+                // position report, tab delimited.
+                String[] pos = value.split("\\s+");
+                if (pos.length >= 2) {
+                    lat = Double.parseDouble(pos[0]);
+                    lon = Double.parseDouble(pos[1]);
+                    speed = Float.NaN;
+                    course = Float.NaN;
+                    return new LiveGpsData(lat, lon, course, speed, true);
+                }
+                break;
+            default:
+                // not interested
+            }
+        }
+
+        return null;
+    }
 }
diff --git a/livegps/src/livegps/LiveGpsLayer.java b/livegps/src/livegps/LiveGpsLayer.java
index 41716ec..92f7fbd 100644
--- a/livegps/src/livegps/LiveGpsLayer.java
+++ b/livegps/src/livegps/LiveGpsLayer.java
@@ -22,162 +22,162 @@ import org.openstreetmap.josm.gui.MapView;
 import org.openstreetmap.josm.gui.layer.GpxLayer;
 
 public class LiveGpsLayer extends GpxLayer implements PropertyChangeListener {
-	public static final String LAYER_NAME = tr("LiveGPS layer");
-	public static final String KEY_LIVEGPS_COLOR = "color.livegps.position";
-	LatLon lastPos;
-	WayPoint lastPoint;
-	private final AppendableGpxTrackSegment trackSegment;
-	float speed;
-	float course;
-	// JLabel lbl;
-	boolean autocenter;
-	private SimpleDateFormat dateFormat = new SimpleDateFormat(
-	"yyyy-MM-dd'T'HH:mm:ss.SSS");
-
-	/**
-	 * The suppressor is queried, if the GUI shall be re-drawn.
-	 */
-	private ILiveGpsSuppressor suppressor;
-
-	public LiveGpsLayer(GpxData data) {
-		super(data, LAYER_NAME);
-		trackSegment = new AppendableGpxTrackSegment();
-
-		Map<String, Object> attr = new HashMap<String, Object>();
-		attr.put("desc", "josm live gps");
-
-		GpxTrack trackBeingWritten = new SingleSegmentGpxTrack(trackSegment, attr);
-		data.tracks.add(trackBeingWritten);
-	}
-
-	void setCurrentPosition(double lat, double lon) {
-		// System.out.println("adding pos " + lat + "," + lon);
-		LatLon thisPos = new LatLon(lat, lon);
-		if ((lastPos != null) && (thisPos.equalsEpsilon(lastPos))) {
-			// no change in position
-			// maybe show a "paused" cursor or some such
-			return;
-		}
-
-		lastPos = thisPos;
-		lastPoint = new WayPoint(thisPos);
-		lastPoint.attr.put("time", dateFormat.format(new Date()));
-		trackSegment.addWaypoint(lastPoint);
-		if (autocenter && allowRedraw()) {
-			center();
-		}
-
-		// Main.map.repaint();
-	}
-
-	public void center() {
-		if (lastPoint != null)
-			Main.map.mapView.zoomTo(lastPoint.getCoor());
-	}
-
-	// void setStatus(String status)
-	// {
-	// this.status = status;
-	// Main.map.repaint();
-	// System.out.println("LiveGps status: " + status);
-	// }
-
-	void setSpeed(float metresPerSecond) {
-		speed = metresPerSecond;
-		// Main.map.repaint();
-	}
-
-	void setCourse(float degrees) {
-		course = degrees;
-		// Main.map.repaint();
-	}
-
-	public void setAutoCenter(boolean ac) {
-		autocenter = ac;
-	}
-
-	@Override
-	public void paint(Graphics2D g, MapView mv, Bounds bounds) {
-		// System.out.println("in paint");
-		// System.out.println("in synced paint");
-		super.paint(g, mv, bounds);
-		// int statusHeight = 50;
-		// Rectangle mvs = mv.getBounds();
-		// mvs.y = mvs.y + mvs.height - statusHeight;
-		// mvs.height = statusHeight;
-		// g.setColor(new Color(1.0f, 1.0f, 1.0f, 0.8f));
-		// g.fillRect(mvs.x, mvs.y, mvs.width, mvs.height);
-
-		if (lastPoint != null) {
-			Point screen = mv.getPoint(lastPoint.getCoor());
-			g.setColor(Main.pref.getColor(KEY_LIVEGPS_COLOR, Color.RED));
-			g.drawOval(screen.x - 10, screen.y - 10, 20, 20);
-			g.drawOval(screen.x - 9, screen.y - 9, 18, 18);
-		}
-
-		// lbl.setText("gpsd: "+status+" Speed: " + speed +
-		// " Course: "+course);
-		// lbl.setBounds(0, 0, mvs.width-10, mvs.height-10);
-		// Graphics sub = g.create(mvs.x+5, mvs.y+5, mvs.width-10,
-		// mvs.height-10);
-		// lbl.paint(sub);
-
-		// if(status != null) {
-		// g.setColor(Color.WHITE);
-		// g.drawString("gpsd: " + status, 5, mv.getBounds().height - 15);
-		// // lower left corner
-		// }
-	}
-
-	/* (non-Javadoc)
-	 * @see java.beans.PropertyChangeListener#propertyChange(java.beans.PropertyChangeEvent)
-	 */
-	public void propertyChange(PropertyChangeEvent evt) {
-		if (!isVisible()) {
-			return;
-		}
-		if ("gpsdata".equals(evt.getPropertyName())) {
-			LiveGpsData data = (LiveGpsData) evt.getNewValue();
-			if (data.isFix()) {
-				setCurrentPosition(data.getLatitude(), data.getLongitude());
-				if (!Float.isNaN(data.getSpeed())) {
-					setSpeed(data.getSpeed());
-				}
-				if (!Float.isNaN(data.getCourse())) {
-					setCourse(data.getCourse());
-				}
-				if (!autocenter && allowRedraw()) {
-					Main.map.repaint();
-				}
-			}
-		}
-	}
-
-	/**
-	 * @param suppressor the suppressor to set
-	 */
-	public void setSuppressor(ILiveGpsSuppressor suppressor) {
-		this.suppressor = suppressor;
-	}
-
-	/**
-	 * @return the suppressor
-	 */
-	public ILiveGpsSuppressor getSuppressor() {
-		return suppressor;
-	}
-
-	/**
-	 * Check, if a redraw is currently allowed.
-	 *
-	 * @return true, if a redraw is permitted, false, if a re-draw
-	 * should be suppressed.
-	 */
-	private boolean allowRedraw() {
-		if (this.suppressor != null) {
-			return this.suppressor.isAllowUpdate();
-		} else {
-			return true;
-		}
-	}
+    public static final String LAYER_NAME = tr("LiveGPS layer");
+    public static final String KEY_LIVEGPS_COLOR = "color.livegps.position";
+    LatLon lastPos;
+    WayPoint lastPoint;
+    private final AppendableGpxTrackSegment trackSegment;
+    float speed;
+    float course;
+    // JLabel lbl;
+    boolean autocenter;
+    private SimpleDateFormat dateFormat = new SimpleDateFormat(
+    "yyyy-MM-dd'T'HH:mm:ss.SSS");
+
+    /**
+     * The suppressor is queried, if the GUI shall be re-drawn.
+     */
+    private ILiveGpsSuppressor suppressor;
+
+    public LiveGpsLayer(GpxData data) {
+        super(data, LAYER_NAME);
+        trackSegment = new AppendableGpxTrackSegment();
+
+        Map<String, Object> attr = new HashMap<String, Object>();
+        attr.put("desc", "josm live gps");
+
+        GpxTrack trackBeingWritten = new SingleSegmentGpxTrack(trackSegment, attr);
+        data.tracks.add(trackBeingWritten);
+    }
+
+    void setCurrentPosition(double lat, double lon) {
+        // System.out.println("adding pos " + lat + "," + lon);
+        LatLon thisPos = new LatLon(lat, lon);
+        if ((lastPos != null) && (thisPos.equalsEpsilon(lastPos))) {
+            // no change in position
+            // maybe show a "paused" cursor or some such
+            return;
+        }
+
+        lastPos = thisPos;
+        lastPoint = new WayPoint(thisPos);
+        lastPoint.attr.put("time", dateFormat.format(new Date()));
+        trackSegment.addWaypoint(lastPoint);
+        if (autocenter && allowRedraw()) {
+            center();
+        }
+
+        // Main.map.repaint();
+    }
+
+    public void center() {
+        if (lastPoint != null)
+            Main.map.mapView.zoomTo(lastPoint.getCoor());
+    }
+
+    // void setStatus(String status)
+    // {
+    // this.status = status;
+    // Main.map.repaint();
+    // System.out.println("LiveGps status: " + status);
+    // }
+
+    void setSpeed(float metresPerSecond) {
+        speed = metresPerSecond;
+        // Main.map.repaint();
+    }
+
+    void setCourse(float degrees) {
+        course = degrees;
+        // Main.map.repaint();
+    }
+
+    public void setAutoCenter(boolean ac) {
+        autocenter = ac;
+    }
+
+    @Override
+    public void paint(Graphics2D g, MapView mv, Bounds bounds) {
+        // System.out.println("in paint");
+        // System.out.println("in synced paint");
+        super.paint(g, mv, bounds);
+        // int statusHeight = 50;
+        // Rectangle mvs = mv.getBounds();
+        // mvs.y = mvs.y + mvs.height - statusHeight;
+        // mvs.height = statusHeight;
+        // g.setColor(new Color(1.0f, 1.0f, 1.0f, 0.8f));
+        // g.fillRect(mvs.x, mvs.y, mvs.width, mvs.height);
+
+        if (lastPoint != null) {
+            Point screen = mv.getPoint(lastPoint.getCoor());
+            g.setColor(Main.pref.getColor(KEY_LIVEGPS_COLOR, Color.RED));
+            g.drawOval(screen.x - 10, screen.y - 10, 20, 20);
+            g.drawOval(screen.x - 9, screen.y - 9, 18, 18);
+        }
+
+        // lbl.setText("gpsd: "+status+" Speed: " + speed +
+        // " Course: "+course);
+        // lbl.setBounds(0, 0, mvs.width-10, mvs.height-10);
+        // Graphics sub = g.create(mvs.x+5, mvs.y+5, mvs.width-10,
+        // mvs.height-10);
+        // lbl.paint(sub);
+
+        // if(status != null) {
+        // g.setColor(Color.WHITE);
+        // g.drawString("gpsd: " + status, 5, mv.getBounds().height - 15);
+        // // lower left corner
+        // }
+    }
+
+    /* (non-Javadoc)
+     * @see java.beans.PropertyChangeListener#propertyChange(java.beans.PropertyChangeEvent)
+     */
+    public void propertyChange(PropertyChangeEvent evt) {
+        if (!isVisible()) {
+            return;
+        }
+        if ("gpsdata".equals(evt.getPropertyName())) {
+            LiveGpsData data = (LiveGpsData) evt.getNewValue();
+            if (data.isFix()) {
+                setCurrentPosition(data.getLatitude(), data.getLongitude());
+                if (!Float.isNaN(data.getSpeed())) {
+                    setSpeed(data.getSpeed());
+                }
+                if (!Float.isNaN(data.getCourse())) {
+                    setCourse(data.getCourse());
+                }
+                if (!autocenter && allowRedraw()) {
+                    Main.map.repaint();
+                }
+            }
+        }
+    }
+
+    /**
+     * @param suppressor the suppressor to set
+     */
+    public void setSuppressor(ILiveGpsSuppressor suppressor) {
+        this.suppressor = suppressor;
+    }
+
+    /**
+     * @return the suppressor
+     */
+    public ILiveGpsSuppressor getSuppressor() {
+        return suppressor;
+    }
+
+    /**
+     * Check, if a redraw is currently allowed.
+     *
+     * @return true, if a redraw is permitted, false, if a re-draw
+     * should be suppressed.
+     */
+    private boolean allowRedraw() {
+        if (this.suppressor != null) {
+            return this.suppressor.isAllowUpdate();
+        } else {
+            return true;
+        }
+    }
 }
diff --git a/livegps/src/livegps/LiveGpsPlugin.java b/livegps/src/livegps/LiveGpsPlugin.java
index 328b6b7..19c24e2 100644
--- a/livegps/src/livegps/LiveGpsPlugin.java
+++ b/livegps/src/livegps/LiveGpsPlugin.java
@@ -27,239 +27,239 @@ import org.openstreetmap.josm.plugins.PluginInformation;
 import org.openstreetmap.josm.tools.Shortcut;
 
 public class LiveGpsPlugin extends Plugin implements LayerChangeListener {
-	private LiveGpsAcquirer acquirer = null;
-	private Thread acquirerThread = null;
-	private JMenu lgpsmenu;
-	private JCheckBoxMenuItem lgpscapture;
-	private JCheckBoxMenuItem lgpsautocenter;
-	private LiveGpsDialog lgpsdialog;
-	List<PropertyChangeListener> listenerQueue;
-
-	private GpxData data = new GpxData();
-	private LiveGpsLayer lgpslayer = null;
-
-	/**
-	 * The LiveGpsSuppressor is queried, if an event shall be suppressed.
-	 */
-	private LiveGpsSuppressor suppressor;
-
-	/**
-	 * separate thread, where the LiveGpsSuppressor executes.
-	 */
-	private Thread suppressorThread;
-
-	public class CaptureAction extends JosmAction {
-		public CaptureAction() {
-			super(
-					tr("Capture GPS Track"),
-					"capturemenu",
-					tr("Connect to gpsd server and show current position in LiveGPS layer."),
-					Shortcut.registerShortcut("menu:livegps:capture", tr(
-							"Menu: {0}", tr("Capture GPS Track")),
-							KeyEvent.VK_R, Shortcut.GROUP_MENU), true);
-		}
-
-		public void actionPerformed(ActionEvent e) {
-			enableTracking(lgpscapture.isSelected());
-		}
-	}
-
-	public class CenterAction extends JosmAction {
-		public CenterAction() {
-			super(tr("Center Once"), "centermenu",
-					tr("Center the LiveGPS layer to current position."),
-					Shortcut.registerShortcut("edit:centergps", tr("Edit: {0}",
-							tr("Center Once")), KeyEvent.VK_HOME,
-							Shortcut.GROUP_EDIT), true);
-		}
-
-		public void actionPerformed(ActionEvent e) {
-			if (lgpslayer != null) {
-				lgpslayer.center();
-			}
-		}
-	}
-
-	public class AutoCenterAction extends JosmAction {
-		public AutoCenterAction() {
-			super(
-					tr("Auto-Center"),
-					"autocentermenu",
-					tr("Continuously center the LiveGPS layer to current position."),
-					Shortcut.registerShortcut("menu:livegps:autocenter", tr(
-							"Menu: {0}", tr("Capture GPS Track")),
-							KeyEvent.VK_HOME, Shortcut.GROUP_MENU), true);
-		}
-
-		public void actionPerformed(ActionEvent e) {
-			if (lgpslayer != null) {
-				setAutoCenter(lgpsautocenter.isSelected());
-			}
-		}
-	}
-
-	public void activeLayerChange(Layer oldLayer, Layer newLayer) {
-	}
-
-	public void layerAdded(Layer newLayer) {
-	}
-
-	public void layerRemoved(Layer oldLayer) {
-		if (oldLayer == lgpslayer) {
-			enableTracking(false);
-			lgpscapture.setSelected(false);
-			removePropertyChangeListener(lgpslayer);
-			MapView.removeLayerChangeListener(this);
-			lgpslayer = null;
-		}
-	}
-
-	public LiveGpsPlugin(PluginInformation info) {
-		super(info);
-		MainMenu menu = Main.main.menu;
-		lgpsmenu = menu.addMenu(marktr("LiveGPS"), KeyEvent.VK_G,
-				menu.defaultMenuPos, ht("/Plugin/LiveGPS"));
-
-		JosmAction captureAction = new CaptureAction();
-		lgpscapture = new JCheckBoxMenuItem(captureAction);
-		lgpsmenu.add(lgpscapture);
-		lgpscapture.setAccelerator(captureAction.getShortcut().getKeyStroke());
-
-		JosmAction centerAction = new CenterAction();
-		JMenuItem centerMenu = new JMenuItem(centerAction);
-		lgpsmenu.add(centerMenu);
-		centerMenu.setAccelerator(centerAction.getShortcut().getKeyStroke());
-
-		JosmAction autoCenterAction = new AutoCenterAction();
-		lgpsautocenter = new JCheckBoxMenuItem(autoCenterAction);
-		lgpsmenu.add(lgpsautocenter);
-		lgpsautocenter.setAccelerator(autoCenterAction.getShortcut()
-				.getKeyStroke());
-	}
-
-	/**
-	 * Set to <code>true</code> if the current position should always be in the center of the map.
-	 * @param autoCenter if <code>true</code> the map is always centered.
-	 */
-	public void setAutoCenter(boolean autoCenter) {
-		lgpsautocenter.setSelected(autoCenter); // just in case this method was
-		// not called from the menu
-		if (lgpslayer != null) {
-			lgpslayer.setAutoCenter(autoCenter);
-			if (autoCenter)
-				lgpslayer.center();
-		}
-	}
-
-	/**
-	 * Returns <code>true</code> if autocenter is selected.
-	 * @return <code>true</code> if autocenter is selected.
-	 */
-	public boolean isAutoCenter() {
-		return lgpsautocenter.isSelected();
-	}
-
-	/**
-	 * Enable or disable gps tracking
-	 * @param enable if <code>true</code> tracking is started.
-	 */
-	public void enableTracking(boolean enable) {
-		if ((acquirer != null) && (!enable)) {
-			acquirer.shutdown();
-			acquirerThread = null;
-
-			// also stop the suppressor
-			if (suppressor != null) {
-				suppressor.shutdown();
-				suppressorThread = null;
-				if (lgpslayer != null) {
-					lgpslayer.setSuppressor(null);
-				}
-			}
-		} else if (enable) {
-			// also start the suppressor
-			if (suppressor == null) {
-				suppressor = new LiveGpsSuppressor();
-			}
-			if (suppressorThread == null) {
-				suppressorThread = new Thread(suppressor);
-				suppressorThread.start();
-			}
-
-			if (acquirer == null) {
-				acquirer = new LiveGpsAcquirer();
-				if (lgpslayer == null) {
-					lgpslayer = new LiveGpsLayer(data);
-					Main.main.addLayer(lgpslayer);
-					MapView.addLayerChangeListener(this);
-					lgpslayer.setAutoCenter(isAutoCenter());
-				}
-				// connect layer with acquirer:
-				addPropertyChangeListener(lgpslayer);
-
-				// connect layer with suppressor:
-				lgpslayer.setSuppressor(suppressor);
-				// add all listeners that were added before the acquirer
-				// existed:
-				if (listenerQueue != null) {
-					for (PropertyChangeListener listener : listenerQueue) {
-						addPropertyChangeListener(listener);
-					}
-					listenerQueue.clear();
-				}
-			}
-			if (acquirerThread == null) {
-				acquirerThread = new Thread(acquirer);
-				acquirerThread.start();
-			}
-
-		}
-	}
-
-	/**
-	 * Add a listener for gps events.
-	 * @param listener the listener.
-	 */
-	public void addPropertyChangeListener(PropertyChangeListener listener) {
-		if (acquirer != null) {
-			acquirer.addPropertyChangeListener(listener);
-		} else {
-			if (listenerQueue == null) {
-				listenerQueue = new ArrayList<PropertyChangeListener>();
-			}
-			listenerQueue.add(listener);
-		}
-	}
-
-	/**
-	 * Remove a listener for gps events.
-	 * @param listener the listener.
-	 */
-	public void removePropertyChangeListener(PropertyChangeListener listener) {
-		if (acquirer != null)
-			acquirer.removePropertyChangeListener(listener);
-		else if (listenerQueue != null && listenerQueue.contains(listener))
-			listenerQueue.remove(listener);
-	}
-
-	/* (non-Javadoc)
-	 * @see org.openstreetmap.josm.plugins.Plugin#mapFrameInitialized(org.openstreetmap.josm.gui.MapFrame, org.openstreetmap.josm.gui.MapFrame)
-	 */
-	@Override
-	public void mapFrameInitialized(MapFrame oldFrame, MapFrame newFrame) {
-		if (newFrame != null) {
-			// add dialog
-			newFrame.addToggleDialog(lgpsdialog = new LiveGpsDialog(newFrame));
-			// connect listeners with acquirer:
-			addPropertyChangeListener(lgpsdialog);
-		}
-	}
-
-	/**
-	 * @return the lgpsmenu
-	 */
-	public JMenu getLgpsMenu() {
-		return this.lgpsmenu;
-	}
+    private LiveGpsAcquirer acquirer = null;
+    private Thread acquirerThread = null;
+    private JMenu lgpsmenu;
+    private JCheckBoxMenuItem lgpscapture;
+    private JCheckBoxMenuItem lgpsautocenter;
+    private LiveGpsDialog lgpsdialog;
+    List<PropertyChangeListener> listenerQueue;
+
+    private GpxData data = new GpxData();
+    private LiveGpsLayer lgpslayer = null;
+
+    /**
+     * The LiveGpsSuppressor is queried, if an event shall be suppressed.
+     */
+    private LiveGpsSuppressor suppressor;
+
+    /**
+     * separate thread, where the LiveGpsSuppressor executes.
+     */
+    private Thread suppressorThread;
+
+    public class CaptureAction extends JosmAction {
+        public CaptureAction() {
+            super(
+                    tr("Capture GPS Track"),
+                    "capturemenu",
+                    tr("Connect to gpsd server and show current position in LiveGPS layer."),
+                    Shortcut.registerShortcut("menu:livegps:capture", tr(
+                            "Menu: {0}", tr("Capture GPS Track")),
+                            KeyEvent.VK_R, Shortcut.GROUP_MENU), true);
+        }
+
+        public void actionPerformed(ActionEvent e) {
+            enableTracking(lgpscapture.isSelected());
+        }
+    }
+
+    public class CenterAction extends JosmAction {
+        public CenterAction() {
+            super(tr("Center Once"), "centermenu",
+                    tr("Center the LiveGPS layer to current position."),
+                    Shortcut.registerShortcut("edit:centergps", tr("Edit: {0}",
+                            tr("Center Once")), KeyEvent.VK_HOME,
+                            Shortcut.GROUP_EDIT), true);
+        }
+
+        public void actionPerformed(ActionEvent e) {
+            if (lgpslayer != null) {
+                lgpslayer.center();
+            }
+        }
+    }
+
+    public class AutoCenterAction extends JosmAction {
+        public AutoCenterAction() {
+            super(
+                    tr("Auto-Center"),
+                    "autocentermenu",
+                    tr("Continuously center the LiveGPS layer to current position."),
+                    Shortcut.registerShortcut("menu:livegps:autocenter", tr(
+                            "Menu: {0}", tr("Capture GPS Track")),
+                            KeyEvent.VK_HOME, Shortcut.GROUP_MENU), true);
+        }
+
+        public void actionPerformed(ActionEvent e) {
+            if (lgpslayer != null) {
+                setAutoCenter(lgpsautocenter.isSelected());
+            }
+        }
+    }
+
+    public void activeLayerChange(Layer oldLayer, Layer newLayer) {
+    }
+
+    public void layerAdded(Layer newLayer) {
+    }
+
+    public void layerRemoved(Layer oldLayer) {
+        if (oldLayer == lgpslayer) {
+            enableTracking(false);
+            lgpscapture.setSelected(false);
+            removePropertyChangeListener(lgpslayer);
+            MapView.removeLayerChangeListener(this);
+            lgpslayer = null;
+        }
+    }
+
+    public LiveGpsPlugin(PluginInformation info) {
+        super(info);
+        MainMenu menu = Main.main.menu;
+        lgpsmenu = menu.addMenu(marktr("LiveGPS"), KeyEvent.VK_G,
+                menu.defaultMenuPos, ht("/Plugin/LiveGPS"));
+
+        JosmAction captureAction = new CaptureAction();
+        lgpscapture = new JCheckBoxMenuItem(captureAction);
+        lgpsmenu.add(lgpscapture);
+        lgpscapture.setAccelerator(captureAction.getShortcut().getKeyStroke());
+
+        JosmAction centerAction = new CenterAction();
+        JMenuItem centerMenu = new JMenuItem(centerAction);
+        lgpsmenu.add(centerMenu);
+        centerMenu.setAccelerator(centerAction.getShortcut().getKeyStroke());
+
+        JosmAction autoCenterAction = new AutoCenterAction();
+        lgpsautocenter = new JCheckBoxMenuItem(autoCenterAction);
+        lgpsmenu.add(lgpsautocenter);
+        lgpsautocenter.setAccelerator(autoCenterAction.getShortcut()
+                .getKeyStroke());
+    }
+
+    /**
+     * Set to <code>true</code> if the current position should always be in the center of the map.
+     * @param autoCenter if <code>true</code> the map is always centered.
+     */
+    public void setAutoCenter(boolean autoCenter) {
+        lgpsautocenter.setSelected(autoCenter); // just in case this method was
+        // not called from the menu
+        if (lgpslayer != null) {
+            lgpslayer.setAutoCenter(autoCenter);
+            if (autoCenter)
+                lgpslayer.center();
+        }
+    }
+
+    /**
+     * Returns <code>true</code> if autocenter is selected.
+     * @return <code>true</code> if autocenter is selected.
+     */
+    public boolean isAutoCenter() {
+        return lgpsautocenter.isSelected();
+    }
+
+    /**
+     * Enable or disable gps tracking
+     * @param enable if <code>true</code> tracking is started.
+     */
+    public void enableTracking(boolean enable) {
+        if ((acquirer != null) && (!enable)) {
+            acquirer.shutdown();
+            acquirerThread = null;
+
+            // also stop the suppressor
+            if (suppressor != null) {
+                suppressor.shutdown();
+                suppressorThread = null;
+                if (lgpslayer != null) {
+                    lgpslayer.setSuppressor(null);
+                }
+            }
+        } else if (enable) {
+            // also start the suppressor
+            if (suppressor == null) {
+                suppressor = new LiveGpsSuppressor();
+            }
+            if (suppressorThread == null) {
+                suppressorThread = new Thread(suppressor);
+                suppressorThread.start();
+            }
+
+            if (acquirer == null) {
+                acquirer = new LiveGpsAcquirer();
+                if (lgpslayer == null) {
+                    lgpslayer = new LiveGpsLayer(data);
+                    Main.main.addLayer(lgpslayer);
+                    MapView.addLayerChangeListener(this);
+                    lgpslayer.setAutoCenter(isAutoCenter());
+                }
+                // connect layer with acquirer:
+                addPropertyChangeListener(lgpslayer);
+
+                // connect layer with suppressor:
+                lgpslayer.setSuppressor(suppressor);
+                // add all listeners that were added before the acquirer
+                // existed:
+                if (listenerQueue != null) {
+                    for (PropertyChangeListener listener : listenerQueue) {
+                        addPropertyChangeListener(listener);
+                    }
+                    listenerQueue.clear();
+                }
+            }
+            if (acquirerThread == null) {
+                acquirerThread = new Thread(acquirer);
+                acquirerThread.start();
+            }
+
+        }
+    }
+
+    /**
+     * Add a listener for gps events.
+     * @param listener the listener.
+     */
+    public void addPropertyChangeListener(PropertyChangeListener listener) {
+        if (acquirer != null) {
+            acquirer.addPropertyChangeListener(listener);
+        } else {
+            if (listenerQueue == null) {
+                listenerQueue = new ArrayList<PropertyChangeListener>();
+            }
+            listenerQueue.add(listener);
+        }
+    }
+
+    /**
+     * Remove a listener for gps events.
+     * @param listener the listener.
+     */
+    public void removePropertyChangeListener(PropertyChangeListener listener) {
+        if (acquirer != null)
+            acquirer.removePropertyChangeListener(listener);
+        else if (listenerQueue != null && listenerQueue.contains(listener))
+            listenerQueue.remove(listener);
+    }
+
+    /* (non-Javadoc)
+     * @see org.openstreetmap.josm.plugins.Plugin#mapFrameInitialized(org.openstreetmap.josm.gui.MapFrame, org.openstreetmap.josm.gui.MapFrame)
+     */
+    @Override
+    public void mapFrameInitialized(MapFrame oldFrame, MapFrame newFrame) {
+        if (newFrame != null) {
+            // add dialog
+            newFrame.addToggleDialog(lgpsdialog = new LiveGpsDialog(newFrame));
+            // connect listeners with acquirer:
+            addPropertyChangeListener(lgpsdialog);
+        }
+    }
+
+    /**
+     * @return the lgpsmenu
+     */
+    public JMenu getLgpsMenu() {
+        return this.lgpsmenu;
+    }
 
 }
diff --git a/livegps/src/livegps/LiveGpsSuppressor.java b/livegps/src/livegps/LiveGpsSuppressor.java
index 1f48cfb..78bcf17 100644
--- a/livegps/src/livegps/LiveGpsSuppressor.java
+++ b/livegps/src/livegps/LiveGpsSuppressor.java
@@ -17,120 +17,120 @@ import org.openstreetmap.josm.Main;
  */
 public class LiveGpsSuppressor implements Runnable, ILiveGpsSuppressor {
 
-	/**
-	 * Default sleep time is 5 seconds.
-	 */
-	private static final int DEFAULT_SLEEP_TIME = 5;
-
-	/**
-	 * The currently used sleepTime.
-	 */
-	private int sleepTime = DEFAULT_SLEEP_TIME;
-
-	/**
-	 * The flag allowUpdate is enabled once during the sleepTime.
-	 */
-	private boolean allowUpdate = false;
-
-	/**
-	 * Controls if this thread is still in used.
-	 */
-	private boolean shutdownFlag = false;
-
-	/**
-	 * Run thread enables the allowUpdate flag once during its cycle.
-	 * @see java.lang.Runnable#run()
-	 */
-	public void run() {
-		initSleepTime();
-
-		shutdownFlag = false;
-		// stop the thread, when explicitely shut down or when disabled by
-		// config setting
-		while (!shutdownFlag && isEnabled()) {
-			setAllowUpdate(true);
-
-			try {
-				Thread.sleep(getSleepTime());
-			} catch (InterruptedException e) {
-				// TODO I never knew, how to handle this??? Probably just carry
-				// on
-			}
-		}
-
-	}
-
-	/**
-	 * Retrieve the sleepTime from the configuration.
-	 * If no such configuration key exists, it will be initialized here.
-	 */
-	private void initSleepTime() {
-		// fetch it from the user setting, or use the default value.
-		int sleepSeconds = 0;
-		sleepSeconds = Main.pref.getInteger("livegps.refreshinterval",
-				DEFAULT_SLEEP_TIME);
-		// creates the setting, if none present.
-		Main.pref.putInteger("livegps.refreshinterval", sleepSeconds);
-
-		// convert seconds into milliseconds internally.
-		this.sleepTime = sleepSeconds * 1000;
-	}
-
-	/**
-	 * Set the allowUpdate flag. May only privately accessible!
-	 * @param allowUpdate the allowUpdate to set
-	 */
-	private synchronized void setAllowUpdate(boolean allowUpdate) {
-		this.allowUpdate = allowUpdate;
-	}
-
-	/**
-	 * Query, if an update is currently allowed.
-	 * When it is allowed, it will disable the allowUpdate flag as a side effect.
-	 * (this means, one thread got to issue an update event)
-	 *
-	 * @return true, if an update is currently allowed; false, if the update shall be suppressed.
-	 * @see livegps.ILiveGpsSuppressor#isAllowUpdate()
-	 */
-	public synchronized boolean isAllowUpdate() {
-
-		// if disabled, always permit a re-draw.
-		if (!isEnabled()) {
-			return true;
-		} else {
-
-			if (allowUpdate) {
-				allowUpdate = false;
-				return true;
-			} else {
-				return false;
-			}
-		}
-	}
-
-	/**
-	 * A value below 1 disables this feature.
-	 * This ensures that a small value does not run this thread
-	 * in a tight loop.
-	 * 
-	 * @return true, if suppressing is enabled
-	 */
-	private boolean isEnabled() {
-		return this.sleepTime > 0;
-	}
-
-	/**
-	 * Shut this thread down.
-	 */
-	public void shutdown() {
-		shutdownFlag = true;
-	}
-
-	/**
-	 * @return the defaultSleepTime
-	 */
-	private int getSleepTime() {
-		return this.sleepTime;
-	}
+    /**
+     * Default sleep time is 5 seconds.
+     */
+    private static final int DEFAULT_SLEEP_TIME = 5;
+
+    /**
+     * The currently used sleepTime.
+     */
+    private int sleepTime = DEFAULT_SLEEP_TIME;
+
+    /**
+     * The flag allowUpdate is enabled once during the sleepTime.
+     */
+    private boolean allowUpdate = false;
+
+    /**
+     * Controls if this thread is still in used.
+     */
+    private boolean shutdownFlag = false;
+
+    /**
+     * Run thread enables the allowUpdate flag once during its cycle.
+     * @see java.lang.Runnable#run()
+     */
+    public void run() {
+        initSleepTime();
+
+        shutdownFlag = false;
+        // stop the thread, when explicitely shut down or when disabled by
+        // config setting
+        while (!shutdownFlag && isEnabled()) {
+            setAllowUpdate(true);
+
+            try {
+                Thread.sleep(getSleepTime());
+            } catch (InterruptedException e) {
+                // TODO I never knew, how to handle this??? Probably just carry
+                // on
+            }
+        }
+
+    }
+
+    /**
+     * Retrieve the sleepTime from the configuration.
+     * If no such configuration key exists, it will be initialized here.
+     */
+    private void initSleepTime() {
+        // fetch it from the user setting, or use the default value.
+        int sleepSeconds = 0;
+        sleepSeconds = Main.pref.getInteger("livegps.refreshinterval",
+                DEFAULT_SLEEP_TIME);
+        // creates the setting, if none present.
+        Main.pref.putInteger("livegps.refreshinterval", sleepSeconds);
+
+        // convert seconds into milliseconds internally.
+        this.sleepTime = sleepSeconds * 1000;
+    }
+
+    /**
+     * Set the allowUpdate flag. May only privately accessible!
+     * @param allowUpdate the allowUpdate to set
+     */
+    private synchronized void setAllowUpdate(boolean allowUpdate) {
+        this.allowUpdate = allowUpdate;
+    }
+
+    /**
+     * Query, if an update is currently allowed.
+     * When it is allowed, it will disable the allowUpdate flag as a side effect.
+     * (this means, one thread got to issue an update event)
+     *
+     * @return true, if an update is currently allowed; false, if the update shall be suppressed.
+     * @see livegps.ILiveGpsSuppressor#isAllowUpdate()
+     */
+    public synchronized boolean isAllowUpdate() {
+
+        // if disabled, always permit a re-draw.
+        if (!isEnabled()) {
+            return true;
+        } else {
+
+            if (allowUpdate) {
+                allowUpdate = false;
+                return true;
+            } else {
+                return false;
+            }
+        }
+    }
+
+    /**
+     * A value below 1 disables this feature.
+     * This ensures that a small value does not run this thread
+     * in a tight loop.
+     *
+     * @return true, if suppressing is enabled
+     */
+    private boolean isEnabled() {
+        return this.sleepTime > 0;
+    }
+
+    /**
+     * Shut this thread down.
+     */
+    public void shutdown() {
+        shutdownFlag = true;
+    }
+
+    /**
+     * @return the defaultSleepTime
+     */
+    private int getSleepTime() {
+        return this.sleepTime;
+    }
 
 }
diff --git a/livegps/src/livegps/SingleSegmentGpxTrack.java b/livegps/src/livegps/SingleSegmentGpxTrack.java
index 68a58a3..4df90aa 100644
--- a/livegps/src/livegps/SingleSegmentGpxTrack.java
+++ b/livegps/src/livegps/SingleSegmentGpxTrack.java
@@ -10,34 +10,34 @@ import org.openstreetmap.josm.data.gpx.GpxTrackSegment;
 
 public class SingleSegmentGpxTrack implements GpxTrack {
 
-	private final Map<String, Object> attributes;
-	private final GpxTrackSegment trackSegment;
+    private final Map<String, Object> attributes;
+    private final GpxTrackSegment trackSegment;
 
-	public SingleSegmentGpxTrack(GpxTrackSegment trackSegment, Map<String, Object> attributes) {
-		this.attributes = Collections.unmodifiableMap(attributes);
-		this.trackSegment = trackSegment;
-	}
+    public SingleSegmentGpxTrack(GpxTrackSegment trackSegment, Map<String, Object> attributes) {
+        this.attributes = Collections.unmodifiableMap(attributes);
+        this.trackSegment = trackSegment;
+    }
 
 
-	public Map<String, Object> getAttributes() {
-		return attributes;
-	}
+    public Map<String, Object> getAttributes() {
+        return attributes;
+    }
 
-	public Bounds getBounds() {
-		return trackSegment.getBounds();
-	}
+    public Bounds getBounds() {
+        return trackSegment.getBounds();
+    }
 
-	public Collection<GpxTrackSegment> getSegments() {
-		return Collections.singleton(trackSegment);
-	}
+    public Collection<GpxTrackSegment> getSegments() {
+        return Collections.singleton(trackSegment);
+    }
 
-	public double length() {
-		return trackSegment.length();
-	}
+    public double length() {
+        return trackSegment.length();
+    }
 
-	@Override
-	public int getUpdateCount() {
-		return trackSegment.getUpdateCount();
-	}
+    @Override
+    public int getUpdateCount() {
+        return trackSegment.getUpdateCount();
+    }
 
 }
diff --git a/livegps/src/org/json/JSONArray.java b/livegps/src/org/json/JSONArray.java
index 5cc6f71..4730803 100644
--- a/livegps/src/org/json/JSONArray.java
+++ b/livegps/src/org/json/JSONArray.java
@@ -73,7 +73,7 @@ import java.util.Map;
  *     <code>false</code>, or <code>null</code>.</li>
  * <li>Values can be separated by <code>;</code> <small>(semicolon)</small> as
  *     well as by <code>,</code> <small>(comma)</small>.</li>
- * <li>Numbers may have the 
+ * <li>Numbers may have the
  *     <code>0x-</code> <small>(hex)</small> prefix.</li>
  * </ul>
 
@@ -163,17 +163,17 @@ public class JSONArray {
      * @param collection     A Collection.
      */
     public JSONArray(Collection collection) {
-		this.myArrayList = new ArrayList();
-		if (collection != null) {
-			Iterator iter = collection.iterator();
-			while (iter.hasNext()) {
-			    Object o = iter.next();
-                this.myArrayList.add(JSONObject.wrap(o));  
-			}
-		}
+        this.myArrayList = new ArrayList();
+        if (collection != null) {
+            Iterator iter = collection.iterator();
+            while (iter.hasNext()) {
+                Object o = iter.next();
+                this.myArrayList.add(JSONObject.wrap(o));
+            }
+        }
     }
 
-    
+
     /**
      * Construct a JSONArray from an array
      * @throws JSONException If not an array.
@@ -191,7 +191,7 @@ public class JSONArray {
         }
     }
 
-     
+
     /**
      * Get the object value associated with an index.
      * @param index
@@ -764,8 +764,8 @@ public class JSONArray {
         }
         return this;
     }
-    
-    
+
+
     /**
      * Remove an index and close the hole.
      * @param index The index of the element to be removed.
@@ -773,7 +773,7 @@ public class JSONArray {
      * or null if there was no value.
      */
     public Object remove(int index) {
-    	Object o = opt(index);
+        Object o = opt(index);
         this.myArrayList.remove(index);
         return o;
     }
diff --git a/livegps/src/org/json/JSONException.java b/livegps/src/org/json/JSONException.java
index 45e3b8d..0c0c207 100644
--- a/livegps/src/org/json/JSONException.java
+++ b/livegps/src/org/json/JSONException.java
@@ -7,10 +7,10 @@ package org.json;
  */
 public class JSONException extends Exception {
     /**
-	 * 
-	 */
-	private static final long serialVersionUID = 0;
-	private Throwable cause;
+     * 
+     */
+    private static final long serialVersionUID = 0;
+    private Throwable cause;
 
     /**
      * Constructs a JSONException with an explanatory message.
diff --git a/livegps/src/org/json/JSONObject.java b/livegps/src/org/json/JSONObject.java
index e34a752..e1194be 100644
--- a/livegps/src/org/json/JSONObject.java
+++ b/livegps/src/org/json/JSONObject.java
@@ -154,16 +154,16 @@ public class JSONObject {
      * Missing keys are ignored.
      * @param jo A JSONObject.
      * @param names An array of strings.
-     * @throws JSONException 
+     * @throws JSONException
      * @exception JSONException If a value is a non-finite number or if a name is duplicated.
      */
     public JSONObject(JSONObject jo, String[] names) {
         this();
         for (int i = 0; i < names.length; i += 1) {
-        	try {
-        		putOnce(names[i], jo.opt(names[i]));
-        	} catch (Exception ignore) {
-        	}
+            try {
+                putOnce(names[i], jo.opt(names[i]));
+            } catch (Exception ignore) {
+            }
         }
     }
 
@@ -234,7 +234,7 @@ public class JSONObject {
      *
      * @param map A map object that can be used to initialize the contents of
      *  the JSONObject.
-     * @throws JSONException 
+     * @throws JSONException
      */
     public JSONObject(Map map) {
         this.map = new HashMap();
@@ -454,7 +454,7 @@ public class JSONObject {
 
 
     /**
-     * Get the int value associated with a key. 
+     * Get the int value associated with a key.
      *
      * @param key   A key string.
      * @return      The integer value.
@@ -511,7 +511,7 @@ public class JSONObject {
 
 
     /**
-     * Get the long value associated with a key. 
+     * Get the long value associated with a key.
      *
      * @param key   A key string.
      * @return      The long value.
@@ -595,8 +595,8 @@ public class JSONObject {
     public boolean has(String key) {
         return this.map.containsKey(key);
     }
-    
-    
+
+
     /**
      * Increment a property of a JSONObject. If there is no such property,
      * create one with a value of 1. If there is such a property, and if
@@ -607,23 +607,23 @@ public class JSONObject {
      * that is not an Integer, Long, Double, or Float.
      */
     public JSONObject increment(String key) throws JSONException {
-    	Object value = opt(key);
-    	if (value == null) {
-    		put(key, 1);
-    	} else {
-    		if (value instanceof Integer) {
-    			put(key, ((Integer)value).intValue() + 1);
-    		} else if (value instanceof Long) {
-    			put(key, ((Long)value).longValue() + 1);    			
-    		} else if (value instanceof Double) {
-	    		put(key, ((Double)value).doubleValue() + 1);    			
-    		} else if (value instanceof Float) {
-	    		put(key, ((Float)value).floatValue() + 1);    			
-		    } else {
-		    	throw new JSONException("Unable to increment [" + key + "].");
-		    }
-	    }
-    	return this;
+        Object value = opt(key);
+        if (value == null) {
+            put(key, 1);
+        } else {
+            if (value instanceof Integer) {
+                put(key, ((Integer)value).intValue() + 1);
+            } else if (value instanceof Long) {
+                put(key, ((Long)value).longValue() + 1);
+            } else if (value instanceof Double) {
+                put(key, ((Double)value).doubleValue() + 1);
+            } else if (value instanceof Float) {
+                put(key, ((Float)value).floatValue() + 1);
+            } else {
+                throw new JSONException("Unable to increment [" + key + "].");
+            }
+        }
+        return this;
     }
 
 
@@ -902,7 +902,7 @@ public class JSONObject {
     private void populateMap(Object bean) {
         Class klass = bean.getClass();
 
-// If klass is a System class then set includeSuperClass to false. 
+// If klass is a System class then set includeSuperClass to false.
 
         boolean includeSuperClass = klass.getClassLoader() != null;
 
@@ -915,12 +915,12 @@ public class JSONObject {
                     String name = method.getName();
                     String key = "";
                     if (name.startsWith("get")) {
-                    	if (name.equals("getClass") || 
-                    			name.equals("getDeclaringClass")) {
-                    		key = "";
-                    	} else {
-                    		key = name.substring(3);
-                    	}
+                        if (name.equals("getClass") ||
+                                name.equals("getDeclaringClass")) {
+                            key = "";
+                        } else {
+                            key = name.substring(3);
+                        }
                     } else if (name.startsWith("is")) {
                         key = name.substring(2);
                     }
@@ -1198,8 +1198,8 @@ public class JSONObject {
         }
 
         /*
-         * If it might be a number, try converting it. 
-         * We support the non-standard 0x- convention. 
+         * If it might be a number, try converting it.
+         * We support the non-standard 0x- convention.
          * If a number cannot be produced, then the value will just
          * be a string. Note that the 0x-, plus, and implied string
          * conventions are non-standard. A JSON parser may accept
@@ -1216,8 +1216,8 @@ public class JSONObject {
                 }
             }
             try {
-                if (s.indexOf('.') > -1 || 
-                		s.indexOf('e') > -1 || s.indexOf('E') > -1) {
+                if (s.indexOf('.') > -1 ||
+                        s.indexOf('e') > -1 || s.indexOf('E') > -1) {
                     return Double.valueOf(s);
                 } else {
                     Long myLong = new Long(s);
@@ -1494,11 +1494,11 @@ public class JSONObject {
 
 
      /**
-      * Wrap an object, if necessary. If the object is null, return the NULL 
-      * object. If it is an array or collection, wrap it in a JSONArray. If 
-      * it is a map, wrap it in a JSONObject. If it is a standard property 
-      * (Double, String, et al) then it is already wrapped. Otherwise, if it 
-      * comes from one of the java packages, turn it into a string. And if 
+      * Wrap an object, if necessary. If the object is null, return the NULL
+      * object. If it is an array or collection, wrap it in a JSONArray. If
+      * it is a map, wrap it in a JSONObject. If it is a standard property
+      * (Double, String, et al) then it is already wrapped. Otherwise, if it
+      * comes from one of the java packages, turn it into a string. And if
       * it doesn't, try to wrap it in a JSONObject. If the wrapping fails,
       * then null is returned.
       *
@@ -1510,16 +1510,16 @@ public class JSONObject {
              if (object == null) {
                  return NULL;
              }
-             if (object instanceof JSONObject || object instanceof JSONArray || 
-            		 NULL.equals(object)      || object instanceof JSONString || 
-            		 object instanceof Byte   || object instanceof Character ||
+             if (object instanceof JSONObject || object instanceof JSONArray ||
+                     NULL.equals(object)      || object instanceof JSONString ||
+                     object instanceof Byte   || object instanceof Character ||
                      object instanceof Short  || object instanceof Integer   ||
-                     object instanceof Long   || object instanceof Boolean   || 
+                     object instanceof Long   || object instanceof Boolean   ||
                      object instanceof Float  || object instanceof Double    ||
                      object instanceof String) {
                  return object;
              }
-             
+
              if (object instanceof Collection) {
                  return new JSONArray((Collection)object);
              }
@@ -1532,8 +1532,8 @@ public class JSONObject {
              Package objectPackage = object.getClass().getPackage();
              String objectPackageName = ( objectPackage != null ? objectPackage.getName() : "" );
              if (objectPackageName.startsWith("java.") ||
-            		 objectPackageName.startsWith("javax.") ||
-            		 object.getClass().getClassLoader() == null) {
+                     objectPackageName.startsWith("javax.") ||
+                     object.getClass().getClassLoader() == null) {
                  return object.toString();
              }
              return new JSONObject(object);
@@ -1542,7 +1542,7 @@ public class JSONObject {
          }
      }
 
-     
+
      /**
       * Write the contents of the JSONObject as JSON text to a writer.
       * For compactness, no whitespace is added.
diff --git a/livegps/src/org/json/JSONString.java b/livegps/src/org/json/JSONString.java
index 17f4384..41726b1 100644
--- a/livegps/src/org/json/JSONString.java
+++ b/livegps/src/org/json/JSONString.java
@@ -8,11 +8,11 @@ package org.json;
  * of using the Object's <code>toString()</code> method and quoting the result.
  */
 public interface JSONString {
-	/**
-	 * The <code>toJSONString</code> method allows a class to produce its own JSON 
-	 * serialization. 
-	 * 
-	 * @return A strictly syntactically correct JSON text.
-	 */
-	public String toJSONString();
+    /**
+     * The <code>toJSONString</code> method allows a class to produce its own JSON 
+     * serialization. 
+     * 
+     * @return A strictly syntactically correct JSON text.
+     */
+    public String toJSONString();
 }
diff --git a/livegps/src/org/json/JSONTokener.java b/livegps/src/org/json/JSONTokener.java
index fe52f31..13d8936 100644
--- a/livegps/src/org/json/JSONTokener.java
+++ b/livegps/src/org/json/JSONTokener.java
@@ -38,12 +38,12 @@ SOFTWARE.
  */
 public class JSONTokener {
 
-    private int 	character;
-	private boolean eof;
-    private int 	index;
-    private int 	line;
-    private char 	previous;
-    private Reader 	reader;
+    private int     character;
+    private boolean eof;
+    private int     index;
+    private int     line;
+    private char    previous;
+    private Reader  reader;
     private boolean usePrevious;
 
 
@@ -53,8 +53,8 @@ public class JSONTokener {
      * @param reader     A reader.
      */
     public JSONTokener(Reader reader) {
-        this.reader = reader.markSupported() ? 
-        		reader : new BufferedReader(reader);
+        this.reader = reader.markSupported() ?
+                reader : new BufferedReader(reader);
         this.eof = false;
         this.usePrevious = false;
         this.previous = 0;
@@ -108,9 +108,9 @@ public class JSONTokener {
         }
         return -1;
     }
-    
+
     public boolean end() {
-    	return eof && !usePrevious;    	
+        return eof && !usePrevious;
     }
 
 
@@ -123,7 +123,7 @@ public class JSONTokener {
         next();
         if (end()) {
             return false;
-        } 
+        }
         back();
         return true;
     }
@@ -137,31 +137,31 @@ public class JSONTokener {
     public char next() throws JSONException {
         int c;
         if (this.usePrevious) {
-        	this.usePrevious = false;
+            this.usePrevious = false;
             c = this.previous;
         } else {
-	        try {
-	            c = this.reader.read();
-	        } catch (IOException exception) {
-	            throw new JSONException(exception);
-	        }
-	
-	        if (c <= 0) { // End of stream
-	        	this.eof = true;
-	        	c = 0;
-	        } 
+            try {
+                c = this.reader.read();
+            } catch (IOException exception) {
+                throw new JSONException(exception);
+            }
+
+            if (c <= 0) { // End of stream
+                this.eof = true;
+                c = 0;
+            }
         }
-    	this.index += 1;
-    	if (this.previous == '\r') {
-    		this.line += 1;
-    		this.character = c == '\n' ? 0 : 1;
-    	} else if (c == '\n') {
-    		this.line += 1;
-    		this.character = 0;
-    	} else {
-    		this.character += 1;
-    	}
-    	this.previous = (char) c;
+        this.index += 1;
+        if (this.previous == '\r') {
+            this.line += 1;
+            this.character = c == '\n' ? 0 : 1;
+        } else if (c == '\n') {
+            this.line += 1;
+            this.character = 0;
+        } else {
+            this.character += 1;
+        }
+        this.previous = (char) c;
         return this.previous;
     }
 
@@ -203,7 +203,7 @@ public class JSONTokener {
          while (pos < n) {
              buffer[pos] = next();
              if (end()) {
-                 throw syntaxError("Substring bounds error");                 
+                 throw syntaxError("Substring bounds error");
              }
              pos += 1;
          }
@@ -272,8 +272,8 @@ public class JSONTokener {
                 case '\'':
                 case '\\':
                 case '/':
-                	sb.append(c);
-                	break;
+                    sb.append(c);
+                    break;
                 default:
                     throw syntaxError("Illegal escape.");
                 }
@@ -411,7 +411,7 @@ public class JSONTokener {
         back();
         return c;
     }
-    
+
 
     /**
      * Make a JSONException to signal a syntax error.
diff --git a/measurement/.classpath b/measurement/.classpath
index 17b8e6a..875df1c 100644
--- a/measurement/.classpath
+++ b/measurement/.classpath
@@ -1,6 +1,7 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <classpath>
 	<classpathentry kind="src" path="src"/>
+	<classpathentry including="images/" kind="src" path=""/>
 	<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JDK 5"/>
 	<classpathentry combineaccessrules="false" kind="src" path="/JOSM"/>
 	<classpathentry kind="output" path="build"/>
diff --git a/measurement/josm-measurement.launch b/measurement/josm-measurement.launch
new file mode 100644
index 0000000..0b704cf
--- /dev/null
+++ b/measurement/josm-measurement.launch
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<launchConfiguration type="org.eclipse.jdt.launching.localJavaApplication">
+<listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_PATHS">
+<listEntry value="/JOSM/src/org/openstreetmap/josm/gui/MainApplication.java"/>
+</listAttribute>
+<listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_TYPES">
+<listEntry value="1"/>
+</listAttribute>
+<stringAttribute key="org.eclipse.jdt.launching.JRE_CONTAINER" value="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JDK 6"/>
+<stringAttribute key="org.eclipse.jdt.launching.MAIN_TYPE" value="org.openstreetmap.josm.gui.MainApplication"/>
+<stringAttribute key="org.eclipse.jdt.launching.PROJECT_ATTR" value="JOSM-Measurement"/>
+</launchConfiguration>
diff --git a/measurement/src/org/openstreetmap/josm/plugins/measurement/MeasurementPlugin.java b/measurement/src/org/openstreetmap/josm/plugins/measurement/MeasurementPlugin.java
index 527db86..6171d04 100644
--- a/measurement/src/org/openstreetmap/josm/plugins/measurement/MeasurementPlugin.java
+++ b/measurement/src/org/openstreetmap/josm/plugins/measurement/MeasurementPlugin.java
@@ -19,7 +19,7 @@ public class MeasurementPlugin extends Plugin {
     protected static MeasurementLayer currentLayer;
 
     public MeasurementPlugin(PluginInformation info) {
-    	super(info);
+        super(info);
         mode = new MeasurementMode(Main.map, "measurement", tr("measurement mode"));
         btn = new IconToggleButton(mode);
         btn.setVisible(true);
@@ -46,8 +46,8 @@ public class MeasurementPlugin extends Plugin {
                 public void layerAdded(final Layer newLayer) {
                 }
                 public void layerRemoved(final Layer oldLayer) {
-                	if (oldLayer != null && oldLayer == currentLayer)
-                		MapView.removeLayerChangeListener(this);
+                    if (oldLayer != null && oldLayer == currentLayer)
+                        MapView.removeLayerChangeListener(this);
                 }
             });
         }
diff --git a/openvisible/src/at/dallermassl/josm/plugin/openvisible/OpenVisibleAction.java b/openvisible/src/at/dallermassl/josm/plugin/openvisible/OpenVisibleAction.java
index 4f13c00..905e351 100644
--- a/openvisible/src/at/dallermassl/josm/plugin/openvisible/OpenVisibleAction.java
+++ b/openvisible/src/at/dallermassl/josm/plugin/openvisible/OpenVisibleAction.java
@@ -97,7 +97,7 @@ public class OpenVisibleAction extends JosmAction {
             } catch (SAXException e1) {
                 e1.printStackTrace();
             } catch(IllegalDataException e1) {
-            	e1.printStackTrace();
+                e1.printStackTrace();
             }
         }
 
@@ -127,7 +127,7 @@ public class OpenVisibleAction extends JosmAction {
                 // input was not properly parsed, abort
                 JOptionPane.showMessageDialog(Main.parent, tr("Parsing file \"{0}\" failed", file));
                 throw new IllegalStateException();
-            }				
+            }
             r.data.storageFile = file;
             GpxLayer gpxLayer = new GpxLayer(r.data, fn);
             Main.main.addLayer(gpxLayer);
diff --git a/remotecontrol/src/org/openstreetmap/josm/plugins/remotecontrol/PermissionPref.java b/remotecontrol/src/org/openstreetmap/josm/plugins/remotecontrol/PermissionPref.java
index b1d8eb0..dda51f2 100644
--- a/remotecontrol/src/org/openstreetmap/josm/plugins/remotecontrol/PermissionPref.java
+++ b/remotecontrol/src/org/openstreetmap/josm/plugins/remotecontrol/PermissionPref.java
@@ -6,19 +6,19 @@ package org.openstreetmap.josm.plugins.remotecontrol;
  * if not permitted.
  *
  * Use @see PermissionPrefWithDefault instead of this class.
- * 
+ *
  * @author Bodo Meissner
  */
  @Deprecated
 public class PermissionPref {
-	/** name of the preference setting to permit the remote operation */
-	String pref;
-	/** message to be displayed if operation is not permitted */
-	String message;
-	
-	public PermissionPref(String pref, String message)
-	{
-		this.pref = pref;
-		this.message = message;
-	}
+    /** name of the preference setting to permit the remote operation */
+    String pref;
+    /** message to be displayed if operation is not permitted */
+    String message;
+
+    public PermissionPref(String pref, String message)
+    {
+        this.pref = pref;
+        this.message = message;
+    }
 }
\ No newline at end of file
diff --git a/remotecontrol/src/org/openstreetmap/josm/plugins/remotecontrol/PermissionPrefWithDefault.java b/remotecontrol/src/org/openstreetmap/josm/plugins/remotecontrol/PermissionPrefWithDefault.java
index 83a2f3d..372130b 100644
--- a/remotecontrol/src/org/openstreetmap/josm/plugins/remotecontrol/PermissionPrefWithDefault.java
+++ b/remotecontrol/src/org/openstreetmap/josm/plugins/remotecontrol/PermissionPrefWithDefault.java
@@ -1,22 +1,22 @@
 package org.openstreetmap.josm.plugins.remotecontrol;
 
 /**
- * This class should replace PermissionPref because it allows explicit 
+ * This class should replace PermissionPref because it allows explicit
  * specification of the permission's default value.
- * 
+ *
  * @author Bodo Meissner
  */
 @SuppressWarnings("deprecation")
 public class PermissionPrefWithDefault extends PermissionPref {
 
-	boolean defaultVal = true;
+    boolean defaultVal = true;
 
-	public PermissionPrefWithDefault(String pref, boolean defaultVal, String message) {
-		super(pref, message);
-		this.defaultVal = defaultVal;
-	}
+    public PermissionPrefWithDefault(String pref, boolean defaultVal, String message) {
+        super(pref, message);
+        this.defaultVal = defaultVal;
+    }
 
-	public PermissionPrefWithDefault(PermissionPref prefWithoutDefault) {
-		super(prefWithoutDefault.pref, prefWithoutDefault.message);
-	}
+    public PermissionPrefWithDefault(PermissionPref prefWithoutDefault) {
+        super(prefWithoutDefault.pref, prefWithoutDefault.message);
+    }
 }
diff --git a/remotecontrol/src/org/openstreetmap/josm/plugins/remotecontrol/RemoteControlPlugin.java b/remotecontrol/src/org/openstreetmap/josm/plugins/remotecontrol/RemoteControlPlugin.java
index fe90e82..380403c 100644
--- a/remotecontrol/src/org/openstreetmap/josm/plugins/remotecontrol/RemoteControlPlugin.java
+++ b/remotecontrol/src/org/openstreetmap/josm/plugins/remotecontrol/RemoteControlPlugin.java
@@ -7,61 +7,61 @@ import org.openstreetmap.josm.plugins.Plugin;
 import org.openstreetmap.josm.plugins.PluginInformation;
 
 /**
- * Base plugin for remote control operations. 
+ * Base plugin for remote control operations.
  * This plugin contains operations that use JOSM core only.
- * 
- * Other plugins can register additional operations by calling 
+ *
+ * Other plugins can register additional operations by calling
  * @see addRequestHandler().
  * To allow API changes this plugin contains a @see getVersion() method.
- * 
+ *
  * IMPORTANT! increment the minor version on compatible API extensions
  * and increment the major version and set minor to 0 on incompatible changes.
  */
 public class RemoteControlPlugin extends Plugin
 {
-	/** API version
-	 * IMPORTANT! update the version number on API changes.
-	 */
-	static final int apiMajorVersion = 1;
-	static final int apiMinorVersion = 0;
-	
-	/**
-	 * RemoteControl HTTP protocol version. Change minor number for compatible
-	 * interface extensions. Change major number in case of incompatible
-	 * changes.
-	 */
-	static final int protocolMajorVersion = 1;
-	static final int protocolMinorVersion = 2;
-	
+    /** API version
+     * IMPORTANT! update the version number on API changes.
+     */
+    static final int apiMajorVersion = 1;
+    static final int apiMinorVersion = 0;
+
+    /**
+     * RemoteControl HTTP protocol version. Change minor number for compatible
+     * interface extensions. Change major number in case of incompatible
+     * changes.
+     */
+    static final int protocolMajorVersion = 1;
+    static final int protocolMinorVersion = 2;
+
     /** The HTTP server this plugin launches */
     static HttpServer server;
 
     /**
-     * Returns an array of int values with major and minor API version 
+     * Returns an array of int values with major and minor API version
      * and major and minor HTTP protocol version.
-     *  
+     *
      * The function returns an int[4] instead of an object with fields
      * to avoid ClassNotFound errors with old versions of remotecontrol.
-     *  
-     * @return array of integer version numbers: 
+     *
+     * @return array of integer version numbers:
      *    apiMajorVersion, apiMinorVersion, protocolMajorVersion, protocolMajorVersion
      */
     public int[] getVersion()
     {
-    	int versions[] = {apiMajorVersion, apiMinorVersion, protocolMajorVersion, protocolMajorVersion};
-    	return versions;
+        int versions[] = {apiMajorVersion, apiMinorVersion, protocolMajorVersion, protocolMajorVersion};
+        return versions;
     }
-    
+
     /**
      * Creates the plugin, and starts the HTTP server
      */
     public RemoteControlPlugin(PluginInformation info)
     {
-    	super(info);
-    	/*
-		System.out.println("constructor " + this.getClass().getName() + " (" + info.name +
-				" v " + info.version + " stage " + info.stage + ")");
-		*/
+        super(info);
+        /*
+        System.out.println("constructor " + this.getClass().getName() + " (" + info.name +
+                " v " + info.version + " stage " + info.stage + ")");
+        */
         restartServer();
     }
 
@@ -102,5 +102,5 @@ public class RemoteControlPlugin extends Plugin
     {
         RequestProcessor.addRequestHandlerClass(command, handlerClass);
     }
-    
+
 }
diff --git a/remotecontrol/src/org/openstreetmap/josm/plugins/remotecontrol/RequestHandler.java b/remotecontrol/src/org/openstreetmap/josm/plugins/remotecontrol/RequestHandler.java
index 2a2175d..4f4cc24 100644
--- a/remotecontrol/src/org/openstreetmap/josm/plugins/remotecontrol/RequestHandler.java
+++ b/remotecontrol/src/org/openstreetmap/josm/plugins/remotecontrol/RequestHandler.java
@@ -10,20 +10,20 @@ import javax.swing.JOptionPane;
 import org.openstreetmap.josm.Main;
 
 /**
- * This is the parent of all classes that handle a specific command 
+ * This is the parent of all classes that handle a specific command
  * in remote control plug-in.
- *   
+ *
  * @author Bodo Meissner
  */
 public abstract class RequestHandler
 {
-	public static final String globalConfirmationKey = "remotecontrol.always-confirm";
-	public static final boolean globalConfirmationDefault = false;
-	
-	/** The GET request arguments */
-	protected HashMap<String,String> args;
-	
-	/** The request URL without "GET". */
+    public static final String globalConfirmationKey = "remotecontrol.always-confirm";
+    public static final boolean globalConfirmationDefault = false;
+
+    /** The GET request arguments */
+    protected HashMap<String,String> args;
+
+    /** The request URL without "GET". */
     protected String request;
 
     /** default response */
@@ -33,38 +33,38 @@ public abstract class RequestHandler
 
     /** will be filled with the command assigned to the subclass */
     protected String myCommand;
-    
+
     /**
      * Check permission and parameters and handle request.
-     * 
+     *
      * @throws RequestHandlerForbiddenException
      * @throws RequestHandlerBadRequestException
      * @throws RequestHandlerErrorException
      */
     final void handle() throws RequestHandlerForbiddenException, RequestHandlerBadRequestException, RequestHandlerErrorException
     {
-    	checkPermission();
-    	checkMandatoryParams();
-    	handleRequest();
+        checkPermission();
+        checkMandatoryParams();
+        handleRequest();
     }
-    
+
     /**
      * Handle a specific command sent as remote control.
-     * 
-     * This method of the subclass will do the real work.  
-     * 
+     *
+     * This method of the subclass will do the real work.
+     *
      * @throws RequestHandlerErrorException
-     * @throws RequestHandlerBadRequestException 
+     * @throws RequestHandlerBadRequestException
      */
     protected abstract void handleRequest() throws RequestHandlerErrorException, RequestHandlerBadRequestException;
 
     /**
      * Get a specific message to ask the user for permission for the operation
      * requested via remote control.
-     * 
+     *
      * This message will be displayed to the user if the preference
      * remotecontrol.always-confirm is true.
-     * 
+     *
      * @return the message
      */
     abstract public String getPermissionMessage();
@@ -73,14 +73,14 @@ public abstract class RequestHandler
      * Get a PermissionPref object containing the name of a special permission
      * preference to individually allow the requested operation and an error
      * message to be displayed when a disabled operation is requested.
-     * 
-     * Default is not to check any special preference. Override this in a 
+     *
+     * Default is not to check any special preference. Override this in a
      * subclass to define permission preference and error message.
-     * 
+     *
      * @return the preference name and error message or null
      */
-	@SuppressWarnings("deprecation")
-	public PermissionPref getPermissionPref()
+    @SuppressWarnings("deprecation")
+    public PermissionPref getPermissionPref()
     {
         /* Example:
         return new PermissionPrefWithDefault("fooobar.remotecontrol",
@@ -92,22 +92,22 @@ public abstract class RequestHandler
 
     protected String[] getMandatoryParams()
     {
-    	return null;
+        return null;
     }
-    
+
     /**
-     * Check permissions in preferences and display error message 
+     * Check permissions in preferences and display error message
      * or ask for permission.
-     * 
+     *
      * @throws RequestHandlerForbiddenException
      */
     @SuppressWarnings("deprecation")
-	final public void checkPermission() throws RequestHandlerForbiddenException
+    final public void checkPermission() throws RequestHandlerForbiddenException
     {
-        /* 
+        /*
          * If the subclass defines a specific preference and if this is set
          * to false, abort with an error message.
-         * 
+         *
          * Note: we use the deprecated class here for compatibility with
          * older versions of WMSPlugin.
          */
@@ -117,14 +117,14 @@ public abstract class RequestHandler
             PermissionPrefWithDefault permissionPrefWithDefault;
             if(permissionPref instanceof PermissionPrefWithDefault)
             {
-            	permissionPrefWithDefault = (PermissionPrefWithDefault) permissionPref;
+                permissionPrefWithDefault = (PermissionPrefWithDefault) permissionPref;
             }
-            else 
+            else
             {
-            	permissionPrefWithDefault = new PermissionPrefWithDefault(permissionPref);
+                permissionPrefWithDefault = new PermissionPrefWithDefault(permissionPref);
             }
             if (!Main.pref.getBoolean(permissionPrefWithDefault.pref,
-            		permissionPrefWithDefault.defaultVal)) {
+                    permissionPrefWithDefault.defaultVal)) {
                 System.out.println(permissionPrefWithDefault.message);
                 throw new RequestHandlerForbiddenException();
             }
@@ -146,62 +146,62 @@ public abstract class RequestHandler
 
     /**
      * Set request URL and parse args.
-     * 
+     *
      * @param url The request URL.
      */
-	public void setUrl(String url) {
-		this.request = url;
-		parseArgs();
-	}
-
-	/**
-	 * Parse the request parameters as key=value pairs.
-	 * The result will be stored in this.args.
-	 * 
-	 * Can be overridden by subclass.
-	 */
-	protected void parseArgs() {
-		StringTokenizer st = new StringTokenizer(this.request, "&?");
-		HashMap<String, String> args = new HashMap<String, String>();
-		// ignore first token which is the command
-		if(st.hasMoreTokens()) st.nextToken();
-		while (st.hasMoreTokens()) {
-			String param = st.nextToken();
-			int eq = param.indexOf("=");
-			if (eq > -1)
-				args.put(param.substring(0, eq),
+    public void setUrl(String url) {
+        this.request = url;
+        parseArgs();
+    }
+
+    /**
+     * Parse the request parameters as key=value pairs.
+     * The result will be stored in this.args.
+     *
+     * Can be overridden by subclass.
+     */
+    protected void parseArgs() {
+        StringTokenizer st = new StringTokenizer(this.request, "&?");
+        HashMap<String, String> args = new HashMap<String, String>();
+        // ignore first token which is the command
+        if(st.hasMoreTokens()) st.nextToken();
+        while (st.hasMoreTokens()) {
+            String param = st.nextToken();
+            int eq = param.indexOf("=");
+            if (eq > -1)
+                args.put(param.substring(0, eq),
                          param.substring(eq + 1));
-		}
-		this.args = args;
-	}
-	
-	void checkMandatoryParams() throws RequestHandlerBadRequestException
-	{
-		String[] mandatory = getMandatoryParams();
-		if(mandatory == null) return;
-		
-		boolean error = false;
-		for(int i = 0; i < mandatory.length; ++i)
-		{
-			String key = mandatory[i];
-			String value = args.get(key);
-			if((value == null) || (value.length() == 0))
-			{
-				error = true;
-				System.out.println("'" + myCommand + "' remote control request must have '" + key + "' parameter");
-			}
-		}
-		if(error) throw new RequestHandlerBadRequestException();
-	}
-	
-	/**
-	 * Save command associated with this handler.
-	 * 
-	 * @param command The command.
-	 */
-	public void setCommand(String command)
-	{
-		if(command.charAt(0) == '/') command = command.substring(1);
-		myCommand = command;
-	}
+        }
+        this.args = args;
+    }
+
+    void checkMandatoryParams() throws RequestHandlerBadRequestException
+    {
+        String[] mandatory = getMandatoryParams();
+        if(mandatory == null) return;
+
+        boolean error = false;
+        for(int i = 0; i < mandatory.length; ++i)
+        {
+            String key = mandatory[i];
+            String value = args.get(key);
+            if((value == null) || (value.length() == 0))
+            {
+                error = true;
+                System.out.println("'" + myCommand + "' remote control request must have '" + key + "' parameter");
+            }
+        }
+        if(error) throw new RequestHandlerBadRequestException();
+    }
+
+    /**
+     * Save command associated with this handler.
+     *
+     * @param command The command.
+     */
+    public void setCommand(String command)
+    {
+        if(command.charAt(0) == '/') command = command.substring(1);
+        myCommand = command;
+    }
 }
\ No newline at end of file
diff --git a/remotecontrol/src/org/openstreetmap/josm/plugins/remotecontrol/RequestHandlerForbiddenException.java b/remotecontrol/src/org/openstreetmap/josm/plugins/remotecontrol/RequestHandlerForbiddenException.java
index 38d9fe4..250d98b 100644
--- a/remotecontrol/src/org/openstreetmap/josm/plugins/remotecontrol/RequestHandlerForbiddenException.java
+++ b/remotecontrol/src/org/openstreetmap/josm/plugins/remotecontrol/RequestHandlerForbiddenException.java
@@ -1,5 +1,5 @@
 package org.openstreetmap.josm.plugins.remotecontrol;
 
 public class RequestHandlerForbiddenException extends RequestHandlerException {
-	private static final long serialVersionUID = 2263904699747115423L;
+    private static final long serialVersionUID = 2263904699747115423L;
 }
diff --git a/remotecontrol/src/org/openstreetmap/josm/plugins/remotecontrol/RequestProcessor.java b/remotecontrol/src/org/openstreetmap/josm/plugins/remotecontrol/RequestProcessor.java
index 5fcc818..a0e5275 100644
--- a/remotecontrol/src/org/openstreetmap/josm/plugins/remotecontrol/RequestProcessor.java
+++ b/remotecontrol/src/org/openstreetmap/josm/plugins/remotecontrol/RequestProcessor.java
@@ -22,287 +22,287 @@ import org.openstreetmap.josm.plugins.remotecontrol.handler.VersionHandler;
  * Processes HTTP "remote control" requests.
  */
 public class RequestProcessor extends Thread {
-	/**
-	 * RemoteControl protocol version. Change minor number for compatible
-	 * interface extensions. Change major number in case of incompatible
-	 * changes.
-	 */
-	public static final String PROTOCOLVERSION = "{\"protocolversion\": {\"major\": " +
-		RemoteControlPlugin.protocolMajorVersion + ", \"minor\": " + 
-		RemoteControlPlugin.protocolMinorVersion +
-		"}, \"application\": \"JOSM RemoteControl\"}";
+    /**
+     * RemoteControl protocol version. Change minor number for compatible
+     * interface extensions. Change major number in case of incompatible
+     * changes.
+     */
+    public static final String PROTOCOLVERSION = "{\"protocolversion\": {\"major\": " +
+        RemoteControlPlugin.protocolMajorVersion + ", \"minor\": " +
+        RemoteControlPlugin.protocolMinorVersion +
+        "}, \"application\": \"JOSM RemoteControl\"}";
 
-	/** The socket this processor listens on */
-	private Socket request;
+    /** The socket this processor listens on */
+    private Socket request;
 
-	/**
-	 * Collection of request handlers.
-	 * Will be initialized with default handlers here. Other plug-ins
-	 * can extend this list by using @see addRequestHandler 
-	 */
-	private static HashMap<String, Class<? extends RequestHandler>> handlers = new HashMap<String, Class<? extends RequestHandler>>();
+    /**
+     * Collection of request handlers.
+     * Will be initialized with default handlers here. Other plug-ins
+     * can extend this list by using @see addRequestHandler
+     */
+    private static HashMap<String, Class<? extends RequestHandler>> handlers = new HashMap<String, Class<? extends RequestHandler>>();
 
-	/**
-	 * Constructor
-	 * 
-	 * @param request A socket to read the request.
-	 */
-	public RequestProcessor(Socket request) {
-		super("RemoteControl request processor");
-		this.setDaemon(true);
-		this.request = request;
-	}
+    /**
+     * Constructor
+     *
+     * @param request A socket to read the request.
+     */
+    public RequestProcessor(Socket request) {
+        super("RemoteControl request processor");
+        this.setDaemon(true);
+        this.request = request;
+    }
 
-	/**
-	 * Spawns a new thread for the request
-	 * 
-	 * @param request
-	 *            The WMS request
-	 */
-	public static void processRequest(Socket request) {
-		RequestProcessor processor = new RequestProcessor(request);
-		processor.start();
-	}
+    /**
+     * Spawns a new thread for the request
+     *
+     * @param request
+     *            The WMS request
+     */
+    public static void processRequest(Socket request) {
+        RequestProcessor processor = new RequestProcessor(request);
+        processor.start();
+    }
 
-	/**
-	 * Add external request handler. Can be used by other plug-ins that
-	 * want to use remote control.
-	 * @param command The command to handle.
-	 * @param handler The additional request handler.
-	 */
-	static void addRequestHandlerClass(String command,
-			Class<? extends RequestHandler> handler) {
-		addRequestHandlerClass(command, handler, false);
-	}
+    /**
+     * Add external request handler. Can be used by other plug-ins that
+     * want to use remote control.
+     * @param command The command to handle.
+     * @param handler The additional request handler.
+     */
+    static void addRequestHandlerClass(String command,
+            Class<? extends RequestHandler> handler) {
+        addRequestHandlerClass(command, handler, false);
+    }
 
-	/**
-	 * Add external request handler. Message can be suppressed.
-	 * (for internal use)
-	 * @param command The command to handle.
-	 * @param handler The additional request handler.
-	 * @param silent Don't show message if true.
-	 */
-	private static void addRequestHandlerClass(String command,
-				Class<? extends RequestHandler> handler, boolean silent) {
-		if(command.charAt(0) == '/')
-		{
-			command = command.substring(1);
-		}
-		String commandWithSlash = "/" + command;
-		if (handlers.get(commandWithSlash) != null) {
-			System.out.println("RemoteControl: ignoring duplicate command " + command
-					+ " with handler " + handler.getName());
-		} else {
-			if(!silent) System.out.println("RemoteControl: adding command \"" + 
-					command + "\" (handled by " + handler.getSimpleName() + ")");
-			handlers.put(commandWithSlash, handler);
-		}
-	}
+    /**
+     * Add external request handler. Message can be suppressed.
+     * (for internal use)
+     * @param command The command to handle.
+     * @param handler The additional request handler.
+     * @param silent Don't show message if true.
+     */
+    private static void addRequestHandlerClass(String command,
+                Class<? extends RequestHandler> handler, boolean silent) {
+        if(command.charAt(0) == '/')
+        {
+            command = command.substring(1);
+        }
+        String commandWithSlash = "/" + command;
+        if (handlers.get(commandWithSlash) != null) {
+            System.out.println("RemoteControl: ignoring duplicate command " + command
+                    + " with handler " + handler.getName());
+        } else {
+            if(!silent) System.out.println("RemoteControl: adding command \"" +
+                    command + "\" (handled by " + handler.getSimpleName() + ")");
+            handlers.put(commandWithSlash, handler);
+        }
+    }
 
-	/** Add default request handlers */
-	static {
-		addRequestHandlerClass(LoadAndZoomHandler.command,
-				LoadAndZoomHandler.class, true);
-		addRequestHandlerClass(LoadAndZoomHandler.command2,
-				LoadAndZoomHandler.class, true);
-		addRequestHandlerClass(AddNodeHandler.command, AddNodeHandler.class, true);
-		addRequestHandlerClass(ImportHandler.command, ImportHandler.class, true);
-		addRequestHandlerClass(VersionHandler.command, VersionHandler.class, true);
-	}
+    /** Add default request handlers */
+    static {
+        addRequestHandlerClass(LoadAndZoomHandler.command,
+                LoadAndZoomHandler.class, true);
+        addRequestHandlerClass(LoadAndZoomHandler.command2,
+                LoadAndZoomHandler.class, true);
+        addRequestHandlerClass(AddNodeHandler.command, AddNodeHandler.class, true);
+        addRequestHandlerClass(ImportHandler.command, ImportHandler.class, true);
+        addRequestHandlerClass(VersionHandler.command, VersionHandler.class, true);
+    }
 
-	/**
-	 * The work is done here.
-	 */
-	public void run() {
-		Writer out = null;
-		try {
-			OutputStream raw = new BufferedOutputStream(
-					request.getOutputStream());
-			out = new OutputStreamWriter(raw);
-			Reader in = new InputStreamReader(new BufferedInputStream(
-					request.getInputStream()), "ASCII");
+    /**
+     * The work is done here.
+     */
+    public void run() {
+        Writer out = null;
+        try {
+            OutputStream raw = new BufferedOutputStream(
+                    request.getOutputStream());
+            out = new OutputStreamWriter(raw);
+            Reader in = new InputStreamReader(new BufferedInputStream(
+                    request.getInputStream()), "ASCII");
 
-			StringBuffer requestLine = new StringBuffer();
-			while (requestLine.length() < 1024) {
-				int c = in.read();
-				if (c == '\r' || c == '\n')
-					break;
-				requestLine.append((char) c);
-			}
+            StringBuffer requestLine = new StringBuffer();
+            while (requestLine.length() < 1024) {
+                int c = in.read();
+                if (c == '\r' || c == '\n')
+                    break;
+                requestLine.append((char) c);
+            }
 
-			System.out.println("RemoteControl received: " + requestLine);
-			String get = requestLine.toString();
-			StringTokenizer st = new StringTokenizer(get);
-			if (!st.hasMoreTokens()) {
-				sendError(out);
-				return;
-			}
-			String method = st.nextToken();
-			if (!st.hasMoreTokens()) {
-				sendError(out);
-				return;
-			}
-			String url = st.nextToken();
+            System.out.println("RemoteControl received: " + requestLine);
+            String get = requestLine.toString();
+            StringTokenizer st = new StringTokenizer(get);
+            if (!st.hasMoreTokens()) {
+                sendError(out);
+                return;
+            }
+            String method = st.nextToken();
+            if (!st.hasMoreTokens()) {
+                sendError(out);
+                return;
+            }
+            String url = st.nextToken();
 
-			if (!method.equals("GET")) {
-				sendNotImplemented(out);
-				return;
-			}
+            if (!method.equals("GET")) {
+                sendNotImplemented(out);
+                return;
+            }
 
-			String command = null;
-			int questionPos = url.indexOf('?');
-			if(questionPos < 0)
-			{
-				command = url;
-			}
-			else
-			{
-				command = url.substring(0, questionPos);
-			}
+            String command = null;
+            int questionPos = url.indexOf('?');
+            if(questionPos < 0)
+            {
+                command = url;
+            }
+            else
+            {
+                command = url.substring(0, questionPos);
+            }
 
-			// find a handler for this command
-			Class<? extends RequestHandler> handlerClass = handlers
-					.get(command);
-			if (handlerClass == null) {
-				// no handler found
-				sendBadRequest(out);
-			} else {
-				// create handler object
-				RequestHandler handler = handlerClass.newInstance();
-				try {
-					handler.setCommand(command);
-					handler.setUrl(url);
-					handler.checkPermission();
-					handler.handle();
-					sendHeader(out, "200 OK", handler.contentType, false);
-					out.write("Content-length: " + handler.content.length()
-							+ "\r\n");
-					out.write("\r\n");
-					out.write(handler.content);
-					out.flush();
-				} catch (RequestHandlerErrorException ex) {
-					sendError(out);
-				} catch (RequestHandlerBadRequestException ex) {
-					sendBadRequest(out);
-				} catch (RequestHandlerForbiddenException ex) {
-					sendForbidden(out);
-				}
-			}
+            // find a handler for this command
+            Class<? extends RequestHandler> handlerClass = handlers
+                    .get(command);
+            if (handlerClass == null) {
+                // no handler found
+                sendBadRequest(out);
+            } else {
+                // create handler object
+                RequestHandler handler = handlerClass.newInstance();
+                try {
+                    handler.setCommand(command);
+                    handler.setUrl(url);
+                    handler.checkPermission();
+                    handler.handle();
+                    sendHeader(out, "200 OK", handler.contentType, false);
+                    out.write("Content-length: " + handler.content.length()
+                            + "\r\n");
+                    out.write("\r\n");
+                    out.write(handler.content);
+                    out.flush();
+                } catch (RequestHandlerErrorException ex) {
+                    sendError(out);
+                } catch (RequestHandlerBadRequestException ex) {
+                    sendBadRequest(out);
+                } catch (RequestHandlerForbiddenException ex) {
+                    sendForbidden(out);
+                }
+            }
 
-		} catch (IOException ioe) {
-		} catch (Exception e) {
-			e.printStackTrace();
-			try {
-				sendError(out);
-			} catch (IOException e1) {
-			}
-		} finally {
-			try {
-				request.close();
-			} catch (IOException e) {
-			}
-		}
-	}
+        } catch (IOException ioe) {
+        } catch (Exception e) {
+            e.printStackTrace();
+            try {
+                sendError(out);
+            } catch (IOException e1) {
+            }
+        } finally {
+            try {
+                request.close();
+            } catch (IOException e) {
+            }
+        }
+    }
 
-	/**
-	 * Sends a 500 error: server error
-	 * 
-	 * @param out
-	 *            The writer where the error is written
-	 * @throws IOException
-	 *             If the error can not be written
-	 */
-	private void sendError(Writer out) throws IOException {
-		sendHeader(out, "500 Internal Server Error", "text/html", true);
-		out.write("<HTML>\r\n");
-		out.write("<HEAD><TITLE>Internal Error</TITLE>\r\n");
-		out.write("</HEAD>\r\n");
-		out.write("<BODY>");
-		out.write("<H1>HTTP Error 500: Internal Server Error</h2>\r\n");
-		out.write("</BODY></HTML>\r\n");
-		out.flush();
-	}
+    /**
+     * Sends a 500 error: server error
+     *
+     * @param out
+     *            The writer where the error is written
+     * @throws IOException
+     *             If the error can not be written
+     */
+    private void sendError(Writer out) throws IOException {
+        sendHeader(out, "500 Internal Server Error", "text/html", true);
+        out.write("<HTML>\r\n");
+        out.write("<HEAD><TITLE>Internal Error</TITLE>\r\n");
+        out.write("</HEAD>\r\n");
+        out.write("<BODY>");
+        out.write("<H1>HTTP Error 500: Internal Server Error</h2>\r\n");
+        out.write("</BODY></HTML>\r\n");
+        out.flush();
+    }
 
-	/**
-	 * Sends a 501 error: not implemented
-	 * 
-	 * @param out
-	 *            The writer where the error is written
-	 * @throws IOException
-	 *             If the error can not be written
-	 */
-	private void sendNotImplemented(Writer out) throws IOException {
-		sendHeader(out, "501 Not Implemented", "text/html", true);
-		out.write("<HTML>\r\n");
-		out.write("<HEAD><TITLE>Not Implemented</TITLE>\r\n");
-		out.write("</HEAD>\r\n");
-		out.write("<BODY>");
-		out.write("<H1>HTTP Error 501: Not Implemented</h2>\r\n");
-		out.write("</BODY></HTML>\r\n");
-		out.flush();
-	}
+    /**
+     * Sends a 501 error: not implemented
+     *
+     * @param out
+     *            The writer where the error is written
+     * @throws IOException
+     *             If the error can not be written
+     */
+    private void sendNotImplemented(Writer out) throws IOException {
+        sendHeader(out, "501 Not Implemented", "text/html", true);
+        out.write("<HTML>\r\n");
+        out.write("<HEAD><TITLE>Not Implemented</TITLE>\r\n");
+        out.write("</HEAD>\r\n");
+        out.write("<BODY>");
+        out.write("<H1>HTTP Error 501: Not Implemented</h2>\r\n");
+        out.write("</BODY></HTML>\r\n");
+        out.flush();
+    }
 
-	/**
-	 * Sends a 403 error: forbidden
-	 * 
-	 * @param out
-	 *            The writer where the error is written
-	 * @throws IOException
-	 *             If the error can not be written
-	 */
-	private void sendForbidden(Writer out) throws IOException {
-		sendHeader(out, "403 Forbidden", "text/html", true);
-		out.write("<HTML>\r\n");
-		out.write("<HEAD><TITLE>Forbidden</TITLE>\r\n");
-		out.write("</HEAD>\r\n");
-		out.write("<BODY>");
-		out.write("<H1>HTTP Error 403: Forbidden</h2>\r\n");
-		out.write("</BODY></HTML>\r\n");
-		out.flush();
-	}
+    /**
+     * Sends a 403 error: forbidden
+     *
+     * @param out
+     *            The writer where the error is written
+     * @throws IOException
+     *             If the error can not be written
+     */
+    private void sendForbidden(Writer out) throws IOException {
+        sendHeader(out, "403 Forbidden", "text/html", true);
+        out.write("<HTML>\r\n");
+        out.write("<HEAD><TITLE>Forbidden</TITLE>\r\n");
+        out.write("</HEAD>\r\n");
+        out.write("<BODY>");
+        out.write("<H1>HTTP Error 403: Forbidden</h2>\r\n");
+        out.write("</BODY></HTML>\r\n");
+        out.flush();
+    }
 
-	/**
-	 * Sends a 403 error: forbidden
-	 * 
-	 * @param out
-	 *            The writer where the error is written
-	 * @throws IOException
-	 *             If the error can not be written
-	 */
-	private void sendBadRequest(Writer out) throws IOException {
-		sendHeader(out, "400 Bad Request", "text/html", true);
-		out.write("<HTML>\r\n");
-		out.write("<HEAD><TITLE>Bad Request</TITLE>\r\n");
-		out.write("</HEAD>\r\n");
-		out.write("<BODY>");
-		out.write("<H1>HTTP Error 400: Bad Request</h2>\r\n");
-		out.write("</BODY></HTML>\r\n");
-		out.flush();
-	}
+    /**
+     * Sends a 403 error: forbidden
+     *
+     * @param out
+     *            The writer where the error is written
+     * @throws IOException
+     *             If the error can not be written
+     */
+    private void sendBadRequest(Writer out) throws IOException {
+        sendHeader(out, "400 Bad Request", "text/html", true);
+        out.write("<HTML>\r\n");
+        out.write("<HEAD><TITLE>Bad Request</TITLE>\r\n");
+        out.write("</HEAD>\r\n");
+        out.write("<BODY>");
+        out.write("<H1>HTTP Error 400: Bad Request</h2>\r\n");
+        out.write("</BODY></HTML>\r\n");
+        out.flush();
+    }
 
-	/**
-	 * Send common HTTP headers to the client.
-	 * 
-	 * @param out
-	 *            The Writer
-	 * @param status
-	 *            The status string ("200 OK", "500", etc)
-	 * @param contentType
-	 *            The content type of the data sent
-	 * @param endHeaders
-	 *            If true, adds a new line, ending the headers.
-	 * @throws IOException
-	 *             When error
-	 */
-	private void sendHeader(Writer out, String status, String contentType,
-			boolean endHeaders) throws IOException {
-		out.write("HTTP/1.1 " + status + "\r\n");
-		Date now = new Date();
-		out.write("Date: " + now + "\r\n");
-		out.write("Server: JOSM RemoteControl\r\n");
-		out.write("Content-type: " + contentType + "\r\n");
-		out.write("Access-Control-Allow-Origin: *\r\n");
-		if (endHeaders)
-			out.write("\r\n");
-	}
+    /**
+     * Send common HTTP headers to the client.
+     *
+     * @param out
+     *            The Writer
+     * @param status
+     *            The status string ("200 OK", "500", etc)
+     * @param contentType
+     *            The content type of the data sent
+     * @param endHeaders
+     *            If true, adds a new line, ending the headers.
+     * @throws IOException
+     *             When error
+     */
+    private void sendHeader(Writer out, String status, String contentType,
+            boolean endHeaders) throws IOException {
+        out.write("HTTP/1.1 " + status + "\r\n");
+        Date now = new Date();
+        out.write("Date: " + now + "\r\n");
+        out.write("Server: JOSM RemoteControl\r\n");
+        out.write("Content-type: " + contentType + "\r\n");
+        out.write("Access-Control-Allow-Origin: *\r\n");
+        if (endHeaders)
+            out.write("\r\n");
+    }
 }
diff --git a/remotecontrol/src/org/openstreetmap/josm/plugins/remotecontrol/handler/AddNodeHandler.java b/remotecontrol/src/org/openstreetmap/josm/plugins/remotecontrol/handler/AddNodeHandler.java
index 2d5b9bd..ddcda10 100644
--- a/remotecontrol/src/org/openstreetmap/josm/plugins/remotecontrol/handler/AddNodeHandler.java
+++ b/remotecontrol/src/org/openstreetmap/josm/plugins/remotecontrol/handler/AddNodeHandler.java
@@ -16,33 +16,33 @@ import org.openstreetmap.josm.plugins.remotecontrol.RequestHandler;
  */
 public class AddNodeHandler extends RequestHandler {
 
-	public static final String command = "add_node";
-	public static final String permissionKey = "remotecontrol.permission.create-objects";
-	public static final boolean permissionDefault = false;
+    public static final String command = "add_node";
+    public static final String permissionKey = "remotecontrol.permission.create-objects";
+    public static final boolean permissionDefault = false;
 
-	@Override
-	protected void handleRequest() {
+    @Override
+    protected void handleRequest() {
         addNode(args);
-	}
+    }
+
+    @Override
+    protected String[] getMandatoryParams()
+    {
+        return new String[] { "lat", "lon" };
+    }
 
-	@Override
-	protected String[] getMandatoryParams()
-	{
-		return new String[] { "lat", "lon" };
-	}
-	
-	@Override
-	public String getPermissionMessage() {
-		return tr("Remote Control has been asked to create a new node.");
-	}
+    @Override
+    public String getPermissionMessage() {
+        return tr("Remote Control has been asked to create a new node.");
+    }
+
+    @Override
+    public PermissionPrefWithDefault getPermissionPref()
+    {
+        return new PermissionPrefWithDefault(permissionKey, permissionDefault,
+                "RemoteControl: creating objects forbidden by preferences");
+    }
 
-	@Override
-	public PermissionPrefWithDefault getPermissionPref()
-	{
-		return new PermissionPrefWithDefault(permissionKey, permissionDefault,
-				"RemoteControl: creating objects forbidden by preferences");
-	}
-	
     /**
      * Adds a node, implements the GET /add_node?lon=...&lat=... request.
      * @param args
diff --git a/remotecontrol/src/org/openstreetmap/josm/plugins/remotecontrol/handler/ImportHandler.java b/remotecontrol/src/org/openstreetmap/josm/plugins/remotecontrol/handler/ImportHandler.java
index 398dd92..55a89d6 100644
--- a/remotecontrol/src/org/openstreetmap/josm/plugins/remotecontrol/handler/ImportHandler.java
+++ b/remotecontrol/src/org/openstreetmap/josm/plugins/remotecontrol/handler/ImportHandler.java
@@ -15,12 +15,12 @@ import org.openstreetmap.josm.plugins.remotecontrol.RequestHandlerErrorException
  */
 public class ImportHandler extends RequestHandler {
 
-	public static final String command = "import";
-	public static final String permissionKey = "remotecontrol.permission.import";
-	public static final boolean permissionDefault = true;
+    public static final String command = "import";
+    public static final String permissionKey = "remotecontrol.permission.import";
+    public static final boolean permissionDefault = true;
 
-	@Override
-	protected void handleRequest() throws RequestHandlerErrorException {
+    @Override
+    protected void handleRequest() throws RequestHandlerErrorException {
         try {
             DownloadTask osmTask = new DownloadOsmTask();
             osmTask.loadUrl(false, URLDecoder.decode(args.get("url"), "UTF-8"), null);
@@ -29,24 +29,24 @@ public class ImportHandler extends RequestHandler {
             ex.printStackTrace();
             throw new RequestHandlerErrorException();
         }
-	}
-
-	@Override
-	protected String[] getMandatoryParams()
-	{
-		return new String[] { "url" };
-	}
-	
-	@Override
-	public String getPermissionMessage() {
-		return tr("Remote Control has been asked to import data from the following URL:") +
+    }
+
+    @Override
+    protected String[] getMandatoryParams()
+    {
+        return new String[] { "url" };
+    }
+
+    @Override
+    public String getPermissionMessage() {
+        return tr("Remote Control has been asked to import data from the following URL:") +
         "<br>" + request;
-	}
-
-	@Override
-	public PermissionPrefWithDefault getPermissionPref()
-	{
-		return new PermissionPrefWithDefault(permissionKey, permissionDefault,
-				"RemoteControl: import forbidden by preferences");
-	}
+    }
+
+    @Override
+    public PermissionPrefWithDefault getPermissionPref()
+    {
+        return new PermissionPrefWithDefault(permissionKey, permissionDefault,
+                "RemoteControl: import forbidden by preferences");
+    }
 }
diff --git a/remotecontrol/src/org/openstreetmap/josm/plugins/remotecontrol/handler/LoadAndZoomHandler.java b/remotecontrol/src/org/openstreetmap/josm/plugins/remotecontrol/handler/LoadAndZoomHandler.java
index 0b7b8a9..0cccb92 100644
--- a/remotecontrol/src/org/openstreetmap/josm/plugins/remotecontrol/handler/LoadAndZoomHandler.java
+++ b/remotecontrol/src/org/openstreetmap/josm/plugins/remotecontrol/handler/LoadAndZoomHandler.java
@@ -28,140 +28,140 @@ import org.openstreetmap.josm.plugins.remotecontrol.RequestHandlerErrorException
  */
 public class LoadAndZoomHandler extends RequestHandler
 {
-	public static final String command = "load_and_zoom";
-	public static final String command2 = "zoom";
-	
-	public static final String loadDataPermissionKey = "remotecontrol.permission.load-data";
-	public static final boolean loadDataPermissionDefault = true;
-	public static final String changeSelectionPermissionKey = "remotecontrol.permission.change-selection";
-	public static final boolean changeSelectionPermissionDefault = true;
-	public static final String changeViewportPermissionKey = "remotecontrol.permission.change-viewport";
-	public static final boolean changeViewportPermissionDefault = true;
-	
+    public static final String command = "load_and_zoom";
+    public static final String command2 = "zoom";
+
+    public static final String loadDataPermissionKey = "remotecontrol.permission.load-data";
+    public static final boolean loadDataPermissionDefault = true;
+    public static final String changeSelectionPermissionKey = "remotecontrol.permission.change-selection";
+    public static final boolean changeSelectionPermissionDefault = true;
+    public static final String changeViewportPermissionKey = "remotecontrol.permission.change-viewport";
+    public static final boolean changeViewportPermissionDefault = true;
+
     @Override
     public String getPermissionMessage()
     {
-    	return tr("Remote Control has been asked to load data from the API.") +
+        return tr("Remote Control has been asked to load data from the API.") +
         "<br>" + tr("Request details: {0}", request);
     }
 
-	@Override
-	protected String[] getMandatoryParams()
-	{
-		return new String[] { "bottom", "top", "left", "right" };
-	}
-	
-	@Override
-	protected void handleRequest() throws RequestHandlerErrorException
-	{
-		DownloadTask osmTask = new DownloadOsmTask();
-		double minlat = 0;
-		double maxlat = 0;
-		double minlon = 0;
-		double maxlon = 0;
-		try {
-			minlat = Double.parseDouble(args.get("bottom"));
-			maxlat = Double.parseDouble(args.get("top"));
-			minlon = Double.parseDouble(args.get("left"));
-			maxlon = Double.parseDouble(args.get("right"));
+    @Override
+    protected String[] getMandatoryParams()
+    {
+        return new String[] { "bottom", "top", "left", "right" };
+    }
 
-			if(command.equals(myCommand))
-			{
-				if (!Main.pref.getBoolean(loadDataPermissionKey, loadDataPermissionDefault))
-				{
-					System.out.println("RemoteControl: download forbidden by preferences");
-				}
-				else
-				{
-	
-					// find out whether some data has already been downloaded
-					Area present = null;
-					Area toDownload = null;
-					DataSet ds = Main.main.getCurrentDataSet();
-					if (ds != null)
-						present = ds.getDataSourceArea();
-					if (present != null && !present.isEmpty()) {
-						toDownload = new Area(new Rectangle2D.Double(minlon,minlat,maxlon-minlon,maxlat-minlat));
-						toDownload.subtract(present);
-						if (!toDownload.isEmpty())
-						{
-							// the result might not be a rectangle (L shaped etc)
-							Rectangle2D downloadBounds = toDownload.getBounds2D();
-							minlat = downloadBounds.getMinY();
-							minlon = downloadBounds.getMinX();
-							maxlat = downloadBounds.getMaxY();
-							maxlon = downloadBounds.getMaxX();
-						}
-					}
-					if((toDownload != null) && toDownload.isEmpty())
-					{
-						System.out.println("RemoteControl: no download necessary");
-					}
-					else
-					{
-	                    Future<?> future = osmTask.download(false /*no new layer*/, new Bounds(minlat,minlon,maxlat,maxlon), null /* let the task manage the progress monitor */);
-	                    Main.worker.submit(new PostDownloadHandler(osmTask, future));
-					}
-				}
-			}
-		} catch (Exception ex) {
-			System.out.println("RemoteControl: Error parsing load_and_zoom remote control request:");
-			ex.printStackTrace();
-			throw new RequestHandlerErrorException();
-		}
-		if (args.containsKey("select") && Main.pref.getBoolean(changeSelectionPermissionKey, changeSelectionPermissionDefault)) {
-			// select objects after downloading, zoom to selection.
-			final String selection = args.get("select");
-			Main.worker.execute(new Runnable() {
-				public void run() {
-					HashSet<Long> ways = new HashSet<Long>();
-					HashSet<Long> nodes = new HashSet<Long>();
-					HashSet<Long> relations = new HashSet<Long>();
-					HashSet<OsmPrimitive> newSel = new HashSet<OsmPrimitive>();
-					for (String item : selection.split(",")) {
-						if (item.startsWith("way")) {
-							ways.add(Long.parseLong(item.substring(3)));
-						} else if (item.startsWith("node")) {
-							nodes.add(Long.parseLong(item.substring(4)));
-						} else if (item.startsWith("relation")) {
-							relations.add(Long.parseLong(item.substring(8)));
-						} else if (item.startsWith("rel")) {
-							relations.add(Long.parseLong(item.substring(3)));
-						} else {
-							System.out.println("RemoteControl: invalid selection '"+item+"' ignored");
-						}
-					}
-					DataSet ds = Main.main.getCurrentDataSet();
-					if(ds == null) // e.g. download failed
-						return;
-					for (Way w : ds.getWays()) if (ways.contains(w.getId())) newSel.add(w);
-					for (Node n : ds.getNodes()) if (nodes.contains(n.getId())) newSel.add(n);
-					for (Relation r : ds.getRelations()) if (relations.contains(r.getId())) newSel.add(r);
-					ds.setSelected(newSel);
-					if (Main.pref.getBoolean(changeViewportPermissionKey, changeViewportPermissionDefault))
-						new AutoScaleAction("selection").actionPerformed(null);
-				}
-			});
-		} else if (Main.pref.getBoolean(changeViewportPermissionKey, changeViewportPermissionDefault)) {
-			// after downloading, zoom to downloaded area.
-			zoom(minlat, maxlat, minlon, maxlon);
-		}
-	}
+    @Override
+    protected void handleRequest() throws RequestHandlerErrorException
+    {
+        DownloadTask osmTask = new DownloadOsmTask();
+        double minlat = 0;
+        double maxlat = 0;
+        double minlon = 0;
+        double maxlon = 0;
+        try {
+            minlat = Double.parseDouble(args.get("bottom"));
+            maxlat = Double.parseDouble(args.get("top"));
+            minlon = Double.parseDouble(args.get("left"));
+            maxlon = Double.parseDouble(args.get("right"));
+
+            if(command.equals(myCommand))
+            {
+                if (!Main.pref.getBoolean(loadDataPermissionKey, loadDataPermissionDefault))
+                {
+                    System.out.println("RemoteControl: download forbidden by preferences");
+                }
+                else
+                {
 
-	protected void zoom(double minlat, double maxlat, double minlon, double maxlon) {
-		final Bounds bounds = new Bounds(new LatLon(minlat, minlon),
-				new LatLon(maxlat, maxlon));
+                    // find out whether some data has already been downloaded
+                    Area present = null;
+                    Area toDownload = null;
+                    DataSet ds = Main.main.getCurrentDataSet();
+                    if (ds != null)
+                        present = ds.getDataSourceArea();
+                    if (present != null && !present.isEmpty()) {
+                        toDownload = new Area(new Rectangle2D.Double(minlon,minlat,maxlon-minlon,maxlat-minlat));
+                        toDownload.subtract(present);
+                        if (!toDownload.isEmpty())
+                        {
+                            // the result might not be a rectangle (L shaped etc)
+                            Rectangle2D downloadBounds = toDownload.getBounds2D();
+                            minlat = downloadBounds.getMinY();
+                            minlon = downloadBounds.getMinX();
+                            maxlat = downloadBounds.getMaxY();
+                            maxlon = downloadBounds.getMaxX();
+                        }
+                    }
+                    if((toDownload != null) && toDownload.isEmpty())
+                    {
+                        System.out.println("RemoteControl: no download necessary");
+                    }
+                    else
+                    {
+                        Future<?> future = osmTask.download(false /*no new layer*/, new Bounds(minlat,minlon,maxlat,maxlon), null /* let the task manage the progress monitor */);
+                        Main.worker.submit(new PostDownloadHandler(osmTask, future));
+                    }
+                }
+            }
+        } catch (Exception ex) {
+            System.out.println("RemoteControl: Error parsing load_and_zoom remote control request:");
+            ex.printStackTrace();
+            throw new RequestHandlerErrorException();
+        }
+        if (args.containsKey("select") && Main.pref.getBoolean(changeSelectionPermissionKey, changeSelectionPermissionDefault)) {
+            // select objects after downloading, zoom to selection.
+            final String selection = args.get("select");
+            Main.worker.execute(new Runnable() {
+                public void run() {
+                    HashSet<Long> ways = new HashSet<Long>();
+                    HashSet<Long> nodes = new HashSet<Long>();
+                    HashSet<Long> relations = new HashSet<Long>();
+                    HashSet<OsmPrimitive> newSel = new HashSet<OsmPrimitive>();
+                    for (String item : selection.split(",")) {
+                        if (item.startsWith("way")) {
+                            ways.add(Long.parseLong(item.substring(3)));
+                        } else if (item.startsWith("node")) {
+                            nodes.add(Long.parseLong(item.substring(4)));
+                        } else if (item.startsWith("relation")) {
+                            relations.add(Long.parseLong(item.substring(8)));
+                        } else if (item.startsWith("rel")) {
+                            relations.add(Long.parseLong(item.substring(3)));
+                        } else {
+                            System.out.println("RemoteControl: invalid selection '"+item+"' ignored");
+                        }
+                    }
+                    DataSet ds = Main.main.getCurrentDataSet();
+                    if(ds == null) // e.g. download failed
+                        return;
+                    for (Way w : ds.getWays()) if (ways.contains(w.getId())) newSel.add(w);
+                    for (Node n : ds.getNodes()) if (nodes.contains(n.getId())) newSel.add(n);
+                    for (Relation r : ds.getRelations()) if (relations.contains(r.getId())) newSel.add(r);
+                    ds.setSelected(newSel);
+                    if (Main.pref.getBoolean(changeViewportPermissionKey, changeViewportPermissionDefault))
+                        new AutoScaleAction("selection").actionPerformed(null);
+                }
+            });
+        } else if (Main.pref.getBoolean(changeViewportPermissionKey, changeViewportPermissionDefault)) {
+            // after downloading, zoom to downloaded area.
+            zoom(minlat, maxlat, minlon, maxlon);
+        }
+    }
 
-		// make sure this isn't called unless there *is* a MapView
-		//
-		if (Main.map != null && Main.map.mapView != null) {
-			Main.worker.execute(new Runnable() {
-				public void run() {
-					BoundingXYVisitor bbox = new BoundingXYVisitor();
-					bbox.visit(bounds);
-					Main.map.mapView.recalculateCenterScale(bbox);
-				}
-			});
-		}
-	}
+    protected void zoom(double minlat, double maxlat, double minlon, double maxlon) {
+        final Bounds bounds = new Bounds(new LatLon(minlat, minlon),
+                new LatLon(maxlat, maxlon));
+
+        // make sure this isn't called unless there *is* a MapView
+        //
+        if (Main.map != null && Main.map.mapView != null) {
+            Main.worker.execute(new Runnable() {
+                public void run() {
+                    BoundingXYVisitor bbox = new BoundingXYVisitor();
+                    bbox.visit(bounds);
+                    Main.map.mapView.recalculateCenterScale(bbox);
+                }
+            });
+        }
+    }
 }
diff --git a/remotecontrol/src/org/openstreetmap/josm/plugins/remotecontrol/handler/VersionHandler.java b/remotecontrol/src/org/openstreetmap/josm/plugins/remotecontrol/handler/VersionHandler.java
index e96690c..4206de5 100644
--- a/remotecontrol/src/org/openstreetmap/josm/plugins/remotecontrol/handler/VersionHandler.java
+++ b/remotecontrol/src/org/openstreetmap/josm/plugins/remotecontrol/handler/VersionHandler.java
@@ -13,29 +13,29 @@ import org.openstreetmap.josm.plugins.remotecontrol.RequestProcessor;
  */
 public class VersionHandler extends RequestHandler {
 
-	public static final String command = "version";
-	public static final String permissionKey = "remotecontrol.permission.read-protocolversion";
-	public static final boolean permissionDefault = true;
+    public static final String command = "version";
+    public static final String permissionKey = "remotecontrol.permission.read-protocolversion";
+    public static final boolean permissionDefault = true;
 
-	@Override
-	protected void handleRequest() throws RequestHandlerErrorException,
-			RequestHandlerBadRequestException {
-		content = RequestProcessor.PROTOCOLVERSION;
-		contentType = "application/json";
-		if (args.containsKey("jsonp")) {
-			content = args.get("jsonp")+ " && " + args.get("jsonp") + "(" + content + ")";
-		}
-	}
+    @Override
+    protected void handleRequest() throws RequestHandlerErrorException,
+            RequestHandlerBadRequestException {
+        content = RequestProcessor.PROTOCOLVERSION;
+        contentType = "application/json";
+        if (args.containsKey("jsonp")) {
+            content = args.get("jsonp")+ " && " + args.get("jsonp") + "(" + content + ")";
+        }
+    }
 
-	@Override
-	public String getPermissionMessage() {
-		return tr("Remote Control has been asked to report its protocol version. This enables web sites to detect a running JOSM.");
-	}
+    @Override
+    public String getPermissionMessage() {
+        return tr("Remote Control has been asked to report its protocol version. This enables web sites to detect a running JOSM.");
+    }
 
-	@Override
-	public PermissionPrefWithDefault getPermissionPref()
-	{
-		return new PermissionPrefWithDefault(permissionKey, permissionDefault,
-				"RemoteControl: /version forbidden by preferences");
-	}
+    @Override
+    public PermissionPrefWithDefault getPermissionPref()
+    {
+        return new PermissionPrefWithDefault(permissionKey, permissionDefault,
+                "RemoteControl: /version forbidden by preferences");
+    }
 }
diff --git a/routing/src/com/innovant/josm/jrt/core/EdgeIterator.java b/routing/src/com/innovant/josm/jrt/core/EdgeIterator.java
index c46f127..778797b 100644
--- a/routing/src/com/innovant/josm/jrt/core/EdgeIterator.java
+++ b/routing/src/com/innovant/josm/jrt/core/EdgeIterator.java
@@ -3,7 +3,7 @@ package com.innovant.josm.jrt.core;
 public interface EdgeIterator {
 
     public boolean hasNext();
-    
+
     public RoutingEdge next();
 
 }
diff --git a/routing/src/com/innovant/josm/jrt/core/RoutingEdge.java b/routing/src/com/innovant/josm/jrt/core/RoutingEdge.java
index af36d81..ba9fd7d 100644
--- a/routing/src/com/innovant/josm/jrt/core/RoutingEdge.java
+++ b/routing/src/com/innovant/josm/jrt/core/RoutingEdge.java
@@ -7,21 +7,21 @@ public interface RoutingEdge {
       public LatLon fromLatLon();
 
       public LatLon toLatLon();
-      
+
       public Object fromV();
 
       public Object toV();
 
       public double getLength();
-      
+
       public void setLength(double length);
-      
+
       public double getSpeed();
 
       public void setSpeed(double speed);
-      
+
       public boolean isOneway();
-      
+
       public void setOneway(boolean isOneway);
 
 }
diff --git a/routing/src/com/innovant/josm/jrt/core/RoutingGraphDelegator.java b/routing/src/com/innovant/josm/jrt/core/RoutingGraphDelegator.java
index bc3c40c..e9e5135 100644
--- a/routing/src/com/innovant/josm/jrt/core/RoutingGraphDelegator.java
+++ b/routing/src/com/innovant/josm/jrt/core/RoutingGraphDelegator.java
@@ -1,5 +1,5 @@
 /**
- * 
+ *
  */
 package com.innovant.josm.jrt.core;
 
@@ -22,16 +22,16 @@ public class RoutingGraphDelegator extends GraphDelegator<Node, OsmEdge> {
      * Logger.
      */
     static Logger logger = Logger.getLogger(RoutingGraphDelegator.class);
-    
+
     /**
      *
      */
     private RouteType routeType;
-    
+
     public RoutingGraphDelegator(Graph<Node, OsmEdge> arg0) {
         super(arg0);
     }
-    
+
 
     public RouteType getRouteType() {
         return routeType;
@@ -43,14 +43,14 @@ public class RoutingGraphDelegator extends GraphDelegator<Node, OsmEdge> {
 
 
     /**
-     * 
+     *
      */
     private static final long serialVersionUID = 1L;
 
     @Override
     public double getEdgeWeight(OsmEdge edge) {
         double weight=Double.MAX_VALUE;
-        
+
         if (routeType==RouteType.SHORTEST) weight=edge.getLength();
         if (routeType==RouteType.FASTEST) weight=edge.getLength() / edge.getSpeed();
         // Return the time spent to traverse the way
diff --git a/routing/src/com/innovant/josm/jrt/osm/OsmEdge.java b/routing/src/com/innovant/josm/jrt/osm/OsmEdge.java
index fbf531e..34c96c5 100644
--- a/routing/src/com/innovant/josm/jrt/osm/OsmEdge.java
+++ b/routing/src/com/innovant/josm/jrt/osm/OsmEdge.java
@@ -93,7 +93,7 @@ public class OsmEdge extends DefaultWeightedEdge {
   public double getLength() {
     return length;
   }
-  
+
   public void setLength(double length) {
     this.length = length;
 }
diff --git a/slippymap/src/org/openstreetmap/josm/plugins/slippymap/SlippyMapKey.java b/slippymap/src/org/openstreetmap/josm/plugins/slippymap/SlippyMapKey.java
index 8f6263f..9cd9482 100644
--- a/slippymap/src/org/openstreetmap/josm/plugins/slippymap/SlippyMapKey.java
+++ b/slippymap/src/org/openstreetmap/josm/plugins/slippymap/SlippyMapKey.java
@@ -1,5 +1,5 @@
 /**
- * 
+ *
  */
 package org.openstreetmap.josm.plugins.slippymap;
 
@@ -8,71 +8,71 @@ package org.openstreetmap.josm.plugins.slippymap;
  * Key for map tile. Key have just X and Y value. It have overriden {@link #hashCode()},
  * {@link #equals(Object)} and also {@link #toString()}.
  * </p>
- * 
+ *
  * @author LuVar <lubomir.varga at freemap.sk>
  * @author Dave Hansen <dave at sr71.net>
  *
  */
 public class SlippyMapKey {
-	private final int x;
-	private final int y;
-	private final int level;
-	
-	/**
-	 * <p>
-	 * Constructs key for hashmaps for some tile describedy by X and Y position. X and Y are tiles
-	 * positions on discrete map.
-	 * </p>
-	 * 
-	 * @param x	x position in tiles table
-	 * @param y	y position in tiles table
-	 */
-	public final boolean valid;
-	public SlippyMapKey(int x, int y, int level) {
-		this.x = x;
-		this.y = y;
-		this.level = level;
-		if (level <= 0 || x < 0 || y < 0) {
-			this.valid = false;
-			System.err.println("invalid SlippyMapKey("+level+", "+x+", "+y+")");
-		} else {
-			this.valid = true;
-		}
-	}
-	
-	/**
-	 * <p>
-	 * Returns true ONLY if x and y are equals.
-	 * </p>
-	 * 
-	 * @see java.lang.Object#equals(java.lang.Object)
-	 */
-	@Override
-	public boolean equals(Object obj) {
-		if (obj instanceof SlippyMapKey) {
-			SlippyMapKey smk = (SlippyMapKey) obj;
-			if((smk.x == this.x) && (smk.y == this.y) && (smk.level == this.level)) {
-				return true;
-			}
-		}
-		return false;
-	}
-	
-	/**
-	 * @return	return new Integer(this.x + this.y * 10000).hashCode();
-	 * @see java.lang.Object#hashCode()
-	 */
-	@Override
-	public int hashCode() {
-		return new Integer(this.x + this.y * 10000 + this.level * 100000).hashCode();
-	}
-	
-	/**
-	 * @see java.lang.Object#toString()
-	 */
-	@Override
-	public String toString() {
-		return "SlippyMapKey(x=" + this.x + ",y=" + this.y + ",level=" + level + ")";
-	}
-	
+    private final int x;
+    private final int y;
+    private final int level;
+
+    /**
+     * <p>
+     * Constructs key for hashmaps for some tile describedy by X and Y position. X and Y are tiles
+     * positions on discrete map.
+     * </p>
+     *
+     * @param x x position in tiles table
+     * @param y y position in tiles table
+     */
+    public final boolean valid;
+    public SlippyMapKey(int x, int y, int level) {
+        this.x = x;
+        this.y = y;
+        this.level = level;
+        if (level <= 0 || x < 0 || y < 0) {
+            this.valid = false;
+            System.err.println("invalid SlippyMapKey("+level+", "+x+", "+y+")");
+        } else {
+            this.valid = true;
+        }
+    }
+
+    /**
+     * <p>
+     * Returns true ONLY if x and y are equals.
+     * </p>
+     *
+     * @see java.lang.Object#equals(java.lang.Object)
+     */
+    @Override
+    public boolean equals(Object obj) {
+        if (obj instanceof SlippyMapKey) {
+            SlippyMapKey smk = (SlippyMapKey) obj;
+            if((smk.x == this.x) && (smk.y == this.y) && (smk.level == this.level)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    /**
+     * @return  return new Integer(this.x + this.y * 10000).hashCode();
+     * @see java.lang.Object#hashCode()
+     */
+    @Override
+    public int hashCode() {
+        return new Integer(this.x + this.y * 10000 + this.level * 100000).hashCode();
+    }
+
+    /**
+     * @see java.lang.Object#toString()
+     */
+    @Override
+    public String toString() {
+        return "SlippyMapKey(x=" + this.x + ",y=" + this.y + ",level=" + level + ")";
+    }
+
 }
diff --git a/slippymap/src/org/openstreetmap/josm/plugins/slippymap/SlippyMapLayer.java b/slippymap/src/org/openstreetmap/josm/plugins/slippymap/SlippyMapLayer.java
index 2874f65..1a1fb83 100644
--- a/slippymap/src/org/openstreetmap/josm/plugins/slippymap/SlippyMapLayer.java
+++ b/slippymap/src/org/openstreetmap/josm/plugins/slippymap/SlippyMapLayer.java
@@ -211,7 +211,7 @@ public class SlippyMapLayer extends Layer implements ImageObserver,
 
         // FIXME: currently ran in errors
 
-		tileOptionMenu.add(new JMenuItem(
+        tileOptionMenu.add(new JMenuItem(
                 new AbstractAction(tr("Snap to tile size")) {
                     public void actionPerformed(ActionEvent ae) {
                         if (lastImageScale == null) {
@@ -251,15 +251,15 @@ public class SlippyMapLayer extends Layer implements ImageObserver,
 
                 MapView.addLayerChangeListener(new LayerChangeListener() {
                     public void activeLayerChange(Layer oldLayer, Layer newLayer) {
-                    	//
+                        //
                     }
 
                     public void layerAdded(Layer newLayer) {
-                    	//
+                        //
                     }
 
                     public void layerRemoved(Layer oldLayer) {
-                    	MapView.removeLayerChangeListener(this);
+                        MapView.removeLayerChangeListener(this);
                     }
                 });
             }
diff --git a/slippymap/src/org/openstreetmap/josm/plugins/slippymap/SlippyMapPlugin.java b/slippymap/src/org/openstreetmap/josm/plugins/slippymap/SlippyMapPlugin.java
index 1f1cb7e..008210a 100644
--- a/slippymap/src/org/openstreetmap/josm/plugins/slippymap/SlippyMapPlugin.java
+++ b/slippymap/src/org/openstreetmap/josm/plugins/slippymap/SlippyMapPlugin.java
@@ -20,12 +20,12 @@ public class SlippyMapPlugin extends Plugin implements PreferenceChangedListener
 {
     public SlippyMapPlugin(PluginInformation info)
     {
-    	super(info);
-    	Main.pref.addPreferenceChangeListener(this);
+        super(info);
+        Main.pref.addPreferenceChangeListener(this);
     }
 
     @Override
-	public void mapFrameInitialized(MapFrame oldFrame, MapFrame newFrame)
+    public void mapFrameInitialized(MapFrame oldFrame, MapFrame newFrame)
     {
         if (newFrame != null && SlippyMapPreferences.getMapSource() != SlippyMapPreferences.NO_DEFAULT_TILE_SOURCE) {
             SlippyMapLayer smlayer;
@@ -52,23 +52,23 @@ public class SlippyMapPlugin extends Plugin implements PreferenceChangedListener
      * preferenceChanged(java.lang.String, java.lang.String)
      */
     public void preferenceChanged(PreferenceChangeEvent event) {
-    	if (!Main.isDisplayingMapView()) {
-    		return;
-    	}
-    	List<SlippyMapLayer> layes = Main.map.mapView.getLayersOfType(SlippyMapLayer.class);
-    	assert layes.size() <= 1;
-    	SlippyMapLayer layer = layes.isEmpty()?null:layes.get(0);
+        if (!Main.isDisplayingMapView()) {
+            return;
+        }
+        List<SlippyMapLayer> layes = Main.map.mapView.getLayersOfType(SlippyMapLayer.class);
+        assert layes.size() <= 1;
+        SlippyMapLayer layer = layes.isEmpty()?null:layes.get(0);
 
         if (event.getKey().equals(SlippyMapPreferences.PREFERENCE_TILE_SOURCE)) {
-        	if (layer == null && SlippyMapPreferences.getMapSource() != SlippyMapPreferences.NO_DEFAULT_TILE_SOURCE) {
-        		Main.map.mapView.addLayer(new SlippyMapLayer());
-        	} else if (layer != null && SlippyMapPreferences.getMapSource() == SlippyMapPreferences.NO_DEFAULT_TILE_SOURCE) {
-        		Main.map.mapView.removeLayer(layer);
-        	} else if (layer == null && SlippyMapPreferences.getMapSource() == SlippyMapPreferences.NO_DEFAULT_TILE_SOURCE) {
-        		// Do nothing
-        	} else {
-        		layer.newTileStorage();
-        	}
+            if (layer == null && SlippyMapPreferences.getMapSource() != SlippyMapPreferences.NO_DEFAULT_TILE_SOURCE) {
+                Main.map.mapView.addLayer(new SlippyMapLayer());
+            } else if (layer != null && SlippyMapPreferences.getMapSource() == SlippyMapPreferences.NO_DEFAULT_TILE_SOURCE) {
+                Main.map.mapView.removeLayer(layer);
+            } else if (layer == null && SlippyMapPreferences.getMapSource() == SlippyMapPreferences.NO_DEFAULT_TILE_SOURCE) {
+                // Do nothing
+            } else {
+                layer.newTileStorage();
+            }
         } else  if (event.getKey().startsWith(SlippyMapPreferences.PREFERENCE_PREFIX) && layer != null) {
             // System.err.println(this + ".preferenceChanged('" + key + "', '"
             // + newValue + "') called");
diff --git a/slippymap/src/org/openstreetmap/josm/plugins/slippymap/SlippyMapPreferenceSetting.java b/slippymap/src/org/openstreetmap/josm/plugins/slippymap/SlippyMapPreferenceSetting.java
index 4cfc0a4..5c29c77 100644
--- a/slippymap/src/org/openstreetmap/josm/plugins/slippymap/SlippyMapPreferenceSetting.java
+++ b/slippymap/src/org/openstreetmap/josm/plugins/slippymap/SlippyMapPreferenceSetting.java
@@ -113,10 +113,10 @@ public class SlippyMapPreferenceSetting implements PreferenceSetting {
      * Load settings from {@link SlippyMapPreferences} class. Loaded preferences are stored to local GUI components.
      * Actualy this method loads and sets this params:<br>
      * <ul>
-     * 	<li>autozoom - {@link #autozoomActive} - {@link SlippyMapPreferences#getAutozoom()}</li>
-     * 	<li>autoload - {@link #autoloadTiles} - {@link SlippyMapPreferences#getAutoloadTiles()}</li>
-     * 	<li>maxZoomLvl - {@link #maxZoomLvl} - {@link SlippyMapPreferences#getMaxZoomLvl()}</li>
-     * 	<li>minZoomLvl - {@link #minZoomLvl} - {@link SlippyMapPreferences#getMaxZoomLvl()}</li>
+     *  <li>autozoom - {@link #autozoomActive} - {@link SlippyMapPreferences#getAutozoom()}</li>
+     *  <li>autoload - {@link #autoloadTiles} - {@link SlippyMapPreferences#getAutoloadTiles()}</li>
+     *  <li>maxZoomLvl - {@link #maxZoomLvl} - {@link SlippyMapPreferences#getMaxZoomLvl()}</li>
+     *  <li>minZoomLvl - {@link #minZoomLvl} - {@link SlippyMapPreferences#getMaxZoomLvl()}</li>
      * </ul>
      * </p>
      */
@@ -138,7 +138,7 @@ public class SlippyMapPreferenceSetting implements PreferenceSetting {
      */
     public boolean ok()
     {
-    	SlippyMapPreferences.setMapSource((TileSource)this.tileSourceCombo.getSelectedItem());
+        SlippyMapPreferences.setMapSource((TileSource)this.tileSourceCombo.getSelectedItem());
         SlippyMapPreferences.setAutozoom(this.autozoomActive.isSelected());
         SlippyMapPreferences.setAutoloadTiles(this.autoloadTiles.isSelected());
         SlippyMapPreferences.setMaxZoomLvl((Integer)this.maxZoomLvl.getValue());
diff --git a/slippymap/src/org/openstreetmap/josm/plugins/slippymap/SlippyMapPreferences.java b/slippymap/src/org/openstreetmap/josm/plugins/slippymap/SlippyMapPreferences.java
index 680726f..f945fac 100644
--- a/slippymap/src/org/openstreetmap/josm/plugins/slippymap/SlippyMapPreferences.java
+++ b/slippymap/src/org/openstreetmap/josm/plugins/slippymap/SlippyMapPreferences.java
@@ -20,7 +20,7 @@ import org.openstreetmap.josm.Main;
  */
 public class SlippyMapPreferences
 {
-	public static final String NO_DEFAULT_TILE_SOURCE_NAME = "{%no_default%}";
+    public static final String NO_DEFAULT_TILE_SOURCE_NAME = "{%no_default%}";
     public static final String PREFERENCE_PREFIX   = "slippymap";
 
     public static final String PREFERENCE_TILE_CUSTOM_SOURCE = PREFERENCE_PREFIX + ".custom_tile_source_";
@@ -46,9 +46,9 @@ public class SlippyMapPreferences
     }
     public static TileSource getMapSource(String name)
     {
-    	if (NO_DEFAULT_TILE_SOURCE_NAME.equals(name)) {
-    		return NO_DEFAULT_TILE_SOURCE; // User don't want to load slippy layer on startup
-    	}
+        if (NO_DEFAULT_TILE_SOURCE_NAME.equals(name)) {
+            return NO_DEFAULT_TILE_SOURCE; // User don't want to load slippy layer on startup
+        }
 
         List<TileSource> sources = SlippyMapPreferences.getAllMapSources();
 
@@ -59,14 +59,14 @@ public class SlippyMapPreferences
 
         for (TileSource s : sources) {
             if (name.equals(s.getName()))
-            	return s;
+                return s;
         }
 
         return sources.get(0);
     }
 
     public static void setMapSource(TileSource source) {
-    	Main.pref.put(SlippyMapPreferences.PREFERENCE_TILE_SOURCE, source == NO_DEFAULT_TILE_SOURCE?NO_DEFAULT_TILE_SOURCE_NAME:source.getName());
+        Main.pref.put(SlippyMapPreferences.PREFERENCE_TILE_SOURCE, source == NO_DEFAULT_TILE_SOURCE?NO_DEFAULT_TILE_SOURCE_NAME:source.getName());
     }
 
     public static boolean getAutozoom()
@@ -75,7 +75,7 @@ public class SlippyMapPreferences
 
         if (autozoom == null || "".equals(autozoom))
         {
-        	autozoom = "true";
+            autozoom = "true";
             Main.pref.put(PREFERENCE_AUTOZOOM, autozoom);
         }
 
@@ -83,18 +83,18 @@ public class SlippyMapPreferences
     }
 
     public static void setAutozoom(boolean autozoom) {
-    	Main.pref.put(SlippyMapPreferences.PREFERENCE_AUTOZOOM, autozoom);
+        Main.pref.put(SlippyMapPreferences.PREFERENCE_AUTOZOOM, autozoom);
     }
 
     public static void setDrawDebug(boolean drawDebug) {
-    	Main.pref.put(SlippyMapPreferences.PREFERENCE_DRAW_DEBUG, drawDebug);
+        Main.pref.put(SlippyMapPreferences.PREFERENCE_DRAW_DEBUG, drawDebug);
     }
 
     public static void setLastZoom(int zoom) {
-    	Main.pref.put(SlippyMapPreferences.PREFERENCE_LAST_ZOOM, ""+zoom);
+        Main.pref.put(SlippyMapPreferences.PREFERENCE_LAST_ZOOM, ""+zoom);
     }
     public static int getLastZoom() {
-    	int ret = -1;
+        int ret = -1;
         String pref = Main.pref.get(SlippyMapPreferences.PREFERENCE_LAST_ZOOM);
         try {
             ret = Integer.parseInt(pref);
@@ -109,7 +109,7 @@ public class SlippyMapPreferences
 
         if (drawDebug == null || "".equals(drawDebug))
         {
-        	drawDebug = "false";
+            drawDebug = "false";
             Main.pref.put(PREFERENCE_DRAW_DEBUG, drawDebug);
         }
 
@@ -122,7 +122,7 @@ public class SlippyMapPreferences
 
         if (autoloadTiles == null || "".equals(autoloadTiles))
         {
-        	autoloadTiles = "true";
+            autoloadTiles = "true";
             Main.pref.put(PREFERENCE_AUTOLOADTILES, autoloadTiles);
         }
 
@@ -130,55 +130,55 @@ public class SlippyMapPreferences
     }
 
     public static void setFadeBackground(float fadeBackground) {
-    	Main.pref.put(SlippyMapPreferences.PREFERENCE_FADE_BACKGROUND, fadeBackground + "");
+        Main.pref.put(SlippyMapPreferences.PREFERENCE_FADE_BACKGROUND, fadeBackground + "");
     }
 
     /**
      *
-     * @return	number between 0 and 1, inclusive
+     * @return  number between 0 and 1, inclusive
      */
     public static float getFadeBackground() {
         String fadeBackground = Main.pref.get(PREFERENCE_FADE_BACKGROUND);
 
         if (fadeBackground == null || "".equals(fadeBackground))
         {
-        	fadeBackground = "0.0";
+            fadeBackground = "0.0";
             Main.pref.put(PREFERENCE_FADE_BACKGROUND, fadeBackground);
         }
 
         float parsed;
         try {
-        	parsed = Float.parseFloat(fadeBackground);
+            parsed = Float.parseFloat(fadeBackground);
         } catch (Exception ex) {
-        	setFadeBackground(0.1f);
-        	System.out.println("Error while parsing setting fade background to float! returning 0.1, because of error:");
-        	ex.printStackTrace(System.out);
-        	return 0.1f;
+            setFadeBackground(0.1f);
+            System.out.println("Error while parsing setting fade background to float! returning 0.1, because of error:");
+            ex.printStackTrace(System.out);
+            return 0.1f;
         }
         if(parsed < 0f) {
-        	parsed = 0f;
+            parsed = 0f;
         } else {
-        	if(parsed > 1f) {
-            	parsed = 1f;
+            if(parsed > 1f) {
+                parsed = 1f;
             }
         }
         return parsed;
     }
 
     public static void setAutoloadTiles(boolean autoloadTiles) {
-    	Main.pref.put(SlippyMapPreferences.PREFERENCE_AUTOLOADTILES, autoloadTiles);
+        Main.pref.put(SlippyMapPreferences.PREFERENCE_AUTOLOADTILES, autoloadTiles);
     }
 
     private static int getIntPref(String prefName, int def)
     {
         int pref;
         try {
-        	//Should we use Main.pref.getInteger(str)?
-        	pref = Main.pref.getInteger(prefName, def);
+            //Should we use Main.pref.getInteger(str)?
+            pref = Main.pref.getInteger(prefName, def);
         } catch (Exception ex) {
             String str = Main.pref.get(prefName);
             Main.pref.put(prefName, null);
-        	throw new RuntimeException("Problem while converting string to int. "
+            throw new RuntimeException("Problem while converting string to int. "
                                        + "Converting value of preferences "
                                        + prefName + ". Value=\"" + str
                                        + "\". Should be an integer. Error: "
@@ -189,17 +189,17 @@ public class SlippyMapPreferences
 
     static int checkMaxZoomLvl(int maxZoomLvl)
     {
-    	if(maxZoomLvl > MAX_ZOOM) {
-    		System.err.println("MaxZoomLvl shouldnt be more than 30! Setting to 30.");
-    		maxZoomLvl = MAX_ZOOM;
-    	}
-    	if(maxZoomLvl < SlippyMapPreferences.__getMinZoomLvl()) {
-    		System.err.println("maxZoomLvl shouldnt be more than minZoomLvl! Setting to minZoomLvl.");
-    		maxZoomLvl = SlippyMapPreferences.__getMinZoomLvl();
-    	}
+        if(maxZoomLvl > MAX_ZOOM) {
+            System.err.println("MaxZoomLvl shouldnt be more than 30! Setting to 30.");
+            maxZoomLvl = MAX_ZOOM;
+        }
+        if(maxZoomLvl < SlippyMapPreferences.__getMinZoomLvl()) {
+            System.err.println("maxZoomLvl shouldnt be more than minZoomLvl! Setting to minZoomLvl.");
+            maxZoomLvl = SlippyMapPreferences.__getMinZoomLvl();
+        }
         TileSource ts = getMapSource();
         if (ts != null && ts.getMaxZoom() < SlippyMapPreferences.__getMinZoomLvl()) {
-    		System.err.println("decreasing maxZoomLvl to match new tile source");
+            System.err.println("decreasing maxZoomLvl to match new tile source");
             maxZoomLvl = ts.getMaxZoom();
         }
         return maxZoomLvl;
@@ -213,19 +213,19 @@ public class SlippyMapPreferences
 
     public static void setMaxZoomLvl(int maxZoomLvl) {
         maxZoomLvl = checkMaxZoomLvl(maxZoomLvl);
-    	Main.pref.put(SlippyMapPreferences.PREFERENCE_MAX_ZOOM_LVL, "" + maxZoomLvl);
+        Main.pref.put(SlippyMapPreferences.PREFERENCE_MAX_ZOOM_LVL, "" + maxZoomLvl);
     }
 
     static int checkMinZoomLvl(int minZoomLvl)
     {
         if(minZoomLvl < MIN_ZOOM) {
-    		System.err.println("minZoomLvl shouldnt be lees than "+MIN_ZOOM+"! Setting to that.");
-    		minZoomLvl = MIN_ZOOM;
-    	}
-    	if(minZoomLvl > SlippyMapPreferences.getMaxZoomLvl()) {
-    		System.err.println("minZoomLvl shouldnt be more than maxZoomLvl! Setting to maxZoomLvl.");
-    		minZoomLvl = SlippyMapPreferences.getMaxZoomLvl();
-    	}
+            System.err.println("minZoomLvl shouldnt be lees than "+MIN_ZOOM+"! Setting to that.");
+            minZoomLvl = MIN_ZOOM;
+        }
+        if(minZoomLvl > SlippyMapPreferences.getMaxZoomLvl()) {
+            System.err.println("minZoomLvl shouldnt be more than maxZoomLvl! Setting to maxZoomLvl.");
+            minZoomLvl = SlippyMapPreferences.getMaxZoomLvl();
+        }
         return minZoomLvl;
     }
 
@@ -241,13 +241,13 @@ public class SlippyMapPreferences
 
     public static void setMinZoomLvl(int minZoomLvl) {
         minZoomLvl = checkMinZoomLvl(minZoomLvl);
-    	Main.pref.put(SlippyMapPreferences.PREFERENCE_MIN_ZOOM_LVL, "" + minZoomLvl);
+        Main.pref.put(SlippyMapPreferences.PREFERENCE_MIN_ZOOM_LVL, "" + minZoomLvl);
     }
 
     public static TileSource NO_DEFAULT_TILE_SOURCE = new AbstractOsmTileSource(tr("(none)"), "") {
-		public TileUpdate getTileUpdate() {
-			return null;
-		}
+        public TileUpdate getTileUpdate() {
+            return null;
+        }
     };
 
     public static class Coastline extends OsmTileSource.AbstractOsmTileSource {
@@ -281,12 +281,12 @@ public class SlippyMapPreferences
         }
 
         @Override
-		public int getMaxZoom() {
+        public int getMaxZoom() {
             return 21;
         }
 
         @Override
-		public String getTilePath(int zoom, int tilex, int tiley) {
+        public String getTilePath(int zoom, int tilex, int tiley) {
             return "z=" + zoom + "&x=" + tilex + "&y=" + tiley;
         }
 
@@ -302,13 +302,13 @@ public class SlippyMapPreferences
         }
 
         @Override
-		public int getMaxZoom() {
+        public int getMaxZoom() {
             return 21;
         }
 
         @Override
-		public String getTilePath(int zoom, int tilex, int tiley) {
-        	return "/" + zoom + "/" + tilex + "/" + tiley + ".png";
+        public String getTilePath(int zoom, int tilex, int tiley) {
+            return "/" + zoom + "/" + tilex + "/" + tiley + ".png";
         }
 
         public TileUpdate getTileUpdate() {
diff --git a/svn-info.xml b/svn-info.xml
index 40df43d..468d4bf 100644
--- a/svn-info.xml
+++ b/svn-info.xml
@@ -3,16 +3,16 @@
 <entry
    kind="dir"
    path="plugins"
-   revision="23040">
+   revision="23541">
 <url>http://svn.openstreetmap.org/applications/editors/josm/plugins</url>
 <repository>
 <root>http://svn.openstreetmap.org</root>
 <uuid>b9d5c4c9-76e1-0310-9c85-f3177eceb1e4</uuid>
 </repository>
 <commit
-   revision="23039">
-<author>postfix</author>
-<date>2010-09-06T21:06:40.259986Z</date>
+   revision="23541">
+<author>upliner</author>
+<date>2010-10-10T18:01:10.304771Z</date>
 </commit>
 </entry>
 </info>
diff --git a/wmsplugin/build.xml b/wmsplugin/build.xml
index c36ce4b..cd59e06 100644
--- a/wmsplugin/build.xml
+++ b/wmsplugin/build.xml
@@ -28,8 +28,7 @@
 
 
 	<property name="commit.message" value="fixed josm bug 4671 - wms url for sicily has changed" />
-	<property name="plugin.main.version" value="3451" />
-
+	<property name="plugin.main.version" value="3530" />
 
 	<property name="josm" location="../../core/dist/josm-custom.jar" />
 	<property name="remotecontrol" location="../../dist/remotecontrol.jar" />
diff --git a/wmsplugin/sources.cfg b/wmsplugin/sources.cfg
index c64ff0a..6740c95 100644
--- a/wmsplugin/sources.cfg
+++ b/wmsplugin/sources.cfg
@@ -48,6 +48,9 @@ false;Lodi - Italy;http://sit.provincia.lodi.it/mapserver/mapserv.exe?map=ortofo
 false;Sicily - Italy;http://88.53.214.52/sitr/services/WGS84_F33/Ortofoto_ATA20072008_f33/MapServer/WMSServer?SERVICE=WMS&VERSION=1.3.0&REQUEST=GetMap&CRS=CRS:84&LAYERS=0&STYLES=default&FORMAT=image/jpeg&
 false;PCN 2006 - Italy;http://wms.pcn.minambiente.it/cgi-bin/mapserv.exe?map=/ms_ogc/service/ortofoto_colore_06.map&LAYERS=ortofoto_colore_06_32,ortofoto_colore_06_33&REQUEST=GetMap&VERSION=1.1.1&FORMAT=image%2Fjpeg&
 #
+# only for France
+false;SPOTMaps (France);http://spotmaps.youmapps.org/cgi-bin/mapserv?map=/home/ortho/ortho.map&service=wms&version=1.1.1&srs=EPSG:4326&request=GetMap&layers=spotmaps4osm&format=image/jpeg&FORMAT=image/jpeg&VERSION=1.1.1&SERVICE=WMS&REQUEST=GetMap&Layers=demo&;http://www.youmapps.org/licenses/EULA-OSM-J-{lang}.html
+#
 #
 # URLS must be designed to append arguments directly behind. So the URLS should either end with '?' or '&'
 # Following arguments are added: width, height, bbox, srs (projection method)
diff --git a/wmsplugin/src/wmsplugin/AddWMSLayerPanel.java b/wmsplugin/src/wmsplugin/AddWMSLayerPanel.java
index 9355b10..2722cdf 100644
--- a/wmsplugin/src/wmsplugin/AddWMSLayerPanel.java
+++ b/wmsplugin/src/wmsplugin/AddWMSLayerPanel.java
@@ -58,450 +58,469 @@ import org.xml.sax.SAXException;
 
 
 public class AddWMSLayerPanel extends JPanel {
-    private List<LayerDetails> selectedLayers;
-    private URL serviceUrl;
-    private LayerDetails selectedLayer;
-
-    private JTextField menuName;
-    private JTextArea resultingLayerField;
-    private MutableTreeNode treeRootNode;
-    private DefaultTreeModel treeData;
-    private JTree layerTree;
-    private JButton showBoundsButton;
-
-    private boolean previouslyShownUnsupportedCrsError = false;
-
-    public AddWMSLayerPanel() {
-        JPanel wmsFetchPanel = new JPanel(new GridBagLayout());
-        menuName = new JTextField(40);
-        menuName.setText(tr("Unnamed WMS Layer"));
-        final JTextArea serviceUrl = new JTextArea(3, 40);
-        serviceUrl.setLineWrap(true);
-        serviceUrl.setText("http://sample.com/wms?");
-        wmsFetchPanel.add(new JLabel(tr("Menu Name")), GBC.std().insets(0,0,5,0));
-        wmsFetchPanel.add(menuName, GBC.eop().insets(5,0,0,0).fill(GridBagConstraints.HORIZONTAL));
-        wmsFetchPanel.add(new JLabel(tr("Service URL")), GBC.std().insets(0,0,5,0));
-        JScrollPane scrollPane = new JScrollPane(serviceUrl,
-                JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED,
-                JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
-        wmsFetchPanel.add(scrollPane, GBC.eop().insets(5,0,0,0));
-        JButton getLayersButton = new JButton(tr("Get Layers"));
-        getLayersButton.addActionListener(new ActionListener() {
-            public void actionPerformed(ActionEvent e) {
-                Cursor beforeCursor = getCursor();
-                try {
-                    setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
-                    attemptGetCapabilities(serviceUrl.getText());
-                } finally {
-                    setCursor(beforeCursor);
-                }
-            }
-        });
-        wmsFetchPanel.add(getLayersButton, GBC.eop().anchor(GridBagConstraints.EAST));
-
-        treeRootNode = new DefaultMutableTreeNode();
-        treeData = new DefaultTreeModel(treeRootNode);
-        layerTree = new JTree(treeData);
-        layerTree.setCellRenderer(new LayerTreeCellRenderer());
-        layerTree.addTreeSelectionListener(new TreeSelectionListener() {
-
-            public void valueChanged(TreeSelectionEvent e) {
-                TreePath[] selectionRows = layerTree.getSelectionPaths();
-                if(selectionRows == null) {
-                    showBoundsButton.setEnabled(false);
-                    selectedLayer = null;
-                    return;
-                }
-
-                selectedLayers = new LinkedList<LayerDetails>();
-                for (TreePath i : selectionRows) {
-                    Object userObject = ((DefaultMutableTreeNode) i.getLastPathComponent()).getUserObject();
-                    if(userObject instanceof LayerDetails) {
-                        LayerDetails detail = (LayerDetails) userObject;
-                        if(!detail.isSupported()) {
-                            layerTree.removeSelectionPath(i);
-                            if(!previouslyShownUnsupportedCrsError) {
-                                JOptionPane.showMessageDialog(null, tr("That layer does not support any of JOSM's projections,\n" +
-                                "so you can not use it. This message will not show again."),
-                                tr("WMS Error"), JOptionPane.ERROR_MESSAGE);
-                                previouslyShownUnsupportedCrsError = true;
-                            }
-                        } else if(detail.ident != null) {
-                            selectedLayers.add(detail);
-                        }
-                    }
-                }
-
-                if (!selectedLayers.isEmpty()) {
-                    resultingLayerField.setText(buildGetMapUrl());
-
-                    if(selectedLayers.size() == 1) {
-                        showBoundsButton.setEnabled(true);
-                        selectedLayer = selectedLayers.get(0);
-                    }
-                } else {
-                    showBoundsButton.setEnabled(false);
-                    selectedLayer = null;
-                }
-            }
-        });
-        wmsFetchPanel.add(new JScrollPane(layerTree), GBC.eop().insets(5,0,0,0).fill(GridBagConstraints.HORIZONTAL));
-
-        JPanel layerManipulationButtons = new JPanel();
-        showBoundsButton = new JButton(tr("Show Bounds"));
-        showBoundsButton.setEnabled(false);
-        showBoundsButton.addActionListener(new ActionListener() {
-            public void actionPerformed(ActionEvent e) {
-                if(selectedLayer.bounds != null) {
-                    SlippyMapBBoxChooser mapPanel = new SlippyMapBBoxChooser();
-                    mapPanel.setBoundingBox(selectedLayer.bounds);
-                    JOptionPane.showMessageDialog(null, mapPanel, tr("Show Bounds"), JOptionPane.PLAIN_MESSAGE);
-                } else {
-                    JOptionPane.showMessageDialog(null, tr("No bounding box was found for this layer."),
-                            tr("WMS Error"), JOptionPane.ERROR_MESSAGE);
-                }
-            }
-        });
-        layerManipulationButtons.add(showBoundsButton);
-
-        wmsFetchPanel.add(layerManipulationButtons, GBC.eol().insets(0,0,5,0));
-        wmsFetchPanel.add(new JLabel(tr("WMS URL")), GBC.std().insets(0,0,5,0));
-        resultingLayerField = new JTextArea(3, 40);
-        resultingLayerField.setLineWrap(true);
-        wmsFetchPanel.add(new JScrollPane(resultingLayerField, JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED, JScrollPane.HORIZONTAL_SCROLLBAR_NEVER), GBC.eop().insets(5,0,0,0).fill(GridBagConstraints.HORIZONTAL));
-
-        add(wmsFetchPanel);
-    }
-
-    private String buildRootUrl() {
-        StringBuilder a = new StringBuilder(serviceUrl.getProtocol());
-        a.append("://");
-        a.append(serviceUrl.getHost());
-        if(serviceUrl.getPort() != -1) {
-            a.append(":");
-            a.append(serviceUrl.getPort());
-        }
-        a.append(serviceUrl.getPath());
-        a.append("?");
-        if(serviceUrl.getQuery() != null) {
-            a.append(serviceUrl.getQuery());
-            if (!serviceUrl.getQuery().isEmpty() && !serviceUrl.getQuery().endsWith("&")) {
-                a.append("&");
-            }
-        }
-        return a.toString();
-    }
-
-    private String buildGetMapUrl() {
-        StringBuilder a = new StringBuilder();
-        a.append(buildRootUrl());
-        a.append("FORMAT=image/jpeg&VERSION=1.1.1&SERVICE=WMS&REQUEST=GetMap&Layers=");
-        a.append(commaSepLayerList());
-        a.append("&");
-
-        return a.toString();
-    }
-
-    private String commaSepLayerList() {
-        StringBuilder b = new StringBuilder();
-
-        Iterator<LayerDetails> iterator = selectedLayers.iterator();
-        while (iterator.hasNext()) {
-            LayerDetails layerDetails = iterator.next();
-            b.append(layerDetails.ident);
-            if(iterator.hasNext()) {
-                b.append(",");
-            }
-        }
-
-        return b.toString();
-    }
-
-    private void attemptGetCapabilities(String serviceUrlStr) {
-        URL getCapabilitiesUrl = null;
-        try {
-            if (!serviceUrlStr.trim().contains("capabilities")) {
-                // If the url doesn't already have GetCapabilities, add it in
-                getCapabilitiesUrl = new URL(serviceUrlStr + "VERSION=1.1.1&SERVICE=WMS&REQUEST=GetCapabilities");
-            } else {
-                // Otherwise assume it's a good URL and let the subsequent error
-                // handling systems deal with problems
-                getCapabilitiesUrl = new URL(serviceUrlStr);
-            }
-            serviceUrl = new URL(serviceUrlStr);
-        } catch (HeadlessException e) {
-            return;
-        } catch (MalformedURLException e) {
-            JOptionPane.showMessageDialog(this, tr("Invalid service URL."),
-                    tr("WMS Error"), JOptionPane.ERROR_MESSAGE);
-            return;
-        }
-
-        System.out.println("Connecting to: " + getCapabilitiesUrl);
-
-        String incomingData;
-        try {
-            URLConnection openConnection = getCapabilitiesUrl.openConnection();
-            InputStream inputStream = openConnection.getInputStream();
-            BufferedReader br = new BufferedReader(new InputStreamReader(inputStream));
-            String line;
-            StringBuilder ba = new StringBuilder();
-            while((line = br.readLine()) != null) {
-                ba.append(line);
-                ba.append("\n");
-            }
-            incomingData = ba.toString();
-        } catch (IOException e) {
-            JOptionPane.showMessageDialog(this, tr("Could not retrieve WMS layer list."),
-                    tr("WMS Error"), JOptionPane.ERROR_MESSAGE);
-            return;
-        }
-
-        System.out.println(incomingData);
-
-        Document document;
-        try {
-            DocumentBuilderFactory builderFactory = DocumentBuilderFactory.newInstance();
-            builderFactory.setValidating(false);
-            builderFactory.setNamespaceAware(true);
-            DocumentBuilder builder = builderFactory.newDocumentBuilder();
-            builder.setEntityResolver(new EntityResolver() {
-                public InputSource resolveEntity(String publicId, String systemId) throws SAXException, IOException {
-                    System.out.println("Ignoring DTD " + publicId + ", " + systemId);
-                    return new InputSource(new StringReader(""));
-                }
-            });
-            document = builder.parse(new InputSource(new StringReader(incomingData)));
-        } catch (ParserConfigurationException e) {
-            JOptionPane.showMessageDialog(this, tr("Could not parse WMS layer list."),
-                    tr("WMS Error"), JOptionPane.ERROR_MESSAGE);
-            return;
-        } catch (SAXException e) {
-            JOptionPane.showMessageDialog(this, tr("Could not parse WMS layer list."),
-                    tr("WMS Error"), JOptionPane.ERROR_MESSAGE);
-            return;
-        } catch (IOException e) {
-            JOptionPane.showMessageDialog(this, tr("Could not parse WMS layer list."),
-                    tr("WMS Error"), JOptionPane.ERROR_MESSAGE);
-            return;
-        }
-
-        try {
-            treeRootNode.setUserObject(getCapabilitiesUrl.getHost());
-            Element capabilityElem = getChild(document.getDocumentElement(), "Capability");
-            List<Element> children = getChildren(capabilityElem, "Layer");
-            List<LayerDetails> layers = parseLayers(children, new HashSet<String>());
-            updateTreeList(layers);
-        } catch(Exception e) {
-            JOptionPane.showMessageDialog(this, tr("Could not parse WMS layer list."),
-                    tr("WMS Error"), JOptionPane.ERROR_MESSAGE);
-            e.printStackTrace();
-            return;
-        }
-    }
-
-    private void updateTreeList(List<LayerDetails> layers) {
-        addLayersToTreeData(treeRootNode, layers);
-        layerTree.expandRow(0);
-    }
-
-    private void addLayersToTreeData(MutableTreeNode parent, List<LayerDetails> layers) {
-        for (LayerDetails layerDetails : layers) {
-            DefaultMutableTreeNode treeNode = new DefaultMutableTreeNode(layerDetails);
-            addLayersToTreeData(treeNode, layerDetails.children);
-            treeData.insertNodeInto(treeNode, parent, 0);
-        }
-    }
-
-    private List<LayerDetails> parseLayers(List<Element> children, Set<String> parentCrs) {
-        List<LayerDetails> details = new LinkedList<LayerDetails>();
-        for (Element element : children) {
-            details.add(parseLayer(element, parentCrs));
-        }
-        return details;
-    }
-
-    private LayerDetails parseLayer(Element element, Set<String> parentCrs) {
-        String name = getChildContent(element, "Title", null, null);
-        String ident = getChildContent(element, "Name", null, null);
-
-        // The set of supported CRS/SRS for this layer
-        Set<String> crsList = new HashSet<String>();
-        // ...including this layer's already-parsed parent projections
-        crsList.addAll(parentCrs);
-
-        // Parse the CRS/SRS pulled out of this layer's XML element
-        // I think CRS and SRS are the same at this point
-        List<Element> crsChildren = getChildren(element, "CRS");
-        crsChildren.addAll(getChildren(element, "SRS"));
-        for (Element child : crsChildren) {
-            String crs = (String) getContent(child);
-            if(crs != null) {
-                String upperCase = crs.trim().toUpperCase();
-                crsList.add(upperCase);
-            }
-        }
-
-        // Check to see if any of the specified projections are supported by JOSM
-        boolean josmSupportsThisLayer = false;
-        for (String crs : crsList) {
-            josmSupportsThisLayer |= isProjSupported(crs);
-        }
-
-        Bounds bounds = null;
-        Element bboxElem = getChild(element, "EX_GeographicBoundingBox");
-        if(bboxElem != null) {
-            // Attempt to use EX_GeographicBoundingBox for bounding box
-            double left = Double.parseDouble(getChildContent(bboxElem, "westBoundLongitude", null, null));
-            double top = Double.parseDouble(getChildContent(bboxElem, "northBoundLatitude", null, null));
-            double right = Double.parseDouble(getChildContent(bboxElem, "eastBoundLongitude", null, null));
-            double bot = Double.parseDouble(getChildContent(bboxElem, "southBoundLatitude", null, null));
-            bounds = new Bounds(bot, left, top, right);
-        } else {
-            // If that's not available, try LatLonBoundingBox
-            bboxElem = getChild(element, "LatLonBoundingBox");
-            if(bboxElem != null) {
-                double left = Double.parseDouble(bboxElem.getAttribute("minx"));
-                double top = Double.parseDouble(bboxElem.getAttribute("maxy"));
-                double right = Double.parseDouble(bboxElem.getAttribute("maxx"));
-                double bot = Double.parseDouble(bboxElem.getAttribute("miny"));
-                bounds = new Bounds(bot, left, top, right);
-            }
-        }
-
-        List<Element> layerChildren = getChildren(element, "Layer");
-        List<LayerDetails> childLayers = parseLayers(layerChildren, crsList);
-
-        return new LayerDetails(name, ident, crsList, josmSupportsThisLayer, bounds, childLayers);
-    }
-
-    private boolean isProjSupported(String crs) {
-        for (Projection proj : Projection.allProjections) {
-            if (proj instanceof ProjectionSubPrefs) {
-                if (((ProjectionSubPrefs) proj).getPreferencesFromCode(crs) == null) {
-                    return true;
-                }
-            } else {
-                if (proj.toCode().equals(crs)) {
-                    return true;
-                }
-            }
-        }
-        return false;
-    }
-
-    public String getUrlName() {
-        return menuName.getText();
-    }
-
-    public String getUrl() {
-        return resultingLayerField.getText();
-    }
-
-    public static void main(String[] args) {
-        JFrame f = new JFrame("Test");
-        f.setContentPane(new AddWMSLayerPanel());
-        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
-        f.pack();
-        f.setVisible(true);
-    }
-
-    private static String getChildContent(Element parent, String name, String missing, String empty) {
-        Element child = getChild(parent, name);
-        if (child == null) {
-            return missing;
-        } else {
-            String content = (String) getContent(child);
-            return (content != null) ? content : empty;
-        }
-    }
-
-    private static Object getContent(Element element) {
-        NodeList nl = element.getChildNodes();
-        StringBuffer content = new StringBuffer();
-        for (int i = 0; i < nl.getLength(); i++) {
-            Node node = nl.item(i);
-            switch (node.getNodeType()) {
-            case Node.ELEMENT_NODE:
-                return node;
-            case Node.CDATA_SECTION_NODE:
-            case Node.TEXT_NODE:
-                content.append(node.getNodeValue());
-                break;
-            }
-        }
-        return content.toString().trim();
-    }
-
-    private static List<Element> getChildren(Element parent, String name) {
-        List<Element> retVal = new LinkedList<Element>();
-        for (Node child = parent.getFirstChild(); child != null; child = child.getNextSibling()) {
-            if (child instanceof Element && name.equals(child.getNodeName())) {
-                retVal.add((Element) child);
-            }
-        }
-        return retVal;
-    }
-
-    private static Element getChild(Element parent, String name) {
-        for (Node child = parent.getFirstChild(); child != null; child = child.getNextSibling()) {
-            if (child instanceof Element && name.equals(child.getNodeName())) {
-                return (Element) child;
-            }
-        }
-        return null;
-    }
-
-    class LayerDetails {
-
-        private String name;
-        private String ident;
-        private Set<String> crsList;
-        private List<LayerDetails> children;
-        private Bounds bounds;
-        private boolean supported;
-
-        public LayerDetails(String name, String ident, Set<String> crsList,
-                boolean supportedLayer, Bounds bounds,
-                List<LayerDetails> childLayers) {
-            this.name = name;
-            this.ident = ident;
-            this.crsList = crsList;
-            this.supported = supportedLayer;
-            this.children = childLayers;
-            this.bounds = bounds;
-        }
-
-        public boolean isSupported() {
-            return this.supported;
-        }
-
-        @Override
-        public String toString() {
-            if(this.name == null || this.name.isEmpty()) {
-                return this.ident;
-            } else {
-                return this.name;
-            }
-        }
-
-    }
-
-    class LayerTreeCellRenderer extends DefaultTreeCellRenderer {
-        @Override
-        public Component getTreeCellRendererComponent(JTree tree, Object value,
-                boolean sel, boolean expanded, boolean leaf, int row,
-                boolean hasFocus) {
-            super.getTreeCellRendererComponent(tree, value, sel, expanded, leaf,
-                    row, hasFocus);
-            DefaultMutableTreeNode treeNode = (DefaultMutableTreeNode) value;
-            Object userObject = treeNode.getUserObject();
-            if (userObject instanceof LayerDetails) {
-                LayerDetails layer = (LayerDetails) userObject;
-                setEnabled(layer.isSupported());
-            }
-            return this;
-        }
-    }
+	private List<LayerDetails> selectedLayers;
+	private URL serviceUrl;
+	private LayerDetails selectedLayer;
+
+	private JTextField menuName;
+	private JTextArea resultingLayerField;
+	private MutableTreeNode treeRootNode;
+	private DefaultTreeModel treeData;
+	private JTree layerTree;
+	private JButton showBoundsButton;
+
+	private boolean previouslyShownUnsupportedCrsError = false;
+
+	public AddWMSLayerPanel() {
+		JPanel wmsFetchPanel = new JPanel(new GridBagLayout());
+		menuName = new JTextField(40);
+		menuName.setText(tr("Unnamed WMS Layer"));
+		final JTextArea serviceUrl = new JTextArea(3, 40);
+		serviceUrl.setLineWrap(true);
+		serviceUrl.setText("http://sample.com/wms?");
+		wmsFetchPanel.add(new JLabel(tr("Menu Name")), GBC.std().insets(0,0,5,0));
+		wmsFetchPanel.add(menuName, GBC.eop().insets(5,0,0,0).fill(GridBagConstraints.HORIZONTAL));
+		wmsFetchPanel.add(new JLabel(tr("Service URL")), GBC.std().insets(0,0,5,0));
+		JScrollPane scrollPane = new JScrollPane(serviceUrl,
+				JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED,
+				JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
+		wmsFetchPanel.add(scrollPane, GBC.eop().insets(5,0,0,0));
+		JButton getLayersButton = new JButton(tr("Get Layers"));
+		getLayersButton.addActionListener(new ActionListener() {
+			public void actionPerformed(ActionEvent e) {
+				Cursor beforeCursor = getCursor();
+				try {
+					setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
+					attemptGetCapabilities(serviceUrl.getText());
+				} finally {
+					setCursor(beforeCursor);
+				}
+			}
+		});
+		wmsFetchPanel.add(getLayersButton, GBC.eop().anchor(GridBagConstraints.EAST));
+
+		treeRootNode = new DefaultMutableTreeNode();
+		treeData = new DefaultTreeModel(treeRootNode);
+		layerTree = new JTree(treeData);
+		layerTree.setCellRenderer(new LayerTreeCellRenderer());
+		layerTree.addTreeSelectionListener(new TreeSelectionListener() {
+
+			public void valueChanged(TreeSelectionEvent e) {
+				TreePath[] selectionRows = layerTree.getSelectionPaths();
+				if(selectionRows == null) {
+					showBoundsButton.setEnabled(false);
+					selectedLayer = null;
+					return;
+				}
+
+				selectedLayers = new LinkedList<LayerDetails>();
+				for (TreePath i : selectionRows) {
+					Object userObject = ((DefaultMutableTreeNode) i.getLastPathComponent()).getUserObject();
+					if(userObject instanceof LayerDetails) {
+						LayerDetails detail = (LayerDetails) userObject;
+						if(!detail.isSupported()) {
+							layerTree.removeSelectionPath(i);
+							if(!previouslyShownUnsupportedCrsError) {
+								JOptionPane.showMessageDialog(null, tr("That layer does not support any of JOSM's projections,\n" +
+								"so you can not use it. This message will not show again."),
+								tr("WMS Error"), JOptionPane.ERROR_MESSAGE);
+								previouslyShownUnsupportedCrsError = true;
+							}
+						} else if(detail.ident != null) {
+							selectedLayers.add(detail);
+						}
+					}
+				}
+
+				if (!selectedLayers.isEmpty()) {
+					resultingLayerField.setText(buildGetMapUrl());
+
+					if(selectedLayers.size() == 1) {
+						showBoundsButton.setEnabled(true);
+						selectedLayer = selectedLayers.get(0);
+					}
+				} else {
+					showBoundsButton.setEnabled(false);
+					selectedLayer = null;
+				}
+			}
+		});
+		wmsFetchPanel.add(new JScrollPane(layerTree), GBC.eop().insets(5,0,0,0).fill(GridBagConstraints.HORIZONTAL));
+
+		JPanel layerManipulationButtons = new JPanel();
+		showBoundsButton = new JButton(tr("Show Bounds"));
+		showBoundsButton.setEnabled(false);
+		showBoundsButton.addActionListener(new ActionListener() {
+			public void actionPerformed(ActionEvent e) {
+				if(selectedLayer.bounds != null) {
+					SlippyMapBBoxChooser mapPanel = new SlippyMapBBoxChooser();
+					mapPanel.setBoundingBox(selectedLayer.bounds);
+					JOptionPane.showMessageDialog(null, mapPanel, tr("Show Bounds"), JOptionPane.PLAIN_MESSAGE);
+				} else {
+					JOptionPane.showMessageDialog(null, tr("No bounding box was found for this layer."),
+							tr("WMS Error"), JOptionPane.ERROR_MESSAGE);
+				}
+			}
+		});
+		layerManipulationButtons.add(showBoundsButton);
+
+		wmsFetchPanel.add(layerManipulationButtons, GBC.eol().insets(0,0,5,0));
+		wmsFetchPanel.add(new JLabel(tr("WMS URL")), GBC.std().insets(0,0,5,0));
+		resultingLayerField = new JTextArea(3, 40);
+		resultingLayerField.setLineWrap(true);
+		wmsFetchPanel.add(new JScrollPane(resultingLayerField, JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED, JScrollPane.HORIZONTAL_SCROLLBAR_NEVER), GBC.eop().insets(5,0,0,0).fill(GridBagConstraints.HORIZONTAL));
+
+		add(wmsFetchPanel);
+	}
+
+	private String buildRootUrl() {
+		StringBuilder a = new StringBuilder(serviceUrl.getProtocol());
+		a.append("://");
+		a.append(serviceUrl.getHost());
+		if(serviceUrl.getPort() != -1) {
+			a.append(":");
+			a.append(serviceUrl.getPort());
+		}
+		a.append(serviceUrl.getPath());
+		a.append("?");
+		if(serviceUrl.getQuery() != null) {
+			a.append(serviceUrl.getQuery());
+			if (!serviceUrl.getQuery().isEmpty() && !serviceUrl.getQuery().endsWith("&")) {
+				a.append("&");
+			}
+		}
+		return a.toString();
+	}
+
+	private String buildGetMapUrl() {
+		StringBuilder a = new StringBuilder();
+		a.append(buildRootUrl());
+		a.append("FORMAT=image/jpeg&VERSION=1.1.1&SERVICE=WMS&REQUEST=GetMap&Layers=");
+		a.append(commaSepLayerList());
+		a.append("&");
+
+		return a.toString();
+	}
+
+	private String commaSepLayerList() {
+		StringBuilder b = new StringBuilder();
+
+		Iterator<LayerDetails> iterator = selectedLayers.iterator();
+		while (iterator.hasNext()) {
+			LayerDetails layerDetails = iterator.next();
+			b.append(layerDetails.ident);
+			if(iterator.hasNext()) {
+				b.append(",");
+			}
+		}
+
+		return b.toString();
+	}
+
+	private void showError(String incomingData, Exception e) {
+		JOptionPane.showMessageDialog(this, tr("Could not parse WMS layer list."),
+				tr("WMS Error"), JOptionPane.ERROR_MESSAGE);
+		System.err.println("Could not parse WMS layer list. Incoming data:");
+		System.err.println(incomingData);
+		e.printStackTrace();
+	}
+
+	private void attemptGetCapabilities(String serviceUrlStr) {
+		URL getCapabilitiesUrl = null;
+		try {
+			if (!serviceUrlStr.trim().contains("capabilities")) {
+				// If the url doesn't already have GetCapabilities, add it in
+				getCapabilitiesUrl = new URL(serviceUrlStr + "VERSION=1.1.1&SERVICE=WMS&REQUEST=GetCapabilities");
+			} else {
+				// Otherwise assume it's a good URL and let the subsequent error
+				// handling systems deal with problems
+				getCapabilitiesUrl = new URL(serviceUrlStr);
+			}
+			serviceUrl = new URL(serviceUrlStr);
+		} catch (HeadlessException e) {
+			return;
+		} catch (MalformedURLException e) {
+			JOptionPane.showMessageDialog(this, tr("Invalid service URL."),
+					tr("WMS Error"), JOptionPane.ERROR_MESSAGE);
+			return;
+		}
+
+		String incomingData;
+		try {
+			URLConnection openConnection = getCapabilitiesUrl.openConnection();
+			InputStream inputStream = openConnection.getInputStream();
+			BufferedReader br = new BufferedReader(new InputStreamReader(inputStream));
+			String line;
+			StringBuilder ba = new StringBuilder();
+			while((line = br.readLine()) != null) {
+				ba.append(line);
+				ba.append("\n");
+			}
+			incomingData = ba.toString();
+		} catch (IOException e) {
+			JOptionPane.showMessageDialog(this, tr("Could not retrieve WMS layer list."),
+					tr("WMS Error"), JOptionPane.ERROR_MESSAGE);
+			return;
+		}
+
+		Document document;
+		try {
+			DocumentBuilderFactory builderFactory = DocumentBuilderFactory.newInstance();
+			builderFactory.setValidating(false);
+			builderFactory.setNamespaceAware(true);
+			DocumentBuilder builder = builderFactory.newDocumentBuilder();
+			builder.setEntityResolver(new EntityResolver() {
+				public InputSource resolveEntity(String publicId, String systemId) throws SAXException, IOException {
+					System.out.println("Ignoring DTD " + publicId + ", " + systemId);
+					return new InputSource(new StringReader(""));
+				}
+			});
+			document = builder.parse(new InputSource(new StringReader(incomingData)));
+		} catch (ParserConfigurationException e) {
+			showError(incomingData, e);
+			return;
+		} catch (SAXException e) {
+			showError(incomingData, e);
+			return;
+		} catch (IOException e) {
+			showError(incomingData, e);
+			return;
+		}
+
+		// Some WMS service URLs specify a different base URL for their GetMap service
+		Element child = getChild(document.getDocumentElement(), "Capability");
+		child = getChild(child, "Request");
+		child = getChild(child, "GetMap");
+		child = getChild(child, "DCPType");
+		child = getChild(child, "HTTP");
+		child = getChild(child, "Get");
+		child = getChild(child, "OnlineResource");
+		if (child != null) {
+			String baseURL = child.getAttribute("xlink:href");
+			if(baseURL != null) {
+				try {
+					System.out.println("GetCapabilities specifies a different service URL: " + baseURL);
+					serviceUrl = new URL(baseURL);
+				} catch (MalformedURLException e1) {
+				}
+			}
+		}
+
+		try {
+			treeRootNode.setUserObject(getCapabilitiesUrl.getHost());
+			Element capabilityElem = getChild(document.getDocumentElement(), "Capability");
+			List<Element> children = getChildren(capabilityElem, "Layer");
+			List<LayerDetails> layers = parseLayers(children, new HashSet<String>());
+			updateTreeList(layers);
+		} catch(Exception e) {
+			showError(incomingData, e);
+			return;
+		}
+	}
+
+	private void updateTreeList(List<LayerDetails> layers) {
+		addLayersToTreeData(treeRootNode, layers);
+		layerTree.expandRow(0);
+	}
+
+	private void addLayersToTreeData(MutableTreeNode parent, List<LayerDetails> layers) {
+		for (LayerDetails layerDetails : layers) {
+			DefaultMutableTreeNode treeNode = new DefaultMutableTreeNode(layerDetails);
+			addLayersToTreeData(treeNode, layerDetails.children);
+			treeData.insertNodeInto(treeNode, parent, 0);
+		}
+	}
+
+	private List<LayerDetails> parseLayers(List<Element> children, Set<String> parentCrs) {
+		List<LayerDetails> details = new LinkedList<LayerDetails>();
+		for (Element element : children) {
+			details.add(parseLayer(element, parentCrs));
+		}
+		return details;
+	}
+
+	private LayerDetails parseLayer(Element element, Set<String> parentCrs) {
+		String name = getChildContent(element, "Title", null, null);
+		String ident = getChildContent(element, "Name", null, null);
+
+		// The set of supported CRS/SRS for this layer
+		Set<String> crsList = new HashSet<String>();
+		// ...including this layer's already-parsed parent projections
+		crsList.addAll(parentCrs);
+
+		// Parse the CRS/SRS pulled out of this layer's XML element
+		// I think CRS and SRS are the same at this point
+		List<Element> crsChildren = getChildren(element, "CRS");
+		crsChildren.addAll(getChildren(element, "SRS"));
+		for (Element child : crsChildren) {
+			String crs = (String) getContent(child);
+			if(crs != null) {
+				String upperCase = crs.trim().toUpperCase();
+				crsList.add(upperCase);
+			}
+		}
+
+		// Check to see if any of the specified projections are supported by JOSM
+		boolean josmSupportsThisLayer = false;
+		for (String crs : crsList) {
+			josmSupportsThisLayer |= isProjSupported(crs);
+		}
+
+		Bounds bounds = null;
+		Element bboxElem = getChild(element, "EX_GeographicBoundingBox");
+		if(bboxElem != null) {
+			// Attempt to use EX_GeographicBoundingBox for bounding box
+			double left = Double.parseDouble(getChildContent(bboxElem, "westBoundLongitude", null, null));
+			double top = Double.parseDouble(getChildContent(bboxElem, "northBoundLatitude", null, null));
+			double right = Double.parseDouble(getChildContent(bboxElem, "eastBoundLongitude", null, null));
+			double bot = Double.parseDouble(getChildContent(bboxElem, "southBoundLatitude", null, null));
+			bounds = new Bounds(bot, left, top, right);
+		} else {
+			// If that's not available, try LatLonBoundingBox
+			bboxElem = getChild(element, "LatLonBoundingBox");
+			if(bboxElem != null) {
+				double left = Double.parseDouble(bboxElem.getAttribute("minx"));
+				double top = Double.parseDouble(bboxElem.getAttribute("maxy"));
+				double right = Double.parseDouble(bboxElem.getAttribute("maxx"));
+				double bot = Double.parseDouble(bboxElem.getAttribute("miny"));
+				bounds = new Bounds(bot, left, top, right);
+			}
+		}
+
+		List<Element> layerChildren = getChildren(element, "Layer");
+		List<LayerDetails> childLayers = parseLayers(layerChildren, crsList);
+
+		return new LayerDetails(name, ident, crsList, josmSupportsThisLayer, bounds, childLayers);
+	}
+
+	private boolean isProjSupported(String crs) {
+		for (Projection proj : Projection.allProjections) {
+			if (proj instanceof ProjectionSubPrefs) {
+				if (((ProjectionSubPrefs) proj).getPreferencesFromCode(crs) == null) {
+					return true;
+				}
+			} else {
+				if (proj.toCode().equals(crs)) {
+					return true;
+				}
+			}
+		}
+		return false;
+	}
+
+	public String getUrlName() {
+		return menuName.getText();
+	}
+
+	public String getUrl() {
+		return resultingLayerField.getText();
+	}
+
+	public static void main(String[] args) {
+		JFrame f = new JFrame("Test");
+		f.setContentPane(new AddWMSLayerPanel());
+		f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
+		f.pack();
+		f.setVisible(true);
+	}
+
+	private static String getChildContent(Element parent, String name, String missing, String empty) {
+		Element child = getChild(parent, name);
+		if (child == null) {
+			return missing;
+		} else {
+			String content = (String) getContent(child);
+			return (content != null) ? content : empty;
+		}
+	}
+
+	private static Object getContent(Element element) {
+		NodeList nl = element.getChildNodes();
+		StringBuffer content = new StringBuffer();
+		for (int i = 0; i < nl.getLength(); i++) {
+			Node node = nl.item(i);
+			switch (node.getNodeType()) {
+			case Node.ELEMENT_NODE:
+				return node;
+			case Node.CDATA_SECTION_NODE:
+			case Node.TEXT_NODE:
+				content.append(node.getNodeValue());
+				break;
+			}
+		}
+		return content.toString().trim();
+	}
+
+	private static List<Element> getChildren(Element parent, String name) {
+		List<Element> retVal = new LinkedList<Element>();
+		for (Node child = parent.getFirstChild(); child != null; child = child.getNextSibling()) {
+			if (child instanceof Element && name.equals(child.getNodeName())) {
+				retVal.add((Element) child);
+			}
+		}
+		return retVal;
+	}
+
+	private static Element getChild(Element parent, String name) {
+		if (parent == null) {
+			return null;
+		}
+		for (Node child = parent.getFirstChild(); child != null; child = child.getNextSibling()) {
+			if (child instanceof Element && name.equals(child.getNodeName())) {
+				return (Element) child;
+			}
+		}
+		return null;
+	}
+
+	class LayerDetails {
+
+		private String name;
+		private String ident;
+		private List<LayerDetails> children;
+		private Bounds bounds;
+		private boolean supported;
+
+		public LayerDetails(String name, String ident, Set<String> crsList,
+				boolean supportedLayer, Bounds bounds,
+				List<LayerDetails> childLayers) {
+			this.name = name;
+			this.ident = ident;
+			this.supported = supportedLayer;
+			this.children = childLayers;
+			this.bounds = bounds;
+		}
+
+		public boolean isSupported() {
+			return this.supported;
+		}
+
+		@Override
+		public String toString() {
+			if(this.name == null || this.name.isEmpty()) {
+				return this.ident;
+			} else {
+				return this.name;
+			}
+		}
+
+	}
+
+	class LayerTreeCellRenderer extends DefaultTreeCellRenderer {
+		@Override
+		public Component getTreeCellRendererComponent(JTree tree, Object value,
+				boolean sel, boolean expanded, boolean leaf, int row,
+				boolean hasFocus) {
+			super.getTreeCellRendererComponent(tree, value, sel, expanded, leaf,
+					row, hasFocus);
+			DefaultMutableTreeNode treeNode = (DefaultMutableTreeNode) value;
+			Object userObject = treeNode.getUserObject();
+			if (userObject instanceof LayerDetails) {
+				LayerDetails layer = (LayerDetails) userObject;
+				setEnabled(layer.isSupported());
+			}
+			return this;
+		}
+	}
 
 }
diff --git a/wmsplugin/src/wmsplugin/GeorefImage.java b/wmsplugin/src/wmsplugin/GeorefImage.java
index 1245ff0..7cce587 100644
--- a/wmsplugin/src/wmsplugin/GeorefImage.java
+++ b/wmsplugin/src/wmsplugin/GeorefImage.java
@@ -20,204 +20,204 @@ import org.openstreetmap.josm.data.coor.EastNorth;
 import org.openstreetmap.josm.gui.NavigatableComponent;
 
 public class GeorefImage implements Serializable {
-	private static final long serialVersionUID = 1L;
-
-	public enum State { IMAGE, NOT_IN_CACHE, FAILED};
-
-	private WMSLayer layer;
-	private State state;
-
-	private BufferedImage image;
-	private SoftReference<BufferedImage> reImg;
-	private int xIndex;
-	private int yIndex;
-
-
-	public EastNorth getMin() {
-		return layer.getEastNorth(xIndex, yIndex);
-	}
-
-	public EastNorth getMax() {
-		return layer.getEastNorth(xIndex+1, yIndex+1);
-	}
-
-
-	public GeorefImage(WMSLayer layer) {
-		this.layer = layer;
-	}
-
-	public void changePosition(int xIndex, int yIndex) {
-		if (!equalPosition(xIndex, yIndex)) {
-			this.xIndex = xIndex;
-			this.yIndex = yIndex;
-			this.image = null;
-			flushedResizedCachedInstance();
-		}
-	}
-
-	public boolean equalPosition(int xIndex, int yIndex) {
-		return this.xIndex == xIndex && this.yIndex == yIndex;
-	}
-
-	public void changeImage(State state, BufferedImage image) {
-		flushedResizedCachedInstance();
-		this.image = image;
-		this.state = state;
-
-		switch (state) {
-		case FAILED:
-		{
-			BufferedImage img = createImage();
-			Graphics g = img.getGraphics();
-			g.setColor(Color.RED);
-			g.fillRect(0, 0, img.getWidth(), img.getHeight());
-			g.setFont(g.getFont().deriveFont(Font.PLAIN).deriveFont(36.0f));
-			g.setColor(Color.BLACK);
-			g.drawString(tr("Exception occurred"), 10, img.getHeight()/2);
-			this.image = img;
-			break;
-		}
-		case NOT_IN_CACHE:
-		{
-			BufferedImage img = createImage();
-			Graphics g = img.getGraphics();
-			g.setColor(Color.GRAY);
-			g.fillRect(0, 0, img.getWidth(), img.getHeight());
-			Font font = g.getFont();
-			Font tempFont = font.deriveFont(Font.PLAIN).deriveFont(36.0f);
-			g.setFont(tempFont);
-			g.setColor(Color.BLACK);
-			g.drawString(tr("Not in cache"), 10, img.getHeight()/2);
-			g.setFont(font);
-			this.image = img;
-			break;
-		}
-		default:
-			break;
-		}
-	}
-
-	private BufferedImage createImage() {
-		return new BufferedImage(layer.getBaseImageWidth(), layer.getBaseImageHeight(), BufferedImage.TYPE_INT_RGB);
-	}
-
-	public boolean paint(Graphics g, NavigatableComponent nc, int xIndex, int yIndex, int leftEdge, int bottomEdge) {
-		if (image == null)
-			return false;
-
-		if(!(this.xIndex == xIndex && this.yIndex == yIndex)){
-			return false;
-		}
-
-		int left = layer.getImageX(xIndex);
-		int bottom = layer.getImageY(yIndex);
-		int width = layer.getImageWidth(xIndex);
-		int height = layer.getImageHeight(yIndex);
-
-		int x = left - leftEdge;
-		int y = nc.getHeight() - (bottom - bottomEdge) - height;
-
-		// This happens if you zoom outside the world
-		if(width == 0 || height == 0)
-			return false;
-
-		BufferedImage img = reImg == null?null:reImg.get();
-		if(img != null && img.getWidth() == width && img.getHeight() == height) {
-			g.drawImage(img, x, y, null);
-			return true;
-		}
-
-		boolean alphaChannel = WMSLayer.PROP_ALPHA_CHANNEL.get() && getImage().getTransparency() != Transparency.OPAQUE;
-
-		try {
-			if(img != null) img.flush();
-			long freeMem = Runtime.getRuntime().maxMemory() - Runtime.getRuntime().totalMemory();
-			//System.out.println("Free Memory:           "+ (freeMem/1024/1024) +" MB");
-			// Notice that this value can get negative due to integer overflows
-			//System.out.println("Img Size:              "+ (width*height*3/1024/1024) +" MB");
-
-			int multipl = alphaChannel ? 4 : 3;
-			// This happens when requesting images while zoomed out and then zooming in
-			// Storing images this large in memory will certainly hang up JOSM. Luckily
-			// traditional rendering is as fast at these zoom levels, so it's no loss.
-			// Also prevent caching if we're out of memory soon
-			if(width > 2000 || height > 2000 || width*height*multipl > freeMem) {
-				fallbackDraw(g, getImage(), x, y, width, height);
-			} else {
-				// We haven't got a saved resized copy, so resize and cache it
-				img = new BufferedImage(width, height, alphaChannel?BufferedImage.TYPE_INT_ARGB:BufferedImage.TYPE_3BYTE_BGR);
-				img.getGraphics().drawImage(getImage(),
-						0, 0, width, height, // dest
-						0, 0, getImage().getWidth(null), getImage().getHeight(null), // src
-						null);
-				img.getGraphics().dispose();
-				g.drawImage(img, x, y, null);
-				reImg = new SoftReference<BufferedImage>(img);
-			}
-		} catch(Exception e) {
-			fallbackDraw(g, getImage(), x, y, width, height);
-		}
-		return true;
-	}
-
-	private void fallbackDraw(Graphics g, Image img, int x, int y, int width, int height) {
-		flushedResizedCachedInstance();
-		g.drawImage(
-				img, x, y, x + width, y + height,
-				0, 0, img.getWidth(null), img.getHeight(null),
-				null);
-	}
-
-	private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
-		state = (State) in.readObject();
-		boolean hasImage = in.readBoolean();
-		if (hasImage)
-			image = (ImageIO.read(ImageIO.createImageInputStream(in)));
-		else {
-			in.readObject(); // read null from input stream
-			image = null;
-		}
-	}
-
-	private void writeObject(ObjectOutputStream out) throws IOException {
-		out.writeObject(state);
-		if(getImage() == null) {
-			out.writeBoolean(false);
-			out.writeObject(null);
-		} else {
-			out.writeBoolean(true);
-			ImageIO.write(getImage(), "png", ImageIO.createImageOutputStream(out));
-		}
-	}
-
-	public void flushedResizedCachedInstance() {
-		if (reImg != null) {
-			BufferedImage img = reImg.get();
-			if (img != null) {
-				img.flush();
-			}
-		}
-		reImg = null;
-	}
-
-
-	public BufferedImage getImage() {
-		return image;
-	}
-
-	public State getState() {
-		return state;
-	}
-
-	public int getXIndex() {
-		return xIndex;
-	}
-
-	public int getYIndex() {
-		return yIndex;
-	}
-
-	public void setLayer(WMSLayer layer) {
-		this.layer = layer;
-	}
+    private static final long serialVersionUID = 1L;
+
+    public enum State { IMAGE, NOT_IN_CACHE, FAILED};
+
+    private WMSLayer layer;
+    private State state;
+
+    private BufferedImage image;
+    private SoftReference<BufferedImage> reImg;
+    private int xIndex;
+    private int yIndex;
+
+
+    public EastNorth getMin() {
+        return layer.getEastNorth(xIndex, yIndex);
+    }
+
+    public EastNorth getMax() {
+        return layer.getEastNorth(xIndex+1, yIndex+1);
+    }
+
+
+    public GeorefImage(WMSLayer layer) {
+        this.layer = layer;
+    }
+
+    public void changePosition(int xIndex, int yIndex) {
+        if (!equalPosition(xIndex, yIndex)) {
+            this.xIndex = xIndex;
+            this.yIndex = yIndex;
+            this.image = null;
+            flushedResizedCachedInstance();
+        }
+    }
+
+    public boolean equalPosition(int xIndex, int yIndex) {
+        return this.xIndex == xIndex && this.yIndex == yIndex;
+    }
+
+    public void changeImage(State state, BufferedImage image) {
+        flushedResizedCachedInstance();
+        this.image = image;
+        this.state = state;
+
+        switch (state) {
+        case FAILED:
+        {
+            BufferedImage img = createImage();
+            Graphics g = img.getGraphics();
+            g.setColor(Color.RED);
+            g.fillRect(0, 0, img.getWidth(), img.getHeight());
+            g.setFont(g.getFont().deriveFont(Font.PLAIN).deriveFont(36.0f));
+            g.setColor(Color.BLACK);
+            g.drawString(tr("Exception occurred"), 10, img.getHeight()/2);
+            this.image = img;
+            break;
+        }
+        case NOT_IN_CACHE:
+        {
+            BufferedImage img = createImage();
+            Graphics g = img.getGraphics();
+            g.setColor(Color.GRAY);
+            g.fillRect(0, 0, img.getWidth(), img.getHeight());
+            Font font = g.getFont();
+            Font tempFont = font.deriveFont(Font.PLAIN).deriveFont(36.0f);
+            g.setFont(tempFont);
+            g.setColor(Color.BLACK);
+            g.drawString(tr("Not in cache"), 10, img.getHeight()/2);
+            g.setFont(font);
+            this.image = img;
+            break;
+        }
+        default:
+            break;
+        }
+    }
+
+    private BufferedImage createImage() {
+        return new BufferedImage(layer.getBaseImageWidth(), layer.getBaseImageHeight(), BufferedImage.TYPE_INT_RGB);
+    }
+
+    public boolean paint(Graphics g, NavigatableComponent nc, int xIndex, int yIndex, int leftEdge, int bottomEdge) {
+        if (image == null)
+            return false;
+
+        if(!(this.xIndex == xIndex && this.yIndex == yIndex)){
+            return false;
+        }
+
+        int left = layer.getImageX(xIndex);
+        int bottom = layer.getImageY(yIndex);
+        int width = layer.getImageWidth(xIndex);
+        int height = layer.getImageHeight(yIndex);
+
+        int x = left - leftEdge;
+        int y = nc.getHeight() - (bottom - bottomEdge) - height;
+
+        // This happens if you zoom outside the world
+        if(width == 0 || height == 0)
+            return false;
+
+        BufferedImage img = reImg == null?null:reImg.get();
+        if(img != null && img.getWidth() == width && img.getHeight() == height) {
+            g.drawImage(img, x, y, null);
+            return true;
+        }
+
+        boolean alphaChannel = WMSLayer.PROP_ALPHA_CHANNEL.get() && getImage().getTransparency() != Transparency.OPAQUE;
+
+        try {
+            if(img != null) img.flush();
+            long freeMem = Runtime.getRuntime().maxMemory() - Runtime.getRuntime().totalMemory();
+            //System.out.println("Free Memory:           "+ (freeMem/1024/1024) +" MB");
+            // Notice that this value can get negative due to integer overflows
+            //System.out.println("Img Size:              "+ (width*height*3/1024/1024) +" MB");
+
+            int multipl = alphaChannel ? 4 : 3;
+            // This happens when requesting images while zoomed out and then zooming in
+            // Storing images this large in memory will certainly hang up JOSM. Luckily
+            // traditional rendering is as fast at these zoom levels, so it's no loss.
+            // Also prevent caching if we're out of memory soon
+            if(width > 2000 || height > 2000 || width*height*multipl > freeMem) {
+                fallbackDraw(g, getImage(), x, y, width, height);
+            } else {
+                // We haven't got a saved resized copy, so resize and cache it
+                img = new BufferedImage(width, height, alphaChannel?BufferedImage.TYPE_INT_ARGB:BufferedImage.TYPE_3BYTE_BGR);
+                img.getGraphics().drawImage(getImage(),
+                        0, 0, width, height, // dest
+                        0, 0, getImage().getWidth(null), getImage().getHeight(null), // src
+                        null);
+                img.getGraphics().dispose();
+                g.drawImage(img, x, y, null);
+                reImg = new SoftReference<BufferedImage>(img);
+            }
+        } catch(Exception e) {
+            fallbackDraw(g, getImage(), x, y, width, height);
+        }
+        return true;
+    }
+
+    private void fallbackDraw(Graphics g, Image img, int x, int y, int width, int height) {
+        flushedResizedCachedInstance();
+        g.drawImage(
+                img, x, y, x + width, y + height,
+                0, 0, img.getWidth(null), img.getHeight(null),
+                null);
+    }
+
+    private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
+        state = (State) in.readObject();
+        boolean hasImage = in.readBoolean();
+        if (hasImage)
+            image = (ImageIO.read(ImageIO.createImageInputStream(in)));
+        else {
+            in.readObject(); // read null from input stream
+            image = null;
+        }
+    }
+
+    private void writeObject(ObjectOutputStream out) throws IOException {
+        out.writeObject(state);
+        if(getImage() == null) {
+            out.writeBoolean(false);
+            out.writeObject(null);
+        } else {
+            out.writeBoolean(true);
+            ImageIO.write(getImage(), "png", ImageIO.createImageOutputStream(out));
+        }
+    }
+
+    public void flushedResizedCachedInstance() {
+        if (reImg != null) {
+            BufferedImage img = reImg.get();
+            if (img != null) {
+                img.flush();
+            }
+        }
+        reImg = null;
+    }
+
+
+    public BufferedImage getImage() {
+        return image;
+    }
+
+    public State getState() {
+        return state;
+    }
+
+    public int getXIndex() {
+        return xIndex;
+    }
+
+    public int getYIndex() {
+        return yIndex;
+    }
+
+    public void setLayer(WMSLayer layer) {
+        this.layer = layer;
+    }
 }
diff --git a/wmsplugin/src/wmsplugin/Grabber.java b/wmsplugin/src/wmsplugin/Grabber.java
index c225370..abf3c44 100644
--- a/wmsplugin/src/wmsplugin/Grabber.java
+++ b/wmsplugin/src/wmsplugin/Grabber.java
@@ -10,106 +10,106 @@ import org.openstreetmap.josm.io.CacheFiles;
 import wmsplugin.GeorefImage.State;
 
 abstract public class Grabber implements Runnable {
-	protected final MapView mv;
-	protected final WMSLayer layer;
-	protected final CacheFiles cache;
-
-	protected ProjectionBounds b;
-	protected Projection proj;
-	protected double pixelPerDegree;
-	protected WMSRequest request;
-	protected volatile boolean canceled;
-
-	Grabber(MapView mv, WMSLayer layer, CacheFiles cache) {
-		this.mv = mv;
-		this.layer = layer;
-		this.cache = cache;
-	}
-
-	private void updateState(WMSRequest request) {
-		b = new ProjectionBounds(
-				layer.getEastNorth(request.getXIndex(), request.getYIndex()),
-				layer.getEastNorth(request.getXIndex() + 1, request.getYIndex() + 1));
-		if (b.min != null && b.max != null && WMSPlugin.PROP_OVERLAP.get()) {
-			double eastSize =  b.max.east() - b.min.east();
-			double northSize =  b.max.north() - b.min.north();
-
-			double eastCoef = WMSPlugin.PROP_OVERLAP_EAST.get() / 100.0;
-			double northCoef = WMSPlugin.PROP_OVERLAP_NORTH.get() / 100.0;
-
-			this.b = new ProjectionBounds( new EastNorth(b.min.east(),
-					b.min.north()),
-					new EastNorth(b.max.east() + eastCoef * eastSize,
-							b.max.north() + northCoef * northSize));
-		}
-
-		this.proj = Main.proj;
-		this.pixelPerDegree = request.getPixelPerDegree();
-		this.request = request;
-	}
-
-	abstract void fetch(WMSRequest request) throws Exception; // the image fetch code
-
-	int width(){
-		return layer.getBaseImageWidth();
-	}
-	int height(){
-		return layer.getBaseImageHeight();
-	}
-
-	@Override
-	public void run() {
-		while (true) {
-			if (canceled) {
-				return;
-			}
-			WMSRequest request = layer.getRequest();
-			if (request == null) {
-				return;
-			}
-			updateState(request);
-			if(!loadFromCache(request)){
-				attempt(request);
-			}
-			if (request.getState() != null) {
-				layer.finishRequest(request);
-				mv.repaint();
-			}
-		}
-	}
-
-	protected void attempt(WMSRequest request){ // try to fetch the image
-		int maxTries = 5; // n tries for every image
-		for (int i = 1; i <= maxTries; i++) {
-			if (canceled) {
-				return;
-			}
-			try {
-				if (!layer.requestIsValid(request)) {
-					return;
-				}
-				fetch(request);
-				break; // break out of the retry loop
-			} catch (Exception e) {
-				try { // sleep some time and then ask the server again
-					Thread.sleep(random(1000, 2000));
-				} catch (InterruptedException e1) {}
-
-				if(i == maxTries) {
-					e.printStackTrace();
-					request.finish(State.FAILED, null);
-				}
-			}
-		}
-	}
-
-	public static int random(int min, int max) {
-		return (int)(Math.random() * ((max+1)-min) ) + min;
-	}
-
-	abstract public boolean loadFromCache(WMSRequest request);
-
-	public void cancel() {
-		canceled = true;
-	}
+    protected final MapView mv;
+    protected final WMSLayer layer;
+    protected final CacheFiles cache;
+
+    protected ProjectionBounds b;
+    protected Projection proj;
+    protected double pixelPerDegree;
+    protected WMSRequest request;
+    protected volatile boolean canceled;
+
+    Grabber(MapView mv, WMSLayer layer, CacheFiles cache) {
+        this.mv = mv;
+        this.layer = layer;
+        this.cache = cache;
+    }
+
+    private void updateState(WMSRequest request) {
+        b = new ProjectionBounds(
+                layer.getEastNorth(request.getXIndex(), request.getYIndex()),
+                layer.getEastNorth(request.getXIndex() + 1, request.getYIndex() + 1));
+        if (b.min != null && b.max != null && WMSPlugin.instance.PROP_OVERLAP.get()) {
+            double eastSize =  b.max.east() - b.min.east();
+            double northSize =  b.max.north() - b.min.north();
+
+            double eastCoef = WMSPlugin.instance.PROP_OVERLAP_EAST.get() / 100.0;
+            double northCoef = WMSPlugin.instance.PROP_OVERLAP_NORTH.get() / 100.0;
+
+            this.b = new ProjectionBounds( new EastNorth(b.min.east(),
+                    b.min.north()),
+                    new EastNorth(b.max.east() + eastCoef * eastSize,
+                            b.max.north() + northCoef * northSize));
+        }
+
+        this.proj = Main.proj;
+        this.pixelPerDegree = request.getPixelPerDegree();
+        this.request = request;
+    }
+
+    abstract void fetch(WMSRequest request) throws Exception; // the image fetch code
+
+    int width(){
+        return layer.getBaseImageWidth();
+    }
+    int height(){
+        return layer.getBaseImageHeight();
+    }
+
+    @Override
+    public void run() {
+        while (true) {
+            if (canceled) {
+                return;
+            }
+            WMSRequest request = layer.getRequest();
+            if (request == null) {
+                return;
+            }
+            updateState(request);
+            if(!loadFromCache(request)){
+                attempt(request);
+            }
+            if (request.getState() != null) {
+                layer.finishRequest(request);
+                mv.repaint();
+            }
+        }
+    }
+
+    protected void attempt(WMSRequest request){ // try to fetch the image
+        int maxTries = 5; // n tries for every image
+        for (int i = 1; i <= maxTries; i++) {
+            if (canceled) {
+                return;
+            }
+            try {
+                if (!layer.requestIsValid(request)) {
+                    return;
+                }
+                fetch(request);
+                break; // break out of the retry loop
+            } catch (Exception e) {
+                try { // sleep some time and then ask the server again
+                    Thread.sleep(random(1000, 2000));
+                } catch (InterruptedException e1) {}
+
+                if(i == maxTries) {
+                    e.printStackTrace();
+                    request.finish(State.FAILED, null);
+                }
+            }
+        }
+    }
+
+    public static int random(int min, int max) {
+        return (int)(Math.random() * ((max+1)-min) ) + min;
+    }
+
+    abstract public boolean loadFromCache(WMSRequest request);
+
+    public void cancel() {
+        canceled = true;
+    }
 }
diff --git a/wmsplugin/src/wmsplugin/HTMLGrabber.java b/wmsplugin/src/wmsplugin/HTMLGrabber.java
index ec5e8d5..4956b9e 100644
--- a/wmsplugin/src/wmsplugin/HTMLGrabber.java
+++ b/wmsplugin/src/wmsplugin/HTMLGrabber.java
@@ -14,34 +14,33 @@ import org.openstreetmap.josm.gui.MapView;
 import org.openstreetmap.josm.io.CacheFiles;
 
 public class HTMLGrabber extends WMSGrabber {
-	HTMLGrabber(MapView mv, WMSLayer layer, CacheFiles cache) {
-		super(mv, layer, cache);
-		this.baseURL = layer.baseURL.replaceFirst("html:", "");
-	}
-
-	@Override
-	protected BufferedImage grab(URL url) throws IOException {
-		String urlstring = url.toExternalForm();
-
-		System.out.println("Grabbing HTML " + url);
-
-		ArrayList<String> cmdParams = new ArrayList<String>();
-		StringTokenizer st = new StringTokenizer(MessageFormat.format(
-				Main.pref.get("wmsplugin.browser", "webkit-image {0}"), urlstring));
-		while( st.hasMoreTokens() )
-			cmdParams.add(st.nextToken());
-
-		ProcessBuilder builder = new ProcessBuilder( cmdParams);
-
-		Process browser;
-		try {
-			browser = builder.start();
-		} catch(IOException ioe) {
-			throw new IOException( "Could not start browser. Please check that the executable path is correct.\n" + ioe.getMessage() );
-		}
-
-		BufferedImage img = ImageIO.read(browser.getInputStream());
-		cache.saveImg(urlstring, img);
-		return img;
-	}
+    HTMLGrabber(MapView mv, WMSLayer layer, CacheFiles cache) {
+        super(mv, layer, cache);
+    }
+
+    @Override
+    protected BufferedImage grab(URL url) throws IOException {
+        String urlstring = url.toExternalForm();
+
+        System.out.println("Grabbing HTML " + url);
+
+        ArrayList<String> cmdParams = new ArrayList<String>();
+        StringTokenizer st = new StringTokenizer(MessageFormat.format(
+                Main.pref.get("wmsplugin.browser", "webkit-image {0}"), urlstring));
+        while( st.hasMoreTokens() )
+            cmdParams.add(st.nextToken());
+
+        ProcessBuilder builder = new ProcessBuilder( cmdParams);
+
+        Process browser;
+        try {
+            browser = builder.start();
+        } catch(IOException ioe) {
+            throw new IOException( "Could not start browser. Please check that the executable path is correct.\n" + ioe.getMessage() );
+        }
+
+        BufferedImage img = ImageIO.read(browser.getInputStream());
+        cache.saveImg(urlstring, img);
+        return img;
+    }
 }
diff --git a/wmsplugin/src/wmsplugin/Map_Rectifier_WMSmenuAction.java b/wmsplugin/src/wmsplugin/Map_Rectifier_WMSmenuAction.java
index b3cf66d..73855da 100644
--- a/wmsplugin/src/wmsplugin/Map_Rectifier_WMSmenuAction.java
+++ b/wmsplugin/src/wmsplugin/Map_Rectifier_WMSmenuAction.java
@@ -28,220 +28,209 @@ import org.openstreetmap.josm.tools.Shortcut;
 import org.openstreetmap.josm.tools.UrlLabel;
 
 public class Map_Rectifier_WMSmenuAction extends JosmAction {
-	/**
-	 * Class that bundles all required information of a rectifier service
-	 */
-	public static class RectifierService {
-		private final String name;
-		private final String url;
-		private final String wmsUrl;
-		private final Pattern urlRegEx;
-		private final Pattern idValidator;
-		public JRadioButton btn;
-		/**
-		 * @param name: Name of the rectifing service
-		 * @param url: URL to the service where users can register, upload, etc.
-		 * @param wmsUrl: URL to the WMS server where JOSM will grab the images. Insert __s__ where the ID should be placed
-		 * @param urlRegEx: a regular expression that determines if a given URL is one of the service and returns the WMS id if so
-		 * @param idValidator: regular expression that checks if a given ID is syntactically valid
-		 */
-		public RectifierService(String name, String url, String wmsUrl, String urlRegEx, String idValidator) {
-			this.name = name;
-			this.url = url;
-			this.wmsUrl = wmsUrl;
-			this.urlRegEx = Pattern.compile(urlRegEx);
-			this.idValidator = Pattern.compile(idValidator);
-		}
-
-		public boolean isSelected() {
-			return btn.isSelected();
-		}
-	}
-
-	/**
-	 * List of available rectifier services. May be extended from the outside
-	 */
-	public ArrayList<RectifierService> services = new ArrayList<RectifierService>();
-
-	public Map_Rectifier_WMSmenuAction() {
-		super(tr("Rectified Image..."),
-				"OLmarker",
-				tr("Download Rectified Images From Various Services"),
-				Shortcut.registerShortcut("wms:rectimg",
-						tr("WMS: {0}", tr("Rectified Image...")),
-						KeyEvent.VK_R,
-						Shortcut.GROUP_NONE),
-						true
-		);
-
-		// Add default services
-		services.add(
-				new RectifierService("Metacarta Map Rectifier",
-						"http://labs.metacarta.com/rectifier/",
-						"http://labs.metacarta.com/rectifier/wms.cgi?id=__s__&srs=EPSG:4326"
-						+ "&Service=WMS&Version=1.1.0&Request=GetMap&format=image/png&",
-						// This matches more than the "classic" WMS link, so users can pretty much
-						// copy any link as long as it includes the ID
-						"labs\\.metacarta\\.com/(?:.*?)(?:/|=)([0-9]+)(?:\\?|/|\\.|$)",
-				"^[0-9]+$")
-		);
-		services.add(
-				// TODO: Change all links to mapwarper.net once the project has moved.
-				// The RegEx already matches the new URL and old URLs will be forwarded
-				// to make the transition as smooth as possible for the users
-				new RectifierService("Geothings Map Warper",
-						"http://warper.geothings.net/",
-						"http://warper.geothings.net/maps/wms/__s__?request=GetMap&version=1.1.1"
-						+ "&styles=&format=image/png&srs=epsg:4326&exceptions=application/vnd.ogc.se_inimage&",
-						// This matches more than the "classic" WMS link, so users can pretty much
-						// copy any link as long as it includes the ID
-						"(?:mapwarper\\.net|warper\\.geothings\\.net)/(?:.*?)/([0-9]+)(?:\\?|/|\\.|$)",
-				"^[0-9]+$")
-		);
-
-		// This service serves the purpose of "just this once" without forcing the user
-		// to commit the link to the preferences
-
-		// Clipboard content gets trimmed, so matching whitespace only ensures that this
-		// service will never be selected automatically.
-		services.add(new RectifierService(tr("Custom WMS Link"), "", "", "^\\s+$", ""));
-	}
-
-	public void actionPerformed(ActionEvent e) {
-		JPanel panel = new JPanel(new GridBagLayout());
-		panel.add(new JLabel(tr("Supported Rectifier Services:")), GBC.eol());
-
-		JTextField tfWmsUrl = new JTextField(30);
-
-		String clip = getClipboardContents();
-		ButtonGroup group = new ButtonGroup();
-
-		JRadioButton firstBtn = null;
-		for(RectifierService s : services) {
-			JRadioButton serviceBtn = new JRadioButton(s.name);
-			if(firstBtn == null)
-				firstBtn = serviceBtn;
-			// Checks clipboard contents against current service if no match has been found yet.
-			// If the contents match, they will be inserted into the text field and the corresponding
-			// service will be pre-selected.
-			if(!clip.equals("") && tfWmsUrl.getText().equals("")
-					&& (s.urlRegEx.matcher(clip).find() || s.idValidator.matcher(clip).matches())) {
-				serviceBtn.setSelected(true);
-				tfWmsUrl.setText(clip);
-			}
-			s.btn = serviceBtn;
-			group.add(serviceBtn);
-			if(!s.url.equals("")) {
-				panel.add(serviceBtn, GBC.std());
-				panel.add(new UrlLabel(s.url, tr("Visit Homepage")), GBC.eol().anchor(GridBagConstraints.EAST));
-			} else
-				panel.add(serviceBtn, GBC.eol().anchor(GridBagConstraints.WEST));
-		}
-
-		// Fallback in case no match was found
-		if(tfWmsUrl.getText().equals("") && firstBtn != null)
-			firstBtn.setSelected(true);
-
-		panel.add(new JLabel(tr("WMS URL or Image ID:")), GBC.eol());
-		panel.add(tfWmsUrl, GBC.eol().fill(GridBagConstraints.HORIZONTAL));
-
-		ExtendedDialog diag = new ExtendedDialog(Main.parent,
-				tr("Add Rectified Image"),
-
-				new String[] {tr("Add Rectified Image"), tr("Cancel")});
-		diag.setContent(panel);
-		diag.setButtonIcons(new String[] {"OLmarker.png", "cancel.png"});
-
-		// This repeatedly shows the dialog in case there has been an error.
-		// The loop is break;-ed if the users cancels
-		outer: while(true) {
-			diag.showDialog();
-			int answer = diag.getValue();
-			// Break loop when the user cancels
-			if(answer != 1)
-				break;
-
-			String text = tfWmsUrl.getText().trim();
-			// Loop all services until we find the selected one
-			for(RectifierService s : services) {
-				if(!s.isSelected())
-					continue;
-
-				// We've reached the custom WMS URL service
-				// Just set the URL and hope everything works out
-				if(s.wmsUrl.equals("")) {
-					addWMSLayer(s.name + " (" + text + ")", text);
-					break outer;
-				}
-
-				// First try to match if the entered string as an URL
-				Matcher m = s.urlRegEx.matcher(text);
-				if(m.find()) {
-					String id = m.group(1);
-					String newURL = s.wmsUrl.replaceAll("__s__", id);
-					String title = s.name + " (" + id + ")";
-					addWMSLayer(title, newURL);
-					break outer;
-				}
-				// If not, look if it's a valid ID for the selected service
-				if(s.idValidator.matcher(text).matches()) {
-					String newURL = s.wmsUrl.replaceAll("__s__", text);
-					String title = s.name + " (" + text + ")";
-					addWMSLayer(title, newURL);
-					break outer;
-				}
-
-				// We've found the selected service, but the entered string isn't suitable for
-				// it. So quit checking the other radio buttons
-				break;
-			}
-
-			// and display an error message. The while(true) ensures that the dialog pops up again
-			JOptionPane.showMessageDialog(Main.parent,
-					tr("Couldn't match the entered link or id to the selected service. Please try again."),
-					tr("No valid WMS URL or id"),
-					JOptionPane.ERROR_MESSAGE);
-			diag.setVisible(true);
-		}
-	}
-
-	/**
-	 * Adds a WMS Layer with given title and URL
-	 * @param title: Name of the layer as it will shop up in the layer manager
-	 * @param url: URL to the WMS server
-	 * @param cookies: Cookies to send with each image request (Format: josm=is; very=cool)
-	 */
-	private void addWMSLayer(String title, String url, String cookies) {
-		WMSLayer wmsLayer = new WMSLayer(title, url, cookies);
-		Main.main.addLayer(wmsLayer);
-	}
-
-	/**
-	 * Adds a WMS Layer with given title and URL
-	 * @param title: Name of the layer as it will shop up in the layer manager
-	 * @param url: URL to the WMS server
-	 */
-	private void addWMSLayer(String title, String url) {
-		addWMSLayer(title, url, "");
-	}
-
-	/**
-	 * Helper function that extracts a String from the Clipboard if available.
-	 * Returns an empty String otherwise
-	 * @return String Clipboard contents if available
-	 */
-	private String getClipboardContents() {
-		String result = "";
-		Transferable contents = Toolkit.getDefaultToolkit().getSystemClipboard().getContents(null);
-
-		if(contents == null || !contents.isDataFlavorSupported(DataFlavor.stringFlavor))
-			return "";
-
-		try {
-			result = (String)contents.getTransferData(DataFlavor.stringFlavor);
-		} catch(Exception ex) {
-			return "";
-		}
-		return result.trim();
-	}
+    /**
+     * Class that bundles all required information of a rectifier service
+     */
+    public static class RectifierService {
+        private final String name;
+        private final String url;
+        private final String wmsUrl;
+        private final Pattern urlRegEx;
+        private final Pattern idValidator;
+        public JRadioButton btn;
+        /**
+         * @param name: Name of the rectifing service
+         * @param url: URL to the service where users can register, upload, etc.
+         * @param wmsUrl: URL to the WMS server where JOSM will grab the images. Insert __s__ where the ID should be placed
+         * @param urlRegEx: a regular expression that determines if a given URL is one of the service and returns the WMS id if so
+         * @param idValidator: regular expression that checks if a given ID is syntactically valid
+         */
+        public RectifierService(String name, String url, String wmsUrl, String urlRegEx, String idValidator) {
+            this.name = name;
+            this.url = url;
+            this.wmsUrl = wmsUrl;
+            this.urlRegEx = Pattern.compile(urlRegEx);
+            this.idValidator = Pattern.compile(idValidator);
+        }
+
+        public boolean isSelected() {
+            return btn.isSelected();
+        }
+    }
+
+    /**
+     * List of available rectifier services. May be extended from the outside
+     */
+    public ArrayList<RectifierService> services = new ArrayList<RectifierService>();
+
+    public Map_Rectifier_WMSmenuAction() {
+        super(tr("Rectified Image..."),
+                "OLmarker",
+                tr("Download Rectified Images From Various Services"),
+                Shortcut.registerShortcut("wms:rectimg",
+                        tr("WMS: {0}", tr("Rectified Image...")),
+                        KeyEvent.VK_R,
+                        Shortcut.GROUP_NONE),
+                        true
+        );
+
+        // Add default services
+        services.add(
+                new RectifierService("Metacarta Map Rectifier",
+                        "http://labs.metacarta.com/rectifier/",
+                        "http://labs.metacarta.com/rectifier/wms.cgi?id=__s__&srs=EPSG:4326"
+                        + "&Service=WMS&Version=1.1.0&Request=GetMap&format=image/png&",
+                        // This matches more than the "classic" WMS link, so users can pretty much
+                        // copy any link as long as it includes the ID
+                        "labs\\.metacarta\\.com/(?:.*?)(?:/|=)([0-9]+)(?:\\?|/|\\.|$)",
+                "^[0-9]+$")
+        );
+        services.add(
+                // TODO: Change all links to mapwarper.net once the project has moved.
+                // The RegEx already matches the new URL and old URLs will be forwarded
+                // to make the transition as smooth as possible for the users
+                new RectifierService("Geothings Map Warper",
+                        "http://warper.geothings.net/",
+                        "http://warper.geothings.net/maps/wms/__s__?request=GetMap&version=1.1.1"
+                        + "&styles=&format=image/png&srs=epsg:4326&exceptions=application/vnd.ogc.se_inimage&",
+                        // This matches more than the "classic" WMS link, so users can pretty much
+                        // copy any link as long as it includes the ID
+                        "(?:mapwarper\\.net|warper\\.geothings\\.net)/(?:.*?)/([0-9]+)(?:\\?|/|\\.|$)",
+                "^[0-9]+$")
+        );
+
+        // This service serves the purpose of "just this once" without forcing the user
+        // to commit the link to the preferences
+
+        // Clipboard content gets trimmed, so matching whitespace only ensures that this
+        // service will never be selected automatically.
+        services.add(new RectifierService(tr("Custom WMS Link"), "", "", "^\\s+$", ""));
+    }
+
+    public void actionPerformed(ActionEvent e) {
+        JPanel panel = new JPanel(new GridBagLayout());
+        panel.add(new JLabel(tr("Supported Rectifier Services:")), GBC.eol());
+
+        JTextField tfWmsUrl = new JTextField(30);
+
+        String clip = getClipboardContents();
+        ButtonGroup group = new ButtonGroup();
+
+        JRadioButton firstBtn = null;
+        for(RectifierService s : services) {
+            JRadioButton serviceBtn = new JRadioButton(s.name);
+            if(firstBtn == null)
+                firstBtn = serviceBtn;
+            // Checks clipboard contents against current service if no match has been found yet.
+            // If the contents match, they will be inserted into the text field and the corresponding
+            // service will be pre-selected.
+            if(!clip.equals("") && tfWmsUrl.getText().equals("")
+                    && (s.urlRegEx.matcher(clip).find() || s.idValidator.matcher(clip).matches())) {
+                serviceBtn.setSelected(true);
+                tfWmsUrl.setText(clip);
+            }
+            s.btn = serviceBtn;
+            group.add(serviceBtn);
+            if(!s.url.equals("")) {
+                panel.add(serviceBtn, GBC.std());
+                panel.add(new UrlLabel(s.url, tr("Visit Homepage")), GBC.eol().anchor(GridBagConstraints.EAST));
+            } else
+                panel.add(serviceBtn, GBC.eol().anchor(GridBagConstraints.WEST));
+        }
+
+        // Fallback in case no match was found
+        if(tfWmsUrl.getText().equals("") && firstBtn != null)
+            firstBtn.setSelected(true);
+
+        panel.add(new JLabel(tr("WMS URL or Image ID:")), GBC.eol());
+        panel.add(tfWmsUrl, GBC.eol().fill(GridBagConstraints.HORIZONTAL));
+
+        ExtendedDialog diag = new ExtendedDialog(Main.parent,
+                tr("Add Rectified Image"),
+
+                new String[] {tr("Add Rectified Image"), tr("Cancel")});
+        diag.setContent(panel);
+        diag.setButtonIcons(new String[] {"OLmarker.png", "cancel.png"});
+
+        // This repeatedly shows the dialog in case there has been an error.
+        // The loop is break;-ed if the users cancels
+        outer: while(true) {
+            diag.showDialog();
+            int answer = diag.getValue();
+            // Break loop when the user cancels
+            if(answer != 1)
+                break;
+
+            String text = tfWmsUrl.getText().trim();
+            // Loop all services until we find the selected one
+            for(RectifierService s : services) {
+                if(!s.isSelected())
+                    continue;
+
+                // We've reached the custom WMS URL service
+                // Just set the URL and hope everything works out
+                if(s.wmsUrl.equals("")) {
+                    addWMSLayer(s.name + " (" + text + ")", text);
+                    break outer;
+                }
+
+                // First try to match if the entered string as an URL
+                Matcher m = s.urlRegEx.matcher(text);
+                if(m.find()) {
+                    String id = m.group(1);
+                    String newURL = s.wmsUrl.replaceAll("__s__", id);
+                    String title = s.name + " (" + id + ")";
+                    addWMSLayer(title, newURL);
+                    break outer;
+                }
+                // If not, look if it's a valid ID for the selected service
+                if(s.idValidator.matcher(text).matches()) {
+                    String newURL = s.wmsUrl.replaceAll("__s__", text);
+                    String title = s.name + " (" + text + ")";
+                    addWMSLayer(title, newURL);
+                    break outer;
+                }
+
+                // We've found the selected service, but the entered string isn't suitable for
+                // it. So quit checking the other radio buttons
+                break;
+            }
+
+            // and display an error message. The while(true) ensures that the dialog pops up again
+            JOptionPane.showMessageDialog(Main.parent,
+                    tr("Couldn't match the entered link or id to the selected service. Please try again."),
+                    tr("No valid WMS URL or id"),
+                    JOptionPane.ERROR_MESSAGE);
+            diag.setVisible(true);
+        }
+    }
+
+    /**
+     * Adds a WMS Layer with given title and URL
+     * @param title: Name of the layer as it will shop up in the layer manager
+     * @param url: URL to the WMS server
+     */
+    private void addWMSLayer(String title, String url) {
+        Main.main.addLayer(new WMSLayer(new WMSInfo(title, url)));
+    }
+
+    /**
+     * Helper function that extracts a String from the Clipboard if available.
+     * Returns an empty String otherwise
+     * @return String Clipboard contents if available
+     */
+    private String getClipboardContents() {
+        String result = "";
+        Transferable contents = Toolkit.getDefaultToolkit().getSystemClipboard().getContents(null);
+
+        if(contents == null || !contents.isDataFlavorSupported(DataFlavor.stringFlavor))
+            return "";
+
+        try {
+            result = (String)contents.getTransferData(DataFlavor.stringFlavor);
+        } catch(Exception ex) {
+            return "";
+        }
+        return result.trim();
+    }
 }
diff --git a/wmsplugin/src/wmsplugin/WMSAdjustAction.java b/wmsplugin/src/wmsplugin/WMSAdjustAction.java
index 4ed12d9..4641cda 100644
--- a/wmsplugin/src/wmsplugin/WMSAdjustAction.java
+++ b/wmsplugin/src/wmsplugin/WMSAdjustAction.java
@@ -30,187 +30,187 @@ import org.openstreetmap.josm.tools.ImageProvider;
 
 
 public class WMSAdjustAction extends MapMode implements MouseListener, MouseMotionListener{
-	//static private final Logger logger = Logger.getLogger(WMSAdjustAction.class.getName());
-
-	GeorefImage selectedImage;
-	boolean mouseDown;
-	EastNorth prevEastNorth;
-	private WMSLayer adjustingLayer;
-
-	public WMSAdjustAction(MapFrame mapFrame) {
-		super(tr("Adjust WMS"), "adjustwms",
-				tr("Adjust the position of the selected WMS layer"), mapFrame,
-				ImageProvider.getCursor("normal", "move"));
-	}
-
-
-
-	@Override public void enterMode() {
-		super.enterMode();
-		if (!hasWMSLayersToAdjust()) {
-			warnNoWMSLayers();
-			return;
-		}
-		List<WMSLayer> wmsLayers = Main.map.mapView.getLayersOfType(WMSLayer.class);
-		if (wmsLayers.size() == 1) {
-			adjustingLayer = wmsLayers.get(0);
-		} else {
-			adjustingLayer = (WMSLayer)askAdjustLayer(Main.map.mapView.getLayersOfType(WMSLayer.class));
-		}
-		if (adjustingLayer == null)
-			return;
-		if (!adjustingLayer.isVisible()) {
-			adjustingLayer.setVisible(true);
-		}
-		Main.map.mapView.addMouseListener(this);
-		Main.map.mapView.addMouseMotionListener(this);
-	}
-
-	@Override public void exitMode() {
-		super.exitMode();
-		Main.map.mapView.removeMouseListener(this);
-		Main.map.mapView.removeMouseMotionListener(this);
-		adjustingLayer = null;
-	}
-
-	@Override public void mousePressed(MouseEvent e) {
-		if (e.getButton() != MouseEvent.BUTTON1)
-			return;
-
-		if (adjustingLayer.isVisible()) {
-			prevEastNorth=Main.map.mapView.getEastNorth(e.getX(),e.getY());
-			selectedImage = adjustingLayer.findImage(prevEastNorth);
-			if(selectedImage!=null) {
-				Main.map.mapView.setCursor
-				(Cursor.getPredefinedCursor(Cursor.MOVE_CURSOR));
-			}
-		}
-	}
-
-	@Override public void mouseDragged(MouseEvent e) {
-		if(selectedImage!=null) {
-			EastNorth eastNorth=
-				Main.map.mapView.getEastNorth(e.getX(),e.getY());
-			adjustingLayer.displace(
-					eastNorth.east()-prevEastNorth.east(),
-					eastNorth.north()-prevEastNorth.north()
-			);
-			prevEastNorth = eastNorth;
-			Main.map.mapView.repaint();
-		}
-	}
-
-	@Override public void mouseReleased(MouseEvent e) {
-		Main.map.mapView.repaint();
-		Main.map.mapView.setCursor(Cursor.getDefaultCursor());
-		selectedImage = null;
-		prevEastNorth = null;
-	}
-
-	@Override
-	public void mouseEntered(MouseEvent e) {
-	}
-
-	@Override
-	public void mouseExited(MouseEvent e) {
-	}
-
-	@Override
-	public void mouseMoved(MouseEvent e) {
-	}
-
-	@Override public void mouseClicked(MouseEvent e) {
-	}
-
-	@Override public boolean layerIsSupported(Layer l) {
-		return hasWMSLayersToAdjust();
-	}
-
-	/**
-	 * the list cell renderer used to render layer list entries
-	 *
-	 */
-	static public class LayerListCellRenderer extends DefaultListCellRenderer {
-
-		protected boolean isActiveLayer(Layer layer) {
-			if (Main.map == null)
-				return false;
-			if (Main.map.mapView == null)
-				return false;
-			return Main.map.mapView.getActiveLayer() == layer;
-		}
-
-		@Override
-		public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected,
-				boolean cellHasFocus) {
-			Layer layer = (Layer) value;
-			JLabel label = (JLabel) super.getListCellRendererComponent(list, layer.getName(), index, isSelected,
-					cellHasFocus);
-			Icon icon = layer.getIcon();
-			label.setIcon(icon);
-			label.setToolTipText(layer.getToolTipText());
-			return label;
-		}
-	}
-
-	/**
-	 * Prompts the user with a list of WMS layers which can be adjusted
-	 *
-	 * @param adjustableLayers the list of adjustable layers
-	 * @return  the selected layer; null, if no layer was selected
-	 */
-	protected Layer askAdjustLayer(List<? extends Layer> adjustableLayers) {
-		JComboBox layerList = new JComboBox();
-		layerList.setRenderer(new LayerListCellRenderer());
-		layerList.setModel(new DefaultComboBoxModel(adjustableLayers.toArray()));
-		layerList.setSelectedIndex(0);
-
-		JPanel pnl = new JPanel();
-		pnl.setLayout(new GridBagLayout());
-		pnl.add(new JLabel(tr("Please select the WMS layer to adjust.")), GBC.eol());
-		pnl.add(layerList, GBC.eol());
-
-		ExtendedDialog diag = new ExtendedDialog(
-				Main.parent,
-				tr("Select WMS layer"),
-				new String[] { tr("Start adjusting"),tr("Cancel") }
-		);
-		diag.setContent(pnl);
-		diag.setButtonIcons(new String[] { "mapmode/adjustwms", "cancel" });
-		diag.showDialog();
-		int decision = diag.getValue();
-		if (decision != 1)
-			return null;
-		Layer adjustLayer = (Layer) layerList.getSelectedItem();
-		return adjustLayer;
-	}
-
-	/**
-	 * Displays a warning message if there are no WMS layers to adjust
-	 *
-	 */
-	protected void warnNoWMSLayers() {
-		JOptionPane.showMessageDialog(
-				Main.parent,
-				tr("There are currently no WMS layer to adjust."),
-				tr("No layers to adjust"),
-				JOptionPane.WARNING_MESSAGE
-		);
-	}
-
-	/**
-	 * Replies true if there is at least one WMS layer
-	 *
-	 * @return true if there is at least one WMS layer
-	 */
-	protected boolean hasWMSLayersToAdjust() {
-		if (Main.map == null) return false;
-		if (Main.map.mapView == null) return false;
-		return ! Main.map.mapView.getLayersOfType(WMSLayer.class).isEmpty();
-	}
-
-	@Override
-	protected void updateEnabledState() {
-		setEnabled(hasWMSLayersToAdjust());
-	}
+    //static private final Logger logger = Logger.getLogger(WMSAdjustAction.class.getName());
+
+    GeorefImage selectedImage;
+    boolean mouseDown;
+    EastNorth prevEastNorth;
+    private WMSLayer adjustingLayer;
+
+    public WMSAdjustAction(MapFrame mapFrame) {
+        super(tr("Adjust WMS"), "adjustwms",
+                tr("Adjust the position of the selected WMS layer"), mapFrame,
+                ImageProvider.getCursor("normal", "move"));
+    }
+
+
+
+    @Override public void enterMode() {
+        super.enterMode();
+        if (!hasWMSLayersToAdjust()) {
+            warnNoWMSLayers();
+            return;
+        }
+        List<WMSLayer> wmsLayers = Main.map.mapView.getLayersOfType(WMSLayer.class);
+        if (wmsLayers.size() == 1) {
+            adjustingLayer = wmsLayers.get(0);
+        } else {
+            adjustingLayer = (WMSLayer)askAdjustLayer(Main.map.mapView.getLayersOfType(WMSLayer.class));
+        }
+        if (adjustingLayer == null)
+            return;
+        if (!adjustingLayer.isVisible()) {
+            adjustingLayer.setVisible(true);
+        }
+        Main.map.mapView.addMouseListener(this);
+        Main.map.mapView.addMouseMotionListener(this);
+    }
+
+    @Override public void exitMode() {
+        super.exitMode();
+        Main.map.mapView.removeMouseListener(this);
+        Main.map.mapView.removeMouseMotionListener(this);
+        adjustingLayer = null;
+    }
+
+    @Override public void mousePressed(MouseEvent e) {
+        if (e.getButton() != MouseEvent.BUTTON1)
+            return;
+
+        if (adjustingLayer.isVisible()) {
+            prevEastNorth=Main.map.mapView.getEastNorth(e.getX(),e.getY());
+            selectedImage = adjustingLayer.findImage(prevEastNorth);
+            if(selectedImage!=null) {
+                Main.map.mapView.setCursor
+                (Cursor.getPredefinedCursor(Cursor.MOVE_CURSOR));
+            }
+        }
+    }
+
+    @Override public void mouseDragged(MouseEvent e) {
+        if(selectedImage!=null) {
+            EastNorth eastNorth=
+                Main.map.mapView.getEastNorth(e.getX(),e.getY());
+            adjustingLayer.displace(
+                    eastNorth.east()-prevEastNorth.east(),
+                    eastNorth.north()-prevEastNorth.north()
+            );
+            prevEastNorth = eastNorth;
+            Main.map.mapView.repaint();
+        }
+    }
+
+    @Override public void mouseReleased(MouseEvent e) {
+        Main.map.mapView.repaint();
+        Main.map.mapView.setCursor(Cursor.getDefaultCursor());
+        selectedImage = null;
+        prevEastNorth = null;
+    }
+
+    @Override
+    public void mouseEntered(MouseEvent e) {
+    }
+
+    @Override
+    public void mouseExited(MouseEvent e) {
+    }
+
+    @Override
+    public void mouseMoved(MouseEvent e) {
+    }
+
+    @Override public void mouseClicked(MouseEvent e) {
+    }
+
+    @Override public boolean layerIsSupported(Layer l) {
+        return hasWMSLayersToAdjust();
+    }
+
+    /**
+     * the list cell renderer used to render layer list entries
+     *
+     */
+    static public class LayerListCellRenderer extends DefaultListCellRenderer {
+
+        protected boolean isActiveLayer(Layer layer) {
+            if (Main.map == null)
+                return false;
+            if (Main.map.mapView == null)
+                return false;
+            return Main.map.mapView.getActiveLayer() == layer;
+        }
+
+        @Override
+        public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected,
+                boolean cellHasFocus) {
+            Layer layer = (Layer) value;
+            JLabel label = (JLabel) super.getListCellRendererComponent(list, layer.getName(), index, isSelected,
+                    cellHasFocus);
+            Icon icon = layer.getIcon();
+            label.setIcon(icon);
+            label.setToolTipText(layer.getToolTipText());
+            return label;
+        }
+    }
+
+    /**
+     * Prompts the user with a list of WMS layers which can be adjusted
+     *
+     * @param adjustableLayers the list of adjustable layers
+     * @return  the selected layer; null, if no layer was selected
+     */
+    protected Layer askAdjustLayer(List<? extends Layer> adjustableLayers) {
+        JComboBox layerList = new JComboBox();
+        layerList.setRenderer(new LayerListCellRenderer());
+        layerList.setModel(new DefaultComboBoxModel(adjustableLayers.toArray()));
+        layerList.setSelectedIndex(0);
+
+        JPanel pnl = new JPanel();
+        pnl.setLayout(new GridBagLayout());
+        pnl.add(new JLabel(tr("Please select the WMS layer to adjust.")), GBC.eol());
+        pnl.add(layerList, GBC.eol());
+
+        ExtendedDialog diag = new ExtendedDialog(
+                Main.parent,
+                tr("Select WMS layer"),
+                new String[] { tr("Start adjusting"),tr("Cancel") }
+        );
+        diag.setContent(pnl);
+        diag.setButtonIcons(new String[] { "mapmode/adjustwms", "cancel" });
+        diag.showDialog();
+        int decision = diag.getValue();
+        if (decision != 1)
+            return null;
+        Layer adjustLayer = (Layer) layerList.getSelectedItem();
+        return adjustLayer;
+    }
+
+    /**
+     * Displays a warning message if there are no WMS layers to adjust
+     *
+     */
+    protected void warnNoWMSLayers() {
+        JOptionPane.showMessageDialog(
+                Main.parent,
+                tr("There are currently no WMS layer to adjust."),
+                tr("No layers to adjust"),
+                JOptionPane.WARNING_MESSAGE
+        );
+    }
+
+    /**
+     * Replies true if there is at least one WMS layer
+     *
+     * @return true if there is at least one WMS layer
+     */
+    protected boolean hasWMSLayersToAdjust() {
+        if (Main.map == null) return false;
+        if (Main.map.mapView == null) return false;
+        return ! Main.map.mapView.getLayersOfType(WMSLayer.class).isEmpty();
+    }
+
+    @Override
+    protected void updateEnabledState() {
+        setEnabled(hasWMSLayersToAdjust());
+    }
 }
diff --git a/wmsplugin/src/wmsplugin/WMSDownloadAction.java b/wmsplugin/src/wmsplugin/WMSDownloadAction.java
index e1f807d..d77e796 100644
--- a/wmsplugin/src/wmsplugin/WMSDownloadAction.java
+++ b/wmsplugin/src/wmsplugin/WMSDownloadAction.java
@@ -9,25 +9,16 @@ import org.openstreetmap.josm.actions.JosmAction;
 
 public class WMSDownloadAction extends JosmAction {
 
-	private final WMSInfo info;
-
-	public WMSDownloadAction(WMSInfo info) {
-		super(info.name, "wmsmenu", tr("Download WMS tile from {0}",info.name), null, false);
-		putValue("toolbar", "wms_" + info.name);
-		this.info = info;
-	}
-
-	public void actionPerformed(ActionEvent e) {
-		//System.out.println(info.url);
-
-		WMSLayer wmsLayer = new WMSLayer(info.name, info.url, info.cookies);
-		Main.main.addLayer(wmsLayer);
-	}
-
-	public static WMSLayer getLayer(WMSInfo info) {
-		// FIXME: move this to WMSPlugin/WMSInfo/preferences.
-		WMSLayer wmsLayer = new WMSLayer(info.name, info.url, info.cookies);
-		Main.main.addLayer(wmsLayer);
-		return wmsLayer;
-	}
+    private final WMSInfo info;
+
+    public WMSDownloadAction(WMSInfo info) {
+        super(info.getMenuName(), "wmsmenu", tr("Download WMS tile from {0}",info.name), null, false);
+        putValue("toolbar", "wms_" + info.getToolbarName());
+        this.info = info;
+    }
+
+    public void actionPerformed(ActionEvent e) {
+        WMSLayer wmsLayer = new WMSLayer(info);
+        Main.main.addLayer(wmsLayer);
+    }
 };
diff --git a/wmsplugin/src/wmsplugin/WMSGrabber.java b/wmsplugin/src/wmsplugin/WMSGrabber.java
index 4ef6f40..0f4590c 100644
--- a/wmsplugin/src/wmsplugin/WMSGrabber.java
+++ b/wmsplugin/src/wmsplugin/WMSGrabber.java
@@ -35,170 +35,170 @@ import wmsplugin.GeorefImage.State;
 
 
 public class WMSGrabber extends Grabber {
-	public static boolean isUrlWithPatterns(String url) {
-		return url != null && url.contains("{") && url.contains("}");
-	}
-
-	protected String baseURL;
-	private final boolean urlWithPatterns;
-
-	WMSGrabber(MapView mv, WMSLayer layer, CacheFiles cache) {
-		super(mv, layer, cache);
-		this.baseURL = layer.baseURL;
-		/* URL containing placeholders? */
-		urlWithPatterns = isUrlWithPatterns(baseURL);
-	}
-
-	@Override
-	void fetch(WMSRequest request) throws Exception{
-		URL url = null;
-		try {
-			url = getURL(
-					b.min.east(), b.min.north(),
-					b.max.east(), b.max.north(),
-					width(), height());
-			request.finish(State.IMAGE, grab(url));
-
-		} catch(Exception e) {
-			e.printStackTrace();
-			throw new Exception(e.getMessage() + "\nImage couldn't be fetched: " + (url != null ? url.toString() : ""));
-		}
-	}
-
-	public static final NumberFormat latLonFormat = new DecimalFormat("###0.0000000",
-			new DecimalFormatSymbols(Locale.US));
-
-	protected URL getURL(double w, double s,double e,double n,
-			int wi, int ht) throws MalformedURLException {
-		String myProj = Main.proj.toCode();
-		if(Main.proj instanceof Mercator) // don't use mercator code directly
-		{
-			LatLon sw = Main.proj.eastNorth2latlon(new EastNorth(w, s));
-			LatLon ne = Main.proj.eastNorth2latlon(new EastNorth(e, n));
-			myProj = "EPSG:4326";
-			s = sw.lat();
-			w = sw.lon();
-			n = ne.lat();
-			e = ne.lon();
-		}
-
-		String str = baseURL;
-		String bbox = latLonFormat.format(w) + ","
-		+ latLonFormat.format(s) + ","
-		+ latLonFormat.format(e) + ","
-		+ latLonFormat.format(n);
-
-		if (urlWithPatterns) {
-			str = str.replaceAll("\\{proj\\}", myProj)
-			.replaceAll("\\{bbox\\}", bbox)
-			.replaceAll("\\{w\\}", latLonFormat.format(w))
-			.replaceAll("\\{s\\}", latLonFormat.format(s))
-			.replaceAll("\\{e\\}", latLonFormat.format(e))
-			.replaceAll("\\{n\\}", latLonFormat.format(n))
-			.replaceAll("\\{width\\}", String.valueOf(wi))
-			.replaceAll("\\{height\\}", String.valueOf(ht));
-		} else {
-			str += "bbox=" + bbox
-			+ getProjection(baseURL, false)
-			+ "&width=" + wi + "&height=" + ht;
-			if (!(baseURL.endsWith("&") || baseURL.endsWith("?"))) {
-				System.out.println(tr("Warning: The base URL ''{0}'' for a WMS service doesn't have a trailing '&' or a trailing '?'.", baseURL));
-				System.out.println(tr("Warning: Fetching WMS tiles is likely to fail. Please check you preference settings."));
-				System.out.println(tr("Warning: The complete URL is ''{0}''.", str));
-			}
-		}
-		return new URL(str.replace(" ", "%20"));
-	}
-
-	static public String getProjection(String baseURL, Boolean warn)
-	{
-		String projname = Main.proj.toCode();
-		if(Main.proj instanceof Mercator) // don't use mercator code
-			projname = "EPSG:4326";
-		String res = "";
-		try
-		{
-			Matcher m = Pattern.compile(".*srs=([a-z0-9:]+).*").matcher(baseURL.toLowerCase());
-			if(m.matches())
-			{
-				projname = projname.toLowerCase();
-				if(!projname.equals(m.group(1)) && warn)
-				{
-					JOptionPane.showMessageDialog(Main.parent,
-							tr("The projection ''{0}'' in URL and current projection ''{1}'' mismatch.\n"
-									+ "This may lead to wrong coordinates.",
-									m.group(1), projname),
-									tr("Warning"),
-									JOptionPane.WARNING_MESSAGE);
-				}
-			}
-			else
-				res ="&srs="+projname;
-		}
-		catch(Exception e)
-		{
-		}
-		return res;
-	}
-
-	@Override
-	public boolean loadFromCache(WMSRequest request) {
-		URL url = null;
-		try{
-			url = getURL(
-					b.min.east(), b.min.north(),
-					b.max.east(), b.max.north(),
-					width(), height());
-		} catch(Exception e) {
-			return false;
-		}
-		BufferedImage cached = cache.getImg(url.toString());
-		if((!request.isReal() && !layer.hasAutoDownload()) || cached != null){
-			if(cached == null){
-				request.finish(State.NOT_IN_CACHE, null);
-				return true;
-			}
-			request.finish(State.IMAGE, cached);
-			return true;
-		}
-		return false;
-	}
-
-	protected BufferedImage grab(URL url) throws IOException, OsmTransferException {
-		System.out.println("Grabbing WMS " + url);
-
-		HttpURLConnection conn = (HttpURLConnection) url.openConnection();
-		if(layer.cookies != null && !layer.cookies.equals(""))
-			conn.setRequestProperty("Cookie", layer.cookies);
-		conn.setRequestProperty("User-Agent", Main.pref.get("wmsplugin.user_agent", Version.getInstance().getAgentString()));
-		conn.setConnectTimeout(Main.pref.getInteger("wmsplugin.timeout.connect", 30) * 1000);
-		conn.setReadTimeout(Main.pref.getInteger("wmsplugin.timeout.read", 30) * 1000);
-
-		String contentType = conn.getHeaderField("Content-Type");
-		if( conn.getResponseCode() != 200
-				|| contentType != null && !contentType.startsWith("image") ) {
-			throw new IOException(readException(conn));
-		}
-
-		InputStream is = new ProgressInputStream(conn, null);
-		BufferedImage img = ImageIO.read(is);
-		is.close();
-
-		cache.saveImg(url.toString(), img);
-		return img;
-	}
-
-	protected String readException(URLConnection conn) throws IOException {
-		StringBuilder exception = new StringBuilder();
-		InputStream in = conn.getInputStream();
-		BufferedReader br = new BufferedReader(new InputStreamReader(in));
-
-		String line = null;
-		while( (line = br.readLine()) != null) {
-			// filter non-ASCII characters and control characters
-			exception.append(line.replaceAll("[^\\p{Print}]", ""));
-			exception.append('\n');
-		}
-		return exception.toString();
-	}
+    public static boolean isUrlWithPatterns(String url) {
+        return url != null && url.contains("{") && url.contains("}");
+    }
+
+    protected String baseURL;
+    private final boolean urlWithPatterns;
+
+    WMSGrabber(MapView mv, WMSLayer layer, CacheFiles cache) {
+        super(mv, layer, cache);
+        this.baseURL = layer.info.url;
+        /* URL containing placeholders? */
+        urlWithPatterns = isUrlWithPatterns(baseURL);
+    }
+
+    @Override
+    void fetch(WMSRequest request) throws Exception{
+        URL url = null;
+        try {
+            url = getURL(
+                    b.min.east(), b.min.north(),
+                    b.max.east(), b.max.north(),
+                    width(), height());
+            request.finish(State.IMAGE, grab(url));
+
+        } catch(Exception e) {
+            e.printStackTrace();
+            throw new Exception(e.getMessage() + "\nImage couldn't be fetched: " + (url != null ? url.toString() : ""));
+        }
+    }
+
+    public static final NumberFormat latLonFormat = new DecimalFormat("###0.0000000",
+            new DecimalFormatSymbols(Locale.US));
+
+    protected URL getURL(double w, double s,double e,double n,
+            int wi, int ht) throws MalformedURLException {
+        String myProj = Main.proj.toCode();
+        if(Main.proj instanceof Mercator) // don't use mercator code directly
+        {
+            LatLon sw = Main.proj.eastNorth2latlon(new EastNorth(w, s));
+            LatLon ne = Main.proj.eastNorth2latlon(new EastNorth(e, n));
+            myProj = "EPSG:4326";
+            s = sw.lat();
+            w = sw.lon();
+            n = ne.lat();
+            e = ne.lon();
+        }
+
+        String str = baseURL;
+        String bbox = latLonFormat.format(w) + ","
+        + latLonFormat.format(s) + ","
+        + latLonFormat.format(e) + ","
+        + latLonFormat.format(n);
+
+        if (urlWithPatterns) {
+            str = str.replaceAll("\\{proj\\}", myProj)
+            .replaceAll("\\{bbox\\}", bbox)
+            .replaceAll("\\{w\\}", latLonFormat.format(w))
+            .replaceAll("\\{s\\}", latLonFormat.format(s))
+            .replaceAll("\\{e\\}", latLonFormat.format(e))
+            .replaceAll("\\{n\\}", latLonFormat.format(n))
+            .replaceAll("\\{width\\}", String.valueOf(wi))
+            .replaceAll("\\{height\\}", String.valueOf(ht));
+        } else {
+            str += "bbox=" + bbox
+            + getProjection(baseURL, false)
+            + "&width=" + wi + "&height=" + ht;
+            if (!(baseURL.endsWith("&") || baseURL.endsWith("?"))) {
+                System.out.println(tr("Warning: The base URL ''{0}'' for a WMS service doesn't have a trailing '&' or a trailing '?'.", baseURL));
+                System.out.println(tr("Warning: Fetching WMS tiles is likely to fail. Please check you preference settings."));
+                System.out.println(tr("Warning: The complete URL is ''{0}''.", str));
+            }
+        }
+        return new URL(str.replace(" ", "%20"));
+    }
+
+    static public String getProjection(String baseURL, Boolean warn)
+    {
+        String projname = Main.proj.toCode();
+        if(Main.proj instanceof Mercator) // don't use mercator code
+            projname = "EPSG:4326";
+        String res = "";
+        try
+        {
+            Matcher m = Pattern.compile(".*srs=([a-z0-9:]+).*").matcher(baseURL.toLowerCase());
+            if(m.matches())
+            {
+                projname = projname.toLowerCase();
+                if(!projname.equals(m.group(1)) && warn)
+                {
+                    JOptionPane.showMessageDialog(Main.parent,
+                            tr("The projection ''{0}'' in URL and current projection ''{1}'' mismatch.\n"
+                                    + "This may lead to wrong coordinates.",
+                                    m.group(1), projname),
+                                    tr("Warning"),
+                                    JOptionPane.WARNING_MESSAGE);
+                }
+            }
+            else
+                res ="&srs="+projname;
+        }
+        catch(Exception e)
+        {
+        }
+        return res;
+    }
+
+    @Override
+    public boolean loadFromCache(WMSRequest request) {
+        URL url = null;
+        try{
+            url = getURL(
+                    b.min.east(), b.min.north(),
+                    b.max.east(), b.max.north(),
+                    width(), height());
+        } catch(Exception e) {
+            return false;
+        }
+        BufferedImage cached = cache.getImg(url.toString());
+        if((!request.isReal() && !layer.hasAutoDownload()) || cached != null){
+            if(cached == null){
+                request.finish(State.NOT_IN_CACHE, null);
+                return true;
+            }
+            request.finish(State.IMAGE, cached);
+            return true;
+        }
+        return false;
+    }
+
+    protected BufferedImage grab(URL url) throws IOException, OsmTransferException {
+        System.out.println("Grabbing WMS " + url);
+
+        HttpURLConnection conn = (HttpURLConnection) url.openConnection();
+        if(layer.info.cookies != null && !layer.info.cookies.equals(""))
+            conn.setRequestProperty("Cookie", layer.info.cookies);
+        conn.setRequestProperty("User-Agent", Main.pref.get("wmsplugin.user_agent", Version.getInstance().getAgentString()));
+        conn.setConnectTimeout(Main.pref.getInteger("wmsplugin.timeout.connect", 30) * 1000);
+        conn.setReadTimeout(Main.pref.getInteger("wmsplugin.timeout.read", 30) * 1000);
+
+        String contentType = conn.getHeaderField("Content-Type");
+        if( conn.getResponseCode() != 200
+                || contentType != null && !contentType.startsWith("image") ) {
+            throw new IOException(readException(conn));
+        }
+
+        InputStream is = new ProgressInputStream(conn, null);
+        BufferedImage img = ImageIO.read(is);
+        is.close();
+
+        cache.saveImg(url.toString(), img);
+        return img;
+    }
+
+    protected String readException(URLConnection conn) throws IOException {
+        StringBuilder exception = new StringBuilder();
+        InputStream in = conn.getInputStream();
+        BufferedReader br = new BufferedReader(new InputStreamReader(in));
+
+        String line = null;
+        while( (line = br.readLine()) != null) {
+            // filter non-ASCII characters and control characters
+            exception.append(line.replaceAll("[^\\p{Print}]", ""));
+            exception.append('\n');
+        }
+        return exception.toString();
+    }
 }
diff --git a/wmsplugin/src/wmsplugin/WMSInfo.java b/wmsplugin/src/wmsplugin/WMSInfo.java
index 4d4094f..5adbab1 100644
--- a/wmsplugin/src/wmsplugin/WMSInfo.java
+++ b/wmsplugin/src/wmsplugin/WMSInfo.java
@@ -1,6 +1,7 @@
 package wmsplugin;
 
-import org.openstreetmap.josm.Main;
+import java.util.ArrayList;
+import java.util.Collection;
 
 /**
  * Class that stores info about a WMS server.
@@ -10,24 +11,72 @@ import org.openstreetmap.josm.Main;
 public class WMSInfo implements Comparable<WMSInfo> {
 
     String name;
-    String url;
-    String cookies;
-    int prefid;
+    String url=null;
+    String cookies = null;
+    String eulaAcceptanceRequired = null;
+    boolean html = false;
+    double pixelPerDegree = 0.0;
 
-    public WMSInfo(String name, String url, int prefid) {
-        this(name, url, null, prefid);
+    public WMSInfo(String name) {
+        this.name=name;
+    }
+
+    public WMSInfo(String name, String url) {
+        this.name=name;
+        setURL(url);
+    }
+
+    public WMSInfo(String name, String url, String eulaAcceptanceRequired) {
+        this.name=name;
+        setURL(url);
+        this.eulaAcceptanceRequired = eulaAcceptanceRequired;
+    }
+
+    public WMSInfo(String name, String url, String eulaAcceptanceRequired, String cookies) {
+        this.name=name;
+        setURL(url);
+        this.cookies=cookies;
     }
 
-    public WMSInfo(String name, String url, String cookies, int prefid) {
+    public WMSInfo(String name, String url, String cookies, double pixelPerDegree) {
         this.name=name;
-        this.url=url;
+        setURL(url);
         this.cookies=cookies;
-        this.prefid=prefid;
+        this.pixelPerDegree=pixelPerDegree;
+    }
+
+    public ArrayList<String> getInfoArray() {
+        String e2 = null;
+        String e3 = null;
+        String e4 = null;
+        if(url != null && !url.isEmpty()) e2 = getFullURL();
+        if(cookies != null && !cookies.isEmpty()) e3 = cookies;
+        if(pixelPerDegree != 0.0) e4 = String.valueOf(pixelPerDegree);
+        if(e4 != null && e3 == null) e3 = "";
+        if(e3 != null && e2 == null) e2 = "";
+
+        ArrayList<String> res = new ArrayList<String>();
+        res.add(name);
+        if(e2 != null) res.add(e2);
+        if(e3 != null) res.add(e3);
+        if(e4 != null) res.add(e4);
+        return res;
+    }
+
+    public WMSInfo(Collection<String> list) {
+        ArrayList<String> array = new ArrayList<String>(list);
+        this.name=array.get(0);
+        if(array.size() >= 2) setURL(array.get(1));
+        if(array.size() >= 3) this.cookies=array.get(2);
+        if(array.size() >= 4) this.pixelPerDegree=Double.valueOf(array.get(3));
     }
 
-    public void save() {
-        Main.pref.put("wmsplugin.url." + prefid + ".name", name);
-        Main.pref.put("wmsplugin.url." + prefid + ".url", url);
+    public WMSInfo(WMSInfo i) {
+        this.name=i.name;
+        this.url=i.url;
+        this.cookies=i.cookies;
+        this.html=i.html;
+        this.pixelPerDegree=i.pixelPerDegree;
     }
 
     public int compareTo(WMSInfo in)
@@ -36,7 +85,45 @@ public class WMSInfo implements Comparable<WMSInfo> {
         if(i == 0)
             i = url.compareTo(in.url);
         if(i == 0)
-            i = prefid-in.prefid;
+            i = Double.compare(pixelPerDegree, in.pixelPerDegree);
         return i;
     }
+
+    public boolean equalsBaseValues(WMSInfo in)
+    {
+        return url.equals(in.url);
+    }
+
+    public void setPixelPerDegree(double ppd) {
+        this.pixelPerDegree = ppd;
+    }
+
+    public void setURL(String url) {
+        if(url.startsWith("html:")) {
+            this.url = url.substring(5);
+            html = true;
+        } else {
+            this.url = url;
+        }
+    }
+
+    public String getFullURL() {
+        return html ? "html:" + url : url;
+    }
+
+    public String getToolbarName()
+    {
+        String res = name;
+        if(pixelPerDegree != 0.0)
+            res += "#PPD="+pixelPerDegree;
+        return res;
+    }
+
+    public String getMenuName()
+    {
+        String res = name;
+        if(pixelPerDegree != 0.0)
+            res += " ("+pixelPerDegree+")";
+        return res;
+    }
 }
diff --git a/wmsplugin/src/wmsplugin/WMSLayer.java b/wmsplugin/src/wmsplugin/WMSLayer.java
index 2d1cf9e..716c2f2 100644
--- a/wmsplugin/src/wmsplugin/WMSLayer.java
+++ b/wmsplugin/src/wmsplugin/WMSLayer.java
@@ -53,765 +53,742 @@ import wmsplugin.GeorefImage.State;
  */
 public class WMSLayer extends Layer implements PreferenceChangedListener {
 
-	protected static final Icon icon =
-		new ImageIcon(Toolkit.getDefaultToolkit().createImage(WMSPlugin.class.getResource("/images/wms_small.png")));
-
-	public static final BooleanProperty PROP_ALPHA_CHANNEL = new BooleanProperty("wmsplugin.alpha_channel", true);
-
-	public int messageNum = 5; //limit for messages per layer
-	protected MapView mv;
-	protected String resolution;
-	protected int imageSize = 500;
-	protected int dax = 10;
-	protected int day = 10;
-	protected int daStep = 5;
-	protected int minZoom = 3;
-
-	protected double dx = 0.0;
-	protected double dy = 0.0;
-
-	protected double pixelPerDegree;
-	protected GeorefImage[][] images;
-	protected String baseURL;
-	protected String cookies;
-	protected final int serializeFormatVersion = 5;
-	protected boolean autoDownloadEnabled = true;
-	protected boolean settingsChanged;
-
-	// Image index boundary for current view
-	private volatile int bminx;
-	private volatile int bminy;
-	private volatile int bmaxx;
-	private volatile int bmaxy;
-	private volatile int leftEdge;
-	private volatile int bottomEdge;
-
-	// Request queue
-	private final List<WMSRequest> requestQueue = new ArrayList<WMSRequest>();
-	private final List<WMSRequest> finishedRequests = new ArrayList<WMSRequest>();
-	private final Lock requestQueueLock = new ReentrantLock();
-	private final Condition queueEmpty = requestQueueLock.newCondition();
-	private final List<Grabber> grabbers = new ArrayList<Grabber>();
-	private final List<Thread> grabberThreads = new ArrayList<Thread>();
-	private int threadCount;
-	private int workingThreadCount;
-	private boolean canceled;
-
-
-	/** set to true if this layer uses an invalid base url */
-	private boolean usesInvalidUrl = false;
-	/** set to true if the user confirmed to use an potentially invalid WMS base url */
-	private boolean isInvalidUrlConfirmed = false;
-
-	public WMSLayer() {
-		this(tr("Blank Layer"), null, null);
-		initializeImages();
-		mv = Main.map.mapView;
-	}
-
-	public WMSLayer(String name, String baseURL, String cookies) {
-		super(name);
-		setBackgroundLayer(true); /* set global background variable */
-		initializeImages();
-		this.baseURL = baseURL;
-		this.cookies = cookies;
-		WMSGrabber.getProjection(baseURL, true);
-		mv = Main.map.mapView;
-
-		// quick hack to predefine the PixelDensity to reuse the cache
-		int codeIndex = getName().indexOf("#PPD=");
-		if (codeIndex != -1) {
-			pixelPerDegree = Double.valueOf(getName().substring(codeIndex+5));
-		} else {
-			pixelPerDegree = getPPD();
-		}
-		resolution = mv.getDist100PixelText();
-
-		if(baseURL != null)
-		{
-			startGrabberThreads();
-		}
-		if (baseURL != null && !baseURL.startsWith("html:") && !WMSGrabber.isUrlWithPatterns(baseURL)) {
-			if (!(baseURL.endsWith("&") || baseURL.endsWith("?"))) {
-				if (!confirmMalformedUrl(baseURL)) {
-					System.out.println(tr("Warning: WMS layer deactivated because of malformed base url ''{0}''", baseURL));
-					usesInvalidUrl = true;
-					setName(getName() + tr("(deactivated)"));
-					return;
-				} else {
-					isInvalidUrlConfirmed = true;
-				}
-			}
-		}
-
-		Main.pref.addPreferenceChangeListener(this);
-	}
-
-	public boolean hasAutoDownload(){
-		return autoDownloadEnabled;
-	}
-
-
-	@Override
-	public void destroy() {
-		cancelGrabberThreads(false);
-		Main.pref.removePreferenceChangeListener(this);
-	}
-
-	public void initializeImages() {
-		GeorefImage[][] old = images;
-		images = new GeorefImage[dax][day];
-		if (old != null) {
-			for (int i=0; i<old.length; i++) {
-				for (int k=0; k<old[i].length; k++) {
-					GeorefImage o = old[i][k];
-					images[modulo(o.getXIndex(),dax)][modulo(o.getYIndex(),day)] = old[i][k];
-				}
-			}
-		}
-		for(int x = 0; x<dax; ++x) {
-			for(int y = 0; y<day; ++y) {
-				if (images[x][y] == null) {
-					images[x][y]= new GeorefImage(this);
-				}
-			}
-		}
-	}
-
-	@Override public Icon getIcon() {
-		return icon;
-	}
-
-	@Override public String getToolTipText() {
-		if(autoDownloadEnabled)
-			return tr("WMS layer ({0}), automatically downloading in zoom {1}", getName(), resolution);
-		else
-			return tr("WMS layer ({0}), downloading in zoom {1}", getName(), resolution);
-	}
-
-	@Override public boolean isMergable(Layer other) {
-		return false;
-	}
-
-	@Override public void mergeFrom(Layer from) {
-	}
-
-	private int modulo (int a, int b) {
-		return a % b >= 0 ? a%b : a%b+b;
-	}
-
-	private boolean zoomIsTooBig() {
-		//don't download when it's too outzoomed
-		return pixelPerDegree / getPPD() > minZoom;
-	}
-
-	@Override public void paint(Graphics2D g, final MapView mv, Bounds b) {
-		if(baseURL == null) return;
-		if (usesInvalidUrl && !isInvalidUrlConfirmed) return;
-
-		settingsChanged = false;
-
-		ProjectionBounds bounds = mv.getProjectionBounds();
-		bminx= getImageXIndex(bounds.min.east());
-		bminy= getImageYIndex(bounds.min.north());
-		bmaxx= getImageXIndex(bounds.max.east());
-		bmaxy= getImageYIndex(bounds.max.north());
-
-		leftEdge = (int)(bounds.min.east() * getPPD());
-		bottomEdge = (int)(bounds.min.north() * getPPD());
-
-		if (zoomIsTooBig()) {
-			for(int x = bminx; x<=bmaxx; ++x) {
-				for(int y = bminy; y<=bmaxy; ++y) {
-					images[modulo(x,dax)][modulo(y,day)].paint(g, mv, x, y, leftEdge, bottomEdge);
-				}
-			}
-		} else {
-			downloadAndPaintVisible(g, mv, false);
-		}
-	}
-
-	protected boolean confirmMalformedUrl(String url) {
-		if (isInvalidUrlConfirmed)
-			return true;
-		String msg  = tr("<html>The base URL<br>"
-				+ "''{0}''<br>"
-				+ "for this WMS layer does neither end with a ''&'' nor with a ''?''.<br>"
-				+ "This is likely to lead to invalid WMS request. You should check your<br>"
-				+ "preference settings.<br>"
-				+ "Do you want to fetch WMS tiles anyway?",
-				url);
-		String [] options = new String[] {
-				tr("Yes, fetch images"),
-				tr("No, abort")
-		};
-		int ret = JOptionPane.showOptionDialog(
-				Main.parent,
-				msg,
-				tr("Invalid URL?"),
-				JOptionPane.YES_NO_OPTION,
-				JOptionPane.WARNING_MESSAGE,
-				null,
-				options, options[1]
-		);
-		switch(ret) {
-		case JOptionPane.YES_OPTION: return true;
-		default: return false;
-		}
-	}
-
-	public double getPPD(){
-		ProjectionBounds bounds = mv.getProjectionBounds();
-		return mv.getWidth() / (bounds.max.east() - bounds.min.east());
-	}
-
-	public void displace(double dx, double dy) {
-		settingsChanged = true;
-		this.dx += dx;
-		this.dy += dy;
-	}
-
-	public int getImageXIndex(double coord) {
-		return (int)Math.floor( ((coord - dx) * pixelPerDegree) / imageSize);
-	}
-
-	public int getImageYIndex(double coord) {
-		return (int)Math.floor( ((coord - dy) * pixelPerDegree) / imageSize);
-	}
-
-	public int getImageX(int imageIndex) {
-		return (int)(imageIndex * imageSize * (getPPD() / pixelPerDegree) + dx * getPPD());
-	}
-
-	public int getImageY(int imageIndex) {
-		return (int)(imageIndex * imageSize * (getPPD() / pixelPerDegree) + dy * getPPD());
-	}
-
-	public int getImageWidth(int xIndex) {
-		int overlap = (int)(WMSPlugin.PROP_OVERLAP.get()?WMSPlugin.PROP_OVERLAP_EAST.get() * imageSize * getPPD() / pixelPerDegree / 100:0);
-		return getImageX(xIndex + 1) - getImageX(xIndex) + overlap;
-	}
-
-	public int getImageHeight(int yIndex) {
-		int overlap = (int)(WMSPlugin.PROP_OVERLAP.get()?WMSPlugin.PROP_OVERLAP_NORTH.get() * imageSize * getPPD() / pixelPerDegree / 100:0);
-		return getImageY(yIndex + 1) - getImageY(yIndex) + overlap;
-	}
-
-	/**
-	 *
-	 * @return Size of image in original zoom
-	 */
-	public int getBaseImageWidth() {
-		int overlap = (WMSPlugin.PROP_OVERLAP.get()?WMSPlugin.PROP_OVERLAP_EAST.get() * imageSize / 100:0);
-		return imageSize + overlap;
-	}
-
-	/**
-	 *
-	 * @return Size of image in original zoom
-	 */
-	public int getBaseImageHeight() {
-		int overlap = (WMSPlugin.PROP_OVERLAP.get()?WMSPlugin.PROP_OVERLAP_NORTH.get() * imageSize / 100:0);
-		return imageSize + overlap;
-	}
-
-
-	/**
-	 *
-	 * @param xIndex
-	 * @param yIndex
-	 * @return Real EastNorth of given tile. dx/dy is not counted in
-	 */
-	public EastNorth getEastNorth(int xIndex, int yIndex) {
-		return new EastNorth((xIndex * imageSize) / pixelPerDegree, (yIndex * imageSize) / pixelPerDegree);
-	}
-
-
-	protected void downloadAndPaintVisible(Graphics g, final MapView mv, boolean real){
-
-		int newDax = dax;
-		int newDay = day;
-
-		if (bmaxx - bminx >= dax || bmaxx - bminx < dax - 2 * daStep) {
-			newDax = ((bmaxx - bminx) / daStep + 1) * daStep;
-		}
-
-		if (bmaxy - bminy >= day || bmaxy - bminx < day - 2 * daStep) {
-			newDay = ((bmaxy - bminy) / daStep + 1) * daStep;
-		}
-
-		if (newDax != dax || newDay != day) {
-			dax = newDax;
-			day = newDay;
-			initializeImages();
-		}
-
-		for(int x = bminx; x<=bmaxx; ++x) {
-			for(int y = bminy; y<=bmaxy; ++y){
-				images[modulo(x,dax)][modulo(y,day)].changePosition(x, y);
-			}
-		}
-
-		gatherFinishedRequests();
-
-		for(int x = bminx; x<=bmaxx; ++x) {
-			for(int y = bminy; y<=bmaxy; ++y){
-				GeorefImage img = images[modulo(x,dax)][modulo(y,day)];
-				if (!img.paint(g, mv, x, y, leftEdge, bottomEdge)) {
-					WMSRequest request = new WMSRequest(x, y, pixelPerDegree, real);
-					addRequest(request);
-				}
-			}
-		}
-	}
-
-	@Override public void visitBoundingBox(BoundingXYVisitor v) {
-		for(int x = 0; x<dax; ++x) {
-			for(int y = 0; y<day; ++y)
-				if(images[x][y].getImage() != null){
-					v.visit(images[x][y].getMin());
-					v.visit(images[x][y].getMax());
-				}
-		}
-	}
-
-	@Override public Object getInfoComponent() {
-		return getToolTipText();
-	}
-
-	@Override public Action[] getMenuEntries() {
-		return new Action[]{
-				LayerListDialog.getInstance().createActivateLayerAction(this),
-				LayerListDialog.getInstance().createShowHideLayerAction(),
-				LayerListDialog.getInstance().createDeleteLayerAction(),
-				SeparatorLayerAction.INSTANCE,
-				new LoadWmsAction(),
-				new SaveWmsAction(),
-				new BookmarkWmsAction(),
-				SeparatorLayerAction.INSTANCE,
-				new StartStopAction(),
-				new ToggleAlphaAction(),
-				new ChangeResolutionAction(),
-				new ReloadErrorTilesAction(),
-				new DownloadAction(),
-				SeparatorLayerAction.INSTANCE,
-				new LayerListPopup.InfoAction(this)
-		};
-	}
-
-	public GeorefImage findImage(EastNorth eastNorth) {
-		int xIndex = getImageXIndex(eastNorth.east());
-		int yIndex = getImageYIndex(eastNorth.north());
-		GeorefImage result = images[modulo(xIndex, dax)][modulo(yIndex, day)];
-		if (result.getXIndex() == xIndex && result.getYIndex() == yIndex) {
-			return result;
-		} else {
-			return null;
-		}
-	}
-
-	/**
-	 *
-	 * @param request
-	 * @return -1 if request is no longer needed, otherwise priority of request (lower number <=> more important request)
-	 */
-	private int getRequestPriority(WMSRequest request) {
-		if (request.getPixelPerDegree() != pixelPerDegree) {
-			return -1;
-		}
-		if (bminx > request.getXIndex()
-				|| bmaxx < request.getXIndex()
-				|| bminy > request.getYIndex()
-				|| bmaxy < request.getYIndex()) {
-			return -1;
-		}
-
-		EastNorth cursorEastNorth = mv.getEastNorth(mv.lastMEvent.getX(), mv.lastMEvent.getY());
-		int mouseX = getImageXIndex(cursorEastNorth.east());
-		int mouseY = getImageYIndex(cursorEastNorth.north());
-		int dx = request.getXIndex() - mouseX;
-		int dy = request.getYIndex() - mouseY;
-
-		return dx * dx + dy * dy;
-	}
-
-	public WMSRequest getRequest() {
-		requestQueueLock.lock();
-		try {
-			workingThreadCount--;
-			Iterator<WMSRequest> it = requestQueue.iterator();
-			while (it.hasNext()) {
-				WMSRequest item = it.next();
-				int priority = getRequestPriority(item);
-				if (priority == -1) {
-					it.remove();
-				} else {
-					item.setPriority(priority);
-				}
-			}
-			Collections.sort(requestQueue);
-
-			EastNorth cursorEastNorth = mv.getEastNorth(mv.lastMEvent.getX(), mv.lastMEvent.getY());
-			int mouseX = getImageXIndex(cursorEastNorth.east());
-			int mouseY = getImageYIndex(cursorEastNorth.north());
-			boolean isOnMouse = requestQueue.size() > 0 && requestQueue.get(0).getXIndex() == mouseX && requestQueue.get(0).getYIndex() == mouseY;
-
-			// If there is only one thread left then keep it in case we need to download other tile urgently
-			while (!canceled &&
-					(requestQueue.isEmpty() || (!isOnMouse && threadCount - workingThreadCount == 0 && threadCount > 1))) {
-				try {
-					queueEmpty.await();
-				} catch (InterruptedException e) {
-					// Shouldn't happen
-				}
-			}
-
-			workingThreadCount++;
-			if (canceled) {
-				return null;
-			} else {
-				return requestQueue.remove(0);
-			}
-
-		} finally {
-			requestQueueLock.unlock();
-		}
-	}
-
-	public void finishRequest(WMSRequest request) {
-		if (request.getState() == null) {
-			throw new IllegalArgumentException("Finished request without state");
-		}
-		requestQueueLock.lock();
-		try {
-			finishedRequests.add(request);
-		} finally {
-			requestQueueLock.unlock();
-		}
-	}
-
-	public void addRequest(WMSRequest request) {
-		requestQueueLock.lock();
-		try {
-			if (!requestQueue.contains(request)) {
-				requestQueue.add(request);
-				queueEmpty.signalAll();
-			}
-		} finally {
-			requestQueueLock.unlock();
-		}
-	}
-
-	public boolean requestIsValid(WMSRequest request) {
-		return bminx <= request.getXIndex() && bmaxx >= request.getXIndex() && bminy <= request.getYIndex() && bmaxy >= request.getYIndex();
-	}
-
-	private void gatherFinishedRequests() {
-		requestQueueLock.lock();
-		try {
-			for (WMSRequest request: finishedRequests) {
-				GeorefImage img = images[modulo(request.getXIndex(),dax)][modulo(request.getYIndex(),day)];
-				if (img.equalPosition(request.getXIndex(), request.getYIndex())) {
-					img.changeImage(request.getState(), request.getImage());
-				}
-			}
-		} finally {
-			finishedRequests.clear();
-			requestQueueLock.unlock();
-		}
-	}
-
-	public class DownloadAction extends AbstractAction {
-		private static final long serialVersionUID = -7183852461015284020L;
-		public DownloadAction() {
-			super(tr("Download visible tiles"));
-		}
-		public void actionPerformed(ActionEvent ev) {
-			if (zoomIsTooBig()) {
-				JOptionPane.showMessageDialog(
-						Main.parent,
-						tr("The requested area is too big. Please zoom in a little, or change resolution"),
-						tr("Error"),
-						JOptionPane.ERROR_MESSAGE
-				);
-			} else {
-				downloadAndPaintVisible(mv.getGraphics(), mv, true);
-			}
-		}
-	}
-
-	public class ChangeResolutionAction extends AbstractAction {
-		public ChangeResolutionAction() {
-			super(tr("Change resolution"));
-		}
-		public void actionPerformed(ActionEvent ev) {
-			initializeImages();
-			resolution = mv.getDist100PixelText();
-			pixelPerDegree = getPPD();
-			settingsChanged = true;
-			mv.repaint();
-		}
-	}
-
-	public class ReloadErrorTilesAction extends AbstractAction {
-		public ReloadErrorTilesAction() {
-			super(tr("Reload erroneous tiles"));
-		}
-		public void actionPerformed(ActionEvent ev) {
-			// Delete small files, because they're probably blank tiles.
-			// See https://josm.openstreetmap.de/ticket/2307
-			WMSPlugin.cache.customCleanUp(CacheFiles.CLEAN_SMALL_FILES, 4096);
-
-			for (int x = 0; x < dax; ++x) {
-				for (int y = 0; y < day; ++y) {
-					GeorefImage img = images[modulo(x,dax)][modulo(y,day)];
-					if(img.getState() == State.FAILED){
-						addRequest(new WMSRequest(img.getXIndex(), img.getYIndex(), pixelPerDegree, true));
-						mv.repaint();
-					}
-				}
-			}
-		}
-	}
-
-	public class ToggleAlphaAction extends AbstractAction implements LayerAction {
-		public ToggleAlphaAction() {
-			super(tr("Alpha channel"));
-		}
-		public void actionPerformed(ActionEvent ev) {
-			JCheckBoxMenuItem checkbox = (JCheckBoxMenuItem) ev.getSource();
-			boolean alphaChannel = checkbox.isSelected();
-			PROP_ALPHA_CHANNEL.put(alphaChannel);
-
-			// clear all resized cached instances and repaint the layer
-			for (int x = 0; x < dax; ++x) {
-				for (int y = 0; y < day; ++y) {
-					GeorefImage img = images[modulo(x, dax)][modulo(y, day)];
-					img.flushedResizedCachedInstance();
-				}
-			}
-			mv.repaint();
-		}
-		public Component createMenuComponent() {
-			JCheckBoxMenuItem item = new JCheckBoxMenuItem(this);
-			item.setSelected(PROP_ALPHA_CHANNEL.get());
-			return item;
-		}
-		public boolean supportLayers(List<Layer> layers) {
-			return layers.size() == 1 && layers.get(0) instanceof WMSLayer;
-		}
-	}
-
-	public class SaveWmsAction extends AbstractAction {
-		public SaveWmsAction() {
-			super(tr("Save WMS layer to file"), ImageProvider.get("save"));
-		}
-		public void actionPerformed(ActionEvent ev) {
-			File f = SaveActionBase.createAndOpenSaveFileChooser(
-					tr("Save WMS layer"), ".wms");
-			try {
-				if (f != null) {
-					ObjectOutputStream oos = new ObjectOutputStream(
-							new FileOutputStream(f)
-					);
-					oos.writeInt(serializeFormatVersion);
-					oos.writeInt(dax);
-					oos.writeInt(day);
-					oos.writeInt(imageSize);
-					oos.writeDouble(pixelPerDegree);
-					oos.writeObject(getName());
-					oos.writeObject(baseURL);
-					oos.writeObject(images);
-					oos.close();
-				}
-			} catch (Exception ex) {
-				ex.printStackTrace(System.out);
-			}
-		}
-	}
-
-	public class LoadWmsAction extends AbstractAction {
-		public LoadWmsAction() {
-			super(tr("Load WMS layer from file"), ImageProvider.get("load"));
-		}
-		public void actionPerformed(ActionEvent ev) {
-			JFileChooser fc = DiskAccessAction.createAndOpenFileChooser(true,
-					false, tr("Load WMS layer"), "wms");
-			if(fc == null) return;
-			File f = fc.getSelectedFile();
-			if (f == null) return;
-			try
-			{
-				FileInputStream fis = new FileInputStream(f);
-				ObjectInputStream ois = new ObjectInputStream(fis);
-				int sfv = ois.readInt();
-				if (sfv != serializeFormatVersion) {
-					JOptionPane.showMessageDialog(Main.parent,
-							tr("Unsupported WMS file version; found {0}, expected {1}", sfv, serializeFormatVersion),
-							tr("File Format Error"),
-							JOptionPane.ERROR_MESSAGE);
-					return;
-				}
-				autoDownloadEnabled = false;
-				dax = ois.readInt();
-				day = ois.readInt();
-				imageSize = ois.readInt();
-				pixelPerDegree = ois.readDouble();
-				setName((String)ois.readObject());
-				baseURL = (String) ois.readObject();
-				images = (GeorefImage[][])ois.readObject();
-				ois.close();
-				fis.close();
-				for (GeorefImage[] imgs : images) {
-					for (GeorefImage img : imgs) {
-						if (img != null) {
-							img.setLayer(WMSLayer.this);
-						}
-					}
-				}
-				settingsChanged = true;
-				mv.repaint();
-				if(baseURL != null)
-				{
-					startGrabberThreads();
-				}
-			}
-			catch (Exception ex) {
-				// FIXME be more specific
-				ex.printStackTrace(System.out);
-				JOptionPane.showMessageDialog(Main.parent,
-						tr("Error loading file"),
-						tr("Error"),
-						JOptionPane.ERROR_MESSAGE);
-				return;
-			}
-		}
-	}
-	/**
-	 * This action will add a WMS layer menu entry with the current WMS layer
-	 * URL and name extended by the current resolution.
-	 * When using the menu entry again, the WMS cache will be used properly.
-	 */
-	public class BookmarkWmsAction extends AbstractAction {
-		public BookmarkWmsAction() {
-			super(tr("Set WMS Bookmark"));
-		}
-		public void actionPerformed(ActionEvent ev) {
-			int i = 0;
-			while (Main.pref.hasKey("wmsplugin.url."+i+".url")) {
-				i++;
-			}
-			String baseName;
-			// cut old parameter
-			int parameterIndex = getName().indexOf("#PPD=");
-			if (parameterIndex != -1) {
-				baseName = getName().substring(0,parameterIndex);
-			}
-			else {
-				baseName = getName();
-			}
-			Main.pref.put("wmsplugin.url."+ i +".url",baseURL );
-			Main.pref.put("wmsplugin.url."+String.valueOf(i)+".name",
-					baseName + "#PPD=" + pixelPerDegree );
-			WMSPlugin.refreshMenu();
-		}
-	}
-
-	private class StartStopAction extends AbstractAction implements LayerAction {
-
-		public StartStopAction() {
-			super(tr("Automatic downloading"));
-		}
-
-		public Component createMenuComponent() {
-			JCheckBoxMenuItem item = new JCheckBoxMenuItem(this);
-			item.setSelected(autoDownloadEnabled);
-			return item;
-		}
-
-		public boolean supportLayers(List<Layer> layers) {
-			return layers.size() == 1 && layers.get(0) instanceof WMSLayer;
-		}
-
-		public void actionPerformed(ActionEvent e) {
-			autoDownloadEnabled = !autoDownloadEnabled;
-			if (autoDownloadEnabled) {
-				mv.repaint();
-			}
-		}
-	}
-
-	private void cancelGrabberThreads(boolean wait) {
-		requestQueueLock.lock();
-		try {
-			canceled = true;
-			for (Grabber grabber: grabbers) {
-				grabber.cancel();
-			}
-			queueEmpty.signalAll();
-		} finally {
-			requestQueueLock.unlock();
-		}
-		if (wait) {
-			for (Thread t: grabberThreads) {
-				try {
-					t.join();
-				} catch (InterruptedException e) {
-					// Shouldn't happen
-					e.printStackTrace();
-				}
-			}
-		}
-	}
-
-	private void startGrabberThreads() {
-		int threadCount = WMSPlugin.PROP_SIMULTANEOUS_CONNECTIONS.get();
-		requestQueueLock.lock();
-		try {
-			canceled = false;
-			grabbers.clear();
-			grabberThreads.clear();
-			for (int i=0; i<threadCount; i++) {
-				Grabber grabber = WMSPlugin.getGrabber(mv, this);
-				grabbers.add(grabber);
-				Thread t = new Thread(grabber, "WMS " + getName() + " " + i);
-				t.setDaemon(true);
-				t.start();
-				grabberThreads.add(t);
-			}
-			this.workingThreadCount = grabbers.size();
-			this.threadCount = grabbers.size();
-		} finally {
-			requestQueueLock.unlock();
-		}
-	}
-
-	@Override
-	public boolean isChanged() {
-		requestQueueLock.lock();
-		try {
-			return !finishedRequests.isEmpty() || settingsChanged;
-		} finally {
-			requestQueueLock.unlock();
-		}
-	}
-
-	public void preferenceChanged(PreferenceChangeEvent event) {
-		if (event.getKey().equals(WMSPlugin.PROP_SIMULTANEOUS_CONNECTIONS.getKey())) {
-			cancelGrabberThreads(true);
-			startGrabberThreads();
-		} else if (
-				event.getKey().equals(WMSPlugin.PROP_OVERLAP.getKey())
-				|| event.getKey().equals(WMSPlugin.PROP_OVERLAP_EAST.getKey())
-				|| event.getKey().equals(WMSPlugin.PROP_OVERLAP_NORTH.getKey())) {
-			for (int i=0; i<images.length; i++) {
-				for (int k=0; k<images[i].length; k++) {
-					images[i][k] = new GeorefImage(this);
-				}
-			}
-
-			settingsChanged = true;
-		}
-	}
+    protected static final Icon icon =
+        new ImageIcon(Toolkit.getDefaultToolkit().createImage(WMSPlugin.class.getResource("/images/wms_small.png")));
+
+    public static final BooleanProperty PROP_ALPHA_CHANNEL = new BooleanProperty("wmsplugin.alpha_channel", true);
+    WMSPlugin plugin = WMSPlugin.instance;
+
+    public int messageNum = 5; //limit for messages per layer
+    protected MapView mv;
+    protected String resolution;
+    protected int imageSize = 500;
+    protected int dax = 10;
+    protected int day = 10;
+    protected int daStep = 5;
+    protected int minZoom = 3;
+
+    protected double dx = 0.0;
+    protected double dy = 0.0;
+
+    protected GeorefImage[][] images;
+    protected final int serializeFormatVersion = 5;
+    protected boolean autoDownloadEnabled = true;
+    protected boolean settingsChanged;
+    protected WMSInfo info;
+
+    // Image index boundary for current view
+    private volatile int bminx;
+    private volatile int bminy;
+    private volatile int bmaxx;
+    private volatile int bmaxy;
+    private volatile int leftEdge;
+    private volatile int bottomEdge;
+
+    // Request queue
+    private final List<WMSRequest> requestQueue = new ArrayList<WMSRequest>();
+    private final List<WMSRequest> finishedRequests = new ArrayList<WMSRequest>();
+    private final Lock requestQueueLock = new ReentrantLock();
+    private final Condition queueEmpty = requestQueueLock.newCondition();
+    private final List<Grabber> grabbers = new ArrayList<Grabber>();
+    private final List<Thread> grabberThreads = new ArrayList<Thread>();
+    private int threadCount;
+    private int workingThreadCount;
+    private boolean canceled;
+
+
+    /** set to true if this layer uses an invalid base url */
+    private boolean usesInvalidUrl = false;
+    /** set to true if the user confirmed to use an potentially invalid WMS base url */
+    private boolean isInvalidUrlConfirmed = false;
+
+    public WMSLayer() {
+        this(new WMSInfo(tr("Blank Layer")));
+    }
+
+    public WMSLayer(WMSInfo info) {
+        super(info.name);
+        setBackgroundLayer(true); /* set global background variable */
+        initializeImages();
+        this.info = new WMSInfo(info);
+        mv = Main.map.mapView;
+        if(this.info.pixelPerDegree == 0.0)
+            this.info.setPixelPerDegree(getPPD());
+        resolution = mv.getDist100PixelText();
+
+        if(info.url != null) {
+            WMSGrabber.getProjection(info.url, true);
+            startGrabberThreads();
+            if(!info.url.startsWith("html:") && !WMSGrabber.isUrlWithPatterns(info.url)) {
+                if (!(info.url.endsWith("&") || info.url.endsWith("?"))) {
+                    if (!confirmMalformedUrl(info.url)) {
+                        System.out.println(tr("Warning: WMS layer deactivated because of malformed base url ''{0}''", info.url));
+                        usesInvalidUrl = true;
+                        setName(getName() + tr("(deactivated)"));
+                        return;
+                    } else {
+                        isInvalidUrlConfirmed = true;
+                    }
+                }
+            }
+        }
+
+        Main.pref.addPreferenceChangeListener(this);
+    }
+
+    public void doSetName(String name) {
+        setName(name);
+        info.name = name;
+    }
+
+    public boolean hasAutoDownload(){
+        return autoDownloadEnabled;
+    }
+
+
+    @Override
+    public void destroy() {
+        cancelGrabberThreads(false);
+        Main.pref.removePreferenceChangeListener(this);
+    }
+
+    public void initializeImages() {
+        GeorefImage[][] old = images;
+        images = new GeorefImage[dax][day];
+        if (old != null) {
+            for (int i=0; i<old.length; i++) {
+                for (int k=0; k<old[i].length; k++) {
+                    GeorefImage o = old[i][k];
+                    images[modulo(o.getXIndex(),dax)][modulo(o.getYIndex(),day)] = old[i][k];
+                }
+            }
+        }
+        for(int x = 0; x<dax; ++x) {
+            for(int y = 0; y<day; ++y) {
+                if (images[x][y] == null) {
+                    images[x][y]= new GeorefImage(this);
+                }
+            }
+        }
+    }
+
+    @Override public Icon getIcon() {
+        return icon;
+    }
+
+    @Override public String getToolTipText() {
+        if(autoDownloadEnabled)
+            return tr("WMS layer ({0}), automatically downloading in zoom {1}", getName(), resolution);
+        else
+            return tr("WMS layer ({0}), downloading in zoom {1}", getName(), resolution);
+    }
+
+    @Override public boolean isMergable(Layer other) {
+        return false;
+    }
+
+    @Override public void mergeFrom(Layer from) {
+    }
+
+    private int modulo (int a, int b) {
+        return a % b >= 0 ? a%b : a%b+b;
+    }
+
+    private boolean zoomIsTooBig() {
+        //don't download when it's too outzoomed
+        return info.pixelPerDegree / getPPD() > minZoom;
+    }
+
+    @Override public void paint(Graphics2D g, final MapView mv, Bounds b) {
+        if(info.url == null || (usesInvalidUrl && !isInvalidUrlConfirmed)) return;
+
+        settingsChanged = false;
+
+        ProjectionBounds bounds = mv.getProjectionBounds();
+        bminx= getImageXIndex(bounds.min.east());
+        bminy= getImageYIndex(bounds.min.north());
+        bmaxx= getImageXIndex(bounds.max.east());
+        bmaxy= getImageYIndex(bounds.max.north());
+
+        leftEdge = (int)(bounds.min.east() * getPPD());
+        bottomEdge = (int)(bounds.min.north() * getPPD());
+
+        if (zoomIsTooBig()) {
+            for(int x = bminx; x<=bmaxx; ++x) {
+                for(int y = bminy; y<=bmaxy; ++y) {
+                    images[modulo(x,dax)][modulo(y,day)].paint(g, mv, x, y, leftEdge, bottomEdge);
+                }
+            }
+        } else {
+            downloadAndPaintVisible(g, mv, false);
+        }
+    }
+
+    protected boolean confirmMalformedUrl(String url) {
+        if (isInvalidUrlConfirmed)
+            return true;
+        String msg  = tr("<html>The base URL<br>"
+                + "''{0}''<br>"
+                + "for this WMS layer does neither end with a ''&'' nor with a ''?''.<br>"
+                + "This is likely to lead to invalid WMS request. You should check your<br>"
+                + "preference settings.<br>"
+                + "Do you want to fetch WMS tiles anyway?",
+                url);
+        String [] options = new String[] {
+                tr("Yes, fetch images"),
+                tr("No, abort")
+        };
+        int ret = JOptionPane.showOptionDialog(
+                Main.parent,
+                msg,
+                tr("Invalid URL?"),
+                JOptionPane.YES_NO_OPTION,
+                JOptionPane.WARNING_MESSAGE,
+                null,
+                options, options[1]
+        );
+        switch(ret) {
+        case JOptionPane.YES_OPTION: return true;
+        default: return false;
+        }
+    }
+
+    public double getPPD(){
+        ProjectionBounds bounds = mv.getProjectionBounds();
+        return mv.getWidth() / (bounds.max.east() - bounds.min.east());
+    }
+
+    public void displace(double dx, double dy) {
+        settingsChanged = true;
+        this.dx += dx;
+        this.dy += dy;
+    }
+
+    public int getImageXIndex(double coord) {
+        return (int)Math.floor( ((coord - dx) * info.pixelPerDegree) / imageSize);
+    }
+
+    public int getImageYIndex(double coord) {
+        return (int)Math.floor( ((coord - dy) * info.pixelPerDegree) / imageSize);
+    }
+
+    public int getImageX(int imageIndex) {
+        return (int)(imageIndex * imageSize * (getPPD() / info.pixelPerDegree) + dx * getPPD());
+    }
+
+    public int getImageY(int imageIndex) {
+        return (int)(imageIndex * imageSize * (getPPD() / info.pixelPerDegree) + dy * getPPD());
+    }
+
+    public int getImageWidth(int xIndex) {
+        int overlap = (int)(plugin.PROP_OVERLAP.get()?plugin.PROP_OVERLAP_EAST.get() * imageSize * getPPD() / info.pixelPerDegree / 100:0);
+        return getImageX(xIndex + 1) - getImageX(xIndex) + overlap;
+    }
+
+    public int getImageHeight(int yIndex) {
+        int overlap = (int)(plugin.PROP_OVERLAP.get()?plugin.PROP_OVERLAP_NORTH.get() * imageSize * getPPD() / info.pixelPerDegree / 100:0);
+        return getImageY(yIndex + 1) - getImageY(yIndex) + overlap;
+    }
+
+    /**
+     *
+     * @return Size of image in original zoom
+     */
+    public int getBaseImageWidth() {
+        int overlap = (plugin.PROP_OVERLAP.get()?plugin.PROP_OVERLAP_EAST.get() * imageSize / 100:0);
+        return imageSize + overlap;
+    }
+
+    /**
+     *
+     * @return Size of image in original zoom
+     */
+    public int getBaseImageHeight() {
+        int overlap = (plugin.PROP_OVERLAP.get()?plugin.PROP_OVERLAP_NORTH.get() * imageSize / 100:0);
+        return imageSize + overlap;
+    }
+
+
+    /**
+     *
+     * @param xIndex
+     * @param yIndex
+     * @return Real EastNorth of given tile. dx/dy is not counted in
+     */
+    public EastNorth getEastNorth(int xIndex, int yIndex) {
+        return new EastNorth((xIndex * imageSize) / info.pixelPerDegree, (yIndex * imageSize) / info.pixelPerDegree);
+    }
+
+
+    protected void downloadAndPaintVisible(Graphics g, final MapView mv, boolean real){
+
+        int newDax = dax;
+        int newDay = day;
+
+        if (bmaxx - bminx >= dax || bmaxx - bminx < dax - 2 * daStep) {
+            newDax = ((bmaxx - bminx) / daStep + 1) * daStep;
+        }
+
+        if (bmaxy - bminy >= day || bmaxy - bminx < day - 2 * daStep) {
+            newDay = ((bmaxy - bminy) / daStep + 1) * daStep;
+        }
+
+        if (newDax != dax || newDay != day) {
+            dax = newDax;
+            day = newDay;
+            initializeImages();
+        }
+
+        for(int x = bminx; x<=bmaxx; ++x) {
+            for(int y = bminy; y<=bmaxy; ++y){
+                images[modulo(x,dax)][modulo(y,day)].changePosition(x, y);
+            }
+        }
+
+        gatherFinishedRequests();
+
+        for(int x = bminx; x<=bmaxx; ++x) {
+            for(int y = bminy; y<=bmaxy; ++y){
+                GeorefImage img = images[modulo(x,dax)][modulo(y,day)];
+                if (!img.paint(g, mv, x, y, leftEdge, bottomEdge)) {
+                    WMSRequest request = new WMSRequest(x, y, info.pixelPerDegree, real);
+                    addRequest(request);
+                }
+            }
+        }
+    }
+
+    @Override public void visitBoundingBox(BoundingXYVisitor v) {
+        for(int x = 0; x<dax; ++x) {
+            for(int y = 0; y<day; ++y)
+                if(images[x][y].getImage() != null){
+                    v.visit(images[x][y].getMin());
+                    v.visit(images[x][y].getMax());
+                }
+        }
+    }
+
+    @Override public Object getInfoComponent() {
+        return getToolTipText();
+    }
+
+    @Override public Action[] getMenuEntries() {
+        return new Action[]{
+                LayerListDialog.getInstance().createActivateLayerAction(this),
+                LayerListDialog.getInstance().createShowHideLayerAction(),
+                LayerListDialog.getInstance().createDeleteLayerAction(),
+                SeparatorLayerAction.INSTANCE,
+                new LoadWmsAction(),
+                new SaveWmsAction(),
+                new BookmarkWmsAction(),
+                SeparatorLayerAction.INSTANCE,
+                new StartStopAction(),
+                new ToggleAlphaAction(),
+                new ChangeResolutionAction(),
+                new ReloadErrorTilesAction(),
+                new DownloadAction(),
+                SeparatorLayerAction.INSTANCE,
+                new LayerListPopup.InfoAction(this)
+        };
+    }
+
+    public GeorefImage findImage(EastNorth eastNorth) {
+        int xIndex = getImageXIndex(eastNorth.east());
+        int yIndex = getImageYIndex(eastNorth.north());
+        GeorefImage result = images[modulo(xIndex, dax)][modulo(yIndex, day)];
+        if (result.getXIndex() == xIndex && result.getYIndex() == yIndex) {
+            return result;
+        } else {
+            return null;
+        }
+    }
+
+    /**
+     *
+     * @param request
+     * @return -1 if request is no longer needed, otherwise priority of request (lower number <=> more important request)
+     */
+    private int getRequestPriority(WMSRequest request) {
+        if (request.getPixelPerDegree() != info.pixelPerDegree) {
+            return -1;
+        }
+        if (bminx > request.getXIndex()
+                || bmaxx < request.getXIndex()
+                || bminy > request.getYIndex()
+                || bmaxy < request.getYIndex()) {
+            return -1;
+        }
+
+        EastNorth cursorEastNorth = mv.getEastNorth(mv.lastMEvent.getX(), mv.lastMEvent.getY());
+        int mouseX = getImageXIndex(cursorEastNorth.east());
+        int mouseY = getImageYIndex(cursorEastNorth.north());
+        int dx = request.getXIndex() - mouseX;
+        int dy = request.getYIndex() - mouseY;
+
+        return dx * dx + dy * dy;
+    }
+
+    public WMSRequest getRequest() {
+        requestQueueLock.lock();
+        try {
+            workingThreadCount--;
+            Iterator<WMSRequest> it = requestQueue.iterator();
+            while (it.hasNext()) {
+                WMSRequest item = it.next();
+                int priority = getRequestPriority(item);
+                if (priority == -1) {
+                    it.remove();
+                } else {
+                    item.setPriority(priority);
+                }
+            }
+            Collections.sort(requestQueue);
+
+            EastNorth cursorEastNorth = mv.getEastNorth(mv.lastMEvent.getX(), mv.lastMEvent.getY());
+            int mouseX = getImageXIndex(cursorEastNorth.east());
+            int mouseY = getImageYIndex(cursorEastNorth.north());
+            boolean isOnMouse = requestQueue.size() > 0 && requestQueue.get(0).getXIndex() == mouseX && requestQueue.get(0).getYIndex() == mouseY;
+
+            // If there is only one thread left then keep it in case we need to download other tile urgently
+            while (!canceled &&
+                    (requestQueue.isEmpty() || (!isOnMouse && threadCount - workingThreadCount == 0 && threadCount > 1))) {
+                try {
+                    queueEmpty.await();
+                } catch (InterruptedException e) {
+                    // Shouldn't happen
+                }
+            }
+
+            workingThreadCount++;
+            if (canceled) {
+                return null;
+            } else {
+                return requestQueue.remove(0);
+            }
+
+        } finally {
+            requestQueueLock.unlock();
+        }
+    }
+
+    public void finishRequest(WMSRequest request) {
+        if (request.getState() == null) {
+            throw new IllegalArgumentException("Finished request without state");
+        }
+        requestQueueLock.lock();
+        try {
+            finishedRequests.add(request);
+        } finally {
+            requestQueueLock.unlock();
+        }
+    }
+
+    public void addRequest(WMSRequest request) {
+        requestQueueLock.lock();
+        try {
+            if (!requestQueue.contains(request)) {
+                requestQueue.add(request);
+                queueEmpty.signalAll();
+            }
+        } finally {
+            requestQueueLock.unlock();
+        }
+    }
+
+    public boolean requestIsValid(WMSRequest request) {
+        return bminx <= request.getXIndex() && bmaxx >= request.getXIndex() && bminy <= request.getYIndex() && bmaxy >= request.getYIndex();
+    }
+
+    private void gatherFinishedRequests() {
+        requestQueueLock.lock();
+        try {
+            for (WMSRequest request: finishedRequests) {
+                GeorefImage img = images[modulo(request.getXIndex(),dax)][modulo(request.getYIndex(),day)];
+                if (img.equalPosition(request.getXIndex(), request.getYIndex())) {
+                    img.changeImage(request.getState(), request.getImage());
+                }
+            }
+        } finally {
+            finishedRequests.clear();
+            requestQueueLock.unlock();
+        }
+    }
+
+    public class DownloadAction extends AbstractAction {
+        private static final long serialVersionUID = -7183852461015284020L;
+        public DownloadAction() {
+            super(tr("Download visible tiles"));
+        }
+        public void actionPerformed(ActionEvent ev) {
+            if (zoomIsTooBig()) {
+                JOptionPane.showMessageDialog(
+                        Main.parent,
+                        tr("The requested area is too big. Please zoom in a little, or change resolution"),
+                        tr("Error"),
+                        JOptionPane.ERROR_MESSAGE
+                );
+            } else {
+                downloadAndPaintVisible(mv.getGraphics(), mv, true);
+            }
+        }
+    }
+
+    public class ChangeResolutionAction extends AbstractAction {
+        public ChangeResolutionAction() {
+            super(tr("Change resolution"));
+        }
+        public void actionPerformed(ActionEvent ev) {
+            initializeImages();
+            resolution = mv.getDist100PixelText();
+            info.setPixelPerDegree(getPPD());
+            settingsChanged = true;
+            mv.repaint();
+        }
+    }
+
+    public class ReloadErrorTilesAction extends AbstractAction {
+        public ReloadErrorTilesAction() {
+            super(tr("Reload erroneous tiles"));
+        }
+        public void actionPerformed(ActionEvent ev) {
+            // Delete small files, because they're probably blank tiles.
+            // See https://josm.openstreetmap.de/ticket/2307
+            plugin.cache.customCleanUp(CacheFiles.CLEAN_SMALL_FILES, 4096);
+
+            for (int x = 0; x < dax; ++x) {
+                for (int y = 0; y < day; ++y) {
+                    GeorefImage img = images[modulo(x,dax)][modulo(y,day)];
+                    if(img.getState() == State.FAILED){
+                        addRequest(new WMSRequest(img.getXIndex(), img.getYIndex(), info.pixelPerDegree, true));
+                        mv.repaint();
+                    }
+                }
+            }
+        }
+    }
+
+    public class ToggleAlphaAction extends AbstractAction implements LayerAction {
+        public ToggleAlphaAction() {
+            super(tr("Alpha channel"));
+        }
+        public void actionPerformed(ActionEvent ev) {
+            JCheckBoxMenuItem checkbox = (JCheckBoxMenuItem) ev.getSource();
+            boolean alphaChannel = checkbox.isSelected();
+            PROP_ALPHA_CHANNEL.put(alphaChannel);
+
+            // clear all resized cached instances and repaint the layer
+            for (int x = 0; x < dax; ++x) {
+                for (int y = 0; y < day; ++y) {
+                    GeorefImage img = images[modulo(x, dax)][modulo(y, day)];
+                    img.flushedResizedCachedInstance();
+                }
+            }
+            mv.repaint();
+        }
+        public Component createMenuComponent() {
+            JCheckBoxMenuItem item = new JCheckBoxMenuItem(this);
+            item.setSelected(PROP_ALPHA_CHANNEL.get());
+            return item;
+        }
+        public boolean supportLayers(List<Layer> layers) {
+            return layers.size() == 1 && layers.get(0) instanceof WMSLayer;
+        }
+    }
+
+    public class SaveWmsAction extends AbstractAction {
+        public SaveWmsAction() {
+            super(tr("Save WMS layer to file"), ImageProvider.get("save"));
+        }
+        public void actionPerformed(ActionEvent ev) {
+            File f = SaveActionBase.createAndOpenSaveFileChooser(
+                    tr("Save WMS layer"), ".wms");
+            try {
+                if (f != null) {
+                    ObjectOutputStream oos = new ObjectOutputStream(
+                            new FileOutputStream(f)
+                    );
+                    oos.writeInt(serializeFormatVersion);
+                    oos.writeInt(dax);
+                    oos.writeInt(day);
+                    oos.writeInt(imageSize);
+                    oos.writeDouble(info.pixelPerDegree);
+                    oos.writeObject(info.name);
+                    oos.writeObject(info.getFullURL());
+                    oos.writeObject(images);
+                    oos.close();
+                }
+            } catch (Exception ex) {
+                ex.printStackTrace(System.out);
+            }
+        }
+    }
+
+    public class LoadWmsAction extends AbstractAction {
+        public LoadWmsAction() {
+            super(tr("Load WMS layer from file"), ImageProvider.get("load"));
+        }
+        public void actionPerformed(ActionEvent ev) {
+            JFileChooser fc = DiskAccessAction.createAndOpenFileChooser(true,
+                    false, tr("Load WMS layer"), "wms");
+            if(fc == null) return;
+            File f = fc.getSelectedFile();
+            if (f == null) return;
+            try
+            {
+                FileInputStream fis = new FileInputStream(f);
+                ObjectInputStream ois = new ObjectInputStream(fis);
+                int sfv = ois.readInt();
+                if (sfv != serializeFormatVersion) {
+                    JOptionPane.showMessageDialog(Main.parent,
+                            tr("Unsupported WMS file version; found {0}, expected {1}", sfv, serializeFormatVersion),
+                            tr("File Format Error"),
+                            JOptionPane.ERROR_MESSAGE);
+                    return;
+                }
+                autoDownloadEnabled = false;
+                dax = ois.readInt();
+                day = ois.readInt();
+                imageSize = ois.readInt();
+                info.setPixelPerDegree(ois.readDouble());
+                doSetName((String)ois.readObject());
+                info.setURL((String) ois.readObject());
+                images = (GeorefImage[][])ois.readObject();
+                ois.close();
+                fis.close();
+                for (GeorefImage[] imgs : images) {
+                    for (GeorefImage img : imgs) {
+                        if (img != null) {
+                            img.setLayer(WMSLayer.this);
+                        }
+                    }
+                }
+                settingsChanged = true;
+                mv.repaint();
+                if(info.url != null)
+                {
+                    startGrabberThreads();
+                }
+            }
+            catch (Exception ex) {
+                // FIXME be more specific
+                ex.printStackTrace(System.out);
+                JOptionPane.showMessageDialog(Main.parent,
+                        tr("Error loading file"),
+                        tr("Error"),
+                        JOptionPane.ERROR_MESSAGE);
+                return;
+            }
+        }
+    }
+    /**
+     * This action will add a WMS layer menu entry with the current WMS layer
+     * URL and name extended by the current resolution.
+     * When using the menu entry again, the WMS cache will be used properly.
+     */
+    public class BookmarkWmsAction extends AbstractAction {
+        public BookmarkWmsAction() {
+            super(tr("Set WMS Bookmark"));
+        }
+        public void actionPerformed(ActionEvent ev) {
+            plugin.addLayer(new WMSInfo(info));
+        }
+    }
+
+    private class StartStopAction extends AbstractAction implements LayerAction {
+
+        public StartStopAction() {
+            super(tr("Automatic downloading"));
+        }
+
+        public Component createMenuComponent() {
+            JCheckBoxMenuItem item = new JCheckBoxMenuItem(this);
+            item.setSelected(autoDownloadEnabled);
+            return item;
+        }
+
+        public boolean supportLayers(List<Layer> layers) {
+            return layers.size() == 1 && layers.get(0) instanceof WMSLayer;
+        }
+
+        public void actionPerformed(ActionEvent e) {
+            autoDownloadEnabled = !autoDownloadEnabled;
+            if (autoDownloadEnabled) {
+                mv.repaint();
+            }
+        }
+    }
+
+    private void cancelGrabberThreads(boolean wait) {
+        requestQueueLock.lock();
+        try {
+            canceled = true;
+            for (Grabber grabber: grabbers) {
+                grabber.cancel();
+            }
+            queueEmpty.signalAll();
+        } finally {
+            requestQueueLock.unlock();
+        }
+        if (wait) {
+            for (Thread t: grabberThreads) {
+                try {
+                    t.join();
+                } catch (InterruptedException e) {
+                    // Shouldn't happen
+                    e.printStackTrace();
+                }
+            }
+        }
+    }
+
+    private void startGrabberThreads() {
+        int threadCount = plugin.PROP_SIMULTANEOUS_CONNECTIONS.get();
+        requestQueueLock.lock();
+        try {
+            canceled = false;
+            grabbers.clear();
+            grabberThreads.clear();
+            for (int i=0; i<threadCount; i++) {
+                Grabber grabber = plugin.getGrabber(mv, this);
+                grabbers.add(grabber);
+                Thread t = new Thread(grabber, "WMS " + getName() + " " + i);
+                t.setDaemon(true);
+                t.start();
+                grabberThreads.add(t);
+            }
+            this.workingThreadCount = grabbers.size();
+            this.threadCount = grabbers.size();
+        } finally {
+            requestQueueLock.unlock();
+        }
+    }
+
+    @Override
+    public boolean isChanged() {
+        requestQueueLock.lock();
+        try {
+            return !finishedRequests.isEmpty() || settingsChanged;
+        } finally {
+            requestQueueLock.unlock();
+        }
+    }
+
+    public void preferenceChanged(PreferenceChangeEvent event) {
+        if (event.getKey().equals(plugin.PROP_SIMULTANEOUS_CONNECTIONS.getKey())) {
+            cancelGrabberThreads(true);
+            startGrabberThreads();
+        } else if (
+                event.getKey().equals(plugin.PROP_OVERLAP.getKey())
+                || event.getKey().equals(plugin.PROP_OVERLAP_EAST.getKey())
+                || event.getKey().equals(plugin.PROP_OVERLAP_NORTH.getKey())) {
+            for (int i=0; i<images.length; i++) {
+                for (int k=0; k<images[i].length; k++) {
+                    images[i][k] = new GeorefImage(this);
+                }
+            }
+
+            settingsChanged = true;
+        }
+    }
 
 }
diff --git a/wmsplugin/src/wmsplugin/WMSLayerInfo.java b/wmsplugin/src/wmsplugin/WMSLayerInfo.java
new file mode 100644
index 0000000..812c60f
--- /dev/null
+++ b/wmsplugin/src/wmsplugin/WMSLayerInfo.java
@@ -0,0 +1,156 @@
+package wmsplugin;
+
+import static org.openstreetmap.josm.tools.I18n.tr;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.io.UnsupportedEncodingException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.LinkedList;
+import java.util.Map;
+import java.util.TreeSet;
+
+import org.openstreetmap.josm.Main;
+import org.openstreetmap.josm.io.MirroredInputStream;
+
+public class WMSLayerInfo {
+    ArrayList<WMSInfo> layers = new ArrayList<WMSInfo>();
+    ArrayList<WMSInfo> defaultLayers = new ArrayList<WMSInfo>();
+    private final static String[] DEFAULT_LAYER_SITES = {
+    "http://svn.openstreetmap.org/applications/editors/josm/plugins/wmsplugin/sources.cfg"};
+
+    public void load() {
+        layers.clear();
+        Collection<String> defaults = Main.pref.getCollection(
+            "wmslayers.default", Collections.<String>emptySet());
+        for(Collection<String> c : Main.pref.getArray("wmslayers",
+        Collections.<Collection<String>>emptySet())) {
+            layers.add(new WMSInfo(c));
+        }
+
+        { /* REMOVE following old block in spring 2011 */
+            defaults = new LinkedList<String>(defaults);
+            Map<String,String> prefs = Main.pref.getAllPrefix("wmsplugin.default.");
+            for(String s : prefs.keySet()) {
+                Main.pref.put(s, null);
+                defaults.add(s.substring(18));
+            }
+            prefs = Main.pref.getAllPrefix("wmsplugin.url.");
+            for(String s : prefs.keySet()) {
+                Main.pref.put(s, null);
+            }
+            TreeSet<String> keys = new TreeSet<String>(prefs.keySet());
+
+            // And then the names+urls of WMS servers
+            int prefid = 0;
+            String name = null;
+            String url = null;
+            String cookies = null;
+            double pixelPerDegree = 0.0;
+            int lastid = -1;
+            for (String key : keys) {
+                String[] elements = key.split("\\.");
+                if (elements.length != 4) continue;
+                try {
+                    prefid = Integer.parseInt(elements[2]);
+                } catch(NumberFormatException e) {
+                    continue;
+                }
+                if (prefid != lastid) {
+                    name = url = cookies = null; pixelPerDegree = 0.0; lastid = prefid;
+                }
+                if (elements[3].equals("name")) {
+                    name = prefs.get(key);
+                    int codeIndex = name.indexOf("#PPD=");
+                    if (codeIndex != -1) {
+                        pixelPerDegree = Double.valueOf(name.substring(codeIndex+5));
+                        name = name.substring(0, codeIndex);
+                    }
+                }
+                else if (elements[3].equals("url"))
+                {
+                    url = prefs.get(key);
+                }
+                else if (elements[3].equals("cookies"))
+                    cookies = prefs.get(key);
+                if (name != null && url != null)
+                    layers.add(new WMSInfo(name, url, cookies, pixelPerDegree));
+            }
+        }
+        ArrayList<String> defaultsSave = new ArrayList<String>();
+        for(String source : Main.pref.getCollection("wmslayers.sites", Arrays.asList(DEFAULT_LAYER_SITES)))
+        {
+            try
+            {
+                MirroredInputStream s = new MirroredInputStream(source, WMSPlugin.instance.getPluginDir(), -1);
+                InputStreamReader r;
+                try
+                {
+                    r = new InputStreamReader(s, "UTF-8");
+                }
+                catch (UnsupportedEncodingException e)
+                {
+                    r = new InputStreamReader(s);
+                }
+                BufferedReader reader = new BufferedReader(r);
+                String line;
+                while((line = reader.readLine()) != null)
+                {
+                    String val[] = line.split(";");
+                    if(!line.startsWith("#") && (val.length == 3 || val.length == 4)) {
+                        boolean force = "true".equals(val[0]);
+                        String name = tr(val[1]);
+                        String url = val[2];
+                        String eulaAcceptanceRequired = null;
+                        if (val.length == 4) {
+                            // 4th parameter optional for license agreement (EULA)
+                            eulaAcceptanceRequired = val[3];
+                        }
+                        defaultLayers.add(new WMSInfo(name, url, eulaAcceptanceRequired));
+
+                        if(force) {
+                            defaultsSave.add(url);
+                            if(!defaults.contains(url)) {
+                                int id = -1;
+                                for(WMSInfo i : layers) {
+                                    if(url.equals(i.url))
+                                        force = false;
+                                }
+                                if(force)
+                                    layers.add(new WMSInfo(name, url));
+                            }
+                        }
+                    }
+                }
+            }
+            catch (IOException e)
+            {
+            }
+        }
+
+        Main.pref.putCollection("wmslayers.default", defaultsSave.size() > 0
+            ? defaultsSave : defaults);
+        Collections.sort(layers);
+        save();
+    }
+
+    public void add(WMSInfo info) {
+        layers.add(info);
+    }
+
+    public void remove(WMSInfo info) {
+        layers.remove(info);
+    }
+
+    public void save() {
+        LinkedList<Collection<String>> coll = new LinkedList<Collection<String>>();
+        for (WMSInfo info : layers) {
+            coll.add(info.getInfoArray());
+        }
+        Main.pref.putArray("wmslayers", coll);
+    }
+}
diff --git a/wmsplugin/src/wmsplugin/WMSPlugin.java b/wmsplugin/src/wmsplugin/WMSPlugin.java
index 7e62f42..8086ed2 100644
--- a/wmsplugin/src/wmsplugin/WMSPlugin.java
+++ b/wmsplugin/src/wmsplugin/WMSPlugin.java
@@ -6,21 +6,9 @@ import static org.openstreetmap.josm.tools.I18n.tr;
 
 import java.awt.event.ActionEvent;
 import java.awt.event.KeyEvent;
-import java.io.BufferedReader;
 import java.io.File;
-import java.io.FileNotFoundException;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.InputStreamReader;
-import java.io.UnsupportedEncodingException;
 import java.lang.reflect.InvocationTargetException;
 import java.lang.reflect.Method;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.Map;
-import java.util.TreeMap;
-import java.util.TreeSet;
 
 import javax.swing.JMenu;
 import javax.swing.JMenuItem;
@@ -37,7 +25,6 @@ import org.openstreetmap.josm.gui.MapFrame;
 import org.openstreetmap.josm.gui.MapView;
 import org.openstreetmap.josm.gui.preferences.PreferenceSetting;
 import org.openstreetmap.josm.io.CacheFiles;
-import org.openstreetmap.josm.io.MirroredInputStream;
 import org.openstreetmap.josm.plugins.Plugin;
 import org.openstreetmap.josm.plugins.PluginHandler;
 import org.openstreetmap.josm.plugins.PluginInformation;
@@ -47,358 +34,255 @@ import wmsplugin.io.WMSLayerExporter;
 import wmsplugin.io.WMSLayerImporter;
 
 public class WMSPlugin extends Plugin {
-	static CacheFiles cache = new CacheFiles("wmsplugin");
-
-	public static final IntegerProperty PROP_SIMULTANEOUS_CONNECTIONS = new IntegerProperty("wmsplugin.simultaneousConnections", 3);
-	public static final BooleanProperty PROP_OVERLAP = new BooleanProperty("wmsplugin.url.overlap", false);
-	public static final IntegerProperty PROP_OVERLAP_EAST = new IntegerProperty("wmsplugin.url.overlapEast", 14);
-	public static final IntegerProperty PROP_OVERLAP_NORTH = new IntegerProperty("wmsplugin.url.overlapNorth", 4);
-
-	WMSLayer wmsLayer;
-	static JMenu wmsJMenu;
-
-	static ArrayList<WMSInfo> wmsList = new ArrayList<WMSInfo>();
-	static TreeMap<String,String> wmsListDefault = new TreeMap<String,String>();
-
-	// remember state of menu item to restore on changed preferences
-	static private boolean menuEnabled = false;
-
-	/***************************************************************
-	 * Remote control initialization:
-	 * If you need remote control in some other plug-in
-	 * copy this stuff and the call to initRemoteControl below
-	 * and replace the RequestHandler subclass in initRemoteControl
-	 ***************************************************************/
-
-	/** name of remote control plugin */
-	private static final String REMOTECONTROL_NAME = "remotecontrol";
-
-	/* if necessary change these version numbers to ensure compatibility */
-
-	/** RemoteControlPlugin older than this SVN revision is not compatible */
-	static final int REMOTECONTROL_MIN_REVISION = 22734;
-	/** WMSPlugin needs this specific API major version of RemoteControlPlugin */
-	static final int REMOTECONTROL_NEED_API_MAJOR = 1;
-	/** All API minor versions starting from this should be compatible */
-	static final int REMOTECONTROL_MIN_API_MINOR = 0;
-
-	/* these fields will contain state and version of remote control plug-in */
-	boolean remoteControlAvailable = false;
-	boolean remoteControlCompatible = true;
-	boolean remoteControlInitialized = false;
-	int remoteControlRevision = 0;
-	int remoteControlApiMajor = 0;
-	int remoteControlApiMinor = 0;
-	int remoteControlProtocolMajor = 0;
-	int remoteControlProtocolMinor = 0;
-
-	/**
-	 * Check if remote control plug-in is available and if its version is
-	 * high enough and register remote control command for this plug-in.
-	 */
-	private void initRemoteControl() {
-		for(PluginProxy pp: PluginHandler.pluginList)
-		{
-			PluginInformation info = pp.getPluginInformation();
-			if(REMOTECONTROL_NAME.equals(info.name))
-			{
-				remoteControlAvailable = true;
-				remoteControlRevision = Integer.parseInt(info.version);
-				if(REMOTECONTROL_MIN_REVISION > remoteControlRevision)
-				{
-					remoteControlCompatible = false;
-				}
-			}
-		}
-
-		if(remoteControlAvailable && remoteControlCompatible)
-		{
-			Plugin plugin =
-				(Plugin) PluginHandler.getPlugin(REMOTECONTROL_NAME);
-			try {
-				Method method;
-				method = plugin.getClass().getMethod("getVersion");
-				Object obj = method.invoke(plugin);
-				if((obj != null ) && (obj instanceof int[]))
-				{
-					int[] versions = (int[]) obj;
-					if(versions.length >= 4)
-					{
-						remoteControlApiMajor = versions[0];
-						remoteControlApiMinor = versions[1];
-						remoteControlProtocolMajor = versions[2];
-						remoteControlProtocolMinor = versions[3];
-					}
-				}
-
-				if((remoteControlApiMajor != REMOTECONTROL_NEED_API_MAJOR) ||
-						(remoteControlApiMinor < REMOTECONTROL_MIN_API_MINOR))
-				{
-					remoteControlCompatible = false;
-				}
-				if(remoteControlCompatible)
-				{
-					System.out.println(this.getClass().getSimpleName() + ": initializing remote control");
-					method = plugin.getClass().getMethod("addRequestHandler", String.class, Class.class);
-					// replace command and class when you copy this to some other plug-in
-					// for compatibility with old remotecontrol add leading "/"
-					method.invoke(plugin, "/" + WMSRemoteHandler.command, WMSRemoteHandler.class);
-					remoteControlInitialized = true;
-				}
-			} catch (SecurityException e) {
-				e.printStackTrace();
-			} catch (NoSuchMethodException e) {
-				e.printStackTrace();
-			} catch (IllegalArgumentException e) {
-				e.printStackTrace();
-			} catch (IllegalAccessException e) {
-				e.printStackTrace();
-			} catch (InvocationTargetException e) {
-				e.printStackTrace();
-			}
-		}
-		if(remoteControlAvailable)
-		{
-			String msg = null;
-
-			if(remoteControlCompatible)
-			{
-				if(!remoteControlInitialized)
-				{
-					msg  = tr("Could not initialize remote control.");
-				}
-			}
-			else
-			{
-				msg  = tr("Remote control plugin is not compatible with {0}.",
-						this.getClass().getSimpleName());
-			}
-
-			if(msg != null)
-			{
-				String additionalMessage = tr("{0} will work but remote control for this plugin is disabled.\n"
-						+ "You should update the plugins.",
-						this.getClass().getSimpleName());
-				String versionMessage = tr("Current version of \"{1}\": {2}, internal version {3}. "
-						+ "Need version {4}, internal version {5}.\n"
-						+ "If updating the plugins does not help report a bug for \"{0}\".",
-						this.getClass().getSimpleName(),
-						REMOTECONTROL_NAME,
-						""+remoteControlRevision,
-						(remoteControlApiMajor != 0) ?
-								""+remoteControlApiMajor+"."+remoteControlApiMinor :
-									tr("unknown"),
-									""+REMOTECONTROL_MIN_REVISION,
-									""+REMOTECONTROL_NEED_API_MAJOR+"."+REMOTECONTROL_MIN_API_MINOR );
-
-				String title = tr("{0}: Problem with remote control",
-						this.getClass().getSimpleName());
-
-				System.out.println(this.getClass().getSimpleName() + ": " +
-						msg + "\n" + versionMessage);
-
-				JOptionPane.showMessageDialog(
-						Main.parent,
-						msg + "\n" + additionalMessage,
-						title,
-						JOptionPane.WARNING_MESSAGE
-				);
-			}
-		}
-
-		if(!remoteControlAvailable) {
-			System.out.println(this.getClass().getSimpleName() + ": remote control not available");
-		}
-	}
-
-	/***************************************
-	 * end of remote control initialization
-	 ***************************************/
-
-	protected void initExporterAndImporter() {
-		ExtensionFileFilter.exporters.add(new WMSLayerExporter());
-		ExtensionFileFilter.importers.add(new WMSLayerImporter());
-	}
-
-	public WMSPlugin(PluginInformation info) {
-		super(info);
-		/*
-		System.out.println("constructor " + this.getClass().getName() + " (" + info.name +
-				" v " + info.version + " stage " + info.stage + ")");
-		 */
-		refreshMenu();
-		cache.setExpire(CacheFiles.EXPIRE_MONTHLY, false);
-		cache.setMaxSize(70, false);
-		initExporterAndImporter();
-		initRemoteControl();
-	}
-
-	// this parses the preferences settings. preferences for the wms plugin have to
-	// look like this:
-	// wmsplugin.1.name=Landsat
-	// wmsplugin.1.url=http://and.so.on/
-
-	@Override
-	public void copy(String from, String to) throws FileNotFoundException, IOException
-	{
-		File pluginDir = new File(getPrefsPath());
-		if (!pluginDir.exists())
-			pluginDir.mkdirs();
-		FileOutputStream out = new FileOutputStream(getPrefsPath() + to);
-		InputStream in = WMSPlugin.class.getResourceAsStream(from);
-		byte[] buffer = new byte[8192];
-		for(int len = in.read(buffer); len > 0; len = in.read(buffer))
-			out.write(buffer, 0, len);
-		in.close();
-		out.close();
-	}
-
-
-	public static void refreshMenu() {
-		wmsList.clear();
-		Map<String,String> prefs = Main.pref.getAllPrefix("wmsplugin.url.");
-
-		TreeSet<String> keys = new TreeSet<String>(prefs.keySet());
-
-		// And then the names+urls of WMS servers
-		int prefid = 0;
-		String name = null;
-		String url = null;
-		String cookies = "";
-		int lastid = -1;
-		for (String key : keys) {
-			String[] elements = key.split("\\.");
-			if (elements.length != 4) continue;
-			try {
-				prefid = Integer.parseInt(elements[2]);
-			} catch(NumberFormatException e) {
-				continue;
-			}
-			if (prefid != lastid) {
-				name = url = null; lastid = prefid;
-			}
-			if (elements[3].equals("name"))
-				name = prefs.get(key);
-			else if (elements[3].equals("url"))
-			{
-				/* FIXME: Remove the if clause after some time */
-				if(!prefs.get(key).startsWith("yahoo:")) /* legacy stuff */
-					url = prefs.get(key);
-			}
-			else if (elements[3].equals("cookies"))
-				cookies = prefs.get(key);
-			if (name != null && url != null)
-				wmsList.add(new WMSInfo(name, url, cookies, prefid));
-		}
-		String source = "http://svn.openstreetmap.org/applications/editors/josm/plugins/wmsplugin/sources.cfg";
-		try
-		{
-			MirroredInputStream s = new MirroredInputStream(source,
-					Main.pref.getPreferencesDir() + "plugins/wmsplugin/", -1);
-			InputStreamReader r;
-			try
-			{
-				r = new InputStreamReader(s, "UTF-8");
-			}
-			catch (UnsupportedEncodingException e)
-			{
-				r = new InputStreamReader(s);
-			}
-			BufferedReader reader = new BufferedReader(r);
-			String line;
-			while((line = reader.readLine()) != null)
-			{
-				String val[] = line.split(";");
-				if(!line.startsWith("#") && val.length == 3)
-					setDefault("true".equals(val[0]), tr(val[1]), val[2]);
-			}
-		}
-		catch (IOException e)
-		{
-		}
-
-		Collections.sort(wmsList);
-		MainMenu menu = Main.main.menu;
-
-		if (wmsJMenu == null)
-			wmsJMenu = menu.addMenu(marktr("WMS"), KeyEvent.VK_W, menu.defaultMenuPos, ht("/Plugin/WMS"));
-		else
-			wmsJMenu.removeAll();
-
-		// for each configured WMSInfo, add a menu entry.
-		for (final WMSInfo u : wmsList) {
-			wmsJMenu.add(new JMenuItem(new WMSDownloadAction(u)));
-		}
-		wmsJMenu.addSeparator();
-		wmsJMenu.add(new JMenuItem(new Map_Rectifier_WMSmenuAction()));
-
-		wmsJMenu.addSeparator();
-		wmsJMenu.add(new JMenuItem(new
-				JosmAction(tr("Blank Layer"), "blankmenu", tr("Open a blank WMS layer to load data from a file"), null, false) {
-			public void actionPerformed(ActionEvent ev) {
-				Main.main.addLayer(new WMSLayer());
-			}
-		}));
-		setEnabledAll(menuEnabled);
-	}
-
-	/* add a default entry in case the URL does not yet exist */
-	private static void setDefault(Boolean force, String name, String url)
-	{
-		String testurl = url.replaceAll("=", "_");
-		wmsListDefault.put(name, url);
-
-		if(force && !Main.pref.getBoolean("wmsplugin.default."+testurl))
-		{
-			Main.pref.put("wmsplugin.default."+testurl, true);
-			int id = -1;
-			for(WMSInfo i : wmsList)
-			{
-				if(url.equals(i.url))
-					return;
-				if(i.prefid > id)
-					id = i.prefid;
-			}
-			WMSInfo newinfo = new WMSInfo(name, url, id+1);
-			newinfo.save();
-			wmsList.add(newinfo);
-		}
-	}
-
-	public static Grabber getGrabber(MapView mv, WMSLayer layer){
-		if(layer.baseURL.startsWith("html:"))
-			return new HTMLGrabber(mv, layer, cache);
-		else
-			return new WMSGrabber(mv, layer, cache);
-	}
-
-	private static void setEnabledAll(boolean isEnabled) {
-		for(int i=0; i < wmsJMenu.getItemCount(); i++) {
-			JMenuItem item = wmsJMenu.getItem(i);
-
-			if(item != null) item.setEnabled(isEnabled);
-		}
-		menuEnabled = isEnabled;
-	}
-
-	@Override
-	public void mapFrameInitialized(MapFrame oldFrame, MapFrame newFrame) {
-		if (oldFrame==null && newFrame!=null) {
-			setEnabledAll(true);
-			Main.map.addMapMode(new IconToggleButton
-					(new WMSAdjustAction(Main.map)));
-		} else if (oldFrame!=null && newFrame==null ) {
-			setEnabledAll(false);
-		}
-	}
-
-	@Override
-	public PreferenceSetting getPreferenceSetting() {
-		return new WMSPreferenceEditor();
-	}
-
-	static public String getPrefsPath()
-	{
-		return Main.pref.getPluginsDirectory().getPath() + "/wmsplugin/";
-	}
+    CacheFiles cache = new CacheFiles("wmsplugin");
+
+    public final IntegerProperty PROP_SIMULTANEOUS_CONNECTIONS = new IntegerProperty("wmsplugin.simultaneousConnections", 3);
+    public final BooleanProperty PROP_OVERLAP = new BooleanProperty("wmsplugin.url.overlap", false);
+    public final IntegerProperty PROP_OVERLAP_EAST = new IntegerProperty("wmsplugin.url.overlapEast", 14);
+    public final IntegerProperty PROP_OVERLAP_NORTH = new IntegerProperty("wmsplugin.url.overlapNorth", 4);
+
+    JMenu wmsJMenu;
+    static WMSPlugin instance;
+
+    public WMSLayerInfo info = new WMSLayerInfo();
+
+    // remember state of menu item to restore on changed preferences
+    private boolean menuEnabled = false;
+
+    /***************************************************************
+     * Remote control initialization:
+     * If you need remote control in some other plug-in
+     * copy this stuff and the call to initRemoteControl below
+     * and replace the RequestHandler subclass in initRemoteControl
+     ***************************************************************/
+
+    /** name of remote control plugin */
+    private final String REMOTECONTROL_NAME = "remotecontrol";
+
+    /* if necessary change these version numbers to ensure compatibility */
+
+    /** RemoteControlPlugin older than this SVN revision is not compatible */
+    final int REMOTECONTROL_MIN_REVISION = 22734;
+    /** WMSPlugin needs this specific API major version of RemoteControlPlugin */
+    final int REMOTECONTROL_NEED_API_MAJOR = 1;
+    /** All API minor versions starting from this should be compatible */
+    final int REMOTECONTROL_MIN_API_MINOR = 0;
+
+    /* these fields will contain state and version of remote control plug-in */
+    boolean remoteControlAvailable = false;
+    boolean remoteControlCompatible = true;
+    boolean remoteControlInitialized = false;
+    int remoteControlRevision = 0;
+    int remoteControlApiMajor = 0;
+    int remoteControlApiMinor = 0;
+    int remoteControlProtocolMajor = 0;
+    int remoteControlProtocolMinor = 0;
+
+    /**
+     * Check if remote control plug-in is available and if its version is
+     * high enough and register remote control command for this plug-in.
+     */
+    private void initRemoteControl() {
+        for(PluginProxy pp: PluginHandler.pluginList)
+        {
+            PluginInformation info = pp.getPluginInformation();
+            if(REMOTECONTROL_NAME.equals(info.name))
+            {
+                remoteControlAvailable = true;
+                remoteControlRevision = Integer.parseInt(info.version);
+                if(REMOTECONTROL_MIN_REVISION > remoteControlRevision)
+                {
+                    remoteControlCompatible = false;
+                }
+            }
+        }
+
+        if(remoteControlAvailable && remoteControlCompatible)
+        {
+            Plugin plugin =
+                (Plugin) PluginHandler.getPlugin(REMOTECONTROL_NAME);
+            try {
+                Method method;
+                method = plugin.getClass().getMethod("getVersion");
+                Object obj = method.invoke(plugin);
+                if((obj != null ) && (obj instanceof int[]))
+                {
+                    int[] versions = (int[]) obj;
+                    if(versions.length >= 4)
+                    {
+                        remoteControlApiMajor = versions[0];
+                        remoteControlApiMinor = versions[1];
+                        remoteControlProtocolMajor = versions[2];
+                        remoteControlProtocolMinor = versions[3];
+                    }
+                }
+
+                if((remoteControlApiMajor != REMOTECONTROL_NEED_API_MAJOR) ||
+                        (remoteControlApiMinor < REMOTECONTROL_MIN_API_MINOR))
+                {
+                    remoteControlCompatible = false;
+                }
+                if(remoteControlCompatible)
+                {
+                    System.out.println(this.getClass().getSimpleName() + ": initializing remote control");
+                    method = plugin.getClass().getMethod("addRequestHandler", String.class, Class.class);
+                    // replace command and class when you copy this to some other plug-in
+                    // for compatibility with old remotecontrol add leading "/"
+                    method.invoke(plugin, "/" + WMSRemoteHandler.command, WMSRemoteHandler.class);
+                    remoteControlInitialized = true;
+                }
+            } catch (SecurityException e) {
+                e.printStackTrace();
+            } catch (NoSuchMethodException e) {
+                e.printStackTrace();
+            } catch (IllegalArgumentException e) {
+                e.printStackTrace();
+            } catch (IllegalAccessException e) {
+                e.printStackTrace();
+            } catch (InvocationTargetException e) {
+                e.printStackTrace();
+            }
+        }
+        if(remoteControlAvailable)
+        {
+            String msg = null;
+
+            if(remoteControlCompatible)
+            {
+                if(!remoteControlInitialized)
+                {
+                    msg  = tr("Could not initialize remote control.");
+                }
+            }
+            else
+            {
+                msg  = tr("Remote control plugin is not compatible with {0}.",
+                        this.getClass().getSimpleName());
+            }
+
+            if(msg != null)
+            {
+                String additionalMessage = tr("{0} will work but remote control for this plugin is disabled.\n"
+                        + "You should update the plugins.",
+                        this.getClass().getSimpleName());
+                String versionMessage = tr("Current version of \"{1}\": {2}, internal version {3}. "
+                        + "Need version {4}, internal version {5}.\n"
+                        + "If updating the plugins does not help report a bug for \"{0}\".",
+                        this.getClass().getSimpleName(),
+                        REMOTECONTROL_NAME,
+                        ""+remoteControlRevision,
+                        (remoteControlApiMajor != 0) ?
+                                ""+remoteControlApiMajor+"."+remoteControlApiMinor :
+                                    tr("unknown"),
+                                    ""+REMOTECONTROL_MIN_REVISION,
+                                    ""+REMOTECONTROL_NEED_API_MAJOR+"."+REMOTECONTROL_MIN_API_MINOR );
+
+                String title = tr("{0}: Problem with remote control",
+                        this.getClass().getSimpleName());
+
+                System.out.println(this.getClass().getSimpleName() + ": " +
+                        msg + "\n" + versionMessage);
+
+                JOptionPane.showMessageDialog(
+                        Main.parent,
+                        msg + "\n" + additionalMessage,
+                        title,
+                        JOptionPane.WARNING_MESSAGE
+                );
+            }
+        }
+
+        if(!remoteControlAvailable) {
+            System.out.println(this.getClass().getSimpleName() + ": remote control not available");
+        }
+    }
+
+    /***************************************
+     * end of remote control initialization
+     ***************************************/
+
+    protected void initExporterAndImporter() {
+        ExtensionFileFilter.exporters.add(new WMSLayerExporter());
+        ExtensionFileFilter.importers.add(new WMSLayerImporter());
+    }
+
+    public WMSPlugin(PluginInformation info) {
+        super(info);
+        instance = this;
+        this.info.load();
+        refreshMenu();
+        cache.setExpire(CacheFiles.EXPIRE_MONTHLY, false);
+        cache.setMaxSize(70, false);
+        initExporterAndImporter();
+        initRemoteControl();
+    }
+
+    public void addLayer(WMSInfo info) {
+        this.info.add(info);
+        this.info.save();
+        refreshMenu();
+    }
+
+    public void refreshMenu() {
+        MainMenu menu = Main.main.menu;
+
+        if (wmsJMenu == null)
+            wmsJMenu = menu.addMenu(marktr("WMS"), KeyEvent.VK_W, menu.defaultMenuPos, ht("/Plugin/WMS"));
+        else
+            wmsJMenu.removeAll();
+
+        // for each configured WMSInfo, add a menu entry.
+        for (final WMSInfo u : info.layers) {
+            wmsJMenu.add(new JMenuItem(new WMSDownloadAction(u)));
+        }
+        wmsJMenu.addSeparator();
+        wmsJMenu.add(new JMenuItem(new Map_Rectifier_WMSmenuAction()));
+
+        wmsJMenu.addSeparator();
+        wmsJMenu.add(new JMenuItem(new
+                JosmAction(tr("Blank Layer"), "blankmenu", tr("Open a blank WMS layer to load data from a file"), null, false) {
+            public void actionPerformed(ActionEvent ev) {
+                Main.main.addLayer(new WMSLayer());
+            }
+        }));
+        setEnabledAll(menuEnabled);
+    }
+
+    public Grabber getGrabber(MapView mv, WMSLayer layer){
+        if(layer.info.html)
+            return new HTMLGrabber(mv, layer, cache);
+        else
+            return new WMSGrabber(mv, layer, cache);
+    }
+
+    private void setEnabledAll(boolean isEnabled) {
+        for(int i=0; i < wmsJMenu.getItemCount(); i++) {
+            JMenuItem item = wmsJMenu.getItem(i);
+
+            if(item != null) item.setEnabled(isEnabled);
+        }
+        menuEnabled = isEnabled;
+    }
+
+    @Override
+    public void mapFrameInitialized(MapFrame oldFrame, MapFrame newFrame) {
+        if (oldFrame==null && newFrame!=null) {
+            setEnabledAll(true);
+            Main.map.addMapMode(new IconToggleButton
+                    (new WMSAdjustAction(Main.map)));
+        } else if (oldFrame!=null && newFrame==null ) {
+            setEnabledAll(false);
+        }
+    }
+
+    @Override
+    public PreferenceSetting getPreferenceSetting() {
+        return new WMSPreferenceEditor();
+    }
+
+    @Override
+    public String getPluginDir()
+    {
+        return new File(Main.pref.getPluginsDirectory(), "wmsplugin").getPath();
+    }
 }
diff --git a/wmsplugin/src/wmsplugin/WMSPreferenceEditor.java b/wmsplugin/src/wmsplugin/WMSPreferenceEditor.java
index aa73c29..7e2af13 100644
--- a/wmsplugin/src/wmsplugin/WMSPreferenceEditor.java
+++ b/wmsplugin/src/wmsplugin/WMSPreferenceEditor.java
@@ -1,19 +1,24 @@
 package wmsplugin;
 
 import static org.openstreetmap.josm.tools.I18n.tr;
+import static org.openstreetmap.josm.tools.I18n.trc;
 
 import java.awt.Dimension;
 import java.awt.FlowLayout;
 import java.awt.GridBagConstraints;
 import java.awt.event.ActionEvent;
 import java.awt.event.ActionListener;
-import java.util.HashMap;
-import java.util.Map;
+import java.awt.event.MouseEvent;
+import java.io.IOException;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.util.Locale;
 
 import javax.swing.Box;
 import javax.swing.JButton;
 import javax.swing.JCheckBox;
 import javax.swing.JComboBox;
+import javax.swing.JEditorPane;
 import javax.swing.JLabel;
 import javax.swing.JOptionPane;
 import javax.swing.JPanel;
@@ -22,6 +27,7 @@ import javax.swing.JSpinner;
 import javax.swing.JTable;
 import javax.swing.SpinnerNumberModel;
 import javax.swing.table.DefaultTableModel;
+import javax.swing.table.TableColumnModel;
 
 import org.openstreetmap.josm.Main;
 import org.openstreetmap.josm.gui.preferences.PreferenceSetting;
@@ -29,9 +35,8 @@ import org.openstreetmap.josm.gui.preferences.PreferenceTabbedPane;
 import org.openstreetmap.josm.tools.GBC;
 
 public class WMSPreferenceEditor implements PreferenceSetting {
-    private DefaultTableModel model;
+    private WMSLayerTableModel model;
     private JComboBox browser;
-    private HashMap<Integer, WMSInfo> oldValues = new HashMap<Integer, WMSInfo>();
 
     JCheckBox overlapCheckBox;
     JSpinner spinEast;
@@ -39,41 +44,49 @@ public class WMSPreferenceEditor implements PreferenceSetting {
     JSpinner spinSimConn;
     JCheckBox remoteCheckBox;
     boolean allowRemoteControl = true;
+    WMSPlugin plugin = WMSPlugin.instance;
 
     public void addGui(final PreferenceTabbedPane gui) {
         JPanel p = gui.createPreferenceTab("wms", tr("WMS Plugin Preferences"), tr("Modify list of WMS servers displayed in the WMS plugin menu"));
 
-        model = new DefaultTableModel(new String[]{tr("Menu Name"), tr("WMS URL")}, 0);
-        final JTable list = new JTable(model);
+        model = new WMSLayerTableModel();
+        final JTable list = new JTable(model) {
+            @Override
+            public String getToolTipText(MouseEvent e) {
+                java.awt.Point p = e.getPoint();
+                return (String) model.getValueAt(rowAtPoint(p), columnAtPoint(p));
+            }
+        };
         JScrollPane scroll = new JScrollPane(list);
         p.add(scroll, GBC.eol().fill(GridBagConstraints.BOTH));
-        scroll.setPreferredSize(new Dimension(200,200));
-
-        for (WMSInfo i : WMSPlugin.wmsList) {
-            oldValues.put(i.prefid, i);
-            model.addRow(new String[]{i.name, i.url});
-        }
+        scroll.setPreferredSize(new Dimension(200, 200));
 
-        final DefaultTableModel modeldef = new DefaultTableModel(
-                new String[]{tr("Menu Name (Default)"), tr("WMS URL (Default)")}, 0);
-        final JTable listdef = new JTable(modeldef){
+        final WMSDefaultLayerTableModel modeldef = new WMSDefaultLayerTableModel();
+        final JTable listdef = new JTable(modeldef) {
             @Override
-            public boolean isCellEditable(int row,int column){return false;}
+            public String getToolTipText(MouseEvent e) {
+                java.awt.Point p = e.getPoint();
+                return (String) modeldef.getValueAt(rowAtPoint(p), columnAtPoint(p));
+            }
         };
         JScrollPane scrolldef = new JScrollPane(listdef);
         // scrolldef is added after the buttons so it's clearer the buttons
         // control the top list and not the default one
-        scrolldef.setPreferredSize(new Dimension(200,200));
+        scrolldef.setPreferredSize(new Dimension(200, 200));
 
-        for (Map.Entry<String,String> i : WMSPlugin.wmsListDefault.entrySet()) {
-            modeldef.addRow(new String[]{i.getKey(), i.getValue()});
-        }
+        TableColumnModel mod = listdef.getColumnModel();
+        mod.getColumn(1).setPreferredWidth(800);
+        mod.getColumn(0).setPreferredWidth(200);
+        mod = list.getColumnModel();
+        mod.getColumn(2).setPreferredWidth(50);
+        mod.getColumn(1).setPreferredWidth(800);
+        mod.getColumn(0).setPreferredWidth(200);
 
         JPanel buttonPanel = new JPanel(new FlowLayout());
 
         JButton add = new JButton(tr("Add"));
-        buttonPanel.add(add, GBC.std().insets(0,5,0,0));
-        add.addActionListener(new ActionListener(){
+        buttonPanel.add(add, GBC.std().insets(0, 5, 0, 0));
+        add.addActionListener(new ActionListener() {
             public void actionPerformed(ActionEvent e) {
                 AddWMSLayerPanel p = new AddWMSLayerPanel();
                 int answer = JOptionPane.showConfirmDialog(
@@ -81,19 +94,18 @@ public class WMSPreferenceEditor implements PreferenceSetting {
                         tr("Add WMS URL"),
                         JOptionPane.OK_CANCEL_OPTION);
                 if (answer == JOptionPane.OK_OPTION) {
-                    model.addRow(new String[]{p.getUrlName(), p.getUrl()});
+                    model.addRow(new WMSInfo(p.getUrlName(), p.getUrl()));
                 }
             }
         });
 
         JButton delete = new JButton(tr("Delete"));
-        buttonPanel.add(delete, GBC.std().insets(0,5,0,0));
-        delete.addActionListener(new ActionListener(){
+        buttonPanel.add(delete, GBC.std().insets(0, 5, 0, 0));
+        delete.addActionListener(new ActionListener() {
             public void actionPerformed(ActionEvent e) {
                 if (list.getSelectedRow() == -1)
                     JOptionPane.showMessageDialog(gui, tr("Please select the row to delete."));
-                else
-                {
+                else {
                     Integer i;
                     while ((i = list.getSelectedRow()) != -1)
                         model.removeRow(i);
@@ -102,8 +114,8 @@ public class WMSPreferenceEditor implements PreferenceSetting {
         });
 
         JButton copy = new JButton(tr("Copy Selected Default(s)"));
-        buttonPanel.add(copy, GBC.std().insets(0,5,0,0));
-        copy.addActionListener(new ActionListener(){
+        buttonPanel.add(copy, GBC.std().insets(0, 5, 0, 0));
+        copy.addActionListener(new ActionListener() {
             public void actionPerformed(ActionEvent e) {
                 int[] lines = listdef.getSelectedRows();
                 if (lines.length == 0) {
@@ -111,20 +123,17 @@ public class WMSPreferenceEditor implements PreferenceSetting {
                             gui,
                             tr("Please select at least one row to copy."),
                             tr("Information"),
-                            JOptionPane.INFORMATION_MESSAGE
-                    );
+                            JOptionPane.INFORMATION_MESSAGE);
                     return;
                 }
 
-                outer: for(int i = 0; i < lines.length; i++) {
-                    String c1 = modeldef.getValueAt(lines[i], 0).toString();
-                    String c2 = modeldef.getValueAt(lines[i], 1).toString();
+                outer: for (int i = 0; i < lines.length; i++) {
+                    WMSInfo info = modeldef.getRow(lines[i]);
 
                     // Check if an entry with exactly the same values already
                     // exists
-                    for(int j = 0; j < model.getRowCount(); j++) {
-                        if(c1.equals(model.getValueAt(j, 0).toString())
-                                && c2.equals(model.getValueAt(j, 1).toString())) {
+                    for (int j = 0; j < model.getRowCount(); j++) {
+                        if (info.equalsBaseValues(model.getRow(j))) {
                             // Select the already existing row so the user has
                             // some feedback in case an entry exists
                             list.getSelectionModel().setSelectionInterval(j, j);
@@ -133,7 +142,12 @@ public class WMSPreferenceEditor implements PreferenceSetting {
                         }
                     }
 
-                    model.addRow(new String[] {c1, c2});
+                    if (info.eulaAcceptanceRequired != null) {
+                        if (!confirmeEulaAcceptance(gui, info.eulaAcceptanceRequired))
+                            continue outer;
+                    }
+
+                    model.addRow(new WMSInfo(info));
                     int lastLine = model.getRowCount() - 1;
                     list.getSelectionModel().setSelectionInterval(lastLine, lastLine);
                     list.scrollRectToVisible(list.getCellRect(lastLine, 0, true));
@@ -144,26 +158,26 @@ public class WMSPreferenceEditor implements PreferenceSetting {
         p.add(buttonPanel);
         p.add(Box.createHorizontalGlue(), GBC.eol().fill(GridBagConstraints.HORIZONTAL));
         // Add default item list
-        p.add(scrolldef, GBC.eol().insets(0,5,0,0).fill(GridBagConstraints.BOTH));
+        p.add(scrolldef, GBC.eol().insets(0, 5, 0, 0).fill(GridBagConstraints.BOTH));
 
-        browser = new JComboBox(new String[]{
+        browser = new JComboBox(new String[] {
                 "webkit-image {0}",
                 "gnome-web-photo --mode=photo --format=png {0} /dev/stdout",
                 "gnome-web-photo-fixed {0}",
-        "webkit-image-gtk {0}"});
+                "webkit-image-gtk {0}"});
         browser.setEditable(true);
         browser.setSelectedItem(Main.pref.get("wmsplugin.browser", "webkit-image {0}"));
         p.add(new JLabel(tr("Downloader:")), GBC.eol().fill(GridBagConstraints.HORIZONTAL));
         p.add(browser);
 
-        //Overlap
+        // Overlap
         p.add(Box.createHorizontalGlue(), GBC.eol().fill(GridBagConstraints.HORIZONTAL));
 
-        overlapCheckBox = new JCheckBox(tr("Overlap tiles"), WMSPlugin.PROP_OVERLAP.get() );
+        overlapCheckBox = new JCheckBox(tr("Overlap tiles"), plugin.PROP_OVERLAP.get());
         JLabel labelEast = new JLabel(tr("% of east:"));
         JLabel labelNorth = new JLabel(tr("% of north:"));
-        spinEast = new JSpinner(new SpinnerNumberModel(WMSPlugin.PROP_OVERLAP_EAST.get(), 1, 50, 1));
-        spinNorth = new JSpinner(new SpinnerNumberModel(WMSPlugin.PROP_OVERLAP_NORTH.get(), 1, 50, 1));
+        spinEast = new JSpinner(new SpinnerNumberModel(plugin.PROP_OVERLAP_EAST.get(), 1, 50, 1));
+        spinNorth = new JSpinner(new SpinnerNumberModel(plugin.PROP_OVERLAP_NORTH.get(), 1, 50, 1));
 
         JPanel overlapPanel = new JPanel(new FlowLayout());
         overlapPanel.add(overlapCheckBox);
@@ -177,106 +191,197 @@ public class WMSPreferenceEditor implements PreferenceSetting {
         // Simultaneous connections
         p.add(Box.createHorizontalGlue(), GBC.eol().fill(GridBagConstraints.HORIZONTAL));
         JLabel labelSimConn = new JLabel(tr("Simultaneous connections"));
-        spinSimConn = new JSpinner(new SpinnerNumberModel(WMSPlugin.PROP_SIMULTANEOUS_CONNECTIONS.get(), 1, 30, 1));
+        spinSimConn = new JSpinner(new SpinnerNumberModel(plugin.PROP_SIMULTANEOUS_CONNECTIONS.get(), 1, 30, 1));
         JPanel overlapPanelSimConn = new JPanel(new FlowLayout());
         overlapPanelSimConn.add(labelSimConn);
         overlapPanelSimConn.add(spinSimConn);
         p.add(overlapPanelSimConn, GBC.eol().fill(GridBagConstraints.HORIZONTAL));
 
-
         allowRemoteControl = Main.pref.getBoolean("wmsplugin.remotecontrol", true);
-        remoteCheckBox = new JCheckBox(tr("Allow remote control (reqires remotecontrol plugin)"), allowRemoteControl );
+        remoteCheckBox = new JCheckBox(tr("Allow remote control (reqires remotecontrol plugin)"), allowRemoteControl);
         JPanel remotePanel = new JPanel(new FlowLayout());
         remotePanel.add(remoteCheckBox);
 
         p.add(remotePanel);
-
     }
 
     public boolean ok() {
-        boolean change = false;
-        for (int i = 0; i < model.getRowCount(); ++i) {
-            String name = model.getValueAt(i,0).toString();
-            String url = model.getValueAt(i,1).toString();
-
-            WMSInfo origValue = oldValues.get(i);
-            if (origValue == null)
-            {
-                new WMSInfo(name, url, i).save();
-                change = true;
-            }
-            else
-            {
-                if (!origValue.name.equals(name) || !origValue.url.equals(url))
-                {
-                    origValue.name = name;
-                    origValue.url = url;
-                    origValue.save();
-                    change = true;
-                }
-                oldValues.remove(i);
-            }
-        }
+        plugin.info.save();
+        plugin.refreshMenu();
 
-        // using null values instead of empty string really deletes
-        // the preferences entry
-        for (WMSInfo i : oldValues.values())
-        {
-            i.url = null;
-            i.name = null;
-            i.save();
-            change = true;
-        }
-
-        if (change) WMSPlugin.refreshMenu();
-
-        WMSPlugin.PROP_OVERLAP.put(overlapCheckBox.getModel().isSelected());
-        WMSPlugin.PROP_OVERLAP_EAST.put((Integer) spinEast.getModel().getValue());
-        WMSPlugin.PROP_OVERLAP_NORTH.put((Integer) spinNorth.getModel().getValue());
-        WMSPlugin.PROP_SIMULTANEOUS_CONNECTIONS.put((Integer) spinSimConn.getModel().getValue());
+        plugin.PROP_OVERLAP.put(overlapCheckBox.getModel().isSelected());
+        plugin.PROP_OVERLAP_EAST.put((Integer) spinEast.getModel().getValue());
+        plugin.PROP_OVERLAP_NORTH.put((Integer) spinNorth.getModel().getValue());
+        plugin.PROP_SIMULTANEOUS_CONNECTIONS.put((Integer) spinSimConn.getModel().getValue());
         allowRemoteControl = remoteCheckBox.getModel().isSelected();
 
         Main.pref.put("wmsplugin.browser", browser.getEditor().getItem().toString());
 
-        Main.pref.put("wmsplugin.remotecontrol",    String.valueOf(allowRemoteControl));
+        Main.pref.put("wmsplugin.remotecontrol", String.valueOf(allowRemoteControl));
         return false;
     }
 
     /**
      * Updates a server URL in the preferences dialog. Used by other plugins.
      *
-     * @param server The server name
-     * @param url The server URL
+     * @param server
+     *            The server name
+     * @param url
+     *            The server URL
      */
-    public void setServerUrl(String server, String url)
-    {
-        for (int i = 0; i < model.getRowCount(); i++)
-        {
-            if( server.equals(model.getValueAt(i,0).toString()) )
-            {
+    public void setServerUrl(String server, String url) {
+        for (int i = 0; i < model.getRowCount(); i++) {
+            if (server.equals(model.getValueAt(i, 0).toString())) {
                 model.setValueAt(url, i, 1);
                 return;
             }
         }
-        model.addRow(new String[]{server, url});
+        model.addRow(new String[] { server, url });
     }
 
     /**
      * Gets a server URL in the preferences dialog. Used by other plugins.
      *
-     * @param server The server name
+     * @param server
+     *            The server name
      * @return The server URL
      */
-    public String getServerUrl(String server)
-    {
-        for (int i = 0; i < model.getRowCount(); i++)
-        {
-            if( server.equals(model.getValueAt(i,0).toString()) )
-            {
-                return model.getValueAt(i,1).toString();
+    public String getServerUrl(String server) {
+        for (int i = 0; i < model.getRowCount(); i++) {
+            if (server.equals(model.getValueAt(i, 0).toString())) {
+                return model.getValueAt(i, 1).toString();
             }
         }
         return null;
     }
-}
 
+    /**
+     * The table model for the WMS layer
+     *
+     */
+    class WMSLayerTableModel extends DefaultTableModel {
+        public WMSLayerTableModel() {
+            setColumnIdentifiers(new String[] { tr("Menu Name"), tr("WMS URL"), trc("layer", "Zoom") });
+        }
+
+        public WMSInfo getRow(int row) {
+            return plugin.info.layers.get(row);
+        }
+
+        public void addRow(WMSInfo i) {
+            plugin.info.add(i);
+            int p = getRowCount() - 1;
+            fireTableRowsInserted(p, p);
+        }
+
+        @Override
+        public void removeRow(int i) {
+            plugin.info.remove(getRow(i));
+            fireTableRowsDeleted(i, i);
+        }
+
+        @Override
+        public int getRowCount() {
+            return plugin.info.layers.size();
+        }
+
+        @Override
+        public Object getValueAt(int row, int column) {
+            WMSInfo info = plugin.info.layers.get(row);
+            switch (column) {
+            case 0:
+                return info.name;
+            case 1:
+                return info.getFullURL();
+            case 2:
+                return info.pixelPerDegree == 0.0 ? "" : info.pixelPerDegree;
+            }
+            return null;
+        }
+
+        @Override
+        public void setValueAt(Object o, int row, int column) {
+            WMSInfo info = plugin.info.layers.get(row);
+            switch (column) {
+            case 0:
+                info.name = (String) o;
+            case 1:
+                info.setURL((String)o);
+            }
+        }
+
+        @Override
+        public boolean isCellEditable(int row, int column) {
+            return (column != 2);
+        }
+    }
+
+    /**
+     * The table model for the WMS layer
+     *
+     */
+    class WMSDefaultLayerTableModel extends DefaultTableModel {
+        public WMSDefaultLayerTableModel() {
+            setColumnIdentifiers(new String[] { tr("Menu Name (Default)"), tr("WMS URL (Default)") });
+        }
+
+        public WMSInfo getRow(int row) {
+            return plugin.info.defaultLayers.get(row);
+        }
+
+        @Override
+        public int getRowCount() {
+            return plugin.info.defaultLayers.size();
+        }
+
+        @Override
+        public Object getValueAt(int row, int column) {
+            WMSInfo info = plugin.info.defaultLayers.get(row);
+            switch (column) {
+            case 0:
+                return info.name;
+            case 1:
+                return info.getFullURL();
+            }
+            return null;
+        }
+
+        @Override
+        public boolean isCellEditable(int row, int column) {
+            return false;
+        }
+    }
+
+    private boolean confirmeEulaAcceptance(PreferenceTabbedPane gui, String eulaUrl) {
+        URL url = null;
+        try {
+            url = new URL(eulaUrl.replaceAll("\\{lang\\}", Locale.getDefault().toString()));
+            JEditorPane htmlPane = null;
+            try {
+                htmlPane = new JEditorPane(url);
+            } catch (IOException e1) {
+                // give a second chance with a default Locale 'en'
+                try {
+                    url = new URL(eulaUrl.replaceAll("\\{lang\\}", "en"));
+                    htmlPane = new JEditorPane(url);
+                } catch (IOException e2) {
+                    JOptionPane.showMessageDialog(gui ,tr("EULA license URL not available: {0}", eulaUrl));
+                    return false;
+                }
+            }
+            Box box = Box.createVerticalBox();
+            htmlPane.setEditable(false);
+            JScrollPane scrollPane = new JScrollPane(htmlPane);
+            scrollPane.setPreferredSize(new Dimension(400, 400));
+            box.add(scrollPane);
+            int option = JOptionPane.showConfirmDialog(Main.parent, box, tr("Please abort if you are not sure"), JOptionPane.YES_NO_OPTION,
+                    JOptionPane.WARNING_MESSAGE);
+            if (option == JOptionPane.YES_OPTION) {
+                return true;
+            }
+        } catch (MalformedURLException e2) {
+            JOptionPane.showMessageDialog(gui ,tr("Malformed URL for the EULA licence: {0}", eulaUrl));
+        }
+        return false;
+    }
+}
diff --git a/wmsplugin/src/wmsplugin/WMSRemoteHandler.java b/wmsplugin/src/wmsplugin/WMSRemoteHandler.java
index 772eca5..94c7c4b 100644
--- a/wmsplugin/src/wmsplugin/WMSRemoteHandler.java
+++ b/wmsplugin/src/wmsplugin/WMSRemoteHandler.java
@@ -14,97 +14,93 @@ import org.openstreetmap.josm.plugins.remotecontrol.RequestHandlerErrorException
 
 public class WMSRemoteHandler extends RequestHandler {
 
-	public static final String command = "wms";
+    public static final String command = "wms";
 
-	@Override
-	public String getPermissionMessage() {
-		return tr("Remote Control has been asked to load a WMS layer from the following URL:") +
-		"<br>" + args.get("url");
-	}
+    @Override
+    public String getPermissionMessage() {
+        return tr("Remote Control has been asked to load a WMS layer from the following URL:") +
+        "<br>" + args.get("url");
+    }
 
-	@Override
-	public PermissionPrefWithDefault getPermissionPref()
-	{
-		return new PermissionPrefWithDefault(
-				"wmsplugin.remotecontrol",
-				true,
-		"RemoteControl: WMS forbidden by preferences");
-	}
+    @Override
+    public PermissionPrefWithDefault getPermissionPref()
+    {
+        return new PermissionPrefWithDefault(
+                "wmsplugin.remotecontrol",
+                true,
+        "RemoteControl: WMS forbidden by preferences");
+    }
 
-	@Override
-	protected String[] getMandatoryParams()
-	{
-		return new String[] { "url" };
-	}
+    @Override
+    protected String[] getMandatoryParams()
+    {
+        return new String[] { "url" };
+    }
 
-	@Override
-	protected void handleRequest() throws RequestHandlerErrorException {
-		String url = args.get("url");
-		String title = args.get("title");
-		if((title == null) || (title.length() == 0))
-		{
-			title = "remote WMS";
-		}
-		String cookies = args.get("cookies");
-		if(cookies == null)
-		{
-			cookies = "";
-		}
-		WMSLayer wmsLayer = new WMSLayer(title, url, cookies);
-		Main.main.addLayer(wmsLayer);
+    @Override
+    protected void handleRequest() throws RequestHandlerErrorException {
+        String url = args.get("url");
+        String title = args.get("title");
+        if((title == null) || (title.length() == 0))
+        {
+            title = tr("Remote WMS");
+        }
+        String cookies = args.get("cookies");
+        WMSLayer wmsLayer = new WMSLayer(new WMSInfo(title, url, cookies));
+        Main.main.addLayer(wmsLayer);
 
-	}
+    }
 
-	@Override
-	public void parseArgs() {
-		StringTokenizer st = new StringTokenizer(request, "&?");
-		HashMap<String, String> args = new HashMap<String, String>();
-		// skip first element which is the command
-		if(st.hasMoreTokens()) st.nextToken();
-		while (st.hasMoreTokens()) {
-			String param = st.nextToken();
-			int eq = param.indexOf("=");
-			if (eq > -1)
-			{
-				String key = param.substring(0, eq);
-				/* "url=" terminates normal parameters
-				 * and will be handled separately
-				 */
-				if("url".equals(key)) break;
+    @Override
+    public void parseArgs() {
+        StringTokenizer st = new StringTokenizer(request, "&?");
+        HashMap<String, String> args = new HashMap<String, String>();
+        // skip first element which is the command
+        if(st.hasMoreTokens()) st.nextToken();
+        while (st.hasMoreTokens()) {
+            String param = st.nextToken();
+            int eq = param.indexOf("=");
+            if (eq > -1)
+            {
+                String key = param.substring(0, eq);
+                /* "url=" terminates normal parameters
+                 * and will be handled separately
+                 */
+                if("url".equals(key)) break;
 
-				String value = param.substring(eq + 1);
-				// urldecode all normal values
-				try {
-					value = URLDecoder.decode(value, "UTF-8");
-				} catch (UnsupportedEncodingException e) {
-					// TODO Auto-generated catch block
-					e.printStackTrace();
-				}
-				args.put(key,
-						value);
-			}
-		}
-		// url as second or later parameter
-		int urlpos = request.indexOf("&url=");
-		// url as first (and only) parameter
-		if(urlpos < 0) urlpos = request.indexOf("?url=");
-		// url found?
-		if(urlpos >= 0) {
-			// URL value
-			String value = request.substring(urlpos + 5);
-			// allow skipping URL decoding with urldecode=false
-			String urldecode = args.get("urldecode");
-			if((urldecode == null) || (Boolean.valueOf(urldecode) == true))
-			{
-				try {
-					value = URLDecoder.decode(value, "UTF-8");
-				} catch (UnsupportedEncodingException e) {
-					// TODO Auto-generated catch block
-					e.printStackTrace();
-				}
-			}
-			args.put("url", value);
-		}
-		this.args = args;
-	}
+                String value = param.substring(eq + 1);
+                // urldecode all normal values
+                try {
+                    value = URLDecoder.decode(value, "UTF-8");
+                } catch (UnsupportedEncodingException e) {
+                    // TODO Auto-generated catch block
+                    e.printStackTrace();
+                }
+                args.put(key,
+                        value);
+            }
+        }
+        // url as second or later parameter
+        int urlpos = request.indexOf("&url=");
+        // url as first (and only) parameter
+        if(urlpos < 0) urlpos = request.indexOf("?url=");
+        // url found?
+        if(urlpos >= 0) {
+            // URL value
+            String value = request.substring(urlpos + 5);
+            // allow skipping URL decoding with urldecode=false
+            String urldecode = args.get("urldecode");
+            if((urldecode == null) || (Boolean.valueOf(urldecode) == true))
+            {
+                try {
+                    value = URLDecoder.decode(value, "UTF-8");
+                } catch (UnsupportedEncodingException e) {
+                    // TODO Auto-generated catch block
+                    e.printStackTrace();
+                }
+            }
+            args.put("url", value);
+        }
+        this.args = args;
+    }
 }
diff --git a/wmsplugin/src/wmsplugin/WMSRequest.java b/wmsplugin/src/wmsplugin/WMSRequest.java
index 8a5bcda..8934158 100644
--- a/wmsplugin/src/wmsplugin/WMSRequest.java
+++ b/wmsplugin/src/wmsplugin/WMSRequest.java
@@ -5,97 +5,97 @@ import java.awt.image.BufferedImage;
 import wmsplugin.GeorefImage.State;
 
 public class WMSRequest implements Comparable<WMSRequest> {
-	private final int xIndex;
-	private final int yIndex;
-	private final double pixelPerDegree;
-	private final boolean real; // Download even if autodownloading is disabled
-	private int priority;
-	// Result
-	private State state;
-	private BufferedImage image;
-
-	public WMSRequest(int xIndex, int yIndex, double pixelPerDegree, boolean real) {
-		this.xIndex = xIndex;
-		this.yIndex = yIndex;
-		this.pixelPerDegree = pixelPerDegree;
-		this.real = real;
-	}
-
-	public void finish(State state, BufferedImage image) {
-		this.state = state;
-		this.image = image;
-	}
-
-	public int getXIndex() {
-		return xIndex;
-	}
-
-	public int getYIndex() {
-		return yIndex;
-	}
-
-	public double getPixelPerDegree() {
-		return pixelPerDegree;
-	}
-
-	@Override
-	public int hashCode() {
-		final int prime = 31;
-		int result = 1;
-		long temp;
-		temp = Double.doubleToLongBits(pixelPerDegree);
-		result = prime * result + (int) (temp ^ (temp >>> 32));
-		result = prime * result + xIndex;
-		result = prime * result + yIndex;
-		return result;
-	}
-
-	@Override
-	public boolean equals(Object obj) {
-		if (this == obj)
-			return true;
-		if (obj == null)
-			return false;
-		if (getClass() != obj.getClass())
-			return false;
-		WMSRequest other = (WMSRequest) obj;
-		if (Double.doubleToLongBits(pixelPerDegree) != Double
-				.doubleToLongBits(other.pixelPerDegree))
-			return false;
-		if (xIndex != other.xIndex)
-			return false;
-		if (yIndex != other.yIndex)
-			return false;
-		return true;
-	}
-
-	public void setPriority(int priority) {
-		this.priority = priority;
-	}
-
-	public int getPriority() {
-		return priority;
-	}
-
-	public int compareTo(WMSRequest o) {
-		return priority - o.priority;
-	}
-
-	public State getState() {
-		return state;
-	}
-
-	public BufferedImage getImage() {
-		return image;
-	}
-
-	@Override
-	public String toString() {
-		return "WMSRequest [xIndex=" + xIndex + ", yIndex=" + yIndex
-		+ ", pixelPerDegree=" + pixelPerDegree + "]";
-	}
-
-	public boolean isReal() {
-		return real;
-	}
+    private final int xIndex;
+    private final int yIndex;
+    private final double pixelPerDegree;
+    private final boolean real; // Download even if autodownloading is disabled
+    private int priority;
+    // Result
+    private State state;
+    private BufferedImage image;
+
+    public WMSRequest(int xIndex, int yIndex, double pixelPerDegree, boolean real) {
+        this.xIndex = xIndex;
+        this.yIndex = yIndex;
+        this.pixelPerDegree = pixelPerDegree;
+        this.real = real;
+    }
+
+    public void finish(State state, BufferedImage image) {
+        this.state = state;
+        this.image = image;
+    }
+
+    public int getXIndex() {
+        return xIndex;
+    }
+
+    public int getYIndex() {
+        return yIndex;
+    }
+
+    public double getPixelPerDegree() {
+        return pixelPerDegree;
+    }
+
+    @Override
+    public int hashCode() {
+        final int prime = 31;
+        int result = 1;
+        long temp;
+        temp = Double.doubleToLongBits(pixelPerDegree);
+        result = prime * result + (int) (temp ^ (temp >>> 32));
+        result = prime * result + xIndex;
+        result = prime * result + yIndex;
+        return result;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj)
+            return true;
+        if (obj == null)
+            return false;
+        if (getClass() != obj.getClass())
+            return false;
+        WMSRequest other = (WMSRequest) obj;
+        if (Double.doubleToLongBits(pixelPerDegree) != Double
+                .doubleToLongBits(other.pixelPerDegree))
+            return false;
+        if (xIndex != other.xIndex)
+            return false;
+        if (yIndex != other.yIndex)
+            return false;
+        return true;
+    }
+
+    public void setPriority(int priority) {
+        this.priority = priority;
+    }
+
+    public int getPriority() {
+        return priority;
+    }
+
+    public int compareTo(WMSRequest o) {
+        return priority - o.priority;
+    }
+
+    public State getState() {
+        return state;
+    }
+
+    public BufferedImage getImage() {
+        return image;
+    }
+
+    @Override
+    public String toString() {
+        return "WMSRequest [xIndex=" + xIndex + ", yIndex=" + yIndex
+        + ", pixelPerDegree=" + pixelPerDegree + "]";
+    }
+
+    public boolean isReal() {
+        return real;
+    }
 }
diff --git a/wmsplugin/src/wmsplugin/io/WMSLayerExporter.java b/wmsplugin/src/wmsplugin/io/WMSLayerExporter.java
index 3030c04..ef87157 100644
--- a/wmsplugin/src/wmsplugin/io/WMSLayerExporter.java
+++ b/wmsplugin/src/wmsplugin/io/WMSLayerExporter.java
@@ -6,8 +6,8 @@ import org.openstreetmap.josm.actions.ExtensionFileFilter;
 import org.openstreetmap.josm.io.FileExporter;
 
 public class WMSLayerExporter extends FileExporter{
-	
-	public WMSLayerExporter() {
-		super(new ExtensionFileFilter("wms", "wms", tr("WMS Files (*.wms)")));
-	}
+    
+    public WMSLayerExporter() {
+        super(new ExtensionFileFilter("wms", "wms", tr("WMS Files (*.wms)")));
+    }
 }
\ No newline at end of file
diff --git a/wmsplugin/src/wmsplugin/io/WMSLayerImporter.java b/wmsplugin/src/wmsplugin/io/WMSLayerImporter.java
index 8de34c4..7724fb2 100644
--- a/wmsplugin/src/wmsplugin/io/WMSLayerImporter.java
+++ b/wmsplugin/src/wmsplugin/io/WMSLayerImporter.java
@@ -6,8 +6,8 @@ import static org.openstreetmap.josm.tools.I18n.tr;
 
 public class WMSLayerImporter extends FileImporter{
 
-	public WMSLayerImporter() {
-		super(new ExtensionFileFilter("wms", "wms", tr("WMS Files (*.wms)")));
-	}
-	
+    public WMSLayerImporter() {
+        super(new ExtensionFileFilter("wms", "wms", tr("WMS Files (*.wms)")));
+    }
+    
 }

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



More information about the Pkg-grass-devel mailing list