diff -r e8e63152f320 -r 2a9601315dfc javacommons/utils/javasrc/com/nokia/mj/impl/utils/ResourceLoader.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/javacommons/utils/javasrc/com/nokia/mj/impl/utils/ResourceLoader.java Mon May 03 12:27:20 2010 +0300 @@ -0,0 +1,369 @@ +/* +* Copyright (c) 2008-2010 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.io.*; +import java.util.*; + +/** + * Resource loader to get localised strings and Formatter patterns. + *
+ * Usage: + *
+ *   ResourceLoader res = new ResourceLoader("javainstaller", "qtn_java_installer_");
+ *   Label subjectLabel = createLabel(
+ *       res.format("subject").arg(certificate.getSubject()).toString(),
+ *       horizontalSpan, labelStyle);
+ *
+ *   Label noteLabel = createLabel(
+ *       res.string("note"), horizontalSpan, labelStyle);
+ * 
+ * + * @author Nokia Corporation + * @version 1.0 + */ +public class ResourceLoader +{ + /** Localisation resource basepath */ + private static final String LOC_RESOURCE_BASE = "/resources/com/nokia/mj/impl/"; + + /** Map for ResourceLoader instances. */ + private static Hashtable resourceLoaders = new Hashtable(); + + /** Resource string map. Null if resource could not be loaded. */ + private Hashtable resourceMap = new Hashtable(); + + /** Resource name prefix */ + private String prefix; + + /*** ----------------------------- PUBLIC ------------------------------ */ + + /** + * Returns a resource loader instance. + * + * @param resourceName name of the resource + * @param prefix prefix added before each id when retrieving + * @return resource loader instance + */ + public static ResourceLoader getInstance(String resourceName, String prefix) + { + String key = resourceName + ":" + prefix; + ResourceLoader result = (ResourceLoader)resourceLoaders.get(key); + if (result == null) + { + result = new ResourceLoader(resourceName, prefix); + resourceLoaders.put(key, result); + } + return result; + } + + /** + * Creates resource loader, using the current locale of the environment. + * + * @param resourceName name of the resource + * @param aPrefix prefix added before each id when retrieving + */ + public ResourceLoader(String resourceName, String aPrefix) + { + prefix = aPrefix; + loadFile(resourceName); + } + + /** + * Get a string formatter of a given resource id. + * + * @param id resource id + * @return formatter instance + * @see Formatter + */ + public Formatter format(String id) + { + return new Formatter(string(id)); + } + + /** + * Formats localised text with specified parameters from an array. + * + * @param id resource id + * @param textParameters parameters to be filled into the text + * @return localised text formatted with the provided parameters + * @see Formatter + */ + public String format(String id, Object[] textParameters) + { + return new Formatter(string(id)).format(textParameters); + } + + /** + * Get a plain string resource with a given resource id. + * + * @param id resource id, either with prefix or without + * @return resource string, or the id if does not exist + */ + public String string(String id) + { + String str = (String)resourceMap.get(id); + if (str == null) + { + // Try with prefix + str = (String)resourceMap.get(prefix + id); + if (str == null) + { + // Not found even with prefix. Use the id itself + if (!id.startsWith(prefix)) + { + str = prefix + id; + } + else + { + str = id; + } + + Logger.WLOG(Logger.EUtils, "Cannot find resource: " + id); + } + + // Put back to hash with original key for quick retrieval + resourceMap.put(id, str); + } + + str = decode(str); + str = replaceCharacterCodes(str); + + return str; + } + + /** + * Gets the locale ID currently being used on the phone. This can be used + * e.g. to load a localized icon file, by adding the locale id as suffix. + * + * @return Locale ID as provided by the platform + */ + public String getLocaleId() + { + int localeId = _getLocaleId(); + if (localeId > 0) + { + if (localeId < 10) + { + // Ensure that the returned locale ID has at least two digits. + return "0" + Integer.toString(localeId); + } + else + { + return Integer.toString(localeId); + } + } + return "sc"; + } + + /*** ----------------------------- PRIVATE ---------------------------- */ + + /** + * Loads the resources from .loc type file + */ + private void loadFile(String resourceName) + { + InputStream is = null; + + // Load with real locale id + is = this.getClass().getResourceAsStream( + LOC_RESOURCE_BASE + resourceName + "_" + getLocaleId() + ".loc"); + if (is == null) + { + // Load the engineering english + is = this.getClass().getResourceAsStream( + LOC_RESOURCE_BASE + resourceName + "_sc" + ".loc"); + } + if (is == null) + { + // Load the reference engineering english + is = this.getClass().getResourceAsStream( + LOC_RESOURCE_BASE + resourceName + ".loc"); + } + if (is == null) + { + Logger.WLOG(Logger.EUtils, + "Cannot load resource file: " + resourceName); + return; + } + + try + { + // Loc-files area always on UTF8 format + LineReader lr = new LineReader( + new BufferedReader(new InputStreamReader(is, "UTF-8"))); + String line; + + while ((line = lr.readLine()) != null) + { + // Ignore lines which are not #define's + if (!line.startsWith("#define ")) + { + continue; + } + try + { + // Skip "#define" + any whitespace + line = line.substring(line.indexOf(' ')).trim(); + + int idEnd = line.indexOf(' '); + String id = line.substring(0, idEnd); + + int strStart = line.indexOf('"', idEnd); + int strEnd = line.lastIndexOf('"'); + String str = line.substring(strStart + 1, strEnd); + + resourceMap.put(id, str); + + } + catch (IndexOutOfBoundsException ex) + { + String error = "Incorrect line " + lr.getLineNumber() + "\"" + + line + "\""; + Logger.WLOG(Logger.EUtils, error); + } + } + is.close(); + + } + catch (IOException ex) + { + Logger.WLOG(Logger.EUtils, + "Resource file " + resourceName + " handling failed: " + + ex.getMessage()); + } + } + + /** + * Decode given string. Decoding means unescaping escaped characters. + * Currently \n, \t, \', \\ and \" patterns are decoded to respective + * characters. + * + * @param str to be decoded. + * @return decoded String. + */ + private String decode(String str) + { + str = replacePattern(str, "\\n", '\n'); + str = replacePattern(str, "\\\\", '\\'); + str = replacePattern(str, "\\\"", '\"'); + str = replacePattern(str, "\\t", '\t'); + str = replacePattern(str, "\\'", '\''); + + return str; + } + + /** + * Replace all occurrences of the pattern in the given String. + * + * @param resource string to be replaced. + * @param pattern to replace. + * @param replacement replacement character. + * @return String where all occurrences of the pattern are replaced. + */ + private String replacePattern( + String resource, String pattern, char replacement) + { + StringBuffer sb = new StringBuffer(); + + int startIndex = resource.indexOf(pattern); + if (startIndex != -1) + { + sb.append(resource.substring(0, startIndex)).append(replacement); + startIndex = startIndex + pattern.length(); + int endIndex = 0; + + while ((endIndex = resource.indexOf(pattern, startIndex)) != -1) + { + sb.append(resource.substring(startIndex, endIndex)) + .append(replacement); + startIndex = endIndex + pattern.length(); + } + + if (startIndex < resource.length()) + { + sb.append(resource.substring(startIndex, resource.length())); + } + return sb.toString(); + } + return resource; + } + + /** + * Replace character codes. They are given as <0x0000> format. Where 0x0000 + * contains character unicode as hex representation. + * + * @param str to replace characters. + * @return String where characters are replaced. + */ + private String replaceCharacterCodes(String str) + { + StringBuffer sb = new StringBuffer(); + int startIndex = str.indexOf("<0x"); + + if (startIndex != -1 && str.charAt(startIndex + 7) == '>') + { + sb.append(str.substring(0, startIndex)); + try + { + int charint = Integer.parseInt( + str.substring(startIndex + 3, startIndex + 7), 16); + sb.append((char) charint); + + int endIndex = 0; + startIndex+= 7; + + while ((endIndex = str.indexOf("<0x", startIndex)) != -1 + && str.charAt(endIndex + 7) == '>') + { + sb.append(str.substring(startIndex + 1, endIndex)); + + charint = Integer.parseInt( + str.substring(endIndex + 3, endIndex + 7), 16); + sb.append((char) charint); + startIndex = endIndex + 7; + } + } + catch (NumberFormatException nfe) + { + Logger.ELOG(Logger.EUtils, + "Cannot replace character from string: " + str); + return str; + } + + if (startIndex < str.length()) + { + sb.append(str.substring(startIndex + 1, str.length())); + } + return sb.toString(); + } + return str; + } + + + /*** ----------------------------- NATIVE ----------------------------- */ + + /** + * Get device language code. + * + * @return languege code. + */ + private native int _getLocaleId(); + +}