Revision: 7148
Author: j...@google.com
Date: Mon Nov 23 18:34:09 2009
Log: Improve the DevMode UI, both for GPE and Swing:
  - startup URLs are specified separately from launching them, allowing them
    to be displayed earlier
  - if no startup URLs are supplied, they are inferred from the contents of
    the war directory
  - the Swing UI is change to better allow launching of the URLs and to give
    feedback while processing modules
  - Ctrl-Key mappings are now Command-Key on the Mac

Patch by: jat
Review by: rdayal

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

Modified:
  /trunk/dev/core/src/com/google/gwt/dev/BootStrapPlatform.java
  /trunk/dev/core/src/com/google/gwt/dev/DevMode.java
  /trunk/dev/core/src/com/google/gwt/dev/DevModeBase.java
  /trunk/dev/core/src/com/google/gwt/dev/GWTShell.java
  /trunk/dev/core/src/com/google/gwt/dev/SwingUI.java
  /trunk/dev/core/src/com/google/gwt/dev/shell/ShellMainWindow.java
  /trunk/dev/core/src/com/google/gwt/dev/shell/log/SwingLoggerPanel.java
  /trunk/dev/core/src/com/google/gwt/dev/ui/DevModeUI.java

=======================================
--- /trunk/dev/core/src/com/google/gwt/dev/BootStrapPlatform.java       Mon Nov 
 
23 16:21:36 2009
+++ /trunk/dev/core/src/com/google/gwt/dev/BootStrapPlatform.java       Mon Nov 
 
23 18:34:09 2009
@@ -48,6 +48,14 @@
    public static void initHostedMode() {
      // nothing required
    }
