kopia lustrzana https://github.com/JOSM/MapWithAI
Porównaj commity
14 Commity
Autor | SHA1 | Data |
---|---|---|
Taylor Smock | cecb9f40be | |
Taylor Smock | 7f725f7e4c | |
Taylor Smock | f7c1d3d8b0 | |
Taylor Smock | fbd3f10541 | |
Taylor Smock | faa031e49c | |
Taylor Smock | ca0b8e479f | |
Taylor Smock | ad6ec16acd | |
Taylor Smock | d56513358d | |
Taylor Smock | eff911c300 | |
Hermann Schwarting | d13d61f13c | |
Taylor Smock | 68b9ff91c1 | |
Taylor Smock | 225abbb685 | |
Taylor Smock | e8c6e96217 | |
Taylor Smock | e796f49d8e |
|
@ -10,20 +10,18 @@ on:
|
|||
branches:
|
||||
- master
|
||||
- $default-branch
|
||||
schedule:
|
||||
- cron: "1 5 * * 6"
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
call-workflow:
|
||||
strategy:
|
||||
matrix:
|
||||
josm-revision: ["", "r18723"]
|
||||
uses: JOSM/JOSMPluginAction/.github/workflows/ant.yml@v1
|
||||
josm-revision: ["", "r18877"]
|
||||
uses: JOSM/JOSMPluginAction/.github/workflows/ant.yml@v2
|
||||
with:
|
||||
java-version: 17
|
||||
josm-revision: ${{ matrix.josm-revision }}
|
||||
plugin-jar-name: 'mapwithai'
|
||||
perform-revision-tagging: ${{ github.repository == 'JOSM/MapWithAI' && github.ref_type == 'branch' && github.ref_name == 'master' && github.event_name != 'schedule' && github.event_name != 'pull_request' && matrix.josm-revision == 'r18723' }}
|
||||
perform-revision-tagging: ${{ matrix.josm-revision == 'r18877' && github.repository == 'JOSM/MapWithAI' && github.ref_type == 'branch' && github.ref_name == 'master' && github.event_name != 'schedule' && github.event_name != 'pull_request' }}
|
||||
secrets: inherit
|
||||
|
||||
|
|
|
@ -10,4 +10,4 @@ permissions:
|
|||
|
||||
jobs:
|
||||
call-workflow:
|
||||
uses: JOSM/JOSMPluginAction/.github/workflows/reports.yaml@v1
|
||||
uses: JOSM/JOSMPluginAction/.github/workflows/reports.yaml@v2
|
||||
|
|
18
build.gradle
18
build.gradle
|
@ -1,9 +1,9 @@
|
|||
import groovy.xml.XmlParser
|
||||
|
||||
plugins {
|
||||
id "com.diffplug.spotless" version "6.20.0"
|
||||
id "com.github.ben-manes.versions" version "0.47.0"
|
||||
id "com.github.spotbugs" version "5.0.14"
|
||||
id "com.diffplug.spotless" version "6.25.0"
|
||||
id "com.github.ben-manes.versions" version "0.51.0"
|
||||
id "com.github.spotbugs" version "6.0.8"
|
||||
// id "de.aaschmid.cpd" version "3.3"
|
||||
id "eclipse"
|
||||
id "jacoco"
|
||||
|
@ -12,7 +12,7 @@ plugins {
|
|||
id "maven-publish"
|
||||
id "net.ltgt.errorprone" version "3.1.0"
|
||||
id "org.openstreetmap.josm" version "0.8.2"
|
||||
id "org.sonarqube" version "4.2.1.3168"
|
||||
id "org.sonarqube" version "4.4.1.3373"
|
||||
id "pmd"
|
||||
}
|
||||
|
||||
|
@ -29,15 +29,15 @@ repositories {
|
|||
|
||||
def versions = [
|
||||
awaitility: "4.2.0",
|
||||
equalsverifier: "3.15",
|
||||
errorprone: "2.20.0",
|
||||
findsecbugs: "1.12.0",
|
||||
equalsverifier: "3.15.8",
|
||||
errorprone: "2.26.0",
|
||||
findsecbugs: "1.13.0",
|
||||
jacoco: "0.8.10",
|
||||
jmockit: "1.49.a",
|
||||
josm: properties.get("plugin.compile.version"),
|
||||
junit: "5.9.1",
|
||||
junit: "5.10.2",
|
||||
pmd: "6.20.0",
|
||||
spotbugs: "4.7.3",
|
||||
spotbugs: "4.8.3",
|
||||
wiremock: "2.35.0",
|
||||
]
|
||||
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
<!-- edit the properties of this plugin in the file `gradle.properties` -->
|
||||
<property file="${basedir}/gradle.properties"/>
|
||||
<property name="java.lang.version" value="17"/>
|
||||
<property name="plugin.minimum.java.version" value="17"/>
|
||||
|
||||
<!-- ** include targets that all plugins have in common ** -->
|
||||
<import file="../build-common.xml"/>
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
# The minimum JOSM version this plugin is compatible with (can be any numeric version
|
||||
plugin.main.version = 18723
|
||||
plugin.main.version = 18877
|
||||
# The JOSM version this plugin is currently compiled against
|
||||
# Please make sure this version is available at https://josm.openstreetmap.de/download
|
||||
# The special values "latest" and "tested" are also possible here, but not recommended.
|
||||
plugin.compile.version = 18724
|
||||
plugin.compile.version = 18877
|
||||
plugin.canloadatruntime = true
|
||||
plugin.author = Taylor Smock
|
||||
plugin.class = org.openstreetmap.josm.plugins.mapwithai.MapWithAIPlugin
|
||||
|
|
Plik binarny nie jest wyświetlany.
|
@ -1,7 +1,8 @@
|
|||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
distributionSha256Sum=03ec176d388f2aa99defcadc3ac6adf8dd2bce5145a129659537c0874dea5ad1
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.2.1-bin.zip
|
||||
distributionSha256Sum=9631d53cf3e74bfa726893aee1f8994fee4e060c401335946dba2156f440f24c
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.6-bin.zip
|
||||
networkTimeout=10000
|
||||
validateDistributionUrl=true
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
||||
|
|
|
@ -85,9 +85,6 @@ done
|
|||
APP_BASE_NAME=${0##*/}
|
||||
APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit
|
||||
|
||||
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
|
||||
|
||||
# Use the maximum available, or set MAX_FD != -1 to use that value.
|
||||
MAX_FD=maximum
|
||||
|
||||
|
@ -133,10 +130,13 @@ location of your Java installation."
|
|||
fi
|
||||
else
|
||||
JAVACMD=java
|
||||
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
||||
if ! command -v java >/dev/null 2>&1
|
||||
then
|
||||
die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
||||
|
||||
Please set the JAVA_HOME variable in your environment to match the
|
||||
location of your Java installation."
|
||||
fi
|
||||
fi
|
||||
|
||||
# Increase the maximum file descriptors if we can.
|
||||
|
@ -144,7 +144,7 @@ if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
|
|||
case $MAX_FD in #(
|
||||
max*)
|
||||
# In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked.
|
||||
# shellcheck disable=SC3045
|
||||
# shellcheck disable=SC3045
|
||||
MAX_FD=$( ulimit -H -n ) ||
|
||||
warn "Could not query maximum file descriptor limit"
|
||||
esac
|
||||
|
@ -152,7 +152,7 @@ if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
|
|||
'' | soft) :;; #(
|
||||
*)
|
||||
# In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked.
|
||||
# shellcheck disable=SC3045
|
||||
# shellcheck disable=SC3045
|
||||
ulimit -n "$MAX_FD" ||
|
||||
warn "Could not set maximum file descriptor limit to $MAX_FD"
|
||||
esac
|
||||
|
@ -197,6 +197,10 @@ if "$cygwin" || "$msys" ; then
|
|||
done
|
||||
fi
|
||||
|
||||
|
||||
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
|
||||
|
||||
# Collect all arguments for the java command;
|
||||
# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of
|
||||
# shell script including quotes and variable substitutions, so put them in
|
||||
|
|
|
@ -3,8 +3,6 @@ package org.openstreetmap.josm.plugins.mapwithai;
|
|||
|
||||
import static org.openstreetmap.josm.tools.I18n.tr;
|
||||
|
||||
import javax.swing.JMenuItem;
|
||||
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
|
@ -12,6 +10,8 @@ import java.util.LinkedHashMap;
|
|||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.swing.JMenuItem;
|
||||
|
||||
import org.openstreetmap.josm.actions.JosmAction;
|
||||
import org.openstreetmap.josm.actions.PreferencesAction;
|
||||
import org.openstreetmap.josm.data.validation.OsmValidator;
|
||||
|
@ -29,6 +29,7 @@ import org.openstreetmap.josm.plugins.Plugin;
|
|||
import org.openstreetmap.josm.plugins.PluginInformation;
|
||||
import org.openstreetmap.josm.plugins.mapwithai.backend.DownloadListener;
|
||||
import org.openstreetmap.josm.plugins.mapwithai.backend.MapWithAIAction;
|
||||
import org.openstreetmap.josm.plugins.mapwithai.backend.MapWithAIDataUtils;
|
||||
import org.openstreetmap.josm.plugins.mapwithai.backend.MapWithAILayer;
|
||||
import org.openstreetmap.josm.plugins.mapwithai.backend.MapWithAIMoveAction;
|
||||
import org.openstreetmap.josm.plugins.mapwithai.backend.MapWithAIObject;
|
||||
|
@ -135,7 +136,8 @@ public final class MapWithAIPlugin extends Plugin implements Destroyable {
|
|||
MainApplication.worker.execute(() -> UpdateProd.doProd(info.mainversion));
|
||||
// Preload the MapWithAILayerInfo for the JOSM download window
|
||||
// This reduces the amount of time taken for first button click by 100ms.
|
||||
MainApplication.worker.execute(MapWithAILayerInfo::getInstance);
|
||||
// Don't use the worker thread to avoid blocking user downloads
|
||||
MapWithAIDataUtils.getForkJoinPool().execute(MapWithAILayerInfo::getInstance);
|
||||
|
||||
destroyables.add(new MapWithAICopyProhibit());
|
||||
}
|
||||
|
|
|
@ -84,10 +84,17 @@ public class AddMapWithAILayerAction extends JosmAction implements AdaptableActi
|
|||
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
if (!isEnabled()) {
|
||||
return;
|
||||
if (isEnabled()) {
|
||||
MainApplication.worker.execute(() -> realRun(this.info));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Run the download tasks. This should be run off of the EDT, see #23529.
|
||||
*
|
||||
* @param info The external data to download
|
||||
*/
|
||||
private static void realRun(MapWithAIInfo info) {
|
||||
MapWithAILayer layer = MapWithAIDataUtils.getLayer(false);
|
||||
final DataSet ds;
|
||||
final OsmData<?, ?, ?, ?> boundsSource;
|
||||
|
|
|
@ -23,11 +23,10 @@ import java.util.Comparator;
|
|||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.TimeoutException;
|
||||
import java.util.stream.IntStream;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import org.openstreetmap.gui.jmapviewer.interfaces.TileSource;
|
||||
import org.openstreetmap.josm.data.Bounds;
|
||||
|
@ -86,114 +85,6 @@ import jakarta.json.stream.JsonParser;
|
|||
* @author Taylor Smock
|
||||
*/
|
||||
public class BoundingBoxMapWithAIDownloader extends BoundingBoxDownloader {
|
||||
private record TileXYZ(int x, int y, int z) {
|
||||
/**
|
||||
* Checks to see if the given bounds are functionally equal to this tile
|
||||
*
|
||||
* @param left left
|
||||
* @param bottom bottom
|
||||
* @param right right
|
||||
* @param top top
|
||||
*/
|
||||
boolean checkBounds(double left, double bottom, double right, double top) {
|
||||
final var thisLeft = xToLongitude(this.x, this.z);
|
||||
final var thisRight = xToLongitude(this.x + 1, this.z);
|
||||
final var thisBottom = yToLatitude(this.y + 1, this.z);
|
||||
final var thisTop = yToLatitude(this.y, this.z);
|
||||
return equalsEpsilon(thisLeft, left, this.z) && equalsEpsilon(thisRight, right, this.z)
|
||||
&& equalsEpsilon(thisBottom, bottom, this.z) && equalsEpsilon(thisTop, top, this.z);
|
||||
}
|
||||
|
||||
private static boolean equalsEpsilon(double first, double second, int z) {
|
||||
// 0.1% of tile size is considered to be "equal"
|
||||
final var maxDiff = (360 / Math.pow(2, z)) / 1000;
|
||||
final var diff = Math.abs(first - second);
|
||||
return diff <= maxDiff;
|
||||
}
|
||||
|
||||
private static double xToLongitude(int x, int z) {
|
||||
return (x / Math.pow(2, z)) * 360 - 180;
|
||||
}
|
||||
|
||||
private static double yToLatitude(int y, int z) {
|
||||
var t = Math.PI - 2 * Math.PI * y / Math.pow(2, z);
|
||||
return 180 / Math.PI * Math.atan((Math.exp(t) - Math.exp(-t)) / 2);
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert bounds to tiles
|
||||
*
|
||||
* @param zoom The zoom level to use
|
||||
* @param bounds The bounds to convert to tiles
|
||||
* @return A stream of tiles for the bounds at the given zoom level
|
||||
*/
|
||||
private static Stream<TileXYZ> tilesFromBBox(int zoom, Bounds bounds) {
|
||||
final var left = bounds.getMinLon();
|
||||
final var bottom = bounds.getMinLat();
|
||||
final var right = bounds.getMaxLon();
|
||||
final var top = bounds.getMaxLat();
|
||||
final var tile1 = tileFromLatLonZoom(left, bottom, zoom);
|
||||
final var tile2 = tileFromLatLonZoom(right, top, zoom);
|
||||
return IntStream.rangeClosed(tile1.x, tile2.x)
|
||||
.mapToObj(x -> IntStream.rangeClosed(tile1.y, tile2.y).mapToObj(y -> new TileXYZ(x, y, zoom)))
|
||||
.flatMap(stream -> stream);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks to see if the given bounds are functionally equal to this tile
|
||||
*
|
||||
* @param left left lon
|
||||
* @param bottom bottom lat
|
||||
* @param right right lon
|
||||
* @param top top lat
|
||||
*/
|
||||
private static TileXYZ tileFromBBox(double left, double bottom, double right, double top) {
|
||||
var zoom = 18;
|
||||
while (zoom > 0) {
|
||||
final var tile1 = tileFromLatLonZoom(left, bottom, zoom);
|
||||
final var tile2 = tileFromLatLonZoom(right, top, zoom);
|
||||
if (tile1.equals(tile2)) {
|
||||
return tile1;
|
||||
} else if (tile1.checkBounds(left, bottom, right, top)) {
|
||||
return tile1;
|
||||
} else if (tile2.checkBounds(left, bottom, right, top)) {
|
||||
return tile2;
|
||||
// Just in case the coordinates are _barely_ in other tiles and not the "common"
|
||||
// tile
|
||||
} else if (Math.abs(tile1.x() - tile2.x()) <= 2 && Math.abs(tile1.y() - tile2.y()) <= 2) {
|
||||
final var tileT = new TileXYZ((tile1.x() + tile2.x()) / 2, (tile1.y() + tile2.y()) / 2, zoom);
|
||||
if (tileT.checkBounds(left, bottom, right, top)) {
|
||||
return tileT;
|
||||
}
|
||||
}
|
||||
zoom--;
|
||||
}
|
||||
return new TileXYZ(0, 0, 0);
|
||||
}
|
||||
|
||||
private static TileXYZ tileFromLatLonZoom(double lon, double lat, int zoom) {
|
||||
var xCoordinate = Math.toIntExact(Math.round(Math.floor(Math.pow(2, zoom) * (180 + lon) / 360)));
|
||||
var yCoordinate = Math.toIntExact(Math.round(Math.floor(Math.pow(2, zoom)
|
||||
* (1 - (Math.log(Math.tan(Math.toRadians(lat)) + 1 / Math.cos(Math.toRadians(lat))) / Math.PI))
|
||||
/ 2)));
|
||||
return new TileXYZ(xCoordinate, yCoordinate, zoom);
|
||||
}
|
||||
|
||||
/**
|
||||
* Extends a bounds object to contain this tile
|
||||
*
|
||||
* @param currentBounds The bounds to extend
|
||||
*/
|
||||
private void expandBounds(Bounds currentBounds) {
|
||||
final var thisLeft = xToLongitude(this.x, this.z);
|
||||
final var thisRight = xToLongitude(this.x + 1, this.z);
|
||||
final var thisBottom = yToLatitude(this.y + 1, this.z);
|
||||
final var thisTop = yToLatitude(this.y, this.z);
|
||||
currentBounds.extend(thisBottom, thisLeft);
|
||||
currentBounds.extend(thisTop, thisRight);
|
||||
}
|
||||
}
|
||||
|
||||
private final String url;
|
||||
private final boolean crop;
|
||||
private final int start;
|
||||
|
@ -240,14 +131,20 @@ public class BoundingBoxMapWithAIDownloader extends BoundingBoxDownloader {
|
|||
final var tile = TileXYZ.tileFromBBox(lon1, lat1, lon2, lat2);
|
||||
return getRequestForTile(tile);
|
||||
}
|
||||
return url.replace("{bbox}", Double.toString(lon1) + ',' + lat1 + ',' + lon2 + ',' + lat2)
|
||||
var current = url.replace("{bbox}", Double.toString(lon1) + ',' + lat1 + ',' + lon2 + ',' + lat2)
|
||||
.replace("{xmin}", Double.toString(lon1)).replace("{ymin}", Double.toString(lat1))
|
||||
.replace("{xmax}", Double.toString(lon2)).replace("{ymax}", Double.toString(lat2))
|
||||
+ (crop ? "&crop_bbox=" + DetectTaskingManagerUtils.getTaskingManagerBounds().toBBox().toStringCSV(",")
|
||||
: "")
|
||||
+ (this.info.getSourceType() == MapWithAIType.ESRI_FEATURE_SERVER && !this.info.isConflated()
|
||||
? "&resultOffset=" + this.start
|
||||
: "");
|
||||
.replace("{xmax}", Double.toString(lon2)).replace("{ymax}", Double.toString(lat2));
|
||||
boolean hasQuery = !Optional.ofNullable(URI.create(current).getRawQuery()).map(String::isEmpty).orElse(true);
|
||||
|
||||
if (crop) {
|
||||
current += (hasQuery ? '&' : '?') + "crop_bbox="
|
||||
+ DetectTaskingManagerUtils.getTaskingManagerBounds().toBBox().toStringCSV(",");
|
||||
hasQuery = true;
|
||||
}
|
||||
if (this.info.getSourceType() == MapWithAIType.ESRI_FEATURE_SERVER && !this.info.isConflated()) {
|
||||
current += (hasQuery ? '&' : '?') + "resultOffset=" + this.start;
|
||||
}
|
||||
return current;
|
||||
}
|
||||
|
||||
private String getRequestForTile(TileXYZ tile) {
|
||||
|
@ -440,19 +337,22 @@ public class BoundingBoxMapWithAIDownloader extends BoundingBoxDownloader {
|
|||
}
|
||||
ds = new DataSet();
|
||||
final var currentBounds = new Bounds(this.downloadArea);
|
||||
progressMonitor.beginTask(tr("Downloading data"), 2 * tiles.size());
|
||||
for (TileXYZ tileXYZ : tiles) {
|
||||
try {
|
||||
final var hilbert = PMTiles.convertToHilbert(tileXYZ.z(), tileXYZ.x(), tileXYZ.y());
|
||||
final var data = this.info.getSourceType() == MapWithAIType.PMTILES
|
||||
? new ByteArrayInputStream(PMTiles.readData(header, hilbert, cachedDirectories))
|
||||
: getInputStream(getRequestForTile(tileXYZ), progressMonitor);
|
||||
: getInputStream(getRequestForTile(tileXYZ), progressMonitor.createSubTaskMonitor(1, true));
|
||||
final var dataSet = loadTile(tileSource, tileXYZ, data);
|
||||
ds.mergeFrom(dataSet, progressMonitor);
|
||||
ds.mergeFrom(dataSet, progressMonitor.createSubTaskMonitor(1, true));
|
||||
tileXYZ.expandBounds(currentBounds);
|
||||
} catch (OsmTransferException | IOException e) {
|
||||
progressMonitor.finishTask();
|
||||
throw new IllegalDataException(e);
|
||||
}
|
||||
}
|
||||
progressMonitor.finishTask();
|
||||
ds.addDataSource(new DataSource(currentBounds, this.url));
|
||||
return ds;
|
||||
}
|
||||
|
|
|
@ -36,7 +36,6 @@ public class DataAvailability {
|
|||
static final Map<String, String> POSSIBLE_DATA_POINTS = new TreeMap<>();
|
||||
|
||||
private static final String PROVIDES = "provides";
|
||||
private static final String EMPTY_STRING = "";
|
||||
private static final int SEVEN_DAYS_IN_SECONDS = 604_800;
|
||||
|
||||
/**
|
||||
|
@ -150,7 +149,7 @@ public class DataAvailability {
|
|||
* @return A string that doesn't have quotes at the beginning or end
|
||||
*/
|
||||
public static String stripQuotes(String string) {
|
||||
return string.replaceAll("((^\")|(\"$))", EMPTY_STRING);
|
||||
return string.replaceAll("((^\")|(\"$))", "");
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -224,7 +223,7 @@ public class DataAvailability {
|
|||
* @return The url or ""
|
||||
*/
|
||||
public String getTermsOfUseUrl() {
|
||||
return EMPTY_STRING;
|
||||
return "";
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -247,11 +246,10 @@ public class DataAvailability {
|
|||
DATA_SOURCES.stream().map(clazz -> {
|
||||
try {
|
||||
return clazz.getConstructor().newInstance().getTermsOfUseUrl();
|
||||
} catch (InstantiationException | IllegalAccessException | IllegalArgumentException
|
||||
| InvocationTargetException | NoSuchMethodException | SecurityException e) {
|
||||
} catch (ReflectiveOperationException e) {
|
||||
Logging.debug(e);
|
||||
}
|
||||
return EMPTY_STRING;
|
||||
return "";
|
||||
})).filter(Objects::nonNull).filter(str -> !Utils.removeWhiteSpaces(str).isEmpty())
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
@ -267,11 +265,10 @@ public class DataAvailability {
|
|||
DATA_SOURCES.stream().map(clazz -> {
|
||||
try {
|
||||
return clazz.getConstructor().newInstance().getPrivacyPolicyUrl();
|
||||
} catch (InstantiationException | IllegalAccessException | IllegalArgumentException
|
||||
| InvocationTargetException | NoSuchMethodException | SecurityException e) {
|
||||
} catch (ReflectiveOperationException e) {
|
||||
Logging.debug(e);
|
||||
}
|
||||
return EMPTY_STRING;
|
||||
return "";
|
||||
}))
|
||||
.filter(Objects::nonNull).filter(str -> !Utils.removeWhiteSpaces(str).isEmpty()).distinct()
|
||||
.collect(Collectors.toList());
|
||||
|
|
|
@ -219,9 +219,7 @@ public class GetDataRunnable extends RecursiveTask<DataSet> {
|
|||
if (!monitor.isCanceled()) {
|
||||
if (bounds.size() == MAX_NUMBER_OF_BBOXES_TO_PROCESS) {
|
||||
final var temporaryDataSet = getDataReal(bounds.get(0), monitor);
|
||||
synchronized (this.dataSet) {
|
||||
dataSet.mergeFrom(temporaryDataSet);
|
||||
}
|
||||
this.dataSet.update(() -> dataSet.mergeFrom(temporaryDataSet));
|
||||
} else {
|
||||
final Collection<GetDataRunnable> tasks = bounds.stream()
|
||||
.map(bound -> new GetDataRunnable(bound, dataSet, monitor.createSubTaskMonitor(0, true)))
|
||||
|
@ -250,10 +248,10 @@ public class GetDataRunnable extends RecursiveTask<DataSet> {
|
|||
* @param info The information used to download the data
|
||||
*/
|
||||
public static void cleanup(DataSet dataSet, Bounds bounds, MapWithAIInfo info) {
|
||||
realCleanup(dataSet, bounds, info);
|
||||
dataSet.update(() -> realCleanup(dataSet, bounds, info));
|
||||
}
|
||||
|
||||
private static synchronized void realCleanup(DataSet dataSet, Bounds bounds, MapWithAIInfo info) {
|
||||
private static void realCleanup(DataSet dataSet, Bounds bounds, MapWithAIInfo info) {
|
||||
final Bounds boundsToUse;
|
||||
if (bounds == null && !dataSet.getDataSourceBounds().isEmpty()) {
|
||||
boundsToUse = new Bounds(dataSet.getDataSourceBounds().get(0));
|
||||
|
@ -277,7 +275,7 @@ public class GetDataRunnable extends RecursiveTask<DataSet> {
|
|||
}
|
||||
(boundsToUse.isCollapsed() || boundsToUse.isOutOfTheWorld() ? dataSet.getWays()
|
||||
: dataSet.searchWays(boundsToUse.toBBox())).stream().filter(way -> !way.isDeleted())
|
||||
.forEach(GetDataRunnable::cleanupArtifacts);
|
||||
.forEach(GetDataRunnable::cleanupArtifacts);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -18,6 +18,7 @@ import java.util.Optional;
|
|||
import java.util.TreeSet;
|
||||
import java.util.concurrent.ForkJoinPool;
|
||||
import java.util.concurrent.ForkJoinTask;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.openstreetmap.josm.data.Bounds;
|
||||
|
@ -213,37 +214,26 @@ public final class MapWithAIDataUtils {
|
|||
}
|
||||
}
|
||||
|
||||
private static boolean confirmBigDownload(List<Bounds> realBounds) {
|
||||
final var confirmation = new ConfirmBigDownload(realBounds);
|
||||
GuiHelper.runInEDTAndWait(confirmation);
|
||||
return confirmation.confirmed();
|
||||
}
|
||||
|
||||
private static class ConfirmBigDownload implements Runnable {
|
||||
Boolean bool;
|
||||
final List<?> realBounds;
|
||||
|
||||
public ConfirmBigDownload(List<?> realBounds) {
|
||||
this.realBounds = realBounds;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
bool = ConditionalOptionPaneUtil.showConfirmationDialog(MapWithAIPlugin.NAME.concat(".alwaysdownload"),
|
||||
null,
|
||||
/**
|
||||
* Confirm a large download
|
||||
*
|
||||
* @param realBounds The list of bounds that will be downloaded
|
||||
* @return {@code true} if the user still wants to download data
|
||||
*/
|
||||
private static synchronized boolean confirmBigDownload(List<Bounds> realBounds) {
|
||||
final var confirmation = new AtomicBoolean(false);
|
||||
// This is not a separate class since we don't want to show multiple
|
||||
// confirmation dialogs
|
||||
// which is why this method is synchronized.
|
||||
GuiHelper.runInEDTAndWait(() -> {
|
||||
final var confirmed = ConditionalOptionPaneUtil.showConfirmationDialog(
|
||||
MapWithAIPlugin.NAME.concat(".alwaysdownload"), null,
|
||||
tr("You are going to make {0} requests to the MapWithAI server. This may take some time. <br /> Continue?",
|
||||
realBounds.size()),
|
||||
null, JOptionPane.YES_NO_CANCEL_OPTION, JOptionPane.WARNING_MESSAGE, JOptionPane.YES_OPTION);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the user confirmed the download
|
||||
*
|
||||
* @return {@code true} if the user wants to continue
|
||||
*/
|
||||
public boolean confirmed() {
|
||||
return bool;
|
||||
}
|
||||
confirmation.set(confirmed);
|
||||
});
|
||||
return confirmation.get();
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -320,21 +320,21 @@ public class MapWithAILayer extends OsmDataLayer implements ActiveLayerChangeLis
|
|||
private record OsmComparator(
|
||||
Collection<OsmPrimitive> previousSelection) implements Comparator<OsmPrimitive>, Serializable {
|
||||
|
||||
@Override
|
||||
public int compare(OsmPrimitive o1, OsmPrimitive o2) {
|
||||
if (previousSelection.contains(o1) == previousSelection.contains(o2)) {
|
||||
if (o1.isTagged() == o2.isTagged()) {
|
||||
return o1.compareTo(o2);
|
||||
} else if (o1.isTagged()) {
|
||||
return -1;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
if (previousSelection.contains(o1)) {
|
||||
@Override
|
||||
public int compare(OsmPrimitive o1, OsmPrimitive o2) {
|
||||
if (previousSelection.contains(o1) == previousSelection.contains(o2)) {
|
||||
if (o1.isTagged() == o2.isTagged()) {
|
||||
return o1.compareTo(o2);
|
||||
} else if (o1.isTagged()) {
|
||||
return -1;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
if (previousSelection.contains(o1)) {
|
||||
return -1;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,121 @@
|
|||
// License: GPL. For details, see LICENSE file.
|
||||
package org.openstreetmap.josm.plugins.mapwithai.backend;
|
||||
|
||||
import java.util.stream.IntStream;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import org.openstreetmap.josm.data.Bounds;
|
||||
|
||||
/**
|
||||
* Create a tile
|
||||
*
|
||||
* @param x The x coordinate of the tile
|
||||
* @param y The y coordinate of the tile
|
||||
* @param z The zoom level
|
||||
*/
|
||||
record TileXYZ(int x, int y, int z) {
|
||||
/**
|
||||
* Checks to see if the given bounds are functionally equal to this tile
|
||||
*
|
||||
* @param left left
|
||||
* @param bottom bottom
|
||||
* @param right right
|
||||
* @param top top
|
||||
*/
|
||||
boolean checkBounds(double left, double bottom, double right, double top) {
|
||||
final var thisLeft = xToLongitude(this.x, this.z);
|
||||
final var thisRight = xToLongitude(this.x + 1, this.z);
|
||||
final var thisBottom = yToLatitude(this.y + 1, this.z);
|
||||
final var thisTop = yToLatitude(this.y, this.z);
|
||||
return equalsEpsilon(thisLeft, left, this.z) && equalsEpsilon(thisRight, right, this.z)
|
||||
&& equalsEpsilon(thisBottom, bottom, this.z) && equalsEpsilon(thisTop, top, this.z);
|
||||
}
|
||||
|
||||
private static boolean equalsEpsilon(double first, double second, int z) {
|
||||
// 0.1% of tile size is considered to be "equal"
|
||||
final var maxDiff = (360 / Math.pow(2, z)) / 1000;
|
||||
final var diff = Math.abs(first - second);
|
||||
return diff <= maxDiff;
|
||||
}
|
||||
|
||||
private static double xToLongitude(int x, int z) {
|
||||
return (x / Math.pow(2, z)) * 360 - 180;
|
||||
}
|
||||
|
||||
private static double yToLatitude(int y, int z) {
|
||||
var t = Math.PI - 2 * Math.PI * y / Math.pow(2, z);
|
||||
return 180 / Math.PI * Math.atan((Math.exp(t) - Math.exp(-t)) / 2);
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert bounds to tiles
|
||||
*
|
||||
* @param zoom The zoom level to use
|
||||
* @param bounds The bounds to convert to tiles
|
||||
* @return A stream of tiles for the bounds at the given zoom level
|
||||
*/
|
||||
static Stream<TileXYZ> tilesFromBBox(int zoom, Bounds bounds) {
|
||||
final var left = bounds.getMinLon();
|
||||
final var bottom = bounds.getMinLat();
|
||||
final var right = bounds.getMaxLon();
|
||||
final var top = bounds.getMaxLat();
|
||||
final var tile1 = tileFromLatLonZoom(left, bottom, zoom);
|
||||
final var tile2 = tileFromLatLonZoom(right, top, zoom);
|
||||
return IntStream.rangeClosed(tile1.x, tile2.x)
|
||||
.mapToObj(x -> IntStream.rangeClosed(tile2.y, tile1.y).mapToObj(y -> new TileXYZ(x, y, zoom)))
|
||||
.flatMap(stream -> stream);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks to see if the given bounds are functionally equal to this tile
|
||||
*
|
||||
* @param left left lon
|
||||
* @param bottom bottom lat
|
||||
* @param right right lon
|
||||
* @param top top lat
|
||||
*/
|
||||
static TileXYZ tileFromBBox(double left, double bottom, double right, double top) {
|
||||
var zoom = 18;
|
||||
while (zoom > 0) {
|
||||
final var tile1 = tileFromLatLonZoom(left, bottom, zoom);
|
||||
final var tile2 = tileFromLatLonZoom(right, top, zoom);
|
||||
if (tile1.equals(tile2)) {
|
||||
return tile1;
|
||||
} else if (tile1.checkBounds(left, bottom, right, top)) {
|
||||
return tile1;
|
||||
} else if (tile2.checkBounds(left, bottom, right, top)) {
|
||||
return tile2;
|
||||
// Just in case the coordinates are _barely_ in other tiles and not the "common"
|
||||
// tile
|
||||
} else if (Math.abs(tile1.x() - tile2.x()) <= 2 && Math.abs(tile1.y() - tile2.y()) <= 2) {
|
||||
final var tileT = new TileXYZ((tile1.x() + tile2.x()) / 2, (tile1.y() + tile2.y()) / 2, zoom);
|
||||
if (tileT.checkBounds(left, bottom, right, top)) {
|
||||
return tileT;
|
||||
}
|
||||
}
|
||||
zoom--;
|
||||
}
|
||||
return new TileXYZ(0, 0, 0);
|
||||
}
|
||||
|
||||
static TileXYZ tileFromLatLonZoom(double lon, double lat, int zoom) {
|
||||
var xCoordinate = Math.toIntExact(Math.round(Math.floor(Math.pow(2, zoom) * (180 + lon) / 360)));
|
||||
var yCoordinate = Math.toIntExact(Math.round(Math.floor(Math.pow(2, zoom)
|
||||
* (1 - (Math.log(Math.tan(Math.toRadians(lat)) + 1 / Math.cos(Math.toRadians(lat))) / Math.PI)) / 2)));
|
||||
return new TileXYZ(xCoordinate, yCoordinate, zoom);
|
||||
}
|
||||
|
||||
/**
|
||||
* Extends a bounds object to contain this tile
|
||||
*
|
||||
* @param currentBounds The bounds to extend
|
||||
*/
|
||||
void expandBounds(Bounds currentBounds) {
|
||||
final var thisLeft = xToLongitude(this.x, this.z);
|
||||
final var thisRight = xToLongitude(this.x + 1, this.z);
|
||||
final var thisBottom = yToLatitude(this.y + 1, this.z);
|
||||
final var thisTop = yToLatitude(this.y, this.z);
|
||||
currentBounds.extend(thisBottom, thisLeft);
|
||||
currentBounds.extend(thisTop, thisRight);
|
||||
}
|
||||
}
|
|
@ -3,12 +3,9 @@ package org.openstreetmap.josm.plugins.mapwithai.commands;
|
|||
|
||||
import static org.openstreetmap.josm.tools.I18n.tr;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import org.openstreetmap.josm.command.Command;
|
||||
|
@ -17,6 +14,8 @@ import org.openstreetmap.josm.data.osm.OsmPrimitive;
|
|||
import org.openstreetmap.josm.data.osm.Relation;
|
||||
import org.openstreetmap.josm.data.osm.Way;
|
||||
|
||||
import jakarta.annotation.Nullable;
|
||||
|
||||
/**
|
||||
* This is similar to the ReplaceGeometryUtils.buildUpgradeNodeCommand method
|
||||
*
|
||||
|
@ -46,19 +45,19 @@ public final class MergeBuildingNodeCommand {
|
|||
|
||||
private static Node getNewOrNoTagNode(OsmPrimitive referenceObject) {
|
||||
List<Node> nodes;
|
||||
if (referenceObject instanceof Way) {
|
||||
nodes = ((Way) referenceObject).getNodes();
|
||||
} else if (referenceObject instanceof Relation) {
|
||||
nodes = ((Relation) referenceObject).getMemberPrimitives().stream().flatMap(o -> {
|
||||
if (o instanceof Way) {
|
||||
return ((Way) o).getNodes().stream();
|
||||
} else if (o instanceof Node) {
|
||||
return Stream.of((Node) o);
|
||||
if (referenceObject instanceof Way way) {
|
||||
nodes = way.getNodes();
|
||||
} else if (referenceObject instanceof Relation relation) {
|
||||
nodes = relation.getMemberPrimitives().stream().flatMap(o -> {
|
||||
if (o instanceof Way way) {
|
||||
return way.getNodes().stream();
|
||||
} else if (o instanceof Node node) {
|
||||
return Stream.of(node);
|
||||
}
|
||||
return null;
|
||||
}).filter(Objects::nonNull).collect(Collectors.toList());
|
||||
} else if (referenceObject instanceof Node) {
|
||||
nodes = Collections.singletonList((Node) referenceObject);
|
||||
}).filter(Objects::nonNull).toList();
|
||||
} else if (referenceObject instanceof Node node) {
|
||||
nodes = Collections.singletonList(node);
|
||||
} else {
|
||||
throw new IllegalArgumentException(tr("Unknown OsmPrimitive type"));
|
||||
}
|
||||
|
|
|
@ -3,15 +3,11 @@ package org.openstreetmap.josm.plugins.mapwithai.commands;
|
|||
|
||||
import static org.openstreetmap.josm.tools.I18n.tr;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.List;
|
||||
|
@ -34,6 +30,9 @@ import org.openstreetmap.josm.plugins.mapwithai.backend.MapWithAIPreferenceHelpe
|
|||
import org.openstreetmap.josm.tools.Logging;
|
||||
import org.openstreetmap.josm.tools.Pair;
|
||||
|
||||
import jakarta.annotation.Nonnull;
|
||||
import jakarta.annotation.Nullable;
|
||||
|
||||
/**
|
||||
* Merge duplicate ways
|
||||
*/
|
||||
|
@ -83,7 +82,7 @@ public class MergeDuplicateWays extends Command {
|
|||
* @param way2 The second way
|
||||
*/
|
||||
public MergeDuplicateWays(DataSet data, Way way1, Way way2) {
|
||||
this(data, Stream.of(way1, way2).filter(Objects::nonNull).collect(Collectors.toList()));
|
||||
this(data, Stream.of(way1, way2).filter(Objects::nonNull).toList());
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -94,7 +93,7 @@ public class MergeDuplicateWays extends Command {
|
|||
*/
|
||||
public MergeDuplicateWays(DataSet data, List<Way> ways) {
|
||||
super(data);
|
||||
this.ways = ways.stream().filter(MergeDuplicateWays::nonDeletedWay).collect(Collectors.toList());
|
||||
this.ways = ways.stream().filter(MergeDuplicateWays::nonDeletedWay).toList();
|
||||
this.commands = new ArrayList<>();
|
||||
}
|
||||
|
||||
|
@ -110,11 +109,11 @@ public class MergeDuplicateWays extends Command {
|
|||
} else if (ways.size() == 1) {
|
||||
checkForDuplicateWays(ways.get(0), commands);
|
||||
} else {
|
||||
Iterator<Way> it = ways.iterator();
|
||||
Way way1 = it.next();
|
||||
final var it = ways.iterator();
|
||||
var way1 = it.next();
|
||||
while (it.hasNext()) {
|
||||
Way way2 = it.next();
|
||||
final Command tCommand = checkForDuplicateWays(way1, way2);
|
||||
final var way2 = it.next();
|
||||
final var tCommand = checkForDuplicateWays(way1, way2);
|
||||
if (tCommand != null) {
|
||||
commands.add(tCommand);
|
||||
tCommand.executeCommand();
|
||||
|
@ -122,8 +121,7 @@ public class MergeDuplicateWays extends Command {
|
|||
way1 = way2;
|
||||
}
|
||||
}
|
||||
final List<Command> realCommands = commands.stream().filter(Objects::nonNull).distinct()
|
||||
.collect(Collectors.toList());
|
||||
final List<Command> realCommands = commands.stream().filter(Objects::nonNull).distinct().toList();
|
||||
commands.clear();
|
||||
commands.addAll(realCommands);
|
||||
if (!commands.isEmpty() && (commands.size() != 1)) {
|
||||
|
@ -165,14 +163,13 @@ public class MergeDuplicateWays extends Command {
|
|||
final List<Way> ways = (bound == null ? dataSet.getWays() : dataSet.searchWays(bound.toBBox())).stream()
|
||||
.filter(prim -> !prim.isIncomplete() && !prim.isDeleted())
|
||||
.collect(Collectors.toCollection(ArrayList::new));
|
||||
for (int i = 0; i < ways.size(); i++) {
|
||||
final Way way1 = ways.get(i);
|
||||
final Collection<Way> nearbyWays = dataSet.searchWays(way1.getBBox()).stream()
|
||||
.filter(MergeDuplicateWays::nonDeletedWay).collect(Collectors.toList());
|
||||
nearbyWays.remove(way1);
|
||||
for (var i = 0; i < ways.size(); i++) {
|
||||
final var way1 = ways.get(i);
|
||||
final var nearbyWays = dataSet.searchWays(way1.getBBox()).stream().filter(MergeDuplicateWays::nonDeletedWay)
|
||||
.filter(w -> !Objects.equals(w, way1)).toList();
|
||||
for (final Way way2 : nearbyWays) {
|
||||
final Command command = checkForDuplicateWays(way1, way2);
|
||||
final Collection<OsmPrimitive> deletedWays = new ArrayList<>();
|
||||
final var command = checkForDuplicateWays(way1, way2);
|
||||
final var deletedWays = new ArrayList<OsmPrimitive>();
|
||||
if (command != null) {
|
||||
commands.add(command);
|
||||
command.executeCommand();
|
||||
|
@ -194,11 +191,10 @@ public class MergeDuplicateWays extends Command {
|
|||
*/
|
||||
public static void checkForDuplicateWays(Way way, List<Command> commands) {
|
||||
final Collection<Way> nearbyWays = way.getDataSet().searchWays(way.getBBox()).stream()
|
||||
.filter(MergeDuplicateWays::nonDeletedWay).collect(Collectors.toList());
|
||||
nearbyWays.remove(way);
|
||||
.filter(MergeDuplicateWays::nonDeletedWay).filter(w -> !Objects.equals(w, way)).toList();
|
||||
for (final Way way2 : nearbyWays) {
|
||||
if (!way2.isDeleted()) {
|
||||
final Command tCommand = checkForDuplicateWays(way, way2);
|
||||
final var tCommand = checkForDuplicateWays(way, way2);
|
||||
if (tCommand != null) {
|
||||
commands.add(tCommand);
|
||||
tCommand.executeCommand();
|
||||
|
@ -230,10 +226,8 @@ public class MergeDuplicateWays extends Command {
|
|||
Logging.error("{0}", way2);
|
||||
}
|
||||
if ((compressed.size() > 1) && duplicateEntrySet.stream().noneMatch(entry -> entry.getValue().size() > 1)) {
|
||||
final List<Integer> initial = compressed.stream().map(entry -> entry.a.a).sorted()
|
||||
.collect(Collectors.toList());
|
||||
final List<Integer> after = compressed.stream().map(entry -> entry.b.a).sorted()
|
||||
.collect(Collectors.toList());
|
||||
final var initial = compressed.stream().map(entry -> entry.a.a).sorted().toList();
|
||||
final var after = compressed.stream().map(entry -> entry.b.a).sorted().toList();
|
||||
if (sorted(initial) && sorted(after)) {
|
||||
returnCommand = mergeWays(way1, way2, compressed);
|
||||
}
|
||||
|
@ -278,12 +272,12 @@ public class MergeDuplicateWays extends Command {
|
|||
}
|
||||
}
|
||||
Collections.reverse(before);
|
||||
final Way newWay = new Way(way1);
|
||||
final var newWay = new Way(way1);
|
||||
List<Command> commands = new ArrayList<>();
|
||||
before.forEach(node -> newWay.addNode(0, node));
|
||||
after.forEach(newWay::addNode);
|
||||
if (newWay.getNodesCount() > 0) {
|
||||
final ChangeCommand changeCommand = new ChangeCommand(way1, newWay);
|
||||
final var changeCommand = new ChangeCommand(way1, newWay);
|
||||
commands.add(changeCommand);
|
||||
/*
|
||||
* This must be executed, otherwise the delete command will believe that way2
|
||||
|
@ -315,8 +309,8 @@ public class MergeDuplicateWays extends Command {
|
|||
* @return The node that the param {@code node} duplicates
|
||||
*/
|
||||
public static Node nodeInCompressed(Node node, Set<Pair<Pair<Integer, Node>, Pair<Integer, Node>>> compressed) {
|
||||
Node returnNode = node;
|
||||
for (final Pair<Pair<Integer, Node>, Pair<Integer, Node>> pair : compressed) {
|
||||
var returnNode = node;
|
||||
for (final var pair : compressed) {
|
||||
if (node.equals(pair.a.b)) {
|
||||
returnNode = pair.b.b;
|
||||
} else if (node.equals(pair.b.b)) {
|
||||
|
@ -326,26 +320,26 @@ public class MergeDuplicateWays extends Command {
|
|||
break;
|
||||
}
|
||||
}
|
||||
final Node tReturnNode = returnNode;
|
||||
final var tReturnNode = returnNode;
|
||||
node.getKeys().forEach(tReturnNode::put);
|
||||
return returnNode;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the node pairs increment in the same direction (only checks first
|
||||
* two pairs), ensure that they are sorted with {@link sorted}
|
||||
* two pairs), ensure that they are sorted with {@link #sorted}
|
||||
*
|
||||
* @param compressed The set of duplicate node/placement pairs
|
||||
* @return true if the node pairs increment in the same direction
|
||||
*/
|
||||
public static boolean checkDirection(Set<Pair<Pair<Integer, Node>, Pair<Integer, Node>>> compressed) {
|
||||
final Iterator<Pair<Pair<Integer, Node>, Pair<Integer, Node>>> iterator = compressed.iterator();
|
||||
boolean returnValue = false;
|
||||
final var iterator = compressed.iterator();
|
||||
var returnValue = false;
|
||||
if (compressed.size() > 1) {
|
||||
final Pair<Pair<Integer, Node>, Pair<Integer, Node>> first = iterator.next();
|
||||
final Pair<Pair<Integer, Node>, Pair<Integer, Node>> second = iterator.next();
|
||||
final boolean way1Forward = first.a.a < second.a.a;
|
||||
final boolean way2Forward = first.b.a < second.b.a;
|
||||
final var first = iterator.next();
|
||||
final var second = iterator.next();
|
||||
final var way1Forward = first.a.a < second.a.a;
|
||||
final var way2Forward = first.b.a < second.b.a;
|
||||
returnValue = way1Forward == way2Forward;
|
||||
}
|
||||
return returnValue;
|
||||
|
@ -358,10 +352,10 @@ public class MergeDuplicateWays extends Command {
|
|||
* @return true if there are no gaps and it increases
|
||||
*/
|
||||
public static boolean sorted(List<Integer> collection) {
|
||||
boolean returnValue = true;
|
||||
var returnValue = true;
|
||||
if (collection.size() > 1) {
|
||||
Integer last = collection.get(0);
|
||||
for (int i = 1; i < collection.size(); i++) {
|
||||
for (var i = 1; i < collection.size(); i++) {
|
||||
final Integer next = collection.get(i);
|
||||
if ((next - last) != 1) {
|
||||
returnValue = false;
|
||||
|
@ -381,17 +375,16 @@ public class MergeDuplicateWays extends Command {
|
|||
* @return A map of node -> node(s) duplicates
|
||||
*/
|
||||
public static Map<Pair<Integer, Node>, Map<Integer, Node>> getDuplicateNodes(Way way1, Way way2) {
|
||||
final Map<Pair<Integer, Node>, Map<Integer, Node>> duplicateNodes = new LinkedHashMap<>();
|
||||
for (int j = 0; j < way1.getNodesCount(); j++) {
|
||||
final Node origNode = way1.getNode(j);
|
||||
for (int k = 0; k < way2.getNodesCount(); k++) {
|
||||
final Node possDupeNode = way2.getNode(k);
|
||||
final var duplicateNodes = new LinkedHashMap<Pair<Integer, Node>, Map<Integer, Node>>();
|
||||
for (var j = 0; j < way1.getNodesCount(); j++) {
|
||||
final var origNode = way1.getNode(j);
|
||||
for (var k = 0; k < way2.getNodesCount(); k++) {
|
||||
final var possDupeNode = way2.getNode(k);
|
||||
if (origNode.equals(possDupeNode) || (origNode
|
||||
.greatCircleDistance(possDupeNode) < MapWithAIPreferenceHelper.getMaxNodeDistance())) {
|
||||
final Pair<Integer, Node> origNodePair = new Pair<>(j, origNode);
|
||||
final Map<Integer, Node> dupeNodeMap = duplicateNodes.getOrDefault(origNodePair, new HashMap<>());
|
||||
final var origNodePair = new Pair<>(j, origNode);
|
||||
final var dupeNodeMap = duplicateNodes.computeIfAbsent(origNodePair, ignored -> new HashMap<>());
|
||||
dupeNodeMap.put(k, possDupeNode);
|
||||
duplicateNodes.put(origNodePair, dupeNodeMap);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,9 +3,7 @@ package org.openstreetmap.josm.plugins.mapwithai.data.mapwithai;
|
|||
|
||||
import static org.openstreetmap.josm.tools.I18n.marktr;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.swing.ImageIcon;
|
||||
|
||||
import java.io.Serial;
|
||||
import java.io.Serializable;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
|
@ -13,11 +11,15 @@ import java.util.EnumMap;
|
|||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.swing.ImageIcon;
|
||||
|
||||
import org.openstreetmap.josm.data.sources.ISourceCategory;
|
||||
import org.openstreetmap.josm.gui.tagging.presets.TaggingPresets;
|
||||
import org.openstreetmap.josm.tools.ImageProvider;
|
||||
import org.openstreetmap.josm.tools.ImageProvider.ImageSizes;
|
||||
|
||||
import jakarta.annotation.Nonnull;
|
||||
|
||||
/**
|
||||
* The category for a MapWithAI source (i.e., buildings/highways/addresses/etc.)
|
||||
*
|
||||
|
@ -26,12 +28,12 @@ import org.openstreetmap.josm.tools.ImageProvider.ImageSizes;
|
|||
*/
|
||||
public enum MapWithAICategory implements ISourceCategory<MapWithAICategory> {
|
||||
|
||||
BUILDING("data/closedway", "buildings", marktr("Buildings")),
|
||||
HIGHWAY("presets/transport/way/way_road", "highways", marktr("Roads")),
|
||||
ADDRESS("presets/misc/housenumber_small", "addresses", marktr("Addresses")),
|
||||
POWER("presets/power/pole", "pole", marktr("Power")), PRESET("dialogs/search", "presets", marktr("Presets")),
|
||||
FEATURED("presets/service/network-wireless", "featured", marktr("Featured")),
|
||||
PREVIEW("presets/misc/fixme", "preview", marktr("Preview")), OTHER(null, "other", marktr("Other"));
|
||||
BUILDING("data/closedway", "buildings", marktr("Buildings")), HIGHWAY("presets/transport/way/way_road", "highways",
|
||||
marktr("Roads")), ADDRESS("presets/misc/housenumber_small", "addresses",
|
||||
marktr("Addresses")), POWER("presets/power/pole", "pole", marktr("Power")), PRESET("dialogs/search",
|
||||
"presets", marktr("Presets")), FEATURED("presets/service/network-wireless", "featured",
|
||||
marktr("Featured")), PREVIEW("presets/misc/fixme", "preview",
|
||||
marktr("Preview")), OTHER(null, "other", marktr("Other"));
|
||||
|
||||
private static final Map<ImageSizes, Map<MapWithAICategory, ImageIcon>> iconCache = Collections
|
||||
.synchronizedMap(new EnumMap<>(ImageSizes.class));
|
||||
|
@ -98,6 +100,7 @@ public enum MapWithAICategory implements ISourceCategory<MapWithAICategory> {
|
|||
*/
|
||||
public static class DescriptionComparator implements Comparator<MapWithAICategory>, Serializable {
|
||||
|
||||
@Serial
|
||||
private static final long serialVersionUID = 9131636715279880580L;
|
||||
|
||||
@Override
|
||||
|
|
|
@ -3,9 +3,6 @@ package org.openstreetmap.josm.plugins.mapwithai.data.mapwithai;
|
|||
|
||||
import static org.openstreetmap.josm.tools.I18n.tr;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.swing.SwingUtilities;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.Serial;
|
||||
import java.time.Instant;
|
||||
|
@ -25,6 +22,8 @@ import java.util.concurrent.ForkJoinTask;
|
|||
import java.util.concurrent.RecursiveTask;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
||||
import javax.swing.SwingUtilities;
|
||||
|
||||
import org.openstreetmap.gui.jmapviewer.tilesources.TileSourceInfo;
|
||||
import org.openstreetmap.josm.actions.ExpertToggleAction;
|
||||
import org.openstreetmap.josm.data.Preferences;
|
||||
|
@ -48,6 +47,8 @@ import org.openstreetmap.josm.tools.ListenerList;
|
|||
import org.openstreetmap.josm.tools.Logging;
|
||||
import org.openstreetmap.josm.tools.Utils;
|
||||
|
||||
import jakarta.annotation.Nonnull;
|
||||
|
||||
/**
|
||||
* Manages the list of imagery entries that are shown in the imagery menu.
|
||||
*/
|
||||
|
@ -97,8 +98,10 @@ public class MapWithAILayerInfo {
|
|||
}
|
||||
// Avoid a deadlock in the EDT.
|
||||
if (!finished.get() && !SwingUtilities.isEventDispatchThread()) {
|
||||
var count = 0;
|
||||
synchronized (MapWithAILayerInfo.class) {
|
||||
while (!finished.get()) {
|
||||
while (!finished.get() && count < 120) {
|
||||
count++;
|
||||
try {
|
||||
MapWithAILayerInfo.class.wait(1000);
|
||||
} catch (InterruptedException e) {
|
||||
|
@ -210,9 +213,13 @@ public class MapWithAILayerInfo {
|
|||
if (this.finishListenerListenerList == null) {
|
||||
this.finishListenerListenerList = ListenerList.create();
|
||||
}
|
||||
boolean running = this.finishListenerListenerList.hasListeners();
|
||||
if (listener != null) {
|
||||
this.finishListenerListenerList.addListener(listener);
|
||||
}
|
||||
if (running) {
|
||||
return;
|
||||
}
|
||||
if (worker == null) {
|
||||
final var pleaseWaitRunnable = new PleaseWaitRunnable(tr("Update default entries")) {
|
||||
@Override
|
||||
|
@ -280,8 +287,8 @@ public class MapWithAILayerInfo {
|
|||
}
|
||||
// This is literally to avoid allocations on startup
|
||||
final Preferences preferences;
|
||||
if (Config.getPref() instanceof Preferences) {
|
||||
preferences = (Preferences) Config.getPref();
|
||||
if (Config.getPref()instanceof Preferences pref) {
|
||||
preferences = pref;
|
||||
} else {
|
||||
preferences = null;
|
||||
}
|
||||
|
@ -339,11 +346,12 @@ public class MapWithAILayerInfo {
|
|||
* @param layers The layers to update
|
||||
*/
|
||||
private void updateEsriLayers(@Nonnull final Collection<MapWithAIInfo> layers) {
|
||||
final var esriInfo = new ArrayList<MapWithAIInfo>(300);
|
||||
for (var layer : layers) {
|
||||
if (MapWithAIType.ESRI == layer.getSourceType()) {
|
||||
for (var future : parseEsri(layer)) {
|
||||
try {
|
||||
allDefaultLayers.add(future.get());
|
||||
esriInfo.add(future.get());
|
||||
} catch (InterruptedException e) {
|
||||
Logging.error(e);
|
||||
Thread.currentThread().interrupt();
|
||||
|
@ -352,9 +360,10 @@ public class MapWithAILayerInfo {
|
|||
}
|
||||
}
|
||||
} else {
|
||||
allDefaultLayers.add(layer);
|
||||
esriInfo.add(layer);
|
||||
}
|
||||
}
|
||||
layers.addAll(esriInfo);
|
||||
}
|
||||
|
||||
protected void finish() {
|
||||
|
@ -362,7 +371,7 @@ public class MapWithAILayerInfo {
|
|||
synchronized (allDefaultLayers) {
|
||||
allDefaultLayers.clear();
|
||||
defaultLayers.addAll(newLayers);
|
||||
this.updateEsriLayers(newLayers);
|
||||
allDefaultLayers.addAll(newLayers);
|
||||
allDefaultLayers.sort(new MapWithAIInfo.MapWithAIInfoCategoryComparator());
|
||||
allDefaultLayers.sort(Comparator.comparing(TileSourceInfo::getName));
|
||||
allDefaultLayers.sort(Comparator.comparing(info -> info.getCategory().getDescription()));
|
||||
|
@ -498,7 +507,7 @@ public class MapWithAILayerInfo {
|
|||
}
|
||||
|
||||
if (changed) {
|
||||
save();
|
||||
MainApplication.worker.execute(this::save);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,18 +1,18 @@
|
|||
// License: GPL. For details, see LICENSE file.
|
||||
package org.openstreetmap.josm.plugins.mapwithai.data.mapwithai;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
|
||||
import org.openstreetmap.josm.data.sources.ISourceType;
|
||||
|
||||
import jakarta.annotation.Nonnull;
|
||||
|
||||
/**
|
||||
* Type of MapWithAI entry
|
||||
*
|
||||
* @author Taylor Smock
|
||||
*/
|
||||
public enum MapWithAIType implements ISourceType<MapWithAIType> {
|
||||
FACEBOOK("facebook"), THIRD_PARTY("thirdParty"), ESRI("esri"), ESRI_FEATURE_SERVER("esriFeatureServer"),
|
||||
MAPBOX_VECTOR_TILE("mvt"), PMTILES("pmtiles");
|
||||
FACEBOOK("facebook"), THIRD_PARTY("thirdParty"), ESRI("esri"), ESRI_FEATURE_SERVER(
|
||||
"esriFeatureServer"), MAPBOX_VECTOR_TILE("mvt"), PMTILES("pmtiles");
|
||||
|
||||
private final String typeString;
|
||||
|
||||
|
|
|
@ -4,9 +4,6 @@ package org.openstreetmap.josm.plugins.mapwithai.data.validation.tests;
|
|||
import static org.openstreetmap.josm.tools.I18n.marktr;
|
||||
import static org.openstreetmap.josm.tools.I18n.tr;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
|
@ -33,6 +30,9 @@ import org.openstreetmap.josm.plugins.mapwithai.tools.Access;
|
|||
import org.openstreetmap.josm.spi.preferences.Config;
|
||||
import org.openstreetmap.josm.tools.Pair;
|
||||
|
||||
import jakarta.annotation.Nonnull;
|
||||
import jakarta.annotation.Nullable;
|
||||
|
||||
/**
|
||||
* A test for routing islands
|
||||
*
|
||||
|
@ -179,9 +179,11 @@ public class RoutingIslandsTest extends Test {
|
|||
.filter(way -> !incomingWays.contains(way) || !outgoingWays.contains(way))
|
||||
.filter(way -> Access.getPositiveAccessValues().contains(
|
||||
getDefaultAccessTags(way).getOrDefault(currentTransportMode, Access.AccessTags.NO.getKey())))
|
||||
.collect(Collectors.toSet())).stream()
|
||||
.map(way -> new Pair<>((incomingWays.containsAll(way) ? marktr("outgoing") : marktr("incoming")), way))
|
||||
.collect(Collectors.toList());
|
||||
.collect(Collectors.toSet()))
|
||||
.stream()
|
||||
.map(way -> new Pair<>(
|
||||
(incomingWays.containsAll(way) ? marktr("outgoing") : marktr("incoming")), way))
|
||||
.toList();
|
||||
createErrors(problematic, currentTransportMode);
|
||||
}
|
||||
|
||||
|
@ -198,9 +200,9 @@ public class RoutingIslandsTest extends Test {
|
|||
private static void findConnectedWays(String currentTransportMode, Collection<Way> potentialWays,
|
||||
Collection<Way> incomingWays, Collection<Way> outgoingWays) {
|
||||
potentialWays.stream().filter(Way::isUsable).filter(Way::isOutsideDownloadArea).forEach(way -> {
|
||||
Node firstNode = firstNode(way, currentTransportMode);
|
||||
Node lastNode = lastNode(way, currentTransportMode);
|
||||
Integer isOneway = isOneway(way, currentTransportMode);
|
||||
final var firstNode = firstNode(way, currentTransportMode);
|
||||
final var lastNode = lastNode(way, currentTransportMode);
|
||||
final var isOneway = isOneway(way, currentTransportMode);
|
||||
if (firstNode != null && firstNode.isOutsideDownloadArea()) {
|
||||
incomingWays.add(way);
|
||||
}
|
||||
|
@ -223,14 +225,14 @@ public class RoutingIslandsTest extends Test {
|
|||
* @return a list of sets of ways that are connected
|
||||
*/
|
||||
private static List<Set<Way>> collectConnected(Collection<Way> ways) {
|
||||
ArrayList<Set<Way>> collected = new ArrayList<>();
|
||||
ArrayList<Way> listOfWays = new ArrayList<>(ways);
|
||||
final int maxLoop = Config.getPref().getInt("validator.routingislands.maxrecursion", MAX_LOOPS);
|
||||
for (int i = 0; i < listOfWays.size(); i++) {
|
||||
Way initial = listOfWays.get(i);
|
||||
final var collected = new ArrayList<Set<Way>>();
|
||||
final var listOfWays = new ArrayList<>(ways);
|
||||
final var maxLoop = Config.getPref().getInt("validator.routingislands.maxrecursion", MAX_LOOPS);
|
||||
for (var i = 0; i < listOfWays.size(); i++) {
|
||||
final var initial = listOfWays.get(i);
|
||||
Set<Way> connected = new HashSet<>();
|
||||
connected.add(initial);
|
||||
int loopCounter = 0;
|
||||
var loopCounter = 0;
|
||||
while (!getConnected(connected) && loopCounter < maxLoop) {
|
||||
loopCounter++;
|
||||
}
|
||||
|
@ -281,8 +283,8 @@ public class RoutingIslandsTest extends Test {
|
|||
*/
|
||||
public static void checkForUnconnectedWays(Collection<Way> incoming, Collection<Way> outgoing,
|
||||
String currentTransportMode) {
|
||||
int loopCount = 0;
|
||||
int maxLoops = Config.getPref().getInt("validator.routingislands.maxrecursion", MAX_LOOPS);
|
||||
var loopCount = 0;
|
||||
var maxLoops = Config.getPref().getInt("validator.routingislands.maxrecursion", MAX_LOOPS);
|
||||
do {
|
||||
loopCount++;
|
||||
} while (loopCount <= maxLoops && getWaysFor(incoming, currentTransportMode,
|
||||
|
@ -325,11 +327,10 @@ public class RoutingIslandsTest extends Test {
|
|||
* clean up and work with via ways
|
||||
*/
|
||||
public static boolean checkAccessibility(Way from, Way to, String currentTransportMode) {
|
||||
boolean isAccessible = true;
|
||||
var isAccessible = true;
|
||||
|
||||
List<Relation> relations = from.getReferrers().stream().distinct().filter(Relation.class::isInstance)
|
||||
.map(Relation.class::cast).filter(relation -> "restriction".equals(relation.get("type")))
|
||||
.collect(Collectors.toList());
|
||||
.map(Relation.class::cast).filter(relation -> "restriction".equals(relation.get("type"))).toList();
|
||||
for (Relation relation : relations) {
|
||||
if (((relation.hasKey("except") && relation.get("except").contains(currentTransportMode))
|
||||
|| (currentTransportMode == null || currentTransportMode.trim().isEmpty()))
|
||||
|
@ -432,7 +433,7 @@ public class RoutingIslandsTest extends Test {
|
|||
* @return The map of access tags to access
|
||||
*/
|
||||
public static TagMap getDefaultAccessTags(OsmPrimitive primitive) {
|
||||
TagMap access = new TagMap();
|
||||
final var access = new TagMap();
|
||||
final TagMap tags;
|
||||
if (primitive.hasKey(HIGHWAY)) {
|
||||
tags = getDefaultHighwayAccessTags(primitive.getKeys());
|
||||
|
@ -451,13 +452,9 @@ public class RoutingIslandsTest extends Test {
|
|||
}
|
||||
|
||||
private static String getCachedDirectionMode(String direction, String mode) {
|
||||
if (!DIRECTION_MAP.containsKey(direction)) {
|
||||
DIRECTION_MAP.put(direction, new HashMap<>(Access.getTransportModes().size()));
|
||||
}
|
||||
DIRECTION_MAP.computeIfAbsent(direction, d -> new HashMap<>(Access.getTransportModes().size()));
|
||||
final var directionMap = DIRECTION_MAP.get(direction);
|
||||
if (!directionMap.containsKey(mode)) {
|
||||
directionMap.put(mode, direction.concat(mode));
|
||||
}
|
||||
directionMap.computeIfAbsent(mode, direction::concat);
|
||||
return directionMap.get(mode);
|
||||
}
|
||||
|
||||
|
|
|
@ -4,22 +4,6 @@ package org.openstreetmap.josm.plugins.mapwithai.gui.preferences.mapwithai;
|
|||
import static org.openstreetmap.josm.tools.I18n.marktr;
|
||||
import static org.openstreetmap.josm.tools.I18n.tr;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.swing.AbstractAction;
|
||||
import javax.swing.Box;
|
||||
import javax.swing.JButton;
|
||||
import javax.swing.JComponent;
|
||||
import javax.swing.JLabel;
|
||||
import javax.swing.JOptionPane;
|
||||
import javax.swing.JPanel;
|
||||
import javax.swing.JScrollPane;
|
||||
import javax.swing.JTable;
|
||||
import javax.swing.JToolBar;
|
||||
import javax.swing.UIManager;
|
||||
import javax.swing.event.ListSelectionEvent;
|
||||
import javax.swing.event.ListSelectionListener;
|
||||
import javax.swing.table.DefaultTableCellRenderer;
|
||||
|
||||
import java.awt.Color;
|
||||
import java.awt.Component;
|
||||
import java.awt.Dimension;
|
||||
|
@ -43,6 +27,22 @@ import java.util.function.Function;
|
|||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import javax.swing.AbstractAction;
|
||||
import javax.swing.Box;
|
||||
import javax.swing.JButton;
|
||||
import javax.swing.JComponent;
|
||||
import javax.swing.JLabel;
|
||||
import javax.swing.JOptionPane;
|
||||
import javax.swing.JPanel;
|
||||
import javax.swing.JScrollPane;
|
||||
import javax.swing.JTable;
|
||||
import javax.swing.JToolBar;
|
||||
import javax.swing.SwingConstants;
|
||||
import javax.swing.UIManager;
|
||||
import javax.swing.event.ListSelectionEvent;
|
||||
import javax.swing.event.ListSelectionListener;
|
||||
import javax.swing.table.DefaultTableCellRenderer;
|
||||
|
||||
import org.openstreetmap.gui.jmapviewer.Coordinate;
|
||||
import org.openstreetmap.gui.jmapviewer.MapPolygonImpl;
|
||||
import org.openstreetmap.gui.jmapviewer.MapRectangleImpl;
|
||||
|
@ -52,6 +52,7 @@ import org.openstreetmap.josm.data.Bounds;
|
|||
import org.openstreetmap.josm.data.coor.LatLon;
|
||||
import org.openstreetmap.josm.data.preferences.NamedColorProperty;
|
||||
import org.openstreetmap.josm.gui.MainApplication;
|
||||
import org.openstreetmap.josm.gui.bbox.JosmMapViewer;
|
||||
import org.openstreetmap.josm.gui.bbox.SlippyMapBBoxChooser;
|
||||
import org.openstreetmap.josm.gui.preferences.imagery.ImageryProvidersPanel;
|
||||
import org.openstreetmap.josm.gui.util.GuiHelper;
|
||||
|
@ -72,6 +73,8 @@ import org.openstreetmap.josm.tools.ListenerList;
|
|||
import org.openstreetmap.josm.tools.Logging;
|
||||
import org.openstreetmap.josm.tools.OpenBrowser;
|
||||
|
||||
import jakarta.annotation.Nonnull;
|
||||
|
||||
/**
|
||||
* A panel displaying imagery providers. Largely duplicates
|
||||
* {@link ImageryProvidersPanel}.
|
||||
|
@ -376,7 +379,7 @@ public class MapWithAIProvidersPanel extends JPanel {
|
|||
|
||||
// Add default item map
|
||||
defaultMap = new SlippyMapBBoxChooser();
|
||||
defaultMap.setTileSource(SlippyMapBBoxChooser.DefaultOsmTileSourceProvider.get()); // for attribution
|
||||
defaultMap.setTileSource(JosmMapViewer.DefaultOsmTileSourceProvider.get()); // for attribution
|
||||
defaultMap.addMouseListener(new MouseAdapter() {
|
||||
@Override
|
||||
public void mouseClicked(MouseEvent e) {
|
||||
|
@ -408,36 +411,36 @@ public class MapWithAIProvidersPanel extends JPanel {
|
|||
defaultTableListener = new DefListSelectionListener();
|
||||
defaultTable.getSelectionModel().addListSelectionListener(defaultTableListener);
|
||||
|
||||
defaultToolbar = new JToolBar(JToolBar.VERTICAL);
|
||||
defaultToolbar = new JToolBar(SwingConstants.VERTICAL);
|
||||
defaultToolbar.setFloatable(false);
|
||||
defaultToolbar.setBorderPainted(false);
|
||||
defaultToolbar.setOpaque(false);
|
||||
defaultToolbar.add(new ReloadAction());
|
||||
add(defaultToolbar, GBC.eol().anchor(GBC.SOUTH).insets(0, 0, 5, 0));
|
||||
add(defaultToolbar, GBC.eol().anchor(GridBagConstraints.SOUTH).insets(0, 0, 5, 0));
|
||||
|
||||
final var help = new HtmlPanel(
|
||||
tr("New default entries can be added in the <a href=\"{0}\">GitHub Repository</a>.",
|
||||
"https://github.com/JOSM/MapWithAI/blob/pages/json/sources.json"));
|
||||
help.enableClickableHyperlinks();
|
||||
add(help, GBC.eol().insets(10, 0, 0, 0).fill(GBC.HORIZONTAL));
|
||||
add(help, GBC.eol().insets(10, 0, 0, 0).fill(GridBagConstraints.HORIZONTAL));
|
||||
|
||||
final var activate = new ActivateAction();
|
||||
defaultTable.getSelectionModel().addListSelectionListener(activate);
|
||||
final var btnActivate = new JButton(activate);
|
||||
|
||||
middleToolbar = new JToolBar(JToolBar.HORIZONTAL);
|
||||
middleToolbar = new JToolBar(SwingConstants.HORIZONTAL);
|
||||
middleToolbar.setFloatable(false);
|
||||
middleToolbar.setBorderPainted(false);
|
||||
middleToolbar.setOpaque(false);
|
||||
middleToolbar.add(btnActivate);
|
||||
add(middleToolbar, GBC.eol().anchor(GBC.CENTER).insets(5, 5, 5, 0));
|
||||
add(middleToolbar, GBC.eol().anchor(GridBagConstraints.CENTER).insets(5, 5, 5, 0));
|
||||
|
||||
add(Box.createHorizontalGlue(), GBC.eol().fill(GridBagConstraints.HORIZONTAL));
|
||||
|
||||
final var scroll = new JScrollPane(activeTable);
|
||||
scroll.setPreferredSize(new Dimension(200, 200));
|
||||
|
||||
activeToolbar = new JToolBar(JToolBar.VERTICAL);
|
||||
activeToolbar = new JToolBar(SwingConstants.VERTICAL);
|
||||
activeToolbar.setFloatable(false);
|
||||
activeToolbar.setBorderPainted(false);
|
||||
activeToolbar.setOpaque(false);
|
||||
|
@ -448,7 +451,7 @@ public class MapWithAIProvidersPanel extends JPanel {
|
|||
add(new JLabel(tr("Selected entries:")), GBC.eol().insets(5, 0, 0, 0));
|
||||
add(scroll, GBC.std().fill(GridBagConstraints.BOTH).span(GridBagConstraints.RELATIVE).weight(1.0, 0.4)
|
||||
.insets(5, 0, 0, 5));
|
||||
add(activeToolbar, GBC.eol().anchor(GBC.NORTH).insets(0, 0, 5, 5));
|
||||
add(activeToolbar, GBC.eol().anchor(GridBagConstraints.NORTH).insets(0, 0, 5, 5));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -500,7 +503,7 @@ public class MapWithAIProvidersPanel extends JPanel {
|
|||
* @param e The MouseEvent (used to get the appropriate JTable)
|
||||
*/
|
||||
private static void clickListener(MouseEvent e) {
|
||||
if (e.getSource() instanceof JTable table && table.getSelectedRow() >= 0 && table.getSelectedColumn() >= 0) {
|
||||
if (e.getSource()instanceof JTable table && table.getSelectedRow() >= 0 && table.getSelectedColumn() >= 0) {
|
||||
final int realCol = table.convertColumnIndexToModel(table.getSelectedColumn());
|
||||
final int realRow = table.convertRowIndexToModel(table.getSelectedRow());
|
||||
final var tableName = table.getModel().getColumnName(realCol);
|
||||
|
|
|
@ -1,9 +1,6 @@
|
|||
// License: GPL. For details, see LICENSE file.
|
||||
package org.openstreetmap.josm.plugins.mapwithai.io.mapwithai;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
|
@ -36,6 +33,8 @@ import org.openstreetmap.josm.spi.preferences.Config;
|
|||
import org.openstreetmap.josm.tools.HttpClient;
|
||||
import org.openstreetmap.josm.tools.Logging;
|
||||
|
||||
import jakarta.annotation.Nonnull;
|
||||
import jakarta.annotation.Nullable;
|
||||
import jakarta.json.Json;
|
||||
import jakarta.json.JsonArray;
|
||||
import jakarta.json.JsonNumber;
|
||||
|
@ -55,6 +54,7 @@ public class ESRISourceReader {
|
|||
/** The cache storing ESRI source information (json) */
|
||||
public static final CacheAccess<String, String> SOURCE_CACHE = JCSCacheManager.getCache("mapwithai:esrisources", 5,
|
||||
50_000, new File(Config.getDirs().getCacheDirectory(true), "mapwithai").getPath());
|
||||
private static final String ACCESS_INFORMATION = "accessInformation";
|
||||
private final MapWithAIInfo source;
|
||||
private boolean fastFail;
|
||||
private final List<MapWithAICategory> ignoreConflationCategories;
|
||||
|
@ -119,10 +119,10 @@ public class ESRISourceReader {
|
|||
/* Do nothing */
|
||||
if (parser.hasNext() && parser.next() == JsonParser.Event.START_OBJECT) {
|
||||
parser.getObjectStream().forEach(entry -> {
|
||||
if ("nextStart".equals(entry.getKey()) && entry.getValue() instanceof JsonNumber number) {
|
||||
if ("nextStart".equals(entry.getKey()) && entry.getValue()instanceof JsonNumber number) {
|
||||
next.set(number.intValue());
|
||||
searchUrl.set(startReplace.matcher(search).replaceAll(Integer.toString(next.get())));
|
||||
} else if ("results".equals(entry.getKey()) && entry.getValue() instanceof JsonArray features) {
|
||||
} else if ("results".equals(entry.getKey()) && entry.getValue()instanceof JsonArray features) {
|
||||
for (var feature : features.getValuesAs(JsonObject.class)) {
|
||||
information.add(parse(feature));
|
||||
}
|
||||
|
@ -187,9 +187,9 @@ public class ESRISourceReader {
|
|||
if (this.ignoreConflationCategories.contains(newInfo.getCategory())) {
|
||||
newInfo.setConflation(false);
|
||||
}
|
||||
if (feature.containsKey("accessInformation")
|
||||
&& feature.get("accessInformation").getValueType() != JsonValue.ValueType.NULL) {
|
||||
newInfo.setAttributionText(feature.getString("accessInformation"));
|
||||
if (feature.containsKey(ACCESS_INFORMATION)
|
||||
&& feature.get(ACCESS_INFORMATION).getValueType() != JsonValue.ValueType.NULL) {
|
||||
newInfo.setAttributionText(feature.getString(ACCESS_INFORMATION));
|
||||
}
|
||||
newInfo.setDescription(feature.getString("snippet"));
|
||||
if (newInfo.getSource() != null) {
|
||||
|
|
|
@ -60,12 +60,13 @@ public final class MapPaintUtils {
|
|||
* Safe colors
|
||||
*/
|
||||
public enum SafeColors {
|
||||
RED(Color.RED), ORANGE(Color.ORANGE), GOLD(Objects.requireNonNull(ColorHelper.html2color("#ffd700"))),
|
||||
LIME(Objects.requireNonNull(ColorHelper.html2color("#00ff00"))), CYAN(Color.CYAN),
|
||||
DODGER_BLUE(Objects.requireNonNull(ColorHelper.html2color("#1e90ff"))),
|
||||
AI_MAGENTA(Objects.requireNonNull(ColorHelper.html2color("#ff26d4"))), PINK(Color.PINK),
|
||||
LIGHT_GREY(Objects.requireNonNull(ColorHelper.html2color("#d3d3d3"))),
|
||||
LINEN(Objects.requireNonNull(ColorHelper.html2color("#faf0e6")));
|
||||
RED(Color.RED), ORANGE(Color.ORANGE), GOLD(Objects.requireNonNull(ColorHelper.html2color("#ffd700"))), LIME(
|
||||
Objects.requireNonNull(ColorHelper.html2color("#00ff00"))), CYAN(Color.CYAN), DODGER_BLUE(
|
||||
Objects.requireNonNull(ColorHelper.html2color("#1e90ff"))), AI_MAGENTA(
|
||||
Objects.requireNonNull(ColorHelper.html2color("#ff26d4"))), PINK(
|
||||
Color.PINK), LIGHT_GREY(
|
||||
Objects.requireNonNull(ColorHelper.html2color("#d3d3d3"))), LINEN(
|
||||
Objects.requireNonNull(ColorHelper.html2color("#faf0e6")));
|
||||
|
||||
private final Color color;
|
||||
|
||||
|
|
|
@ -4,14 +4,11 @@ package org.openstreetmap.josm.plugins.mapwithai.actions;
|
|||
import static org.junit.jupiter.api.Assertions.assertArrayEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
|
||||
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||
import static org.junit.jupiter.api.Assertions.assertInstanceOf;
|
||||
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||
import static org.junit.jupiter.api.Assertions.assertNull;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
import javax.imageio.ImageIO;
|
||||
import javax.swing.Action;
|
||||
import javax.swing.ImageIcon;
|
||||
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
|
@ -19,20 +16,22 @@ import java.util.ArrayList;
|
|||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.logging.Handler;
|
||||
import java.util.logging.LogRecord;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.awaitility.Awaitility;
|
||||
import org.awaitility.Durations;
|
||||
import javax.imageio.ImageIO;
|
||||
import javax.swing.Action;
|
||||
import javax.swing.ImageIcon;
|
||||
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.RegisterExtension;
|
||||
import org.openstreetmap.josm.data.Bounds;
|
||||
import org.openstreetmap.josm.data.DataSource;
|
||||
import org.openstreetmap.josm.data.osm.DataSet;
|
||||
import org.openstreetmap.josm.gui.MainApplication;
|
||||
import org.openstreetmap.josm.gui.layer.OsmDataLayer;
|
||||
import org.openstreetmap.josm.gui.util.GuiHelper;
|
||||
import org.openstreetmap.josm.plugins.mapwithai.backend.MapWithAIDataUtils;
|
||||
import org.openstreetmap.josm.plugins.mapwithai.backend.MapWithAILayer;
|
||||
import org.openstreetmap.josm.plugins.mapwithai.data.mapwithai.MapWithAIInfo;
|
||||
|
@ -41,17 +40,19 @@ import org.openstreetmap.josm.plugins.mapwithai.data.mapwithai.MapWithAIType;
|
|||
import org.openstreetmap.josm.plugins.mapwithai.testutils.annotations.MapWithAISources;
|
||||
import org.openstreetmap.josm.plugins.mapwithai.testutils.annotations.NoExceptions;
|
||||
import org.openstreetmap.josm.testutils.annotations.BasicPreferences;
|
||||
import org.openstreetmap.josm.testutils.annotations.BasicWiremock;
|
||||
import org.openstreetmap.josm.testutils.annotations.Projection;
|
||||
import org.openstreetmap.josm.testutils.annotations.ThreadSync;
|
||||
import org.openstreetmap.josm.tools.ImageProvider;
|
||||
import org.openstreetmap.josm.tools.Logging;
|
||||
|
||||
import com.github.tomakehurst.wiremock.WireMockServer;
|
||||
import com.github.tomakehurst.wiremock.client.WireMock;
|
||||
import com.github.tomakehurst.wiremock.core.WireMockConfiguration;
|
||||
import com.github.tomakehurst.wiremock.matching.AnythingPattern;
|
||||
import com.github.tomakehurst.wiremock.matching.EqualToPattern;
|
||||
import com.github.tomakehurst.wiremock.matching.StringValuePattern;
|
||||
import com.github.tomakehurst.wiremock.matching.UrlPathPattern;
|
||||
import jakarta.json.Json;
|
||||
|
||||
/**
|
||||
* Test class for {@link AddMapWithAILayerAction}
|
||||
|
@ -63,11 +64,47 @@ import com.github.tomakehurst.wiremock.matching.UrlPathPattern;
|
|||
@MapWithAISources
|
||||
@Projection
|
||||
class AddMapWithAILayerActionTest {
|
||||
@Test
|
||||
void testAddMapWithAILayerActionTest() {
|
||||
MapWithAIInfo info = MapWithAILayerInfo.getInstance().getLayers().stream()
|
||||
|
||||
private static class ThreadSyncMWAI extends ThreadSync.ThreadSyncExtension {
|
||||
public ThreadSyncMWAI() {
|
||||
this.registerForkJoinPool(MapWithAIDataUtils.getForkJoinPool());
|
||||
}
|
||||
}
|
||||
|
||||
@RegisterExtension
|
||||
static ThreadSyncMWAI threadSync = new ThreadSyncMWAI();
|
||||
|
||||
@BasicWiremock
|
||||
WireMockServer wireMockServer;
|
||||
|
||||
private static MapWithAIInfo info;
|
||||
private static MapWithAIInfo backupInfo;
|
||||
|
||||
@BeforeEach
|
||||
void setup() {
|
||||
final Map<String, StringValuePattern> parameterMap = new HashMap<>();
|
||||
final AnythingPattern anythingPattern = new AnythingPattern();
|
||||
parameterMap.put("geometryType", anythingPattern);
|
||||
parameterMap.put("geometry", anythingPattern);
|
||||
parameterMap.put("inSR", new EqualToPattern("4326"));
|
||||
parameterMap.put("f", new EqualToPattern("geojson"));
|
||||
parameterMap.put("outfields", new EqualToPattern("*"));
|
||||
parameterMap.put("result_type", new EqualToPattern("road_building_vector_xml"));
|
||||
parameterMap.put("resultOffset", anythingPattern);
|
||||
wireMockServer.stubFor(
|
||||
WireMock.get(new UrlPathPattern(new EqualToPattern("/query"), false)).withQueryParams(parameterMap)
|
||||
.willReturn(WireMock.aResponse()
|
||||
.withBody(Json.createObjectBuilder().add("type", "FeatureCollection")
|
||||
.add("features", Json.createArrayBuilder().build()).build().toString()))
|
||||
.atPriority(Integer.MIN_VALUE));
|
||||
info = MapWithAILayerInfo.getInstance().getLayers().stream()
|
||||
.filter(i -> i.getName().equalsIgnoreCase("MapWithAI")).findAny().orElse(null);
|
||||
assertNotNull(info);
|
||||
info = new MapWithAIInfo(info);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testAddMapWithAILayerActionTest() {
|
||||
AddMapWithAILayerAction action = new AddMapWithAILayerAction(info);
|
||||
assertDoesNotThrow(() -> action.actionPerformed(null));
|
||||
OsmDataLayer osmLayer = new OsmDataLayer(new DataSet(), "TEST DATA", null);
|
||||
|
@ -78,7 +115,7 @@ class AddMapWithAILayerActionTest {
|
|||
assertNull(MapWithAIDataUtils.getLayer(false));
|
||||
action.updateEnabledState();
|
||||
action.actionPerformed(null);
|
||||
Awaitility.await().atMost(Durations.FIVE_SECONDS).until(() -> MapWithAIDataUtils.getLayer(false) != null);
|
||||
threadSync.threadSync();
|
||||
assertNotNull(MapWithAIDataUtils.getLayer(false));
|
||||
|
||||
MainApplication.getLayerManager().removeLayer(MapWithAIDataUtils.getLayer(false));
|
||||
|
@ -90,7 +127,7 @@ class AddMapWithAILayerActionTest {
|
|||
|
||||
action.updateEnabledState();
|
||||
action.actionPerformed(null);
|
||||
Awaitility.await().atMost(Durations.FIVE_SECONDS).until(() -> !layer.getDataSet().isEmpty());
|
||||
threadSync.threadSync();
|
||||
assertFalse(layer.getDataSet().isEmpty());
|
||||
|
||||
MainApplication.getLayerManager().removeLayer(MapWithAIDataUtils.getLayer(false));
|
||||
|
@ -100,69 +137,40 @@ class AddMapWithAILayerActionTest {
|
|||
mapwithaiLayer.getDataSet()
|
||||
.addDataSource(new DataSource(new Bounds(39.095376, -108.4495519, 39.0987811, -108.4422314), ""));
|
||||
action.actionPerformed(null);
|
||||
Awaitility.await().atMost(Durations.FIVE_SECONDS).until(() -> !mapwithaiLayer.getDataSet().isEmpty());
|
||||
threadSync.threadSync();
|
||||
assertFalse(mapwithaiLayer.getDataSet().isEmpty());
|
||||
}
|
||||
|
||||
@Test
|
||||
void testRemoteIcon() throws IOException, ExecutionException, InterruptedException {
|
||||
void testRemoteIcon() throws IOException {
|
||||
final ImageIcon blankImage = ImageProvider.createBlankIcon(ImageProvider.ImageSizes.LARGEICON);
|
||||
final ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
|
||||
// BufferedImage is what the current implementation uses. Otherwise, we will
|
||||
// have to copy it into a BufferedImage.
|
||||
assertTrue(blankImage.getImage() instanceof BufferedImage);
|
||||
final BufferedImage bi = (BufferedImage) blankImage.getImage();
|
||||
final BufferedImage bi = assertInstanceOf(BufferedImage.class, blankImage.getImage());
|
||||
ImageIO.write(bi, "png", byteArrayOutputStream);
|
||||
byte[] originalImage = byteArrayOutputStream.toByteArray();
|
||||
final WireMockServer wireMockServer = new WireMockServer(WireMockConfiguration.options().dynamicPort());
|
||||
try {
|
||||
wireMockServer.start();
|
||||
wireMockServer.addStubMapping(wireMockServer
|
||||
.stubFor(WireMock.get("/icon").willReturn(WireMock.aResponse().withBody(originalImage))));
|
||||
final MapWithAIInfo info = MapWithAILayerInfo.getInstance().getLayers().stream()
|
||||
.filter(i -> i.getName().equalsIgnoreCase("MapWithAI")).findAny().orElse(null);
|
||||
assertNotNull(info);
|
||||
final MapWithAIInfo remoteInfo = new MapWithAIInfo(info);
|
||||
remoteInfo.setIcon(wireMockServer.baseUrl() + "/icon");
|
||||
final AddMapWithAILayerAction action = new AddMapWithAILayerAction(remoteInfo);
|
||||
GuiHelper.runInEDTAndWait(() -> {
|
||||
/* Sync EDT */});
|
||||
MainApplication.worker.submit(() -> {
|
||||
/* Sync worker thread */}).get();
|
||||
final Object image = action.getValue(Action.LARGE_ICON_KEY);
|
||||
assertTrue(image instanceof ImageIcon);
|
||||
final ImageIcon attachedIcon = (ImageIcon) image;
|
||||
assertTrue(attachedIcon.getImage() instanceof BufferedImage);
|
||||
byteArrayOutputStream.reset();
|
||||
ImageIO.write((BufferedImage) attachedIcon.getImage(), "png", byteArrayOutputStream);
|
||||
final byte[] downloadedImage = byteArrayOutputStream.toByteArray();
|
||||
assertArrayEquals(originalImage, downloadedImage);
|
||||
} finally {
|
||||
wireMockServer.stop();
|
||||
}
|
||||
wireMockServer.addStubMapping(
|
||||
wireMockServer.stubFor(WireMock.get("/icon").willReturn(WireMock.aResponse().withBody(originalImage))));
|
||||
final MapWithAIInfo remoteInfo = new MapWithAIInfo(info);
|
||||
remoteInfo.setIcon(wireMockServer.baseUrl() + "/icon");
|
||||
final AddMapWithAILayerAction action = new AddMapWithAILayerAction(remoteInfo);
|
||||
threadSync.threadSync();
|
||||
final Object image = action.getValue(Action.LARGE_ICON_KEY);
|
||||
final ImageIcon attachedIcon = assertInstanceOf(ImageIcon.class, image);
|
||||
final BufferedImage bufferedImage = assertInstanceOf(BufferedImage.class, attachedIcon.getImage());
|
||||
byteArrayOutputStream.reset();
|
||||
ImageIO.write(bufferedImage, "png", byteArrayOutputStream);
|
||||
final byte[] downloadedImage = byteArrayOutputStream.toByteArray();
|
||||
assertArrayEquals(originalImage, downloadedImage);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testNonRegression22683() throws ExecutionException, InterruptedException {
|
||||
final MapWithAIInfo info = MapWithAILayerInfo.getInstance().getLayers().stream()
|
||||
.filter(i -> i.getName().equalsIgnoreCase("MapWithAI")).findAny().orElse(null);
|
||||
assertNotNull(info);
|
||||
void testNonRegression22683() {
|
||||
final OsmDataLayer layer = new OsmDataLayer(new DataSet(), "testNonRegression22683", null);
|
||||
layer.getDataSet().addDataSource(new DataSource(new Bounds(0, 0, 0.001, 0.001), "Area 1"));
|
||||
layer.getDataSet().addDataSource(new DataSource(new Bounds(-0.001, -0.001, 0, 0), "Area 2"));
|
||||
MainApplication.getLayerManager().addLayer(layer);
|
||||
final WireMockServer server = new WireMockServer(WireMockConfiguration.options().dynamicPort());
|
||||
final Map<String, StringValuePattern> parameterMap = new HashMap<>();
|
||||
final AnythingPattern anythingPattern = new AnythingPattern();
|
||||
parameterMap.put("geometryType", anythingPattern);
|
||||
parameterMap.put("geometry", anythingPattern);
|
||||
parameterMap.put("inSR", new EqualToPattern("4326"));
|
||||
parameterMap.put("f", new EqualToPattern("geojson"));
|
||||
parameterMap.put("outfields", new EqualToPattern("*"));
|
||||
parameterMap.put("result_type", new EqualToPattern("road_building_vector_xml"));
|
||||
parameterMap.put("resultOffset", anythingPattern);
|
||||
server.stubFor(WireMock.get(new UrlPathPattern(new EqualToPattern("/query"), false))
|
||||
.withQueryParams(parameterMap).willReturn(WireMock.aResponse().withBody("{\"test\":0}")));
|
||||
final List<LogRecord> logs = new ArrayList<>();
|
||||
Handler testHandler = new Handler() {
|
||||
@Override
|
||||
|
@ -182,22 +190,16 @@ class AddMapWithAILayerActionTest {
|
|||
};
|
||||
Logging.getLogger().addHandler(testHandler);
|
||||
try {
|
||||
server.start();
|
||||
info.setUrl(server.baseUrl());
|
||||
info.setUrl(wireMockServer.baseUrl());
|
||||
info.setSourceType(MapWithAIType.ESRI_FEATURE_SERVER);
|
||||
final AddMapWithAILayerAction action = new AddMapWithAILayerAction(info);
|
||||
Logging.clearLastErrorAndWarnings();
|
||||
assertDoesNotThrow(() -> action.actionPerformed(null));
|
||||
GuiHelper.runInEDTAndWait(() -> {
|
||||
/* Sync thread */ });
|
||||
MainApplication.worker.submit(() -> {
|
||||
/* Sync thread */ }).get();
|
||||
threadSync.threadSync();
|
||||
final List<LogRecord> ides = logs.stream()
|
||||
.filter(record -> record.getThrown() instanceof IllegalArgumentException)
|
||||
.collect(Collectors.toList());
|
||||
.filter(record -> record.getThrown() instanceof IllegalArgumentException).toList();
|
||||
assertTrue(ides.isEmpty(), ides.stream().map(LogRecord::getMessage).collect(Collectors.joining("\n")));
|
||||
} finally {
|
||||
server.stop();
|
||||
Logging.getLogger().removeHandler(testHandler);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,7 +8,6 @@ import static org.junit.jupiter.api.Assertions.assertNotNull;
|
|||
import java.util.stream.Collectors;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.RegisterExtension;
|
||||
import org.openstreetmap.josm.data.Bounds;
|
||||
import org.openstreetmap.josm.data.osm.DataSet;
|
||||
import org.openstreetmap.josm.gui.progress.NullProgressMonitor;
|
||||
|
@ -17,10 +16,10 @@ import org.openstreetmap.josm.plugins.mapwithai.data.mapwithai.MapWithAIInfo;
|
|||
import org.openstreetmap.josm.plugins.mapwithai.data.mapwithai.MapWithAIType;
|
||||
import org.openstreetmap.josm.plugins.mapwithai.testutils.annotations.MapWithAIConfig;
|
||||
import org.openstreetmap.josm.plugins.mapwithai.testutils.annotations.Wiremock;
|
||||
import org.openstreetmap.josm.testutils.JOSMTestRules;
|
||||
import org.openstreetmap.josm.testutils.annotations.BasicPreferences;
|
||||
import org.openstreetmap.josm.testutils.annotations.BasicWiremock;
|
||||
import org.openstreetmap.josm.testutils.annotations.HTTP;
|
||||
import org.openstreetmap.josm.testutils.annotations.OsmApi;
|
||||
|
||||
import com.github.tomakehurst.wiremock.WireMockServer;
|
||||
import com.github.tomakehurst.wiremock.admin.model.GetServeEventsResult;
|
||||
|
@ -41,12 +40,11 @@ import com.github.tomakehurst.wiremock.verification.LoggedRequest;
|
|||
*/
|
||||
@BasicPreferences
|
||||
@HTTP
|
||||
@Wiremock
|
||||
@MapWithAIConfig
|
||||
@OsmApi(OsmApi.APIType.FAKE)
|
||||
@Wiremock
|
||||
class BoundingBoxMapWithAIDownloaderTest {
|
||||
private static final String TEST_DATA = "<osm version=\"0.6\"><node id=\"1\" lat=\"0\" lon=\"0\" version=\"1\"/><node id=\"2\" lat=\"1\" lon=\"1\" version=\"1\"/></osm>";
|
||||
@RegisterExtension
|
||||
JOSMTestRules josmTestRules = new JOSMTestRules().fakeAPI();
|
||||
|
||||
@BasicWiremock
|
||||
public WireMockServer wireMockServer;
|
||||
|
|
|
@ -11,31 +11,25 @@ import java.util.concurrent.ExecutionException;
|
|||
import java.util.concurrent.Future;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.RegisterExtension;
|
||||
import org.openstreetmap.josm.actions.downloadtasks.DownloadParams;
|
||||
import org.openstreetmap.josm.gui.progress.NullProgressMonitor;
|
||||
import org.openstreetmap.josm.plugins.mapwithai.data.mapwithai.MapWithAILayerInfo;
|
||||
import org.openstreetmap.josm.plugins.mapwithai.testutils.MapWithAITestRules;
|
||||
import org.openstreetmap.josm.plugins.mapwithai.testutils.annotations.MapWithAISources;
|
||||
import org.openstreetmap.josm.plugins.mapwithai.testutils.annotations.NoExceptions;
|
||||
import org.openstreetmap.josm.plugins.mapwithai.testutils.annotations.Wiremock;
|
||||
import org.openstreetmap.josm.testutils.JOSMTestRules;
|
||||
import org.openstreetmap.josm.testutils.annotations.BasicPreferences;
|
||||
import org.openstreetmap.josm.testutils.annotations.OsmApi;
|
||||
import org.openstreetmap.josm.testutils.annotations.Projection;
|
||||
import org.openstreetmap.josm.testutils.annotations.Territories;
|
||||
|
||||
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
|
||||
|
||||
@BasicPreferences
|
||||
@MapWithAISources
|
||||
@NoExceptions
|
||||
@Wiremock
|
||||
@Territories
|
||||
@OsmApi(OsmApi.APIType.FAKE)
|
||||
@Projection
|
||||
@Territories
|
||||
@Wiremock
|
||||
class DownloadMapWithAITaskTest {
|
||||
@RegisterExtension
|
||||
@SuppressFBWarnings("URF_UNREAD_PUBLIC_OR_PROTECTED_FIELD")
|
||||
JOSMTestRules rule = new MapWithAITestRules().fakeAPI();
|
||||
|
||||
@Test
|
||||
void testDownloadOsmServerReaderDownloadParamsBoundsProgressMonitor()
|
||||
|
|
|
@ -17,7 +17,6 @@ import java.util.Map;
|
|||
import java.util.Objects;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.RegisterExtension;
|
||||
import org.openstreetmap.josm.TestUtils;
|
||||
import org.openstreetmap.josm.data.Bounds;
|
||||
import org.openstreetmap.josm.data.coor.LatLon;
|
||||
|
@ -28,30 +27,24 @@ import org.openstreetmap.josm.data.osm.Way;
|
|||
import org.openstreetmap.josm.data.projection.ProjectionRegistry;
|
||||
import org.openstreetmap.josm.gui.MainApplication;
|
||||
import org.openstreetmap.josm.gui.layer.OsmDataLayer;
|
||||
import org.openstreetmap.josm.plugins.mapwithai.testutils.MapWithAITestRules;
|
||||
import org.openstreetmap.josm.plugins.mapwithai.testutils.annotations.MapWithAISources;
|
||||
import org.openstreetmap.josm.plugins.mapwithai.testutils.annotations.NoExceptions;
|
||||
import org.openstreetmap.josm.testutils.JOSMTestRules;
|
||||
import org.openstreetmap.josm.testutils.annotations.OsmApi;
|
||||
import org.openstreetmap.josm.testutils.annotations.Projection;
|
||||
import org.openstreetmap.josm.testutils.annotations.Territories;
|
||||
import org.openstreetmap.josm.tools.Geometry;
|
||||
|
||||
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
|
||||
|
||||
/**
|
||||
* Test class for {@link GetDataRunnable}
|
||||
*
|
||||
* @author Taylor Smock
|
||||
*/
|
||||
@NoExceptions
|
||||
@MapWithAISources
|
||||
@NoExceptions
|
||||
@OsmApi(OsmApi.APIType.FAKE)
|
||||
@Projection
|
||||
@Territories
|
||||
class GetDataRunnableTest {
|
||||
@RegisterExtension
|
||||
@SuppressFBWarnings("URF_UNREAD_PUBLIC_OR_PROTECTED_FIELD")
|
||||
static JOSMTestRules rule = new MapWithAITestRules().fakeAPI();
|
||||
|
||||
@Test
|
||||
void testAddMissingElement() {
|
||||
Way way1 = TestUtils.newWay("", new Node(new LatLon(-5.7117803, 34.5011898)),
|
||||
|
|
|
@ -17,7 +17,6 @@ import java.util.stream.Collectors;
|
|||
|
||||
import org.junit.jupiter.api.Disabled;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.RegisterExtension;
|
||||
import org.openstreetmap.josm.TestUtils;
|
||||
import org.openstreetmap.josm.data.Bounds;
|
||||
import org.openstreetmap.josm.data.coor.ILatLon;
|
||||
|
@ -32,19 +31,16 @@ import org.openstreetmap.josm.data.osm.Way;
|
|||
import org.openstreetmap.josm.gui.MainApplication;
|
||||
import org.openstreetmap.josm.gui.layer.GpxLayer;
|
||||
import org.openstreetmap.josm.plugins.mapwithai.data.mapwithai.MapWithAIInfo;
|
||||
import org.openstreetmap.josm.plugins.mapwithai.testutils.MapWithAITestRules;
|
||||
import org.openstreetmap.josm.plugins.mapwithai.testutils.annotations.MapWithAISources;
|
||||
import org.openstreetmap.josm.plugins.mapwithai.testutils.annotations.NoExceptions;
|
||||
import org.openstreetmap.josm.plugins.mapwithai.testutils.annotations.Wiremock;
|
||||
import org.openstreetmap.josm.testutils.JOSMTestRules;
|
||||
import org.openstreetmap.josm.testutils.annotations.BasicPreferences;
|
||||
import org.openstreetmap.josm.testutils.annotations.Main;
|
||||
import org.openstreetmap.josm.testutils.annotations.OsmApi;
|
||||
import org.openstreetmap.josm.testutils.annotations.Projection;
|
||||
import org.openstreetmap.josm.testutils.annotations.Territories;
|
||||
import org.openstreetmap.josm.tools.Logging;
|
||||
|
||||
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
|
||||
|
||||
/**
|
||||
* Test class for {@link MapWithAIDataUtils}
|
||||
*
|
||||
|
@ -54,6 +50,7 @@ import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
|
|||
@Main
|
||||
@MapWithAISources
|
||||
@NoExceptions
|
||||
@OsmApi(OsmApi.APIType.FAKE)
|
||||
@Projection
|
||||
@Territories
|
||||
@Wiremock
|
||||
|
@ -61,10 +58,6 @@ public class MapWithAIDataUtilsTest {
|
|||
/** This is the default MapWithAI URL */
|
||||
private static final String DEFAULT_MAPWITHAI_API = "https://www.mapwith.ai/maps/ml_roads?conflate_with_osm=true&theme=ml_road_vector&collaborator=josm&token=ASb3N5o9HbX8QWn8G_NtHIRQaYv3nuG2r7_f3vnGld3KhZNCxg57IsaQyssIaEw5rfRNsPpMwg4TsnrSJtIJms5m&hash=ASawRla3rBcwEjY4HIY&bbox={bbox}";
|
||||
|
||||
@RegisterExtension
|
||||
@SuppressFBWarnings("URF_UNREAD_PUBLIC_OR_PROTECTED_FIELD")
|
||||
static JOSMTestRules test = new MapWithAITestRules().fakeAPI();
|
||||
|
||||
/**
|
||||
* This gets data from MapWithAI. This test may fail if someone adds the data to
|
||||
* OSM.
|
||||
|
|
|
@ -4,17 +4,13 @@ package org.openstreetmap.josm.plugins.mapwithai.backend;
|
|||
import static org.awaitility.Awaitility.await;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||
import static org.junit.jupiter.api.Assertions.assertInstanceOf;
|
||||
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||
import static org.junit.jupiter.api.Assertions.assertNull;
|
||||
import static org.junit.jupiter.api.Assertions.assertSame;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
import static org.openstreetmap.josm.tools.I18n.tr;
|
||||
|
||||
import javax.swing.Action;
|
||||
import javax.swing.JLabel;
|
||||
import javax.swing.JPanel;
|
||||
import javax.swing.SwingUtilities;
|
||||
|
||||
import java.awt.Component;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.text.MessageFormat;
|
||||
|
@ -23,6 +19,11 @@ import java.util.Collections;
|
|||
import java.util.List;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import javax.swing.Action;
|
||||
import javax.swing.JLabel;
|
||||
import javax.swing.JPanel;
|
||||
import javax.swing.SwingUtilities;
|
||||
|
||||
import org.awaitility.Durations;
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
|
@ -53,6 +54,7 @@ import org.openstreetmap.josm.testutils.annotations.BasicPreferences;
|
|||
import org.openstreetmap.josm.testutils.annotations.Main;
|
||||
import org.openstreetmap.josm.testutils.annotations.OsmApi;
|
||||
import org.openstreetmap.josm.testutils.annotations.Projection;
|
||||
import org.openstreetmap.josm.testutils.annotations.ResetUniquePrimitiveIdCounters;
|
||||
import org.openstreetmap.josm.testutils.annotations.Territories;
|
||||
|
||||
/**
|
||||
|
@ -124,9 +126,9 @@ class MapWithAILayerTest {
|
|||
@Test
|
||||
void testGetInfoComponent() {
|
||||
final Object tObject = layer.getInfoComponent();
|
||||
assertTrue(tObject instanceof JPanel, "The info component should be a JPanel instead of a string");
|
||||
JPanel jPanel = assertInstanceOf(JPanel.class, tObject,
|
||||
"The info component should be a JPanel instead of a string");
|
||||
|
||||
JPanel jPanel = (JPanel) tObject;
|
||||
final Component[] startComponents = jPanel.getComponents();
|
||||
for (final Component comp : startComponents) {
|
||||
final JLabel label = (JLabel) comp;
|
||||
|
@ -173,6 +175,7 @@ class MapWithAILayerTest {
|
|||
}
|
||||
}
|
||||
|
||||
@ResetUniquePrimitiveIdCounters
|
||||
@Test
|
||||
void testSelection() throws InvocationTargetException, InterruptedException {
|
||||
MapWithAILayer mapWithAILayer = MapWithAIDataUtils.getLayer(true);
|
||||
|
@ -186,10 +189,10 @@ class MapWithAILayerTest {
|
|||
SwingUtilities.invokeAndWait(() -> ds.setSelected(ds.allNonDeletedCompletePrimitives()));
|
||||
assertEquals(1, ds.getSelected().size());
|
||||
OsmPrimitive prim = ds.getSelected().iterator().next();
|
||||
assertTrue(prim instanceof Way);
|
||||
SwingUtilities.invokeAndWait(() -> ds.setSelected(((Way) prim).getNodes()));
|
||||
assertEquals(((Way) prim).getNodes().size(), ds.getSelected().size());
|
||||
assertTrue(((Way) prim).getNodes().stream().allMatch(ds::isSelected));
|
||||
final Way way = assertInstanceOf(Way.class, prim);
|
||||
SwingUtilities.invokeAndWait(() -> ds.setSelected(way.getNodes()));
|
||||
assertEquals(way.getNodes().size(), ds.getSelected().size());
|
||||
assertTrue(way.getNodes().stream().allMatch(ds::isSelected));
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
|
@ -0,0 +1,46 @@
|
|||
// License: GPL. For details, see LICENSE file.
|
||||
package org.openstreetmap.josm.plugins.mapwithai.backend;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.params.ParameterizedTest;
|
||||
import org.junit.jupiter.params.provider.Arguments;
|
||||
import org.junit.jupiter.params.provider.MethodSource;
|
||||
import org.openstreetmap.josm.data.Bounds;
|
||||
|
||||
/**
|
||||
* Test class for {@link TileXYZ}
|
||||
*/
|
||||
class TileXYZTest {
|
||||
static Stream<Arguments> testTileCalculations() {
|
||||
return Stream.of(Arguments.of(39.07035, -108.5709286, 52013, 100120, 18),
|
||||
Arguments.of(39.0643941, -108.5610312, 52020, 100125, 18),
|
||||
Arguments.of(39.0643941, -108.5709286, 52013, 100125, 18),
|
||||
Arguments.of(39.07035, -108.5610312, 52020, 100120, 18));
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@MethodSource
|
||||
void testTileCalculations(double lat, double lon, int x, int y, int z) {
|
||||
final var tile = TileXYZ.tileFromLatLonZoom(lon, lat, z);
|
||||
assertAll(() -> assertEquals(x, tile.x()), () -> assertEquals(y, tile.y()), () -> assertEquals(z, tile.z()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Check that the tiles calculated for a bbox are correct
|
||||
*/
|
||||
@Test
|
||||
void testNonRegressionGH44() {
|
||||
final var tiles = TileXYZ.tilesFromBBox(18, new Bounds(39.0643941, -108.5709286, 39.07035, -108.5610312))
|
||||
.toArray(TileXYZ[]::new);
|
||||
assertAll(() -> assertEquals(100125, Arrays.stream(tiles).mapToInt(TileXYZ::y).max().orElse(0)),
|
||||
() -> assertEquals(100120, Arrays.stream(tiles).mapToInt(TileXYZ::y).min().orElse(0)),
|
||||
() -> assertEquals(52013, Arrays.stream(tiles).mapToInt(TileXYZ::x).min().orElse(0)),
|
||||
() -> assertEquals(52020, Arrays.stream(tiles).mapToInt(TileXYZ::x).max().orElse(0)));
|
||||
assertEquals(48, tiles.length, "Should be 6x8 tiles (rangeClosed)");
|
||||
}
|
||||
}
|
|
@ -62,7 +62,7 @@ import mockit.Mock;
|
|||
@MapWithAISources
|
||||
@Projection
|
||||
@Wiremock
|
||||
class MapWithAIAddComandTest {
|
||||
class MapWithAIAddCommandTest {
|
||||
private final static String HIGHWAY_RESIDENTIAL = "highway=residential";
|
||||
|
||||
@BeforeEach
|
||||
|
@ -70,7 +70,7 @@ class MapWithAIAddComandTest {
|
|||
// Required to avoid an NPE with AutoZoomHandler
|
||||
new WindowMocker() {
|
||||
@Mock
|
||||
void pack() {
|
||||
public void pack() {
|
||||
// Do nothing
|
||||
}
|
||||
};
|
|
@ -49,8 +49,8 @@ class MovePrimitiveDataSetCommandTest {
|
|||
move.fillModifiedData(modified, deleted, added);
|
||||
final Collection<? extends OsmPrimitive> participatingPrimitives = move.getParticipatingPrimitives();
|
||||
assertAll(() -> assertEquals(0, deleted.size()), () -> assertEquals(0, added.size()), // the JOSM Add command
|
||||
// doesn't add to this
|
||||
// list
|
||||
// doesn't add to this
|
||||
// list
|
||||
() -> assertEquals(0, modified.size()), () -> assertEquals(1, from.allNonDeletedPrimitives().size()),
|
||||
() -> assertEquals(3, to.allNonDeletedPrimitives().size()),
|
||||
() -> assertNotNull(to.getPrimitiveById(way1)), () -> assertTrue(way1.isDeleted()),
|
||||
|
@ -86,8 +86,8 @@ class MovePrimitiveDataSetCommandTest {
|
|||
move.fillModifiedData(modified, deleted, added);
|
||||
final List<OsmPrimitive> participatingPrimitives = new ArrayList<>(move.getParticipatingPrimitives());
|
||||
assertAll(() -> assertEquals(0, deleted.size()), () -> assertEquals(0, added.size()), // the JOSM Add command
|
||||
// doesn't add to this
|
||||
// list
|
||||
// doesn't add to this
|
||||
// list
|
||||
() -> assertEquals(0, modified.size()), () -> assertEquals(1, from.allNonDeletedPrimitives().size()),
|
||||
() -> assertEquals(3, to.allNonDeletedPrimitives().size()),
|
||||
() -> assertNotNull(to.getPrimitiveById(way1)),
|
||||
|
|
|
@ -157,6 +157,7 @@ class RoutingIslandsTestTest {
|
|||
/**
|
||||
* Test method for {@link RoutingIslandsTest#checkForUnconnectedWays}.
|
||||
*/
|
||||
@BasicPreferences
|
||||
@Test
|
||||
void testCheckForUnconnectedWaysIncoming() {
|
||||
RoutingIslandsTest.checkForUnconnectedWays(Collections.emptySet(), Collections.emptySet(), null);
|
||||
|
|
|
@ -1,59 +0,0 @@
|
|||
// License: GPL. For details, see LICENSE file.
|
||||
package org.openstreetmap.josm.plugins.mapwithai.testutils;
|
||||
|
||||
import java.lang.Thread.UncaughtExceptionHandler;
|
||||
import java.util.logging.Level;
|
||||
|
||||
import org.junit.runners.model.InitializationError;
|
||||
import org.openstreetmap.josm.testutils.JOSMTestRules;
|
||||
import org.openstreetmap.josm.tools.Logging;
|
||||
|
||||
import mockit.integration.TestRunnerDecorator;
|
||||
|
||||
public class MapWithAITestRules extends JOSMTestRules {
|
||||
|
||||
private boolean workerExceptions = true;
|
||||
private UncaughtExceptionHandler currentExceptionHandler;
|
||||
|
||||
public MapWithAITestRules() {
|
||||
super();
|
||||
}
|
||||
|
||||
public MapWithAITestRules noWorkerExceptions() {
|
||||
this.workerExceptions = false;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set up before running a test
|
||||
*
|
||||
* @throws InitializationError If an error occurred while creating the
|
||||
* required environment.
|
||||
* @throws ReflectiveOperationException if a reflective access error occurs
|
||||
*/
|
||||
@Override
|
||||
protected void before() throws InitializationError, ReflectiveOperationException {
|
||||
TestRunnerDecorator.cleanUpAllMocks();
|
||||
super.before();
|
||||
Logging.getLogger().setFilter(record -> record.getLevel().intValue() >= Level.WARNING.intValue()
|
||||
|| record.getSourceClassName().startsWith("org.openstreetmap.josm.plugins.mapwithai"));
|
||||
|
||||
if (workerExceptions) {
|
||||
currentExceptionHandler = Thread.getDefaultUncaughtExceptionHandler();
|
||||
Thread.setDefaultUncaughtExceptionHandler((t, e) -> {
|
||||
Logging.error(t.getClass().getSimpleName());
|
||||
Logging.error(e);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void after() throws ReflectiveOperationException {
|
||||
super.after();
|
||||
|
||||
if (workerExceptions) {
|
||||
Thread.setDefaultUncaughtExceptionHandler(currentExceptionHandler);
|
||||
}
|
||||
TestRunnerDecorator.cleanUpAllMocks();
|
||||
}
|
||||
}
|
|
@ -20,5 +20,4 @@ import org.openstreetmap.josm.testutils.annotations.Territories;
|
|||
@Wiremock
|
||||
@Territories
|
||||
@ExtendWith(Wiremock.MapWithAILayerInfoExtension.class)
|
||||
public @interface MapWithAISources {
|
||||
}
|
||||
public @interface MapWithAISources {}
|
||||
|
|
|
@ -105,6 +105,8 @@ public @interface Wiremock {
|
|||
* Extension for {@link MapWithAILayerInfo}
|
||||
*/
|
||||
class MapWithAILayerInfoExtension extends WiremockExtension {
|
||||
private static int hashCode;
|
||||
|
||||
@Override
|
||||
public void afterAll(ExtensionContext context) throws Exception {
|
||||
try {
|
||||
|
@ -129,7 +131,7 @@ public @interface Wiremock {
|
|||
synchronized (MapWithAILayerInfo.class) {
|
||||
final var info = MapWithAILayerInfo.getInstance();
|
||||
info.clear();
|
||||
if (false && AnnotationSupport.isAnnotated(context.getTestClass(), Territories.class)) {
|
||||
if (AnnotationSupport.isAnnotated(context.getTestClass(), Territories.class)) {
|
||||
// This should probably only be run if territories is initialized
|
||||
info.getDefaultLayers().stream().filter(MapWithAIInfo::isDefaultEntry).forEach(info::add);
|
||||
}
|
||||
|
|
|
@ -6,19 +6,23 @@ import static com.github.tomakehurst.wiremock.client.WireMock.get;
|
|||
import static com.github.tomakehurst.wiremock.client.WireMock.noContent;
|
||||
import static com.github.tomakehurst.wiremock.client.WireMock.notFound;
|
||||
import static com.github.tomakehurst.wiremock.client.WireMock.urlMatching;
|
||||
import static com.github.tomakehurst.wiremock.core.WireMockConfiguration.options;
|
||||
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
import org.junit.jupiter.api.AfterAll;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.openstreetmap.josm.TestUtils;
|
||||
import org.openstreetmap.josm.plugins.mapwithai.MapWithAIPlugin;
|
||||
import org.openstreetmap.josm.plugins.mapwithai.testutils.MapWithAIPluginMock;
|
||||
import org.openstreetmap.josm.spi.preferences.Config;
|
||||
|
||||
import com.github.tomakehurst.wiremock.WireMockServer;
|
||||
import com.github.tomakehurst.wiremock.junit5.WireMockRuntimeInfo;
|
||||
import com.github.tomakehurst.wiremock.junit5.WireMockTest;
|
||||
|
||||
/**
|
||||
* Tests for {@link BlacklistUtils}
|
||||
|
@ -26,85 +30,90 @@ import com.github.tomakehurst.wiremock.WireMockServer;
|
|||
* @author Taylor Smock
|
||||
*
|
||||
*/
|
||||
@WireMockTest
|
||||
class BlacklistUtilsTest {
|
||||
private static WireMockServer wireMock;
|
||||
private static String blacklistUrl;
|
||||
|
||||
@BeforeAll
|
||||
static void setup() {
|
||||
static void setup(WireMockRuntimeInfo wireMockRuntimeInfo) {
|
||||
TestUtils.assumeWorkingJMockit();
|
||||
wireMock = new WireMockServer(options().dynamicPort());
|
||||
wireMock.start();
|
||||
BlacklistUtils.setBlacklistUrl(wireMock.baseUrl() + "/MapWithAI/json/blacklisted_versions.json");
|
||||
blacklistUrl = wireMockRuntimeInfo.getHttpBaseUrl() + "/MapWithAI/json/blacklisted_versions.json";
|
||||
BlacklistUtils.setBlacklistUrl(blacklistUrl);
|
||||
new MapWithAIPluginMock();
|
||||
}
|
||||
|
||||
@BeforeEach
|
||||
void clear() {
|
||||
wireMock.resetMappings();
|
||||
@AfterEach
|
||||
void cleanup(WireMockRuntimeInfo wireMockRuntimeInfo) {
|
||||
final var file = new File(Config.getDirs().getCacheDirectory(false), "mirror_http___localhost_"
|
||||
+ wireMockRuntimeInfo.getHttpPort() + "_MapWithAI_json_blacklisted_versions.json");
|
||||
// Ensure that we aren't reading a cached response from a different test
|
||||
if (file.exists()) {
|
||||
assertTrue(file.delete());
|
||||
}
|
||||
}
|
||||
|
||||
@AfterAll
|
||||
static void tearDown() {
|
||||
BlacklistUtils.setBlacklistUrl(BlacklistUtils.DEFAULT_BLACKLIST_URL);
|
||||
assertTrue(wireMock.findAllUnmatchedRequests().isEmpty());
|
||||
wireMock.stop();
|
||||
blacklistUrl = null;
|
||||
}
|
||||
|
||||
@Test
|
||||
void testArrayBad() {
|
||||
wireMock.addStubMapping(get(urlMatching("/MapWithAI/json/blacklisted_versions.json"))
|
||||
.willReturn(aResponse().withStatus(200).withBody("[\"" + MapWithAIPlugin.getVersionInfo() + "\"]"))
|
||||
.build());
|
||||
void testArrayBad(WireMockRuntimeInfo wireMockRuntimeInfo) {
|
||||
wireMockRuntimeInfo.getWireMock().register(get(urlMatching("/MapWithAI/json/blacklisted_versions.json"))
|
||||
.willReturn(aResponse().withStatus(200).withBody("[\"" + MapWithAIPlugin.getVersionInfo() + "\"]")));
|
||||
assertTrue(BlacklistUtils.isBlacklisted());
|
||||
}
|
||||
|
||||
@Test
|
||||
void testArrayGood() {
|
||||
wireMock.addStubMapping(get(urlMatching("/MapWithAI/json/blacklisted_versions.json"))
|
||||
.willReturn(aResponse().withStatus(200).withBody("[null, 0, false]")).build());
|
||||
void testArrayGood(WireMockRuntimeInfo wireMockRuntimeInfo) {
|
||||
wireMockRuntimeInfo.getWireMock().register(get(urlMatching("/MapWithAI/json/blacklisted_versions.json"))
|
||||
.willReturn(aResponse().withStatus(200).withBody("[null, 0, false]")));
|
||||
assertFalse(BlacklistUtils.isBlacklisted());
|
||||
}
|
||||
|
||||
@Test
|
||||
void testObjectBad() {
|
||||
wireMock.addStubMapping(get(urlMatching("/MapWithAI/json/blacklisted_versions.json")).willReturn(aResponse()
|
||||
.withStatus(200).withBody("{ \"" + MapWithAIPlugin.getVersionInfo() + "\": \"reason here\"}")).build());
|
||||
void testObjectBad(WireMockRuntimeInfo wireMockRuntimeInfo) {
|
||||
wireMockRuntimeInfo.getWireMock()
|
||||
.register(get(urlMatching("/MapWithAI/json/blacklisted_versions.json")).willReturn(aResponse()
|
||||
.withStatus(200).withBody("{ \"" + MapWithAIPlugin.getVersionInfo() + "\": \"reason here\"}")));
|
||||
assertTrue(BlacklistUtils.isBlacklisted());
|
||||
}
|
||||
|
||||
@Test
|
||||
void testObjectGood() {
|
||||
wireMock.addStubMapping(get(urlMatching("/MapWithAI/json/blacklisted_versions.json"))
|
||||
.willReturn(aResponse().withStatus(200).withBody("{ \"version\": \"reason here\"}")).build());
|
||||
void testObjectGood(WireMockRuntimeInfo wireMockRuntimeInfo) {
|
||||
wireMockRuntimeInfo.getWireMock().register(get(urlMatching("/MapWithAI/json/blacklisted_versions.json"))
|
||||
.willReturn(aResponse().withStatus(200).withBody("{ \"version\": \"reason here\"}")));
|
||||
assertFalse(BlacklistUtils.isBlacklisted());
|
||||
}
|
||||
|
||||
@Test
|
||||
void testNullJson() {
|
||||
wireMock.addStubMapping(get(urlMatching("/MapWithAI/json/blacklisted_versions.json"))
|
||||
.willReturn(aResponse().withStatus(200).withBody("null")).build());
|
||||
void testNullJson(WireMockRuntimeInfo wireMockRuntimeInfo) {
|
||||
wireMockRuntimeInfo.getWireMock().register(get(urlMatching("/MapWithAI/json/blacklisted_versions.json"))
|
||||
.willReturn(aResponse().withStatus(200).withBody("null")));
|
||||
assertTrue(BlacklistUtils.isBlacklisted());
|
||||
}
|
||||
|
||||
@Test
|
||||
void testBrokenJson() {
|
||||
wireMock.addStubMapping(get(urlMatching("/MapWithAI/json/blacklisted_versions.json")).willReturn(
|
||||
aResponse().withStatus(200).withBody("{ \"" + MapWithAIPlugin.getVersionInfo() + "\": \"reason here\""))
|
||||
.build());
|
||||
void testBrokenJson(WireMockRuntimeInfo wireMockRuntimeInfo) {
|
||||
wireMockRuntimeInfo.getWireMock()
|
||||
.register(get(urlMatching("/MapWithAI/json/blacklisted_versions.json")).willReturn(aResponse()
|
||||
.withStatus(200).withBody("{ \"" + MapWithAIPlugin.getVersionInfo() + "\": \"reason here\"")));
|
||||
assertTrue(BlacklistUtils.isBlacklisted());
|
||||
}
|
||||
|
||||
@Test
|
||||
void testNoResponse() {
|
||||
wireMock.addStubMapping(
|
||||
get(urlMatching("/MapWithAI/json/blacklisted_versions.json")).willReturn(noContent()).build());
|
||||
void testNoResponse(WireMockRuntimeInfo wireMockRuntimeInfo) {
|
||||
wireMockRuntimeInfo.getWireMock()
|
||||
.register(get(urlMatching("/MapWithAI/json/blacklisted_versions.json")).willReturn(noContent()));
|
||||
assertTrue(BlacklistUtils.isBlacklisted());
|
||||
}
|
||||
|
||||
@Test
|
||||
void testNotFound() {
|
||||
wireMock.addStubMapping(
|
||||
get(urlMatching("/MapWithAI/json/blacklisted_versions.json")).willReturn(notFound()).build());
|
||||
void testNotFound(WireMockRuntimeInfo wireMockRuntimeInfo) {
|
||||
wireMockRuntimeInfo.getWireMock()
|
||||
.register(get(urlMatching("/MapWithAI/json/blacklisted_versions.json")).willReturn(notFound()));
|
||||
assertTrue(BlacklistUtils.isBlacklisted());
|
||||
}
|
||||
}
|
||||
|
|
Ładowanie…
Reference in New Issue