34 * <LI>%nC - Character in position n |
34 * <LI>%nC - Character in position n |
35 * <LI>%C - Next character |
35 * <LI>%C - Next character |
36 * <LI>%n - Parameter in position n |
36 * <LI>%n - Parameter in position n |
37 * </UL> |
37 * </UL> |
38 * <br> |
38 * <br> |
|
39 * Supported parameters in Qt environment are: |
|
40 * <UL> |
|
41 * <LI>%1, %2, %3, ... - for String parameters |
|
42 * <LI>%L1, %L2, %L3, ... - for Integer parameters (%1, %2, %3, ... is also ok) |
|
43 * <LI>%Ln - for Integers indicating plurality |
|
44 * </UL> |
|
45 * <br> |
|
46 * Text parameter indices start from 0 when Avkon is used and from 1 |
|
47 * when Qt is used. One text can only contain one %Ln parameter. |
|
48 * <br> |
39 * Example of usage: |
49 * Example of usage: |
40 * <pre> |
50 * <pre> |
41 * Formatter formatter = new Formatter("You have %N email(s) left"); |
51 * Formatter formatter = resourceLoader.format("You have %N email(s) left"); |
42 * String message = formatter.arg(5).toString(); |
52 * String message = formatter.arg(5).toString(); |
43 * // Becomes :You have 5 email(s) left |
53 * // Becomes: You have 5 email(s) left |
44 * |
54 * |
45 * Formatter formatter = new Formatter("There are %N0 files in folder \"%U1\""); |
55 * Formatter formatter = new Formatter("There are %N0 files in folder \"%U1\""); |
46 * String message = formatter.arg(5).arg("photos").toString(); |
56 * String message = formatter.arg(5).arg("photos").toString(); |
47 * // Becomes :There are 5 files in folder "photos" |
57 * // Becomes: There are 5 files in folder "photos" |
48 * </pre> |
58 * </pre> |
49 * <br> |
59 * <br> |
50 * Limitation: more than 10 positional arguments are not supported (only 0...9) |
|
51 * <br> |
|
52 * Note that Formatter supports Avkon and Qt based localisation. |
|
53 * Text parameter indices start from 0 when Avkon is used and from 1 |
|
54 * when Qt is used. |
|
55 */ |
60 */ |
56 public class Formatter |
61 abstract public class Formatter |
57 { |
62 { |
58 /** Original pattern string */ |
|
59 private String pattern; |
|
60 |
|
61 /** String with latest replacements */ |
|
62 private String replaced; |
|
63 |
|
64 /** |
|
65 * Platform localisation type. |
|
66 * Either ResourceLoader.AVKON or ResourceLoader.QT. */ |
|
67 private final int locType; |
|
68 |
|
69 /** |
|
70 * The first text parameter replacement index. For Avkon based |
|
71 * localisation this is 0, for Qt based localisation this is 1. |
|
72 */ |
|
73 private final int startIndex; |
|
74 |
|
75 /** Next replacement index */ |
|
76 private int nextIndex; |
|
77 |
|
78 /*** ----------------------------- PUBLIC ------------------------------ */ |
63 /*** ----------------------------- PUBLIC ------------------------------ */ |
79 |
64 |
80 /** |
65 /** |
81 * Create a new formatter |
66 * Set the plurality for this Formatter. Note that this method does |
82 * |
67 * nothing when Avkon localisation is used. |
83 * @param pattern formatter pattern |
68 * |
84 */ |
69 * @param n number indicating plurality |
85 Formatter(String aPattern) |
70 * @return same formatter |
86 { |
71 */ |
87 this(aPattern, ResourceLoader.AVKON); |
72 public Formatter argn(int n) |
88 } |
73 { |
89 |
74 return this; |
90 /** |
|
91 * Create a new formatter |
|
92 * |
|
93 * @param pattern formatter pattern |
|
94 * @param aLocType platform localisation type |
|
95 */ |
|
96 Formatter(String aPattern, int aLocType) |
|
97 { |
|
98 pattern = aPattern; |
|
99 replaced = aPattern; |
|
100 locType = aLocType; |
|
101 startIndex = (locType == ResourceLoader.QT? 1: 0); |
|
102 nextIndex = startIndex; |
|
103 } |
75 } |
104 |
76 |
105 /** |
77 /** |
106 * Replace the lowest numbered parameter in the string, which is not yet |
78 * Replace the lowest numbered parameter in the string, which is not yet |
107 * replaced. |
79 * replaced. |
108 * |
80 * |
109 * @param string string to replace at the argument |
81 * @param string string to replace at the argument |
110 * @return same formatter |
82 * @return same formatter |
111 */ |
83 */ |
112 public Formatter arg(String string) |
84 abstract public Formatter arg(String string); |
113 { |
|
114 // Try to replace with patterns %[N...N]n, %nU, %n, %U |
|
115 String maxPattern = findMaxPattern(); |
|
116 if ((maxPattern != null && replace(maxPattern, string)) || |
|
117 replace("%" + nextIndex + "U", string) || |
|
118 replace("%" + nextIndex, string) || |
|
119 replace("%U", string)) |
|
120 { |
|
121 nextIndex++; |
|
122 } |
|
123 else |
|
124 { |
|
125 Logger.WLOG(Logger.EUtils, |
|
126 "String replacement failed on parameter " + |
|
127 nextIndex + ": " + pattern); |
|
128 } |
|
129 return this; |
|
130 } |
|
131 |
85 |
132 /** |
86 /** |
133 * Replace the least numbered parameter in the string, which is not yet |
87 * Replace the least numbered parameter in the string, which is not yet |
134 * replaced. |
88 * replaced. |
135 * |
89 * |
136 * @param number number to replace at the argument |
90 * @param number number to replace at the argument |
137 * @return same formatter |
91 * @return same formatter |
138 */ |
92 */ |
139 public Formatter arg(int number) |
93 abstract public Formatter arg(int number); |
140 { |
|
141 String localisedNumber = _formatInteger(number); |
|
142 |
|
143 // Try to replace with patterns %[N...N]n, %Ln, %nN, %n, %N |
|
144 String maxPattern = findMaxPattern(); |
|
145 if ((maxPattern != null && replace(maxPattern, localisedNumber)) || |
|
146 replace("%" + "L" + nextIndex, localisedNumber) || |
|
147 replace("%" + nextIndex + "N", localisedNumber) || |
|
148 replace("%" + nextIndex, localisedNumber) || |
|
149 replace("%N", localisedNumber)) |
|
150 { |
|
151 nextIndex++; |
|
152 |
|
153 } |
|
154 else |
|
155 { |
|
156 Logger.WLOG(Logger.EUtils, |
|
157 "Integer replacement failed on parameter " + |
|
158 nextIndex + ": " + pattern); |
|
159 } |
|
160 return this; |
|
161 } |
|
162 |
94 |
163 /** |
95 /** |
164 * Replace the least numbered parameter in the string, which is not yet |
96 * Replace the least numbered parameter in the string, which is not yet |
165 * replaced. |
97 * replaced. |
166 * |
98 * |
167 * @param ch character to replace at the argument |
99 * @param ch character to replace at the argument |
168 * @return same formatter |
100 * @return same formatter |
169 */ |
101 */ |
170 public Formatter arg(char ch) |
102 abstract public Formatter arg(char ch); |
171 { |
|
172 String chString = new String(new char[] { ch }); |
|
173 |
|
174 // Try to replace with patterns %nC, %n, %C |
|
175 if (replace("%" + nextIndex + "C", chString) || |
|
176 replace("%" + nextIndex, chString) || |
|
177 replace("%C", chString)) |
|
178 { |
|
179 nextIndex++; |
|
180 |
|
181 } |
|
182 else |
|
183 { |
|
184 Logger.WLOG(Logger.EUtils, |
|
185 "Character replacement failed on parameter " + |
|
186 nextIndex + ": " + pattern); |
|
187 } |
|
188 return this; |
|
189 } |
|
190 |
103 |
191 /** |
104 /** |
192 * Replace the least numbered parameter in the string, which is not yet |
105 * Replace the least numbered parameter in the string, which is not yet |
193 * replaced. Date is formatted according to current device date format. |
106 * replaced. Date is formatted according to current device date format. |
194 * |
107 * |
195 * @param date date to replace at the argument |
108 * @param date date to replace at the argument |
196 * @return same formatter |
109 * @return same formatter |
197 */ |
110 */ |
198 public Formatter arg(Date date) |
111 abstract public Formatter arg(Date date); |
199 { |
112 |
200 String dateString = _formatDate(date.getTime()); |
113 /** |
201 return arg(dateString); |
114 * Replace the least numbered parameter in the string, which is not yet |
202 } |
115 * replaced. |
203 |
116 * |
204 /** |
117 * @param o object which will be used for argument position |
205 * Replace the least numbered parameter in the string, which is not yet |
|
206 * replaced. |
|
207 * |
|
208 * @param o object whose toString() will be used for argument position |
|
209 * @return same formatter |
118 * @return same formatter |
210 */ |
119 */ |
211 public Formatter arg(Object o) |
120 public Formatter arg(Object o) |
212 { |
121 { |
213 if (o != null) |
122 if (o != null) |
293 * @return A string identical with the provided string but with the |
178 * @return A string identical with the provided string but with the |
294 * european digits (if any) converted to arabic-indic digits |
179 * european digits (if any) converted to arabic-indic digits |
295 */ |
180 */ |
296 public static String formatDigits(String str) |
181 public static String formatDigits(String str) |
297 { |
182 { |
298 return _formatDigits(str); |
183 if (ResourceLoader.getLocaleIdQt() == null) |
|
184 { |
|
185 return FormatterAvkon.formatDigits(str); |
|
186 } |
|
187 else |
|
188 { |
|
189 return FormatterQt.formatDigits(str); |
|
190 } |
|
191 } |
|
192 |
|
193 /*** ----------------------------- PROTECTED -------------------------- */ |
|
194 |
|
195 /** |
|
196 * Default constructor. |
|
197 */ |
|
198 protected Formatter() |
|
199 { |
299 } |
200 } |
300 |
201 |
301 /*** ----------------------------- PRIVATE ---------------------------- */ |
202 /*** ----------------------------- PRIVATE ---------------------------- */ |
302 |
203 |
303 /** |
|
304 * Replace first occurrence of the string pattern in the replaced field. |
|
305 * |
|
306 * @param pattern string to search for |
|
307 * @param replacement string to replace patterns |
|
308 * @return true if pattern was found and replaced, false if pattern was |
|
309 * not found |
|
310 */ |
|
311 private boolean replace(String pattern, String replacement) |
|
312 { |
|
313 int index = replaced.indexOf(pattern); |
|
314 if (index != -1) |
|
315 { |
|
316 if (replaced.indexOf(pattern + "[]") != -1) |
|
317 { |
|
318 replaced = |
|
319 replaced.substring(0, index) + replacement + |
|
320 replaced.substring(index + pattern.length() + 2); |
|
321 } |
|
322 else if (replaced.indexOf(pattern + "[") != -1) |
|
323 { |
|
324 return replaceWithMax(pattern, replacement, index); |
|
325 } |
|
326 else |
|
327 { |
|
328 replaced = |
|
329 replaced.substring(0, index) + replacement + |
|
330 replaced.substring(index + pattern.length()); |
|
331 } |
|
332 return true; |
|
333 } |
|
334 return false; |
|
335 } |
|
336 |
|
337 /** |
|
338 * Replace first occurrence of the string pattern in the replaced field. |
|
339 * Replace [N...N] defined amount of characters. |
|
340 * |
|
341 * @param pattern string to search for |
|
342 * @param replacement string to replace patterns |
|
343 * @param index of replacement tag. |
|
344 * @return true if pattern was found and replaced, false if pattern was |
|
345 * not found |
|
346 */ |
|
347 private boolean replaceWithMax(String pattern, String replacement, int maxIndex) |
|
348 { |
|
349 boolean result = false; |
|
350 int closingIndex = replaced.indexOf("]", maxIndex + pattern.length()); |
|
351 |
|
352 // Check format [N...N] comply. If not skip. |
|
353 if (closingIndex > 0) |
|
354 { |
|
355 try |
|
356 { |
|
357 int maxLen = Integer.parseInt(replaced.substring( |
|
358 maxIndex + pattern.length() + 1, closingIndex)); |
|
359 |
|
360 if (maxLen > replacement.length()) |
|
361 { |
|
362 maxLen = replacement.length(); |
|
363 } |
|
364 |
|
365 replaced = replaced.substring(0, maxIndex) + |
|
366 replacement.substring(0, maxLen) + |
|
367 replaced.substring(closingIndex + 1); |
|
368 result = true; |
|
369 } |
|
370 catch (NumberFormatException nfe) |
|
371 { |
|
372 Logger.WLOG(Logger.EUtils, "Replace with max failed to invalid" |
|
373 + " replacement amount"); |
|
374 } |
|
375 } |
|
376 return result; |
|
377 } |
|
378 |
|
379 /** |
|
380 * Finds next %[N...N]n pattern from the replaced field. |
|
381 * Returns found pattern, or null if no pattern was found. |
|
382 */ |
|
383 private String findMaxPattern() |
|
384 { |
|
385 String result = null; |
|
386 String startPattern = "%["; |
|
387 String endPattern = "]" + nextIndex; |
|
388 int startIndex = replaced.indexOf(startPattern); |
|
389 if (startIndex >= 0) |
|
390 { |
|
391 int endIndex = replaced.indexOf(endPattern, startIndex); |
|
392 if (endIndex >= 0) |
|
393 { |
|
394 result = replaced.substring( |
|
395 startIndex, endIndex + endPattern.length()); |
|
396 } |
|
397 } |
|
398 return result; |
|
399 } |
|
400 |
|
401 /*** ----------------------------- NATIVE ----------------------------- */ |
204 /*** ----------------------------- NATIVE ----------------------------- */ |
402 |
|
403 /** |
|
404 * Format integer to current locale. |
|
405 * |
|
406 * @param number to be formatted. |
|
407 * @return number formatted as current locale String. |
|
408 */ |
|
409 private native String _formatInteger(int number); |
|
410 |
|
411 /** |
|
412 * Format date to current locale. |
|
413 * |
|
414 * @param timeInMilliSecs to be formatted. |
|
415 * @param format Date format. |
|
416 * @return date formatted as current locale String. |
|
417 * |
|
418 */ |
|
419 private native String _formatDate(long timeInMilliSecs); |
|
420 |
|
421 /** |
|
422 * Applies convertion from european digits into arabic-indic digits |
|
423 * based on existing language settings |
|
424 * |
|
425 * @param str String which might contain european digits |
|
426 * @return A string identical with the provided string but with the |
|
427 * european digits (if any) converted to arabic-indic digits |
|
428 */ |
|
429 private static native String _formatDigits(String str); |
|
430 } |
205 } |