Index: src/org/openstreetmap/josm/io/BoundingBoxDownloader.java
===================================================================
--- src/org/openstreetmap/josm/io/BoundingBoxDownloader.java    (revision 1809)
+++ src/org/openstreetmap/josm/io/BoundingBoxDownloader.java    (working copy)
@@ -7,8 +7,9 @@
 import java.io.InputStream;
 
 import org.openstreetmap.josm.Main;
-import org.openstreetmap.josm.data.osm.DataSet;
 import org.openstreetmap.josm.data.gpx.GpxData;
+import org.openstreetmap.josm.data.osm.DataSet;
+import org.openstreetmap.josm.gui.progress.ProgressMonitor;
 import org.xml.sax.SAXException;
 
 
@@ -38,20 +39,21 @@
      *      contain only one list, since the server cannot distinguish between
      *      ways.
      */
-    public GpxData parseRawGps() throws IOException, SAXException {
-        Main.pleaseWaitDlg.progress.setValue(0);
-        Main.pleaseWaitDlg.currentAction.setText(tr("Contacting OSM Server..."));
+    public GpxData parseRawGps(ProgressMonitor progressMonitor) throws IOException, SAXException {
+        progressMonitor.beginTask("", 1);
         try {
+            progressMonitor.indeterminateSubTask(tr("Contacting OSM Server..."));
             String url = "trackpoints?bbox="+lon1+","+lat1+","+lon2+","+lat2+"&page=";
 
             boolean done = false;
             GpxData result = null;
             for (int i = 0;!done;++i) {
-                Main.pleaseWaitDlg.currentAction.setText(tr("Downloading points {0} to {1}...", i * 5000, ((i + 1) * 5000)));
-                InputStream in = getInputStream(url+i, Main.pleaseWaitDlg);
+                progressMonitor.subTask(tr("Downloading points {0} to {1}...", i * 5000, ((i + 1) * 5000)));
+                InputStream in = getInputStream(url+i, progressMonitor.createSubTaskMonitor(1, true));
                 if (in == null) {
                     break;
                 }
+                progressMonitor.setTicks(0);
                 GpxData currentGpx = new GpxReader(in, null).data;
                 if (result == null) {
                     result = currentGpx;
@@ -82,6 +84,8 @@
             if (e instanceof RuntimeException)
                 throw (RuntimeException)e;
             throw new RuntimeException(e);
+        } finally {
+            progressMonitor.finishTask();
         }
     }
 
@@ -90,17 +94,14 @@
      * @return A data set containing all data retrieved from that url
      */
     @Override
-    public DataSet parseOsm() throws OsmTransferException {
+    public DataSet parseOsm(ProgressMonitor progressMonitor) throws OsmTransferException {
+        progressMonitor.beginTask(tr("Contacting OSM Server..."), 10);
         try {
-            Main.pleaseWaitDlg.progress.setValue(0);
-            Main.pleaseWaitDlg.currentAction.setText(tr("Contacting OSM Server..."));
-            Main.pleaseWaitDlg.setIndeterminate(true);
-            final InputStream in = getInputStream("map?bbox="+lon1+","+lat1+","+lon2+","+lat2, Main.pleaseWaitDlg);
-            Main.pleaseWaitDlg.setIndeterminate(false);
+            progressMonitor.indeterminateSubTask(null);
+            final InputStream in = getInputStream("map?bbox="+lon1+","+lat1+","+lon2+","+lat2, progressMonitor.createSubTaskMonitor(9, false));
             if (in == null)
                 return null;
-            Main.pleaseWaitDlg.currentAction.setText(tr("Downloading OSM data..."));
-            final DataSet data = OsmReader.parseDataSet(in,Main.pleaseWaitDlg);
+            final DataSet data = OsmReader.parseDataSet(in, progressMonitor.createSubTaskMonitor(1, false));
             in.close();
             activeConnection = null;
             return data;
@@ -116,6 +117,8 @@
             if (cancel)
                 return null;
             throw new OsmTransferException(e);
+        } finally {
+            progressMonitor.finishTask();
         }
     }
 }
Index: src/org/openstreetmap/josm/io/MultiFetchServerObjectReader.java
===================================================================
--- src/org/openstreetmap/josm/io/MultiFetchServerObjectReader.java (revision 1809)
+++ src/org/openstreetmap/josm/io/MultiFetchServerObjectReader.java (working copy)
@@ -3,7 +3,6 @@
 
 import static org.openstreetmap.josm.tools.I18n.tr;
 
-import java.io.IOException;
 import java.io.InputStream;
 import java.net.HttpURLConnection;
 import java.util.Collection;
@@ -13,7 +12,6 @@
 import java.util.Set;
 import java.util.logging.Logger;
 
-import org.openstreetmap.josm.Main;
 import org.openstreetmap.josm.data.osm.DataSet;
 import org.openstreetmap.josm.data.osm.Node;
 import org.openstreetmap.josm.data.osm.OsmPrimitive;
@@ -22,12 +20,13 @@
 import org.openstreetmap.josm.data.osm.RelationMember;
 import org.openstreetmap.josm.data.osm.Way;
 import org.openstreetmap.josm.data.osm.visitor.MergeVisitor;
-import org.xml.sax.SAXException;
+import org.openstreetmap.josm.gui.progress.NullProgressMonitor;
+import org.openstreetmap.josm.gui.progress.ProgressMonitor;
 
 /**
  * Retrieves a set of {@see OsmPrimitive}s from an OSM server using the so called
  * Multi Fetch API.
- * 
+ *
  * Usage:
  * <pre>
  *    MultiFetchServerObjectReader reader = MultiFetchServerObjectReader()
@@ -41,7 +40,7 @@
  *       System.out.println("There are skipped ways: " + reader.getMissingPrimitives());
  *    }
  * </pre>
- * 
+ *
  *
  */
 public class MultiFetchServerObjectReader extends OsmServerReader{
@@ -52,7 +51,7 @@
      * this leads to a max. request URL of ~  1600 Bytes ((7 digits +  1 Seperator) * 200),
      * which should be safe according to the
      * <a href="http://www.boutell.com/newfaq/misc/urllength.html">WWW FAQ</a>.
-     * 
+     *
      */
     static private int MAX_IDS_PER_REQUEST = 200;
 
@@ -78,9 +77,9 @@
     /**
      * remembers an {@see OsmPrimitive}'s id and its type. The id will
      * later be fetched as part of a Multi Get request.
-     * 
+     *
      * Ignore the id if it id <= 0.
-     * 
+     *
      * @param id  the id
      * @param type  the type
      */
@@ -99,9 +98,9 @@
      * remembers an {@see OsmPrimitive}'s id. <code>ds</code> must include
      * an {@see OsmPrimitive} with id=<code>id</code>. The id will
      * later we fetched as part of a Multi Get request.
-     * 
+     *
      * Ignore the id if it id <= 0.
-     * 
+     *
      * @param ds  the dataset (must not be null)
      * @param id  the id
      * @exception IllegalArgumentException thrown, if ds is null
@@ -122,13 +121,13 @@
     /**
      * appends a list of  ids to the list of ids which will be fetched from the server. ds must
      * include an {@see OsmPrimitive} for each id in ids.
-     * 
+     *
      * id is ignored if id <= 0.
-     * 
+     *
      * @param ds  the dataset
      * @param ids  the list of ids
      * @return this
-     * 
+     *
      */
     public MultiFetchServerObjectReader append(DataSet ds, long ... ids)  {
         if (ids == null) return this;
@@ -141,13 +140,13 @@
     /**
      * appends a collection of  ids to the list of ids which will be fetched from the server. ds must
      * include an {@see OsmPrimitive} for each id in ids.
-     * 
+     *
      * id is ignored if id <= 0.
-     * 
+     *
      * @param ds  the dataset
      * @param ids  the collection of ids
      * @return this
-     * 
+     *
      */
     public MultiFetchServerObjectReader append(DataSet ds, Collection<Long> ids) {
         if (ids == null) return null;
@@ -162,7 +161,7 @@
      *
      * @param node  the node (ignored, if null)
      * @return this
-     * 
+     *
      */
     public MultiFetchServerObjectReader append(Node node) {
         if (node == null) return this;
@@ -176,7 +175,7 @@
      *
      * @param way the way (ignored, if null)
      * @return this
-     * 
+     *
      */
     public MultiFetchServerObjectReader append(Way way) {
         if (way == null) return this;
@@ -195,7 +194,7 @@
      *
      * @param relation  the relation (ignored, if null)
      * @return this
-     * 
+     *
      */
     public MultiFetchServerObjectReader append(Relation relation) {
         if (relation == null) return this;
@@ -224,11 +223,11 @@
      *
      * @param primitives  the list of primitives (ignored, if null)
      * @return this
-     * 
+     *
      * @see #append(Node)
      * @see #append(Way)
      * @see #append(Relation)
-     * 
+     *
      */
     public MultiFetchServerObjectReader append(Collection<OsmPrimitive> primitives) {
         if (primitives == null) return this;
@@ -241,7 +240,7 @@
     /**
      * extracts a subset of max {@see #MAX_IDS_PER_REQUEST} ids from <code>ids</code> and
      * replies the subset. The extracted subset is removed from <code>ids</code>.
-     * 
+     *
      * @param ids a set of ids
      * @return the subset of ids
      */
@@ -266,7 +265,7 @@
     /**
      * builds the Multi Get request string for a set of ids and a given
      * {@see OsmPrimitiveType}.
-     * 
+     *
      * @param type the type
      * @param idPackage  the package of ids
      * @return the request string
@@ -289,7 +288,7 @@
     /**
      * builds the Multi Get request string for a single id and a given
      * {@see OsmPrimitiveType}.
-     * 
+     *
      * @param type the type
      * @param id the id
      * @return the request string
@@ -305,19 +304,19 @@
     /**
      * invokes a Multi Get for a set of ids and a given {@see OsmPrimitiveType}.
      * The retrieved primitives are merged to {@see #outputDataSet}.
-     * 
+     *
      * @param type the type
      * @param pkg the package of ids
      * @exception OsmTransferException thrown if an error occurs while communicating with the API server
-     * 
+     *
      */
-    protected void multiGetIdPackage(OsmPrimitiveType type, Set<Long> pkg) throws OsmTransferException {
+    protected void multiGetIdPackage(OsmPrimitiveType type, Set<Long> pkg, ProgressMonitor progressMonitor) throws OsmTransferException {
         String request = buildRequestString(type, pkg);
-        final InputStream in = getInputStream(request, Main.pleaseWaitDlg);
+        final InputStream in = getInputStream(request, NullProgressMonitor.INSTANCE);
         if (in == null) return;
-        Main.pleaseWaitDlg.currentAction.setText(tr("Downloading OSM data..."));
+        progressMonitor.subTask(tr("Downloading OSM data..."));
         try {
-            final OsmReader osm = OsmReader.parseDataSetOsm(in, Main.pleaseWaitDlg);
+            final OsmReader osm = OsmReader.parseDataSetOsm(in, progressMonitor.createSubTaskMonitor(ProgressMonitor.ALL_TICKS, false));
             merge(osm.getDs());
         } catch(Exception e) {
             throw new OsmTransferException(e);
@@ -327,20 +326,20 @@
     /**
      * invokes a Multi Get for a single id and a given {@see OsmPrimitiveType}.
      * The retrieved primitive is merged to {@see #outputDataSet}.
-     * 
+     *
      * @param type the type
      * @param id the id
      * @exception OsmTransferException thrown if an error occurs while communicating with the API server
-     * 
+     *
      */
-    protected void singleGetId(OsmPrimitiveType type, long id) throws OsmTransferException {
+    protected void singleGetId(OsmPrimitiveType type, long id, ProgressMonitor progressMonitor) throws OsmTransferException {
         String request = buildRequestString(type, id);
-        final InputStream in = getInputStream(request, Main.pleaseWaitDlg);
+        final InputStream in = getInputStream(request, NullProgressMonitor.INSTANCE);
         if (in == null)
             return;
-        Main.pleaseWaitDlg.currentAction.setText(tr("Downloading OSM data..."));
+        progressMonitor.subTask(tr("Downloading OSM data..."));
         try {
-            final OsmReader osm = OsmReader.parseDataSetOsm(in,Main.pleaseWaitDlg);
+            final OsmReader osm = OsmReader.parseDataSetOsm(in, progressMonitor.createSubTaskMonitor(ProgressMonitor.ALL_TICKS, false));
             merge(osm.getDs());
         } catch(Exception e) {
             throw new OsmTransferException(e);
@@ -350,20 +349,20 @@
     /**
      * invokes a sequence of Multi Gets for individual ids in a set of ids and a given {@see OsmPrimitiveType}.
      * The retrieved primitives are merged to {@see #outputDataSet}.
-     * 
+     *
      * This method is used if one of the ids in pkg doesn't exist (the server replies with return code 404).
      * If the set is fetched with this method it is possible to find out which of the ids doesn't exist.
      * Unfortunatelly, the server does not provide an error header or an error body for a 404 reply.
-     * 
+     *
      * @param type the type
      * @param pkg the set of ids
      * @exception OsmTransferException thrown if an error occurs while communicating with the API server
-     * 
+     *
      */
-    protected void singleGetIdPackage(OsmPrimitiveType type, Set<Long> pkg) throws OsmTransferException {
+    protected void singleGetIdPackage(OsmPrimitiveType type, Set<Long> pkg, ProgressMonitor progressMonitor) throws OsmTransferException {
         for (long id : pkg) {
             try {
-                singleGetId(type, id);
+                singleGetId(type, id, progressMonitor);
             } catch(OsmApiException e) {
                 if (e.getResponseCode() == HttpURLConnection.HTTP_NOT_FOUND) {
                     logger.warning(tr("Server replied with response code 404 for id {0}. Skipping.", Long.toString(id)));
@@ -377,9 +376,9 @@
 
     /**
      * merges the dataset <code>from</code> to {@see #outputDataSet}.
-     * 
+     *
      * @param from the other dataset
-     * 
+     *
      */
     protected void merge(DataSet from) {
         final MergeVisitor visitor = new MergeVisitor(outputDataSet,from);
@@ -388,22 +387,22 @@
 
     /**
      * fetches a set of ids of a given {@see OsmPrimitiveType} from the server
-     * 
+     *
      * @param ids the set of ids
      * @param type the  type
      * @exception OsmTransferException thrown if an error occurs while communicating with the API server
      */
-    protected void fetchPrimitives(Set<Long> ids, OsmPrimitiveType type) throws OsmTransferException{
+    protected void fetchPrimitives(Set<Long> ids, OsmPrimitiveType type, ProgressMonitor progressMonitor) throws OsmTransferException{
         Set<Long> toFetch = new HashSet<Long>(ids);
         toFetch.addAll(ids);
         while(! toFetch.isEmpty()) {
             Set<Long> pkg = extractIdPackage(toFetch);
             try {
-                multiGetIdPackage(type, pkg);
+                multiGetIdPackage(type, pkg, progressMonitor);
             } catch(OsmApiException e) {
                 if (e.getResponseCode() == HttpURLConnection.HTTP_NOT_FOUND) {
                     logger.warning(tr("Server replied with response code 404, retrying with an individual request for each primitive"));
-                    singleGetIdPackage(type, pkg);
+                    singleGetIdPackage(type, pkg, progressMonitor);
                 } else
                     throw e;
             }
@@ -416,35 +415,40 @@
      * In contrast to a simple Get for a node, a way, or a relation, a Multi Get always replies
      * the latest version of the primitive (if any), even if the primitive is not visible (i.e. if
      * visible==false).
-     * 
+     *
      * Invoke {@see #getMissingPrimitives()} to get a list of primitives which have not been
      * found on  the server (the server response code was 404)
-     * 
+     *
      * Invoke {@see #getSkippedWay()} to get a list of ways which this reader could not build from
      * the fetched data because the ways refer to nodes which don't exist on the server.
-     * 
+     *
      * @return the parsed data
      * @exception OsmTransferException thrown if an error occurs while communicating with the API server
      * @see #getMissingPrimitives()
      * @see #getSkippedWays()
-     * 
+     *
 
      */
     @Override
-    public DataSet parseOsm() throws OsmTransferException {
-        missingPrimitives = new HashSet<Long>();
+    public DataSet parseOsm(ProgressMonitor progressMonitor) throws OsmTransferException {
+        progressMonitor.beginTask("");
+        try {
+            missingPrimitives = new HashSet<Long>();
 
-        fetchPrimitives(nodes,OsmPrimitiveType.NODE);
-        fetchPrimitives(ways,OsmPrimitiveType.WAY);
-        fetchPrimitives(relations,OsmPrimitiveType.RELATION);
-        return outputDataSet;
+            fetchPrimitives(nodes,OsmPrimitiveType.NODE, progressMonitor);
+            fetchPrimitives(ways,OsmPrimitiveType.WAY, progressMonitor);
+            fetchPrimitives(relations,OsmPrimitiveType.RELATION, progressMonitor);
+            return outputDataSet;
+        } finally {
+            progressMonitor.finishTask();
+        }
     }
 
     /**
      * replies the set of ids of all primitives for which a fetch request to the
      * server was submitted but which are not available from the server (the server
      * replied a return code of 404)
-     * 
+     *
      * @return the set of ids of missing primitives
      */
     public Set<Long> getMissingPrimitives() {
Index: src/org/openstreetmap/josm/io/OsmServerLocationReader.java
===================================================================
--- src/org/openstreetmap/josm/io/OsmServerLocationReader.java  (revision 1809)
+++ src/org/openstreetmap/josm/io/OsmServerLocationReader.java  (working copy)
@@ -3,12 +3,10 @@
 
 import static org.openstreetmap.josm.tools.I18n.tr;
 
-import java.io.IOException;
 import java.io.InputStream;
 
-import org.openstreetmap.josm.Main;
 import org.openstreetmap.josm.data.osm.DataSet;
-import org.xml.sax.SAXException;
+import org.openstreetmap.josm.gui.progress.ProgressMonitor;
 
 public class OsmServerLocationReader extends OsmServerReader {
 
@@ -22,17 +20,15 @@
      * Method to download OSM files from somewhere
      */
     @Override
-    public DataSet parseOsm() throws OsmTransferException {
+    public DataSet parseOsm(ProgressMonitor progressMonitor) throws OsmTransferException {
         InputStream in = null;
+        progressMonitor.beginTask(tr("Contacting Server...", 10));
         try {
-            Main.pleaseWaitDlg.progress.setValue(0);
-            Main.pleaseWaitDlg.currentAction.setText(tr("Contacting Server..."));
-
-            in = getInputStreamRaw(url, Main.pleaseWaitDlg);
+            in = getInputStreamRaw(url, progressMonitor.createSubTaskMonitor(9, false));
             if (in == null)
                 return null;
-            Main.pleaseWaitDlg.currentAction.setText(tr("Downloading OSM data..."));
-            return OsmReader.parseDataSet(in, Main.pleaseWaitDlg);
+            progressMonitor.subTask(tr("Downloading OSM data..."));
+            return OsmReader.parseDataSet(in, progressMonitor.createSubTaskMonitor(1, false));
         } catch(OsmTransferException e) {
             throw e;
         } catch (Exception e) {
@@ -40,6 +36,7 @@
                 return null;
             throw new OsmTransferException(e);
         } finally {
+            progressMonitor.finishTask();
             try {
                 if (in != null) {
                     in.close();
Index: src/org/openstreetmap/josm/io/OsmServerObjectReader.java
===================================================================
--- src/org/openstreetmap/josm/io/OsmServerObjectReader.java    (revision 1809)
+++ src/org/openstreetmap/josm/io/OsmServerObjectReader.java    (working copy)
@@ -6,9 +6,9 @@
 import java.io.IOException;
 import java.io.InputStream;
 
-import org.openstreetmap.josm.Main;
 import org.openstreetmap.josm.data.osm.DataSet;
 import org.openstreetmap.josm.data.osm.OsmPrimitiveType;
+import org.openstreetmap.josm.gui.progress.ProgressMonitor;
 import org.xml.sax.SAXException;
 
 public class OsmServerObjectReader extends OsmServerReader {
@@ -29,10 +29,10 @@
      * @throws IOException
      */
     @Override
-    public DataSet parseOsm() throws OsmTransferException {
+    public DataSet parseOsm(ProgressMonitor progressMonitor) throws OsmTransferException {
+        progressMonitor.beginTask("", 1);
         try {
-            Main.pleaseWaitDlg.progress.setValue(0);
-            Main.pleaseWaitDlg.currentAction.setText(tr("Contacting OSM Server..."));
+            progressMonitor.subTask(tr("Downloading OSM data..."));
             StringBuffer sb = new StringBuffer();
             sb.append(type.getAPIName());
             sb.append("/");
@@ -41,11 +41,10 @@
                 sb.append("/full");
             }
 
-            final InputStream in = getInputStream(sb.toString(), Main.pleaseWaitDlg);
+            final InputStream in = getInputStream(sb.toString(), progressMonitor.createSubTaskMonitor(1, true));
             if (in == null)
                 return null;
-            Main.pleaseWaitDlg.currentAction.setText(tr("Downloading OSM data..."));
-            final OsmReader osm = OsmReader.parseDataSetOsm(in,Main.pleaseWaitDlg);
+            final OsmReader osm = OsmReader.parseDataSetOsm(in, progressMonitor.createSubTaskMonitor(ProgressMonitor.ALL_TICKS, false));
             final DataSet data = osm.getDs();
 
             in.close();
@@ -63,6 +62,8 @@
             if (cancel)
                 return null;
             throw new OsmTransferException(e);
+        } finally {
+            progressMonitor.finishTask();
         }
     }
 
Index: src/org/openstreetmap/josm/io/OsmConnection.java
===================================================================
--- src/org/openstreetmap/josm/io/OsmConnection.java    (revision 1809)
+++ src/org/openstreetmap/josm/io/OsmConnection.java    (working copy)
@@ -10,9 +10,9 @@
 import java.net.PasswordAuthentication;
 import java.nio.ByteBuffer;
 import java.nio.CharBuffer;
+import java.nio.charset.CharacterCodingException;
 import java.nio.charset.Charset;
 import java.nio.charset.CharsetEncoder;
-import java.nio.charset.CharacterCodingException;
 
 import javax.swing.JCheckBox;
 import javax.swing.JLabel;
@@ -125,7 +125,8 @@
     }
 
     public void cancel() {
-        Main.pleaseWaitDlg.currentAction.setText(tr("Aborting..."));
+        //TODO
+        //Main.pleaseWaitDlg.currentAction.setText(tr("Aborting..."));
         cancel = true;
         if (activeConnection != null) {
             activeConnection.setConnectTimeout(100);
Index: src/org/openstreetmap/josm/io/OsmReader.java
===================================================================
--- src/org/openstreetmap/josm/io/OsmReader.java    (revision 1809)
+++ src/org/openstreetmap/josm/io/OsmReader.java    (working copy)
@@ -15,7 +15,6 @@
 import java.util.Map.Entry;
 import java.util.logging.Logger;
 
-import javax.swing.SwingUtilities;
 import javax.xml.parsers.ParserConfigurationException;
 import javax.xml.parsers.SAXParserFactory;
 
@@ -30,7 +29,7 @@
 import org.openstreetmap.josm.data.osm.User;
 import org.openstreetmap.josm.data.osm.Way;
 import org.openstreetmap.josm.data.osm.visitor.AddVisitor;
-import org.openstreetmap.josm.gui.PleaseWaitDialog;
+import org.openstreetmap.josm.gui.progress.ProgressMonitor;
 import org.openstreetmap.josm.tools.DateUtils;
 import org.xml.sax.Attributes;
 import org.xml.sax.InputSource;
@@ -69,9 +68,9 @@
 
     /**
      * constructor (for private use only)
-     * 
-     * @see #parseDataSet(InputStream, DataSet, PleaseWaitDialog)
-     * @see #parseDataSetOsm(InputStream, DataSet, PleaseWaitDialog)
+     *
+     * @see #parseDataSet(InputStream, DataSet, ProgressMonitor)
+     * @see #parseDataSetOsm(InputStream, DataSet, ProgressMonitor)
      */
     private OsmReader() {
     }
@@ -453,11 +452,11 @@
      *      the Reference is not found here, Main.ds is searched and a copy of the
      *  element found there is returned.
      */
-    public static DataSet parseDataSet(InputStream source, PleaseWaitDialog pleaseWaitDlg) throws SAXException, IOException {
-        return parseDataSetOsm(source, pleaseWaitDlg).ds;
+    public static DataSet parseDataSet(InputStream source, ProgressMonitor progressMonitor) throws SAXException, IOException {
+        return parseDataSetOsm(source, progressMonitor).ds;
     }
 
-    public static OsmReader parseDataSetOsm(InputStream source, final PleaseWaitDialog pleaseWaitDlg) throws SAXException, IOException {
+    public static OsmReader parseDataSetOsm(InputStream source, ProgressMonitor progressMonitor) throws SAXException, IOException {
         OsmReader osm = new OsmReader();
 
         // phase 1: Parse nodes and read in raw ways
@@ -469,42 +468,31 @@
             throw new SAXException(e1);
         }
 
-        SwingUtilities.invokeLater(
-                new Runnable() {
-                    public void run() {
-                        pleaseWaitDlg.currentAction.setText(tr("Prepare OSM data..."));
-                        pleaseWaitDlg.setIndeterminate(true);
-                    }
-                }
-        );
-
-        for (Node n : osm.nodes.values()) {
-            osm.adder.visit(n);
-        }
-
+        progressMonitor.beginTask(tr("Prepare OSM data...", 2));
         try {
-            osm.createWays();
-            osm.createRelations();
-        } catch (NumberFormatException e) {
-            e.printStackTrace();
-            throw new SAXException(tr("Ill-formed node id"));
-        }
+            for (Node n : osm.nodes.values()) {
+                osm.adder.visit(n);
+            }
+
+            progressMonitor.worked(1);
 
-        // clear all negative ids (new to this file)
-        for (OsmPrimitive o : osm.ds.allPrimitives())
-            if (o.id < 0) {
-                o.id = 0;
+            try {
+                osm.createWays();
+                osm.createRelations();
+            } catch (NumberFormatException e) {
+                e.printStackTrace();
+                throw new SAXException(tr("Ill-formed node id"));
             }
 
-        SwingUtilities.invokeLater(
-                new Runnable() {
-                    public void run() {
-                        pleaseWaitDlg.setIndeterminate(false);
-                        pleaseWaitDlg.progress.setValue(0);
-                    }
+            // clear all negative ids (new to this file)
+            for (OsmPrimitive o : osm.ds.allPrimitives())
+                if (o.id < 0) {
+                    o.id = 0;
                 }
-        );
 
-        return osm;
+            return osm;
+        } finally {
+            progressMonitor.finishTask();
+        }
     }
 }
Index: src/org/openstreetmap/josm/io/ProgressInputStream.java
===================================================================
--- src/org/openstreetmap/josm/io/ProgressInputStream.java  (revision 1809)
+++ src/org/openstreetmap/josm/io/ProgressInputStream.java  (working copy)
@@ -7,7 +7,8 @@
 import java.io.InputStream;
 import java.net.URLConnection;
 
-import org.openstreetmap.josm.gui.PleaseWaitDialog;
+import org.openstreetmap.josm.gui.progress.NullProgressMonitor;
+import org.openstreetmap.josm.gui.progress.ProgressMonitor;
 
 /**
  * Read from an other reader and increment an progress counter while on the way.
@@ -18,11 +19,18 @@
     private final InputStream in;
     private int readSoFar = 0;
     private int lastDialogUpdate = 0;
+    private boolean sizeKnown;
     private final URLConnection connection;
-    private PleaseWaitDialog pleaseWaitDlg;
+    private final ProgressMonitor progressMonitor;
 
-    public ProgressInputStream(URLConnection con, PleaseWaitDialog pleaseWaitDlg) throws OsmTransferException {
+    public ProgressInputStream(URLConnection con, ProgressMonitor progressMonitor) throws OsmTransferException {
         this.connection = con;
+        if (progressMonitor == null) {
+            progressMonitor = NullProgressMonitor.INSTANCE;
+        }
+        this.progressMonitor = progressMonitor;
+        progressMonitor.beginTask(tr("Contacting OSM Server..."), 1);
+        progressMonitor.indeterminateSubTask(null);
 
         try {
             this.in = con.getInputStream();
@@ -32,26 +40,23 @@
             throw new OsmTransferException(e);
         }
 
-        int contentLength = con.getContentLength();
-        this.pleaseWaitDlg = pleaseWaitDlg;
-        if (pleaseWaitDlg == null)
-            return;
-        if (contentLength > 0) {
-            pleaseWaitDlg.progress.setMaximum(contentLength);
-        } else {
-            pleaseWaitDlg.progress.setMaximum(0);
+        updateSize();
+        if (!sizeKnown) {
+            progressMonitor.indeterminateSubTask(tr("Downloading OSM data..."));
         }
-        pleaseWaitDlg.progress.setValue(0);
     }
 
     @Override public void close() throws IOException {
         in.close();
+        progressMonitor.finishTask();
     }
 
     @Override public int read(byte[] b, int off, int len) throws IOException {
         int read = in.read(b, off, len);
         if (read != -1) {
             advanceTicker(read);
+        } else {
+            progressMonitor.finishTask();
         }
         return read;
     }
@@ -60,6 +65,8 @@
         int read = in.read();
         if (read != -1) {
             advanceTicker(1);
+        } else {
+            progressMonitor.finishTask();
         }
         return read;
     }
@@ -69,29 +76,25 @@
      * @param amount
      */
     private void advanceTicker(int amount) {
-        if (pleaseWaitDlg == null)
-            return;
-
-        if (pleaseWaitDlg.progress.getMaximum() == 0 && connection.getContentLength() != -1) {
-            pleaseWaitDlg.progress.setMaximum(connection.getContentLength());
-        }
-
         readSoFar += amount;
+        updateSize();
 
         if (readSoFar / 1024 != lastDialogUpdate) {
             lastDialogUpdate++;
-            String progStr = " "+readSoFar/1024+"/";
-            progStr += (pleaseWaitDlg.progress.getMaximum()==0) ? "??? KB" : (pleaseWaitDlg.progress.getMaximum()/1024)+" KB";
-            pleaseWaitDlg.progress.setValue(readSoFar);
-
-            String cur = pleaseWaitDlg.currentAction.getText();
-            int i = cur.indexOf(' ');
-            if (i != -1) {
-                cur = cur.substring(0, i) + progStr;
+            if (sizeKnown) {
+                progressMonitor.setExtraText(readSoFar/1024 + " KB");
+                progressMonitor.setTicks(readSoFar);
             } else {
-                cur += progStr;
+                progressMonitor.setExtraText("??? KB");
             }
-            pleaseWaitDlg.currentAction.setText(cur);
+        }
+    }
+
+    private void updateSize() {
+        if (!sizeKnown && connection.getContentLength() > 0) {
+            sizeKnown = true;
+            progressMonitor.subTask(tr("Downloading OSM data..."));
+            progressMonitor.setTicksCount(connection.getContentLength());
         }
     }
 }
Index: src/org/openstreetmap/josm/io/OsmApi.java
===================================================================
--- src/org/openstreetmap/josm/io/OsmApi.java   (revision 1809)
+++ src/org/openstreetmap/josm/io/OsmApi.java   (working copy)
@@ -3,7 +3,6 @@
 
 import static org.openstreetmap.josm.tools.I18n.tr;
 
-import java.awt.EventQueue;
 import java.io.BufferedReader;
 import java.io.BufferedWriter;
 import java.io.IOException;
@@ -31,6 +30,7 @@
 import org.openstreetmap.josm.data.osm.OsmPrimitive;
 import org.openstreetmap.josm.data.osm.OsmPrimitiveType;
 import org.openstreetmap.josm.data.osm.visitor.CreateOsmChangeVisitor;
+import org.openstreetmap.josm.gui.progress.ProgressMonitor;
 import org.xml.sax.Attributes;
 import org.xml.sax.InputSource;
 import org.xml.sax.SAXException;
@@ -278,14 +278,18 @@
      * @param comment the "commit comment" for the new changeset
      * @throws OsmTransferException signifying a non-200 return code, or connection errors
      */
-    public void createChangeset(String comment) throws OsmTransferException {
-        changeset = new Changeset();
-        notifyStatusMessage(tr("Opening changeset..."));
-        Properties sysProp = System.getProperties();
-        Object ua = sysProp.get("http.agent");
-        changeset.put("created_by", (ua == null) ? "JOSM" : ua.toString());
-        changeset.put("comment", comment);
-        createPrimitive(changeset);
+    public void createChangeset(String comment, ProgressMonitor progressMonitor) throws OsmTransferException {
+        progressMonitor.beginTask((tr("Opening changeset...")));
+        try {
+            changeset = new Changeset();
+            Properties sysProp = System.getProperties();
+            Object ua = sysProp.get("http.agent");
+            changeset.put("created_by", (ua == null) ? "JOSM" : ua.toString());
+            changeset.put("comment", comment);
+            createPrimitive(changeset);
+        } finally {
+            progressMonitor.finishTask();
+        }
     }
 
     /**
@@ -293,11 +297,15 @@
      *
      * @throws OsmTransferException if something goes wrong.
      */
-    public void stopChangeset() throws OsmTransferException {
-        initialize();
-        notifyStatusMessage(tr("Closing changeset..."));
-        sendRequest("PUT", "changeset" + "/" + changeset.id + "/close", null);
-        changeset = null;
+    public void stopChangeset(ProgressMonitor progressMonitor) throws OsmTransferException {
+        progressMonitor.beginTask(tr("Closing changeset..."));
+        try {
+            initialize();
+            sendRequest("PUT", "changeset" + "/" + changeset.id + "/close", null);
+            changeset = null;
+        } finally {
+            progressMonitor.finishTask();
+        }
     }
 
     /**
@@ -307,37 +315,40 @@
      * @return list of processed primitives
      * @throws OsmTransferException if something is wrong
      */
-    public Collection<OsmPrimitive> uploadDiff(final Collection<OsmPrimitive> list) throws OsmTransferException {
+    public Collection<OsmPrimitive> uploadDiff(final Collection<OsmPrimitive> list, ProgressMonitor progressMonitor) throws OsmTransferException {
 
-        if (changeset == null)
-            throw new OsmTransferException(tr("No changeset present for diff upload"));
+        progressMonitor.beginTask("", list.size() * 2);
+        try {
+            if (changeset == null)
+                throw new OsmTransferException(tr("No changeset present for diff upload"));
 
-        initialize();
-        final ArrayList<OsmPrimitive> processed = new ArrayList<OsmPrimitive>();
+            initialize();
+            final ArrayList<OsmPrimitive> processed = new ArrayList<OsmPrimitive>();
 
-        CreateOsmChangeVisitor duv = new CreateOsmChangeVisitor(changeset, OsmApi.this);
+            CreateOsmChangeVisitor duv = new CreateOsmChangeVisitor(changeset, OsmApi.this);
 
-        notifyStatusMessage(tr("Preparing..."));
-        for (OsmPrimitive osm : list) {
-            osm.visit(duv);
-            notifyRelativeProgress(1);
-        }
-        notifyStatusMessage(tr("Uploading..."));
-        setAutoProgressIndication(true);
+            progressMonitor.subTask(tr("Preparing..."));
+            for (OsmPrimitive osm : list) {
+                osm.visit(duv);
+                progressMonitor.worked(1);
+            }
+            progressMonitor.indeterminateSubTask(tr("Uploading..."));
 
-        String diff = duv.getDocument();
-        try {
-            String diffresult = sendRequest("POST", "changeset/" + changeset.id + "/upload", diff);
-            DiffResultReader.parseDiffResult(diffresult, list, processed, duv.getNewIdMap(), Main.pleaseWaitDlg);
-        } catch(OsmTransferException e) {
-            throw e;
-        } catch(Exception e) {
-            throw new OsmTransferException(e);
+            String diff = duv.getDocument();
+            try {
+                String diffresult = sendRequest("POST", "changeset/" + changeset.id + "/upload", diff);
+                DiffResultReader.parseDiffResult(diffresult, list, processed, duv.getNewIdMap(),
+                        progressMonitor.createSubTaskMonitor(ProgressMonitor.ALL_TICKS, false));
+            } catch(OsmTransferException e) {
+                throw e;
+            } catch(Exception e) {
+                throw new OsmTransferException(e);
+            }
+
+            return processed;
         } finally {
-            setAutoProgressIndication(false);
+            progressMonitor.finishTask();
         }
-
-        return processed;
     }
 
 
@@ -467,40 +478,8 @@
     }
 
     /**
-     * notifies any listeners about the current state of this API. Currently just
-     * displays the message in the global progress dialog, see {@see Main#pleaseWaitDlg}
-     *
-     * @param message a status message.
-     */
-    protected void notifyStatusMessage(String message) {
-        Main.pleaseWaitDlg.currentAction.setText(message);
-    }
-
-    /**
-     * notifies any listeners about the current about a relative progress. Currently just
-     * increments the progress monitor in the in the global progress dialog, see {@see Main#pleaseWaitDlg}
-     *
-     * @param int the delta
-     */
-    protected void notifyRelativeProgress(int delta) {
-        int current= Main.pleaseWaitDlg.progress.getValue();
-        Main.pleaseWaitDlg.progress.setValue(current + delta);
-    }
-
-
-    protected void setAutoProgressIndication(final boolean enabled) {
-        EventQueue.invokeLater(
-                new Runnable() {
-                    public void run() {
-                        Main.pleaseWaitDlg.setIndeterminate(enabled);
-                    }
-                }
-        );
-    }
-
-    /**
      * returns the API capabilities; null, if the API is not initialized yet
-     * 
+     *
      * @return the API capabilities
      */
     public Capabilities getCapabilities() {
Index: src/org/openstreetmap/josm/io/OsmServerReader.java
===================================================================
--- src/org/openstreetmap/josm/io/OsmServerReader.java  (revision 1809)
+++ src/org/openstreetmap/josm/io/OsmServerReader.java  (working copy)
@@ -13,11 +13,9 @@
 import java.util.zip.Inflater;
 import java.util.zip.InflaterInputStream;
 
-import javax.swing.JOptionPane;
-
 import org.openstreetmap.josm.Main;
 import org.openstreetmap.josm.data.osm.DataSet;
-import org.openstreetmap.josm.gui.PleaseWaitDialog;
+import org.openstreetmap.josm.gui.progress.ProgressMonitor;
 
 /**
  * This DataReader reads directly from the REST API of the osm server.
@@ -39,13 +37,13 @@
      * @param pleaseWaitDlg
      * @return An reader reading the input stream (servers answer) or <code>null</code>.
      */
-    protected InputStream getInputStream(String urlStr, PleaseWaitDialog pleaseWaitDlg) throws OsmTransferException  {
+    protected InputStream getInputStream(String urlStr, ProgressMonitor progressMonitor) throws OsmTransferException  {
         api.initialize();
         urlStr = api.getBaseUrl() + urlStr;
-        return getInputStreamRaw(urlStr, pleaseWaitDlg);
+        return getInputStreamRaw(urlStr, progressMonitor);
     }
 
-    protected InputStream getInputStreamRaw(String urlStr, PleaseWaitDialog pleaseWaitDlg) throws OsmTransferException {
+    protected InputStream getInputStreamRaw(String urlStr, ProgressMonitor progressMonitor) throws OsmTransferException {
         URL url = null;
         try {
             url = new URL(urlStr);
@@ -96,7 +94,7 @@
             }
 
             String encoding = activeConnection.getContentEncoding();
-            InputStream inputStream = new ProgressInputStream(activeConnection, pleaseWaitDlg);
+            InputStream inputStream = new ProgressInputStream(activeConnection, progressMonitor);
             if (encoding != null && encoding.equalsIgnoreCase("gzip")) {
                 inputStream = new GZIPInputStream(inputStream);
             }
@@ -113,6 +111,6 @@
         }
     }
 
-    public abstract DataSet parseOsm() throws OsmTransferException;
+    public abstract DataSet parseOsm(ProgressMonitor progressMonitor) throws OsmTransferException;
 
 }
Index: src/org/openstreetmap/josm/io/OsmServerBackreferenceReader.java
===================================================================
--- src/org/openstreetmap/josm/io/OsmServerBackreferenceReader.java (revision 1809)
+++ src/org/openstreetmap/josm/io/OsmServerBackreferenceReader.java (working copy)
@@ -7,27 +7,27 @@
 import java.util.ArrayList;
 import java.util.Collection;
 
-import org.openstreetmap.josm.Main;
 import org.openstreetmap.josm.data.osm.DataSet;
 import org.openstreetmap.josm.data.osm.OsmPrimitive;
 import org.openstreetmap.josm.data.osm.OsmPrimitiveType;
 import org.openstreetmap.josm.data.osm.Relation;
 import org.openstreetmap.josm.data.osm.Way;
 import org.openstreetmap.josm.data.osm.visitor.MergeVisitor;
+import org.openstreetmap.josm.gui.progress.ProgressMonitor;
 
 /**
  * OsmServerBackreferenceReader fetches the primitives from the OSM server which
  * refer to a specific primitive. For a {@see Node}, ways and relations are retrieved
  * which refer to the node. For a {@see Way} or a {@see Relation}, only relations are
  * read.
- * 
+ *
  * OsmServerBackreferenceReader uses the API calls <code>[node|way|relation]/#id/relations</code>
  * and  <code>node/#id/ways</code> to retrieve the referring primitives. The default behaviour
  * of these calls is to reply incomplete primitives only.
- * 
+ *
  * If you set {@see #setReadFull(boolean)} to true this reader uses a {@see MultiFetchServerObjectReader}
  * to complete incomplete primitives.
- * 
+ *
  *
  */
 public class OsmServerBackreferenceReader extends OsmServerReader {
@@ -41,9 +41,9 @@
 
     /**
      * constructor
-     * 
+     *
      * @param primitive  the primitive to be read. Must not be null. primitive.id > 0 expected
-     * 
+     *
      * @exception IllegalArgumentException thrown if primitive is null
      * @exception IllegalArgumentException thrown if primitive.id <= 0
      */
@@ -59,13 +59,13 @@
 
     /**
      * constructor
-     * 
+     *
      * @param id  the id of the primitive. > 0 expected
      * @param type the type of the primitive. Must not be null.
-     * 
+     *
      * @exception IllegalArgumentException thrown if id <= 0
      * @exception IllegalArgumentException thrown if type is null
-     * 
+     *
      */
     public OsmServerBackreferenceReader(long id, OsmPrimitiveType type) throws IllegalArgumentException   {
         if (id <= 0)
@@ -79,11 +79,11 @@
 
     /**
      * constructor
-     * 
+     *
      * @param id  the id of the primitive. > 0 expected
      * @param type the type of the primitive. Must not be null.
      * @param readFull true, if referers should be read fully (i.e. including their immediate children)
-     * 
+     *
      */
     public OsmServerBackreferenceReader(OsmPrimitive primitive, boolean readFull) {
         this(primitive);
@@ -92,13 +92,13 @@
 
     /**
      * constructor
-     * 
+     *
      * @param primitive the primitive whose referers are to be read
      * @param readFull true, if referers should be read fully (i.e. including their immediate children)
-     * 
+     *
      * @exception IllegalArgumentException thrown if id <= 0
      * @exception IllegalArgumentException thrown if type is null
-     * 
+     *
      */
     public OsmServerBackreferenceReader(long id, OsmPrimitiveType type, boolean readFull) throws IllegalArgumentException  {
         this(id, type);
@@ -107,7 +107,7 @@
 
     /**
      * Replies true if this reader also reads immediate children of referring primitives
-     * 
+     *
      * @return true if this reader also reads immediate children of referring primitives
      */
     public boolean isReadFull() {
@@ -116,7 +116,7 @@
 
     /**
      * Set true if this reader should reads immediate children of referring primitives too. False, otherweise.
-     * 
+     *
      * @param readFull true if this reader should reads immediate children of referring primitives too. False, otherweise.
      */
     public void setReadFull(boolean readFull) {
@@ -125,24 +125,24 @@
 
     /**
      * Reads referring ways from the API server and replies them in a {@see DataSet}
-     * 
+     *
      * @return the data set
      * @throws OsmTransferException
      */
-    protected DataSet getReferringWays() throws OsmTransferException {
+    protected DataSet getReferringWays(ProgressMonitor progressMonitor) throws OsmTransferException {
         InputStream in = null;
+        progressMonitor.beginTask(null, 2);
         try {
-            Main.pleaseWaitDlg.progress.setValue(0);
-            Main.pleaseWaitDlg.currentAction.setText(tr("Contacting OSM Server..."));
+            progressMonitor.indeterminateSubTask(tr("Contacting OSM Server..."));
             StringBuffer sb = new StringBuffer();
             sb.append(primitiveType.getAPIName())
             .append("/").append(id).append("/ways");
 
-            in = getInputStream(sb.toString(), Main.pleaseWaitDlg);
+            in = getInputStream(sb.toString(), progressMonitor.createSubTaskMonitor(1, true));
             if (in == null)
                 return null;
-            Main.pleaseWaitDlg.currentAction.setText(tr("Downloading referring ways ..."));
-            return OsmReader.parseDataSet(in,Main.pleaseWaitDlg);
+            progressMonitor.subTask(tr("Downloading referring ways ..."));
+            return OsmReader.parseDataSet(in, progressMonitor.createSubTaskMonitor(1, true));
         } catch(OsmTransferException e) {
             throw e;
         } catch (Exception e) {
@@ -150,6 +150,7 @@
                 return null;
             throw new OsmTransferException(e);
         } finally {
+            progressMonitor.finishTask();
             if (in != null) {
                 try {
                     in.close();
@@ -161,24 +162,24 @@
     /**
 
      * Reads referring relations from the API server and replies them in a {@see DataSet}
-     * 
+     *
      * @return the data set
      * @throws OsmTransferException
      */
-    protected DataSet getReferringRelations() throws OsmTransferException {
+    protected DataSet getReferringRelations(ProgressMonitor progressMonitor) throws OsmTransferException {
         InputStream in = null;
+        progressMonitor.beginTask(null, 2);
         try {
-            Main.pleaseWaitDlg.progress.setValue(0);
-            Main.pleaseWaitDlg.currentAction.setText(tr("Contacting OSM Server..."));
+            progressMonitor.subTask(tr("Contacting OSM Server..."));
             StringBuffer sb = new StringBuffer();
             sb.append(primitiveType.getAPIName())
             .append("/").append(id).append("/relations");
 
-            in = getInputStream(sb.toString(), Main.pleaseWaitDlg);
+            in = getInputStream(sb.toString(), progressMonitor.createSubTaskMonitor(1, true));
             if (in == null)
                 return null;
-            Main.pleaseWaitDlg.currentAction.setText(tr("Downloading referring relations ..."));
-            return OsmReader.parseDataSet(in,Main.pleaseWaitDlg);
+            progressMonitor.subTask(tr("Downloading referring relations ..."));
+            return OsmReader.parseDataSet(in, progressMonitor.createSubTaskMonitor(1, true));
         } catch(OsmTransferException e) {
             throw e;
         } catch (Exception e) {
@@ -186,6 +187,7 @@
                 return null;
             throw new OsmTransferException(e);
         } finally {
+            progressMonitor.finishTask();
             if (in != null) {
                 try {
                     in.close();
@@ -199,67 +201,77 @@
      * Scans a dataset for incomplete primitives. Depending on the configuration of this reader
      * incomplete primitives are read from the server with an individual <tt>/api/0.6/[way,relation]/#id/full</tt>
      * request.
-     * 
+     *
      * <ul>
      *   <li>if this reader reads referers for an {@see Node}, referring ways are always
      *     read individually from the server</li>
      *   <li>if this reader reads referers for an {@see Way} or a {@see Relation}, referring relations
      *    are only read fully if {@see #setReadFull(boolean)} is set to true.</li>
      * </ul>
-     * 
+     *
      * The method replies the modified dataset.
-     * 
+     *
      * @param ds the original dataset
      * @return the modified dataset
      * @throws OsmTransferException thrown if an exception occurs.
      */
-    protected DataSet readIncompletePrimitives(DataSet ds) throws OsmTransferException {
-        Collection<Way> waysToCheck = new ArrayList<Way>(ds.ways);
-        if (isReadFull() ||primitiveType.equals(OsmPrimitiveType.NODE)) {
-            for (Way way: waysToCheck) {
-                if (way.id > 0 && way.incomplete) {
-                    OsmServerObjectReader reader = new OsmServerObjectReader(way.id, OsmPrimitiveType.from(way), true /* read full */);
-                    DataSet wayDs = reader.parseOsm();
-                    MergeVisitor visitor = new MergeVisitor(ds, wayDs);
-                    visitor.merge();
+    protected DataSet readIncompletePrimitives(DataSet ds, ProgressMonitor progressMonitor) throws OsmTransferException {
+        progressMonitor.beginTask(null, 2);
+        try {
+            Collection<Way> waysToCheck = new ArrayList<Way>(ds.ways);
+            if (isReadFull() ||primitiveType.equals(OsmPrimitiveType.NODE)) {
+                for (Way way: waysToCheck) {
+                    if (way.id > 0 && way.incomplete) {
+                        OsmServerObjectReader reader = new OsmServerObjectReader(way.id, OsmPrimitiveType.from(way), true /* read full */);
+                        DataSet wayDs = reader.parseOsm(progressMonitor.createSubTaskMonitor(1, false));
+                        MergeVisitor visitor = new MergeVisitor(ds, wayDs);
+                        visitor.merge();
+                    }
                 }
             }
-        }
-        if (isReadFull()) {
-            Collection<Relation> relationsToCheck  = new ArrayList<Relation>(ds.relations);
-            for (Relation relation: relationsToCheck) {
-                if (relation.id > 0 && relation.incomplete) {
-                    OsmServerObjectReader reader = new OsmServerObjectReader(relation.id, OsmPrimitiveType.from(relation), true /* read full */);
-                    DataSet wayDs = reader.parseOsm();
-                    MergeVisitor visitor = new MergeVisitor(ds, wayDs);
-                    visitor.merge();
+            if (isReadFull()) {
+                Collection<Relation> relationsToCheck  = new ArrayList<Relation>(ds.relations);
+                for (Relation relation: relationsToCheck) {
+                    if (relation.id > 0 && relation.incomplete) {
+                        OsmServerObjectReader reader = new OsmServerObjectReader(relation.id, OsmPrimitiveType.from(relation), true /* read full */);
+                        DataSet wayDs = reader.parseOsm(progressMonitor.createSubTaskMonitor(1, false));
+                        MergeVisitor visitor = new MergeVisitor(ds, wayDs);
+                        visitor.merge();
+                    }
                 }
             }
+            return ds;
+        } finally {
+            progressMonitor.finishTask();
         }
-        return ds;
     }
 
     /**
      * Reads the referring primitives from the OSM server, parses them and
      * replies them as {@see DataSet}
-     * 
+     *
      * @return the dataset with the referring primitives
      * @exception OsmTransferException thrown if an error occurs while communicating with the server
      */
     @Override
-    public DataSet parseOsm() throws OsmTransferException {
-        DataSet ret = new DataSet();
-        if (primitiveType.equals(OsmPrimitiveType.NODE)) {
-            DataSet ds = getReferringWays();
+    public DataSet parseOsm(ProgressMonitor progressMonitor) throws OsmTransferException {
+        progressMonitor.beginTask(null, 3);
+        try {
+            DataSet ret = new DataSet();
+            if (primitiveType.equals(OsmPrimitiveType.NODE)) {
+                DataSet ds = getReferringWays(progressMonitor.createSubTaskMonitor(1, false));
+                MergeVisitor visitor = new MergeVisitor(ret,ds);
+                visitor.merge();
+                ret = visitor.getMyDataSet();
+            }
+            DataSet ds = getReferringRelations(progressMonitor.createSubTaskMonitor(1, false));
             MergeVisitor visitor = new MergeVisitor(ret,ds);
             visitor.merge();
             ret = visitor.getMyDataSet();
+            readIncompletePrimitives(ret, progressMonitor.createSubTaskMonitor(1, false));
+            return ret;
+        } finally {
+            progressMonitor.finishTask();
         }
-        DataSet ds = getReferringRelations();
-        MergeVisitor visitor = new MergeVisitor(ret,ds);
-        visitor.merge();
-        ret = visitor.getMyDataSet();
-        readIncompletePrimitives(ret);
-        return ret;
     }
 }
Index: src/org/openstreetmap/josm/io/OsmImporter.java
===================================================================
--- src/org/openstreetmap/josm/io/OsmImporter.java  (revision 1809)
+++ src/org/openstreetmap/josm/io/OsmImporter.java  (working copy)
@@ -10,12 +10,11 @@
 import java.io.IOException;
 import java.io.InputStream;
 
-import javax.swing.JOptionPane;
-
 import org.openstreetmap.josm.Main;
 import org.openstreetmap.josm.actions.ExtensionFileFilter;
 import org.openstreetmap.josm.data.osm.DataSet;
 import org.openstreetmap.josm.gui.layer.OsmDataLayer;
+import org.openstreetmap.josm.gui.progress.NullProgressMonitor;
 import org.xml.sax.SAXException;
 
 public class OsmImporter extends FileImporter {
@@ -45,7 +44,7 @@
     }
 
     protected void importData(InputStream in, File associatedFile) throws SAXException, IOException {
-        OsmReader osm = OsmReader.parseDataSetOsm(in,Main.pleaseWaitDlg);
+        OsmReader osm = OsmReader.parseDataSetOsm(in, NullProgressMonitor.INSTANCE);
         DataSet dataSet = osm.getDs();
         OsmDataLayer layer = new OsmDataLayer(dataSet, associatedFile.getName(), associatedFile);
         Main.main.addLayer(layer);
Index: src/org/openstreetmap/josm/io/OsmServerWriter.java
===================================================================
--- src/org/openstreetmap/josm/io/OsmServerWriter.java  (revision 1809)
+++ src/org/openstreetmap/josm/io/OsmServerWriter.java  (working copy)
@@ -12,6 +12,7 @@
 import org.openstreetmap.josm.actions.UploadAction;
 import org.openstreetmap.josm.data.osm.OsmPrimitive;
 import org.openstreetmap.josm.data.osm.visitor.NameVisitor;
+import org.openstreetmap.josm.gui.progress.ProgressMonitor;
 
 /**
  * Class that uploads all changes to the osm server.
@@ -80,60 +81,65 @@
      * @param apiVersion version of the data set
      * @param primitives list of objects to send
      */
-    public void uploadOsm(String apiVersion, Collection<OsmPrimitive> primitives) throws OsmTransferException {
+    public void uploadOsm(String apiVersion, Collection<OsmPrimitive> primitives, ProgressMonitor progressMonitor) throws OsmTransferException {
         processed = new LinkedList<OsmPrimitive>();
 
         api.initialize();
 
-        Main.pleaseWaitDlg.progress.setMaximum(primitives.size());
-        Main.pleaseWaitDlg.progress.setValue(0);
+        progressMonitor.beginTask("");
 
-        // check whether we can use changeset
-        //
-        boolean canUseChangeset = api.hasChangesetSupport();
-        boolean useChangeset = Main.pref.getBoolean("osm-server.atomic-upload", apiVersion.compareTo("0.6")>=0);
-        if (useChangeset && ! canUseChangeset) {
-            System.out.println(tr("WARNING: preference ''{0}'' or api version ''{1}'' of dataset requires to use changesets, but API is not able to handle them. Ignoring changesets.", "osm-server.atomic-upload", apiVersion));
-            useChangeset = false;
-        }
+        try {
 
-        if (useChangeset) {
-            // upload everything in one changeset
+            // check whether we can use changeset
             //
-            try {
-                api.createChangeset(getChangesetComment());
-                processed.addAll(api.uploadDiff(primitives));
-            } catch(OsmTransferException e) {
-                throw e;
-            } finally {
+            boolean canUseChangeset = api.hasChangesetSupport();
+            boolean useChangeset = Main.pref.getBoolean("osm-server.atomic-upload", apiVersion.compareTo("0.6")>=0);
+            if (useChangeset && ! canUseChangeset) {
+                System.out.println(tr("WARNING: preference ''{0}'' or api version ''{1}'' of dataset requires to use changesets, but API is not able to handle them. Ignoring changesets.", "osm-server.atomic-upload", apiVersion));
+                useChangeset = false;
+            }
+
+            if (useChangeset) {
+                // upload everything in one changeset
+                //
                 try {
-                    if (canUseChangeset) {
-                        api.stopChangeset();
+                    api.createChangeset(getChangesetComment(), progressMonitor.createSubTaskMonitor(0, false));
+                    processed.addAll(api.uploadDiff(primitives, progressMonitor.createSubTaskMonitor(ProgressMonitor.ALL_TICKS, false)));
+                } catch(OsmTransferException e) {
+                    throw e;
+                } finally {
+                    try {
+                        if (canUseChangeset) {
+                            api.stopChangeset(progressMonitor.createSubTaskMonitor(0, false));
+                        }
+                    } catch (Exception ee) {
+                        ee.printStackTrace();
+                        // ignore nested exception
                     }
-                } catch (Exception ee) {
-                    ee.printStackTrace();
-                    // ignore nested exception
                 }
-            }
-        } else {
-            // upload changes individually (90% of code is for the status display...)
-            //
-            api.createChangeset(getChangesetComment());
-            NameVisitor v = new NameVisitor();
-            uploadStartTime = System.currentTimeMillis();
-            for (OsmPrimitive osm : primitives) {
-                osm.visit(v);
-                int progress = Main.pleaseWaitDlg.progress.getValue();
-                String time_left_str = timeLeft(progress, primitives.size());
-                Main.pleaseWaitDlg.currentAction.setText(
-                        tr("{0}% ({1}/{2}), {3} left. Uploading {4}: {5} (id: {6})",
-                                Math.round(100.0*progress/primitives.size()), progress,
-                                primitives.size(), time_left_str, tr(v.className), v.name, osm.id));
-                makeApiRequest(osm);
-                processed.add(osm);
-                Main.pleaseWaitDlg.progress.setValue(progress+1);
+            } else {
+                // upload changes individually (90% of code is for the status display...)
+                //
+                progressMonitor.setTicksCount(primitives.size());
+                api.createChangeset(getChangesetComment(), progressMonitor.createSubTaskMonitor(0, false));
+                NameVisitor v = new NameVisitor();
+                uploadStartTime = System.currentTimeMillis();
+                for (OsmPrimitive osm : primitives) {
+                    osm.visit(v);
+                    int progress = progressMonitor.getTicks();
+                    String time_left_str = timeLeft(progress, primitives.size());
+                    progressMonitor.subTask(
+                            tr("{0}% ({1}/{2}), {3} left. Uploading {4}: {5} (id: {6})",
+                                    Math.round(100.0*progress/primitives.size()), progress,
+                                    primitives.size(), time_left_str, tr(v.className), v.name, osm.id));
+                    makeApiRequest(osm);
+                    processed.add(osm);
+                    progressMonitor.worked(1);
+                }
+                api.stopChangeset(progressMonitor.createSubTaskMonitor(0, false));
             }
-            api.stopChangeset();
+        } finally {
+            progressMonitor.finishTask();
         }
     }
 
Index: src/org/openstreetmap/josm/io/DiffResultReader.java
===================================================================
--- src/org/openstreetmap/josm/io/DiffResultReader.java (revision 1809)
+++ src/org/openstreetmap/josm/io/DiffResultReader.java (working copy)
@@ -17,7 +17,7 @@
 import org.openstreetmap.josm.data.osm.Relation;
 import org.openstreetmap.josm.data.osm.Way;
 import org.openstreetmap.josm.data.osm.visitor.AbstractVisitor;
-import org.openstreetmap.josm.gui.PleaseWaitDialog;
+import org.openstreetmap.josm.gui.progress.ProgressMonitor;
 import org.xml.sax.Attributes;
 import org.xml.sax.InputSource;
 import org.xml.sax.SAXException;
@@ -63,31 +63,32 @@
     /**
      * Parse the given input source and return the dataset.
      */
-    public static void parseDiffResult(String source, Collection<OsmPrimitive> osm, Collection<OsmPrimitive> processed, Map<OsmPrimitive,Long> newIdMap, PleaseWaitDialog pleaseWaitDlg)
+    public static void parseDiffResult(String source, Collection<OsmPrimitive> osm, Collection<OsmPrimitive> processed, Map<OsmPrimitive,Long> newIdMap, ProgressMonitor progressMonitor)
     throws SAXException, IOException {
 
-       DiffResultReader drr = new DiffResultReader();
-       drr.processed = processed;
-       drr.newIdMap = newIdMap;
-       InputSource inputSource = new InputSource(new StringReader(source));
-       try {
-           SAXParserFactory.newInstance().newSAXParser().parse(inputSource, drr.new Parser());
-       } catch (ParserConfigurationException e1) {
-           e1.printStackTrace(); // broken SAXException chaining
-           throw new SAXException(e1);
-       }
+        progressMonitor.beginTask(tr("Preparing data..."));
+        try {
 
-       if (pleaseWaitDlg != null) {
-           pleaseWaitDlg.progress.setValue(0);
-           pleaseWaitDlg.currentAction.setText(tr("Preparing data..."));
-       }
+            DiffResultReader drr = new DiffResultReader();
+            drr.processed = processed;
+            drr.newIdMap = newIdMap;
+            InputSource inputSource = new InputSource(new StringReader(source));
+            try {
+                SAXParserFactory.newInstance().newSAXParser().parse(inputSource, drr.new Parser());
+            } catch (ParserConfigurationException e1) {
+                e1.printStackTrace(); // broken SAXException chaining
+                throw new SAXException(e1);
+            }
 
-       for (OsmPrimitive p : osm) {
-           //System.out.println("old: "+ p);
-           p.visit(drr);
-           //System.out.println("new: "+ p);
-           //System.out.println("");
-       }
+            for (OsmPrimitive p : osm) {
+                //System.out.println("old: "+ p);
+                p.visit(drr);
+                //System.out.println("new: "+ p);
+                //System.out.println("");
+            }
+        } finally {
+            progressMonitor.finishTask();
+        }
     }
 
     public void visit(Node n) {
Index: src/org/openstreetmap/josm/io/OsmServerHistoryReader.java
===================================================================
--- src/org/openstreetmap/josm/io/OsmServerHistoryReader.java   (revision 1809)
+++ src/org/openstreetmap/josm/io/OsmServerHistoryReader.java   (working copy)
@@ -6,17 +6,17 @@
 import java.io.IOException;
 import java.io.InputStream;
 
-import org.openstreetmap.josm.Main;
 import org.openstreetmap.josm.data.osm.DataSet;
 import org.openstreetmap.josm.data.osm.OsmPrimitiveType;
 import org.openstreetmap.josm.data.osm.history.HistoryDataSet;
+import org.openstreetmap.josm.gui.progress.ProgressMonitor;
 import org.xml.sax.SAXException;
 
 import sun.reflect.generics.reflectiveObjects.NotImplementedException;
 
 /**
  * Reads the history of an {@see OsmPrimitive} from the OSM API server.
- * 
+ *
  */
 public class OsmServerHistoryReader extends OsmServerReader {
 
@@ -25,11 +25,11 @@
 
     /**
      * constructor
-     * 
+     *
      * @param type the type of the primitive whose history is to be fetched from the server.
      *   Must not be null.
      * @param id the id of the primitive
-     * 
+     *
      *  @exception IllegalArgumentException thrown, if type is null
      */
     public OsmServerHistoryReader(OsmPrimitiveType type, long id) throws IllegalArgumentException {
@@ -43,35 +43,35 @@
 
     /**
      * don't use - not implemented!
-     * 
+     *
      * @exception NotImplementedException
      */
     @Override
-    public DataSet parseOsm() throws OsmTransferException {
+    public DataSet parseOsm(ProgressMonitor progressMonitor) throws OsmTransferException {
         throw new NotImplementedException();
     }
 
     /**
      * Fetches the history from the OSM API and parses it
-     * 
+     *
      * @return the data set with the parsed history data
      * @throws OsmTransferException thrown, if an exception occurs
      */
-    public HistoryDataSet parseHistory() throws OsmTransferException {
+    public HistoryDataSet parseHistory(ProgressMonitor progressMonitor) throws OsmTransferException {
         InputStream in = null;
+        progressMonitor.beginTask("");
         try {
-            Main.pleaseWaitDlg.progress.setValue(0);
-            Main.pleaseWaitDlg.currentAction.setText(tr("Contacting OSM Server..."));
+            progressMonitor.indeterminateSubTask(tr("Contacting OSM Server..."));
             StringBuffer sb = new StringBuffer();
             sb.append(primitiveType.getAPIName())
             .append("/").append(id).append("/history");
 
-            in = getInputStream(sb.toString(), Main.pleaseWaitDlg);
+            in = getInputStream(sb.toString(), progressMonitor.createSubTaskMonitor(1, true));
             if (in == null)
                 return null;
-            Main.pleaseWaitDlg.currentAction.setText(tr("Downloading history..."));
+            progressMonitor.indeterminateSubTask(tr("Downloading history..."));
             final OsmHistoryReader reader = new OsmHistoryReader(in);
-            HistoryDataSet data = reader.parse(Main.pleaseWaitDlg);
+            HistoryDataSet data = reader.parse(progressMonitor.createSubTaskMonitor(1, true));
             return data;
         } catch(OsmTransferException e) {
             throw e;
@@ -80,6 +80,7 @@
                 return null;
             throw new OsmTransferException(e);
         } finally {
+            progressMonitor.finishTask();
             if (in != null) {
                 try {
                     in.close();
Index: src/org/openstreetmap/josm/io/OsmHistoryReader.java
===================================================================
--- src/org/openstreetmap/josm/io/OsmHistoryReader.java (revision 1809)
+++ src/org/openstreetmap/josm/io/OsmHistoryReader.java (working copy)
@@ -17,7 +17,7 @@
 import org.openstreetmap.josm.data.osm.history.HistoryOsmPrimitive;
 import org.openstreetmap.josm.data.osm.history.HistoryRelation;
 import org.openstreetmap.josm.data.osm.history.HistoryWay;
-import org.openstreetmap.josm.gui.PleaseWaitDialog;
+import org.openstreetmap.josm.gui.progress.ProgressMonitor;
 import org.openstreetmap.josm.tools.DateUtils;
 import org.xml.sax.Attributes;
 import org.xml.sax.InputSource;
@@ -31,7 +31,7 @@
  * It is slightly different from {@see OsmReader} because we don't build an internal graph of
  * {@see OsmPrimitive}s. We use objects derived from {@see HistoryOsmPrimitive} instead and we
  * keep the data in a dedicated {@see HistoryDataSet}.
- * 
+ *
  */
 public class OsmHistoryReader {
 
@@ -209,14 +209,16 @@
         data = new HistoryDataSet();
     }
 
-    public HistoryDataSet parse(PleaseWaitDialog dialog) throws SAXException, IOException {
+    public HistoryDataSet parse(ProgressMonitor progressMonitor) throws SAXException, IOException {
         InputSource inputSource = new InputSource(new InputStreamReader(in, "UTF-8"));
-        dialog.currentAction.setText("Parsing OSM history data ...");
+        progressMonitor.beginTask(tr("Parsing OSM history data ..."));
         try {
             SAXParserFactory.newInstance().newSAXParser().parse(inputSource, new Parser());
         } catch (ParserConfigurationException e1) {
             e1.printStackTrace(); // broken SAXException chaining
             throw new SAXException(e1);
+        } finally {
+            progressMonitor.finishTask();
         }
         return data;
     }
Index: src/org/openstreetmap/josm/actions/UploadAction.java
===================================================================
--- src/org/openstreetmap/josm/actions/UploadAction.java    (revision 1809)
+++ src/org/openstreetmap/josm/actions/UploadAction.java    (working copy)
@@ -30,6 +30,7 @@
 import org.openstreetmap.josm.gui.historycombobox.SuggestingJHistoryComboBox;
 import org.openstreetmap.josm.gui.layer.Layer;
 import org.openstreetmap.josm.gui.layer.Layer.LayerChangeListener;
+import org.openstreetmap.josm.gui.progress.ProgressMonitor;
 import org.openstreetmap.josm.io.OsmApi;
 import org.openstreetmap.josm.io.OsmApiException;
 import org.openstreetmap.josm.io.OsmApiInitializationException;
@@ -160,7 +161,7 @@
 
     /**
      * Refreshes the enabled state
-     * 
+     *
      */
     protected void refreshEnabled() {
         setEnabled(Main.main != null
@@ -229,7 +230,7 @@
 
             @Override protected void realRun() throws SAXException, IOException {
                 try {
-                    server.uploadOsm(Main.ds.version, all);
+                    server.uploadOsm(Main.ds.version, all, progressMonitor.createSubTaskMonitor(ProgressMonitor.ALL_TICKS, false));
                     Main.main.createOrGetEditLayer().cleanData(server.processed, !add.isEmpty());
                 } catch (Exception sxe) {
                     if (uploadCancelled) {
Index: src/org/openstreetmap/josm/actions/DownloadAction.java
===================================================================
--- src/org/openstreetmap/josm/actions/DownloadAction.java  (revision 1809)
+++ src/org/openstreetmap/josm/actions/DownloadAction.java  (working copy)
@@ -59,7 +59,7 @@
                 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);
+                        task.download(this, dialog.minlat, dialog.minlon, dialog.maxlat, dialog.maxlon, null);
                         finish = true;
                     }
                 }
Index: src/org/openstreetmap/josm/actions/UpdateSelectionAction.java
===================================================================
--- src/org/openstreetmap/josm/actions/UpdateSelectionAction.java   (revision 1809)
+++ src/org/openstreetmap/josm/actions/UpdateSelectionAction.java   (working copy)
@@ -3,7 +3,6 @@
 
 import static org.openstreetmap.josm.tools.I18n.tr;
 
-import java.awt.EventQueue;
 import java.awt.event.ActionEvent;
 import java.awt.event.KeyEvent;
 import java.io.IOException;
@@ -20,6 +19,8 @@
 import org.openstreetmap.josm.gui.PleaseWaitRunnable;
 import org.openstreetmap.josm.gui.layer.Layer;
 import org.openstreetmap.josm.gui.layer.Layer.LayerChangeListener;
+import org.openstreetmap.josm.gui.progress.NullProgressMonitor;
+import org.openstreetmap.josm.gui.progress.ProgressMonitor;
 import org.openstreetmap.josm.io.MultiFetchServerObjectReader;
 import org.openstreetmap.josm.io.OsmApi;
 import org.openstreetmap.josm.io.OsmTransferException;
@@ -28,14 +29,14 @@
 
 /**
  * This action synchronizes a set of primitives with their state on the server.
- * 
+ *
  *
  */
 public class UpdateSelectionAction extends JosmAction implements SelectionChangedListener, LayerChangeListener {
 
     /**
      * handle an exception thrown because a primitive was deleted on the server
-     * 
+     *
      * @param id the primitive id
      */
     protected void handlePrimitiveGoneException(long id) {
@@ -43,7 +44,7 @@
         reader.append(Main.main.createOrGetEditLayer().data,id);
         DataSet ds = null;
         try {
-            ds = reader.parseOsm();
+            ds = reader.parseOsm(NullProgressMonitor.INSTANCE);
         } catch(Exception e) {
             handleUpdateException(e);
             return;
@@ -54,7 +55,7 @@
 
     /**
      * handle an exception thrown during updating a primitive
-     * 
+     *
      * @param id the id of the primitive
      * @param e the exception
      */
@@ -71,7 +72,7 @@
     /**
      * handles an exception case: primitive with id <code>id</code> is not in the current
      * data set
-     * 
+     *
      * @param id the primitive id
      */
     protected void handleMissingPrimitive(long id) {
@@ -86,9 +87,9 @@
     /**
      * Updates the data for for the {@see OsmPrimitive}s in <code>selection</code>
      * with the data currently kept on the server.
-     * 
+     *
      * @param selection a collection of {@see OsmPrimitive}s to update
-     * 
+     *
      */
     public void updatePrimitives(final Collection<OsmPrimitive> selection) {
 
@@ -101,16 +102,6 @@
             private boolean cancelled;
             Exception lastException;
 
-            protected void setIndeterminateEnabled(final boolean enabled) {
-                EventQueue.invokeLater(
-                        new Runnable() {
-                            public void run() {
-                                Main.pleaseWaitDlg.setIndeterminate(enabled);
-                            }
-                        }
-                );
-            }
-
             public UpdatePrimitiveTask() {
                 super("Update primitives", false /* don't ignore exception*/);
                 cancelled = false;
@@ -150,17 +141,15 @@
 
             @Override
             protected void realRun() throws SAXException, IOException, OsmTransferException {
-                setIndeterminateEnabled(true);
+                progressMonitor.indeterminateSubTask("");
                 try {
                     MultiFetchServerObjectReader reader = new MultiFetchServerObjectReader();
                     reader.append(selection);
-                    ds = reader.parseOsm();
+                    ds = reader.parseOsm(progressMonitor.createSubTaskMonitor(ProgressMonitor.ALL_TICKS, false));
                 } catch(Exception e) {
                     if (cancelled)
                         return;
                     lastException = e;
-                } finally {
-                    setIndeterminateEnabled(false);
                 }
             }
         }
@@ -171,9 +160,9 @@
     /**
      * Updates the data for for the {@see OsmPrimitive}s with id <code>id</code>
      * with the data currently kept on the server.
-     * 
+     *
      * @param id  the id of a primitive in the {@see DataSet} of the current edit layser
-     * 
+     *
      */
     public void updatePrimitive(long id) {
         OsmPrimitive primitive = Main.map.mapView.getEditLayer().data.getPrimitiveById(id);
@@ -201,7 +190,7 @@
 
     /**
      * Refreshes the enabled state
-     * 
+     *
      */
     protected void refreshEnabled() {
         setEnabled(Main.main != null
Index: src/org/openstreetmap/josm/actions/downloadtasks/DownloadGpsTask.java
===================================================================
--- src/org/openstreetmap/josm/actions/downloadtasks/DownloadGpsTask.java   (revision 1809)
+++ src/org/openstreetmap/josm/actions/downloadtasks/DownloadGpsTask.java   (working copy)
@@ -15,6 +15,7 @@
 import org.openstreetmap.josm.gui.download.DownloadDialog.DownloadTask;
 import org.openstreetmap.josm.gui.layer.GpxLayer;
 import org.openstreetmap.josm.gui.layer.Layer;
+import org.openstreetmap.josm.gui.progress.ProgressMonitor;
 import org.openstreetmap.josm.io.BoundingBoxDownloader;
 import org.xml.sax.SAXException;
 
@@ -25,19 +26,15 @@
         private BoundingBoxDownloader reader;
         private GpxData rawData;
         private final boolean newLayer;
-        private String msg = "";
 
-        public Task(boolean newLayer, BoundingBoxDownloader reader, boolean silent, String msg) {
+        public Task(boolean newLayer, BoundingBoxDownloader reader, ProgressMonitor progressMonitor) {
             super(tr("Downloading GPS data"));
-            this.msg = msg;
             this.reader = reader;
             this.newLayer = newLayer;
-            this.silent = silent;
         }
 
         @Override public void realRun() throws IOException, SAXException {
-            Main.pleaseWaitDlg.setCustomText(msg);
-            rawData = reader.parseRawGps();
+            rawData = reader.parseRawGps(progressMonitor.createSubTaskMonitor(ProgressMonitor.ALL_TICKS, false));
         }
 
         @Override protected void finish() {
@@ -51,8 +48,6 @@
                 Main.main.addLayer(layer);
             else
                 x.mergeFrom(layer);
-
-            Main.pleaseWaitDlg.setCustomText("");
         }
 
         private Layer findMergeLayer() {
@@ -71,23 +66,15 @@
         @Override protected void cancel() {
             if (reader != null)
                 reader.cancel();
-            Main.pleaseWaitDlg.cancel.setEnabled(false);
         }
     }
 
     private JCheckBox checkBox = new JCheckBox(tr("Raw GPS data"));
 
     public void download(DownloadAction action, double minlat, double minlon,
-            double maxlat, double maxlon) {
-        download(action, minlat, minlon, maxlat, maxlon, false, "");
-    }
-
-    public void download(DownloadAction action, double minlat, double minlon,
-            double maxlat, double maxlon, boolean silent, String message) {
+            double maxlat, double maxlon, ProgressMonitor progressMonitor) {
         Task t = new Task(action.dialog.newLayer.isSelected(),
-                new BoundingBoxDownloader(minlat, minlon, maxlat, maxlon),
-                silent,
-                message);
+                new BoundingBoxDownloader(minlat, minlon, maxlat, maxlon), progressMonitor);
         // We need submit instead of execute so we can wait for it to finish and get the error
         // message if necessary. If no one calls getErrorMessage() it just behaves like execute.
         task = Main.worker.submit(t, t);
@@ -115,9 +102,9 @@
 
         try {
             Task t = task.get();
-            return t.errorMessage == null
+            return t.getProgressMonitor().getErrorMessage() == null
                 ? ""
-                : t.errorMessage;
+                : t.getProgressMonitor().getErrorMessage();
         } catch (Exception e) {
             return "";
         }
Index: src/org/openstreetmap/josm/actions/downloadtasks/DownloadOsmTask.java
===================================================================
--- src/org/openstreetmap/josm/actions/downloadtasks/DownloadOsmTask.java   (revision 1809)
+++ src/org/openstreetmap/josm/actions/downloadtasks/DownloadOsmTask.java   (working copy)
@@ -17,6 +17,8 @@
 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.gui.progress.NullProgressMonitor;
+import org.openstreetmap.josm.gui.progress.ProgressMonitor;
 import org.openstreetmap.josm.io.BoundingBoxDownloader;
 import org.openstreetmap.josm.io.OsmServerLocationReader;
 import org.openstreetmap.josm.io.OsmServerReader;
@@ -37,29 +39,22 @@
         private OsmServerReader reader;
         private DataSet dataSet;
         private boolean newLayer;
-        private String msg = "";
 
-        public Task(boolean newLayer, OsmServerReader reader, boolean silent, String msg) {
-            super(tr("Downloading data"));
-            this.msg = msg;
+        public Task(boolean newLayer, OsmServerReader reader, ProgressMonitor progressMonitor) {
+            super(tr("Downloading data"), progressMonitor, false);
             this.reader = reader;
             this.newLayer = newLayer;
-            this.silent = silent;
         }
 
         @Override public void realRun() throws IOException, SAXException, OsmTransferException {
-            Main.pleaseWaitDlg.setCustomText(msg);
-            dataSet = reader.parseOsm();
+            dataSet = reader.parseOsm(progressMonitor.createSubTaskMonitor(ProgressMonitor.ALL_TICKS, false));
         }
 
         @Override protected void finish() {
             if (dataSet == null)
                 return; // user canceled download or error occurred
             if (dataSet.allPrimitives().isEmpty()) {
-                // If silent is set to true, we don't want to see information messages
-                if(!silent) {
-                    errorMessage = tr("No data imported.");
-                }
+                progressMonitor.setErrorMessage(tr("No data imported."));
                 // need to synthesize a download bounds lest the visual indication of downloaded
                 // area doesn't work
                 dataSet.dataSources.add(new DataSource(currentBounds, "OpenStreetMap server"));
@@ -71,15 +66,12 @@
             } else {
                 Main.main.createOrGetEditLayer().mergeFrom(dataSet);
             }
-
-            Main.pleaseWaitDlg.setCustomText("");
         }
 
         @Override protected void cancel() {
             if (reader != null) {
                 reader.cancel();
             }
-            Main.pleaseWaitDlg.cancel.setEnabled(false);
         }
     }
     private JCheckBox checkBox = new JCheckBox(tr("OpenStreetMap data"), true);
@@ -93,7 +85,7 @@
     }
 
     public void download(DownloadAction action, double minlat, double minlon,
-            double maxlat, double maxlon, boolean silent, String message) {
+            double maxlat, double maxlon, ProgressMonitor progressMonitor) {
         // Swap min and max if user has specified them the wrong way round
         // (easy to do if you are crossing 0, for example)
         // FIXME should perhaps be done in download dialog?
@@ -108,20 +100,13 @@
         && (action.dialog == null || action.dialog.newLayer.isSelected());
 
         Task t = new Task(newLayer,
-                new BoundingBoxDownloader(minlat, minlon, maxlat, maxlon),
-                silent,
-                message);
+                new BoundingBoxDownloader(minlat, minlon, maxlat, maxlon), progressMonitor);
         currentBounds = new Bounds(new LatLon(minlat, minlon), new LatLon(maxlat, maxlon));
         // We need submit instead of execute so we can wait for it to finish and get the error
         // message if necessary. If no one calls getErrorMessage() it just behaves like execute.
         task = Main.worker.submit(t, t);
     }
 
-    public void download(DownloadAction action, double minlat, double minlon,
-            double maxlat, double maxlon) {
-        download(action, minlat, minlon, maxlat, maxlon, false, "");
-    }
-
     /**
      * Loads a given URL from the OSM Server
      * @param True if the data should be saved to a new layer
@@ -130,8 +115,7 @@
     public void loadUrl(boolean new_layer, String url) {
         Task t = new Task(new_layer,
                 new OsmServerLocationReader(url),
-                false,
-        "");
+                NullProgressMonitor.INSTANCE);
         task = Main.worker.submit(t, t);
     }
 
@@ -153,9 +137,9 @@
 
         try {
             Task t = task.get();
-            return t.errorMessage == null
+            return t.getProgressMonitor().getErrorMessage() == null
             ? ""
-                    : t.errorMessage;
+                    : t.getProgressMonitor().getErrorMessage();
         } catch (Exception e) {
             return "";
         }
Index: src/org/openstreetmap/josm/actions/downloadtasks/DownloadOsmTaskList.java
===================================================================
--- src/org/openstreetmap/josm/actions/downloadtasks/DownloadOsmTaskList.java   (revision 1809)
+++ src/org/openstreetmap/josm/actions/downloadtasks/DownloadOsmTaskList.java   (working copy)
@@ -22,6 +22,8 @@
 import org.openstreetmap.josm.gui.download.DownloadDialog.DownloadTask;
 import org.openstreetmap.josm.gui.layer.Layer;
 import org.openstreetmap.josm.gui.layer.OsmDataLayer;
+import org.openstreetmap.josm.gui.progress.NullProgressMonitor;
+import org.openstreetmap.josm.gui.progress.ProgressMonitor;
 
 /**
  * This class encapsulates the downloading of several bounding boxes that would otherwise be too
@@ -32,32 +34,39 @@
  */
 public class DownloadOsmTaskList implements Runnable {
     private List<DownloadTask> osmTasks = new LinkedList<DownloadTask>();
+    private ProgressMonitor progressMonitor;
 
     /**
      * Downloads a list of areas from the OSM Server
      * @param newLayer Set to true if all areas should be put into a single new layer
      * @param The List of Rectangle2D to download
      */
-    public void download(boolean newLayer, List<Rectangle2D> rects) {
+    public void download(boolean newLayer, List<Rectangle2D> rects, ProgressMonitor progressMonitor) {
+        this.progressMonitor = progressMonitor;
         if(newLayer) {
             Layer l = new OsmDataLayer(new DataSet(), OsmDataLayer.createNewName(), null);
             Main.main.addLayer(l);
             Main.map.mapView.setActiveLayer(l);
         }
 
-        int i = 0;
-        for(Rectangle2D td : rects) {
-            i++;
-            DownloadTask dt = new DownloadOsmTask();
-            dt.download(null, td.getMinY(), td.getMinX(), td.getMaxY(), td.getMaxX(), true,
-                    tr("Download {0} of {1} ({2} left)", i, rects.size(), rects.size()-i));
-            osmTasks.add(dt);
+        progressMonitor.beginTask(null, rects.size());
+        try {
+            int i = 0;
+            for(Rectangle2D td : rects) {
+                i++;
+                DownloadTask dt = new DownloadOsmTask();
+                ProgressMonitor childProgress = progressMonitor.createSubTaskMonitor(1, false);
+                childProgress.setSilent(true);
+                childProgress.setCustomText(tr("Download {0} of {1} ({2} left)", i, rects.size(), rects.size()-i));
+                dt.download(null, td.getMinY(), td.getMinX(), td.getMaxY(), td.getMaxX(), childProgress);
+                osmTasks.add(dt);
+            }
+        } finally {
+            // If we try to get the error message now the download task will never have been started
+            // and we'd be stuck in a classical dead lock. Instead attach this to the worker and once
+            // run() gets called all downloadTasks have finished and we can grab the error messages.
+            Main.worker.execute(this);
         }
-
-        // If we try to get the error message now the download task will never have been started
-        // and we'd be stuck in a classical dead lock. Instead attach this to the worker and once
-        // run() gets called all downloadTasks have finished and we can grab the error messages.
-        Main.worker.execute(this);
     }
 
     /**
@@ -71,13 +80,14 @@
             rects.add(a.getBounds2D());
         }
 
-        download(newLayer, rects);
+        download(newLayer, rects, NullProgressMonitor.INSTANCE);
     }
 
     /**
      * Grabs and displays the error messages after all download threads have finished.
      */
     public void run() {
+        progressMonitor.finishTask();
         String errors = "";
 
         for(DownloadTask dt : osmTasks) {
@@ -108,7 +118,7 @@
     /**
      * Updates the local state of a set of primitives (given by a set of primitive
      * ids) with the state currently held on the server.
-     * 
+     *
      * @param potentiallyDeleted a set of ids to check update from the server
      */
     protected void updatePotentiallyDeletedPrimitives(Set<Long> potentiallyDeleted) {
@@ -134,7 +144,7 @@
      * deleted on the server. First prompts the user whether he wants to check
      * the current state on the server. If yes, retrieves the current state on the server
      * and checks whether the primitives are indeed deleted on the server.
-     * 
+     *
      * @param potentiallyDeleted a set of primitives (given by their ids)
      */
     protected void handlePotentiallyDeletedPrimitives(Set<Long> potentiallyDeleted) {
@@ -176,7 +186,7 @@
     /**
      * replies true, if the primitive with id <code>id</code> was downloaded into the
      * dataset <code>ds</code>
-     * 
+     *
      * @param id the id
      * @param ds the dataset
      * @return true, if the primitive with id <code>id</code> was downloaded into the
@@ -190,11 +200,11 @@
     /**
      * replies true, if the primitive with id <code>id</code> was downloaded into the
      * dataset of one of the download tasks
-     * 
+     *
      * @param id the id
      * @return true, if the primitive with id <code>id</code> was downloaded into the
      * dataset of one of the download tasks
-     * 
+     *
      */
     public boolean wasDownloaded(long id) {
         for (DownloadTask task : osmTasks) {
@@ -208,7 +218,7 @@
 
     /**
      * Replies the set of primitive ids which have been downloaded by this task list
-     * 
+     *
      * @return the set of primitive ids which have been downloaded by this task list
      */
     public Set<Long> getDownloadedIds() {
Index: src/org/openstreetmap/josm/actions/search/SelectionWebsiteLoader.java
===================================================================
--- src/org/openstreetmap/josm/actions/search/SelectionWebsiteLoader.java   (revision 1809)
+++ src/org/openstreetmap/josm/actions/search/SelectionWebsiteLoader.java   (working copy)
@@ -38,12 +38,13 @@
         this.url = u;
     }
     @Override protected void realRun() {
-        Main.pleaseWaitDlg.currentAction.setText(tr("Contact {0}...", url.getHost()));
+        progressMonitor.setTicksCount(2);
         sel = mode != SearchAction.SearchMode.remove ? new LinkedList<OsmPrimitive>() : Main.ds.allNonDeletedPrimitives();
         try {
             URLConnection con = url.openConnection();
-            InputStream in = new ProgressInputStream(con, Main.pleaseWaitDlg);
-            Main.pleaseWaitDlg.currentAction.setText(tr("Downloading..."));
+            progressMonitor.subTask(tr("Contact {0}...", url.getHost()));
+            InputStream in = new ProgressInputStream(con, progressMonitor.createSubTaskMonitor(1, true));
+            progressMonitor.subTask(tr("Downloading..."));
             Map<Long, String> ids = idReader.parseIds(in);
             for (OsmPrimitive osm : Main.ds.allNonDeletedPrimitives()) {
                 if (ids.containsKey(osm.id) && osm.getClass().getName().toLowerCase().endsWith(ids.get(osm.id))) {
@@ -54,6 +55,7 @@
                     }
                 }
             }
+            progressMonitor.worked(1);
         } catch (IOException e) {
             e.printStackTrace();
             JOptionPane.showMessageDialog(Main.parent, tr("Could not read from URL: \"{0}\"",url));
Index: src/org/openstreetmap/josm/Main.java
===================================================================
--- src/org/openstreetmap/josm/Main.java    (revision 1809)
+++ src/org/openstreetmap/josm/Main.java    (working copy)
@@ -12,7 +12,6 @@
 import java.net.URI;
 import java.net.URISyntaxException;
 import java.util.Collection;
-import java.util.Locale;
 import java.util.Map;
 import java.util.StringTokenizer;
 import java.util.concurrent.ExecutorService;
@@ -41,7 +40,6 @@
 import org.openstreetmap.josm.gui.GettingStarted;
 import org.openstreetmap.josm.gui.MainMenu;
 import org.openstreetmap.josm.gui.MapFrame;
-import org.openstreetmap.josm.gui.PleaseWaitDialog;
 import org.openstreetmap.josm.gui.SplashScreen;
 import org.openstreetmap.josm.gui.download.DownloadDialog.DownloadTask;
 import org.openstreetmap.josm.gui.layer.Layer;
@@ -98,7 +96,7 @@
     /**
      * The dialog that gets displayed during background task execution.
      */
-    public static PleaseWaitDialog pleaseWaitDlg;
+    //public static PleaseWaitDialog pleaseWaitDlg;
 
     /**
      * True, when in applet mode
@@ -229,7 +227,7 @@
      * Replies the current edit layer. Creates one if no {@see OsmDataLayer}
      * exists. Replies null, if the currently active layer isn't an instance
      * of {@see OsmDataLayer}.
-     * 
+     *
      * @return the current edit layer
      */
     public final OsmDataLayer createOrGetEditLayer() {
@@ -241,7 +239,7 @@
 
     /**
      * Replies true if this map view has an edit layer
-     * 
+     *
      * @return true if this map view has an edit layer
      */
     public boolean hasEditLayer() {
@@ -351,15 +349,9 @@
         if (bounds == null) {
             bounds = !args.containsKey("no-maximize") ? new Rectangle(0,0,screenDimension.width,screenDimension.height) : new Rectangle(1000,740);
         }
-
-        // preinitialize a wait dialog for all early downloads (e.g. via command line)
-        pleaseWaitDlg = new PleaseWaitDialog(null);
     }
 
     public void postConstructorProcessCmdLine(Map<String, Collection<String>> args) {
-        // initialize the pleaseWaitDialog with the application as parent to handle focus stuff
-        pleaseWaitDlg = new PleaseWaitDialog(parent);
-
         if (args.containsKey("download")) {
             for (String s : args.get("download")) {
                 downloadFromParamString(false, s);
@@ -425,7 +417,7 @@
             } else {
                 //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());
+                osmTask.download(main.menu.download, b.min.lat(), b.min.lon(), b.max.lat(), b.max.lon(), null);
             }
             return;
         }
@@ -443,7 +435,7 @@
         if (st.countTokens() == 4) {
             try {
                 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()));
+                task.download(main.menu.download, Double.parseDouble(st.nextToken()), Double.parseDouble(st.nextToken()), Double.parseDouble(st.nextToken()), Double.parseDouble(st.nextToken()), null);
                 return;
             } catch (final NumberFormatException e) {
             }
Index: src/org/openstreetmap/josm/plugins/PluginDownloader.java
===================================================================
--- src/org/openstreetmap/josm/plugins/PluginDownloader.java    (revision 1809)
+++ src/org/openstreetmap/josm/plugins/PluginDownloader.java    (working copy)
@@ -48,7 +48,6 @@
         }
 
         @Override protected void finish() {
-            Main.pleaseWaitDlg.setVisible(false);
             if (errors.length() > 0)
                 JOptionPane.showMessageDialog(Main.parent, tr("There were problems with the following plugins:\n\n {0}",errors));
             else
@@ -59,11 +58,10 @@
             File pluginDir = Main.pref.getPluginsDirFile();
             if (!pluginDir.exists())
                 pluginDir.mkdirs();
-            Main.pleaseWaitDlg.progress.setMaximum(toUpdate.size());
-            int progressValue = 0;
+            progressMonitor.setTicksCount(toUpdate.size());
             for (PluginInformation d : toUpdate) {
-                Main.pleaseWaitDlg.progress.setValue(progressValue++);
-                Main.pleaseWaitDlg.currentAction.setText(tr("Downloading Plugin {0}...", d.name));
+                progressMonitor.subTask(tr("Downloading Plugin {0}...", d.name));
+                progressMonitor.worked(1);
                 File pluginFile = new File(pluginDir, d.name + ".jar.new");
                 if(download(d, pluginFile))
                     count++;
Index: src/org/openstreetmap/josm/gui/PleaseWaitRunnable.java
===================================================================
--- src/org/openstreetmap/josm/gui/PleaseWaitRunnable.java  (revision 1809)
+++ src/org/openstreetmap/josm/gui/PleaseWaitRunnable.java  (working copy)
@@ -4,19 +4,14 @@
 import static org.openstreetmap.josm.tools.I18n.tr;
 
 import java.awt.EventQueue;
-import java.awt.event.ActionEvent;
-import java.awt.event.ActionListener;
-import java.awt.event.WindowAdapter;
-import java.awt.event.WindowEvent;
-import java.awt.event.WindowListener;
 import java.io.FileNotFoundException;
 import java.io.IOException;
-import java.lang.reflect.InvocationTargetException;
 
-import javax.swing.JOptionPane;
 import javax.swing.SwingUtilities;
 
-import org.openstreetmap.josm.Main;
+import org.openstreetmap.josm.gui.progress.PleaseWaitProgressMonitor;
+import org.openstreetmap.josm.gui.progress.ProgressMonitor;
+import org.openstreetmap.josm.gui.progress.ProgressMonitor.CancelListener;
 import org.openstreetmap.josm.io.OsmTransferException;
 import org.xml.sax.SAXException;
 
@@ -26,36 +21,13 @@
  *
  * @author Imi
  */
-public abstract class PleaseWaitRunnable implements Runnable {
-    public boolean silent = false;
-    public String errorMessage;
+public abstract class PleaseWaitRunnable implements Runnable, CancelListener {
 
-    private boolean closeDialogCalled = false;
     private boolean cancelled = false;
     private boolean ignoreException;
-
     private final String title;
 
-    private ActionListener cancelListener = new ActionListener(){
-        public void actionPerformed(ActionEvent e) {
-            if (!cancelled) {
-                cancelled = true;
-                cancel();
-            }
-        }
-    };
-
-    private WindowListener windowListener = new WindowAdapter(){
-        @Override public void windowClosing(WindowEvent e) {
-            if (!closeDialogCalled) {
-                if (!cancelled) {
-                    cancelled = true;
-                    cancel();
-                }
-                closeDialog();
-            }
-        }
-    };
+    protected final ProgressMonitor progressMonitor;
 
     /**
      * Create the runnable object with a given message for the user.
@@ -72,45 +44,51 @@
      * then use false unless you read result of task (because exception will get lost if you don't)
      */
     public PleaseWaitRunnable(String title, boolean ignoreException) {
-        this.title = title;
-        this.ignoreException = ignoreException;
+        this(title, new PleaseWaitProgressMonitor(), ignoreException);
     }
 
-    private void prepareDialog() {
-        // reset dialog state
-        errorMessage = null;
-        closeDialogCalled = false;
-
-        Main.pleaseWaitDlg.setTitle(title);
-        Main.pleaseWaitDlg.cancel.setEnabled(true);
-        Main.pleaseWaitDlg.setCustomText("");
-        Main.pleaseWaitDlg.cancel.addActionListener(cancelListener);
-        Main.pleaseWaitDlg.addWindowListener(windowListener);
-        Main.pleaseWaitDlg.setVisible(true);
+    public PleaseWaitRunnable(String title, ProgressMonitor progressMonitor, boolean ignoreException) {
+        this.title = title;
+        this.progressMonitor = progressMonitor == null?new PleaseWaitProgressMonitor():progressMonitor;
+        this.ignoreException = ignoreException;
+        this.progressMonitor.addCancelListener(this);
     }
 
     private void doRealRun() {
         try {
             try {
-                realRun();
+                progressMonitor.beginTask(title);
+                try {
+                    realRun();
+                } finally {
+                    if (EventQueue.isDispatchThread()) {
+                        finish();
+                    } else {
+                        EventQueue.invokeAndWait(new Runnable() {
+                            public void run() {
+                                finish();
+                            }
+                        });
+                    }
+                }
             } catch (SAXException x) {
                 x.printStackTrace();
-                errorMessage = tr("Error while parsing")+": "+x.getMessage();
+                progressMonitor.setErrorMessage(tr("Error while parsing")+": "+x.getMessage());
             } catch (FileNotFoundException x) {
                 x.printStackTrace();
-                errorMessage = tr("File not found")+": "+x.getMessage();
+                progressMonitor.setErrorMessage(tr("File not found")+": "+x.getMessage());
             } catch (IOException x) {
                 x.printStackTrace();
-                errorMessage = x.getMessage();
+                progressMonitor.setErrorMessage(x.getMessage());
             } catch(OsmTransferException x) {
                 x.printStackTrace();
                 if (x.getCause() != null) {
-                    errorMessage = x.getCause().getMessage();
+                    progressMonitor.setErrorMessage(x.getCause().getMessage());
                 } else {
-                    errorMessage = x.getMessage();
+                    progressMonitor.setErrorMessage(x.getMessage());
                 }
             } finally {
-                closeDialog();
+                progressMonitor.finishTask();
             }
         } catch (final Throwable e) {
             if (!ignoreException) {
@@ -134,17 +112,15 @@
                     doRealRun();
                 }
             }).start();
-            prepareDialog();
         } else {
-            EventQueue.invokeLater(new Runnable() {
-                public void run() {
-                    prepareDialog();
-                }
-            });
             doRealRun();
         }
     }
 
+    public void operationCanceled() {
+        cancel();
+    }
+
     /**
      * User pressed cancel button.
      */
@@ -163,40 +139,7 @@
      */
     protected abstract void finish();
 
-    /**
-     * Close the dialog. Usually called from worker thread.
-     */
-    public void closeDialog() {
-        if (closeDialogCalled)
-            return;
-        closeDialogCalled  = true;
-        try {
-            Runnable runnable = new Runnable(){
-                public void run() {
-                    try {
-                        finish();
-                    } finally {
-                        Main.pleaseWaitDlg.setVisible(false);
-                        Main.pleaseWaitDlg.dispose();
-                        Main.pleaseWaitDlg.removeWindowListener(windowListener);
-                        Main.pleaseWaitDlg.cancel.removeActionListener(cancelListener);
-                    }
-                    if (errorMessage != null && !silent) {
-                        JOptionPane.showMessageDialog(Main.parent, errorMessage);
-                    }
-                }
-            };
-
-            // make sure, this is called in the dispatcher thread ASAP
-            if (EventQueue.isDispatchThread()) {
-                runnable.run();
-            } else {
-                EventQueue.invokeAndWait(runnable);
-            }
-
-        } catch (InterruptedException e) {
-        } catch (InvocationTargetException e) {
-            throw new RuntimeException(e);
-        }
+    public ProgressMonitor getProgressMonitor() {
+        return progressMonitor;
     }
 }
Index: src/org/openstreetmap/josm/gui/download/DownloadDialog.java
===================================================================
--- src/org/openstreetmap/josm/gui/download/DownloadDialog.java (revision 1809)
+++ src/org/openstreetmap/josm/gui/download/DownloadDialog.java (working copy)
@@ -4,14 +4,14 @@
 import static org.openstreetmap.josm.tools.I18n.tr;
 
 import java.awt.Color;
+import java.awt.Font;
+import java.awt.GridBagLayout;
+import java.awt.Toolkit;
 import java.awt.datatransfer.DataFlavor;
 import java.awt.datatransfer.Transferable;
 import java.awt.event.ActionEvent;
 import java.awt.event.InputEvent;
 import java.awt.event.KeyEvent;
-import java.awt.Font;
-import java.awt.GridBagLayout;
-import java.awt.Toolkit;
 import java.util.ArrayList;
 import java.util.List;
 
@@ -29,6 +29,7 @@
 import org.openstreetmap.josm.actions.downloadtasks.DownloadOsmTask;
 import org.openstreetmap.josm.data.Bounds;
 import org.openstreetmap.josm.gui.MapView;
+import org.openstreetmap.josm.gui.progress.ProgressMonitor;
 import org.openstreetmap.josm.plugins.PluginHandler;
 import org.openstreetmap.josm.tools.GBC;
 import org.openstreetmap.josm.tools.OsmUrlToBounds;
@@ -50,18 +51,11 @@
 
     public interface DownloadTask {
         /**
-         * Execute the download using the given bounding box
+         * Execute the download using the given bounding box. Set silent on progressMonitor
+         * if no error messages should be popped up.
          */
         void download(DownloadAction action, double minlat, double minlon,
-                double maxlat, double maxlon);
-
-        /**
-         * Execute the download using the given bounding box. Set silent to true if no error
-         * messages should be popped up. Message can be used to display an additional text below
-         * the default description.
-         */
-        void download(DownloadAction action, double minlat, double minlon,
-                double maxlat, double maxlon, boolean silent, String message);
+                double maxlat, double maxlon, ProgressMonitor progressMonitor);
 
         /**
          * Execute the download using the given URL
Index: src/org/openstreetmap/josm/gui/conflict/properties/PropertiesMergeModel.java
===================================================================
--- src/org/openstreetmap/josm/gui/conflict/properties/PropertiesMergeModel.java    (revision 1809)
+++ src/org/openstreetmap/josm/gui/conflict/properties/PropertiesMergeModel.java    (working copy)
@@ -6,15 +6,12 @@
 
 import java.beans.PropertyChangeListener;
 import java.beans.PropertyChangeSupport;
-import java.io.IOException;
-import java.net.HttpURLConnection;
 import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Observable;
 
 import javax.swing.JOptionPane;
-import javax.swing.text.html.HTML;
 
 import org.openstreetmap.josm.Main;
 import org.openstreetmap.josm.command.Command;
@@ -26,19 +23,13 @@
 import org.openstreetmap.josm.data.osm.DataSet;
 import org.openstreetmap.josm.data.osm.Node;
 import org.openstreetmap.josm.data.osm.OsmPrimitive;
-import org.openstreetmap.josm.data.osm.OsmPrimitiveType;
 import org.openstreetmap.josm.data.osm.Relation;
 import org.openstreetmap.josm.data.osm.RelationMember;
 import org.openstreetmap.josm.data.osm.Way;
-import org.openstreetmap.josm.gui.PleaseWaitRunnable;
 import org.openstreetmap.josm.gui.conflict.MergeDecisionType;
-import org.openstreetmap.josm.gui.conflict.properties.PropertiesMerger.KeepMyVisibleStateAction;
+import org.openstreetmap.josm.gui.progress.NullProgressMonitor;
 import org.openstreetmap.josm.io.MultiFetchServerObjectReader;
-import org.openstreetmap.josm.io.OsmApi;
-import org.openstreetmap.josm.io.OsmApiException;
-import org.openstreetmap.josm.io.OsmServerObjectReader;
 import org.openstreetmap.josm.io.OsmTransferException;
-import org.xml.sax.SAXException;
 
 /**
  * This is the model for resolving conflicts in the properties of the
@@ -282,7 +273,7 @@
     /**
      * replies the merged visible state; null, if the merge decision is
      * {@see MergeDecisionType#UNDECIDED}.
-     * 
+     *
      * @return the merged visible state
      */
     public Boolean getMergedVisibleState() {
@@ -298,7 +289,7 @@
     /**
      * decides the conflict between two deleted states
      * @param decision the decision (must not be null)
-     * 
+     *
      * @throws IllegalArgumentException thrown, if decision is null
      */
     public void decideDeletedStateConflict(MergeDecisionType decision) throws IllegalArgumentException{
@@ -313,7 +304,7 @@
     /**
      * decides the conflict between two visible states
      * @param decision the decision (must not be null)
-     * 
+     *
      * @throws IllegalArgumentException thrown, if decision is null
      */
     public void decideVisibleStateConflict(MergeDecisionType decision) throws IllegalArgumentException {
@@ -418,7 +409,7 @@
     }
 
     /**
-     * 
+     *
      * @param id
      */
     protected void handleExceptionWhileBuildingCommand(Exception e) {
@@ -439,7 +430,7 @@
     /**
      * User has decided to keep his local version of a primitive which had been deleted
      * on the server
-     * 
+     *
      * @param id the primitive id
      */
     protected UndeletePrimitivesCommand createUndeletePrimitiveCommand(OsmPrimitive my) throws OsmTransferException {
@@ -456,7 +447,7 @@
      * doesn't offer a call for "undeleting" a node. We therefore create
      * a clone of the node which we flag as new. On the next upload the
      * server will assign the node a new id.
-     * 
+     *
      * @param node the node to undelete
      */
     protected UndeletePrimitivesCommand  createUndeleteNodeCommand(Node node) {
@@ -466,7 +457,7 @@
     /**
      * displays a confirmation message. The user has to confirm that additional dependent
      * nodes should be undeleted too.
-     * 
+     *
      * @param way  the way
      * @param dependent a list of dependent nodes which have to be undelete too
      * @return true, if the user confirms; false, otherwise
@@ -531,10 +522,10 @@
 
     /**
      * Creates the undelete command for a way which is already deleted on the server.
-     * 
+     *
      * This method also checks whether there are additional nodes referred to by
      * this way which are deleted on the server too.
-     * 
+     *
      * @param way the way to undelete
      * @return the undelete command
      * @see #createUndeleteNodeCommand(Node)
@@ -549,7 +540,7 @@
         }
         MultiFetchServerObjectReader reader = new MultiFetchServerObjectReader();
         reader.append(candidates.values());
-        DataSet ds = reader.parseOsm();
+        DataSet ds = reader.parseOsm(NullProgressMonitor.INSTANCE);
 
         ArrayList<OsmPrimitive> toDelete = new ArrayList<OsmPrimitive>();
         for (OsmPrimitive their : ds.allPrimitives()) {
@@ -568,10 +559,10 @@
 
     /**
      * Creates an undelete command for a relation which is already deleted on the server.
-     * 
+     *
      * This method  checks whether there are additional primitives referred to by
      * this relation which are already deleted on the server.
-     * 
+     *
      * @param r the relation
      * @return the undelete command
      * @see #createUndeleteNodeCommand(Node)
@@ -587,7 +578,7 @@
 
         MultiFetchServerObjectReader reader = new MultiFetchServerObjectReader();
         reader.append(candidates.values());
-        DataSet ds = reader.parseOsm();
+        DataSet ds = reader.parseOsm(NullProgressMonitor.INSTANCE);
 
         ArrayList<OsmPrimitive> toDelete = new ArrayList<OsmPrimitive>();
         for (OsmPrimitive their : ds.allPrimitives()) {
Index: src/org/openstreetmap/josm/gui/PleaseWaitDialog.java
===================================================================
--- src/org/openstreetmap/josm/gui/PleaseWaitDialog.java    (revision 1809)
+++ src/org/openstreetmap/josm/gui/PleaseWaitDialog.java    (working copy)
@@ -1,7 +1,8 @@
 // License: GPL. Copyright 2007 by Immanuel Scholz and others
 package org.openstreetmap.josm.gui;
 
-import java.awt.Component;
+import java.awt.Dialog;
+import java.awt.Frame;
 import java.awt.GridBagLayout;
 import java.awt.event.ComponentEvent;
 import java.awt.event.ComponentListener;
@@ -11,7 +12,6 @@
 import javax.swing.JButton;
 import javax.swing.JDialog;
 import javax.swing.JLabel;
-import javax.swing.JOptionPane;
 import javax.swing.JPanel;
 import javax.swing.JProgressBar;
 import javax.swing.UIManager;
@@ -24,13 +24,12 @@
 
     private final JProgressBar progressBar = new JProgressBar();
 
-    public final JLabel currentAction = new JLabel(I18n.tr("Contacting the OSM server..."));
+    public final JLabel currentAction = new JLabel("");
     private final JLabel customText = new JLabel("");
     public final BoundedRangeModel progress = progressBar.getModel();
     public final JButton cancel = new JButton(I18n.tr("Cancel"));
 
-    public PleaseWaitDialog(Component parent) {
-        super(JOptionPane.getFrameForComponent(parent), true);
+    private void initDialog() {
         setLayout(new GridBagLayout());
         JPanel pane = new JPanel(new GridBagLayout());
         pane.setBorder(BorderFactory.createEmptyBorder(10,10,10,10));
@@ -54,6 +53,16 @@
         });
     }
 
+    public PleaseWaitDialog(Frame parent) {
+        super(parent, true);
+        initDialog();
+    }
+
+    public PleaseWaitDialog(Dialog parent) {
+        super(parent, true);
+        initDialog();
+    }
+
     public void setIndeterminate(boolean newValue) {
         UIManager.put("ProgressBar.cycleTime", UIManager.getInt("ProgressBar.repaintInterval") * 100);
         progressBar.setIndeterminate(newValue);
Index: src/org/openstreetmap/josm/gui/progress/AbstractProgressMonitor.java
===================================================================
--- src/org/openstreetmap/josm/gui/progress/AbstractProgressMonitor.java    (revision 0)
+++ src/org/openstreetmap/josm/gui/progress/AbstractProgressMonitor.java    (revision 0)
@@ -0,0 +1,388 @@
+// License: GPL. For details, see LICENSE file.
+package org.openstreetmap.josm.gui.progress;
+
+import java.util.Arrays;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.Queue;
+
+
+public abstract class AbstractProgressMonitor implements ProgressMonitor {
+
+    private static class Request {
+        AbstractProgressMonitor originator;
+        int childTicks;
+        double currentValue;
+
+        String title;
+        String customText;
+        String extraText;
+        Boolean intermediate;
+    }
+
+    private final CancelHandler cancelHandler;
+
+    protected enum State {INIT, IN_TASK, IN_SUBTASK, FINISHED}
+
+    protected State state = State.INIT;
+
+    int ticksCount;
+    int ticks;
+    private int childTicks;
+
+    private String taskTitle;
+    private String customText;
+    private String extraText;
+    private String shownTitle;
+    private String shownCustomText;
+    private boolean intermediateTask;
+
+    private Queue<Request> requests = new LinkedList<Request>();
+    private AbstractProgressMonitor currentChild;
+    private Request requestedState = new Request();
+
+    private boolean silent;
+    private String errorMessage;
+
+    protected abstract void doBeginTask();
+    protected abstract void doFinishTask();
+    protected abstract void doSetIntermediate(boolean value);
+    protected abstract void doSetTitle(String title);
+    protected abstract void doSetCustomText(String title);
+    protected abstract void doSetErrorMessage(String message);
+
+    protected AbstractProgressMonitor(CancelHandler cancelHandler) {
+        this.cancelHandler = cancelHandler;
+    }
+
+    protected void checkState(State... expectedStates) {
+        for (State s:expectedStates) {
+            if (s == state) {
+                return;
+            }
+        }
+        throw new ProgressException("Expected states are %s but current state is %s", Arrays.asList(expectedStates).toString(), state);
+    }
+
+    /*=======
+     * Tasks
+     =======*/
+
+    public void beginTask(String title) {
+        beginTask(title, DEFAULT_TICKS);
+    }
+
+    public synchronized void beginTask(final String title, int ticks) {
+        this.taskTitle = title;
+        checkState(State.INIT);
+        state = State.IN_TASK;
+        doBeginTask();
+        setTicksCount(ticks);
+        resetState();
+    }
+
+    public synchronized void finishTask() {
+        if (state != State.FINISHED) {
+
+            if (state == State.IN_SUBTASK) {
+                // Make sure the subtask didn't start yet (once task start it must be finished)
+                boolean broken = currentChild.state != State.INIT;
+                for (Request request:requests) {
+                    broken = broken | request.originator.state != State.INIT;
+                }
+                if (broken) {
+                    throw new ProgressException("Cannot call finishTask when there are unfinished tasks");
+                } else {
+                    state = State.IN_TASK;
+                }
+            }
+
+            checkState(State.IN_TASK);
+            state = State.FINISHED;
+            doFinishTask();
+        }
+    }
+
+    public synchronized void invalidate() {
+        checkState(State.INIT);
+        state = State.FINISHED;
+        doFinishTask();
+    }
+
+    public synchronized void subTask(final String title) {
+        if (state == State.IN_SUBTASK) {
+            if (title != null) {
+                requestedState.title = title;
+            }
+            requestedState.intermediate = false;
+        } else {
+            checkState(State.IN_TASK);
+            if (title != null) {
+                this.taskTitle = title;
+                resetState();
+            }
+            this.intermediateTask = false;
+            doSetIntermediate(false);
+        }
+    }
+
+    public synchronized void indeterminateSubTask(String title) {
+        if (state == State.IN_SUBTASK) {
+            if (title != null) {
+                requestedState.title = title;
+            }
+            requestedState.intermediate = true;
+        } else {
+            checkState(State.IN_TASK);
+            if (title != null) {
+                this.taskTitle = title;
+                resetState();
+            }
+            this.intermediateTask = true;
+            doSetIntermediate(true);
+        }
+    }
+
+    public synchronized void setCustomText(String text) {
+        if (state == State.IN_SUBTASK) {
+            requestedState.customText = text;
+        } else {
+            this.customText = text;
+            resetState();
+        }
+    }
+
+    public synchronized void setExtraText(String text) {
+        if (state == State.IN_SUBTASK) {
+            requestedState.extraText = text;
+        } else {
+            this.extraText = text;
+            resetState();
+        }
+    }
+
+    private void resetState() {
+        String newTitle;
+        if (extraText != null) {
+            newTitle = taskTitle + " " + extraText;
+        } else {
+            newTitle = taskTitle;
+        }
+
+        if (newTitle == null?shownTitle != null:!newTitle.equals(shownTitle)) {
+            shownTitle = newTitle;
+            doSetTitle(shownTitle);
+        }
+
+        if (customText == null?shownCustomText != null:!customText.equals(shownCustomText)) {
+            shownCustomText = customText;
+            doSetCustomText(shownCustomText);
+        }
+        doSetIntermediate(intermediateTask);
+    }
+
+    public void cancel() {
+        cancelHandler.cancel();
+    }
+
+    public boolean isCancelled() {
+        return cancelHandler.isCanceled();
+    }
+
+    public void addCancelListener(CancelListener listener) {
+        cancelHandler.addCancelListener(listener);
+    }
+
+    public void removeCancelListener(CancelListener listener) {
+        cancelHandler.removeCancelListener(listener);
+    }
+
+    /*=================
+     * Ticks handling
+    ==================*/
+
+    abstract void updateProgress(double value);
+
+    public synchronized void setTicks(int ticks) {
+        if (ticks >= ticksCount) {
+            ticks = ticksCount - 1;
+        }
+        this.ticks = ticks;
+        internalUpdateProgress(0);
+    }
+
+    public synchronized void setTicksCount(int ticks) {
+        this.ticksCount = ticks;
+        internalUpdateProgress(0);
+    }
+
+    public void worked(int ticks) {
+        if (ticks == ALL_TICKS) {
+            setTicks(this.ticksCount - 1);
+        } else {
+            setTicks(this.ticks + ticks);
+        }
+    }
+
+    private void internalUpdateProgress(double childProgress) {
+        if (childProgress > 1) {
+            childProgress = 1;
+        }
+        checkState(State.IN_TASK, State.IN_SUBTASK);
+        updateProgress(ticksCount == 0?0:(ticks + childProgress * childTicks) / ticksCount);
+    }
+
+    public synchronized int getTicks() {
+        return ticks;
+    }
+
+    /*==========
+     * Subtasks
+     ==========*/
+
+    public synchronized ProgressMonitor createSubTaskMonitor(int ticks, boolean internal) {
+        if (ticks == ALL_TICKS) {
+            ticks = ticksCount - this.ticks;
+        }
+
+        if (state == State.IN_SUBTASK) {
+            Request request = new Request();
+            request.originator = new ChildProgress(this, cancelHandler, internal);
+            request.childTicks = ticks;
+            requests.add(request);
+            return request.originator;
+        } else {
+            checkState(State.IN_TASK);
+            state = State.IN_SUBTASK;
+            this.childTicks = ticks;
+            currentChild = new ChildProgress(this, cancelHandler, internal);
+            return currentChild;
+        }
+    }
+
+    private void applyChildRequest(Request request) {
+        if (request.customText != null) {
+            doSetCustomText(request.customText);
+        }
+
+        if (request.title != null) {
+            doSetTitle(request.title);
+        }
+
+        if (request.intermediate != null) {
+            doSetIntermediate(request.intermediate);
+        }
+
+        internalUpdateProgress(request.currentValue);
+    }
+
+    private void applyThisRequest(Request request) {
+        if (request.customText != null) {
+            this.customText = request.customText;
+        }
+
+        if (request.title != null) {
+            this.taskTitle = request.title;
+        }
+
+        if (request.intermediate != null) {
+            this.intermediateTask = request.intermediate;
+        }
+
+        if (request.extraText != null) {
+            this.extraText = request.extraText;
+        }
+
+        resetState();
+    }
+
+    protected synchronized void childFinished(AbstractProgressMonitor child) {
+        checkState(State.IN_SUBTASK);
+        if (currentChild == child) {
+            setTicks(ticks + childTicks);
+            if (requests.isEmpty()) {
+                state = State.IN_TASK;
+                applyThisRequest(requestedState);
+                requestedState = new Request();
+            } else {
+                Request newChild = requests.poll();
+                currentChild = newChild.originator;
+                childTicks = newChild.childTicks;
+                applyChildRequest(newChild);
+            }
+        } else {
+            Iterator<Request> it = requests.iterator();
+            while (it.hasNext()) {
+                if (it.next().originator == child) {
+                    it.remove();
+                    return;
+                }
+            }
+            throw new ProgressException("Subtask %s not found", child);
+        }
+    }
+
+    private Request getRequest(AbstractProgressMonitor child) {
+        for (Request request:requests) {
+            if (request.originator == child) {
+                return request;
+            }
+        }
+        throw new ProgressException("Subtask %s not found", child);
+    }
+
+    protected synchronized void childSetProgress(AbstractProgressMonitor child, double value) {
+        checkState(State.IN_SUBTASK);
+        if (currentChild == child) {
+            internalUpdateProgress(value);
+        } else {
+            getRequest(child).currentValue = value;
+        }
+    }
+
+    protected synchronized void childSetTitle(AbstractProgressMonitor child, String title) {
+        checkState(State.IN_SUBTASK);
+        if (currentChild == child) {
+            doSetTitle(title);
+        } else {
+            getRequest(child).title = title;
+        }
+    }
+
+    protected synchronized void childSetCustomText(AbstractProgressMonitor child, String customText) {
+        checkState(State.IN_SUBTASK);
+        if (currentChild == child) {
+            doSetCustomText(customText);
+        } else {
+            getRequest(child).customText = customText;
+        }
+    }
+
+    protected synchronized void childSetIntermediate(AbstractProgressMonitor child, boolean value) {
+        checkState(State.IN_SUBTASK);
+        if (currentChild == child) {
+            doSetIntermediate(value);
+        } else {
+            getRequest(child).intermediate = value;
+        }
+    }
+
+    /*======================
+     * Silent/error message
+     ======================*/
+    public synchronized void setSilent(boolean value) {
+        this.silent = value;
+    }
+
+    public synchronized void setErrorMessage(String message) {
+        this.errorMessage = message;
+        if (!silent) {
+            doSetErrorMessage(message);
+        }
+    }
+
+    public synchronized String getErrorMessage() {
+        return errorMessage;
+    }
+
+}

Property changes on: src/org/openstreetmap/josm/gui/progress/AbstractProgressMonitor.java
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Index: src/org/openstreetmap/josm/gui/progress/ProgressException.java
===================================================================
--- src/org/openstreetmap/josm/gui/progress/ProgressException.java  (revision 0)
+++ src/org/openstreetmap/josm/gui/progress/ProgressException.java  (revision 0)
@@ -0,0 +1,10 @@
+// License: GPL. For details, see LICENSE file.
+package org.openstreetmap.josm.gui.progress;
+
+public class ProgressException extends RuntimeException {
+
+    public ProgressException(String message, Object... args) {
+        super(String.format(message, args));
+    }
+
+}

Property changes on: src/org/openstreetmap/josm/gui/progress/ProgressException.java
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Index: src/org/openstreetmap/josm/gui/progress/PleaseWaitProgressMonitor.java
===================================================================
--- src/org/openstreetmap/josm/gui/progress/PleaseWaitProgressMonitor.java  (revision 0)
+++ src/org/openstreetmap/josm/gui/progress/PleaseWaitProgressMonitor.java  (revision 0)
@@ -0,0 +1,165 @@
+// License: GPL. For details, see LICENSE file.
+package org.openstreetmap.josm.gui.progress;
+
+import java.awt.Dialog;
+import java.awt.EventQueue;
+import java.awt.Frame;
+import java.awt.Window;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.awt.event.WindowAdapter;
+import java.awt.event.WindowEvent;
+import java.awt.event.WindowListener;
+import java.lang.reflect.InvocationTargetException;
+
+import javax.swing.JOptionPane;
+
+import org.openstreetmap.josm.Main;
+import org.openstreetmap.josm.gui.PleaseWaitDialog;
+
+
+public class PleaseWaitProgressMonitor extends AbstractProgressMonitor {
+
+    private static final int PROGRESS_BAR_MAX = 100;
+    private final Window dialogParent;
+
+    private PleaseWaitDialog dialog;
+
+    public PleaseWaitProgressMonitor() {
+        this(JOptionPane.getFrameForComponent(Main.map));
+    }
+
+    public PleaseWaitProgressMonitor(Window dialogParent) {
+        super(new CancelHandler());
+        this.dialogParent = dialogParent;
+    }
+
+    private ActionListener cancelListener = new ActionListener(){
+        public void actionPerformed(ActionEvent e) {
+            cancel();
+        }
+    };
+
+    private WindowListener windowListener = new WindowAdapter(){
+        @Override public void windowClosing(WindowEvent e) {
+            cancel();
+            closeDialog();
+        }
+    };
+
+    private void closeDialog() {
+        try {
+            Runnable runnable = new Runnable(){
+                public void run() {
+                }
+            };
+
+            // make sure, this is called in the dispatcher thread ASAP
+            if (EventQueue.isDispatchThread()) {
+                runnable.run();
+            } else {
+                EventQueue.invokeAndWait(runnable);
+            }
+
+        } catch (InterruptedException e) {
+        } catch (InvocationTargetException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    private void doInEDT(Runnable runnable) {
+        EventQueue.invokeLater(runnable);
+    }
+
+    public void doBeginTask() {
+        doInEDT(new Runnable() {
+            public void run() {
+                if (dialogParent instanceof Frame) {
+                    dialog = new PleaseWaitDialog((Frame)dialogParent);
+                } else if (dialogParent instanceof Dialog) {
+                    dialog = new PleaseWaitDialog((Dialog)dialogParent);
+                } else {
+                    throw new ProgressException("PleaseWaitDialog parent must be either Frame or Dialog");
+                }
+
+                dialog.cancel.setEnabled(true);
+                dialog.setCustomText("");
+                dialog.cancel.addActionListener(cancelListener);
+                dialog.addWindowListener(windowListener);
+                dialog.progress.setMaximum(PROGRESS_BAR_MAX);
+                dialog.setVisible(true);
+            }
+        });
+    }
+
+    public void doFinishTask() {
+        doInEDT(new Runnable() {
+            public void run() {
+                if (dialog != null) {
+                    dialog.setVisible(false);
+                    dialog.dispose();
+                    dialog.removeWindowListener(windowListener);
+                    dialog.cancel.removeActionListener(cancelListener);
+                    if (getErrorMessage() != null) {
+                        JOptionPane.showMessageDialog(Main.parent, getErrorMessage());
+                    }
+                    dialog = null;
+                }
+            }
+        });
+    }
+
+    public void worked(int ticks) {
+        this.ticks += ticks;
+        updateProgress(0);
+    }
+
+    protected void updateProgress(final double progressValue) {
+        doInEDT(new Runnable() {
+            public void run() {
+                dialog.progress.setValue((int)(progressValue * PROGRESS_BAR_MAX));
+            }
+        });
+    }
+
+    @Override
+    protected void doSetCustomText(final String title) {
+        checkState(State.IN_TASK, State.IN_SUBTASK);
+        doInEDT(new Runnable() {
+            public void run() {
+                dialog.setCustomText(title);
+            }
+        });
+    }
+
+    @Override
+    protected void doSetTitle(final String title) {
+        checkState(State.IN_TASK, State.IN_SUBTASK);
+        doInEDT(new Runnable() {
+            public void run() {
+                dialog.currentAction.setText(title);
+            }
+        });
+    }
+
+    @Override
+    protected void doSetIntermediate(final boolean value) {
+        doInEDT(new Runnable() {
+            public void run() {
+                if (value && dialog.progress.getValue() == 0) {
+                    // Enable only if progress is at the begging. Doing intermediate progress in the middle
+                    // will hide already reached progress
+                    dialog.setIndeterminate(true);
+                } else {
+                    dialog.setIndeterminate(false);
+                }
+            }
+        });
+    }
+
+    @Override
+    protected void doSetErrorMessage(String message) {
+        // Do nothing
+    }
+
+}

Property changes on: src/org/openstreetmap/josm/gui/progress/PleaseWaitProgressMonitor.java
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Index: src/org/openstreetmap/josm/gui/progress/ProgressMonitor.java
===================================================================
--- src/org/openstreetmap/josm/gui/progress/ProgressMonitor.java    (revision 0)
+++ src/org/openstreetmap/josm/gui/progress/ProgressMonitor.java    (revision 0)
@@ -0,0 +1,118 @@
+// License: GPL. For details, see LICENSE file.
+package org.openstreetmap.josm.gui.progress;
+
+/**
+ * Typical usecase is:
+ * <pre>
+ *   monitor.beginTask()
+ *   try {
+ *     .. do some work
+ *     monitor.worked()
+ *     monitor.subTask()/monitor.intermediateTask()
+ *     .. do some work
+ *     monitor.worked()
+ *   } finally {
+ *     monitor.finishTask();
+ *   }
+ * </pre>
+ *
+ * {@link #subTask(String)} and {@link #indeterminateSubTask(String)} has nothing to do with logical
+ * structure of the work, they just show task title to the user.
+ *
+ * If task consists of multiple tasks then {@link #createSubTaskMonitor(int, boolean)} may be used. It
+ * will create new ProgressMonitor, then can be passed to the subtask. Subtask doesn't know whether
+ * it runs standalono or as a part of other task. Progressbar will be updated so that total progress is
+ * shown, not just progress of the subtask
+ *
+ * All ProgressMonitor implemenenatations should be thread safe.
+ *
+ */
+public interface ProgressMonitor {
+
+    public interface CancelListener {
+        void operationCanceled();
+    }
+
+    public final int DEFAULT_TICKS = 100;
+
+    /**
+     * Can be used with {@link #worked(int)} and {@link #createSubTaskMonitor(int, boolean)} to
+     * express that the task should use all remaining ticks
+     */
+    public final int ALL_TICKS = -1;
+
+    void beginTask(String title);
+
+    /**
+     * Starts this progress monitor. Must be called excatly once
+     * @param title
+     * @param ticks
+     */
+    void beginTask(String title, int ticks);
+    /**
+     * Finish this progress monitor, close the dialog or inform the parent progress monitor
+     * that it can continue with other tasks. Must be called at least once (if called multiply times
+     * then futher calls are ignored)
+     */
+    void finishTask();
+    /**
+     * Can be used if method receive ProgressMonitor but it's not interested progress monitoring.
+     * Basically replaces {@link #beginTask(String)} and {@link #finishTask()}
+     */
+    void invalidate();
+
+    /**
+     *
+     * @param ticks Number of total work units
+     */
+    void setTicksCount(int ticks);
+    /**
+     *
+     * @param ticks Number of work units already done
+     */
+    void setTicks(int ticks);
+    int getTicks();
+    /**
+     * Increase number of already done work units by ticks
+     * @param ticks
+     */
+    void worked(int ticks);
+
+    /**
+     * Subtask that will show progress runing back and forworth
+     * @param title Can be null, in that case task title is not changed
+     */
+    void indeterminateSubTask(String title);
+    /**
+     * Normal subtask
+     * @param title Can be null, in that case task title is not changed
+     */
+    void subTask(String title);
+    /**
+     * Shows additonal text
+     */
+    void setCustomText(String text);
+    /**
+     * Show extra text after normal task title. Hack for ProgressInputStream to show number of kB
+     * already downloaded
+     * @param text
+     */
+    void setExtraText(String text);
+
+    /**
+     * Creates subtasks monitor.
+     * @param ticks Number of work units that should be done when subtask finishes
+     * @param internal If true then subtask can't modify task title/custom text
+     * @return
+     */
+    ProgressMonitor createSubTaskMonitor(int ticks, boolean internal);
+
+    boolean isCancelled();
+    void cancel();
+    void addCancelListener(CancelListener listener);
+    void removeCancelListener(CancelListener listener);
+
+    void setSilent(boolean value);
+    void setErrorMessage(String message);
+    String getErrorMessage();
+}

Property changes on: src/org/openstreetmap/josm/gui/progress/ProgressMonitor.java
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Index: src/org/openstreetmap/josm/gui/progress/NullProgressMonitor.java
===================================================================
--- src/org/openstreetmap/josm/gui/progress/NullProgressMonitor.java    (revision 0)
+++ src/org/openstreetmap/josm/gui/progress/NullProgressMonitor.java    (revision 0)
@@ -0,0 +1,76 @@
+// License: GPL. For details, see LICENSE file.
+package org.openstreetmap.josm.gui.progress;
+
+
+public class NullProgressMonitor implements ProgressMonitor {
+
+    public static final ProgressMonitor INSTANCE = new NullProgressMonitor();
+
+    private NullProgressMonitor() {
+
+    }
+
+    public void addCancelListener(CancelListener listener) {
+    }
+
+    public void beginTask(String title) {
+    }
+
+    public void beginTask(String title, int ticks) {
+    }
+
+    public void cancel() {
+    }
+
+    public ProgressMonitor createSubTaskMonitor(int ticks, boolean internal) {
+        return INSTANCE;
+    }
+
+    public void finishTask() {
+    }
+
+    public String getErrorMessage() {
+        return null;
+    }
+
+    public int getTicks() {
+        return 0;
+    }
+
+    public void indeterminateSubTask(String title) {
+    }
+
+    public void invalidate() {
+    }
+
+    public boolean isCancelled() {
+        return false;
+    }
+
+    public void removeCancelListener(CancelListener listener) {
+    }
+
+    public void setCustomText(String text) {
+    }
+
+    public void setErrorMessage(String message) {
+    }
+
+    public void setExtraText(String text) {
+    }
+
+    public void setSilent(boolean value) {
+    }
+
+    public void setTicks(int ticks) {
+    }
+
+    public void setTicksCount(int ticks) {
+    }
+
+    public void subTask(String title) {
+    }
+
+    public void worked(int ticks) {
+    }
+}

Property changes on: src/org/openstreetmap/josm/gui/progress/NullProgressMonitor.java
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Index: src/org/openstreetmap/josm/gui/progress/StackableProgress.java
===================================================================
--- src/org/openstreetmap/josm/gui/progress/StackableProgress.java  (revision 0)
+++ src/org/openstreetmap/josm/gui/progress/StackableProgress.java  (revision 0)
@@ -0,0 +1,7 @@
+// License: GPL. For details, see LICENSE file.
+package org.openstreetmap.josm.gui.progress;
+
+public interface StackableProgress {
+    public void setChildProgress(double value);
+    public void setSubTaskName(String value);
+}

Property changes on: src/org/openstreetmap/josm/gui/progress/StackableProgress.java
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Index: src/org/openstreetmap/josm/gui/progress/CancelHandler.java
===================================================================
--- src/org/openstreetmap/josm/gui/progress/CancelHandler.java  (revision 0)
+++ src/org/openstreetmap/josm/gui/progress/CancelHandler.java  (revision 0)
@@ -0,0 +1,35 @@
+// License: GPL. For details, see LICENSE file.
+package org.openstreetmap.josm.gui.progress;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.openstreetmap.josm.gui.progress.ProgressMonitor.CancelListener;
+
+public class CancelHandler {
+
+    private boolean isCanceled;
+    private List<CancelListener> listeners = new ArrayList<CancelListener>();
+
+    public synchronized void cancel() {
+        if (!isCanceled) {
+            isCanceled = true;
+            for (CancelListener listener:listeners) {
+                listener.operationCanceled();
+            }
+        }
+    }
+
+    public synchronized boolean isCanceled() {
+        return isCanceled;
+    }
+
+    public synchronized void addCancelListener(CancelListener listener) {
+        listeners.add(listener);
+    }
+
+    public synchronized void removeCancelListener(CancelListener listener) {
+        listeners.remove(listener);
+    }
+
+}

Property changes on: src/org/openstreetmap/josm/gui/progress/CancelHandler.java
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Index: src/org/openstreetmap/josm/gui/progress/ChildProgress.java
===================================================================
--- src/org/openstreetmap/josm/gui/progress/ChildProgress.java  (revision 0)
+++ src/org/openstreetmap/josm/gui/progress/ChildProgress.java  (revision 0)
@@ -0,0 +1,54 @@
+// License: GPL. For details, see LICENSE file.
+package org.openstreetmap.josm.gui.progress;
+
+class ChildProgress extends AbstractProgressMonitor {
+
+    private final AbstractProgressMonitor parent;
+    private final boolean internal;
+
+    public ChildProgress(AbstractProgressMonitor parent, CancelHandler cancelHandler, boolean internal) {
+        super(cancelHandler);
+        this.parent = parent;
+        this.internal = internal;
+    }
+
+    @Override
+    void updateProgress(double value) {
+        parent.childSetProgress(this, value);
+    }
+
+    @Override
+    protected void doBeginTask() {
+    }
+
+    @Override
+    protected void doSetCustomText(String title) {
+        if (!internal) {
+            parent.childSetCustomText(this, title);
+        }
+    }
+
+    @Override
+    protected void doSetTitle(String title) {
+        if (!internal) {
+            parent.childSetTitle(this, title);
+        }
+    }
+
+    @Override
+    protected void doSetIntermediate(boolean value) {
+        if (!internal) {
+            parent.childSetIntermediate(this, value);
+        }
+    }
+
+    @Override
+    protected void doSetErrorMessage(String message) {
+        parent.setErrorMessage(message);
+    }
+
+    @Override
+    protected void doFinishTask() {
+        parent.childFinished(this);
+    }
+}

Property changes on: src/org/openstreetmap/josm/gui/progress/ChildProgress.java
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Index: src/org/openstreetmap/josm/gui/dialogs/relation/ReferringRelationsBrowser.java
===================================================================
--- src/org/openstreetmap/josm/gui/dialogs/relation/ReferringRelationsBrowser.java  (revision 1809)
+++ src/org/openstreetmap/josm/gui/dialogs/relation/ReferringRelationsBrowser.java  (working copy)
@@ -4,7 +4,7 @@
 import static org.openstreetmap.josm.tools.I18n.tr;
 
 import java.awt.BorderLayout;
-import java.awt.EventQueue;
+import java.awt.Dialog;
 import java.awt.FlowLayout;
 import java.awt.event.ActionEvent;
 import java.awt.event.MouseAdapter;
@@ -13,7 +13,6 @@
 import java.util.ArrayList;
 
 import javax.swing.AbstractAction;
-import javax.swing.JButton;
 import javax.swing.JCheckBox;
 import javax.swing.JDialog;
 import javax.swing.JLabel;
@@ -36,6 +35,7 @@
 import org.openstreetmap.josm.gui.PleaseWaitRunnable;
 import org.openstreetmap.josm.gui.SideButton;
 import org.openstreetmap.josm.gui.layer.OsmDataLayer;
+import org.openstreetmap.josm.gui.progress.PleaseWaitProgressMonitor;
 import org.openstreetmap.josm.io.OsmApi;
 import org.openstreetmap.josm.io.OsmServerBackreferenceReader;
 import org.openstreetmap.josm.io.OsmTransferException;
@@ -44,7 +44,7 @@
 
 /**
  * This is browser for a list of relations which refer to another relations
- * 
+ *
  *
  */
 public class ReferringRelationsBrowser extends JPanel {
@@ -55,6 +55,7 @@
     private OsmDataLayer layer;
     private JCheckBox cbReadFull;
     private EditAction editAction;
+    private final GenericRelationEditor relationEditor;
 
     /**
      * build the GUI
@@ -82,7 +83,8 @@
         add(pnl, BorderLayout.SOUTH);
     }
 
-    public ReferringRelationsBrowser(OsmDataLayer layer, ReferringRelationsBrowserModel model) {
+    public ReferringRelationsBrowser(OsmDataLayer layer, ReferringRelationsBrowserModel model, GenericRelationEditor relationEditor) {
+        this.relationEditor = relationEditor;
         this.model = model;
         this.layer = layer;
         build();
@@ -110,7 +112,7 @@
 
         public void actionPerformed(ActionEvent e) {
             boolean full = cbReadFull.isSelected();
-            ReloadTask task = new ReloadTask(full);
+            ReloadTask task = new ReloadTask(full, relationEditor);
             Main.worker.submit(task);
         }
 
@@ -129,7 +131,7 @@
 
     /**
      * Action for editing the currently selected relation
-     * 
+     *
      */
     class EditAction extends AbstractAction implements ListSelectionListener {
         public EditAction() {
@@ -180,18 +182,8 @@
         private DataSet referrers;
         private boolean full;
 
-        protected void setIndeterminateEnabled(final boolean enabled) {
-            EventQueue.invokeLater(
-                    new Runnable() {
-                        public void run() {
-                            Main.pleaseWaitDlg.setIndeterminate(enabled);
-                        }
-                    }
-            );
-        }
-
-        public ReloadTask(boolean full) {
-            super(tr("Download referring relations"), false /* don't ignore exception */);
+        public ReloadTask(boolean full, Dialog parent) {
+            super(tr("Download referring relations"), new PleaseWaitProgressMonitor(parent), false /* don't ignore exception */);
             referrers = null;
         }
         @Override
@@ -236,11 +228,9 @@
         @Override
         protected void realRun() throws SAXException, IOException, OsmTransferException {
             try {
-                Main.pleaseWaitDlg.setAlwaysOnTop(true);
-                Main.pleaseWaitDlg.toFront();
-                setIndeterminateEnabled(true);
+                progressMonitor.indeterminateSubTask(null);
                 OsmServerBackreferenceReader reader = new OsmServerBackreferenceReader(model.getRelation(), full);
-                referrers = reader.parseOsm();
+                referrers = reader.parseOsm(progressMonitor.createSubTaskMonitor(1, false));
                 if (referrers != null) {
                     final MergeVisitor visitor = new MergeVisitor(getLayer().data, referrers);
                     visitor.merge();
@@ -269,7 +259,7 @@
                                     visitor.getConflicts().size()),
                                     JOptionPane.WARNING_MESSAGE
                     );
-                    JDialog dialog = op.createDialog(Main.pleaseWaitDlg, tr("Conflicts in data"));
+                    JDialog dialog = op.createDialog(ReferringRelationsBrowser.this, tr("Conflicts in data"));
                     dialog.setAlwaysOnTop(true);
                     dialog.setModal(true);
                     dialog.setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE);
@@ -281,9 +271,6 @@
                     return;
                 }
                 lastException = e;
-            } finally {
-                Main.pleaseWaitDlg.setAlwaysOnTop(false);
-                setIndeterminateEnabled(false);
             }
         }
     }
Index: src/org/openstreetmap/josm/gui/dialogs/relation/GenericRelationEditor.java
===================================================================
--- src/org/openstreetmap/josm/gui/dialogs/relation/GenericRelationEditor.java  (revision 1809)
+++ src/org/openstreetmap/josm/gui/dialogs/relation/GenericRelationEditor.java  (working copy)
@@ -3,8 +3,8 @@
 import static org.openstreetmap.josm.tools.I18n.tr;
 
 import java.awt.BorderLayout;
+import java.awt.Dialog;
 import java.awt.Dimension;
-import java.awt.EventQueue;
 import java.awt.FlowLayout;
 import java.awt.GridBagConstraints;
 import java.awt.GridBagLayout;
@@ -59,6 +59,8 @@
 import org.openstreetmap.josm.gui.dialogs.relation.ac.AutoCompletionCache;
 import org.openstreetmap.josm.gui.dialogs.relation.ac.AutoCompletionList;
 import org.openstreetmap.josm.gui.layer.OsmDataLayer;
+import org.openstreetmap.josm.gui.progress.PleaseWaitProgressMonitor;
+import org.openstreetmap.josm.gui.progress.ProgressMonitor;
 import org.openstreetmap.josm.io.OsmApi;
 import org.openstreetmap.josm.io.OsmServerObjectReader;
 import org.openstreetmap.josm.io.OsmTransferException;
@@ -149,7 +151,7 @@
         JTabbedPane tabbedPane = new JTabbedPane();
         tabbedPane.add(tr("Tags and Members"), pnl);
         if (relation != null && relation.id > 0) {
-            tabbedPane.add(tr("Parent Relations"), new ReferringRelationsBrowser(getLayer(), referrerModel));
+            tabbedPane.add(tr("Parent Relations"), new ReferringRelationsBrowser(getLayer(), referrerModel, this));
         }
 
         getContentPane().add(tabbedPane,BorderLayout.CENTER);
@@ -165,7 +167,7 @@
 
     /**
      * builds the panel with the OK and  the Cancel button
-     * 
+     *
      * @return the panel with the OK and  the Cancel button
      */
     protected JPanel buildOkCancelButtonPanel() {
@@ -180,7 +182,7 @@
 
     /**
      * build the panel with the buttons on the left
-     * 
+     *
      * @return
      */
     protected JPanel buildTagEditorControlPanel() {
@@ -219,7 +221,7 @@
 
     /**
      * builds the panel with the tag editor
-     * 
+     *
      * @return the panel with the tag editor
      */
     protected JPanel buildTagEditorPanel() {
@@ -286,7 +288,7 @@
 
     /**
      * builds the panel for the relation member editor
-     * 
+     *
      * @return the panel for the relation member editor
      */
     protected JPanel buildMemberEditorPanel() {
@@ -384,7 +386,7 @@
 
     /**
      * builds the panel with the table displaying the currently selected primitives
-     * 
+     *
      * @return
      */
     protected JPanel buildSelectionTablePanel() {
@@ -400,7 +402,7 @@
     /**
      * builds the {@see JSplitPane} which divides the editor in an upper and a lower
      * half
-     * 
+     *
      * @return the split panel
      */
     protected JSplitPane buildSplitPane() {
@@ -414,7 +416,7 @@
 
     /**
      * build the panel with the buttons on the left
-     * 
+     *
      * @return
      */
     protected JPanel buildLeftButtonPanel() {
@@ -458,7 +460,7 @@
 
     /**
      * build the panel with the buttons for adding or removing the current selection
-     * 
+     *
      * @return
      */
     protected JPanel buildSelectionControlButtonPanel() {
@@ -575,7 +577,7 @@
                         ),
                         JOptionPane.WARNING_MESSAGE
                 );
-                JDialog dialog = op.createDialog(Main.pleaseWaitDlg, tr("Conflict created"));
+                JDialog dialog = op.createDialog(this, tr("Conflict created"));
                 dialog.setAlwaysOnTop(true);
                 dialog.setModal(true);
                 dialog.setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE);
@@ -603,7 +605,7 @@
     private void downloadRelationMembers() {
         if (!memberTableModel.hasIncompleteMembers())
             return;
-        Main.worker.submit(new DownloadTask());
+        Main.worker.submit(new DownloadTask(this));
     }
 
     @Override
@@ -980,7 +982,7 @@
 
     /**
      * Action for editing the currently selected relation
-     * 
+     *
      *
      */
     class EditAction extends AbstractAction implements ListSelectionListener {
@@ -1013,15 +1015,16 @@
 
     /**
      * The asynchronous task for downloading relation members.
-     * 
+     *
      *
      */
     class DownloadTask extends PleaseWaitRunnable {
         private boolean cancelled;
+        private int conflictsCount;
         private Exception lastException;
 
-        public DownloadTask() {
-            super(tr("Download relation members"), false /* don't ignore exception */);
+        public DownloadTask(Dialog parent) {
+            super(tr("Download relation members"), new PleaseWaitProgressMonitor(parent), false /* don't ignore exception */);
         }
         @Override
         protected void cancel() {
@@ -1046,24 +1049,30 @@
         protected void finish() {
             if (cancelled) return;
             memberTableModel.updateMemberReferences(getLayer().data);
-            if (lastException == null) return;
-            showLastException();
+            if (lastException != null) {
+                showLastException();
+            }
+
+            if (conflictsCount > 0) {
+                JOptionPane op = new JOptionPane(
+                        tr("There were {0} conflicts during import.",
+                                conflictsCount),
+                                JOptionPane.WARNING_MESSAGE
+                );
+                JDialog dialog = op.createDialog(GenericRelationEditor.this, tr("Conflicts in data"));
+                dialog.setAlwaysOnTop(true);
+                dialog.setModal(true);
+                dialog.setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE);
+                dialog.setVisible(true);
+            }
         }
 
         @Override
         protected void realRun() throws SAXException, IOException, OsmTransferException {
             try {
-                SwingUtilities.invokeLater(
-                        new Runnable() {
-                            public void run() {
-                                Main.pleaseWaitDlg.setAlwaysOnTop(true);
-                                Main.pleaseWaitDlg.toFront();
-                                Main.pleaseWaitDlg.setIndeterminate(true);
-                            }
-                        }
-                );
+                progressMonitor.indeterminateSubTask("");
                 OsmServerObjectReader reader = new OsmServerObjectReader(getRelation().id, OsmPrimitiveType.RELATION, true);
-                DataSet dataSet = reader.parseOsm();
+                DataSet dataSet = reader.parseOsm(progressMonitor.createSubTaskMonitor(ProgressMonitor.ALL_TICKS, false));
                 if (dataSet != null) {
                     final MergeVisitor visitor = new MergeVisitor(getLayer().data, dataSet);
                     visitor.merge();
@@ -1083,19 +1092,10 @@
                                 }
                             }
                     );
-                    if (visitor.getConflicts().isEmpty())
-                        return;
-                    getLayer().getConflicts().add(visitor.getConflicts());
-                    JOptionPane op = new JOptionPane(
-                            tr("There were {0} conflicts during import.",
-                                    visitor.getConflicts().size()),
-                                    JOptionPane.WARNING_MESSAGE
-                    );
-                    JDialog dialog = op.createDialog(Main.pleaseWaitDlg, tr("Conflicts in data"));
-                    dialog.setAlwaysOnTop(true);
-                    dialog.setModal(true);
-                    dialog.setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE);
-                    dialog.setVisible(true);
+                    if (!visitor.getConflicts().isEmpty()) {
+                        getLayer().getConflicts().add(visitor.getConflicts());
+                        conflictsCount = visitor.getConflicts().size();
+                    }
                 }
             } catch(Exception e) {
                 if (cancelled) {
@@ -1103,15 +1103,6 @@
                     return;
                 }
                 lastException = e;
-            } finally {
-                SwingUtilities.invokeLater(
-                        new Runnable() {
-                            public void run() {
-                                Main.pleaseWaitDlg.setAlwaysOnTop(false);
-                                Main.pleaseWaitDlg.setIndeterminate(false);
-                            }
-                        }
-                );
             }
         }
     }
Index: src/org/openstreetmap/josm/gui/dialogs/HistoryDialog.java
===================================================================
--- src/org/openstreetmap/josm/gui/dialogs/HistoryDialog.java   (revision 1809)
+++ src/org/openstreetmap/josm/gui/dialogs/HistoryDialog.java   (working copy)
@@ -27,7 +27,6 @@
 import javax.swing.JScrollPane;
 import javax.swing.JTable;
 import javax.swing.ListSelectionModel;
-import javax.swing.SwingUtilities;
 import javax.swing.event.ListSelectionEvent;
 import javax.swing.event.ListSelectionListener;
 import javax.swing.table.DefaultTableCellRenderer;
@@ -86,7 +85,7 @@
     /**
      * unregisters a {@see HistoryBrowserDialog}
      * @param id the id of the primitive whose history dialog is to be unregistered
-     * 
+     *
      */
     public static void unregisterHistoryBrowserDialog(long id) {
         if (historyBrowserDialogs == null)
@@ -97,7 +96,7 @@
     /**
      * replies the history dialog for the primitive with id <code>id</code>; null, if
      * no such {@see HistoryBrowserDialog} is currently showing
-     * 
+     *
      * @param id the id of the primitive
      * @return the dialog; null, if no such dialog is showing
      */
@@ -118,7 +117,7 @@
 
     /**
      * builds the row with the command buttons
-     * 
+     *
      * @return the rows with the command buttons
      */
     protected JPanel buildButtonRow() {
@@ -208,7 +207,7 @@
 
     /**
      * shows the {@see HistoryBrowserDialog} for a given {@see History}
-     * 
+     *
      * @param h the history. Must not be null.
      * @exception IllegalArgumentException thrown, if h is null
      */
@@ -224,7 +223,7 @@
 
     /**
      * invoked after the asynchronous {@see HistoryLoadTask} is finished.
-     * 
+     *
      * @param task the task which is calling back.
      */
     protected void postRefresh(HistoryLoadTask task) {
@@ -260,7 +259,7 @@
 
     /**
      * The table model with the history items
-     * 
+     *
      */
     class HistoryItemDataModel extends DefaultTableModel implements SelectionChangedListener{
         private ArrayList<History> data;
@@ -396,47 +395,10 @@
             postRefresh(this);
         }
 
-        /**
-         * update the title of the {@see PleaseWaitDialog} with information about
-         * which primitive is currently loaded
-         * 
-         * @param primitive the primitive to be loaded
-         */
-        protected void notifyStartLoadingHistory(final OsmPrimitive primitive) {
-            SwingUtilities.invokeLater(
-                    new Runnable() {
-                        public void run() {
-                            Main.pleaseWaitDlg.setTitle(
-                                    tr("Loading history for {0} with id {1}",
-                                            OsmPrimitiveType.from(primitive).getLocalizedDisplayNameSingular(),
-                                            Long.toString(primitive.id)
-                                    )
-                            );
-                        }
-                    }
-            );
-        }
-
-        /**
-         * enables/disables interminate progress indication in the {@see PleaseWaitDialog}
-         * 
-         * @param enabled true, if interminate progress indication is to enabled; false, otherwise
-         */
-        protected void setInterminateEnabled(final boolean enabled) {
-            SwingUtilities.invokeLater(
-                    new Runnable() {
-                        public void run() {
-                            Main.pleaseWaitDlg.setIndeterminate(enabled);
-                        }
-                    }
-            );
-        }
-
         @Override
         protected void realRun() throws SAXException, IOException, OsmTransferException {
             Collection<OsmPrimitive> selection = Main.ds.getSelected();
             Iterator<OsmPrimitive> it = selection.iterator();
-            setInterminateEnabled(true);
             try {
                 while(it.hasNext()) {
                     OsmPrimitive primitive = it.next();
@@ -446,12 +408,14 @@
                     if (primitive.id == 0) {
                         continue;
                     }
-                    notifyStartLoadingHistory(primitive);
+                    progressMonitor.indeterminateSubTask(tr("Loading history for {0} with id {1}",
+                            OsmPrimitiveType.from(primitive).getLocalizedDisplayNameSingular(),
+                            Long.toString(primitive.id)));
                     OsmServerHistoryReader reader = null;
                     HistoryDataSet ds = null;
                     try {
                         reader = new OsmServerHistoryReader(OsmPrimitiveType.from(primitive), primitive.id);
-                        ds = reader.parseHistory();
+                        ds = reader.parseHistory(progressMonitor.createSubTaskMonitor(1, false));
                     } catch(OsmTransferException e) {
                         if (cancelled)
                             return;
@@ -462,8 +426,6 @@
             } catch(OsmTransferException e) {
                 lastException = e;
                 return;
-            } finally {
-                setInterminateEnabled(false);
             }
         }
 
Index: src/org/openstreetmap/josm/gui/layer/GpxLayer.java
===================================================================
--- src/org/openstreetmap/josm/gui/layer/GpxLayer.java  (revision 1809)
+++ src/org/openstreetmap/josm/gui/layer/GpxLayer.java  (working copy)
@@ -50,7 +50,6 @@
 import org.openstreetmap.josm.data.coor.EastNorth;
 import org.openstreetmap.josm.data.coor.LatLon;
 import org.openstreetmap.josm.data.gpx.GpxData;
-import org.openstreetmap.josm.data.gpx.GpxRoute;
 import org.openstreetmap.josm.data.gpx.GpxTrack;
 import org.openstreetmap.josm.data.gpx.WayPoint;
 import org.openstreetmap.josm.data.osm.DataSet;
@@ -62,6 +61,7 @@
 import org.openstreetmap.josm.gui.dialogs.LayerListPopup;
 import org.openstreetmap.josm.gui.layer.markerlayer.AudioMarker;
 import org.openstreetmap.josm.gui.layer.markerlayer.MarkerLayer;
+import org.openstreetmap.josm.gui.progress.PleaseWaitProgressMonitor;
 import org.openstreetmap.josm.tools.AudioUtil;
 import org.openstreetmap.josm.tools.DateUtils;
 import org.openstreetmap.josm.tools.DontShowAgainInfo;
@@ -841,7 +841,7 @@
                     JOptionPane.OK_CANCEL_OPTION) == JOptionPane.CANCEL_OPTION)
                 return;
 
-            new DownloadOsmTaskList().download(false, toDownload);
+            new DownloadOsmTaskList().download(false, toDownload, new PleaseWaitProgressMonitor());
         }
     }
 
Index: src/org/openstreetmap/josm/gui/layer/GeoImageLayer.java
===================================================================
--- src/org/openstreetmap/josm/gui/layer/GeoImageLayer.java (revision 1809)
+++ src/org/openstreetmap/josm/gui/layer/GeoImageLayer.java (working copy)
@@ -269,7 +269,6 @@
     }
 
     private static final class Loader extends PleaseWaitRunnable {
-        boolean cancelled = false;
         private GeoImageLayer layer;
         private final Collection<File> files;
         private final GpxLayer gpxLayer;
@@ -279,7 +278,7 @@
             this.gpxLayer = gpxLayer;
         }
         @Override protected void realRun() throws IOException {
-            Main.pleaseWaitDlg.currentAction.setText(tr("Read GPX..."));
+            progressMonitor.subTask(tr("Read GPX..."));
             LinkedList<TimedPoint> gps = new LinkedList<TimedPoint>();
 
             // Extract dates and locations from GPX input
@@ -302,19 +301,17 @@
             }
 
             if (gps.isEmpty()) {
-                errorMessage = tr("No images with readable timestamps found.");
+                progressMonitor.setErrorMessage(tr("No images with readable timestamps found."));
                 return;
             }
 
             // read the image files
             ArrayList<ImageEntry> data = new ArrayList<ImageEntry>(files.size());
-            int i = 0;
-            Main.pleaseWaitDlg.progress.setMaximum(files.size());
+            progressMonitor.setTicksCount(files.size());
             for (File f : files) {
-                if (cancelled)
+                if (progressMonitor.isCancelled())
                     break;
-                Main.pleaseWaitDlg.currentAction.setText(tr("Reading {0}...",f.getName()));
-                Main.pleaseWaitDlg.progress.setValue(i++);
+                progressMonitor.subTask(tr("Reading {0}...",f.getName()));
 
                 ImageEntry e = new ImageEntry(f);
                 try {
@@ -326,6 +323,7 @@
                     continue;
 
                 data.add(e);
+                progressMonitor.worked(1);
             }
             layer = new GeoImageLayer(data, gps);
             layer.calculatePosition();
@@ -334,7 +332,10 @@
             if (layer != null)
                 Main.main.addLayer(layer);
         }
-        @Override protected void cancel() {cancelled = true;}
+        @Override
+        protected void cancel() {
+
+        }
     }
 
     public ArrayList<ImageEntry> data;
