Index: applications/editors/josm/plugins/opendata/src/org/openstreetmap/josm/plugins/opendata/core/OdConstants.java
===================================================================
--- applications/editors/josm/plugins/opendata/src/org/openstreetmap/josm/plugins/opendata/core/OdConstants.java	(revision 28091)
+++ applications/editors/josm/plugins/opendata/src/org/openstreetmap/josm/plugins/opendata/core/OdConstants.java	(revision 28113)
@@ -87,4 +87,6 @@
 	public static final String ICON_EMPTY_24 = "empty24.png";
 
+	public static final String ICON_LOOL_48 = "lool48.png";
+
     /**
      * File extensions.
@@ -156,4 +158,5 @@
      * Resources
      */
-    public static final String DICTIONARY_FR = "/org/openstreetmap/josm/plugins/opendata/core/resources/dictionary.fr.csv";
+    public static final String RESOURCE_PATH = "/org/openstreetmap/josm/plugins/opendata/core/resources/";
+    public static final String DICTIONARY_FR = RESOURCE_PATH+"dictionary.fr.csv";
 }
Index: applications/editors/josm/plugins/opendata/src/org/openstreetmap/josm/plugins/opendata/core/actions/DownloadDataTask.java
===================================================================
--- applications/editors/josm/plugins/opendata/src/org/openstreetmap/josm/plugins/opendata/core/actions/DownloadDataTask.java	(revision 28091)
+++ applications/editors/josm/plugins/opendata/src/org/openstreetmap/josm/plugins/opendata/core/actions/DownloadDataTask.java	(revision 28113)
@@ -16,7 +16,12 @@
 package org.openstreetmap.josm.plugins.opendata.core.actions;
 
+import static org.openstreetmap.josm.tools.I18n.tr;
+
 import java.io.File;
+import java.io.IOException;
 import java.util.concurrent.Future;
 import java.util.regex.Pattern;
+
+import javax.swing.JOptionPane;
 
 import org.openstreetmap.josm.Main;
@@ -25,10 +30,11 @@
 import org.openstreetmap.josm.gui.layer.OsmDataLayer;
 import org.openstreetmap.josm.gui.progress.ProgressMonitor;
-import org.openstreetmap.josm.io.AbstractReader;
 import org.openstreetmap.josm.plugins.opendata.core.OdConstants;
 import org.openstreetmap.josm.plugins.opendata.core.datasets.AbstractDataSetHandler;
 import org.openstreetmap.josm.plugins.opendata.core.datasets.DataSetUpdater;
+import org.openstreetmap.josm.plugins.opendata.core.gui.AskLicenseAgreementDialog;
 import org.openstreetmap.josm.plugins.opendata.core.io.NetworkReader;
 import org.openstreetmap.josm.plugins.opendata.core.layers.OdDataLayer;
+import org.openstreetmap.josm.plugins.opendata.core.licenses.License;
 import org.openstreetmap.josm.plugins.opendata.core.modules.Module;
 import org.openstreetmap.josm.plugins.opendata.core.modules.ModuleHandler;
@@ -37,4 +43,6 @@
 
 	private AbstractDataSetHandler handler;
+	
+	//private static final PdfEditorKit pdfEditorKit = new PdfEditorKit();
 	
 	@Override
@@ -45,11 +53,11 @@
 	@Override
 	public Future<?> loadUrl(boolean newLayer, String url, ProgressMonitor progressMonitor) {
-		Class<? extends AbstractReader> readerClass = null; // TODO
-        downloadTask = new InternDownloadTasK(newLayer, new NetworkReader(url, handler, readerClass), progressMonitor);
+        downloadTask = new InternalDownloadTasK(newLayer, new NetworkReader(url, handler), progressMonitor);
         currentBounds = null;
-        // Extract .osm filename from URL to set the new layer name
-        //Matcher matcher = Pattern.compile("http://.*/(.*\\.osm)").matcher(url);
-        //newLayerName = matcher.matches() ? matcher.group(1) : null;
-        return Main.worker.submit(downloadTask);
+        if (handler == null || !handler.hasLicenseToBeAccepted() || askLicenseAgreement(handler.getLicense())) {
+        	return Main.worker.submit(downloadTask);
+        } else {
+        	return null;
+        }
 	}
 
@@ -73,7 +81,7 @@
 	}
 	
-	protected class InternDownloadTasK extends DownloadTask {
+	protected class InternalDownloadTasK extends DownloadTask {
 
-		public InternDownloadTasK(boolean newLayer, NetworkReader reader, ProgressMonitor progressMonitor) {
+		public InternalDownloadTasK(boolean newLayer, NetworkReader reader, ProgressMonitor progressMonitor) {
 			super(newLayer, reader, progressMonitor);
 		}
@@ -99,3 +107,19 @@
 		}
 	}
+	
+    /**
+     * returns true if the user accepts the license, false if they refuse
+     */
+    protected final boolean askLicenseAgreement(License license) {
+    	if (license == null || (license.getURL() == null && license.getSummaryURL() == null)) {
+    		return true;
+    	}
+    	try {
+	        return new AskLicenseAgreementDialog(license).showDialog().getValue() == 1;
+	        
+		} catch (IOException e) {
+            JOptionPane.showMessageDialog(Main.parent, tr("License URL not available: {0}", license.toString()));
+            return false;
+		}
+    }
 }
Index: applications/editors/josm/plugins/opendata/src/org/openstreetmap/josm/plugins/opendata/core/datasets/AbstractDataSetHandler.java
===================================================================
--- applications/editors/josm/plugins/opendata/src/org/openstreetmap/josm/plugins/opendata/core/datasets/AbstractDataSetHandler.java	(revision 28091)
+++ applications/editors/josm/plugins/opendata/src/org/openstreetmap/josm/plugins/opendata/core/datasets/AbstractDataSetHandler.java	(revision 28113)
@@ -19,5 +19,4 @@
 import java.net.MalformedURLException;
 import java.net.URL;
-import java.nio.charset.Charset;
 import java.util.ArrayList;
 import java.util.Collection;
@@ -25,36 +24,20 @@
 import java.util.regex.Pattern;
 
-import org.geotools.referencing.CRS;
-import org.geotools.referencing.crs.AbstractDerivedCRS;
-import org.geotools.referencing.datum.DefaultEllipsoid;
-import org.geotools.referencing.operation.projection.LambertConformal;
-import org.geotools.referencing.operation.projection.LambertConformal1SP;
-import org.geotools.referencing.operation.projection.LambertConformal2SP;
-import org.geotools.referencing.operation.projection.MapProjection.AbstractProvider;
-import org.opengis.parameter.ParameterDescriptor;
-import org.opengis.parameter.ParameterValueGroup;
-import org.opengis.referencing.FactoryException;
-import org.opengis.referencing.crs.CoordinateReferenceSystem;
-import org.opengis.referencing.crs.GeographicCRS;
-import org.opengis.referencing.datum.GeodeticDatum;
-import org.opengis.referencing.operation.MathTransform;
-import org.openstreetmap.josm.Main;
 import org.openstreetmap.josm.data.Bounds;
-import org.openstreetmap.josm.data.coor.EastNorth;
 import org.openstreetmap.josm.data.coor.LatLon;
 import org.openstreetmap.josm.data.osm.DataSet;
 import org.openstreetmap.josm.data.osm.IPrimitive;
 import org.openstreetmap.josm.data.osm.OsmPrimitive;
-import org.openstreetmap.josm.data.projection.AbstractProjection;
-import org.openstreetmap.josm.data.projection.Ellipsoid;
-import org.openstreetmap.josm.data.projection.Projection;
-import org.openstreetmap.josm.data.projection.Projections;
-import org.openstreetmap.josm.data.projection.proj.LambertConformalConic;
-import org.openstreetmap.josm.data.projection.proj.LambertConformalConic.Parameters;
-import org.openstreetmap.josm.data.projection.proj.LambertConformalConic.Parameters1SP;
-import org.openstreetmap.josm.data.projection.proj.LambertConformalConic.Parameters2SP;
 import org.openstreetmap.josm.gui.preferences.SourceEditor.ExtendedSourceEntry;
 import org.openstreetmap.josm.io.AbstractReader;
 import org.openstreetmap.josm.plugins.opendata.core.OdConstants;
+import org.openstreetmap.josm.plugins.opendata.core.io.archive.DefaultZipHandler;
+import org.openstreetmap.josm.plugins.opendata.core.io.archive.ZipHandler;
+import org.openstreetmap.josm.plugins.opendata.core.io.geographic.DefaultShpHandler;
+import org.openstreetmap.josm.plugins.opendata.core.io.geographic.ShpHandler;
+import org.openstreetmap.josm.plugins.opendata.core.io.tabular.CsvHandler;
+import org.openstreetmap.josm.plugins.opendata.core.io.tabular.DefaultCsvHandler;
+import org.openstreetmap.josm.plugins.opendata.core.io.tabular.SpreadSheetHandler;
+import org.openstreetmap.josm.plugins.opendata.core.licenses.License;
 import org.openstreetmap.josm.plugins.opendata.core.util.NamesFrUtils;
 import org.openstreetmap.josm.tools.Pair;
@@ -99,7 +82,9 @@
 	private String sourceDate;
 	private File associatedFile;
-	private URL dataURL;
 
 	public AbstractDataSetHandler() {
+		setShpHandler(new DefaultShpHandler());
+		setZipHandler(new DefaultZipHandler());
+		setCsvHandler(new DefaultCsvHandler());
 	}
 	
@@ -178,20 +163,69 @@
 	}
 	
