1 /* 2 * Licensed to the Apache Software Foundation (ASF) under one or more 3 * contributor license agreements. See the NOTICE file distributed with 4 * this work for additional information regarding copyright ownership. 5 * The ASF licenses this file to You under the Apache License, Version 2.0 6 * (the "License"); you may not use this file except in compliance with 7 * the License. You may obtain a copy of the License at 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 */ 17 18 /* $Id: AbstractRetrieveMarker.java 1466146 2013-04-09 17:31:41Z vhennebert $ */ 19 20 package org.apache.fop.fo.flow; 21 22 import java.util.Iterator; 23 24 import org.xml.sax.Locator; 25 26 import org.apache.fop.accessibility.StructureTreeElement; 27 import org.apache.fop.apps.FOPException; 28 import org.apache.fop.fo.FONode; 29 import org.apache.fop.fo.FOText; 30 import org.apache.fop.fo.FObj; 31 import org.apache.fop.fo.FObjMixed; 32 import org.apache.fop.fo.PropertyList; 33 import org.apache.fop.fo.ValidationException; 34 import org.apache.fop.fo.XMLObj; 35 import org.apache.fop.fo.flow.table.Table; 36 37 /** 38 * Abstract base class for the <a href="http://www.w3.org/TR/xsl/#fo_retrieve-marker"> 39 * <code>fo:retrieve-marker</code></a> and 40 * <a href="http://www.w3.org/TR/xsl/#fo_retrieve-table-marker"> 41 * <code>fo:retrieve-table-marker</code></a> formatting objects. 42 43 */ 44 public abstract class AbstractRetrieveMarker extends FObjMixed { 45 46 private PropertyList propertyList; 47 48 private String retrieveClassName; 49 50 private int position; 51 private String positionLabel; 52 private int boundary; 53 private String boundaryLabel; 54 55 private StructureTreeElement structureTreeElement; 56 57 /** 58 * Create a new AbstractRetrieveMarker instance that 59 * is a child of the given {@link FONode} 60 * 61 * @param parent the parent {@link FONode} 62 */ AbstractRetrieveMarker(FONode parent)63 public AbstractRetrieveMarker(FONode parent) { 64 super(parent); 65 } 66 67 /** 68 * {@inheritDoc} 69 * <p>XSL Content Model: empty 70 */ validateChildNode(Locator loc, String nsURI, String localName)71 protected void validateChildNode(Locator loc, String nsURI, String localName) 72 throws ValidationException { 73 if (FO_URI.equals(nsURI)) { 74 invalidChildError(loc, nsURI, localName); 75 } 76 } 77 78 /** 79 * {@inheritDoc} 80 * Store a reference to the parent {@link PropertyList} 81 * to be used when the retrieve-marker is resolved. 82 */ bind(PropertyList pList)83 public void bind(PropertyList pList) throws FOPException { 84 super.bind(pList); 85 this.retrieveClassName = pList.get(PR_RETRIEVE_CLASS_NAME).getString(); 86 if (retrieveClassName == null || retrieveClassName.equals("")) { 87 missingPropertyError("retrieve-class-name"); 88 } 89 this.propertyList = pList.getParentPropertyList(); 90 } 91 92 @Override setStructureTreeElement(StructureTreeElement structureTreeElement)93 public void setStructureTreeElement(StructureTreeElement structureTreeElement) { 94 this.structureTreeElement = structureTreeElement; 95 } 96 97 @Override getStructureTreeElement()98 public StructureTreeElement getStructureTreeElement() { 99 return structureTreeElement; 100 } 101 createPropertyListFor(FObj fo, PropertyList parent)102 private PropertyList createPropertyListFor(FObj fo, PropertyList parent) { 103 return getBuilderContext().getPropertyListMaker().make(fo, parent); 104 } 105 cloneSingleNode(FONode child, FONode newParent, Marker marker, PropertyList parentPropertyList)106 private void cloneSingleNode(FONode child, FONode newParent, 107 Marker marker, PropertyList parentPropertyList) 108 throws FOPException { 109 110 if (child != null) { 111 FONode newChild = child.clone(newParent, true); 112 if (child instanceof FObj) { 113 Marker.MarkerPropertyList pList; 114 PropertyList newPropertyList = createPropertyListFor( 115 (FObj) newChild, parentPropertyList); 116 117 pList = marker.getPropertyListFor(child); 118 newChild.processNode( 119 child.getLocalName(), 120 getLocator(), 121 pList, 122 newPropertyList); 123 addChildTo(newChild, newParent); 124 newChild.startOfNode(); 125 switch (newChild.getNameId()) { 126 case FO_TABLE: 127 Table t = (Table) child; 128 cloneSubtree(t.getColumns().iterator(), 129 newChild, marker, newPropertyList); 130 cloneSingleNode(t.getTableHeader(), 131 newChild, marker, newPropertyList); 132 cloneSingleNode(t.getTableFooter(), 133 newChild, marker, newPropertyList); 134 cloneSubtree(child.getChildNodes(), 135 newChild, marker, newPropertyList); 136 break; 137 case FO_LIST_ITEM: 138 ListItem li = (ListItem) child; 139 cloneSingleNode(li.getLabel(), 140 newChild, marker, newPropertyList); 141 cloneSingleNode(li.getBody(), 142 newChild, marker, newPropertyList); 143 break; 144 default: 145 cloneSubtree(child.getChildNodes(), 146 newChild, marker, newPropertyList); 147 break; 148 } 149 newChild.endOfNode(); 150 } else if (child instanceof FOText) { 151 FOText ft = (FOText) newChild; 152 ft.bind(parentPropertyList); 153 addChildTo(newChild, newParent); 154 if (newParent instanceof AbstractRetrieveMarker) { 155 /* 156 * Otherwise the parent of newChild is a cloned FObjMixed that will 157 * call this FOText's endOfNode when its own endOfNode method is 158 * called. 159 */ 160 newChild.endOfNode(); 161 } 162 } else if (child instanceof XMLObj) { 163 addChildTo(newChild, newParent); 164 } 165 } 166 } 167 168 /** 169 * Clone the FO nodes in the parent iterator, 170 * attach the new nodes to the new parent, 171 * and map the new nodes to the existing property lists. 172 * FOText nodes are also in the new map, with a null value. 173 * Clone the subtree by a recursive call to this method. 174 * @param parentIter the iterator over the children of the old parent 175 * @param newParent the new parent for the cloned nodes 176 * @param marker the marker that contains the old property list mapping 177 * @param parentPropertyList the parent PropertyList 178 * @throws FOPException in case there was an error 179 */ cloneSubtree(Iterator parentIter, FONode newParent, Marker marker, PropertyList parentPropertyList)180 private void cloneSubtree(Iterator parentIter, FONode newParent, 181 Marker marker, PropertyList parentPropertyList) 182 throws FOPException { 183 if (parentIter != null) { 184 FONode child; 185 while (parentIter.hasNext()) { 186 child = (FONode) parentIter.next(); 187 cloneSingleNode(child, newParent, 188 marker, parentPropertyList); 189 } 190 } 191 } 192 cloneFromMarker(Marker marker)193 private void cloneFromMarker(Marker marker) 194 throws FOPException { 195 cloneSubtree(marker.getChildNodes(), this, 196 marker, propertyList); 197 handleWhiteSpaceFor(this, null); 198 } 199 200 /** 201 * Clone the subtree of the given marker 202 * 203 * @param marker the marker that is to be cloned 204 */ bindMarker(Marker marker)205 public void bindMarker(Marker marker) { 206 // clean up remnants from a possible earlier layout 207 if (firstChild != null) { 208 currentTextNode = null; 209 firstChild = null; 210 } 211 if (marker.getChildNodes() != null) { 212 try { 213 restoreFOEventHandlerState(); 214 cloneFromMarker(marker); 215 } catch (FOPException exc) { 216 getFOValidationEventProducer().markerCloningFailed(this, 217 marker.getMarkerClassName(), exc, getLocator()); 218 } 219 } else if (log.isDebugEnabled()) { 220 log.debug("Empty marker retrieved..."); 221 } 222 } 223 restoreFOEventHandlerState()224 protected abstract void restoreFOEventHandlerState(); 225 226 /** 227 * Return the value for the <code>retrieve-class-name</code> 228 * property 229 * 230 * @return the value for retrieve-class-name 231 */ getRetrieveClassName()232 public String getRetrieveClassName() { 233 return this.retrieveClassName; 234 } 235 setBoundaryLabel(String label)236 protected void setBoundaryLabel(String label) { 237 this.boundaryLabel = label; 238 } 239 setPositionLabel(String label)240 protected void setPositionLabel(String label) { 241 this.positionLabel = label; 242 } 243 getBoundaryLabel()244 public String getBoundaryLabel() { 245 return this.boundaryLabel; 246 } 247 getPositionLabel()248 public String getPositionLabel() { 249 return this.positionLabel; 250 } 251 setPosition(int position)252 protected void setPosition(int position) { 253 this.position = position; 254 } 255 setBoundary(int boundary)256 protected void setBoundary(int boundary) { 257 this.boundary = boundary; 258 } 259 getPosition()260 public int getPosition() { 261 return this.position; 262 } 263 getBoundary()264 public int getBoundary() { 265 return this.boundary; 266 } 267 getLocalName()268 public abstract String getLocalName(); 269 getNameId()270 public abstract int getNameId(); 271 changePositionTo(int position)272 public void changePositionTo(int position) { 273 this.position = position; 274 } 275 } 276