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;
043:
044: import java.awt.datatransfer.ClipboardOwner;
045: import java.awt.datatransfer.Transferable;
046: import java.util.Arrays;
047:
048: import junit.framework.Test;
049: import junit.framework.TestSuite;
050: import org.netbeans.junit.NbTestCase;
051: import org.netbeans.junit.NbTestSuite;
052:
053: import javax.swing.Action;
054: import org.openide.DialogDisplayer;
055: import org.openide.NotifyDescriptor;
056:
057: import org.openide.actions.CopyAction;
058: import org.openide.actions.CutAction;
059: import org.openide.filesystems.FileObject;
060: import org.openide.filesystems.Repository;
061: import org.openide.nodes.Children;
062: import org.openide.nodes.Node;
063: import org.openide.nodes.AbstractNode;
064: import org.openide.util.actions.SystemAction;
065: import org.openide.util.ContextAwareAction;
066: import org.openide.util.Lookup;
067: import org.openide.util.datatransfer.PasteType;
068: import org.openide.util.io.NbMarshalledObject;
069:
070: /**
071: * Tests for <code>ExplorerPanel</code>.
072: *
073: * @author Peter Zavadsky
074: */
075: public class ExplorerPanelTest extends NbTestCase {
076: /** context the action should work in */
077: private Lookup context;
078: /** explorer manager to work on */
079: private ExplorerManager manager;
080:
081: /** need it for stopActions here */
082: private ExplorerPanel ep;
083:
084: public ExplorerPanelTest(java.lang.String testName) {
085: super (testName);
086: }
087:
088: public static void main(java.lang.String[] args) {
089: junit.textui.TestRunner.run(suite());
090: }
091:
092: public static Test suite() {
093: TestSuite suite = new NbTestSuite(ExplorerPanelTest.class);
094: return suite;
095: }
096:
097: protected boolean runInEQ() {
098: return true;
099: }
100:
101: /** Setups the tests.
102: */
103: protected final void setUp() {
104: // XXX consider replacing with MockServices
105: System.setProperty("org.openide.util.Lookup",
106: "org.openide.explorer.ExplorerPanelTest$Lkp");
107:
108: Object[] arr = createManagerAndContext(false);
109: manager = (ExplorerManager) arr[0];
110: context = (Lookup) arr[1];
111:
112: }
113:
114: /** Creates a manager to operate on.
115: */
116: protected Object[] createManagerAndContext(boolean confirm) {
117: ep = new ExplorerPanel(null, confirm);
118: return new Object[] { ep.getExplorerManager(), ep.getLookup() };
119: }
120:
121: /** Instructs the actions to stop/
122: */
123: protected void stopActions(ExplorerManager em) {
124: ep.componentDeactivated();
125: }
126:
127: /** Instructs the actions to start again.
128: */
129: protected void startActions(ExplorerManager em) {
130: ep.componentActivated();
131: }
132:
133: /** Tests whether the cut, copy (callback) actions are enabled/disabled
134: * in the right time, see # */
135: public void testCutCopyActionsEnabling() throws Exception {
136: assertTrue("Can run only in AWT thread", java.awt.EventQueue
137: .isDispatchThread());
138:
139: TestNode enabledNode = new TestNode(true, true, true);
140: TestNode disabledNode = new TestNode(false, false, false);
141:
142: manager.setRootContext(new TestRoot(new Node[] { enabledNode,
143: disabledNode }));
144:
145: Action copy = ((ContextAwareAction) SystemAction
146: .get(CopyAction.class))
147: .createContextAwareInstance(context);
148: Action cut = ((ContextAwareAction) SystemAction
149: .get(CutAction.class))
150: .createContextAwareInstance(context);
151:
152: assertTrue("Copy action has to be disabled", !copy.isEnabled());
153: assertTrue("Cut action has to be disabled", !cut.isEnabled());
154:
155: manager.setSelectedNodes(new Node[] { enabledNode });
156:
157: assertTrue("Copy action has to be enabled", copy.isEnabled());
158: assertTrue("Cut action has to be enabled", cut.isEnabled());
159:
160: copy.actionPerformed(new java.awt.event.ActionEvent(this , 0,
161: "waitFinished"));
162: assertEquals("clipboardCopy invoked", 1, enabledNode.countCopy);
163:
164: cut.actionPerformed(new java.awt.event.ActionEvent(this , 0,
165: "waitFinished"));
166: assertEquals("clipboardCut invoked", 1, enabledNode.countCut);
167:
168: manager.setSelectedNodes(new Node[] { disabledNode });
169:
170: assertTrue("Copy action has to be disabled", !copy.isEnabled());
171: assertTrue("Cut action has to be disabled", !cut.isEnabled());
172: }
173:
174: public void testDeleteAction() throws Exception {
175: TestNode enabledNode = new TestNode(true, true, true);
176: TestNode enabledNode2 = new TestNode(true, true, true);
177: TestNode disabledNode = new TestNode(false, false, false);
178:
179: manager.setRootContext(new TestRoot(new Node[] { enabledNode,
180: enabledNode2, disabledNode }));
181:
182: Action delete = ((ContextAwareAction) SystemAction
183: .get(org.openide.actions.DeleteAction.class))
184: .createContextAwareInstance(context);
185:
186: assertTrue("By default delete is disabled", !delete.isEnabled());
187:
188: manager.setSelectedNodes(new Node[] { enabledNode });
189: assertTrue("Now it gets enabled", delete.isEnabled());
190:
191: manager.setSelectedNodes(new Node[] { disabledNode });
192: assertTrue("Is disabled", !delete.isEnabled());
193:
194: manager
195: .setSelectedNodes(new Node[] { manager.getRootContext() });
196: assertTrue("Delete is enabled on root", delete.isEnabled());
197:
198: manager.setSelectedNodes(new Node[] { manager.getRootContext(),
199: enabledNode });
200: assertTrue(
201: "But is disabled on now, as one selected node is child of another",
202: !delete.isEnabled());
203:
204: manager
205: .setSelectedNodes(new Node[] { enabledNode,
206: enabledNode2 });
207: assertTrue("It gets enabled", delete.isEnabled());
208:
209: delete.actionPerformed(new java.awt.event.ActionEvent(this , 0,
210: "waitFinished"));
211:
212: assertEquals("Destoy was called", 1, enabledNode.countDelete);
213: assertEquals("Destoy was called", 1, enabledNode2.countDelete);
214:
215: }
216:
217: public void testDeleteConfirmAction() throws Exception {
218: TestNode[] nodes = new TestNode[] {
219: new TestNode(true, true, true),
220: new TestNode(true, true, true, true),
221: new TestNode(true, true, true),
222: new TestNode(true, true, true, true),
223: new TestNode(false, false, false) };
224:
225: YesDialogDisplayer ydd = (YesDialogDisplayer) Lookup
226: .getDefault().lookup(YesDialogDisplayer.class);
227: DialogDisplayer dd = (DialogDisplayer) Lookup.getDefault()
228: .lookup(DialogDisplayer.class);
229: assertNotNull("Custom DialogDisplayer is not set", ydd);
230: int notifyCount = ydd.getNotifyCount();
231: assertEquals("YesDialogDisplayer is current DialogDisplayer",
232: ydd, dd);
233:
234: Object[] arr = createManagerAndContext(true);
235:
236: ExplorerPanel delep = new ExplorerPanel(
237: (ExplorerManager) arr[0], true);
238: ExplorerManager delManager = delep.getExplorerManager();
239: delManager.setRootContext(new TestRoot(nodes));
240:
241: Action delete = ((ContextAwareAction) SystemAction
242: .get(org.openide.actions.DeleteAction.class))
243: .createContextAwareInstance((Lookup) arr[1]);
244:
245: // delete should ask for confirmation
246: delManager.setSelectedNodes(new Node[] { nodes[0] });
247: assertTrue("It gets enabled", delete.isEnabled());
248:
249: delete.actionPerformed(new java.awt.event.ActionEvent(this , 0,
250: "waitFinished"));
251:
252: assertEquals("Destoy was called", 1, nodes[0].countDelete);
253:
254: assertEquals("Confirm delete was called ", notifyCount + 1, ydd
255: .getNotifyCount());
256:
257: // but delete should not ask for confirmation if the node wants to perform handle delete
258: delManager.setSelectedNodes(new Node[] { nodes[1] });
259: assertTrue("It gets enabled", delete.isEnabled());
260:
261: delete.actionPerformed(new java.awt.event.ActionEvent(this , 0,
262: "waitFinished"));
263:
264: assertEquals("Destoy was called", 1, nodes[1].countDelete);
265:
266: assertEquals("Confirm delete was called ", notifyCount + 1, ydd
267: .getNotifyCount()); // no next dialog
268:
269: // anyway ask for confirmation if at least one node has default behaviour
270: delManager.setSelectedNodes(new Node[] { nodes[2], nodes[3] });
271: assertTrue("It gets enabled", delete.isEnabled());
272:
273: delete.actionPerformed(new java.awt.event.ActionEvent(this , 0,
274: "waitFinished"));
275:
276: assertEquals("Destoy was called", 1, nodes[2].countDelete);
277: assertEquals("Destoy was called", 1, nodes[3].countDelete);
278:
279: assertEquals("Confirm delete was called ", notifyCount + 2, ydd
280: .getNotifyCount()); // no next dialog
281:
282: }
283:
284: public void testPasteAction() throws Exception {
285: TestNode enabledNode = new TestNode(true, true, true);
286: TestNode disabledNode = new TestNode(false, false, false);
287:
288: manager.setRootContext(new TestRoot(new Node[] { enabledNode,
289: disabledNode }));
290:
291: Action paste = ((ContextAwareAction) SystemAction
292: .get(org.openide.actions.PasteAction.class))
293: .createContextAwareInstance(context);
294: assertTrue("Disabled by default", !paste.isEnabled());
295:
296: class PT extends PasteType {
297: public int count;
298:
299: public java.awt.datatransfer.Transferable paste() {
300: count++;
301: return null;
302: }
303: }
304: PT[] arr = { new PT() };
305:
306: enabledNode.types = arr;
307:
308: manager.setSelectedNodes(new Node[] { enabledNode });
309:
310: assertTrue("Paste is enabled", paste.isEnabled());
311:
312: paste.actionPerformed(new java.awt.event.ActionEvent(this , 0,
313: "waitFinished"));
314: assertEquals("Paste invoked", 1, arr[0].count);
315:
316: manager.setSelectedNodes(new Node[] { disabledNode });
317: assertTrue("Disabled paste", !paste.isEnabled());
318:
319: arr = new PT[] { new PT(), new PT() };
320: enabledNode.types = arr;
321:
322: manager.setSelectedNodes(new Node[] { enabledNode });
323: assertTrue("Paste enabled again", paste.isEnabled());
324:
325: org.openide.util.datatransfer.ExClipboard ec = (org.openide.util.datatransfer.ExClipboard) Lookup
326: .getDefault()
327: .lookup(org.openide.util.datatransfer.ExClipboard.class);
328: assertNotNull("Without ExClipboard this will not work much", ec);
329:
330: java.awt.datatransfer.StringSelection ss = new java.awt.datatransfer.StringSelection(
331: "Hi");
332: ec.setContents(ss, ss);
333:
334: assertTranferables(ss, enabledNode.lastTransferable);
335:
336: stopActions(manager);
337:
338: manager.setSelectedNodes(new Node[] { disabledNode });
339: assertTrue("Paste still enabled as we are not listening", paste
340: .isEnabled());
341:
342: java.awt.datatransfer.StringSelection ns = new java.awt.datatransfer.StringSelection(
343: "New Selection");
344: ec.setContents(ns, ns);
345:
346: assertTranferables(ss, enabledNode.lastTransferable);
347:
348: startActions(manager);
349:
350: assertFalse(
351: "The selected node is the disabled one, so now we are disabled",
352: paste.isEnabled());
353: assertTranferables(ns, disabledNode.lastTransferable);
354:
355: ns = new java.awt.datatransfer.StringSelection(
356: "Another Selection");
357: ec.setContents(ns, ns);
358: assertTranferables(ns, disabledNode.lastTransferable);
359: }
360:
361: public void skipForNowtestSelectedNodesInDeserializedPanel()
362: throws Exception {
363: ExplorerPanel panel = new ExplorerPanel();
364:
365: FileObject fo = Repository.getDefault().getDefaultFileSystem()
366: .getRoot();
367:
368: Node root = new SerializableNode();
369: panel.getExplorerManager().setRootContext(root);
370: panel.getExplorerManager()
371: .setSelectedNodes(new Node[] { root });
372:
373: assertNotNull("Array of selected nodes is not null.", panel
374: .getExplorerManager().getSelectedNodes());
375: assertFalse("Array of selected nodes is not empty.", panel
376: .getExplorerManager().getSelectedNodes().length == 0);
377: assertEquals("The selected node is Filesystems root.", panel
378: .getExplorerManager().getSelectedNodes()[0], root);
379:
380: NbMarshalledObject mar = new NbMarshalledObject(panel);
381: Object obj = mar.get();
382: ExplorerPanel deserializedPanel = (ExplorerPanel) obj;
383:
384: assertNotNull("Deserialized panel is not null.",
385: deserializedPanel);
386:
387: assertNotNull(
388: "[Deserialized panel] Array of selected nodes is not null.",
389: deserializedPanel.getExplorerManager()
390: .getSelectedNodes());
391: assertFalse(
392: "[Deserialized panel] Array of selected nodes is not empty.",
393: deserializedPanel.getExplorerManager()
394: .getSelectedNodes().length == 0);
395: assertEquals(
396: "[Deserialized panel] The selected node is Filesystems root.",
397: deserializedPanel.getExplorerManager()
398: .getSelectedNodes()[0], root);
399:
400: }
401:
402: /** Compares whether two transferables are the same.
403: */
404: private static void assertTranferables(
405: java.awt.datatransfer.Transferable t1,
406: java.awt.datatransfer.Transferable t2) throws Exception {
407: // if (t1 == t2) return;
408:
409: java.awt.datatransfer.DataFlavor[] arr1 = t1
410: .getTransferDataFlavors();
411: java.awt.datatransfer.DataFlavor[] arr2 = t2
412: .getTransferDataFlavors();
413:
414: assertEquals("Flavors are the same", Arrays.asList(arr1),
415: Arrays.asList(arr2));
416:
417: for (int i = 0; i < arr1.length; i++) {
418: Object f1 = convert(t1.getTransferData(arr1[i]));
419: Object f2 = convert(t2.getTransferData(arr1[i]));
420:
421: assertEquals(i + " flavor " + arr1[i], f1, f2);
422: }
423: }
424:
425: private static Object convert(Object obj) throws Exception {
426: if (obj instanceof java.io.StringReader) {
427: java.io.StringReader sr = (java.io.StringReader) obj;
428: StringBuffer sb = new StringBuffer();
429: for (;;) {
430: int ch = sr.read();
431: if (ch == -1)
432: return sb.toString();
433: sb.append((char) ch);
434: }
435: }
436:
437: return obj;
438: }
439:
440: /** Test root node. */
441: private static class TestRoot extends AbstractNode {
442: public TestRoot(Node[] children) {
443: super (new Children.Array());
444: getChildren().add(children);
445: }
446:
447: public boolean canDestroy() {
448: return true;
449: }
450: }
451:
452: /** Node which enables both cut and copy actions. */
453: private static class TestNode extends AbstractNode {
454: public boolean canCopy;
455: public boolean canCut;
456: public boolean canDelete;
457: private boolean customDelete;
458: public PasteType[] types = new PasteType[0];
459: public java.awt.datatransfer.Transferable lastTransferable;
460:
461: public int countCopy;
462: public int countCut;
463: public int countDelete;
464:
465: public TestNode(boolean canCopy, boolean canCut,
466: boolean canDelete, boolean customDelete) {
467: this (canCopy, canCut, canDelete);
468: this .customDelete = customDelete;
469: }
470:
471: public TestNode(boolean b, boolean c, boolean d) {
472: super (Children.LEAF);
473: canCopy = b;
474: canCut = c;
475: canDelete = d;
476: }
477:
478: public void destroy() {
479: countDelete++;
480: }
481:
482: public boolean canDestroy() {
483: return canDelete;
484: }
485:
486: public boolean canCopy() {
487: return canCopy;
488: }
489:
490: public boolean canCut() {
491: return canCut;
492: }
493:
494: public java.awt.datatransfer.Transferable clipboardCopy()
495: throws java.io.IOException {
496: java.awt.datatransfer.Transferable retValue;
497:
498: retValue = super .clipboardCopy();
499:
500: countCopy++;
501:
502: return retValue;
503: }
504:
505: public java.awt.datatransfer.Transferable clipboardCut()
506: throws java.io.IOException {
507: java.awt.datatransfer.Transferable retValue;
508:
509: retValue = super .clipboardCut();
510:
511: countCut++;
512:
513: return retValue;
514: }
515:
516: protected void createPasteTypes(
517: java.awt.datatransfer.Transferable t, java.util.List s) {
518: this .lastTransferable = t;
519: s.addAll(Arrays.asList(types));
520: }
521:
522: public Object getValue(String attributeName) {
523: if (customDelete && "customDelete".equals(attributeName)) {
524: return Boolean.TRUE;
525: }
526: return super .getValue(attributeName);
527: }
528:
529: }
530:
531: public static final class SerializableNode extends AbstractNode
532: implements Node.Handle, java.io.Externalizable {
533:
534: static final long serialVersionUID = 439503248509342L;
535:
536: public SerializableNode() {
537: super (Children.LEAF);
538: }
539:
540: public Handle getHandle() {
541: return this ;
542: }
543:
544: public Node getNode() {
545: return this ;
546: }
547:
548: public void writeExternal(java.io.ObjectOutput oo) {
549: }
550:
551: public void readExternal(java.io.ObjectInput oi) {
552: }
553:
554: //
555: // All instances of SerializableNode are equal
556: //
557:
558: public int hashCode() {
559: return getClass().hashCode();
560: }
561:
562: public boolean equals(java.lang.Object obj) {
563: return obj != null && getClass().equals(obj.getClass());
564: }
565: } // end SerializableNode
566:
567: public static final class Lkp extends
568: org.openide.util.lookup.AbstractLookup {
569: public Lkp() {
570: this (new org.openide.util.lookup.InstanceContent());
571: }
572:
573: private Lkp(org.openide.util.lookup.InstanceContent ic) {
574: super (ic);
575: ic.add(new Clb("Testing clipboard"));
576: ic.add(new YesDialogDisplayer());
577: }
578: }
579:
580: private static final class Clb extends
581: org.openide.util.datatransfer.ExClipboard {
582: public Clb(String s) {
583: super (s);
584: }
585:
586: protected org.openide.util.datatransfer.ExClipboard.Convertor[] getConvertors() {
587: return new org.openide.util.datatransfer.ExClipboard.Convertor[0];
588: }
589:
590: public void setContents(Transferable t, ClipboardOwner o) {
591: super .setContents(t, o);
592: fireClipboardChange();
593: }
594: }
595:
596: private static final class YesDialogDisplayer extends
597: DialogDisplayer {
598: private int counter = 0;
599:
600: public YesDialogDisplayer() {
601: super ();
602: }
603:
604: public Object notify(org.openide.NotifyDescriptor descriptor) {
605: counter++;
606: return NotifyDescriptor.YES_OPTION;
607: }
608:
609: public java.awt.Dialog createDialog(
610: org.openide.DialogDescriptor descriptor) {
611: return null;
612: }
613:
614: public int getNotifyCount() {
615: return counter;
616: }
617: }
618: }
|