Package org.apache.fop.fo.pagination

Source Code of org.apache.fop.fo.pagination.PageSequence$Maker

/*
* $Id: PageSequence.java,v 1.39.2.16 2003/04/11 00:24:41 pietsch Exp $
* ============================================================================
*                    The Apache Software License, Version 1.1
* ============================================================================
*
* Copyright (C) 1999-2003 The Apache Software Foundation. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modifica-
* tion, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
*    this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
*    this list of conditions and the following disclaimer in the documentation
*    and/or other materials provided with the distribution.
*
* 3. The end-user documentation included with the redistribution, if any, must
*    include the following acknowledgment: "This product includes software
*    developed by the Apache Software Foundation (http://www.apache.org/)."
*    Alternately, this acknowledgment may appear in the software itself, if
*    and wherever such third-party acknowledgments normally appear.
*
* 4. The names "FOP" and "Apache Software Foundation" must not be used to
*    endorse or promote products derived from this software without prior
*    written permission. For written permission, please contact
*    apache@apache.org.
*
* 5. Products derived from this software may not be called "Apache", nor may
*    "Apache" appear in their name, without prior written permission of the
*    Apache Software Foundation.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* APACHE SOFTWARE FOUNDATION OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLU-
* DING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
* ============================================================================
*
* This software consists of voluntary contributions made by many individuals
* on behalf of the Apache Software Foundation and was originally created by
* James Tauber <jtauber@jtauber.com>. For more information on the Apache
* Software Foundation, please see <http://www.apache.org/>.
*/
package org.apache.fop.fo.pagination;

// FOP
import org.apache.fop.fo.*;
import org.apache.fop.fo.properties.*;
import org.apache.fop.fo.flow.Flow;
import org.apache.fop.fo.flow.StaticContent;
import org.apache.fop.layout.AreaContainer;
import org.apache.fop.layout.BodyAreaContainer;
import org.apache.fop.layout.AreaTree;
import org.apache.fop.layout.Page;
import org.apache.fop.apps.FOPException;

// Java
import java.util.HashMap;
import java.util.ArrayList;

/**
* Class modeling the fo:page-sequence object. Provides pagination of flows.
* Much of the logic for paginating flows is contained in this class. The main
* entry point is the format method.
*
* @see <a href="@XSLFO-STD@#fo_page-sequence" target="_xslfostd">@XSLFO-STDID@
*     &para;6.4.5</a>
*/
public class PageSequence extends FObj {
    //
    // Factory methods
    //
    public static class Maker extends FObj.Maker {
        public FObj make(FObj parent, PropertyList propertyList,
                        String systemId, int line, int column)
            throws FOPException {
            return new PageSequence(parent, propertyList,
                                    systemId, line, column);
        }

    }

    public static FObj.Maker maker() {
        return new PageSequence.Maker();
    }

    //
    // intial-page-number types
    //
    private static final int EXPLICIT = 0;
    private static final int AUTO = 1;
    private static final int AUTO_EVEN = 2;
    private static final int AUTO_ODD = 3;

    /**
     * The parent root object
     */
    private Root root;

    /**
     * the set of layout masters (provided by the root object)
     */
    private LayoutMasterSet layoutMasterSet;

    // There doesn't seem to be anything in the spec requiring flows
    // to be in the order given, only that they map to the regions
    // defined in the page sequence, so all we need is this one hashtable
    // the set of flows includes StaticContent flows also

    /**
     * Map of flows to their flow name (flow-name, Flow)
     * Does only contain flows for static content!
     */
    private HashMap flowMap;

    // according to communication from Paul Grosso (XSL-List,
    // 001228, Number 406), confusion in spec section 6.4.5 about
    // multiplicity of fo:flow in XSL 1.0 is cleared up - one (1)
    // fo:flow per fo:page-sequence only.
    private Flow flow = null;

    /**
     * the "master-reference" attribute,
     * which specifies the name of the page-sequence-master or
     * page-master to be used to create pages in the sequence
     */
    private String masterName;

    // page number and related formatting variables
    private int firstPageNumber = 0;
    private PageNumberGenerator pageNumberGenerator;


    private int pageCount = 0;
    private int currentPageNumber;

    /**
     * specifies page numbering type (auto|auto-even|auto-odd|explicit)
     */
    private int pageNumberType;

    private int forcePageCountType;

    /**
     * the current page master
     */
    private SimplePageMaster currentSimplePageMaster;
    private PageSequenceMaster pageSequenceMaster;

