Ignore:
Timestamp:
2012-02-17T23:07:13+01:00 (12 years ago)
Author:
stoecker
Message:

rework Shortcut handling a bit more, replace conflict handling with 'move out of way' to fix cascading conflicts, drop old group names for more descriptive names, sadly this deprecates the old group values again :-(

File:
1 edited

Legend:

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

    r4956 r4971  
    3737 */
    3838public class Shortcut {
    39     @Deprecated
    40     public static final int SHIFT_DEFAULT = 1;
    4139    private String shortText;        // the unique ID of the shortcut
    4240    private String longText;         // a human readable description that will be shown in the preferences
     
    160158    private boolean isSame(int isKey, int isModifier) {
    161159        // -1 --- an unassigned shortcut is different from any other shortcut
    162         return( isKey == assignedKey && isModifier == assignedModifier && assignedModifier != getGroupModifier(GROUP_NONE));
     160        return( isKey == assignedKey && isModifier == assignedModifier && assignedModifier != getGroupModifier(NONE));
    163161    }
    164162
     
    176174    }
    177175
    178     private void saveDefault(int modifier) {
     176    private void saveDefault() {
    179177        Main.pref.getCollection("shortcut.entry."+shortText, Arrays.asList(new String[]{longText,
    180178        String.valueOf(requestedKey), String.valueOf(requestedGroup), String.valueOf(requestedKey),
    181         String.valueOf(modifier), String.valueOf(true), String.valueOf(false)}));
     179        String.valueOf(getGroupModifier(requestedGroup)), String.valueOf(true), String.valueOf(false)}));
    182180    }
    183181
     
    246244
    247245    // and here our modifier groups
    248     private static Map<Integer, Integer> groups;
     246    private static Map<Integer, Integer> groups= new HashMap<Integer, Integer>();
    249247
    250248    // check if something collides with an existing shortcut
     
    273271    }
    274272
    275     // try to find an unused shortcut
    276     private static Shortcut findRandomShortcut(String shortText, String longText, int requestedKey, int requestedGroup) {
    277         int[] mods = {getGroupModifier(requestedGroup + GROUPS_DEFAULT), getGroupModifier(requestedGroup + GROUPS_ALT1), getGroupModifier(requestedGroup + GROUPS_ALT2)};
    278         for (int m : mods) {
    279             for (int k = KeyEvent.VK_A; k < KeyEvent.VK_Z; k++) { // we'll limit ourself to 100% safe keys
    280                 if ( findShortcut(k, m) == null )
    281                     return new Shortcut(shortText, longText, requestedKey, requestedGroup, k, m, false, false);
    282             }
    283         }
    284         return new Shortcut(shortText, longText, requestedKey, requestedGroup, requestedKey, getGroupModifier(GROUP_NONE), false, false);
    285     }
    286 
    287     // use these constants to request shortcuts
    288     /**
    289      * no shortcut.
    290      */
    291     public static final int GROUP_NONE = 0;
    292     /**
    293      * a button action, will use another modifier than MENU on system with a meta key.
    294      */
    295     public static final int GROUP_HOTKEY = 1;
    296     /**
    297      * a menu action, e.g. "ctrl-e" (export).
    298      */
    299     public static final int GROUP_MENU = 2;
    300     /**
    301      * direct edit key, e.g. "a" (add).
    302      */
    303     public static final int GROUP_EDIT = 3;
    304     /**
    305      * toggle one of the right-hand-side windows, e.g. "alt-l" (layers).
    306      */
    307     public static final int GROUP_LAYER = 4;
    308     /**
    309      * for non-letter keys, preferable without modifier, e.g. F5.
    310      */
    311     public static final int GROUP_DIRECT = 5;
    312     /**
    313      * for use with {@see #setMnemonic} only!
    314      */
    315     public static final int GROUP_MNEMONIC = 6;
    316     /**
    317      * for direct access, with alt modifier.
    318      */
    319     public static final int GROUP_DIRECT2 = 7;
    320     /**
    321      * for direct access, remaining modifiers.
    322      */
    323     public static final int GROUP_DIRECT3 = 8;
    324     public static final int GROUP_RESERVED = 1000;
    325     public static final int GROUPS_DEFAULT = 0;
    326     public static final int GROUPS_ALT1 = 100;
    327     public static final int GROUPS_ALT2 = 200;
     273    public static final int NONE = 5000;
     274    public static final int MNEMONIC = 5001;
     275    public static final int RESERVED = 5002;
     276    public static final int DIRECT = 5003;
     277    public static final int ALT = 5004;
     278    public static final int SHIFT = 5005;
     279    public static final int CTRL = 5006;
     280    public static final int ALT_SHIFT = 5007;
     281    public static final int ALT_CTRL = 5008;
     282    public static final int CTRL_SHIFT = 5009;
     283    public static final int ALT_CTRL_SHIFT = 5010;
     284
     285    /* old */
     286    @Deprecated public static final int GROUP_NONE = 0;
     287    @Deprecated public static final int GROUP_HOTKEY = 1;
     288    @Deprecated public static final int GROUP_MENU = 2;
     289    @Deprecated public static final int GROUP_EDIT = 3;
     290    @Deprecated public static final int GROUP_LAYER = 4;
     291    @Deprecated public static final int GROUP_DIRECT = 5;
     292    @Deprecated public static final int GROUP_MNEMONIC = 6;
     293    @Deprecated public static final int GROUP_DIRECT2 = 7;
     294    @Deprecated public static final int GROUP_DIRECT3 = 8;
     295    @Deprecated public static final int GROUPS_DEFAULT = 0;
     296    @Deprecated public static final int GROUPS_ALT1 = 100;
     297    @Deprecated public static final int GROUPS_ALT2 = 200;
     298    @Deprecated public static final int SHIFT_DEFAULT = 1;
    328299
    329300    // bootstrap
     
    332303        if (initdone) return;
    333304        initdone = true;
    334         groups = Main.platform.initShortcutGroups(true);
     305        groups.put(NONE, -1);
     306        groups.put(MNEMONIC, KeyEvent.ALT_DOWN_MASK);
     307        groups.put(DIRECT, 0);
     308        groups.put(ALT, KeyEvent.ALT_DOWN_MASK);
     309        groups.put(SHIFT, KeyEvent.SHIFT_DOWN_MASK);
     310        groups.put(CTRL, KeyEvent.CTRL_DOWN_MASK);
     311        groups.put(ALT_SHIFT, KeyEvent.ALT_DOWN_MASK|KeyEvent.SHIFT_DOWN_MASK);
     312        groups.put(ALT_CTRL, KeyEvent.ALT_DOWN_MASK|KeyEvent.CTRL_DOWN_MASK);
     313        groups.put(CTRL_SHIFT, KeyEvent.CTRL_DOWN_MASK|KeyEvent.SHIFT_DOWN_MASK);
     314        groups.put(ALT_CTRL_SHIFT, KeyEvent.ALT_DOWN_MASK|KeyEvent.CTRL_DOWN_MASK|KeyEvent.SHIFT_DOWN_MASK);
     315
     316        /* old */
     317        groups.put(GROUPS_DEFAULT+GROUP_NONE,    -1);
     318        groups.put(GROUPS_DEFAULT+GROUP_HOTKEY,  KeyEvent.CTRL_DOWN_MASK);
     319        groups.put(GROUPS_DEFAULT+GROUP_MENU,    KeyEvent.CTRL_DOWN_MASK);
     320        groups.put(GROUPS_DEFAULT+GROUP_EDIT,    0);
     321        groups.put(GROUPS_DEFAULT+GROUP_LAYER,   KeyEvent.ALT_DOWN_MASK);
     322        groups.put(GROUPS_DEFAULT+GROUP_DIRECT,  0);
     323        groups.put(GROUPS_DEFAULT+GROUP_MNEMONIC,KeyEvent.ALT_DOWN_MASK);
     324        groups.put(GROUPS_DEFAULT+GROUP_DIRECT2, KeyEvent.ALT_DOWN_MASK);
     325        groups.put(GROUPS_DEFAULT+GROUP_DIRECT3, KeyEvent.CTRL_DOWN_MASK | KeyEvent.SHIFT_DOWN_MASK);
     326
     327        groups.put(GROUPS_ALT1+GROUP_NONE,       -1);
     328        groups.put(GROUPS_ALT1+GROUP_HOTKEY,     KeyEvent.CTRL_DOWN_MASK | KeyEvent.SHIFT_DOWN_MASK);
     329        groups.put(GROUPS_ALT1+GROUP_MENU,       KeyEvent.CTRL_DOWN_MASK | KeyEvent.SHIFT_DOWN_MASK);
     330        groups.put(GROUPS_ALT1+GROUP_EDIT,       KeyEvent.SHIFT_DOWN_MASK);
     331        groups.put(GROUPS_ALT1+GROUP_LAYER,      KeyEvent.ALT_DOWN_MASK  | KeyEvent.SHIFT_DOWN_MASK);
     332        groups.put(GROUPS_ALT1+GROUP_DIRECT,     KeyEvent.SHIFT_DOWN_MASK);
     333        groups.put(GROUPS_ALT1+GROUP_MNEMONIC,   KeyEvent.ALT_DOWN_MASK);
     334        groups.put(GROUPS_ALT1+GROUP_DIRECT2,    KeyEvent.ALT_DOWN_MASK  | KeyEvent.SHIFT_DOWN_MASK);
     335        groups.put(GROUPS_ALT1+GROUP_DIRECT3,    KeyEvent.ALT_DOWN_MASK  | KeyEvent.CTRL_DOWN_MASK | KeyEvent.SHIFT_DOWN_MASK);
     336
     337        groups.put(GROUPS_ALT2+GROUP_NONE,       -1);
     338        groups.put(GROUPS_ALT2+GROUP_HOTKEY,     KeyEvent.CTRL_DOWN_MASK | KeyEvent.ALT_DOWN_MASK);
     339        groups.put(GROUPS_ALT2+GROUP_MENU,       KeyEvent.CTRL_DOWN_MASK | KeyEvent.ALT_DOWN_MASK);
     340        groups.put(GROUPS_ALT2+GROUP_EDIT,       KeyEvent.ALT_DOWN_MASK  | KeyEvent.SHIFT_DOWN_MASK);
     341        groups.put(GROUPS_ALT2+GROUP_LAYER,      KeyEvent.SHIFT_DOWN_MASK);
     342        groups.put(GROUPS_ALT2+GROUP_DIRECT,     KeyEvent.CTRL_DOWN_MASK);
     343        groups.put(GROUPS_ALT2+GROUP_MNEMONIC,   KeyEvent.ALT_DOWN_MASK);
     344        groups.put(GROUPS_ALT2+GROUP_DIRECT2,    KeyEvent.ALT_DOWN_MASK  | KeyEvent.CTRL_DOWN_MASK);
     345        groups.put(GROUPS_ALT2+GROUP_DIRECT3,    KeyEvent.META_DOWN_MASK | KeyEvent.CTRL_DOWN_MASK);
     346
    335347        // (1) System reserved shortcuts
    336348        Main.platform.initSystemShortcuts();
     
    401413            return null;
    402414        }
    403         potentialShortcut = new Shortcut(shortText, longText, key, GROUP_RESERVED, key, modifier, true, false);
     415        potentialShortcut = new Shortcut(shortText, longText, key, RESERVED, key, modifier, true, false);
    404416        shortcuts.put(shortText, potentialShortcut);
    405417        return potentialShortcut;
     
    458470        }
    459471        else if (defaultModifier == null) { // garbage in, no shortcut out
    460             defaultModifier = getGroupModifier(GROUP_NONE + GROUPS_DEFAULT);
     472            defaultModifier = getGroupModifier(NONE);
    461473        }
    462474        return defaultModifier;
    463475    }
    464476
     477    private static int[] mods = {ALT_CTRL, ALT_SHIFT, CTRL_SHIFT, ALT_CTRL_SHIFT};
     478    private static int[] keys = {KeyEvent.VK_F1, KeyEvent.VK_F2, KeyEvent.VK_F3, KeyEvent.VK_F4,
     479                                 KeyEvent.VK_F5, KeyEvent.VK_F6, KeyEvent.VK_F7, KeyEvent.VK_F8,
     480                                 KeyEvent.VK_F9, KeyEvent.VK_F10, KeyEvent.VK_F11, KeyEvent.VK_F12};
    465481    // and now the workhorse. same parameters as above, just one more: if originalShortcut is not null and
    466482    // is different from the shortcut that will be assigned, a popup warning will be displayed to the user.
     
    475491            Shortcut sc = shortcuts.get(shortText);
    476492            sc.setLongText(longText); // or set by the platformHook, in this case the original longText doesn't match the real action
    477             sc.saveDefault(defaultModifier);
     493            sc.saveDefault();
    478494            return sc;
    479495        }
    480         Shortcut conflictsWith = null;
    481         Shortcut potentialShortcut = findShortcut(requestedKey, defaultModifier);
    482         if (potentialShortcut != null) { // 3 stage conflict handling
    483             conflictsWith = potentialShortcut;
    484             defaultModifier = getGroupModifier(requestedGroup + GROUPS_ALT1);
    485             if (defaultModifier == null) { // garbage in, no shortcut out
    486                 defaultModifier = getGroupModifier(GROUP_NONE + GROUPS_DEFAULT);
    487             }
    488             potentialShortcut = findShortcut(requestedKey, defaultModifier);
    489             if (potentialShortcut != null) {
    490                 defaultModifier = getGroupModifier(requestedGroup + GROUPS_ALT2);
    491                 if (defaultModifier == null) { // garbage in, no shortcut out
    492                     defaultModifier = getGroupModifier(GROUP_NONE + GROUPS_DEFAULT);
     496        Shortcut conflict = findShortcut(requestedKey, defaultModifier);
     497        if (conflict != null) {
     498            for (int m : mods) {
     499                for (int k : keys) {
     500                    int newmodifier = getGroupModifier(m);
     501                    if ( findShortcut(k, m) == null ) {
     502                        Shortcut newsc = new Shortcut(shortText, longText, requestedKey, m, k, newmodifier, false, false);
     503                        System.out.println(tr("Silent shortcut conflict: ''{0}'' moved by ''{1}'' to ''{2}''.",
     504                            shortText, conflict.getShortText(), newsc.getKeyText()));
     505                        newsc.saveDefault();
     506                        shortcuts.put(shortText, newsc);
     507                        return newsc;
     508                    }
    493509                }
    494                 potentialShortcut = findShortcut(requestedKey, defaultModifier);
    495                 if (potentialShortcut != null) { // if all 3 modifiers for a group are used, we give up
    496                     potentialShortcut = findRandomShortcut(shortText, longText, requestedKey, requestedGroup);
    497                 } else {
    498                     potentialShortcut = new Shortcut(shortText, longText, requestedKey, requestedGroup, requestedKey, defaultModifier, false, false);
    499                 }
    500             } else {
    501                 potentialShortcut = new Shortcut(shortText, longText, requestedKey, requestedGroup, requestedKey, defaultModifier, false, false);
    502             }
    503             if (originalShortcut != null && !originalShortcut.isSame(potentialShortcut)) {
    504                 displayWarning(conflictsWith, potentialShortcut, shortText, longText);
    505             } else if (originalShortcut == null) {
    506                 System.out.println("Silent shortcut conflict: '"+shortText+"' moved by '"+conflictsWith.getShortText()+"' to '"+potentialShortcut.getKeyText()+"'.");
    507510            }
    508511        } else {
    509             potentialShortcut = new Shortcut(shortText, longText, requestedKey, requestedGroup, requestedKey, defaultModifier, true, false);
    510         }
    511 
    512         potentialShortcut.saveDefault(defaultModifier);
    513         shortcuts.put(shortText, potentialShortcut);
    514         return potentialShortcut;
    515     }
    516 
    517     // a lengthy warning message
    518     private static void displayWarning(Shortcut conflictsWith, Shortcut potentialShortcut, String shortText, String longText) {
    519         JOptionPane.showMessageDialog(Main.parent,
    520                 tr("Setting the keyboard shortcut ''{0}'' for the action ''{1}'' ({2}) failed\n"+
    521                         "because the shortcut is already taken by the action ''{3}'' ({4}).\n\n",
    522                         conflictsWith.getKeyText(), longText, shortText,
    523                         conflictsWith.getLongText(), conflictsWith.getShortText())+
    524                         (potentialShortcut.getKeyText().equals("") ?
    525                                 tr("This action will have no shortcut.\n\n")
    526                                 :
    527                                     tr("Using the shortcut ''{0}'' instead.\n\n", potentialShortcut.getKeyText())
    528                                 )+
    529                                 tr("(Hint: You can edit the shortcuts in the preferences.)"),
    530                                 tr("Error"),
    531                                 JOptionPane.ERROR_MESSAGE
    532                 );
     512            Shortcut newsc = new Shortcut(shortText, longText, requestedKey, requestedGroup, requestedKey, defaultModifier, true, false);
     513            newsc.saveDefault();
     514            shortcuts.put(shortText, newsc);
     515            return newsc;
     516        }
     517
     518        return null;
    533519    }
    534520
Note: See TracChangeset for help on using the changeset viewer.