Package org.apache.fop.fo.pagination

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

/*-- $Id: PageSequence.java,v 1.27 2001/03/31 20:10:24 kellyc Exp $ --
*
* Copyright (C) 2001 The Apache Software Foundation. All rights reserved.
* For details on use and redistribution please refer to the
* LICENSE file included with these sources."
*/

package org.apache.fop.fo.pagination;

// FOP
import org.apache.fop.fo.*;
import org.apache.fop.messaging.MessageHandler;
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.Area;
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.layout.PageMaster;
import org.apache.fop.apps.FOPException;                  

// Java
import java.util.*;


/**
* This provides pagination of flows onto pages. Much of the logic for paginating
* flows is contained in this class. The main entry point is the format method.
*/
public class PageSequence extends FObj
{
    //
    // Factory methods
    //
    public static class Maker extends FObj.Maker
    {
        public FObj make(FObj parent, PropertyList propertyList)
        throws FOPException {
            return new PageSequence(parent, propertyList);
        }
    }

    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;

    //
    // associations
    //
    /** 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) */
    private Hashtable _flowMap;
       
    /** the "master-name" attribute */
    private String masterName;
 
  // 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 boolean isFlowSet = false;
 
    //
    // state attributes used during layout
    //

    private Page currentPage;

    private int currentPageNumber = 0;

    /** keeps count of page number from previous PageSequence */
    private static int runningPageNumberCounter = 0;

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

    /** used to determine whether to calculate auto, auto-even, auto-odd */
    private boolean thisIsFirstPage;

    /** the current subsequence while formatting a given page sequence */
    private SubSequenceSpecifier currentSubsequence;

    /** the current index in the subsequence list */
    private int currentSubsequenceNumber = -1; // starting case is -1 so that first getNext increments to 0
   
    /** the name of the current page master */
    private String currentPageMasterName;


    protected PageSequence(FObj parent, PropertyList propertyList)
    throws FOPException {
        super(parent, propertyList);
        this.name = "fo:page-sequence";

        if ( parent.getName().equals("fo:root") )
        {
            this.runningPageNumberCounter=0; //else not initialized correctly
            this.root = (Root) parent;
            this.root.addPageSequence(this);
        }
        else
        {
            throw
            new FOPException("page-sequence must be child of root, not "
            + parent.getName());
        }
 
        layoutMasterSet = root.getLayoutMasterSet();

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

  _flowMap = new Hashtable();

        thisIsFirstPage=true; // we are now on the first page of the page sequence
        String ipnValue= this.properties.get("initial-page-number").getString();

        if ( ipnValue.equals("auto") )
        {
            pageNumberType=AUTO;           
        }
        else if ( ipnValue.equals("auto-even") )
        {
            pageNumberType=AUTO_EVEN;           
        }
        else if ( ipnValue.equals("auto-odd") )
        {
            pageNumberType=AUTO_ODD;           
        }
        else
        {
            pageNumberType=EXPLICIT;           
            try
            {
                int pageStart = new Integer(ipnValue).intValue();
                this.currentPageNumber = (pageStart > 0) ? pageStart - 1 : 0;
            }
            catch ( NumberFormatException nfe )
            {
                throw new FOPException("\""+ipnValue+"\" is not a valid value for initial-page-number");
            }
        }

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

    }
   
    public void addFlow(Flow flow)
  throws FOPException
    {
  if (_flowMap.containsKey(flow.getFlowName())) {
      throw new FOPException("flow-names must be unique within an fo:page-sequence");
  }
  if (!this.layoutMasterSet.regionNameExists(flow.getFlowName())) {
      MessageHandler.errorln("WARNING: region-name '"+flow.getFlowName()+"' doesn't exist in the layout-master-set.");
  }
  _flowMap.put(flow.getFlowName(), flow);
  setIsFlowSet(true);
    }
   

