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.io.IOException; 7 import java.util.List; 8 import java.util.Set; 9 10 import org.unicode.cldr.draft.keyboard.KeyboardId.Platform; 11 12 import com.google.common.base.Charsets; 13 import com.google.common.base.Splitter; 14 import com.google.common.collect.ImmutableCollection; 15 import com.google.common.collect.ImmutableList; 16 import com.google.common.collect.ImmutableMultimap; 17 import com.google.common.collect.Iterables; 18 import com.google.common.collect.Sets; 19 import com.google.common.io.Resources; 20 import com.ibm.icu.util.ULocale; 21 22 public final class KeyboardIdMap { 23 private final ImmutableMultimap<String, KeyboardId> nameToKeyboardId; 24 // Internal only. 25 private final Set<String> coveredNames; 26 KeyboardIdMap(ImmutableMultimap<String, KeyboardId> nameToKeyboardId)27 private KeyboardIdMap(ImmutableMultimap<String, KeyboardId> nameToKeyboardId) { 28 this.nameToKeyboardId = checkNotNull(nameToKeyboardId); 29 coveredNames = Sets.newHashSet(); 30 } 31 32 private static final Splitter LINE_SPLITTER = Splitter.on("\n").omitEmptyStrings(); 33 private static final Splitter COMMA_SPLITTER = Splitter.on(","); 34 private static final Splitter DASH_SPLITTER = Splitter.on("-").omitEmptyStrings(); 35 36 /** 37 * Creates the mapping from csv contents. The first line must contain the column headers 38 * "name,locale,attributes". 39 */ fromCsv(String csv, Platform platform)40 public static KeyboardIdMap fromCsv(String csv, Platform platform) { 41 checkArgument(!csv.isEmpty()); 42 List<String> lines = LINE_SPLITTER.splitToList(csv); 43 checkArgument(lines.get(0).equals("name,locale,attributes"), "Missing csv headers"); 44 ImmutableMultimap.Builder<String, KeyboardId> builder = ImmutableMultimap.builder(); 45 for (String line : Iterables.skip(lines, 1)) { 46 // The first element may be between quotes (if it includes a comma), if so parse it manually. 47 String name; 48 int closingQuote = line.startsWith("\"") ? line.indexOf("\"", 1) : 0; 49 List<String> components = COMMA_SPLITTER.splitToList(line.substring(closingQuote)); 50 if (closingQuote != 0) { 51 name = line.substring(1, closingQuote); 52 } else { 53 name = components.get(0); 54 } 55 ULocale locale = ULocale.forLanguageTag(components.get(1)); 56 ImmutableList<String> attributes = ImmutableList.copyOf(DASH_SPLITTER.splitToList(components.get(2))); 57 builder.put(name, KeyboardId.of(locale, platform, attributes)); 58 } 59 return new KeyboardIdMap(builder.build()); 60 } 61 62 /** Retrieves the csv file relative to the class given. */ fromResource(Class<?> clazz, String fileName, Platform platform)63 public static KeyboardIdMap fromResource(Class<?> clazz, String fileName, Platform platform) { 64 try { 65 String csv = Resources.toString(Resources.getResource(clazz, fileName), 66 Charsets.UTF_8); 67 return fromCsv(csv, platform); 68 } catch (IOException e) { 69 throw new IllegalArgumentException(e); 70 } 71 } 72 getKeyboardId(String name)73 public ImmutableCollection<KeyboardId> getKeyboardId(String name) { 74 coveredNames.add(name); 75 ImmutableCollection<KeyboardId> ids = nameToKeyboardId.get(name); 76 checkArgument(ids.size() > 0, "No keyboard id for %s [%s]", name, nameToKeyboardId); 77 return ids; 78 } 79 unmatchedIds()80 public Set<String> unmatchedIds() { 81 return Sets.difference(nameToKeyboardId.keySet(), coveredNames); 82 } 83 } 84