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: * CleanPaginatedBoxesStep.java
027: * ------------
028: * (C) Copyright 2001-2007, by Object Refinery Ltd, Pentaho Corporation and Contributors.
029: */package org.jfree.report.layout.process;
030:
031: import org.jfree.report.layout.model.BlockRenderBox;
032: import org.jfree.report.layout.model.CanvasRenderBox;
033: import org.jfree.report.layout.model.FinishedRenderNode;
034: import org.jfree.report.layout.model.LogicalPageBox;
035: import org.jfree.report.layout.model.ParagraphRenderBox;
036: import org.jfree.report.layout.model.RenderBox;
037: import org.jfree.report.layout.model.RenderNode;
038: import org.jfree.report.util.InstanceID;
039:
040: /**
041: * This step must not remove boxes that have a manual break attached.
042: *
043: * @author Thomas Morgner
044: */
045: public final class CleanPaginatedBoxesStep extends
046: IterateStructuralProcessStep {
047: private long pageOffset;
048: private long shiftOffset;
049: private InstanceID shiftNode;
050:
051: public CleanPaginatedBoxesStep() {
052: }
053:
054: public long compute(final LogicalPageBox pageBox) {
055: shiftOffset = 0;
056: pageOffset = pageBox.getPageOffset();
057: if (startBlockBox(pageBox)) {
058: // not processing the header and footer area: they are 'out-of-context' bands
059: processBoxChilds(pageBox);
060: }
061: finishBlockBox(pageBox);
062: //Log.debug ("ShiftOffset after clean: " + shiftOffset);
063: return shiftOffset;
064: }
065:
066: public InstanceID getShiftNode() {
067: return shiftNode;
068: }
069:
070: protected void processParagraphChilds(final ParagraphRenderBox box) {
071: // we do not process the paragraph lines. This should have been done
072: // in the startblock thing and they get re-added anyway as long as the
073: // paragraph is active.
074: }
075:
076: public boolean startCanvasBox(final CanvasRenderBox box) {
077: return false;
078: }
079:
080: protected boolean startBlockBox(final BlockRenderBox box) {
081: if (box instanceof ParagraphRenderBox) {
082: return false;
083: }
084:
085: if (box.isFinished() == false) {
086: return true;
087: }
088:
089: final RenderNode firstNode = box.getVisibleFirst();
090: if (firstNode == null) {
091: // The cell is empty ..
092: return false;
093: }
094:
095: final long nodeY = firstNode.getY();
096: if (nodeY > pageOffset) {
097: // This box will be visible or will be processed in the future.
098: return false;
099: }
100:
101: if (firstNode.isOpen()) {
102: return true;
103: }
104:
105: if ((firstNode.getY() + firstNode.getHeight()) > pageOffset) {
106: // this box will span to the next page and cannot be removed ...
107: return true;
108: }
109:
110: // Next, search the last node that is fully invisible. We collapse all
111: // invisible node into one big box for efficiency reasons. They wont be
112: // visible anyway and thus the result will be the same as if they were
113: // still alive ..
114: RenderNode last = firstNode;
115: while (true) {
116: final RenderNode next = last.getVisibleNext();
117: if (next == null) {
118: break;
119: }
120: if (next.isOpen()) {
121: // as long as a box is open, it can grow and therefore it cannot be
122: // removed ..
123: break;
124: }
125:
126: if ((next.getY() + next.getHeight()) > pageOffset) {
127: // we cant handle that. This node will be visible. So the current last
128: // node is the one we can shrink ..
129: break;
130: }
131: last = next;
132: }
133:
134: if (last == firstNode) {
135: if (last instanceof FinishedRenderNode) {
136: // In this case, we can skip the replace-action below ..
137: return true;
138: }
139: }
140:
141: // So lets get started. We remove all nodes between (and inclusive)
142: // node and last.
143: final long width = box.getContentAreaX2()
144: - box.getContentAreaX1();
145: final long lastY2 = last.getY() + last.getHeight();
146: final long height = lastY2 - nodeY;
147:
148: // make sure that the finished-box inherits the margins ..
149: final long marginsTop = firstNode.getEffectiveMarginTop();
150: final long marginsBottom = last.getEffectiveMarginBottom();
151: final boolean breakAfter = isBreakAfter(last);
152: final FinishedRenderNode replacement = new FinishedRenderNode(
153: width, height, marginsTop, marginsBottom, breakAfter);
154:
155: RenderNode removeNode = firstNode;
156: while (removeNode != last) {
157: final RenderNode next = removeNode.getNext();
158: if (removeNode.isOpen()) {
159: throw new IllegalStateException(
160: "A node is still open. We should not have come that far.");
161: }
162: box.remove(removeNode);
163: removeNode = next;
164: }
165:
166: if (last.isOpen()) {
167: throw new IllegalStateException(
168: "The last node is still open. We should not have come that far.");
169: }
170: box.replaceChild(last, replacement);
171: if (replacement.getParent() != box) {
172: // return true;
173: throw new IllegalStateException(
174: "The replacement did not work.");
175: }
176:
177: final long cachedY2 = last.getCachedY()
178: + last.getCachedHeight();
179: final long newShift = lastY2 - cachedY2;
180: if (newShift > shiftOffset) {
181: shiftOffset = newShift;
182: shiftNode = replacement.getInstanceId();
183: }
184: return (box.getLastChild() != replacement);
185: }
186:
187: private boolean isBreakAfter(final RenderNode node) {
188: if (node.isBreakAfter()) {
189: return true;
190: }
191:
192: if (node instanceof BlockRenderBox) {
193: final RenderBox box = (RenderBox) node;
194: final RenderNode lastChild = box.getLastChild();
195: if (lastChild != null) {
196: return isBreakAfter(lastChild);
197: }
198: }
199: return false;
200: }
201:
202: }
|