FileDocCategorySizeDatePackage
TableView.javaAPI DocJava SE 5 API26196Fri Aug 26 14:58:16 BST 2005javax.swing.text

TableView

public abstract class TableView extends BoxView

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.


  TABLE
  ROW
  CELL
  CELL
  ROW
  CELL
  CELL

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
version
1.33 05/18/04
see
View

Fields Summary
int[]
columnSpans
int[]
columnOffsets
SizeRequirements[]
columnRequirements
Vector
rows
boolean
gridValid
private static final BitSet
EMPTY
Constructors Summary
public TableView(Element elem)
Constructs a TableView for the given element.

param
elem the element that this view is responsible for

	super(elem, View.Y_AXIS);
	rows = new Vector();
	gridValid = false;
    
Methods Summary
voidaddFill(int row, int col)
Mark a grid location as filled in for a cells overflow.

	TableRow rv = getRow(row);
	if (rv != null) {
	    rv.fillColumn(col);
	}
    
voidcalculateColumnRequirements(int axis)
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.

	// 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]);
	    }
	}
	*/
    
protected javax.swing.SizeRequirementscalculateMinorAxisRequirements(int axis, javax.swing.SizeRequirements r)
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).

This is implemented to calculate the requirements as the sum of the requirements of the columns.

	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 (int i = 0; i < columnRequirements.length; i++) {
	    SizeRequirements req = columnRequirements[i];
	    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;
    
voidcheckMultiColumnCell(int axis, int col, int ncols, javax.swing.text.View v)
check the requirements of a table cell that spans multiple columns.

	// 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);
	    }
	}

    
voidcheckSingleColumnCell(int axis, int col, javax.swing.text.View v)
check the requirements of a table cell that spans a single column.

	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);
    
protected javax.swing.text.TableView$TableCellcreateTableCell(javax.swing.text.Element 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

	return new TableCell(elem);
    
protected javax.swing.text.TableView$TableRowcreateTableRow(javax.swing.text.Element elem)
Creates a new table row.

param
elem an element
return
the row

	return new TableRow(elem);
    
protected voidforwardUpdate(javax.swing.event.DocumentEvent$ElementChange ec, javax.swing.event.DocumentEvent e, java.awt.Shape a, javax.swing.text.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);
	    }
	}
    
intgetColumnCount()
The number of columns in the table.

	return columnSpans.length;
    
intgetColumnSpan(int col)
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.

	return columnSpans[col];
    
intgetColumnsOccupied(javax.swing.text.View v)
Determines the number of columns occupied by the table cell represented by given element.

	// 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;
    
javax.swing.text.TableView$TableRowgetRow(int row)

	if (row < rows.size()) {
	    return (TableRow) rows.elementAt(row);
	}
	return null;
    
intgetRowCount()
The number of rows in the table.

	return rows.size();
    
intgetRowSpan(int row)
Fetches the span (height) of the given row.

	View rv = getRow(row);
	if (rv != null) {
	    return (int) rv.getPreferredSpan(Y_AXIS);
	}
	return 0;
    
intgetRowsOccupied(javax.swing.text.View v)
Determines the number of rows occupied by the table cell represented by given element.

	// 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 javax.swing.text.ViewgetViewAtPosition(int pos, java.awt.Rectangle a)
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 null if there isn't one

        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;
    
voidinvalidateGrid()

	gridValid = false;
    
protected voidlayoutColumns(int targetSpan, int[] offsets, int[] spans, javax.swing.SizeRequirements[] reqs)
Layout the columns to fit within the given target span.

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.
return
the offset from the origin and the span for each column in the offsets and spans parameters

	// allocate using the convenience method on SizeRequirements
	SizeRequirements.calculateTiledPositions(targetSpan, null, reqs, 
						 offsets, spans);
    
protected voidlayoutMinorAxis(int targetSpan, int axis, int[] offsets, int[] spans)
Perform layout for the minor axis of the box (i.e. the axis orthoginal 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.

This is implemented to call the 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 whould 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.
return
the offset and span for each child view in the offsets and spans parameters

	// 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);
    
public voidreplace(int offset, int length, javax.swing.text.View[] views)
Change the child views. This is implemented to provide the superclass behavior and invalidate the grid so that rows and columns will be recalculated.

	super.replace(offset, length, views);
	invalidateGrid();
    
voidupdateGrid()
Fill in the grid locations that are placeholders for multi-column, multi-row, and missing grid locations.

	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(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;
	}