From 9e2e551a0afeee267151d0f84fe7bd66eff5f8a5 Mon Sep 17 00:00:00 2001
From: Robert Scott <code@humanleg.org.uk>
Date: Sat, 6 Oct 2018 12:27:38 +0100
Subject: [PATCH v1 4/4] SlippyMapBBoxChooser: add ability to listen for layer
 additions & removals, triggering refreshTileSources

hook this up for MiniMapDialog. most other SlippyMapBBoxChooser uses in josm
aren't really long-lived enough for this to be worth it.
---
 .../josm/gui/bbox/SlippyMapBBoxChooser.java        |  20 ++-
 .../josm/gui/dialogs/MinimapDialog.java            |   1 +
 .../josm/gui/dialogs/MinimapDialogTest.java        | 138 +++++++++++++++++++--
 3 files changed, 149 insertions(+), 10 deletions(-)

diff --git a/src/org/openstreetmap/josm/gui/bbox/SlippyMapBBoxChooser.java b/src/org/openstreetmap/josm/gui/bbox/SlippyMapBBoxChooser.java
index 821065de6..e4344b220 100644
--- a/src/org/openstreetmap/josm/gui/bbox/SlippyMapBBoxChooser.java
+++ b/src/org/openstreetmap/josm/gui/bbox/SlippyMapBBoxChooser.java
@@ -63,8 +63,7 @@ import org.openstreetmap.josm.tools.Logging;
 /**
  * This panel displays a map and lets the user chose a {@link BBox}.
  */
-public class SlippyMapBBoxChooser extends JMapViewer implements BBoxChooser, ChangeListener, MainLayerManager.ActiveLayerChangeListener {
-
+public class SlippyMapBBoxChooser extends JMapViewer implements BBoxChooser, ChangeListener, MainLayerManager.ActiveLayerChangeListener, MainLayerManager.LayerChangeListener {
     /**
      * A list of tile sources that can be used for displaying the map.
      */
@@ -449,4 +448,21 @@ public class SlippyMapBBoxChooser extends JMapViewer implements BBoxChooser, Cha
 
         this.iSourceButton.setSources(new ArrayList<>(newTileSources.values()));
     }
+
+    @Override
+    public void layerAdded(MainLayerManager.LayerAddEvent e) {
+        if (e.getAddedLayer() instanceof ImageryLayer) {
+            this.refreshTileSources();
+        }
+    }
+
+    @Override
+    public void layerRemoving(MainLayerManager.LayerRemoveEvent e) {
+        if (e.getRemovedLayer() instanceof ImageryLayer) {
+            this.refreshTileSources();
+        }
+    }
+
+    @Override
+    public void layerOrderChanged(MainLayerManager.LayerOrderChangeEvent e) {}
 }
diff --git a/src/org/openstreetmap/josm/gui/dialogs/MinimapDialog.java b/src/org/openstreetmap/josm/gui/dialogs/MinimapDialog.java
index 26248164b..509b4a3e4 100644
--- a/src/org/openstreetmap/josm/gui/dialogs/MinimapDialog.java
+++ b/src/org/openstreetmap/josm/gui/dialogs/MinimapDialog.java
@@ -37,6 +37,7 @@ public class MinimapDialog extends ToggleDialog implements NavigatableComponent.
         createLayout(slippyMap, false, Collections.emptyList());
         slippyMap.setSizeButtonVisible(false);
         slippyMap.addPropertyChangeListener(BBoxChooser.BBOX_PROP, this);
+        MainApplication.getLayerManager().addLayerChangeListener(slippyMap);
     }
 
     @Override
diff --git a/test/unit/org/openstreetmap/josm/gui/dialogs/MinimapDialogTest.java b/test/unit/org/openstreetmap/josm/gui/dialogs/MinimapDialogTest.java
index 8d33d3f2a..69103a30b 100644
--- a/test/unit/org/openstreetmap/josm/gui/dialogs/MinimapDialogTest.java
+++ b/test/unit/org/openstreetmap/josm/gui/dialogs/MinimapDialogTest.java
@@ -2,6 +2,7 @@
 package org.openstreetmap.josm.gui.dialogs;
 
 import static java.util.concurrent.TimeUnit.MILLISECONDS;
+import static org.junit.Assert.assertArrayEquals;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertTrue;
@@ -13,6 +14,7 @@ import java.awt.Component;
 import java.awt.Graphics2D;
 import java.awt.event.ComponentEvent;
 import java.awt.image.BufferedImage;
+import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Map;
 import java.util.Objects;
@@ -130,6 +132,24 @@ public class MinimapDialogTest {
         }
     }
 
+    protected void assertSourceLabelsVisible(final String... labels) {
+        GuiHelper.runInEDTAndWaitWithException(() -> {
+            final ArrayList<String> menuLabels = new ArrayList<>();
+            final JPopupMenu menu = this.sourceButton.getPopupMenu();
+            for (Component c: menu.getComponents()) {
+                if (c instanceof JPopupMenu.Separator) {
+                    break;
+                }
+                menuLabels.add(((JMenuItem) c).getText());
+            }
+
+            assertArrayEquals(
+                labels,
+                menuLabels.toArray()
+            );
+        });
+    }
+
     private MinimapDialog minimap;
     private SlippyMapBBoxChooser slippyMap;
     private SourceButton sourceButton;
