/*
* 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 - 2016 Object Refinery Ltd, Pentaho Corporation and Contributors.. All rights reserved.
*/
package org.pentaho.reporting.engine.classic.core.event;
import org.pentaho.reporting.engine.classic.core.states.ReportState;
import java.util.EventObject;
/**
* A report progress event notifies the listeners about the proceedings of the report processing. It is generated by the
* report processor implementations.
*
* @author Thomas Morgner
*/
public class ReportProgressEvent extends EventObject implements Cloneable {
/**
* An activity constant that indicates that the current report is currently being processed. (This is a boilerplate
* event in case none of the other events matched.)
*/
public static final int COMPUTING_LAYOUT = 0;
/**
* An activity constant that indicates that the report is precomputing values. This is usually the first stage of
* report processing.
*/
public static final int PRECOMPUTING_VALUES = 1;
/**
* An activity constant that indicates that the report's page-layout is being computed. This computes where pagebreaks
* will be inserted and how many pages are available.
*/
public static final int PAGINATING = 2;
/**
* An activity constant that indicates that the report content is generated. This is the final processing step.
*/
public static final int GENERATING_CONTENT = 3;
private static final int DEFAULT_VALUE = -1;
/**
* The progress level is an indicator for the current processing level.
*/
private int level;
/**
* The maximum value the progress level will get for this report.
*/
private int maximumLevel;
/**
* The indicator for the current activity. One of COMPUTING_LAYOUT, PRECOMPUTING_VALUES, PAGINATING or
* GENERATING_CONTENT.
*/
private int activity;
/**
* The current row of the outermost master report.
*/
private int row;
/**
* The maximum row of the outermost master report.
*/
private int maximumRow;
/**
* The current physical page.
*/
private int page;
/**
* Total number of pages in the report
*/
private int totalPages;
/**
* Creates a new even without any properties defined. Use this to create a reusable event object.
*
* @param source
* the report processor that generated this event.
*/
public ReportProgressEvent( final Object source ) {
super( source );
this.maximumLevel = DEFAULT_VALUE;
this.level = DEFAULT_VALUE;
this.maximumRow = DEFAULT_VALUE;
this.page = DEFAULT_VALUE;
this.totalPages = DEFAULT_VALUE;
this.activity = COMPUTING_LAYOUT;
this.row = DEFAULT_VALUE;
}
/**
* Creates a new even without any properties defined. Use this to create a reusable event object.
*
* @param source
* the report processor that generated this event.
* @deprecated Use constructor with total pages instead
*/
@Deprecated
public ReportProgressEvent( final Object source, final int page ) {
super( source );
this.maximumLevel = DEFAULT_VALUE;
this.level = DEFAULT_VALUE;
this.maximumRow = DEFAULT_VALUE;
this.page = page;
this.totalPages = DEFAULT_VALUE;
this.activity = COMPUTING_LAYOUT;
this.row = DEFAULT_VALUE;
}
/**
* Creates a new even without any properties defined. Use this to create a reusable event object.
*
* @param source
* the report processor that generated this event.
* @param totalPages
* total pages in the report
*/
public ReportProgressEvent( final Object source, final int page, final int totalPages ) {
this( source, page );
this.totalPages = totalPages;
}
/**
* Creates a new report-progress event.
*
* @param source
* the report processor that generated this event.
* @param activity
* the current activity.
* @param row
* the currently processed row.
* @param maximumRow
* the number of rows in this local report.
* @param page
* the current page that is being processed.
* @param level
* the current processing level.
* @param maximumLevel
* the maximum processing level.
* @deprecated Use constructor with total pages instead
*/
@Deprecated
public ReportProgressEvent( final Object source, final int activity, final int row, final int maximumRow,
final int page, final int level, final int maximumLevel ) {
super( source );
this.maximumLevel = maximumLevel;
this.level = level;
this.maximumRow = maximumRow;
this.page = page;
this.totalPages = DEFAULT_VALUE;
this.activity = activity;
this.row = row;
}
/**
* Creates a new report-progress event.
*
* @param source
* the report processor that generated this event.
* @param activity
* the current activity.
* @param row
* the currently processed row.
* @param maximumRow
* the number of rows in this local report.
* @param page
* the current page that is being processed.
* @param totalPages
* total pages in the report
* @param level
* the current processing level.
* @param maximumLevel
* the maximum processing level.
*/
public ReportProgressEvent( final Object source, final int activity, final int row, final int maximumRow,
final int page, final int totalPages, final int level, final int maximumLevel ) {
this( source, activity, row, maximumRow, page, level, maximumLevel );
this.totalPages = totalPages;
}
/**
* Returns a string representation of this object.
*
* @return a string representing the state of this object.
*/
public String toString() {
return "ReportProgressEvent[activity=" + activity //$NON-NLS-1$
+ ", row=" + row //$NON-NLS-1$
+ ", maximumRow=" + maximumRow //$NON-NLS-1$
+ ", page=" + page //$NON-NLS-1$
+ ", totalPages=" + totalPages //$NON-NLS-1$
+ ", level=" + level //$NON-NLS-1$
+ ", maximumLevel=" + maximumLevel + ']'; //$NON-NLS-1$ //$NON-NLS-2$
}
/**
* Returns the current row.
*
* @return the row.
*/
public int getRow() {
return row;
}
/**
* Returns the current activity (one of COMPUTING_LAYOUT, PRECOMPUTING_VALUES, PAGINATING or GENERATING_CONTENT).
*
* @return the activity constant.
* @see ReportProgressEvent#COMPUTING_LAYOUT
* @see ReportProgressEvent#PRECOMPUTING_VALUES
* @see ReportProgressEvent#PAGINATING
* @see ReportProgressEvent#GENERATING_CONTENT
*/
public int getActivity() {
return activity;
}
/**
* Returns the current page number.
*
* @return the current page.
*/
public int getPage() {
return page;
}
/**
* Returns total number pages in the report
*
* @return total number pages in the report
*/
public int getTotalPages() {
return totalPages;
}
/**
* Returns the total number of rows contained in this report's datasource.
*
* @return the number of rows.
*/
public int getMaximumRow() {
return maximumRow;
}
/**
* Returns the maximum level the report processing can reach for the report that generated the event.
*
* @return the maximum level.
*/
public int getMaximumLevel() {
return maximumLevel;
}
/**
* Returns the current processing level. Report processing is a multi-pass process, the level provides a linear
* measurement of the current progress.
*
* @return the level.
*/
public int getLevel() {
return level;
}
public void reuse( final int activity, final ReportState rawState, final int pageCount ) {
reuse( activity, rawState, pageCount, this.totalPages );
}
public void reuse( final int activity, final ReportState rawState, final int pageCount, final int totalPages ) {
ReportState state = rawState;
while ( state.getParentState() != null ) {
state = state.getParentState();
}
reuse( activity, state.getCurrentRow(), state.getNumberOfRows(), pageCount, totalPages, state.getProgressLevel(), state
.getProgressLevelCount() );
}
/**
* Reuses the report event by updating the internal properties. This is used as simple mean to reduce the number of
* objects generated in the system and should not be used elsewhere.
*
* @param activity
* the activity as constant.
* @param row
* the current row.
* @param maximumRow
* the total rows in the datasource.
* @param page
* the current page.
* @param level
* the current processing level.
* @param maximumLevel
* the maximum processing level.
*/
public void reuse( final int activity, final int row, final int maximumRow, final int page, final int level,
final int maximumLevel ) {
this.maximumRow = maximumRow;
this.page = page;
this.activity = activity;
this.row = row;
this.maximumLevel = maximumLevel;
this.level = level;
}
/**
* Reuses the report event by updating the internal properties. This is used as simple mean to reduce the number of
* objects generated in the system and should not be used elsewhere.
*
* @param activity
* the activity as constant.
* @param row
* the current row.
* @param maximumRow
* the total rows in the datasource.
* @param page
* the current page.
* @param totalPages
* total pages in the report
* @param level
* the current processing level.
* @param maximumLevel
* the maximum processing level.
*/
public void reuse( final int activity, final int row, final int maximumRow, final int page, final int totalPages, final int level,
final int maximumLevel ) {
reuse( activity, row, maximumRow, page, level, maximumLevel );
this.totalPages = totalPages;
}
/**
* Creats a copy of the current instance of this object.
*
* @return a copy of the current object as a new object.
*/
public Object clone() {
try {
return super.clone();
} catch ( final CloneNotSupportedException e ) {
throw new IllegalStateException( "Cloning not successful." );
}
}
/**
* Computes the percentage complete (on a scale from 0.0 to 100.0) based on the information found in the report
* progress event.
*
* @param event
* the data used to calculate the percentage complete
* @param onlyPagination
* true, if the processing stops after pagination, or false, if a full export is done.
* @return the calculated percentage complete
*/
public static double computePercentageComplete( final ReportProgressEvent event, final boolean onlyPagination ) {
final double levelPercentage; // the amount of work already done in previous levels;
final double levelSizePercentage; // the amount of work we complete this time ..
if ( event.getLevel() == Integer.MAX_VALUE ) {
// reserve 10% for structural computations
levelPercentage = 0;
levelSizePercentage = 0.1;
} else if ( onlyPagination ) {
// reserve 10% for the structure (and assume it has been done already)
// and assume the layouting takes at least 5 times as much effort than a single level.
final int dataLevels = Math.max( 0, event.getMaximumLevel() );
final int layoutWeight = 5;
if ( event.getLevel() == ( event.getMaximumLevel() - 1 ) ) {
// layouter stage
levelPercentage = 0.1 + ( 0.9 * ( dataLevels / ( dataLevels + layoutWeight ) ) );
levelSizePercentage = 1.0 - levelPercentage;
} else {
// data stage
levelPercentage = 0.1 + ( 0.9 * ( event.getLevel() / ( dataLevels + layoutWeight ) ) );
levelSizePercentage = 0.1 + ( 0.9 * ( 1.0 / ( dataLevels + layoutWeight ) ) );
}
} else {
final int dataLevels = Math.max( 0, event.getMaximumLevel() );
final int layoutWeight = 5;
if ( event.getLevel() == ( event.getMaximumLevel() - 1 ) ) {
if ( event.getActivity() == ReportProgressEvent.GENERATING_CONTENT ) {
levelPercentage = 0.1 + ( 0.9 * ( event.getLevel() / dataLevels + 2 * layoutWeight ) );
levelSizePercentage = 0.1 + ( 0.9 * ( ( dataLevels + layoutWeight ) / ( dataLevels + 2 * layoutWeight ) ) );
} else {
levelPercentage = 0.1 + ( 0.9 * ( event.getLevel() / ( dataLevels + 2 * layoutWeight ) ) );
levelSizePercentage = 0.1 + ( 0.9 * ( dataLevels / ( dataLevels + 2 * layoutWeight ) ) );
}
} else {
// data stage
levelPercentage = 0.1 + ( 0.9 * ( event.getLevel() / ( dataLevels + 2 * layoutWeight ) ) );
levelSizePercentage = 0.1 + ( 0.9 * ( 1.0 / ( dataLevels + 2 * layoutWeight ) ) );
}
}
final double subPercentage = levelSizePercentage * ( event.getRow() / (double) event.getMaximumRow() );
final double percentage = 100.0 * ( levelPercentage + subPercentage );
return Math.max( 0.0, Math.min( 100.0, percentage ) );
}
}