diff -r f5050f1da672 -r 04becd199f91 javacommons/utils/javasrc/com/nokia/mj/impl/utils/Formatter.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/javacommons/utils/javasrc/com/nokia/mj/impl/utils/Formatter.java Tue Apr 27 16:30:29 2010 +0300 @@ -0,0 +1,362 @@ +/* +* Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies). +* All rights reserved. +* This component and the accompanying materials are made available +* under the terms of "Eclipse Public License v1.0" +* which accompanies this distribution, and is available +* at the URL "http://www.eclipse.org/legal/epl-v10.html". +* +* Initial Contributors: +* Nokia Corporation - initial contribution. +* +* Contributors: +* +* Description: +* +*/ + + +package com.nokia.mj.impl.utils; + +import java.util.Date; + +/** + * Utility for formatting text strings from a pattern with positional + * parameters. + *
+ * Supported parameters are: + * + *
+ * Example of usage: + *
+ *   Formatter formatter = new Formatter("You have %N email(s) left");
+ *   String message = formatter.arg(5).toString();
+ *   // Becomes :You have 5 email(s) left
+ *
+ *   Formatter formatter = new Formatter("There are %N0 files in folder \"%U1\"");
+ *   String message = formatter.arg(5).arg("photos").toString();
+ *   // Becomes :There are 5 files in folder "photos"
+ * 
+ *
+ * Limitation: more than 10 positional arguments are not supported (only 0...9) + * + * @author Nokia Corporation + * @version 1.0 + */ +public class Formatter +{ + /** Original pattern string */ + private String pattern; + + /** String with latest replacements */ + private String replaced; + + /** Next replacement index */ + private int nextIndex = 0; + + /*** ----------------------------- PUBLIC ------------------------------ */ + + /** + * Create a new formatter + * + * @param pattern formatter pattern + */ + public Formatter(String aPattern) + { + pattern = aPattern; + replaced = aPattern; + } + + /** + * Replace the lowest numbered parameter in the string, which is not yet + * replaced. + * + * @param string string to replace at the argument + * @return same formatter + */ + public Formatter arg(String string) + { + // Try to replace with patterns %nU,%n, %U + if (replace("%" + nextIndex + "U", string) || + replace("%" + nextIndex, string) || + replace("%U", string)) + { + nextIndex++; + + } + else + { + Logger.WLOG(Logger.EUtils, "String replacement failed"); + } + return this; + } + + /** + * Replace the least numbered parameter in the string, which is not yet + * replaced. + * + * @param number number to replace at the argument + * @return same formatter + */ + public Formatter arg(int number) + { + String localisedNumber = _formatInteger(number); + + // Try to replace with patterns %nN, %n, %N + if (replace("%" + nextIndex + "N", localisedNumber) || + replace("%" + nextIndex, localisedNumber) || + replace("%N", localisedNumber)) + { + nextIndex++; + + } + else + { + Logger.WLOG(Logger.EUtils, "Integer replacement failed"); + } + return this; + } + + /** + * Replace the least numbered parameter in the string, which is not yet + * replaced. + * + * @param ch character to replace at the argument + * @return same formatter + */ + public Formatter arg(char ch) + { + String chString = new String(new char[] { ch }); + + // Try to replace with patterns %nC,%n, %C + if (replace("%" + nextIndex + "C", chString) || + replace("%" + nextIndex, chString) || + replace("%C", chString)) + { + nextIndex++; + + } + else + { + Logger.WLOG(Logger.EUtils, "Character replacement failed"); + } + return this; + } + + /** + * Replace the least numbered parameter in the string, which is not yet + * replaced. Date is formatted according to current device date format. + * + * @param date date to replace at the argument + * @return same formatter + */ + public Formatter arg(Date date) + { + String dateString = _formatDate(date.getTime()); + return arg(dateString); + } + + /** + * Replace the least numbered parameter in the string, which is not yet + * replaced. + * + * @param o object whose toString() will be used for argument position + * @return same formatter + */ + public Formatter arg(Object o) + { + if (o != null) + { + if (o instanceof String) + { + return arg((String) o); + } + else if (o instanceof Integer) + { + return arg(((Integer) o).intValue()); + } + else if (o instanceof Character) + { + return arg(((Character) o).charValue()); + } + else if (o instanceof Date) + { + return arg((Date) o); + } + // Skip not supported types. + } + return this; + } + + /** + * Convert the current pattern to string, along with parameter + * replacements. + * + * @return string where parameters are replaced + */ + public String toString() + { + String result = replaced; + + // Reset for next usage + replaced = pattern; + nextIndex = 0; + + return result; + } + + /** + * Gets a clone of this formatter. This can be used for caching preparsed + * Formatters. + * + * @return clone of the formatter, as if new Formatter were created with + * same pattern as current one. + */ + public Formatter getClone() + { + return new Formatter(pattern); + } + + /** + * Formats localised text with specified parameters from an array. + * + * Note that the arg().arg().toString() is preferred method of + * usage. E.g. Date format type can not be defined with this method. + * + * @param textParameters parameters to be filled into the text + * @return localised text formatted with the provided parameters + */ + public String format(Object[] textParameters) + { + if (textParameters != null) + { + for (int i = 0; i < textParameters.length; i++) + { + if (textParameters[i] instanceof String) + { + arg((String)textParameters[i]); + } + else if (textParameters[i] instanceof Integer) + { + arg(((Integer)textParameters[i]).intValue()); + } + else if (textParameters[i] instanceof Date) + { + arg((Date)textParameters[i]); + } + else + { + arg(textParameters[i]); + } + } + } + return toString(); + } + + /*** ----------------------------- PRIVATE ---------------------------- */ + + /** + * Replace first occurrence of the string pattern in the replaced field. + * + * @param pattern string to search for + * @param replacement string to replace patterns + * @return true if pattern was found and replaced, false if pattern was + * not found + */ + private boolean replace(String pattern, String replacement) + { + int index = replaced.indexOf(pattern); + if (index != -1) + { + if (replaced.indexOf(pattern + "[]") != -1) + { + replaced = + replaced.substring(0, index) + replacement + + replaced.substring(index + pattern.length() + 2); + } + else if (replaced.indexOf(pattern + "[") != -1) + { + return replaceWithMax(pattern, replacement, index); + } + else + { + replaced = + replaced.substring(0, index) + replacement + + replaced.substring(index + pattern.length()); + } + return true; + } + return false; + } + + /** + * Replace first occurrence of the string pattern in the replaced field. + * Replace only [NN] defined amount of characters. + * + * @param pattern string to search for + * @param replacement string to replace patterns + * @param index of replacement tag. + * @return true if pattern was found and replaced, false if pattern was + * not found + */ + private boolean replaceWithMax(String pattern, String replacement, int maxIndex) + { + boolean result = false; + int closingIndex = maxIndex + pattern.length() + 3; + + // Check format [NN] comply. If not skip. + if (replaced.length() > closingIndex + && replaced.charAt(closingIndex) == ']') + { + try + { + int maxLen = Integer.parseInt(replaced.substring( + maxIndex + pattern.length() + 1, closingIndex)); + + if (maxLen > replacement.length()) + { + maxLen = replacement.length(); + } + + replaced = replaced.substring(0, maxIndex) + + replacement.substring(0, maxLen) + + replaced.substring(maxIndex + pattern.length() + 4); + result = true; + } + catch (NumberFormatException nfe) + { + Logger.WLOG(Logger.EUtils, "Replace with max failed to invalid" + + " replacement amount"); + } + } + return result; + } + + /*** ----------------------------- NATIVE ----------------------------- */ + + /** + * Format integer to current locale. + * + * @param number to be formatted. + * @return number formatted as current locale String. + */ + private native String _formatInteger(int number); + + /** + * Format date to current locale. + * + * @param timeInMilliSecs to be formatted. + * @param format Date format. + * @return date formatted as current locale String. + * + */ + private native String _formatDate(long timeInMilliSecs); +}