jdk/src/share/classes/javax/swing/text/TableView.java
changeset 2 90ce3da70b43
child 1287 a04aca99c77a
equal deleted inserted replaced
0:fd16c54261b3 2:90ce3da70b43
       
     1 /*
       
     2  * Copyright 1997-2006 Sun Microsystems, Inc.  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.  Sun designates this
       
     8  * particular file as subject to the "Classpath" exception as provided
       
     9  * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
       
    22  * CA 95054 USA or visit www.sun.com if you need additional information or
       
    23  * have any 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();
       
    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 (TableRow) 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(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      * <a href="#layoutColumns">layoutColumns</a> 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 (int i = 0; i < columnRequirements.length; i++) {
       
   372             SizeRequirements req = columnRequirements[i];
       
   373             min += req.minimum;
       
   374             pref += req.preferred;
       
   375             max += req.maximum;
       
   376         }
       
   377         r.minimum = (int) min;
       
   378         r.preferred = (int) pref;
       
   379         r.maximum = (int) max;
       
   380         r.alignment = 0;
       
   381         return r;
       
   382     }
       
   383 
       
   384     /*
       
   385     boolean shouldTrace() {
       
   386         AttributeSet a = getElement().getAttributes();
       
   387         Object o = a.getAttribute(HTML.Attribute.ID);
       
   388         if ((o != null) && o.equals("debug")) {
       
   389             return true;
       
   390         }
       
   391         return false;
       
   392     }
       
   393     */
       
   394 
       
   395     /**
       
   396      * Calculate the requirements for each column.  The calculation
       
   397      * is done as two passes over the table.  The table cells that
       
   398      * occupy a single column are scanned first to determine the
       
   399      * maximum of minimum, preferred, and maximum spans along the
       
   400      * give axis.  Table cells that span multiple columns are excluded
       
   401      * from the first pass.  A second pass is made to determine if
       
   402      * the cells that span multiple columns are satisfied.  If the
       
   403      * column requirements are not satisified, the needs of the
       
   404      * multi-column cell is mixed into the existing column requirements.
       
   405      * The calculation of the multi-column distribution is based upon
       
   406      * the proportions of the existing column requirements and taking
       
   407      * into consideration any constraining maximums.
       
   408      */
       
   409     void calculateColumnRequirements(int axis) {
       
   410         // pass 1 - single column cells
       
   411         boolean hasMultiColumn = false;
       
   412         int nrows = getRowCount();
       
   413         for (int i = 0; i < nrows; i++) {
       
   414             TableRow row = getRow(i);
       
   415             int col = 0;
       
   416             int ncells = row.getViewCount();
       
   417             for (int cell = 0; cell < ncells; cell++, col++) {
       
   418                 View cv = row.getView(cell);
       
   419                 for (; row.isFilled(col); col++); // advance to a free column
       
   420                 int rowSpan = getRowsOccupied(cv);
       
   421                 int colSpan = getColumnsOccupied(cv);
       
   422                 if (colSpan == 1) {
       
   423                     checkSingleColumnCell(axis, col, cv);
       
   424                 } else {
       
   425                     hasMultiColumn = true;
       
   426                     col += colSpan - 1;
       
   427                 }
       
   428             }
       
   429         }
       
   430 
       
   431         // pass 2 - multi-column cells
       
   432         if (hasMultiColumn) {
       
   433             for (int i = 0; i < nrows; i++) {
       
   434                 TableRow row = getRow(i);
       
   435                 int col = 0;
       
   436                 int ncells = row.getViewCount();
       
   437                 for (int cell = 0; cell < ncells; cell++, col++) {
       
   438                     View cv = row.getView(cell);
       
   439                     for (; row.isFilled(col); col++); // advance to a free column
       
   440                     int colSpan = getColumnsOccupied(cv);
       
   441                     if (colSpan > 1) {
       
   442                         checkMultiColumnCell(axis, col, colSpan, cv);
       
   443                         col += colSpan - 1;
       
   444                     }
       
   445                 }
       
   446             }
       
   447         }
       
   448 
       
   449         /*
       
   450         if (shouldTrace()) {
       
   451             System.err.println("calc:");
       
   452             for (int i = 0; i < columnRequirements.length; i++) {
       
   453                 System.err.println(" " + i + ": " + columnRequirements[i]);
       
   454             }
       
   455         }
       
   456         */
       
   457     }
       
   458 
       
   459     /**
       
   460      * check the requirements of a table cell that spans a single column.
       
   461      */
       
   462     void checkSingleColumnCell(int axis, int col, View v) {
       
   463         SizeRequirements req = columnRequirements[col];
       
   464         req.minimum = Math.max((int) v.getMinimumSpan(axis), req.minimum);
       
   465         req.preferred = Math.max((int) v.getPreferredSpan(axis), req.preferred);
       
   466         req.maximum = Math.max((int) v.getMaximumSpan(axis), req.maximum);
       
   467     }
       
   468 
       
   469     /**
       
   470      * check the requirements of a table cell that spans multiple
       
   471      * columns.
       
   472      */
       
   473     void checkMultiColumnCell(int axis, int col, int ncols, View v) {
       
   474         // calculate the totals
       
   475         long min = 0;
       
   476         long pref = 0;
       
   477         long max = 0;
       
   478         for (int i = 0; i < ncols; i++) {
       
   479             SizeRequirements req = columnRequirements[col + i];
       
   480             min += req.minimum;
       
   481             pref += req.preferred;
       
   482             max += req.maximum;
       
   483         }
       
   484 
       
   485         // check if the minimum size needs adjustment.
       
   486         int cmin = (int) v.getMinimumSpan(axis);
       
   487         if (cmin > min) {
       
   488             /*
       
   489              * the columns that this cell spans need adjustment to fit
       
   490              * this table cell.... calculate the adjustments.  The
       
   491              * maximum for each cell is the maximum of the existing
       
   492              * maximum or the amount needed by the cell.
       
   493              */
       
   494             SizeRequirements[] reqs = new SizeRequirements[ncols];
       
   495             for (int i = 0; i < ncols; i++) {
       
   496                 SizeRequirements r = reqs[i] = columnRequirements[col + i];
       
   497                 r.maximum = Math.max(r.maximum, (int) v.getMaximumSpan(axis));
       
   498             }
       
   499             int[] spans = new int[ncols];
       
   500             int[] offsets = new int[ncols];
       
   501             SizeRequirements.calculateTiledPositions(cmin, null, reqs,
       
   502                                                      offsets, spans);
       
   503             // apply the adjustments
       
   504             for (int i = 0; i < ncols; i++) {
       
   505                 SizeRequirements req = reqs[i];
       
   506                 req.minimum = Math.max(spans[i], req.minimum);
       
   507                 req.preferred = Math.max(req.minimum, req.preferred);
       
   508                 req.maximum = Math.max(req.preferred, req.maximum);
       
   509             }
       
   510         }
       
   511 
       
   512         // check if the preferred size needs adjustment.
       
   513         int cpref = (int) v.getPreferredSpan(axis);
       
   514         if (cpref > pref) {
       
   515             /*
       
   516              * the columns that this cell spans need adjustment to fit
       
   517              * this table cell.... calculate the adjustments.  The
       
   518              * maximum for each cell is the maximum of the existing
       
   519              * maximum or the amount needed by the cell.
       
   520              */
       
   521             SizeRequirements[] reqs = new SizeRequirements[ncols];
       
   522             for (int i = 0; i < ncols; i++) {
       
   523                 SizeRequirements r = reqs[i] = columnRequirements[col + i];
       
   524             }
       
   525             int[] spans = new int[ncols];
       
   526             int[] offsets = new int[ncols];
       
   527             SizeRequirements.calculateTiledPositions(cpref, null, reqs,
       
   528                                                      offsets, spans);
       
   529             // apply the adjustments
       
   530             for (int i = 0; i < ncols; i++) {
       
   531                 SizeRequirements req = reqs[i];
       
   532                 req.preferred = Math.max(spans[i], req.preferred);
       
   533                 req.maximum = Math.max(req.preferred, req.maximum);
       
   534             }
       
   535         }
       
   536 
       
   537     }
       
   538 
       
   539     /**
       
   540      * Fetches the child view that represents the given position in
       
   541      * the model.  This is implemented to walk through the children
       
   542      * looking for a range that contains the given position.  In this
       
   543      * view the children do not necessarily have a one to one mapping
       
   544      * with the child elements.
       
   545      *
       
   546      * @param pos  the search position >= 0
       
   547      * @param a  the allocation to the table on entry, and the
       
   548      *   allocation of the view containing the position on exit
       
   549      * @return  the view representing the given position, or
       
   550      *   <code>null</code> if there isn't one
       
   551      */
       
   552     protected View getViewAtPosition(int pos, Rectangle a) {
       
   553         int n = getViewCount();
       
   554         for (int i = 0; i < n; i++) {
       
   555             View v = getView(i);
       
   556             int p0 = v.getStartOffset();
       
   557             int p1 = v.getEndOffset();
       
   558             if ((pos >= p0) && (pos < p1)) {
       
   559                 // it's in this view.
       
   560                 if (a != null) {
       
   561                     childAllocation(i, a);
       
   562                 }
       
   563                 return v;
       
   564             }
       
   565         }
       
   566         if (pos == getEndOffset()) {
       
   567             View v = getView(n - 1);
       
   568             if (a != null) {
       
   569                 this.childAllocation(n - 1, a);
       
   570             }
       
   571             return v;
       
   572         }
       
   573         return null;
       
   574     }
       
   575 
       
   576     // ---- variables ----------------------------------------------------
       
   577 
       
   578     int[] columnSpans;
       
   579     int[] columnOffsets;
       
   580     SizeRequirements[] columnRequirements;
       
   581     Vector rows;
       
   582     boolean gridValid;
       
   583     static final private BitSet EMPTY = new BitSet();
       
   584 
       
   585     /**
       
   586      * View of a row in a row-centric table.
       
   587      */
       
   588     public class TableRow extends BoxView {
       
   589 
       
   590         /**
       
   591          * Constructs a TableView for the given element.
       
   592          *
       
   593          * @param elem the element that this view is responsible for
       
   594          * @since 1.4
       
   595          */
       
   596         public TableRow(Element elem) {
       
   597             super(elem, View.X_AXIS);
       
   598             fillColumns = new BitSet();
       
   599         }
       
   600 
       
   601         void clearFilledColumns() {
       
   602             fillColumns.and(EMPTY);
       
   603         }
       
   604 
       
   605         void fillColumn(int col) {
       
   606             fillColumns.set(col);
       
   607         }
       
   608 
       
   609         boolean isFilled(int col) {
       
   610             return fillColumns.get(col);
       
   611         }
       
   612 
       
   613         /** get location in the overall set of rows */
       
   614         int getRow() {
       
   615             return row;
       
   616         }
       
   617 
       
   618         /**
       
   619          * set location in the overall set of rows, this is
       
   620          * set by the TableView.updateGrid() method.
       
   621          */
       
   622         void setRow(int row) {
       
   623             this.row = row;
       
   624         }
       
   625 
       
   626         /**
       
   627          * The number of columns present in this row.
       
   628          */
       
   629         int getColumnCount() {
       
   630             int nfill = 0;
       
   631             int n = fillColumns.size();
       
   632             for (int i = 0; i < n; i++) {
       
   633                 if (fillColumns.get(i)) {
       
   634                     nfill ++;
       
   635                 }
       
   636             }
       
   637             return getViewCount() + nfill;
       
   638         }
       
   639 
       
   640         /**
       
   641          * Change the child views.  This is implemented to
       
   642          * provide the superclass behavior and invalidate the
       
   643          * grid so that rows and columns will be recalculated.
       
   644          */
       
   645         public void replace(int offset, int length, View[] views) {
       
   646             super.replace(offset, length, views);
       
   647             invalidateGrid();
       
   648         }
       
   649 
       
   650         /**
       
   651          * Perform layout for the major axis of the box (i.e. the
       
   652          * axis that it represents).  The results of the layout should
       
   653          * be placed in the given arrays which represent the allocations
       
   654          * to the children along the major axis.
       
   655          * <p>
       
   656          * This is re-implemented to give each child the span of the column
       
   657          * width for the table, and to give cells that span multiple columns
       
   658          * the multi-column span.
       
   659          *
       
   660          * @param targetSpan the total span given to the view, which
       
   661          *  whould be used to layout the children.
       
   662          * @param axis the axis being layed out.
       
   663          * @param offsets the offsets from the origin of the view for
       
   664          *  each of the child views.  This is a return value and is
       
   665          *  filled in by the implementation of this method.
       
   666          * @param spans the span of each child view.  This is a return
       
   667          *  value and is filled in by the implementation of this method.
       
   668          */
       
   669         protected void layoutMajorAxis(int targetSpan, int axis, int[] offsets, int[] spans) {
       
   670             int col = 0;
       
   671             int ncells = getViewCount();
       
   672             for (int cell = 0; cell < ncells; cell++, col++) {
       
   673                 View cv = getView(cell);
       
   674                 for (; isFilled(col); col++); // advance to a free column
       
   675                 int colSpan = getColumnsOccupied(cv);
       
   676                 spans[cell] = columnSpans[col];
       
   677                 offsets[cell] = columnOffsets[col];
       
   678                 if (colSpan > 1) {
       
   679                     int n = columnSpans.length;
       
   680                     for (int j = 1; j < colSpan; j++) {
       
   681                         // Because the table may be only partially formed, some
       
   682                         // of the columns may not yet exist.  Therefore we check
       
   683                         // the bounds.
       
   684                         if ((col+j) < n) {
       
   685                             spans[cell] += columnSpans[col+j];
       
   686                         }
       
   687                     }
       
   688                     col += colSpan - 1;
       
   689                 }
       
   690             }
       
   691         }
       
   692 
       
   693         /**
       
   694          * Perform layout for the minor axis of the box (i.e. the
       
   695          * axis orthoginal to the axis that it represents).  The results
       
   696          * of the layout should be placed in the given arrays which represent
       
   697          * the allocations to the children along the minor axis.  This
       
   698          * is called by the superclass whenever the layout needs to be
       
   699          * updated along the minor axis.
       
   700          * <p>
       
   701          * This is implemented to delegate to the superclass, then adjust
       
   702          * the span for any cell that spans multiple rows.
       
   703          *
       
   704          * @param targetSpan the total span given to the view, which
       
   705          *  whould be used to layout the children.
       
   706          * @param axis the axis being layed out.
       
   707          * @param offsets the offsets from the origin of the view for
       
   708          *  each of the child views.  This is a return value and is
       
   709          *  filled in by the implementation of this method.
       
   710          * @param spans the span of each child view.  This is a return
       
   711          *  value and is filled in by the implementation of this method.
       
   712          */
       
   713         protected void layoutMinorAxis(int targetSpan, int axis, int[] offsets, int[] spans) {
       
   714             super.layoutMinorAxis(targetSpan, axis, offsets, spans);
       
   715             int col = 0;
       
   716             int ncells = getViewCount();
       
   717             for (int cell = 0; cell < ncells; cell++, col++) {
       
   718                 View cv = getView(cell);
       
   719                 for (; isFilled(col); col++); // advance to a free column
       
   720                 int colSpan = getColumnsOccupied(cv);
       
   721                 int rowSpan = getRowsOccupied(cv);
       
   722                 if (rowSpan > 1) {
       
   723                     for (int j = 1; j < rowSpan; j++) {
       
   724                         // test bounds of each row because it may not exist
       
   725                         // either because of error or because the table isn't
       
   726                         // fully loaded yet.
       
   727                         int row = getRow() + j;
       
   728                         if (row < TableView.this.getViewCount()) {
       
   729                             int span = TableView.this.getSpan(Y_AXIS, getRow()+j);
       
   730                             spans[cell] += span;
       
   731                         }
       
   732                     }
       
   733                 }
       
   734                 if (colSpan > 1) {
       
   735                     col += colSpan - 1;
       
   736                 }
       
   737             }
       
   738         }
       
   739 
       
   740         /**
       
   741          * Determines the resizability of the view along the
       
   742          * given axis.  A value of 0 or less is not resizable.
       
   743          *
       
   744          * @param axis may be either View.X_AXIS or View.Y_AXIS
       
   745          * @return the resize weight
       
   746          * @exception IllegalArgumentException for an invalid axis
       
   747          */
       
   748         public int getResizeWeight(int axis) {
       
   749             return 1;
       
   750         }
       
   751 
       
   752         /**
       
   753          * Fetches the child view that represents the given position in
       
   754          * the model.  This is implemented to walk through the children
       
   755          * looking for a range that contains the given position.  In this
       
   756          * view the children do not necessarily have a one to one mapping
       
   757          * with the child elements.
       
   758          *
       
   759          * @param pos  the search position >= 0
       
   760          * @param a  the allocation to the table on entry, and the
       
   761          *   allocation of the view containing the position on exit
       
   762          * @return  the view representing the given position, or
       
   763          *   <code>null</code> if there isn't one
       
   764          */
       
   765         protected View getViewAtPosition(int pos, Rectangle a) {
       
   766             int n = getViewCount();
       
   767             for (int i = 0; i < n; i++) {
       
   768                 View v = getView(i);
       
   769                 int p0 = v.getStartOffset();
       
   770                 int p1 = v.getEndOffset();
       
   771                 if ((pos >= p0) && (pos < p1)) {
       
   772                     // it's in this view.
       
   773                     if (a != null) {
       
   774                         childAllocation(i, a);
       
   775                     }
       
   776                     return v;
       
   777                 }
       
   778             }
       
   779             if (pos == getEndOffset()) {
       
   780                 View v = getView(n - 1);
       
   781                 if (a != null) {
       
   782                     this.childAllocation(n - 1, a);
       
   783                 }
       
   784                 return v;
       
   785             }
       
   786             return null;
       
   787         }
       
   788 
       
   789         /** columns filled by multi-column or multi-row cells */
       
   790         BitSet fillColumns;
       
   791         /** the row within the overall grid */
       
   792         int row;
       
   793     }
       
   794 
       
   795     /**
       
   796      * @deprecated  A table cell can now be any View implementation.
       
   797      */
       
   798     @Deprecated
       
   799     public class TableCell extends BoxView implements GridCell {
       
   800 
       
   801         /**
       
   802          * Constructs a TableCell for the given element.
       
   803          *
       
   804          * @param elem the element that this view is responsible for
       
   805          * @since 1.4
       
   806          */
       
   807         public TableCell(Element elem) {
       
   808             super(elem, View.Y_AXIS);
       
   809         }
       
   810 
       
   811         // --- GridCell methods -------------------------------------
       
   812 
       
   813         /**
       
   814          * Gets the number of columns this cell spans (e.g. the
       
   815          * grid width).
       
   816          *
       
   817          * @return the number of columns
       
   818          */
       
   819         public int getColumnCount() {
       
   820             return 1;
       
   821         }
       
   822 
       
   823         /**
       
   824          * Gets the number of rows this cell spans (that is, the
       
   825          * grid height).
       
   826          *
       
   827          * @return the number of rows
       
   828          */
       
   829         public int getRowCount() {
       
   830             return 1;
       
   831         }
       
   832 
       
   833 
       
   834         /**
       
   835          * Sets the grid location.
       
   836          *
       
   837          * @param row the row >= 0
       
   838          * @param col the column >= 0
       
   839          */
       
   840         public void setGridLocation(int row, int col) {
       
   841             this.row = row;
       
   842             this.col = col;
       
   843         }
       
   844 
       
   845         /**
       
   846          * Gets the row of the grid location
       
   847          */
       
   848         public int getGridRow() {
       
   849             return row;
       
   850         }
       
   851 
       
   852         /**
       
   853          * Gets the column of the grid location
       
   854          */
       
   855         public int getGridColumn() {
       
   856             return col;
       
   857         }
       
   858 
       
   859         int row;
       
   860         int col;
       
   861     }
       
   862 
       
   863     /**
       
   864      * <em>
       
   865      * THIS IS NO LONGER USED, AND WILL BE REMOVED IN THE
       
   866      * NEXT RELEASE.  THE JCK SIGNATURE TEST THINKS THIS INTERFACE
       
   867      * SHOULD EXIST
       
   868      * </em>
       
   869      */
       
   870     interface GridCell {
       
   871 
       
   872         /**
       
   873          * Sets the grid location.
       
   874          *
       
   875          * @param row the row >= 0
       
   876          * @param col the column >= 0
       
   877          */
       
   878         public void setGridLocation(int row, int col);
       
   879 
       
   880         /**
       
   881          * Gets the row of the grid location
       
   882          */
       
   883         public int getGridRow();
       
   884 
       
   885         /**
       
   886          * Gets the column of the grid location
       
   887          */
       
   888         public int getGridColumn();
       
   889 
       
   890         /**
       
   891          * Gets the number of columns this cell spans (e.g. the
       
   892          * grid width).
       
   893          *
       
   894          * @return the number of columns
       
   895          */
       
   896         public int getColumnCount();
       
   897 
       
   898         /**
       
   899          * Gets the number of rows this cell spans (that is, the
       
   900          * grid height).
       
   901          *
       
   902          * @return the number of rows
       
   903          */
       
   904         public int getRowCount();
       
   905 
       
   906     }
       
   907 
       
   908 }