-	public URL getWikiURL() {return null;}
-	
-	public URL getLocalPortalURL() {return null;}
-	
-	public URL getNationalPortalURL() {return null;}
-
-	public URL getLicenseURL() {return null;}
-
-	public URL getDataURL() {return dataURL;}
-	
-	public final void setDataURL(String url) throws MalformedURLException {
-		this.dataURL = new URL(url);
-	}
-	
-	public final void setDataURL(URL url) {
-		this.dataURL = url;
+	// -------------------- License --------------------
+	
+	private License license;
+	
+	public License getLicense() {
+		return license;
+	}
+
+	public final void setLicense(License license) {
+		this.license = license;
+	}
+
+	// --------------------- URLs ---------------------
+	
+	private URL dataURL;
+	private URL wikiURL;
+	private URL localPortalURL;
+	private URL nationalPortalURL;
+	
+	public URL getDataURL() {
+		return dataURL;
+	}
+
+	public final void setDataURL(URL dataURL) {
+		this.dataURL = dataURL;
+	}
+
+	public final void setDataURL(String dataURL) throws MalformedURLException {
+		setDataURL(new URL(dataURL));
+	}
+
+	public URL getWikiURL() {
+		return wikiURL;
+	}
+
+	public final void setWikiURL(URL wikiURL) {
+		this.wikiURL = wikiURL;
+	}
+
+	public final void setWikiURL(String wikiURL) throws MalformedURLException {
+		setWikiURL(new URL(wikiURL));
+	}
+
+	public URL getLocalPortalURL() {
+		return localPortalURL;
+	}
+
+	public final void setLocalPortalURL(URL localPortalURL) {
+		this.localPortalURL = localPortalURL;
+	}
+
+	public final void setLocalPortalURL(String localPortalURL) throws MalformedURLException {
+		setLocalPortalURL(new URL(localPortalURL));
+	}
+
+	public URL getNationalPortalURL() {
+		return nationalPortalURL;
+	}
+
+	public final void setNationalPortalURL(URL nationalPortalURL) {
+		this.nationalPortalURL = nationalPortalURL;
+	}
+
+	public final void setNationalPortalURL(String nationalPortalURL) throws MalformedURLException {
+		setNationalPortalURL(new URL(nationalPortalURL));
 	}
 
@@ -199,4 +233,14 @@
 
 	public AbstractReader getReaderForUrl(String url) {return null;}
+	
+	private boolean hasLicenseToBeAccepted = true;
+
+	public final boolean hasLicenseToBeAccepted() {
+		return hasLicenseToBeAccepted;
+	}
+
+	public final void setHasLicenseToBeAccepted(boolean hasLicenseToBeAccepted) {
+		this.hasLicenseToBeAccepted = hasLicenseToBeAccepted;
+	}
 
 	public final DataSetCategory getCategory() {
@@ -226,79 +270,6 @@
 	}
 
-	public enum OaQueryType {
-		NODE ("node"),
-		WAY ("way"),
-		RELATION ("relation");
-		@Override
-		public String toString() { return this.value; }
-		private OaQueryType(final String value) { this.value = value; }
-		private final String value;
-	}
-
-	public enum OaRecurseType {
-		RELATION_RELATION ("relation-relation"),
-		RELATION_BACKWARDS ("relation-backwards"),
-		RELATION_WAY ("relation-way"),
-		RELATION_NODE ("relation-node"),
-		WAY_NODE ("way-node"),
-		WAY_RELATION ("way-relation"),
-		NODE_RELATION ("node-relation"),
-		NODE_WAY ("node-way");
-		@Override
-		public String toString() { return this.value; }
-		private OaRecurseType(final String value) { this.value = value; }
-		private final String value;
-	}
 
 	protected String getOverpassApiRequest(String bbox) {return null;}
-	
-	protected final String oaUnion(String ... queries) {
-		String result = "<union>\n";
-		for (String query : queries) {
-			if (query != null) {
-				result += query + "\n";
-			}
-		}
-		result += "</union>";
-		return result;
-	}
-	
-	protected final String oaQuery(String bbox, OaQueryType type, String ... conditions) {
-		String result = "<query type=\""+type+"\" >\n";
-		if (bbox != null) {
-			result += "<bbox-query "+bbox+"/>\n";
-		}
-		for (String condition : conditions) {
-			if (condition != null) {
-				result += condition + "\n";
-			}
-		}
-		result += "</query>";
-		return result;
-	}
-
-	protected final String oaRecurse(OaRecurseType type, String into) {
-		return "<recurse type=\""+type+"\" into=\""+into+"\"/>\n";
-	}
-
-	protected final String oaRecurse(OaRecurseType ... types) {
-		String result = "";
-		for (OaRecurseType type : types) {
-			result += "<recurse type=\""+type+"\"/>\n";
-		}
-		return result;
-	}
-	
-	protected final String oaPrint() {
-		return "<print mode=\"meta\"/>";
-	}
-	
-	protected final String oaHasKey(String key) {
-		return oaHasKey(key, null);
-	}
-
-	protected final String oaHasKey(String key, String value) {
-		return "<has-kv k=\""+key+"\" "+(value != null && !value.isEmpty() ? "v=\""+value+"\"" : "")+" />";
-	}
 
 	public boolean equals(IPrimitive p1, IPrimitive p2) {return false;}
@@ -405,28 +376,4 @@
 	}
 	
-	public boolean handlesSpreadSheetProjection() {
-		return false;
-	}
-	
-	public List<Projection> getSpreadSheetProjections() {
-		return null;
-	}
-
-	public LatLon getSpreadSheetCoor(EastNorth en, String[] fields) {
-		return null;
-	}
-	
-	public Charset getCsvCharset() {
-		return null;
-	}
-	
-	public String getCsvSeparator() {
-		return null;
-	}
-	
-	public int getSheetNumber() {
-		return -1;
-	}
-	
 	public ExtendedSourceEntry getMapPaintStyle() {
 		return null;
@@ -446,9 +393,5 @@
 				fileNameWithoutExtension+"."+MAPCSS_EXT);
 	}
-	
-	public boolean preferMultipolygonToSimpleWay() {
-		return false;
-	}
-	
+		
 	public final void setAssociatedFile(File associatedFile) {
 		this.associatedFile = associatedFile;
@@ -457,87 +400,4 @@
 	public final File getAssociatedFile() {
 		return this.associatedFile;
-	}
-	
-	private static final List<Pair<org.opengis.referencing.datum.Ellipsoid, Ellipsoid>> 
-		ellipsoids = new ArrayList<Pair<org.opengis.referencing.datum.Ellipsoid, Ellipsoid>>();
-	static {
-		ellipsoids.add(new Pair<org.opengis.referencing.datum.Ellipsoid, Ellipsoid>(DefaultEllipsoid.GRS80, Ellipsoid.GRS80));
-		ellipsoids.add(new Pair<org.opengis.referencing.datum.Ellipsoid, Ellipsoid>(DefaultEllipsoid.WGS84, Ellipsoid.WGS84));
-	}
-	
-	private static final Double get(ParameterValueGroup values, ParameterDescriptor desc) {
-		return (Double) values.parameter(desc.getName().getCode()).getValue();
-	}
-	
-	private static final boolean equals(Double a, Double b) {
-		boolean res = Math.abs(a - b) <= Main.pref.getDouble(PREF_CRS_COMPARISON_TOLERANCE, DEFAULT_CRS_COMPARISON_TOLERANCE);
-		if (Main.pref.getBoolean(PREF_CRS_COMPARISON_DEBUG, false)) {
-			System.out.println("Comparing "+a+" and "+b+" -> "+res);
-		}
-		return res; 
-	}
-	
-	public MathTransform findMathTransform(CoordinateReferenceSystem sourceCRS, CoordinateReferenceSystem targetCRS, boolean lenient) throws FactoryException {
-		if (sourceCRS instanceof GeographicCRS && sourceCRS.getName().getCode().equalsIgnoreCase("GCS_ETRS_1989")) {
-			return CRS.findMathTransform(CRS.decode("EPSG:4258"), targetCRS, lenient);
-		} else if (sourceCRS instanceof AbstractDerivedCRS && sourceCRS.getName().getCode().equalsIgnoreCase("Lambert_Conformal_Conic")) {
-			List<MathTransform> result = new ArrayList<MathTransform>();
-			AbstractDerivedCRS crs = (AbstractDerivedCRS) sourceCRS;
-			MathTransform transform = crs.getConversionFromBase().getMathTransform();
-			if (transform instanceof LambertConformal && crs.getDatum() instanceof GeodeticDatum) {
-				LambertConformal lambert = (LambertConformal) transform;
-				GeodeticDatum geo = (GeodeticDatum) crs.getDatum();
-				for (Projection p : Projections.getProjections()) {
-					if (p instanceof AbstractProjection) {
-						AbstractProjection ap = (AbstractProjection) p;
-						if (ap.getProj() instanceof LambertConformalConic) {
-							for (Pair<org.opengis.referencing.datum.Ellipsoid, Ellipsoid> pair : ellipsoids) {
-								if (pair.a.equals(geo.getEllipsoid()) && pair.b.equals(ap.getEllipsoid())) {
-									boolean ok = true;
-									ParameterValueGroup values = lambert.getParameterValues();
-									Parameters params = ((LambertConformalConic) ap.getProj()).getParameters();
-									
-									ok = ok ? equals(get(values, AbstractProvider.LATITUDE_OF_ORIGIN), params.latitudeOrigin) : ok;
-									ok = ok ? equals(get(values, AbstractProvider.CENTRAL_MERIDIAN), ap.getCentralMeridian()) : ok;
-									ok = ok ? equals(get(values, AbstractProvider.SCALE_FACTOR), ap.getScaleFactor()) : ok;
-									ok = ok ? equals(get(values, AbstractProvider.FALSE_EASTING), ap.getFalseEasting()) : ok;
-									ok = ok ? equals(get(values, AbstractProvider.FALSE_NORTHING), ap.getFalseNorthing()) : ok;
-									
-									if (lambert instanceof LambertConformal2SP && params instanceof Parameters2SP) {
-										Parameters2SP param = (Parameters2SP) params;
-										ok = ok ? equals(Math.min(get(values, AbstractProvider.STANDARD_PARALLEL_1),get(values, AbstractProvider.STANDARD_PARALLEL_2)), 
-														 Math.min(param.standardParallel1, param.standardParallel2)) : ok;
-										ok = ok ? equals(Math.max(get(values, AbstractProvider.STANDARD_PARALLEL_1), get(values, AbstractProvider.STANDARD_PARALLEL_2)),
-												         Math.max(param.standardParallel1, param.standardParallel2)) : ok;
-										
-									} else if (!(lambert instanceof LambertConformal1SP && params instanceof Parameters1SP)) {
-										ok = false;
-									}
-
-									if (ok) {
-										try {
-											result.add(CRS.findMathTransform(CRS.decode(p.toCode()), targetCRS, lenient));
-										} catch (FactoryException e) {
-											System.err.println(e.getMessage());
-										}
-									}
-								}
-							}
-						}
-					}
-				}
-			}
-			if (!result.isEmpty()) {
-				if (result.size() > 1) {
-					System.err.println("Found multiple projections !"); // TODO: something
-				}
-				return result.get(0);
-			}
-		}
-		return null;
-	}
-
-	public boolean checkShpNodeProximity() {
-		return false;
 	}
 	
@@ -555,17 +415,51 @@
 		return false;
 	}
