1 /* GENERATED SOURCE. DO NOT MODIFY. */ 2 // © 2018 and later: Unicode, Inc. and others. 3 // License & terms of use: http://www.unicode.org/copyright.html 4 package android.icu.text; 5 6 import java.text.Format.Field; 7 import java.util.Objects; 8 9 /** 10 * Represents a span of a string containing a given field. 11 * 12 * This class differs from FieldPosition in the following ways: 13 * 14 * 1. It has information on the field category. 15 * 2. It allows you to set constraints to use when iterating over field positions. 16 * 3. It is used for the newer FormattedValue APIs. 17 * 18 * @author sffc 19 */ 20 public class ConstrainedFieldPosition { 21 22 /** 23 * Represents the type of constraint for ConstrainedFieldPosition. 24 * 25 * Constraints are used to control the behavior of iteration in FormattedValue. 26 */ 27 private enum ConstraintType { 28 /** 29 * Represents the lack of a constraint. 30 * 31 * This is the value of fConstraint 32 * if no "constrain" methods were called. 33 */ 34 NONE, 35 36 /** 37 * Represents that the field class is constrained. 38 * 39 * This is the value of fConstraint 40 * after {@link #constrainClass} is called. 41 * 42 * FormattedValue implementations should not change the field class when this constraint is active. 43 */ 44 CLASS, 45 46 /** 47 * Represents that the field is constrained. 48 * 49 * This is the value of fConstraint 50 * after {@link #constrainField} is called. 51 * 52 * FormattedValue implementations should not change the field when this constraint is active. 53 */ 54 FIELD, 55 56 /** 57 * Represents that the field value is constrained. 58 * 59 * This is the value of fConstraint 60 * after {@link #constrainField} is called. 61 * 62 * FormattedValue implementations should not change the field or value with this constraint. 63 */ 64 VALUE 65 }; 66 67 private ConstraintType fConstraint; 68 private Class<?> fClassConstraint; 69 private Field fField; 70 private Object fValue; 71 private int fStart; 72 private int fLimit; 73 private long fContext; 74 75 /** 76 * Initializes a CategoryFieldPosition. 77 * 78 * By default, the CategoryFieldPosition has no iteration constraints. 79 */ ConstrainedFieldPosition()80 public ConstrainedFieldPosition() { 81 reset(); 82 } 83 84 /** 85 * Resets this ConstrainedFieldPosition to its initial state, as if it were newly created: 86 * 87 * - Removes any constraints that may have been set on the instance. 88 * - Resets the iteration position. 89 */ reset()90 public void reset() { 91 fConstraint = ConstraintType.NONE; 92 fClassConstraint = Object.class; 93 fField = null; 94 fValue = null; 95 fStart = 0; 96 fLimit = 0; 97 fContext = 0; 98 } 99 100 /** 101 * Sets a constraint on the field. 102 * 103 * When this instance of ConstrainedFieldPosition is passed to {@link FormattedValue#nextPosition}, positions are 104 * skipped unless they have the given field. 105 * 106 * Any previously set constraints are cleared. 107 * 108 * For example, to loop over all grouping separators: 109 * 110 * <pre> 111 * ConstrainedFieldPosition cfpos; 112 * cfpos.constrainField(NumberFormat.Field.GROUPING_SEPARATOR); 113 * while (fmtval.nextPosition(cfpos)) { 114 * // handle the grouping separator position 115 * } 116 * </pre> 117 * 118 * Changing the constraint while in the middle of iterating over a FormattedValue 119 * does not generally have well-defined behavior. 120 * 121 * @param field 122 * The field to fix when iterating. 123 */ constrainField(Field field)124 public void constrainField(Field field) { 125 if (field == null) { 126 throw new IllegalArgumentException("Cannot constrain on null field"); 127 } 128 fConstraint = ConstraintType.FIELD; 129 fClassConstraint = Object.class; 130 fField = field; 131 fValue = null; 132 } 133 134 /** 135 * Sets a constraint on the field class. 136 * 137 * When this instance of ConstrainedFieldPosition is passed to {@link FormattedValue#nextPosition}, positions are 138 * skipped unless the field is an instance of the class constraint, including subclasses. 139 * 140 * Any previously set constraints are cleared. 141 * 142 * For example, to loop over only the number-related fields: 143 * 144 * <pre> 145 * ConstrainedFieldPosition cfpos; 146 * cfpos.constrainClass(NumberFormat.Field.class); 147 * while (fmtval.nextPosition(cfpos)) { 148 * // handle the number-related field position 149 * } 150 * </pre> 151 * 152 * @param classConstraint 153 * The field class to fix when iterating. 154 */ constrainClass(Class<?> classConstraint)155 public void constrainClass(Class<?> classConstraint) { 156 if (classConstraint == null) { 157 throw new IllegalArgumentException("Cannot constrain on null field class"); 158 } 159 fConstraint = ConstraintType.CLASS; 160 fClassConstraint = classConstraint; 161 fField = null; 162 fValue = null; 163 } 164 165 /** 166 * Sets a constraint on field and field value. 167 * 168 * When this instance of ConstrainedFieldPosition is passed to {@link FormattedValue#nextPosition}, positions are 169 * skipped unless both the field and the field value are equal. 170 * 171 * Any previously set constraints are cleared. 172 * 173 * For example, to find the span a date interval corresponding to the first date: 174 * 175 * <pre> 176 * ConstrainedFieldPosition cfpos; 177 * cfpos.constrainFieldAndValue(DateIntervalFormat.SpanField.DATE_INTERVAL_SPAN, 0); 178 * while (fmtval.nextPosition(cfpos)) { 179 * // handle the span of the first date in the date interval 180 * } 181 * </pre> 182 * 183 * @param field The field to fix when iterating. 184 * @param fieldValue The field value to fix when iterating. 185 * @deprecated This API is for technology preview and might be changed or removed in a future release. 186 * @hide draft / provisional / internal are hidden on Android 187 */ 188 @Deprecated constrainFieldAndValue(Field field, Object fieldValue)189 public void constrainFieldAndValue(Field field, Object fieldValue) { 190 fConstraint = ConstraintType.VALUE; 191 fClassConstraint = Object.class; 192 fField = field; 193 fValue = fieldValue; 194 } 195 196 /** 197 * Gets the field for the current position. 198 * 199 * The return value is well-defined and non-null only after 200 * FormattedValue#nextPosition returns true. 201 * 202 * @return The field saved in the instance. See above for null conditions. 203 */ getField()204 public Field getField() { 205 return fField; 206 } 207 208 /** 209 * Gets the INCLUSIVE start index for the current position. 210 * 211 * The return value is well-defined only after FormattedValue#nextPosition returns true. 212 * 213 * @return The start index saved in the instance. 214 */ getStart()215 public int getStart() { 216 return fStart; 217 } 218 219 /** 220 * Gets the EXCLUSIVE end index stored for the current position. 221 * 222 * The return value is well-defined only after FormattedValue#nextPosition returns true. 223 * 224 * @return The end index saved in the instance. 225 */ getLimit()226 public int getLimit() { 227 return fLimit; 228 } 229 230 /** 231 * Gets the value associated with the current field position. The field value is often not set. 232 * 233 * The return value is well-defined only after FormattedValue#nextPosition returns true. 234 * 235 * @return The value for the current position. Might be null. 236 */ getFieldValue()237 public Object getFieldValue() { 238 return fValue; 239 } 240 241 /** 242 * Gets an int64 that FormattedValue implementations may use for storage. 243 * 244 * The initial value is zero. 245 * 246 * Users of FormattedValue should not need to call this method. 247 * 248 * @return The current iteration context from {@link #setInt64IterationContext}. 249 */ getInt64IterationContext()250 public long getInt64IterationContext() { 251 return fContext; 252 } 253 254 /** 255 * Sets an int64 that FormattedValue implementations may use for storage. 256 * 257 * Intended to be used by FormattedValue implementations. 258 * 259 * @param context 260 * The new iteration context. 261 */ setInt64IterationContext(long context)262 public void setInt64IterationContext(long context) { 263 fContext = context; 264 } 265 266 /** 267 * Sets new values for the primary public getters. 268 * 269 * Intended to be used by FormattedValue implementations. 270 * 271 * It is up to the implementation to ensure that the user-requested 272 * constraints are satisfied. This method does not check! 273 * 274 * @param field 275 * The new field. 276 * @param value 277 * The new field value. Should be null if there is no value. 278 * @param start 279 * The new inclusive start index. 280 * @param limit 281 * The new exclusive end index. 282 */ setState(Field field, Object value, int start, int limit)283 public void setState(Field field, Object value, int start, int limit) { 284 // Check matchesField only as an assertion (debug build) 285 if (field != null) { 286 assert matchesField(field, value); 287 } 288 289 fField = field; 290 fValue = value; 291 fStart = start; 292 fLimit = limit; 293 } 294 295 /** 296 * Determines whether a given field and value should be included given the 297 * constraints. 298 * 299 * Intended to be used by FormattedValue implementations. 300 * 301 * @param field The field to test. 302 * @param fieldValue The field value to test. Should be null if there is no value. 303 * @return Whether the field should be included given the constraints. 304 */ matchesField(Field field, Object fieldValue)305 public boolean matchesField(Field field, Object fieldValue) { 306 if (field == null) { 307 throw new IllegalArgumentException("field must not be null"); 308 } 309 switch (fConstraint) { 310 case NONE: 311 return true; 312 case CLASS: 313 return fClassConstraint.isAssignableFrom(field.getClass()); 314 case FIELD: 315 return fField == field; 316 case VALUE: 317 // Note: Objects.equals is Android API level 19 and Java 1.7 318 return fField == field && Objects.equals(fValue, fieldValue); 319 default: 320 throw new AssertionError(); 321 } 322 } 323 324 /** 325 * {@inheritDoc} 326 */ 327 @Override toString()328 public String toString() { 329 StringBuilder sb = new StringBuilder(); 330 sb.append("CFPos["); 331 sb.append(fStart); 332 sb.append('-'); 333 sb.append(fLimit); 334 sb.append(' '); 335 sb.append(fField); 336 sb.append(']'); 337 return sb.toString(); 338 } 339 } 340