themeinstaller/source/src/com/nokia/tools/themeinstaller/cssparser/CSSHandler.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/themeinstaller/source/src/com/nokia/tools/themeinstaller/cssparser/CSSHandler.java Tue Feb 02 00:15:44 2010 +0200
@@ -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
+ {
+ }
+
+ }