[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, "&nbsp;");
+    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, "&nbsp;");
+    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