    protected PageSequence(FObj parent, PropertyList propertyList,
                        String systemId, int line, int column)
        throws FOPException {
        super(parent, propertyList, systemId, line, column);

        if (parent.getName().equals("fo:root")) {
            this.root = (Root)parent;
        }
        else {
            throw new FOPException("page-sequence must be child of root, not "
                                   + parent.getName(), systemId, line, column);
        }

        layoutMasterSet = root.getLayoutMasterSet();

        // best time to run some checks on LayoutMasterSet
        layoutMasterSet.checkRegionNames();

        flowMap = new HashMap();

        String ipnValue = this.properties.get("initial-page-number").getString();

        if (ipnValue.equals("auto")) {
            pageNumberType = AUTO;
            this.firstPageNumber = 1;
        } else if (ipnValue.equals("auto-even")) {
            pageNumberType = AUTO_EVEN;
            this.firstPageNumber = 2;
        } else if (ipnValue.equals("auto-odd")) {
            pageNumberType = AUTO_ODD;
            this.firstPageNumber = 1;
        } else {
            pageNumberType = EXPLICIT;
            try {
                int pageStart = Integer.parseInt(ipnValue);
                this.firstPageNumber = (pageStart > 0) ? pageStart  : 1;
            } catch (NumberFormatException nfe) {
                throw new FOPException("The value '" + ipnValue
                                       + "' is not valid for initial-page-number", systemId, line, column);
            }
        }

        masterName = this.properties.get("master-reference").getString();

        // get the 'format' properties
        this.pageNumberGenerator =
            new PageNumberGenerator(this.properties.get("format").getString(),
                                    this.properties.get("grouping-separator").getCharacter(),
                                    this.properties.get("grouping-size").getNumber().intValue(),
                                    this.properties.get("letter-value").getEnum());

        this.forcePageCountType =
            this.properties.get("force-page-count").getEnum();

        // this.properties.get("country");
        // this.properties.get("language");
        // this.properties.get("id");
    }

    public String getName() {
        return "fo:page-sequence";
    }

    public void addFlow(Flow flow) throws FOPException {
        if (this.flow!=null) {
            throw new FOPException("Only a single fo:flow permitted per fo:page-sequence", systemId, line, column);
        }
        if (flowMap.containsKey(flow.getFlowName())) {
            throw new FOPException("flow-names must be unique within an fo:page-sequence", systemId, line, column);
        }
        this.flow = flow;
    }


    public void addStaticContent(StaticContent staticContent) throws FOPException {
        if (this.flow!=null) {
            throw new FOPException("Static content ('"
                                   + staticContent.getFlowName()
                                   + "') is not allowed after fo:flow",
                                   systemId, line, column);
        }
        if (flowMap.containsKey(staticContent.getFlowName())) {
            throw new FOPException("flow-names must be unique within an fo:page-sequence", systemId, line, column);
        }
        String flowName = staticContent.getFlowName();
        if (!this.layoutMasterSet.regionNameExists(flowName)
            && !flowName.equals("xsl-before-float-separator")
            && !flowName.equals("xsl-footnote-separator")) {
            log.error("region-name '"
                      + staticContent.getFlowName()
                      + "' doesn't exist in the layout-master-set.");
        }
        flowMap.put(staticContent.getFlowName(), staticContent);
    }


