M webclient/classes_spec/org/mozilla/webclient/NewWindowEvent.java

- changes for new responsibilities of NewWindowEvent

 * <p>Indicates the browser is requesting a new window be created to
 * display a new <code>BrowserControlCanvas</code> 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.</p>

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
This commit is contained in:
edburns%acm.org
2007-06-28 12:05:07 +00:00
parent 4489b12465
commit 5c3d713df2
6 changed files with 213 additions and 117 deletions

View File

@@ -22,7 +22,96 @@
package org.mozilla.webclient;
import java.awt.Container;
import java.util.List;
/**
*
* <p>Indicates the browser is requesting a new window be created to
* display a new <code>BrowserControlCanvas</code> 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.</p>
*
* <p>Usage contract:</p>
*
* <p>The unfortunately complex usage contract to accomodate differences
* in the UI threading models in a platform indepent manner.</p>
*
* <p>On the application main thread, do something like this:</p>
*
* <code><pre>
final List<Runnable> realizeNewWindowRunnableList =
new CopyOnWriteArrayList<Runnable>();
<a href="EventRegistrationImpl.html">eventRegistration</a>.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();
}
* </pre></code>
*
* <p>The above code accomplishes the folliwng goals:</p>
* <p>Create a thread safe list data structure. This will hold the
* <code>Runnable</code> that we define to create the parent window and
* make it visible. Add a <code><a
* href="NewWindowListener.html">NewWindowListener</a></code> instance
* to the "main" <code>BrowserControl</code>. When this listener
* instance receives an <code>eventDispatched</code> call (on a platform
* specific <code>Thread</code>), it must create a <b>new</b>
* <code>BrowserControl</code>, gets its
* <code>BrowserControlCanvas</code>, 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
* <code>Thread</code>. The <code>toString()</code> implementation is
* just good practice for debugging.</p>
*
* <p>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.</p>
*
*/
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<Runnable> browserWillAdd;
public void setRealizeNewWindowRunnableList(List<Runnable> browserWillAdd){
this.browserWillAdd = browserWillAdd;
}
public List<Runnable> 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

View File

@@ -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<Runnable> addToList =
event.getRealizeNewWindowRunnableList();
event.getRealizeNewWindowRunnable().run();
addToList.add(new Runnable() { public void run() {} });
}
public static NativeEventThread newNativeEventThread(WrapperFactory owner) {
NativeEventThread result = new CocoaAppKitThreadDelegatingNativeEventThread("WebclientEventThread",

View File

@@ -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

View File

@@ -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());

View File

@@ -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<Runnable> 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",

View File

@@ -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<Runnable> realizeNewWindowRunnableList =
new CopyOnWriteArrayList<Runnable>();
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;
}
}
}