javacommons/utils/javasrc/com/nokia/mj/impl/utils/ResourceLoaderAvkon.java
changeset 80 d6dafc5d983f
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/javacommons/utils/javasrc/com/nokia/mj/impl/utils/ResourceLoaderAvkon.java	Fri Oct 15 12:29:39 2010 +0300
@@ -0,0 +1,547 @@
+/*
+* 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.InputStream;
+import java.io.InputStreamReader;
+import java.io.IOException;
+import java.util.Hashtable;
+
+/**
+ * Resource loader to get localised strings and Formatter patterns.
+ * <br>
+ * Usage:
+ * <pre>
+ *   ResourceLoader res = ResourceLoader.getInstance("javainstaller", "qtn_java_installer_");
+ *   Label subjectLabel = createLabel(
+ *       res.format("subject").arg(certificate.getSubject()).toString(),
+ *       horizontalSpan, labelStyle);
+ * </pre>
+ * @see ResourceLoader
+ */
+class ResourceLoaderAvkon extends ResourceLoader
+{
+    /** Localisation resource basepath */
+    private static final String LOC_RESOURCE_BASE = "/resources/com/nokia/mj/impl/";
+
+    /**
+     * Resource string map for the resources that have been fetched
+     * at least once.
+     */
+    private Hashtable iResourceMap = new Hashtable();
+
+    /**
+     * Resource string maps for resources read from each resource file
+     * specified in comma separated list of resource file names.
+     */
+    private Hashtable[] iResourceMaps = null;
+
+    /** Resource name prefix passed when ResourceLoader is constructed. */
+    private String iPrefix = null;
+
+    /** Array of resource name prefixes. */
+    private String[] iPrefixes = null;
+
+    /** Platform localisation type. */
+    private int iLocType = -1;
+
+    /*** ----------------------------- PUBLIC ------------------------------ */
+
+    /**
+     * Returns a resource loader instance.
+     *
+     * @param avkonFileName name of the Avkon resource file
+     * @param avkonPrefix prefix added before each id when retrieving
+     * @param qtFileName name of the Qt resource file
+     * @param qtPrefix prefix added before each id when retrieving
+     * @return resource loader instance
+     */
+    public static ResourceLoader getInstance(String avkonFileName,
+                                             String avkonPrefix,
+                                             String qtFileName,
+                                             String qtPrefix)
+    {
+        // Construct key from filenames and prefixes, this is the same
+        // between platforms.
+        String key = (new StringBuffer()).append(avkonFileName).append(":")
+            .append(avkonPrefix).append(":").append(qtFileName).append(":")
+            .append(qtPrefix).toString();
+        ResourceLoader result = (ResourceLoader)iResourceLoaders.get(key);
+        if (result == null)
+        {
+            result = new ResourceLoaderAvkon(
+                avkonFileName, avkonPrefix, qtFileName, qtPrefix);
+            iResourceLoaders.put(key, result);
+        }
+        return result;
+    }
+
+    /**
+     * Returns a resource loader instance.
+     *
+     * @param resourceName comma separated list of resource file names
+     * @param prefix comma separated list of prefixes 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)iResourceLoaders.get(key);
+        if (result == null)
+        {
+            result = new ResourceLoaderAvkon(resourceName, prefix);
+            iResourceLoaders.put(key, result);
+        }
+        return result;
+    }
+
+    /**
+     * Get a string formatter of a given resource id.
+     *
+     * @param id comma separated list of resource ids
+     * @return formatter instance
+     * @see Formatter
+     */
+    public Formatter format(String id)
+    {
+        return new FormatterAvkon(string(id), iLocType);
+    }
+
+    /**
+     * Get a string formatter of a given resource id.
+     *
+     * @param id resource id
+     * @return formatter instance
+     * @see Formatter
+     */
+    public Formatter format(Id id)
+    {
+        return new FormatterAvkon(string(id.getString(iLocType)), iLocType);
+    }
+
+    /**
+     * Formats localised text with specified parameters from an array.
+     *
+     * @param id comma separated list of resource ids
+     * @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 FormatterAvkon(string(id), iLocType).format(textParameters);
+    }
+
+    /**
+     * 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(Id id, Object[] textParameters)
+    {
+        return new FormatterAvkon(string(id.getString(iLocType)), iLocType).format(textParameters);
+    }
+
+
+    /*** ----------------------------- PRIVATE ---------------------------- */
+
+    /**
+     * 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
+     */
+    private String string(String id)
+    {
+        String str = (String)iResourceMap.get(id);
+        if (str == null)
+        {
+            str = getResourceStringByList(id);
+            // Put to resource map with original key for quick retrieval.
+            str = decode(str);
+            str = replaceCharacterCodes(str);
+            iResourceMap.put(id, str);
+        }
+        return str;
+    }
+
+    /**
+     * Private constructor. Loads localisation resource file.
+     * On Avkon UI it's resources are loaded. On Qt platfor it's
+     * resource is first read and if that fails Avkon one is read.
+     *
+     * @param avkonFileName Avkon localisation resource file.
+     * @param avkonPrefix   Avkon logical string prefix.
+     * @param qtFileName    Qt localisation resource file.
+     * @param qtPrefix      Qt logical string prefix.
+     */
+    private ResourceLoaderAvkon(String avkonFileName, String avkonPrefix,
+                                String qtFileName, String qtPrefix)
+    {
+        String localeId = getLocaleIdQt();
+        if (localeId == null)
+        {
+            iLocType = AVKON;
+            setPrefix(avkonPrefix);
+            loadFiles(avkonFileName, true);
+        }
+        else
+        {
+            if (!loadFiles(qtFileName, false))
+            {
+                // Fallback to Avkon
+                iLocType = AVKON;
+                setPrefix(avkonPrefix);
+                loadFiles(avkonFileName, true);
+            }
+            else
+            {
+                iLocType = QT;
+                setPrefix(qtPrefix);
+            }
+        }
+    }
+
+    /**
+     * 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
+     */
+    private ResourceLoaderAvkon(String resourceName, String aPrefix)
+    {
+        iLocType = AVKON;
+        setPrefix(aPrefix);
+        loadFiles(resourceName, true); // Avkon
+    }
+
+    /**
+     * Initializes member variables according to given prefix.
+     *
+     * @param aPrefix comma separated list of text id prefixes
+     */
+    private void setPrefix(String aPrefix)
+    {
+        iPrefix = aPrefix;
+        iPrefixes = Tokenizer.split(iPrefix, SEPARATOR);
+        if (iPrefixes == null)
+        {
+            iPrefixes = new String[0];
+        }
+        for (int i = 0; i < iPrefixes.length; i++)
+        {
+            iPrefixes[i] = iPrefixes[i].trim();
+        }
+    }
+
+    /**
+     * Loads the resources from .loc type files.
+     *
+     * @param resourceNames comma separated list of resource filenames.
+     * @param avkon true if Avkon based localisation is in use
+     * @param true if operation succeed.
+     */
+    private boolean loadFiles(String resourceNames, boolean avkon)
+    {
+        if (resourceNames == null)
+        {
+            return false;
+        }
+        boolean result = false;
+        String[] filenames = Tokenizer.split(resourceNames, SEPARATOR);
+        iResourceMaps = new Hashtable[filenames.length];
+        for (int i = 0; i < filenames.length; i++)
+        {
+            iResourceMaps[i] = new Hashtable();
+            if (loadFile(filenames[i].trim(), avkon, iResourceMaps[i]))
+            {
+                // Return true if loading succeeds for at least one file.
+                result = true;
+            }
+        }
+        return result;
+    }
+
+    /**
+     * Loads the resources from .loc type file.
+     *
+     * @param resourceName name of the resource file
+     * @param avkon true if Avkon based localisation is in use
+     * @param resourceMap Map where the resources are stored to
+     * @param true if operation succeed.
+     */
+    private boolean loadFile(String resourceName, boolean avkon, Hashtable resourceMap)
+    {
+        InputStream is = null;
+
+        if (!avkon)  // Qt resources.
+        {
+            String langName = getLocaleIdQt();
+
+            // Emulator returns falsely en_GB as engineering English locale name.
+            if (langName.equals("en_GB"))
+            {
+                langName = "en";
+            }
+
+            // Load with real locale id
+            is = this.getClass().getResourceAsStream(
+                LOC_RESOURCE_BASE + resourceName + "_" + langName + ".loc");
+
+            if (is == null)
+            {
+                // Load the reference without locale id
+                is = this.getClass().getResourceAsStream(
+                         LOC_RESOURCE_BASE + resourceName + ".loc");
+            }
+            if (is == null)
+            {
+                /*
+                 * Does not exist. No need to continue as avkon file cannot
+                 * found using qt name.
+                 */
+                return false;
+            }
+        }
+        else  // Avkon resources.
+        {
+            // 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,
+                            "ResourceLoaderAvkon: Cannot load resource file: " +
+                            resourceName);
+                return false;
+            }
+        }
+
+        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);
+
+                    str = decode(str);
+                    str = replaceCharacterCodes(str);
+                    resourceMap.put(id, str);
+
+                }
+                catch (IndexOutOfBoundsException ex)
+                {
+                    String error = "ResourceLoaderAvkon: Incorrect line " +
+                        resourceName + ":" + lr.getLineNumber() + "\"" +
+                        line + "\"";
+                    Logger.WLOG(Logger.EUtils, error);
+                }
+            }
+            is.close();
+
+        }
+        catch (IOException ex)
+        {
+            Logger.WLOG(Logger.EUtils,
+                        "ResourceLoaderAvkon: Resource file " + resourceName +
+                        " handling failed: " + ex.getMessage());
+        }
+
+        return true;
+    }
+
+    /**
+     * 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,
+                            "ResourceLoaderAvkon: 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;
+    }
+
+    /**
+     * Get a string from resource map with a given comma
+     * separated resource id list.
+     *
+     * @param id comma separated resource id list, either with prefix or without
+     * @return resource string, or the id if does not exist
+     */
+    private String getResourceStringByList(String id)
+    {
+        String str = null;
+        String[] ids = Tokenizer.split(id, SEPARATOR);
+        for (int i = 0; i < ids.length && str == null; i++)
+        {
+            // Search text ids from resource maps.
+            for (int j = 0; j < iResourceMaps.length && str == null; j++)
+            {
+                str = (String)iResourceMaps[j].get(ids[i]);
+                if (str == null && iPrefixes != null && iPrefixes.length > j)
+                {
+                    // Try with prefix.
+                    str = (String)iResourceMaps[j].get(
+                        iPrefixes[j] + ids[i]);
+                }
+            }
+        }
+        if (str == null)
+        {
+            // Not found. Use the id itself.
+            str = id;
+            Logger.WLOG(Logger.EUtils,
+                        "ResourceLoaderAvkon: Cannot find resource: " + id +
+                        ", prefix: " + iPrefix);
+        }
+        return str;
+    }
+}