    /**
     * Runs the formatting of this page sequence into the given area tree
     */
    public void format(AreaTree areaTree) throws FOPException {
        if (flow == null) {
            throw new FOPException("No flow in page-sequence", systemId, line, column);
        }
        PageSequence previousPageSequence=this.root.getPageSequence();
        if( previousPageSequence!=null ) {
            if (previousPageSequence.forcePageCountType == ForcePageCount.AUTO) {
                if (pageNumberType == AUTO_ODD) {
                    if (previousPageSequence.currentPageNumber % 2 == 0) {
                        previousPageSequence.makePage(areaTree,true,null);
                    }
                    currentPageNumber = previousPageSequence.currentPageNumber;
                } else if (pageNumberType == AUTO_EVEN) {
                    if (previousPageSequence.currentPageNumber % 2 == 1) {
                        previousPageSequence.makePage(areaTree,true,null);
                    }
                    currentPageNumber = previousPageSequence.currentPageNumber;
                } else if (pageNumberType == EXPLICIT){
                    if ((previousPageSequence.currentPageNumber % 2)
                        != (firstPageNumber % 2)) {
                        previousPageSequence.makePage(areaTree,true,null);
                    }
                    currentPageNumber = firstPageNumber;
                } else {
                    currentPageNumber = previousPageSequence.currentPageNumber;
                }
            } else {
                currentPageNumber = previousPageSequence.currentPageNumber;
                if (pageNumberType == AUTO_ODD) {
                    if (currentPageNumber % 2 == 0) {
                      currentPageNumber++;
                    }
                } else if (pageNumberType == AUTO_EVEN) {
                    if (currentPageNumber % 2 == 1) {
                      currentPageNumber++;
                    }
                } else if (pageNumberType == EXPLICIT){
                    currentPageNumber = firstPageNumber;
                }
            }
        } else {
            currentPageNumber = firstPageNumber;
        }
        previousPageSequence = null;
        this.root.setPageSequence(this);
        this.currentSimplePageMaster =
          this.layoutMasterSet.getSimplePageMaster(masterName);
        if (this.currentSimplePageMaster==null) {
            this.pageSequenceMaster =
              this.layoutMasterSet.getPageSequenceMaster(masterName);
            if (this.pageSequenceMaster==null) {
                throw new FOPException("master-reference '" + masterName
                                       + "' for fo:page-sequence matches no simple-page-master or page-sequence-master", systemId, line, column);
            }
            pageSequenceMaster.reset();
        } else {
            Region region = currentSimplePageMaster
              .getRegion(RegionBody.REGION_CLASS);
            if (!flow.getFlowName().equals(region.getRegionName())) {
                throw new FOPException("Flow '" + flow.getFlowName()
                                       + "' does not map to the region-body in page-master '"
                                       + currentSimplePageMaster.getMasterName() + "'", systemId, line, column);
            }
        }

        // make pages and layout content
        int status = Status.OK;
        Page currentPage = null;
        do {
            boolean isBlankPage = false;

            // for this calculation we are already on the
            // blank page
            if (status == Status.FORCE_PAGE_BREAK_EVEN) {
                if ((currentPageNumber % 2) == 1) {
                   isBlankPage = true;
                }
            } else if (status == Status.FORCE_PAGE_BREAK_ODD) {
                if ((currentPageNumber % 2) == 0) {
                   isBlankPage = true;
                }
            }
            currentPage = makePage(areaTree, isBlankPage, currentPage);
            status = flow.getStatus();
        } while (Status.isIncomplete(status));

        // handle cases of 'force-page-count' which do not depend
        // on the presence of a following page sequence
        if (this.forcePageCountType == ForcePageCount.EVEN) {
            if (this.pageCount % 2 != 0) {
                makePage(areaTree,true, null);
            }
        } else if (this.forcePageCountType == ForcePageCount.ODD) {
            if (this.pageCount % 2 != 1) {
                makePage(areaTree,true, null);
            }
        } else if (this.forcePageCountType == ForcePageCount.END_ON_EVEN) {
            if (this.currentPageNumber % 2 == 0) {
                makePage(areaTree,true, null);
            }
        } else if (this.forcePageCountType == ForcePageCount.END_ON_ODD) {
            if (this.currentPageNumber % 2 == 1) {
                makePage(areaTree,true, null);
            }
        }
    }

