Added a new TitledPanel Widget that uses the HTML fieldset element to create a nicely bordered container around a Widget.

Issue: 1614
Patch by: jlabanca
Review by: jgw


git-svn-id: https://google-web-toolkit.googlecode.com/svn/trunk@1784 8db76d5a-ed1c-0410-87a9-c151d255dfc7
diff --git a/user/src/com/google/gwt/user/TitledPanel.gwt.xml b/user/src/com/google/gwt/user/TitledPanel.gwt.xml
new file mode 100644
index 0000000..785daf4
--- /dev/null
+++ b/user/src/com/google/gwt/user/TitledPanel.gwt.xml
@@ -0,0 +1,37 @@
+<!--                                                                        -->
+<!-- Copyright 2008 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   -->
+<!-- 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. License for the specific language governing permissions and   -->
+<!-- limitations under the License.                                         -->
+
+<!-- Deferred binding rules for browser selection.                          -->
+<!--                                                                        -->
+<!-- This module is typically inherited via com.google.gwt.user.User        -->
+<!--                                                                        -->
+<module>
+  <inherits name="com.google.gwt.core.Core"/>
+  <inherits name="com.google.gwt.user.UserAgent"/>
+
+  <!-- Mozilla has a different implementation to handle rendering issues -->
+  <replace-with class="com.google.gwt.user.client.ui.TitledPanel.TitledPanelImplMozilla">
+    <when-type-is class="com.google.gwt.user.client.ui.TitledPanel.TitledPanelImpl"/>
+    <any>
+      <when-property-is name="user.agent" value="gecko"/>
+      <when-property-is name="user.agent" value="gecko1_8"/>
+    </any>
+  </replace-with>
+
+  <!-- Safari has a different implementation to handle rendering issues -->
+  <replace-with class="com.google.gwt.user.client.ui.TitledPanel.TitledPanelImplSafari">
+    <when-type-is class="com.google.gwt.user.client.ui.TitledPanel.TitledPanelImpl"/>
+    <when-property-is name="user.agent" value="safari"/>
+  </replace-with>
+</module>
diff --git a/user/src/com/google/gwt/user/User.gwt.xml b/user/src/com/google/gwt/user/User.gwt.xml
index c6364d9..252649e 100644
--- a/user/src/com/google/gwt/user/User.gwt.xml
+++ b/user/src/com/google/gwt/user/User.gwt.xml
@@ -1,5 +1,5 @@
 <!--
-  Copyright 2007 Google Inc.
+  Copyright 2008 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
@@ -32,4 +32,5 @@
    <inherits name="com.google.gwt.user.RichText"/>
    <inherits name="com.google.gwt.user.SplitPanel"/>
    <inherits name="com.google.gwt.user.ListBox" />
+   <inherits name="com.google.gwt.user.TitledPanel" />
 </module>
diff --git a/user/src/com/google/gwt/user/client/ui/TitledPanel.java b/user/src/com/google/gwt/user/client/ui/TitledPanel.java
new file mode 100644
index 0000000..4135875
--- /dev/null
+++ b/user/src/com/google/gwt/user/client/ui/TitledPanel.java
@@ -0,0 +1,127 @@
+/*
+ * Copyright 2008 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.user.client.ui;
+
+import com.google.gwt.core.client.GWT;
+import com.google.gwt.user.client.Command;
+import com.google.gwt.user.client.DOM;
+import com.google.gwt.user.client.DeferredCommand;
+import com.google.gwt.user.client.Element;
+
+/**
+ * A panel that wraps its contents in a border with a title that appears in the
+ * upper left corner of the border. This is an implementation of the fieldset
+ * HTML element.
+ */
+public class TitledPanel extends SimplePanel {
+  /**
+   * Implementation class for TitledPanel.
+   */
+  public static class TitledPanelImpl {
+    public void setCaption(Element fieldset, Element legend, String caption) {
+      if ((caption != "") && (caption != null)) {
+        DOM.setInnerHTML(legend, caption);
+        DOM.insertChild(fieldset, legend, 0);
+      } else if (DOM.getParent(legend) != null) {
+        DOM.removeChild(fieldset, legend);
+      }
+    }
+  }
+
+  /**
+   * Implementation class for TitledPanel that handles Mozilla rendering issues.
+   */
+  public static class TitledPanelImplMozilla extends TitledPanelImpl {
+    @Override
+    public void setCaption(final Element fieldset, Element legend, String caption) {
+      DOM.setStyleAttribute(fieldset, "display", "none");
+      super.setCaption(fieldset, legend, caption);
+      DOM.setStyleAttribute(fieldset, "display", "");
+    }
+  }
+  
+  /**
+   * Implementation class for TitledPanel that handles Safari rendering issues.
+   */
+  public static class TitledPanelImplSafari extends TitledPanelImpl {
+    @Override
+    public void setCaption(final Element fieldset, Element legend, String caption) {
+      DOM.setStyleAttribute(fieldset, "visibility", "hidden");
+      super.setCaption(fieldset, legend, caption);
+      DeferredCommand.addCommand(new Command() {
+        public void execute() {
+          DOM.setStyleAttribute(fieldset, "visibility", "");
+        }
+      });
+    }
+  }
+
+  /**
+   * The implementation instance.
+   */
+  private static TitledPanelImpl impl = (TitledPanelImpl) GWT.create(TitledPanelImpl.class);
+
+  /**
+   * The legend used as the title.
+   */
+  private Element legend;
+
+  /**
+   * The title at the top of the border.
+   */
+  private String caption;
+
+  /**
+   * Constructor.
+   * 
+   * @param caption the title to display
+   */
+  public TitledPanel(String caption) {
+    super(DOM.createElement("fieldset"));
+    legend = DOM.createElement("legend");
+    DOM.appendChild(getElement(), legend);
+    setCaption(caption);
+  }
+
+  /**
+   * Constructor.
+   * 
+   * @param caption the title to display
+   * @param w the widget to add to the panel
+   */
+  public TitledPanel(String caption, Widget w) {
+    this(caption);
+    setWidget(w);
+  }
+
+  /**
+   * @return the title on top of the border
+   */
+  public String getCaption() {
+    return this.caption;
+  }
+
+  /**
+   * Set the title in the border. Pass in null or an empty string to remove the
+   * title completely, leaving just a box.
+   * 
+   * @param caption the new title
+   */
+  public void setCaption(String caption) {
+    this.caption = caption;
+    impl.setCaption(getElement(), legend, caption);
+  }
+}
diff --git a/user/test/com/google/gwt/user/UISuite.java b/user/test/com/google/gwt/user/UISuite.java
index 4551140..3391780 100644
--- a/user/test/com/google/gwt/user/UISuite.java
+++ b/user/test/com/google/gwt/user/UISuite.java
@@ -46,6 +46,7 @@
 import com.google.gwt.user.client.ui.TabBarTest;
 import com.google.gwt.user.client.ui.TabPanelTest;
 import com.google.gwt.user.client.ui.TextAreaTest;
