Changeset 11122 in josm


Ignore:
Timestamp:
2016-10-12T20:01:36+02:00 (19 months ago)
Author:
simon04
Message:

fix #12030 - ConcurrentModificationException in findShortcut

Use a CopyOnWriteArrayList to store the shortcuts.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/org/openstreetmap/josm/tools/Shortcut.java

    r10378 r11122  
    88import java.util.Arrays;
    99import java.util.HashMap;
    10 import java.util.LinkedHashMap;
    1110import java.util.LinkedList;
    1211import java.util.List;
    1312import java.util.Map;
     13import java.util.Optional;
     14import java.util.concurrent.CopyOnWriteArrayList;
     15import java.util.stream.Collectors;
    1416
    1517import javax.swing.AbstractAction;
     
    268270
    269271    // here we store our shortcuts
    270     private static Map<String, Shortcut> shortcuts = new LinkedHashMap<>();
     272    private static List<Shortcut> shortcuts = new CopyOnWriteArrayList<>();
    271273
    272274    // and here our modifier groups
     
    274276
    275277    // check if something collides with an existing shortcut
     278
     279    /**
     280     * Returns the registered shortcut fot the key and modifier
     281     * @param requestedKey the requested key
     282     * @param modifier the modifier
     283     * @return the registered shortcut or {@code null}
     284     */
    276285    public static Shortcut findShortcut(int requestedKey, int modifier) {
     286        return findShortcutByKeyOrShortText(requestedKey, modifier, null)
     287                .orElse(null);
     288    }
     289
     290    private static Optional<Shortcut> findShortcutByKeyOrShortText(int requestedKey, int modifier, String shortText) {
    277291        if (modifier == getGroupModifier(NONE))
    278             return null;
    279         for (Shortcut sc : shortcuts.values()) {
    280             if (sc.isSame(requestedKey, modifier))
    281                 return sc;
    282         }
    283         return null;
     292            return Optional.empty();
     293        return shortcuts.stream()
     294                .filter(sc -> sc.isSame(requestedKey, modifier) || (shortText != null && shortText.equals(sc.getShortText())))
     295                .findAny();
     296
    284297    }
    285298
     
    289302     */
    290303    public static List<Shortcut> listAll() {
    291         List<Shortcut> l = new ArrayList<>();
    292         for (Shortcut c : shortcuts.values()) {
    293             if (!"core:none".equals(c.shortText)) {
    294                 l.add(c);
    295             }
    296         }
    297         return l;
     304        return shortcuts.stream()
     305                .filter(c -> !"core:none".equals(c.shortText))
     306                .collect(Collectors.toList());
    298307    }
    299308
     
    354363            if (sc.isAssignedUser()
    355364            && findShortcut(sc.getAssignedKey(), sc.getAssignedModifier()) == null) {
    356                 shortcuts.put(sc.getShortText(), sc);
     365                shortcuts.add(sc);
    357366            }
    358367        }
     
    361370            if (!sc.isAssignedUser() && sc.isAssignedDefault()
    362371            && findShortcut(sc.getAssignedKey(), sc.getAssignedModifier()) == null) {
    363                 shortcuts.put(sc.getShortText(), sc);
     372                shortcuts.add(sc);
    364373            }
    365374        }
     
    368377            if (!sc.isAssignedUser() && !sc.isAssignedDefault()
    369378            && findShortcut(sc.getAssignedKey(), sc.getAssignedModifier()) == null) {
    370                 shortcuts.put(sc.getShortText(), sc);
     379                shortcuts.add(sc);
    371380            }
    372381        }
     
    393402    public static boolean savePrefs() {
    394403        boolean changed = false;
    395         for (Shortcut sc : shortcuts.values()) {
     404        for (Shortcut sc : shortcuts) {
    396405            changed = changed | sc.save();
    397406        }
     
    411420     */
    412421    public static Shortcut registerSystemShortcut(String shortText, String longText, int key, int modifier) {
    413         if (shortcuts.containsKey(shortText))
    414             return shortcuts.get(shortText);
    415         Shortcut potentialShortcut = findShortcut(key, modifier);
    416         if (potentialShortcut != null) {
     422        final Optional<Shortcut> existing = findShortcutByKeyOrShortText(key, modifier, shortText);
     423        if (existing.isPresent() && shortText.equals(existing.get().getShortText())) {
     424            return existing.get();
     425        } else if (existing.isPresent()) {
    417426            // this always is a logic error in the hook
    418             Main.error("CONFLICT WITH SYSTEM KEY "+shortText+": "+potentialShortcut);
     427            Main.error("CONFLICT WITH SYSTEM KEY " + shortText + ": " + existing.get());
    419428            return null;
    420429        }
    421         potentialShortcut = new Shortcut(shortText, longText, key, RESERVED, key, modifier, true, false);
    422         shortcuts.put(shortText, potentialShortcut);
    423         return potentialShortcut;
     430        final Shortcut shortcut = new Shortcut(shortText, longText, key, RESERVED, key, modifier, true, false);
     431        shortcuts.add(shortcut);
     432        return shortcut;
    424433    }
    425434
     
    447456    private static Shortcut registerShortcut(String shortText, String longText, int requestedKey, int requestedGroup, Integer modifier) {
    448457        doInit();
    449         if (shortcuts.containsKey(shortText)) { // a re-register? maybe a sc already read from the preferences?
    450             Shortcut sc = shortcuts.get(shortText);
     458        Integer defaultModifier = findModifier(requestedGroup, modifier);
     459        final Optional<Shortcut> existing = findShortcutByKeyOrShortText(requestedKey, defaultModifier, shortText);
     460        if (existing.isPresent() && shortText.equals(existing.get().getShortText())) {
     461            // a re-register? maybe a sc already read from the preferences?
     462            final Shortcut sc = existing.get();
    451463            sc.setLongText(longText); // or set by the platformHook, in this case the original longText doesn't match the real action
    452464            sc.saveDefault();
    453465            return sc;
    454         }
    455         Integer defaultModifier = findModifier(requestedGroup, modifier);
    456         Shortcut conflict = findShortcut(requestedKey, defaultModifier);
    457         if (conflict != null) {
     466        } else if (existing.isPresent()) {
     467            final Shortcut conflict = existing.get();
    458468            if (Main.isPlatformOsx()) {
    459469                // Try to reassign Meta to Ctrl
     
    477487            Shortcut newsc = new Shortcut(shortText, longText, requestedKey, requestedGroup, requestedKey, defaultModifier, true, false);
    478488            newsc.saveDefault();
    479             shortcuts.put(shortText, newsc);
     489            shortcuts.add(newsc);
    480490            return newsc;
    481491        }
     
    500510            shortText, conflict.getShortText(), newsc.getKeyText()));
    501511        newsc.saveDefault();
    502         shortcuts.put(shortText, newsc);
     512        shortcuts.replaceAll(sc -> shortText.equals(sc.getShortText()) ? newsc : sc);
    503513        return newsc;
    504514    }
     
    512522     */
    513523    public static KeyStroke getCopyKeyStroke() {
    514         Shortcut sc = shortcuts.get("system:copy");
    515         if (sc == null) return null;
    516         return sc.getKeyStroke();
     524        return getKeyStrokeForShortKey("system:copy");
    517525    }
    518526
     
    525533     */
    526534    public static KeyStroke getPasteKeyStroke() {
    527         Shortcut sc = shortcuts.get("system:paste");
    528         if (sc == null) return null;
    529         return sc.getKeyStroke();
     535        return getKeyStrokeForShortKey("system:paste");
    530536    }
    531537
     
    538544     */
    539545    public static KeyStroke getCutKeyStroke() {
    540         Shortcut sc = shortcuts.get("system:cut");
    541         if (sc == null) return null;
    542         return sc.getKeyStroke();
     546        return getKeyStrokeForShortKey("system:cut");
     547    }
     548
     549    private static KeyStroke getKeyStrokeForShortKey(String shortKey) {
     550        return shortcuts.stream()
     551                .filter(sc -> shortKey.equals(sc.getShortText()))
     552                .findAny()
     553                .map(Shortcut::getKeyStroke)
     554                .orElse(null);
    543555    }
    544556}
Note: See TracChangeset for help on using the changeset viewer.