KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > openide > util > actions > NodeActionTest


1 /*
2  * The contents of this file are subject to the terms of the Common Development
3  * and Distribution License (the License). You may not use this file except in
4  * compliance with the License.
5  *
6  * You can obtain a copy of the License at http://www.netbeans.org/cddl.html
7  * or http://www.netbeans.org/cddl.txt.
8  *
9  * When distributing Covered Code, include this CDDL Header Notice in each file
10  * and include the License file at http://www.netbeans.org/cddl.txt.
11  * If applicable, add the following below the CDDL Header, with the fields
12  * enclosed by brackets [] replaced by your own identifying information:
13  * "Portions Copyrighted [year] [name of copyright owner]"
14  *
15  * The Original Software is NetBeans. The Initial Developer of the Original
16  * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
17  * Microsystems, Inc. All Rights Reserved.
18  */

19
20 package org.openide.util.actions;
21
22 import java.awt.event.ActionEvent JavaDoc;
23 import java.beans.PropertyChangeEvent JavaDoc;
24 import java.beans.PropertyChangeListener JavaDoc;
25 import java.util.ArrayList JavaDoc;
26 import java.util.Arrays JavaDoc;
27 import java.util.Collection JavaDoc;
28 import java.util.Collections JavaDoc;
29 import java.util.List JavaDoc;
30 import javax.swing.Action JavaDoc;
31 import org.netbeans.junit.NbTestCase;
32 import org.openide.nodes.AbstractNode;
33 import org.openide.nodes.Children;
34 import org.openide.nodes.Node;
35 import org.openide.util.HelpCtx;
36 import org.openide.util.lookup.AbstractLookup;
37 import org.openide.util.lookup.InstanceContent;
38
39 /** Test that node actions are enabled on the right nodes and track selection changes.
40  * @author Jesse Glick
41  */

