diff -r 4fe4a8fce84e core.ui/nbproject/project.xml
--- a/core.ui/nbproject/project.xml Mon Jul 27 00:17:05 2009 +0400
+++ b/core.ui/nbproject/project.xml Mon Jul 27 09:35:02 2009 +0200
@@ -94,7 +94,7 @@
- 7.10
+ 7.12
diff -r 4fe4a8fce84e core.ui/src/org/netbeans/core/ui/resources/layer.xml
--- a/core.ui/src/org/netbeans/core/ui/resources/layer.xml Mon Jul 27 00:17:05 2009 +0400
+++ b/core.ui/src/org/netbeans/core/ui/resources/layer.xml Mon Jul 27 09:35:02 2009 +0200
@@ -73,6 +73,7 @@
+
diff -r 4fe4a8fce84e openide.awt/apichanges.xml
--- a/openide.awt/apichanges.xml Mon Jul 27 00:17:05 2009 +0400
+++ b/openide.awt/apichanges.xml Mon Jul 27 09:35:02 2009 +0200
@@ -47,6 +47,32 @@
AWT API
+
+
+ Support for asynchronous actions
+
+
+
+
+
+ The layer definition used by factory methods for
+
+ context
+ and
+
+ callback
+ and
+
+ alwaysEnabledAction
+ were enhanced to understand <attr name="asynchronous" boolvalue="true"/>
+ attribute. This extends these new factories with capabilities
+ already present in old SystemAction
, thus makes
+ it easier to migrate from old to new while retaining compatible
+ behaviour.
+
+
+
+
Added dispose() method.
diff -r 4fe4a8fce84e openide.awt/nbproject/project.properties
--- a/openide.awt/nbproject/project.properties Mon Jul 27 00:17:05 2009 +0400
+++ b/openide.awt/nbproject/project.properties Mon Jul 27 09:35:02 2009 +0200
@@ -44,4 +44,4 @@
javadoc.arch=${basedir}/arch.xml
javadoc.apichanges=${basedir}/apichanges.xml
-spec.version.base=7.11.0
+spec.version.base=7.12.0
diff -r 4fe4a8fce84e openide.awt/src/org/openide/awt/Actions.java
--- a/openide.awt/src/org/openide/awt/Actions.java Mon Jul 27 00:17:05 2009 +0400
+++ b/openide.awt/src/org/openide/awt/Actions.java Mon Jul 27 09:35:02 2009 +0200
@@ -404,6 +404,7 @@
* <attr name="displayName" bundlevalue="your.pkg.Bundle#key"/>
* <attr name="iconBase" stringvalue="your/pkg/YourImage.png"/>
* <!-- if desired: <attr name="noIconInMenu" boolvalue="false"/> -->
+ * <!-- if desired: <attr name="asynchronous" boolvalue="true"/> -->
* </file>
*
* In case the "delegate" is not just {@link ActionListener}, but also
@@ -451,6 +452,7 @@
* <attr name="displayName" bundlevalue="your.pkg.Bundle#key"/>
* <attr name="iconBase" stringvalue="your/pkg/YourImage.png"/>
* <!-- if desired: <attr name="noIconInMenu" boolvalue="false"/> -->
+ * <!-- if desired: <attr name="asynchronous" boolvalue="true"/> -->
* </file>
*
*
@@ -508,6 +510,7 @@
* <attr name="displayName" bundlevalue="your.pkg.Bundle#key"/>
* <attr name="iconBase" stringvalue="your/pkg/YourImage.png"/>
* <!-- if desired: <attr name="noIconInMenu" boolvalue="false"/> -->
+ * <!-- if desired: <attr name="asynchronous" boolvalue="true"/> -->
* </file>
*
* In the previous case there has to be a class with public default constructor
diff -r 4fe4a8fce84e openide.awt/src/org/openide/awt/AlwaysEnabledAction.java
--- a/openide.awt/src/org/openide/awt/AlwaysEnabledAction.java Mon Jul 27 00:17:05 2009 +0400
+++ b/openide.awt/src/org/openide/awt/AlwaysEnabledAction.java Mon Jul 27 09:35:02 2009 +0200
@@ -16,6 +16,8 @@
import javax.swing.Icon;
import javax.swing.KeyStroke;
import javax.swing.text.Keymap;
+import org.netbeans.modules.openide.util.ActionsBridge;
+import org.netbeans.modules.openide.util.ActionsBridge.ActionRunnable;
import org.openide.util.ContextAwareAction;
import org.openide.util.ImageUtilities;
import org.openide.util.Lookup;
@@ -102,7 +104,7 @@
return true;
}
- public void actionPerformed(ActionEvent e) {
+ public void actionPerformed(final ActionEvent e) {
assert EventQueue.isDispatchThread();
if (getDelegate() instanceof Action) {
if (!((Action)getDelegate()).isEnabled()) {
@@ -112,7 +114,14 @@
}
}
- getDelegate().actionPerformed(e);
+ boolean async = Boolean.TRUE.equals(map.get("asynchronous")); // NOI18N
+ ActionRunnable ar = new ActionRunnable(e, this, async) {
+ @Override
+ protected void run() {
+ getDelegate().actionPerformed(e);
+ }
+ };
+ ActionsBridge.doPerformAction(this, ar);
}
@Override
diff -r 4fe4a8fce84e openide.awt/src/org/openide/awt/ContextAction.java
--- a/openide.awt/src/org/openide/awt/ContextAction.java Mon Jul 27 00:17:05 2009 +0400
+++ b/openide.awt/src/org/openide/awt/ContextAction.java Mon Jul 27 09:35:02 2009 +0200
@@ -103,8 +103,6 @@
/** Invoked when an action occurs.
*/
public void actionPerformed(final java.awt.event.ActionEvent e) {
- assert EventQueue.isDispatchThread();
-
global.actionPerformed(e, performer, type, selectMode);
}
diff -r 4fe4a8fce84e openide.awt/src/org/openide/awt/GeneralAction.java
--- a/openide.awt/src/org/openide/awt/GeneralAction.java Mon Jul 27 00:17:05 2009 +0400
+++ b/openide.awt/src/org/openide/awt/GeneralAction.java Mon Jul 27 09:35:02 2009 +0200
@@ -49,6 +49,8 @@
import java.util.logging.Logger;
import javax.swing.Action;
import javax.swing.ActionMap;
+import org.netbeans.modules.openide.util.ActionsBridge;
+import org.netbeans.modules.openide.util.ActionsBridge.ActionRunnable;
import org.openide.awt.ContextAction.Performer;
import org.openide.util.ContextAwareAction;
import org.openide.util.Lookup;
@@ -69,12 +71,12 @@
static final Logger LOG = Logger.getLogger(GeneralAction.class.getName());
public static ContextAwareAction callback(
- String key, Action defaultDelegate, Lookup context, boolean surviveFocusChange
+ String key, Action defaultDelegate, Lookup context, boolean surviveFocusChange, boolean async
) {
if (key == null) {
throw new NullPointerException();
}
- return new DelegateAction(null, key, context, defaultDelegate, surviveFocusChange);
+ return new DelegateAction(null, key, context, defaultDelegate, surviveFocusChange, async);
}
public static Action alwaysEnabled(Map map) {
@@ -161,6 +163,8 @@
private Action fallback;
/** key to delegate to */
private Object key;
+ /** are we asynchronous? */
+ private final boolean async;
/** global lookup to work with */
private GlobalManager global;
@@ -175,12 +179,13 @@
* listens for changes of ActionMap
in order to delegate
* to right action.
*/
- public DelegateAction(Map map, Object key, Lookup actionContext, Action fallback, boolean surviveFocusChange) {
+ public DelegateAction(Map map, Object key, Lookup actionContext, Action fallback, boolean surviveFocusChange, boolean async) {
this.map = map;
this.key = key;
this.fallback = fallback;
this.global = GlobalManager.findManager(actionContext, surviveFocusChange);
this.weakL = WeakListeners.propertyChange(this, fallback);
+ this.async = async;
if (fallback != null) {
fallback.addPropertyChangeListener(weakL);
}
@@ -192,7 +197,8 @@
map.get("key"), // NOI18N
Utilities.actionsGlobalContext(), // NOI18N
fallback, // NOI18N
- Boolean.TRUE.equals(map.get("surviveFocusChange")) // NOI18N
+ Boolean.TRUE.equals(map.get("surviveFocusChange")), // NOI18N
+ Boolean.TRUE.equals(map.get("asynchronous")) // NOI18N
);
}
@@ -208,7 +214,8 @@
assert EventQueue.isDispatchThread();
final javax.swing.Action a = findAction();
if (a != null) {
- a.actionPerformed(e);
+ ActionRunnable ar = ActionRunnable.create(e, a, async);
+ ActionsBridge.doPerformAction(a, ar);
}
}
@@ -288,7 +295,7 @@
if (f instanceof ContextAwareAction) {
f = ((ContextAwareAction)f).createContextAwareInstance(actionContext);
}
- return new DelegateAction(map, key, actionContext, f, global.isSurvive());
+ return new DelegateAction(map, key, actionContext, f, global.isSurvive(), async);
}
public void propertyChange(PropertyChangeEvent evt) {
diff -r 4fe4a8fce84e openide.awt/test/unit/src/org/openide/awt/AsynchronousTest.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/openide.awt/test/unit/src/org/openide/awt/AsynchronousTest.java Mon Jul 27 09:35:02 2009 +0200
@@ -0,0 +1,185 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of either the GNU
+ * General Public License Version 2 only ("GPL") or the Common
+ * Development and Distribution License("CDDL") (collectively, the
+ * "License"). You may not use this file except in compliance with the
+ * License. You can obtain a copy of the License at
+ * http://www.netbeans.org/cddl-gplv2.html
+ * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
+ * specific language governing permissions and limitations under the
+ * License. When distributing the software, include this License Header
+ * Notice in each file and include the License file at
+ * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun in the GPL Version 2 section of the License file that
+ * accompanied this code. If applicable, add the following below the
+ * License Header, with the fields enclosed by brackets [] replaced by
+ * your own identifying information:
+ * "Portions Copyrighted [year] [name of copyright owner]"
+ *
+ * Contributor(s):
+ *
+ * The Original Software is NetBeans. The Initial Developer of the Original
+ * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
+ * Microsystems, Inc. All Rights Reserved.
+ *
+ * If you wish your version of this file to be governed by only the CDDL
+ * or only the GPL Version 2, indicate your decision by adding
+ * "[Contributor] elects to include this software in this distribution
+ * under the [CDDL or GPL Version 2] license." If you do not indicate a
+ * single choice of license, a recipient has the option to distribute
+ * your version of this file under either the CDDL, the GPL Version 2 or
+ * to extend the choice of license to its licensees as provided above.
+ * However, if you add GPL Version 2 code and therefore, elected the GPL
+ * Version 2 license, then the option applies only if the new code is
+ * made subject to such option by the copyright holder.
+ */
+
+package org.openide.awt;
+
+import java.awt.event.ActionEvent;
+import java.util.logging.Level;
+import javax.swing.AbstractAction;
+import javax.swing.Action;
+import org.netbeans.junit.Log;
+import org.netbeans.junit.NbTestCase;
+import org.openide.filesystems.FileUtil;
+import org.openide.util.ContextAwareAction;
+import org.openide.util.Lookup;
+
+/** Verifies asynchronous aspects of actions systems are close to the
+ * original behaviour of SystemAction one.
+ * Taken from org.openide.util.actions.AsynchronousTest
+ * @author Jaroslav Tulach
+ */
+public class AsynchronousTest extends NbTestCase {
+
+ private CharSequence err;
+
+ public AsynchronousTest(String name) {
+ super(name);
+ }
+
+ @Override
+ protected int timeOut() {
+ return 5000;
+ }
+
+ @Override
+ protected boolean runInEQ() {
+ return true;
+ }
+
+ @Override
+ protected void setUp() {
+ err = Log.enable("", Level.WARNING);
+ AC.finished = false;
+ }
+
+ public void testExecutionOfActionsThatDoesNotDefineAsynchronousIsSynchronousNoWarningIsPrinted() throws Exception {
+ Action action = (Action)FileUtil.getConfigFile("actions/async/none.instance").getAttribute("instanceCreate");
+
+ synchronized (AsynchronousTest.class) {
+ action.actionPerformed(new ActionEvent(this, 0, ""));
+ assertTrue("The synchronous action is finished immediatelly", AC.finished);
+ }
+
+ if (err.length() > 0) {
+ fail("There should be no warning about missing asynchronous: " + err);
+ }
+ }
+
+ public void testExecutionCanBeAsynchronous() throws Exception {
+ Action action = (Action)FileUtil.getConfigFile("actions/async/true.instance").getAttribute("instanceCreate");
+
+ synchronized (AsynchronousTest.class) {
+ action.actionPerformed(new ActionEvent(this, 0, ""));
+ Thread.sleep(500);
+ assertFalse("Shall Not be finished yet", AC.finished);
+ AsynchronousTest.class.wait();
+ assertTrue("The asynchronous action is finished", AC.finished);
+ }
+
+ if (err.length() > 0) {
+ fail("No warning about the class: " + err);
+ }
+ }
+
+ public void testExecutionCanBeAsynchronousForAlways() throws Exception {
+ Action action = (Action)FileUtil.getConfigFile("actions/async/true-always.instance").getAttribute("instanceCreate");
+
+ synchronized (AsynchronousTest.class) {
+ action.actionPerformed(new ActionEvent(this, 0, ""));
+ Thread.sleep(500);
+ assertFalse("Shall Not be finished yet", AC.finished);
+ AsynchronousTest.class.wait();
+ assertTrue("The asynchronous action is finished", AC.finished);
+ }
+
+ if (err.length() > 0) {
+ fail("No warning about the class: " + err);
+ }
+ }
+ public void testExecutionCanBeSynchronous() throws Exception {
+ Action action = (Action)FileUtil.getConfigFile("actions/async/false.instance").getAttribute("instanceCreate");
+
+ synchronized (AsynchronousTest.class) {
+ action.actionPerformed(new ActionEvent(this, 0, ""));
+ assertTrue("The synchronous action is finished immediatelly", AC.finished);
+ }
+
+ if (err.length() > 0) {
+ fail("No warning about the class: " + err);
+ }
+ }
+
+ public void testExecutionCanBeForcedToBeSynchronous() throws Exception {
+ Action action = (Action)FileUtil.getConfigFile("actions/async/true.instance").getAttribute("instanceCreate");
+
+ synchronized (AsynchronousTest.class) {
+ action.actionPerformed(new ActionEvent(this, 0, "waitFinished"));
+ assertTrue("When asked for synchronous the action is finished immediatelly", AC.finished);
+ }
+
+ if (err.length() > 0) {
+ fail("No warning about the class: " + err);
+ }
+ }
+
+ public void testExecutionCanBeAsynchronousForContext() throws Exception {
+ Action action = (Action)FileUtil.getConfigFile("actions/async/true-context.instance").getAttribute("instanceCreate");
+
+ synchronized (AsynchronousTest.class) {
+ action.actionPerformed(new ActionEvent(this, 0, ""));
+ Thread.sleep(500);
+ assertFalse("Shall Not be finished yet", AC.finished);
+ AsynchronousTest.class.wait();
+ assertTrue("The asynchronous action is finished", AC.finished);
+ }
+
+ if (err.length() > 0) {
+ fail("No warning about the class: " + err);
+ }
+ }
+
+ public static class AC extends AbstractAction {
+ static boolean finished;
+
+ public void actionPerformed(ActionEvent ev) {
+ synchronized (AsynchronousTest.class) {
+ AsynchronousTest.class.notifyAll();
+ finished = true;
+ }
+ }
+ }
+
+ public static class CAC extends AC implements ContextAwareAction {
+ public Action createContextAwareInstance(Lookup actionContext) {
+ return this;
+ }
+ }
+}
diff -r 4fe4a8fce84e openide.awt/test/unit/src/org/openide/awt/CallbackActionTest.java
--- a/openide.awt/test/unit/src/org/openide/awt/CallbackActionTest.java Mon Jul 27 00:17:05 2009 +0400
+++ b/openide.awt/test/unit/src/org/openide/awt/CallbackActionTest.java Mon Jul 27 09:35:02 2009 +0200
@@ -180,7 +180,7 @@
}
static ContextAwareAction callback(String key, AbstractAction fallAction, Lookup al, boolean b) {
- return GeneralAction.callback(key, fallAction, al, b);
+ return GeneralAction.callback(key, fallAction, al, b, false);
}
private static final class CntListener extends Object
diff -r 4fe4a8fce84e openide.awt/test/unit/src/org/openide/awt/GeneralActionTest.java
--- a/openide.awt/test/unit/src/org/openide/awt/GeneralActionTest.java Mon Jul 27 00:17:05 2009 +0400
+++ b/openide.awt/test/unit/src/org/openide/awt/GeneralActionTest.java Mon Jul 27 09:35:02 2009 +0200
@@ -81,7 +81,7 @@
ContextAwareAction expResult = null;
try {
- ContextAwareAction result = GeneralAction.callback(key, defaultDelegate, context, false);
+ ContextAwareAction result = GeneralAction.callback(key, defaultDelegate, context, false, false);
fail("Shall fail as key is null");
} catch (NullPointerException ex) {
// ok
diff -r 4fe4a8fce84e openide.awt/test/unit/src/org/openide/awt/test-layer.xml
--- a/openide.awt/test/unit/src/org/openide/awt/test-layer.xml Mon Jul 27 00:17:05 2009 +0400
+++ b/openide.awt/test/unit/src/org/openide/awt/test-layer.xml Mon Jul 27 09:35:02 2009 +0200
@@ -170,5 +170,42 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff -r 4fe4a8fce84e openide.util/src/org/netbeans/modules/openide/util/ActionsBridge.java
--- a/openide.util/src/org/netbeans/modules/openide/util/ActionsBridge.java Mon Jul 27 00:17:05 2009 +0400
+++ b/openide.util/src/org/netbeans/modules/openide/util/ActionsBridge.java Mon Jul 27 09:35:02 2009 +0200
@@ -61,6 +61,12 @@
protected abstract void invokeAction(Action action, ActionEvent ev);
public static void doPerformAction(CallableSystemAction action, final ActionsBridge.ActionRunnable r) {
+ implPerformAction(action, r);
+ }
+ public static void doPerformAction(Action action, final ActionsBridge.ActionRunnable r) {
+ implPerformAction(action, r);
+ }
+ private static void implPerformAction(Action action, final ActionsBridge.ActionRunnable r) {
assert java.awt.EventQueue.isDispatchThread() : "Action " + action.getClass().getName() +
" may not be invoked from the thread " + Thread.currentThread().getName() +
", only the event queue: http://www.netbeans.org/download/4_1/javadoc/OpenAPIs/apichanges.html#actions-event-thread";
@@ -83,15 +89,27 @@
*/
public static abstract class ActionRunnable implements Action {
final ActionEvent ev;
- final SystemAction action;
+ final Action action;
final boolean async;
public ActionRunnable(ActionEvent ev, SystemAction action, boolean async) {
+ this(ev, (Action)action, async);
+ }
+ public ActionRunnable(ActionEvent ev, Action action, boolean async) {
this.ev = ev;
this.action = action;
this.async = async;
}
+ public static ActionRunnable create(ActionEvent ev, Action a, boolean async) {
+ return new ActionRunnable(ev, a, async) {
+ @Override
+ protected void run() {
+ action.actionPerformed(ev);
+ }
+ };
+ }
+
public final boolean needsToBeSynchronous() {
return "waitFinished".equals(ev.getActionCommand()); // NOI18N
}