001: /**
002: * ===========================================
003: * JFreeReport : a free Java reporting library
004: * ===========================================
005: *
006: * Project Info: http://reporting.pentaho.org/
007: *
008: * (C) Copyright 2001-2007, by Object Refinery Ltd, Pentaho Corporation and Contributors.
009: *
010: * This library is free software; you can redistribute it and/or modify it under the terms
011: * of the GNU Lesser General Public License as published by the Free Software Foundation;
012: * either version 2.1 of the License, or (at your option) any later version.
013: *
014: * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
015: * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
016: * See the GNU Lesser General Public License for more details.
017: *
018: * You should have received a copy of the GNU Lesser General Public License along with this
019: * library; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
020: * Boston, MA 02111-1307, USA.
021: *
022: * [Java is a trademark or registered trademark of Sun Microsystems, Inc.
023: * in the United States and other countries.]
024: *
025: * ------------
026: * PageFunction.java
027: * ------------
028: * (C) Copyright 2001-2007, by Object Refinery Ltd, Pentaho Corporation and Contributors.
029: */package org.jfree.report.function;
030:
031: import org.jfree.report.event.PageEventListener;
032: import org.jfree.report.event.ReportEvent;
033: import org.jfree.report.states.LayoutProcess;
034: import org.jfree.report.util.IntegerCache;
035:
036: /**
037: * A report function that counts pages. This method is only useable when a report processor is used, which generated
038: * PageEvents. The PageableReportProcessor is one of them.
039: * <p/>
040: * As with all page dependent functions: The function will only be active, when the page events get fired, this usually
041: * only happens during the last pagination run and the printing. The function level will be negative when this happens.
042: * <p/>
043: *
044: * @author Thomas Morgner
045: */
046: public class PageFunction extends AbstractFunction implements
047: PageEventListener {
048: /**
049: * The current page.
050: */
051: private transient int page;
052:
053: /**
054: * The name of the group on which to reset the count. This can be set to null to compute the page count for the whole
055: * report.
056: */
057: private String group;
058: /**
059: * The initial page number on which the counting should start.
060: */
061: private int startPage;
062: /**
063: * The increment by which the page number should be increases each time.
064: */
065: private int pageIncrement;
066: /**
067: * The dependency level of the function.
068: */
069: private int dependencyLevel;
070: /**
071: * An internal state-management flag.
072: */
073: private boolean ignoreNextPageStart;
074: /**
075: * An internal state-management flag.
076: */
077: private boolean ignoreNextGroupStart;
078:
079: /**
080: * Constructs an unnamed function. <P> This constructor is intended for use by the SAX handler class only.
081: */
082: public PageFunction() {
083: this .startPage = 1;
084: this .pageIncrement = 1;
085: this .dependencyLevel = LayoutProcess.LEVEL_PAGINATE;
086: }
087:
088: /**
089: * Constructs a named function.
090: *
091: * @param name the function name.
092: */
093: public PageFunction(final String name) {
094: this ();
095: setName(name);
096: }
097:
098: /**
099: * Checks, whether this expression is a deep-traversing expression. Deep-traversing expressions receive events from
100: * all sub-reports. This returns true, as this function has to receive page-events even if a sub-report is currently
101: * being processed.
102: *
103: * @return true.
104: */
105: public boolean isDeepTraversing() {
106: return true;
107: }
108:
109: /**
110: * Returns the defined dependency level. For page functions, this level can be as low as the pagination level.
111: *
112: * @return the dependency level.
113: */
114: public int getDependencyLevel() {
115: return dependencyLevel;
116: }
117:
118: /**
119: * Defines the defined dependency level. For page functions, this level can be as low as the pagination level.
120: *
121: * @param dependencyLevel the dependency level.
122: */
123: public void setDependencyLevel(final int dependencyLevel) {
124: if (dependencyLevel < LayoutProcess.LEVEL_PAGINATE) {
125: throw new IllegalArgumentException(
126: "PageFunction.setDependencyLevel(...) : A dependency level lower than paginate is not allowed.");
127: }
128: this .dependencyLevel = dependencyLevel;
129: }
130:
131: /**
132: * Returns the page increment.
133: *
134: * @return the page increment.
135: */
136: public int getPageIncrement() {
137: return pageIncrement;
138: }
139:
140: /**
141: * Defines the page increment.
142: *
143: * @param pageIncrement the page increment.
144: */
145: public void setPageIncrement(final int pageIncrement) {
146: this .pageIncrement = pageIncrement;
147: }
148:
149: /**
150: * Returns the group name.
151: *
152: * @return the group name.
153: */
154: public String getGroup() {
155: return group;
156: }
157:
158: /**
159: * Sets the name of the group that the function acts upon.
160: *
161: * @param group the group name.
162: */
163: public void setGroup(final String group) {
164: this .group = group;
165: }
166:
167: /**
168: * Returns the page number where the counting starts.
169: *
170: * @return the page number of the first page.
171: */
172: public int getStartPage() {
173: return this .startPage;
174: }
175:
176: /**
177: * Defines the page number where the counting starts.
178: *
179: * @param startPage the page number of the first page.
180: */
181: public void setStartPage(final int startPage) {
182: this .startPage = startPage;
183: }
184:
185: /**
186: * Returns the current page.
187: *
188: * @return the current page.
189: */
190: protected int getPage() {
191: return page;
192: }
193:
194: /**
195: * Sets the current page.
196: *
197: * @param page the page.
198: */
199: protected void setPage(final int page) {
200: this .page = page;
201: }
202:
203: /**
204: * Receives notification that the report has started.
205: *
206: * @param event the event.
207: */
208: public void reportInitialized(final ReportEvent event) {
209: if (event.isDeepTraversing()) {
210: return;
211: }
212: // Next event in list will be the first page-started event. Will set the page number again..
213: this .setPage(getStartPage());
214: ignoreNextGroupStart = true;
215: ignoreNextPageStart = false;
216: // waitForNextGroupStart = false;
217: }
218:
219: /**
220: * Receives notification that a group has started.
221: *
222: * @param event the event.
223: */
224: public void groupStarted(final ReportEvent event) {
225: // The defined group is only valid for the master-report.
226: if (event.isDeepTraversing()) {
227: return;
228: }
229: // if we have no defined group, no need to do anything else.
230: if (getGroup() == null) {
231: return;
232: }
233:
234: if (FunctionUtilities.isDefinedGroup(getGroup(), event)) {
235: // waitForNextGroupStart = false;
236:
237: if (ignoreNextGroupStart) {
238: // The report-header had been printed recently. Add it to the group's list of pages
239: ignoreNextGroupStart = false;
240: return;
241: }
242:
243: ignoreNextPageStart = true;
244: // Unconditionally reset the page counter. For groups not starting with a new page, the
245: // behaviour of the function is undefined.
246: this .setPage(getStartPage());
247: }
248: }
249:
250: /**
251: * Receives notification from the report engine that a new page is starting. Grabs the page number from the report
252: * state and stores it.
253: *
254: * @param event the event.
255: */
256: public void pageStarted(final ReportEvent event) {
257: if ((event.getType() & ReportEvent.REPORT_INITIALIZED) == ReportEvent.REPORT_INITIALIZED) {
258: this .setPage(getStartPage());
259: return;
260: }
261: if (ignoreNextPageStart) {
262: ignoreNextPageStart = false;
263: return;
264: }
265: // if (waitForNextGroupStart &&
266: // (event.getType() & ReportEvent.GROUP_STARTED) == ReportEvent.GROUP_STARTED)
267: // {
268: // this.setPage(getStartPage());
269: // this.waitForNextGroupStart = false;
270: // return;
271: // }
272:
273: setPage(getPage() + getPageIncrement());
274: }
275:
276: /**
277: * Returns, whether the next page-start event will be ignored. This is an internal state flag to keep the
278: * computation in sync with the events.
279: *
280: * @return the flag.
281: */
282: protected boolean isIgnoreNextPageStart() {
283: return ignoreNextPageStart;
284: }
285:
286: /**
287: * Receives notification that a page is completed.
288: *
289: * @param event The event.
290: */
291: public void pageFinished(final ReportEvent event) {
292: // ignored ...
293: }
294:
295: //
296: // public void groupFinished(final ReportEvent event)
297: // {
298: // // The defined group is only valid for the master-report.
299: // if (event.isDeepTraversing())
300: // {
301: // return;
302: // }
303: // // if we have no defined group, no need to do anything else.
304: // if (getGroup() == null)
305: // {
306: // return;
307: // }
308: //
309: //// if (FunctionUtilities.isDefinedGroup(getGroup(), event))
310: //// {
311: //// waitForNextGroupStart = true;
312: //// }
313: // }
314:
315: /**
316: * Returns the page number (function value).
317: *
318: * @return the page number.
319: */
320: public Object getValue() {
321: return IntegerCache.getInteger(getPage());
322: }
323:
324: /**
325: * A internal flag that defines wether the next group start should be ignored. We have to ignore the first
326: * group start of each report so that the report-header becomes part of the first group's page sequence.
327: *
328: * @return the internal flag.
329: */
330: protected boolean isIgnoreNextGroupStart() {
331: return ignoreNextGroupStart;
332: }
333:
334: /**
335: * A obsolete getter. Ignore it please, it has no effect.
336: *
337: * @return true, if you care to know.
338: * @deprecated No longer used.
339: */
340: protected boolean isIgnorePageCancelEvents() {
341: return true;
342: }
343:
344: /**
345: * A obsolete setter. Ignore it please, it has no effect.
346: *
347: * @param ignorePageCancelEvents ignored.
348: * @deprecated No longer used.
349: */
350: public void setIgnorePageCancelEvents(
351: final boolean ignorePageCancelEvents) {
352: }
353: }
|