Revision: 7163
Author: [email protected]
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