001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: */
017:
018: /* $Id: ActiveCell.java 555686 2007-07-12 16:28:22Z vhennebert $ */
019:
020: package org.apache.fop.layoutmgr.table;
021:
022: import java.util.List;
023:
024: import org.apache.fop.layoutmgr.ElementListUtils;
025: import org.apache.fop.layoutmgr.KnuthBox;
026: import org.apache.fop.layoutmgr.KnuthElement;
027: import org.apache.fop.layoutmgr.KnuthPenalty;
028:
029: class ActiveCell {
030: private PrimaryGridUnit pgu;
031: /** Knuth elements for this active cell. */
032: private List elementList;
033: private boolean prevIsBox = false;
034: /** Number of the row where the row-span begins, zero-based. */
035: private int startRow;
036: /** Index, in the list of Knuth elements, of the element starting the current step. */
037: private int start;
038: /** Index, in the list of Knuth elements, of the element ending the current step. */
039: private int end;
040: /**
041: * Total length of the Knuth elements already included in the steps, up to the
042: * current one.
043: */
044: private int width;
045: private int remainingLength;
046: private int baseWidth;
047: private int totalLength;
048: private int includedLength;
049: private int borderBefore;
050: private int borderAfter;
051: private int paddingBefore;
052: private int paddingAfter;
053: private boolean keepWithNextSignal;
054: private int lastPenaltyLength;
055:
056: ActiveCell(PrimaryGridUnit pgu, EffRow row, int rowIndex,
057: EffRow[] rowGroup, TableLayoutManager tableLM) {
058: this .pgu = pgu;
059: boolean makeBoxForWholeRow = false;
060: if (row.getExplicitHeight().min > 0) {
061: boolean contentsSmaller = ElementListUtils
062: .removeLegalBreaks(pgu.getElements(), row
063: .getExplicitHeight());
064: if (contentsSmaller) {
065: makeBoxForWholeRow = true;
066: }
067: }
068: if (pgu.isLastGridUnitRowSpan() && pgu.getRow() != null) {
069: makeBoxForWholeRow |= pgu.getRow().mustKeepTogether();
070: makeBoxForWholeRow |= pgu.getTable().mustKeepTogether();
071: }
072: if (makeBoxForWholeRow) {
073: elementList = new java.util.ArrayList(1);
074: int height = row.getExplicitHeight().opt;
075: if (height == 0) {
076: height = row.getHeight().opt;
077: }
078: elementList.add(new KnuthBoxCellWithBPD(height));
079: } else {
080: elementList = pgu.getElements();
081: // if (log.isTraceEnabled()) {
082: // log.trace("column " + (column+1) + ": recording " + elementLists.size() + " element(s)");
083: // }
084: }
085: totalLength = ElementListUtils.calcContentLength(elementList);
086: if (pgu.getTable().isSeparateBorderModel()) {
087: borderBefore = pgu.getBorders().getBorderBeforeWidth(false)
088: + tableLM.getHalfBorderSeparationBPD();
089: borderAfter = pgu.getBorders().getBorderAfterWidth(false)
090: + tableLM.getHalfBorderSeparationBPD();
091: } else {
092: borderBefore = pgu.getHalfMaxBeforeBorderWidth();
093: borderAfter = pgu.getHalfMaxAfterBorderWidth();
094: }
095: paddingBefore = pgu.getBorders().getPaddingBefore(false,
096: pgu.getCellLM());
097: paddingAfter = pgu.getBorders().getPaddingAfter(false,
098: pgu.getCellLM());
099: start = 0;
100: end = -1;
101: startRow = rowIndex;
102: keepWithNextSignal = false;
103: computeBaseWidth(rowGroup);
104: remainingLength = totalLength;
105: goToNextLegalBreak();
106: }
107:
108: private void computeBaseWidth(EffRow[] rowGroup) {
109: width = 0;
110: includedLength = -1; // Avoid troubles with cells having content of zero length
111: for (int prevRow = 0; prevRow < startRow; prevRow++) {
112: width += rowGroup[prevRow].getHeight().opt;
113: }
114: baseWidth = width;
115: }
116:
117: boolean endsOnRow(int rowIndex) {
118: return rowIndex == startRow
119: + pgu.getCell().getNumberRowsSpanned() - 1;
120: }
121:
122: int getRemainingHeight(int activeRowIndex, EffRow[] rowGroup) {
123: if (!endsOnRow(activeRowIndex)) {
124: return 0;
125: } else if (includedLength == totalLength) {
126: return 0;
127: } else {
128: return remainingLength + borderBefore + borderAfter
129: + paddingBefore + paddingAfter;
130: }
131: }
132:
133: private void goToNextLegalBreak() {
134: lastPenaltyLength = 0;
135: boolean breakFound = false;
136: while (!breakFound && end + 1 < elementList.size()) {
137: end++;
138: KnuthElement el = (KnuthElement) elementList.get(end);
139: if (el.isPenalty()) {
140: prevIsBox = false;
141: if (el.getP() < KnuthElement.INFINITE) {
142: //First legal break point
143: lastPenaltyLength = el.getW();
144: breakFound = true;
145: }
146: } else if (el.isGlue()) {
147: if (prevIsBox) {
148: //Second legal break point
149: breakFound = true;
150: } else {
151: width += el.getW();
152: }
153: prevIsBox = false;
154: } else {
155: prevIsBox = true;
156: width += el.getW();
157: }
158: }
159: }
160:
161: int getNextStep() {
162: if (!includedInLastStep()) {
163: return width + lastPenaltyLength + borderBefore
164: + borderAfter + paddingBefore + paddingAfter;
165: } else {
166: start = end + 1;
167: if (end < elementList.size() - 1) {
168:
169: goToNextLegalBreak();
170: return width + lastPenaltyLength + borderBefore
171: + borderAfter + paddingBefore + paddingAfter;
172: } else {
173: return 0;
174: }
175: }
176: }
177:
178: private boolean includedInLastStep() {
179: return includedLength == width;
180: }
181:
182: boolean signalMinStep(int minStep) {
183: if (width + lastPenaltyLength + borderBefore + borderAfter
184: + paddingBefore + paddingAfter <= minStep) {
185: includedLength = width;
186: computeRemainingLength();
187: return false;
188: } else {
189: return baseWidth + borderBefore + borderAfter
190: + paddingBefore + paddingAfter > minStep;
191: }
192: }
193:
194: private void computeRemainingLength() {
195: remainingLength = totalLength - width;
196: int index = end + 1;
197: while (index < elementList.size()) {
198: KnuthElement el = (KnuthElement) elementList.get(index);
199: if (el.isBox()) {
200: break;
201: } else if (el.isGlue()) {
202: remainingLength -= el.getW();
203: }
204: index++;
205: }
206: }
207:
208: boolean contributesContent() {
209: return includedInLastStep() && end >= start;
210: }
211:
212: boolean hasStarted() {
213: return includedLength > 0;
214: }
215:
216: boolean isFinished() {
217: return includedInLastStep() && (end == elementList.size() - 1);
218: }
219:
220: GridUnitPart createGridUnitPart() {
221: if (end + 1 == elementList.size()) {
222: if (pgu.getFlag(GridUnit.KEEP_WITH_NEXT_PENDING)) {
223: keepWithNextSignal = true;
224: }
225: if (pgu.getRow() != null && pgu.getRow().mustKeepWithNext()) {
226: keepWithNextSignal = true;
227: }
228: }
229: if (start == 0 && end == 0 && elementList.size() == 1
230: && elementList.get(0) instanceof KnuthBoxCellWithBPD) {
231: //Special case: Cell with fixed BPD
232: return new GridUnitPart(pgu, 0,
233: pgu.getElements().size() - 1);
234: } else {
235: return new GridUnitPart(pgu, start, end);
236: }
237: }
238:
239: boolean isLastForcedBreak() {
240: return ((KnuthElement) elementList.get(end)).isForcedBreak();
241: }
242:
243: int getLastBreakClass() {
244: return ((KnuthPenalty) elementList.get(end)).getBreakClass();
245: }
246:
247: boolean keepWithNextSignal() {
248: return keepWithNextSignal;
249: }
250:
251: /**
252: * Marker class denoting table cells fitting in just one box (no legal break inside).
253: */
254: private static class KnuthBoxCellWithBPD extends KnuthBox {
255:
256: public KnuthBoxCellWithBPD(int w) {
257: super (w, null, true);
258: }
259: }
260: }
|