-
-	private boolean setSkipXsdValidationInZipReading = false;
-	
-	public final void setSkipXsdValidationInZipReading(boolean skip) {
-		setSkipXsdValidationInZipReading = skip;
-	}
-	
-	public boolean skipXsdValidationInZipReading() {
-		return setSkipXsdValidationInZipReading;
-	}
-
-	public void notifyTempFileWritten(File file) {
-		// Do nothing, let handler overload this method if they need it
+	
+	// --------- Shapefile handling ---------
+	
+	private ShpHandler shpHandler;
+
+	public final void setShpHandler(ShpHandler handler) {
+		shpHandler = handler;
+	}
+	
+	public final ShpHandler getShpHandler() {
+		return shpHandler;
+	}
+
+	// ------------ Zip handling ------------
+	
+	private ZipHandler zipHandler;
+
+	public final void setZipHandler(ZipHandler handler) {
+		zipHandler = handler;
+	}
+	
+	public ZipHandler getZipHandler() {
+		return zipHandler;
+	}
+	
+	// ------ Spreadsheet handling ----------
+
+	private SpreadSheetHandler ssHandler;
+
+	public final void setSpreadSheetHandler(SpreadSheetHandler handler) {
+		ssHandler = handler;
+	}
+	
+	public final SpreadSheetHandler getSpreadSheetHandler() {
+		return ssHandler;
+	}
+
+	public final void setCsvHandler(CsvHandler handler) {
+		setSpreadSheetHandler(handler);
+	}
+	
+	public final CsvHandler getCsvHandler() {
+		if (ssHandler instanceof CsvHandler) {
+			return (CsvHandler) ssHandler;
+		} else {
+			return null;
+		}
 	}
 }
Index: applications/editors/josm/plugins/opendata/src/org/openstreetmap/josm/plugins/opendata/core/datasets/SimpleDataSetHandler.java
===================================================================
--- applications/editors/josm/plugins/opendata/src/org/openstreetmap/josm/plugins/opendata/core/datasets/SimpleDataSetHandler.java	(revision 28091)
+++ applications/editors/josm/plugins/opendata/src/org/openstreetmap/josm/plugins/opendata/core/datasets/SimpleDataSetHandler.java	(revision 28113)
@@ -1,11 +1,18 @@
+//    JOSM opendata plugin.
+//    Copyright (C) 2011-2012 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.opendata.core.datasets;
-
-import static org.openstreetmap.josm.plugins.opendata.core.datasets.AbstractDataSetHandler.OaQueryType.NODE;
-import static org.openstreetmap.josm.plugins.opendata.core.datasets.AbstractDataSetHandler.OaQueryType.WAY;
-import static org.openstreetmap.josm.plugins.opendata.core.datasets.AbstractDataSetHandler.OaQueryType.RELATION;
-import static org.openstreetmap.josm.plugins.opendata.core.datasets.AbstractDataSetHandler.OaRecurseType.NODE_RELATION;
-import static org.openstreetmap.josm.plugins.opendata.core.datasets.AbstractDataSetHandler.OaRecurseType.RELATION_WAY;
-import static org.openstreetmap.josm.plugins.opendata.core.datasets.AbstractDataSetHandler.OaRecurseType.WAY_NODE;
-import static org.openstreetmap.josm.plugins.opendata.core.datasets.AbstractDataSetHandler.OaRecurseType.WAY_RELATION;
 
 import java.util.ArrayList;
@@ -17,4 +24,8 @@
 import org.openstreetmap.josm.data.osm.Tag;
 import org.openstreetmap.josm.data.projection.Projection;
+import org.openstreetmap.josm.plugins.opendata.core.io.OverpassApi;
+
+import static org.openstreetmap.josm.plugins.opendata.core.io.OverpassApi.OaQueryType.*;
+import static org.openstreetmap.josm.plugins.opendata.core.io.OverpassApi.OaRecurseType.*;
 
 public abstract class SimpleDataSetHandler extends AbstractDataSetHandler {
@@ -155,5 +166,5 @@
 		List<String> conditions = new ArrayList<String>();
 		for (Tag tag : this.relevantTags) {
-			conditions.add(oaHasKey(tag.getKey(), tag.getValue()));
+			conditions.add(OverpassApi.hasKey(tag.getKey(), tag.getValue()));
 		}
 		return conditions.toArray(new String[0]);
@@ -162,15 +173,15 @@
 	protected String getOverpassApiQueries(String bbox, String ... conditions) {
 		String[] mpconditions = new String[conditions.length+1];
-		mpconditions[0] = oaHasKey("type", "multipolygon");
+		mpconditions[0] = OverpassApi.hasKey("type", "multipolygon");
 		for (int i=0; i<conditions.length; i++) {
 			mpconditions[i+1] = conditions[i];
 		}
-		return oaQuery(bbox, NODE, conditions) + "\n" + // Nodes 
-				oaRecurse(NODE_RELATION, RELATION_WAY, WAY_NODE) + "\n" +
-				oaQuery(bbox, WAY, conditions) + "\n" + // Full ways and their full relations 
-				oaRecurse(WAY_NODE, "nodes") + "\n" +
-				oaRecurse(WAY_RELATION, RELATION_WAY, WAY_NODE) + "\n" +
-				oaQuery(bbox, RELATION, mpconditions) + "\n" + // Full multipolygons
-				oaRecurse(RELATION_WAY, WAY_NODE);
+		return OverpassApi.query(bbox, NODE, conditions) + "\n" + // Nodes 
+			OverpassApi.recurse(NODE_RELATION, RELATION_WAY, WAY_NODE) + "\n" +
+			OverpassApi.query(bbox, WAY, conditions) + "\n" + // Full ways and their full relations 
+			OverpassApi.recurse(WAY_NODE, "nodes") + "\n" +
+			OverpassApi.recurse(WAY_RELATION, RELATION_WAY, WAY_NODE) + "\n" +
+			OverpassApi.query(bbox, RELATION, mpconditions) + "\n" + // Full multipolygons
+			OverpassApi.recurse(RELATION_WAY, WAY_NODE);
 	}
 	
@@ -183,11 +194,11 @@
 		if (this.relevantUnion) {
 			for (Tag tag : this.relevantTags) {
-				result += getOverpassApiQueries(bbox, oaHasKey(tag.getKey(), tag.getValue())); 
-			}
-			result = oaUnion(result);
+				result += getOverpassApiQueries(bbox, OverpassApi.hasKey(tag.getKey(), tag.getValue())); 
+			}
+			result = OverpassApi.union(result);
 		} else {
-			result = oaUnion(getOverpassApiQueries(bbox, getOverpassApiConditions()));
-		}
-		return result + oaPrint();
+			result = OverpassApi.union(getOverpassApiQueries(bbox, getOverpassApiConditions()));
+		}
+		return result + OverpassApi.print();
 	}
 
Index: applications/editors/josm/plugins/opendata/src/org/openstreetmap/josm/plugins/opendata/core/datasets/be/BelgianDataSetHandler.java
===================================================================
--- applications/editors/josm/plugins/opendata/src/org/openstreetmap/josm/plugins/opendata/core/datasets/be/BelgianDataSetHandler.java	(revision 28091)
+++ applications/editors/josm/plugins/opendata/src/org/openstreetmap/josm/plugins/opendata/core/datasets/be/BelgianDataSetHandler.java	(revision 28113)
@@ -18,6 +18,4 @@
 import java.net.MalformedURLException;
 import java.net.URL;
-import java.util.Arrays;
-import java.util.List;
 import java.util.Locale;
 
@@ -28,4 +26,5 @@
 import org.openstreetmap.josm.data.projection.Projection;
 import org.openstreetmap.josm.plugins.opendata.core.datasets.SimpleDataSetHandler;
+import org.openstreetmap.josm.plugins.opendata.core.io.tabular.DefaultCsvHandler;
 
 public abstract class BelgianDataSetHandler extends SimpleDataSetHandler implements BelgianConstants {
@@ -45,21 +44,48 @@
 		lambert2008
 	};
+	
+	protected class InternalCsvHandler extends DefaultCsvHandler {
+		/*@Override
+		public List<Projection> getSpreadSheetProjections() {
+			if (singleProjection != null) {
+				return Arrays.asList(new Projection[]{singleProjection});
+			} else {
+				return Arrays.asList(projections);
+			}
+		}*/
+		
+		@Override
+		public LatLon getCoor(EastNorth en, String[] fields) {
+			if (singleProjection != null) {
+				return singleProjection.eastNorth2latlon(en);
+			} else {
+				return super.getCoor(en, fields);
+			}
+		}
+	}
 
 	public BelgianDataSetHandler() {
-		
+		init();
 	}
 
 	public BelgianDataSetHandler(String relevantTag) {
 		super(relevantTag);
+		init();
 	}
 
 	public BelgianDataSetHandler(boolean relevantUnion, String[] relevantTags) {
 		super(relevantUnion, relevantTags);
+		init();
 	}
 
 	public BelgianDataSetHandler(boolean relevantUnion, Tag[] relevantTags) {
 		super(relevantUnion, relevantTags);
+		init();
 	}
 	
+	private void init() {
+		setCsvHandler(new InternalCsvHandler());
+	}
+
 	protected final void setNationalPortalPath(String nationalPortalPathDe, String nationalPortalPathEn, String nationalPortalPathFr, String nationalPortalPathNl) {
 		this.nationalPortalPathDe = nationalPortalPathDe;
@@ -71,4 +97,5 @@
 	protected final void setSingleProjection(Projection singleProjection) {
 		this.singleProjection = singleProjection;
+		getCsvHandler().setHandlesProjection(singleProjection != null);
 	}
 
@@ -116,35 +143,3 @@
 		return ICON_BE_24;
 	}
-	
-	/* (non-Javadoc)
-	 * @see org.openstreetmap.josm.plugins.opendata.core.datasets.AbstractDataSetHandler#handlesCsvProjection()
-	 */
-	@Override
-	public boolean handlesSpreadSheetProjection() {
-		return singleProjection != null ? true : super.handlesSpreadSheetProjection();
-	}
-	
-	/* (non-Javadoc)
-	 * @see org.openstreetmap.josm.plugins.opendata.core.datasets.AbstractDataSetHandler#getCsvProjections()
-	 */
-	@Override
-	public List<Projection> getSpreadSheetProjections() {
-		if (singleProjection != null) {
-			return Arrays.asList(new Projection[]{singleProjection});
-		} else {
-			return Arrays.asList(projections);
-		}
-	}
-	
-	/* (non-Javadoc)
-	 * @see org.openstreetmap.josm.plugins.opendata.core.datasets.AbstractDataSetHandler#getCsvCoor(org.openstreetmap.josm.data.coor.EastNorth, java.lang.String[])
-	 */
-	@Override
-	public LatLon getSpreadSheetCoor(EastNorth en, String[] fields) {
-		if (singleProjection != null) {
-			return singleProjection.eastNorth2latlon(en);
-		} else {
-			return super.getSpreadSheetCoor(en, fields);
-		}
-	}
 }
