Index: openide/loaders/src/org/openide/loaders/DataLdrActions.java =================================================================== RCS file: openide/loaders/src/org/openide/loaders/DataLdrActions.java diff -N openide/loaders/src/org/openide/loaders/DataLdrActions.java --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openide/loaders/src/org/openide/loaders/DataLdrActions.java 1 Aug 2004 19:21:56 -0000 @@ -0,0 +1,181 @@ +/* + * Sun Public License Notice + * + * The contents of this file are subject to the Sun Public License + * Version 1.0 (the "License"). You may not use this file except in + * compliance with the License. A copy of the License is available at + * http://www.sun.com/ + * + * The Original Code is NetBeans. The Initial Developer of the Original + * Code is Sun Microsystems, Inc. Portions Copyright 1997-2000 Sun + * Microsystems, Inc. All Rights Reserved. + */ + +package org.openide.loaders; + +import java.beans.*; +import java.io.*; +import java.util.*; + +import org.openide.ErrorManager; +import org.openide.cookies.InstanceCookie; +import org.openide.filesystems.*; +import org.openide.nodes.NodeOp; +import org.openide.util.Lookup; +import org.openide.util.NbBundle; +import org.openide.util.SharedClassObject; +import org.openide.util.Utilities; +import org.openide.util.actions.SystemAction; +import org.openide.util.io.SafeException; + +/** Manages actions read and write for a given loader. + * + * @author Jaroslav Tulach + */ +final class DataLdrActions extends FolderInstance { + /** Reference to know for what loader we work */ + private java.lang.ref.Reference ref; + /** last creating task */ + private org.openide.util.Task creation; + /** processor to use */ + private static org.openide.util.RequestProcessor RP = new org.openide.util.RequestProcessor ("Loader Actions"); + + public DataLdrActions (DataFolder f, DataLoader l) { + super (f); + + this.ref = new java.lang.ref.WeakReference (l); + } + + /** Asks the manager to store these actions to disk. Provided for + * backward compatibility. + */ + public synchronized void setActions (final SystemAction[] arr) { + class DoTheWork implements Runnable, FileSystem.AtomicAction { + private int state; + + /** The goal of this method is to make sure that all actions + * will really be stored on the disk. + */ + private void work () throws IOException { + DataObject[] now = folder.getChildren (); + HashMap nowToObj = new HashMap (); + LinkedList sepObjs = new LinkedList (); + for (int i = 0; i < now.length; i++) { + InstanceCookie ic = (InstanceCookie)now[i].getCookie (InstanceCookie.class); + if (ic != null) { + try { + Object instance = ic.instanceCreate (); + if (instance instanceof javax.swing.Action) { + nowToObj.put (instance, now[i]); + continue; + } + if (instance instanceof javax.swing.JSeparator) { + sepObjs.add (now[i]); + continue; + } + } catch (ClassNotFoundException ex) { + ErrorManager.getDefault ().notify (ex); + } + } + } + + ArrayList order = new ArrayList (); + + for (int i = 0; i < arr.length; i++) { + DataObject obj = (DataObject)nowToObj.remove (arr[i]); + if (obj == null) { + if (arr[i] != null) { + obj = InstanceDataObject.create (folder, null, arr[i].getClass ()); + } else { + if (!sepObjs.isEmpty ()) { + obj = (DataObject)sepObjs.removeFirst (); + } else { + obj = InstanceDataObject.create (folder, "Separator" + order.size (), javax.swing.JSeparator.class); + } + } + } + order.add (obj); + } + + // these were there but are not there anymore + for (Iterator it = nowToObj.values ().iterator (); it.hasNext (); ) { + DataObject obj = (DataObject)it.next (); + obj.delete (); + } + for (Iterator it = sepObjs.iterator (); it.hasNext (); ) { + DataObject obj = (DataObject)it.next (); + obj.delete (); + } + + folder.setOrder ((DataObject[])order.toArray (new DataObject[0])); + } + + public void run () { + try { + switch (state) { + case 0: + state = 1; + folder.getPrimaryFile ().getFileSystem ().runAtomicAction (this); + break; + case 1: + work (); + break; + } + } catch (IOException ex) { + ErrorManager.getDefault ().notify (ex); + } + } + } + + DoTheWork dtw = new DoTheWork (); + creation = RP.post (dtw); + } + + + /** Creates the actions and notifies the loader. + */ + protected Object createInstance (org.openide.cookies.InstanceCookie[] cookies) throws java.io.IOException, ClassNotFoundException { + ArrayList list = new ArrayList (); + for (int i = 0; i < cookies.length; i++) { + Object action = cookies[i].instanceCreate (); + if (action instanceof javax.swing.Action) { + list.add (action); + continue; + } + if (action instanceof javax.swing.JSeparator) { + list.add (null); + } + } + + DataLoader l = (DataLoader)ref.get (); + if (l != null) { + l.setSwingActions (list); + } + + return list.toArray (new javax.swing.Action[0]); + } + + /** Currently not recursive */ + protected org.openide.cookies.InstanceCookie acceptFolder (DataFolder df) { + return null; + } + + /** Creation in our own thread, so we can exclude storage modifications */ + protected org.openide.util.Task postCreationTask (Runnable run) { + return RP.post (run); + } + + public void waitFinished () { + org.openide.util.Task t; + synchronized (this) { + t = creation; + } + + if (t != null) { + t.waitFinished (); + } + + super.waitFinished (); + } + +} Index: openide/loaders/src/org/openide/loaders/DataLoader.java =================================================================== RCS file: /cvs/openide/loaders/src/org/openide/loaders/DataLoader.java,v retrieving revision 1.4 diff -u -r1.4 DataLoader.java --- openide/loaders/src/org/openide/loaders/DataLoader.java 7 Jan 2004 13:19:49 -0000 1.4 +++ openide/loaders/src/org/openide/loaders/DataLoader.java 1 Aug 2004 19:22:01 -0000 @@ -49,6 +49,8 @@ public static final String PROP_ACTIONS = "actions"; // NOI18N /** property name of list of default actions */ private static final String PROP_DEF_ACTIONS = "defaultActions"; // NOI18N + /** key to hold reference to out action manager */ + private static final Object ACTION_MANAGER = new Object (); /** representation class, not public property */ private static final Object PROP_REPRESENTATION_CLASS = new Object (); /** representation class name, not public property */ @@ -133,17 +135,65 @@ * actions */ public final SystemAction[] getActions () { - SystemAction[] actions = (SystemAction[])getProperty (PROP_ACTIONS); - if ( actions == null ) { - actions = (SystemAction[])getProperty (PROP_DEF_ACTIONS); + javax.swing.Action[] arr = getSwingActions (); + + ArrayList list = new ArrayList (); + for (int i = 0; i < arr.length; i++) { + if (arr[i] instanceof SystemAction || arr[i] == null) { + list.add (arr[i]); + } + } + + return (SystemAction[])list.toArray (new SystemAction[0]); + } + + /** Swing actions getter, used from DataNode */ + final javax.swing.Action[] getSwingActions () { + DataLdrActions mgr = findManager (); + if (mgr != null) { + Object actions; + try { + actions = mgr.instanceCreate (); + } catch (IOException ex) { + ErrorManager.getDefault ().notify (ex); + actions = null; + } catch (ClassNotFoundException ex) { + ErrorManager.getDefault ().notify (ex); + actions = null; + } + + return (javax.swing.Action[])actions; + } else { + // old behaviour, that stores actions in properties + SystemAction[] actions = (SystemAction[])getProperty (PROP_ACTIONS); if ( actions == null ) { - actions = defaultActions(); - putProperty (PROP_DEF_ACTIONS, actions, false); - } + actions = (SystemAction[])getProperty (PROP_DEF_ACTIONS); + if ( actions == null ) { + actions = defaultActions(); + putProperty (PROP_DEF_ACTIONS, actions, false); + } + } + return actions; } - return actions; } - + + + /** Identifies the name of context in layer files where the + * loader wishes to store its own actions and also read them. + * In principle any {@link javax.swing.Action} instance can be registered + * in the context and it will be visible in the default DataNode + * for data object created by this loader. Only SystemAction can however + * be manipulated from DataLoader getActions/setActions methods. + *

+ * The default implementation returns null to indicate that no + * layer reading should be used + * + * @return the string name of the context on layer files to read/write acitons to + */ + protected String actionsContext () { + return null; + } + /** Get default actions. * @return array of default system actions or null if this loader * does not have any actions. @@ -160,6 +210,57 @@ return actions; } + /** Actions manager. + */ + private final DataLdrActions findManager () { + Object manager = getProperty (ACTION_MANAGER); + if (manager instanceof Class) { + return null; + } + DataLdrActions mgr = (DataLdrActions)manager; + boolean newlyCreated = false; + if (mgr == null) { + String context = actionsContext (); + if (context == null) { + // mark we have no context + putProperty (ACTION_MANAGER, getClass ()); + return null; + } + + FileObject fo = Repository.getDefault ().getDefaultFileSystem ().findResource (context); + if (fo == null) { + fo = Repository.getDefault ().getDefaultFileSystem ().getRoot (); + try { + fo = FileUtil.createFolder (fo, context); + + } catch (IOException ex) { + ErrorManager.getDefault ().notify (ex); + } + newlyCreated = true; + } + + mgr = new DataLdrActions (DataFolder.findFolder (fo), this); + if (newlyCreated) { + SystemAction[] arr = defaultActions (); + if (arr != null) { + mgr.setActions (arr); + } + } + putProperty (ACTION_MANAGER, mgr); + } + return mgr; + } + + /** Allows the friend code (package and tests) to wait while actions + * are synchronized with the state of disk. + */ + final void waitForActions () { + DataLdrActions mgr = findManager (); + if (mgr != null) { + mgr.waitFinished (); + } + } + /** Set actions. *

Note that this method is public, not protected, so it is possible for anyone * to modify the loader's popup actions externally (after finding the loader @@ -172,7 +273,19 @@ * @see #getActions */ public final void setActions (SystemAction[] actions) { - putProperty (PROP_ACTIONS, actions, true); + DataLdrActions mgr = findManager (); + if (mgr != null) { + mgr.setActions (actions); + } else { + putProperty (PROP_ACTIONS, actions, true); + } + } + + /** Assigns this loader new array of swing actions. + * @param arr List + */ + final void setSwingActions (List/**/ arr) { + firePropertyChange (PROP_ACTIONS, null, null); } /** Get the current display name of this loader. @@ -349,10 +462,15 @@ } try { + ClassLoader loader = (ClassLoader)Lookup.getDefault().lookup(ClassLoader.class); + if (loader == null) { + loader = getClass ().getClassLoader (); + } + Class c = Class.forName ( Utilities.translate((String)arr[i]), false, // why resolve?? --jglick - (ClassLoader)Lookup.getDefault().lookup(ClassLoader.class) + loader ); SystemAction ac = SystemAction.get (c); Index: openide/loaders/src/org/openide/loaders/DataNode.java =================================================================== RCS file: /cvs/openide/loaders/src/org/openide/loaders/DataNode.java,v retrieving revision 1.14 diff -u -r1.14 DataNode.java --- openide/loaders/src/org/openide/loaders/DataNode.java 9 Jun 2004 20:33:53 -0000 1.14 +++ openide/loaders/src/org/openide/loaders/DataNode.java 1 Aug 2004 19:22:06 -0000 @@ -302,6 +302,22 @@ * @see DataLoader#getActions * @return array of actions or null */ + public Action[] getActions (boolean context) { + if (systemActions == null) { + systemActions = createActions (); + } + + if (systemActions != null) { + return systemActions; + } + + return obj.getLoader ().getSwingActions (); + } + + /** Get actions for this data object. + * @deprecated Use getActions(boolean) + * @return array of actions or null + */ public SystemAction[] getActions () { if (systemActions == null) { systemActions = createActions (); @@ -314,6 +330,7 @@ return obj.getLoader ().getActions (); } + /** Get default action. In the current implementation the *null is returned in case the underlying data * object is a template. The templates should not have any default Index: openide/test/unit/src/org/openide/loaders/DataLoaderGetActionsCompatibilityTest.java =================================================================== RCS file: openide/test/unit/src/org/openide/loaders/DataLoaderGetActionsCompatibilityTest.java diff -N openide/test/unit/src/org/openide/loaders/DataLoaderGetActionsCompatibilityTest.java --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openide/test/unit/src/org/openide/loaders/DataLoaderGetActionsCompatibilityTest.java 1 Aug 2004 19:22:23 -0000 @@ -0,0 +1,260 @@ +/* + * Sun Public License Notice + * + * The contents of this file are subject to the Sun Public License + * Version 1.0 (the "License"). You may not use this file except in + * compliance with the License. A copy of the License is available at + * http://www.sun.com/ + * + * The Original Code is NetBeans. The Initial Developer of the Original + * Code is Sun Microsystems, Inc. Portions Copyright 1997-2001 Sun + * Microsystems, Inc. All Rights Reserved. + */ + +package org.openide.loaders; + +import junit.textui.TestRunner; + +import org.openide.filesystems.*; +import org.openide.util.Lookup; +import java.io.IOException; +import java.util.*; +import org.netbeans.junit.*; +import java.beans.PropertyChangeListener; +import javax.swing.Action; +import org.openide.util.io.NbMarshalledObject; + +/** Check how the default behaviour of DataLoader without overriden + * actionsContext works. + * + * @author Jaroslav Tulach + */ +public class DataLoaderGetActionsCompatibilityTest extends NbTestCase { + /** sample data object */ + private DataObject obj; + /** its node */ + private org.openide.nodes.Node node; + /** monitor sfs */ + private PCL sfs; + + public DataLoaderGetActionsCompatibilityTest (String name) { + super(name); + } + + public static void main(String[] args) { + if (args.length == 1) { + TestRunner.run (new DataLoaderGetActionsCompatibilityTest (args[0])); + } else { + TestRunner.run(new NbTestSuite(DataLoaderGetActionsCompatibilityTest.class)); + } + } + + /** + * Sets up the testing environment by creating testing folders + * on the system file system. + */ + protected void setUp () throws Exception { + System.setProperty ("org.openide.util.Lookup", "org.openide.loaders.DataLoaderGetActionsCompatibilityTest$Lkp"); + assertEquals ("Our lookup is installed", Lookup.getDefault ().getClass (), Lkp.class); + + MyDL loader = (MyDL)MyDL.getLoader (MyDL.class); + + FileSystem dfs = Repository.getDefault().getDefaultFileSystem(); + dfs.refresh (true); + + FileObject fo = FileUtil.createData (dfs.getRoot (), "a.txt"); + obj = DataObject.find (fo); + + assertEquals ("The correct loader", loader, obj.getLoader ()); + + node = obj.getNodeDelegate (); + + sfs = new PCL (); + dfs.addFileChangeListener (sfs); + } + + /** + * Deletes the folders created in method setUp(). + */ + protected void tearDown() throws Exception { + obj.getLoader ().setActions (new org.openide.util.actions.SystemAction[0]); + + int l = node.getActions (false).length; + if (l != 0) { + fail ("Not empty actions at the end!!!"); + } + Repository.getDefault ().getDefaultFileSystem ().removeFileChangeListener (sfs); + + // no suspicious activity on getDefaultFileSystem + sfs.assertEvent (0, null); + } + + public void testDefaultActionContextReturnsNull () { + assertNull (obj.getLoader ().actionsContext ()); + } + + public void testDefaultActionsUsedWhenCreatedForTheFirstTime () throws Exception { + SndDL loader = (SndDL)SndDL.getLoader (SndDL.class); + + org.openide.util.actions.SystemAction[] arr = loader.getActions (); + + assertEquals ( + "Arrays of actions are the same", + java.util.Arrays.asList (loader.defaultActions ()), + java.util.Arrays.asList (arr) + ); + } + + /** Test to check that the deserialization of actions works as expected. + */ + public void testNoDeserializationOfActions () throws Exception { + assertEquals("No actions at the start", 0, node.getActions(false).length); + + PCL pcl = new PCL (); + obj.getLoader ().addPropertyChangeListener (pcl); + + obj.getLoader ().setActions (new org.openide.util.actions.SystemAction[] { + org.openide.util.actions.SystemAction.get (org.openide.actions.PropertiesAction.class) + }); + + pcl.assertEvent (1, "actions"); + + Action [] res = node.getActions(false); + assertEquals("There should be exactly one action.", 1, res.length); + + NbMarshalledObject m = new NbMarshalledObject (obj.getLoader ()); + + obj.getLoader ().setActions (new org.openide.util.actions.SystemAction[0]); + + pcl.assertEvent (2, "actions"); + assertEquals("No actions after setting empty array", 0, node.getActions(false).length); + + assertEquals ("Loader deserialized", obj.getLoader (), m.get ()); + res = node.getActions(false); + assertEquals("One action", 1, res.length); + assertEquals ( + "and that is the property action", + org.openide.util.actions.SystemAction.get (org.openide.actions.PropertiesAction.class), + res[0] + ); + + obj.getLoader ().removePropertyChangeListener (pcl); + } + + /** Loader that does not override the actionsContext. + */ + private static class MyDL extends UniFileLoader { + public MyDL () { + super ("org.openide.loaders.DataObject"); + getExtensions ().addExtension ("txt"); + } + + protected org.openide.loaders.MultiDataObject createMultiObject (FileObject primaryFile) throws org.openide.loaders.DataObjectExistsException, IOException { + + + + return new MultiDataObject (primaryFile, this); + } + + protected org.openide.util.actions.SystemAction[] defaultActions () { + return new org.openide.util.actions.SystemAction[0]; + } + + } // end of MyDL + + // + // Our fake lookup + // + public static final class Lkp extends org.openide.util.lookup.AbstractLookup { + public Lkp () throws Exception { + this (new org.openide.util.lookup.InstanceContent ()); + } + + private Lkp (org.openide.util.lookup.InstanceContent ic) throws Exception { + super (ic); + + TestUtilHid.destroyLocalFileSystem (Lkp.class.getName ()); + ic.add (new Repository (TestUtilHid.createLocalFileSystem (Lkp.class.getName (), new String[0]))); + ic.add (new Pool ()); +// ic.add (new EM ()); + } + } + + + private static final class Pool extends DataLoaderPool { + + protected java.util.Enumeration loaders () { + return org.openide.util.Enumerations.singleton ( + DataLoader.getLoader(MyDL.class) + ); + } + + } // end of Pool + + private final class PCL implements org.openide.filesystems.FileChangeListener, java.beans.PropertyChangeListener { + int cnt; + String name; + + public void propertyChange (java.beans.PropertyChangeEvent ev) { + name = ev.getPropertyName(); + cnt++; + } + + public void assertEvent (int cnt, String name) { + obj.getLoader ().waitForActions (); + + if (cnt != this.cnt) { + fail ("Excepted more changes then we got: expected: " + cnt + " we got: " + this.cnt + " with name: " + this.name); + } + } + + public void fileAttributeChanged(org.openide.filesystems.FileAttributeEvent fe) { + cnt++; + name = "fileAttributeChanged"; + } + + public void fileChanged(org.openide.filesystems.FileEvent fe) { + cnt++; + name = "fileChanged"; + } + + public void fileDataCreated(org.openide.filesystems.FileEvent fe) { + cnt++; + name = "fileDataCreated"; + } + + public void fileDeleted(org.openide.filesystems.FileEvent fe) { + cnt++; + name = "fileDeleted"; + } + + public void fileFolderCreated(org.openide.filesystems.FileEvent fe) { + cnt++; + name = "fileFolderCreated"; + } + + public void fileRenamed(org.openide.filesystems.FileRenameEvent fe) { + cnt++; + name = "fileRenamed"; + } + } // end of PCL + + public static final class SndDL extends MyDL { + public SndDL () { + getExtensions ().addExtension ("bla"); + } + + protected org.openide.util.actions.SystemAction[] defaultActions () { + return new org.openide.util.actions.SystemAction[] { + org.openide.util.actions.SystemAction.get (org.openide.actions.CutAction.class), + null, + org.openide.util.actions.SystemAction.get (org.openide.actions.CopyAction.class), + null, + org.openide.util.actions.SystemAction.get (org.openide.actions.DeleteAction.class), + + }; + } + + } + +} Index: openide/test/unit/src/org/openide/loaders/DataLoaderGetActionsTest.java =================================================================== RCS file: openide/test/unit/src/org/openide/loaders/DataLoaderGetActionsTest.java diff -N openide/test/unit/src/org/openide/loaders/DataLoaderGetActionsTest.java --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openide/test/unit/src/org/openide/loaders/DataLoaderGetActionsTest.java 1 Aug 2004 19:22:23 -0000 @@ -0,0 +1,347 @@ +/* + * Sun Public License Notice + * + * The contents of this file are subject to the Sun Public License + * Version 1.0 (the "License"). You may not use this file except in + * compliance with the License. A copy of the License is available at + * http://www.sun.com/ + * + * The Original Code is NetBeans. The Initial Developer of the Original + * Code is Sun Microsystems, Inc. Portions Copyright 1997-2001 Sun + * Microsystems, Inc. All Rights Reserved. + */ + +package org.openide.loaders; + +import junit.textui.TestRunner; + +import org.openide.filesystems.*; +import org.openide.util.Lookup; +import java.io.IOException; +import java.util.*; +import org.netbeans.junit.*; +import java.beans.PropertyChangeListener; +import javax.swing.Action; +import org.openide.util.io.NbMarshalledObject; + +/** Tests the proposed behaviour of DataLoader.getActions that is going + * to read its values from layer. + * + * @author Jaroslav Tulach (taken from openidex/enode by David Strupl) + */ +public class DataLoaderGetActionsTest extends NbTestCase { + /** root folder FileObject */ + private FileObject root; + /** sample data object */ + private DataObject obj; + /** its node */ + private org.openide.nodes.Node node; + + public DataLoaderGetActionsTest (String name) { + super(name); + } + + public static void main(String[] args) { + if (args.length == 1) { + TestRunner.run (new DataLoaderGetActionsTest (args[0])); + } else { + TestRunner.run(new NbTestSuite(DataLoaderGetActionsTest.class)); + } + } + + /** + * Sets up the testing environment by creating testing folders + * on the system file system. + */ + protected void setUp () throws Exception { + System.setProperty ("org.openide.util.Lookup", "org.openide.loaders.DataLoaderGetActionsTest$Lkp"); + assertEquals ("Our lookup is installed", Lookup.getDefault ().getClass (), Lkp.class); + + MyDL loader = (MyDL)MyDL.getLoader (MyDL.class); + + FileSystem dfs = Repository.getDefault().getDefaultFileSystem(); + dfs.refresh (true); + root = FileUtil.createFolder (dfs.getRoot (), loader.actionsContext ()); + + + FileObject fo = FileUtil.createData (dfs.getRoot (), "a.txt"); + obj = DataObject.find (fo); + + assertEquals ("The correct loader", loader, obj.getLoader ()); + + node = obj.getNodeDelegate (); + } + + /** + * Deletes the folders created in method setUp(). + */ + protected void tearDown() throws Exception { + FileObject[] arr = root.getChildren (); + for (int i = 0; i < arr.length; i++) { + arr[i].delete(); + } + int l = node.getActions (false).length; + if (l != 0) { + System.err.println("Not empty actions at the end!!!"); + } + } + + /** + * This test tests the presence of declarative actions from + * system file system without the hierarchical flag set (the ExtensibleNode + * instance is created with constructor ExtensibleNode("test", false). + * The tests performs following steps: + *

  1. Create an instance of ExtensibleNode with folder set to "test" + *
  2. No actions should be returned by getActions since the "test" folder + * is not there + *
  3. Create one action in the testing folder + *
  4. The action should be visible in the result of getActions + *
  5. After deleting the action from the folder the action should + * not be returned from getActions(). + *
+ */ + public void testCreateAndDeleteAction() throws Exception { + assertEquals("No actions at the start", 0, node.getActions(false).length); + FileObject test = root; + + PCL pcl = new PCL (); + obj.getLoader ().addPropertyChangeListener (pcl); + + FileObject a1 = test.createData("org-openide-actions-PropertiesAction.instance"); + + pcl.assertEvent (1, "actions"); + + Action [] res = node.getActions(false); + assertEquals("There should be exactly one action.", 1, res.length); + a1.delete(); + + pcl.assertEvent (2, "actions"); + assertEquals("No actions after deleting", 0, node.getActions(false).length); + + obj.getLoader ().removePropertyChangeListener (pcl); + } + + /** + * An attempt to create a simple stress test. Just calls + * the testCreateAndDeleteAction 100 times. + */ + public void testRepetitiveDeleting() throws Exception { + for (int i = 0; i < 10; i++) { + testCreateAndDeleteAction(); + } + } + + /** + * This test should test behaviour of the getActions method when + * there is some alien object specified in the configuration folder. + * The testing object is of type Integer (instead of javax.swing.Action). + */ + public void testWrongActionObjectInConfig() throws Exception { + assertEquals("No actions at the start", 0, node.getActions(false).length); + FileObject test = root; + FileObject a1 = test.createData("java-lang-String.instance"); + Action [] res = node.getActions(false); + assertEquals("There should be zero actions.", 0, res.length); + } + + /** + * This test checks whether the JSeparator added from the configuration + * file is reflected in the resulting popup. + * The tests performs following steps: + *
  1. Create an instance of ExtensibleNode with folder set to "test" + *
  2. No actions should be returned by getActions since the "test" folder + * is not there + *
  3. Create two actions in the testing folder separated by JSeparator + *
  4. getActions should return 3 elements - null element for the separator + *
  5. Popup is created from the actions array - the null element + * should be replaced by a JSeparator again + *
+ */ + public void testAddingSeparators() throws Exception { + org.openide.nodes.Node en1 = node; + assertEquals("No actions at the start", 0, en1.getActions(false).length); + FileObject test = root; + FileObject a1 = test.createData("1[org-openide-actions-PropertiesAction].instance"); + FileObject sep = test.createData("2[javax-swing-JSeparator].instance"); + FileObject a2 = test.createData("3[org-openide-actions-CutAction].instance"); + javax.swing.Action[] actions = en1.getActions(false); + assertEquals("Actions array should contain 3 elements", 3, actions.length); + assertNull("separator should create null element in the array", actions[1]); + javax.swing.JPopupMenu jp = org.openide.util.Utilities.actionsToPopup(actions, org.openide.util.lookup.Lookups.singleton(en1)); + assertEquals("Popup should contain 3 components", 3, jp.getComponentCount()); + assertTrue("Separator should be second", jp.getComponent(1) instanceof javax.swing.JSeparator); + } + + /** Test to see whether a compatibility behaviour is still kept. E.g. + * if one adds actions using DataLoader.setActions they really will be + * there. + */ + public void testCompatibilityIsPropagatedToDisk () throws Exception { + assertEquals("No actions at the start", 0, node.getActions(false).length); + FileObject test = root; + + PCL pcl = new PCL (); + obj.getLoader ().addPropertyChangeListener (pcl); + + obj.getLoader ().setActions (new org.openide.util.actions.SystemAction[] { + org.openide.util.actions.SystemAction.get (org.openide.actions.PropertiesAction.class) + }); + + pcl.assertEvent (1, "actions"); + + Action [] res = node.getActions(false); + assertEquals("There should be exactly one action.", 1, res.length); + assertEquals("One file created", 1, test.getChildren ().length); + + obj.getLoader ().setActions (new org.openide.util.actions.SystemAction[0]); + + pcl.assertEvent (2, "actions"); + assertEquals("No actions after deleting", 0, node.getActions(false).length); + + assertEquals("file disappeared", 0, test.getChildren ().length); + obj.getLoader ().removePropertyChangeListener (pcl); + } + + /** Test to check that the deserialization of actions is completely ignored. + */ + public void testNoDeserializationOfActions () throws Exception { + assertEquals("No actions at the start", 0, node.getActions(false).length); + FileObject test = root; + + PCL pcl = new PCL (); + obj.getLoader ().addPropertyChangeListener (pcl); + + obj.getLoader ().setActions (new org.openide.util.actions.SystemAction[] { + org.openide.util.actions.SystemAction.get (org.openide.actions.PropertiesAction.class) + }); + + pcl.assertEvent (1, "actions"); + + Action [] res = node.getActions(false); + assertEquals("There should be exactly one action.", 1, res.length); + assertEquals("One file created", 1, test.getChildren ().length); + + NbMarshalledObject m = new NbMarshalledObject (obj.getLoader ()); + + obj.getLoader ().setActions (new org.openide.util.actions.SystemAction[0]); + + pcl.assertEvent (2, "actions"); + assertEquals("No actions after deleting", 0, node.getActions(false).length); + + assertEquals("file disappeared", 0, test.getChildren ().length); + + assertEquals ("Loader deserialized", obj.getLoader (), m.get ()); + assertEquals("Still no actions", 0, node.getActions(false).length); + + obj.getLoader ().removePropertyChangeListener (pcl); + } + + public void testDefaultActionsUsedWhenCreatedForTheFirstTime () throws Exception { + SndDL loader = (SndDL)SndDL.getLoader (SndDL.class); + + org.openide.util.actions.SystemAction[] arr = loader.getActions (); + + assertEquals ( + "Arrays of actions are the same", + java.util.Arrays.asList (loader.defaultActions ()), + java.util.Arrays.asList (arr) + ); + } + + private static class MyDL extends UniFileLoader { + public MyDL () { + super ("org.openide.loaders.DataObject"); + getExtensions ().addExtension ("txt"); + } + + /** Returns the name of the folder to read the actions from + */ + protected String actionsContext () { + return "test"; + } + + protected org.openide.loaders.MultiDataObject createMultiObject (FileObject primaryFile) throws org.openide.loaders.DataObjectExistsException, IOException { + + + + return new MultiDataObject (primaryFile, this); + } + + protected org.openide.util.actions.SystemAction[] defaultActions () { + return new org.openide.util.actions.SystemAction[0]; + } + + } // end of MyDL + + // + // Our fake lookup + // + public static final class Lkp extends org.openide.util.lookup.AbstractLookup { + public Lkp () throws Exception { + this (new org.openide.util.lookup.InstanceContent ()); + } + + private Lkp (org.openide.util.lookup.InstanceContent ic) throws Exception { + super (ic); + + TestUtilHid.destroyLocalFileSystem (Lkp.class.getName ()); + ic.add (new Repository (TestUtilHid.createLocalFileSystem (Lkp.class.getName (), new String[0]))); + ic.add (new Pool ()); +// ic.add (new EM ()); + } + } + + + private static final class Pool extends DataLoaderPool { + + protected java.util.Enumeration loaders () { + return new org.openide.util.enum.SingletonEnumeration ( + DataLoader.getLoader(MyDL.class) + ); + } + + } // end of Pool + + private final class PCL + implements java.beans.PropertyChangeListener { + int cnt; + String name; + + public void propertyChange (java.beans.PropertyChangeEvent ev) { + name = ev.getPropertyName(); + cnt++; + } + + public void assertEvent (int cnt, String name) { + obj.getLoader ().waitForActions (); + + if (cnt > this.cnt) { + fail ("Excepted more changes then we got: expected: " + cnt + " we got: " + this.cnt); + } + assertEquals ("same name", name, this.name); + } + } // end of PCL + + public static final class SndDL extends MyDL { + public SndDL () { + getExtensions ().addExtension ("bla"); + } + + protected org.openide.util.actions.SystemAction[] defaultActions () { + return new org.openide.util.actions.SystemAction[] { + org.openide.util.actions.SystemAction.get (org.openide.actions.CutAction.class), + null, + org.openide.util.actions.SystemAction.get (org.openide.actions.CopyAction.class), + null, + org.openide.util.actions.SystemAction.get (org.openide.actions.DeleteAction.class), + + }; + } + + protected String actionsContext () { + return "2ndtestdir"; + } + + } + +}