blob: f6964911099c4d4097a3ceee328b39be12a22d0c [file] [log] [blame]
/*
* 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;
import java.util.Iterator;
import org.xml.sax.Locator;
import org.apache.fop.accessibility.StructureTreeElement;
import org.apache.fop.apps.FOPException;
import org.apache.fop.fo.FONode;
import org.apache.fop.fo.FOText;
import org.apache.fop.fo.FObj;
import org.apache.fop.fo.FObjMixed;
import org.apache.fop.fo.PropertyList;
import org.apache.fop.fo.ValidationException;
import org.apache.fop.fo.XMLObj;
import org.apache.fop.fo.flow.table.Table;
/**
* Abstract base class for the <a href="http://www.w3.org/TR/xsl/#fo_retrieve-marker">
* <code>fo:retrieve-marker</code></a> and
* <a href="http://www.w3.org/TR/xsl/#fo_retrieve-table-marker">
* <code>fo:retrieve-table-marker</code></a> formatting objects.
*/
public abstract class AbstractRetrieveMarker extends FObjMixed {
private PropertyList propertyList;
private String retrieveClassName;
private int position;
private String positionLabel;
private int boundary;
private String boundaryLabel;
private StructureTreeElement structureTreeElement;
/**
* Create a new AbstractRetrieveMarker instance that
* is a child of the given {@link FONode}
*
* @param parent the parent {@link FONode}
*/
public AbstractRetrieveMarker(FONode parent) {
super(parent);
}
/**
* {@inheritDoc}
* <p>XSL Content Model: empty
*/
protected void validateChildNode(Locator loc, String nsURI, String localName)
throws ValidationException {
if (FO_URI.equals(nsURI)) {
invalidChildError(loc, nsURI, localName);
}
}
/**
* {@inheritDoc}
* Store a reference to the parent {@link PropertyList}
* to be used when the retrieve-marker is resolved.
*/
public void bind(PropertyList pList) throws FOPException {
super.bind(pList);
this.retrieveClassName = pList.get(PR_RETRIEVE_CLASS_NAME).getString();
if (retrieveClassName == null || retrieveClassName.equals("")) {
missingPropertyError("retrieve-class-name");
}
this.propertyList = pList.getParentPropertyList();
}
@Override
public void setStructureTreeElement(StructureTreeElement structureTreeElement) {
this.structureTreeElement = structureTreeElement;
}
@Override
public StructureTreeElement getStructureTreeElement() {
return structureTreeElement;
}
private PropertyList createPropertyListFor(FObj fo, PropertyList parent) {
return getBuilderContext().getPropertyListMaker().make(fo, parent);
}
private void cloneSingleNode(FONode child, FONode newParent,
Marker marker, PropertyList parentPropertyList)
throws FOPException {
if (child != null) {
FONode newChild = child.clone(newParent, true);
if (child instanceof FObj) {
Marker.MarkerPropertyList pList;
PropertyList newPropertyList = createPropertyListFor(
(FObj) newChild, parentPropertyList);
pList = marker.getPropertyListFor(child);
newChild.processNode(
child.getLocalName(),
getLocator(),
pList,
newPropertyList);
addChildTo(newChild, newParent);
newChild.startOfNode();
switch (newChild.getNameId()) {
case FO_TABLE:
Table t = (Table) child;
cloneSubtree(t.getColumns().iterator(),
newChild, marker, newPropertyList);
cloneSingleNode(t.getTableHeader(),
newChild, marker, newPropertyList);
cloneSingleNode(t.getTableFooter(),
newChild, marker, newPropertyList);
cloneSubtree(child.getChildNodes(),
newChild, marker, newPropertyList);
break;
case FO_LIST_ITEM:
ListItem li = (ListItem) child;
cloneSingleNode(li.getLabel(),
newChild, marker, newPropertyList);
cloneSingleNode(li.getBody(),
newChild, marker, newPropertyList);
break;
default:
cloneSubtree(child.getChildNodes(),
newChild, marker, newPropertyList);
break;
}
newChild.endOfNode();
} else if (child instanceof FOText) {
FOText ft = (FOText) newChild;
ft.bind(parentPropertyList);
addChildTo(newChild, newParent);
if (newParent instanceof AbstractRetrieveMarker) {
/*
* Otherwise the parent of newChild is a cloned FObjMixed that will
* call this FOText's endOfNode when its own endOfNode method is
* called.
*/
newChild.endOfNode();
}
} else if (child instanceof XMLObj) {
addChildTo(newChild, newParent);
}
}
}
/**
* Clone the FO nodes in the parent iterator,
* attach the new nodes to the new parent,
* and map the new nodes to the existing property lists.
* FOText nodes are also in the new map, with a null value.
* Clone the subtree by a recursive call to this method.
* @param parentIter the iterator over the children of the old parent
* @param newParent the new parent for the cloned nodes
* @param marker the marker that contains the old property list mapping
* @param parentPropertyList the parent PropertyList
* @throws FOPException in case there was an error
*/
private void cloneSubtree(Iterator parentIter, FONode newParent,
Marker marker, PropertyList parentPropertyList)
throws FOPException {
if (parentIter != null) {
FONode child;
while (parentIter.hasNext()) {
child = (FONode) parentIter.next();
cloneSingleNode(child, newParent,
marker, parentPropertyList);
}
}
}
private void cloneFromMarker(Marker marker)
throws FOPException {
cloneSubtree(marker.getChildNodes(), this,
marker, propertyList);
handleWhiteSpaceFor(this, null);
}
/**
* Clone the subtree of the given marker
*
* @param marker the marker that is to be cloned
*/
public void bindMarker(Marker marker) {
// clean up remnants from a possible earlier layout
if (firstChild != null) {
currentTextNode = null;
firstChild = null;
}
if (marker.getChildNodes() != null) {
try {
restoreFOEventHandlerState();
cloneFromMarker(marker);
} catch (FOPException exc) {
getFOValidationEventProducer().markerCloningFailed(this,
marker.getMarkerClassName(), exc, getLocator());
}
} else if (log.isDebugEnabled()) {
log.debug("Empty marker retrieved...");
}
}
protected abstract void restoreFOEventHandlerState();
/**
* Return the value for the <code>retrieve-class-name</code>
* property
*
* @return the value for retrieve-class-name
*/
public String getRetrieveClassName() {
return this.retrieveClassName;
}
protected void setBoundaryLabel(String label) {
this.boundaryLabel = label;
}
protected void setPositionLabel(String label) {
this.positionLabel = label;
}
public String getBoundaryLabel() {
return this.boundaryLabel;
}
public String getPositionLabel() {
return this.positionLabel;
}
protected void setPosition(int position) {
this.position = position;
}
protected void setBoundary(int boundary) {
this.boundary = boundary;
}
public int getPosition() {
return this.position;
}
public int getBoundary() {
return this.boundary;
}
public abstract String getLocalName();
public abstract int getNameId();
public void changePositionTo(int position) {
this.position = position;
}
}