Ticket #21605: 21605.3.patch

File 21605.3.patch, 24.0 KB (added by taylor.smock, 3 years ago)

Fix #16056, #21605, #22536

  • src/org/openstreetmap/josm/gui/layer/geoimage/GeoImageLayer.java

    IDEA additional info:
    Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
    <+>UTF-8
    diff --git a/src/org/openstreetmap/josm/gui/layer/geoimage/GeoImageLayer.java b/src/org/openstreetmap/josm/gui/layer/geoimage/GeoImageLayer.java
    a b  
    6262import org.openstreetmap.josm.gui.layer.JumpToMarkerActions.JumpToPreviousMarker;
    6363import org.openstreetmap.josm.gui.layer.Layer;
    6464import org.openstreetmap.josm.gui.layer.MainLayerManager.ActiveLayerChangeListener;
     65import org.openstreetmap.josm.gui.util.GuiHelper;
    6566import org.openstreetmap.josm.gui.util.imagery.Vector3D;
    6667import org.openstreetmap.josm.tools.ImageProvider;
    6768import org.openstreetmap.josm.tools.Utils;
     
    7172 * @since 99
    7273 */
    7374public class GeoImageLayer extends AbstractModifiableLayer implements
    74         JumpToMarkerLayer, NavigatableComponent.ZoomChangeListener, ImageDataUpdateListener {
     75        JumpToMarkerLayer, NavigatableComponent.ZoomChangeListener, ImageDataUpdateListener,
     76        IGeoImageLayer {
    7577
    7678    private static final List<Action> menuAdditions = new LinkedList<>();
    7779
     
    172174        this.useThumbs = useThumbs;
    173175        this.data.addImageDataUpdateListener(this);
    174176        this.data.setLayer(this);
     177        if (!ImageViewerDialog.hasInstance()) {
     178            this.data.setSelectedImage(this.data.getFirstImage());
     179            // This must be called *after* this layer is added to the layer manager.
     180            // But it must also be run in the EDT. By adding this to the worker queue
     181            // and then running the actual code in the EDT, we ensure that the layer
     182            // will be added to the layer manager regardless of whether or not this
     183            // was instantiated in the worker thread or the EDT thread.
     184            MainApplication.worker.submit(() -> GuiHelper.runInEDT(() ->
     185                    ImageViewerDialog.getInstance().displayImages(this, Collections.singletonList(this.data.getSelectedImage()))));
     186        }
    175187    }
    176188
    177189    private final class ImageMouseListener extends MouseAdapter {
     
    247259        MainApplication.worker.execute(new ImagesLoader(files, gpxLayer));
    248260    }
    249261
     262    @Override
     263    public void clearSelection() {
     264        this.getImageData().clearSelectedImage();
     265    }
     266
    250267    @Override
    251268    public Icon getIcon() {
    252269        return ImageProvider.get("dialogs/geoimage", ImageProvider.ImageSizes.LAYER);
    253270    }
    254271
     272    @Override
     273    public List<ImageEntry> getSelection() {
     274        return this.getImageData().getSelectedImages();
     275    }
     276
    255277    /**
    256278     * Register actions on the layer
    257279     * @param addition the action to be added
  • new file src/org/openstreetmap/josm/gui/layer/geoimage/IGeoImageLayer.java

    IDEA additional info:
    Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
    <+>UTF-8
    diff --git a/src/org/openstreetmap/josm/gui/layer/geoimage/IGeoImageLayer.java b/src/org/openstreetmap/josm/gui/layer/geoimage/IGeoImageLayer.java
    new file mode 100644
    - +  
     1// License: GPL. For details, see LICENSE file.
     2package org.openstreetmap.josm.gui.layer.geoimage;
     3
     4import java.util.List;
     5
     6import org.openstreetmap.josm.data.imagery.street_level.IImageEntry;
     7
     8/**
     9 * An interface for layers which want to show images
     10 * @since xxx
     11 */
     12public interface IGeoImageLayer {
     13    /**
     14     * Clear the selection of the layer
     15     */
     16    void clearSelection();
     17
     18    /**
     19     * Get the current selection
     20     * @return The currently selected images
     21     */
     22    List<? extends IImageEntry<?>> getSelection();
     23}
  • src/org/openstreetmap/josm/gui/layer/geoimage/ImageViewerDialog.java

    IDEA additional info:
    Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
    <+>UTF-8
    diff --git a/src/org/openstreetmap/josm/gui/layer/geoimage/ImageViewerDialog.java b/src/org/openstreetmap/josm/gui/layer/geoimage/ImageViewerDialog.java
    a b  
    1111import java.awt.GridBagConstraints;
    1212import java.awt.GridBagLayout;
    1313import java.awt.event.ActionEvent;
    14 import java.awt.event.ActionListener;
    1514import java.awt.event.KeyEvent;
    1615import java.awt.event.WindowEvent;
    1716import java.io.IOException;
     
    3130import java.util.concurrent.Future;
    3231import java.util.function.UnaryOperator;
    3332import java.util.stream.Collectors;
     33import java.util.stream.IntStream;
     34import java.util.stream.Stream;
    3435
     36import javax.annotation.Nonnull;
     37import javax.annotation.Nullable;
    3538import javax.swing.AbstractAction;
     39import javax.swing.AbstractButton;
    3640import javax.swing.Box;
    3741import javax.swing.JButton;
    3842import javax.swing.JLabel;
     
    4246import javax.swing.SwingConstants;
    4347import javax.swing.SwingUtilities;
    4448
     49import org.openstreetmap.josm.actions.ExpertToggleAction;
    4550import org.openstreetmap.josm.actions.JosmAction;
    4651import org.openstreetmap.josm.data.ImageData;
    4752import org.openstreetmap.josm.data.ImageData.ImageDataUpdateListener;
     
    6469import org.openstreetmap.josm.gui.layer.imagery.ImageryFilterSettings;
    6570import org.openstreetmap.josm.gui.util.GuiHelper;
    6671import org.openstreetmap.josm.gui.util.imagery.Vector3D;
     72import org.openstreetmap.josm.gui.widgets.HideableTabbedPane;
     73import org.openstreetmap.josm.spi.preferences.Config;
    6774import org.openstreetmap.josm.tools.ImageProvider;
    6875import org.openstreetmap.josm.tools.Logging;
    6976import org.openstreetmap.josm.tools.PlatformManager;
     
    124131        return dialog;
    125132    }
    126133
     134    /**
     135     * Check if there is an instance for the {@link ImageViewerDialog}
     136     * @return {@code true} if there is a static singleton instance of {@link ImageViewerDialog}
     137     * @since xxx
     138     */
     139    public static boolean hasInstance() {
     140        return dialog != null;
     141    }
     142
     143    /**
     144     * Destroy the current dialog
     145     */
     146    private static void destroyInstance() {
     147        dialog = null;
     148    }
     149
    127150    private JButton btnLast;
    128151    private JButton btnNext;
    129152    private JButton btnPrevious;
     
    135158    private JButton btnDeleteFromDisk;
    136159    private JToggleButton tbCentre;
    137160    /** The layer tab (used to select images when multiple layers provide images, makes for easy switching) */
    138     private JPanel layers;
     161    private HideableTabbedPane layers;
    139162
    140163    private ImageViewerDialog() {
    141164        super(tr("Geotagged Images"), "geoimage", tr("Display geotagged images"), Shortcut.registerShortcut("tools:geotagged",
     
    168191
    169192    private void build() {
    170193        JPanel content = new JPanel(new BorderLayout());
    171         this.layers = new JPanel(new GridBagLayout());
    172         content.add(layers, BorderLayout.NORTH);
    173 
    174         content.add(imgDisplay, BorderLayout.CENTER);
     194        this.layers = new HideableTabbedPane();
     195        content.add(layers, BorderLayout.CENTER);
    175196
    176197        Dimension buttonDim = new Dimension(26, 26);
    177198
     
    187208        btnLast = createNavigationButton(imageLastAction, buttonDim);
    188209
    189210        tbCentre = new JToggleButton(imageCenterViewAction);
     211        tbCentre.setSelected(Config.getPref().getBoolean("geoimage.viewer.centre.on.image", false));
    190212        tbCentre.setPreferredSize(buttonDim);
    191213
    192214        JButton btnZoomBestFit = new JButton(imageZoomAction);
     
    196218        btnCollapse.setAlignmentY(Component.TOP_ALIGNMENT);
    197219
    198220        JPanel buttons = new JPanel();
    199         buttons.add(btnFirst);
    200         buttons.add(btnPrevious);
    201         buttons.add(btnNext);
    202         buttons.add(btnLast);
    203         buttons.add(Box.createRigidArea(new Dimension(7, 0)));
    204         buttons.add(tbCentre);
    205         buttons.add(btnZoomBestFit);
    206         buttons.add(Box.createRigidArea(new Dimension(7, 0)));
    207         buttons.add(btnDelete);
    208         buttons.add(btnDeleteFromDisk);
    209         buttons.add(Box.createRigidArea(new Dimension(7, 0)));
    210         buttons.add(btnCopyPath);
    211         buttons.add(btnOpenExternal);
    212         buttons.add(Box.createRigidArea(new Dimension(7, 0)));
    213         buttons.add(createButton(visibilityAction, buttonDim));
     221        addButtonGroup(buttons, this.btnFirst, this.btnPrevious, this.btnNext, this.btnLast);
     222        addButtonGroup(buttons, this.tbCentre, btnZoomBestFit);
     223        addButtonGroup(buttons, this.btnDelete, this.btnDeleteFromDisk);
     224        addButtonGroup(buttons, this.btnCopyPath, this.btnOpenExternal);
     225        addButtonGroup(buttons, createButton(visibilityAction, buttonDim));
    214226
    215227        JPanel bottomPane = new JPanel(new GridBagLayout());
    216228        GridBagConstraints gc = new GridBagConstraints();
     
    231243        createLayout(content, false, null);
    232244    }
    233245
    234     private void updateLayers() {
    235         if (this.tabbedEntries.size() <= 1) {
     246    /**
     247     * Add a button group to a panel
     248     * @param buttonPanel The panel holding the buttons
     249     * @param buttons The button group to add
     250     */
     251    private static void addButtonGroup(JPanel buttonPanel, AbstractButton... buttons) {
     252        if (buttonPanel.getComponentCount() != 0) {
     253            buttonPanel.add(Box.createRigidArea(new Dimension(7, 0)));
     254        }
     255
     256        for (AbstractButton jButton : buttons) {
     257            buttonPanel.add(jButton);
     258        }
     259    }
     260
     261    /**
     262     * Update the tabs for the different image layers
     263     * @param changed {@code true} if the tabs changed
     264     */
     265    private void updateLayers(boolean changed) {
     266        if (this.tabbedEntries.isEmpty()) {
    236267            this.layers.setVisible(false);
    237             this.layers.removeAll();
    238268        } else {
    239269            this.layers.setVisible(true);
    240270            // Remove all old components
    241             this.layers.removeAll();
    242271            MainLayerManager layerManager = MainApplication.getLayerManager();
    243272            List<Layer> invalidLayers = this.tabbedEntries.keySet().stream().filter(layer -> !layerManager.containsLayer(layer))
    244273                    .collect(Collectors.toList());
    245274            // `null` is for anything using the old methods, without telling us what layer it comes from.
    246             invalidLayers.remove(null);
     275            if (this.tabbedEntries.containsKey(null) && !this.tabbedEntries.getOrDefault(null, Collections.emptyList()).isEmpty()) {
     276                invalidLayers.remove(null);
     277            }
    247278            // We need to do multiple calls to avoid ConcurrentModificationExceptions
    248279            invalidLayers.forEach(this.tabbedEntries::remove);
    249             addButtonsForImageLayers();
     280            if (changed) {
     281                addButtonsForImageLayers();
     282            }
     283            MoveImgDisplayPanel selected = (MoveImgDisplayPanel) this.layers.getSelectedComponent();
     284            if ((this.imgDisplay.getParent() == null || this.imgDisplay.getParent().getParent() == null)
     285                && selected != null && selected.entries.contains(this.currentEntry)) {
     286                selected.setVisible(selected.isVisible());
     287            } else if (selected != null && !selected.entries.contains(this.currentEntry)) {
     288                this.getImageTabs().filter(m -> m.entries.contains(this.currentEntry)).mapToInt(this.layers::indexOfComponent).findFirst()
     289                        .ifPresent(this.layers::setSelectedIndex);
     290            }
    250291            this.layers.invalidate();
    251292        }
     293        this.layers.getParent().invalidate();
    252294        this.revalidate();
    253295    }
    254296
     
    256298     * Add the buttons for image layers
    257299     */
    258300    private void addButtonsForImageLayers() {
    259         final IImageEntry<?> current;
    260         synchronized (this) {
    261             current = this.currentEntry;
    262         }
    263         List<JButton> layerButtons = new ArrayList<>(this.tabbedEntries.size());
     301        List<MoveImgDisplayPanel> alreadyAdded = this.getImageTabs().collect(Collectors.toList());
    264302        if (this.tabbedEntries.containsKey(null)) {
    265303            List<IImageEntry<?>> nullEntries = this.tabbedEntries.get(null);
    266             JButton layerButton = createImageLayerButton(null, nullEntries);
    267             layerButtons.add(layerButton);
    268             layerButton.setEnabled(!nullEntries.contains(current));
     304            if (alreadyAdded.stream().noneMatch(m -> Objects.isNull(m.layer) && Objects.equals(nullEntries, m.entries))) {
     305                this.layers.addTab(tr("Default"), new MoveImgDisplayPanel(this.imgDisplay, null, nullEntries));
     306            }
     307        } else {
     308            this.removeImageTab(null);
    269309        }
     310        List<Layer> availableLayers = MainApplication.getLayerManager().getLayers();
    270311        for (Map.Entry<Layer, List<IImageEntry<?>>> entry :
    271312                this.tabbedEntries.entrySet().stream().filter(entry -> entry.getKey() != null)
    272                         .sorted(Comparator.comparing(entry -> entry.getKey().getName())).collect(Collectors.toList())) {
    273             JButton layerButton = createImageLayerButton(entry.getKey(), entry.getValue());
    274             layerButtons.add(layerButton);
    275             layerButton.setEnabled(!entry.getValue().contains(current));
     313                        .sorted(Comparator.comparingInt(entry -> /*reverse*/-availableLayers.indexOf(entry.getKey())))
     314                        .collect(Collectors.toList())) {
     315            final Layer layer = entry.getKey();
     316            final int index = availableLayers.size() - availableLayers.indexOf(layer);
     317            final String label = (ExpertToggleAction.isExpert() ? "[" + index + "] " : "") + layer.getLabel();
     318            final Optional<MoveImgDisplayPanel> originalPanel = alreadyAdded.stream()
     319                    .filter(m -> Objects.equals(m.layer, entry.getKey())).findFirst();
     320            if (originalPanel.isPresent()) {
     321                int componentIndex = this.layers.indexOfComponent(originalPanel.get());
     322                this.layers.setTitleAt(componentIndex, label);
     323            } else {
     324                this.layers.addTab(label, new MoveImgDisplayPanel(this.imgDisplay, entry.getKey(), entry.getValue()));
     325            }
    276326        }
    277         layerButtons.forEach(this.layers::add);
     327        this.getImageTabs().map(p -> p.layer).filter(layer -> !this.tabbedEntries.containsKey(layer))
     328                // We have to collect to a list prior to removal -- if we don't, then the stream may get a layer at index 0, remove that layer,
     329                // and then get a layer at index 1, which was previously at index 2.
     330                .collect(Collectors.toList()).forEach(this::removeImageTab);
    278331    }
     332
     333    /**
     334     * Remove a tab for a layer from the {@link #layers} tab pane
     335     * @param layer The layer to remove
     336     */
     337    private void removeImageTab(Layer layer) {
     338        // This must be reversed to avoid removing the wrong tab
     339        for (int i = this.layers.getTabCount() - 1; i >= 0; i--) {
     340            Component component = this.layers.getComponentAt(i);
     341            if (component instanceof MoveImgDisplayPanel) {
     342                MoveImgDisplayPanel moveImgDisplayPanel = (MoveImgDisplayPanel) component;
     343                if (Objects.equals(layer, moveImgDisplayPanel.layer)) {
     344                    this.layers.removeTabAt(i);
     345                    this.layers.remove(moveImgDisplayPanel);
     346                }
     347            }
     348        }
     349    }
    279350
    280351    /**
    281      * Create a button for a specific layer and its entries
    282      *
    283      * @param layer     The layer to switch to
    284      * @param entries   The entries to display
    285      * @return The button to use to switch to the specified layer
     352     * Get the {@link MoveImgDisplayPanel} objects in {@link #layers}.
     353     * @return The individual panels
    286354     */
    287     private static JButton createImageLayerButton(Layer layer, List<IImageEntry<?>> entries) {
    288         final JButton layerButton = new JButton();
    289         layerButton.addActionListener(new ImageActionListener(layer, entries));
    290         layerButton.setText(layer != null ? layer.getLabel() : tr("Default"));
    291         return layerButton;
     355    private Stream<MoveImgDisplayPanel> getImageTabs() {
     356        return IntStream.range(0, this.layers.getTabCount())
     357                .mapToObj(this.layers::getComponentAt)
     358                .filter(MoveImgDisplayPanel.class::isInstance)
     359                .map(MoveImgDisplayPanel.class::cast);
    292360    }
    293361
    294362    @Override
     
    309377        imageZoomAction.destroy();
    310378        cancelLoadingImage();
    311379        super.destroy();
    312         dialog = null;
     380        destroyInstance();
    313381    }
    314382
    315383    /**
     
    433501        }
    434502    }
    435503
    436     /**
    437      * A listener that is called to change the viewing layer
    438      */
    439     private static class ImageActionListener implements ActionListener {
    440 
    441         private final Layer layer;
    442         private final List<IImageEntry<?>> entries;
    443 
    444         ImageActionListener(Layer layer, List<IImageEntry<?>> entries) {
    445             this.layer = layer;
    446             this.entries = entries;
    447         }
    448 
    449         @Override
    450         public void actionPerformed(ActionEvent e) {
    451             ImageViewerDialog.getInstance().displayImages(this.layer, this.entries);
    452         }
    453     }
    454 
    455504    private class ImageFirstAction extends ImageRememberAction {
    456505        ImageFirstAction() {
    457506            super(null, new ImageProvider(DIALOG_FOLDER, "first"), tr("First"), Shortcut.registerShortcut(
     
    478527        public void actionPerformed(ActionEvent e) {
    479528            final JToggleButton button = (JToggleButton) e.getSource();
    480529            centerView = button.isEnabled() && button.isSelected();
     530            Config.getPref().putBoolean("geoimage.viewer.centre.on.image", centerView);
    481531            if (centerView && currentEntry != null && currentEntry.getPos() != null) {
    482532                MainApplication.getMap().mapView.zoomTo(currentEntry.getPos());
    483533            }
     
    618668        }
    619669    }
    620670
     671    /**
     672     * A JPanel whose entire purpose is to display an image by (a) moving the imgDisplay arround and (b) setting the imgDisplay as a child
     673     * for this panel.
     674     */
     675    private static class MoveImgDisplayPanel extends JPanel {
     676        private final Layer layer;
     677        private final List<IImageEntry<?>> entries;
     678        private final ImageDisplay imgDisplay;
     679        MoveImgDisplayPanel(ImageDisplay imgDisplay, Layer layer, List<IImageEntry<?>> entries) {
     680            super(new BorderLayout());
     681            this.layer = layer;
     682            this.entries = entries;
     683            this.imgDisplay = imgDisplay;
     684        }
     685
     686        @Override
     687        public void setVisible(boolean visible) {
     688            super.setVisible(visible);
     689            if (visible) {
     690                if (!ImageViewerDialog.getInstance().getDisplayedImages(this.layer).isEmpty()
     691                        && !this.entries.contains(ImageViewerDialog.getCurrentImage())) {
     692                    ImageViewerDialog.getInstance().displayImages(this.layer, this.entries);
     693                }
     694                if (this.imgDisplay.getParent() != this) {
     695                    this.add(this.imgDisplay, BorderLayout.CENTER);
     696                    this.imgDisplay.invalidate();
     697                    this.revalidate();
     698                }
     699            }
     700        }
     701    }
     702
     703    /**
     704     * Get the images displayed for a layer
     705     * @param layer The layer to get the displayed images for
     706     * @return The images for the layer that are displayed (assuming the tab for the layer is selected)
     707     * @since xxx
     708     */
     709    @Nonnull
     710    public List<IImageEntry<?>> getDisplayedImages(Layer layer) {
     711        return this.tabbedEntries.getOrDefault(layer, Collections.emptyList());
     712    }
     713
    621714    /**
    622715     * Enables (or disables) the "Previous" button.
    623716     * @param value {@code true} to enable the button, {@code false} otherwise
     
    680773     * @since 18246
    681774     */
    682775    public void displayImages(List<IImageEntry<?>> entries) {
    683         this.displayImages((Layer) null, entries);
     776        this.displayImages(null, entries);
    684777    }
    685778
    686779    /**
     
    689782     * @param entries image entries
    690783     * @since 18591
    691784     */
    692     public void displayImages(Layer layer, List<IImageEntry<?>> entries) {
     785    public void displayImages(@Nullable Layer layer, @Nullable List<IImageEntry<?>> entries) {
    693786        boolean imageChanged;
    694787        IImageEntry<?> entry = entries != null && entries.size() == 1 ? entries.get(0) : null;
    695788
     
    710803            }
    711804        }
    712805
    713         if (entries == null || entries.isEmpty() || entries.stream().allMatch(Objects::isNull)) {
     806
     807        final boolean updateRequired;
     808        if (!Config.getPref().getBoolean("geoimage.viewer.show.tabs", true)) {
     809            updateRequired = true;
     810            // Clear the selected images in other geoimage layers
     811            this.getImageTabs().map(m -> m.layer).filter(IGeoImageLayer.class::isInstance).map(IGeoImageLayer.class::cast)
     812                    .filter(l -> !Objects.equals(entries, l.getSelection()))
     813                    .forEach(IGeoImageLayer::clearSelection);
     814            this.tabbedEntries.clear();
     815            this.tabbedEntries.put(layer, entries);
     816        } else if (entries == null || entries.isEmpty() || entries.stream().allMatch(Objects::isNull)) {
     817            updateRequired = this.tabbedEntries.containsKey(layer);
    714818            this.tabbedEntries.remove(layer);
    715819        } else {
     820            updateRequired = !this.tabbedEntries.containsKey(layer);
    716821            this.tabbedEntries.put(layer, entries);
    717822        }
    718         this.updateLayers();
     823        this.updateLayers(updateRequired);
    719824        if (entry != null) {
    720825            this.updateButtonsNonNullEntry(entry, imageChanged);
    721826        } else if (this.tabbedEntries.isEmpty()) {
     
    818923        imgDisplay.setOsdText(osd.toString());
    819924    }
    820925
    821     /**
    822      * Displays images for the given layer.
    823      * @param ignoredData the image data (unused, may be {@code null})
    824      * @param entries image entries
    825      * @since 18246 (signature)
    826      * @deprecated Use {@link #displayImages(List)} (The data param is no longer used)
    827      */
    828     @Deprecated
    829     public void displayImages(ImageData ignoredData, List<IImageEntry<?>> entries) {
    830         this.displayImages(entries);
    831     }
    832 
    833926    private static boolean isLastImageSelected(List<IImageEntry<?>> data) {
    834927        return data.stream().anyMatch(image -> data.contains(image.getLastImage()));
    835928    }
     
    857950        if (btnCollapse != null) {
    858951            btnCollapse.setVisible(!isDocked);
    859952        }
    860         this.updateLayers();
     953        this.updateLayers(true);
    861954    }
    862955
    863956    /**
     
    9121005            removedData.removeImageDataUpdateListener(this);
    9131006        }
    9141007        // Unfortunately, there will be no way to remove the default null layer. This will be fixed as plugins update.
    915         this.tabbedEntries.remove(e.getRemovedLayer());
     1008        this.updateLayers(true);
    9161009    }
    9171010
    9181011    @Override
    9191012    public void layerOrderChanged(LayerOrderChangeEvent e) {
    920         // ignored
     1013        this.updateLayers(true);
    9211014    }
    9221015
    9231016    @Override
     
    9441037        if (layer instanceof GeoImageLayer) {
    9451038            ((GeoImageLayer) layer).getImageData().addImageDataUpdateListener(this);
    9461039        }
     1040        layer.addPropertyChangeListener(l -> {
     1041            if (Layer.NAME_PROP.equals(l.getPropertyName()) && this.tabbedEntries.containsKey(layer)) {
     1042                this.updateLayers(true);
     1043                if (this.tabbedEntries.get(layer).contains(this.currentEntry)) {
     1044                    this.setTitle(layer.getLabel());
     1045                }
     1046            } else if (Layer.VISIBLE_PROP.equals(l.getPropertyName()) && this.tabbedEntries.containsKey(layer)) {
     1047                this.getImageTabs().filter(m -> Objects.equals(m.layer, layer)).mapToInt(this.layers::indexOfComponent)
     1048                        .filter(i -> i >= 0).forEach(i -> this.layers.setEnabledAt(i, layer.isVisible()));
     1049            }
     1050        });
    9471051    }
    9481052
    9491053    private void showLayer(Layer newLayer) {