[jboss-svn-commits] JBL Code SVN: r6787 - in labs/jbossrules/trunk/drools-jbrms/src/main/java: . com com/google com/google/gwt com/google/gwt/user com/google/gwt/user/client com/google/gwt/user/client/ui org/drools/brms/client/decisiontable org/drools/brms/public
jboss-svn-commits at lists.jboss.org
jboss-svn-commits at lists.jboss.org
Fri Oct 13 05:35:27 EDT 2006
Author: michael.neale at jboss.com
Date: 2006-10-13 05:35:21 -0400 (Fri, 13 Oct 2006)
New Revision: 6787
Added:
labs/jbossrules/trunk/drools-jbrms/src/main/java/com/
labs/jbossrules/trunk/drools-jbrms/src/main/java/com/google/
labs/jbossrules/trunk/drools-jbrms/src/main/java/com/google/gwt/
labs/jbossrules/trunk/drools-jbrms/src/main/java/com/google/gwt/user/
labs/jbossrules/trunk/drools-jbrms/src/main/java/com/google/gwt/user/client/
labs/jbossrules/trunk/drools-jbrms/src/main/java/com/google/gwt/user/client/ui/
labs/jbossrules/trunk/drools-jbrms/src/main/java/com/google/gwt/user/client/ui/FastStringMap.java
labs/jbossrules/trunk/drools-jbrms/src/main/java/com/google/gwt/user/client/ui/FlexTable.java
labs/jbossrules/trunk/drools-jbrms/src/main/java/com/google/gwt/user/client/ui/Grid.java
labs/jbossrules/trunk/drools-jbrms/src/main/java/com/google/gwt/user/client/ui/HTMLTable.java
labs/jbossrules/trunk/drools-jbrms/src/main/java/org/drools/brms/client/decisiontable/EditActions.java
Modified:
labs/jbossrules/trunk/drools-jbrms/src/main/java/org/drools/brms/client/decisiontable/EditableDTGrid.java
labs/jbossrules/trunk/drools-jbrms/src/main/java/org/drools/brms/public/JBRMS.css
Log:
more fixes and a patch from google for faster flextable
Added: labs/jbossrules/trunk/drools-jbrms/src/main/java/com/google/gwt/user/client/ui/FastStringMap.java
===================================================================
--- labs/jbossrules/trunk/drools-jbrms/src/main/java/com/google/gwt/user/client/ui/FastStringMap.java 2006-10-13 08:10:58 UTC (rev 6786)
+++ labs/jbossrules/trunk/drools-jbrms/src/main/java/com/google/gwt/user/client/ui/FastStringMap.java 2006-10-13 09:35:21 UTC (rev 6787)
@@ -0,0 +1,274 @@
+/*
+ * 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.user.client.ui;
+
+import com.google.gwt.core.client.GWT;
+import com.google.gwt.core.client.JavaScriptObject;
+
+import java.util.AbstractMap;
+import java.util.AbstractSet;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * Special-case Map implementation which imposes limits on the types of keys
+ * that can be used in return for much faster speed. In specific, only strings
+ * that could be added to a JavaScript object as keys are valid.
+ */
+
+class FastStringMap extends AbstractMap {
+ private static class ImplMapEntry implements Map.Entry {
+
+ ImplMapEntry(String key, Object value) {
+ this.key = key;
+ this.value = value;
+ }
+
+ public boolean equals(Object a) {
+ if (a instanceof Map.Entry) {
+ Map.Entry s = (Map.Entry) a;
+ if (equalsWithNullCheck(key, s.getKey())
+ && equalsWithNullCheck(value, s.getValue())) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ public Object getKey() {
+ return key;
+ }
+
+ public Object getValue() {
+ return value;
+ }
+
+ public int hashCode() {
+ int keyHash = 0;
+ int valueHash = 0;
+ if (key != null) {
+ keyHash = key.hashCode();
+ }
+ if (value != null) {
+ valueHash = value.hashCode();
+ }
+ return keyHash ^ valueHash;
+ }
+
+ public Object setValue(Object object) {
+ Object old = value;
+ value = object;
+ return old;
+ }
+
+ private boolean equalsWithNullCheck(Object a, Object b) {
+ if (a == b) {
+ return true;
+ } else if (a == null) {
+ return false;
+ } else {
+ return a.equals(b);
+ }
+ }
+
+ private Object key;
+ private Object value;
+ }
+
+ public FastStringMap() {
+ init();
+ }
+
+ public void clear() {
+ init();
+ }
+
+ public boolean containsKey(Object key) {
+ return containsKey(keyMustBeString(key), map);
+ }
+
+ public boolean containsValue(Object arg0) {
+ return values().contains(arg0);
+ }
+
+ public Set entrySet() {
+ return new AbstractSet() {
+
+ public boolean contains(Object key) {
+ Map.Entry s = (Map.Entry) key;
+ Object value = get(s.getKey());
+ if (value == null) {
+ return value == s.getValue();
+ } else {
+ return value.equals(s.getValue());
+ }
+ }
+
+ public Iterator iterator() {
+
+ Iterator custom = new Iterator() {
+ public boolean hasNext() {
+ return keys.hasNext();
+ }
+
+ public Object next() {
+ String key = (String) keys.next();
+ return new ImplMapEntry(key, get(key));
+ }
+
+ public void remove() {
+ keys.remove();
+ }
+
+ Iterator keys = keySet().iterator();
+ };
+ return custom;
+ }
+
+ public int size() {
+ return FastStringMap.this.size();
+ }
+
+ };
+ }
+
+ public Object get(Object key) {
+ return get(keyMustBeString(key));
+ }
+
+ public native Object get(String key) /*-{
+ var value = this. at com.google.gwt.user.client.ui.FastStringMap::map[key];
+ if(value == null){
+ return null;
+ } else{
+ return value;
+ }
+ }-*/;
+
+ public boolean isEmpty() {
+ return size() == 0;
+ }
+
+ public Set keySet() {
+ return new AbstractSet() {
+ public boolean contains(Object key) {
+ return containsKey(key);
+ }
+
+ public Iterator iterator() {
+ List l = new ArrayList();
+ addAllKeysFromJavascriptObject(l, map);
+ return l.iterator();
+ }
+
+ public int size() {
+ return FastStringMap.this.size();
+ }
+ };
+ }
+
+ public Object put(Object key, Object widget) {
+ return put(keyMustBeString(key), widget);
+ }
+
+ public native Object put(String key, Object widget) /*-{
+ var previous = this. at com.google.gwt.user.client.ui.FastStringMap::map[key];
+ this. at com.google.gwt.user.client.ui.FastStringMap::map[key] = widget;
+ if(previous == null){
+ return null;
+ } else{
+ return previous;
+ }
+ }-*/;
+
+ public void putAll(Map arg0) {
+ Iterator iter = arg0.entrySet().iterator();
+ while (iter.hasNext()) {
+ Map.Entry entry = (Entry) iter.next();
+ put(entry.getKey(), entry.getValue());
+ }
+ }
+
+ public Object remove(Object key) {
+ return remove(keyMustBeString(key));
+ }
+
+ public native int size() /*-{
+ var value = this. at com.google.gwt.user.client.ui.FastStringMap::map;
+ var count = 0;
+ for(var key in value){
+ ++count;
+ }
+ return count;
+ }-*/;
+
+ public Collection values() {
+ List values = new ArrayList();
+ addAllValuesFromJavascriptObject(values, map);
+ return values;
+
+ }
+
+ private native void addAllKeysFromJavascriptObject(Collection s,
+ JavaScriptObject javaScriptObject) /*-{
+ for(var key in javaScriptObject) {
+ s. at java.util.Collection::add(Ljava/lang/Object;)(key);
+ }
+ }-*/;
+
+ private native void addAllValuesFromJavascriptObject(Collection s,
+ JavaScriptObject javaScriptObject) /*-{
+ for(var key in javaScriptObject) {
+ var value = javaScriptObject[key];
+ s. at java.util.Collection::add(Ljava/lang/Object;)(value);
+ }
+ }-*/;
+
+ private native boolean containsKey(String key, JavaScriptObject obj)/*-{
+ return obj[key] !== undefined;
+ }-*/;
+
+ private native void init() /*-{
+ this. at com.google.gwt.user.client.ui.FastStringMap::map = [];
+ }-*/;
+
+ private String keyMustBeString(Object key) {
+ if (key instanceof String) {
+ return (String) key;
+ } else {
+ throw new IllegalArgumentException(GWT.getTypeName(this)
+ + " can only have Strings as keys, not" + key);
+ }
+ }
+
+ private native Object remove(String key) /*-{
+ var previous = this. at com.google.gwt.user.client.ui.FastStringMap::map[key];
+ delete this. at com.google.gwt.user.client.ui.FastStringMap::map[key];
+ if(previous == null){
+ return null;
+ } else{
+ return previous;
+ }
+ }-*/;
+
+ JavaScriptObject map;
+
+}
Added: labs/jbossrules/trunk/drools-jbrms/src/main/java/com/google/gwt/user/client/ui/FlexTable.java
===================================================================
--- labs/jbossrules/trunk/drools-jbrms/src/main/java/com/google/gwt/user/client/ui/FlexTable.java 2006-10-13 08:10:58 UTC (rev 6786)
+++ labs/jbossrules/trunk/drools-jbrms/src/main/java/com/google/gwt/user/client/ui/FlexTable.java 2006-10-13 09:35:21 UTC (rev 6787)
@@ -0,0 +1,226 @@
+/*
+ * 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.user.client.ui;
+
+import com.google.gwt.user.client.DOM;
+
+/**
+ * A flexible table that creates cells on demand. It can be jagged (that is,
+ * each row can contain a different number of cells) and individual cells can be
+ * set to span multiple rows or columns.
+ * <p>
+ * <img class='gallery' src='Table.png'/>
+ * </p>
+ * <p>
+ * <h3>Example</h3>
+ * {@example com.google.gwt.examples.FlexTableExample}
+ * </p>
+ */
+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.getIntAttribute(this.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.getIntAttribute(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.setIntAttribute(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.setIntAttribute(ensureElement(row, column), "rowSpan", rowSpan);
+ }
+ }
+
+ public FlexTable() {
+ super();
+ setCellFormatter(new FlexCellFormatter());
+ setRowFormatter(new RowFormatter());
+ }
+
+ /**
+ * 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
+ */
+ public int getCellCount(int row) {
+ checkRowBounds(row);
+ return super.getDOMCellCount(getBodyElement(), row);
+ }
+
+ /**
+ * 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
+ */
+ public int getRowCount() {
+ return getDOMRowCount();
+ }
+
+ /**
+ * Inserts a cell into the FlexTable.
+ *
+ * @param beforeRow the cell's row
+ * @param beforeColumn the cell's column
+ */
+ public void insertCell(int beforeRow, int beforeColumn) {
+ super.insertCell(beforeRow, beforeColumn);
+ }
+
+ /**
+ * Inserts a row into the FlexTable.
+ *
+ * @param beforeRow the row to insert
+ */
+ public int insertRow(int beforeRow) {
+ return super.insertRow(beforeRow);
+ }
+
+ /**
+ * @see com.google.gwt.user.client.ui.HTMLTable#removeCell(int, int)
+ */
+ public void removeCell(int row, int col) {
+ super.removeCell(row, col);
+ }
+
+ /**
+ * 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);
+ }
+ }
+
+ public void removeRow(int row) {
+ super.removeRow(row);
+ }
+
+ /**
+ * Ensure that the cell exists.
+ *
+ * @param row the row to prepare.
+ * @param column the column to prepare.
+ * @throws IndexOutOfBoundsException if the row is negative
+ */
+ 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(getBodyElement(), row, required);
+ }
+ }
+
+ /**
+ * Ensure that the row exists.
+ *
+ * @param row The row to prepare.
+ * @throws IndexOutOfBoundsException if the row is negative
+ */
+ 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);
+ }
+ }
+}
Added: labs/jbossrules/trunk/drools-jbrms/src/main/java/com/google/gwt/user/client/ui/Grid.java
===================================================================
--- labs/jbossrules/trunk/drools-jbrms/src/main/java/com/google/gwt/user/client/ui/Grid.java 2006-10-13 08:10:58 UTC (rev 6786)
+++ labs/jbossrules/trunk/drools-jbrms/src/main/java/com/google/gwt/user/client/ui/Grid.java 2006-10-13 09:35:21 UTC (rev 6787)
@@ -0,0 +1,227 @@
+/*
+ * 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.user.client.ui;
+
+import com.google.gwt.user.client.DOM;
+import com.google.gwt.user.client.Element;
+
+/**
+ * A rectangular grid that can contain text, html, or a child
+ * {@link com.google.gwt.user.client.ui.Widget} within its cells. It must be
+ * resized explicitly to the desired number of rows and columns.
+ * <p>
+ * <img class='gallery' src='Table.png'/>
+ * </p>
+ * <p>
+ * <h3>Example</h3>
+ * {@example com.google.gwt.examples.GridExample}
+ * </p>
+ */
+public class Grid extends HTMLTable {
+
+ /**
+ * Number of columns in the current grid.
+ */
+ protected int numColumns;
+
+ /**
+ * Number of rows in the current grid.
+ */
+ protected int numRows;
+
+ /**
+ * Constructor for <code>Grid</code>.
+ */
+ public Grid() {
+ super();
+ setCellFormatter(new CellFormatter());
+ setRowFormatter(new RowFormatter());
+ }
+
+ /**
+ * Constructs a grid with the requested size.
+ *
+ * @param rows the number of rows
+ * @param columns the number of columns
+ * @throws IndexOutOfBoundsException
+ */
+ public Grid(int rows, int columns) {
+ this();
+ resize(rows, columns);
+ }
+
+ /**
+ * Replaces the contents of the specified cell with a single space.
+ *
+ * @param row the cell's row
+ * @param column the cell's column
+ * @throws IndexOutOfBoundsException
+ */
+ public boolean clearCell(int row, int column) {
+ Element td = getCellFormatter().getElement(row, column);
+ boolean b = super.internalClearCell(td);
+ DOM.setInnerHTML(td, " ");
+ return b;
+ }
+
+ /**
+ * Return number of columns. For grid, row argument is ignored as all grids
+ * are rectangular.
+ */
+ public int getCellCount(int row) {
+ return numColumns;
+ }
+
+ /**
+ * Gets the number of columns in this grid.
+ *
+ * @return the number of columns
+ */
+ public int getColumnCount() {
+ return numColumns;
+ }
+
+ /**
+ * Return number of rows.
+ */
+ public int getRowCount() {
+ return numRows;
+ }
+
+ /**
+ * Resizes the grid.
+ *
+ * @param rows the number of rows
+ * @param columns the number of columns
+ * @throws IndexOutOfBoundsException
+ */
+ public void resize(int rows, int columns) {
+ resizeColumns(columns);
+ resizeRows(rows);
+ }
+
+ /**
+ * Resizes the grid to the specified number of columns.
+ *
+ * @param columns the number of columns
+ * @throws IndexOutOfBoundsException
+ */
+ public void resizeColumns(int columns) {
+ if (numColumns == columns)
+ return;
+
+ if (columns <= 0) {
+ throw new IndexOutOfBoundsException("Cannot set number of columns to "
+ + columns);
+ }
+
+ if (numColumns > columns) {
+ // Fewer columns. Remove extraneous cells.
+ for (int i = 0; i < numRows; i++) {
+ for (int j = numColumns - 1; j >= columns; j--)
+ removeCell(i, j);
+ }
+ } else {
+ // More columns. add cells where necessary.
+ for (int i = 0; i < numRows; i++) {
+ for (int j = numColumns; j < columns; j++)
+ insertCell(i, j);
+ }
+ }
+ numColumns = columns;
+ }
+
+ /**
+ * Resizes the grid to the specified number of rows.
+ *
+ * @param rows the number of rows
+ * @throws IndexOutOfBoundsException
+ */
+ public void resizeRows(int rows) {
+ if (numRows == rows)
+ return;
+
+ if (rows <= 0) {
+ throw new IndexOutOfBoundsException("Cannot set number of rows to "
+ + rows);
+ }
+ if (numRows < rows) {
+ addRows(getElement(), rows - numRows, numColumns);
+ numRows = rows;
+ } else {
+ while (numRows > rows) {
+ // Fewer rows. Remove extraneous ones.
+ removeRow(--numRows);
+ }
+ }
+ }
+
+ /**
+ * Creates a new, empty cell.
+ */
+ protected Element createCell() {
+ Element td = super.createCell();
+
+ // Add a non-breaking space to the TD. This ensures that the cell is
+ // displayed.
+ DOM.setInnerHTML(td, " ");
+ return td;
+ }
+
+ /**
+ * Checks that a cell is a valid cell in the table.
+ *
+ * @param row the cell's row
+ * @param column the cell's column
+ * @throws IndexOutOfBoundsException
+ */
+ protected void prepareCell(int row, int column) {
+ // Ensure that the indices are not negative.
+ prepareRow(row);
+ if (column < 0) {
+ throw new IndexOutOfBoundsException(
+ "Cannot access a column with a negative index: " + column);
+ }
+
+ if (column >= numColumns) {
+ throw new IndexOutOfBoundsException("Column index: " + column
+ + ", Column size: " + numColumns);
+ }
+ }
+
+ /**
+ * Checks that the row index is valid.
+ *
+ * @param row The row index to be checked
+ * @throws IndexOutOfBoundsException if the row is negative
+ */
+ protected void prepareRow(int row) {
+ // Ensure that the indices are not negative.
+ if (row < 0) {
+ throw new IndexOutOfBoundsException(
+ "Cannot access a row with a negative index: " + row);
+ }
+
+ /**
+ * Grid does not lazily create cells, so simply ensure that the requested
+ * row and column are valid
+ */
+ if (row >= numRows) {
+ throw new IndexOutOfBoundsException("Row index: " + row + ", Row size: "
+ + numRows);
+ }
+ }
+}
Added: labs/jbossrules/trunk/drools-jbrms/src/main/java/com/google/gwt/user/client/ui/HTMLTable.java
===================================================================
--- labs/jbossrules/trunk/drools-jbrms/src/main/java/com/google/gwt/user/client/ui/HTMLTable.java 2006-10-13 08:10:58 UTC (rev 6786)
+++ labs/jbossrules/trunk/drools-jbrms/src/main/java/com/google/gwt/user/client/ui/HTMLTable.java 2006-10-13 09:35:21 UTC (rev 6787)
@@ -0,0 +1,1148 @@
+/*
+ * 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.user.client.ui;
+
+import com.google.gwt.user.client.DOM;
+import com.google.gwt.user.client.Element;
+import com.google.gwt.user.client.Event;
+import com.google.gwt.user.client.ui.HasHorizontalAlignment.HorizontalAlignmentConstant;
+import com.google.gwt.user.client.ui.HasVerticalAlignment.VerticalAlignmentConstant;
+
+import java.util.Iterator;
+
+/**
+ * HTMLTable contains the common table algorithms for
+ * {@link com.google.gwt.user.client.ui.Grid} and
+ * {@link com.google.gwt.user.client.ui.FlexTable}.
+ * <p>
+ * <img class='gallery' src='Table.png'/>
+ * </p>
+ */
+public abstract class HTMLTable extends Panel implements SourcesTableEvents {
+ /**
+ * 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);
+ UIObject.setStyleName(getElement(row, column), styleName, true/** add */
+ );
+ }
+
+ /**
+ * 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 Element getElement(int row, int column) {
+ checkCellBounds(row, column);
+ return DOM.getChild(rowFormatter.getRow(bodyElem ,row), column);
+ }
+
+ /**
+ * Gets a style from a specified row.
+ *
+ * @param row the row of the cell which the style while be added to
+ * @param column the column of the cell which the style will be added to
+ * @see UIObject#getStyleName()
+ * @return returns the style name
+ * @throws IndexOutOfBoundsException
+ */
+ public String getStyleName(int row, int column) {
+ return DOM.getAttribute(getElement(row, column), "className");
+ }
+
+ /**
+ * 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 <code>true</code> 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);
+ UIObject.setStyleName(getElement(row, column), 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 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 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(tableElem, row, column);
+ DOM.setAttribute(elem, "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 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(tableElem, row, column);
+ DOM.setAttribute(elem, "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);
+ setAttr(row, column, "className", 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 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);
+ DOM.setStyleAttribute(getCellElement(tableElem, row, column),
+ "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 <code>true</code> to show the cell, <code>false</code>
+ * 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 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);
+ DOM.setAttribute(getCellElement(tableElem, row, column), "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 cell whose word-wrap is to be set
+ * @param wrap <code>false </code> 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";
+ DOM.setStyleAttribute(getElement(row, column), "whiteSpace", wrapValue);
+ }
+
+ /**
+ * Native method to get a cell's element.
+ *
+ * @param table the table element
+ * @param row the row of the cell
+ * @param col the column of the cell
+ * @return the element
+ */
+ private native Element getCellElement(Element table, int row, int col) /*-{
+ var out = table.rows[row].cells[col];
+ return (out==null?null:out);
+ }-*/;
+
+ /**
+ * Gets the TD element representing the specified cell unsafely (meaning
+ * that it doesn't ensure that the 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 column's TD element
+ */
+ private Element getRawElement(int row, int column) {
+ return getCellElement(tableElem, row, column);
+ }
+
+ /**
+ * 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 Element ensureElement(int row, int column) {
+ prepareCell(row, column);
+ return DOM.getChild(rowFormatter.ensureElement(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 DOM.getAttribute(elem, 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);
+ DOM.setAttribute(elem, attrName, value);
+ }
+
+ }
+
+ /**
+ * 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 while 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 Element getElement(int row) {
+ checkRowBounds(row);
+ return getRow(bodyElem,row);
+ }
+
+ /**
+ * Gets a style from a specified row.
+ *
+ * @param row the row to which the style while be added
+ * @see UIObject#getStyleName()
+ * @throws IndexOutOfBoundsException
+ * @return the style name
+ */
+ public String getStyleName(int row) {
+ return DOM.getAttribute(getElement(row), "className");
+ }
+
+ /**
+ * Determines whether or not this row is visible via the display style
+ * attribute.
+ *
+ * @param row the row whose visibility is to be set
+ * @return <code>true</code> 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 to which the style while 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(getElement(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) {
+ Element elem = ensureElement(row);
+ DOM.setAttribute(elem, "className", 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) {
+ DOM.setStyleAttribute(ensureElement(row), "verticalAlign", align
+ .getVerticalAlignString());
+ }
+
+ /**
+ * Sets whether this row is visible.
+ *
+ * @param row the row whose visibility is to be set
+ * @param visible <code>true</code> to show the row, <code>false</code>
+ * 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 Element ensureElement(int row) {
+ prepareRow(row);
+ return getRow(bodyElem, row);
+ }
+
+ protected native Element getRow(Element elem, int row)/*-{
+ return elem.rows[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);
+ DOM.setAttribute(elem, attrName, value);
+ }
+ }
+
+ /** Attribute name to store hash. */
+ private static final String HASH_ATTR = "__hash";
+
+ protected native static 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");
+ rowElem.appendChild(cell);
+ }
+ }-*/;
+
+ /**
+ * Native method to add rows to a table with a given number of columns.
+ *
+ * @param table the table element
+ * @param rows the number of rows
+ * @param columns the number of columns per row
+ */
+ protected native static void addRows(Element table, int rows, int columns) /*-{
+ for(var rowNum=0; rowNum<rows;rowNum++) {
+ var row =table.insertRow(rowNum);
+ for(var cellNum = 0; cellNum < columns; cellNum++) {
+ var cell =$doc.createElement("td");
+ row.appendChild(cell);
+ }
+ }
+ }-*/;
+
+ /**
+ * Create a new empty HTML Table.
+ */
+ public HTMLTable() {
+ tableElem = DOM.createTable();
+ bodyElem = DOM.createTBody();
+ DOM.appendChild(tableElem, bodyElem);
+ setElement(tableElem);
+ sinkEvents(Event.ONCLICK);
+ }
+
+ /**
+ * Adds a listener to the current table.
+ *
+ * @param listener listener to add
+ */
+ public void addTableListener(TableListener listener) {
+ if (tableListeners == null) {
+ tableListeners = new TableListenerCollection();
+ }
+ tableListeners.add(listener);
+ }
+
+ /**
+ * Removes all widgets from this table, but does not remove other HTML or text
+ * contents of cells.
+ */
+ public void clear() {
+ for (int row = 0; row < getRowCount(); ++row) {
+ for (int col = 0; col < getCellCount(row); ++col) {
+ Widget child = getWidget(row, col);
+ if (child != null) {
+ removeWidget(child);
+ }
+ }
+ }
+ //assert (widgetMap.size() == 0);
+ }
+
+ /**
+ * Clears 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 column
+ * @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);
+ }
+
+ /**
+ * 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);
+
+ /**
+ * 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 DOM.getIntAttribute(tableElem, "cellPadding");
+ }
+
+ /**
+ * Gets the amount of spacing that is added around all cells.
+ *
+ * @return the cell spacing, in pixels
+ */
+ public int getCellSpacing() {
+ return DOM.getIntAttribute(tableElem, "cellSpacing");
+ }
+
+ /**
+ * 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 DOM.getInnerHTML(cellFormatter.getElement(row, column));
+ }
+
+ /**
+ * 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 DOM.getInnerText(e);
+ }
+
+ /**
+ * 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 <code>null</code> if none is
+ * present
+ * @throws IndexOutOfBoundsException
+ */
+ public Widget getWidget(int row, int column) {
+ checkCellBounds(row, column);
+ Object key = computeKey(row, column);
+ return (Widget) widgetMap.get(key);
+ }
+
+ /**
+ * Determines whether the specified cell exists.
+ *
+ * @param row the cell's row
+ * @param column the cell's column
+ * @return <code>true</code> 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 widgetMap.values().iterator();
+ }
+
+ /**
+ * Method to process events generated from the browser.
+ *
+ * @param event the generated event
+ */
+ public void onBrowserEvent(Event event) {
+ switch (DOM.eventGetType(event)) {
+ case Event.ONCLICK: {
+ if (tableListeners != null) {
+ // Find out which cell was actually clicked.
+ Element td = getEventTargetCell(event);
+ if (td == null) {
+ return;
+ }
+ Element tr = DOM.getParent(td);
+ Element body = DOM.getParent(tr);
+ int row = DOM.getChildIndex(body, tr);
+ int column = DOM.getChildIndex(tr, td);
+ // Fire the event.
+ tableListeners.fireCellClicked(this, row, column);
+ }
+ break;
+ }
+ default: {
+ // Do nothing
+ }
+ }
+ }
+
+ /**
+ * Remove the specified widget from the table.
+ *
+ * @param widget widget to remove
+ * @return was the widget removed from the table.
+ */
+ public boolean remove(Widget widget) {
+ // Make sure the Widget is actually contained in this table.
+ if (widget.getParent() != this) {
+ return false;
+ }
+ // Get the row and column of the cell containing this widget.
+ removeWidget(widget);
+ return true;
+ }
+
+ /**
+ * Removes the specified table listener.
+ *
+ * @param listener listener to remove
+ */
+ public void removeTableListener(TableListener listener) {
+ if (tableListeners != null) {
+ tableListeners.remove(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) {
+ DOM.setAttribute(tableElem, "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) {
+ DOM.setIntAttribute(tableElem, "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) {
+ DOM.setIntAttribute(tableElem, "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, String html) {
+ prepareCell(row, column);
+ Element td = cleanCell(row, column);
+ if (html != null) {
+ DOM.setInnerHTML(td, html);
+ }
+ }
+
+ /**
+ * 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 = cleanCell(row, column);
+ if (text != null) {
+ DOM.setInnerText(td, text);
+ }
+ }
+
+ /**
+ * Sets the widget within the specified cell.
+ * <p>
+ * Inherited implementations may either throw IndexOutOfBounds exception if
+ * the cell does not exist, or allocate a new cell to store the content.
+ * </p>
+ * <p>
+ * 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.
+ * </p>
+ *
+ * @param widget The widget to be added
+ * @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);
+ if (widget != null) {
+ // Call this early to ensure that the table doesn't end up partially
+ // constructed when an exception is thrown from adopt().
+ widget.removeFromParent();
+
+ // Attach it to the cell's TD.
+ Element td = cleanCell(row, column);
+
+ // Add the widget to the map.
+ String hash = Integer.toString(widget.hashCode());
+ Element e = widget.getElement();
+ DOM.setAttribute(e, HASH_ATTR, hash);
+ widgetMap.put(hash, widget);
+ // Set the widget's parent.
+ adopt(widget, td);
+ }
+ }
+
+ /**
+ * 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
+ * @return element that has been cleaned
+ */
+ private Element cleanCell(int row, int column) {
+ // Clear whatever is in the cell.
+ Element td = getCellFormatter().getRawElement(row, column);
+ internalClearCell(td);
+ return td;
+ }
+
+ /**
+ * Gets the key associated with the cell. This key is used within the widget
+ * map.
+ *
+ * @param row the cell's row
+ * @param column the cell's column
+ * @return the associated key
+ */
+ private Object computeKey(int row, int column) {
+ Element e = cellFormatter.getRawElement(row, column);
+ Element child = DOM.getFirstChild(e);
+ if (child == null) {
+ return null;
+ } else {
+ return computeKeyForElement(child);
+ }
+ }
+
+ /**
+ * Computes the key to lookup the Widget.
+ *
+ * @param widgetElement
+ * @return returns the key
+ */
+ private String computeKeyForElement(Element widgetElement) {
+ return DOM.getAttribute(widgetElement, HASH_ATTR);
+ }
+
+ /**
+ * Gets the Widget associated with the element.
+ *
+ * @param widgetElement widget's element
+ * @return the widget
+ */
+ private Widget getWidget(Element widgetElement) {
+ Object key = computeKeyForElement(widgetElement);
+ if (key != null) {
+ Widget widget = (Widget) widgetMap.get(key);
+ //assert (widget != null);
+ return widget;
+ } else {
+ return null;
+ }
+ }
+
+ /**
+ * Removes the given widget from a cell. The widget must not be
+ * <code>null</code>.
+ *
+ * @param widget widget to be removed
+ * @return always return true
+ */
+ private boolean removeWidget(Widget widget) {
+ // Clear the widget's parent.
+ disown(widget);
+
+ // Remove the widget from the map.
+ Object x = widgetMap.remove(computeKeyForElement(widget.getElement()));
+ //assert (x != null);
+ return true;
+ }
+
+ /**
+ * 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 Element createCell() {
+ return DOM.createTD();
+ }
+
+ /**
+ * Gets the table's TBODY element.
+ *
+ * @return the TBODY element
+ */
+ protected Element getBodyElement() {
+ return bodyElem;
+ }
+
+ /**
+ * 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 native int getDOMCellCount(Element elem, int row) /*-{
+ return elem.rows[row].cells.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);
+ }
+
+ protected native int getDOMRowCount(Element elem) /*-{
+ return elem.rows.length;
+ }-*/;
+
+ /**
+ * Determines the TD associated with the specified event.
+ *
+ * @param event the event to be queried
+ * @return the TD associated with the event, or <code>null</code> if none is
+ * found.
+ */
+ protected 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 (DOM.getAttribute(td, "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 (DOM.compare(body, bodyElem)) {
+ return td;
+ }
+ }
+ // If we run into this table's body, we're out of options.
+ if (DOM.compare(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
+ * @return returns whether a widget was cleared
+ */
+ protected boolean internalClearCell(Element td) {
+ Element maybeChild = DOM.getFirstChild(td);
+ Widget widget = null;
+ if (maybeChild != null) {
+ widget = getWidget(maybeChild);
+ }
+ if (widget != null) {
+ // If there is a widget, remove it.
+ removeWidget(widget);
+ return true;
+ } else {
+ // Otherwise, simply clear whatever text and/or HTML may be there.
+ DOM.setInnerHTML(td, "");
+ return false;
+ }
+ }
+
+ /**
+ * 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 must implement this method. It allows them to decide what to do
+ * just before a row is accessed. 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);
+ Element tr = rowFormatter.getRow(bodyElem, row);
+ DOM.removeChild(tr, 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);
+ }
+ DOM.removeChild(bodyElem, rowFormatter.getRow(bodyElem, row));
+ }
+
+ /**
+ * Sets the table's CellFormatter.
+ *
+ * @param cellFormatter the table's cell formatter
+ */
+ protected void setCellFormatter(CellFormatter cellFormatter) {
+ this.cellFormatter = cellFormatter;
+ }
+
+ /**
+ * Sets the table's RowFormatter.
+ *
+ * @param rowFormatter the table's row formatter
+ */
+ protected void setRowFormatter(RowFormatter rowFormatter) {
+ this.rowFormatter = rowFormatter;
+ }
+
+ /**
+ * Gets the widget map, only should be used by testing code.
+ *
+ * @return the internal widget map
+ */
+ FastStringMap getWidgetMap() {
+ return widgetMap;
+ }
+
+ /**
+ * Table's body.
+ */
+ private final Element bodyElem;
+ /**
+ * Current cell formatter.
+ */
+ private CellFormatter cellFormatter;
+ /**
+ * Current row formatter.
+ */
+ private RowFormatter rowFormatter;
+ /**
+ * Table element.
+ */
+ private final Element tableElem;
+ /**
+ * Current table listener.
+ */
+ private TableListenerCollection tableListeners;
+ /**
+ * The element map, used to quickly look up the Widget in a particular cell.
+ * We have to use a map here, because hanging references to Widgets from
+ * Elements would cause memory leaks.
+ */
+ private FastStringMap widgetMap = new FastStringMap();
+}
\ No newline at end of file
Added: labs/jbossrules/trunk/drools-jbrms/src/main/java/org/drools/brms/client/decisiontable/EditActions.java
===================================================================
--- labs/jbossrules/trunk/drools-jbrms/src/main/java/org/drools/brms/client/decisiontable/EditActions.java 2006-10-13 08:10:58 UTC (rev 6786)
+++ labs/jbossrules/trunk/drools-jbrms/src/main/java/org/drools/brms/client/decisiontable/EditActions.java 2006-10-13 09:35:21 UTC (rev 6787)
@@ -0,0 +1,72 @@
+package org.drools.brms.client.decisiontable;
+
+import com.google.gwt.user.client.ui.ClickListener;
+import com.google.gwt.user.client.ui.Composite;
+import com.google.gwt.user.client.ui.HorizontalPanel;
+import com.google.gwt.user.client.ui.Image;
+import com.google.gwt.user.client.ui.Widget;
+
+/**
+ * This shows the widgets for editing a row.
+ * @author Michael Neale
+ */
+public class EditActions extends Composite {
+
+ private HorizontalPanel panel = new HorizontalPanel();
+ private Image edit;
+ private Image ok;
+
+
+
+
+ /**
+ * Pass in the click listener delegates for when the respective action is clicked
+ * @param editClickListener
+ * @param okClickListener
+ */
+ public EditActions(final ClickListener editClickListener,
+ final ClickListener okClickListener) {
+
+ edit = new Image("images/edit.gif");
+ edit.setTitle( "Edit this row" );
+ edit.addClickListener( new ClickListener() {
+
+ public void onClick(Widget w) {
+ makeEditable();
+ editClickListener.onClick( w );
+ }
+
+ });
+
+ ok = new Image("images/tick.gif");
+ ok.setTitle( "Apply the edit changes to this row." );
+ ok.addClickListener( new ClickListener() {
+
+ public void onClick(Widget w) {
+ makeReadOnly();
+ okClickListener.onClick( w );
+ }
+
+ });
+
+ panel.add( edit );
+ panel.add( ok );
+ ok.setVisible( false );
+
+ initWidget( panel );
+ }
+
+ public void makeEditable() {
+ edit.setVisible( false );
+ ok.setVisible( true );
+
+ }
+
+ public void makeReadOnly() {
+ edit.setVisible( true );
+ ok.setVisible( false );
+ }
+
+
+
+}
Modified: labs/jbossrules/trunk/drools-jbrms/src/main/java/org/drools/brms/client/decisiontable/EditableDTGrid.java
===================================================================
--- labs/jbossrules/trunk/drools-jbrms/src/main/java/org/drools/brms/client/decisiontable/EditableDTGrid.java 2006-10-13 08:10:58 UTC (rev 6786)
+++ labs/jbossrules/trunk/drools-jbrms/src/main/java/org/drools/brms/client/decisiontable/EditableDTGrid.java 2006-10-13 09:35:21 UTC (rev 6787)
@@ -10,12 +10,20 @@
import com.google.gwt.user.client.ui.VerticalPanel;
import com.google.gwt.user.client.ui.Widget;
import com.google.gwt.user.client.ui.FlexTable.FlexCellFormatter;
+import com.google.gwt.user.client.ui.HTMLTable.CellFormatter;
/**
* The decision table viewer and editor.
* @author Michael Neale
* @author Stephen Williams
- *
+ *
+ * TODO: add editors for header stuff,
+ * and ability to add rows/cols and shift rows around
+ * This probably can be done from a seperate "editor" such that it is re-rendered
+ * when you need to add/move a col or row.
+ *
+ * Should be able to add/shift stuff around by entering a row number to deal with.
+ *
*/
public class EditableDTGrid extends Composite {
@@ -38,7 +46,6 @@
header.add( title );
vert.add( header );
-
vert.add( table );
FlexCellFormatter cellFormatter = table.getFlexCellFormatter();
@@ -51,77 +58,97 @@
//and the data follows
populateDataGrid( cellFormatter );
- //and this is how you span things, FYI
+ //and this is how you span/merge things, FYI
//table.getFlexCellFormatter().setColSpan( 2, 3, 4 );
-
-
+ //needed for Composite
initWidget( vert );
-
}
private void populateHeader(FlexCellFormatter cellFormatter) {
- for (int col = 0; col < numCols(); col++) {
+
+ //for the count column
+ cellFormatter.setStyleName( 0, 0, "dt-editor-DescriptionCell" );
+
+ for (int col = 1; col < numCols() + 1; col++) {
table.setText( 0, col, "some header " + col );
cellFormatter.setStyleName( 0, col, "dt-editor-DescriptionCell" );
}
}
+ /**
+ * This populates the "data" part of the decision table (not the header bits).
+ * It starts at the row offset.
+ * @param cellFormatter So it can set the style of each cell that is created.
+ */
private void populateDataGrid(FlexCellFormatter cellFormatter) {
+
for ( int i = 0; i < numRows(); i++ ) {
- int column = 0;
+
+ int rowCount = i + 1;
+
+ int column = 1;
int row = i + START_DATA_ROW;
- for ( ; column < numCols(); column++ ) {
+
+ //now do the count column
+ table.setText( row, 0, Integer.toString( rowCount) );
+ cellFormatter.setStyleName( row, 0, "dt-editor-CountColumn" );
+ for ( ; column < numCols() + 1; column++ ) {
table.setText( row,
column,
"boo " + column );
cellFormatter.setStyleName( row, column, "dt-editor-Cell" );
}
-
+
final int currentRow = row;
- Image editButton = new Image("images/edit.gif");
- editButton.addClickListener( new ClickListener() {
- public void onClick(Widget w) {
- editRow(currentRow);
-
- }
- });
+ //the action magic
+ final EditActions actions = new EditActions(new ClickListener() {
+ public void onClick(Widget w) {editRow( currentRow );}
+ },
+ new ClickListener() {
+ public void onClick(Widget w) {updateRow( currentRow );}
+ });
+ table.setWidget( currentRow, column, actions );
- table.setWidget( row, column, editButton );
-
}
}
-
+ /**
+ * Apply the changes to the row.
+ */
+ private void updateRow(int row) {
+ for (int column = 1; column < numCols() + 1; column++) {
+ TextBox text = (TextBox) table.getWidget( row, column );
+ table.setText( row, column, text.getText() );
+ }
+ }
+
+
+ /**
+ * This switches the given row into edit mode.
+ * @param row
+ */
private void editRow(int row) {
- for (int column = 0; column < numCols(); column++) {
+ for (int column = 1; column < numCols() + 1; column++) {
String text = table.getText( row, column );
- Widget w = table.getWidget( row, column );
- if (w == null) {
TextBox box = new TextBox();
box.setText( text );
box.setStyleName( "dsl-field-TextBox" );
- box.setVisibleLength( 3 );
+ box.setVisibleLength( 3 );
+ table.setWidget( row, column, box );
- table.setWidget( row, column, box );
-
- } else {
- table.setText( row, column, ((TextBox ) w).getText());
- }
}
-
-
}
private int numCols() {
- return 7;
+ return 6;
}
private int numRows() {
- return 12;
+ return 14;
}
}
Modified: labs/jbossrules/trunk/drools-jbrms/src/main/java/org/drools/brms/public/JBRMS.css
===================================================================
--- labs/jbossrules/trunk/drools-jbrms/src/main/java/org/drools/brms/public/JBRMS.css 2006-10-13 08:10:58 UTC (rev 6786)
+++ labs/jbossrules/trunk/drools-jbrms/src/main/java/org/drools/brms/public/JBRMS.css 2006-10-13 09:35:21 UTC (rev 6787)
@@ -274,6 +274,13 @@
padding: 3px;
}
+.dt-editor-CountColumn {
+ background-color: #FDFCDC;
+ font-size: smaller;
+ padding: 3px;
+}
+
+
.dt-editor-Title {
font-size: larger;
}
More information about the jboss-svn-commits
mailing list