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.

GridUnit.java 15KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457
  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.fo.flow.table;
  19. import org.apache.fop.fo.FONode;
  20. import org.apache.fop.fo.properties.CommonBorderPaddingBackground;
  21. import org.apache.fop.fo.properties.CommonBorderPaddingBackground.BorderInfo;
  22. import org.apache.fop.layoutmgr.table.CollapsingBorderModel;
  23. /**
  24. * This class represents one grid unit inside a table.
  25. */
  26. public class GridUnit {
  27. /**
  28. * Indicates that the grid unit is in the first row of the table part (header, footer,
  29. * body).
  30. */
  31. public static final int FIRST_IN_PART = 0;
  32. /**
  33. * Indicates that the grid unit is in the last row of the table part (header, footer,
  34. * body).
  35. */
  36. public static final int LAST_IN_PART = 1;
  37. /** Indicates that the primary grid unit has a pending keep-with-next. */
  38. public static final int KEEP_WITH_NEXT_PENDING = 2;
  39. /** Indicates that the primary grid unit has a pending keep-with-previous. */
  40. public static final int KEEP_WITH_PREVIOUS_PENDING = 3;
  41. /** Primary grid unit */
  42. private PrimaryGridUnit primary;
  43. /** Table cell which occupies this grid unit */
  44. protected TableCell cell;
  45. /** Table row occupied by this grid unit (may be null). */
  46. private TableRow row;
  47. /** index of grid unit within cell in column direction */
  48. private int colSpanIndex;
  49. /** index of grid unit within cell in row direction */
  50. private int rowSpanIndex;
  51. /** flags for the grid unit */
  52. private byte flags = 0;
  53. ConditionalBorder borderBefore;
  54. ConditionalBorder borderAfter;
  55. BorderSpecification borderStart;
  56. BorderSpecification borderEnd;
  57. protected CollapsingBorderModel collapsingBorderModel;
  58. /**
  59. * Creates a new grid unit.
  60. *
  61. * @param table the containing table
  62. * @param colSpanIndex index of this grid unit in the span, in column direction
  63. * @param rowSpanIndex index of this grid unit in the span, in row direction
  64. */
  65. protected GridUnit(Table table, int colSpanIndex, int rowSpanIndex) {
  66. this(colSpanIndex, rowSpanIndex);
  67. setBorders(table);
  68. }
  69. /**
  70. * Creates a new grid unit.
  71. *
  72. * @param cell table cell which occupies this grid unit
  73. * @param colSpanIndex index of this grid unit in the span, in column direction
  74. * @param rowSpanIndex index of this grid unit in the span, in row direction
  75. */
  76. protected GridUnit(TableCell cell, int colSpanIndex, int rowSpanIndex) {
  77. this(colSpanIndex, rowSpanIndex);
  78. this.cell = cell;
  79. setBorders(cell.getTable());
  80. }
  81. /**
  82. * Creates a new grid unit.
  83. *
  84. * @param primary the before-start grid unit of the cell containing this grid unit
  85. * @param colSpanIndex index of this grid unit in the span, in column direction
  86. * @param rowSpanIndex index of this grid unit in the span, in row direction
  87. */
  88. GridUnit(PrimaryGridUnit primary, int colSpanIndex, int rowSpanIndex) {
  89. this(primary.getCell(), colSpanIndex, rowSpanIndex);
  90. this.primary = primary;
  91. }
  92. private GridUnit(int colSpanIndex, int rowSpanIndex) {
  93. this.colSpanIndex = colSpanIndex;
  94. this.rowSpanIndex = rowSpanIndex;
  95. }
  96. private void setBorders(Table table/*TODO*/) {
  97. if (!table.isSeparateBorderModel()) {
  98. collapsingBorderModel = CollapsingBorderModel.getBorderModelFor(table
  99. .getBorderCollapse());
  100. setBordersFromCell();
  101. }
  102. }
  103. /**
  104. * Prepares the borders of this grid unit for upcoming resolution, in the collapsing
  105. * model.
  106. */
  107. protected void setBordersFromCell() {
  108. borderBefore = cell.borderBefore.copy();
  109. if (rowSpanIndex > 0) {
  110. borderBefore.nonLeadingTrailing = BorderSpecification.getDefaultBorder();
  111. }
  112. borderAfter = cell.borderAfter.copy();
  113. if (!isLastGridUnitRowSpan()) {
  114. borderAfter.nonLeadingTrailing = BorderSpecification.getDefaultBorder();
  115. }
  116. if (colSpanIndex == 0) {
  117. borderStart = cell.borderStart;
  118. } else {
  119. borderStart = BorderSpecification.getDefaultBorder();
  120. }
  121. if (isLastGridUnitColSpan()) {
  122. borderEnd = cell.borderEnd;
  123. } else {
  124. borderEnd = BorderSpecification.getDefaultBorder();
  125. }
  126. }
  127. public TableCell getCell() {
  128. return cell;
  129. }
  130. /**
  131. * Returns the fo:table-row element (if any) this grid unit belongs to.
  132. *
  133. * @return the row containing this grid unit, or null if there is no fo:table-row
  134. * element in the corresponding table-part
  135. */
  136. public TableRow getRow() {
  137. return row;
  138. }
  139. void setRow(TableRow row) {
  140. this.row = row;
  141. }
  142. public TableBody getBody() {
  143. FONode node = getCell();
  144. while (node != null && !(node instanceof TableBody)) {
  145. node = node.getParent();
  146. }
  147. return (TableBody) node;
  148. }
  149. /**
  150. * Returns the before-start grid unit of the cell containing this grid unit.
  151. *
  152. * @return the before-start grid unit of the cell containing this grid unit.
  153. */
  154. public PrimaryGridUnit getPrimary() {
  155. return primary;
  156. }
  157. /**
  158. * Is this grid unit the before-start grid unit of the cell?
  159. *
  160. * @return true if this grid unit is the before-start grid unit of the cell
  161. */
  162. public boolean isPrimary() {
  163. return false;
  164. }
  165. /**
  166. * Does this grid unit belong to an empty cell?
  167. *
  168. * @return true if this grid unit belongs to an empty cell
  169. */
  170. public boolean isEmpty() {
  171. return cell == null;
  172. }
  173. /** @return true if the grid unit is the last in column spanning direction */
  174. public boolean isLastGridUnitColSpan() {
  175. return (colSpanIndex == cell.getNumberColumnsSpanned() - 1);
  176. }
  177. /** @return true if the grid unit is the last in row spanning direction */
  178. public boolean isLastGridUnitRowSpan() {
  179. return (rowSpanIndex == cell.getNumberRowsSpanned() - 1);
  180. }
  181. /**
  182. * @return the index of the grid unit inside a cell in row direction
  183. */
  184. public int getRowSpanIndex() {
  185. return rowSpanIndex;
  186. }
  187. /**
  188. * @return the index of the grid unit inside a cell in column direction
  189. */
  190. public int getColSpanIndex() {
  191. return colSpanIndex;
  192. }
  193. /**
  194. * Returns the resolved border-before of this grid unit, in the collapsing-border
  195. * model.
  196. *
  197. * @param which one of {@link ConditionalBorder#NORMAL},
  198. * {@link ConditionalBorder#LEADING_TRAILING} or {@link ConditionalBorder#REST}
  199. * @return the corresponding border
  200. */
  201. public BorderInfo getBorderBefore(int which) {
  202. switch (which) {
  203. case ConditionalBorder.NORMAL:
  204. return borderBefore.nonLeadingTrailing.getBorderInfo();
  205. case ConditionalBorder.LEADING_TRAILING:
  206. return borderBefore.leadingTrailing.getBorderInfo();
  207. case ConditionalBorder.REST:
  208. return borderBefore.rest.getBorderInfo();
  209. default:
  210. assert false;
  211. return null;
  212. }
  213. }
  214. /**
  215. * Returns the resolved border-after of this grid unit, in the collapsing-border
  216. * model.
  217. *
  218. * @param which one of {@link ConditionalBorder#NORMAL},
  219. * {@link ConditionalBorder#LEADING_TRAILING} or {@link ConditionalBorder#REST}
  220. * @return the corresponding border
  221. */
  222. public BorderInfo getBorderAfter(int which) {
  223. switch (which) {
  224. case ConditionalBorder.NORMAL:
  225. return borderAfter.nonLeadingTrailing.getBorderInfo();
  226. case ConditionalBorder.LEADING_TRAILING:
  227. return borderAfter.leadingTrailing.getBorderInfo();
  228. case ConditionalBorder.REST:
  229. return borderAfter.rest.getBorderInfo();
  230. default:
  231. assert false;
  232. return null;
  233. }
  234. }
  235. /**
  236. * Returns the resolved border-start of this grid unit, in the collapsing-border
  237. * model.
  238. *
  239. * @return the corresponding border
  240. */
  241. public BorderInfo getBorderStart() {
  242. return borderStart.getBorderInfo();
  243. }
  244. /**
  245. * Returns the resolved border-end of this grid unit, in the collapsing-border
  246. * model.
  247. *
  248. * @return the corresponding border
  249. */
  250. public BorderInfo getBorderEnd() {
  251. return borderEnd.getBorderInfo();
  252. }
  253. /**
  254. * Resolve collapsing borders for the given cell. Used in case of the collapsing
  255. * border model.
  256. *
  257. * @param other neighbouring grid unit
  258. * @param side the side to resolve (one of
  259. * CommonBorderPaddingBackground.BEFORE|AFTER|START|END)
  260. */
  261. void resolveBorder(GridUnit other, int side) {
  262. switch (side) {
  263. case CommonBorderPaddingBackground.BEFORE:
  264. borderBefore.resolve(other.borderAfter, false, true, false);
  265. break;
  266. case CommonBorderPaddingBackground.AFTER:
  267. borderAfter.resolve(other.borderBefore, false, true, false);
  268. break;
  269. case CommonBorderPaddingBackground.START:
  270. BorderSpecification resolvedBorder = collapsingBorderModel.determineWinner(
  271. borderStart, other.borderEnd);
  272. if (resolvedBorder != null) {
  273. this.borderStart = resolvedBorder;
  274. other.borderEnd = resolvedBorder;
  275. }
  276. break;
  277. case CommonBorderPaddingBackground.END:
  278. resolvedBorder = collapsingBorderModel.determineWinner(
  279. borderEnd, other.borderStart);
  280. if (resolvedBorder != null) {
  281. this.borderEnd = resolvedBorder;
  282. other.borderStart = resolvedBorder;
  283. }
  284. break;
  285. default: assert false;
  286. }
  287. }
  288. /**
  289. * For the given side, integrates in the conflict resolution the border segment of the
  290. * given parent element.
  291. *
  292. * @param side the side to consider (either CommonBorderPaddingBackground.BEFORE or
  293. * AFTER)
  294. * @param parent a table element whose corresponding border coincides on the given
  295. * side
  296. */
  297. void integrateBorderSegment(int side, TableFObj parent, boolean withLeadingTrailing,
  298. boolean withNonLeadingTrailing, boolean withRest) {
  299. switch (side) {
  300. case CommonBorderPaddingBackground.BEFORE:
  301. borderBefore.integrateSegment(parent.borderBefore, withLeadingTrailing,
  302. withNonLeadingTrailing, withRest);
  303. break;
  304. case CommonBorderPaddingBackground.AFTER:
  305. borderAfter.integrateSegment(parent.borderAfter, withLeadingTrailing,
  306. withNonLeadingTrailing, withRest);
  307. break;
  308. default: assert false;
  309. }
  310. }
  311. /**
  312. * For the given side, integrates in the conflict resolution the border segment of the
  313. * given parent element.
  314. *
  315. * @param side the side to consider (one of
  316. * CommonBorderPaddingBackground.BEFORE|AFTER|START|END)
  317. * @param parent a table element whose corresponding border coincides on the given side
  318. */
  319. void integrateBorderSegment(int side, TableFObj parent) {
  320. switch (side) {
  321. case CommonBorderPaddingBackground.BEFORE:
  322. case CommonBorderPaddingBackground.AFTER:
  323. integrateBorderSegment(side, parent, true, true, true);
  324. break;
  325. case CommonBorderPaddingBackground.START:
  326. borderStart = collapsingBorderModel.determineWinner(borderStart,
  327. parent.borderStart);
  328. break;
  329. case CommonBorderPaddingBackground.END:
  330. borderEnd = collapsingBorderModel.determineWinner(borderEnd,
  331. parent.borderEnd);
  332. break;
  333. default: assert false;
  334. }
  335. }
  336. void integrateCompetingBorder(int side, ConditionalBorder competitor,
  337. boolean withLeadingTrailing, boolean withNonLeadingTrailing, boolean withRest) {
  338. switch (side) {
  339. case CommonBorderPaddingBackground.BEFORE:
  340. borderBefore.integrateCompetingSegment(competitor, withLeadingTrailing,
  341. withNonLeadingTrailing, withRest);
  342. break;
  343. case CommonBorderPaddingBackground.AFTER:
  344. borderAfter.integrateCompetingSegment(competitor, withLeadingTrailing,
  345. withNonLeadingTrailing, withRest);
  346. break;
  347. default: assert false;
  348. }
  349. }
  350. /**
  351. * Returns a flag for this GridUnit.
  352. *
  353. * @param which the requested flag
  354. * @return the value of the flag
  355. */
  356. public boolean getFlag(int which) {
  357. return (flags & (1 << which)) != 0;
  358. }
  359. /**
  360. * Sets a flag on a GridUnit.
  361. *
  362. * @param which the flag to set
  363. * @param value the new value for the flag
  364. */
  365. public void setFlag(int which, boolean value) {
  366. if (value) {
  367. flags |= (1 << which); // set flag
  368. } else {
  369. flags &= ~(1 << which); // clear flag
  370. }
  371. }
  372. /**
  373. * Sets the given flag on this grid unit.
  374. *
  375. * @param which the flag to set
  376. */
  377. public void setFlag(int which) {
  378. setFlag(which, true);
  379. }
  380. /** {@inheritDoc} */
  381. public String toString() {
  382. StringBuffer buffer = new StringBuffer();
  383. if (isEmpty()) {
  384. buffer.append("EMPTY");
  385. } else if (isPrimary()) {
  386. buffer.append("Primary");
  387. }
  388. buffer.append("GridUnit:");
  389. if (colSpanIndex > 0) {
  390. buffer.append(" colSpan=").append(colSpanIndex);
  391. if (isLastGridUnitColSpan()) {
  392. buffer.append("(last)");
  393. }
  394. }
  395. if (rowSpanIndex > 0) {
  396. buffer.append(" rowSpan=").append(rowSpanIndex);
  397. if (isLastGridUnitRowSpan()) {
  398. buffer.append("(last)");
  399. }
  400. }
  401. if (!isPrimary() && getPrimary() != null) {
  402. buffer.append(" primary=").append(getPrimary().getRowIndex());
  403. buffer.append("/").append(getPrimary().getColIndex());
  404. if (getPrimary().getCell() != null) {
  405. buffer.append(" id=" + getPrimary().getCell().getId());
  406. }
  407. }
  408. buffer.append(" flags=").append(Integer.toBinaryString(flags));
  409. return buffer.toString();
  410. }
  411. }