選択できるのは25トピックまでです。 トピックは、先頭が英数字で、英数字とダッシュ('-')を使用した35文字以内のものにしてください。

ColumnSetup.java 11KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314
  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.Iterator;
  20. import java.util.List;
  21. import org.apache.commons.logging.Log;
  22. import org.apache.commons.logging.LogFactory;
  23. import org.apache.fop.datatypes.Length;
  24. import org.apache.fop.datatypes.PercentBaseContext;
  25. import org.apache.fop.fo.FONode;
  26. import org.apache.fop.fo.expr.RelativeNumericProperty;
  27. import org.apache.fop.fo.flow.table.Table;
  28. import org.apache.fop.fo.flow.table.TableColumn;
  29. import org.apache.fop.fo.properties.TableColLength;
  30. import org.apache.fop.traits.Direction;
  31. import org.apache.fop.traits.WritingModeTraits;
  32. import org.apache.fop.traits.WritingModeTraitsGetter;
  33. /**
  34. * Class holding a number of columns making up the column setup of a row.
  35. */
  36. public class ColumnSetup {
  37. /** Logger **/
  38. private static Log log = LogFactory.getLog(ColumnSetup.class);
  39. private Table table;
  40. private WritingModeTraitsGetter wmTraits;
  41. private List columns = new java.util.ArrayList();
  42. private List colWidths = new java.util.ArrayList();
  43. private int maxColIndexReferenced;
  44. /**
  45. * Main Constructor.
  46. * @param table the table to construct this column setup for
  47. */
  48. public ColumnSetup(Table table) {
  49. assert table != null;
  50. this.table = table;
  51. this.wmTraits = WritingModeTraits.getWritingModeTraitsGetter(table);
  52. prepareColumns();
  53. initializeColumnWidths();
  54. }
  55. private void prepareColumns() {
  56. List rawCols = table.getColumns();
  57. if (rawCols != null) {
  58. int colnum = 1;
  59. for (Object rawCol : rawCols) {
  60. TableColumn col = (TableColumn) rawCol;
  61. if (col == null) {
  62. continue;
  63. }
  64. colnum = col.getColumnNumber();
  65. for (int i = 0; i < col.getNumberColumnsRepeated(); i++) {
  66. while (colnum > columns.size()) {
  67. columns.add(null);
  68. }
  69. columns.set(colnum - 1, col);
  70. colnum++;
  71. }
  72. }
  73. //Post-processing the list (looking for gaps)
  74. //TODO The following block could possibly be removed
  75. int pos = 1;
  76. for (Object column : columns) {
  77. TableColumn col = (TableColumn) column;
  78. if (col == null) {
  79. assert false; //Gaps are filled earlier by fo.flow.table.Table.finalizeColumns()
  80. //log.error("Found a gap in the table-columns at position " + pos);
  81. }
  82. pos++;
  83. }
  84. }
  85. }
  86. /**
  87. * Returns a column. If the index of the column is bigger than the number of explicitly
  88. * defined columns the last column is returned.
  89. * @param index index of the column (1 is the first column)
  90. * @return the requested column
  91. */
  92. public TableColumn getColumn(int index) {
  93. int size = columns.size();
  94. if (index > size) {
  95. if (index > maxColIndexReferenced) {
  96. maxColIndexReferenced = index;
  97. TableColumn col = getColumn(1);
  98. if (!(size == 1 && col.isImplicitColumn())) {
  99. assert false; //TODO Seems to be removable as this is now done in the FO tree
  100. log.warn(FONode.decorateWithContextInfo(
  101. "There are fewer table-columns than are needed. "
  102. + "Column " + index + " was accessed, but only "
  103. + size + " columns have been defined. "
  104. + "The last defined column will be reused."
  105. , table));
  106. if (!table.isAutoLayout()) {
  107. log.warn("Please note that according XSL-FO 1.0 (7.26.9) says that "
  108. + "the 'column-width' property must be specified for every "
  109. + "column, unless the automatic table layout is used.");
  110. }
  111. }
  112. }
  113. return (TableColumn) columns.get(size - 1);
  114. } else {
  115. return (TableColumn) columns.get(index - 1);
  116. }
  117. }
  118. /** {@inheritDoc} */
  119. public String toString() {
  120. return columns.toString();
  121. }
  122. /** @return the number of columns in the setup. */
  123. public int getColumnCount() {
  124. if (maxColIndexReferenced > columns.size()) {
  125. return maxColIndexReferenced;
  126. } else {
  127. return columns.size();
  128. }
  129. }
  130. /** @return an Iterator over all columns */
  131. public Iterator iterator() {
  132. return this.columns.iterator();
  133. }
  134. /*
  135. private void createColumnsFromFirstRow() {
  136. //TODO Create oldColumns from first row here
  137. //--> rule 2 in "fixed table layout", see CSS2, 17.5.2
  138. //Alternative: extend oldColumns on-the-fly, but in this case we need the
  139. //new property evaluation context so proportional-column-width() works
  140. //correctly.
  141. if (columns.size() == 0) {
  142. this.columns.add(table.getDefaultColumn());
  143. }
  144. }
  145. */
  146. /**
  147. * Initializes the column's widths
  148. *
  149. */
  150. private void initializeColumnWidths() {
  151. TableColumn col;
  152. Length colWidth;
  153. for (int i = columns.size(); --i >= 0;) {
  154. if (columns.get(i) != null) {
  155. col = (TableColumn) columns.get(i);
  156. colWidth = col.getColumnWidth();
  157. colWidths.add(0, colWidth);
  158. }
  159. }
  160. colWidths.add(0, null);
  161. }
  162. /**
  163. * Works out the base unit for resolving proportional-column-width()
  164. * [p-c-w(x) = x * base_unit_ipd]
  165. *
  166. * @param tlm the TableLayoutManager
  167. * @return the computed base unit (in millipoint)
  168. */
  169. protected double computeTableUnit(TableLayoutManager tlm) {
  170. return computeTableUnit(tlm, tlm.getContentAreaIPD());
  171. }
  172. /**
  173. * Works out the base unit for resolving proportional-column-width()
  174. * [p-c-w(x) = x * base_unit_ipd]
  175. *
  176. * @param percentBaseContext the percent base context for relative values
  177. * @param contentAreaIPD the IPD of the available content area
  178. * @return the computed base unit (in millipoints)
  179. */
  180. public float computeTableUnit(PercentBaseContext percentBaseContext, int contentAreaIPD) {
  181. int sumCols = 0;
  182. float factors = 0;
  183. float unit = 0;
  184. /* calculate the total width (specified absolute/percentages),
  185. * and work out the total number of factors to use to distribute
  186. * the remaining space (if any)
  187. */
  188. for (Object colWidth1 : colWidths) {
  189. Length colWidth = (Length) colWidth1;
  190. if (colWidth != null) {
  191. sumCols += colWidth.getValue(percentBaseContext);
  192. if (colWidth instanceof RelativeNumericProperty) {
  193. factors += ((RelativeNumericProperty) colWidth).getTableUnits();
  194. } else if (colWidth instanceof TableColLength) {
  195. factors += ((TableColLength) colWidth).getTableUnits();
  196. }
  197. }
  198. }
  199. /* distribute the remaining space over the accumulated
  200. * factors (if any)
  201. */
  202. if (factors > 0) {
  203. if (sumCols < contentAreaIPD) {
  204. unit = (contentAreaIPD - sumCols) / factors;
  205. } else {
  206. log.warn("No space remaining to distribute over columns.");
  207. }
  208. }
  209. return unit;
  210. }
  211. /**
  212. * Determine the X offset of the indicated column, where this
  213. * offset denotes the left edge of the column irrespective of writing
  214. * mode. If writing mode's column progression direction is right-to-left,
  215. * then the first column is the right-most column and the last column is
  216. * the left-most column; otherwise, the first column is the left-most
  217. * column.
  218. * @param col column index (1 is first column)
  219. * @param nrColSpan number columns spanned (for calculating offset in rtl mode)
  220. * @param context the context for percentage based calculations
  221. * @return the X offset of the requested column
  222. */
  223. public int getXOffset(int col, int nrColSpan, PercentBaseContext context) {
  224. // TODO handle vertical WMs [GA]
  225. if ((wmTraits != null) && (wmTraits.getColumnProgressionDirection() == Direction.RL)) {
  226. return getXOffsetRTL(col, nrColSpan, context);
  227. } else {
  228. return getXOffsetLTR(col, context);
  229. }
  230. }
  231. /*
  232. * Determine x offset by summing widths of columns to left of specified
  233. * column; i.e., those columns whose column numbers are greater than the
  234. * specified column number.
  235. */
  236. private int getXOffsetRTL(int col, int nrColSpan, PercentBaseContext context) {
  237. int xoffset = 0;
  238. for (int i = (col + nrColSpan - 1), nc = colWidths.size(); ++i < nc;) {
  239. int effCol = i;
  240. if (colWidths.get(effCol) != null) {
  241. xoffset += ((Length) colWidths.get(effCol)).getValue(context);
  242. }
  243. }
  244. return xoffset;
  245. }
  246. /*
  247. * Determine x offset by summing widths of columns to left of specified
  248. * column; i.e., those columns whose column numbers are less than the
  249. * specified column number.
  250. */
  251. private int getXOffsetLTR(int col, PercentBaseContext context) {
  252. int xoffset = 0;
  253. for (int i = col; --i >= 0;) {
  254. int effCol;
  255. if (i < colWidths.size()) {
  256. effCol = i;
  257. } else {
  258. effCol = colWidths.size() - 1;
  259. }
  260. if (colWidths.get(effCol) != null) {
  261. xoffset += ((Length) colWidths.get(effCol)).getValue(context);
  262. }
  263. }
  264. return xoffset;
  265. }
  266. /**
  267. * Calculates the sum of all column widths.
  268. * @param context the context for percentage based calculations
  269. * @return the requested sum in millipoints
  270. */
  271. public int getSumOfColumnWidths(PercentBaseContext context) {
  272. int sum = 0;
  273. for (int i = 1, c = getColumnCount(); i <= c; i++) {
  274. int effIndex = i;
  275. if (i >= colWidths.size()) {
  276. effIndex = colWidths.size() - 1;
  277. }
  278. if (colWidths.get(effIndex) != null) {
  279. sum += ((Length) colWidths.get(effIndex)).getValue(context);
  280. }
  281. }
  282. return sum;
  283. }
  284. }