@@ -302,18 +322,36 @@ public class MinimapDialogTest {
         // relevant prefs starting out empty, should choose the first (ImageryLayerInfo) source and have shown download area enabled
         // (not that there's a data layer for it to use)
 
-        // first we will remove "Green Tiles" from ImageryLayerInfo
-        final ImageryInfo greenTilesInfo = ImageryLayerInfo.instance.getLayers().stream().filter(
-            i -> i.getName().equals("Green Tiles")
+        final ImageryInfo magentaTilesInfo = ImageryLayerInfo.instance.getLayers().stream().filter(
+            i -> i.getName().equals("Magenta Tiles")
+        ).findAny().get();
+        final ImageryInfo blackTilesInfo = ImageryLayerInfo.instance.getLayers().stream().filter(
+            i -> i.getName().equals("Black Tiles")
         ).findAny().get();
-        ImageryLayerInfo.instance.remove(greenTilesInfo);
 
-        GuiHelper.runInEDT(() -> MainApplication.getLayerManager().addLayer(ImageryLayer.create(greenTilesInfo)));
+        // first we will remove "Magenta Tiles" from ImageryLayerInfo
+        ImageryLayerInfo.instance.remove(magentaTilesInfo);
 
         this.setUpMiniMap();
 
-        this.clickSourceMenuItemByLabel("Green Tiles");
-        this.assertSingleSelectedSourceLabel("Green Tiles");
+        assertSourceLabelsVisible(
+            "White Tiles",
+            "Black Tiles",
+            "Green Tiles"
+        );
+
+        final ImageryLayer magentaTilesLayer = ImageryLayer.create(magentaTilesInfo);
+        GuiHelper.runInEDT(() -> MainApplication.getLayerManager().addLayer(magentaTilesLayer));
+
+        assertSourceLabelsVisible(
+            "White Tiles",
+            "Black Tiles",
+            "Green Tiles",
+            "Magenta Tiles"
+        );
+
+        this.clickSourceMenuItemByLabel("Magenta Tiles");
+        this.assertSingleSelectedSourceLabel("Magenta Tiles");
 
         // call paint to trigger new tile fetch
         this.paintSlippyMap();
@@ -322,7 +360,91 @@ public class MinimapDialogTest {
 
         this.paintSlippyMap();
 
-        assertEquals(0xff00ff00, paintedSlippyMap.getRGB(0, 0));
+        assertEquals(0xffff00ff, paintedSlippyMap.getRGB(0, 0));
+
+        final ImageryLayer blackTilesLayer = ImageryLayer.create(blackTilesInfo);
+        GuiHelper.runInEDT(() -> MainApplication.getLayerManager().addLayer(blackTilesLayer));
+
+        assertSourceLabelsVisible(
+            "White Tiles",
+            "Black Tiles",
+            "Green Tiles",
+            "Magenta Tiles"
+        );
+
+        this.clickSourceMenuItemByLabel("Black Tiles");
+        this.assertSingleSelectedSourceLabel("Black Tiles");
+
+        // call paint to trigger new tile fetch
+        this.paintSlippyMap();
+
+        Awaitility.await().atMost(1000, MILLISECONDS).until(this.slippyMapTasksFinished);
+
+        this.paintSlippyMap();
+
+        assertEquals(0xff000000, paintedSlippyMap.getRGB(0, 0));
+
+        // removing magentaTilesLayer while it is *not* the selected TileSource should make it disappear
+        // immediately
+        GuiHelper.runInEDT(() -> MainApplication.getLayerManager().removeLayer(magentaTilesLayer));
+
+        assertSourceLabelsVisible(
+            "White Tiles",
+            "Black Tiles",
+            "Green Tiles"
+        );
+        this.assertSingleSelectedSourceLabel("Black Tiles");
+
+        final ImageryLayer magentaTilesLayer2 = ImageryLayer.create(magentaTilesInfo);
+        GuiHelper.runInEDT(() -> MainApplication.getLayerManager().addLayer(magentaTilesLayer2));
+
+        assertSourceLabelsVisible(
+            "White Tiles",
+            "Black Tiles",
+            "Green Tiles",
+            "Magenta Tiles"
+        );
+
+        this.clickSourceMenuItemByLabel("Magenta Tiles");
+        this.assertSingleSelectedSourceLabel("Magenta Tiles");
+
+        // call paint to trigger new tile fetch
+        this.paintSlippyMap();
+
+        Awaitility.await().atMost(1000, MILLISECONDS).until(this.slippyMapTasksFinished);
+
+        this.paintSlippyMap();
+
+        assertEquals(0xffff00ff, paintedSlippyMap.getRGB(0, 0));
+
+        // removing magentaTilesLayer while it *is* the selected TileSource...
+        GuiHelper.runInEDT(() -> MainApplication.getLayerManager().removeLayer(magentaTilesLayer2));
+
+        assertSourceLabelsVisible(
+            "White Tiles",
+            "Black Tiles",
+            "Green Tiles",
+            "Magenta Tiles"
+        );
+        this.assertSingleSelectedSourceLabel("Magenta Tiles");
+
+        this.clickSourceMenuItemByLabel("Green Tiles");
+        this.assertSingleSelectedSourceLabel("Green Tiles");
+        assertSourceLabelsVisible(
+            "White Tiles",
+            "Black Tiles",
+            "Green Tiles"
+        );
+
+        // removing blackTilesLayer shouldn't remove it from the menu as it is already in ImageryLayerInfo
+        GuiHelper.runInEDT(() -> MainApplication.getLayerManager().removeLayer(blackTilesLayer));
+
+        this.assertSingleSelectedSourceLabel("Green Tiles");
+        assertSourceLabelsVisible(
+            "White Tiles",
+            "Black Tiles",
+            "Green Tiles"
+        );
     }
 
     /**
-- 
2.11.0

