| /* |
| * Copyright 2010 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.core.client.GWT; |
| import com.google.gwt.dom.client.BrowserEvents; |
| import com.google.gwt.dom.client.Document; |
| import com.google.gwt.dom.client.Style.TableLayout; |
| import com.google.gwt.dom.client.Style.Unit; |
| import com.google.gwt.dom.client.TableCellElement; |
| import com.google.gwt.dom.client.TableColElement; |
| import com.google.gwt.dom.client.TableElement; |
| import com.google.gwt.dom.client.TableRowElement; |
| import com.google.gwt.dom.client.TableSectionElement; |
| import com.google.gwt.resources.client.ClientBundle; |
| import com.google.gwt.resources.client.CssResource; |
| import com.google.gwt.resources.client.CssResource.ImportedWithPrefix; |
| import com.google.gwt.resources.client.ImageResource; |
| import com.google.gwt.resources.client.ImageResource.ImageOptions; |
| import com.google.gwt.resources.client.ImageResource.RepeatStyle; |
| import com.google.gwt.user.cellview.client.LoadingStateChangeEvent.LoadingState; |
| import com.google.gwt.user.client.ui.DeckPanel; |
| import com.google.gwt.user.client.ui.Image; |
| import com.google.gwt.user.client.ui.SimplePanel; |
| import com.google.gwt.user.client.ui.Widget; |
| import com.google.gwt.view.client.ProvidesKey; |
| |
| import java.util.HashSet; |
| import java.util.Set; |
| |
| /** |
| * A tabular view that supports paging and columns. |
| * |
| * <p> |
| * <h3>Columns</h3> The {@link Column} class defines the |
| * {@link com.google.gwt.cell.client.Cell} used to render a column. Implement |
| * {@link Column#getValue(Object)} to retrieve the field value from the row |
| * object that will be rendered in the {@link com.google.gwt.cell.client.Cell}. |
| * </p> |
| * |
| * <p> |
| * <h3>Headers and Footers</h3> A {@link Header} can be placed at the top |
| * (header) or bottom (footer) of the {@link CellTable}. You can specify a |
| * header as text using {@link #addColumn(Column, String)}, or you can create a |
| * custom {@link Header} that can change with the value of the cells, such as a |
| * column total. The {@link Header} will be rendered every time the row data |
| * changes or the table is redrawn. If you pass the same header instance (==) |
| * into adjacent columns, the header will span the columns. |
| * </p> |
| * |
| * <p> |
| * <h3>Examples</h3> |
| * <dl> |
| * <dt>Trivial example</dt> |
| * <dd>{@example com.google.gwt.examples.cellview.CellTableExample}</dd> |
| * <dt>Handling user input with trivial FieldUpdater example</dt> |
| * <dd>{@example com.google.gwt.examples.cellview.CellTableFieldUpdaterExample}</dd> |
| * <dt>Handling user input with complex FieldUpdater example</dt> |
| * <dd>{@example |
| * com.google.gwt.examples.cellview.CellTableFieldUpdaterExampleComplex}</dd> |
| * <dt>Pushing data with List Data Provider (backed by {@link java.util.List})</dt> |
| * <dd>{@example com.google.gwt.examples.view.ListDataProviderExample}</dd> |
| * <dt>Pushing data asynchronously with Async Data Provider</dt> |
| * <dd>{@example com.google.gwt.examples.view.AsyncDataProviderExample}</dd> |
| * <dt>Writing a custom data provider</dt> |
| * <dd>{@example com.google.gwt.examples.view.RangeChangeHandlerExample}</dd> |
| * <dt>Using a key provider to track objects as they change</dt> |
| * <dd>{@example com.google.gwt.examples.view.KeyProviderExample}</dd> |
| * </dl> |
| * </p> |
| * |
| * @param <T> the data type of each row |
| */ |
| public class CellTable<T> extends AbstractCellTable<T> implements |
| AbstractCellTable.TableSectionChangeHandler { |
| |
| /** |
| * Resources that match the GWT standard style theme. |
| */ |
| public interface BasicResources extends Resources { |
| /** |
| * The styles used in this widget. |
| */ |
| @Override |
| @Source(BasicStyle.DEFAULT_CSS) |
| BasicStyle cellTableStyle(); |
| } |
| |
| /** |
| * A ClientBundle that provides images for this widget. |
| */ |
| public interface Resources extends ClientBundle { |
| /** |
| * The background used for footer cells. |
| */ |
| @Source("cellTableHeaderBackground.png") |
| @ImageOptions(repeatStyle = RepeatStyle.Horizontal, flipRtl = true) |
| ImageResource cellTableFooterBackground(); |
| |
| /** |
| * The background used for header cells. |
| */ |
| @ImageOptions(repeatStyle = RepeatStyle.Horizontal, flipRtl = true) |
| ImageResource cellTableHeaderBackground(); |
| |
| /** |
| * The loading indicator used while the table is waiting for data. |
| */ |
| @ImageOptions(flipRtl = true) |
| ImageResource cellTableLoading(); |
| |
| /** |
| * The background used for selected cells. |
| */ |
| @Source("cellListSelectedBackground.png") |
| @ImageOptions(repeatStyle = RepeatStyle.Horizontal, flipRtl = true) |
| ImageResource cellTableSelectedBackground(); |
| |
| /** |
| * Icon used when a column is sorted in ascending order. |
| */ |
| @Source("sortAscending.png") |
| @ImageOptions(flipRtl = true) |
| ImageResource cellTableSortAscending(); |
| |
| /** |
| * Icon used when a column is sorted in descending order. |
| */ |
| @Source("sortDescending.png") |
| @ImageOptions(flipRtl = true) |
| ImageResource cellTableSortDescending(); |
| |
| /** |
| * The styles used in this widget. |
| */ |
| @Source(Style.DEFAULT_CSS) |
| Style cellTableStyle(); |
| } |
| |
| /** |
| * Styles used by this widget. |
| */ |
| @ImportedWithPrefix("gwt-CellTable") |
| public interface Style extends CssResource { |
| /** |
| * The path to the default CSS styles used by this resource. |
| */ |
| String DEFAULT_CSS = "com/google/gwt/user/cellview/client/CellTable.css"; |
| |
| /** |
| * Applied to every cell. |
| */ |
| String cellTableCell(); |
| |
| /** |
| * Applied to even rows. |
| */ |
| String cellTableEvenRow(); |
| |
| /** |
| * Applied to cells in even rows. |
| */ |
| String cellTableEvenRowCell(); |
| |
| /** |
| * Applied to the first column. |
| */ |
| String cellTableFirstColumn(); |
| |
| /** |
| * Applied to the first column footers. |
| */ |
| String cellTableFirstColumnFooter(); |
| |
| /** |
| * Applied to the first column headers. |
| */ |
| String cellTableFirstColumnHeader(); |
| |
| /** |
| * Applied to footers cells. |
| */ |
| String cellTableFooter(); |
| |
| /** |
| * Applied to headers cells. |
| */ |
| String cellTableHeader(); |
| |
| /** |
| * Applied to the hovered row. |
| */ |
| String cellTableHoveredRow(); |
| |
| /** |
| * Applied to the cells in the hovered row. |
| */ |
| String cellTableHoveredRowCell(); |
| |
| /** |
| * Applied to the keyboard selected cell. |
| */ |
| String cellTableKeyboardSelectedCell(); |
| |
| /** |
| * Applied to the keyboard selected row. |
| */ |
| String cellTableKeyboardSelectedRow(); |
| |
| /** |
| * Applied to the cells in the keyboard selected row. |
| */ |
| String cellTableKeyboardSelectedRowCell(); |
| |
| /** |
| * Applied to the last column. |
| */ |
| String cellTableLastColumn(); |
| |
| /** |
| * Applied to the last column footers. |
| */ |
| String cellTableLastColumnFooter(); |
| |
| /** |
| * Applied to the last column headers. |
| */ |
| String cellTableLastColumnHeader(); |
| |
| /** |
| * Applied to the loading indicator. |
| */ |
| String cellTableLoading(); |
| |
| /** |
| * Applied to odd rows. |
| */ |
| String cellTableOddRow(); |
| |
| /** |
| * Applied to cells in odd rows. |
| */ |
| String cellTableOddRowCell(); |
| |
| /** |
| * Applied to selected rows. |
| */ |
| String cellTableSelectedRow(); |
| |
| /** |
| * Applied to cells in selected rows. |
| */ |
| String cellTableSelectedRowCell(); |
| |
| /** |
| * Applied to header cells that are sortable. |
| */ |
| String cellTableSortableHeader(); |
| |
| /** |
| * Applied to header cells that are sorted in ascending order. |
| */ |
| String cellTableSortedHeaderAscending(); |
| |
| /** |
| * Applied to header cells that are sorted in descending order. |
| */ |
| String cellTableSortedHeaderDescending(); |
| |
| /** |
| * Applied to the table. |
| */ |
| String cellTableWidget(); |
| } |
| |
| /** |
| * Styles used by {@link BasicResources}. |
| */ |
| @ImportedWithPrefix("gwt-CellTable") |
| interface BasicStyle extends Style { |
| /** |
| * The path to the default CSS styles used by this resource. |
| */ |
| String DEFAULT_CSS = "com/google/gwt/user/cellview/client/CellTableBasic.css"; |
| } |
| |
| /** |
| * Adapter class to convert {@link Resources} to |
| * {@link AbstractCellTable.Resources}. |
| */ |
| private static class ResourcesAdapter implements AbstractCellTable.Resources { |
| |
| private final CellTable.Resources resources; |
| private final StyleAdapter style; |
| |
| public ResourcesAdapter(CellTable.Resources resources) { |
| this.resources = resources; |
| this.style = new StyleAdapter(resources.cellTableStyle()); |
| } |
| |
| @Override |
| public ImageResource sortAscending() { |
| return resources.cellTableSortAscending(); |
| } |
| |
| @Override |
| public ImageResource sortDescending() { |
| return resources.cellTableSortDescending(); |
| } |
| |
| @Override |
| public AbstractCellTable.Style style() { |
| return style; |
| } |
| } |
| |
| /** |
| * Adapter class to convert {@link Style} to {@link AbstractCellTable.Style}. |
| */ |
| private static class StyleAdapter implements AbstractCellTable.Style { |
| private final CellTable.Style style; |
| |
| public StyleAdapter(CellTable.Style style) { |
| this.style = style; |
| } |
| |
| @Override |
| public String cell() { |
| return style.cellTableCell(); |
| } |
| |
| @Override |
| public String evenRow() { |
| return style.cellTableEvenRow(); |
| } |
| |
| @Override |
| public String evenRowCell() { |
| return style.cellTableEvenRowCell(); |
| } |
| |
| @Override |
| public String firstColumn() { |
| return style.cellTableFirstColumn(); |
| } |
| |
| @Override |
| public String firstColumnFooter() { |
| return style.cellTableFirstColumnFooter(); |
| } |
| |
| @Override |
| public String firstColumnHeader() { |
| return style.cellTableFirstColumnHeader(); |
| } |
| |
| @Override |
| public String footer() { |
| return style.cellTableFooter(); |
| } |
| |
| @Override |
| public String header() { |
| return style.cellTableHeader(); |
| } |
| |
| @Override |
| public String hoveredRow() { |
| return style.cellTableHoveredRow(); |
| } |
| |
| @Override |
| public String hoveredRowCell() { |
| return style.cellTableHoveredRowCell(); |
| } |
| |
| @Override |
| public String keyboardSelectedCell() { |
| return style.cellTableKeyboardSelectedCell(); |
| } |
| |
| @Override |
| public String keyboardSelectedRow() { |
| return style.cellTableKeyboardSelectedRow(); |
| } |
| |
| @Override |
| public String keyboardSelectedRowCell() { |
| return style.cellTableKeyboardSelectedRowCell(); |
| } |
| |
| @Override |
| public String lastColumn() { |
| return style.cellTableLastColumn(); |
| } |
| |
| @Override |
| public String lastColumnFooter() { |
| return style.cellTableLastColumnFooter(); |
| } |
| |
| @Override |
| public String lastColumnHeader() { |
| return style.cellTableLastColumnHeader(); |
| } |
| |
| @Override |
| public String oddRow() { |
| return style.cellTableOddRow(); |
| } |
| |
| @Override |
| public String oddRowCell() { |
| return style.cellTableOddRowCell(); |
| } |
| |
| @Override |
| public String selectedRow() { |
| return style.cellTableSelectedRow(); |
| } |
| |
| @Override |
| public String selectedRowCell() { |
| return style.cellTableSelectedRowCell(); |
| } |
| |
| @Override |
| public String sortableHeader() { |
| return style.cellTableSortableHeader(); |
| } |
| |
| @Override |
| public String sortedHeaderAscending() { |
| return style.cellTableSortedHeaderAscending(); |
| } |
| |
| @Override |
| public String sortedHeaderDescending() { |
| return style.cellTableSortedHeaderDescending(); |
| } |
| |
| @Override |
| public String widget() { |
| return style.cellTableWidget(); |
| } |
| } |
| |
| /** |
| * The default page size. |
| */ |
| private static final int DEFAULT_PAGESIZE = 15; |
| |
| private static Resources DEFAULT_RESOURCES; |
| |
| private static Resources getDefaultResources() { |
| if (DEFAULT_RESOURCES == null) { |
| DEFAULT_RESOURCES = GWT.create(Resources.class); |
| } |
| return DEFAULT_RESOURCES; |
| } |
| |
| /** |
| * Create the default loading indicator using the loading image in the |
| * specified {@link Resources}. |
| * |
| * @param resources the resources |
| * @return a widget loading indicator |
| */ |
| private static Widget createDefaultLoadingIndicator(Resources resources) { |
| ImageResource loadingImg = resources.cellTableLoading(); |
| return (loadingImg == null) ? null : new Image(loadingImg); |
| } |
| |
| final TableColElement colgroup; |
| private final SimplePanel emptyTableWidgetContainer = new SimplePanel(); |
| private final SimplePanel loadingIndicatorContainer = new SimplePanel(); |
| |
| /** |
| * A {@link DeckPanel} to hold widgets associated with various loading states. |
| */ |
| private final DeckPanel messagesPanel = new DeckPanel(); |
| |
| private final Style style; |
| private final TableElement table; |
| private TableSectionElement tbody; |
| private final TableSectionElement tbodyLoading; |
| private final TableCellElement tbodyLoadingCell; |
| private TableSectionElement tfoot; |
| private TableSectionElement thead; |
| private boolean colGroupEnabled = true; |
| |
| /** |
| * Constructs a table with a default page size of 15. |
| */ |
| public CellTable() { |
| this(DEFAULT_PAGESIZE); |
| } |
| |
| /** |
| * Constructs a table with the given page size. |
| * |
| * @param pageSize the page size |
| */ |
| public CellTable(final int pageSize) { |
| this(pageSize, getDefaultResources()); |
| } |
| |
| /** |
| * Constructs a table with a default page size of 15, and the given |
| * {@link ProvidesKey key provider}. |
| * |
| * @param keyProvider an instance of ProvidesKey<T>, or null if the record |
| * object should act as its own key |
| */ |
| public CellTable(ProvidesKey<T> keyProvider) { |
| this(DEFAULT_PAGESIZE, keyProvider); |
| } |
| |
| /** |
| * Constructs a table with the given page size with the specified |
| * {@link Resources}. |
| * |
| * @param pageSize the page size |
| * @param resources the resources to use for this widget |
| */ |
| public CellTable(int pageSize, Resources resources) { |
| this(pageSize, resources, null); |
| } |
| |
| /** |
| * Constructs a table with the given page size and the given |
| * {@link ProvidesKey key provider}. |
| * |
| * @param pageSize the page size |
| * @param keyProvider an instance of ProvidesKey<T>, or null if the record |
| * object should act as its own key |
| */ |
| public CellTable(int pageSize, ProvidesKey<T> keyProvider) { |
| this(pageSize, getDefaultResources(), keyProvider); |
| } |
| |
| /** |
| * Constructs a table with the given page size, the specified |
| * {@link Resources}, and the given key provider. |
| * |
| * @param pageSize the page size |
| * @param resources the resources to use for this widget |
| * @param keyProvider an instance of ProvidesKey<T>, or null if the record |
| * object should act as its own key |
| */ |
| public CellTable(final int pageSize, Resources resources, ProvidesKey<T> keyProvider) { |
| this(pageSize, resources, keyProvider, createDefaultLoadingIndicator(resources)); |
| } |
| |
| /** |
| * Constructs a table with the specified page size, {@link Resources}, key |
| * provider, and loading indicator. |
| * |
| * @param pageSize the page size |
| * @param resources the resources to use for this widget |
| * @param keyProvider an instance of ProvidesKey<T>, or null if the record |
| * object should act as its own key |
| * @param loadingIndicator the widget to use as a loading indicator, or null |
| * to disable |
| */ |
| public CellTable(final int pageSize, Resources resources, ProvidesKey<T> keyProvider, |
| Widget loadingIndicator) { |
| this(pageSize, resources, keyProvider, loadingIndicator, true, true); |
| } |
| |
| /** |
| * Constructs a table with the specified page size, {@link Resources}, key |
| * provider, and loading indicator. |
| * |
| * @param pageSize the page size |
| * @param resources the resources to use for this widget |
| * @param keyProvider an instance of ProvidesKey<T>, or null if the record |
| * object should act as its own key |
| * @param loadingIndicator the widget to use as a loading indicator, or null |
| * to disable |
| * @param enableColGroup enable colgroup element. This is used when the table is using fixed |
| * layout and when column style is added. Ignoring this element will boost rendering |
| * performance. Note that when colgroup is disabled, {@link #setColumnWidth}, |
| * {@link setTableLayoutFixed} and {@link addColumnStyleName} are no longe supported |
| * @param attachLoadingPanel attaching the table section that contains the empty table widget and |
| * the loading indicator. Attaching this to the table significantly improve the rendering |
| * performance in webkit based browsers but also introduces significantly larger latency |
| * in IE. If the panel is not attached to the table, it won't be displayed. But the user |
| * can call {@link #getTableLoadingSection} and attach it to other elements outside the |
| * table element |
| */ |
| public CellTable(final int pageSize, Resources resources, ProvidesKey<T> keyProvider, |
| Widget loadingIndicator, boolean enableColGroup, boolean attachLoadingPanel) { |
| super(Document.get().createTableElement(), pageSize, new ResourcesAdapter(resources), |
| keyProvider); |
| this.style = resources.cellTableStyle(); |
| this.style.ensureInjected(); |
| this.colGroupEnabled = enableColGroup; |
| |
| table = getElement().cast(); |
| table.setCellSpacing(0); |
| if (enableColGroup) { |
| colgroup = Document.get().createColGroupElement(); |
| table.appendChild(colgroup); |
| } else { |
| colgroup = null; |
| } |
| thead = table.createTHead(); |
| // Some browsers create a tbody automatically, others do not. |
| if (table.getTBodies().getLength() > 0) { |
| tbody = table.getTBodies().getItem(0); |
| } else { |
| tbody = Document.get().createTBodyElement(); |
| table.appendChild(tbody); |
| } |
| tbodyLoading = Document.get().createTBodyElement(); |
| if (attachLoadingPanel) { |
| table.appendChild(tbodyLoading); |
| } |
| tfoot = table.createTFoot(); |
| setStyleName(resources.cellTableStyle().cellTableWidget()); |
| |
| // Attach the messages panel. |
| { |
| tbodyLoadingCell = Document.get().createTDElement(); |
| TableRowElement tr = Document.get().createTRElement(); |
| tbodyLoading.appendChild(tr); |
| tr.appendChild(tbodyLoadingCell); |
| tbodyLoadingCell.setAlign("center"); |
| tbodyLoadingCell.appendChild(messagesPanel.getElement()); |
| adopt(messagesPanel); |
| messagesPanel.add(emptyTableWidgetContainer); |
| messagesPanel.add(loadingIndicatorContainer); |
| loadingIndicatorContainer.setStyleName(style.cellTableLoading()); |
| } |
| |
| // Set the loading indicator. |
| setLoadingIndicator(loadingIndicator); // Can be null. |
| |
| // Sink events. |
| Set<String> eventTypes = new HashSet<String>(); |
| eventTypes.add(BrowserEvents.MOUSEOVER); |
| eventTypes.add(BrowserEvents.MOUSEOUT); |
| CellBasedWidgetImpl.get().sinkEvents(this, eventTypes); |
| } |
| |
| @Override |
| public void addColumnStyleName(int index, String styleName) { |
| assertColumnGroupEnabled("Cannot add column style when colgroup is disabled"); |
| ensureTableColElement(index).addClassName(styleName); |
| } |
| |
| /** |
| * Return the height of the table body. |
| * |
| * @return an int representing the body height |
| */ |
| public int getBodyHeight() { |
| return tbody.getClientHeight(); |
| } |
| |
| /** |
| * Return the height of the table header. |
| * |
| * @return an int representing the header height |
| */ |
| public int getHeaderHeight() { |
| return thead.getClientHeight(); |
| } |
| |
| /** |
| * Return the section that display loading indicator and the empty table widget. If |
| * attachLoadingPanel is set to false in the constructor, this section may not be attached |
| * to any element. |
| */ |
| public TableSectionElement getTableLoadingSection() { |
| return tbodyLoading; |
| } |
| |
| @Override |
| public void onTableBodyChange(TableSectionElement newTBody) { |
| tbody = newTBody; |
| } |
| |
| @Override |
| public void onTableFootChange(TableSectionElement newTFoot) { |
| tfoot = newTFoot; |
| } |
| |
| @Override |
| public void onTableHeadChange(TableSectionElement newTHead) { |
| thead = newTHead; |
| } |
| |
| @Override |
| public void removeColumnStyleName(int index, String styleName) { |
| assertColumnGroupEnabled("Cannot remove column style when colgroup is disabled"); |
| if (index >= colgroup.getChildCount()) { |
| return; |
| } |
| ensureTableColElement(index).removeClassName(styleName); |
| } |
| |
| /** |
| * {@inheritDoc} |
| * |
| * <p> |
| * The layout behavior depends on whether or not the table is using fixed |
| * layout. |
| * </p> |
| * |
| * @see #setTableLayoutFixed(boolean) |
| */ |
| @Override |
| public void setColumnWidth(Column<T, ?> column, String width) { |
| assertColumnGroupEnabled("Cannot set column width when colgroup is disabled"); |
| // Overridden to add JavaDoc comments about fixed layout. |
| super.setColumnWidth(column, width); |
| } |
| |
| /** |
| * {@inheritDoc} |
| * |
| * <p> |
| * The layout behavior depends on whether or not the table is using fixed |
| * layout. |
| * </p> |
| * |
| * @see #setTableLayoutFixed(boolean) |
| */ |
| @Override |
| public void setColumnWidth(Column<T, ?> column, double width, Unit unit) { |
| // Overridden to add JavaDoc comments about fixed layout. |
| super.setColumnWidth(column, width, unit); |
| } |
| |
| @Override |
| public void setEmptyTableWidget(Widget widget) { |
| emptyTableWidgetContainer.setWidget(widget); |
| super.setEmptyTableWidget(widget); |
| } |
| |
| @Override |
| public void setLoadingIndicator(Widget widget) { |
| loadingIndicatorContainer.setWidget(widget); |
| super.setLoadingIndicator(widget); |
| } |
| |
| /** |
| * <p> |
| * Enable or disable fixed table layout. |
| * </p> |
| * |
| * <p> |
| * <h1>Fixed Table Layout</h1> |
| * When using the fixed table layout, cell contents are truncated as needed, |
| * which allows you to set the exact width of columns and the table. The |
| * default column width is 0 (invisible). In order to see all columns, you |
| * must set the width of the table (recommended 100%), or set the width of |
| * every column in the table. The following conditions are true for fixed |
| * layout tables: |
| * <ul> |
| * <li> |
| * If the widths of <b>all</b> columns are set, the width becomes a weight and |
| * the columns are resized proportionally.</li> |
| * <li>If the widths of <b>some</b> columns are set using absolute values |
| * (PX), those columns are fixed and the remaining width is divided evenly |
| * over the other columns. If there is no remaining width, the other columns |
| * will not be visible.</li> |
| * <li>If the width of some columns are set in absolute values (PX) and others |
| * are set in relative values (PCT), the absolute columns will be fixed and |
| * the remaining width is divided proportionally over the PCT columns. This |
| * allows users to define how the remaining width is allocated.</li> |
| * </ul> |
| * </p> |
| * |
| * @param isFixed true to use fixed table layout, false not to |
| * @see <a href="http://www.w3.org/TR/CSS2/tables.html#width-layout">W3C HTML |
| * Specification</a> |
| */ |
| public void setTableLayoutFixed(boolean isFixed) { |
| if (isFixed && !colGroupEnabled) { |
| throw new IllegalStateException("Cannot set table to fixed layout when colgroup is disabled"); |
| } |
| if (isFixed) { |
| table.getStyle().setTableLayout(TableLayout.FIXED); |
| } else { |
| table.getStyle().clearTableLayout(); |
| } |
| } |
| |
| /** |
| * Set the width of the width and specify whether or not it should use fixed |
| * table layout. See {@link #setTableLayoutFixed(boolean)} for more |
| * information about fixed layout tables. |
| * |
| * @param width the width of the table |
| * @param isFixedLayout true to use fixed width layout, false not to |
| * @see #setTableLayoutFixed(boolean) |
| * @see <a href="http://www.w3.org/TR/CSS2/tables.html#width-layout">W3C HTML |
| * Specification</a> |
| */ |
| public final void setWidth(String width, boolean isFixedLayout) { |
| super.setWidth(width); |
| setTableLayoutFixed(isFixedLayout); |
| } |
| |
| @Override |
| protected void doSetColumnWidth(int column, String width) { |
| // This is invoked when column width is set (which will throw an exception if colgroup is not |
| // enabled), and refreshColumnWidth/clearColumnWidth. The latter two are no op if setColumnWidth |
| // is not invoked first. |
| if (colGroupEnabled) { |
| if (width == null) { |
| ensureTableColElement(column).getStyle().clearWidth(); |
| } else { |
| ensureTableColElement(column).getStyle().setProperty("width", width); |
| } |
| } |
| } |
| |
| @Override |
| protected void doSetHeaderVisible(boolean isFooter, boolean isVisible) { |
| setVisible(isFooter ? tfoot : thead, isVisible); |
| } |
| |
| @Override |
| protected TableSectionElement getTableBodyElement() { |
| return tbody; |
| } |
| |
| @Override |
| protected TableSectionElement getTableFootElement() { |
| return tfoot; |
| } |
| |
| @Override |
| protected TableSectionElement getTableHeadElement() { |
| return thead; |
| } |
| |
| /** |
| * Called when the loading state changes. |
| * |
| * @param state the new loading state |
| */ |
| @Override |
| protected void onLoadingStateChanged(LoadingState state) { |
| Widget message = null; |
| if (state == LoadingState.LOADING) { |
| // Loading indicator. |
| message = loadingIndicatorContainer; |
| } else if (state == LoadingState.LOADED && getPresenter().isEmpty()) { |
| // Empty table. |
| message = emptyTableWidgetContainer; |
| } |
| |
| // Switch out the message to display. |
| if (message != null) { |
| messagesPanel.showWidget(messagesPanel.getWidgetIndex(message)); |
| } |
| |
| // Adjust the colspan of the messages panel container. |
| tbodyLoadingCell.setColSpan(Math.max(1, getRealColumnCount())); |
| |
| // Show the correct container. |
| showOrHide(getChildContainer(), message == null); |
| showOrHide(tbodyLoading, message != null); |
| |
| // Fire an event. |
| super.onLoadingStateChanged(state); |
| } |
| |
| @Override |
| protected void refreshColumnWidths() { |
| super.refreshColumnWidths(); |
| |
| /* |
| * Set the width to zero for all col elements that appear after the last |
| * column. Clearing the width would cause it to take up the remaining width |
| * in a fixed layout table. |
| */ |
| if (colGroupEnabled) { |
| int colCount = colgroup.getChildCount(); |
| for (int i = getRealColumnCount(); i < colCount; i++) { |
| doSetColumnWidth(i, "0px"); |
| } |
| } |
| } |
| |
| /** |
| * Assert if colgroup is enabled, and throw an exception with the supplied message if it's not |
| * enabled. |
| */ |
| private void assertColumnGroupEnabled(String message) { |
| if (!colGroupEnabled) { |
| throw new IllegalStateException(message); |
| } |
| } |
| |
| /** |
| * Get the {@link TableColElement} at the specified index, creating it if |
| * necessary. |
| * |
| * @param index the column index |
| * @return the {@link TableColElement} |
| */ |
| private TableColElement ensureTableColElement(int index) { |
| // Ensure that we have enough columns. |
| for (int i = colgroup.getChildCount(); i <= index; i++) { |
| colgroup.appendChild(Document.get().createColElement()); |
| } |
| return colgroup.getChild(index).cast(); |
| } |
| } |