+
+  /**
+   * Return true if we are running on a Mac.
+   */
+  public static boolean isMac() {
+    String lcOSName =  
System.getProperty("os.name").toLowerCase(Locale.ENGLISH);
+    return lcOSName.startsWith("mac ");
+  }

    /**
     * This works around apple radr:5569300. When -XstartOnFirstThread is  
passed
@@ -61,14 +69,6 @@
            BootStrapPlatform.class.getClassLoader());
      }
    }
-
-  /**
-   * Return true if we are running on a Mac.
-   */
-  private static boolean isMac() {
-    String lcOSName =  
System.getProperty("os.name").toLowerCase(Locale.ENGLISH);
-    return lcOSName.startsWith("mac ");
-  }

    /**
     * Sets platform specific system properties. Currently, this disables
=======================================
--- /trunk/dev/core/src/com/google/gwt/dev/DevMode.java Mon Nov 23 16:21:36  
2009
+++ /trunk/dev/core/src/com/google/gwt/dev/DevMode.java Mon Nov 23 18:34:09  
2009
@@ -36,6 +36,7 @@
  import com.google.gwt.util.tools.Utility;

  import java.io.File;
+import java.io.FilenameFilter;
  import java.io.IOException;
  import java.net.BindException;
  import java.util.HashMap;
@@ -227,6 +228,11 @@
      }
    }

+  /**
+   * Startup development mode.
+   *
+   * @param args command line arguments
+   */
    public static void main(String[] args) {
      /*
       * NOTE: main always exits with a call to System.exit to terminate any
@@ -302,10 +308,7 @@
    }

    @Override
-  protected boolean doStartup() {
-    if (!super.doStartup()) {
-      return false;
-    }
+  protected boolean doSlowStartup() {
      tempWorkDir = options.getWorkDir() == null;
      if (tempWorkDir) {
        try {
@@ -390,6 +393,19 @@
    protected String getWebServerName() {
      return options.getServletContainerLauncher().getName();
    }
+
+  @Override
+  protected void inferStartupUrls() {
+    // Look for any HTML files directly under war
+    File warDir = options.getWarDir();
+    for (File htmlFile : warDir.listFiles(new FilenameFilter() {
+          public boolean accept(File dir, String name) {
+            return name.matches(".*\\.html");
+          }
+        })) {
+      options.addStartupURL(htmlFile.getName());
+    }
+  }

    @Override
    protected ModuleDef loadModule(TreeLogger logger, String moduleName,
=======================================
--- /trunk/dev/core/src/com/google/gwt/dev/DevModeBase.java     Mon Nov 23  
16:21:36 2009
+++ /trunk/dev/core/src/com/google/gwt/dev/DevModeBase.java     Mon Nov 23  
18:34:09 2009
@@ -674,6 +674,8 @@
     * Gets the base log level recommended by the UI for INFO-level  
messages. This
     * method can only be called once {...@link #createUI()} has been called.  
Please
     * do not depend on this method, as it is subject to change.
+   *
+   * @return the log level to use for INFO-level messages
     */
    public TreeLogger.Type getBaseLogLevelForUI() {
      if (baseLogLevelForUI == null) {
@@ -691,29 +693,6 @@
    public TreeLogger getTopLogger() {
      return topLogger;
    }
-
-  /**
-   * Launch the arguments as Urls in separate windows.
-   *
-   * @param logger TreeLogger instance to use
-   */
-  public void launchStartupUrls(final TreeLogger logger) {
-    ensureCodeServerListener();
-    String startupURL = "";
-    Map<String, URL> startupUrls = new HashMap<String, URL>();
-    for (String prenormalized : options.getStartupURLs()) {
-      startupURL = normalizeURL(prenormalized, getPort(), getHost());
-      logger.log(TreeLogger.TRACE, "Starting URL: " + startupURL, null);
-      try {
-        URL url = processUrl(startupURL);
-        startupUrls.put(prenormalized, url);
-      } catch (UnableToCompleteException e) {
-        logger.log(TreeLogger.ERROR, "Unable to process startup URL "
-            + startupURL, null);
-      }
-    }
-    ui.setStartupUrls(startupUrls);
-  }

    /**
     * Callback for the UI to indicate it is done.
@@ -733,7 +712,7 @@

        if (startUp()) {
          // The web server is running now, so launch browsers for startup  
urls.
-        launchStartupUrls(getTopLogger());
+        launchStartupUrls();
        }

        blockUntilDone.acquire();
@@ -786,6 +765,18 @@
    }

    protected abstract void doShutDownServer();
+
+  /**
+   * Perform any slower startup tasks, such as loading modules.  This is
+   * separate from {...@link #doStartup()} so that the UI can be updated as
+   * soon as possible and the web server can be started earlier.
+   *
+   * @return false if startup failed
+   */
+  protected boolean doSlowStartup() {
+    // do nothing by default
+    return true;
+  }

    /**
     * Perform any startup tasks, including initializing the UI (if any) and  
the
@@ -846,6 +837,14 @@
    protected String getHost() {
      return "localhost";
    }
+
+  /**
+   * Add any plausible HTML files which might be used as startup URLs.  
Found
+   * URLs should be added to {...@code options.addStartupUrl(url)}.
+   */
+  protected void inferStartupUrls() {
+    // do nothing by default
+  }

    /**
     * By default we will open the application window.
@@ -967,6 +966,16 @@
        getTopLogger().log(TreeLogger.TRACE,
            "Started web server on port " + resultPort);
      }
+
+    if (options.getStartupURLs().isEmpty()) {
+      inferStartupUrls();
+    }
+
+    setStartupUrls(topLogger);
+
+    if (!doSlowStartup()) {
+      return false;
+    }

      return true;
    }
@@ -1015,6 +1024,14 @@

      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
@@ -1035,4 +1052,30 @@
          newlyGeneratedArtifacts);
      produceOutput(linkLogger, linkerContext, artifacts, module, true);
    }
-}
+
+  /**
+   * 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.
+   *
+   * @param logger TreeLogger instance to use
+   */
+  private void setStartupUrls(final TreeLogger logger) {
+    ensureCodeServerListener();
+    Map<String, URL> startupUrls = new HashMap<String, URL>();
+    for (String prenormalized : options.getStartupURLs()) {
+      String startupURL = normalizeURL(prenormalized, getPort(),  
getHost());
+      logger.log(TreeLogger.DEBUG, "URL " + prenormalized + " normalized  
as "
+          + startupURL, null);
+      try {
+        URL url = processUrl(startupURL);
+        startupUrls.put(prenormalized, url);
+      } catch (UnableToCompleteException e) {
+        logger.log(TreeLogger.ERROR, "Unable to process startup URL "
+            + startupURL, null);
+      }
+    }
+    ui.setStartupUrls(startupUrls);
+  }
+}
=======================================
--- /trunk/dev/core/src/com/google/gwt/dev/GWTShell.java        Mon Nov 23  
16:21:36 2009
+++ /trunk/dev/core/src/com/google/gwt/dev/GWTShell.java        Mon Nov 23  
18:34:09 2009
@@ -209,6 +209,7 @@
      return EmbeddedTomcatServer.getPort();
    }

+  @Override
    protected synchronized void produceOutput(TreeLogger logger,
        StandardLinkerContext linkerStack, ArtifactSet artifacts,
        ModuleDef module, boolean isRelink) throws UnableToCompleteException  
{
=======================================
--- /trunk/dev/core/src/com/google/gwt/dev/SwingUI.java Thu Nov 19 12:24:42  
2009
+++ /trunk/dev/core/src/com/google/gwt/dev/SwingUI.java Mon Nov 23 18:34:09  
2009
@@ -16,7 +16,6 @@
  package com.google.gwt.dev;

  import com.google.gwt.core.ext.TreeLogger;
-import com.google.gwt.core.ext.TreeLogger.HelpInfo;
  import com.google.gwt.core.ext.TreeLogger.Type;
  import com.google.gwt.dev.DevModeBase.HostedModeBaseOptions;
  import com.google.gwt.dev.WebServerPanel.RestartAction;
@@ -36,7 +35,6 @@
  import java.lang.reflect.Method;
  import java.net.URL;
  import java.util.ArrayList;
-import java.util.Collections;
  import java.util.List;
  import java.util.Map;

@@ -266,32 +264,14 @@
      maybeInitializeOsXApplication();
    }

+  @Override
+  public void launchStartupUrls() {
+    mainWnd.setLaunchable();
+  }
+
    @Override
    public void setStartupUrls(Map<String, URL> urls) {
-    // TODO(jat): provide UI for selecting URLs and launching
-    ArrayList<String> keys = new ArrayList<String>(urls.keySet());
-    Collections.sort(keys);
-    for (String url : keys) {
-      final URL helpInfoUrl = urls.get(url);
-      getTopLogger().log(TreeLogger.INFO, "Waiting for browser connection  
to "
-          + helpInfoUrl.toExternalForm(), null,
-          new HelpInfo() {
-            @Override
-            public String getAnchorText() {
-              return "Launch default browser";
-            }
-
-            @Override
-            public String getPrefix() {
-              return "";
-            }
-
-            @Override
-            public URL getURL() {
-              return helpInfoUrl;
-            }
-          });
-    }
+    mainWnd.setStartupUrls(urls);
    }

    protected int getNextSessionCounter(File logdir) {
=======================================
--- /trunk/dev/core/src/com/google/gwt/dev/shell/ShellMainWindow.java   Mon  
Nov 23 16:21:36 2009
+++ /trunk/dev/core/src/com/google/gwt/dev/shell/ShellMainWindow.java   Mon  
Nov 23 18:34:09 2009
@@ -17,22 +17,150 @@

  import com.google.gwt.core.ext.TreeLogger;
  import com.google.gwt.dev.shell.log.SwingLoggerPanel;
+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;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
  import java.io.File;
+import java.io.IOException;
+import java.net.URISyntaxException;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Map;

  import javax.swing.BorderFactory;
+import javax.swing.JButton;
+import javax.swing.JComboBox;
  import javax.swing.JLabel;
  import javax.swing.JPanel;

  /**
+ * Top-level window for the Swing DevMode UI.
   */
-...@suppresswarnings("deprecation")
  public class ShellMainWindow extends JPanel {

+  /**
+   * A class for implementing different methods of launching a URL.
+   */
+  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 String toString() {
+      return displayName;
+    }
+  }
+
+  /**
+   * Launches a URL using the default browser, as defined by
+   * {...@link BrowserLauncher}.
+   */
+  private class DefaultBrowserLauncher extends LaunchMethod {
+
+    public DefaultBrowserLauncher() {
+      super("Default browser");
+    }
+
+    @Override
+    public void launchUrl(URL url) {
+      Throwable caught = null;
+      try {
+        BrowserLauncher.browse(url.toExternalForm());
+        return;
+      } catch (IOException e) {
+        caught = e;
+      } catch (URISyntaxException e) {
+        caught = e;
+      }
+      getLogger().log(TreeLogger.ERROR, "Unable to launch default browser",
+          caught);
+    }
+  }
+
+  /**
+   * Launches a URL by copying it to the clipboard.
+   */
+  private class CopyToClipboardLauncher extends LaunchMethod {
+
+    public CopyToClipboardLauncher() {
+      super("Copy URL to clipboard");
+    }
+
+    @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);
+    }
+  }
+
+  /**
+   * User-visible URL and complete URL for use in combo box.
+   */
+  private static class UrlComboEntry {
+
+    private final String urlFragment;
+    private final URL url;
+
+    public UrlComboEntry(String urlFragment, URL url) {
+      this.urlFragment = urlFragment;
+      this.url = url;
+    }
+
+    public URL getUrl() {
+      return url;
+    }
+
+    @Override
+    public String toString() {
+      return urlFragment;
+    }
+  }
    private SwingLoggerPanel logWindow;
