From 4b0a07bb2f3d4abb31188bac40ba26e4e9ba2313 Mon Sep 17 00:00:00 2001 From: Taylor Smock Date: Mon, 13 Jan 2020 10:42:53 -0700 Subject: [PATCH] This allows for continuous download of areas Downloading data from OSM will trigger a download of MapWithAI data, if continous download is enabled (per MapWithAI layer basis, don't currently want to create another pref key). Signed-off-by: Taylor Smock --- .gitlab-ci.yml | 1 - build.gradle | 1 + gradle.properties | 4 +- .../plugins/mapwithai/MapWithAIPlugin.java | 7 +- .../mapwithai/backend/DownloadListener.java | 65 +++++++++++++++++++ .../mapwithai/backend/MapWithAIAction.java | 1 + .../mapwithai/backend/MapWithAILayer.java | 51 ++++++++++++++- 7 files changed, 122 insertions(+), 8 deletions(-) create mode 100644 src/main/java/org/openstreetmap/josm/plugins/mapwithai/backend/DownloadListener.java diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 1429c64..aff96eb 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -112,7 +112,6 @@ compile against min JOSM: - ./gradlew compileJava_minJosm dependencies: - assemble - allow_failure: true compile against latest JOSM: stage: test diff --git a/build.gradle b/build.gradle index b04a55c..2825850 100644 --- a/build.gradle +++ b/build.gradle @@ -127,6 +127,7 @@ jacocoTestCoverageVerification { josm { manifest { + oldVersionDownloadLink 15542, "v1.0.3", new URL("https://gokaart.gitlab.io/JOSM_MapWithAI/dist/v1.0.3/mapwithai.jar") oldVersionDownloadLink 15233, "v0.2.9", new URL("https://gokaart.gitlab.io/JOSM_MapWithAI/dist/v0.2.9/mapwithai.jar") } i18n { diff --git a/gradle.properties b/gradle.properties index fdf16e4..d0e0ad1 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,9 +1,9 @@ # The minimum JOSM version this plugin is compatible with (can be any numeric version -plugin.main.version = 15542 +plugin.main.version = 15609 # The JOSM version this plugin is currently compiled against # Please make sure this version is available at https://josm.openstreetmap.de/download # The special values "latest" and "tested" are also possible here, but not recommended. -plugin.compile.version = 15603 +plugin.compile.version = 15609 plugin.canloadatruntime = true plugin.author = Taylor Smock plugin.class = org.openstreetmap.josm.plugins.mapwithai.MapWithAIPlugin diff --git a/src/main/java/org/openstreetmap/josm/plugins/mapwithai/MapWithAIPlugin.java b/src/main/java/org/openstreetmap/josm/plugins/mapwithai/MapWithAIPlugin.java index 13b8f4e..dc90f29 100644 --- a/src/main/java/org/openstreetmap/josm/plugins/mapwithai/MapWithAIPlugin.java +++ b/src/main/java/org/openstreetmap/josm/plugins/mapwithai/MapWithAIPlugin.java @@ -17,7 +17,6 @@ import javax.swing.JMenu; import javax.swing.JMenuItem; import org.openstreetmap.josm.actions.JosmAction; -import org.openstreetmap.josm.data.Version; import org.openstreetmap.josm.data.validation.OsmValidator; import org.openstreetmap.josm.gui.MainApplication; import org.openstreetmap.josm.gui.MainMenu; @@ -27,6 +26,7 @@ import org.openstreetmap.josm.gui.preferences.PreferenceSetting; import org.openstreetmap.josm.io.remotecontrol.RequestProcessor; import org.openstreetmap.josm.plugins.Plugin; import org.openstreetmap.josm.plugins.PluginInformation; +import org.openstreetmap.josm.plugins.mapwithai.backend.DownloadListener; import org.openstreetmap.josm.plugins.mapwithai.backend.MapWithAIAction; import org.openstreetmap.josm.plugins.mapwithai.backend.MapWithAIDataUtils; import org.openstreetmap.josm.plugins.mapwithai.backend.MapWithAILayer; @@ -160,8 +160,7 @@ public final class MapWithAIPlugin extends Plugin implements Destroyable { destroyables.forEach(Destroyable::destroy); DownloadDialog.removeDownloadSource(mapWithAIDownloadReader); - if (Version.getInstance().getVersion() >= 15603) { - OsmValidator.removeTest(RoutingIslandsTest.class); - } + OsmValidator.removeTest(RoutingIslandsTest.class); + DownloadListener.destroyAll(); } } diff --git a/src/main/java/org/openstreetmap/josm/plugins/mapwithai/backend/DownloadListener.java b/src/main/java/org/openstreetmap/josm/plugins/mapwithai/backend/DownloadListener.java new file mode 100644 index 0000000..0f77fbc --- /dev/null +++ b/src/main/java/org/openstreetmap/josm/plugins/mapwithai/backend/DownloadListener.java @@ -0,0 +1,65 @@ +// License: GPL. For details, see LICENSE file. +package org.openstreetmap.josm.plugins.mapwithai.backend; + +import java.lang.ref.WeakReference; +import java.util.Collection; +import java.util.HashSet; +import java.util.Objects; +import java.util.stream.Collectors; + +import org.openstreetmap.josm.data.Bounds; +import org.openstreetmap.josm.data.osm.DataSet; +import org.openstreetmap.josm.data.osm.DataSourceChangeEvent; +import org.openstreetmap.josm.data.osm.DataSourceListener; +import org.openstreetmap.josm.data.osm.event.DataSourceAddedEvent; +import org.openstreetmap.josm.tools.Destroyable; + +/** + * This class listens for download events, and then gets new data + * + * @author Taylor Smock + * + */ +public final class DownloadListener implements DataSourceListener, Destroyable { + + private WeakReference ds; + private static final Collection LISTENERS = new HashSet<>(); + + public DownloadListener(DataSet dataSet) { + ds = new WeakReference<>(Objects.requireNonNull(dataSet, "DataSet cannot be null")); + ds.get().addDataSourceListener(this); + LISTENERS.add(this); + } + + @Override + public void dataSourceChange(DataSourceChangeEvent event) { + if (event instanceof DataSourceAddedEvent) { + MapWithAILayer layer = MapWithAIDataUtils.getLayer(false); + if (layer == null) { + destroy(); + return; + } + if (layer.downloadContinuous()) { + MapWithAIDataUtils.getMapWithAIData(layer, event.getAdded().stream().map(ev -> ev.bounds) + .map(Bounds::toBBox).collect(Collectors.toList())); + } + } + } + + @Override + public void destroy() { + if (ds.get() != null) { + // Should be added, so no exception should be thrown + ds.get().removeDataSourceListener(this); + ds.clear(); + LISTENERS.remove(this); + } + } + + /** + * Destroy all download listeners for MapWithAI + */ + public static void destroyAll() { + LISTENERS.forEach(DownloadListener::destroy); + } +} diff --git a/src/main/java/org/openstreetmap/josm/plugins/mapwithai/backend/MapWithAIAction.java b/src/main/java/org/openstreetmap/josm/plugins/mapwithai/backend/MapWithAIAction.java index e1b9a56..d357904 100644 --- a/src/main/java/org/openstreetmap/josm/plugins/mapwithai/backend/MapWithAIAction.java +++ b/src/main/java/org/openstreetmap/josm/plugins/mapwithai/backend/MapWithAIAction.java @@ -47,6 +47,7 @@ public class MapWithAIAction extends JosmAction { .collect(Collectors.toList()); final OsmDataLayer layer = getOsmLayer(osmLayers); if ((layer != null) && MapWithAIDataUtils.getMapWithAIData(MapWithAIDataUtils.getLayer(true), layer)) { + new DownloadListener(layer.getDataSet()); final Notification notification = createMessageDialog(); if (notification != null) { notification.show(); diff --git a/src/main/java/org/openstreetmap/josm/plugins/mapwithai/backend/MapWithAILayer.java b/src/main/java/org/openstreetmap/josm/plugins/mapwithai/backend/MapWithAILayer.java index 6215f0f..403fde7 100644 --- a/src/main/java/org/openstreetmap/josm/plugins/mapwithai/backend/MapWithAILayer.java +++ b/src/main/java/org/openstreetmap/josm/plugins/mapwithai/backend/MapWithAILayer.java @@ -3,7 +3,10 @@ package org.openstreetmap.josm.plugins.mapwithai.backend; import static org.openstreetmap.josm.tools.I18n.tr; +import java.awt.Component; +import java.awt.event.ActionEvent; import java.io.File; +import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.List; @@ -11,8 +14,10 @@ import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; import java.util.stream.Collectors; +import javax.swing.AbstractAction; import javax.swing.Action; import javax.swing.Icon; +import javax.swing.JCheckBoxMenuItem; import javax.swing.JLabel; import javax.swing.JPanel; import javax.swing.SwingConstants; @@ -25,6 +30,7 @@ import org.openstreetmap.josm.data.osm.DownloadPolicy; import org.openstreetmap.josm.data.osm.OsmPrimitive; import org.openstreetmap.josm.data.osm.UploadPolicy; import org.openstreetmap.josm.gui.MainApplication; +import org.openstreetmap.josm.gui.layer.Layer; import org.openstreetmap.josm.gui.layer.MainLayerManager.ActiveLayerChangeEvent; import org.openstreetmap.josm.gui.layer.MainLayerManager.ActiveLayerChangeListener; import org.openstreetmap.josm.gui.layer.OsmDataLayer; @@ -43,6 +49,7 @@ public class MapWithAILayer extends OsmDataLayer implements ActiveLayerChangeLis private Integer maximumAddition; private String url; private Boolean switchLayers; + private boolean continuousDownload; private final Lock lock; /** @@ -114,7 +121,12 @@ public class MapWithAILayer extends OsmDataLayer implements ActiveLayerChangeLis public Action[] getMenuEntries() { final List actions = Arrays.asList(super.getMenuEntries()).stream() .filter(action -> !(action instanceof LayerSaveAction) && !(action instanceof LayerSaveAsAction)) - .collect(Collectors.toList()); + .collect(Collectors.toCollection(ArrayList::new)); + if (actions.isEmpty()) { + actions.add(new ContinuousDownloadAction(this)); + } else { + actions.add(actions.size() - 2, new ContinuousDownloadAction(this)); + } return actions.toArray(new Action[0]); } @@ -205,4 +217,41 @@ public class MapWithAILayer extends OsmDataLayer implements ActiveLayerChangeLis SwingUtilities.invokeLater(() -> getDataSet().setSelected(selection)); } } + + /** + * @return {@code true} indicates that we should attempt to keep it in sync with + * the data layer(s) + */ + public boolean downloadContinuous() { + return continuousDownload; + } + + private class ContinuousDownloadAction extends AbstractAction implements LayerAction { + private static final long serialVersionUID = -3528632887550700527L; + private final MapWithAILayer layer; + + public ContinuousDownloadAction(MapWithAILayer layer) { + super(tr("Continuous download")); + new ImageProvider("download").getResource().attachImageIcon(this, true); + this.layer = layer; + } + + @Override + public void actionPerformed(ActionEvent e) { + layer.continuousDownload = !layer.continuousDownload; + } + + @Override + public boolean supportLayers(List layers) { + return layers.stream().allMatch(MapWithAILayer.class::isInstance); + } + + @Override + public Component createMenuComponent() { + JCheckBoxMenuItem item = new JCheckBoxMenuItem(this); + item.setSelected(layer.continuousDownload); + return item; + } + + } }