themeinstaller/source/src/com/nokia/tools/themeinstaller/cssparser/CSSHandler.java
branchRCL_3
changeset 17 fe49e33862e2
parent 16 b685c59de105
child 18 04b7640f6fb5
equal deleted inserted replaced
16:b685c59de105 17:fe49e33862e2
     1 /*
       
     2 * Copyright (c) 2007 Nokia Corporation and/or its subsidiary(-ies). 
       
     3 * All rights reserved.
       
     4 * This component and the accompanying materials are made available
       
     5 * under the terms of "Eclipse Public License v1.0"
       
     6 * which accompanies this distribution, and is available
       
     7 * at the URL "http://www.eclipse.org/legal/epl-v10.html".
       
     8 *
       
     9 * Initial Contributors:
       
    10 * Nokia Corporation - initial contribution.
       
    11 *
       
    12 * Contributors:
       
    13 *
       
    14 * Description:  This class gets notified during the CSS file parsing
       
    15  *
       
    16 */
       
    17 
       
    18 
       
    19 package com.nokia.tools.themeinstaller.cssparser;
       
    20 
       
    21 import java.awt.Color;
       
    22 import java.io.File;
       
    23 import java.io.FileReader;
       
    24 import java.io.Reader;
       
    25 import java.util.HashMap;
       
    26 import java.util.Vector;
       
    27 
       
    28 import org.w3c.css.sac.CSSException;
       
    29 import org.w3c.css.sac.DocumentHandler;
       
    30 import org.w3c.css.sac.InputSource;
       
    31 import org.w3c.css.sac.LexicalUnit;
       
    32 import org.w3c.css.sac.Parser;
       
    33 import org.w3c.css.sac.SACMediaList;
       
    34 import org.w3c.css.sac.SelectorList;
       
    35 import org.w3c.css.sac.helpers.ParserFactory;
       
    36 import org.w3c.dom.Document;
       
    37 
       
    38 import com.nokia.tools.themeinstaller.logger.LogWriter;
       
    39 
       
    40 /**
       
    41  * The Class CSSHandler. Informs application of basic parsing events. This
       
    42  * should be registered with CSS Parser with setDocumentHandler method.
       
    43  *
       
    44  * Handler gets notified during the CSS parsing:
       
    45  * 1. startSelector(), when new selector is noticed
       
    46  * 2. property(), when new property is noticed
       
    47  * 3. lexicalValue() is used to calculate the values of the parsed property
       
    48  *
       
    49  * If you are using CSS import with paths relative to main CSS, you need to
       
    50  * set the path of main CSS using setImportDirectory( String aImportDirectory )
       
    51  */
       
    52 
       
    53 public class CSSHandler implements DocumentHandler
       
    54     {
       
    55 
       
    56     /** The style map for style property. */
       
    57     private HashMap iStyleMap;
       
    58 
       
    59     /** List of parsed rules. */
       
    60     private Vector iRuleList;
       
    61 
       
    62     /** The DOM document. */
       
    63     private Document iDocument;
       
    64 
       
    65     /** Color resolver for resolving colors in string form */
       
    66     private ColorResolver iColorResolver;
       
    67 
       
    68     /** The main CSS directory for finding imported CSS File's relative path. */
       
    69     private String iImportDirectory;
       
    70 
       
    71     /** The Constant FUNCTION_HSL. */
       
    72     public static final String FUNCTION_HSL = "hsl";
       
    73 
       
    74     /** The Constant COMMA. */
       
    75     public static final String COMMA = ",";
       
    76 
       
    77     /** The Constant CHAR_APOSTROPHE. */
       
    78     private static final char CHAR_APOSTROPHE = '"';
       
    79 
       
    80     /** The Constant CHAR_SPACE. */
       
    81     private static final char CHAR_SPACE = ' ';
       
    82 
       
    83     /** The Constant CHAR_COLON. */
       
    84     private static final char CHAR_COLON = ':';
       
    85 
       
    86     /** The Constant SEPARATOR. */
       
    87     public static final String SEPARATOR = "|";
       
    88 
       
    89     /** The Constant FORWARD_SLASH. */
       
    90     public static final String FORWARD_SLASH = "/";
       
    91 
       
    92     /** The Constant BACKWARD_SLASH. */
       
    93     public static final String BACKWARD_SLASH = "\\";
       
    94 
       
    95     /** The CSS to DOM Processor for applying changes to DOM. */
       
    96     private CSSDOMProcessor iCSSDOMProcessor;
       
    97 
       
    98     /**
       
    99      * Instantiates a new CSS handler.
       
   100      */
       
   101     public CSSHandler()
       
   102         {
       
   103         super();
       
   104         iCSSDOMProcessor = new CSSDOMProcessor();
       
   105         iStyleMap = new HashMap();
       
   106         iRuleList = new Vector();
       
   107         iColorResolver = new ColorResolver();
       
   108         }
       
   109 
       
   110     /**
       
   111      * Instantiates a new CSS handler. This one is used for handling imported
       
   112      * CSS files
       
   113      *
       
   114      * @param aHandler The handler to retrieve previous rule list and DOM document
       
   115      *            from
       
   116      */
       
   117     private CSSHandler( CSSHandler aHandler )
       
   118         {
       
   119         super();
       
   120         iCSSDOMProcessor = new CSSDOMProcessor();
       
   121         iStyleMap = new HashMap();
       
   122 
       
   123         iRuleList = aHandler.iRuleList;
       
   124         iDocument = aHandler.iDocument;
       
   125         iColorResolver = new ColorResolver();
       
   126         }
       
   127 
       
   128     /**
       
   129      * Sets the document.
       
   130      *
       
   131      * @param aDocument The new document
       
   132      */
       
   133     public void setDocument( Document aDocument )
       
   134         {
       
   135         iDocument = aDocument;
       
   136         }
       
   137 
       
   138     /**
       
   139      * Gets the document.
       
   140      *
       
   141      * @return the document
       
   142      */
       
   143     public Document getDocument()
       
   144         {
       
   145         return iDocument;
       
   146         }
       
   147 
       
   148     /**
       
   149      * Sets the directory of main CSS.
       
   150      *
       
   151      * @param aImportDirectory The directory of main CSS
       
   152      */
       
   153     public void setImportDirectory( String aImportDirectory )
       
   154         {
       
   155         iImportDirectory = aImportDirectory;
       
   156         }
       
   157 
       
   158     /*
       
   159      * (non-Javadoc)
       
   160      *
       
   161      * @see org.w3c.css.sac.DocumentHandler#startDocument(org.w3c.css.sac.InputSource)
       
   162      */
       
   163     public void startDocument( InputSource arg0 ) throws CSSException
       
   164         {
       
   165         iRuleList = new Vector();
       
   166         }
       
   167 
       
   168     /*
       
   169      * (non-Javadoc)
       
   170      *
       
   171      * @see org.w3c.css.sac.DocumentHandler#startSelector(org.w3c.css.sac.SelectorList)
       
   172      */
       
   173     public void startSelector( SelectorList aSelectorList ) throws CSSException
       
   174         {
       
   175         iStyleMap = new HashMap();
       
   176         }
       
   177 
       
   178     /*
       
   179      * (non-Javadoc)
       
   180      *
       
   181      * @see org.w3c.css.sac.DocumentHandler#endSelector(org.w3c.css.sac.SelectorList)
       
   182      */
       
   183     public void endSelector( SelectorList aSelectors ) throws CSSException
       
   184         {
       
   185         if ( iStyleMap.size() != 0 )
       
   186             {
       
   187             for ( int i = 0; i < aSelectors.getLength(); i++ )
       
   188                 {
       
   189 //            	System.out.println("CSSHandler Selectors --> "+aSelectors.item(i));
       
   190                 CSSRule rule = new CSSRule( aSelectors.item( i ), iStyleMap );
       
   191                 iRuleList.add( rule );
       
   192                 }
       
   193             }
       
   194         }
       
   195 
       
   196     /*
       
   197      * (non-Javadoc)
       
   198      *
       
   199      * @see org.w3c.css.sac.DocumentHandler#property(java.lang.String,
       
   200      *      org.w3c.css.sac.LexicalUnit, boolean)
       
   201      */
       
   202     public void property( String aName, LexicalUnit aLexicalUnit,
       
   203             boolean aImportant ) throws CSSException
       
   204         {
       
   205         Vector propertyValues = new Vector();
       
   206         lexicalValue( aLexicalUnit, propertyValues );
       
   207         iStyleMap.put( aName, new CSSStyleProperty( propertyValues, aImportant ) );
       
   208         }
       
   209 
       
   210     /*
       
   211      * (non-Javadoc)
       
   212      *
       
   213      * @see org.w3c.css.sac.DocumentHandler#endDocument(org.w3c.css.sac.InputSource)
       
   214      */
       
   215     public void endDocument( InputSource aInputSource ) throws CSSException
       
   216         {
       
   217         if ( iDocument == null )
       
   218             {
       
   219             throw new IllegalStateException( "CSSHandler has null DOM Document" );
       
   220             }
       
   221         
       
   222         iCSSDOMProcessor.applyRulesToDom( iDocument, iRuleList );
       
   223         }
       
   224 
       
   225 
       
   226     /**
       
   227      * Finds out the property values and adds them into a Vector
       
   228      * aPropertyValues. Property types that are taken into account are
       
   229      * from Symbian side: ...\Xuikon\Dom\src\xndompropertyvalue.cpp
       
   230      *
       
   231      * @param aLexicalUnit Value
       
   232      * @param aPropertyValues Vector for Property values
       
   233      */
       
   234     public void lexicalValue( LexicalUnit aLexicalUnit,
       
   235             Vector aPropertyValues )
       
   236         {
       
   237         while ( aLexicalUnit != null )
       
   238             {
       
   239             switch ( aLexicalUnit.getLexicalUnitType() )
       
   240                 {
       
   241                 case LexicalUnit.SAC_OPERATOR_COMMA:
       
   242                     break;
       
   243                 // Allowed cases for integer value
       
   244                 case LexicalUnit.SAC_INTEGER:
       
   245                     aPropertyValues
       
   246                             .add( new CSSPropertyValue(
       
   247                                     LexicalUnit.SAC_INTEGER, Integer
       
   248                                             .toString( aLexicalUnit
       
   249                                                     .getIntegerValue() ) ) );
       
   250                     break;
       
   251                 // Allowed cases for real value
       
   252                 // Fallthrough
       
   253                 case LexicalUnit.SAC_REAL:
       
   254                 case LexicalUnit.SAC_DIMENSION:
       
   255                 case LexicalUnit.SAC_EM:
       
   256                 case LexicalUnit.SAC_EX:
       
   257                 case LexicalUnit.SAC_INCH:
       
   258                 case LexicalUnit.SAC_PIXEL:
       
   259                 case LexicalUnit.SAC_CENTIMETER:
       
   260                 case LexicalUnit.SAC_MILLIMETER:
       
   261                 case LexicalUnit.SAC_POINT:
       
   262                 case LexicalUnit.SAC_PICA:
       
   263                 case LexicalUnit.SAC_PERCENTAGE:
       
   264                 case LexicalUnit.SAC_DEGREE:
       
   265                 case LexicalUnit.SAC_GRADIAN:
       
   266                 case LexicalUnit.SAC_RADIAN:
       
   267                 case LexicalUnit.SAC_MILLISECOND:
       
   268                 case LexicalUnit.SAC_SECOND:
       
   269                 case LexicalUnit.SAC_HERTZ:
       
   270                 case LexicalUnit.SAC_KILOHERTZ:
       
   271                     aPropertyValues.add( new CSSPropertyValue( aLexicalUnit
       
   272                             .getLexicalUnitType(), Float.toString( aLexicalUnit
       
   273                             .getFloatValue() ) ) );
       
   274                     break;
       
   275                 // RGB Values
       
   276                 case LexicalUnit.SAC_RGBCOLOR:
       
   277                     //Using StringBuffer to store values of RGB property
       
   278                     //in order to handle values (R,G and B) as one value
       
   279                     StringBuffer sb = new StringBuffer();
       
   280                     colorValue( aLexicalUnit.getParameters(), sb );
       
   281                     aPropertyValues.add( new CSSPropertyValue( aLexicalUnit
       
   282                             .getLexicalUnitType(), sb.toString() ) );
       
   283                     break;
       
   284                 // Allowed cases for string values
       
   285                 // Fallthrough
       
   286                 case LexicalUnit.SAC_URI:
       
   287                 case LexicalUnit.SAC_IDENT:
       
   288                 case LexicalUnit.SAC_STRING_VALUE:
       
   289                 case LexicalUnit.SAC_ATTR:
       
   290                     // Color value as string
       
   291                     if ( iColorResolver.get( aLexicalUnit.getStringValue() ) != null )
       
   292                         {
       
   293                         Color color = ( Color ) iColorResolver.get( aLexicalUnit
       
   294                                 .getStringValue() );
       
   295                         aPropertyValues.add( new CSSPropertyValue(
       
   296                                 LexicalUnit.SAC_RGBCOLOR,
       
   297                                 LexicalUnit.SAC_INTEGER + SEPARATOR
       
   298                                         + color.getRed() + COMMA
       
   299                                         + LexicalUnit.SAC_INTEGER + SEPARATOR
       
   300                                         + color.getGreen() + COMMA
       
   301                                         + LexicalUnit.SAC_INTEGER + SEPARATOR
       
   302                                         + color.getBlue() ) );
       
   303                         }
       
   304                     // Space
       
   305                     else if ( aLexicalUnit.getStringValue()
       
   306                             .indexOf( CHAR_SPACE ) != -1 )
       
   307                         {
       
   308                         aPropertyValues.add( new CSSPropertyValue( aLexicalUnit
       
   309                                 .getLexicalUnitType(), CHAR_APOSTROPHE
       
   310                                 + aLexicalUnit.getStringValue()
       
   311                                 + CHAR_APOSTROPHE ) );
       
   312                         }
       
   313                     // Text
       
   314                     else
       
   315                         {
       
   316                         aPropertyValues.add( new CSSPropertyValue( aLexicalUnit
       
   317                                 .getLexicalUnitType(), aLexicalUnit
       
   318                                 .getStringValue() ) );
       
   319                         }
       
   320                     break;
       
   321                 // In case value is set as "inherit" already in CSS -file
       
   322                 // This sets it to DOM as Ident value that is "inherit"
       
   323                 case LexicalUnit.SAC_INHERIT:
       
   324                     aPropertyValues.add( new CSSPropertyValue(
       
   325                             LexicalUnit.SAC_IDENT,
       
   326                             CSSDOMProcessor.STRING_INHERIT ) );
       
   327                     break;
       
   328                 case LexicalUnit.SAC_FUNCTION:
       
   329                     String functionName = aLexicalUnit.getFunctionName();
       
   330                     if ( functionName.equals( FUNCTION_HSL ) )
       
   331                         {
       
   332                         Color color = colorFromHsl( aLexicalUnit
       
   333                                 .getParameters() );
       
   334                         aPropertyValues.add( new CSSPropertyValue(
       
   335                                 LexicalUnit.SAC_RGBCOLOR,
       
   336                                 LexicalUnit.SAC_INTEGER + SEPARATOR
       
   337                                         + color.getRed() + COMMA
       
   338                                         + LexicalUnit.SAC_INTEGER + SEPARATOR
       
   339                                         + color.getGreen() + COMMA
       
   340                                         + LexicalUnit.SAC_INTEGER + SEPARATOR
       
   341                                         + color.getBlue() ) );
       
   342 
       
   343                         }
       
   344                     else
       
   345                         {
       
   346                         throw new IllegalStateException(
       
   347                                 "Unknown CSS Function : " + functionName );
       
   348                         }
       
   349                     break;
       
   350                 default:
       
   351                     break;
       
   352                 }
       
   353             aLexicalUnit = aLexicalUnit.getNextLexicalUnit();
       
   354             }
       
   355         }
       
   356 
       
   357     /**
       
   358      * Parses HSL Function using ColorResolver.
       
   359      *
       
   360      * @param aLexicalUnit Parameters containing color values
       
   361      *
       
   362      * @return the color
       
   363      */
       
   364     private Color colorFromHsl( LexicalUnit aLexicalUnit )
       
   365         {
       
   366         float h = 0;
       
   367         float s = 0;
       
   368         float l = 0;
       
   369         try
       
   370             {
       
   371             h = ( float ) aLexicalUnit.getIntegerValue();
       
   372             aLexicalUnit = aLexicalUnit.getNextLexicalUnit()
       
   373                     .getNextLexicalUnit();
       
   374             s = aLexicalUnit.getFloatValue();
       
   375             aLexicalUnit = aLexicalUnit.getNextLexicalUnit()
       
   376                     .getNextLexicalUnit();
       
   377             l = aLexicalUnit.getFloatValue();
       
   378             }
       
   379         catch ( RuntimeException e )
       
   380             {
       
   381             throw new IllegalStateException( "Illegal HSL Color values" );
       
   382             }
       
   383         if ( aLexicalUnit.getNextLexicalUnit() != null )
       
   384             {
       
   385             throw new IllegalStateException( "Too many parameters in HSL color" );
       
   386             }
       
   387         return iColorResolver.hslToRgb( h, s, l );
       
   388         }
       
   389 
       
   390     /**
       
   391      * Finds out the property values for RGB color and adds them into a
       
   392      * StringBuffer aProperty.
       
   393      *
       
   394      * @param aLexicalUnit Parameters containing color values
       
   395      * @param aProperty StringBuffer for storing property information
       
   396      */
       
   397     public void colorValue( LexicalUnit aLexicalUnit, StringBuffer aProperty )
       
   398         {
       
   399         while ( aLexicalUnit != null )
       
   400             {
       
   401             switch ( aLexicalUnit.getLexicalUnitType() )
       
   402                 {
       
   403                 // Operator ","
       
   404                 case LexicalUnit.SAC_OPERATOR_COMMA:
       
   405                     aProperty.append( COMMA );
       
   406                     break;
       
   407                 case LexicalUnit.SAC_INTEGER:
       
   408                     aProperty.append( aLexicalUnit.getLexicalUnitType() );
       
   409                     aProperty.append( SEPARATOR );
       
   410                     aProperty.append( aLexicalUnit.getIntegerValue() );
       
   411                     break;
       
   412                 case LexicalUnit.SAC_PERCENTAGE:
       
   413                     aProperty.append( LexicalUnit.SAC_INTEGER );
       
   414                     aProperty.append( SEPARATOR );
       
   415                     aProperty.append( iColorResolver
       
   416                             .getColorValueFromPercentage( aLexicalUnit
       
   417                                     .getFloatValue() ) );
       
   418                     break;
       
   419                 default:
       
   420                     break;
       
   421                 }
       
   422             aLexicalUnit = aLexicalUnit.getNextLexicalUnit();
       
   423             }
       
   424         }
       
   425 
       
   426     /*
       
   427      * (non-Javadoc)
       
   428      *
       
   429      * @see org.w3c.css.sac.DocumentHandler#startFontFace ()
       
   430      */
       
   431     public void startFontFace() throws CSSException
       
   432         {
       
   433         }
       
   434 
       
   435     /*
       
   436      * (non-Javadoc)
       
   437      *
       
   438      * @see org.w3c.css.sac.DocumentHandler#startPage(java.lang.String,
       
   439      *      java.lang.String)
       
   440      */
       
   441     public void startPage( String arg0, String arg1 ) throws CSSException
       
   442         {
       
   443         }
       
   444 
       
   445     /*
       
   446      * (non-Javadoc)
       
   447      *
       
   448      * @see org.w3c.css.sac.DocumentHandler#endFontFace ()
       
   449      */
       
   450     public void endFontFace() throws CSSException
       
   451         {
       
   452         }
       
   453 
       
   454     /*
       
   455      * (non-Javadoc)
       
   456      *
       
   457      * @see org.w3c.css.sac.DocumentHandler#endPage(java.lang.String,
       
   458      *      java.lang.String)
       
   459      */
       
   460     public void endPage( String arg0, String arg1 ) throws CSSException
       
   461         {
       
   462         }
       
   463 
       
   464     /*
       
   465      * (non-Javadoc)
       
   466      *
       
   467      * @see org.w3c.css.sac.DocumentHandler#comment (java.lang.String)
       
   468      */
       
   469     public void comment( String arg0 ) throws CSSException
       
   470         {
       
   471         }
       
   472 
       
   473     /*
       
   474      * (non-Javadoc)
       
   475      *
       
   476      * @see org.w3c.css.sac.DocumentHandler#endMedia (org.w3c.css.sac.SACMediaList)
       
   477      */
       
   478     public void endMedia( SACMediaList arg0 ) throws CSSException
       
   479         {
       
   480         }
       
   481 
       
   482     /*
       
   483      * (non-Javadoc)
       
   484      *
       
   485      * @see org.w3c.css.sac.DocumentHandler#ignorableAtRule (java.lang.String)
       
   486      */
       
   487     public void ignorableAtRule( String arg0 ) throws CSSException
       
   488         {
       
   489         }
       
   490 
       
   491     /*
       
   492      * (non-Javadoc)
       
   493      *
       
   494      * @see org.w3c.css.sac.DocumentHandler#importStyle (java.lang.String,
       
   495      *      org.w3c.css.sac.SACMediaList, java.lang.String)
       
   496      */
       
   497     public void importStyle( String aCSSFileName, SACMediaList aMedia,
       
   498             String aNameSpaceUri ) throws CSSException
       
   499         {
       
   500         try
       
   501             {
       
   502             CSSHandler handler = new CSSHandler( this );
       
   503             ParserFactory factory = new ParserFactory();
       
   504 
       
   505             Parser parser = factory.makeParser();
       
   506             parser.setDocumentHandler( handler );
       
   507             Reader r = null;
       
   508 
       
   509             File cssImport = new File( aCSSFileName );
       
   510             if ( isAbsolutePath( aCSSFileName ) && cssImport.exists() )
       
   511                 {
       
   512                 // The imported CSS file is given with absolute path
       
   513                 r = new FileReader( aCSSFileName );
       
   514                 LogWriter.getInstance().logInfo(
       
   515                         "Imported CSS : " + cssImport.getAbsolutePath() );
       
   516                 }
       
   517             else if ( !isAbsolutePath( aCSSFileName )
       
   518                     && iImportDirectory != null )
       
   519                 {
       
   520                 // If the given imported CSS File is not found,
       
   521                 // try to locate it using path relative to main CSS
       
   522                 File relativeCSS = new File( iImportDirectory + File.separator
       
   523                         + aCSSFileName );
       
   524                 r = new FileReader( relativeCSS );
       
   525                 LogWriter.getInstance().logInfo(
       
   526                         "Imported CSS : " + relativeCSS.getAbsolutePath() );
       
   527                 }
       
   528             else
       
   529                 {
       
   530                 throw new IllegalStateException(
       
   531                         "Can't resolve imported CSS File: " + aCSSFileName );
       
   532                 }
       
   533 
       
   534             InputSource is = new InputSource( r );
       
   535             parser.parseStyleSheet( is );
       
   536             }
       
   537         catch ( Exception e )
       
   538             {
       
   539             throw new CSSException( e.getMessage() );
       
   540             }
       
   541         }
       
   542 
       
   543     /**
       
   544      * Checks if path is absolute path.
       
   545      * Path is absolute if it starts with '/', '\'
       
   546      * or is of form [drive]:[path]
       
   547      * @param aFilePath the a file path
       
   548      *
       
   549      * @return true, if is absolute path
       
   550      */
       
   551     private boolean isAbsolutePath( String aFilePath )
       
   552         {
       
   553         if ( aFilePath.startsWith( FORWARD_SLASH ) )
       
   554             {
       
   555             return true;
       
   556             }
       
   557         if ( aFilePath.startsWith( BACKWARD_SLASH ) )
       
   558             {
       
   559             return true;
       
   560             }
       
   561         if ( aFilePath.length() > 1 && aFilePath.charAt( 1 ) == CHAR_COLON )
       
   562             {
       
   563             return true;
       
   564             }
       
   565         return false;
       
   566         }
       
   567 
       
   568     /*
       
   569      * (non-Javadoc)
       
   570      *
       
   571      * @see org.w3c.css.sac.DocumentHandler#namespaceDeclaration(java.lang.String,
       
   572      *      java.lang.String)
       
   573      */
       
   574     public void namespaceDeclaration( String arg0, String arg1 )
       
   575             throws CSSException
       
   576         {
       
   577         }
       
   578 
       
   579     /*
       
   580      * (non-Javadoc)
       
   581      *
       
   582      * @see org.w3c.css.sac.DocumentHandler#startMedia(org.w3c.css.sac.SACMediaList)
       
   583      */
       
   584     public void startMedia( SACMediaList arg0 ) throws CSSException
       
   585         {
       
   586         }
       
   587 
       
   588     }