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-2009, 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 import java.util.TimeZone; 14 15 /** 16 * Abstract factory object used to create DurationFormatters. 17 * DurationFormatters are immutable once created. 18 * <p> 19 * Setters on the factory mutate the factory and return it, 20 * for chaining. 21 * <p> 22 * Subclasses override getFormatter to return a custom 23 * DurationFormatter. 24 */ 25 class BasicDurationFormatterFactory implements DurationFormatterFactory { 26 private BasicPeriodFormatterService ps; 27 private PeriodFormatter formatter; 28 private PeriodBuilder builder; 29 private DateFormatter fallback; 30 private long fallbackLimit; 31 private String localeName; 32 private TimeZone timeZone; 33 private BasicDurationFormatter f; // cache 34 35 /** 36 * Create a default formatter for the current locale and time zone. 37 */ BasicDurationFormatterFactory(BasicPeriodFormatterService ps)38 BasicDurationFormatterFactory(BasicPeriodFormatterService ps) { 39 this.ps = ps; 40 this.localeName = Locale.getDefault().toString(); 41 this.timeZone = TimeZone.getDefault(); 42 } 43 44 /** 45 * Set the period formatter used by the factory. New formatters created 46 * with this factory will use the given period formatter. 47 * 48 * @return this BasicDurationFormatterFactory 49 */ 50 @Override setPeriodFormatter( PeriodFormatter formatter)51 public DurationFormatterFactory setPeriodFormatter( 52 PeriodFormatter formatter) { 53 if (formatter != this.formatter) { 54 this.formatter = formatter; 55 reset(); 56 } 57 return this; 58 } 59 60 /** 61 * Set the builder used by the factory. New formatters created 62 * with this factory will use the given locale. 63 * 64 * @param builder the builder to use 65 * @return this BasicDurationFormatterFactory 66 */ 67 @Override setPeriodBuilder(PeriodBuilder builder)68 public DurationFormatterFactory setPeriodBuilder(PeriodBuilder builder) { 69 if (builder != this.builder) { 70 this.builder = builder; 71 reset(); 72 } 73 return this; 74 } 75 76 /** 77 * Set a fallback formatter for durations over a given limit. 78 * 79 * @param fallback the fallback formatter to use, or null 80 * @return this BasicDurationFormatterFactory 81 */ 82 @Override setFallback(DateFormatter fallback)83 public DurationFormatterFactory setFallback(DateFormatter fallback) { 84 boolean doReset = fallback == null 85 ? this.fallback != null 86 : !fallback.equals(this.fallback); 87 if (doReset) { 88 this.fallback = fallback; 89 reset(); 90 } 91 return this; 92 } 93 94 /** 95 * Set a fallback limit for durations over a given limit. 96 * 97 * @param fallbackLimit the fallback limit to use, or 0 if none is desired. 98 * @return this BasicDurationFormatterFactory 99 */ 100 @Override setFallbackLimit(long fallbackLimit)101 public DurationFormatterFactory setFallbackLimit(long fallbackLimit) { 102 if (fallbackLimit < 0) { 103 fallbackLimit = 0; 104 } 105 if (fallbackLimit != this.fallbackLimit) { 106 this.fallbackLimit = fallbackLimit; 107 reset(); 108 } 109 return this; 110 } 111 112 /** 113 * Set the name of the locale that will be used when 114 * creating new formatters. 115 * 116 * @param localeName the name of the Locale 117 * @return this BasicDurationFormatterFactory 118 */ 119 @Override setLocale(String localeName)120 public DurationFormatterFactory setLocale(String localeName) { 121 if (!localeName.equals(this.localeName)) { 122 this.localeName = localeName; 123 if (builder != null) { 124 builder = builder.withLocale(localeName); 125 } 126 if (formatter != null) { 127 formatter = formatter.withLocale(localeName); 128 } 129 reset(); 130 } 131 return this; 132 } 133 134 /** 135 * Set the name of the locale that will be used when 136 * creating new formatters. 137 * 138 * @param timeZone The time zone to use. 139 * @return this BasicDurationFormatterFactory 140 */ 141 @Override setTimeZone(TimeZone timeZone)142 public DurationFormatterFactory setTimeZone(TimeZone timeZone) { 143 if (!timeZone.equals(this.timeZone)) { 144 this.timeZone = timeZone; 145 if (builder != null) { 146 builder = builder.withTimeZone(timeZone); 147 } 148 reset(); 149 } 150 return this; 151 } 152 153 /** 154 * Return a formatter based on this factory's current settings. 155 * 156 * @return a BasicDurationFormatter 157 */ 158 @Override getFormatter()159 public DurationFormatter getFormatter() { 160 if (f == null) { 161 if (fallback != null) { 162 fallback = fallback.withLocale(localeName).withTimeZone(timeZone); 163 } 164 formatter = getPeriodFormatter(); 165 builder = getPeriodBuilder(); 166 167 f = createFormatter(); 168 } 169 return f; 170 } 171 172 /** 173 * Return the current period formatter. 174 * 175 * @return the current period formatter 176 */ getPeriodFormatter()177 public PeriodFormatter getPeriodFormatter() { 178 if (formatter == null) { 179 formatter = ps.newPeriodFormatterFactory() 180 .setLocale(localeName) 181 .getFormatter(); 182 } 183 return formatter; 184 } 185 186 /** 187 * Return the current builder. 188 * 189 * @return the current builder 190 */ getPeriodBuilder()191 public PeriodBuilder getPeriodBuilder() { 192 if (builder == null) { 193 builder = ps.newPeriodBuilderFactory() 194 .setLocale(localeName) 195 .setTimeZone(timeZone) 196 .getSingleUnitBuilder(); 197 } 198 return builder; 199 } 200 201 /** 202 * Return the current fallback formatter. 203 * 204 * @return the fallback formatter, or null if there is no fallback 205 * formatter 206 */ getFallback()207 public DateFormatter getFallback() { 208 return fallback; 209 } 210 211 /** 212 * Return the current fallback formatter limit 213 * 214 * @return the limit, or 0 if there is no fallback. 215 */ getFallbackLimit()216 public long getFallbackLimit() { 217 return fallback == null ? 0 : fallbackLimit; 218 } 219 220 /** 221 * Return the current locale name. 222 * 223 * @return the current locale name 224 */ getLocaleName()225 public String getLocaleName() { 226 return localeName; 227 } 228 229 /** 230 * Return the current locale name. 231 * 232 * @return the current locale name 233 */ getTimeZone()234 public TimeZone getTimeZone() { 235 return timeZone; 236 } 237 238 /** 239 * Create the formatter. All local fields are already initialized. 240 */ createFormatter()241 protected BasicDurationFormatter createFormatter() { 242 return new BasicDurationFormatter(formatter, builder, fallback, 243 fallbackLimit, localeName, 244 timeZone); 245 } 246 247 /** 248 * Clear the cached formatter. Subclasses must call this if their 249 * state has changed. This is automatically invoked by setBuilder, 250 * setFormatter, setFallback, setLocaleName, and setTimeZone 251 */ reset()252 protected void reset() { 253 f = null; 254 } 255 } 256