Revision: 7163
Author: j...@google.com
Date: Tue Nov 24 15:07:18 2009
Log: Merge trunk r7162 into this branch

UI cleanups.

     svn merge --ignore-ancestry -c7162 \
       https://google-web-toolkit.googlecode.com/svn/trunk/ .


http://code.google.com/p/google-web-toolkit/source/detail?r=7163

Modified:
  /releases/2.0/branch-info.txt
  /releases/2.0/dev/core/src/com/google/gwt/dev/DevModeBase.java
  /releases/2.0/dev/core/src/com/google/gwt/dev/SwingUI.java
  /releases/2.0/dev/core/src/com/google/gwt/dev/shell/ShellMainWindow.java
   
/releases/2.0/dev/core/src/com/google/gwt/dev/shell/jetty/JettyLauncher.java
  /releases/2.0/dev/core/src/com/google/gwt/dev/shell/remoteui/RemoteUI.java
  /releases/2.0/dev/core/src/com/google/gwt/dev/ui/DevModeUI.java

=======================================
--- /releases/2.0/branch-info.txt       Tue Nov 24 14:41:20 2009
+++ /releases/2.0/branch-info.txt       Tue Nov 24 15:07:18 2009
@@ -1038,3 +1038,8 @@
    Cleans up javadoc in layout panels (TODOs will be captured as issues).
    Fix for non-standard gwt-Tab style name.
      svn merge --ignore-ancestry -c7160  
https://google-web-toolkit.googlecode.com/svn/trunk/ .
+
+tr...@7162 was merged into this branch
+ UI cleanups.
+    svn merge --ignore-ancestry -c7162 \
+      https://google-web-toolkit.googlecode.com/svn/trunk/ .
=======================================
--- /releases/2.0/dev/core/src/com/google/gwt/dev/DevModeBase.java      Mon Nov 
 
23 21:23:36 2009
+++ /releases/2.0/dev/core/src/com/google/gwt/dev/DevModeBase.java      Tue Nov 
 
24 15:07:18 2009
@@ -687,11 +687,11 @@
        // Eager AWT init for OS X to ensure safe coexistence with SWT.
        BootStrapPlatform.initGui();

-      if (startUp()) {
-        // The web server is running now, so launch browsers for startup  
urls.
-        launchStartupUrls();
-      }
-
+      boolean success = startUp();
+
+      // The web server is running now, so launch browsers for startup  
urls.
+      ui.moduleLoadComplete(success);
+
        blockUntilDone.acquire();
      } catch (Exception e) {
        e.printStackTrace();
@@ -1000,14 +1000,6 @@

      return newUI;
    }
-
-  /**
-   * Actually launch (or indicate to the user they can be launched)  
previously
-   * specified (via {...@link #setStartupUrls(TreeLogger)}) URLs.
-   */
-  private void launchStartupUrls() {
-    ui.launchStartupUrls();
-  }

    /**
     * Perform hosted mode relink when new artifacts are generated, without
@@ -1030,10 +1022,11 @@
    }

    /**
-   * Set the set of startup URLs.  This is done before launching to allow  
the
-   * UI to better present the options to the user, but note that the UI  
should
-   * not attempt to launch the URLs until {...@link #launchStartupUrls()}
-   * is called.
+   * Set the set of startup URLs. This is done before launching to allow  
the UI
+   * to better present the options to the user, but note that the UI  
should not
+   * attempt to launch the URLs until
+   * {...@link DevModeUI#moduleLoadComplete(boolean)} is called, and should  
not
+   * automatically launch any URLs if they
     *
     * @param logger TreeLogger instance to use
     */
=======================================
--- /releases/2.0/dev/core/src/com/google/gwt/dev/SwingUI.java  Mon Nov 23  
19:54:09 2009
+++ /releases/2.0/dev/core/src/com/google/gwt/dev/SwingUI.java  Tue Nov 24  
15:07:18 2009
@@ -27,6 +27,7 @@
  import com.google.gwt.dev.ui.RestartServerEvent;
  import com.google.gwt.dev.util.collect.HashMap;

