001    /*
002     * Created on Mar 26, 2008
003     *
004     * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
005     * the License. You may obtain a copy of the License at
006     *
007     * http://www.apache.org/licenses/LICENSE-2.0
008     *
009     * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
010     * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
011     * specific language governing permissions and limitations under the License.
012     *
013     * Copyright @2008-2010 the original author or authors.
014     */
015    package org.fest.swing.keystroke;
016    
017    import static java.awt.event.InputEvent.SHIFT_MASK;
018    import static java.awt.event.KeyEvent.CHAR_UNDEFINED;
019    import static org.fest.swing.util.Platform.osFamily;
020    
021    import java.util.Locale;
022    
023    import javax.swing.KeyStroke;
024    
025    import org.fest.util.VisibleForTesting;
026    
027    /**
028     * Understands a collection of <code>{@link KeyStrokeMapping}</code>.
029     *
030     * @author Yvonne Wang
031     * @author Alex Ruiz
032     */
033    public class KeyStrokeMap {
034    
035      private static KeyStrokeMapCollection maps = new KeyStrokeMapCollection();
036    
037      static {
038        reloadFromSystemSettings();
039      }
040    
041      /**
042       * Reloads the key stroke mappings for the language from the default locale.
043       * @deprecated use <code>{@link #reloadFromSystemSettings()}</code> instead.
044       */
045      @Deprecated
046      public static void reloadFromLocale() {
047        reloadFromSystemSettings();
048      }
049    
050      /**
051       * Reloads the key stroke mappings for the language using the current system settings.
052       * @since 1.2
053       */
054      public static void reloadFromSystemSettings() {
055        KeyStrokeMappingProviderPicker picker = new KeyStrokeMappingProviderPicker();
056        maps.clear();
057        addKeyStrokesFrom(picker.providerFor(osFamily(), Locale.getDefault()));
058      }
059    
060      @VisibleForTesting
061      static void updateKeyStrokeMapCollection(KeyStrokeMapCollection c) {
062        maps = c;
063      }
064    
065      /**
066       * Adds the collection of <code>{@link KeyStrokeMapping}</code>s from the given
067       * <code>{@link KeyStrokeMappingProvider}</code> to this map.
068       * @param provider the given <code>KeyStrokeMappingProvider</code>.
069       */
070      public static void addKeyStrokesFrom(KeyStrokeMappingProvider provider) {
071        for (KeyStrokeMapping entry : provider.keyStrokeMappings())
072          add(entry.character(), entry.keyStroke());
073      }
074    
075      private static void add(Character character, KeyStroke keyStroke) {
076        maps.add(character, keyStroke);
077      }
078    
079      /**
080       * Removes all the character-<code>{@link KeyStroke}</code> mappings.
081       */
082      public static void clearKeyStrokes() {
083        maps.clear();
084      }
085    
086      /**
087       * Indicates whether <code>{@link KeyStrokeMap}</code> has mappings or not.
088       * @return <code>true</code> if it has mappings, <code>false</code> otherwise.
089       */
090      public static boolean hasKeyStrokes() {
091        return !maps.isEmpty();
092      }
093    
094      /**
095       * Returns the <code>{@link KeyStroke}</code> corresponding to the given character, as best we can guess it, or
096       * <code>null</code> if we don't know how to generate it.
097       * @param character the given character.
098       * @return the key code-based <code>KeyStroke</code> corresponding to the given character, or <code>null</code> if
099       * we cannot generate it.
100       */
101      public static KeyStroke keyStrokeFor(char character) {
102        return maps.keyStrokeFor(character);
103      }
104    
105      /**
106       * Given a <code>{@link KeyStroke}</code>, returns the equivalent character. Key strokes are defined properly for
107       * US keyboards only. To contribute your own, please add them using the method
108       * <code>{@link #addKeyStrokesFrom(KeyStrokeMappingProvider)}</code>.
109       * @param keyStroke the given <code>KeyStroke</code>.
110       * @return KeyEvent.VK_UNDEFINED if the result is unknown.
111       */
112      public static char charFor(KeyStroke keyStroke) {
113        Character character = maps.charFor(keyStroke);
114        // Try again, but strip all modifiers but shift
115        if (character == null) character = charWithoutModifiersButShift(keyStroke);
116        if (character == null) return CHAR_UNDEFINED;
117        return character.charValue();
118      }
119    
120      private static Character charWithoutModifiersButShift(KeyStroke keyStroke) {
121        int mask = keyStroke.getModifiers() & ~SHIFT_MASK;
122        return maps.charFor(KeyStroke.getKeyStroke(keyStroke.getKeyCode(), mask));
123      }
124    
125      private KeyStrokeMap() {}
126    }