Merging releases/1.5 into trunk

svn merge -r3372:3391 https://google-web-toolkit.googlecode.com/svn/releases/1.5 .



git-svn-id: https://google-web-toolkit.googlecode.com/svn/trunk@3395 8db76d5a-ed1c-0410-87a9-c151d255dfc7
diff --git a/dev/core/src/com/google/gwt/dev/shell/ModuleSpace.java b/dev/core/src/com/google/gwt/dev/shell/ModuleSpace.java
index c381889..1671046 100644
--- a/dev/core/src/com/google/gwt/dev/shell/ModuleSpace.java
+++ b/dev/core/src/com/google/gwt/dev/shell/ModuleSpace.java
@@ -22,6 +22,10 @@
 import java.lang.reflect.InvocationTargetException;
 import java.lang.reflect.Method;
 import java.lang.reflect.Modifier;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.ListIterator;
 
 /**
  * The interface to the low-level browser, this class serves as a 'domain' for a
@@ -103,6 +107,15 @@
       caught = (Throwable) exception;
     } else {
       caught = createJavaScriptException(getIsolatedClassLoader(), exception);
+      // Remove excess stack frames from the new exception.
+      caught.fillInStackTrace();
+      StackTraceElement[] trace = caught.getStackTrace();
+      assert trace.length > 1;
+      assert trace[1].getClassName().equals(JavaScriptHost.class.getName());
+      assert trace[1].getMethodName().equals("exceptionCaught");
+      StackTraceElement[] newTrace = new StackTraceElement[trace.length - 1];
+      System.arraycopy(trace, 1, newTrace, 0, newTrace.length);
+      caught.setStackTrace(newTrace);
     }
     sCaughtJavaExceptionObject.set(caught);
   }
@@ -439,12 +452,7 @@
     }
     sCaughtJavaExceptionObject.set(null);
 
-    /*
-     * The stack trace on the stored exception will not be very useful due to
-     * how it was created. Using fillInStackTrace() resets the stack trace to
-     * this moment in time, which is usually far more useful.
-     */
-    thrown.fillInStackTrace();
+    scrubStackTrace(thrown);
     throw thrown;
   }
 
@@ -475,6 +483,28 @@
     return "Something other than " + typePhrase + " was returned from JSNI method '" + name + "'";
   }
 
+  private boolean isUserFrame(StackTraceElement element) {
+    try {
+      CompilingClassLoader cl = getIsolatedClassLoader();
+      String className = element.getClassName();
+      Class<?> clazz = Class.forName(className, false, cl);
+      if (clazz.getClassLoader() == cl) {
+        // Lives in user classLoader.
+        return true;
+      }
+      // At this point, it must be a JRE class to qualify.
+      if (clazz.getClassLoader() != null || !className.startsWith("java.")) {
+        return false;
+      }
+      if (className.startsWith("java.lang.reflect.")) {
+        return false;
+      }
+      return true;
+    } catch (ClassNotFoundException e) {
+      return false;
+    }
+  }
+
   /**
    * Handles loading a class that might be nested given a source type name.
    */
@@ -496,4 +526,44 @@
       }
     }
   }
+
+  /**
+   * Clean up the stack trace by removing our hosting frames. But don't do this
+   * if our own frames are at the top of the stack, because we may be the real
+   * cause of the exception.
+   */
+  private void scrubStackTrace(Throwable thrown) {
+    List<StackTraceElement> trace = new ArrayList<StackTraceElement>(
+        Arrays.asList(thrown.getStackTrace()));
+    boolean seenUserFrame = false;
+    for (ListIterator<StackTraceElement> it = trace.listIterator(); it.hasNext();) {
+      StackTraceElement element = it.next();
+      if (!isUserFrame(element)) {
+        if (seenUserFrame) {
+          it.remove();
+        }
+        continue;
+      }
+      seenUserFrame = true;
+
+      // Remove a JavaScriptHost.invokeNative*() frame.
+      if (element.getClassName().equals(JavaScriptHost.class.getName())) {
+        if (element.getMethodName().equals("exceptionCaught")) {
+          it.remove();
+        } else if (element.getMethodName().startsWith("invokeNative")) {
+          it.remove();
+          // Also try to convert the next frame to a true native.
+          if (it.hasNext()) {
+            StackTraceElement next = it.next();
+            if (next.getLineNumber() == -1) {
+              next = new StackTraceElement(next.getClassName(),
+                  next.getMethodName(), next.getFileName(), -2);
+              it.set(next);
+            }
+          }
+        }
+      }
+    }
+    thrown.setStackTrace(trace.toArray(new StackTraceElement[trace.size()]));
+  }
 }