42 public class NodeActionTest extends NbTestCase {
43     
44     public NodeActionTest(String JavaDoc name) {
45         super(name);
46     }
47     
48     private Node n1, n2, n3;
49     
50     
51     /**
52      * in order to run in awt event queue
53      * fix for #39789
54      */

55     protected boolean runInEQ() {
56         return true;
57     }
58     
59     protected void setUp() throws Exception JavaDoc {
60         n1 = new AbstractNode(Children.LEAF);
61         n1.setName("n1");
62         n1.setDisplayName("text");
63         n2 = new AbstractNode(Children.LEAF);
64         n2.setName("n2");
65         n2.setDisplayName("text");
66         n3 = new AbstractNode(Children.LEAF);
67         n3.setName("n3");
68         n3.setDisplayName("somethingelse");
69     }
70     
71     public void testBasicUsage() throws Exception JavaDoc {
72         SimpleNodeAction a1 = SystemAction.get(SimpleNodeAction.class);
73         ActionsInfraHid.WaitPCL l = new ActionsInfraHid.WaitPCL(NodeAction.PROP_ENABLED);
74         try {
75             // Check enablement logic.
76
a1.addPropertyChangeListener(l);
77             assertFalse(a1.isEnabled());
78             // Note that changes to enabled are made asynch, so it is necessary to listen
79
// for that (will not generally take effect immediately).
80
ActionsInfraHid.setCurrentNodes(new Node[] {n1});
81             assertTrue(l.changed());
82             l.gotit = 0;
83             assertTrue(a1.isEnabled());
84             ActionsInfraHid.setCurrentNodes(new Node[] {n1, n2});
85             assertTrue(l.changed());
86             l.gotit = 0;
87             assertFalse(a1.isEnabled());
88             ActionsInfraHid.setCurrentNodes(new Node[] {n2});
89             assertTrue(l.changed());
90             l.gotit = 0;
91             assertTrue(a1.isEnabled());
92             ActionsInfraHid.setCurrentNodes(new Node[] {n3});
93             assertTrue(l.changed());
94             l.gotit = 0;
95             assertFalse(a1.isEnabled());
96             // Check that the action is performed correctly.
97
ActionsInfraHid.setCurrentNodes(new Node[] {n1});
98             assertTrue(l.changed());
99             l.gotit = 0;
100             assertTrue(a1.isEnabled());
101             a1.actionPerformed(null);
102             a1.actionPerformed(new ActionEvent JavaDoc(a1, ActionEvent.ACTION_PERFORMED, "runit"));
103             assertEquals(Arrays.asList(new List JavaDoc[] {
104                 Collections.singletonList(n1),
105                 Collections.singletonList(n1),
106             }), a1.runOn);
107             // Also that idempotent node list changes do not harm anything, at least.
108
ActionsInfraHid.setCurrentNodes(new Node[] {n1});
109             // It need not fire a change event; if not, just wait a moment for it to recalc.
110
if (!l.changed()) {
111                 //System.err.println("waiting a moment...");
112
Thread.sleep(1000);
113             }
114             l.gotit = 0;
115             assertTrue(a1.isEnabled());
116             ActionsInfraHid.setCurrentNodes(new Node[] {n3});
117             assertTrue(l.changed());
118             l.gotit = 0;
119             assertFalse(a1.isEnabled());
120             ActionsInfraHid.setCurrentNodes(new Node[] {n3});
121             if (!l.changed()) {
122                 //System.err.println("waiting a moment...");
123
Thread.sleep(1000);
124             }
125             l.gotit = 0;
126             assertFalse(a1.isEnabled());
127         } finally {
128             a1.removePropertyChangeListener(l);
129             ActionsInfraHid.setCurrentNodes(new Node[0]);
130             ActionsInfraHid.setCurrentNodes(null);
131             a1.runOn.clear();
132         }
133     }
134     
135     public void testPerformActionWithArgs() throws Exception JavaDoc {
136         SimpleNodeAction a1 = SystemAction.get(SimpleNodeAction.class);
137         try {
138             assertFalse(a1.isEnabled());
139             assertEquals(Collections.EMPTY_LIST, a1.runOn);
140             a1.actionPerformed(new ActionEvent JavaDoc(n1, ActionEvent.ACTION_PERFORMED, "exec"));
141             a1.actionPerformed(new ActionEvent JavaDoc(new Node[] {n1}, ActionEvent.ACTION_PERFORMED, "exec"));
142             assertEquals(Arrays.asList(new List JavaDoc[] {
143                 Collections.singletonList(n1),
144                 Collections.singletonList(n1),
145             }), a1.runOn);
146             // XXX probably NodeAction.actionPerformed with Node or Node[] should
147
// first check that the action is in fact enabled on those nodes, else
148
// throw an IllegalArgumentException; in which case add a test to that effect here
149
} finally {
150             ActionsInfraHid.setCurrentNodes(new Node[0]);
151             ActionsInfraHid.setCurrentNodes(null);
152             a1.runOn.clear();
153         }
154     }
155     
156     /** Test that surviveFocusChange really controls whether node actions are enabled or not.
157      */

158     public void testFocusChange() throws Exception JavaDoc {
159         helpTestFocusChange();
160         // XXX does not work: refuses to collect the node actions!
161
// Yet similar code works in CallbackSystemActionTest.
162
// Profiler shows that the references are held only from WeakReference's,
163
// one of which is in the finalizer queue. ???
164
/*
165         ActionsInfraHid.doGC();
166         assertEquals("Garbage collection removed all SimpleNodeAction's", 0, SimpleNodeAction.INSTANCES);
167         helpTestFocusChange();
168          */

169     }
170     private void helpTestFocusChange() throws Exception JavaDoc {
171         SimpleNodeAction a1 = SystemAction.get(SimpleNodeAction.class);
172         DoesNotSurviveFocusChgAction a2 = SystemAction.get(DoesNotSurviveFocusChgAction.class);
173         ActionsInfraHid.WaitPCL l1 = new ActionsInfraHid.WaitPCL(NodeAction.PROP_ENABLED);
174         ActionsInfraHid.WaitPCL l2 = new ActionsInfraHid.WaitPCL(NodeAction.PROP_ENABLED);
175         try {
176             /*
177             assertEquals(null, ActionsInfraHid.getCurrentNodes());
178             assertEquals(Collections.EMPTY_LIST, Arrays.asList(ActionsInfraHid.getActivatedNodes()));
179              */

180             a1.addPropertyChangeListener(l1);
181             a2.addPropertyChangeListener(l2);
182             assertFalse(a1.isEnabled());
183             assertFalse(a2.isEnabled());
184             ActionsInfraHid.setCurrentNodes(new Node[] {n1});
185             assertTrue(l1.changed());
186             l1.gotit = 0;
187             assertTrue(a1.isEnabled());
188             assertTrue(l2.changed());
189             l2.gotit = 0;
190             assertTrue(a2.isEnabled());
191             ActionsInfraHid.setCurrentNodes(null);
192             assertTrue(l2.changed());
193             l2.gotit = 0;
194             assertFalse(a2.isEnabled());
195             if (!l1.changed()) {
196                 Thread.sleep(1000);
197             }
198             l1.gotit = 0;
199             assertTrue(a1.isEnabled());
200             ActionsInfraHid.setCurrentNodes(new Node[] {n2});
201             assertTrue(l2.changed());
202             l2.gotit = 0;
203             assertTrue(a2.isEnabled());
204             if (!l1.changed()) {
205                 Thread.sleep(1000);
206             }
207             l1.gotit = 0;
208             assertTrue(a1.isEnabled());
209             
210             // another trick, sets n1 to enable everything and then
211
// switches to Node[0] to disable everything
212
ActionsInfraHid.setCurrentNodes(new Node[] {n1});
213             assertTrue(l1.changed());
214             l1.gotit = 0;
215             assertTrue(a1.isEnabled());
216             assertTrue(l2.changed());
217             l2.gotit = 0;
218             assertTrue(a2.isEnabled());
219             ActionsInfraHid.setCurrentNodes(new Node[0]);
220             assertTrue(l2.changed());
221             l2.gotit = 0;
222             assertFalse(a2.isEnabled());
223             l1.gotit = 0;
224             assertFalse(a1.isEnabled());
225         } finally {
226             a1.removePropertyChangeListener(l1);
227             a2.removePropertyChangeListener(l2);
228             ActionsInfraHid.setCurrentNodes(new Node[0]);
229             ActionsInfraHid.setCurrentNodes(null);
230         }
231         a1 = null;
232         a2 = null;
233     }
234     
235     /** Make sure NodeAction itself does not do anything dumb by requiring enablement
236      * checks too often.
237      * The important fix is that even when it has listeners, after firing PROP_ENABLED
238      * in response to a selection change, it should not actually compute the enablement
239      * status again until someone asks isEnabled(). Otherwise it will perpetually be
240      * firing changes, when in fact no one cares (the action is not even visible).
241      * @see "#13505"
242      */

243     public void testNoRedundantEnablementChecks() throws Exception JavaDoc {
244         LazyNodeAction a = SystemAction.get(LazyNodeAction.class);
245         ActionsInfraHid.WaitPCL l = new ActionsInfraHid.WaitPCL(NodeAction.PROP_ENABLED);
246         try {
247             assertEquals(0, a.count);
248             assertFalse(a.listeners);
249             assertFalse(a.isEnabled());
250             a.addPropertyChangeListener(l);
251             assertTrue(a.listeners);
252             assertFalse(a.isEnabled());
253             ActionsInfraHid.setCurrentNodes(new Node[] {n1});
254             assertTrue(l.changed());
255             l.gotit = 0;
256             assertTrue(a.isEnabled());
257             // Now make sure calls to isEnabled() do not do anything while the selection has not changed.
258
a.count = 0;
259             assertTrue(a.isEnabled());
260             assertEquals("Adjacent calls to isEnabled() do not recheck the same node selection", 0, a.count);
261             /* This is pretty irrelevant, it probably never happens anyway:
262             // Make sure equivalent node arrays are not considered significant.
263             ActionsInfraHid.setCurrentNodes(new Node[] {n1});
264             if (!l.changed()) {
265                 Thread.sleep(1000);
266             }
267             l.gotit = 0;
268             assertTrue(a.isEnabled());
269             assertEquals("Adjacent calls to isEnabled() do not recheck equivalent node selections", 0, a.count);
270              */

271             // But a real change is significant and enable(Node[]) is checked.
272
ActionsInfraHid.setCurrentNodes(new Node[] {n2});
273             if (!l.changed()) {
274                 Thread.sleep(1000);
275             }
276             l.gotit = 0;
277             assertTrue(a.isEnabled());
278             assertEquals("A real change to selection calls enable(Node[]) again", 1, a.count);
279             // No checks made just because there was a selection change, but no request.
280
a.count = 0;
281             ActionsInfraHid.setCurrentNodes(new Node[] {n1, n3});
282             assertTrue(l.changed());
283             l.gotit = 0;
284             assertEquals("Do not make extra checks until someone asks", 0, a.count);
285             ActionsInfraHid.setCurrentNodes(new Node[] {n2, n3});
286             assertTrue("Do not keep firing changes when nobody is paying attention", !l.changed());
287             // After detaching all listeners, selection changes are not tracked more than once.
288
a.removePropertyChangeListener(l);
289             assertFalse(a.listeners);
290             ActionsInfraHid.setCurrentNodes(new Node[] {});
291             Thread.sleep(1000);
292             assertFalse(a.isEnabled());
293             a.count = 0;
294             assertFalse(a.isEnabled());
295             assertEquals("Even with no listeners, adjacent isEnabled()s are clean", 0, a.count);
296             ActionsInfraHid.setCurrentNodes(new Node[] {n3});
297             Thread.sleep(1000);
298             assertEquals("With no listeners, node selection changes are ignored", 0, a.count);
299             assertTrue(a.isEnabled());
300             assertEquals("With no listeners, isEnabled() works on demand", 1, a.count);
301         } finally {
302             a.removePropertyChangeListener(l);
303             ActionsInfraHid.setCurrentNodes(new Node[0]);
304             ActionsInfraHid.setCurrentNodes(null);
305             a.count = 0;
306         }
307     }
308     
309     /** Due to lack of a coherent API in NodeAction for telling it that any previous
310      * results with a given node selection are now void, some subclasses such as
311      * CookieAction and Move{Up,Down}Action actually call setEnabled directly, when
312      * some aspect of the selected nodes changes without the selection itself changing.
313      * Make sure that such changes are respected - they had best not call enable() as
314      * typically the subclass itself does the new check anyway - but a subsequent selection
315      * must call enable() again.
316      */

317     public void testCallSetEnabledDirectly() throws Exception JavaDoc {
318         SimpleNodeAction a1 = SystemAction.get(SimpleNodeAction.class);
319         ActionsInfraHid.WaitPCL l = new ActionsInfraHid.WaitPCL(NodeAction.PROP_ENABLED);
320         try {
321             assertFalse(a1.isEnabled());
322             ActionsInfraHid.setCurrentNodes(new Node[] {n1});
323             assertTrue(a1.isEnabled());
324             n1.setDisplayName("foo");
325             a1.setEnabled(false);
326             assertFalse(a1.isEnabled());
327             n1.setDisplayName("text");
328             ActionsInfraHid.setCurrentNodes(new Node[] {n2});
329             assertTrue(a1.isEnabled());
330             // Now try it with listeners.
331
a1.addPropertyChangeListener(l);
332             assertTrue(a1.isEnabled());
333             n2.setDisplayName("foo");
334             a1.setEnabled(false);
335             assertTrue(l.changed());
336             l.gotit = 0;
337             assertFalse(a1.isEnabled());
338             n2.setDisplayName("text");
339             ActionsInfraHid.setCurrentNodes(new Node[] {n1});
340             assertTrue(l.changed());
341             l.gotit = 0;
342             assertTrue(a1.isEnabled());
343             n1.setDisplayName("foo");
344             a1.setEnabled(false);
345             assertTrue(l.changed());
346             l.gotit = 0;
347             assertFalse(a1.isEnabled());
348             n1.setDisplayName("text");
349             ActionsInfraHid.setCurrentNodes(new Node[] {n2});
350             assertTrue(l.changed());
351             l.gotit = 0;
352             assertTrue(a1.isEnabled());
353         } finally {
354             a1.removePropertyChangeListener(l);
355             n1.setDisplayName("text");
356             ActionsInfraHid.setCurrentNodes(new Node[0]);
357             ActionsInfraHid.setCurrentNodes(null);
358         }
359     }
360     
361     //
362
// cloneAction support
363
//
364

365     public void testNodeActionIsCorrectlyClonned() throws Exception JavaDoc {
366         class MN extends AbstractNode {
367             public MN(String JavaDoc displayName) {
368                 super(Children.LEAF);
369                 setDisplayName(displayName);
370             }
371         }
372         
373         class Counter implements PropertyChangeListener JavaDoc {
374             int cnt;
375             
376             public void propertyChange(PropertyChangeEvent JavaDoc ev) {
377                 cnt++;
378             }
379             
380             public void assertCnt(String JavaDoc txt, int cnt) {
381                 assertEquals(txt, cnt, this.cnt);
382                 this.cnt = 0;
383             }
384         }
385         
386         
387         SimpleNodeAction s = SimpleNodeAction.get(SimpleNodeAction.class);
388         Counter counter = new Counter();
389         
390         InstanceContent ic = new InstanceContent();
391         AbstractLookup lookup = new AbstractLookup(ic);
392         
393         Action JavaDoc clone = s.createContextAwareInstance(lookup);
394         clone.addPropertyChangeListener(counter);
395         
396         assertTrue("Not enabled", !clone.isEnabled());
397         
398         MN mn1 = new MN("text");
399         ic.add(mn1);
400         
401         assertTrue("Enabled", clone.isEnabled());
402         counter.assertCnt("Once change in enabled state", 1);
403         
404         clone.actionPerformed(new ActionEvent JavaDoc(this, 0, ""));
405         
406         assertEquals("Has been executed just once: ", 1, SimpleNodeAction.runOn.size());
407         Collection JavaDoc c = (Collection JavaDoc)SimpleNodeAction.runOn.iterator().next();
408         SimpleNodeAction.runOn.clear();
409         assertTrue("Has been executed on mn1", c.contains(mn1));
410         
411         MN mn2 = new MN("x");
412         ic.add(mn2);
413         
414         assertTrue("Not enabled, because there are two items", !clone.isEnabled());
415         counter.assertCnt("Another change in the state", 1);
416         
417         ic.remove(mn1);
418         assertTrue("Not enabled, the one item is not named correctly", !clone.isEnabled());
419         counter.assertCnt("No change right now, the action remains disabled", 0);
420         
421     }
422     
423     
424     public static class SimpleNodeAction extends NodeAction {
425         protected boolean enable(Node[] activatedNodes) {
426             boolean r = activatedNodes.length == 1 &&
427                     activatedNodes[0].getDisplayName().equals("text");
428             //System.err.println("enable: activatedNodes=" + Arrays.asList(activatedNodes) + " r=" + r);
429
return r;
430         }
431         public static final List JavaDoc runOn = new ArrayList JavaDoc(); // List<List<Node>>
432
protected void performAction(Node[] activatedNodes) {
433             runOn.add(Arrays.asList(activatedNodes));
434         }
435         public String JavaDoc getName() {
436             return "SimpleNodeAction";
437         }
438         public HelpCtx getHelpCtx() {
439             return null;
440         }
441         public static int INSTANCES = 0;
442         public SimpleNodeAction() {
443             INSTANCES++;
444         }
445         protected boolean clearSharedData() {
446             INSTANCES--;
447             System.err.println("collecting a SimpleNodeAction or subclass");//XXX
448
return super.clearSharedData();
449         }
450         protected boolean asynchronous() {
451             return false;
452         }
453     }
454     
455     public static class DoesNotSurviveFocusChgAction extends SimpleNodeAction {
456         protected boolean surviveFocusChange() {
457             return false;
458         }
459         public String JavaDoc getName() {
460             return "DoesNotSurviveFocusChgAction";
461         }
462         protected boolean asynchronous() {
463             return false;
464         }
465     }
466     
467     public static class LazyNodeAction extends NodeAction {
468         public static int count = 0;
469         protected boolean enable(Node[] activatedNodes) {
470             count++;
471             return activatedNodes.length == 1;
472         }
473         public static boolean listeners = false;
474         protected void addNotify() {
475             if (listeners) throw new IllegalStateException JavaDoc();
476             super.addNotify();
477             listeners = true;
478         }
479         protected void removeNotify() {
480             if (!listeners) throw new IllegalStateException JavaDoc();
481             listeners = false;
482             super.removeNotify();
483         }
484         protected void performAction(Node[] activatedNodes) {
485             // do nothing
486
}
487         public String JavaDoc getName() {
488             return "LazyNodeAction";
489         }
490         public HelpCtx getHelpCtx() {
491             return null;
492         }
493         protected boolean asynchronous() {
494             return false;
495         }
496     }
497     
498 }
499
Popular Tags