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.explorer.view;
043:
044: import java.lang.ref.WeakReference;
045: import java.util.ArrayList;
046: import java.util.List;
047: import java.util.logging.Level;
048: import java.util.logging.Logger;
049: import javax.swing.JPanel;
050: import javax.swing.event.TreeModelEvent;
051: import javax.swing.event.TreeModelListener;
052: import javax.swing.tree.TreeNode;
053: import org.netbeans.junit.NbTestCase;
054: import org.openide.explorer.ExplorerManager;
055: import org.openide.nodes.AbstractNode;
056: import org.openide.nodes.Children;
057: import org.openide.nodes.Node;
058:
059: /**
060: * Tests for class ContextTreeViewTest
061: */
062: public class ContextTreeViewModelTest extends NbTestCase {
063:
064: private static final int NO_OF_NODES = 3;
065:
066: private Logger LOG = Logger.getLogger("TEST-" + getName());
067:
068: public ContextTreeViewModelTest(String name) {
069: super (name);
070: }
071:
072: protected boolean runInEQ() {
073: return true;
074: }
075:
076: protected Level logLevel() {
077: return Level.ALL;
078: }
079:
080: public void testCheckThatTheModelFiresChangesAboutOnlyVisibleNodes()
081: throws Throwable {
082: final AbstractNode root = new AbstractNode(new Children.Array());
083: root.setName("test root");
084:
085: LOG.info("node created");
086:
087: root.getChildren().add(
088: new Node[] { createNode("kuk", true),
089: createNode("huk", true), });
090:
091: LOG.info("two subnodes added");
092:
093: NodeTreeModel m = new ContextTreeView.NodeContextModel();
094:
095: LOG.info("model created");
096:
097: m.setNode(root);
098:
099: LOG.info("its root node set");
100:
101: TreeNode visual = (TreeNode) m.getRoot();
102:
103: LOG.info("getting the root: " + visual);
104:
105: waitEQ();
106:
107: assertEquals("Leaf nodes are not counted", 0, m
108: .getChildCount(visual));
109:
110: Listener listener = new Listener(visual);
111: m.addTreeModelListener(listener);
112:
113: LOG.info("listener added");
114:
115: Node n = createNode("blik", true);
116:
117: LOG.info("node created");
118:
119: root.getChildren().add(new Node[] { n });
120:
121: LOG.info("node added");
122:
123: assertEquals("Leaf nodes are not counted even when added", 0, m
124: .getChildCount(visual));
125: assertEquals("Really added", n.getParentNode(), root);
126: listener.assertEvents("No events", 0);
127:
128: LOG.info("events ok");
129:
130: root.getChildren().remove(new Node[] { n });
131: listener.assertEvents("Still no events", 0);
132: assertNull("Removed", n.getParentNode());
133:
134: LOG.info("node removed");
135:
136: Node nonLeaf = createNode("nonleaf", false);
137: root.getChildren().add(new Node[] { nonLeaf });
138:
139: LOG.info("non-leaf added");
140:
141: assertEquals("One child is there", 1, m.getChildCount(visual));
142: listener.assertEvents("This node is visible there", 1);
143: listener.assertIndexes("Added at position zero",
144: new int[] { 0 });
145: assertEquals("Really added", nonLeaf.getParentNode(), root);
146:
147: LOG.info("all checked");
148:
149: assertAgressiveGC();
150:
151: root.getChildren().remove(new Node[] { nonLeaf });
152:
153: LOG.info("non-leaf removed");
154:
155: assertEquals("One child is away", 0, m.getChildCount(visual));
156: assertNull("Removed", nonLeaf.getParentNode());
157: listener.assertEvents("And it has been removed", 1);
158: listener.assertIndexes("Removed from position zero",
159: new int[] { 0 });
160:
161: LOG.info("all ok");
162: }
163:
164: public void testABitMoreComplexAddAndRemoveEventCheck()
165: throws Throwable {
166: final AbstractNode root = new AbstractNode(new Children.Array());
167: root.setName("test root");
168:
169: LOG.info("root created");
170:
171: root.getChildren().add(
172: new Node[] { createNode("kuk", false),
173: createNode("huk", false), });
174:
175: LOG.info("two nodes added");
176:
177: NodeTreeModel m = new ContextTreeView.NodeContextModel();
178: m.setNode(root);
179:
180: LOG.info("root set");
181:
182: TreeNode visual = (TreeNode) m.getRoot();
183: waitEQ();
184:
185: LOG.info("visual is here: " + visual);
186:
187: assertEquals("Initial size is two", 2, m.getChildCount(visual));
188:
189: Listener listener = new Listener(visual);
190: m.addTreeModelListener(listener);
191:
192: LOG.info("listener added");
193:
194: Node[] arr = { createNode("add1", false),
195: createNode("add2", false) };
196:
197: assertAgressiveGC();
198:
199: LOG.info("adding children");
200: root.getChildren().add(arr);
201:
202: LOG.info("children added");
203:
204: listener.assertEvents("One addition", 1);
205: listener.assertIndexes("after the two first",
206: new int[] { 2, 3 });
207:
208: LOG.info("removing children");
209: root.getChildren().remove(arr);
210: LOG.info("children removed");
211:
212: listener.assertEvents("One removal", 1);
213: listener.assertIndexes("from end", new int[] { 2, 3 });
214:
215: LOG.info("all well");
216: }
217:
218: public void testRemoveInMiddle() throws Throwable {
219: final AbstractNode root = new AbstractNode(new Children.Array());
220: root.setName("test root");
221:
222: LOG.info("root added");
223:
224: root.getChildren()
225: .add(new Node[] { createNode("Ahoj", false) });
226:
227: LOG.info("a node added");
228:
229: Node[] first = { createNode("kuk", false),
230: createNode("huk", false), };
231:
232: LOG.info("adding more nodes");
233:
234: root.getChildren().add(first);
235:
236: LOG.info("nodes added");
237:
238: NodeTreeModel m = new ContextTreeView.NodeContextModel();
239: m.setNode(root);
240:
241: LOG.info("root set");
242: TreeNode visual = (TreeNode) m.getRoot();
243:
244: LOG.info("visual is here: " + visual);
245:
246: waitEQ();
247:
248: assertEquals("Initial size is two", 3, m.getChildCount(visual));
249:
250: Listener listener = new Listener(visual);
251: m.addTreeModelListener(listener);
252:
253: LOG.info("listener added");
254:
255: Node[] arr = { createNode("add1", false),
256: createNode("add2", false) };
257:
258: assertAgressiveGC();
259:
260: root.getChildren().add(arr);
261:
262: LOG.info("arr added");
263:
264: listener.assertEvents("One addition", 1);
265: listener.assertIndexes("after the three first", new int[] { 3,
266: 4 });
267:
268: LOG.info("arr ok");
269:
270: root.getChildren().remove(first);
271:
272: LOG.info("arr removed");
273:
274: listener.assertEvents("One removal", 1);
275: listener.assertIndexes("from end", new int[] { 1, 2 });
276:
277: LOG.info("all ok");
278: }
279:
280: private static Node createNode(String name, boolean leaf) {
281: AbstractNode n = new AbstractNode(leaf ? Children.LEAF
282: : new Children.Array());
283: n.setName(name);
284: return n;
285: }
286:
287: private static void assertAgressiveGC() {
288: for (int i = 0; i < 10; i++) {
289: System.gc();
290: }
291: }
292:
293: private void waitEQ() throws Throwable {
294: /*
295: try {
296: javax.swing.SwingUtilities.invokeAndWait (new Runnable () { public void run () { } } );
297: } catch (java.lang.reflect.InvocationTargetException ex) {
298: throw ex.getTargetException ();
299: }
300: */
301: }
302:
303: private static class Panel extends JPanel implements
304: ExplorerManager.Provider {
305: private ExplorerManager em = new ExplorerManager();
306:
307: public ExplorerManager getExplorerManager() {
308: return em;
309: }
310: }
311:
312: private class Listener implements TreeModelListener {
313: private int cnt;
314: private int[] indexes;
315:
316: private TreeNode keep;
317: private List all = new ArrayList();
318:
319: public Listener(TreeNode keep) {
320: this .keep = keep;
321: addChildren();
322: }
323:
324: public void assertEvents(String msg, int cnt) throws Throwable {
325: waitEQ();
326: assertEquals(msg, cnt, this .cnt);
327: this .cnt = 0;
328: }
329:
330: public void assertIndexes(String msg, int[] arr)
331: throws Throwable {
332: waitEQ();
333: assertNotNull(msg + " there has to be some", indexes);
334: boolean bad = false;
335: if (arr.length != indexes.length) {
336: bad = true;
337: } else {
338: for (int i = 0; i < arr.length; i++) {
339: if (arr[i] != indexes[i]) {
340: bad = true;
341: }
342: }
343: }
344: if (bad) {
345: fail(msg + " expected: " + toStr(arr) + " was: "
346: + toStr(indexes));
347: }
348:
349: this .indexes = null;
350: }
351:
352: private String toStr(int[] arr) {
353: StringBuffer sb = new StringBuffer();
354: String sep = "[";
355: for (int i = 0; i < arr.length; i++) {
356: sb.append(sep);
357: sb.append(arr[i]);
358: sep = ", ";
359: }
360: sb.append(']');
361: return sb.toString();
362: }
363:
364: public void treeNodesChanged(TreeModelEvent treeModelEvent) {
365: cnt++;
366: }
367:
368: public void treeNodesInserted(TreeModelEvent treeModelEvent) {
369: cnt++;
370: indexes = treeModelEvent.getChildIndices();
371: }
372:
373: public void treeNodesRemoved(TreeModelEvent treeModelEvent) {
374: cnt++;
375: indexes = treeModelEvent.getChildIndices();
376: }
377:
378: public void treeStructureChanged(TreeModelEvent treeModelEvent) {
379: cnt++;
380: }
381:
382: private void addChildren() {
383: int cnt = keep.getChildCount();
384: for (int i = 0; i < cnt; i++) {
385: all.add(keep.getChildAt(i));
386: }
387: }
388: }
389: }
|