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