diff --git a/dev/core/src/com/google/gwt/dev/util/log/AbstractTreeLogger.java b/dev/core/src/com/google/gwt/dev/util/log/AbstractTreeLogger.java
index af2f497..6d648dc 100644
--- a/dev/core/src/com/google/gwt/dev/util/log/AbstractTreeLogger.java
+++ b/dev/core/src/com/google/gwt/dev/util/log/AbstractTreeLogger.java
@@ -17,7 +17,6 @@
 
 import com.google.gwt.core.ext.TreeLogger;
 
-import java.util.ArrayList;
 import java.util.HashSet;
 
 /**
@@ -56,12 +55,11 @@
     while (currentCause != null && !seenCauses.contains(currentCause)) {
       seenCauses.add(currentCause);
 
-      StackTraceElement[] trace = currentCause.getStackTrace();
       message.append(causedBy);
       causedBy = "\nCaused by: "; // after 1st, all say "caused by"
       message.append(currentCause.getClass().getName());
       message.append(": " + currentCause.getMessage());
-      StackTraceElement[] stackElems = findMeaningfulStackTraceElements(trace);
+      StackTraceElement[] stackElems = currentCause.getStackTrace();
       if (stackElems != null) {
         for (int i = 0; i < stackElems.length; ++i) {
           message.append("\n\tat ");
@@ -74,31 +72,6 @@
     return message.toString();
   }
 
-  private static StackTraceElement[] findMeaningfulStackTraceElements(
-      StackTraceElement[] elems) {
-    ArrayList<StackTraceElement> goodElems = new ArrayList<StackTraceElement>();
-    StackTraceElement prevElem = null;
-    for (int i = 0; i < elems.length; i++) {
-      StackTraceElement elem = elems[i];
-      if (elem.getLineNumber() > 0) {
-        goodElems.add(elem);
-        if (goodElems.size() < 10
-            || prevElem.getClassName().equals(elem.getClassName())) {
-          // Keep going.
-          prevElem = elem;
-        } else {
-          // That's enough.
-          break;
-        }
-      }
-    }
-    if (goodElems.size() > 0) {
-      return goodElems.toArray(new StackTraceElement[goodElems.size()]);
-    } else {
-      return null;
-    }
-  }
-
   public int indexWithinMyParent;
 
   private TreeLogger.Type logLevel = TreeLogger.ALL;
diff --git a/user/src/com/google/gwt/user/client/ui/DeckPanel.java b/user/src/com/google/gwt/user/client/ui/DeckPanel.java
index 273edb5..9d65a5d 100644
--- a/user/src/com/google/gwt/user/client/ui/DeckPanel.java
+++ b/user/src/com/google/gwt/user/client/ui/DeckPanel.java
@@ -63,6 +63,11 @@
     private int fixedHeight = -1;
 
     /**
+     * The old {@link Widget} that is being hidden.
+     */
+    private Widget oldWidget = null;
+
+    /**
      * Switch to a new {@link Widget}.
      * 
      * @param oldWidget the {@link Widget} to hide
@@ -84,6 +89,7 @@
         newWidget.setVisible(true);
         return;
       }
+      this.oldWidget = oldWidget;
 
       // Get the container and index of the old widget
       Element oldContainer = getContainer(oldWidget);
@@ -132,6 +138,7 @@
       DOM.setStyleAttribute(container2, "overflow", "visible");
       container1 = null;
       container2 = null;
+      hideOldWidget();
     }
 
     @Override
@@ -190,11 +197,22 @@
       DOM.setStyleAttribute(container2, "height", height2 + "px");
     }
 
+    /**
+     * Hide the old widget when the animation completes.
+     */
+    private void hideOldWidget() {
+      // Issue 2510: Hiding the widget isn't necessary because we hide its
+      // wrapper, but its in here for legacy support.
+      oldWidget.setVisible(false);
+      oldWidget = null;
+    }
+
     private void onInstantaneousRun() {
       UIObject.setVisible(container1, growing);
       UIObject.setVisible(container2, !growing);
       container1 = null;
       container2 = null;
+      hideOldWidget();
     }
   }
 
@@ -335,6 +353,10 @@
     UIObject.setVisible(container, false);
     DOM.setStyleAttribute(container, "height", "100%");
     w.setSize("100%", "100%");
+
+    // Issue 2510: Hiding the widget isn't necessary because we hide its
+    // wrapper, but it's in here for legacy support.
+    w.setVisible(false);
   }
 
   /**
@@ -342,5 +364,6 @@
    */
   private void resetChildWidget(Widget w) {
     w.setSize("", "");
+    w.setVisible(true);
   }
 }
