Index: applications/editors/josm/plugins/opendata/src/org/openstreetmap/josm/plugins/opendata/OdPlugin.java
===================================================================
--- applications/editors/josm/plugins/opendata/src/org/openstreetmap/josm/plugins/opendata/OdPlugin.java	(revision 28033)
+++ applications/editors/josm/plugins/opendata/src/org/openstreetmap/josm/plugins/opendata/OdPlugin.java	(revision 28044)
@@ -16,10 +16,19 @@
 package org.openstreetmap.josm.plugins.opendata;
 
+import static org.openstreetmap.josm.gui.help.HelpUtil.ht;
+import static org.openstreetmap.josm.tools.I18n.marktr;
+
+import java.awt.event.KeyEvent;
 import java.io.File;
 import java.util.Arrays;
+import java.util.HashMap;
 import java.util.List;
+import java.util.Map;
+
+import javax.swing.JMenu;
 
 import org.openstreetmap.josm.Main;
 import org.openstreetmap.josm.actions.ExtensionFileFilter;
+import org.openstreetmap.josm.gui.MainMenu;
 import org.openstreetmap.josm.gui.MapFrame;
 import org.openstreetmap.josm.gui.preferences.PreferenceSetting;
@@ -27,4 +36,9 @@
 import org.openstreetmap.josm.plugins.PluginInformation;
 import org.openstreetmap.josm.plugins.opendata.core.OdConstants;
+import org.openstreetmap.josm.plugins.opendata.core.actions.DownloadDataAction;
+import org.openstreetmap.josm.plugins.opendata.core.actions.DownloadDataTask;
+import org.openstreetmap.josm.plugins.opendata.core.actions.OpenPreferencesActions;
+import org.openstreetmap.josm.plugins.opendata.core.datasets.AbstractDataSetHandler;
+import org.openstreetmap.josm.plugins.opendata.core.datasets.DataSetCategory;
 import org.openstreetmap.josm.plugins.opendata.core.gui.OdDialog;
 import org.openstreetmap.josm.plugins.opendata.core.gui.OdPreferenceSetting;
@@ -38,4 +52,5 @@
 import org.openstreetmap.josm.plugins.opendata.core.io.tabular.OdsImporter;
 import org.openstreetmap.josm.plugins.opendata.core.io.tabular.XlsImporter;
+import org.openstreetmap.josm.plugins.opendata.core.modules.Module;
 import org.openstreetmap.josm.plugins.opendata.core.modules.ModuleHandler;
 import org.openstreetmap.josm.plugins.opendata.core.modules.ModuleInformation;
@@ -46,4 +61,6 @@
 	
 	public final XmlImporter xmlImporter;
+	
+	private final JMenu menu;
 	
 	public OdPlugin(PluginInformation info) { // NO_UCD
@@ -65,8 +82,49 @@
         // Load modules
         loadModules();
+        // Add menu
+        menu = Main.main.menu.addMenu(marktr("Open Data"), KeyEvent.VK_O, Main.main.menu.defaultMenuPos, ht("/Plugin/OpenData"));
+        buildMenu();
+        // Add download task
+        Main.main.menu.openLocation.addDownloadTaskClass(DownloadDataTask.class);
 	}
 	
 	public static final OdPlugin getInstance() {
 		return instance;
+	}
+	
+	private void buildMenu() {
+        for (Module module : ModuleHandler.moduleList) {
+        	Map<DataSetCategory, JMenu> catMenus = new HashMap<DataSetCategory, JMenu>();
+        	JMenu moduleMenu = null;
+        	for (AbstractDataSetHandler handler: module.getHandlers()) {
+        		if (handler.getDataURL() != null) {
+        			if (moduleMenu == null) {
+        				String moduleName = module.getDisplayedName();
+        				if (moduleName == null || moduleName.isEmpty()) {
+        					moduleName = module.getModuleInformation().getName();
+        				}
+        				moduleMenu = new JMenu(moduleName);
+        				moduleMenu.setIcon(module.getModuleInformation().getScaledIcon());
+        			}
+        			DataSetCategory cat = handler.getCategory();
+        			JMenu endMenu = null;
+        			if (cat != null) {
+        				if ((endMenu = catMenus.get(cat)) == null) {
+        					catMenus.put(cat, endMenu = new JMenu(cat.getName()));
+        					moduleMenu.add(endMenu);
+        				}
+        			}
+        			if (endMenu == null) {
+        				endMenu = moduleMenu;
+        			}
+        			endMenu.add(new DownloadDataAction(handler));
+        		}
+        	}
+        	if (moduleMenu != null) {
+        		menu.add(moduleMenu);
+        	}
+        }
+        menu.addSeparator();
+        MainMenu.add(menu, new OpenPreferencesActions());
 	}
 
