diff --git a/src/org/openstreetmap/josm/tools/Shortcut.java b/src/org/openstreetmap/josm/tools/Shortcut.java
index 2448aec..8c212bc 100644
a
|
b
|
|
6 | 6 | import java.awt.event.KeyEvent; |
7 | 7 | import java.util.ArrayList; |
8 | 8 | import java.util.Arrays; |
| 9 | import java.util.Collections; |
9 | 10 | import java.util.HashMap; |
10 | | import java.util.LinkedHashMap; |
11 | 11 | import java.util.LinkedList; |
12 | 12 | import java.util.List; |
13 | 13 | import java.util.Map; |
| 14 | import java.util.Optional; |
| 15 | import java.util.concurrent.CopyOnWriteArrayList; |
14 | 16 | |
15 | 17 | import javax.swing.AbstractAction; |
16 | 18 | import javax.swing.AbstractButton; |
… |
… |
public String toString() {
|
267 | 269 | /////////////////////////////// |
268 | 270 | |
269 | 271 | // here we store our shortcuts |
270 | | private static Map<String, Shortcut> shortcuts = new LinkedHashMap<>(); |
| 272 | private static List<Shortcut> shortcuts = new CopyOnWriteArrayList<>(); |
271 | 273 | |
272 | 274 | // and here our modifier groups |
273 | 275 | private static Map<Integer, Integer> groups = new HashMap<>(); |
274 | 276 | |
275 | 277 | // 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 | */ |
276 | 285 | 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) { |
277 | 291 | 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 | |
284 | 297 | } |
285 | 298 | |
286 | 299 | /** |
… |
… |
public static Shortcut findShortcut(int requestedKey, int modifier) {
|
288 | 301 | * @return a list of all shortcuts |
289 | 302 | */ |
290 | 303 | 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 Collections.unmodifiableList(shortcuts); |
298 | 305 | } |
299 | 306 | |
300 | 307 | /** None group: used with KeyEvent.CHAR_UNDEFINED if no shortcut is defined */ |
… |
… |
private static void doInit() {
|
353 | 360 | for (Shortcut sc : newshortcuts) { |
354 | 361 | if (sc.isAssignedUser() |
355 | 362 | && findShortcut(sc.getAssignedKey(), sc.getAssignedModifier()) == null) { |
356 | | shortcuts.put(sc.getShortText(), sc); |
| 363 | shortcuts.add(sc); |
357 | 364 | } |
358 | 365 | } |
359 | 366 | // Shortcuts at their default values |
360 | 367 | for (Shortcut sc : newshortcuts) { |
361 | 368 | if (!sc.isAssignedUser() && sc.isAssignedDefault() |
362 | 369 | && findShortcut(sc.getAssignedKey(), sc.getAssignedModifier()) == null) { |
363 | | shortcuts.put(sc.getShortText(), sc); |
| 370 | shortcuts.add(sc); |
364 | 371 | } |
365 | 372 | } |
366 | 373 | // Shortcuts that were automatically moved |
367 | 374 | for (Shortcut sc : newshortcuts) { |
368 | 375 | if (!sc.isAssignedUser() && !sc.isAssignedDefault() |
369 | 376 | && findShortcut(sc.getAssignedKey(), sc.getAssignedModifier()) == null) { |
370 | | shortcuts.put(sc.getShortText(), sc); |
| 377 | shortcuts.add(sc); |
371 | 378 | } |
372 | 379 | } |
373 | 380 | } |
… |
… |
private static int findModifier(int group, Integer modifier) {
|
392 | 399 | // shutdown handling |
393 | 400 | public static boolean savePrefs() { |
394 | 401 | boolean changed = false; |
395 | | for (Shortcut sc : shortcuts.values()) { |
| 402 | for (Shortcut sc : shortcuts) { |
396 | 403 | changed = changed | sc.save(); |
397 | 404 | } |
398 | 405 | return changed; |
… |
… |
public static boolean savePrefs() {
|
410 | 417 | * @return the system shortcut |
411 | 418 | */ |
412 | 419 | 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) { |
| 420 | final Optional<Shortcut> existing = findShortcutByKeyOrShortText(key, modifier, shortText); |
| 421 | if (existing.isPresent() && shortText.equals(existing.get().getShortText())) { |
| 422 | return existing.get(); |
| 423 | } else if (existing.isPresent()) { |
417 | 424 | // this always is a logic error in the hook |
418 | | Main.error("CONFLICT WITH SYSTEM KEY "+shortText+": "+potentialShortcut); |
| 425 | Main.error("CONFLICT WITH SYSTEM KEY " + shortText + ": " + existing.get()); |
419 | 426 | return null; |
420 | 427 | } |
421 | | potentialShortcut = new Shortcut(shortText, longText, key, RESERVED, key, modifier, true, false); |
422 | | shortcuts.put(shortText, potentialShortcut); |
423 | | return potentialShortcut; |
| 428 | final Shortcut shortcut = new Shortcut(shortText, longText, key, RESERVED, key, modifier, true, false); |
| 429 | shortcuts.add(shortcut); |
| 430 | return shortcut; |
424 | 431 | } |
425 | 432 | |
426 | 433 | /** |
… |
… |
public static Shortcut registerShortcut(String shortText, String longText, int r
|
446 | 453 | // and now the workhorse. same parameters as above, just one more |
447 | 454 | private static Shortcut registerShortcut(String shortText, String longText, int requestedKey, int requestedGroup, Integer modifier) { |
448 | 455 | doInit(); |
449 | | if (shortcuts.containsKey(shortText)) { // a re-register? maybe a sc already read from the preferences? |
450 | | Shortcut sc = shortcuts.get(shortText); |
| 456 | Integer defaultModifier = findModifier(requestedGroup, modifier); |
| 457 | final Optional<Shortcut> existing = findShortcutByKeyOrShortText(requestedKey, defaultModifier, shortText); |
| 458 | if (existing.isPresent() && shortText.equals(existing.get().getShortText())) { |
| 459 | // a re-register? maybe a sc already read from the preferences? |
| 460 | final Shortcut sc = existing.get(); |
451 | 461 | sc.setLongText(longText); // or set by the platformHook, in this case the original longText doesn't match the real action |
452 | 462 | sc.saveDefault(); |
453 | 463 | return sc; |
454 | | } |
455 | | Integer defaultModifier = findModifier(requestedGroup, modifier); |
456 | | Shortcut conflict = findShortcut(requestedKey, defaultModifier); |
457 | | if (conflict != null) { |
| 464 | } else if (existing.isPresent()) { |
| 465 | final Shortcut conflict = existing.get(); |
458 | 466 | if (Main.isPlatformOsx()) { |
459 | 467 | // Try to reassign Meta to Ctrl |
460 | 468 | int newmodifier = findNewOsxModifier(requestedGroup); |
… |
… |
private static Shortcut registerShortcut(String shortText, String longText, int
|
476 | 484 | } else { |
477 | 485 | Shortcut newsc = new Shortcut(shortText, longText, requestedKey, requestedGroup, requestedKey, defaultModifier, true, false); |
478 | 486 | newsc.saveDefault(); |
479 | | shortcuts.put(shortText, newsc); |
| 487 | shortcuts.add(newsc); |
480 | 488 | return newsc; |
481 | 489 | } |
482 | 490 | |
… |
… |
private static Shortcut reassignShortcut(String shortText, String longText, int
|
499 | 507 | Main.info(tr("Silent shortcut conflict: ''{0}'' moved by ''{1}'' to ''{2}''.", |
500 | 508 | shortText, conflict.getShortText(), newsc.getKeyText())); |
501 | 509 | newsc.saveDefault(); |
502 | | shortcuts.put(shortText, newsc); |
| 510 | shortcuts.replaceAll(sc -> shortText.equals(sc.getShortText()) ? newsc : sc); |
503 | 511 | return newsc; |
504 | 512 | } |
505 | 513 | |
… |
… |
private static Shortcut reassignShortcut(String shortText, String longText, int
|
511 | 519 | * @return the platform specific key stroke for the 'Copy' command |
512 | 520 | */ |
513 | 521 | public static KeyStroke getCopyKeyStroke() { |
514 | | Shortcut sc = shortcuts.get("system:copy"); |
515 | | if (sc == null) return null; |
516 | | return sc.getKeyStroke(); |
| 522 | return getKeyStrokeForShortKey("system:copy"); |
517 | 523 | } |
518 | 524 | |
519 | 525 | /** |
… |
… |
public static KeyStroke getCopyKeyStroke() {
|
524 | 530 | * @return the platform specific key stroke for the 'Paste' command |
525 | 531 | */ |
526 | 532 | public static KeyStroke getPasteKeyStroke() { |
527 | | Shortcut sc = shortcuts.get("system:paste"); |
528 | | if (sc == null) return null; |
529 | | return sc.getKeyStroke(); |
| 533 | return getKeyStrokeForShortKey("system:paste"); |
530 | 534 | } |
531 | 535 | |
532 | 536 | /** |
… |
… |
public static KeyStroke getPasteKeyStroke() {
|
537 | 541 | * @return the platform specific key stroke for the 'Cut' command |
538 | 542 | */ |
539 | 543 | public static KeyStroke getCutKeyStroke() { |
540 | | Shortcut sc = shortcuts.get("system:cut"); |
541 | | if (sc == null) return null; |
542 | | return sc.getKeyStroke(); |
| 544 | return getKeyStrokeForShortKey("system:cut"); |
| 545 | } |
| 546 | |
| 547 | private static KeyStroke getKeyStrokeForShortKey(String shortKey) { |
| 548 | return shortcuts.stream() |
| 549 | .filter(sc -> shortKey.equals(sc.getShortText())) |
| 550 | .findAny() |
| 551 | .map(Shortcut::getKeyStroke) |
| 552 | .orElse(null); |
543 | 553 | } |
544 | 554 | } |