1 // © 2016 and later: Unicode, Inc. and others. 2 // License & terms of use: http://www.unicode.org/copyright.html#License 3 /* 4 ****************************************************************************** 5 * Copyright (C) 2007-2010, International Business Machines Corporation and * 6 * others. All Rights Reserved. * 7 ****************************************************************************** 8 */ 9 10 package com.ibm.icu.impl.duration; 11 12 import java.util.Locale; 13 14 import com.ibm.icu.impl.duration.impl.DataRecord.ECountVariant; 15 import com.ibm.icu.impl.duration.impl.DataRecord.ESeparatorVariant; 16 import com.ibm.icu.impl.duration.impl.DataRecord.EUnitVariant; 17 import com.ibm.icu.impl.duration.impl.PeriodFormatterData; 18 import com.ibm.icu.impl.duration.impl.PeriodFormatterDataService; 19 20 /** 21 * An implementation of PeriodFormatterFactory that provides customization of 22 * formatting behavior. Instances of this factory are created by 23 * BasicPeriodFormatterService. 24 * 25 * The settings on BasicPeriodFormatterFactory are: 26 * <ul> 27 * 28 * <li><b>setDisplayLimit</b> controls whether phrases like 'more than' 29 * or 'less than' will be displayed when the Period has a defined 30 * limit. Default is to display them.</li> 31 * 32 * <li><b>setDisplayPastFuture</b> controls whether phrases like 'ago' 33 * or 'from now' will be displayed to indicate past or future 34 * time. Default is to display them.</li> 35 * 36 * <li><b>setSeparatorVariant</b> controls how separators (between 37 * count and period, and multiple periods) will be displayed, when 38 * appropriate for the language. Default is to use full 39 * separators.</li> 40 * 41 * <li><b>setUnitVariant</b> controls which of various types of 42 * unit names to use. PLURALIZED indicates that full names will be 43 * used. MEDIUM indicates that medium-length (usually 2-3 character) 44 * names will be used. SHORT indicates that short (usually single 45 * character) names will be used. If there is no localization data 46 * available for either the SHORT or MEDIUM names, the other will be 47 * used, if neither is available, the PLURALIZED names will be used. 48 * Default is PLURALIZED.</li> 49 * 50 * <li><b>setCountVariant</b> controls how the count for the smallest 51 * unit will be formatted: either as an integer, a fraction to the 52 * smallest half, or as a decimal with 1, 2, or 3 decimal points.</li> 53 * Counts for higher units will be formatted as integers. 54 * 55 * </ul> 56 */ 57 public class BasicPeriodFormatterFactory implements PeriodFormatterFactory { 58 private final PeriodFormatterDataService ds; 59 private PeriodFormatterData data; 60 private Customizations customizations; 61 private boolean customizationsInUse; 62 private String localeName; 63 64 // package-only constructor BasicPeriodFormatterFactory(PeriodFormatterDataService ds)65 BasicPeriodFormatterFactory(PeriodFormatterDataService ds) { 66 this.ds = ds; 67 this.customizations = new Customizations(); 68 this.localeName = Locale.getDefault().toString(); 69 } 70 71 /** 72 * Return the default rdf factory as a BasicPeriodFormatterFactory. 73 * 74 * @return a default BasicPeriodFormatterFactory 75 */ getDefault()76 public static BasicPeriodFormatterFactory getDefault() { 77 return (BasicPeriodFormatterFactory) 78 BasicPeriodFormatterService.getInstance().newPeriodFormatterFactory(); 79 } 80 81 /** 82 * Set the locale for this factory. 83 */ 84 @Override setLocale(String localeName)85 public PeriodFormatterFactory setLocale(String localeName) { 86 data = null; 87 this.localeName = localeName; 88 return this; 89 } 90 91 /** 92 * Set whether limits will be displayed. 93 * 94 * @param display true if limits will be displayed 95 * @return this PeriodFormatterFactory 96 */ 97 @Override setDisplayLimit(boolean display)98 public PeriodFormatterFactory setDisplayLimit(boolean display) { 99 updateCustomizations().displayLimit = display; 100 return this; 101 } 102 103 /** 104 * Return true if limits will be displayed. 105 * 106 * @return true if limits will be displayed 107 */ getDisplayLimit()108 public boolean getDisplayLimit() { 109 return customizations.displayLimit; 110 } 111 112 /** 113 * Set whether past and future will be displayed. 114 * 115 * @param display true if past and future will be displayed 116 * @return this PeriodFormatterFactory 117 */ 118 @Override setDisplayPastFuture(boolean display)119 public PeriodFormatterFactory setDisplayPastFuture(boolean display) { 120 updateCustomizations().displayDirection = display; 121 return this; 122 } 123 124 /** 125 * Return true if past and future will be displayed. 126 * 127 * @return true if past and future will be displayed 128 */ getDisplayPastFuture()129 public boolean getDisplayPastFuture() { 130 return customizations.displayDirection; 131 } 132 133 /** 134 * Set how separators will be displayed. 135 * 136 * @param variant the variant indicating separators will be displayed 137 * @return this PeriodFormatterFactory 138 */ 139 @Override setSeparatorVariant(int variant)140 public PeriodFormatterFactory setSeparatorVariant(int variant) { 141 updateCustomizations().separatorVariant = (byte) variant; 142 return this; 143 } 144 145 /** 146 * Return the variant indicating how separators will be displayed. 147 * 148 * @return the variant 149 */ getSeparatorVariant()150 public int getSeparatorVariant() { 151 return customizations.separatorVariant; 152 } 153 154 /** 155 * Set the variant of the time unit names to use. 156 * 157 * @param variant the variant to use 158 * @return this PeriodFormatterFactory 159 */ 160 @Override setUnitVariant(int variant)161 public PeriodFormatterFactory setUnitVariant(int variant) { 162 updateCustomizations().unitVariant = (byte) variant; 163 return this; 164 } 165 166 /** 167 * Return the unit variant. 168 * 169 * @return the unit variant 170 */ getUnitVariant()171 public int getUnitVariant() { 172 return customizations.unitVariant; 173 } 174 175 /** 176 * Set the variant of the count to use. 177 * 178 * @param variant the variant to use 179 * @return this PeriodFormatterFactory 180 */ 181 @Override setCountVariant(int variant)182 public PeriodFormatterFactory setCountVariant(int variant) { 183 updateCustomizations().countVariant = (byte) variant; 184 return this; 185 } 186 187 /** 188 * Return the count variant. 189 * 190 * @return the count variant 191 */ getCountVariant()192 public int getCountVariant() { 193 return customizations.countVariant; 194 } 195 196 @Override getFormatter()197 public PeriodFormatter getFormatter() { 198 customizationsInUse = true; 199 return new BasicPeriodFormatter(this, localeName, getData(), 200 customizations); 201 } 202 updateCustomizations()203 private Customizations updateCustomizations() { 204 if (customizationsInUse) { 205 customizations = customizations.copy(); 206 customizationsInUse = false; 207 } 208 return customizations; 209 } 210 211 // package access only getData()212 PeriodFormatterData getData() { 213 if (data == null) { 214 data = ds.get(localeName); 215 } 216 return data; 217 } 218 219 // package access for use by BasicPeriodFormatter getData(String locName)220 PeriodFormatterData getData(String locName) { 221 return ds.get(locName); 222 } 223 224 // package access for use by BasicPeriodFormatter 225 static class Customizations { 226 boolean displayLimit = true; 227 boolean displayDirection = true; 228 byte separatorVariant = ESeparatorVariant.FULL; 229 byte unitVariant = EUnitVariant.PLURALIZED; 230 byte countVariant = ECountVariant.INTEGER; 231 copy()232 public Customizations copy() { 233 Customizations result = new Customizations(); 234 result.displayLimit = displayLimit; 235 result.displayDirection = displayDirection; 236 result.separatorVariant = separatorVariant; 237 result.unitVariant = unitVariant; 238 result.countVariant = countVariant; 239 return result; 240 } 241 } 242 } 243