Revision: 9765
Author: [email protected]
Date: Thu Feb 24 13:46:49 2011
Log: Edited wiki page CellBackedWIdgets through web user interface.
http://code.google.com/p/google-web-toolkit/source/detail?r=9765
Modified:
/wiki/CellBackedWIdgets.wiki
=======================================
--- /wiki/CellBackedWIdgets.wiki Thu Feb 24 13:09:51 2011
+++ /wiki/CellBackedWIdgets.wiki Thu Feb 24 13:46:49 2011
@@ -20,12 +20,143 @@
* Offer an identical Cell equivalent of every (most) new widgets
* Shared code between Cell and Widget
-New Widgets in GWT will be backed by a Cell, so users can call upon common
view components for CellTable and the rest of their application. GWT
already provides the {{{CellWidget}} wrapper class that can convert any
Cell into a Widget. More details on this appear toward the end of the
document.
+New Widgets in GWT will be backed by a Cell, so users can call upon common
view components for CellTable and the rest of their application. GWT
already provides the {{{CellWidget}} wrapper class that can convert any
Cell into a Widget. More details on this appear toward the end of the
document, but understand that when we refer to Cells throughout this
document, all Cells will have an equivalent Widget.
+
= Appearance Pattern =
-
-
-= Cell Backed Widgets =
-
+Each Cell will expose an abstract Appearance class that plays two
important roles:
+ # Renders the view as a SafeHtml string.
+ # Updates the view in response to state changes of the widget, such as
by applying styles to elements.
+
+In this way, the Cell becomes the presenter for the Appearance (the
view). Cells will be written such that they do not rely on a specific DOM
structure. For example, in {{{ButtonCell}}} below, the Appearance could be
rendered as a {{{button}}} element or a series of nested divs, but the Cell
would still respond to click events in the same way.
+
+{{{
+public class ButtonCell extends AbstractCell<String> {
+
+ // The appearance of this cell.
+ public abstract static class Appearance {
+
+ // Called when the user hovers the button with the mouse.
+ public void onHover(Context context, Element parent, String value) {}
+
+ // Called when the user pushes the button down.
+ public void onPush(Context context, Element parent, String value) {}
+
+ // Called when the user unhovers the button with the mouse.
+ public void onUnhover(Context context, Element parent, String value) {}
+
+ // Called when the user releases the button from being pushed.
+ public void onUnpush(Context context, Element parent, String value) {}
+
+ // Render the DOM structure of the cell.
+ public abstract void render(Context context, SafeHtml data,
SafeHtmlBuilder sb);
+ }
+
+ // The default implementation of the appearance.
+ public static class DefaultAppearance extends Appearance {
+
+ public static interface Resources extends ClientBundle {
+ @Source(Style.DEFAULT_CSS)
+ Style buttonCellStyle();
+ }
+
+ @ImportedWithPrefix("gwt-ButtonCell")
+ public interface Style extends CssResource {
+ String DEFAULT_CSS = "com/google/gwt/cell/client/ButtonCell.css";
+
+ String hover();
+
+ String push();
+ }
+
+ private final Resources resources;
+
+ public DefaultAppearance() {
+ this(GWT.create(Resources.class));
+ }
+
+ public DefaultAppearance(Resources resources) {
+ this.resources = resources;
+ resources.buttonCellStyle().ensureInjected();
+ }
+
+ @Override
+ public void onHover(Context context, Element parent, String value) {
+ addClassName(parent, resources.buttonCellStyle().hover());
+ }
+
+ @Override
+ public void onPush(Context context, Element parent, String value) {
+ addClassName(parent, resources.buttonCellStyle().push());
+ }
+
+ @Override
+ public void onUnhover(Context context, Element parent, String value) {
+ removeClassName(parent, resources.buttonCellStyle().hover());
+ }
+
+ @Override
+ public void onUnpush(Context context, Element parent, String value) {
+ removeClassName(parent, resources.buttonCellStyle().push());
+ }
+
+ @Override
+ public void render(Context context, SafeHtml data, SafeHtmlBuilder sb)
{
+ sb.appendHtmlConstant("<button type=\"button\" tabindex=\"-1\">");
+ if (data != null) {
+ sb.append(data);
+ }
+ sb.appendHtmlConstant("</button>");
+ }
+
+ protected void addClassName(Element parent, String styleName) {
+ parent.getFirstChildElement().addClassName(styleName);
+ }
+
+ protected void removeClassName(Element parent, String styleName) {
+ parent.getFirstChildElement().removeClassName(styleName);
+ }
+ }
+
+ private final Appearance appearance;
+
+ // Use the default look and feel of the Cell.
+ public ButtonCell() {
+ this(GWT.create(Appearance.class));
+ }
+
+ // Replace the styles used by this cell instance.
+ public ButtonCell(DefaultAppearance.Resources resources) {
+ this(new DefaultAppearance(resources));
+ }
+
+ // Replace the appearance used by this cell instance.
+ public ButtonCell(Appearance appearance) {
+ this.appearance = appearance;
+ }
+
+ ...
+}
+}}}
+
+First, notice that the Appearance class does not provide any view
implementations, and thus the Cell does not make any assumptions about the
structure of the Appearance. Even the Resources and Styles live in the
default implementation of the appearance, instead of in the Cell itself.
In the DefaultAppearence, we update state by simply applying a class name
to the outer {{{button}}} element. A more complex Appearance may apply
class names not just to the outer element, but to inner elements as well.
+
+Now take a look at the constructors for ButtonCell. The default
constructor calls {{{GWT.create(Appearance.class)}}}, which is bound to the
DefaultAppearance. However, users can use the third constructor to provide
a specific appearance for this instance of the Cell. Alternatively, the
second constructor (which is just there for convenience) takes a
{{{DefaultAppearance.Resources}}}, which allows users to replace just the
styles of the DefaultAppearance.
+
+As mentioned, we call {{{GWT.create(Appearance.class)}}} by default. The
DefaultAppearance is bound in a gwt.xml file:
+{{{
+ <!-- Bind the default ButtonCell.Appearance. -->
+ <replace-with
class="com.google.gwt.cell.client.ButtonCell.DefaultAppearance">
+ <when-type-is
class="com.google.gwt.cell.client.ButtonCell.Appearance"/>
+ </replace-with>
+}}}
+
+By overriding the deferred binding rule, a user can reskin a Cell for an
entire application. Alternatively, third party libraries can provide skins
for multiple widgets, which would be applied by inheriting a single Module
containing a bunch of deferred binding overrides.
+
+Finally, note that Appearance is an abstract class. This allows us to add
more state logic in the future without breaking existing Appearances. For
example, we could add new methods "setRightFlush()" and "setLeftFlush()"
which would make the right and left edges of the button flat, such that
they could be lined up next to each other. Existing appearances may not
support the new feature, but they would still work.
+
+
+
+= Cell Backed Widgets =
--
http://groups.google.com/group/Google-Web-Toolkit-Contributors