Fix for issue #897; prevents IE from throwing an exception when trying to set focus on a hidden/detached widget.  Also does some yummy refactoring goodness.

Review by: knorton, jgw (postmortem)


git-svn-id: https://google-web-toolkit.googlecode.com/svn/trunk@1059 8db76d5a-ed1c-0410-87a9-c151d255dfc7
diff --git a/user/src/com/google/gwt/user/Focus.gwt.xml b/user/src/com/google/gwt/user/Focus.gwt.xml
index 35e95b0..300320a 100644
--- a/user/src/com/google/gwt/user/Focus.gwt.xml
+++ b/user/src/com/google/gwt/user/Focus.gwt.xml
@@ -20,7 +20,7 @@
 	<inherits name="com.google.gwt.core.Core"/>
 	<inherits name="com.google.gwt.user.UserAgent"/>
 
-	<!-- Safari and old mozillae need a different implementation -->
+	<!-- Safari, old Mozilla, and Opera need a different implementation -->
 	<replace-with class="com.google.gwt.user.client.ui.impl.FocusImplOld">
 		<when-type-is class="com.google.gwt.user.client.ui.impl.FocusImpl"/>
 		<any>
@@ -29,4 +29,13 @@
 			<when-property-is name="user.agent" value="opera"/>
  	    </any>
 	</replace-with>
+
+	<!-- IE's implementation traps exceptions on invalid setFocus() -->
+	<replace-with class="com.google.gwt.user.client.ui.impl.FocusImplIE6">
+		<when-type-is class="com.google.gwt.user.client.ui.impl.FocusImpl"/>
+		<any>
+		    <when-property-is name="user.agent" value="ie6"/>
+ 	    </any>
+	</replace-with>
+
 </module>
diff --git a/user/src/com/google/gwt/user/client/ui/FocusPanel.java b/user/src/com/google/gwt/user/client/ui/FocusPanel.java
index b2f3f1a..843bb9a 100644
--- a/user/src/com/google/gwt/user/client/ui/FocusPanel.java
+++ b/user/src/com/google/gwt/user/client/ui/FocusPanel.java
@@ -15,7 +15,6 @@
  */
 package com.google.gwt.user.client.ui;
 
-import com.google.gwt.core.client.GWT;
 import com.google.gwt.user.client.DOM;
 import com.google.gwt.user.client.Event;
 import com.google.gwt.user.client.ui.impl.FocusImpl;
@@ -27,7 +26,7 @@
 public class FocusPanel extends SimplePanel implements HasFocus,
     SourcesClickEvents, SourcesMouseEvents, SourcesMouseWheelEvents {
 
-  static final FocusImpl impl = (FocusImpl) GWT.create(FocusImpl.class);
+  static final FocusImpl impl = FocusImpl.getFocusImplForPanel();
 
   private ClickListenerCollection clickListeners;
   private FocusListenerCollection focusListeners;
diff --git a/user/src/com/google/gwt/user/client/ui/FocusWidget.java b/user/src/com/google/gwt/user/client/ui/FocusWidget.java
index 9ff3b9b..195d39e 100644
--- a/user/src/com/google/gwt/user/client/ui/FocusWidget.java
+++ b/user/src/com/google/gwt/user/client/ui/FocusWidget.java
@@ -1,5 +1,5 @@
 /*
- * Copyright 2006 Google Inc.
+ * Copyright 2007 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
@@ -26,14 +26,7 @@
 public abstract class FocusWidget extends Widget implements SourcesClickEvents,
     SourcesFocusEvents, HasFocus {
 
-  /**
-   * <code>FocusImpl</code> contains browser specific focus code for focusable
-   * widgets. This <code>FocusImpl</code> instance is intentionally _not_
-   * rebound, as the base implementation works on all browsers for truly
-   * focusable widgets. The special cases are only needed for things that aren't
-   * naturally focusable on some browsers, such as DIVs.
-   */
-  private static final FocusImpl impl = new FocusImpl();
+  private static final FocusImpl impl = FocusImpl.getFocusImplForWidget();
 
   /**
    * Gets the FocusImpl instance.
diff --git a/user/src/com/google/gwt/user/client/ui/impl/FocusImpl.java b/user/src/com/google/gwt/user/client/ui/impl/FocusImpl.java
index 2426cb4..9e71e69 100644
--- a/user/src/com/google/gwt/user/client/ui/impl/FocusImpl.java
+++ b/user/src/com/google/gwt/user/client/ui/impl/FocusImpl.java
@@ -1,5 +1,5 @@
 /*
- * Copyright 2006 Google Inc.
+ * Copyright 2007 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
@@ -15,6 +15,7 @@
  */
 package com.google.gwt.user.client.ui.impl;
 
+import com.google.gwt.core.client.GWT;
 import com.google.gwt.user.client.Element;
 
 /**
@@ -22,6 +23,42 @@
  * that aren't naturally focusable in all browsers, such as DIVs.
  */
 public class FocusImpl {
+  
+  private static FocusImpl implPanel = (FocusImpl) GWT.create(FocusImpl.class);
+
+  /**
+   * This instance may not be a {@link FocusImplOld}, because that special case
+   * is only needed for things that aren't naturally focusable on some browsers,
+   * such as DIVs. This exact class works for truly focusable widgets on those
+   * browsers.
+   * 
+   * The compiler will optimize out the conditional.
+   */
+  private static FocusImpl implWidget = (implPanel instanceof FocusImplOld)
+      ? new FocusImpl() : implPanel;
+  
+  /**
+   * Returns the focus implementation class for creating and manipulating
+   * focusable elements that aren't naturally focusable in all browsers, such as
+   * DIVs.
+   */
+  public static FocusImpl getFocusImplForPanel() {
+    return implPanel;
+  }
+  
+  /**
+   * Returns the focus implementation class for manipulating focusable elements
+   * that are naturally focusable in all browsers, such as text boxes.
+   */
+  public static FocusImpl getFocusImplForWidget() {
+    return implWidget;
+  }
+  
+  /**
+   * Not externally instantiable or extensible. 
+   */
+  FocusImpl() {
+  }
 
   public native void blur(Element elem) /*-{
     elem.blur();
diff --git a/user/src/com/google/gwt/user/client/ui/impl/FocusImplIE6.java b/user/src/com/google/gwt/user/client/ui/impl/FocusImplIE6.java
new file mode 100644
index 0000000..88c58d8
--- /dev/null
+++ b/user/src/com/google/gwt/user/client/ui/impl/FocusImplIE6.java
@@ -0,0 +1,38 @@
+/*

+ * Copyright 2007 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.impl;

+

+import com.google.gwt.user.client.Element;

+

+/**

+ * Implementation of {@link com.google.gwt.user.client.ui.impl.FocusImpl}

+ * for IE that traps invalid focus attempts to match other browsers.

+ */

+public class FocusImplIE6 extends FocusImpl {

+

+  public native void focus(Element elem) /*-{

+    try {

+      elem.focus();

+    } catch (e) {

+      // Only trap the exception if the attempt was mostly legit

+      if (!elem || !elem.focus) {

+        // Rethrow the probable NPE or invalid type

+        throw e;

+      }

+    }

+  }-*/;

+

+}