| /* |
| * Licensed to the Apache Software Foundation (ASF) under one or more |
| * contributor license agreements. See the NOTICE file distributed with |
| * this work for additional information regarding copyright ownership. |
| * The ASF licenses this file to You under the Apache License, Version 2.0 |
| * (the "License"); you may not use this file except in compliance with |
| * the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| /* $Id$ */ |
| |
| package org.apache.fop.fo.flow.table; |
| |
| import org.apache.fop.apps.FOPException; |
| import org.apache.fop.datatypes.Numeric; |
| import org.apache.fop.datatypes.ValidationPercentBaseContext; |
| import org.apache.fop.fo.Constants; |
| import org.apache.fop.fo.FONode; |
| import org.apache.fop.fo.FObj; |
| import org.apache.fop.fo.PropertyList; |
| import org.apache.fop.fo.expr.PropertyException; |
| import org.apache.fop.fo.properties.CommonBorderPaddingBackground; |
| import org.apache.fop.fo.properties.EnumNumber; |
| import org.apache.fop.fo.properties.EnumProperty; |
| import org.apache.fop.fo.properties.NumberProperty; |
| import org.apache.fop.fo.properties.Property; |
| import org.apache.fop.fo.properties.PropertyMaker; |
| import org.apache.fop.layoutmgr.table.CollapsingBorderModel; |
| import org.xml.sax.Locator; |
| import org.xml.sax.Attributes; |
| |
| /** |
| * Common base class for table-related FOs |
| */ |
| public abstract class TableFObj extends FObj { |
| |
| private Numeric borderAfterPrecedence; |
| private Numeric borderBeforePrecedence; |
| private Numeric borderEndPrecedence; |
| private Numeric borderStartPrecedence; |
| |
| ConditionalBorder borderBefore; |
| ConditionalBorder borderAfter; |
| BorderSpecification borderStart; |
| BorderSpecification borderEnd; |
| |
| CollapsingBorderModel collapsingBorderModel; |
| |
| /** |
| * Create a TableFObj instance that is a child |
| * of the given {@link FONode} |
| * |
| * @param parent the parent {@link FONode} |
| */ |
| public TableFObj(FONode parent) { |
| super(parent); |
| } |
| |
| /** {@inheritDoc} */ |
| public void bind(PropertyList pList) throws FOPException { |
| super.bind(pList); |
| borderAfterPrecedence = pList.get(PR_BORDER_AFTER_PRECEDENCE).getNumeric(); |
| borderBeforePrecedence = pList.get(PR_BORDER_BEFORE_PRECEDENCE).getNumeric(); |
| borderEndPrecedence = pList.get(PR_BORDER_END_PRECEDENCE).getNumeric(); |
| borderStartPrecedence = pList.get(PR_BORDER_START_PRECEDENCE).getNumeric(); |
| if (getNameId() != FO_TABLE //Separate check for fo:table in Table.java |
| && getNameId() != FO_TABLE_CELL |
| && getCommonBorderPaddingBackground().hasPadding( |
| ValidationPercentBaseContext.getPseudoContext())) { |
| TableEventProducer eventProducer = TableEventProducer.Provider.get( |
| getUserAgent().getEventBroadcaster()); |
| eventProducer.paddingNotApplicable(this, getName(), getLocator()); |
| } |
| } |
| |
| /** |
| * Return the value for the "border-precedence" property |
| * for the given side. |
| * |
| * @param side the side for which to return the border precedence |
| * @return the "border-precedence" value for the given side |
| */ |
| public Numeric getBorderPrecedence(int side) { |
| switch (side) { |
| case CommonBorderPaddingBackground.BEFORE: |
| return borderBeforePrecedence; |
| case CommonBorderPaddingBackground.AFTER: |
| return borderAfterPrecedence; |
| case CommonBorderPaddingBackground.START: |
| return borderStartPrecedence; |
| case CommonBorderPaddingBackground.END: |
| return borderEndPrecedence; |
| default: |
| return null; |
| } |
| } |
| |
| /** |
| * Convenience method to returns a reference |
| * to the base {@link Table} instance. |
| * |
| * @return the base table instance |
| * |
| */ |
| public Table getTable() { |
| // Overridden in Table; for any other Table-node, recursive call to |
| // parent.getTable() |
| return ((TableFObj) parent).getTable(); |
| } |
| |
| /** |
| * @return the Common Border, Padding, and Background Properties. |
| */ |
| public abstract CommonBorderPaddingBackground getCommonBorderPaddingBackground(); |
| |
| /** |
| * {@link PropertyMaker} subclass for the column-number property |
| */ |
| public static class ColumnNumberPropertyMaker extends PropertyMaker { |
| |
| /** |
| * Constructor |
| * |
| * @param propId the id of the property for which the maker should |
| * be created |
| */ |
| public ColumnNumberPropertyMaker(int propId) { |
| super(propId); |
| } |
| |
| /** {@inheritDoc} */ |
| public Property make(PropertyList propertyList) |
| throws PropertyException { |
| FObj fo = propertyList.getFObj(); |
| |
| return NumberProperty.getInstance(((ColumnNumberManagerHolder) fo.getParent()) |
| .getColumnNumberManager().getCurrentColumnNumber()); |
| } |
| |
| |
| /** |
| * {@inheritDoc} |
| * Check the value of the column-number property. |
| */ |
| public Property make(PropertyList propertyList, String value, FObj fo) |
| throws PropertyException { |
| |
| Property p = super.make(propertyList, value, fo); |
| |
| int columnIndex = p.getNumeric().getValue(); |
| int colSpan = propertyList.get(Constants.PR_NUMBER_COLUMNS_SPANNED) |
| .getNumeric().getValue(); |
| |
| // only check whether the column-number is occupied in case it was |
| // specified on a fo:table-cell or fo:table-column |
| int foId = propertyList.getFObj().getNameId(); |
| if (foId == FO_TABLE_COLUMN || foId == FO_TABLE_CELL) { |
| ColumnNumberManagerHolder parent |
| = (ColumnNumberManagerHolder) propertyList.getParentFObj(); |
| ColumnNumberManager columnIndexManager = parent.getColumnNumberManager(); |
| int lastIndex = columnIndex - 1 + colSpan; |
| for (int i = columnIndex; i <= lastIndex; ++i) { |
| if (columnIndexManager.isColumnNumberUsed(i)) { |
| /* if column-number is already in use by another |
| * cell/column => error! |
| */ |
| TableEventProducer eventProducer |
| = TableEventProducer.Provider.get( |
| fo.getUserAgent().getEventBroadcaster()); |
| eventProducer.cellOverlap( |
| this, propertyList.getFObj().getName(), |
| i, propertyList.getFObj().getLocator()); |
| } |
| } |
| } |
| return p; |
| } |
| |
| /** |
| * {@inheritDoc} |
| * If the value is not positive, return a property whose value |
| * is the next column number. |
| */ |
| public Property convertProperty(Property p, |
| PropertyList propertyList, FObj fo) |
| throws PropertyException { |
| if (p instanceof EnumProperty) { |
| return EnumNumber.getInstance(p); |
| } |
| Number val = p.getNumber(); |
| if (val != null) { |
| int i = Math.round(val.floatValue()); |
| int foId = propertyList.getFObj().getNameId(); |
| if (i <= 0) { |
| if (foId == FO_TABLE_CELL || foId == FO_TABLE_COLUMN) { |
| ColumnNumberManagerHolder parent = |
| (ColumnNumberManagerHolder) propertyList.getParentFObj(); |
| ColumnNumberManager columnIndexManager = parent.getColumnNumberManager(); |
| i = columnIndexManager.getCurrentColumnNumber(); |
| } else { |
| /* very exceptional case: |
| * negative column-number specified on |
| * a FO that is not a fo:table-cell or fo:table-column |
| */ |
| i = 1; |
| } |
| TableEventProducer eventProducer = |
| TableEventProducer.Provider.get(fo.getUserAgent().getEventBroadcaster()); |
| eventProducer.forceNextColumnNumber(this, propertyList.getFObj().getName(), |
| val, i, propertyList.getFObj().getLocator()); |
| } |
| return NumberProperty.getInstance(i); |
| } |
| return convertPropertyDatatype(p, propertyList, fo); |
| } |
| |
| } |
| |
| /** {@inheritDoc} */ |
| public void processNode(String elementName, Locator locator, Attributes attlist, PropertyList pList) throws FOPException { |
| super.processNode(elementName, locator, attlist, pList); |
| Table table = getTable(); |
| if (!inMarker() && !table.isSeparateBorderModel()) { |
| collapsingBorderModel = CollapsingBorderModel.getBorderModelFor(table |
| .getBorderCollapse()); |
| setCollapsedBorders(); |
| } |
| } |
| |
| /** |
| * Prepares the borders of this element if the collapsing-border model is in use. |
| * Conflict resolution with parent elements is done where applicable. |
| */ |
| protected void setCollapsedBorders() { |
| createBorder(CommonBorderPaddingBackground.START); |
| createBorder(CommonBorderPaddingBackground.END); |
| createBorder(CommonBorderPaddingBackground.BEFORE); |
| createBorder(CommonBorderPaddingBackground.AFTER); |
| } |
| |
| /** |
| * Creates a BorderSpecification from the border set on the given side. If no border |
| * is set, a BorderSpecification with border-style none is created. |
| * |
| * @param side one of CommonBorderPaddingBackground.BEFORE|AFTER|START|END |
| */ |
| private void createBorder(int side) { |
| BorderSpecification borderSpec = new BorderSpecification( |
| getCommonBorderPaddingBackground().getBorderInfo(side), getNameId()); |
| switch (side) { |
| case CommonBorderPaddingBackground.BEFORE: |
| borderBefore = new ConditionalBorder(borderSpec, collapsingBorderModel); |
| break; |
| case CommonBorderPaddingBackground.AFTER: |
| borderAfter = new ConditionalBorder(borderSpec, collapsingBorderModel); |
| break; |
| case CommonBorderPaddingBackground.START: |
| borderStart = borderSpec; |
| break; |
| case CommonBorderPaddingBackground.END: |
| borderEnd = borderSpec; |
| break; |
| default: assert false; |
| } |
| } |
| } |