+import java.awt.EventQueue;
  import java.awt.Image;
  import java.awt.event.WindowAdapter;
  import java.awt.event.WindowEvent;
@@ -37,6 +38,9 @@
  import java.util.ArrayList;
  import java.util.List;
  import java.util.Map;
+import java.util.concurrent.Callable;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.FutureTask;

  import javax.swing.Icon;
  import javax.swing.ImageIcon;
@@ -54,22 +58,18 @@
     */
    protected class SwingModuleHandle implements ModuleHandle {

-    private final TreeLogger logger;
      private final ModulePanel tab;

      /**
       * Create an immutable module handle.
-     *
-     * @param logger logger to use for this module
       * @param tab the module panel associated with this instance
       */
-    public SwingModuleHandle(TreeLogger logger, ModulePanel tab) {
-      this.logger = logger;
+    public SwingModuleHandle(ModulePanel tab) {
        this.tab = tab;
      }

      public TreeLogger getLogger() {
-      return logger;
+      return tab.getLogger();
      }

      /**
@@ -170,18 +170,24 @@
    }

    @Override
-  public ModuleHandle getModuleLogger(String userAgent, String  
remoteSocket,
-      String url, String tabKey, String moduleName, String sessionKey,
-      String agentTag, byte[] agentIcon, TreeLogger.Type logLevel) {
+  public ModuleHandle getModuleLogger(final String userAgent,
+      final String remoteSocket, final String url, final String tabKey,
+      final String moduleName, final String sessionKey, final String  
agentTag,
+      final byte[] agentIcon, final TreeLogger.Type logLevel) {
      // TODO(jat): add support for closing an active module
-    ModuleTabPanel tabPanel = null;
-    ModulePanel tab = null;
-    tabPanel = findModuleTab(userAgent, remoteSocket, url, tabKey,
-        moduleName, agentIcon);
-    tab = tabPanel.addModuleSession(logLevel, moduleName, sessionKey,
-        options.getLogFile(String.format("%s-%s-%d.log", moduleName,  
agentTag,
-            getNextSessionCounter(options.getLogDir()))));
-    TreeLogger logger = tab.getLogger();
+    ModuleHandle handle = invokeAndGet(new Callable<ModuleHandle>() {
+          public ModuleHandle call() throws Exception {
+            ModuleTabPanel tabPanel = findModuleTab(userAgent,  
remoteSocket,
+                url, tabKey, moduleName, agentIcon);
+            ModulePanel tab = tabPanel.addModuleSession(logLevel,  
moduleName,
+                sessionKey,  
options.getLogFile(String.format("%s-%s-%d.log",
+                    moduleName, agentTag, getNextSessionCounter(
+                        options.getLogDir()))));
+            // TODO: Switch to a wait cursor?
+            return new SwingModuleHandle(tab);
+          }
+        });
+    TreeLogger logger = handle.getLogger();
      TreeLogger branch = logger.branch(TreeLogger.INFO, "Loading module "
          + moduleName);
      if (url != null) {
@@ -195,8 +201,7 @@
      if (sessionKey != null) {
        branch.log(TreeLogger.DEBUG, "Session key: " + sessionKey);
      }
-    // TODO: Switch to a wait cursor?
-    return new SwingModuleHandle(logger, tab);
+    return handle;
    }

    @Override
@@ -229,51 +234,63 @@
    }

    @Override
-  public void initialize(Type logLevel) {
+  public void initialize(final Type logLevel) {
      super.initialize(logLevel);
-    ImageIcon gwtIcon16 = loadImageIcon("icon16.png");
-    ImageIcon gwtIcon24 = loadImageIcon("icon24.png");
-    ImageIcon gwtIcon32 = loadImageIcon("icon32.png");
-    ImageIcon gwtIcon48 = loadImageIcon("icon48.png");
-    ImageIcon gwtIcon64 = loadImageIcon("icon64.png");
-    ImageIcon gwtIcon128 = loadImageIcon("icon128.png");
-    frame = new JFrame("GWT Development Mode");
-    tabs = new JTabbedPane();
-    if (options.alsoLogToFile()) {
-      options.getLogDir().mkdirs();
-    }
-    mainWnd = new ShellMainWindow(logLevel,  
options.getLogFile("main.log"));
-    topLogger = mainWnd.getLogger();
-    tabs.addTab("Development Mode", gwtIcon24, mainWnd, "GWT Development  
Mode");
-    frame.getContentPane().add(tabs);
-    frame.setSize(950, 700);
-    frame.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
-    frame.addWindowListener(new WindowAdapter() {
-      @Override
-      public void windowClosed(WindowEvent e) {
-        DoneCallback callback = getCallback(DoneEvent.getType());
-        if (callback != null) {
-          callback.onDone();
-        }
+    invokeAndWait(new Runnable() {
+      public void run() {
+        ImageIcon gwtIcon16 = loadImageIcon("icon16.png");
+        ImageIcon gwtIcon24 = loadImageIcon("icon24.png");
+        ImageIcon gwtIcon32 = loadImageIcon("icon32.png");
+        ImageIcon gwtIcon48 = loadImageIcon("icon48.png");
+        ImageIcon gwtIcon64 = loadImageIcon("icon64.png");
+        ImageIcon gwtIcon128 = loadImageIcon("icon128.png");
+        frame = new JFrame("GWT Development Mode");
+        tabs = new JTabbedPane();
+        if (options.alsoLogToFile()) {
+          options.getLogDir().mkdirs();
+        }
+        mainWnd = new ShellMainWindow(logLevel,  
options.getLogFile("main.log"));
+        topLogger = mainWnd.getLogger();
+        tabs.addTab("Development Mode", gwtIcon24, mainWnd,
+            "GWT Development Mode");
+        frame.getContentPane().add(tabs);
+        frame.setSize(950, 700);
+        frame.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
+        frame.addWindowListener(new WindowAdapter() {
+          @Override
+          public void windowClosed(WindowEvent e) {
+            DoneCallback callback = getCallback(DoneEvent.getType());
+            if (callback != null) {
+              callback.onDone();
+            }
+          }
+        });
+        setIconImages(topLogger, gwtIcon48, gwtIcon32, gwtIcon64,  
gwtIcon128,
+            gwtIcon16);
+        frame.setVisible(true);
        }
      });
-    setIconImages(topLogger, gwtIcon48, gwtIcon32, gwtIcon64, gwtIcon128,
-        gwtIcon16);
-    frame.setVisible(true);
-
      maybeInitializeOsXApplication();
    }

    @Override
-  public void launchStartupUrls() {
-    mainWnd.setLaunchable();
-  }
-
+  public void moduleLoadComplete(final boolean success) {
+    EventQueue.invokeLater(new Runnable() {
+      public void run() {
+        mainWnd.moduleLoadComplete(success);
+      }
+    });
+  }
+
    @Override
-  public void setStartupUrls(Map<String, URL> urls) {
-    mainWnd.setStartupUrls(urls);
-  }
-
+  public void setStartupUrls(final Map<String, URL> urls) {
+    invokeAndWait(new Runnable() {
+      public void run() {
+        mainWnd.setStartupUrls(urls);
+      }
+    });
+  }
+
    protected int getNextSessionCounter(File logdir) {
      synchronized (sessionCounterLock) {
        if (sessionCounter == 0 && logdir != null) {
@@ -325,6 +342,45 @@
      }
      return moduleTabPanel;
    }
+
+  /**
+   * Invoke a Callable on the UI thread, wait for it to finish, and return  
the
+   * result.
+   *
+   * @param <T> return type
+   * @param callable wrapper of the method to run on the UI thread
+   * @return the return value of callable.call()
+   * @throws RuntimeException if an error occurs
+   */
+  private <T> T invokeAndGet(Callable<T> callable) {
+    FutureTask<T> task = new FutureTask<T>(callable);
+    try {
+      EventQueue.invokeAndWait(task);
+      return task.get();
+    } catch (InterruptedException e) {
+      throw new RuntimeException(e);
+    } catch (ExecutionException e) {
+      throw new RuntimeException(e);
+    } catch (InvocationTargetException e) {
+      throw new RuntimeException(e);
+    }
+  }
+
+  /**
+   * Invoke a Runnable on the UI thread and wait for it to finish.
+   *
+   * @param runnable
+   * @throws RuntimeException if an error occurs
+   */
+  private void invokeAndWait(Runnable runnable) {
+    try {
+      EventQueue.invokeAndWait(runnable);
+    } catch (InterruptedException e) {
+      throw new RuntimeException("Error running on Swing UI thread", e);
+    } catch (InvocationTargetException e) {
+      throw new RuntimeException("Error running on Swing UI thread", e);
+    }
+  }

    /**
     * This method contains code that will call certain Apple extensions to  
make
=======================================
---  
/releases/2.0/dev/core/src/com/google/gwt/dev/shell/ShellMainWindow.java        
 
Mon Nov 23 19:54:09 2009
+++  
/releases/2.0/dev/core/src/com/google/gwt/dev/shell/ShellMainWindow.java        
 
Tue Nov 24 15:07:18 2009
@@ -20,7 +20,6 @@
  import com.google.gwt.dev.util.BrowserLauncher;

  import java.awt.BorderLayout;
-import java.awt.GridLayout;
  import java.awt.HeadlessException;
  import java.awt.datatransfer.Clipboard;
  import java.awt.datatransfer.StringSelection;
@@ -46,32 +45,32 @@
  public class ShellMainWindow extends JPanel {

    /**
-   * A class for implementing different methods of launching a URL.
+   * Launches a URL by copying it to the clipboard.
     */
-  private abstract static class LaunchMethod {
-
-    private final String displayName;
-
-    /**
-     * Construct the launch method.
-     *
-     * @param displayName the name that will display in the UI for this  
launch
-     *     method
-     */
-    public LaunchMethod(String displayName) {
-      this.displayName = displayName;
-    }
-
-    /**
-     * Launch the specified URL.
-     *
-     * @param url
-     */
-    public abstract void launchUrl(URL url);
+  private class CopyToClipboardLauncher extends LaunchMethod {
+
+    public CopyToClipboardLauncher() {
+      super("Copy URL to clipboard");
+    }

      @Override
-    public String toString() {
-      return displayName;
+    public void launchUrl(URL url) {
+      getLogger().log(TreeLogger.INFO, "Paste " + url.toExternalForm()
+          + " in a browser");
+      // is it better to use SwingUtilities2.canAccessSystemClipboard()  
here?
+      Throwable caught = null;
+      try {
+        Clipboard clipboard = logWindow.getToolkit().getSystemClipboard();
+        StringSelection selection = new  
StringSelection(url.toExternalForm());
+        clipboard.setContents(selection, selection);
+        return;
+      } catch (SecurityException e) {
+        caught = e;
+      } catch (HeadlessException e) {
+        caught = e;
+      }
+      getLogger().log(TreeLogger.ERROR, "Unable to copy URL to clipboard",
+          caught);
      }
    }

@@ -96,36 +95,39 @@
        } catch (URISyntaxException e) {
          caught = e;
        }
-      getLogger().log(TreeLogger.ERROR, "Unable to launch default browser",
-          caught);
+      TreeLogger branch = getLogger().branch(TreeLogger.ERROR,
+          "Unable to launch default browser", caught);
+      branch.log(TreeLogger.INFO, url.toExternalForm());
      }
    }

    /**
-   * Launches a URL by copying it to the clipboard.
+   * A class for implementing different methods of launching a URL.
     */
-  private class CopyToClipboardLauncher extends LaunchMethod {
-
-    public CopyToClipboardLauncher() {
-      super("Copy URL to clipboard");
-    }
+  private abstract static class LaunchMethod {
+
+    private final String displayName;
+
+    /**
+     * Construct the launch method.
+     *
+     * @param displayName the name that will display in the UI for this  
launch
+     *     method
+     */
+    public LaunchMethod(String displayName) {
+      this.displayName = displayName;
+    }
+
+    /**
+     * Launch the specified URL.
+     *
+     * @param url
+     */
+    public abstract void launchUrl(URL url);

      @Override
-    public void launchUrl(URL url) {
-      // is it better to use SwingUtilities2.canAccessSystemClipboard()  
here?
-      Throwable caught = null;
-      try {
-        Clipboard clipboard = logWindow.getToolkit().getSystemClipboard();
-        StringSelection selection = new  
StringSelection(url.toExternalForm());
-        clipboard.setContents(selection, selection);
-        return;
-      } catch (SecurityException e) {
-        caught = e;
-      } catch (HeadlessException e) {
-        caught = e;
-      }
-      getLogger().log(TreeLogger.ERROR, "Unable to copy URL to clipboard",
-          caught);
+    public String toString() {
+      return displayName;
      }
    }

@@ -151,27 +153,22 @@
        return urlFragment;
      }
    }
+
    private SwingLoggerPanel logWindow;
    private JComboBox launchCombo;
    private JButton launchButton;
-
    private JComboBox urlCombo;

    /**
+   * Create the main window with the top-level logger and launch controls.
+   * <p>
+   * MUST BE CALLED FROM THE UI THREAD
+   *
     * @param maxLevel
     * @param logFile
     */
    public ShellMainWindow(TreeLogger.Type maxLevel, File logFile) {
      super(new BorderLayout());
-    // TODO(jat): add back when we have real options
-    if (false) {
-      JPanel panel = new JPanel(new GridLayout(2, 1));
-      JPanel optionPanel = new JPanel();
-      optionPanel.setBorder(BorderFactory.createTitledBorder("Options"));
-      optionPanel.add(new JLabel("Miscellaneous options here"));
-      panel.add(optionPanel);
-      add(panel, BorderLayout.NORTH);
-    }
      JPanel launchPanel = new JPanel();
      launchPanel.setBorder(BorderFactory.createTitledBorder(
          "Launch GWT Module"));
@@ -206,10 +203,18 @@
    }

    /**
-   * Indicate that URLs specified in {...@link #setStartupUrls(Map)} are now
-   * launchable.
+   * Indicate that all modules have been loaded -- on success, URLs  
previously
+   * specified in {...@link #setStartupUrls(Map)} may be launched.
+   * <p>
+   * MUST BE CALLED FROM THE UI THREAD
+   *
+   * @param successfulLoad true if all modules were successfully loaded
     */
-  public void setLaunchable() {
+  public void moduleLoadComplete(boolean successfulLoad) {
+    if (!successfulLoad) {
+      launchButton.setText("Module Load Failure");
+      return;
+    }
      if (urlCombo.getItemCount() == 0) {
        launchButton.setText("No URLs to Launch");
        urlCombo.addItem("No startup URLs");
@@ -222,11 +227,14 @@

    /**
     * Create the UI to show available startup URLs.  These should not be
-   * launchable by the user until the {...@link #setLaunchable()} method is  
called.
-   *
+   * launchable by the user until the {...@link #moduleLoadComplete(boolean)}  
method is
+   * called.
+   * <p>
+   * MUST BE CALLED FROM THE UI THREAD
+
     * @param urls map of user-specified URL fragments to final URLs
     */
-  public void setStartupUrls(Map<String, URL> urls) {
+  public void setStartupUrls(final Map<String, URL> urls) {
      urlCombo.removeAllItems();
      ArrayList<String> keys = new ArrayList<String>(urls.keySet());
      Collections.sort(keys);
@@ -236,15 +244,30 @@
      urlCombo.revalidate();
    }

+  /**
+   * Launch the selected URL with the selected launch method.
+   * <p>
+   * MUST BE CALLED FROM THE UI THREAD
+   */
    protected void launch() {
      LaunchMethod launcher = (LaunchMethod) launchCombo.getSelectedItem();
      UrlComboEntry selectedUrl = (UrlComboEntry) urlCombo.getSelectedItem();
+    if (launcher == null || selectedUrl == null) {
+      // Shouldn't happen - should we log anything?
+      return;
+    }
      URL url = selectedUrl.getUrl();
      launcher.launchUrl(url);
    }

+  /**
+   * Populate the launch method combo box with possible choices.
+   * <p>
+   * MUST BE CALLED FROM THE UI THREAD
+   */
    private void populateLaunchComboBox() {
-    // TODO(jat): support scanning for other browsers and launching them
+    // TODO(jat): support scanning for other browsers and launching them,  
as
+    // well as user preferences of launch methods and their order.
      launchCombo.addItem(new DefaultBrowserLauncher());
      launchCombo.addItem(new CopyToClipboardLauncher());
    }
=======================================
---  
/releases/2.0/dev/core/src/com/google/gwt/dev/shell/jetty/JettyLauncher.java    
 
Thu Nov 19 14:41:30 2009
+++  
/releases/2.0/dev/core/src/com/google/gwt/dev/shell/jetty/JettyLauncher.java    
 
Tue Nov 24 15:07:18 2009
@@ -81,13 +81,12 @@
             * We do not want to call the developer's attention to a 404 when
             * requesting favicon.ico. This is a very common 404.
             */
-          logStatus = normalLogLevel;
+          logStatus = TreeLogger.TRACE;
            logHeaders = TreeLogger.DEBUG;
          } else {
            logStatus = TreeLogger.WARN;
            logHeaders = TreeLogger.INFO;
          }
-        logHeaders = TreeLogger.INFO;
        } else if (status >= 400) {
          logStatus = TreeLogger.WARN;
          logHeaders = TreeLogger.INFO;
=======================================
---  
/releases/2.0/dev/core/src/com/google/gwt/dev/shell/remoteui/RemoteUI.java      
 
Mon Nov 23 21:23:36 2009
+++  
/releases/2.0/dev/core/src/com/google/gwt/dev/shell/remoteui/RemoteUI.java      
 
Tue Nov 24 15:07:18 2009
@@ -127,7 +127,7 @@
    }

    @Override
-  public void launchStartupUrls() {
+  public void moduleLoadComplete(boolean success) {
      /*
       * TODO: Send a message to the server indicating that the URLs are
       * launchable.
=======================================
--- /releases/2.0/dev/core/src/com/google/gwt/dev/ui/DevModeUI.java     Mon Nov 
 
23 19:54:09 2009
+++ /releases/2.0/dev/core/src/com/google/gwt/dev/ui/DevModeUI.java     Tue Nov 
 
24 15:07:18 2009
@@ -27,6 +27,18 @@
  /**
   * Defines the interaction between DevelopmentMode and the UI, so that
   * alternate UIs can be implemented.
+ * <p>
+ * Sequence of calls:
+ * <ul>
+ * <li>{...@link #initialize(Type)}
+ * <li>{...@link #getTopLogger()}
+ * <li>possibly {...@link #getWebServerLogger(String, byte[])}
+ * <li>{...@link #setStartupUrls(Map)}
+ * <li>{...@link #moduleLoadComplete(boolean)} or
+ * <li>zero or more {...@link #getModuleLogger}
+ * </ul>
+ * {...@link #setCallback(com.google.gwt.dev.ui.UiEvent.Type, UiCallback)}  
may be
+ * interspersed among these calls after {...@link #initialize(Type)} is  
called.
   */
  public abstract class DevModeUI {

@@ -111,10 +123,13 @@
    }

    /**
-   * Indicate to the user that URLs may be started, or actually launch  
browsers
-   * with the URLs specified in {...@link #setStartupUrls(Map)}.
+   * Indicates that all modules have been loaded (loading the XML, not
+   * completing onModuleLoad), and that URLs previously specified in
+   * {...@link #setStartupUrls(Map)} may be launched if successful.
+   *
+   * @param success true if all modules were successfully loaded
     */
-  public void launchStartupUrls() {
+  public void moduleLoadComplete(boolean success) {
      // do nothing by default
    }

-- 
http://groups.google.com/group/Google-Web-Toolkit-Contributors

Reply via email to