com.google.gwt.user.cellview.client.AbstractCellTableBuilder Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of vaadin-client Show documentation
Show all versions of vaadin-client Show documentation
Vaadin is a web application framework for Rich Internet Applications (RIA).
Vaadin enables easy development and maintenance of fast and
secure rich web
applications with a stunning look and feel and a wide browser support.
It features a server-side architecture with the majority of the logic
running
on the server. Ajax technology is used at the browser-side to ensure a
rich
and interactive user experience.
/*
* Copyright 2011 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.user.cellview.client;
import com.google.gwt.cell.client.Cell.Context;
import com.google.gwt.cell.client.HasCell;
import com.google.gwt.dom.builder.shared.ElementBuilderBase;
import com.google.gwt.dom.builder.shared.HtmlBuilderFactory;
import com.google.gwt.dom.builder.shared.HtmlTableSectionBuilder;
import com.google.gwt.dom.builder.shared.TableRowBuilder;
import com.google.gwt.dom.builder.shared.TableSectionBuilder;
import com.google.gwt.dom.client.Document;
import com.google.gwt.dom.client.Element;
import com.google.gwt.dom.client.TableRowElement;
import com.google.gwt.safehtml.shared.SafeHtmlBuilder;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
/**
* Builder used to construct a CellTable.
*
* @param the row data type
*/
public abstract class AbstractCellTableBuilder implements CellTableBuilder {
/**
* The attribute used to indicate that an element contains a cell.
*/
private static final String CELL_ATTRIBUTE = "__gwt_cell";
/**
* The attribute used to specify the logical row index.
*/
private static final String ROW_ATTRIBUTE = "__gwt_row";
/**
* The attribute used to specify the subrow within a logical row value.
*/
private static final String SUBROW_ATTRIBUTE = "__gwt_subrow";
protected final AbstractCellTable cellTable;
/**
* A mapping of unique cell IDs to the cell.
*/
private final Map> idToCellMap = new HashMap>();
private final Map, String> cellToIdMap = new HashMap, String>();
private HtmlTableSectionBuilder tbody;
private int rowIndex;
private int subrowIndex;
private Object rowValueKey;
/**
* Construct a new table builder.
*
* @param cellTable the table this builder will build rows for
*/
public AbstractCellTableBuilder(AbstractCellTable cellTable) {
this.cellTable = cellTable;
}
/**
* Build zero or more table rows for the specified row value.
*
* @param rowValue the value for the row to render
* @param absRowIndex the absolute row index
*/
@Override
public final void buildRow(T rowValue, int absRowIndex) {
setRowInfo(absRowIndex, rowValue);
buildRowImpl(rowValue, absRowIndex);
}
/**
* Create the context for a column based on the current table building state.
*
* @param column the column id
* @return the context that contains the column index, row/subrow indexes, and the row value key
*/
public final Context createContext(int column) {
return new Context(rowIndex, column, rowValueKey, subrowIndex);
}
/**
* Finish the building and get the {@link TableSectionBuilder} containing the children.
*/
@Override
public final TableSectionBuilder finish() {
// End dangling elements.
while (tbody.getDepth() > 0) {
tbody.endTBody();
}
return tbody;
}
/**
* Return the column containing an element.
*
* @param context the context for the element
* @param rowValue the value for the row corresponding to the element
* @param elem the element that the column contains
* @return the immediate column containing the element
*/
@Override
public final HasCell getColumn(Context context, T rowValue, Element elem) {
return getColumn(elem);
}
/**
* Return all the columns that this table builder has renderred.
*/
@Override
public final Collection> getColumns() {
return idToCellMap.values();
}
/**
* Get the index of the row value from the associated {@link TableRowElement}.
*
* @param row the row element
* @return the row value index
*/
@Override
public final int getRowValueIndex(TableRowElement row) {
try {
return Integer.parseInt(row.getAttribute(ROW_ATTRIBUTE));
} catch (NumberFormatException e) {
// The attribute doesn't exist. Maybe the user is overriding
// renderRowValues().
return row.getSectionRowIndex() + cellTable.getPageStart();
}
}
/**
* Get the index of the subrow value from the associated
* {@link TableRowElement}. The sub row value starts at 0 for the first row
* that represents a row value.
*
* @param row the row element
* @return the subrow value index, or 0 if not found
*/
@Override
public final int getSubrowValueIndex(TableRowElement row) {
try {
return Integer.parseInt(row.getAttribute(SUBROW_ATTRIBUTE));
} catch (NumberFormatException e) {
// The attribute doesn't exist. Maybe the user is overriding
// renderRowValues() in {@link AbstractCellTable}.
return 0;
}
}
/**
* Return if an element contains a cell. This may be faster to execute than {@link getColumn}.
*
* @param elem the element of interest
*/
@Override
public final boolean isColumn(Element elem) {
return getCellId(elem) != null;
}
/**
* Render the cell into an {@link ElementBuilderBase}.
*
* @param builder the {@link ElementBuilderBase} that cell contents append to
* @param context the context for the element
* @param column the column containing the cell
* @param rowValue the value for the row corresponding to the element
*/
public final void renderCell(ElementBuilderBase> builder, Context context,
HasCell column, T rowValue) {
// Generate a unique ID for the cell.
String cellId = cellToIdMap.get(column);
if (cellId == null) {
cellId = "cell-" + Document.get().createUniqueId();
idToCellMap.put(cellId, column);
cellToIdMap.put(column, cellId);
}
builder.attribute(CELL_ATTRIBUTE, cellId);
// Render the cell into the builder.
SafeHtmlBuilder cellBuilder = new SafeHtmlBuilder();
if (column instanceof Column) {
/*
* If the HasCell is a Column, let it render the Cell itself. This is
* here for legacy support.
*/
Column theColumn = (Column) column;
theColumn.render(context, rowValue, cellBuilder);
} else {
column.getCell().render(context, column.getValue(rowValue), cellBuilder);
}
builder.html(cellBuilder.toSafeHtml());
}
/**
*
*/
/**
* Start building rows. Reset the internal table section builder. If the table builder is going
* to re-build all rows, the internal the maps associating the cells and ids will be cleared.
*
* @param isRebuildingAllRows is this start intended for rebuilding all rows
*/
@Override
public final void start(boolean isRebuildingAllRows) {
/*
* TODO(jlabanca): Test with DomBuilder.
*
* DOM manipulation is sometimes faster than String concatenation and
* innerHTML, but not when mixing the two. Cells render as HTML strings,
* so its faster to render the entire table as a string.
*/
tbody = HtmlBuilderFactory.get().createTBodyBuilder();
if (isRebuildingAllRows) {
cellToIdMap.clear();
idToCellMap.clear();
}
}
/**
* Start a row and return the {@link TableRowBuilder} for this row.
*/
public final TableRowBuilder startRow() {
// End any dangling rows.
while (tbody.getDepth() > 1) {
tbody.end();
}
// Verify the depth.
if (tbody.getDepth() < 1) {
throw new IllegalStateException(
"Cannot start a row. Did you call TableRowBuilder.end() too many times?");
}
// Start the next row.
TableRowBuilder row = tbody.startTR();
row.attribute(ROW_ATTRIBUTE, rowIndex);
row.attribute(SUBROW_ATTRIBUTE, subrowIndex);
addRowAttributes(row);
subrowIndex++;
return row;
}
/**
* Hook for subclasses to add their own attributes to each row in the table.
* The default does nothing.
*
* @param row the row element
*/
protected void addRowAttributes(TableRowBuilder row) {
}
/**
* Build zero or more table rows for the specified row value.
*
* @param rowValue the value for the row to render
* @param absRowIndex the absolute row index
*/
protected abstract void buildRowImpl(T rowValue, int absRowIndex);
/**
* Check if an element is the parent of a rendered cell.
*
* @param elem the element to check
* @return the cellId if a cell parent, null if not
*/
private String getCellId(Element elem) {
if (elem == null) {
return null;
}
String cellId = elem.getAttribute(CELL_ATTRIBUTE);
return (cellId == null) || (cellId.length() == 0) ? null : cellId;
}
/**
* Return the column containing an element.
*
* @param elem the elm that the column contains
* @return the column containing the element.
*/
private HasCell getColumn(Element elem) {
String cellId = getCellId(elem);
return (cellId == null) ? null : idToCellMap.get(cellId);
}
/**
* Set the information for the current row to build.
*
* @param rowIndex the index of the row
* @param rowValue the value of this row
*/
private void setRowInfo(int rowIndex, T rowValue) {
this.rowIndex = rowIndex;
this.rowValueKey = cellTable.getValueKey(rowValue);
this.subrowIndex = 0; // Reset the subrow.
}
}