1. /*
  2. * @(#)TableView.java 1.33 04/05/18
  3. *
  4. * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
  5. * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
  6. */
  7. package javax.swing.text;
  8. import java.awt.*;
  9. import java.util.BitSet;
  10. import java.util.Vector;
  11. import javax.swing.SizeRequirements;
  12. import javax.swing.event.DocumentEvent;
  13. import javax.swing.text.html.HTML;
  14. /**
  15. * <p>
  16. * Implements View interface for a table, that is composed of an
  17. * element structure where the child elements of the element
  18. * this view is responsible for represent rows and the child
  19. * elements of the row elements are cells. The cell elements can
  20. * have an arbitrary element structure under them, which will
  21. * be built with the ViewFactory returned by the getViewFactory
  22. * method.
  23. * <pre>
  24. *
  25. *   TABLE
  26. *   ROW
  27. *   CELL
  28. *   CELL
  29. *   ROW
  30. *   CELL
  31. *   CELL
  32. *
  33. * </pre>
  34. * <p>
  35. * This is implemented as a hierarchy of boxes, the table itself
  36. * is a vertical box, the rows are horizontal boxes, and the cells
  37. * are vertical boxes. The cells are allowed to span multiple
  38. * columns and rows. By default, the table can be thought of as
  39. * being formed over a grid (i.e. somewhat like one would find in
  40. * gridbag layout), where table cells can request to span more
  41. * than one grid cell. The default horizontal span of table cells
  42. * will be based upon this grid, but can be changed by reimplementing
  43. * the requested span of the cell (i.e. table cells can have independant
  44. * spans if desired).
  45. *
  46. * @author Timothy Prinzing
  47. * @version 1.33 05/18/04
  48. * @see View
  49. */
  50. public abstract class TableView extends BoxView {
  51. /**
  52. * Constructs a TableView for the given element.
  53. *
  54. * @param elem the element that this view is responsible for
  55. */
  56. public TableView(Element elem) {
  57. super(elem, View.Y_AXIS);
  58. rows = new Vector();
  59. gridValid = false;
  60. }
  61. /**
  62. * Creates a new table row.
  63. *
  64. * @param elem an element
  65. * @return the row
  66. */
  67. protected TableRow createTableRow(Element elem) {
  68. return new TableRow(elem);
  69. }
  70. /**
  71. * @deprecated Table cells can now be any arbitrary
  72. * View implementation and should be produced by the
  73. * ViewFactory rather than the table.
  74. *
  75. * @param elem an element
  76. * @return the cell
  77. */
  78. @Deprecated
  79. protected TableCell createTableCell(Element elem) {
  80. return new TableCell(elem);
  81. }
  82. /**
  83. * The number of columns in the table.
  84. */
  85. int getColumnCount() {
  86. return columnSpans.length;
  87. }
  88. /**
  89. * Fetches the span (width) of the given column.
  90. * This is used by the nested cells to query the
  91. * sizes of grid locations outside of themselves.
  92. */
  93. int getColumnSpan(int col) {
  94. return columnSpans[col];
  95. }
  96. /**
  97. * The number of rows in the table.
  98. */
  99. int getRowCount() {
  100. return rows.size();
  101. }
  102. /**
  103. * Fetches the span (height) of the given row.
  104. */
  105. int getRowSpan(int row) {
  106. View rv = getRow(row);
  107. if (rv != null) {
  108. return (int) rv.getPreferredSpan(Y_AXIS);
  109. }
  110. return 0;
  111. }
  112. TableRow getRow(int row) {
  113. if (row < rows.size()) {
  114. return (TableRow) rows.elementAt(row);
  115. }
  116. return null;
  117. }
  118. /**
  119. * Determines the number of columns occupied by
  120. * the table cell represented by given element.
  121. */
  122. /*protected*/ int getColumnsOccupied(View v) {
  123. // PENDING(prinz) this code should be in the html
  124. // paragraph, but we can't add api to enable it.
  125. AttributeSet a = v.getElement().getAttributes();
  126. String s = (String) a.getAttribute(HTML.Attribute.COLSPAN);
  127. if (s != null) {
  128. try {
  129. return Integer.parseInt(s);
  130. } catch (NumberFormatException nfe) {
  131. // fall through to one column
  132. }
  133. }
  134. return 1;
  135. }
  136. /**
  137. * Determines the number of rows occupied by
  138. * the table cell represented by given element.
  139. */
  140. /*protected*/ int getRowsOccupied(View v) {
  141. // PENDING(prinz) this code should be in the html
  142. // paragraph, but we can't add api to enable it.
  143. AttributeSet a = v.getElement().getAttributes();
  144. String s = (String) a.getAttribute(HTML.Attribute.ROWSPAN);
  145. if (s != null) {
  146. try {
  147. return Integer.parseInt(s);
  148. } catch (NumberFormatException nfe) {
  149. // fall through to one row
  150. }
  151. }
  152. return 1;
  153. }
  154. /*protected*/ void invalidateGrid() {
  155. gridValid = false;
  156. }
  157. protected void forwardUpdate(DocumentEvent.ElementChange ec,
  158. DocumentEvent e, Shape a, ViewFactory f) {
  159. super.forwardUpdate(ec, e, a, f);
  160. // A change in any of the table cells usually effects the whole table,
  161. // so redraw it all!
  162. if (a != null) {
  163. Component c = getContainer();
  164. if (c != null) {
  165. Rectangle alloc = (a instanceof Rectangle) ? (Rectangle)a :
  166. a.getBounds();
  167. c.repaint(alloc.x, alloc.y, alloc.width, alloc.height);
  168. }
  169. }
  170. }
  171. /**
  172. * Change the child views. This is implemented to
  173. * provide the superclass behavior and invalidate the
  174. * grid so that rows and columns will be recalculated.
  175. */
  176. public void replace(int offset, int length, View[] views) {
  177. super.replace(offset, length, views);
  178. invalidateGrid();
  179. }
  180. /**
  181. * Fill in the grid locations that are placeholders
  182. * for multi-column, multi-row, and missing grid
  183. * locations.
  184. */
  185. void updateGrid() {
  186. if (! gridValid) {
  187. // determine which views are table rows and clear out
  188. // grid points marked filled.
  189. rows.removeAllElements();
  190. int n = getViewCount();
  191. for (int i = 0; i < n; i++) {
  192. View v = getView(i);
  193. if (v instanceof TableRow) {
  194. rows.addElement(v);
  195. TableRow rv = (TableRow) v;
  196. rv.clearFilledColumns();
  197. rv.setRow(i);
  198. }
  199. }
  200. int maxColumns = 0;
  201. int nrows = rows.size();
  202. for (int row = 0; row < nrows; row++) {
  203. TableRow rv = getRow(row);
  204. int col = 0;
  205. for (int cell = 0; cell < rv.getViewCount(); cell++, col++) {
  206. View cv = rv.getView(cell);
  207. // advance to a free column
  208. for (; rv.isFilled(col); col++);
  209. int rowSpan = getRowsOccupied(cv);
  210. int colSpan = getColumnsOccupied(cv);
  211. if ((colSpan > 1) || (rowSpan > 1)) {
  212. // fill in the overflow entries for this cell
  213. int rowLimit = row + rowSpan;
  214. int colLimit = col + colSpan;
  215. for (int i = row; i < rowLimit; i++) {
  216. for (int j = col; j < colLimit; j++) {
  217. if (i != row || j != col) {
  218. addFill(i, j);
  219. }
  220. }
  221. }
  222. if (colSpan > 1) {
  223. col += colSpan - 1;
  224. }
  225. }
  226. }
  227. maxColumns = Math.max(maxColumns, col);
  228. }
  229. // setup the column layout/requirements
  230. columnSpans = new int[maxColumns];
  231. columnOffsets = new int[maxColumns];
  232. columnRequirements = new SizeRequirements[maxColumns];
  233. for (int i = 0; i < maxColumns; i++) {
  234. columnRequirements[i] = new SizeRequirements();
  235. }
  236. gridValid = true;
  237. }
  238. }
  239. /**
  240. * Mark a grid location as filled in for a cells overflow.
  241. */
  242. void addFill(int row, int col) {
  243. TableRow rv = getRow(row);
  244. if (rv != null) {
  245. rv.fillColumn(col);
  246. }
  247. }
  248. /**
  249. * Layout the columns to fit within the given target span.
  250. *
  251. * @param targetSpan the given span for total of all the table
  252. * columns.
  253. * @param reqs the requirements desired for each column. This
  254. * is the column maximum of the cells minimum, preferred, and
  255. * maximum requested span.
  256. * @param spans the return value of how much to allocated to
  257. * each column.
  258. * @param offsets the return value of the offset from the
  259. * origin for each column.
  260. * @return the offset from the origin and the span for each column
  261. * in the offsets and spans parameters
  262. */
  263. protected void layoutColumns(int targetSpan, int[] offsets, int[] spans,
  264. SizeRequirements[] reqs) {
  265. // allocate using the convenience method on SizeRequirements
  266. SizeRequirements.calculateTiledPositions(targetSpan, null, reqs,
  267. offsets, spans);
  268. }
  269. /**
  270. * Perform layout for the minor axis of the box (i.e. the
  271. * axis orthoginal to the axis that it represents). The results
  272. * of the layout should be placed in the given arrays which represent
  273. * the allocations to the children along the minor axis. This
  274. * is called by the superclass whenever the layout needs to be
  275. * updated along the minor axis.
  276. * <p>
  277. * This is implemented to call the
  278. * <a href="#layoutColumns">layoutColumns</a> method, and then
  279. * forward to the superclass to actually carry out the layout
  280. * of the tables rows.
  281. *
  282. * @param targetSpan the total span given to the view, which
  283. * whould be used to layout the children.
  284. * @param axis the axis being layed out.
  285. * @param offsets the offsets from the origin of the view for
  286. * each of the child views. This is a return value and is
  287. * filled in by the implementation of this method.
  288. * @param spans the span of each child view. This is a return
  289. * value and is filled in by the implementation of this method.
  290. * @return the offset and span for each child view in the
  291. * offsets and spans parameters
  292. */
  293. protected void layoutMinorAxis(int targetSpan, int axis, int[] offsets, int[] spans) {
  294. // make grid is properly represented
  295. updateGrid();
  296. // all of the row layouts are invalid, so mark them that way
  297. int n = getRowCount();
  298. for (int i = 0; i < n; i++) {
  299. TableRow row = getRow(i);
  300. row.layoutChanged(axis);
  301. }
  302. // calculate column spans
  303. layoutColumns(targetSpan, columnOffsets, columnSpans, columnRequirements);
  304. // continue normal layout
  305. super.layoutMinorAxis(targetSpan, axis, offsets, spans);
  306. }
  307. /**
  308. * Calculate the requirements for the minor axis. This is called by
  309. * the superclass whenever the requirements need to be updated (i.e.
  310. * a preferenceChanged was messaged through this view).
  311. * <p>
  312. * This is implemented to calculate the requirements as the sum of the
  313. * requirements of the columns.
  314. */
  315. protected SizeRequirements calculateMinorAxisRequirements(int axis, SizeRequirements r) {
  316. updateGrid();
  317. // calculate column requirements for each column
  318. calculateColumnRequirements(axis);
  319. // the requirements are the sum of the columns.
  320. if (r == null) {
  321. r = new SizeRequirements();
  322. }
  323. long min = 0;
  324. long pref = 0;
  325. long max = 0;
  326. for (int i = 0; i < columnRequirements.length; i++) {
  327. SizeRequirements req = columnRequirements[i];
  328. min += req.minimum;
  329. pref += req.preferred;
  330. max += req.maximum;
  331. }
  332. r.minimum = (int) min;
  333. r.preferred = (int) pref;
  334. r.maximum = (int) max;
  335. r.alignment = 0;
  336. return r;
  337. }
  338. /*
  339. boolean shouldTrace() {
  340. AttributeSet a = getElement().getAttributes();
  341. Object o = a.getAttribute(HTML.Attribute.ID);
  342. if ((o != null) && o.equals("debug")) {
  343. return true;
  344. }
  345. return false;
  346. }
  347. */
  348. /**
  349. * Calculate the requirements for each column. The calculation
  350. * is done as two passes over the table. The table cells that
  351. * occupy a single column are scanned first to determine the
  352. * maximum of minimum, preferred, and maximum spans along the
  353. * give axis. Table cells that span multiple columns are excluded
  354. * from the first pass. A second pass is made to determine if
  355. * the cells that span multiple columns are satisfied. If the
  356. * column requirements are not satisified, the needs of the
  357. * multi-column cell is mixed into the existing column requirements.
  358. * The calculation of the multi-column distribution is based upon
  359. * the proportions of the existing column requirements and taking
  360. * into consideration any constraining maximums.
  361. */
  362. void calculateColumnRequirements(int axis) {
  363. // pass 1 - single column cells
  364. boolean hasMultiColumn = false;
  365. int nrows = getRowCount();
  366. for (int i = 0; i < nrows; i++) {
  367. TableRow row = getRow(i);
  368. int col = 0;
  369. int ncells = row.getViewCount();
  370. for (int cell = 0; cell < ncells; cell++, col++) {
  371. View cv = row.getView(cell);
  372. for (; row.isFilled(col); col++); // advance to a free column
  373. int rowSpan = getRowsOccupied(cv);
  374. int colSpan = getColumnsOccupied(cv);
  375. if (colSpan == 1) {
  376. checkSingleColumnCell(axis, col, cv);
  377. } else {
  378. hasMultiColumn = true;
  379. col += colSpan - 1;
  380. }
  381. }
  382. }
  383. // pass 2 - multi-column cells
  384. if (hasMultiColumn) {
  385. for (int i = 0; i < nrows; i++) {
  386. TableRow row = getRow(i);
  387. int col = 0;
  388. int ncells = row.getViewCount();
  389. for (int cell = 0; cell < ncells; cell++, col++) {
  390. View cv = row.getView(cell);
  391. for (; row.isFilled(col); col++); // advance to a free column
  392. int colSpan = getColumnsOccupied(cv);
  393. if (colSpan > 1) {
  394. checkMultiColumnCell(axis, col, colSpan, cv);
  395. col += colSpan - 1;
  396. }
  397. }
  398. }
  399. }
  400. /*
  401. if (shouldTrace()) {
  402. System.err.println("calc:");
  403. for (int i = 0; i < columnRequirements.length; i++) {
  404. System.err.println(" " + i + ": " + columnRequirements[i]);
  405. }
  406. }
  407. */
  408. }
  409. /**
  410. * check the requirements of a table cell that spans a single column.
  411. */
  412. void checkSingleColumnCell(int axis, int col, View v) {
  413. SizeRequirements req = columnRequirements[col];
  414. req.minimum = Math.max((int) v.getMinimumSpan(axis), req.minimum);
  415. req.preferred = Math.max((int) v.getPreferredSpan(axis), req.preferred);
  416. req.maximum = Math.max((int) v.getMaximumSpan(axis), req.maximum);
  417. }
  418. /**
  419. * check the requirements of a table cell that spans multiple
  420. * columns.
  421. */
  422. void checkMultiColumnCell(int axis, int col, int ncols, View v) {
  423. // calculate the totals
  424. long min = 0;
  425. long pref = 0;
  426. long max = 0;
  427. for (int i = 0; i < ncols; i++) {
  428. SizeRequirements req = columnRequirements[col + i];
  429. min += req.minimum;
  430. pref += req.preferred;
  431. max += req.maximum;
  432. }
  433. // check if the minimum size needs adjustment.
  434. int cmin = (int) v.getMinimumSpan(axis);
  435. if (cmin > min) {
  436. /*
  437. * the columns that this cell spans need adjustment to fit
  438. * this table cell.... calculate the adjustments. The
  439. * maximum for each cell is the maximum of the existing
  440. * maximum or the amount needed by the cell.
  441. */
  442. SizeRequirements[] reqs = new SizeRequirements[ncols];
  443. for (int i = 0; i < ncols; i++) {
  444. SizeRequirements r = reqs[i] = columnRequirements[col + i];
  445. r.maximum = Math.max(r.maximum, (int) v.getMaximumSpan(axis));
  446. }
  447. int[] spans = new int[ncols];
  448. int[] offsets = new int[ncols];
  449. SizeRequirements.calculateTiledPositions(cmin, null, reqs,
  450. offsets, spans);
  451. // apply the adjustments
  452. for (int i = 0; i < ncols; i++) {
  453. SizeRequirements req = reqs[i];
  454. req.minimum = Math.max(spans[i], req.minimum);
  455. req.preferred = Math.max(req.minimum, req.preferred);
  456. req.maximum = Math.max(req.preferred, req.maximum);
  457. }
  458. }
  459. // check if the preferred size needs adjustment.
  460. int cpref = (int) v.getPreferredSpan(axis);
  461. if (cpref > pref) {
  462. /*
  463. * the columns that this cell spans need adjustment to fit
  464. * this table cell.... calculate the adjustments. The
  465. * maximum for each cell is the maximum of the existing
  466. * maximum or the amount needed by the cell.
  467. */
  468. SizeRequirements[] reqs = new SizeRequirements[ncols];
  469. for (int i = 0; i < ncols; i++) {
  470. SizeRequirements r = reqs[i] = columnRequirements[col + i];
  471. }
  472. int[] spans = new int[ncols];
  473. int[] offsets = new int[ncols];
  474. SizeRequirements.calculateTiledPositions(cpref, null, reqs,
  475. offsets, spans);
  476. // apply the adjustments
  477. for (int i = 0; i < ncols; i++) {
  478. SizeRequirements req = reqs[i];
  479. req.preferred = Math.max(spans[i], req.preferred);
  480. req.maximum = Math.max(req.preferred, req.maximum);
  481. }
  482. }
  483. }
  484. /**
  485. * Fetches the child view that represents the given position in
  486. * the model. This is implemented to walk through the children
  487. * looking for a range that contains the given position. In this
  488. * view the children do not necessarily have a one to one mapping
  489. * with the child elements.
  490. *
  491. * @param pos the search position >= 0
  492. * @param a the allocation to the table on entry, and the
  493. * allocation of the view containing the position on exit
  494. * @return the view representing the given position, or
  495. * <code>null</code> if there isn't one
  496. */
  497. protected View getViewAtPosition(int pos, Rectangle a) {
  498. int n = getViewCount();
  499. for (int i = 0; i < n; i++) {
  500. View v = getView(i);
  501. int p0 = v.getStartOffset();
  502. int p1 = v.getEndOffset();
  503. if ((pos >= p0) && (pos < p1)) {
  504. // it's in this view.
  505. if (a != null) {
  506. childAllocation(i, a);
  507. }
  508. return v;
  509. }
  510. }
  511. if (pos == getEndOffset()) {
  512. View v = getView(n - 1);
  513. if (a != null) {
  514. this.childAllocation(n - 1, a);
  515. }
  516. return v;
  517. }
  518. return null;
  519. }
  520. // ---- variables ----------------------------------------------------
  521. int[] columnSpans;
  522. int[] columnOffsets;
  523. SizeRequirements[] columnRequirements;
  524. Vector rows;
  525. boolean gridValid;
  526. static final private BitSet EMPTY = new BitSet();
  527. /**
  528. * View of a row in a row-centric table.
  529. */
  530. public class TableRow extends BoxView {
  531. /**
  532. * Constructs a TableView for the given element.
  533. *
  534. * @param elem the element that this view is responsible for
  535. */
  536. public TableRow(Element elem) {
  537. super(elem, View.X_AXIS);
  538. fillColumns = new BitSet();
  539. }
  540. void clearFilledColumns() {
  541. fillColumns.and(EMPTY);
  542. }
  543. void fillColumn(int col) {
  544. fillColumns.set(col);
  545. }
  546. boolean isFilled(int col) {
  547. return fillColumns.get(col);
  548. }
  549. /** get location in the overall set of rows */
  550. int getRow() {
  551. return row;
  552. }
  553. /**
  554. * set location in the overall set of rows, this is
  555. * set by the TableView.updateGrid() method.
  556. */
  557. void setRow(int row) {
  558. this.row = row;
  559. }
  560. /**
  561. * The number of columns present in this row.
  562. */
  563. int getColumnCount() {
  564. int nfill = 0;
  565. int n = fillColumns.size();
  566. for (int i = 0; i < n; i++) {
  567. if (fillColumns.get(i)) {
  568. nfill ++;
  569. }
  570. }
  571. return getViewCount() + nfill;
  572. }
  573. /**
  574. * Change the child views. This is implemented to
  575. * provide the superclass behavior and invalidate the
  576. * grid so that rows and columns will be recalculated.
  577. */
  578. public void replace(int offset, int length, View[] views) {
  579. super.replace(offset, length, views);
  580. invalidateGrid();
  581. }
  582. /**
  583. * Perform layout for the major axis of the box (i.e. the
  584. * axis that it represents). The results of the layout should
  585. * be placed in the given arrays which represent the allocations
  586. * to the children along the major axis.
  587. * <p>
  588. * This is re-implemented to give each child the span of the column
  589. * width for the table, and to give cells that span multiple columns
  590. * the multi-column span.
  591. *
  592. * @param targetSpan the total span given to the view, which
  593. * whould be used to layout the children.
  594. * @param axis the axis being layed out.
  595. * @param offsets the offsets from the origin of the view for
  596. * each of the child views. This is a return value and is
  597. * filled in by the implementation of this method.
  598. * @param spans the span of each child view. This is a return
  599. * value and is filled in by the implementation of this method.
  600. * @return the offset and span for each child view in the
  601. * offsets and spans parameters
  602. */
  603. protected void layoutMajorAxis(int targetSpan, int axis, int[] offsets, int[] spans) {
  604. int col = 0;
  605. int ncells = getViewCount();
  606. for (int cell = 0; cell < ncells; cell++, col++) {
  607. View cv = getView(cell);
  608. for (; isFilled(col); col++); // advance to a free column
  609. int colSpan = getColumnsOccupied(cv);
  610. spans[cell] = columnSpans[col];
  611. offsets[cell] = columnOffsets[col];
  612. if (colSpan > 1) {
  613. int n = columnSpans.length;
  614. for (int j = 1; j < colSpan; j++) {
  615. // Because the table may be only partially formed, some
  616. // of the columns may not yet exist. Therefore we check
  617. // the bounds.
  618. if ((col+j) < n) {
  619. spans[cell] += columnSpans[col+j];
  620. }
  621. }
  622. col += colSpan - 1;
  623. }
  624. }
  625. }
  626. /**
  627. * Perform layout for the minor axis of the box (i.e. the
  628. * axis orthoginal to the axis that it represents). The results
  629. * of the layout should be placed in the given arrays which represent
  630. * the allocations to the children along the minor axis. This
  631. * is called by the superclass whenever the layout needs to be
  632. * updated along the minor axis.
  633. * <p>
  634. * This is implemented to delegate to the superclass, then adjust
  635. * the span for any cell that spans multiple rows.
  636. *
  637. * @param targetSpan the total span given to the view, which
  638. * whould be used to layout the children.
  639. * @param axis the axis being layed out.
  640. * @param offsets the offsets from the origin of the view for
  641. * each of the child views. This is a return value and is
  642. * filled in by the implementation of this method.
  643. * @param spans the span of each child view. This is a return
  644. * value and is filled in by the implementation of this method.
  645. * @return the offset and span for each child view in the
  646. * offsets and spans parameters
  647. */
  648. protected void layoutMinorAxis(int targetSpan, int axis, int[] offsets, int[] spans) {
  649. super.layoutMinorAxis(targetSpan, axis, offsets, spans);
  650. int col = 0;
  651. int ncells = getViewCount();
  652. for (int cell = 0; cell < ncells; cell++, col++) {
  653. View cv = getView(cell);
  654. for (; isFilled(col); col++); // advance to a free column
  655. int colSpan = getColumnsOccupied(cv);
  656. int rowSpan = getRowsOccupied(cv);
  657. if (rowSpan > 1) {
  658. for (int j = 1; j < rowSpan; j++) {
  659. // test bounds of each row because it may not exist
  660. // either because of error or because the table isn't
  661. // fully loaded yet.
  662. int row = getRow() + j;
  663. if (row < TableView.this.getViewCount()) {
  664. int span = TableView.this.getSpan(Y_AXIS, getRow()+j);
  665. spans[cell] += span;
  666. }
  667. }
  668. }
  669. if (colSpan > 1) {
  670. col += colSpan - 1;
  671. }
  672. }
  673. }
  674. /**
  675. * Determines the resizability of the view along the
  676. * given axis. A value of 0 or less is not resizable.
  677. *
  678. * @param axis may be either View.X_AXIS or View.Y_AXIS
  679. * @return the resize weight
  680. * @exception IllegalArgumentException for an invalid axis
  681. */
  682. public int getResizeWeight(int axis) {
  683. return 1;
  684. }
  685. /**
  686. * Fetches the child view that represents the given position in
  687. * the model. This is implemented to walk through the children
  688. * looking for a range that contains the given position. In this
  689. * view the children do not necessarily have a one to one mapping
  690. * with the child elements.
  691. *
  692. * @param pos the search position >= 0
  693. * @param a the allocation to the table on entry, and the
  694. * allocation of the view containing the position on exit
  695. * @return the view representing the given position, or
  696. * <code>null</code> if there isn't one
  697. */
  698. protected View getViewAtPosition(int pos, Rectangle a) {
  699. int n = getViewCount();
  700. for (int i = 0; i < n; i++) {
  701. View v = getView(i);
  702. int p0 = v.getStartOffset();
  703. int p1 = v.getEndOffset();
  704. if ((pos >= p0) && (pos < p1)) {
  705. // it's in this view.
  706. if (a != null) {
  707. childAllocation(i, a);
  708. }
  709. return v;
  710. }
  711. }
  712. if (pos == getEndOffset()) {
  713. View v = getView(n - 1);
  714. if (a != null) {
  715. this.childAllocation(n - 1, a);
  716. }
  717. return v;
  718. }
  719. return null;
  720. }
  721. /** columns filled by multi-column or multi-row cells */
  722. BitSet fillColumns;
  723. /** the row within the overall grid */
  724. int row;
  725. }
  726. /**
  727. * @deprecated A table cell can now be any View implementation.
  728. */
  729. @Deprecated
  730. public class TableCell extends BoxView implements GridCell {
  731. /**
  732. * Constructs a TableCell for the given element.
  733. *
  734. * @param elem the element that this view is responsible for
  735. */
  736. public TableCell(Element elem) {
  737. super(elem, View.Y_AXIS);
  738. }
  739. // --- GridCell methods -------------------------------------
  740. /**
  741. * Gets the number of columns this cell spans (e.g. the
  742. * grid width).
  743. *
  744. * @return the number of columns
  745. */
  746. public int getColumnCount() {
  747. return 1;
  748. }
  749. /**
  750. * Gets the number of rows this cell spans (that is, the
  751. * grid height).
  752. *
  753. * @return the number of rows
  754. */
  755. public int getRowCount() {
  756. return 1;
  757. }
  758. /**
  759. * Sets the grid location.
  760. *
  761. * @param row the row >= 0
  762. * @param col the column >= 0
  763. */
  764. public void setGridLocation(int row, int col) {
  765. this.row = row;
  766. this.col = col;
  767. }
  768. /**
  769. * Gets the row of the grid location
  770. */
  771. public int getGridRow() {
  772. return row;
  773. }
  774. /**
  775. * Gets the column of the grid location
  776. */
  777. public int getGridColumn() {
  778. return col;
  779. }
  780. int row;
  781. int col;
  782. }
  783. /**
  784. * <em>
  785. * THIS IS NO LONGER USED, AND WILL BE REMOVED IN THE
  786. * NEXT RELEASE. THE JCK SIGNATURE TEST THINKS THIS INTERFACE
  787. * SHOULD EXIST
  788. * </em>
  789. */
  790. interface GridCell {
  791. /**
  792. * Sets the grid location.
  793. *
  794. * @param row the row >= 0
  795. * @param col the column >= 0
  796. */
  797. public void setGridLocation(int row, int col);
  798. /**
  799. * Gets the row of the grid location
  800. */
  801. public int getGridRow();
  802. /**
  803. * Gets the column of the grid location
  804. */
  805. public int getGridColumn();
  806. /**
  807. * Gets the number of columns this cell spans (e.g. the
  808. * grid width).
  809. *
  810. * @return the number of columns
  811. */
  812. public int getColumnCount();
  813. /**
  814. * Gets the number of rows this cell spans (that is, the
  815. * grid height).
  816. *
  817. * @return the number of rows
  818. */
  819. public int getRowCount();
  820. }
  821. }