KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > fop > fo > pagination > PageSequence


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

51 package org.apache.fop.fo.pagination;
52
53 // FOP
54
import org.apache.fop.fo.*;
55 import org.apache.fop.fo.properties.*;
56 import org.apache.fop.fo.flow.Flow;
57 import org.apache.fop.fo.flow.StaticContent;
58 import org.apache.fop.layout.AreaContainer;
59 import org.apache.fop.layout.BodyAreaContainer;
60 import org.apache.fop.layout.AreaTree;
61 import org.apache.fop.layout.Page;
62 import org.apache.fop.apps.FOPException;
63
64 // Java
65
import java.util.HashMap JavaDoc;
66 import java.util.ArrayList JavaDoc;
67
68 /**
69  * Class modeling the fo:page-sequence object. Provides pagination of flows.
70  * Much of the logic for paginating flows is contained in this class. The main
71  * entry point is the format method.
72  *
73  * @see <a HREF="@XSLFO-STD@#fo_page-sequence" target="_xslfostd">@XSLFO-STDID@
74  * &para;6.4.5</a>
75  */

76 public class PageSequence extends FObj {
77     //
78
// Factory methods
79
//
80
public static class Maker extends FObj.Maker {
81         public FObj make(FObj parent, PropertyList propertyList,
82                         String JavaDoc systemId, int line, int column)
83             throws FOPException {
84             return new PageSequence(parent, propertyList,
85                                     systemId, line, column);
86         }
87
88     }
89
90     public static FObj.Maker maker() {
91         return new PageSequence.Maker();
92     }
93
94     //
95
// intial-page-number types
96
//
97
private static final int EXPLICIT = 0;
98     private static final int AUTO = 1;
99     private static final int AUTO_EVEN = 2;
100     private static final int AUTO_ODD = 3;
101
102     /**
103      * The parent root object
104      */

105     private Root root;
106
107     /**
108      * the set of layout masters (provided by the root object)
109      */

110     private LayoutMasterSet layoutMasterSet;
111
112     // There doesn't seem to be anything in the spec requiring flows
113
// to be in the order given, only that they map to the regions
114
// defined in the page sequence, so all we need is this one hashtable
115
// the set of flows includes StaticContent flows also
116

117     /**
118      * Map of flows to their flow name (flow-name, Flow)
119      * Does only contain flows for static content!
120      */

121     private HashMap JavaDoc flowMap;
122
123     // according to communication from Paul Grosso (XSL-List,
124
// 001228, Number 406), confusion in spec section 6.4.5 about
125
// multiplicity of fo:flow in XSL 1.0 is cleared up - one (1)
126
// fo:flow per fo:page-sequence only.
127
private Flow flow = null;
128
129     /**
130      * the "master-reference" attribute,
131      * which specifies the name of the page-sequence-master or
132      * page-master to be used to create pages in the sequence
133      */

134     private String JavaDoc masterName;
135
136     // page number and related formatting variables
137
private int firstPageNumber = 0;
138     private PageNumberGenerator pageNumberGenerator;
139
140
141     private int pageCount = 0;
142     private int currentPageNumber;
143
144     /**
145      * specifies page numbering type (auto|auto-even|auto-odd|explicit)
146      */

147     private int pageNumberType;
148
149     private int forcePageCountType;
150
151     /**
152      * the current page master
153      */

154     private SimplePageMaster currentSimplePageMaster;
155     private PageSequenceMaster pageSequenceMaster;
156
157     protected PageSequence(FObj parent, PropertyList propertyList,
158                         String JavaDoc systemId, int line, int column)
159         throws FOPException {
160         super(parent, propertyList, systemId, line, column);
161
162         if (parent.getName().equals("fo:root")) {
163             this.root = (Root)parent;
164         }
165         else {
166             throw new FOPException("page-sequence must be child of root, not "
167                                    + parent.getName(), systemId, line, column);
168         }
169
170         layoutMasterSet = root.getLayoutMasterSet();
171
172         // best time to run some checks on LayoutMasterSet
173
layoutMasterSet.checkRegionNames();
174
175         flowMap = new HashMap JavaDoc();
176
177         String JavaDoc ipnValue = this.properties.get("initial-page-number").getString();
178
179         if (ipnValue.equals("auto")) {
180             pageNumberType = AUTO;
181             this.firstPageNumber = 1;
182         } else if (ipnValue.equals("auto-even")) {
183             pageNumberType = AUTO_EVEN;
184             this.firstPageNumber = 2;
185         } else if (ipnValue.equals("auto-odd")) {
186             pageNumberType = AUTO_ODD;
187             this.firstPageNumber = 1;
188         } else {
189             pageNumberType = EXPLICIT;
190             try {
191                 int pageStart = Integer.parseInt(ipnValue);
192                 this.firstPageNumber = (pageStart > 0) ? pageStart : 1;
193             } catch (NumberFormatException JavaDoc nfe) {
194                 throw new FOPException("The value '" + ipnValue
195                                        + "' is not valid for initial-page-number", systemId, line, column);
196             }
197         }
198
199         masterName = this.properties.get("master-reference").getString();
200
201         // get the 'format' properties
202
this.pageNumberGenerator =
203             new PageNumberGenerator(this.properties.get("format").getString(),
204                                     this.properties.get("grouping-separator").getCharacter(),
205                                     this.properties.get("grouping-size").getNumber().intValue(),
206                                     this.properties.get("letter-value").getEnum());
207
208         this.forcePageCountType =
209             this.properties.get("force-page-count").getEnum();
210
211         // this.properties.get("country");
212
// this.properties.get("language");
213
// this.properties.get("id");
214
}
215
216     public String JavaDoc getName() {
217         return "fo:page-sequence";
218     }
219
220     public void addFlow(Flow flow) throws FOPException {
221         if (this.flow!=null) {
222             throw new FOPException("Only a single fo:flow permitted per fo:page-sequence", systemId, line, column);
223         }
224         if (flowMap.containsKey(flow.getFlowName())) {
225             throw new FOPException("flow-names must be unique within an fo:page-sequence", systemId, line, column);
226         }
227         this.flow = flow;
228     }
229
230
231     public void addStaticContent(StaticContent staticContent) throws FOPException {
232         if (this.flow!=null) {
233             throw new FOPException("Static content ('"
234                                    + staticContent.getFlowName()
235                                    + "') is not allowed after fo:flow",
236                                    systemId, line, column);
237         }
238         if (flowMap.containsKey(staticContent.getFlowName())) {
239             throw new FOPException("flow-names must be unique within an fo:page-sequence", systemId, line, column);
240         }
241         String JavaDoc flowName = staticContent.getFlowName();
242         if (!this.layoutMasterSet.regionNameExists(flowName)
243             && !flowName.equals("xsl-before-float-separator")
244             && !flowName.equals("xsl-footnote-separator")) {
245             log.error("region-name '"
246                       + staticContent.getFlowName()
247                       + "' doesn't exist in the layout-master-set.");
248         }
249         flowMap.put(staticContent.getFlowName(), staticContent);
250     }
251
252
253     /**
254      * Runs the formatting of this page sequence into the given area tree
255      */

256     public void format(AreaTree areaTree) throws FOPException {
257         if (flow == null) {
258             throw new FOPException("No flow in page-sequence", systemId, line, column);
259         }
260         PageSequence previousPageSequence=this.root.getPageSequence();
261         if( previousPageSequence!=null ) {
262             if (previousPageSequence.forcePageCountType == ForcePageCount.AUTO) {
263                 if (pageNumberType == AUTO_ODD) {
264                     if (previousPageSequence.currentPageNumber % 2 == 0) {
265                         previousPageSequence.makePage(areaTree,true,null);
266                     }
267                     currentPageNumber = previousPageSequence.currentPageNumber;
268                 } else if (pageNumberType == AUTO_EVEN) {
269                     if (previousPageSequence.currentPageNumber % 2 == 1) {
270                         previousPageSequence.makePage(areaTree,true,null);
271                     }
272                     currentPageNumber = previousPageSequence.currentPageNumber;
273                 } else if (pageNumberType == EXPLICIT){
274                     if ((previousPageSequence.currentPageNumber % 2)
275                         != (firstPageNumber % 2)) {
276                         previousPageSequence.makePage(areaTree,true,null);
277                     }
278                     currentPageNumber = firstPageNumber;
279                 } else {
280                     currentPageNumber = previousPageSequence.currentPageNumber;
281                 }
282             } else {
283                 currentPageNumber = previousPageSequence.currentPageNumber;
284                 if (pageNumberType == AUTO_ODD) {
285                     if (currentPageNumber % 2 == 0) {
286                       currentPageNumber++;
287                     }
288                 } else if (pageNumberType == AUTO_EVEN) {
289                     if (currentPageNumber % 2 == 1) {
290                       currentPageNumber++;
291                     }
292                 } else if (pageNumberType == EXPLICIT){
293                     currentPageNumber = firstPageNumber;
294                 }
295             }
296         } else {
297             currentPageNumber = firstPageNumber;
298         }
299         previousPageSequence = null;
300         this.root.setPageSequence(this);
301         this.currentSimplePageMaster =
302           this.layoutMasterSet.getSimplePageMaster(masterName);
303         if (this.currentSimplePageMaster==null) {
304             this.pageSequenceMaster =
305               this.layoutMasterSet.getPageSequenceMaster(masterName);
306             if (this.pageSequenceMaster==null) {
307                 throw new FOPException("master-reference '" + masterName
308                                        + "' for fo:page-sequence matches no simple-page-master or page-sequence-master", systemId, line, column);
309             }
310             pageSequenceMaster.reset();
311         } else {
312             Region region = currentSimplePageMaster
313               .getRegion(RegionBody.REGION_CLASS);
314             if (!flow.getFlowName().equals(region.getRegionName())) {
315                 throw new FOPException("Flow '" + flow.getFlowName()
316                                        + "' does not map to the region-body in page-master '"
317                                        + currentSimplePageMaster.getMasterName() + "'", systemId, line, column);
318             }
319         }
320
321         // make pages and layout content
322
int status = Status.OK;
323         Page currentPage = null;
324         do {
325             boolean isBlankPage = false;
326
327             // for this calculation we are already on the
328
// blank page
329
if (status == Status.FORCE_PAGE_BREAK_EVEN) {
330                 if ((currentPageNumber % 2) == 1) {
331                    isBlankPage = true;
332                 }
333             } else if (status == Status.FORCE_PAGE_BREAK_ODD) {
334                 if ((currentPageNumber % 2) == 0) {
335                    isBlankPage = true;
336                 }
337             }
338             currentPage = makePage(areaTree, isBlankPage, currentPage);
339             status = flow.getStatus();
340         } while (Status.isIncomplete(status));
341
342         // handle cases of 'force-page-count' which do not depend
343
// on the presence of a following page sequence
344
if (this.forcePageCountType == ForcePageCount.EVEN) {
345             if (this.pageCount % 2 != 0) {
346                 makePage(areaTree,true, null);
347             }
348         } else if (this.forcePageCountType == ForcePageCount.ODD) {
349             if (this.pageCount % 2 != 1) {
350                 makePage(areaTree,true, null);
351             }
352         } else if (this.forcePageCountType == ForcePageCount.END_ON_EVEN) {
353             if (this.currentPageNumber % 2 == 0) {
354                 makePage(areaTree,true, null);
355             }
356         } else if (this.forcePageCountType == ForcePageCount.END_ON_ODD) {
357             if (this.currentPageNumber % 2 == 1) {
358                 makePage(areaTree,true, null);
359             }
360         }
361     }
362
363     /**
364      * Creates a new page area for the given parameters
365      * @param areaTree the area tree the page should be contained in
366      * @param isBlankPage true if this page will be empty (e.g. forced even or odd break, or forced page count)
367      * @return a Page layout object based on the page master selected from the params
368      */

369     private Page makePage(AreaTree areaTree,
370                           boolean isBlankPage,
371                           Page currentPage)
372       throws FOPException {
373         if (this.pageSequenceMaster!=null) {
374             this.currentSimplePageMaster = this.pageSequenceMaster
375               .getNextSimplePageMaster(((this.currentPageNumber % 2)==1),
376                                        isBlankPage);
377             Region region = currentSimplePageMaster
378               .getRegion(RegionBody.REGION_CLASS);
379             if (!flow.getFlowName().equals(region.getRegionName())) {
380                 throw new FOPException("Flow '" + flow.getFlowName()
381                                        + "' does not map to the region-body in page-master '"
382                                        + currentSimplePageMaster.getMasterName() + "'", systemId, line, column);
383             }
384         }
385         Page newPage = this.currentSimplePageMaster.getPageMaster()
386           .makePage(areaTree);
387         newPage.setNumber(this.currentPageNumber);
388         String JavaDoc formattedPageNumber =
389           pageNumberGenerator.makeFormattedPageNumber(this.currentPageNumber);
390         newPage.setFormattedNumber(formattedPageNumber);
391         newPage.setPageSequence(this);
392         if (!isBlankPage) {
393             log.info("[" + currentPageNumber + "]");
394             BodyAreaContainer bodyArea = newPage.getBody();
395             bodyArea.setIDReferences(areaTree.getIDReferences());
396             if (currentPage != null) {
397                 ArrayList JavaDoc foots = currentPage.getPendingFootnotes();
398                 newPage.setPendingFootnotes(foots);
399             }
400             flow.layout(bodyArea);
401         } else {
402             log.info("[" + currentPageNumber + "] (blank)");
403             if (currentPage != null) {
404                 ArrayList JavaDoc foots = currentPage.getPendingFootnotes();
405                 if (foots != null) {
406                     BodyAreaContainer bodyArea = newPage.getBody();
407                     bodyArea.setIDReferences(areaTree.getIDReferences());
408                     newPage.setPendingFootnotes(foots);
409                 }
410             }
411         }
412         // because of markers, do after fo:flow (likely also
413
// justifiable because of spec)
414
formatStaticContent(areaTree, newPage);
415         areaTree.addPage(newPage);
416         this.currentPageNumber++;
417         this.pageCount++;
418         return newPage;
419     }
420
421     /**
422      * Formats the static content of the current page
423      */

424     private void formatStaticContent(AreaTree areaTree, Page page)
425       throws FOPException {
426         SimplePageMaster simpleMaster = currentSimplePageMaster;
427
428         if (simpleMaster.getRegion(RegionBefore.REGION_CLASS) != null
429                 && (page.getBefore() != null)) {
430             StaticContent staticFlow =
431                 (StaticContent)flowMap.get(simpleMaster.getRegion(RegionBefore.REGION_CLASS).getRegionName());
432             if (staticFlow != null) {
433                 AreaContainer beforeArea = page.getBefore();
434                 beforeArea.setIDReferences(areaTree.getIDReferences());
435                 layoutStaticContent(staticFlow,
436                                     simpleMaster.getRegion(RegionBefore.REGION_CLASS),
437                                     beforeArea);
438             }
439         }
440
441         if (simpleMaster.getRegion(RegionAfter.REGION_CLASS) != null
442                 && (page.getAfter() != null)) {
443             StaticContent staticFlow =
444                 (StaticContent)flowMap.get(simpleMaster.getRegion(RegionAfter.REGION_CLASS).getRegionName());
445             if (staticFlow != null) {
446                 AreaContainer afterArea = page.getAfter();
447                 afterArea.setIDReferences(areaTree.getIDReferences());
448                 layoutStaticContent(staticFlow,
449                                     simpleMaster.getRegion(RegionAfter.REGION_CLASS),
450                                     afterArea);
451             }
452         }
453
454         if (simpleMaster.getRegion(RegionStart.REGION_CLASS) != null
455                 && (page.getStart() != null)) {
456             StaticContent staticFlow =
457                 (StaticContent)flowMap.get(simpleMaster.getRegion(RegionStart.REGION_CLASS).getRegionName());
458             if (staticFlow != null) {
459                 AreaContainer startArea = page.getStart();
460                 startArea.setIDReferences(areaTree.getIDReferences());
461                 layoutStaticContent(staticFlow,
462                                     simpleMaster.getRegion(RegionStart.REGION_CLASS),
463                                     startArea);
464             }
465         }
466
467         if (simpleMaster.getRegion(RegionEnd.REGION_CLASS) != null
468                 && (page.getEnd() != null)) {
469             StaticContent staticFlow =
470                 (StaticContent)flowMap.get(simpleMaster.getRegion(RegionEnd.REGION_CLASS).getRegionName());
471             if (staticFlow != null) {
472                 AreaContainer endArea = page.getEnd();
473                 endArea.setIDReferences(areaTree.getIDReferences());
474                 layoutStaticContent(staticFlow,
475                                     simpleMaster.getRegion(RegionEnd.REGION_CLASS),
476                                     endArea);
477             }
478         }
479
480     }
481
482     private void layoutStaticContent(StaticContent flow, Region region,
483                                      AreaContainer area) throws FOPException {
484         flow.layout(area, region);
485 // log.error("The region '" + region.getRegionName()
486
// + "' only supports static-content. Cannot use flow named '"
487
// + flow.getFlowName() + "'");
488
}
489
490     public StaticContent getStaticContent(String JavaDoc regionName) {
491         return (StaticContent)flowMap.get(regionName);
492     }
493     
494     public int getCurrentPageNumber() {
495         return currentPageNumber;
496     }
497
498     public int getPageCount() {
499         return pageCount;
500     }
501
502 }
503
Popular Tags