Index: /applications/editors/josm/plugins/imagery-xml-bounds/src/org/openstreetmap/josm/plugins/imageryxmlbounds/ImageryXmlBoundsPlugin.java
===================================================================
--- /applications/editors/josm/plugins/imagery-xml-bounds/src/org/openstreetmap/josm/plugins/imageryxmlbounds/ImageryXmlBoundsPlugin.java	(revision 26895)
+++ /applications/editors/josm/plugins/imagery-xml-bounds/src/org/openstreetmap/josm/plugins/imageryxmlbounds/ImageryXmlBoundsPlugin.java	(revision 26896)
@@ -25,10 +25,14 @@
 import org.openstreetmap.josm.plugins.imageryxmlbounds.actions.ShowBoundsPropertiesAction;
 import org.openstreetmap.josm.plugins.imageryxmlbounds.actions.ShowBoundsSelectionAction;
+import org.openstreetmap.josm.plugins.imageryxmlbounds.actions.downloadtask.DownloadXmlBoundsTask;
+import org.openstreetmap.josm.plugins.imageryxmlbounds.io.XmlBoundsExporter;
+import org.openstreetmap.josm.plugins.imageryxmlbounds.io.XmlBoundsImporter;
 
 /**
  * Main class of Imagery XML bounds plugin.
  * @author Don-vip
- * @version 1.1
+ * @version 1.2
  * History:
+ * 1.2 17-Oct-2011 Update for #6960 and JOSM 4523 (allow to download imagery XML bounds with Ctrl-L)
  * 1.1 08-Oct-2011 Update for #6934 and JOSM 4506, code refactorisation, removing debug code
  * 1.0 03-Oct-2011 first version
@@ -69,4 +73,6 @@
 		DataSet.addSelectionListener(selectionAction);
 		Main.toolbar.register(selectionAction);
+		// Allow JOSM to download *.imagery.xml files
+		Main.main.menu.openLocation.addDownloadTaskClass(DownloadXmlBoundsTask.class);
 	}
 
Index: plications/editors/josm/plugins/imagery-xml-bounds/src/org/openstreetmap/josm/plugins/imageryxmlbounds/ValidatingImageryReader.java
===================================================================
--- /applications/editors/josm/plugins/imagery-xml-bounds/src/org/openstreetmap/josm/plugins/imageryxmlbounds/ValidatingImageryReader.java	(revision 26895)
+++ 	(revision )
@@ -1,40 +1,0 @@
-/**
- * 
- */
-package org.openstreetmap.josm.plugins.imageryxmlbounds;
-
-import java.io.IOException;
-
-import javax.xml.XMLConstants;
-import javax.xml.transform.stream.StreamSource;
-import javax.xml.validation.Schema;
-import javax.xml.validation.SchemaFactory;
-
-import org.openstreetmap.josm.io.MirroredInputStream;
-import org.openstreetmap.josm.io.imagery.ImageryReader;
-import org.xml.sax.SAXException;
-
-/**
- * An extended Imagery Reader able to validate input against the JOSM Maps XSD.
- * @author Don-vip
- *
- */
-public class ValidatingImageryReader extends ImageryReader implements XmlBoundsConstants {
-
-	public ValidatingImageryReader(String source) throws SAXException, IOException {
-		this(source, true);
-	}
-
-	public ValidatingImageryReader(String source, boolean validateFirst) throws SAXException, IOException {
-		super(source);
-		if (validateFirst) {
-			validate(source);
-		}
-	}
-
-	public static void validate(String source) throws SAXException, IOException {
-        SchemaFactory factory =  SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
-        Schema schema = factory.newSchema(new StreamSource(new MirroredInputStream(XML_SCHEMA)));
-        schema.newValidator().validate(new StreamSource(source));
-	}
-}
Index: /applications/editors/josm/plugins/imagery-xml-bounds/src/org/openstreetmap/josm/plugins/imageryxmlbounds/XmlBoundsConstants.java
===================================================================
--- /applications/editors/josm/plugins/imagery-xml-bounds/src/org/openstreetmap/josm/plugins/imageryxmlbounds/XmlBoundsConstants.java	(revision 26895)
+++ /applications/editors/josm/plugins/imagery-xml-bounds/src/org/openstreetmap/josm/plugins/imageryxmlbounds/XmlBoundsConstants.java	(revision 26896)
@@ -33,5 +33,5 @@
 	 * Plugin version.
 	 */
-	public static final String PLUGIN_VERSION = "1.1";
+	public static final String PLUGIN_VERSION = "1.2";
 	
 	/**
@@ -39,5 +39,10 @@
 	 */
 	public static final String XML_NAMESPACE = "http://josm.openstreetmap.de/maps-1.0";
