Index: core/src/org/netbeans/core/resources/mf-layer.xml =================================================================== RCS file: /cvs/core/src/org/netbeans/core/resources/mf-layer.xml,v retrieving revision 1.122 diff -u -r1.122 mf-layer.xml --- core/src/org/netbeans/core/resources/mf-layer.xml 14 Jan 2003 13:30:21 -0000 1.122 +++ core/src/org/netbeans/core/resources/mf-layer.xml 16 Jan 2003 18:06:55 -0000 @@ -71,9 +71,30 @@ - + + + + + + + + + + + + + + + + + + + + + + Index: core/src/org/netbeans/core/NbPropertyEditorManagerImpl.java =================================================================== RCS file: core/src/org/netbeans/core/NbPropertyEditorManagerImpl.java diff -N core/src/org/netbeans/core/NbPropertyEditorManagerImpl.java --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ core/src/org/netbeans/core/NbPropertyEditorManagerImpl.java 16 Jan 2003 18:06:55 -0000 @@ -0,0 +1,239 @@ +/* + * 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-2003 Sun + * Microsystems, Inc. All Rights Reserved. + */ +/* + * NbPropertyEditorManager.java + * + * Created on January 12, 2003, 8:06 PM + */ + +package org.netbeans.core; +import java.beans.*; +import java.util.*; +import org.openide.filesystems.*; +import org.openide.ErrorManager; +import org.openide.util.NbPropertyEditorManager; +/** Provides property editors registered via XML, falling + * back to java.beans.PropertyEditorManager. + * @author Tim Boudreau + */ +final class NbPropertyEditorManagerImpl extends NbPropertyEditorManager { + private final HashMap map = new HashMap(); + private String folder; + public static final String ATTR_EDITORFOR = "editorFor"; //NOI18N + public static final String ATTR_EDITORCLASS = "editorClass"; //NOI18N + + public NbPropertyEditorManagerImpl () { + this ("/propertyeditors"); + } + + private NbPropertyEditorManagerImpl (String editorFolder) { + //XXX may want to expose this constructor later, for e.g. form + //editor which wants its own private property editor registry + folder = editorFolder; + } + + public PropertyEditor findEditor (Class clazz) { + return findEditor (clazz, true); + } + + private static NbPropertyEditorManager instance=null; + public static NbPropertyEditorManager getInstance() { + if (instance == null) { + instance = new NbPropertyEditorManagerImpl(); //NOI18N + } + return instance; + } + + public PropertyEditor findEditor (Class clazz, boolean newInstance) { + synchronized (map) { + if (map.isEmpty()) buildMap(); + } + System.out.println("Looking for editor for " + clazz.getName()); + String cname = clazz.getName(); + + System.out.println("Map lookup for " + cname); + System.out.println("Map contents:"); + Iterator i = map.keySet().iterator(); + while (i.hasNext()) + System.out.println(" -" + i.next()); + + Info in = (Info) map.get(cname); + PropertyEditor result = null; + if (in != null) + result = in.get (newInstance); + //Result will only be null if there was a cnfe fetching the editor + //class, or if no editor is registered via XML + if (result != null) return result; + System.out.println("Falling back to property editor manager"); + //Fall back to PropertyEditorManager + return PropertyEditorManager.findEditor (clazz); + } + + private boolean listening=false; + private void buildMap() { + synchronized (map) { + FileObject fo = org.openide.filesystems.Repository.getDefault().getDefaultFileSystem().findResource(folder); + FileObject[] kids = fo.getChildren(); + synchronized (map) { + for (int i=0; i < kids.length; i++) { + String editorFor = (String)kids[i].getAttribute ("editorFor"); //NOI18N + map.put (editorFor, new InfoImpl (kids[i])); + } + } + if (listening == false) { + fo.addFileChangeListener(new FileChangeListener () { + public void fileFolderCreated (FileEvent fe){ + //meaningless + } + public void fileDataCreated (FileEvent fe){ + synchronized (map) { + map.clear(); + } + } + public void fileChanged (FileEvent fe) { + synchronized (map) { + map.clear(); + } + } + public void fileDeleted (FileEvent fe) { + synchronized (map) { + map.clear(); + } + } + + public void fileRenamed (FileRenameEvent fe) { + //no effect + } + + public void fileAttributeChanged (FileAttributeEvent fe) { + //in the case that editors are added or removed, + //dump the cache - the next call will rebuild it + synchronized (map) { + map.clear(); + } + } + + }); + listening = true; + } + } + } + + public boolean hasEditor (Class clazz) { + synchronized (map) { + if (map.isEmpty()) buildMap(); + } + String cname = clazz.getName(); + return map.keySet().contains (cname); + } + + public Info findInfo(Class clazz) { + if (map.isEmpty()) buildMap(); + return (Info) map.get (clazz.getName()); + } + + class InfoImpl implements NbPropertyEditorManager.Info { + private String editorClassName; + private String editorFor; + private Class editorClass; + private Class edForClass; + private boolean badClassInfo=false; + private PropertyEditor defaultInstance=null; //make weak/soft ref? + private boolean initFromPe=false; + public InfoImpl (FileObject fo) { + editorClassName = (String) fo.getAttribute (ATTR_EDITORCLASS); //NOI18N + editorFor = (String) fo.getAttribute (ATTR_EDITORFOR); //NOI18N + System.out.println("Registered " + editorClassName + " for " + editorFor); //XXX debug code + } + + public PropertyEditor get(boolean newInstance) { + PropertyEditor result = null; + if (newInstance) { + try { + result = (PropertyEditor) getEditorClass().newInstance(); + System.out.println("Created new instance of " + result.getClass().getName()); + return result; + } catch (Exception e) { + e.printStackTrace(); + return null; + } + } else if (defaultInstance == null) { + try { + result = (PropertyEditor) getEditorClass().newInstance(); + defaultInstance = result; + System.out.println("Created default instance of " + result.getClass().getName()); + } catch (Exception e) { + e.printStackTrace(); + } + } + return result; + } + + private Class getEditorClass () { + //If we know we have a bad registration, throwing the + //exception once is enough. + if (badClassInfo) return null; + if (editorClass == null) { + try { + editorClass = Class.forName(editorClassName); + } catch (ClassNotFoundException cnfe) { + ErrorManager.getDefault().log (ErrorManager.WARNING, + "The class \"" + editorClassName + "\" which is a property editor class for \"" //NOI18N + + editorFor + "\" is registered cannot be loaded."); //NOI18N + ErrorManager.getDefault().notify(ErrorManager.WARNING, cnfe); + badClassInfo = true; + } + if (editorClass != null) editorClassName = null; + } + return editorClass; + } + + private Class getEdForClass () { + //If we know we have a bad registration, throwing the + //exception once is enough. + if (badClassInfo) { + return null; + } + if (edForClass == null) { + try { + edForClass = Class.forName(editorFor); + } catch (ClassNotFoundException cnfe) { + ErrorManager.getDefault().log (ErrorManager.WARNING, + "The class \"" + editorFor + "\" for which the property editor class \"" //NOI18N + + editorClassName + "\" is registered cannot be loaded."); //NOI18N + ErrorManager.getDefault().notify(ErrorManager.WARNING, cnfe); + badClassInfo = true; + } + if (edForClass != null) editorFor = null; + } + return edForClass; + } + + public int hashCode () { + if (badClassInfo) return super.hashCode(); + return getEditorClass().getName().hashCode() ^ 31; + } + + public boolean equals (Object o) { + if (!(o instanceof NbPropertyEditorManager.Info)) + return false; + return o.hashCode() == hashCode(); + } + + public Object getAttribute(Object key) { + //do nothing for now, maybe return fo's attributes + return null; + } + } + +} Index: openide/src/org/openide/util/NbPropertyEditorManager.java =================================================================== RCS file: openide/src/org/openide/util/NbPropertyEditorManager.java diff -N openide/src/org/openide/util/NbPropertyEditorManager.java --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openide/src/org/openide/util/NbPropertyEditorManager.java 16 Jan 2003 18:06:59 -0000 @@ -0,0 +1,164 @@ +/* + * 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-2003 Sun + * Microsystems, Inc. All Rights Reserved. + */ +/* + * NbPropertyEditorManager.java + * + * Created on January 12, 2003, 10:49 PM + */ + +package org.openide.util; +import java.beans.PropertyEditor; +import java.beans.PropertyEditorManager; +import org.openide.ErrorManager; +/** NetBeans property editor manager. The default implementation + * in the NetBeans IDE allows registration of property editors + * via XML.

The preferred method of fetching property editors + * in NetBeans is by using this class - + * java.beans.PropertyEditorManager will not contain + * property editors registered using the XML registration + * technique. The advantage of registration via XML is that + * the classes do not need to be loaded on IDE startup, and + * many modules that currently use ModuleInstall classes to + * do such registration may eliminated them by using layer-based + * registration instead. + * @author Tim Boudreau + */ +public abstract class NbPropertyEditorManager { + + private static NbPropertyEditorManager defaultInstance=null; + /** Get the default implementation of NbPropertyEditorManager + * @return The implementation of NbPropertyEditorManager. + */ + public static NbPropertyEditorManager getDefault() { + if (defaultInstance == null) { + try { + defaultInstance = (NbPropertyEditorManager) Lookup.getDefault().lookup (NbPropertyEditorManager.class); + } catch (Exception e) { + ErrorManager.getDefault().log (ErrorManager.INFORMATIONAL, + "No instance of NbPropertyEditorManager registered in lookup. Using proxy for java.beans.PropertyEditorManager instead."); //NOI18N + ErrorManager.getDefault().notify (ErrorManager.INFORMATIONAL, e); + } finally { + if (defaultInstance == null) defaultInstance = new BeansWrapper(); + return defaultInstance; + } + } + return defaultInstance; + } + /* + //could optionally implement as static methods, changing names of instance methods + public static final PropertyEditor findEditor (Class clazz, boolean newInstance) { + return getDefault().findEditor (clazz, newInstance); + } + + public static final PropertyEditor findEditor (Class clazz) { + return getDefault().findEditor (clazz); + } + + public static final boolean hasEditor (Class clazz) { + return getDefault().hasEditor (clazz); + } + + public static final Info findInfo (Class clazz) { + return getDefault().findInfo (clazz); + } + */ + + /** Find a property editor for the given class, specifying whether a new + * or shared instance should be used. Looks first for + * editors registered with the NetBeans property editor + * infrastructure, and if it finds none, falls back to + * java.beans.PropertyEditorManager.

+ * Do not attach listeners to instances returned when + * newInstance is false! Such returned property + * editors' values are liable to change without notice, as + * property displaying infrastructure may reconfigure them + * without notice! + * @param clazz The class an editor is sought for. + * @param newInstance If true, method will return a new instance of the class in question. + * @return A property editor instance. + */ + public abstract PropertyEditor findEditor (Class clazz, boolean newInstance); + /** Find an editor for the given class. There are two use cases for + * property editors - as renderers, which are used merely for + * display purposes, and to actually edit properties.

Looks first for + * editors registered with the NetBeans property editor + * infrastructure, and if it finds none, falls back to + * java.beans.PropertyEditorManager. + * @param clazz The class an editor is sought for + * @return A new property editor instance + */ + public abstract PropertyEditor findEditor (Class clazz); + /** Returns true if a property editor has been registered with + * this implementation (if using the default NetBeans implementation, + * this means if an editor has been registered using XML). Note + * that findEditor() may return true even if this + * method returns false, in the case that an editor was registered + * via java.beans.PropertyEditorManager. + * @param clazz The class sought + * @return True if an editor has been registered + */ + public abstract boolean hasEditor (Class clazz); + /** Get an object representing the extended information that is part + * of property editor registration. This information is primarily + * used by the property sheet infrastructure for performance + * optimizations. + * @param clazz The class an Info object is sought for + * @return An Info instance containing the extended registration + * information, or null if no editor was registered using + * the default registration mechanism (this does not mean + * that no editor was registered with + * java.beans.PropertyEditorManager. + */ + public abstract Info findInfo (Class clazz); + + /** Extended information pertaining to a property editor. */ + public interface Info { + /** Get an instance of the property editor class represented by + * this Info object. If newInstance is false, do + * not attach listeners to the result! + * @param newInstance True if a new instance of this property editor is desired, rather than a shared + * instance + * @return The property editor instance + */ + public PropertyEditor get (boolean newInstance); + /**Get an arbitrary keyed attribute pertaining to the property editor. + * This method is here for future flexibility - there is the + * potential for optimizations if property editors register + * additional information about themselves. */ + public Object getAttribute (Object key); + } + + /**A fallback default implementation in the case that no + * instance of NbPropertyEditorManager is registered via + * a layer.*/ + private static class BeansWrapper extends NbPropertyEditorManager { + + public PropertyEditor findEditor(Class clazz) { + return PropertyEditorManager.findEditor (clazz); + } + + public PropertyEditor findEditor(Class clazz, boolean newInstance) { + return PropertyEditorManager.findEditor (clazz); + } + + public Info findInfo(Class clazz) { + return null; + } + + public boolean hasEditor(Class clazz) { + return false; + } + + } + +} Index: openide/src/org/openide/nodes/Node.java =================================================================== RCS file: /cvs/openide/src/org/openide/nodes/Node.java,v retrieving revision 1.60 diff -u -r1.60 Node.java --- openide/src/org/openide/nodes/Node.java 16 Jan 2003 15:13:22 -0000 1.60 +++ openide/src/org/openide/nodes/Node.java 16 Jan 2003 18:07:00 -0000 @@ -23,6 +23,7 @@ import java.lang.ref.WeakReference; import java.lang.reflect.InvocationTargetException; +import java.lang.ref.SoftReference; import java.util.WeakHashMap; import javax.swing.Action; import javax.swing.JPopupMenu; @@ -36,6 +37,7 @@ import org.openide.util.LookupListener; import org.openide.util.NbBundle; import org.openide.util.actions.SystemAction; +import org.openide.util.NbPropertyEditorManager; /** A node represents one element in a hierarchy of objects (beans). @@ -1057,13 +1059,20 @@ return true; } + SoftReference ped = null; /** Get a property editor for this property. * The default implementation tries to use {@link java.beans.PropertyEditorManager}. - * @return the property editor, or null if there is no editor - */ + * @return the property editor, or null if there is no editor */ public PropertyEditor getPropertyEditor () { if (type == null) return null; - return java.beans.PropertyEditorManager.findEditor(type); + PropertyEditor result=null; + if (ped != null) { + result = (PropertyEditor) ped.get(); + if (result != null) return result; + } + result = NbPropertyEditorManager.getDefault().findEditor (type); + ped = new SoftReference (result); + return result; } /* Standard equals implementation for all property @@ -1259,7 +1268,6 @@ if (result == null) { result = lookup.lookup (TEMPL_COOKIE); result.addLookupListener (this); - result.allItems(); } }