Index: applications/editors/josm/plugins/opendata/src/org/openstreetmap/josm/plugins/opendata/core/actions/DownloadDataAction.java
===================================================================
--- applications/editors/josm/plugins/opendata/src/org/openstreetmap/josm/plugins/opendata/core/actions/DownloadDataAction.java	(revision 28044)
+++ applications/editors/josm/plugins/opendata/src/org/openstreetmap/josm/plugins/opendata/core/actions/DownloadDataAction.java	(revision 28044)
@@ -0,0 +1,45 @@
+//    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.actions;
+
+import java.awt.event.ActionEvent;
+
+import javax.swing.Action;
+
+import org.openstreetmap.josm.Main;
+import org.openstreetmap.josm.actions.JosmAction;
+import org.openstreetmap.josm.plugins.opendata.core.datasets.AbstractDataSetHandler;
+import org.openstreetmap.josm.tools.CheckParameterUtil;
+
+public class DownloadDataAction extends JosmAction {
+
+	private final AbstractDataSetHandler handler;
+	
+	public DownloadDataAction(AbstractDataSetHandler handler) {
+		CheckParameterUtil.ensureParameterNotNull(handler, "handler");
+		this.handler = handler;
+		String name = handler.getName();
+		if (name == null || name.isEmpty()) {
+			name = handler.getClass().getName();
+		}
+		putValue(Action.NAME, name);
+	}
+	
+	@Override
+	public void actionPerformed(ActionEvent e) {
+		Main.main.menu.openLocation.openUrl(true, handler.getDataURL().toString());
+	}
+}
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 28044)
+++ applications/editors/josm/plugins/opendata/src/org/openstreetmap/josm/plugins/opendata/core/actions/DownloadDataTask.java	(revision 28044)
@@ -0,0 +1,86 @@
+//    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.actions;
+
+import java.io.File;
+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.OsmDataLayer;
+import org.openstreetmap.josm.gui.progress.ProgressMonitor;
+import org.openstreetmap.josm.io.AbstractReader;
+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.io.NetworkReader;
+import org.openstreetmap.josm.plugins.opendata.core.layers.OdDataLayer;
+import org.openstreetmap.josm.plugins.opendata.core.modules.Module;
+import org.openstreetmap.josm.plugins.opendata.core.modules.ModuleHandler;
+
+public class DownloadDataTask extends DownloadOsmTask {
+
+	private AbstractDataSetHandler handler;
+	
+	@Override
+	public Future<?> download(boolean newLayer, Bounds downloadArea, ProgressMonitor progressMonitor) {
+		return null;
+	}
+
+	@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);
+        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);
+	}
+
+	@Override
+	public boolean acceptsUrl(String url) {
+		for (Module module : ModuleHandler.moduleList) {
+			for (AbstractDataSetHandler handler : module.getHandlers()) {
+				if (handler != null && handler.getDataURL() != null && url.equals(handler.getDataURL().toString())) {
+					this.handler = handler;
+					return true;
+				}
+			}
+		}
+		return false;
+	}
+	
+	protected class InternDownloadTasK extends DownloadTask {
+
+		public InternDownloadTasK(boolean newLayer, NetworkReader reader, ProgressMonitor progressMonitor) {
+			super(newLayer, reader, progressMonitor);
+		}
+
+		/* (non-Javadoc)
+		 * @see org.openstreetmap.josm.actions.downloadtasks.DownloadOsmTask.DownloadTask#createNewLayer(java.lang.String)
+		 */
+		@Override
+		protected OsmDataLayer createNewLayer(String layerName) {
+            File associatedFile = ((NetworkReader)reader).getReadFile();
+            if (layerName == null || layerName.isEmpty()) {
+                layerName = associatedFile == null ? OsmDataLayer.createNewName() : associatedFile.getName();
+            }
+    		DataSetUpdater.updateDataSet(dataSet, handler, associatedFile);
+    		return new OdDataLayer(dataSet, layerName, associatedFile, handler);
+		}
+	}
+}
Index: applications/editors/josm/plugins/opendata/src/org/openstreetmap/josm/plugins/opendata/core/actions/OpenPreferencesActions.java
===================================================================
--- applications/editors/josm/plugins/opendata/src/org/openstreetmap/josm/plugins/opendata/core/actions/OpenPreferencesActions.java	(revision 28044)
+++ applications/editors/josm/plugins/opendata/src/org/openstreetmap/josm/plugins/opendata/core/actions/OpenPreferencesActions.java	(revision 28044)
@@ -0,0 +1,42 @@
+//    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.actions;
+
+import static org.openstreetmap.josm.tools.I18n.tr;
+
+import java.awt.event.ActionEvent;
+
+import org.openstreetmap.josm.Main;
+import org.openstreetmap.josm.actions.JosmAction;
+import org.openstreetmap.josm.gui.preferences.PreferenceDialog;
+import org.openstreetmap.josm.plugins.opendata.core.OdConstants;
+import org.openstreetmap.josm.plugins.opendata.core.gui.OdPreferenceSetting;
+import org.openstreetmap.josm.tools.ImageProvider;
+
+public class OpenPreferencesActions extends JosmAction implements OdConstants {
+	
+    public OpenPreferencesActions() {
+        putValue(NAME, tr("Preferences"));
+        putValue(SMALL_ICON, ImageProvider.get("dialogs", ICON_CORE_24));
+    }
+    
+	@Override
+	public void actionPerformed(ActionEvent e) {
+        final PreferenceDialog p = new PreferenceDialog(Main.parent);
+        p.selectPreferencesTabByClass(OdPreferenceSetting.class);
+        p.setVisible(true);
+	}
+}
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 28033)
+++ applications/editors/josm/plugins/opendata/src/org/openstreetmap/josm/plugins/opendata/core/datasets/AbstractDataSetHandler.java	(revision 28044)
@@ -53,4 +53,5 @@
 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.util.NamesFrUtils;
