Making Column implement HasAlignment so users can specify the default alignment of cells in a column. In the future, we may add a way to specify the alignment of specific Cells. Issue: 5623 Review at http://gwt-code-reviews.appspot.com/1134801 Review by: rchandia@google.com git-svn-id: https://google-web-toolkit.googlecode.com/svn/trunk@9269 8db76d5a-ed1c-0410-87a9-c151d255dfc7
diff --git a/samples/showcase/src/com/google/gwt/sample/showcase/client/content/cell/CwCellSampler.java b/samples/showcase/src/com/google/gwt/sample/showcase/client/content/cell/CwCellSampler.java index dbc5850..3e37407 100644 --- a/samples/showcase/src/com/google/gwt/sample/showcase/client/content/cell/CwCellSampler.java +++ b/samples/showcase/src/com/google/gwt/sample/showcase/client/content/cell/CwCellSampler.java
@@ -53,6 +53,7 @@ import com.google.gwt.user.client.Window; import com.google.gwt.user.client.rpc.AsyncCallback; import com.google.gwt.user.client.ui.Button; +import com.google.gwt.user.client.ui.HasHorizontalAlignment; import com.google.gwt.user.client.ui.Widget; import java.util.ArrayList; @@ -268,8 +269,8 @@ pendingChanges.add(new CategoryChange(object, categories[0])); } else { // If not a relative, use the Contacts Category. - pendingChanges.add( - new CategoryChange(object, categories[categories.length - 1])); + pendingChanges.add(new CategoryChange(object, + categories[categories.length - 1])); } } }); @@ -315,8 +316,8 @@ }); // ActionCell. - addColumn(new ActionCell<ContactInfo>( - "Click Me", new ActionCell.Delegate<ContactInfo>() { + addColumn(new ActionCell<ContactInfo>("Click Me", + new ActionCell.Delegate<ContactInfo>() { public void execute(ContactInfo contact) { Window.alert("You clicked " + contact.getFullName()); } @@ -338,8 +339,7 @@ }); // DateCell. - DateTimeFormat dateFormat = DateTimeFormat.getFormat( - PredefinedFormat.DATE_MEDIUM); + DateTimeFormat dateFormat = DateTimeFormat.getFormat(PredefinedFormat.DATE_MEDIUM); addColumn(new DateCell(dateFormat), "Date", new GetValue<Date>() { public Date getValue(ContactInfo contact) { return contact.getBirthday(); @@ -347,8 +347,8 @@ }, null); // DatePickerCell. - addColumn( - new DatePickerCell(dateFormat), "DatePicker", new GetValue<Date>() { + addColumn(new DatePickerCell(dateFormat), "DatePicker", + new GetValue<Date>() { public Date getValue(ContactInfo contact) { return contact.getBirthday(); } @@ -359,29 +359,29 @@ }); // NumberCell. - addColumn(new NumberCell(), "Number", new GetValue<Number>() { - @SuppressWarnings("deprecation") - public Number getValue(ContactInfo contact) { - Date today = new Date(); - Date birthday = contact.getBirthday(); - int age = today.getYear() - birthday.getYear(); - if (today.getMonth() > birthday.getMonth() - || (today.getMonth() == birthday.getMonth() - && today.getDate() > birthday.getDate())) { - age--; - } - return age; - } - }, null); - - // IconCellDecorator. - addColumn( - new IconCellDecorator<String>(images.contactsGroup(), new TextCell()), - "Icon", new GetValue<String>() { - public String getValue(ContactInfo contact) { - return contact.getCategory().getDisplayName(); + Column<ContactInfo, Number> numberColumn = addColumn(new NumberCell(), + "Number", new GetValue<Number>() { + @SuppressWarnings("deprecation") + public Number getValue(ContactInfo contact) { + Date today = new Date(); + Date birthday = contact.getBirthday(); + int age = today.getYear() - birthday.getYear(); + if (today.getMonth() > birthday.getMonth() + || (today.getMonth() == birthday.getMonth() && today.getDate() > birthday.getDate())) { + age--; + } + return age; } }, null); + numberColumn.setHorizontalAlignment(HasHorizontalAlignment.ALIGN_LOCALE_END); + + // IconCellDecorator. + addColumn(new IconCellDecorator<String>(images.contactsGroup(), + new TextCell()), "Icon", new GetValue<String>() { + public String getValue(ContactInfo contact) { + return contact.getCategory().getDisplayName(); + } + }, null); // ImageCell. addColumn(new ImageCell(), "Image", new GetValue<String>() { @@ -459,7 +459,7 @@ * @param getter the value getter for the cell */ @ShowcaseSource - private <C> void addColumn(Cell<C> cell, String headerText, + private <C> Column<ContactInfo, C> addColumn(Cell<C> cell, String headerText, final GetValue<C> getter, FieldUpdater<ContactInfo, C> fieldUpdater) { Column<ContactInfo, C> column = new Column<ContactInfo, C>(cell) { @Override @@ -472,5 +472,6 @@ editableCells.add((AbstractEditableCell<?, ?>) cell); } cellTable.addColumn(column, headerText); + return column; } }
diff --git a/tools/api-checker/config/gwt21_22userApi.conf b/tools/api-checker/config/gwt21_22userApi.conf index 8735494..959caeb 100644 --- a/tools/api-checker/config/gwt21_22userApi.conf +++ b/tools/api-checker/config/gwt21_22userApi.conf
@@ -144,3 +144,8 @@ com.google.gwt.i18n.shared.DirectionEstimator::estimateDirection(Ljava/lang/String;) OVERLOADED_METHOD_CALL com.google.gwt.i18n.shared.FirstStrongDirectionEstimator::estimateDirection(Ljava/lang/String;) OVERLOADED_METHOD_CALL com.google.gwt.i18n.shared.WordCountDirectionEstimator::estimateDirection(Ljava/lang/String;) OVERLOADED_METHOD_CALL + +# Two fields in Column were exposed as protected but should be private. +com.google.gwt.user.cellview.client.Column::cell MISSING +com.google.gwt.user.cellview.client.Column::fieldUpdater MISSING +
diff --git a/user/src/com/google/gwt/user/cellview/client/CellTable.java b/user/src/com/google/gwt/user/cellview/client/CellTable.java index cbf2365..3c2cf31 100644 --- a/user/src/com/google/gwt/user/cellview/client/CellTable.java +++ b/user/src/com/google/gwt/user/cellview/client/CellTable.java
@@ -39,9 +39,12 @@ import com.google.gwt.safehtml.client.SafeHtmlTemplates; import com.google.gwt.safehtml.shared.SafeHtml; import com.google.gwt.safehtml.shared.SafeHtmlBuilder; +import com.google.gwt.safehtml.shared.SafeHtmlUtils; import com.google.gwt.user.cellview.client.HasDataPresenter.LoadingState; import com.google.gwt.user.client.DOM; 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 com.google.gwt.view.client.ProvidesKey; import com.google.gwt.view.client.SelectionModel; @@ -268,22 +271,34 @@ } interface Template extends SafeHtmlTemplates { + @Template("<div style=\"outline:none;\">{0}</div>") + SafeHtml div(SafeHtml contents); + + @Template("<div style=\"outline:none;\" tabindex=\"{0}\">{1}</div>") + SafeHtml divFocusable(int tabIndex, SafeHtml contents); + + @Template("<div style=\"outline:none;\" tabindex=\"{0}\" accessKey=\"{1}\">{2}</div>") + SafeHtml divFocusableWithKey(int tabIndex, char accessKey, SafeHtml contents); + @Template("<div class=\"{0}\"/>") SafeHtml loading(String loading); @Template("<table><tbody>{0}</tbody></table>") SafeHtml tbody(SafeHtml rowHtml); - @Template("<td class=\"{0}\"><div style=\"outline:none;\">{1}</div></td>") + @Template("<td class=\"{0}\">{1}</td>") SafeHtml td(String classes, SafeHtml contents); - @Template("<td class=\"{0}\"><div style=\"outline:none;\" tabindex=\"{1}\">{2}</div></td>") - SafeHtml tdFocusable(String classes, int tabIndex, SafeHtml contents); - - @Template("<td class=\"{0}\"><div style=\"outline:none;\" tabindex=\"{1}\" accessKey=\"{2}\">{3}</div></td>") - SafeHtml tdFocusableWithKey(String classes, int tabIndex, char accessKey, + @Template("<td class=\"{0}\" align=\"{1}\" valign=\"{2}\">{3}</td>") + SafeHtml tdBothAlign(String classes, String hAlign, String vAlign, SafeHtml contents); + @Template("<td class=\"{0}\" align=\"{1}\">{2}</td>") + SafeHtml tdHorizontalAlign(String classes, String hAlign, SafeHtml contents); + + @Template("<td class=\"{0}\" valign=\"{1}\">{2}</td>") + SafeHtml tdVerticalAlign(String classes, String vAlign, SafeHtml contents); + @Template("<table><tfoot>{0}</tfoot></table>") SafeHtml tfoot(SafeHtml rowHtml); @@ -522,7 +537,7 @@ /** * Constructs a table with the given page size, the specified * {@link Resources}, and the given key provider. - * + * * @param pageSize the page size * @param resources the resources to use for this widget * @param keyProvider an instance of ProvidesKey<T>, or null if the record @@ -545,7 +560,13 @@ colgroup = Document.get().createColGroupElement(); table.appendChild(colgroup); thead = table.createTHead(); - table.appendChild(tbody = Document.get().createTBodyElement()); + // Some browsers create a tbody automatically, others do not. + if (table.getTBodies().getLength() > 0) { + tbody = table.getTBodies().getItem(0); + } else { + tbody = Document.get().createTBodyElement(); + table.appendChild(tbody); + } table.appendChild(tbodyLoading = Document.get().createTBodyElement()); tfoot = table.createTFoot(); setStyleName(this.style.cellTableWidget()); @@ -1048,6 +1069,8 @@ column.render(value, keyProvider, cellBuilder); } + // Build the contents. + SafeHtml contents = SafeHtmlUtils.EMPTY_SAFE_HTML; if (i == keyboardSelectedRow && curColumn == keyboardSelectedColumn) { // This is the focused cell. if (isFocused) { @@ -1055,14 +1078,31 @@ } char accessKey = getAccessKey(); if (accessKey != 0) { - trBuilder.append(template.tdFocusableWithKey(tdClasses, - getTabIndex(), accessKey, cellBuilder.toSafeHtml())); + contents = template.divFocusableWithKey(getTabIndex(), accessKey, + cellBuilder.toSafeHtml()); } else { - trBuilder.append(template.tdFocusable(tdClasses, getTabIndex(), - cellBuilder.toSafeHtml())); + contents = template.divFocusable(getTabIndex(), + cellBuilder.toSafeHtml()); } } else { - trBuilder.append(template.td(tdClasses, cellBuilder.toSafeHtml())); + contents = template.div(cellBuilder.toSafeHtml()); + } + + // Build the cell. + HorizontalAlignmentConstant hAlign = column.getHorizontalAlignment(); + VerticalAlignmentConstant vAlign = column.getVerticalAlignment(); + if (hAlign != null && vAlign != null) { + trBuilder.append(template.tdBothAlign(tdClasses, + hAlign.getTextAlignString(), vAlign.getVerticalAlignString(), + contents)); + } else if (hAlign != null) { + trBuilder.append(template.tdHorizontalAlign(tdClasses, + hAlign.getTextAlignString(), contents)); + } else if (vAlign != null) { + trBuilder.append(template.tdVerticalAlign(tdClasses, + vAlign.getVerticalAlignString(), contents)); + } else { + trBuilder.append(template.td(tdClasses, contents)); } curColumn++;
diff --git a/user/src/com/google/gwt/user/cellview/client/Column.java b/user/src/com/google/gwt/user/cellview/client/Column.java index 7802303..0ad4215 100644 --- a/user/src/com/google/gwt/user/cellview/client/Column.java +++ b/user/src/com/google/gwt/user/cellview/client/Column.java
@@ -1,12 +1,12 @@ /* * Copyright 2010 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 @@ -22,6 +22,7 @@ import com.google.gwt.dom.client.Element; import com.google.gwt.dom.client.NativeEvent; import com.google.gwt.safehtml.shared.SafeHtmlBuilder; +import com.google.gwt.user.client.ui.HasAlignment; import com.google.gwt.view.client.ProvidesKey; /** @@ -29,25 +30,28 @@ * for each cell on demand. New view data, if needed, is created by the cell's * onBrowserEvent method, stored in the Column, and passed to future calls to * Cell's {@link Cell#onBrowserEvent} and {@link Cell#render} methods. - * + * * @param <T> the row type * @param <C> the column type */ -public abstract class Column<T, C> implements HasCell<T, C> { +public abstract class Column<T, C> implements HasCell<T, C>, HasAlignment { /** * The {@link Cell} responsible for rendering items in the column. */ - protected final Cell<C> cell; + private final Cell<C> cell; /** * The {@link FieldUpdater} used for updating values in the column. */ - protected FieldUpdater<T, C> fieldUpdater; + private FieldUpdater<T, C> fieldUpdater; + + private HorizontalAlignmentConstant hAlign = null; + private VerticalAlignmentConstant vAlign = null; /** * Construct a new Column with a given {@link Cell}. - * + * * @param cell the Cell used by this Column */ public Column(Cell<C> cell) { @@ -73,14 +77,22 @@ return fieldUpdater; } + public HorizontalAlignmentConstant getHorizontalAlignment() { + return hAlign; + } + /** * Returns the column value from within the underlying data object. */ public abstract C getValue(T object); + public VerticalAlignmentConstant getVerticalAlignment() { + return vAlign; + } + /** * Handle a browser event that took place within the column. - * + * * @param elem the parent Element * @param index the current row index of the object * @param object the base object to be updated @@ -91,8 +103,8 @@ public void onBrowserEvent(Element elem, final int index, final T object, NativeEvent event, ProvidesKey<T> keyProvider) { Object key = getKey(object, keyProvider); - ValueUpdater<C> valueUpdater = (fieldUpdater == null) - ? null : new ValueUpdater<C>() { + ValueUpdater<C> valueUpdater = (fieldUpdater == null) ? null + : new ValueUpdater<C>() { public void update(C value) { fieldUpdater.update(index, object, value); } @@ -102,7 +114,7 @@ /** * Render the object into the cell. - * + * * @param object the object to render * @param keyProvider the {@link ProvidesKey} for the object * @param sb the buffer to render into @@ -114,7 +126,7 @@ /** * Set the {@link FieldUpdater} used for updating values in the column. - * + * * @param fieldUpdater the field updater * @see #getFieldUpdater() */ @@ -123,9 +135,32 @@ } /** + * {@inheritDoc} + * + * <p> + * The new horizontal alignment will apply the next time the table is + * rendered. + * </p> + */ + public void setHorizontalAlignment(HorizontalAlignmentConstant align) { + this.hAlign = align; + } + + /** + * {@inheritDoc} + * + * <p> + * The new vertical alignment will apply the next time the table is rendered. + * </p> + */ + public void setVerticalAlignment(VerticalAlignmentConstant align) { + this.vAlign = align; + } + + /** * Get the view key for the object given the {@link ProvidesKey}. If the * {@link ProvidesKey} is null, the object is used as the key. - * + * * @param object the row object * @param keyProvider the {@link ProvidesKey} * @return the key for the object
diff --git a/user/test/com/google/gwt/user/cellview/client/CellTableTest.java b/user/test/com/google/gwt/user/cellview/client/CellTableTest.java index 99a346d..d47d9c4 100644 --- a/user/test/com/google/gwt/user/cellview/client/CellTableTest.java +++ b/user/test/com/google/gwt/user/cellview/client/CellTableTest.java
@@ -24,6 +24,8 @@ import com.google.gwt.safehtml.shared.SafeHtml; import com.google.gwt.user.cellview.client.CellTable.Resources; import com.google.gwt.user.cellview.client.CellTable.Style; +import com.google.gwt.user.client.ui.HasHorizontalAlignment; +import com.google.gwt.user.client.ui.HasVerticalAlignment; import java.util.ArrayList; import java.util.List; @@ -60,7 +62,61 @@ table.getPresenter().flush(); assertEquals(1, replaceValues.size()); } - + + public void testCellAlignment() { + CellTable<String> table = createAbstractHasData(); + Column<String, String> column = new Column<String, String>(new TextCell()) { + @Override + public String getValue(String object) { + return object; + } + }; + table.addColumn(column); + + /* + * No alignment. Some browsers (FF) return a default value when alignment is + * not specified, others (IE/HtmlUnit) return an empty string. + */ + table.setRowData(0, createData(0, 1)); + table.getPresenter().flush(); + TableCellElement td = getBodyElement(table, 0, 2); + String hAlign = td.getAlign(); + String vAlign = td.getVAlign(); + assertTrue("".equals(hAlign) || "left".equals(hAlign)); + assertTrue("".equals(vAlign) || "middle".equals(vAlign)); + + // Horizontal alignment. + column.setHorizontalAlignment(HasHorizontalAlignment.ALIGN_RIGHT); + table.setRowData(0, createData(0, 1)); + table.getPresenter().flush(); + td = getBodyElement(table, 0, 2); + hAlign = td.getAlign(); + vAlign = td.getVAlign(); + assertTrue("right".equals(hAlign)); + assertTrue("".equals(vAlign) || "middle".equals(vAlign)); + + // Vertical alignment. + column.setHorizontalAlignment(null); + column.setVerticalAlignment(HasVerticalAlignment.ALIGN_BOTTOM); + table.setRowData(0, createData(0, 1)); + table.getPresenter().flush(); + td = getBodyElement(table, 0, 2); + hAlign = td.getAlign(); + vAlign = td.getVAlign(); + assertTrue("".equals(hAlign) || "left".equals(hAlign)); + assertTrue("bottom".equals(vAlign)); + + // Horizontal and vertical alignment. + column.setHorizontalAlignment(HasHorizontalAlignment.ALIGN_RIGHT); + table.setRowData(0, createData(0, 1)); + table.getPresenter().flush(); + td = getBodyElement(table, 0, 2); + hAlign = td.getAlign(); + vAlign = td.getVAlign(); + assertTrue("right".equals(hAlign)); + assertTrue("bottom".equals(vAlign)); + } + public void testGetRowElement() { CellTable<String> table = createAbstractHasData(); table.setRowData(0, createData(0, 10)); @@ -200,6 +256,22 @@ } /** + * Get a td element from the table body. + * + * @param table the {@link CellTable} + * @param row the row index + * @param column the column index + * @return the column header + */ + private TableCellElement getBodyElement(CellTable<?> table, int row, + int column) { + TableElement tableElem = table.getElement().cast(); + TableSectionElement tbody = tableElem.getTBodies().getItem(0); + TableRowElement tr = tbody.getRows().getItem(row); + return tr.getCells().getItem(column); + } + + /** * Get the number of column headers in the table. * * @param table the {@link CellTable}