diff --git a/user/src/com/google/gwt/user/client/ui/Tree.java b/user/src/com/google/gwt/user/client/ui/Tree.java
index 334f166..7d92b6d 100644
--- a/user/src/com/google/gwt/user/client/ui/Tree.java
+++ b/user/src/com/google/gwt/user/client/ui/Tree.java
@@ -797,7 +797,7 @@
     collectElementChain(chain, getElement(), hElem);
 
     TreeItem item = findItemByChain(chain, 0, root);
-    if (item != null) {
+    if (item != null && item != root) {
       if (item.getChildCount() > 0
           && DOM.isOrHasChild(item.getImageElement(), hElem)) {
         item.setState(!item.getState(), true);
@@ -993,8 +993,6 @@
 
   /**
    * Move the tree focus to the specified selected item.
-   * 
-   * @param
    */
   private void moveFocus() {
     HasFocus focusableWidget = curSelection.getFocusableWidget();
diff --git a/user/src/com/google/gwt/user/theme/dark/public/gwt/dark/dark.css b/user/src/com/google/gwt/user/theme/dark/public/gwt/dark/dark.css
index 44e114a..7be80e9 100644
--- a/user/src/com/google/gwt/user/theme/dark/public/gwt/dark/dark.css
+++ b/user/src/com/google/gwt/user/theme/dark/public/gwt/dark/dark.css
@@ -19,6 +19,9 @@
   font-size: small;
   color: #bec7cc;
 }
+select {
+  color: #000;
+}
 pre {
   font-family: "courier new", courier;
   font-size: small;
diff --git a/user/src/com/google/gwt/user/theme/dark/public/gwt/dark/dark_rtl.css b/user/src/com/google/gwt/user/theme/dark/public/gwt/dark/dark_rtl.css
index 356e11e..8a27178 100644
--- a/user/src/com/google/gwt/user/theme/dark/public/gwt/dark/dark_rtl.css
+++ b/user/src/com/google/gwt/user/theme/dark/public/gwt/dark/dark_rtl.css
@@ -19,6 +19,9 @@
   font-size: small;
   color: #bec7cc;
 }
+select {
+  color: #000;
+}
 pre {
   font-family: "courier new", courier;
   font-size: small;
diff --git a/user/super/com/google/gwt/emul/java/util/Collections.java b/user/super/com/google/gwt/emul/java/util/Collections.java
index e0e5ef4..7ad66e8 100644
--- a/user/super/com/google/gwt/emul/java/util/Collections.java
+++ b/user/super/com/google/gwt/emul/java/util/Collections.java
@@ -15,63 +15,423 @@
  */
 package java.util;
 
+import java.io.Serializable;
+
 /**
  * Utility methods that operate on collections. <a
  * href="http://java.sun.com/j2se/1.5.0/docs/api/java/util/Collections.html">[Sun
  * docs]</a>
  */
 public class Collections {
-
-  /**
-   * Used to implement iterators on unmodifiable lists.
-   * 
-   * @param <E> element type.
+  /*
+   * TODO: make the unmodifiable collections serializable.
    */
-  private static class UnmodifiableListIterator<E> implements ListIterator<E> {
 
-    final ListIterator<? extends E> it;
+  static class UnmodifiableCollection<T> implements Collection<T> {
+    protected final Collection<? extends T> coll;
 
-    public UnmodifiableListIterator(ListIterator<? extends E> it) {
-      this.it = it;
+    public UnmodifiableCollection(Collection<? extends T> coll) {
+      this.coll = coll;
     }
 
-    public void add(E o) {
-      throw new UnsupportedOperationException(
-          "UnmodifiableListIterator: add not permitted");
+    public boolean add(T o) {
+      throw new UnsupportedOperationException();
+    }
+
+    public boolean addAll(Collection<? extends T> c) {
+      throw new UnsupportedOperationException();
+    }
+
+    public void clear() {
+      throw new UnsupportedOperationException();
+    }
+
+    public boolean contains(Object o) {
+      return coll.contains(o);
+    }
+
+    public boolean containsAll(Collection<?> c) {
+      return coll.containsAll(c);
+    }
+
+    public boolean isEmpty() {
+      return coll.isEmpty();
+    }
+
+    public Iterator<T> iterator() {
+      return new UnmodifiableCollectionIterator<T>(coll.iterator());
+    }
+
+    public boolean remove(Object o) {
+      throw new UnsupportedOperationException();
+    }
+
+    public boolean removeAll(Collection<?> c) {
+      throw new UnsupportedOperationException();
+    }
+
+    public boolean retainAll(Collection<?> c) {
+      throw new UnsupportedOperationException();
+    }
+
+    public int size() {
+      return coll.size();
+    }
+
+    public Object[] toArray() {
+      return coll.toArray();
+    }
+
+    public <E> E[] toArray(E[] a) {
+      return coll.toArray(a);
+    }
+  }
+
+  static class UnmodifiableList<T> extends UnmodifiableCollection<T> implements
+      List<T> {
+    private final List<? extends T> list;
+
+    public UnmodifiableList(List<? extends T> list) {
+      super(list);
+      this.list = list;
+    }
+
+    public void add(int index, T element) {
+      throw new UnsupportedOperationException();
+    }
+
+    public boolean addAll(int index, Collection<? extends T> c) {
+      throw new UnsupportedOperationException();
+    }
+
+    public T get(int index) {
+      return list.get(index);
+    }
+
+    public int indexOf(Object o) {
+      return list.indexOf(o);
+    }
+
+    public boolean isEmpty() {
+      return list.isEmpty();
+    }
+
+    public int lastIndexOf(Object o) {
+      return list.lastIndexOf(o);
+    }
+
+    public ListIterator<T> listIterator() {
+      return listIterator(0);
+    }
+
+    public ListIterator<T> listIterator(int from) {
+      return new UnmodifiableListIterator<T>(list.listIterator(from));
+    }
+
+    public T remove(int index) {
+      throw new UnsupportedOperationException();
+    }
+
+    public T set(int index, T element) {
+      throw new UnsupportedOperationException();
+    }
+  }
+
+  static class UnmodifiableMap<K, V> implements Map<K, V> {
+
+    static class UnmodifiableEntrySet<K, V> extends
+        UnmodifiableSet<Map.Entry<K, V>> {
+
+      private static class UnmodifiableEntry<K, V> implements Map.Entry<K, V> {
+        private Map.Entry<? extends K, ? extends V> entry;
+
+        public UnmodifiableEntry(Map.Entry<? extends K, ? extends V> entry) {
+          this.entry = entry;
+        }
+
+        public boolean equals(Object o) {
+          return entry.equals(o);
+        }
+
+        public K getKey() {
+          return entry.getKey();
+        }
+
+        public V getValue() {
+          return entry.getValue();
+        }
+
+        public int hashCode() {
+          return entry.hashCode();
+        }
+
+        public V setValue(V value) {
+          throw new UnsupportedOperationException();
+        }
+
+        public String toString() {
+          return entry.toString();
+        }
+      }
+
+      @SuppressWarnings("unchecked")
+      public UnmodifiableEntrySet(
+          Set<? extends Map.Entry<? extends K, ? extends V>> s) {
+        super((Set<? extends Entry<K, V>>) s);
+      }
+
+      public boolean contains(Object o) {
+        return coll.contains(o);
+      }
+
+      public boolean containsAll(Collection<?> o) {
+        return coll.containsAll(o);
+      }
+
+      @SuppressWarnings("unchecked")
+      public Iterator<Map.Entry<K, V>> iterator() {
+        final Iterator<Map.Entry<K, V>> it = (Iterator<Entry<K, V>>) coll.iterator();
+        return new Iterator<Map.Entry<K, V>>() {
+          public boolean hasNext() {
+            return it.hasNext();
+          }
+
+          public Map.Entry<K, V> next() {
+            return new UnmodifiableEntry<K, V>(it.next());
+          }
+
+          public void remove() {
+            throw new UnsupportedOperationException();
+          }
+        };
+      }
+
+      @SuppressWarnings("unchecked")
+      public Object[] toArray() {
+        return toArray(super.toArray());
+      }
+
+      @SuppressWarnings("unchecked")
+      public <T> T[] toArray(T[] a) {
+        Object[] result = super.toArray(a);
+        for (int i = 0, c = result.length; i < c; ++i) {
+          result[i] = new UnmodifiableEntry<K, V>((Map.Entry<K, V>) result[i]);
+        }
+        return (T[]) result;
+      }
+    }
+
+    private final Map<? extends K, ? extends V> map;
+
+    public UnmodifiableMap(Map<? extends K, ? extends V> map) {
+      this.map = map;
+    }
+
+    public void clear() {
+      throw new UnsupportedOperationException();
+    }
+
+    public boolean containsKey(Object key) {
+      return map.containsKey(key);
+    }
+
+    public boolean containsValue(Object val) {
+      return map.containsValue(val);
+    }
+
+    public Set<Map.Entry<K, V>> entrySet() {
+      return new UnmodifiableEntrySet<K, V>(map.entrySet());
+    }
+
+    public boolean equals(Object o) {
+      return map.equals(o);
+    }
+
+    public V get(Object key) {
+      return map.get(key);
+    }
+
+    public int hashCode() {
+      return map.hashCode();
+    }
+
+    public boolean isEmpty() {
+      return map.isEmpty();
+    }
+
+    public Set<K> keySet() {
+      return unmodifiableSet(map.keySet());
+    }
+
+    public V put(K key, V value) {
+      throw new UnsupportedOperationException();
+    }
+
+    public void putAll(Map<? extends K, ? extends V> t) {
+      throw new UnsupportedOperationException();
+    }
+
+    public V remove(Object key) {
+      throw new UnsupportedOperationException();
+    }
+
+    public int size() {
+      return map.size();
+    }
+
+    public String toString() {
+      return map.toString();
+    }
+
+    public Collection<V> values() {
+      return unmodifiableCollection(map.values());
+    }
+  }
+
+  static class UnmodifiableRandomAccessList<T> extends UnmodifiableList<T>
+      implements RandomAccess {
+    public UnmodifiableRandomAccessList(List<? extends T> list) {
+      super(list);
+    }
+  }
+
+  static class UnmodifiableSet<T> extends UnmodifiableCollection<T> implements
+      Set<T> {
+    public UnmodifiableSet(Set<? extends T> set) {
+      super(set);
+    }
+
+    public boolean equals(Object o) {
+      return coll.equals(o);
+    }
+
+    public int hashCode() {
+      return coll.hashCode();
+    }
+  }
+
+  static class UnmodifiableSortedMap<K, V> extends UnmodifiableMap<K, V>
+      implements SortedMap<K, V> {
+
+    private SortedMap<K, ? extends V> sortedMap;
+
+    public UnmodifiableSortedMap(SortedMap<K, ? extends V> sortedMap) {
+      super(sortedMap);
+      this.sortedMap = sortedMap;
+    }
+
+    public Comparator<? super K> comparator() {
+      return sortedMap.comparator();
+    }
+
+    public K firstKey() {
+      return sortedMap.firstKey();
+    }
+
+    public SortedMap<K, V> headMap(K toKey) {
+      return new UnmodifiableSortedMap<K, V>(sortedMap.headMap(toKey));
+    }
+
+    public K lastKey() {
+      return sortedMap.lastKey();
+    }
+
+    public SortedMap<K, V> subMap(K fromKey, K toKey) {
+      return new UnmodifiableSortedMap<K, V>(sortedMap.subMap(fromKey, toKey));
+    }
+
+    public SortedMap<K, V> tailMap(K fromKey) {
+      return new UnmodifiableSortedMap<K, V>(sortedMap.tailMap(fromKey));
+    }
+  }
+
+  static class UnmodifiableSortedSet<E> extends UnmodifiableSet<E> implements
+      SortedSet<E> {
+    private SortedSet<E> sortedSet;
+
+    @SuppressWarnings("unchecked")
+    public UnmodifiableSortedSet(SortedSet<? extends E> sortedSet) {
+      super(sortedSet);
+      this.sortedSet = (SortedSet<E>) sortedSet;
+    }
+
+    public Comparator<? super E> comparator() {
+      return sortedSet.comparator();
+    }
+
+    public E first() {
+      return sortedSet.first();
+    }
+
+    public SortedSet<E> headSet(E toElement) {
+      return new UnmodifiableSortedSet<E>(sortedSet.headSet(toElement));
+    }
+
+    public E last() {
+      return sortedSet.last();
+    }
+
+    public SortedSet<E> subSet(E fromElement, E toElement) {
+      return new UnmodifiableSortedSet<E>(sortedSet.subSet(fromElement,
+          toElement));
+    }
+
+    public SortedSet<E> tailSet(E fromElement) {
+      return new UnmodifiableSortedSet<E>(sortedSet.tailSet(fromElement));
+    }
+  }
+
+  private static class UnmodifiableCollectionIterator<T> implements Iterator<T> {
+    private final Iterator<? extends T> it;
+
+    private UnmodifiableCollectionIterator(Iterator<? extends T> it) {
+      this.it = it;
     }
 
     public boolean hasNext() {
       return it.hasNext();
     }
 
-    public boolean hasPrevious() {
-      return it.hasPrevious();
-    }
-
-    public E next() {
+    public T next() {
       return it.next();
     }
 
-    public int nextIndex() {
-      return it.nextIndex();
+    public void remove() {
+      throw new UnsupportedOperationException();
+    }
+  }
+
+  private static class UnmodifiableListIterator<T> extends
+      UnmodifiableCollectionIterator<T> implements ListIterator<T> {
+    private final ListIterator<? extends T> lit;
+
+    private UnmodifiableListIterator(ListIterator<? extends T> lit) {
+      super(lit);
+      this.lit = lit;
     }
 
-    public E previous() {
-      return it.previous();
+    public void add(T o) {
+      throw new UnsupportedOperationException();
+    }
+
+    public boolean hasPrevious() {
+      return lit.hasPrevious();
+    }
+
+    public int nextIndex() {
+      return lit.nextIndex();
+    }
+
+    public T previous() {
+      return lit.previous();
     }
 
     public int previousIndex() {
-      return it.previousIndex();
+      return lit.previousIndex();
     }
 
-    public void remove() {
-      throw new UnsupportedOperationException(
-          "UnmodifiableListIterator: remove not permitted");
-    }
-
-    public void set(E o) {
-      throw new UnsupportedOperationException(
-          "UnmodifiableListIterator: set not permitted");
+    public void set(T o) {
+      throw new UnsupportedOperationException();
     }
   }
 
@@ -235,17 +595,17 @@
     return true;
   }
 
-  @SuppressWarnings({"unchecked", "cast"})
+  @SuppressWarnings(value = {"unchecked", "cast"})
   public static <T> List<T> emptyList() {
     return (List<T>) EMPTY_LIST;
   }
 
-  @SuppressWarnings({"unchecked", "cast"})
+  @SuppressWarnings(value = {"unchecked", "cast"})
   public static <K, V> Map<K, V> emptyMap() {
     return (Map<K, V>) EMPTY_MAP;
   }
 
-  @SuppressWarnings({"unchecked", "cast"})
+  @SuppressWarnings(value = {"unchecked", "cast"})
   public static <T> Set<T> emptySet() {
     return (Set<T>) EMPTY_SET;
   }
@@ -378,15 +738,15 @@
     };
   }
 
-  // TODO(tobyr) Is it worth creating custom singleton sets, lists, and maps?
-  // More efficient at runtime, but more code bloat to download
-
   public static <T> Set<T> singleton(T o) {
     HashSet<T> set = new HashSet<T>(1);
     set.add(o);
     return unmodifiableSet(set);
   }
 
+  // TODO(tobyr) Is it worth creating custom singleton sets, lists, and maps?
+  // More efficient at runtime, but more code bloat to download
+
   public static <T> List<T> singletonList(T o) {
     List<T> list = new ArrayList<T>(1);
     list.add(o);
@@ -405,6 +765,7 @@
     replaceContents(target, x);
   }
 
+  @SuppressWarnings("unchecked")
   public static <T> void sort(List<T> target, Comparator<? super T> c) {
     Object[] x = target.toArray();
     Arrays.sort(x, (Comparator<Object>) c);
@@ -417,338 +778,30 @@
 
   public static <T> Collection<T> unmodifiableCollection(
       final Collection<? extends T> coll) {
-    return new Collection<T>() {
-
-      public boolean add(T o) {
-        throw new UnsupportedOperationException(
-            "unmodifiableCollection: add not permitted");
-      }
-
-      public boolean addAll(Collection<? extends T> c) {
-        throw new UnsupportedOperationException(
-            "unmodifiableCollection: addAll not permitted");
-      }
-
-      public void clear() {
-        throw new UnsupportedOperationException(
-            "unmodifiableCollection: clear not permitted");
-      }
-
-      public boolean contains(Object o) {
-        return coll.contains(o);
-      }
-
-      public boolean containsAll(Collection<?> c) {
-        return coll.containsAll(c);
-      }
-
-      public boolean isEmpty() {
-        return coll.isEmpty();
-      }
-
-      public Iterator<T> iterator() {
-        final Iterator<? extends T> it = coll.iterator();
-        return new Iterator<T>() {
-
-          public boolean hasNext() {
-            return it.hasNext();
-          }
-
-          public T next() {
-            return it.next();
-          }
-
-          public void remove() {
-            throw new UnsupportedOperationException(
-                "unmodifiableCollection.iterator: remove not permitted");
-          }
-        };
-      }
-
-      public boolean remove(Object o) {
-        throw new UnsupportedOperationException(
-            "unmodifiableCollection: remove not permitted");
-      }
-
-      public boolean removeAll(Collection<?> c) {
-        throw new UnsupportedOperationException(
-            "unmodifiableCollection: removeAll not permitted");
-      }
-
-      public boolean retainAll(Collection<?> c) {
-        throw new UnsupportedOperationException(
-            "unmodifiableCollection: retainAll not permitted");
-      }
-
-      public int size() {
-        return coll.size();
-      }
-
-      public Object[] toArray() {
-        return coll.toArray();
-      }
-
-      public <OT> OT[] toArray(OT[] a) {
-        return coll.toArray(a);
-      }
-    };
+    return new UnmodifiableCollection<T>(coll);
   }
 
   public static <T> List<T> unmodifiableList(final List<? extends T> list) {
-    return new List<T>() {
-      public void add(int index, T element) {
-        throw new UnsupportedOperationException(
-            "unmodifiableList: add not permitted");
-      }
-
-      public boolean add(T o) {
-        throw new UnsupportedOperationException(
-            "unmodifiableList: add not permitted");
-      }
-
-      public boolean addAll(Collection<? extends T> c) {
-        throw new UnsupportedOperationException(
-            "unmodifiableList: addAll not permitted");
-      }
-
-      public boolean addAll(int index, Collection<? extends T> c) {
-        throw new UnsupportedOperationException(
-            "unmodifiableList: addAll not permitted");
-      }
-
-      public void clear() {
-        throw new UnsupportedOperationException(
-            "unmodifiableList: clear not permitted");
-      }
-
-      public boolean contains(Object o) {
-        return list.contains(o);
-      }
-
-      public boolean containsAll(Collection<?> c) {
-        return list.containsAll(c);
-      }
-
-      public T get(int index) {
-        return list.get(index);
-      }
-
-      public int indexOf(Object o) {
-        return list.indexOf(o);
-      }
-
-      public boolean isEmpty() {
-        return list.isEmpty();
-      }
-
-      public Iterator<T> iterator() {
-        return listIterator();
-      }
-
-      public int lastIndexOf(Object o) {
-        return list.lastIndexOf(o);
-      }
-
-      public ListIterator<T> listIterator() {
-        return new UnmodifiableListIterator<T>(list.listIterator());
-      }
-
-      public ListIterator<T> listIterator(int from) {
-        return new UnmodifiableListIterator<T>(list.listIterator(from));
-      }
-
-      public T remove(int index) {
-        throw new UnsupportedOperationException(
-            "unmodifiableList: remove not permitted");
-      }
-
-      public boolean remove(Object o) {
-        throw new UnsupportedOperationException(
-            "unmodifiableList: remove not permitted");
-      }
-
-      public boolean removeAll(Collection<?> c) {
-        throw new UnsupportedOperationException(
-            "unmodifiableList: removeAll not permitted");
-      }
-
-      public boolean retainAll(Collection<?> c) {
-        throw new UnsupportedOperationException(
-            "unmodifiableList: retainAll not permitted");
-      }
-
-      public T set(int index, T element) {
-        throw new UnsupportedOperationException(
-            "unmodifiableList: set not permitted");
-      }
-
-      public int size() {
-        return list.size();
-      }
-
-      // TODO(jat): implement
-//      public List<T> subList(int fromIndex, int toIndex) {
-//      }
-
-      public Object[] toArray() {
-        return list.toArray();
-      }
-
-      public <OT> OT[] toArray(OT[] array) {
-        return list.toArray(array);
-      }
-    };
+    return new UnmodifiableList<T>(list);
   }
 
   public static <K, V> Map<K, V> unmodifiableMap(
       final Map<? extends K, ? extends V> map) {
-    return new Map<K, V>() {
-
-      public void clear() {
-        throw new UnsupportedOperationException(
-            "unmodifiableMap: clear not permitted");
-      }
-
-      public boolean containsKey(Object key) {
-        return map.containsKey(key);
-      }
-
-      public boolean containsValue(Object value) {
-        return map.containsValue(value);
-      }
-
-      public Set<Map.Entry<K, V>> entrySet() {
-        Set<? extends Map.Entry<? extends K, ? extends V>> entrySet = map.entrySet();
-        return (Set<Map.Entry<K, V>>) entrySet;
-      }
-
-      public V get(Object key) {
-        return map.get(key);
-      }
-
-      public boolean isEmpty() {
-        return map.isEmpty();
-      }
-
-      public Set<K> keySet() {
-        return (Set<K>) map.keySet();
-      }
-
-      public V put(K key, V value) {
-        throw new UnsupportedOperationException(
-            "unmodifiableMap: put not permitted");
-      }
-
-      public void putAll(Map<? extends K, ? extends V> t) {
-        throw new UnsupportedOperationException(
-            "unmodifiableMap: putAll not permitted");
-      }
-
-      public V remove(Object key) {
-        throw new UnsupportedOperationException(
-            "unmodifiableMap: remove not permitted");
-      }
-
-      public int size() {
-        return map.size();
-      }
-
-      public Collection<V> values() {
-        return (Collection<V>) map.values();
-      }
-
-    };
+    return new UnmodifiableMap<K, V>(map);
   }
 
   public static <T> Set<T> unmodifiableSet(final Set<? extends T> set) {
-    return new Set<T>() {
-
-      public boolean add(T o) {
-        throw new UnsupportedOperationException(
-            "unmodifiableSet: add not permitted");
-      }
-
-      public boolean addAll(Collection<? extends T> c) {
-        throw new UnsupportedOperationException(
-            "unmodifiableSet: addAll not permitted");
-      }
-
-      public void clear() {
-        throw new UnsupportedOperationException(
-            "unmodifiableSet: clear not permitted");
-      }
-
-      public boolean contains(Object o) {
-        return set.contains(o);
-      }
-
-      public boolean containsAll(Collection<?> c) {
-        return set.containsAll(c);
-      }
-
-      public boolean isEmpty() {
-        return set.isEmpty();
-      }
-
-      public Iterator<T> iterator() {
-        final Iterator<? extends T> it = set.iterator();
-        return new Iterator<T>() {
-
-          public boolean hasNext() {
-            return it.hasNext();
-          }
-
-          public T next() {
-            return it.next();
-          }
-
-          public void remove() {
-            throw new UnsupportedOperationException(
-                "unmodifiableCollection.iterator: remove not permitted");
-          }
-        };
-      }
-
-      public boolean remove(Object o) {
-        throw new UnsupportedOperationException(
-            "unmodifiableSet: remove not permitted");
-      }
-
-      public boolean removeAll(Collection<?> c) {
-        throw new UnsupportedOperationException(
-            "unmodifiableSet: removeAll not permitted");
-      }
-
-      public boolean retainAll(Collection<?> c) {
-        throw new UnsupportedOperationException(
-            "unmodifiableSet: retainAll not permitted");
-      }
-
-      public int size() {
-        return set.size();
-      }
-
-      public Object[] toArray() {
-        return set.toArray();
-      }
-
-      public <OT> OT[] toArray(OT[] a) {
-        return set.toArray(a);
-      }
-
-    };
+    return new UnmodifiableSet<T>(set);
   }
 
   public static <K, V> SortedMap<K, V> unmodifiableSortedMap(
-      SortedMap<? extends K, ? extends V> map) {
-    throw new UnsupportedOperationException(
-        "unmodifiableSortedMap not implemented");
+      SortedMap<K, ? extends V> map) {
+    return new UnmodifiableSortedMap<K, V>(map);
   }
 
   public static <T> SortedSet<T> unmodifiableSortedSet(
       SortedSet<? extends T> set) {
-    throw new UnsupportedOperationException(
-        "unmodifiableSortedSet not implemented");
+    return new UnmodifiableSortedSet<T>(set);
   }
 
   /**
diff --git a/user/test/com/google/gwt/user/client/ui/DeckPanelTest.java b/user/test/com/google/gwt/user/client/ui/DeckPanelTest.java
index f9c1889..66155a5 100644
--- a/user/test/com/google/gwt/user/client/ui/DeckPanelTest.java
+++ b/user/test/com/google/gwt/user/client/ui/DeckPanelTest.java
@@ -40,7 +40,6 @@
       Label[] labels = new Label[3];
       for (int i = 0; i < labels.length; i++) {
         labels[i] = new Label("content" + i);
-        labels[i].setVisible(false);
         deck.add(labels[i]);
       }
 
@@ -53,7 +52,7 @@
       // Show widget at index 0, make sure widget 1 is still visible
       deck.showWidget(0);
       assertTrue(labels[0].isVisible());
-      assertTrue(labels[1].isVisible());
+      assertFalse(labels[1].isVisible());
       assertFalse(labels[2].isVisible());
     }
 
@@ -64,7 +63,6 @@
       Label[] labels = new Label[3];
       for (int i = 0; i < labels.length; i++) {
         labels[i] = new Label("content" + i);
-        labels[i].setVisible(false);
         deck.add(labels[i]);
       }
 
@@ -77,7 +75,7 @@
       // Show widget at index 0, make sure widget 1 is still visible
       deck.showWidget(0);
       assertTrue(labels[0].isVisible());
-      assertTrue(labels[1].isVisible());
+      assertFalse(labels[1].isVisible());
       assertFalse(labels[2].isVisible());
     }
   }