-	
+
+    /**
+     * XML file location.
+     */
+    public static final String XML_LOCATION = "http://josm.openstreetmap.de/maps";
+
 	/**
 	 * XML Schema
Index: plications/editors/josm/plugins/imagery-xml-bounds/src/org/openstreetmap/josm/plugins/imageryxmlbounds/XmlBoundsExporter.java
===================================================================
--- /applications/editors/josm/plugins/imagery-xml-bounds/src/org/openstreetmap/josm/plugins/imageryxmlbounds/XmlBoundsExporter.java	(revision 26895)
+++ 	(revision )
@@ -1,54 +1,0 @@
-//    JOSM Imagery XML Bounds plugin.
-//    Copyright (C) 2011 Don-vip
-//
-//    This program is free software: you can redistribute it and/or modify
-//    it under the terms of the GNU General Public License as published by
-//    the Free Software Foundation, either version 3 of the License, or
-//    (at your option) any later version.
-//
-//    This program is distributed in the hope that it will be useful,
-//    but WITHOUT ANY WARRANTY; without even the implied warranty of
-//    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-//    GNU General Public License for more details.
-//
-//    You should have received a copy of the GNU General Public License
-//    along with this program.  If not, see <http://www.gnu.org/licenses/>.
-package org.openstreetmap.josm.plugins.imageryxmlbounds;
-
-import java.io.BufferedWriter;
-import java.io.File;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.io.OutputStreamWriter;
-import java.io.Writer;
-
-import org.openstreetmap.josm.gui.layer.Layer;
-import org.openstreetmap.josm.gui.layer.OsmDataLayer;
-import org.openstreetmap.josm.io.FileExporter;
-import org.openstreetmap.josm.plugins.imageryxmlbounds.actions.ComputeBoundsAction;
-
-/**
- * @author Don-vip
- *
- */
-public class XmlBoundsExporter extends FileExporter implements XmlBoundsConstants {
-
-	public XmlBoundsExporter() {
-		super(FILE_FILTER);
-	}
-
-	/* (non-Javadoc)
-	 * @see org.openstreetmap.josm.io.FileExporter#exportData(java.io.File, org.openstreetmap.josm.gui.layer.Layer)
-	 */
-	@Override
-	public void exportData(File file, Layer layer) throws IOException {
-		if (layer instanceof OsmDataLayer) {
-			Writer writer = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(file), ENCODING));
-			try {
-				writer.write(new ComputeBoundsAction((OsmDataLayer) layer).getXml());
-			} finally {
-				writer.close();
-			}
-		}
-	}
-}
Index: plications/editors/josm/plugins/imagery-xml-bounds/src/org/openstreetmap/josm/plugins/imageryxmlbounds/XmlBoundsImporter.java
===================================================================
--- /applications/editors/josm/plugins/imagery-xml-bounds/src/org/openstreetmap/josm/plugins/imageryxmlbounds/XmlBoundsImporter.java	(revision 26895)
+++ 	(revision )
@@ -1,225 +1,0 @@
-//    JOSM Imagery XML Bounds plugin.
-//    Copyright (C) 2011 Don-vip
-//
-//    This program is free software: you can redistribute it and/or modify
-//    it under the terms of the GNU General Public License as published by
-//    the Free Software Foundation, either version 3 of the License, or
-//    (at your option) any later version.
-//
-//    This program is distributed in the hope that it will be useful,
-//    but WITHOUT ANY WARRANTY; without even the implied warranty of
-//    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-//    GNU General Public License for more details.
-//
-//    You should have received a copy of the GNU General Public License
-//    along with this program.  If not, see <http://www.gnu.org/licenses/>.
-package org.openstreetmap.josm.plugins.imageryxmlbounds;
-
-import static org.openstreetmap.josm.tools.I18n.tr;
-
-import java.io.File;
-import java.io.IOException;
-import java.util.Collection;
-import java.util.List;
-
-import javax.swing.JOptionPane;
-import javax.swing.SwingUtilities;
-
-import org.openstreetmap.gui.jmapviewer.Coordinate;
-import org.openstreetmap.josm.Main;
-import org.openstreetmap.josm.data.coor.LatLon;
-import org.openstreetmap.josm.data.imagery.ImageryInfo;
-import org.openstreetmap.josm.data.imagery.ImageryInfo.ImageryBounds;
-import org.openstreetmap.josm.data.imagery.ImageryInfo.ImageryType;
-import org.openstreetmap.josm.data.imagery.Shape;
-import org.openstreetmap.josm.data.osm.BBox;
-import org.openstreetmap.josm.data.osm.DataSet;
-import org.openstreetmap.josm.data.osm.Node;
-import org.openstreetmap.josm.data.osm.OsmPrimitive;
-import org.openstreetmap.josm.data.osm.Relation;
-import org.openstreetmap.josm.data.osm.RelationMember;
-import org.openstreetmap.josm.data.osm.Way;
-import org.openstreetmap.josm.gui.progress.ProgressMonitor;
-import org.openstreetmap.josm.io.FileImporter;
-import org.openstreetmap.josm.io.IllegalDataException;
-import org.openstreetmap.josm.io.imagery.ImageryReader;
-import org.xml.sax.SAXException;
-
-/**
- * @author Don-vip
- *
- */
-public class XmlBoundsImporter extends FileImporter implements XmlBoundsConstants {
-
-	public XmlBoundsImporter() {
-		super(FILE_FILTER);
-	}
-
-	public DataSet convertImageryEntries(List<ImageryInfo> entries) {
-		DataSet dataSet = new DataSet();
-		
-		for (ImageryInfo imagery : entries) {
-			if (!imagery.isBlacklisted()) {
-				ImageryBounds bounds = imagery.getBounds();
-				if (bounds != null) {
-					dataSet.addPrimitive(convertImagery(imagery, bounds, dataSet));
-				}
-			}
-		}
-		return dataSet;
-	}
-	
-	private void safePut(OsmPrimitive p, String key, Object value) {
-		if (value != null) {
-			if (value instanceof Collection) {
-				String s = "";
-				for (Object elt : (Collection<?>)value) {
-					if (elt != null && elt.toString() != null && !elt.toString().isEmpty()) {
-						if (!s.isEmpty()) {
-							s += ";";
-						}
-						s += elt.toString();
-					}
-				}
-				if (!s.isEmpty()) {
-					p.put(key, s);
-				}
-			} else if (!value.equals(0) && value.toString() != null && !value.toString().isEmpty()) {
-				p.put(key, value.toString());
-			}
-		}
-	}
-	
-    private Node getNode(LatLon latlon, DataSet dataSet) {
-        List<Node> nodes = dataSet.searchNodes(new BBox(latlon, latlon));
-        if (!nodes.isEmpty()) {
-            return nodes.get(0);
-        } else {
-            Node node = new Node(latlon);
-            dataSet.addPrimitive(node);
-            return node;
-        }
-    }
-
-	private Node getNode(double lat, double lon, DataSet dataSet) {
-	    return getNode(new LatLon(lat, lon), dataSet);
-	}
-	
-	private void ensureWayIsClosed(Way way) {
-	    if (!way.getNode(0).equals(way.getNode(way.getNodesCount()-1))) {
-	        way.addNode(way.getNode(0));
-	    }
-	}
-	
-	private OsmPrimitive convertImagery(ImageryInfo imagery, ImageryBounds bounds, DataSet dataSet) {
-		OsmPrimitive osmImagery = null;
-		if (bounds.getShapes().isEmpty()) {
-			LatLon bottomLeft = bounds.getMin();
-			LatLon topRight = bounds.getMax();
-			LatLon topLeft = new LatLon(topRight.lat(), bottomLeft.lon());
-			LatLon bottomRight = new LatLon(bottomLeft.lat(), topRight.lon());
-			
-			Way way = new Way();
-			for (LatLon ll : new LatLon[]{bottomLeft, topLeft, topRight, bottomRight}) {
-				way.addNode(getNode(ll, dataSet));
-			}
-			ensureWayIsClosed(way);
-			osmImagery = way;
-			
-		} else {
-			Relation relation = new Relation();
-			relation.put("type", "multipolygon");
-			for (Shape shape : bounds.getShapes()) {
-				Way way = new Way();
-				for (Coordinate coor : shape.getPoints()) {
-					way.addNode(getNode(coor.getLat(), coor.getLon(), dataSet));
-				}
-				ensureWayIsClosed(way);
-				dataSet.addPrimitive(way);
-				relation.addMember(new RelationMember("outer", way));
-			}
-			osmImagery = relation;
-		}
-		
-		safePut(osmImagery, KEY_NAME, imagery.getName());
-		safePut(osmImagery, KEY_TYPE, imagery.getImageryType().getUrlString());
-		safePut(osmImagery, KEY_DEFAULT, imagery.isDefaultEntry());
-		safePut(osmImagery, KEY_URL, imagery.getUrl());
-		safePut(osmImagery, KEY_PROJECTIONS, imagery.getServerProjections());
-		safePut(osmImagery, KEY_EULA, imagery.getEulaAcceptanceRequired());
-		safePut(osmImagery, KEY_ATTR_TEXT, imagery.getAttributionText(0, null, null));
-		safePut(osmImagery, KEY_ATTR_URL, imagery.getAttributionLinkURL());
-        safePut(osmImagery, KEY_TERMS_TEXT, imagery.getTermsOfUseText());
-		safePut(osmImagery, KEY_TERMS_URL, imagery.getTermsOfUseURL());
-		safePut(osmImagery, KEY_COUNTRY_CODE, imagery.getCountryCode());
-		safePut(osmImagery, KEY_LOGO_URL, imagery.getAttributionImageURL());
-
-		if (imagery.getImageryType().equals(ImageryType.TMS)) {
-			safePut(osmImagery, KEY_MAX_ZOOM, imagery.getMaxZoom());
-			safePut(osmImagery, KEY_MIN_ZOOM, imagery.getMinZoom());
-		}
-		
-		return osmImagery;
-	}
-	
-	/* (non-Javadoc)
-	 * @see org.openstreetmap.josm.io.FileImporter#importData(java.io.File, org.openstreetmap.josm.gui.progress.ProgressMonitor)
-	 */
-	@Override
-	public void importData(final File file, ProgressMonitor progressMonitor)
-			throws IOException, IllegalDataException {
-		try {
-			ImageryReader reader = null;
-			
-			try {
-				reader = new ValidatingImageryReader(file.getAbsolutePath());
-			} catch (SAXException e)  {
-                if (JOptionPane.showConfirmDialog(
-                        Main.parent,
-                        tr("Validating error in file {0}:\n{1}\nDo you want to continue without validating the file ?", file.getPath(), e.getLocalizedMessage()),
-                        tr("Open Imagery XML file"),
-                        JOptionPane.YES_NO_CANCEL_OPTION) != JOptionPane.YES_OPTION) {
-                	return;
-                }
-
-				reader = new ImageryReader(file.getAbsolutePath());
-			}
-			
-			final DataSet dataSet = convertImageryEntries(reader.parse());
-			        
-	        final XmlBoundsLayer layer = new XmlBoundsLayer(dataSet, file.getName(), file);
-	        Runnable uiStuff = new Runnable() {
-	            @Override
-	            public void run() {
-	                if (dataSet.allPrimitives().isEmpty()) {
-	                    JOptionPane.showMessageDialog(
-	                            Main.parent,
-	                            tr("No data found in file {0}.", file.getPath()),
-	                            tr("Open Imagery XML file"),
-	                            JOptionPane.INFORMATION_MESSAGE);
-	                }
-	                Main.main.addLayer(layer);
-	                layer.onPostLoadFromFile();
-	            }
-	        };
-	        if (SwingUtilities.isEventDispatchThread()) {
-	            uiStuff.run();
-	        } else {
-	            SwingUtilities.invokeLater(uiStuff);
-	        }
-		} catch (SAXException e) {
-			e.printStackTrace();
-		}
-	}
-
-	/* (non-Javadoc)
-	 * @see org.openstreetmap.josm.io.FileImporter#importData(java.util.List, org.openstreetmap.josm.gui.progress.ProgressMonitor)
-	 */
-	@Override
-	public void importData(List<File> files, ProgressMonitor progressMonitor)
-			throws IOException, IllegalDataException {
-		for (File file : files) {
-			importData(file, progressMonitor);
-		}
-	}
-}
Index: /applications/editors/josm/plugins/imagery-xml-bounds/src/org/openstreetmap/josm/plugins/imageryxmlbounds/actions/downloadtask/DownloadXmlBoundsTask.java
===================================================================
--- /applications/editors/josm/plugins/imagery-xml-bounds/src/org/openstreetmap/josm/plugins/imageryxmlbounds/actions/downloadtask/DownloadXmlBoundsTask.java	(revision 26896)
+++ /applications/editors/josm/plugins/imagery-xml-bounds/src/org/openstreetmap/josm/plugins/imageryxmlbounds/actions/downloadtask/DownloadXmlBoundsTask.java	(revision 26896)
@@ -0,0 +1,104 @@
+//    JOSM Imagery XML Bounds plugin.
+//    Copyright (C) 2011 Don-vip
+//
+//    This program is free software: you can redistribute it and/or modify
+//    it under the terms of the GNU General Public License as published by
+//    the Free Software Foundation, either version 3 of the License, or
+//    (at your option) any later version.
+//
+//    This program is distributed in the hope that it will be useful,
+//    but WITHOUT ANY WARRANTY; without even the implied warranty of
+//    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+//    GNU General Public License for more details.
+//
+//    You should have received a copy of the GNU General Public License
+//    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+package org.openstreetmap.josm.plugins.imageryxmlbounds.actions.downloadtask;
+
+import java.util.concurrent.Future;
+
+import org.openstreetmap.josm.Main;
+import org.openstreetmap.josm.actions.downloadtasks.DownloadOsmTask;
+import org.openstreetmap.josm.data.Bounds;
+import org.openstreetmap.josm.gui.layer.Layer;
+import org.openstreetmap.josm.gui.layer.OsmDataLayer;
+import org.openstreetmap.josm.gui.progress.ProgressMonitor;
+import org.openstreetmap.josm.io.OsmServerReader;
+import org.openstreetmap.josm.plugins.imageryxmlbounds.XmlBoundsConstants;
+import org.openstreetmap.josm.plugins.imageryxmlbounds.XmlBoundsLayer;
+import org.openstreetmap.josm.plugins.imageryxmlbounds.io.JosmServerLocationReader;
+
+public class DownloadXmlBoundsTask extends DownloadOsmTask implements XmlBoundsConstants {
+
+    @Override
+    public Future<?> download(boolean newLayer, Bounds downloadArea,
+            ProgressMonitor progressMonitor) {
+        return null;
+    }
+
+    @Override
+    public Future<?> loadUrl(boolean newLayer, String url,
+            ProgressMonitor progressMonitor) {
+        downloadTask = new DownloadTask(newLayer,
+                new JosmServerLocationReader(url), progressMonitor);
+        // We need submit instead of execute so we can wait for it to finish and get the error
+        // message if necessary. If no one calls getErrorMessage() it just behaves like execute.
+        return Main.worker.submit(downloadTask);
+    }
+
+    @Override
+    public boolean acceptsUrl(String url) {
+        return url != null && (url.equals(XML_LOCATION) || url.matches("http://.*\\."+EXTENSION.replace(".", "\\.")));
+    }
+
+    protected class DownloadTask extends DownloadOsmTask.DownloadTask {
+        public DownloadTask(boolean newLayer, OsmServerReader reader, ProgressMonitor progressMonitor) {
+            super(newLayer, reader, progressMonitor);
+        }
+        
+        /* (non-Javadoc)
+         * @see org.openstreetmap.josm.actions.downloadtasks.DownloadOsmTask.DownloadTask#getEditLayer()
+         */
+        @Override
+        protected OsmDataLayer getEditLayer() {
+            OsmDataLayer editLayer = super.getEditLayer();
+            return editLayer instanceof XmlBoundsLayer ? editLayer : null;
+        }
+
+        /* (non-Javadoc)
+         * @see org.openstreetmap.josm.actions.downloadtasks.DownloadOsmTask.DownloadTask#getNumDataLayers()
+         */
+        @Override
+        protected int getNumDataLayers() {
+            int count = 0;
+            if (!Main.isDisplayingMapView()) return 0;
+            for (Layer layer : Main.map.mapView.getAllLayers()) {
+                if (layer instanceof XmlBoundsLayer) {
+                    count++;
+                }
+            }
+            return count;
+        }
+
+        /* (non-Javadoc)
+         * @see org.openstreetmap.josm.actions.downloadtasks.DownloadOsmTask.DownloadTask#getFirstDataLayer()
+         */
+        @Override
+        protected OsmDataLayer getFirstDataLayer() {
+            if (!Main.isDisplayingMapView()) return null;
+            for (Layer layer : Main.map.mapView.getAllLayersAsList()) {
+                if (layer instanceof XmlBoundsLayer)
+                    return (XmlBoundsLayer) layer;
+            }
+            return null;
+        }
+
+        /* (non-Javadoc)
+         * @see org.openstreetmap.josm.actions.downloadtasks.DownloadOsmTask.DownloadTask#createNewLayer()
+         */
+        @Override
+        protected OsmDataLayer createNewLayer() {
+            return new XmlBoundsLayer(dataSet, XmlBoundsLayer.createNewName(), null);
+        }
+    }
+}
Index: /applications/editors/josm/plugins/imagery-xml-bounds/src/org/openstreetmap/josm/plugins/imageryxmlbounds/io/JosmServerLocationReader.java
===================================================================
--- /applications/editors/josm/plugins/imagery-xml-bounds/src/org/openstreetmap/josm/plugins/imageryxmlbounds/io/JosmServerLocationReader.java	(revision 26896)
+++ /applications/editors/josm/plugins/imagery-xml-bounds/src/org/openstreetmap/josm/plugins/imageryxmlbounds/io/JosmServerLocationReader.java	(revision 26896)
@@ -0,0 +1,45 @@
+//    JOSM Imagery XML Bounds plugin.
+//    Copyright (C) 2011 Don-vip
+//
+//    This program is free software: you can redistribute it and/or modify
+//    it under the terms of the GNU General Public License as published by
+//    the Free Software Foundation, either version 3 of the License, or
+//    (at your option) any later version.
+//
+//    This program is distributed in the hope that it will be useful,
+//    but WITHOUT ANY WARRANTY; without even the implied warranty of
+//    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+//    GNU General Public License for more details.
+//
+//    You should have received a copy of the GNU General Public License
+//    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+package org.openstreetmap.josm.plugins.imageryxmlbounds.io;
+
+import static org.openstreetmap.josm.tools.I18n.tr;
+
+import org.openstreetmap.josm.data.osm.DataSet;
+import org.openstreetmap.josm.gui.progress.ProgressMonitor;
+import org.openstreetmap.josm.io.OsmServerReader;
+import org.openstreetmap.josm.io.OsmTransferException;
+
+public class JosmServerLocationReader extends OsmServerReader {
+
+    private String url;
+    
+    public JosmServerLocationReader(String url) {
+        this.url = url;
+    }
+
+    @Override
+    public DataSet parseOsm(ProgressMonitor progressMonitor)
+            throws OsmTransferException {
+        try {
+            progressMonitor.beginTask(tr("Contacting Server...", 10));
+            return new XmlBoundsImporter().parseDataSet(url);
+        } catch (Exception e) {
+            throw new OsmTransferException(e);
+        } finally {
+            progressMonitor.finishTask();
+        }
+    }
+}
Index: /applications/editors/josm/plugins/imagery-xml-bounds/src/org/openstreetmap/josm/plugins/imageryxmlbounds/io/ValidatingImageryReader.java
===================================================================
--- /applications/editors/josm/plugins/imagery-xml-bounds/src/org/openstreetmap/josm/plugins/imageryxmlbounds/io/ValidatingImageryReader.java	(revision 26896)
+++ /applications/editors/josm/plugins/imagery-xml-bounds/src/org/openstreetmap/josm/plugins/imageryxmlbounds/io/ValidatingImageryReader.java	(revision 26896)
@@ -0,0 +1,41 @@
+/**
+ * 
+ */
+package org.openstreetmap.josm.plugins.imageryxmlbounds.io;
+
+import java.io.IOException;
+
+import javax.xml.XMLConstants;
+import javax.xml.transform.stream.StreamSource;
+import javax.xml.validation.Schema;
+import javax.xml.validation.SchemaFactory;
+
+import org.openstreetmap.josm.io.MirroredInputStream;
+import org.openstreetmap.josm.io.imagery.ImageryReader;
+import org.openstreetmap.josm.plugins.imageryxmlbounds.XmlBoundsConstants;
+import org.xml.sax.SAXException;
+
+/**
+ * An extended Imagery Reader able to validate input against the JOSM Maps XSD.
+ * @author Don-vip
+ *
+ */
+public class ValidatingImageryReader extends ImageryReader implements XmlBoundsConstants {
+
+	public ValidatingImageryReader(String source) throws SAXException, IOException {
+		this(source, true);
+	}
+
+	public ValidatingImageryReader(String source, boolean validateFirst) throws SAXException, IOException {
+		super(source);
+		if (validateFirst) {
+			validate(source);
+		}
+	}
+
+	public static void validate(String source) throws SAXException, IOException {
+        SchemaFactory factory =  SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
+        Schema schema = factory.newSchema(new StreamSource(new MirroredInputStream(XML_SCHEMA)));
+        schema.newValidator().validate(new StreamSource(source));
+	}
+}
Index: /applications/editors/josm/plugins/imagery-xml-bounds/src/org/openstreetmap/josm/plugins/imageryxmlbounds/io/XmlBoundsExporter.java
===================================================================
--- /applications/editors/josm/plugins/imagery-xml-bounds/src/org/openstreetmap/josm/plugins/imageryxmlbounds/io/XmlBoundsExporter.java	(revision 26896)
+++ /applications/editors/josm/plugins/imagery-xml-bounds/src/org/openstreetmap/josm/plugins/imageryxmlbounds/io/XmlBoundsExporter.java	(revision 26896)
@@ -0,0 +1,55 @@
+//    JOSM Imagery XML Bounds plugin.
+//    Copyright (C) 2011 Don-vip
+//
+//    This program is free software: you can redistribute it and/or modify
+//    it under the terms of the GNU General Public License as published by
+//    the Free Software Foundation, either version 3 of the License, or
+//    (at your option) any later version.
+//
+//    This program is distributed in the hope that it will be useful,
+//    but WITHOUT ANY WARRANTY; without even the implied warranty of
+//    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+//    GNU General Public License for more details.
+//
+//    You should have received a copy of the GNU General Public License
+//    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+package org.openstreetmap.josm.plugins.imageryxmlbounds.io;
+
+import java.io.BufferedWriter;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.OutputStreamWriter;
+import java.io.Writer;
+
+import org.openstreetmap.josm.gui.layer.Layer;
+import org.openstreetmap.josm.gui.layer.OsmDataLayer;
+import org.openstreetmap.josm.io.FileExporter;
+import org.openstreetmap.josm.plugins.imageryxmlbounds.XmlBoundsConstants;
+import org.openstreetmap.josm.plugins.imageryxmlbounds.actions.ComputeBoundsAction;
+
+/**
+ * @author Don-vip
+ *
+ */
+public class XmlBoundsExporter extends FileExporter implements XmlBoundsConstants {
+
+	public XmlBoundsExporter() {
+		super(FILE_FILTER);
+	}
+
+	/* (non-Javadoc)
+	 * @see org.openstreetmap.josm.io.FileExporter#exportData(java.io.File, org.openstreetmap.josm.gui.layer.Layer)
+	 */
+	@Override
+	public void exportData(File file, Layer layer) throws IOException {
+		if (layer instanceof OsmDataLayer) {
+			Writer writer = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(file), ENCODING));
+			try {
+				writer.write(new ComputeBoundsAction((OsmDataLayer) layer).getXml());
+			} finally {
+				writer.close();
+			}
+		}
+	}
+}
Index: /applications/editors/josm/plugins/imagery-xml-bounds/src/org/openstreetmap/josm/plugins/imageryxmlbounds/io/XmlBoundsImporter.java
===================================================================
--- /applications/editors/josm/plugins/imagery-xml-bounds/src/org/openstreetmap/josm/plugins/imageryxmlbounds/io/XmlBoundsImporter.java	(revision 26896)
+++ /applications/editors/josm/plugins/imagery-xml-bounds/src/org/openstreetmap/josm/plugins/imageryxmlbounds/io/XmlBoundsImporter.java	(revision 26896)
@@ -0,0 +1,247 @@
+//    JOSM Imagery XML Bounds plugin.
+//    Copyright (C) 2011 Don-vip
+//
+//    This program is free software: you can redistribute it and/or modify
+//    it under the terms of the GNU General Public License as published by
+//    the Free Software Foundation, either version 3 of the License, or
+//    (at your option) any later version.
+//
+//    This program is distributed in the hope that it will be useful,
+//    but WITHOUT ANY WARRANTY; without even the implied warranty of
+//    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+//    GNU General Public License for more details.
+//
+//    You should have received a copy of the GNU General Public License
+//    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+package org.openstreetmap.josm.plugins.imageryxmlbounds.io;
+
+import static org.openstreetmap.josm.tools.I18n.tr;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.Collection;
+import java.util.List;
+
+import javax.swing.JOptionPane;
+import javax.swing.SwingUtilities;
+
+import org.openstreetmap.gui.jmapviewer.Coordinate;
+import org.openstreetmap.josm.Main;
+import org.openstreetmap.josm.data.coor.LatLon;
+import org.openstreetmap.josm.data.imagery.ImageryInfo;
+import org.openstreetmap.josm.data.imagery.ImageryInfo.ImageryBounds;
+import org.openstreetmap.josm.data.imagery.ImageryInfo.ImageryType;
+import org.openstreetmap.josm.data.imagery.Shape;
+import org.openstreetmap.josm.data.osm.BBox;
+import org.openstreetmap.josm.data.osm.DataSet;
+import org.openstreetmap.josm.data.osm.Node;
+import org.openstreetmap.josm.data.osm.OsmPrimitive;
+import org.openstreetmap.josm.data.osm.Relation;
+import org.openstreetmap.josm.data.osm.RelationMember;
+import org.openstreetmap.josm.data.osm.Way;
+import org.openstreetmap.josm.gui.progress.ProgressMonitor;
+import org.openstreetmap.josm.io.FileImporter;
+import org.openstreetmap.josm.io.IllegalDataException;
+import org.openstreetmap.josm.io.imagery.ImageryReader;
+import org.openstreetmap.josm.plugins.imageryxmlbounds.XmlBoundsConstants;
+import org.openstreetmap.josm.plugins.imageryxmlbounds.XmlBoundsLayer;
+import org.xml.sax.SAXException;
+
+/**
+ * @author Don-vip
+ *
+ */
+public class XmlBoundsImporter extends FileImporter implements XmlBoundsConstants {
+
+	public XmlBoundsImporter() {
+		super(FILE_FILTER);
+	}
+
+	public DataSet convertImageryEntries(List<ImageryInfo> entries) {
+		DataSet dataSet = new DataSet();
+		
+		for (ImageryInfo imagery : entries) {
+			if (!imagery.isBlacklisted()) {
+				ImageryBounds bounds = imagery.getBounds();
+				if (bounds != null) {
+					dataSet.addPrimitive(convertImagery(imagery, bounds, dataSet));
+				}
+			}
+		}
+		return dataSet;
+	}
+	
+	private void safePut(OsmPrimitive p, String key, Object value) {
+		if (value != null) {
+			if (value instanceof Collection) {
+				String s = "";
+				for (Object elt : (Collection<?>)value) {
+					if (elt != null && elt.toString() != null && !elt.toString().isEmpty()) {
+						if (!s.isEmpty()) {
+							s += ";";
+						}
+						s += elt.toString();
+					}
+				}
+				if (!s.isEmpty()) {
+					p.put(key, s);
+				}
+			} else if (!value.equals(0) && value.toString() != null && !value.toString().isEmpty()) {
+				p.put(key, value.toString());
+			}
+		}
+	}
+	
+    private Node getNode(LatLon latlon, DataSet dataSet) {
+        List<Node> nodes = dataSet.searchNodes(new BBox(latlon, latlon));
+        if (!nodes.isEmpty()) {
+            return nodes.get(0);
+        } else {
+            Node node = new Node(latlon);
+            dataSet.addPrimitive(node);
+            return node;
+        }
+    }
+
+	private Node getNode(double lat, double lon, DataSet dataSet) {
+	    return getNode(new LatLon(lat, lon), dataSet);
+	}
+	
+	private void ensureWayIsClosed(Way way) {
+	    if (!way.getNode(0).equals(way.getNode(way.getNodesCount()-1))) {
+	        way.addNode(way.getNode(0));
+	    }
+	}
+	
+	private OsmPrimitive convertImagery(ImageryInfo imagery, ImageryBounds bounds, DataSet dataSet) {
+		OsmPrimitive osmImagery = null;
+		if (bounds.getShapes().isEmpty()) {
+			LatLon bottomLeft = bounds.getMin();
+			LatLon topRight = bounds.getMax();
+			LatLon topLeft = new LatLon(topRight.lat(), bottomLeft.lon());
+			LatLon bottomRight = new LatLon(bottomLeft.lat(), topRight.lon());
+			
+			Way way = new Way();
+			for (LatLon ll : new LatLon[]{bottomLeft, topLeft, topRight, bottomRight}) {
+				way.addNode(getNode(ll, dataSet));
+			}
+			ensureWayIsClosed(way);
+			osmImagery = way;
+			
+		} else {
+			Relation relation = new Relation();
+			relation.put("type", "multipolygon");
+			for (Shape shape : bounds.getShapes()) {
+				Way way = new Way();
+				for (Coordinate coor : shape.getPoints()) {
+					way.addNode(getNode(coor.getLat(), coor.getLon(), dataSet));
+				}
+				ensureWayIsClosed(way);
+				dataSet.addPrimitive(way);
+				relation.addMember(new RelationMember("outer", way));
+			}
+			osmImagery = relation;
+		}
+		
+		safePut(osmImagery, KEY_NAME, imagery.getName());
+		safePut(osmImagery, KEY_TYPE, imagery.getImageryType().getUrlString());
+		safePut(osmImagery, KEY_DEFAULT, imagery.isDefaultEntry());
+		safePut(osmImagery, KEY_URL, imagery.getUrl());
+		safePut(osmImagery, KEY_PROJECTIONS, imagery.getServerProjections());
+		safePut(osmImagery, KEY_EULA, imagery.getEulaAcceptanceRequired());
+		safePut(osmImagery, KEY_ATTR_TEXT, imagery.getAttributionText(0, null, null));
+		safePut(osmImagery, KEY_ATTR_URL, imagery.getAttributionLinkURL());
+        safePut(osmImagery, KEY_TERMS_TEXT, imagery.getTermsOfUseText());
+		safePut(osmImagery, KEY_TERMS_URL, imagery.getTermsOfUseURL());
+		safePut(osmImagery, KEY_COUNTRY_CODE, imagery.getCountryCode());
+		safePut(osmImagery, KEY_LOGO_URL, imagery.getAttributionImageURL());
+
+		if (imagery.getImageryType().equals(ImageryType.TMS)) {
+			safePut(osmImagery, KEY_MAX_ZOOM, imagery.getMaxZoom());
+			safePut(osmImagery, KEY_MIN_ZOOM, imagery.getMinZoom());
+		}
+		
+		return osmImagery;
+	}
+	
+	public DataSet parseDataSet(final String source) throws IOException, SAXException {
+	    return parseDataSet(source, null);
+	}
+
+	public DataSet parseDataSet(final File file) throws IOException, SAXException {
+        return parseDataSet(null, file);
+    }
+	
+	protected DataSet parseDataSet(final String source, final File file) throws IOException, SAXException {
+        ImageryReader reader = null;
+        
+        try {
+            reader = new ValidatingImageryReader(source != null ? source : file.getAbsolutePath());
+        } catch (SAXException e)  {
+            if (JOptionPane.showConfirmDialog(
+                    Main.parent,
+                    tr("Validating error in file {0}:\n{1}\nDo you want to continue without validating the file ?", 
+                            source != null ? source : file.getPath(), e.getLocalizedMessage()),
+                    tr("Open Imagery XML file"),
+                    JOptionPane.YES_NO_CANCEL_OPTION) != JOptionPane.YES_OPTION) {
+                return null;
+            }
+
+            reader = new ImageryReader(source != null ? source : file.getAbsolutePath());
+        }
+        
+        return convertImageryEntries(reader.parse());
+	}
+	
+    protected void importData(final String source, final String layerName, final File file, ProgressMonitor progressMonitor)
+            throws IOException, IllegalDataException {
+        try {
+            final DataSet dataSet = parseDataSet(source, file);
+            final XmlBoundsLayer layer = new XmlBoundsLayer(dataSet, source != null ? layerName : file.getName(), file);
+            Runnable uiStuff = new Runnable() {
+                @Override
+                public void run() {
+                    if (dataSet.allPrimitives().isEmpty()) {
+                        JOptionPane.showMessageDialog(
+                                Main.parent, tr("No data found in file {0}.", source != null ? source : file.getPath()),
+                                tr("Open Imagery XML file"), JOptionPane.INFORMATION_MESSAGE);
+                    }
+                    Main.main.addLayer(layer);
+                    layer.onPostLoadFromFile();
+                }
+            };
+            if (SwingUtilities.isEventDispatchThread()) {
+                uiStuff.run();
+            } else {
+                SwingUtilities.invokeLater(uiStuff);
+            }
+        } catch (SAXException e) {
+            e.printStackTrace();
+        }
+    }
+	
+	/* (non-Javadoc)
+	 * @see org.openstreetmap.josm.io.FileImporter#importData(java.io.File, org.openstreetmap.josm.gui.progress.ProgressMonitor)
+	 */
+	@Override
+	public void importData(final File file, ProgressMonitor progressMonitor)
+			throws IOException, IllegalDataException {
+		importData(null, null, file, progressMonitor);
+	}
+	
+	public void importData(final String source, final String layerName, ProgressMonitor progressMonitor)
+	        throws IOException, IllegalDataException {
+	    importData(source, layerName, null, progressMonitor);
+    }
+
+	/* (non-Javadoc)
+	 * @see org.openstreetmap.josm.io.FileImporter#importData(java.util.List, org.openstreetmap.josm.gui.progress.ProgressMonitor)
+	 */
+	@Override
+	public void importData(List<File> files, ProgressMonitor progressMonitor)
+			throws IOException, IllegalDataException {
+		for (File file : files) {
+			importData(file, progressMonitor);
+		}
+	}
+}
