- Adds UiBinder parsers for DockLayoutPanel and StackLayoutPanel.
- Changes DockLayoutPanel interface to be more direct
(e.g., addNorth(w) rather than add(w, NORTH)).
- Changes Mail sample to use UiBinder throughout.
Review: http://gwt-code-reviews.appspot.com/68805
git-svn-id: https://google-web-toolkit.googlecode.com/svn/trunk@6192 8db76d5a-ed1c-0410-87a9-c151d255dfc7
diff --git a/samples/mail/src/com/google/gwt/sample/mail/Mail.gwt.xml b/samples/mail/src/com/google/gwt/sample/mail/Mail.gwt.xml
index 6cca2a8..9225cee 100644
--- a/samples/mail/src/com/google/gwt/sample/mail/Mail.gwt.xml
+++ b/samples/mail/src/com/google/gwt/sample/mail/Mail.gwt.xml
@@ -14,5 +14,6 @@
<module rename-to="mail">
<inherits name='com.google.gwt.user.User'/>
+ <inherits name="com.google.gwt.uibinder.UiBinder" />
<entry-point class='com.google.gwt.sample.mail.client.Mail'/>
</module>
diff --git a/samples/mail/src/com/google/gwt/sample/mail/client/AboutDialog.java b/samples/mail/src/com/google/gwt/sample/mail/client/AboutDialog.java
index f371ee0..12d1e62 100644
--- a/samples/mail/src/com/google/gwt/sample/mail/client/AboutDialog.java
+++ b/samples/mail/src/com/google/gwt/sample/mail/client/AboutDialog.java
@@ -15,57 +15,53 @@
*/
package com.google.gwt.sample.mail.client;
+import com.google.gwt.core.client.GWT;
+import com.google.gwt.dom.client.NativeEvent;
import com.google.gwt.event.dom.client.ClickEvent;
-import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.event.dom.client.KeyCodes;
+import com.google.gwt.uibinder.client.UiBinder;
+import com.google.gwt.uibinder.client.UiField;
+import com.google.gwt.uibinder.client.UiHandler;
+import com.google.gwt.user.client.Event.NativePreviewEvent;
import com.google.gwt.user.client.ui.Button;
import com.google.gwt.user.client.ui.DialogBox;
-import com.google.gwt.user.client.ui.HTML;
-import com.google.gwt.user.client.ui.VerticalPanel;
+import com.google.gwt.user.client.ui.Widget;
/**
* A simple example of an 'about' dialog box.
*/
public class AboutDialog extends DialogBox {
+ interface Binder extends UiBinder<Widget, AboutDialog> { }
+ private static final Binder binder = GWT.create(Binder.class);
+
+ @UiField Button closeButton;
+
public AboutDialog() {
// Use this opportunity to set the dialog's caption.
setText("About the Mail Sample");
-
- // Create a VerticalPanel to contain the 'about' label and the 'OK' button.
- VerticalPanel outer = new VerticalPanel();
-
- // Create the 'about' text and set a style name so we can style it with CSS.
-
- HTML text = new HTML("This sample application demonstrates the "
- + "construction of a complex user interface using GWT's built-in "
- + "widgets. Have a look at the code to see how easy it is to build "
- + "your own apps!");
- text.setStyleName("mail-AboutText");
- outer.add(text);
-
- // Create the 'OK' button, along with a handler that hides the dialog
- // when the button is clicked.
- outer.add(new Button("Close", new ClickHandler() {
- public void onClick(ClickEvent event) {
- hide();
- }
- }));
-
- setWidget(outer);
+ setWidget(binder.createAndBindUi(this));
}
@Override
- public boolean onKeyDownPreview(char key, int modifiers) {
- // Use the popup's key preview hooks to close the dialog when either
- // enter or escape is pressed.
- switch (key) {
- case KeyCodes.KEY_ENTER:
- case KeyCodes.KEY_ESCAPE:
- hide();
- break;
- }
+ protected void onPreviewNativeEvent(NativePreviewEvent preview) {
+ super.onPreviewNativeEvent(preview);
- return true;
+ NativeEvent evt = preview.getNativeEvent();
+ if (evt.getType().equals("keydown")) {
+ // Use the popup's key preview hooks to close the dialog when either
+ // enter or escape is pressed.
+ switch (evt.getKeyCode()) {
+ case KeyCodes.KEY_ENTER:
+ case KeyCodes.KEY_ESCAPE:
+ hide();
+ break;
+ }
+ }
+ }
+
+ @UiHandler("closeButton")
+ void onSignOutClicked(ClickEvent event) {
+ hide();
}
}
diff --git a/samples/mail/src/com/google/gwt/sample/mail/client/AboutDialog.ui.xml b/samples/mail/src/com/google/gwt/sample/mail/client/AboutDialog.ui.xml
new file mode 100644
index 0000000..3aa9afc
--- /dev/null
+++ b/samples/mail/src/com/google/gwt/sample/mail/client/AboutDialog.ui.xml
@@ -0,0 +1,27 @@
+<ui:UiBinder xmlns:ui='urn:ui:com.google.gwt.uibinder'
+ xmlns:g='urn:import:com.google.gwt.user.client.ui'
+ xmlns:mail='urn:import:com.google.gwt.sample.mail.client'>
+
+ <ui:style>
+ .aboutText {
+ width: 24em;
+ padding: 10px;
+ text-align: left;
+ }
+ </ui:style>
+
+ <g:DockPanel>
+ <g:Dock direction='SOUTH'>
+ <g:Button text='Close' ui:field='closeButton' />
+ </g:Dock>
+ <g:Dock direction='CENTER'>
+ <g:HTML styleName='{style.aboutText}'>
+ This sample application demonstrates the
+ construction of a complex user interface using GWT's built-in
+ widgets. Have a look at the code to see how easy it is to build
+ your own apps!
+ </g:HTML>
+ </g:Dock>
+ </g:DockPanel>
+
+</ui:UiBinder>
diff --git a/samples/mail/src/com/google/gwt/sample/mail/client/ContactPopup.ui.xml b/samples/mail/src/com/google/gwt/sample/mail/client/ContactPopup.ui.xml
new file mode 100644
index 0000000..fc5b2a0
--- /dev/null
+++ b/samples/mail/src/com/google/gwt/sample/mail/client/ContactPopup.ui.xml
@@ -0,0 +1,41 @@
+<ui:UiBinder
+ xmlns:ui='urn:ui:com.google.gwt.uibinder'
+ xmlns:g='urn:import:com.google.gwt.user.client.ui'
+ xmlns:mail='urn:import:com.google.gwt.sample.mail.client'>
+
+ <ui:style>
+ .popup {
+ background: #fff;
+ border: 1px solid #666;
+ padding: 0.5em;
+ width: 14em;
+ height: 2.5em;
+ }
+
+ .photo {
+ float: left;
+ margin-right: 4px;
+
+ background: url(default_photo.jpg);
+ width: 32px;
+ height: 32px;
+ }
+
+ .right {
+ white-space: nowrap;
+ }
+
+ .email {
+ font-style:italic;
+ }
+ </ui:style>
+
+ <g:HTMLPanel styleName='{style.popup}'>
+ <div class='{style.photo}'/>
+ <div class='{style.right}'>
+ <div ui:field='nameDiv' />
+ <div ui:field='emailDiv' class='{style.email}'/>
+ </div>
+ </g:HTMLPanel>
+
+</ui:UiBinder>
diff --git a/samples/mail/src/com/google/gwt/sample/mail/client/Contacts.java b/samples/mail/src/com/google/gwt/sample/mail/client/Contacts.java
index 738b1fb..df69bdf 100644
--- a/samples/mail/src/com/google/gwt/sample/mail/client/Contacts.java
+++ b/samples/mail/src/com/google/gwt/sample/mail/client/Contacts.java
@@ -15,17 +15,18 @@
*/
package com.google.gwt.sample.mail.client;
+import com.google.gwt.core.client.GWT;
+import com.google.gwt.dom.client.Element;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
-import com.google.gwt.user.client.ui.AbstractImagePrototype;
+import com.google.gwt.uibinder.client.UiBinder;
+import com.google.gwt.uibinder.client.UiField;
+import com.google.gwt.uibinder.client.UiTemplate;
+import com.google.gwt.user.client.ui.Anchor;
import com.google.gwt.user.client.ui.Composite;
-import com.google.gwt.user.client.ui.HTML;
-import com.google.gwt.user.client.ui.HorizontalPanel;
-import com.google.gwt.user.client.ui.ImageBundle;
-import com.google.gwt.user.client.ui.Label;
import com.google.gwt.user.client.ui.PopupPanel;
-import com.google.gwt.user.client.ui.SimplePanel;
import com.google.gwt.user.client.ui.VerticalPanel;
+import com.google.gwt.user.client.ui.Widget;
/**
* A component that displays a list of contacts.
@@ -33,14 +34,6 @@
public class Contacts extends Composite {
/**
- * An image bundle for this widget and an example of the use of @Resource.
- */
- public interface Images extends ImageBundle {
- @Resource("default_photo.jpg")
- AbstractImagePrototype defaultPhoto();
- }
-
- /**
* Simple data structure representing a contact.
*/
private static class Contact {
@@ -56,31 +49,28 @@
/**
* A simple popup that displays a contact's information.
*/
- private class ContactPopup extends PopupPanel {
+ static class ContactPopup extends PopupPanel {
+ @UiTemplate("ContactPopup.ui.xml")
+ interface Binder extends UiBinder<Widget, ContactPopup> { }
+ private static final Binder binder = GWT.create(Binder.class);
+
+ @UiField Element nameDiv;
+ @UiField Element emailDiv;
public ContactPopup(Contact contact) {
// The popup's constructor's argument is a boolean specifying that it
// auto-close itself when the user clicks outside of it.
super(true);
+ add(binder.createAndBindUi(this));
- VerticalPanel inner = new VerticalPanel();
- Label nameLabel = new Label(contact.name);
- Label emailLabel = new Label(contact.email);
- inner.add(nameLabel);
- inner.add(emailLabel);
-
- HorizontalPanel hp = new HorizontalPanel();
- hp.setSpacing(4);
- hp.add(images.defaultPhoto().createImage());
- hp.add(inner);
-
- add(hp);
- setStyleName("mail-ContactPopup");
- nameLabel.setStyleName("mail-ContactPopupName");
- emailLabel.setStyleName("mail-ContactPopupEmail");
+ nameDiv.setInnerText(contact.name);
+ emailDiv.setInnerText(contact.email);
}
}
+ interface Binder extends UiBinder<VerticalPanel, Contacts> { }
+ private static final Binder binder = GWT.create(Binder.class);
+
private Contact[] contacts = new Contact[] {
new Contact("Benoit Mandelbrot", "benoit@example.com"),
new Contact("Albert Einstein", "albert@example.com"),
@@ -91,26 +81,19 @@
new Contact("Alan Turing", "alan@example.com"),
new Contact("John von Neumann", "john@example.com")};
- private VerticalPanel panel = new VerticalPanel();
- private final Images images;
+ private VerticalPanel panel;
- public Contacts(Images images) {
- SimplePanel outer = new SimplePanel();
- outer.setWidget(panel);
+ public Contacts() {
+ initWidget(panel = binder.createAndBindUi(this));
- this.images = images;
// Add all the contacts to the list.
for (int i = 0; i < contacts.length; ++i) {
addContact(contacts[i]);
}
-
- initWidget(outer);
- setStyleName("mail-Contacts");
}
private void addContact(final Contact contact) {
- final HTML link = new HTML("<a href='javascript:;'>" + contact.name
- + "</a>");
+ final Anchor link = new Anchor(contact.name);
panel.add(link);
// Add a click handler that displays a ContactPopup when it is clicked.
diff --git a/samples/mail/src/com/google/gwt/sample/mail/client/Contacts.ui.xml b/samples/mail/src/com/google/gwt/sample/mail/client/Contacts.ui.xml
new file mode 100644
index 0000000..5349613
--- /dev/null
+++ b/samples/mail/src/com/google/gwt/sample/mail/client/Contacts.ui.xml
@@ -0,0 +1,13 @@
+<ui:UiBinder
+ xmlns:ui='urn:ui:com.google.gwt.uibinder'
+ xmlns:g='urn:import:com.google.gwt.user.client.ui'
+ xmlns:mail='urn:import:com.google.gwt.sample.mail.client'>
+
+ <ui:style>
+ .contacts {
+ padding: 0.5em;
+ }
+ </ui:style>
+
+ <g:VerticalPanel styleName='{style.contacts}'/>
+</ui:UiBinder>
diff --git a/samples/mail/src/com/google/gwt/sample/mail/client/Mail.java b/samples/mail/src/com/google/gwt/sample/mail/client/Mail.java
index 1b7f652..a639a12 100644
--- a/samples/mail/src/com/google/gwt/sample/mail/client/Mail.java
+++ b/samples/mail/src/com/google/gwt/sample/mail/client/Mail.java
@@ -17,128 +17,58 @@
import com.google.gwt.core.client.EntryPoint;
import com.google.gwt.core.client.GWT;
-import com.google.gwt.event.logical.shared.ResizeEvent;
-import com.google.gwt.event.logical.shared.ResizeHandler;
-import com.google.gwt.user.client.Command;
-import com.google.gwt.user.client.DeferredCommand;
+import com.google.gwt.dom.client.Element;
+import com.google.gwt.dom.client.Style.Overflow;
+import com.google.gwt.uibinder.client.UiBinder;
+import com.google.gwt.uibinder.client.UiField;
import com.google.gwt.user.client.Window;
-import com.google.gwt.user.client.ui.DockPanel;
-import com.google.gwt.user.client.ui.RootPanel;
-import com.google.gwt.user.client.ui.VerticalPanel;
+import com.google.gwt.user.client.ui.DockLayoutPanel;
+import com.google.gwt.user.client.ui.RootLayoutPanel;
/**
* This application demonstrates how to construct a relatively complex user
* interface, similar to many common email readers. It has no back-end,
* populating its components with hard-coded data.
*/
-public class Mail implements EntryPoint, ResizeHandler {
+public class Mail implements EntryPoint {
- private static Mail singleton;
+ interface Binder extends UiBinder<DockLayoutPanel, Mail> { }
+ private static final Binder binder = GWT.create(Binder.class);
- /**
- * Instantiate an application-level image bundle. This object will provide
- * programmatic access to all the images needed by widgets.
- */
- private static final Images images = GWT.create(Images.class);
-
- /**
- * An aggregate image bundle that pulls together all the images for this
- * application into a single bundle.
- */
- public interface Images extends Shortcuts.Images, TopPanel.Images {
- }
-
- /**
- * Gets the singleton Mail instance.
- */
- public static Mail get() {
- return singleton;
- }
-
- private TopPanel topPanel = new TopPanel(images);
- private VerticalPanel rightPanel = new VerticalPanel();
- private MailList mailList;
- private MailDetail mailDetail = new MailDetail();
- private Shortcuts shortcuts = new Shortcuts(images);
-
- /**
- * Displays the specified item.
- *
- * @param item
- */
- public void displayItem(MailItem item) {
- mailDetail.setItem(item);
- }
+ @UiField TopPanel topPanel;
+ @UiField MailList mailList;
+ @UiField MailDetail mailDetail;
+ @UiField Shortcuts shortcuts;
/**
* This method constructs the application user interface by instantiating
* controls and hooking up event handler.
*/
public void onModuleLoad() {
- singleton = this;
-
- topPanel.setWidth("100%");
-
- // MailList uses Mail.get() in its constructor, so initialize it after
- // 'singleton'.
- mailList = new MailList();
- mailList.setWidth("100%");
-
- // Create the right panel, containing the email list & details.
- rightPanel.add(mailList);
- rightPanel.add(mailDetail);
- mailList.setWidth("100%");
- mailDetail.setWidth("100%");
-
- // Create a dock panel that will contain the menu bar at the top,
- // the shortcuts to the left, and the mail list & details taking the rest.
- DockPanel outer = new DockPanel();
- outer.add(topPanel, DockPanel.NORTH);
- outer.add(shortcuts, DockPanel.WEST);
- outer.add(rightPanel, DockPanel.CENTER);
- outer.setWidth("100%");
-
- outer.setSpacing(4);
- outer.setCellWidth(rightPanel, "100%");
-
- // Hook the window resize event, so that we can adjust the UI.
- Window.addResizeHandler(this);
+ DockLayoutPanel outer = binder.createAndBindUi(this);
// Get rid of scrollbars, and clear out the window's built-in margin,
// because we want to take advantage of the entire client area.
Window.enableScrolling(false);
Window.setMargin("0px");
- // Finally, add the outer panel to the RootPanel, so that it will be
- // displayed.
- RootPanel.get().add(outer);
+ // Special-case stuff to make topPanel overhang a bit.
+ Element topElem = outer.getContainerElementFor(topPanel);
+ topElem.getStyle().setZIndex(2);
+ topElem.getStyle().setOverflow(Overflow.VISIBLE);
- // Call the window resized handler to get the initial sizes setup. Doing
- // this in a deferred command causes it to occur after all widgets' sizes
- // have been computed by the browser.
- DeferredCommand.addCommand(new Command() {
- public void execute() {
- onWindowResized(Window.getClientWidth(), Window.getClientHeight());
+ // Listen for item selection, displaying the currently-selected item in
+ // the detail area.
+ mailList.setListener(new MailList.Listener() {
+ public void onItemSelected(MailItem item) {
+ mailDetail.setItem(item);
}
});
- onWindowResized(Window.getClientWidth(), Window.getClientHeight());
- }
-
- public void onResize(ResizeEvent event) {
- onWindowResized(event.getWidth(), event.getHeight());
- }
-
- public void onWindowResized(int width, int height) {
- // Adjust the shortcut panel and detail area to take up the available room
- // in the window.
- int shortcutHeight = height - shortcuts.getAbsoluteTop() - 8;
- if (shortcutHeight < 1) {
- shortcutHeight = 1;
- }
- shortcuts.setHeight(shortcutHeight + "px");
-
- // Give the mail detail widget a chance to resize itself as well.
- mailDetail.adjustSize(width, height);
+ // Add the outer panel to the RootLayoutPanel, so that it will be
+ // displayed.
+ RootLayoutPanel root = RootLayoutPanel.get();
+ root.add(outer);
+ root.layout();
}
}
diff --git a/samples/mail/src/com/google/gwt/sample/mail/client/Mail.ui.xml b/samples/mail/src/com/google/gwt/sample/mail/client/Mail.ui.xml
new file mode 100644
index 0000000..08abf6f
--- /dev/null
+++ b/samples/mail/src/com/google/gwt/sample/mail/client/Mail.ui.xml
@@ -0,0 +1,28 @@
+<ui:UiBinder
+ xmlns:ui='urn:ui:com.google.gwt.uibinder'
+ xmlns:g='urn:import:com.google.gwt.user.client.ui'
+ xmlns:mail='urn:import:com.google.gwt.sample.mail.client'>
+
+ <g:DockLayoutPanel unit='EM'>
+ <g:north size='5'>
+ <mail:TopPanel ui:field='topPanel' />
+ </g:north>
+
+ <g:center>
+ <g:SplitLayoutPanel>
+ <g:west size='192'>
+ <mail:Shortcuts ui:field='shortcuts' />
+ </g:west>
+
+ <g:north size='200'>
+ <mail:MailList ui:field='mailList' />
+ </g:north>
+
+ <g:center>
+ <mail:MailDetail ui:field='mailDetail' />
+ </g:center>
+ </g:SplitLayoutPanel>
+ </g:center>
+ </g:DockLayoutPanel>
+
+</ui:UiBinder>
diff --git a/samples/mail/src/com/google/gwt/sample/mail/client/MailDetail.java b/samples/mail/src/com/google/gwt/sample/mail/client/MailDetail.java
index 42901ba..b8697ec 100644
--- a/samples/mail/src/com/google/gwt/sample/mail/client/MailDetail.java
+++ b/samples/mail/src/com/google/gwt/sample/mail/client/MailDetail.java
@@ -15,74 +15,39 @@
*/
package com.google.gwt.sample.mail.client;
-import com.google.gwt.user.client.ui.Composite;
-import com.google.gwt.user.client.ui.DockPanel;
+import com.google.gwt.core.client.GWT;
+import com.google.gwt.dom.client.Element;
+import com.google.gwt.uibinder.client.UiBinder;
+import com.google.gwt.uibinder.client.UiField;
import com.google.gwt.user.client.ui.HTML;
-import com.google.gwt.user.client.ui.ScrollPanel;
-import com.google.gwt.user.client.ui.VerticalPanel;
+import com.google.gwt.user.client.ui.LayoutComposite;
+import com.google.gwt.user.client.ui.Widget;
/**
* A composite for displaying the details of an email message.
*/
-public class MailDetail extends Composite {
+public class MailDetail extends LayoutComposite {
- private VerticalPanel panel = new VerticalPanel();
- private VerticalPanel headerPanel = new VerticalPanel();
- private HTML subject = new HTML();
- private HTML sender = new HTML();
- private HTML recipient = new HTML();
- private HTML body = new HTML();
- private ScrollPanel scroller = new ScrollPanel(body);
+ interface Binder extends UiBinder<Widget, MailDetail> { }
+ private static final Binder binder = GWT.create(Binder.class);
+
+ @UiField Element subject;
+ @UiField Element sender;
+ @UiField Element recipient;
+ @UiField HTML body;
public MailDetail() {
- body.setWordWrap(true);
-
- headerPanel.add(subject);
- headerPanel.add(sender);
- headerPanel.add(recipient);
- headerPanel.setWidth("100%");
-
- DockPanel innerPanel = new DockPanel();
- innerPanel.add(headerPanel, DockPanel.NORTH);
- innerPanel.add(scroller, DockPanel.CENTER);
-
- innerPanel.setCellHeight(scroller, "100%");
- panel.add(innerPanel);
- innerPanel.setSize("100%", "100%");
- scroller.setSize("100%", "100%");
- initWidget(panel);
-
- setStyleName("mail-Detail");
- headerPanel.setStyleName("mail-DetailHeader");
- innerPanel.setStyleName("mail-DetailInner");
- subject.setStyleName("mail-DetailSubject");
- sender.setStyleName("mail-DetailSender");
- recipient.setStyleName("mail-DetailRecipient");
- body.setStyleName("mail-DetailBody");
- }
-
- /**
- * Adjusts the widget's size such that it fits within the window's client
- * area.
- */
- public void adjustSize(int windowWidth, int windowHeight) {
- int scrollWidth = windowWidth - scroller.getAbsoluteLeft() - 9;
- if (scrollWidth < 1) {
- scrollWidth = 1;
- }
-
- int scrollHeight = windowHeight - scroller.getAbsoluteTop() - 9;
- if (scrollHeight < 1) {
- scrollHeight = 1;
- }
-
- scroller.setPixelSize(scrollWidth, scrollHeight);
+ initWidget(binder.createAndBindUi(this));
}
public void setItem(MailItem item) {
- subject.setHTML(item.subject);
- sender.setHTML("<b>From:</b> " + item.sender);
- recipient.setHTML("<b>To:</b> foo@example.com");
+ subject.setInnerText(item.subject);
+ sender.setInnerText(item.sender);
+ recipient.setInnerHTML("foo@example.com");
+
+ // WARNING: For the purposes of this demo, we're using HTML directly, on
+ // the assumption that the "server" would have appropriately scrubbed the
+ // HTML. Failure to do so would open your application to XSS attacks.
body.setHTML(item.body);
}
}
diff --git a/samples/mail/src/com/google/gwt/sample/mail/client/MailDetail.ui.xml b/samples/mail/src/com/google/gwt/sample/mail/client/MailDetail.ui.xml
new file mode 100644
index 0000000..d5872ff
--- /dev/null
+++ b/samples/mail/src/com/google/gwt/sample/mail/client/MailDetail.ui.xml
@@ -0,0 +1,44 @@
+<ui:UiBinder xmlns:ui='urn:ui:com.google.gwt.uibinder'
+ xmlns:g='urn:import:com.google.gwt.user.client.ui'
+ xmlns:mail='urn:import:com.google.gwt.sample.mail.client'>
+
+ <ui:style>
+ .detail {
+ border: 1px solid #666;
+ background-color: white;
+ }
+
+ .header {
+ background: #eee;
+ border-bottom: 1px solid #666;
+ padding: 0.5em;
+ }
+
+ .headerItem {
+ margin-bottom:0.5em;
+ }
+
+ .body {
+ line-height: 150%;
+ padding: 20px 40px 20px 10px;
+ font-family: 'Times New Roman', Times, serif;
+ }
+ </ui:style>
+
+ <g:DockLayoutPanel unit='EM' styleName='{style.detail}'>
+ <g:north size='6'>
+ <g:HTMLPanel styleName='{style.header}'>
+ <div class='{style.headerItem}' ui:field='subject'/>
+ <div class='{style.headerItem}'><b>From:</b> <span ui:field='sender'/></div>
+ <div class='{style.headerItem}'><b>To:</b> <span ui:field='recipient'/></div>
+ </g:HTMLPanel>
+ </g:north>
+
+ <g:center>
+ <g:ScrollPanel>
+ <g:HTML styleName='{style.body}' ui:field='body' wordWrap='true'/>
+ </g:ScrollPanel>
+ </g:center>
+ </g:DockLayoutPanel>
+
+</ui:UiBinder>
diff --git a/samples/mail/src/com/google/gwt/sample/mail/client/MailItems.java b/samples/mail/src/com/google/gwt/sample/mail/client/MailItems.java
index d36b789..3b4828c 100644
--- a/samples/mail/src/com/google/gwt/sample/mail/client/MailItems.java
+++ b/samples/mail/src/com/google/gwt/sample/mail/client/MailItems.java
@@ -22,7 +22,7 @@
*/
public class MailItems {
- private static final int NUM_ITEMS = 37;
+ private static final int NUM_ITEMS = 64;
private static final int FRAGMENTS_PER_EMAIL = 10;
private static final String[] senders = new String[] {
diff --git a/samples/mail/src/com/google/gwt/sample/mail/client/MailList.java b/samples/mail/src/com/google/gwt/sample/mail/client/MailList.java
index 43fa86a..f6345a0 100644
--- a/samples/mail/src/com/google/gwt/sample/mail/client/MailList.java
+++ b/samples/mail/src/com/google/gwt/sample/mail/client/MailList.java
@@ -15,20 +15,29 @@
*/
package com.google.gwt.sample.mail.client;
+import com.google.gwt.dom.client.Style.Unit;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
-import com.google.gwt.user.client.ui.Composite;
+import com.google.gwt.user.client.ui.DockLayoutPanel;
import com.google.gwt.user.client.ui.FlexTable;
import com.google.gwt.user.client.ui.HTML;
import com.google.gwt.user.client.ui.HorizontalPanel;
+import com.google.gwt.user.client.ui.LayoutComposite;
+import com.google.gwt.user.client.ui.ScrollPanel;
import com.google.gwt.user.client.ui.HTMLTable.Cell;
/**
* A composite that displays a list of emails that can be selected.
*/
-public class MailList extends Composite implements ClickHandler {
+public class MailList extends LayoutComposite implements ClickHandler {
- private static final int VISIBLE_EMAIL_COUNT = 10;
+ private static final int VISIBLE_EMAIL_COUNT = 20;
+
+ public interface Listener {
+ void onItemSelected(MailItem item);
+ }
+
+ private Listener listener;
private HTML countLabel = new HTML();
private HTML newerButton = new HTML("<a href='javascript:;'>< newer</a>",
@@ -36,6 +45,7 @@
private HTML olderButton = new HTML("<a href='javascript:;'>older ></a>",
true);
private int startIndex, selectedRow = -1;
+ private FlexTable header = new FlexTable();
private FlexTable table = new FlexTable();
private HorizontalPanel navBar = new HorizontalPanel();
@@ -61,7 +71,13 @@
navBar.add(innerNavBar);
navBar.setWidth("100%");
- initWidget(table);
+ DockLayoutPanel dock = new DockLayoutPanel(Unit.EM);
+ dock.addNorth(header, 2);
+ dock.add(new ScrollPanel(table));
+ header.setWidth("100%");
+ table.setWidth("100%");
+ dock.layout();
+ initWidget(dock);
setStyleName("mail-List");
initTable();
@@ -95,34 +111,60 @@
Cell cell = table.getCellForEvent(event);
if (cell != null) {
int row = cell.getRowIndex();
- if (row > 0) {
- selectRow(row - 1);
- }
+ selectRow(row);
}
}
}
/**
+ * Sets the listener that will be notified when an item is selected.
+ */
+ public void setListener(Listener listener) {
+ this.listener = listener;
+ }
+
+ @Override
+ protected void onLoad() {
+ // Select the first row if none is selected.
+ if (selectedRow == -1) {
+ selectRow(0);
+ }
+ }
+
+ /**
* Initializes the table so that it contains enough rows for a full page of
* emails. Also creates the images that will be used as 'read' flags.
*/
private void initTable() {
- // Create the header row.
- table.setText(0, 0, "Sender");
- table.setText(0, 1, "Email");
- table.setText(0, 2, "Subject");
- table.setWidget(0, 3, navBar);
- table.getRowFormatter().setStyleName(0, "mail-ListHeader");
+ // Create the header.
+ header.getRowFormatter().setStyleName(0, "mail-ListHeader");
+ header.getElement().getStyle().setProperty("tableLayout", "fixed");
+ header.setCellSpacing(0);
- // Initialize the rest of the rows.
+ header.getColumnFormatter().setWidth(0, "96px");
+ header.getColumnFormatter().setWidth(1, "160px");
+ header.getColumnFormatter().setWidth(3, "256px");
+
+ header.setText(0, 0, "Sender");
+ header.setText(0, 1, "Email");
+ header.setText(0, 2, "Subject");
+ header.setWidget(0, 3, navBar);
+
+ // Initialize the table.
+ table.getElement().getStyle().setProperty("tableLayout", "fixed");
+ header.setCellSpacing(0);
+
+ table.getColumnFormatter().setWidth(0, "96px");
+ table.getColumnFormatter().setWidth(1, "160px");
+
for (int i = 0; i < VISIBLE_EMAIL_COUNT; ++i) {
- table.setText(i + 1, 0, "");
- table.setText(i + 1, 1, "");
- table.setText(i + 1, 2, "");
- table.getCellFormatter().setWordWrap(i + 1, 0, false);
- table.getCellFormatter().setWordWrap(i + 1, 1, false);
- table.getCellFormatter().setWordWrap(i + 1, 2, false);
- table.getFlexCellFormatter().setColSpan(i + 1, 2, 2);
+ table.setText(i, 0, "");
+ table.setText(i, 1, "");
+ table.setText(i, 2, "");
+ table.getCellFormatter().setWordWrap(i, 0, false);
+ table.getCellFormatter().setWordWrap(i, 1, false);
+ table.getCellFormatter().setWordWrap(i, 2, false);
+ table.getFlexCellFormatter().setColSpan(i, 2, 2);
}
}
@@ -144,15 +186,18 @@
item.read = true;
selectedRow = row;
- Mail.get().displayItem(item);
+
+ if (listener != null) {
+ listener.onItemSelected(item);
+ }
}
private void styleRow(int row, boolean selected) {
if (row != -1) {
if (selected) {
- table.getRowFormatter().addStyleName(row + 1, "mail-SelectedRow");
+ table.getRowFormatter().addStyleName(row, "mail-SelectedRow");
} else {
- table.getRowFormatter().removeStyleName(row + 1, "mail-SelectedRow");
+ table.getRowFormatter().removeStyleName(row, "mail-SelectedRow");
}
}
}
@@ -181,21 +226,16 @@
// Add a new row to the table, then set each of its columns to the
// email's sender and subject values.
- table.setText(i + 1, 0, item.sender);
- table.setText(i + 1, 1, item.email);
- table.setText(i + 1, 2, item.subject);
+ table.setText(i, 0, item.sender);
+ table.setText(i, 1, item.email);
+ table.setText(i, 2, item.subject);
}
// Clear any remaining slots.
for (; i < VISIBLE_EMAIL_COUNT; ++i) {
- table.setHTML(i + 1, 0, " ");
- table.setHTML(i + 1, 1, " ");
- table.setHTML(i + 1, 2, " ");
- }
-
- // Select the first row if none is selected.
- if (selectedRow == -1) {
- selectRow(0);
+ table.setHTML(i, 0, " ");
+ table.setHTML(i, 1, " ");
+ table.setHTML(i, 2, " ");
}
}
}
diff --git a/samples/mail/src/com/google/gwt/sample/mail/client/Mailboxes.java b/samples/mail/src/com/google/gwt/sample/mail/client/Mailboxes.java
index f0e852d..27fb3c5 100644
--- a/samples/mail/src/com/google/gwt/sample/mail/client/Mailboxes.java
+++ b/samples/mail/src/com/google/gwt/sample/mail/client/Mailboxes.java
@@ -15,6 +15,7 @@
*/
package com.google.gwt.sample.mail.client;
+import com.google.gwt.core.client.GWT;
import com.google.gwt.user.client.ui.AbstractImagePrototype;
import com.google.gwt.user.client.ui.Composite;
import com.google.gwt.user.client.ui.ImageBundle;
@@ -55,7 +56,9 @@
*
* @param images a bundle that provides the images for this widget
*/
- public Mailboxes(Images images) {
+ public Mailboxes() {
+ Images images = GWT.create(Images.class);
+
tree = new Tree(images);
TreeItem root = new TreeItem(
imageItemHTML(images.home(), "foo@example.com"));
diff --git a/samples/mail/src/com/google/gwt/sample/mail/client/Shortcuts.java b/samples/mail/src/com/google/gwt/sample/mail/client/Shortcuts.java
index c58b71a..28687a1 100644
--- a/samples/mail/src/com/google/gwt/sample/mail/client/Shortcuts.java
+++ b/samples/mail/src/com/google/gwt/sample/mail/client/Shortcuts.java
@@ -15,10 +15,11 @@
*/
package com.google.gwt.sample.mail.client;
-import com.google.gwt.user.client.ui.AbstractImagePrototype;
-import com.google.gwt.user.client.ui.Composite;
-import com.google.gwt.user.client.ui.DecoratedStackPanel;
-import com.google.gwt.user.client.ui.Widget;
+import com.google.gwt.core.client.GWT;
+import com.google.gwt.uibinder.client.UiBinder;
+import com.google.gwt.uibinder.client.UiField;
+import com.google.gwt.user.client.ui.LayoutComposite;
+import com.google.gwt.user.client.ui.StackLayoutPanel;
/**
* A composite that contains the shortcut stack panel on the left side. The
@@ -27,67 +28,29 @@
* {@link com.google.gwt.user.client.ui.StackPanel},
* {@link com.google.gwt.user.client.ui.Tree}, and other custom widgets.
*/
-public class Shortcuts extends Composite {
+public class Shortcuts extends LayoutComposite {
- /**
- * An image bundle specifying the images for this Widget and aggragating
- * images needed in child widgets.
- */
- public interface Images extends Contacts.Images, Mailboxes.Images {
- AbstractImagePrototype contactsgroup();
+ interface Binder extends UiBinder<StackLayoutPanel, Shortcuts> { }
+ private static final Binder binder = GWT.create(Binder.class);
- AbstractImagePrototype mailgroup();
+ private StackLayoutPanel stackPanel;
- AbstractImagePrototype tasksgroup();
- }
-
- private int nextHeaderIndex = 0;
- private DecoratedStackPanel stackPanel = new DecoratedStackPanel();
+ @UiField Mailboxes mailboxes;
+ @UiField Tasks tasks;
+ @UiField Contacts contacts;
/**
* Constructs a new shortcuts widget using the specified images.
*
* @param images a bundle that provides the images for this widget
*/
- public Shortcuts(Images images) {
- // Create the groups within the stack panel.
- add(new Mailboxes(images), images.mailgroup(), "Mail");
- add(new Tasks(), images.tasksgroup(), "Tasks");
- add(new Contacts(images), images.contactsgroup(), "Contacts");
-
- initWidget(stackPanel);
+ public Shortcuts() {
+ initWidget(stackPanel = binder.createAndBindUi(this));
}
@Override
protected void onLoad() {
// Show the mailboxes group by default.
- stackPanel.showStack(0);
- }
-
- private void add(Widget widget, AbstractImagePrototype imageProto,
- String caption) {
- widget.addStyleName("mail-StackContent");
- stackPanel.add(widget, createHeaderHTML(imageProto, caption), true);
- }
-
- /**
- * Creates an HTML fragment that places an image & caption together, for use
- * in a group header.
- *
- * @param imageProto an image prototype for an image
- * @param caption the group caption
- * @return the header HTML fragment
- */
- private String createHeaderHTML(AbstractImagePrototype imageProto,
- String caption) {
- nextHeaderIndex++;
-
- String captionHTML = "<table class='caption' cellpadding='0' cellspacing='0'>"
- + "<tr><td class='lcaption'>"
- + imageProto.getHTML()
- + "</td><td class='rcaption'><b style='white-space:nowrap'>"
- + caption
- + "</b></td></tr></table>";
- return captionHTML;
+ stackPanel.showWidget(mailboxes);
}
}
diff --git a/samples/mail/src/com/google/gwt/sample/mail/client/Shortcuts.ui.xml b/samples/mail/src/com/google/gwt/sample/mail/client/Shortcuts.ui.xml
new file mode 100644
index 0000000..2cfa4eb
--- /dev/null
+++ b/samples/mail/src/com/google/gwt/sample/mail/client/Shortcuts.ui.xml
@@ -0,0 +1,45 @@
+<ui:UiBinder
+ xmlns:ui='urn:ui:com.google.gwt.uibinder'
+ xmlns:g='urn:import:com.google.gwt.user.client.ui'
+ xmlns:mail='urn:import:com.google.gwt.sample.mail.client'>
+
+ <ui:style>
+ .shortcuts {
+ border-left: 1px solid #666;
+ border-right: 1px solid #666;
+ }
+
+ .stackHeader {
+ background: #c1eec8 url(gradient.gif) repeat-x 0px -1px;
+ padding-top: 1em;
+ font-weight: bold;
+ text-align: center;
+ border-top: 1px solid #666;
+ border-bottom: 1px solid #666;
+ }
+ </ui:style>
+
+ <g:StackLayoutPanel styleName='{style.shortcuts}' unit='EM'>
+ <g:stack>
+ <g:header size='4'>
+ <g:Label styleName='{style.stackHeader}'>Mailboxes</g:Label>
+ </g:header>
+ <mail:Mailboxes ui:field='mailboxes'/>
+ </g:stack>
+
+ <g:stack>
+ <g:header size='4'>
+ <g:Label styleName='{style.stackHeader}'>Tasks</g:Label>
+ </g:header>
+ <mail:Tasks ui:field='tasks'/>
+ </g:stack>
+
+ <g:stack>
+ <g:header size='4'>
+ <g:Label styleName='{style.stackHeader}'>Contacts</g:Label>
+ </g:header>
+ <mail:Contacts ui:field='contacts'/>
+ </g:stack>
+ </g:StackLayoutPanel>
+
+</ui:UiBinder>
diff --git a/samples/mail/src/com/google/gwt/sample/mail/client/Tasks.java b/samples/mail/src/com/google/gwt/sample/mail/client/Tasks.java
index b8e79d4..73a4fe7 100644
--- a/samples/mail/src/com/google/gwt/sample/mail/client/Tasks.java
+++ b/samples/mail/src/com/google/gwt/sample/mail/client/Tasks.java
@@ -17,7 +17,6 @@
import com.google.gwt.user.client.ui.CheckBox;
import com.google.gwt.user.client.ui.Composite;
-import com.google.gwt.user.client.ui.SimplePanel;
import com.google.gwt.user.client.ui.VerticalPanel;
/**
@@ -26,17 +25,14 @@
public class Tasks extends Composite {
public Tasks() {
- SimplePanel panel = new SimplePanel();
VerticalPanel list = new VerticalPanel();
- panel.setWidget(list);
list.add(new CheckBox("Get groceries"));
list.add(new CheckBox("Walk the dog"));
list.add(new CheckBox("Start Web 2.0 company"));
list.add(new CheckBox("Write cool app in GWT"));
list.add(new CheckBox("Get funding"));
list.add(new CheckBox("Take a vacation"));
- initWidget(panel);
+ initWidget(list);
setStyleName("mail-Tasks");
}
-
}
diff --git a/samples/mail/src/com/google/gwt/sample/mail/client/TopPanel.java b/samples/mail/src/com/google/gwt/sample/mail/client/TopPanel.java
index 0d6d178..ad5bc84 100644
--- a/samples/mail/src/com/google/gwt/sample/mail/client/TopPanel.java
+++ b/samples/mail/src/com/google/gwt/sample/mail/client/TopPanel.java
@@ -15,71 +15,43 @@
*/
package com.google.gwt.sample.mail.client;
+import com.google.gwt.core.client.GWT;
import com.google.gwt.event.dom.client.ClickEvent;
-import com.google.gwt.event.dom.client.ClickHandler;
+import com.google.gwt.uibinder.client.UiBinder;
+import com.google.gwt.uibinder.client.UiField;
+import com.google.gwt.uibinder.client.UiHandler;
import com.google.gwt.user.client.Window;
-import com.google.gwt.user.client.ui.AbstractImagePrototype;
+import com.google.gwt.user.client.ui.Anchor;
import com.google.gwt.user.client.ui.Composite;
-import com.google.gwt.user.client.ui.HTML;
-import com.google.gwt.user.client.ui.HorizontalPanel;
-import com.google.gwt.user.client.ui.Image;
-import com.google.gwt.user.client.ui.ImageBundle;
-import com.google.gwt.user.client.ui.VerticalPanel;
+import com.google.gwt.user.client.ui.Widget;
/**
* The top panel, which contains the 'welcome' message and various links.
*/
-public class TopPanel extends Composite implements ClickHandler {
+public class TopPanel extends Composite {
- /**
- * An image bundle for this widgets images.
- */
- public interface Images extends ImageBundle {
- AbstractImagePrototype logo();
+ interface Binder extends UiBinder<Widget, TopPanel> { }
+ private static final Binder binder = GWT.create(Binder.class);
+
+ @UiField Anchor signOutLink;
+ @UiField Anchor aboutLink;
+
+ public TopPanel() {
+ initWidget(binder.createAndBindUi(this));
}
- private HTML signOutLink = new HTML("<a href='javascript:;'>Sign Out</a>");
- private HTML aboutLink = new HTML("<a href='javascript:;'>About</a>");
-
- public TopPanel(Images images) {
- HorizontalPanel outer = new HorizontalPanel();
- VerticalPanel inner = new VerticalPanel();
-
- outer.setHorizontalAlignment(HorizontalPanel.ALIGN_RIGHT);
- inner.setHorizontalAlignment(HorizontalPanel.ALIGN_RIGHT);
-
- HorizontalPanel links = new HorizontalPanel();
- links.setSpacing(4);
- links.add(signOutLink);
- links.add(aboutLink);
-
- final Image logo = images.logo().createImage();
- outer.add(logo);
- outer.setCellHorizontalAlignment(logo, HorizontalPanel.ALIGN_LEFT);
-
- outer.add(inner);
- inner.add(new HTML("<b>Welcome back, foo@example.com</b>"));
- inner.add(links);
-
- signOutLink.addClickHandler(this);
- aboutLink.addClickHandler(this);
-
- initWidget(outer);
- setStyleName("mail-TopPanel");
- links.setStyleName("mail-TopPanelLinks");
+ @UiHandler("aboutLink")
+ void onAboutClicked(ClickEvent event) {
+ // When the 'About' item is selected, show the AboutDialog.
+ // Note that showing a dialog box does not block -- execution continues
+ // normally, and the dialog fires an event when it is closed.
+ AboutDialog dlg = new AboutDialog();
+ dlg.show();
+ dlg.center();
}
- public void onClick(ClickEvent event) {
- Object sender = event.getSource();
- if (sender == signOutLink) {
- Window.alert("If this were implemented, you would be signed out now.");
- } else if (sender == aboutLink) {
- // When the 'About' item is selected, show the AboutDialog.
- // Note that showing a dialog box does not block -- execution continues
- // normally, and the dialog fires an event when it is closed.
- AboutDialog dlg = new AboutDialog();
- dlg.show();
- dlg.center();
- }
+ @UiHandler("signOutLink")
+ void onSignOutClicked(ClickEvent event) {
+ Window.alert("If this were implemented, you would be signed out now.");
}
}
diff --git a/samples/mail/src/com/google/gwt/sample/mail/client/TopPanel.ui.xml b/samples/mail/src/com/google/gwt/sample/mail/client/TopPanel.ui.xml
new file mode 100644
index 0000000..1981a59
--- /dev/null
+++ b/samples/mail/src/com/google/gwt/sample/mail/client/TopPanel.ui.xml
@@ -0,0 +1,39 @@
+<ui:UiBinder
+ xmlns:ui='urn:ui:com.google.gwt.uibinder'
+ xmlns:g='urn:import:com.google.gwt.user.client.ui'
+ xmlns:mail='urn:import:com.google.gwt.sample.mail.client'>
+
+ <ui:style>
+ .statusDiv {
+ text-align: right;
+ margin: 1em;
+ }
+
+ .linksDiv {
+ text-align: right;
+ }
+
+ .logo {
+ background: url(logo.png);
+ position: absolute;
+ width: 140px;
+ height: 75px;
+ }
+ </ui:style>
+
+ <g:HTMLPanel>
+ <div class='{style.logo}'/>
+
+ <div class="{style.statusDiv}">
+ <div>
+ <b>Welcome back, foo@example.com</b>
+ </div>
+
+ <div class='{style.linksDiv}'>
+ <g:Anchor href='javascript:;' ui:field='signOutLink'>Sign Out</g:Anchor>
+ <g:Anchor href='javascript:;' ui:field='aboutLink'>About</g:Anchor>
+ </div>
+ </div>
+ </g:HTMLPanel>
+
+</ui:UiBinder>
diff --git a/samples/mail/war/Mail.css b/samples/mail/war/Mail.css
index 2d045a4..023ced9 100644
--- a/samples/mail/war/Mail.css
+++ b/samples/mail/war/Mail.css
@@ -1,11 +1,11 @@
-body, html {
- height: 100%;
+body, table {
+ font-size: small;
}
+
body {
background: #fff;
color: black;
font-family: Helvetica, Arial, sans-serif;
- font-size: small;
margin: 8px;
margin-top: 3px;
}
@@ -24,7 +24,7 @@
.gwt-DialogBox .Caption {
background: url(gradient.gif) repeat-x 0px -1px;
- font-weight: bold;
+ font-weight: normal;
cursor: default;
padding: 5px 10px;
border: 1px solid #666;
@@ -44,26 +44,10 @@
margin: 10px;
}
-.gwt-MenuBar {
- background: #c3d9ff;
- cursor: default;
-}
-
-.gwt-MenuItem {
- font-size: 80%;
- margin: 1px;
- cursor: default;
-}
-
-.gwt-MenuItem-selected {
- background: #e8eef7;
-}
-
.gwt-Tree {
}
.gwt-Tree .gwt-TreeItem {
- font-size: 80%;
padding: 1px 3px 0 3px;
cursor: hand;
cursor: pointer;
@@ -74,142 +58,10 @@
background: #ccc;
}
-.gwt-DecoratedStackPanel {
- width: 15em;
- border-bottom: 1px solid #666;
-}
-.gwt-DecoratedStackPanel .lcaption {
- width: 32px;
- padding: 0 0 4px 5px;
-}
-.gwt-DecoratedStackPanel .rcaption {
- padding: 0 0 4px 5px;
-}
-.gwt-DecoratedStackPanel .gwt-StackPanelContent {
- border: 1px solid #666;
- border-bottom: 0px;
- background: white;
- padding: 2px 2px 10px 5px;
-}
-.gwt-DecoratedStackPanel .gwt-StackPanelItem {
- cursor: pointer;
- cursor: hand;
-}
-.gwt-DecoratedStackPanel .stackItemTopLeft,
-.gwt-DecoratedStackPanel .stackItemTopRight {
- width: 4px;
- height: 4px;
- zoom: 1;
-}
-html>body .gwt-DecoratedStackPanel .stackItemTopLeft {
- background: #c1eec8 url(leftCorner.gif) no-repeat;
- border-left: 1px solid #666;
-}
-html>body .gwt-DecoratedStackPanel .stackItemTopRight {
- background: #c1eec8 url(rightCorner.gif) no-repeat;
- border-right: 1px solid #666;
-}
-.gwt-DecoratedStackPanel .stackItemTopLeftInner,
-.gwt-DecoratedStackPanel .stackItemTopRightInner {
- width: 4px;
- height: 4px;
-}
-* html .gwt-DecoratedStackPanel .stackItemTopLeftInner {
- overflow: hidden;
- border-left: 1px solid #666;
- background-color: #d3def6;
- filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='leftCorner.gif',sizingMethod='crop');
-}
-* html .gwt-DecoratedStackPanel .stackItemTopRightInner {
- overflow: hidden;
- border-right: 1px solid #666;
- background-color: #d3def6;
- filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='rightCorner.gif',sizingMethod='crop');
-}
-.gwt-DecoratedStackPanel .stackItemTopCenter {
- background: #ddefde url(gradient.gif) repeat-x 0px 0px;
-}
-.gwt-DecoratedStackPanel .stackItemMiddleLeft {
- background: #d3def6 url(gradient.gif) repeat-x 0px -1px;
- border-left: 1px solid #666;
-}
-.gwt-DecoratedStackPanel .stackItemMiddleLeftInner,
-.gwt-DecoratedStackPanel .stackItemMiddleRightInner {
- width: 1px;
- height: 1px;
-}
-.gwt-DecoratedStackPanel .stackItemMiddleRight {
- background: #d3def6 url(gradient.gif) repeat-x 0px -1px;
- border-right: 1px solid #666;
-}
-.gwt-DecoratedStackPanel .stackItemMiddleCenter {
- font-weight: bold;
- font-size: 1.3em;
- background: #d3def6 url(gradient.gif) repeat-x 0px -1px;
-}
-html>body .gwt-DecoratedStackPanel .gwt-StackPanelItem-first .stackItemTopRight,
-html>body .gwt-DecoratedStackPanel .gwt-StackPanelItem-first .stackItemTopLeft {
- border: 0px;
- background-color: white;
-}
-html>body .gwt-DecoratedStackPanel .gwt-StackPanelItem-below-selected .stackItemTopLeft,
-html>body .gwt-DecoratedStackPanel .gwt-StackPanelItem-below-selected .stackItemTopRight {
- background-color: white;
-}
-* html .gwt-DecoratedStackPanel .gwt-StackPanelItem-first .stackItemTopLeftInner,
-* html .gwt-DecoratedStackPanel .gwt-StackPanelItem-first .stackItemTopRightInner {
- border: 0px;
- background-color: white;
-}
-* html .gwt-DecoratedStackPanel .gwt-StackPanelItem-first .stackItemTopLeftInner {
- padding-left: 1px;
-}
-* html .gwt-DecoratedStackPanel .gwt-StackPanelItem-below-selected .stackItemTopLeftInner,
-* html .gwt-DecoratedStackPanel .gwt-StackPanelItem-below-selected .stackItemTopRightInner {
- background-color: white;
-}
-
-.mail-TopPanel {
- height: 60px;
-}
-
-.mail-TopPanel table {
- font-size: 80%;
-}
-
-.mail-TopPanel .gwt-Image {
- margin-left: 10px;
- position: absolute;
-}
-
-.mail-TopPanelLinks {
- font-size: 80%;
-}
-
-.mail-AboutText {
- width: 24em;
- font-size: 80%;
- padding: 10px;
- text-align: left;
-}
-
-.mail-Contacts td, .mail-Tasks td {
- padding: 4px 0 0 0;
-}
-
-.mail-Contacts table {
- font-size: 80%;
-}
-
-.mail-Tasks table {
- font-size: 80%;
-}
-
.mail-List {
border-left: 1px solid #666;
border-right: 1px solid #666;
border-bottom: 1px solid #666;
- font-size: 80%;
cursor: pointer;
cursor: hand;
}
@@ -226,11 +78,11 @@
.mail-ListHeader {
background: #c1eec8 url(gradient.gif) repeat-x 0px -1px;
- font-weight: bold;
+ font-weight: normal;
}
.mail-ListHeader .mail-ListNavBar .gwt-HTML {
- font-weight: bold;
+ font-weight: normal;
}
.mail-ListHeader td {
@@ -240,7 +92,6 @@
}
.mail-ListNavBar table {
- font-size: 80%;
}
.mail-ListNavBar td {
@@ -259,76 +110,3 @@
.mail-SelectedRow {
background: #eee;
}
-
-.mail-Toolbar .gwt-Image {
-}
-
-.mail-ToolButton {
- font-size: 80%;
- width: 10em;
-}
-
-.mail-Detail {
- border: 1px solid #666;
- margin-top: 4px;
-}
-
-.mail-DetailHeader {
- background: #eee;
- border-bottom: 1px solid #666;
- padding: 6px 4px;
-}
-
-.mail-DetailHeader td {
- padding: 0;
-}
-
-.mail-DetailInner {
- background-color: white;
- font-size: 80%;
-}
-
-.mail-DetailSubject {
- padding: 2px 10px;
- font-weight: bold;
-}
-
-.mail-DetailSender {
- font-size: 80%;
- padding: 2px 10px;
-}
-
-.mail-DetailRecipient {
- font-size: 80%;
- padding: 2px 10px;
-}
-
-.mail-DetailBody {
- line-height: 150%;
- padding: 20px 40px 20px 10px;
- font-family: 'Times New Roman', Times, serif;
-}
-
-.mail-ContactPopup {
- background: #fff;
- border: 1px solid #666;
- padding: 4px;
-}
-
-.mail-ContactPopupName {
- font-size: 80%;
- font-weight: bold;
-}
-
-.mail-ContactPopupEmail {
- font-size: 80%;
- font-style: italic;
-}
-
-.mail-StackContent {
- height: 100%;
-}
-
-.mail-Contacts {
- border-bottom: none;
-}
diff --git a/samples/mail/war/default_photo.jpg b/samples/mail/war/default_photo.jpg
new file mode 100644
index 0000000..751970d
--- /dev/null
+++ b/samples/mail/war/default_photo.jpg
Binary files differ
diff --git a/samples/mail/war/logo.png b/samples/mail/war/logo.png
new file mode 100644
index 0000000..a3123b2
--- /dev/null
+++ b/samples/mail/war/logo.png
Binary files differ
diff --git a/user/javadoc/com/google/gwt/examples/DockLayoutPanelExample.java b/user/javadoc/com/google/gwt/examples/DockLayoutPanelExample.java
index 31fa1ad..6474fb1 100644
--- a/user/javadoc/com/google/gwt/examples/DockLayoutPanelExample.java
+++ b/user/javadoc/com/google/gwt/examples/DockLayoutPanelExample.java
@@ -20,7 +20,6 @@
import com.google.gwt.user.client.ui.DockLayoutPanel;
import com.google.gwt.user.client.ui.HTML;
import com.google.gwt.user.client.ui.RootLayoutPanel;
-import com.google.gwt.user.client.ui.DockLayoutPanel.Direction;
public class DockLayoutPanelExample implements EntryPoint {
@@ -28,11 +27,11 @@
// Attach five widgets to a DockLayoutPanel, one in each direction. Lay
// them out in 'em' units.
DockLayoutPanel p = new DockLayoutPanel(Unit.EM);
- p.add(new HTML("north"), Direction.NORTH, 2);
- p.add(new HTML("south"), Direction.SOUTH, 2);
- p.add(new HTML("east"), Direction.EAST, 2);
- p.add(new HTML("west"), Direction.WEST, 2);
- p.add(new HTML("center"), Direction.CENTER, 2);
+ p.addNorth(new HTML("north"), 2);
+ p.addSouth(new HTML("south"), 2);
+ p.addEast(new HTML("east"), 2);
+ p.addWest(new HTML("west"), 2);
+ p.add(new HTML("center"));
// Note the explicit call to layout(). This is required for the layout to
// take effect.
diff --git a/user/src/com/google/gwt/uibinder/parsers/DockLayoutPanelParser.java b/user/src/com/google/gwt/uibinder/parsers/DockLayoutPanelParser.java
new file mode 100644
index 0000000..d3c1a66
--- /dev/null
+++ b/user/src/com/google/gwt/uibinder/parsers/DockLayoutPanelParser.java
@@ -0,0 +1,124 @@
+/*
+ * Copyright 2009 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
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.google.gwt.uibinder.parsers;
+
+import com.google.gwt.core.ext.UnableToCompleteException;
+import com.google.gwt.core.ext.typeinfo.JClassType;
+import com.google.gwt.core.ext.typeinfo.NotFoundException;
+import com.google.gwt.dom.client.Style.Unit;
+import com.google.gwt.uibinder.rebind.UiBinderWriter;
+import com.google.gwt.uibinder.rebind.XMLElement;
+import com.google.gwt.user.client.ui.DockLayoutPanel;
+import com.google.gwt.user.client.ui.SplitLayoutPanel;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * Parses {@link DockLayoutPanel} widgets.
+ *
+ * TODO(jgw): The code that explicitly excludes SplitLayoutPanel in a fairly
+ * awkward way could be greatly simplified if we hoisted the "dock-ness" into an
+ * interface implemented by both DockLayoutPanel and SplitLayoutPanel, and moved
+ * most of this code into a parser for that specific interface. This parser
+ * would then be reduced to a simple special case for the ctor param.
+ */
+public class DockLayoutPanelParser implements ElementParser {
+
+ private static final Map<String, String> DOCK_NAMES = new HashMap<String, String>();
+
+ static {
+ DOCK_NAMES.put("north", "addNorth");
+ DOCK_NAMES.put("south", "addSouth");
+ DOCK_NAMES.put("east", "addEast");
+ DOCK_NAMES.put("west", "addWest");
+ DOCK_NAMES.put("center", "add");
+ }
+
+ /**
+ * TODO(jgw): This will be moved into EnumAttributeParser as soon as I get
+ * around to building it.
+ */
+ static String getFullyQualifiedEnumName(Enum<?> e) {
+ Class<?> cls = e.getClass();
+ String clsName = cls.getCanonicalName();
+ if (clsName == null) {
+ // A synthesized enum subtype (e.g., Unit$3) will have no canonical name
+ // (yet will not be marked as synthetic). Its superclass will be the
+ // one we want (e.g., Unit).
+ clsName = cls.getSuperclass().getCanonicalName();
+ }
+ return clsName + "." + e.name();
+ }
+
+ public void parse(XMLElement elem, String fieldName, JClassType type,
+ UiBinderWriter writer) throws UnableToCompleteException {
+ // Generate instantiation (requires a 'unit' ctor param).
+ // (Don't generate a ctor for the SplitLayoutPanel; it's implicitly PX).
+ if (type != getSplitLayoutPanelType(writer)) {
+ Unit unit = elem.consumeEnumAttribute("unit", Unit.class);
+ writer.setFieldInitializerAsConstructor(fieldName, writer.getOracle()
+ .findType(DockLayoutPanel.class.getName()),
+ getFullyQualifiedEnumName(unit));
+ }
+
+ // Parse children.
+ for (XMLElement child : elem.consumeChildElements()) {
+ // Make sure the element is one of the fixed set of valid directions.
+ if (!isValidChildElement(elem, child)) {
+ writer.die("In %s, child must be one of {north, south, east, west, center}", elem);
+ }
+
+ // Consume the single widget element.
+ XMLElement widget = child.consumeSingleChildElement();
+ String childFieldName = writer.parseElementToField(widget);
+
+ if (requiresSize(child)) {
+ double size = child.consumeDoubleAttribute("size");
+ writer.addStatement("%s.%s(%s, %f);", fieldName, addMethodName(child),
+ childFieldName, size);
+ } else {
+ writer.addStatement("%s.%s(%s);", fieldName, addMethodName(child),
+ childFieldName);
+ }
+ }
+
+ // Emit the layout() call.
+ writer.addStatement("%s.layout();", fieldName);
+ }
+
+ private String addMethodName(XMLElement elem) {
+ return DOCK_NAMES.get(elem.getLocalName());
+ }
+
+ private JClassType getSplitLayoutPanelType(UiBinderWriter writer)
+ throws UnableToCompleteException {
+ try {
+ return writer.getOracle().getType(SplitLayoutPanel.class.getName());
+ } catch (NotFoundException e) {
+ throw new RuntimeException("Unexpected exception", e);
+ }
+ }
+
+ private boolean isValidChildElement(XMLElement parent, XMLElement child) {
+ return child.getNamespaceUri().equals(parent.getNamespaceUri())
+ && DOCK_NAMES.containsKey(child.getLocalName());
+ }
+
+ private boolean requiresSize(XMLElement elem) {
+ return !elem.getLocalName().equals("center");
+ }
+}
diff --git a/user/src/com/google/gwt/uibinder/parsers/StackLayoutPanelParser.java b/user/src/com/google/gwt/uibinder/parsers/StackLayoutPanelParser.java
new file mode 100644
index 0000000..ca773de
--- /dev/null
+++ b/user/src/com/google/gwt/uibinder/parsers/StackLayoutPanelParser.java
@@ -0,0 +1,83 @@
+/*
+ * Copyright 2009 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
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.google.gwt.uibinder.parsers;
+
+import com.google.gwt.core.ext.UnableToCompleteException;
+import com.google.gwt.core.ext.typeinfo.JClassType;
+import com.google.gwt.dom.client.Style.Unit;
+import com.google.gwt.uibinder.rebind.UiBinderWriter;
+import com.google.gwt.uibinder.rebind.XMLElement;
+import com.google.gwt.user.client.ui.StackLayoutPanel;
+
+/**
+ * Parses {@link StackLayoutPanel} widgets.
+ */
+public class StackLayoutPanelParser implements ElementParser {
+
+ private static final String HEADER_ELEM = "header";
+ private static final String STACK_ELEM = "stack";
+
+ public void parse(XMLElement elem, String fieldName, JClassType type,
+ UiBinderWriter writer) throws UnableToCompleteException {
+ // StackLayoutPanel requires a unit ctor.
+ Unit unit = elem.consumeEnumAttribute("unit", Unit.class);
+ writer.setFieldInitializerAsConstructor(fieldName, writer.getOracle()
+ .findType(StackLayoutPanel.class.getName()), DockLayoutPanelParser
+ .getFullyQualifiedEnumName(unit));
+
+ // Parse children.
+ for (XMLElement child : elem.consumeChildElements()) {
+ // Get the stack element.
+ if (!isElementType(elem, child, STACK_ELEM)) {
+ writer.die("In %s, Only <stack> children are allowed.", elem);
+ }
+
+ XMLElement headerElem = null, widgetElem = null;
+ for (XMLElement stackChild : child.consumeChildElements()) {
+ // Get the header.
+ if (isElementType(elem, stackChild, HEADER_ELEM)) {
+ if (headerElem != null) {
+ writer.die("In %s, Only one <header> allowed per <stack>", elem);
+ }
+ headerElem = stackChild;
+ continue;
+ }
+
+ // Get the widget.
+ if (widgetElem != null) {
+ writer.die("In %s, Only one child widget allowed per <stack>", elem);
+ }
+ widgetElem = stackChild;
+ }
+
+ double size = headerElem.consumeDoubleAttribute("size");
+ XMLElement headerWidgetElem = headerElem.consumeSingleChildElement();
+ String headerFieldName = writer.parseElementToField(headerWidgetElem);
+ String childFieldName = writer.parseElementToField(widgetElem);
+
+ writer.addStatement("%s.add(%s, %s, %f);", fieldName, childFieldName,
+ headerFieldName, size);
+ }
+
+ // Emit the layout() call.
+ writer.addStatement("%s.layout();", fieldName);
+ }
+
+ private boolean isElementType(XMLElement parent, XMLElement child, String type) {
+ return child.getNamespaceUri().equals(parent.getNamespaceUri())
+ && type.equals(child.getLocalName());
+ }
+}
diff --git a/user/src/com/google/gwt/uibinder/rebind/UiBinderWriter.java b/user/src/com/google/gwt/uibinder/rebind/UiBinderWriter.java
index 743ee19..739f365 100644
--- a/user/src/com/google/gwt/uibinder/rebind/UiBinderWriter.java
+++ b/user/src/com/google/gwt/uibinder/rebind/UiBinderWriter.java
@@ -341,6 +341,7 @@
// something like that, but in FieldManager.
fieldName = ("f_" + elem.getLocalName() + (++fieldIndex));
}
+ fieldName = normalizeFieldName(fieldName);
fieldManager.registerField(type, fieldName);
return fieldName;
}
@@ -874,6 +875,13 @@
}
}
+ private String normalizeFieldName(String fieldName) {
+ // If a field name has a '.' in it, replace it with '$' to make it a legal
+ // identifier. This can happen with the field names associated with nested
+ // classes.
+ return fieldName.replace('.', '$');
+ }
+
/**
* Parse the document element and return the source of the Java class that
* will implement its UiBinder.
@@ -979,6 +987,9 @@
addWidgetParser("CellPanel");
addWidgetParser("CustomButton");
+ addWidgetParser("DockLayoutPanel");
+ addWidgetParser("StackLayoutPanel");
+
addAttributeParser("boolean",
"com.google.gwt.uibinder.parsers.BooleanAttributeParser");
diff --git a/user/src/com/google/gwt/uibinder/rebind/XMLElement.java b/user/src/com/google/gwt/uibinder/rebind/XMLElement.java
index 0ff9000..a1c8055 100644
--- a/user/src/com/google/gwt/uibinder/rebind/XMLElement.java
+++ b/user/src/com/google/gwt/uibinder/rebind/XMLElement.java
@@ -206,6 +206,54 @@
}
/**
+ * Consumes the given attribute as a double value.
+ *
+ * @param attr the attribute's full name (including prefix)
+ * @return the attribute's value as a double
+ * @throws UnableToCompleteException
+ */
+ public double consumeDoubleAttribute(String attr)
+ throws UnableToCompleteException {
+ try {
+ return Double.parseDouble(consumeAttribute(attr));
+ } catch (NumberFormatException e) {
+ writer.die(String.format("Error parsing \"%s\" attribute of \"%s\" "
+ + "as a double value", attr, this));
+ return 0; // unreachable line for happy compiler
+ }
+ }
+
+ /**
+ * Consumes the given attribute as an enum value.
+ *
+ * @param attr the attribute's full name (including prefix)
+ * @param type the enumerated type of which this attribute must be a member
+ * @return the attribute's value
+ * @throws UnableToCompleteException
+ */
+ public <T extends Enum<T>> T consumeEnumAttribute(String attr, Class<T> type)
+ throws UnableToCompleteException {
+ String strValue = consumeAttribute(attr);
+
+ // Get the enum value. Enum.valueOf() throws IAE if the specified string is
+ // not valid.
+ T value = null;
+ try {
+ // Enum.valueOf() doesn't accept null arguments.
+ if (strValue != null) {
+ value = Enum.valueOf(type, strValue);
+ }
+ } catch (IllegalArgumentException e) {
+ }
+
+ if (value == null) {
+ writer.die(String.format("Error parsing \"%s\" attribute of \"%s\" "
+ + "as a %s enum", attr, this, type.getSimpleName()));
+ }
+ return value;
+ }
+
+ /**
* Consumes all child elements, and returns an HTML interpretation of them.
* Trailing and leading whitespace is trimmed.
* <p>
@@ -287,6 +335,23 @@
}
/**
+ * Consumes the given attribute as an int value.
+ *
+ * @param attr the attribute's full name (including prefix)
+ * @return the attribute's value as an int
+ * @throws UnableToCompleteException
+ */
+ public int consumeIntAttribute(String attr) throws UnableToCompleteException {
+ try {
+ return Integer.parseInt(consumeAttribute(attr));
+ } catch (NumberFormatException e) {
+ writer.die(String.format("Error parsing \"%s\" attribute of \"%s\" "
+ + "as an int value", attr, this));
+ return 0; // unreachable line for happy compiler
+ }
+ }
+
+ /**
* Consumes all attributes, and returns a string representing the entire
* opening tag. E.g., "<div able='baker'>"
*/
@@ -306,7 +371,7 @@
throws UnableToCompleteException {
String value = consumeAttribute(name);
if ("".equals(value)) {
- writer.die("In %s, missing required attribute name\"%s\"", this, name);
+ writer.die("In %s, missing required attribute name \"%s\"", this, name);
}
return value;
}
diff --git a/user/src/com/google/gwt/user/client/ui/DockLayoutPanel.java b/user/src/com/google/gwt/user/client/ui/DockLayoutPanel.java
index 58e15d3..9c2883f 100644
--- a/user/src/com/google/gwt/user/client/ui/DockLayoutPanel.java
+++ b/user/src/com/google/gwt/user/client/ui/DockLayoutPanel.java
@@ -17,6 +17,7 @@
import com.google.gwt.dom.client.Document;
import com.google.gwt.dom.client.Element;
+import com.google.gwt.dom.client.Style;
import com.google.gwt.dom.client.Style.Unit;
import com.google.gwt.layout.client.Layout;
import com.google.gwt.layout.client.Layout.Layer;
@@ -95,23 +96,69 @@
}
/**
- * Adds a widget to the specified edge of the dock. If the widget is already a
- * child of this panel, this method behaves as though {@link #remove(Widget)}
- * had already been called.
+ * Adds a widget at the center of the dock. No further widgets may be added
+ * after this one.
*
* @param widget the widget to be added
- * @param direction the widget's direction in the dock
- * @param size the child widget's size
- *
- * @throws IllegalArgumentException when adding to the {@link #CENTER} and
- * there is already a different widget there
*/
- public void add(Widget widget, Direction direction, double size) {
- insert(widget, direction, size, null);
+ @Override
+ public void add(Widget widget) {
+ insert(widget, Direction.CENTER, 0, null);
}
/**
+ * Adds a widget to the east edge of the dock.
+ *
+ * @param widget the widget to be added
+ * @param size the child widget's size
+ */
+ public void addEast(Widget widget, double size) {
+ insert(widget, Direction.EAST, size, null);
+ }
+
+ /**
+ * Adds a widget to the north edge of the dock.
+ *
+ * @param widget the widget to be added
+ * @param size the child widget's size
+ */
+ public void addNorth(Widget widget, double size) {
+ insert(widget, Direction.NORTH, size, null);
+ }
+
+ /**
+ * Adds a widget to the south edge of the dock.
+ *
+ * @param widget the widget to be added
+ * @param size the child widget's size
+ */
+ public void addSouth(Widget widget, double size) {
+ insert(widget, Direction.SOUTH, size, null);
+ }
+
+ /**
+ * Adds a widget to the west edge of the dock.
+ *
+ * @param widget the widget to be added
+ * @param size the child widget's size
+ */
+ public void addWest(Widget widget, double size) {
+ insert(widget, Direction.WEST, size, null);
+ }
+
+ /**
+ * Gets the container element associated with the given child widget.
+ *
+ * <p>
+ * The container element is created by the {@link Layout} class. This should
+ * be used with certain styles, such as {@link Style#setZIndex(int)}, that
+ * must be applied to the container, rather than directly to the child widget.
+ * </p>
+ *
* TODO(jgw): Is this really the best way to do this?
+ *
+ * @param widget the widget whose container element is to be retrieved
+ * @return the widget's container element
*/
public Element getContainerElementFor(Widget widget) {
assertIsChild(widget);
@@ -133,46 +180,55 @@
}
/**
- * Adds a widget to the specified edge of the dock. If the widget is already a
- * child of this panel, this method behaves as though {@link #remove(Widget)}
- * had already been called.
+ * Adds a widget to the east edge of the dock, inserting it before an
+ * existing widget.
*
* @param widget the widget to be added
- * @param direction the widget's direction in the dock
+ * @param size the child widget's size
* @param before the widget before which to insert the new child, or
* <code>null</code> to append
- *
- * @throws IllegalArgumentException when adding to the {@link #CENTER} and
- * there is already a different widget there
*/
- public void insert(Widget widget, Direction direction, double size,
- Widget before) {
- assertIsChild(before);
+ public void insertEast(Widget widget, double size, Widget before) {
+ insert(widget, Direction.EAST, size, before);
+ }
- // Validation.
- if (before == null) {
- assert center == null : "No widget may be added after the CENTER widget";
- } else {
- assert direction != Direction.CENTER : "A CENTER widget must always be added last";
- }
+ /**
+ * Adds a widget to the north edge of the dock, inserting it before an
+ * existing widget.
+ *
+ * @param widget the widget to be added
+ * @param size the child widget's size
+ * @param before the widget before which to insert the new child, or
+ * <code>null</code> to append
+ */
+ public void insertNorth(Widget widget, double size, Widget before) {
+ insert(widget, Direction.NORTH, size, before);
+ }
- // Detach new child.
- widget.removeFromParent();
+ /**
+ * Adds a widget to the south edge of the dock, inserting it before an
+ * existing widget.
+ *
+ * @param widget the widget to be added
+ * @param size the child widget's size
+ * @param before the widget before which to insert the new child, or
+ * <code>null</code> to append
+ */
+ public void insertSouth(Widget widget, double size, Widget before) {
+ insert(widget, Direction.SOUTH, size, before);
+ }
- // Logical attach.
- getChildren().add(widget);
- if (direction == Direction.CENTER) {
- center = widget;
- }
-
- // Physical attach.
- Layer layer = layout.attachChild(widget.getElement(),
- (before != null) ? before.getElement() : null, widget);
- LayoutData data = new LayoutData(direction, size, layer);
- widget.setLayoutData(data);
-
- // Adopt.
- adopt(widget);
+ /**
+ * Adds a widget to the west edge of the dock, inserting it before an
+ * existing widget.
+ *
+ * @param widget the widget to be added
+ * @param size the child widget's size
+ * @param before the widget before which to insert the new child, or
+ * <code>null</code> to append
+ */
+ public void insertWest(Widget widget, double size, Widget before) {
+ insert(widget, Direction.WEST, size, before);
}
public void layout() {
@@ -284,6 +340,46 @@
return unit;
}
+ /**
+ * Adds a widget to the specified edge of the dock. If the widget is already a
+ * child of this panel, this method behaves as though {@link #remove(Widget)}
+ * had already been called.
+ *
+ * @param widget the widget to be added
+ * @param direction the widget's direction in the dock
+ * @param before the widget before which to insert the new child, or
+ * <code>null</code> to append
+ */
+ protected void insert(Widget widget, Direction direction, double size,
+ Widget before) {
+ assertIsChild(before);
+
+ // Validation.
+ if (before == null) {
+ assert center == null : "No widget may be added after the CENTER widget";
+ } else {
+ assert direction != Direction.CENTER : "A CENTER widget must always be added last";
+ }
+
+ // Detach new child.
+ widget.removeFromParent();
+
+ // Logical attach.
+ getChildren().add(widget);
+ if (direction == Direction.CENTER) {
+ center = widget;
+ }
+
+ // Physical attach.
+ Layer layer = layout.attachChild(widget.getElement(),
+ (before != null) ? before.getElement() : null, widget);
+ LayoutData data = new LayoutData(direction, size, layer);
+ widget.setLayoutData(data);
+
+ // Adopt.
+ adopt(widget);
+ }
+
@Override
protected void onLoad() {
layout.onAttach();
@@ -295,6 +391,6 @@
}
private void assertIsChild(Widget widget) {
- assert (widget == null) || (widget.getParent() == this) : "TODO";
+ assert (widget == null) || (widget.getParent() == this) : "The specified widget is not a child of this panel";
}
}
diff --git a/user/src/com/google/gwt/user/client/ui/SplitLayoutPanel.java b/user/src/com/google/gwt/user/client/ui/SplitLayoutPanel.java
index 46a43e8..db42600 100644
--- a/user/src/com/google/gwt/user/client/ui/SplitLayoutPanel.java
+++ b/user/src/com/google/gwt/user/client/ui/SplitLayoutPanel.java
@@ -212,10 +212,10 @@
}
@Override
- public void add(Widget child, Direction direction, double size) {
- super.add(child, direction, size);
+ public void insert(Widget child, Direction direction, double size, Widget before) {
+ super.insert(child, direction, size, before);
if (direction != Direction.CENTER) {
- addSplitter();
+ insertSplitter(before);
}
}
@@ -251,13 +251,13 @@
splitter.setMinSize(minSize);
}
- private void addSplitter() {
+ private void insertSplitter(Widget before) {
assert getChildren().size() > 0 : "Can't add a splitter before any children";
assert getCenter() == null : "Can't add a splitter after the CENTER widget";
Widget lastChild = getChildren().get(getChildren().size() - 1);
LayoutData lastChildLayout = (LayoutData) lastChild.getLayoutData();
- Splitter splitter;
+ Splitter splitter = null;
switch (lastChildLayout.direction) {
case WEST:
splitter = new HSplitter(lastChild, false);
@@ -273,10 +273,9 @@
break;
default:
assert false : "Unexpected direction";
- return;
}
- super.add(splitter, lastChildLayout.direction, SPLITTER_SIZE);
+ super.insert(splitter, lastChildLayout.direction, SPLITTER_SIZE, before);
}
private Splitter getAssociatedSplitter(Widget child) {