/* * This program is free software; you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License, version 2.1 as published by the Free Software * Foundation. * * You should have received a copy of the GNU Lesser General Public License along with this * program; if not, you can obtain a copy at http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html * or from the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * Copyright (c) 2001 - 2013 Object Refinery Ltd, Pentaho Corporation and Contributors.. All rights reserved. */ package org.pentaho.reporting.engine.classic.core.layout.model.context; import java.awt.Color; import org.pentaho.reporting.engine.classic.core.layout.model.Border; import org.pentaho.reporting.engine.classic.core.layout.model.BorderCorner; import org.pentaho.reporting.engine.classic.core.layout.model.BorderEdge; import org.pentaho.reporting.engine.classic.core.layout.model.RenderLength; import org.pentaho.reporting.engine.classic.core.style.BandStyleKeys; import org.pentaho.reporting.engine.classic.core.style.BorderStyle; import org.pentaho.reporting.engine.classic.core.style.BoxSizing; import org.pentaho.reporting.engine.classic.core.style.ElementStyleKeys; import org.pentaho.reporting.engine.classic.core.style.StyleKey; import org.pentaho.reporting.engine.classic.core.style.StyleSheet; import org.pentaho.reporting.engine.classic.core.util.InstanceID; import org.pentaho.reporting.engine.classic.core.util.geom.StrictGeomUtility; import org.pentaho.reporting.libraries.base.util.LFUMap; public final class BoxDefinitionFactory { private static class CacheKey { private Object instanceId; private String styleClass; protected CacheKey() { } protected CacheKey( final Object instanceId, final String styleClass ) { if ( instanceId == null ) { throw new NullPointerException(); } if ( styleClass == null ) { throw new NullPointerException(); } this.instanceId = instanceId; this.styleClass = styleClass; } protected void reuse( final Object instanceId, final String styleClass ) { if ( instanceId == null ) { throw new NullPointerException(); } if ( styleClass == null ) { throw new NullPointerException(); } this.instanceId = instanceId; this.styleClass = styleClass; } public Object getInstanceId() { return instanceId; } public void setInstanceId( final Object instanceId ) { this.instanceId = instanceId; } public String getStyleClass() { return styleClass; } public void setStyleClass( final String styleClass ) { this.styleClass = styleClass; } public boolean equals( final Object o ) { if ( this == o ) { return true; } if ( o == null || getClass() != o.getClass() ) { return false; } final CacheKey cacheKey = (CacheKey) o; if ( !instanceId.equals( cacheKey.instanceId ) ) { return false; } if ( !styleClass.equals( cacheKey.styleClass ) ) { return false; } return true; } public int hashCode() { int result = instanceId.hashCode(); result = 31 * result + styleClass.hashCode(); return result; } public String toString() { return "CacheKey{" + "instanceId=" + instanceId + ", styleClass='" + styleClass + '\'' + '}'; } } private static class CacheCarrier { private long changeTracker; private BoxDefinition boxDefinition; protected CacheCarrier( final long changeTracker, final BoxDefinition border ) { this.changeTracker = changeTracker; this.boxDefinition = border; } protected void update( final long changeTracker, final BoxDefinition border ) { this.changeTracker = changeTracker; this.boxDefinition = border; } public long getChangeTracker() { return changeTracker; } public BoxDefinition getBoxDefinition() { return boxDefinition; } } private LFUMap<CacheKey, CacheCarrier> cache; private CacheKey cacheKey; public BoxDefinitionFactory() { this.cacheKey = new CacheKey(); this.cache = new LFUMap<CacheKey, CacheCarrier>( 500 ); } public BoxDefinition getBoxDefinition( final StyleSheet es ) { final InstanceID id = es.getId(); cacheKey.reuse( id, es.getClass().getName() ); final CacheCarrier cc = cache.get( cacheKey ); if ( cc == null ) { final BoxDefinition boxDefinition = createBoxDefinition( es ); cache.put( new CacheKey( id, es.getClass().getName() ), new CacheCarrier( es.getChangeTracker(), boxDefinition ) ); return boxDefinition; } if ( cc.getChangeTracker() != es.getChangeTracker() ) { final BoxDefinition boxDefinition = createBoxDefinition( es ); cc.update( es.getChangeTracker(), boxDefinition ); return boxDefinition; } return cc.getBoxDefinition(); } private BoxDefinition createBoxDefinition( final StyleSheet style ) { final BoxDefinition box = new BoxDefinition(); box.setPreferredWidth( produceFromStyle( style, ElementStyleKeys.WIDTH, RenderLength.AUTO ) ); box.setPreferredHeight( produceFromStyle( style, ElementStyleKeys.HEIGHT, RenderLength.AUTO ) ); box.setMinimumWidth( produceFromStyle( style, ElementStyleKeys.MIN_WIDTH, RenderLength.EMPTY ) ); box.setMinimumHeight( produceFromStyle( style, ElementStyleKeys.MIN_HEIGHT, RenderLength.EMPTY ) ); box.setSizeSpecifiesBorderBox( BoxSizing.BORDER_BOX.equals( style.getStyleProperty( ElementStyleKeys.BOX_SIZING ) ) ); box.setMaximumWidth( produceFromStyle( style, ElementStyleKeys.MAX_WIDTH, RenderLength.AUTO ) ); box.setMaximumHeight( produceFromStyle( style, ElementStyleKeys.MAX_HEIGHT, RenderLength.AUTO ) ); box.setFixedPosition( produceFromStyle( style, BandStyleKeys.FIXED_POSITION, RenderLength.AUTO ) ); box.setPaddingTop( Math.max( 0, StrictGeomUtility.toInternalValue( style.getDoubleStyleProperty( ElementStyleKeys.PADDING_TOP, 0 ) ) ) ); box.setPaddingLeft( Math.max( 0, StrictGeomUtility.toInternalValue( style.getDoubleStyleProperty( ElementStyleKeys.PADDING_LEFT, 0 ) ) ) ); box.setPaddingBottom( Math.max( 0, StrictGeomUtility.toInternalValue( style.getDoubleStyleProperty( ElementStyleKeys.PADDING_BOTTOM, 0 ) ) ) ); box.setPaddingRight( Math.max( 0, StrictGeomUtility.toInternalValue( style.getDoubleStyleProperty( ElementStyleKeys.PADDING_RIGHT, 0 ) ) ) ); final BorderEdge edgeTop = createEdge( style, ElementStyleKeys.BORDER_TOP_STYLE, ElementStyleKeys.BORDER_TOP_COLOR, ElementStyleKeys.BORDER_TOP_WIDTH ); final BorderEdge edgeLeft = createEdge( style, ElementStyleKeys.BORDER_LEFT_STYLE, ElementStyleKeys.BORDER_LEFT_COLOR, ElementStyleKeys.BORDER_LEFT_WIDTH ); final BorderEdge edgeBottom = createEdge( style, ElementStyleKeys.BORDER_BOTTOM_STYLE, ElementStyleKeys.BORDER_BOTTOM_COLOR, ElementStyleKeys.BORDER_BOTTOM_WIDTH ); final BorderEdge edgeRight = createEdge( style, ElementStyleKeys.BORDER_RIGHT_STYLE, ElementStyleKeys.BORDER_RIGHT_COLOR, ElementStyleKeys.BORDER_RIGHT_WIDTH ); final BorderEdge edgeBreak = createEdge( style, ElementStyleKeys.BORDER_BREAK_STYLE, ElementStyleKeys.BORDER_BREAK_COLOR, ElementStyleKeys.BORDER_BREAK_WIDTH ); if ( BorderEdge.EMPTY.equals( edgeBottom ) && BorderEdge.EMPTY.equals( edgeLeft ) && BorderEdge.EMPTY.equals( edgeBreak ) && BorderEdge.EMPTY.equals( edgeRight ) && BorderEdge.EMPTY.equals( edgeTop ) ) { box.setBorder( Border.EMPTY_BORDER ); } else { final BorderCorner topLeftCorner = createCorner( style, ElementStyleKeys.BORDER_TOP_LEFT_RADIUS_WIDTH, ElementStyleKeys.BORDER_TOP_LEFT_RADIUS_HEIGHT ); final BorderCorner topRightCorner = createCorner( style, ElementStyleKeys.BORDER_TOP_RIGHT_RADIUS_WIDTH, ElementStyleKeys.BORDER_TOP_RIGHT_RADIUS_HEIGHT ); final BorderCorner bottmLeftCorner = createCorner( style, ElementStyleKeys.BORDER_BOTTOM_LEFT_RADIUS_WIDTH, ElementStyleKeys.BORDER_BOTTOM_LEFT_RADIUS_HEIGHT ); final BorderCorner bottomRightCorner = createCorner( style, ElementStyleKeys.BORDER_BOTTOM_RIGHT_RADIUS_WIDTH, ElementStyleKeys.BORDER_BOTTOM_RIGHT_RADIUS_HEIGHT ); box.setBorder( new Border( edgeTop, edgeLeft, edgeBottom, edgeRight, edgeBreak, topLeftCorner, topRightCorner, bottmLeftCorner, bottomRightCorner ) ); } box.lock(); return box; } private BorderCorner createCorner( final StyleSheet style, final StyleKey radiusKeyX, final StyleKey radiusKeyY ) { final float dimX = (float) style.getDoubleStyleProperty( radiusKeyX, 0 ); final float dimY = (float) style.getDoubleStyleProperty( radiusKeyY, 0 ); if ( dimX <= 0 || dimY <= 0 ) { return BorderCorner.EMPTY; } return new BorderCorner( StrictGeomUtility.toInternalValue( dimX ), StrictGeomUtility.toInternalValue( dimY ) ); } private BorderEdge createEdge( final StyleSheet style, final StyleKey borderStyleKey, final StyleKey borderColorKey, final StyleKey borderWidthKey ) { final BorderStyle styleRight = (BorderStyle) style.getStyleProperty( borderStyleKey ); if ( styleRight == null || BorderStyle.NONE.equals( styleRight ) ) { return BorderEdge.EMPTY; } final Color color = (Color) style.getStyleProperty( borderColorKey ); final double width = style.getDoubleStyleProperty( borderWidthKey, 0 ); if ( color == null || width <= 0 ) { return BorderEdge.EMPTY; } return new BorderEdge( styleRight, color, StrictGeomUtility.toInternalValue( width ) ); } private RenderLength produceFromStyle( final StyleSheet styleSheet, final StyleKey key, final RenderLength retval ) { final Float value = (Float) styleSheet.getStyleProperty( key ); if ( value == null ) { return retval; } return RenderLength.createFromRaw( value.doubleValue() ); } }