ssue: 211 
      There is some very useful functionality on the JavaScript Window.location object, such as getting the query string of a url, refreshing the page, redirecting the url, etc.  This patch creates a static Location class within the Window class to expose these methods.  

Author:
   iamroberthanson and ecc

git-svn-id: https://google-web-toolkit.googlecode.com/svn/trunk@1706 8db76d5a-ed1c-0410-87a9-c151d255dfc7
diff --git a/user/src/com/google/gwt/user/client/Window.java b/user/src/com/google/gwt/user/client/Window.java
index 3cb0818..c532a7b 100644
--- a/user/src/com/google/gwt/user/client/Window.java
+++ b/user/src/com/google/gwt/user/client/Window.java
@@ -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
@@ -17,8 +17,11 @@
 
 import com.google.gwt.core.client.GWT;
 import com.google.gwt.core.client.GWT.UncaughtExceptionHandler;
+import com.google.gwt.http.client.URL;
 
 import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Map;
 
 /**
  * This class provides access to the browser window's methods, properties, and
@@ -26,7 +29,150 @@
  */
 public class Window {
 
+  /**
+   * This class provides access to the browser's location's object. The location
+   * object contains information about the current URL and methods to manipulate
+   * it. <code>Location</code> is a very simple wrapper, so not all browser quirks are hidden from
+   * the user.
+   * 
+   */
+  public static class Location {
+    private static Map<String, String> paramMap;
+
+    /**
+     * Assigns the window to a new URL. All GWT state will be lost.
+     * 
+     * @param newURL the new URL
+     */
+    public static native void assign(String newURL) /*-{
+      $wnd.location.assign(newURL);
+    }-*/;
+
+    /**
+     * Gets the string to the right of the URL's hash.
+     * 
+     * @return the string to the right of the URL's hash.
+     */
+
+    public static native String getHash() /*-{
+      return $wnd.location.hash;
+    }-*/;
+
+    /**
+     * Gets the URL's host and port name.
+     * 
+     * @return the host and port name
+     */
+    public static native String getHost() /*-{
+      return $wnd.location.host;
+    }-*/;
+
+    /**
+     * Gets the URL's host name.
+     * 
+     * @return the host name
+     */
+    public static native String getHostName() /*-{
+      return $wnd.location.hostname;
+    }-*/;
+
+    /**
+     * Gets the entire URL.
+     * 
+     * @return the URL
+     */
+    public static native String getHref() /*-{
+      return $wnd.location.href;
+    }-*/;
+
+    /**
+     * Gets the URL's parameter of the specified name.
+     * 
+     * @param name the name of the URL's parameter
+     * @return the value of the URL's parameter
+     */
+    public static String getParameter(String name) {
+      return ensureParameterMap().get(name);
+    }
+
+    /**
+     * Gets the path to the URL.
+     * 
+     * @return the path to the URL.
+     */
+    public static native String getPath() /*-{
+      return $wnd.location.pathname;
+    }-*/;
+
+    /**
+     * Gets the URL's port.
+     * 
+     * @return the URL's port
+     */
+    public static native String getPort() /*-{
+      return $wnd.location.port;
+    }-*/;
+
+    /**
+     * Gets the URL's protocol.
+     * 
+     * @return the URL's protocol.
+     */
+    public static native String getProtocol() /*-{
+      return $wnd.location.protocol;
+    }-*/;
+
+    /**
+     * Gets the URL's query string.
+     * 
+     * @return the URL's query string
+     */
+    public static native String getQueryString() /*-{
+      return $wnd.location.search;
+    }-*/;
+
+    /**
+     * Reloads the current browser window. All GWT state will be lost.
+     */
+    public static native void reload() /*-{
+      $wnd.location.reload();
+    }-*/;
+
+    /**
+     * Replaces the current URL with a new one. All GWT state will be lost. In
+     * the browser's history, the current URL will be replaced by the new URL.
+     * 
+     * @param newURL the new URL
+     */
+    public static native void replace(String newURL) /*-{
+      $wnd.location.replace(newURL);
+    }-*/;
+
+    private static Map<String, String> ensureParameterMap() {
+      if (paramMap == null) {
+        paramMap = new HashMap<String, String>();
+        String queryString = getQueryString();
+        if (queryString != null && queryString.length() > 1) {
+          String qs = queryString.substring(1);
+          for (String kvPair : qs.split("&")) {
+            String[] kv = kvPair.split("=");
+            if (kv.length > 1) {
+              paramMap.put(kv[0], URL.decode(kv[1]));
+            } else {
+              paramMap.put(kv[0], "");
+            }
+          }
+        }
+      }
+      return paramMap;
+    }
+
+    private Location() {
+    }
+  }
+
   private static boolean handlersAreInitialized;
+
   private static ArrayList<WindowCloseListener> closingListeners;
   private static ArrayList<WindowResizeListener> resizeListeners;
 
@@ -89,8 +235,8 @@
   }-*/;
 
   /**
-   * Gets the height of the browser window's client area excluding the
-   * scroll bar.
+   * Gets the height of the browser window's client area excluding the scroll
+   * bar.
    * 
    * @return the window's client height
    */