+import com.google.gwt.user.client.ui.TitledPanelTest;
 import com.google.gwt.user.client.ui.TreeTest;
 import com.google.gwt.user.client.ui.UIObjectTest;
 import com.google.gwt.user.client.ui.VerticalPanelTest;
@@ -96,6 +97,7 @@
     suite.addTestSuite(TabBarTest.class);
     suite.addTestSuite(TabPanelTest.class);
     suite.addTestSuite(TextAreaTest.class);
+    suite.addTestSuite(TitledPanelTest.class);
     suite.addTestSuite(TreeTest.class);
     suite.addTestSuite(UIObjectTest.class);
     suite.addTestSuite(VerticalPanelTest.class);
diff --git a/user/test/com/google/gwt/user/client/ui/TitledPanelTest.java b/user/test/com/google/gwt/user/client/ui/TitledPanelTest.java
new file mode 100644
index 0000000..1b28a29
--- /dev/null
+++ b/user/test/com/google/gwt/user/client/ui/TitledPanelTest.java
@@ -0,0 +1,74 @@
+/*
+ * Copyright 2008 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.user.client.ui;
+
+import com.google.gwt.junit.client.GWTTestCase;
+import com.google.gwt.user.client.DOM;
+
+/**
+ * Tests {@link TitledPanel}.
+ */
+public class TitledPanelTest extends GWTTestCase {
+
+  @Override
+  public String getModuleName() {
+    return "com.google.gwt.user.User";
+  }
+  
+  /**
+   * Test the basic setting and getting of the title.
+   */
+  public void testSetCaption() {
+    // Null title
+    TitledPanel panel1 = new TitledPanel(null);
+    assertNull(panel1.getCaption());
+    assertNull(DOM.getFirstChild(panel1.getElement()));
+    panel1.setCaption("");
+    assertEquals("", panel1.getCaption());
+    assertNull(DOM.getFirstChild(panel1.getElement()));
+    
+    // Actual title
+    TitledPanel panel2 = new TitledPanel("my panel2");
+    assertEquals("my panel2", panel2.getCaption());
+    assertNotNull(DOM.getFirstChild(panel2.getElement()));
+    panel2.setCaption("my cool panel 2");
+    assertEquals("my cool panel 2", panel2.getCaption());
+    assertNotNull(DOM.getFirstChild(panel2.getElement()));
+  }
+  
+  /**
+   * Test the setting and removal of a widget.
+   */
+  public void testSetWidget() {
+    // No Widget constructor
+    TitledPanel panel1 = new TitledPanel("no widget");
+    assertNull(panel1.getWidget());
+    
+    // Widget constructor
+    HTML widget2 = new HTML("widget 2");
+    TitledPanel panel2 = new TitledPanel("has widget", widget2);
+    assertEquals(widget2, panel2.getWidget());
+    
+    // Set widget
+    HTML widget3 = new HTML("widget 3");
+    TitledPanel panel3 = new TitledPanel("set widget", null);
+    assertNull(panel3.getWidget());
+    panel3.setWidget(widget3);
+    assertEquals(widget3, panel3.getWidget());
+    panel3.remove(widget3);
+    assertNull(panel3.getWidget());
+  }
+}