001// License: GPL. For details, see LICENSE file. 002package org.openstreetmap.josm.gui.tagging.presets; 003 004import static org.openstreetmap.josm.tools.I18n.tr; 005 006import java.awt.Component; 007import java.awt.MouseInfo; 008import java.awt.Point; 009import java.awt.event.ActionEvent; 010import java.io.Serializable; 011import java.util.ArrayList; 012import java.util.Collections; 013import java.util.Comparator; 014import java.util.List; 015import java.util.Objects; 016 017import javax.swing.Action; 018import javax.swing.JMenu; 019import javax.swing.JMenuItem; 020import javax.swing.JPopupMenu; 021import javax.swing.JSeparator; 022 023import org.openstreetmap.josm.Main; 024import org.openstreetmap.josm.tools.AlphanumComparator; 025 026public class TaggingPresetMenu extends TaggingPreset { 027 public JMenu menu; // set by TaggingPresets 028 029 private static class PresetTextComparator implements Comparator<JMenuItem>, Serializable { 030 @Override 031 public int compare(JMenuItem o1, JMenuItem o2) { 032 if (Main.main.menu.presetSearchAction.equals(o1.getAction())) 033 return -1; 034 else if (Main.main.menu.presetSearchAction.equals(o2.getAction())) 035 return 1; 036 else 037 return AlphanumComparator.getInstance().compare(o1.getText(), o2.getText()); 038 } 039 } 040 041 /** 042 * {@code TaggingPresetMenu} are considered equivalent if (and only if) their {@link #getRawName()} match. 043 */ 044 @Override 045 public boolean equals(Object o) { 046 if (this == o) return true; 047 if (o == null || getClass() != o.getClass()) return false; 048 TaggingPresetMenu that = (TaggingPresetMenu) o; 049 return Objects.equals(getRawName(), that.getRawName()); 050 } 051 052 @Override 053 public int hashCode() { 054 return Objects.hash(getRawName()); 055 } 056 057 @Override 058 public void setDisplayName() { 059 putValue(Action.NAME, getName()); 060 /** Tooltips should be shown for the toolbar buttons, but not in the menu. */ 061 putValue(OPTIONAL_TOOLTIP_TEXT, group != null ? 062 tr("Preset group {1} / {0}", getLocaleName(), group.getName()) : 063 tr("Preset group {0}", getLocaleName())); 064 putValue("toolbar", "tagginggroup_" + getRawName()); 065 } 066 067 private static Component copyMenuComponent(Component menuComponent) { 068 if (menuComponent instanceof JMenu) { 069 JMenu menu = (JMenu) menuComponent; 070 JMenu result = new JMenu(menu.getAction()); 071 for (Component item:menu.getMenuComponents()) { 072 result.add(copyMenuComponent(item)); 073 } 074 result.setText(menu.getText()); 075 return result; 076 } else if (menuComponent instanceof JMenuItem) { 077 JMenuItem menuItem = (JMenuItem) menuComponent; 078 JMenuItem result = new JMenuItem(menuItem.getAction()); 079 result.setText(menuItem.getText()); 080 return result; 081 } else if (menuComponent instanceof JSeparator) { 082 return new JSeparator(); 083 } else { 084 return menuComponent; 085 } 086 } 087 088 @Override 089 public void actionPerformed(ActionEvent e) { 090 Object s = e.getSource(); 091 if (menu != null && s instanceof Component) { 092 JPopupMenu pm = new JPopupMenu(getName()); 093 for (Component c : menu.getMenuComponents()) { 094 pm.add(copyMenuComponent(c)); 095 } 096 Point p = MouseInfo.getPointerInfo().getLocation(); 097 pm.show(Main.parent, p.x-Main.parent.getX(), p.y-Main.parent.getY()); 098 } 099 } 100 101 /** 102 * Sorts the menu items using the translated item text 103 */ 104 public void sortMenu() { 105 TaggingPresetMenu.sortMenu(this.menu); 106 } 107 108 /** 109 * Sorts the menu items using the translated item text 110 * @param menu menu to sort 111 */ 112 public static void sortMenu(JMenu menu) { 113 Component[] items = menu.getMenuComponents(); 114 PresetTextComparator comp = new PresetTextComparator(); 115 List<JMenuItem> sortarray = new ArrayList<>(); 116 int lastSeparator = 0; 117 for (int i = 0; i < items.length; i++) { 118 Object item = items[i]; 119 if (item instanceof JMenu) { 120 sortMenu((JMenu) item); 121 } 122 if (item instanceof JMenuItem) { 123 sortarray.add((JMenuItem) item); 124 if (i == items.length-1) { 125 Collections.sort(sortarray, comp); 126 int pos = 0; 127 for (JMenuItem menuItem : sortarray) { 128 int oldPos; 129 if (lastSeparator == 0) { 130 oldPos = pos; 131 } else { 132 oldPos = pos+lastSeparator+1; 133 } 134 menu.add(menuItem, oldPos); 135 pos++; 136 } 137 sortarray = new ArrayList<>(); 138 lastSeparator = 0; 139 } 140 } else if (item instanceof JSeparator) { 141 Collections.sort(sortarray, comp); 142 int pos = 0; 143 for (JMenuItem menuItem : sortarray) { 144 int oldPos; 145 if (lastSeparator == 0) { 146 oldPos = pos; 147 } else { 148 oldPos = pos+lastSeparator+1; 149 } 150 menu.add(menuItem, oldPos); 151 pos++; 152 } 153 sortarray = new ArrayList<>(); 154 lastSeparator = i; 155 } 156 } 157 } 158}