|
1 /* |
|
2 * Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies). |
|
3 * All rights reserved. |
|
4 * This component and the accompanying materials are made available |
|
5 * under the terms of "Eclipse Public License v1.0" |
|
6 * which accompanies this distribution, and is available |
|
7 * at the URL "http://www.eclipse.org/legal/epl-v10.html". |
|
8 * |
|
9 * Initial Contributors: |
|
10 * Nokia Corporation - initial contribution. |
|
11 * |
|
12 * Contributors: |
|
13 * |
|
14 * Description: |
|
15 * |
|
16 */ |
|
17 |
|
18 |
|
19 package com.nokia.mj.impl.utils; |
|
20 |
|
21 import java.util.Date; |
|
22 |
|
23 /** |
|
24 * Utility for formatting text strings from a pattern with positional |
|
25 * parameters. |
|
26 * <br> |
|
27 * Supported parameters are: |
|
28 * <UL> |
|
29 * <LI>%nU - String in position n |
|
30 * <LI>%U - Next string |
|
31 * <LI>%nN - Integer in position n |
|
32 * <LI>%N - Next integer |
|
33 * <LI>%nC - Character in position n |
|
34 * <LI>%C - Next character |
|
35 * <LI>%n - Parameter in position n |
|
36 * </UL> |
|
37 * <br> |
|
38 * Example of usage: |
|
39 * <pre> |
|
40 * Formatter formatter = new Formatter("You have %N email(s) left"); |
|
41 * String message = formatter.arg(5).toString(); |
|
42 * // Becomes :You have 5 email(s) left |
|
43 * |
|
44 * Formatter formatter = new Formatter("There are %N0 files in folder \"%U1\""); |
|
45 * String message = formatter.arg(5).arg("photos").toString(); |
|
46 * // Becomes :There are 5 files in folder "photos" |
|
47 * </pre> |
|
48 * <br> |
|
49 * Limitation: more than 10 positional arguments are not supported (only 0...9) |
|
50 * |
|
51 * @author Nokia Corporation |
|
52 * @version 1.0 |
|
53 */ |
|
54 public class Formatter |
|
55 { |
|
56 /** Original pattern string */ |
|
57 private String pattern; |
|
58 |
|
59 /** String with latest replacements */ |
|
60 private String replaced; |
|
61 |
|
62 /** Next replacement index */ |
|
63 private int nextIndex = 0; |
|
64 |
|
65 /*** ----------------------------- PUBLIC ------------------------------ */ |
|
66 |
|
67 /** |
|
68 * Create a new formatter |
|
69 * |
|
70 * @param pattern formatter pattern |
|
71 */ |
|
72 public Formatter(String aPattern) |
|
73 { |
|
74 pattern = aPattern; |
|
75 replaced = aPattern; |
|
76 } |
|
77 |
|
78 /** |
|
79 * Replace the lowest numbered parameter in the string, which is not yet |
|
80 * replaced. |
|
81 * |
|
82 * @param string string to replace at the argument |
|
83 * @return same formatter |
|
84 */ |
|
85 public Formatter arg(String string) |
|
86 { |
|
87 // Try to replace with patterns %nU,%n, %U |
|
88 if (replace("%" + nextIndex + "U", string) || |
|
89 replace("%" + nextIndex, string) || |
|
90 replace("%U", string)) |
|
91 { |
|
92 nextIndex++; |
|
93 |
|
94 } |
|
95 else |
|
96 { |
|
97 Logger.WLOG(Logger.EUtils, "String replacement failed"); |
|
98 } |
|
99 return this; |
|
100 } |
|
101 |
|
102 /** |
|
103 * Replace the least numbered parameter in the string, which is not yet |
|
104 * replaced. |
|
105 * |
|
106 * @param number number to replace at the argument |
|
107 * @return same formatter |
|
108 */ |
|
109 public Formatter arg(int number) |
|
110 { |
|
111 String localisedNumber = _formatInteger(number); |
|
112 |
|
113 // Try to replace with patterns %nN, %n, %N |
|
114 if (replace("%" + nextIndex + "N", localisedNumber) || |
|
115 replace("%" + nextIndex, localisedNumber) || |
|
116 replace("%N", localisedNumber)) |
|
117 { |
|
118 nextIndex++; |
|
119 |
|
120 } |
|
121 else |
|
122 { |
|
123 Logger.WLOG(Logger.EUtils, "Integer replacement failed"); |
|
124 } |
|
125 return this; |
|
126 } |
|
127 |
|
128 /** |
|
129 * Replace the least numbered parameter in the string, which is not yet |
|
130 * replaced. |
|
131 * |
|
132 * @param ch character to replace at the argument |
|
133 * @return same formatter |
|
134 */ |
|
135 public Formatter arg(char ch) |
|
136 { |
|
137 String chString = new String(new char[] { ch }); |
|
138 |
|
139 // Try to replace with patterns %nC,%n, %C |
|
140 if (replace("%" + nextIndex + "C", chString) || |
|
141 replace("%" + nextIndex, chString) || |
|
142 replace("%C", chString)) |
|
143 { |
|
144 nextIndex++; |
|
145 |
|
146 } |
|
147 else |
|
148 { |
|
149 Logger.WLOG(Logger.EUtils, "Character replacement failed"); |
|
150 } |
|
151 return this; |
|
152 } |
|
153 |
|
154 /** |
|
155 * Replace the least numbered parameter in the string, which is not yet |
|
156 * replaced. Date is formatted according to current device date format. |
|
157 * |
|
158 * @param date date to replace at the argument |
|
159 * @return same formatter |
|
160 */ |
|
161 public Formatter arg(Date date) |
|
162 { |
|
163 String dateString = _formatDate(date.getTime()); |
|
164 return arg(dateString); |
|
165 } |
|
166 |
|
167 /** |
|
168 * Replace the least numbered parameter in the string, which is not yet |
|
169 * replaced. |
|
170 * |
|
171 * @param o object whose toString() will be used for argument position |
|
172 * @return same formatter |
|
173 */ |
|
174 public Formatter arg(Object o) |
|
175 { |
|
176 if (o != null) |
|
177 { |
|
178 if (o instanceof String) |
|
179 { |
|
180 return arg((String) o); |
|
181 } |
|
182 else if (o instanceof Integer) |
|
183 { |
|
184 return arg(((Integer) o).intValue()); |
|
185 } |
|
186 else if (o instanceof Character) |
|
187 { |
|
188 return arg(((Character) o).charValue()); |
|
189 } |
|
190 else if (o instanceof Date) |
|
191 { |
|
192 return arg((Date) o); |
|
193 } |
|
194 // Skip not supported types. |
|
195 } |
|
196 return this; |
|
197 } |
|
198 |
|
199 /** |
|
200 * Convert the current pattern to string, along with parameter |
|
201 * replacements. |
|
202 * |
|
203 * @return string where parameters are replaced |
|
204 */ |
|
205 public String toString() |
|
206 { |
|
207 String result = replaced; |
|
208 |
|
209 // Reset for next usage |
|
210 replaced = pattern; |
|
211 nextIndex = 0; |
|
212 |
|
213 return result; |
|
214 } |
|
215 |
|
216 /** |
|
217 * Gets a clone of this formatter. This can be used for caching preparsed |
|
218 * Formatters. |
|
219 * |
|
220 * @return clone of the formatter, as if new Formatter were created with |
|
221 * same pattern as current one. |
|
222 */ |
|
223 public Formatter getClone() |
|
224 { |
|
225 return new Formatter(pattern); |
|
226 } |
|
227 |
|
228 /** |
|
229 * Formats localised text with specified parameters from an array. |
|
230 * |
|
231 * Note that the arg().arg().toString() is preferred method of |
|
232 * usage. E.g. Date format type can not be defined with this method. |
|
233 * |
|
234 * @param textParameters parameters to be filled into the text |
|
235 * @return localised text formatted with the provided parameters |
|
236 */ |
|
237 public String format(Object[] textParameters) |
|
238 { |
|
239 if (textParameters != null) |
|
240 { |
|
241 for (int i = 0; i < textParameters.length; i++) |
|
242 { |
|
243 if (textParameters[i] instanceof String) |
|
244 { |
|
245 arg((String)textParameters[i]); |
|
246 } |
|
247 else if (textParameters[i] instanceof Integer) |
|
248 { |
|
249 arg(((Integer)textParameters[i]).intValue()); |
|
250 } |
|
251 else if (textParameters[i] instanceof Date) |
|
252 { |
|
253 arg((Date)textParameters[i]); |
|
254 } |
|
255 else |
|
256 { |
|
257 arg(textParameters[i]); |
|
258 } |
|
259 } |
|
260 } |
|
261 return toString(); |
|
262 } |
|
263 |
|
264 /*** ----------------------------- PRIVATE ---------------------------- */ |
|
265 |
|
266 /** |
|
267 * Replace first occurrence of the string pattern in the replaced field. |
|
268 * |
|
269 * @param pattern string to search for |
|
270 * @param replacement string to replace patterns |
|
271 * @return true if pattern was found and replaced, false if pattern was |
|
272 * not found |
|
273 */ |
|
274 private boolean replace(String pattern, String replacement) |
|
275 { |
|
276 int index = replaced.indexOf(pattern); |
|
277 if (index != -1) |
|
278 { |
|
279 if (replaced.indexOf(pattern + "[]") != -1) |
|
280 { |
|
281 replaced = |
|
282 replaced.substring(0, index) + replacement + |
|
283 replaced.substring(index + pattern.length() + 2); |
|
284 } |
|
285 else if (replaced.indexOf(pattern + "[") != -1) |
|
286 { |
|
287 return replaceWithMax(pattern, replacement, index); |
|
288 } |
|
289 else |
|
290 { |
|
291 replaced = |
|
292 replaced.substring(0, index) + replacement + |
|
293 replaced.substring(index + pattern.length()); |
|
294 } |
|
295 return true; |
|
296 } |
|
297 return false; |
|
298 } |
|
299 |
|
300 /** |
|
301 * Replace first occurrence of the string pattern in the replaced field. |
|
302 * Replace only [NN] defined amount of characters. |
|
303 * |
|
304 * @param pattern string to search for |
|
305 * @param replacement string to replace patterns |
|
306 * @param index of replacement tag. |
|
307 * @return true if pattern was found and replaced, false if pattern was |
|
308 * not found |
|
309 */ |
|
310 private boolean replaceWithMax(String pattern, String replacement, int maxIndex) |
|
311 { |
|
312 boolean result = false; |
|
313 int closingIndex = maxIndex + pattern.length() + 3; |
|
314 |
|
315 // Check format [NN] comply. If not skip. |
|
316 if (replaced.length() > closingIndex |
|
317 && replaced.charAt(closingIndex) == ']') |
|
318 { |
|
319 try |
|
320 { |
|
321 int maxLen = Integer.parseInt(replaced.substring( |
|
322 maxIndex + pattern.length() + 1, closingIndex)); |
|
323 |
|
324 if (maxLen > replacement.length()) |
|
325 { |
|
326 maxLen = replacement.length(); |
|
327 } |
|
328 |
|
329 replaced = replaced.substring(0, maxIndex) + |
|
330 replacement.substring(0, maxLen) + |
|
331 replaced.substring(maxIndex + pattern.length() + 4); |
|
332 result = true; |
|
333 } |
|
334 catch (NumberFormatException nfe) |
|
335 { |
|
336 Logger.WLOG(Logger.EUtils, "Replace with max failed to invalid" |
|
337 + " replacement amount"); |
|
338 } |
|
339 } |
|
340 return result; |
|
341 } |
|
342 |
|
343 /*** ----------------------------- NATIVE ----------------------------- */ |
|
344 |
|
345 /** |
|
346 * Format integer to current locale. |
|
347 * |
|
348 * @param number to be formatted. |
|
349 * @return number formatted as current locale String. |
|
350 */ |
|
351 private native String _formatInteger(int number); |
|
352 |
|
353 /** |
|
354 * Format date to current locale. |
|
355 * |
|
356 * @param timeInMilliSecs to be formatted. |
|
357 * @param format Date format. |
|
358 * @return date formatted as current locale String. |
|
359 * |
|
360 */ |
|
361 private native String _formatDate(long timeInMilliSecs); |
|
362 } |