diff --git a/src/main/java/org/openstreetmap/josm/plugins/rapid/RapiDPlugin.java b/src/main/java/org/openstreetmap/josm/plugins/rapid/RapiDPlugin.java index a58b5dd..b048d90 100644 --- a/src/main/java/org/openstreetmap/josm/plugins/rapid/RapiDPlugin.java +++ b/src/main/java/org/openstreetmap/josm/plugins/rapid/RapiDPlugin.java @@ -9,6 +9,7 @@ import org.openstreetmap.josm.gui.preferences.PreferenceSetting; import org.openstreetmap.josm.plugins.Plugin; import org.openstreetmap.josm.plugins.PluginInformation; import org.openstreetmap.josm.plugins.rapid.backend.RapiDAction; +import org.openstreetmap.josm.plugins.rapid.backend.RapiDArbitraryAction; import org.openstreetmap.josm.plugins.rapid.backend.RapiDDataUtils; import org.openstreetmap.josm.plugins.rapid.backend.RapiDMoveAction; @@ -27,6 +28,7 @@ public final class RapiDPlugin extends Plugin { final JMenu dataMenu = MainApplication.getMenu().dataMenu; MainMenu.add(dataMenu, new RapiDAction(), false); MainMenu.add(dataMenu, new RapiDMoveAction(), false); + MainMenu.add(dataMenu, new RapiDArbitraryAction(), true); RapiDDataUtils.addRapiDPaintStyles(); 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 c98595e..ac54f12 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 @@ -1,3 +1,4 @@ +// License: GPL. For details, see LICENSE file. package org.openstreetmap.josm.plugins.rapid.backend; import static org.openstreetmap.josm.tools.I18n.tr; 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 new file mode 100644 index 0000000..6a46a48 --- /dev/null +++ b/src/main/java/org/openstreetmap/josm/plugins/rapid/backend/RapiDArbitraryAction.java @@ -0,0 +1,155 @@ +// License: GPL. For details, see LICENSE file. +package org.openstreetmap.josm.plugins.rapid.backend; + +import static org.openstreetmap.josm.gui.help.HelpUtil.ht; +import static org.openstreetmap.josm.tools.I18n.tr; + +import java.awt.BorderLayout; +import java.awt.GridBagLayout; +import java.awt.event.ActionEvent; +import java.awt.event.KeyEvent; +import java.util.Optional; + +import javax.swing.JCheckBox; +import javax.swing.JLabel; +import javax.swing.JOptionPane; +import javax.swing.JPanel; + +import org.openstreetmap.josm.actions.JosmAction; +import org.openstreetmap.josm.data.Bounds; +import org.openstreetmap.josm.data.coor.LatLon; +import org.openstreetmap.josm.data.gpx.GpxData; +import org.openstreetmap.josm.data.gpx.WayPoint; +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; +import org.openstreetmap.josm.gui.datatransfer.ClipboardUtils; +import org.openstreetmap.josm.gui.layer.GpxLayer; +import org.openstreetmap.josm.gui.widgets.JosmTextField; +import org.openstreetmap.josm.gui.widgets.SelectAllOnFocusGainedDecorator; +import org.openstreetmap.josm.plugins.rapid.RapiDPlugin; +import org.openstreetmap.josm.spi.preferences.Config; +import org.openstreetmap.josm.tools.GBC; +import org.openstreetmap.josm.tools.OsmUrlToBounds; +import org.openstreetmap.josm.tools.Shortcut; + +/** + * @author Taylor Smock + */ +public class RapiDArbitraryAction extends JosmAction { + private static final long serialVersionUID = 9048113038651190619L; + + private final JosmTextField lowerLat = new JosmTextField(); + private final JosmTextField upperLat = new JosmTextField(); + private final JosmTextField leftLon = new JosmTextField(); + private final JosmTextField rightLon = new JosmTextField(); + private final JCheckBox checkbox = new JCheckBox(); + + public RapiDArbitraryAction() { + super(RapiDPlugin.NAME, null, tr("Get arbitrary data from RapiD"), Shortcut.registerShortcut("data:rapid", + tr("Data: Arbitrary {0} Data", tr("Get arbitrary data from RapiD")), KeyEvent.VK_R, + Shortcut.ALT_CTRL_SHIFT), true); + } + + @Override + public void actionPerformed(ActionEvent e) { + showDownloadDialog(); + } + + static class RapiDArbitraryDialog extends ExtendedDialog { + private static final long serialVersionUID = 2795301151521238635L; + + RapiDArbitraryDialog(String[] buttons, JPanel panel) { + super(MainApplication.getMainFrame(), tr("Get arbitrary data from RapiD"), buttons); + setButtonIcons("ok", "cancel"); + configureContextsensitiveHelp(ht("/Action/DownloadArbitraryRapiDData"), true); + setContent(panel); + setCancelButton(2); + } + } + + public void showDownloadDialog() { + final Optional boundsFromClipboard = Optional.ofNullable(ClipboardUtils.getClipboardStringContent()) + .map(OsmUrlToBounds::parse); + if (boundsFromClipboard.isPresent() && Config.getPref().getBoolean("jumpto.use.clipboard", true)) { + setBounds(boundsFromClipboard.get()); + } else if (MainApplication.isDisplayingMapView()) { + final MapView mv = MainApplication.getMap().mapView; + setBounds(mv.getState().getViewArea().getCornerBounds()); + } + + final JPanel panel = new JPanel(new BorderLayout()); + panel.add(new JLabel("" + tr("Enter Lat/Lon to download RapiD data.") + "
" + ""), + BorderLayout.NORTH); + + SelectAllOnFocusGainedDecorator.decorate(lowerLat); + SelectAllOnFocusGainedDecorator.decorate(leftLon); + + final JPanel p = new JPanel(new GridBagLayout()); + panel.add(p, BorderLayout.NORTH); + + p.add(new JLabel(tr("Lower Latitude")), GBC.eol()); + p.add(lowerLat, GBC.eol().fill(GBC.HORIZONTAL)); + + p.add(new JLabel(tr("Left Longitude")), GBC.eol()); + p.add(leftLon, GBC.eol().fill(GBC.HORIZONTAL)); + p.add(new JLabel(tr("Upper Latitude")), GBC.eol()); + p.add(upperLat, GBC.eol().fill(GBC.HORIZONTAL)); + p.add(new JLabel(tr("Right Longitude")), GBC.eol()); + p.add(rightLon, GBC.eol().fill(GBC.HORIZONTAL)); + + p.add(new JLabel(tr("Crop to bbox?"))); + p.add(checkbox, GBC.eol()); + + final String[] buttons = { tr("Download"), tr("Cancel") }; + BBox bbox = new BBox(); + while (!bbox.isInWorld()) { + final int option = new RapiDArbitraryDialog(buttons, panel).showDialog().getValue(); + if (option != 1) { + return; + } + try { + bbox = new BBox(); + bbox.add(new LatLon(Double.parseDouble(lowerLat.getText()), Double.parseDouble(leftLon.getText()))); + bbox.add(new LatLon(Double.parseDouble(upperLat.getText()), Double.parseDouble(rightLon.getText()))); + } catch (NumberFormatException e) { + JOptionPane.showMessageDialog(MainApplication.getMainFrame(), + tr("Could not parse Latitude or Longitude. Please check."), tr("Unable to parse Lon/Lat"), + JOptionPane.ERROR_MESSAGE); + bbox = new BBox(); + } + } + + if (checkbox.isSelected()) { + final GpxData data = new GpxData(); + data.addWaypoint(new WayPoint(bbox.getBottomRight())); + data.addWaypoint(new WayPoint(bbox.getTopLeft())); + MainApplication.getLayerManager().addLayer(new GpxLayer(data, tr("{0}: Crop Area", RapiDPlugin.NAME))); + } + + final DataSet data = RapiDDataUtils.getData(bbox); + final RapiDLayer layer = RapiDAction.getLayer(true); + final DataSet rapidData = layer.getDataSet(); + boolean locked = rapidData.isLocked(); + if (locked) { + rapidData.unlock(); + } + rapidData.mergeFrom(data); + if (locked) { + rapidData.lock(); + } + } + + private void setBounds(Bounds b) { + if (b != null) { + final LatLon min = b.getMin(); + final LatLon max = b.getMax(); + lowerLat.setText(Double.toString(min.lat())); + leftLon.setText(Double.toString(min.lon())); + rightLon.setText(Double.toString(max.lon())); + upperLat.setText(Double.toString(max.lat())); + } + } +} 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 3a7ecc2..17b3718 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,6 +11,7 @@ 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 org.openstreetmap.josm.data.coor.LatLon; @@ -19,6 +20,7 @@ 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.Relation; +import org.openstreetmap.josm.data.osm.UploadPolicy; import org.openstreetmap.josm.data.osm.Way; import org.openstreetmap.josm.data.preferences.sources.ExtendedSourceEntry; import org.openstreetmap.josm.data.preferences.sources.MapPaintPrefHelper; @@ -61,14 +63,12 @@ public final class RapiDDataUtils { } for (final Future future : futures) { try { - int count = 0; - while (!future.isDone() && !future.isCancelled() && count < 100) { - Thread.sleep(100); - count++; - } + future.get(); } catch (final InterruptedException e) { Logging.debug(e); Thread.currentThread().interrupt(); + } catch (ExecutionException e) { + Logging.debug(e); } } } @@ -109,9 +109,16 @@ public final class RapiDDataUtils { private static DataSet getDataReal(BBox bbox) { InputStream inputStream = null; final DataSet dataSet = new DataSet(); - final String urlString = getRapiDURL(); + String urlString = getRapiDURL(); + if (DetectTaskingManager.hasTaskingManagerLayer()) { + urlString += "&crop_bbox={crop_bbox}"; + } + + dataSet.setUploadPolicy(UploadPolicy.DISCOURAGED); + try { - final URL url = new URL(urlString.replace("{bbox}", bbox.toStringCSV(","))); + final URL url = new URL(urlString.replace("{bbox}", bbox.toStringCSV(",")).replace("{crop_bbox}", + DetectTaskingManager.getTaskingManagerBBox().toStringCSV(","))); final HttpClient client = HttpClient.create(url); final StringBuilder defaultUserAgent = new StringBuilder(); defaultUserAgent.append(client.getHeaders().get("User-Agent")); @@ -123,7 +130,8 @@ public final class RapiDDataUtils { Logging.debug("{0}: Getting {1}", RapiDPlugin.NAME, client.getURL().toString()); final Response response = client.connect(); inputStream = response.getContent(); - dataSet.mergeFrom(OsmReader.parseDataSet(inputStream, null)); + final DataSet mergeData = OsmReader.parseDataSet(inputStream, null); + dataSet.mergeFrom(mergeData); response.disconnect(); } catch (UnsupportedOperationException | IllegalDataException | IOException e) { Logging.debug(e); @@ -135,6 +143,7 @@ public final class RapiDDataUtils { Logging.debug(e); } } + dataSet.setUploadPolicy(UploadPolicy.BLOCKED); } return dataSet; } diff --git a/test/unit/org/openstreetmap/josm/plugins/rapid/backend/RapiDDataUtilsTest.java b/test/unit/org/openstreetmap/josm/plugins/rapid/backend/RapiDDataUtilsTest.java index a7889aa..a2e5e1d 100644 --- a/test/unit/org/openstreetmap/josm/plugins/rapid/backend/RapiDDataUtilsTest.java +++ b/test/unit/org/openstreetmap/josm/plugins/rapid/backend/RapiDDataUtilsTest.java @@ -12,6 +12,8 @@ import org.junit.Rule; import org.junit.Test; import org.openstreetmap.josm.TestUtils; import org.openstreetmap.josm.data.coor.LatLon; +import org.openstreetmap.josm.data.gpx.GpxData; +import org.openstreetmap.josm.data.gpx.WayPoint; import org.openstreetmap.josm.data.osm.BBox; import org.openstreetmap.josm.data.osm.DataSet; import org.openstreetmap.josm.data.osm.Node; @@ -19,11 +21,13 @@ import org.openstreetmap.josm.data.osm.OsmPrimitive; import org.openstreetmap.josm.data.osm.Way; import org.openstreetmap.josm.data.preferences.sources.MapPaintPrefHelper; import org.openstreetmap.josm.data.preferences.sources.SourceEntry; +import org.openstreetmap.josm.gui.MainApplication; +import org.openstreetmap.josm.gui.layer.GpxLayer; import org.openstreetmap.josm.testutils.JOSMTestRules; public class RapiDDataUtilsTest { @Rule - public JOSMTestRules test = new JOSMTestRules().preferences(); + public JOSMTestRules test = new JOSMTestRules().preferences().main().projection(); /** * This gets data from RapiD. This test may fail if someone adds the data to @@ -36,6 +40,23 @@ public class RapiDDataUtilsTest { Assert.assertEquals(1, ds.getWays().size()); } + /** + * This gets data from RapiD. This test may fail if someone adds the data to + * OSM. + */ + @Test + public void testGetDataCropped() { + final BBox testBBox = getTestBBox(); + GpxData gpxData = new GpxData(); + gpxData.addWaypoint(new WayPoint(new LatLon(39.0738798, -108.5709922))); + gpxData.addWaypoint(new WayPoint(new LatLon(39.0732914, -108.5707436))); + GpxLayer gpx = new GpxLayer(gpxData); + MainApplication.getLayerManager().addLayer(gpx); + final DataSet ds = new DataSet(RapiDDataUtils.getData(testBBox)); + Assert.assertEquals(1, ds.getWays().size()); + Assert.assertEquals(2, ds.getNodes().size()); + } + @Test public void testAddSourceTags() { final Way way1 = TestUtils.newWay("highway=residential", new Node(new LatLon(0, 0)), @@ -50,8 +71,8 @@ public class RapiDDataUtilsTest { public static BBox getTestBBox() { final BBox testBBox = new BBox(); - testBBox.add(new LatLon(39.076, -108.547)); - testBBox.add(new LatLon(39.078, -108.545)); + testBBox.add(new LatLon(39.0734162, -108.5707107)); + testBBox.add(new LatLon(39.0738791, -108.5715723)); return testBBox; }