    /**
     * Runs the formatting of this page sequence into the given area tree
     */
    public void format(AreaTree areaTree) throws FOPException {
        Status status = new Status(Status.OK);

    this.layoutMasterSet.resetPageMasters();

        do
        {
      // makePage() moved to after the page-number computations,
      // but store the page-number at this point for that method,
      // since we want the 'current' current page-number...
      int firstAvailPageNumber = this.runningPageNumberCounter;
      boolean tempIsFirstPage = false;
        
            if ( thisIsFirstPage )
            {
        tempIsFirstPage = thisIsFirstPage;
                if ( pageNumberType==AUTO )
                {
                    this.currentPageNumber=this.runningPageNumberCounter;
                }
                else if ( pageNumberType==AUTO_ODD )
                {
                    this.currentPageNumber=this.runningPageNumberCounter;
                    if ( this.currentPageNumber % 2== 1 )
                    {
                        this.currentPageNumber++;
                    }
                }
                else if ( pageNumberType==AUTO_EVEN )
                {
                    this.currentPageNumber=this.runningPageNumberCounter;
                    if ( this.currentPageNumber % 2 == 0 )
                    {
                        this.currentPageNumber++;
                    }
                }
                thisIsFirstPage=false;
            }

      this.currentPageNumber++;
 
      // deliberately moved down here so page-number calculations
      // are complete;
       // compute flag for 'blank-or-not-blank'
      boolean isEmptyPage = false;
     
      if ( (status.getCode() == Status.FORCE_PAGE_BREAK_EVEN) &&
     ((currentPageNumber % 2) == 1) ) {
    isEmptyPage = true;
      }
      else if ( (status.getCode() == Status.FORCE_PAGE_BREAK_ODD) &&
          ((currentPageNumber % 2) == 0) ) {
    isEmptyPage = true;
      }
      else {
    isEmptyPage = false;
      }

      currentPage = makePage(areaTree, firstAvailPageNumber,
           tempIsFirstPage, isEmptyPage);
           
      currentPage.setNumber(this.currentPageNumber);
      this.runningPageNumberCounter=this.currentPageNumber;           

            MessageHandler.log(" [" + currentPageNumber);

      formatStaticContent(areaTree);
         
            if ( (status.getCode() == Status.FORCE_PAGE_BREAK_EVEN) &&
            ((currentPageNumber % 2) == 1) )
            {
            }
            else if ( (status.getCode() == Status.FORCE_PAGE_BREAK_ODD) &&
            ((currentPageNumber % 2) == 0) )
            {
            }
            else
            {
                BodyAreaContainer bodyArea = currentPage.getBody();
                bodyArea.setIDReferences(areaTree.getIDReferences());
   
    Flow flow = getCurrentFlow(RegionBody.REGION_CLASS);
   
    if (null == flow) {
         MessageHandler.errorln("No flow found for region-body "
              + "in page-master '" + currentPageMasterName + "'");
        break;
       
    }
    else {
        status = flow.layout(bodyArea);
    }
   
            }
            MessageHandler.log("]");
            areaTree.addPage(currentPage);
  } while ( flowsAreIncomplete() );
   
        MessageHandler.logln("");
    }

    /**
     * Creates a new page area for the given parameters
     * @param areaTree the area tree the page should be contained in
     * @param firstAvailPageNumber the page number for this page
     * @param isFirstPage true when this is the first page in the sequence
     * @param isEmptyPage true if this page will be empty (e.g. forced even or odd break)
     * @return a Page layout object based on the page master selected from the params
     */
    private Page makePage(AreaTree areaTree, int firstAvailPageNumber,
        boolean isFirstPage, boolean isEmptyPage)
  throws FOPException {
        // layout this page sequence
   
        // while there is still stuff in the flow, ask the
        // layoutMasterSet for a new page

  // page number is 0-indexed
        PageMaster pageMaster = getNextPageMaster(masterName, firstAvailPageNumber,
              isFirstPage, isEmptyPage );

    // a legal alternative is to use the last sub-sequence
    // specification which should be handled in getNextSubsequence. That's not done here.
        if ( pageMaster == null )
        {
    throw new FOPException("page masters exhausted. Cannot recover.");
        }
        Page p = pageMaster.makePage(areaTree);
        if(currentPage != null) {
            Vector foots = currentPage.getPendingFootnotes();
            p.setPendingFootnotes(foots);
        }
        return p;
    }

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

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

