Index: src/org/openstreetmap/josm/Main.java
===================================================================
--- src/org/openstreetmap/josm/Main.java	(revision 236)
+++ src/org/openstreetmap/josm/Main.java	(revision 237)
@@ -29,5 +29,6 @@
 
 import org.openstreetmap.josm.actions.DownloadAction;
-import org.openstreetmap.josm.actions.DownloadAction.DownloadTask;
+import org.openstreetmap.josm.actions.downloadtasks.DownloadGpsTask;
+import org.openstreetmap.josm.actions.downloadtasks.DownloadOsmTask;
 import org.openstreetmap.josm.actions.mapmode.MapMode;
 import org.openstreetmap.josm.actions.search.SearchAction;
@@ -41,4 +42,6 @@
 import org.openstreetmap.josm.gui.PleaseWaitDialog;
 import org.openstreetmap.josm.gui.MapView.LayerChangeListener;
+import org.openstreetmap.josm.gui.download.BoundingBoxSelection;
+import org.openstreetmap.josm.gui.download.DownloadDialog.DownloadTask;
 import org.openstreetmap.josm.gui.layer.Layer;
 import org.openstreetmap.josm.gui.layer.OsmDataLayer;
@@ -372,9 +375,10 @@
 	private static void downloadFromParamString(final boolean rawGps, String s) {
 		if (s.startsWith("http:")) {
-			final Bounds b = DownloadAction.osmurl2bounds(s);
+			final Bounds b = BoundingBoxSelection.osmurl2bounds(s);
 			if (b == null)
 				JOptionPane.showMessageDialog(Main.parent, tr("Ignoring malformed url: \"{0}\"", s));
 			else {
-				DownloadTask osmTask = main.menu.download.downloadTasks.get(0);
+				//DownloadTask osmTask = main.menu.download.downloadTasks.get(0);
+				DownloadTask osmTask = new DownloadOsmTask();
 				osmTask.download(main.menu.download, b.min.lat(), b.min.lon(), b.max.lat(), b.max.lon());
 			}
@@ -394,5 +398,6 @@
 		if (st.countTokens() == 4) {
 			try {
-				DownloadTask task = main.menu.download.downloadTasks.get(rawGps ? 1 : 0);
+				//DownloadTask task = main.menu.download.downloadTasks.get(rawGps ? 1 : 0);
+				DownloadTask task = rawGps ? new DownloadGpsTask() : new DownloadOsmTask();
 				task.download(main.menu.download, Double.parseDouble(st.nextToken()), Double.parseDouble(st.nextToken()), Double.parseDouble(st.nextToken()), Double.parseDouble(st.nextToken()));
 				return;
Index: src/org/openstreetmap/josm/actions/DownloadAction.java
===================================================================
--- src/org/openstreetmap/josm/actions/DownloadAction.java	(revision 236)
+++ src/org/openstreetmap/josm/actions/DownloadAction.java	(revision 237)
@@ -39,5 +39,8 @@
 import org.openstreetmap.josm.gui.BookmarkList;
 import org.openstreetmap.josm.gui.MapView;
-import org.openstreetmap.josm.gui.WorldChooser;
+import org.openstreetmap.josm.gui.download.DownloadDialog;
+import org.openstreetmap.josm.gui.download.WorldChooser;
+import org.openstreetmap.josm.gui.download.DownloadDialog.DownloadTask;
+import org.openstreetmap.josm.gui.preferences.PreferenceDialog;
 import org.openstreetmap.josm.tools.GBC;
 
@@ -51,296 +54,33 @@
  */
 public class DownloadAction extends JosmAction {
-
-	public interface DownloadTask {
-		/**
-		 * Execute the download.
-		 */
-		void download(DownloadAction action, double minlat, double minlon, double maxlat, double maxlon);
-		/**
-		 * @return The checkbox presented to the user
-		 */
-		JCheckBox getCheckBox();
-		/**
-		 * @return The name of the preferences suffix to use for storing the
-		 * selection state.
-		 */
-		String getPreferencesSuffix();
-	}
-
-	/**
-	 * The list of download tasks. First entry should be the osm data entry
-	 * and the second the gps entry. After that, plugins can register additional
-	 * download possibilities.
-	 */
-	public final List<DownloadTask> downloadTasks = new ArrayList<DownloadTask>(5);
-
-	/**
-	 * minlat, minlon, maxlat, maxlon
-	 */
-	public JTextField[] latlon = new JTextField[]{
-			new JTextField(9),
-			new JTextField(9),
-			new JTextField(9),
-			new JTextField(9)};
-
+	
+	public DownloadDialog dialog;
+	
 	public DownloadAction() {
 		super(tr("Download from OSM"), "download", tr("Download map data from the OSM server."), KeyEvent.VK_D, InputEvent.CTRL_DOWN_MASK | InputEvent.SHIFT_DOWN_MASK, true);
-		// TODO remove when bug in Java6 is fixed
-		for (JTextField f : latlon)
-			f.setMinimumSize(new Dimension(100,new JTextField().getMinimumSize().height));
-
-		downloadTasks.add(new DownloadOsmTask());
-		downloadTasks.add(new DownloadGpsTask());
 	}
 
 	public void actionPerformed(ActionEvent e) {
-		JPanel dlg = new JPanel(new GridBagLayout());
+		dialog = new DownloadDialog(Integer.parseInt(Main.pref.get("download.tab", "0")));
+		
+		JPanel downPanel = new JPanel(new GridBagLayout());
+		downPanel.add(dialog, GBC.eol().fill(GBC.BOTH));
 
-		// World image
-		WorldChooser wc = new WorldChooser();
-		dlg.add(wc, GBC.eop());
-		wc.setToolTipText(tr("Move and zoom the image like the main map. Select an area to download by dragging."));
+		JOptionPane pane = new JOptionPane(downPanel, JOptionPane.PLAIN_MESSAGE, JOptionPane.OK_CANCEL_OPTION);
+		JDialog dlg = pane.createDialog(Main.parent, tr("Download"));
 
-		// Bounding box edits
-		dlg.add(new JLabel(tr("Bounding box")), GBC.eol());
-		dlg.add(new JLabel(tr("min lat")), GBC.std().insets(10,0,5,0));
-		dlg.add(latlon[0], GBC.std());
-		dlg.add(new JLabel(tr("min lon")), GBC.std().insets(10,0,5,0));
-		dlg.add(latlon[1], GBC.eol());
-		dlg.add(new JLabel(tr("max lat")), GBC.std().insets(10,0,5,0));
-		dlg.add(latlon[2], GBC.std());
-		dlg.add(new JLabel(tr("max lon")), GBC.std().insets(10,0,5,0));
-		dlg.add(latlon[3], GBC.eol());
-		if (Main.map != null) {
-			MapView mv = Main.map.mapView;
-			setEditBounds(new Bounds(
-					mv.getLatLon(0, mv.getHeight()),
-					mv.getLatLon(mv.getWidth(), 0)));
-		}
+		if (dlg.getWidth() > 1000)
+			dlg.setSize(1000, dlg.getHeight());
+		if (dlg.getHeight() > 600)
+			dlg.setSize(dlg.getWidth(),600);
 
-		// adding the download tasks
-		dlg.add(new JLabel(tr("Download the following data:")), GBC.eol().insets(0,5,0,0));
-		for (DownloadTask task : downloadTasks) {
-			dlg.add(task.getCheckBox(), GBC.eol().insets(20,0,0,0));
-			task.getCheckBox().setSelected(Main.pref.getBoolean("download."+task.getPreferencesSuffix()));
-		}
-
-		// OSM url edit
-		dlg.add(new JLabel(tr("URL from www.openstreetmap.org")), GBC.eol().insets(0,5,0,0));
-		final JTextField osmUrl = new JTextField();
-		dlg.add(osmUrl, GBC.eop().fill(GBC.HORIZONTAL));
-		final KeyListener osmUrlRefresher = new KeyAdapter(){
-			@Override public void keyTyped(KeyEvent e) {
-				SwingUtilities.invokeLater(new Runnable() {
-					public void run() {
-						try {
-							double latMin = Double.parseDouble(latlon[0].getText());
-							double lonMin = Double.parseDouble(latlon[1].getText());
-							double latMax = Double.parseDouble(latlon[2].getText());
-							double lonMax = Double.parseDouble(latlon[3].getText());
-							double lat = (latMax+latMin)/2;
-							double lon = (lonMax+lonMin)/2;
-							// convert to mercator (for calculation of zoom only)
-							latMin = Math.log(Math.tan(Math.PI/4.0+latMin/180.0*Math.PI/2.0))*180.0/Math.PI;
-							latMax = Math.log(Math.tan(Math.PI/4.0+latMax/180.0*Math.PI/2.0))*180.0/Math.PI;
-							double size = Math.max(Math.abs(latMax-latMin), Math.abs(lonMax-lonMin));
-							int zoom = 0;
-							while (zoom <= 20) {
-								if (size >= 180)
-									break;
-								size *= 2;
-								zoom++;
-							}
-							osmUrl.setText("http://www.openstreetmap.org/index.html?lat="+lat+"&lon="+lon+"&zoom="+zoom);
-						} catch (NumberFormatException x) {
-							osmUrl.setText("");
-						}
-						osmUrl.setCaretPosition(0);
-					}
-				});
-			}
-		};
-		for (JTextField f : latlon)
-			f.addKeyListener(osmUrlRefresher);
-		SwingUtilities.invokeLater(new Runnable() {public void run() {osmUrlRefresher.keyTyped(null);}});
-		osmUrl.addKeyListener(new KeyAdapter(){
-			@Override public void keyTyped(KeyEvent e) {
-				SwingUtilities.invokeLater(new Runnable() {
-					public void run() {
-						Bounds b = osmurl2bounds(osmUrl.getText());
-						if (b != null)
-							setEditBounds(b);
-						else
-							for (JTextField f : latlon)
-								f.setText("");
-					}
-				});
-			}
-		});
-
-		// Bookmarks
-		dlg.add(new JLabel(tr("Bookmarks")), GBC.eol());
-		final BookmarkList bookmarks = new BookmarkList();
-		bookmarks.getSelectionModel().addListSelectionListener(new ListSelectionListener(){
-			public void valueChanged(ListSelectionEvent e) {
-				Preferences.Bookmark b = (Preferences.Bookmark)bookmarks.getSelectedValue();
-				for (int i = 0; i < 4; ++i) {
-					latlon[i].setText(b == null ? "" : ""+b.latlon[i]);
-					latlon[i].setCaretPosition(0);
+		dlg.setVisible(true);
+		if (pane.getValue() instanceof Integer && (Integer)pane.getValue() == JOptionPane.OK_OPTION) {
+			Main.pref.put("download.tab", Integer.toString(dialog.getSelectedTab()));
+			for (DownloadTask task : dialog.downloadTasks) {
+				Main.pref.put("download."+task.getPreferencesSuffix(), task.getCheckBox().isSelected());
+				if (task.getCheckBox().isSelected()) {
+					task.download(this, dialog.minlat, dialog.minlon, dialog.maxlat, dialog.maxlon);
 				}
-				osmUrlRefresher.keyTyped(null);
-			}
-		});
-		wc.addListMarker(bookmarks);
-		dlg.add(new JScrollPane(bookmarks), GBC.eol().fill());
-
-		JPanel buttons = new JPanel(new GridLayout(1,2));
-		JButton add = new JButton(tr("Add"));
-		add.addActionListener(new ActionListener(){
-			public void actionPerformed(ActionEvent e) {
-				Preferences.Bookmark b = readBookmark();
-				if (b == null) {
-					JOptionPane.showMessageDialog(Main.parent, tr("Please enter the desired coordinates first."));
-					return;
-				}
-				b.name = JOptionPane.showInputDialog(Main.parent,tr("Please enter a name for the location."));
-				if (b.name != null && !b.name.equals("")) {
-					((DefaultListModel)bookmarks.getModel()).addElement(b);
-					bookmarks.save();
-				}
-			}
-		});
-		buttons.add(add);
-		JButton remove = new JButton(tr("Remove"));
-		remove.addActionListener(new ActionListener(){
-			public void actionPerformed(ActionEvent e) {
-				Object sel = bookmarks.getSelectedValue();
-				if (sel == null) {
-					JOptionPane.showMessageDialog(Main.parent,tr("Select a bookmark first."));
-					return;
-				}
-				((DefaultListModel)bookmarks.getModel()).removeElement(sel);
-				bookmarks.save();
-			}
-		});
-		buttons.add(remove);
-		dlg.add(buttons, GBC.eop().fill(GBC.HORIZONTAL));
-
-		Dimension d = dlg.getPreferredSize();
-		wc.setPreferredSize(new Dimension(d.width, d.width/2));
-		wc.addInputFields(latlon, osmUrl, osmUrlRefresher);
-
-		// Finally: the dialog
-		Preferences.Bookmark b;
-		boolean anySelected = false;
-		do {
-			final JOptionPane pane = new JOptionPane(dlg, JOptionPane.PLAIN_MESSAGE, JOptionPane.OK_CANCEL_OPTION);
-			final JDialog panedlg = pane.createDialog(Main.parent, tr("Choose an area"));
-			bookmarks.addMouseListener(new MouseAdapter(){
-				@Override public void mouseClicked(MouseEvent e) {
-	                if (e.getClickCount() >= 2) {
-	    				pane.setValue(JOptionPane.OK_OPTION);
-	    				panedlg.setVisible(false);
-	                }
-                }
-			});
-			panedlg.setVisible(true);
-			Object answer = pane.getValue();
-			if (answer == null || answer == JOptionPane.UNINITIALIZED_VALUE || (answer instanceof Integer && (Integer)answer != JOptionPane.OK_OPTION))
-				return;
-			b = readBookmark();
-
-			for (DownloadTask task : downloadTasks) {
-				if (task.getCheckBox().isSelected()) {
-					anySelected = true;
-					break;
-				}
-			}
-
-			if (b == null)
-				JOptionPane.showMessageDialog(Main.parent,tr("Please enter the desired coordinates or click on a bookmark."));
-			else if (!anySelected)
-				JOptionPane.showMessageDialog(Main.parent,tr("Please select at least one download data type."));
-		} while (b == null || !anySelected);
-
-		double minlon = b.latlon[0];
-		double minlat = b.latlon[1];
-		double maxlon = b.latlon[2];
-		double maxlat = b.latlon[3];
-		download(minlon, minlat, maxlon, maxlat);
-	}
-
-	/**
-	 * Read a bookmark from the current set edit fields. If one of the fields is
-	 * empty or contain illegal chars, <code>null</code> is returned.
-	 * The name of the bookmark is <code>null</code>.
-	 * @return A bookmark containing information from the edit fields and rawgps
-	 * 		checkbox.
-	 */
-	Preferences.Bookmark readBookmark() {
-		try {
-			Preferences.Bookmark b = new Preferences.Bookmark();
-			for (int i = 0; i < 4; ++i) {
-				if (latlon[i].getText().equals(""))
-					return null;
-				b.latlon[i] = Double.parseDouble(latlon[i].getText());
-			}
-			return b;
-		} catch (NumberFormatException x) {
-			return null;
-		}
-	}
-
-	public static Bounds osmurl2bounds(String url) {
-		int i = url.indexOf('?');
-		if (i == -1)
-			return null;
-		String[] args = url.substring(i+1).split("&");
-		HashMap<String, Double> map = new HashMap<String, Double>();
-		for (String arg : args) {
-			int eq = arg.indexOf('=');
-			if (eq != -1) {
-				try {
-					map.put(arg.substring(0, eq), Double.parseDouble(arg.substring(eq + 1)));
-				} catch (NumberFormatException e) {
-				}
-			}
-		}
-		try {
-			double size = 180.0 / Math.pow(2, map.get("zoom"));
-			return new Bounds(
-					new LatLon(map.get("lat") - size/2, map.get("lon") - size),
-					new LatLon(map.get("lat") + size/2, map.get("lon") + size));
-		} catch (Exception x) { // NPE or IAE
-			return null;
-		}
-	}
-
-	/**
-	 * Set the four edit fields to the given bounds coordinates.
-	 */
-	private void setEditBounds(Bounds b) {
-		LatLon bottomLeft = b.min;
-		LatLon topRight = b.max;
-		if (bottomLeft.isOutSideWorld())
-			bottomLeft = new LatLon(-89.999, -179.999); // do not use the Projection constants, since this looks better.
-		if (topRight.isOutSideWorld())
-			topRight = new LatLon(89.999, 179.999);
-		latlon[0].setText(""+bottomLeft.lat());
-		latlon[1].setText(""+bottomLeft.lon());
-		latlon[2].setText(""+topRight.lat());
-		latlon[3].setText(""+topRight.lon());
-		for (JTextField f : latlon)
-			f.setCaretPosition(0);
-	}
-
-	/**
-	 * Do the download for the given area.
-	 */
-	public void download(double minlat, double minlon, double maxlat, double maxlon) {
-		for (DownloadTask task : downloadTasks) {
-			Main.pref.put("download."+task.getPreferencesSuffix(), task.getCheckBox().isSelected());
-			if (task.getCheckBox().isSelected()) {
-				task.download(this, minlat, minlon, maxlat, maxlon);
 			}
 		}
Index: src/org/openstreetmap/josm/actions/downloadtasks/DownloadGpsTask.java
===================================================================
--- src/org/openstreetmap/josm/actions/downloadtasks/DownloadGpsTask.java	(revision 236)
+++ src/org/openstreetmap/josm/actions/downloadtasks/DownloadGpsTask.java	(revision 237)
@@ -10,6 +10,6 @@
 import org.openstreetmap.josm.Main;
 import org.openstreetmap.josm.actions.DownloadAction;
-import org.openstreetmap.josm.actions.DownloadAction.DownloadTask;
 import org.openstreetmap.josm.gui.PleaseWaitRunnable;
+import org.openstreetmap.josm.gui.download.DownloadDialog.DownloadTask;
 import org.openstreetmap.josm.gui.layer.RawGpsLayer;
 import org.openstreetmap.josm.gui.layer.RawGpsLayer.GpsPoint;
@@ -37,5 +37,5 @@
 			if (rawData == null)
 				return;
-			String name = action.latlon[0].getText() + " " + action.latlon[1].getText() + " x " + this.action.latlon[2].getText() + " " + this.action.latlon[3].getText();
+			String name = action.dialog.minlat + " " + action.dialog.minlon + " x " + action.dialog.maxlat + " " + action.dialog.maxlon;
 			Main.main.addLayer(new RawGpsLayer(rawData, name, null));
 		}
Index: src/org/openstreetmap/josm/actions/downloadtasks/DownloadOsmTask.java
===================================================================
--- src/org/openstreetmap/josm/actions/downloadtasks/DownloadOsmTask.java	(revision 236)
+++ src/org/openstreetmap/josm/actions/downloadtasks/DownloadOsmTask.java	(revision 237)
@@ -9,7 +9,7 @@
 import org.openstreetmap.josm.Main;
 import org.openstreetmap.josm.actions.DownloadAction;
-import org.openstreetmap.josm.actions.DownloadAction.DownloadTask;
 import org.openstreetmap.josm.data.osm.DataSet;
 import org.openstreetmap.josm.gui.PleaseWaitRunnable;
+import org.openstreetmap.josm.gui.download.DownloadDialog.DownloadTask;
 import org.openstreetmap.josm.gui.layer.OsmDataLayer;
 import org.openstreetmap.josm.io.BoundingBoxDownloader;
Index: src/org/openstreetmap/josm/gui/MapFrame.java
===================================================================
--- src/org/openstreetmap/josm/gui/MapFrame.java	(revision 236)
+++ src/org/openstreetmap/josm/gui/MapFrame.java	(revision 237)
@@ -28,4 +28,5 @@
 import org.openstreetmap.josm.gui.dialogs.SelectionListDialog;
 import org.openstreetmap.josm.gui.dialogs.ToggleDialog;
+import org.openstreetmap.josm.gui.dialogs.UserListDialog;
 import org.openstreetmap.josm.tools.Destroyable;
 
@@ -105,4 +106,5 @@
 		addToggleDialog(new HistoryDialog());
 		addToggleDialog(new SelectionListDialog());
+		addToggleDialog(new UserListDialog());
 		addToggleDialog(conflictDialog = new ConflictDialog());
 		addToggleDialog(new CommandStackDialog(this));
Index: src/org/openstreetmap/josm/gui/MapMover.java
===================================================================
--- src/org/openstreetmap/josm/gui/MapMover.java	(revision 236)
+++ src/org/openstreetmap/josm/gui/MapMover.java	(revision 237)
@@ -13,4 +13,5 @@
 import javax.swing.AbstractAction;
 import javax.swing.JComponent;
+import javax.swing.JPanel;
 import javax.swing.KeyStroke;
 
@@ -24,5 +25,5 @@
  * @author imi
  */
-class MapMover extends MouseAdapter implements MouseMotionListener, MouseWheelListener {
+public class MapMover extends MouseAdapter implements MouseMotionListener, MouseWheelListener {
 
 	private final class ZoomerAction extends AbstractAction {
@@ -72,5 +73,5 @@
 	 * Create a new MapMover
 	 */
-	MapMover(NavigatableComponent navComp, boolean registerKeys) {
+	public MapMover(NavigatableComponent navComp, JPanel contentPane) {
 		this.nc = navComp;
 		nc.addMouseListener(this);
@@ -81,8 +82,8 @@
 		int[] k = {KeyEvent.VK_COMMA, KeyEvent.VK_PERIOD, KeyEvent.VK_UP, KeyEvent.VK_RIGHT, KeyEvent.VK_DOWN, KeyEvent.VK_LEFT};
 
-		if (registerKeys) {
+		if (contentPane != null) {
 			for (int i = 0; i < n.length; ++i) {
-				Main.contentPane.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke(k[i], KeyEvent.CTRL_DOWN_MASK), "MapMover.Zoomer."+n[i]);
-				Main.contentPane.getActionMap().put("MapMover.Zoomer."+n[i], new ZoomerAction(n[i]));
+				contentPane.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke(k[i], KeyEvent.CTRL_DOWN_MASK), "MapMover.Zoomer."+n[i]);
+				contentPane.getActionMap().put("MapMover.Zoomer."+n[i], new ZoomerAction(n[i]));
 			}
 		}
Index: src/org/openstreetmap/josm/gui/MapScaler.java
===================================================================
--- src/org/openstreetmap/josm/gui/MapScaler.java	(revision 236)
+++ src/org/openstreetmap/josm/gui/MapScaler.java	(revision 237)
@@ -8,12 +8,15 @@
 import org.openstreetmap.josm.Main;
 import org.openstreetmap.josm.actions.HelpAction.Helpful;
+import org.openstreetmap.josm.data.projection.Projection;
 import org.openstreetmap.josm.tools.ColorHelper;
 
 public class MapScaler extends JComponent implements Helpful {
 
-	private final MapView mv;
+	private final NavigatableComponent mv;
+	private final Projection proj;
 
-	public MapScaler(MapView mv) {
+	public MapScaler(NavigatableComponent mv, Projection proj) {
 		this.mv = mv;
+		this.proj = proj;
 		setSize(100,30);
 		setOpaque(false);
@@ -21,5 +24,5 @@
 
 	@Override public void paint(Graphics g) {
-		double circum = mv.getScale()*100*Main.proj.scaleFactor()*40041455; // circumference of the earth in meter
+		double circum = mv.getScale()*100*proj.scaleFactor()*40041455; // circumference of the earth in meter
 		String text = circum > 1000 ? (Math.round(circum/100)/10.0)+"km" : Math.round(circum)+"m";
 		g.setColor(ColorHelper.html2color(Main.pref.get("color.scale", "#ffffff")));
Index: src/org/openstreetmap/josm/gui/MapView.java
===================================================================
--- src/org/openstreetmap/josm/gui/MapView.java	(revision 236)
+++ src/org/openstreetmap/josm/gui/MapView.java	(revision 237)
@@ -79,5 +79,5 @@
 		});
 
-		new MapMover(this, true);
+		new MapMover(this, Main.contentPane);
 
 		// listend to selection changes to redraw the map
@@ -92,5 +92,5 @@
 		zoomSlider.setBounds(3, 0, 114, 30);
 
-		MapScaler scaler = new MapScaler(this);
+		MapScaler scaler = new MapScaler(this, Main.proj);
 		add(scaler);
 		scaler.setLocation(10,30);
Index: src/org/openstreetmap/josm/gui/WorldChooser.java
===================================================================
--- src/org/openstreetmap/josm/gui/WorldChooser.java	(revision 236)
+++ 	(revision )
@@ -1,219 +1,0 @@
-package org.openstreetmap.josm.gui;
-
-import java.awt.Color;
-import java.awt.Dimension;
-import java.awt.Graphics;
-import java.awt.Point;
-import java.awt.Rectangle;
-import java.awt.event.KeyAdapter;
-import java.awt.event.KeyEvent;
-import java.awt.event.KeyListener;
-import java.beans.PropertyChangeListener;
-import java.net.URL;
-
-import javax.swing.ImageIcon;
-import javax.swing.JTextField;
-import javax.swing.SwingUtilities;
-import javax.swing.event.ListSelectionEvent;
-import javax.swing.event.ListSelectionListener;
-
-import org.openstreetmap.josm.Main;
-import org.openstreetmap.josm.data.Preferences;
-import org.openstreetmap.josm.data.coor.EastNorth;
-import org.openstreetmap.josm.data.coor.LatLon;
-import org.openstreetmap.josm.data.projection.Projection;
-import org.openstreetmap.josm.gui.SelectionManager.SelectionEnded;
-
-/**
- * A component that let the user select a lat/lon bounding box from zooming
- * into the world as a picture and selecting a region.
- *
- * The component has to be of the aspect ration 2:1 to look good.
- *
- * @author imi
- */
-public class WorldChooser extends NavigatableComponent {
-
-	/**
-	 * The world as picture.
-	 */
-	private ImageIcon world;
-
-	/**
-	 * Maximum scale level
-	 */
-	private double scaleMax;
-
-	/**
-	 * Mark this rectangle (lat/lon values) when painting.
-	 */
-	private EastNorth markerMin, markerMax;
-
-	private Projection projection;
-
-	/**
-	 * Create the chooser component.
-	 */
-	public WorldChooser() {
-		URL path = Main.class.getResource("/images/world.jpg");
-		world = new ImageIcon(path);
-		center = new EastNorth(world.getIconWidth()/2, world.getIconHeight()/2);
-		setPreferredSize(new Dimension(200, 100));
-		new MapMover(this, false);
-		projection = new Projection() {
-			public EastNorth latlon2eastNorth(LatLon p) {
-				return new EastNorth(
-						(p.lon()+180) / 360 * world.getIconWidth(),
-						(p.lat()+90) / 180 * world.getIconHeight());
-			}
-			public LatLon eastNorth2latlon(EastNorth p) {
-				return new LatLon(
-						p.north()*180/world.getIconHeight() - 90,
-						p.east()*360/world.getIconWidth() - 180);
-			}
-			@Override public String toString() {
-				return "WorldChooser";
-			}
-            public String getCacheDirectoryName() {
-                throw new UnsupportedOperationException();
-            }
-			public double scaleFactor() {
-	            return 1;
-            }
-		};
-		setMinimumSize(new Dimension(350, 350/2));
-	}
-
-
-	/**
-	 * Set the scale as well as the preferred size.
-	 */
-	@Override public void setPreferredSize(Dimension preferredSize) {
-		super.setPreferredSize(preferredSize);
-		scale = world.getIconWidth()/preferredSize.getWidth();
-		scaleMax = scale;
-	}
-
-
-	/**
-	 * Draw the current selected region.
-	 */
-	@Override public void paint(Graphics g) {
-		EastNorth tl = getEastNorth(0,0);
-		EastNorth br = getEastNorth(getWidth(),getHeight());
-		g.drawImage(world.getImage(),0,0,getWidth(),getHeight(),(int)tl.east(),(int)tl.north(),(int)br.east(),(int)br.north(), null);
-
-		// draw marker rect
-		if (markerMin != null && markerMax != null) {
-			Point p1 = getPoint(markerMin);
-			Point p2 = getPoint(markerMax);
-			double x = Math.min(p1.x, p2.x);
-			double y = Math.min(p1.y, p2.y);
-			double w = Math.max(p1.x, p2.x) - x;
-			double h = Math.max(p1.y, p2.y) - y;
-			if (w < 1)
-				w = 1;
-			if (h < 1)
-				h = 1;
-			g.setColor(Color.YELLOW);
-			g.drawRect((int)x, (int)y, (int)w, (int)h);
-		}
-	}
-
-
-	@Override public void zoomTo(EastNorth newCenter, double scale) {
-		if (getWidth() != 0 && scale > scaleMax) {
-			scale = scaleMax;
-			newCenter = center;
-		}
-		super.zoomTo(newCenter, scale);
-	}
-
-	/**
-	 * Show the selection bookmark in the world.
-	 */
-	public void addListMarker(final BookmarkList list) {
-		list.addListSelectionListener(new ListSelectionListener(){
-			public void valueChanged(ListSelectionEvent e) {
-				Preferences.Bookmark b = (Preferences.Bookmark)list.getSelectedValue();
-				if (b != null) {
-					markerMin = getProjection().latlon2eastNorth(new LatLon(b.latlon[0],b.latlon[1]));
-					markerMax = getProjection().latlon2eastNorth(new LatLon(b.latlon[2],b.latlon[3]));
-				} else {
-					markerMin = null;
-					markerMax = null;
-				}
-				repaint();
-			}
-		});
-	}
-
-	/**
-	 * Update edit fields and react upon changes.
-	 * @param field Must have exactly 4 entries (min lat to max lon)
-	 */
-	public void addInputFields(final JTextField[] field, JTextField osmUrl, final KeyListener osmUrlRefresher) {
-		// listener that invokes updateMarkerFromTextField after all
-		// messages are dispatched and so text fields are updated.
-		KeyListener listener = new KeyAdapter(){
-			@Override public void keyTyped(KeyEvent e) {
-				SwingUtilities.invokeLater(new Runnable(){
-					public void run() {
-						updateMarkerFromTextFields(field);
-					}
-				});
-			}
-		};
-
-		for (JTextField f : field)
-			f.addKeyListener(listener);
-		osmUrl.addKeyListener(listener);
-
-		SelectionEnded selListener = new SelectionEnded(){
-			public void selectionEnded(Rectangle r, boolean alt, boolean shift, boolean ctrl) {
-				markerMin = getEastNorth(r.x, r.y+r.height);
-				markerMax = getEastNorth(r.x+r.width, r.y);
-				LatLon min = getProjection().eastNorth2latlon(markerMin);
-				LatLon max = getProjection().eastNorth2latlon(markerMax);
-				field[0].setText(""+min.lat());
-				field[1].setText(""+min.lon());
-				field[2].setText(""+max.lat());
-				field[3].setText(""+max.lon());
-				for (JTextField f : field)
-					f.setCaretPosition(0);
-				osmUrlRefresher.keyTyped(null);
-				repaint();
-			}
-			public void addPropertyChangeListener(PropertyChangeListener listener) {}
-			public void removePropertyChangeListener(PropertyChangeListener listener) {}
-		};
-		SelectionManager sm = new SelectionManager(selListener, false, this);
-		sm.register(this);
-		updateMarkerFromTextFields(field);
-	}
-
-	/**
-	 * Update the marker field from the values of the given textfields
-	 */
-	private void updateMarkerFromTextFields(JTextField[] field) {
-		// try to read all values
-		double v[] = new double[field.length];
-		for (int i = 0; i < field.length; ++i) {
-			try {
-				v[i] = Double.parseDouble(field[i].getText());
-			} catch (NumberFormatException nfe) {
-				return;
-			}
-		}
-		markerMin = getProjection().latlon2eastNorth(new LatLon(v[0], v[1]));
-		markerMax = getProjection().latlon2eastNorth(new LatLon(v[2], v[3]));
-		repaint();
-	}
-
-	/**
-	 * Always use our image projection mode.
-	 */
-	@Override protected Projection getProjection() {
-		return projection;
-	}
-}
Index: src/org/openstreetmap/josm/gui/dialogs/UserListDialog.java
===================================================================
--- src/org/openstreetmap/josm/gui/dialogs/UserListDialog.java	(revision 237)
+++ src/org/openstreetmap/josm/gui/dialogs/UserListDialog.java	(revision 237)
@@ -0,0 +1,107 @@
+package org.openstreetmap.josm.gui.dialogs;
+
+import static org.openstreetmap.josm.tools.I18n.tr;
+
+import java.awt.BorderLayout;
+
+import java.awt.event.KeyEvent;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Comparator;
+import java.util.HashMap;
+
+import javax.swing.DefaultListModel;
+
+import javax.swing.JScrollPane;
+import javax.swing.JTable;
+import javax.swing.ListSelectionModel;
+
+import javax.swing.table.DefaultTableModel;
+
+import org.openstreetmap.josm.Main;
+import org.openstreetmap.josm.data.SelectionChangedListener;
+import org.openstreetmap.josm.data.osm.OsmPrimitive;
+import org.openstreetmap.josm.data.osm.User;
+
+/**
+ * Displays a dialog with all users who have last edited something in the 
+ * selection area, along with the number of objects.
+ * 
+ * @author Frederik Ramm <frederik@remote.org>
+ */
+public class UserListDialog extends ToggleDialog implements SelectionChangedListener {
+
+	/**
+	 * The display list.
+	 */
+	private final DefaultTableModel data = new DefaultTableModel() {
+		@Override public boolean isCellEditable(int row, int column) {
+			return false;
+		}
+		@Override public Class<?> getColumnClass(int columnIndex) {
+			return columnIndex == 0 ? String.class : Integer.class;
+		}
+	};
+	private JTable userTable = new JTable(data);
+			
+	public UserListDialog() {
+		super(tr("Authors"), "userlist", tr("Open a list of people working on the selected objects."), KeyEvent.VK_A, 150);
+		
+		data.setColumnIdentifiers(new String[]{tr("Author"),tr("# Objects"),"%"});
+		userTable.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
+		add(new JScrollPane(userTable), BorderLayout.CENTER);
+		selectionChanged(Main.ds.getSelected());
+	}
+
+	@Override public void setVisible(boolean b) {
+		if (b) {
+			Main.ds.listeners.add(this);
+			selectionChanged(Main.ds.getSelected());
+		} else {
+			Main.ds.listeners.remove(this);
+		}
+		super.setVisible(b);
+	}
+
+	/**
+	 * Called when the selection in the dataset changed.
+	 * @param newSelection The new selection array.
+	 */
+	public void selectionChanged(Collection<? extends OsmPrimitive> newSelection) {
+		
+		class UserCount {
+			User user;
+			int count;
+			UserCount(User user, int count) { this.user=user; this.count=count; }
+		};
+		
+		if (data == null)
+			return; // selection changed may be received in base class constructor before init
+		
+		data.setRowCount(0);
+		
+		HashMap<User,UserCount> counters = new HashMap<User,UserCount>();
+		int all = 0;
+		for (OsmPrimitive p : newSelection) {
+			if (p.user != null) {
+				UserCount uc = counters.get(p.user);
+				if (uc == null) 
+					counters.put(p.user, uc = new UserCount(p.user, 0));
+				uc.count++;
+				all++;
+			}
+		}
+		UserCount[] ucArr = new UserCount[counters.size()];
+		counters.values().toArray(ucArr);
+		Arrays.sort(ucArr, new Comparator<UserCount>() {
+			public int compare(UserCount a, UserCount b) { 
+				return (a.count<b.count) ? 1 : (a.count>b.count) ? -1 : 0;
+			};
+		});
+		
+		for (UserCount uc : ucArr) {
+			data.addRow(new Object[] { uc.user.name, uc.count, uc.count * 100 / all });
+		}
+	}
+
+}
Index: src/org/openstreetmap/josm/gui/download/BookmarkSelection.java
===================================================================
--- src/org/openstreetmap/josm/gui/download/BookmarkSelection.java	(revision 237)
+++ src/org/openstreetmap/josm/gui/download/BookmarkSelection.java	(revision 237)
@@ -0,0 +1,107 @@
+package org.openstreetmap.josm.gui.download;
+
+import static org.openstreetmap.josm.tools.I18n.tr;
+
+import java.awt.GridBagLayout;
+import java.awt.GridLayout;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.awt.event.MouseAdapter;
+import java.awt.event.MouseEvent;
+
+import javax.swing.DefaultListModel;
+import javax.swing.JButton;
+import javax.swing.JDialog;
+import javax.swing.JLabel;
+import javax.swing.JOptionPane;
+import javax.swing.JPanel;
+import javax.swing.JScrollPane;
+import javax.swing.event.ListSelectionEvent;
+import javax.swing.event.ListSelectionListener;
+
+import org.openstreetmap.josm.Main;
+import org.openstreetmap.josm.data.Preferences;
+import org.openstreetmap.josm.data.coor.LatLon;
+import org.openstreetmap.josm.gui.BookmarkList;
+import org.openstreetmap.josm.tools.GBC;
+
+/**
+ * Bookmark selector.
+ * 
+ * Provides selection, creation and deletion of bookmarks.
+ * Extracted from old DownloadAction.
+ * 
+ * @author Frederik Ramm <frederik@remote.org>
+ *
+ */
+public class BookmarkSelection implements DownloadSelection {
+
+	private Preferences.Bookmark tempBookmark= null;
+	private BookmarkList bookmarks; 
+	
+	public void addGui(final DownloadDialog gui) {
+		
+		JPanel dlg = new JPanel(new GridBagLayout());
+		gui.tabpane.addTab("Bookmarks", dlg);
+
+		bookmarks = new BookmarkList();
+		bookmarks.getSelectionModel().addListSelectionListener(new ListSelectionListener() {
+			public void valueChanged(ListSelectionEvent e) {
+				Preferences.Bookmark b = (Preferences.Bookmark)bookmarks.getSelectedValue();
+				if (b != null) {
+					gui.minlat = b.latlon[0];
+					gui.minlon = b.latlon[1];
+					gui.maxlat = b.latlon[2];
+					gui.maxlon = b.latlon[3];
+					gui.boundingBoxChanged(BookmarkSelection.this);
+				}
+			}
+		});
+		//wc.addListMarker(bookmarks);
+		dlg.add(new JScrollPane(bookmarks), GBC.eol().fill());
+
+		JPanel buttons = new JPanel(new GridLayout(1,2));
+		JButton add = new JButton(tr("Add"));
+		add.addActionListener(new ActionListener(){
+			public void actionPerformed(ActionEvent e) {
+				
+				if (tempBookmark == null) {
+					JOptionPane.showMessageDialog(Main.parent, tr("Please enter the desired coordinates first."));
+					return;
+				}
+				tempBookmark.name = JOptionPane.showInputDialog(Main.parent,tr("Please enter a name for the location."));
+				if (tempBookmark.name != null && !tempBookmark.name.equals("")) {
+					((DefaultListModel)bookmarks.getModel()).addElement(tempBookmark);
+					bookmarks.save();
+				}
+			}
+		});
+		buttons.add(add);
+		JButton remove = new JButton(tr("Remove"));
+		remove.addActionListener(new ActionListener(){
+			public void actionPerformed(ActionEvent e) {
+				Object sel = bookmarks.getSelectedValue();
+				if (sel == null) {
+					JOptionPane.showMessageDialog(Main.parent,tr("Select a bookmark first."));
+					return;
+				}
+				((DefaultListModel)bookmarks.getModel()).removeElement(sel);
+				bookmarks.save();
+			}
+		});
+		buttons.add(remove);
+		dlg.add(buttons, GBC.eop().fill(GBC.HORIZONTAL));
+	}		
+
+	public void boundingBoxChanged(DownloadDialog gui) {
+		tempBookmark = new Preferences.Bookmark();
+		tempBookmark.latlon[0] = gui.minlat;
+		tempBookmark.latlon[1] = gui.minlon;
+		tempBookmark.latlon[2] = gui.maxlat;
+		tempBookmark.latlon[3] = gui.maxlon;
+		System.out.println("CHANGED");
+		bookmarks.clearSelection();
+	}
+
+
+}
Index: src/org/openstreetmap/josm/gui/download/BoundingBoxSelection.java
===================================================================
--- src/org/openstreetmap/josm/gui/download/BoundingBoxSelection.java	(revision 237)
+++ src/org/openstreetmap/josm/gui/download/BoundingBoxSelection.java	(revision 237)
@@ -0,0 +1,200 @@
+package org.openstreetmap.josm.gui.download;
+
+import static org.openstreetmap.josm.tools.I18n.tr;
+
+import java.awt.Color;
+import java.awt.Dimension;
+import java.awt.Font;
+import java.awt.GridBagLayout;
+import java.awt.event.FocusAdapter;
+import java.awt.event.FocusEvent;
+import java.awt.event.FocusListener;
+import java.awt.event.KeyAdapter;
+import java.awt.event.KeyEvent;
+import java.awt.event.KeyListener;
+import java.util.HashMap;
+
+import javax.swing.BorderFactory;
+import javax.swing.JLabel;
+import javax.swing.JPanel;
+import javax.swing.JTextArea;
+import javax.swing.JTextField;
+import javax.swing.SwingUtilities;
+
+import org.openstreetmap.josm.Main;
+import org.openstreetmap.josm.data.Bounds;
+import org.openstreetmap.josm.data.coor.LatLon;
+import org.openstreetmap.josm.gui.MapView;
+import org.openstreetmap.josm.tools.GBC;
+/**
+ * Bounding box selector.
+ * 
+ * Provides max/min lat/lon input fields as well as the "URL from www.openstreetmap.org" text field.
+ * 
+ * @author Frederik Ramm <frederik@remote.org>
+ *
+ */
+public class BoundingBoxSelection implements DownloadSelection {
+
+	private JTextField[] latlon = new JTextField[] {
+			new JTextField(11),
+			new JTextField(11),
+			new JTextField(11),
+			new JTextField(11) };
+	final JTextArea osmUrl = new JTextArea();
+	
+	final JLabel sizeCheck = new JLabel();
+	
+	public void addGui(final DownloadDialog gui) {
+
+		JPanel dlg = new JPanel(new GridBagLayout());
+		osmUrl.setText(tr("You can paste an URL here to download the area."));
+
+		final FocusListener dialogUpdater = new FocusAdapter() {
+			@Override public void focusLost(FocusEvent e) {
+				SwingUtilities.invokeLater(new Runnable() {
+					public void run() {
+						try {
+							double minlat = Double.parseDouble(latlon[0].getText());
+							double minlon = Double.parseDouble(latlon[1].getText());
+							double maxlat = Double.parseDouble(latlon[2].getText());
+							double maxlon = Double.parseDouble(latlon[3].getText());
+							if (minlat != gui.minlat || minlon != gui.minlon || maxlat != gui.maxlat || maxlon != gui.maxlon) {
+								gui.minlat = minlat; gui.minlon = minlon; 
+								gui.maxlat = maxlat; gui.maxlon = maxlon;
+								gui.boundingBoxChanged(BoundingBoxSelection.this);
+							}
+						} catch (NumberFormatException x) {
+							// ignore
+						}
+						updateUrl(gui);
+						updateSizeCheck(gui);
+					}
+				});
+			}
+		};
+		
+		for (JTextField f : latlon) {
+			f.setMinimumSize(new Dimension(100,new JTextField().getMinimumSize().height));
+			f.addFocusListener(dialogUpdater);
+		}
+		
+		final KeyListener osmUrlRefresher = new KeyAdapter() {
+			@Override public void keyTyped(KeyEvent e) {
+				SwingUtilities.invokeLater(new Runnable() {
+					public void run() {
+						Bounds b = osmurl2bounds(osmUrl.getText());
+						if (b != null) {
+							gui.minlon = b.min.lon();
+							gui.minlat = b.min.lat();
+							gui.maxlon = b.max.lon();
+							gui.maxlat = b.max.lat();
+							gui.boundingBoxChanged(BoundingBoxSelection.this);
+							updateBboxFields(gui);
+							updateSizeCheck(gui);
+						}
+					}
+				});
+			};
+		};
+		
+		osmUrl.addKeyListener(osmUrlRefresher);
+		osmUrl.setLineWrap(true);
+		osmUrl.setBorder(latlon[0].getBorder());
+		
+		Font labelFont = sizeCheck.getFont();
+		sizeCheck.setFont(labelFont.deriveFont(Font.PLAIN, labelFont.getSize()));
+		
+		dlg.add(new JLabel(tr("min lat")), GBC.std().insets(10,20,5,0));
+		dlg.add(latlon[0], GBC.std().insets(0,20,0,0));
+		dlg.add(new JLabel(tr("min lon")), GBC.std().insets(10,20,5,0));
+		dlg.add(latlon[1], GBC.eol().insets(0,20,0,0));
+		dlg.add(new JLabel(tr("max lat")), GBC.std().insets(10,0,5,0));
+		dlg.add(latlon[2], GBC.std());
+		dlg.add(new JLabel(tr("max lon")), GBC.std().insets(10,0,5,0));
+		dlg.add(latlon[3], GBC.eol());
+		
+		dlg.add(new JLabel(tr("URL from www.openstreetmap.org")), GBC.eol().insets(10,20,5,0));
+		dlg.add(osmUrl, GBC.eop().insets(10,0,5,0).fill());
+		dlg.add(sizeCheck, GBC.eop().insets(10,0,5,20));
+
+		gui.tabpane.addTab("Bounding Box", dlg);
+	}
+	
+	/**
+	 * Called when bounding box is changed by one of the other download dialog tabs.
+	 */
+	public void boundingBoxChanged(DownloadDialog gui) {
+		updateBboxFields(gui);
+		updateUrl(gui);
+		updateSizeCheck(gui);
+	}
+	
+	private void updateBboxFields(DownloadDialog gui) {
+		latlon[0].setText(Double.toString(gui.minlat));
+		latlon[1].setText(Double.toString(gui.minlon));
+		latlon[2].setText(Double.toString(gui.maxlat));
+		latlon[3].setText(Double.toString(gui.maxlon));
+		for (JTextField f : latlon) 
+			f.setCaretPosition(0);
+	}
+	
+	private void updateUrl(DownloadDialog gui) {	
+		double lat = (gui.minlat + gui.maxlat)/2;
+		double lon = (gui.minlon + gui.maxlon)/2;
+		// convert to mercator (for calculation of zoom only)
+		double latMin = Math.log(Math.tan(Math.PI/4.0+gui.minlat/180.0*Math.PI/2.0))*180.0/Math.PI;
+		double latMax = Math.log(Math.tan(Math.PI/4.0+gui.maxlat/180.0*Math.PI/2.0))*180.0/Math.PI;
+		double size = Math.max(Math.abs(latMax-latMin), Math.abs(gui.maxlon-gui.minlon));
+		int zoom = 0;
+		while (zoom <= 20) {
+			if (size >= 180)
+				break;
+			size *= 2;
+			zoom++;
+		}
+		osmUrl.setText("http://www.openstreetmap.org/index.html?lat="+lat+"&lon="+lon+"&zoom="+zoom);
+	}
+	
+	private void updateSizeCheck(DownloadDialog gui) {
+		double squareDegrees = (gui.maxlon-gui.minlon)*(gui.maxlat-gui.minlat);
+		double maxBboxSize = 0.25;
+		try {
+			Double.parseDouble(Main.pref.get("osm-server.max-request-area", "0.25"));
+		} catch (NumberFormatException nfe) {
+			maxBboxSize = 0.25;
+		}
+		if (squareDegrees > maxBboxSize) {
+			sizeCheck.setText(tr("Download area too large; will probably be rejected by server"));
+			sizeCheck.setForeground(Color.red);
+		} else {
+			sizeCheck.setText(tr("Download area ok, size probably acceptable to server"));
+			sizeCheck.setForeground(Color.darkGray);
+		}
+	}
+	
+	public static Bounds osmurl2bounds(String url) {
+		int i = url.indexOf('?');
+		if (i == -1)
+			return null;
+		String[] args = url.substring(i+1).split("&");
+		HashMap<String, Double> map = new HashMap<String, Double>();
+		for (String arg : args) {
+			int eq = arg.indexOf('=');
+			if (eq != -1) {
+				try {
+					map.put(arg.substring(0, eq), Double.parseDouble(arg.substring(eq + 1)));
+				} catch (NumberFormatException e) {
+				}
+			}
+		}
+		try {
+			double size = 180.0 / Math.pow(2, map.get("zoom"));
+			return new Bounds(
+					new LatLon(map.get("lat") - size/2, map.get("lon") - size),
+					new LatLon(map.get("lat") + size/2, map.get("lon") + size));
+		} catch (Exception x) { // NPE or IAE
+			return null;
+		}
+	}
+}
Index: src/org/openstreetmap/josm/gui/download/DownloadDialog.java
===================================================================
--- src/org/openstreetmap/josm/gui/download/DownloadDialog.java	(revision 237)
+++ src/org/openstreetmap/josm/gui/download/DownloadDialog.java	(revision 237)
@@ -0,0 +1,143 @@
+package org.openstreetmap.josm.gui.download;
+
+import static org.openstreetmap.josm.tools.I18n.tr;
+
+import java.awt.Dimension;
+import java.awt.GridBagLayout;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+
+import javax.swing.JCheckBox;
+import javax.swing.JLabel;
+import javax.swing.JPanel;
+import javax.swing.JTabbedPane;
+
+import org.openstreetmap.josm.Main;
+import org.openstreetmap.josm.actions.DownloadAction;
+import org.openstreetmap.josm.actions.downloadtasks.DownloadGpsTask;
+import org.openstreetmap.josm.actions.downloadtasks.DownloadOsmTask;
+import org.openstreetmap.josm.data.Bounds;
+import org.openstreetmap.josm.data.coor.LatLon;
+import org.openstreetmap.josm.gui.MapView;
+import org.openstreetmap.josm.plugins.PluginProxy;
+import org.openstreetmap.josm.tools.GBC;
+
+/**
+ * Main download dialog.
+ * 
+ * Can be extended by plugins in two ways:
+ * (1) by adding download tasks that are then called with the selected bounding box
+ * (2) by adding "DownloadSelection" objects that implement different ways of selecting a bounding box
+ * 
+ * @author Frederik Ramm <frederik@remote.org>
+ *
+ */
+public class DownloadDialog extends JPanel {
+	
+
+	public interface DownloadTask {
+		/**
+		 * Execute the download.
+		 */
+		void download(DownloadAction action, double minlat, double minlon, double maxlat, double maxlon);
+		/**
+		 * @return The checkbox presented to the user
+		 */
+		JCheckBox getCheckBox();
+		/**
+		 * @return The name of the preferences suffix to use for storing the
+		 * selection state.
+		 */
+		String getPreferencesSuffix();
+	}
+
+	/**
+	 * The list of download tasks. First entry should be the osm data entry
+	 * and the second the gps entry. After that, plugins can register additional
+	 * download possibilities.
+	 */
+	public final List<DownloadTask> downloadTasks = new ArrayList<DownloadTask>(5);
+
+	public final List<DownloadSelection> downloadSelections = new ArrayList<DownloadSelection>();
+	
+	public double minlon;
+	public double minlat;
+	public double maxlon;
+	public double maxlat;
+	
+	public JTabbedPane tabpane = new JTabbedPane();
+	
+	public DownloadDialog(int tabindex)
+	{
+		setLayout(new GridBagLayout());
+		
+		downloadTasks.add(new DownloadOsmTask());
+		downloadTasks.add(new DownloadGpsTask());
+		
+		// adding the download tasks
+		add(new JLabel(tr("Data Sources and Types")), GBC.eol().insets(0,5,0,0));
+		for (DownloadTask task : downloadTasks) {
+			add(task.getCheckBox(), GBC.eol().insets(20,0,0,0));
+			task.getCheckBox().setSelected(Main.pref.getBoolean("download."+task.getPreferencesSuffix()));
+		}
+		
+		// predefined download selections
+		downloadSelections.add(new BoundingBoxSelection());
+		downloadSelections.add(new BookmarkSelection());	
+		downloadSelections.add(new WorldChooser());
+		
+		// add selections from plugins
+		for (PluginProxy p : Main.plugins) {
+			p.addDownloadSelection(downloadSelections);
+		}
+		
+		// now everybody may add their tab to the tabbed pane
+		// (not done right away to allow plugins to remove one of
+		// the default selectors!)
+		for (DownloadSelection s : downloadSelections) {
+			s.addGui(this);
+		}
+		
+		if (Main.map != null) {
+			MapView mv = Main.map.mapView;
+			minlon = mv.getLatLon(0, mv.getHeight()).lon();
+			minlat = mv.getLatLon(0, mv.getHeight()).lat();
+			maxlon = mv.getLatLon(mv.getWidth(), 0).lon();
+			maxlat = mv.getLatLon(mv.getWidth(), 0).lat();
+			boundingBoxChanged(null);
+		}
+		
+		add(new JLabel(tr("Download Area")), GBC.eol().insets(0,5,0,0));
+		add(tabpane, GBC.eol().fill());
+		
+		try {
+			tabpane.setSelectedIndex(tabindex);
+		} catch (Exception ex) {
+			// ignore
+		}
+		//Dimension d = getPreferredSize();
+		//setPreferredSize(new Dimension((int)(d.width*1.5), d.height));
+		//wc.addInputFields(latlon, osmUrl, osmUrlRefresher);
+	}
+	
+	/**
+	 * Distributes a "bounding box changed" from ohne DownloadSelection 
+	 * object to the others, so they may update or clear their input 
+	 * fields.
+	 * 
+	 * @param eventSource - the DownloadSelection object that fired this notification.
+	 */
+	public void boundingBoxChanged(DownloadSelection eventSource) {
+		for (DownloadSelection s : downloadSelections) {
+			if (s != eventSource) s.boundingBoxChanged(this);
+		}	
+	}
+
+	/*
+	 * Returns currently selected tab.
+	 */
+	public int getSelectedTab() {
+		return tabpane.getSelectedIndex();
+	}
+}
Index: src/org/openstreetmap/josm/gui/download/DownloadSelection.java
===================================================================
--- src/org/openstreetmap/josm/gui/download/DownloadSelection.java	(revision 237)
+++ src/org/openstreetmap/josm/gui/download/DownloadSelection.java	(revision 237)
@@ -0,0 +1,18 @@
+package org.openstreetmap.josm.gui.download;
+
+import org.openstreetmap.josm.data.coor.LatLon;
+import org.openstreetmap.josm.gui.preferences.PreferenceDialog;
+
+public interface DownloadSelection {
+	/**
+	 * Add the GUI elements to the dialog. 
+	 */
+	void addGui(DownloadDialog gui);
+
+	/** 
+	 * Update or clear display when a selection is made through another
+	 * DownloadSelection object
+	 */
+	void boundingBoxChanged(DownloadDialog gui);
+	
+}
Index: src/org/openstreetmap/josm/gui/download/WorldChooser.java
===================================================================
--- src/org/openstreetmap/josm/gui/download/WorldChooser.java	(revision 237)
+++ src/org/openstreetmap/josm/gui/download/WorldChooser.java	(revision 237)
@@ -0,0 +1,185 @@
+package org.openstreetmap.josm.gui.download;
+
+import static org.openstreetmap.josm.tools.I18n.tr;
+import java.awt.BorderLayout;
+import java.awt.Color;
+import java.awt.Dimension;
+import java.awt.Graphics;
+import java.awt.Point;
+import java.awt.Rectangle;
+import java.awt.event.KeyAdapter;
+import java.awt.event.KeyEvent;
+import java.awt.event.KeyListener;
+import java.beans.PropertyChangeListener;
+import java.net.URL;
+
+import javax.swing.ImageIcon;
+import javax.swing.JLabel;
+import javax.swing.JPanel;
+import javax.swing.JTextField;
+import javax.swing.SwingUtilities;
+import javax.swing.event.ListSelectionEvent;
+import javax.swing.event.ListSelectionListener;
+
+import org.openstreetmap.josm.Main;
+import org.openstreetmap.josm.data.Preferences;
+import org.openstreetmap.josm.data.coor.EastNorth;
+import org.openstreetmap.josm.data.coor.LatLon;
+import org.openstreetmap.josm.data.projection.Projection;
+import org.openstreetmap.josm.gui.BookmarkList;
+import org.openstreetmap.josm.gui.MapMover;
+import org.openstreetmap.josm.gui.MapScaler;
+import org.openstreetmap.josm.gui.NavigatableComponent;
+import org.openstreetmap.josm.gui.SelectionManager;
+import org.openstreetmap.josm.gui.SelectionManager.SelectionEnded;
+
+
+/**
+ * A component that let the user select a lat/lon bounding box from zooming
+ * into the world as a picture and selecting a region.
+ *
+ * The component has to be of the aspect ration 2:1 to look good.
+ *
+ * @author imi
+ */
+public class WorldChooser extends NavigatableComponent implements DownloadSelection {
+
+	/**
+	 * The world as picture.
+	 */
+	private ImageIcon world;
+
+	/**
+	 * Maximum scale level
+	 */
+	private double scaleMax;
+
+	/**
+	 * Mark this rectangle (lat/lon values) when painting.
+	 */
+	private EastNorth markerMin, markerMax;
+
+	private Projection projection;
+
+	/**
+	 * Create the chooser component.
+	 */
+	public WorldChooser() {
+		URL path = Main.class.getResource("/images/world.jpg");
+		world = new ImageIcon(path);
+		center = new EastNorth(world.getIconWidth()/2, world.getIconHeight()/2);
+		setPreferredSize(new Dimension(400, 200));
+
+		projection = new Projection() {
+			public EastNorth latlon2eastNorth(LatLon p) {
+				return new EastNorth(
+						(p.lon()+180) / 360 * world.getIconWidth(),
+						(p.lat()+90) / 180 * world.getIconHeight());
+			}
+			public LatLon eastNorth2latlon(EastNorth p) {
+				return new LatLon(
+						p.north()*180/world.getIconHeight() - 90,
+						p.east()*360/world.getIconWidth() - 180);
+			}
+			@Override public String toString() {
+				return "WorldChooser";
+			}
+            public String getCacheDirectoryName() {
+                throw new UnsupportedOperationException();
+            }
+			public double scaleFactor() {
+	            return 1.0 / world.getIconWidth();
+            }
+
+		};
+
+		MapScaler scaler = new MapScaler(this, projection);
+		add(scaler);
+		scaler.setLocation(10,10);
+
+		setMinimumSize(new Dimension(350, 350/2));
+	}
+
+	public void addGui(final DownloadDialog gui) {
+		JPanel temp = new JPanel();
+		temp.setLayout(new BorderLayout());
+		temp.add(this, BorderLayout.CENTER);
+		temp.add(new JLabel(tr("You can use the mouse or Ctrl+Arrow keys/./, to zoom and pan.")), BorderLayout.SOUTH);
+		gui.tabpane.add(temp, "Map");
+		new MapMover(this, temp);		
+		SelectionEnded selListener = new SelectionEnded(){
+			public void selectionEnded(Rectangle r, boolean alt, boolean shift, boolean ctrl) {
+				markerMin = getEastNorth(r.x, r.y+r.height);
+				markerMax = getEastNorth(r.x+r.width, r.y);
+				LatLon min = getProjection().eastNorth2latlon(markerMin);
+				LatLon max = getProjection().eastNorth2latlon(markerMax);
+				gui.minlat = min.lat();
+				gui.minlon = min.lon();
+				gui.maxlat = max.lat();
+				gui.maxlon = max.lon();
+				gui.boundingBoxChanged(WorldChooser.this);
+				repaint();
+			}
+			public void addPropertyChangeListener(PropertyChangeListener listener) {}
+			public void removePropertyChangeListener(PropertyChangeListener listener) {}
+		};
+		SelectionManager sm = new SelectionManager(selListener, false, this);
+		sm.register(this);
+    }
+
+	public void boundingBoxChanged(DownloadDialog gui) {
+		markerMin = getProjection().latlon2eastNorth(new LatLon(gui.minlat, gui.minlon));
+		markerMax = getProjection().latlon2eastNorth(new LatLon(gui.maxlat, gui.maxlon));
+		repaint();
+	}
+
+	/**
+	 * Set the scale as well as the preferred size.
+	 */
+	@Override public void setPreferredSize(Dimension preferredSize) {
+		super.setPreferredSize(preferredSize);
+		scale = world.getIconWidth()/preferredSize.getWidth();
+		scaleMax = scale;
+	}
+
+	/**
+	 * Draw the current selected region.
+	 */
+	@Override public void paint(Graphics g) {
+		EastNorth tl = getEastNorth(0,0);
+		EastNorth br = getEastNorth(getWidth(),getHeight());
+		g.drawImage(world.getImage(),0,0,getWidth(),getHeight(),(int)tl.east(),(int)tl.north(),(int)br.east(),(int)br.north(), null);
+
+		// draw marker rect
+		if (markerMin != null && markerMax != null) {
+			Point p1 = getPoint(markerMin);
+			Point p2 = getPoint(markerMax);
+			double x = Math.min(p1.x, p2.x);
+			double y = Math.min(p1.y, p2.y);
+			double w = Math.max(p1.x, p2.x) - x;
+			double h = Math.max(p1.y, p2.y) - y;
+			if (w < 1)
+				w = 1;
+			if (h < 1)
+				h = 1;
+			g.setColor(Color.YELLOW);
+			g.drawRect((int)x, (int)y, (int)w, (int)h);
+		}
+		super.paint(g);
+	}
+
+	@Override public void zoomTo(EastNorth newCenter, double scale) {
+		if (getWidth() != 0 && scale > scaleMax) {
+			scale = scaleMax;
+			newCenter = center;
+		}
+		super.zoomTo(newCenter, scale);
+	}
+
+	/**
+	 * Always use our image projection mode.
+	 */
+	@Override protected Projection getProjection() {
+		return projection;
+	}
+}
Index: src/org/openstreetmap/josm/plugins/Plugin.java
===================================================================
--- src/org/openstreetmap/josm/plugins/Plugin.java	(revision 236)
+++ src/org/openstreetmap/josm/plugins/Plugin.java	(revision 237)
@@ -8,7 +8,9 @@
 import java.net.URL;
 import java.net.URLClassLoader;
+import java.util.List;
 
 import org.openstreetmap.josm.Main;
 import org.openstreetmap.josm.gui.MapFrame;
+import org.openstreetmap.josm.gui.download.DownloadSelection;
 import org.openstreetmap.josm.gui.preferences.PreferenceSetting;
 
@@ -75,6 +77,11 @@
 	 * if any available.
 	 */
-	public PreferenceSetting getPreferenceSetting() {return null;}
+	public PreferenceSetting getPreferenceSetting() { return null; }
 	
+	/**
+	 * Called in the download dialog to give the plugin a chance to modify the list
+	 * of bounding box selectors.
+	 */
+	public void addDownloadSelection(List<DownloadSelection> list) {}
 	
 	/**
Index: src/org/openstreetmap/josm/plugins/PluginProxy.java
===================================================================
--- src/org/openstreetmap/josm/plugins/PluginProxy.java	(revision 236)
+++ src/org/openstreetmap/josm/plugins/PluginProxy.java	(revision 237)
@@ -1,5 +1,8 @@
 package org.openstreetmap.josm.plugins;
 
+import java.util.List;
+
 import org.openstreetmap.josm.gui.MapFrame;
+import org.openstreetmap.josm.gui.download.DownloadSelection;
 import org.openstreetmap.josm.gui.preferences.PreferenceSetting;
 
@@ -41,3 +44,13 @@
 		}
     }
+	
+	@Override public void addDownloadSelection(List<DownloadSelection> list) {
+		try {
+			plugin.getClass().getMethod("getDownloadSelection", List.class).invoke(plugin);
+		} catch (NoSuchMethodException e) {
+			// ignore
+		} catch (Exception e) {
+			throw new PluginException(this, info.name, e);
+		}
+	}
 }
