Revision: 7696
Author: [email protected]
Date: Wed Mar 10 08:48:25 2010
Log: Adds basic support for headers and footers in the table view widget.
In its
current form, it removes the next/prev-page buttons; I'll re-add those in a
separate pass.
http://code.google.com/p/google-web-toolkit/source/detail?r=7696
Modified:
/trunk/bikeshed/src/com/google/gwt/bikeshed/cells/client/CheckboxCell.java
/trunk/bikeshed/src/com/google/gwt/bikeshed/list/client/PagingTableListView.java
/trunk/bikeshed/src/com/google/gwt/bikeshed/list/client/SimpleCellList.java
/trunk/bikeshed/src/com/google/gwt/bikeshed/sample/stocks/client/StockQueryWidget.java
/trunk/bikeshed/src/com/google/gwt/bikeshed/sample/stocks/client/StockSample.java
=======================================
---
/trunk/bikeshed/src/com/google/gwt/bikeshed/cells/client/CheckboxCell.java
Fri Mar 5 07:05:48 2010
+++
/trunk/bikeshed/src/com/google/gwt/bikeshed/cells/client/CheckboxCell.java
Wed Mar 10 08:48:25 2010
@@ -40,7 +40,7 @@
@Override
public void render(Boolean data, StringBuilder sb) {
sb.append("<input type=\"checkbox\"");
- if (data == true) {
+ if ((data != null) && (data == true)) {
sb.append(" checked");
}
sb.append("/>");
=======================================
---
/trunk/bikeshed/src/com/google/gwt/bikeshed/list/client/PagingTableListView.java
Fri Feb 26 09:32:06 2010
+++
/trunk/bikeshed/src/com/google/gwt/bikeshed/list/client/PagingTableListView.java
Wed Mar 10 08:48:25 2010
@@ -15,8 +15,6 @@
*/
package com.google.gwt.bikeshed.list.client;
-import com.google.gwt.bikeshed.cells.client.ButtonCell;
-import com.google.gwt.bikeshed.cells.client.ValueUpdater;
import com.google.gwt.bikeshed.list.shared.ListEvent;
import com.google.gwt.bikeshed.list.shared.ListHandler;
import com.google.gwt.bikeshed.list.shared.ListModel;
@@ -31,6 +29,7 @@
import com.google.gwt.dom.client.TableCellElement;
import com.google.gwt.dom.client.TableElement;
import com.google.gwt.dom.client.TableRowElement;
+import com.google.gwt.dom.client.TableSectionElement;
import com.google.gwt.dom.client.Style.Display;
import com.google.gwt.user.client.Event;
import com.google.gwt.user.client.ui.Widget;
@@ -52,16 +51,27 @@
private int totalSize;
private List<Column<T, ?>> columns = new ArrayList<Column<T, ?>>();
private ArrayList<T> data = new ArrayList<T>();
- private ButtonCell prevButton = new ButtonCell();
- private ButtonCell nextButton = new ButtonCell();
+
+ private List<Header<?>> headers = new ArrayList<Header<?>>();
+ private List<Header<?>> footers = new ArrayList<Header<?>>();
+
+ private TableElement table;
+ private TableSectionElement thead;
+ private TableSectionElement tfoot;
+ private TableSectionElement tbody;
public PagingTableListView(ListModel<T> listModel, final int pageSize) {
this.pageSize = pageSize;
- setElement(Document.get().createTableElement());
+ setElement(table = Document.get().createTableElement());
+ thead = table.createTHead();
+ table.appendChild(tbody = Document.get().createTBodyElement());
+ tfoot = table.createTFoot();
createRows();
- // TODO: total hack.
- sinkEvents(Event.MOUSEEVENTS | Event.KEYEVENTS);
+ // TODO: Total hack. It would almost definitely be preferable to sink
only
+ // those events actually needed by cells.
+ sinkEvents(Event.ONCLICK | Event.MOUSEEVENTS | Event.KEYEVENTS
+ | Event.ONCHANGE);
// Attach to the list model.
listReg = listModel.addListHandler(new ListHandler<T>() {
@@ -82,8 +92,19 @@
listReg.setRangeOfInterest(0, pageSize);
}
- // TODO: remove(Column)
public void addColumn(Column<T, ?> col) {
+ addColumn(col, null, null);
+ }
+
+ public void addColumn(Column<T, ?> col, Header<?> header) {
+ addColumn(col, header, null);
+ }
+
+ // TODO: remove(Column)
+ public void addColumn(Column<T, ?> col, Header<?> header, Header<?>
footer) {
+ headers.add(header);
+ footers.add(footer);
+ createHeadersAndFooters(); // TODO: defer header recreation
columns.add(col);
createRows();
setPage(curPage); // TODO: better way to refresh?
@@ -106,44 +127,29 @@
public void onBrowserEvent(Event event) {
EventTarget target = event.getEventTarget();
Node node = Node.as(target);
- while (node != null) {
- if (Element.is(node)) {
- Element elem = Element.as(node);
-
- // TODO: We need is() implementations in all Element subclasses.
- String tagName = elem.getTagName();
- if ("td".equalsIgnoreCase(tagName)) {
- TableCellElement td = TableCellElement.as(elem);
- TableRowElement tr = TableRowElement.as(td.getParentElement());
-
- // TODO: row/col assertions.
- int row = tr.getRowIndex(), col = td.getCellIndex();
- if (row < pageSize) {
- T value = data.get(row);
- Column<T, ?> column = columns.get(col);
- column.onBrowserEvent(elem, value, event);
- } else if (row == pageSize) {
- if (col == 0) {
- prevButton.onBrowserEvent(elem, null, event,
- new ValueUpdater<String>() {
- public void update(String value) {
- previousPage();
- }
- });
- } else if (col == 2) {
- nextButton.onBrowserEvent(elem, null, event,
- new ValueUpdater<String>() {
- public void update(String value) {
- nextPage();
- }
- });
- }
- }
- break;
- }
- }
-
- node = node.getParentNode();
+ TableCellElement cell = findNearestParentCell(node);
+ if (cell == null) {
+ return;
+ }
+
+ TableRowElement tr = TableRowElement.as(cell.getParentElement());
+ TableSectionElement section =
TableSectionElement.as(tr.getParentElement());
+ int col = cell.getCellIndex();
+ if (section == thead) {
+ Header<?> header = headers.get(col);
+ if (header != null) {
+ header.onBrowserEvent(cell, event);
+ }
+ } else if (section == tfoot) {
+ Header<?> footer = footers.get(col);
+ if (footer != null) {
+ footer.onBrowserEvent(cell, event);
+ }
+ } else if (section == tbody) {
+ int row = tr.getSectionRowIndex();
+ T value = data.get(row);
+ Column<T, ?> column = columns.get(col);
+ column.onBrowserEvent(cell, value, event);
}
}
@@ -187,11 +193,10 @@
}
protected void render(int start, int length, List<T> values) {
- TableElement table = getElement().cast();
int numCols = columns.size();
int pageStart = curPage * pageSize;
- NodeList<TableRowElement> rows = table.getRows();
+ NodeList<TableRowElement> rows = tbody.getRows();
for (int r = start; r < start + length; ++r) {
TableRowElement row = rows.getItem(r - pageStart);
T q = values.get(r - start);
@@ -203,55 +208,53 @@
columns.get(c).render(q, sb);
cell.setInnerHTML(sb.toString());
- // TODO: really total hack!
+ // TODO: Really total hack! There's gotta be a better way...
Element child = cell.getFirstChildElement();
if (child != null) {
- Event.sinkEvents(child, Event.ONCHANGE | Event.ONFOCUS |
Event.ONBLUR);
+ Event.sinkEvents(child, Event.ONFOCUS | Event.ONBLUR);
}
}
}
}
+
+ private void createHeaders(List<Header<?>> headers, TableSectionElement
section) {
+ StringBuilder sb = new StringBuilder();
+ sb.append("<tr>");
+ for (Header<?> header : headers) {
+ sb.append("<th>");
+ if (header != null) {
+ header.render(sb);
+ }
+ sb.append("</th>");
+ }
+ sb.append("</tr>");
+
+ section.setInnerHTML(sb.toString());
+ }
+
+ private void createHeadersAndFooters() {
+ createHeaders(headers, thead);
+ createHeaders(footers, tfoot);
+ }
private void createRows() {
- TableElement table = getElement().cast();
int numCols = columns.size();
// TODO - only delete as needed
- int numRows = table.getRows().getLength();
+ int numRows = tbody.getRows().getLength();
while (numRows-- > 0) {
- table.deleteRow(0);
+ tbody.deleteRow(0);
}
for (int r = 0; r < pageSize; ++r) {
- TableRowElement row = table.insertRow(0);
- row.setClassName("pagingTableListView "
- + ((r & 0x1) == 0 ? "evenRow" : "oddRow"));
+ TableRowElement row = tbody.insertRow(0);
+ row.setClassName("pagingTableListView " + ((r & 0x1) ==
0 ? "evenRow" : "oddRow"));
// TODO: use cloneNode() to make this even faster.
for (int c = 0; c < numCols; ++c) {
row.insertCell(c);
}
}
-
- // Add the final row containing paging buttons
- TableRowElement pageRow = table.insertRow(pageSize);
- pageRow.insertCell(0);
- pageRow.insertCell(1);
- pageRow.insertCell(2);
-
- StringBuilder sb;
-
- sb = new StringBuilder();
- prevButton.render("Previous", sb);
- pageRow.getCells().getItem(0).setInnerHTML(sb.toString());
-
- pageRow.getCells().getItem(1).setAttribute("colspan", "" + (numCols -
2));
- pageRow.getCells().getItem(1).setAttribute("align", "center");
-
- sb = new StringBuilder();
- nextButton.render("Next", sb);
- pageRow.getCells().getItem(2).setInnerHTML(sb.toString());
- pageRow.getCells().getItem(2).setAttribute("align", "right");
// Make room for the data cache
data.ensureCapacity(pageSize);
@@ -259,6 +262,23 @@
data.add(null);
}
}
+
+ private TableCellElement findNearestParentCell(Node node) {
+ while ((node != null) && (node != table)) {
+ if (Element.is(node)) {
+ Element elem = Element.as(node);
+
+ // TODO: We need is() implementations in all Element subclasses.
+ // This would allow us to use TableCellElement.is() -- much
cleaner.
+ String tagName = elem.getTagName();
+ if ("td".equalsIgnoreCase(tagName) |
| "th".equalsIgnoreCase(tagName)) {
+ return elem.cast();
+ }
+ }
+ node = node.getParentNode();
+ }
+ return null;
+ }
/**
* Update the text that shows the current page.
@@ -266,18 +286,14 @@
* @param page the current page
*/
private void updatePageText(int page) {
- TableElement table = getElement().cast();
- NodeList<TableRowElement> rows = table.getRows();
- String text = "Page " + (page + 1) + " of " + numPages;
- rows.getItem(rows.getLength() -
1).getCells().getItem(1).setInnerText(text);
+ // TODO: Update external paging widget.
}
private void updateRowVisibility() {
int visible = Math.min(pageSize, totalSize - curPage * pageSize);
- TableElement table = getElement().cast();
for (int r = 0; r < pageSize; ++r) {
- Style rowStyle = table.getRows().getItem(r).getStyle();
+ Style rowStyle = tbody.getRows().getItem(r).getStyle();
if (r < visible) {
rowStyle.clearDisplay();
} else {
=======================================
---
/trunk/bikeshed/src/com/google/gwt/bikeshed/list/client/SimpleCellList.java
Fri Feb 26 09:32:06 2010
+++
/trunk/bikeshed/src/com/google/gwt/bikeshed/list/client/SimpleCellList.java
Wed Mar 10 08:48:25 2010
@@ -24,6 +24,7 @@
import com.google.gwt.bikeshed.list.shared.SizeChangeEvent;
import com.google.gwt.dom.client.Document;
import com.google.gwt.dom.client.Element;
+import com.google.gwt.dom.client.Node;
import com.google.gwt.user.client.Event;
import com.google.gwt.user.client.ui.Widget;
@@ -113,19 +114,25 @@
Element parent = getElement();
int childCount = parent.getChildCount();
- // Update existing cells with new values.
- int i, existing = Math.min(len, childCount);
- for (i = start; i < existing; ++i) {
- Element elem = parent.getChild(i).cast();
- cell.setValue(elem, values.get(i));
+ // Create innerHTML for the new items.
+ int end = start + len;
+ StringBuilder html = new StringBuilder();
+
+ // Empty items to fill any gaps.
+ int totalToAdd = 0;
+ for (int i = childCount; i < start; ++i) {
+ html.append("<div __idx='" + i + "'>");
+ cell.render(null, html);
+ html.append("</div>");
+ ++totalToAdd;
}
- // Create new cells if necessary.
- StringBuilder html = new StringBuilder();
- for (; i < len; ++i) {
+ // Items rendered from data.
+ for (int i = start; i < end; ++i) {
html.append("<div __idx='" + i + "'>");
- cell.render(values.get(i), html);
+ cell.render(values.get(i - start), html);
html.append("</div>");
+ ++totalToAdd;
}
if (childCount == 0) {
@@ -135,10 +142,28 @@
// Slower path: We can't clobber the existing cells, so we use
innerHTML
// in a temporary element, then move the cells back to the main
element.
tmpElem.setInnerHTML(html.toString());
+
+ // Clear out old cells that overlap the new cells.
+ if (start < childCount) {
+ int toRemove = Math.min(end, childCount) - start;
+ for (int i = 0; i < toRemove; ++i) {
+ parent.removeChild(parent.getChild(start));
+ }
+ childCount = parent.getChildCount();
+ }
// Move the new cells over from the temp element.
- for (i = 0; i < len - childCount; ++i) {
- parent.appendChild(tmpElem.getChild(0));
+ if (start >= childCount) {
+ // Just append to the end.
+ for (int i = 0; i < totalToAdd; ++i) {
+ parent.appendChild(tmpElem.getChild(0));
+ }
+ } else {
+ // Insert them in the middle somewhere.
+ Node before = parent.getChild(start);
+ for (int i = 0; i < totalToAdd; ++i) {
+ parent.insertBefore(tmpElem.getChild(0), before);
+ }
}
}
}
=======================================
---
/trunk/bikeshed/src/com/google/gwt/bikeshed/sample/stocks/client/StockQueryWidget.java
Wed Mar 10 05:41:10 2010
+++
/trunk/bikeshed/src/com/google/gwt/bikeshed/sample/stocks/client/StockQueryWidget.java
Wed Mar 10 08:48:25 2010
@@ -16,6 +16,7 @@
package com.google.gwt.bikeshed.sample.stocks.client;
import com.google.gwt.bikeshed.list.client.PagingTableListView;
+import com.google.gwt.bikeshed.list.client.TextHeader;
import com.google.gwt.bikeshed.list.shared.ListModel;
import com.google.gwt.bikeshed.sample.stocks.shared.StockQuote;
import com.google.gwt.dom.client.Style.Unit;
@@ -40,9 +41,9 @@
// Create the results table.
resultsTable = new PagingTableListView<StockQuote>(searchListModel,
10);
resultsTable.addColumn(Columns.favoriteColumn);
- resultsTable.addColumn(Columns.tickerColumn);
- resultsTable.addColumn(Columns.nameColumn);
- resultsTable.addColumn(Columns.priceColumn);
+ resultsTable.addColumn(Columns.tickerColumn, new TextHeader("ticker"));
+ resultsTable.addColumn(Columns.nameColumn, new TextHeader("name"));
+ resultsTable.addColumn(Columns.priceColumn, new TextHeader("price"));
resultsTable.addColumn(Columns.buyColumn);
// Focus the cursor on the name field when the app loads
=======================================
---
/trunk/bikeshed/src/com/google/gwt/bikeshed/sample/stocks/client/StockSample.java
Wed Mar 10 08:08:46 2010
+++
/trunk/bikeshed/src/com/google/gwt/bikeshed/sample/stocks/client/StockSample.java
Wed Mar 10 08:48:25 2010
@@ -17,6 +17,7 @@
import com.google.gwt.bikeshed.cells.client.FieldUpdater;
import com.google.gwt.bikeshed.list.client.PagingTableListView;
+import com.google.gwt.bikeshed.list.client.TextHeader;
import com.google.gwt.bikeshed.list.shared.AsyncListModel;
import com.google.gwt.bikeshed.list.shared.ListListModel;
import com.google.gwt.bikeshed.list.shared.Range;
@@ -135,10 +136,10 @@
// Create the favorites table.
favoritesTable = new
PagingTableListView<StockQuote>(favoritesListModel, 10);
- favoritesTable.addColumn(Columns.tickerColumn);
- favoritesTable.addColumn(Columns.priceColumn);
- favoritesTable.addColumn(Columns.sharesColumn);
- favoritesTable.addColumn(Columns.dollarsColumn);
+ favoritesTable.addColumn(Columns.tickerColumn, new
TextHeader("ticker"));
+ favoritesTable.addColumn(Columns.priceColumn, new TextHeader("price"));
+ favoritesTable.addColumn(Columns.sharesColumn, new
TextHeader("shares"));
+ favoritesTable.addColumn(Columns.dollarsColumn, new
TextHeader("value"));
favoritesTable.addColumn(Columns.buyColumn);
favoritesTable.addColumn(Columns.sellColumn);
--
http://groups.google.com/group/Google-Web-Toolkit-Contributors