@@ -92,4 +93,6 @@
 	}
 
+	private String name;
+	private DataSetCategory category;
 	private String sourceDate;
 	private File associatedFile;
@@ -170,8 +173,21 @@
 	public URL getWikiURL() {return null;}
 	
-	public abstract URL getLocalPortalURL();
-	public abstract URL getNationalPortalURL();
+	public URL getLocalPortalURL() {return null;}
+	
+	public URL getNationalPortalURL() {return null;}
 
 	public URL getLicenseURL() {return null;}
+
+	public URL getDataURL() {return null;}
+	
+	public AbstractReader getReaderForUrl(String url) {return null;}
+
+	public final DataSetCategory getCategory() {
+		return category;
+	}
+
+	public final void setCategory(DataSetCategory category) {
+		this.category = category;
+	}
 
 	public final Collection<String> getOsmXapiRequests(Bounds bounds) {
@@ -340,25 +356,24 @@
 	}
 
-	/**
-	 * @return the source
-	 */
 	public String getSource() {
 		return null;
 	}
 		
-	/**
-	 * @return the sourceDate
-	 */
 	public final String getSourceDate() {
 		return sourceDate;
 	}
 	
-	/**
-	 * @param sourceDate the sourceDate to set
-	 */
 	public final void setSourceDate(String sourceDate) {
 		this.sourceDate = sourceDate;
 	}
-	
+
+	public final String getName() {
+		return name;
+	}
+	
+	public final void setName(String name) {
+		this.name = name;
+	}
+
 	public String getLocalPortalIconName() {
 		return ICON_CORE_24;
@@ -503,3 +518,7 @@
 		return null;
 	}
+
+	public boolean checkShpNodeProximity() {
+		return false;
+	}
 }
