1 package com.sharkysoft.printf.engine;
2
3 import java.math.BigDecimal;
4
5 /***
6 * Formats numbers.
7 *
8 * <p>A <code>NumberFormatter</code> formats numbers in a field by adjusting
9 * their precision and padding them as necessary, according to criteria selected
10 * by the client. Properties control various formatting constraints, such as
11 * field width, justification style, padding characters, and so on.</p>
12 *
13 * <p>Because applications that format numeric values frequently format multiple
14 * values with the same criteria, this class is designed to "remember" selected
15 * formatting properties so that the settings they can be reused with each
16 * subsequent formatting request. This approach minimizes the number of
17 * parameters that must be passed with each formatting call and results in more
18 * efficient execution for large formatting jobs.</p>
19 *
20 * <p><code>NumberFormatter</code> extends {@link StringFormatter} with abstract
21 * number formatting constraints that are common to {@link IntegerFormatter} and
22 * {@link RealFormatter}. This class does not actually implement any of the
23 * specific numeric formatting rules, but leaves that work to the
24 * subclasses.</p>
25 *
26 * @see IntegerFormatter
27 * @see RealFormatter
28 *
29 * @author Sharky
30 */
31 public abstract class NumberFormatter extends StringFormatter
32 {
33
34
35
36
37
38
39
40 /***
41 * Radix.
42 *
43 * <p><b>Details:</b> Property <code>Radix</code> is the output radix (numeric
44 * base) for stringified numbers. For example, a value of 16 indicates that
45 * the value will be represented in hexadecimal. This value may not be set
46 * to values less than 2 or greater than 36. <b>Default value:</b> 10.</p>
47 *
48 * @see #getRadix()
49 * @see #setRadix(int)
50 */
51 protected int mnRadix = 10;
52
53 /***
54 * Retrieves Radix property.
55 *
56 * @return current value
57 *
58 * @see #mnRadix
59 */
60 public int getRadix() {return mnRadix;}
61
62 /***
63 * Updates Radix property.
64 *
65 * @param inRadix new value
66 *
67 * @see #mnRadix
68 */
69 public void setRadix(final int inRadix)
70 {
71 if (inRadix < 2 || inRadix > 36)
72 throw new IllegalArgumentException("inRadix=" + inRadix);
73 mnRadix = inRadix;
74 }
75
76
77
78
79
80
81
82 /***
83 * Upper case/lower case.
84 *
85 * <p><b>Details:</b> Property <code>UpperCase</code> determines whether upper
86 * or lower case letters will be used when property <code>Radix</code> is
87 * greater than 10. If this property is <code>true</code>, upper case letters
88 * will be used. If this property is <code>false</code>, lower case letters
89 * will be used. The default value for this property is
90 * <code>false</code>.</p>
91 *
92 * @see #getUpperCase()
93 * @see #setUpperCase(boolean)
94 */
95 protected boolean mzUpperCase = false;
96
97 /***
98 * Retrieves UpperCase property.
99 *
100 * @return current value
101 *
102 * @see #mzUpperCase
103 */
104 public boolean getUpperCase() {return mzUpperCase;}
105
106 /***
107 * Updates UpperCase property.
108 *
109 * @param izUpperCase new value
110 *
111 * @see #mzUpperCase
112 */
113 public void setUpperCase(final boolean izUpperCase)
114 {
115 mzUpperCase = izUpperCase;
116 }
117
118
119
120
121
122
123
124 /***
125 * Significant digits.
126 *
127 * <p><b>Details:</b> Property <code>SigDigits</code> constrains the number of
128 * significant digits to express in the output, so that the value will be
129 * rounded if necessary. Setting this value to 0 indicates that all digits
130 * are considered significant. This constraint may conflict with the
131 * MaxRightDigits property in {@link RealFormatter}. Default value: 0.</p>
132 *
133 * @see #getSigDigits()
134 * @see #setSigDigits(int)
135 */
136 protected int mnSigDigits = 0;
137
138 /***
139 * Retrieves SigDigits property.
140 *
141 * @return current value
142 *
143 * @see #mnSigDigits
144 */
145 public int getSigDigits() {return mnSigDigits;}
146
147 /***
148 * Updates SigDigits property.
149 *
150 * @param inSigDigits new value
151 *
152 * @see #mnSigDigits
153 */
154 public void setSigDigits(final int inSigDigits)
155 {
156 if (inSigDigits < 0)
157 throw new IllegalArgumentException("inSigDigits=" + inSigDigits);
158 mnSigDigits = inSigDigits;
159 }
160
161
162
163
164
165
166
167 /***
168 * Positive prefix.
169 *
170 * <p><b>Details:</b> Property <code>PosPrefix</code> is the string that
171 * precedes positive values. This property may not be <code>null</code>.
172 * Default value: "".</p>
173 *
174 * @see #getPosPrefix()
175 * @see #setPosPrefix(String)
176 */
177 protected String msPosPrefix = "";
178
179 /***
180 * Retrieves PosPrefix property.
181 *
182 * @return current value
183 *
184 * @see #msPosPrefix
185 */
186 public String getPosPrefix() {return msPosPrefix;}
187
188 /***
189 * Updates PosPrefix property.
190 *
191 * @param isPosPrefix new value
192 *
193 * @see #msPosPrefix
194 */
195 public void setPosPrefix(final String isPosPrefix)
196 {
197 if (isPosPrefix == null)
198 throw new NullPointerException("isPosPrefix");
199 msPosPrefix = isPosPrefix;
200 }
201
202
203
204
205
206
207
208 /***
209 * Positive suffix.
210 *
211 * <p><b>Details:</b> Property <code>PosSuffix</code> is the string that
212 * follows positive values. This property may not be <code>null</code>.
213 * Default value: "".</p>
214 *
215 * @see #getPosSuffix()
216 * @see #setPosSuffix(String)
217 */
218 protected String msPosSuffix = "";
219
220 /***
221 * Retrieves PosSuffix property.
222 *
223 * @return current value
224 *
225 * @see #msPosSuffix
226 */
227 public String getPosSuffix() {return msPosSuffix;}
228
229 /***
230 * Updates PosSuffix property.
231 *
232 * @param isPosSuffix new value
233 *
234 * @see #msPosSuffix
235 */
236 public void setPosSuffix(final String isPosSuffix)
237 {
238 if (isPosSuffix == null)
239 throw new NullPointerException("isPosSuffix");
240 msPosSuffix = isPosSuffix;
241 }
242
243
244
245
246
247
248
249 /***
250 * Zero prefix.
251 *
252 * <p><b>Details:</b> Property <code>ZeroPrefix</code> is the string that
253 * precedes zero values. This property may not be <code>null</code>. Default
254 * value: "".</p>
255 *
256 * @see #getZeroPrefix()
257 * @see #setZeroPrefix(String)
258 */
259 protected String msZeroPrefix = "";
260
261 /***
262 * Retrieves ZeroPrefix property.
263 *
264 * @return current value
265 *
266 * @see #msZeroPrefix
267 */
268 public String getZeroPrefix() {return msZeroPrefix;}
269
270 /***
271 * Updates ZeroPrefix property.
272 *
273 * @param isZeroPrefix new value
274 *
275 * @see #msZeroPrefix
276 */
277 public void setZeroPrefix(final String isZeroPrefix)
278 {
279 if (isZeroPrefix == null)
280 throw new NullPointerException("isZeroPrefix");
281 msZeroPrefix = isZeroPrefix;
282 }
283
284
285
286
287
288
289
290 /***
291 * Zero suffix.
292 *
293 * <p><b>Details:</b> Property <code>ZeroSuffix</code> is the string that
294 * follows zero values. This property may not be <code>null</code>. Default
295 * value: "".</p>
296 *
297 * @see #getZeroSuffix()
298 * @see #setZeroSuffix(String)
299 */
300 protected String msZeroSuffix = "";
301
302 /***
303 * Retrieves ZeroSuffix property.
304 *
305 * @return current value
306 *
307 * @see #msZeroSuffix
308 */
309 public String getZeroSuffix() {return msZeroSuffix;}
310
311 /***
312 * Updates ZeroSuffix property.
313 *
314 * @param isZeroSuffix new value
315 *
316 * @see #msZeroSuffix
317 */
318 public void setZeroSuffix(final String isZeroSuffix)
319 {
320 if (isZeroSuffix == null)
321 throw new NullPointerException("isZeroSuffix");
322 msZeroSuffix = isZeroSuffix;
323 }
324
325
326
327
328
329
330
331 /***
332 * Negative prefix.
333 *
334 * <p><b>Details:</b> Property <code>NegPrefix</code> is the string that
335 * precedes negative values. This property may not be <code>null</code>.
336 * Default value: "-".</p>
337 *
338 * @see #getNegPrefix()
339 * @see #setNegPrefix(String)
340 */
341 protected String msNegPrefix = "-";
342
343 /***
344 * Retrieves NegPrefix property.
345 *
346 * @return current value
347 *
348 * @see #msNegPrefix
349 */
350 public String getNegPrefix() {return msNegPrefix;}
351
352 /***
353 * Updates NegPrefix property.
354 *
355 * @param isNegPrefix new value
356 *
357 * @see #msNegPrefix
358 */
359 public void setNegPrefix(final String isNegPrefix)
360 {
361 if (isNegPrefix == null)
362 throw new NullPointerException("isNegPrefix");
363 msNegPrefix = isNegPrefix;
364 }
365
366
367
368
369
370
371
372 /***
373 * Negative suffix.
374 *
375 * <p><b>Details:</b> Property <code>NegSuffix</code> is the string that
376 * follows negative values. This property may not be <code>null</code>.
377 * Default value: "".</p>
378 *
379 * @see #getNegSuffix()
380 * @see #setNegSuffix(String)
381 */
382 protected String msNegSuffix = "";
383
384 /***
385 * Retrieves NegSuffix property.
386 *
387 * @return current value
388 *
389 * @see #msNegSuffix
390 */
391 public String getNegSuffix() {return msNegSuffix;}
392
393 /***
394 * Updates NegSuffix property.
395 *
396 * @param isNegSuffix new value
397 *
398 * @see #msNegSuffix
399 */
400 public void setNegSuffix(final String isNegSuffix)
401 {
402 if (isNegSuffix == null)
403 throw new NullPointerException("isNegSuffix");
404 msNegSuffix = isNegSuffix;
405 }
406
407 /***
408 * Default constructor.
409 */
410 protected NumberFormatter() {}
411
412 /***
413 * Adjusts significant digits.
414 *
415 * <p><b>Details:</b> This method adjusts the number of significant digits in
416 * the given <code>BigDecimal</code> and returns the adjusted value.</p>
417 *
418 * <p>This method is a temporary hack to overcome a limitation in
419 * <code>BigDecimal</code>. A feature request has been submitted to the Java
420 * Bug Parade and it has been address. This method should be reimplemented
421 * using the latest methods available in <code>BigDecimal</code>.</p>
422 *
423 * @param ipValue value to adjust
424 * @param inSigDigits number of significant digits
425 * @return adjusted value
426 */
427 static final BigDecimal setSignificantDigits(BigDecimal ipValue, final int inSigDigits)
428 {
429 if (inSigDigits <= 0)
430 throw new IllegalArgumentException("inSigDigits=" + inSigDigits);
431 final int vnScale = ipValue.scale();
432 ipValue = ipValue.movePointRight(vnScale);
433 final String vsString = ipValue.toString();
434 int vnSize = vsString.length();
435 if (vsString.charAt(vnSize - 1) == '.')
436 -- vnSize;
437 if (vsString.charAt(0) == '-')
438 -- vnSize;
439 ipValue = ipValue.movePointLeft(vnSize);
440 ipValue = ipValue.setScale(inSigDigits, BigDecimal.ROUND_HALF_UP);
441 return ipValue.movePointRight(vnSize - vnScale);
442 }
443
444 }
445