  if (simpleMaster.getRegion(RegionAfter.REGION_CLASS) != null && (currentPage.getAfter() != null)) {
      Flow staticFlow = (Flow)_flowMap.get(simpleMaster.getRegion(RegionAfter.REGION_CLASS).getRegionName());
      if (staticFlow != null) {
    AreaContainer afterArea = currentPage.getAfter();
    afterArea.setIDReferences(areaTree.getIDReferences());
    layoutStaticContent(staticFlow, simpleMaster.getRegion(RegionAfter.REGION_CLASS),
            afterArea);
      }
  }
 
  if (simpleMaster.getRegion(RegionStart.REGION_CLASS) != null && (currentPage.getStart() != null)) {
      Flow staticFlow = (Flow)_flowMap.get(simpleMaster.getRegion(RegionStart.REGION_CLASS).getRegionName());
      if (staticFlow != null) {
    AreaContainer startArea = currentPage.getStart();
    startArea.setIDReferences(areaTree.getIDReferences());
    layoutStaticContent(staticFlow, simpleMaster.getRegion(RegionStart.REGION_CLASS),
      startArea);
      }
  }
 
  if (simpleMaster.getRegion(RegionEnd.REGION_CLASS) != null && (currentPage.getEnd() != null)) {
      Flow staticFlow = (Flow)_flowMap.get(simpleMaster.getRegion(RegionEnd.REGION_CLASS).getRegionName());
      if (staticFlow != null) {
    AreaContainer endArea = currentPage.getEnd();
    endArea.setIDReferences(areaTree.getIDReferences());
    layoutStaticContent(staticFlow, simpleMaster.getRegion(RegionEnd.REGION_CLASS),
      endArea);
      }
  }
 
    }
   
    private void layoutStaticContent(Flow flow, Region region,
             AreaContainer area)
  throws FOPException
    {
  if (flow instanceof StaticContent) {
      AreaContainer beforeArea = currentPage.getBefore();
      ((StaticContent)flow).layout(area, region);
  }
  else {
      MessageHandler.errorln("WARNING: "+region.getName()+" only supports static-content flows currently. Cannot use flow named '"+flow.getFlowName()+"'");
  }
    }
   
 
   
   

    /**
     * Returns the next SubSequenceSpecifier for the given page sequence master. The result
     * is bassed on the current state of this page sequence.
     */
    // refactored from PageSequenceMaster
    private SubSequenceSpecifier getNextSubsequence(PageSequenceMaster master)
    {
  if (master.getSubSequenceSpecifierCount() > currentSubsequenceNumber + 1) {
     
      currentSubsequence = master.getSubSequenceSpecifier(currentSubsequenceNumber + 1);
      currentSubsequenceNumber++;
      return currentSubsequence;
  }
  else {
      return null;
  }
   
    }
      
    /**
     * Returns the next simple page master for the given sequence master, page number and
     * other state information
     */
    private SimplePageMaster getNextSimplePageMaster(PageSequenceMaster sequenceMaster,
                 int currentPageNumber,
                 boolean thisIsFirstPage,
                 boolean isEmptyPage)
    { 
  String nextPageMaster = getNextPageMasterName(sequenceMaster, currentPageNumber, thisIsFirstPage, isEmptyPage);
  return this.layoutMasterSet.getSimplePageMaster( nextPageMaster );
 
    }

    private String getNextPageMasterName(PageSequenceMaster sequenceMaster,
           int currentPageNumber,
           boolean thisIsFirstPage,
           boolean isEmptyPage)
    {

  if (null == currentSubsequence) {
      currentSubsequence = getNextSubsequence(sequenceMaster);
  }
 
  String nextPageMaster =
      currentSubsequence.getNextPageMaster( currentPageNumber, thisIsFirstPage, isEmptyPage );


  if (null == nextPageMaster ||  isFlowForMasterNameDone(currentPageMasterName)) {
      SubSequenceSpecifier nextSubsequence = getNextSubsequence(sequenceMaster);
      if (nextSubsequence == null) {
    MessageHandler.errorln("\nWARNING: Page subsequences exhausted. Using previous subsequence.");
    thisIsFirstPage = true; // this becomes the first page in the new (old really) page master
    currentSubsequence.reset();
   
    // we leave currentSubsequence alone
      }
      else {
    currentSubsequence = nextSubsequence;
      }
     
      nextPageMaster = currentSubsequence.getNextPageMaster( currentPageNumber,
                   thisIsFirstPage,
                   isEmptyPage);
  }
  currentPageMasterName = nextPageMaster;
 
  return nextPageMaster;
 
    }

    private SimplePageMaster getCurrentSimplePageMaster()
    {
  return this.layoutMasterSet.getSimplePageMaster( currentPageMasterName );
    }

    private String getCurrentPageMasterName()
    {
  return currentPageMasterName;
    }

    // refactored from LayoutMasterSet
    private PageMaster getNextPageMaster(String pageSequenceName,
           int currentPageNumber,
           boolean thisIsFirstPage,
           boolean isEmptyPage )
  throws FOPException
    {
  PageMaster pageMaster = null;

  // see if there is a page master sequence for this master name   
  PageSequenceMaster sequenceMaster =
      this.layoutMasterSet.getPageSequenceMaster( pageSequenceName );

  if (sequenceMaster != null) {
      pageMaster = getNextSimplePageMaster(sequenceMaster,
             currentPageNumber,
             thisIsFirstPage,
             isEmptyPage).getPageMaster();

  } else { // otherwise see if there's a simple master by the given name
      SimplePageMaster simpleMaster =
    this.layoutMasterSet.getSimplePageMaster( pageSequenceName );
      if (simpleMaster == null) {
    throw new FOPException( "'master-name' for 'fo:page-sequence'" +
          "matches no 'simple-page-master' or 'page-sequence-master'" );
      }
      currentPageMasterName = pageSequenceName;
     
      pageMaster = simpleMaster.getNextPageMaster();
  }
  return pageMaster;
    }


    /**
     * Returns true when there is more flow elements left to lay out.
     */
    private boolean flowsAreIncomplete()
    {
  boolean isIncomplete = false;

  for (Enumeration e = _flowMap.elements(); e.hasMoreElements(); ) {
      Flow flow = (Flow)e.nextElement();
      if (flow instanceof StaticContent) {
    continue;
      }
     
      Status status = flow.getStatus();
      isIncomplete |= status.isIncomplete();
  }
  return isIncomplete;
    }

    /**
     * Returns the flow that maps to the given region class for the current
     * page master.
     */
    private Flow getCurrentFlow(String regionClass)
    {
  Region region = getCurrentSimplePageMaster().getRegion(regionClass);
        if (region != null) {
      Flow flow = (Flow)_flowMap.get(region.getRegionName());
      return flow;
     
  }
  else {
     
  System.out.println("flow is null. regionClass = '"+regionClass+"' currentSPM = "+getCurrentSimplePageMaster());
 
  return null;
  }
 
    }

    private boolean isFlowForMasterNameDone( String masterName )
    {   
  // parameter is master-name of PMR; we need to locate PM
  // referenced by this, and determine whether flow(s) are OK
  if (masterName != null) {
   
      SimplePageMaster spm = this.layoutMasterSet.getSimplePageMaster( masterName );
      Region region = spm.getRegion(RegionBody.REGION_CLASS);
     
     
      Flow flow = (Flow)_flowMap.get( region.getRegionName() );
      if ((null == flow) || flow.getStatus().isIncomplete())
    return false;
      else
    return true;
  }
  return false;
    }
 
  public boolean isFlowSet()
  {
    return isFlowSet;
  }
 
  public void setIsFlowSet(boolean isFlowSet)
  {
    this.isFlowSet = isFlowSet;
  }
}
TOP

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

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.