Index: core/src/org/netbeans/core/projects/SettingChildren.java
===================================================================
RCS file: /cvs/core/src/org/netbeans/core/projects/SettingChildren.java,v
retrieving revision 1.18
diff -c -r1.18 SettingChildren.java
*** core/src/org/netbeans/core/projects/SettingChildren.java 12 Nov 2002 16:19:47 -0000 1.18
--- core/src/org/netbeans/core/projects/SettingChildren.java 15 Jan 2003 14:10:07 -0000
***************
*** 19,24 ****
--- 19,25 ----
import org.openide.nodes.*;
import org.openide.loaders.DataObject;
import org.openide.loaders.DataFolder;
+ import org.openide.loaders.DataShadow;
import org.openide.filesystems.FileObject;
import org.openide.filesystems.FileSystem;
import org.openide.filesystems.FileStateInvalidException;
***************
*** 93,98 ****
--- 94,105 ----
public int hashCode() {
return getOriginal().hashCode();
}
+ public String getDisplayName() {
+ //find the original to discard the (->) text
+ DataObject dob = (DataObject) getCookie (DataObject.class);
+ while (dob instanceof DataShadow) dob = ((DataShadow) dob).getOriginal();
+ return dob.getNodeDelegate().getDisplayName();
+ }
}
/** Property allowing display/manipulation of setting status for one specific layer. */
***************
*** 311,317 ****
public SettingFilterNode (Node original) {
super (original);
!
FileObject pf = ((DataObject) getCookie (DataObject.class)).getPrimaryFile ();
weakL = new FSL (this);
FileStateManager.getDefault ().addFileStatusListener (weakL, pf);
--- 318,324 ----
public SettingFilterNode (Node original) {
super (original);
!
FileObject pf = ((DataObject) getCookie (DataObject.class)).getPrimaryFile ();
weakL = new FSL (this);
FileStateManager.getDefault ().addFileStatusListener (weakL, pf);
***************
*** 320,325 ****
--- 327,339 ----
specialProp (new FileStateProperty (pf, FileStateManager.LAYER_PROJECT, PROP_LAYER_PROJECT, false));
specialProp (new FileStateProperty (pf, FileStateManager.LAYER_SESSION, PROP_LAYER_SESSION, false));
specialProp (new FileStateProperty (pf, FileStateManager.LAYER_MODULES, PROP_LAYER_MODULES, false));
+ }
+
+ public String getDisplayName() {
+ //find the original to discard the (->) text
+ DataObject dob = (DataObject) getCookie (DataObject.class);
+ while (dob instanceof DataShadow) dob = ((DataShadow) dob).getOriginal();
+ return dob.getNodeDelegate().getDisplayName();
}
/** Registers special property.
Index: openide/src/org/openide/actions/NewTemplateAction.java
===================================================================
RCS file: /cvs/openide/src/org/openide/actions/NewTemplateAction.java,v
retrieving revision 1.71
diff -c -r1.71 NewTemplateAction.java
*** openide/src/org/openide/actions/NewTemplateAction.java 9 Jan 2003 17:08:47 -0000 1.71
--- openide/src/org/openide/actions/NewTemplateAction.java 15 Jan 2003 14:10:08 -0000
***************
*** 299,318 ****
protected Node[] createNodes (Object key) {
Node n = (Node)key;
String nodeName = n.getDisplayName();
!
! DataObject obj = null;
! DataShadow shadow = (DataShadow)n.getCookie (DataShadow.class);
! if (shadow != null) {
! // I need DataNode here to get localized name of the
! // shadow, but without the ugly "(->)" at the end
! DataNode dn = new DataNode(shadow, Children.LEAF);
! nodeName = dn.getDisplayName();
! obj = shadow.getOriginal();
! n = obj.getNodeDelegate();
! }
!
! if (obj == null)
! obj = (DataObject)n.getCookie (DataObject.class);
if (obj != null) {
if (obj.isTemplate ()) {
// on normal nodes stop recursion
--- 299,305 ----
protected Node[] createNodes (Object key) {
Node n = (Node)key;
String nodeName = n.getDisplayName();
! DataObject obj = (DataObject) n.getCookie(DataObject.class);
if (obj != null) {
if (obj.isTemplate ()) {
// on normal nodes stop recursion
***************
*** 439,454 ****
Node n = (Node)key;
String nodeName = n.getDisplayName();
! DataObject obj = null;
! DataShadow shadow = (DataShadow)n.getCookie (DataShadow.class);
! if (shadow != null) {
! // I need DataNode here to get localized name of the
! // shadow, but without the ugly "(->)" at the end
! DataNode dn = new DataNode(shadow, Children.LEAF);
! nodeName = dn.getDisplayName();
! obj = shadow.getOriginal();
! n = obj.getNodeDelegate();
! }
if (obj == null)
obj = (DataObject)n.getCookie (DataObject.class);
--- 426,432 ----
Node n = (Node)key;
String nodeName = n.getDisplayName();
! DataObject obj = (DataObject) n.getCookie(DataObject.class);
if (obj == null)
obj = (DataObject)n.getCookie (DataObject.class);
Index: openide/src/org/openide/loaders/DataObject.java
===================================================================
RCS file: /cvs/openide/src/org/openide/loaders/DataObject.java,v
retrieving revision 1.84
diff -c -r1.84 DataObject.java
*** openide/src/org/openide/loaders/DataObject.java 21 Dec 2002 08:40:24 -0000 1.84
--- openide/src/org/openide/loaders/DataObject.java 15 Jan 2003 14:10:08 -0000
***************
*** 339,350 ****
* @return true
if it is a template
*/
public final boolean isTemplate () {
Object o = getPrimaryFile().getAttribute(PROP_TEMPLATE);
boolean ret = false;
if (o instanceof Boolean)
ret = ((Boolean) o).booleanValue();
return ret;
! }
/** Test whether the object may be deleted.
--- 339,357 ----
* @return true
if it is a template
*/
public final boolean isTemplate () {
+ return isTemplateImpl();
+ }
+
+ /** Implementation of isTemplate test. Overridden by
+ * DataShadow to return the template value for the
+ * file pointed to. */
+ boolean isTemplateImpl () {
Object o = getPrimaryFile().getAttribute(PROP_TEMPLATE);
boolean ret = false;
if (o instanceof Boolean)
ret = ((Boolean) o).booleanValue();
return ret;
! }
/** Test whether the object may be deleted.
Index: openide/src/org/openide/loaders/DataLoaderPool.java
===================================================================
RCS file: /cvs/openide/src/org/openide/loaders/DataLoaderPool.java,v
retrieving revision 1.95
diff -c -r1.95 DataLoaderPool.java
*** openide/src/org/openide/loaders/DataLoaderPool.java 21 Dec 2002 08:40:24 -0000 1.95
--- openide/src/org/openide/loaders/DataLoaderPool.java 15 Jan 2003 14:10:08 -0000
***************
*** 813,820 ****
*/
protected MultiDataObject createMultiObject(FileObject primaryFile) throws DataObjectExistsException, IOException {
try {
! DataObject d = DataShadow.deserialize (primaryFile);
! if (d != null) return new DataShadow (primaryFile, d, this);
} catch (IOException ex) {
// broken link or damaged shadow file
}
--- 813,833 ----
*/
protected MultiDataObject createMultiObject(FileObject primaryFile) throws DataObjectExistsException, IOException {
try {
! //first, try to instantiate the shadow without creating
! //the underlying DataObject
! if (DataShadow.canInstantiateLazily (primaryFile)) {
! //Make sure the shadow points to a valid file
! if (primaryFile == null) {
! return new BrokenDataShadow (primaryFile, this);
! } else {
! FileObject fo = DataShadow.validate (primaryFile);
! return new DataShadow (primaryFile, this);
! }
! } else {
! //use the old behavior, instantiating the DataObject
! DataObject d = DataShadow.deserialize (primaryFile);
! if (d != null) return new DataShadow (primaryFile, d, this);
! }
} catch (IOException ex) {
// broken link or damaged shadow file
}
Index: openide/src/org/openide/loaders/DataShadow.java
===================================================================
RCS file: /cvs/openide/src/org/openide/loaders/DataShadow.java,v
retrieving revision 1.49
diff -c -r1.49 DataShadow.java
*** openide/src/org/openide/loaders/DataShadow.java 21 Dec 2002 08:40:25 -0000 1.49
--- openide/src/org/openide/loaders/DataShadow.java 15 Jan 2003 14:10:08 -0000
***************
*** 13,19 ****
package org.openide.loaders;
! import java.awt.datatransfer.Transferable;
import java.awt.Image;
import java.beans.*;
import java.io.*;
--- 13,20 ----
package org.openide.loaders;
! import java.awt.Component;
! import java.awt.datatransfer.*;
import java.awt.Image;
import java.beans.*;
import java.io.*;
***************
*** 21,26 ****
--- 22,28 ----
import java.lang.reflect.*;
import java.lang.ref.*;
import java.util.*;
+ import javax.swing.Action;
import org.openide.filesystems.*;
import org.openide.filesystems.FileSystem;
***************
*** 28,34 ****
import org.openide.nodes.*;
import org.openide.util.HelpCtx;
import org.openide.ErrorManager;
! import org.openide.util.datatransfer.ExTransferable;
import org.openide.util.Mutex;
import org.openide.util.MutexException;
--- 30,36 ----
import org.openide.nodes.*;
import org.openide.util.HelpCtx;
import org.openide.ErrorManager;
! import org.openide.util.datatransfer.*;
import org.openide.util.Mutex;
import org.openide.util.MutexException;
***************
*** 59,64 ****
--- 61,69 ----
private static final int IDX_FS = 0;
private static final int IDX_PATH = 1;
+ //tracking variable to enforce display name consistency
+ //across ProxyShadowNode and ShadowNode
+ boolean wasLazy = false;
/** Getter for the Set that contains all DataShadows. */
private static Set getDataShadowsSet() {
***************
*** 181,191 ****
init(original);
}
/** Perform initialization after construction.
* @param original original data object
*/
private void init(DataObject original) {
! if (original == null)
throw new IllegalArgumentException();
setOriginal (original);
enqueueDataShadow(this);
--- 186,216 ----
init(original);
}
+ /** Constructs a new data shadow which will lazily dereference
+ * its original DataObject only if information (generally cookies
+ * or description) are asked for that cannot be found on the primary
+ * file.
+ * Used to avoid creation of the original if the display name and
+ * icon are available on the original node. Note that this constructor
+ * should not be used for shadows where the original DataObject might
+ * change out from under them, because it will only start listening
+ * to the original DataObject if something causes it to call
+ * DataObject.find() and dereference the original. It is primarily
+ * useful for shadows where the common case is that they will remain
+ * untouched and creating the real DataObject to represent the
+ * underlying file would cause additional classloading. See
+ * issue 28683.
+ */
+ DataShadow (FileObject fo, DataLoader loader) throws DataObjectExistsException {
+ super (fo, loader);
+ wasLazy=true;
+ }
+
/** Perform initialization after construction.
* @param original original data object
*/
private void init(DataObject original) {
! if ((original == null) && (!canInstantiateLazily (getPrimaryFile())))
throw new IllegalArgumentException();
setOriginal (original);
enqueueDataShadow(this);
***************
*** 311,316 ****
--- 336,358 ----
throw (IOException) e.getException ();
}
}
+
+ /** Returns the primary file of the DataObject this
+ * shadow links to. If this DataShadow was instantiated
+ * without the DataObject it points to instantiated (i.e.,
+ * in an XML layer with the SystemFileSystem.icon
+ * and SystemFileSystem.localizingBundle
attributes
+ * present), calling this method will not force instantiation
+ * of the DataObject this shadow links to.
+ */
+ final FileObject getOriginalPrimaryFile() {
+ try {
+ return validate (getPrimaryFile());
+ } catch (java.io.IOException ioe) {
+ ErrorManager.getDefault().notify (ErrorManager.INFORMATIONAL, ioe);
+ return getOriginal().getPrimaryFile();
+ }
+ }
/** Loads proper dataShadow from the file fileObject.
*
***************
*** 319,327 ****
* @exception IOException error during load
*/
protected static DataObject deserialize (FileObject fileObject) throws java.io.IOException {
String result [] = read (fileObject);
FileObject fo = checkOriginal (result [IDX_PATH], result [IDX_FS], fileObject.getFileSystem());
! return DataObject.find (fo);
}
private static String [] read (final FileObject f) throws IOException {
--- 361,400 ----
* @exception IOException error during load
*/
protected static DataObject deserialize (FileObject fileObject) throws java.io.IOException {
+ FileObject fo = validate (fileObject);
+ return DataObject.find (fo);
+ }
+
+ /** Can the shadow be instantiated lazily? This could be done for
+ * all shadows, but as this is a micro-optimization, it will hurt
+ * in the case that a lazy node would be created and immediately
+ * asked for some cookie that would force the node's replacement. */
+ private static final boolean isLazy(FileObject fo) {
+ return (Boolean.TRUE.equals (fo.getAttribute("isLazy")) &&
+ fo.getAttribute("SystemFileSystem.icon") != null && //NOI18N
+ fo.getAttribute ("SystemFileSystem.localizingBundle") != null); //NOI18N
+ }
+
+ /** Checks for icon and display name properties that will allow the
+ * Shadow to be instantiated without first creating the DataObject. */
+ static final boolean canInstantiateLazily (FileObject fo) {
+ //See if it specifies an icon and display name
+ boolean result = isLazy (fo);
+ //If no, see if the file pointed to does
+ try {
+ if (!result) result = isLazy(validate(fo));
+ } catch (java.io.IOException ioe) {
+ ErrorManager.getDefault().notify(ErrorManager.INFORMATIONAL, ioe);
+ }
+ return result;
+ }
+
+ /** Returns the primary file pointed to by the passed shadow file
+ * without instantiating a DataObject. */
+ static FileObject validate (FileObject fileObject) throws java.io.IOException {
String result [] = read (fileObject);
FileObject fo = checkOriginal (result [IDX_PATH], result [IDX_FS], fileObject.getFileSystem());
! return fo;
}
private static String [] read (final FileObject f) throws IOException {
***************
*** 420,428 ****
--- 493,519 ----
* @return the data object
*/
public DataObject getOriginal () {
+ if (original == null) {
+ resolveOriginal();
+ }
return original;
}
+ /** For the case of lazy initialization, find the
+ * DataObject.
+ */
+ private synchronized void resolveOriginal () {
+ try {
+ FileObject fo = this.getPrimaryFile();
+ init (deserialize (fo));
+ } catch (java.io.IOException ioe) {
+ IllegalStateException e = new IllegalStateException ("Failure resolving file " //NOI18N
+ + getPrimaryFile());
+ ErrorManager.getDefault().annotate (ioe, e);
+ throw e;
+ }
+ }
+
/** Implementation of Container interface.
* @return array of one element, the original
*/
***************
*** 430,439 ****
return new DataObject[] { getOriginal () };
}
/* Creates node delegate.
*/
protected Node createNodeDelegate () {
! return new ShadowNode (this);
}
/* Getter for delete action.
--- 521,557 ----
return new DataObject[] { getOriginal () };
}
+ /**Overrides DataObject.isTemplateImpl() to check if the primary
+ * file the shadow points to has its template attribute set.
+ * This avoids DataObject creation if this shadow is was
+ * created from an XML layer and instantiates its backing
+ * DataObject lazily. */
+ protected boolean isTemplateImpl() {
+ if (original == null) {
+ try {
+ FileObject DOPrimary = validate(getPrimaryFile());
+ if (DOPrimary != null) {
+ Object o = (Boolean) DOPrimary.getAttribute(PROP_TEMPLATE);
+ return Boolean.TRUE.equals (o);
+ }
+ } catch (java.io.IOException ioe) {
+ ErrorManager.getDefault().notify (ErrorManager.INFORMATIONAL, ioe);
+ }
+ }
+ return getOriginal().isTemplate();
+ }
+
/* Creates node delegate.
*/
protected Node createNodeDelegate () {
! Node realNode;
! if ((original == null) && canInstantiateLazily (getPrimaryFile())) {
! realNode = new ProxyShadowNode(new ProxyDOChildren());
! } else {
! realNode = new ShadowNode(this);
! }
! MutableFilterNode result = new MutableFilterNode (realNode);
! return result;
}
/* Getter for delete action.
***************
*** 479,485 ****
* @return the shadow
*/
protected DataShadow handleCreateShadow (DataFolder f) throws IOException {
! return original.handleCreateShadow (f);
}
/* Scans the orginal bundle */
--- 597,603 ----
* @return the shadow
*/
protected DataShadow handleCreateShadow (DataFolder f) throws IOException {
! return getOriginal().handleCreateShadow (f);
}
/* Scans the orginal bundle */
***************
*** 487,493 ****
if (c.isInstance (this)) {
return this;
}
! return original.getCookie (this, c);
}
/* Try to refresh link to original file */
--- 605,611 ----
if (c.isInstance (this)) {
return this;
}
! return getOriginal().getCookie (this, c);
}
/* Try to refresh link to original file */
***************
*** 500,506 ****
/* Link isn't broken */
if (moved)
tryUpdate();
! if (checkOriginal(original) != null)
return;
} catch (IOException e) {
}
--- 618,624 ----
/* Link isn't broken */
if (moved)
tryUpdate();
! if (checkOriginal(getOriginal()) != null)
return;
} catch (IOException e) {
}
***************
*** 513,519 ****
private void tryUpdate() throws IOException {
String result [] = read (getPrimaryFile ());
! FileObject pf = original.getPrimaryFile ();
if (result [IDX_PATH].equals (pf.getPath())) {
if (result[IDX_FS] == null) {
if (getPrimaryFile().getFileSystem() == pf.getFileSystem ())
--- 631,637 ----
private void tryUpdate() throws IOException {
String result [] = read (getPrimaryFile ());
! FileObject pf = getOriginal().getPrimaryFile ();
if (result [IDX_PATH].equals (pf.getPath())) {
if (result[IDX_FS] == null) {
if (getPrimaryFile().getFileSystem() == pf.getFileSystem ())
***************
*** 563,569 ****
}
private static void updateShadowOriginal(final DataShadow shadow) {
! final FileObject primary = shadow.original.getPrimaryFile ();
org.openide.util.RequestProcessor.postRequest (new Runnable () {
public void run () {
--- 681,687 ----
}
private static void updateShadowOriginal(final DataShadow shadow) {
! final FileObject primary = shadow.getOriginal().getPrimaryFile ();
org.openide.util.RequestProcessor.postRequest (new Runnable () {
public void run () {
***************
*** 595,601 ****
--- 713,1128 ----
}
}
}
+
+
+ /** Utility method for getting the declared resource bundle for the
+ * shadow and looking the display name up in it. Looks for the attribute
+ * SystemFileSystem.localizingBundle
first on the
+ * shadow's file, then on the original file it represents, then
+ * tries to find a key for whatever file it got the bundle attribute
+ * from.
+ */
+ private static final String displayNameForShadow (DataShadow ds) {
+ FileObject fo = ds.getPrimaryFile();
+ String bundlename = (String) fo.getAttribute ("SystemFileSystem.localizingBundle"); //NOI18N
+ if (bundlename == null) {
+ fo = ds.getOriginalPrimaryFile();
+ bundlename = (String) fo.getAttribute("SystemFileSystem.localizingBundle"); //NOI18N
+ }
+ if (bundlename != null) {
+ try {
+ ResourceBundle rb = NbBundle.getBundle(bundlename);
+ return rb.getString (fo.getPath());
+ } catch (MissingResourceException mre) {
+ ErrorManager.getDefault().log
+ (ErrorManager.INFORMATIONAL,
+ "Missing display name key for " + fo + " in resource bundle "
+ + bundlename); //NOI18N
+ ErrorManager.getDefault().notify(ErrorManager.WARNING, mre);
+ }
+ }
+ return null;
+ }
+
+ /** Utility method for fetching an attribute from the shadow's source file
+ * or if not present there, on the file pointed to by it, while not
+ * forcing DataObject instantiation. If checkParent is true, will
+ * also check for the attribute on the containing folder for the
+ * shadow (useful, e.g., for specifying HelpCtx for a group of templates)*/
+ private static final Object attributeForShadow (DataShadow ds, String attr, boolean checkParent) {
+ FileObject fo = ds.getPrimaryFile();
+ Object result = fo.getAttribute (attr);
+ if (result == null) {
+ fo = ds.getOriginalPrimaryFile();
+ result = fo.getAttribute (attr);
+ }
+ if ((result == null) && checkParent) {
+ fo = ds.getPrimaryFile().getParent();
+ result = fo.getAttribute (attr);
+ if (result == null) {
+ fo = ds.getOriginalPrimaryFile();
+ result = fo.getAttribute (attr);
+ }
+ }
+ return result;
+ }
+
+
+
+ /**Attempt to get the icon from the file's attributes without
+ * recourse to the underlying DataObject. */
+ private static final Image getDeclaredIcon (DataShadow ds, int type) {
+ //XXX sfs not annotating icon; need to investigate further
+ //Try to get the icon from file attributes.
+ try {
+ if (!ds.getOriginalPrimaryFile().getFileSystem().equals (
+ Repository.getDefault().getDefaultFileSystem())) return null;
+ Object iconRes=null;
+ switch (type) {
+ case BeanInfo.ICON_COLOR_32x32 :
+ iconRes = attributeForShadow (ds, "SystemFileSystem.icon32",false); //NOI18N
+ break;
+ default :
+ iconRes = attributeForShadow (ds, "SystemFileSystem.icon",false); //NOI18N
+ break;
+ }
+ if (iconRes instanceof java.net.URL) {
+ Image i = java.awt.Toolkit.getDefaultToolkit ().getImage ((java.net.URL) iconRes);
+ return i;
+ }
+ } catch (FileStateInvalidException fsie) {
+ ErrorManager.getDefault().notify(ErrorManager.INFORMATIONAL, fsie);
+ }
+ return null;
+ }
+
+ /** Create a new data object from template.
+ * In DataShadow, this delegates to
+ * getOriginal().createFromTemplate()
+ *
+ * @param df data folder to create object in
+ * @param name name to give to the new object (or null
+ * if the name should be chosen according to the template)
+ * @return the new data object
+ * @exception IOException if an error occured
+ *
+ */
+ protected DataObject handleCreateFromTemplate(DataFolder df, String name) throws IOException {
+ DataObject retValue;
+ retValue = getOriginal().createFromTemplate(df, name);
+ return retValue;
+ }
+
+
+
+ /** A trivial class to make FilterNode.changeOriginal public
+ * for use by ProxyShadowNode. The base DataShadow root
+ * node is a MutableFilterNode that delegates either
+ * to a ProxyShadowNode or a ShadowNode, depending on
+ * whether the DataObject has been instantiated. */
+ private static class MutableFilterNode extends FilterNode {
+ public MutableFilterNode (Node n) {
+ super (n);
+ }
+
+ public void setOriginal (Node n) {
+ changeOriginal (n, true);
+ }
+ }
+
+ /**A node that stands in for ShadowNode and tries to proxy
+ * display name and icon to the filesystem. When asked for
+ * data it can't provide (since it does not represent the
+ * node delegate for the underlying DataObject, which ideally
+ * is not yet instantiated), it will force instantiation of
+ * the DataObject (causing it to be replaced by a bona-fide
+ * ShadowNode) and return the result of the same call to its
+ * replacement. */
+ private class ProxyShadowNode extends AbstractNode {
+ //This is an inner class of MutableFilterNode in order
+ //to have access to MutableFilterNode.changeOriginal().
+ public ProxyShadowNode (ProxyDOChildren children) {
+ super (children); //XXX
+ }
+
+ private boolean dying=false;
+ private ShadowNode replacement=null;
+ /* The method below should *probably* be synchronized,
+ * as it could conceivably be entered before
+ * dying is set to true. This causes a deadlock
+ * in the options dialog, when FormEditorSettings
+ * is selected. TODO: See if the ShadowNode for
+ * a single shadow is ever created twice. -TDB
+ */
+ /** Create a ShadowNode to replace this instance and
+ * call changeOriginal on the MutableFilterNode that
+ * was proxying this instance. */
+ private Node die() {
+ if (dying) return replacement;
+ //Get the filter node that proxies this node
+ MutableFilterNode mfn = (MutableFilterNode)DataShadow.this.getNodeDelegate();
+ //Create a new ShadowNode to represent the DataObject
+ dying=true;
+ replacement = new ShadowNode (DataShadow.this);
+ //Node, replace thyself
+ mfn.setOriginal(replacement);
+ return replacement;
+ }
+
+ public Node.Cookie getCookie (Class clazz) {
+ if (clazz.isInstance (DataShadow.this)) {
+ return DataShadow.this;
+ }
+ Node n = die();
+ return getOriginal().getCookie(clazz);
+ }
+
+
+ public String getDisplayName() {
+ //if original is null, see if the FS will supply the filename
+ //from attributes and we can avoid instantiating the DataObject
+ try {
+ String name = displayNameForShadow (DataShadow.this);
+ if (name == null) {
+ name = "";
+ name = getOriginalPrimaryFile().getFileSystem().getStatus().annotateName(name, files());
+ }
+ if (name != null) {
+ return name;
+ }
+ } catch (FileStateInvalidException fsie) {
+ ErrorManager.getDefault().notify(ErrorManager.INFORMATIONAL, fsie);
+ }
+ return getOriginal().getNodeDelegate().getDisplayName();
+ }
+
+ public Image getOpenedIcon(int type) {
+ Image i = baseIcon (type);
+ if (i != null) {
+ return i;
+ } else {
+ Node n = die();
+ return n.getOpenedIcon(type);
+ }
+ }
+
+ public Image getIcon(int type) {
+ Image i = baseIcon (type);
+ if (i != null) {
+ return i;
+ } else {
+ Node n = die();
+ return n.getIcon (type);
+ }
+ }
+
+ Image icon;
+ boolean noDeclaredIcon = false;
+ private final Image baseIcon(int type) {
+ if ((icon == null) && !noDeclaredIcon) {
+ icon = getDeclaredIcon (DataShadow.this, type);
+ noDeclaredIcon = icon == null;
+ }
+ return icon;
+ }
+ /* Renames the shadow data object.
+ * @param name new name for the object
+ * @exception IllegalArgumentException if the rename failed */
+ public void setName (String name) {
+ //Modified from ShadowNode - TDB
+ try {
+ if (!name.equals (DataShadow.this.getName ())) {
+ rename (name);
+ // (String strFile, String strFS, FileSystem origSystem)
+ FileObject orig = getOriginalPrimaryFile();
+ String result [] = read (orig);
+ FileObject fo = checkOriginal (result [IDX_PATH], result [IDX_FS], orig.getFileSystem());
+ if (fo.isRoot()) {
+ orig.setAttribute (ShadowNode.ATTR_USEOWNNAME, Boolean.TRUE);
+ }
+ fireDisplayNameChange (null, null);
+ fireNameChange (null, null);
+ }
+ } catch (IOException ex) {
+ throw new IllegalArgumentException (ex.getMessage ());
+ }
+ }
+
+ MessageFormat descriptionFormat = null;
+ /* Creates description based on the original one. */
+ public String getShortDescription () {
+ //Note this will instantiate the DO. This node can
+ //remain, however, unless asked for something it can't give.
+ //Cannot use die() pattern here - changeOriginal() in FilterNode
+ //will create an endless loop because it also calls this
+ //method in order to fire changes.
+ //Lacking a spec for specifying short description for a
+ //node in fs layers, this means the DO will be created
+ //when a temnplate node is asked for a tooltip.
+ //IMO, this is not such a bad thing, as this means
+ //that the classloading will be done when the user is
+ //browsing the nodes, rather than waiting for a wizard
+ //step, etc.
+ return getOriginal().getNodeDelegate().getShortDescription();
+ }
+
+ public org.openide.util.actions.SystemAction[] getActions () {
+ Node n = die();
+ return n.getActions();
+ }
+
+ public org.openide.util.actions.SystemAction[] getContextActions () {
+ Node n = die();
+ return n.getContextActions();
+ }
+
+ public String getName () {
+ return DataShadow.this.getName();
+ }
+
+ /** Returns a help context. Will look for it first on the
+ * file pointed to by the shadow, in the attribute
+ * helpID
. If that fails, it will look for
+ * the same attribute on the parent folder of the shadow
+ * (e.g. Templates/
). If that also fails, it
+ * falls back to instantiating the DataObject and retrieving
+ * the value from its node delegate. */
+ public HelpCtx getHelpCtx() {
+ //Find helpID as an attribute of the primary file or original's primary file,
+ //or parent folder of either, shadow first
+ Object id= attributeForShadow (DataShadow.this, "SystemFileSystem.helpID", true); //NOI18N
+
+ if (id instanceof String) {
+ return new HelpCtx ((String) id);
+ } else if (id instanceof java.net.URL) {
+ return new HelpCtx ((java.net.URL) id);
+ }
+ //if the check failed, instantiate the DataObject and return it
+ Node n = die();
+ return n.getHelpCtx();
+ }
+
+ public org.openide.util.actions.SystemAction getDefaultAction() {
+ Node n = die();
+ return n.getDefaultAction();
+ }
+
+ public Component getCustomizer () {
+ Node n = die();
+ return n.getCustomizer();
+ }
+
+ public Node.Handle getHandle() {
+ //XXX probably could return a real handle for this node, which
+ //will avoid creating the DO on deserialization.
+ Node n = die();
+ return n.getHandle();
+ }
+
+ public NewType[] getNewTypes() {
+ Node n = die();
+ return n.getNewTypes();
+ }
+
+ public PasteType getDropType (Transferable t, int action, int index) {
+ Node n = die();
+ return n.getDropType (t, action, index);
+ }
+
+ public PasteType[] getPasteType (Transferable t) {
+ Node n = die();
+ return n.getPasteTypes(t);
+ }
+
+ public Node.PropertySet[] getPropertySets() {
+ Node n = die();
+ return n.getPropertySets();
+ }
+
+ public boolean hasCustomizer() {
+ Node n = die();
+ return n.hasCustomizer();
+ }
+
+ public void setShortDescription (String s) {
+ Node n = die();
+ n.setShortDescription (s);
+ }
+
+ public void setDisplayName(String s) {
+ Node n = die();
+ n.setShortDescription (s);
+ }
+
+ /* @return obj.isDeleteAllowed () */
+ public boolean canDestroy () {
+ return DataShadow.this.isDeleteAllowed ();
+ }
+
+ /* Destroyes the node
+ */
+ public void destroy () throws IOException {
+ synchronized (DataShadow.this.nodes) {
+ DataShadow.this.nodes.remove (this);
+ }
+ DataShadow.this.delete ();
+ // super.destroy ();
+ }
+
+ /** @return true if shadow can be renamed
+ */
+ public final boolean canRename () {
+ return DataShadow.this.isRenameAllowed ();
+ }
+
+ /* Returns true if this object allows copying.
+ * @returns true if so
+ */
+ public final boolean canCopy () {
+ return DataShadow.this.isCopyAllowed ();
+ }
+
+ /* Returns true if this object allows cutting.
+ * @returns true if so
+ */
+ public final boolean canCut () {
+ return DataShadow.this.isMoveAllowed ();
+ }
+
+ public Node cloneNode() {
+ return new ProxyShadowNode(new ProxyDOChildren());
+ }
+ }
+
+ /**A children object that avoids forcing the original DO to be
+ *instantiated until addNotify() is called. */
+ private class ProxyDOChildren extends Children.Keys {
+
+ public ProxyDOChildren() {
+ }
+
+ public void addNotify() {
+ //avoid creating the DataObject if the primary file specifies
+ //that there are no children
+ Boolean isLeaf = (Boolean) attributeForShadow (DataShadow.this, "isLeaf",false);
+ if ((isLeaf == null) || Boolean.FALSE.equals (isLeaf))
+ setKeys (getOriginal().getNodeDelegate().getChildren().getNodes());
+ else
+ setKeys (Collections.EMPTY_SET);
+ }
+
+ public Node[] createNodes (Object key) {
+ Node n = (Node) key;
+ return new Node[] {new FilterNode (n)};
+ }
+
+ public void removeNotify() {
+ setKeys (Collections.EMPTY_SET);
+ }
+ }
+
+
/** Node for a shadow object. */
protected static class ShadowNode extends FilterNode {
/** message to create name of node */
***************
*** 647,653 ****
try {
if (!name.equals (obj.getName ())) {
obj.rename (name);
! if (obj.original.getPrimaryFile ().isRoot ()) {
obj.getPrimaryFile ().setAttribute (ATTR_USEOWNNAME, Boolean.TRUE);
}
fireDisplayNameChange (null, null);
--- 1174,1180 ----
try {
if (!name.equals (obj.getName ())) {
obj.rename (name);
! if (obj.getOriginal().getPrimaryFile ().isRoot ()) {
obj.getPrimaryFile ().setAttribute (ATTR_USEOWNNAME, Boolean.TRUE);
}
fireDisplayNameChange (null, null);
***************
*** 684,693 ****
/* Creates name based on the original one.
*/
public String getDisplayName () {
if (format == null) {
format = new MessageFormat (NbBundle.getBundle (DataShadow.class).getString ("FMT_shadowName"));
}
! String n = format.format (createArguments ());
try {
obj.getPrimaryFile().getFileSystem().getStatus().annotateName(n, obj.files());
} catch (FileStateInvalidException fsie) {
--- 1211,1227 ----
/* Creates name based on the original one.
*/
public String getDisplayName () {
+ //enforce naming consistency so name cannot accidentally
+ //change if the ShadowNode is instantiated for a lazily
+ //created DataObject. Who uses lazy instantiation shall
+ //forfeit the right for the shadow to display a link
+ String n = canInstantiateLazily (obj.getPrimaryFile()) ?
+ displayNameForShadow (obj) : null;
+ if (n != null) return n;
if (format == null) {
format = new MessageFormat (NbBundle.getBundle (DataShadow.class).getString ("FMT_shadowName"));
}
! n = format.format (createArguments ());
try {
obj.getPrimaryFile().getFileSystem().getStatus().annotateName(n, obj.files());
} catch (FileStateInvalidException fsie) {
***************
*** 700,706 ****
private Object[] createArguments () {
String origDisp;
String shadowName = obj.getName ();
! if (obj.original.isValid()) {
origDisp = obj.original.getNodeDelegate().getDisplayName();
} else {
// We will soon be a broken data shadow, in the meantime...
--- 1234,1240 ----
private Object[] createArguments () {
String origDisp;
String shadowName = obj.getName ();
! if (obj.getOriginal().isValid()) {
origDisp = obj.original.getNodeDelegate().getDisplayName();
} else {
// We will soon be a broken data shadow, in the meantime...
***************
*** 781,787 ****
// ignore
}
}
! return null;
}
/* @return obj.isDeleteAllowed () */
--- 1315,1321 ----
// ignore
}
}
! return getDeclaredIcon (obj, type);
}
/* @return obj.isDeleteAllowed () */
***************
*** 827,832 ****
--- 1361,1367 ----
* @return the cookie or null
*/
public Node.Cookie getCookie (Class cl) {
+ if (cl.isInstance(DataShadow.class)) return obj;
Node.Cookie c = obj.getCookie (cl);
if (c != null) {
return c;
Index: openide/src/org/openide/loaders/TemplateWizard.java
===================================================================
RCS file: /cvs/openide/src/org/openide/loaders/TemplateWizard.java,v
retrieving revision 1.66
diff -c -r1.66 TemplateWizard.java
*** openide/src/org/openide/loaders/TemplateWizard.java 21 Dec 2002 08:40:26 -0000 1.66
--- openide/src/org/openide/loaders/TemplateWizard.java 15 Jan 2003 14:10:08 -0000
***************
*** 481,495 ****
obj.getPrimaryFile().setAttribute(EA_DESCRIPTION, url);
}
! /** Method to get a description for a data object.
* @param obj data object to attach description to
* @return the url with description or null
*/
public static URL getDescription (DataObject obj) {
! URL desc = (URL)obj.getPrimaryFile().getAttribute(EA_DESCRIPTION);
if (desc != null) return desc;
// Backwards compatibility:
! String rsrc = (String) obj.getPrimaryFile ().getAttribute (EA_DESC_RESOURCE);
if (rsrc != null) {
try {
URL better = new URL ("nbresloc:/" + rsrc); // NOI18N
--- 481,503 ----
obj.getPrimaryFile().setAttribute(EA_DESCRIPTION, url);
}
! /** Get a description for a data object. The description is
! * specified as a URL attribute of the DataObject's primary file named
! * templateWizardURL
.
* @param obj data object to attach description to
* @return the url with description or null
*/
public static URL getDescription (DataObject obj) {
! FileObject primaryFile;
! if (obj instanceof DataShadow) {
! primaryFile = ((DataShadow) obj).getOriginalPrimaryFile();
! } else {
! primaryFile = obj.getPrimaryFile();
! }
! URL desc = (URL)primaryFile.getAttribute(EA_DESCRIPTION);
if (desc != null) return desc;
// Backwards compatibility:
! String rsrc = (String) primaryFile.getAttribute (EA_DESC_RESOURCE);
if (rsrc != null) {
try {
URL better = new URL ("nbresloc:/" + rsrc); // NOI18N
***************
*** 544,550 ****
*/
public static void setIterator (DataObject obj, Iterator iter)
throws IOException {
! obj.getPrimaryFile().setAttribute(EA_ITERATOR, iter);
}
/** Finds a custom iterator attached to a template that should
--- 552,561 ----
*/
public static void setIterator (DataObject obj, Iterator iter)
throws IOException {
! if ((obj instanceof DataShadow) && ((DataShadow) obj).wasLazy)
! ((DataShadow) obj).getOriginalPrimaryFile().setAttribute (EA_ITERATOR, iter);
! else
! obj.getPrimaryFile().setAttribute(EA_ITERATOR, iter);
}
/** Finds a custom iterator attached to a template that should
***************
*** 555,562 ****
* @param obj the data object
* @return custom iterator or null
*/
! public static Iterator getIterator (DataObject obj) {
! Iterator it = (Iterator)obj.getPrimaryFile ().getAttribute(EA_ITERATOR);
if (it != null) {
return it;
}
--- 566,577 ----
* @param obj the data object
* @return custom iterator or null
*/
! public static Iterator getIterator (DataObject obj) {
! Iterator it;
! it = (Iterator) obj.getPrimaryFile().getAttribute (EA_ITERATOR);
! if ((it == null) && (obj instanceof DataShadow)) {
! it = (Iterator)((DataShadow) obj).getOriginalPrimaryFile ().getAttribute(EA_ITERATOR);
! }
if (it != null) {
return it;
}
Index: openide/src/org/openide/loaders/TemplateWizard1.java
===================================================================
RCS file: /cvs/openide/src/org/openide/loaders/TemplateWizard1.java,v
retrieving revision 1.37
diff -c -r1.37 TemplateWizard1.java
*** openide/src/org/openide/loaders/TemplateWizard1.java 8 Jan 2003 14:24:10 -0000 1.37
--- openide/src/org/openide/loaders/TemplateWizard1.java 15 Jan 2003 14:10:09 -0000
***************
*** 183,199 ****
Node n = (Node)key;
String nodeName = n.getDisplayName();
! DataObject obj = null;
! DataShadow shadow = (DataShadow)n.getCookie (DataShadow.class);
! if (shadow != null) {
! // I need DataNode here to get localized name of the
! // shadow, but without the ugly "(->)" at the end
! DataNode dn = new DataNode(shadow, Children.LEAF);
! nodeName = dn.getDisplayName();
! obj = shadow.getOriginal();
! n = obj.getNodeDelegate();
! }
if (obj == null)
obj = (DataObject)n.getCookie (DataObject.class);
--- 183,193 ----
Node n = (Node)key;
String nodeName = n.getDisplayName();
! //try getting a shadow first, for lazy instantiation
! DataObject obj = (DataObject) n.getCookie(DataShadow.class);
+ //if that fails, force instantiation of the DataObject and get
+ //the real DataObject
if (obj == null)
obj = (DataObject)n.getCookie (DataObject.class);
***************
*** 508,514 ****
boolean enable = false;
Node[] n = getExplorerManager().getSelectedNodes();
if (n.length == 1) {
! template = (DataObject)n[0].getCookie (DataObject.class);
enable = template != null && template.isTemplate();
}
return enable;
--- 502,510 ----
boolean enable = false;
Node[] n = getExplorerManager().getSelectedNodes();
if (n.length == 1) {
! template = (DataObject) n[0].getCookie (DataShadow.class);
! if (template == null)
! template = (DataObject)n[0].getCookie (DataObject.class);
enable = template != null && template.isTemplate();
}
return enable;
***************
*** 542,548 ****
public boolean isLeaf (Object o) {
Node n = Visualizer.findNode(o);
! DataObject obj = (DataObject)n.getCookie (DataObject.class);
return obj == null || obj.isTemplate ();
}
--- 538,546 ----
public boolean isLeaf (Object o) {
Node n = Visualizer.findNode(o);
! DataObject obj = (DataShadow) n.getCookie (DataShadow.class);
! if (obj == null)
! obj = (DataObject)n.getCookie (DataObject.class);
return obj == null || obj.isTemplate ();
}