diff --git a/src/main/java/org/openstreetmap/josm/plugins/rapid/backend/RapiDAction.java b/src/main/java/org/openstreetmap/josm/plugins/rapid/backend/RapiDAction.java index 2713a43..e159ab7 100644 --- a/src/main/java/org/openstreetmap/josm/plugins/rapid/backend/RapiDAction.java +++ b/src/main/java/org/openstreetmap/josm/plugins/rapid/backend/RapiDAction.java @@ -22,8 +22,7 @@ public class RapiDAction extends JosmAction { @Override public void actionPerformed(ActionEvent event) { - final RapiDLayer layer = RapiDDataUtils.getLayer(true); - RapiDDataUtils.getRapiDData(layer); + RapiDDataUtils.getRapiDData(RapiDDataUtils.getLayer(true)); } @Override diff --git a/src/main/java/org/openstreetmap/josm/plugins/rapid/backend/RapiDArbitraryAction.java b/src/main/java/org/openstreetmap/josm/plugins/rapid/backend/RapiDArbitraryAction.java index 29628d2..1eb81d1 100644 --- a/src/main/java/org/openstreetmap/josm/plugins/rapid/backend/RapiDArbitraryAction.java +++ b/src/main/java/org/openstreetmap/josm/plugins/rapid/backend/RapiDArbitraryAction.java @@ -20,7 +20,6 @@ import org.openstreetmap.josm.actions.JosmAction; import org.openstreetmap.josm.data.Bounds; import org.openstreetmap.josm.data.coor.LatLon; import org.openstreetmap.josm.data.osm.BBox; -import org.openstreetmap.josm.data.osm.DataSet; import org.openstreetmap.josm.gui.ExtendedDialog; import org.openstreetmap.josm.gui.MainApplication; import org.openstreetmap.josm.gui.MapView; @@ -129,17 +128,7 @@ public class RapiDArbitraryAction extends JosmAction { DetectTaskingManagerUtils.createTaskingManagerGpxData(bbox), DetectTaskingManagerUtils.RAPID_CROP_AREA)); } - final DataSet data = RapiDDataUtils.getData(bbox); - final RapiDLayer layer = RapiDDataUtils.getLayer(true); - final DataSet rapidData = layer.getDataSet(); - boolean locked = rapidData.isLocked(); - if (locked) { - rapidData.unlock(); - } - rapidData.mergeFrom(data); - if (locked) { - rapidData.lock(); - } + RapiDDataUtils.getRapiDData(RapiDDataUtils.getLayer(true), bbox); } private void setBounds(Bounds b) { diff --git a/src/main/java/org/openstreetmap/josm/plugins/rapid/backend/RapiDDataUtils.java b/src/main/java/org/openstreetmap/josm/plugins/rapid/backend/RapiDDataUtils.java index c8f35ef..90948d5 100644 --- a/src/main/java/org/openstreetmap/josm/plugins/rapid/backend/RapiDDataUtils.java +++ b/src/main/java/org/openstreetmap/josm/plugins/rapid/backend/RapiDDataUtils.java @@ -11,8 +11,9 @@ import java.util.Arrays; import java.util.Collection; import java.util.List; import java.util.TreeSet; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.Future; +import java.util.concurrent.ForkJoinPool; +import java.util.concurrent.TimeUnit; +import java.util.stream.Collectors; import org.openstreetmap.josm.data.Bounds; import org.openstreetmap.josm.data.coor.LatLon; @@ -29,6 +30,7 @@ import org.openstreetmap.josm.data.preferences.sources.SourceEntry; import org.openstreetmap.josm.data.preferences.sources.SourceType; import org.openstreetmap.josm.gui.MainApplication; import org.openstreetmap.josm.gui.layer.OsmDataLayer; +import org.openstreetmap.josm.gui.progress.swing.PleaseWaitProgressMonitor; import org.openstreetmap.josm.io.IllegalDataException; import org.openstreetmap.josm.io.OsmReader; import org.openstreetmap.josm.plugins.rapid.RapiDPlugin; @@ -81,20 +83,23 @@ public final class RapiDDataUtils { public static DataSet getData(BBox bbox) { final DataSet dataSet = new DataSet(); if (bbox.isValid()) { - final List> futures = new ArrayList<>(); - for (final BBox tbbox : reduceBBoxSize(bbox)) { - futures.add(MainApplication.worker.submit(new GetDataRunnable(tbbox, dataSet))); + final PleaseWaitProgressMonitor monitor = new PleaseWaitProgressMonitor(); + monitor.setCancelable(Boolean.FALSE); + final List bboxes = reduceBBoxSize(bbox); + monitor.beginTask(tr("Downloading {0} data", RapiDPlugin.NAME), bboxes.size()); + final ForkJoinPool pool = new ForkJoinPool(); + for (final BBox tbbox : bboxes) { + pool.submit(new GetDataRunnable(tbbox, dataSet, monitor)); } - for (final Future future : futures) { - try { - future.get(); - } catch (final InterruptedException e) { - Logging.debug(e); - Thread.currentThread().interrupt(); - } catch (ExecutionException e) { - Logging.debug(e); - } + pool.shutdown(); + try { + pool.awaitTermination(10, TimeUnit.SECONDS); + } catch (InterruptedException e) { + Logging.debug(e); + Thread.currentThread().interrupt(); } + monitor.finishTask(); + monitor.close(); } /* Microsoft buildings don't have a source, so we add one */ @@ -105,10 +110,12 @@ public final class RapiDDataUtils { private static class GetDataRunnable implements Runnable { private final BBox bbox; private final DataSet dataSet; + private final PleaseWaitProgressMonitor monitor; - public GetDataRunnable(BBox bbox, DataSet dataSet) { + public GetDataRunnable(BBox bbox, DataSet dataSet, PleaseWaitProgressMonitor monitor) { this.bbox = bbox; this.dataSet = dataSet; + this.monitor = monitor; } @Override @@ -117,6 +124,7 @@ public final class RapiDDataUtils { synchronized (RapiDDataUtils.GetDataRunnable.class) { getDataSet().mergeFrom(temporaryDataSet); } + monitor.worked(1); } /** @@ -420,6 +428,55 @@ public final class RapiDDataUtils { return topLeft.greatCircleDistance(bottomLeft); } + /** + * Get the data for RapiD + * + * @param layer A pre-existing {@link RapiDLayer} + * @param bboxes The bboxes to get the data in + */ + public static void getRapiDData(RapiDLayer layer, Collection bboxes) { + final DataSet rapidSet = layer.getDataSet(); + final List rapidBounds = rapidSet.getDataSourceBounds().stream().map(Bounds::toBBox).collect(Collectors.toList()); + final List editSetBBoxes = bboxes.stream() + .filter(bbox -> rapidBounds.stream().noneMatch(tBBox -> tBBox.bounds(bbox))) + .collect(Collectors.toList()); + final ForkJoinPool pool = new ForkJoinPool(); + for (final BBox bbox : editSetBBoxes) { + // TODO remove bounds that are already downloaded + if (rapidBounds.parallelStream().filter(bbox::bounds).count() == 0) { + pool.execute(() -> { + final DataSet newData = getData(bbox); + synchronized (LAYER_LOCK) { + layer.unlock(); + try { + layer.mergeFrom(newData); + } finally { + layer.lock(); + } + } + }); + } + } + pool.shutdown(); + try { + pool.awaitTermination(10, TimeUnit.SECONDS); + } catch (InterruptedException e) { + Logging.debug(e); + Thread.currentThread().interrupt(); + } + + } + + /** + * Get the data for RapiD + * + * @param layer A pre-existing {@link RapiDLayer} + * @param bboxes The bboxes to get the data in + */ + public static void getRapiDData(RapiDLayer layer, BBox... bboxes) { + getRapiDData(layer, Arrays.asList(bboxes)); + } + /** * Get the data for RapiD * @@ -427,21 +484,8 @@ public final class RapiDDataUtils { * @param osmLayer The osm datalayer with a set of bounds */ public static void getRapiDData(RapiDLayer layer, OsmDataLayer osmLayer) { - final DataSet editSet = osmLayer.getDataSet(); - final List editSetBounds = editSet.getDataSourceBounds(); - final DataSet rapidSet = layer.getDataSet(); - final List rapidBounds = rapidSet.getDataSourceBounds(); - for (final Bounds bound : editSetBounds) { - // TODO remove bounds that are already downloaded - if (rapidBounds.parallelStream().filter(bound::equals).count() == 0) { - final DataSet newData = getData(bound.toBBox()); - synchronized (LAYER_LOCK) { - layer.unlock(); - layer.mergeFrom(newData); - layer.lock(); - } - } - } + getRapiDData(layer, + osmLayer.getDataSet().getDataSourceBounds().stream().map(Bounds::toBBox).collect(Collectors.toList())); } /** diff --git a/src/main/java/org/openstreetmap/josm/plugins/rapid/backend/RapiDRemoteControl.java b/src/main/java/org/openstreetmap/josm/plugins/rapid/backend/RapiDRemoteControl.java index d43f11d..6779178 100644 --- a/src/main/java/org/openstreetmap/josm/plugins/rapid/backend/RapiDRemoteControl.java +++ b/src/main/java/org/openstreetmap/josm/plugins/rapid/backend/RapiDRemoteControl.java @@ -93,16 +93,12 @@ public class RapiDRemoteControl extends RequestHandler.RawURLParseRequestHandler } if (download != null && download.isInWorld()) { - layer.getDataSet().unlock(); - layer.getDataSet().mergeFrom(RapiDDataUtils.getData(download)); - layer.getDataSet().lock(); + RapiDDataUtils.getRapiDData(layer, download); } else if (MainApplication.getLayerManager().getLayersOfType(OsmDataLayer.class).stream() - .filter(tLayer -> !(tLayer instanceof RapiDLayer)).count() != 0) { + .anyMatch(tLayer -> !(tLayer instanceof RapiDLayer))) { RapiDDataUtils.getRapiDData(layer); } else if (crop != null && crop.isInWorld()) { - layer.getDataSet().unlock(); - layer.getDataSet().mergeFrom(RapiDDataUtils.getData(crop)); - layer.getDataSet().lock(); + RapiDDataUtils.getRapiDData(layer, crop); } } diff --git a/src/main/java/org/openstreetmap/josm/plugins/rapid/commands/RapiDAddCommand.java b/src/main/java/org/openstreetmap/josm/plugins/rapid/commands/RapiDAddCommand.java index f93b294..15a29e5 100644 --- a/src/main/java/org/openstreetmap/josm/plugins/rapid/commands/RapiDAddCommand.java +++ b/src/main/java/org/openstreetmap/josm/plugins/rapid/commands/RapiDAddCommand.java @@ -69,20 +69,22 @@ public class RapiDAddCommand extends Command implements Runnable { } synchronized (this) { final boolean locked = rapid.isLocked(); - if (locked) { - rapid.unlock(); - } - final Command movePrimitivesCommand = new MovePrimitiveDataSetCommand(editable, rapid, primitives); - final List allPrimitives = new ArrayList<>(); - RapiDDataUtils.addPrimitivesToCollection(allPrimitives, primitives); - final Command createConnectionsCommand = createConnections(editable, allPrimitives); - if (command == null) { // needed for undo/redo (don't create a new command) - command = new SequenceCommand(getDescriptionText(), movePrimitivesCommand, createConnectionsCommand); - } - command.executeCommand(); - - if (locked) { - rapid.lock(); + try { + if (locked) { + rapid.unlock(); + } + final Command movePrimitivesCommand = new MovePrimitiveDataSetCommand(editable, rapid, primitives); + final List allPrimitives = new ArrayList<>(); + RapiDDataUtils.addPrimitivesToCollection(allPrimitives, primitives); + final Command createConnectionsCommand = createConnections(editable, allPrimitives); + if (command == null) { // needed for undo/redo (don't create a new command) + command = new SequenceCommand(getDescriptionText(), movePrimitivesCommand, createConnectionsCommand); + } + command.executeCommand(); + } finally { + if (locked) { + rapid.lock(); + } } } } @@ -102,16 +104,19 @@ public class RapiDAddCommand extends Command implements Runnable { @Override public void undoCommand() { final boolean locked = rapid.isLocked(); - if (locked) { - rapid.unlock(); - } - synchronized (this) { - if (command != null) { - command.undoCommand(); + try { + if (locked) { + rapid.unlock(); + } + synchronized (this) { + if (command != null) { + command.undoCommand(); + } + } + } finally { + if (locked) { + rapid.lock(); } - } - if (locked) { - rapid.lock(); } }