You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
908 lines
30 KiB
908 lines
30 KiB
/*
|
|
* Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
|
|
* ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
|
|
*
|
|
*
|
|
*
|
|
*
|
|
*
|
|
*
|
|
*
|
|
*
|
|
*
|
|
*
|
|
*
|
|
*
|
|
*
|
|
*
|
|
*
|
|
*
|
|
*
|
|
*
|
|
*
|
|
*
|
|
*/
|
|
package javax.swing.text;
|
|
|
|
import java.awt.*;
|
|
import java.util.BitSet;
|
|
import java.util.Vector;
|
|
import javax.swing.SizeRequirements;
|
|
import javax.swing.event.DocumentEvent;
|
|
|
|
import javax.swing.text.html.HTML;
|
|
|
|
/**
|
|
* <p>
|
|
* Implements View interface for a table, that is composed of an
|
|
* element structure where the child elements of the element
|
|
* this view is responsible for represent rows and the child
|
|
* elements of the row elements are cells. The cell elements can
|
|
* have an arbitrary element structure under them, which will
|
|
* be built with the ViewFactory returned by the getViewFactory
|
|
* method.
|
|
* <pre>
|
|
*
|
|
* TABLE
|
|
* ROW
|
|
* CELL
|
|
* CELL
|
|
* ROW
|
|
* CELL
|
|
* CELL
|
|
*
|
|
* </pre>
|
|
* <p>
|
|
* This is implemented as a hierarchy of boxes, the table itself
|
|
* is a vertical box, the rows are horizontal boxes, and the cells
|
|
* are vertical boxes. The cells are allowed to span multiple
|
|
* columns and rows. By default, the table can be thought of as
|
|
* being formed over a grid (i.e. somewhat like one would find in
|
|
* gridbag layout), where table cells can request to span more
|
|
* than one grid cell. The default horizontal span of table cells
|
|
* will be based upon this grid, but can be changed by reimplementing
|
|
* the requested span of the cell (i.e. table cells can have independant
|
|
* spans if desired).
|
|
*
|
|
* @author Timothy Prinzing
|
|
* @see View
|
|
*/
|
|
public abstract class TableView extends BoxView {
|
|
|
|
/**
|
|
* Constructs a TableView for the given element.
|
|
*
|
|
* @param elem the element that this view is responsible for
|
|
*/
|
|
public TableView(Element elem) {
|
|
super(elem, View.Y_AXIS);
|
|
rows = new Vector<TableRow>();
|
|
gridValid = false;
|
|
}
|
|
|
|
/**
|
|
* Creates a new table row.
|
|
*
|
|
* @param elem an element
|
|
* @return the row
|
|
*/
|
|
protected TableRow createTableRow(Element elem) {
|
|
return new TableRow(elem);
|
|
}
|
|
|
|
/**
|
|
* @deprecated Table cells can now be any arbitrary
|
|
* View implementation and should be produced by the
|
|
* ViewFactory rather than the table.
|
|
*
|
|
* @param elem an element
|
|
* @return the cell
|
|
*/
|
|
@Deprecated
|
|
protected TableCell createTableCell(Element elem) {
|
|
return new TableCell(elem);
|
|
}
|
|
|
|
/**
|
|
* The number of columns in the table.
|
|
*/
|
|
int getColumnCount() {
|
|
return columnSpans.length;
|
|
}
|
|
|
|
/**
|
|
* Fetches the span (width) of the given column.
|
|
* This is used by the nested cells to query the
|
|
* sizes of grid locations outside of themselves.
|
|
*/
|
|
int getColumnSpan(int col) {
|
|
return columnSpans[col];
|
|
}
|
|
|
|
/**
|
|
* The number of rows in the table.
|
|
*/
|
|
int getRowCount() {
|
|
return rows.size();
|
|
}
|
|
|
|
/**
|
|
* Fetches the span (height) of the given row.
|
|
*/
|
|
int getRowSpan(int row) {
|
|
View rv = getRow(row);
|
|
if (rv != null) {
|
|
return (int) rv.getPreferredSpan(Y_AXIS);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
TableRow getRow(int row) {
|
|
if (row < rows.size()) {
|
|
return rows.elementAt(row);
|
|
}
|
|
return null;
|
|
}
|
|
|
|
/**
|
|
* Determines the number of columns occupied by
|
|
* the table cell represented by given element.
|
|
*/
|
|
/*protected*/ int getColumnsOccupied(View v) {
|
|
// PENDING(prinz) this code should be in the html
|
|
// paragraph, but we can't add api to enable it.
|
|
AttributeSet a = v.getElement().getAttributes();
|
|
String s = (String) a.getAttribute(HTML.Attribute.COLSPAN);
|
|
if (s != null) {
|
|
try {
|
|
return Integer.parseInt(s);
|
|
} catch (NumberFormatException nfe) {
|
|
// fall through to one column
|
|
}
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
/**
|
|
* Determines the number of rows occupied by
|
|
* the table cell represented by given element.
|
|
*/
|
|
/*protected*/ int getRowsOccupied(View v) {
|
|
// PENDING(prinz) this code should be in the html
|
|
// paragraph, but we can't add api to enable it.
|
|
AttributeSet a = v.getElement().getAttributes();
|
|
String s = (String) a.getAttribute(HTML.Attribute.ROWSPAN);
|
|
if (s != null) {
|
|
try {
|
|
return Integer.parseInt(s);
|
|
} catch (NumberFormatException nfe) {
|
|
// fall through to one row
|
|
}
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
/*protected*/ void invalidateGrid() {
|
|
gridValid = false;
|
|
}
|
|
|
|
protected void forwardUpdate(DocumentEvent.ElementChange ec,
|
|
DocumentEvent e, Shape a, ViewFactory f) {
|
|
super.forwardUpdate(ec, e, a, f);
|
|
// A change in any of the table cells usually effects the whole table,
|
|
// so redraw it all!
|
|
if (a != null) {
|
|
Component c = getContainer();
|
|
if (c != null) {
|
|
Rectangle alloc = (a instanceof Rectangle) ? (Rectangle)a :
|
|
a.getBounds();
|
|
c.repaint(alloc.x, alloc.y, alloc.width, alloc.height);
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Change the child views. This is implemented to
|
|
* provide the superclass behavior and invalidate the
|
|
* grid so that rows and columns will be recalculated.
|
|
*/
|
|
public void replace(int offset, int length, View[] views) {
|
|
super.replace(offset, length, views);
|
|
invalidateGrid();
|
|
}
|
|
|
|
/**
|
|
* Fill in the grid locations that are placeholders
|
|
* for multi-column, multi-row, and missing grid
|
|
* locations.
|
|
*/
|
|
void updateGrid() {
|
|
if (! gridValid) {
|
|
// determine which views are table rows and clear out
|
|
// grid points marked filled.
|
|
rows.removeAllElements();
|
|
int n = getViewCount();
|
|
for (int i = 0; i < n; i++) {
|
|
View v = getView(i);
|
|
if (v instanceof TableRow) {
|
|
rows.addElement((TableRow) v);
|
|
TableRow rv = (TableRow) v;
|
|
rv.clearFilledColumns();
|
|
rv.setRow(i);
|
|
}
|
|
}
|
|
|
|
int maxColumns = 0;
|
|
int nrows = rows.size();
|
|
for (int row = 0; row < nrows; row++) {
|
|
TableRow rv = getRow(row);
|
|
int col = 0;
|
|
for (int cell = 0; cell < rv.getViewCount(); cell++, col++) {
|
|
View cv = rv.getView(cell);
|
|
// advance to a free column
|
|
for (; rv.isFilled(col); col++);
|
|
int rowSpan = getRowsOccupied(cv);
|
|
int colSpan = getColumnsOccupied(cv);
|
|
if ((colSpan > 1) || (rowSpan > 1)) {
|
|
// fill in the overflow entries for this cell
|
|
int rowLimit = row + rowSpan;
|
|
int colLimit = col + colSpan;
|
|
for (int i = row; i < rowLimit; i++) {
|
|
for (int j = col; j < colLimit; j++) {
|
|
if (i != row || j != col) {
|
|
addFill(i, j);
|
|
}
|
|
}
|
|
}
|
|
if (colSpan > 1) {
|
|
col += colSpan - 1;
|
|
}
|
|
}
|
|
}
|
|
maxColumns = Math.max(maxColumns, col);
|
|
}
|
|
|
|
// setup the column layout/requirements
|
|
columnSpans = new int[maxColumns];
|
|
columnOffsets = new int[maxColumns];
|
|
columnRequirements = new SizeRequirements[maxColumns];
|
|
for (int i = 0; i < maxColumns; i++) {
|
|
columnRequirements[i] = new SizeRequirements();
|
|
}
|
|
gridValid = true;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Mark a grid location as filled in for a cells overflow.
|
|
*/
|
|
void addFill(int row, int col) {
|
|
TableRow rv = getRow(row);
|
|
if (rv != null) {
|
|
rv.fillColumn(col);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Lays out the columns to fit within the given target span.
|
|
* Returns the results through {@code offsets} and {@code spans}.
|
|
*
|
|
* @param targetSpan the given span for total of all the table
|
|
* columns
|
|
* @param reqs the requirements desired for each column. This
|
|
* is the column maximum of the cells minimum, preferred, and
|
|
* maximum requested span
|
|
* @param spans the return value of how much to allocated to
|
|
* each column
|
|
* @param offsets the return value of the offset from the
|
|
* origin for each column
|
|
*/
|
|
protected void layoutColumns(int targetSpan, int[] offsets, int[] spans,
|
|
SizeRequirements[] reqs) {
|
|
// allocate using the convenience method on SizeRequirements
|
|
SizeRequirements.calculateTiledPositions(targetSpan, null, reqs,
|
|
offsets, spans);
|
|
}
|
|
|
|
/**
|
|
* Perform layout for the minor axis of the box (i.e. the
|
|
* axis orthogonal to the axis that it represents). The results
|
|
* of the layout should be placed in the given arrays which represent
|
|
* the allocations to the children along the minor axis. This
|
|
* is called by the superclass whenever the layout needs to be
|
|
* updated along the minor axis.
|
|
* <p>
|
|
* This is implemented to call the
|
|
* {@link #layoutColumns layoutColumns} method, and then
|
|
* forward to the superclass to actually carry out the layout
|
|
* of the tables rows.
|
|
*
|
|
* @param targetSpan the total span given to the view, which
|
|
* would be used to layout the children.
|
|
* @param axis the axis being layed out.
|
|
* @param offsets the offsets from the origin of the view for
|
|
* each of the child views. This is a return value and is
|
|
* filled in by the implementation of this method.
|
|
* @param spans the span of each child view. This is a return
|
|
* value and is filled in by the implementation of this method.
|
|
*/
|
|
protected void layoutMinorAxis(int targetSpan, int axis, int[] offsets, int[] spans) {
|
|
// make grid is properly represented
|
|
updateGrid();
|
|
|
|
// all of the row layouts are invalid, so mark them that way
|
|
int n = getRowCount();
|
|
for (int i = 0; i < n; i++) {
|
|
TableRow row = getRow(i);
|
|
row.layoutChanged(axis);
|
|
}
|
|
|
|
// calculate column spans
|
|
layoutColumns(targetSpan, columnOffsets, columnSpans, columnRequirements);
|
|
|
|
// continue normal layout
|
|
super.layoutMinorAxis(targetSpan, axis, offsets, spans);
|
|
}
|
|
|
|
/**
|
|
* Calculate the requirements for the minor axis. This is called by
|
|
* the superclass whenever the requirements need to be updated (i.e.
|
|
* a preferenceChanged was messaged through this view).
|
|
* <p>
|
|
* This is implemented to calculate the requirements as the sum of the
|
|
* requirements of the columns.
|
|
*/
|
|
protected SizeRequirements calculateMinorAxisRequirements(int axis, SizeRequirements r) {
|
|
updateGrid();
|
|
|
|
// calculate column requirements for each column
|
|
calculateColumnRequirements(axis);
|
|
|
|
|
|
// the requirements are the sum of the columns.
|
|
if (r == null) {
|
|
r = new SizeRequirements();
|
|
}
|
|
long min = 0;
|
|
long pref = 0;
|
|
long max = 0;
|
|
for (SizeRequirements req : columnRequirements) {
|
|
min += req.minimum;
|
|
pref += req.preferred;
|
|
max += req.maximum;
|
|
}
|
|
r.minimum = (int) min;
|
|
r.preferred = (int) pref;
|
|
r.maximum = (int) max;
|
|
r.alignment = 0;
|
|
return r;
|
|
}
|
|
|
|
/*
|
|
boolean shouldTrace() {
|
|
AttributeSet a = getElement().getAttributes();
|
|
Object o = a.getAttribute(HTML.Attribute.ID);
|
|
if ((o != null) && o.equals("debug")) {
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
*/
|
|
|
|
/**
|
|
* Calculate the requirements for each column. The calculation
|
|
* is done as two passes over the table. The table cells that
|
|
* occupy a single column are scanned first to determine the
|
|
* maximum of minimum, preferred, and maximum spans along the
|
|
* give axis. Table cells that span multiple columns are excluded
|
|
* from the first pass. A second pass is made to determine if
|
|
* the cells that span multiple columns are satisfied. If the
|
|
* column requirements are not satisified, the needs of the
|
|
* multi-column cell is mixed into the existing column requirements.
|
|
* The calculation of the multi-column distribution is based upon
|
|
* the proportions of the existing column requirements and taking
|
|
* into consideration any constraining maximums.
|
|
*/
|
|
void calculateColumnRequirements(int axis) {
|
|
// pass 1 - single column cells
|
|
boolean hasMultiColumn = false;
|
|
int nrows = getRowCount();
|
|
for (int i = 0; i < nrows; i++) {
|
|
TableRow row = getRow(i);
|
|
int col = 0;
|
|
int ncells = row.getViewCount();
|
|
for (int cell = 0; cell < ncells; cell++, col++) {
|
|
View cv = row.getView(cell);
|
|
for (; row.isFilled(col); col++); // advance to a free column
|
|
int rowSpan = getRowsOccupied(cv);
|
|
int colSpan = getColumnsOccupied(cv);
|
|
if (colSpan == 1) {
|
|
checkSingleColumnCell(axis, col, cv);
|
|
} else {
|
|
hasMultiColumn = true;
|
|
col += colSpan - 1;
|
|
}
|
|
}
|
|
}
|
|
|
|
// pass 2 - multi-column cells
|
|
if (hasMultiColumn) {
|
|
for (int i = 0; i < nrows; i++) {
|
|
TableRow row = getRow(i);
|
|
int col = 0;
|
|
int ncells = row.getViewCount();
|
|
for (int cell = 0; cell < ncells; cell++, col++) {
|
|
View cv = row.getView(cell);
|
|
for (; row.isFilled(col); col++); // advance to a free column
|
|
int colSpan = getColumnsOccupied(cv);
|
|
if (colSpan > 1) {
|
|
checkMultiColumnCell(axis, col, colSpan, cv);
|
|
col += colSpan - 1;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
if (shouldTrace()) {
|
|
System.err.println("calc:");
|
|
for (int i = 0; i < columnRequirements.length; i++) {
|
|
System.err.println(" " + i + ": " + columnRequirements[i]);
|
|
}
|
|
}
|
|
*/
|
|
}
|
|
|
|
/**
|
|
* check the requirements of a table cell that spans a single column.
|
|
*/
|
|
void checkSingleColumnCell(int axis, int col, View v) {
|
|
SizeRequirements req = columnRequirements[col];
|
|
req.minimum = Math.max((int) v.getMinimumSpan(axis), req.minimum);
|
|
req.preferred = Math.max((int) v.getPreferredSpan(axis), req.preferred);
|
|
req.maximum = Math.max((int) v.getMaximumSpan(axis), req.maximum);
|
|
}
|
|
|
|
/**
|
|
* check the requirements of a table cell that spans multiple
|
|
* columns.
|
|
*/
|
|
void checkMultiColumnCell(int axis, int col, int ncols, View v) {
|
|
// calculate the totals
|
|
long min = 0;
|
|
long pref = 0;
|
|
long max = 0;
|
|
for (int i = 0; i < ncols; i++) {
|
|
SizeRequirements req = columnRequirements[col + i];
|
|
min += req.minimum;
|
|
pref += req.preferred;
|
|
max += req.maximum;
|
|
}
|
|
|
|
// check if the minimum size needs adjustment.
|
|
int cmin = (int) v.getMinimumSpan(axis);
|
|
if (cmin > min) {
|
|
/*
|
|
* the columns that this cell spans need adjustment to fit
|
|
* this table cell.... calculate the adjustments. The
|
|
* maximum for each cell is the maximum of the existing
|
|
* maximum or the amount needed by the cell.
|
|
*/
|
|
SizeRequirements[] reqs = new SizeRequirements[ncols];
|
|
for (int i = 0; i < ncols; i++) {
|
|
SizeRequirements r = reqs[i] = columnRequirements[col + i];
|
|
r.maximum = Math.max(r.maximum, (int) v.getMaximumSpan(axis));
|
|
}
|
|
int[] spans = new int[ncols];
|
|
int[] offsets = new int[ncols];
|
|
SizeRequirements.calculateTiledPositions(cmin, null, reqs,
|
|
offsets, spans);
|
|
// apply the adjustments
|
|
for (int i = 0; i < ncols; i++) {
|
|
SizeRequirements req = reqs[i];
|
|
req.minimum = Math.max(spans[i], req.minimum);
|
|
req.preferred = Math.max(req.minimum, req.preferred);
|
|
req.maximum = Math.max(req.preferred, req.maximum);
|
|
}
|
|
}
|
|
|
|
// check if the preferred size needs adjustment.
|
|
int cpref = (int) v.getPreferredSpan(axis);
|
|
if (cpref > pref) {
|
|
/*
|
|
* the columns that this cell spans need adjustment to fit
|
|
* this table cell.... calculate the adjustments. The
|
|
* maximum for each cell is the maximum of the existing
|
|
* maximum or the amount needed by the cell.
|
|
*/
|
|
SizeRequirements[] reqs = new SizeRequirements[ncols];
|
|
for (int i = 0; i < ncols; i++) {
|
|
SizeRequirements r = reqs[i] = columnRequirements[col + i];
|
|
}
|
|
int[] spans = new int[ncols];
|
|
int[] offsets = new int[ncols];
|
|
SizeRequirements.calculateTiledPositions(cpref, null, reqs,
|
|
offsets, spans);
|
|
// apply the adjustments
|
|
for (int i = 0; i < ncols; i++) {
|
|
SizeRequirements req = reqs[i];
|
|
req.preferred = Math.max(spans[i], req.preferred);
|
|
req.maximum = Math.max(req.preferred, req.maximum);
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
/**
|
|
* Fetches the child view that represents the given position in
|
|
* the model. This is implemented to walk through the children
|
|
* looking for a range that contains the given position. In this
|
|
* view the children do not necessarily have a one to one mapping
|
|
* with the child elements.
|
|
*
|
|
* @param pos the search position >= 0
|
|
* @param a the allocation to the table on entry, and the
|
|
* allocation of the view containing the position on exit
|
|
* @return the view representing the given position, or
|
|
* <code>null</code> if there isn't one
|
|
*/
|
|
protected View getViewAtPosition(int pos, Rectangle a) {
|
|
int n = getViewCount();
|
|
for (int i = 0; i < n; i++) {
|
|
View v = getView(i);
|
|
int p0 = v.getStartOffset();
|
|
int p1 = v.getEndOffset();
|
|
if ((pos >= p0) && (pos < p1)) {
|
|
// it's in this view.
|
|
if (a != null) {
|
|
childAllocation(i, a);
|
|
}
|
|
return v;
|
|
}
|
|
}
|
|
if (pos == getEndOffset()) {
|
|
View v = getView(n - 1);
|
|
if (a != null) {
|
|
this.childAllocation(n - 1, a);
|
|
}
|
|
return v;
|
|
}
|
|
return null;
|
|
}
|
|
|
|
// ---- variables ----------------------------------------------------
|
|
|
|
int[] columnSpans;
|
|
int[] columnOffsets;
|
|
SizeRequirements[] columnRequirements;
|
|
Vector<TableRow> rows;
|
|
boolean gridValid;
|
|
static final private BitSet EMPTY = new BitSet();
|
|
|
|
/**
|
|
* View of a row in a row-centric table.
|
|
*/
|
|
public class TableRow extends BoxView {
|
|
|
|
/**
|
|
* Constructs a TableView for the given element.
|
|
*
|
|
* @param elem the element that this view is responsible for
|
|
* @since 1.4
|
|
*/
|
|
public TableRow(Element elem) {
|
|
super(elem, View.X_AXIS);
|
|
fillColumns = new BitSet();
|
|
}
|
|
|
|
void clearFilledColumns() {
|
|
fillColumns.and(EMPTY);
|
|
}
|
|
|
|
void fillColumn(int col) {
|
|
fillColumns.set(col);
|
|
}
|
|
|
|
boolean isFilled(int col) {
|
|
return fillColumns.get(col);
|
|
}
|
|
|
|
/** get location in the overall set of rows */
|
|
int getRow() {
|
|
return row;
|
|
}
|
|
|
|
/**
|
|
* set location in the overall set of rows, this is
|
|
* set by the TableView.updateGrid() method.
|
|
*/
|
|
void setRow(int row) {
|
|
this.row = row;
|
|
}
|
|
|
|
/**
|
|
* The number of columns present in this row.
|
|
*/
|
|
int getColumnCount() {
|
|
int nfill = 0;
|
|
int n = fillColumns.size();
|
|
for (int i = 0; i < n; i++) {
|
|
if (fillColumns.get(i)) {
|
|
nfill ++;
|
|
}
|
|
}
|
|
return getViewCount() + nfill;
|
|
}
|
|
|
|
/**
|
|
* Change the child views. This is implemented to
|
|
* provide the superclass behavior and invalidate the
|
|
* grid so that rows and columns will be recalculated.
|
|
*/
|
|
public void replace(int offset, int length, View[] views) {
|
|
super.replace(offset, length, views);
|
|
invalidateGrid();
|
|
}
|
|
|
|
/**
|
|
* Perform layout for the major axis of the box (i.e. the
|
|
* axis that it represents). The results of the layout should
|
|
* be placed in the given arrays which represent the allocations
|
|
* to the children along the major axis.
|
|
* <p>
|
|
* This is re-implemented to give each child the span of the column
|
|
* width for the table, and to give cells that span multiple columns
|
|
* the multi-column span.
|
|
*
|
|
* @param targetSpan the total span given to the view, which
|
|
* would be used to layout the children.
|
|
* @param axis the axis being layed out.
|
|
* @param offsets the offsets from the origin of the view for
|
|
* each of the child views. This is a return value and is
|
|
* filled in by the implementation of this method.
|
|
* @param spans the span of each child view. This is a return
|
|
* value and is filled in by the implementation of this method.
|
|
*/
|
|
protected void layoutMajorAxis(int targetSpan, int axis, int[] offsets, int[] spans) {
|
|
int col = 0;
|
|
int ncells = getViewCount();
|
|
for (int cell = 0; cell < ncells; cell++, col++) {
|
|
View cv = getView(cell);
|
|
for (; isFilled(col); col++); // advance to a free column
|
|
int colSpan = getColumnsOccupied(cv);
|
|
spans[cell] = columnSpans[col];
|
|
offsets[cell] = columnOffsets[col];
|
|
if (colSpan > 1) {
|
|
int n = columnSpans.length;
|
|
for (int j = 1; j < colSpan; j++) {
|
|
// Because the table may be only partially formed, some
|
|
// of the columns may not yet exist. Therefore we check
|
|
// the bounds.
|
|
if ((col+j) < n) {
|
|
spans[cell] += columnSpans[col+j];
|
|
}
|
|
}
|
|
col += colSpan - 1;
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Perform layout for the minor axis of the box (i.e. the
|
|
* axis orthogonal to the axis that it represents). The results
|
|
* of the layout should be placed in the given arrays which represent
|
|
* the allocations to the children along the minor axis. This
|
|
* is called by the superclass whenever the layout needs to be
|
|
* updated along the minor axis.
|
|
* <p>
|
|
* This is implemented to delegate to the superclass, then adjust
|
|
* the span for any cell that spans multiple rows.
|
|
*
|
|
* @param targetSpan the total span given to the view, which
|
|
* would be used to layout the children.
|
|
* @param axis the axis being layed out.
|
|
* @param offsets the offsets from the origin of the view for
|
|
* each of the child views. This is a return value and is
|
|
* filled in by the implementation of this method.
|
|
* @param spans the span of each child view. This is a return
|
|
* value and is filled in by the implementation of this method.
|
|
*/
|
|
protected void layoutMinorAxis(int targetSpan, int axis, int[] offsets, int[] spans) {
|
|
super.layoutMinorAxis(targetSpan, axis, offsets, spans);
|
|
int col = 0;
|
|
int ncells = getViewCount();
|
|
for (int cell = 0; cell < ncells; cell++, col++) {
|
|
View cv = getView(cell);
|
|
for (; isFilled(col); col++); // advance to a free column
|
|
int colSpan = getColumnsOccupied(cv);
|
|
int rowSpan = getRowsOccupied(cv);
|
|
if (rowSpan > 1) {
|
|
for (int j = 1; j < rowSpan; j++) {
|
|
// test bounds of each row because it may not exist
|
|
// either because of error or because the table isn't
|
|
// fully loaded yet.
|
|
int row = getRow() + j;
|
|
if (row < TableView.this.getViewCount()) {
|
|
int span = TableView.this.getSpan(Y_AXIS, getRow()+j);
|
|
spans[cell] += span;
|
|
}
|
|
}
|
|
}
|
|
if (colSpan > 1) {
|
|
col += colSpan - 1;
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Determines the resizability of the view along the
|
|
* given axis. A value of 0 or less is not resizable.
|
|
*
|
|
* @param axis may be either View.X_AXIS or View.Y_AXIS
|
|
* @return the resize weight
|
|
* @exception IllegalArgumentException for an invalid axis
|
|
*/
|
|
public int getResizeWeight(int axis) {
|
|
return 1;
|
|
}
|
|
|
|
/**
|
|
* Fetches the child view that represents the given position in
|
|
* the model. This is implemented to walk through the children
|
|
* looking for a range that contains the given position. In this
|
|
* view the children do not necessarily have a one to one mapping
|
|
* with the child elements.
|
|
*
|
|
* @param pos the search position >= 0
|
|
* @param a the allocation to the table on entry, and the
|
|
* allocation of the view containing the position on exit
|
|
* @return the view representing the given position, or
|
|
* <code>null</code> if there isn't one
|
|
*/
|
|
protected View getViewAtPosition(int pos, Rectangle a) {
|
|
int n = getViewCount();
|
|
for (int i = 0; i < n; i++) {
|
|
View v = getView(i);
|
|
int p0 = v.getStartOffset();
|
|
int p1 = v.getEndOffset();
|
|
if ((pos >= p0) && (pos < p1)) {
|
|
// it's in this view.
|
|
if (a != null) {
|
|
childAllocation(i, a);
|
|
}
|
|
return v;
|
|
}
|
|
}
|
|
if (pos == getEndOffset()) {
|
|
View v = getView(n - 1);
|
|
if (a != null) {
|
|
this.childAllocation(n - 1, a);
|
|
}
|
|
return v;
|
|
}
|
|
return null;
|
|
}
|
|
|
|
/** columns filled by multi-column or multi-row cells */
|
|
BitSet fillColumns;
|
|
/** the row within the overall grid */
|
|
int row;
|
|
}
|
|
|
|
/**
|
|
* @deprecated A table cell can now be any View implementation.
|
|
*/
|
|
@Deprecated
|
|
public class TableCell extends BoxView implements GridCell {
|
|
|
|
/**
|
|
* Constructs a TableCell for the given element.
|
|
*
|
|
* @param elem the element that this view is responsible for
|
|
* @since 1.4
|
|
*/
|
|
public TableCell(Element elem) {
|
|
super(elem, View.Y_AXIS);
|
|
}
|
|
|
|
// --- GridCell methods -------------------------------------
|
|
|
|
/**
|
|
* Gets the number of columns this cell spans (e.g. the
|
|
* grid width).
|
|
*
|
|
* @return the number of columns
|
|
*/
|
|
public int getColumnCount() {
|
|
return 1;
|
|
}
|
|
|
|
/**
|
|
* Gets the number of rows this cell spans (that is, the
|
|
* grid height).
|
|
*
|
|
* @return the number of rows
|
|
*/
|
|
public int getRowCount() {
|
|
return 1;
|
|
}
|
|
|
|
|
|
/**
|
|
* Sets the grid location.
|
|
*
|
|
* @param row the row >= 0
|
|
* @param col the column >= 0
|
|
*/
|
|
public void setGridLocation(int row, int col) {
|
|
this.row = row;
|
|
this.col = col;
|
|
}
|
|
|
|
/**
|
|
* Gets the row of the grid location
|
|
*/
|
|
public int getGridRow() {
|
|
return row;
|
|
}
|
|
|
|
/**
|
|
* Gets the column of the grid location
|
|
*/
|
|
public int getGridColumn() {
|
|
return col;
|
|
}
|
|
|
|
int row;
|
|
int col;
|
|
}
|
|
|
|
/**
|
|
* <em>
|
|
* THIS IS NO LONGER USED, AND WILL BE REMOVED IN THE
|
|
* NEXT RELEASE. THE JCK SIGNATURE TEST THINKS THIS INTERFACE
|
|
* SHOULD EXIST
|
|
* </em>
|
|
*/
|
|
interface GridCell {
|
|
|
|
/**
|
|
* Sets the grid location.
|
|
*
|
|
* @param row the row >= 0
|
|
* @param col the column >= 0
|
|
*/
|
|
public void setGridLocation(int row, int col);
|
|
|
|
/**
|
|
* Gets the row of the grid location
|
|
*/
|
|
public int getGridRow();
|
|
|
|
/**
|
|
* Gets the column of the grid location
|
|
*/
|
|
public int getGridColumn();
|
|
|
|
/**
|
|
* Gets the number of columns this cell spans (e.g. the
|
|
* grid width).
|
|
*
|
|
* @return the number of columns
|
|
*/
|
|
public int getColumnCount();
|
|
|
|
/**
|
|
* Gets the number of rows this cell spans (that is, the
|
|
* grid height).
|
|
*
|
|
* @return the number of rows
|
|
*/
|
|
public int getRowCount();
|
|
|
|
}
|
|
|
|
}
|