📄 pageablereportprocessor.java
字号:
int level = ((Integer) it.next()).intValue();
// outer loop: process all function levels
do
{
// if the current level is the output-level, then save the report state.
// The state is used later to restart the report processing.
if (level == PRINT_FUNCTION_LEVEL)
{
pageStates = new ReportStateList(this);
state = processPrintedPages(state, pageStates, dummyOutput, maxRows);
}
else
{
state = processPrepareLevels(state, level, maxRows);
}
// if there is an other level to process, then use the finish state to
// create a new start state, which will continue the report processing on
// the next higher level.
hasNext = it.hasNext();
if (hasNext)
{
level = ((Integer) it.next()).intValue();
if (state instanceof FinishState)
{
state = new StartState((FinishState) state, level);
if (state.getCurrentPage() != ReportState.BEFORE_FIRST_PAGE)
{
throw new IllegalStateException("State was not set up properly");
}
}
else
{
throw new IllegalStateException("Repaginate did not produce an finish state");
}
}
}
while (hasNext == true);
dummyOutput.close();
state.setProperty(JFreeReport.REPORT_PREPARERUN_PROPERTY, Boolean.FALSE);
// finally return the saved page states.
return pageStates;
}
catch (OutputTargetException ote)
{
throw new ReportProcessingException("Unable to repaginate Report", ote);
}
catch (FunctionInitializeException fne)
{
throw new ReportProcessingException("Unable to initialize the functions/expressions.", fne);
}
catch (CloneNotSupportedException cne)
{
throw new ReportProcessingException("Unable to initialize the report, clone error", cne);
}
}
/**
* Processes the print level for the current report. This function will
* fill the report state list while performing the repagination.
*
* @param state the start state for the print level.
* @param pageStates the list of report states that should receive the created page states.
* @param dummyOutput a dummy output target which performs the layout calculations.
* @param maxRows the number of rows in the report (used to estaminate the current progress).
* @return the finish state for the report.
* @throws ReportProcessingException if there was a problem processing the report.
*/
private ReportState processPrintedPages(ReportState state, final ReportStateList pageStates,
final OutputTarget dummyOutput, final int maxRows)
throws ReportProcessingException
{
final boolean failOnError = getReport().getReportConfiguration().isStrictErrorHandling();
ReportStateProgress progress = null;
final RepaginationState repaginationState = new RepaginationState(this, 0, 0, 0, 0, true);
// inner loop: process the complete report, calculate the function values
// for the current level. Higher level functions are not available in the
// dataRow.
while (!state.isFinish())
{
// fire an event for every generated page. It does not really matter
// if that policy is not very informative, it is sufficient ...
repaginationState.reuse(PRINT_FUNCTION_LEVEL,
state.getCurrentPage(), state.getCurrentDataItem(), maxRows, true);
fireStateUpdate(repaginationState);
final ReportState oldstate = state;
progress = state.createStateProgress(progress);
state = processPage(state, dummyOutput, failOnError);
if (!state.isFinish())
{
// if the report processing is stalled, throw an exception; an infinite
// loop would be caused.
if (!state.isProceeding(progress))
{
throw new ReportProcessingException("State did not proceed, bailing out!");
}
}
// if layout level has reached, and some content was generated, then add the page
if (isEmptyPageGenerated(state) == false)
{
// add the page start event ..
pageStates.add(oldstate);
}
else
{
// inform the next page, that the last one was canceled ...
state.firePageCanceledEvent();
}
}
return state;
}
/**
* Processes all prepare levels to compute the function values.
*
* @param state the state state with which we beginn the processing.
* @param level the current processing level.
* @param maxRows the number of rows in the table model.
* @return the finish state for the current level.
* @throws ReportProcessingException if processing failed or if there are
* exceptions during the function execution.
*/
private ReportState processPrepareLevels(ReportState state, final int level, final int maxRows)
throws ReportProcessingException
{
final boolean failOnError = getReport().getReportConfiguration().isStrictErrorHandling();
ReportStateProgress progress = null;
int lastRow = -1;
int eventCount = 0;
final int eventTrigger = maxRows / MAX_EVENTS_PER_RUN;
final RepaginationState repaginationState = new RepaginationState(this, 0, 0, 0, 0, true);
// Function processing does not use the PageLayouter, so we don't need
// the expensive cloning ...
while (!state.isFinish())
{
checkInterrupted();
if (lastRow != state.getCurrentDisplayItem())
{
lastRow = state.getCurrentDisplayItem();
if (eventCount == 0)
{
repaginationState.reuse(level,
state.getCurrentPage(), state.getCurrentDataItem(), maxRows, true);
fireStateUpdate(repaginationState);
eventCount += 1;
}
else
{
if (eventCount == eventTrigger)
{
eventCount = 0;
}
else
{
eventCount += 1;
}
}
}
progress = state.createStateProgress(progress);
state = state.advance();
if (failOnError)
{
if (state.isErrorOccured() == true)
{
throw new ReportEventException("Failed to dispatch an event.", state.getErrors());
}
}
else
{
if (state.isErrorOccured() == true)
{
Log.error("Failed to dispatch an event.",
new ReportEventException("Failed to dispatch an event.", state.getErrors()));
}
}
if (!state.isFinish())
{
// if the report processing is stalled, throw an exception; an infinite
// loop would be caused.
if (!state.isProceeding(progress))
{
throw new ReportProcessingException("State did not proceed, bailing out!");
}
}
}
return state;
}
/**
* Draws a single page of the report to the specified graphics device, and returns state
* information. The caller should check the returned state to ensure that some progress has
* been made, because on some small paper sizes the report may get stuck (particularly if the
* header and footer are large).
* <p>
* To check the progress, use ReportState.isProceeding(oldstate).
*
* @param out The output target.
* @param currPage The report state at the beginning of the current page.
*
* @return The report state suitable for the next page or ReportState.FinishState.
*
* @throws IllegalArgumentException if the given state is a start or a finish state.
* @throws ReportProcessingException if there is a problem processing the report or the
* current thread has been interrupted.
*/
public ReportState processPage(final ReportState currPage, final OutputTarget out)
throws ReportProcessingException
{
return processPage(currPage, out, getReport().getReportConfiguration().isStrictErrorHandling());
}
/**
* Checks, whether the current thread is interrupted.
*
* @throws ReportInterruptedException if the thread is interrupted to
* abort the report processing.
*/
private void checkInterrupted () throws ReportInterruptedException
{
if (isHandleInterruptedState() && Thread.interrupted())
{
throw new ReportInterruptedException("Current thread is interrupted. Returning.");
}
}
/**
* Draws a single page of the report to the specified graphics device, and returns state
* information. The caller should check the returned state to ensure that some progress has
* been made, because on some small paper sizes the report may get stuck (particularly if the
* header and footer are large).
* <p>
* To check the progress, use ReportState.isProceeding(oldstate).
*
* @param out The output target.
* @param currPage The report state at the beginning of the current page.
* @param failOnError if set to true, then errors in the report event handling will cause the
* reporting to fail.
*
* @return The report state suitable for the next page or ReportState.FinishState.
*
* @throws IllegalArgumentException if the given state is a start or a finish state.
* @throws ReportProcessingException if there is a problem processing the report or the
* current thread has been interrupted.
*/
public ReportState processPage(final ReportState currPage, final OutputTarget out,
final boolean failOnError)
throws ReportProcessingException
{
if (out == null)
{
throw new NullPointerException("OutputTarget != null");
}
if (out.isOpen() == false)
{
throw new IllegalStateException("OutputTarget is not open!");
}
if (currPage == null)
{
throw new NullPointerException("State != null");
}
// if a finish state is set to be processed, crash to make sure that FinishStates
// are caught outside, we won't handle them here
if (currPage.isFinish())
{
throw new IllegalArgumentException("No finish state for processpage allowed: ");
}
ReportState state = null;
PageLayouter lm = null;
try
{
checkInterrupted();
try
{
state = (ReportState) currPage.clone();
}
catch (CloneNotSupportedException cne)
{
throw new ReportProcessingException("Clone not supported by ReportState?!");
}
lm = (PageLayouter) state.getDataRow().get(LAYOUTMANAGER_NAME);
lm.setLogicalPage(out.getLogicalPage());
lm.restoreSaveState(state);
// docmark: page spanning bands will affect this badly designed code.
// this code will definitly be affected by the Band-intenal-pagebreak code
// to this is non-fatal. the next redesign is planed here :)
// The state restoration must not finish the current page, except the whole
// report processing will be finished.
if (lm.isPageEnded())
{
state = state.advance();
if (state.isFinish() == false)
{
throw new ReportProcessingException("State finished page during restore");
}
}
else
{
// Do some real work. The report header and footer, and the page headers and footers are
// just decorations, as far as the report state is concerned. The state only changes in
// the following code...
// this loop advances the report state until the next page gets started or
// the end of the reporting is reached.
// note: Dont test the end of the page, this gives no hint whether there will
// be a next page ...
while ((lm.isPageEnded() == false) && (state.isFinish() == false))
{
final PageLayouter org = (PageLayouter) state.getDataRow().get(LAYOUTMANAGER_NAME);
state = state.advance();
if (failOnError)
{
if (state.isErrorOccured() == true)
{
throw new ReportEventException("Failed to dispatch an event.", state.getErrors());
}
}
else
{
if (state.isErrorOccured() == true)
{
Log.error("Failed to dispatch an event.",
new ReportEventException("Failed to dispatch an event.", state.getErrors()));
}
}
lm = (PageLayouter) state.getDataRow().get(LAYOUTMANAGER_NAME);
if (org != lm)
{
// assertation check, the pagelayouter must not change during the processing.
throw new IllegalStateException("Lost the layout manager");
}
checkInterrupted();
}
}
}
finally
{
// clear the logical page reference, so that no memleak is created...
if (lm != null)
{
lm.clearLogicalPage();
}
}
return state;
}
/**
* Checks the state of the logical page, to see whether some content has been
* printed on the page.
*
* @param state the state which should be checked
* @return true, if the page is empty, false otherwise.
*/
protected boolean isEmptyPageGenerated(final ReportState state)
{
final PageLayouter org = (PageLayouter) state.getDataRow().get(LAYOUTMANAGER_NAME);
return org.isGeneratedPageEmpty();
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -