Home | History | Annotate | Download | only in table
      1 package autotest.common.table;
      2 
      3 import autotest.common.DomUtils;
      4 import autotest.common.ui.RightClickTable;
      5 
      6 import com.google.gwt.event.dom.client.ClickEvent;
      7 import com.google.gwt.user.client.DOM;
      8 import com.google.gwt.user.client.Element;
      9 import com.google.gwt.user.client.Event;
     10 import com.google.gwt.user.client.ui.HTMLTable;
     11 
     12 import java.util.ArrayList;
     13 import java.util.List;
     14 
     15 /**
     16  * Customized table class supporting multiple tbody elements.  It is modified to support input
     17  * handling, getRowCount(), getCellCount(), and getCellFormatter().getElement().  getElement()
     18  * also works.  Calls to other methods aren't guaranteed to work.
     19  */
     20 public class FragmentedTable extends RightClickTable {
     21     public class FragmentedCellFormatter extends HTMLTable.CellFormatter {
     22         @Override
     23         public Element getElement(int row, int column) {
     24             checkCellBounds(row, column);
     25             Element bodyElem = bodyElems.get(getFragmentIndex(row));
     26             return getCellElement(bodyElem, getRowWithinFragment(row), column);
     27         }
     28 
     29         /**
     30          * Native method to efficiently get a td element from a tbody. Copied from GWT's
     31          * HTMLTable.java.
     32          */
     33         private native Element getCellElement(Element tbody, int row, int col) /*-{
     34             return tbody.rows[row].cells[col];
     35         }-*/;
     36     }
     37 
     38     private List<Element> bodyElems = new ArrayList<Element>();
     39     private int totalRowCount;
     40     private int rowsPerFragment;
     41 
     42     public FragmentedTable() {
     43         super();
     44         setCellFormatter(new FragmentedCellFormatter());
     45 
     46         // Reset the FragmentedTable to clear out elements that were added by the HTMLTable and
     47         // FlexTable constructors
     48         reset();
     49     }
     50 
     51     /**
     52      * This method must be called after added or removing tbody elements and before using other
     53      * functionality (accessing cell elements, input handling, etc.).
     54      */
     55     public void updateBodyElems() {
     56         totalRowCount = 0;
     57         Element tbody = DOM.getFirstChild(getElement());
     58         for(; tbody != null; tbody = DOM.getNextSibling(tbody)) {
     59             assert tbody.getTagName().equalsIgnoreCase("tbody");
     60             bodyElems.add(tbody);
     61             totalRowCount += getRowCount(tbody);
     62         }
     63     }
     64 
     65     public void reset() {
     66         bodyElems.clear();
     67         DomUtils.clearDomChildren(getElement());
     68     }
     69 
     70     private int getRowWithinFragment(int row) {
     71         return row % rowsPerFragment;
     72     }
     73 
     74     private int getFragmentIndex(int row) {
     75         return row / rowsPerFragment;
     76     }
     77 
     78     @Override
     79     public HTMLTable.Cell getCellForEvent(ClickEvent event) {
     80         return getCellForDomEvent(event);
     81     }
     82 
     83     @Override
     84     protected RowColumn getCellPosition(Element td) {
     85         Element tr = DOM.getParent(td);
     86         Element body = DOM.getParent(tr);
     87         int fragmentIndex = DOM.getChildIndex(getElement(), body);
     88         int rowWithinFragment = DOM.getChildIndex(body, tr);
     89         int row = fragmentIndex * rowsPerFragment + rowWithinFragment;
     90         int column = DOM.getChildIndex(tr, td);
     91         return new RowColumn(row, column);
     92     }
     93 
     94     /**
     95      * This is a modified version of getEventTargetCell() from HTMLTable.java.
     96      */
     97     @Override
     98     protected Element getEventTargetCell(Event event) {
     99         Element td = DOM.eventGetTarget(event);
    100         for (; td != null; td = DOM.getParent(td)) {
    101             // If it's a TD, it might be the one we're looking for.
    102             if (DOM.getElementProperty(td, "tagName").equalsIgnoreCase("td")) {
    103                 // Make sure it's directly a part of this table before returning
    104                 // it.
    105                 Element tr = DOM.getParent(td);
    106                 Element body = DOM.getParent(tr);
    107                 Element tableElem = DOM.getParent(body);
    108                 if (tableElem == getElement()) {
    109                     return td;
    110                 }
    111             }
    112             // If we run into this table's element, we're out of options.
    113             if (td == getElement()) {
    114                 return null;
    115             }
    116         }
    117         return null;
    118     }
    119 
    120     @Override
    121     public int getCellCount(int row) {
    122         Element bodyElem = bodyElems.get(getFragmentIndex(row));
    123         return getCellCount(bodyElem, getRowWithinFragment(row));
    124     }
    125 
    126     @Override
    127     public int getRowCount() {
    128         return totalRowCount;
    129     }
    130 
    131     private native int getRowCount(Element tbody) /*-{
    132         return tbody.rows.length;
    133     }-*/;
    134 
    135     private native int getCellCount(Element tbody, int row) /*-{
    136         return tbody.rows[row].cells.length;
    137     }-*/;
    138 
    139     /**
    140      * This must be called before using other functionality (accessing cell elements, input
    141      * handling, etc.).
    142      * @param rowsPerFragment  The number of rows in each tbody.  The last tbody may have fewer
    143      * rows.  All others must have exactly this number of rows.
    144      */
    145     public void setRowsPerFragment(int rowsPerFragment) {
    146         this.rowsPerFragment = rowsPerFragment;
    147     }
    148 }
    149