001// License: GPL. For details, see LICENSE file.
002package org.openstreetmap.josm.gui.dialogs;
003
004import static org.openstreetmap.josm.tools.I18n.tr;
005
006import java.awt.Component;
007import java.awt.Dimension;
008import java.awt.event.ActionEvent;
009import java.awt.event.KeyEvent;
010
011import javax.swing.DefaultListCellRenderer;
012import javax.swing.JLabel;
013import javax.swing.JList;
014import javax.swing.JMenuItem;
015import javax.swing.ListCellRenderer;
016
017import org.openstreetmap.josm.Main;
018import org.openstreetmap.josm.actions.JosmAction;
019import org.openstreetmap.josm.gui.ExtendedDialog;
020import org.openstreetmap.josm.gui.MainMenu;
021import org.openstreetmap.josm.gui.widgets.SearchTextResultListPanel;
022import org.openstreetmap.josm.tools.Shortcut;
023
024public final class MenuItemSearchDialog extends ExtendedDialog {
025
026    private final Selector selector;
027    private static final MenuItemSearchDialog INSTANCE = new MenuItemSearchDialog(Main.main.menu);
028
029    private MenuItemSearchDialog(MainMenu menu) {
030        super(Main.parent, tr("Search menu items"), new String[]{tr("Select"), tr("Cancel")});
031        this.selector = new Selector(menu);
032        this.selector.setDblClickListener(e -> buttonAction(0, null));
033        setContent(selector, false);
034        setPreferredSize(new Dimension(600, 300));
035    }
036
037    /**
038     * Returns the unique instance of {@code MenuItemSearchDialog}.
039     *
040     * @return the unique instance of {@code MenuItemSearchDialog}.
041     */
042    public static synchronized MenuItemSearchDialog getInstance() {
043        return INSTANCE;
044    }
045
046    @Override
047    public ExtendedDialog showDialog() {
048        selector.init();
049        super.showDialog();
050        selector.clearSelection();
051        return this;
052    }
053
054    @Override
055    protected void buttonAction(int buttonIndex, ActionEvent evt) {
056        super.buttonAction(buttonIndex, evt);
057        if (buttonIndex == 0 && selector.getSelectedItem() != null && selector.getSelectedItem().isEnabled()) {
058            selector.getSelectedItem().getAction().actionPerformed(evt);
059        }
060    }
061
062    private static class Selector extends SearchTextResultListPanel<JMenuItem> {
063
064        private final MainMenu menu;
065
066        Selector(MainMenu menu) {
067            super();
068            this.menu = menu;
069            lsResult.setCellRenderer(new CellRenderer());
070        }
071
072        public JMenuItem getSelectedItem() {
073            final JMenuItem selected = lsResult.getSelectedValue();
074            if (selected != null) {
075                return selected;
076            } else if (!lsResultModel.isEmpty()) {
077                return lsResultModel.getElementAt(0);
078            } else {
079                return null;
080            }
081        }
082
083        @Override
084        protected void filterItems() {
085            lsResultModel.setItems(menu.findMenuItems(edSearchText.getText(), true));
086        }
087    }
088
089    private static class CellRenderer implements ListCellRenderer<JMenuItem> {
090
091        private final DefaultListCellRenderer def = new DefaultListCellRenderer();
092
093        @Override
094        public Component getListCellRendererComponent(JList<? extends JMenuItem> list, JMenuItem value, int index,
095                                                      boolean isSelected, boolean cellHasFocus) {
096            final JLabel label = (JLabel) def.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus);
097            label.setText(value.getText());
098            label.setIcon(value.getIcon());
099            label.setEnabled(value.isEnabled());
100            final JMenuItem item = new JMenuItem(value.getText());
101            item.setAction(value.getAction());
102            if (isSelected) {
103                item.setBackground(list.getSelectionBackground());
104                item.setForeground(list.getSelectionForeground());
105            } else {
106                item.setBackground(list.getBackground());
107                item.setForeground(list.getForeground());
108            }
109            return item;
110        }
111    }
112
113    public static class Action extends JosmAction {
114
115        // CHECKSTYLE.OFF: LineLength
116        /** Action shortcut (ctrl / space by default */
117        public static final Shortcut SHORTCUT = Shortcut.registerShortcut("help:search-items", "Search menu items", KeyEvent.VK_SPACE, Shortcut.CTRL);
118        // CHECKSTYLE.ON: LineLength
119
120        /**
121         * Constructs a new {@code Action}.
122         */
123        public Action() {
124            super(tr("Search menu items"), "dialogs/search", null,
125                    SHORTCUT,
126                    true, "dialogs/search-items", false);
127        }
128
129        @Override
130        public void actionPerformed(ActionEvent e) {
131            MenuItemSearchDialog.getInstance().showDialog();
132        }
133    }
134}