/*
* Copyright 2006 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package com.google.gwt.gen2.table.override.client;
import com.google.gwt.user.client.DOM;
import com.google.gwt.user.client.Element;
/**
* This class should replace the actual class of the same name.
*
* TODO: Incorporate changes into actual class.
*/
public class FlexTable extends HTMLTable {
/**
* FlexTable-specific implementation of {@link HTMLTable.CellFormatter}. The
* formatter retrieved from {@link HTMLTable#getCellFormatter()} may be cast
* to this class.
*/
public class FlexCellFormatter extends CellFormatter {
/**
* Gets the column span for the given cell. This is the number of logical
* columns covered by the cell.
*
* @param row the cell's row
* @param column the cell's column
* @return the cell's column span
* @throws IndexOutOfBoundsException
*/
public int getColSpan(int row, int column) {
return DOM.getElementPropertyInt(getElement(row, column), "colSpan");
}
/**
* Gets the row span for the given cell. This is the number of logical rows
* covered by the cell.
*
* @param row the cell's row
* @param column the cell's column
* @return the cell's row span
* @throws IndexOutOfBoundsException
*/
public int getRowSpan(int row, int column) {
return DOM.getElementPropertyInt(getElement(row, column), "rowSpan");
}
/**
* Sets the column span for the given cell. This is the number of logical
* columns covered by the cell.
*
* @param row the cell's row
* @param column the cell's column
* @param colSpan the cell's column span
* @throws IndexOutOfBoundsException
*/
public void setColSpan(int row, int column, int colSpan) {
DOM.setElementPropertyInt(ensureElement(row, column), "colSpan", colSpan);
}
/**
* Sets the row span for the given cell. This is the number of logical rows
* covered by the cell.
*
* @param row the cell's row
* @param column the cell's column
* @param rowSpan the cell's row span
* @throws IndexOutOfBoundsException
*/
public void setRowSpan(int row, int column, int rowSpan) {
DOM.setElementPropertyInt(ensureElement(row, column), "rowSpan", rowSpan);
}
}
/**
* Add cells to the specified row.
*
* @param table the table to affect
* @param row the row to affect
* @param num the number of cells to add
*/
private static native void addCells(Element table, int row, int num)/*-{
var rowElem = table.rows[row];
for(var i = 0; i < num; i++){
var cell = $doc.createElement("td");
cell['colSpan'] = 1;
cell['rowSpan'] = 1;
rowElem.appendChild(cell);
}
}-*/;
public FlexTable() {
super();
setCellFormatter(new FlexCellFormatter());
setRowFormatter(new RowFormatter());
setColumnFormatter(new ColumnFormatter());
}
/**
* Appends a cell to the specified row.
*
* @param row the row to which the new cell will be added
* @throws IndexOutOfBoundsException
*/
public void addCell(int row) {
insertCell(row, getCellCount(row));
}
/**
* Gets the number of cells on a given row.
*
* @param row the row whose cells are to be counted
* @return the number of cells present
* @throws IndexOutOfBoundsException
*/
@Override
public int getCellCount(int row) {
checkRowBounds(row);
return getDOMCellCount(row);
}
/**
* Gets the overall column index of this cell as if this table were a grid, as
* determined by the rowspan and colspan of other cells in the table.
*
* @param row the cell's row
* @param column the cell's column
* @return the cell's column index
* @throws IndexOutOfBoundsException
*/
public int getColumnIndex(int row, int column) {
checkCellBounds(row, column);
return getRawColumnIndex(row, column);
}
/**
* Explicitly gets the {@link FlexCellFormatter}. The results of
* {@link HTMLTable#getCellFormatter()} may also be downcast to a
* {@link FlexCellFormatter}.
*
* @return the FlexTable's cell formatter
*/
public FlexCellFormatter getFlexCellFormatter() {
return (FlexCellFormatter) getCellFormatter();
}
/**
* Gets the number of rows.
*
* @return number of rows
*/
@Override
public int getRowCount() {
return getDOMRowCount();
}
/**
* Inserts a cell into the FlexTable.
*
* @param beforeRow the cell's row
* @param beforeColumn the cell's column
* @return the element
*/
@Override
public Element insertCell(int beforeRow, int beforeColumn) {
return super.insertCell(beforeRow, beforeColumn);
}
/**
* Inserts a row into the FlexTable.
*
* @param beforeRow the row to insert
*/
@Override
public int insertRow(int beforeRow) {
return super.insertRow(beforeRow);
}
/**
* Removes the specified cell from the table.
*
* @param row the row of the cell to remove
* @param column the column of cell to remove
* @throws IndexOutOfBoundsException
*/
@Override
public void removeCell(int row, int column) {
super.removeCell(row, column);
}
/**
* Removes a number of cells from a row in the table.
*
* @param row the row of the cells to be removed
* @param column the column of the first cell to be removed
* @param num the number of cells to be removed
* @throws IndexOutOfBoundsException
*/
public void removeCells(int row, int column, int num) {
for (int i = 0; i < num; i++) {
removeCell(row, column);
}
}
@Override
public void removeRow(int row) {
super.removeRow(row);
}
/**
* Add cells to the specified row.
*
* @param row the row to affect
* @param num the number of cells to add
*/
protected void addCells(int row, int num) {
addCells(getBodyElement(), row, num);
}
/**
* Ensure that the cell exists.
*
* @param row the row to prepare.
* @param column the column to prepare.
* @throws IndexOutOfBoundsException if the row is negative
*/
@Override
protected void prepareCell(int row, int column) {
prepareRow(row);
if (column < 0) {
throw new IndexOutOfBoundsException(
"Cannot create a column with a negative index: " + column);
}
// Ensure that the requested column exists.
int cellCount = getCellCount(row);
int required = column + 1 - cellCount;
if (required > 0) {
addCells(row, required);
}
}
/**
* Ensure that the row exists.
*
* @param row The row to prepare.
* @throws IndexOutOfBoundsException if the row is negative
*/
@Override
protected void prepareRow(int row) {
if (row < 0) {
throw new IndexOutOfBoundsException(
"Cannot create a row with a negative index: " + row);
}
// Ensure that the requested row exists.
int rowCount = getRowCount();
for (int i = rowCount; i <= row; i++) {
insertRow(i);
}
}
/**
* Gets the overall column index of this cell as if this table were a grid, as
* determined by the rowspan and colspan of other cells in the table. This
* helper method doesn't check the bounds on every recursive call.
*
* @param row the cell's row
* @param column the cell's column
* @return the cell's column index
* @throws IndexOutOfBoundsException
*/
private int getRawColumnIndex(int row, int column) {
// Get cells before me in my row
FlexCellFormatter formatter = getFlexCellFormatter();
int columnIndex = 0;
for (int curCell = 0; curCell < column; curCell++) {
columnIndex += formatter.getColSpan(row, curCell);
}
// Get cells that span down into my row
int numCells = 0;
for (int curRow = 0; curRow < row; curRow++) {
numCells = getCellCount(curRow);
for (int curCell = 0; curCell < numCells; curCell++) {
if ((curRow + formatter.getRowSpan(curRow, curCell) - 1) >= row) {
if (getRawColumnIndex(curRow, curCell) <= columnIndex) {
columnIndex += formatter.getColSpan(curRow, curCell);
}
}
}
}
return columnIndex;
}
}