Ticket #15118: menu-disable.patch

File menu-disable.patch, 4.3 KB (added by bafonins, 7 years ago)

The patch itself

  • src/org/openstreetmap/josm/gui/JosmMenu.java

     
     1// License: GPL. For details, see LICENSE file.
     2
     3package org.openstreetmap.josm.gui;
     4
     5import javax.swing.JMenu;
     6import javax.swing.JMenuItem;
     7import java.awt.Component;
     8import java.awt.event.ContainerEvent;
     9import java.awt.event.ContainerListener;
     10import java.beans.PropertyChangeEvent;
     11import java.beans.PropertyChangeListener;
     12import java.util.ArrayList;
     13import java.util.Arrays;
     14import java.util.List;
     15import java.util.Objects;
     16import java.util.stream.IntStream;
     17import java.util.stream.Stream;
     18
     19/**
     20 * Represents a menu containing a popup menu.
     21 */
     22public class JosmMenu extends JMenu {
     23
     24    /**
     25     * Constructs a new instance of {@link JosmMenu}.
     26     * @param label The label to be displayed on the menu.
     27     */
     28    public JosmMenu(String label) {
     29        super(label);
     30    }
     31
     32    /**
     33     * Gets a stream of {@link JMenuItem} objects contained within this menu.
     34     * @return A stream of {@link JMenuItem} contained within this menu.
     35     */
     36    public Stream<JMenuItem> streamMenuItems() {
     37        return IntStream.range(0, this.getItemCount())
     38                .mapToObj(this::getItem)
     39                .filter(Objects::nonNull)
     40                .filter(JMenuItem.class::isInstance);
     41    }
     42
     43    /**
     44     * Adds a listener to the underlying {@link javax.swing.JPopupMenu} to react
     45     * on {@link JMenuItem} addition/removal. Mainly, adds {@link PropertyChangeListener} to every
     46     * item that disables the menu if none of containing items are enabled.
     47     */
     48    public void addPopupContainerListener() {
     49        enabledPropertyChangeListener(null); // initial check
     50
     51        super.getPopupMenu().addContainerListener(new ContainerListener() {
     52
     53            /**
     54             * Keeps references to all listeners that were added, in order to be able to
     55             * delete them later if needed.
     56             */
     57            private final List<PropertyChangeListener> listeners = new ArrayList<>();
     58
     59            @Override
     60            public void componentAdded(ContainerEvent e) {
     61                Component child = e.getChild();
     62                if (child != null && child instanceof JMenuItem) {
     63                    PropertyChangeListener l = ev -> enabledPropertyChangeListener(ev);
     64                    listeners.add(l);
     65                    child.addPropertyChangeListener("enabled", l);
     66
     67                    enabledPropertyChangeListener(null);
     68                }
     69            }
     70
     71            @Override
     72            public void componentRemoved(ContainerEvent e) {
     73                Component child = e.getChild();
     74                if (child != null && child instanceof JMenuItem) {
     75                    PropertyChangeListener[] ls = child.getPropertyChangeListeners("enabled");
     76                    Arrays.stream(ls)
     77                            .filter(this.listeners::contains)
     78                            .findFirst()
     79                            .ifPresent(l -> {
     80                                this.listeners.remove(l);
     81                                child.removePropertyChangeListener("enabled", l);
     82
     83                                enabledPropertyChangeListener(null);
     84                            });
     85                }
     86            }
     87        });
     88    }
     89
     90    private void enabledPropertyChangeListener(PropertyChangeEvent ev) {
     91        boolean enable = this.streamMenuItems().anyMatch(Component::isEnabled);
     92        this.setEnabled(enable);
     93    }
     94}
  • src/org/openstreetmap/josm/gui/MainMenu.java

     
    608608     * @return the newly created menu
    609609     */
    610610    public JMenu addMenu(String name, String translatedName, int mnemonicKey, int position, String relativeHelpTopic) {
    611         final JMenu menu = new JMenu(translatedName);
     611        final JosmMenu menu = new JosmMenu(translatedName);
     612        menu.addPopupContainerListener();
     613
    612614        if (!GraphicsEnvironment.isHeadless()) {
    613615            MenuScroller.setScrollerFor(menu);
    614616        }