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}