Index: applications/editors/josm/plugins/opendata/src/org/openstreetmap/josm/plugins/opendata/core/datasets/fr/FrenchDataSetHandler.java
===================================================================
--- applications/editors/josm/plugins/opendata/src/org/openstreetmap/josm/plugins/opendata/core/datasets/fr/FrenchDataSetHandler.java	(revision 28091)
+++ applications/editors/josm/plugins/opendata/src/org/openstreetmap/josm/plugins/opendata/core/datasets/fr/FrenchDataSetHandler.java	(revision 28113)
@@ -21,12 +21,7 @@
 import java.net.URL;
 import java.util.Arrays;
-import java.util.List;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 
-import org.geotools.referencing.CRS;
-import org.opengis.referencing.FactoryException;
-import org.opengis.referencing.crs.CoordinateReferenceSystem;
-import org.opengis.referencing.operation.MathTransform;
 import org.openstreetmap.josm.data.coor.EastNorth;
 import org.openstreetmap.josm.data.coor.LatLon;
@@ -38,4 +33,5 @@
 import org.openstreetmap.josm.data.projection.UTM.Hemisphere;
 import org.openstreetmap.josm.plugins.opendata.core.datasets.SimpleDataSetHandler;
+import org.openstreetmap.josm.plugins.opendata.core.io.tabular.DefaultCsvHandler;
 
 public abstract class FrenchDataSetHandler extends SimpleDataSetHandler implements FrenchConstants {
@@ -66,21 +62,54 @@
 		utm40, // Reunion
 	};
+	
+	protected class InternalCsvHandler extends DefaultCsvHandler {
+		/*@Override
+		public List<Projection> getSpreadSheetProjections() {
+			if (singleProjection != null) {
+				return Arrays.asList(new Projection[]{singleProjection});
+			} else {
+				return Arrays.asList(projections);
+			}
+		}*/
+		
+		@Override
+		public LatLon getCoor(EastNorth en, String[] fields) {
+			if (singleProjection != null) {
+				return singleProjection.eastNorth2latlon(en);
+			} else {
+				return super.getCoor(en, fields);
+			}
+		}
+
+		@Override
+		public boolean handlesProjection() {
+			return singleProjection != null;
+		}
+	}
 
 	public FrenchDataSetHandler() {
-		
+		init();
 	}
 
 	public FrenchDataSetHandler(String relevantTag) {
 		super(relevantTag);
+		init();
 	}
 
 	public FrenchDataSetHandler(boolean relevantUnion, String[] relevantTags) {
 		super(relevantUnion, relevantTags);
+		init();
 	}
 
 	public FrenchDataSetHandler(boolean relevantUnion, Tag[] relevantTags) {
 		super(relevantUnion, relevantTags);
-	}
-	
+		init();
+	}
+	
+	private void init() {
+		setShpHandler(new FrenchShpHandler());
+		setCsvHandler(new InternalCsvHandler());
+	}
+
 	protected final void setNationalPortalPath(String nationalPortalPath) {
 		this.nationalPortalPath = nationalPortalPath;
@@ -120,36 +149,4 @@
 	public String getNationalPortalIconName() {
 		return ICON_FR_24;
-	}
-	
-	/* (non-Javadoc)
-	 * @see org.openstreetmap.josm.plugins.opendata.core.datasets.AbstractDataSetHandler#handlesCsvProjection()
-	 */
-	@Override
-	public boolean handlesSpreadSheetProjection() {
-		return singleProjection != null ? true : super.handlesSpreadSheetProjection();
-	}
-	
-	/* (non-Javadoc)
-	 * @see org.openstreetmap.josm.plugins.opendata.core.datasets.AbstractDataSetHandler#getCsvProjections()
-	 */
-	@Override
-	public List<Projection> getSpreadSheetProjections() {
-		if (singleProjection != null) {
-			return Arrays.asList(new Projection[]{singleProjection});
-		} else {
-			return Arrays.asList(projections);
-		}
-	}
-	
-	/* (non-Javadoc)
-	 * @see org.openstreetmap.josm.plugins.opendata.core.datasets.AbstractDataSetHandler#getCsvCoor(org.openstreetmap.josm.data.coor.EastNorth, java.lang.String[])
-	 */
-	@Override
-	public LatLon getSpreadSheetCoor(EastNorth en, String[] fields) {
-		if (singleProjection != null) {
-			return singleProjection.eastNorth2latlon(en);
-		} else {
-			return super.getSpreadSheetCoor(en, fields);
-		}
 	}
 	
@@ -258,18 +255,3 @@
 		return "";
 	}
-
-	/* (non-Javadoc)
-	 * @see org.openstreetmap.josm.plugins.opendata.core.datasets.AbstractDataSetHandler#findMathTransform(org.opengis.referencing.crs.CoordinateReferenceSystem, org.opengis.referencing.crs.CoordinateReferenceSystem, boolean)
-	 */
-	@Override
-	public MathTransform findMathTransform(CoordinateReferenceSystem sourceCRS, CoordinateReferenceSystem targetCRS, boolean lenient)
-			throws FactoryException {
-		if (sourceCRS.getName().getCode().equalsIgnoreCase("RGM04")) {
-			return CRS.findMathTransform(CRS.decode("EPSG:4471"), targetCRS, lenient);
-		} else if (sourceCRS.getName().getCode().equalsIgnoreCase("RGFG95_UTM_Zone_22N")) {
-			return CRS.findMathTransform(CRS.decode("EPSG:2972"), targetCRS, lenient);
-		} else {
-			return super.findMathTransform(sourceCRS, targetCRS, lenient);
-		}
-	}
 }
Index: applications/editors/josm/plugins/opendata/src/org/openstreetmap/josm/plugins/opendata/core/datasets/fr/FrenchShpHandler.java
===================================================================
--- applications/editors/josm/plugins/opendata/src/org/openstreetmap/josm/plugins/opendata/core/datasets/fr/FrenchShpHandler.java	(revision 28113)
+++ applications/editors/josm/plugins/opendata/src/org/openstreetmap/josm/plugins/opendata/core/datasets/fr/FrenchShpHandler.java	(revision 28113)
@@ -0,0 +1,40 @@
+//    JOSM opendata plugin.
+//    Copyright (C) 2011-2012 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.opendata.core.datasets.fr;
+
+import org.geotools.referencing.CRS;
+import org.opengis.referencing.FactoryException;
+import org.opengis.referencing.crs.CoordinateReferenceSystem;
+import org.opengis.referencing.operation.MathTransform;
+import org.openstreetmap.josm.plugins.opendata.core.io.geographic.DefaultShpHandler;
+
+public class FrenchShpHandler extends DefaultShpHandler {
+
+	/* (non-Javadoc)
+	 * @see org.openstreetmap.josm.plugins.opendata.core.datasets.AbstractDataSetHandler#findMathTransform(org.opengis.referencing.crs.CoordinateReferenceSystem, org.opengis.referencing.crs.CoordinateReferenceSystem, boolean)
+	 */
+	@Override
+	public MathTransform findMathTransform(CoordinateReferenceSystem sourceCRS, CoordinateReferenceSystem targetCRS, boolean lenient)
+			throws FactoryException {
+		if (sourceCRS.getName().getCode().equalsIgnoreCase("RGM04")) {
+			return CRS.findMathTransform(CRS.decode("EPSG:4471"), targetCRS, lenient);
+		} else if (sourceCRS.getName().getCode().equalsIgnoreCase("RGFG95_UTM_Zone_22N")) {
+			return CRS.findMathTransform(CRS.decode("EPSG:2972"), targetCRS, lenient);
+		} else {
+			return super.findMathTransform(sourceCRS, targetCRS, lenient);
+		}
+	}
+}
Index: applications/editors/josm/plugins/opendata/src/org/openstreetmap/josm/plugins/opendata/core/gui/AskLicenseAgreementDialog.java
===================================================================
--- applications/editors/josm/plugins/opendata/src/org/openstreetmap/josm/plugins/opendata/core/gui/AskLicenseAgreementDialog.java	(revision 28113)
+++ applications/editors/josm/plugins/opendata/src/org/openstreetmap/josm/plugins/opendata/core/gui/AskLicenseAgreementDialog.java	(revision 28113)
@@ -0,0 +1,91 @@
+package org.openstreetmap.josm.plugins.opendata.core.gui;
+
+import static org.openstreetmap.josm.tools.I18n.tr;
+
+import java.awt.Dimension;
+import java.awt.event.ActionEvent;
+import java.io.IOException;
+
+import javax.swing.Icon;
+import javax.swing.JEditorPane;
+import javax.swing.JOptionPane;
+import javax.swing.JScrollPane;
+
+import org.openstreetmap.josm.Main;
+import org.openstreetmap.josm.gui.ExtendedDialog;
+import org.openstreetmap.josm.plugins.opendata.core.licenses.License;
+import org.openstreetmap.josm.tools.ImageProvider;
+
+public class AskLicenseAgreementDialog extends ExtendedDialog {
+
+	private final License license;
+	private final JEditorPane htmlPane;
+	private boolean summary;
+	
+	public AskLicenseAgreementDialog(License license) throws IOException {
+		super(Main.parent, tr("License Agreement"), new String[] {tr("Accept"), "", tr("Refuse")});
+		
+		this.license = license;
+		this.htmlPane = new JEditorPane();
+		//htmlPane.setEditorKitForContentType(pdfEditorKit.getContentType(), pdfEditorKit);
+		htmlPane.setEditable(false);
+		if (license.getSummaryURL() != null) {
+			htmlPane.setPage(license.getSummaryURL());
+			summary = true;
+		} else {
+			htmlPane.setPage(license.getURL());
+			summary = false;
+		}
+		JScrollPane scrollPane = new JScrollPane(htmlPane);
+		scrollPane.setPreferredSize(new Dimension(800, 600));
+        
+        setButtonIcons(new Icon[] {
+                ImageProvider.get("ok"),
+                ImageProvider.get("agreement24"),
+                ImageProvider.get("cancel"),
+                });
+        setToolTipTexts(new String[] {
+                tr("I understand and accept these terms and conditions"),
+                tr("View the full text of this license"),
+                tr("I refuse these terms and conditions. Cancel download.")});
+        if (license.getIcon() != null) {
+        	setIcon(license.getIcon());
+        } else {
+        	setIcon(JOptionPane.INFORMATION_MESSAGE);
+        }
+        setCancelButton(3);
+        setMinimumSize(new Dimension(300, 200));
+        setContent(scrollPane, false);
+	}
+
+	@Override
+	protected void buttonAction(int buttonIndex, ActionEvent evt) {
+		if (buttonIndex == 1) {
+			try {
+				if (summary) {
+					buttons.get(1).setText(tr("View summary"));
+					htmlPane.setPage(license.getURL());
+				} else {
+					buttons.get(1).setText(tr("View full text"));
+					htmlPane.setPage(license.getSummaryURL());
+				}
+			} catch (IOException e) {
+				e.printStackTrace();
+			}
+			summary = !summary;
+		} else {
+			super.buttonAction(buttonIndex, evt);
+		}
+	}
+
+	@Override
+	public void setupDialog() {
+		super.setupDialog();
+		buttons.get(1).setEnabled(license.getSummaryURL() != null && license.getURL() != null);
+		if (summary) {
+			buttons.get(1).setText(tr("View full text"));
+		} else {
+			buttons.get(1).setText(tr("View summary"));
+		}
+	}
+}
Index: applications/editors/josm/plugins/opendata/src/org/openstreetmap/josm/plugins/opendata/core/io/NetworkReader.java
===================================================================
--- applications/editors/josm/plugins/opendata/src/org/openstreetmap/josm/plugins/opendata/core/io/NetworkReader.java	(revision 28091)
+++ applications/editors/josm/plugins/opendata/src/org/openstreetmap/josm/plugins/opendata/core/io/NetworkReader.java	(revision 28113)
@@ -50,10 +50,9 @@
 	private String filename;
 	
