From 5c3d713df2b7bc38c884a4600564751f1bee5aa0 Mon Sep 17 00:00:00 2001 From: "edburns%acm.org" Date: Thu, 28 Jun 2007 12:05:07 +0000 Subject: [PATCH] M webclient/classes_spec/org/mozilla/webclient/NewWindowEvent.java - changes for new responsibilities of NewWindowEvent *

Indicates the browser is requesting a new window be created to * display a new BrowserControlCanvas instance. This * mechanism is only necessary if your embedding application wishes to * allow the browser to pop up new windows (or tabs). Such is often the * case when the user clicks on an href with a "target" attribute, or * the embedding application wants to enable some right-click "open in * new window" or "open in new tab" feature.

M webclient/classes_spec/org/mozilla/webclient/impl/wrapper_native/NativeBrowserControlCanvas.java M webclient/classes_spec/org/mozilla/webclient/impl/wrapper_native/CocoaBrowserControlCanvas.java M webclient/classes_spec/org/mozilla/webclient/impl/wrapper_native/Win32BrowserControlCanvas.java - introduce new performPlatformAppropriateNewWindowRealization * Allow platform specific handling of new window creation. M webclient/classes_spec/org/mozilla/webclient/impl/wrapper_native/EventRegistrationImpl.java - modify the contract for new window creation M webclient/test/automated/src/classes/org/mozilla/webclient/WindowCreatorTest.java - verify it all works. git-svn-id: svn://10.0.0.236/trunk@228930 18797224-902f-48f8-a5cc-f745e15eee43 --- .../org/mozilla/webclient/NewWindowEvent.java | 125 ++++++++++++++++- .../CocoaBrowserControlCanvas.java | 11 +- .../wrapper_native/EventRegistrationImpl.java | 33 ++--- .../NativeBrowserControlCanvas.java | 8 ++ .../Win32BrowserControlCanvas.java | 21 ++- .../mozilla/webclient/WindowCreatorTest.java | 132 +++++++----------- 6 files changed, 213 insertions(+), 117 deletions(-) diff --git a/mozilla/java/webclient/classes_spec/org/mozilla/webclient/NewWindowEvent.java b/mozilla/java/webclient/classes_spec/org/mozilla/webclient/NewWindowEvent.java index 6148d9ab031..d290eb2e6e1 100644 --- a/mozilla/java/webclient/classes_spec/org/mozilla/webclient/NewWindowEvent.java +++ b/mozilla/java/webclient/classes_spec/org/mozilla/webclient/NewWindowEvent.java @@ -22,7 +22,96 @@ package org.mozilla.webclient; -import java.awt.Container; +import java.util.List; + +/** + * + *

Indicates the browser is requesting a new window be created to + * display a new BrowserControlCanvas instance. This + * mechanism is only necessary if your embedding application wishes to + * allow the browser to pop up new windows (or tabs). Such is often the + * case when the user clicks on an href with a "target" attribute, or + * the embedding application wants to enable some right-click "open in + * new window" or "open in new tab" feature.

+ * + *

Usage contract:

+ * + *

The unfortunately complex usage contract to accomodate differences + * in the UI threading models in a platform indepent manner.

+ * + *

On the application main thread, do something like this:

