Adds an option to SplitLayoutPanel to hide a widget when its splitter is double clicked.  We set the width to 0 instead of hiding the widget because hiding a widget can cause issues with flash components.

Also adds a method DockLayoutPanel#setWidgetHidden() which allows users to hide a widget in a DockLayoutPanel.  The existance of a "hidden" field in LayoutData suggests that we intended to support this functionality but never got around to it.

http://gwt-code-reviews.appspot.com/1398801/

Author: antoine.dessaigne
Reviewer: jlabanca
Issue: 5264


git-svn-id: https://google-web-toolkit.googlecode.com/svn/trunk@10896 8db76d5a-ed1c-0410-87a9-c151d255dfc7
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 29ef48e..654927d 100644
--- a/user/src/com/google/gwt/user/client/ui/DockLayoutPanel.java
+++ b/user/src/com/google/gwt/user/client/ui/DockLayoutPanel.java
@@ -396,6 +396,24 @@
 
     return removed;
   }
+  
+  /**
+   * Sets whether or not the given widget should be hidden.
+   * 
+   * @param widget the widget to hide or display
+   * @param hidden true to hide the widget, false to display it
+   */
+  public void setWidgetHidden(Widget widget, boolean hidden) {
+    assertIsChild(widget);
+    
+    LayoutData data = (LayoutData) widget.getLayoutData();
+    if (data.hidden == hidden) {
+      return;
+    }
+    
+    data.hidden = hidden;
+    animate(0);
+  }
 
   /**
    * Updates the size of the widget passed in as long as it is not the center
@@ -532,6 +550,11 @@
       LayoutData data = (LayoutData) child.getLayoutData();
       Layer layer = data.layer;
 
+      if (data.hidden) {
+        layer.setVisible(false);
+        continue;
+      }
+
       switch (getResolvedDirection(data.direction)) {
         case NORTH:
           layer.setLeftRight(left, unit, right, unit);
@@ -562,6 +585,9 @@
           layer.setTopBottom(top, unit, bottom, unit);
           break;
       }
+
+      // First set the size, then ensure it's visible
+      layer.setVisible(true);
     }
 
     filledWidth = left + right;
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 0a2422f..aaca39f 100644
--- a/user/src/com/google/gwt/user/client/ui/SplitLayoutPanel.java
+++ b/user/src/com/google/gwt/user/client/ui/SplitLayoutPanel.java
@@ -15,6 +15,7 @@
  */
 package com.google.gwt.user.client.ui;
 
+import com.google.gwt.core.client.Duration;
 import com.google.gwt.core.client.Scheduler;
 import com.google.gwt.core.client.Scheduler.ScheduledCommand;
 import com.google.gwt.dom.client.Document;
@@ -101,6 +102,9 @@
     private int minSize;
 
     private double centerSize, syncedCenterSize;
+    
+    private boolean toggleDisplayAllowed = false;
+    private double lastClick = 0;
 
     public Splitter(Widget target, boolean reverse) {
       this.target = target;
@@ -138,6 +142,29 @@
           mouseDown = false;
 
           glassElem.removeFromParent();
+          
+          // Handle double-clicks.
+          // Fake them since the double-click event aren't fired.
+          if (this.toggleDisplayAllowed) {
+            double now = Duration.currentTimeMillis();
+            if (now - this.lastClick < DOUBLE_CLICK_TIMEOUT) {
+              now = 0;
+              LayoutData layout = (LayoutData) target.getLayoutData();
+              if (layout.size == 0) {
+                // Restore the old size.
+                setAssociatedWidgetSize(layout.oldSize);
+              } else {
+                /*
+                 * Collapse to size 0. We change the size instead of hiding the
+                 * widget because hiding the widget can cause issues if the
+                 * widget contains a flash component.
+                 */
+                layout.oldSize = layout.size;
+                setAssociatedWidgetSize(0);
+              }
+            }
+            this.lastClick = now;
+          }
 
           Event.releaseCapture(getElement());
           event.preventDefault();
@@ -152,6 +179,7 @@
             } else {
               size = getEventPosition(event) - getTargetPosition() - offset;
             }
+            ((LayoutData) target.getLayoutData()).hidden = false;
             setAssociatedWidgetSize(size);
             event.preventDefault();
           }
@@ -167,6 +195,10 @@
       // minSize value.
       setAssociatedWidgetSize((int) layout.size);
     }
+    
+    public void setToggleDisplayAllowed(boolean allowed) {
+      this.toggleDisplayAllowed = allowed;
+    }
 
     protected abstract int getAbsolutePosition();
 
@@ -215,6 +247,7 @@
       // mouse events before layout/paint occurs, we'll only update once.
       if (layoutCommand == null) {
         layoutCommand = new Command() {
+          @Override
           public void execute() {
             layoutCommand = null;
             forceLayout();
@@ -259,6 +292,7 @@
   }
 
   private static final int DEFAULT_SPLITTER_SIZE = 8;
+  private static final int DOUBLE_CLICK_TIMEOUT = 500;
 
   /**
    * The element that masks the screen so we can catch mouse events over
@@ -358,6 +392,22 @@
       splitter.setMinSize(minSize);
     }
   }
+  
+  /**
+   * Sets whether or not double-clicking on the splitter should toggle the
+   * display of the widget.
+   * 
+   * @param child the child whose display toggling will be allowed or not.
+   * @param allowed whether or not display toggling is allowed for this widget
+   */
+  public void setWidgetToggleDisplayAllowed(Widget child, boolean allowed) {
+    assertIsChild(child);
+    Splitter splitter = getAssociatedSplitter(child);
+    // The splitter is null for the center element.
+    if (splitter != null) {
+      splitter.setToggleDisplayAllowed(allowed);
+    }
+  }
 
   private Splitter getAssociatedSplitter(Widget child) {
     // If a widget has a next sibling, it must be a splitter, because the only