Index: applications/editors/josm/plugins/opendata/src/org/openstreetmap/josm/plugins/opendata/core/datasets/DataSetCategory.java
===================================================================
--- applications/editors/josm/plugins/opendata/src/org/openstreetmap/josm/plugins/opendata/core/datasets/DataSetCategory.java	(revision 28044)
+++ applications/editors/josm/plugins/opendata/src/org/openstreetmap/josm/plugins/opendata/core/datasets/DataSetCategory.java	(revision 28044)
@@ -0,0 +1,43 @@
+//    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 javax.swing.ImageIcon;
+
+import org.openstreetmap.josm.plugins.opendata.core.util.OdUtils;
+
+public class DataSetCategory {
+
+	private final String name;
+	private final ImageIcon icon;
+	
+	public DataSetCategory(String name, ImageIcon icon) {
+		this.name = name;
+		this.icon = icon;
+	}
+	
+	public DataSetCategory(String name, String iconName) {
+		this(name, iconName != null && !iconName.isEmpty() ? OdUtils.getImageIcon(iconName) : null);
+	}
+
+	public final String getName() {
+		return name;
+	}
+
+	public final ImageIcon getIcon() {
+		return icon;
+	}
+}
Index: applications/editors/josm/plugins/opendata/src/org/openstreetmap/josm/plugins/opendata/core/datasets/DataSetUpdater.java
===================================================================
--- applications/editors/josm/plugins/opendata/src/org/openstreetmap/josm/plugins/opendata/core/datasets/DataSetUpdater.java	(revision 28044)
+++ applications/editors/josm/plugins/opendata/src/org/openstreetmap/josm/plugins/opendata/core/datasets/DataSetUpdater.java	(revision 28044)
@@ -0,0 +1,41 @@
+//    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 java.io.File;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+
+import org.openstreetmap.josm.Main;
+import org.openstreetmap.josm.data.osm.DataSet;
+import org.openstreetmap.josm.plugins.opendata.core.OdConstants;
+
+public abstract class DataSetUpdater implements OdConstants {
+
+	public static final void updateDataSet(DataSet dataSet, AbstractDataSetHandler handler, File associatedFile) {
+		if (dataSet != null && handler != null) {
+			if (associatedFile != null) {
+				handler.setAssociatedFile(associatedFile);
+				handler.setSourceDate(new SimpleDateFormat("yyyy-MM-dd").format(new Date(associatedFile.lastModified())));
+			}
+			if (!Main.pref.getBoolean(PREF_RAWDATA)) {
+				handler.updateDataSet(dataSet);
+			}
+			handler.checkDataSetSource(dataSet);
+			handler.checkNames(dataSet);
+		}
+	}
+}
Index: applications/editors/josm/plugins/opendata/src/org/openstreetmap/josm/plugins/opendata/core/datasets/WayCombiner.java
===================================================================
--- applications/editors/josm/plugins/opendata/src/org/openstreetmap/josm/plugins/opendata/core/datasets/WayCombiner.java	(revision 28044)
+++ applications/editors/josm/plugins/opendata/src/org/openstreetmap/josm/plugins/opendata/core/datasets/WayCombiner.java	(revision 28044)
@@ -0,0 +1,180 @@
+//    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.gui.conflict.tags.TagConflictResolutionUtil.combineTigerTags;
+import static org.openstreetmap.josm.gui.conflict.tags.TagConflictResolutionUtil.completeTagCollectionForEditing;
+import static org.openstreetmap.josm.gui.conflict.tags.TagConflictResolutionUtil.normalizeTagCollectionBeforeEditing;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.LinkedHashSet;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Set;
+
+import org.openstreetmap.josm.actions.CombineWayAction;
+import org.openstreetmap.josm.actions.CombineWayAction.NodeGraph;
+import org.openstreetmap.josm.command.Command;
+import org.openstreetmap.josm.corrector.ReverseWayTagCorrector;
+import org.openstreetmap.josm.corrector.UserCancelException;
+import org.openstreetmap.josm.data.osm.Node;
+import org.openstreetmap.josm.data.osm.Relation;
+import org.openstreetmap.josm.data.osm.TagCollection;
+import org.openstreetmap.josm.data.osm.Way;
+import org.openstreetmap.josm.gui.conflict.tags.CombinePrimitiveResolverDialog;
+
+// FIXME: Try to refactor CombineWayAction instead of using this class
+public class WayCombiner {
+	
+    protected static Way getTargetWay(Collection<Way> combinedWays) {
+        // init with an arbitrary way
+        Way targetWay = combinedWays.iterator().next();
+
+        // look for the first way already existing on
+        // the server
+        for (Way w : combinedWays) {
+            targetWay = w;
+            if (!w.isNew()) {
+                break;
+            }
+        }
+        return targetWay;
+    }
+    
+    /**
+     * @param ways
+     * @throws UserCancelException
+     */
+    public static void combineWays(Collection<Way> ways) throws UserCancelException {
+
+        // prepare and clean the list of ways to combine
+        //
+        if (ways == null || ways.isEmpty())
+            return;
+        ways.remove(null); // just in case -  remove all null ways from the collection
+
+        // remove duplicates, preserving order
+        ways = new LinkedHashSet<Way>(ways);
+
+        // try to build a new way which includes all the combined
+        // ways
+        //
+        NodeGraph graph = NodeGraph.createUndirectedGraphFromNodeWays(ways);
+        List<Node> path = graph.buildSpanningPath();
+        if (path == null) {
+            return;
+        }
+        // check whether any ways have been reversed in the process
+        // and build the collection of tags used by the ways to combine
+        //
+        TagCollection wayTags = TagCollection.unionOfAllPrimitives(ways);
+
+        List<Way> reversedWays = new LinkedList<Way>();
+        List<Way> unreversedWays = new LinkedList<Way>();
+        for (Way w: ways) {
+            if ((path.indexOf(w.getNode(0)) + 1) == path.lastIndexOf(w.getNode(1))) {
+                unreversedWays.add(w);
+            } else {
+                reversedWays.add(w);
+            }
+        }
+        // reverse path if all ways have been reversed
+        if (unreversedWays.isEmpty()) {
+            Collections.reverse(path);
+            unreversedWays = reversedWays;
+            reversedWays = null;
+        }
+        if ((reversedWays != null) && !reversedWays.isEmpty()) {
+            // filter out ways that have no direction-dependent tags
+            unreversedWays = ReverseWayTagCorrector.irreversibleWays(unreversedWays);
+            reversedWays = ReverseWayTagCorrector.irreversibleWays(reversedWays);
+            // reverse path if there are more reversed than unreversed ways with direction-dependent tags
+            if (reversedWays.size() > unreversedWays.size()) {
+                Collections.reverse(path);
+                List<Way> tempWays = unreversedWays;
+                unreversedWays = reversedWays;
+                reversedWays = tempWays;
+            }
+            // if there are still reversed ways with direction-dependent tags, reverse their tags
+            if (!reversedWays.isEmpty()) {
+                List<Way> unreversedTagWays = new ArrayList<Way>(ways);
+                unreversedTagWays.removeAll(reversedWays);
+                ReverseWayTagCorrector reverseWayTagCorrector = new ReverseWayTagCorrector();
+                List<Way> reversedTagWays = new ArrayList<Way>();
+                Collection<Command> changePropertyCommands =  null;
+                for (Way w : reversedWays) {
+                    Way wnew = new Way(w);
+                    reversedTagWays.add(wnew);
+                    changePropertyCommands = reverseWayTagCorrector.execute(w, wnew);
+                }
+                if ((changePropertyCommands != null) && !changePropertyCommands.isEmpty()) {
+                    for (Command c : changePropertyCommands) {
+                        c.executeCommand();
+                    }
+                }
+                wayTags = TagCollection.unionOfAllPrimitives(reversedTagWays);
+                wayTags.add(TagCollection.unionOfAllPrimitives(unreversedTagWays));
+            }
+        }
+
+        // create the new way and apply the new node list
+        //
+        Way targetWay = getTargetWay(ways);
+        Way modifiedTargetWay = new Way(targetWay);
+        modifiedTargetWay.setNodes(path);
+
+        TagCollection completeWayTags = new TagCollection(wayTags);
+        combineTigerTags(completeWayTags);
+        normalizeTagCollectionBeforeEditing(completeWayTags, ways);
+        TagCollection tagsToEdit = new TagCollection(completeWayTags);
+        completeTagCollectionForEditing(tagsToEdit);
+
+        CombinePrimitiveResolverDialog dialog = CombinePrimitiveResolverDialog.getInstance();
+        dialog.getTagConflictResolverModel().populate(tagsToEdit, completeWayTags.getKeysWithMultipleValues());
+        dialog.setTargetPrimitive(targetWay);
+        Set<Relation> parentRelations = CombineWayAction.getParentRelations(ways);
+        dialog.getRelationMemberConflictResolverModel().populate(
+                parentRelations,
+                ways
+        );
+        dialog.prepareDefaultDecisions();
+
+        // resolve tag conflicts if necessary
+        //
+        if (!completeWayTags.isApplicableToPrimitive() || !parentRelations.isEmpty()) {
+            dialog.setVisible(true);
+            //if (dialog.isCanceled()) // FIXME
+                throw new UserCancelException();
+        }
+
+        LinkedList<Way> deletedWays = new LinkedList<Way>(ways);
+        deletedWays.remove(targetWay);
+
+        //new ChangeCommand(targetWay, modifiedTargetWay).executeCommand();
+        targetWay.cloneFrom(modifiedTargetWay);
+        /*for (Command c : dialog.buildResolutionCommands()) {
+        	c.executeCommand();//FIXME
+        }*/
+        //new DeleteCommand(deletedWays).executeCommand();
+        for (Way way: deletedWays) {
+            way.setNodes(null);
+            way.setDeleted(true);
+            way.getDataSet().removePrimitive(way);
+        }
+    }
+}
Index: applications/editors/josm/plugins/opendata/src/org/openstreetmap/josm/plugins/opendata/core/io/AbstractImporter.java
===================================================================
--- applications/editors/josm/plugins/opendata/src/org/openstreetmap/josm/plugins/opendata/core/io/AbstractImporter.java	(revision 28033)
+++ applications/editors/josm/plugins/opendata/src/org/openstreetmap/josm/plugins/opendata/core/io/AbstractImporter.java	(revision 28044)
@@ -18,8 +18,5 @@
 import java.io.File;
 import java.io.IOException;
