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