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.

RtfExtraRowSet.java 12KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324
  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.render.rtf.rtflib.rtfdoc;
  19. /*
  20. * This file is part of the RTF library of the FOP project, which was originally
  21. * created by Bertrand Delacretaz <bdelacretaz@codeconsult.ch> and by other
  22. * contributors to the jfor project (www.jfor.org), who agreed to donate jfor to
  23. * the FOP project.
  24. */
  25. import java.io.IOException;
  26. import java.io.Writer;
  27. import java.util.Collections;
  28. import java.util.LinkedList;
  29. import java.util.List;
  30. /**
  31. * <p>Used to add extra table rows after a row that contains a nested table:</p>
  32. * <ul>
  33. * <li> created by RtfTableRow before generating RTF code
  34. * <li> an RtfTableCell that contains a nested table can ask this to put
  35. * some of its children in extra rows that after the current row
  36. * <li> once RtfTableRow is done rendering its children, it renders this,
  37. * causing extra rows to be generated, with content that can come
  38. * from several RtfTableCells
  39. * </ul>
  40. *
  41. * <p>See org.apache.fop.rtf.rtflib.testdocs.NestedTable for an example of
  42. * usage.</p>
  43. *
  44. * <p>This work was authored by Bertrand Delacretaz (bdelacretaz@codeconsult.ch).</p>
  45. */
  46. public class RtfExtraRowSet extends RtfContainer {
  47. // TODO what is idnum?
  48. static final int DEFAULT_IDNUM = 0;
  49. /** Parent table context
  50. * (added by Boris Poudérous on july 2002 in order to process nested tables)
  51. */
  52. private ITableColumnsInfo parentITableColumnsInfo;
  53. /** While a top-level RtfTableRow is being rendered, we build a list of
  54. * RtfTableCells that must be rendered in extra rows.
  55. * This holds a cell with positioning information
  56. */
  57. private final List cells = new LinkedList();
  58. private static class PositionedCell
  59. implements Comparable {
  60. private final RtfTableCell cell;
  61. private final int xOffset;
  62. private final int rowIndex;
  63. PositionedCell(RtfTableCell c, int index, int offset) {
  64. cell = c;
  65. xOffset = offset;
  66. rowIndex = index;
  67. }
  68. /** debugging dump */
  69. public String toString() {
  70. return "PositionedCell: row " + rowIndex + ", offset " + xOffset;
  71. }
  72. /** cells need to be sorted by row index and then by x offset */
  73. public int compareTo(Object o) {
  74. int result = 0;
  75. if (o == null) {
  76. result = 1;
  77. } else if (!(o instanceof PositionedCell)) {
  78. result = 1;
  79. } else {
  80. final PositionedCell pc = (PositionedCell)o;
  81. if (this.rowIndex < pc.rowIndex) {
  82. result = -1;
  83. } else if (this.rowIndex > pc.rowIndex) {
  84. result = 1;
  85. } else if (this.xOffset < pc.xOffset) {
  86. result = -1;
  87. } else if (this.xOffset > pc.xOffset) {
  88. result = 1;
  89. }
  90. }
  91. return result;
  92. }
  93. public int hashCode() {
  94. int hc = super.hashCode();
  95. hc ^= (hc * 11) + xOffset;
  96. hc ^= (hc * 19) + rowIndex;
  97. return hc;
  98. }
  99. public boolean equals(Object o) {
  100. if (o instanceof PositionedCell) {
  101. PositionedCell pc = (PositionedCell) o;
  102. return (pc.rowIndex == rowIndex) && (pc.xOffset == xOffset);
  103. } else {
  104. return false;
  105. }
  106. }
  107. }
  108. /** our maximum row index */
  109. private int maxRowIndex;
  110. /** an RtfExtraRowSet has no parent, it is only used temporary during
  111. * generation of RTF for an RtfTableRow
  112. */
  113. RtfExtraRowSet(Writer w)
  114. throws IOException {
  115. super(null, w);
  116. }
  117. /** Add all cells of given Table to this set for later rendering in extra rows
  118. * @return index of extra row to use for elements that follow this table in the same cell
  119. * @param rowIndex index of first extra row to create to hold cells of tbl
  120. * @param xOffset horizontal position of left edge of first column of tbl
  121. */
  122. int addTable(RtfTable tbl, int rowIndex, int xOffset) {
  123. // process all rows of the table
  124. for (Object o : tbl.getChildren()) {
  125. final RtfElement e = (RtfElement) o;
  126. if (e instanceof RtfTableRow) {
  127. addRow((RtfTableRow) e, rowIndex, xOffset);
  128. rowIndex++;
  129. maxRowIndex = Math.max(rowIndex, maxRowIndex);
  130. }
  131. }
  132. return rowIndex;
  133. }
  134. /** add all cells of given row to this set */
  135. private void addRow(RtfTableRow row, int rowIndex, int xOffset) {
  136. for (Object o : row.getChildren()) {
  137. final RtfElement e = (RtfElement) o;
  138. if (e instanceof RtfTableCell) {
  139. final RtfTableCell c = (RtfTableCell) e;
  140. cells.add(new PositionedCell(c, rowIndex, xOffset));
  141. xOffset += c.getCellWidth();
  142. }
  143. }
  144. }
  145. /** create an extra cell to hold content that comes after a nested table in a cell
  146. * Modified by Boris Poudérous in order to permit the extra cell to have
  147. * the attributes of its parent cell
  148. */
  149. RtfTableCell createExtraCell(int rowIndex, int xOffset, int cellWidth,
  150. RtfAttributes parentCellAttributes)
  151. throws IOException {
  152. final RtfTableCell c = new RtfTableCell(null, writer, cellWidth,
  153. parentCellAttributes, DEFAULT_IDNUM);
  154. cells.add(new PositionedCell(c, rowIndex, xOffset));
  155. return c;
  156. }
  157. /**
  158. * render extra RtfTableRows containing all the extra RtfTableCells that we
  159. * contain
  160. * @throws IOException for I/O problems
  161. */
  162. protected void writeRtfContent() throws IOException {
  163. // sort cells by rowIndex and xOffset
  164. Collections.sort(cells);
  165. // process all extra cells by rendering them into extra rows
  166. List rowCells = null;
  167. int rowIndex = -1;
  168. for (Object cell : cells) {
  169. final PositionedCell pc = (PositionedCell) cell;
  170. if (pc.rowIndex != rowIndex) {
  171. // starting a new row, render previous one
  172. if (rowCells != null) {
  173. writeRow(rowCells);
  174. }
  175. rowIndex = pc.rowIndex;
  176. rowCells = new LinkedList();
  177. }
  178. rowCells.add(pc);
  179. }
  180. // render last row
  181. if (rowCells != null) {
  182. writeRow(rowCells);
  183. }
  184. }
  185. /** write one RtfTableRow containing given PositionedCells */
  186. private void writeRow(List cells)
  187. throws IOException {
  188. if (allCellsEmpty(cells)) {
  189. return;
  190. }
  191. final RtfTableRow row = new RtfTableRow(null, writer, DEFAULT_IDNUM);
  192. int cellIndex = 0;
  193. // Get the context of the table that holds the nested table
  194. ITableColumnsInfo parentITableColumnsInfo = getParentITableColumnsInfo();
  195. parentITableColumnsInfo.selectFirstColumn();
  196. // X offset of the current empty cell to add
  197. float xOffset = 0;
  198. float xOffsetOfLastPositionedCell = 0;
  199. for (Object cell : cells) {
  200. final PositionedCell pc = (PositionedCell) cell;
  201. // if first cell is not at offset 0, add placeholder cell
  202. // TODO should be merged with the cell that is above it
  203. if (cellIndex == 0 && pc.xOffset > 0) {
  204. /**
  205. * Added by Boris Poudérous
  206. */
  207. // Add empty cells merged vertically with the cells above and with the same widths
  208. // (BEFORE the cell that contains the nested table)
  209. for (int i = 0; (xOffset < pc.xOffset)
  210. && (i < parentITableColumnsInfo.getNumberOfColumns()); i++) {
  211. // Get the width of the cell above
  212. xOffset += parentITableColumnsInfo.getColumnWidth();
  213. // Create the empty cell merged vertically
  214. row.newTableCellMergedVertically((int) parentITableColumnsInfo.getColumnWidth(),
  215. pc.cell.attrib);
  216. // Select next column in order to have its width
  217. parentITableColumnsInfo.selectNextColumn();
  218. }
  219. }
  220. row.addChild(pc.cell);
  221. // Line added by Boris Poudérous
  222. xOffsetOfLastPositionedCell = pc.xOffset + pc.cell.getCellWidth();
  223. cellIndex++;
  224. }
  225. /**
  226. * Added by Boris Poudérous
  227. */
  228. // Add empty cells merged vertically with the cells above AFTER the cell
  229. // that contains the nested table
  230. // The cells added have the same widths than the cells above.
  231. if (parentITableColumnsInfo.getColumnIndex()
  232. < (parentITableColumnsInfo.getNumberOfColumns() - 1)) {
  233. parentITableColumnsInfo.selectNextColumn();
  234. while (parentITableColumnsInfo.getColumnIndex()
  235. < parentITableColumnsInfo.getNumberOfColumns()) {
  236. // Create the empty cell merged vertically
  237. // TODO : the new cells after the extra cell don't have its
  238. // attributes as we did for the previous cells.
  239. // => in fact the m_attrib below (last argument) is
  240. // empty => should be the attributes of the above cells.
  241. row.newTableCellMergedVertically((int)parentITableColumnsInfo.getColumnWidth(),
  242. attrib);
  243. // Select next column in order to have its width
  244. parentITableColumnsInfo.selectNextColumn();
  245. }
  246. }
  247. row.writeRtf();
  248. }
  249. /** true if all cells of given list are empty
  250. * @param cells List of PositionedCell objects
  251. */
  252. private static boolean allCellsEmpty(List cells) {
  253. boolean empty = true;
  254. for (Object cell : cells) {
  255. final PositionedCell pc = (PositionedCell) cell;
  256. if (pc.cell.containsText()) {
  257. empty = false;
  258. break;
  259. }
  260. }
  261. return empty;
  262. }
  263. /**
  264. * As this contains cells from several rows, we say that it's empty
  265. * only if we have no cells.
  266. * writeRow makes the decision about rendering specific rows
  267. * @return false (always)
  268. */
  269. public boolean isEmpty() {
  270. return false;
  271. }
  272. /**
  273. * @return The table context of the parent table
  274. * Added by Boris Poudérous on july 2002 in order to process nested tables
  275. */
  276. public ITableColumnsInfo getParentITableColumnsInfo() {
  277. return this.parentITableColumnsInfo;
  278. }
  279. /**
  280. *
  281. * @param parentITableColumnsInfo table context to set
  282. */
  283. public void setParentITableColumnsInfo(ITableColumnsInfo parentITableColumnsInfo) {
  284. this.parentITableColumnsInfo = parentITableColumnsInfo;
  285. }
  286. /** - end - */
  287. }