-import java.text.SimpleDateFormat;
-import java.util.Date;
 
-import org.openstreetmap.josm.Main;
 import org.openstreetmap.josm.actions.ExtensionFileFilter;
 import org.openstreetmap.josm.data.osm.DataSet;
@@ -30,4 +27,5 @@
 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.layers.OdDataLayer;
 import org.openstreetmap.josm.plugins.opendata.core.modules.Module;
@@ -73,13 +71,5 @@
 	@Override
 	protected OsmDataLayer createLayer(DataSet dataSet, File associatedFile, String layerName) {
-		if (handler != null) {
-			handler.setAssociatedFile(associatedFile);
-			handler.setSourceDate(new SimpleDateFormat("yyyy-MM-dd").format(new Date(associatedFile.lastModified())));
-			if (!Main.pref.getBoolean(PREF_RAWDATA)) {
-				handler.updateDataSet(dataSet);
-			}
-			handler.checkDataSetSource(dataSet);
-			handler.checkNames(dataSet);
-		}
+		DataSetUpdater.updateDataSet(dataSet, handler, associatedFile);
 		return new OdDataLayer(dataSet, layerName, associatedFile, handler);
 	}
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 28044)
+++ applications/editors/josm/plugins/opendata/src/org/openstreetmap/josm/plugins/opendata/core/io/NetworkReader.java	(revision 28044)
@@ -0,0 +1,118 @@
+//    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;
+
+import static org.openstreetmap.josm.tools.I18n.tr;
+
+import java.io.File;
+import java.io.InputStream;
+
+import org.openstreetmap.josm.data.osm.DataSet;
+import org.openstreetmap.josm.gui.progress.ProgressMonitor;
+import org.openstreetmap.josm.io.AbstractReader;
+import org.openstreetmap.josm.io.OsmServerReader;
+import org.openstreetmap.josm.io.OsmTransferException;
+import org.openstreetmap.josm.plugins.opendata.core.datasets.AbstractDataSetHandler;
+import org.openstreetmap.josm.plugins.opendata.core.io.archive.ZipReader;
+import org.openstreetmap.josm.plugins.opendata.core.io.geographic.KmlReader;
+import org.openstreetmap.josm.plugins.opendata.core.io.geographic.KmzReader;
+import org.openstreetmap.josm.plugins.opendata.core.io.geographic.MifReader;
+import org.openstreetmap.josm.plugins.opendata.core.io.geographic.ShpReader;
+import org.openstreetmap.josm.plugins.opendata.core.io.geographic.TabReader;
+import org.openstreetmap.josm.plugins.opendata.core.io.tabular.CsvReader;
+import org.openstreetmap.josm.plugins.opendata.core.io.tabular.OdsReader;
+import org.openstreetmap.josm.plugins.opendata.core.io.tabular.XlsReader;
+import org.openstreetmap.josm.tools.CheckParameterUtil;
+
+public class NetworkReader extends OsmServerReader {
+
+	private final String url;
+	private final AbstractDataSetHandler handler;
+	private Class<? extends AbstractReader> readerClass;
+
+	private File file;
+	
+    public NetworkReader(String url, AbstractDataSetHandler handler, Class<? extends AbstractReader> readerClass) {
+        CheckParameterUtil.ensureParameterNotNull(url, "url");
+        //CheckParameterUtil.ensureParameterNotNull(readerClass, "readerClass");
+    	this.url = url;
+        this.readerClass = readerClass;
+        this.handler = handler;
+    }
+    
+	public final File getReadFile() {
+		return file;
+	}
+
+	@Override
+	public DataSet parseOsm(ProgressMonitor progressMonitor) throws OsmTransferException {
+        InputStream in = null;
+        progressMonitor.beginTask(tr("Contacting Server...", 10));
+        try {
+            in = getInputStreamRaw(url, progressMonitor.createSubTaskMonitor(9, false));
+            if (in == null)
+                return null;
+            progressMonitor.subTask(tr("Downloading data..."));
+            ProgressMonitor instance = progressMonitor.createSubTaskMonitor(1, false);
+            if (readerClass == null) {
+            	String contentType = this.activeConnection.getContentType();
+            	if (contentType.startsWith("application/zip")) {
+            		readerClass = ZipReader.class;
+            	} else {
+            		throw new IllegalArgumentException("Unsupported content type: "+contentType);
+            	}
+            }
+            if (readerClass.equals(ZipReader.class)) {
+            	ZipReader zipReader = new ZipReader(in, handler);
+            	DataSet ds = zipReader.parseDoc(instance);
+            	file = zipReader.getReadFile();
+            	return ds;
+            } else if (readerClass.equals(KmlReader.class)) {
+            	return KmlReader.parseDataSet(in, instance);
+            } else if (readerClass.equals(KmzReader.class)) {
+            	return KmzReader.parseDataSet(in, instance);
+            } else if (readerClass.equals(MifReader.class)) {
+            	return MifReader.parseDataSet(in, null, handler, instance);
+            } else if (readerClass.equals(ShpReader.class)) {
+            	return ShpReader.parseDataSet(in, null, handler, instance);
+            } else if (readerClass.equals(TabReader.class)) {
+            	return TabReader.parseDataSet(in, null, handler, instance);
+            } else if (readerClass.equals(CsvReader.class)) {
+            	return CsvReader.parseDataSet(in, handler, instance);
+            } else if (readerClass.equals(OdsReader.class)) {
+            	return OdsReader.parseDataSet(in, handler, instance);
+            } else if (readerClass.equals(XlsReader.class)) {
+            	return XlsReader.parseDataSet(in, handler, instance);
+            } else {
+            	throw new IllegalArgumentException("Unsupported reader class: "+readerClass.getName());
+            }
+        } catch (OsmTransferException e) {
+            throw e;
+        } catch (Exception e) {
+            if (cancel)
+                return null;
+            throw new OsmTransferException(e);
+        } finally {
+            progressMonitor.finishTask();
+            try {
+                activeConnection = null;
+                if (in != null) {
+                    in.close();
+                }
+            } catch (Exception e) {/* ignore it */}
+        }
+	}
+}
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 28033)
+++ applications/editors/josm/plugins/opendata/src/org/openstreetmap/josm/plugins/opendata/core/io/archive/ZipReader.java	(revision 28044)
@@ -50,12 +50,18 @@
 	private final ZipInputStream zis;
 	private final AbstractDataSetHandler handler;
