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; 010import java.util.Optional; 011 012import javax.swing.DefaultListCellRenderer; 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 JMenuItem item = new JMenuItem(value.getText()); 097 item.setAction(value.getAction()); 098 Optional.ofNullable(value.getAction()) 099 .filter(JosmAction.class::isInstance) 100 .map(JosmAction.class::cast) 101 .map(JosmAction::getShortcut) 102 .map(Shortcut::getKeyStroke) 103 .ifPresent(item::setAccelerator); 104 if (isSelected) { 105 item.setBackground(list.getSelectionBackground()); 106 item.setForeground(list.getSelectionForeground()); 107 } else { 108 item.setBackground(list.getBackground()); 109 item.setForeground(list.getForeground()); 110 } 111 return item; 112 } 113 } 114 115 public static class Action extends JosmAction { 116 117 // CHECKSTYLE.OFF: LineLength 118 /** Action shortcut (ctrl / space by default */ 119 public static final Shortcut SHORTCUT = Shortcut.registerShortcut("help:search-items", "Search menu items", KeyEvent.VK_SPACE, Shortcut.CTRL); 120 // CHECKSTYLE.ON: LineLength 121 122 /** 123 * Constructs a new {@code Action}. 124 */ 125 public Action() { 126 super(tr("Search menu items"), "dialogs/search", null, 127 SHORTCUT, 128 true, "dialogs/search-items", false); 129 } 130 131 @Override 132 public void actionPerformed(ActionEvent e) { 133 MenuItemSearchDialog.getInstance().showDialog(); 134 } 135 } 136}