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 KeyboardBuilder()30 public KeyboardBuilder() { 31 keyboardIds = ImmutableSet.builder(); 32 names = ImmutableList.builder(); 33 transformSequenceToOutput = Maps.newHashMap(); 34 modifierAndPositionToCharacter = HashBasedTable.create(); 35 } 36 addKeyboardIds(Iterable<KeyboardId> keyboardIds)37 public KeyboardBuilder addKeyboardIds(Iterable<KeyboardId> keyboardIds) { 38 this.keyboardIds.addAll(keyboardIds); 39 return this; 40 } 41 addName(String name)42 public KeyboardBuilder addName(String name) { 43 names.add(name); 44 return this; 45 } 46 addTransform(String sequence, String output)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 addCharacterMap( ModifierKeyCombination combination, CharacterMap characterMap)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 addCharacterMap( Collection<ModifierKeyCombination> combinations, CharacterMap characterMap)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 build()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 transformSequences()110 public Set<String> transformSequences() { 111 return transformSequenceToOutput.keySet(); 112 } 113 collatorComparator(final Collator collator)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