-
+  private JComboBox launchCombo;
+  private JButton launchButton;
+
+  private JComboBox urlCombo;
+
+  /**
+   * @param maxLevel
+   * @param logFile
+   */
    public ShellMainWindow(TreeLogger.Type maxLevel, File logFile) {
      super(new BorderLayout());
      // TODO(jat): add back when we have real options
@@ -42,13 +170,30 @@
        optionPanel.setBorder(BorderFactory.createTitledBorder("Options"));
        optionPanel.add(new JLabel("Miscellaneous options here"));
        panel.add(optionPanel);
-      JPanel launchPanel = new JPanel();
-      launchPanel.setBorder(BorderFactory.createTitledBorder("Launch GWT  
Module"));
-      launchPanel.add(new JLabel(
-          "Selections for launching a new module on a selected browser"));
-      panel.add(launchPanel);
        add(panel, BorderLayout.NORTH);
      }
+    JPanel launchPanel = new JPanel();
+    launchPanel.setBorder(BorderFactory.createTitledBorder(
+        "Launch GWT Module"));
+    launchPanel.add(new JLabel("Startup URL:"));
+    JPanel startupPanel = new JPanel();
+    urlCombo = new JComboBox();
+    urlCombo.addItem("Computing...");
+    startupPanel.add(urlCombo);
+    launchPanel.add(startupPanel);
+    launchPanel.add(new JLabel("Launch Method:"));
+    launchCombo = new JComboBox();
+    populateLaunchComboBox();
+    launchPanel.add(launchCombo);
+    launchButton = new JButton("Loading...");
+    launchButton.setEnabled(false);
+    launchButton.addActionListener(new ActionListener() {
+      public void actionPerformed(ActionEvent e) {
+        launch();
+      }
+    });
+    launchPanel.add(launchButton);
+    add(launchPanel, BorderLayout.NORTH);
      logWindow = new SwingLoggerPanel(maxLevel, logFile);
      add(logWindow);
    }
@@ -59,4 +204,48 @@
    public TreeLogger getLogger() {
      return logWindow.getLogger();
    }
-}
+
+  /**
+   * Indicate that URLs specified in {...@link #setStartupUrls(Map)} are now
+   * launchable.
+   */
+  public void setLaunchable() {
+    if (urlCombo.getItemCount() == 0) {
+      launchButton.setText("No URLs to Launch");
+      urlCombo.addItem("No startup URLs");
+      urlCombo.setEnabled(false);
+      return;
+    }
+    launchButton.setText("Launch");
+    launchButton.setEnabled(true);
+  }
+
+  /**
+   * Create the UI to show available startup URLs.  These should not be
+   * launchable by the user until the {...@link #setLaunchable()} method is  
called.
+   *
+   * @param urls map of user-specified URL fragments to final URLs
+   */
+  public void setStartupUrls(Map<String, URL> urls) {
+    urlCombo.removeAllItems();
+    ArrayList<String> keys = new ArrayList<String>(urls.keySet());
+    Collections.sort(keys);
+    for (String url : keys) {
+      urlCombo.addItem(new UrlComboEntry(url, urls.get(url)));
+    }
+    urlCombo.revalidate();
+  }
+
+  protected void launch() {
+    LaunchMethod launcher = (LaunchMethod) launchCombo.getSelectedItem();
+    UrlComboEntry selectedUrl = (UrlComboEntry) urlCombo.getSelectedItem();
+    URL url = selectedUrl.getUrl();
+    launcher.launchUrl(url);
+  }
+
+  private void populateLaunchComboBox() {
+    // TODO(jat): support scanning for other browsers and launching them
+    launchCombo.addItem(new DefaultBrowserLauncher());
+    launchCombo.addItem(new CopyToClipboardLauncher());
+  }
+}
=======================================
--- /trunk/dev/core/src/com/google/gwt/dev/shell/log/SwingLoggerPanel.java      
 
