// License: GPL. For details, see LICENSE file. package org.openstreetmap.josm.gui.tagging.presets; import static org.openstreetmap.josm.tools.I18n.tr; import java.awt.Component; import java.awt.MouseInfo; import java.awt.Point; import java.awt.PointerInfo; import java.awt.event.ActionEvent; import java.io.Serializable; import java.util.ArrayList; import java.util.Comparator; import java.util.List; import java.util.Objects; import javax.swing.Action; import javax.swing.JMenu; import javax.swing.JMenuItem; import javax.swing.JPopupMenu; import javax.swing.JSeparator; import org.openstreetmap.josm.Main; import org.openstreetmap.josm.tools.AlphanumComparator; public class TaggingPresetMenu extends TaggingPreset { public JMenu menu; // set by TaggingPresets private static class PresetTextComparator implements Comparator<JMenuItem>, Serializable { @Override public int compare(JMenuItem o1, JMenuItem o2) { if (Main.main.menu.presetSearchAction.equals(o1.getAction())) return -1; else if (Main.main.menu.presetSearchAction.equals(o2.getAction())) return 1; else return AlphanumComparator.getInstance().compare(o1.getText(), o2.getText()); } } /** * {@code TaggingPresetMenu} are considered equivalent if (and only if) their {@link #getRawName()} match. */ @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; TaggingPresetMenu that = (TaggingPresetMenu) o; return Objects.equals(getRawName(), that.getRawName()); } @Override public int hashCode() { return Objects.hash(getRawName()); } @Override public void setDisplayName() { putValue(Action.NAME, getName()); /** Tooltips should be shown for the toolbar buttons, but not in the menu. */ putValue(OPTIONAL_TOOLTIP_TEXT, group != null ? tr("Preset group {1} / {0}", getLocaleName(), group.getName()) : tr("Preset group {0}", getLocaleName())); putValue("toolbar", "tagginggroup_" + getRawName()); } private static Component copyMenuComponent(Component menuComponent) { if (menuComponent instanceof JMenu) { JMenu menu = (JMenu) menuComponent; JMenu result = new JMenu(menu.getAction()); for (Component item:menu.getMenuComponents()) { result.add(copyMenuComponent(item)); } result.setText(menu.getText()); return result; } else if (menuComponent instanceof JMenuItem) { JMenuItem menuItem = (JMenuItem) menuComponent; JMenuItem result = new JMenuItem(menuItem.getAction()); result.setText(menuItem.getText()); return result; } else if (menuComponent instanceof JSeparator) { return new JSeparator(); } else { return menuComponent; } } @Override public void actionPerformed(ActionEvent e) { Object s = e.getSource(); if (menu != null && s instanceof Component) { JPopupMenu pm = new JPopupMenu(getName()); for (Component c : menu.getMenuComponents()) { pm.add(copyMenuComponent(c)); } PointerInfo pointerInfo = MouseInfo.getPointerInfo(); if (pointerInfo != null) { Point p = pointerInfo.getLocation(); pm.show(Main.parent, p.x-Main.parent.getX(), p.y-Main.parent.getY()); } } } /** * Sorts the menu items using the translated item text */ public void sortMenu() { TaggingPresetMenu.sortMenu(this.menu); } /** * Sorts the menu items using the translated item text * @param menu menu to sort */ public static void sortMenu(JMenu menu) { Component[] items = menu.getMenuComponents(); PresetTextComparator comp = new PresetTextComparator(); List<JMenuItem> sortarray = new ArrayList<>(); int lastSeparator = 0; for (int i = 0; i < items.length; i++) { Object item = items[i]; if (item instanceof JMenu) { sortMenu((JMenu) item); } if (item instanceof JMenuItem) { sortarray.add((JMenuItem) item); if (i == items.length-1) { handleMenuItem(menu, comp, sortarray, lastSeparator); sortarray = new ArrayList<>(); lastSeparator = 0; } } else if (item instanceof JSeparator) { handleMenuItem(menu, comp, sortarray, lastSeparator); sortarray = new ArrayList<>(); lastSeparator = i; } } } private static void handleMenuItem(JMenu menu, PresetTextComparator comp, List<JMenuItem> sortarray, int lastSeparator) { sortarray.sort(comp); int pos = 0; for (JMenuItem menuItem : sortarray) { int oldPos; if (lastSeparator == 0) { oldPos = pos; } else { oldPos = pos+lastSeparator+1; } menu.add(menuItem, oldPos); pos++; } } }