/*
* This program is free software; you can redistribute it and/or modify it under the
* terms of the GNU Lesser General Public License, version 2.1 as published by the Free Software
* Foundation.
*
* You should have received a copy of the GNU Lesser General Public License along with this
* program; if not, you can obtain a copy at http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html
* or from the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU Lesser General Public License for more details.
*
* Copyright (c) 2001 - 2013 Object Refinery Ltd, Pentaho Corporation and Contributors.. All rights reserved.
*/
package org.pentaho.reporting.engine.classic.core.function;
import org.pentaho.reporting.engine.classic.core.event.PageEventListener;
import org.pentaho.reporting.engine.classic.core.event.ReportEvent;
import org.pentaho.reporting.engine.classic.core.states.LayoutProcess;
import org.pentaho.reporting.engine.classic.core.util.IntegerCache;
/**
* A report function that counts pages. This method is only useable when a report processor is used, which generated
* PageEvents. The PageableReportProcessor is one of them.
* <p/>
* As with all page dependent functions: The function will only be active, when the page events get fired, this usually
* only happens during the last pagination run and the printing. The function level will be negative when this happens.
* <p/>
*
* @author Thomas Morgner
*/
public class PageFunction extends AbstractFunction implements PageEventListener {
/**
* The current page.
*/
private transient int page;
/**
* 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
* report.
*/
private String group;
/**
* The initial page number on which the counting should start.
*/
private int startPage;
/**
* The increment by which the page number should be increases each time.
*/
private int pageIncrement;
/**
* The dependency level of the function.
*/
private int dependencyLevel;
/**
* An internal state-management flag.
*/
private boolean ignoreNextPageStart;
/**
* An internal state-management flag.
*/
private boolean ignoreNextGroupStart;
/**
* Constructs an unnamed function.
* <P>
* This constructor is intended for use by the SAX handler class only.
*/
public PageFunction() {
this.startPage = 1;
this.pageIncrement = 1;
this.dependencyLevel = LayoutProcess.LEVEL_PAGINATE;
}
/**
* Constructs a named function.
*
* @param name
* the function name.
*/
public PageFunction( final String name ) {
this();
setName( name );
}
/**
* Checks whether this expression is a deep-traversing expression. Deep-traversing expressions receive events from all
* sub-reports. This returns true, as this function has to receive page-events even if a sub-report is currently being
* processed.
*
* @return true.
*/
public boolean isDeepTraversing() {
return true;
}
/**
* Returns the defined dependency level. For page functions, this level can be as low as the pagination level.
*
* @return the dependency level.
*/
public int getDependencyLevel() {
return dependencyLevel;
}
/**
* Defines the defined dependency level. For page functions, this level can be as low as the pagination level.
*
* @param dependencyLevel
* the dependency level.
*/
public void setDependencyLevel( final int dependencyLevel ) {
if ( dependencyLevel < LayoutProcess.LEVEL_PAGINATE ) {
throw new IllegalArgumentException(
"PageFunction.setDependencyLevel(...) : A dependency level lower than paginate is not allowed." );
}
this.dependencyLevel = dependencyLevel;
}
/**
* Returns the page increment.
*
* @return the page increment.
*/
public int getPageIncrement() {
return pageIncrement;
}
/**
* Defines the page increment.
*
* @param pageIncrement
* the page increment.
*/
public void setPageIncrement( final int pageIncrement ) {
this.pageIncrement = pageIncrement;
}
/**
* Returns the group name.
*
* @return the group name.
*/
public String getGroup() {
return group;
}
/**
* Sets the name of the group that the function acts upon.
*
* @param group
* the group name.
*/
public void setGroup( final String group ) {
this.group = group;
}
/**
* Returns the page number where the counting starts.
*
* @return the page number of the first page.
*/
public int getStartPage() {
return this.startPage;
}
/**
* Defines the page number where the counting starts.
*
* @param startPage
* the page number of the first page.
*/
public void setStartPage( final int startPage ) {
this.startPage = startPage;
}
/**
* Returns the current page.
*
* @return the current page.
*/
public int getPage() {
return page;
}
/**
* Sets the current page.
*
* @param page
* the page.
*/
protected void setPage( final int page ) {
this.page = page;
}
/**
* Receives notification that the report has started.
*
* @param event
* the event.
*/
public void reportInitialized( final ReportEvent event ) {
if ( event.isDeepTraversing() ) {
return;
}
// Next event in list will be the first page-started event. Will set the page number again..
this.setPage( getStartPage() );
ignoreNextGroupStart = true;
ignoreNextPageStart = false;
// waitForNextGroupStart = false;
}
/**
* Receives notification that a group has started.
*
* @param event
* the event.
*/
public void groupStarted( final ReportEvent event ) {
// The defined group is only valid for the master-report.
if ( event.isDeepTraversing() ) {
return;
}
// if we have no defined group, no need to do anything else.
if ( getGroup() == null ) {
return;
}
if ( FunctionUtilities.isDefinedGroup( getGroup(), event ) ) {
// waitForNextGroupStart = false;
if ( ignoreNextGroupStart ) {
// The report-header had been printed recently. Add it to the group's list of pages
ignoreNextGroupStart = false;
return;
}
ignoreNextPageStart = true;
// Unconditionally reset the page counter. For groups not starting with a new page, the
// behaviour of the function is undefined.
this.setPage( getStartPage() );
}
}
/**
* Receives notification from the report engine that a new page is starting. Grabs the page number from the report
* state and stores it.
*
* @param event
* the event.
*/
public void pageStarted( final ReportEvent event ) {
if ( ( event.getType() & ReportEvent.REPORT_INITIALIZED ) == ReportEvent.REPORT_INITIALIZED ) {
if ( event.isDeepTraversing() == false ) {
this.setPage( getStartPage() );
return;
}
}
if ( ignoreNextPageStart ) {
ignoreNextPageStart = false;
return;
}
// if (waitForNextGroupStart &&
// (event.getType() & ReportEvent.GROUP_STARTED) == ReportEvent.GROUP_STARTED)
// {
// this.setPage(getStartPage());
// this.waitForNextGroupStart = false;
// return;
// }
setPage( getPage() + getPageIncrement() );
}
/**
* Returns, whether the next page-start event will be ignored. This is an internal state flag to keep the computation
* in sync with the events.
*
* @return the flag.
*/
protected boolean isIgnoreNextPageStart() {
return ignoreNextPageStart;
}
/**
* Receives notification that a page is completed.
*
* @param event
* The event.
*/
public void pageFinished( final ReportEvent event ) {
// ignored ...
}
//
// public void groupFinished(final ReportEvent event)
// {
// // The defined group is only valid for the master-report.
// if (event.isDeepTraversing())
// {
// return;
// }
// // if we have no defined group, no need to do anything else.
// if (getGroup() == null)
// {
// return;
// }
//
// // if (FunctionUtilities.isDefinedGroup(getGroup(), event))
// // {
// // waitForNextGroupStart = true;
// // }
// }
/**
* Returns the page number (function value).
*
* @return the page number.
*/
public Object getValue() {
return IntegerCache.getInteger( getPage() );
}
/**
* A internal flag that defines wether the next group start should be ignored. We have to ignore the first group start
* of each report so that the report-header becomes part of the first group's page sequence.
*
* @return the internal flag.
*/
protected boolean isIgnoreNextGroupStart() {
return ignoreNextGroupStart;
}
/**
* A obsolete getter. Ignore it please, it has no effect.
*
* @return true, if you care to know.
* @deprecated No longer used.
*/
protected boolean isIgnorePageCancelEvents() {
return true;
}
/**
* A obsolete setter. Ignore it please, it has no effect.
*
* @param ignorePageCancelEvents
* ignored.
* @deprecated No longer used.
*/
public void setIgnorePageCancelEvents( final boolean ignorePageCancelEvents ) {
}
}