Mon Nov 23 16:21:36 2009
+++ /trunk/dev/core/src/com/google/gwt/dev/shell/log/SwingLoggerPanel.java      
 
Mon Nov 23 18:34:09 2009
@@ -17,6 +17,7 @@

  import com.google.gwt.core.ext.TreeLogger;
  import com.google.gwt.core.ext.TreeLogger.Type;
+import com.google.gwt.dev.BootStrapPlatform;
  import com.google.gwt.dev.shell.CloseButton;
  import com.google.gwt.dev.shell.CloseButton.Callback;
  import com.google.gwt.dev.shell.log.SwingTreeLogger.LogEvent;
@@ -101,15 +102,15 @@

    private class FindBox extends JPanel {

-    private JTextField searchField;
-    private JLabel searchStatus;
-
      private Popup findPopup;
-
      private String lastSearch;
-    private int matchNumber;
+
      private ArrayList<DefaultMutableTreeNode> matches;

+    private int matchNumber;
+    private JTextField searchField;
+    private JLabel searchStatus;
+
      public FindBox() {
        super(new BorderLayout());
        JPanel top = new JPanel(new FlowLayout());
@@ -241,39 +242,49 @@
      }
    }

-  private static final Color DISCONNECTED_COLOR = Color.decode("0xFFDDDD");
-
-  // package protected for SwingTreeLogger to access
-
-  final JTree tree;
-
-  DefaultTreeModel treeModel;
-
+  /**
+   * The mask to use for Ctrl -- mapped to Command on Mac.
+   */
+  private static int ctrlKeyDown;
+
+
+  private static final Color DISCONNECTED_COLOR = Color.decode("0xFFDDDD");
+
+  static {
+    ctrlKeyDown = BootStrapPlatform.isMac() ?  InputEvent.ALT_DOWN_MASK
+        : InputEvent.CTRL_DOWN_MASK;
+  }
+
+  // package protected for SwingTreeLogger to access
    Type levelFilter;

    String regexFilter;