@@ -99,15 +245,15 @@
   }
 
   /**
-   * Gets the width of the browser window's client area excluding the
-   * vertical scroll bar.
+   * Gets the width of the browser window's client area excluding the vertical
+   * scroll bar.
    * 
    * @return the window's client width
    */
   public static int getClientWidth() {
     return DOM.windowGetClientWidth();
   }
- 
+
   /**
    * Gets the window's scroll left.
    * 
@@ -157,7 +303,7 @@
   public static native void print() /*-{
     $wnd.print();
   }-*/;
-  
+
   /**
    * Displays a request for information in a modal dialog box, along with the
    * standard 'OK' and 'Cancel' buttons.
@@ -206,15 +352,15 @@
   }-*/;
 
   /**
-   * Sets the status text for the window. Calling this method in Firefox
-   * has no effect.
+   * Sets the status text for the window. Calling this method in Firefox has no
+   * effect.
    * 
    * @param status the new message to display.
    */
   public static native void setStatus(String status) /*-{
     $wnd.status = status;
   }-*/;
-  
+
   /**
    * Sets the browser window's title.
    * 
@@ -280,7 +426,8 @@
     String ret = null;
     if (closingListeners != null) {
       for (WindowCloseListener listener : closingListeners) {
-        // If any listener wants to suppress the window closing event, then do so.
+        // If any listener wants to suppress the window closing event, then do
+        // so.
         String msg = listener.onWindowClosing();
         if (ret == null) {
           ret = msg;
@@ -324,7 +471,7 @@
       }
     );
   }-*/;
-  
+
   private static void maybeInitializeHandlers() {
     if (!handlersAreInitialized) {
       init();
diff --git a/user/test/com/google/gwt/user/client/WindowTest.java b/user/test/com/google/gwt/user/client/WindowTest.java
index a1d9ab6..03a2310 100644
--- a/user/test/com/google/gwt/user/client/WindowTest.java
+++ b/user/test/com/google/gwt/user/client/WindowTest.java
@@ -28,17 +28,37 @@
     return "com.google.gwt.user.User";
   }
 
+  public void testLocation() {
+    // testing reload, replace, and assign seemed to hang our junit harness. Therefore
+    // only testing subset of Location that is testable.
+
+    // As we have no control over these values we cannot assert much about them.
+    String hash = Window.Location.getHash();
+    String host = Window.Location.getHost();
+    String hostName = Window.Location.getHostName();
+    String href = Window.Location.getHref();
+    assertNull(Window.Location.getParameter("fuzzy bunny"));
+    String path = Window.Location.getPath();
+    String port = Window.Location.getPort();
+    String protocol = Window.Location.getProtocol();
+    String query = Window.Location.getQueryString();
+
+    // Check that the sum is equal to its parts.
+    assertEquals(host, hostName + ":" + port);
+    assertEquals(href, protocol + "//" + host + path + query + hash);
+  }
+
   /**
-   * Tests the ability of the Window to get the client size correctly
-   * with and without visible scroll bars.
+   * Tests the ability of the Window to get the client size correctly with and
+   * without visible scroll bars.
    */
   public void testGetClientSize() {
     // Get the dimensions without any scroll bars
     Window.enableScrolling(false);
     final int oldClientHeight = Window.getClientHeight();
     final int oldClientWidth = Window.getClientWidth();
-    assertTrue( oldClientHeight > 0 );
-    assertTrue( oldClientWidth > 0 );
+    assertTrue(oldClientHeight > 0);
+    assertTrue(oldClientWidth > 0);
 
     // Compare to the dimensions with scroll bars
     Window.enableScrolling(true);
@@ -48,9 +68,9 @@
     DeferredCommand.addCommand(new Command() {
       public void execute() {
         int newClientHeight = Window.getClientHeight();
-        int newClientWidth  = Window.getClientWidth();
-        assertTrue( newClientHeight < oldClientHeight );
-        assertTrue( newClientWidth < oldClientWidth );
+        int newClientWidth = Window.getClientWidth();
+        assertTrue(newClientHeight < oldClientHeight);
+        assertTrue(newClientWidth < oldClientWidth);
         finishTest();
       }
     });