+ * + *
+
+final List realizeNewWindowRunnableList = 
+   new CopyOnWriteArrayList();
+ 
+eventRegistration.setNewWindowListener(new NewWindowListener() {
+   public void eventDispatched(WebclientEvent wcEvent) {
+     NewWindowEvent event = (NewWindowEvent) wcEvent;
+     final BrowserControlCanvas secondCanvas;
+		    
+     try {
+       secondBrowserControl = 
+         BrowserControlFactory.newBrowserControl();
+       secondCanvas = (BrowserControlCanvas)
+         secondBrowserControl.queryInterface(BrowserControl.BROWSER_CONTROL_CANVAS_NAME);
+     } catch (Throwable e) {
+       System.out.println(e.getMessage());
+       fail();
+       return;
+     }
+	 event.setBrowserControl(secondBrowserControl);
+     event.setRealizeNewWindowRunnableList(realizeNewWindowRunnableList);
+     event.setRealizeNewWindowRunnable(new Runnable() {
+       public void run() {
+         secondFrame.add(secondCanvas, BorderLayout.CENTER);
+         secondFrame.setVisible(true);
+         secondCanvas.setVisible(true);
+       }
+       public String toString() {
+         return "WindowCreatorTest newWindowRunnable";
+         }
+       });
+    }  
+  });
+
+// ... continue with browser code.
+
+  while (realizeNewWindowRunnableList.isEmpty()) {
+    Thread.currentThread().sleep(1000);
+  }
+  
+  for (Runnable cur : realizeNewWindowRunnableList) {
+    cur.run();
+  }
+ * 
+ * + *

The above code accomplishes the folliwng goals:

+ + *

Create a thread safe list data structure. This will hold the + * Runnable that we define to create the parent window and + * make it visible. Add a NewWindowListener instance + * to the "main" BrowserControl. When this listener + * instance receives an eventDispatched call (on a platform + * specific Thread), it must create a new + * BrowserControl, gets its + * BrowserControlCanvas, store the canvas into the event, + * store the thread safe list data structure into the event, and store a + * Runnable into the event that adds the canvas to its parent container, + * and sets the parent container and the canvas visible. This Runnable + * will be called at a platform specific time, on a platform specific + * Thread. The toString() implementation is + * just good practice for debugging.

+ * + *

Meanwhile, back on the main thread the thread safe list data + * structure mest be polled, as often as desired, until Runnable appears + * in the list. It will have been placed there by the Webclient API and + * the embedding application is required to run() it on the main + * thread.

