You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

ActiveCell.java 23KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599
  1. /*
  2. * Licensed to the Apache Software Foundation (ASF) under one or more
  3. * contributor license agreements. See the NOTICE file distributed with
  4. * this work for additional information regarding copyright ownership.
  5. * The ASF licenses this file to You under the Apache License, Version 2.0
  6. * (the "License"); you may not use this file except in compliance with
  7. * the License. You may obtain a copy of the License at
  8. *
  9. * http://www.apache.org/licenses/LICENSE-2.0
  10. *
  11. * Unless required by applicable law or agreed to in writing, software
  12. * distributed under the License is distributed on an "AS IS" BASIS,
  13. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14. * See the License for the specific language governing permissions and
  15. * limitations under the License.
  16. */
  17. /* $Id$ */
  18. package org.apache.fop.layoutmgr.table;
  19. import java.util.ArrayList;
  20. import java.util.LinkedList;
  21. import java.util.List;
  22. import java.util.ListIterator;
  23. import org.apache.commons.logging.Log;
  24. import org.apache.commons.logging.LogFactory;
  25. import org.apache.fop.fo.Constants;
  26. import org.apache.fop.fo.flow.table.ConditionalBorder;
  27. import org.apache.fop.fo.flow.table.EffRow;
  28. import org.apache.fop.fo.flow.table.PrimaryGridUnit;
  29. import org.apache.fop.fo.properties.CommonBorderPaddingBackground;
  30. import org.apache.fop.layoutmgr.ElementListUtils;
  31. import org.apache.fop.layoutmgr.Keep;
  32. import org.apache.fop.layoutmgr.KnuthBlockBox;
  33. import org.apache.fop.layoutmgr.KnuthBox;
  34. import org.apache.fop.layoutmgr.KnuthElement;
  35. import org.apache.fop.layoutmgr.KnuthPenalty;
  36. import org.apache.fop.traits.MinOptMax;
  37. /**
  38. * A cell playing in the construction of steps for a row-group.
  39. */
  40. class ActiveCell {
  41. private static Log log = LogFactory.getLog(ActiveCell.class);
  42. private PrimaryGridUnit pgu;
  43. /** Knuth elements for this active cell. */
  44. private List elementList;
  45. /** Iterator over the Knuth element list. */
  46. private ListIterator knuthIter;
  47. /** Number of the row where the row-span ends, zero-based. */
  48. private int endRowIndex;
  49. /** Length of the Knuth elements not yet included in the steps. */
  50. private int remainingLength;
  51. /** Total length of this cell's content plus the lengths of the previous rows. */
  52. private int totalLength;
  53. /** Length of the Knuth elements already included in the steps. */
  54. private int includedLength;
  55. private int paddingBeforeNormal;
  56. private int paddingBeforeLeading;
  57. private int paddingAfterNormal;
  58. private int paddingAfterTrailing;
  59. private int bpBeforeNormal;
  60. private int bpBeforeLeading;
  61. private int bpAfterNormal;
  62. private int bpAfterTrailing;
  63. /** True if the next CellPart that will be created will be the last one for this cell. */
  64. private boolean lastCellPart;
  65. private Keep keepWithNext;
  66. private int spanIndex;
  67. private Step previousStep;
  68. private Step nextStep;
  69. /**
  70. * The step following nextStep. Computing it early allows to calculate
  71. * {@link Step#condBeforeContentLength}, thus to easily determine the remaining
  72. * length. That also helps for {@link #increaseCurrentStep(int)}.
  73. */
  74. private Step afterNextStep;
  75. /**
  76. * Auxiliary class to store all the informations related to a breaking step.
  77. */
  78. private static class Step {
  79. /** Index, in the list of Knuth elements, of the element starting this step. */
  80. private int start;
  81. /** Index, in the list of Knuth elements, of the element ending this step. */
  82. private int end;
  83. /** Length of the Knuth elements up to this step. */
  84. private int contentLength;
  85. /** Total length up to this step, including paddings and borders. */
  86. private int totalLength;
  87. /** Length of the penalty ending this step, if any. */
  88. private int penaltyLength;
  89. /** Value of the penalty ending this step, 0 if the step does not end on a penalty. */
  90. private int penaltyValue;
  91. /** List of footnotes for this step. */
  92. private List footnoteList;
  93. /**
  94. * One of {@link Constants#EN_AUTO}, {@link Constants#EN_COLUMN},
  95. * {@link Constants#EN_PAGE}, {@link Constants#EN_EVEN_PAGE},
  96. * {@link Constants#EN_ODD_PAGE}. Set to auto if the break isn't at a penalty
  97. * element.
  98. */
  99. private int breakClass;
  100. /**
  101. * Length of the optional content at the beginning of the step. That is, content
  102. * that will not appear if this step starts a new page.
  103. */
  104. private int condBeforeContentLength;
  105. Step(int contentLength) {
  106. this.contentLength = contentLength;
  107. this.end = -1;
  108. }
  109. Step(Step other) {
  110. set(other);
  111. }
  112. void set(Step other) {
  113. this.start = other.start;
  114. this.end = other.end;
  115. this.contentLength = other.contentLength;
  116. this.totalLength = other.totalLength;
  117. this.penaltyLength = other.penaltyLength;
  118. this.penaltyValue = other.penaltyValue;
  119. if (other.footnoteList != null) {
  120. if (this.footnoteList == null) {
  121. this.footnoteList = new ArrayList();
  122. }
  123. this.footnoteList.addAll(other.footnoteList);
  124. }
  125. this.condBeforeContentLength = other.condBeforeContentLength;
  126. this.breakClass = other.breakClass;
  127. }
  128. /** {@inheritDoc} */
  129. public String toString() {
  130. return "Step: start=" + start + " end=" + end + " length=" + totalLength;
  131. }
  132. }
  133. // TODO to be removed along with the RowPainter#computeContentLength method
  134. /** See {@link ActiveCell#handleExplicitHeight(MinOptMax, MinOptMax)}. */
  135. private static class FillerPenalty extends KnuthPenalty {
  136. private int contentLength;
  137. FillerPenalty(KnuthPenalty p, int length) {
  138. super(length, p.getPenalty(), p.isPenaltyFlagged(), p.getBreakClass(),
  139. p.getPosition(), p.isAuxiliary());
  140. contentLength = p.getWidth();
  141. }
  142. FillerPenalty(int length) {
  143. super(length, 0, false, null, true);
  144. contentLength = 0;
  145. }
  146. }
  147. /** See {@link ActiveCell#handleExplicitHeight(MinOptMax, MinOptMax)}. */
  148. private static class FillerBox extends KnuthBox {
  149. FillerBox(int length) {
  150. super(length, null, true);
  151. }
  152. }
  153. /**
  154. * Returns the actual length of the content represented by the given element. In the
  155. * case where this element is used as a filler to match a row's fixed height, the
  156. * value returned by the getW() method will be higher than the actual content.
  157. *
  158. * @param el an element
  159. * @return the actual content length corresponding to the element
  160. */
  161. static int getElementContentLength(KnuthElement el) {
  162. if (el instanceof FillerPenalty) {
  163. return ((FillerPenalty) el).contentLength;
  164. } else if (el instanceof FillerBox) {
  165. return 0;
  166. } else {
  167. return el.getWidth();
  168. }
  169. }
  170. ActiveCell(PrimaryGridUnit pgu, EffRow row, int rowIndex, int previousRowsLength,
  171. TableLayoutManager tableLM) {
  172. this.pgu = pgu;
  173. CommonBorderPaddingBackground bordersPaddings = pgu.getCell()
  174. .getCommonBorderPaddingBackground();
  175. TableCellLayoutManager cellLM = pgu.getCellLM();
  176. paddingBeforeNormal = bordersPaddings.getPaddingBefore(false, cellLM);
  177. paddingBeforeLeading = bordersPaddings.getPaddingBefore(true, cellLM);
  178. paddingAfterNormal = bordersPaddings.getPaddingAfter(false, cellLM);
  179. paddingAfterTrailing = bordersPaddings.getPaddingAfter(true, cellLM);
  180. bpBeforeNormal = paddingBeforeNormal
  181. + pgu.getBeforeBorderWidth(0, ConditionalBorder.NORMAL);
  182. bpBeforeLeading = paddingBeforeLeading
  183. + pgu.getBeforeBorderWidth(0, ConditionalBorder.REST);
  184. bpAfterNormal = paddingAfterNormal + pgu.getAfterBorderWidth(ConditionalBorder.NORMAL);
  185. bpAfterTrailing = paddingAfterTrailing + pgu.getAfterBorderWidth(0, ConditionalBorder.REST);
  186. elementList = pgu.getElements();
  187. handleExplicitHeight(pgu.getCell().getBlockProgressionDimension().toMinOptMax(tableLM),
  188. row.getExplicitHeight());
  189. knuthIter = elementList.listIterator();
  190. includedLength = -1; // Avoid troubles with cells having content of zero length
  191. totalLength = previousRowsLength + ElementListUtils.calcContentLength(elementList);
  192. endRowIndex = rowIndex + pgu.getCell().getNumberRowsSpanned() - 1;
  193. keepWithNext = Keep.KEEP_AUTO;
  194. remainingLength = totalLength - previousRowsLength;
  195. afterNextStep = new Step(previousRowsLength);
  196. previousStep = new Step(afterNextStep);
  197. gotoNextLegalBreak();
  198. nextStep = new Step(afterNextStep);
  199. if (afterNextStep.end < elementList.size() - 1) {
  200. gotoNextLegalBreak();
  201. }
  202. }
  203. /**
  204. * Modifies the cell's element list by putting filler elements, so that the cell's or
  205. * row's explicit height is always reached.
  206. *
  207. * TODO this will work properly only for the first break. Then the limitation
  208. * explained on http://wiki.apache.org/xmlgraphics-fop/TableLayout/KnownProblems
  209. * occurs. The list of elements needs to be re-adjusted after each break.
  210. */
  211. private void handleExplicitHeight(MinOptMax cellBPD, MinOptMax rowBPD) {
  212. int minBPD = Math.max(cellBPD.getMin(), rowBPD.getMin());
  213. if (minBPD > 0) {
  214. ListIterator iter = elementList.listIterator();
  215. int cumulateLength = 0;
  216. boolean prevIsBox = false;
  217. while (iter.hasNext() && cumulateLength < minBPD) {
  218. KnuthElement el = (KnuthElement) iter.next();
  219. if (el.isBox()) {
  220. prevIsBox = true;
  221. cumulateLength += el.getWidth();
  222. } else if (el.isGlue()) {
  223. if (prevIsBox) {
  224. elementList.add(iter.nextIndex() - 1,
  225. new FillerPenalty(minBPD - cumulateLength));
  226. }
  227. prevIsBox = false;
  228. cumulateLength += el.getWidth();
  229. } else {
  230. prevIsBox = false;
  231. if (cumulateLength + el.getWidth() < minBPD) {
  232. iter.set(new FillerPenalty((KnuthPenalty) el, minBPD - cumulateLength));
  233. }
  234. }
  235. }
  236. }
  237. int optBPD = Math.max(minBPD, Math.max(cellBPD.getOpt(), rowBPD.getOpt()));
  238. if (pgu.getContentLength() < optBPD) {
  239. elementList.add(new FillerBox(optBPD - pgu.getContentLength()));
  240. }
  241. }
  242. PrimaryGridUnit getPrimaryGridUnit() {
  243. return pgu;
  244. }
  245. /**
  246. * Returns true if this cell ends on the given row.
  247. *
  248. * @param rowIndex index of a row in the row-group, zero-based
  249. * @return true if this cell ends on the given row
  250. */
  251. boolean endsOnRow(int rowIndex) {
  252. return rowIndex == endRowIndex;
  253. }
  254. /**
  255. * Returns the length of this cell's content not yet included in the steps, plus the
  256. * cell's borders and paddings if applicable.
  257. *
  258. * @return the remaining length, zero if the cell is finished
  259. */
  260. int getRemainingLength() {
  261. if (includedInLastStep() && (nextStep.end == elementList.size() - 1)) {
  262. // The cell is finished
  263. return 0;
  264. } else {
  265. return bpBeforeLeading + remainingLength + bpAfterNormal;
  266. }
  267. }
  268. private void gotoNextLegalBreak() {
  269. afterNextStep.penaltyLength = 0;
  270. afterNextStep.penaltyValue = 0;
  271. afterNextStep.condBeforeContentLength = 0;
  272. afterNextStep.breakClass = Constants.EN_AUTO;
  273. if (afterNextStep.footnoteList != null) {
  274. afterNextStep.footnoteList.clear();
  275. }
  276. boolean breakFound = false;
  277. boolean prevIsBox = false;
  278. boolean boxFound = false;
  279. while (!breakFound && knuthIter.hasNext()) {
  280. KnuthElement el = (KnuthElement) knuthIter.next();
  281. if (el.isPenalty()) {
  282. prevIsBox = false;
  283. if (el.getPenalty() < KnuthElement.INFINITE
  284. || ((KnuthPenalty) el).getBreakClass() == Constants.EN_PAGE) {
  285. // TODO too much is being done in that test, only to handle
  286. // keep.within-column properly.
  287. // First legal break point
  288. breakFound = true;
  289. KnuthPenalty p = (KnuthPenalty) el;
  290. afterNextStep.penaltyLength = p.getWidth();
  291. afterNextStep.penaltyValue = p.getPenalty();
  292. if (p.isForcedBreak()) {
  293. afterNextStep.breakClass = p.getBreakClass();
  294. }
  295. }
  296. } else if (el.isGlue()) {
  297. if (prevIsBox) {
  298. // Second legal break point
  299. breakFound = true;
  300. } else {
  301. afterNextStep.contentLength += el.getWidth();
  302. if (!boxFound) {
  303. afterNextStep.condBeforeContentLength += el.getWidth();
  304. }
  305. }
  306. prevIsBox = false;
  307. } else {
  308. if (el instanceof KnuthBlockBox && ((KnuthBlockBox) el).hasAnchors()) {
  309. if (afterNextStep.footnoteList == null) {
  310. afterNextStep.footnoteList = new LinkedList();
  311. }
  312. afterNextStep.footnoteList.addAll(((KnuthBlockBox) el).getFootnoteBodyLMs());
  313. }
  314. prevIsBox = true;
  315. boxFound = true;
  316. afterNextStep.contentLength += el.getWidth();
  317. }
  318. }
  319. afterNextStep.end = knuthIter.nextIndex() - 1;
  320. afterNextStep.totalLength = bpBeforeNormal
  321. + afterNextStep.contentLength + afterNextStep.penaltyLength
  322. + bpAfterTrailing;
  323. }
  324. /**
  325. * Returns the minimal step that is needed for this cell to contribute some content.
  326. *
  327. * @return the step for this cell's first legal break
  328. */
  329. int getFirstStep() {
  330. log.debug(this + ": min first step = " + nextStep.totalLength);
  331. return nextStep.totalLength;
  332. }
  333. /**
  334. * Returns the last step for this cell. This includes the normal border- and
  335. * padding-before, the whole content, the normal padding-after, and the
  336. * <em>trailing</em> after border. Indeed, if the normal border is taken instead,
  337. * and appears to be smaller than the trailing one, the last step may be smaller than
  338. * the current step (see TableStepper#considerRowLastStep). This will produce a wrong
  339. * infinite penalty, plus the cell's content won't be taken into account since the
  340. * final step will be smaller than the current one (see {@link #signalNextStep(int)}).
  341. * This actually means that the content will be swallowed.
  342. *
  343. * @return the length of last step
  344. */
  345. int getLastStep() {
  346. assert nextStep.end == elementList.size() - 1;
  347. assert nextStep.contentLength == totalLength && nextStep.penaltyLength == 0;
  348. int lastStep = bpBeforeNormal + totalLength + paddingAfterNormal
  349. + pgu.getAfterBorderWidth(ConditionalBorder.LEADING_TRAILING);
  350. log.debug(this + ": last step = " + lastStep);
  351. return lastStep;
  352. }
  353. /**
  354. * Increases the next step up to the given limit.
  355. *
  356. * @param limit the length up to which the next step is allowed to increase
  357. * @see #signalRowFirstStep(int)
  358. * @see #signalRowLastStep(int)
  359. */
  360. private void increaseCurrentStep(int limit) {
  361. if (nextStep.end < elementList.size() - 1) {
  362. while (afterNextStep.totalLength <= limit && nextStep.breakClass == Constants.EN_AUTO) {
  363. int condBeforeContentLength = nextStep.condBeforeContentLength;
  364. nextStep.set(afterNextStep);
  365. nextStep.condBeforeContentLength = condBeforeContentLength;
  366. if (afterNextStep.end >= elementList.size() - 1) {
  367. break;
  368. }
  369. gotoNextLegalBreak();
  370. }
  371. }
  372. }
  373. /**
  374. * Gets the selected first step for the current row. If this cell's first step is
  375. * smaller, then it may be able to add some more of its content, since there will be
  376. * no break before the given step anyway.
  377. *
  378. * @param firstStep the current row's first step
  379. */
  380. void signalRowFirstStep(int firstStep) {
  381. increaseCurrentStep(firstStep);
  382. if (log.isTraceEnabled()) {
  383. log.trace(this + ": first step increased to " + nextStep.totalLength);
  384. }
  385. }
  386. /** See {@link #signalRowFirstStep(int)}. */
  387. void signalRowLastStep(int lastStep) {
  388. increaseCurrentStep(lastStep);
  389. if (log.isTraceEnabled()) {
  390. log.trace(this + ": next step increased to " + nextStep.totalLength);
  391. }
  392. }
  393. /**
  394. * Returns the total length up to the next legal break, not yet included in the steps.
  395. *
  396. * @return the total length up to the next legal break (-1 signals no further step)
  397. */
  398. int getNextStep() {
  399. if (includedInLastStep()) {
  400. previousStep.set(nextStep);
  401. if (nextStep.end >= elementList.size() - 1) {
  402. nextStep.start = elementList.size();
  403. return -1;
  404. } else {
  405. nextStep.set(afterNextStep);
  406. nextStep.start = previousStep.end + 1;
  407. afterNextStep.start = nextStep.start;
  408. if (afterNextStep.end < elementList.size() - 1) {
  409. gotoNextLegalBreak();
  410. }
  411. }
  412. }
  413. return nextStep.totalLength;
  414. }
  415. private boolean includedInLastStep() {
  416. return includedLength == nextStep.contentLength;
  417. }
  418. /**
  419. * Signals the length of the chosen next step, so that this cell determines whether
  420. * its own step may be included or not.
  421. *
  422. * @param minStep length of the chosen next step
  423. * @return the break class of the step, if any. One of {@link Constants#EN_AUTO},
  424. * {@link Constants#EN_COLUMN}, {@link Constants#EN_PAGE},
  425. * {@link Constants#EN_EVEN_PAGE}, {@link Constants#EN_ODD_PAGE}. EN_AUTO if this
  426. * cell's step is not included in the next step.
  427. */
  428. int signalNextStep(int minStep) {
  429. if (nextStep.totalLength <= minStep) {
  430. includedLength = nextStep.contentLength;
  431. remainingLength = totalLength - includedLength - afterNextStep.condBeforeContentLength;
  432. return nextStep.breakClass;
  433. } else {
  434. return Constants.EN_AUTO;
  435. }
  436. }
  437. /**
  438. * Receives indication that the next row is about to start, and that (collapse)
  439. * borders must be updated accordingly.
  440. */
  441. void nextRowStarts() {
  442. spanIndex++;
  443. // Subtract the old value of bpAfterTrailing...
  444. nextStep.totalLength -= bpAfterTrailing;
  445. afterNextStep.totalLength -= bpAfterTrailing;
  446. bpAfterTrailing = paddingAfterTrailing
  447. + pgu.getAfterBorderWidth(spanIndex, ConditionalBorder.REST);
  448. // ... and add the new one
  449. nextStep.totalLength += bpAfterTrailing;
  450. afterNextStep.totalLength += bpAfterTrailing;
  451. // TODO if the new after border is greater than the previous one the next step may
  452. // increase further than the row's first step, which can lead to wrong output in
  453. // some cases
  454. }
  455. /**
  456. * Receives indication that the current row is ending, and that (collapse) borders
  457. * must be updated accordingly.
  458. *
  459. * @param rowIndex the index of the ending row
  460. */
  461. void endRow(int rowIndex) {
  462. if (endsOnRow(rowIndex)) {
  463. // Subtract the old value of bpAfterTrailing...
  464. nextStep.totalLength -= bpAfterTrailing;
  465. bpAfterTrailing = paddingAfterNormal
  466. + pgu.getAfterBorderWidth(ConditionalBorder.LEADING_TRAILING);
  467. // ... and add the new one
  468. nextStep.totalLength += bpAfterTrailing;
  469. lastCellPart = true;
  470. } else {
  471. bpBeforeLeading = paddingBeforeLeading
  472. + pgu.getBeforeBorderWidth(spanIndex + 1, ConditionalBorder.REST);
  473. }
  474. }
  475. /**
  476. * Returns true if this cell would be finished after the given step. That is, it would
  477. * be included in the step and the end of its content would be reached.
  478. *
  479. * @param step the next step
  480. * @return true if this cell finishes at the given step
  481. */
  482. boolean finishes(int step) {
  483. return nextStep.totalLength <= step && (nextStep.end == elementList.size() - 1);
  484. }
  485. /**
  486. * Creates and returns a CellPart instance for the content of this cell which
  487. * is included in the next step.
  488. *
  489. * @return a CellPart instance
  490. */
  491. CellPart createCellPart() {
  492. if (nextStep.end + 1 == elementList.size()) {
  493. keepWithNext = pgu.getKeepWithNext();
  494. // TODO if keep-with-next is set on the row, must every cell of the row
  495. // contribute some content from children blocks?
  496. // see http://mail-archives.apache.org/mod_mbox/xmlgraphics-fop-dev/200802.mbox/
  497. // %3c47BDA379.4050606@anyware-tech.com%3e
  498. // Assuming no, but if yes the following code should enable this behaviour
  499. // if (pgu.getRow() != null && pgu.getRow().mustKeepWithNext()) {
  500. // keepWithNextSignal = true; //to be converted to integer strengths
  501. // }
  502. }
  503. int bpBeforeFirst;
  504. if (nextStep.start == 0) {
  505. bpBeforeFirst = pgu.getBeforeBorderWidth(0, ConditionalBorder.LEADING_TRAILING)
  506. + paddingBeforeNormal;
  507. } else {
  508. bpBeforeFirst = bpBeforeLeading;
  509. }
  510. int length = nextStep.contentLength - nextStep.condBeforeContentLength
  511. - previousStep.contentLength;
  512. if (!includedInLastStep() || nextStep.start == elementList.size()) {
  513. return new CellPart(pgu, nextStep.start, previousStep.end, lastCellPart,
  514. 0, 0, previousStep.penaltyLength,
  515. bpBeforeNormal, bpBeforeFirst, bpAfterNormal, bpAfterTrailing);
  516. } else {
  517. return new CellPart(pgu, nextStep.start, nextStep.end, lastCellPart,
  518. nextStep.condBeforeContentLength, length, nextStep.penaltyLength,
  519. bpBeforeNormal, bpBeforeFirst, bpAfterNormal, bpAfterTrailing);
  520. }
  521. }
  522. /**
  523. * Adds the footnotes (if any) that are part of the next step, if this cell
  524. * contributes content to the next step.
  525. *
  526. * @param footnoteList the list to which this cell must add its footnotes
  527. */
  528. void addFootnotes(List footnoteList) {
  529. if (includedInLastStep() && nextStep.footnoteList != null) {
  530. footnoteList.addAll(nextStep.footnoteList);
  531. nextStep.footnoteList.clear();
  532. }
  533. }
  534. Keep getKeepWithNext() {
  535. return keepWithNext;
  536. }
  537. int getPenaltyValue() {
  538. if (includedInLastStep()) {
  539. return nextStep.penaltyValue;
  540. } else {
  541. return previousStep.penaltyValue;
  542. }
  543. }
  544. /** {@inheritDoc} */
  545. public String toString() {
  546. return "Cell " + (pgu.getRowIndex() + 1) + "." + (pgu.getColIndex() + 1);
  547. }
  548. }