kopia lustrzana https://github.com/JOSM/MapWithAI
Reduce startup costs
This largely focuses on reducing memory allocations. There are also some conversions to Java 17 standards. Signed-off-by: Taylor Smock <tsmock@meta.com>pull/31/head
rodzic
9aab77dd4f
commit
056b9db064
|
@ -3,7 +3,6 @@ package org.openstreetmap.josm.plugins.mapwithai;
|
||||||
|
|
||||||
import static org.openstreetmap.josm.tools.I18n.tr;
|
import static org.openstreetmap.josm.tools.I18n.tr;
|
||||||
|
|
||||||
import javax.swing.JMenu;
|
|
||||||
import javax.swing.JMenuItem;
|
import javax.swing.JMenuItem;
|
||||||
|
|
||||||
import java.lang.reflect.InvocationTargetException;
|
import java.lang.reflect.InvocationTargetException;
|
||||||
|
@ -12,7 +11,6 @@ import java.util.Arrays;
|
||||||
import java.util.LinkedHashMap;
|
import java.util.LinkedHashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Optional;
|
|
||||||
|
|
||||||
import org.openstreetmap.josm.actions.JosmAction;
|
import org.openstreetmap.josm.actions.JosmAction;
|
||||||
import org.openstreetmap.josm.actions.PreferencesAction;
|
import org.openstreetmap.josm.actions.PreferencesAction;
|
||||||
|
@ -70,8 +68,6 @@ public final class MapWithAIPlugin extends Plugin implements Destroyable {
|
||||||
|
|
||||||
private final List<Destroyable> destroyables;
|
private final List<Destroyable> destroyables;
|
||||||
|
|
||||||
private final PreferencesAction preferenceAction;
|
|
||||||
|
|
||||||
private final MapWithAIMenu mapwithaiMenu;
|
private final MapWithAIMenu mapwithaiMenu;
|
||||||
|
|
||||||
private static final Map<Class<? extends JosmAction>, Boolean> MENU_ENTRIES = new LinkedHashMap<>();
|
private static final Map<Class<? extends JosmAction>, Boolean> MENU_ENTRIES = new LinkedHashMap<>();
|
||||||
|
@ -92,7 +88,7 @@ public final class MapWithAIPlugin extends Plugin implements Destroyable {
|
||||||
preferenceSetting = new MapWithAIPreferences();
|
preferenceSetting = new MapWithAIPreferences();
|
||||||
|
|
||||||
// Add MapWithAI specific menu
|
// Add MapWithAI specific menu
|
||||||
JMenu dataMenu = MainApplication.getMenu().dataMenu;
|
final var dataMenu = MainApplication.getMenu().dataMenu;
|
||||||
mapwithaiMenu = new MapWithAIMenu();
|
mapwithaiMenu = new MapWithAIMenu();
|
||||||
|
|
||||||
dataMenu.add(mapwithaiMenu);
|
dataMenu.add(mapwithaiMenu);
|
||||||
|
@ -111,8 +107,8 @@ public final class MapWithAIPlugin extends Plugin implements Destroyable {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add the preferences last to data
|
// Add the preferences last to data
|
||||||
preferenceAction = PreferencesAction.forPreferenceTab(tr("MapWithAI Preferences"), tr("MapWithAI Preferences"),
|
final var preferenceAction = PreferencesAction.forPreferenceTab(tr("MapWithAI Preferences"),
|
||||||
MapWithAIPreferences.class);
|
tr("MapWithAI Preferences"), MapWithAIPreferences.class);
|
||||||
MainMenu.add(mapwithaiMenu, preferenceAction);
|
MainMenu.add(mapwithaiMenu, preferenceAction);
|
||||||
|
|
||||||
VALIDATORS.forEach(clazz -> {
|
VALIDATORS.forEach(clazz -> {
|
||||||
|
@ -137,6 +133,9 @@ public final class MapWithAIPlugin extends Plugin implements Destroyable {
|
||||||
mapFrameInitialized(null, MainApplication.getMap());
|
mapFrameInitialized(null, MainApplication.getMap());
|
||||||
OSMDownloadSource.addDownloadType(new MapWithAIDownloadSourceType());
|
OSMDownloadSource.addDownloadType(new MapWithAIDownloadSourceType());
|
||||||
MainApplication.worker.execute(() -> UpdateProd.doProd(info.mainversion));
|
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);
|
||||||
|
|
||||||
destroyables.add(new MapWithAICopyProhibit());
|
destroyables.add(new MapWithAICopyProhibit());
|
||||||
}
|
}
|
||||||
|
@ -146,7 +145,7 @@ public final class MapWithAIPlugin extends Plugin implements Destroyable {
|
||||||
// Run in EDT to avoid blocking (has to be run before MapWithAIDownloadOptions
|
// Run in EDT to avoid blocking (has to be run before MapWithAIDownloadOptions
|
||||||
// so its already initialized)
|
// so its already initialized)
|
||||||
GuiHelper.runInEDT(MapWithAILayerInfo::getInstance);
|
GuiHelper.runInEDT(MapWithAILayerInfo::getInstance);
|
||||||
MapWithAIDownloadOptions mapWithAIDownloadOptions = new MapWithAIDownloadOptions();
|
final var mapWithAIDownloadOptions = new MapWithAIDownloadOptions();
|
||||||
MainApplication.worker
|
MainApplication.worker
|
||||||
.execute(() -> GuiHelper.runInEDT(() -> mapWithAIDownloadOptions.addGui(DownloadDialog.getInstance())));
|
.execute(() -> GuiHelper.runInEDT(() -> mapWithAIDownloadOptions.addGui(DownloadDialog.getInstance())));
|
||||||
destroyables.add(mapWithAIDownloadOptions);
|
destroyables.add(mapWithAIDownloadOptions);
|
||||||
|
@ -154,9 +153,8 @@ public final class MapWithAIPlugin extends Plugin implements Destroyable {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void mapFrameInitialized(MapFrame oldFrame, MapFrame newFrame) {
|
public void mapFrameInitialized(MapFrame oldFrame, MapFrame newFrame) {
|
||||||
final Optional<MapWithAIObject> possibleMapWithAIObject = destroyables.stream()
|
final var mapWithAIObject = destroyables.stream().filter(MapWithAIObject.class::isInstance)
|
||||||
.filter(MapWithAIObject.class::isInstance).map(MapWithAIObject.class::cast).findFirst();
|
.map(MapWithAIObject.class::cast).findFirst().orElseGet(MapWithAIObject::new);
|
||||||
final MapWithAIObject mapWithAIObject = possibleMapWithAIObject.orElse(new MapWithAIObject());
|
|
||||||
if ((oldFrame != null) && (oldFrame.statusLine != null)) {
|
if ((oldFrame != null) && (oldFrame.statusLine != null)) {
|
||||||
mapWithAIObject.removeMapStatus(oldFrame.statusLine);
|
mapWithAIObject.removeMapStatus(oldFrame.statusLine);
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,14 +4,12 @@ package org.openstreetmap.josm.plugins.mapwithai.backend;
|
||||||
import static org.openstreetmap.josm.tools.I18n.tr;
|
import static org.openstreetmap.josm.tools.I18n.tr;
|
||||||
|
|
||||||
import javax.json.Json;
|
import javax.json.Json;
|
||||||
import javax.json.JsonObject;
|
|
||||||
import javax.json.JsonReader;
|
import javax.json.JsonReader;
|
||||||
import javax.json.JsonStructure;
|
import javax.json.JsonStructure;
|
||||||
import javax.json.JsonValue;
|
import javax.json.JsonValue;
|
||||||
import javax.json.stream.JsonParser;
|
import javax.json.stream.JsonParser;
|
||||||
import javax.swing.JOptionPane;
|
import javax.swing.JOptionPane;
|
||||||
|
|
||||||
import java.awt.geom.Area;
|
|
||||||
import java.io.ByteArrayInputStream;
|
import java.io.ByteArrayInputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
|
@ -24,13 +22,10 @@ import java.time.Instant;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.Comparator;
|
import java.util.Comparator;
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.OptionalInt;
|
|
||||||
import java.util.concurrent.ExecutionException;
|
import java.util.concurrent.ExecutionException;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
import java.util.concurrent.TimeoutException;
|
import java.util.concurrent.TimeoutException;
|
||||||
import java.util.stream.Collectors;
|
|
||||||
|
|
||||||
import org.openstreetmap.josm.data.Bounds;
|
import org.openstreetmap.josm.data.Bounds;
|
||||||
import org.openstreetmap.josm.data.DataSource;
|
import org.openstreetmap.josm.data.DataSource;
|
||||||
|
@ -54,6 +49,7 @@ import org.openstreetmap.josm.plugins.mapwithai.data.mapwithai.MapWithAIInfo;
|
||||||
import org.openstreetmap.josm.plugins.mapwithai.data.mapwithai.MapWithAILayerInfo;
|
import org.openstreetmap.josm.plugins.mapwithai.data.mapwithai.MapWithAILayerInfo;
|
||||||
import org.openstreetmap.josm.plugins.mapwithai.data.mapwithai.MapWithAIType;
|
import org.openstreetmap.josm.plugins.mapwithai.data.mapwithai.MapWithAIType;
|
||||||
import org.openstreetmap.josm.plugins.mapwithai.tools.MapPaintUtils;
|
import org.openstreetmap.josm.plugins.mapwithai.tools.MapPaintUtils;
|
||||||
|
import org.openstreetmap.josm.spi.preferences.Config;
|
||||||
import org.openstreetmap.josm.tools.HttpClient;
|
import org.openstreetmap.josm.tools.HttpClient;
|
||||||
import org.openstreetmap.josm.tools.JosmRuntimeException;
|
import org.openstreetmap.josm.tools.JosmRuntimeException;
|
||||||
import org.openstreetmap.josm.tools.Logging;
|
import org.openstreetmap.josm.tools.Logging;
|
||||||
|
@ -64,11 +60,6 @@ import org.openstreetmap.josm.tools.Logging;
|
||||||
* @author Taylor Smock
|
* @author Taylor Smock
|
||||||
*/
|
*/
|
||||||
public class BoundingBoxMapWithAIDownloader extends BoundingBoxDownloader {
|
public class BoundingBoxMapWithAIDownloader extends BoundingBoxDownloader {
|
||||||
/**
|
|
||||||
* The time that the data URL's were last updated. See #22683 for why this is
|
|
||||||
* necessary.
|
|
||||||
*/
|
|
||||||
private static Instant DATA_LAST_UPDATED = Instant.EPOCH;
|
|
||||||
private final String url;
|
private final String url;
|
||||||
private final boolean crop;
|
private final boolean crop;
|
||||||
private final int start;
|
private final int start;
|
||||||
|
@ -157,23 +148,22 @@ public class BoundingBoxMapWithAIDownloader extends BoundingBoxDownloader {
|
||||||
} catch (OsmTransferException e) {
|
} catch (OsmTransferException e) {
|
||||||
if (e.getCause() instanceof SocketTimeoutException && (System.nanoTime() - startTime) > 30_000_000_000L) {
|
if (e.getCause() instanceof SocketTimeoutException && (System.nanoTime() - startTime) > 30_000_000_000L) {
|
||||||
updateLastErrorTime(System.nanoTime());
|
updateLastErrorTime(System.nanoTime());
|
||||||
Notification note = new Notification();
|
final var note = new Notification();
|
||||||
GuiHelper.runInEDT(() -> note.setContent(tr(
|
GuiHelper.runInEDT(() -> note.setContent(tr(
|
||||||
"Attempting to download data in the background. This may fail or succeed in a few minutes.")));
|
"Attempting to download data in the background. This may fail or succeed in a few minutes.")));
|
||||||
GuiHelper.runInEDT(note::show);
|
GuiHelper.runInEDT(note::show);
|
||||||
} else if (e.getCause() instanceof IllegalDataException) {
|
} else if (e.getCause() instanceof IllegalDataException) {
|
||||||
final Instant lastUpdated;
|
final Instant lastUpdated;
|
||||||
final Instant now;
|
final var now = Instant.now();
|
||||||
synchronized (BoundingBoxMapWithAIDownloader.class) {
|
synchronized (BoundingBoxMapWithAIDownloader.class) {
|
||||||
lastUpdated = DATA_LAST_UPDATED;
|
lastUpdated = Instant.ofEpochSecond(Config.getPref().getLong("mapwithai.layerinfo.lastupdated", 0));
|
||||||
now = Instant.now();
|
Config.getPref().putLong("mapwithai.layerinfo.lastupdated", now.getEpochSecond());
|
||||||
DATA_LAST_UPDATED = now;
|
|
||||||
}
|
}
|
||||||
// Only force an update if the last update time is sufficiently old.
|
// Only force an update if the last update time is sufficiently old.
|
||||||
if (now.toEpochMilli() - lastUpdated.toEpochMilli() > TimeUnit.MINUTES.toMillis(10)) {
|
if (now.toEpochMilli() - lastUpdated.toEpochMilli() > TimeUnit.MINUTES.toMillis(10)) {
|
||||||
MapWithAILayerInfo.getInstance().loadDefaults(true, MapWithAIDataUtils.getForkJoinPool(), false,
|
MapWithAILayerInfo.getInstance().loadDefaults(true, MapWithAIDataUtils.getForkJoinPool(), false,
|
||||||
() -> GuiHelper.runInEDT(() -> {
|
() -> GuiHelper.runInEDT(() -> {
|
||||||
Notification notification = new Notification(tr(
|
final var notification = new Notification(tr(
|
||||||
"MapWithAI layers reloaded. Removing and re-adding the MapWithAI layer may be necessary."));
|
"MapWithAI layers reloaded. Removing and re-adding the MapWithAI layer may be necessary."));
|
||||||
notification.setIcon(JOptionPane.INFORMATION_MESSAGE);
|
notification.setIcon(JOptionPane.INFORMATION_MESSAGE);
|
||||||
notification.setDuration(Notification.TIME_LONG);
|
notification.setDuration(Notification.TIME_LONG);
|
||||||
|
@ -185,8 +175,8 @@ public class BoundingBoxMapWithAIDownloader extends BoundingBoxDownloader {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Just in case something happens, try again...
|
// Just in case something happens, try again...
|
||||||
DataSet ds = new DataSet();
|
final var ds = new DataSet();
|
||||||
GetDataRunnable runnable = new GetDataRunnable(downloadArea, ds, NullProgressMonitor.INSTANCE);
|
final var runnable = new GetDataRunnable(downloadArea, ds, NullProgressMonitor.INSTANCE);
|
||||||
runnable.setMapWithAIInfo(info);
|
runnable.setMapWithAIInfo(info);
|
||||||
MainApplication.worker.execute(() -> {
|
MainApplication.worker.execute(() -> {
|
||||||
try {
|
try {
|
||||||
|
@ -210,12 +200,11 @@ public class BoundingBoxMapWithAIDownloader extends BoundingBoxDownloader {
|
||||||
* @return The dataset to send to the server
|
* @return The dataset to send to the server
|
||||||
*/
|
*/
|
||||||
private static DataSet getConflationData(Bounds bound) {
|
private static DataSet getConflationData(Bounds bound) {
|
||||||
Area area = DataSource.getDataSourceArea(Collections.singleton(new DataSource(bound, "")));
|
final var area = DataSource.getDataSourceArea(Collections.singleton(new DataSource(bound, "")));
|
||||||
if (area != null) {
|
if (area != null) {
|
||||||
List<OsmDataLayer> layers = MainApplication
|
final var layers = MainApplication.getLayerManager().getLayersOfType(OsmDataLayer.class).stream().filter(
|
||||||
.getLayerManager().getLayersOfType(OsmDataLayer.class).stream().filter(l -> l.getDataSet()
|
l -> l.getDataSet().getDataSourceBounds().stream().anyMatch(b -> area.contains(bound.asRect())))
|
||||||
.getDataSourceBounds().stream().anyMatch(b -> area.contains(bound.asRect())))
|
.toList();
|
||||||
.collect(Collectors.toList());
|
|
||||||
return layers.stream().max(Comparator.comparingInt(l -> l.getDataSet().allPrimitives().size()))
|
return layers.stream().max(Comparator.comparingInt(l -> l.getDataSet().allPrimitives().size()))
|
||||||
.map(OsmDataLayer::getDataSet).orElse(null);
|
.map(OsmDataLayer::getDataSet).orElse(null);
|
||||||
}
|
}
|
||||||
|
@ -229,7 +218,7 @@ public class BoundingBoxMapWithAIDownloader extends BoundingBoxDownloader {
|
||||||
@Override
|
@Override
|
||||||
protected DataSet parseDataSet(InputStream source, ProgressMonitor progressMonitor) throws IllegalDataException {
|
protected DataSet parseDataSet(InputStream source, ProgressMonitor progressMonitor) throws IllegalDataException {
|
||||||
DataSet ds;
|
DataSet ds;
|
||||||
String contentType = this.activeConnection.getResponse().getContentType();
|
final var contentType = this.activeConnection.getResponse().getContentType();
|
||||||
if (Arrays.asList("text/json", "application/json", "application/geo+json").contains(contentType)
|
if (Arrays.asList("text/json", "application/json", "application/geo+json").contains(contentType)
|
||||||
// Fall back to Esri Feature Server check. They don't always indicate a json
|
// Fall back to Esri Feature Server check. They don't always indicate a json
|
||||||
// return type. :(
|
// return type. :(
|
||||||
|
@ -238,15 +227,14 @@ public class BoundingBoxMapWithAIDownloader extends BoundingBoxDownloader {
|
||||||
// if we need to make additional calls
|
// if we need to make additional calls
|
||||||
try (JsonReader reader = Json.createReader(source)) {
|
try (JsonReader reader = Json.createReader(source)) {
|
||||||
JsonStructure structure = reader.read();
|
JsonStructure structure = reader.read();
|
||||||
try (ByteArrayInputStream bais = new ByteArrayInputStream(
|
try (var bais = new ByteArrayInputStream(structure.toString().getBytes(StandardCharsets.UTF_8))) {
|
||||||
structure.toString().getBytes(StandardCharsets.UTF_8))) {
|
|
||||||
ds = GeoJSONReader.parseDataSet(bais, progressMonitor);
|
ds = GeoJSONReader.parseDataSet(bais, progressMonitor);
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
throw new UncheckedIOException(e);
|
throw new UncheckedIOException(e);
|
||||||
}
|
}
|
||||||
/* We should only call this from the "root" call */
|
/* We should only call this from the "root" call */
|
||||||
if (this.start == 0 && structure.getValueType() == JsonValue.ValueType.OBJECT) {
|
if (this.start == 0 && structure.getValueType() == JsonValue.ValueType.OBJECT) {
|
||||||
final JsonObject serverObj = structure.asJsonObject();
|
final var serverObj = structure.asJsonObject();
|
||||||
final boolean exceededTransferLimit = serverObj.entrySet().stream()
|
final boolean exceededTransferLimit = serverObj.entrySet().stream()
|
||||||
.filter(entry -> "properties".equals(entry.getKey())
|
.filter(entry -> "properties".equals(entry.getKey())
|
||||||
&& entry.getValue().getValueType() == JsonValue.ValueType.OBJECT)
|
&& entry.getValue().getValueType() == JsonValue.ValueType.OBJECT)
|
||||||
|
@ -254,7 +242,7 @@ public class BoundingBoxMapWithAIDownloader extends BoundingBoxDownloader {
|
||||||
.map(obj -> obj.getBoolean("exceededTransferLimit", false)).findFirst().orElse(false);
|
.map(obj -> obj.getBoolean("exceededTransferLimit", false)).findFirst().orElse(false);
|
||||||
if (exceededTransferLimit && this.info.getSourceType() == MapWithAIType.ESRI_FEATURE_SERVER) {
|
if (exceededTransferLimit && this.info.getSourceType() == MapWithAIType.ESRI_FEATURE_SERVER) {
|
||||||
final int size = serverObj.getJsonArray("features").size();
|
final int size = serverObj.getJsonArray("features").size();
|
||||||
final DataSet other = this.getAdditionalEsriData(progressMonitor,
|
final var other = this.getAdditionalEsriData(progressMonitor,
|
||||||
this.getRequestForBbox(this.lon1, this.lat1, this.lon2, this.lat2), size);
|
this.getRequestForBbox(this.lon1, this.lat1, this.lon2, this.lat2), size);
|
||||||
ds.mergeFrom(other, progressMonitor.createSubTaskMonitor(0, false));
|
ds.mergeFrom(other, progressMonitor.createSubTaskMonitor(0, false));
|
||||||
}
|
}
|
||||||
|
@ -280,15 +268,15 @@ public class BoundingBoxMapWithAIDownloader extends BoundingBoxDownloader {
|
||||||
}
|
}
|
||||||
|
|
||||||
private DataSet getAdditionalEsriData(ProgressMonitor progressMonitor, String baseUrl, int size) {
|
private DataSet getAdditionalEsriData(ProgressMonitor progressMonitor, String baseUrl, int size) {
|
||||||
DataSet returnDs = new DataSet();
|
final var returnDs = new DataSet();
|
||||||
try {
|
try {
|
||||||
HttpClient client = HttpClient.create(new URL(baseUrl + "&returnCountOnly=true"));
|
final var client = HttpClient.create(new URL(baseUrl + "&returnCountOnly=true"));
|
||||||
int objects = Integer.MIN_VALUE;
|
int objects = Integer.MIN_VALUE;
|
||||||
try (InputStream is = client.connect().getContent(); JsonParser parser = Json.createParser(is)) {
|
try (InputStream is = client.connect().getContent(); JsonParser parser = Json.createParser(is)) {
|
||||||
while (parser.hasNext()) {
|
while (parser.hasNext()) {
|
||||||
JsonParser.Event event = parser.next();
|
final var event = parser.next();
|
||||||
if (event == JsonParser.Event.START_OBJECT) {
|
if (event == JsonParser.Event.START_OBJECT) {
|
||||||
OptionalInt objCount = parser.getObjectStream()
|
final var objCount = parser.getObjectStream()
|
||||||
.filter(entry -> "properties".equals(entry.getKey()))
|
.filter(entry -> "properties".equals(entry.getKey()))
|
||||||
.map(entry -> entry.getValue().asJsonObject())
|
.map(entry -> entry.getValue().asJsonObject())
|
||||||
.mapToInt(properties -> properties.getInt("count")).findFirst();
|
.mapToInt(properties -> properties.getInt("count")).findFirst();
|
||||||
|
@ -310,7 +298,7 @@ public class BoundingBoxMapWithAIDownloader extends BoundingBoxDownloader {
|
||||||
// We have already downloaded some of the objects. Set the ticks.
|
// We have already downloaded some of the objects. Set the ticks.
|
||||||
progressMonitor.worked(size);
|
progressMonitor.worked(size);
|
||||||
while (progressMonitor.getTicks() < progressMonitor.getTicksCount() - 1) {
|
while (progressMonitor.getTicks() < progressMonitor.getTicksCount() - 1) {
|
||||||
DataSet next = new BoundingBoxMapWithAIDownloader(this.downloadArea, this.info, this.crop,
|
final var next = new BoundingBoxMapWithAIDownloader(this.downloadArea, this.info, this.crop,
|
||||||
this.start + size).parseOsm(progressMonitor.createSubTaskMonitor(0, false));
|
this.start + size).parseOsm(progressMonitor.createSubTaskMonitor(0, false));
|
||||||
progressMonitor.worked((int) next.allPrimitives().stream().filter(IPrimitive::isTagged).count());
|
progressMonitor.worked((int) next.allPrimitives().stream().filter(IPrimitive::isTagged).count());
|
||||||
returnDs.mergeFrom(next);
|
returnDs.mergeFrom(next);
|
||||||
|
@ -348,7 +336,7 @@ public class BoundingBoxMapWithAIDownloader extends BoundingBoxDownloader {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void adaptRequest(HttpClient request) {
|
protected void adaptRequest(HttpClient request) {
|
||||||
final StringBuilder defaultUserAgent = new StringBuilder();
|
final var defaultUserAgent = new StringBuilder();
|
||||||
request.setReadTimeout(DEFAULT_TIMEOUT);
|
request.setReadTimeout(DEFAULT_TIMEOUT);
|
||||||
defaultUserAgent.append(request.getHeaders().get("User-Agent"));
|
defaultUserAgent.append(request.getHeaders().get("User-Agent"));
|
||||||
if (defaultUserAgent.toString().trim().length() == 0) {
|
if (defaultUserAgent.toString().trim().length() == 0) {
|
||||||
|
|
|
@ -59,6 +59,11 @@ public final class MapWithAIDataUtils {
|
||||||
public static final int MAXIMUM_SIDE_DIMENSIONS = 10_000; // RapiD is about 1 km, max is 10 km, but 10 km causes
|
public static final int MAXIMUM_SIDE_DIMENSIONS = 10_000; // RapiD is about 1 km, max is 10 km, but 10 km causes
|
||||||
// timeouts
|
// timeouts
|
||||||
private static final int TOO_MANY_BBOXES = 4;
|
private static final int TOO_MANY_BBOXES = 4;
|
||||||
|
/**
|
||||||
|
* {@code true} if we need a fork join pool that is not the
|
||||||
|
* {@link ForkJoinPool#commonPool()}
|
||||||
|
*/
|
||||||
|
private static Boolean requiresForkJoinPool;
|
||||||
private static ForkJoinPool forkJoinPool;
|
private static ForkJoinPool forkJoinPool;
|
||||||
static final Object LAYER_LOCK = new Object();
|
static final Object LAYER_LOCK = new Object();
|
||||||
|
|
||||||
|
@ -248,7 +253,10 @@ public final class MapWithAIDataUtils {
|
||||||
* @return The {@link ForkJoinPool} for MapWithAI use.
|
* @return The {@link ForkJoinPool} for MapWithAI use.
|
||||||
*/
|
*/
|
||||||
public static ForkJoinPool getForkJoinPool() {
|
public static ForkJoinPool getForkJoinPool() {
|
||||||
if (Utils.isRunningWebStart() || System.getSecurityManager() != null) {
|
if (requiresForkJoinPool == null) {
|
||||||
|
requiresForkJoinPool = Utils.isRunningWebStart() || System.getSecurityManager() != null;
|
||||||
|
}
|
||||||
|
if (requiresForkJoinPool) {
|
||||||
synchronized (MapWithAIDataUtils.class) {
|
synchronized (MapWithAIDataUtils.class) {
|
||||||
if (Objects.isNull(forkJoinPool) || forkJoinPool.isShutdown()) {
|
if (Objects.isNull(forkJoinPool) || forkJoinPool.isShutdown()) {
|
||||||
forkJoinPool = Utils.newForkJoinPool(MapWithAIPlugin.NAME.concat(".forkjoinpoolthreads"),
|
forkJoinPool = Utils.newForkJoinPool(MapWithAIPlugin.NAME.concat(".forkjoinpoolthreads"),
|
||||||
|
|
|
@ -9,6 +9,7 @@ import javax.json.JsonObject;
|
||||||
import javax.json.JsonValue;
|
import javax.json.JsonValue;
|
||||||
import javax.json.stream.JsonParser;
|
import javax.json.stream.JsonParser;
|
||||||
|
|
||||||
|
import java.io.Serial;
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
import java.io.StringReader;
|
import java.io.StringReader;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
@ -140,7 +141,7 @@ public class MapWithAIInfo extends
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
StringBuilder s = new StringBuilder("MapWithAIPreferenceEntry [name=").append(name);
|
final var s = new StringBuilder("MapWithAIPreferenceEntry [name=").append(name);
|
||||||
if (id != null) {
|
if (id != null) {
|
||||||
s.append(" id=").append(id);
|
s.append(" id=").append(id);
|
||||||
}
|
}
|
||||||
|
@ -154,6 +155,7 @@ public class MapWithAIInfo extends
|
||||||
*/
|
*/
|
||||||
public static class MapWithAIInfoCategoryComparator implements Comparator<MapWithAIInfo>, Serializable {
|
public static class MapWithAIInfoCategoryComparator implements Comparator<MapWithAIInfo>, Serializable {
|
||||||
|
|
||||||
|
@Serial
|
||||||
private static final long serialVersionUID = -7992892476979310835L;
|
private static final long serialVersionUID = -7992892476979310835L;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -219,15 +221,8 @@ public class MapWithAIInfo extends
|
||||||
*/
|
*/
|
||||||
public MapWithAIInfo(String name, String url, String type, String eulaAcceptanceRequired, String id) {
|
public MapWithAIInfo(String name, String url, String type, String eulaAcceptanceRequired, String id) {
|
||||||
this(name, url, id);
|
this(name, url, id);
|
||||||
MapWithAIType t = MapWithAIType.fromString(type);
|
|
||||||
this.setEulaAcceptanceRequired(eulaAcceptanceRequired);
|
this.setEulaAcceptanceRequired(eulaAcceptanceRequired);
|
||||||
if (t != null) {
|
super.setSourceType(MapWithAIType.fromString(type));
|
||||||
super.setSourceType(t);
|
|
||||||
} else if (type != null && !type.isEmpty()) {
|
|
||||||
throw new IllegalArgumentException("unknown type: " + type);
|
|
||||||
} else {
|
|
||||||
super.setSourceType(MapWithAIType.THIRD_PARTY.getDefault());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -243,7 +238,7 @@ public class MapWithAIInfo extends
|
||||||
setCookies(e.cookies);
|
setCookies(e.cookies);
|
||||||
setEulaAcceptanceRequired(e.eula);
|
setEulaAcceptanceRequired(e.eula);
|
||||||
if (e.parameters != null) {
|
if (e.parameters != null) {
|
||||||
try (JsonParser parser = Json.createParser(new StringReader(e.parameters))) {
|
try (var parser = Json.createParser(new StringReader(e.parameters))) {
|
||||||
if (parser.hasNext() && JsonParser.Event.START_ARRAY == parser.next()) {
|
if (parser.hasNext() && JsonParser.Event.START_ARRAY == parser.next()) {
|
||||||
setParameters(parser.getArray());
|
setParameters(parser.getArray());
|
||||||
}
|
}
|
||||||
|
@ -379,7 +374,7 @@ public class MapWithAIInfo extends
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (first != null && second != null && first.size() == second.size()) {
|
if (first != null && second != null && first.size() == second.size()) {
|
||||||
for (JsonObject value : Utils.filteredCollection(first, JsonObject.class)) {
|
for (var value : Utils.filteredCollection(first, JsonObject.class)) {
|
||||||
if (value.containsKey(PARAMETER_STRING)
|
if (value.containsKey(PARAMETER_STRING)
|
||||||
&& value.get(PARAMETER_STRING).getValueType() == JsonValue.ValueType.STRING
|
&& value.get(PARAMETER_STRING).getValueType() == JsonValue.ValueType.STRING
|
||||||
&& Utils.filteredCollection(second, JsonObject.class).stream()
|
&& Utils.filteredCollection(second, JsonObject.class).stream()
|
||||||
|
@ -483,35 +478,42 @@ public class MapWithAIInfo extends
|
||||||
return getParametersString(this.conflationParameters);
|
return getParametersString(this.conflationParameters);
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getUrlExpanded() {
|
/**
|
||||||
StringBuilder sb;
|
* Check if this source will have a valid URL when {@link #getUrlExpanded()} is
|
||||||
if (this.isConflated()) {
|
* called
|
||||||
sb = getConflationUrl();
|
*
|
||||||
} else {
|
* @return {@code true} if this source will have a valid url
|
||||||
sb = getNonConflatedUrl();
|
*/
|
||||||
|
public boolean hasValidUrl() {
|
||||||
|
return this.url != null || (this.isConflated() && this.conflationUrl != null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getUrlExpanded() {
|
||||||
|
if (this.isConflated()) {
|
||||||
|
return getConflationUrl().toString();
|
||||||
|
} else {
|
||||||
|
return getNonConflatedUrl().toString();
|
||||||
}
|
}
|
||||||
return sb.toString();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private StringBuilder getConflationUrl() {
|
private StringBuilder getConflationUrl() {
|
||||||
if (conflationUrl == null) {
|
if (conflationUrl == null) {
|
||||||
return getNonConflatedUrl();
|
return getNonConflatedUrl();
|
||||||
}
|
}
|
||||||
StringBuilder sb = new StringBuilder();
|
final var sb = new StringBuilder();
|
||||||
if (this.conflationUrl.contains("{id}") && this.id != null) {
|
if (this.conflationUrl.contains("{id}") && this.id != null) {
|
||||||
sb.append(conflationUrl.replace("{id}", this.id));
|
sb.append(conflationUrl.replace("{id}", this.id));
|
||||||
} else if (this.conflationUrl.contains("{id}")) {
|
} else if (this.conflationUrl.contains("{id}")) {
|
||||||
// We need to trigger synchronization. This means that the current download
|
// We need to trigger synchronization. This means that the current download
|
||||||
// may won't be conflated.
|
// may won't be conflated.
|
||||||
// But this should automatically correct the behavior for the next attempt.
|
// But this should automatically correct the behavior for the next attempt.
|
||||||
final MapWithAILayerInfo mwli = MapWithAILayerInfo.getInstance();
|
final var mwli = MapWithAILayerInfo.getInstance();
|
||||||
mwli.load(false, () -> {
|
mwli.load(false, () -> {
|
||||||
Optional<MapWithAIInfo> defaultLayer = mwli.getAllDefaultLayers().stream().filter(this::equals)
|
final var defaultLayer = mwli.getAllDefaultLayers().stream().filter(this::equals).findFirst();
|
||||||
.findFirst();
|
|
||||||
if (defaultLayer.isPresent()) {
|
if (defaultLayer.isPresent()) {
|
||||||
this.id = defaultLayer.get().id;
|
this.id = defaultLayer.get().id;
|
||||||
} else {
|
} else {
|
||||||
MapWithAIInfo newInfo = mwli.getAllDefaultLayers().stream()
|
final var newInfo = mwli.getAllDefaultLayers().stream()
|
||||||
.filter(layer -> Objects.equals(this.url, layer.url) && Objects.nonNull(layer.id))
|
.filter(layer -> Objects.equals(this.url, layer.url) && Objects.nonNull(layer.id))
|
||||||
.findFirst().orElse(this);
|
.findFirst().orElse(this);
|
||||||
this.id = newInfo.id;
|
this.id = newInfo.id;
|
||||||
|
@ -530,7 +532,7 @@ public class MapWithAIInfo extends
|
||||||
}
|
}
|
||||||
|
|
||||||
private StringBuilder getNonConflatedUrl() {
|
private StringBuilder getNonConflatedUrl() {
|
||||||
StringBuilder sb = new StringBuilder();
|
final var sb = new StringBuilder();
|
||||||
if (url != null && !url.trim().isEmpty()) {
|
if (url != null && !url.trim().isEmpty()) {
|
||||||
sb.append(url);
|
sb.append(url);
|
||||||
if (MapWithAIType.ESRI_FEATURE_SERVER == sourceType) {
|
if (MapWithAIType.ESRI_FEATURE_SERVER == sourceType) {
|
||||||
|
@ -624,7 +626,7 @@ public class MapWithAIInfo extends
|
||||||
* @param parameters Set the conflation parameters
|
* @param parameters Set the conflation parameters
|
||||||
*/
|
*/
|
||||||
public void setConflationParameters(JsonArray parameters) {
|
public void setConflationParameters(JsonArray parameters) {
|
||||||
this.conflationParameters = parameters != null ? Json.createArrayBuilder(parameters).build() : null;
|
this.conflationParameters = parameters;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -7,6 +7,8 @@ import javax.annotation.Nonnull;
|
||||||
import javax.swing.SwingUtilities;
|
import javax.swing.SwingUtilities;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.io.Serial;
|
||||||
|
import java.time.Instant;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
|
@ -16,7 +18,6 @@ import java.util.HashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
import java.util.Set;
|
|
||||||
import java.util.TreeSet;
|
import java.util.TreeSet;
|
||||||
import java.util.concurrent.ExecutionException;
|
import java.util.concurrent.ExecutionException;
|
||||||
import java.util.concurrent.ForkJoinPool;
|
import java.util.concurrent.ForkJoinPool;
|
||||||
|
@ -80,7 +81,7 @@ public class MapWithAILayerInfo {
|
||||||
if (instance != null) {
|
if (instance != null) {
|
||||||
return instance;
|
return instance;
|
||||||
}
|
}
|
||||||
final AtomicBoolean finished = new AtomicBoolean();
|
final var finished = new AtomicBoolean();
|
||||||
synchronized (MapWithAILayerInfo.class) {
|
synchronized (MapWithAILayerInfo.class) {
|
||||||
if (instance == null) {
|
if (instance == null) {
|
||||||
instance = new MapWithAILayerInfo(() -> {
|
instance = new MapWithAILayerInfo(() -> {
|
||||||
|
@ -156,16 +157,6 @@ public class MapWithAILayerInfo {
|
||||||
layerIds.clear();
|
layerIds.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Loads the custom as well as default imagery entries.
|
|
||||||
*
|
|
||||||
* @param fastFail whether opening HTTP connections should fail fast, see
|
|
||||||
* {@link ImageryReader#setFastFail(boolean)}
|
|
||||||
*/
|
|
||||||
public void load(boolean fastFail) {
|
|
||||||
load(fastFail, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Loads the custom as well as default imagery entries.
|
* Loads the custom as well as default imagery entries.
|
||||||
*
|
*
|
||||||
|
@ -175,12 +166,12 @@ public class MapWithAILayerInfo {
|
||||||
*/
|
*/
|
||||||
public void load(boolean fastFail, FinishListener listener) {
|
public void load(boolean fastFail, FinishListener listener) {
|
||||||
clear();
|
clear();
|
||||||
List<MapWithAIPreferenceEntry> entries = StructUtils.getListOfStructs(Config.getPref(),
|
final var entries = StructUtils.getListOfStructs(Config.getPref(), CONFIG_PREFIX + "entries", null,
|
||||||
CONFIG_PREFIX + "entries", null, MapWithAIPreferenceEntry.class);
|
MapWithAIPreferenceEntry.class);
|
||||||
if (entries != null) {
|
if (entries != null) {
|
||||||
for (MapWithAIPreferenceEntry prefEntry : entries) {
|
for (MapWithAIPreferenceEntry prefEntry : entries) {
|
||||||
try {
|
try {
|
||||||
MapWithAIInfo i = new MapWithAIInfo(prefEntry);
|
final var i = new MapWithAIInfo(prefEntry);
|
||||||
add(i);
|
add(i);
|
||||||
} catch (IllegalArgumentException e) {
|
} catch (IllegalArgumentException e) {
|
||||||
Logging.warn("Unable to load imagery preference entry:" + e);
|
Logging.warn("Unable to load imagery preference entry:" + e);
|
||||||
|
@ -200,7 +191,7 @@ public class MapWithAILayerInfo {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Loads the available imagery entries.
|
* Loads the available imagery entries.
|
||||||
*
|
* <p>
|
||||||
* The data is downloaded from the JOSM website (or loaded from cache). Entries
|
* The data is downloaded from the JOSM website (or loaded from cache). Entries
|
||||||
* marked as "default" are added to the user selection, if not already present.
|
* marked as "default" are added to the user selection, if not already present.
|
||||||
*
|
*
|
||||||
|
@ -214,7 +205,7 @@ public class MapWithAILayerInfo {
|
||||||
* @since 12634
|
* @since 12634
|
||||||
*/
|
*/
|
||||||
public void loadDefaults(boolean clearCache, ForkJoinPool worker, boolean fastFail, FinishListener listener) {
|
public void loadDefaults(boolean clearCache, ForkJoinPool worker, boolean fastFail, FinishListener listener) {
|
||||||
final DefaultEntryLoader loader = new DefaultEntryLoader(clearCache, fastFail);
|
final var loader = new DefaultEntryLoader(clearCache, fastFail);
|
||||||
if (this.finishListenerListenerList == null) {
|
if (this.finishListenerListenerList == null) {
|
||||||
this.finishListenerListenerList = ListenerList.create();
|
this.finishListenerListenerList = ListenerList.create();
|
||||||
}
|
}
|
||||||
|
@ -222,7 +213,7 @@ public class MapWithAILayerInfo {
|
||||||
this.finishListenerListenerList.addListener(listener);
|
this.finishListenerListenerList.addListener(listener);
|
||||||
}
|
}
|
||||||
if (worker == null) {
|
if (worker == null) {
|
||||||
PleaseWaitRunnable pleaseWaitRunnable = new PleaseWaitRunnable(tr("Update default entries")) {
|
final var pleaseWaitRunnable = new PleaseWaitRunnable(tr("Update default entries")) {
|
||||||
@Override
|
@Override
|
||||||
protected void cancel() {
|
protected void cancel() {
|
||||||
loader.canceled = true;
|
loader.canceled = true;
|
||||||
|
@ -262,6 +253,7 @@ public class MapWithAILayerInfo {
|
||||||
*/
|
*/
|
||||||
class DefaultEntryLoader extends RecursiveTask<List<MapWithAIInfo>> {
|
class DefaultEntryLoader extends RecursiveTask<List<MapWithAIInfo>> {
|
||||||
|
|
||||||
|
@Serial
|
||||||
private static final long serialVersionUID = 12550342142551680L;
|
private static final long serialVersionUID = 12550342142551680L;
|
||||||
private final boolean clearCache;
|
private final boolean clearCache;
|
||||||
private final boolean fastFail;
|
private final boolean fastFail;
|
||||||
|
@ -329,7 +321,7 @@ public class MapWithAILayerInfo {
|
||||||
reader = new MapWithAISourceReader(source);
|
reader = new MapWithAISourceReader(source);
|
||||||
this.reader.setClearCache(this.clearCache);
|
this.reader.setClearCache(this.clearCache);
|
||||||
reader.setFastFail(fastFail);
|
reader.setFastFail(fastFail);
|
||||||
Collection<MapWithAIInfo> result = reader.parse().orElse(Collections.emptyList());
|
final var result = reader.parse().orElse(Collections.emptyList());
|
||||||
// This is called here to "pre-cache" the layer information, to avoid blocking
|
// This is called here to "pre-cache" the layer information, to avoid blocking
|
||||||
// the EDT
|
// the EDT
|
||||||
this.updateEsriLayers(result);
|
this.updateEsriLayers(result);
|
||||||
|
@ -346,9 +338,9 @@ public class MapWithAILayerInfo {
|
||||||
* @param layers The layers to update
|
* @param layers The layers to update
|
||||||
*/
|
*/
|
||||||
private void updateEsriLayers(@Nonnull final Collection<MapWithAIInfo> layers) {
|
private void updateEsriLayers(@Nonnull final Collection<MapWithAIInfo> layers) {
|
||||||
for (MapWithAIInfo layer : layers) {
|
for (var layer : layers) {
|
||||||
if (MapWithAIType.ESRI == layer.getSourceType()) {
|
if (MapWithAIType.ESRI == layer.getSourceType()) {
|
||||||
for (ForkJoinTask<MapWithAIInfo> future : parseEsri(layer)) {
|
for (var future : parseEsri(layer)) {
|
||||||
try {
|
try {
|
||||||
allDefaultLayers.add(future.get());
|
allDefaultLayers.add(future.get());
|
||||||
} catch (InterruptedException e) {
|
} catch (InterruptedException e) {
|
||||||
|
@ -385,8 +377,9 @@ public class MapWithAILayerInfo {
|
||||||
if (!loadError && !defaultLayerIds.isEmpty()) {
|
if (!loadError && !defaultLayerIds.isEmpty()) {
|
||||||
dropOldEntries();
|
dropOldEntries();
|
||||||
}
|
}
|
||||||
final ListenerList<FinishListener> listenerList = MapWithAILayerInfo.this.finishListenerListenerList;
|
final var listenerList = MapWithAILayerInfo.this.finishListenerListenerList;
|
||||||
MapWithAILayerInfo.this.finishListenerListenerList = null;
|
MapWithAILayerInfo.this.finishListenerListenerList = null;
|
||||||
|
Config.getPref().putLong("mapwithai.layerinfo.lastupdated", Instant.now().getEpochSecond());
|
||||||
if (listenerList != null) {
|
if (listenerList != null) {
|
||||||
listenerList.fireEvent(FinishListener::onFinish);
|
listenerList.fireEvent(FinishListener::onFinish);
|
||||||
}
|
}
|
||||||
|
@ -415,8 +408,8 @@ public class MapWithAILayerInfo {
|
||||||
*/
|
*/
|
||||||
private void buildIdMap(List<MapWithAIInfo> lst, Map<String, MapWithAIInfo> idMap) {
|
private void buildIdMap(List<MapWithAIInfo> lst, Map<String, MapWithAIInfo> idMap) {
|
||||||
idMap.clear();
|
idMap.clear();
|
||||||
Set<String> notUnique = new HashSet<>();
|
final var notUnique = new HashSet<String>();
|
||||||
for (MapWithAIInfo i : lst) {
|
for (var i : lst) {
|
||||||
if (i.getId() != null) {
|
if (i.getId() != null) {
|
||||||
if (idMap.containsKey(i.getId())) {
|
if (idMap.containsKey(i.getId())) {
|
||||||
notUnique.add(i.getId());
|
notUnique.add(i.getId());
|
||||||
|
@ -427,7 +420,7 @@ public class MapWithAILayerInfo {
|
||||||
idMap.put(i.getId(), i);
|
idMap.put(i.getId(), i);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (String i : notUnique) {
|
for (var i : notUnique) {
|
||||||
idMap.remove(i);
|
idMap.remove(i);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -441,14 +434,14 @@ public class MapWithAILayerInfo {
|
||||||
*/
|
*/
|
||||||
public void updateEntriesFromDefaults(boolean dropold) {
|
public void updateEntriesFromDefaults(boolean dropold) {
|
||||||
// add new default entries to the user selection
|
// add new default entries to the user selection
|
||||||
boolean changed = false;
|
var changed = false;
|
||||||
Collection<String> knownDefaults = new TreeSet<>(Config.getPref().getList(CONFIG_PREFIX + "layers.default"));
|
final var knownDefaults = new TreeSet<>(Config.getPref().getList(CONFIG_PREFIX + "layers.default"));
|
||||||
Collection<String> newKnownDefaults = new TreeSet<>();
|
final var newKnownDefaults = new TreeSet<String>();
|
||||||
synchronized (defaultLayers) {
|
synchronized (defaultLayers) {
|
||||||
for (MapWithAIInfo def : defaultLayers) {
|
for (var def : defaultLayers) {
|
||||||
if (def.isDefaultEntry()) {
|
if (def.isDefaultEntry()) {
|
||||||
boolean isKnownDefault = false;
|
var isKnownDefault = false;
|
||||||
for (String entry : knownDefaults) {
|
for (var entry : knownDefaults) {
|
||||||
if (entry.equals(def.getId())) {
|
if (entry.equals(def.getId())) {
|
||||||
isKnownDefault = true;
|
isKnownDefault = true;
|
||||||
newKnownDefaults.add(entry);
|
newKnownDefaults.add(entry);
|
||||||
|
@ -463,11 +456,11 @@ public class MapWithAILayerInfo {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
boolean isInUserList = false;
|
var isInUserList = false;
|
||||||
if (!isKnownDefault) {
|
if (!isKnownDefault) {
|
||||||
if (def.getId() != null) {
|
if (def.getId() != null) {
|
||||||
newKnownDefaults.add(def.getId());
|
newKnownDefaults.add(def.getId());
|
||||||
for (MapWithAIInfo i : layers) {
|
for (var i : layers) {
|
||||||
if (isSimilar(def, i)) {
|
if (isSimilar(def, i)) {
|
||||||
isInUserList = true;
|
isInUserList = true;
|
||||||
break;
|
break;
|
||||||
|
@ -490,12 +483,12 @@ public class MapWithAILayerInfo {
|
||||||
Config.getPref().putList(CONFIG_PREFIX + "layers.default", new ArrayList<>(newKnownDefaults));
|
Config.getPref().putList(CONFIG_PREFIX + "layers.default", new ArrayList<>(newKnownDefaults));
|
||||||
|
|
||||||
// automatically update user entries with same id as a default entry
|
// automatically update user entries with same id as a default entry
|
||||||
for (int i = 0; i < layers.size(); i++) {
|
for (var i = 0; i < layers.size(); i++) {
|
||||||
MapWithAIInfo info = layers.get(i);
|
final var info = layers.get(i);
|
||||||
if (info.getId() == null) {
|
if (info.getId() == null) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
MapWithAIInfo matchingDefault = defaultLayerIds.get(info.getId());
|
final var matchingDefault = defaultLayerIds.get(info.getId());
|
||||||
if (matchingDefault != null && !matchingDefault.equalsPref(info)) {
|
if (matchingDefault != null && !matchingDefault.equalsPref(info)) {
|
||||||
layers.set(i, matchingDefault);
|
layers.set(i, matchingDefault);
|
||||||
Logging.info(tr("Update imagery ''{0}''", info.getName()));
|
Logging.info(tr("Update imagery ''{0}''", info.getName()));
|
||||||
|
@ -514,9 +507,9 @@ public class MapWithAILayerInfo {
|
||||||
* @since 11527
|
* @since 11527
|
||||||
*/
|
*/
|
||||||
public void dropOldEntries() {
|
public void dropOldEntries() {
|
||||||
List<String> drop = new ArrayList<>();
|
final var drop = new ArrayList<String>();
|
||||||
|
|
||||||
for (Map.Entry<String, MapWithAIInfo> info : layerIds.entrySet()) {
|
for (var info : layerIds.entrySet()) {
|
||||||
if (!defaultLayerIds.containsKey(info.getKey())) {
|
if (!defaultLayerIds.containsKey(info.getKey())) {
|
||||||
remove(info.getValue());
|
remove(info.getValue());
|
||||||
drop.add(info.getKey());
|
drop.add(info.getKey());
|
||||||
|
@ -525,7 +518,7 @@ public class MapWithAILayerInfo {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!drop.isEmpty()) {
|
if (!drop.isEmpty()) {
|
||||||
for (String id : drop) {
|
for (var id : drop) {
|
||||||
layerIds.remove(id);
|
layerIds.remove(id);
|
||||||
}
|
}
|
||||||
save();
|
save();
|
||||||
|
@ -573,9 +566,9 @@ public class MapWithAILayerInfo {
|
||||||
* Save the list of imagery entries to preferences.
|
* Save the list of imagery entries to preferences.
|
||||||
*/
|
*/
|
||||||
public synchronized void save() {
|
public synchronized void save() {
|
||||||
List<MapWithAIPreferenceEntry> entries = new ArrayList<>();
|
final var entries = new ArrayList<MapWithAIPreferenceEntry>();
|
||||||
synchronized (layers) {
|
synchronized (layers) {
|
||||||
for (MapWithAIInfo info : layers) {
|
for (var info : layers) {
|
||||||
entries.add(new MapWithAIPreferenceEntry(info));
|
entries.add(new MapWithAIPreferenceEntry(info));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -625,8 +618,7 @@ public class MapWithAILayerInfo {
|
||||||
return layers.stream()
|
return layers.stream()
|
||||||
.filter(i -> i.getCategory() != MapWithAICategory.PREVIEW
|
.filter(i -> i.getCategory() != MapWithAICategory.PREVIEW
|
||||||
&& !i.getAdditionalCategories().contains(MapWithAICategory.PREVIEW))
|
&& !i.getAdditionalCategories().contains(MapWithAICategory.PREVIEW))
|
||||||
.filter(info -> !Utils.isBlank(info.getUrlExpanded()) && !Utils.isBlank(info.getUrl()))
|
.filter(MapWithAIInfo::hasValidUrl).collect(Collectors.toList());
|
||||||
.collect(Collectors.toList());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -652,7 +644,7 @@ public class MapWithAILayerInfo {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get unique id for ImageryInfo.
|
* Get unique id for ImageryInfo.
|
||||||
*
|
* <p>
|
||||||
* This takes care, that no id is used twice (due to a user error)
|
* This takes care, that no id is used twice (due to a user error)
|
||||||
*
|
*
|
||||||
* @param info the ImageryInfo to look up
|
* @param info the ImageryInfo to look up
|
||||||
|
|
|
@ -37,7 +37,7 @@ public class MapWithAIDownloadOptions extends JPanel implements DownloadSelectio
|
||||||
*/
|
*/
|
||||||
public MapWithAIDownloadOptions() {
|
public MapWithAIDownloadOptions() {
|
||||||
optionPanel = new JPanel(new GridBagLayout());
|
optionPanel = new JPanel(new GridBagLayout());
|
||||||
JPanel infoHeader = new JPanel();
|
final var infoHeader = new JPanel();
|
||||||
infoHeader.add(new JLabel("Browse and activate extra data sets to facilitate your mapping needs."));
|
infoHeader.add(new JLabel("Browse and activate extra data sets to facilitate your mapping needs."));
|
||||||
optionPanel.add(infoHeader, GBC.eol().fill(GridBagConstraints.HORIZONTAL).anchor(GridBagConstraints.NORTH));
|
optionPanel.add(infoHeader, GBC.eol().fill(GridBagConstraints.HORIZONTAL).anchor(GridBagConstraints.NORTH));
|
||||||
mapwithaiProvidersPanel = new MapWithAIProvidersPanel(this);
|
mapwithaiProvidersPanel = new MapWithAIProvidersPanel(this);
|
||||||
|
@ -63,7 +63,7 @@ public class MapWithAIDownloadOptions extends JPanel implements DownloadSelectio
|
||||||
@Override
|
@Override
|
||||||
public void destroy() {
|
public void destroy() {
|
||||||
if (this.iGui != null) {
|
if (this.iGui != null) {
|
||||||
for (JComponent component : getJComponents(this.iGui.getComponents())) {
|
for (var component : getJComponents(this.iGui.getComponents())) {
|
||||||
removeFromComponent(component);
|
removeFromComponent(component);
|
||||||
}
|
}
|
||||||
this.iGui.removeDownloadAreaListener(this);
|
this.iGui.removeDownloadAreaListener(this);
|
||||||
|
@ -77,7 +77,7 @@ public class MapWithAIDownloadOptions extends JPanel implements DownloadSelectio
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean removeFromComponent(JComponent component) {
|
private boolean removeFromComponent(JComponent component) {
|
||||||
for (JComponent newComponent : getJComponents(component.getComponents())) {
|
for (var newComponent : getJComponents(component.getComponents())) {
|
||||||
if (optionPanel.equals(newComponent)) {
|
if (optionPanel.equals(newComponent)) {
|
||||||
component.remove(optionPanel);
|
component.remove(optionPanel);
|
||||||
return true;
|
return true;
|
||||||
|
|
|
@ -25,10 +25,9 @@ import java.util.Arrays;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.TreeMap;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
import org.openstreetmap.josm.actions.ExpertToggleAction;
|
import org.openstreetmap.josm.actions.ExpertToggleAction;
|
||||||
import org.openstreetmap.josm.data.preferences.BooleanProperty;
|
|
||||||
import org.openstreetmap.josm.gui.preferences.DefaultTabPreferenceSetting;
|
import org.openstreetmap.josm.gui.preferences.DefaultTabPreferenceSetting;
|
||||||
import org.openstreetmap.josm.gui.preferences.PreferenceTabbedPane;
|
import org.openstreetmap.josm.gui.preferences.PreferenceTabbedPane;
|
||||||
import org.openstreetmap.josm.gui.preferences.advanced.PrefEntry;
|
import org.openstreetmap.josm.gui.preferences.advanced.PrefEntry;
|
||||||
|
@ -68,17 +67,14 @@ public class MapWithAIPreferences extends DefaultTabPreferenceSetting {
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void fillReplacementTagDisplayData(List<PrefEntry> list) {
|
private static void fillReplacementTagDisplayData(List<PrefEntry> list) {
|
||||||
final Map<String, String> current = new TreeMap<>(MapWithAIPreferenceHelper.getReplacementTags());
|
MapWithAIPreferenceHelper.getReplacementTags().forEach(
|
||||||
for (final Map.Entry<String, String> entry : current.entrySet()) {
|
(key, value) -> list.add(new PrefEntry(key, new StringSetting(value), new StringSetting(null), false)));
|
||||||
list.add(
|
|
||||||
new PrefEntry(entry.getKey(), new StringSetting(entry.getValue()), new StringSetting(null), false));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void addGui(PreferenceTabbedPane gui) {
|
public void addGui(PreferenceTabbedPane gui) {
|
||||||
final JPanel p = gui.createPreferenceTab(this);
|
final var p = gui.createPreferenceTab(this);
|
||||||
final JTabbedPane panel = getTabPane();
|
final var panel = getTabPane();
|
||||||
if (panel.getTabCount() == 0) {
|
if (panel.getTabCount() == 0) {
|
||||||
panel.addTab(tr("Servers"), getServerList(gui));
|
panel.addTab(tr("Servers"), getServerList(gui));
|
||||||
panel.addTab(tr("Settings"), getSettingsPanel(gui));
|
panel.addTab(tr("Settings"), getSettingsPanel(gui));
|
||||||
|
@ -91,12 +87,12 @@ public class MapWithAIPreferences extends DefaultTabPreferenceSetting {
|
||||||
}
|
}
|
||||||
|
|
||||||
private Component getSettingsPanel(PreferenceTabbedPane gui) {
|
private Component getSettingsPanel(PreferenceTabbedPane gui) {
|
||||||
final JPanel pane = new JPanel(new GridBagLayout());
|
final var pane = new JPanel(new GridBagLayout());
|
||||||
final int width = 200;
|
final var width = 200;
|
||||||
final int height = 200;
|
final var height = 200;
|
||||||
final JLabel switchLayer = new JLabel(tr("Automatically switch layers"));
|
final var switchLayer = new JLabel(tr("Automatically switch layers"));
|
||||||
final JLabel maximumAddition = new JLabel(tr("Maximum features (add)"));
|
final var maximumAddition = new JLabel(tr("Maximum features (add)"));
|
||||||
final JLabel mergeBuildingWithAddress = new JLabel(tr("Merge address nodes and buildings"));
|
final var mergeBuildingWithAddress = new JLabel(tr("Merge address nodes and buildings"));
|
||||||
|
|
||||||
switchLayer.setToolTipText(
|
switchLayer.setToolTipText(
|
||||||
tr("If checked, automatically switch from the {0} layer to the OSM layer when objects are added",
|
tr("If checked, automatically switch from the {0} layer to the OSM layer when objects are added",
|
||||||
|
@ -116,9 +112,9 @@ public class MapWithAIPreferences extends DefaultTabPreferenceSetting {
|
||||||
pane.setAlignmentY(Component.TOP_ALIGNMENT);
|
pane.setAlignmentY(Component.TOP_ALIGNMENT);
|
||||||
pane.setAlignmentX(Component.LEFT_ALIGNMENT);
|
pane.setAlignmentX(Component.LEFT_ALIGNMENT);
|
||||||
|
|
||||||
final GBC first = GBC.std().weight(0, 1).anchor(GridBagConstraints.WEST);
|
final var first = GBC.std().weight(0, 1).anchor(GridBagConstraints.WEST);
|
||||||
final GBC second = GBC.eol().fill(GridBagConstraints.HORIZONTAL);
|
final var second = GBC.eol().fill(GridBagConstraints.HORIZONTAL);
|
||||||
final GBC buttonInsets = GBC.std().insets(5, 5, 0, 0);
|
final var buttonInsets = GBC.std().insets(5, 5, 0, 0);
|
||||||
|
|
||||||
pane.add(switchLayer, first);
|
pane.add(switchLayer, first);
|
||||||
|
|
||||||
|
@ -132,11 +128,11 @@ public class MapWithAIPreferences extends DefaultTabPreferenceSetting {
|
||||||
pane.add(mergeBuildingWithAddress, first);
|
pane.add(mergeBuildingWithAddress, first);
|
||||||
pane.add(mergeBuildingAddressCheckBox, second);
|
pane.add(mergeBuildingAddressCheckBox, second);
|
||||||
|
|
||||||
final Component expertHorizontalGlue = Box.createHorizontalGlue();
|
final var expertHorizontalGlue = Box.createHorizontalGlue();
|
||||||
pane.add(expertHorizontalGlue, GBC.eol().fill(GridBagConstraints.HORIZONTAL));
|
pane.add(expertHorizontalGlue, GBC.eol().fill(GridBagConstraints.HORIZONTAL));
|
||||||
final JLabel previewFeatureSets = new JLabel(tr("Show Preview DataSets"));
|
final var previewFeatureSets = new JLabel(tr("Show Preview DataSets"));
|
||||||
final JCheckBox previewFeatureSetCheckbox = new JCheckBox();
|
final var previewFeatureSetCheckbox = new JCheckBox();
|
||||||
BooleanProperty previewFeatureSetProperty = MapWithAILayerInfo.SHOW_PREVIEW;
|
final var previewFeatureSetProperty = MapWithAILayerInfo.SHOW_PREVIEW;
|
||||||
previewFeatureSetCheckbox.setToolTipText(tr("If selected, show datasets which may have various issues"));
|
previewFeatureSetCheckbox.setToolTipText(tr("If selected, show datasets which may have various issues"));
|
||||||
previewFeatureSetCheckbox.setSelected(Boolean.TRUE.equals(previewFeatureSetProperty.get()));
|
previewFeatureSetCheckbox.setSelected(Boolean.TRUE.equals(previewFeatureSetProperty.get()));
|
||||||
previewFeatureSetCheckbox
|
previewFeatureSetCheckbox
|
||||||
|
@ -144,19 +140,19 @@ public class MapWithAIPreferences extends DefaultTabPreferenceSetting {
|
||||||
pane.add(previewFeatureSets, first);
|
pane.add(previewFeatureSets, first);
|
||||||
pane.add(previewFeatureSetCheckbox, second);
|
pane.add(previewFeatureSetCheckbox, second);
|
||||||
|
|
||||||
final JLabel replacementTags = new JLabel(tr("Replacement Tags (to be replaced on download)"));
|
final var replacementTags = new JLabel(tr("Replacement Tags (to be replaced on download)"));
|
||||||
pane.add(replacementTags, first);
|
pane.add(replacementTags, first);
|
||||||
final JScrollPane scroll2 = new JScrollPane(replacementPreferenceTable);
|
final var scroll2 = new JScrollPane(replacementPreferenceTable);
|
||||||
pane.add(scroll2, GBC.eol().fill(GridBagConstraints.BOTH));
|
pane.add(scroll2, GBC.eol().fill(GridBagConstraints.BOTH));
|
||||||
scroll2.setPreferredSize(new Dimension(width, height));
|
scroll2.setPreferredSize(new Dimension(width, height));
|
||||||
|
|
||||||
pane.add(new JLabel(), first);
|
pane.add(new JLabel(), first);
|
||||||
final JPanel replaceAddEditDeleteScroll2 = new JPanel(new GridBagLayout());
|
final var replaceAddEditDeleteScroll2 = new JPanel(new GridBagLayout());
|
||||||
pane.add(replaceAddEditDeleteScroll2, second);
|
pane.add(replaceAddEditDeleteScroll2, second);
|
||||||
final JButton addScroll2 = new JButton(tr("Add"));
|
final var addScroll2 = new JButton(tr("Add"));
|
||||||
replaceAddEditDeleteScroll2.add(addScroll2, buttonInsets);
|
replaceAddEditDeleteScroll2.add(addScroll2, buttonInsets);
|
||||||
addScroll2.addActionListener(e -> {
|
addScroll2.addActionListener(e -> {
|
||||||
final PrefEntry pe = replacementPreferenceTable.addPreference(gui);
|
final var pe = replacementPreferenceTable.addPreference(gui);
|
||||||
if ((pe != null) && (pe.getValue() instanceof StringSetting)) {
|
if ((pe != null) && (pe.getValue() instanceof StringSetting)) {
|
||||||
replacementTableDisplayData.add(pe);
|
replacementTableDisplayData.add(pe);
|
||||||
Collections.sort(replacementTableDisplayData);
|
Collections.sort(replacementTableDisplayData);
|
||||||
|
@ -164,19 +160,19 @@ public class MapWithAIPreferences extends DefaultTabPreferenceSetting {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
final JButton editScroll2 = new JButton(tr("Edit"));
|
final var editScroll2 = new JButton(tr("Edit"));
|
||||||
replaceAddEditDeleteScroll2.add(editScroll2, buttonInsets);
|
replaceAddEditDeleteScroll2.add(editScroll2, buttonInsets);
|
||||||
editScroll2.addActionListener(e -> {
|
editScroll2.addActionListener(e -> {
|
||||||
final List<PrefEntry> toEdit = replacementPreferenceTable.getSelectedItems();
|
final var toEdit = replacementPreferenceTable.getSelectedItems();
|
||||||
if (toEdit.size() == MAX_SELECTED_TO_EDIT) {
|
if (toEdit.size() == MAX_SELECTED_TO_EDIT) {
|
||||||
replacementPreferenceTable.editPreference(gui);
|
replacementPreferenceTable.editPreference(gui);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
final JButton deleteScroll2 = new JButton(tr("Delete"));
|
final var deleteScroll2 = new JButton(tr("Delete"));
|
||||||
replaceAddEditDeleteScroll2.add(deleteScroll2, buttonInsets);
|
replaceAddEditDeleteScroll2.add(deleteScroll2, buttonInsets);
|
||||||
deleteScroll2.addActionListener(e -> {
|
deleteScroll2.addActionListener(e -> {
|
||||||
final List<PrefEntry> toRemove = replacementPreferenceTable.getSelectedItems();
|
final var toRemove = replacementPreferenceTable.getSelectedItems();
|
||||||
if (!toRemove.isEmpty()) {
|
if (!toRemove.isEmpty()) {
|
||||||
replacementTableDisplayData.removeAll(toRemove);
|
replacementTableDisplayData.removeAll(toRemove);
|
||||||
}
|
}
|
||||||
|
@ -185,7 +181,7 @@ public class MapWithAIPreferences extends DefaultTabPreferenceSetting {
|
||||||
|
|
||||||
pane.add(Box.createHorizontalGlue(), second);
|
pane.add(Box.createHorizontalGlue(), second);
|
||||||
|
|
||||||
JButton kaartLogo = new JButton(ImageProvider.getIfAvailable("kaart") == null ? null
|
final var kaartLogo = new JButton(ImageProvider.getIfAvailable("kaart") == null ? null
|
||||||
: new ImageProvider("kaart").setHeight(ImageProvider.ImageSizes.SETTINGS_TAB.getAdjustedHeight())
|
: new ImageProvider("kaart").setHeight(ImageProvider.ImageSizes.SETTINGS_TAB.getAdjustedHeight())
|
||||||
.get());
|
.get());
|
||||||
kaartLogo.setToolTipText(tr("Link to source code repository"));
|
kaartLogo.setToolTipText(tr("Link to source code repository"));
|
||||||
|
@ -198,7 +194,7 @@ public class MapWithAIPreferences extends DefaultTabPreferenceSetting {
|
||||||
kaartLogo.setCursor(new Cursor(Cursor.HAND_CURSOR));
|
kaartLogo.setCursor(new Cursor(Cursor.HAND_CURSOR));
|
||||||
pane.add(kaartLogo, GBC.std().anchor(GridBagConstraints.WEST));
|
pane.add(kaartLogo, GBC.std().anchor(GridBagConstraints.WEST));
|
||||||
|
|
||||||
JButton mapWithAILogo = new JButton(ImageProvider.getIfAvailable("mapwithai_text") == null ? null
|
final var mapWithAILogo = new JButton(ImageProvider.getIfAvailable("mapwithai_text") == null ? null
|
||||||
: new ImageProvider("mapwithai_text")
|
: new ImageProvider("mapwithai_text")
|
||||||
.setHeight(ImageProvider.ImageSizes.SETTINGS_TAB.getAdjustedHeight()).get());
|
.setHeight(ImageProvider.ImageSizes.SETTINGS_TAB.getAdjustedHeight()).get());
|
||||||
mapWithAILogo.setCursor(new Cursor(Cursor.HAND_CURSOR));
|
mapWithAILogo.setCursor(new Cursor(Cursor.HAND_CURSOR));
|
||||||
|
@ -218,22 +214,21 @@ public class MapWithAIPreferences extends DefaultTabPreferenceSetting {
|
||||||
@Override
|
@Override
|
||||||
public boolean ok() {
|
public boolean ok() {
|
||||||
MapWithAIPreferenceHelper.setSwitchLayers(switchLayerCheckBox.isSelected(), true);
|
MapWithAIPreferenceHelper.setSwitchLayers(switchLayerCheckBox.isSelected(), true);
|
||||||
final Object value = maximumAdditionSpinner.getValue();
|
final var value = maximumAdditionSpinner.getValue();
|
||||||
MapWithAIPreferenceHelper.setMergeBuildingAddress(this.mergeBuildingAddressCheckBox.isSelected(), true);
|
MapWithAIPreferenceHelper.setMergeBuildingAddress(this.mergeBuildingAddressCheckBox.isSelected(), true);
|
||||||
if (value instanceof Number) {
|
if (value instanceof Number number) {
|
||||||
MapWithAIPreferenceHelper.setMaximumAddition(((Number) value).intValue(), true);
|
MapWithAIPreferenceHelper.setMaximumAddition(number.intValue(), true);
|
||||||
}
|
}
|
||||||
MapWithAILayerInfo.getInstance().save();
|
MapWithAILayerInfo.getInstance().save();
|
||||||
MapWithAILayerInfo.getInstance().clear();
|
MapWithAILayerInfo.getInstance().clear();
|
||||||
MapWithAILayerInfo.getInstance().load(false);
|
MapWithAILayerInfo.getInstance().load(false, null);
|
||||||
MapWithAIPreferenceHelper.setReplacementTags(convertReplacementPrefToMap(replacementTableDisplayData));
|
MapWithAIPreferenceHelper.setReplacementTags(convertReplacementPrefToMap(replacementTableDisplayData));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Map<String, String> convertReplacementPrefToMap(List<PrefEntry> displayData) {
|
private static Map<String, String> convertReplacementPrefToMap(List<PrefEntry> displayData) {
|
||||||
final Map<String, String> returnMap = displayData.isEmpty() ? Collections.emptyMap() : new TreeMap<>();
|
return displayData.stream()
|
||||||
displayData.forEach(entry -> returnMap.put(entry.getKey(), entry.getValue().getValue().toString()));
|
.collect(Collectors.toMap(PrefEntry::getKey, entry -> entry.getValue().getValue().toString()));
|
||||||
return returnMap;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -4,6 +4,7 @@ package org.openstreetmap.josm.plugins.mapwithai.gui.preferences.mapwithai;
|
||||||
import static org.openstreetmap.josm.tools.I18n.marktr;
|
import static org.openstreetmap.josm.tools.I18n.marktr;
|
||||||
import static org.openstreetmap.josm.tools.I18n.tr;
|
import static org.openstreetmap.josm.tools.I18n.tr;
|
||||||
|
|
||||||
|
import javax.annotation.Nonnull;
|
||||||
import javax.swing.AbstractAction;
|
import javax.swing.AbstractAction;
|
||||||
import javax.swing.Box;
|
import javax.swing.Box;
|
||||||
import javax.swing.JButton;
|
import javax.swing.JButton;
|
||||||
|
@ -18,7 +19,6 @@ import javax.swing.UIManager;
|
||||||
import javax.swing.event.ListSelectionEvent;
|
import javax.swing.event.ListSelectionEvent;
|
||||||
import javax.swing.event.ListSelectionListener;
|
import javax.swing.event.ListSelectionListener;
|
||||||
import javax.swing.table.DefaultTableCellRenderer;
|
import javax.swing.table.DefaultTableCellRenderer;
|
||||||
import javax.swing.table.TableColumnModel;
|
|
||||||
|
|
||||||
import java.awt.Color;
|
import java.awt.Color;
|
||||||
import java.awt.Component;
|
import java.awt.Component;
|
||||||
|
@ -28,8 +28,8 @@ import java.awt.GridBagLayout;
|
||||||
import java.awt.event.ActionEvent;
|
import java.awt.event.ActionEvent;
|
||||||
import java.awt.event.MouseAdapter;
|
import java.awt.event.MouseAdapter;
|
||||||
import java.awt.event.MouseEvent;
|
import java.awt.event.MouseEvent;
|
||||||
import java.awt.geom.Rectangle2D;
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.io.Serial;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
|
@ -37,7 +37,6 @@ import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.concurrent.ExecutionException;
|
import java.util.concurrent.ExecutionException;
|
||||||
import java.util.concurrent.Future;
|
|
||||||
import java.util.function.BiConsumer;
|
import java.util.function.BiConsumer;
|
||||||
import java.util.function.Consumer;
|
import java.util.function.Consumer;
|
||||||
import java.util.function.Function;
|
import java.util.function.Function;
|
||||||
|
@ -47,13 +46,10 @@ import java.util.stream.Stream;
|
||||||
import org.openstreetmap.gui.jmapviewer.Coordinate;
|
import org.openstreetmap.gui.jmapviewer.Coordinate;
|
||||||
import org.openstreetmap.gui.jmapviewer.MapPolygonImpl;
|
import org.openstreetmap.gui.jmapviewer.MapPolygonImpl;
|
||||||
import org.openstreetmap.gui.jmapviewer.MapRectangleImpl;
|
import org.openstreetmap.gui.jmapviewer.MapRectangleImpl;
|
||||||
import org.openstreetmap.gui.jmapviewer.interfaces.ICoordinate;
|
|
||||||
import org.openstreetmap.gui.jmapviewer.interfaces.MapPolygon;
|
import org.openstreetmap.gui.jmapviewer.interfaces.MapPolygon;
|
||||||
import org.openstreetmap.gui.jmapviewer.interfaces.MapRectangle;
|
import org.openstreetmap.gui.jmapviewer.interfaces.MapRectangle;
|
||||||
import org.openstreetmap.josm.data.Bounds;
|
import org.openstreetmap.josm.data.Bounds;
|
||||||
import org.openstreetmap.josm.data.coor.LatLon;
|
import org.openstreetmap.josm.data.coor.LatLon;
|
||||||
import org.openstreetmap.josm.data.imagery.ImageryInfo.ImageryBounds;
|
|
||||||
import org.openstreetmap.josm.data.imagery.Shape;
|
|
||||||
import org.openstreetmap.josm.data.preferences.NamedColorProperty;
|
import org.openstreetmap.josm.data.preferences.NamedColorProperty;
|
||||||
import org.openstreetmap.josm.gui.MainApplication;
|
import org.openstreetmap.josm.gui.MainApplication;
|
||||||
import org.openstreetmap.josm.gui.bbox.SlippyMapBBoxChooser;
|
import org.openstreetmap.josm.gui.bbox.SlippyMapBBoxChooser;
|
||||||
|
@ -92,6 +88,7 @@ public class MapWithAIProvidersPanel extends JPanel {
|
||||||
SHOW_ACTIVE
|
SHOW_ACTIVE
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Serial
|
||||||
private static final long serialVersionUID = -5876039771496409422L;
|
private static final long serialVersionUID = -5876039771496409422L;
|
||||||
// Public JTables and JosmMapViewer
|
// Public JTables and JosmMapViewer
|
||||||
/** The table of active providers **/
|
/** The table of active providers **/
|
||||||
|
@ -112,9 +109,9 @@ public class MapWithAIProvidersPanel extends JPanel {
|
||||||
|
|
||||||
// Public models
|
// Public models
|
||||||
/** The model of active providers **/
|
/** The model of active providers **/
|
||||||
public static final MapWithAILayerTableModel ACTIVE_MODEL = new MapWithAILayerTableModel();
|
static final MapWithAILayerTableModel ACTIVE_MODEL = new MapWithAILayerTableModel();
|
||||||
/** The model of default providers **/
|
/** The model of default providers **/
|
||||||
public static final MapWithAIDefaultLayerTableModel DEFAULT_MODEL = new MapWithAIDefaultLayerTableModel();
|
static final MapWithAIDefaultLayerTableModel DEFAULT_MODEL = new MapWithAIDefaultLayerTableModel();
|
||||||
|
|
||||||
// Public JToolbars
|
// Public JToolbars
|
||||||
/** The toolbar on the right of active providers **/
|
/** The toolbar on the right of active providers **/
|
||||||
|
@ -188,24 +185,24 @@ public class MapWithAIProvidersPanel extends JPanel {
|
||||||
public final Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected,
|
public final Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected,
|
||||||
boolean hasFocus, int row, int column) {
|
boolean hasFocus, int row, int column) {
|
||||||
T obj = (T) value;
|
T obj = (T) value;
|
||||||
JLabel label = (JLabel) super.getTableCellRendererComponent(table, mapper.apply(obj), isSelected, hasFocus,
|
final var label = (JLabel) super.getTableCellRendererComponent(table, mapper.apply(obj), isSelected,
|
||||||
row, column);
|
hasFocus, row, column);
|
||||||
Color defaultColor = UIManager.getColor("Table.background");
|
final var defaultColor = UIManager.getColor("Table.background");
|
||||||
Color selectedColor = UIManager.getColor("Table.selectionBackground");
|
final var selectedColor = UIManager.getColor("Table.selectionBackground");
|
||||||
GuiHelper.setBackgroundReadable(label, defaultColor);
|
GuiHelper.setBackgroundReadable(label, defaultColor);
|
||||||
|
|
||||||
GuiHelper.setBackgroundReadable(label, isSelected ? selectedColor : defaultColor);
|
GuiHelper.setBackgroundReadable(label, isSelected ? selectedColor : defaultColor);
|
||||||
if (this.highlightIfActive && obj != null) {
|
if (this.highlightIfActive && obj != null) {
|
||||||
MapWithAIInfo info = obj instanceof MapWithAIInfo ? (MapWithAIInfo) obj : reverseMapper.apply(obj);
|
final var info = obj instanceof MapWithAIInfo ? (MapWithAIInfo) obj : reverseMapper.apply(obj);
|
||||||
if (info == null) {
|
if (info == null) {
|
||||||
GuiHelper.setBackgroundReadable(label, defaultColor);
|
GuiHelper.setBackgroundReadable(label, defaultColor);
|
||||||
} else {
|
} else {
|
||||||
if (MapWithAILayerTableModel.contains(info)) {
|
if (MapWithAILayerTableModel.contains(info)) {
|
||||||
Color t = IMAGERY_BACKGROUND_COLOR.get();
|
final var t = IMAGERY_BACKGROUND_COLOR.get();
|
||||||
GuiHelper.setBackgroundReadable(label, isSelected ? t.darker() : t);
|
GuiHelper.setBackgroundReadable(label, isSelected ? t.darker() : t);
|
||||||
} else if (this.area != null && info.getBounds() != null
|
} else if (this.area != null && info.getBounds() != null
|
||||||
&& (this.area.intersects(info.getBounds()) || info.getBounds().intersects(this.area))) {
|
&& (this.area.intersects(info.getBounds()) || info.getBounds().intersects(this.area))) {
|
||||||
Color t = MAPWITHAI_AREA_BACKGROUND_COLOR.get();
|
final var t = MAPWITHAI_AREA_BACKGROUND_COLOR.get();
|
||||||
GuiHelper.setBackgroundReadable(label, isSelected ? t.darker() : t);
|
GuiHelper.setBackgroundReadable(label, isSelected ? t.darker() : t);
|
||||||
} else {
|
} else {
|
||||||
GuiHelper.setBackgroundReadable(label, isSelected ? selectedColor : defaultColor);
|
GuiHelper.setBackgroundReadable(label, isSelected ? selectedColor : defaultColor);
|
||||||
|
@ -300,6 +297,7 @@ public class MapWithAIProvidersPanel extends JPanel {
|
||||||
private static class MapWithAINameTableCellRenderer
|
private static class MapWithAINameTableCellRenderer
|
||||||
extends MapWithAIProvidersPanel.MapWithAITableCellRenderer<MapWithAIInfo> {
|
extends MapWithAIProvidersPanel.MapWithAITableCellRenderer<MapWithAIInfo> {
|
||||||
|
|
||||||
|
@Serial
|
||||||
private static final long serialVersionUID = 6669934435517244629L;
|
private static final long serialVersionUID = 6669934435517244629L;
|
||||||
|
|
||||||
MapWithAINameTableCellRenderer(boolean showActive) {
|
MapWithAINameTableCellRenderer(boolean showActive) {
|
||||||
|
@ -308,6 +306,26 @@ public class MapWithAIProvidersPanel extends JPanel {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static class ProvidersTable extends JTable {
|
||||||
|
@Serial
|
||||||
|
private static final long serialVersionUID = -6136421378119093719L;
|
||||||
|
|
||||||
|
ProvidersTable() {
|
||||||
|
super(ACTIVE_MODEL);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getToolTipText(@Nonnull MouseEvent e) {
|
||||||
|
final var p = e.getPoint();
|
||||||
|
try {
|
||||||
|
return ACTIVE_MODEL.getValueAt(rowAtPoint(p), columnAtPoint(p)).toString();
|
||||||
|
} catch (ArrayIndexOutOfBoundsException ex) {
|
||||||
|
Logging.debug(ex);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructs a new {@code MapWithAIProvidersPanel}.
|
* Constructs a new {@code MapWithAIProvidersPanel}.
|
||||||
*
|
*
|
||||||
|
@ -320,21 +338,7 @@ public class MapWithAIProvidersPanel extends JPanel {
|
||||||
this.options = options;
|
this.options = options;
|
||||||
boolean showActive = Arrays.asList(options).contains(Options.SHOW_ACTIVE);
|
boolean showActive = Arrays.asList(options).contains(Options.SHOW_ACTIVE);
|
||||||
|
|
||||||
activeTable = new JTable(ACTIVE_MODEL) {
|
activeTable = new ProvidersTable();
|
||||||
|
|
||||||
private static final long serialVersionUID = -6136421378119093719L;
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getToolTipText(MouseEvent e) {
|
|
||||||
java.awt.Point p = e.getPoint();
|
|
||||||
try {
|
|
||||||
return ACTIVE_MODEL.getValueAt(rowAtPoint(p), columnAtPoint(p)).toString();
|
|
||||||
} catch (ArrayIndexOutOfBoundsException ex) {
|
|
||||||
Logging.debug(ex);
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
activeTable.putClientProperty("terminateEditOnFocusLost", Boolean.TRUE);
|
activeTable.putClientProperty("terminateEditOnFocusLost", Boolean.TRUE);
|
||||||
|
|
||||||
defaultTable = new JTable(DEFAULT_MODEL);
|
defaultTable = new JTable(DEFAULT_MODEL);
|
||||||
|
@ -346,25 +350,25 @@ public class MapWithAIProvidersPanel extends JPanel {
|
||||||
|
|
||||||
setupDefaultTable(defaultTable, options, areaListeners);
|
setupDefaultTable(defaultTable, options, areaListeners);
|
||||||
|
|
||||||
TableColumnModel mod = activeTable.getColumnModel();
|
final var mod = activeTable.getColumnModel();
|
||||||
mod.getColumn(1).setPreferredWidth(800);
|
mod.getColumn(1).setPreferredWidth(800);
|
||||||
MapWithAIURLTableCellRenderer activeTableCellRenderer = new MapWithAIURLTableCellRenderer();
|
final var activeTableCellRenderer = new MapWithAIURLTableCellRenderer();
|
||||||
areaListeners.addListener(activeTableCellRenderer);
|
areaListeners.addListener(activeTableCellRenderer);
|
||||||
mod.getColumn(1).setCellRenderer(activeTableCellRenderer);
|
mod.getColumn(1).setCellRenderer(activeTableCellRenderer);
|
||||||
mod.getColumn(0).setMaxWidth(200);
|
mod.getColumn(0).setMaxWidth(200);
|
||||||
|
|
||||||
RemoveEntryAction remove = new RemoveEntryAction();
|
final var remove = new RemoveEntryAction();
|
||||||
activeTable.getSelectionModel().addListSelectionListener(remove);
|
activeTable.getSelectionModel().addListSelectionListener(remove);
|
||||||
|
|
||||||
EditEntryAction edit = new EditEntryAction();
|
final var edit = new EditEntryAction();
|
||||||
activeTable.getSelectionModel().addListSelectionListener(edit);
|
activeTable.getSelectionModel().addListSelectionListener(edit);
|
||||||
|
|
||||||
add(new JLabel(tr("Available default entries:")), GBC.std().insets(5, 5, 0, 0));
|
add(new JLabel(tr("Available default entries:")), GBC.std().insets(5, 5, 0, 0));
|
||||||
add(new JLabel(tr("Boundaries of selected MapWithAI entries:")), GBC.eol().insets(5, 5, 0, 0));
|
add(new JLabel(tr("Boundaries of selected MapWithAI entries:")), GBC.eol().insets(5, 5, 0, 0));
|
||||||
|
|
||||||
// Add default item list
|
// Add default item list
|
||||||
JPanel defaultPane = new JPanel(new GridBagLayout());
|
final var defaultPane = new JPanel(new GridBagLayout());
|
||||||
JScrollPane scrolldef = new JScrollPane(defaultTable);
|
final var scrolldef = new JScrollPane(defaultTable);
|
||||||
scrolldef.setPreferredSize(new Dimension(200, 200));
|
scrolldef.setPreferredSize(new Dimension(200, 200));
|
||||||
defaultPane.add(defaultFilter, GBC.eol().insets(0, 0, 0, 0).fill(GridBagConstraints.HORIZONTAL));
|
defaultPane.add(defaultFilter, GBC.eol().insets(0, 0, 0, 0).fill(GridBagConstraints.HORIZONTAL));
|
||||||
defaultPane.add(scrolldef, GBC.eol().insets(0, 0, 0, 0).fill(GridBagConstraints.BOTH));
|
defaultPane.add(scrolldef, GBC.eol().insets(0, 0, 0, 0).fill(GridBagConstraints.BOTH));
|
||||||
|
@ -384,10 +388,10 @@ public class MapWithAIProvidersPanel extends JPanel {
|
||||||
defaultMap.setZoomControlsVisible(false);
|
defaultMap.setZoomControlsVisible(false);
|
||||||
defaultMap.setMinimumSize(new Dimension(100, 200));
|
defaultMap.setMinimumSize(new Dimension(100, 200));
|
||||||
defaultMap.addJMVListener(e -> {
|
defaultMap.addJMVListener(e -> {
|
||||||
Rectangle2D visibleRect = defaultMap.getVisibleRect();
|
final var visibleRect = defaultMap.getVisibleRect();
|
||||||
ICoordinate max = defaultMap.getPosition((int) visibleRect.getMaxX(), (int) visibleRect.getMaxY());
|
final var max = defaultMap.getPosition((int) visibleRect.getMaxX(), (int) visibleRect.getMaxY());
|
||||||
ICoordinate min = defaultMap.getPosition((int) visibleRect.getMinX(), (int) visibleRect.getMinY());
|
final var min = defaultMap.getPosition((int) visibleRect.getMinX(), (int) visibleRect.getMinY());
|
||||||
Bounds b = new Bounds(
|
final var b = new Bounds(
|
||||||
new LatLon(Math.min(max.getLat(), min.getLat()),
|
new LatLon(Math.min(max.getLat(), min.getLat()),
|
||||||
LatLon.toIntervalLon(Math.min(max.getLon(), min.getLon()))),
|
LatLon.toIntervalLon(Math.min(max.getLon(), min.getLon()))),
|
||||||
new LatLon(Math.max(max.getLat(), min.getLat()),
|
new LatLon(Math.max(max.getLat(), min.getLat()),
|
||||||
|
@ -411,15 +415,15 @@ public class MapWithAIProvidersPanel extends JPanel {
|
||||||
defaultToolbar.add(new ReloadAction());
|
defaultToolbar.add(new ReloadAction());
|
||||||
add(defaultToolbar, GBC.eol().anchor(GBC.SOUTH).insets(0, 0, 5, 0));
|
add(defaultToolbar, GBC.eol().anchor(GBC.SOUTH).insets(0, 0, 5, 0));
|
||||||
|
|
||||||
HtmlPanel help = new HtmlPanel(
|
final var help = new HtmlPanel(
|
||||||
tr("New default entries can be added in the <a href=\"{0}\">GitHub Repository</a>.",
|
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"));
|
"https://github.com/JOSM/MapWithAI/blob/pages/json/sources.json"));
|
||||||
help.enableClickableHyperlinks();
|
help.enableClickableHyperlinks();
|
||||||
add(help, GBC.eol().insets(10, 0, 0, 0).fill(GBC.HORIZONTAL));
|
add(help, GBC.eol().insets(10, 0, 0, 0).fill(GBC.HORIZONTAL));
|
||||||
|
|
||||||
ActivateAction activate = new ActivateAction();
|
final var activate = new ActivateAction();
|
||||||
defaultTable.getSelectionModel().addListSelectionListener(activate);
|
defaultTable.getSelectionModel().addListSelectionListener(activate);
|
||||||
JButton btnActivate = new JButton(activate);
|
final var btnActivate = new JButton(activate);
|
||||||
|
|
||||||
middleToolbar = new JToolBar(JToolBar.HORIZONTAL);
|
middleToolbar = new JToolBar(JToolBar.HORIZONTAL);
|
||||||
middleToolbar.setFloatable(false);
|
middleToolbar.setFloatable(false);
|
||||||
|
@ -430,7 +434,7 @@ public class MapWithAIProvidersPanel extends JPanel {
|
||||||
|
|
||||||
add(Box.createHorizontalGlue(), GBC.eol().fill(GridBagConstraints.HORIZONTAL));
|
add(Box.createHorizontalGlue(), GBC.eol().fill(GridBagConstraints.HORIZONTAL));
|
||||||
|
|
||||||
JScrollPane scroll = new JScrollPane(activeTable);
|
final var scroll = new JScrollPane(activeTable);
|
||||||
scroll.setPreferredSize(new Dimension(200, 200));
|
scroll.setPreferredSize(new Dimension(200, 200));
|
||||||
|
|
||||||
activeToolbar = new JToolBar(JToolBar.VERTICAL);
|
activeToolbar = new JToolBar(JToolBar.VERTICAL);
|
||||||
|
@ -452,7 +456,7 @@ public class MapWithAIProvidersPanel extends JPanel {
|
||||||
ListenerList<AreaListener> areaListeners) {
|
ListenerList<AreaListener> areaListeners) {
|
||||||
boolean showActive = Arrays.asList(options).contains(Options.SHOW_ACTIVE);
|
boolean showActive = Arrays.asList(options).contains(Options.SHOW_ACTIVE);
|
||||||
int tenXWidth = defaultTable.getFontMetrics(defaultTable.getFont()).stringWidth("XXXXXXXXXX");
|
int tenXWidth = defaultTable.getFontMetrics(defaultTable.getFont()).stringWidth("XXXXXXXXXX");
|
||||||
TableColumnModel mod = defaultTable.getColumnModel();
|
final var mod = defaultTable.getColumnModel();
|
||||||
int urlWidth = (showActive ? 3 : 0) * tenXWidth;
|
int urlWidth = (showActive ? 3 : 0) * tenXWidth;
|
||||||
mod.getColumn(6).setCellRenderer(defaultTable.getDefaultRenderer(Boolean.class));
|
mod.getColumn(6).setCellRenderer(defaultTable.getDefaultRenderer(Boolean.class));
|
||||||
mod.getColumn(6).setMaxWidth(20);
|
mod.getColumn(6).setMaxWidth(20);
|
||||||
|
@ -461,13 +465,13 @@ public class MapWithAIProvidersPanel extends JPanel {
|
||||||
mod.getColumn(4).setPreferredWidth((showActive ? 2 : 0) * tenXWidth);
|
mod.getColumn(4).setPreferredWidth((showActive ? 2 : 0) * tenXWidth);
|
||||||
mod.getColumn(4).setCellRenderer(new MapWithAIProviderTableCellRenderer());
|
mod.getColumn(4).setCellRenderer(new MapWithAIProviderTableCellRenderer());
|
||||||
mod.getColumn(3).setPreferredWidth(urlWidth);
|
mod.getColumn(3).setPreferredWidth(urlWidth);
|
||||||
MapWithAIURLTableCellRenderer defaultUrlTableCellRenderer = new MapWithAIURLTableCellRenderer();
|
final var defaultUrlTableCellRenderer = new MapWithAIURLTableCellRenderer();
|
||||||
mod.getColumn(3).setCellRenderer(defaultUrlTableCellRenderer);
|
mod.getColumn(3).setCellRenderer(defaultUrlTableCellRenderer);
|
||||||
mod.getColumn(2).setPreferredWidth((int) ((showActive ? 0 : 0.3) * tenXWidth));
|
mod.getColumn(2).setPreferredWidth((int) ((showActive ? 0 : 0.3) * tenXWidth));
|
||||||
|
|
||||||
mod.getColumn(2).setCellRenderer(new MapWithAITypeTableCellRenderer());
|
mod.getColumn(2).setCellRenderer(new MapWithAITypeTableCellRenderer());
|
||||||
|
|
||||||
MapWithAINameTableCellRenderer defaultNameTableCellRenderer = new MapWithAINameTableCellRenderer(!showActive);
|
final var defaultNameTableCellRenderer = new MapWithAINameTableCellRenderer(!showActive);
|
||||||
mod.getColumn(1).setCellRenderer(defaultNameTableCellRenderer);
|
mod.getColumn(1).setCellRenderer(defaultNameTableCellRenderer);
|
||||||
mod.getColumn(1).setPreferredWidth((showActive ? 3 : 2) * tenXWidth);
|
mod.getColumn(1).setPreferredWidth((showActive ? 3 : 2) * tenXWidth);
|
||||||
mod.getColumn(0).setCellRenderer(new MapWithAICategoryTableCellRenderer());
|
mod.getColumn(0).setCellRenderer(new MapWithAICategoryTableCellRenderer());
|
||||||
|
@ -496,20 +500,18 @@ public class MapWithAIProvidersPanel extends JPanel {
|
||||||
* @param e The MouseEvent (used to get the appropriate JTable)
|
* @param e The MouseEvent (used to get the appropriate JTable)
|
||||||
*/
|
*/
|
||||||
private static void clickListener(MouseEvent e) {
|
private static void clickListener(MouseEvent e) {
|
||||||
if (e.getSource() instanceof JTable) {
|
if (e.getSource() instanceof JTable table && table.getSelectedRow() >= 0 && table.getSelectedColumn() >= 0) {
|
||||||
JTable table = (JTable) e.getSource();
|
final int realCol = table.convertColumnIndexToModel(table.getSelectedColumn());
|
||||||
if (table.getSelectedRow() >= 0 && table.getSelectedColumn() >= 0) {
|
final int realRow = table.convertRowIndexToModel(table.getSelectedRow());
|
||||||
int realCol = table.convertColumnIndexToModel(table.getSelectedColumn());
|
final var tableName = table.getModel().getColumnName(realCol);
|
||||||
int realRow = table.convertRowIndexToModel(table.getSelectedRow());
|
|
||||||
String tableName = table.getModel().getColumnName(realCol);
|
|
||||||
if (tr("License").equals(tableName)) {
|
if (tr("License").equals(tableName)) {
|
||||||
MapWithAIInfo info = MapWithAIDefaultLayerTableModel.getRow(realRow);
|
final var info = MapWithAIDefaultLayerTableModel.getRow(realRow);
|
||||||
if (info.getTermsOfUseURL() != null) {
|
if (info.getTermsOfUseURL() != null) {
|
||||||
OpenBrowser.displayUrl(info.getTermsOfUseURL());
|
OpenBrowser.displayUrl(info.getTermsOfUseURL());
|
||||||
}
|
}
|
||||||
} else if (tr("Enabled").equals(tableName)) {
|
} else if (tr("Enabled").equals(tableName)) {
|
||||||
MapWithAIInfo info = MapWithAIDefaultLayerTableModel.getRow(realRow);
|
final var info = MapWithAIDefaultLayerTableModel.getRow(realRow);
|
||||||
MapWithAILayerInfo instance = MapWithAILayerInfo.getInstance();
|
final var instance = MapWithAILayerInfo.getInstance();
|
||||||
if (instance.getLayers().contains(info)) {
|
if (instance.getLayers().contains(info)) {
|
||||||
instance.remove(info);
|
instance.remove(info);
|
||||||
} else {
|
} else {
|
||||||
|
@ -518,7 +520,6 @@ public class MapWithAIProvidersPanel extends JPanel {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set the current bounds of the map and the area to select
|
* Set the current bounds of the map and the area to select
|
||||||
|
@ -585,17 +586,17 @@ public class MapWithAIProvidersPanel extends JPanel {
|
||||||
* @param i model index
|
* @param i model index
|
||||||
*/
|
*/
|
||||||
private void updateBoundsAndShapes(int i) {
|
private void updateBoundsAndShapes(int i) {
|
||||||
ImageryBounds bounds = MapWithAIDefaultLayerTableModel.getRow(i).getBounds();
|
final var bounds = MapWithAIDefaultLayerTableModel.getRow(i).getBounds();
|
||||||
if (bounds != null) {
|
if (bounds != null) {
|
||||||
int viewIndex = defaultTable.convertRowIndexToView(i);
|
int viewIndex = defaultTable.convertRowIndexToView(i);
|
||||||
List<Shape> shapes = bounds.getShapes();
|
final var shapes = bounds.getShapes();
|
||||||
if (shapes != null && !shapes.isEmpty()) {
|
if (shapes != null && !shapes.isEmpty()) {
|
||||||
if (defaultTable.getSelectionModel().isSelectedIndex(viewIndex)) {
|
if (defaultTable.getSelectionModel().isSelectedIndex(viewIndex)) {
|
||||||
mapPolygons.computeIfAbsent(i, key -> {
|
mapPolygons.computeIfAbsent(i, key -> {
|
||||||
List<MapPolygon> list = new ArrayList<>();
|
final var list = new ArrayList<MapPolygon>(shapes.size());
|
||||||
// Add new map polygons
|
// Add new map polygons
|
||||||
for (Shape shape : shapes) {
|
for (var shape : shapes) {
|
||||||
MapPolygon polygon = new MapPolygonImpl(shape.getPoints());
|
final var polygon = new MapPolygonImpl(shape.getPoints());
|
||||||
list.add(polygon);
|
list.add(polygon);
|
||||||
defaultMap.addMapPolygon(polygon);
|
defaultMap.addMapPolygon(polygon);
|
||||||
}
|
}
|
||||||
|
@ -603,7 +604,7 @@ public class MapWithAIProvidersPanel extends JPanel {
|
||||||
});
|
});
|
||||||
} else if (mapPolygons.containsKey(i)) {
|
} else if (mapPolygons.containsKey(i)) {
|
||||||
// Remove previously drawn map polygons
|
// Remove previously drawn map polygons
|
||||||
for (MapPolygon polygon : mapPolygons.get(i)) {
|
for (var polygon : mapPolygons.get(i)) {
|
||||||
defaultMap.removeMapPolygon(polygon);
|
defaultMap.removeMapPolygon(polygon);
|
||||||
}
|
}
|
||||||
mapPolygons.remove(i);
|
mapPolygons.remove(i);
|
||||||
|
@ -613,9 +614,9 @@ public class MapWithAIProvidersPanel extends JPanel {
|
||||||
if (defaultTable.getSelectionModel().isSelectedIndex(viewIndex)) {
|
if (defaultTable.getSelectionModel().isSelectedIndex(viewIndex)) {
|
||||||
mapRectangles.computeIfAbsent(i, key -> {
|
mapRectangles.computeIfAbsent(i, key -> {
|
||||||
// Add new map rectangle
|
// Add new map rectangle
|
||||||
Coordinate topLeft = new Coordinate(bounds.getMaxLat(), bounds.getMinLon());
|
final var topLeft = new Coordinate(bounds.getMaxLat(), bounds.getMinLon());
|
||||||
Coordinate bottomRight = new Coordinate(bounds.getMinLat(), bounds.getMaxLon());
|
final var bottomRight = new Coordinate(bounds.getMinLat(), bounds.getMaxLon());
|
||||||
MapRectangle rectangle = new MapRectangleImpl(topLeft, bottomRight);
|
final var rectangle = new MapRectangleImpl(topLeft, bottomRight);
|
||||||
defaultMap.addMapRectangle(rectangle);
|
defaultMap.addMapRectangle(rectangle);
|
||||||
return rectangle;
|
return rectangle;
|
||||||
});
|
});
|
||||||
|
@ -629,8 +630,8 @@ public class MapWithAIProvidersPanel extends JPanel {
|
||||||
}
|
}
|
||||||
|
|
||||||
private <T> void doCleanupResidualBounds(Map<Integer, T> map, Consumer<T> removalEffect) {
|
private <T> void doCleanupResidualBounds(Map<Integer, T> map, Consumer<T> removalEffect) {
|
||||||
List<Integer> toRemove = new ArrayList<>();
|
final var toRemove = new ArrayList<Integer>();
|
||||||
for (Integer i : map.keySet()) {
|
for (var i : map.keySet()) {
|
||||||
int viewIndex = defaultTable.convertRowIndexToView(i);
|
int viewIndex = defaultTable.convertRowIndexToView(i);
|
||||||
if (!defaultTable.getSelectionModel().isSelectedIndex(viewIndex)) {
|
if (!defaultTable.getSelectionModel().isSelectedIndex(viewIndex)) {
|
||||||
toRemove.add(i);
|
toRemove.add(i);
|
||||||
|
@ -647,32 +648,32 @@ public class MapWithAIProvidersPanel extends JPanel {
|
||||||
|
|
||||||
private class NewEntryAction extends AbstractAction {
|
private class NewEntryAction extends AbstractAction {
|
||||||
|
|
||||||
|
@Serial
|
||||||
private static final long serialVersionUID = 7451336680150337942L;
|
private static final long serialVersionUID = 7451336680150337942L;
|
||||||
|
|
||||||
NewEntryAction(MapWithAIType type) {
|
NewEntryAction(MapWithAIType type) {
|
||||||
putValue(NAME, type.toString());
|
putValue(NAME, type.toString());
|
||||||
putValue(SHORT_DESCRIPTION, tr("Add a new {0} entry by entering the URL", type.toString()));
|
putValue(SHORT_DESCRIPTION, tr("Add a new {0} entry by entering the URL", type.toString()));
|
||||||
String icon = /* ICON(dialogs/) */ "add";
|
new ImageProvider(DIALOG_IMAGES_DIR, "add").getResource().attachImageIcon(this, true);
|
||||||
new ImageProvider(DIALOG_IMAGES_DIR, icon).getResource().attachImageIcon(this, true);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void actionPerformed(ActionEvent evt) {
|
public void actionPerformed(ActionEvent evt) {
|
||||||
final AddMapWithAIPanel p = new AddMapWithAIPanel();
|
final var p = new AddMapWithAIPanel();
|
||||||
final AddMapWithAIDialog addDialog = new AddMapWithAIDialog(gui, p);
|
final var addDialog = new AddMapWithAIDialog(gui, p);
|
||||||
addDialog.showDialog();
|
addDialog.showDialog();
|
||||||
|
|
||||||
if (addDialog.getValue() == 1) {
|
if (addDialog.getValue() == 1) {
|
||||||
try {
|
try {
|
||||||
MapWithAIInfo info = p.getSourceInfo();
|
final var info = p.getSourceInfo();
|
||||||
// Fix a possible NPE
|
// Fix a possible NPE
|
||||||
if (info.getSourceType() == null) {
|
if (info.getSourceType() == null) {
|
||||||
info.setSourceType(MapWithAIType.THIRD_PARTY);
|
info.setSourceType(MapWithAIType.THIRD_PARTY);
|
||||||
}
|
}
|
||||||
if (MapWithAIType.ESRI == info.getSourceType()) {
|
if (MapWithAIType.ESRI == info.getSourceType()) {
|
||||||
final ESRISourceReader reader = new ESRISourceReader(info);
|
final var reader = new ESRISourceReader(info);
|
||||||
try {
|
try {
|
||||||
for (Future<MapWithAIInfo> i : reader.parse()) {
|
for (var i : reader.parse()) {
|
||||||
try {
|
try {
|
||||||
ACTIVE_MODEL.addRow(i.get());
|
ACTIVE_MODEL.addRow(i.get());
|
||||||
} catch (InterruptedException e) {
|
} catch (InterruptedException e) {
|
||||||
|
@ -701,6 +702,7 @@ public class MapWithAIProvidersPanel extends JPanel {
|
||||||
|
|
||||||
private class EditEntryAction extends AbstractAction implements ListSelectionListener {
|
private class EditEntryAction extends AbstractAction implements ListSelectionListener {
|
||||||
|
|
||||||
|
@Serial
|
||||||
private static final long serialVersionUID = -1682304557691078801L;
|
private static final long serialVersionUID = -1682304557691078801L;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -725,9 +727,8 @@ public class MapWithAIProvidersPanel extends JPanel {
|
||||||
@Override
|
@Override
|
||||||
public void actionPerformed(ActionEvent e) {
|
public void actionPerformed(ActionEvent e) {
|
||||||
if (activeTable.getSelectedRow() != -1) {
|
if (activeTable.getSelectedRow() != -1) {
|
||||||
final AddMapWithAIPanel p = new AddMapWithAIPanel(
|
final var p = new AddMapWithAIPanel(MapWithAILayerTableModel.getRow(activeTable.getSelectedRow()));
|
||||||
MapWithAILayerTableModel.getRow(activeTable.getSelectedRow()));
|
final var addDialog = new AddMapWithAIDialog(gui, p);
|
||||||
final AddMapWithAIDialog addDialog = new AddMapWithAIDialog(gui, p);
|
|
||||||
addDialog.showDialog();
|
addDialog.showDialog();
|
||||||
if (addDialog.getValue() == 1) {
|
if (addDialog.getValue() == 1) {
|
||||||
p.getSourceInfo();
|
p.getSourceInfo();
|
||||||
|
@ -738,6 +739,7 @@ public class MapWithAIProvidersPanel extends JPanel {
|
||||||
|
|
||||||
private class RemoveEntryAction extends AbstractAction implements ListSelectionListener {
|
private class RemoveEntryAction extends AbstractAction implements ListSelectionListener {
|
||||||
|
|
||||||
|
@Serial
|
||||||
private static final long serialVersionUID = 2666450386256004180L;
|
private static final long serialVersionUID = 2666450386256004180L;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -770,6 +772,7 @@ public class MapWithAIProvidersPanel extends JPanel {
|
||||||
|
|
||||||
private class ActivateAction extends AbstractAction implements ListSelectionListener, LayerChangeListener {
|
private class ActivateAction extends AbstractAction implements ListSelectionListener, LayerChangeListener {
|
||||||
|
|
||||||
|
@Serial
|
||||||
private static final long serialVersionUID = -452335751201424801L;
|
private static final long serialVersionUID = -452335751201424801L;
|
||||||
private final transient ImageResource activate;
|
private final transient ImageResource activate;
|
||||||
private final transient ImageResource deactivate;
|
private final transient ImageResource deactivate;
|
||||||
|
@ -788,9 +791,8 @@ public class MapWithAIProvidersPanel extends JPanel {
|
||||||
|
|
||||||
protected void updateEnabledState() {
|
protected void updateEnabledState() {
|
||||||
setEnabled(defaultTable.getSelectedRowCount() > 0);
|
setEnabled(defaultTable.getSelectedRowCount() > 0);
|
||||||
List<MapWithAIInfo> selected = Arrays.stream(defaultTable.getSelectedRows())
|
final var selected = Arrays.stream(defaultTable.getSelectedRows()).map(defaultTable::convertRowIndexToModel)
|
||||||
.map(defaultTable::convertRowIndexToModel).mapToObj(MapWithAIDefaultLayerTableModel::getRow)
|
.mapToObj(MapWithAIDefaultLayerTableModel::getRow).toList();
|
||||||
.collect(Collectors.toList());
|
|
||||||
if (selected.stream().anyMatch(MapWithAILayerTableModel::doesNotContain)) {
|
if (selected.stream().anyMatch(MapWithAILayerTableModel::doesNotContain)) {
|
||||||
activate.attachImageIcon(this, true);
|
activate.attachImageIcon(this, true);
|
||||||
putValue(NAME, tr("Activate"));
|
putValue(NAME, tr("Activate"));
|
||||||
|
@ -817,14 +819,12 @@ public class MapWithAIProvidersPanel extends JPanel {
|
||||||
JOptionPane.INFORMATION_MESSAGE);
|
JOptionPane.INFORMATION_MESSAGE);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
List<MapWithAIInfo> selected = Arrays.stream(defaultTable.getSelectedRows())
|
final var selected = Arrays.stream(defaultTable.getSelectedRows()).map(defaultTable::convertRowIndexToModel)
|
||||||
.map(defaultTable::convertRowIndexToModel).mapToObj(MapWithAIDefaultLayerTableModel::getRow)
|
.mapToObj(MapWithAIDefaultLayerTableModel::getRow).collect(Collectors.toCollection(ArrayList::new));
|
||||||
.collect(Collectors.toList());
|
|
||||||
if (selected.stream().anyMatch(MapWithAILayerTableModel::doesNotContain)) {
|
if (selected.stream().anyMatch(MapWithAILayerTableModel::doesNotContain)) {
|
||||||
List<MapWithAIInfo> toAdd = selected.stream().filter(MapWithAILayerTableModel::doesNotContain)
|
final var toAdd = selected.stream().filter(MapWithAILayerTableModel::doesNotContain).toList();
|
||||||
.collect(Collectors.toList());
|
|
||||||
activeTable.getSelectionModel().clearSelection();
|
activeTable.getSelectionModel().clearSelection();
|
||||||
for (MapWithAIInfo info : toAdd) {
|
for (var info : toAdd) {
|
||||||
ACTIVE_MODEL.addRow(new MapWithAIInfo(info));
|
ACTIVE_MODEL.addRow(new MapWithAIInfo(info));
|
||||||
int lastLine = ACTIVE_MODEL.getRowCount() - 1;
|
int lastLine = ACTIVE_MODEL.getRowCount() - 1;
|
||||||
activeTable.getSelectionModel().setSelectionInterval(lastLine, lastLine);
|
activeTable.getSelectionModel().setSelectionInterval(lastLine, lastLine);
|
||||||
|
@ -853,6 +853,7 @@ public class MapWithAIProvidersPanel extends JPanel {
|
||||||
|
|
||||||
private class ReloadAction extends AbstractAction {
|
private class ReloadAction extends AbstractAction {
|
||||||
|
|
||||||
|
@Serial
|
||||||
private static final long serialVersionUID = 7801339998423585685L;
|
private static final long serialVersionUID = 7801339998423585685L;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -7,10 +7,9 @@ import javax.json.Json;
|
||||||
import javax.json.JsonArray;
|
import javax.json.JsonArray;
|
||||||
import javax.json.JsonNumber;
|
import javax.json.JsonNumber;
|
||||||
import javax.json.JsonObject;
|
import javax.json.JsonObject;
|
||||||
import javax.json.JsonReader;
|
|
||||||
import javax.json.JsonString;
|
import javax.json.JsonString;
|
||||||
import javax.json.JsonStructure;
|
|
||||||
import javax.json.JsonValue;
|
import javax.json.JsonValue;
|
||||||
|
import javax.json.spi.JsonProvider;
|
||||||
import javax.json.stream.JsonParsingException;
|
import javax.json.stream.JsonParsingException;
|
||||||
|
|
||||||
import java.io.ByteArrayInputStream;
|
import java.io.ByteArrayInputStream;
|
||||||
|
@ -31,7 +30,6 @@ import java.util.regex.Pattern;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
import org.apache.commons.jcs3.access.CacheAccess;
|
import org.apache.commons.jcs3.access.CacheAccess;
|
||||||
import org.apache.commons.jcs3.engine.behavior.IElementAttributes;
|
|
||||||
import org.openstreetmap.josm.data.cache.JCSCacheManager;
|
import org.openstreetmap.josm.data.cache.JCSCacheManager;
|
||||||
import org.openstreetmap.josm.data.imagery.ImageryInfo.ImageryBounds;
|
import org.openstreetmap.josm.data.imagery.ImageryInfo.ImageryBounds;
|
||||||
import org.openstreetmap.josm.data.preferences.LongProperty;
|
import org.openstreetmap.josm.data.preferences.LongProperty;
|
||||||
|
@ -59,6 +57,8 @@ public class ESRISourceReader {
|
||||||
private static final String JSON_QUERY_PARAM = "?f=json";
|
private static final String JSON_QUERY_PARAM = "?f=json";
|
||||||
private static final LongProperty MIRROR_MAXTIME = new LongProperty("mirror.maxtime", TimeUnit.DAYS.toSeconds(7));
|
private static final LongProperty MIRROR_MAXTIME = new LongProperty("mirror.maxtime", TimeUnit.DAYS.toSeconds(7));
|
||||||
|
|
||||||
|
private final JsonProvider jsonProvider = JsonProvider.provider();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructs a {@code ImageryReader} from a given filename, URL or internal
|
* Constructs a {@code ImageryReader} from a given filename, URL or internal
|
||||||
* resource.
|
* resource.
|
||||||
|
@ -88,36 +88,36 @@ public class ESRISourceReader {
|
||||||
* @throws IOException if any I/O error occurs
|
* @throws IOException if any I/O error occurs
|
||||||
*/
|
*/
|
||||||
public List<ForkJoinTask<MapWithAIInfo>> parse() throws IOException {
|
public List<ForkJoinTask<MapWithAIInfo>> parse() throws IOException {
|
||||||
Pattern startReplace = Pattern.compile("\\{start}");
|
final var startReplace = Pattern.compile("\\{start}");
|
||||||
String search = "/search" + JSON_QUERY_PARAM + "&sortField=added&sortOrder=desc&num=" + INITIAL_SEARCH
|
final var search = "/search" + JSON_QUERY_PARAM + "&sortField=added&sortOrder=desc&num=" + INITIAL_SEARCH
|
||||||
+ "&start={start}";
|
+ "&start={start}";
|
||||||
String url = source.getUrl();
|
final var group = source.getId();
|
||||||
String group = source.getId();
|
var url = source.getUrl();
|
||||||
if (!url.endsWith("/")) {
|
if (!url.endsWith("/")) {
|
||||||
url = url.concat("/");
|
url = url.concat("/");
|
||||||
}
|
}
|
||||||
|
|
||||||
final List<ForkJoinTask<MapWithAIInfo>> information = new ArrayList<>();
|
final var information = new ArrayList<ForkJoinTask<MapWithAIInfo>>();
|
||||||
|
|
||||||
int next = 1;
|
var next = 1;
|
||||||
String searchUrl = startReplace.matcher(search).replaceAll(Integer.toString(next));
|
var searchUrl = startReplace.matcher(search).replaceAll(Integer.toString(next));
|
||||||
|
|
||||||
while (next != -1) {
|
while (next != -1) {
|
||||||
final String finalUrl = url + "content/groups/" + group + searchUrl;
|
final var finalUrl = url + "content/groups/" + group + searchUrl;
|
||||||
final String jsonString = getJsonString(finalUrl, TimeUnit.SECONDS.toMillis(MIRROR_MAXTIME.get()) / 7,
|
final var jsonString = getJsonString(finalUrl, TimeUnit.SECONDS.toMillis(MIRROR_MAXTIME.get()) / 7,
|
||||||
this.fastFail);
|
this.fastFail);
|
||||||
if (jsonString == null) {
|
if (jsonString == null) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
try (JsonReader reader = Json
|
try (var reader = jsonProvider
|
||||||
.createReader(new ByteArrayInputStream(jsonString.getBytes(StandardCharsets.UTF_8)))) {
|
.createReader(new ByteArrayInputStream(jsonString.getBytes(StandardCharsets.UTF_8)))) {
|
||||||
JsonStructure parser = reader.read();
|
final var parser = reader.read();
|
||||||
if (parser.getValueType() == JsonValue.ValueType.OBJECT) {
|
if (parser.getValueType() == JsonValue.ValueType.OBJECT) {
|
||||||
JsonObject obj = parser.asJsonObject();
|
final var obj = parser.asJsonObject();
|
||||||
next = obj.getInt("nextStart", -1);
|
next = obj.getInt("nextStart", -1);
|
||||||
searchUrl = startReplace.matcher(search).replaceAll(Integer.toString(next));
|
searchUrl = startReplace.matcher(search).replaceAll(Integer.toString(next));
|
||||||
JsonArray features = obj.getJsonArray("results");
|
final var features = obj.getJsonArray("results");
|
||||||
for (JsonObject feature : features.getValuesAs(JsonObject.class)) {
|
for (var feature : features.getValuesAs(JsonObject.class)) {
|
||||||
information.add(parse(feature));
|
information.add(parse(feature));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -126,7 +126,7 @@ public class ESRISourceReader {
|
||||||
next = -1;
|
next = -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (ForkJoinTask<MapWithAIInfo> future : information) {
|
for (var future : information) {
|
||||||
try {
|
try {
|
||||||
future.join();
|
future.join();
|
||||||
future.get(1, TimeUnit.MINUTES);
|
future.get(1, TimeUnit.MINUTES);
|
||||||
|
@ -142,7 +142,7 @@ public class ESRISourceReader {
|
||||||
|
|
||||||
private ForkJoinTask<MapWithAIInfo> parse(JsonObject feature) {
|
private ForkJoinTask<MapWithAIInfo> parse(JsonObject feature) {
|
||||||
// Use the initial esri server information to keep conflation info
|
// Use the initial esri server information to keep conflation info
|
||||||
MapWithAIInfo newInfo = new MapWithAIInfo(source);
|
final var newInfo = new MapWithAIInfo(source);
|
||||||
newInfo.setId(feature.getString("id"));
|
newInfo.setId(feature.getString("id"));
|
||||||
ForkJoinTask<MapWithAIInfo> future;
|
ForkJoinTask<MapWithAIInfo> future;
|
||||||
if ("Feature Service".equals(feature.getString("type", ""))) {
|
if ("Feature Service".equals(feature.getString("type", ""))) {
|
||||||
|
@ -154,11 +154,10 @@ public class ESRISourceReader {
|
||||||
}
|
}
|
||||||
MapWithAIDataUtils.getForkJoinPool().execute(future);
|
MapWithAIDataUtils.getForkJoinPool().execute(future);
|
||||||
newInfo.setName(feature.getString("title", feature.getString("name")));
|
newInfo.setName(feature.getString("title", feature.getString("name")));
|
||||||
String[] extent = feature.getJsonArray("extent").getValuesAs(JsonArray.class).stream()
|
final var extent = feature.getJsonArray("extent").getValuesAs(JsonArray.class).stream()
|
||||||
.flatMap(array -> array.getValuesAs(JsonNumber.class).stream()).map(JsonNumber::doubleValue)
|
.flatMap(array -> array.getValuesAs(JsonNumber.class).stream()).map(JsonNumber::doubleValue)
|
||||||
.map(Object::toString).toArray(String[]::new);
|
.map(Object::toString).toArray(String[]::new);
|
||||||
ImageryBounds imageryBounds = new ImageryBounds(String.join(",", extent[1], extent[0], extent[3], extent[2]),
|
final var imageryBounds = new ImageryBounds(String.join(",", extent[1], extent[0], extent[3], extent[2]), ",");
|
||||||
",");
|
|
||||||
newInfo.setBounds(imageryBounds);
|
newInfo.setBounds(imageryBounds);
|
||||||
newInfo.setSourceType(MapWithAIType.ESRI_FEATURE_SERVER);
|
newInfo.setSourceType(MapWithAIType.ESRI_FEATURE_SERVER);
|
||||||
newInfo.setTermsOfUseText(feature.getString("licenseInfo", null));
|
newInfo.setTermsOfUseText(feature.getString("licenseInfo", null));
|
||||||
|
@ -167,11 +166,10 @@ public class ESRISourceReader {
|
||||||
source.getUrl() + "content/items/" + newInfo.getId() + "/info/" + feature.getString("thumbnail"));
|
source.getUrl() + "content/items/" + newInfo.getId() + "/info/" + feature.getString("thumbnail"));
|
||||||
}
|
}
|
||||||
if (feature.containsKey("groupCategories")) {
|
if (feature.containsKey("groupCategories")) {
|
||||||
List<MapWithAICategory> categories = feature.getJsonArray("groupCategories").getValuesAs(JsonString.class)
|
final var categories = feature.getJsonArray("groupCategories").getValuesAs(JsonString.class).stream()
|
||||||
.stream().map(JsonString::getString).map(s -> s.replace("/Categories/", ""))
|
.map(JsonString::getString).map(s -> s.replace("/Categories/", ""))
|
||||||
.map(MapWithAICategory::fromString).filter(Objects::nonNull)
|
.map(MapWithAICategory::fromString).collect(Collectors.toCollection(ArrayList::new));
|
||||||
.collect(Collectors.toCollection(ArrayList::new));
|
final var category = categories.stream().filter(c -> MapWithAICategory.FEATURED != c).findFirst()
|
||||||
MapWithAICategory category = categories.stream().filter(c -> MapWithAICategory.FEATURED != c).findFirst()
|
|
||||||
.orElse(MapWithAICategory.OTHER);
|
.orElse(MapWithAICategory.OTHER);
|
||||||
newInfo.setCategory(category);
|
newInfo.setCategory(category);
|
||||||
categories.remove(category);
|
categories.remove(category);
|
||||||
|
@ -187,7 +185,7 @@ public class ESRISourceReader {
|
||||||
}
|
}
|
||||||
newInfo.setDescription(feature.getString("snippet"));
|
newInfo.setDescription(feature.getString("snippet"));
|
||||||
if (newInfo.getSource() != null) {
|
if (newInfo.getSource() != null) {
|
||||||
StringBuilder sourceTag = new StringBuilder(newInfo.getSource());
|
final var sourceTag = new StringBuilder(newInfo.getSource());
|
||||||
if (!sourceTag.toString().endsWith("/")) {
|
if (!sourceTag.toString().endsWith("/")) {
|
||||||
sourceTag.append('/');
|
sourceTag.append('/');
|
||||||
}
|
}
|
||||||
|
@ -208,7 +206,7 @@ public class ESRISourceReader {
|
||||||
*/
|
*/
|
||||||
@Nullable
|
@Nullable
|
||||||
private static String getJsonString(@Nonnull final String url, final long defaultMaxAge, final boolean fastFail) {
|
private static String getJsonString(@Nonnull final String url, final long defaultMaxAge, final boolean fastFail) {
|
||||||
String jsonString = SOURCE_CACHE.get(url);
|
var jsonString = SOURCE_CACHE.get(url);
|
||||||
if (jsonString == null) {
|
if (jsonString == null) {
|
||||||
HttpClient client = null;
|
HttpClient client = null;
|
||||||
try {
|
try {
|
||||||
|
@ -216,12 +214,12 @@ public class ESRISourceReader {
|
||||||
if (fastFail) {
|
if (fastFail) {
|
||||||
client.setReadTimeout(1000);
|
client.setReadTimeout(1000);
|
||||||
}
|
}
|
||||||
final HttpClient.Response response = client.connect();
|
final var response = client.connect();
|
||||||
jsonString = response.fetchContent();
|
jsonString = response.fetchContent();
|
||||||
if (jsonString != null && response.getResponseCode() < 400 && response.getResponseCode() >= 200) {
|
if (jsonString != null && response.getResponseCode() < 400 && response.getResponseCode() >= 200) {
|
||||||
// getExpiration returns milliseconds
|
// getExpiration returns milliseconds
|
||||||
final long expirationTime = response.getExpiration();
|
final long expirationTime = response.getExpiration();
|
||||||
final IElementAttributes elementAttributes = SOURCE_CACHE.getDefaultElementAttributes();
|
final var elementAttributes = SOURCE_CACHE.getDefaultElementAttributes();
|
||||||
if (expirationTime > 0) {
|
if (expirationTime > 0) {
|
||||||
elementAttributes.setMaxLife(response.getExpiration());
|
elementAttributes.setMaxLife(response.getExpiration());
|
||||||
} else {
|
} else {
|
||||||
|
@ -249,22 +247,21 @@ public class ESRISourceReader {
|
||||||
*/
|
*/
|
||||||
@Nullable
|
@Nullable
|
||||||
private String featureService(@Nonnull MapWithAIInfo mapwithaiInfo, @Nonnull String url) {
|
private String featureService(@Nonnull MapWithAIInfo mapwithaiInfo, @Nonnull String url) {
|
||||||
final String toGet = url.endsWith(JSON_QUERY_PARAM) ? url : url.concat(JSON_QUERY_PARAM);
|
final var toGet = url.endsWith(JSON_QUERY_PARAM) ? url : url + JSON_QUERY_PARAM;
|
||||||
final String jsonString = getJsonString(toGet, TimeUnit.SECONDS.toMillis(MIRROR_MAXTIME.get()), this.fastFail);
|
final var jsonString = getJsonString(toGet, TimeUnit.SECONDS.toMillis(MIRROR_MAXTIME.get()), this.fastFail);
|
||||||
if (jsonString == null) {
|
if (jsonString == null) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
try (JsonReader reader = Json
|
try (var reader = Json.createReader(new ByteArrayInputStream(jsonString.getBytes(StandardCharsets.UTF_8)))) {
|
||||||
.createReader(new ByteArrayInputStream(jsonString.getBytes(StandardCharsets.UTF_8)))) {
|
final var info = reader.readObject();
|
||||||
JsonObject info = reader.readObject();
|
final var layers = info.getJsonArray("layers");
|
||||||
JsonArray layers = info.getJsonArray("layers");
|
|
||||||
// This fixes #20551
|
// This fixes #20551
|
||||||
if (layers == null || layers.stream().noneMatch(Objects::nonNull)) {
|
if (layers == null || layers.stream().noneMatch(Objects::nonNull)) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
// TODO use all the layers?
|
// TODO use all the layers?
|
||||||
JsonObject layer = layers.stream().filter(Objects::nonNull).findFirst().orElse(JsonValue.EMPTY_JSON_OBJECT)
|
final var layer = layers.stream().filter(Objects::nonNull).findFirst().orElse(JsonValue.EMPTY_JSON_OBJECT)
|
||||||
.asJsonObject();
|
.asJsonObject();
|
||||||
if (layer.containsKey("id")) {
|
if (layer.containsKey("id")) {
|
||||||
String partialUrl = (url.endsWith("/") ? url : url + "/") + layer.getInt("id");
|
String partialUrl = (url.endsWith("/") ? url : url + "/") + layer.getInt("id");
|
||||||
|
@ -286,10 +283,10 @@ public class ESRISourceReader {
|
||||||
*/
|
*/
|
||||||
@Nonnull
|
@Nonnull
|
||||||
private Map<String, String> getReplacementTags(@Nonnull String layerUrl) {
|
private Map<String, String> getReplacementTags(@Nonnull String layerUrl) {
|
||||||
String toGet = layerUrl.endsWith(JSON_QUERY_PARAM) ? layerUrl : layerUrl.concat(JSON_QUERY_PARAM);
|
final var toGet = layerUrl.endsWith(JSON_QUERY_PARAM) ? layerUrl : layerUrl.concat(JSON_QUERY_PARAM);
|
||||||
final String jsonString = getJsonString(toGet, TimeUnit.SECONDS.toMillis(MIRROR_MAXTIME.get()), this.fastFail);
|
final var jsonString = getJsonString(toGet, TimeUnit.SECONDS.toMillis(MIRROR_MAXTIME.get()), this.fastFail);
|
||||||
if (jsonString != null) {
|
if (jsonString != null) {
|
||||||
try (JsonReader reader = Json
|
try (var reader = Json
|
||||||
.createReader(new ByteArrayInputStream(jsonString.getBytes(StandardCharsets.UTF_8)))) {
|
.createReader(new ByteArrayInputStream(jsonString.getBytes(StandardCharsets.UTF_8)))) {
|
||||||
return reader.readObject().getJsonArray("fields").getValuesAs(JsonObject.class).stream()
|
return reader.readObject().getJsonArray("fields").getValuesAs(JsonObject.class).stream()
|
||||||
.collect(Collectors.toMap(o -> o.getString("name"), ESRISourceReader::getReplacementTag));
|
.collect(Collectors.toMap(o -> o.getString("name"), ESRISourceReader::getReplacementTag));
|
||||||
|
|
Ładowanie…
Reference in New Issue