+ * + */ public class NewWindowEvent extends WebclientEvent { @@ -46,15 +135,37 @@ public void setBrowserControl(BrowserControl newBrowserControl) { browserControl = newBrowserControl; } -private Container parentContainer; +private Runnable realizeNewWindowRunnable; - public Container getParentContainer() { - return parentContainer; +protected List browserWillAdd; + +public void setRealizeNewWindowRunnableList(List browserWillAdd){ + this.browserWillAdd = browserWillAdd; +} + +public List getRealizeNewWindowRunnableList() { + return browserWillAdd; +} + +public static class RealizeNewWindowEvent { + private BrowserControl browserControl; + + public BrowserControl getBrowserControl() { + return browserControl; + } + + public void setBrowserControl(BrowserControl browserControl) { + this.browserControl = browserControl; + } +} + + public Runnable getRealizeNewWindowRunnable() { + return realizeNewWindowRunnable; } - public void setParentContainer(Container parentContainer) { - this.parentContainer = parentContainer; + public void setRealizeNewWindowRunnable(Runnable realizeNewWindowRunnable) { + this.realizeNewWindowRunnable = realizeNewWindowRunnable; } - + } // end of class NewWindowEvent diff --git a/mozilla/java/webclient/classes_spec/org/mozilla/webclient/impl/wrapper_native/CocoaBrowserControlCanvas.java b/mozilla/java/webclient/classes_spec/org/mozilla/webclient/impl/wrapper_native/CocoaBrowserControlCanvas.java index 1abfab645fb..7c3bf491ee0 100644 --- a/mozilla/java/webclient/classes_spec/org/mozilla/webclient/impl/wrapper_native/CocoaBrowserControlCanvas.java +++ b/mozilla/java/webclient/classes_spec/org/mozilla/webclient/impl/wrapper_native/CocoaBrowserControlCanvas.java @@ -26,12 +26,12 @@ package org.mozilla.webclient.impl.wrapper_native; -import org.mozilla.webclient.BrowserControlCanvas; -import java.awt.*; +import java.util.List; import java.util.logging.Logger; import org.mozilla.util.Log; import org.mozilla.util.ReturnRunnable; +import org.mozilla.webclient.NewWindowEvent; import org.mozilla.webclient.impl.WrapperFactory; /** @@ -80,6 +80,13 @@ public class CocoaBrowserControlCanvas extends NativeBrowserControlCanvas { return nativeView; } + + void performPlatformAppropriateNewWindowRealization(NewWindowEvent event) { + List addToList = + event.getRealizeNewWindowRunnableList(); + event.getRealizeNewWindowRunnable().run(); + addToList.add(new Runnable() { public void run() {} }); + } public static NativeEventThread newNativeEventThread(WrapperFactory owner) { NativeEventThread result = new CocoaAppKitThreadDelegatingNativeEventThread("WebclientEventThread", diff --git a/mozilla/java/webclient/classes_spec/org/mozilla/webclient/impl/wrapper_native/EventRegistrationImpl.java b/mozilla/java/webclient/classes_spec/org/mozilla/webclient/impl/wrapper_native/EventRegistrationImpl.java index 1422f1acb75..2eb367ae1f3 100644 --- a/mozilla/java/webclient/classes_spec/org/mozilla/webclient/impl/wrapper_native/EventRegistrationImpl.java +++ b/mozilla/java/webclient/classes_spec/org/mozilla/webclient/impl/wrapper_native/EventRegistrationImpl.java @@ -21,8 +21,6 @@ */ package org.mozilla.webclient.impl.wrapper_native; -import java.awt.BorderLayout; -import java.awt.Container; import org.mozilla.util.ParameterCheck; import java.util.ArrayList; @@ -47,13 +45,14 @@ import org.mozilla.util.Log; import org.mozilla.util.ReturnRunnable; import org.mozilla.webclient.BrowserControl; +import org.mozilla.webclient.BrowserControlCanvas; import org.mozilla.webclient.EventRegistration2; -import org.mozilla.webclient.impl.BrowserControlImpl; import org.mozilla.webclient.impl.WrapperFactory; import org.mozilla.webclient.DocumentLoadEvent; import org.mozilla.webclient.DocumentLoadListener; import org.mozilla.webclient.PageInfoListener; import org.mozilla.webclient.NewWindowEvent; +import org.mozilla.webclient.NewWindowEvent.RealizeNewWindowEvent; import org.mozilla.webclient.NewWindowListener; import org.mozilla.webclient.WCKeyEvent; import org.mozilla.webclient.WebclientEvent; @@ -551,28 +550,18 @@ private EventObject createKeyEvent(long eventType, Object eventData) { return keyEvent; } -private int getNativeBrowserControlFromNewWindowEvent(NewWindowEvent event) { - NativeBrowserControlCanvas - currentCanvas = null, - newCanvas = null; - BrowserControlImpl newBrowserControl = null; +private int getNativeBrowserControlFromNewWindowEvent(final NewWindowEvent event) { + final BrowserControl newBrowserControl; + NativeBrowserControlCanvas newCanvas = null; EventRegistration2 newEventRegistration = null; - Container parentContainer = null; int result = 0; - if (null == (newBrowserControl = - (BrowserControlImpl) event.getBrowserControl())) { + if (null == (newBrowserControl = event.getBrowserControl())) { return 0; } - if (null == (parentContainer = - event.getParentContainer())) { - return 0; - } - currentCanvas = browserControlCanvas; try { - newCanvas = - (NativeBrowserControlCanvas) + newCanvas = (NativeBrowserControlCanvas) newBrowserControl.queryInterface(BrowserControl.BROWSER_CONTROL_CANVAS_NAME); } catch (ClassNotFoundException cnfe) { if (LOGGER.isLoggable(Level.SEVERE)) { @@ -582,10 +571,6 @@ private int getNativeBrowserControlFromNewWindowEvent(NewWindowEvent event) { throw new IllegalStateException(cnfe); } - parentContainer.add(newCanvas, BorderLayout.CENTER); - parentContainer.setVisible(true); - newCanvas.setVisible(true); - try { newEventRegistration = (EventRegistration2) newBrowserControl.queryInterface(BrowserControl.EVENT_REGISTRATION_NAME); @@ -602,6 +587,8 @@ private int getNativeBrowserControlFromNewWindowEvent(NewWindowEvent event) { return 0; } + newCanvas.performPlatformAppropriateNewWindowRealization(event); + result = ((ImplObjectNative)newEventRegistration).getNativeBrowserControl(); return result; @@ -834,4 +821,4 @@ class URIToStringMap extends Object implements Map { } -} // end of class EventRegistrationImpl +} // end of class EventRegistrationImpl \ No newline at end of file diff --git a/mozilla/java/webclient/classes_spec/org/mozilla/webclient/impl/wrapper_native/NativeBrowserControlCanvas.java b/mozilla/java/webclient/classes_spec/org/mozilla/webclient/impl/wrapper_native/NativeBrowserControlCanvas.java index b977f6e046e..80a2970f3b5 100644 --- a/mozilla/java/webclient/classes_spec/org/mozilla/webclient/impl/wrapper_native/NativeBrowserControlCanvas.java +++ b/mozilla/java/webclient/classes_spec/org/mozilla/webclient/impl/wrapper_native/NativeBrowserControlCanvas.java @@ -32,6 +32,7 @@ import org.mozilla.util.Assert; import org.mozilla.util.Log; import org.mozilla.webclient.BrowserControl; import org.mozilla.webclient.BrowserControlCanvas; +import org.mozilla.webclient.NewWindowEvent; import org.mozilla.webclient.WindowControl; import org.mozilla.webclient.impl.BrowserControlImpl; import org.mozilla.webclient.impl.WrapperFactory; @@ -88,6 +89,13 @@ abstract class NativeBrowserControlCanvas extends BrowserControlCanvas { abstract protected int getWindow(); + /** + * Allow platform specific handling of new window creation. + * + */ + + abstract void performPlatformAppropriateNewWindowRealization(NewWindowEvent event); + private void createNativeBrowser() throws IllegalStateException { try { Rectangle r = new Rectangle(getBoundsRelativeToWindow()); diff --git a/mozilla/java/webclient/classes_spec/org/mozilla/webclient/impl/wrapper_native/Win32BrowserControlCanvas.java b/mozilla/java/webclient/classes_spec/org/mozilla/webclient/impl/wrapper_native/Win32BrowserControlCanvas.java index 07807bc7807..b4c11316b15 100644 --- a/mozilla/java/webclient/classes_spec/org/mozilla/webclient/impl/wrapper_native/Win32BrowserControlCanvas.java +++ b/mozilla/java/webclient/classes_spec/org/mozilla/webclient/impl/wrapper_native/Win32BrowserControlCanvas.java @@ -22,7 +22,9 @@ package org.mozilla.webclient.impl.wrapper_native; +import java.util.List; import org.mozilla.util.ReturnRunnable; +import org.mozilla.webclient.NewWindowEvent; /** @@ -33,7 +35,7 @@ import org.mozilla.util.ReturnRunnable; * There is one instance of the BrowserControlCanvas per top level awt Frame. - * @version $Id: Win32BrowserControlCanvas.java,v 1.5 2007-06-19 20:18:11 edburns%acm.org Exp $ + * @version $Id: Win32BrowserControlCanvas.java,v 1.6 2007-06-28 12:05:07 edburns%acm.org Exp $ * * @see org.mozilla.webclient.BrowserControlCanvasFactory * @@ -76,6 +78,23 @@ public class Win32BrowserControlCanvas extends NativeBrowserControlCanvas { }); return result.intValue(); } + + void performPlatformAppropriateNewWindowRealization(final NewWindowEvent event) { + final List addToList = + event.getRealizeNewWindowRunnableList(); + NativeEventThread.instance.pushRunnable(new Runnable() { + public void run() { + addToList.add(event.getRealizeNewWindowRunnable()); + } + + public String toString() { + return "EventRegistrationImpl.RealizeNewWindowEvent"; + } + }); + + NativeEventThread.instance.runUntilEventOfType(WindowControlImpl.NativeRealizeWCRunnable.class); + } + public static NativeEventThread newNativeEventThread(WrapperFactory owner) { NativeEventThread result = new NativeEventThread("WebclientEventThread", diff --git a/mozilla/java/webclient/test/automated/src/classes/org/mozilla/webclient/WindowCreatorTest.java b/mozilla/java/webclient/test/automated/src/classes/org/mozilla/webclient/WindowCreatorTest.java index 603c2276296..1fc97fd4299 100644 --- a/mozilla/java/webclient/test/automated/src/classes/org/mozilla/webclient/WindowCreatorTest.java +++ b/mozilla/java/webclient/test/automated/src/classes/org/mozilla/webclient/WindowCreatorTest.java @@ -1,5 +1,5 @@ /* - * $Id: WindowCreatorTest.java,v 1.6 2007-06-19 20:18:13 edburns%acm.org Exp $ + * $Id: WindowCreatorTest.java,v 1.7 2007-06-28 12:05:07 edburns%acm.org Exp $ */ /* @@ -34,8 +34,10 @@ import java.awt.Frame; import java.awt.Robot; import java.awt.event.InputEvent; import java.awt.BorderLayout; -import java.awt.Container; +import java.util.List; +import java.util.concurrent.CopyOnWriteArrayList; import org.mozilla.mcp.junit.WebclientTestCase; +import org.mozilla.webclient.NewWindowEvent.RealizeNewWindowEvent; import org.w3c.dom.Document; import org.w3c.dom.Element; @@ -62,6 +64,10 @@ public class WindowCreatorTest extends WebclientTestCase { static EventRegistration2 eventRegistration; static boolean keepWaiting; + + static BrowserControl secondBrowserControl; + static Frame secondFrame = null; + // // Constants @@ -73,6 +79,9 @@ public class WindowCreatorTest extends WebclientTestCase { public void testNewWindow() throws Exception { BrowserControl firstBrowserControl = null; + secondFrame = new Frame(); + secondFrame.setBounds(100, 100, 540, 380); + final DocumentLoadListenerImpl listener = new DocumentLoadListenerImpl() { public void doEndCheck() { @@ -105,46 +114,39 @@ public class WindowCreatorTest extends WebclientTestCase { eventRegistration.addDocumentLoadListener(listener); final BitSet bitSet = new BitSet(); - final WebclientWrapper secondBrowser = new WebclientWrapper(); + final List realizeNewWindowRunnableList = + new CopyOnWriteArrayList(); eventRegistration.setNewWindowListener(new NewWindowListener() { public void eventDispatched(WebclientEvent wcEvent) { bitSet.set(0); NewWindowEvent event = (NewWindowEvent) wcEvent; - BrowserControl secondBrowserControl = null; - EventRegistration2 secondEventRegistration = null; - Frame parentContainer = new Frame(); - parentContainer.setBounds(100, 100, 540, 380); + final BrowserControlCanvas secondCanvas; try { secondBrowserControl = BrowserControlFactory.newBrowserControl(); - secondEventRegistration = - (EventRegistration2) - secondBrowserControl.queryInterface(BrowserControl.EVENT_REGISTRATION_NAME); - - assertNotNull(secondEventRegistration); - + secondCanvas = (BrowserControlCanvas) + secondBrowserControl. + queryInterface(BrowserControl.BROWSER_CONTROL_CANVAS_NAME); } catch (Throwable e) { System.out.println(e.getMessage()); fail(); + return; } - secondEventRegistration.addDocumentLoadListener(new DocumentLoadListenerImpl() { - public void doEndCheck() { - secondBrowser.setKeepWaiting(false); + event.setBrowserControl(secondBrowserControl); + event.setRealizeNewWindowRunnableList(realizeNewWindowRunnableList); + event.setRealizeNewWindowRunnable(new Runnable() { + public void run() { + secondFrame.add(secondCanvas, BorderLayout.CENTER); + secondFrame.setVisible(true); + secondCanvas.setVisible(true); + } + public String toString() { + return "WindowCreatorTest newWindowRunnable"; } }); - event.setBrowserControl(secondBrowserControl); - event.setParentContainer(parentContainer); - // Pass the content of the new window back to the - // main Thread. - secondBrowser.setParentContainer(parentContainer); - secondBrowser.setBrowserControl(secondBrowserControl); - secondBrowser.setEventRegistration(secondEventRegistration); - secondBrowser.setKeepWaiting(false); - - } }); @@ -160,8 +162,6 @@ public class WindowCreatorTest extends WebclientTestCase { Thread.currentThread().sleep(1000); } - secondBrowser.setKeepWaiting(true); - Robot robot = new Robot(); Document dom = currentPage.getDOM(); @@ -190,68 +190,32 @@ public class WindowCreatorTest extends WebclientTestCase { robot.mouseRelease(InputEvent.BUTTON1_MASK); - // keep waiting until the second window is ready to make visible - while (secondBrowser.isKeepWaiting()) { - Thread.currentThread().sleep(1000); - } - - BrowserControlCanvas secondCanvas = (BrowserControlCanvas) - secondBrowser.getBrowserControl().queryInterface(BrowserControl.BROWSER_CONTROL_CANVAS_NAME); - CurrentPage2 secondCurrentPage = (CurrentPage2) - secondBrowser.getBrowserControl().queryInterface(BrowserControl.CURRENT_PAGE_NAME); - + while (realizeNewWindowRunnableList.isEmpty()) { + Thread.currentThread().sleep(1000); + } + assertTrue(!bitSet.isEmpty()); - assertNotNull(secondCurrentPage); - secondCurrentPage.selectAll(); - selection = secondCurrentPage.getSelection(); - assertTrue(-1 !=selection.toString().indexOf("This is page 1 of the WindowCreatorTest.")); - - secondBrowser.getParentContainer().setVisible(false); - BrowserControlFactory.deleteBrowserControl(secondBrowser.getBrowserControl()); + for (Runnable cur : realizeNewWindowRunnableList) { + cur.run(); + Thread.currentThread().sleep(5000); + CurrentPage2 secondCurrentPage = (CurrentPage2) + secondBrowserControl.queryInterface(BrowserControl.CURRENT_PAGE_NAME); + assertNotNull(secondCurrentPage); + + secondCurrentPage.selectAll(); + selection = secondCurrentPage.getSelection(); + assertTrue(-1 !=selection.toString().indexOf("This is page 1 of the WindowCreatorTest.")); + + secondFrame.setVisible(false); + BrowserControlFactory.deleteBrowserControl(secondBrowserControl); + } + frame.setVisible(false); BrowserControlFactory.deleteBrowserControl(firstBrowserControl); } -} - -class WebclientWrapper { - private boolean keepWaiting = true; - private BrowserControl browserControl = null; - private BrowserControlCanvas canvas = null; - private EventRegistration2 eventRegistration = null; - private Container parentContainer; - - public BrowserControl getBrowserControl() { - return browserControl; - } - - public void setBrowserControl(BrowserControl browserControl) { - this.browserControl = browserControl; - } - - public void setEventRegistration(EventRegistration2 eventRegistration) { - this.eventRegistration = eventRegistration; - } - - public boolean isKeepWaiting() { - return keepWaiting; - } - - public void setKeepWaiting(boolean keepWaiting) { - this.keepWaiting = keepWaiting; - } - - public Container getParentContainer() { - return parentContainer; - } - - public void setParentContainer(Container parentContainer) { - this.parentContainer = parentContainer; - } - -} - +} \ No newline at end of file