1 /*
2  * Licensed to the Apache Software Foundation (ASF) under one or more
3  * contributor license agreements.  See the NOTICE file distributed with
4  * this work for additional information regarding copyright ownership.
5  * The ASF licenses this file to You under the Apache License, Version 2.0
6  * (the "License"); you may not use this file except in compliance with
7  * the License.  You may obtain a copy of the License at
8  *
9  *      http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  */
17 
18 /* $Id: RepeatablePageMasterAlternatives.java 1733431 2016-03-03 09:40:50Z gadams $ */
19 
20 package org.apache.fop.fo.pagination;
21 
22 // Java
23 import java.util.ArrayList;
24 import java.util.List;
25 
26 import org.xml.sax.Locator;
27 
28 import org.apache.fop.apps.FOPException;
29 import org.apache.fop.fo.FONode;
30 import org.apache.fop.fo.FObj;
31 import org.apache.fop.fo.PropertyList;
32 import org.apache.fop.fo.ValidationException;
33 import org.apache.fop.fo.properties.Property;
34 import org.apache.fop.layoutmgr.BlockLevelEventProducer;
35 
36 /**
37  * Class modelling the <a href="http://www.w3.org/TR/xsl/#fo_repeatable-page-master-alternatives">
38  * <code>fo:repeatable-page-master-alternatives</code></a> object.
39  * This contains a list of conditional-page-master-reference
40  * and the page master is found from the reference that
41  * matches the page number and emptyness.
42  */
43 public class RepeatablePageMasterAlternatives extends FObj
44     implements SubSequenceSpecifier {
45     // The value of properties relevant for fo:repeatable-page-master-alternatives.
46     private Property maximumRepeats;
47     // End of property values
48 
49     private static final int INFINITE = -1;
50 
51     private int numberConsumed;
52 
53     private List<ConditionalPageMasterReference> conditionalPageMasterRefs;
54     private boolean hasPagePositionLast;
55     private boolean hasPagePositionOnly;
56 
57     /**
58      * Base constructor
59      *
60      * @param parent {@link FONode} that is the parent of this object
61      */
RepeatablePageMasterAlternatives(FONode parent)62     public RepeatablePageMasterAlternatives(FONode parent) {
63         super(parent);
64     }
65 
66     /** {@inheritDoc} */
bind(PropertyList pList)67     public void bind(PropertyList pList) throws FOPException {
68         maximumRepeats = pList.get(PR_MAXIMUM_REPEATS);
69     }
70 
71     /** {@inheritDoc} */
startOfNode()72     public void startOfNode() throws FOPException {
73         conditionalPageMasterRefs = new java.util.ArrayList<ConditionalPageMasterReference>();
74 
75         assert parent.getName().equals("fo:page-sequence-master"); //Validation by the parent
76         PageSequenceMaster pageSequenceMaster = (PageSequenceMaster)parent;
77         pageSequenceMaster.addSubsequenceSpecifier(this);
78     }
79 
80     /** {@inheritDoc} */
endOfNode()81     public void endOfNode() throws FOPException {
82         if (firstChild == null) {
83            missingChildElementError("(conditional-page-master-reference+)");
84         }
85     }
86 
87     /**
88      * {@inheritDoc}
89      * <br>XSL/FOP: (conditional-page-master-reference+)
90      */
validateChildNode(Locator loc, String nsURI, String localName)91     protected void validateChildNode(Locator loc, String nsURI, String localName)
92                 throws ValidationException {
93         if (FO_URI.equals(nsURI)) {
94             if (!localName.equals("conditional-page-master-reference")) {
95                 invalidChildError(loc, nsURI, localName);
96             }
97         }
98     }
99 
100     /**
101      * Get the value of the <code>maximum-repeats</code> property?
102      * @return the "maximum-repeats" property
103      */
getMaximumRepeats()104     public int getMaximumRepeats() {
105         if (maximumRepeats.getEnum() == EN_NO_LIMIT) {
106             return INFINITE;
107         } else {
108             int mr = maximumRepeats.getNumeric().getValue();
109             if (mr < 0) {
110                 log.debug("negative maximum-repeats: "
111                         + this.maximumRepeats);
112                 mr = 0;
113             }
114             return mr;
115         }
116     }
117 
118     /** {@inheritDoc} */
getNextPageMaster(boolean isOddPage, boolean isFirstPage, boolean isLastPage, boolean isBlankPage)119     public SimplePageMaster getNextPageMaster(boolean isOddPage,
120                                         boolean isFirstPage,
121                                         boolean isLastPage,
122                                         boolean isBlankPage) {
123 
124         if (!isInfinite() && numberConsumed >= getMaximumRepeats()) {
125             return null;
126         }
127 
128         numberConsumed++;
129 
130         for (ConditionalPageMasterReference cpmr : conditionalPageMasterRefs) {
131             if (cpmr.isValid(isOddPage, isFirstPage, isLastPage, isBlankPage)) {
132                 return cpmr.getMaster();
133             }
134         }
135 
136 
137         return null;
138     }
139 
getLastPageMaster(boolean isOddPage, boolean isFirstPage, boolean isBlankPage, BlockLevelEventProducer blockLevelEventProducer)140     public SimplePageMaster getLastPageMaster(boolean isOddPage, boolean isFirstPage, boolean isBlankPage,
141                                               BlockLevelEventProducer blockLevelEventProducer) {
142         for (ConditionalPageMasterReference cpmr : conditionalPageMasterRefs) {
143             if (cpmr.isValid(isOddPage, isFirstPage, true, isBlankPage)) {
144                 return cpmr.getMaster();
145             }
146         }
147         blockLevelEventProducer.lastPageMasterReferenceMissing(this, getLocator());
148         for (ConditionalPageMasterReference cpmr : conditionalPageMasterRefs) {
149             if (cpmr.isValid(isOddPage, isFirstPage, false, isBlankPage)) {
150                 return cpmr.getMaster();
151             }
152         }
153         throw new PageProductionException("Last page master not found: oddpage=" + isOddPage
154                 + " firstpage=" + isFirstPage + " blankpage=" + isBlankPage);
155     }
156 
157     /**
158      * Adds a new conditional page master reference.
159      * @param cpmr the new conditional reference
160      */
addConditionalPageMasterReference(ConditionalPageMasterReference cpmr)161     public void addConditionalPageMasterReference(ConditionalPageMasterReference cpmr) {
162         this.conditionalPageMasterRefs.add(cpmr);
163         if (cpmr.getPagePosition() == EN_LAST) {
164             this.hasPagePositionLast = true;
165         }
166         if (cpmr.getPagePosition() == EN_ONLY) {
167             this.hasPagePositionOnly = true;
168         }
169     }
170 
171     /** {@inheritDoc} */
reset()172     public void reset() {
173         this.numberConsumed = 0;
174     }
175 
176     /** {@inheritDoc} */
goToPrevious()177     public boolean goToPrevious() {
178         if (numberConsumed == 0) {
179             return false;
180         } else {
181             numberConsumed--;
182             return true;
183         }
184     }
185 
186     /** {@inheritDoc} */
hasPagePositionLast()187     public boolean hasPagePositionLast() {
188         return this.hasPagePositionLast;
189     }
190 
191     /** {@inheritDoc} */
hasPagePositionOnly()192     public boolean hasPagePositionOnly() {
193         return this.hasPagePositionOnly;
194     }
195 
196     /** {@inheritDoc} */
getLocalName()197     public String getLocalName() {
198         return "repeatable-page-master-alternatives";
199     }
200 
201     /**
202      * {@inheritDoc}
203      * @return {@link org.apache.fop.fo.Constants#FO_REPEATABLE_PAGE_MASTER_ALTERNATIVES}
204      */
getNameId()205     public int getNameId() {
206         return FO_REPEATABLE_PAGE_MASTER_ALTERNATIVES;
207     }
208 
209 
210 
211     /** {@inheritDoc} */
resolveReferences(LayoutMasterSet layoutMasterSet)212     public void resolveReferences(LayoutMasterSet layoutMasterSet) throws ValidationException {
213         for (ConditionalPageMasterReference conditionalPageMasterReference
214                 : conditionalPageMasterRefs) {
215             conditionalPageMasterReference.resolveReferences(layoutMasterSet);
216         }
217 
218     }
219 
220     /** {@inheritDoc} */
canProcess(String flowName)221     public boolean canProcess(String flowName) {
222 
223         boolean willTerminate = true;
224 
225 
226         //Look for rest spm that cannot terminate
227         ArrayList<ConditionalPageMasterReference> rest
228                 = new ArrayList<ConditionalPageMasterReference>();
229         for (ConditionalPageMasterReference cpmr
230                 : conditionalPageMasterRefs) {
231             if (cpmr.isValid(true, false, false, false)
232                     || cpmr.isValid(false, false, false, false)) {
233                 rest.add(cpmr);
234             }
235         }
236         if (!rest.isEmpty()) {
237             willTerminate = false;
238             for (ConditionalPageMasterReference cpmr : rest) {
239                 willTerminate |= cpmr.getMaster().getRegion(FO_REGION_BODY).getRegionName()
240                         .equals(flowName);
241             }
242         }
243 
244 
245         return willTerminate;
246     }
247 
248     /** {@inheritDoc} */
isInfinite()249     public boolean isInfinite() {
250         return getMaximumRepeats() == INFINITE;
251     }
252 
253     /** {@inheritDoc} */
isReusable()254     public boolean isReusable() {
255         return false;
256     }
257 
258 }
259