diff options
author | Mehdi Houshmand <mehdi@apache.org> | 2012-09-28 15:22:49 +0000 |
---|---|---|
committer | Mehdi Houshmand <mehdi@apache.org> | 2012-09-28 15:22:49 +0000 |
commit | d261730a4f7be752ae12a5ec52e6bad8ee4fa5c1 (patch) | |
tree | 1acacd7c6dd92e04e06ef6e902ee5e72b5f27523 /src/java/org/apache | |
parent | aaa7da8a0dd8ce9ce4e975c4eabbadbea0a67476 (diff) | |
download | xmlgraphics-fop-d261730a4f7be752ae12a5ec52e6bad8ee4fa5c1.tar.gz xmlgraphics-fop-d261730a4f7be752ae12a5ec52e6bad8ee4fa5c1.zip |
Bugzilla#53924: Support for retrieve-table-markers, submitted by Luis Bernardo.
git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/fop/trunk@1391502 13f79535-47bb-0310-9956-ffa450edef68
Diffstat (limited to 'src/java/org/apache')
31 files changed, 998 insertions, 331 deletions
diff --git a/src/java/org/apache/fop/area/PageViewport.java b/src/java/org/apache/fop/area/PageViewport.java index f38964ebc..d1250238a 100644 --- a/src/java/org/apache/fop/area/PageViewport.java +++ b/src/java/org/apache/fop/area/PageViewport.java @@ -34,6 +34,10 @@ import org.apache.commons.logging.LogFactory; import org.apache.fop.apps.FOPException; import org.apache.fop.fo.flow.Marker; +import org.apache.fop.fo.Constants; +import org.apache.fop.fo.flow.AbstractRetrieveMarker; +import org.apache.fop.fo.flow.Marker; +import org.apache.fop.fo.flow.Markers; import org.apache.fop.fo.pagination.SimplePageMaster; import org.apache.fop.traits.WritingModeTraitsGetter; @@ -81,13 +85,7 @@ public class PageViewport extends AreaTreeObject implements Resolvable { private Map<String, List<PageViewport>> pendingResolved = null; - // hashmap of markers for this page - // start and end are added by the fo that contains the markers - private Map<String, Marker> markerFirstStart = null; - private Map<String, Marker> markerLastStart = null; - private Map<String, Marker> markerFirstAny = null; - private Map<String, Marker> markerLastEnd = null; - private Map<String, Marker> markerLastAny = null; + private Markers pageMarkers; /** * logging instance @@ -352,115 +350,23 @@ public class PageViewport extends AreaTreeObject implements Resolvable { } /** - * Add the markers for this page. - * Only the required markers are kept. - * For "first-starting-within-page" it adds the markers - * that are starting only if the marker class name is not - * already added. - * For "first-including-carryover" it adds any starting marker - * if the marker class name is not already added. - * For "last-starting-within-page" it adds all marks that - * are starting, replacing earlier markers. - * For "last-ending-within-page" it adds all markers that - * are ending, replacing earlier markers. - * - * Should this logic be placed in the Page layout manager. + * Register the markers for this page. * * @param marks the map of markers to add * @param starting if the area being added is starting or ending * @param isfirst if the area being added has is-first trait * @param islast if the area being added has is-last trait */ - public void addMarkers(Map<String, Marker> marks, boolean starting, - boolean isfirst, boolean islast) { - - if (marks == null) { - return; - } - if (log.isDebugEnabled()) { - log.debug("--" + marks.keySet() + ": " - + (starting ? "starting" : "ending") - + (isfirst ? ", first" : "") - + (islast ? ", last" : "")); - } - - // at the start of the area, register is-first and any areas - if (starting) { - if (isfirst) { - if (markerFirstStart == null) { - markerFirstStart = new HashMap<String, Marker>(); - } - if (markerFirstAny == null) { - markerFirstAny = new HashMap<String, Marker>(); - } - // first on page: only put in new values, leave current - for (String key : marks.keySet()) { - if (!markerFirstStart.containsKey(key)) { - markerFirstStart.put(key, marks.get(key)); - if (log.isTraceEnabled()) { - log.trace("page " + pageNumberString + ": " - + "Adding marker " + key + " to FirstStart"); - } - } - if (!markerFirstAny.containsKey(key)) { - markerFirstAny.put(key, marks.get(key)); - if (log.isTraceEnabled()) { - log.trace("page " + pageNumberString + ": " - + "Adding marker " + key + " to FirstAny"); - } - } - } - if (markerLastStart == null) { - markerLastStart = new HashMap<String, Marker>(); - } - // last on page: replace all - markerLastStart.putAll(marks); - if (log.isTraceEnabled()) { - log.trace("page " + pageNumberString + ": " - + "Adding all markers to LastStart"); - } - } else { - if (markerFirstAny == null) { - markerFirstAny = new HashMap<String, Marker>(); - } - // first on page: only put in new values, leave current - for (String key : marks.keySet()) { - if (!markerFirstAny.containsKey(key)) { - markerFirstAny.put(key, marks.get(key)); - if (log.isTraceEnabled()) { - log.trace("page " + pageNumberString + ": " - + "Adding marker " + key + " to FirstAny"); - } - } - } - } - } else { - // at the end of the area, register is-last and any areas - if (islast) { - if (markerLastEnd == null) { - markerLastEnd = new HashMap<String, Marker>(); - } - // last on page: replace all - markerLastEnd.putAll(marks); - if (log.isTraceEnabled()) { - log.trace("page " + pageNumberString + ": " - + "Adding all markers to LastEnd"); - } - } - if (markerLastAny == null) { - markerLastAny = new HashMap<String, Marker>(); - } - // last on page: replace all - markerLastAny.putAll(marks); - if (log.isTraceEnabled()) { - log.trace("page " + pageNumberString + ": " - + "Adding all markers to LastAny"); - } + public void registerMarkers(Map<String, Marker> marks, boolean starting, boolean isfirst, boolean islast) { + if (pageMarkers == null) { + pageMarkers = new Markers(); } + pageMarkers.register(marks, starting, isfirst, islast); } + /** - * Get a marker from this page. + * Resolve a marker from this page. * This will retrieve a marker with the class name * and position. * @@ -468,64 +374,17 @@ public class PageViewport extends AreaTreeObject implements Resolvable { * @param pos the position to retrieve * @return Object the marker found or null */ - public Marker getMarker(String name, int pos) { - Marker mark = null; - String posName = null; - switch (pos) { - case EN_FSWP: - if (markerFirstStart != null) { - mark = markerFirstStart.get(name); - posName = "FSWP"; - } - if (mark == null && markerFirstAny != null) { - mark = markerFirstAny.get(name); - posName = "FirstAny after " + posName; - } - break; - case EN_FIC: - if (markerFirstAny != null) { - mark = markerFirstAny.get(name); - posName = "FIC"; - } - break; - case EN_LSWP: - if (markerLastStart != null) { - mark = markerLastStart.get(name); - posName = "LSWP"; - } - if (mark == null && markerLastAny != null) { - mark = markerLastAny.get(name); - posName = "LastAny after " + posName; - } - break; - case EN_LEWP: - if (markerLastEnd != null) { - mark = markerLastEnd.get(name); - posName = "LEWP"; - } - if (mark == null && markerLastAny != null) { - mark = markerLastAny.get(name); - posName = "LastAny after " + posName; - } - break; - default: - assert false; - } - if (log.isTraceEnabled()) { - log.trace("page " + pageNumberString + ": " + "Retrieving marker " + name - + " at position " + posName); + public Marker resolveMarker(AbstractRetrieveMarker rm) { + if (pageMarkers == null) { + return null; } - return mark; + return pageMarkers.resolve(rm); } /** Dumps the current marker data to the logger. */ public void dumpMarkers() { - if (log.isTraceEnabled()) { - log.trace("FirstAny: " + this.markerFirstAny); - log.trace("FirstStart: " + this.markerFirstStart); - log.trace("LastAny: " + this.markerLastAny); - log.trace("LastEnd: " + this.markerLastEnd); - log.trace("LastStart: " + this.markerLastStart); + if (pageMarkers != null) { + pageMarkers.dump(); } } diff --git a/src/java/org/apache/fop/fo/Constants.java b/src/java/org/apache/fop/fo/Constants.java index 6688042e2..1f098fe05 100644 --- a/src/java/org/apache/fop/fo/Constants.java +++ b/src/java/org/apache/fop/fo/Constants.java @@ -1227,6 +1227,8 @@ public interface Constants { int EN_BT = 204; // bottom to top /** Enumeration constant */ int EN_TB_LR = 205; // for top-to-bottom, left-to-right writing mode + /** Enumeration constant -- for fo:retrieve-table-marker */ + int EN_FIRST_INCLUDING_CARRYOVER = 206; /** Number of enumeration constants defined */ - int ENUM_COUNT = 205; + int ENUM_COUNT = 206; } diff --git a/src/java/org/apache/fop/fo/FONode.java b/src/java/org/apache/fop/fo/FONode.java index 8b55e6d30..707dae91e 100644 --- a/src/java/org/apache/fop/fo/FONode.java +++ b/src/java/org/apache/fop/fo/FONode.java @@ -563,6 +563,19 @@ public abstract class FONode implements Cloneable { } /** + * Helper function to return "not supported child" exceptions. Note that the child is valid, just not + * supported yet by FOP. + * + * @param loc org.xml.sax.Locator object of the error (*not* parent node) + * @param nsURI namespace URI of incoming invalid node + * @param lName local name (i.e., no prefix) of incoming node + * @throws ValidationException the validation error provoked by the method call + */ + protected void notSupportedChildError(Locator loc, String nsURI, String lName) throws ValidationException { + getFOValidationEventProducer().notSupportedChild(this, getName(), new QName(nsURI, lName), loc); + } + + /** * Helper function to throw an error caused by missing mandatory child elements. * (e.g., <code>fo:layout-master-set</code> not having any <code>fo:page-master</code> * child element. diff --git a/src/java/org/apache/fop/fo/FOPropertyMapping.java b/src/java/org/apache/fop/fo/FOPropertyMapping.java index a92b71ef9..6f77efc93 100644 --- a/src/java/org/apache/fop/fo/FOPropertyMapping.java +++ b/src/java/org/apache/fop/fo/FOPropertyMapping.java @@ -2178,7 +2178,8 @@ public final class FOPropertyMapping implements Constants { m = new EnumProperty.Maker(PR_RETRIEVE_POSITION_WITHIN_TABLE); m.setInherited(false); m.addEnum("first-starting", getEnumProperty(EN_FIRST_STARTING, "FIRST_STARTING")); - m.addEnum("first-including-carryover", getEnumProperty(EN_FIC, "FIC")); + m.addEnum("first-including-carryover", + getEnumProperty(EN_FIRST_INCLUDING_CARRYOVER, "FIRST_INCLUDING_CARRYOVER")); m.addEnum("last-starting", getEnumProperty(EN_LAST_STARTING, "LAST_STARTING")); m.addEnum("last-ending", getEnumProperty(EN_LAST_ENDING, "LAST_ENDING")); m.setDefault("first-starting"); @@ -2189,7 +2190,7 @@ public final class FOPropertyMapping implements Constants { m.setInherited(false); m.addEnum("table", getEnumProperty(EN_TABLE, "TABLE")); m.addEnum("table-fragment", getEnumProperty(EN_TABLE_FRAGMENT, "TABLE_FRAGMENT")); - m.addEnum("page", getEnumProperty(EN_DOCUMENT, "PAGE")); + m.addEnum("page", getEnumProperty(EN_PAGE, "PAGE")); m.setDefault("table"); addPropertyMaker("retrieve-boundary-within-table", m); } diff --git a/src/java/org/apache/fop/fo/FOValidationEventProducer.java b/src/java/org/apache/fop/fo/FOValidationEventProducer.java index ff005b1b4..ee6b078b5 100644 --- a/src/java/org/apache/fop/fo/FOValidationEventProducer.java +++ b/src/java/org/apache/fop/fo/FOValidationEventProducer.java @@ -90,6 +90,18 @@ public interface FOValidationEventProducer extends EventProducer { Locator loc) throws ValidationException; /** + * A valid but not yet supported child was encountered. + * + * @param source the event source + * @param elementName the name of the context node + * @param offendingNode the offending node + * @param loc the location of the error or null + * @throws ValidationException the validation error provoked by the method call + */ + void notSupportedChild(Object source, String elementName, QName offendingNode, Locator loc) + throws ValidationException; + + /** * A required child element is missing. * @param source the event source * @param elementName the name of the context node diff --git a/src/java/org/apache/fop/fo/FOValidationEventProducer.xml b/src/java/org/apache/fop/fo/FOValidationEventProducer.xml index 509f7c1d3..a8b2fffb1 100644 --- a/src/java/org/apache/fop/fo/FOValidationEventProducer.xml +++ b/src/java/org/apache/fop/fo/FOValidationEventProducer.xml @@ -17,6 +17,7 @@ <message key="tooManyNodes">For "{elementName}", only one "{offendingNode}" may be declared.{{locator}}</message> <message key="nodeOutOfOrder">For "{elementName}", "{tooLateNode}" must be declared before "{tooEarlyNode}"!{{locator}}</message> <message key="invalidChild">"{offendingNode}" is not a valid child of "{elementName}"![ {ruleViolated,lookup}]{{locator}}</message> + <message key="notSupportedChild">"{offendingNode}" as a child of "{elementName}" is not supported yet!{{locator}}</message> <message key="missingChildElement">"{elementName}" is missing child elements.[ Required content model: {contentModel}]{{locator}}</message> <message key="missingProperty">Element "{elementName}" is missing required property "{propertyName}"!{{locator}}</message> <message key="idNotUnique">Property ID "{id}" (found on "{elementName}") previously used; ID values must be unique within a document!{severity,equals,EventSeverity:FATAL,, Any reference to it will be considered a reference to the first occurrence in the document.}{{locator}}</message> diff --git a/src/java/org/apache/fop/fo/FObj.java b/src/java/org/apache/fop/fo/FObj.java index 241a442ab..0e7e55aa9 100644 --- a/src/java/org/apache/fop/fo/FObj.java +++ b/src/java/org/apache/fop/fo/FObj.java @@ -20,6 +20,7 @@ package org.apache.fop.fo; import java.util.Collections; +import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.ListIterator; @@ -35,6 +36,7 @@ import org.apache.xmlgraphics.util.QName; import org.apache.fop.apps.FOPException; import org.apache.fop.fo.extensions.ExtensionAttachment; import org.apache.fop.fo.flow.Marker; +import org.apache.fop.fo.flow.table.TableCell; import org.apache.fop.fo.properties.PropertyMaker; /** @@ -65,7 +67,7 @@ public abstract class FObj extends FONode implements Constants { private boolean isOutOfLineFODescendant = false; /** Markers added to this element. */ - private Map markers = null; + private Map<String, Marker> markers; private int bidiLevel = -1; @@ -356,7 +358,7 @@ public abstract class FObj extends FONode implements Constants { } } if (markers == null) { - markers = new java.util.HashMap(); + markers = new HashMap<String, Marker>(); } if (!markers.containsKey(mcname)) { markers.put(mcname, marker); @@ -376,7 +378,7 @@ public abstract class FObj extends FONode implements Constants { /** * @return the collection of Markers attached to this object */ - public Map getMarkers() { + public Map<String, Marker> getMarkers() { return markers; } @@ -522,6 +524,11 @@ public abstract class FObj extends FONode implements Constants { int found = 1; FONode temp = getParent(); while (temp != null) { + if (temp instanceof TableCell && (ancestorID == FO_TABLE_HEADER || ancestorID == FO_TABLE_FOOTER)) { + // note that if the retrieve-table-marker is not in a table-header/footer an exception is + // thrown, so no need to reset this flag in that case + ((TableCell) temp).flagAsHavingRetrieveTableMarker(); + } if (temp.getNameId() == ancestorID) { return found; } diff --git a/src/java/org/apache/fop/fo/flow/AbstractRetrieveMarker.java b/src/java/org/apache/fop/fo/flow/AbstractRetrieveMarker.java index 62c821504..636bc04df 100644 --- a/src/java/org/apache/fop/fo/flow/AbstractRetrieveMarker.java +++ b/src/java/org/apache/fop/fo/flow/AbstractRetrieveMarker.java @@ -46,6 +46,11 @@ public abstract class AbstractRetrieveMarker extends FObjMixed { private String retrieveClassName; + private int position; + private String positionLabel; + private int boundary; + private String boundaryLabel; + /** * Create a new AbstractRetrieveMarker instance that * is a child of the given {@link FONode} @@ -206,4 +211,43 @@ public abstract class AbstractRetrieveMarker extends FObjMixed { 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; + } } diff --git a/src/java/org/apache/fop/fo/flow/Markers.java b/src/java/org/apache/fop/fo/flow/Markers.java new file mode 100644 index 000000000..24da818af --- /dev/null +++ b/src/java/org/apache/fop/fo/flow/Markers.java @@ -0,0 +1,212 @@ +/* + * 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.HashMap; +import java.util.Iterator; +import java.util.Map; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +import org.apache.fop.fo.Constants; + +/** + * A class to register and resolve markers. + */ +public final class Markers { + + // IsAny means either IsFirst or IsLast + private Map<String, Marker> firstQualifyingIsFirst; + private Map<String, Marker> firstQualifyingIsAny; + private Map<String, Marker> lastQualifyingIsFirst; + private Map<String, Marker> lastQualifyingIsLast; + private Map<String, Marker> lastQualifyingIsAny; + + private static Log log = LogFactory.getLog(Markers.class); + + /** + * Registers a marker with the position traits set. + * Only the required markers are kept. + * For "first-starting-within-page" it adds the markers + * that are starting only if the marker class name is not + * already added. + * For "first-including-carryover" it adds any starting marker + * if the marker class name is not already added. + * For "last-starting-within-page" it adds all marks that + * are starting, replacing earlier markers. + * For "last-ending-within-page" it adds all markers that + * are ending, replacing earlier markers. + * + * @param marks a map of markers to register + * @param starting whether the registration happens at the start (true) or end (false) the the area + * @param isfirst whether it is the first area of the parent LM + * @param islast whether it is the last area of the parent LM + */ + public void register(Map<String, Marker> marks, boolean starting, boolean isfirst, boolean islast) { + // TODO: find way to put the page number in the log tracing + + if (marks == null) { + return; + } + if (log.isDebugEnabled()) { + log.debug("--" + marks.keySet() + ": " + (starting ? "starting" : "ending") + + (isfirst ? ", first" : "") + (islast ? ", last" : "")); + } + + if (starting) { + // at the start of the area, register is-first and any areas + if (firstQualifyingIsAny == null) { + firstQualifyingIsAny = new HashMap<String, Marker>(); + } + if (isfirst) { + if (firstQualifyingIsFirst == null) { + firstQualifyingIsFirst = new HashMap<String, Marker>(); + } + // first on scope: only put in new values, leave current + for (Iterator<String> iter = marks.keySet().iterator(); iter.hasNext();) { + String key = iter.next(); + if (!firstQualifyingIsFirst.containsKey(key)) { + firstQualifyingIsFirst.put(key, marks.get(key)); + if (log.isTraceEnabled()) { + log.trace("Adding marker " + key + " to firstQualifyingIsFirst"); + } + } + if (!firstQualifyingIsAny.containsKey(key)) { + firstQualifyingIsAny.put(key, marks.get(key)); + if (log.isTraceEnabled()) { + log.trace("Adding marker " + key + " to firstQualifyingIsAny"); + } + } + } + if (lastQualifyingIsFirst == null) { + lastQualifyingIsFirst = new HashMap<String, Marker>(); + } + // last on scope: replace all + lastQualifyingIsFirst.putAll(marks); + if (log.isTraceEnabled()) { + log.trace("Adding all markers to LastStart"); + } + } else { + // first on scope: only put in new values, leave current + for (Iterator<String> iter = marks.keySet().iterator(); iter.hasNext();) { + String key = iter.next(); + if (!firstQualifyingIsAny.containsKey(key)) { + firstQualifyingIsAny.put(key, marks.get(key)); + if (log.isTraceEnabled()) { + log.trace("Adding marker " + key + " to firstQualifyingIsAny"); + } + } + } + } + } else { + // at the end of the area, register is-last and any areas + if (islast) { + if (lastQualifyingIsLast == null) { + lastQualifyingIsLast = new HashMap<String, Marker>(); + } + // last on page: replace all + lastQualifyingIsLast.putAll(marks); + if (log.isTraceEnabled()) { + log.trace("Adding all markers to lastQualifyingIsLast"); + } + } + if (lastQualifyingIsAny == null) { + lastQualifyingIsAny = new HashMap<String, Marker>(); + } + // last on page: replace all + lastQualifyingIsAny.putAll(marks); + if (log.isTraceEnabled()) { + log.trace("Adding all markers to lastQualifyingIsAny"); + } + } + } + + /** + * Retrieves the best candidate marker for the given position. + * @param name the key used to register the marker + * @param pos the retrieval scope position + * @return a Marker instance + */ + public Marker resolve(AbstractRetrieveMarker arm) { + Marker mark = null; + int pos = arm.getPosition(); + String name = arm.getRetrieveClassName(); + String posName = arm.getPositionLabel(); + String localName = arm.getLocalName(); + switch (pos) { + case Constants.EN_FSWP: // retrieve-marker + case Constants.EN_FIRST_STARTING: // retrieve-table-marker + if (firstQualifyingIsFirst != null) { + mark = firstQualifyingIsFirst.get(name); + } + if (mark == null && firstQualifyingIsAny != null) { + mark = firstQualifyingIsAny.get(name); + posName = "FirstAny after " + posName; + } + break; + case Constants.EN_FIC: // retrieve-marker + case Constants.EN_FIRST_INCLUDING_CARRYOVER: // retrieve-table-marker + if (firstQualifyingIsAny != null) { + mark = firstQualifyingIsAny.get(name); + } + break; + case Constants.EN_LSWP: // retrieve-marker + case Constants.EN_LAST_STARTING: // retrieve-table-marker + if (lastQualifyingIsFirst != null) { + mark = lastQualifyingIsFirst.get(name); + } + if (mark == null && lastQualifyingIsAny != null) { + mark = lastQualifyingIsAny.get(name); + posName = "LastAny after " + posName; + } + break; + case Constants.EN_LEWP: // retrieve-marker + case Constants.EN_LAST_ENDING: // retrieve-table-marker + if (lastQualifyingIsLast != null) { + mark = lastQualifyingIsLast.get(name); + } + if (mark == null && lastQualifyingIsAny != null) { + mark = lastQualifyingIsAny.get(name); + posName = "LastAny after " + posName; + } + break; + default: + throw new RuntimeException("Invalid position attribute in " + localName + "."); + } + if (log.isTraceEnabled()) { + // TODO: find way to put the page number here + log.trace(localName + ": name[" + name + "]; position [" + posName + "]"); + } + return mark; + } + + /** Dumps the current marker data to the logger. */ + public void dump() { + if (log.isTraceEnabled()) { + log.trace("FirstAny: " + this.firstQualifyingIsAny); + log.trace("FirstStart: " + this.firstQualifyingIsFirst); + log.trace("LastAny: " + this.lastQualifyingIsAny); + log.trace("LastEnd: " + this.lastQualifyingIsLast); + log.trace("LastStart: " + this.lastQualifyingIsFirst); + } + } + +} diff --git a/src/java/org/apache/fop/fo/flow/RetrieveMarker.java b/src/java/org/apache/fop/fo/flow/RetrieveMarker.java index 5fc70c7f2..b001a41ee 100644 --- a/src/java/org/apache/fop/fo/flow/RetrieveMarker.java +++ b/src/java/org/apache/fop/fo/flow/RetrieveMarker.java @@ -34,11 +34,6 @@ import org.apache.fop.fo.PropertyList; */ public class RetrieveMarker extends AbstractRetrieveMarker { - // The value of properties relevant for fo:retrieve-marker. - private int retrievePosition; - private int retrieveBoundary; - // End of property values - /** * Create a new RetrieveMarker instance that is a * child of the given {@link FONode}. @@ -70,8 +65,10 @@ public class RetrieveMarker extends AbstractRetrieveMarker { /** {@inheritDoc} */ public void bind(PropertyList pList) throws FOPException { super.bind(pList); - this.retrievePosition = pList.get(PR_RETRIEVE_POSITION).getEnum(); - this.retrieveBoundary = pList.get(PR_RETRIEVE_BOUNDARY).getEnum(); + setPosition(pList.get(PR_RETRIEVE_POSITION).getEnum()); + setPositionLabel((String) pList.get(PR_RETRIEVE_POSITION).getObject()); + setBoundary(pList.get(PR_RETRIEVE_BOUNDARY).getEnum()); + setBoundaryLabel((String) pList.get(PR_RETRIEVE_BOUNDARY).getObject()); } /** @@ -84,19 +81,19 @@ public class RetrieveMarker extends AbstractRetrieveMarker { * {@link org.apache.fop.fo.Constants#EN_LEWP}. */ public int getRetrievePosition() { - return this.retrievePosition; + return getPosition(); } /** * Return the value for the <code>retrieve-boundary</code> * property - * @return the value for retrieve-boundary-within-table; one of + * @return the value for retrieve-boundary; one of * {@link org.apache.fop.fo.Constants#EN_PAGE}, * {@link org.apache.fop.fo.Constants#EN_PAGE_SEQUENCE}, * {@link org.apache.fop.fo.Constants#EN_DOCUMENT}. */ public int getRetrieveBoundary() { - return this.retrieveBoundary; + return getBoundary(); } /** {@inheritDoc} */ diff --git a/src/java/org/apache/fop/fo/flow/RetrieveTableMarker.java b/src/java/org/apache/fop/fo/flow/RetrieveTableMarker.java index 3090cb702..efacba864 100644 --- a/src/java/org/apache/fop/fo/flow/RetrieveTableMarker.java +++ b/src/java/org/apache/fop/fo/flow/RetrieveTableMarker.java @@ -32,11 +32,6 @@ import org.apache.fop.fo.PropertyList; */ public class RetrieveTableMarker extends AbstractRetrieveMarker { - // The value of properties relevant for fo:retrieve-table-marker. - private int retrievePositionWithinTable; - private int retrieveBoundaryWithinTable; - // end property values - /** * Create a new RetrieveTableMarker instance that is * a child of the given {@link FONode}. @@ -67,10 +62,10 @@ public class RetrieveTableMarker extends AbstractRetrieveMarker { /** {@inheritDoc} */ public void bind(PropertyList pList) throws FOPException { super.bind(pList); - this.retrievePositionWithinTable - = pList.get(PR_RETRIEVE_POSITION_WITHIN_TABLE).getEnum(); - this.retrieveBoundaryWithinTable - = pList.get(PR_RETRIEVE_BOUNDARY_WITHIN_TABLE).getEnum(); + setPosition(pList.get(PR_RETRIEVE_POSITION_WITHIN_TABLE).getEnum()); + setPositionLabel((String) pList.get(PR_RETRIEVE_POSITION_WITHIN_TABLE).getObject()); + setBoundary(pList.get(PR_RETRIEVE_BOUNDARY_WITHIN_TABLE).getEnum()); + setBoundaryLabel((String) pList.get(PR_RETRIEVE_BOUNDARY_WITHIN_TABLE).getObject()); } /** @@ -83,7 +78,7 @@ public class RetrieveTableMarker extends AbstractRetrieveMarker { * {@link org.apache.fop.fo.Constants#EN_LAST_ENDING}. */ public int getRetrievePositionWithinTable() { - return this.retrievePositionWithinTable; + return getPosition(); } /** @@ -95,7 +90,7 @@ public class RetrieveTableMarker extends AbstractRetrieveMarker { * {@link org.apache.fop.fo.Constants#EN_PAGE}. */ public int getRetrieveBoundaryWithinTable() { - return this.retrieveBoundaryWithinTable; + return getBoundary(); } /** {@inheritDoc} */ @@ -110,4 +105,12 @@ public class RetrieveTableMarker extends AbstractRetrieveMarker { public int getNameId() { return FO_RETRIEVE_TABLE_MARKER; } + + /** {@inheritDoc} */ + public void clearChildNodes() { + super.clearChildNodes(); + this.currentTextNode = null; + this.lastFOTextProcessed = null; + } + } diff --git a/src/java/org/apache/fop/fo/flow/table/TableCell.java b/src/java/org/apache/fop/fo/flow/table/TableCell.java index c4f9c2aa6..f198f3aad 100644 --- a/src/java/org/apache/fop/fo/flow/table/TableCell.java +++ b/src/java/org/apache/fop/fo/flow/table/TableCell.java @@ -62,6 +62,8 @@ public class TableCell extends TableFObj implements CommonAccessibilityHolder { /** used for FO validation */ private boolean blockItemFound = false; + private boolean hasRetrieveTableMarker; + /** * Create a TableCell instance with the given {@link FONode} * as parent. @@ -247,4 +249,11 @@ public class TableCell extends TableFObj implements CommonAccessibilityHolder { return FO_TABLE_CELL; } + public void flagAsHavingRetrieveTableMarker() { + hasRetrieveTableMarker = true; + } + + public boolean hasRetrieveTableMarker() { + return hasRetrieveTableMarker; + } } diff --git a/src/java/org/apache/fop/fo/flow/table/TablePart.java b/src/java/org/apache/fop/fo/flow/table/TablePart.java index 3ab92cc94..032340681 100644 --- a/src/java/org/apache/fop/fo/flow/table/TablePart.java +++ b/src/java/org/apache/fop/fo/flow/table/TablePart.java @@ -169,6 +169,8 @@ public abstract class TablePart extends TableCellContainer { getUserAgent().getEventBroadcaster()); eventProducer.noMixRowsAndCells(this, getName(), getLocator()); } + } else if (localName.equals("retrieve-table-marker")) { + notSupportedChildError(loc, nsURI, localName); } else { invalidChildError(loc, nsURI, localName); } diff --git a/src/java/org/apache/fop/layoutmgr/AbstractBaseLayoutManager.java b/src/java/org/apache/fop/layoutmgr/AbstractBaseLayoutManager.java index 8c213d7d5..5d7cc0b64 100644 --- a/src/java/org/apache/fop/layoutmgr/AbstractBaseLayoutManager.java +++ b/src/java/org/apache/fop/layoutmgr/AbstractBaseLayoutManager.java @@ -273,4 +273,11 @@ public abstract class AbstractBaseLayoutManager throw new UnsupportedOperationException("Not implemented"); } + public void preserveChildrenAtEndOfLayout() { + + } + + public void recreateChildrenLMs() { + + } } diff --git a/src/java/org/apache/fop/layoutmgr/AbstractLayoutManager.java b/src/java/org/apache/fop/layoutmgr/AbstractLayoutManager.java index 0089f228f..3d64c436c 100644 --- a/src/java/org/apache/fop/layoutmgr/AbstractLayoutManager.java +++ b/src/java/org/apache/fop/layoutmgr/AbstractLayoutManager.java @@ -37,6 +37,7 @@ import org.apache.fop.fo.FONode; import org.apache.fop.fo.FObj; import org.apache.fop.fo.flow.Marker; import org.apache.fop.fo.flow.RetrieveMarker; +import org.apache.fop.layoutmgr.table.TableLayoutManager; /** * The base class for most LayoutManagers. @@ -67,6 +68,8 @@ public abstract class AbstractLayoutManager extends AbstractBaseLayoutManager im private int lastGeneratedPosition = -1; private int smallestPosNumberChecked = Integer.MAX_VALUE; + private boolean preserveChildrenAtEndOfLayout; + /** * Abstract layout manager. */ @@ -370,19 +373,20 @@ public abstract class AbstractLayoutManager extends AbstractBaseLayoutManager im } /** - * Registers the FO's markers on the current PageViewport + * Registers the FO's markers on the current PageViewport, and if applicable on the parent TableLM. * * @param isStarting boolean indicating whether the markers qualify as 'starting' * @param isFirst boolean indicating whether the markers qualify as 'first' * @param isLast boolean indicating whether the markers qualify as 'last' */ - protected void addMarkersToPage(boolean isStarting, boolean isFirst, boolean isLast) { + protected void registerMarkers(boolean isStarting, boolean isFirst, boolean isLast) { if (this.markers != null) { - getCurrentPV().addMarkers( + getCurrentPV().registerMarkers( this.markers, isStarting, isFirst, isLast); + possiblyRegisterMarkersForTables(markers, isStarting, isFirst, isLast); } } @@ -419,11 +423,12 @@ public abstract class AbstractLayoutManager extends AbstractBaseLayoutManager im notifyEndOfLayout(); - /* References to the child LMs are no longer needed - */ - childLMs = null; - curChildLM = null; - childLMiter = null; + if (!preserveChildrenAtEndOfLayout) { + // References to the child LMs are no longer needed + childLMs = null; + curChildLM = null; + childLMiter = null; + } /* markers that qualify have been transferred to the page */ @@ -438,13 +443,21 @@ public abstract class AbstractLayoutManager extends AbstractBaseLayoutManager im || lm instanceof PageSequenceLayoutManager)) { lm = lm.getParent(); } - if (lm instanceof FlowLayoutManager) { + if (lm instanceof FlowLayoutManager && !preserveChildrenAtEndOfLayout) { fobj.clearChildNodes(); fobjIter = null; } } } + /* + * Preserves the children LMs at the end of layout. This is necessary if the layout is expected to be + * repeated, as when using retrieve-table-markers. + */ + public void preserveChildrenAtEndOfLayout() { + preserveChildrenAtEndOfLayout = true; + } + /** {@inheritDoc} */ @Override public String toString() { @@ -467,4 +480,34 @@ public abstract class AbstractLayoutManager extends AbstractBaseLayoutManager im lastGeneratedPosition = -1; } + public void recreateChildrenLMs() { + childLMs = new ArrayList(); + isFinished = false; + if (fobj == null) { + return; + } + fobjIter = fobj.getChildNodes(); + int position = 0; + while (createNextChildLMs(position++)) { + // + } + childLMiter = new LMiter(this); + for (LMiter iter = new LMiter(this); iter.hasNext();) { + AbstractBaseLayoutManager alm = (AbstractBaseLayoutManager) iter.next(); + alm.initialize(); + alm.recreateChildrenLMs(); + alm.preserveChildrenAtEndOfLayout(); + } + curChildLM = getChildLM(); + } + + protected void possiblyRegisterMarkersForTables(Map<String, Marker> markers, boolean isStarting, + boolean isFirst, boolean isLast) { + LayoutManager lm = this.parentLayoutManager; + if (lm instanceof FlowLayoutManager || lm instanceof PageSequenceLayoutManager + || !(lm instanceof AbstractLayoutManager)) { + return; + } + ((AbstractLayoutManager) lm).possiblyRegisterMarkersForTables(markers, isStarting, isFirst, isLast); + } } diff --git a/src/java/org/apache/fop/layoutmgr/AbstractPageSequenceLayoutManager.java b/src/java/org/apache/fop/layoutmgr/AbstractPageSequenceLayoutManager.java index f36cde158..edfb389ed 100644 --- a/src/java/org/apache/fop/layoutmgr/AbstractPageSequenceLayoutManager.java +++ b/src/java/org/apache/fop/layoutmgr/AbstractPageSequenceLayoutManager.java @@ -226,15 +226,14 @@ public abstract class AbstractPageSequenceLayoutManager extends AbstractLayoutMa public RetrieveMarker resolveRetrieveMarker(RetrieveMarker rm) { AreaTreeModel areaTreeModel = areaTreeHandler.getAreaTreeModel(); String name = rm.getRetrieveClassName(); - int pos = rm.getRetrievePosition(); int boundary = rm.getRetrieveBoundary(); // get marker from the current markers on area tree - Marker mark = (Marker)getCurrentPV().getMarker(name, pos); + Marker mark = getCurrentPV().resolveMarker(rm); if (mark == null && boundary != EN_PAGE) { // go back over pages until mark found // if document boundary then keep going - boolean doc = boundary == EN_DOCUMENT; + boolean doc = (boundary == EN_DOCUMENT); int seq = areaTreeModel.getPageSequenceCount(); int page = areaTreeModel.getPageCount(seq) - 1; while (page < 0 && doc && seq > 1) { @@ -243,7 +242,11 @@ public abstract class AbstractPageSequenceLayoutManager extends AbstractLayoutMa } while (page >= 0) { PageViewport pv = areaTreeModel.getPage(seq, page); - mark = (Marker)pv.getMarker(name, Constants.EN_LEWP); + int originalPosition = rm.getPosition(); + rm.changePositionTo(Constants.EN_LEWP); + mark = (Marker) pv.resolveMarker(rm); + // this is probably not necessary since the RM will not be used again, but to be safe... + rm.changePositionTo(originalPosition); if (mark != null) { break; } diff --git a/src/java/org/apache/fop/layoutmgr/AreaAdditionUtil.java b/src/java/org/apache/fop/layoutmgr/AreaAdditionUtil.java index c80982cce..0ed6cb69b 100644 --- a/src/java/org/apache/fop/layoutmgr/AreaAdditionUtil.java +++ b/src/java/org/apache/fop/layoutmgr/AreaAdditionUtil.java @@ -87,7 +87,7 @@ public final class AreaAdditionUtil { } if (bslm != null) { - bslm.addMarkersToPage( + bslm.registerMarkers( true, bslm.isFirst(firstPos), bslm.isLast(lastPos)); @@ -114,11 +114,10 @@ public final class AreaAdditionUtil { } if (bslm != null) { - bslm.addMarkersToPage( + bslm.registerMarkers( false, bslm.isFirst(firstPos), bslm.isLast(lastPos)); - bslm.checkEndOfLayout(lastPos); } diff --git a/src/java/org/apache/fop/layoutmgr/BlockContainerLayoutManager.java b/src/java/org/apache/fop/layoutmgr/BlockContainerLayoutManager.java index 920589657..d20215151 100644 --- a/src/java/org/apache/fop/layoutmgr/BlockContainerLayoutManager.java +++ b/src/java/org/apache/fop/layoutmgr/BlockContainerLayoutManager.java @@ -806,7 +806,7 @@ public class BlockContainerLayoutManager extends BlockStackingLayoutManager impl addId(); - addMarkersToPage(true, isFirst(firstPos), isLast(lastPos)); + registerMarkers(true, isFirst(firstPos), isLast(lastPos)); if (bcpos == null) { // the Positions in positionList were inside the elements @@ -826,7 +826,7 @@ public class BlockContainerLayoutManager extends BlockStackingLayoutManager impl bcpos.getBreaker().addContainedAreas(layoutContext); } - addMarkersToPage(false, isFirst(firstPos), isLast(lastPos)); + registerMarkers(false, isFirst(firstPos), isLast(lastPos)); TraitSetter.addSpaceBeforeAfter(viewportBlockArea, layoutContext.getSpaceAdjust(), effSpaceBefore, effSpaceAfter); diff --git a/src/java/org/apache/fop/layoutmgr/BlockLayoutManager.java b/src/java/org/apache/fop/layoutmgr/BlockLayoutManager.java index a99b45620..f62d7f946 100644 --- a/src/java/org/apache/fop/layoutmgr/BlockLayoutManager.java +++ b/src/java/org/apache/fop/layoutmgr/BlockLayoutManager.java @@ -312,7 +312,7 @@ public class BlockLayoutManager extends BlockStackingLayoutManager implements Co addId(); - addMarkersToPage(true, isFirst(firstPos), isLast(lastPos)); + registerMarkers(true, isFirst(firstPos), isLast(lastPos)); // the Positions in positionList were inside the elements // created by the LineLM @@ -327,7 +327,7 @@ public class BlockLayoutManager extends BlockStackingLayoutManager implements Co childLM.addAreas(childPosIter, lc); } - addMarkersToPage(false, isFirst(firstPos), isLast(lastPos)); + registerMarkers(false, isFirst(firstPos), isLast(lastPos)); TraitSetter.addSpaceBeforeAfter(curBlockArea, layoutContext.getSpaceAdjust(), effSpaceBefore, effSpaceAfter); diff --git a/src/java/org/apache/fop/layoutmgr/LayoutManagerMapping.java b/src/java/org/apache/fop/layoutmgr/LayoutManagerMapping.java index 76a1cb9e4..5f4aa5725 100644 --- a/src/java/org/apache/fop/layoutmgr/LayoutManagerMapping.java +++ b/src/java/org/apache/fop/layoutmgr/LayoutManagerMapping.java @@ -31,6 +31,7 @@ import org.apache.commons.logging.LogFactory; import org.apache.fop.area.AreaTreeHandler; import org.apache.fop.fo.FOElementMapping; import org.apache.fop.fo.FONode; +import org.apache.fop.fo.FONode.FONodeIterator; import org.apache.fop.fo.FOText; import org.apache.fop.fo.FObjMixed; import org.apache.fop.fo.extensions.ExternalDocument; @@ -117,7 +118,7 @@ public class LayoutManagerMapping implements LayoutManagerMaker { registerMaker(Block.class, new BlockLayoutManagerMaker()); registerMaker(Leader.class, new LeaderLayoutManagerMaker()); registerMaker(RetrieveMarker.class, new RetrieveMarkerLayoutManagerMaker()); - registerMaker(RetrieveTableMarker.class, new Maker()); + registerMaker(RetrieveTableMarker.class, new RetrieveTableMarkerLayoutManagerMaker()); registerMaker(Character.class, new CharacterLayoutManagerMaker()); registerMaker(ExternalGraphic.class, new ExternalGraphicLayoutManagerMaker()); @@ -407,6 +408,24 @@ public class LayoutManagerMapping implements LayoutManagerMaker { } } + public class RetrieveTableMarkerLayoutManagerMaker extends Maker { + public void make(FONode node, List lms) { + FONodeIterator baseIter = node.getChildNodes(); + if (baseIter == null) { + // this happens when the retrieve-table-marker cannot be resolved yet + RetrieveTableMarker rtm = (RetrieveTableMarker) node; + RetrieveTableMarkerLayoutManager rtmlm = new RetrieveTableMarkerLayoutManager(rtm); + lms.add(rtmlm); + return; + } + while (baseIter.hasNext()) { + // this happens when the retrieve-table-marker has been resolved + FONode child = (FONode) baseIter.next(); + makeLayoutManagers(child, lms); + } + } + } + /** a layout manager maker */ public class WrapperLayoutManagerMaker extends Maker { /** {@inheritDoc} */ diff --git a/src/java/org/apache/fop/layoutmgr/LocalBreaker.java b/src/java/org/apache/fop/layoutmgr/LocalBreaker.java new file mode 100644 index 000000000..bb08446cc --- /dev/null +++ b/src/java/org/apache/fop/layoutmgr/LocalBreaker.java @@ -0,0 +1,137 @@ +/* + * 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.layoutmgr; + +import java.util.LinkedList; +import java.util.List; + +import org.apache.fop.fo.FObj; +import org.apache.fop.layoutmgr.PageBreakingAlgorithm.PageBreakingLayoutListener; +import org.apache.fop.layoutmgr.inline.TextLayoutManager; + +public abstract class LocalBreaker extends AbstractBreaker { + protected BlockStackingLayoutManager lm; + private int displayAlign; + private int ipd; + private int overflow = 0; + + public LocalBreaker(BlockStackingLayoutManager lm, int ipd, int displayAlign) { + this.lm = lm; + this.ipd = ipd; + this.displayAlign = displayAlign; + } + + /** {@inheritDoc} */ + protected boolean isPartOverflowRecoveryActivated() { + // For side regions, this must be disabled because of wanted overflow. + return false; + } + + public boolean isOverflow() { + return (this.overflow != 0); + } + + public int getOverflowAmount() { + return this.overflow; + } + + /** {@inheritDoc} */ + protected PageBreakingLayoutListener createLayoutListener() { + return new PageBreakingLayoutListener() { + + public void notifyOverflow(int part, int amount, FObj obj) { + if (LocalBreaker.this.overflow == 0) { + LocalBreaker.this.overflow = amount; + } + } + + }; + } + + protected LayoutManager getTopLevelLM() { + return lm; + } + + protected LayoutContext createLayoutContext() { + LayoutContext lc = super.createLayoutContext(); + lc.setRefIPD(ipd); + return lc; + } + + protected List getNextKnuthElements(LayoutContext context, int alignment) { + LayoutManager curLM; // currently active LM + List returnList = new LinkedList(); + + while ((curLM = lm.getChildLM()) != null) { + LayoutContext childLC = LayoutContext.newInstance(); + childLC.setStackLimitBP(context.getStackLimitBP()); + childLC.setRefIPD(context.getRefIPD()); + childLC.setWritingMode(context.getWritingMode()); + + List returnedList = null; + // The following is a HACK! Ignore leading and trailing white space + boolean ignore = curLM instanceof TextLayoutManager; + if (!curLM.isFinished()) { + returnedList = curLM.getNextKnuthElements(childLC, alignment); + } + if (returnedList != null && !ignore) { + lm.wrapPositionElements(returnedList, returnList); + } + } + SpaceResolver.resolveElementList(returnList); + lm.setFinished(true); + return returnList; + } + + protected int getCurrentDisplayAlign() { + return displayAlign; + } + + protected boolean hasMoreContent() { + return !lm.isFinished(); + } + + protected void addAreas(PositionIterator posIter, LayoutContext context) { + AreaAdditionUtil.addAreas(lm, posIter, context); + } + + protected void doPhase3(PageBreakingAlgorithm alg, int partCount, BlockSequence originalList, + BlockSequence effectiveList) { + if (partCount > 1) { + PageBreakPosition pos = (PageBreakPosition) alg.getPageBreaks().getFirst(); + int firstPartLength = ElementListUtils.calcContentLength(effectiveList, + effectiveList.ignoreAtStart, pos.getLeafPos()); + overflow += alg.totalWidth - firstPartLength; + } + // Rendering all parts (not just the first) at once for the case where the parts that + // overflow should be visible. + alg.removeAllPageBreaks(); + // Directly add areas after finding the breaks + this.addAreas(alg, 1, originalList, effectiveList); + } + + protected void finishPart(PageBreakingAlgorithm alg, PageBreakPosition pbp) { + // nop for static content + } + + protected LayoutManager getCurrentChildLM() { + return null; // TODO NYI + } +} diff --git a/src/java/org/apache/fop/layoutmgr/RetrieveTableMarkerLayoutManager.java b/src/java/org/apache/fop/layoutmgr/RetrieveTableMarkerLayoutManager.java new file mode 100644 index 000000000..9d0979a29 --- /dev/null +++ b/src/java/org/apache/fop/layoutmgr/RetrieveTableMarkerLayoutManager.java @@ -0,0 +1,75 @@ +/* + * 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.layoutmgr; + +import java.util.List; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +import org.apache.fop.fo.FONode; +import org.apache.fop.fo.flow.RetrieveTableMarker; +import org.apache.fop.layoutmgr.inline.InlineLevelLayoutManager; +import org.apache.fop.layoutmgr.inline.LeafNodeLayoutManager; +import org.apache.fop.layoutmgr.table.TableLayoutManager; + +public class RetrieveTableMarkerLayoutManager extends LeafNodeLayoutManager { + + private static Log log = LogFactory.getLog(RetrieveTableMarkerLayoutManager.class); + + public RetrieveTableMarkerLayoutManager(RetrieveTableMarker node) { + super(node); + } + + /** {@inheritDoc} */ + public List getNextKnuthElements(LayoutContext context, int alignment) { + setFinished(true); + FONode foNode = (FONode) getFObj(); + foNode = getTableLayoutManager().resolveRetrieveTableMarker((RetrieveTableMarker) foNode); + if (foNode != null) { + // resolve the RTM and replace current LM by the resolved target LM + InlineLevelLayoutManager illm = (InlineLevelLayoutManager) getPSLM().getLayoutManagerMaker() + .makeLayoutManager(foNode); + if (illm instanceof RetrieveTableMarkerLayoutManager) { + // happens if the retrieve-marker was empty + return null; + } + illm.setParent(getParent()); + illm.initialize(); + return illm.getNextKnuthElements(context, alignment); + } else { + return null; + } + } + + /** {@inheritDoc} */ + public void addAreas(PositionIterator posIter, LayoutContext context) { + } + + private TableLayoutManager getTableLayoutManager() { + LayoutManager parentLM = getParent(); + while (!(parentLM instanceof TableLayoutManager)) { + parentLM = parentLM.getParent(); + } + TableLayoutManager tlm = (TableLayoutManager) parentLM; + return tlm; + } + +} diff --git a/src/java/org/apache/fop/layoutmgr/StaticContentLayoutManager.java b/src/java/org/apache/fop/layoutmgr/StaticContentLayoutManager.java index 403daceb3..058b02270 100644 --- a/src/java/org/apache/fop/layoutmgr/StaticContentLayoutManager.java +++ b/src/java/org/apache/fop/layoutmgr/StaticContentLayoutManager.java @@ -167,125 +167,22 @@ public class StaticContentLayoutManager extends BlockStackingLayoutManager { return (StaticContent) fobj; } - private class StaticContentBreaker extends AbstractBreaker { - private StaticContentLayoutManager lm; - private int displayAlign; - private int ipd; - private int overflow = 0; - - public StaticContentBreaker(StaticContentLayoutManager lm, int ipd, - int displayAlign) { - this.lm = lm; - this.ipd = ipd; - this.displayAlign = displayAlign; + private class StaticContentBreaker extends LocalBreaker { + + public StaticContentBreaker(StaticContentLayoutManager lm, int ipd, int displayAlign) { + super(lm, ipd, displayAlign); } /** {@inheritDoc} */ protected void observeElementList(List elementList) { String elementListID = getStaticContentFO().getFlowName(); - String pageSequenceID = ((PageSequence)lm.getParent().getFObj()).getId(); + String pageSequenceID = ((PageSequence) lm.getParent().getFObj()).getId(); if (pageSequenceID != null && pageSequenceID.length() > 0) { elementListID += "-" + pageSequenceID; } ElementListObserver.observe(elementList, "static-content", elementListID); } - /** {@inheritDoc} */ - protected boolean isPartOverflowRecoveryActivated() { - //For side regions, this must be disabled because of wanted overflow. - return false; - } - - public boolean isOverflow() { - return (this.overflow != 0); - } - - public int getOverflowAmount() { - return this.overflow; - } - - /** {@inheritDoc} */ - protected PageBreakingLayoutListener createLayoutListener() { - return new PageBreakingLayoutListener() { - - public void notifyOverflow(int part, int amount, FObj obj) { - if (StaticContentBreaker.this.overflow == 0) { - StaticContentBreaker.this.overflow = amount; - } - } - - }; - } - - protected LayoutManager getTopLevelLM() { - return lm; - } - - protected LayoutContext createLayoutContext() { - LayoutContext lc = super.createLayoutContext(); - lc.setRefIPD(ipd); - return lc; - } - - protected List getNextKnuthElements(LayoutContext context, int alignment) { - LayoutManager curLM; // currently active LM - List returnList = new LinkedList(); - - while ((curLM = getChildLM()) != null) { - LayoutContext childLC = LayoutContext.newInstance(); - childLC.setStackLimitBP(context.getStackLimitBP()); - childLC.setRefIPD(context.getRefIPD()); - childLC.setWritingMode(context.getWritingMode()); - - List returnedList = null; - //The following is a HACK! Ignore leading and trailing white space - boolean ignore = curLM instanceof TextLayoutManager; - if (!curLM.isFinished()) { - returnedList = curLM.getNextKnuthElements(childLC, alignment); - } - if (returnedList != null && !ignore) { - lm.wrapPositionElements(returnedList, returnList); - } - } - SpaceResolver.resolveElementList(returnList); - setFinished(true); - return returnList; - } - - protected int getCurrentDisplayAlign() { - return displayAlign; - } - - protected boolean hasMoreContent() { - return !lm.isFinished(); - } - - protected void addAreas(PositionIterator posIter, LayoutContext context) { - AreaAdditionUtil.addAreas(lm, posIter, context); - } - - protected void doPhase3(PageBreakingAlgorithm alg, int partCount, - BlockSequence originalList, BlockSequence effectiveList) { - if (partCount > 1) { - PageBreakPosition pos = (PageBreakPosition)alg.getPageBreaks().getFirst(); - int firstPartLength = ElementListUtils.calcContentLength(effectiveList, - effectiveList.ignoreAtStart, pos.getLeafPos()); - overflow += alg.totalWidth - firstPartLength; - } - //Rendering all parts (not just the first) at once for the case where the parts that - //overflow should be visible. - alg.removeAllPageBreaks(); - //Directly add areas after finding the breaks - this.addAreas(alg, 1, originalList, effectiveList); - } - - protected void finishPart(PageBreakingAlgorithm alg, PageBreakPosition pbp) { - //nop for static content - } - - protected LayoutManager getCurrentChildLM() { - return null; //TODO NYI - } } /** diff --git a/src/java/org/apache/fop/layoutmgr/inline/InlineLayoutManager.java b/src/java/org/apache/fop/layoutmgr/inline/InlineLayoutManager.java index 77ac8c4d6..ebf7a9ccb 100644 --- a/src/java/org/apache/fop/layoutmgr/inline/InlineLayoutManager.java +++ b/src/java/org/apache/fop/layoutmgr/inline/InlineLayoutManager.java @@ -480,7 +480,7 @@ public class InlineLayoutManager extends InlineStackingLayoutManager { context.getLeadingSpace().addSpace(new SpaceVal(getSpaceStart(), this)); } - addMarkersToPage( + registerMarkers( true, !areaCreated, lastPos == null || isLast(lastPos)); @@ -542,7 +542,7 @@ public class InlineLayoutManager extends InlineStackingLayoutManager { setTraits(areaCreated, lastPos == null || !isLast(lastPos)); parentLayoutManager.addChildArea(getCurrentArea()); - addMarkersToPage( + registerMarkers( false, !areaCreated, lastPos == null || isLast(lastPos)); diff --git a/src/java/org/apache/fop/layoutmgr/list/ListBlockLayoutManager.java b/src/java/org/apache/fop/layoutmgr/list/ListBlockLayoutManager.java index 480934bf3..61d8a891d 100644 --- a/src/java/org/apache/fop/layoutmgr/list/ListBlockLayoutManager.java +++ b/src/java/org/apache/fop/layoutmgr/list/ListBlockLayoutManager.java @@ -171,7 +171,7 @@ public class ListBlockLayoutManager extends BlockStackingLayoutManager } } - addMarkersToPage(true, isFirst(firstPos), isLast(lastPos)); + registerMarkers(true, isFirst(firstPos), isLast(lastPos)); PositionIterator childPosIter = new PositionIterator(positionList.listIterator()); while ((childLM = childPosIter.getNextChildLM()) != null) { @@ -184,7 +184,7 @@ public class ListBlockLayoutManager extends BlockStackingLayoutManager childLM.addAreas(childPosIter, lc); } - addMarkersToPage(false, isFirst(firstPos), isLast(lastPos)); + registerMarkers(false, isFirst(firstPos), isLast(lastPos)); // We are done with this area add the background TraitSetter.addBackground(curBlockArea, diff --git a/src/java/org/apache/fop/layoutmgr/list/ListItemContentLayoutManager.java b/src/java/org/apache/fop/layoutmgr/list/ListItemContentLayoutManager.java index 3204a867e..f017da381 100644 --- a/src/java/org/apache/fop/layoutmgr/list/ListItemContentLayoutManager.java +++ b/src/java/org/apache/fop/layoutmgr/list/ListItemContentLayoutManager.java @@ -136,7 +136,7 @@ public class ListItemContentLayoutManager extends BlockStackingLayoutManager imp } } - addMarkersToPage(true, isFirst(firstPos), isLast(lastPos)); + registerMarkers(true, isFirst(firstPos), isLast(lastPos)); PositionIterator childPosIter = new PositionIterator(positionList.listIterator()); while ((childLM = childPosIter.getNextChildLM()) != null) { @@ -149,7 +149,7 @@ public class ListItemContentLayoutManager extends BlockStackingLayoutManager imp childLM.addAreas(childPosIter, lc); } - addMarkersToPage(false, isFirst(firstPos), isLast(lastPos)); + registerMarkers(false, isFirst(firstPos), isLast(lastPos)); flush(); diff --git a/src/java/org/apache/fop/layoutmgr/list/ListItemLayoutManager.java b/src/java/org/apache/fop/layoutmgr/list/ListItemLayoutManager.java index 32aa4c674..083e4ee1b 100644 --- a/src/java/org/apache/fop/layoutmgr/list/ListItemLayoutManager.java +++ b/src/java/org/apache/fop/layoutmgr/list/ListItemLayoutManager.java @@ -509,7 +509,7 @@ public class ListItemLayoutManager extends BlockStackingLayoutManager implements } } - addMarkersToPage(true, isFirst(firstPos), isLast(lastPos)); + registerMarkers(true, isFirst(firstPos), isLast(lastPos)); // use the first and the last ListItemPosition to determine the // corresponding indexes in the original labelList and bodyList @@ -563,7 +563,7 @@ public class ListItemLayoutManager extends BlockStackingLayoutManager implements } curBlockArea.setBPD(itemBPD); - addMarkersToPage(false, isFirst(firstPos), isLast(lastPos)); + registerMarkers(false, isFirst(firstPos), isLast(lastPos)); // We are done with this area add the background TraitSetter.addBackground(curBlockArea, diff --git a/src/java/org/apache/fop/layoutmgr/table/RowPainter.java b/src/java/org/apache/fop/layoutmgr/table/RowPainter.java index 955dafabd..6b0ef6ebb 100644 --- a/src/java/org/apache/fop/layoutmgr/table/RowPainter.java +++ b/src/java/org/apache/fop/layoutmgr/table/RowPainter.java @@ -303,11 +303,16 @@ class RowPainter { borderAfterWhich = ConditionalBorder.REST; } + // when adding the areas for the TableCellLayoutManager this helps with the isLast trait + // if, say, the first cell of a row has content that fits in the page, but the content of + // the second cell does not fit this will assure that the isLast trait for the first cell + // will also be false + lastCellParts[i].pgu.getCellLM().setLastTrait(lastCellParts[i].isLastPart()); addAreasForCell(firstCellParts[i].pgu, firstCellParts[i].start, lastCellParts[i].end, actualRowHeight, borderBeforeWhich, borderAfterWhich, lastOnPage); - firstCellParts[i] = null; + firstCellParts[i] = null; // why? what about the lastCellParts[i]? Arrays.fill(firstCellOnPage, i, i + currentGU.getCell().getNumberColumnsSpanned(), false); } diff --git a/src/java/org/apache/fop/layoutmgr/table/TableCellLayoutManager.java b/src/java/org/apache/fop/layoutmgr/table/TableCellLayoutManager.java index 2ca5a26d1..f810d20c5 100644 --- a/src/java/org/apache/fop/layoutmgr/table/TableCellLayoutManager.java +++ b/src/java/org/apache/fop/layoutmgr/table/TableCellLayoutManager.java @@ -21,6 +21,7 @@ package org.apache.fop.layoutmgr.table; import java.util.LinkedList; import java.util.List; +import java.util.Map; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; @@ -28,19 +29,24 @@ import org.apache.commons.logging.LogFactory; import org.apache.fop.area.Area; import org.apache.fop.area.Block; import org.apache.fop.area.Trait; +import org.apache.fop.fo.flow.Marker; import org.apache.fop.fo.flow.table.ConditionalBorder; import org.apache.fop.fo.flow.table.GridUnit; import org.apache.fop.fo.flow.table.PrimaryGridUnit; import org.apache.fop.fo.flow.table.Table; import org.apache.fop.fo.flow.table.TableCell; import org.apache.fop.fo.flow.table.TableColumn; +import org.apache.fop.fo.flow.table.TableFooter; +import org.apache.fop.fo.flow.table.TableHeader; import org.apache.fop.fo.flow.table.TablePart; import org.apache.fop.fo.flow.table.TableRow; import org.apache.fop.fo.properties.CommonBorderPaddingBackground; import org.apache.fop.fo.properties.CommonBorderPaddingBackground.BorderInfo; +import org.apache.fop.layoutmgr.AbstractLayoutManager; import org.apache.fop.layoutmgr.AreaAdditionUtil; import org.apache.fop.layoutmgr.BlockLevelLayoutManager; import org.apache.fop.layoutmgr.BlockStackingLayoutManager; +import org.apache.fop.layoutmgr.ElementListObserver; import org.apache.fop.layoutmgr.ElementListUtils; import org.apache.fop.layoutmgr.Keep; import org.apache.fop.layoutmgr.KnuthBox; @@ -49,8 +55,10 @@ import org.apache.fop.layoutmgr.KnuthGlue; import org.apache.fop.layoutmgr.KnuthPenalty; import org.apache.fop.layoutmgr.LayoutContext; import org.apache.fop.layoutmgr.LayoutManager; +import org.apache.fop.layoutmgr.LocalBreaker; import org.apache.fop.layoutmgr.Position; import org.apache.fop.layoutmgr.PositionIterator; +import org.apache.fop.layoutmgr.RetrieveTableMarkerLayoutManager; import org.apache.fop.layoutmgr.SpaceResolver; import org.apache.fop.layoutmgr.TraitSetter; import org.apache.fop.traits.BorderProps; @@ -79,6 +87,28 @@ public class TableCellLayoutManager extends BlockStackingLayoutManager private int totalHeight; private int usedBPD; private boolean emptyCell = true; + private boolean isDescendantOfTableFooter; + private boolean isDescendantOfTableHeader; + private boolean hasRetrieveTableMarker; + + // place holder for the addAreas arguments + private boolean savedAddAreasArguments; + private PositionIterator savedParentIter; + private LayoutContext savedLayoutContext; + private int[] savedSpannedGridRowHeights; + private int savedStartRow; + private int savedEndRow; + private int savedBorderBeforeWhich; + private int savedBorderAfterWhich; + private boolean savedFirstOnPage; + private boolean savedLastOnPage; + private RowPainter savedPainter; + private int savedFirstRowHeight; + // this is set to false when the table-cell has a retrieve-table-marker and is in the table-header + private boolean flushArea = true; + + // this information is set by the RowPainter + private boolean isLastTrait; /** * Create a new Cell layout manager. @@ -88,6 +118,11 @@ public class TableCellLayoutManager extends BlockStackingLayoutManager public TableCellLayoutManager(TableCell node, PrimaryGridUnit pgu) { super(node); this.primaryGridUnit = pgu; + this.isDescendantOfTableHeader = node.getParent().getParent() instanceof TableHeader + || node.getParent() instanceof TableHeader; + this.isDescendantOfTableFooter = node.getParent().getParent() instanceof TableFooter + || node.getParent() instanceof TableFooter; + this.hasRetrieveTableMarker = node.hasRetrieveTableMarker(); } /** @return the table-cell FO */ @@ -248,6 +283,84 @@ public class TableCellLayoutManager extends BlockStackingLayoutManager totalHeight = h; } + private void clearRetrieveTableMarkerChildNodes(List<LayoutManager> childrenLMs) { + if (childrenLMs == null) { + return; + } + int n = childrenLMs.size(); + for (int j = 0; j < n; j++) { + LayoutManager lm = (LayoutManager) childrenLMs.get(j); + if (lm == null) { + return; + } else if (lm instanceof RetrieveTableMarkerLayoutManager) { + ((AbstractLayoutManager) lm).getFObj().clearChildNodes(); + } else { + List<LayoutManager> lms = lm.getChildLMs(); + clearRetrieveTableMarkerChildNodes(lms); + } + } + } + + /** + * Checks whether the associated table cell of this LM is in a table header or footer. + * @return true if descendant of table header or footer + */ + private boolean isDescendantOfTableHeaderOrFooter() { + return (isDescendantOfTableFooter || isDescendantOfTableHeader); + } + + private void saveAddAreasArguments(PositionIterator parentIter, LayoutContext layoutContext, + int[] spannedGridRowHeights, int startRow, int endRow, int borderBeforeWhich, + int borderAfterWhich, boolean firstOnPage, boolean lastOnPage, RowPainter painter, + int firstRowHeight) { + // checks for savedAddAreasArguments and isDescendantOfTableHeader were already made but repeat them + if (savedAddAreasArguments) { + return; + } + if (isDescendantOfTableHeader) { + savedAddAreasArguments = true; + savedParentIter = null /* parentIter */; + savedLayoutContext = null /* layoutContext */; + savedSpannedGridRowHeights = spannedGridRowHeights; + savedStartRow = startRow; + savedEndRow = endRow; + savedBorderBeforeWhich = borderBeforeWhich; + savedBorderAfterWhich = borderAfterWhich; + savedFirstOnPage = firstOnPage; + savedLastOnPage = lastOnPage; + savedPainter = painter; + savedFirstRowHeight = firstRowHeight; + TableLayoutManager parentTableLayoutManager = getTableLayoutManager(); + parentTableLayoutManager.saveTableHeaderTableCellLayoutManagers(this); + // this saving is done the first time the addArea() is called; since the retrieve-table-markers + // cannot be resolved at this time we do not want to flush the area; the area needs nevertheless + // be built so that space is allocated for it. + flushArea = false; + } + } + + private TableLayoutManager getTableLayoutManager() { + LayoutManager parentLM = getParent(); + while (!(parentLM instanceof TableLayoutManager)) { + parentLM = parentLM.getParent(); + } + TableLayoutManager tlm = (TableLayoutManager) parentLM; + return tlm; + } + + /** + * Calls the addAreas() using the original arguments. + */ + protected void repeatAddAreas() { + if (savedAddAreasArguments) { + addAreas(savedParentIter, savedLayoutContext, savedSpannedGridRowHeights, savedStartRow, + savedEndRow, savedBorderBeforeWhich, savedBorderAfterWhich, savedFirstOnPage, + savedLastOnPage, savedPainter, savedFirstRowHeight); + // so that the arguments of the next table fragment header can be saved + savedAddAreasArguments = false; + } + } + /** * Add the areas for the break points. The cell contains block stacking layout * managers that add block areas. @@ -407,7 +520,28 @@ public class TableCellLayoutManager extends BlockStackingLayoutManager } } - AreaAdditionUtil.addAreas(this, parentIter, layoutContext); + if (isDescendantOfTableHeaderOrFooter()) { + if (hasRetrieveTableMarker) { + if (isDescendantOfTableHeader && !savedAddAreasArguments) { + saveAddAreasArguments(parentIter, layoutContext, spannedGridRowHeights, startRow, endRow, + borderBeforeWhich, borderAfterWhich, firstOnPage, lastOnPage, painter, + firstRowHeight); + } + recreateChildrenLMs(); + int displayAlign = ((TableCell) this.getFObj()).getDisplayAlign(); + TableCellBreaker breaker = new TableCellBreaker(this, cellIPD, displayAlign); + breaker.doLayout(usedBPD, false); + // this is needed so the next time the LMs are recreated they look like the originals; this + // is due to the fact that during the doLayout() above the FO tree changes when the + // retrieve-table-markers are resolved + clearRetrieveTableMarkerChildNodes(getChildLMs()); + } + } + + // if hasRetrieveTableMarker == true the areas were already added when the re-layout was done above + if (!hasRetrieveTableMarker) { + AreaAdditionUtil.addAreas(this, parentIter, layoutContext); + } // Re-adjust the cell's bpd as it may have been modified by the previous call // for some reason (?) curBlockArea.setBPD(cellBPD); @@ -418,7 +552,11 @@ public class TableCellLayoutManager extends BlockStackingLayoutManager getTableCell().getCommonBorderPaddingBackground(), this); } - flush(); + if (flushArea) { + flush(); + } else { + flushArea = true; + } curBlockArea = null; @@ -604,4 +742,49 @@ public class TableCellLayoutManager extends BlockStackingLayoutManager return true; } + private class TableCellBreaker extends LocalBreaker { + + public TableCellBreaker(TableCellLayoutManager lm, int ipd, int displayAlign) { + super(lm, ipd, displayAlign); + } + + /** + * {@inheritDoc} + */ + protected void observeElementList(List elementList) { + String elementListID = lm.getParent().getFObj().getId() + "-" + lm.getFObj().getId(); + ElementListObserver.observe(elementList, "table-cell", elementListID); + } + + } + + /** + * Registers the FO's markers on the current PageViewport and parent Table. + * + * @param isStarting boolean indicating whether the markers qualify as 'starting' + * @param isFirst boolean indicating whether the markers qualify as 'first' + * @param isLast boolean indicating whether the markers qualify as 'last' + */ + protected void registerMarkers(boolean isStarting, boolean isFirst, boolean isLast) { + Map<String, Marker> markers = getTableCell().getMarkers(); + if (markers != null) { + getCurrentPV().registerMarkers(markers, isStarting, isFirst, isLast && isLastTrait); + if (!isDescendantOfTableHeaderOrFooter()) { + getTableLayoutManager().registerMarkers(markers, isStarting, isFirst, isLast && isLastTrait); + } + } + } + + void setLastTrait(boolean isLast) { + isLastTrait = isLast; + } + + /** {@inheritDoc} */ + public void setParent(LayoutManager lm) { + this.parentLayoutManager = lm; + if (this.hasRetrieveTableMarker) { + this.getTableLayoutManager().flagAsHavingRetrieveTableMarker(); + } + } + } diff --git a/src/java/org/apache/fop/layoutmgr/table/TableContentLayoutManager.java b/src/java/org/apache/fop/layoutmgr/table/TableContentLayoutManager.java index ea8774716..d423b339d 100644 --- a/src/java/org/apache/fop/layoutmgr/table/TableContentLayoutManager.java +++ b/src/java/org/apache/fop/layoutmgr/table/TableContentLayoutManager.java @@ -31,9 +31,11 @@ import org.apache.commons.logging.LogFactory; import org.apache.fop.datatypes.PercentBaseContext; import org.apache.fop.fo.Constants; import org.apache.fop.fo.FObj; +import org.apache.fop.fo.flow.Marker; import org.apache.fop.fo.flow.table.EffRow; import org.apache.fop.fo.flow.table.PrimaryGridUnit; import org.apache.fop.fo.flow.table.Table; +import org.apache.fop.fo.flow.table.TableBody; import org.apache.fop.fo.flow.table.TablePart; import org.apache.fop.layoutmgr.BreakElement; import org.apache.fop.layoutmgr.ElementListUtils; @@ -400,9 +402,13 @@ public class TableContentLayoutManager implements PercentBaseContext { } } - Map markers = getTableLM().getTable().getMarkers(); + // there may be table fragment markers stored; clear them since we are starting a new fragment + tableLM.clearTableFragmentMarkers(); + + // note: markers at table level are to be retrieved by the page, not by the table itself + Map<String, Marker> markers = getTableLM().getTable().getMarkers(); if (markers != null) { - getTableLM().getCurrentPV().addMarkers(markers, + getTableLM().getCurrentPV().registerMarkers(markers, true, getTableLM().isFirst(firstPos), getTableLM().isLast(lastCheckPos)); } @@ -430,6 +436,10 @@ public class TableContentLayoutManager implements PercentBaseContext { addBodyAreas(tablePositions.iterator(), painter, footerElements == null); } + // if there are TCLMs saved because they have a RetrieveTableMarker, we repeat the header areas now; + // this can also be done after the areas for the footer are added but should be the same as here + tableLM.repeatAddAreasForSavedTableHeaderTableCellLayoutManagers(); + if (footerElements != null) { boolean ancestorTreatAsArtifact = layoutContext.treatAsArtifact(); layoutContext.setTreatAsArtifact(treatFooterAsArtifact); @@ -442,7 +452,7 @@ public class TableContentLayoutManager implements PercentBaseContext { this.usedBPD += painter.getAccumulatedBPD(); if (markers != null) { - getTableLM().getCurrentPV().addMarkers(markers, + getTableLM().getCurrentPV().registerMarkers(markers, false, getTableLM().isFirst(firstPos), getTableLM().isLast(lastCheckPos)); } } @@ -503,14 +513,20 @@ public class TableContentLayoutManager implements PercentBaseContext { */ private void addTablePartAreas(List positions, RowPainter painter, TablePart body, boolean isFirstPos, boolean isLastPos, boolean lastInBody, boolean lastOnPage) { - getTableLM().getCurrentPV().addMarkers(body.getMarkers(), + getTableLM().getCurrentPV().registerMarkers(body.getMarkers(), true, isFirstPos, isLastPos); + if (body instanceof TableBody) { + getTableLM().registerMarkers(body.getMarkers(), true, isFirstPos, isLastPos); + } painter.startTablePart(body); for (Iterator iter = positions.iterator(); iter.hasNext();) { painter.handleTableContentPosition((TableContentPosition) iter.next()); } - getTableLM().getCurrentPV().addMarkers(body.getMarkers(), + getTableLM().getCurrentPV().registerMarkers(body.getMarkers(), false, isFirstPos, isLastPos); + if (body instanceof TableBody) { + getTableLM().registerMarkers(body.getMarkers(), false, isFirstPos, isLastPos); + } painter.endTablePart(lastInBody, lastOnPage); } diff --git a/src/java/org/apache/fop/layoutmgr/table/TableLayoutManager.java b/src/java/org/apache/fop/layoutmgr/table/TableLayoutManager.java index 928be43c4..7d4c26546 100644 --- a/src/java/org/apache/fop/layoutmgr/table/TableLayoutManager.java +++ b/src/java/org/apache/fop/layoutmgr/table/TableLayoutManager.java @@ -23,6 +23,7 @@ import java.util.ArrayList; import java.util.Iterator; import java.util.LinkedList; import java.util.List; +import java.util.Map; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; @@ -33,6 +34,9 @@ import org.apache.fop.datatypes.LengthBase; import org.apache.fop.fo.Constants; import org.apache.fop.fo.FONode; import org.apache.fop.fo.FObj; +import org.apache.fop.fo.flow.Marker; +import org.apache.fop.fo.flow.Markers; +import org.apache.fop.fo.flow.RetrieveTableMarker; import org.apache.fop.fo.flow.table.Table; import org.apache.fop.fo.flow.table.TableColumn; import org.apache.fop.fo.properties.KeepProperty; @@ -93,6 +97,15 @@ public class TableLayoutManager extends BlockStackingLayoutManager private Position auxiliaryPosition; + // this holds a possible list of TCLMs that needed to have their addAreas() repeated + private List<TableCellLayoutManager> savedTCLMs; + private boolean areAllTCLMsSaved; + + private Markers tableMarkers; + private Markers tableFragmentMarkers; + + private boolean hasRetrieveTableMarker; + /** * Temporary holder of column background informations for a table-cell's area. * @@ -560,4 +573,112 @@ public class TableLayoutManager extends BlockStackingLayoutManager tableUnit = 0.0; } + /** + * Saves a TableCellLayoutManager for later use. + * + * @param tclm a TableCellLayoutManager that has a RetrieveTableMarker + */ + protected void saveTableHeaderTableCellLayoutManagers(TableCellLayoutManager tclm) { + if (savedTCLMs == null) { + savedTCLMs = new ArrayList<TableCellLayoutManager>(); + } + if (!areAllTCLMsSaved) { + savedTCLMs.add(tclm); + } + } + + /** + * Calls addAreas() for each of the saved TableCellLayoutManagers. + */ + protected void repeatAddAreasForSavedTableHeaderTableCellLayoutManagers() { + if (savedTCLMs == null) { + return; + } + // if we get to this stage then we are at the footer of the table fragment; this means that no more + // different TCLM need to be saved (we already have all); we flag the list as being complete then + areAllTCLMsSaved = true; + for (int i = 0; i < savedTCLMs.size(); i++) { + TableCellLayoutManager tclm = savedTCLMs.get(i); + tclm.repeatAddAreas(); + } + } + + /** + * Resolves a RetrieveTableMarker by finding a qualifying Marker to which it is bound to. + * @param rtm the RetrieveTableMarker to be resolved + * @return a bound RetrieveTableMarker instance or null if no qualifying Marker found + */ + public RetrieveTableMarker resolveRetrieveTableMarker(RetrieveTableMarker rtm) { + String name = rtm.getRetrieveClassName(); + int originalPosition = rtm.getPosition(); + boolean changedPosition = false; + + Marker mark = null; + // try the primary retrieve scope area, which is the same as table-fragment + mark = (tableFragmentMarkers == null) ? null : tableFragmentMarkers.resolve(rtm); + if (mark == null && rtm.getBoundary() != Constants.EN_TABLE_FRAGMENT) { + rtm.changePositionTo(Constants.EN_LAST_ENDING); + changedPosition = true; + // try the page scope area + mark = getCurrentPV().resolveMarker(rtm); + if (mark == null && rtm.getBoundary() != Constants.EN_PAGE) { + // try the table scope area + mark = (tableMarkers == null) ? null : tableMarkers.resolve(rtm); + } + } + if (changedPosition) { + // so that the next time it is called looks unchanged + rtm.changePositionTo(originalPosition); + } + if (mark == null) { + log.debug("found no marker with name: " + name); + return null; + } else { + rtm.bindMarker(mark); + return rtm; + } + } + + /** + * Register the markers for this table. + * + * @param marks the map of markers to add + * @param starting if the area being added is starting or ending + * @param isfirst if the area being added has is-first trait + * @param islast if the area being added has is-last trait + */ + public void registerMarkers(Map<String, Marker> marks, boolean starting, boolean isfirst, + boolean islast) { + if (tableMarkers == null) { + tableMarkers = new Markers(); + } + tableMarkers.register(marks, starting, isfirst, islast); + if (tableFragmentMarkers == null) { + tableFragmentMarkers = new Markers(); + } + tableFragmentMarkers.register(marks, starting, isfirst, islast); + } + + /** + * Clears the list of markers in the current table fragment. Should be called just before starting a new + * header (that belongs to the next table fragment). + */ + protected void clearTableFragmentMarkers() { + tableFragmentMarkers = null; + } + + public void flagAsHavingRetrieveTableMarker() { + hasRetrieveTableMarker = true; + } + + protected void possiblyRegisterMarkersForTables(Map<String, Marker> markers, boolean isStarting, + boolean isFirst, boolean isLast) { + // note: if we allow table-footer after a table-body this check should not be made and the markers + // should be registered regardless because the retrieval may be done only in the footer + if (hasRetrieveTableMarker) { + registerMarkers(markers, isStarting, isFirst, isLast); + } + super.possiblyRegisterMarkersForTables(markers, isStarting, isFirst, isLast); + } + } |