1. /*
  2. * @(#)TableView.java 1.20 00/02/02
  3. *
  4. * Copyright 1997-2000 Sun Microsystems, Inc. All Rights Reserved.
  5. *
  6. * This software is the proprietary information of Sun Microsystems, Inc.
  7. * Use is subject to license terms.
  8. *
  9. */
  10. package javax.swing.text.html;
  11. import java.awt.*;
  12. import java.util.BitSet;
  13. import java.util.Vector;
  14. import javax.swing.SizeRequirements;
  15. import javax.swing.event.DocumentEvent;
  16. import javax.swing.text.*;
  17. /**
  18. * HTML table view.
  19. *
  20. * @author Timothy Prinzing
  21. * @version 1.20 02/02/00
  22. * @see View
  23. */
  24. /*public*/ class TableView extends BoxView implements ViewFactory {
  25. /**
  26. * Constructs a TableView for the given element.
  27. *
  28. * @param elem the element that this view is responsible for
  29. */
  30. public TableView(Element elem) {
  31. super(elem, View.Y_AXIS);
  32. rows = new Vector();
  33. gridValid = false;
  34. captionIndex = -1;
  35. }
  36. /**
  37. * Creates a new table row.
  38. *
  39. * @param elem an element
  40. * @return the row
  41. */
  42. protected RowView createTableRow(Element elem) {
  43. // PENDING(prinz) need to add support for some of the other
  44. // elements, but for now just ignore anything that is not
  45. // a TR.
  46. Object o = elem.getAttributes().getAttribute(StyleConstants.NameAttribute);
  47. if (o == HTML.Tag.TR) {
  48. return new RowView(elem);
  49. }
  50. return null;
  51. }
  52. /**
  53. * The number of columns in the table.
  54. */
  55. public int getColumnCount() {
  56. return columnSpans.length;
  57. }
  58. /**
  59. * Fetches the span (width) of the given column.
  60. * This is used by the nested cells to query the
  61. * sizes of grid locations outside of themselves.
  62. */
  63. public int getColumnSpan(int col) {
  64. if (col < columnSpans.length) {
  65. return columnSpans[col];
  66. }
  67. return 0;
  68. }
  69. /**
  70. * The number of rows in the table.
  71. */
  72. public int getRowCount() {
  73. return rows.size();
  74. }
  75. /**
  76. * Fetch the span of multiple rows. This includes
  77. * the border area.
  78. */
  79. public int getMultiRowSpan(int row0, int row1) {
  80. RowView rv0 = getRow(row0);
  81. RowView rv1 = getRow(row1);
  82. if ((rv0 != null) && (rv1 != null)) {
  83. int index0 = rv0.viewIndex;
  84. int index1 = rv1.viewIndex;
  85. int span = getOffset(Y_AXIS, index1) - getOffset(Y_AXIS, index0) +
  86. getSpan(Y_AXIS, index1);
  87. return span;
  88. }
  89. return 0;
  90. }
  91. /**
  92. * Fetches the span (height) of the given row.
  93. */
  94. public int getRowSpan(int row) {
  95. RowView rv = getRow(row);
  96. if (rv != null) {
  97. return getSpan(Y_AXIS, rv.viewIndex);
  98. }
  99. return 0;
  100. }
  101. RowView getRow(int row) {
  102. if (row < rows.size()) {
  103. return (RowView) rows.elementAt(row);
  104. }
  105. return null;
  106. }
  107. /**
  108. * Determines the number of columns occupied by
  109. * the table cell represented by given element.
  110. */
  111. protected int getColumnsOccupied(View v) {
  112. AttributeSet a = v.getElement().getAttributes();
  113. String s = (String) a.getAttribute(HTML.Attribute.COLSPAN);
  114. if (s != null) {
  115. try {
  116. return Integer.parseInt(s);
  117. } catch (NumberFormatException nfe) {
  118. // fall through to one column
  119. }
  120. }
  121. return 1;
  122. }
  123. /**
  124. * Determines the number of rows occupied by
  125. * the table cell represented by given element.
  126. */
  127. protected int getRowsOccupied(View v) {
  128. AttributeSet a = v.getElement().getAttributes();
  129. String s = (String) a.getAttribute(HTML.Attribute.ROWSPAN);
  130. if (s != null) {
  131. try {
  132. return Integer.parseInt(s);
  133. } catch (NumberFormatException nfe) {
  134. // fall through to one row
  135. }
  136. }
  137. return 1;
  138. }
  139. protected void invalidateGrid() {
  140. gridValid = false;
  141. }
  142. protected StyleSheet getStyleSheet() {
  143. HTMLDocument doc = (HTMLDocument) getDocument();
  144. return doc.getStyleSheet();
  145. }
  146. /**
  147. * Update the insets, which contain the caption if there
  148. * is a caption.
  149. */
  150. void updateInsets() {
  151. short top = (short) painter.getInset(TOP, this);
  152. short bottom = (short) painter.getInset(BOTTOM, this);
  153. if (captionIndex != -1) {
  154. View caption = getView(captionIndex);
  155. short h = (short) caption.getPreferredSpan(Y_AXIS);
  156. AttributeSet a = caption.getAttributes();
  157. Object align = a.getAttribute(CSS.Attribute.CAPTION_SIDE);
  158. if ((align != null) && (align.equals("bottom"))) {
  159. bottom += h;
  160. } else {
  161. top += h;
  162. }
  163. }
  164. setInsets(top, (short) painter.getInset(LEFT, this),
  165. bottom, (short) painter.getInset(RIGHT, this));
  166. }
  167. /**
  168. * Update any cached values that come from attributes.
  169. */
  170. protected void setPropertiesFromAttributes() {
  171. StyleSheet sheet = getStyleSheet();
  172. attr = sheet.getViewAttributes(this);
  173. painter = sheet.getBoxPainter(attr);
  174. if (attr != null) {
  175. setInsets((short) painter.getInset(TOP, this),
  176. (short) painter.getInset(LEFT, this),
  177. (short) painter.getInset(BOTTOM, this),
  178. (short) painter.getInset(RIGHT, this));
  179. /*
  180. CSS.LengthValue lv = (CSS.LengthValue)
  181. attr.getAttribute(CSS.Attribute.BORDER_SPACING);
  182. if (lv != null) {
  183. cellSpacing = (int) lv.getValue();
  184. } else {
  185. cellSpacing = 0;
  186. }
  187. */
  188. }
  189. }
  190. /**
  191. * Fill in the grid locations that are placeholders
  192. * for multi-column, multi-row, and missing grid
  193. * locations.
  194. */
  195. void updateGrid() {
  196. if (! gridValid) {
  197. relativeCells = false;
  198. multiRowCells = false;
  199. // determine which views are table rows and clear out
  200. // grid points marked filled.
  201. captionIndex = -1;
  202. rows.removeAllElements();
  203. int n = getViewCount();
  204. for (int i = 0; i < n; i++) {
  205. View v = getView(i);
  206. if (v instanceof RowView) {
  207. rows.addElement(v);
  208. RowView rv = (RowView) v;
  209. rv.clearFilledColumns();
  210. rv.rowIndex = rows.size() - 1;
  211. rv.viewIndex = i;
  212. } else {
  213. Object o = v.getElement().getAttributes().getAttribute(StyleConstants.NameAttribute);
  214. if (o instanceof HTML.Tag) {
  215. HTML.Tag kind = (HTML.Tag) o;
  216. if (kind == HTML.Tag.CAPTION) {
  217. captionIndex = i;
  218. }
  219. }
  220. }
  221. }
  222. int maxColumns = 0;
  223. int nrows = rows.size();
  224. for (int row = 0; row < nrows; row++) {
  225. RowView rv = getRow(row);
  226. int col = 0;
  227. for (int cell = 0; cell < rv.getViewCount(); cell++, col++) {
  228. View cv = rv.getView(cell);
  229. if (! relativeCells) {
  230. AttributeSet a = cv.getAttributes();
  231. CSS.LengthValue lv = (CSS.LengthValue)
  232. a.getAttribute(CSS.Attribute.WIDTH);
  233. if ((lv != null) && (lv.isPercentage())) {
  234. relativeCells = true;
  235. }
  236. }
  237. // advance to a free column
  238. for (; rv.isFilled(col); col++);
  239. int rowSpan = getRowsOccupied(cv);
  240. if (rowSpan > 1) {
  241. multiRowCells = true;
  242. }
  243. int colSpan = getColumnsOccupied(cv);
  244. if ((colSpan > 1) || (rowSpan > 1)) {
  245. // fill in the overflow entries for this cell
  246. int rowLimit = row + rowSpan;
  247. int colLimit = col + colSpan;
  248. for (int i = row; i < rowLimit; i++) {
  249. for (int j = col; j < colLimit; j++) {
  250. if (i != row || j != col) {
  251. addFill(i, j);
  252. }
  253. }
  254. }
  255. if (colSpan > 1) {
  256. col += colSpan - 1;
  257. }
  258. }
  259. }
  260. maxColumns = Math.max(maxColumns, col);
  261. }
  262. // setup the column layout/requirements
  263. columnSpans = new int[maxColumns];
  264. columnOffsets = new int[maxColumns];
  265. columnRequirements = new SizeRequirements[maxColumns];
  266. for (int i = 0; i < maxColumns; i++) {
  267. columnRequirements[i] = new SizeRequirements();
  268. }
  269. gridValid = true;
  270. }
  271. }
  272. /**
  273. * Mark a grid location as filled in for a cells overflow.
  274. */
  275. void addFill(int row, int col) {
  276. RowView rv = getRow(row);
  277. if (rv != null) {
  278. rv.fillColumn(col);
  279. }
  280. }
  281. /**
  282. * Layout the columns to fit within the given target span.
  283. *
  284. * @param targetSpan the given span for total of all the table
  285. * columns.
  286. * @param reqs the requirements desired for each column. This
  287. * is the column maximum of the cells minimum, preferred, and
  288. * maximum requested span.
  289. * @param spans the return value of how much to allocated to
  290. * each column.
  291. * @param offsets the return value of the offset from the
  292. * origin for each column.
  293. * @returns the offset from the origin and the span for each column
  294. * in the offsets and spans parameters.
  295. */
  296. protected void layoutColumns(int targetSpan, int[] offsets, int[] spans,
  297. SizeRequirements[] reqs) {
  298. colIterator.setLayoutArrays(offsets, spans, targetSpan);
  299. CSS.calculateTiledLayout(colIterator, targetSpan);
  300. }
  301. /**
  302. * Calculate the requirements for each column. The calculation
  303. * is done as two passes over the table. The table cells that
  304. * occupy a single column are scanned first to determine the
  305. * maximum of minimum, preferred, and maximum spans along the
  306. * give axis. Table cells that span multiple columns are excluded
  307. * from the first pass. A second pass is made to determine if
  308. * the cells that span multiple columns are satisfied. If the
  309. * column requirements are not satisified, the needs of the
  310. * multi-column cell is mixed into the existing column requirements.
  311. * The calculation of the multi-column distribution is based upon
  312. * the proportions of the existing column requirements and taking
  313. * into consideration any constraining maximums.
  314. */
  315. void calculateColumnRequirements(int axis) {
  316. // pass 1 - single column cells
  317. boolean hasMultiColumn = false;
  318. int nrows = getRowCount();
  319. for (int i = 0; i < nrows; i++) {
  320. RowView row = getRow(i);
  321. int col = 0;
  322. int ncells = row.getViewCount();
  323. for (int cell = 0; cell < ncells; cell++, col++) {
  324. View cv = row.getView(cell);
  325. for (; row.isFilled(col); col++); // advance to a free column
  326. int rowSpan = getRowsOccupied(cv);
  327. int colSpan = getColumnsOccupied(cv);
  328. if (colSpan == 1) {
  329. checkSingleColumnCell(axis, col, cv);
  330. } else {
  331. hasMultiColumn = true;
  332. col += colSpan - 1;
  333. }
  334. }
  335. }
  336. // pass 2 - multi-column cells
  337. if (hasMultiColumn) {
  338. for (int i = 0; i < nrows; i++) {
  339. RowView row = getRow(i);
  340. int col = 0;
  341. int ncells = row.getViewCount();
  342. for (int cell = 0; cell < ncells; cell++, col++) {
  343. View cv = row.getView(cell);
  344. for (; row.isFilled(col); col++); // advance to a free column
  345. int colSpan = getColumnsOccupied(cv);
  346. if (colSpan > 1) {
  347. checkMultiColumnCell(axis, col, colSpan, cv);
  348. col += colSpan - 1;
  349. }
  350. }
  351. }
  352. }
  353. }
  354. /**
  355. * check the requirements of a table cell that spans a single column.
  356. */
  357. void checkSingleColumnCell(int axis, int col, View v) {
  358. SizeRequirements req = columnRequirements[col];
  359. req.minimum = Math.max((int) v.getMinimumSpan(axis), req.minimum);
  360. req.preferred = Math.max((int) v.getPreferredSpan(axis), req.preferred);
  361. req.maximum = Math.max((int) v.getMaximumSpan(axis), req.maximum);
  362. }
  363. /**
  364. * check the requirements of a table cell that spans multiple
  365. * columns.
  366. */
  367. void checkMultiColumnCell(int axis, int col, int ncols, View v) {
  368. // calculate the totals
  369. long min = 0;
  370. long pref = 0;
  371. long max = 0;
  372. for (int i = 0; i < ncols; i++) {
  373. SizeRequirements req = columnRequirements[col + i];
  374. min += req.minimum;
  375. pref += req.preferred;
  376. max += req.maximum;
  377. }
  378. // check if the minimum size needs adjustment.
  379. int cmin = (int) v.getMinimumSpan(axis);
  380. if (cmin > min) {
  381. /*
  382. * the columns that this cell spans need adjustment to fit
  383. * this table cell.... calculate the adjustments. The
  384. * maximum for each cell is the maximum of the existing
  385. * maximum or the amount needed by the cell.
  386. */
  387. SizeRequirements[] reqs = new SizeRequirements[ncols];
  388. for (int i = 0; i < ncols; i++) {
  389. SizeRequirements r = reqs[i] = columnRequirements[col + i];
  390. r.maximum = Math.max(r.maximum, (int) v.getMaximumSpan(axis));
  391. }
  392. int[] spans = new int[ncols];
  393. int[] offsets = new int[ncols];
  394. SizeRequirements.calculateTiledPositions(cmin, null, reqs,
  395. offsets, spans);
  396. // apply the adjustments
  397. for (int i = 0; i < ncols; i++) {
  398. SizeRequirements req = reqs[i];
  399. req.minimum = Math.max(spans[i], req.minimum);
  400. req.preferred = Math.max(req.minimum, req.preferred);
  401. req.maximum = Math.max(req.preferred, req.maximum);
  402. }
  403. }
  404. // check if the preferred size needs adjustment.
  405. int cpref = (int) v.getPreferredSpan(axis);
  406. if (cpref > pref) {
  407. /*
  408. * the columns that this cell spans need adjustment to fit
  409. * this table cell.... calculate the adjustments. The
  410. * maximum for each cell is the maximum of the existing
  411. * maximum or the amount needed by the cell.
  412. */
  413. SizeRequirements[] reqs = new SizeRequirements[ncols];
  414. for (int i = 0; i < ncols; i++) {
  415. SizeRequirements r = reqs[i] = columnRequirements[col + i];
  416. }
  417. int[] spans = new int[ncols];
  418. int[] offsets = new int[ncols];
  419. SizeRequirements.calculateTiledPositions(cpref, null, reqs,
  420. offsets, spans);
  421. // apply the adjustments
  422. for (int i = 0; i < ncols; i++) {
  423. SizeRequirements req = reqs[i];
  424. req.preferred = Math.max(spans[i], req.preferred);
  425. req.maximum = Math.max(req.preferred, req.maximum);
  426. }
  427. }
  428. }
  429. /**
  430. * Adjust the given requirements to the CSS width or height if
  431. * it is specified along the applicable axis. Return true if the
  432. * size is exactly specified, false if the span is not specified
  433. * in an attribute or the size specified is a percentage.
  434. */
  435. boolean spanSetFromAttributes(int axis, SizeRequirements r) {
  436. AttributeSet attr = getAttributes();
  437. if (axis == X_AXIS) {
  438. CSS.LengthValue cssWidth = (CSS.LengthValue) attr.getAttribute(CSS.Attribute.WIDTH);
  439. if ((cssWidth != null) && (! cssWidth.isPercentage())) {
  440. r.minimum = r.preferred = r.maximum = (int) cssWidth.getValue();
  441. return true;
  442. }
  443. } else {
  444. CSS.LengthValue cssHeight = (CSS.LengthValue) attr.getAttribute(CSS.Attribute.HEIGHT);
  445. if ((cssHeight != null) && (! cssHeight.isPercentage())) {
  446. r.minimum = r.preferred = r.maximum = (int) cssHeight.getValue();
  447. return true;
  448. }
  449. }
  450. return false;
  451. }
  452. // --- BoxView methods -----------------------------------------
  453. /**
  454. * Calculate the requirements for the minor axis. This is called by
  455. * the superclass whenever the requirements need to be updated (i.e.
  456. * a preferenceChanged was messaged through this view).
  457. * <p>
  458. * This is implemented to calculate the requirements as the sum of the
  459. * requirements of the columns and then adjust it if the
  460. * CSS width or height attribute is specified and applicable to
  461. * the axis.
  462. */
  463. protected SizeRequirements calculateMinorAxisRequirements(int axis, SizeRequirements r) {
  464. updateGrid();
  465. // calculate column requirements for each column
  466. calculateColumnRequirements(axis);
  467. // the requirements are the sum of the columns.
  468. if (r == null) {
  469. r = new SizeRequirements();
  470. }
  471. long min = 0;
  472. long pref = 0;
  473. long max = 0;
  474. int n = columnRequirements.length;
  475. for (int i = 0; i < n; i++) {
  476. SizeRequirements req = columnRequirements[i];
  477. min += req.minimum;
  478. pref += req.preferred;
  479. max += req.maximum;
  480. }
  481. int adjust = (n - 1) * cellSpacing;
  482. min += adjust;
  483. pref += adjust;
  484. r.minimum = (int) min;
  485. r.preferred = (int) pref;
  486. r.maximum = (int) pref;
  487. spanSetFromAttributes(axis, r);
  488. // set the alignment
  489. Object o = attr.getAttribute(CSS.Attribute.TEXT_ALIGN);
  490. if (o != null) {
  491. // set horizontal alignment
  492. String ta = o.toString();
  493. if (ta.equals("left")) {
  494. r.alignment = 0;
  495. } else if (ta.equals("center")) {
  496. r.alignment = 0.5f;
  497. } else if (ta.equals("right")) {
  498. r.alignment = 1;
  499. } else {
  500. r.alignment = 0;
  501. }
  502. } else {
  503. r.alignment = 0;
  504. }
  505. return r;
  506. }
  507. /**
  508. * Calculate the requirements for the major axis. This is called by
  509. * the superclass whenever the requirements need to be updated (i.e.
  510. * a preferenceChanged was messaged through this view).
  511. * <p>
  512. * This is implemented to provide the superclass behavior adjusted for
  513. * multi-row table cells.
  514. */
  515. protected SizeRequirements calculateMajorAxisRequirements(int axis, SizeRequirements r) {
  516. updateInsets();
  517. rowIterator.updateAdjustments();
  518. r = CSS.calculateTiledRequirements(rowIterator, r);
  519. r.maximum = r.preferred;
  520. return r;
  521. }
  522. /**
  523. * Perform layout for the minor axis of the box (i.e. the
  524. * axis orthoginal to the axis that it represents). The results
  525. * of the layout should be placed in the given arrays which represent
  526. * the allocations to the children along the minor axis. This
  527. * is called by the superclass whenever the layout needs to be
  528. * updated along the minor axis.
  529. * <p>
  530. * This is implemented to call the
  531. * <a href="#layoutColumns">layoutColumns</a> method, and then
  532. * forward to the superclass to actually carry out the layout
  533. * of the tables rows.
  534. *
  535. * @param targetSpan the total span given to the view, which
  536. * whould be used to layout the children.
  537. * @param axis the axis being layed out.
  538. * @param offsets the offsets from the origin of the view for
  539. * each of the child views. This is a return value and is
  540. * filled in by the implementation of this method.
  541. * @param spans the span of each child view. This is a return
  542. * value and is filled in by the implementation of this method.
  543. * @returns the offset and span for each child view in the
  544. * offsets and spans parameters.
  545. */
  546. protected void layoutMinorAxis(int targetSpan, int axis, int[] offsets, int[] spans) {
  547. // make grid is properly represented
  548. updateGrid();
  549. // all of the row layouts are invalid, so mark them that way
  550. int n = getRowCount();
  551. for (int i = 0; i < n; i++) {
  552. RowView row = getRow(i);
  553. row.layoutChanged(axis);
  554. }
  555. // calculate column spans
  556. layoutColumns(targetSpan, columnOffsets, columnSpans, columnRequirements);
  557. // continue normal layout
  558. super.layoutMinorAxis(targetSpan, axis, offsets, spans);
  559. }
  560. /**
  561. * Perform layout for the major axis of the box (i.e. the
  562. * axis that it represents). The results
  563. * of the layout should be placed in the given arrays which represent
  564. * the allocations to the children along the minor axis. This
  565. * is called by the superclass whenever the layout needs to be
  566. * updated along the minor axis.
  567. * <p>
  568. * This method is where the layout of the table rows within the
  569. * table takes place. This method is implemented to call the use
  570. * the RowIterator and the CSS collapsing tile to layout
  571. * with border spacing and border collapsing capabilities.
  572. *
  573. * @param targetSpan the total span given to the view, which
  574. * whould be used to layout the children.
  575. * @param axis the axis being layed out.
  576. * @param offsets the offsets from the origin of the view for
  577. * each of the child views. This is a return value and is
  578. * filled in by the implementation of this method.
  579. * @param spans the span of each child view. This is a return
  580. * value and is filled in by the implementation of this method.
  581. * @returns the offset and span for each child view in the
  582. * offsets and spans parameters.
  583. */
  584. protected void layoutMajorAxis(int targetSpan, int axis, int[] offsets, int[] spans) {
  585. rowIterator.setLayoutArrays(offsets, spans);
  586. CSS.calculateTiledLayout(rowIterator, targetSpan);
  587. if (captionIndex != -1) {
  588. // place the caption
  589. View caption = getView(captionIndex);
  590. int h = (int) caption.getPreferredSpan(Y_AXIS);
  591. spans[captionIndex] = h;
  592. short boxBottom = (short) painter.getInset(BOTTOM, this);
  593. if (boxBottom != getBottomInset()) {
  594. offsets[captionIndex] = targetSpan + boxBottom;
  595. } else {
  596. offsets[captionIndex] = - getTopInset();
  597. }
  598. }
  599. }
  600. /**
  601. * Fetches the child view that represents the given position in
  602. * the model. This is implemented to walk through the children
  603. * looking for a range that contains the given position. In this
  604. * view the children do not necessarily have a one to one mapping
  605. * with the child elements.
  606. *
  607. * @param pos the search position >= 0
  608. * @param a the allocation to the table on entry, and the
  609. * allocation of the view containing the position on exit
  610. * @returns the view representing the given position, or
  611. * null if there isn't one
  612. */
  613. protected View getViewAtPosition(int pos, Rectangle a) {
  614. int n = getViewCount();
  615. for (int i = 0; i < n; i++) {
  616. View v = getView(i);
  617. int p0 = v.getStartOffset();
  618. int p1 = v.getEndOffset();
  619. if ((pos >= p0) && (pos < p1)) {
  620. // it's in this view.
  621. if (a != null) {
  622. childAllocation(i, a);
  623. }
  624. return v;
  625. }
  626. }
  627. if (pos == getEndOffset()) {
  628. View v = getView(n - 1);
  629. if (a != null) {
  630. this.childAllocation(n - 1, a);
  631. }
  632. return v;
  633. }
  634. return null;
  635. }
  636. // --- View methods ---------------------------------------------
  637. /**
  638. * Fetches the attributes to use when rendering. This is
  639. * implemented to multiplex the attributes specified in the
  640. * model with a StyleSheet.
  641. */
  642. public AttributeSet getAttributes() {
  643. if (attr == null) {
  644. StyleSheet sheet = getStyleSheet();
  645. attr = sheet.getViewAttributes(this);
  646. }
  647. return attr;
  648. }
  649. /**
  650. * Renders using the given rendering surface and area on that
  651. * surface. This is implemented to delegate to the css box
  652. * painter to paint the border and background prior to the
  653. * interior. The superclass culls rendering the children
  654. * that don't directly intersect the clip and the row may
  655. * have cells hanging from a row above in it. The table
  656. * does not use the superclass rendering behavior and instead
  657. * paints all of the rows and lets the rows cull those
  658. * cells not intersecting the clip region.
  659. *
  660. * @param g the rendering surface to use
  661. * @param allocation the allocated region to render into
  662. * @see View#paint
  663. */
  664. public void paint(Graphics g, Shape allocation) {
  665. // paint the border
  666. Rectangle a = allocation.getBounds();
  667. setSize(a.width, a.height);
  668. if (captionIndex != -1) {
  669. // adjust the border for the caption
  670. short top = (short) painter.getInset(TOP, this);
  671. short bottom = (short) painter.getInset(BOTTOM, this);
  672. if (top != getTopInset()) {
  673. int h = getTopInset() - top;
  674. a.y += h;
  675. a.height -= h;
  676. } else {
  677. a.height -= getBottomInset() - bottom;
  678. }
  679. }
  680. painter.paint(g, a.x, a.y, a.width, a.height, this);
  681. // paint interior
  682. int n = getViewCount();
  683. for (int i = 0; i < n; i++) {
  684. View v = getView(i);
  685. v.paint(g, getChildAllocation(i, allocation));
  686. }
  687. //super.paint(g, a);
  688. }
  689. /**
  690. * Establishes the parent view for this view. This is
  691. * guaranteed to be called before any other methods if the
  692. * parent view is functioning properly.
  693. * <p>
  694. * This is implemented
  695. * to forward to the superclass as well as call the
  696. * <a href="#setPropertiesFromAttributes">setPropertiesFromAttributes</a>
  697. * method to set the paragraph properties from the css
  698. * attributes. The call is made at this time to ensure
  699. * the ability to resolve upward through the parents
  700. * view attributes.
  701. *
  702. * @param parent the new parent, or null if the view is
  703. * being removed from a parent it was previously added
  704. * to
  705. */
  706. public void setParent(View parent) {
  707. super.setParent(parent);
  708. setPropertiesFromAttributes();
  709. }
  710. /**
  711. * Fetches the ViewFactory implementation that is feeding
  712. * the view hierarchy.
  713. * This replaces the ViewFactory with an implementation that
  714. * calls through to the createTableRow and createTableCell
  715. * methods. If the element given to the factory isn't a
  716. * table row or cell, the request is delegated to the factory
  717. * produced by the superclass behavior.
  718. *
  719. * @return the factory, null if none
  720. */
  721. public ViewFactory getViewFactory() {
  722. return this;
  723. }
  724. /**
  725. * Gives notification that something was inserted into
  726. * the document in a location that this view is responsible for.
  727. * This replaces the ViewFactory with an implementation that
  728. * calls through to the createTableRow and createTableCell
  729. * methods. If the element given to the factory isn't a
  730. * table row or cell, the request is delegated to the factory
  731. * passed as an argument.
  732. *
  733. * @param e the change information from the associated document
  734. * @param a the current allocation of the view
  735. * @param f the factory to use to rebuild if the view has children
  736. * @see View#insertUpdate
  737. */
  738. public void insertUpdate(DocumentEvent e, Shape a, ViewFactory f) {
  739. super.insertUpdate(e, a, this);
  740. }
  741. /**
  742. * Gives notification that something was removed from the document
  743. * in a location that this view is responsible for.
  744. * This replaces the ViewFactory with an implementation that
  745. * calls through to the createTableRow and createTableCell
  746. * methods. If the element given to the factory isn't a
  747. * table row or cell, the request is delegated to the factory
  748. * passed as an argument.
  749. *
  750. * @param e the change information from the associated document
  751. * @param a the current allocation of the view
  752. * @param f the factory to use to rebuild if the view has children
  753. * @see View#removeUpdate
  754. */
  755. public void removeUpdate(DocumentEvent e, Shape a, ViewFactory f) {
  756. super.removeUpdate(e, a, this);
  757. }
  758. /**
  759. * Gives notification from the document that attributes were changed
  760. * in a location that this view is responsible for.
  761. * This replaces the ViewFactory with an implementation that
  762. * calls through to the createTableRow and createTableCell
  763. * methods. If the element given to the factory isn't a
  764. * table row or cell, the request is delegated to the factory
  765. * passed as an argument.
  766. *
  767. * @param e the change information from the associated document
  768. * @param a the current allocation of the view
  769. * @param f the factory to use to rebuild if the view has children
  770. * @see View#changedUpdate
  771. */
  772. public void changedUpdate(DocumentEvent e, Shape a, ViewFactory f) {
  773. super.changedUpdate(e, a, this);
  774. }
  775. protected void forwardUpdate(DocumentEvent.ElementChange ec,
  776. DocumentEvent e, Shape a, ViewFactory f) {
  777. super.forwardUpdate(ec, e, a, f);
  778. // A change in any of the table cells usually effects the whole table,
  779. // so redraw it all!
  780. if (a != null) {
  781. Component c = getContainer();
  782. if (c != null) {
  783. Rectangle alloc = (a instanceof Rectangle) ? (Rectangle)a :
  784. a.getBounds();
  785. c.repaint(alloc.x, alloc.y, alloc.width, alloc.height);
  786. }
  787. }
  788. }
  789. /**
  790. * Change the child views. This is implemented to
  791. * provide the superclass behavior and invalidate the
  792. * grid so that rows and columns will be recalculated.
  793. */
  794. public void replace(int offset, int length, View[] views) {
  795. super.replace(offset, length, views);
  796. invalidateGrid();
  797. }
  798. // --- ViewFactory methods ------------------------------------------
  799. /**
  800. * The table itself acts as a factory for the various
  801. * views that actually represent pieces of the table.
  802. * All other factory activity is delegated to the factory
  803. * returned by the parent of the table.
  804. */
  805. public View create(Element elem) {
  806. Object o = elem.getAttributes().getAttribute(StyleConstants.NameAttribute);
  807. if (o instanceof HTML.Tag) {
  808. HTML.Tag kind = (HTML.Tag) o;
  809. if (kind == HTML.Tag.TR) {
  810. return createTableRow(elem);
  811. } else if ((kind == HTML.Tag.TD) || (kind == HTML.Tag.TH)) {
  812. return new CellView(elem);
  813. } else if (kind == HTML.Tag.CAPTION) {
  814. return new javax.swing.text.html.ParagraphView(elem);
  815. }
  816. }
  817. // default is to delegate to the normal factory
  818. View p = getParent();
  819. if (p != null) {
  820. ViewFactory f = p.getViewFactory();
  821. if (f != null) {
  822. return f.create(elem);
  823. }
  824. }
  825. return null;
  826. }
  827. // ---- variables ----------------------------------------------------
  828. private AttributeSet attr;
  829. private StyleSheet.BoxPainter painter;
  830. private int cellSpacing;
  831. /**
  832. * The index of the caption view if there is a caption.
  833. * This has a value of -1 if there is no caption. The
  834. * caption lives in the inset area of the table, and is
  835. * updated with each time the grid is recalculated.
  836. */
  837. private int captionIndex;
  838. /**
  839. * Do any of the table cells contain a relative size
  840. * specification? This is updated with each call to
  841. * updateGrid(). If this is true, the ColumnIterator
  842. * will do extra work to calculate relative cell
  843. * specifications.
  844. */
  845. private boolean relativeCells;
  846. /**
  847. * Do any of the table cells span multiple rows? If
  848. * true, the RowRequirementIterator will do additional
  849. * work to adjust the requirements of rows spanned by
  850. * a single table cell. This is updated with each call to
  851. * updateGrid().
  852. */
  853. private boolean multiRowCells;
  854. int[] columnSpans;
  855. int[] columnOffsets;
  856. SizeRequirements[] columnRequirements;
  857. RowIterator rowIterator = new RowIterator();
  858. ColumnIterator colIterator = new ColumnIterator();
  859. Vector rows;
  860. boolean gridValid;
  861. static final private BitSet EMPTY = new BitSet();
  862. class ColumnIterator implements CSS.LayoutIterator {
  863. /**
  864. * Disable percentage adjustments which should only apply
  865. * when calculating layout, not requirements.
  866. */
  867. void disablePercentages() {
  868. percentages = null;
  869. }
  870. /**
  871. * Update percentage adjustments if they are needed.
  872. */
  873. private void updatePercentages(int span) {
  874. if (relativeCells) {
  875. percentages = new int[columnRequirements.length];
  876. int nrows = getRowCount();
  877. for (int rowIndex = 0; rowIndex < nrows; rowIndex++) {
  878. RowView row = getRow(rowIndex);
  879. int col = 0;
  880. int ncells = row.getViewCount();
  881. for (int cell = 0; cell < ncells; cell++, col++) {
  882. View cv = row.getView(cell);
  883. for (; row.isFilled(col); col++); // advance to a free column
  884. int rowSpan = getRowsOccupied(cv);
  885. int colSpan = getColumnsOccupied(cv);
  886. AttributeSet a = cv.getAttributes();
  887. CSS.LengthValue lv = (CSS.LengthValue)
  888. a.getAttribute(CSS.Attribute.WIDTH);
  889. if ((lv != null) && (lv.isPercentage())) {
  890. // add a percentage requirement
  891. int len = (int) (lv.getValue(span) / colSpan + 0.5f);
  892. for (int i = 0; i < colSpan; i++) {
  893. percentages[col+i] = Math.max(percentages[col+i], len);
  894. }
  895. }
  896. col += colSpan - 1;
  897. }
  898. }
  899. } else {
  900. percentages = null;
  901. }
  902. }
  903. /**
  904. * Set the layout arrays to use for holding layout results
  905. */
  906. public void setLayoutArrays(int offsets[], int spans[], int targetSpan) {
  907. this.offsets = offsets;
  908. this.spans = spans;
  909. updatePercentages(targetSpan);
  910. }
  911. // --- RequirementIterator methods -------------------
  912. public int getCount() {
  913. return columnRequirements.length;
  914. }
  915. public void setIndex(int i) {
  916. col = i;
  917. }
  918. public void setOffset(int offs) {
  919. offsets[col] = offs;
  920. }
  921. public int getOffset() {
  922. return offsets[col];
  923. }
  924. public void setSpan(int span) {
  925. spans[col] = span;
  926. }
  927. public int getSpan() {
  928. return spans[col];
  929. }
  930. public float getMinimumSpan(float parentSpan) {
  931. if ((percentages != null) && (percentages[col] != 0)) {
  932. return Math.max(percentages[col], columnRequirements[col].minimum);
  933. }
  934. return columnRequirements[col].minimum;
  935. }
  936. public float getPreferredSpan(float parentSpan) {
  937. if ((percentages != null) && (percentages[col] != 0)) {
  938. return Math.max(percentages[col], columnRequirements[col].preferred);
  939. }
  940. return columnRequirements[col].preferred;
  941. }
  942. public float getMaximumSpan(float parentSpan) {
  943. if ((percentages != null) && (percentages[col] != 0)) {
  944. return Math.max(percentages[col], columnRequirements[col].preferred);
  945. }
  946. return columnRequirements[col].maximum;
  947. }
  948. public float getLeadingCollapseSpan() {
  949. return cellSpacing;
  950. }
  951. public float getTrailingCollapseSpan() {
  952. return cellSpacing;
  953. }
  954. /**
  955. * Current column index
  956. */
  957. private int col;
  958. /**
  959. * percentage values (may be null since there
  960. * might not be any).
  961. */
  962. private int[] percentages;
  963. private int[] offsets;
  964. private int[] spans;
  965. }
  966. class RowIterator implements CSS.LayoutIterator {
  967. RowIterator() {
  968. }
  969. void updateAdjustments() {
  970. int axis = Y_AXIS;
  971. if (multiRowCells) {
  972. // adjust requirements of multi-row cells
  973. int n = getRowCount();
  974. adjustments = new int[n];
  975. for (int i = 0; i < n; i++) {
  976. RowView rv = getRow(i);
  977. if (rv.multiRowCells == true) {
  978. int ncells = rv.getViewCount();
  979. for (int j = 0; j < ncells; j++) {
  980. View v = rv.getView(j);
  981. int nrows = getRowsOccupied(v);
  982. if (nrows > 1) {
  983. int spanNeeded = (int) v.getPreferredSpan(axis);
  984. adjustMultiRowSpan(spanNeeded, nrows, i);
  985. }
  986. }
  987. }
  988. }
  989. } else {
  990. adjustments = null;
  991. }
  992. }
  993. /**
  994. * Fixup preferences to accomodate a multi-row table cell
  995. * if not already covered by existing preferences. This is
  996. * a no-op if not all of the rows needed (to do this check/fixup)
  997. * have arrived yet.
  998. */
  999. void adjustMultiRowSpan(int spanNeeded, int nrows, int rowIndex) {
  1000. if ((rowIndex + nrows) > getCount()) {
  1001. // rows are missing (could be a bad rowspan specification)
  1002. // or not all the rows have arrived. Do the best we can with
  1003. // the current set of rows.
  1004. nrows = getCount() - rowIndex;
  1005. if (nrows < 1) {
  1006. return;
  1007. }
  1008. }
  1009. int span = 0;
  1010. for (int i = 0; i < nrows; i++) {
  1011. RowView rv = getRow(rowIndex + i);
  1012. span += rv.getPreferredSpan(Y_AXIS);
  1013. }
  1014. if (spanNeeded > span) {
  1015. int adjust = (spanNeeded - span);
  1016. int rowAdjust = adjust / nrows;
  1017. int firstAdjust = rowAdjust + (adjust - (rowAdjust * nrows));
  1018. RowView rv = getRow(rowIndex);
  1019. adjustments[rowIndex] += firstAdjust;
  1020. for (int i = 1; i < nrows; i++) {
  1021. adjustments[rowIndex + i] += rowAdjust;
  1022. }
  1023. }
  1024. }
  1025. void setLayoutArrays(int[] offsets, int[] spans) {
  1026. this.offsets = offsets;
  1027. this.spans = spans;
  1028. }
  1029. // --- RequirementIterator methods -------------------
  1030. public void setOffset(int offs) {
  1031. RowView rv = getRow(row);
  1032. if (rv != null) {
  1033. offsets[rv.viewIndex] = offs;
  1034. }
  1035. }
  1036. public int getOffset() {
  1037. RowView rv = getRow(row);
  1038. if (rv != null) {
  1039. return offsets[rv.viewIndex];
  1040. }
  1041. return 0;
  1042. }
  1043. public void setSpan(int span) {
  1044. RowView rv = getRow(row);
  1045. if (rv != null) {
  1046. spans[rv.viewIndex] = span;
  1047. }
  1048. }
  1049. public int getSpan() {
  1050. RowView rv = getRow(row);
  1051. if (rv != null) {
  1052. return spans[rv.viewIndex];
  1053. }
  1054. return 0;
  1055. }
  1056. public int getCount() {
  1057. return rows.size();
  1058. }
  1059. public void setIndex(int i) {
  1060. row = i;
  1061. }
  1062. public float getMinimumSpan(float parentSpan) {
  1063. return getPreferredSpan(parentSpan);
  1064. }
  1065. public float getPreferredSpan(float parentSpan) {
  1066. RowView rv = getRow(row);
  1067. if (rv != null) {
  1068. int adjust = (adjustments != null) ? adjustments[row] : 0;
  1069. adjust += 2 * cellSpacing;
  1070. return rv.getPreferredSpan(TableView.this.getAxis()) + adjust;
  1071. }
  1072. return 0;
  1073. }
  1074. public float getMaximumSpan(float parentSpan) {
  1075. return getPreferredSpan(parentSpan);
  1076. }
  1077. public float getLeadingCollapseSpan() {
  1078. return cellSpacing;
  1079. }
  1080. public float getTrailingCollapseSpan() {
  1081. return cellSpacing;
  1082. }
  1083. /**
  1084. * Current row index
  1085. */
  1086. private int row;
  1087. /**
  1088. * Adjustments to the row requirements to handle multi-row
  1089. * table cells.
  1090. */
  1091. private int[] adjustments;
  1092. private int[] offsets;
  1093. private int[] spans;
  1094. }
  1095. /**
  1096. * View of a row in a row-centric table.
  1097. */
  1098. public class RowView extends BoxView {
  1099. /**
  1100. * Constructs a TableView for the given element.
  1101. *
  1102. * @param elem the element that this view is responsible for
  1103. */
  1104. public RowView(Element elem) {
  1105. super(elem, View.X_AXIS);
  1106. fillColumns = new BitSet();
  1107. RowView.this.setPropertiesFromAttributes();
  1108. }
  1109. void clearFilledColumns() {
  1110. fillColumns.and(EMPTY);
  1111. }
  1112. void fillColumn(int col) {
  1113. fillColumns.set(col);
  1114. }
  1115. boolean isFilled(int col) {
  1116. return fillColumns.get(col);
  1117. }
  1118. /**
  1119. * The number of columns present in this row.
  1120. */
  1121. int getColumnCount() {
  1122. int nfill = 0;
  1123. int n = fillColumns.size();
  1124. for (int i = 0; i < n; i++) {
  1125. if (fillColumns.get(i)) {
  1126. nfill ++;
  1127. }
  1128. }
  1129. return getViewCount() + nfill;
  1130. }
  1131. /**
  1132. * Fetches the attributes to use when rendering. This is
  1133. * implemented to multiplex the attributes specified in the
  1134. * model with a StyleSheet.
  1135. */
  1136. public AttributeSet getAttributes() {
  1137. return attr;
  1138. }
  1139. protected StyleSheet getStyleSheet() {
  1140. HTMLDocument doc = (HTMLDocument) getDocument();
  1141. return doc.getStyleSheet();
  1142. }
  1143. /**
  1144. * This is called by a child to indicate its
  1145. * preferred span has changed. This is implemented to
  1146. * execute the superclass behavior and well as try to
  1147. * determine if a row with a multi-row cell hangs across
  1148. * this row. If a multi-row cell covers this row it also
  1149. * needs to propagate a preferenceChanged so that it will
  1150. * recalculate the multi-row cell.
  1151. *
  1152. * @param child the child view
  1153. * @param width true if the width preference should change
  1154. * @param height true if the height preference should change
  1155. */
  1156. public void preferenceChanged(View child, boolean width, boolean height) {
  1157. super.preferenceChanged(child, width, height);
  1158. if (TableView.this.multiRowCells && height) {
  1159. for (int i = rowIndex - 1; i >= 0; i--) {
  1160. RowView rv = TableView.this.getRow(i);
  1161. if (rv.multiRowCells) {
  1162. rv.preferenceChanged(null, false, true);
  1163. break;
  1164. }
  1165. }
  1166. }
  1167. }
  1168. public void changedUpdate(DocumentEvent e, Shape a, ViewFactory f) {
  1169. super.changedUpdate(e, a, f);
  1170. int pos = e.getOffset();
  1171. if (pos <= getStartOffset() && (pos + e.getLength()) >=
  1172. getEndOffset()) {
  1173. RowView.this.setPropertiesFromAttributes();
  1174. }
  1175. }
  1176. /**
  1177. * Renders using the given rendering surface and area on that
  1178. * surface. This is implemented to delegate to the css box
  1179. * painter to paint the border and background prior to the
  1180. * interior.
  1181. *
  1182. * @param g the rendering surface to use
  1183. * @param allocation the allocated region to render into
  1184. * @see View#paint
  1185. */
  1186. public void paint(Graphics g, Shape allocation) {
  1187. Rectangle a = (Rectangle) allocation;
  1188. painter.paint(g, a.x, a.y, a.width, a.height, this);
  1189. super.paint(g, a);
  1190. }
  1191. /**
  1192. * Change the child views. This is implemented to
  1193. * provide the superclass behavior and invalidate the
  1194. * grid so that rows and columns will be recalculated.
  1195. */
  1196. public void replace(int offset, int length, View[] views) {
  1197. super.replace(offset, length, views);
  1198. invalidateGrid();
  1199. }
  1200. /**
  1201. * Calculate the height requirements of the table row. The
  1202. * requirements of multi-row cells are not considered for this
  1203. * calculation. The table itself will check and adjust the row
  1204. * requirements for all the rows that have multi-row cells spanning
  1205. * them. This method updates the multi-row flag that indicates that
  1206. * this row and rows below need additional consideration.
  1207. */
  1208. protected SizeRequirements calculateMinorAxisRequirements(int axis, SizeRequirements r) {
  1209. // return super.calculateMinorAxisRequirements(axis, r);
  1210. long min = 0;
  1211. long pref = 0;
  1212. long max = 0;
  1213. multiRowCells = false;
  1214. int n = getViewCount();
  1215. for (int i = 0; i < n; i++) {
  1216. View v = getView(i);
  1217. if (getRowsOccupied(v) > 1) {
  1218. multiRowCells = true;
  1219. max = Math.max((int) v.getMaximumSpan(axis), max);
  1220. } else {
  1221. min = Math.max((int) v.getMinimumSpan(axis), min);
  1222. pref = Math.max((int) v.getPreferredSpan(axis), pref);
  1223. max = Math.max((int) v.getMaximumSpan(axis), max);
  1224. }
  1225. }
  1226. if (r == null) {
  1227. r = new SizeRequirements();
  1228. r.alignment = 0.5f;
  1229. }
  1230. r.preferred = (int) pref;
  1231. r.minimum = (int) min;
  1232. r.maximum = (int) max;
  1233. return r;
  1234. }
  1235. /**
  1236. * Perform layout for the major axis of the box (i.e. the
  1237. * axis that it represents). The results of the layout should
  1238. * be placed in the given arrays which represent the allocations
  1239. * to the children along the major axis.
  1240. * <p>
  1241. * This is re-implemented to give each child the span of the column
  1242. * width for the table, and to give cells that span multiple columns
  1243. * the multi-column span.
  1244. *
  1245. * @param targetSpan the total span given to the view, which
  1246. * whould be used to layout the children.
  1247. * @param axis the axis being layed out.
  1248. * @param offsets the offsets from the origin of the view for
  1249. * each of the child views. This is a return value and is
  1250. * filled in by the implementation of this method.
  1251. * @param spans the span of each child view. This is a return
  1252. * value and is filled in by the implementation of this method.
  1253. * @returns the offset and span for each child view in the
  1254. * offsets and spans parameters.
  1255. */
  1256. protected void layoutMajorAxis(int targetSpan, int axis, int[] offsets, int[] spans) {
  1257. int col = 0;
  1258. int ncells = getViewCount();
  1259. for (int cell = 0; cell < ncells; cell++, col++) {
  1260. View cv = getView(cell);
  1261. for (; isFilled(col); col++); // advance to a free column
  1262. int colSpan = getColumnsOccupied(cv);
  1263. spans[cell] = columnSpans[col];
  1264. offsets[cell] = columnOffsets[col];
  1265. if (colSpan > 1) {
  1266. int n = columnSpans.length;
  1267. for (int j = 1; j < colSpan; j++) {
  1268. // Because the table may be only partially formed, some
  1269. // of the columns may not yet exist. Therefore we check
  1270. // the bounds.
  1271. if ((col+j) < n) {
  1272. spans[cell] += columnSpans[col+j];
  1273. }
  1274. }
  1275. col += colSpan - 1;
  1276. }
  1277. }
  1278. }
  1279. /**
  1280. * Perform layout for the minor axis of the box (i.e. the
  1281. * axis orthoginal to the axis that it represents). The results
  1282. * of the layout should be placed in the given arrays which represent
  1283. * the allocations to the children along the minor axis. This
  1284. * is called by the superclass whenever the layout needs to be
  1285. * updated along the minor axis.
  1286. * <p>
  1287. * This is implemented to delegate to the superclass, then adjust
  1288. * the span for any cell that spans multiple rows.
  1289. *
  1290. * @param targetSpan the total span given to the view, which
  1291. * whould be used to layout the children.
  1292. * @param axis the axis being layed out.
  1293. * @param offsets the offsets from the origin of the view for
  1294. * each of the child views. This is a return value and is
  1295. * filled in by the implementation of this method.
  1296. * @param spans the span of each child view. This is a return
  1297. * value and is filled in by the implementation of this method.
  1298. * @returns the offset and span for each child view in the
  1299. * offsets and spans parameters.
  1300. */
  1301. protected void layoutMinorAxis(int targetSpan, int axis, int[] offsets, int[] spans) {
  1302. super.layoutMinorAxis(targetSpan, axis, offsets, spans);
  1303. int col = 0;
  1304. int ncells = getViewCount();
  1305. for (int cell = 0; cell < ncells; cell++, col++) {
  1306. View cv = getView(cell);
  1307. for (; isFilled(col); col++); // advance to a free column
  1308. int colSpan = getColumnsOccupied(cv);
  1309. int rowSpan = getRowsOccupied(cv);
  1310. if (rowSpan > 1) {
  1311. int row0 = rowIndex;
  1312. int row1 = Math.min(rowIndex + rowSpan - 1, getRowCount()-1);
  1313. spans[cell] = getMultiRowSpan(row0, row1);
  1314. }
  1315. if (colSpan > 1) {
  1316. col += colSpan - 1;
  1317. }
  1318. }
  1319. }
  1320. /**
  1321. * Determines the resizability of the view along the
  1322. * given axis. A value of 0 or less is not resizable.
  1323. *
  1324. * @param axis may be either View.X_AXIS or View.Y_AXIS
  1325. * @return the resize weight
  1326. * @exception IllegalArgumentException for an invalid axis
  1327. */
  1328. public int getResizeWeight(int axis) {
  1329. return 1;
  1330. }
  1331. /**
  1332. * Fetches the child view that represents the given position in
  1333. * the model. This is implemented to walk through the children
  1334. * looking for a range that contains the given position. In this
  1335. * view the children do not necessarily have a one to one mapping
  1336. * with the child elements.
  1337. *
  1338. * @param pos the search position >= 0
  1339. * @param a the allocation to the table on entry, and the
  1340. * allocation of the view containing the position on exit
  1341. * @returns the view representing the given position, or
  1342. * null if there isn't one
  1343. */
  1344. protected View getViewAtPosition(int pos, Rectangle a) {
  1345. int n = getViewCount();
  1346. for (int i = 0; i < n; i++) {
  1347. View v = getView(i);
  1348. int p0 = v.getStartOffset();
  1349. int p1 = v.getEndOffset();
  1350. if ((pos >= p0) && (pos < p1)) {
  1351. // it's in this view.
  1352. if (a != null) {
  1353. childAllocation(i, a);
  1354. }
  1355. return v;
  1356. }
  1357. }
  1358. if (pos == getEndOffset()) {
  1359. View v = getView(n - 1);
  1360. if (a != null) {
  1361. this.childAllocation(n - 1, a);
  1362. }
  1363. return v;
  1364. }
  1365. return null;
  1366. }
  1367. /**
  1368. * Update any cached values that come from attributes.
  1369. */
  1370. void setPropertiesFromAttributes() {
  1371. StyleSheet sheet = getStyleSheet();
  1372. attr = sheet.getViewAttributes(this);
  1373. painter = sheet.getBoxPainter(attr);
  1374. }
  1375. private StyleSheet.BoxPainter painter;
  1376. private AttributeSet attr;
  1377. /** columns filled by multi-column or multi-row cells */
  1378. BitSet fillColumns;
  1379. /**
  1380. * The row index within the overall grid
  1381. */
  1382. int rowIndex;
  1383. /**
  1384. * The view index (for row index to view index conversion).
  1385. * This is set by the updateGrid method.
  1386. */
  1387. int viewIndex;
  1388. /**
  1389. * Does this table row have cells that span multiple rows?
  1390. */
  1391. boolean multiRowCells;
  1392. }
  1393. /**
  1394. * Default view of an html table cell. This needs to be moved
  1395. * somewhere else.
  1396. */
  1397. class CellView extends BlockView {
  1398. /**
  1399. * Constructs a TableCell for the given element.
  1400. *
  1401. * @param elem the element that this view is responsible for
  1402. */
  1403. public CellView(Element elem) {
  1404. super(elem, Y_AXIS);
  1405. }
  1406. /**
  1407. * Perform layout for the major axis of the box (i.e. the
  1408. * axis that it represents). The results of the layout should
  1409. * be placed in the given arrays which represent the allocations
  1410. * to the children along the major axis. This is called by the
  1411. * superclass to recalculate the positions of the child views
  1412. * when the layout might have changed.
  1413. * <p>
  1414. * This is implemented to delegate to the superclass to
  1415. * tile the children. If the target span is greater than
  1416. * was needed, the offsets are adjusted to align the children
  1417. * (i.e. position according to the html valign attribute).
  1418. *
  1419. * @param targetSpan the total span given to the view, which
  1420. * whould be used to layout the children.
  1421. * @param axis the axis being layed out.
  1422. * @param offsets the offsets from the origin of the view for
  1423. * each of the child views. This is a return value and is
  1424. * filled in by the implementation of this method.
  1425. * @param spans the span of each child view. This is a return
  1426. * value and is filled in by the implementation of this method.
  1427. * @returns the offset and span for each child view in the
  1428. * offsets and spans parameters.
  1429. */
  1430. protected void layoutMajorAxis(int targetSpan, int axis, int[] offsets, int[] spans) {
  1431. super.layoutMajorAxis(targetSpan, axis, offsets, spans);
  1432. // calculate usage
  1433. int used = 0;
  1434. int n = spans.length;
  1435. for (int i = 0; i < n; i++) {
  1436. used += spans[i];
  1437. }
  1438. // calculate adjustments
  1439. int adjust = 0;
  1440. if (used < targetSpan) {
  1441. // PENDING(prinz) change to use the css alignment.
  1442. String valign = (String) getElement().getAttributes().getAttribute(
  1443. HTML.Attribute.VALIGN);
  1444. if (valign == null) {
  1445. AttributeSet rowAttr = getElement().getParentElement().getAttributes();
  1446. valign = (String) rowAttr.getAttribute(HTML.Attribute.VALIGN);
  1447. }
  1448. if ((valign == null) || valign.equals("middle")) {
  1449. adjust = (targetSpan - used) / 2;
  1450. } else if (valign.equals("bottom")) {
  1451. adjust = targetSpan - used;
  1452. }
  1453. }
  1454. // make adjustments.
  1455. if (adjust != 0) {
  1456. for (int i = 0; i < n; i++) {
  1457. offsets[i] += adjust;
  1458. }
  1459. }
  1460. }
  1461. /**
  1462. * Calculate the requirements needed along the major axis.
  1463. * This is called by the superclass whenever the requirements
  1464. * need to be updated (i.e. a preferenceChanged was messaged
  1465. * through this view).
  1466. * <p>
  1467. * This is implemented to delegate to the superclass, but
  1468. * indicate the maximum size is very large (i.e. the cell
  1469. * is willing to expend to occupy the full height of the row).
  1470. *
  1471. * @param axis the axis being layed out.
  1472. * @param r the requirements to fill in. If null, a new one
  1473. * should be allocated.
  1474. */
  1475. protected SizeRequirements calculateMajorAxisRequirements(int axis,
  1476. SizeRequirements r) {
  1477. SizeRequirements req = super.calculateMajorAxisRequirements(axis, r);
  1478. req.maximum = Integer.MAX_VALUE;
  1479. return req;
  1480. }
  1481. }
  1482. }