Home | History | Annotate | Download | only in text
      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