1 /* GENERATED SOURCE. DO NOT MODIFY. */ 2 // 2016 and later: Unicode, Inc. and others. 3 // License & terms of use: http://www.unicode.org/copyright.html#License 4 /* 5 ******************************************************************************* 6 * Copyright (C) 2012-2016, Google, International Business Machines Corporation and 7 * others. All Rights Reserved. 8 ******************************************************************************* 9 */ 10 package android.icu.text; 11 12 import java.util.ArrayList; 13 import java.util.Arrays; 14 import java.util.Collection; 15 import java.util.Iterator; 16 import java.util.Locale; 17 18 import android.icu.impl.ICUCache; 19 import android.icu.impl.ICUData; 20 import android.icu.impl.ICUResourceBundle; 21 import android.icu.impl.SimpleCache; 22 import android.icu.impl.SimpleFormatterImpl; 23 import android.icu.util.ULocale; 24 import android.icu.util.UResourceBundle; 25 26 /** 27 * Immutable class for formatting a list, using data from CLDR (or supplied 28 * separately). The class is not subclassable. 29 * 30 * @author Mark Davis 31 */ 32 final public class ListFormatter { 33 // Compiled SimpleFormatter patterns. 34 private final String two; 35 private final String start; 36 private final String middle; 37 private final String end; 38 private final ULocale locale; 39 40 /** 41 * Indicates the style of Listformatter 42 * @deprecated This API is ICU internal only. 43 * @hide draft / provisional / internal are hidden on Android 44 */ 45 @Deprecated 46 public enum Style { 47 /** 48 * Standard style. 49 * @deprecated This API is ICU internal only. 50 * @hide draft / provisional / internal are hidden on Android 51 */ 52 @Deprecated 53 STANDARD("standard"), 54 /** 55 * Style for full durations 56 * @deprecated This API is ICU internal only. 57 * @hide draft / provisional / internal are hidden on Android 58 */ 59 @Deprecated 60 DURATION("unit"), 61 /** 62 * Style for durations in abbrevated form 63 * @deprecated This API is ICU internal only. 64 * @hide draft / provisional / internal are hidden on Android 65 */ 66 @Deprecated 67 DURATION_SHORT("unit-short"), 68 /** 69 * Style for durations in narrow form 70 * @deprecated This API is ICU internal only. 71 * @hide draft / provisional / internal are hidden on Android 72 */ 73 @Deprecated 74 DURATION_NARROW("unit-narrow"); 75 76 private final String name; 77 78 Style(String name) { 79 this.name = name; 80 } 81 /** 82 * @deprecated This API is ICU internal only. 83 * @hide draft / provisional / internal are hidden on Android 84 */ 85 @Deprecated 86 public String getName() { 87 return name; 88 } 89 90 } 91 92 /** 93 * <b>Internal:</b> Create a ListFormatter from component strings, 94 * with definitions as in LDML. 95 * 96 * @param two 97 * string for two items, containing {0} for the first, and {1} 98 * for the second. 99 * @param start 100 * string for the start of a list items, containing {0} for the 101 * first, and {1} for the rest. 102 * @param middle 103 * string for the start of a list items, containing {0} for the 104 * first part of the list, and {1} for the rest of the list. 105 * @param end 106 * string for the end of a list items, containing {0} for the 107 * first part of the list, and {1} for the last item. 108 * @deprecated This API is ICU internal only. 109 * @hide draft / provisional / internal are hidden on Android 110 */ 111 @Deprecated 112 public ListFormatter(String two, String start, String middle, String end) { 113 this( 114 compilePattern(two, new StringBuilder()), 115 compilePattern(start, new StringBuilder()), 116 compilePattern(middle, new StringBuilder()), 117 compilePattern(end, new StringBuilder()), 118 null); 119 } 120 121 private ListFormatter(String two, String start, String middle, String end, ULocale locale) { 122 this.two = two; 123 this.start = start; 124 this.middle = middle; 125 this.end = end; 126 this.locale = locale; 127 } 128 129 private static String compilePattern(String pattern, StringBuilder sb) { 130 return SimpleFormatterImpl.compileToStringMinMaxArguments(pattern, sb, 2, 2); 131 } 132 133 /** 134 * Create a list formatter that is appropriate for a locale. 135 * 136 * @param locale 137 * the locale in question. 138 * @return ListFormatter 139 */ 140 public static ListFormatter getInstance(ULocale locale) { 141 return getInstance(locale, Style.STANDARD); 142 } 143 144 /** 145 * Create a list formatter that is appropriate for a locale. 146 * 147 * @param locale 148 * the locale in question. 149 * @return ListFormatter 150 */ 151 public static ListFormatter getInstance(Locale locale) { 152 return getInstance(ULocale.forLocale(locale), Style.STANDARD); 153 } 154 155 /** 156 * Create a list formatter that is appropriate for a locale and style. 157 * 158 * @param locale the locale in question. 159 * @param style the style 160 * @return ListFormatter 161 * @deprecated This API is ICU internal only. 162 * @hide draft / provisional / internal are hidden on Android 163 */ 164 @Deprecated 165 public static ListFormatter getInstance(ULocale locale, Style style) { 166 return cache.get(locale, style.getName()); 167 } 168 169 /** 170 * Create a list formatter that is appropriate for the default FORMAT locale. 171 * 172 * @return ListFormatter 173 */ 174 public static ListFormatter getInstance() { 175 return getInstance(ULocale.getDefault(ULocale.Category.FORMAT)); 176 } 177 178 /** 179 * Format a list of objects. 180 * 181 * @param items 182 * items to format. The toString() method is called on each. 183 * @return items formatted into a string 184 */ 185 public String format(Object... items) { 186 return format(Arrays.asList(items)); 187 } 188 189 /** 190 * Format a collection of objects. The toString() method is called on each. 191 * 192 * @param items 193 * items to format. The toString() method is called on each. 194 * @return items formatted into a string 195 */ 196 public String format(Collection<?> items) { 197 return format(items, -1).toString(); 198 } 199 200 // Formats a collection of objects and returns the formatted string plus the offset 201 // in the string where the index th element appears. index is zero based. If index is 202 // negative or greater than or equal to the size of items then this function returns -1 for 203 // the offset. 204 FormattedListBuilder format(Collection<?> items, int index) { 205 Iterator<?> it = items.iterator(); 206 int count = items.size(); 207 switch (count) { 208 case 0: 209 return new FormattedListBuilder("", false); 210 case 1: 211 return new FormattedListBuilder(it.next(), index == 0); 212 case 2: 213 return new FormattedListBuilder(it.next(), index == 0).append(two, it.next(), index == 1); 214 } 215 FormattedListBuilder builder = new FormattedListBuilder(it.next(), index == 0); 216 builder.append(start, it.next(), index == 1); 217 for (int idx = 2; idx < count - 1; ++idx) { 218 builder.append(middle, it.next(), index == idx); 219 } 220 return builder.append(end, it.next(), index == count - 1); 221 } 222 223 /** 224 * Returns the pattern to use for a particular item count. 225 * @param count the item count. 226 * @return the pattern with {0}, {1}, {2}, etc. For English, 227 * getPatternForNumItems(3) == "{0}, {1}, and {2}" 228 * @throws IllegalArgumentException when count is 0 or negative. 229 */ 230 public String getPatternForNumItems(int count) { 231 if (count <= 0) { 232 throw new IllegalArgumentException("count must be > 0"); 233 } 234 ArrayList<String> list = new ArrayList<String>(); 235 for (int i = 0; i < count; i++) { 236 list.add(String.format("{%d}", i)); 237 } 238 return format(list); 239 } 240 241 /** 242 * Returns the locale of this object. 243 * @deprecated This API is ICU internal only. 244 * @hide draft / provisional / internal are hidden on Android 245 */ 246 @Deprecated 247 public ULocale getLocale() { 248 return locale; 249 } 250 251 // Builds a formatted list 252 static class FormattedListBuilder { 253 private StringBuilder current; 254 private int offset; 255 256 // Start is the first object in the list; If recordOffset is true, records the offset of 257 // this first object. 258 public FormattedListBuilder(Object start, boolean recordOffset) { 259 this.current = new StringBuilder(start.toString()); 260 this.offset = recordOffset ? 0 : -1; 261 } 262 263 // Appends additional object. pattern is a template indicating where the new object gets 264 // added in relation to the rest of the list. {0} represents the rest of the list; {1} 265 // represents the new object in pattern. next is the object to be added. If recordOffset 266 // is true, records the offset of next in the formatted string. 267 public FormattedListBuilder append(String pattern, Object next, boolean recordOffset) { 268 int[] offsets = (recordOffset || offsetRecorded()) ? new int[2] : null; 269 SimpleFormatterImpl.formatAndReplace( 270 pattern, current, offsets, current, next.toString()); 271 if (offsets != null) { 272 if (offsets[0] == -1 || offsets[1] == -1) { 273 throw new IllegalArgumentException( 274 "{0} or {1} missing from pattern " + pattern); 275 } 276 if (recordOffset) { 277 offset = offsets[1]; 278 } else { 279 offset += offsets[0]; 280 } 281 } 282 return this; 283 } 284 285 @Override 286 public String toString() { 287 return current.toString(); 288 } 289 290 // Gets the last recorded offset or -1 if no offset recorded. 291 public int getOffset() { 292 return offset; 293 } 294 295 private boolean offsetRecorded() { 296 return offset >= 0; 297 } 298 } 299 300 private static class Cache { 301 private final ICUCache<String, ListFormatter> cache = 302 new SimpleCache<String, ListFormatter>(); 303 304 public ListFormatter get(ULocale locale, String style) { 305 String key = String.format("%s:%s", locale.toString(), style); 306 ListFormatter result = cache.get(key); 307 if (result == null) { 308 result = load(locale, style); 309 cache.put(key, result); 310 } 311 return result; 312 } 313 314 private static ListFormatter load(ULocale ulocale, String style) { 315 ICUResourceBundle r = (ICUResourceBundle)UResourceBundle. 316 getBundleInstance(ICUData.ICU_BASE_NAME, ulocale); 317 StringBuilder sb = new StringBuilder(); 318 return new ListFormatter( 319 compilePattern(r.getWithFallback("listPattern/" + style + "/2").getString(), sb), 320 compilePattern(r.getWithFallback("listPattern/" + style + "/start").getString(), sb), 321 compilePattern(r.getWithFallback("listPattern/" + style + "/middle").getString(), sb), 322 compilePattern(r.getWithFallback("listPattern/" + style + "/end").getString(), sb), 323 ulocale); 324 } 325 } 326 327 static Cache cache = new Cache(); 328 } 329