001: /*
002: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
003: *
004: * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
005: *
006: * The contents of this file are subject to the terms of either the GNU
007: * General Public License Version 2 only ("GPL") or the Common
008: * Development and Distribution License("CDDL") (collectively, the
009: * "License"). You may not use this file except in compliance with the
010: * License. You can obtain a copy of the License at
011: * http://www.netbeans.org/cddl-gplv2.html
012: * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
013: * specific language governing permissions and limitations under the
014: * License. When distributing the software, include this License Header
015: * Notice in each file and include the License file at
016: * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
017: * particular file as subject to the "Classpath" exception as provided
018: * by Sun in the GPL Version 2 section of the License file that
019: * accompanied this code. If applicable, add the following below the
020: * License Header, with the fields enclosed by brackets [] replaced by
021: * your own identifying information:
022: * "Portions Copyrighted [year] [name of copyright owner]"
023: *
024: * Contributor(s):
025: *
026: * The Original Software is NetBeans. The Initial Developer of the Original
027: * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
028: * Microsystems, Inc. All Rights Reserved.
029: *
030: * If you wish your version of this file to be governed by only the CDDL
031: * or only the GPL Version 2, indicate your decision by adding
032: * "[Contributor] elects to include this software in this distribution
033: * under the [CDDL or GPL Version 2] license." If you do not indicate a
034: * single choice of license, a recipient has the option to distribute
035: * your version of this file under either the CDDL, the GPL Version 2 or
036: * to extend the choice of license to its licensees as provided above.
037: * However, if you add GPL Version 2 code and therefore, elected the GPL
038: * Version 2 license, then the option applies only if the new code is
039: * made subject to such option by the copyright holder.
040: */
041:
042: package org.openide.windows;
043:
044: import java.awt.BorderLayout;
045: import java.awt.Component;
046: import java.awt.DefaultKeyboardFocusManager;
047: import java.awt.KeyboardFocusManager;
048: import java.awt.event.ActionEvent;
049: import java.beans.FeatureDescriptor;
050: import java.util.*;
051: import javax.swing.AbstractAction;
052: import javax.swing.ActionMap;
053: import javax.swing.JTextField;
054:
055: import junit.framework.*;
056:
057: import org.netbeans.junit.*;
058: import org.openide.cookies.*;
059: import org.openide.nodes.*;
060: import org.openide.util.*;
061: import org.openide.util.lookup.AbstractLookup;
062: import org.openide.util.lookup.InstanceContent;
063:
064: /**
065: * Check the behaviour of TopComponent's lookup.
066: * @author Jaroslav Tulach, Jesse Glick
067: */
068: public class TopComponentGetLookupTest extends NbTestCase {
069:
070: /** top component we work on */
071: protected TopComponent top;
072: protected TopComponent get;
073: /** its lookup */
074: protected Lookup lookup;
075:
076: public TopComponentGetLookupTest(String testName) {
077: super (testName);
078: }
079:
080: public static Test suite() {
081: return new NbTestSuite(TopComponentGetLookupTest.class);
082: }
083:
084: /** Setup component with lookup.
085: */
086: protected void setUp() {
087: top = new TopComponent();
088: get = top;
089: lookup = top.getLookup();
090: }
091:
092: protected boolean runInEQ() {
093: return true;
094: }
095:
096: /** Test to find nodes.
097: */
098: private void doTestNodes(Node[] arr, Class c, int cnt) {
099: if (arr != null) {
100: top.setActivatedNodes(arr);
101: }
102:
103: assertNotNull("At least one node is registered", lookup
104: .lookup(c));
105: Lookup.Result res = lookup.lookup(new Lookup.Template(c));
106: Collection coll = res.allItems();
107: assertEquals("Two registered: " + coll, cnt, coll.size());
108: }
109:
110: public void testNodes() {
111: doTestNodes(new Node[] { new N("1"), new N("2") }, N.class, 2);
112: doTestNodes(new Node[] { new N("1"), new N("2") },
113: FeatureDescriptor.class, 2);
114: }
115:
116: private void doTestNodesWithChangesInLookup(Class c) {
117: InstanceContent ic = new InstanceContent();
118:
119: Node[] arr = new Node[] {
120: new AbstractNode(Children.LEAF, new AbstractLookup(ic)),
121: new AbstractNode(Children.LEAF, Lookup.EMPTY), };
122: arr[0].setName("cookie-container-node");
123: arr[1].setName("node-as-cookie");
124: //doTestNodes(arr, AbstractNode.class);
125: doTestNodes(arr, c, 2);
126:
127: ic.add(arr[1]);
128:
129: /* Huh? There should be both [0] and [1], how can you say which one will be returned?
130: assertEquals ("Now the [1] is in lookup of [0]", arr[1], lookup.lookup (c));
131: */
132: Collection all = lookup.lookup(new Lookup.Template(c))
133: .allInstances();
134: assertEquals("Two nodes are in TC lookup", 2, all.size());
135: assertEquals("They are the ones we expect", new HashSet(Arrays
136: .asList(arr)), new HashSet(all));
137: assertTrue("Lookup simple query gives one or the other",
138: new HashSet(Arrays.asList(arr)).contains(lookup
139: .lookup(c)));
140: assertEquals("Have two lookup items", 2, lookup.lookup(
141: new Lookup.Template(c)).allItems().size());
142:
143: doTestNodes(null, c, 2);
144: }
145:
146: public void testNodesWhenTheyAreNotInTheirLookup() {
147: doTestNodesWithChangesInLookup(AbstractNode.class);
148: }
149:
150: public void testNodesSuperclassesWhenTheyAreNotInTheirLookup() {
151: doTestNodesWithChangesInLookup(FeatureDescriptor.class);
152: }
153:
154: public void testFilterNodeProblems() {
155: class CookieN extends AbstractNode implements Node.Cookie {
156: public CookieN() {
157: super (Children.LEAF);
158: getCookieSet().add(this );
159: }
160:
161: }
162:
163: CookieN n = new CookieN();
164: FilterNode fn = new FilterNode(n);
165: top.setActivatedNodes(new Node[] { fn });
166: assertTrue("CookieN is in FilterNode lookup", n == fn
167: .getLookup().lookup(CookieN.class));
168: assertTrue("CookieN is in TopComponent", n == lookup
169: .lookup(CookieN.class));
170: assertEquals("Just one node", 1, lookup.lookup(
171: new Lookup.Template(Node.class)).allItems().size());
172: assertTrue("Plain cookie found", n == lookup
173: .lookup(Node.Cookie.class));
174: }
175:
176: /** Tests changes in cookies.
177: */
178: public void testCookies() {
179: N[] arr = { new N("1"), new N("2"), new N("3") };
180:
181: top.setActivatedNodes(arr);
182: assertEquals("Three nodes there", 3,
183: top.getActivatedNodes().length);
184:
185: L l = new L();
186: Lookup.Result res = lookup.lookup(new Lookup.Template(
187: OpenCookie.class));
188: res.addLookupListener(l);
189:
190: assertEquals("Empty now", res.allItems().size(), 0);
191:
192: arr[0].state(0x01); // enabled open cookie
193:
194: assertEquals("One item", res.allItems().size(), 1);
195: l.check("One change", 1);
196:
197: arr[2].state(0x02); // change of different cookie
198:
199: assertEquals("Still one item", res.allItems().size(), 1);
200: l.check("No change", 0);
201:
202: arr[2].state(0x03); // added also OpenCookie
203:
204: assertEquals("Both items", res.allItems().size(), 2);
205: l.check("One change again", 1);
206:
207: arr[0].state(0x00);
208:
209: assertEquals("One still there", res.allItems().size(), 1);
210: assertEquals("The second object", lookup
211: .lookup(OpenCookie.class), arr[2]
212: .getCookie(OpenCookie.class));
213:
214: top.setActivatedNodes(new Node[0]);
215: assertNull("No cookie now", lookup.lookup(OpenCookie.class));
216: }
217:
218: public void testNodesAreInTheLookupAndNothingIsFiredBeforeFirstQuery() {
219: AbstractNode n1 = new AbstractNode(Children.LEAF, Lookup.EMPTY);
220: top.setActivatedNodes(new Node[] { n1 });
221: assertEquals("One node there", 1,
222: top.getActivatedNodes().length);
223: assertEquals("Is the right now", n1, top.getActivatedNodes()[0]);
224:
225: Lookup.Result res = lookup.lookup(new Lookup.Template(
226: Node.class));
227: L l = new L();
228: res.addLookupListener(l);
229:
230: l.check("Nothing fired before first query", 0);
231: res.allInstances();
232: l.check("Nothing is fired on first query", 0);
233: lookup.lookup(new Lookup.Template(Node.class)).allInstances();
234: l.check("And additional query does not change anything either",
235: 0);
236: }
237:
238: public void testNodesAreThereEvenIfTheyAreNotContainedInTheirOwnLookup() {
239: Lookup.Result res = lookup.lookup(new Lookup.Template(
240: Node.class));
241:
242: AbstractNode n1 = new AbstractNode(Children.LEAF, Lookup.EMPTY);
243:
244: InstanceContent content = new InstanceContent();
245: AbstractNode n2 = new AbstractNode(Children.LEAF,
246: new AbstractLookup(content));
247:
248: assertNull("Not present in its lookup", n1.getLookup().lookup(
249: n1.getClass()));
250: assertNull("Not present in its lookup", n2.getLookup().lookup(
251: n2.getClass()));
252:
253: top.setActivatedNodes(new AbstractNode[] { n1 });
254: assertEquals("But node is in the lookup", n1, lookup.lookup(n1
255: .getClass()));
256:
257: assertEquals("One item there", 1, res.allInstances().size());
258:
259: L listener = new L();
260: res.addLookupListener(listener);
261:
262: top.setActivatedNodes(new AbstractNode[] { n2 });
263: assertEquals("One node there", 1,
264: top.getActivatedNodes().length);
265: assertEquals("n2", n2, top.getActivatedNodes()[0]);
266:
267: //MK - here it changes twice.. because the setAtivatedNodes is trigger on inner TC, then lookup of MVTC contains old activated node..
268: // at this monent the merged lookup contains both items.. later it gets synchronized by setting the activated nodes on the MVTC as well..
269: // then it contains only the one correct node..
270: listener.check("Node changed", 1);
271:
272: Collection addedByTCLookup = res.allInstances();
273: assertEquals("One item still", 1, addedByTCLookup.size());
274:
275: content.add(n2);
276: assertEquals(
277: "After the n2.getLookup starts to return itself, there is no change",
278: addedByTCLookup, res.allInstances());
279:
280: // this could be commented out if necessary:
281: listener.check("And nothing is fired", 0);
282:
283: content.remove(n2);
284: assertEquals(
285: "After the n2.getLookup stops to return itself, there is no change",
286: addedByTCLookup, res.allInstances());
287: // this could be commented out if necessary:
288: listener.check("And nothing is fired", 0);
289:
290: content.add(n1);
291: // this could be commented out if necessary:
292: listener.check("And nothing is fired", 0);
293: // Change from former behavior (#36336): we don't *want* n1 in res.
294: Collection one = res.allInstances();
295: assertEquals("Really just the activated node", 1, one.size());
296: Iterator it = one.iterator();
297: assertEquals("It is the one added by the TC lookup", n2, it
298: .next());
299: }
300:
301: public void testNoChangeWhenSomethingIsChangedOnNotActivatedNode() {
302: doTestNoChangeWhenSomethingIsChangedOnNotActivatedNode(0);
303: }
304:
305: public void testNoChangeWhenSomethingIsChangedOnNotActivatedNode2() {
306: doTestNoChangeWhenSomethingIsChangedOnNotActivatedNode(50);
307: }
308:
309: private void doTestNoChangeWhenSomethingIsChangedOnNotActivatedNode(
310: int initialSize) {
311: Object obj = new OpenCookie() {
312: public void open() {
313: }
314: };
315:
316: Lookup.Result res = lookup.lookup(new Lookup.Template(
317: OpenCookie.class));
318: Lookup.Result nodeRes = lookup.lookup(new Lookup.Template(
319: Node.class));
320:
321: InstanceContent ic = new InstanceContent();
322: CountingLookup cnt = new CountingLookup(ic);
323: AbstractNode ac = new AbstractNode(Children.LEAF, cnt);
324: for (int i = 0; i < initialSize; i++) {
325: ic.add(new Integer(i));
326: }
327:
328: top.setActivatedNodes(new org.openide.nodes.Node[] { ac });
329: assertEquals("One node there", 1,
330: top.getActivatedNodes().length);
331: assertEquals("It is the ac one", ac, top.getActivatedNodes()[0]);
332: ic.add(obj);
333:
334: L listener = new L();
335:
336: res.allItems();
337: nodeRes.allItems();
338: res.addLookupListener(listener);
339:
340: Collection allListeners = cnt.listeners;
341:
342: assertEquals("Has the cookie", 1, res.allItems().size());
343: listener.check("No changes yet", 0);
344:
345: ic.remove(obj);
346:
347: assertEquals("Does not have the cookie", 0, res.allItems()
348: .size());
349: listener.check("One change", 1);
350:
351: top.setActivatedNodes(new N[0]);
352: assertEquals("The nodes are empty", 0,
353: top.getActivatedNodes().length);
354: listener.check("No change", 0);
355:
356: cnt.queries = 0;
357: ic.add(obj);
358: ic.add(ac);
359: listener
360: .check(
361: "Removing the object or node from not active node does not send any event",
362: 0);
363:
364: nodeRes.allItems();
365: listener.check("Queriing for node does generate an event", 0);
366: assertEquals("No Queries to the not active node made", 0,
367: cnt.queries);
368: assertEquals("No listeneners on cookies", allListeners,
369: cnt.listeners);
370: }
371:
372: public void testBug32470FilterNodeAndANodeImplementingACookie() {
373: class NY extends AbstractNode implements SaveCookie {
374: public NY() {
375: super (Children.LEAF);
376: getCookieSet().add(this );
377: }
378:
379: public void save() {
380: }
381: }
382:
383: Node ny = new NY();
384: Node node = new FilterNode(new FilterNode(ny, null, ny
385: .getLookup()));
386: top.setActivatedNodes(new Node[] { node });
387:
388: Lookup.Template nodeTemplate = new Lookup.Template(Node.class);
389: Lookup.Template saveTemplate = new Lookup.Template(
390: SaveCookie.class);
391: java.util.Collection res;
392:
393: res = lookup.lookup(nodeTemplate).allInstances();
394:
395: assertEquals("just one returned", res.size(), 1);
396: assertEquals("node is node", node, res.iterator().next());
397: //MK - the above 2 tests should test the same..
398: // assertEquals ("FilterNode is the only node there",
399: // Collections.singletonList(node), res
400: // );
401:
402: res = lookup.lookup(saveTemplate).allInstances();
403:
404: assertEquals("just one returned", res.size(), 1);
405: assertEquals("node is node", ny, res.iterator().next());
406: //MK - the above 2 tests should test the same..
407: // assertEquals ("SaveCookie is there only once",
408: // Collections.singletonList(ny), res
409: // );
410:
411: res = lookup.lookup(nodeTemplate).allInstances();
412:
413: assertEquals("just one returned", res.size(), 1);
414: assertEquals("node is node", node, res.iterator().next());
415: //MK - the above 2 tests should test the same..
416: // assertEquals ("FilterNode is still the only node there",
417: // Collections.singletonList(node), res
418: // );
419: }
420:
421: public void testActionMapIsTakenFromComponentAndAlsoFromFocusedOne() {
422: JTextField panel = new JTextField();
423:
424: class Def extends DefaultKeyboardFocusManager {
425: private Component c;
426:
427: public Def(Component c) {
428: this .c = c;
429: }
430:
431: public Component getFocusOwner() {
432: return c;
433: }
434: }
435: KeyboardFocusManager prev = KeyboardFocusManager
436: .getCurrentKeyboardFocusManager();
437:
438: try {
439: KeyboardFocusManager
440: .setCurrentKeyboardFocusManager(new Def(panel));
441:
442: top.add(BorderLayout.CENTER, panel);
443:
444: class Act extends AbstractAction {
445: public void actionPerformed(ActionEvent ev) {
446: }
447: }
448: Act act1 = new Act();
449: Act act2 = new Act();
450: Act act3 = new Act();
451:
452: top.getActionMap().put("globalRegistration", act1);
453: top.getActionMap().put("doubleRegistration", act2);
454:
455: panel.getActionMap().put("doubleRegistration", act3);
456: panel.getActionMap().put("focusedRegistration", act3);
457:
458: ActionMap map = (ActionMap) top.getLookup().lookup(
459: ActionMap.class);
460:
461: assertEquals("actions registered directly on TC are found",
462: act1, map.get("globalRegistration"));
463: assertEquals(
464: "even if they are provided by focused component",
465: act2, map.get("doubleRegistration"));
466:
467: assertEquals("Should be focused now", panel,
468: KeyboardFocusManager
469: .getCurrentKeyboardFocusManager()
470: .getFocusOwner());
471: assertEquals(
472: "actions are delegated to focus owner, if not present",
473: act3, map.get("focusedRegistration"));
474:
475: JTextField f = new JTextField();
476: f.getActionMap().put("focusedRegistration", act3);
477: KeyboardFocusManager
478: .setCurrentKeyboardFocusManager(new Def(f));
479: assertEquals("f should be focused now", f,
480: KeyboardFocusManager
481: .getCurrentKeyboardFocusManager()
482: .getFocusOwner());
483: assertEquals(
484: "but as it is not in the right component, nothing is found",
485: null, map.get("focusedRegistration"));
486: } finally {
487: KeyboardFocusManager.setCurrentKeyboardFocusManager(prev);
488: }
489: }
490:
491: public void testChangingNodesDoesNotChangeActionMap() {
492: N node = new N("testChangingNodesDoesNotChangeActionMap");
493: node.state(0x00);
494: top.setActivatedNodes(new Node[] { node });
495:
496: Lookup.Result res = lookup.lookup(new Lookup.Template(
497: ActionMap.class));
498: assertEquals("One item there", 1, res.allInstances().size());
499: ActionMap map = (ActionMap) res.allInstances().toArray()[0];
500:
501: L l = new L();
502: res.addLookupListener(l);
503:
504: node.state(0x01);
505:
506: assertEquals("Map is still the same", map, res.allInstances()
507: .toArray()[0]);
508:
509: l.check("No change in lookup", 0);
510:
511: top.setActivatedNodes(new Node[] { Node.EMPTY });
512: assertEquals("Map remains the same", map, res.allInstances()
513: .toArray()[0]);
514:
515: l.check("There is no change", 0);
516:
517: }
518:
519: public void testMapKeys45323() {
520: assertNotNull(top.getActionMap().keys());
521: }
522:
523: /**
524: * Check that even if a node has a <em>different</em> node in its lookup, a
525: * query on Node.class will produce only the actual activated nodes.
526: * Other queries may return the embedded node, but not duplicates.
527: * @see "#36336"
528: */
529: public void testForeignNodesInLookupIgnoredForNodeQuery()
530: throws Exception {
531: class CloseCookieNode extends AbstractNode implements
532: CloseCookie {
533: CloseCookieNode() {
534: super (Children.LEAF);
535: setName("n1");
536: }
537:
538: public boolean close() {
539: return true;
540: }
541: }
542: Node n1 = new CloseCookieNode();
543: Node n2 = new AbstractNode(Children.LEAF) {
544: {
545: setName("n2");
546: class ViewCookieNode extends AbstractNode implements
547: ViewCookie {
548: ViewCookieNode() {
549: super (Children.LEAF);
550: setName("n3");
551: }
552:
553: public void view() {
554: }
555: }
556: getCookieSet().add(new ViewCookieNode());
557: getCookieSet().add(new OpenCookie() {
558: public void open() {
559: }
560: });
561: }
562: };
563: Node[] sel = new Node[] { n1, n2 };
564: assertEquals("First node in selection has CloseCookie", 1, n1
565: .getLookup().lookup(
566: new Lookup.Template(CloseCookie.class))
567: .allInstances().size());
568: assertEquals("Second node in selection has OpenCookie", 1, n2
569: .getLookup().lookup(
570: new Lookup.Template(OpenCookie.class))
571: .allInstances().size());
572: assertEquals(
573: "Second node in selection has ViewCookie (actually a Node)",
574: 1, n2.getLookup().lookup(
575: new Lookup.Template(ViewCookie.class))
576: .allInstances().size());
577: ViewCookie v = (ViewCookie) n2.getCookie(ViewCookie.class);
578: assertNotNull(v);
579: assertTrue(v instanceof Node);
580:
581: HashSet queryJustOnce = new HashSet(n2.getLookup().lookup(
582: new Lookup.Template(Node.class)).allInstances());
583: assertEquals(
584: "Second node in selection has two nodes in its own lookup",
585: new HashSet(Arrays.asList(new Object[] { n2, v })),
586: queryJustOnce);
587: assertEquals(2, queryJustOnce.size());
588: top.setActivatedNodes(sel);
589: assertEquals(
590: "CloseCookie propagated from one member of node selection to TC lookup",
591: 1, lookup
592: .lookup(new Lookup.Template(CloseCookie.class))
593: .allInstances().size());
594: assertEquals(
595: "OpenCookie propagated from one member of node selection to TC lookup",
596: 1, lookup.lookup(new Lookup.Template(OpenCookie.class))
597: .allInstances().size());
598: assertEquals(
599: "ViewCookie propagated from one member of node selection to TC lookup",
600: 1, lookup.lookup(new Lookup.Template(ViewCookie.class))
601: .allInstances().size());
602: assertEquals(
603: "But TC lookup query on Node gives only selection, not cookie node",
604: new HashSet(Arrays.asList(sel)), new HashSet(lookup
605: .lookup(new Lookup.Template(Node.class))
606: .allInstances()));
607: assertEquals(2, lookup.lookup(new Lookup.Template(Node.class))
608: .allInstances().size());
609: assertEquals(
610: "TC lookup query on FeatureDescriptor gives all three however",
611: 3, lookup.lookup(
612: new Lookup.Template(FeatureDescriptor.class))
613: .allInstances().size());
614: top.setActivatedNodes(new Node[] { n1 });
615: assertEquals(
616: "After setting node selection to one node, TC lookup has only that node",
617: Collections.singleton(n1),
618: new HashSet(lookup.lookup(
619: new Lookup.Template(Node.class)).allInstances()));
620: assertEquals(1, lookup.lookup(new Lookup.Template(Node.class))
621: .allInstances().size());
622: assertEquals("And the OpenCookie is gone", 0, lookup.lookup(
623: new Lookup.Template(OpenCookie.class)).allInstances()
624: .size());
625: assertEquals("And the ViewCookie is gone", 0, lookup.lookup(
626: new Lookup.Template(ViewCookie.class)).allInstances()
627: .size());
628: assertEquals("But the CloseCookie remains", 1, lookup.lookup(
629: new Lookup.Template(CloseCookie.class)).allInstances()
630: .size());
631: }
632:
633: public void testAssociateLookupCanBecalledJustOnce()
634: throws Exception {
635: class TC extends TopComponent {
636: public TC() {
637: }
638:
639: public TC(Lookup l) {
640: super (l);
641: }
642:
643: public void asso(Lookup l) {
644: associateLookup(l);
645: }
646: }
647:
648: TC tc = new TC();
649: assertNotNull("There is default lookup", tc.getLookup());
650: try {
651: tc.asso(Lookup.EMPTY);
652: fail("Should throw an exception");
653: } catch (IllegalStateException ex) {
654: // ok, should be thrown
655: }
656:
657: tc = new TC(Lookup.EMPTY);
658: assertEquals("Should return the provided lookup", Lookup.EMPTY,
659: tc.getLookup());
660:
661: try {
662: tc.asso(Lookup.EMPTY);
663: fail("Should throw an exception - second association not possible");
664: } catch (IllegalStateException ex) {
665: // ok, should be thrown
666: }
667:
668: tc = new TC();
669: tc.asso(Lookup.EMPTY);
670: assertEquals("First association was successful", Lookup.EMPTY,
671: tc.getLookup());
672:
673: try {
674: tc.asso(new TC().getLookup());
675: fail("Should throw an exception - second association not possible");
676: } catch (IllegalStateException ex) {
677: // ok, should be thrown
678: }
679: }
680:
681: /** Listener to count number of changes.
682: */
683: private static final class L extends Object implements
684: LookupListener {
685: private int cnt;
686:
687: /** A change in lookup occured.
688: * @param ev event describing the change
689: */
690: public void resultChanged(LookupEvent ev) {
691: cnt++;
692: }
693:
694: /** Checks at least given number of changes.
695: */
696: public void checkAtLeast(String text, int num) {
697: if (cnt < num) {
698: fail(text + " expected at least " + num + " but was "
699: + cnt);
700: }
701: cnt = 0;
702: }
703:
704: /** Checks number of modifications.
705: */
706: public void check(String text, int num) {
707: assertEquals(text, num, cnt);
708: cnt = 0;
709: }
710: }
711:
712: /** Overides some methods so it is not necessary to use the data object.
713: */
714: protected static final class N extends AbstractNode {
715: private Node.Cookie[] cookies = { new OpenCookie() {
716: public void open() {
717: }
718: }, new EditCookie() {
719: public void edit() {
720: }
721: }, new SaveCookie() {
722: public void save() {
723: }
724: }, new CloseCookie() {
725: public boolean close() {
726: return true;
727: }
728: }, };
729:
730: private int s;
731:
732: public N(String name) {
733: super (Children.LEAF);
734: setName(name);
735: }
736:
737: public void state(int s) {
738: this .s = s;
739: fireCookieChange();
740: }
741:
742: public Node.Cookie getCookie(Class c) {
743: int mask = 0x01;
744:
745: for (int i = 0; i < cookies.length; i++) {
746: if ((s & mask) != 0 && c.isInstance(cookies[i])) {
747: return cookies[i];
748: }
749: mask = mask << 1;
750:
751: }
752: return null;
753: }
754: }
755:
756: private static final class CountingLookup extends Lookup {
757: private Lookup delegate;
758: public List listeners = new ArrayList();
759: public int queries;
760:
761: public CountingLookup(InstanceContent ic) {
762: delegate = new AbstractLookup(ic);
763:
764: }
765:
766: public Object lookup(Class clazz) {
767: return delegate.lookup(clazz);
768: }
769:
770: public Lookup.Result lookup(Lookup.Template template) {
771: if (!Node.Cookie.class.isAssignableFrom(template.getType())
772: && !Node.class.isAssignableFrom(template.getType())) {
773: return delegate.lookup(template);
774: }
775:
776: final Lookup.Result d = delegate.lookup(template);
777:
778: class Wrap extends Lookup.Result {
779: public void addLookupListener(LookupListener l) {
780: listeners.add(l);
781: d.addLookupListener(l);
782: }
783:
784: public void removeLookupListener(LookupListener l) {
785: listeners.remove(l);
786: d.removeLookupListener(l);
787: }
788:
789: public Collection allInstances() {
790: queries++;
791: return d.allInstances();
792: }
793:
794: public Collection allItems() {
795: queries++;
796: return d.allItems();
797: }
798:
799: public Set allClasses() {
800: queries++;
801: return d.allClasses();
802: }
803: }
804:
805: return new Wrap();
806: }
807:
808: }
809: }
|