/******************************************************************************* * Copyright (c) 2008, 2015 Innoopract Informationssysteme GmbH. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * Innoopract Informationssysteme GmbH - initial API and implementation * EclipseSource - ongoing development ******************************************************************************/ package org.eclipse.rap.rwt.internal.theme; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.HashMap; import java.util.LinkedHashMap; import java.util.LinkedHashSet; import java.util.Map; import java.util.Set; import org.eclipse.rap.rwt.internal.theme.css.ConditionalValue; import org.eclipse.rap.rwt.internal.theme.css.StyleSheet; /** * Contains the values defined in a CSS style sheet in an optimized structure * for providing quick access to the values for a given element and property. */ public final class CssValuesMap { private final Map<String, Map<String, ConditionalValue[]>> elementsMap; public CssValuesMap( StyleSheet styleSheet, ThemeableWidget[] themeableWidgets ) { elementsMap = new HashMap<>(); extractValues( styleSheet, themeableWidgets ); } public ConditionalValue[] getValues( String elementName, String propertyName ) { ConditionalValue[] result = null; Map<String, ConditionalValue[]> valuesMap = elementsMap.get( elementName ); if( valuesMap != null ) { result = valuesMap.get( propertyName ); } if( result == null ) { result = elementsMap.get( "*" ).get( propertyName ); } return result; } public CssValue[] getAllValues() { Set<CssValue> resultSet = new LinkedHashSet<>(); for( Map<String, ConditionalValue[]> valuesMap : elementsMap.values() ) { for( ConditionalValue[] condValues : valuesMap.values() ) { for( ConditionalValue condValue : condValues ) { resultSet.add( condValue.value ); } } } return resultSet.toArray( new CssValue[ resultSet.size() ] ); } private void extractValues( StyleSheet styleSheet, ThemeableWidget[] themeableWidgets ) { for( ThemeableWidget themeableWidget : themeableWidgets ) { extractValuesForWidget( styleSheet, themeableWidget ); } } private void extractValuesForWidget( StyleSheet styleSheet, ThemeableWidget themeableWidget ) { if( themeableWidget.elements != null ) { for( CssElement element : themeableWidget.elements ) { extractValuesForElement( styleSheet, element ); } } } private void extractValuesForElement( StyleSheet styleSheet, CssElement element ) { String elementName = element.getName(); String[] properties = element.getProperties(); Map<String, ConditionalValue[]> valuesMap = new LinkedHashMap<>(); elementsMap.put( elementName, valuesMap ); for( String propertyName : properties ) { ConditionalValue[] values = styleSheet.getValues( elementName, propertyName ); valuesMap.put( propertyName, filterValues( values, element ) ); } } private static ConditionalValue[] filterValues( ConditionalValue[] values, CssElement element ) { Collection<ConditionalValue> resultList = new ArrayList<>(); String[] latestConstraint = null; for( ConditionalValue value : values ) { if( !Arrays.equals( latestConstraint, value.constraints ) ) { if( matches( element, value.constraints ) ) { resultList.add( value ); latestConstraint = value.constraints; } } } return resultList.toArray( new ConditionalValue[ resultList.size() ] ); } private static boolean matches( CssElement element, String[] constraints ) { boolean passed = true; // TODO [rst] Revise: no restrictions for * rules if( !"*".equals( element.getName() ) ) { for( int k = 0; k < constraints.length && passed; k++ ) { String constraint = constraints[ k ]; if( constraint.charAt( 0 ) == ':' ) { passed &= contains( element.getStates(), constraint.substring( 1 ) ); } else if( constraint.charAt( 0 ) == '[' ) { passed &= contains( element.getStyles(), constraint.substring( 1 ) ); } } } return passed; } private static boolean contains( String[] elements, String string ) { for( int i = 0; i < elements.length; i++ ) { if( string.equals( elements[ i ] ) ) { return true; } } return false; } }