All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.google.gwt.user.client.ui.HTMLTable Maven / Gradle / Ivy

There is a newer version: 2.8.2-v20191108
Show newest version
/*
 * Copyright 2007 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.client.ui;

import com.google.gwt.core.client.JsArray;
import com.google.gwt.core.shared.GWT;
import com.google.gwt.dom.client.Document;
import com.google.gwt.dom.client.Element;
import com.google.gwt.dom.client.TableCellElement;
import com.google.gwt.dom.client.TableRowElement;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.event.dom.client.DoubleClickEvent;
import com.google.gwt.event.dom.client.DoubleClickHandler;
import com.google.gwt.event.dom.client.DragEndEvent;
import com.google.gwt.event.dom.client.DragEndHandler;
import com.google.gwt.event.dom.client.DragEnterEvent;
import com.google.gwt.event.dom.client.DragEnterHandler;
import com.google.gwt.event.dom.client.DragEvent;
import com.google.gwt.event.dom.client.DragHandler;
import com.google.gwt.event.dom.client.DragLeaveEvent;
import com.google.gwt.event.dom.client.DragLeaveHandler;
import com.google.gwt.event.dom.client.DragOverEvent;
import com.google.gwt.event.dom.client.DragOverHandler;
import com.google.gwt.event.dom.client.DragStartEvent;
import com.google.gwt.event.dom.client.DragStartHandler;
import com.google.gwt.event.dom.client.DropEvent;
import com.google.gwt.event.dom.client.DropHandler;
import com.google.gwt.event.dom.client.HasAllDragAndDropHandlers;
import com.google.gwt.event.dom.client.HasClickHandlers;
import com.google.gwt.event.dom.client.HasDoubleClickHandlers;
import com.google.gwt.event.shared.HandlerRegistration;
import com.google.gwt.safehtml.shared.SafeHtml;
import com.google.gwt.safehtml.shared.annotations.IsSafeHtml;
import com.google.gwt.user.client.DOM;
import com.google.gwt.user.client.Event;
import com.google.gwt.user.client.impl.ElementMapperImpl;
import com.google.gwt.user.client.ui.HasHorizontalAlignment.HorizontalAlignmentConstant;
import com.google.gwt.user.client.ui.HasVerticalAlignment.VerticalAlignmentConstant;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.NoSuchElementException;

/**
 * HTMLTable contains the common table algorithms for
 * {@link com.google.gwt.user.client.ui.Grid} and
 * {@link com.google.gwt.user.client.ui.FlexTable}.
 * 

* *

*/ @SuppressWarnings("deprecation") public abstract class HTMLTable extends Panel implements SourcesTableEvents, HasAllDragAndDropHandlers, HasClickHandlers, HasDoubleClickHandlers { /** * Interface to access {@link HTMLTable}'s DOM. */ private interface HTMLTableImpl { JsArray getRows(Element tbody); JsArray getCells(Element row); } /** * Standard implementation for accessing the Table DOM. */ @SuppressWarnings("unused") // used due to rebinding private static class HTMLTableStandardImpl implements HTMLTableImpl { @Override public native JsArray getRows(Element tbody) /*-{ return tbody.rows; }-*/; @Override public native JsArray getCells(Element row) /*-{ return row.cells; }-*/; } /** * IE specific implementation for accessing the Table DOM. * see: issue 6938 */ @SuppressWarnings("unused") // used due to rebinding private static class HTMLTableIEImpl implements HTMLTableImpl { @Override public native JsArray getRows(Element tbody) /*-{ return tbody.children; }-*/; @Override public native JsArray getCells(Element row) /*-{ return row.children; }-*/; } /** * Return value for {@link HTMLTable#getCellForEvent}. */ public class Cell { private final int rowIndex; private final int cellIndex; /** * Creates a cell. * * @param rowIndex the cell's row * @param cellIndex the cell's index */ protected Cell(int rowIndex, int cellIndex) { this.cellIndex = cellIndex; this.rowIndex = rowIndex; } /** * Gets the cell index. * * @return the cell index */ public int getCellIndex() { return cellIndex; } /** * Gets the cell's element. * * @return the cell's element. */ public com.google.gwt.user.client.Element getElement() { return DOM.asOld(getCellFormatter().getElement(rowIndex, cellIndex)); } /** * Get row index. * * @return the row index */ public int getRowIndex() { return rowIndex; } } /** * This class contains methods used to format a table's cells. */ public class CellFormatter { /** * Adds a style to the specified cell. * * @param row the cell's row * @param column the cell's column * @param styleName the style name to be added * @see UIObject#addStyleName(String) */ public void addStyleName(int row, int column, String styleName) { prepareCell(row, column); Element td = getCellElement(bodyElem, row, column); UIObject.setStyleName(td, styleName, true); } /** * Gets the TD element representing the specified cell. * * @param row the row of the cell to be retrieved * @param column the column of the cell to be retrieved * @return the column's TD element * @throws IndexOutOfBoundsException */ public com.google.gwt.user.client.Element getElement(int row, int column) { checkCellBounds(row, column); return DOM.asOld(getCellElement(bodyElem, row, column)); } /** * Gets the style of a specified cell. * * @param row the cell's row * @param column the cell's column * @see UIObject#getStyleName() * @return returns the style name * @throws IndexOutOfBoundsException */ public String getStyleName(int row, int column) { return UIObject.getStyleName(getElement(row, column)); } /** * Gets the primary style of a specified cell. * * @param row the cell's row * @param column the cell's column * @see UIObject#getStylePrimaryName() * @return returns the style name * @throws IndexOutOfBoundsException */ public String getStylePrimaryName(int row, int column) { return UIObject.getStylePrimaryName(getElement(row, column)); } /** * Determines whether or not this cell is visible. * * @param row the row of the cell whose visibility is to be set * @param column the column of the cell whose visibility is to be set * @return true if the object is visible */ public boolean isVisible(int row, int column) { Element e = getElement(row, column); return UIObject.isVisible(e); } /** * Removes a style from the specified cell. * * @param row the cell's row * @param column the cell's column * @param styleName the style name to be removed * @see UIObject#removeStyleName(String) * @throws IndexOutOfBoundsException */ public void removeStyleName(int row, int column, String styleName) { checkCellBounds(row, column); Element td = getCellElement(bodyElem, row, column); UIObject.setStyleName(td, styleName, false); } /** * Sets the horizontal and vertical alignment of the specified cell's * contents. * * @param row the row of the cell whose alignment is to be set * @param column the column of the cell whose alignment is to be set * @param hAlign the cell's new horizontal alignment as specified in * {@link HasHorizontalAlignment} * @param vAlign the cell's new vertical alignment as specified in * {@link HasVerticalAlignment} * @throws IndexOutOfBoundsException */ public void setAlignment(int row, int column, HorizontalAlignmentConstant hAlign, VerticalAlignmentConstant vAlign) { setHorizontalAlignment(row, column, hAlign); setVerticalAlignment(row, column, vAlign); } /** * Sets the height of the specified cell. * * @param row the row of the cell whose height is to be set * @param column the column of the cell whose height is to be set * @param height the cell's new height, in CSS units * @throws IndexOutOfBoundsException */ public void setHeight(int row, int column, String height) { prepareCell(row, column); Element elem = getCellElement(bodyElem, row, column); elem.setPropertyString("height", height); } /** * Sets the horizontal alignment of the specified cell. * * @param row the row of the cell whose alignment is to be set * @param column the column of the cell whose alignment is to be set * @param align the cell's new horizontal alignment as specified in * {@link HasHorizontalAlignment}. * @throws IndexOutOfBoundsException */ public void setHorizontalAlignment(int row, int column, HorizontalAlignmentConstant align) { prepareCell(row, column); Element elem = getCellElement(bodyElem, row, column); elem.setPropertyString("align", align.getTextAlignString()); } /** * Sets the style name associated with the specified cell. * * @param row the row of the cell whose style name is to be set * @param column the column of the cell whose style name is to be set * @param styleName the new style name * @see UIObject#setStyleName(String) * @throws IndexOutOfBoundsException */ public void setStyleName(int row, int column, String styleName) { prepareCell(row, column); UIObject.setStyleName(getCellElement(bodyElem, row, column), styleName); } /** * Sets the primary style name associated with the specified cell. * * @param row the row of the cell whose style name is to be set * @param column the column of the cell whose style name is to be set * @param styleName the new style name * @see UIObject#setStylePrimaryName(String) * @throws IndexOutOfBoundsException */ public void setStylePrimaryName(int row, int column, String styleName) { UIObject.setStylePrimaryName(getCellElement(bodyElem, row, column), styleName); } /** * Sets the vertical alignment of the specified cell. * * @param row the row of the cell whose alignment is to be set * @param column the column of the cell whose alignment is to be set * @param align the cell's new vertical alignment as specified in * {@link HasVerticalAlignment}. * @throws IndexOutOfBoundsException */ public void setVerticalAlignment(int row, int column, VerticalAlignmentConstant align) { prepareCell(row, column); getCellElement(bodyElem, row, column).getStyle() .setProperty("verticalAlign", align.getVerticalAlignString()); } /** * Sets whether this cell is visible via the display style property. The * other cells in the row will all shift left to fill the cell's space. So, * for example a table with (0,1,2) will become (1,2) if cell 1 is hidden. * * @param row the row of the cell whose visibility is to be set * @param column the column of the cell whose visibility is to be set * @param visible true to show the cell, false to * hide it */ public void setVisible(int row, int column, boolean visible) { Element e = ensureElement(row, column); UIObject.setVisible(e, visible); } /** * Sets the width of the specified cell. * * @param row the row of the cell whose width is to be set * @param column the column of the cell whose width is to be set * @param width the cell's new width, in CSS units * @throws IndexOutOfBoundsException */ public void setWidth(int row, int column, String width) { // Give the subclass a chance to prepare the cell. prepareCell(row, column); getCellElement(bodyElem, row, column).setPropertyString("width", width); } /** * Sets whether the specified cell will allow word wrapping of its contents. * * @param row the row of the cell whose word-wrap is to be set * @param column the column of the cell whose word-wrap is to be set * @param wrap false to disable word wrapping in this cell * @throws IndexOutOfBoundsException */ public void setWordWrap(int row, int column, boolean wrap) { prepareCell(row, column); String wrapValue = wrap ? "" : "nowrap"; getElement(row, column).getStyle().setProperty("whiteSpace", wrapValue); } /** * Gets the element associated with a cell. If it does not exist and the * subtype allows creation of elements, creates it. * * @param row the cell's row * @param column the cell's column * @return the cell's element * @throws IndexOutOfBoundsException */ protected com.google.gwt.user.client.Element ensureElement(int row, int column) { prepareCell(row, column); return DOM.asOld(getCellElement(bodyElem, row, column)); } /** * Convenience methods to get an attribute on a cell. * * @param row cell's row * @param column cell's column * @param attr attribute to get * @return the attribute's value * @throws IndexOutOfBoundsException */ protected String getAttr(int row, int column, String attr) { Element elem = getElement(row, column); return elem.getAttribute(attr); } /** * Convenience methods to set an attribute on a cell. * * @param row cell's row * @param column cell's column * @param attrName attribute to set * @param value value to set * @throws IndexOutOfBoundsException */ protected void setAttr(int row, int column, String attrName, String value) { Element elem = ensureElement(row, column); elem.setAttribute(attrName, value); } /** * Get a cell's element. * * @param tbody the table element * @param row the row of the cell * @param col the column of the cell * @return the element */ private Element getCellElement(Element tbody, int row, int col) { return impl.getCells(impl.getRows(tbody).get(row)).get(col); } /** * Gets the TD element representing the specified cell unsafely (meaning * that it doesn't ensure that row and column are * valid). * * @param row the row of the cell to be retrieved * @param column the column of the cell to be retrieved * @return the cell's TD element */ private Element getRawElement(int row, int column) { return getCellElement(bodyElem, row, column); } } /** * This class contains methods used to format a table's columns. It is limited * by the support cross-browser HTML support for column formatting. */ public class ColumnFormatter { protected Element columnGroup; /** * Adds a style to the specified column. * * @param col the col to which the style will be added * @param styleName the style name to be added * @see UIObject#addStyleName(String) * @throws IndexOutOfBoundsException */ public void addStyleName(int col, String styleName) { UIObject.setStyleName(ensureColumn(col), styleName, true); } /** * Get the col element for the column. * * @param column the column index * @return the col element */ public com.google.gwt.user.client.Element getElement(int column) { return DOM.asOld(ensureColumn(column)); } /** * Gets the style of the specified column. * * @param column the column to be queried * @return the style name * @see UIObject#getStyleName() * @throws IndexOutOfBoundsException */ public String getStyleName(int column) { return UIObject.getStyleName(ensureColumn(column)); } /** * Gets the primary style of the specified column. * * @param column the column to be queried * @return the style name * @see UIObject#getStylePrimaryName() * @throws IndexOutOfBoundsException */ public String getStylePrimaryName(int column) { return UIObject.getStylePrimaryName(ensureColumn(column)); } /** * Removes a style from the specified column. * * @param column the column from which the style will be removed * @param styleName the style name to be removed * @see UIObject#removeStyleName(String) * @throws IndexOutOfBoundsException */ public void removeStyleName(int column, String styleName) { UIObject.setStyleName(ensureColumn(column), styleName, false); } /** * Sets the style name associated with the specified column. * * @param column the column whose style name is to be set * @param styleName the new style name * @see UIObject#setStyleName(String) * @throws IndexOutOfBoundsException */ public void setStyleName(int column, String styleName) { UIObject.setStyleName(ensureColumn(column), styleName); } /** * Sets the primary style name associated with the specified column. * * @param column the column whose style name is to be set * @param styleName the new style name * @see UIObject#setStylePrimaryName(String) * @throws IndexOutOfBoundsException */ public void setStylePrimaryName(int column, String styleName) { UIObject.setStylePrimaryName(ensureColumn(column), styleName); } /** * Sets the width of the specified column. * * @param column the column of the cell whose width is to be set * @param width the cell's new width, in percentage or pixel units * @throws IndexOutOfBoundsException */ public void setWidth(int column, String width) { ensureColumn(column).setPropertyString("width", width); } /** * Resize the column group element. * * @param columns the number of columns * @param growOnly true to only grow, false to shrink if needed */ void resizeColumnGroup(int columns, boolean growOnly) { // The colgroup should always have at least one element. See // prepareColumnGroup() for more details. columns = Math.max(columns, 1); int num = columnGroup.getChildCount(); if (num < columns) { for (int i = num; i < columns; i++) { columnGroup.appendChild(Document.get().createColElement()); } } else if (!growOnly && num > columns) { for (int i = num; i > columns; i--) { columnGroup.removeChild(columnGroup.getLastChild()); } } } private Element ensureColumn(int col) { prepareColumn(col); prepareColumnGroup(); resizeColumnGroup(col + 1, true); return columnGroup.getChild(col).cast(); } /** * Prepare the colgroup tag for the first time, guaranteeing that it exists * and has at least one col tag in it. This method corrects a Mozilla issue * where the col tag will affect the wrong column if a col tag doesn't exist * when the element is attached to the page. */ private void prepareColumnGroup() { if (columnGroup == null) { columnGroup = DOM.createElement("colgroup"); DOM.insertChild(tableElem, columnGroup, 0); DOM.appendChild(columnGroup, DOM.createElement("col")); } } } /** * This class contains methods used to format a table's rows. */ public class RowFormatter { /** * Adds a style to the specified row. * * @param row the row to which the style will be added * @param styleName the style name to be added * @see UIObject#addStyleName(String) * @throws IndexOutOfBoundsException */ public void addStyleName(int row, String styleName) { UIObject.setStyleName(ensureElement(row), styleName, true); } /** * Gets the TR element representing the specified row. * * @param row the row whose TR element is to be retrieved * @return the row's TR element * @throws IndexOutOfBoundsException */ public com.google.gwt.user.client.Element getElement(int row) { checkRowBounds(row); return DOM.asOld(getRow(bodyElem, row)); } /** * Gets the style of the specified row. * * @param row the row to be queried * @return the style name * @see UIObject#getStyleName() * @throws IndexOutOfBoundsException */ public String getStyleName(int row) { return UIObject.getStyleName(getElement(row)); } /** * Gets the primary style of the specified row. * * @param row the row to be queried * @return the style name * @see UIObject#getStylePrimaryName() * @throws IndexOutOfBoundsException */ public String getStylePrimaryName(int row) { return UIObject.getStylePrimaryName(getElement(row)); } /** * Determines whether or not this row is visible via the display style * attribute. * * @param row the row whose visibility is to be set * @return true if the row is visible */ public boolean isVisible(int row) { Element e = getElement(row); return UIObject.isVisible(e); } /** * Removes a style from the specified row. * * @param row the row from which the style will be removed * @param styleName the style name to be removed * @see UIObject#removeStyleName(String) * @throws IndexOutOfBoundsException */ public void removeStyleName(int row, String styleName) { UIObject.setStyleName(ensureElement(row), styleName, false); } /** * Sets the style name associated with the specified row. * * @param row the row whose style name is to be set * @param styleName the new style name * @see UIObject#setStyleName(String) * @throws IndexOutOfBoundsException */ public void setStyleName(int row, String styleName) { UIObject.setStyleName(ensureElement(row), styleName); } /** * Sets the primary style name associated with the specified row. * * @param row the row whose style name is to be set * @param styleName the new style name * @see UIObject#setStylePrimaryName(String) * @throws IndexOutOfBoundsException */ public void setStylePrimaryName(int row, String styleName) { UIObject.setStylePrimaryName(ensureElement(row), styleName); } /** * Sets the vertical alignment of the specified row. * * @param row the row whose alignment is to be set * @param align the row's new vertical alignment as specified in * {@link HasVerticalAlignment} * @throws IndexOutOfBoundsException */ public void setVerticalAlign(int row, VerticalAlignmentConstant align) { ensureElement(row).getStyle().setProperty("verticalAlign", align.getVerticalAlignString()); } /** * Sets whether this row is visible. * * @param row the row whose visibility is to be set * @param visible true to show the row, false to * hide it */ public void setVisible(int row, boolean visible) { Element e = ensureElement(row); UIObject.setVisible(e, visible); } /** * Ensure the TR element representing the specified row exists for * subclasses that allow dynamic addition of elements. * * @param row the row whose TR element is to be retrieved * @return the row's TR element * @throws IndexOutOfBoundsException */ protected com.google.gwt.user.client.Element ensureElement(int row) { prepareRow(row); return DOM.asOld(getRow(bodyElem, row)); } @SuppressWarnings("deprecation") protected com.google.gwt.user.client.Element getRow(Element tbody, int row) { return getRow(DOM.asOld(tbody), row); } /** * @deprecated Call and override {@link #getRow(Element, int)} instead. */ @Deprecated protected com.google.gwt.user.client.Element getRow( com.google.gwt.user.client.Element tbody, int row) { return DOM.asOld(impl.getRows(tbody).get(row)); } /** * Convenience methods to set an attribute on a row. * * @param row cell's row * @param attrName attribute to set * @param value value to set * @throws IndexOutOfBoundsException */ protected void setAttr(int row, String attrName, String value) { Element elem = ensureElement(row); elem.setAttribute(attrName, value); } } private static final HTMLTableImpl impl = GWT.create(HTMLTableImpl.class); /** * Table's body. */ private final Element bodyElem; /** * Current cell formatter. */ private CellFormatter cellFormatter; /** * Column Formatter. */ private ColumnFormatter columnFormatter; /** * Current row formatter. */ private RowFormatter rowFormatter; /** * Table element. */ private final Element tableElem; private ElementMapperImpl widgetMap = new ElementMapperImpl(); /** * Create a new empty HTML Table. */ public HTMLTable() { tableElem = DOM.createTable(); bodyElem = DOM.createTBody(); DOM.appendChild(tableElem, bodyElem); setElement(tableElem); } public HandlerRegistration addClickHandler(ClickHandler handler) { return addDomHandler(handler, ClickEvent.getType()); } public HandlerRegistration addDoubleClickHandler(DoubleClickHandler handler) { return addDomHandler(handler, DoubleClickEvent.getType()); } public HandlerRegistration addDragEndHandler(DragEndHandler handler) { return addBitlessDomHandler(handler, DragEndEvent.getType()); } public HandlerRegistration addDragEnterHandler(DragEnterHandler handler) { return addBitlessDomHandler(handler, DragEnterEvent.getType()); } public HandlerRegistration addDragHandler(DragHandler handler) { return addBitlessDomHandler(handler, DragEvent.getType()); } public HandlerRegistration addDragLeaveHandler(DragLeaveHandler handler) { return addBitlessDomHandler(handler, DragLeaveEvent.getType()); } public HandlerRegistration addDragOverHandler(DragOverHandler handler) { return addBitlessDomHandler(handler, DragOverEvent.getType()); } public HandlerRegistration addDragStartHandler(DragStartHandler handler) { return addBitlessDomHandler(handler, DragStartEvent.getType()); } public HandlerRegistration addDropHandler(DropHandler handler) { return addBitlessDomHandler(handler, DropEvent.getType()); } /** * Adds a listener to the current table. * * @param listener listener to add * @deprecated add a click handler instead and use * {@link HTMLTable#getCellForEvent(ClickEvent)} to get the cell * information (remember to check for a null return value) */ @Deprecated public void addTableListener(TableListener listener) { ListenerWrapper.WrappedTableListener.add(this, listener); } /** * Removes all widgets from this table, but does not remove other HTML or text * contents of cells. */ @Override public void clear() { clear(false); } /** * Removes all widgets from this table, optionally clearing the inner HTML of * each cell. Note that this method does not remove any cells or rows. * * @param clearInnerHTML should the cell's inner html be cleared? */ public void clear(boolean clearInnerHTML) { for (int row = 0; row < getRowCount(); ++row) { for (int col = 0; col < getCellCount(row); ++col) { cleanCell(row, col, clearInnerHTML); } } } /** * Clears the cell at the given row and column. If it contains a Widget, it * will be removed from the table. If not, its contents will simply be * cleared. * * @param row the widget's row * @param column the widget's column * @return true if a widget was removed * @throws IndexOutOfBoundsException */ public boolean clearCell(int row, int column) { Element td = getCellFormatter().getElement(row, column); return internalClearCell(td, true); } /** * Gets the number of cells in a given row. * * @param row the row whose cells are to be counted * @return the number of cells present in the row */ public abstract int getCellCount(int row); /** * Given a click event, return the Cell that was clicked, or null if the event * did not hit this table. The cell can also be null if the click event does * not occur on a specific cell. * * @param event A click event of indeterminate origin * @return The appropriate cell, or null */ public Cell getCellForEvent(ClickEvent event) { Element td = getEventTargetCell(Event.as(event.getNativeEvent())); if (td == null) { return null; } int row = TableRowElement.as(td.getParentElement()).getSectionRowIndex(); int column = TableCellElement.as(td).getCellIndex(); return new Cell(row, column); } /** * Gets the {@link CellFormatter} associated with this table. Use casting to * get subclass-specific functionality * * @return this table's cell formatter */ public CellFormatter getCellFormatter() { return cellFormatter; } /** * Gets the amount of padding that is added around all cells. * * @return the cell padding, in pixels */ public int getCellPadding() { return tableElem.getPropertyInt("cellPadding"); } /** * Gets the amount of spacing that is added around all cells. * * @return the cell spacing, in pixels */ public int getCellSpacing() { return tableElem.getPropertyInt("cellSpacing"); } /** * Gets the column formatter. * * @return the column formatter */ public ColumnFormatter getColumnFormatter() { return columnFormatter; } /** * Gets the HTML contents of the specified cell. * * @param row the cell's row * @param column the cell's column * @return the cell's HTML contents * @throws IndexOutOfBoundsException */ public String getHTML(int row, int column) { return cellFormatter.getElement(row, column).getInnerHTML(); } /** * Gets the number of rows present in this table. * * @return the table's row count */ public abstract int getRowCount(); /** * Gets the RowFormatter associated with this table. * * @return the table's row formatter */ public RowFormatter getRowFormatter() { return rowFormatter; } /** * Gets the text within the specified cell. * * @param row the cell's row * @param column the cell's column * @return the cell's text contents * @throws IndexOutOfBoundsException */ public String getText(int row, int column) { checkCellBounds(row, column); Element e = cellFormatter.getElement(row, column); return e.getInnerText(); } /** * Gets the widget in the specified cell. * * @param row the cell's row * @param column the cell's column * @return the widget in the specified cell, or null if none is * present * @throws IndexOutOfBoundsException */ public Widget getWidget(int row, int column) { checkCellBounds(row, column); return getWidgetImpl(row, column); } /** * Determines whether the specified cell exists. * * @param row the cell's row * @param column the cell's column * @return true if the specified cell exists */ public boolean isCellPresent(int row, int column) { if ((row >= getRowCount()) || (row < 0)) { return false; } if ((column < 0) || (column >= getCellCount(row))) { return false; } else { return true; } } /** * Returns an iterator containing all the widgets in this table. * * @return the iterator */ public Iterator iterator() { return new Iterator() { final ArrayList widgetList = widgetMap.getObjectList(); int lastIndex = -1; int nextIndex = -1; { findNext(); } public boolean hasNext() { return nextIndex < widgetList.size(); } public Widget next() { if (!hasNext()) { throw new NoSuchElementException(); } Widget result = widgetList.get(nextIndex); lastIndex = nextIndex; findNext(); return result; } public void remove() { if (lastIndex < 0) { throw new IllegalStateException(); } Widget w = widgetList.get(lastIndex); assert (w.getParent() instanceof HTMLTable); w.removeFromParent(); lastIndex = -1; } private void findNext() { while (++nextIndex < widgetList.size()) { if (widgetList.get(nextIndex) != null) { return; } } } }; } /** * Remove the specified widget from the table. * * @param widget widget to remove * @return was the widget removed from the table. */ @Override public boolean remove(Widget widget) { // Validate. if (widget.getParent() != this) { return false; } // Orphan. try { orphan(widget); } finally { // Physical detach. Element elem = widget.getElement(); DOM.getParent(elem).removeChild(elem); // Logical detach. widgetMap.removeByElement(elem); } return true; } /** * Removes the specified table listener. * * @param listener listener to remove * * @deprecated Use the {@link HandlerRegistration#removeHandler} * method on the object returned by an add*Handler method instead */ @Deprecated public void removeTableListener(TableListener listener) { ListenerWrapper.WrappedTableListener.remove(this, listener); } /** * Sets the width of the table's border. This border is displayed around all * cells in the table. * * @param width the width of the border, in pixels */ public void setBorderWidth(int width) { tableElem.setPropertyString("border", "" + width); } /** * Sets the amount of padding to be added around all cells. * * @param padding the cell padding, in pixels */ public void setCellPadding(int padding) { tableElem.setPropertyInt("cellPadding", padding); } /** * Sets the amount of spacing to be added around all cells. * * @param spacing the cell spacing, in pixels */ public void setCellSpacing(int spacing) { tableElem.setPropertyInt("cellSpacing", spacing); } /** * Sets the HTML contents of the specified cell. * * @param row the cell's row * @param column the cell's column * @param html the cell's HTML contents * @throws IndexOutOfBoundsException */ public void setHTML(int row, int column, @IsSafeHtml String html) { prepareCell(row, column); Element td = cleanCell(row, column, html == null); if (html != null) { td.setInnerHTML(html); } } /** * Sets the HTML contents of the specified cell. * * @param row the cell's row * @param column the cell's column * @param html the cell's safe html contents * @throws IndexOutOfBoundsException */ public void setHTML(int row, int column, SafeHtml html) { setHTML(row, column, html.asString()); } /** * Sets the text within the specified cell. * * @param row the cell's row * @param column cell's column * @param text the cell's text contents * @throws IndexOutOfBoundsException */ public void setText(int row, int column, String text) { prepareCell(row, column); Element td; td = cleanCell(row, column, text == null); if (text != null) { td.setInnerText(text); } } /** * Sets the widget within the specified cell. *

* Inherited implementations may either throw IndexOutOfBounds exception if * the cell does not exist, or allocate a new cell to store the content. *

*

* FlexTable will automatically allocate the cell at the correct location and * then set the widget. Grid will set the widget if and only if the cell is * within the Grid's bounding box. *

* * @param widget The widget to be added, or null to clear the cell * @param row the cell's row * @param column the cell's column * @throws IndexOutOfBoundsException */ public void setWidget(int row, int column, Widget widget) { prepareCell(row, column); // Removes any existing widget. Element td = cleanCell(row, column, true); if (widget != null) { widget.removeFromParent(); // Logical attach. widgetMap.put(widget); // Physical attach. DOM.appendChild(td, widget.getElement()); adopt(widget); } } /** * Overloaded version for IsWidget. * * @see #setWidget(int,int,Widget) */ public void setWidget(int row, int column, IsWidget widget) { this.setWidget(row, column, asWidgetOrNull(widget)); } /** * Bounds checks that the cell exists at the specified location. * * @param row cell's row * @param column cell's column * @throws IndexOutOfBoundsException */ protected void checkCellBounds(int row, int column) { checkRowBounds(row); if (column < 0) { throw new IndexOutOfBoundsException("Column " + column + " must be non-negative: " + column); } int cellSize = getCellCount(row); if (cellSize <= column) { throw new IndexOutOfBoundsException("Column index: " + column + ", Column size: " + getCellCount(row)); } } /** * Checks that the row is within the correct bounds. * * @param row row index to check * @throws IndexOutOfBoundsException */ protected void checkRowBounds(int row) { int rowSize = getRowCount(); if ((row >= rowSize) || (row < 0)) { throw new IndexOutOfBoundsException("Row index: " + row + ", Row size: " + rowSize); } } /** * Creates a new cell. Override this method if the cell should have initial * contents. * * @return the newly created TD */ protected com.google.gwt.user.client.Element createCell() { return DOM.createTD(); } /** * Gets the table's TBODY element. * * @return the TBODY element */ protected com.google.gwt.user.client.Element getBodyElement() { return DOM.asOld(bodyElem); } /** * Directly ask the underlying DOM what the cell count on the given row is. * * @param tableBody the element * @param row the row * @return number of columns in the row */ @SuppressWarnings("deprecation") protected int getDOMCellCount(Element tableBody, int row) { return getDOMCellCount(DOM.asOld(tableBody), row); } /** * @deprecated Call and override {@link #getDOMCellCount(Element, int)} instead. */ @Deprecated protected int getDOMCellCount(com.google.gwt.user.client.Element tableBody, int row) { Element rowElement = impl.getRows(tableBody).get(row); return impl.getCells(rowElement).length(); } /** * Directly ask the underlying DOM what the cell count on the given row is. * * @param row the row * @return number of columns in the row */ protected int getDOMCellCount(int row) { return getDOMCellCount(bodyElem, row); } /** * Directly ask the underlying DOM what the row count is. * * @return Returns the number of rows in the table */ protected int getDOMRowCount() { return getDOMRowCount(bodyElem); } @SuppressWarnings("deprecation") protected int getDOMRowCount(Element tbody) { return getDOMRowCount(DOM.asOld(tbody)); } /** * @deprecated Call and override {@link #getDOMRowCount(Element)} instead. */ @Deprecated protected int getDOMRowCount(com.google.gwt.user.client.Element tbody) { return impl.getRows(tbody).length(); } /** * Determines the TD associated with the specified event. * * @param event the event to be queried * @return the TD associated with the event, or null if none is * found. */ protected com.google.gwt.user.client.Element getEventTargetCell(Event event) { Element td = DOM.eventGetTarget(event); for (; td != null; td = DOM.getParent(td)) { // If it's a TD, it might be the one we're looking for. if (td.getPropertyString("tagName").equalsIgnoreCase("td")) { // Make sure it's directly a part of this table before returning // it. Element tr = DOM.getParent(td); Element body = DOM.getParent(tr); if (body == bodyElem) { return DOM.asOld(td); } } // If we run into this table's body, we're out of options. if (td == bodyElem) { return null; } } return null; } /** * Inserts a new cell into the specified row. * * @param row the row into which the new cell will be inserted * @param column the column before which the cell will be inserted * @throws IndexOutOfBoundsException */ protected void insertCell(int row, int column) { Element tr = rowFormatter.getRow(bodyElem, row); Element td = createCell(); DOM.insertChild(tr, td, column); } /** * Inserts a number of cells before the specified cell. * * @param row the row into which the new cells will be inserted * @param column the column before which the new cells will be inserted * @param count number of cells to be inserted * @throws IndexOutOfBoundsException */ protected void insertCells(int row, int column, int count) { Element tr = rowFormatter.getRow(bodyElem, row); for (int i = column; i < column + count; i++) { Element td = createCell(); DOM.insertChild(tr, td, i); } } /** * Inserts a new row into the table. * * @param beforeRow the index before which the new row will be inserted * @return the index of the newly-created row * @throws IndexOutOfBoundsException */ protected int insertRow(int beforeRow) { // Specifically allow the row count as an insert position. if (beforeRow != getRowCount()) { checkRowBounds(beforeRow); } Element tr = DOM.createTR(); DOM.insertChild(bodyElem, tr, beforeRow); return beforeRow; } /** * Does actual clearing, used by clearCell and cleanCell. All HTMLTable * methods should use internalClearCell rather than clearCell, as clearCell * may be overridden in subclasses to format an empty cell. * * @param td element to clear * @param clearInnerHTML should the cell's inner html be cleared? * @return returns whether a widget was cleared */ @SuppressWarnings("deprecation") protected boolean internalClearCell(Element td, boolean clearInnerHTML) { return internalClearCell(DOM.asOld(td), clearInnerHTML); } /** * @deprecated Call and override {@link internalClearCell(Element, boolean)} instead. */ @Deprecated protected boolean internalClearCell(com.google.gwt.user.client.Element td, boolean clearInnerHTML) { Element maybeChild = DOM.getFirstChild(td); Widget widget = null; if (maybeChild != null) { widget = widgetMap.get(maybeChild); } if (widget != null) { // If there is a widget, remove it. remove(widget); return true; } else { // Otherwise, simply clear whatever text and/or HTML may be there. if (clearInnerHTML) { td.setInnerHTML(""); } return false; } } /** * Affected Elements: *
    *
  • -(row)#-(cell)# = the cell at the given row and cell index.
  • *
* * @see UIObject#onEnsureDebugId(String) */ @Override protected void onEnsureDebugId(String baseID) { super.onEnsureDebugId(baseID); int rowCount = getRowCount(); for (int row = 0; row < rowCount; row++) { int cellCount = getCellCount(row); for (int cell = 0; cell < cellCount; cell++) { Element cellElem = cellFormatter.getRawElement(row, cell); ensureDebugId(cellElem, baseID, row + "-" + cell); } } } /** * Subclasses must implement this method. It allows them to decide what to do * just before a cell is accessed. If the cell already exists, this method * must do nothing. Otherwise, a subclass must either ensure that the cell * exists or throw an {@link IndexOutOfBoundsException}. * * @param row the cell's row * @param column the cell's column */ protected abstract void prepareCell(int row, int column); /** * Subclasses can implement this method. It allows them to decide what to do * just before a column is accessed. For classes, such as * FlexTable, that do not have a concept of a global column * length can ignore this method. * * @param column the cell's column * @throws IndexOutOfBoundsException */ protected void prepareColumn(int column) { // Ensure that the indices are not negative. if (column < 0) { throw new IndexOutOfBoundsException( "Cannot access a column with a negative index: " + column); } } /** * Subclasses must implement this method. If the row already exists, this * method must do nothing. Otherwise, a subclass must either ensure that the * row exists or throw an {@link IndexOutOfBoundsException}. * * @param row the cell's row */ protected abstract void prepareRow(int row); /** * 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 */ protected void removeCell(int row, int column) { checkCellBounds(row, column); Element td = cleanCell(row, column, false); Element tr = rowFormatter.getRow(bodyElem, row); tr.removeChild(td); } /** * Removes the specified row from the table. * * @param row the index of the row to be removed * @throws IndexOutOfBoundsException */ protected void removeRow(int row) { int columnCount = getCellCount(row); for (int column = 0; column < columnCount; ++column) { cleanCell(row, column, false); } bodyElem.removeChild(rowFormatter.getRow(bodyElem, row)); } /** * Sets the table's CellFormatter. * * @param cellFormatter the table's cell formatter */ protected void setCellFormatter(CellFormatter cellFormatter) { this.cellFormatter = cellFormatter; } protected void setColumnFormatter(ColumnFormatter formatter) { // Copy the columnGroup element to the new formatter so we don't create a // second colgroup element. if (columnFormatter != null) { formatter.columnGroup = columnFormatter.columnGroup; } columnFormatter = formatter; columnFormatter.prepareColumnGroup(); } /** * Sets the table's RowFormatter. * * @param rowFormatter the table's row formatter */ protected void setRowFormatter(RowFormatter rowFormatter) { this.rowFormatter = rowFormatter; } void addCells(Element tbody, int row, int num) { com.google.gwt.dom.client.Element rowElem = impl.getRows(tbody).get(row); for (int i = 0; i < num; i++) { TableCellElement tdElement = Document.get().createTDElement(); rowElem.appendChild(tdElement); } } /** * Removes any widgets, text, and HTML within the cell. This method assumes * that the requested cell already exists. * * @param row the cell's row * @param column the cell's column * @param clearInnerHTML should the cell's inner html be cleared? * @return element that has been cleaned */ private Element cleanCell(int row, int column, boolean clearInnerHTML) { // Clear whatever is in the cell. Element td = getCellFormatter().getRawElement(row, column); internalClearCell(td, clearInnerHTML); return td; } /** * Gets the Widget associated with the given cell. * * @param row the cell's row * @param column the cell's column * @return the widget */ private Widget getWidgetImpl(int row, int column) { Element e = cellFormatter.getRawElement(row, column); Element child = DOM.getFirstChild(e); if (child == null) { return null; } else { return widgetMap.get(child); } } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy