themeinstaller/source/src/com/nokia/tools/themeinstaller/cssparser/CSSHandler.java
branchRCL_3
changeset 33 04b7640f6fb5
parent 0 05da4621cfb2
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/themeinstaller/source/src/com/nokia/tools/themeinstaller/cssparser/CSSHandler.java	Wed Sep 01 12:32:13 2010 +0100
@@ -0,0 +1,588 @@
+/*
+* Copyright (c) 2007 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:  This class gets notified during the CSS file parsing
+ *
+*/
+
+
+package com.nokia.tools.themeinstaller.cssparser;
+
+import java.awt.Color;
+import java.io.File;
+import java.io.FileReader;
+import java.io.Reader;
+import java.util.HashMap;
+import java.util.Vector;
+
+import org.w3c.css.sac.CSSException;
+import org.w3c.css.sac.DocumentHandler;
+import org.w3c.css.sac.InputSource;
+import org.w3c.css.sac.LexicalUnit;
+import org.w3c.css.sac.Parser;
+import org.w3c.css.sac.SACMediaList;
+import org.w3c.css.sac.SelectorList;
+import org.w3c.css.sac.helpers.ParserFactory;
+import org.w3c.dom.Document;
+
+import com.nokia.tools.themeinstaller.logger.LogWriter;
+
+/**
+ * The Class CSSHandler. Informs application of basic parsing events. This
+ * should be registered with CSS Parser with setDocumentHandler method.
+ *
+ * Handler gets notified during the CSS parsing:
+ * 1. startSelector(), when new selector is noticed
+ * 2. property(), when new property is noticed
+ * 3. lexicalValue() is used to calculate the values of the parsed property
+ *
+ * If you are using CSS import with paths relative to main CSS, you need to
+ * set the path of main CSS using setImportDirectory( String aImportDirectory )
+ */
+
+public class CSSHandler implements DocumentHandler
+    {
+
+    /** The style map for style property. */
+    private HashMap iStyleMap;
+
+    /** List of parsed rules. */
+    private Vector iRuleList;
+
+    /** The DOM document. */
+    private Document iDocument;
+
+    /** Color resolver for resolving colors in string form */
+    private ColorResolver iColorResolver;
+
+    /** The main CSS directory for finding imported CSS File's relative path. */
+    private String iImportDirectory;
+
+    /** The Constant FUNCTION_HSL. */
+    public static final String FUNCTION_HSL = "hsl";
+
+    /** The Constant COMMA. */
+    public static final String COMMA = ",";
+
+    /** The Constant CHAR_APOSTROPHE. */
+    private static final char CHAR_APOSTROPHE = '"';
+
+    /** The Constant CHAR_SPACE. */
+    private static final char CHAR_SPACE = ' ';
+
+    /** The Constant CHAR_COLON. */
+    private static final char CHAR_COLON = ':';
+
+    /** The Constant SEPARATOR. */
+    public static final String SEPARATOR = "|";
+
+    /** The Constant FORWARD_SLASH. */
+    public static final String FORWARD_SLASH = "/";
+
+    /** The Constant BACKWARD_SLASH. */
+    public static final String BACKWARD_SLASH = "\\";
+
+    /** The CSS to DOM Processor for applying changes to DOM. */
+    private CSSDOMProcessor iCSSDOMProcessor;
+
+    /**
+     * Instantiates a new CSS handler.
+     */
+    public CSSHandler()
+        {
+        super();
+        iCSSDOMProcessor = new CSSDOMProcessor();
+        iStyleMap = new HashMap();
+        iRuleList = new Vector();
+        iColorResolver = new ColorResolver();
+        }
+
+    /**
+     * Instantiates a new CSS handler. This one is used for handling imported
+     * CSS files
+     *
+     * @param aHandler The handler to retrieve previous rule list and DOM document
+     *            from
+     */
+    private CSSHandler( CSSHandler aHandler )
+        {
+        super();
+        iCSSDOMProcessor = new CSSDOMProcessor();
+        iStyleMap = new HashMap();
+
+        iRuleList = aHandler.iRuleList;
+        iDocument = aHandler.iDocument;
+        iColorResolver = new ColorResolver();
+        }
+
+    /**
+     * Sets the document.
+     *
+     * @param aDocument The new document
+     */
+    public void setDocument( Document aDocument )
+        {
+        iDocument = aDocument;
+        }
+
+    /**
+     * Gets the document.
+     *
+     * @return the document
+     */
+    public Document getDocument()
+        {
+        return iDocument;
+        }
+
+    /**
+     * Sets the directory of main CSS.
+     *
+     * @param aImportDirectory The directory of main CSS
+     */
+    public void setImportDirectory( String aImportDirectory )
+        {
+        iImportDirectory = aImportDirectory;
+        }
+
+    /*
+     * (non-Javadoc)
+     *
+     * @see org.w3c.css.sac.DocumentHandler#startDocument(org.w3c.css.sac.InputSource)
+     */
+    public void startDocument( InputSource arg0 ) throws CSSException
+        {
+        iRuleList = new Vector();
+        }
+
+    /*
+     * (non-Javadoc)
+     *
+     * @see org.w3c.css.sac.DocumentHandler#startSelector(org.w3c.css.sac.SelectorList)
+     */
+    public void startSelector( SelectorList aSelectorList ) throws CSSException
+        {
+        iStyleMap = new HashMap();
+        }
+
+    /*
+     * (non-Javadoc)
+     *
+     * @see org.w3c.css.sac.DocumentHandler#endSelector(org.w3c.css.sac.SelectorList)
+     */
+    public void endSelector( SelectorList aSelectors ) throws CSSException
+        {
+        if ( iStyleMap.size() != 0 )
+            {
+            for ( int i = 0; i < aSelectors.getLength(); i++ )
+                {
+//            	System.out.println("CSSHandler Selectors --> "+aSelectors.item(i));
+                CSSRule rule = new CSSRule( aSelectors.item( i ), iStyleMap );
+                iRuleList.add( rule );
+                }
+            }
+        }
+
+    /*
+     * (non-Javadoc)
+     *
+     * @see org.w3c.css.sac.DocumentHandler#property(java.lang.String,
+     *      org.w3c.css.sac.LexicalUnit, boolean)
+     */
+    public void property( String aName, LexicalUnit aLexicalUnit,
+            boolean aImportant ) throws CSSException
+        {
+        Vector propertyValues = new Vector();
+        lexicalValue( aLexicalUnit, propertyValues );
+        iStyleMap.put( aName, new CSSStyleProperty( propertyValues, aImportant ) );
+        }
+
+    /*
+     * (non-Javadoc)
+     *
+     * @see org.w3c.css.sac.DocumentHandler#endDocument(org.w3c.css.sac.InputSource)
+     */
+    public void endDocument( InputSource aInputSource ) throws CSSException
+        {
+        if ( iDocument == null )
+            {
+            throw new IllegalStateException( "CSSHandler has null DOM Document" );
+            }
+        
+        iCSSDOMProcessor.applyRulesToDom( iDocument, iRuleList );
+        }
+
+
+    /**
+     * Finds out the property values and adds them into a Vector
+     * aPropertyValues. Property types that are taken into account are
+     * from Symbian side: ...\Xuikon\Dom\src\xndompropertyvalue.cpp
+     *
+     * @param aLexicalUnit Value
+     * @param aPropertyValues Vector for Property values
+     */
+    public void lexicalValue( LexicalUnit aLexicalUnit,
+            Vector aPropertyValues )
+        {
+        while ( aLexicalUnit != null )
+            {
+            switch ( aLexicalUnit.getLexicalUnitType() )
+                {
+                case LexicalUnit.SAC_OPERATOR_COMMA:
+                    break;
+                // Allowed cases for integer value
+                case LexicalUnit.SAC_INTEGER:
+                    aPropertyValues
+                            .add( new CSSPropertyValue(
+                                    LexicalUnit.SAC_INTEGER, Integer
+                                            .toString( aLexicalUnit
+                                                    .getIntegerValue() ) ) );
+                    break;
+                // Allowed cases for real value
+                // Fallthrough
+                case LexicalUnit.SAC_REAL:
+                case LexicalUnit.SAC_DIMENSION:
+                case LexicalUnit.SAC_EM:
+                case LexicalUnit.SAC_EX:
+                case LexicalUnit.SAC_INCH:
+                case LexicalUnit.SAC_PIXEL:
+                case LexicalUnit.SAC_CENTIMETER:
+                case LexicalUnit.SAC_MILLIMETER:
+                case LexicalUnit.SAC_POINT:
+                case LexicalUnit.SAC_PICA:
+                case LexicalUnit.SAC_PERCENTAGE:
+                case LexicalUnit.SAC_DEGREE:
+                case LexicalUnit.SAC_GRADIAN:
+                case LexicalUnit.SAC_RADIAN:
+                case LexicalUnit.SAC_MILLISECOND:
+                case LexicalUnit.SAC_SECOND:
+                case LexicalUnit.SAC_HERTZ:
+                case LexicalUnit.SAC_KILOHERTZ:
+                    aPropertyValues.add( new CSSPropertyValue( aLexicalUnit
+                            .getLexicalUnitType(), Float.toString( aLexicalUnit
+                            .getFloatValue() ) ) );
+                    break;
+                // RGB Values
+                case LexicalUnit.SAC_RGBCOLOR:
+                    //Using StringBuffer to store values of RGB property
+                    //in order to handle values (R,G and B) as one value
+                    StringBuffer sb = new StringBuffer();
+                    colorValue( aLexicalUnit.getParameters(), sb );
+                    aPropertyValues.add( new CSSPropertyValue( aLexicalUnit
+                            .getLexicalUnitType(), sb.toString() ) );
+                    break;
+                // Allowed cases for string values
+                // Fallthrough
+                case LexicalUnit.SAC_URI:
+                case LexicalUnit.SAC_IDENT:
+                case LexicalUnit.SAC_STRING_VALUE:
+                case LexicalUnit.SAC_ATTR:
+                    // Color value as string
+                    if ( iColorResolver.get( aLexicalUnit.getStringValue() ) != null )
+                        {
+                        Color color = ( Color ) iColorResolver.get( aLexicalUnit
+                                .getStringValue() );
+                        aPropertyValues.add( new CSSPropertyValue(
+                                LexicalUnit.SAC_RGBCOLOR,
+                                LexicalUnit.SAC_INTEGER + SEPARATOR
+                                        + color.getRed() + COMMA
+                                        + LexicalUnit.SAC_INTEGER + SEPARATOR
+                                        + color.getGreen() + COMMA
+                                        + LexicalUnit.SAC_INTEGER + SEPARATOR
+                                        + color.getBlue() ) );
+                        }
+                    // Space
+                    else if ( aLexicalUnit.getStringValue()
+                            .indexOf( CHAR_SPACE ) != -1 )
+                        {
+                        aPropertyValues.add( new CSSPropertyValue( aLexicalUnit
+                                .getLexicalUnitType(), CHAR_APOSTROPHE
+                                + aLexicalUnit.getStringValue()
+                                + CHAR_APOSTROPHE ) );
+                        }
+                    // Text
+                    else
+                        {
+                        aPropertyValues.add( new CSSPropertyValue( aLexicalUnit
+                                .getLexicalUnitType(), aLexicalUnit
+                                .getStringValue() ) );
+                        }
+                    break;
+                // In case value is set as "inherit" already in CSS -file
+                // This sets it to DOM as Ident value that is "inherit"
+                case LexicalUnit.SAC_INHERIT:
+                    aPropertyValues.add( new CSSPropertyValue(
+                            LexicalUnit.SAC_IDENT,
+                            CSSDOMProcessor.STRING_INHERIT ) );
+                    break;
+                case LexicalUnit.SAC_FUNCTION:
+                    String functionName = aLexicalUnit.getFunctionName();
+                    if ( functionName.equals( FUNCTION_HSL ) )
+                        {
+                        Color color = colorFromHsl( aLexicalUnit
+                                .getParameters() );
+                        aPropertyValues.add( new CSSPropertyValue(
+                                LexicalUnit.SAC_RGBCOLOR,
+                                LexicalUnit.SAC_INTEGER + SEPARATOR
+                                        + color.getRed() + COMMA
+                                        + LexicalUnit.SAC_INTEGER + SEPARATOR
+                                        + color.getGreen() + COMMA
+                                        + LexicalUnit.SAC_INTEGER + SEPARATOR
+                                        + color.getBlue() ) );
+
+                        }
+                    else
+                        {
+                        throw new IllegalStateException(
+                                "Unknown CSS Function : " + functionName );
+                        }
+                    break;
+                default:
+                    break;
+                }
+            aLexicalUnit = aLexicalUnit.getNextLexicalUnit();
+            }
+        }
+
+    /**
+     * Parses HSL Function using ColorResolver.
+     *
+     * @param aLexicalUnit Parameters containing color values
+     *
+     * @return the color
+     */
+    private Color colorFromHsl( LexicalUnit aLexicalUnit )
+        {
+        float h = 0;
+        float s = 0;
+        float l = 0;
+        try
+            {
+            h = ( float ) aLexicalUnit.getIntegerValue();
+            aLexicalUnit = aLexicalUnit.getNextLexicalUnit()
+                    .getNextLexicalUnit();
+            s = aLexicalUnit.getFloatValue();
+            aLexicalUnit = aLexicalUnit.getNextLexicalUnit()
+                    .getNextLexicalUnit();
+            l = aLexicalUnit.getFloatValue();
+            }
+        catch ( RuntimeException e )
+            {
+            throw new IllegalStateException( "Illegal HSL Color values" );
+            }
+        if ( aLexicalUnit.getNextLexicalUnit() != null )
+            {
+            throw new IllegalStateException( "Too many parameters in HSL color" );
+            }
+        return iColorResolver.hslToRgb( h, s, l );
+        }
+
+    /**
+     * Finds out the property values for RGB color and adds them into a
+     * StringBuffer aProperty.
+     *
+     * @param aLexicalUnit Parameters containing color values
+     * @param aProperty StringBuffer for storing property information
+     */
+    public void colorValue( LexicalUnit aLexicalUnit, StringBuffer aProperty )
+        {
+        while ( aLexicalUnit != null )
+            {
+            switch ( aLexicalUnit.getLexicalUnitType() )
+                {
+                // Operator ","
+                case LexicalUnit.SAC_OPERATOR_COMMA:
+                    aProperty.append( COMMA );
+                    break;
+                case LexicalUnit.SAC_INTEGER:
+                    aProperty.append( aLexicalUnit.getLexicalUnitType() );
+                    aProperty.append( SEPARATOR );
+                    aProperty.append( aLexicalUnit.getIntegerValue() );
+                    break;
+                case LexicalUnit.SAC_PERCENTAGE:
+                    aProperty.append( LexicalUnit.SAC_INTEGER );
+                    aProperty.append( SEPARATOR );
+                    aProperty.append( iColorResolver
+                            .getColorValueFromPercentage( aLexicalUnit
+                                    .getFloatValue() ) );
+                    break;
+                default:
+                    break;
+                }
+            aLexicalUnit = aLexicalUnit.getNextLexicalUnit();
+            }
+        }
+
+    /*
+     * (non-Javadoc)
+     *
+     * @see org.w3c.css.sac.DocumentHandler#startFontFace ()
+     */
+    public void startFontFace() throws CSSException
+        {
+        }
+
+    /*
+     * (non-Javadoc)
+     *
+     * @see org.w3c.css.sac.DocumentHandler#startPage(java.lang.String,
+     *      java.lang.String)
+     */
+    public void startPage( String arg0, String arg1 ) throws CSSException
+        {
+        }
+
+    /*
+     * (non-Javadoc)
+     *
+     * @see org.w3c.css.sac.DocumentHandler#endFontFace ()
+     */
+    public void endFontFace() throws CSSException
+        {
+        }
+
+    /*
+     * (non-Javadoc)
+     *
+     * @see org.w3c.css.sac.DocumentHandler#endPage(java.lang.String,
+     *      java.lang.String)
+     */
+    public void endPage( String arg0, String arg1 ) throws CSSException
+        {
+        }
+
+    /*
+     * (non-Javadoc)
+     *
+     * @see org.w3c.css.sac.DocumentHandler#comment (java.lang.String)
+     */
+    public void comment( String arg0 ) throws CSSException
+        {
+        }
+
+    /*
+     * (non-Javadoc)
+     *
+     * @see org.w3c.css.sac.DocumentHandler#endMedia (org.w3c.css.sac.SACMediaList)
+     */
+    public void endMedia( SACMediaList arg0 ) throws CSSException
+        {
+        }
+
+    /*
+     * (non-Javadoc)
+     *
+     * @see org.w3c.css.sac.DocumentHandler#ignorableAtRule (java.lang.String)
+     */
+    public void ignorableAtRule( String arg0 ) throws CSSException
+        {
+        }
+
+    /*
+     * (non-Javadoc)
+     *
+     * @see org.w3c.css.sac.DocumentHandler#importStyle (java.lang.String,
+     *      org.w3c.css.sac.SACMediaList, java.lang.String)
+     */
+    public void importStyle( String aCSSFileName, SACMediaList aMedia,
+            String aNameSpaceUri ) throws CSSException
+        {
+        try
+            {
+            CSSHandler handler = new CSSHandler( this );
+            ParserFactory factory = new ParserFactory();
+
+            Parser parser = factory.makeParser();
+            parser.setDocumentHandler( handler );
+            Reader r = null;
+
+            File cssImport = new File( aCSSFileName );
+            if ( isAbsolutePath( aCSSFileName ) && cssImport.exists() )
+                {
+                // The imported CSS file is given with absolute path
+                r = new FileReader( aCSSFileName );
+                LogWriter.getInstance().logInfo(
+                        "Imported CSS : " + cssImport.getAbsolutePath() );
+                }
+            else if ( !isAbsolutePath( aCSSFileName )
+                    && iImportDirectory != null )
+                {
+                // If the given imported CSS File is not found,
+                // try to locate it using path relative to main CSS
+                File relativeCSS = new File( iImportDirectory + File.separator
+                        + aCSSFileName );
+                r = new FileReader( relativeCSS );
+                LogWriter.getInstance().logInfo(
+                        "Imported CSS : " + relativeCSS.getAbsolutePath() );
+                }
+            else
+                {
+                throw new IllegalStateException(
+                        "Can't resolve imported CSS File: " + aCSSFileName );
+                }
+
+            InputSource is = new InputSource( r );
+            parser.parseStyleSheet( is );
+            }
+        catch ( Exception e )
+            {
+            throw new CSSException( e.getMessage() );
+            }
+        }
+
+    /**
+     * Checks if path is absolute path.
+     * Path is absolute if it starts with '/', '\'
+     * or is of form [drive]:[path]
+     * @param aFilePath the a file path
+     *
+     * @return true, if is absolute path
+     */
+    private boolean isAbsolutePath( String aFilePath )
+        {
+        if ( aFilePath.startsWith( FORWARD_SLASH ) )
+            {
+            return true;
+            }
+        if ( aFilePath.startsWith( BACKWARD_SLASH ) )
+            {
+            return true;
+            }
+        if ( aFilePath.length() > 1 && aFilePath.charAt( 1 ) == CHAR_COLON )
+            {
+            return true;
+            }
+        return false;
+        }
+
+    /*
+     * (non-Javadoc)
+     *
+     * @see org.w3c.css.sac.DocumentHandler#namespaceDeclaration(java.lang.String,
+     *      java.lang.String)
+     */
+    public void namespaceDeclaration( String arg0, String arg1 )
+            throws CSSException
+        {
+        }
+
+    /*
+     * (non-Javadoc)
+     *
+     * @see org.w3c.css.sac.DocumentHandler#startMedia(org.w3c.css.sac.SACMediaList)
+     */
+    public void startMedia( SACMediaList arg0 ) throws CSSException
+        {
+        }
+
+    }