diff --git a/src/main/java/org/openstreetmap/josm/plugins/mapwithai/MapWithAIPlugin.java b/src/main/java/org/openstreetmap/josm/plugins/mapwithai/MapWithAIPlugin.java index 5278fc8..d6b0676 100644 --- a/src/main/java/org/openstreetmap/josm/plugins/mapwithai/MapWithAIPlugin.java +++ b/src/main/java/org/openstreetmap/josm/plugins/mapwithai/MapWithAIPlugin.java @@ -37,6 +37,7 @@ import org.openstreetmap.josm.plugins.mapwithai.backend.MapWithAIObject; import org.openstreetmap.josm.plugins.mapwithai.backend.MapWithAIRemoteControl; import org.openstreetmap.josm.plugins.mapwithai.backend.MapWithAIUploadHook; import org.openstreetmap.josm.plugins.mapwithai.backend.MergeDuplicateWaysAction; +import org.openstreetmap.josm.plugins.mapwithai.data.mapwithai.PreConflatedDataUtils; import org.openstreetmap.josm.plugins.mapwithai.data.validation.tests.ConnectingNodeInformationTest; import org.openstreetmap.josm.plugins.mapwithai.data.validation.tests.RoutingIslandsTest; import org.openstreetmap.josm.plugins.mapwithai.data.validation.tests.StreetAddressOrder; @@ -110,6 +111,7 @@ public final class MapWithAIPlugin extends Plugin implements Destroyable { RequestProcessor.addRequestHandlerClass("mapwithai", MapWithAIRemoteControl.class); new MapWithAIRemoteControl(); // instantiate to get action into Remote Control Preferences destroyables.add(new MapWithAIUploadHook(info)); + destroyables.add(new PreConflatedDataUtils()); mapFrameInitialized(null, MainApplication.getMap()); OSMDownloadSource.addDownloadType(new MapWithAIDownloadSourceType()); MainApplication.worker.execute(() -> UpdateProd.doProd(info.mainversion)); diff --git a/src/main/java/org/openstreetmap/josm/plugins/mapwithai/backend/BoundingBoxMapWithAIDownloader.java b/src/main/java/org/openstreetmap/josm/plugins/mapwithai/backend/BoundingBoxMapWithAIDownloader.java index f617769..e63174c 100644 --- a/src/main/java/org/openstreetmap/josm/plugins/mapwithai/backend/BoundingBoxMapWithAIDownloader.java +++ b/src/main/java/org/openstreetmap/josm/plugins/mapwithai/backend/BoundingBoxMapWithAIDownloader.java @@ -74,6 +74,7 @@ class BoundingBoxMapWithAIDownloader extends BoundingBoxDownloader { } DataSet ds = new DataSet(); GetDataRunnable runnable = new GetDataRunnable(downloadArea.toBBox(), ds, NullProgressMonitor.INSTANCE); + runnable.setMapWithAIInfo(info); MainApplication.worker.execute(() -> { try { // It seems that the server has issues if I make a request soon @@ -109,7 +110,7 @@ class BoundingBoxMapWithAIDownloader extends BoundingBoxDownloader { if (url != null && info.getUrl() != null && !info.getUrl().trim().isEmpty()) { GetDataRunnable.addMapWithAISourceTag(ds, getSourceTag(info)); } - GetDataRunnable.cleanup(ds, downloadArea); + GetDataRunnable.cleanup(ds, downloadArea, info); return ds; } diff --git a/src/main/java/org/openstreetmap/josm/plugins/mapwithai/backend/DownloadMapWithAITask.java b/src/main/java/org/openstreetmap/josm/plugins/mapwithai/backend/DownloadMapWithAITask.java index 0dd1b6c..2d4e6f1 100644 --- a/src/main/java/org/openstreetmap/josm/plugins/mapwithai/backend/DownloadMapWithAITask.java +++ b/src/main/java/org/openstreetmap/josm/plugins/mapwithai/backend/DownloadMapWithAITask.java @@ -116,7 +116,7 @@ public class DownloadMapWithAITask extends DownloadOsmTask { synchronized (DownloadMapWithAITask.DownloadTask.class) { MapWithAIDataUtils.getLayer(true).getDataSet().mergeFrom(downloadedData); } - GetDataRunnable.cleanup(MapWithAIDataUtils.getLayer(true).getDataSet(), null); + GetDataRunnable.cleanup(MapWithAIDataUtils.getLayer(true).getDataSet(), null, null); } } diff --git a/src/main/java/org/openstreetmap/josm/plugins/mapwithai/backend/GetDataRunnable.java b/src/main/java/org/openstreetmap/josm/plugins/mapwithai/backend/GetDataRunnable.java index 4d4bae0..ceedc67 100644 --- a/src/main/java/org/openstreetmap/josm/plugins/mapwithai/backend/GetDataRunnable.java +++ b/src/main/java/org/openstreetmap/josm/plugins/mapwithai/backend/GetDataRunnable.java @@ -9,7 +9,6 @@ import java.util.Collection; import java.util.Collections; import java.util.List; import java.util.Map; -import java.util.Map.Entry; import java.util.Optional; import java.util.TreeMap; import java.util.concurrent.RecursiveTask; @@ -40,7 +39,9 @@ import org.openstreetmap.josm.gui.util.GuiHelper; import org.openstreetmap.josm.io.OsmTransferException; import org.openstreetmap.josm.plugins.mapwithai.MapWithAIPlugin; import org.openstreetmap.josm.plugins.mapwithai.commands.MergeDuplicateWays; +import org.openstreetmap.josm.plugins.mapwithai.data.mapwithai.MapWithAIInfo; import org.openstreetmap.josm.plugins.mapwithai.data.mapwithai.MapWithAILayerInfo; +import org.openstreetmap.josm.plugins.mapwithai.data.mapwithai.PreConflatedDataUtils; import org.openstreetmap.josm.tools.Geometry; import org.openstreetmap.josm.tools.Logging; import org.openstreetmap.josm.tools.Pair; @@ -60,6 +61,7 @@ public class GetDataRunnable extends RecursiveTask { private static final int MAX_LONGITUDE = 180; private Integer maximumDimensions; + private MapWithAIInfo info; private static final int MAX_NUMBER_OF_BBOXES_TO_PROCESS = 1; private static final String SERVER_ID_KEY = "server_id"; @@ -126,7 +128,7 @@ public class GetDataRunnable extends RecursiveTask { // This can technically be included in the above block, but it is here so that // cancellation is a little faster if (!monitor.isCanceled() && !bboxes.isEmpty()) { - cleanup(dataSet, new Bounds(bboxes.get(0).getBottomRight(), bboxes.get(0).getTopLeft())); + cleanup(dataSet, new Bounds(bboxes.get(0).getBottomRight(), bboxes.get(0).getTopLeft()), info); } monitor.finishTask(); return dataSet; @@ -137,12 +139,13 @@ public class GetDataRunnable extends RecursiveTask { * * @param dataSet The dataset to cleanup * @param bounds The newly added bounds to the dataset. May be {@code null}. + * @param info The information used to download the data */ - public static void cleanup(DataSet dataSet, Bounds bounds) { - GuiHelper.runInEDTAndWait(() -> realCleanup(dataSet, bounds)); + public static void cleanup(DataSet dataSet, Bounds bounds, MapWithAIInfo info) { + GuiHelper.runInEDTAndWait(() -> realCleanup(dataSet, bounds, info)); } - private static synchronized void realCleanup(DataSet dataSet, Bounds bounds) { + private static synchronized void realCleanup(DataSet dataSet, Bounds bounds, MapWithAIInfo info) { Bounds boundsToUse; if (bounds == null && !dataSet.getDataSourceBounds().isEmpty()) { boundsToUse = dataSet.getDataSourceBounds().get(0); @@ -158,6 +161,7 @@ public class GetDataRunnable extends RecursiveTask { mergeNodes(dataSet); cleanupDataSet(dataSet); mergeWays(dataSet); + PreConflatedDataUtils.removeConflatedData(dataSet, info); removeAlreadyAddedData(dataSet); List ways = dataSet.searchWays(boundsToUse.toBBox()).stream().filter(w -> w.hasKey("highway")) .collect(Collectors.toList()); @@ -544,4 +548,13 @@ public class GetDataRunnable extends RecursiveTask { return !prim.isDeleted() && !prim.hasTag(MAPWITHAI_SOURCE_TAG_KEY); } + /** + * Set the info that is being used to download data + * + * @param info The info being used + */ + public void setMapWithAIInfo(MapWithAIInfo info) { + this.info = info; + } + } diff --git a/src/main/java/org/openstreetmap/josm/plugins/mapwithai/backend/MapWithAIDataUtils.java b/src/main/java/org/openstreetmap/josm/plugins/mapwithai/backend/MapWithAIDataUtils.java index beb4b01..32a12ac 100644 --- a/src/main/java/org/openstreetmap/josm/plugins/mapwithai/backend/MapWithAIDataUtils.java +++ b/src/main/java/org/openstreetmap/josm/plugins/mapwithai/backend/MapWithAIDataUtils.java @@ -388,7 +388,7 @@ public final class MapWithAIDataUtils { lock.lock(); try { mapWithAISet.mergeFrom(newData); - GetDataRunnable.cleanup(mapWithAISet, null); + GetDataRunnable.cleanup(mapWithAISet, null, null); } finally { lock.unlock(); } diff --git a/src/main/java/org/openstreetmap/josm/plugins/mapwithai/backend/MapWithAILayer.java b/src/main/java/org/openstreetmap/josm/plugins/mapwithai/backend/MapWithAILayer.java index c24cbe1..2b07f6a 100644 --- a/src/main/java/org/openstreetmap/josm/plugins/mapwithai/backend/MapWithAILayer.java +++ b/src/main/java/org/openstreetmap/josm/plugins/mapwithai/backend/MapWithAILayer.java @@ -209,7 +209,7 @@ public class MapWithAILayer extends OsmDataLayer implements ActiveLayerChangeLis */ public void onPostDownloadFromServer(Bounds bounds) { super.onPostDownloadFromServer(); - GetDataRunnable.cleanup(getDataSet(), bounds); + GetDataRunnable.cleanup(getDataSet(), bounds, null); } @Override diff --git a/src/main/java/org/openstreetmap/josm/plugins/mapwithai/backend/commands/conflation/AbstractConflationCommand.java b/src/main/java/org/openstreetmap/josm/plugins/mapwithai/backend/commands/conflation/AbstractConflationCommand.java index dc262c5..10c983e 100644 --- a/src/main/java/org/openstreetmap/josm/plugins/mapwithai/backend/commands/conflation/AbstractConflationCommand.java +++ b/src/main/java/org/openstreetmap/josm/plugins/mapwithai/backend/commands/conflation/AbstractConflationCommand.java @@ -26,10 +26,12 @@ import org.openstreetmap.josm.gui.layer.OsmDataLayer; import org.openstreetmap.josm.gui.progress.NullProgressMonitor; import org.openstreetmap.josm.gui.progress.ProgressMonitor; import org.openstreetmap.josm.gui.progress.swing.PleaseWaitProgressMonitor; +import org.openstreetmap.josm.plugins.mapwithai.commands.CreateConnectionsCommand; import org.openstreetmap.josm.tools.Pair; /** - * This is an abstract class for conflation commands + * This is an abstract class for conflation commands. This class is primarily + * used in {@link CreateConnectionsCommand#createConnections}. * * @author Taylor Smock * diff --git a/src/main/java/org/openstreetmap/josm/plugins/mapwithai/backend/commands/conflation/AlreadyConflatedCommand.java b/src/main/java/org/openstreetmap/josm/plugins/mapwithai/backend/commands/conflation/AlreadyConflatedCommand.java new file mode 100644 index 0000000..e34753b --- /dev/null +++ b/src/main/java/org/openstreetmap/josm/plugins/mapwithai/backend/commands/conflation/AlreadyConflatedCommand.java @@ -0,0 +1,66 @@ +// License: GPL. For details, see LICENSE file. +package org.openstreetmap.josm.plugins.mapwithai.backend.commands.conflation; + +import static org.openstreetmap.josm.tools.I18n.tr; + +import java.util.Arrays; +import java.util.Collection; +import java.util.List; +import java.util.stream.Collectors; + +import org.openstreetmap.josm.command.ChangePropertyCommand; +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.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.plugins.mapwithai.data.mapwithai.PreConflatedDataUtils; + +/** + * All this currently does is remove + * {@link PreConflatedDataUtils#CONFLATED_KEY}. + * + * @author Taylor Smock + * + */ +public class AlreadyConflatedCommand extends AbstractConflationCommand { + + public AlreadyConflatedCommand(DataSet data) { + super(data); + } + + @Override + public String getDescriptionText() { + return tr("Remove key for already conflated data"); + } + + @Override + public Collection> getInterestedTypes() { + return Arrays.asList(Node.class, Way.class, Relation.class); + } + + @Override + public String getKey() { + return PreConflatedDataUtils.getConflatedKey(); + } + + @Override + public Command getRealCommand() { + List commands = possiblyAffectedPrimitives.stream().filter(p -> p.hasTag(getKey())) + .map(k -> new ChangePropertyCommand(k, getKey(), "")).collect(Collectors.toList()); + return commands.isEmpty() ? null : SequenceCommand.wrapIfNeeded(getDescriptionText(), commands); + } + + @Override + public boolean allowUndo() { + return true; + } + + @Override + public boolean keyShouldNotExistInOSM() { + return true; + } + +} diff --git a/src/main/java/org/openstreetmap/josm/plugins/mapwithai/commands/CreateConnectionsCommand.java b/src/main/java/org/openstreetmap/josm/plugins/mapwithai/commands/CreateConnectionsCommand.java index 302caf2..e1a9d6a 100644 --- a/src/main/java/org/openstreetmap/josm/plugins/mapwithai/commands/CreateConnectionsCommand.java +++ b/src/main/java/org/openstreetmap/josm/plugins/mapwithai/commands/CreateConnectionsCommand.java @@ -24,6 +24,7 @@ import org.openstreetmap.josm.data.osm.PrimitiveData; import org.openstreetmap.josm.gui.util.GuiHelper; import org.openstreetmap.josm.plugins.mapwithai.MapWithAIPlugin; import org.openstreetmap.josm.plugins.mapwithai.backend.commands.conflation.AbstractConflationCommand; +import org.openstreetmap.josm.plugins.mapwithai.backend.commands.conflation.AlreadyConflatedCommand; import org.openstreetmap.josm.plugins.mapwithai.backend.commands.conflation.ConnectedCommand; import org.openstreetmap.josm.plugins.mapwithai.backend.commands.conflation.DuplicateCommand; import org.openstreetmap.josm.plugins.mapwithai.backend.commands.conflation.MergeAddressBuildings; @@ -45,6 +46,7 @@ public class CreateConnectionsCommand extends Command { CONFLATION_COMMANDS.add(MergeAddressBuildings.class); CONFLATION_COMMANDS.add(MergeBuildingAddress.class); CONFLATION_COMMANDS.add(OverNodedWays.class); + CONFLATION_COMMANDS.add(AlreadyConflatedCommand.class); } public CreateConnectionsCommand(DataSet data, Collection primitives) { diff --git a/src/main/java/org/openstreetmap/josm/plugins/mapwithai/data/mapwithai/MapWithAIInfo.java b/src/main/java/org/openstreetmap/josm/plugins/mapwithai/data/mapwithai/MapWithAIInfo.java index 9fa1f49..1ab3a2b 100644 --- a/src/main/java/org/openstreetmap/josm/plugins/mapwithai/data/mapwithai/MapWithAIInfo.java +++ b/src/main/java/org/openstreetmap/josm/plugins/mapwithai/data/mapwithai/MapWithAIInfo.java @@ -38,6 +38,7 @@ public class MapWithAIInfo extends private boolean conflate; private String conflationUrl; private JsonArray conflationParameters; + private String alreadyConflatedKey; /** * when adding a field, also adapt the: {@link #MapWithAIPreferenceEntry @@ -62,6 +63,8 @@ public class MapWithAIInfo extends String conflationParameters; @StructEntry String categories; + @StructEntry + String alreadyConflatedKey; /** * Constructs a new empty {@link MapWithAIPreferenceEntry} @@ -93,6 +96,7 @@ public class MapWithAIInfo extends categories = i.categories.stream().map(MapWithAICategory::getCategoryString) .collect(Collectors.joining(";")); } + alreadyConflatedKey = i.alreadyConflatedKey; } @Override @@ -218,6 +222,7 @@ public class MapWithAIInfo extends } } } + alreadyConflatedKey = e.alreadyConflatedKey; } public MapWithAIInfo(MapWithAIInfo i) { @@ -250,6 +255,7 @@ public class MapWithAIInfo extends this.conflate = i.conflate; this.conflationUrl = i.conflationUrl; this.conflationParameters = i.conflationParameters; + this.alreadyConflatedKey = i.alreadyConflatedKey; } public boolean equalsPref(MapWithAIInfo other) { @@ -261,7 +267,8 @@ public class MapWithAIInfo extends return super.equalsPref(other) && Objects.equals(this.replacementTags, other.replacementTags) && Objects.equals(this.conflationUrl, other.conflationUrl) && Objects.equals(this.conflationParameters, other.conflationParameters) - && Objects.equals(this.categories, other.categories); + && Objects.equals(this.categories, other.categories) + && Objects.equals(this.alreadyConflatedKey, other.alreadyConflatedKey); // CHECKSTYLE.ON: BooleanExpressionComplexity } @@ -425,4 +432,23 @@ public class MapWithAIInfo extends public List getAdditionalCategories() { return this.categories != null ? Collections.unmodifiableList(this.categories) : Collections.emptyList(); } + + /** + * Set the key that indicates an object is already conflated, and if so, to what + * + * @param key The key returned by the server indicating the conflation object + */ + public void setAlreadyConflatedKey(String key) { + alreadyConflatedKey = key; + } + + /** + * Get the key that indicates an object is already conflated, and if so, to what + * Please note that it may be `true`/`false` instead of an object id. + * + * return The key returned by the server indicating the conflation object + */ + public String getAlreadyConflatedKey() { + return alreadyConflatedKey; + } } diff --git a/src/main/java/org/openstreetmap/josm/plugins/mapwithai/data/mapwithai/PreConflatedDataUtils.java b/src/main/java/org/openstreetmap/josm/plugins/mapwithai/data/mapwithai/PreConflatedDataUtils.java new file mode 100644 index 0000000..b8b58d9 --- /dev/null +++ b/src/main/java/org/openstreetmap/josm/plugins/mapwithai/data/mapwithai/PreConflatedDataUtils.java @@ -0,0 +1,93 @@ +// License: GPL. For details, see LICENSE file. +package org.openstreetmap.josm.plugins.mapwithai.data.mapwithai; + +import org.openstreetmap.josm.command.ChangePropertyKeyCommand; +import org.openstreetmap.josm.data.osm.DataSet; +import org.openstreetmap.josm.gui.MainApplication; +import org.openstreetmap.josm.plugins.mapwithai.backend.MapWithAILayer; +import org.openstreetmap.josm.spi.preferences.Config; +import org.openstreetmap.josm.spi.preferences.PreferenceChangeEvent; +import org.openstreetmap.josm.spi.preferences.PreferenceChangedListener; +import org.openstreetmap.josm.tools.Destroyable; + +/** + * Show/hide conflated objects. This depends upon the server indicating that an + * object is conflated. + * + * @author Taylor Smock + * + */ +public class PreConflatedDataUtils implements PreferenceChangedListener, Destroyable { + /** The preference key that determines if objects are shown/hidden */ + protected static final String PREF_KEY = "mapwithai.conflated.hide"; + /** + * If this config value is true, completely hide the conflated item instead of + * just greying it out + */ + protected static final String PREF_KEY_FULL = PREF_KEY + ".full"; + /** + * The key added to objects to indicate that they have been conflated. May show + * object or be true/false + */ + private static final String CONFLATED_KEY = "mapwithai:conflated"; + + public PreConflatedDataUtils() { + Config.getPref().addKeyPreferenceChangeListener(PREF_KEY, this); + Config.getPref().addKeyPreferenceChangeListener(PREF_KEY_FULL, this); + } + + /** + * Despite the name, this method changes the conflated tag to a standard tag, + * and then hides the data. + * + * @param dataSet The dataset to look through + * @param info The info with the key to use to convert to the + * mapwithai:conflated tag + */ + public static void removeConflatedData(DataSet dataSet, MapWithAIInfo info) { + if (info != null && info.getAlreadyConflatedKey() != null && !info.getAlreadyConflatedKey().trim().isEmpty()) { + String key = info.getAlreadyConflatedKey(); + dataSet.allPrimitives().parallelStream().filter(p -> p.hasKey(key)) + .forEach(p -> new ChangePropertyKeyCommand(p, key, getConflatedKey()).executeCommand()); + hideConflatedData(dataSet); + } + } + + /** + * Hide conflated data. + * + * @param dataSet The dataset to show/hide data in + */ + public static void hideConflatedData(DataSet dataSet) { + boolean hide = Config.getPref().getBoolean(PREF_KEY, true); + boolean fullHide = Config.getPref().getBoolean(PREF_KEY_FULL, false); + dataSet.allPrimitives().parallelStream().filter(p -> p.hasKey(getConflatedKey())).forEach(p -> { + if (hide) { + p.setDisabledState(fullHide); + } else { + p.unsetDisabledState(); + } + }); + } + + @Override + public void preferenceChanged(PreferenceChangeEvent e) { + MainApplication.getLayerManager().getLayersOfType(MapWithAILayer.class).stream().map(MapWithAILayer::getDataSet) + .distinct().forEach(PreConflatedDataUtils::hideConflatedData); + } + + @Override + public void destroy() { + Config.getPref().removeKeyPreferenceChangeListener(PREF_KEY, this); + Config.getPref().removeKeyPreferenceChangeListener(PREF_KEY_FULL, this); + } + + /** + * Get the key used to indicate that an object is already conflated. + * + * @return the conflatedKey + */ + public static String getConflatedKey() { + return CONFLATED_KEY; + } +} diff --git a/src/main/java/org/openstreetmap/josm/plugins/mapwithai/io/mapwithai/MapWithAISourceReader.java b/src/main/java/org/openstreetmap/josm/plugins/mapwithai/io/mapwithai/MapWithAISourceReader.java index da00a1a..ec33ca2 100644 --- a/src/main/java/org/openstreetmap/josm/plugins/mapwithai/io/mapwithai/MapWithAISourceReader.java +++ b/src/main/java/org/openstreetmap/josm/plugins/mapwithai/io/mapwithai/MapWithAISourceReader.java @@ -115,6 +115,7 @@ public class MapWithAISourceReader implements Closeable { boolean conflation = values.getBoolean("conflate", false); String conflationUrl = values.getString("conflationUrl", null); String id = values.getString("id", name.replace(" ", "_")); + String alreadyConflatedKey = values.getString("conflated_key", null); JsonValue countries = values.getOrDefault("countries", JsonValue.EMPTY_JSON_OBJECT); List bounds = new ArrayList<>(); if (JsonValue.ValueType.OBJECT == countries.getValueType()) { @@ -139,6 +140,7 @@ public class MapWithAISourceReader implements Closeable { info.setConflationParameters(values.getJsonArray("conflationParameters")); info.setConflation(conflation); info.setConflationUrl(conflationUrl); + info.setAlreadyConflatedKey(alreadyConflatedKey); if (values.containsKey("terms_of_use_url")) { info.setTermsOfUseURL(values.getString("terms_of_use_url")); } diff --git a/test/unit/org/openstreetmap/josm/plugins/mapwithai/commands/conflation/AlreadyConflatedCommandTest.java b/test/unit/org/openstreetmap/josm/plugins/mapwithai/commands/conflation/AlreadyConflatedCommandTest.java new file mode 100644 index 0000000..0c5ba05 --- /dev/null +++ b/test/unit/org/openstreetmap/josm/plugins/mapwithai/commands/conflation/AlreadyConflatedCommandTest.java @@ -0,0 +1,95 @@ +// License: GPL. For details, see LICENSE file. +package org.openstreetmap.josm.plugins.mapwithai.commands.conflation; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import java.util.Arrays; + +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.openstreetmap.josm.TestUtils; +import org.openstreetmap.josm.command.Command; +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.Relation; +import org.openstreetmap.josm.data.osm.RelationMember; +import org.openstreetmap.josm.data.osm.Way; +import org.openstreetmap.josm.plugins.mapwithai.backend.commands.conflation.AlreadyConflatedCommand; +import org.openstreetmap.josm.plugins.mapwithai.data.mapwithai.PreConflatedDataUtils; +import org.openstreetmap.josm.testutils.JOSMTestRules; + +public class AlreadyConflatedCommandTest { + @Rule + public JOSMTestRules rule = new JOSMTestRules().projection(); + private AlreadyConflatedCommand alreadyConflatedCommand; + + @Before + public void setUp() { + DataSet ds = new DataSet(); + alreadyConflatedCommand = new AlreadyConflatedCommand(ds); + } + + @Test + public void testGetInterestedTypes() { + assertTrue(alreadyConflatedCommand.getInterestedTypes().contains(Relation.class)); + assertTrue(alreadyConflatedCommand.getInterestedTypes().contains(Way.class)); + assertTrue(alreadyConflatedCommand.getInterestedTypes().contains(Node.class)); + } + + @Test + public void testGetKey() { + assertEquals(PreConflatedDataUtils.getConflatedKey(), alreadyConflatedCommand.getKey()); + } + + @Test + public void testGetRealCommand() { + DataSet ds = alreadyConflatedCommand.getAffectedDataSet(); + String key = PreConflatedDataUtils.getConflatedKey(); + ds.addPrimitive(TestUtils.newNode(key + "=w1000")); + ds.addPrimitive(TestUtils.newNode("addr:street=42")); + Way way1 = TestUtils.newWay(key + "=n1", new Node(LatLon.ZERO), new Node(LatLon.NORTH_POLE)); + Way way2 = TestUtils.newWay("highway=residential", new Node(LatLon.ZERO), new Node(LatLon.SOUTH_POLE)); + Relation relation1 = TestUtils.newRelation(key + "=true", new RelationMember("", new Node(LatLon.ZERO))); + Relation relation2 = TestUtils.newRelation("type=restriction", new RelationMember("", new Node(LatLon.ZERO))); + for (Way w : Arrays.asList(way1, way2)) { + w.getNodes().forEach(ds::addPrimitive); + ds.addPrimitive(w); + } + for (Relation r : Arrays.asList(relation1, relation2)) { + r.getMemberPrimitives().forEach(ds::addPrimitive); + ds.addPrimitive(r); + } + + Command command = alreadyConflatedCommand.getCommand(ds.allPrimitives()); + for (int i = 0; i < 10; i++) { + assertEquals(3, ds.allPrimitives().stream().filter(p -> p.hasKey(key)).count()); + command.executeCommand(); + assertEquals(0, ds.allPrimitives().stream().filter(p -> p.hasKey(key)).count()); + + command.undoCommand(); + assertEquals(3, ds.allPrimitives().stream().filter(p -> p.hasKey(key)).count()); + } + } + + @Test + public void testAllowUndo() { + assertTrue(alreadyConflatedCommand.allowUndo()); + } + + @Test + public void testKeyShouldNotExistInOSM() { + assertTrue(alreadyConflatedCommand.keyShouldNotExistInOSM()); + } + + @Test + public void testGetDescriptionText() { + assertNotNull(alreadyConflatedCommand.getDescriptionText()); + assertFalse(alreadyConflatedCommand.getDescriptionText().trim().isEmpty()); + } + +} diff --git a/test/unit/org/openstreetmap/josm/plugins/mapwithai/data/mapwithai/PreConflatedDataUtilsTest.java b/test/unit/org/openstreetmap/josm/plugins/mapwithai/data/mapwithai/PreConflatedDataUtilsTest.java new file mode 100644 index 0000000..414e179 --- /dev/null +++ b/test/unit/org/openstreetmap/josm/plugins/mapwithai/data/mapwithai/PreConflatedDataUtilsTest.java @@ -0,0 +1,113 @@ +// License: GPL. For details, see LICENSE file. +package org.openstreetmap.josm.plugins.mapwithai.data.mapwithai; + +import static org.junit.Assert.assertEquals; + +import org.junit.Before; +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.plugins.mapwithai.backend.MapWithAIDataUtils; +import org.openstreetmap.josm.plugins.mapwithai.backend.MapWithAILayer; +import org.openstreetmap.josm.spi.preferences.Config; +import org.openstreetmap.josm.testutils.JOSMTestRules; + +/** + * Test case for {@link PreConflatedDataUtils} + * + * @author Taylor Smock + * + */ +public class PreConflatedDataUtilsTest { + @Rule + public JOSMTestRules rules = new JOSMTestRules().preferences().projection(); + private DataSet ds; + + @Before + public void setUp() { + MapWithAILayer layer = MapWithAIDataUtils.getLayer(true); + ds = layer.getDataSet(); + Node node1 = new Node(LatLon.ZERO); + Node node2 = new Node(LatLon.NORTH_POLE); + node1.put(PreConflatedDataUtils.getConflatedKey(), "true"); + ds.addPrimitive(node1); + ds.addPrimitive(node2); + Config.getPref().put(PreConflatedDataUtils.PREF_KEY, null); + } + + @Test + public void testRemoveConflatedData() { + MapWithAIInfo info = new MapWithAIInfo(); + info.setAlreadyConflatedKey("test_conflation"); + ds.addPrimitive(TestUtils.newNode("test_conflation=test")); + assertEquals(1, ds.allPrimitives().stream().filter(p -> p.hasTag("test_conflation")).count()); + PreConflatedDataUtils.removeConflatedData(ds, info); + assertEquals(0, ds.allPrimitives().stream().filter(p -> p.hasTag("test_conflation")).count()); + assertEquals(2, + ds.allPrimitives().stream().filter(p -> p.hasTag(PreConflatedDataUtils.getConflatedKey())).count()); + } + + @Test + public void testRemoveConflatedDataNoKey() { + MapWithAIInfo info = new MapWithAIInfo(); + ds.addPrimitive(TestUtils.newNode("test_conflation=test")); + assertEquals(1, ds.allPrimitives().stream().filter(p -> p.hasTag("test_conflation")).count()); + PreConflatedDataUtils.removeConflatedData(ds, info); + assertEquals(1, ds.allPrimitives().stream().filter(p -> p.hasTag("test_conflation")).count()); + assertEquals(1, + ds.allPrimitives().stream().filter(p -> p.hasTag(PreConflatedDataUtils.getConflatedKey())).count()); + } + + @Test + public void testRemoveConflatedDataEmptyKey() { + MapWithAIInfo info = new MapWithAIInfo(); + info.setAlreadyConflatedKey(" "); + ds.addPrimitive(TestUtils.newNode("test_conflation=test")); + assertEquals(1, ds.allPrimitives().stream().filter(p -> p.hasTag("test_conflation")).count()); + PreConflatedDataUtils.removeConflatedData(ds, info); + assertEquals(1, ds.allPrimitives().stream().filter(p -> p.hasTag("test_conflation")).count()); + assertEquals(1, + ds.allPrimitives().stream().filter(p -> p.hasTag(PreConflatedDataUtils.getConflatedKey())).count()); + } + + @Test + public void testRemoveConflatedDataNull() { + ds.addPrimitive(TestUtils.newNode("test_conflation=test")); + assertEquals(1, ds.allPrimitives().stream().filter(p -> p.hasTag("test_conflation")).count()); + PreConflatedDataUtils.removeConflatedData(ds, null); + assertEquals(1, ds.allPrimitives().stream().filter(p -> p.hasTag("test_conflation")).count()); + assertEquals(1, + ds.allPrimitives().stream().filter(p -> p.hasTag(PreConflatedDataUtils.getConflatedKey())).count()); + } + + @Test + public void testHideConflatedData() { + PreConflatedDataUtils.hideConflatedData(ds); + assertEquals(1, ds.allPrimitives().stream().filter(OsmPrimitive::isDisabled).count()); + Config.getPref().putBoolean(PreConflatedDataUtils.PREF_KEY, false); + PreConflatedDataUtils.hideConflatedData(ds); + assertEquals(0, ds.allPrimitives().stream().filter(OsmPrimitive::isDisabled).count()); + } + + @Test + public void testPreferenceChanged() { + PreConflatedDataUtils util = new PreConflatedDataUtils(); + PreConflatedDataUtils.hideConflatedData(ds); + assertEquals(1, ds.allPrimitives().stream().filter(OsmPrimitive::isDisabled).count()); + Config.getPref().putBoolean(PreConflatedDataUtils.PREF_KEY, false); + assertEquals(0, ds.allPrimitives().stream().filter(OsmPrimitive::isDisabled).count()); + util.destroy(); + } + + @Test + public void testDestroy() { + new PreConflatedDataUtils().destroy(); + Config.getPref().putBoolean(PreConflatedDataUtils.PREF_KEY, true); + assertEquals(0, ds.allPrimitives().stream().filter(OsmPrimitive::isDisabled).count()); + } + +}