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 cf9adb2..eaa571c 100644 --- a/src/main/java/org/openstreetmap/josm/plugins/rapid/RapiDPlugin.java +++ b/src/main/java/org/openstreetmap/josm/plugins/rapid/RapiDPlugin.java @@ -2,21 +2,26 @@ package org.openstreetmap.josm.plugins.rapid; import java.awt.Component; +import java.lang.reflect.InvocationTargetException; import java.util.LinkedHashMap; +import java.util.Map; import java.util.Map.Entry; import javax.swing.JMenu; +import javax.swing.JMenuItem; import org.openstreetmap.josm.actions.JosmAction; import org.openstreetmap.josm.gui.MainApplication; import org.openstreetmap.josm.gui.MainMenu; import org.openstreetmap.josm.gui.preferences.PreferenceSetting; +import org.openstreetmap.josm.io.remotecontrol.RequestProcessor; 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; +import org.openstreetmap.josm.plugins.rapid.backend.RapiDRemoteControl; import org.openstreetmap.josm.tools.Logging; public final class RapiDPlugin extends Plugin { @@ -26,11 +31,11 @@ public final class RapiDPlugin extends Plugin { private final PreferenceSetting preferenceSetting; - private static final LinkedHashMap, Boolean> MENU_ENTRIES = new LinkedHashMap<>(); + private static final Map, Boolean> MENU_ENTRIES = new LinkedHashMap<>(); static { MENU_ENTRIES.put(RapiDAction.class, false); - MENU_ENTRIES.put(RapiDMoveAction.class, false); MENU_ENTRIES.put(RapiDArbitraryAction.class, true); + MENU_ENTRIES.put(RapiDMoveAction.class, false); } public RapiDPlugin(PluginInformation info) { @@ -39,18 +44,20 @@ public final class RapiDPlugin extends Plugin { preferenceSetting = new RapiDPreferences(); final JMenu dataMenu = MainApplication.getMenu().dataMenu; - for (Entry, Boolean> entry : MENU_ENTRIES.entrySet()) { + for (final Entry, Boolean> entry : MENU_ENTRIES.entrySet()) { boolean alreadyAdded = false; - for (Component component : dataMenu.getMenuComponents()) { - if (entry.getKey().equals(component.getClass())) { + for (final Component component : dataMenu.getMenuComponents()) { + if (component instanceof JMenuItem + && entry.getKey().equals(((JMenuItem) component).getAction().getClass())) { alreadyAdded = true; break; } } if (!alreadyAdded) { try { - MainMenu.add(dataMenu, entry.getKey().newInstance(), entry.getValue()); - } catch (InstantiationException | IllegalAccessException e) { + MainMenu.add(dataMenu, entry.getKey().getDeclaredConstructor().newInstance(), entry.getValue()); + } catch (InstantiationException | IllegalAccessException | IllegalArgumentException + | InvocationTargetException | NoSuchMethodException | SecurityException e) { Logging.debug(e); } } @@ -59,6 +66,7 @@ public final class RapiDPlugin extends Plugin { RapiDDataUtils.addRapiDPaintStyles(); setVersionInfo(info.localversion); + RequestProcessor.addRequestHandlerClass("mapwithai", RapiDRemoteControl.class); } @Override diff --git a/src/main/java/org/openstreetmap/josm/plugins/rapid/RapiDPreferences.java b/src/main/java/org/openstreetmap/josm/plugins/rapid/RapiDPreferences.java index e6e7285..e6d98bf 100644 --- a/src/main/java/org/openstreetmap/josm/plugins/rapid/RapiDPreferences.java +++ b/src/main/java/org/openstreetmap/josm/plugins/rapid/RapiDPreferences.java @@ -85,11 +85,11 @@ public class RapiDPreferences implements SubPreferenceSetting { @Override public boolean ok() { - RapiDDataUtils.setRapiDUrl((String) possibleRapidApiUrl.getSelectedItem()); - RapiDDataUtils.setSwitchLayers(switchLayerCheckBox.isSelected()); + RapiDDataUtils.setRapiDUrl((String) possibleRapidApiUrl.getSelectedItem(), true); + RapiDDataUtils.setSwitchLayers(switchLayerCheckBox.isSelected(), true); final Object value = maximumAdditionSpinner.getValue(); if (value instanceof Number) { - RapiDDataUtils.setMaximumAddition(((Number) value).intValue()); + RapiDDataUtils.setMaximumAddition(((Number) value).intValue(), true); } return false; } diff --git a/src/main/java/org/openstreetmap/josm/plugins/rapid/backend/DetectTaskingManager.java b/src/main/java/org/openstreetmap/josm/plugins/rapid/backend/DetectTaskingManagerUtils.java similarity index 72% rename from src/main/java/org/openstreetmap/josm/plugins/rapid/backend/DetectTaskingManager.java rename to src/main/java/org/openstreetmap/josm/plugins/rapid/backend/DetectTaskingManagerUtils.java index aae9cd2..5d3a084 100644 --- a/src/main/java/org/openstreetmap/josm/plugins/rapid/backend/DetectTaskingManager.java +++ b/src/main/java/org/openstreetmap/josm/plugins/rapid/backend/DetectTaskingManagerUtils.java @@ -23,15 +23,15 @@ import org.openstreetmap.josm.plugins.rapid.RapiDPlugin; * @author Taylor Smock * */ -public class DetectTaskingManager { +public final class DetectTaskingManagerUtils { public static final String RAPID_CROP_AREA = tr("{0}: Crop Area", RapiDPlugin.NAME); - public static final List patterns = new ArrayList<>(); + private static final List PATTERNS = new ArrayList<>(); static { - patterns.add(Pattern.compile("^Task Boundaries.*$")); - patterns.add(Pattern.compile("^" + RAPID_CROP_AREA + "$")); + PATTERNS.add(Pattern.compile("^Task Boundaries.*$")); + PATTERNS.add(Pattern.compile("^" + RAPID_CROP_AREA + "$")); } - private DetectTaskingManager() { + private DetectTaskingManagerUtils() { // Hide since this is going to be a static class } @@ -44,13 +44,13 @@ public class DetectTaskingManager { /** * @return A {@link Layer} that matches a pattern defined in - * {@link DetectTaskingManager#patterns} or {@code null}. + * {@link DetectTaskingManagerUtils#PATTERNS} or {@code null}. */ public static Layer getTaskingManagerLayer() { Layer returnLayer = null; - List layers = MainApplication.getLayerManager().getLayers(); - for (Pattern pattern : patterns) { - Optional layer = layers.parallelStream() + final List layers = MainApplication.getLayerManager().getLayers(); + for (final Pattern pattern : PATTERNS) { + final Optional layer = layers.parallelStream() .filter(tlayer -> pattern.matcher(tlayer.getName()).matches()) .findFirst(); if (layer.isPresent()) { @@ -66,19 +66,23 @@ public class DetectTaskingManager { * valid. */ public static BBox getTaskingManagerBBox() { - BBox returnBBox = new BBox(); - Layer layer = getTaskingManagerLayer(); + final BBox returnBBox = new BBox(); + final Layer layer = getTaskingManagerLayer(); if (layer instanceof GpxLayer) { - GpxLayer gpxLayer = (GpxLayer) layer; - Bounds realBounds = gpxLayer.data.recalculateBounds(); + final GpxLayer gpxLayer = (GpxLayer) layer; + final Bounds realBounds = gpxLayer.data.recalculateBounds(); returnBBox.add(realBounds.toBBox()); } return returnBBox; } + /** + * @param bbox A bbox to crop data to + * @return A gpx layer that can be used to crop data from MapWithAI + */ public static GpxData createTaskingManagerGpxData(BBox bbox) { final GpxData data = new GpxData(); - GpxRoute route = new GpxRoute(); + final GpxRoute route = new GpxRoute(); route.routePoints.add(new WayPoint(bbox.getBottomRight())); route.routePoints.add(new WayPoint(new LatLon(bbox.getBottomRightLat(), bbox.getTopLeftLon()))); route.routePoints.add(new WayPoint(bbox.getTopLeft())); 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 2f9c298..2713a43 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 @@ -5,13 +5,8 @@ import static org.openstreetmap.josm.tools.I18n.tr; import java.awt.event.ActionEvent; import java.awt.event.KeyEvent; -import java.util.List; import org.openstreetmap.josm.actions.JosmAction; -import org.openstreetmap.josm.data.Bounds; -import org.openstreetmap.josm.data.osm.DataSet; -import org.openstreetmap.josm.gui.MainApplication; -import org.openstreetmap.josm.gui.layer.OsmDataLayer; import org.openstreetmap.josm.plugins.rapid.RapiDPlugin; import org.openstreetmap.josm.tools.Shortcut; @@ -19,8 +14,6 @@ public class RapiDAction extends JosmAction { /** UID */ private static final long serialVersionUID = 8886705479253246588L; - private static final Object LAYER_LOCK = new Object(); - public RapiDAction() { super(tr("{0}: Download data", RapiDPlugin.NAME), null, tr("Get data from RapiD"), Shortcut.registerShortcut("data:rapid", tr("Data: {0}", tr("RapiD")), KeyEvent.VK_R, Shortcut.SHIFT), @@ -29,67 +22,8 @@ public class RapiDAction extends JosmAction { @Override public void actionPerformed(ActionEvent event) { - final RapiDLayer layer = getLayer(true); - getRapiDData(layer); - } - - /** - * Get the first {@link RapiDLayer} that we can find. - * - * @param create true if we want to create a new layer - * @return A RapiDLayer, or a new RapiDLayer if none exist. May return - * {@code null} if {@code create} is {@code false}. - */ - public static RapiDLayer getLayer(boolean create) { - final List rapidLayers = MainApplication.getLayerManager().getLayersOfType(RapiDLayer.class); - RapiDLayer layer = null; - synchronized (LAYER_LOCK) { - if (rapidLayers.isEmpty() && create) { - layer = new RapiDLayer(new DataSet(), RapiDPlugin.NAME, null); - MainApplication.getLayerManager().addLayer(layer); - } else if (!rapidLayers.isEmpty()) { - layer = rapidLayers.get(0); - } - } - return layer; - } - - /** - * Get data for a {@link RapiDLayer} - * - * @param layer The {@link RapiDLayer} to add data to - */ - public static void getRapiDData(RapiDLayer layer) { - final List osmLayers = MainApplication.getLayerManager().getLayersOfType(OsmDataLayer.class); - for (final OsmDataLayer osmLayer : osmLayers) { - if (!osmLayer.isLocked()) { - getRapiDData(layer, osmLayer); - } - } - } - - /** - * Get the data for RapiD - * - * @param layer A pre-existing {@link RapiDLayer} - * @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 = RapiDDataUtils.getData(bound.toBBox()); - synchronized (LAYER_LOCK) { - layer.unlock(); - layer.mergeFrom(newData); - layer.lock(); - } - } - } + final RapiDLayer layer = RapiDDataUtils.getLayer(true); + RapiDDataUtils.getRapiDData(layer); } @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 e979032..29628d2 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 @@ -5,6 +5,7 @@ import static org.openstreetmap.josm.gui.help.HelpUtil.ht; import static org.openstreetmap.josm.tools.I18n.tr; import java.awt.BorderLayout; +import java.awt.GridBagConstraints; import java.awt.GridBagLayout; import java.awt.event.ActionEvent; import java.awt.event.KeyEvent; @@ -18,8 +19,6 @@ 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; @@ -47,10 +46,12 @@ public class RapiDArbitraryAction extends JosmAction { private final JosmTextField rightLon = new JosmTextField(); private final JCheckBox checkbox = new JCheckBox(); + private static final String ARBITRARY_DATA_STRING = "Get arbitrary data from RapiD"; + public RapiDArbitraryAction() { - super(tr("{0}: Download arbitrary data", RapiDPlugin.NAME), null, tr("Get arbitrary data from RapiD"), + super(tr("{0}: Download arbitrary data", RapiDPlugin.NAME), null, tr(ARBITRARY_DATA_STRING), Shortcut.registerShortcut("data:arbitraryrapid", - tr("Data: Arbitrary {0} Data", tr("Get arbitrary data from RapiD")), KeyEvent.VK_R, + tr("Data: Arbitrary {0} Data", tr(ARBITRARY_DATA_STRING)), KeyEvent.VK_R, Shortcut.ALT_CTRL_SHIFT), true); } @@ -63,7 +64,7 @@ public class RapiDArbitraryAction extends JosmAction { private static final long serialVersionUID = 2795301151521238635L; RapiDArbitraryDialog(String[] buttons, JPanel panel) { - super(MainApplication.getMainFrame(), tr("Get arbitrary data from RapiD"), buttons); + super(MainApplication.getMainFrame(), tr(ARBITRARY_DATA_STRING), buttons); setButtonIcons("ok", "cancel"); configureContextsensitiveHelp(ht("/Action/DownloadArbitraryRapiDData"), true); setContent(panel); @@ -92,14 +93,14 @@ public class RapiDArbitraryAction extends JosmAction { panel.add(p, BorderLayout.NORTH); p.add(new JLabel(tr("Lower Latitude")), GBC.eol()); - p.add(lowerLat, GBC.eol().fill(GBC.HORIZONTAL)); + p.add(lowerLat, GBC.eol().fill(GridBagConstraints.HORIZONTAL)); p.add(new JLabel(tr("Left Longitude")), GBC.eol()); - p.add(leftLon, GBC.eol().fill(GBC.HORIZONTAL)); + p.add(leftLon, GBC.eol().fill(GridBagConstraints.HORIZONTAL)); p.add(new JLabel(tr("Upper Latitude")), GBC.eol()); - p.add(upperLat, GBC.eol().fill(GBC.HORIZONTAL)); + p.add(upperLat, GBC.eol().fill(GridBagConstraints.HORIZONTAL)); p.add(new JLabel(tr("Right Longitude")), GBC.eol()); - p.add(rightLon, GBC.eol().fill(GBC.HORIZONTAL)); + p.add(rightLon, GBC.eol().fill(GridBagConstraints.HORIZONTAL)); p.add(new JLabel(tr("Crop to bbox?"))); p.add(checkbox, GBC.eol()); @@ -125,11 +126,11 @@ public class RapiDArbitraryAction extends JosmAction { if (checkbox.isSelected()) { MainApplication.getLayerManager().addLayer(new GpxLayer( - DetectTaskingManager.createTaskingManagerGpxData(bbox), DetectTaskingManager.RAPID_CROP_AREA)); + DetectTaskingManagerUtils.createTaskingManagerGpxData(bbox), DetectTaskingManagerUtils.RAPID_CROP_AREA)); } final DataSet data = RapiDDataUtils.getData(bbox); - final RapiDLayer layer = RapiDAction.getLayer(true); + final RapiDLayer layer = RapiDDataUtils.getLayer(true); final DataSet rapidData = layer.getDataSet(); boolean locked = rapidData.isLocked(); if (locked) { 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 04c60e5..10745f2 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 @@ -14,6 +14,7 @@ import java.util.TreeSet; import java.util.concurrent.ExecutionException; import java.util.concurrent.Future; +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; @@ -27,6 +28,7 @@ import org.openstreetmap.josm.data.preferences.sources.MapPaintPrefHelper; 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.io.IllegalDataException; import org.openstreetmap.josm.io.OsmReader; import org.openstreetmap.josm.plugins.rapid.RapiDPlugin; @@ -43,10 +45,33 @@ public final class RapiDDataUtils { public static final String DEFAULT_RAPID_API = "https://www.facebook.com/maps/ml_roads?conflate_with_osm=true&theme=ml_road_vector&collaborator=josm&token=ASb3N5o9HbX8QWn8G_NtHIRQaYv3nuG2r7_f3vnGld3KhZNCxg57IsaQyssIaEw5rfRNsPpMwg4TsnrSJtIJms5m&hash=ASawRla3rBcwEjY4HIY&result_type=road_building_vector_xml&bbox={bbox}"; public static final int MAXIMUM_SIDE_DIMENSIONS = 1000; // 1 km + static final Object LAYER_LOCK = new Object(); + private RapiDDataUtils() { // Hide the constructor } + /** + * Get the first {@link RapiDLayer} that we can find. + * + * @param create true if we want to create a new layer + * @return A RapiDLayer, or a new RapiDLayer if none exist. May return + * {@code null} if {@code create} is {@code false}. + */ + public static RapiDLayer getLayer(boolean create) { + final List rapidLayers = MainApplication.getLayerManager().getLayersOfType(RapiDLayer.class); + RapiDLayer layer = null; + synchronized (LAYER_LOCK) { + if (rapidLayers.isEmpty() && create) { + layer = new RapiDLayer(new DataSet(), RapiDPlugin.NAME, null); + MainApplication.getLayerManager().addLayer(layer); + } else if (!rapidLayers.isEmpty()) { + layer = rapidLayers.get(0); + } + } + return layer; + } + /** * Get a dataset from the API servers using a bbox * @@ -112,7 +137,7 @@ public final class RapiDDataUtils { InputStream inputStream = null; final DataSet dataSet = new DataSet(); String urlString = getRapiDURL(); - if (DetectTaskingManager.hasTaskingManagerLayer()) { + if (DetectTaskingManagerUtils.hasTaskingManagerLayer()) { urlString += "&crop_bbox={crop_bbox}"; } @@ -120,7 +145,7 @@ public final class RapiDDataUtils { try { final URL url = new URL(urlString.replace("{bbox}", bbox.toStringCSV(",")).replace("{crop_bbox}", - DetectTaskingManager.getTaskingManagerBBox().toStringCSV(","))); + DetectTaskingManagerUtils.getTaskingManagerBBox().toStringCSV(","))); final HttpClient client = HttpClient.create(url); final StringBuilder defaultUserAgent = new StringBuilder(); defaultUserAgent.append(client.getHeaders().get("User-Agent")); @@ -216,11 +241,16 @@ public final class RapiDDataUtils { * @return A RapiD url */ public static String getRapiDURL() { - final List urls = getRapiDURLs(); + final RapiDLayer layer = getLayer(false); String url = Config.getPref().get(RapiDPlugin.NAME.concat(".current_api"), DEFAULT_RAPID_API); - if (!urls.contains(url)) { - url = DEFAULT_RAPID_API; - setRapiDUrl(DEFAULT_RAPID_API); + if (layer != null && layer.getRapiDUrl() != null) { + url = layer.getRapiDUrl(); + } else { + final List urls = getRapiDURLs(); + if (!urls.contains(url)) { + url = DEFAULT_RAPID_API; + setRapiDUrl(DEFAULT_RAPID_API, true); + } } return url; } @@ -228,15 +258,22 @@ public final class RapiDDataUtils { /** * Set the RapiD url * - * @param url The url to set as the default + * @param url The url to set as the default + * @param permanent {@code true} if we want the setting to persist between + * sessions */ - public static void setRapiDUrl(String url) { - final List urls = getRapiDURLs(); - if (!urls.contains(url)) { - urls.add(url); - setRapiDURLs(urls); + public static void setRapiDUrl(String url, boolean permanent) { + final RapiDLayer layer = getLayer(false); + if (permanent) { + final List urls = getRapiDURLs(); + if (!urls.contains(url)) { + urls.add(url); + setRapiDURLs(urls); + } + Config.getPref().put(RapiDPlugin.NAME.concat(".current_api"), url); + } else if (layer != null) { + layer.setRapiDUrl(url); } - Config.getPref().put(RapiDPlugin.NAME.concat(".current_api"), url); } /** @@ -278,17 +315,29 @@ public final class RapiDDataUtils { /** * Set whether or not a we switch from the RapiD layer to an OSM data layer * - * @param selected true if we are going to switch layers + * @param selected true if we are going to switch layers + * @param permanent {@code true} if we want the setting to persist between + * sessions */ - public static void setSwitchLayers(boolean selected) { - Config.getPref().putBoolean(RapiDPlugin.NAME.concat(".autoswitchlayers"), selected); + public static void setSwitchLayers(boolean selected, boolean permanent) { + final RapiDLayer layer = getLayer(false); + if (permanent) { + Config.getPref().putBoolean(RapiDPlugin.NAME.concat(".autoswitchlayers"), selected); + } else if (layer != null) { + layer.setSwitchLayers(selected); + } } /** * @return {@code true} if we want to automatically switch layers */ public static boolean isSwitchLayers() { - return Config.getPref().getBoolean(RapiDPlugin.NAME.concat(".autoswitchlayers"), true); + final RapiDLayer layer = getLayer(false); + boolean returnBoolean = Config.getPref().getBoolean(RapiDPlugin.NAME.concat(".autoswitchlayers"), true); + if (layer != null && layer.isSwitchLayers() != null) { + returnBoolean = layer.isSwitchLayers(); + } + return returnBoolean; } /** @@ -297,17 +346,29 @@ public final class RapiDDataUtils { * @return The maximum selection. If 0, allow any number. */ public static int getMaximumAddition() { - return Config.getPref().getInt(RapiDPlugin.NAME.concat(".maximumselection"), 50); + final RapiDLayer rapidLayer = RapiDDataUtils.getLayer(false); + Integer defaultReturn = Config.getPref().getInt(RapiDPlugin.NAME.concat(".maximumselection"), 50); + if (rapidLayer != null && rapidLayer.getMaximumAddition() != null) { + defaultReturn = rapidLayer.getMaximumAddition(); + } + return defaultReturn; } /** * Set the maximum number of objects that can be added at one time. * - * @param max The maximum number of objects to select (0 allows any number to be - * selected). + * @param max The maximum number of objects to select (0 allows any number + * to be selected). + * @param permanent {@code true} if we want the setting to persist between + * sessions */ - public static void setMaximumAddition(int max) { - Config.getPref().putInt(RapiDPlugin.NAME.concat(".maximumselection"), max); + public static void setMaximumAddition(int max, boolean permanent) { + final RapiDLayer rapidLayer = getLayer(false); + if (permanent) { + Config.getPref().putInt(RapiDPlugin.NAME.concat(".maximumselection"), max); + } else if (rapidLayer != null) { + rapidLayer.setMaximumAddition(max); + } } public static List reduceBBoxSize(BBox bbox) { @@ -358,4 +419,42 @@ public final class RapiDDataUtils { // TODO handle poles return topLeft.greatCircleDistance(bottomLeft); } + + /** + * Get the data for RapiD + * + * @param layer A pre-existing {@link RapiDLayer} + * @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(); + } + } + } + } + + /** + * Get data for a {@link RapiDLayer} + * + * @param layer The {@link RapiDLayer} to add data to + */ + public static void getRapiDData(RapiDLayer layer) { + final List osmLayers = MainApplication.getLayerManager().getLayersOfType(OsmDataLayer.class); + for (final OsmDataLayer osmLayer : osmLayers) { + if (!osmLayer.isLocked()) { + getRapiDData(layer, osmLayer); + } + } + } } diff --git a/src/main/java/org/openstreetmap/josm/plugins/rapid/backend/RapiDLayer.java b/src/main/java/org/openstreetmap/josm/plugins/rapid/backend/RapiDLayer.java index d0df617..3f0cc4f 100644 --- a/src/main/java/org/openstreetmap/josm/plugins/rapid/backend/RapiDLayer.java +++ b/src/main/java/org/openstreetmap/josm/plugins/rapid/backend/RapiDLayer.java @@ -1,21 +1,30 @@ // License: GPL. For details, see LICENSE file. package org.openstreetmap.josm.plugins.rapid.backend; +import static org.openstreetmap.josm.tools.I18n.tr; + import java.io.File; +import javax.swing.JLabel; +import javax.swing.JPanel; + import org.openstreetmap.josm.data.osm.DataSet; import org.openstreetmap.josm.data.osm.UploadPolicy; import org.openstreetmap.josm.gui.layer.OsmDataLayer; +import org.openstreetmap.josm.tools.GBC; /** * @author Taylor Smock * */ public class RapiDLayer extends OsmDataLayer { + private Integer maximumAddition = null; + private String url = null; + private Boolean switchLayers = null; /** * Create a new RapiD layer - * + * * @param data OSM data from rapid * @param name Layer name * @param associatedFile an associated file (can be null) @@ -30,4 +39,48 @@ public class RapiDLayer extends OsmDataLayer { public String getChangesetSourceTag() { return "MapWithAI"; } + + public void setMaximumAddition(Integer max) { + maximumAddition = max; + } + + public Integer getMaximumAddition() { + return maximumAddition; + } + + public void setRapiDUrl(String url) { + this.url = url; + } + + public String getRapiDUrl() { + return url; + } + + public void setSwitchLayers(boolean selected) { + switchLayers = selected; + } + + public Boolean isSwitchLayers() { + return switchLayers; + } + + @Override + public Object getInfoComponent() { + final Object p = super.getInfoComponent(); + if (p instanceof JPanel) { + final JPanel panel = (JPanel) p; + if (maximumAddition != null) { + panel.add(new JLabel(tr("Maximum Additions: {0}", maximumAddition), JLabel.HORIZONTAL), + GBC.eop().insets(15, 0, 0, 0)); + } + if (url != null) { + panel.add(new JLabel(tr("URL: {0}", url), JLabel.HORIZONTAL), GBC.eop().insets(15, 0, 0, 0)); + } + if (switchLayers != null) { + panel.add(new JLabel(tr("Switch Layers: {0}", switchLayers), JLabel.HORIZONTAL), + GBC.eop().insets(15, 0, 0, 0)); + } + } + return p; + } } 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 new file mode 100644 index 0000000..d43f11d --- /dev/null +++ b/src/main/java/org/openstreetmap/josm/plugins/rapid/backend/RapiDRemoteControl.java @@ -0,0 +1,154 @@ +// License: GPL. For details, see LICENSE file. +package org.openstreetmap.josm.plugins.rapid.backend; + +import static org.openstreetmap.josm.tools.I18n.tr; + +import java.net.MalformedURLException; +import java.net.URL; + +import org.openstreetmap.josm.data.osm.BBox; +import org.openstreetmap.josm.gui.MainApplication; +import org.openstreetmap.josm.gui.layer.GpxLayer; +import org.openstreetmap.josm.gui.layer.OsmDataLayer; +import org.openstreetmap.josm.io.remotecontrol.PermissionPrefWithDefault; +import org.openstreetmap.josm.io.remotecontrol.handler.RequestHandler; +import org.openstreetmap.josm.plugins.rapid.RapiDPlugin; + +public class RapiDRemoteControl extends RequestHandler.RawURLParseRequestHandler { + + private BBox download = null; + private BBox crop = null; + private Integer maxObj = null; + private Boolean switchLayer = null; + private String url = null; + + private static final String MAX_OBJ = "max_obj"; + private static final String SWITCH_LAYER = "switch_layer"; + + public RapiDRemoteControl() { + super(); + } + + @Override + protected void validateRequest() throws RequestHandlerBadRequestException { + if (args != null) { + try { + if (args.containsKey("bbox")) { + download = parseBBox(args.get("bbox")); + } + if (args.containsKey("crop_bbox")) { + crop = parseBBox(args.get("crop_bbox")); + } + if (args.containsKey(MAX_OBJ)) { + maxObj = Integer.parseInt(args.get(MAX_OBJ)); + } + if (args.containsKey("url")) { + final String urlString = args.get("url"); + // Ensure the URL is valid + url = new URL(urlString).toString(); + } + if (args.containsKey(SWITCH_LAYER)) { + switchLayer = Boolean.parseBoolean(args.get(SWITCH_LAYER)); + } + } catch (NumberFormatException e) { + throw new RequestHandlerBadRequestException("NumberFormatException (" + e.getMessage() + ')', e); + } catch (MalformedURLException e) { + throw new RequestHandlerBadRequestException("MalformedURLException: " + e.getMessage(), e); + } + } + } + + private static BBox parseBBox(String coordinates) throws RequestHandlerBadRequestException { + final String[] coords = coordinates.split(",", -1); + final BBox tBBox = new BBox(); + if (coords.length >= 4 && coords.length % 2 == 0) { + for (int i = 0; i < coords.length / 2; i++) { + tBBox.add(Double.parseDouble(coords[2 * i]), Double.parseDouble(coords[2 * i + 1])); + } + } + if (!tBBox.isInWorld()) { + throw new RequestHandlerBadRequestException( + tr("Bad bbox: {0} (converted to {1})", coordinates, tBBox.toString())); + } + return tBBox; + } + + @Override + protected void handleRequest() throws RequestHandlerErrorException, RequestHandlerBadRequestException { + if (crop != null && crop.isInWorld()) { + MainApplication.getLayerManager().addLayer(new GpxLayer( + DetectTaskingManagerUtils.createTaskingManagerGpxData(crop), DetectTaskingManagerUtils.RAPID_CROP_AREA)); + } + + final RapiDLayer layer = RapiDDataUtils.getLayer(true); + + if (maxObj != null) { + RapiDDataUtils.setMaximumAddition(maxObj, false); + } + if (url != null) { + RapiDDataUtils.setRapiDUrl(url, false); + } + if (switchLayer != null) { + RapiDDataUtils.setSwitchLayers(switchLayer, false); + } + + if (download != null && download.isInWorld()) { + layer.getDataSet().unlock(); + layer.getDataSet().mergeFrom(RapiDDataUtils.getData(download)); + layer.getDataSet().lock(); + } else if (MainApplication.getLayerManager().getLayersOfType(OsmDataLayer.class).stream() + .filter(tLayer -> !(tLayer instanceof RapiDLayer)).count() != 0) { + RapiDDataUtils.getRapiDData(layer); + } else if (crop != null && crop.isInWorld()) { + layer.getDataSet().unlock(); + layer.getDataSet().mergeFrom(RapiDDataUtils.getData(crop)); + layer.getDataSet().lock(); + } + } + + @Override + public String getPermissionMessage() { + final String br = "
"; + final StringBuilder sb = new StringBuilder(); + sb.append(tr("Remote Control has been asked to load data from the API.")); + sb.append(" ("); + sb.append(url); + sb.append(")"); + sb.append(br); + sb.append(tr("{0} will ", RapiDPlugin.NAME)); + if (!switchLayer) { + sb.append(tr("not ")); + } + sb.append(tr("automatically switch layers.")); + sb.append(br); + if (download != null) { + sb.append(tr("We will download data in ")); + sb.append(download.toStringCSV(",")); + sb.append(br); + } + if (crop != null) { + sb.append(tr("We will crop the data to")); + sb.append(crop.toStringCSV(",")); + sb.append(br); + } + sb.append(tr("There is a maximum addition of {0} objects at one time", maxObj)); + return sb.toString(); + + } + + @Override + public PermissionPrefWithDefault getPermissionPref() { + return null; + } + + @Override + public String[] getMandatoryParams() { + return new String[] {}; + } + + @Override + public String[] getOptionalParams() { + return new String[] { "bbox", "url", MAX_OBJ, SWITCH_LAYER, "crop_bbox" }; + } + +} diff --git a/src/main/java/org/openstreetmap/josm/plugins/rapid/commands/AddPrimitivesCommand.java b/src/main/java/org/openstreetmap/josm/plugins/rapid/commands/AddPrimitivesCommand.java deleted file mode 100644 index 4b3923b..0000000 --- a/src/main/java/org/openstreetmap/josm/plugins/rapid/commands/AddPrimitivesCommand.java +++ /dev/null @@ -1,126 +0,0 @@ -// License: GPL. For details, see LICENSE file. -package org.openstreetmap.josm.plugins.rapid.commands; - -import static org.openstreetmap.josm.tools.I18n.tr; - -import java.lang.reflect.InvocationTargetException; -import java.util.ArrayList; -import java.util.Collection; -import java.util.stream.Collectors; - -import javax.swing.SwingUtilities; - -import org.openstreetmap.josm.command.Command; -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.Way; -import org.openstreetmap.josm.tools.Logging; -import org.openstreetmap.josm.tools.Utils; - -public class AddPrimitivesCommand extends Command { - private final Collection add; - private final Collection actuallyAdded; - private final Collection selection; - - /** - * Add source primitives (not {@code PrimitiveData}) to a dataset. - * - * @param data The destination dataset - * @param add The primitives to add. It must be complete. - * @param selection The primitives to select in the dataset. May be null. - */ - public AddPrimitivesCommand(DataSet data, Collection add, Collection selection) { - super(data); - this.add = add; - this.selection = selection; - actuallyAdded = new ArrayList<>(); - } - - @Override - public boolean executeCommand() { - actuallyAdded.addAll(addPrimitives(getAffectedDataSet(), add)); - if (selection != null) { - final Collection realSelection = selection.stream() - .filter(primitive -> getAffectedDataSet().allPrimitives().contains(primitive)) - .collect(Collectors.toList()); - try { - SwingUtilities.invokeAndWait(() -> getAffectedDataSet().setSelected(realSelection)); - } catch (final InvocationTargetException e) { - Logging.error(e); - } catch (final InterruptedException e) { - Logging.error(e); - Thread.currentThread().interrupt(); - } - } - return true; - } - - @Override - public void undoCommand() { - final DataSet ds = getAffectedDataSet(); - Utils.filteredCollection(actuallyAdded, Relation.class).stream().filter(ds::containsRelation) - .forEach(ds::removePrimitive); - Utils.filteredCollection(actuallyAdded, Way.class).stream().filter(ds::containsWay) - .forEach(ds::removePrimitive); - Utils.filteredCollection(actuallyAdded, Node.class).stream().filter(ds::containsNode) - .forEach(ds::removePrimitive); - actuallyAdded.clear(); - } - - /** - * Add primitives to a dataset - * - * @param ds The dataset to add primitives to - * @param primitives A collection of primitives to add - * @return The primitives actually added - */ - public static Collection addPrimitives(DataSet ds, Collection primitives) { - final Collection returnCollection = new ArrayList<>(); - returnCollection.addAll(addRelations(ds, Utils.filteredCollection(primitives, Relation.class))); - returnCollection.addAll(addWays(ds, Utils.filteredCollection(primitives, Way.class))); - returnCollection.addAll(addNodes(ds, Utils.filteredCollection(primitives, Node.class))); - return returnCollection; - } - - private static Collection addNodes(DataSet ds, Collection nodes) { - final Collection toAdd = nodes.stream().filter(node -> node.getDataSet() == null).distinct() - .collect(Collectors.toList()); - toAdd.stream().forEach(ds::addPrimitive); - return toAdd; - } - - private static Collection addWays(DataSet ds, Collection ways) { - final Collection toAdd = new ArrayList<>(); - ways.stream().map(Way::getNodes).forEach(list -> toAdd.addAll(addNodes(ds, list))); - ways.stream().distinct() - .filter(way -> way.getDataSet() == null - && way.getNodes().stream().filter(node -> node.getDataSet() != ds).count() == 0) - .forEach(way -> { - ds.addPrimitive(way); - toAdd.add(way); - }); - return toAdd; - } - - // This might break with relations. TODO (not needed right now) - private static Collection addRelations(DataSet ds, Collection relations) { - final Collection toAdd = relations.stream().distinct() - .filter(relation -> relation.getDataSet() != null).collect(Collectors.toList()); - toAdd.forEach(ds::addPrimitive); - return toAdd; - } - - @Override - public String getDescriptionText() { - return tr("Add OSM Primitives to a dataset"); - } - - @Override - public void fillModifiedData(Collection modified, Collection deleted, - Collection added) { - added.addAll(actuallyAdded); - } - -} diff --git a/src/main/java/org/openstreetmap/josm/plugins/rapid/commands/CreateConnectionsCommand.java b/src/main/java/org/openstreetmap/josm/plugins/rapid/commands/CreateConnectionsCommand.java index b262ea4..f138999 100644 --- a/src/main/java/org/openstreetmap/josm/plugins/rapid/commands/CreateConnectionsCommand.java +++ b/src/main/java/org/openstreetmap/josm/plugins/rapid/commands/CreateConnectionsCommand.java @@ -9,6 +9,7 @@ import java.util.Collection; import java.util.List; import java.util.Map; import java.util.Map.Entry; +import java.util.Objects; import java.util.Optional; import java.util.TreeMap; import java.util.stream.Collectors; @@ -71,8 +72,11 @@ public class CreateConnectionsCommand extends Command { * @return A {@link SequenceCommand} to create connections with */ public static SequenceCommand createConnections(DataSet dataSet, Collection collection) { - final Collection nodes = Utils.filteredCollection(collection, Node.class); + final Collection nodes = Utils.filteredCollection(collection, Node.class).stream() + .map(dataSet::getPrimitiveById).map(Node.class::cast).filter(Objects::nonNull) + .collect(Collectors.toList()); final List changedKeyList = new ArrayList<>(); + SequenceCommand returnSequence = null; for (final Node node : nodes) { if (node.hasKey(CONN_KEY)) { changedKeyList.addAll(connectedCommand(dataSet, node)); @@ -82,9 +86,9 @@ public class CreateConnectionsCommand extends Command { } } if (!changedKeyList.isEmpty()) { - return new SequenceCommand(getRealDescriptionText(), changedKeyList); + returnSequence = new SequenceCommand(getRealDescriptionText(), changedKeyList); } - return null; + return returnSequence; } private static List connectedCommand(DataSet dataSet, Node node) { @@ -114,14 +118,14 @@ public class CreateConnectionsCommand extends Command { node.get(DUPE_KEY), DUPE_KEY); } - List commands = new ArrayList<>(); + final List commands = new ArrayList<>(); if (primitiveConnections[0] instanceof Node) { - Node replaceNode = (Node) primitiveConnections[0]; - Command tCommand = replaceNode(node, replaceNode); + final Node replaceNode = (Node) primitiveConnections[0]; + final Command tCommand = replaceNode(node, replaceNode); if (tCommand != null) { commands.add(tCommand); if (replaceNode.hasKey(DUPE_KEY)) { - String key = replaceNode.get(DUPE_KEY); + final String key = replaceNode.get(DUPE_KEY); commands.add(new ChangePropertyCommand(replaceNode, DUPE_KEY, key)); } else { replaceNode.put(DUPE_KEY, "empty_value"); // This is needed to actually have a command. diff --git a/src/main/java/org/openstreetmap/josm/plugins/rapid/commands/DeletePrimitivesCommand.java b/src/main/java/org/openstreetmap/josm/plugins/rapid/commands/DeletePrimitivesCommand.java index 3e4f889..81db503 100644 --- a/src/main/java/org/openstreetmap/josm/plugins/rapid/commands/DeletePrimitivesCommand.java +++ b/src/main/java/org/openstreetmap/josm/plugins/rapid/commands/DeletePrimitivesCommand.java @@ -2,20 +2,15 @@ package org.openstreetmap.josm.plugins.rapid.commands; import static org.openstreetmap.josm.tools.I18n.tr; -import java.lang.reflect.InvocationTargetException; import java.util.ArrayList; import java.util.Collection; import java.util.List; import java.util.stream.Collectors; -import javax.swing.SwingUtilities; - import org.openstreetmap.josm.command.Command; 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.Way; -import org.openstreetmap.josm.tools.Logging; public class DeletePrimitivesCommand extends Command { private final Collection selection; @@ -53,22 +48,11 @@ public class DeletePrimitivesCommand extends Command { @Override public boolean executeCommand() { for (final OsmPrimitive primitive : selection) { - final DataSet dataSet = primitive.getDataSet(); - - if (from.equals(dataSet)) { - try { - SwingUtilities.invokeAndWait(() -> dataSet.removePrimitive(primitive)); - } catch (final InvocationTargetException e) { - Logging.debug(e); - } catch (final InterruptedException e) { - Logging.debug(e); - Thread.currentThread().interrupt(); - } - removed.add(primitive); - } + primitive.setDeleted(true); + removed.add(primitive); if (primitive instanceof Way) { final List nodes = ((Way) primitive).getNodes().stream() - .filter(node -> (!node.hasKeys() || deleteChildren) && !selection.contains(node)) + .filter(node -> (!node.hasKeys() || deleteChildren) && node.getParentWays().isEmpty()) .collect(Collectors.toList()); final DeletePrimitivesCommand delNodes = new DeletePrimitivesCommand(from, nodes); delNodes.executeCommand(); @@ -84,19 +68,9 @@ public class DeletePrimitivesCommand extends Command { command.undoCommand(); } for (final OsmPrimitive primitive : removed) { - final DataSet removedPrimitiveDataSet = primitive.getDataSet(); - if (removedPrimitiveDataSet != null) { - removedPrimitiveDataSet.removePrimitive(primitive); - } - if (primitive instanceof Way) { - for (final Node node : ((Way) primitive).getNodes()) { - if (node.getDataSet() == null) { - from.addPrimitive(node); - } - } - } - from.addPrimitive(primitive); + primitive.setDeleted(false); } + removed.clear(); } @Override diff --git a/src/main/java/org/openstreetmap/josm/plugins/rapid/commands/MovePrimitiveDataSetCommand.java b/src/main/java/org/openstreetmap/josm/plugins/rapid/commands/MovePrimitiveDataSetCommand.java index 35ecc5b..def383b 100644 --- a/src/main/java/org/openstreetmap/josm/plugins/rapid/commands/MovePrimitiveDataSetCommand.java +++ b/src/main/java/org/openstreetmap/josm/plugins/rapid/commands/MovePrimitiveDataSetCommand.java @@ -7,13 +7,16 @@ import static org.openstreetmap.josm.tools.I18n.trn; import java.util.ArrayList; import java.util.Collection; import java.util.List; +import java.util.stream.Collectors; +import org.openstreetmap.josm.command.AddPrimitivesCommand; import org.openstreetmap.josm.command.Command; import org.openstreetmap.josm.command.SequenceCommand; import org.openstreetmap.josm.data.osm.DataSet; import org.openstreetmap.josm.data.osm.OsmPrimitive; +import org.openstreetmap.josm.data.osm.PrimitiveData; +import org.openstreetmap.josm.data.osm.visitor.MergeSourceBuildingVisitor; import org.openstreetmap.josm.plugins.rapid.RapiDPlugin; -import org.openstreetmap.josm.plugins.rapid.backend.RapiDDataUtils; import org.openstreetmap.josm.tools.Logging; /** @@ -22,21 +25,19 @@ import org.openstreetmap.josm.tools.Logging; * @author Taylor Smock */ public class MovePrimitiveDataSetCommand extends Command { - private final DataSet to; - private final DataSet from; - private final Collection primitives; private SequenceCommand command = null; public MovePrimitiveDataSetCommand(DataSet to, DataSet from, Collection primitives) { super(to); - this.to = to; - this.from = from; - this.primitives = primitives; + if (from == null || to.isLocked() || from.isLocked() || to.equals(from)) { + Logging.error("{0}: Cannot move primitives from {1} to {2}", RapiDPlugin.NAME, from, to); + } else { + command = moveCollection(from, to, primitives); + } } @Override public boolean executeCommand() { - command = moveCollection(from, to, primitives); if (command != null) { command.executeCommand(); } @@ -50,24 +51,24 @@ public class MovePrimitiveDataSetCommand extends Command { * @param from The sending dataset * @param selection The primitives to move */ - public SequenceCommand moveCollection(DataSet from, DataSet to, Collection selection) { - SequenceCommand returnCommand = null; - if (from == null || to.isLocked() || from.isLocked() || to.equals(from)) { - Logging.error("{0}: Cannot move primitives from {1} to {2}", RapiDPlugin.NAME, from, to); - } else { - final List commands = new ArrayList<>(); + public static SequenceCommand moveCollection(DataSet from, DataSet to, Collection selection) { + final List commands = new ArrayList<>(); - final Collection allNeededPrimitives = new ArrayList<>(); - RapiDDataUtils.addPrimitivesToCollection(allNeededPrimitives, selection); + final Collection selected = from.getAllSelected(); + from.setSelected(selection); + final MergeSourceBuildingVisitor builder = new MergeSourceBuildingVisitor(from); + final DataSet hull = builder.build(); + from.setSelected(selected); - commands.add(new DeletePrimitivesCommand(from, selection, true)); - final AddPrimitivesCommand addPrimitivesCommand = new AddPrimitivesCommand(to, allNeededPrimitives, selection); - commands.add(addPrimitivesCommand); + final List primitiveAddData = hull.allPrimitives().stream().map(OsmPrimitive::save) + .collect(Collectors.toList()); - returnCommand = new SequenceCommand(trn("Move {0} OSM Primitive between data sets", - "Move {0} OSM Primitives between data sets", selection.size(), selection.size()), commands); - } - return returnCommand; + commands.add(new AddPrimitivesCommand(primitiveAddData, + selection.stream().map(OsmPrimitive::save).collect(Collectors.toList()), to)); + commands.add(new DeletePrimitivesCommand(from, selection, true)); + + return new SequenceCommand(trn("Move {0} OSM Primitive between data sets", + "Move {0} OSM Primitives between data sets", selection.size(), selection.size()), commands); } @Override 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 4bc6d31..f93b294 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 @@ -72,11 +72,13 @@ public class RapiDAddCommand extends Command implements Runnable { if (locked) { rapid.unlock(); } - final Command tCommand = new MovePrimitiveDataSetCommand(editable, rapid, primitives); - List allPrimitives = new ArrayList<>(); + final Command movePrimitivesCommand = new MovePrimitiveDataSetCommand(editable, rapid, primitives); + final List allPrimitives = new ArrayList<>(); RapiDDataUtils.addPrimitivesToCollection(allPrimitives, primitives); final Command createConnectionsCommand = createConnections(editable, allPrimitives); - command = new SequenceCommand(getDescriptionText(), tCommand, createConnectionsCommand); + if (command == null) { // needed for undo/redo (don't create a new command) + command = new SequenceCommand(getDescriptionText(), movePrimitivesCommand, createConnectionsCommand); + } command.executeCommand(); if (locked) { diff --git a/test/unit/org/openstreetmap/josm/plugins/rapid/RapiDPluginTest.java b/test/unit/org/openstreetmap/josm/plugins/rapid/RapiDPluginTest.java index 4442295..551b0ae 100644 --- a/test/unit/org/openstreetmap/josm/plugins/rapid/RapiDPluginTest.java +++ b/test/unit/org/openstreetmap/josm/plugins/rapid/RapiDPluginTest.java @@ -16,11 +16,14 @@ import org.openstreetmap.josm.gui.MainApplication; import org.openstreetmap.josm.plugins.PluginInformation; import org.openstreetmap.josm.testutils.JOSMTestRules; +import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; + /** * @author Taylor Smock */ public class RapiDPluginTest { @Rule + @SuppressFBWarnings("URF_UNREAD_PUBLIC_OR_PROTECTED_FIELD") public JOSMTestRules test = new JOSMTestRules().preferences().main(); public PluginInformation info; diff --git a/test/unit/org/openstreetmap/josm/plugins/rapid/RapiDPreferencesTest.java b/test/unit/org/openstreetmap/josm/plugins/rapid/RapiDPreferencesTest.java index d9f625f..f4f749e 100644 --- a/test/unit/org/openstreetmap/josm/plugins/rapid/RapiDPreferencesTest.java +++ b/test/unit/org/openstreetmap/josm/plugins/rapid/RapiDPreferencesTest.java @@ -11,12 +11,15 @@ import org.openstreetmap.josm.gui.preferences.PreferenceTabbedPane; import org.openstreetmap.josm.plugins.rapid.backend.RapiDDataUtils; import org.openstreetmap.josm.testutils.JOSMTestRules; +import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; + /** * @author Taylor Smock * */ public class RapiDPreferencesTest { @Rule + @SuppressFBWarnings("URF_UNREAD_PUBLIC_OR_PROTECTED_FIELD") public JOSMTestRules test = new JOSMTestRules().preferences().main(); private RapiDPreferences preferences; diff --git a/test/unit/org/openstreetmap/josm/plugins/rapid/backend/DetectTaskingManagerTest.java b/test/unit/org/openstreetmap/josm/plugins/rapid/backend/DetectTaskingManagerTest.java deleted file mode 100644 index bc2c767..0000000 --- a/test/unit/org/openstreetmap/josm/plugins/rapid/backend/DetectTaskingManagerTest.java +++ /dev/null @@ -1,58 +0,0 @@ -// License: GPL. For details, see LICENSE file. -package org.openstreetmap.josm.plugins.rapid.backend; - -import org.junit.Assert; -import org.junit.Rule; -import org.junit.Test; -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.gui.MainApplication; -import org.openstreetmap.josm.gui.layer.GpxLayer; -import org.openstreetmap.josm.testutils.JOSMTestRules; - -/** - * @author Taylor Smock - * - */ -public class DetectTaskingManagerTest { - private static final String LAYER_NAME = "Task Boundaries"; - - @Rule - public JOSMTestRules test = new JOSMTestRules().preferences().main().projection(); - - @Test - public void testHasTaskingManagerLayer() { - Assert.assertFalse(DetectTaskingManager.hasTaskingManagerLayer()); - MainApplication.getLayerManager().addLayer(new GpxLayer(new GpxData())); - Assert.assertFalse(DetectTaskingManager.hasTaskingManagerLayer()); - MainApplication.getLayerManager().addLayer(new GpxLayer(new GpxData(), LAYER_NAME)); - Assert.assertTrue(DetectTaskingManager.hasTaskingManagerLayer()); - } - - @Test - public void testGetTaskingManagerLayer() { - Assert.assertNull(DetectTaskingManager.getTaskingManagerLayer()); - GpxLayer layer = new GpxLayer(new GpxData(), LAYER_NAME); - MainApplication.getLayerManager().addLayer(layer); - Assert.assertSame(layer, DetectTaskingManager.getTaskingManagerLayer()); - } - - @Test - public void testGetTaskingManagerBounds() { - Assert.assertFalse(DetectTaskingManager.getTaskingManagerBBox().isInWorld()); - - GpxLayer layer = new GpxLayer(new GpxData(), LAYER_NAME); - layer.data.addWaypoint(new WayPoint(new LatLon(0, 0))); - MainApplication.getLayerManager().addLayer(layer); - Assert.assertEquals(0, DetectTaskingManager.getTaskingManagerBBox().height(), 0.000001); - Assert.assertEquals(0, DetectTaskingManager.getTaskingManagerBBox().width(), 0.000001); - - layer.data.addWaypoint(new WayPoint(new LatLon(1, 1))); - BBox bbox = DetectTaskingManager.getTaskingManagerBBox(); - Assert.assertTrue(bbox.isInWorld()); - Assert.assertTrue(bbox.getBottomRight().equalsEpsilon(new LatLon(0, 1))); - Assert.assertTrue(bbox.getTopLeft().equalsEpsilon(new LatLon(1, 0))); - } -} diff --git a/test/unit/org/openstreetmap/josm/plugins/rapid/backend/DetectTaskingManagerUtilsTest.java b/test/unit/org/openstreetmap/josm/plugins/rapid/backend/DetectTaskingManagerUtilsTest.java new file mode 100644 index 0000000..7eb38e4 --- /dev/null +++ b/test/unit/org/openstreetmap/josm/plugins/rapid/backend/DetectTaskingManagerUtilsTest.java @@ -0,0 +1,73 @@ +// License: GPL. For details, see LICENSE file. +package org.openstreetmap.josm.plugins.rapid.backend; + +import org.junit.Assert; +import org.junit.Rule; +import org.junit.Test; +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.gui.MainApplication; +import org.openstreetmap.josm.gui.layer.GpxLayer; +import org.openstreetmap.josm.testutils.JOSMTestRules; + +import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; + +/** + * @author Taylor Smock + * + */ +public class DetectTaskingManagerUtilsTest { + private static final String LAYER_NAME = "Task Boundaries"; + + @Rule + @SuppressFBWarnings("URF_UNREAD_PUBLIC_OR_PROTECTED_FIELD") + public JOSMTestRules test = new JOSMTestRules().preferences().main().projection(); + + @Test + public void testHasTaskingManagerLayer() { + Assert.assertFalse(DetectTaskingManagerUtils.hasTaskingManagerLayer()); + MainApplication.getLayerManager().addLayer(new GpxLayer(new GpxData())); + Assert.assertFalse(DetectTaskingManagerUtils.hasTaskingManagerLayer()); + MainApplication.getLayerManager().addLayer(new GpxLayer(new GpxData(), LAYER_NAME)); + Assert.assertTrue(DetectTaskingManagerUtils.hasTaskingManagerLayer()); + } + + @Test + public void testGetTaskingManagerLayer() { + Assert.assertNull(DetectTaskingManagerUtils.getTaskingManagerLayer()); + final GpxLayer layer = new GpxLayer(new GpxData(), LAYER_NAME); + MainApplication.getLayerManager().addLayer(layer); + Assert.assertSame(layer, DetectTaskingManagerUtils.getTaskingManagerLayer()); + } + + @Test + public void testGetTaskingManagerBounds() { + Assert.assertFalse(DetectTaskingManagerUtils.getTaskingManagerBBox().isInWorld()); + + final GpxLayer layer = new GpxLayer(new GpxData(), LAYER_NAME); + layer.data.addWaypoint(new WayPoint(new LatLon(0, 0))); + MainApplication.getLayerManager().addLayer(layer); + Assert.assertEquals(0, DetectTaskingManagerUtils.getTaskingManagerBBox().height(), 0.000001); + Assert.assertEquals(0, DetectTaskingManagerUtils.getTaskingManagerBBox().width(), 0.000001); + + layer.data.addWaypoint(new WayPoint(new LatLon(1, 1))); + final BBox bbox = DetectTaskingManagerUtils.getTaskingManagerBBox(); + Assert.assertTrue(bbox.isInWorld()); + Assert.assertTrue(bbox.getBottomRight().equalsEpsilon(new LatLon(0, 1))); + Assert.assertTrue(bbox.getTopLeft().equalsEpsilon(new LatLon(1, 0))); + } + + @Test + public void testCreateTaskingManagerGpxBounds() { + Assert.assertFalse(DetectTaskingManagerUtils.hasTaskingManagerLayer()); + + final BBox bbox = new BBox(0, 0, 1, 1); + MainApplication.getLayerManager().addLayer(new GpxLayer(DetectTaskingManagerUtils.createTaskingManagerGpxData(bbox), + DetectTaskingManagerUtils.RAPID_CROP_AREA)); + + Assert.assertTrue(DetectTaskingManagerUtils.hasTaskingManagerLayer()); + Assert.assertTrue(DetectTaskingManagerUtils.getTaskingManagerBBox().bounds(bbox)); + } +} diff --git a/test/unit/org/openstreetmap/josm/plugins/rapid/backend/RapiDActionTest.java b/test/unit/org/openstreetmap/josm/plugins/rapid/backend/RapiDActionTest.java index cf413a3..5f7591e 100644 --- a/test/unit/org/openstreetmap/josm/plugins/rapid/backend/RapiDActionTest.java +++ b/test/unit/org/openstreetmap/josm/plugins/rapid/backend/RapiDActionTest.java @@ -12,50 +12,53 @@ import org.openstreetmap.josm.gui.layer.Layer; import org.openstreetmap.josm.gui.layer.OsmDataLayer; import org.openstreetmap.josm.testutils.JOSMTestRules; +import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; + public class RapiDActionTest { @Rule + @SuppressFBWarnings("URF_UNREAD_PUBLIC_OR_PROTECTED_FIELD") public JOSMTestRules test = new JOSMTestRules().preferences().main().projection(); @Test public void testGetLayer() { - Layer rapid = RapiDAction.getLayer(false); + Layer rapid = RapiDDataUtils.getLayer(false); Assert.assertNull(rapid); - rapid = RapiDAction.getLayer(true); + rapid = RapiDDataUtils.getLayer(true); Assert.assertEquals(RapiDLayer.class, rapid.getClass()); - Layer tRapid = RapiDAction.getLayer(false); + Layer tRapid = RapiDDataUtils.getLayer(false); Assert.assertSame(rapid, tRapid); - tRapid = RapiDAction.getLayer(true); + tRapid = RapiDDataUtils.getLayer(true); Assert.assertSame(rapid, tRapid); } @Test public void testGetData() { - final RapiDLayer rapid = RapiDAction.getLayer(true); + final RapiDLayer rapid = RapiDDataUtils.getLayer(true); final OsmDataLayer osm = new OsmDataLayer(new DataSet(), "test", null); MainApplication.getLayerManager().addLayer(osm); - RapiDAction.getRapiDData(rapid, osm); + RapiDDataUtils.getRapiDData(rapid, osm); Assert.assertTrue(rapid.getDataSet().getDataSourceBounds().isEmpty()); osm.getDataSet().addDataSource(new DataSource(new Bounds(0, 0, 0.001, 0.001), "random test")); osm.lock(); - RapiDAction.getRapiDData(rapid); + RapiDDataUtils.getRapiDData(rapid); Assert.assertTrue(rapid.getDataSet().getDataSourceBounds().isEmpty()); osm.unlock(); - RapiDAction.getRapiDData(rapid); + RapiDDataUtils.getRapiDData(rapid); Assert.assertFalse(rapid.getDataSet().getDataSourceBounds().isEmpty()); Assert.assertEquals(1, rapid.getDataSet().getDataSourceBounds().parallelStream().distinct().count()); osm.getDataSet().addDataSource(new DataSource(new Bounds(-0.001, -0.001, 0, 0), "random test")); - RapiDAction.getRapiDData(rapid); + RapiDDataUtils.getRapiDData(rapid); Assert.assertEquals(2, rapid.getDataSet().getDataSourceBounds().parallelStream().distinct().count()); - RapiDAction.getRapiDData(rapid); + RapiDDataUtils.getRapiDData(rapid); Assert.assertEquals(2, rapid.getDataSet().getDataSourceBounds().parallelStream().distinct().count()); } } 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 36e209a..7eab77b 100644 --- a/test/unit/org/openstreetmap/josm/plugins/rapid/backend/RapiDDataUtilsTest.java +++ b/test/unit/org/openstreetmap/josm/plugins/rapid/backend/RapiDDataUtilsTest.java @@ -25,8 +25,11 @@ import org.openstreetmap.josm.gui.MainApplication; import org.openstreetmap.josm.gui.layer.GpxLayer; import org.openstreetmap.josm.testutils.JOSMTestRules; +import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; + public class RapiDDataUtilsTest { @Rule + @SuppressFBWarnings("URF_UNREAD_PUBLIC_OR_PROTECTED_FIELD") public JOSMTestRules test = new JOSMTestRules().preferences().main().projection(); /** @@ -47,10 +50,10 @@ public class RapiDDataUtilsTest { @Test public void testGetDataCropped() { final BBox testBBox = getTestBBox(); - GpxData gpxData = new GpxData(); + final GpxData gpxData = new GpxData(); gpxData.addWaypoint(new WayPoint(new LatLon(39.0735205, -108.5711561))); gpxData.addWaypoint(new WayPoint(new LatLon(39.0736682, -108.5708568))); - GpxLayer gpx = new GpxLayer(gpxData, DetectTaskingManager.RAPID_CROP_AREA); + final GpxLayer gpx = new GpxLayer(gpxData, DetectTaskingManagerUtils.RAPID_CROP_AREA); final DataSet originalData = RapiDDataUtils.getData(testBBox); MainApplication.getLayerManager().addLayer(gpx); final DataSet ds = RapiDDataUtils.getData(testBBox); @@ -122,13 +125,13 @@ public class RapiDDataUtilsTest { public void testRapiDURLPreferences() { final String fakeUrl = "https://fake.url"; Assert.assertEquals(RapiDDataUtils.DEFAULT_RAPID_API, RapiDDataUtils.getRapiDURL()); - RapiDDataUtils.setRapiDUrl(fakeUrl); + RapiDDataUtils.setRapiDUrl(fakeUrl, true); Assert.assertEquals(fakeUrl, RapiDDataUtils.getRapiDURL()); final List urls = new ArrayList<>(RapiDDataUtils.getRapiDURLs()); Assert.assertEquals(2, urls.size()); - RapiDDataUtils.setRapiDUrl(RapiDDataUtils.DEFAULT_RAPID_API); + RapiDDataUtils.setRapiDUrl(RapiDDataUtils.DEFAULT_RAPID_API, true); Assert.assertEquals(RapiDDataUtils.DEFAULT_RAPID_API, RapiDDataUtils.getRapiDURL()); - RapiDDataUtils.setRapiDUrl(fakeUrl); + RapiDDataUtils.setRapiDUrl(fakeUrl, true); Assert.assertEquals(fakeUrl, RapiDDataUtils.getRapiDURL()); urls.remove(fakeUrl); RapiDDataUtils.setRapiDURLs(urls); @@ -167,9 +170,9 @@ public class RapiDDataUtilsTest { } private static void checkBBoxesConnect(BBox originalBBox, Collection bboxes) { - for (BBox bbox1 : bboxes) { + for (final BBox bbox1 : bboxes) { boolean bboxFoundConnections = false; - for (BBox bbox2 : bboxes) { + for (final BBox bbox2 : bboxes) { if (!bbox1.equals(bbox2)) { bboxFoundConnections = bboxCheckConnections(bbox1, bbox2); if (bboxFoundConnections) { @@ -186,8 +189,8 @@ public class RapiDDataUtilsTest { private static boolean bboxCheckConnections(BBox bbox1, BBox bbox2) { int shared = 0; - for (LatLon bbox1Corner : getBBoxCorners(bbox1)) { - for (LatLon bbox2Corner : getBBoxCorners(bbox2)) { + for (final LatLon bbox1Corner : getBBoxCorners(bbox1)) { + for (final LatLon bbox2Corner : getBBoxCorners(bbox2)) { if (bbox1Corner.equalsEpsilon(bbox2Corner)) { shared++; } diff --git a/test/unit/org/openstreetmap/josm/plugins/rapid/backend/RapiDLayerTest.java b/test/unit/org/openstreetmap/josm/plugins/rapid/backend/RapiDLayerTest.java new file mode 100644 index 0000000..897e820 --- /dev/null +++ b/test/unit/org/openstreetmap/josm/plugins/rapid/backend/RapiDLayerTest.java @@ -0,0 +1,77 @@ +// License: GPL. For details, see LICENSE file. +package org.openstreetmap.josm.plugins.rapid.backend; + +import static org.openstreetmap.josm.tools.I18n.tr; + +import java.awt.Component; +import java.util.Arrays; +import java.util.List; + +import javax.swing.JLabel; +import javax.swing.JPanel; + +import org.junit.Assert; +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.openstreetmap.josm.data.osm.DataSet; +import org.openstreetmap.josm.testutils.JOSMTestRules; + +import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; + +/** + * @author Taylor Smock + * + */ +public class RapiDLayerTest { + @Rule + @SuppressFBWarnings("URF_UNREAD_PUBLIC_OR_PROTECTED_FIELD") + public JOSMTestRules test = new JOSMTestRules().preferences().main().projection(); + + RapiDLayer layer; + + @Before + public void setUp() { + layer = new RapiDLayer(new DataSet(), "test", null); + } + + @Test + public void testGetSource() { + Assert.assertNotNull(layer.getChangesetSourceTag()); + Assert.assertFalse(layer.getChangesetSourceTag().trim().isEmpty()); + } + + @Test + public void testGetInfoComponent() { + final Object tObject = layer.getInfoComponent(); + Assert.assertTrue(tObject instanceof JPanel); + + JPanel jPanel = (JPanel) tObject; + final List startComponents = Arrays.asList(jPanel.getComponents()); + for (final Component comp : startComponents) { + final JLabel label = (JLabel) comp; + Assert.assertFalse(label.getText().contains("URL")); + Assert.assertFalse(label.getText().contains("Maximum Additions")); + Assert.assertFalse(label.getText().contains("Switch Layers")); + } + + layer.setRapiDUrl("bad_url"); + layer.setMaximumAddition(0); + layer.setSwitchLayers(false); + + jPanel = (JPanel) layer.getInfoComponent(); + final List currentComponents = Arrays.asList(jPanel.getComponents()); + + for (final Component comp : currentComponents) { + final JLabel label = (JLabel) comp; + if (label.getText().contains("URL")) { + Assert.assertEquals(tr("URL: {0}", "bad_url"), label.getText()); + } else if (label.getText().contains("Maximum Additions")) { + Assert.assertEquals(tr("Maximum Additions: {0}", 0), label.getText()); + } else if (label.getText().contains("Switch Layers")) { + Assert.assertEquals(tr("Switch Layers: {0}", false), label.getText()); + } + } + + } +} diff --git a/test/unit/org/openstreetmap/josm/plugins/rapid/backend/RapiDMoveActionTest.java b/test/unit/org/openstreetmap/josm/plugins/rapid/backend/RapiDMoveActionTest.java index 301830f..a8c28df 100644 --- a/test/unit/org/openstreetmap/josm/plugins/rapid/backend/RapiDMoveActionTest.java +++ b/test/unit/org/openstreetmap/josm/plugins/rapid/backend/RapiDMoveActionTest.java @@ -16,6 +16,8 @@ import org.openstreetmap.josm.gui.layer.OsmDataLayer; import org.openstreetmap.josm.plugins.rapid.commands.CreateConnectionsCommand; import org.openstreetmap.josm.testutils.JOSMTestRules; +import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; + public class RapiDMoveActionTest { RapiDMoveAction moveAction; DataSet rapidData; @@ -24,6 +26,7 @@ public class RapiDMoveActionTest { Way way2; @Rule + @SuppressFBWarnings("URF_UNREAD_PUBLIC_OR_PROTECTED_FIELD") public JOSMTestRules test = new JOSMTestRules().preferences().main().projection(); @Before @@ -53,9 +56,9 @@ public class RapiDMoveActionTest { rapidData.addSelected(way1); moveAction.actionPerformed(null); Assert.assertEquals(osmLayer, MainApplication.getLayerManager().getActiveLayer()); - Assert.assertSame(osmLayer.getDataSet(), way1.getDataSet()); + Assert.assertNotNull(osmLayer.getDataSet().getPrimitiveById(way1)); UndoRedoHandler.getInstance().undo(); - Assert.assertNotSame(osmLayer.getDataSet(), way1.getDataSet()); + Assert.assertNull(osmLayer.getDataSet().getPrimitiveById(way1)); } @Test @@ -64,10 +67,11 @@ public class RapiDMoveActionTest { way1.lastNode().put(CreateConnectionsCommand.DUPE_KEY, "n" + Long.toString(way2.lastNode().getUniqueId())); rapidData.lock(); rapidData.addSelected(way1); + final DataSet ds = osmLayer.getDataSet(); moveAction.actionPerformed(null); - Assert.assertFalse(way2.lastNode().hasKey(CreateConnectionsCommand.DUPE_KEY)); - Assert.assertFalse(way1.lastNode().hasKey(CreateConnectionsCommand.DUPE_KEY)); + Assert.assertFalse(((Way) ds.getPrimitiveById(way2)).lastNode().hasKey(CreateConnectionsCommand.DUPE_KEY)); + Assert.assertFalse(((Way) ds.getPrimitiveById(way1)).lastNode().hasKey(CreateConnectionsCommand.DUPE_KEY)); UndoRedoHandler.getInstance().undo(); Assert.assertFalse(way2.lastNode().hasKey(CreateConnectionsCommand.DUPE_KEY)); @@ -86,10 +90,11 @@ public class RapiDMoveActionTest { Assert.assertFalse(way2.lastNode().hasKey(CreateConnectionsCommand.CONN_KEY)); Assert.assertFalse(way2.firstNode().hasKey(CreateConnectionsCommand.CONN_KEY)); Assert.assertFalse(way2.getNode(1).hasKey(CreateConnectionsCommand.CONN_KEY)); - Assert.assertFalse(way1.lastNode().hasKey(CreateConnectionsCommand.CONN_KEY)); + Assert.assertTrue(way1.lastNode().isDeleted()); UndoRedoHandler.getInstance().undo(); Assert.assertFalse(way2.lastNode().hasKey(CreateConnectionsCommand.CONN_KEY)); Assert.assertTrue(way1.lastNode().hasKey(CreateConnectionsCommand.CONN_KEY)); + Assert.assertFalse(way1.lastNode().isDeleted()); } } diff --git a/test/unit/org/openstreetmap/josm/plugins/rapid/backend/RapiDRemoteControlTest.java b/test/unit/org/openstreetmap/josm/plugins/rapid/backend/RapiDRemoteControlTest.java new file mode 100644 index 0000000..afa05c7 --- /dev/null +++ b/test/unit/org/openstreetmap/josm/plugins/rapid/backend/RapiDRemoteControlTest.java @@ -0,0 +1,122 @@ +// License: GPL. For details, see LICENSE file. +package org.openstreetmap.josm.plugins.rapid.backend; + +import org.junit.Assert; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.ExpectedException; +import org.openstreetmap.josm.data.osm.BBox; +import org.openstreetmap.josm.gui.MainApplication; +import org.openstreetmap.josm.io.remotecontrol.handler.RequestHandler.RequestHandlerBadRequestException; +import org.openstreetmap.josm.testutils.JOSMTestRules; +import org.openstreetmap.josm.tools.Utils; + +import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; + +/** + * @author Taylor Smock + * + */ +public class RapiDRemoteControlTest { + + /** + * Rule used for tests throwing exceptions. + */ + @Rule + public ExpectedException thrown = ExpectedException.none(); + + /** + * Setup test. + */ + @Rule + @SuppressFBWarnings("URF_UNREAD_PUBLIC_OR_PROTECTED_FIELD") + public JOSMTestRules test = new JOSMTestRules().main().projection(); + + private static RapiDRemoteControl newHandler(String url) throws RequestHandlerBadRequestException { + final RapiDRemoteControl req = new RapiDRemoteControl(); + if (url != null) { + req.setUrl(url); + } + return req; + } + + /** + * Unit test for bad request - invalid URL. + * @throws Exception if any error occurs + */ + @Test + public void testBadRequestInvalidUrl() throws Exception { + thrown.expect(RequestHandlerBadRequestException.class); + thrown.expectMessage("MalformedURLException: no protocol: invalid_url"); + newHandler("https://localhost?url=invalid_url").handle(); + } + + private static BBox getTestBBox() { + return new BBox(-108.4625, 39.0621, -108.4594, 39.0633); + } + + /** + * Unit test for nominal request. + * + * @throws Exception if any error occurs + */ + @Test + public void testNominalRequest() throws Exception { + newHandler("https://localhost?url=" + Utils.encodeUrl(RapiDDataUtils.getRapiDURL())).handle(); + Assert.assertFalse(MainApplication.getLayerManager().getLayersOfType(RapiDLayer.class).isEmpty()); + + Assert.assertTrue(RapiDDataUtils.getLayer(false).getDataSet().getDataSourceBounds().isEmpty()); + } + + @Test + public void testTemporaryUrl() throws Exception { + String badUrl = "https://bad.url"; + newHandler("https://localhost?url=" + Utils.encodeUrl(badUrl)).handle(); + Assert.assertFalse(MainApplication.getLayerManager().getLayersOfType(RapiDLayer.class).isEmpty()); + + Assert.assertEquals(badUrl, RapiDDataUtils.getRapiDURL()); + MainApplication.getLayerManager().removeLayer(RapiDDataUtils.getLayer(false)); + Assert.assertNotEquals(badUrl, RapiDDataUtils.getRapiDURL()); + + badUrl = "NothingToSeeHere"; + thrown.expect(RequestHandlerBadRequestException.class); + thrown.expectMessage("MalformedURLException: no protocol: " + badUrl); + + newHandler("https://localhost?url=" + Utils.encodeUrl(badUrl)).handle(); + } + + @Test + public void testTemporaryMaxAdd() throws Exception { + final Integer maxObj = 1; + newHandler("http://127.0.0.1:8111/mapwithai?bbox=" + getTestBBox().toStringCSV(",") + "&max_obj=" + + maxObj.toString()).handle(); + Assert.assertFalse(MainApplication.getLayerManager().getLayersOfType(RapiDLayer.class).isEmpty()); + + Assert.assertEquals(maxObj.intValue(), RapiDDataUtils.getMaximumAddition()); + MainApplication.getLayerManager().removeLayer(RapiDDataUtils.getLayer(false)); + Assert.assertNotEquals(maxObj.intValue(), RapiDDataUtils.getMaximumAddition()); + + thrown.expect(RequestHandlerBadRequestException.class); + thrown.expectMessage("NumberFormatException (For input string: \"BAD_VALUE\")"); + newHandler( + "http://127.0.0.1:8111/mapwithai?bbox=" + getTestBBox().toStringCSV(",") + "&max_obj=BAD_VALUE") + .handle(); + } + + @Test + public void testBBox() throws Exception { + BBox temp = getTestBBox(); + newHandler("http://127.0.0.1:8111/mapwithai?bbox={bbox}".replace("{bbox}", temp.toStringCSV(","))).handle(); + Assert.assertFalse(MainApplication.getLayerManager().getLayersOfType(RapiDLayer.class).isEmpty()); + + final BBox added = RapiDDataUtils.getLayer(false).getDataSet().getDataSourceBounds().iterator().next().toBBox(); + Assert.assertTrue(temp.bounds(added)); + + MainApplication.getLayerManager().removeLayer(RapiDDataUtils.getLayer(false)); + temp = new BBox(39.0621223, -108.4625421, 39.0633059, -108.4594728); + thrown.expect(RequestHandlerBadRequestException.class); + thrown.expectMessage( + "Bad bbox: 39.0621223,-108.4625421,39.0633059,-108.4594728 (converted to [ x: 39.0621223 -> 39.0633059, y: -108.4625421 -> -108.4594728 ])"); + newHandler("http://127.0.0.1:8111/mapwithai?bbox={bbox}".replace("{bbox}", temp.toStringCSV(","))).handle(); + } +} diff --git a/test/unit/org/openstreetmap/josm/plugins/rapid/commands/AddNodeToWayCommandTest.java b/test/unit/org/openstreetmap/josm/plugins/rapid/commands/AddNodeToWayCommandTest.java index a73fa83..872ca8a 100644 --- a/test/unit/org/openstreetmap/josm/plugins/rapid/commands/AddNodeToWayCommandTest.java +++ b/test/unit/org/openstreetmap/josm/plugins/rapid/commands/AddNodeToWayCommandTest.java @@ -16,11 +16,14 @@ import org.openstreetmap.josm.data.osm.OsmPrimitive; import org.openstreetmap.josm.data.osm.Way; import org.openstreetmap.josm.testutils.JOSMTestRules; +import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; + public class AddNodeToWayCommandTest { private Node toAdd; private Way way; private AddNodeToWayCommand command; @Rule + @SuppressFBWarnings("URF_UNREAD_PUBLIC_OR_PROTECTED_FIELD") public JOSMTestRules test = new JOSMTestRules(); @Before diff --git a/test/unit/org/openstreetmap/josm/plugins/rapid/commands/AddPrimitivesCommandTest.java b/test/unit/org/openstreetmap/josm/plugins/rapid/commands/AddPrimitivesCommandTest.java deleted file mode 100644 index 22c6626..0000000 --- a/test/unit/org/openstreetmap/josm/plugins/rapid/commands/AddPrimitivesCommandTest.java +++ /dev/null @@ -1,130 +0,0 @@ -// License: GPL. For details, see LICENSE file. -package org.openstreetmap.josm.plugins.rapid.commands; - -import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; -import java.util.List; -import java.util.TreeSet; - -import org.junit.Assert; -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.osm.DataSet; -import org.openstreetmap.josm.data.osm.Node; -import org.openstreetmap.josm.data.osm.OsmPrimitive; -import org.openstreetmap.josm.data.osm.Way; -import org.openstreetmap.josm.testutils.JOSMTestRules; - -public class AddPrimitivesCommandTest { - @Rule - public JOSMTestRules test = new JOSMTestRules(); - - @Test - public void testAddPrimitives() { - final DataSet dataSet = new DataSet(); - final Way way1 = TestUtils.newWay("highway=secondary", new Node(new LatLon(0, 0)), - new Node(new LatLon(0.1, 0.1))); - Assert.assertNull(way1.getDataSet()); - - final Collection added = AddPrimitivesCommand.addPrimitives(dataSet, Collections.singleton(way1)); - Assert.assertEquals(3, added.size()); - Assert.assertSame(dataSet, way1.getDataSet()); - } - - @Test - public void testUndoRedo() { - final DataSet dataSet = new DataSet(); - final List added = new ArrayList<>(); - final List modified = new ArrayList<>(); - final List deleted = new ArrayList<>(); - final Way way1 = TestUtils.newWay("highway=secondary", new Node(new LatLon(0, 0)), - new Node(new LatLon(0.1, -0.1))); - AddPrimitivesCommand command = new AddPrimitivesCommand(dataSet, Collections.singleton(way1), null); - final Collection selection = dataSet.getAllSelected(); - Assert.assertNull(way1.getDataSet()); - - command.executeCommand(); - command.fillModifiedData(modified, deleted, added); - Assert.assertSame(dataSet, way1.getDataSet()); - Assert.assertEquals(new TreeSet<>(selection), new TreeSet<>(dataSet.getAllSelected())); - Assert.assertTrue(deleted.isEmpty()); - Assert.assertTrue(modified.isEmpty()); - Assert.assertEquals(3, added.size()); - - command.undoCommand(); - Assert.assertNull(way1.getDataSet()); - Assert.assertEquals(new TreeSet<>(selection), new TreeSet<>(dataSet.getAllSelected())); - - added.clear(); - command.executeCommand(); - Assert.assertSame(dataSet, way1.getDataSet()); - Assert.assertEquals(new TreeSet<>(selection), new TreeSet<>(dataSet.getAllSelected())); - command.fillModifiedData(modified, deleted, added); - Assert.assertTrue(deleted.isEmpty()); - Assert.assertTrue(modified.isEmpty()); - Assert.assertEquals(3, added.size()); - - command.undoCommand(); - - command = new AddPrimitivesCommand(dataSet, Collections.singleton(way1), Collections.singleton(way1)); - - command.executeCommand(); - Assert.assertSame(dataSet, way1.getDataSet()); - Assert.assertNotEquals(new TreeSet<>(selection), new TreeSet<>(dataSet.getAllSelected())); - - command.undoCommand(); - Assert.assertNull(way1.getDataSet()); - Assert.assertEquals(new TreeSet<>(selection), new TreeSet<>(dataSet.getAllSelected())); - - dataSet.addPrimitive(way1.firstNode()); - command.executeCommand(); - Assert.assertSame(dataSet, way1.getDataSet()); - Assert.assertNotEquals(new TreeSet<>(selection), new TreeSet<>(dataSet.getAllSelected())); - - command.undoCommand(); - Assert.assertNull(way1.getDataSet()); - Assert.assertEquals(new TreeSet<>(selection), new TreeSet<>(dataSet.getAllSelected())); - - dataSet.addPrimitive(way1.lastNode()); - dataSet.addPrimitive(way1); - command.executeCommand(); - Assert.assertSame(dataSet, way1.getDataSet()); - Assert.assertNotEquals(new TreeSet<>(selection), new TreeSet<>(dataSet.getAllSelected())); - - command.undoCommand(); - Assert.assertSame(dataSet, way1.getDataSet()); - - dataSet.removePrimitive(way1); - dataSet.removePrimitive(way1.lastNode()); - new DataSet().addPrimitive(way1.lastNode()); - command.executeCommand(); - Assert.assertNull(way1.getDataSet()); - Assert.assertEquals(new TreeSet<>(selection), new TreeSet<>(dataSet.getAllSelected())); - - command.undoCommand(); - Assert.assertNull(way1.getDataSet()); - } - - @Test - public void testSelection() { - final DataSet dataSet = new DataSet(); - final Way way1 = TestUtils.newWay("highway=secondary", new Node(new LatLon(0.1, 0)), - new Node(new LatLon(0.1, -0.1))); - AddPrimitivesCommand command = new AddPrimitivesCommand(dataSet, Collections.singleton(way1), - Collections.singleton(way1)); - final Collection selection = dataSet.getAllSelected(); - Assert.assertNull(way1.getDataSet()); - - command.executeCommand(); - Assert.assertNotEquals(new TreeSet<>(selection), new TreeSet<>(dataSet.getAllSelected())); - Assert.assertEquals(new TreeSet<>(Collections.singleton(way1)), dataSet.getAllSelected()); - } - - @Test - public void testDescription() { - Assert.assertNotNull(new AddPrimitivesCommand(new DataSet(), null, null).getDescriptionText()); - } -} diff --git a/test/unit/org/openstreetmap/josm/plugins/rapid/commands/CreateConnectionsCommandTest.java b/test/unit/org/openstreetmap/josm/plugins/rapid/commands/CreateConnectionsCommandTest.java index c449454..7075c2c 100644 --- a/test/unit/org/openstreetmap/josm/plugins/rapid/commands/CreateConnectionsCommandTest.java +++ b/test/unit/org/openstreetmap/josm/plugins/rapid/commands/CreateConnectionsCommandTest.java @@ -20,6 +20,8 @@ import org.openstreetmap.josm.gui.MainApplication; import org.openstreetmap.josm.gui.layer.OsmDataLayer; import org.openstreetmap.josm.testutils.JOSMTestRules; +import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; + /** * Tests for {@link CreateConnections} * @@ -27,6 +29,7 @@ import org.openstreetmap.josm.testutils.JOSMTestRules; */ public class CreateConnectionsCommandTest { @Rule + @SuppressFBWarnings("URF_UNREAD_PUBLIC_OR_PROTECTED_FIELD") public JOSMTestRules test = new JOSMTestRules().projection(); /** @@ -160,7 +163,7 @@ public class CreateConnectionsCommandTest { node1.setCoor(new LatLon(39.067399, -108.5608433)); node1.put(CreateConnectionsCommand.DUPE_KEY, "n6151680832"); - OsmDataLayer layer = new OsmDataLayer(dataSet, "temp layer", null); + final OsmDataLayer layer = new OsmDataLayer(dataSet, "temp layer", null); MainApplication.getLayerManager().addLayer(layer); replaceNodeCommand = CreateConnectionsCommand.createConnections(dataSet, Collections.singleton(node1)); @@ -179,7 +182,7 @@ public class CreateConnectionsCommandTest { */ @Test public void testGetDescriptionText() { - final String text = new CreateConnectionsCommand(new DataSet(), null).getDescriptionText(); + final String text = new CreateConnectionsCommand(new DataSet(), Collections.emptyList()).getDescriptionText(); Assert.assertNotNull(text); Assert.assertFalse(text.isEmpty()); } diff --git a/test/unit/org/openstreetmap/josm/plugins/rapid/commands/DeletePrimitivesCommandTest.java b/test/unit/org/openstreetmap/josm/plugins/rapid/commands/DeletePrimitivesCommandTest.java index 108ad85..c04dd6a 100644 --- a/test/unit/org/openstreetmap/josm/plugins/rapid/commands/DeletePrimitivesCommandTest.java +++ b/test/unit/org/openstreetmap/josm/plugins/rapid/commands/DeletePrimitivesCommandTest.java @@ -13,8 +13,11 @@ import org.openstreetmap.josm.data.osm.Node; import org.openstreetmap.josm.data.osm.Way; import org.openstreetmap.josm.testutils.JOSMTestRules; +import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; + public class DeletePrimitivesCommandTest { @Rule + @SuppressFBWarnings("URF_UNREAD_PUBLIC_OR_PROTECTED_FIELD") public JOSMTestRules test = new JOSMTestRules(); @Test @@ -29,30 +32,30 @@ public class DeletePrimitivesCommandTest { DeletePrimitivesCommand delete = new DeletePrimitivesCommand(ds, Collections.singleton(way1)); delete.executeCommand(); - Assert.assertFalse(ds.containsWay(way1)); - Assert.assertEquals(0, ds.allPrimitives().size()); + Assert.assertTrue(way1.isDeleted()); + Assert.assertEquals(0, ds.allNonDeletedPrimitives().size()); delete.undoCommand(); Assert.assertTrue(ds.containsWay(way1)); - Assert.assertEquals(3, ds.allPrimitives().size()); + Assert.assertEquals(3, ds.allNonDeletedPrimitives().size()); final Node tNode = new Node(new LatLon(0.1, 0.1)); ds.addPrimitive(tNode); - Assert.assertEquals(4, ds.allPrimitives().size()); + Assert.assertEquals(4, ds.allNonDeletedPrimitives().size()); delete.executeCommand(); - Assert.assertFalse(ds.containsWay(way1)); - Assert.assertEquals(1, ds.allPrimitives().size()); + Assert.assertTrue(way1.isDeleted()); + Assert.assertEquals(1, ds.allNonDeletedPrimitives().size()); delete.undoCommand(); - Assert.assertEquals(4, ds.allPrimitives().size()); + Assert.assertEquals(4, ds.allNonDeletedPrimitives().size()); way1.firstNode().put("highway", "stop"); delete.executeCommand(); - Assert.assertFalse(ds.containsWay(way1)); - Assert.assertEquals(2, ds.allPrimitives().size()); + Assert.assertTrue(way1.isDeleted()); + Assert.assertEquals(2, ds.allNonDeletedPrimitives().size()); delete.undoCommand(); Assert.assertTrue(way1.firstNode().hasKey("highway")); @@ -60,11 +63,11 @@ public class DeletePrimitivesCommandTest { delete = new DeletePrimitivesCommand(ds, Collections.singleton(way1), true); delete.executeCommand(); - Assert.assertFalse(ds.containsWay(way1)); - Assert.assertEquals(1, ds.allPrimitives().size()); + Assert.assertTrue(way1.isDeleted()); + Assert.assertEquals(1, ds.allNonDeletedPrimitives().size()); delete.undoCommand(); - Assert.assertEquals(4, ds.allPrimitives().size()); + Assert.assertEquals(4, ds.allNonDeletedPrimitives().size()); Assert.assertTrue(way1.firstNode().hasKey("highway")); } diff --git a/test/unit/org/openstreetmap/josm/plugins/rapid/commands/MovePrimitiveDataSetCommandTest.java b/test/unit/org/openstreetmap/josm/plugins/rapid/commands/MovePrimitiveDataSetCommandTest.java index a730be7..06eef2c 100644 --- a/test/unit/org/openstreetmap/josm/plugins/rapid/commands/MovePrimitiveDataSetCommandTest.java +++ b/test/unit/org/openstreetmap/josm/plugins/rapid/commands/MovePrimitiveDataSetCommandTest.java @@ -10,6 +10,8 @@ import org.junit.Assert; import org.junit.Rule; import org.junit.Test; import org.openstreetmap.josm.TestUtils; +import org.openstreetmap.josm.command.MoveCommand; +import org.openstreetmap.josm.data.UndoRedoHandler; import org.openstreetmap.josm.data.coor.LatLon; import org.openstreetmap.josm.data.osm.DataSet; import org.openstreetmap.josm.data.osm.Node; @@ -17,9 +19,12 @@ import org.openstreetmap.josm.data.osm.OsmPrimitive; import org.openstreetmap.josm.data.osm.Way; import org.openstreetmap.josm.testutils.JOSMTestRules; +import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; + public class MovePrimitiveDataSetCommandTest { @Rule - public JOSMTestRules test = new JOSMTestRules(); + @SuppressFBWarnings("URF_UNREAD_PUBLIC_OR_PROTECTED_FIELD") + public JOSMTestRules test = new JOSMTestRules().projection(); @Test public void testMovePrimitives() { @@ -35,22 +40,24 @@ public class MovePrimitiveDataSetCommandTest { from.addPrimitive(new Node(new LatLon(-0.1, 0.1))); final MovePrimitiveDataSetCommand move = new MovePrimitiveDataSetCommand(to, from, Collections.singleton(way1)); - Assert.assertEquals(0, to.allPrimitives().size()); - Assert.assertEquals(4, from.allPrimitives().size()); + Assert.assertEquals(0, to.allNonDeletedPrimitives().size()); + Assert.assertEquals(4, from.allNonDeletedPrimitives().size()); move.executeCommand(); move.fillModifiedData(modified, deleted, added); Assert.assertEquals(3, deleted.size()); - Assert.assertEquals(3, added.size()); + Assert.assertEquals(0, added.size()); // the JOSM Add command doesn't add to this list Assert.assertEquals(0, modified.size()); - Assert.assertEquals(1, from.allPrimitives().size()); - Assert.assertEquals(3, to.allPrimitives().size()); - Assert.assertEquals(to, way1.getDataSet()); + Assert.assertEquals(1, from.allNonDeletedPrimitives().size()); + Assert.assertEquals(3, to.allNonDeletedPrimitives().size()); + Assert.assertNotNull(to.getPrimitiveById(way1)); + Assert.assertTrue(way1.isDeleted()); move.undoCommand(); - Assert.assertEquals(0, to.allPrimitives().size()); - Assert.assertEquals(4, from.allPrimitives().size()); - Assert.assertEquals(from, way1.getDataSet()); + Assert.assertEquals(0, to.allNonDeletedPrimitives().size()); + Assert.assertEquals(4, from.allNonDeletedPrimitives().size()); + Assert.assertNotNull(from.getPrimitiveById(way1)); + Assert.assertFalse(way1.isDeleted()); } @Test @@ -76,40 +83,76 @@ public class MovePrimitiveDataSetCommandTest { move.executeCommand(); move.fillModifiedData(modified, deleted, added); Assert.assertEquals(3, deleted.size()); - Assert.assertEquals(3, added.size()); + Assert.assertEquals(0, added.size()); // the JOSM Add command doesn't add to this list Assert.assertEquals(0, modified.size()); - Assert.assertEquals(1, from.allPrimitives().size()); - Assert.assertEquals(3, to.allPrimitives().size()); - Assert.assertEquals(to, way1.getDataSet()); + Assert.assertEquals(1, from.allNonDeletedPrimitives().size()); + Assert.assertEquals(3, to.allNonDeletedPrimitives().size()); + Assert.assertNotNull(to.getPrimitiveById(way1)); move.undoCommand(); - Assert.assertEquals(0, to.allPrimitives().size()); - Assert.assertEquals(4, from.allPrimitives().size()); + Assert.assertEquals(0, to.allNonDeletedPrimitives().size()); + Assert.assertEquals(4, from.allNonDeletedPrimitives().size()); Assert.assertEquals(from, way1.getDataSet()); for (final DataSet ds : Arrays.asList(from, to)) { ds.lock(); + move = new MovePrimitiveDataSetCommand(to, from, Collections.singleton(way1)); move.executeCommand(); - Assert.assertEquals(0, to.allPrimitives().size()); - Assert.assertEquals(4, from.allPrimitives().size()); - Assert.assertEquals(from, way1.getDataSet()); + Assert.assertEquals(0, to.allNonDeletedPrimitives().size()); + Assert.assertEquals(4, from.allNonDeletedPrimitives().size()); + Assert.assertNotNull(from.getPrimitiveById(way1)); move.undoCommand(); + Assert.assertFalse(from.getPrimitiveById(way1).isDeleted()); ds.unlock(); } move = new MovePrimitiveDataSetCommand(to, null, Collections.singleton(way1)); move.executeCommand(); - Assert.assertEquals(0, to.allPrimitives().size()); - Assert.assertEquals(4, from.allPrimitives().size()); - Assert.assertEquals(from, way1.getDataSet()); + Assert.assertEquals(0, to.allNonDeletedPrimitives().size()); + Assert.assertEquals(4, from.allNonDeletedPrimitives().size()); + Assert.assertNotNull(from.getPrimitiveById(way1)); move.undoCommand(); + Assert.assertFalse(from.getPrimitiveById(way1).isDeleted()); move = new MovePrimitiveDataSetCommand(to, to, Collections.singleton(way1)); move.executeCommand(); - Assert.assertEquals(0, to.allPrimitives().size()); - Assert.assertEquals(4, from.allPrimitives().size()); - Assert.assertEquals(from, way1.getDataSet()); + Assert.assertEquals(0, to.allNonDeletedPrimitives().size()); + Assert.assertEquals(4, from.allNonDeletedPrimitives().size()); + Assert.assertNotNull(from.getPrimitiveById(way1)); move.undoCommand(); + Assert.assertFalse(from.getPrimitiveById(way1).isDeleted()); + } + + @Test + public void testMultipleUndoRedoWithMove() { + UndoRedoHandler.getInstance().clean(); // Needed due to command line testing keeping instance from somewhere. + final DataSet to = new DataSet(); + final DataSet from = new DataSet(); + final Way way1 = TestUtils.newWay("highway=tertiary", new Node(new LatLon(0, 0)), + new Node(new LatLon(0.1, 0.1))); + way1.getNodes().stream().forEach(node -> from.addPrimitive(node)); + from.addPrimitive(way1); + from.addPrimitive(new Node(new LatLon(-0.1, 0.1))); + + UndoRedoHandler.getInstance().add(new MovePrimitiveDataSetCommand(to, from, Collections.singleton(way1))); + + final Node tNode = (Node) to.getPrimitiveById(way1.firstNode()); + + UndoRedoHandler.getInstance().add(new MoveCommand(tNode, LatLon.ZERO)); + + Assert.assertTrue(UndoRedoHandler.getInstance().getRedoCommands().isEmpty()); + Assert.assertEquals(2, UndoRedoHandler.getInstance().getUndoCommands().size()); + + UndoRedoHandler.getInstance().undo(UndoRedoHandler.getInstance().getUndoCommands().size()); + Assert.assertTrue(UndoRedoHandler.getInstance().getUndoCommands().isEmpty()); + Assert.assertEquals(2, UndoRedoHandler.getInstance().getRedoCommands().size()); + UndoRedoHandler.getInstance().redo(UndoRedoHandler.getInstance().getRedoCommands().size()); + + UndoRedoHandler.getInstance().undo(UndoRedoHandler.getInstance().getUndoCommands().size()); + UndoRedoHandler.getInstance().redo(UndoRedoHandler.getInstance().getRedoCommands().size()); + + UndoRedoHandler.getInstance().undo(UndoRedoHandler.getInstance().getUndoCommands().size()); + UndoRedoHandler.getInstance().redo(UndoRedoHandler.getInstance().getRedoCommands().size()); } @Test diff --git a/test/unit/org/openstreetmap/josm/plugins/rapid/commands/RapiDAddComandTest.java b/test/unit/org/openstreetmap/josm/plugins/rapid/commands/RapiDAddComandTest.java index be58179..edefeb3 100644 --- a/test/unit/org/openstreetmap/josm/plugins/rapid/commands/RapiDAddComandTest.java +++ b/test/unit/org/openstreetmap/josm/plugins/rapid/commands/RapiDAddComandTest.java @@ -8,6 +8,8 @@ import org.junit.Assert; import org.junit.Rule; import org.junit.Test; import org.openstreetmap.josm.TestUtils; +import org.openstreetmap.josm.command.MoveCommand; +import org.openstreetmap.josm.data.UndoRedoHandler; import org.openstreetmap.josm.data.coor.LatLon; import org.openstreetmap.josm.data.osm.DataSet; import org.openstreetmap.josm.data.osm.Node; @@ -15,11 +17,14 @@ import org.openstreetmap.josm.data.osm.Tag; import org.openstreetmap.josm.data.osm.Way; import org.openstreetmap.josm.testutils.JOSMTestRules; +import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; + public class RapiDAddComandTest { private final static String HIGHWAY_RESIDENTIAL = "highway=residential"; @Rule - public JOSMTestRules test = new JOSMTestRules(); + @SuppressFBWarnings("URF_UNREAD_PUBLIC_OR_PROTECTED_FIELD") + public JOSMTestRules test = new JOSMTestRules().projection(); @Test public void testMoveCollection() { @@ -43,28 +48,28 @@ public class RapiDAddComandTest { ds1.lock(); RapiDAddCommand command = new RapiDAddCommand(ds1, ds2, Arrays.asList(way1, way2)); command.executeCommand(); - Assert.assertTrue(ds2.containsWay(way1)); - Assert.assertTrue(ds2.containsNode(way1.firstNode())); - Assert.assertTrue(ds2.containsNode(way1.lastNode())); - Assert.assertFalse(ds1.containsWay(way1)); - Assert.assertTrue(ds2.containsWay(way2)); - Assert.assertTrue(ds2.containsNode(way2.firstNode())); - Assert.assertTrue(ds2.containsNode(way2.lastNode())); - Assert.assertFalse(ds1.containsWay(way2)); + Assert.assertNotNull(ds2.getPrimitiveById(way1)); + Assert.assertNotNull(ds2.getPrimitiveById(way1.firstNode())); + Assert.assertNotNull(ds2.getPrimitiveById(way1.lastNode())); + Assert.assertTrue(way1.isDeleted()); + Assert.assertNotNull(ds2.getPrimitiveById(way2)); + Assert.assertNotNull(ds2.getPrimitiveById(way2.firstNode())); + Assert.assertNotNull(ds2.getPrimitiveById(way2.lastNode())); + Assert.assertTrue(way2.isDeleted()); - Assert.assertFalse(ds2.containsWay(way3)); + Assert.assertNull(ds2.getPrimitiveById(way3)); command = new RapiDAddCommand(ds1, ds2, Arrays.asList(way3)); command.executeCommand(); - Assert.assertTrue(ds2.containsWay(way3)); - Assert.assertTrue(ds2.containsNode(way3.firstNode())); - Assert.assertTrue(ds2.containsNode(way3.lastNode())); - Assert.assertFalse(ds1.containsWay(way3)); + Assert.assertNotNull(ds2.getPrimitiveById(way3)); + Assert.assertNotNull(ds2.getPrimitiveById(way3.firstNode())); + Assert.assertNotNull(ds2.getPrimitiveById(way3.lastNode())); + Assert.assertTrue(way3.isDeleted()); command.undoCommand(); - Assert.assertFalse(ds2.containsWay(way3)); - Assert.assertFalse(ds2.containsNode(way3.firstNode())); - Assert.assertFalse(ds2.containsNode(way3.lastNode())); - Assert.assertTrue(ds1.containsWay(way3)); + Assert.assertNull(ds2.getPrimitiveById(way3)); + Assert.assertNull(ds2.getPrimitiveById(way3.firstNode())); + Assert.assertNull(ds2.getPrimitiveById(way3.lastNode())); + Assert.assertFalse(ds1.getPrimitiveById(way3).isDeleted()); } @Test @@ -112,26 +117,58 @@ public class RapiDAddComandTest { rapidData.addPrimitive(way1); rapidData.setSelected(way1); - Assert.assertEquals(3, osmData.allPrimitives().size()); - Assert.assertEquals(3, rapidData.allPrimitives().size()); + Assert.assertEquals(3, osmData.allNonDeletedPrimitives().size()); + Assert.assertEquals(3, rapidData.allNonDeletedPrimitives().size()); - final RapiDAddCommand command = new RapiDAddCommand(rapidData, osmData, rapidData.getSelected()); + RapiDAddCommand command = new RapiDAddCommand(rapidData, osmData, rapidData.getSelected()); command.executeCommand(); - Assert.assertEquals(6, osmData.allPrimitives().size()); - Assert.assertTrue(rapidData.allPrimitives().isEmpty()); + Assert.assertEquals(6, osmData.allNonDeletedPrimitives().size()); + Assert.assertTrue(rapidData.allNonDeletedPrimitives().isEmpty()); command.undoCommand(); - Assert.assertEquals(3, osmData.allPrimitives().size()); - Assert.assertEquals(3, rapidData.allPrimitives().size()); + Assert.assertEquals(3, osmData.allNonDeletedPrimitives().size()); + Assert.assertEquals(3, rapidData.allNonDeletedPrimitives().size()); final Tag dupe = new Tag("dupe", "n".concat(Long.toString(way2.lastNode().getUniqueId()))); way1.lastNode().put(dupe); + command = new RapiDAddCommand(rapidData, osmData, rapidData.getSelected()); command.executeCommand(); - Assert.assertEquals(6, osmData.allPrimitives().size()); - Assert.assertTrue(rapidData.allPrimitives().isEmpty()); + Assert.assertEquals(5, osmData.allNonDeletedPrimitives().size()); + Assert.assertTrue(rapidData.allNonDeletedPrimitives().isEmpty()); command.undoCommand(); - Assert.assertEquals(3, osmData.allPrimitives().size()); - Assert.assertEquals(3, rapidData.allPrimitives().size()); + Assert.assertEquals(3, osmData.allNonDeletedPrimitives().size()); + Assert.assertEquals(3, rapidData.allNonDeletedPrimitives().size()); + } + + @Test + public void testMultipleUndoRedoWithMove() { + final DataSet to = new DataSet(); + final DataSet from = new DataSet(); + final Way way1 = TestUtils.newWay("highway=tertiary", new Node(new LatLon(0, 0)), + new Node(new LatLon(0.1, 0.1))); + way1.getNodes().stream().forEach(node -> from.addPrimitive(node)); + from.addPrimitive(way1); + from.addPrimitive(new Node(new LatLon(-0.1, 0.1))); + + UndoRedoHandler.getInstance().add(new RapiDAddCommand(from, to, Collections.singleton(way1))); + + final Node tNode = (Node) to.getPrimitiveById(way1.firstNode()); + + UndoRedoHandler.getInstance().add(new MoveCommand(tNode, LatLon.ZERO)); + + Assert.assertTrue(UndoRedoHandler.getInstance().getRedoCommands().isEmpty()); + Assert.assertEquals(2, UndoRedoHandler.getInstance().getUndoCommands().size()); + + UndoRedoHandler.getInstance().undo(UndoRedoHandler.getInstance().getUndoCommands().size()); + Assert.assertTrue(UndoRedoHandler.getInstance().getUndoCommands().isEmpty()); + Assert.assertEquals(2, UndoRedoHandler.getInstance().getRedoCommands().size()); + UndoRedoHandler.getInstance().redo(UndoRedoHandler.getInstance().getRedoCommands().size()); + + UndoRedoHandler.getInstance().undo(UndoRedoHandler.getInstance().getUndoCommands().size()); + UndoRedoHandler.getInstance().redo(UndoRedoHandler.getInstance().getRedoCommands().size()); + + UndoRedoHandler.getInstance().undo(UndoRedoHandler.getInstance().getUndoCommands().size()); + UndoRedoHandler.getInstance().redo(UndoRedoHandler.getInstance().getRedoCommands().size()); } }