DisclosurePanel now does  ImageResource and is nice in UiBinder.

Deprecates many of its convience constructors--necessary for
UiBinder sanity, and just plain good API hygiene.

Reviewed by: jgw

git-svn-id: https://google-web-toolkit.googlecode.com/svn/trunk@6387 8db76d5a-ed1c-0410-87a9-c151d255dfc7
diff --git a/user/src/com/google/gwt/uibinder/parsers/DisclosurePanelParser.java b/user/src/com/google/gwt/uibinder/parsers/DisclosurePanelParser.java
index 79c8a26..690c927 100644
--- a/user/src/com/google/gwt/uibinder/parsers/DisclosurePanelParser.java
+++ b/user/src/com/google/gwt/uibinder/parsers/DisclosurePanelParser.java
@@ -1,12 +1,12 @@
 /*
- * Copyright 2007 Google Inc.
- *
+ * 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
@@ -19,100 +19,134 @@
 import com.google.gwt.core.ext.typeinfo.JClassType;
 import com.google.gwt.uibinder.rebind.UiBinderWriter;
 import com.google.gwt.uibinder.rebind.XMLElement;
-import com.google.gwt.user.client.ui.DisclosurePanel;
 
 /**
  * Parses {@link com.google.gwt.user.client.ui.DisclosurePanel} widgets.
  */
 public class DisclosurePanelParser implements ElementParser {
 
-  private static final String ATTRIBUTE_HEADER_WIDGET = "DisclosurePanel-header";
-
-  private static final String ATTRIBUTE_HEADER_BUNDLE = "imageBundle";
-
-  private static final String ATTRIBUTE_INITIALLY_OPEN = "initiallyOpen";
-
-  private static final String ATTRIBUTE_ENABLE_ANIMATION = "enableAnimation";
-
-  /**
-   * @return the type oracle's DisclosurePanel class
-   */
-  private static JClassType getDisclosurePanelClass(UiBinderWriter w) {
-    return w.getOracle().findType(DisclosurePanel.class.getName());
+  private static class Children {
+    XMLElement body;
+    XMLElement header;
+    XMLElement customHeader;
   }
 
-  public void parse(XMLElement elem, String fieldName, JClassType type,
-      UiBinderWriter writer) throws UnableToCompleteException {
+  private static final String CUSTOM = "customHeader";
+  private static final String HEADER = "header";
+  private static final String OPEN_IMAGE = "openImage";
 
-    String text = null;
-    // They must specify a label
-    if (elem.hasAttribute("text")) {
-      text = elem.consumeAttribute("text");
-      text = '"' + UiBinderWriter.escapeTextForJavaStringLiteral(text) + '"';
-    }
+  private static final String CLOSED_IMAGE = "closedImage";
 
-    // They may specify an image bundle
-    String imageBundle = null;
-    if (elem.hasAttribute(ATTRIBUTE_HEADER_BUNDLE)) {
-      imageBundle = elem.consumeAttribute(ATTRIBUTE_HEADER_BUNDLE);
-    }
+  public void parse(final XMLElement panelElem, String panelField,
+      JClassType type, final UiBinderWriter writer)
+      throws UnableToCompleteException {
+    Children children = findChildren(panelElem, writer);
 
-    // They may specify an initial closed state
-    String initiallyOpen = "false";
-    if (elem.hasAttribute(ATTRIBUTE_INITIALLY_OPEN)) {
-      initiallyOpen = elem.consumeAttribute(ATTRIBUTE_INITIALLY_OPEN);
-    }
-
-    // They may enable animation
-    String enableAnimation = "true";
-    if (elem.hasAttribute(ATTRIBUTE_ENABLE_ANIMATION)) {
-      enableAnimation = elem.consumeAttribute(ATTRIBUTE_ENABLE_ANIMATION);
-    }
-
-    String childFieldName = null;
-    String headerFieldName = null;
-
-    for (XMLElement child : elem.consumeChildElements()) {
-      // Disclosure panel header optionally comes from the DisclosurePanel-header attribute of the
-      // child
-      boolean childIsHeader = false;
-      String headerAttributeName = elem.getPrefix() + ":" + ATTRIBUTE_HEADER_WIDGET;
-      if (child.hasAttribute(headerAttributeName)) {
-        if (headerFieldName != null) {
-          writer.die("In %s, DisclosurePanel cannot contain more than one header widget.", elem);
-        }
-        child.consumeAttribute(headerAttributeName);
-        headerFieldName = writer.parseElementToField(child);
-        childIsHeader = true;
+    if (null != children.body) {
+      if (!writer.isWidgetElement(children.body)) {
+        writer.die("In %s, %s must be a widget", panelElem, children.body);
       }
-      if (!childIsHeader) {
-        if (childFieldName != null) {
-          writer.die("In %s, DisclosurePanel cannot contain more than one content widget.", elem);
-        }
-        childFieldName = writer.parseElementToField(child);
-      }
+
+      String bodyField = writer.parseElementToField(children.body);
+      writer.addInitStatement("%s.add(%s);", panelField, bodyField);
     }
 
-    // To use the image bundle, you must provide a text header.
-    if (imageBundle != null) {
-      writer.setFieldInitializerAsConstructor(fieldName,
-          getDisclosurePanelClass(writer), imageBundle, (text != null ? text : "\"\""),
-          initiallyOpen);
-    } else {
-      JClassType panelClass = getDisclosurePanelClass(writer);
-      if (text != null) {
-        writer.setFieldInitializerAsConstructor(fieldName, panelClass, text);
+    if (null != children.customHeader) {
+      XMLElement headerElement = children.customHeader.consumeSingleChildElement();
+
+      if (!writer.isWidgetElement(headerElement)) {
+        writer.die("In %s of %s, %s is not a widget", children.customHeader,
+            panelElem, headerElement);
+      }
+
+      String headerField = writer.parseElementToField(headerElement);
+      writer.addInitStatement("%s.setHeader(%s);", panelField, headerField);
+    }
+
+    if (null != children.header) {
+      String openImage = getAttribute(OPEN_IMAGE, children.header, writer);
+      String closedImage = getAttribute(CLOSED_IMAGE, children.header, writer);
+      String headerText = children.header.consumeInnerTextEscapedAsHtmlStringLiteral(new TextInterpreter(
+          writer));
+
+      if ((openImage == null || closedImage == null)
+          && !(openImage == closedImage)) {
+        writer.die("In %s of %s, both %s and %s must be specified, or neither",
+            children.header, panelElem, OPEN_IMAGE, CLOSED_IMAGE);
+      }
+
+      String panelTypeName = type.getQualifiedSourceName();
+      if (openImage != null) {
+        writer.setFieldInitializer(panelField, String.format(
+            "new %s(%s, %s, \"%s\")", panelTypeName, openImage, closedImage,
+            headerText));
       } else {
-        writer.setFieldInitializerAsConstructor(fieldName, panelClass);
+        writer.setFieldInitializer(panelField, String.format("new %s(\"%s\")",
+            panelTypeName, headerText));
       }
     }
-    if (childFieldName != null) {
-      writer.addStatement("%1$s.setContent(%2$s);", fieldName, childFieldName);
+  }
+
+  private Children findChildren(final XMLElement elem,
+      final UiBinderWriter writer) throws UnableToCompleteException {
+    final Children children = new Children();
+
+    elem.consumeChildElements(new XMLElement.Interpreter<Boolean>() {
+      public Boolean interpretElement(XMLElement child)
+          throws UnableToCompleteException {
+
+        if (hasAttribute(child, HEADER)) {
+          assertFirstHeader();
+          children.header = child;
+          return true;
+        }
+
+        if (hasAttribute(child, CUSTOM)) {
+          assertFirstHeader();
+          children.customHeader = child;
+          return true;
+        }
+
+        // Must be the body, then
+        if (null != children.body) {
+          writer.die("In %s, may have only one body element", elem);
+        }
+
+        children.body = child;
+        return true;
+      }
+
+      void assertFirstHeader() throws UnableToCompleteException {
+        if ((null != children.header) && (null != children.customHeader)) {
+          writer.die("In %1$s, may have only one %2$s:header "
+              + "or %2$s:customHeader", elem, elem.getPrefix());
+        }
+      }
+
+      private boolean hasAttribute(XMLElement child, final String attribute) {
+        return rightNamespace(child) && child.getLocalName().equals(attribute);
+      }
+
+      private boolean rightNamespace(XMLElement child) {
+        return child.getNamespaceUri().equals(elem.getNamespaceUri());
+      }
+    });
+
+    return children;
+  }
+
+  /**
+   * @return a field reference or a null string if the attribute is unset
+   * @throws UnableToCompleteException on bad value
+   */
+  private String getAttribute(String attribute, XMLElement headerElem,
+      UiBinderWriter writer) throws UnableToCompleteException {
+    // TODO(rjrjr) parser should come from XMLElement
+
+    String value = headerElem.consumeAttribute(attribute, null);
+    if (value != null) {
+      value = new StrictAttributeParser().parse(value, writer);
     }
-    if (headerFieldName != null) {
-      writer.addStatement("%1$s.setHeader(%2$s);", fieldName, headerFieldName);
-    }
-    writer.addStatement("%1$s.setAnimationEnabled(%2$s);", fieldName, enableAnimation);
-    writer.addStatement("%1$s.setOpen(%2$s);", fieldName, initiallyOpen);
+    return value;
   }
 }
diff --git a/user/src/com/google/gwt/uibinder/sample/client/WidgetBasedUi.ui.xml b/user/src/com/google/gwt/uibinder/sample/client/WidgetBasedUi.ui.xml
index 169888e..d8ffecd 100644
--- a/user/src/com/google/gwt/uibinder/sample/client/WidgetBasedUi.ui.xml
+++ b/user/src/com/google/gwt/uibinder/sample/client/WidgetBasedUi.ui.xml
@@ -126,6 +126,8 @@
 </ui:style>
 <ui:image field='prettyImage' />
 <ui:image field='prettyTilingImage' src='prettyImage.png' flipRtl='true' repeatStyle='Both'/>
+<ui:image field='right'/>
+<ui:image field='down'/>
 
 <gwt:DockPanel ui:field="root" width="100%">
   <gwt:Dock direction='NORTH'>
@@ -257,6 +259,7 @@
         <gwt:Tree ui:field='myTree' width="100px" />
 
       <p>...TextBoxes...</p>
+      
       <gwt:TextBox maxLength="21">21 chars only, please</gwt:TextBox>
 
       <p>...or perhaps a handful of RadioButtons:</p>
@@ -270,7 +273,9 @@
         text="Charlie (this one is a subclass of RadioButton)">
         <ui:attribute name="text" description="radio button name"/>
       </demo:PointlessRadioButtonSubclass>
+      
       <p> ... a StackPanel ... </p>
+      
       <gwt:StackPanel stylePrimaryName="myStyle" width="280px" ui:field='myStackPanel'>
         <gwt:Label text="Stack One Text"  gwt:StackPanel-text="Stack One"
             ui:field='myStackPanelItem'>
@@ -287,47 +292,94 @@
         </gwt:HTMLPanel>
         <gwt:Label text="Stack Three Text"  gwt:StackPanel-text="Stack Three" />
       </gwt:StackPanel>
+      
       <p> ... a DisclosurePanel with a text header ... </p>
-      <gwt:DisclosurePanel text="I just have a text header" ui:field='myDisclosurePanel'>
-        <!--ui:attribute name="text" description="Label for Disclosure One"/ -->
-        <gwt:Label text="Disclosure Text" ui:field='myDisclosurePanelItem'>
-          <ui:attribute name="text" description="Content for Disclosure One Text"/>
-        </gwt:Label>
+      
+      <gwt:DisclosurePanel ui:field='myDisclosurePanel' animationEnabled='true'>
+        <gwt:header>
+          <ui:msg description="Label for Disclosure One">I just have a text header</ui:msg>
+        </gwt:header>
+
+
+          <gwt:Label ui:field='myDisclosurePanelItem'>
+            <ui:msg  description="Content for Disclosure One Text">Disclosure Text</ui:msg>
+          </gwt:Label>
+
       </gwt:DisclosurePanel>
+      
       <p> ... a DisclosurePanel with a widget header ... </p>
-      <gwt:DisclosurePanel>
-        <gwt:Label text="Disclosure Header - closed" gwt:DisclosurePanel-header="true">
-          <ui:attribute name="text" description="Content for Disclosure Two Text"/>
-        </gwt:Label>
-        <gwt:Label text="Disclosure Two - closed">
-          <ui:attribute name="text" description="Content for Disclosure Two"/>
-        </gwt:Label>
+      
+      <gwt:DisclosurePanel animationEnabled='true'>
+        <gwt:customHeader>
+          <gwt:Label>
+            <ui:msg description="Content for Disclosure Two Text">Disclosure Header - closed</ui:msg>
+          </gwt:Label>
+        </gwt:customHeader>
+
+
+          <gwt:Label>
+            <ui:msg description="Content for Disclosure Two">Disclosure Two - closed</ui:msg>
+          </gwt:Label>
+
       </gwt:DisclosurePanel>
+
       <p> ... an open DisclosurePanel with a widget header ... </p>
-      <gwt:DisclosurePanel initiallyOpen="true">
-        <gwt:Label text="Disclosure Header - open" gwt:DisclosurePanel-header="true">
-          <ui:attribute name="text" description="Content for Disclosure Two Text"/>
-        </gwt:Label>
-        <gwt:Label text="Disclosure Two - open">
-          <ui:attribute name="text" description="Content for Disclosure Two"/>
-        </gwt:Label>
+
+      <gwt:DisclosurePanel open='true' animationEnabled='true'>
+        <gwt:customHeader>
+          <gwt:Label>
+            <ui:msg description="Content for Disclosure Two Text">Disclosure Header - open</ui:msg>
+          </gwt:Label>
+        </gwt:customHeader>
+
+
+          <gwt:Label>
+            <ui:msg description="Content for Disclosure Two">Disclosure Two - open</ui:msg>
+          </gwt:Label>
+
       </gwt:DisclosurePanel>
+
       <p> ... a DisclosurePanel with no header ... </p>
-      <gwt:DisclosurePanel initiallyOpen="true">
-        <gwt:Label text="Disclosure Three">
-          <ui:attribute name="text" description="Content for Disclosure Three"/>
-        </gwt:Label>
+
+      <gwt:DisclosurePanel open="true" animationEnabled='true'>
+
+          <gwt:Label>
+            <ui:msg description="Content for Disclosure Three">Disclosure Three</ui:msg>
+          </gwt:Label>
+
       </gwt:DisclosurePanel>
+
       <p> ... an open DisclosurePanel with a text label and no animation</p>
-      <gwt:DisclosurePanel text="Disclosure Three - open" initiallyOpen="true"
-          enableAnimation="false">
-        <gwt:Label text="Disclosure Three">
-          <ui:attribute name="text" description="Content for Disclosure Three"/>
-        </gwt:Label>
+
+      <gwt:DisclosurePanel open="true" >
+        <gwt:header><ui:msg>Disclosure Three - open</ui:msg></gwt:header>
+
+
+          <gwt:Label>
+            <ui:msg description="Content for Disclosure Three">Disclosure Three</ui:msg>
+          </gwt:Label>
+
       </gwt:DisclosurePanel>
+
       <p> ... a DisclosurePanel with no content ... </p>
-      <gwt:DisclosurePanel text="I just have a text header" />
- 
+
+      <gwt:DisclosurePanel>
+        <gwt:header><ui:msg>"I just have a text header"</ui:msg></gwt:header>
+      </gwt:DisclosurePanel>
+      
+      <p> ... a DisclosurePanel with custom images ... </p>
+      
+      <gwt:DisclosurePanel open='false' animationEnabled='true'>
+        <gwt:header openImage='{down}' closedImage='{right}'>
+          <ui:msg description="Content for Disclosure Two Text">Custom images header</ui:msg>
+        </gwt:header>
+
+          <gwt:Label>
+            <ui:msg description="Content for Disclosure Two">Custom images body</ui:msg>
+          </gwt:Label>
+
+      </gwt:DisclosurePanel>
+      
       <h2>Stylish</h2>
       <p>
        Templates work with ClientBundle. For example,
diff --git a/user/src/com/google/gwt/uibinder/sample/client/down.png b/user/src/com/google/gwt/uibinder/sample/client/down.png
new file mode 100644
index 0000000..6b43b35
--- /dev/null
+++ b/user/src/com/google/gwt/uibinder/sample/client/down.png
Binary files differ
diff --git a/user/src/com/google/gwt/uibinder/sample/client/right.png b/user/src/com/google/gwt/uibinder/sample/client/right.png
new file mode 100644
index 0000000..2711541
--- /dev/null
+++ b/user/src/com/google/gwt/uibinder/sample/client/right.png
Binary files differ
diff --git a/user/src/com/google/gwt/user/client/ui/DisclosurePanel.java b/user/src/com/google/gwt/user/client/ui/DisclosurePanel.java
index 04d9989..65e7a3e 100644
--- a/user/src/com/google/gwt/user/client/ui/DisclosurePanel.java
+++ b/user/src/com/google/gwt/user/client/ui/DisclosurePanel.java
@@ -24,7 +24,8 @@
 import com.google.gwt.event.logical.shared.OpenEvent;
 import com.google.gwt.event.logical.shared.OpenHandler;
 import com.google.gwt.event.shared.HandlerRegistration;
-import com.google.gwt.i18n.client.LocaleInfo;
+import com.google.gwt.resources.client.ClientBundle;
+import com.google.gwt.resources.client.ImageResource;
 import com.google.gwt.user.client.DOM;
 import com.google.gwt.user.client.Element;
 import com.google.gwt.user.client.Event;
@@ -35,11 +36,10 @@
  * A widget that consists of a header and a content panel that discloses the
  * content when a user clicks on the header.
  * 
- * <h3>CSS Style Rules</h3>
- * <ul class="css">
- * <li>.gwt-DisclosurePanel { the panel's primary style }</li>
- * <li>.gwt-DisclosurePanel-open { dependent style set when panel is open }</li>
- * <li>.gwt-DisclosurePanel-closed { dependent style set when panel is closed }</li>
+ * <h3>CSS Style Rules</h3> <ul class="css"> <li>.gwt-DisclosurePanel { the
+ * panel's primary style }</li> <li>.gwt-DisclosurePanel-open { dependent style
+ * set when panel is open }</li> <li>.gwt-DisclosurePanel-closed { dependent
+ * style set when panel is closed }</li>
  * 
  * <p>
  * <img class='gallery' src='DisclosurePanel.png'/>
@@ -47,17 +47,51 @@
  * 
  * <p>
  * The header and content sections can be easily selected using css with a child
- * selector:<br/> .gwt-DisclosurePanel-open .header { ... }
+ * selector:<br/>
+ * .gwt-DisclosurePanel-open .header { ... }
  * </p>
  */
 @SuppressWarnings("deprecation")
 public final class DisclosurePanel extends Composite implements
     FiresDisclosureEvents, HasWidgets, HasAnimation,
     HasOpenHandlers<DisclosurePanel>, HasCloseHandlers<DisclosurePanel> {
+  interface DefaultImages extends ClientBundle {
+    ImageResource disclosurePanelClosed();
+
+    ImageResource disclosurePanelOpen();
+  }
+
+  private static final DefaultImages DEFAULT_IMAGES = GWT.create(DefaultImages.class);
+
   /**
-   * The duration of the animation.
+   * Used to wrap widgets in the header to provide click support. Effectively
+   * wraps the widget in an <code>anchor</code> to get automatic keyboard
+   * access.
    */
-  private static final int ANIMATION_DURATION = 350;
+  private final class ClickableHeader extends SimplePanel {
+
+    private ClickableHeader() {
+      // Anchor is used to allow keyboard access.
+      super(DOM.createAnchor());
+      Element elem = getElement();
+      DOM.setElementProperty(elem, "href", "javascript:void(0);");
+      // Avoids layout problems from having blocks in inlines.
+      DOM.setStyleAttribute(elem, "display", "block");
+      sinkEvents(Event.ONCLICK);
+      setStyleName(STYLENAME_HEADER);
+    }
+
+    @Override
+    public void onBrowserEvent(Event event) {
+      // no need to call super.
+      switch (DOM.eventGetType(event)) {
+        case Event.ONCLICK:
+          // Prevent link default action.
+          DOM.eventPreventDefault(event);
+          setOpen(!isOpen);
+      }
+    }
+  }
 
   /**
    * An {@link Animation} used to open the content.
@@ -91,7 +125,7 @@
       } else {
         panel.contentWrapper.setVisible(panel.isOpen);
         if (panel.isOpen) {
-          // Special treatment on the visible case to ensure LazyPanel works 
+          // Special treatment on the visible case to ensure LazyPanel works
           panel.getContent().setVisible(true);
         }
       }
@@ -112,9 +146,9 @@
       super.onStart();
       if (opening) {
         curPanel.contentWrapper.setVisible(true);
-        // Special treatment on the visible case to ensure LazyPanel works 
+        // Special treatment on the visible case to ensure LazyPanel works
         curPanel.getContent().setVisible(true);
-     }
+      }
     }
 
     @Override
@@ -134,36 +168,6 @@
   }
 
   /**
-   * Used to wrap widgets in the header to provide click support. Effectively
-   * wraps the widget in an <code>anchor</code> to get automatic keyboard
-   * access.
-   */
-  private final class ClickableHeader extends SimplePanel {
-
-    private ClickableHeader() {
-      // Anchor is used to allow keyboard access.
-      super(DOM.createAnchor());
-      Element elem = getElement();
-      DOM.setElementProperty(elem, "href", "javascript:void(0);");
-      // Avoids layout problems from having blocks in inlines.
-      DOM.setStyleAttribute(elem, "display", "block");
-      sinkEvents(Event.ONCLICK);
-      setStyleName(STYLENAME_HEADER);
-    }
-
-    @Override
-    public void onBrowserEvent(Event event) {
-      // no need to call super.
-      switch (DOM.eventGetType(event)) {
-        case Event.ONCLICK:
-          // Prevent link default action.
-          DOM.eventPreventDefault(event);
-          setOpen(!isOpen);
-      }
-    }
-  }
-
-  /**
    * The default header widget used within a {@link DisclosurePanel}.
    */
   private class DefaultHeader extends Widget implements HasText,
@@ -176,13 +180,27 @@
     private final Element labelTD;
 
     private final Image iconImage;
-    private final DisclosurePanelImages images;
+    private final Imager imager;
 
-    private DefaultHeader(DisclosurePanelImages images, String text) {
-      this.images = images;
+    private DefaultHeader(final DisclosurePanelImages images, String text) {
+      this(new Imager() {
+        public Image makeImage() {
+          return images.disclosurePanelClosed().createImage();
+        }
 
-      iconImage = isOpen ? images.disclosurePanelOpen().createImage()
-          : images.disclosurePanelClosed().createImage();
+        public void updateImage(boolean open, Image image) {
+          if (open) {
+            images.disclosurePanelOpen().applyTo(image);
+          } else {
+            images.disclosurePanelClosed().applyTo(image);
+          }
+        }
+      }, text);
+    }
+
+    private DefaultHeader(Imager imager, String text) {
+      this.imager = imager;
+      iconImage = imager.makeImage();
 
       // I do not need any Widgets here, just a DOM structure.
       Element root = DOM.createTable();
@@ -212,6 +230,23 @@
       setStyle();
     }
 
+    private DefaultHeader(final ImageResource openImage,
+        final ImageResource closedImage, String text) {
+      this(new Imager() {
+        public Image makeImage() {
+          return new Image(closedImage);
+        }
+
+        public void updateImage(boolean open, Image image) {
+          if (open) {
+            image.setResource(openImage);
+          } else {
+            image.setResource(closedImage);
+          }
+        }
+      }, text);
+    }
+
     public final String getText() {
       return DOM.getInnerText(labelTD);
     }
@@ -229,14 +264,21 @@
     }
 
     private void setStyle() {
-      if (isOpen) {
-        images.disclosurePanelOpen().applyTo(iconImage);
-      } else {
-        images.disclosurePanelClosed().applyTo(iconImage);
-      }
+      imager.updateImage(isOpen, iconImage);
     }
   }
 
+  private interface Imager {
+    Image makeImage();
+
+    void updateImage(boolean open, Image image);
+  }
+
+  /**
+   * The duration of the animation.
+   */
+  private static final int ANIMATION_DURATION = 350;
+
   // Stylename constants.
   private static final String STYLENAME_DEFAULT = "gwt-DisclosurePanel";
 
@@ -253,13 +295,6 @@
    */
   private static ContentAnimation contentAnimation;
 
-  private static DisclosurePanelImages createDefaultImages() {
-    if (LocaleInfo.getCurrentLocale().isRTL()) {
-      return GWT.create(DisclosurePanelImagesRTL.class);
-    }
-    return GWT.create(DisclosurePanelImages.class);
-  }
-
   /**
    * top level widget. The first child will be a reference to {@link #header}.
    * The second child will be a reference to {@link #contentWrapper}.
@@ -284,7 +319,34 @@
    * Creates an empty DisclosurePanel that is initially closed.
    */
   public DisclosurePanel() {
-    init(false);
+    initWidget(mainPanel);
+    mainPanel.add(header);
+    mainPanel.add(contentWrapper);
+    DOM.setStyleAttribute(contentWrapper.getElement(), "padding", "0px");
+    DOM.setStyleAttribute(contentWrapper.getElement(), "overflow", "hidden");
+    setStyleName(STYLENAME_DEFAULT);
+    setContentDisplay(false);
+  }
+
+  /**
+   * Creates a DisclosurePanel with the specified header text, an initial
+   * open/close state and a bundle of images to be used in the default header
+   * widget.
+   * 
+   * @param images a bundle that provides disclosure panel specific images
+   * @param headerText the text to be displayed in the header
+   * @param isOpen the initial open/close state of the content panel
+   * 
+   * @deprecated use
+   *             {@link #DisclosurePanel(ImageResource, ImageResource, String)
+   *             and {@link #setOpen(boolean)}
+   */
+  @Deprecated
+  public DisclosurePanel(DisclosurePanelImages images, String headerText,
+      boolean isOpen) {
+    this();
+    setOpen(isOpen);
+    setHeader(new DefaultHeader(images, headerText));
   }
 
   /**
@@ -296,10 +358,10 @@
    * @param headerText the text to be displayed in the header
    * @param isOpen the initial open/close state of the content panel
    */
-  public DisclosurePanel(DisclosurePanelImages images, String headerText,
-      boolean isOpen) {
-    init(isOpen);
-    setHeader(new DefaultHeader(images, headerText));
+  public DisclosurePanel(ImageResource openImage, ImageResource closedImage,
+      String headerText) {
+    this();
+    setHeader(new DefaultHeader(openImage, closedImage, headerText));
   }
 
   /**
@@ -309,7 +371,8 @@
    * @param headerText the text to be displayed in the header
    */
   public DisclosurePanel(String headerText) {
-    this(createDefaultImages(), headerText, false);
+    this(DEFAULT_IMAGES.disclosurePanelOpen(),
+        DEFAULT_IMAGES.disclosurePanelClosed(), headerText);
   }
 
   /**
@@ -318,9 +381,14 @@
    * 
    * @param headerText the text to be displayed in the header
    * @param isOpen the initial open/close state of the content panel
+   * @deprecated use {@link #DisclosurePanel(String)} and
+   *             {@link #setOpen(boolean)}
    */
+  @Deprecated
   public DisclosurePanel(String headerText, boolean isOpen) {
-    this(createDefaultImages(), headerText, isOpen);
+    this(DEFAULT_IMAGES.disclosurePanelOpen(),
+        DEFAULT_IMAGES.disclosurePanelClosed(), headerText);
+    this.setOpen(isOpen);
   }
 
   /**
@@ -328,9 +396,11 @@
    * the header.
    * 
    * @param header the widget to be used as a header
+   * @deprecated use {@link #DisclosurePanel()} and {@link #setHeader(Widget)}
    */
   public DisclosurePanel(Widget header) {
-    this(header, false);
+    this();
+    setHeader(header);
   }
 
   /**
@@ -339,10 +409,14 @@
    * 
    * @param header the widget to be used as a header
    * @param isOpen the initial open/close state of the content panel
+   * @deprecated use {@link #DisclosurePanel()}, {@link #setOpen(boolean)} and
+   *             {@link #setHeader(Widget)} instead
    */
+  @Deprecated
   public DisclosurePanel(Widget header, boolean isOpen) {
-    init(isOpen);
+    this();
     setHeader(header);
+    setOpen(isOpen);
   }
 
   public void add(Widget w) {
@@ -365,7 +439,7 @@
    * 
    * @param handler the handler to be added (should not be null)
    * @deprecated Use {@link DisclosurePanel#addOpenHandler(OpenHandler)} and
-   * {@link DisclosurePanel#addCloseHandler(CloseHandler)} instead
+   *             {@link DisclosurePanel#addCloseHandler(CloseHandler)} instead
    */
   @Deprecated
   public void addEventHandler(final DisclosureHandler handler) {
@@ -403,7 +477,7 @@
    * the header widget does provide such access.
    * 
    * @return a reference to the header widget if it implements {@link HasText},
-   * <code>null</code> otherwise
+   *         <code>null</code> otherwise
    */
   public HasText getHeaderTextAccessor() {
     Widget widget = header.getWidget();
@@ -440,8 +514,8 @@
    * Removes an event handler from the panel.
    * 
    * @param handler the handler to be removed
-   * @deprecated Use the {@link HandlerRegistration#removeHandler} method on 
-   * the object returned by an add*Handler method instead
+   * @deprecated Use the {@link HandlerRegistration#removeHandler} method on the
+   *             object returned by an add*Handler method instead
    */
   @Deprecated
   public void removeEventHandler(DisclosureHandler handler) {
@@ -488,7 +562,7 @@
    * Changes the visible state of this <code>DisclosurePanel</code>.
    * 
    * @param isOpen <code>true</code> to open the panel, <code>false</code> to
-   * close
+   *          close
    */
   public void setOpen(boolean isOpen) {
     if (this.isOpen != isOpen) {
@@ -520,17 +594,6 @@
     }
   }
 
-  private void init(boolean isOpen) {
-    initWidget(mainPanel);
-    mainPanel.add(header);
-    mainPanel.add(contentWrapper);
-    DOM.setStyleAttribute(contentWrapper.getElement(), "padding", "0px");
-    DOM.setStyleAttribute(contentWrapper.getElement(), "overflow", "hidden");
-    this.isOpen = isOpen;
-    setStyleName(STYLENAME_DEFAULT);
-    setContentDisplay(false);
-  }
-
   private void setContentDisplay(boolean animate) {
     if (isOpen) {
       removeStyleDependentName(STYLENAME_SUFFIX_CLOSED);
diff --git a/user/src/com/google/gwt/user/client/ui/DisclosurePanelImages.java b/user/src/com/google/gwt/user/client/ui/DisclosurePanelImages.java
index 89497f2..2ef848a 100644
--- a/user/src/com/google/gwt/user/client/ui/DisclosurePanelImages.java
+++ b/user/src/com/google/gwt/user/client/ui/DisclosurePanelImages.java
@@ -18,6 +18,7 @@
 /**
  * An {@link ImageBundle} that provides images for {@link DisclosurePanel}.
  */
+@Deprecated
 public interface DisclosurePanelImages extends ImageBundle {
 
   /**
diff --git a/user/src/com/google/gwt/user/client/ui/DisclosurePanelImagesRTL.java b/user/src/com/google/gwt/user/client/ui/DisclosurePanelImagesRTL.java
index 05872bc..e1ee3f1b 100644
--- a/user/src/com/google/gwt/user/client/ui/DisclosurePanelImagesRTL.java
+++ b/user/src/com/google/gwt/user/client/ui/DisclosurePanelImagesRTL.java
@@ -20,6 +20,7 @@
  * only need to override the disclosurePanelClosed() method, as the image that we provide
  * for disclosurePanelOpen() is direction-agnostic.
  */
+@Deprecated
 public interface DisclosurePanelImagesRTL extends DisclosurePanelImages {
   /**
    * An image indicating a closed disclosure panel for a RTL context.