package example;
// -*- mode:java; encoding:utf-8 -*-
// vim:set fileencoding=utf-8:
// @homepage@
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.event.*;
import javax.swing.plaf.basic.BasicCheckBoxMenuItemUI;

public final class MainPanel extends JPanel {
    private MainPanel() {
        super();

        JToggleButton button = new JToggleButton("JPopupMenu Test");
        JPopupMenu popup = new JPopupMenu();
        TogglePopupHandler handler = new TogglePopupHandler(popup, button);
        popup.addPopupMenuListener(handler);
        button.addActionListener(handler);

        popup.add(new JCheckBox("JCheckBox") {
            @Override public void updateUI() {
                super.updateUI();
                setFocusPainted(false);
            }
            @Override public Dimension getMinimumSize() {
                Dimension d = getPreferredSize();
                d.width = Short.MAX_VALUE;
                return d;
            }
        });
        popup.add(makeStayOpenCheckBoxMenuItem("JMenuItem + JCheckBox"));
        popup.add(new JCheckBoxMenuItem("JCheckBoxMenuItem"));
        popup.add(new JCheckBoxMenuItem("keeping open #1")).addActionListener(e -> {
            System.out.println("ActionListener");
            Container c = SwingUtilities.getAncestorOfClass(JPopupMenu.class, (Component) e.getSource());
            if (c instanceof JPopupMenu) {
                ((JPopupMenu) c).setVisible(true);
            }
        });
        popup.add(new JCheckBoxMenuItem("keeping open #2") {
            @Override public void updateUI() {
                super.updateUI();
                setUI(new BasicCheckBoxMenuItemUI() {
                    // https://stackoverflow.com/questions/3759379/how-to-prevent-jpopupmenu-disappearing-when-checking-checkboxes-in-it
                    @Override protected void doClick(MenuSelectionManager msm) {
                        // super.doClick(msm);
                        System.out.println("MenuSelectionManager: doClick");
                        menuItem.doClick(0);
                    }
                });
            }
        });

        setOpaque(true);
        setComponentPopupMenu(popup);
        add(button);
        setPreferredSize(new Dimension(320, 240));
    }
    private static JMenuItem makeStayOpenCheckBoxMenuItem(String title) {
        JMenuItem mi = new JMenuItem(" ");
        mi.setLayout(new BorderLayout());
        mi.add(new JCheckBox(title) {
            private transient MouseInputListener handler;
            @Override public void updateUI() {
                removeMouseListener(handler);
                removeMouseMotionListener(handler);
                super.updateUI();
                handler = new DispatchParentHandler();
                addMouseListener(handler);
                addMouseMotionListener(handler);
                setFocusable(false);
                setOpaque(false);
            }
        });
        return mi;
    }
    public static void main(String... args) {
        EventQueue.invokeLater(new Runnable() {
            @Override public void run() {
                createAndShowGui();
            }
        });
    }
    public static void createAndShowGui() {
        try {
            UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
        } catch (ClassNotFoundException | InstantiationException
               | IllegalAccessException | UnsupportedLookAndFeelException ex) {
            ex.printStackTrace();
        }
        JFrame frame = new JFrame("@title@");
        frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
        frame.getContentPane().add(new MainPanel());
        frame.pack();
        frame.setLocationRelativeTo(null);
        frame.setVisible(true);
    }
}

class DispatchParentHandler extends MouseInputAdapter {
    private void dispatchEvent(MouseEvent e) {
        Component src = e.getComponent();
        Container tgt = SwingUtilities.getUnwrappedParent(src);
        tgt.dispatchEvent(SwingUtilities.convertMouseEvent(src, e, tgt));
    }
    @Override public void mouseEntered(MouseEvent e) {
        dispatchEvent(e);
    }
    @Override public void mouseExited(MouseEvent e) {
        dispatchEvent(e);
    }
    @Override public void mouseMoved(MouseEvent e) {
        dispatchEvent(e);
    }
    @Override public void mouseDragged(MouseEvent e) {
        dispatchEvent(e);
    }
}

class TogglePopupHandler implements PopupMenuListener, ActionListener {
    private final JPopupMenu popup;
    private final AbstractButton button;
    protected TogglePopupHandler(JPopupMenu popup, AbstractButton button) {
        this.popup = popup;
        this.button = button;
    }
    @Override public void actionPerformed(ActionEvent e) {
        AbstractButton b = (AbstractButton) e.getSource();
        if (b.isSelected()) {
            Container p = SwingUtilities.getUnwrappedParent(b);
            Rectangle r = b.getBounds();
            popup.show(p, r.x, r.y + r.height);
        } else {
            popup.setVisible(false);
        }
    }
    @Override public void popupMenuCanceled(PopupMenuEvent e) { /* not needed */ }
    @Override public void popupMenuWillBecomeInvisible(PopupMenuEvent e) {
        EventQueue.invokeLater(() -> {
            button.getModel().setArmed(false);
            button.getModel().setSelected(false);
        });
    }
    @Override public void popupMenuWillBecomeVisible(PopupMenuEvent e) { /* not needed */ }
}

@@ -137,59 +137,287 @@
 ent.
-*;%0Aimport javax.swing.*;%0Aimport javax.swing.event.*
+ActionEvent;%0Aimport java.awt.event.ActionListener;%0Aimport java.awt.event.MouseEvent;%0Aimport javax.swing.*;%0Aimport javax.swing.event.MouseInputAdapter;%0Aimport javax.swing.event.MouseInputListener;%0Aimport javax.swing.event.PopupMenuEvent;%0Aimport javax.swing.event.PopupMenuListener
 ;%0Aim
@@ -558,16 +558,109 @@
 super();
+%0A        // Java 9%0A        // UIManager.put(%22CheckBoxMenuItem.doNotCloseOnMouseClick%22, true);
 %0A%0A      
@@ -928,24 +928,268 @@
 (handler);%0A%0A
+        // Java 9%0A        // JCheckBoxMenuItem checkMenuItem = new JCheckBoxMenuItemd(%22doNotCloseOnMouseClick%22);%0A        // checkMenuItem.putClientProperty(%22CheckBoxMenuItem.doNotCloseOnMouseClick%22, true);%0A        // popup.add(checkMenuItem);%0A%0A
         popu

add CheckBoxMenuItem.doNotCloseOnMouseClick usage example in comments