+	
+	private File file;
     
-    public ZipReader(ZipInputStream zis, AbstractDataSetHandler handler) {
-        this.zis = zis;
+    public ZipReader(InputStream in, AbstractDataSetHandler handler) {
+        this.zis = in instanceof ZipInputStream ? (ZipInputStream) in : new ZipInputStream(in);
         this.handler = handler;
     }
 
 	public static DataSet parseDataSet(InputStream in, AbstractDataSetHandler handler, ProgressMonitor instance) throws IOException, XMLStreamException, FactoryConfigurationError, JAXBException {
-		return new ZipReader(new ZipInputStream(in), handler).parseDoc(instance);
+		return new ZipReader(in, handler).parseDoc(instance);
+	}
+	
+	public final File getReadFile() {
+		return file;
 	}
 	
@@ -81,5 +87,5 @@
 	}
 
-	private DataSet parseDoc(ProgressMonitor instance) throws IOException, XMLStreamException, FactoryConfigurationError, JAXBException  {
+	public DataSet parseDoc(ProgressMonitor instance) throws IOException, XMLStreamException, FactoryConfigurationError, JAXBException  {
 		
 	    final File temp = createTempDir();
@@ -91,28 +97,36 @@
 				File file = new File(temp + File.separator + entry.getName());
 			    if (file.exists() && !file.delete()) {
-			        throw new IOException("Could not delete temp file: " + file.getAbsolutePath());
+			        throw new IOException("Could not delete temp file/dir: " + file.getAbsolutePath());
 			    }
-				if (!file.createNewFile()) {
-					throw new IOException("Could not create temp file: " + file.getAbsolutePath());
-				}
-				FileOutputStream fos = new FileOutputStream(file);
-				byte[] buffer = new byte[8192];
-				int count = 0;
-				while ((count = zis.read(buffer, 0, buffer.length)) > 0) {
-					fos.write(buffer, 0, count);
-				}
-				fos.close();
-				for (String ext : new String[] {
-						CSV_EXT, KML_EXT, KMZ_EXT, XLS_EXT, ODS_EXT, SHP_EXT, MIF_EXT, TAB_EXT, XML_EXT
-				}) {
-					if (entry.getName().toLowerCase().endsWith("."+ext)) {
-						candidates.add(file);
-						System.out.println(entry.getName());
-						break;
+			    if (!entry.isDirectory()) {
+			    	if (!file.createNewFile()) { 
+			    		throw new IOException("Could not create temp file: " + file.getAbsolutePath());
+			    	}
+					FileOutputStream fos = new FileOutputStream(file);
+					byte[] buffer = new byte[8192];
+					int count = 0;
+					while ((count = zis.read(buffer, 0, buffer.length)) > 0) {
+						fos.write(buffer, 0, count);
 					}
+					fos.close();
+					long time = entry.getTime();
+					if (time > -1) {
+						file.setLastModified(time);
+					}
+					for (String ext : new String[] {
+							CSV_EXT, KML_EXT, KMZ_EXT, XLS_EXT, ODS_EXT, SHP_EXT, MIF_EXT, TAB_EXT, XML_EXT
+					}) {
+						if (entry.getName().toLowerCase().endsWith("."+ext)) {
+							candidates.add(file);
+							System.out.println(entry.getName());
+							break;
+						}
+					}
+				} else if (!file.mkdir()) {
+					throw new IOException("Could not create temp dir: " + file.getAbsolutePath());
 				}
 			}
 			
-			File file = null;
+			file = null;
 			
 			if (candidates.size() > 1) {
@@ -159,5 +173,6 @@
 				}
 			}
-			
+	    } catch (IllegalArgumentException e) {
+	    	System.err.println(e.getMessage());
 	    } finally {
 	    	deleteDir(temp);
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 28033)
+++ applications/editors/josm/plugins/opendata/src/org/openstreetmap/josm/plugins/opendata/core/io/geographic/ShpReader.java	(revision 28044)
@@ -371,9 +371,23 @@
 	}
 	
