1 /*
   2  * Copyright (c) 1997, 2011, 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  * &nbsp;  TABLE
  47  * &nbsp;    ROW
  48  * &nbsp;      CELL
  49  * &nbsp;      CELL
  50  * &nbsp;    ROW
  51  * &nbsp;      CELL
  52  * &nbsp;      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 orthoginal 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      *  whould 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          *  whould 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 orthoginal 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          *  whould 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 }