-  private final JEditorPane details;
-
-  private final TreeLogger logger;
-
-  private DefaultMutableTreeNode root;
-
-  private JTextField regexField;
-
-  private JComboBox levelComboBox;
-
-  private JPanel topPanel;
+  final JTree tree;
+
+  DefaultTreeModel treeModel;
+
+  private CloseHandler closeHandler;
+
+  private CloseButton closeLogger;
+
+  private final JEditorPane details;
+
+  private boolean disconnected = false;

    private FindBox findBox;

-  private JScrollPane treeView;
-
-  private CloseButton closeLogger;
-
-  private CloseHandler closeHandler;
-
-  private boolean disconnected = false;
+  private JComboBox levelComboBox;
+
+  private final TreeLogger logger;
+
+  private JTextField regexField;
+
+  private DefaultMutableTreeNode root;
+
+  private JPanel topPanel;
+
+  private JScrollPane treeView;

    /**
     * Create a Swing-based logger panel, with a tree section and a detail
@@ -407,15 +418,14 @@
        }
      }
      logger = bestLogger;
-    KeyStroke key = KeyStroke.getKeyStroke(KeyEvent.VK_F,
-        InputEvent.CTRL_DOWN_MASK);
+    KeyStroke key = getCommandKeyStroke(KeyEvent.VK_F);
      getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(key, "find");
      getActionMap().put("find", new AbstractAction() {
        public void actionPerformed(ActionEvent e) {
          showFindBox();
        }
      });
-    key = KeyStroke.getKeyStroke(KeyEvent.VK_C, InputEvent.CTRL_DOWN_MASK);
+    key = getCommandKeyStroke(KeyEvent.VK_C);
      tree.getInputMap().put(key, "copy");
      tree.getActionMap().put("copy", new AbstractAction() {
        public void actionPerformed(ActionEvent e) {
@@ -423,14 +433,14 @@
        }
      });
      findBox = new FindBox();
-    key = KeyStroke.getKeyStroke(KeyEvent.VK_N, InputEvent.CTRL_DOWN_MASK);
+    key = getCommandKeyStroke(KeyEvent.VK_N);
       
tree.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(key, "findnext");
      tree.getActionMap().put("findnext", new AbstractAction() {
        public void actionPerformed(ActionEvent e) {
          findBox.nextMatch();
        }
      });
-    key = KeyStroke.getKeyStroke(KeyEvent.VK_P, InputEvent.CTRL_DOWN_MASK);
+    key = getCommandKeyStroke(KeyEvent.VK_P);
       
tree.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(key, "findprev");
      tree.getActionMap().put("findprev", new AbstractAction() {
        public void actionPerformed(ActionEvent e) {
@@ -566,7 +576,7 @@
          JOptionPane.WARNING_MESSAGE);
      return response != JOptionPane.YES_OPTION;
    }
-
+
    protected ArrayList<DefaultMutableTreeNode> doFind(String search) {
      @SuppressWarnings("unchecked")
      Enumeration<DefaultMutableTreeNode> children =  
root.preorderEnumeration();
@@ -631,6 +641,17 @@
      StringSelection selection = new StringSelection(text.toString());
      clipboard.setContents(selection, selection);
    }
+
+  /**
+   * Returns a keystroke which adds the appropriate modifier for a command  
key:
+   * Command on mac, Ctrl everywhere else.
+   *
+   * @param key
+   * @return KeyStroke of the Ctrl/Command-key
+   */
+  private KeyStroke getCommandKeyStroke(int key) {
+    return KeyStroke.getKeyStroke(key, ctrlKeyDown);
+  }

    private String htmlUnescape(String str) {
      // TODO(jat): real implementation, needs to correspond to
=======================================
--- /trunk/dev/core/src/com/google/gwt/dev/ui/DevModeUI.java    Thu Nov 19  
12:24:42 2009
+++ /trunk/dev/core/src/com/google/gwt/dev/ui/DevModeUI.java    Mon Nov 23  
18:34:09 2009
@@ -80,7 +80,7 @@
    public TreeLogger getTopLogger() {
      return getConsoleLogger();
    }
-
+
    /**
     * Create the web server portion of the UI if not already created, and
     * return its TreeLogger instance.
@@ -109,7 +109,15 @@
    public void initialize(Type logLevel) {
      this.logLevel = logLevel;
    }
-
+
+  /**
+   * Indicate to the user that URLs may be started, or actually launch  
browsers
+   * with the URLs specified in {...@link #setStartupUrls(Map)}.
+   */
+  public void launchStartupUrls() {
+    // do nothing by default
+  }
+
    /**
     * Sets the callback for a given event type..
     *
@@ -132,7 +140,7 @@
    public void setStartupUrls(Map<String, URL> urls) {
      // do nothing by default
    }
-
+
    /**
     * Call callback for a given event.
     *
@@ -144,7 +152,7 @@
        UiEvent.Type<?> eventType) {
      return (C) callbacks.get(eventType);
    }
-
+
    /**
     * @return a console-based logger.
     */
@@ -155,14 +163,14 @@
      }
      return consoleLogger;
    }
-
+
    /**
     * @return the log level for all logging.
     */
    protected final Type getLogLevel() {
      return logLevel;
    }
-
+
    /**
     * Returns true if a callback has been registered for an event.
     *

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

Reply via email to