-    public NetworkReader(String url, AbstractDataSetHandler handler, Class<? extends AbstractReader> readerClass) {
+    public NetworkReader(String url, AbstractDataSetHandler handler) {
         CheckParameterUtil.ensureParameterNotNull(url, "url");
-        //CheckParameterUtil.ensureParameterNotNull(readerClass, "readerClass");
     	this.url = url;
-        this.readerClass = readerClass;
         this.handler = handler;
+        this.readerClass = null;
     }
     
Index: applications/editors/josm/plugins/opendata/src/org/openstreetmap/josm/plugins/opendata/core/io/OverpassApi.java
===================================================================
--- applications/editors/josm/plugins/opendata/src/org/openstreetmap/josm/plugins/opendata/core/io/OverpassApi.java	(revision 28113)
+++ applications/editors/josm/plugins/opendata/src/org/openstreetmap/josm/plugins/opendata/core/io/OverpassApi.java	(revision 28113)
@@ -0,0 +1,93 @@
+//    JOSM opendata plugin.
+//    Copyright (C) 2011-2012 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.opendata.core.io;
+
+public abstract class OverpassApi {
+
+	public enum OaQueryType {
+		NODE ("node"),
+		WAY ("way"),
+		RELATION ("relation");
+		@Override
+		public String toString() { return this.value; }
+		private OaQueryType(final String value) { this.value = value; }
+		private final String value;
+	}
+
+	public enum OaRecurseType {
+		RELATION_RELATION ("relation-relation"),
+		RELATION_BACKWARDS ("relation-backwards"),
+		RELATION_WAY ("relation-way"),
+		RELATION_NODE ("relation-node"),
+		WAY_NODE ("way-node"),
+		WAY_RELATION ("way-relation"),
+		NODE_RELATION ("node-relation"),
+		NODE_WAY ("node-way");
+		@Override
+		public String toString() { return this.value; }
+		private OaRecurseType(final String value) { this.value = value; }
+		private final String value;
+	}
+	
+	public static final String union(String ... queries) {
+		String result = "<union>\n";
+		for (String query : queries) {
+			if (query != null) {
+				result += query + "\n";
+			}
+		}
+		result += "</union>";
+		return result;
+	}
+	
+	public static final String query(String bbox, OaQueryType type, String ... conditions) {
+		String result = "<query type=\""+type+"\" >\n";
+		if (bbox != null) {
+			result += "<bbox-query "+bbox+"/>\n";
+		}
+		for (String condition : conditions) {
+			if (condition != null) {
+				result += condition + "\n";
+			}
+		}
+		result += "</query>";
+		return result;
+	}
+
+	public static final String recurse(OaRecurseType type, String into) {
+		return "<recurse type=\""+type+"\" into=\""+into+"\"/>\n";
+	}
+
+	public static final String recurse(OaRecurseType ... types) {
+		String result = "";
+		for (OaRecurseType type : types) {
+			result += "<recurse type=\""+type+"\"/>\n";
+		}
+		return result;
+	}
+	
+	public static final String print() {
+		return "<print mode=\"meta\"/>";
+	}
+	
+	public static final String hasKey(String key) {
+		return hasKey(key, null);
+	}
+
+	public static final String hasKey(String key, String value) {
+		return "<has-kv k=\""+key+"\" "+(value != null && !value.isEmpty() ? "v=\""+value+"\"" : "")+" />";
+	}
+}
Index: applications/editors/josm/plugins/opendata/src/org/openstreetmap/josm/plugins/opendata/core/io/archive/DefaultZipHandler.java
===================================================================
--- applications/editors/josm/plugins/opendata/src/org/openstreetmap/josm/plugins/opendata/core/io/archive/DefaultZipHandler.java	(revision 28113)
+++ applications/editors/josm/plugins/opendata/src/org/openstreetmap/josm/plugins/opendata/core/io/archive/DefaultZipHandler.java	(revision 28113)
@@ -0,0 +1,38 @@
+//    JOSM opendata plugin.
+//    Copyright (C) 2011-2012 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.opendata.core.io.archive;
+
+import java.io.File;
+
+public class DefaultZipHandler implements ZipHandler {
+
+	private boolean skipXsdValidation = false;
+	
+	@Override
+	public final void setSkipXsdValidation(boolean skip) {
+		skipXsdValidation = skip;
+	}
+	
+	@Override
+	public boolean skipXsdValidation() {
+		return skipXsdValidation;
+	}
+	
+	@Override
+	public void notifyTempFileWritten(File file) {
+		// Do nothing, let subclass override this method if they need it
+	}
+}
Index: applications/editors/josm/plugins/opendata/src/org/openstreetmap/josm/plugins/opendata/core/io/archive/ZipHandler.java
===================================================================
--- applications/editors/josm/plugins/opendata/src/org/openstreetmap/josm/plugins/opendata/core/io/archive/ZipHandler.java	(revision 28113)
+++ applications/editors/josm/plugins/opendata/src/org/openstreetmap/josm/plugins/opendata/core/io/archive/ZipHandler.java	(revision 28113)
@@ -0,0 +1,27 @@
+//    JOSM opendata plugin.
+//    Copyright (C) 2011-2012 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.opendata.core.io.archive;
+
+import java.io.File;
+
+public interface ZipHandler {
+
+	public void notifyTempFileWritten(File file);
+
+	public boolean skipXsdValidation();
+
+	public void setSkipXsdValidation(boolean skip);
+}
Index: applications/editors/josm/plugins/opendata/src/org/openstreetmap/josm/plugins/opendata/core/io/archive/ZipReader.java
===================================================================
--- applications/editors/josm/plugins/opendata/src/org/openstreetmap/josm/plugins/opendata/core/io/archive/ZipReader.java	(revision 28091)
+++ applications/editors/josm/plugins/opendata/src/org/openstreetmap/josm/plugins/opendata/core/io/archive/ZipReader.java	(revision 28113)
@@ -50,4 +50,5 @@
 	private final ZipInputStream zis;
 	private final AbstractDataSetHandler handler;
+	private final ZipHandler zipHandler;
 	
 	private File file;
@@ -56,4 +57,5 @@
         this.zis = in instanceof ZipInputStream ? (ZipInputStream) in : new ZipInputStream(in);
         this.handler = handler;
+        this.zipHandler = handler != null ? handler.getZipHandler() : null;
     }
 
@@ -116,6 +118,6 @@
 					fos.close();
 					// Allow handler to perform specific treatments (for example, fix invalid .prj files)
-					if (handler != null) {
-						handler.notifyTempFileWritten(file);
+					if (zipHandler != null) {
+						zipHandler.notifyTempFileWritten(file);
 					}
 					// Set last modification date
@@ -135,5 +137,5 @@
 					}
 					// Special treatment for XML files (check supported XSD), unless handler explicitely skip it
