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.

TableBody.java 13KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388
  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;
  19. // Java
  20. import java.util.BitSet;
  21. import java.util.List;
  22. import org.xml.sax.Attributes;
  23. import org.xml.sax.Locator;
  24. import org.apache.fop.apps.FOPException;
  25. import org.apache.fop.datatypes.Length;
  26. import org.apache.fop.fo.FONode;
  27. import org.apache.fop.fo.FObj;
  28. import org.apache.fop.fo.PropertyList;
  29. import org.apache.fop.fo.ValidationException;
  30. import org.apache.fop.fo.properties.CommonBorderPaddingBackground;
  31. /**
  32. * Class modelling the fo:table-body object.
  33. */
  34. public class TableBody extends TableFObj {
  35. // The value of properties relevant for fo:table-body.
  36. private CommonBorderPaddingBackground commonBorderPaddingBackground;
  37. // Unused but valid items, commented out for performance:
  38. // private CommonAccessibility commonAccessibility;
  39. // private CommonAural commonAural;
  40. // private CommonRelativePosition commonRelativePosition;
  41. // private int visibility;
  42. // End of property values
  43. private PropertyList savedPropertyList;
  44. /**
  45. * used for validation
  46. */
  47. protected boolean tableRowsFound = false;
  48. protected boolean tableCellsFound = false;
  49. /**
  50. * used for initial values of column-number property
  51. */
  52. protected List pendingSpans;
  53. protected BitSet usedColumnIndices;
  54. private int columnIndex = 1;
  55. protected boolean firstRow = true;
  56. /**
  57. * @param parent FONode that is the parent of the object
  58. */
  59. public TableBody(FONode parent) {
  60. super(parent);
  61. }
  62. /**
  63. * @see FObj#bind(PropertyList)
  64. */
  65. public void bind(PropertyList pList) throws FOPException {
  66. commonBorderPaddingBackground = pList.getBorderPaddingBackgroundProps();
  67. super.bind(pList);
  68. //Used by convertCellsToRows()
  69. savedPropertyList = pList;
  70. }
  71. /**
  72. * @see org.apache.fop.fo.FONode#processNode(String, Locator, Attributes, PropertyList)
  73. */
  74. public void processNode(String elementName, Locator locator,
  75. Attributes attlist, PropertyList pList)
  76. throws FOPException {
  77. if (!inMarker()) {
  78. if (getTable().columns != null) {
  79. int cap = getTable().columns.size();
  80. pendingSpans = new java.util.ArrayList(cap);
  81. usedColumnIndices = new java.util.BitSet(cap);
  82. } else {
  83. pendingSpans = new java.util.ArrayList();
  84. usedColumnIndices = new java.util.BitSet();
  85. }
  86. setNextColumnIndex();
  87. }
  88. super.processNode(elementName, locator, attlist, pList);
  89. }
  90. /**
  91. * @see org.apache.fop.fo.FONode#startOfNode
  92. */
  93. protected void startOfNode() throws FOPException {
  94. getFOEventHandler().startBody(this);
  95. }
  96. /**
  97. * @see org.apache.fop.fo.FONode#endOfNode
  98. */
  99. protected void endOfNode() throws FOPException {
  100. if (!inMarker()) {
  101. // clean up
  102. savedPropertyList = null;
  103. pendingSpans = null;
  104. usedColumnIndices = null;
  105. }
  106. getFOEventHandler().endBody(this);
  107. if (!(tableRowsFound || tableCellsFound)) {
  108. if (getUserAgent().validateStrictly()) {
  109. missingChildElementError("marker* (table-row+|table-cell+)");
  110. } else {
  111. log.error("fo:table-body must not be empty. "
  112. + "Expected: marker* (table-row+|table-cell+)");
  113. getParent().removeChild(this);
  114. }
  115. }
  116. /*
  117. if (tableCellsFound) {
  118. convertCellsToRows();
  119. }
  120. */
  121. }
  122. /**
  123. * @see org.apache.fop.fo.FONode#validateChildNode(Locator, String, String)
  124. * XSL Content Model: marker* (table-row+|table-cell+)
  125. */
  126. protected void validateChildNode(Locator loc, String nsURI, String localName)
  127. throws ValidationException {
  128. if (FO_URI.equals(nsURI)) {
  129. if (localName.equals("marker")) {
  130. if (tableRowsFound || tableCellsFound) {
  131. nodesOutOfOrderError(loc, "fo:marker", "(table-row+|table-cell+)");
  132. }
  133. } else if (localName.equals("table-row")) {
  134. tableRowsFound = true;
  135. if (tableCellsFound) {
  136. invalidChildError(loc, nsURI, localName, "Either fo:table-rows" +
  137. " or fo:table-cells may be children of an " + getName() +
  138. " but not both");
  139. }
  140. } else if (localName.equals("table-cell")) {
  141. tableCellsFound = true;
  142. if (tableRowsFound) {
  143. invalidChildError(loc, nsURI, localName,
  144. "Either fo:table-rows or fo:table-cells "
  145. + "may be children of an "
  146. + getName() + " but not both");
  147. }
  148. } else {
  149. invalidChildError(loc, nsURI, localName);
  150. }
  151. } else {
  152. invalidChildError(loc, nsURI, localName);
  153. }
  154. }
  155. /**
  156. * @see org.apache.fop.fo.FONode#addChildNode(FONode)
  157. */
  158. protected void addChildNode(FONode child) throws FOPException {
  159. if (!inMarker()) {
  160. if (firstRow) {
  161. Table t = getTable();
  162. if (t.columns == null) {
  163. t.columns = new java.util.ArrayList();
  164. }
  165. switch (child.getNameId()) {
  166. case FO_TABLE_ROW:
  167. firstRow = false;
  168. break;
  169. case FO_TABLE_CELL:
  170. TableCell cell = (TableCell) child;
  171. int colNr = cell.getColumnNumber();
  172. int colSpan = cell.getNumberColumnsSpanned();
  173. Length colWidth = null;
  174. if (cell.getWidth().getEnum() != EN_AUTO
  175. && colSpan == 1) {
  176. colWidth = cell.getWidth();
  177. }
  178. for (int i = colNr; i < colNr + colSpan; ++i) {
  179. if (t.columns.size() < i
  180. || t.columns.get(i - 1) == null) {
  181. t.addDefaultColumn(colWidth,
  182. i == colNr
  183. ? cell.getColumnNumber()
  184. : 0);
  185. } else {
  186. TableColumn col =
  187. (TableColumn) t.columns.get(i - 1);
  188. if (!col.isDefaultColumn()
  189. && colWidth != null) {
  190. col.setColumnWidth(colWidth);
  191. }
  192. }
  193. }
  194. break;
  195. default:
  196. //nop
  197. }
  198. }
  199. }
  200. super.addChildNode(child);
  201. }
  202. /**
  203. * @return the Common Border, Padding, and Background Properties.
  204. */
  205. public CommonBorderPaddingBackground getCommonBorderPaddingBackground() {
  206. return commonBorderPaddingBackground;
  207. }
  208. /** @see org.apache.fop.fo.FONode#getLocalName() */
  209. public String getLocalName() {
  210. return "table-body";
  211. }
  212. /**
  213. * @see org.apache.fop.fo.FObj#getNameId()
  214. */
  215. public int getNameId() {
  216. return FO_TABLE_BODY;
  217. }
  218. /**
  219. * @param obj table row in question
  220. * @return true if the given table row is the first row of this body.
  221. */
  222. public boolean isFirst(TableRow obj) {
  223. return (firstChild == null
  224. || firstChild == obj);
  225. }
  226. /**
  227. * Initializes list of pending row-spans; used for correctly
  228. * assigning initial value for column-number for the
  229. * cells of following rows
  230. * (note: not literally mentioned in the Rec, but it is assumed
  231. * that, if the first cell in a given row spans two rows, then
  232. * the first cell of the following row will have an initial
  233. * column-number of 2, since the first column is already
  234. * occupied...)
  235. */
  236. protected void initPendingSpans(FONode child) {
  237. if (child.getNameId() == FO_TABLE_ROW) {
  238. pendingSpans = ((TableRow) child).pendingSpans;
  239. } else if (pendingSpans == null) {
  240. if (getTable().columns != null) {
  241. List tableCols = getTable().columns;
  242. pendingSpans = new java.util.ArrayList(tableCols.size());
  243. for (int i = tableCols.size(); --i >= 0;) {
  244. pendingSpans.add(null);
  245. }
  246. } else {
  247. pendingSpans = new java.util.ArrayList();
  248. }
  249. }
  250. }
  251. /**
  252. * Returns the current column index of the TableBody
  253. *
  254. * @return the next column number to use
  255. */
  256. public int getCurrentColumnIndex() {
  257. return columnIndex;
  258. }
  259. /**
  260. * Sets the current column index to a specific value
  261. * (used by ColumnNumberPropertyMaker.make() in case the
  262. * column-number was explicitly specified on the cell)
  263. *
  264. * @param newIndex the new column index
  265. */
  266. public void setCurrentColumnIndex(int newIndex) {
  267. columnIndex = newIndex;
  268. }
  269. /**
  270. * Resets the current column index for the TableBody
  271. *
  272. */
  273. public void resetColumnIndex() {
  274. columnIndex = 1;
  275. for (int i = usedColumnIndices.length(); --i >= 0;) {
  276. usedColumnIndices.clear(i);
  277. }
  278. PendingSpan pSpan;
  279. for (int i = pendingSpans.size(); --i >= 0;) {
  280. pSpan = (PendingSpan) pendingSpans.get(i);
  281. if (pSpan != null) {
  282. pSpan.rowsLeft--;
  283. if (pSpan.rowsLeft == 0) {
  284. pendingSpans.set(i, null);
  285. } else {
  286. usedColumnIndices.set(i);
  287. }
  288. }
  289. }
  290. if (!firstRow) {
  291. setNextColumnIndex();
  292. }
  293. }
  294. /**
  295. * Increases columnIndex to the next available value
  296. *
  297. */
  298. protected void setNextColumnIndex() {
  299. while (usedColumnIndices.get(columnIndex - 1)) {
  300. //increment columnIndex
  301. columnIndex++;
  302. }
  303. //if the table has explicit columns, and
  304. //the index is not assigned to any
  305. //column, increment further until the next
  306. //index occupied by a column...
  307. if (getTable().columns != null) {
  308. while (columnIndex <= getTable().columns.size()
  309. && !getTable().isColumnNumberUsed(columnIndex) ) {
  310. columnIndex++;
  311. }
  312. }
  313. }
  314. /**
  315. * Checks whether the previous cell had 'ends-row="true"'
  316. *
  317. * @return true if:
  318. * a) there is a previous cell, which
  319. * had ends-row="true"
  320. * b) there is no previous cell (implicit
  321. * start of row)
  322. */
  323. public boolean previousCellEndedRow() {
  324. if (firstChild != null) {
  325. FONode prevNode = getChildNodes().lastNode();
  326. if (prevNode.getNameId() == FO_TABLE_CELL) {
  327. return ((TableCell) prevNode).endsRow();
  328. }
  329. }
  330. return true;
  331. }
  332. /**
  333. * Checks whether a given column-number is already in use
  334. * for the current row;
  335. *
  336. * @param colNr the column-number to check
  337. * @return true if column-number is already occupied
  338. */
  339. public boolean isColumnNumberUsed(int colNr) {
  340. return usedColumnIndices.get(colNr - 1);
  341. }
  342. /**
  343. * @see org.apache.fop.fo.flow.TableFObj#flagColumnIndices(int, int)
  344. */
  345. protected void flagColumnIndices(int start, int end) {
  346. for (int i = start; i < end; i++) {
  347. usedColumnIndices.set(i);
  348. }
  349. setNextColumnIndex();
  350. }
  351. }