+	private Node getNode(Point p, String key) {
+		Node n = nodes.get(key);
+		if (n == null && handler != null && handler.checkShpNodeProximity()) {
+			LatLon ll = new LatLon(p.getY(), p.getX());
+			for (Node node : nodes.values()) {
+				if (node.getCoor().equalsEpsilon(ll)) {
+					return node;
+				}
+			}
+		}
+		return n;
+	}
+	
 	private Node createOrGetNode(Point p) throws MismatchedDimensionException, TransformException {
 		if (transform != null) {
 			Point p2 = (Point) JTS.transform(p, transform);
 			String key = p2.getX()+"/"+p2.getY();
-			Node n = nodes.get(key);
+			//String key = LatLon.roundToOsmPrecisionStrict(p2.getX())+"/"+LatLon.roundToOsmPrecisionStrict(p2.getY());
+			Node n = getNode(p2, key);
 			if (n == null) {
 				nodes.put(key, n = new Node(new LatLon(p2.getY(), p2.getX())));
Index: applications/editors/josm/plugins/opendata/src/org/openstreetmap/josm/plugins/opendata/core/modules/AbstractModule.java
===================================================================
--- applications/editors/josm/plugins/opendata/src/org/openstreetmap/josm/plugins/opendata/core/modules/AbstractModule.java	(revision 28033)
+++ applications/editors/josm/plugins/opendata/src/org/openstreetmap/josm/plugins/opendata/core/modules/AbstractModule.java	(revision 28044)
@@ -55,4 +55,12 @@
 	public List<AbstractDataSetHandler> getHandlers() {
 		return handlers;
+	}
+
+	/* (non-Javadoc)
+	 * @see org.openstreetmap.josm.plugins.opendata.core.modules.Module#getDisplayedName()
+	 */
+	@Override
+	public String getDisplayedName() {
+		return info.name;
 	}
 
Index: applications/editors/josm/plugins/opendata/src/org/openstreetmap/josm/plugins/opendata/core/modules/Module.java
===================================================================
--- applications/editors/josm/plugins/opendata/src/org/openstreetmap/josm/plugins/opendata/core/modules/Module.java	(revision 28033)
+++ applications/editors/josm/plugins/opendata/src/org/openstreetmap/josm/plugins/opendata/core/modules/Module.java	(revision 28044)
@@ -23,4 +23,6 @@
 public interface Module {
 
+	public String getDisplayedName();
+
 	public List<AbstractDataSetHandler> getHandlers();
 	