-					if (XML_FILE_FILTER.accept(file) && ((handler != null && handler.skipXsdValidationInZipReading()) 
+					if (XML_FILE_FILTER.accept(file) && ((zipHandler != null && zipHandler.skipXsdValidation()) 
 							|| OdPlugin.getInstance().xmlImporter.acceptFile(file))) {
 						candidates.add(file);
Index: applications/editors/josm/plugins/opendata/src/org/openstreetmap/josm/plugins/opendata/core/io/geographic/DefaultShpHandler.java
===================================================================
--- applications/editors/josm/plugins/opendata/src/org/openstreetmap/josm/plugins/opendata/core/io/geographic/DefaultShpHandler.java	(revision 28113)
+++ applications/editors/josm/plugins/opendata/src/org/openstreetmap/josm/plugins/opendata/core/io/geographic/DefaultShpHandler.java	(revision 28113)
@@ -0,0 +1,153 @@
+//    JOSM opendata plugin.
+//    Copyright (C) 2011-2012 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.opendata.core.io.geographic;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.geotools.referencing.CRS;
+import org.geotools.referencing.crs.AbstractDerivedCRS;
+import org.geotools.referencing.datum.DefaultEllipsoid;
+import org.geotools.referencing.operation.projection.LambertConformal;
+import org.geotools.referencing.operation.projection.LambertConformal1SP;
+import org.geotools.referencing.operation.projection.LambertConformal2SP;
+import org.geotools.referencing.operation.projection.MapProjection.AbstractProvider;
+import org.opengis.parameter.ParameterDescriptor;
+import org.opengis.parameter.ParameterValueGroup;
+import org.opengis.referencing.FactoryException;
+import org.opengis.referencing.crs.CoordinateReferenceSystem;
+import org.opengis.referencing.crs.GeographicCRS;
+import org.opengis.referencing.datum.GeodeticDatum;
+import org.opengis.referencing.operation.MathTransform;
+import org.openstreetmap.josm.Main;
+import org.openstreetmap.josm.data.projection.AbstractProjection;
+import org.openstreetmap.josm.data.projection.Ellipsoid;
+import org.openstreetmap.josm.data.projection.Projection;
+import org.openstreetmap.josm.data.projection.Projections;
+import org.openstreetmap.josm.data.projection.proj.LambertConformalConic;
+import org.openstreetmap.josm.data.projection.proj.LambertConformalConic.Parameters;
+import org.openstreetmap.josm.data.projection.proj.LambertConformalConic.Parameters1SP;
+import org.openstreetmap.josm.data.projection.proj.LambertConformalConic.Parameters2SP;
+import org.openstreetmap.josm.plugins.opendata.core.OdConstants;
+import org.openstreetmap.josm.tools.Pair;
+
+public class DefaultShpHandler implements ShpHandler, OdConstants {
+
+	private static final List<Pair<org.opengis.referencing.datum.Ellipsoid, Ellipsoid>> 
+		ellipsoids = new ArrayList<Pair<org.opengis.referencing.datum.Ellipsoid, Ellipsoid>>();
+	static {
+		ellipsoids.add(new Pair<org.opengis.referencing.datum.Ellipsoid, Ellipsoid>(DefaultEllipsoid.GRS80, Ellipsoid.GRS80));
+		ellipsoids.add(new Pair<org.opengis.referencing.datum.Ellipsoid, Ellipsoid>(DefaultEllipsoid.WGS84, Ellipsoid.WGS84));
+	}
+	
+	private static final Double get(ParameterValueGroup values, ParameterDescriptor desc) {
+		return (Double) values.parameter(desc.getName().getCode()).getValue();
+	}
+	
+	private static final boolean equals(Double a, Double b) {
+		boolean res = Math.abs(a - b) <= Main.pref.getDouble(PREF_CRS_COMPARISON_TOLERANCE, DEFAULT_CRS_COMPARISON_TOLERANCE);
+		if (Main.pref.getBoolean(PREF_CRS_COMPARISON_DEBUG, false)) {
+			System.out.println("Comparing "+a+" and "+b+" -> "+res);
+		}
+		return res; 
+	}
+	
+	private boolean checkNodeProximity = false;
+	private boolean preferMultipolygonToSimpleWay = false;
+
+	@Override
+	public MathTransform findMathTransform(CoordinateReferenceSystem sourceCRS,
+			CoordinateReferenceSystem targetCRS, boolean lenient)
+			throws FactoryException {
+		if (sourceCRS instanceof GeographicCRS && sourceCRS.getName().getCode().equalsIgnoreCase("GCS_ETRS_1989")) {
+			return CRS.findMathTransform(CRS.decode("EPSG:4258"), targetCRS, lenient);
+		} else if (sourceCRS instanceof AbstractDerivedCRS && sourceCRS.getName().getCode().equalsIgnoreCase("Lambert_Conformal_Conic")) {
+			List<MathTransform> result = new ArrayList<MathTransform>();
+			AbstractDerivedCRS crs = (AbstractDerivedCRS) sourceCRS;
+			MathTransform transform = crs.getConversionFromBase().getMathTransform();
+			if (transform instanceof LambertConformal && crs.getDatum() instanceof GeodeticDatum) {
+				LambertConformal lambert = (LambertConformal) transform;
+				GeodeticDatum geo = (GeodeticDatum) crs.getDatum();
+				for (Projection p : Projections.getProjections()) {
+					if (p instanceof AbstractProjection) {
+						AbstractProjection ap = (AbstractProjection) p;
+						if (ap.getProj() instanceof LambertConformalConic) {
+							for (Pair<org.opengis.referencing.datum.Ellipsoid, Ellipsoid> pair : ellipsoids) {
+								if (pair.a.equals(geo.getEllipsoid()) && pair.b.equals(ap.getEllipsoid())) {
+									boolean ok = true;
+									ParameterValueGroup values = lambert.getParameterValues();
+									Parameters params = ((LambertConformalConic) ap.getProj()).getParameters();
+									
+									ok = ok ? equals(get(values, AbstractProvider.LATITUDE_OF_ORIGIN), params.latitudeOrigin) : ok;
+									ok = ok ? equals(get(values, AbstractProvider.CENTRAL_MERIDIAN), ap.getCentralMeridian()) : ok;
+									ok = ok ? equals(get(values, AbstractProvider.SCALE_FACTOR), ap.getScaleFactor()) : ok;
+									ok = ok ? equals(get(values, AbstractProvider.FALSE_EASTING), ap.getFalseEasting()) : ok;
+									ok = ok ? equals(get(values, AbstractProvider.FALSE_NORTHING), ap.getFalseNorthing()) : ok;
+									
+									if (lambert instanceof LambertConformal2SP && params instanceof Parameters2SP) {
+										Parameters2SP param = (Parameters2SP) params;
+										ok = ok ? equals(Math.min(get(values, AbstractProvider.STANDARD_PARALLEL_1),get(values, AbstractProvider.STANDARD_PARALLEL_2)), 
+														 Math.min(param.standardParallel1, param.standardParallel2)) : ok;
+										ok = ok ? equals(Math.max(get(values, AbstractProvider.STANDARD_PARALLEL_1), get(values, AbstractProvider.STANDARD_PARALLEL_2)),
+												         Math.max(param.standardParallel1, param.standardParallel2)) : ok;
+										
+									} else if (!(lambert instanceof LambertConformal1SP && params instanceof Parameters1SP)) {
+										ok = false;
+									}
+
+									if (ok) {
+										try {
+											result.add(CRS.findMathTransform(CRS.decode(p.toCode()), targetCRS, lenient));
+										} catch (FactoryException e) {
+											System.err.println(e.getMessage());
+										}
+									}
+								}
+							}
+						}
+					}
+				}
+			}
+			if (!result.isEmpty()) {
+				if (result.size() > 1) {
+					System.err.println("Found multiple projections !"); // TODO: something
+				}
+				return result.get(0);
+			}
+		}
+		return null;
+	}
+
+	@Override
+	public boolean preferMultipolygonToSimpleWay() {
+		return preferMultipolygonToSimpleWay;
+	}
+
+	@Override
+	public void setPreferMultipolygonToSimpleWay(boolean prefer) {
+		preferMultipolygonToSimpleWay = prefer;
+	}
+
+	@Override
+	public boolean checkNodeProximity() {
+		return checkNodeProximity;
+	}
+
+	@Override
+	public void setCheckNodeProximity(boolean check) {
+		checkNodeProximity = check;
+	}
+}
Index: applications/editors/josm/plugins/opendata/src/org/openstreetmap/josm/plugins/opendata/core/io/geographic/ShpHandler.java
===================================================================
--- applications/editors/josm/plugins/opendata/src/org/openstreetmap/josm/plugins/opendata/core/io/geographic/ShpHandler.java	(revision 28113)
+++ applications/editors/josm/plugins/opendata/src/org/openstreetmap/josm/plugins/opendata/core/io/geographic/ShpHandler.java	(revision 28113)
@@ -0,0 +1,33 @@
+//    JOSM opendata plugin.
+//    Copyright (C) 2011-2012 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.opendata.core.io.geographic;
+
+import org.opengis.referencing.FactoryException;
+import org.opengis.referencing.crs.CoordinateReferenceSystem;
+import org.opengis.referencing.operation.MathTransform;
+
+public interface ShpHandler {
+
+	public MathTransform findMathTransform(CoordinateReferenceSystem sourceCRS, CoordinateReferenceSystem targetCRS, boolean lenient) throws FactoryException;
+
+	public void setPreferMultipolygonToSimpleWay(boolean prefer);
+
+	public boolean preferMultipolygonToSimpleWay();
+
+	public void setCheckNodeProximity(boolean check);
+	
+	public boolean checkNodeProximity();
+}
Index: applications/editors/josm/plugins/opendata/src/org/openstreetmap/josm/plugins/opendata/core/io/geographic/ShpReader.java
===================================================================
--- applications/editors/josm/plugins/opendata/src/org/openstreetmap/josm/plugins/opendata/core/io/geographic/ShpReader.java	(revision 28091)
+++ applications/editors/josm/plugins/opendata/src/org/openstreetmap/josm/plugins/opendata/core/io/geographic/ShpReader.java	(revision 28113)
@@ -84,5 +84,5 @@
 public class ShpReader extends AbstractReader implements OdConstants {
 
-	private final AbstractDataSetHandler handler;
+	private final ShpHandler handler;
 	
 	private final CoordinateReferenceSystem wgs84;
@@ -93,5 +93,5 @@
 	private MathTransform transform;
 	
-	public ShpReader(AbstractDataSetHandler handler) throws NoSuchAuthorityCodeException, FactoryException {
+	public ShpReader(ShpHandler handler) throws NoSuchAuthorityCodeException, FactoryException {
 		this.handler = handler;
 		this.wgs84 = CRS.decode("EPSG:4326");
@@ -105,5 +105,5 @@
 		}
 		try {
-			return new ShpReader(handler).parse(file, instance);
+			return new ShpReader(handler != null ? handler.getShpHandler() : null).parse(file, instance);
 		} catch (IOException e) {
 			throw e;
@@ -373,5 +373,5 @@
 	private Node getNode(Point p, String key) {
 		Node n = nodes.get(key);
-		if (n == null && handler != null && handler.checkShpNodeProximity()) {
+		if (n == null && handler != null && handler.checkNodeProximity()) {
 			LatLon ll = new LatLon(p.getY(), p.getX());
 			for (Node node : nodes.values()) {
Index: applications/editors/josm/plugins/opendata/src/org/openstreetmap/josm/plugins/opendata/core/io/geographic/TabReader.java
===================================================================
--- applications/editors/josm/plugins/opendata/src/org/openstreetmap/josm/plugins/opendata/core/io/geographic/TabReader.java	(revision 28091)
+++ applications/editors/josm/plugins/opendata/src/org/openstreetmap/josm/plugins/opendata/core/io/geographic/TabReader.java	(revision 28113)
@@ -34,4 +34,5 @@
 import org.openstreetmap.josm.gui.progress.ProgressMonitor;
 import org.openstreetmap.josm.plugins.opendata.core.datasets.AbstractDataSetHandler;
+import org.openstreetmap.josm.plugins.opendata.core.io.tabular.SpreadSheetHandler;
 import org.openstreetmap.josm.plugins.opendata.core.io.tabular.SpreadSheetReader;
 
@@ -76,5 +77,5 @@
 
 		private final DbaseFileReader dbfReader;
-		public TabOsmReader(AbstractDataSetHandler handler, TabFiles tabFiles) throws IOException {
+		public TabOsmReader(SpreadSheetHandler handler, TabFiles tabFiles) throws IOException {
 			super(handler);
 			this.dbfReader = new DbaseFileReader(tabFiles, false, datCharset, null);
@@ -111,5 +112,5 @@
         try {
         	File dataFile = getDataFile(file, ".dat");
-        	ds.mergeFrom(new TabOsmReader(handler, new TabFiles(file, dataFile)).
+        	ds.mergeFrom(new TabOsmReader(handler != null ? handler.getSpreadSheetHandler() : null, new TabFiles(file, dataFile)).
         			doParse(columns.toArray(new String[0]), instance));
         } catch (IOException e) {
Index: applications/editors/josm/plugins/opendata/src/org/openstreetmap/josm/plugins/opendata/core/io/tabular/CsvHandler.java
===================================================================
--- applications/editors/josm/plugins/opendata/src/org/openstreetmap/josm/plugins/opendata/core/io/tabular/CsvHandler.java	(revision 28113)
+++ applications/editors/josm/plugins/opendata/src/org/openstreetmap/josm/plugins/opendata/core/io/tabular/CsvHandler.java	(revision 28113)
@@ -0,0 +1,31 @@
+//    JOSM opendata plugin.
+//    Copyright (C) 2011-2012 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.opendata.core.io.tabular;
+
+import java.nio.charset.Charset;
+
+public interface CsvHandler extends SpreadSheetHandler {
+
+	public void setCharset(Charset charset);
+
+	public void setCharset(String charset);
+
+	public Charset getCharset();
+
+	public void setSeparator(String sep);
+	
+	public String getSeparator();
+}
Index: applications/editors/josm/plugins/opendata/src/org/openstreetmap/josm/plugins/opendata/core/io/tabular/CsvReader.java
===================================================================
--- applications/editors/josm/plugins/opendata/src/org/openstreetmap/josm/plugins/opendata/core/io/tabular/CsvReader.java	(revision 28091)
+++ applications/editors/josm/plugins/opendata/src/org/openstreetmap/josm/plugins/opendata/core/io/tabular/CsvReader.java	(revision 28113)
@@ -35,23 +35,27 @@
 	private String line;
 
-	public CsvReader(AbstractDataSetHandler handler) {
+	public CsvReader(CsvHandler handler) {
 		this(handler, ";");
 	}
 
-	public CsvReader(AbstractDataSetHandler handler, String defaultSep) {
+	public CsvReader(CsvHandler handler, String defaultSep) {
 		super(handler);
-		this.charset = handler != null && handler.getCsvCharset() != null ? handler.getCsvCharset() : Charset.forName(UTF8);
-		this.sep = handler != null && handler.getCsvSeparator() != null ? handler.getCsvSeparator() : defaultSep;
+		this.charset = handler != null && handler.getCharset() != null ? handler.getCharset() : Charset.forName(UTF8);
+		this.sep = handler != null && handler.getSeparator() != null ? handler.getSeparator() : defaultSep;
 	}
 	
 	public static DataSet parseDataSet(InputStream in, AbstractDataSetHandler handler, ProgressMonitor instance) throws IOException {
-		CsvReader csvReader = new CsvReader(handler);
+		CsvHandler csvHandler = null;
+		if (handler.getSpreadSheetHandler() instanceof CsvHandler) {
+			csvHandler = (CsvHandler) handler.getSpreadSheetHandler();
+		}
+		CsvReader csvReader = new CsvReader(csvHandler);
 		try {
 			return csvReader.parse(in, instance);
 		} catch (IllegalArgumentException e) {
-			if (handler == null) {
+			if (csvHandler == null || (csvHandler.getSeparator() != null && csvHandler.getSeparator().equals(";"))) {
 				// If default sep has been used, try comma
 				System.out.println(e.getMessage());
-				CsvReader newReader = new CsvReader(handler, ",");
+				CsvReader newReader = new CsvReader(csvHandler, ",");
 				newReader.initResources(in, instance);
 				newReader.line = csvReader.line;
Index: applications/editors/josm/plugins/opendata/src/org/openstreetmap/josm/plugins/opendata/core/io/tabular/DefaultCsvHandler.java
===================================================================
--- applications/editors/josm/plugins/opendata/src/org/openstreetmap/josm/plugins/opendata/core/io/tabular/DefaultCsvHandler.java	(revision 28113)
+++ applications/editors/josm/plugins/opendata/src/org/openstreetmap/josm/plugins/opendata/core/io/tabular/DefaultCsvHandler.java	(revision 28113)
@@ -0,0 +1,49 @@
+//    JOSM opendata plugin.
+//    Copyright (C) 2011-2012 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.opendata.core.io.tabular;
+
+import java.nio.charset.Charset;
+
+public class DefaultCsvHandler extends DefaultSpreadSheetHandler implements CsvHandler {
+
+	private Charset charset = null;
+	private String separator = null;
+	
+	@Override
+	public void setCharset(Charset cs) {
+		charset = cs;
+	}
+
+	@Override
+	public void setCharset(String charset) {
+		setCharset(Charset.forName(charset));
+	}
+
+	@Override
+	public Charset getCharset() {
+		return charset;
+	}
+
+	@Override
+	public void setSeparator(String sep) {
+		separator = sep;
+	}
+
+	@Override
+	public String getSeparator() {
+		return separator;
+	}
+}
Index: applications/editors/josm/plugins/opendata/src/org/openstreetmap/josm/plugins/opendata/core/io/tabular/DefaultSpreadSheetHandler.java
===================================================================
--- applications/editors/josm/plugins/opendata/src/org/openstreetmap/josm/plugins/opendata/core/io/tabular/DefaultSpreadSheetHandler.java	(revision 28113)
+++ applications/editors/josm/plugins/opendata/src/org/openstreetmap/josm/plugins/opendata/core/io/tabular/DefaultSpreadSheetHandler.java	(revision 28113)
@@ -0,0 +1,50 @@
+//    JOSM opendata plugin.
+//    Copyright (C) 2011-2012 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.opendata.core.io.tabular;
+
+import org.openstreetmap.josm.data.coor.EastNorth;
+import org.openstreetmap.josm.data.coor.LatLon;
+
+public class DefaultSpreadSheetHandler implements SpreadSheetHandler {
+
+	private int sheetNumber = -1;
+	private boolean handlesProjection = false;
+	
+	@Override
+	public int getSheetNumber() {
+		return sheetNumber;
+	}
+
+	@Override
+	public void setSheetNumber(int n) {
+		sheetNumber = n;
+	}
+	
+	@Override
+	public boolean handlesProjection() {
+		return handlesProjection;
+	}
+
+	@Override
+	public void setHandlesProjection(boolean handle) {
+		handlesProjection = handle;
+	}
+
+	@Override
+	public LatLon getCoor(EastNorth en, String[] fields) {
+		return null;
+	}
+}
Index: applications/editors/josm/plugins/opendata/src/org/openstreetmap/josm/plugins/opendata/core/io/tabular/OdsReader.java
===================================================================
--- applications/editors/josm/plugins/opendata/src/org/openstreetmap/josm/plugins/opendata/core/io/tabular/OdsReader.java	(revision 28091)
+++ applications/editors/josm/plugins/opendata/src/org/openstreetmap/josm/plugins/opendata/core/io/tabular/OdsReader.java	(revision 28113)
@@ -38,5 +38,5 @@
 	private static final String SEP = "TextP:\\[";
 	
-	public OdsReader(AbstractDataSetHandler handler) {
+	public OdsReader(SpreadSheetHandler handler) {
 		super(handler);
 	}
@@ -44,5 +44,5 @@
 	public static DataSet parseDataSet(InputStream in,
 			AbstractDataSetHandler handler, ProgressMonitor instance) throws IOException {
-		return new OdsReader(handler).parse(in, instance);
+		return new OdsReader(handler != null ? handler.getSpreadSheetHandler() : null).parse(in, instance);
 	}
 
Index: applications/editors/josm/plugins/opendata/src/org/openstreetmap/josm/plugins/opendata/core/io/tabular/SpreadSheetHandler.java
===================================================================
--- applications/editors/josm/plugins/opendata/src/org/openstreetmap/josm/plugins/opendata/core/io/tabular/SpreadSheetHandler.java	(revision 28113)
+++ applications/editors/josm/plugins/opendata/src/org/openstreetmap/josm/plugins/opendata/core/io/tabular/SpreadSheetHandler.java	(revision 28113)
@@ -0,0 +1,32 @@
+//    JOSM opendata plugin.
+//    Copyright (C) 2011-2012 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.opendata.core.io.tabular;
+
+import org.openstreetmap.josm.data.coor.EastNorth;
+import org.openstreetmap.josm.data.coor.LatLon;
+
+public interface SpreadSheetHandler {
+
+	public void setSheetNumber(int n);
+	
+	public int getSheetNumber();
+
+	public void setHandlesProjection(boolean handle);
+	
+	public boolean handlesProjection();
+
+	public LatLon getCoor(EastNorth en, String[] fields);
+}
Index: applications/editors/josm/plugins/opendata/src/org/openstreetmap/josm/plugins/opendata/core/io/tabular/SpreadSheetReader.java
===================================================================
--- applications/editors/josm/plugins/opendata/src/org/openstreetmap/josm/plugins/opendata/core/io/tabular/SpreadSheetReader.java	(revision 28091)
+++ applications/editors/josm/plugins/opendata/src/org/openstreetmap/josm/plugins/opendata/core/io/tabular/SpreadSheetReader.java	(revision 28113)
@@ -37,5 +37,4 @@
 import org.openstreetmap.josm.io.AbstractReader;
 import org.openstreetmap.josm.plugins.opendata.core.OdConstants;
-import org.openstreetmap.josm.plugins.opendata.core.datasets.AbstractDataSetHandler;
 import org.openstreetmap.josm.plugins.opendata.core.io.ProjectionChooser;
 import org.openstreetmap.josm.plugins.opendata.core.io.ProjectionPatterns;
@@ -53,7 +52,7 @@
 	}
 
-	protected final AbstractDataSetHandler handler;
-
-	public SpreadSheetReader(AbstractDataSetHandler handler) {
+	protected final SpreadSheetHandler handler;
+
+	public SpreadSheetReader(SpreadSheetHandler handler) {
 		this.handler = handler;
 	}
@@ -122,5 +121,5 @@
 		}
 
-		final boolean handlerOK = handler != null && handler.handlesSpreadSheetProjection();
+		final boolean handlerOK = handler != null && handler.handlesProjection();
 
 		if (proj != null) {
@@ -168,5 +167,5 @@
 			}
 			if (en.isValid()) {
-				n.setCoor(proj != null && !handlerOK ? proj.eastNorth2latlon(en) : handler.getSpreadSheetCoor(en, fields));
+				n.setCoor(proj != null && !handlerOK ? proj.eastNorth2latlon(en) : handler.getCoor(en, fields));
 			} else {
 				System.err.println("Warning: Skipping line "+lineNumber+" because no valid coordinates have been found.");
Index: applications/editors/josm/plugins/opendata/src/org/openstreetmap/josm/plugins/opendata/core/io/tabular/XlsReader.java
===================================================================
--- applications/editors/josm/plugins/opendata/src/org/openstreetmap/josm/plugins/opendata/core/io/tabular/XlsReader.java	(revision 28091)
+++ applications/editors/josm/plugins/opendata/src/org/openstreetmap/josm/plugins/opendata/core/io/tabular/XlsReader.java	(revision 28113)
@@ -38,5 +38,5 @@
 	private int rowIndex;
 	
-	public XlsReader(AbstractDataSetHandler handler) {
+	public XlsReader(SpreadSheetHandler handler) {
 		super(handler);
 	}
@@ -44,5 +44,5 @@
 	public static DataSet parseDataSet(InputStream in,
 			AbstractDataSetHandler handler, ProgressMonitor instance) throws IOException {
-		return new XlsReader(handler).parse(in, instance);
+		return new XlsReader(handler != null ? handler.getSpreadSheetHandler() : null).parse(in, instance);
 	}
 
Index: applications/editors/josm/plugins/opendata/src/org/openstreetmap/josm/plugins/opendata/core/layers/OdDataLayer.java
===================================================================
--- applications/editors/josm/plugins/opendata/src/org/openstreetmap/josm/plugins/opendata/core/layers/OdDataLayer.java	(revision 28091)
+++ applications/editors/josm/plugins/opendata/src/org/openstreetmap/josm/plugins/opendata/core/layers/OdDataLayer.java	(revision 28113)
@@ -38,4 +38,5 @@
 import org.openstreetmap.josm.plugins.opendata.core.datasets.AbstractDataSetHandler;
 import org.openstreetmap.josm.plugins.opendata.core.io.OsmDownloader;
+import org.openstreetmap.josm.plugins.opendata.core.licenses.License;
 import org.openstreetmap.josm.plugins.opendata.core.util.OdUtils;
 
@@ -155,8 +156,15 @@
 					tr("View National Portal page"), tr("Launch browser to the national portal page of the selected data set")));
 		}
-		if (this.handler.getLicenseURL() != null) {
-			if (this.handler.getLicenseURL().getProtocol().startsWith("http")) {
-				result.add(new OpenLinkAction(this.handler.getLicenseURL(), ICON_AGREEMENT_24, 
+		if (this.handler.getLicense() != null) {
+			License lic = this.handler.getLicense();
+			if (lic.getURL() != null && lic.getURL().getProtocol().startsWith("http")) {
+				result.add(new OpenLinkAction(lic.getURL(), ICON_AGREEMENT_24, 
 						tr("View License"), tr("Launch browser to the license page of the selected data set")));
+			} else {
+				// TODO: view embedded licenses
+			}
+			if (lic.getSummaryURL() != null && lic.getSummaryURL().getProtocol().startsWith("http")) {
+				result.add(new OpenLinkAction(lic.getSummaryURL(), ICON_AGREEMENT_24, 
+						tr("View License (summary)"), tr("Launch browser to the summary license page of the selected data set")));
 			} else {
 				// TODO: view embedded licenses
Index: applications/editors/josm/plugins/opendata/src/org/openstreetmap/josm/plugins/opendata/core/licenses/LOOL.java
===================================================================
--- applications/editors/josm/plugins/opendata/src/org/openstreetmap/josm/plugins/opendata/core/licenses/LOOL.java	(revision 28113)
+++ applications/editors/josm/plugins/opendata/src/org/openstreetmap/josm/plugins/opendata/core/licenses/LOOL.java	(revision 28113)
@@ -0,0 +1,30 @@
+//    JOSM opendata plugin.
+//    Copyright (C) 2011-2012 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.opendata.core.licenses;
+
+import org.openstreetmap.josm.plugins.opendata.core.OdConstants;
+import org.openstreetmap.josm.plugins.opendata.core.util.OdUtils;
+
+public class LOOL extends License implements OdConstants {
+	
+    //public static final String URL_FR = "http://www.data.gouv.fr/Licence-Ouverte-Open-Licence";
+    
+	public LOOL() {
+		setIcon(OdUtils.getImageIcon(ICON_LOOL_48, true));
+		setURL(LOOL.class.getResource(RESOURCE_PATH+"Licence-Ouverte-Open-Licence-ENG.rtf"), "en");
+		setURL(LOOL.class.getResource(RESOURCE_PATH+"Licence-Ouverte-Open-Licence.rtf"), "fr");
+	}
+}
Index: applications/editors/josm/plugins/opendata/src/org/openstreetmap/josm/plugins/opendata/core/licenses/License.java
===================================================================
--- applications/editors/josm/plugins/opendata/src/org/openstreetmap/josm/plugins/opendata/core/licenses/License.java	(revision 28113)
+++ applications/editors/josm/plugins/opendata/src/org/openstreetmap/josm/plugins/opendata/core/licenses/License.java	(revision 28113)
@@ -0,0 +1,122 @@
+//    JOSM opendata plugin.
+//    Copyright (C) 2011-2012 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.opendata.core.licenses;
+
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+
+import javax.swing.Icon;
+
+import org.openstreetmap.josm.plugins.opendata.core.util.OdUtils;
+
+public abstract class License {
+	
+	public static final ODbL ODbL = new ODbL();
+	public static final LOOL LOOL = new LOOL();
+	
+	private final Map<String, URL> urls = new HashMap<String, URL>();
+	private final Map<String, URL> summaryURLs = new HashMap<String, URL>();
+	
+	private Icon icon;
+	
+	private static final URL getURL(Map<String, URL> map) {
+		// Find URL for current language
+		String lang = OdUtils.getJosmLanguage();
+		for (String l : map.keySet()) {
+			if (lang.startsWith(l)) {
+				return map.get(l);
+			}
+		}
+		// If not found, return english URL
+		URL url = map.get("en");
+		if (url != null) {
+			return url;
+		}
+		// If not found, return first non-null url
+		if (map.keySet().size() > 0) {
+			for (Iterator<String> it=map.keySet().iterator(); it.hasNext(); ) {
+				url = map.get(it.next());
+				if (url != null) {
+					return url;
+				}
+			}
+		}
+		// If empty, return null
+		return null;
+	}
+
+	public URL getURL() {
+		return getURL(urls);
+	}
+
+	public URL getSummaryURL() {
+		return getURL(summaryURLs);
+	}
+	
+	public final void setURL(URL url) {
+		setURL(url, "en");
+	}
+
+	public final void setURL(String url, String lang) throws MalformedURLException {
+		setURL(new URL(url), lang);
+	}
+
+	public final void setURL(String url) throws MalformedURLException {
+		setURL(new URL(url), "en");
+	}
+
+	public final void setURL(URL url, String lang) {
+		if (url != null) {
+			urls.put(lang, url);
+		}
+	}
+
+	public final void setSummaryURL(URL url) {
+		setSummaryURL(url, "en");
+	}
+
+	public final void setSummaryURL(String url, String lang) throws MalformedURLException {
+		setSummaryURL(new URL(url), lang);
+	}
+
+	public final void setSummaryURL(String url) throws MalformedURLException {
+		setSummaryURL(new URL(url), "en");
+	}
+
+	public final void setSummaryURL(URL url, String lang) {
+		if (url != null) {
+			summaryURLs.put(lang, url);
+		}
+	}
+
+	public final Icon getIcon() {
+		return icon;
+	}
+
+	public final void setIcon(Icon icon) {
+		this.icon = icon;
+	}
+
+	@Override
+	public String toString() {
+		return "License [" + (urls != null ? "urls=" + urls + ", " : "")
+				+ (summaryURLs != null ? "summaryURLs=" + summaryURLs : "")
+				+ "]";
+	}
+}
Index: applications/editors/josm/plugins/opendata/src/org/openstreetmap/josm/plugins/opendata/core/licenses/ODbL.java
===================================================================
--- applications/editors/josm/plugins/opendata/src/org/openstreetmap/josm/plugins/opendata/core/licenses/ODbL.java	(revision 28113)
+++ applications/editors/josm/plugins/opendata/src/org/openstreetmap/josm/plugins/opendata/core/licenses/ODbL.java	(revision 28113)
@@ -0,0 +1,38 @@
+//    JOSM opendata plugin.
+//    Copyright (C) 2011-2012 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.opendata.core.licenses;
+
+import org.openstreetmap.josm.plugins.opendata.core.OdConstants;
+
+public class ODbL extends License implements OdConstants {
+	
+    //public static final String URL            = "http://opendatacommons.org/licenses/odbl/1-0";
+    //public static final String SUMMARY_URL    = "http://opendatacommons.org/licenses/odbl/summary";
+    //public static final String URL_FR         = "http://vvlibri.org/fr/licence/odbl/10/fr/legalcode#La_Licence_ODbL";
+    //public static final String SUMMARY_URL_FR = "http://vvlibri.org/fr/licence/odbl/10/fr";
+    
+	public ODbL() {
+		for (String lang : new String[]{"", "fr"}) {
+			if (lang.isEmpty()) {
+				setURL(ODbL.class.getResource(RESOURCE_PATH+"odbl-1.0.htm"));
+				setSummaryURL(ODbL.class.getResource(RESOURCE_PATH+"odbl-summary-1.0.htm"));
+			} else {
+				setURL(ODbL.class.getResource(RESOURCE_PATH+"odbl-1.0-"+lang+".htm"), lang);
+				setSummaryURL(ODbL.class.getResource(RESOURCE_PATH+"odbl-summary-1.0-"+lang+".htm"), lang);
+			}
+		}
+	}
+}
Index: applications/editors/josm/plugins/opendata/src/org/openstreetmap/josm/plugins/opendata/core/util/OdUtils.java
===================================================================
--- applications/editors/josm/plugins/opendata/src/org/openstreetmap/josm/plugins/opendata/core/util/OdUtils.java	(revision 28091)
+++ applications/editors/josm/plugins/opendata/src/org/openstreetmap/josm/plugins/opendata/core/util/OdUtils.java	(revision 28113)
@@ -18,8 +18,10 @@
 import java.util.ArrayList;
 import java.util.List;
+import java.util.Locale;
 
 import javax.swing.ImageIcon;
 
 import org.apache.commons.lang3.StringUtils;
+import org.openstreetmap.josm.Main;
 import org.openstreetmap.josm.data.osm.OsmPrimitive;
 import org.openstreetmap.josm.data.osm.Relation;
@@ -56,5 +58,17 @@
 	
 	public static final ImageIcon getImageIcon(String iconName) {
-		return new ImageProvider(iconName).setAdditionalClassLoaders(ModuleHandler.getResourceClassLoaders()).get();
+		return getImageIcon(iconName, false);
+	}
+	
+	public static final ImageIcon getImageIcon(String iconName, boolean optional) {
+		return new ImageProvider(iconName).setOptional(optional).setAdditionalClassLoaders(ModuleHandler.getResourceClassLoaders()).get();
+	}
+	
+	public static final String getJosmLanguage() {
+		String lang = Main.pref.get("language");
+		if (lang == null || lang.isEmpty()) {
+			lang = Locale.getDefault().toString();
+		}
+		return lang;
 	}
 }
