• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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
getElement(int row, int column)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          */
getCellElement(Element tbody, int row, int col)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 
FragmentedTable()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      */
updateBodyElems()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 
reset()65     public void reset() {
66         bodyElems.clear();
67         DomUtils.clearDomChildren(getElement());
68     }
69 
getRowWithinFragment(int row)70     private int getRowWithinFragment(int row) {
71         return row % rowsPerFragment;
72     }
73 
getFragmentIndex(int row)74     private int getFragmentIndex(int row) {
75         return row / rowsPerFragment;
76     }
77 
78     @Override
getCellForEvent(ClickEvent event)79     public HTMLTable.Cell getCellForEvent(ClickEvent event) {
80         return getCellForDomEvent(event);
81     }
82 
83     @Override
getCellPosition(Element td)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
getEventTargetCell(Event event)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
getCellCount(int row)121     public int getCellCount(int row) {
122         Element bodyElem = bodyElems.get(getFragmentIndex(row));
123         return getCellCount(bodyElem, getRowWithinFragment(row));
124     }
125 
126     @Override
getRowCount()127     public int getRowCount() {
128         return totalRowCount;
129     }
130 
getRowCount(Element tbody)131     private native int getRowCount(Element tbody) /*-{
132         return tbody.rows.length;
133     }-*/;
134 
getCellCount(Element tbody, int row)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      */
setRowsPerFragment(int rowsPerFragment)145     public void setRowsPerFragment(int rowsPerFragment) {
146         this.rowsPerFragment = rowsPerFragment;
147     }
148 }
149