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: * FlowRenderer.java
027: * ------------
028: * (C) Copyright 2001-2007, by Object Refinery Ltd, Pentaho Corporation and Contributors.
029: */package org.jfree.report.layout;
030:
031: import org.jfree.report.PageDefinition;
032: import org.jfree.report.layout.model.LogicalPageBox;
033: import org.jfree.report.layout.output.ContentProcessingException;
034: import org.jfree.report.layout.output.IterativeOutputProcessor;
035: import org.jfree.report.layout.output.LayoutPagebreakHandler;
036: import org.jfree.report.layout.output.OutputProcessor;
037: import org.jfree.report.layout.output.OutputProcessorFeature;
038: import org.jfree.report.layout.process.ApplyPageShiftValuesStep;
039: import org.jfree.report.layout.process.CleanFlowBoxesStep;
040: import org.jfree.report.layout.process.CleanPaginatedBoxesStep;
041: import org.jfree.report.layout.process.FillFlowPagesStep;
042: import org.jfree.report.layout.process.FlowPaginationStep;
043: import org.jfree.report.layout.process.PaginationResult;
044: import org.jfree.report.layout.process.ApplyAutoCommitPageHeaderStep;
045: import org.jfree.report.util.InstanceID;
046:
047: /**
048: * A flow renderer is a light-weight paginating renderer. It does not care about the page-size but searches for manual
049: * breaks. Once a manual break is encountered, the flow shifts and creates a page-event. (This is the behavior of the
050: * old table-exporters.)
051: * <p/>
052: * This implementation is a mix of a paginated and streaming renderer.
053: *
054: * @author Thomas Morgner
055: */
056: public class FlowRenderer extends AbstractRenderer {
057: private FlowPaginationStep paginationStep;
058: private FillFlowPagesStep fillPhysicalPagesStep;
059: private CleanPaginatedBoxesStep cleanPaginatedBoxesStep;
060: private CleanFlowBoxesStep cleanFlowBoxesStep;
061: private ApplyPageShiftValuesStep applyPageShiftValuesStep;
062: private ApplyAutoCommitPageHeaderStep applyAutoCommitPageHeaderStep;
063: private int flowCount;
064: private long lastPageAge;
065: private boolean pageStartPending;
066:
067: public FlowRenderer(final OutputProcessor outputProcessor) {
068: super (outputProcessor);
069: this .paginationStep = new FlowPaginationStep();
070: this .fillPhysicalPagesStep = new FillFlowPagesStep();
071: this .cleanPaginatedBoxesStep = new CleanPaginatedBoxesStep();
072: this .cleanFlowBoxesStep = new CleanFlowBoxesStep();
073: this .applyPageShiftValuesStep = new ApplyPageShiftValuesStep();
074: this .applyAutoCommitPageHeaderStep = new ApplyAutoCommitPageHeaderStep();
075: }
076:
077: public void startReport(final PageDefinition pageDefinition) {
078: super .startReport(pageDefinition);
079: lastPageAge = System.currentTimeMillis();
080: }
081:
082: protected boolean isPageFinished() {
083: final LogicalPageBox pageBox = getPageBox();
084: // final long sizeBeforePagination = pageBox.getHeight();
085: //final LogicalPageBox clone = (LogicalPageBox) pageBox.deriveForAdvance(true);
086: final PaginationResult pageBreak = paginationStep
087: .performPagebreak(pageBox);
088: if (pageBreak.isOverflow() || pageBox.isOpen() == false) {
089: setLastStateKey(pageBreak.getLastVisibleState());
090: return true;
091: }
092: return false;
093: }
094:
095: protected void debugPrint(final LogicalPageBox pageBox) {
096: // ModelPrinter.print(pageBox);
097: }
098:
099: public void processIncrementalUpdate(final boolean performOutput)
100: throws ContentProcessingException {
101: if (isDirty() == false) {
102: // Log.debug ("Not dirty, no update needed.");
103: return;
104: }
105: clearDirty();
106:
107: final OutputProcessor outputProcessor = getOutputProcessor();
108: if (outputProcessor instanceof IterativeOutputProcessor == false
109: || outputProcessor.getMetaData().isFeatureSupported(
110: OutputProcessorFeature.ITERATIVE_RENDERING) == false) {
111: // Log.debug ("No incremental system.");
112: return;
113: }
114:
115: final LogicalPageBox pageBox = getPageBox();
116: pageBox.setPageEnd(pageBox.getHeight());
117: // Log.debug ("Computing Incremental update: " + pageBox.getPageOffset() + " " + pageBox.getPageEnd());
118: // shiftBox(pageBox, true);
119:
120: if (pageBox.isOpen()) {
121: final IterativeOutputProcessor io = (IterativeOutputProcessor) outputProcessor;
122: if (applyAutoCommitPageHeaderStep.compute(pageBox)) {
123: io.processIterativeContent(pageBox, performOutput);
124: cleanFlowBoxesStep.compute(pageBox);
125: }
126: }
127: }
128:
129: protected boolean performPagination(
130: final LayoutPagebreakHandler layoutPagebreakHandler,
131: final boolean performOutput)
132: throws ContentProcessingException {
133: final OutputProcessor outputProcessor = getOutputProcessor();
134: // next: perform pagination.
135: final LogicalPageBox pageBox = getPageBox();
136: // final long sizeBeforePagination = pageBox.getHeight();
137: //final LogicalPageBox clone = (LogicalPageBox) pageBox.deriveForAdvance(true);
138: final PaginationResult pageBreak = paginationStep
139: .performPagebreak(pageBox);
140: if (pageBreak.isOverflow() || pageBox.isOpen() == false) {
141: setLastStateKey(pageBreak.getLastVisibleState());
142: // final long sizeAfterPagination = pageBox.getHeight();
143: setPagebreaks(getPagebreaks() + 1);
144: pageBox.setAllVerticalBreaks(pageBreak.getAllBreaks());
145:
146: flowCount += 1;
147: debugPrint(pageBox);
148:
149: // A new page has been started. Recover the page-grid, then restart
150: // everything from scratch. (We have to recompute, as the pages may
151: // be different now, due to changed margins or page definitions)
152: final long nextOffset = pageBox.computePageEnd();
153: pageBox.setPageEnd(nextOffset);
154: final long pageOffset = pageBox.getPageOffset();
155:
156: if (performOutput) {
157: if (outputProcessor.isNeedAlignedPage()) {
158: final LogicalPageBox box = fillPhysicalPagesStep
159: .compute(pageBox, pageOffset, nextOffset);
160: // Log.debug("Processing contents for Page " + flowCount + " Page-Offset: " + pageOffset + " -> " + nextOffset);
161:
162: outputProcessor.processContent(box);
163: } else {
164: // Log.debug("Processing fast contents for Page " + flowCount + " Page-Offset: " + pageOffset + " -> " + nextOffset);
165: outputProcessor.processContent(pageBox);
166: }
167: } else {
168: // Log.debug("Recomputing contents for Page " + flowCount + " Page-Offset: " + pageOffset + " -> " + nextOffset);
169: outputProcessor.processRecomputedContent(pageBox);
170: }
171:
172: // Now fire the pagebreak. This goes through all layers and informs all
173: // components, that a pagebreak has been encountered and possibly a
174: // new page has been set. It does not save the state or perform other
175: // expensive operations. However, it updates the 'isPagebreakEncountered'
176: // flag, which will be active until the input-feed received a new event.
177: final long currentPageAge = System.currentTimeMillis();
178: // Log.debug("PageTime " + (currentPageAge - lastPageAge));
179: lastPageAge = currentPageAge;
180:
181: final boolean repeat = pageBox.isOpen()
182: || pageBreak.isOverflow();
183: if (repeat) {
184: // pageBox.setAllVerticalBreaks(pageBreak.getAllBreaks());
185: // First clean all boxes that have been marked as finished. This reduces the overall complexity of the
186: // pagebox and improves performance on huge reports.
187: cleanFlowBoxesStep.compute(pageBox);
188:
189: final long l = cleanPaginatedBoxesStep.compute(pageBox);
190: if (l > 0) {
191: // Log.debug ("Apply shift afterwards " + l);
192: final InstanceID shiftNode = cleanPaginatedBoxesStep
193: .getShiftNode();
194: applyPageShiftValuesStep.compute(pageBox, l,
195: shiftNode);
196: debugPrint(pageBox);
197: }
198:
199: pageBox.setPageOffset(nextOffset);
200: if (pageBreak.isNextPageContainsContent()) {
201: if (layoutPagebreakHandler != null) {
202: layoutPagebreakHandler.pageStarted();
203: }
204: return true;
205: }
206: // No need to try again, we know that the result will not change, as the next page is
207: // empty. (We already tested it.)
208: pageStartPending = true;
209: return false;
210: } else {
211: outputProcessor.processingFinished();
212: pageBox.setPageOffset(nextOffset);
213: return false;
214: }
215: } else if (outputProcessor instanceof IterativeOutputProcessor
216: && outputProcessor.getMetaData().isFeatureSupported(
217: OutputProcessorFeature.ITERATIVE_RENDERING)) {
218: processIncrementalUpdate(performOutput);
219: // final IterativeOutputProcessor io = (IterativeOutputProcessor) outputProcessor;
220: // io.processIterativeContent(pageBox, performOutput);
221: // cleanFlowBoxesStep.compute(pageBox);
222: }
223: return false;
224: }
225:
226: public int getFlowCount() {
227: return flowCount;
228: }
229:
230: public boolean clearPendingPageStart(
231: final LayoutPagebreakHandler layoutPagebreakHandler) {
232: if (pageStartPending == false) {
233: return false;
234: }
235:
236: if (layoutPagebreakHandler != null) {
237: layoutPagebreakHandler.pageStarted();
238: }
239: pageStartPending = false;
240: return true;
241: }
242:
243: public boolean isPageStartPending() {
244: return pageStartPending;
245: }
246: }
|