Index: /trunk/src/org/openstreetmap/josm/gui/layer/GpxLayer.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/gui/layer/GpxLayer.java	(revision 4322)
+++ /trunk/src/org/openstreetmap/josm/gui/layer/GpxLayer.java	(revision 4323)
@@ -65,4 +65,5 @@
 import org.openstreetmap.josm.gui.MapView;
 import org.openstreetmap.josm.gui.NavigatableComponent;
+import org.openstreetmap.josm.gui.PleaseWaitRunnable;
 import org.openstreetmap.josm.gui.dialogs.LayerListDialog;
 import org.openstreetmap.josm.gui.dialogs.LayerListPopup;
@@ -72,4 +73,5 @@
 import org.openstreetmap.josm.gui.progress.NullProgressMonitor;
 import org.openstreetmap.josm.gui.progress.PleaseWaitProgressMonitor;
+import org.openstreetmap.josm.gui.progress.ProgressMonitor;
 import org.openstreetmap.josm.gui.widgets.HtmlPanel;
 import org.openstreetmap.josm.io.JpgImporter;
@@ -828,4 +830,10 @@
      */
     public class DownloadAlongTrackAction extends AbstractAction {
+        final static int NEAR_TRACK=0;
+        final static int NEAR_WAYPOINTS=1;
+        final static int NEAR_BOTH=2;
+        final Integer dist[] = { 5000, 500, 50 };
+        final Integer area[] = { 20, 10, 5, 1 };
+
         public DownloadAlongTrackAction() {
             super(tr("Download from OSM along this track"), ImageProvider.get("downloadalongtrack"));
@@ -834,7 +842,8 @@
         @Override
         public void actionPerformed(ActionEvent e) {
+            /*
+             * build selection dialog
+             */
             JPanel msg = new JPanel(new GridBagLayout());
-            Integer dist[] = { 5000, 500, 50 };
-            Integer area[] = { 20, 10, 5, 1 };
 
             msg.add(new JLabel(tr("Download everything within:")), GBC.eol());
@@ -858,7 +867,4 @@
             msg.add(new JLabel(tr("Download near:")), GBC.eol());
             JList downloadNear = new JList(new String[] { tr("track only"), tr("waypoints only"), tr("track and waypoints") });
-            int NEAR_TRACK=0;
-            int NEAR_WAYPOINTS=1;
-            int NEAR_BOTH=2;
 
             downloadNear.setSelectedIndex(Main.pref.getInteger(PREF_DOWNLOAD_ALONG_TRACK_NEAR, 0));
@@ -882,5 +888,5 @@
             Main.pref.putInteger(PREF_DOWNLOAD_ALONG_TRACK_DISTANCE, buffer.getSelectedIndex());
             Main.pref.putInteger(PREF_DOWNLOAD_ALONG_TRACK_AREA, maxRect.getSelectedIndex());
-            int near = downloadNear.getSelectedIndex();
+            final int near = downloadNear.getSelectedIndex();
             Main.pref.putInteger(PREF_DOWNLOAD_ALONG_TRACK_NEAR, near);
 
@@ -920,35 +926,54 @@
              */
             Integer i = buffer.getSelectedIndex();
-            int buffer_dist = dist[i < 0 ? 0 : i];
-            double buffer_y = buffer_dist / 100000.0;
-            double buffer_x = buffer_y / scale;
+            final int buffer_dist = dist[i < 0 ? 0 : i];
             i = maxRect.getSelectedIndex();
-            double max_area = area[i < 0 ? 0 : i] / 10000.0 / scale;
-            Area a = new Area();
-            Rectangle2D r = new Rectangle2D.Double();
-
-            /*
-             * Collect the combined area of all gpx points plus buffer zones around them. We ignore
-             * points that lie closer to the previous point than the given buffer size because
-             * otherwise this operation takes ages.
-             */
-            LatLon previous = null;
-            if (near == NEAR_TRACK || near == NEAR_BOTH) {
-                for (GpxTrack trk : data.tracks) {
-                    for (GpxTrackSegment segment : trk.getSegments()) {
-                        for (WayPoint p : segment.getWayPoints()) {
-                            LatLon c = p.getCoor();
-                            if (previous == null || c.greatCircleDistance(previous) > buffer_dist) {
-                                // we add a buffer around the point.
-                                r.setRect(c.lon() - buffer_x, c.lat() - buffer_y, 2 * buffer_x, 2 * buffer_y);
-                                a.add(new Area(r));
-                                previous = c;
-                            }
-                        }
-                    }
-                }
-            }
-            if (near == NEAR_WAYPOINTS || near == NEAR_BOTH) {
-                for (WayPoint p : data.waypoints) {
+            final double max_area = area[i < 0 ? 0 : i] / 10000.0 / scale;
+            final double buffer_y = buffer_dist / 100000.0;
+            final double buffer_x = buffer_y / scale;
+
+            final int totalTicks = latcnt;
+            // guess if a progress bar might be useful.
+            final boolean displayProgress = totalTicks > 2000 && buffer_y < 0.01;
+
+            class CalculateDownloadArea extends PleaseWaitRunnable {
+                private Area a = new Area();
+                private boolean cancel = false;
+                private int ticks = 0;
+                private Rectangle2D r = new Rectangle2D.Double();
+
+                public CalculateDownloadArea() {
+                    super(tr("Calculating Download Area"),
+                            (displayProgress ? null : NullProgressMonitor.INSTANCE),
+                            false);
+                }
+
+                @Override
+                protected void cancel() {
+                    cancel = true;
+                }
+
+                @Override
+                protected void finish() {
+                    if(cancel)
+                        return;
+                    confirmAndDownloadAreas(a, max_area, progressMonitor);
+                }
+
+                /**
+                 * increase tick count by one, report progress every 100 ticks
+                 */
+                private void tick() {
+                    ticks++;
+                    if(ticks % 100 == 0) {
+                        progressMonitor.worked(100);
+                    }
+                }
+
+                /**
+                 * calculate area for single, given way point and return new LatLon if the
+                 * way point has been used to modify the area.
+                 */
+                private LatLon calcAreaForWayPoint(WayPoint p, LatLon previous) {
+                    tick();
                     LatLon c = p.getCoor();
                     if (previous == null || c.greatCircleDistance(previous) > buffer_dist) {
@@ -956,29 +981,68 @@
                         r.setRect(c.lon() - buffer_x, c.lat() - buffer_y, 2 * buffer_x, 2 * buffer_y);
                         a.add(new Area(r));
-                        previous = c;
-                    }
-                }
-            }
-
-            /*
-             * Area "a" now contains the hull that we would like to download data for. however we
-             * can only download rectangles, so the following is an attempt at finding a number of
-             * rectangles to download.
-             *
-             * The idea is simply: Start out with the full bounding box. If it is too large, then
-             * split it in half and repeat recursively for each half until you arrive at something
-             * small enough to download. The algorithm is improved by always using the intersection
-             * between the rectangle and the actual desired area. For example, if you have a track
-             * that goes like this: +----+ | /| | / | | / | |/ | +----+ then we would first look at
-             * downloading the whole rectangle (assume it's too big), after that we split it in half
-             * (upper and lower half), but we donot request the full upper and lower rectangle, only
-             * the part of the upper/lower rectangle that actually has something in it.
-             */
-
+                        return c;
+                    }
+                    return previous;
+                }
+
+                @Override
+                protected void realRun() {
+                    progressMonitor.setTicksCount(totalTicks);
+                    /*
+                     * Collect the combined area of all gpx points plus buffer zones around them. We ignore
+                     * points that lie closer to the previous point than the given buffer size because
+                     * otherwise this operation takes ages.
+                     */
+                    LatLon previous = null;
+                    if (near == NEAR_TRACK || near == NEAR_BOTH) {
+                        for (GpxTrack trk : data.tracks) {
+                            for (GpxTrackSegment segment : trk.getSegments()) {
+                                for (WayPoint p : segment.getWayPoints()) {
+                                    if(cancel)
+                                        return;
+                                    previous = calcAreaForWayPoint(p, previous);
+                                }
+                            }
+                        }
+                    }
+                    if (near == NEAR_WAYPOINTS || near == NEAR_BOTH) {
+                        for (WayPoint p : data.waypoints) {
+                            if(cancel)
+                                return;
+                            previous = calcAreaForWayPoint(p, previous);
+                        }
+                    }
+                }
+            }
+
+            Main.worker.submit(new CalculateDownloadArea());
+        }
+
+        /**
+         * Area "a" contains the hull that we would like to download data for. however we
+         * can only download rectangles, so the following is an attempt at finding a number of
+         * rectangles to download.
+         *
+         * The idea is simply: Start out with the full bounding box. If it is too large, then
+         * split it in half and repeat recursively for each half until you arrive at something
+         * small enough to download. The algorithm is improved by always using the intersection
+         * between the rectangle and the actual desired area. For example, if you have a track
+         * that goes like this: +----+ | /| | / | | / | |/ | +----+ then we would first look at
+         * downloading the whole rectangle (assume it's too big), after that we split it in half
+         * (upper and lower half), but we donot request the full upper and lower rectangle, only
+         * the part of the upper/lower rectangle that actually has something in it.
+         *
+         * This functions calculates the rectangles, asks the user to continue and downloads
+         * the areas if applicable.
+         */
+        private void confirmAndDownloadAreas(Area a, double max_area, ProgressMonitor progressMonitor) {
             List<Rectangle2D> toDownload = new ArrayList<Rectangle2D>();
 
             addToDownload(a, a.getBounds(), toDownload, max_area);
 
-            msg = new JPanel(new GridBagLayout());
+            if(toDownload.size() == 0)
+                return;
+
+            JPanel msg = new JPanel(new GridBagLayout());
 
             msg.add(new JLabel(
@@ -988,5 +1052,11 @@
 
             if (toDownload.size() > 1) {
-                ret = JOptionPane.showConfirmDialog(
+                // hide progress dialog before displaying another pop up. Really closing the
+                // dialog will be handled by PleaseWaitRunnable.
+                if (progressMonitor instanceof PleaseWaitProgressMonitor) {
+                    ((PleaseWaitProgressMonitor) progressMonitor).getDialog().setVisible(false);
+                }
+
+                int ret = JOptionPane.showConfirmDialog(
                         Main.parent,
                         msg,
