Home | History | Annotate | Download | only in keyboard
      1 package org.unicode.cldr.draft.keyboard;
      2 
      3 import static com.google.common.base.Preconditions.checkArgument;
      4 import static com.google.common.base.Preconditions.checkNotNull;
      5 
      6 import java.util.Collection;
      7 import java.util.Comparator;
      8 import java.util.List;
      9 import java.util.Map;
     10 import java.util.Map.Entry;
     11 import java.util.Set;
     12 
     13 import com.google.common.collect.ArrayListMultimap;
     14 import com.google.common.collect.HashBasedTable;
     15 import com.google.common.collect.ImmutableList;
     16 import com.google.common.collect.ImmutableSet;
     17 import com.google.common.collect.ImmutableSortedSet;
     18 import com.google.common.collect.ListMultimap;
     19 import com.google.common.collect.Maps;
     20 import com.google.common.collect.Table;
     21 import com.ibm.icu.text.Collator;
     22 
     23 /** Builder class to assist in constructing a keyboard object. */
     24 public final class KeyboardBuilder {
     25     private final ImmutableSet.Builder<KeyboardId> keyboardIds;
     26     private final ImmutableList.Builder<String> names;
     27     private final Map<String, String> transformSequenceToOutput;
     28     private final Table<ModifierKeyCombination, IsoLayoutPosition, CharacterMap> modifierAndPositionToCharacter;
     29 
     30     public KeyboardBuilder() {
     31         keyboardIds = ImmutableSet.builder();
     32         names = ImmutableList.builder();
     33         transformSequenceToOutput = Maps.newHashMap();
     34         modifierAndPositionToCharacter = HashBasedTable.create();
     35     }
     36 
     37     public KeyboardBuilder addKeyboardIds(Iterable<KeyboardId> keyboardIds) {
     38         this.keyboardIds.addAll(keyboardIds);
     39         return this;
     40     }
     41 
     42     public KeyboardBuilder addName(String name) {
     43         names.add(name);
     44         return this;
     45     }
     46 
     47     public KeyboardBuilder addTransform(String sequence, String output) {
     48         if (transformSequenceToOutput.containsKey(sequence)
     49             && !transformSequenceToOutput.get(sequence).equals(output)) {
     50             String errorMessage = String.format("Duplicate entry for [%s:%s]", sequence, output);
     51             throw new IllegalArgumentException(errorMessage);
     52         }
     53         transformSequenceToOutput.put(sequence, output);
     54         return this;
     55     }
     56 
     57     public KeyboardBuilder addCharacterMap(
     58         ModifierKeyCombination combination, CharacterMap characterMap) {
     59         checkNotNull(combination);
     60         if (modifierAndPositionToCharacter.contains(combination, characterMap.position())) {
     61             CharacterMap existing = modifierAndPositionToCharacter.get(combination, characterMap.position());
     62             checkArgument(
     63                 existing.equals(characterMap),
     64                 "Duplicate entry for [%s:%s:%s]",
     65                 combination,
     66                 characterMap,
     67                 existing);
     68         }
     69         modifierAndPositionToCharacter.put(combination, characterMap.position(), characterMap);
     70         return this;
     71     }
     72 
     73     public KeyboardBuilder addCharacterMap(
     74         Collection<ModifierKeyCombination> combinations, CharacterMap characterMap) {
     75         for (ModifierKeyCombination combination : combinations) {
     76             addCharacterMap(combination, characterMap);
     77         }
     78         return this;
     79     }
     80 
     81     public ImmutableList<Keyboard> build() {
     82         ImmutableSet<KeyboardId> keyboardIds = this.keyboardIds.build();
     83         checkArgument(keyboardIds.size() > 0, "KeyboardIds must contain at least one element");
     84         // See if key map consolidation is possible.
     85         ListMultimap<ImmutableSet<CharacterMap>, ModifierKeyCombination> charactersToCombinations = ArrayListMultimap.create();
     86         for (ModifierKeyCombination combination : modifierAndPositionToCharacter.rowKeySet()) {
     87             Collection<CharacterMap> characterMaps = modifierAndPositionToCharacter.row(combination).values();
     88             charactersToCombinations.put(ImmutableSet.copyOf(characterMaps), combination);
     89         }
     90         // Build the key maps.
     91         KeyboardId id = keyboardIds.iterator().next();
     92         ImmutableSortedSet.Builder<KeyMap> keyMaps = ImmutableSortedSet.naturalOrder();
     93         for (ImmutableSet<CharacterMap> characterMaps : charactersToCombinations.keySet()) {
     94             List<ModifierKeyCombination> combinations = charactersToCombinations.get(characterMaps);
     95             ModifierKeyCombinationSet combinationSet = ModifierKeyCombinationSet.of(ImmutableSet.copyOf(combinations));
     96             keyMaps.add(KeyMap.of(combinationSet, characterMaps));
     97         }
     98         // Add the transforms.
     99         ImmutableSortedSet.Builder<Transform> transforms = ImmutableSortedSet.orderedBy(collatorComparator(Collator.getInstance(id.locale())));
    100         for (Entry<String, String> transformEntry : transformSequenceToOutput.entrySet()) {
    101             transforms.add(Transform.of(transformEntry.getKey(), transformEntry.getValue()));
    102         }
    103         ImmutableList.Builder<Keyboard> keyboards = ImmutableList.builder();
    104         for (KeyboardId keyboardId : keyboardIds) {
    105             keyboards.add(Keyboard.of(keyboardId, names.build(), keyMaps.build(), transforms.build()));
    106         }
    107         return keyboards.build();
    108     }
    109 
    110     public Set<String> transformSequences() {
    111         return transformSequenceToOutput.keySet();
    112     }
    113 
    114     private static Comparator<Transform> collatorComparator(final Collator collator) {
    115         return new Comparator<Transform>() {
    116             @Override
    117             public int compare(Transform o1, Transform o2) {
    118                 return collator.compare(o1.sequence(), o2.sequence());
    119             }
    120         };
    121     }
    122 }
    123