    /**
     * Creates a new page area for the given parameters
     * @param areaTree the area tree the page should be contained in
     * @param isBlankPage true if this page will be empty (e.g. forced even or odd break, or forced page count)
     * @return a Page layout object based on the page master selected from the params
     */
    private Page makePage(AreaTree areaTree,
                          boolean isBlankPage,
                          Page currentPage)
      throws FOPException {
        if (this.pageSequenceMaster!=null) {
            this.currentSimplePageMaster = this.pageSequenceMaster
              .getNextSimplePageMaster(((this.currentPageNumber % 2)==1),
                                       isBlankPage);
            Region region = currentSimplePageMaster
              .getRegion(RegionBody.REGION_CLASS);
            if (!flow.getFlowName().equals(region.getRegionName())) {
                throw new FOPException("Flow '" + flow.getFlowName()
                                       + "' does not map to the region-body in page-master '"
                                       + currentSimplePageMaster.getMasterName() + "'", systemId, line, column);
            }
        }
        Page newPage = this.currentSimplePageMaster.getPageMaster()
          .makePage(areaTree);
        newPage.setNumber(this.currentPageNumber);
        String formattedPageNumber =
          pageNumberGenerator.makeFormattedPageNumber(this.currentPageNumber);
        newPage.setFormattedNumber(formattedPageNumber);
        newPage.setPageSequence(this);
        if (!isBlankPage) {
            log.info("[" + currentPageNumber + "]");
            BodyAreaContainer bodyArea = newPage.getBody();
            bodyArea.setIDReferences(areaTree.getIDReferences());
            if (currentPage != null) {
                ArrayList foots = currentPage.getPendingFootnotes();
                newPage.setPendingFootnotes(foots);
            }
            flow.layout(bodyArea);
        } else {
            log.info("[" + currentPageNumber + "] (blank)");
            if (currentPage != null) {
                ArrayList foots = currentPage.getPendingFootnotes();
                if (foots != null) {
                    BodyAreaContainer bodyArea = newPage.getBody();
                    bodyArea.setIDReferences(areaTree.getIDReferences());
                    newPage.setPendingFootnotes(foots);
                }
            }
        }
        // because of markers, do after fo:flow (likely also
        // justifiable because of spec)
        formatStaticContent(areaTree, newPage);
        areaTree.addPage(newPage);
        this.currentPageNumber++;
        this.pageCount++;
        return newPage;
    }

    /**
     * Formats the static content of the current page
     */
    private void formatStaticContent(AreaTree areaTree, Page page)
      throws FOPException {
        SimplePageMaster simpleMaster = currentSimplePageMaster;

        if (simpleMaster.getRegion(RegionBefore.REGION_CLASS) != null
                && (page.getBefore() != null)) {
            StaticContent staticFlow =
                (StaticContent)flowMap.get(simpleMaster.getRegion(RegionBefore.REGION_CLASS).getRegionName());
            if (staticFlow != null) {
                AreaContainer beforeArea = page.getBefore();
                beforeArea.setIDReferences(areaTree.getIDReferences());
                layoutStaticContent(staticFlow,
                                    simpleMaster.getRegion(RegionBefore.REGION_CLASS),
                                    beforeArea);
            }
        }

        if (simpleMaster.getRegion(RegionAfter.REGION_CLASS) != null
                && (page.getAfter() != null)) {
            StaticContent staticFlow =
                (StaticContent)flowMap.get(simpleMaster.getRegion(RegionAfter.REGION_CLASS).getRegionName());
            if (staticFlow != null) {
                AreaContainer afterArea = page.getAfter();
                afterArea.setIDReferences(areaTree.getIDReferences());
                layoutStaticContent(staticFlow,
                                    simpleMaster.getRegion(RegionAfter.REGION_CLASS),
                                    afterArea);
            }
        }

        if (simpleMaster.getRegion(RegionStart.REGION_CLASS) != null
                && (page.getStart() != null)) {
            StaticContent staticFlow =
                (StaticContent)flowMap.get(simpleMaster.getRegion(RegionStart.REGION_CLASS).getRegionName());
            if (staticFlow != null) {
                AreaContainer startArea = page.getStart();
                startArea.setIDReferences(areaTree.getIDReferences());
                layoutStaticContent(staticFlow,
                                    simpleMaster.getRegion(RegionStart.REGION_CLASS),
                                    startArea);
            }
        }

        if (simpleMaster.getRegion(RegionEnd.REGION_CLASS) != null
                && (page.getEnd() != null)) {
            StaticContent staticFlow =
                (StaticContent)flowMap.get(simpleMaster.getRegion(RegionEnd.REGION_CLASS).getRegionName());
            if (staticFlow != null) {
                AreaContainer endArea = page.getEnd();
                endArea.setIDReferences(areaTree.getIDReferences());
                layoutStaticContent(staticFlow,
                                    simpleMaster.getRegion(RegionEnd.REGION_CLASS),
                                    endArea);
            }
        }

    }

    private void layoutStaticContent(StaticContent flow, Region region,
                                     AreaContainer area) throws FOPException {
        flow.layout(area, region);
//              log.error("The region '" + region.getRegionName()
//                        + "' only supports static-content. Cannot use flow named '"
//                        + flow.getFlowName() + "'");
    }

    public StaticContent getStaticContent(String regionName) {
        return (StaticContent)flowMap.get(regionName);
    }
   
    public int getCurrentPageNumber() {
        return currentPageNumber;
    }

    public int getPageCount() {
        return pageCount;
    }

}
TOP

Related Classes of org.apache.fop.fo.pagination.PageSequence$Maker

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.