diff -r b685c59de105 -r fe49e33862e2 themeinstaller/source/src/com/nokia/tools/themeinstaller/cssparser/CSSDOMProcessor.java --- a/themeinstaller/source/src/com/nokia/tools/themeinstaller/cssparser/CSSDOMProcessor.java Thu Aug 19 09:43:47 2010 +0300 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,687 +0,0 @@ -/* -* 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: CSSDOMProcessor applies given CSSRules to DOM Document. - * -*/ - - -package com.nokia.tools.themeinstaller.cssparser; - -import java.util.Collections; -import java.util.HashMap; -import java.util.Iterator; -import java.util.Vector; - -import org.w3c.css.sac.LexicalUnit; -import org.w3c.dom.Document; -import org.w3c.dom.Element; -import org.w3c.dom.NamedNodeMap; -import org.w3c.dom.Node; -import org.w3c.dom.traversal.DocumentTraversal; -import org.w3c.dom.traversal.NodeFilter; -import org.w3c.dom.traversal.NodeIterator; - -/** - * CSSDOMProcessor applies given CSSRules to DOM Document. - */ -public class CSSDOMProcessor - { - /** The Constant STRING_PROPERTY. */ - public static final String STRING_PROPERTY = "styleproperty"; - - /** The Constant STRING_PSEUDOCLASS. */ - public static final String STRING_PSEUDOCLASS = "pseudoclass"; - - /** The Constant STRING_NAME. */ - public static final String STRING_NAME = "name"; - - /** The Constant STRING_VALUE. */ - public static final String STRING_VALUE = "value"; - - /** The Constant STRING_INHERIT. */ - public static final String STRING_INHERIT = "inherit"; - - /** The Constant CHAR_COLON. */ - private static final char CHAR_COLON = ':'; - - /** The Constant STRING_SEPARATOR. */ - private static final String STRING_SEPARATOR = "|"; - - /** The Constant PSEUDO_TABLE. */ - private static final String[] UNSTYLABLE_ELEMENTS_TABLE = { "styleproperty" }; - - /** The Element type resolver. */ - private static ElementTypeResolver iElementTypeResolver = new ElementTypeResolver(); - - /** The Constant INHERITABLE_PROPERTIES. */ - public static final String[] INHERITABLE_PROPERTIES = { "visibility", - "block-progression", "direction", "color", "font-family", - "font-size", "font-weight", "font-style", "_s60-tab-style", - "_s60-tab-color" }; - - /** The Match Maker. */ - private CSSMatchMaker iCSSMatchMaker; - - /** - * Instantiates a new CSSDOM processor. - */ - public CSSDOMProcessor() - { - iCSSMatchMaker = new CSSMatchMaker(); - } - - /** - * Sort rules. - * - * @param rules The rules to be sorted by priority - */ - private static void sortRules( Vector rules ) - { - Collections.sort( rules ); - } - - /** - * Checks if is stylable element. - * - * @param aElement The element to be checked - * - * @return true, if is stylable element - */ - private static boolean isStylableElement(Element aElement){ - - for ( int i = 0; i < UNSTYLABLE_ELEMENTS_TABLE.length; i++ ) - { - if ( UNSTYLABLE_ELEMENTS_TABLE[ i ].equals( aElement.getTagName() )) - { - return false; - } - } - - return true; - } - - /** - * Apply style rule to DOM. Walks through the DOM tree elements and finds - * those that match with the CSSRule Selector. If matching element is found, - * Rule is applied to DOM Element. - * - * @param aDocument The DOM document to apply the rules - * @param aRuleList List of CSS style rules - */ - public void applyRulesToDom( Document aDocument, - Vector aRuleList ) - { - DocumentTraversal traversal = ( DocumentTraversal ) aDocument; - - NodeIterator iterator = traversal.createNodeIterator( aDocument - .getDocumentElement(), NodeFilter.SHOW_ELEMENT, null, true ); - - for ( Node node = iterator.nextNode(); node != null; node = iterator - .nextNode() ) - { - Element element = ( Element ) node; - if ( isStylableElement(element) ) - { - Vector rulesMatch = new Vector(); - - for ( int i = 0; i < aRuleList.size(); i++ ) - { - - CSSRule rule = ( CSSRule ) aRuleList.get( i ); - - if ( iCSSMatchMaker.match( rule, element ) ) - { - rulesMatch.add( rule ); - } - } - - sortRules( rulesMatch ); - - for ( int j = 0; j < rulesMatch.size(); j++ ) - { - CSSRule matchingRule = ( CSSRule ) rulesMatch.elementAt( j ); -// if(matchingRule.getSelector().toString().equals("box:edit")){ -// System.out.println("Party"); -// } - - applyRuleToElement( element, matchingRule ); - } - } - } - applyInheritance( aDocument ); - } - - - /** - * Checks if given property is inheritable property. - * - * @param aProperty the a property - * - * @return true, if is inheritable property - */ - public boolean isInheritableProperty( String aProperty ) - { - for ( int i = 0; i < INHERITABLE_PROPERTIES.length; i++ ) - { - if ( aProperty.equals( INHERITABLE_PROPERTIES[ i ] ) ) - { - return true; - } - } - return false; - } - - /** - * Checks if given element can inherit given property name. - * - * @param aElement the a element - * @param aPropertyName the a value's name - * - * @return true, if element can inherit the property - */ - public boolean canInherit( Element aElement, String aPropertyName ) - { - return canInherit( aElement, aPropertyName, null ); - } - - /** - * Checks if given element can inherit given property. - * - * If property value equals "inherit", the property - * is interpreted as inherited. - * - * If property is inheritable and element can inherit - * properties, the element can inherit the property. - * - * @param aElement the a element - * @param aPropertyName the a property's name - * @param aPropertyValue the a property's value - * - * @return true, if element can inherit the property - */ - public boolean canInherit( Element aElement, String aPropertyName, - String aPropertyValue ) - { - if ( aPropertyValue != null && aPropertyValue.equals( STRING_INHERIT ) ) - { - return true; - } - - if ( !isInheritableProperty( aPropertyName ) ) - { - return false; - } - - if ( iElementTypeResolver.canInherit( aElement.getNodeName() ) ) - { - return true; - } - - return false; - } - - /** - * Apply inheritance for stylable nodes that can inherit properties from - * parent elements. - * - * @param aDocument The DOM document to be modified - */ - private void applyInheritance( Document aDocument ) - { - DocumentTraversal traversal = ( DocumentTraversal ) aDocument; - - NodeIterator iterator = traversal.createNodeIterator( aDocument - .getDocumentElement(), NodeFilter.SHOW_ELEMENT, null, true ); - - for ( Node node = iterator.nextNode(); node != null; node = iterator - .nextNode() ) - { - Element element = ( Element ) node; -// if(node.getLocalName().equals("box")) -// System.out.println("Kill me!!!"); - if ( isStylableElement( element ) ) - { - if ( iElementTypeResolver.canInherit( element.getNodeName() ) ) - { - applyInheritance( element ); - } - } - } - } - - /** - * Apply inheritance for DOM Element. Checks if any of the elements parents - * has properties that can be inherited in the given element. If such - * property is found, new property to the element is added, unless there - * already exists a property with the same name. - * - * @param aElement The element to be modified - */ - private void applyInheritance( Element aElement ) - { - for ( int i = 0; i < INHERITABLE_PROPERTIES.length; i++ ) - { - String inheritableProperty = INHERITABLE_PROPERTIES[ i ]; - if ( iElementTypeResolver.canInherit( aElement.getNodeName() ) ) - { - if ( !hasAttribute( aElement, inheritableProperty ) ) - { - if ( hasParentElementWithAttribute( aElement, - inheritableProperty ) ) - { - if ( hasChildElementWithAttribute( aElement, - STRING_PROPERTY, inheritableProperty ) == null ) - { - addNewChildElement( aElement, STRING_PROPERTY, - inheritableProperty, - LexicalUnit.SAC_IDENT - + STRING_SEPARATOR + STRING_INHERIT ); - } - } - } - } - } - } - - /** - * Checks for parent element with attribute name. - * - * @param aElement The element that's parents are checked - * @param aAttributeName The name of the property - * - * @return true, aElement has parent node with given attribute name - */ - private static boolean hasParentElementWithAttribute( Element aElement, - String aAttributeName ) - { - Node n = aElement.getParentNode(); - while ( n != null ) - { - if ( n.getNodeType() == Node.ELEMENT_NODE ) - { - if ( hasChildElementWithAttribute( ( Element ) n, - STRING_PROPERTY, aAttributeName ) != null ) - { - return true; - } - } - n = n.getParentNode(); - } - return false; - } - - /** - * Apply rule to DOM Element. Creates child elements for aElement with style - * data. If the element already has matching child element, the value of it - * is overwritten. - * - * @param aElement The DOM Element - * @param aRule CSS style rule - */ - private void applyRuleToElement( Element aElement, CSSRule aRule ) - { - HashMap styleMap = aRule.getStyleMap(); - - Iterator itKeys = styleMap.keySet().iterator(); - while ( itKeys.hasNext() ) - { - String keyName = ( String ) itKeys.next(); - - // Case 1 : Rule has pseudo selector, add or replace Element - if ( aRule.isPseudo() ) - { - String selectorString = aRule.getSelector().toString(); - String pseudoPart = selectorString.substring( selectorString - .lastIndexOf( CHAR_COLON ) + 1 ); - - Vector elementsAttributes = new Vector(); - elementsAttributes.add( new NameValuePair(STRING_NAME, keyName) ); - elementsAttributes.add( new NameValuePair(STRING_PSEUDOCLASS, pseudoPart) ); - - Element e = hasChildElementWithAttributes( aElement, - STRING_PROPERTY, elementsAttributes ); - if ( e != null && hasAttribute( e, STRING_NAME, keyName ) ) - { - - CSSStyleProperty property = ( CSSStyleProperty ) styleMap - .get( keyName ); - Vector values = property.getValues(); - - CSSPropertyValue propertyValue = ( CSSPropertyValue ) values - .elementAt( 0 ); - - // 1st value has name "value" - e.setAttribute( STRING_VALUE, propertyValue - .getValueTypeAndValue() ); - - // if there are more values, their name is set to "value1, - // value 2, ..." - for ( int i = 1; i < values.size(); i++ ) - { - - propertyValue = ( CSSPropertyValue ) values - .elementAt( i ); - - e.setAttribute( STRING_VALUE + i, propertyValue - .getValueTypeAndValue() ); - } - } - else - { - - CSSStyleProperty property = ( CSSStyleProperty ) styleMap - .get( keyName ); - Vector values = property.getValues(); - - CSSPropertyValue propertyValue = ( CSSPropertyValue ) values - .elementAt( 0 ); - - Element newElement = addNewChildElement( aElement, - STRING_PROPERTY, keyName, propertyValue - .getValueTypeAndValue(), pseudoPart ); - - // Rest of the values are set to element we just created - for ( int i = 1; i < values.size(); i++ ) - { - propertyValue = ( CSSPropertyValue ) values - .elementAt( i ); - newElement.setAttribute( STRING_VALUE + i, - propertyValue.getValueTypeAndValue() ); - } - } - } - // Case 2 : Rule don't have pseudo selector, add or replace Element - else - { - Vector elementsAttributes = new Vector(); - elementsAttributes.add( new NameValuePair(STRING_NAME, keyName) ); - - Element e = hasChildElementWithAttributes( aElement, - STRING_PROPERTY, elementsAttributes ); - - if ( e != null && hasAttribute( e, STRING_NAME, keyName ) ) - { - CSSStyleProperty property = ( CSSStyleProperty ) styleMap - .get( keyName ); - Vector values = property.getValues(); - - CSSPropertyValue propertyValue = ( CSSPropertyValue ) values - .elementAt( 0 ); - - // 1st value has name "value" - e.setAttribute( STRING_VALUE, propertyValue - .getValueTypeAndValue() ); - - // if there are more values, their name is set to "value1, - // value 2, ..." - for ( int i = 1; i < values.size(); i++ ) - { - propertyValue = ( CSSPropertyValue ) values - .elementAt( i ); - e.setAttribute( STRING_VALUE + i, propertyValue - .getValueTypeAndValue() ); - } - } - else - { - - CSSStyleProperty property = ( CSSStyleProperty ) styleMap - .get( keyName ); - Vector values = property.getValues(); - - CSSPropertyValue propertyValue = ( CSSPropertyValue ) values - .elementAt( 0 ); - - Element newElement = addNewChildElement( aElement, - STRING_PROPERTY, keyName, propertyValue - .getValueTypeAndValue() ); - - // Rest of the values are set to element we just created - for ( int i = 1; i < values.size(); i++ ) - { - propertyValue = ( CSSPropertyValue ) values - .elementAt( i ); - newElement.setAttribute( STRING_VALUE + i, - propertyValue.getValueTypeAndValue() ); - } - } - } - } - } - - /** - * Checks if DOM Element has a attribute with given value. - * - * @param aElement The DOM element to check - * @param aValue Attributes value - * - * @return true, if successful - */ - private static boolean hasAttribute( Element aElement, String aValue ) - { - return hasAttribute( aElement, null, aValue ); - } - - - /** - * Checks if DOM Element has a attribute with given name and value. - * Attribute's name can be null, when only the attributes value is checked - * - * @param aElement The DOM element to check - * @param aName Attributes name - * @param aValue Attributes value - * - * @return true, if successful - */ - private static boolean hasAttribute( Element aElement, String aName, - String aValue ) - { - if ( aElement == null ) - { - return false; - } - if ( aElement.hasAttributes() ) - { - NamedNodeMap nnm = aElement.getAttributes(); - for ( int i = 0; i < nnm.getLength(); i++ ) - { - Node att = nnm.item( i ); - if ( aName != null ) - { - if ( att.getNodeValue().equals( aValue ) - && att.getNodeName().equals( aName ) ) - { - return true; - } - } - else - { - if ( att.getNodeValue().equals( aValue ) ) - { - return true; - } - } - } - } - return false; - } - - /** - * Checks for elements attributes. - * - * @param aElement The element to be checked - * @param aAttributes Attributes in name-value pairs - * - * @return true, if element has attributes given in aAttributes - */ - private static boolean hasAttributes( Element aElement, Vector aAttributes ) - { - if ( aElement == null ) - { - return false; - } - - if ( aElement.hasAttributes() ) - { - - for ( int i = 0; i < aAttributes.size(); i++ ) - { - - NameValuePair nameValuePair = ( NameValuePair ) aAttributes - .get( i ); - - String name = nameValuePair.getName(); - String value = nameValuePair.getValue(); - - if ( !hasAttribute( aElement, name, value ) ) - { - return false; - } - } - } - return true; - } - - /** - * Checks for child element with attribute's name. - * - * @param aParent The parent element - * @param aElementName The element tag name to be matched with child nodes - * name - * @param aName Attributes name to be matched - * - * @return Child element with attribute, null if none - */ - private static Element hasChildElementWithAttribute( Element aParent, - String aElementName, String aName ) - { - for ( Node n = aParent.getFirstChild(); n != null; n = n - .getNextSibling() ) - { - if ( n.getNodeType() == Node.ELEMENT_NODE ) - { - if ( hasAttribute( ( Element ) n, aName ) - && n.getNodeName().equals( aElementName ) ) - { - return ( Element ) n; - } - } - } - return null; - } - - - - /** - * Checks for child element with attributes. - * - * @param aParent The parent element - * @param aElementName The element tag name to be matched with child nodes - * name - * @param aNameValuePairs The Name-Value pairs for attributes that need to be - * found - * - * @return Child element with attributes, null if none - */ - private static Element hasChildElementWithAttributes( Element aParent, - String aElementName, Vector aNameValuePairs ) - { - for ( Node n = aParent.getFirstChild(); n != null; n = n - .getNextSibling() ) - { - if ( n.getNodeType() == Node.ELEMENT_NODE ) - { - if ( n.getNodeName().equals( aElementName ) - && hasAttributes( ( Element ) n, aNameValuePairs ) ) - { - return ( Element ) n; - } - } - } - return null; - } - - /** - * Adds the new node to DOM. - * - * @param aParent The parent of the new node - * @param aElementName Element name for new DOM node - * @param aKeyName Attribute name for new DOM node - * @param aKeyValue Attribute value for new DOM node - */ - private Element addNewChildElement( Element aParent, - String aElementName, String aKeyName, String aKeyValue ) - { - return addNewChildElement( aParent, aElementName, aKeyName, aKeyValue, null ); - } - - /** - * Adds the new node to DOM. - * - * @param aParent The parent of the new node - * @param aElementName Element name for new DOM node - * @param aKeyName Attribute name for new DOM node - * @param aKeyValue Attribute value for new DOM node - * @param aPseudo Pseudo attribute value for the DOM node - */ - private Element addNewChildElement( Element aParent, String aElementName, - String aKeyName, String aKeyValue, String aPseudo ) - { - Document document = aParent.getOwnerDocument(); - - String namespaceUri = aParent.getNamespaceURI(); - - Element newElement = document.createElementNS( namespaceUri, - aElementName ); - - if ( aPseudo != null ) - { - newElement.setAttribute( STRING_PSEUDOCLASS, aPseudo ); - } - newElement.setAttribute( STRING_NAME, aKeyName ); - newElement.setAttribute( STRING_VALUE, aKeyValue ); - - aParent.appendChild( newElement ); - return newElement; - } - - - /** - * Class for temporarily store Node's attribute name and value. - */ - private class NameValuePair - { - private String iName; - - private String iValue; - - NameValuePair( String aName, String aValue ) - { - iName = aName; - iValue = aValue; - } - - public String getName() - { - return iName; - } - - public String getValue() - { - return iValue; - } - - } - - }