| /* |
| * 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.pagination; |
| |
| // java |
| import java.util.List; |
| import java.util.Locale; |
| |
| import org.xml.sax.Locator; |
| |
| import org.apache.fop.apps.FOPException; |
| import org.apache.fop.fo.FOEventHandler; |
| import org.apache.fop.fo.FONode; |
| import org.apache.fop.fo.FOTreeBuilderContext; |
| import org.apache.fop.fo.FObj; |
| import org.apache.fop.fo.PropertyList; |
| import org.apache.fop.fo.ValidationException; |
| import org.apache.fop.fo.extensions.destination.Destination; |
| import org.apache.fop.fo.pagination.bookmarks.BookmarkTree; |
| import org.apache.fop.fo.properties.CommonAccessibility; |
| import org.apache.fop.fo.properties.CommonAccessibilityHolder; |
| import org.apache.fop.fo.properties.CommonHyphenation; |
| |
| /** |
| * Class modeling the <a href="http://www.w3.org/TR/xsl/#fo_root"> |
| * <code>fo:root</code></a> formatting object. |
| * Contains page masters, page-sequences. |
| */ |
| public class Root extends FObj implements CommonAccessibilityHolder { |
| |
| private CommonAccessibility commonAccessibility; |
| |
| private int mediaUsage; |
| |
| private LayoutMasterSet layoutMasterSet; |
| private Declarations declarations; |
| private BookmarkTree bookmarkTree; |
| private List<Destination> destinationList; |
| private List<PageSequence> pageSequences; |
| private Locale locale; |
| |
| // temporary until above list populated |
| private boolean pageSequenceFound; |
| |
| /** |
| * Keeps count of page number from over PageSequence instances |
| */ |
| private int endingPageNumberOfPreviousSequence; |
| private int totalPagesGenerated; |
| |
| /** |
| * Context class used while building the FO tree. |
| */ |
| private FOTreeBuilderContext builderContext; |
| |
| /** |
| * FOEventHandler object for this FO Tree |
| */ |
| private FOEventHandler foEventHandler; |
| |
| private PageSequence lastSeq; |
| |
| public void setLastSeq(PageSequence seq) { |
| lastSeq = seq; |
| } |
| |
| public PageSequence getLastSeq() { |
| return lastSeq; |
| } |
| |
| /** |
| * Base constructor |
| * |
| * @param parent {@link FONode} that is the parent of this object |
| * Note: parent should be null for the fo:root. |
| */ |
| public Root(FONode parent) { |
| super(parent); |
| pageSequences = new java.util.ArrayList<PageSequence>(); |
| } |
| |
| /** {@inheritDoc} */ |
| public void bind(PropertyList pList) throws FOPException { |
| super.bind(pList); |
| commonAccessibility = CommonAccessibility.getInstance(pList); |
| mediaUsage = pList.get(PR_MEDIA_USAGE).getEnum(); |
| String language = pList.get(PR_LANGUAGE).getString(); |
| String country = pList.get(PR_COUNTRY).getString(); |
| locale = CommonHyphenation.toLocale(language, country); |
| } |
| |
| /** {@inheritDoc} */ |
| public void startOfNode() throws FOPException { |
| foEventHandler.startRoot(this); |
| } |
| |
| /** {@inheritDoc} */ |
| public void endOfNode() throws FOPException { |
| if (!pageSequenceFound || layoutMasterSet == null) { |
| missingChildElementError("(layout-master-set, declarations?, " |
| + "bookmark-tree?, (page-sequence|fox:external-document)+)"); |
| } |
| foEventHandler.endRoot(this); |
| } |
| |
| /** |
| * {@inheritDoc} |
| * <br>XSL 1.0 Spec: (layout-master-set,declarations?,page-sequence+) |
| * <br>FOP: (layout-master-set, declarations?, fox:bookmarks?, page-sequence+) |
| */ |
| protected void validateChildNode(Locator loc, String nsURI, String localName) |
| throws ValidationException { |
| if (FO_URI.equals(nsURI)) { |
| if (localName.equals("layout-master-set")) { |
| if (layoutMasterSet != null) { |
| tooManyNodesError(loc, "fo:layout-master-set"); |
| } |
| } else if (localName.equals("declarations")) { |
| if (layoutMasterSet == null) { |
| nodesOutOfOrderError(loc, "fo:layout-master-set", "fo:declarations"); |
| } else if (declarations != null) { |
| tooManyNodesError(loc, "fo:declarations"); |
| } else if (bookmarkTree != null && getUserAgent().validateStrictly()) { |
| nodesOutOfOrderError(loc, "fo:declarations", "fo:bookmark-tree"); |
| } else if (pageSequenceFound) { |
| nodesOutOfOrderError(loc, "fo:declarations", "fo:page-sequence"); |
| } |
| } else if (localName.equals("bookmark-tree")) { |
| if (layoutMasterSet == null) { |
| nodesOutOfOrderError(loc, "fo:layout-master-set", "fo:bookmark-tree"); |
| } else if (bookmarkTree != null) { |
| tooManyNodesError(loc, "fo:bookmark-tree"); |
| } else if (pageSequenceFound) { |
| nodesOutOfOrderError(loc, "fo:bookmark-tree", "fo:page-sequence"); |
| } |
| } else if (localName.equals("page-sequence")) { |
| if (layoutMasterSet == null) { |
| nodesOutOfOrderError(loc, "fo:layout-master-set", "fo:page-sequence"); |
| } else { |
| pageSequenceFound = true; |
| } |
| } else { |
| invalidChildError(loc, nsURI, localName); |
| } |
| } else { |
| if (FOX_URI.equals(nsURI)) { |
| if ("external-document".equals(localName)) { |
| pageSequenceFound = true; |
| } |
| } |
| //invalidChildError(loc, nsURI, localName); |
| //Ignore non-FO elements under root |
| } |
| } |
| |
| |
| /** |
| * @param loc location in the source file |
| * @param child the {@link FONode} to validate against |
| * @throws ValidationException if the incoming node is not a valid child for the given FO |
| */ |
| protected void validateChildNode(Locator loc, FONode child) throws ValidationException { |
| if (child instanceof AbstractPageSequence) { |
| pageSequenceFound = true; |
| } |
| } |
| |
| /** {@inheritDoc} */ |
| public CommonAccessibility getCommonAccessibility() { |
| return commonAccessibility; |
| } |
| |
| /** |
| * Sets the FOEventHandler object that this Root is attached to |
| * @param foEventHandler the FOEventHandler object |
| */ |
| public void setFOEventHandler(FOEventHandler foEventHandler) { |
| this.foEventHandler = foEventHandler; |
| } |
| |
| /** |
| * This method overrides the FONode version. The FONode version calls the |
| * method by the same name for the parent object. Since Root is at the top |
| * of the tree, it returns the actual FOEventHandler object. Thus, any FONode |
| * can use this chain to find which FOEventHandler it is being built for. |
| * @return the FOEventHandler implementation that this Root is attached to |
| */ |
| public FOEventHandler getFOEventHandler() { |
| return foEventHandler; |
| } |
| |
| /** |
| * Sets the builder context for this FO tree. |
| * @param context the builder context to be used |
| */ |
| public void setBuilderContext(FOTreeBuilderContext context) { |
| this.builderContext = context; |
| } |
| |
| /** {@inheritDoc} */ |
| public FOTreeBuilderContext getBuilderContext() { |
| return this.builderContext; |
| } |
| |
| /** |
| * Gets the last page number generated by the previous page-sequence |
| * @return the last page number, 0 if no page sequences yet generated |
| */ |
| public int getEndingPageNumberOfPreviousSequence() { |
| return endingPageNumberOfPreviousSequence; |
| } |
| |
| /** |
| * Returns the total number of pages generated by FOP |
| * (May not equal endingPageNumberOfPreviousSequence due to |
| * initial-page-number property on fo:page-sequences.) |
| * @return the last page number, 0 if no page sequences yet generated |
| */ |
| public int getTotalPagesGenerated() { |
| return totalPagesGenerated; |
| } |
| |
| /** |
| * Notify additional pages generated to increase the totalPagesGenerated counter |
| * @param lastPageNumber the last page number generated by the sequence |
| * @param additionalPages the total pages generated by the sequence (for statistics) |
| * @throws IllegalArgumentException for negative additional page counts |
| */ |
| public void notifyPageSequenceFinished(int lastPageNumber, int additionalPages) |
| throws IllegalArgumentException { |
| |
| if (additionalPages >= 0) { |
| totalPagesGenerated += additionalPages; |
| endingPageNumberOfPreviousSequence = lastPageNumber; |
| } else { |
| throw new IllegalArgumentException( |
| "Number of additional pages must be zero or greater."); |
| } |
| } |
| |
| /** |
| * Returns the number of PageSequence instances. |
| * @return the number of PageSequence instances |
| */ |
| public int getPageSequenceCount() { |
| return pageSequences.size(); |
| } |
| |
| /** |
| * Some properties, such as 'force-page-count', require a |
| * page-sequence to know about some properties of the next. |
| * @param current the current PageSequence |
| * @return succeeding PageSequence; null if none |
| */ |
| public PageSequence getSucceedingPageSequence(PageSequence current) { |
| int currentIndex = pageSequences.indexOf(current); |
| if (currentIndex == -1) { |
| return null; |
| } |
| if (currentIndex < (pageSequences.size() - 1)) { |
| return pageSequences.get(currentIndex + 1); |
| } else { |
| return null; |
| } |
| } |
| |
| /** |
| * Adds the specified page sequence. |
| * |
| * @param pageSequence The page sequence to add |
| */ |
| public void addPageSequence(PageSequence pageSequence) { |
| pageSequences.add(pageSequence); |
| } |
| |
| /** |
| * Returns the last page sequence (current while parsing). |
| * |
| * @return The last page sequence or null |
| */ |
| public PageSequence getLastPageSequence() { |
| if (getPageSequenceCount() > 0) { |
| return pageSequences.get(getPageSequenceCount() - 1); |
| } else { |
| return null; |
| } |
| } |
| |
| /** |
| * Returns the associated LayoutMasterSet. |
| * @return the LayoutMasterSet instance |
| */ |
| public LayoutMasterSet getLayoutMasterSet() { |
| return this.layoutMasterSet; |
| } |
| |
| /** |
| * Sets the associated LayoutMasterSet. |
| * @param layoutMasterSet the LayoutMasterSet to use |
| */ |
| public void setLayoutMasterSet(LayoutMasterSet layoutMasterSet) { |
| this.layoutMasterSet = layoutMasterSet; |
| } |
| |
| /** |
| * Returns the associated Declarations. |
| * @return the Declarations instance |
| */ |
| public Declarations getDeclarations() { |
| return this.declarations; |
| } |
| |
| /** |
| * Sets the associated Declarations. |
| * @param declarations the Declarations to use |
| */ |
| public void setDeclarations(Declarations declarations) { |
| this.declarations = declarations; |
| } |
| |
| /** |
| * Set the BookmarkTree object for this FO |
| * @param bookmarkTree the BookmarkTree object |
| */ |
| public void setBookmarkTree(BookmarkTree bookmarkTree) { |
| this.bookmarkTree = bookmarkTree; |
| } |
| |
| /** |
| * Add a Destination object to this FO |
| * @param destination the Destination object to add |
| */ |
| public void addDestination(Destination destination) { |
| if (destinationList == null) { |
| destinationList = new java.util.ArrayList<Destination>(); |
| } |
| destinationList.add(destination); |
| } |
| |
| /** |
| * Public accessor for the list of Destination objects for this FO |
| * @return the Destination object |
| */ |
| public List getDestinationList() { |
| return destinationList; |
| } |
| |
| /** |
| * Public accessor for the BookmarkTree object for this FO |
| * @return the BookmarkTree object |
| */ |
| public BookmarkTree getBookmarkTree() { |
| return bookmarkTree; |
| } |
| |
| /** {@inheritDoc} */ |
| public Root getRoot() { |
| return this; |
| } |
| |
| /** {@inheritDoc} */ |
| public String getLocalName() { |
| return "root"; |
| } |
| |
| /** |
| * {@inheritDoc} |
| * @return {@link org.apache.fop.fo.Constants#FO_ROOT} |
| */ |
| public int getNameId() { |
| return FO_ROOT; |
| } |
| |
| |
| /** @return locale proprty. */ |
| public Locale getLocale() { |
| return locale; |
| } |
| |
| } |